OmniAICreator/Qiita-1.07M huggingface dataset:
MoCA 2.5 を使用しTVの同軸ケーブルを使ってLAN構築

# はじめに
新築で建売住宅を購入すると、TVアンテナ用として各部屋に同軸ケーブルの配線はされているけど、LANケーブルは通っていないし配管すらないなんてこと、あると思います。私もその1人です。
なんとか同軸ケーブルで通信させることができないか探したところ、**MoCA 2.5** という規格の機器を使用することで、最大2.5Gbpsで通信させることができるとのこと。しかし、日本語での情報がほとんどなかったため、機器を購入して実際に試してみました。

# MoCAとは
MoCAとは、Multimedia over Coax Allianceの略で、住宅用アンテナ同軸ケーブルを利用したホームネットワーキングの仕様を開発している業界団体です。

https://en.wikipedia.org/wiki/Multimedia_over_Coax_Alliance

2016年に登場したMoCA 2.5では、最大で2.5Gbpsの速度を出すことができます。100MHzの帯域を5つ束ねることで(=500MHz)、2.5Gbpsの速度を実現しているようです。goCoax社の製品では、1125〜1675 MHz（Extended Band D）の帯域をサポートしています。

https://www.gocoax.com/

# 日本で使用する上での注意点
TVアンテナを設置していれば、当然同軸ケーブルには地上波放送やBS放送の信号も乗っています。MoCAは海外で策定されている規格であるため、日本国内の事情が考慮されていません。そのため、下記を考慮する必要があります。
- 電波が外部に発信されないこと
- 地上波放送やBS放送の信号を伝送する周波数と干渉しないこと

## 電波が外部に発信されないこと
電波の発信については、日本国内においては電波法で厳しく制限されています。TVアンテナとMoCAの機器が直接接続されていると、アンテナから電波が放出してしまう恐れがありNGです。

## 地上波放送やBS放送の信号を伝送する周波数と干渉しないこと
TVの信号で使用している周波数と干渉してしまうと、電波が混信してしまい、TVとMoCAの両方が使用できなくなってしまいます。そのため、地上波放送やBS放送の信号を伝送する周波数と干渉しないかを検証する必要があります。詳細は下記に記載しますが、結論はBS放送の周波数と干渉してしまうため、地上波デジタル放送のみとの併用であれば使用できると考えられます。
### 地上波デジタル放送
日本では、地上波デジタル放送に470MHzから710MHz（Ch.13 - 52）を使用しており、関東広域圏の場合は、以下の周波数を使用しています。（参照元：[テレビ周波数チャンネル-Wikipedia][1]）

|テレビ局|チャンネル|周波数範囲（MHz）|
|:-:|:-:|:-:|
|NHK総合|27|554.357857 - 559.927857|
|NHKEテレ|26|548.357857 - 553.927857|
|日本テレビ|25|542.357857 - 547.927857|
|テレビ朝日|24|536.357857 - 541.927857|
|TBSテレビ|22|524.357857 - 529.927857|
|テレビ東京|23|530.357857 - 535.927857|
|フジテレビ|21|518.357857 - 523.927857|

MoCA2.5（1125〜1675 MHz）と地上波デジタル放送（470MHz～710MHz）は周波数が重複しないため、併用して使用できそうです。

### 衛星放送（BSデジタル放送）

BS放送の場合は、同軸ケーブル中で1032.23～1488.69MHz、2224.41～2680.87MHzの範囲を使用しており、NHKのチャンネルは以下の周波数を使用しています。（参照元：[テレビ周波数チャンネル-Wikipedia][1]、[日本における衛星放送-Wikipedia][2]）

|テレビ局|チャンネル|BS-IF周波数（MHz）|
|:-:|:-:|:-:|
|NHK BS1|BS-15ch|1300.75 - 1335.25|
|NHK BS4K|BS-17ch|1339.11 - 1373.61|
|NHK BS8K|BS-14ch|2454.57 - 2489.07|

MoCA 2.5で使用する周波数は1125〜1675 MHzであるため、干渉してしまうと考えられます。

# 購入・設置
我が家は地上波デジタル放送のみの環境で、今後もBSを増やす予定はないため、機器を購入して設置してみました。電波が発信されないよう、アンテナまでの間にローパスフィルタ(LPF)などのMoCAの電波が外部に漏れないようにするための機器を挟み込みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/776880/61a1822a-ecb4-be4b-2b13-caaf7c72f8d8.png)

MoCAアダプタ自体の接続はシンプルで、部屋にある同軸ケーブルを差すところにMoCAアダプタを差し込むだけです。ただし、1Fの差込口はTVとも共用したかったため、分波器を用いてTVとMoCAアダプタに分岐させています。MoCAアダプタはBS/CS用の差込口に差せば問題ありません。

# 速度測定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/776880/0bcfcc03-91b7-8600-05b9-26cc4bffc40d.png)

2FのPCから1Fに設置しているNASへ通信を試みたところ、77.2MB/s＝618Mbpsの通信速度が出ています。おそらくNASの上限値に引っかかっているようで、インターネットのスピードテストでは700Mbpsを超えることもありました。MoCA 2.5の機器同士では2.5Gbpsをサポートしていますが、家庭内のLAN環境はギガビットイーサネットなので、十分なスピードが出ていると考えられます。

# その他
BS放送が視聴できる環境だけど同軸ケーブルで通信させたい場合は、以下のような製品もあります。
[DXアンテナ 同軸線モデムシリーズ][3]
これらの製品は、使用する周波数が2〜60MHzとなっているため、地上波デジタル放送やBSデジタル放送の周波数と干渉せずに使用することができます。ただし、通信速度は低めです。（法人向けで330Mbps、家庭向けは90Mbps）

[1]:https://ja.wikipedia.org/wiki/%E3%83%86%E3%83%AC%E3%83%93%E5%91%A8%E6%B3%A2%E6%95%B0%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%AB
[2]:https://ja.wikipedia.org/wiki/%E6%97%A5%E6%9C%AC%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E8%A1%9B%E6%98%9F%E6%94%BE%E9%80%81
[3]:https://www.dxantenna.co.jp/business/dxdelcatec-eoc/
scipy.stats.mannwhitneyuのデフォルト設定に注意

## 結論
scipyでマンホイットニーU検定をする際は，alternative=‘two-sided’を省略すると結果表示が変わってくる可能性があるので，省略せずに明示した方が良い．  

現時点での最新版(scipy 1.8.0)のデフォルト設定は，

```python
# scipy version 1.8.0
# https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.mannwhitneyu.html
scipy.stats.mannwhitneyu(x, y, alternative="two-sided")
```

であるが，過去のバージョン(scipy 1.6.1)では

```python
# scipy version 1.6.1
# https://docs.scipy.org/doc/scipy-1.6.1/reference/generated/scipy.stats.mannwhitneyu.html
scipy.stats.mannwhitneyu(x, y, alternative=None)
```

である．
None: computes p-value half the size of the ‘two-sided’ p-value and a different U statistic.
との説明があり，alternativeの記述を省略すると，同じコードでも環境により異なる計算結果が出てくる可能性がある．
（alternative=Noneは最新版だと非推奨．動作しない？）

## 気づいたきっかけ
[stat_annot](https://github.com/webermarcolivier/statannot)パッケージのadd_stat_annotationで計算されるp値と，scipy.stats.mannwhitneyuで計算したp値が違う現象に遭遇し，原因究明のためソースコードを確認した．

その結果，
・add_stat_annotationのtest='Mann-Whitney'の中身ではalternative=‘two-sided’と書かれている一方で，自分で計算したコードでは宣言が省略されていること，
・環境に入っていたScipyのバージョンが1.6.1であり，デフォルトの設定がalternative=Noneになること
が原因であることが分かった．
100日でSQLの達人になる@LeetCode! Day39 <要復習: WITH句で再帰SQL>

## 1270. All People Report to the Given Manager （問題レベル: Medium）要課金
今日の問題はこれ。
職員IDとそのスーパーバイザーのIDがある表から社長（ID=1)からたどれる社員IDを全て列挙せよ（ただし３回層まで）という問題。

たかだか３回層なので愚直に記載して提出したものがこれ。
```:SQL
SELECT t1.employee_id
FROM employees t1
WHERE t1.manager_id=1 AND t1.employee_id !=1

UNION

SELECT e.employee_id
FROM employees e
JOIN
(SELECT employee_id FROM employees WHERE manager_id=1 AND employee_id !=1) t2
ON t2.employee_id=e.manager_id

UNION

SELECT e2.employee_id
FROM employees e2
JOIN
(
SELECT e.employee_id
FROM employees e
JOIN
(SELECT employee_id FROM employees WHERE manager_id=1 AND employee_id !=1) t2
ON t2.employee_id=e.manager_id
    ) t3
    ON t3.employee_id=e2.manager_id
```

しかし`Discuss`には下記の通り`WITH`句を使った`再帰SQL`の手法が紹介されていました。
```:SQL
WITH CTE AS (
    SELECT employee_id
    FROM Employees
    WHERE manager_id = 1 AND employee_id != 1
    UNION ALL
    SELECT e.employee_id
    FROM CTE c INNER JOIN Employees e ON c.employee_id = e.manager_id
)
SELECT employee_id
FROM CTE
ORDER BY employee_id
OPTION (MAXRECURSION 3);
```

これまで`WITH`句は何度もみかけて知っていましたがあまり有用性を理解していませんでした。
`再帰SQL`で使うにはとても便利な記法だと分かりました。
しかし、`再帰SQL`はまだ十分に理解できていないのでまた復習したいと思います！

今日のポイントは`WITH`句は`再帰SQL`に使えるとしました。

* [LeetCode](https://leetcode.com/)の問題は、`MS SQL Server`で解いています。
docker-compose　build定義とは？

# docker-compose　build定義とは？

`Services top-level element`で定義される`build`定義とは何なのか、軽くまとめました。

## build定義

build要素は、ソースから`Docker image`をビルドするためにCompose実装によって適用される構成オプションを定義します。ビルドは、ビルドコンテキストへのパスを含む文字列または詳細な構造として指定できます。

最もシンプルに書くなら、dockerfileがあるディレクトリの相対パスを以下のように記述すれば良いです。

```yaml
services:
  webapp:
    build: ./dir
```

この文字列構文を使用すると、ビルドコンテキストのみを作成ファイルの親フォルダーへの相対パスとして構成できます。
このパスはディレクトリであり、Dockerfileが含まれている必要があります。

### 保持できるフィールド

| フィールド | 説明 |
| - | - |
| context (REQUIRED) | Dockerfileを含むディレクトリへのパス、またはgitリポジトリへのURLのいずれかを定義します。 |
| dockerfile | 代替Dockerfileを設定できます。相対パスは、ビルドコンテキストから解決する必要があります。 |
| args | ビルド引数を定義します。 |
| ssh | イメージビルダーがイメージビルド中に使用する必要があるSSH認証を定義します（例：プライベートリポジトリのクローン作成） |
| cache_from | ImageBuilderがキャッシュ解決に使用する必要があるソースのリストを定義します。 |
| cache_to | ビルドキャッシュを将来のビルドと共有するために使用されるエクスポート場所のリストを定義します。 |
| extra_hosts | ビルド時にホスト名マッピングを追加します。 |
| isolation | ビルドのコンテナ分離テクノロジーを指定します。 |
| labels | 結果のimageにメタデータを追加します。ラベルは、配列またはマップのいずれかとして設定できます。 |
| shm_size | Dockerイメージの構築に割り当てられる共有メモリ（Linuxでは/ dev / shmパーティション）のサイズを設定します。 |
| target | マルチステージDockerfile内で定義されているようにビルドするステージを定義します。 |

## 参考

[compose-spec/build.md at master · compose-spec/compose-spec](https://github.com/compose-spec/compose-spec/blob/master/build.md)
Python でキーボードイベントを確認するための簡単な方法

keyboard https://github.com/boppreh/keyboard を使います。

上のリンクと下のコードだけでわかると思いますが、需要があれば解説を足します。
```
pip install keyboard

python -m keyboard
```
実行例
```
{"event_type": "down", "scan_code": 16, "name": "q", "time": 1646975615.8746192, "is_keypad": false}
q{"event_type": "up", "scan_code": 16, "name": "q", "time": 1646975615.9862385, "is_keypad": false}
{"event_type": "down", "scan_code": 42, "name": "shift", "time": 1646975617.9866295, "is_keypad": false}
{"event_type": "up", "scan_code": 42, "name": "shift", "time": 1646975618.059266, "is_keypad": false}
{"event_type": "down", "scan_code": 54, "name": "right shift", "time": 1646975621.0223727, "is_keypad": false}
{"event_type": "up", "scan_code": 54, "name": "right shift", "time": 1646975621.0913706, "is_keypad": false}
{"event_type": "down", "scan_code": 29, "name": "right ctrl", "time": 1646975624.3792064, "is_keypad": false}
{"event_type": "up", "scan_code": 29, "name": "right ctrl", "time": 1646975624.4272087, "is_keypad": false}
{"event_type": "down", "scan_code": 28, "name": "enter", "time": 1646975626.379538, "is_keypad": false}
```
最後の Enter で抜けています。
GoogleWorkSpace LDAPサーバ作成方法(Jamf Pro連携用)

# 背景
JamfProをちゃんと導入検討＆勉強しようということで。
GoogleWorkSpaceのアカウント情報をJamfProに連携させるよ。
ハマる落とし穴があるのでメモを残します。

参照先：
・[Google のセキュア LDAP 統合](https://docs.jamf.com/ja/10.30.0/jamf-pro/administrator-guide/Google_%E3%81%AE%E3%82%BB%E3%82%AD%E3%83%A5%E3%82%A2_LDAP_%E7%B5%B1%E5%90%88.html)
・[Generating a PKCS12 (.p12) Keystore File from a Google Cloud LDAP Client](https://docs.jamf.com/technical-articles/Generating_the_PKCS12_Keystore_File_When_Integrating_Google_Cloud_Identity_Provider_with_Jamf_Pro.html)

# やること
1. GoogleWorkSpace側にLDAPサーバを作る
1. JamfProに連携させる

# 手順
1. Jamf Pro にログイン。
1. "システム設定" > "クラウドアイデンティティプロバイダ"
1. "新規"をクリック
1. Google を選択
1. 表示名は適当に入力(e.g. GoogleWorkSpace)
1. LDAPSが選択されているはずなのでそのまま(次のポート番号も勝手に入力済みになってるはず e.g. ldap.google.com:636)
1. ドメイン名はGoogleWorkSpaceで利用してるドメイン名入れる(e.g. favy.co.jp)
1. keystoreには GoogleWorkSpace側で作ったcrtとkeyを使ってp12ファイルを生成する必要がありますので、**ここで一旦保留**

次にGoogle側にログインします。
1. GoogleWorkSpaceの管理者画面にログイン(https://admin.google.com/)。
1. "アプリ" > "LDAP"
1. "クライアントを追加"
1. LDAPクライアント名は適当に入力(e.g. JamfPro)
1. 説明も適当に入力。省略可能。
1. "続行"を押して次の画面へ
1. アクセス権限を適した内容に設定(大体はドメイン全体を選択することになりそう)
1. "クライアントを追加"を押す
1. その後の画面で「証明書のダウンロード」が出てくるのでダウンロードする(e.g. Google_2025_03_10_17409.zip)
1. 元の画面に戻って "アプリ" > "LDAP"
1. 今作った設定の　**「サービスのステータス」を"オン"に変更**

今度は手元でコンソールを開きます。
1. ダウンロードしてきてたzipを解凍してcrtとkeyを取り出す。
1. `openssl pkcs12 -export -out /path/to/generated/keystore.p12 -inkey /path/to/saved/privatekey.key -in /path/to/saved/certificate.crt` でp12ファイルを生成する
1. コンソール上でパスワードを入力(e.g. p8WkXm6fのようなランダム文字で。2回入力)
参考： ・[Generating a PKCS12 (.p12) Keystore File from a Google Cloud LDAP Client](https://docs.jamf.com/technical-articles/Generating_the_PKCS12_Keystore_File_When_Integrating_Google_Cloud_Identity_Provider_with_Jamf_Pro.html)

元のJamfProに戻ります。
1. keystoreに作ったp12ファイルをドラッグ
1. Keystore パスワード に上記コンソールで2回入力したパスワードを入力
1. 右下の保存

これで完了です。

罠1は、LDAPのサービスを作った後の「オン」にする作業。
罠２は、p12ファイルの生成(パスワードの打ち間違えなどに注意)

以上です。
【Unity2D】カードを裏返すアニメーションを作る

# やりたいこと
<b>カードをひっくり返すアニメーション</b>を作ります。
タッチで裏返したようなUIは簡単に動きが出せるので、トランプ等のカードゲームを作る際はもちろん、他のゲームでも重宝しそうです。

<img width="400" alt="card_turn" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2508660/b15aa727-9282-f91b-ff19-407fa5d75767.gif">

# 方法
カードの横幅を100% → 0% → 100%と連続で変化させると、2D視点ではまるでY軸で回転しているように見えます。
あとは横幅0%の瞬間画像(sprite)を変更すれば完成です。

アニメーションウィンドウからコードレスで作ることも当然可能ですが、汎用性や操作性の面から今回はコードで実装します。
アニメーション部分はコルーチンで記述しています。

以下のコードをひっくり返したいImageにくっつけて、StartTurn()を呼び出せばokです。

```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TurnCard : MonoBehaviour
{
    public Sprite spriteCardFront;
    public Sprite spriteCardBack;

    static bool isFront = true;  // カードの表裏
    static float speed = 4.0f;  // 裏返すスピード 裏返しには(2/speed)秒かかる

    RectTransform rectTransform;
    Image cardImage;


    private void Awake()
    {
        rectTransform = GetComponent<RectTransform>();
        cardImage = GetComponent<Image>();
    }

    // 初期設定
    private void Start()
    {
        if (isFront)
        {
            cardImage.sprite = spriteCardFront;
        }
        else
        {
            cardImage.sprite = spriteCardBack;
        }
    }

    // コルーチンの開始
    public void StartTurn()
    {
        StartCoroutine(Turn());
    }

    // 裏返す
    IEnumerator Turn()
    {
        float tick = 0f;

        Vector3 startScale = new Vector3(1.0f, 1.0f, 1.0f); // 開始時のスケール
        Vector3 endScale = new Vector3(0f, 1.0f, 1.0f); // 中間地点のスケール (x = 0)

        Vector3 localScale = new Vector3();


        // (1/speed)秒で中間地点までひっくり返す
        while (tick < 1.0f)
        {
            tick += Time.deltaTime * speed;

            localScale = Vector3.Lerp(startScale, endScale, tick); // 線形補間

            rectTransform.localScale = localScale;

            yield return null;
        }

        // カードの画像(sprite)を変更する
        if (isFront)
        {
            cardImage.sprite = spriteCardBack;
        }
        else
        {
            cardImage.sprite = spriteCardFront;
        }

        // 表裏を変更
        isFront = !isFront;
        
        tick = 0f;

        // (1/speed)秒で中間から最後までひっくり返す
        while (tick < 1.0f)
        {
            tick += Time.deltaTime * speed;

            localScale = Vector3.Lerp(endScale, startScale, tick);

            rectTransform.localScale = localScale;

            yield return null;
        }
    }
}
```

# 使用例
UI.Imageのカードを用意して、上のスクリプトをアタッチします。
インスペクターからspriteCardFront(表の画像)とspriteCardBack(裏の画像)を登録してください。
今回は「カードをクリックすると裏返る」ようにしたいので、EventTriggerのPointerClickを使っています。
これでカードをクリックすると、StartTurn()が呼び出され、カードが裏返るようになりました。
![スクリーンショット 2022-03-11 13.23.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2508660/5c0d12c1-9c95-a576-6db8-9aa56d4287aa.png)

これだけでも何だか嬉しいですね。
<img width="300" alt="card_turn" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2508660/b15aa727-9282-f91b-ff19-407fa5d75767.gif">

以上です。
配列操作：新しい配列をスプレッド構文でコピーし変数に代入後、変数自体を操作するvs 配列の展開と同時に配列操作する 


# はじめに
先日スプレッド構文を用いて配列を扱う学習を行っていた際に気がついたことがありましたので、書き残しておきたいと思います。
スプレッドした配列を変数に入れる、つまり配列のコピーを作ってから配列メソッドを実行する場合
と
スプレッドした配列自体に配列メソッドを実行する
のではどのような違いがあるのかについて調べました。

### 配列をコピーし、変数に格納した後、変数に対して要素を追加する
```javascript
 const originalArr = [0,1,2,3,4,5];
 
 const newArr = [...originalArr];
 newArr.push(6);//元の配列をコピーし、全く別の配列として定義した後、作成した配列に対して追加メソッドを実行
 
 console.log(newArr)//[0,1,2,3,4,5,6]
```
これは想定通りの挙動をしていると思います。

僕が問題にぶち当たったのは、次のパターンです。

### スプレッドした配列そのものに対して追加メソッドを実行
```javascript
 const originalArr = [0,1,2,3,4,5];
 
 const newArr = [...originalArr].push(6));//スプレッドした配列に対してpush
 console.log(newArr)//[7];//push()の返り値である配列lengthが代入されている
```
？？？

と思ったのですが、@dswc　様からご教授をいただきました。ありがとうございます。
# なぜ異なる結果になるのか？
上述のコード：元の配列をスプレッドし、展開された配列に対してメソッドを実行する動作を一度に行うコードを日本語に直すと
```
const 変数 = [...配列を展開する動作].展開した配列に対するメソッド();
```
となります。
ここにおいて変数には、配列メソッドが実行された元の配列ではなく、元の配列に対して実行された**配列メソッドの戻り値**が代入されているのです。
今回で言えば、`Array.push()`は**メソッドが実行された配列のlengthを返す**ので、変数には`orginalArr`のlength、つまり`7`が代入されます。
```javascript
 const originalArr = [0,1,2,3,4,5];
 
 const newArr = [...originalArr].push(6));//push()メソッドの戻り値である配列のlengthが代入
 console.log(newArr)//7
```

試しに、push()の引数を指定せずに実行すると、
```javascript
const originalArr = [0,1,2,3,4,5];
const newArr = [...originalArr].push();
console.log(newArr)//6 ←配列の長さに変化なし！
```
となり、実行元の配列の長さが代入されています。


普段配列メソッドを使う時、実行した配列にしか注目してこなかったため、今回のように配列メソッドの戻り値を意識したことがなく、大変驚きました。
改めて、ご指摘いただきありがとうございます！


### おまけ：　スプレッドした配列自体に対して実行された配列メソッドの効果はどうなっているの？？
今回のトピックとは関係ないですが、配列のスプレッドと配列メソッドを一度に実行した場合、元の配列はどうなっているのでしょうか。
つまり、
```javascript
const originalArr = [0,1,2,3,4,5];
const newArr = [...originalArr].push(6);
```
こうした場合、`originalArr`はどのようになっているのでしょうか。私は、先述したとおり、push()メソッドの戻り値が6→7変化していたことから`originalArr`には新しい値が追加されていると思っていたのですが、実際には:

```javascript
console.log(orignalArr)//[0,1,2,3,4,5]
```
なんと、originalArrの中身は変化していませんでした。
つまり、**スプレッド構文を用いて展開した配列を実行元とした配列メソッド**には**効果がない**のですね。
push以外にspliceメソッドも実行してみましたが、同様でした。
あくまで配列メソッドの戻り値だけが変化して返ってきているみたいなので、気をつけたほうが良さそうです。

# 結論：配列を操作するなら、一旦元の配列のコピーを作成してからにすべし
immutableな処理を行うためにも、

1:元の配列をスプレッドしてコピーを作成
2:コピーに対して配列操作をしてあげる

が無難なのかな・・・と思います。
Pythonでロゴなどを中央に配置したQRコードを生成する

[qrcode]:https://pypi.org/project/qrcode/
[Pillow]:https://pypi.org/project/Pillow/
App StoreやGoogle Playに誘導する際に、中央にロゴ付きのQRコードを使いたい場合がありますが、PythonのQRコード生成ライブラリと（[qrcode]）と、画像処理のライブラリ（[Pillow]）を使うと比較的かんたんにできたので備忘録を兼ねて情報を共有します。

ちなみに、ロゴ入りのQRコードですが、QRコードの仕様にロゴの部分を避けるような仕組みがあるのではなく、エラー訂正機能によりロゴで隠れている部分は補正してしまうという少々強引な感のあるハックで実現されていて大変興味深いです。誰が最初に始めたのでしょう？

## 実装例

こんな感じの実装になります:

```python
def encode_qr_with_logo(body, logo_filename, output_filename, transparent=False, size=0, version=None, logo_bg='white'):
    qr = qrcode.QRCode(
            version=version,
            error_correction=qrcode.constants.ERROR_CORRECT_Q)
    qr.add_data(body)
    qr.make()
    qr_image = qr.make_image().convert('RGB')
    if size == 0:
        MARGIN_WIDTH = 40   # 4 modules
        size = (qr_image.width - (MARGIN_WIDTH * 2)) // 4
    logo = Image.open(logo_filename).convert('RGBA')
    logo = logo.resize((size,size), resample=Image.LANCZOS)
    pos = ((qr_image.size[0] - logo.size[0]) // 2, (qr_image.size[1] - logo.size[1]) // 2)
    if transparent:
        qr_image.paste(logo, pos, logo)
    else:
        logo_bg = Image.new('RGB', logo.size, logo_bg)
        logo_bg.paste(logo, mask=logo)
        qr_image.paste(logo_bg, pos)
    qr_image.save(output_filename)
```

- `body` &mdash; QRコードに変換する文字列
- `logo_filename` &mdash; ロゴの元データのファイル名
- `output_filename` &mdash; 生成したQRコードを保存するファイル名
- `transparent` &mdash; 透過PNGの処理をするかのフラグ（Bool値）
- `size` &mdash; ロゴのサイズ（px）
- `version` &mdash; QRコードのバージョン（ほぼサイズと同じと考えて良い）

出力はこんな感じ：

![sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423595/81e48f2c-e331-9eb6-832e-7baa88d4b468.png)

## ポイント

1. Error Correction を `ERROR_CORRECT_Q` に設定し、QRコードを生成します（通常の誤り補正レベルです）。
    1. QRコードの [仕様](https://www.qrcode.com/about/error_correction.html) によれば、この場合の誤り訂正能力は約25%となります。
    1. これにより、画像がQRコードの上に重なっていても補正により情報が伝達できます。たとえばQRコードの幅の25%程度の幅でロゴを描画しても問題なく認識できます（ロゴで隠れる大きさは6.25%未満となるため）。
1. 上の例ではロゴは正方形であることを想定しています。これをリサイズして利用します。
1. リサイズした画像を、最初のステップで生成したQRコードの画像の上に貼り付けます。
    1. この際、重ねるアイコンが透過PNGの場合、`paste()` の引数として自分自身をマスクに設定してあげればPNGの透明部分を透過して貼り付けることが可能です。
    1. 逆に透過させたくない場合、背景色の箱を作ってその上にロゴを貼り付けたもの（上記コードだと `logo_bg`）をQRコードの画像上に貼るという処理にすると透過部分の色のコントロールができます。
1. ロゴのサイズを計算により算出する場合は、以下を考慮すると良いでしょう：
   1. `qrcode` モジュールでは特に指定しない場合、QRコードの１セルの大きさは10pxで描画されます。
   1. [仕様](https://www.qrcode.com/howto/code.html) に従い、特に指定しない場合、QRコードには4セル分のマージンがつきます。

## 成果物

https://github.com/aikige/qr_with_logo

[pip](https://github.com/pypa/pip) でインストールできる形にしてあるので、比較的簡単にインストールできるはずです。

## 確認した環境

```
$ uname -a
Darwin wlc-lap-114.local 21.3.0 Darwin Kernel Version 21.3.0: Wed Jan  5 21:37:58 PST 2022; root:xnu-8019.80.24~20/RELEASE_ARM64_T8101 x86_64
$ python --version
Python 3.7.9
$ pip list | grep -i -e 'pillow' -e 'qrcode'
Pillow                         9.0.1
qrcode                         7.3.1
```
Error: Permission denied @ apply2files - /usr/local/share/ghostscript/... の対処法

## エラー内容

```bash
Error: Permission denied @ apply2files - /usr/local/share/ghostscript/...
```


## 解決方法

該当ディレクトリのユーザとグループを変更することで解決できる。

今回の場合、修正前は次のようになっていた。

```shell
 ls -la /usr/local/share
> ...
> drwxrwxr-x    4 root    wheel   128 12 24 19:58 ghostscript
> ...
```

`chown`により、該当ディレクトリのユーザとグループを変更する。
ただし、`username`には任意のユーザ名を入力する。

```shell
sudo chown -R username:admin /usr/local/share/ghostscript/
```

修正後は次のようになる。

```shell
 ls -la /usr/local/share
> ...
> drwxrwxr-x    4 username  admin   128 12 24 19:58 ghostscript
> ...
```

これでエラーの原因は解決される。

## 参考文献

https://webkaru.net/linux/chown-command/

https://geniusium.hatenablog.com/entry/2019/12/20/230947
同じテーブルに複数の関連づけ



# 前提条件
Staff（職員）は複数のAsessments（評価）を持っている。その評価には評価される人(staff_id)と評価する人（input_staff_id）が存在する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2508607/a56f21f1-3c0f-760f-0ad8-fe7b89523968.png)

# やりたいこと
StaffがAssessmentテーブルのstaff_idとinput_staff_idの両者共に関係を持つようにModelに追記したい。

# 方法
外部キー(foreign_key)と関連先のクラス名(class_name)を指定するだけでOK。

```Assessment.rb
belongs_to :input_staff, foreign_key: 'input_staff_id', class_name: 'Staff'
belongs_to :staff, foreign_key: 'staff_id'
```

`input_staff`と`staff`が使用できるメソッドになる。

```Staff.rb
has_many :input_assessments, foreign_key: 'staff_id', class_name: 'Assessment'
has_many :assessments, foreign_key: 'staff_id'
```

`input_assessments`と`assessments`が使用できるメソッドになる。

# 使い方
以下のように呼び出すことができるようになる

```ruby
assessment = Assessment.find(10)
staff = staff.find(10)

評価を登録したstaffを取得したい時
assessment.input_staff

評価されるstaffを取得したいとき
assessment.staff

入力した評価を取得したい時
staff.input_assessments

評価されたstaffの評価を取得したい時
staff.assessments
```

また、joinsの中にも使うことができる
```ruby
シンプルなjoins
staff.joins(:input_assessments)

staffテーブルと連結する関連先カラムの条件で絞り込みしたい時
staff.left_joins(:input_assessments).merge(Assessment.where(条件))
```



## 参考にした記事
[アソシエーションにおけるclass_nameの定義！](https://qiita.com/wacker8818/items/eccdf0a63616feb14a70)

[belongs-toで追加されるメソッド](https://railsguides.jp/association_basics.html#belongs-to%E3%81%A7%E8%BF%BD%E5%8A%A0%E3%81%95%E3%82%8C%E3%82%8B%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89)

[has-manyで追加されるメソッド](https://railsguides.jp/association_basics.html#has-many%E3%81%A7%E8%BF%BD%E5%8A%A0%E3%81%95%E3%82%8C%E3%82%8B%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89)
flaskでおうむ返しbotのコードをherokuにpushするときに生じたエラーまとめ

https://programming-holic.com/2021/12/23/python-flask-linebot/
この記事にそっておうむ返しbotを作成しました。
あくまで個人的なメモです。最低限参考リンクは貼るようにしました。

# 1. requirementsをpushするときのエラー
https://teratail.com/questions/379xix14utnidw

requirementsの中にバージョンでなくパス形式の記載があることが問題。
パスの記載部分をすべて削除することで解決

# 2. slug sizeが大きすぎる
requirementsに要らないパッケージが多すぎたのが原因。今回はおうむ返しbotを作るだけなのでtensorflowやKerasなど重いものはrequirementsから削除

# 3. ルーティングできない
https://teratail.com/questions/125939

# 4. gitから狙ったプロジェクトにアップロードできない
元のサイトだと
$ heroku login
$ git init
$ git add .
$ git commit -am "make it better"
$ git push heroku master
の流れで解説されていますが
heroku git:remote -a アプリ名　を差し込みます

以上です。自分向けに書いたのでだいぶわかりにくいと思いますがどなたかの参考になればと思います。それでは👋
【Vue.js】ファイルアップロード時、前回と同じファイルがアップロードできない



# 事案

Vueでファイルを選択し、アップロードする処理を書きました。

下記はファイルを選択するコンポーネントのコードの例です。
``` Vue
<template>
  <label>
    ファイルを選択
    <input type="file" @change="onChange">
  </label>
</template>
```

ところが、これだとファイルを選択して、再度同じファイルを選び直した時に
アップロードの処理が走らなくなっていました。
これでは、例えばアップロードの処理が失敗した時などに、再度同じファイルを選べないので困ります。

アップロードができない理由としては、同じファイルを選択するとonChangeが発火していないためのようです。


# 解決策

valueを空にしてあげるonClickを追加すればOKでした。

``` Vue
<template>
  <label>
    ファイルを選択
    <input
      type="file"
      @change="onChange"
      @click="(e) => { e.target.value = '' }"
    >
  </label>
</template>
```



# 参考記事

[input fileで同じファイルを連続で選ぶとonChangeが発火しない問題](https://strip.koatech.info/articles/vue-input-same-file/)
データベース上のテーブル名とカラムデータを確認する方法（Ruby on Rails）

（開発環境：Ruby3.1.0　Rails7.0.2.2）

まずはターミナルで確認したいアプリケーションディレクトリに移動（ディレクトリの移動方法：cd １階層下のディレクトリ名）


```ruby:ターミナル
ディレクトリ名% rails c　#Railsコンソール起動
irb(main):001:0> 確認したいデータのモデル名.all
```


これで以下のようにテーブル名とカラムデータの内容が確認できます。

```sql:ターミナル
 (1.8ms)  SELECT sqlite_version(*)
  モデル名 Load (0.3ms)  SELECT "テーブル名".* FROM "テーブル名" 
id: 1,　#自動生成                                                           
  name: nil,　#任意に生成したデータ名（データ名は（例）name、nilは値が何もないという表記）                                                                                                           
  created_at: Mon, 28 Feb 2022 21:49:47.896089000 UTC +00:00,　#自動生成     
  updated_at: Mon, 28 Feb 2022 21:49:47.896089000 UTC　#自動生成
```
ドメイン駆動設計（DDD）の原則をアプリケーションに適用する

刻々と変化する顧客のニーズに完璧に対応するプログラムを設計したいですか？挑戦を受けます:v:。

これは大きな課題ですが、幸いなことに、**ドメイン駆動設計**が私たちを助けてくれるのです。

開発者である私たちは、コードに潜るのが大好きです。 最新の技術を試し、新たな課題に取り組むことを期待しています。それはよくわかります。しかし、一歩も引かずにコーディングすると、大抵の場合、修正が困難な脆弱なソリューションになってしまいます。

でも、顧客がいつもしていることをご存知でしょうか？考えを変える！アプリケーションを変更するたびに髪をかきむしるのを避けたいなら、それを予期する能力が必要です。

このコースでは、複雑な問題に対処するソフトウェアを設計するための包括的なアプローチであるドメイン駆動設計（DDD）について学びます。

このコースの前半では、「DDDとは何か」を発見します。顧客との**コラボレーション**、特にビジネスロジックを理解することために、顧客の視点からアプリケーションを理解する方法について説明します。ここでは、ビジネスロジックをコードに最適な形で転記するための**共通語彙**を作成する方法について説明します。

後半では、UMLのユースケース図とクラス図を用いて、最初の**ドメインモデル**を一緒に作成します。エンティティ・オブジェクト、バリュー、アグリゲートという概念が、プログラミングの味方になってくれます。

これで、アプリケーションを納品した後、クライアントから「『忘れてしまった！それもやってもらえませんですか？あれを修正してもらえませんですか？それほど難しいことではないよね！」」と言うコメントを下げます。

## 目的
- ドメイン駆動設計の手法でユーザーニーズを把握する。
- ユーザー要求をドメインモデルで定式化する。

## 流れ

### 第1部　ドメイン駆動設計手法によるユーザーニーズの把握
- [ドメインモデルで設計上の問題を解決する](https://qiita.com/monchan-suzuki/items/0f1f8bc071c015e7e857)
- ドメイン駆動設計のアプローチでモデルを構築する（構築中）
- イベントストーミングでアプリケーションの目的を明確にする（構築中）
- 顧客のモデルにおけるアクター、ユースケース、エンティティの特定（構築中）

### 第2部　ユーザーのニーズを形にする
- ユースケース図によるドメインモデルの形式化（構築中）
- クラス図から共通用語集を定義する（構築中）
- クライアントのニーズの変化に対応したダイアグラムの作成（構築中）
- ドメインモデルの実装（構築中）
Next.jsでRecoilの永続化

ログイン認証済みかどうかの判別をRecoilに保存し永続化したときのメモ

## 永続化はRecoil-persistライブラリを使う

もともとインストールしていたRecoilのバージョンがv0.6.1でしたが、recoil-persistをインストールするとエラーとなってしまったので、バージョンをv0.5.2でインストールし直したらいけました。

```powershell
npm install recoil@0.5.2 
```

```powershell
npm install recoil-persist
```

## RecoilRootでwrapする場所

Recoilを利用する場合はRecoilRootで全体をwrapします。
Next.jsの場合は`‗app.tsx`で囲えば大丈夫です。

![RecoilRoot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1614172/54d386ec-32d4-8921-222c-8c21be6fbe98.png)
## Atomを設定する

続いてAtomを用意します。今回認証済みかどうかはbooleanで判定します。

```tsx
import { atom } from "recoil";

export const isAuthenticatedState = atom({
	key: "isAuthenticatedState",
	default: false
});
```

## Sessionに保存

永続化する場合は下記のコードを追加します。通常`recoilPersist();`とすると値はlocalStrageに保存されます。
今回はSessionStrageに保存してみようと思います。その場合`recoilPersist();`の引数に下記のようなオブジェクトを渡します。

```tsx
import { atom } from "recoil";
import { recoilPersist } from "recoil-persist"; //追加

const { persistAtom } = recoilPersist({　//追加
	key: "recoil-persist",
	storage: sessionStorage
});

export const isAuthenticatedState = atom({
	key: "isAuthenticatedState",
	default: false,
	effects_UNSTABLE: [persistAtom]　//追加
});
```

## エラーになる

![サーバーサイドエラー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1614172/ff155d25-c3c2-b3ce-e91e-47709238578c.png)


Next .jsだとサーバー側でレンダリングを行うのでこのように怒られるようです。
サーバー側でstorageないですよって言われてしまいます。
調べたら参考になる記事がありました。

****[Next.js使用時にrecoil-persistのStorageを変更する](https://sunday-morning.app/posts/2021-11-10-change-recoil-persist-storage-with-nextjs)****

記事に習いコードを修正します。

```tsx
import { atom } from "recoil";
import { recoilPersist } from "recoil-persist";

const { persistAtom } = recoilPersist({
	key: "recoil-persist",
	storage: typeof window === "undefined" ? undefined : sessionStorage　//修正
});

export const isAuthenticatedState = atom({
	key: "isAuthenticatedState",
	default: false,
	effects_UNSTABLE: [persistAtom]
});
```

保存できてます。

![セッションstorage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1614172/dc2935b6-3e40-fcf4-ddf8-ebbc2be4009b.png)


## 感想

いくつか詰まりましたが、とはいえRecoilでの永続化すごく簡単ですね。
recoil-persistインストールできなかったときは焦りましたが。。。
【ポエム】Nextflowと再現性 - OSS的な観点から

個人の意見に基づくポエムです。あらかじめご了承ください。

## Nextflowとは？

AWS、GCP、Azureなどのクラウド環境を使って、大きめのデータを処理するためのワークフロー言語です。

データ処理では、シェルスクリプトを使った作業が行われます。しかし、シェルスクリプトは、標準入力と標準出力が一つしかありません。だから、データの処理の流れが分岐する場合は、データをファイルに一時保存しながら処理を行う必要があります。また、シェルスクリプトは複数のコンピュータ、クラスタで実行することを想定していません。言い換えるとクラウド環境で動的に計算資源を立てて実行するような実行方法は想定されていません。ワークフロー言語は、動的にクラウド環境の計算資源を確保し、仮想環境を利用して任意のOS環境を用いて、複数の複雑な分岐を持つ処理工程を単一のソースコードで記述することを可能にします。また、Makefileのように、途中まで行った処理を続きから実行することも可能にします。

## Nextflow言語で再現性は高まるのか？

「再現性のあるワークフロー言語」という言葉は少なくとも２つの意味があると思います。

* 世界中の異なるコンピュータで実行できるか？ - 仮に空間的な再現性とでも呼びましょうか。
* 同じワークフローが10年後も実行可能であり続けるか？ - 仮に経時的な再現性とでも呼びましょうか。

ワークフロー言語は前者をある程度解決します。しかし、ワークフロー言語で後者の問題が改善されるかはかなり疑問に思っています。

ワークフロー言語の特徴は、Docker、Singularityなどの仮想環境、AWSなどのクラウド環境を活用することです。ワークフロー言語はクラウドの差異を吸収します。クラウド環境はAWS、GCPなど複数あり、動的に計算資源を確保します。

Nextflowを利用すると、中間レイヤーが差異を吸収してくれるため、同じワークフローを異なるマシンを使って、世界のいろいろな場所で実行できるようになります。これは第三者がワークフローを利用する場合や、ワークフローの妥当性を検証する場合には非常に有効な手段となるでしょう。例えば、公開されているRNA-Seqのパイプラインを利用したい場合や、研究者がプレプリントで発表したワークフローを追試して動作を検証したい場合が、それに相当します。

では経時的な再現性はどうでしょうか。

個人的には、経時的な再現性は下がると考えています。理由は、ワークフロー言語は多くの中間層を持つことで、より複雑になっているからです。複雑なものは、より多くのメンテナンスコストが必要になります。しかし、メンテナンスコストが増えたとは感じないかも知れません。その理由は、ユーザーがメンテナンスコストを直接負担しなくてもいい構造になっているからだと思います。増加したメンテナンスコストは、ユーザーの見えないところで、多くのエンジニアが労力をかけて支払っています。

DockerはDocker社が中心となって開発を継続しているOSSの製品です。Nextflowはクラウド環境の差異を吸収してくれるOSSの言語です。seqeralabsという民間企業が中心となって開発を継続しています。互換レイヤーを維持し続けるためには組織的な取り組みが必要で、技術者を雇用し続ける必要があります。

例えば、世界で一番有名なソフトウェアであるMicrosoft Windowsも、デバイス間の差異を吸収してさまざまなコンピュータで同じプログラムが動作することを可能にすることで価値を生み出しています。現在ではLinuxもかなり普及していますが、仮にオープンソースソフトウェアであるとしても、質の高いソフトウェアを維持し続けるためには、何らかの営利組織の強力なバックアップは必須になると思います。（個人の感想です）

開発団体は通常ソフトウェアの持続的開発について不安を呼ぶようなメッセージは発信しません。しかし実際にはAdobeのFlashを例に出すまでもなく、互換レイヤーを提供していたソフトウェアが開発終了されることは珍しいことではありません。Amazon社など、各社の提供するクラウド環境が進化し続けるので、ワークフロー言語も最新の環境に対応し続けることが求められます。しかし、開発が中断されれば追従していくことは難しくなります。

そういったこともあり、ワークフロー言語の利用はクラウド環境の効率的な利用を可能にしますが、経時的な再現性の確保についてはあまり期待してはいけないと思いました。

もっとも、研究・科学向けのソフトウェアは、複雑性が高い割に実行回数が少ないという顕著な特徴があります。科学者は常に新しい試みを行うことが求められ、ツールを必要とする社会的文脈は急速に陳腐化します。そのため一部の重要なツールを除くと、時代を超えて利用されるということはほとんどないかも知れません。経時的な再現性に対する需要は高くなく、むしろ空間的な再現性こそが重要であるという主張には一定の説得力があります。

将来的にAWSのようなクラウド産業がコモディティ化して、たとえばAWS互換のクラウドを多くの発展途上国の事業者が提供するようなことになると、クラウド環境の規格の統一化がはじまり、オープンなワークフロー言語が誕生して普及していくかもしれません。

その場合でも、移り変わるクラウド環境に対応し続ける人的な開発リソースは必ず必要になると思います。

利用者としては、メンテナンスコストを企業やOSSに付け替えることで支払わなくて済むようになったことを喜ぶだけではなく、影で動いている開発体制やエンジニアの労力にも関心を払い、場合によっては負担のない範囲で貢献する手段がないか頭の片隅で考えるのが望ましいと思います。実際には難しいとしても。

この記事は以上です。
【Python】パーフェクトPython・イメージ(pypng) packageを使用できるまでの手順

## 背景
第18章のマルチメディアトピックにおいて、pypng packageの活用を紹介していますが、事前にインストールが必要な項目があるので、それを整理していく。
なお、Python3.5以上でないとpypngは利用できない。

## 環境情報
PC : Macbook Pro - Apple M1 - macOS Montery
環境 : pyenv 2.2.4
Python : 3.8.12

## 手順
以下の手順を踏んで必要なファイルを作成していく。

```
mkdir [フォルダ名]
cd [フォルダ名]
pip install pypng
# セットアップツールを作成するために、以下の2つのファイルを作成する。空ファイルでOK。ディレクトリは、同じところで問題ありません。

touch pyproject.toml
touch setup.cfg


# 以下のコマンドを実行して、build/UNKNOWN.egg-infoフォルダが作成される
pip install .

# png.pyファイルを作成して、pngをimportできるようにする。
curl -LO https://raw.github.com/drj11/pypng/main/code/png.py

```

以上のプロセスを踏むとpypng packageを利用できます。

## 参考資料
[pypng - PyPI](https://pypi.org/project/pypng/)
【Laravel】指定のページにDigest認証を実装

# はじめに
今回本番環境にて外部APIへ疎通確認しなければならない事象が生じたため、
あるページにのみダイジェスト認証を設けた。

# Digest認証用のパスワードファイルの作成
サーバーにて`htdigest`コマンドを用いてパスワードファイルを作成します。

```
$ sudo htdigest -c /var/www/html/.digestpass "Digest Auth" yamato

# コマンドの説明：sudo htdigest -c {ファイルパス} '{領域名}' {ユーザー名}

```

※ファイルの場所は任意の場所、領域名も任意

以下のコマンドでファイルが作成されたことを確認。


```
$ cat /var/www/html/.digestpass
yamato:Digest Auth:bce31c0fdafwerkjlwr8cdda656f24b23nifer
```

# アクセスを制御する.htaccessを編集
Laravelプロジェクトの場合は`/public`配下にある。
任意の場所に下記を追記。

```php:.htaccess

<IfModule mod_rewrite.c>

※中略

AuthType Digest
AuthName "Digest Auth"　#領域名
AuthUserFile "/var/www/html/.digestpass"
Require valid-user

</IfModule>
```

これでユーザー名とパスワードを求められるが全てのページに認証がかかってしまいます。
ここで本題の**指定のページ**に認証かけるなら**パス**で条件を加える方法です。

以下を追記します。

```php:.htaccess

<IfModule mod_rewrite.c>

※中略

# AllowかRequireいづれかでアクセス許可
Satisfy Any

AuthType Digest
AuthName "Digest Auth"
AuthUserFile "/var/www/html/.digestpass"
Require valid-user

# /connectでDigest認証を求める
SetEnvIf REQUEST_URI "^/connect" restricted_url
Order allow,deny
Allow from all
Deny from env=restricted_url

</IfModule>
```
これで`/connect`でアクセスしたときのみ認証を求められるようになり無事完了！

指定のページに認証を設けるのにbladeファイルのディレクトリに設定ファイル作成？
などさまざま遠回りしながらたどりつきました（＾ー＾；
ざっくり古典暗号の種類とアルゴリズム

## はじめに

暗号化技術のうちの古典暗号をまとめる。

## 古典暗号とは

古典暗号とは、コンピューターが登場する以前に用いられていた暗号です。
古典暗号の特徴としては、以下があげられます。

- 復号するための鍵の総数が少ない
- アルゴリズムが単純

この記事では、以下の古典暗号について書きます。

- シーザー暗号
- スキュタレー暗号
- 転置式暗号
- 単一換字式暗号

## シーザー暗号

#### アルゴリズム

以下のようにアルファベットを 3 文字ずらして暗号化します。

| 平文   | A   | B   | C   | D   | E   | F   | G   | H   | I   | J   | K   | L   | M   | N   | O   | P   | Q   | R   | S   | T   | U   | V   | W   | X   | Y   | Z   |
| :----- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- |
| 暗号文 | D   | E   | F   | G   | H   | I   | J   | K   | L   | M   | N   | O   | P   | Q   | R   | S   | T   | U   | V   | W   | X   | Y   | Z   | A   | B   | C   |

#### 例

`apple`を暗号化する際は、上記の表の対応から`DSSOH`になります。

## スキュタレー暗号

#### アルゴリズム

細長い紙を決まった太さの棒に巻きつけ、横に読んだときに平文になるというものです。
この場合の鍵にあたるのは「棒」で、同じ太さの棒を事前に共有しておくことで復号することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352836/5302bb63-46a3-f9ac-316c-e487ca11eefd.png)

（引用: https://ja.wikipedia.org/wiki/%E3%82%B9%E3%82%AD%E3%83%A5%E3%82%BF%E3%83%AC%E3%83%BC）

## 転置式暗号

#### アルゴリズム

平文を n 文字ずつのブロックに区切り、決められた規則で文字を置き換えるものです。

#### 例

`n=4`の場合で、以下の様に文字を置き換えるとします。

| 平文   |   1 |   2 |   3 |   4 |
| :----- | --: | --: | --: | --: |
| 暗号文 |   4 |   1 |   2 |   3 |

この場合、

- 1 文字目は 4 文字目に置き換える
- 2 文字目は 1 文字目に置き換える
- 3 文字目は 2 文字目に置き換える
- 4 文字目は 3 文字目に置き換える

`i love you`を暗号化する場合、（空白は今回取り除いて`iloveyou`）

`ilov`と`eyou`の 2 つのブロックに分けられます。
それぞれを暗号化すると、

`ilov` → `VILO`
`eyou` → `UEYO`

になり、最後にこれらをつなげて`VILOUEYO`にして暗号化が完了です。
復号化はこの逆をすれば良いです。

## 単一換字式暗号

#### アルゴリズム

1 つの文字を別の文字に 1 対 1 で対応させたものです。
例えば、以下のような表です。

| 平文   | A   | B   | C   | D   | E   | F   | G   | H   | I   | J   | K   | L   | M   | N   | O   | P   | Q   | R   | S   | T   | U   | V   | W   | X   | Y   | Z   |
| :----- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- | :-- |
| 暗号文 | D   | I   | C   | O   | X   | V   | U   | T   | P   | A   | Y   | Q   | L   | H   | B   | G   | S   | W   | R   | F   | Z   | M   | E   | N   | K   | I   |

#### 例

上記の表で、`apple`を暗号化する場合は`DGGQX`になります。

## 最後に

古典暗号は人間が暗号化・復号化をする必要があるので、比較的単純なアルゴリズムで出来ています。
今度は、現代暗号をある程度学び、普段身の回りで使われている暗号について考えれればと思います。
Python: シリアルコード的なランダム文字列を発行する

```python
    def make_serial_code(n: int = 16) -> str:
        # I と O は 0,1と混同するので外す
        randlst = [random.choice("ABCDEFGHJKLMNPQRSTUVWXYZ0123456789") for _ in range(n)]
        return "".join(randlst)

    print(make_serial_code())

# 4E0G4XZLMFFSEB44
```
ファイルの特定行を抜き出してソートした結果を取得

catでファイルを読み込んで、sedで行数指定して取得。その結果をsortする。

例、 ファイルの10行目〜20行目をソートする
``` shell
cat hoge.txt | sed -n '10,20p' | sort -f -d
```
sedの部分を変更すれば行数指定以外のやり方もできる。

### sortコマンドのパラメータについて補足
* `-f` 大文字/小文字を区別しない
* `-d` データが空白と英数位のみ含まれていると仮定して並び替える
  * どういうアルゴリズムか知らないが、これをつけないと""で囲った中身がアルファベット順にソートされない

### 余談
Pipfileの[packages]に指定したモジュールの並びがばらばらだったので並び替えたかった
virtualboxでvagrant up時にCommand: ["import"で進まない

virtualbox で vagrant up  つまづく事、結構あると思います（個人的に、、）

で、マシン(mac）を何回か載せ替える度に、設定してるんですが、今回さすがに　大ハマり
いろいろ試してもダメ、、、

で、じっくりエラーを眺めていたら、、、、

```
There was an error while executing `VBoxManage`, a CLI used by Vagrant
for controlling VirtualBox. The command and stderr is shown below.

Command: ["import", "/Users/ユーザ名/.vagrant.d/boxes/xxxxxxxxxxxxxx/0/virtualbox/box.ovf", "--vsys", "0", "--vmname", "xxxxxxxxxxxxxxx", "--vsys", "0", "--unit", "15", "--disk", "/Users/user/VirtualBox VMs/xxxxxxxxxxxbox-disk1.vmdk"]

Stderr: 0%...10%...20%...30%...40%...50%...60%. 
```

oh......
「--disk", "/Users/user/VirtualBox VMs」
おまえ、パス違うやんけ、、、、

たぶん、macの場合
VirtualBoxは仮想マシンの情報を保存する（？）ファイルパスがデフォで
```
/Users/user/VirtualBox VMs
```
となっている模様、、、
ので、
```
/Users/[ユーザ名]/VirtualBox VMs
```
に書き換えてめでたく、、、くそぅ、、、何時間溶かしたんだ、、、、
GoでAPIを作る際の技術選定

## 概要
GoでAPIを作ることになったので、ライブラリやアーキテクチャの検討をした際のメモ

## Web framework
:star: Gin

https://gin-gonic.com/

標準ライブラリの[net/http](https://pkg.go.dev/net/http)でもよかったけど、フレームワークを使って楽できるところはしたかった
その他にも[echo](https://github.com/labstack/echo)や[chi](https://github.com/go-chi/chi)など選択肢は豊富だが、2022/03時点でGinが最も人気が高そうで、触ってみて問題なさそうだったので

https://github.com/mingrammer/go-web-framework-stars

## API specification
:star: swag

https://github.com/swaggo/swag

コード内のコメントからSwaggerドキュメントが生成でき、Swagger UIも使えて便利
複数のフレームワークをサポートしてる
こんな感じでドキュメントを生成できる
```sh
$ swag init -g main.go
```

## Kubernetes client
:star: client-go

Kubernetesのリソースを操作する要件があったため（これ以外に選択肢ないはず）

https://github.com/kubernetes/client-go

## Logging
標準の[log](https://pkg.go.dev/log)を使用
必要があればzapを検討しようと思う

https://github.com/uber-go/zap

追記：標準パッケージに構造化ロガーが追加された

https://pkg.go.dev/log/slog

## DI
とりあえず手でfactoryを書こうと思う
しんどくなってきたらwireの導入を検討したい

https://github.com/google/wire

## Configuration
環境変数をstructに変換してくれるライブラリを使用

https://github.com/caarlos0/env

これも良さそう

https://github.com/kelseyhightower/envconfig

## Test
[gomock](https://github.com/golang/mock)の利用を検討したが、こちらの記事を参考に手作りすることにしてみた

https://moneyforward.com/engineers_blog/2021/03/08/go-test-mock/

## Build tool
`go build`して`docker build`しているが、koが気になってるところ

https://github.com/google/ko

## パッケージ構成
これが果たして本当にスタンダードなのか怪しいが、他に有力な選択肢もなさそうなのでこれに倣ってみる

https://github.com/golang-standards/project-layout

追記：公式でドキュメントが出た

https://go.dev/doc/modules/layout

## アーキテクチャ
保守性を考慮して何らかのアーキテクチャを採用したいが、オニオン・ヘキサゴナル・クリーンアーキテクチャと色々な選択肢がある中で、あまり複雑にはしたくなかったのでシンプルそうなレイヤードアーキテクチャにしてみる

https://qiita.com/tono-maron/items/345c433b86f74d314c8d


## 参考
https://github.com/avelino/awesome-go
【Microsoft Lists】[BUG：修正済] Lists のモバイルアプリで列の表示／非表示を切り替えるとフィルター条件が破損する

# 事象

> 2022/04/12 Ver. 1.62.2 で修正されていることを確認しました。

## 列の表示／非表示を切り替えると…

Lists の iPhone アプリでリストを開いて、[タイトル] 列を非表示に変更したところ、フィルター条件の [Today] が壊れました…。

###### 変更前
![Filter01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111975/fcdd8f22-54dd-9481-3f87-3225dda21979.png)

###### 変更後
![Filter02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111975/dcf94a79-8f1b-e21a-4f77-b71c7253f414.png)

MS サポートからの回答を以下に抜粋します。(2022/03)

> 誠に恐れ入りますが、本事象について回避策となる設定は確認が行えませんため、現状 Lists アプリ上で列の表示非表示の変更は行わないようご運用いただけますと幸いでございます。

## 事象発生のトリガーとなる操作

その他、事象が発生する条件です。

- 新しい列の追加
- 列の編集 (名称変更)
- 列の編集 (説明文の追加)
- 列の編集 (グループの編集を許可、複数選択を許可、列には情報を含める必要があります、一意の値を適用)
- 左に列を挿入
- 列を右に追加

※今後、修正されたなどの情報があれば更新します。

# 追記

2022/03/16

MS サポートからの返答を抜粋

> 本事象につきましては、今後予定されている Lists モバイル アプリのアップデートにより、3 月末頃または 4 月初旬頃に改善予定であることを確認しております。

2022/04/13

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111975/d5d963ac-0e89-e1fd-3dbc-af019b444994.png)

[朗報] 昨日、アップデートがありました。この現象について修正が入ったようです！
TypeScript初心者向けのリンク集

## はじめに

- TypeScriptを初めるにあたって参考になったサイトを紹介します。

## 対象読者

- TypeScript初心者
- チームメンバーの教育担当者

## TypeScriptについて知る

### 公式サイト

https://www.typescriptlang.org/ja/

- ほぼ英語ですが、導入方法から基本的な文法、リリース情報など全ての情報が網羅出来ます。
- [プレイグラウンド](https://www.typescriptlang.org/ja/play)も存在するため、そこで簡単なプログラムの動作確認が出来ます。

### TypeScript Deep Dive 日本語版

https://typescript-jp.gitbook.io/deep-dive/

- 主要な文法などがのっていてとても便利なサイトです。
- 日本語なので英語が苦手なメンバーにも紹介できます。

## 開発ツール

### npmパッケージ

https://www.npmjs.com/package/typescript

- TypeScriptのコードをJavaScriptにビルドするために必要です。

https://www.npmjs.com/package/ts-node

- JavaScriptにビルドせずに動作確認が出来るパッケージです。
- 開発環境などに入れると便利です。

### Visual Studio Code

https://code.visualstudio.com/docs/typescript/typescript-tutorial

- TypeScript開発ではかかせない開発ツールです。
- 各種拡張機能も充実しているので導入は必須だと思います。

## コーディングルール

### TypeScript Deep Dive 日本語版 - スタイルガイド

https://typescript-jp.gitbook.io/deep-dive/styleguide

- 基本部分を日本語で書かれているのでとても参考になります。

### TypeScript ESLint

https://typescript-eslint.io/

- ESLintのTypeScript向けのプラグインです。
- 開発ツールと連動出来るため、積極的に採用してCIなどでチェックできるようにしましょう。

### clean-code-typescript

https://github.com/labs42io/clean-code-typescript

- クラス、変数、テスト、コメント、エラーハンドリングなど幅広い分野について書かれています。
- 他のスタイルガイドでカバーできていないところをカバーするのに使用できます。

### Google TypeScript Style Guide

https://google.github.io/styleguide/tsguide.html

- Googleが出しているスタイルガイドです。
- 会社名だけでチームメンバーに納得感を出せます。

## プログラム初心者向け

https://qiita.com/KeithYokoma/items/ee21fec6a3ebb5d1e9a8

https://qiita.com/KeithYokoma/items/2193cf79ba76563e3db6

- メソッド名やクラス名などが自己流になっている人も多いので上記のステキな記事を読んで恥ずかしくない命名をしましょう。

https://qiita.com/alt_yamamoto/items/25eda376e6b947208996

- 他のプログラム言語でも使える内容が書かれています。
- チーム開発で継続的に修正をするプログラムを書く場合は是非参考にしてください。
S3で公開した静的サイトのCSSが反映されない

S3で静的サイトをホスティングしたが，
https://qiita.com/suama-akdo5317/items/2a7edfc8c1e230305640

CSSファイル修正しアップロードしたところ反映されない問題が発生
ブラウザのキャッシュクリアを行なっても反映されず。

### CloudFrontのキャッシュ削除が必要
CloudFrontは高速表示のためにキャッシュをしてくれます
これを削除してあげる必要がある
該当のディストリビューションにアクセス→キャッシュ削除→キャッシュ削除を作成→オブジェクトパスを追加


![スクリーンショット 2022-03-11 11.30.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869250/81bd34c0-33be-8d0d-2626-80d113e5bafa.png)

![スクリーンショット 2022-03-11 11.28.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869250/1989388b-f822-c0d0-52c0-2e3b28d25685.png)

![スクリーンショット 2022-03-11 11.29.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869250/a965ff1f-e327-ed3e-ec0a-d4783bd944fb.png)
全キャッシュを削除したいのでワイルドカード(*)をつける

処理が完了になればキャッシュがクリアされCSSの修正箇所が反映されている
　　
　　
公式ドキュメント有り
https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/Invalidation.html
【TypeORM】存在しないカラム/テーブルが作成される（開発環境）

# 環境

- [TypeORM 0.2.29](https://github.com/typeorm/typeorm)
- ローカル開発環境で `synchronize: true` としている。

# 事象

例えば、、、
- `entity A, B` を作成し、サーバーを起動して `table A, B` が自動で作成される （`synchronize: true` の期待動作）。
- その後 `entity B` のコードを削除し、データベースからも `table B` を削除する。
- その状態で、サーバーを起動したところ、存在するべきではない `table B` が作られる。

期待動作は、`entity B` が存在しないので、`table B` も作られないこと。

# 以下のいずれか或いは全てを実行すれば解消する

- `yarn prebuild` を実行して、`dist` ディレクトリを削除する。
- `docker rm -v <db-container-id>` を実行して、ボリューム毎 docker を削除する。
- 一度 `synchronize: false` としてサーバを起動する（この時点で、テーブルは全く作られていない）。サーバを停止後、`synchronize: true` に戻して立ち上げる。
PostgreSQL dualがないので代替策

# 課題: PostgreSQLにdualがない

Oracleを業務でよく使っている人は、
特定のテーブルを利用しないデータベースアクセスで`DUAL`表を使っています。

Oracleをセットアップしたときから存在する特別なテーブルで、
SELECTでDBの時刻取得など関数の結果を使いたい場合に用いられます。

```sql:Oracleの場合
-- 現在日
select SYSDATE from DUAL;
```

PostgreSQLではこの`DUAL`表がないのですが同様のことができます。

# PostgreSQLでの解決方法

`FROM`句を省略して書くことで対応できます。

### 固定文字取得

```sql
-- 固定文字
SELECT 'hello!';
```

### 現在日取得

```sql
-- 現在日
SELECT current_date;
```

### 現在日時取得

```sql
-- 現在日時
SELECT now();
-- 現在日時（日付書式指定）
SELECT TO_CHAR(now(), 'YYYY/MM/DD HH24:MI:SS');
```
初心者ブロックチェーンに挑戦する　11

# だれがだれに払うのか

## 少しアップグレード

　昨日、保存してません問題に翻弄されたこともあり、VisualStudioでfileを一枚一枚開くのをやめて、VisualStudioCodeで一元管理してみることにした。Androidstudioの使い勝手に少し近づく。自動更新はされないけど、｢保存してませんよ｣マークが赤くて大きめな数字になったので、さすがに目立つ。

　最初のファイルがおなじみ@@.sol。これまで、このファイルだけいつも文字が色分けされてなくて、え、大丈夫、このファイル生きてる？って不安だったけど、今朝は開けると一番に

- solidity のサポートパッケージを入れますか？

と聞かれて、はいはいはいって、答えたら、一瞬でテキストと同じように色分けされた表示に変わった。おめでとう。

　でも、これを入れたセイかどうか、一行目のimportに赤波線の警告が出る。でも走る。とりあえず放置。こんどはterminalが

- npmが少しアップグレードしてるけど入れる？

これは今日の作業が終わってからにしよう、下手に沼りたくないし。

　ちびちびと綴り間違いがあるのを、ちびちびと直し、少しずつエラーを減らし、無事走った〜と思ったのだが、コンソールに表示されるべき数列が出ない。

- console.log("WavePortal address:", waveContract.address);

と書くべきところ、

- console.log("WavePortal address:, waveContract.address");

と書いてました(ﾟﾟ)(｡｡)ﾍﾟｺｯ、これはDiscordで通りがかりさんに教えてもらいました。

　ということで、第三章終了〜。
　そうだ、nmpアップデートする？　やってみたら、半分来たけど、いくつか足りません、みたいに言われた。詳細はこちら、を見たら、わかるわけないっしょというぐらいいろいろ書いてあったので、見なかったことにして、もうしばらく放置する。なさけな(>_<)

## 新しい関係の感覚

　今日は何をやったかというと、私のサイトで私に手を振ってくれた人に、おもちゃのイーサをプレゼントする。

　これまではブロックチェーン使わせてもらいます料金をマイナーさんに払う、という、いったら常識的な｢使用料｣だけど、今日のは毛色が違うよね。挨拶してくれた人にお金を払うってなんなんだって、多分、特に私より上の世代はむっとするんじゃなかろうか。失礼だろう、それ、みたいな。または、お金が欲しいから挨拶するのか、誠意のないヤツ、とかね。

　以前、というか、昔、高校生が内申書の評価を上げるためにボランティア活動をするのは是か非か、とかいう論争があった。ボランティアはもっと無欲な活動であるべきだ、みたいな。一方、内申書でつろうと、お小遣いでつろうと、ボランティア活動する人が増えるなら、それでいいじゃん、という意見も当然あった。

　いずれにせよ、Web3の自律分散型コミュニティでは、親切にも、挨拶にも、トークンで応えるよ、という文化が定着していくんだろう。どっちが動機で、どっちが結果であっても、そんなこと気にしなくていいんだろうね。

## 小学校の｢元気に挨拶運動｣とかも、トークンつける時代が来るのかな笑
【MySQLエラー】Specified key was too long; max key length is 3072 bytes

# 環境

MySQL: 5.7

# エラー内容

```
Specified key was too long; max key length is 3072　bytes
```

# 原因

４つの `varchar(255)` カラムで複合ユニークインデックスを張ろうとしたため発生。

# 回避方法

4つの内、2つのカラムが `char(36)` で良かったため、そのように変更して回避。
dockerビルド時にGPGエラーが出た

# 背景
dockerを使用したLAMP構成のWebアプリケーション開発環境構築時、
```
docker compose build
```

コマンドにてエラーが発生し、ビルドが成功しなかった
これは私の端末でのみ再現し、他のメンバーの端末では正常にビルドできていた。


## 対象のDockerfile略
```docker
FROM mysql:5.7

RUN apt-get update && apt-get install -y
```

## 発生したエラー略
```
failed to solve: rpc error: code = Unknown desc = executor failed running [/bin/sh -c apt-get update && apt-get install -y]: exit code: 100
```

```
#9 4.515 W: GPG error: http://repo.mysql.com/apt/debian buster InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY <パブリックキー>
```

# 解決方法
下記のコマンドを実行
```
$ docker pull mysql:5.7
$ docker compose build --no-cache
```

# 原因
GPG keyが古くなっているというニュアンスのエラー。

dockerでやっていなければ新しいものに交換すればいいが、
dockerfileに書く内容のものではない。

そのため、元イメージ `mysql:5.7`を、新しいGPG keyを持っているであろうイメージに更新 `pull`する。

その上で、キャッシュを使用せずに `--no-cache` ビルドを実行する。

# 参考
[docker内でGPG errorが出た際の対処](https://nice-mikan.hatenablog.jp/entry/2020/07/30/013517)
Pythonのコマンドラインパーサーclickでサブコマンドのサブコマンドを作る

Pythonのコマンドラインパーサーclickを使って、サブコマンドのサブコマンドを実装したかったので、雛形を掲載します。

コード
```python
import click


@click.group()  # (1)
@click.pass_context
def aws(ctx):
    pass


# サブコマンド

@aws.group()
@click.pass_context
def ec2(ctx):
    pass


@aws.group()
@click.pass_context
def s3(ctx):
    pass


# ec2サブコマンドのサブコマンド

@ec2.command()
@click.pass_context
def describe_instances(ctx):
    pass


@ec2.command()
def run_instances(ctx):
    pass


# s3サブコマンドのサブコマンド

@s3.command()
@click.pass_context
def cp(ctx):
    pass


@s3.command()
@click.pass_context
def ls(ctx):
    pass


if __name__ == '__main__':
    aws()

```

実行例

```
 $ python aws.py 
Usage: aws.py [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  ec2
  s3

```

```
 $ python aws.py ec2
Usage: aws.py ec2 [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  describe-instances
  run-instances

```

```
$ python aws.py s3
Usage: aws.py s3 [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  cp
  ls

```
ブラウザにwebページが表示されるまで

ブラウザのアドレスバーにURLを入力してから、Webページが表示されるまでの流れ。
キャッシュなしの場合でざっくり纏めてみた。

## Webページが表示されるまでの流れ（ざっくり）
1. WebブラウザのアドレスバーにURLを入力
2. クライアントはアドレスバーに入力されたURLから「ドメイン」部分を抜き出しDNSサーバーに送り、IPアドレスを要求する
3. DNSサーバーは、受け取ったドメインからWebサーバーのIPアドレスを特定する（名前解決）
4. DNSサーバーからクライアントにIPアドレスが返信される
5. クライアントは取得したIPアドレスのWebサーバーに、URLのパスの部分（/path/path/）のWebページデータをHTTPで要求する
6. WebサーバーはクライアントにWebページのHTMLデータを最初に送信する
7. Webブラウザは、HTMLを解析し、JS、CSS、画像などのそのページで参照されている全てのリソースに対してデータを複数回に分けてリクエストする
8. WebブラウザはHTML / CSS / JSを読み込むと構文を解釈しレンダリング処理を行う


## 用語集
### DNS
ドメインネームシステム（Domain Name System）の略で、ドメイン名（人が使う言葉で書かれた住所）とIPアドレスをリンクさせる仕組み。
「名前解決」ともいう。

### DNSサーバー
ドメイン名とIPアドレスを対応づけるデータベースを管理しているサーバー

### HTTPメッセージ
クライアントとサーバーがデータを交換する手段。
クライアントがサーバーに送信してアクションを起こさせる「HTTP リクエスト」とサーバーの回答である「HTTPレスポンス」の2種類がある。

### HTTPプロトコル
HTTPは、HTML文書などのリソースを取り出すことを可能にするプロトコル。

### レンダリング処理（ブラウザ側）
ブラウザはHTML、JS、CSSを読み込むと構文を解釈し「レンダリング処理」を行う。
レンダリング処理の順番は以下。
1. HTML マークアップを処理して DOM ツリーを構築する。
2. CSS マークアップを処理して CSSOM ツリーを構築する。
3. DOM と CSSOM を組み合わせてレンダリング ツリーを構成する。
4. レンダリングツリーでレイアウトを実行して各ノードの形状を計算する。
5. 各ノードをブラウザにペイントする。

* DOM (Document Object Model) -> HTML マークアップ
* CSSOM (CSS Object Model) -> CSS マークアップ
* レンダリングツリー　-> DOM ツリーと CSSOM ツリーを組み合わせたのがレンダリングツリーの正体

## 参照サイト
- [HTTP - MDN](https://developer.mozilla.org/ja/docs/Web/HTTP)
- [Webサイト表示の流れをざっくりとまとめた。HTML,CSSからSPA,SSR,SSGまで。](https://tadtadya.com/summary-of-the-web-site-display-process-flow/)
- [ウェブサイトが表示されるまでにブラウザはどういった仕事を行っているのか？](https://gigazine.net/news/20190624-how-web-works/)
- [Webページ表示の仕組みと表示までの流れ](https://daeuwordpress.com/homepage-system/)
- [オブジェクト モデルの構築](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/constructing-the-object-model?hl=ja)
- [レンダリング ツリーの構築、レイアウト、ペイント](https://developers.google.com/web/fundamentals/performance/critical-rendering-path/render-tree-construction?hl=ja)
【Python】パーフェクトPythonの12章・asyncio項目でエラーが警告への対処法

パーフェクトPythonの12章・asyncioの項目でエラーが警告が発生

### 基本情報
環境 : Python3.10 
PC : MacBook Pro
Editor : Visual Studio Code

### 警告内容
```
DeprecationWarning: There is no current event loop
  loop = asyncio.get_event_loop()
```

Python3.10では、get_event_loop()を呼ぶと警告を発生する模様。
get_event_loop()ではなく、get_running_loopが推奨されている。


【参照】
- https://github.com/pytest-dev/pytest-asyncio/issues/212
- https://docs.python.org/3.10/library/asyncio-eventloop.html#asyncio.get_event_loop

パーフェクトPythonは、Python Version3.8ベースで書かれているので、少しばかり相違点があり、意外なエラーが出るので、注意が必要ですね。
【ダッシュボードページ】サンプルダッシュボードページ

[Sharperlight](https://sharperlight.jp/)ダッシュボードページでこのようなページを作成し公開することができます。
![2022-03-xx Figure 01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/e348795e-9bb2-9bbf-f446-968d2eb0c7ae.png)
![2022-03-10 15_04_10-Window.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/61a22f49-c726-1be6-619f-4fd232f30962.png)

:postbox:[Sharperlight](https://sharperlight.jp/)