OmniAICreator/Qiita-1.07M huggingface dataset:
GASのHtmlService.createTemplateFromFile(template).evaluate()は何をしているのか

# Google App ScriptのHtmlService.createTemplateFromFile(template).evaluate()は何をしているのか
# まずはじめに
GoogleApp Script（以降GAS）でHTMLファイルを表示させる際に記載する「HtmlService.createTemplateFromFile(template).evaluate();」という長い式みたいなもの。「とりあえずこれを書けばHTMLが表示される」という認識で使っている人も多いと思います。私も最初は「HTMLファイルを表示してくれる魔法の文」と思って使用していました。それが嫌で今回はその魔法の文の正体を、自分なりに調べてまとめてみたので、備忘録がてら書いていきます。

# 分解してみる
まずは長い式みたいなものを分解して細かくみていきましょう。
HtmlService.createTemplateFromFile(template).evaluate()は
・HtmlService
・createTemplateFromFile(引数)
・evaluate()
の３つに分けることができます。

あえてその長いコードを日本語で表すなら、「HtmlServiceクラスがもつcreateTemplateFromFile()メソッドが呼び出され、その戻り値のオブジェクトがもつevaluate()メソッドを呼び出す」というような感じになります。

ではその１つ１つをみていきましょう。

# HtmlService
これは
>スクリプトからHTMLやその他コンテンツを返すためのサービス

参考：[https://developers.google.com/apps-script/reference/html/html-service](https://developers.google.com/apps-script/reference/html/html-service)

です。「Webページを作成するための機能たちを提供するもの」と考えればよいでしょう。

# createTemplateFromFile(引数)
>コードエディタのファイルから新しい HtmlTemplate オブジェクトを作成するメソッド

参考:[https://developers.google.com/apps-script/reference/html/html-service#createHtmlOutput(String)](https://developers.google.com/apps-script/reference/html/html-service#createHtmlOutput(String))

です。引数にHTMLのファイル名を記述することによって、HtmlTemplateオブジェクトといわれるものを作成します。
このHtmlTemplateオブジェクトというのはHTMLを動的に生成するためのオブジェクトだと思っていただければよいです。

# evaluate()
簡単に書くと
>HtmlOutput オブジェクトを返すメソッド

です。HtmlOutputオブジェクトとは何かといいますと、GASの公式ホームページによると、
>セキュリティ上の考慮事項により、スクリプトでは、HTML をブラウザにそのまま返すことはできません。その代わりに、悪意のあるアクションを実行できないようにサニタイズする必要があります

参考:[https://developers.google.com/apps-script/reference/html/html-output](https://developers.google.com/apps-script/reference/html/html-output)

と書いてありました。つまりHtmlOutputオブジェクトとは「HTMLをブラウザにはそのまま表示出来ないからサニタイズされたものが入っている」と思えばよいでしょう。（サニタイズについては各自でお調べください）

# まとめると
HtmlService.createTemplateFromFile(template).evaluate()の大まかな処理の意味としては、
「HtmlServiceクラス」にある「createTemplateFromFileメソッド」を呼び出し、「HTMLを動的に生成するオブジェクト」を作成し、そのままではHTMLを表示出来ないので「evaluateメソッドでサニタイズ」して表示する、になります。

# 最後に
ここまでみてきましたが、長くて複雑そうなものは、細分化して一つ一つをチェックし、最後に組み合わせると、案外何をしているかわかったりもします。以上備忘録でした。
保守点検を行い、その場で資材の発注や部品の発注を行う。Dynamics 365 Field Service 在庫管理をする

## はじめに
Dynamics 365 Field　Serviceで在庫管理を行う。

## ユースケース
保守点検を行い、その場で資材の発注や部品の発注を行う。

## 在庫管理を行うために一覧画面に製品と数量を登録する
### 1.在庫仕訳帳へのアクセス
会計要件として、追加は可能であるが、削除は通常できないようにしている。（もちろんログが残る形で削除は可能。）

高度な検索　→「inventory Journals」で検索　在庫仕訳帳へアクセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367026/36a0c885-e5b3-44b9-7a28-ba790acbc8af.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367026/c906c947-2b54-4345-85fa-e09ad307d1c6.png)

### 2.在庫仕訳帳の一覧へ遷移
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367026/914195ad-8833-1a86-cc28-74e15070d994.png)

### 3.在庫の製品を登録する。任意レコード選択し新規ボタンを押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367026/21c39bb3-1e16-6502-d321-da1aada5fb51.png)

### 4.製品を追加
例えば　淡水タンクN1234の製品を400個在庫登録する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367026/8932f402-5501-aec1-5bbd-8220ce513577.png)

在庫仕訳帳一覧をみると、一番上に先ほど400個追加した在庫の製品が存在する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367026/457bd9d1-9e63-0b43-4919-0989210add26.png)


## 在庫管理をするために、タスク票（作業指示書）より見積もりまたは保守点検で淡水タンク5個使用したとする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367026/2facf406-ad61-b154-c118-590b9a300bab.png)


### 在庫を5個つかってみる。1個12万円の設定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367026/b2c9226e-1435-98aa-4bdd-6433fed1b6cc.png)

### 作業指示書には製品　淡水タンク5個利用と登録。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367026/e98401dc-cc34-c99c-6bd4-1da8d027306b.png)

### 在庫は400－5個の395個とわかる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367026/5ad79da4-7257-9259-355a-24de4cbe2e9b.png)



参考

https://docs.microsoft.com/ja-jp/dynamics365/field-service/manual-inventory-journals#instructions
Pythonの便利技と注意点:変数編

[目次に戻る](https://qiita.com/yuta-sanjyo/items/416b05f8498df1ed3f49)

# 予約語・キーワード
```py:ここに挙げた単語は変数として使ってはいけない
False      await      else       import     pass
None       break      except     in         raise
True       class      finally    is         return
and        continue   for        lambda     try
as         def        from       nonlocal   while
assert     del        global     not        with
async      elif       if         or         yield
```

# 一連の値を、各単独の変数に格納
```py:数字
>>> num_val = 1, 2, 3
>>> num_val
(1, 2, 3)
>>> one, two, three = num_val
>>> one
1
>>> two
2
>>> three
3
```
```py:文字
>>> str_val = list('abc')
>>> str_val
['a', 'b', 'c']
>>> x, y, z = str_val
>>> x
'a'
>>> y
'b'
>>> z
'c'
```
```py:辞書のキーと値
>>> macdo = {'ハンバーガー':200, 'ポテト':150, 'コーラ':100}
>>> メニュー, 金額 = macdo.popitem()
>>> メニュー
'コーラ'
>>> 金額
100
```

```py:左辺・右辺の数が合わないとエラー
[左辺が少ない場合]
>>> a, b = 1, 2, 3
Traceback (most recent call last):
  File "<pyshell#20>", line 1, in <module>
    a, b = 1, 2, 3
ValueError: too many values to unpack (expected 2)

[右辺が少ない場合]
>>> a, b, c = 1, 2
Traceback (most recent call last):
  File "<pyshell#23>", line 1, in <module>
    a, b, c = 1, 2
ValueError: not enough values to unpack (expected 3, got 2)
```
```py:*を使うと代入する方が多くても残り全て引き取ってくれる
[最初の*変数が引き取るパターン]
>>> waza = "スーパー・ウルトラ・グレート・デリシャス・ワンダフル・ボンバー"
>>> *fst, snd, trd = waza.split("・")
>>> fst
['スーパー', 'ウルトラ', 'グレート', 'デリシャス']
>>> snd
'ワンダフル'
>>> trd
'ボンバー'

[真ん中の*変数が引き取るパターン]
>>> waza = "スーパー・ウルトラ・グレート・デリシャス・ワンダフル・ボンバー"
>>> fst, *snd, trd = waza.split("・")
>>> fst
'スーパー'
>>> snd
['ウルトラ', 'グレート', 'デリシャス', 'ワンダフル']
>>> trd
'ボンバー'

[最後の*変数が引き取るパターン]
>>> waza = "スーパー・ウルトラ・グレート・デリシャス・ワンダフル・ボンバー"
>>> fst, snd, *trd = waza.split("・")
>>> fst
'スーパー'
>>> snd
'ウルトラ'
>>> trd
['グレート', 'デリシャス', 'ワンダフル', 'ボンバー']
```
```py:*をつけた変数は、例え1文字であってもリストになる
>>> x, *y, z = "123"
>>> a, y, z
(1, ['2'], '3')
```

# ==とisの違い
```py:==は値を比較する
>>> x = y = [1, 2, 3]
>>> z = [1, 2, 3]
>>> x == y
True
>>> x == z
True
```

```py:zは同じ値をもつだけであり、同一のリストを参照しているのではない
>>> x is y
True
>>> x is z
False
```

# 関数内からグローバル変数を書き換える
```Py:関数内でglobalをつけて再宣言すると関数の中からglobal変数にアクセスできる
drink = 'orange juice'
print('関数実行前:', drink)
def example_func():
    global drink
    drink = 'cola'
    print('関数内:', drink)

example_func()
print('関数実行後:', drink)
==========================
# 出力結果
関数実行前: orange juice
関数内: cola
関数実行後: cola
```

```Py:globalをつけずに宣言すると、同じ変数名でも別の変数を作り出している
drink = 'orange juice'
print('関数実行前:', drink)
def example_func():
    drink = 'cola'
    print('関数内:', drink)

example_func()
print('関数実行後:', drink)
==========================
# 出力結果
関数実行前: orange juice
関数内: cola
関数実行後: orange juice
```

[目次に戻る](https://qiita.com/yuta-sanjyo/items/416b05f8498df1ed3f49)
supersetをBigQueryと連携する。

# 目的

* supersetをBigBueryに接続するための備忘録

# Dockerfile

* BigQueryに接続するためのmoduleをinstall

```Dockerfile
FROM apache/superset:2.0.0

RUN pip install pybigquery

USER superset
```

# docker-compose.yaml

```yaml
version: '3.7'
services:
  superset:
    build: .
    container_name: superset
    ports:
      - "8088:8088"
```

# init.sh

* superset初期化

```
#!/bin/bash
CONTAINER_NAME='superset'

docker exec -it ${CONTAINER_NAME} superset db upgrade

docker exec -it ${CONTAINER_NAME} superset fab create-admin \
    --username admin \
    --firstname admin \
    --lastname user \
    --email admin@fab.org \
    --password admin

docker exec -it ${CONTAINER_NAME} superset load-examples

docker exec -it ${CONTAINER_NAME} superset init
```

# Supersetの実行

```bash
$ docker-compose up -d
$ ./init.sh
```

* login
* <https://127.0.0.1:8088>
* username: admin
* password: admin

# supersetのdatabaseにBigQueryを追加

* 以下のリンク　「Connecting to BigQuery」を参照
* https://superset.apache.org/docs/databases/bigquery/

# あとがき

* 何故これをやりたかったか。
1. 自分の日々の体重を記録してSupersetのグラフで見たくなった。
2. Spreadsheetに体重を記録してそれをSupersetで見れるようにすれば良いと思った。
3. SpredsheetとSupersetの接続方法もあるようだがうまくいかず。
4. BigqueryからSpreadsheetの情報を取得できることが分かった。
5. SupersetとBigQueryの接続方法はうまくいった。
6. 結果　Spreadsheet->BigQuery->Supersetという構成が出来上がった。
7. 毎回Spreadsheetに記載するのがめんどくさいので、SlackからGASを経由してSpreadsheetに記載できるようにした。
8. 現在の構成 Slack -> GAS -> Spreadsheet -> Bigquery -> Superset
Pythonの便利技と注意点:Jupyter編

[目次に戻る](https://qiita.com/yuta-sanjyo/items/416b05f8498df1ed3f49)

# JupyterとRをJupyter Notebookで使う時の注意
こちらに別途記事を記載しました：https://qiita.com/yuta-sanjyo/items/7fda2059408e0e604413

# グラフの日本語文字化けを防ぐ
```py:フォントを指定しないと日本語タイトルがこのように文字化けする
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns

plt.plot([0, 100, 200], [100, 0, 200])
plt.title("タイトル")
plt.show()
```
![Pythonグラフ文字化け.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588352/a89c1f6b-1608-41c5-a79f-0b9fd920456a.png)

```py:Windowsの場合：Meiryo, Yu Gothic, Hiragino Maru Gothic Pro等を設定する
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(font=["Meiryo", "Yu Gothic", "Hiragino Maru Gothic Pro"])

plt.plot([0, 100, 200], [100, 0, 200])
plt.title("タイトル")
plt.show()
```
![Pythonグラフ文字化けしない.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588352/d6eebf35-4f8b-4729-f60d-98fd46f89003.png)

```py:Ubuntuの場合：Noto Serif CJK JP, Noto Sans CJK JPを設定する
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(font=["Noto Serif CJK JP", "Noto Sans CJK JP"])

plt.plot([0, 100, 200], [100, 0, 200])
plt.title("タイトル")
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588352/0b4ea705-2e54-adac-9be3-b385c38953cc.png)


# conda installでパッケージがない場合

```py:-cでconda-forgeを指定するとインストールできる場合がある
$ conda install -c conda-forge <パッケージ名>
```

# ライブラリや関数の詳細を表示する
```Py:「?」をつけるとDocStringが表示される
import logging
logging.debug?
```

```Py:出力結果
Signature: logging.debug(msg, *args, **kwargs)
Docstring:
Log a message with severity 'DEBUG' on the root logger. If the logger has
no handlers, call basicConfig() to add a console handler with a pre-defined
format.
File:      c:\users\<user_name>\.conda\envs\<virtual_environment_name>\lib\logging\__init__.py
Type:      function
```

```Py:「??」をつけるとsourceが表示される
import logging
logging.debug??
```

```Py:出力結果
Signature: logging.debug(msg, *args, **kwargs)
Source:   
def debug(msg, *args, **kwargs):
    """
    Log a message with severity 'DEBUG' on the root logger. If the logger has
    no handlers, call basicConfig() to add a console handler with a pre-defined
    format.
    """
    if len(root.handlers) == 0:
        basicConfig()
    root.debug(msg, *args, **kwargs)
File:      c:\users\<user_name>\.conda\envs\<virtual_environment_name>\lib\logging\__init__.py
Type:      function
```


[目次に戻る](https://qiita.com/yuta-sanjyo/items/416b05f8498df1ed3f49)
ingress filtering とは

## 勉強前イメージ

Ingressってあのイングレスしか出てこない・・・

## 調査

### ingress filtering とは

イングレスフィルタリングと読み、
送信元を偽装したIPパケットの転送を防ぐ手法の一つです。
元々内部で保持していないIPアドレスを送信元とするパケットが外部に送信される場合
送信元IPアドレスが詐称されていると判断してフィルタリングします。

サービスの運用を妨害する攻撃手法には送信元のIPアドレスをフィルタリングして行うものがあります。
TCP SYNフラッディングなどもその一つになります。
また、送信元IPアドレスが第三者の正規アドレスだった場合、SYN/ACKのパケットを返送して
その正規アドレス先にも攻撃をすることになってしまいます。

このようなことにならないようにイングレスフィルタリングが推奨されています。
導入することで送信元IPアドレスを偽って行う攻撃を防ぐことができます。

## 勉強後イメージ

送信元IPが間違ってるものを防ぐとたしかに攻撃もできないもんね

## 参考

- [イングレスフィルタリングとは](https://www.nic.ad.jp/ja/basics/terms/ingress-filtering.html)
- [送信元 IP アドレスを詐称したパケットのフィルタリング](https://www.jpcert.or.jp/tips/2005/wr053201.html)
Pythonの便利技と注意点:関数編

[目次に戻る](https://qiita.com/yuta-sanjyo/items/416b05f8498df1ed3f49)

# 関数のドキュメント：#を使わなくても関数にドキュメンテーション文字列を残す
```py:関数定義の冒頭に文字列を書く（PEP257に従い""" """を使用します）
>>> def greetings(name):
        """nameに入った人に挨拶を交わす"""
        print(f'こんにちは{name}さん')
	
>>> greetings('太郎')
こんにちは太郎さん
```
```py:定義した関数名.__doc__でアクセスできる
>>> greetings.__doc__
'nameに入った人に挨拶を交わす'
```
```py:help(定義した関数名)でも表示できる
>>> help(greetings)
Help on function greetings in module __main__:

greetings(name)
    nameに入った人に挨拶を交わす
```

# 関数に引数を渡す時の影響
```py:変数だけを渡しても影響を受けない
>>> def ch_arg(str):
        str = 'Apple'
	
>>> fruit = 'Grape'
>>> ch_arg(fruit)
>>> fruit
'Grape'
```
```py:リストを渡すと影響を受ける
>>> def change_arg(n):
        n[0] = 'Banana'
	
>>> fruits = ['Apple', 'Grape']
>>> change_arg(fruits)
>>> fruits
['Banana', 'Grape']
```
```py:リストを渡しても影響を受けないようにするにはリスト全体のスライスをコピーする
>>> fruits = ['Apple', 'Grape']
>>> change_arg(fruits[:])
>>> fruits
['Apple', 'Grape']
```

# 関数に複数の引数を渡す時に*（アスタリスク）を活用する
```py:変数に複数の値を定義して関数に引き渡す時、*をつけないと「1つしかない」とエラーが出る
>>> params = (1, 2)
>>> def add(x, y):
        return x + y

>>> add(params)
Traceback (most recent call last):
  File "<pyshell#30>", line 1, in <module>
    add(params)
TypeError: add() missing 1 required positional argument: 'y'
```
```py:*をつけて渡すと複数が格納されている変数を渡せる
>>> add(*params)
3
```
```py:上の例ではタプルにしているが、リストでも引き渡せる
>>> para = [1, 2]
>>> add(*para)
3
```
```py:辞書型を引き渡す場合は*を2つつける
>>> def hi_there(greetings, name):
        print(f'{greetings}, {name}')
	
>>> params = {'greetings':'Hello', 'name':'Everyone'}
>>> hi_there(**params)
Hello, Everyone
```

# 関数を呼び出す度にリストを初期化してリストに値を入れる方法
```Py:リストを初期化しないと、関数を呼び出す度にリストの中が増えていく
def saving_box(coin, box=[]):
    box.append(coin)
    return box

# 100円玉投下1回目
insert_coin = saving_box(100)
print(insert_coin)

# 100円玉投下2回目
insert_coin = saving_box(100)
print(insert_coin)
```

```Py:出力結果
[100]
[100, 100]
```

```Py:リストを初期化すると、関数を呼び出すごとに、リストの中身がリセットされる
# デフォルトリストをNoneで指定して、
# 関数の中でリストがNoneであれば初期化する処理を追加すると、
# 呼び出す度にリストがリセットされる

def saving_box(coin, box=None):
    if box is None:
        box = []
    box.append(coin)
    return box

# 100円玉投下1回目
insert_coin = saving_box(100)
print(insert_coin)

# 100円玉投下2回目
insert_coin = saving_box(100)
print(insert_coin)
```

```Py:出力結果
[100]
[100]
```

[目次に戻る](https://qiita.com/yuta-sanjyo/items/416b05f8498df1ed3f49)
Pythonの便利技と注意点:format編

[目次に戻る](https://qiita.com/yuta-sanjyo/items/416b05f8498df1ed3f49)

# format()もしくはf''の技
```py:インデックスは順番になってなくてもよい上、複数回使用可能
>>> "{3} {0} {2} {1} {3} {0}".format("be", "not", "or", "to")
'to be or not to be'
```
```py:フィールドは番号ではなく名前やインポートした名前でも使用可能
>>> from math import pi
>>> "{name}の値はおよそ{value:.2f}。".format(value=pi, name="π")
'πの値はおよそ3.14。'
```
```py:無名フィールド、名前フィールドの混在も可能だが、名前フィールドを先に指定するとエラー
>>> "{} {} {} {foo}".format(1, 5, 10, foo=3)
'1 5 10 3'

>>> "{} {} {} {foo}".format(foo=3, 1, 5, 10)
SyntaxError: positional argument follows keyword argument
```
```py:位置フィールドと名前フィールドの混在も可能
>>> "{hoge} {1} {geho} {0}".format(1, 2, geho=4, hoge=3)
'3 2 4 1'
```
```py:無名フィールドと位置フィールドを混在させるとエラーになる
>>> "{} {2} {} {3}".format(1, 2, 4, 3)
Traceback (most recent call last):
  File "<pyshell#33>", line 1, in <module>
    "{} {2} {} {3}".format(1, 2, 4, 3)
ValueError: cannot switch from automatic field numbering to manual field specification
```
```py:値の一部を使うこともできる
>>> fruits = ["Apple", "Orange"]
>>> "{name[0]}".format(name=fruits)
'Apple'
>>> "{name[1]}".format(name=fruits)
'Orange'
```
```py:数値の型指定も可能
>>> "Int型：{num}".format(num=15)
'Int型：15'

>>> "Float型：{num:f}".format(num=15)
'Float型：15.000000'

>>> "2進数型：{num:b}".format(num=15)
'2進数型：1111'
```
```py:変数には日本語も使えて当然計算も可能
>>> from math import pi
>>> 半径 = 3
>>> f'半径{半径}の円の面積は{pi * 半径 * 半径:.2f}です。'
'半径3の円の面積は28.27です。'
```

[目次に戻る](https://qiita.com/yuta-sanjyo/items/416b05f8498df1ed3f49)
Pythonの便利技と注意点:文字列編

[目次に戻る](https://qiita.com/yuta-sanjyo/items/416b05f8498df1ed3f49)

# raw文字とフォルダパス記述
```py:raw文字：フォルダパスで使う時に便利
>>> print(r'C:\Program Files\fnord')
C:\Program Files\fnord
```
```py:但し、文字列の最後に「\」を入れるとエラーになる
>>> print(r'C:\Program Files\')
  File "<stdin>", line 1
    print('C:\Program Files\')
                             ^
SyntaxError: EOL while scanning string literal
```
```py:最後に\を入れたい場合は、分けて記載する
>>> print(r'C:\Program Files' '\\')
C:\Program Files\
```
```py:Windowsのパスでもバックスラッシュor円マークではなく/で代替するのもアリ
>>> import os
>>> path = r'C:/Program Files/7-Zip'
>>> flist = os.listdir(path)
>>> print(flist)
['7-zip.chm', '7-zip.dll', '7-zip32.dll', '7z.dll', '7z.exe', '7z.sfx', '7zCon.sfx', '7zFM.exe', '7zG.exe', 'descript.ion', 'History.txt', 'Lang', 'License.txt', 'readme.txt', 'Uninstall.exe']
```
```py:Windowsのパスを/に代替する場合、rなしでもOK
>>> import os
>>> path = 'C:/Program Files/7-Zip'
>>> flist = os.listdir(path)
>>> print(flist)
['7-zip.chm', '7-zip.dll', '7-zip32.dll', '7z.dll', '7z.exe', '7z.sfx', '7zCon.sfx', '7zFM.exe', '7zG.exe', 'descript.ion', 'History.txt', 'Lang', 'License.txt', 'readme.txt', 'Uninstall.exe']
```

# 文字列を簡単にListに入れる
```py:文字列をリストに変換すると一文字ずつ「''」で囲わなくて便利
>>> list('Hello')
['H', 'e', 'l', 'l', 'o']

>>> list('12345')
['1', '2', '3', '4', '5']
```
```py:文字列リストを本来の並びに戻したい場合はjoin
>>> l = list('Hello')
>>> l
['H', 'e', 'l', 'l', 'o']
>>> ''.join(l)
'Hello'
```

# テンプレート文字列：Template()とsubstitute()
```py:format()やf''以外の方法で表示する
>>> from string import Template
>>> tmpl = Template("こんにちは、$whoさん、$whatですか？")
>>> tmpl.substitute(who="一郎", what="お元気")
'こんにちは、一郎さん、お元気ですか？'
>>> tmpl.substitute(who="二郎", what="ご機嫌いかが")
'こんにちは、二郎さん、ご機嫌いかがですか？'
```

# 英単語の先頭文字だけを大文字にするtitle()とcapwords()
```py:title()だと’の後の文字も大文字にしてしまう
>>> "let's call it a day!".title()
"Let'S Call It A Day!"
```
```py:capwords()の方が便利
>>> import string
>>> string.capwords("let's call it a day!")
"Let's Call It A Day!"
```

# 文字コードを知る方法
```py:ord()を使うとその文字のコードを返してくれる
>>> ord("A")
65
>>> ord("a")
97
>>> ord("あ")
12354
>>> ord("蝶")
34678
```
```py:chr()にコードを入れるとその文字を返してくれる
>>> chr(65)
'A'
>>> chr(97)
'a'
>>> chr(12354)
'あ'
>>> chr(34678)
'蝶'
```

# 文字列を一定文字数ごとに改行する技
```py:添え字+1ごとに"\n"を追加する
>>> aiueo = 'あいうえおかきくけこさしすせそたちつてとなにぬねの'
>>> s = ''
>>> for i in range(len(aiueo)):
	s += aiueo[i]
	if (i>0) and ((i+1) % 5 == 0):
		s += "\n"		
>>> print(s)
あいうえお
かきくけこ
さしすせそ
たちつてと
なにぬねの
```

# 文字列を何文字目か1文字だけ変える技
```Py:文字列を1つだけ入れ替えようとしても不変なのでエラーが出る
Char_A = 'Apple'
Char_A[0] = 'a'
print(Char_A)
================
TypeError: 'str' object does not support item assignment
```

```Py:文字列をリスト化すれば入れ替えられる
# 文字列をlist化して格納
# [['A', 'p', 'p', 'l', 'e'], ['O', 'r', 'a', 'n', 'g', 'e']]
Char_A = []
Char_A.append(list('Apple'))
Char_A.append(list('Orange'))

# list化された文字列の該当箇所を指定して交換
Char_A[0][0] = 'a'
Char_A[1][0] = 'o'

# listから各文字をくっつけて取り出す
for i in range(len(Char_A)):
    print("".join(Char_A[i]))
==============================================================
apple
orange
```

[目次に戻る](https://qiita.com/yuta-sanjyo/items/416b05f8498df1ed3f49)
Pythonの便利技と注意点:計算編

[目次に戻る](https://qiita.com/yuta-sanjyo/items/416b05f8498df1ed3f49)

# Pythonは小数点の計算が苦手
```py:小数点の引き算するとこうなる
>>> 1.0 - 0.1
0.9
>>> 1.0 - 0.2
0.8
>>> 1.0 - 0.3
0.7
>>> 1.0 - 0.4
0.6
>>> 1.0 - 0.5
0.5
>>> 1.0 - 0.6
0.4
>>> 1.0 - 0.7
0.30000000000000004
>>> 1.0 - 0.8
0.19999999999999996
>>> 1.0 - 0.9
0.09999999999999998
```
```py:解決法の1つ：整数の計算は問題ないようなので1度整数倍にしてあげて後で戻す
>>> num_a = 1.0
>>> num_b = 0.7

>>> ((num_a * 10) - (num_b * 10)) / 10
0.3
>>> num_b = 0.8
>>> ((num_a * 10) - (num_b * 10)) / 10
0.2
>>> num_b = 0.9
>>> ((num_a * 10) - (num_b * 10)) / 10
0.1
```

# round関数を使わずに小数点切り捨てする技
```py:// 1を使う　※但し小数点以下の.0は残る
>>> 2837.20 // 1
2837.0
```
```py:int()を使うと小数点以下の.0は消える
>>> int(2837.20)
2837
```
```py:whileの条件で割り引いて0円になったら抜けるつもりが、0.xxxxxが永遠に続く
※intを設定したとしても、割合の計算の時点で、自動にfloatに変換され永遠に続く
>>> a = 150
>>> b = 70
>>> while(a>0):
	a -= a * 70 / 100
	print(a)

45.0
13.5
4.050000000000001
・
・
・
7.971615000000002e-05
2.3914845e-05
```
```py:こういう時は上記の例を使って整数にして抜け出す
※割合計算でfloatにされたものをintに戻してあげることで、a>0の条件を設定できる
>>> a = 150
>>> b = 70
>>> while(a>0):
	a -= a * 70 / 100
	a = int(a)
	print(a)	
45
13
3
0
```

# マイナスを含む割り算の注意点
仕様：Pythonの負の数の割り算は、割り切れない場合、商の値は0から離れた方の整数になる
```py:10 // -3 は、少数にすると、-3.333...となり、この値を挟む-3と-4を比較して0からより離れた値になる
>>> 10 // -3
-4
```
```py:-10 // 3も同じ
>>> -10 // 3
-4
```

また、Pythonの % による余りの計算は、割られる数 - 割る数 x 商、が行われるので、下記のような結果が出てくる
```py:商が-4になるので、10 % -3 は、10 - {-3 x (-4)} と計算されて -2 となる
>>> 10 % -3
-2
```
```py:同様に -10 % 3 は、-10 - {3 x (-4)} と計算されて 2 となる
>>> -10 % 3
2
```

[目次に戻る](https://qiita.com/yuta-sanjyo/items/416b05f8498df1ed3f49)
UbuntuでIPアドレスを固定する方法

## はじめに
備忘録
タイトルの通りです。
実行環境はUbuntu20.04（bash）です。
どなたかのお役に立てれば幸いです。
## 現在のIPアドレスを確認
以下のコマンドで現在のIPを確認してみましょう。
```bash
$ ip a
```
インターフェースの名前（お使いの環境に合わせてください。今回は`ens160`とします。）は後で使います。
## yamlファイルを作成
`/etc/netplan/`の中に`99_config.yaml`を作成します。
```yaml:99_config.yaml
network:
  version: 2
  renderer: networkd
  ethernets: 
    ens160:
      dhcp4: false
      addresses: [xxx.xxx.xxx.xxx/xx]
      gateway4: xxx.xxx.xxx.xxx
      nameservers:
        addresses: [xxx.xxx.xxx.xxx]
```
`xxx.xxx.xxx.xxx/xx`や`xxx.xxx.xxx.xxx`のところはお使いの環境に合わせて設定してください。
## 設定を適用
`99_config.yaml`を保存した後、次のコマンドで設定を適用します。
```bash
$ sudo netplan apply
```
# ブログもあります
https://kyit.net/how-to-fix-ip-address-in-ubuntu/
Ubuntuでユーザーを追加する方法

## はじめに
備忘録
タイトルの通りです。
実行環境はUbuntu20.04（bash）です。
どなたかのお役に立てれば幸いです。
## ユーザーを作成
`useradd`コマンドでユーザーを作成できます。
```bash
$ sudo useradd -m username
```
:::note
`-m`をつけることで`bash`の設定ファイル等を持ったユーザーを作成してくれます。
ユーザーを作成しただけではまだユーザーにロックがかかった状態なので、パスワードを設定しましょう。
:::
## ユーザーのパスワードを設定
`passwd`コマンドで任意のユーザーのパスワードを設定で来ます。
```bash
$ sudo passwd username
```
:::note
パスワードを設定することで初めてユーザーが有効化されます。
SSHのパスワード認証時にはここで設定したパスワードを利用します。
:::
## ユーザーの切り替え
次のコマンドで任意のユーザーに切り替えることができます。
```bash
$ sudo su - username
```
`ｐｗｄ`でパスを確認してみましょう。指定したユーザー名のディレクトリが表示されれば大丈夫です。
`exit`で抜けることができます。
## sudoグループにユーザーを追加
ユーザーが`sudo`権限を持ちます。
```bash
$ sudo usermod -aG sudo username
```
## `sudo`時のパスワードを不要にする
`visudo`を書き換えることで`sudo`時のパスワードを不要にすることができます
```bash
$ sudo visudo 
```
`NOPASSWD`を追加するだけです。
```diff
- %sudo  ALL=(ALL:ALL) ALL
+ %sudo  ALL=(ALL:ALL) NOPASSWD:ALL
```
# ブログもあります
https://kyit.net/how-to-add-user-in-ubuntu/
XAMPPでMySQLのポート番号の変更方法

MySQLのConfigボタンをクリックし、my.iniをクリックする。
ポート番号を3306以外に変更する。
```[client]
# password       = your_password 
#port=3306
port=3309　←　ここ
socket="D:/xampp/mysql/mysql.sock"

# The MySQL server
default-character-set=utf8mb4
[mysqld]
#port=3306
port=3309　←　ここ
socket="D:/xampp/mysql/mysql.sock"
```
# 参考文献
https://itsakura.com/xampp-port
クロスサイトスクリプティングについて学び、Webサイトを守ろう

# はじめに
セキュリティはエンジニアとして生きていく以上目を背けることができないものです。今回は、有名な攻撃手法のクロスサイトスクリプティングというものについて紹介します。
本記事の対象者：Webサイトを運用してみたい初学者の方

# クロスサイトスクリプティングとは
Webサイトの不備をついて、サイト上に悪意のあるスクリプトを埋め込む攻撃です。基本情報技術者試験とかでも出題される攻撃手法なので名前は知っているという方も多いのではないでしょうか。さて、この攻撃ですが注意しないといけないのは以下のような機能をもったサイトを運用している方です。

- 入力内容を確認させる表示画面(会員登録、アンケート等)
- 誤入力時の再入力を要求する画面で、前の入力内容を表示するとき
- 検索結果の表示
- エラー表示
- コメントの反映(ブログ、掲示板等)

ほとんどのWebサイトがいずれかに該当する機能をもっているのではないでしょうか。つまり、Webサイトを運用していく上でこのクロスサイトスクリプティングについて知り対策することは必要不可欠です。

# 被害事例
簡単に過去のクロスサイトスクリプティングを利用した被害事例を見てみましょう。
- Youtube
    - コメントシステムにおけるクロスサイトスクリプティングの脆弱性が悪用された。デマニュースのポップアップが表示されたり、別のWebサイトにリダイレクトされるなどの被害が相次いだ。

- Twitter
    - TwitterDeckにおけるクロスサイトスクリプティングの脆弱性が悪用された。勝手に意味不明な投稿をさせられるワームが拡散。50万人ほどが影響を受けたと言われている。

# デモサイトを使って実験してみる
どんなものかを視覚的に理解しやすくするため、脆弱性のあるWebサイトを用意し、実験をしてみました。
名前とメッセージを入力して送信すると、リアルタイムでメッセージが反映される掲示板のようなサイトです。
まずは意図する挙動を見てみましょう。これは名前を「test」、メッセージを「Hello World」にしています。これを送信すると...
![スクリーンショット 2022-08-25 185243.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742387/60ed2fbd-debc-7c59-2721-8fac0a6fe366.png)
掲示板部分にチャットが反映されました。当然ながら、これが本来望まれている挙動です。
![スクリーンショット 2022-08-25 185316.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742387/a7276e5f-35ba-19c9-9578-e5709c10f21b.png)
では、次に予期せぬ挙動をするメッセージを送信してみます。
![スクリーンショット 2022-08-25 185506.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742387/21b2d134-3cf6-d747-6159-2c43e94efb7f.png)
なんということでしょう。文字が大きくなり、字は赤色に変えられてメッセージが投稿されています。これは意図する挙動ではありません。
![スクリーンショット 2022-08-25 185518.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742387/5798c622-3fec-e3fc-624b-0b3b751be1b3.png)
何が起こったのでしょうか。答えは簡単で、メッセージ部分に入力された文字列がhtmlタグとして解釈されてしまったからです。先ほどメッセージ部分に入力した文字列はhtml上で「Hello World」を見出しの大きさにして、赤色にするという意味になります。
このhtmlタグをユーザが利用できてしまうヤバさを認識してください。htmlタグを入力できるということは\<script>タグが使えます。つまり、JavaScriptのコードをユーザが実行することができます。以下のメッセージを送信してみます。
![スクリーンショット 2022-08-25 194859.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742387/51cc5180-8e66-8afa-c8e0-2d587bc41d41.png)
画面にアラートが表示されてしまいました。JavaScriptのコードを実行できることがわかりましたね。
![スクリーンショット 2022-08-25 194803.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2742387/7c706a25-bf75-fb86-7828-797e7e65c683.png)

# 対策
これだけには限りませんが、重要なものをピックアップしました。
- サニタイジング
    - 特殊な記号にエスケープ処理を施す。例えば、「<」「>」「&」など。フレームワークを使って文字の受け渡しをしている場合、勝手にエスケープ処理されていることが多いが、油断は禁物。

- URLの出力時には、「http://」「https://」で始まるURLのみを許可
    - URLには「javascript:」で始まるものがあるので、ユーザが入力したURLを\<a>タグで出力する処理がある場合、「http://」「https://」以外は弾くようにする。※「javascript:」だけを拒否するブラックリスト方式ではなく、「http://」「https://」だけを許可するホワイトリスト方式にする方が漏れがなくて安全。


# おわりに
もしも、Webサイトにクロスサイトスクリプティングの脆弱性が残っていた場合、Cookie情報の流出、不正なサイトへの強制リダイレクト、Webページの改ざんといった重大な被害につながる恐れがあります。自分のサイトを運用している方は今一度設定を見直しましょう。
React (Next.js) のオープニングアニメーション

# React Web Opening Animation
### Next.jsでオープニングアニメーション

:::note warn
Opening Animationはwebページを初めて開いたときに表示されるアニメーションを指しています
:::


## 最もシンプルなもの
```react:index.tsx
const Home: NextPage = () => {
  const [isLoading, setIsLoading] = useState(true)
  useEffect(() => {
    setIsLoading(true)
    setTimeout(() => {
      setIsLoading(false);
    }, 2 * 1000)
  }, [])
    
  {isLoading ? 
    <>
      {/* Loading */}
    </>
    : <>
      {/* After Loading */}
    </>
  }
}
```

1. Loadされた直後にisLoadingをTrueに
2. setTimeoutを使って２秒後にisLoadingをFalseに

することによって表示されるコンポーネントを切り替えてオープニングアニメーションを実装

## フェードイン
フェードインなどを入れるとそれっぽくなります

```react:index.tsx
import styles from "./**/Home.module.css"

const Home: NextPage = () => {
  const [isLoading, setIsLoading] = useState(true)
  useEffect(() => {
    setIsLoading(true)
    setTimeout(() => {
      setIsLoading(false);
    }, 2 * 1000)
  }, [])
    
  {isLoading ? 
    <div className={`${styles.fadeIn} ... `}>
      {/* Loading */}
    </div>
    : <div className={`${styles.fadeIn} ... `}>
      {/* After Loading */}
    </div>
  }
}
```

```css:Home.module.css
.fadeIn {
  animation-name: fadeInAnime;
  animation-duration: 0.5s;
  animation-fill-mode: forwards;
  opacity: 0;
}

@keyframes fadeInAnime {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

```
AWS solution architect professional 攻略

## 取得日
2022/8/13 
## 過去の受験歴
aws solution architect associate(2021/12)
## 学習期間
3ヶ月程
## 使用した教材
<書籍>
AWS認定資格試験テキスト&問題集 AWS認定ソリューションアーキテクト - プロフェッショナル
https://www.amazon.co.jp/dp/4815609063?tag=rifoundation-22&linkCode=ogi&th=1&psc=1

<問題集>
①Web問題集で学ぼう[★★☆]
https://aws.koiwaclub.com/
aws solution architect professionalレベルの問題にアクセスできるプランだと6000円程度と少し値は張るが、実際の問題に近く良い練習になるので、マストで解いておいた方が良いと思われる。
7問1セットで70セットぐらい(500問位)見ることができる。特に後半の#30-70の方を90%取れるまで繰り返して解くと良い。

② Udemy問題集[★☆☆]
https://www.udemy.com/course/aws-53225/
解説が充実していて理解の助けになるが、実際の試験問題からはやや遠いと思われる。Nice to haveという感じ。

<補助教材>
①black belt[★☆☆]
https://aws.amazon.com/jp/aws-jp-introduction/aws-jp-webinar-service-cut/
主にpdf資料を見て教科書だけでは不足している知識を補うのに役に立った。重要なサービスは時々youtubeの方も見て勉強した。サービスによっては比較的古い資料が掲載されているものもあるので、気をつけて適宜活用すると良い。

②DevelopersIOの解説[★★☆]
https://dev.classmethod.jp/articles/aws-elastic-beanstalk-rds-decoupled/
最新のサービスを使ってみたレポから入門者向けの基礎的な知識まで守備範囲が広く、DNSなどの知識が薄い部分の理解に非常に役に立った。これが無かったら死んでた。

③その他
qiita記事など

## 勉強方法
1. AWS認定資格試験テキスト&問題集 AWS認定ソリューションアーキテクト - プロフェッショナルを3周位読み、各サービスの概要を理解する。初っ端でスイッチロールでつまづき、何日か勉強をさぼった。
2. udemyを2周位解く。最初は30%位しか取れず凹んだ。
3. 間違えた箇所をdev ioやblack belt資料で見直して、分からないところを全て潰す。
4. WEB問題集で学ぼうを直前の1週間で周回する。最終的に2周位しかできなかった。
昨年末にassociateに合格した後しばらく間が開き、4月位から何となく勉強を再開してちんたらやっていたが、2ヶ月くらいで集中して勉強した方が良かった。

## 受験
会場が小さいながら快適で、イヤーマフでしっかり防音できたのでリラックスして受験できた。持参した耳栓が使えず不安だったが、イヤーマフの防音効果が申し分なかったので問題なし。
一通り解き切ったところで残りが50分位だったので、急いでフラグを立てた問題を見直し。最後までかなり迷った問題があったが、時間切れで強制終了だった。
AWS Cloud Practitioner Essentials モジュール2まとめ

この記事はAmazonが提供する教材「AWS Cloud Practitioner Essentials（日本語字幕）」の初心者によるメモです。
情報に不備がある可能性があります。
本講座は[こちら](https://explore.skillbuilder.aws/learn/home)から.無料です！

# クラウドコンピューティング
従量課金製によるインターネット経由でのITリソースのオンデマンド配信

# AWSのサービス（一部）
## EC2・周辺サービス
### EC2
ECインスタンスと呼ばれる仮想サーバーをいつでも作成できいつでも削除できる
- インスタンスファミリー
  - 汎用
  - コンピューティング最適化
  　グループ単位でデータを処理するバッチ処理など、高パフォーマンスプロセッサの恩恵を受けるタイプのワークロードに最適
  - メモリ最適化
  　高性能データベースなど、メモリ内の大規模なデータセットを処理するワークロードに適している
  - ストレージ最適化
  　ローカルストレージの大規模なデータセットに対する高速シーケンシャルの読み取りおよび書き込みのアクセスを必要とするワークロード用に設計

- 料金プラン
  - オンデマンド
  - スポットインスタンス
  - リザーブドインスタンス
  - Saving Plans

- Auto Scaling
自動化された垂直スケーリング

### ELB
サーバーにかかる負荷を分散するロードバランサー



### SQS
コンポーネント同士を疎結合にする
メッセージを受け取り、削除するまでキューに保存する
### SNS
Eメールなどのメッセージの送信に用いるチャネル
サブスクライバーへのメッセージの発行などに用いる

## EC2以外のコンピューティングサービス
### ECS・EKS
コンテナサービスに用いる、コンテナオーケストレションツール
EC2上で実行される

### Fargate
コンテナをサーバーレスで実行できる

### Lambda
コードをアップロードするだけでトリガーに基づいて実行するよう設定
サーバーの煩雑な設定が不要
PhpStormで使っているプラグイン

PhpStormで使ってるプラグイン一覧。
PHPに関係あるなし関わらず追加で入れてあるプラグインを全部。


## 開発全般
https://plugins.jetbrains.com/plugin/9333-makefile-language

makefileに実行ボタンが付いてポチッとな、ができるようになる。

---

https://plugins.jetbrains.com/plugin/9746-ideolog

各種ログファイルに色づけできる。
ログフォーマットをカスタムすることも可能。

---

https://plugins.jetbrains.com/plugin/9525--env-files-support

## PHP

https://plugins.jetbrains.com/plugin/7622-php-inspections-ea-extended-

（2023年3月21日現在 2021年を最後に更新が途絶えているようです）
これのおかげでPHPのプログラムの質が爆上げ。入れないと損する。
自分の昔のソースコードに手を入れるときに改善指摘が多すぎて泣く。

---

https://plugins.jetbrains.com/plugin/19515-php-hammer

最近PHP Inspectionsの更新が途絶えてしまっているようです。
それに変わって登場したのがこのプラグイン。
PhpStorm2023.1あたりからはこちらを導入してみましょう。

---

https://plugins.jetbrains.com/plugin/7320-php-annotations

インストールすれば幸せ（Just install and be happy）。
PHPDoc周りのカイゼン。

---

https://plugins.jetbrains.com/plugin/8133-php-toolbox

ごめんなさい。正直PHP Annotationsの説明に「Optional: Install PHP Toolbox」ってあったので。

---

https://github.com/JetBrains/phpstorm-stubs

プラグインじゃないけどJetBrainsが管理してるPHPの関数などのスタブ`phpstorm-stubs`。
これを設定すれば常に最新のドキュメントがオフラインで閲覧できるようになる。
中身はPHPなのでこういったスタブに対応していれば他のエディターでも使える。たぶん。

## Laravelやるなら
https://plugins.jetbrains.com/plugin/13441-laravel-idea

優良な有料プラグイン。会社（株式会社ニジボックス）が購入してくれました。やったぜ。

---

https://plugins.jetbrains.com/plugin/16309-laravel-query

Laravelのクエリービルダーで補完が効くようになったりする。

## Denoやるなら

https://plugins.jetbrains.com/plugin/14382-deno

Denoやるなら入れないと始まらない。

---


他に追加があったら随時更新。
初心者　MySQL8に挑戦する 16

# 砕け散って一時撤退　
　３週間もあいてしまった。といって、何もしていなかったわけではない。無限ループの中をひたすらぐるぐるしていた。要素は4つ。　

- MySQL8
- mysql1
- m1mac
- Flutter3

　独学者がついに音を上げてメンターさんをお願いする。メンターさん、速攻でサンプルコードを提示してくださる。ネットで拾うサンプルコードと違うのは、「作って、動かしてる本人」が、直接、私のコードを見たり、質問に答えてくれたりするところだ。

　メンターさんもFlutter3なので、それが原因という可能性は早々と消える。最初は自分の個人開発のプロジェクト内にメンターさんのコードを取り込んでいたが、もしか別のなにかと競合してたりするとややこしいので、私も全く新しく、全く同じコードを書いてみる。　

　が･･･・・ダメじゃん。はい、繋がっています、でも読み書きできません。　

　つまりコードがまちがってるわけでもない。

　メンターさんと状況を揃えるために、SequelAceじゃなく、Workbenchを入れる。
　userをrootから読み書きの権限付与した独自userに変える。
　あと、何したっけ？
　いつもはsimulatorだけど、メンターさんと同じemulatorでビルド。　
　いつもはAndroidstudioだけど、メンターさんと同じVSCodeを使う。

　すべての関数にprint()を挟んで、debugする。
　すると、読みに行ってはいる。けど、resultsが取れてない。そこで止まる。ということが判明。　

　メンターさんとの残った差分は、何？　メンターさんはIntelMacでMySQL5.7 結局そこ。確定。　

　せっかくの愛機m1macをいったん諦める。　
　2015年製という年季の入ったMacAirを引っ張り出す。　
　そこにMySQL5.7を入れる。　

　それさえもスムーズにいかない。そもそもこれにもMySQL8を入れてあったのを忘れていた。uninstallして、installして、「なんか古いfile残ってて引っかかります」とかいうエラーに遭遇して、「徹底uninstall」、「たぶんこういうfileが引っかかってますよ」記事を参照しながら、terminalで片っ端から削除していく。勢い余って、brewまで消えてしまって、brewのinstallからやり直して、MySQL5.7、始動します。

https://blog.proglus.jp/1077/

　
　といったって、もう長く使っていないので、Flutterが２のままだ。Androidstudioも古い。まあ、とりあえずこのまま行こう。

　まだMySQL5.7は空っぽだ。テスト用のデータベースを作らなきゃならない。　
　ああ、Workbenchも入れなきゃならない。
　テスト用のプロジェクトも復習だと思ってちゃんとコード書いて作る。

　旧機、何やるのも、遅い！　ビルド待ちながら数独ができるぐらい遅い。(>_<)　

　さあ、ようやくビルドできました。ボタン押します。･･･動きません。　
　もうやけになって、連打、　

　と・・・　えっ？　　トツゼン動いた。

　今までずっと空白だったtextfieldに名前が１つ、表示されている。　

 私の気が短かっただけとか、いわないでよね。アプリ使う人に、うまく動かないときは連打してください、とか言えないでしょう。　

　まあ、久しぶりに起こされたAirは眠かったのかもしれない。

　慌てて作ったデーターベースには３人の名前が入っている。idで呼び出してみると、最初のうちはほんと、連打しないと反応しなかったのだけれど、だんだん、ちゃんと動くようになってきた。　

　昭和のブラウン管テレビか、君は。

　試しに、四人目のデータをinsert。恐る恐るWorkbenchを開けると、　

　おおお、入ってますよ〜。めでたい。　

## いつかきっとMySQL8をm1macで動かすぞ!

 でもその日まで、まずはこの新境地を個人開発のプロジェクトに活かしていこうと思う。・・・Airでかぁ(>_<)

　それともm1macで、連打してみる？

https://qiita.com/dongri727/items/447e59179e1fa2dfed4f

https://qiita.com/dongri727/items/ca9c12f082254365fa91
ガウス過程回帰のメリットデメリット

ガウス過程回帰に関する自分用のメリット・デメリットのメモ


### 特徴
- ノンパラメトリックなモデルである
- 確率モデル(ベイズ推定)
### メリット
- 線形回帰でフィットできないものでもフィットできる
  - ガウス分布型の基底関数を無限個持ってきた線形回帰とRBFカーネルを用いたガウス過程回帰は対応している
- ノンパラメトリックなので予めモデルを選択する必要がない
- 確率的モデルであるため予測がどれくらい『当たらないのか』がわかる
  - データが少ない部分の予測は分散が大きくなってしまいブレることが視覚的にプロットできる 
- ハイパーパラメータは過学習の可能性があるが、訓練データに対しては過学習しにくい(ベイズ推定なので)
  - 要出典 

### デメリット
- 共分散行列の逆行列の計算が訓練用データ$N$に対して$O(N^{3})$ 程度になる
  - がもっと良いアルゴリズムがあるのである程度解消されている


## 参考文献
- [ガウス過程と機械学習](https://www.kspub.co.jp/book/detail/1529267.html)
- [「ガウス過程と機械学習」第3章のグラフ（一部）を作図する](https://ushi-goroshi.hatenablog.com/entry/2019/03/12/231741)
- [『ガウス過程と機械学習』サポートページ](http://chasen.org/~daiti-m/gpbook/)
- [MMDS（大阪大学数理・データ科学教育センター）の機械学習・データ学習スプリングキャンプに参加しました](https://hacarus.com/ja/information/tech/mmds_ml_springcamp2019/#:~:text=%E3%82%AC%E3%82%A6%E3%82%B9%E9%81%8E%E7%A8%8B%E5%9B%9E%E5%B8%B0%E3%81%AE%E3%83%A1%E3%83%AA%E3%83%83%E3%83%88&text=%E4%B8%80%E3%81%A4%E3%81%AF%E3%80%81%E3%80%8C%E3%81%A9%E3%82%8C%E3%81%8F%E3%82%89%E3%81%84%E3%82%8F%E3%81%8B%E3%82%89%E3%81%AA%E3%81%84,%E3%81%8C%E8%A6%8B%E3%81%88%E3%82%8B%E3%81%A8%E3%81%84%E3%81%86%E3%81%93%E3%81%A8%E3%81%A7%E3%81%99%E3%80%82)
- [ガウス過程回帰の基礎](https://www.jstage.jst.go.jp/article/isciesci/62/10/62_390/_pdf)
- [深層学習はガウス過程](https://machine-learning.hatenablog.com/entry/2018/01/13/142612)
- [DEEP NEURAL NETWORKS AS GAUSSIAN PROCESSES](https://arxiv.org/pdf/1711.00165.pdf) 深層学習をガウス過程で解釈する話
slackのログ出力で生成されるjsonファイルを見やすいログの形式にするpythonプログラム

# slack有料化
slackが9/1以降無料ユーザーが使える機能を変更し、無料ユーザーは90日前までの発言しか閲覧できなくなります。全体連絡等に使っていたところは他のアプリに移行することも多いと思います。その際、過去のやり取りとしてログを保存することになると思います。そのときに.jsonファイルができます。このファイルにはやり取りのすべての情報が入っているといっても過言ではないですが、見づらいためそれをよく見るテキストの形式に変換するpythonのプログラムを作りました。

# pythonソースコード
ソースコードを以下に示します。下のソースコード中の**フォルダ名**の部分を変更して使ってください。
簡単に説明すると、jsonファイルを辞書型(dict型)として読み込んで、メッセージ部分と発言者だけを抽出、タイムスタンプを変換して文字列型(str型)に変換して、それを成形してテキストファイルとして出力しています。同じ階層のgeneratedに出力されてるはずです。

※**注**　画像は取得できないのでメッセージと同じように記録されたリンクからダウンロードなりなんなりしてください。
この部分は純粋に自分の力不足です。すみません。
~~~python
from cgitb import text
import json
import datetime
import re
import os
from tkinter import filedialog

dr_path='target'
dr_path=os.path.join(dr_path,'フォルダ名')
root=os.getcwd()
gene=os.path.join(root,'generated')
#print(gene)


def autlogex(path):
    if os.path.isdir(path):
        # directoryだったら中のファイルに対して再帰的にこの関数を実行
        files = os.listdir(path)
        for file in files:
            autlogex(os.path.join(path,file))
    else:
        # fileだったら処理
        ex_log(path)
    return

def ex_log(path):
    global gene
    ip=path.split('\\')
    #print(ip)
    #print(path)
    fname=ip[-1]
    fname=fname[:-5]
    logtext=''
    with open(path, 'r',encoding='utf-8') as f:
        json_dict=json.load(f)
        count=0

        for i in json_dict :
            ts,user,file='','',''
            if i.get('type')=='message':
            
                ts=i.get('ts')
            
                if ts !=None:
                    dt = datetime.datetime.fromtimestamp(float(ts))
                    #print('\n\n{}'.format(dt))
                    logtext+='\n'+'\n\n{}'.format(dt)

                user=i.get('user_profile')
                if user !=None:
                    #print('----------{}----------'.format(user['first_name']))
                    logtext+='\n'+'----------{}----------'.format(user['first_name'])
                file=i.get('files')
                if file !=None:
                    count+=1
                    path=file[0].get('permalink')
                    #print('画像< {} >のURL---->   {}'.format(count,path))
                    logtext+='\n'+'画像< {} >のURL---->   {}'.format(count,path)
            txt=i.get('text')
            #print(txt)
            if txt==None:
                txt=''
            logtext+='\n'+ txt
        #print('------ログここまで-----\n画像は{}枚あります'.format(count))
        logtext+='\n'+'------ログここまで-----\n画像は{}枚あります'.format(count)
        #print(gene)
        genefile=os.path.join(gene,'extract-{}.txt'.format(fname))
        #print(genefile)

        try:
            os.mkdir(gene)
        except FileExistsError as e:
            pass
        with open(genefile,'w',encoding='utf-8',newline='') as d:
            d.write(logtext)

    return


autlogex(dr_path)

~~~
# シーン間の遷移

# 💎手順💎

<details>
  <summary>①シーンを作成する</summary>
・File ⇒ New Scene<br>
・追加するテンプレートを選択<br>
・File ⇒ Save as で保存<br>
・プロジェクトウィンドウから画像をシーンビューにD&D
⇒ シーンの完成
</details>

<details>
  <summary>②シーンの遷移</summary>
・スクリプトの作成<br>
⇒ using UnityEngine.SceneManagement
⇒ SceneManager.LoadScene("");
・空のオブジェクトを作成<br>
・スクリプトを空のオブジェクトにアタッチ<br>
・どの順番で使うか登録<br>
⇒ File Build Setting からシーンをD&D<br>
・数字の確認（0番からスタート：編集中は編集シーンからスタート）
</details>

<details>
  <summary>③シーンの遷移を調整</summary>
・操作にあった遷移にする<br>
⇒ 現在のシーンを保存してから，遷移の初めのシーンを開く
・遷移スクリプトの作成<br>
⇒ UnityEngine.SceneManagement;
⇒ SceneManager.LoadScene();
</details>
【Java】throwとthrowsの使い方を簡潔に説明してみる

# はじめに

今回の記事はthrow、throwsの解説を簡潔に書くことを目的としているため、検査例外・非検査例外とは何か等の細かい内容は省かせていただきます。お許しを。

# 実行環境
OS：Windows10　バージョン20H2
言語：Java 8
使用ツール：Spring Tool Suite 4

## 1. throw
 ### 1-1. throwとは

 ***例外を意図的に起こすことが出来る処理のこと。***

 ### 1-2. 使い方
    throw new 例外クラス名();
 ### 1-3. 使用例
```Sample.java
public class Sample {
	public void hello(String name) {
		if (name == null) {
			throw new IllegalArgumentException();
		}
		System.out.println(name + "さん、こんにちは！");	
	}
}
```


```Main.java
public class Main {
	public static void main(String[] args) {
		Sample s = new Sample();
		s.hello(null);
	}
}
```

```
実行結果
Exception in thread "main" java.lang.IllegalArgumentException
```
何らかの名前（文字列）を受け取ったら「こんにちは！〇〇さん！」と画面に表示する```helloメソッド```を作るとします。

しかしこの場合```helloメソッド```の引数に```null```を渡したとしても、「こんにちは！nullさん！」と表示されてしまいます。

そこで、```Sampleクラス```にて「もし```name```の値が```null```だった場合、```throw```を用いて```IllegalArgumentException```という非検査例外を発生させる」というプログラムを組み、例外を意図的に発生させています。

```Main.java
public class Main {
	public static void main(String[] args) {
		Sample s = new Sample();
		try {
			s.hello(null);
		} catch (IllegalArgumentException e){
			System.out.println("名前が空です！");
		}
	}
}
```

```
実行結果
名前が空です！
```

```try-catch```を用いることで、上記のコードのように意図的に起こした例外に対して処理を組むことも可能です。

## 2. throws
 ### 2-1. throwsとは
 ***メソッド内でスローする可能性のある例外を宣言する処理のこと。***

 ※ 扱う例外が先程の```throw```の例のように、**非検査例外**（```IllegalArgumentException```、```NullPointerExceptiont```等）であれば、```throws```は記述しなくても良いのですが、 **検査例外**（```IOException
```、```SQLException```等）であれば```throws```を宣言する必要があります。
 ### 2-2. 使い方
	メソッド名() throws 例外クラス名{}
	（複数例外を宣言する場合は、メソッド名() throws　例外クラス名 , 例外クラス名{}）
 ### 2-3. 使用例
 ```Sample.java
 public class Sample {
	public void hello(String name) throws Exception {
		
		if ("".equals(name)) {
			throw new Exception();
		}
		
		if (name == null) {
			throw new IllegalArgumentException();
		}
		
		System.out.println(name + "さん、こんにちは！");	
	}
}
```


```Main.java
public class Main {
	public static void main(String[] args) {
		Sample s = new Sample();
		try {
			s.hello("");
		} catch (IllegalArgumentException e){
			System.out.println("名前が空です！");
		} catch (Exception e) {
			System.out.println("名前を入力して下さい！");
		}
	}
}
```

```
実行結果
名前を入力してください！
```

先程の```Sampleクラス```に「もし```name```の値が""だった場合、```throw```を用いて```Exception```という例外を発生させる」という記述を追加しています。

```Exception```は**検査例外**であるため、```helloメソッド```に```throws```を宣言し、更に```Mainクラス```内で```catch```文に例外をスロー(投げる)しなければいけません。しないとコンパイルエラーが起こります。

ちなみに、この場合```IllegalArgumentException```は***非検査例外***なので```throws```で宣言していません。

```Sample.java
 public class Sample {
	public void hello(String name) throws Exception, IllegalArgumentException{}
```

もちろんこのような形で、***非検査例外***を```throws```で宣言することもできます。


# 参考資料

↓ こちらの方の動画を非常に参考にさせていただきました

https://www.youtube.com/watch?v=UvfnxoZ4igo

↓ Exception公式ドキュメント

https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Exception.html

↓ 検査例外と非検査例外に関する記事

https://freelance-jak.com/technology/java/1157/
.find()メソッドのメソッドチェーンは便利だった

# 概要
再生リストをDOMアクセスする場合、リストの構造がネスト構造になっていて複雑な場合、深いところにあるセレクターをチェックしたい場合、どうしたらいいか悩んでいたところ、find()メソッドが使えることに気がつきました。このfind()メソッドをメソッドチェーンでつなげて行くと簡単に深いところにある、セレクターをチェックできました。

# 事例
「なつかしの曲(ポータル)」サイトの王冠再生ボタンでそのテクニックを使用しました。


```
//王冠を再生
//
var crown_list=[];
//王冠再生ボタンのクリックイベント処理
//
$(document).on("click","#crown_play",function (e){
    crown_list = [];
    //再生リストのタグを順にチェックして、class=".goodness"
    //要素の中に<img要素があるかをチェック
    $.each($(".ui-state-default"),function(i,val){
        //.goodnessに、<imgタグがあるかチェック
        if($(val).find(".goodness").find("img").length===1){
            //あれば、crown_list配列に保存
            crown_list.push(val);
            
        }        
    });
    //
    if(crown_list.length!==0){
            //id="sortable"要素へセット
            $("#sortable").html(crown_list);
    }
    
});
//
```
ここで、.find()メソッドを2回続けて使用しています。要素の中の要素をチェックしています。
DOMチェックで、要素の中の要素と深いところにある要素を、この.find()メソッドチェーンを続けることでチェックできます。


# あとがき
.find()を使わなければ、非常に複雑で長ったらしいコードを書くところでした。気が付いてよかったです。
unable to find user vscode: no matching entries in passwd file

# 問題　`unable to find user vscode: no matching entries in passwd file`というエラーが出てremoteでVscodeが開けない
![スクリーンショット 2022-08-25 21.27.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1246495/f7be0225-5ecc-3e87-a0e7-aa46f61b72df.png)

## 対処:"remoteUser": "vscode"を消す
### before
![スクリーンショット 2022-08-25 21.32.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1246495/05d08913-d983-6c39-2fa7-f459e3979c3e.png)
### after
![スクリーンショット 2022-08-25 21.32.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1246495/63a2c4d6-41c1-066f-7d77-aa19fc82b793.png)

以上
他のパターンもあるみたいなのでこれで解決しない場合もあるかと思われます
CpawCTF write up(Level1) Q6

<h2>はじめに</h2>
存在自体は知っていたが、手を付けていなかった「CTF」にチャレンジしてみました。<br/>
備忘録としてアウトプットしていこうと思います。

:::note warn
注意
CTF初心者が自分で解いた方法を記載しています。
誤った情報が記載されていることがあります。
:::

<h2>Q6.[Crypto] Classical Cipher</h2>

>暗号には大きく分けて、古典暗号と現代暗号の2種類があります。<br/>特に古典暗号では、古代ローマの軍事的指導者ガイウス・ユリウス・カエサル（英語読みでシーザー）が初めて使ったことから、名称がついたシーザー暗号が有名です。<br/>これは3文字分アルファベットをずらすという単一換字式暗号の一つです。<br/>次の暗号文は、このシーザー暗号を用いて暗号化しました。暗号文を解読してフラグを手にいれましょう。
暗号文: fsdz{Fdhvdu_flskhu_lv_fodvvlfdo_flskhu}

手動で置き換えてもよいが、便利なサイトを利用しました。
[Line Segment](https://linesegment.web.fc2.com/application/cipher/Caesar.html)

ここで暗号文「fsdz{Fdhvdu_flskhu_lv_fodvvlfdo_flskhu}」を復号するとフラグを入手できました。

<h2>補足</h2>

<dl>
  <dt>シーザー暗号</dt>
  <dd>
    問題文にある通り、古代ローマの軍事的指導者ガイウス・ユリウス・カエサルが使用した単一換字式暗号の一つ。<br/>
    文字のシフト数は固定であるが、3文字分の固定である必要はない。
  </dd>
</dl>

```mermaid
graph TD;
    a-->d;
    b-->e;
    c-->f;
```

<h2>最後に</h2>
これから解いていった問題を備忘録として、アウトプットしていこうと思います。<br/>
ここまで読んでいただき、ありがとうございました。
javascript using formcontext in dynamics 365

function OnLoad() {
    // グローバルコンテキストのユーザ設定情報を取得
    var userSettings = Xrm.Utility.getGlobalContext().userSettings;
    // ユーザ名を取得して表示
    var userName = document.getElementById("userName");
    userName.innerHTML = "ユーザ名は " + userSettings.userName + " です。";
    // ユーザIDを取得して表示
    var userId = document.getElementById("userId");
    userId.innerHTML = "ユーザIDは " + userSettings.userId + " です。";
}


/*
* ログインユーザー情報取得
*
*/
function GetUserInfo() {
    debugger;
    var result = new Array();
    var loggedInUserId = Xrm.Utility.getGlobalContext().userSettings.userId;
    loggedInUserId = loggedInUserId.replace('{', '').replace('}', '');
    var globalContext = Xrm.Utility.getGlobalContext();
    var globalUrl = globalContext.getClientUrl();
    var req = new XMLHttpRequest();
    req.open("GET", globalUrl + "/api/data/v9.1/systemusers(" + loggedInUserId + ")?$select=new_system_executive,internalemailaddress,fullname,firstname,lastname", false);
    req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    req.setRequestHeader("Accept", "application/json");
    req.setRequestHeader("OData-MaxVersion", "4.0");
    req.setRequestHeader("OData-Version", "4.0");
    req.onreadystatechange = function () {
        if (this.readyState === 4) {
            req.onreadystatechange = null;
            if (this.status === 200) {
                var data = JSON.parse(this.response);
                result[0] = data.new_system_executive;
                result[1] = data.internalemailaddress;
                result[2] = data.fullname;
                result[3] = data.firstname;
                result[4] = data.lastname;
            } else {
                Xrm.Utility.alertDialog(this.statusText);
            }
        }
    };
    req.send();

    return result;
}

===================================
![img_5cb698b8bc827.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654080/1d755b65-25e2-d55b-2191-b39fea722273.png)


****************************LookUp項目取得、設定する****************
/*
 * エンティティのOnLoadイベントに追加します。
 * @para: formContext コンテキスト
 */
function OnLoad(executionContextObj) {
    debugger;
    var formContext = executionContextObj.getFormContext();
    var loginUserId = Xrm.Utility.getGlobalContext().userSettings.userId;
    loginUserId = loginUserId.replace('{', '').replace('}', '');
    var loginName = Xrm.Utility.getGlobalContext().userSettings.userName;

    var systemUserLookUp = new Array();
    systemUserLookUp[0] = new Object();
    systemUserLookUp[0].id = loginUserId;
    systemUserLookUp[0].name = loginName;
    systemUserLookUp[0].entityType = "systemuser";

    formContext.getAttribute("new_field_name").setValue(systemUserLookUp);
    
    
    var filedLabel, filedId, entityType, lookupFieldObject;
    lookupFieldObject = formContext.getAttribute("new_lookup_user");
    if (lookupFieldObject != null) {
        if (lookupFieldObject.getValue() != null) {
            filedLabel = lookupFieldObject.getValue()[0].name;
            filedId = lookupFieldObject.getValue()[0].Id;
            entityType = lookupFieldObject.getValue()[0].entityType;
        }
    }
    
}
React 立ち上げまで　メモ

①node.js
②npm
のインストール
③node -v
④npm -v
でバージョン確認し表示されたらインストール完了している。
reactアプリ作成
⑤npx create-react-app my-app
⑥作成されたmy-appフォルダにターミナルで移動して、
(ターミナル移動の仕方は調べれば無限に出てくる)
⑦npm startで画面が立ち上がる。
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
Mac版
C＃とReactのアプリを作成したかったので、
①〜④を行なった後、visualu studioをインストールして、
⑧左側の.NET Coreのアプリ→ReactとReduxを選択
⑨適当にプロジェクト名入力して作成
⑩ビルド起動 (左上の動画再生マークみたいなのおす)
⑪ClientAppで右クリックFinderで表示
⑫「情報でみる」押下でファイルの場所調べる
⑥と⑦を行う。

ファイルの場所と移動で少し時間がかかった。
CpawCTF write up(Level1) Q1

<h2>はじめに</h2>
初投稿です。存在自体は知っていたが、手を付けていなかった「CTF」にチャレンジしてみました。<br/>
備忘録としてアウトプットしていこうと思います。

:::note warn
注意
CTF初心者が自分で解いた方法を記載しています。
誤った情報が記載されていることがあります。
:::

<h2>CpawCTF</h2>
日本語の問題であり、入門者向けの易しい問題からあるため、挑戦してみました。<br/>
常設のCTFであり、「CTFとはどのようなものか」を体験するために選びました。

[CpawCTF](https://ctf.cpaw.site/index.php)

<h2>Q1.[Misc] Test Problem</h2>
この問題は問題文内にあるFLAG(cpaw{xxxxx})をそのまま入力します。<br/>
FLAGを探して、入力するというCFTの流れを理解するための問題のようです。

<h2>最後に</h2>
これから解いていった問題を備忘録として、アウトプットしていこうと思います。<br/>
ここまで読んでいただき、ありがとうございました。
Webサービスの高アクセス負荷対策

# 概要
高アクセス負荷への対策を真剣にやることになったときのために、これまでの経験 + 参考サイトの情報を列挙。
いずれ、どういったときにどれやるのが有効か？とか用語の掘り下げを詳細にまとめたい。

# アクセスが集中するタイミング
- PUSH通知による誘致
- メディア放送による誘致
- 報酬がよいイベント期間(特にランキングイベントだと終了日時間近)
- 超短期間の無料ガチャ開催

# Webサーバの負荷対策
- アクセス数自体をへらす(不変なデータはクライアント側でキャッシュしてもらう)
- スケールアウトさせる(=台数増やす)
    - 実現:LB(ELBなど),DNSラウンドロビン利用して負荷分散した上で、必要なときだけスケールアウトするオートスケーリング機能を組み込む
    - 注意すべき機能
        - セッション: 毎回クライアントが異なるサーバーにアクセスすることになるので、セッション維持を工夫する必要あり(memcachedやRDBへ保存)
        - クライアントからの画像アップロード: 各Webサーバーでなく、各Webサーバが参照する共通のストレージ(S3とか)へ
        - ログ出力: オートスケーリング利用時は、各Webサーバのログが失われるため、Fluentdなどを利用して集約
 - CDNを利用する
    - 実現: CloudFrontなどの利用
  
# DBサーバの負荷対策
## DBアクセスを実際に行うアプリケーションサーバー側での努力
- DBアクセス回数を減らせるようにする(「DBサーバ群全体の通信回数・同時接続数・処理回数」を低減)
    - 更新されないテーブルに対する(マスターデータなど)検索クエリの結果(頻度が高いもの)は、アプリケーションサーバ側でキャッシュする
    - 処理に必要なレコード群はなるべく一括で取得する
    - 関係するテーブル間レコードを取得する際はN+1問題を発生させないようにする
## DBサーバー側での努力
- 同一テーブルを複数DBにまたがせる(「1DBサーバあたりの通信回数・同時接続数・処理回数」を低減、水平分割: 1DBサーバあたりのレコード数低減による検索の高速化、そもそも1DBあたりのレコード件数上限があるので、想定外のレコード数増加によるパンク防止の効果もある)
    - 垂直分割: 同じテーブルに含まれるカラムを、更新頻度が高いもの・低いもので分割して複数DBにまたがせる
    - 水平分割(シャーディング): 同じテーブルに含まれるレコードを、IDの範囲などで分割して複数DBにまたがせる
        - こちらは、分割基準となるカラム以外での検索をするとなると、全DBへの検索が必要になってしまうことに注意(どのシャードに所属してるかわからないため。分割基準となるカラムとその分割アルゴリズムはアプリケーションサーバー側で把握している)
        - 経験したスマホゲーだと、ユーザーデータ系テーブルで「user_idの値をシャード数で割った余り」で所属シャードを決めていた。これにより、同一ユーザーのユーザーデータ系のテーブルはすべて同じシャードに所属していたので、関連レコードの検索が容易にできていた印象。
- インデックスを張る(各テーブルにおける検索の高速化)
- 書き込み用の1台のDB(マスタ)と、読み込み用の複数DB(リードレプリカ)の構成にする(書き込み読み込みに関して「1DBサーバあたりの通信回数・同時接続数・処理回数」を低減)
- DB自体のキャッシュ機能を使う

## 運用段階での継続的な改善
- スロークエリの分析・改善など


# 参考

https://medium.com/eureka-engineering/%E3%81%84%E3%81%BE%E3%81%99%E3%81%90%E5%A7%8B%E3%82%81%E3%82%8B%E9%AB%98%E8%B2%A0%E8%8D%B7%E5%AF%BE%E7%AD%96-d75ad21d602a

https://commerble.github.io/ecspec/specs/SystemLoad.html

https://dev.classmethod.jp/articles/developers-io-2019-in-osaka-aurora-or-rds/

https://postd.cc/a-beginners-guide-to-scaling-to-11-million-users-on-amazons/
DNSレコードの種類

## はじめに
- 業務で Route53 の設定変更の際にDNSレコードの知識を使用するので、備忘録として残しておきます。

## DNSレコードの種類

|  レコード  |  説明  |
| ---- | ---- |
|  A (Address) |  特定のホスト名に対応するIPv4アドレスを定義  |
|  AAAA  |  特定のホスト名に対応するIPv6アドレスを定義  |
|  PTR (Pointer)  |  特定のIPアドレスに対応するホスト名を定義  |
|  MX (Mail Exchanger)  | 対象ドメイン宛のメールの配送先（メールサーバー）のホスト名を定義するレコード  |
|  NS (Name Server)  | ドメインのゾーン情報を管理するDNSサーバーを定義  |
|  SOA (Start Of Authority record)  |  ドメインに関する管理情報を格納(管理者の電子メールアドレス)  |
|  TXT (text record)  |  ホスト名に関連付けるテキスト情報の定義 |
|  CNAME (Canonical Name record) |  正規ホスト名に対する別名を定義  |

## 参考
- [【ドメイン】DNSレコード設定の各レコードの意味を教えてください。](https://help.onamae.com/answer/7883)
- [DNSレコード](https://www.cloudflare.com/ja-jp/learning/dns/dns-records/)