OmniAICreator/Qiita-1.07M huggingface dataset:
QTableWidget::currentItemChanged をキャンセルし セレクションを戻す

# はじめに

Qt6.2 の QTableWidget::currentItemChanged　に接続した Functor でキャンセルさせ セレクションを戻す方法に迷走
力技的なところはありますが共有

# 確認環境

- Windows 10 x64
- Qt 6.2

# 概要

QTableWidget::currentItemChanged と接続した Functor 内で previous を選択してもダメなようなので Functor から抜けた処理で選択すれば良いとのではと考察
その結果 QTimer::singleShot と接続した Functor 内で選択処理すれば実現できることを確認
⇒タイマーイベントで選択処理をキューイング

# サンプルコード

``` c++
#include <QtWidgets>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QWidget w;
    QTableWidget *tbl = new QTableWidget(&w);
    QGridLayout *l = new QGridLayout;

    w.setLayout(l);
    l->addWidget(tbl, 0, 0);
    QObject::connect(&app, &QApplication::lastWindowClosed, &app, &QApplication::quit);
	tbl->setColumnCount(1);
	tbl->setHorizontalHeaderLabels({("Name")});
	tbl->setSelectionBehavior(tbl->SelectRows);
	tbl->setSelectionMode(tbl->SingleSelection);
	tbl->setEditTriggers(tbl->NoEditTriggers);
    for (int row = 0; row < 5; ++row) {
        tbl->setRowCount(row + 1);
        tbl->setItem(row, 0, new QTableWidgetItem(QString::number(row)));
    }
    QObject::connect(tbl, &QTableWidget::currentItemChanged, [&](QTableWidgetItem *current, QTableWidgetItem *previous) {
		if (! previous) {
            return;
        }
        if (QMessageBox::Yes != QMessageBox::question(&w, "Confirm", "Do you want to switch?")) {
            /*
             * QTableWidget::currentItemChanged の後に選択処理を入れてあげればよさげ
             */
            QTimer::singleShot(1, [previous]() {
                QTableWidget *tbl = previous->tableWidget();
                QSignalBlocker sb(tbl); // これを忘れるとループ

                tbl->setCurrentItem(previous);
            });
            return;
        }
        // TODO: current に対して必要な処理
        current;
	});
    w.show();
    return app.exec();
}
```
Djangoプロジェクト, アプリの作成手順

【事前準備】
1.こちら(https://qiita.com/Kota0925/items/e60c1327d71d226c20b6 )を事前に行ってください。

【Djangoのインストール】(初回のみ)
1.コマンドプロンプトで仮想環境を立ち上げる
2.「pip install django」を実行
3.「pip freeze」を実行し、インストールされていることを確認


【プロジェクトの作成】
1.コマンドプロンプトで仮想環境を立ち上げる
2.「django-admin startproject ○○」を実行
3.指定したディレクトリに「○○」フォルダが作成されていることを確認


【アプリケーションの作成】
1.コマンドプロンプトで仮想環境を立ち上げる
2.アプリケーションを作成したいプロジェクトのディレクトリに移動
3.「django-admin startapp ××」を実行
4.指定したディレクトリに「××」フォルダが作成されていることを確認



【サーバーの起動】
1.コマンドプロンプトで起動したいプロジェクトのディレクトリに移動
2.「manage.py runserver」を実行
3.指定されたURL「http://127.0.0.1:8000/ 」 にアクセスし、トップページが表示されることを確認
AWS Fargateのタスク起動時間がzstd圧縮のイメージを使うと早くなるようなので試してみた


# はじめに
GoQSystemではアプリケーションやAPIサーバーの基盤にAWS ECS on Fargateを採用しています。
ECS Task起動時間短縮はインフラ担当として取り組んでいることの一つです。（イメージサイズを下げるの限界。。。）
2022/10/13 AWSブログでzstd圧縮イメージを使用すると起動時間が短縮されると発表したので試してみました。

https://aws.amazon.com/jp/blogs/containers/reducing-aws-fargate-startup-times-with-zstd-compressed-container-images/

# zstdとは
Zstandardの略でMetaに所属しているYann Colletによって開発された可逆圧縮アルゴリズムです。

# Docker builxコマンド
AWSブログにあるコマンドオプションを指定してイメージをビルドしています。
```
docker buildx build \
  --file Dockerfile \
  --output type=image,name=$IMAGE_URI:$IMAGE_TAG,oci-mediatypes=true,compression=zstd,compression-level=3,force-compression=true,push=true .
```

# 計測について
ECS Taskの`Started at`と`Created at`の「差分 = 起動時間」とします。
通常のDocker buildのイメージとbuildxでzstd圧縮したイメージそれぞれを使用したECS Taskを30個立ち上げて確認しています。（10タスク×3回）
ECS Taskの内容はどちらも同じものです。

**aws cli：ECS Taskの`Started at`と`Created at`を確認**
```
aws ecs describe-tasks --tasks $TASK_ARN --cluster $CLUSTER_NAME
```

※ コンソール画面でも確認できます

### タスク構成
php-fpm + Nginxの2コンテナでベースイメージはAlpineです。
本番環境で使用している設定と構成を使用しました。
プラットフォームバージョンは1.4.0、OSはLinux、CPUアーキテクチャーはamd64(x86)を使用しています。

# Docker build イメージを使用したECS Task
■ **イメージサイズ** 
* Nginx： 25.53MB
* PHP： 165.31MB

■ **ECS Taskサイズ** 
* CPU： 4
* Memory： 8GB

■ **ECS Task起動時間** 
* 平均： 24.6(秒)
* 最小： 22.0(秒)
* 最大： 36.0(秒)
* 中央値： 24.5(秒)

# Docker buildxでzstd圧縮したイメージを使用したECS Task
■ **イメージサイズ** 
* Nginx： 24.42MB
* PHP： 158.43MB

■ **ECS Taskサイズ** 
* CPU： 4
* Memory： 8GB

■ **ECS Task起動時間** 
* 平均： 23.0(秒)
* 最小： 21.0(秒)
* 最大： 27.0(秒)
* 中央値： 23.0(秒)

# まとめ
ざっくりな検証ですが通常のDocker Buildのイメージを使用したECS Taskよりもzstd圧縮したイメージを使用したECS Taskの起動時間の方が早い結果になりました。
バラツキなど他のことも考慮すると本来もっともっとN数やパターンを増やしてみなければいけませんが、時間の関係上いずれまたということで。

**AWSブログ内にもあるように機械学習やAI、データ分析系ラージサイズイメージに効果的ということなので、元々イメージサイズが大きくない弊社のようなケースでは劇的な改善が見られることはなさそうです。**
> In our internal testing of zstd compressed container images on AWS Fargate, we have seen up to a 27% reduction in Amazon ECS Task or Kubernetes Pod startup times. The reduction in startup time varies by container image, with the larger container images seeing the greatest improvement. Uses cases like machine learning, artificial intelligence, and data analytics traditionally have large container images. Consequently, these workloads could see the most benefit from adopting zstd compression.

今回は普段使っているCircleCIではなくGitHub Actionsを使用してDocker Imageをbuildし、ECRへpushしました。その中でDocker buildとbuildxの設定方法であったり色々と学べることがありました。この辺りもいずれ公開できればと思います。

## 最後に
#### **GoQSystemでは一緒に働いてくれる仲間を募集中です！**
ご興味がある方は以下リンクよりご確認ください。

https://goqsystem.recruit.site?qiita=65173b164498de4641f8
【Salesforce】この 取引先責任者 には重複が存在しているようです。を非表示にする

# 問題

重複ルールの条件に引っ掛かった取引先責任者レコードを表示すると件名のメッセージが表示される。
画面を移動しても「✕」を押下しないと消えない。

# 解決策

▼設定手順
(1) トーストメッセージが表示されているレコード詳細画面を表示
(2) 右上の [歯車アイコン] > [編集ページ] をクリック
(3) 配置されている [潜在的な重複] コンポーネントをクリック
(4) 右側に表示された [表示オプション] にて [カードを表示] に変更
(5) 右上の [有効化] > [保存] を順にクリック
※有効化時に[組織のデフォルトとして割り当て]ボタンが表示されている場合はクリック

# 参考
従来の重複ルールのトーストメッセージはユーザがアクションを実施するには短い時間であったことから、Summer'22のリリースに伴い、[×] にてトーストメッセージを削除するまで表示され続ける動作へと変更された。
unityアニメーションョンswitch

```C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class Animation : MonoBehaviour
{
    private Animator anim;
    bool play = false;
    public InputAction playerControls;
    private float leftClick;

    private float doubleClickTimeLimit = 0.25f;

    private void OnEnable()
    {
        playerControls.Enable();
    }

    private void OnDisable()
    {
        playerControls.Disable();
    }

    void Start()
    {
        anim = GetComponent<Animator>();
        StartCoroutine(InputListener());
    }

    void Update()
    {
        leftClick = playerControls.ReadValue<float>();
        // if (Input.GetMouseButtonDown(0) || Input.GetKeyUp(KeyCode.P) || Input.GetKeyUp(KeyCode.Space) || leftClick==1)
        if (Input.GetKeyUp(KeyCode.P) || Input.GetKeyUp(KeyCode.Space))
        {
            play = !play;
        }

        if (play) 
            anim.SetBool("isPlay", true);
        else
            anim.SetBool("isPlay", false);
    }

    // Update is called once per frame
    private IEnumerator InputListener() 
    {
        while(enabled)
        { //Run as long as this is activ

            if(Input.GetMouseButtonDown(0))
                yield return ClickEvent();

            yield return null;
        }
    }

    private IEnumerator ClickEvent()
    {
        //pause a frame so you don't pick up the same mouse down event.
        yield return new WaitForEndOfFrame();

        float count = 0f;
        while(count < doubleClickTimeLimit)
        {
            if(Input.GetMouseButtonDown(0))
            {
                DoubleClick();
                yield break;
            }
            count += Time.deltaTime;// increment counter by change in time between frames
            yield return null; // wait for the next frame
        }
        SingleClick();
    }


    private void SingleClick()
    {
        play = !play;
    }

    private void DoubleClick()
    {
        play = !play;
    }
}
```
「基本設計書」を作成してみる

この記事は、「[架空プロジェクトを通してシステム開発とドキュメント作成を体験してみる（2022 Late）](https://qiita.com/minimumskills/items/aedf6a93658db3f74747)」の記事の一部です。

## 基本設計書の概要

一般にはシステムの全体像、外部設計（画面系）、内部設計（I/F、バッチ等）を記述するようですが、私はシステム全体に関連する基本的・共通の技術要素を記述するようにしています。

>これは私がアジャイル的な開発をすることが多く、詳細設計については実装が先行しドキュメントは不要か後作成となるため、実装の前に決めておくべき最低限の情報 = 基本設計書として記述しておくことが習慣になっているためです。

|項目|内容|
|-|-|
|作成目的|システムの基本・共通となる技術情報を記載（独自）|
|記述すべき内容|名称定義、方式、（Webの）構成等|
|作成タイミング|基本設計|
|対象者|技術者|
|ファイル形式|パワーポイント、Excel、Word|
|備考|一般的な基本設計書と内容が異なります|

>一般的にはどうなのか？が気になる人は後半にある「一般的には（参考）」に先に目を通してもらったほうがいいかもしれません。

### サンプルダウンロード

サンプルのダウンロードは[こちら](https://docs.google.com/uc?export=download&id=19nLaWU--yL8SuSC0a37-zETzCY7tRIFp)から。

:::note warn
サンプルの基本設計書は一般的な基本設計書と記述内容（スコープ）が異なります。
:::


## 作成してみる

では作成していきましょう。

### 作成方針・ポイント

概要でも書きましたが、私の基本設計書は一般と少し違います。アジャイル開発でも決めておかないといけない要素を基本設計書に記述し、実装で補う範囲については、ドキュメントを作成しないか、後から詳細設計書を起こすようにしています。

### 構成（目次）を考える

アジャイル開発をする場合でも、決めておいたほうが良い要素として、サンプルでは下記のような項目を記述してみることにしました。

* システムの構成要素と名称
* 方式設計
* Webサイト構成

>一般的な基本設計の構成例が知りたい方は、下段にある実践ガイドの基本設計の構成例を見てみてください。

### 記述例（サンプルから抜粋）

では、サンプルの主要なページについて少し解説したいと思います。

#### 表紙

特に補足することはありません。

![000001.jpg](https://drive.google.com/uc?export=view&id=1s1H5eh1GHj7Nn2O7zjD9bqFPxC9JSFz3)

#### 目次

こんな感じ。

![000010.jpg](https://drive.google.com/uc?export=view&id=13xgHzaFGfZrhLrOb5J26JDKHONs1Fei7)

#### 基本設計の位置付け

通常の基本設計書とは内容が違うので位置付けを記述。

![000020.jpg](https://drive.google.com/uc?export=view&id=1fWnBPn9ummPdImRkbd3ofKkyO44nr633)

#### システムの構成要素と名称

設計するには設計対象に名称をつけないと何かと不自由なので名称定義を最初に行っています。

![000030.jpg](https://drive.google.com/uc?export=view&id=1biufRSrH_4wI7HQYgk4H6qidT94yZ9pL)

#### 方式設計

各機能をどういう技術で開発するのかについて定義しています。

![000040.jpg](https://drive.google.com/uc?export=view&id=1K-0lqggmp_PJERQLs71Q9plQ4U6BBOSm)


#### Webサイト構成

今回はWebベースのシステムなのでWebサイトとしての構成を定義しています。

![000050.jpg](https://drive.google.com/uc?export=view&id=1naGnwOg5V2xWJV5VHWNisw9NAiC51mPe)

基本設計書のサンプルではこの3枚だけです。

>この程度の内容であれば、基本設計と詳細設計を無理してわけず、設計書の「基本部分」として記述するのもありだと思います。

## 一般的には（参考）

### 実践ガイドブックでは？

実践ガイドブックでは残念ながら「基本設計書」としてのテンプレートは提供されていないようですが、ガイドライン中（第3編7章 設計・開発 P18）に基本設計書の構成例として下記の記述があります。

結構がっつり系の内容になってます。

>実は実践ガイドブックには詳細設計に関する具体的な記述やテンプレートが無いため基本設計と詳細設計をどう切り分けるのかという明確な指針はありません・・・。

<img width="700" alt="000060.jpg" src="https://drive.google.com/uc?export=view&id=120ArTyL6m8zRTkZqHPXRakDqGBcObk05">

設計工程をどう分けるかは会社によりことなる例も示されています。

* 基本設計＋詳細設計派
* 外部設計＋内部設計派
* その他派

に大きく分かれるのかな？

<img width="700" alt="000070.jpg" src="https://drive.google.com/uc?export=view&id=124S1sF10RCXoavr70GlJ3EBlTmF_fFvI">

## 参考

* [デジタル庁 デジタル社会推進標準ガイドライン](https://www.digital.go.jp/resources/standard_guidelines/)
* [DS-120 デジタル・ガバメント推進標準ガイドライン実践ガイドブック　各種テンプレート](https://www.digital.go.jp/assets/contents/node/basic_page/field_ref_resources/e2a06143-ed29-4f1d-9c31-0f06fca67afc/ec6f6641/20220422_resources_standard_guidelines_guideline_09.zip)
初心者 flutter_unity_widget 2022.2.0のpub.devを読む １

# 初心者を名乗るものは、いつまでも初心者である。　
　先日、トヨタのFlutter研修のビデオを見ていたら、講師が冒頭でそんなようなことを言っていた。きっとそれは正しい。なので、いったんは、私もそろそろ初心者を冠するのは卒業しようかと思ったのだが、結局、また書いている。


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


## 初心者記事を書く理由
　だれでも、どんな分野でも、人はまず初心者から始まって、だんだんに成長していく。ほんの数ヶ月で卒業する人もいれば、ちょっと滞って乗り越えていく人もいる。けれどその後に、いつもまた新しい「初心者」が現れる。　
　私がプログラミング初心者として一番困るのは、たいがいの技術記事が、初心者向けではないことだ。「あたりまえなこと」が省かれている。限られた紙面で要領よく知見を伝達するのに、それは必要なことだろう。この「あたりまえのこと」が省かれている記事をちゃんと読めるようになれば、初級卒業なのかもしれない。だけれど実際問題として、たぶん多くの初心者が、「省かれたあたりまえ」に躓いて、時間が溶ける。　
　なので私は、省かないで書く、を心がけている。あるいは、省かれていて困ったこと、を書く。そういう記事は、中級、上級者には冗長でムダが多いだろう。だから私はタイトルに初心者と付記し、タグ付けもすることで、はっきりとこれを初級者に届けたいと思っているし、中・上級者にも無駄足を踏ませないようにしているつもりだ。

## なぜ　flutter x unityか　
　私がこれまで書いてきた初心者記事はFlutter × ブロックチェーン（停滞中）やFlutter × MySQL8（いったん終了）のように、そもそもあまり記事のない領域だし、それって初心者がやることか、まずはどれか一つしっかりやれよ、と言われたら返す言葉もないのだけれど、これは性分なので仕方がない。今回も、FlutterFlameもあるのに、なんでUnityなんだと言われればそれまでだけど、それをやってみたいと思い、せっかくこういうwidgetがあるのだから、「いつかもっとよくわかるようになったら」などと言っていないで、今、挑戦すればいいんじゃないかと思っている。

# flutter_unity_widget 2022.2.0とは何か　
　公式ページを読んでいこう。

https://pub.dev/packages/flutter_unity_widget

***
FlutterでUnityを埋め込むためのFlutter unity 3Dウィジェットです。Unityで作ったアプリをFlutterでレンダリングして、フルスクリーンとエンベッダブルモードで楽しむことができます。Android、iPad OS、iOS、Webで動作し、Windowsは完成間近です。現在、unityフォルダには、デフォルトのシーンを使用したものと、Unity ARファンデーションサンプルをベースにした2つのUnityアプリの例があります。
注意：Unity 2019.4.3以降のみサポートします。UnityFrameworkはエミュレータをサポートしていません。注意：Graphics APIは当面OpenGLES3のみをご使用ください（Androidのみ）。  公式ドキュメントのDeepLによる翻訳
***

　この解説がするっと読める人は、この記事を読む必要がないだとろうと思う。ほとんどわからない、でも、とりあえず問題はない。

### Notice
***
レックス・アイザック・ラファエル（Rex Isaac Raphael）のタグを付けてください。使用しているUnityのバージョンに合ったFUW unitypackageを常に使用してください。

このプラグインは、少なくともUnity Engineの使い方を知っていることを前提にしています。もし、unity widgetの表示方法に問題がある場合は、unityプロジェクトのビルド設定を適当に変更してください。

今後、パッケージのバージョンは、適切なテストの後、unityのリリースに合わせて変更される予定です。これはパッケージが他のバージョンと互換性がないことを意味するものではありません、それはただ、unityバージョンで動作するようにテストされたことを意味します。

Windowsはもうすぐです。

^2022.1.0+5 は Flutter 3.0.0 をサポートし、今のところ PlatformViewSurface のみで動作します。この意味は、UnityWidgetにuseAndroidViewSurface: trueを渡す必要があることです。この問題を追跡することができます。現在、AndroidViewのサポートに取り組んでいます。（同）
***

　DeepLの「変な」部分もあえて直していない。気になる方は英語原文に当たってください。
　ここで大事なのは第２パラグラフ「少なくともUnity Engineの使い方を知っていることを前提にしています」だろう。ちなみに私は、Unityで球やキューブを装飾して動かしたり、三次元空間内を一人称視点で歩き回ったりすることができるが、ゲームを完成させたことはまだない。そして「問題がある場合は、unityプロジェクトのビルド設定を適当に変更」する能力があるか、といったらあまり自信はない。
　このあとの具体的設定で、Flutter3とそれ以前についての言及がある。ネット上の記事や動画は、作成時期によって、Flutter3ではないもの、また、Unityが古いものもある。参照するときは気をつけて読んでください。

### Installation
 pubspec.yamlへの追記が　Flutter3とそれ以前が分けて書かれている。fileへのimportも、他のパッケージと同様だ。

### Preview
 初心者にはわかりづらいところだが、この動画は何を表しているのか。一つは、Unityでつくったキューブの回転するシーン。もう一つは、Flutterでつくったスピード調整バー（名前がわからない）。つまりFlutterの指定した速度で、Unityの挙動を制御している。単なる「Unityのアニメーションを見られるFlutterアプリ」なわけではない。　

# 具体的なセットアップ方法は次回以降で

https://qiita.com/dongri727/items/e484564439b1da62566e
「課題管理表」を作成してみる

この記事は、「[架空プロジェクトを通してシステム開発とドキュメント作成を体験してみる（2022 Late）](https://qiita.com/minimumskills/items/aedf6a93658db3f74747)」の記事の一部です。

## 課題管理表の概要

プロジェクト開始から終了（場合にっては終了後）までの間に発生した課題を管理するためのドキュメントです。なお、課題以外にも「確認事項」や「軽微なタスク」などを管理する場合もあります。

|項目|内容|
|-|-|
|作成目的|プロジェクトにおける課題と対応状況の管理|
|記述すべき内容|課題、対応状況、担当者、重要度等|
|作成タイミング|プロジェクト開始時〜完了時|
|対象者|プロジェクトメンバー（非技術者・技術者）|
|ファイル形式|Excelで作成されることが多い|
|備考|会社によっては既存のテンプレートがあったりツールを利用したりするので確認してみる|

>一般的にはどうなのか？が気になる人は後半にある「一般的には（参考）」に先に目を通してもらったほうがいいかもしれません。

### サンプルダウンロード

サンプルのダウンロードは[こちら](https://docs.google.com/uc?export=download&id=1QVKIMBd8NYlWWnFizbWQ1FvWyd-aJJAt)から。

## 作成してみる

### 作成方針・ポイント

特に方針やポイントはありません。課題管理表は会社に標準テンプレートがある場合もあるので、もしある場合はそれを踏襲する方が無難です。なお、課題管理表はテンプレートを作るだけでは意味がなく、課題の状況の更新が必要なので、いつ更新するのか？を明確にしておく必要があります。

>多くの場合、定例会議のアジェンダの一つとして「課題管理表の確認」を設定し、更新（メンテナンス）します。

### 構成（管理項目）を考える

課題管理表で管理すべき項目（カラム）は、

* 課題
* 分類
* 管理番号
* 対応・回答
* 起票者
* 起票日
* 対応者
* ステータス
* 重要度
* 対応期限
* 解決日（クローズ日）

といったところが一般的です。
分類をどう設定するか、終了となった課題をどう取り扱うか等も決めておくといいでしょう。

>分類は、「課題」、「バグ」、「確認」、「その他」という感じでしょうか。終了課題は削除せず、グレーアウトが一般的なのでしょうか。

### 各内容を記述する（サンプルの說明）

では、サンプルの内容について少し解説したいと思います。

#### 課題管理表

特に解説する点はなく、記載すべき項目を記述している感じです。

![000001.jpg](https://drive.google.com/uc?export=view&id=1Whz7KdlQtq12KdxBtvRgLX83cfMV1hWV)



## 一般的には（参考）

### 実践ガイドブックでは？

さすが行政での運用を前提としているので少々複雑というか、大掛かりです。
まず、プロジェクト管理要項（第6章）にて、課題管理について定義しています。

![000010.jpg](https://drive.google.com/uc?export=view&id=17e-HtH5eFNY-kF1iGBmrZSzx5jvv0o8K)

上記の２，３章で課題登録簿、課題個別管理表が定義されており、テンプレートが提供されています。

#### 課題管理簿

![000020.jpg](https://drive.google.com/uc?export=view&id=1eoy7wYi3z2woKAvVbkkASC4koebjztGn)

#### 課題対応状況一覧

![000030.jpg](https://drive.google.com/uc?export=view&id=1DlkXOdYIHvct7mdzCEHlVhUHpRTKlQeG)

#### 課題個別管理簿

![000040.jpg](https://drive.google.com/uc?export=view&id=1QZGEWYhtMUDaRcqqHiUD5Io4f9l6aFM5)

少し冗長な感じもしますが、管理項目などは参考になります。

>ただ、私もそれなりの規模と数のプロジェクトに参加してきましたが、多くの場合一枚のExcelで管理することが多いです（可読性の問題ですかね）。

## 参考

* [デジタル庁 デジタル社会推進標準ガイドライン](https://www.digital.go.jp/resources/standard_guidelines/)
* [DS-120 デジタル・ガバメント推進標準ガイドライン実践ガイドブック　各種テンプレート](https://www.digital.go.jp/assets/contents/node/basic_page/field_ref_resources/e2a06143-ed29-4f1d-9c31-0f06fca67afc/ec6f6641/20220422_resources_standard_guidelines_guideline_09.zip)
「WBS（ガントチャート）」を作成してみる

この記事は、「[架空プロジェクトを通してシステム開発とドキュメント作成を体験してみる（2022 Late）](https://qiita.com/minimumskills/items/aedf6a93658db3f74747)」の記事の一部です。

## WBS（ガントチャート）の概要

WBSとはWork Breakdown Structureの略で、正確には大きなタスクを実行可能なレベルに分解したもの（資料）のことですが、実行スケジュールを示すガントチャート表記と組み合わせて利用されることが多いため、WBS = ガントチャート、ガントチャート = WBSとして、現場ではあまり区別されていません。ここでも、WBS = ガントチャートとして区別せずに說明します。

|項目|内容|
|-|-|
|作成目的|プロジェクトにおけるタスク、実施時期、担当者等の明確化・管理のための資料|
|記述すべき内容|実行レベルに分解されたタスク、担当者、開始日、終了日時|
|作成タイミング|計画時、要件定義時（必要に応じて更新）|
|対象者|プロジェクトメンバー全員（非技術者、技術者）|
|ファイル形式|Excelで作成することが一般的|
|備考|実務ではWBSとガントチャートがあまり区別されませんが、厳密にはWBSとガントチャートは別ものです。がここではWBSということにします。|

>一般的にはどうなのか？が気になる人は後半にある「一般的には（参考）」に先に目を通してください。

### サンプルダウンロード
サンプルのダウンロードは[こちら](https://docs.google.com/uc?export=download&id=16Dt07xTh9j3ceXn1rcpB57Iryr8wnatJ)から。

## 作成してみる

では作成していきましょう。

### 作成方針・ポイント

#### いきなり完成品を作ろうとしない

プロジェクト計画書でも書きましたが、いきなり完成品を作ろうとしないことです。
私の場合、下記のような感じで作ります。

* まずはタスクの洗い出しがてらラフに作ってみる
* 各タスクを整理しつつラフにスケジュールを割り当ててみてスケジュールに無理が無いかやタスク間の整合性を確認
* 上記での作成内容を懸念点を含めて上長にレビューしてもらう
* レビュー意見を反映して清書する


#### タスクは実行可能かつ細かすぎないレベルで設定する

WBSのタスクの記述には毎回悩みます。
大きすぎず、小さすぎず、かつ実行可能なレベルで記述するのがポイントです。

* 大き過ぎるタスク例：各種サーバを立てる
* 小さ過ぎるタスク例：Apacheをインストールする。PHPをインストールする（これは手順書に書くレベルかな）
* 適切な？例：Webサーバの構築、DBサーバの構築

>本来のWBS（Work Breakdown Structure）という意味ではApacheをインストールする。というのもありかもしれませんが、ガントチャートという観点では細かすぎるかなと。

### 構成（管理項目）を考える

WBSに記述すべき項目（カラム）は、

* タスク
* 管理番号
* 担当者
* 開始日
* 終了日
* スケジュール：ガントチャート（適切な区切りで作成：日次、週次、月次）

あたりが必須項目で、必要に応じて以下を追加という感じ。

* タスクカテゴリ
* 担当者の部署
* 各タスクの完了基準（成果物）
* 会議スケジュール
* 重要度（優先度、難易度）
* クリティカルポイント

などを記載する場合もあります。

ぜひ、自分の環境に合わせて作成してみてください！

### 各内容を記述する（サンプルの說明）

では、サンプルについて少し解説したいと思います。

### WBS（ガントチャート）全体

個別ページがあるわけではないので全体をまとめて說明します。

時間軸に沿った項目（社内手続き、要件定義、設計等）をカテゴリとして、子タスクを設定しています。
あとは管理番号、タスク名、開始日、終了日です。

>プロジェクトにおける役割はサンプルの便宜上追加しているもので、通常はありません。

ガントチャートを日次レベルで作成しているのであえて開始日、終了日は記入していません（記入しても問題ありません）。ガントチャートを日次で作成する場合は祝日等もわかるようにします。定例会議と祝日がかぶるような場合は、あらかじめ別日を予定日として調整するように準備したりします。

![000001.jpg](https://drive.google.com/uc?export=view&id=1mJFItq1hEasyiN3VKkYl-c8jUxnL7KHJ)

## 一般的には（参考）

### 実践ガイドブックでは？

WBSは本来のWBSとして、スケジュール（ガントチャート）は開発イベントマップとして別々に準備・記載しているようです。

* WBS（教科書どおり、作業を分解したもの）
* 開発イベントマップ（概要レベルのガントチャート）

### 実践ガイドブックのWBS

ガイドラインの項目に従ってタスクが分解されています（細かい・・・）。

![000010.jpg](https://drive.google.com/uc?export=view&id=1TlSUAN3tyyHgocyTiyI4DbUVBJ85uEK6)

### 実践ガイドブックの開発イベントマップ

矢羽でタスクとスケジュールが表現されています。
恐らく実案件の進捗においては別途ガントチャートを作ることになるのかなと思います。。。

![000020.jpg](https://drive.google.com/uc?export=view&id=1iQcYso646MJXfu2peZdCgb0IIa0pXSNB)

### その他

なお、WBSについては専用ツールやサービスが使われることも多いです（古いところではMicrosoft Projectとか。最近では各種クラウドサービスがありますね）。
ただ、ツールを使う場合でも「一旦Excelで作ろう」とかなるので、自力で作れた方がいいです。

## 参考

* [デジタル庁 デジタル社会推進標準ガイドライン](https://www.digital.go.jp/resources/standard_guidelines/)
* [DS-120 デジタル・ガバメント推進標準ガイドライン実践ガイドブック　各種テンプレート](https://www.digital.go.jp/assets/contents/node/basic_page/field_ref_resources/e2a06143-ed29-4f1d-9c31-0f06fca67afc/ec6f6641/20220422_resources_standard_guidelines_guideline_09.zip)
暗号化技術

# 暗号方式
### 関連記事（共通暗号方式、公開暗号方式）
https://qiita.com/masatom86650860/items/8f9fecf76e27c3ed3759#%E6%9A%97%E5%8F%B7%E5%8C%96%E3%81%A8%E5%BE%A9%E5%8F%B7

## 代表的な共通暗号方式
### AES
鍵の長さが128ビット、１９２ビット、２５６ビットのいずれでも選択できる。
これまでの主流だったDESに比べて解読されにくい

## 代表的な公開鍵暗号方式
### RSA
```大きな数の素因数分解の困難さを利用している。```
その計算量が膨大となるため、安全性が保つことができる。デジタル署名に利用できる。

### エルマガル暗号
```離散対数問題の難しさを利用している。```
改良したものに```DSA```がある。

### 楕円曲線暗号
RSAに比べて鍵のサイズが小さく、高速処理が可能。
楕円曲線暗号を利用してDSAを改良したECDSAが考案されている。

# ハイブリッド暗号
共通鍵暗号方式（鍵の受け渡し）と公開鍵暗号方式（暗号/複合に時間がかかる)の弱点を補う方法。
最初に公開鍵の暗号方式で共通鍵を送り、以降は共通鍵をやりとりする。

### 関連記事
https://it-trend.jp/encryption/article/64-0063

# 出典
https://gihyo.jp/book/2022/978-4-297-12375-8
apacheで現在のフォルダをサーブしたい

# 経緯
apacheサーバーで運用している開発案件に参画
apacheじゃ無いと、jqueryの読み込み順序がバグる。
.htaccessも使いたい。
でも、docker-composeとか毎回書くのだるい。

### やりたいこと
apacheでコマンド１つで現在ディレクトリを配信するサーバーを構築したい。

# 解決策
`serve`とコマンドを打つと、apacheのdockerコンテナが起動するようにfish functionを作った。
zshやbashでも同じように作れると思う。

```bash:tree
# ~/.config/fish/functions
.
├── serve
│   └── Dockerfile
└── serve.fish
```
```Dockerfile:~/.config/fish/functions/serve/Dockerfile
FROM php:7.0-apache
 
RUN  a2enmod rewrite proxy proxy_http
```
```fish:~/.config/fish/functions/serve.fish
function serve
    echo (dirname (status --current-filename))
    docker run -it -p 8080:80 -v "$PWD":/var/www/html (docker build -q (dirname (status --current-filename))/serve)
end
```

# appendix
### 今後
以下をやるかも
- argsでポート指定できるように
- 
### 他の手段
##### serveコマンド(npmやyarnでインストール)
読み込み順序がバグる。.htaccessが使えない。などの理由から今回は正常に動作しなかった。
##### nginxコマンドを作る
本番環境で.htaccessを使ってるので、近い環境で試したかった。
PlayCanvasでLottieを使ったローディングスクリーンを作る

[Lottie](https://github.com/airbnb/lottie-web) - ([LottieFiles](https://lottiefiles.com/))を利用して動的なロード画面をPlayCanvasで作成する方法となります。

実行URL: https://playcanv.as/b/c9f69d9d

### 1. External Scriptからスクリプトを読み込む

CDNからスクリプトファイルを読み込みます。
最新のバージョンは[こちら](https://cdnjs.com/libraries/bodymovin)からご確認ください。
```bash
https://cdnjs.cloudflare.com/ajax/libs/bodymovin/5.9.6/lottie.min.js
```

#### 2. 「SETTINGS」 → 「EXTERNAL SCRIPT」にスクリプトのURLを設定
![スクリーンショット 2022-10-19 11.46.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257048/9b44b8a1-77f4-ebb2-8a47-b8249210fd90.png)


### 3. 「SETTINGS」 →「LOADING SCREEN」からローディングスクリーンを作成
「CREATE LOADING SCREEN」から新規にロード画面を作成します。
ファイル名は`custom-loading.js`などとして置きます。
![スクリーンショット 2022-10-19 11.48.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257048/ea0af373-f012-1e60-e6bb-0eb92b047ee9.png)

### 4. ローディングスクリーンを書き換え
ロード画面のテンプレートが作成されておりますが、そちらの中身を下記のスクリプトに書き換えます。

```javascript
// custom-loading.js
pc.script.createLoadingScreen((app) => {
    // アニメーション用の要素を作成
    const wrapper = document.createElement('div');
    wrapper.style.position = "absolute";
    wrapper.style.background = "#fff";
    wrapper.style.width = "100vw";
    wrapper.style.height = "100vh";
    wrapper.id = 'application-splash-wrapper';
    document.body.appendChild(wrapper);

    const lottieAnimation = lottie.loadAnimation({
        container: wrapper,
        name: "loading",
        loop: false, // ループしない
        autoplay: false, // 自動再生をしない
        path: "https://assets7.lottiefiles.com/packages/lf20_gapacy3r.json", // アニメーションデータのURL
    });


    // progress - 0.0 - 1.0の値
    app.on('preload:progress', (progress) => {
        lottieAnimation.goToAndStop(progress * lottieAnimation.timeCompleted, true);
    });

    app.once('preload:end', () => {
        app.off('preload:progress');
    });

    // アプリケーションのフレームが始まった場合にローディング画面を削除
    app.once('start', () => {
        const splash = document.getElementById('application-splash-wrapper');
        splash.parentElement.removeChild(splash);
    });
});
```

これでロード画面にLottieを利用する事ができます。

### 自分で作ったアニメーション / 公開されているアニメーションを変更する
Lottieで作成したアニメーションをコピーし`.json`形式のアニメーションファイルのURLをコピーします。
![スクリーンショット 2022-10-19 11.55.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257048/dde356f0-e5d0-ff50-0d11-6c62f56048bb.png)


次にロード画面のスクリプト(`custom-loading.js`)を書きえます。

```javascript
   const lottieAnimation = lottie.loadAnimation({
        container: wrapper,
        name: "loading",
        loop: false, // ループしない
        autoplay: false, // 自動再生をしない
        path: "コピーしたURL"
    });
```
これで任意のアニメーションを利用することができます。
今回は、自動再生をせずに、ロードの状況に合わせてプログレスバーを進めています。
ループするアニメーションなどの場合は、`loadAnimation`の`loop`,`autoplay`を`true`にすることでループしたアニメーションを再生できます。

参考: [loadAnimation options](https://github.com/airbnb/lottie-web/wiki/loadAnimation-options)
Tensor Numpy PIL image 相互変換【PyTorch】

# 目的
PyTorchで画像等を扱っていると、Tensor、Numpy、PIL imageのそれぞれの形式に変換したい場合が多々ある。
ここでは、備忘録としてそれぞれの形式に対する相互変換方法を示す。

# 各データ形式の特徴
* __Tensor__：学習モデルへの入力や中間層での計算に用いる。torchvisionを用いると各種画像処理が楽に行える。
* __Numpy__：Numpyの機能はほぼTensorでも使用可能だが、matplotlibでデータを扱いたい場合に変換が必要。
* __PIL__：画像の読み込みや書き出し、簡単な画像処理などを行える。

# 各種変換方法
### Tensor ↔ Numpy
```python
import torch
import numpy as np

# tensor -> numpy
t = torch.zeros(3,128,128)
n = t.to('cpu').detach().numpy()

# numpy -> tensor
n = np.zeros((3,128,128))
t = torch.from_numpy(n)
```
### Numpy ↔ PIL image
```python
from PIL import Image
import numpy as np

# numpy -> PIL image
n = np.zeros((128,128,3))
p = Image.fromarray(np.uint8(n))

# PIL image -> numpy
p = Image.open('sample.jpg')
n = np.array(p)
```

### PIL image ↔ Tensor
```python
from PIL import Image
import torch
import torchvision

# PIL image -> tensor
p = Image.open('sample.jpg')
t = torchvision.transforms.functional.to_tensor(p)

# tensor -> PIL image
t = torch.zeros(3,128,128)
p = torchvision.transforms.functional.to_pil_image(t)
```

# 参考
https://pillow.readthedocs.io/en/stable/reference/Image.html

https://pytorch.org/vision/stable/generated/torchvision.transforms.ToTensor.html

https://pytorch.org/vision/stable/generated/torchvision.transforms.functional.to_pil_image.html

https://numpy.org/doc/stable/reference/generated/numpy.array.html
Proxy環境内のWSL2でapt updateが失敗する

## はじめに

解決するためにやったことを、自分用の備忘も兼ねて残しておきます。

既に多くの方々が発信してくださっている内容なので今更感がありますが、記事を書くことを習慣づけるためにも、あえて手を動かしてみます。

## 目次

- 環境
- 名前解決
- プロキシを通す

## 環境

ちなみに、職場環境です。

### Windows

Windows 10 Pro
バージョン：20H2

### WSL2

Ubuntu 18.04.5 LTS

### プロキシ

プロキシサーバでプロキシ自動構成（PAC）ファイルを使用。

id、パスワードは不要です。

なお、プロキシサーバIP、ポートの抜き取り方は本記事では記載していません。

## 名前解決

以下の記事を参考にさせていただきました。

[WSLにてapt update時の『Temporary failure resolving ~』を解決する方法](https://qiita.com/ryosukeYamazaki/items/c04ec3ff78aac6eb8d26)

### /etc/wsl.conf

wsl2の起動時にresolv.confが自動再生成されないようにします。

以下のように設定すればOKです。

```
$ cat /etc/wsl.conf
[network]
generateResolvConf = false
```

### resolv.conf

自環境のDNSサーバのIPを使用することにしました。

#### Windowsで設定値を調べる

PowerShellで`ipconfig /all`

「DNS サーバー」の値を控えておきます。

#### ubuntuに設定

控えた値を以下のように設定します。

```
$ cat /etc/resolv.conf
nameserver xxx.xxx.xxx.xxx
```
---

※上記の参考記事同様、`/etc/resolv.comf`に`nameserver 8.8.8.8`を追加しても、私の環境ではうまくいきませんでした。

## プロキシを通す

以下の記事を参考にさせていただきました。

[apt のプロキシ対応](https://qiita.com/m-tmatma/items/e3d9de76be50763ac01c)

### ~.bashrc

以下を記載します。

```
if [ -z "$http_proxy" ]; then
    export http_proxy=http(s)://<server>:<port>
    export https_proxy=${http_proxy}
    export HTTP_PROXY=${http_proxy}
    export HTTPS_PROXY=${https_proxy}
fi
```

`apt`を実行するときは、rootに昇格しても現在の環境変数を保持できるように、`-E`を付けます。

`sudo -E apt update`

`-E`を不要にする方法は以下です。

### /etc/apt/apt.conf

`/etc/apt/apt.conf`に、以下のように設定します。

```
Acquire::http::Proxy "http(s)://<server>:<port>";
Acquire::https::Proxy "http(s)://<server>:<port>";
```

ただし、この方法だとid、パスワードを要求される場合、それも記載することになるため注意が必要です。

以上で`apt update`を実行すると、正常終了しました。

## 終わりに

事の発端はCI/CDを導入したいという私の無謀な提案でした。
試しにjenkinsをインストールしようということで、まず`apt update`したらいきなりコケました。
先は長いです。

この記事がどなたかの役に立てば幸いです。
ITプロジェクトのプロセスと関連ドキュメント

この記事は、「[架空プロジェクトを通してシステム開発とドキュメント作成を体験してみる（2022 Late）](https://qiita.com/minimumskills/items/aedf6a93658db3f74747)」の記事の一部です。

## ITプロジェクトのプロセスについて

ITプロジェクトを理解するにはまずITプロジェクトの標準的なプロセスを理解する必要があります。
ITプロジェクトに限らず、ビジネスの各種業務には凡そ標準的なプロセスがあり、各プロセスにおいてそれらを管理したり、進捗させたりするための関連ドキュメントが存在しています。

**ITプロジェクトの場合、それ特有のプロセスが存在するというより、要件定義→設計→開発→テストといったいわゆる開発プロセスと、見積→稟議→発注→納品→検収→請求といった一般ビジネスプロセス（受発注プロセス）が融合した形**となっていて、関連するドキュメントもそれらを融合したものになっていますので、それぞれのプロセスを少し解説します。

### 開発プロセス

開発プロセスとは開発を進める工程（順序）のことです。開発プロセスにも「ウォーターフォール型」、「アジャイル型」、「スパイラル型」、「プロトタイプ型」等、各種存在していますが、実際の業務現場でよく見かけるのは、以下の２つです。

* ウォーターフォール型
* アジャイル型

ウォーターフォール型プロセスは、水が落ち流れるように**要件定義→設計→開発→テスト**という順序で開発を進めるプロセスで、アジャイル型は一定に区切られたこまかな開発（イテレーションとかスプリントとかいいます）を繰り返し行っていくプロセスになりますが、アジャイル型においても、その繰り返される開発行為の中で、（要件定義）設計→開発→テストを繰り返す形となりますので、ウォーターフォール型が開発プロセスの基本とも言えます。ここではウォーターフォール型プロセス前提として話を進めます。

![000001.jpg](https://drive.google.com/uc?export=view&id=1q5f_5OxtMpE-bbubCltzxwYDGZa5Pq2E)
>なお、ウォーターフォールでもプロセスの区切り方などは会社やプロジェクト毎に異なり、絶対的な基準が存在するわけではありません（補足も見てね）。

>アジャイル型もさらにXP、スクラム、それらの融合等、いくつかに分類できますが、ここでは触れません。興味のある人はググってね。

### 一般ビジネスプロセス（受発注プロセス）

ITプロジェクトを円滑に進めるためには開発プロセスの理解のみでは不十分で、周辺業務のプロセスも合わせて理解しておく必要があります。必要となるビジネスプロセスは状況により異なりますが、開発業務を外注する場合などには、**見積→発注→（開発）→納品→検収→請求**といったいわゆる受発注プロセスおよび関連ドキュメントを理解しておく必要があります。

![000002.jpg](https://drive.google.com/uc?export=view&id=1a-Kfl7cZ6TiR3O1NFMi3gk0rDUBbvT-G)


### 改めてITプロジェクトのプロセスとは？

本コンテンツではITプロジェクトのプロセスおよび必要なドキュメンを以下のように定義し、話を進めます。

![000003.jpg](https://drive.google.com/uc?export=view&id=1tW3w2ZbhS3hiI3jyzQrzN2ha_k7U5dkF)

なお、ITプロジェクトで作成するドキュメントはだいたい決まってはいるものの会社やプロジェクトにより異なるので、どのようなドキュメントをどのような方針で作成するかは、プロジェクト計画書や要件定義書等で定義しておくのが無難です。

ちなみに本コンテンツにおいてはプロジェクト計画書にて成果物一覧として定義しています。

## 補足

### いろいろ存在するプロセス

デジタル・ガバメント推進標準ガイドライン 実践ガイドブック においても、各種プロセスが異なることが紹介されています。

![000004.jpg](https://drive.google.com/uc?export=view&id=1fRwBRJcFOzn9gTKWSlRdm0wAQ9bXP1Me)


### 必要なドキュメント

デジタル・ガバメント推進標準ガイドライン 実践ガイドブックでは、以下のドキュメントテンプレートが提供されています（本コンテンツで提供するドキュメントとの対比も記載）。

![000005.jpg](https://drive.google.com/uc?export=view&id=1aGP09zK8aHhtK_jcjzPZjTQjBWuanJwN)


政府の調達を前提としているので、民間ではあまり見られない要領（ルール等を記載したもの）や調達、監査などのドキュメントが追加されているのがわかります。

>民間？では要領は別途作らず、各種ドキュメントに含めてしまう印象です。

なお、民間の参考資料としては[TISさん](https://www.tis.co.jp/)が運営する[Fintan](https://fintan.jp/)の[開発プロセス関連](https://fintan.jp/blog-category/development-process/)の資料も参考になります。
ドキュメントという視点での整理はないですが、プロセス毎の役割分担、合意事項などが整理されています。各役割や合意に関連するドキュメントが必要という見方もできますので、興味のある方は見てみてください。特に「[ウォーターフォール開発における役割分担シート](https://fintan.jp/page/1436/)」の小項目は「決めないといけないこと」のチェックリストになるかと思います。
AWS SageMaker Studio 費用（ノートブックとインスタンスもシャットダウンしないと課金される）

AWS SageMaker Studio初心者です。
Abalone pipelineチュートリアル実行して費用発生（約$10/day）したので
原因を探ってみました。

１）結論
ノートブックとインスタンスもシャットダウンしないと課金される

２）原因
公式の料金表だとml.m5.xlargeは$0.298/Hなので24Hずっと動かしてたらしい。
作業終了時には必ずノートブックをシャットダウンしてたのになぜ？と思い
サポートページ（コンソールの右上の？にある）へ質問してみました。
3日ほどで回答が来て、丁寧に色々と説明がある中に
「自動シャットダウン拡張機能を利用した Amazon SageMaker Studio のコスト削減方法」があり
どうやらノートブックをシャットダウンしても、インスタンスまでシャットダウンしないと
課金され続ける事が判明。
https://aws.amazon.com/jp/blogs/news/save-costs-by-automatically-shutting-down-idle-resources-within-amazon-sagemaker-studio/#:~:text=%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E4%B8%8A%E3%81%A7%E5%AE%9F%E8%A1%8C%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%E3%83%8E%E3%83%BC%E3%83%88%E3%83%96%E3%83%83%E3%82%AF%E3%82%92%E3%82%B7%E3%83%A3%E3%83%83%E3%83%88%E3%83%80%E3%82%A6%E3%83%B3%E3%81%97%E3%81%A6%E3%82%82%E3%80%81%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%82%92%E3%82%B7%E3%83%A3%E3%83%83%E3%83%88%E3%83%80%E3%82%A6%E3%83%B3%E3%81%97%E3%81%AA%E3%81%91%E3%82%8C%E3%81%B0%E3%80%81%E8%AA%B2%E9%87%91%E3%81%AF%E7%B6%99%E7%B6%9A%E3%81%97%E3%81%BE%E3%81%99%E3%80%82


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1683167/88d0f118-e15b-2db5-1754-99ab81e671eb.png)


３）対策
SageMaker Studioの画面左にある「Running Terminal and Kernels」ペインで
インスタンスもちゃんとシャットダウンする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1683167/6611aba5-bf4a-a67e-5362-da4a4302abf4.png)
pythonでjwtを検証してみる。

# 概要

pythonでjwtを検証してみる。

# 参考にしたページ

https://qiita.com/leo1109/items/2e82c899891f8e771315

# サンプルコード

```
# coding: utf-8
# Your code here!
import base64
import json
import jwt

jwt_ = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ'
tmp = jwt_.split('.')
header = json.loads(base64.b64decode(tmp[0]).decode())
payload = json.loads(base64.b64decode(tmp[1]).decode())
print(header)
print(payload)
print(jwt.decode(jwt_, options = {"verify_signature": False}))
print(jwt.decode(jwt_, 'secret', algorithms = ['HS256']))
result = jwt.encode(payload, 'secret', algorithm = 'HS256', headers = header)
print(result)
print(jwt.decode(result, 'secret', algorithms = ['HS256']))
header = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}"
payload = "{\"sub\":\"1234567890\",\"iat\":1516239022}"
header = json.loads(header)
payload = json.loads(payload)
print(header)
print(payload)
result = jwt.encode(payload, 'secretkey', algorithm = 'HS256', headers = header)
print(result)
print(jwt.decode(result, 'secretkey', algorithms = ['HS256']))



```

# 実行結果

```
{'alg': 'HS256', 'typ': 'JWT'}
{'sub': '1234567890', 'name': 'John Doe', 'admin': True}
{'sub': '1234567890', 'name': 'John Doe', 'admin': True}
{'sub': '1234567890', 'name': 'John Doe', 'admin': True}
b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.pcHcZspUvuiqIPVB_i_qmcvCJv63KLUgIAKIlXI1gY8'
{'sub': '1234567890', 'name': 'John Doe', 'admin': True}
{'alg': 'HS256', 'typ': 'JWT'}
{'sub': '1234567890', 'iat': 1516239022}
b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyfQ.fta4kBfweubZrnpiTZhk-sjj2DarBLTV0WoZ8Qer9dg'
{'sub': '1234567890', 'iat': 1516239022}
```

# 成果物

https://paiza.io/projects/EjyzCPu-WWskANvE_WCxNQ


以上。
Azure Fundamentals(AZ-900)：Azure の基礎: Azure のアーキテクチャとサービスについて説明する「Azure ExpressRoute」

Microsoft Learnを用いたMicrosoft Azure Fundamentals(AZ-900)の試験内容をまとめる投稿です。
この投稿ではMicrosoft Learnで学ぶ内容をできるだけ簡潔にまとめております。
Azureの勉強を一から始める方の参考になれば幸いです。

## 今回の学習内容
**◆「Azure ExpressRoute」**
◇対応するMicrosoft Learn ラーニングパス
[Azure の基礎: Azure のアーキテクチャとサービスについて説明する](https://learn.microsoft.com/ja-jp/training/paths/azure-fundamentals-describe-azure-architecture-services/)
◇対応するモジュール
[Azure ExpressRoute について説明する](https://learn.microsoft.com/ja-jp/training/modules/describe-azure-compute-networking-services/11-expressroute)

※前回の投稿は下記から確認できます。
[Azure Fundamentals(AZ-900)：Azure の基礎: Azure のアーキテクチャとサービスについて説明する「Azure仮想プライベートネットワーク(VPN)」](https://qiita.com/fsd-jume/items/7d5b49c320035a5a28b3)

## Azure ExpressRoute
**接続プロバイダが提供するプライベート接続を介して、オンプレミスのネットワークをMicrosoftクラウドに接続するサービス**
・公共のインターネット回線を使用せず、専用の回線(ExpressRoute回線)を使用して接続
⇒堅牢なセキュリティで品質の高い通信が可能

### ExpressRouteの機能と利点
**◆Microsoftクラウドサービスへの接続**
・すべてのリージョンの下記のサービスに直接接続できる
　-Microsoft Office 365
　-Microsoft Dynamics 365
　-Azure VMなどのAzureコンピューティングサービス
　-Azure Cosmos DBやAzure StorageなどのAzureクラウドサービス

**◆グローバル接続**
・ExpressRoute Global Reachを有効にすると、オンプレミスサイト間の通信をExpressRoute回線経由で可能になる
・トラフィックはMicrosoftネットワークの中を通過
・例)ExpressRoute回線でMicrosoftネットワークに接続されたアジアのオフィスとヨーロッパのデータセンターが直接通信可能になる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851723/eb525f5a-cf91-64e2-3d20-1f0ff481435c.png)

**◆動的ルーティング**
・ExpressRouteではBGPを使用
・オンプレミスネットワークとAzureリソース、Microsoftパブリックアドレスとの間でそれぞれルートを交換

**◆組み込みの冗長性**
・各ExpressRoute回線は接続プロバイダ側から2つのMicrosoft Enterprise エッジルータ(MSEE)に対してそれぞれ接続
・MSEEデバイスはMicrosoftのネットワークへの入り口
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851723/9bc2fa40-5b0b-d268-766f-22892367c7ff.png)

### 接続モデル
**◆CloudExchangeでのコロケーション接続**
・クラウドの接続口(CloudExchange)があるデータセンターからMicrosoftクラウドに接続
・データセンターにあるネットワーク機器から接続プロバイダの専用回線を使用して接続

**◆ポイント ツー ポイントのイーサネット接続**
・オンプレミスのデータセンターやオフィスをP2PのイーサネットリンクでMicrosoftクラウドに接続
・通信事業者の専用回線を使用して接続

**◆Any-to-Anyネットワーク接続**
・WANからMicrosoftクラウドまでをIP-VPNを使用して接続
※IP-VPN：通信事業者が独自に保有する閉域ネットワークを使用してVPNを構築

**◆ExpressRouteサイトからの直接接続(ExpressRoute Direct)**
・プロバイダを介さずにピアリングの場所(MSEEが設置された場所)から直接Microsoftのグローバルネットワークに接続
・大規模なアクティブ/アクティブ接続をサポートするデュアル100Gbps/10Gbps接続が提供
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851723/8d3266c8-ad48-5251-e9cd-481fb4379808.png)

## 次の学習内容
**◆Azure DNS**

https://qiita.com/fsd-jume/items/14c962b0f88227eb456f

## 学習内容をまとめたページの一覧

https://qiita.com/fsd-jume/items/e4ec76959adb547ac5e8
MS Graph APIを利用する認証情報を取得する手順

参照サイト：
https://dev.classmethod.jp/articles/get-azuread-signin-log/

トークンの取得：
curl -X POST -d "grant_type=client_credentials&scope=https://graph.microsoft.com/.default&client_id=クライアントID&client_secret=クライアントシークレット" "https://login.microsoftonline.com/テナントID/oauth2/v2.0/token"
【AWS】複数のIdpを紐づけたCognito ユーザプールを作る

# きっかけ
- とある案件にて拠点ごとにAzure ADが構築されており、それらを使用して、ユーザをSAML連携したCognitoで一括管理できないかという案を受けて調べることになった。
    - 内心、できないんじゃないか（ユーザプールがIdpと１対1対応で複数ユーザプール化）と思っていたが、できちゃったのでこの記事が書かれています

# Cognito, AzureADの構築手順は過去記事参照（CognitoのUIは古いままです）
- 【AWS】Cognito ユーザプールをAzure ADをIdPとして構築する(前編)

https://qiita.com/kei1-dev/items/a0870c26da51dbaa6580

- 【AWS】Cognito ユーザプールをAzure ADをIdPとして構築する(後編)

https://qiita.com/kei1-dev/items/c8ae68e975dccb2902be

# 検証結果
- Azure ADのディレクトリを2つ作り、それぞれユーザを紐づける。
![スクリーンショット 2022-10-18 13.28.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479886/2534a009-087a-3108-3ccb-778fc3debe6b.png)

- Cognitoでフェデレーション>IDプロバイダ>SAMLから作成したAzure ADの各フェデレーション メタデータ XMLを使用し、IDプロバイダを2つ登録する。
![スクリーンショット 2022-10-19 1.38.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479886/0058dc4a-09f0-5bce-49e7-d48e1ac3a0c1.png)

- 属性マッピングも各IDプロバイダに合わせて2つ設定
![スクリーンショット 2022-10-19 1.48.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479886/62a7abc0-a557-c0c0-9321-5c4353929585.png)


- Cognitoのログイン画面へ遷移
    - ログイン画面にIdpを選択する項目（今回は2つ）が表示
![スクリーンショット 2022-10-19 1.49.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479886/aa01f11d-5448-2755-ae9f-0d8b49c3f31c.png)

- リダイレクト指定しているlocalhost:8000の適当なWebページへ遷移したことを確認
![スクリーンショット 2022-10-19 1.55.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479886/73db6522-eddc-130d-c1b7-a92a31afbfa1.png)

- Cognitoユーザプール、ユーザグループにそれぞれ対応しているユーザ、グループができることを確認
    - IDプロバイダ名 + ユーザIDで一意になっている
![スクリーンショット 2022-10-19 1.57.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479886/32eea0d5-4600-f64d-8457-22c806519e5f.png)
![スクリーンショット 2022-10-19 1.58.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479886/5eb6f928-94aa-c340-0723-3fd32c7764b9.png)
Chrome、Edgeのグループポリシーによる従来通りのSamesite属性の振る舞いは、少なくとも2023年6月27日までしかサポートされない問題について

■投稿した理由
以下記載の通りブラウザでのSamesite属性の制御についての猶予が近づいているため、本件について投稿してみました。
(Apr 27, 2022) LegacySameSiteCookieBehaviorEnabledForDomainList will be available until at least Jun 27, 2023. We will be monitoring feedback and will provide updates on its lifetime as appropriate.
(2022 年 4 月 27 日) LegacySameSiteCookieBehaviorEnabledForDomainList は、少なくとも 2023 年 6 月 27 日まで利用できます。フィードバックを監視し、必要に応じて有効期間の更新を提供します。

https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies/


■Samesite属性の問題とは

CSRF対策としてSamesite属性が明示されていない場合におけるブラウザでのデフォルトの振る舞いがNoneからLaxに変更された事に伴い、
クロスサイトでのCookie連携が実施出来ない場合がある問題。

HTTPリクエストヘッダーにてSamesite属性が明示されていない場合、ブラウザとしてSamesite属性をLaxとして振る舞う事により
TopLevelNavigationかつSafeメソッド(GET,HEAD,OPTIONS,TRACE)の場合のみCookieが送信されるので、以下の様な場合においてCookie連携が出来ない。

⇒  Iframeを利用している。（TopLevelNavigationではない）
⇒　POST通信を利用している。（Safeメソッドではない）


最も簡単な問題回避方法としてはブラウザ側の設定変更により、
Samesite属性の取り扱いを以前のバージョンと同じように、Samesite属性が明示されていない場合にSamesite属性：Noneとして振る舞うように変更する事である。


＜SameSite 属性について＞
Cookie の SameSite 属性は、Cookie をファースト パーティまたは同じサイトのコンテキストに制限するかどうかを指定します。SameSite のいくつかの値が許可されています。

「SameSite=Strict」の Cookie は、同一サイト リクエストでのみ送信されます。
「SameSite=Lax」の Cookie は、同一サイト リクエスト、または「安全な」HTTP メソッドを使用したクロスサイト トップレベル ナビゲーションで送信されます。
「SameSite=None」の Cookie は、同一サイト要求とクロスサイト要求の両方で送信されます。



■ブラウザ側での制御の歴史

Samesite属性が明示されていない場合にSamesite属性：Noneとして取り扱う、以前までのブラウザの振る舞いをする為のポリシーは以下2種類存在するが
１つは既に廃止済み、もう１つも近い将来廃止予定となっております。

・LegacySameSiteCookieBehaviorEnable
（Samesite属性の振る舞いを従来通りに戻すポリシー）
　⇨　Chrome、Edge94以降で廃止済み
・LegacySameSiteCookieBehaviorEnabledForDomainList
（ドメイン単位に振る舞いを戻すポリシー）
　⇨　少なくとも2023年6月27日までは利用可能。（2022/10/18時点の情報）


■対処方法

2023年6月28日以降のバージョンのChrome、Edgeにおいては上記設定が使えない為、以下の様な対処が考えられる。

　１．Laxの影響を受けないシステムデザインへ変更する
　（例：POST通信からGET通信への変更など）

　２．Cookie連携しないシステムデザインへ変更する
　（例：APIの開発）

　３．Cookie発行するサーバにてSamesite属性＝Noneを指定する
　　※通信のHTTPS化が同時に必要となる。
　　（少なくともブラウザ側でHTTPS化していれば良いので、通信経路上でHTTPへの復号化処理が出来ればバックエンドの業務サーバの改修は不要な場合もある。）

　４．ブラウザのバージョンを塩漬けする
　　※バージョンアップ以外でセキュリティが担保できる仕組みがあれば可能であるが、いずれ限界は来ると思われる。。。


■参考にしたサイト

＜CSRF（クロスサイトリクエストフォージェリ）＞
https://www.ipa.go.jp/security/vuln/websecurity-HTML-1_6.html

＜Samesite属性について＞
https://numb86-tech.hatenablog.com/entry/2020/01/26/112607

＜LegacySameSiteCookieBehaviorEnabled＞
https://support.google.com/chrome/a/answer/10314655#93
https://learn.microsoft.com/ja-jp/deployedge/microsoft-edge-policies#legacysamesitecookiebehaviorenabled

＜LegacySameSiteCookieBehaviorEnabledForDomainList＞
https://www.chromium.org/administrators/policy-list-3/cookie-legacy-samesite-policies/
user登録者毎に画面表示させる方法

「id」を使って、各ユーザー毎に画面表示させる方法を学習したので、皆さんに共有します。


当初の遷移方法は
reg.php（登録画面） →　reg_list.php（登録一覧画面） となる。



reg.php(入力画面)
```php

　　　　　　　 　　　　　　　<div class="form_title">
          <div class="date">日付：<?php echo date("m月d日");?></div>
          <div class="input_form">
            <form method="post" action="reg_list.php" class="reg_method">
              <input type="text" name="title" class="reg_input">
              <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']?>">
              <input type="hidden" name="created_at">
              <button class="hozon">保存</button>
            </form>
          </div>
        </div>

```

 inputタグの　name="title" で入力を行う。




reg_list.php 1/2 インサート画面
```php

<?php
   try {
      $pdo->beginTransaction();
      // データをSQLに登録する
      $stmt = $pdo->prepare('INSERT INTO tasks (title,user_id) VALUES (:title, :user_id)');

      // バインドパラムでセットする
      $stmt->bindParam( ':title', $title, PDO::PARAM_STR);
      $stmt->bindParam( ':user_id',$_SESSION["id"], PDO::PARAM_INT);
 
      // SQL実行
      $res = $stmt->execute();

      // コミット
      if( $res ) {
        $pdo->commit();
      }
      //ここでトランザクション終了。
    } catch(PDOException $e) {

      // ロールバック
      $pdo->rollBack();

      // エラーメッセージを出力
      echo $e->getMessage();
      exit;
    }
    header("Location:./reg_list.php");
    exit();
  };

```

データをSQLに登録する。「user_id」を登録することによって、
データベースの「title」の列表示がnull　→ ID番号へになる。

バインドパラムの「 $_SESSION["id"] 」をSESSIONからidを引っ張ってくることによって
別のテーブル（users）とtasksのIDをリンクさせる準備をする。

$res = $stmt->execute();　を実施してSQL実行する。


※$_SESSION["id"]はスーパーグローバル変数になるため必ず大文字で　「　SESSION　　　」と記述する






reg_list.php 2/2 画面表示画面
```php
  //画面表示start。
  try {
    // データを取得するSQL
    $stmt = $pdo->prepare("SELECT id, title, done_at, user_id FROM tasks where user_id=:user_id");
    $stmt->bindParam( ':user_id', $_SESSION["id"], PDO::PARAM_INT);


    // SQL実行
    $res = $stmt->execute();

    $titless = $stmt->fetchAll(PDO::FETCH_ASSOC);  //title全てを抽出し、＄titlessに入れる

  } catch(PDOException $e) {
    // エラーメッセージを出力
    echo $e->getMessage();
  } finally {

    // データベースの接続解除
    $pdo = null;
  }

?>

```
画面表示を行う。
("select id, title, done_at, user_id FROM tasks where user_id=:user_id");
 $stmt->bindParam( ':user_id', $_SESSION["id"], PDO::PARAM_INT);
taskの中の「user_id」をバインドパラムにセットする。
$_SESSION["id"]はusersテーブルから取得する。

※$_SESSION["id"]はスーパーグローバル変数になるため必ず大文字で　「　SESSION　　　」と記述する


$res = $stmt->execute();
SQLを実行する。



まとめ
sessionを使えば、今までformでやっていた削除や編集もidで取得してできそうなので、次回挑戦してみたい
【rails + minitest】 flashに格納したメッセージをassertする方法

## 概要
minitestでrailsのテストを書いていてふと、
「flashの内容でコードの挙動を確認出来れば、testコードの可読性があがりスマートなのでは？🤔」と思ったので、書き方をメモします。

## 結論
以下のように記載すればOK。

    assert flash.to_hash.value? "想定されるメッセージ"

## 詳細
Flashクラスはよくわからないので、`to_hash`でハッシュに変換したのち、`value?`メソッドで格納されたメッセージを検索してます。

これを使えば、以下のように、テストコードの可読性がグンッと上がって幸せ

```ruby:sample-test
test "records-destroy" do
# 正常系
  sign_in(@user2) 
  delete record_path(1) 
  assert flash.to_hash.value? "レコードを破棄しました"
  # ↑ 一目瞭然
  assert_redirected_to records_path

# 異常系
  delete record_path(2)
  assert flash.to_hash.value? "不正なアクセスです"
  # ↑ 一目瞭然
end
```
 ただしAjaxを利用しており、js.erb内で flash.clearが実行される場合、flashが消えてしまい、この方法では評価できないのでご注意を。

 以上。初学者なので、突っ込みあればコメントくださいませ。
Error getting RMW implementation identifier / RMW implementation not installed のERRORの解決策【ROS&ROS2】

# Error getting RMW ~ の解決策

ROS2-foxyのturtlesimを使って，チュートリアルを行おうとした際に生じた，以下のようなエラーに関する解決策．

### エラー内容

```
[ERROR] [1666143744.592924817] [rcl]: Error getting RMW implementation identifier / RMW implementation not installed (expected identifier of 'opensplice_cpp'), with error message 'failed to find shared library 'opensplice_cpp' ~
```

### 解決策

```
$ sudo apt-get update 
$ sudo apt-get install -y ros-foxy-rmw-cyclonedds-cpp
```

# 参考文献
・[“Error getting RMW implementation identifier” error](https://get-help.robotigniteacademy.com/t/error-getting-rmw-implementation-identifier-error/13982)
【graphql-upload】export in package.json causes import failuresの解消方法

# はじめに

ファイルをアップロードする関係上、`multipart/form-data`をリクエストで受け取る必要があったので`graphql-upload`を利用したが　`No "main" export in package.json causes import failures`エラーが発生したので調査した結果をまとめています。

# 環境

`graphql-upload` latest(16.0.2）で発生

`graphql-upload`の`README.md`に記載のある`Requirements`の通りにコンパイルオプションを変更した

# 結論

`graphql-upload-minimal`で代用しました
こちらは`graphql-upload`をフォークされて作られたものなので同じように使用することが可能です

https://github.com/flash-oss/graphql-upload-minimal

https://github.com/jaydenseric/graphql-upload/issues/305#issuecomment-1260573907

> Simply said, if you're not ready for the enlightenment, just stick with the @13 version 😄 or use graphql-upload-minimal package

実際に利用する場合は以下の形式でインポート先を変更するだけで利用が可能です
`NestJS`を利用していますが`Node.js`等で利用される場合は構文を読み替えていただければ同様の結果を得ることができると思います。

```ts:app.module.ts
import { MiddlewareConsumer, Module } from '@nestjs/common'
import { AppController } from './app.controller'
import { PrismaModule } from './prisma/prisma.module'
import { GraphQLModule } from '@nestjs/graphql'
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo'
import * as Process from 'process'
import * as path from 'path'
import { LoggerModule } from 'nestjs-pino'
import { ConfigModule } from '@nestjs/config'
import { AuthorModule } from './author/author.module'
import { AppService } from './app.service'
import configuration from './common/config/configuration'
import { graphqlUploadExpress } from 'graphql-upload-minimal'


@Module({
  imports: [
    LoggerModule.forRoot(),
    PrismaModule,
    ConfigModule.forRoot({
      isGlobal: true,
      load: [configuration],
    }),
    AuthorModule,
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      autoSchemaFile: path.join(process.cwd(), 'src/graphql/schema.gql'),
      sortSchema: true,
    }),
    CustomJwtModule,
    Auth0Module,
  ],
  providers: [AppService],
  controllers: [AppController],
})
export class AppModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(graphqlUploadExpress()).forRoutes('graphql')
  }
```
備忘録 Ubuntu からcode .でVScodeが開けなくなった

Ubuntu からcode .でVScodeを開こうとしたが、
/mnt/c/Users/ユーザー名/AppData/Local/Programs/Microsoft VS Code/bin/code: 46: cannot create /tmp/remote-wsl-loc.txt: Permission denied
/mnt/c/Users/ユーザー名/AppData/Local/Programs/Microsoft VS Code/bin/code: 52: /mnt/c/Users/ユーザー名/.vscode/extensions/ms-vscode-remote.remote-wsl-0.66.3/scripts/wslCode.sh: not found
というエラーが出て開けなくなった。

【解決方法】
エラー通り/tmp/remote-wsl-loc.txtファイルの権限がrootユーザーに変更されていたため、権限を一般ユーザーに変更した。

1.Ubuntuでcd /tmpを実行しtmpディレクトリまで移動。
2.sudo chown ユーザー名:ユーザー名 -R remote-wsl-loc.txt
権限がユーザーに変更できたので、再度code .で実行すると起動できた。
Excel VBAでOutlookの未読メールのみ処理をするテンプレート

# はじめに
タイトル通りの記事です。
検索するとGetDefaultFolderが多かったのですが、それ以外のフォルダで処理したい人に向けて記事にしました。
ついでに、未読メールのみ、新着順で処理するようにしてあります。

# ソースコード
```vb:template.vba
Sub test()
    Dim OutLookObject As New Outlook.Application
    Dim myNamespace As Outlook.Namespace
    Dim myFolder As Folder
    Dim n As Integer
    Dim oItem As Object
    Dim objItems As Items

    Set myNamespace = OutLookObject.GetNamespace("MAPI")
    Set myFolder = myNamespace.Folders("user@template.jp").Folders.Item("受信トレイ")
    Set objItems = myFolder.Items
    objItems.Sort "[受信日時]", True    '新着順でソート
    
    n = 0   '処理件数
    
    For Each oItem In objItems
        If oItem.UnRead = True Then
            oItem.UnRead = False
            n = n + 1   '処理件数をカウントアップ
            'メールの処理
            With oItem
                Debug.Print .ReceivedTime & ":" & .SenderName & ":" & .Subject
            End With
            '終了判定
            If myFolder.UnReadItemCount = n Then
                MsgBox "終わり"
                Exit For
            End If
        End If
    Next oItem
    
End Sub
```

# UnreadItemCountについて
Folder.UnreadプロパティをFalseにすることでUnreadItemCountも変化すると思ったのですが、どうやらそうではなかったようです。苦肉の策、と言うほどではないのですが、処理件数用の変数を用意して、すべての未読メールを処理したタイミングで処理を抜けるようにしておきました。
SQLの命令体系について

# この記事を書くにあたって
SQLについて学習を始めました。基礎的なことなのですが、学んだことをQiitaにOUTPUTさせてもらいます。

# はじめに
ほとんどのデータ操作を「SELECT」「UPDATE」「DELETE」「INSERT」の4つの命令文で実行することが出来ます。
この4つのデータ操作を「DML」（Date Mnipulation Language）と総称されてる。
頻繁に使用するのはこの4つですが、この4つの命令文に様々な修飾語を付与することで複雑なデータ操作を可能にしているのがSQL言語です。
今回はこの「DML」について簡潔に説明を書いていきたいと思います。

# 4つの命令文（DML）に」ついて
## SELECT
SELECT文はテーブルから目的のデータを指定して取得する命令です。
```sql:例
SELECT --列名
FROM --テーブル名
```
## UPDATE
UPDATE文はすでにテーブルに存在しているデータを書き換えるための命令です。
```sql:例
UPDATE /*テーブル名*/
FROM /*列名*/　= /*変更したい値*/
WHERE　/*列名*/ = /*変更したい値が存在する行*/
```
「WHERE」を使用しなかった場合、「FROM」で選択した列全てに書き換えたい値が入ってしまう。
なので「WHERE」を記述しないUPDATE文はあまり使わない。
## DELETE
DELETE文はすでに存在している行を削除する命令です。
```sql:例
DELETE
FROM /*テーブル名*/
WHERE　/*列名*/ = /*削除したい行*/
```
「WHERE」を使用しなかった場合、テーブル内の全データを削除してしまうので注意しなければならない。
## INSERT
INSERT文はテーブルに新しいデータを追加するための命令です。
```sql:例
INSERT　INTO　/*テーブル名*/
           (/*列名１*/, /*列名２*/, /*列名３*/)
VALUES (/*値１*/, /*値２*/, /*値３*/)
```
上の例では、2行目で指定した列に3行目で指定した値が追加されます。
列名1には値1が入り、列名2には値2が入り、列名3には値3が入ります。

# 終わりに
今回は4つの命令について簡単に説明をする記事を書いてみました。
この命令を説明するにあたって出てきた「FROM」や「WHERE」の説明を、またQiitaでOUTPUTしていきたいと思います。