OmniAICreator/Qiita-1.07M huggingface dataset:
LINEに投稿されたメッセージをSlackに流す（セキュリティ＆確実性無視編

LINEに投稿されたメッセージをSlackに集約したい。という要件あり。
IFTTTでできるんじゃないかな？　とおもったものの、パッとみたところ[ここの一覧](https://ifttt.com/create)  にLINEが存在しない。
WebHookを駆使すればIFTTTで実現可能な気がするが、pythonでサーバーを立てて実現してみる。
サーバを立ち上げるところはHeroku,Azure,AWS,etc...お好きなところで。


#### 大雑把な機構は以下のとおり

LINEに投稿あり
↓
LINEが messaging-api webhooks 機能により、自作のpythonサーバーにPOSTメッセージを送る
↓
pythonサーバーでLINEから送られるメッセージ受信。
LINEから送られるメッセージにはユーザー名が含まれていないのでLINEのAPIを叩き、
そのメッセージを送ったユーザー情報（欲しいのは表示名）を取得
↓
pythonサーバーでSlack の Webhookを叩く
↓
Slackに表示された〜


#### Slack側　Incoming Webhook の用意

+ https://api.slack.com/apps を開く
+ Create New App ボタンを押す。From scratchを選択。
+ App Name をなんか適当に決める。投稿したいワークスペースを選んで Create App! 
+ そしたらアプリが作成される（おそらく作成したアプリのBasic Information画面に遷移している）
左メニューからIncoming Webhooksを選択。
+ Incoming Webhooks を On にする。「どこのチャンネルに投稿する？」を聞かれるので適宜選ぶ。
この画面下に「Webhook URL」
　https://hooks.slack.com/services/XXXXXXXXX/YYYYYYYYYYY/ZZZZZZZZZZZZZZZZZZZZZZZZ
というのが表示されていると思うのでそれをメモしておく。（これは他人に見せちゃダメなやつ）

Slack側　の準備はこれで終わりです

#### LINE側 Messaging API の設定
ドキュメントはこの辺だがあんまり見なくていい　https://developers.line.biz/ja/reference/messaging-api/#webhooks


- https://developers.line.biz/console/ にアクセス。
- プロバイダーを新規作成
- 画面左　プロバイダー　→　新規チャネル作成（チャネルの種類：Messageing API、さっき作ったプロバイダーを選ぶ）
- 作成したチャネルの、チャネル基本設定を選択、Messaging API設定　タブを選択
- 以下の設定を行う
    - Webhook設定 に、自作のpythonサーバーにアクセスして欲しいURLを入れる。
       - 下記pythonサンプルで言えば https://example.com/endpoint になる
    - Webhookの利用 -> ON
    - LINE公式アカウント機能 グループ・複数人チャットへの参加を許可する -> 有効
    - LINE公式アカウント機能 ->  応答メッセージ  
        - 基本設定 : ボット   
        - あいさつメッセージ : OFF
        - 応答メッセージ : ON
        - Webhook : ON

- チャネルアクセストークン（長期） 
 +~~~~~~中略~~~~~~= が表示されているはずなのでメモしておく（これは他人に見せちゃダメなやつ）

LINE側　の準備はこれで終わりです


#### Python
下記ソースの
「LINEのチャネルアクセストークン」
「slackのWebhook URL」
を先ほどメモったものを置換する。（下記ソースコメント参照のこと）
下記ソースをwebサーバーにデプロイし、webアプリとして稼働させる。
購読したいLINEのグループに、先程のチャネル、を参加させる

うまくいっていればこれで実現できているはずです。
いろいろ脆弱性がありますがそれは攻撃された時に考えましょう・・・

```python:app.py
from flask import Flask, request
import requests
import json

app = Flask(__name__)

lineURL = 'https://api.line.me/v2/bot/profile/'
lineAuthHeaders = {'Authorization': 'Bearer ここにLINEのチャネルアクセストークンを記載'}

slackURL = 'https://hooks.slack.com/services/XXXXXXXXX/YYYYYYYYYYY/ZZZZZZZZZZZZZZZZZZZZZZZZ' #slackのWebhook URLを記載

@app.route("/")
def hello_world():
	#サーバー死活確認用
	return "<p>Hello</p>"

@app.route("/endpoint",methods=["POST"])
def endpoint():
	try:
		webHook = json.loads( request.get_data(as_text=True) )
		events = webHook['events']

		for event in events:
			if (event['type'] == 'message') and  event['message']['type'] == 'text' :
				message_text = event['message']['text']
				user_id = event['source']['userId']

				lineRes = requests.get(lineURL+user_id, headers=lineAuthHeaders)
				user_name = lineRes.json()['displayName']

				postSlackData = {
			    'text': user_name + ' : ' + message_text
				}

				_ = requests.post(slackURL, json=postSlackData)
	except Exception as e:
		return ("Error {0}".format(str(e)))

	return "OK"
```
FlutterWeb×FirebaseHostingでデプロイしたときにバージョンが更新されない問題について

#1. はじめに
タイトルにもあるとおり、FlutterWeb（じゃなくてもいいけど）で開発しながらFirebaseHostingでデプロイしたときに内容が反映されないことがあります。調べてみるとブラウザのキャッシュを読んでしまい最新版を引っ張ってくることができないとのこと。

解決法を検索してみると、スーパーリロードとやらをすることでブラウザのキャッシュをクリアすると最新版をサーバーから引っ張ってくることができるそうです。
ただ、これは開発者目線であり、ユーザにスーパーリロードを求めるのは少し難しいかと思います。

また、バージョンが最新じゃないアプリケーションを使ったユーザによってバグが発生してしまう可能性を考えると、全てのユーザに最新バージョンで使ってもらいたいと考えるのが普通なのではないでしょうか。
(古いバージョンのユーザがいてもバグが起きないように設計しろと言われればそれまでですが、なかなか難しい。)

そこで最新版をアップロードした際に、ブラウザのキャッシュを無視して最新版を引っ張ってくることをこの記事の目標とします。
**また、この記事は紆余曲折を書き連ねているため、まず結論からお読みいただくことをお勧めします。**

#目次
[1.はじめに](#1-はじめに)
[2.試行錯誤1](#2-試行錯誤1)
[3.試行錯誤2](#3-試行錯誤2)
[4.試行錯誤3](#4-試行錯誤3)
[5.結論](#5-結論)


#2. 試行錯誤1


まず参考にした記事
https://qiita.com/fukusin/items/51b1f98fde15f7994a12
https://tech.playground.style/javascript/cra-cache/

上記の記事を参考に色々試しましたが、いけそうで上手くいかない。。。

#3. 試行錯誤2


次にjavascriptのコードでlocation.reload(true)とすることで最新版をサーバから引っ張ってくることができるとの情報を手に入れたので試してみるが、safariでは上手くいくもののchromeでは上手くいかない。少し情報が古いのでなんとも言えないが、下の記事を見るにchromeは対応していないのかもしれない。。。
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q12176544187

#4. 試行錯誤3

次に参考にしたのがこちらの内容です。
https://www.reddit.com/r/flutterhelp/comments/m02olu/how_to_force_hardreload_on_flutter_web_after/

要するにindex.htmlを編集するといいとのこと。ただし、index.htmlは二つありソースとビルド後の生成物？がある。
その両方を編集する必要がある。この方法でうまくいったのだが、ここで問題が発生。
自分が携わっているプロジェクトではGitHubActionsでプルリクのマージをトリガーにデプロイを自動化している。
GithubActionsにビルドとデプロイを任せているため、ビルド後にビルド後のindex.htmlを編集するのは少しめんどくさい。。。

と思っていたのですが、ここで色々調べたり考えたりした結果、重要なのはindex.htmlに記述されているmain.dart.jsのソースURLをアップデートのたびに少し変えることだと気づいた。
上記の記事ではビルド時にflutter_service_worker.jsに割り振られる文字列をmain.dart.jsのソールURLに追記することで変えているが、ここに追記する文字列はなんでもよさそうであり、ビルド前のindex.htmlに記載するだけでよさそうだと考えた。



#5. 結論
flutterプロジェクトの/web/index.htmlにある下の1行を

```
<script src="main.dart.js" type="application/javascript"></script>
```
下の1行のように変更することでキャッシュを無視して最新バージョンを引っ張ってくることができる。

```
<script src="main.dart.js?v=1.3.3" type="application/javascript"></script>
```
v=○.◯.◯はアプリのバージョンに合わせて運用していけばよさそう。

なぜこれでキャッシュを無視できるのかは下の記事を読んだらわかりそう。
https://taishon.nagoya/browser-cache-delete/

上記のやり方で、デプロイ後の最新バージョンを引っ張ってくることができました。(ただし、普通のリロードをしないといけないかも。)

何かご指摘があればよろしくお願いします。
GASでGoogleドライブのフォルダ・ファイル構造をスプレッドシートに一覧化する

# はじめに
こんにちは。人差し指の詰めが割れ欠けてて、でも皮膚はくっついているので困っています、筆者です:innocent:

さて、今回はGoogleドライブのフォルダ構造とそのフォルダに属しているファイルたちをスプレッドシートで見れるようにGASを書いていこうと思います。
参考になれば幸いです:pray:

# 方針
1. Googleドライブのルートフォルダから所属するフォルダがある場合再帰的に掘っていく.
1. フォルダ掘ると同時にファイルがあれば配列に追加していく.
1. 配列の長さを調整
1. ヘッダー追加
1. スプレッドシート書き込み

# Googleドライブのフォルダ・ファイル構造をスプレッドシートで一覧化する
スクリプトはこちらです。

```js
const sheet = SpreadsheetApp.getActiveSheet()
const headers = ['No.', 'id', 'size', 'mimeType', 'url']

const main = () => {
  let folder = DriveApp.getRootFolder(),
    folder_name = folder.getName(),
    data = []
  
  data = seek(data, folder, [folder_name])
  data = convert(data)

  // スプレッドシートに書き込み.
  sheet.getRange(1, 1, data.length, data[0].length).setValues(data)
}

const seek = (data, folder, ancestors) => {
  const files = folder.getFiles()
  let file
  while (files.hasNext()) {
    file = files.next()

    // ファイル数やフォルダ数が少ない場合はここで直接スプレッドシートに書き込んでもいいけど処理遅いからおすすめしないよ.
    data.push([
      '=row() - 1',
      file.getId(),
      file.getSize(),
      file.getMimeType(),
      file.getUrl(),
      ...ancestors,
      file.getName()
    ])
  }

  const folders = folder.getFolders()
  let folder_descendant
  while (folders.hasNext()) {
    folder_descendant = folders.next()
    seek(data, folder_descendant, [...ancestors, folder_descendant.getName()])
  }

  return data
}

const convert = data => {
  // 深さの最大値を取得.
  const depth_max = data.map(e => e.length).reduce((a, b) => a > b ? a : b)

  // 深さを基に配列の長さを統一する.
  // 配列の長さが異なると後続でスプレッドシートに値を書き込む際に怒られる...
  for (let i in data) {
    if (data[i].length < depth_max) {
      data[i] = [
        ...data[i],
        ...[...Array(depth_max - data[i].length).keys()].map(i => '')
      ]
    }
  }

  // header追加.
  data = [
    [
      ...headers,
      ...[...Array(depth_max - headers.length).keys()].map(i => `Layer${i + 1}`)
    ],
    ...data
  ]

  return data
}
```

# 実行結果
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86984/de9d2054-3056-3326-b1af-1fcfcdd7fb6d.png)

# 所感
convert関数で処理している最後にスプレッドシートに渡す配列の長さを調整する処理ですが、内部的にかなりfor文が回っています... :sob:

ただ、data配列にpushせずそのタイミングでスプレッドシートに1行ずつ書き込むとAPIのリクエストがその数発生し、書き込み速度が遅くなるのでそれはもっとおすすめしないです。

https://gas.excelspeedup.com/gas-spreadsheet-speedup/

そのため、スマートではないですが、GAS側で少し負荷掛かってますが、ご留意を:pray:
総じてこっちの方が高速処理できますので:pray:

# おわりに
意外と600ファイルくらいあってビビりました。
いらないファイル消していこうと思います:pray:

それでは！
【Laravel】スケジューラ（Lravelの定期バッチ）を手動実行する。

自分用のメモとして残します。

開発環境とかになると、タスクスケジューラに登録してないことが多いです。
そこで手動でLaravelのスケジューラを実行して動作を確認する方法をメモ。


#やり方
```shell
php artisan schedule:run
```




以上。
ローカルの公開鍵をAWSに登録する


自分で立てた EC2 に接続する時は、EC2インスタンス作成時に、公開鍵を登録することができます。
ただ他の人が作成した EC2 に　ローカルの PC から SSH 接続する方法が分からなくて調べたのでメモ。

## 1. マイセキュリティ資格情報へ移動

AWS マネジメントコンソールの 「マイセキュリティ資格情報」 をクリック。

![スクリーンショット 2021-06-22 13.48.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142797/5914929e-007a-af45-6779-129699c86216.png)

## 2. 公開鍵をアップロード

「AWS CodeCommit認証情報」タブをクリックして、「SSH パブリックキーのアップロード」から、ローカルの公開鍵ををアップロード。

![スクリーンショット 2021-06-22 13.49.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142797/f65a482f-fdfe-dc9e-6e91-bd17b020faf0.png)


## 3. ローカルでSSH接続

ローカルから秘密鍵を指定して SSH 接続。

```
$ ssh -i ~/id_rsa ubuntu@00.000.00.000
```
【react-hook-form】TypeError: path split is not a functionのエラー対応

# react-hook-form
`TypeError: path split is not a function`というエラーが出たので

```
yarn remove react-hook-form
yarn add react-hook-form@^6.11.4
```
バージョンを下げて対応しようとしたが解決できず、もう1度もとのバージョン（"react-hook-form": "^7.9.0",）に戻し、対象となりそうなコードを変更しました。

```TaskForm.tsx
// 変更前
  <TextField
    className={styles.text_field}
    id="outlined-basic"
    inputRef={register}
    label="New Task"
    name="taskTitle"
    variant="outlined"
  />
```
```TaskForm.tsx
// 変更後
  <TextField
    className={styles.text_field}
    id="outlined-basic"
    {...register("taskTitle")} //このように変更
    label="New Task"
    variant="outlined"
  />

```

`inputRef`と`name`の値を一つにまとめたところ、エラーは解消しました。
ローカル開発とデザインマネージャーの同期問題


モジュールがローカルにもデザインマネージャー上にもある場合、
デザインマネージャーで設定変更しローカルからfetchしてもローカルには反映されない。
--overwriteすれば可能。ただし上書き許可は影響範囲を考えるとためらわれる。
影響範囲が怖い場合にはローカルの対象モジュールを削除してからfetchすれば安全にfetchが可能かもしれない。


模索中
③CUDA-PCL評価用のROS2(Foxy) VLP-16 Nodeの構築

CUDA-PCL評価用にVLP-16を動かしたときのメモ。

## 事前作業

https://qiita.com/akira-sasaki/items/58ac9f5915a557882d4f

## VLP-16 Nodeの構築

Docker内でVLP-16用のNodeをBuildしておきます。

```
cd ~/data/ros2_ws/src/
git clone -b ros2 https://github.com/ros-drivers/velodyne
```

```
cd ~/data/ros2_ws/
colcon build --base-paths src/velodyne
source install/setup.bash
```

## Jetson側の設定

Docker内ではなく、大本のUbuntu上で、ここからは作業します。先に必要なパッケージをインストールしておきます。

```
sudo apt-get install arp-scan
```

Jetsonのeth0のIPアドレスを`10.0.0.2`に固定します。

```
sudo vi /etc/network/interfaces.d/network
```

```
# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
auto eth0

# DHCP 
#iface eth0 inet dhcp

# Static IP
iface eth0 inet static
address 10.0.0.2
netmask 255.255.255.0
#dns-nameservers 8.8.8.8
```
ネットワークの再起動をおこないます。

```
sudo /etc/init.d/networking restart
```

IPアドレスが割り振られたことの確認

```
ifconfig -a
```

```
...
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.0.0.2  netmask 255.255.255.0  broadcast 10.0.0.255
        inet6 fe80::204:4bff:fecb:e19a  prefixlen 64  scopeid 0x20<link>
        ether 00:04:4b:cb:e1:9a  txqueuelen 1000  (Ethernet)
        RX packets 54497  bytes 61371918 (61.3 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 131  bytes 45724 (45.7 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        device interrupt 41  
...
```

## VLP-16の設定

VLP-16とJetson AGX XavierをダイレクトにEthernetケーブルで接続します。Jetson AGX Xavier側でブラウザを起動し、`10.0.0.201`に接続します。初期設定では、マルチキャストでデータ送信が行われるため、Jetson AGX XavierのIPアドレスに限定してデータ送信するように変更します。

![vlp001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63450/32aabb2e-ee09-2994-5806-768500837dc8.png)

|項目|値|
|:--|:--|
|Host(Destination) IP Address|10.0.0.2|

![vlp002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63450/4ac945d9-80e6-8645-2e03-106307783756.png)

VLP-16がネットワーク内に存在していることの確認をおこないます。

```
sudo arp-scan -l
```

```
Interface: eth0, datalink type: EN10MB (Ethernet)
Starting arp-scan 1.9 with 256 hosts (http://www.nta-monitor.com/tools/arp-scan/)
10.0.0.201	60:76:88:10:5e:f9	Velodyne

3 packets received by filter, 0 packets dropped by kernel
Ending arp-scan 1.9: 256 hosts scanned in 3.386 seconds (75.61 hosts/sec). 1 responded
```

## ROS Nodeの起動

再びDockerにログインし、ROS Nodeを起動します。

```
ros2 run velodyne_driver velodyne_driver_node
```

```
ros2 launch velodyne_pointcloud velodyne_convert_node-VLP16-launch.py
```

```
rviz2 
```

## rviz2の設定

![vlp003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63450/5532cdff-45a7-9c2c-e5f3-d285f9a8bbae.png)

![vlp004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63450/c699eabe-f3bd-6123-005a-36d21df82cd8.png)

![vlp005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63450/349791d0-1530-da49-b686-145b007abf7a.png)

![vlp06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63450/d4bea9b9-824c-8e18-4423-f7df0e7993b6.png)
[Sass] Sassについて

##はじめに
railsでコマンドを使ってファイルを生成したりすると、自動で拡張子が「.scss」となったファイルが生成されて、なんだろうと思いながら、放置していました笑

実はこれCSSの進化版みたいな「Sass」という言語で書くファイルだったみたいです。
ちなみにSassはサスと読む人とサースと読む人がいて、私が第三者としてたまたまサスと読む人とサースと読む人がSassについてお話ししている場面に出くわした時は個人的にちょっと面白かったです。

私はどちら派かわからないように「サァス」と発音することで、曖昧にしています。
すみません余談でした。


簡単に「Sassとは」を書いてみました。また、少しだけ一部の機能も紹介してみます。
よろしくお願いします！


## Sassとは
SassとはCSSを効率的に書くことができる言語です。
書き方が2種類あって**SASS記法**と**SCSS記法**というのがあります。
*※今回はSCSS記法で紹介していきます。*

Sassを使うことによりCSSよりも記述量を減らしたりコードを再利用できるといったメリットがあります。


少しだけ一部の機能を紹介します。
##入れ子構造
Sassでは入れ子構造を使うことができます。例えばHTMLで下記のように入れ子構造があったとします。

```HTML
<div class = "header">
  <ul>
    <li>
  <!-- 省略 -->
    </li>
  </ul>
</div>
```

通常、CSSでこのセレクタに何か効果を与えようとすれば下記のようになります。

```CSS
.header {
  width: 100%;
}

.header ul {
  padeding: 5px;
}

.header ul li {
  font-size: 10px;
}
```

このような記述をSassの場合では、入れ子構造で記述できます↓

```SCSS
.header {
  width: 100%;

  ul {
    padding: 5px;
    li {
      font-size: 10px;
    }
  }
}
```

もし、class名の変更などがあった際は一番上のhedderだけを変更するだけで、子になっているセレクタも変更されるのでわざわざ全てを書き直す必要がなくなります。

##変数
Sassでは変数の定義ができます。
変数の定義の仕方はこうです。↓

```SCSS
$my-color: #26546a;
```
このように定義すると下記のように使えます。

```SCSS
$my-color: #26546a;

h1 {
  color: $my-color;
}

p {
  color: $my-color;
}
```

##終わりに
今回は簡単にSassについてと、一部の機能を紹介しました。
Sassには**mixin**というとても便利な機能があるのですが、次回の記事でmixinについてまとめたいと思います。
[pydantic の基礎] よくあるエラーと nested model を一発でインスタンスにするコツ

nestしてくとこんがらがるのでmemo

pydantic の 基礎から行きます

# BaseModel

これでモデルを作れる。dictを入れて使うときは `**` をつけて keyword arguments に展開させる。

## keyword arguments とは

よくわかってないけど多分こんな感じ。 コロン式がイコール式になる

```py
# dictの場合
{ "a": 1 }

# keyword argumentsの場合
(a=1)
```

## 1. BaseModel
 
```py
from pydantic import BaseModel

# 作りたいもの、goal
{
    'name': 'a'
}

# model
class A(BaseModel):
    name: str

## モデルへの値の入れ方
# 1. object方式
obj = A(name="a")

# 2. dict方式
obj = A(**{"name": "a"})

# 3. dictのままいれるとエラー TypeError: __init__() takes exactly ....
>>> A({"name": "a"})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pydantic/main.py", line 397, in pydantic.main.BaseModel.__init__
TypeError: __init__() takes exactly 1 positional argument (2 given)


# 使い方
obj.dict()   # {'name': 'a'}     <--- type=dict
obj.json()   # '{"name": "a"}'     <--- type=str
```

`TypeError: __init__() takes exactly N positional argument(N given)` これは dict だめだぞ！ あるある。


# 2. Nested Model
nestするときは複数classにする

```py
# 作りたいもの
{
    'a': {
        'root': 1
    }
}

# model
class A(BaseModel):
    root: int
class B(BaseModel):
    a: A

# 1. 子供のmodel使う方式
obj = B(a=A(root=1))

# 2. 子供はdict方式
obj = B(a=A(**{"root": 1}))

# 3. 全部dict方式
obj = B(**{'a': {'root': 1}})

# 使い方
obj.dict()   # {'a': {'root': 1}}     <--- type=dict
obj.json()   # '{"a": {"root": 1}}'    <--- type=str
```

# 3. Deeper nested model
さらにnestさせると、dictとか こんがり始めます

```py
# 作りたいもの
{
  'c': {
     'b': {
        'a': 1
     }
  }
}

# model
class A(BaseModel):
    a: int
class B(BaseModel):
    b: A
class C(BaseModel):
    c: B


# 1. 子供のmodel使う方式
obj = C(c=B(b=A(a=1)))

# 2. 全部dict方式
obj = C(**{"c": {"b": {"a": 1}}})

# 3. 子供はmodelだけどdictで入れたい時
objA = A(a=1)         # {'a': 1}
obj = C(**{"c": {"b": objA.dict()}})   # <----- modelはdictにしながら代入

# 4. 実は dict にしなくても動く
obj = C(**{"c": {"b": objA}})



# 使い方
obj.dict()     # {'c': {'b': {'a': 1}}}
obj.json()     # '{"c": {"b": {"a": 1}}}'
```


# まとめ

1. nestされたmodelを使うときは、値を入れるときに object / dict を統一するように気をつける。
1. `TypeError: __init__() takes exactly ....` はとにかく いれる値が間違ってるってこと
SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: nodename nor servname provided, or not known 解決方法

今回はこちらのエラーを解決した方法についてご紹介します！

```
SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: nodename nor servname provided, or not known
```

##エラーが発生した流れ
ここ数日間ポートフォリオのテストコードを実装していて、ターミナルでテストを実行したところエラー発生！

その後、ブラウザからポートフォリオにアクセスしてみたのですが、何故かいつもアクセスしていたURL（127.0.0:8000)でアクセスすると接続拒否されるように。。。

エラーについて調べてみると、.envとdocker-compose.ymlの設定が間違っている可能性があるとのこと。

ですが、ここ数日間はテストコードの実装しかしていなく、.envやdocker-compose.yml等はいじっていなかったので全くもって原因不明でした。

そこで個人で契約しているメンターの方に相談しながら以下の手順で解決しました！

##解決方法
1.現在のプロジェクトのコンテナを削除

```
$ docker-compose down
```

2.docker-compose.yml webのportsを8000に変更

```
web:
    ports:
      - 8000:80
```

3.コンテナ再作成

```
$ docker-compose up -d --build
```

4.ブラウザから127.0.0:8000でアクセス確認
→エラー発生！

```
UnexpectedValueException
There is no existing directory at "/Users/yusei/Desktop/laravel-zaikokanri/backend/storage/logs" and it could not be created: Permission denied
http://127.0.0.1:8000/
```

5.下記コマンド実行

```
$ php artisan cache:clear
$ php artisan route:clear
$ php artisan config:clear
```
6.再度アクセス確認 （成功！）
7.テストの実行確認　(成功！）
NestJSのコントローラーのレスポンスにHTTPステータスコードを追加する

#@Resを使うとステータスコードを追加できる
https://docs.nestjs.com/controllers

上記サイトより引用
>We can use the library-specific (e.g., Express) response object, which can be injected using the @Res() decorator in the method handler signature (e.g., findAll(@Res() response)). With this approach, you have the ability to use the native response handling methods exposed by that object. For example, with Express, you can construct responses using code like response.status(200).send().

ライブラリ固有の（Expressなど）レスポンスオブジェクトを使用できます。これは、メソッドハンドラシグニチャの中で@Res（）デコレータ（findAll（@Res（）応答）など）を使用して挿入できます。このアプローチでは、そのオブジェクトによって公開されているネイティブのレスポンス処理メソッドを使用できます。たとえば、Expressでは、response.status（200）.send（）のようなコードを使用して応答を作成できます。

#実際のコードの簡単な例

```javascript:
import {Response} from "express";

@POST("findList")
async findList(@Res() res :Response){
res.status(401).json({message:"you are not allowed to call this api"});
}
```
【windows】windows10のシステムチェック＆修復

自分用のメモとして残します。

windowsUpdateに失敗しまくるので、システムチェックのコマンドをメモ。

#「sfc /scannow」でとりあえず確認
こっちの方が検証早く、とりあえず感覚でできる。

```shell
sfc /scannow
```

#DISMでがっつりスキャン＆修復
sfc /scannow で修復できなかったら試す価値あり。
1時間以上かかる場合もあり。

```shell
DISM /Online /Cleanup-Image /RestoreHealth
```




以上。
【AWS】EC2踏み台サーバー経由でプライベートサブネットのDBに接続する

#SSHトンネルが簡単

下記のコマンドでsshトンネルを作成します。

```shell
ssh ec2-user@踏み台のhostname -i pemファイルのパス　-L 3306:DBのhostname:3306
```
今回は例としてmysql(aurora)に接続します。
別のシェルで、以下のコマンドでmysqlに接続します。
ホスト名を127.0.0.1ではなくlocalhostにすると、エラーが発生する場合があります。
（ソケット接続か、TCP接続かの問題らしい）

```
mysql　-h 127.0.0.1 -P 3306 -u DBのユーザー名　-p
```

#接続成功！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659469/eccfb701-f923-feee-f2d3-4f0d3ce7e53e.png)

バックエンドの開発の際にも、127.0.0.1でDBに接続できるので便利です。
情報通信初めての人にSQLを教える時に使っていただきたいクラスをpythonで作ってみた

```python3
from 初めてのSQL import *

データベース = 'データベース.db'
橋 = プログラムとの間に橋を架ける(データベース)
スタッフ = 橋.を渡ってデータベースのスタッフを呼んでくる()
スタッフ.に指示を与える('CREATE TABLE items(id INTEGER PRIMARY KEY AUTOINCREMENT, name STRING, price INTEGER)')
橋.に向かってGOサインを出す()
橋.をぶっ壊す()
```

こんな感じのプログラムでデータベースへの接続からSQLの実行、接続の切断ができたらわかりやすくないでしょうか。

尚、データベースへの接続については、「プログラム(あるいはユーザ)とデータベースの間に橋を架けるんだよ～」という例え話を用いております。

>我々とデータベースの間には元々大きな運河が流れているせいで、そのままではデータベースにあれこれ指示を出すことができない。
だから橋を架ける必要があるんだよ。
また、指示を出した後は橋を撤去するのが鉄則。
橋がいつまでも掛ったままだと、
>
- 他の人が同じデータベースへ橋を架けたいときに、スペースが足りないせいで架けられない
- データベースからしてみれば、いつ命令されるかわからなくて精神的に大きな負担
>
など、いいことないよね、

とでも説けば、コネクションの考え方を大まかに教えられるのではないでしょうか。

また、カーソルを「データベースに勤める営業マン」に例えています。
こうすることで、「コネクションからカーソルを取得する」ことを、

> 我々とデータベースとの間に橋を架けたから、データベースの営業マンに来てもらうんだよ。
この営業マンに指示を与えることで、データベースを操作できるっていうわけだ。

と説明できるでしょう。

また、`橋.に向かってGOサインを出す()`というのは、コミットを行うためのものです。

こうすることで、

> 指示の内容によっては、営業マンに伝えてもデータベースはすぐにその指示を実行してくれないんだ。
慎重を期す必要があったりするからね。
この場合、橋に向かって合図を送ることで、「御社の営業マンに伝えた指示を、実行してください」って、もう一回言わなければいけないんだ。

などと、コミットの概念を説明することができます。

```python:初めてのSQL.py
import sqlite3

def プログラムとの間に橋を架ける(データベース):
# 「プログラムとデータベースの間に橋を架ける」という例え話は
    return 橋Type(sqlite3.connect(データベース))
    # 実際にはデータベースへ接続し、「接続オブジェクト」を取得することを意味しています。

class 橋Type:
    def __init__(self, conn):
        self.__conn = conn
    def を渡ってデータベースのスタッフを呼んでくる(橋):
    # 「橋を渡ってデータベースのスタッフを呼んでくる」という例え話は
        return スタッフType(橋.__conn.cursor())
        # 実際には接続オブジェクトから「カーソル」と呼ばれるオブジェクトを取得することを意味しています。
    def をぶっ壊す(橋):
    # 「橋をぶっ壊す」という例え話は
        橋.__conn.close()
        # 実際には接続を切断することを意味しています。
    def に向かってGOサインを出す(橋):
    # 「橋に向かってGOサインを出す」という例え話は
        橋.__conn.commit()
        # 実際には「データベースにコミット命令を送るために接続オブジェクトにその手続きを行わせること」を意味しています。

class スタッフType:
    def __init__(self, cur):
        self.__cur = cur
    def に指示を与える(スタッフ, 指示):
    # 「スタッフに指示を与える」という例え話は
        return スタッフ.__cur.execute(指示)
        # 実際には「データベースへSQL文を送るためにカーソルにその手続きを行わせること」ことを意味しています。
    def が結果を報告する(スタッフ):
        return list(スタッフ.__cur)

```
よくわからないコマンドの正式名称

### 目的

よく実行するコマンドの意味がわかればきっと何をやるコマンドかより理解が深まるのでその目的で本記事を記載する

- pwd 
 - print working directory
 →__作業ディレクトリをprint(表示)するよ__

- ls
 - list segments→__全体を分割したもの(セグメント)をリスト表示するよ__

- getcwd
 - Get current Working Directory→__カレント作業ディレクトリをgetするよ__

- wc
 - word count→__単語をカウントするよ(これはわかりやすい)__

- lsof
 - list open files→__開いているファイルをリストで表示するよ__

- cat
 - concatnate→__連結させるよ(ファイルの中身を見るコマンドじゃなくて本来連結させるのが主目的のコマンド)__



- sudo 
 - substitute user do→__スーパーユーザdoだとずっと思っていたけどsubstitute(代わりの)ユーザdoだったよ__
ドメイン駆動設計とは

# 背景

昇進面接で「ドメイン駆動設計とは何か？」と聞かれて、わかり易く説明できなかった反省を踏まえて、本稿を執筆することにしました。
~~無事、昇進できました。~~

# ドメイン駆動設計とは？
ドメイン駆動設計とは、ソフトウェア設計の手法です。
設計に時間と労力が掛かる分、多くのメリットを享受することができます。
例えば、ソフトウェアの修正や機能の追加がラクになり、バグの混入も減らすことができます。
変化を前提とするアジャイル開発では、ソフトウェアの改善を繰り返します。
そのため、ドメイン駆動設計を上手く取り入れることで、開発工数の大幅な削減に繋がります。

# ドメイン駆動設計が向いているものとそうでないもの

ドメイン駆動設計は、解決する方法が複雑となる場合に有効です。
例えば、複雑な業務ロジックを組む必要があるシステムなどが挙げられます。
一方で、シンプルな場合にはドメイン駆動設計の労力に対して見合わないため、向いていません。

# ドメイン駆動設計でまず必要なもの

ドメイン駆動設計では以下の２つのモデルが必要です。

- ドメインモデル：特定領域の問題を解決するためのモデル
- データモデル：データの永続方法を決めるモデル

ドメイン駆動設計は、これらモデルを作ることから始まります。


# モデリングする方法

ユースケース図とドメインモデル図を作成することで、モデリングします。
他にもモデリング手法はあるみたいですが、この２つが手軽にできて良いみたいです。

## ユースケース図とは

まずアクターとしてユーザーの種類を定義します。
そして、ユースケースとして「〇〇を××する」という形式でシステムの振る舞いを定義します。
ユースケースが具体化されないと、解決するべき問題が明確になりません。
ユースケース図を作成した上で、どのユースケースをソフトウェアに落とし込むかスコープを決めることが重要です。
スコープを定義することで、やること／やらないことが明確にできます。

ユースケース図のサンプル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533960/20ced674-3267-2df7-2ba3-ee6ff65f5bb8.png)



## ドメインモデル図とは

書き方は色々とあるので、開発メンバーと相談して決めましょう。

本記事を執筆していたら、既にまとめられていることに気付きました。
下記を参考にしましょう。

https://qiita.com/little_hand_s/items/dfa4b156f533ba1a1491


## 参考文献

この記事は以下の情報を参考にして執筆しました。

- [ドメイン駆動設計 モデリング/実装ガイド](https://booth.pm/ja/items/1835632)
生産現場IoTへの挑戦 #05.5 データベースとか全く知らない人がコピペだけで乗り切るクエリの覚書

#1.はじめに
IoTにあこがれて、ちょっとイキってMariaDB使い始めたけど、DB全くわからんちんでデータ取り出すのも一苦労なので一度使ったクエリをとにかく貯めていく

#2.とにかく貯めてく

```sql
SELECT * FROM TimeRecord WHERE TIME BETWEEN  "2021-6-2 00:00:00" AND "2021-6-3 00:00:00";
```
TimeRecordテーブルのTimeってカラムを見て指定期間内のレコードを引っ張り出す。Timeはdatetime型


```sql
SELECT * FROM test WHERE DATE_FORMAT(EnvTime,"%i") = "00" AND DATE_FORMAT(EnvTime,"%s") = "00";
```
testテーブルのEnvTimeカラムを見て、00分00秒のときのデータだけを抜き出す。
調子に乗って5秒置きにデータ取ったのはいいけど、１日で17,280レコードも溜まってしまうので、一週間とか一カ月間の気温推移を見てられねーって時用。
FlutterのDartからWebViewへ画像を送るにはData URIを使う

最近FlutterをはじめましたがWidgetの挙動がよくわからず困ってます。仕方ないので邪道だけどFlutterアプリにWebViewを貼り、Dartプログラムで生成したHtmlを表示するようにしてしのぎました。そのときに使ったDart側からWebViewに画像を渡す方法を紹介します。

####DartからWebViewへのテキスト転送
WebViewクラスにセットされるWebViewControllerのevaluateJavascriptを使うと、WebViewで表示しているhtmlテキスト中のJavascript関数を実行することができます。evaluateJavascriptは送った文字列をそのまま解釈して実行するので、パラメータ込みの文字列を送ればテキスト情報をWebView側に送ることができます。

たとえばWebView側に次のような関数がセットされていたとします。idで指定されたimgタグのsrcを書き換えるものです。

```html
<script>
function putimg( id, url ){
    document.getElementById( id ).src = url;
}
</script>
```

これをDartから次のようにコールしてやると、WebView上のid:img00の画像を書き換えることができます。

```dart
 webviewcontroller.evaluateJavascript("putimg('img00','http://example.com/icon.jpg');");
```
####Data URI 
HTTPサーバーにある画像ならこれでOKです。Dart内部データとか外部サーバーでもAPI経由でないと取得できないような場合は、Dartのプログラムで取得したバイナリーデータをData URIに変換すれば送ることができます。Data URIとは詳しくはWikiなど見て欲しいのですが、バイナリーデータをBase64でテキスト化して、"data:image/jpeg;base64," などのヘッダをつける処理です。FlutterにはUri.dataFromBytesというメソッドあります。
　WebViewにDartで作成したHtmlを送るときもData URIに変換する必要がありますが、テキストをData URIに変換するには、Uri.dataFromString というメソッドを使います。メソッドを間違えるとVSCodeごと落ちたりするのでご注意ください。

```dart
    var response = await http.get(uri);
    var dataurl = Uri.dataFromBytes(response.bodyBytes, mimeType: 'image/jpeg');
    webviewcontroller.evaluateJavascript("putimg('img00','"+ dataurl +"');");
```
https://ja.wikipedia.org/wiki/Data_URI_scheme

####WebView表示と画像取得を並行して行う
Dartで表示するHtmlを生成するときに、最初からData URI形式で画像を埋めこんでおくことも可能です。ただし、画像の取得に時間がかかったり、しかもそれが複数あるような場合は、全部の画像の取得が終わってからようやくHtmlが転送されるので画面が真っ白な状態が長く続きます。まずHtmlを表示させておいて、後から順に画像にアクセスし、取得できたタイミングでevaluateJavascriptで漸次WebViewに画像を転送するようにすると、とりあえず画面に何かでるまでの時間を短くできます。

以下のようなJSON形式の画像のリストが itemlistに入っているとします。
[ 
{id:'a01', src:'http://example.com/a01.jpg'},
{id:'a02', src:'http://example.com/a02.jpg'},
]
この画像一覧をWebViewに表示するには、WebViewのonWebViewCreated:パラメータで指定するコールバックの中で以下のように処理します。

```dart
onWebViewCreated: (WebViewController webViewController) async {
        // まずHtmlを作成
        String html = "<html><head><script>function putimg(id,src){document.getElementById(id).src=src;}</script></head><body>";
        for( var item in itemlist){
          html = html + item['id'] +" <img id='"+item['id']+"' /> <br/>\n";
        }
        html = html + "</body></html>";
        // HtmlをData URIに変換してサーバー経由しないで取得できるようにする
        final fileurl = Uri.dataFromString(
            html,
            mimeType: 'text/html',
            encoding: Encoding.getByName('utf-8')
        ).toString();
        // それをWebViewで表示
        webviewcontroller.loadUrl( fileurl );

        // 一覧から画像をダウンロードし、Data URIでWebViewに転送
        for( var item in itemlist){
          http.get(Uri.parse(item['src'])).then((response) { 
            var dataurl = Uri.dataFromBytes(response.bodyBytes, mimeType: 'image/jpeg').toString();
            webviewcontroller.evaluateJavascript("putimg('"+ item['id'] +"','"+ dataurl +"');");
          });
        }
}
```


https://qiita.com/official-events/d523df99d6479293ffa7
【GCP】GMECとは

#エッジとは
・利用者に近い場所でサービスを提供できるエッジ（MEC: Multi-access Edge Computing）のこと
・米アマゾン・ウェブ・サービス（AWS）や米マイクロソフト（Microsoft）、米グーグル（Google）といった大手クラウド事業者が、5G（第5世代移動通信システム）を契機に通信事業者（キャリア）のネットワークに接近してこちらを進めようとしている。

#5Gについて
・４G/LTEが一般のモバイルユーザーを対象としていたのに対して5Gは企業をターゲットとしている


#戦略
・グーグルの新戦略「Global Mobile Edge Cloud（GMEC）」
・同社が通信事業者らと共同で、5Gネットワーク上のユニークなアプリケーションやサービスの構築を目指すもの
・グーグルが掲げるビジョンは、GCP（グーグル クラウド プラットフォーム）が使える最先端のエッジコンピューティングの基盤を通信事業者に提供すること

#イメージ
![KDDI.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/f2da1ed6-abf7-65bb-0cac-3fb14fae3463.png)

ここのWavelenghの部分をGoogleのGMECに置き換えるような感じ？

#関連記事
https://forbesjapan.com/articles/detail/33173
https://xtech.nikkei.com/atcl/nxt/column/18/01273/00005/
https://jp.techcrunch.com/2021/10/13/2021-10-12-google-goes-all-in-on-hybrid-cloud-with-new-portfolio-of-edge-and-managed-on-prem-solutions/
本格的に打ち出してきた

#公式ドキュメント
https://cloud.google.com/blog/ja/products/gcp/google-cloud-unveils-strategy-telecommunications-industry
Jamstackセミナー開催予定

今回はBejamas社のブログ記事のご紹介ではなく
無料のJamstack_Webセミナーについて告知させていただきます:loudspeaker:

2021年7月6日（火）15時00分〜16時30分で
Jamstackのデモを見ていただきつつ、
「Webサイト改善」をテーマにお話しさせていただきます。

:warning:詳細はConnpassでの告知をご確認ください:warning:
https://connpass.com/event/215681/

最新のWeb開発事情にご興味のある方は、良ければご参加ください:bow_tone2:
CSS関連走り書き

#はじめに
TailwindCSSネタ流行に便乗した走り書き。時間が出来たらプロット化、正書化するかも。

#駄文
* tailwindCSSへの反発と文書構造とデザインの分離
* 関心の分離として、文書構造とデザインの分離のみを言うのは正しいのか
* （一般に想定される）文書構造とデザインの分離は、コンポーネントの内面を侵している
* コンポーネントに閉じる事による関心の分離とインラインデザイン
* コンポーネント指向はWeb文化よりデスクトップアプリに近い
* 独自デザインのバグの多さ
* デスクトップアプリの傾向
 * デザインをより広範なユーザーを持つGUI環境側のテーマ機能に委ねる、アプリ側では弄らない
 * コンポーネントも最低限のデザインで、そのまま再利用、独自デザインは地雷
* 多くのCSSフレームワークはもはや独自のGUIツールキット
* デザインもコンポーネントで閉じる事による関心の分離
* 大手Webアプリも操作や表示上の問題が多くデスクトップアプリに劣る。そもそもWebアプリのデザインは過剰ではないか、Web文化のままで正しいのか
* レスポンシブ対応による最低限のデザインの必要性
  * ユーティリティは、CSSに不足しているレスポンシブを含む最低限の理論分類、抽象化として利用できる
* TailwindCSSは多少バグ出しされてる共有ライブラリ。コンポーネントより大きい単位で弄らない方が良い
* ユーティリティファーストは文書構造とデザインがより直交する、より小さくシンプルな部品を組み合わせる。よりClojure的、あるいは高階関数的なのではないか
  * ただの集合に名前も型定義もいらない
  * 一般的なCSS設計はisであり、ユーティリティファーストはhasである。
  * オブジェクト指向設計は名詞の王国、ユーティリティファーストは動詞の王国
  * hasはisよりも小さな部品であり、より再利用を前提とする
     * 余談： isはhasの集合か、チューリングテスト、行動科学、人間、哲学的ゾンビ
  * デザイン4大原則での命名の不要と性質としてのhas
     * cf.トゲを持つ物は踏めない、トゲゾーかトゲメットかというisによって変わらないデザイン的に意図されたhasである
  * 同じ物を同じように、異なる物を異なるように。オブジェクト指向と分類学の難解性
  * isよりhasの方が小さく、デカルトの分析の規則に適う
  * ユーティリティーはデザインの意図を、背景の理論をより分割し表記できる小さく単純な部品である
* ある物が何々であり何々のデザインはこれこれであるはクラスベースに似る、ユーティリティファーストはデザインを外部から渡す高階関数スタイルに似る
  * 関数スタイルの方がよりデカルトの分析の規則に合致する小さな部品概念であり、糊付け・合成・思考もデカルトの総合の規則に合致するため容易である
* ドキュメントビューアーたるブラウザーのGUIアプリへの流用は何でもExcel文化か
* ホームページ対コンポーネント指向、ついでに関数指向
  * Reactは関数型を指向しているが、現在のCSS設計はオブジェクト指向を背景にしたままである
     * 余談： Reactにはコンポーネント指向の後を引いて、elm等の関数型に比べて設計単位が大きい傾向を感じる
* CSS設計はオブジェクト指向系が人気だが、オブジェクト指向自体の評価が下落中
* アトミックデザインは理論的な背景基盤が皆無、混乱させるだけなので使わない方が良い
* CSSの仕様は場当たりに過ぎる、特にアプリ構築には向かない、BEM等も本来バッドノウハウ、将来的には再構築必須

#推奨URL
https://boxofpapers.hatenablog.com/entry/simple_made_easy
http://www.syugo.com/4th/thermidor/work.php?author=descartes&work=discours_de_la_methode
https://kazu-yamamoto.hatenablog.jp/entry/20080722/1216734420
https://qiita.com/oedkty/items/81e405aa2b18670ab028
https://www.sampou.org/haskell/article/whyfp.html
https://qiita.com/Takazudo/items/78ee15564bfefdea844c
https://yuheiy.hatenablog.com/entry/2020/05/25/021342
https://yuheiy.hatenablog.com/entry/2020/05/06/213311
https://qiita.com/70ki8suda/items/76209ea566bab4ba1268
【Rails】Rubocopの導入

# 目的
Railsで作成したアプリに`Rubocop`を導入する。

# 開発環境
macOS: *Big Sur*
Rubyバージョン: *2.6.5*
Railsバージョン: *6.0.0*

# 前提

- `アプリ`が作成されている。
[【Rails】簡単な投稿アプリの作成](https://qiita.com/oak1331/items/18a4f3a3386aab0fa354)

# 手順

1. [はじめに](#はじめに)
1. [Rubocopの導入](#rubocopの導入)
1. [Rubocop設定ファイルの作成](#rubocop設定ファイルの作成)
1. [Rubocopの設定](#rubocopの設定)
1. [Rubocopの実行](#rubocopの実行)

# はじめに

今回は`Rubocop`の導入を行っていきます。
`Rubocop`とはRubyの静的コード解析ツールのことです。
「インデントが揃っていない」「余分な改行・スペースがある」などの指摘を行ってくれるため、コードの品質を保つことができます。

# Rubocopの導入

それでは早速始めていきます!

まずGemをインストールします。

```ruby:Gemfile
group :development do
  gem 'rubocop', require: false
end
```

```:ターミナル
% bundle install
```

これでインストールできました!

# Rubocop設定ファイルの作成

次に`Rubocop`の設定を記述するファイルを作成します。

```:ターミナル
% touch .rubocop.yml
```

# Rubocopの設定

続いて`Rubocop`の設定を行っていきます。

```ruby:.rubocop.yml
AllCops:
# 除外するディレクトリ（自動生成されたファイル）
# デフォルト設定にある"vendor/**/*"が無効化されないように記述
 Exclude:
   - "vendor/**/*" # rubocop config/default.yml
   - "db/**/*"
   - "config/**/*"
   - "bin/*"
   - "node_modules/**/*"
   - "Gemfile"


# 1行あたりの文字数をチェックする
Layout/LineLength:
 Max: 130
# 下記ファイルはチェックの対象から外す
 Exclude:
   - "Rakefile"
   - "spec/rails_helper.rb"
   - "spec/spec_helper.rb"

# RSpecは1つのブロックあたりの行数が多くなるため、チェックの除外から外す
# ブロック内の行数をチェックする
Metrics/BlockLength:
 Exclude:
   - "spec/**/*"

# Assignment: 変数への代入
# Branch: メソッド呼び出し
# Condition: 条件文
# 上記項目をRubocopが計算して基準値を超えると警告を出す（上記頭文字をとって'Abc'）
Metrics/AbcSize:
 Max: 50

# メソッドの中身が複雑になっていないか、Rubocopが計算して基準値を超えると警告を出す
Metrics/PerceivedComplexity:
 Max: 8

# 循環的複雑度が高すぎないかをチェック（ifやforなどを1メソッド内で使いすぎている）
Metrics/CyclomaticComplexity:
 Max: 10

# メソッドの行数が多すぎないかをチェック
Metrics/MethodLength:
 Max: 30

# ネストが深すぎないかをチェック（if文のネストもチェック）
Metrics/BlockNesting:
 Max: 5

# クラスの行数をチェック（無効）
Metrics/ClassLength:
 Enabled: false

# 空メソッドの場合に、1行のスタイルにしない　NG例：def style1; end
Style/EmptyMethod:
 EnforcedStyle: expanded

# クラス内にクラスが定義されていないかチェック（無効）
Style/ClassAndModuleChildren:
 Enabled: false

# 日本語でのコメントを許可
Style/AsciiComments:
 Enabled: false

# クラスやモジュール定義前に、それらの説明書きがあるかをチェック（無効）
Style/Documentation:
 Enabled: false

# ％i（）構文を使用していないシンボルで構成される配列リテラルをチェック（無効）
Style/SymbolArray:
 Enabled: false

# 文字列に値が代入されて変わっていないかチェック（無効）
Style/FrozenStringLiteralComment:
 Enabled: false

# メソッドパラメータ名の最小文字数を設定
Naming/MethodParameterName:
 MinNameLength: 1
```

以上で設定が完了しました。

# Rubocopの実行

`Rubocop`を実行するには、下記コマンドを打ちます!

```:ターミナル
% bundle exec rubocop
```

また下記コマンドでは、チェック内容を自動で修正させることもできます。

```:ターミナル
% bundle exec rubocop -a
```

# 最後に

以上で`Rubocop`の導入は完了です。
では。
[fluentd][Amazon Linux2] php-fpm のエラーログに Fatal Error が出現したらメール送信する

メモです。
Fluentd の連携先としてメールしか選べないシステムだったので...

## Amazon Linux2 への fluentd のインストール

```
curl -L https://toolbelt.treasuredata.com/sh/install-amazon2-td-agent4.sh | sh
sudo td-agent-gem install fluent-plugin-mail
```

## /etc/td-agent/td-agent.conf

```
<source>
  type tail
  path /var/log/php-fpm/error.log
  tag php-fpm.error
  pos_file /var/log/td-agent/php-fpm-error_log.pos
  format none
  read_from_head true
</source>

<source>
  type tail
  path /var/log/php-fpm/www-error.log
  tag php-fpm.www-error
  pos_file /var/log/td-agent/php-fpm-www-error_log.pos
  format none
  read_from_head true
</source>

<match **>
  @type copy
  <store>
    @type stdout
    @id @all.logging
  </store>
  <store>
    @type relabel
    @label @handle.error
  </store>
</match>

<label @handle.error>
  <filter **>
    @type record_transformer
    <record>
      host ${hostname}
    </record>
  </filter>

  <filter **>
    @type grep

    <regexp>
      key message
      pattern /Fatal error/i
    </regexp>
  </filter>

  <match **>
    @type mail
    host localhost
    port 25
    from no-reply@example.com
    to alert@example.com

    subject "PHP Fatal Error"

    out_keys host, message
  </match>
</label>
```

source は `/var/log/php-fpm/error.log` と `/var/log/php-fpm/www-error.log`

stdout と @handle.error に copy

`@type record_transformer` で host レコードを追加

`@type grep` で `Fatal error` が含まれる行だけを抽出

`@type mail` でメール送信
PowerShellからSQLコマンドを実行する方法

# PowerShellからSQLコマンドを実行する方法

##環境

Windows10
PowerShell7.1.0
SQLServer2014R2

##インストール
はじめにPowerShellをインストールします。

https://docs.microsoft.com/ja-jp/powershell/scripting/install/installing-powershell-core-on-windows?view=powershell-7.1


##PowerShellの実行

キーボードのWindowsキーとRを同時に押下して、ファイル名を指定して実行のダイアログを表示します。

PWSHと入力して、PowerShellを実行します。
（この際に、Shift+Ctrlを押しながらEnterで実行すると管理者権限で起動することが出来ます。）

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1667007/29732cfa-1ce4-1c83-0868-5088e1c2584e.png)

##SQLコマンドモードの実行と終了

PowerShellの窓が開いたら、sqlcmdと入力します。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1667007/b5099d64-6568-02fa-5667-e45e74ba26e9.png)

先頭が1>に表示が変わったのを確認したら、これ以降で、SQLクエリを実行することが出来ます。
1> は sqlcmd プロンプトであり、行番号を表しています。 
Enter キーを押すたびに、この番号が 1 ずつ増えます。
(sqlcmd セッションを終了するには、 sqlcmd プロンプトで「 EXIT 」と入力します。)

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1667007/b5a19d1a-a92d-1b96-e5c3-f3e7de27fdae.png)

##SQLServerへの接続

ここでは、WWALMDBというDBに接続します。

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1667007/5aa3364e-46d9-9c4e-6cfa-013a312cc28d.png)

接続先がWWALMDBになったことを確認します。

![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1667007/5de1b518-ef0a-f2fc-a894-9c9e17708d00.png)

##Transact-SQLクエリの実行

上位10件のSELECTを実行します。

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1667007/b104e205-bcd0-8a88-3978-fc34bb77d095.png)


そのままだとレイアウトが崩れているので、幅を指定します。

公式サイトより

-w column_width　
出力用の画面幅を指定します。 このオプションにより、 sqlcmd スクリプト変数 SQLCMDCOLWIDTH が設定されます。 列幅は 8 よりも大きくかつ 65,536 よりも小さい値にする必要があります。 指定した列幅が範囲外の場合、 sqlcmd はエラー メッセージを生成します。 既定の幅は 80 文字です。 指定した列幅を超えると、出力行は次の列に折り返されます。

-W　(remove trailing spaces)
このオプションは、列から後続の空白を削除します。 他のアプリケーションにエクスポートするデータを準備するときは、 -s オプションと同時にこのオプションを使用します。 -y または -Y オプションと共には使用できません。

はじめに、SQLモードに入るところで「sqlcmd -W」のパラメータを付けます。

![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1667007/af90debe-a9b7-8008-8771-6de9c1e2c384.png)
PythonでRemoEから消費電力を取得する方法

#目的
Nature RemoEに登録したスマートメーターから消費電力データを取得する。

#方法
ざっくりの流れは以下の通りです。

1. [Nature Remo Cloud API](https://swagger.nature.global/)のGET /1/appliances というエンドポイントを叩く
2. smart_meterというプロパティからepcとvalを取得する
3. 正方向の積算電力量に係数を掛けて、単位変換を行う
4. 任意の期間の積算電力量の差分をとる

それでは、コードを載せながら、それぞれ詳しく説明していきます。

####[Nature Remo Cloud API](https://swagger.nature.global/)のGET /1/appliances というエンドポイントを叩く

APIは、HTTPクライアントがNatureのサーバへHTTPSリクエストを行うことで利用します。レスポンスはJSON形式です。認証、認可にはOAuth2を利用します。
APIを利用する際には、必ず以下のHTTPヘッダを付加する必要があります。

Authorization: Bearer {TOKEN}

{TOKEN} 部には、OAuth2を通して取得したアクセストークンを入れてください。

```python
# スマートメーター情報取得
def get_smartmeter_info():
    url = 'https://api.nature.global/1/appliances'
    headers = {'Authorization': 'Bearer ' + REMOAPI, 'accept':'application/json'}
    appliances = requests.get(url, headers = headers).json()
```

####smart_meterというプロパティからepcとvalを取得する
appliance(機器)情報にsmart_meterというプロパティが生えており、そこにさらに、echonetlite_propertiesという配列があるので、epcとvalを取得します。
epcとはECHONETプロパティのことで、機器の情報を取得するためのキーとなります。
valはプロパティの値を示します。ECHONET Liteのプロパティは任意の型の値を取るため、このフィールドの型は数値ではなく文字列であることに気をつけてください。


```python
# スマートメーター情報取得
def get_smartmeter_info():
    url = 'https://api.nature.global/1/appliances'
    headers = {'Authorization': 'Bearer ' + REMOAPI, 'accept':'application/json'}
    appliances = requests.get(url, headers = headers).json()
    
    # 電力情報を取得
    smart_meter_info = appliances[0]['smart_meter']['echonetlite_properties']
    sm_info = {}
    for item in smart_meter_info:
        key = item['epc']
        sm_info[key] = item['val']

    return sm_info
```

####正方向の積算電力量に係数を掛けて、単位変換を行う
epc224の積算電力量の単位がkWhではないので、係数と単位の反映が必要です。
係数はepc211、単位はepc225で値を保持しています。
単位については、値がそのまま単位になるわけではなく、読み替えが必要です。
どの値がどの単位に対応するかは下記のとおりです。

|値|単位|
|:|:|
|0x00|1kWh|
|0x01|0.1kWh|
|0x02|0.01kWh|
|0x03|0.001kWh|
|0x04|0.0001kWh|
|0x0A|10kWh|
|0x0B|100kWh|
|0x0C|1000kWh|
|0x0D|10000kWh|

必要な値を取得したら、それぞれの値を乗じることで積算電力量がkWhで求められます。

```python
# 正方向積算電力量計算
def calc_normal_direction_cumulative_electric_energy(normal_direction_cumulative_electric_energy, coefficient, unit):
    
    calc_result = float(normal_direction_cumulative_electric_energy) * float(coefficient) * float(unit)
    
    return calc_result

def lambda_handler(event, context):
    # スマートメーター情報取得取得
    sm_info = get_smartmeter_info()
    # 係数
    coefficient = sm_info[211]
    # 積算電力量計測値(正方向・買電)
    normal_direction_cumulative_electric_energy = sm_info[224]
    # 積算電力量単位
    cumulative_electric_energy_unit = sm_info[225]
    # 単位変換
    unit=0
    if cumulative_electric_energy_unit == '1': 
        unit = 0.1
    
    normal_electric_energy = calc_normal_direction_cumulative_electric_energy(normal_direction_cumulative_electric_energy, coefficient, unit)
```

###任意の期間の積算電力量の差分をとる
あとは上記積算電力量を定期的に取得し、任意の期間の差分をとることで、その期間の消費電力が求められます。

注意点として、電力量は積算値で表すわけですが、これはカウンター値であり、無限にカウントアップするわけではありません。
epc215は積算電力量有効桁数を示しています。たとえばこれが6だとすると、値域が、0-999999で、999999を超えると0に戻るという仕様です。また、これは係数情報などを乗じる前の生の値に対して適用されます。


#まとめ
PythonでNature RemoEに登録したスマートメーターから消費電力データを取得する方法を簡単に解説しました。上記の内容は公式情報を参考にしましたので、詳細は[こちら](https://developer.nature.global/jp/how-to-calculate-energy-data-from-smart-meter-values)からご確認ください。
ラップするコマンドの作り方

誰向けかわからないけど，ラップするコマンドを作る方法

## 目標とする状態

- 複数のコマンドが存在する．それら全てのラッパーコマンドを作りたい
    - 例えば，`/usr/bin/*` の全てに対して `~/local/bin` 配下に似たような名前のコマンドを作りたい
        - コマンド名は別名として，例えば `ls` に対しては `wrap_ls` のような名前のコマンドにする
        - 例えは，`ln -s /usr/bin/ls ~/local/bin/wrap_ls` みたいな状態にする．
        - `wrap_xx` は，元のコマンドを呼び出す可能性があるので，別名にするようにする．(`ls` という名前ではなく，`wrap_` を付ける)
- ラップするコマンドは，全て同じコマンドを呼び出して引数に元のコマンドが渡せるようにする．
    - 例えば，`wrap_ls` の中身は `echo ls` になっている．
- 引数を受け付けて上記コマンドに渡すようにする．
- ログインシェルから起動しない可能性があるので，alias では実装しない．

## 中身

```shell:wrapper.sh
#!/bin/sh

prefix=wrap
command=`basename $0 | sed -e 's/^${prefix}_//'`

echo $command "${@}"
```

```shell-session
$ for f in /usr/bin/*; do 
  ln -s wrapper.sh ~/local/bin/wrap_`basename $f`
done
```

## 実行確認

```shell-session
$ exa -1 wrap*
wrap_ls -> wrapper.sh
wrapper.sh
$ ./wrap_ls aaa
ls aaa
```
【Docker】 nodemonを使ってjsファイルの変更を反映させる no.17

![パンプキン カフェ (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/e3fc25d3-1ee2-cb7f-9b0f-8b2e2a9f3ca9.png)


こんにちは、まゆみです。

Dockerについての記事をシリーズで書いています。

前々回の記事から3記事連続で『-v』オプションについての記事を書いてきました。

-v でバインドマウントしたら、htmlファイルの変更がイメージをrebuildすることなしに反映されることは、[こちらの記事](https://qiita.com/Mayumi_Pythonista/items/15257212e0822b40a98a#1build-context-%E5%86%85%E3%81%AB%E3%81%82%E3%82%8B%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E6%9B%B4%E6%96%B0%E3%82%92%E3%82%AA%E3%83%B3%E3%82%BF%E3%82%A4%E3%83%A0%E3%81%A7container%E3%81%AB%E5%8F%8D%E6%98%A0%E3%81%95%E3%81%9B%E3%82%8B)に書かせていただきました。

ただ、<font color="Red">jsファイルの変更は-vオプションで、バインドマウントしても即、反映されません。</font>(nodeではなく、nodemonを使わない限り)

今回の記事では、nodemonを使ってContainer を実行するにはどのようにDockerfileを書かなければいけないのか、書いていきます


ではさっそく始めていきます。

#nodemonを使う

nodemon とはソースを監視して、自動でサーバーを再起動してくれるツールになります。

ソースコードに変更が加えられたら、nodemon自らがその変更に気づいてくれて再起動してくれるのです。

##package.jsonに書き加えること

では、nodemonをContainerで使うのに必要な事項をpackage.json に書き加えていきます

```
"devDependencies": {
    "nodemon": "2.0.4"
  }
```


```
"scripts": {
    "start": "nodemon server.js"
  },
```

これらのコードをpackage.jsonに書き加えると下記のようになります。

そして、package.jsonが変更された後saveしてください。

![2021-06-22_9-46-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/e0e4a586-996d-c048-573f-56f77c90bf05.png)

#Dockerfileを書き換えるところ

では次にDockerfileを書き換えていきます

```
CMD ["npm","start"]
```

上記のコードが意味するのは、Containerを起動させるとき、package.json"の中の"scripts"にある"start"で指示しているファイルを使ってくれということになります


![2021-06-22_10-10-16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/44fdb3a2-ff5d-344f-2866-20f72d198667.png)

#WSL2をWindowsで使っている方への注意点

WSL2を使っている方の場合、上記のようにDockerfileやpackage.jsonを書き換えても、jsファイルの変更が即反映されるようにはなりません。

```
 "scripts": {
    "start": "nodemon -L server.js"
  },
```
<font color="Red">package.jsonを上記のように書き換えて</font>ください。

『-L』が必要になります。

#jsファイルの変更がrebuildしなくても反映される


![2021-06-22_10-36-41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/7015ee50-31d0-d48c-c6f5-63a252697b21.png)

jsファイルにconsole.log()を書き加えて、その中のテキストを変更してみました。

```
docker logs <container ID>
```

を使うとコンテナからログを取得できます

![2021-06-22_10-52-28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/9bca303b-4524-c481-095a-514a2473ca05.png)

#まとめ

今回の記事はここらへんで締めくくらせていただきます。

お役に立てれば幸いです。
pythonにおけるキーワード引数について

#記事はあとから編集します
下記はpythonチュートリアルからの引用である。

 ```python
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
    print("-- This parrot wouldn't", action, end=' ')
    print("if you put", voltage, "volts through it.")
    print("-- Lovely plumage, the", type)
    print("-- It's", state, "!")


parrot(1000)                                          # 1 positional argument
parrot(voltage=1000)                                  # 1 keyword argument
parrot(voltage=1000000, action='VOOOOOM')             # 2 keyword arguments
parrot(action='VOOOOOM', voltage=1000000)             # 2 keyword arguments
parrot('a million', 'bereft of life', 'jump')         # 3 positional arguments
parrot('a thousand', state='pushing up the daisies')  # 1 positional, 1 keyword


parrot()                     # required argument missing
parrot(voltage=5.0, 'dead')  # non-keyword argument after a keyword argument
parrot(110, voltage=220)     # duplicate value for the same argument
parrot(actor='John Cleese')  # unknown keyword argument
 ```
https://docs.python.org/ja/3/tutorial/controlflow.html

初学者の私にとっては・・・という量のコードですが、よく見ると気づくことがありませんか？
変数にイコールがついています。こういったものを見たら、キーワード引数が使われているとまず認識しましょう。
もう少ししっかりいうと、関数に指定されている引数名を、関数呼び出し時に指定することで引数を明示するものです。

```java:title
code
```
SwiftUIでSearchBarを作ってみた

## はじめに
SwiftUIにSearchBarが無くて困ったので、自作してみました。
paddingやcornerRadius等の値は多少雑になっているので、気になる方は数値を調整してください。

## SerachBar

``` Swift
struct SearchBar: View {
    
    @Binding var text: String
    @State private var isEditing = false

    var onSearchButtonClick: () -> Void
    
    var body: some View {
        ZStack(alignment: .leading) {
            HStack {
                
                Image(systemName: "magnifyingglass")
                    .foregroundColor(Color(.lightGray))
                    .padding(.leading, 5)
                
                TextField("Search", text: $text,
                          onCommit: {
                            self.onSearchButtonClick()
                          }
                )
                .padding(.top, 5)
                .padding(.bottom, 5)
                .padding(.leading, -5)
                .onTapGesture {
                    self.isEditing = true
                }
                
                if isEditing {
                    Button(action: {
                        self.text = ""
                    }, label: {
                        Image(systemName: "multiply.circle.fill")
                            .foregroundColor(.gray)
                            .offset(x: -5)
                    })
                }
                
            }
        }
        .background(Color(.systemGray6))
        .cornerRadius(8)
    }
    
    public func onSearchButtonClick(action: () -> Void) -> some View {
        action()
        return self
    }
}

```

見た目はこれで完成ですが、キーボードのreturnKeyがデフォルトのままなので、変更します。

## returnKeyTypeを変更
ライブラリを追加

``` 
pod 'Introspect'
```

他の記事を見ていると、ライブラリなしでもできるみたいですが、自分の環境だと動作しませんでした。

SearchBarを呼び出すViewにて

```Swift
import SwiftUI
import Introspect

struct SomeView: View {
    @State var searchWord: String = ""
    
    var body: some View {
        SearchBar(text: $searchWord,
                  onSearchButtonClick: {
                    print("Did tap search button")
                  })
            .padding(.leading, 5)
            .padding(.trailing, 5)
            .introspectTextField { textField in
                textField.returnKeyType = .search
            }
    }
}

```

## 結果
![Simulator Screen Shot - iPod touch (7th generation) - 2021-06-22 at 10.43.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253564/07b234a2-ec62-143f-3ed9-770fed8fada1.png)

以上です。
Couchbase Serverにおけるインデックスとデータ更新との整合性（現代のシステムに求められる要件の観点から）


#### Couchbase Serverにおけるインデックス更新メカニズム

Couchbase Serverでは、インデックスはキューを介して非同期的に更新されます。そのため、インデックスの内容は、データよりも古い可能性があります。レプリカへの反映や、ディスクへ永続化については、これらも又キューを介して非同期に実行されるのがデフォルトの動作ですが、アプリケーションからの**データ更新時**に同期を強制する方法があります。一方、インデックスにはそのオプションがありません。インデックスとデータとの間の厳密な整合性の確保は、**データ読み込み時**に行います。インデックスとデータとの間の厳密な整合性は、必ずしも全ての場合において必要とされるわけではないこと、そして整合性の要否はデータ利用時のニーズ次第であることを考えると、これは合理的なメカニズムであると言えます。

#### 自分で書いたデータを自分で読む（Read your own writes）

インデックス、つまりクエリの結果と、データ更新との間に、厳密な整合性が必要とされるケースとして、自分で書いたデータを自分で読む（Read your own writes）場合があります。典型的な例として、アプリケーション上の操作が、何らかのデータのリスト画面が表示されている状態から始まり、そのリストの一行に当たるデータを追加・編集・削除した後に、同じリスト画面に戻る、というケースが考えられます。データの変更（追加・編集・削除）実行の直後に、リストは更新されることになります。その際に、データ更新とクエリが直列的に実行される結果として、クエリの結果に直前のデータ更新の内容が反映されない可能性が生じます。

#### システム要件の多様化に対する最適化の結果として

クエリの結果が最新のデータを反映していない可能性があると聞かされると、一般的なデータベースを使ったアプリケーションの開発に慣れた方にとって、奇異に感じるであろうことは容易に想像されます。この違いは、一般的なデータベースを使ったアプリケーションでは、インデックスの更新まで完了した後に、データベースでの更新処理完了としてアプリケーションに操作が戻り（APIコールからリターン）、その後にクエリ処理実行を行なっているのに対して、Couchbase　Serverを使っているアプリケーションでは、データ更新処理時、データベースのメモリレベルでの処理完了をもって、更新処理完了としてアプリケーションに操作が戻り、クエリの実行へ進めることができるためです。

このような違いについて、Couchbase Serverでは、データ更新は行うが、更新したデータを読む必要はない場合、あるいは、自分以外が更新したデータを利用する際に、システム全体として厳密に同期された最新のデータである必要がない場合、といった、システム/アプリケーションの適用領域が旧来のデータベースが想定していた範囲を超え、拡大している現代においては、実際上大多数を占めるケースについて、最適化が行われているということが言えます（結果として、エンドユーザーは快適な操作性を得ることができるでしょうし、企業にとっては、より良いサービス提供により差別化が行える他、リソースの最適化により、コストダウンにつながると言えます）。
そして、自分で書いたデータを自分で読む（Read your own writes）ケースや、システム全体として厳密に同期された最新のデータの利用といったニーズについては、これらを実現可能な方法が別に用意されています。

#### ミューテーション トークン（MutationTokens） 

自分で書いたデータを自分で読む（Read your own writes）場合、アプリケーション（データの利用者）にとって、自分が発行するクエリの結果として、クエリ/インデックスに反映されていなければならないデータの変更は、特定されているということが言えます。Couchbase Serverは、これをトークンとして表現しています。データ変更時に取得したトークンを、クエリ実行時に用いることにより、最小のオーバーヘッドで必要な整合性を確保することができます。

以下は、トークンを用いたコード例です。

```JAVA
token = collection.upsert( “key”, document, Options{} );

queryStr = “SELECT * FROM `retail-sample`”;

result = cluster.query( queryStr, Options{ ConsistentWith: token } );

```

トークンを使用すると、メタデータが追加されるために、トークンを用いない場合よりもネットワークにいくらかのオーバーヘッドが発生します

#### `ScanConsistency` オプション

自分で書いたデータを自分で読む（Read your own writes）場合ではなく、つまりトークンを用いずに、データとクエリの整合性をコントロールする方法として、クエリ実行時に`ScanConsistency` オプションを用いることができます。このアプリョンには、下記の三つのタイプがあります。


- `ScanConsistency.at_plus`：　インデックスが、**データ更新のタイムスタンプ**に対して更新されている事を保証して、クエリを実行します。インデックスの更新状況に遅延がある場合、クエリは追いつくのを待ちます。

- `ScanConsistency.request_plus`：インデックスが**クエリ・リクエストのタイムスタンプ**に更新されている事を保証して、クエリを実行します。インデックスの更新状況に遅延がある場合、クエリは追いつくのを待ちます。

- `ScanConsistency.not_bounded`：　どんな一貫性制約にも妨げられずに、クエリを直ちに実行します。インデックスの更新状況がデータ更新に対して遅延がある場合、古い結果が返されることがあります。


デフォルトの整合性は`not_bounded` です。