OmniAICreator/Qiita-1.07M huggingface dataset:
DNSサーバーって何？

「[ブラウザにwebページが表示されるまで](https://qiita.com/blueray777/items/90c727c1d721c6cc1389)」を纏めたので、
DNSサーバーについても纏めてみた。

## DNSとはなんぞや？
DNSは「ドメインネームシステム（Domain Name System）」の略。
ドメインとIPアドレスをリンクさせるシステムのこと。
人が使う言葉で書かれた住所 (ドメイン名) とネットワーク上にあるコンピュータ (WebやメールサーバーのIPアドレス) の間で、翻訳機としての役割があるとも言える。

## DNSサーバーの仕組み
Webサイトをブラウザで観覧するには、URLにアクセスしてWebサーバーからデータを取得する必要がある。
人間はIPアドレスを覚えるのが大変なので、IPアドレスを人間が分かりやすく覚えやすいアルファベット表記にした「ドメイン」と紐付けて使用している。
だけど、Webサーバーの場所は「IPアドレス」というネットワーク上の機器を識別するための識別番号を探す必要があるので、
DNSサーバーを使って、ドメインと紐づいているIPアドレスを探してWebサーバーにアクセスしている。

## DNSキャッシュ
ドメイン名に対応するIPアドレス情報が一時的に保存されている状態のこと。

## DNSキャッシュサーバー
クライアントから問い合わせがあったドメイン名に対応するIPアドレス情報を一定時間保存しておくサーバー。
クライアントからドメインの問い合わせがあった際、DNSキャッシュサーバーに情報が保存されていたら、DNSルートサーバーにアクセスせずにIPアドレスをクライアントに返す。
以下の役割のために、DNSルートサーバーへのアクセスの前にDNSキャッシュサーバーにアクセスする。
1. DNSルートサーバーの負担を軽減させる
2. DNSサーバーの仕組み全体の高速化

## DNSルートサーバー
DNSキャッシュサーバーが最初に問い合わせをするサーバー。ドメイン名空間の頂点にある情報を保持する。世界に13台しかない。
トップレベルドメイン部分の名前解決を担当する。
- [DNSルートサーバー一覧（Wikipedia）](https://ja.wikipedia.org/wiki/%E3%83%AB%E3%83%BC%E3%83%88%E3%82%B5%E3%83%BC%E3%83%90#%E3%83%AB%E3%83%BC%E3%83%88%E3%82%B5%E3%83%BC%E3%83%90%E4%B8%80%E8%A6%A7)


## 参照
- [【図解】DNSサーバーとは？設定・変更と確認方法](https://www.kagoya.jp/howto/it-glossary/domain/dns-server/)
- [ルートサーバ（Wikipedia）](https://ja.wikipedia.org/wiki/%E3%83%AB%E3%83%BC%E3%83%88%E3%82%B5%E3%83%BC%E3%83%90)
TerraformでCodepipelineの検出オプションを変更する

TerraformでCodePipelineを構築していて、ソースステージの「ソースコードの変更時にパイプラインを開始する」を「無効」にする方法がわからなかったので調べた結果を書きます

![detect_changes.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1219565/0e874e03-d81d-108a-1e4e-6a89ca57ae15.png)


## 結論
* ``DetectChanges = "false" `` でできました

## 確認までの流れ
- [公式サイトのCodepipeline](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/codepipeline)の定義を見るが明記されていない
- さらにAWSの[CodePipeline pipeline structure reference](https://docs.aws.amazon.com/codepipeline/latest/userguide/reference-pipeline-structure.html#action-requirements)の定義を確認
- ``PollForSourceChanges``というキーワードがあるが、これを指定してもterraformで存在しないエラーとなる
- AWSマネジメントコンソールでCodePipelineを適当に作り、terraformerで設定値を確認して、``DetectChanges = "false"``があることを確認

## terraformerで設定値確認
- terraformerで確認すると存在した

```bash:terraformer
terraformer import aws --resources=codepipeline  --regions=ap-northeast-1 --profile=default
```
```terraform:generated/aws/codepipeline/codepipeline.tf
  stage {
    action {
      category = "Source"

      configuration = {
        BranchName           = "mybranchname"
        ConnectionArn        = "arn:aws:codestar-connections:ap-northeast-1:xxxxxxxxxxxx:connection/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
        DetectChanges        = "false"
        FullRepositoryId     = "owner/reponame"
        OutputArtifactFormat = "CODE_ZIP"
      }
```

## メモ
- ``DetectChange``を省略した時の``.tfstate``には、``DetectChanges``はなかった
```bash:terraform state pull
$ terraform state pull > ./terraform.tfstate.current
```
```json:terraform.tfstate.current
"stage": [
    {
    "action": [
        {
        "category": "Source",
        "configuration": {
            "BranchName": "mybranchname",
            "ConnectionArn": "arn:aws:codestar-connections:ap-northeast-1:xxxxxxxxxxxx:connection/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
            "FullRepositoryId": "owner/reponame",
            "OutputArtifactFormat": "CODE_ZIP"
        },
```
公開鍵認証方式について

鍵という名前がついてはいるが、実際はただのファイルである。
公開鍵は南京錠、秘密鍵は南京錠を開ける鍵だと考えるとわかりやすい。
![ビットマップ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353901/8b819677-1d1a-1813-e58b-c18a5a31b686.png)

公開鍵を渡されたコンピュータはその公開鍵(南京錠)を使ってデータを暗号化(ロック)する。
そしてその暗号化されたデータを復号できるのは自分のPCが持っている秘密鍵のみ。

![公開鍵認証.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353901/202f2bcd-d055-6de7-9a8d-c60a2aa69b09.png)



公開鍵はその名の通り公開しても問題はない。むしろ公開するためにある。
暗号化してデータをやりとりしたい相手に渡すのが公開鍵で、公開鍵を渡された相手は自分にデータを暗号化して送ることができるようになる。
一方秘密鍵は、絶対に漏らしては行けない。

これが漏れてしまうと、自分が公開鍵を渡した相手が暗号化したデータを盗みとられた秘密鍵で復号できてしまう。
つまりデータを盗み見ることが可能になる。
仕事において生産性が低くなる原因

仕事において、生産性が低くなる原因について書いてみました。
ここでいう「生産性が低い」とは、時間に対する成果が乏しいことを指します。

## ■同じことを何度も考えている。堂々巡り状態

例えば何か問題が起きたときに、
案Aを考える→ダメだった→
案Bを考える→ダメだった→
案Cを考える→ダメだった→
案Aをもう一回考えてみるかあ、がループするイメージです。

質問や相談をせずに自分で長時間ずっと考えている状態は、殆どが堂々巡り状態です。
「考えている」というよりかは、「悩んでいる」が正確でしょう。

岡目八目で、人に聞いてみると、意外と簡単に解決する場合があります。

## ■手戻り、やり直しが多い。認識合わせ不足

これは自由度が高いタスクや、クリエイティブ系で起きやすいです。
「こんなイメージではなかった」「思っていたのとかなり違う」。それは単純に時間の浪費です。

改善策としては、「2割共有」が推奨されます。
少し進めてみて、「こんな感じです」とざっくりと相手に伝え、方向性を確認することが大切です。たとえ結果として方向性の認識が合っていたとしても、確認というアクションをすることで心理的な安全性が生まれます。

このとき、変にかっこつけず、自分のありのままの考えを伝えることです。しっかりときれいに整理してから共有しようと考えていると、あっという間に時間が経ってしまいます。

## ■なんでもかんでも自分でやってしまおうとする

これは個人というよりもチームとしての生産性に関わる話ですね。

前提として、タスクの割り込みや緊急発生が頻発している職場については、構造的に問題がある気はしており、それは個人で解決することは難しいです。

その上で個人のアクションとして、タスクを二つ返事でどんどん引き受けてしまうと、大抵の場合パンクします。それは適切なタスク配分ができている状態ではありません。

特に、チームで仕事をしているときに怖いのは、キーマンが多忙であることがチーム全体のボトルネックになることです。（特にリーダー、管理職はそうなりがちであり、リーダーに相談したいのに、リーダーが多忙なために何も話せない、という悪循環が発生するとこれはもう最悪です。）

特に割り込みタスクを引き受けるときは、リーダーに確認し、安請け合いをしないようにしましょう。
とはいえ、チームの体制や構造に限界がある場合は、率直に言ってどうしようもないと思います。割り込みタスクが入らないように、なるべく一人キリになって作業する、というくらいが防衛策でしょうか。

## ■知識や技術が不足しているために、最適な方法をわかっていない

特にITエンジニアで経験が浅い人の場合、もっと良い手段があるのに、知識や技術がないために非効率な方法で進めてしまうことが多々あります。

例えば、テスト用の巨大な入力ファイルを、スクリプトで作成すればいいところ、「手動でちまちま」作るなどです。他には、データの解析でExcelやサクラエディタ等の使い方を知らないが故の遠回りをしている場合があります。極端な話としては、ショートカットキーをまともに使えていないパターンです。

周りに親切な先輩がいれば、「こんな方法があるよ」と教えてくれるでしょうけど、このあたりの知識は体系的にまとめてある書籍やサイトは少ないですし、見つけづらいです。

特に経験が浅いうちは、「今行っている作業を効率よくする方法はないか？」を、常に考えて検索する意識が必要です。
自分が「こんなことできないかなあ」「こんな機能ほしいなあ」と思ったならば、既に誰かが同じことを思っているはずなのです。特にITエンジニアにはその精神が必要です。


## ■タスクの明確なゴールがわかっていない

生産性が低くなる原因として書いている中で、最も危険なパターンです。
自分が何をすべきなのか、実はよくわかっていない状態では、自分の行動が正解であるのかを図る物差しがありません。「これでいいのかなぁ」という不安と同居しながらの業務は、確実に生産性が低くなります。というよりも、やる気が上がることが絶対にありません。

これは放置していては必ず状況は悪化します。一刻も早く誰かに確認しましょう。

----------------------------------------------------

以上です。
ubuntu20 LEMPP phpmyadmin 

install.sh
```
# ufw(ファイアウォール)をインストール
sudo apt install ufw

# インストール直後はufwはファイアウォールとして指定されないためufwを有効化「このコマンドを実行するとssh接続が切れるかも知れませんがいいですか？」と聞かれるので y を入力してEnter
sudo ufw enable

# sshのポートを開く
# これを行わないとssh切断したあと接続出来なくなってしまいます！
sudo ufw allow 22

# nginxを使用するポートを開く
sudo ufw allow 80

```
sudo chmod u+x install.sh
sudo ./install.sh

sudo vi LEMPP.sh

```bssh
sudo apt-get install -y php php-intl php-mbstring php-mysql php-gd php-xml
sudo apt-get install -y php-fpm php-curl php-common php-json php-mbstring php-zip php-xml php-tokenizer
sudo apt-get install -y mysql-server
sudo apt install -y sqlite3
sudo apt install php7.4 
sudo apt install php7.4-fpm
sudo apt-get install -y nginx
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install npm
sudo pip3 install uwsgi
sudo apt-get install python3 
sudo apt install python3-pip
sudo apt-get install python3-dev default-libmysqlclient-dev
sudo pip3 install mysqlclient
sudo pip3 install django


```
sudo chmod u+x LEMPP.sh
sudo ./LEMPP.sh

nginxの設定

```
sudo systemctl start nginx
sudo systemctl enable nginx
sudo systemctl restart nginx
sudo systemctl status nginx 
sudo systemctl is-enabled nginx
sudo systemctl restart nginx
sudo systemctl status php7.4-fpm
sudo systemctl is-enabled php7.4-fpm
sudo systemctl restart php7.4-fpm
sudo apt install php php-mysql php-fpm
sudo nginx -t
sudo systemctl restart nginx
echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/info.php

```

14.ブラウザで、次のアドレスを使用してナビゲートします。次のスクリーンショットに示すように、PHP構成ページが読み込まれます。
点線部内のように設定する
http://IP/info.php

webサーバーはescキーでエスケープし、DB設定のみいいえで次へ進む。

---------------------------------
```
sudo apt-get install phpmyadmin
sudo systemctl status php7.4-fpm
sudo systemctl is-enabled php7.4-fpm

sudo vi /etc/nginx/sites-available/default
---------------------------------


           # Add index.php to the list if you are using PHP
        index index.php index.html index.htm index.nginx-debian.html;

        server_name _;

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;
        }

        # pass PHP scripts to FastCGI server
        #
        location ~ \.php$ {
                include snippets/fastcgi-php.conf;
        #
        #       # With php-fpm (or other unix sockets):
                fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        #       # With php-cgi (or other tcp sockets):
        #       fastcgi_pass 127.0.0.1:9000;
        }

---------------------------------

#設定
sudo nginx -t
sudo systemctl restart nginx
sudo ln -s  /usr/share/phpmyadmin /var/www/html/phpmyadmin
sudo chmod 775 -R /usr/share/phpmyadmin/
sudo chown root:www-data -R /usr/share/phpmyadmin/

http://SERVER_IP/phpmyadmin
PC Keibaでセットアップデータの登録に失敗する

jra-data labのデータをpostgresqlに登録できるPC Keibaというアプリがある。

初期登録時にセットアップデータを登録するが、
「中央ディレクトリの終わりレコードが見つかりません。」
のようなエラーが出る場合がある。
zipファイルの解凍か読み込みに失敗している様子。

# 結論から先に言うと

AppData\Roaming\PC-KEIBA Database\setupdata
にzipファイルがあるのですべて削除してから再実行する。

AppDataのディレクトリの位置: https://novlog.me/win/win10-appdata/

# こんな感じのエラーがでる
引用元: データダウンロード中のエラー (PC Keiba Forum)

https://pc-keiba.com/wp/forums/topic/%E3%83%87%E3%83%BC%E3%82%BF%E3%83%80%E3%82%A6%E3%83%B3%E3%83%AD%E3%83%BC%E3%83%89%E4%B8%AD%E3%81%AE%E3%82%A8%E3%83%A9%E3%83%BC/
````
場所 System.IO.Compression.ZipArchive.ReadEndOfCentralDirectory()
場所 System.IO.Compression.ZipArchive.Init(Stream stream, ZipArchiveMode mode, Boolean leaveOpen)
場所 System.IO.Compression.ZipArchive..ctor(Stream stream, ZipArchiveMode mode, Boolean leaveOpen, Encoding entryNameEncoding)
場所 System.IO.Compression.ZipFile.Open(String archiveFileName, ZipArchiveMode mode, Encoding entryNameEncoding)
場所 System.IO.Compression.ZipFile.ExtractToDirectory(String sourceArchiveFileName, String destinationDirectoryName, Encoding entryNameEncoding)
場所 System.IO.Compression.ZipFile.ExtractToDirectory(String sourceArchiveFileName, String destinationDirectoryName)
場所 Com.Pckeiba.Database.Forms.SetupDataToroku2Form.<>c__DisplayClass18_0.<JVGets1>b__0()
場所 System.Threading.Tasks.Task.InnerInvoke()
場所 System.Threading.Tasks.Task.Execute()
...
```
SSHトンネルによる安心RDP〜Remminaを添えて〜

# About
グローバルネット上のPCにリモートデスクトップ（RDP）をするときは、SSHトンネルして接続するのがセキュリティ上よい、と言われています。

RDPするときよく使われるアプリ「xrdp」ですが、こちらは認証がパスワードであるためセキュリティへの懸念が生まれます。そういったときSSHを通してRDPすればSSHで接続するため公開鍵暗号を使うことができ、セキュリティを向上させることができます。

このようにSSHを通して何らかの通信を行うことを**SSHトンネル**と呼ばれています。

ここではUbuntuでSSHやRDPするときによく使われるRemminaを用いてSSHトンネルをする方法をご紹介します。

対象者はクライアントのPCにUbuntuを使っている人です。

もう既出っぽそうだけど、、、自分のときは見つけられなかったので。。。

# やり方
## 1. Connection Profileを追加
Remminaでは接続するための設定を「Connection Profile」と呼んでおり、次の画像で示したボタンから追加することができます。

![Screenshot from 2022-03-12 17-29-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665043/bd7db294-8912-d480-96f8-908f3e8584ef.png)

ボタンを押すと次のようなウィンドウが開きます。

![Screenshot from 2022-03-12 17-28-46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665043/0bb07e43-d344-6d43-e403-6419499b02dd.png)

この画面のServer、Username、PasswordにRDPするときの設定を入れておきましょう。

## 2. SSHトンネルの有効化
次に、開かれたウィンドウの中に「SSH Tunnel」というタブがあるので、そちらに切り替えます。

![Screenshot from 2022-03-12 17-36-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665043/a82ff544-4a62-10eb-d030-53c673d76c02.png)

ここで「Enable SSH tunnel」を押し、SSHトンネルを有効化します。あとは秘密鍵を設定したり、踏み台を通したり、適宜設定をしていくだけです。
Discord メッセージフォーマット一覧

# Discord メッセージフォーマット一覧
英語を読めるならこっち呼んだ方が早いです
[Discord Developer Portal — Documentation — Reference](https://discord.com/developers/docs/reference#message-formatting)

## はじめに
Discordのメッセージには特定のフォーマットが存在します。例えば、メンションやロールの指定、タイムスタンプの表示などが可能です。しかし、Botを使用すると通常のメンションが `@USER` のような文字列になってしまうことがあります。

本記事では、Discordのメッセージフォーマットの一覧を紹介し、最後に絵文字やカスタム絵文字のフォーマットを取得する方法も説明します。

## メッセージのフォーマット
| タイプ                             | 構造                    | 使用例                          |
| :--------------------------------: | :---------------------: | :-----------------------------: |
| ユーザー                           | `<@ID>`                  | `<@80351110224678912>`          |
| ユーザー(ニックネーム)             | `<@!ID>`                 | `<@!80351110224678912>`         |
| チャンネル                         | `<#ID>`                  | `<#103735883630395392>`         |
| ロール                             | `<@&ID>`                 | `<@&165511591545143296>`        |
| スタンダード絵文字                 | Unicode Characters       | 💯                              |
| カスタム絵文字                     | `<:名前:ID>`             | `<:mmLol:216154654256398347>`  |
| カスタム絵文字(アニメ)             | `<a:名前:ID>`            | `<a:b1nzy:392938283556143104>` |
| スラッシュコマンド                 | `</名前:コマンドのid>`    | `</airhorn:816437322781949972>` |
| Unixタイムスタンプ                 | `<t:TIMESTAMP>`          | `<t:1618953630>`               |
| Unixタイムスタンプ（スタイルあり） | `<t:TIMESTAMP:STYLE>`    | `<t:1618953630:d>`             |

## タイムスタンプのスタイル

| スタイル | 出力例                    | 説明          |
| -------- | ------------------------- | ------------- |
| `t`      | 16:20                      | 短時間        |
| `T`      | 16:20:30                   | 長い時間      |
| `d`      | 20/04/2021                 | 短い日付      |
| `D`      | 2021年4月20日              | 長い日付      |
| `f`      | 2021年4月20日 16:20        | 短い日付/時間 |
| `F`      | 2021年4月20日 火曜日 16:20 | 長い日付/時間 |
| `R`      | 2ヶ月前                    | 相対時間      |

## メッセージフォーマットの取得方法
Discordのテキストボックスで `\`（バックスラッシュ）を入力した後に絵文字やカスタム絵文字を入力すると、以下のような形式で取得できます。

- 絵文字 → OSに搭載されている絵文字
- カスタム絵文字 → `<:名前:ID>`
- アニメーションカスタム絵文字 → `<a:名前:ID>`

これをコピーしてメッセージ内で使用することで、Botなどでも適切なフォーマットで表示可能になります。

---

以上、Discordのメッセージフォーマットについて紹介しました。ぜひ活用してみてください！
【自分用】gitコマンドまとめ

gitでcommitやpull、pushのような基本的な操作はマスターした初心者向けのコマンド一覧です。


## ローカルの変更を取り消す

```
git checkout .
```
新規追加したファイルは取り消されないので注意


## 直前のコミットの取り消し
### 変更ごと取り消す
直前の変更を取り消す

```
git reset --hard HEAD^
```

変更ごと無かったことになるので注意。

### コミットのみを取り消す(変更は取り消さない)

```
git reset --soft HEAD^
```
コミットのみを取り消すので変更はステージング状態に戻される。

:::note info
HEADの後の^は1つだと直前のコミット。^^のように2つつけると2つ分のコミットを取り消すことができる。
:::

### 直前のコミットのメッセージを変更する。
コミットした直後にメッセージの誤字脱字に気づくことがある。
そんなときはamendを使用します。
```
git commit --amend -m "直前のコミットメッセージを修正"
```



## stash関係
手元の変更を一時的に退避する。
```
git stash -u
```

対比した作業一覧を見る。
```
git stash list
```


stashした変更を元に戻す。
```
git stash pop # 最新のスタッシュを適用して、そのまま削除
git stahs pop stash@{0} # 特定の作業を選択して戻す。この場合はstash@{0}を指定している。
```

`git stash pop`でコンフリクトしたとき、なかったことにする。
```
git checkout --ours .
git reset
git checkout .
```


stash listの内容を全部削除する。
```
git stash clear
```

## コンフリクトしたとき
### 一旦元の状態に戻したい時
コンフリクトが起きてまだ何もしていない時。
```
git merge --abort
```
コンフリクト解消のために色々編集した時。
```
git reset --hard HEAD # 編集内容は消えるので注意
```

### 片方の変更だけを適用したい時
```
# マージさせたブランチ側を適用
git checkout --theirs .

# マージされるブランチ側(現在checkoutしているブランチ)を適用。
git checkout --ours .
```
## ブランチではなく特定のコミットをマージしたいとき
git cherry-pickを使う。
```
git cherry-pick [取り込むコミットID]
```
【Ruby】ぼっち演算子とその書き換え方

# ぼっち演算子`&.`


「レシーバがnilのときに起こるエラーを回避するため」に`.`の代わりに` &.`を使います。
レシーバがnilでもエラーにならず、nilを返してくれます。
    
```ruby
user = User.new
user.name # => "ユーザー名"
    
object = nil
object.name # => NoMethodError
object&.name # => nil
```

# ぼっち演算子を使わない書き方

ぼっち演算子は、if文や三項演算子で書き換えることができます。

```ruby
# ぼっち演算子
name = object&.name
```


```ruby
# ifを使った書き換え
name = if object
 	object.name
else
  	nil
end

# 三項演算子を使った書き換え
name = object ? object.name : nil
```

@scivola さんからご指摘いただきました。(追記: 2022/03/14)

この書き換え方だと、たしかに`object`が`nil`のときには`nil`を返してくれるのですが、`object`が`false`のときも`nil`を返してしまいます。
つまり、`false`によるエラー回避もしてしまっているわけです。

ぼっち演算子は「レシーバが`nil`のときでもエラーを出さない」だけですので、`false`に関しては挙動が変わらないはずです。

したがって、`nil?`で条件分岐をさせた書き換えのほうが、ぼっち演算子を正確に書き換えていると言えます。
```ruby
# ifを使った書き換え
name = if object.nil?
 	nil
else
  	object.name
end

# 三項演算子を使った書き換え
name = object.nil? ? nil : object.name
```

`false`によるエラー回避が必要な場面では修正前のコードを使ったほうがよい場面もあるかもしれません。
修正前のコードでも問題ない場面が多いとは思いますが、コードを理解することは大切です。。。勉強になりました！
【Golang】Ginを使ってフラッシュメッセージを表示させる

# はじめに
Ginでフラッシュメッセージを実装する情報があまり見つからなかったため、備忘録として残します。
コードが冗長的だったり、良い書き方ではなかったりするかもしれませんが、ご了承いただければと思います。

# フラッシュメッセージ機能の実装
フラッシュメッセージを表示させるために、Cookieに一時的に保存しすぐに削除することでリダイレクトされた時のみ表示するようにしています。

```golang:flash/flash.go
package flash

import (
	"github.com/gin-gonic/gin"
)

func SetFlash(c *gin.Context, status string, msg string) {
	c.SetCookie("Status", status, 1, "/", "localhost", true, true)
	c.SetCookie("Msg", msg, 1, "/", "localhost", true, true)
}

```
``Status``にはメッセージの種類（success,danger等)が入り、``Status``に応じて、CSSでフラッシュメッセージの背景色や文字色を変えています。
1秒だけCookieに情報を保存することで、フラッシュメッセージを実装しています。

`c.SetCookie()`については下記の記事がわかりやすかったです。

https://korattablog.com/2020/07/20/gin%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9Fgo-api%E9%96%8B%E7%99%BA%E3%81%AE%E5%88%9D%E6%AD%A9%EF%BC%88cookie%E7%B7%A8%EF%BC%89/

# 使い方

```golang:server/routers.go

func DefineRoutes(r gin.IRouter) {
	v1 := r.Group("/")
	{
		v1.GET("/", handler.GetStatic())
	}
	{
		v1.GET("/login", handler.GetLogin())
		v1.POST("/login", handler.PostLogin())
	}
}
```

```golang:handler/handler.go

func GetStatic() gin.HandlerFunc {
	return func(c *gin.Context) {
		status, _ := c.Cookie("Status")
		msg, _ := c.Cookie("Msg")
		c.HTML(200, "static/index.html", gin.H{"Title": "トップ","Status": status, "Msg": msg})
	}
}

func GetLogin() gin.HandlerFunc {
	return func(c *gin.Context) {
		c.HTML(200, "session/new.html", gin.H{"Title": "ログイン"})
	}
}

func PostLogin() gin.HandlerFunc {
	return func(c *gin.Context) {
　　　　　　　　　　　　　　　　//ログイン処理

		flash.SetFlash(c, "success", "ログインしました")
		c.Redirect(302, "/")
	}
}
```

HTMLではフラッシュメッセージがある時のみ、表示するようにしています。

```html:static/index.html
{{if .Msg}}
	<div class="alert">
		<div class="alert__{{.Status}}">
			<p>{{.Msg}}</p>
		</div>
	</div>
{{end}}
```
拡張機能を無効化しても重いVS Codeを軽かった頃に戻す方法

# 概要

長いことバージョンアップを繰り返しながらVS Codeを使ってきて、最近、小さなテキストファイルですら開くのに5秒かかるとか、やたらと重くなっていた。
拡張機能の起動数を減らしてもダメ、再インストールしてもダメ。
で、それの根本解決したときのメモ。
OSはWin10です。

# 手順

##### 1. 設定を退避

[ユーザーのフォルダー]¥AppData¥Roaming¥Code¥User¥settings.json
をどこかにコピーして退避。

##### 2. アンインストール

普通にアプリ一覧からアンインストール
(2022/9/14追記: アンインストールしなくても結構効果ありそうです。)

##### 3. ユーザーデータを削除

[ユーザーのフォルダー]¥AppData¥Roaming¥Code
をゴミ箱にポイ
（念のため、Roamingフォルダにあった、Visual Studio Codeフォルダも捨てました。中身は短いログ一個だけだったので、特に影響無いと思う。）

##### 4. 再インストール

公式からダウンロードしてきて、普通にインストールして起動


##### 5. 症状が収まった事を確認し設定を戻す

テキストファイル開いてみて、直ってるのを確認。
いったんVS Codeを閉じて、元の設定ファイルで上書き → 再度起動

なぜかこれで、元々使ってた拡張機能も勝手にインストールされてました。
「4」で起動する前に、退避してた設定ファイルを上書きしても、大丈夫だと思います。

##### (2022/9/14追記:参考)

以下も参考にどうぞ。
https://zenn.dev/korinvr/articles/vscode-performance
「Developer: Startup Performance」で、起動のどこに時間がかかったか、解析してくれるようです（単位はミリ秒っぽい）。
「Performance Marks」「Extension Activation Stats」「Extension」では「Duration」がその項目にかかった時間で、単位はミリ秒っぽい。
一部詳細は次以降の項目に記載されています。
「## Raw Perf Marks: main」以降の項目「Delta」がその項目にかかった時間、「Total」がそのくくりの累積時間（単位はマイクロ秒っぽい）なので・・・
累積がいきなり大きくなった所の「Delta」を見ると、そこに何マイクロ秒かかったか分かります。
(キーボードの)配列をつくった

## 概要
NICOLAの亜種。
中指、親指、小指でシフトする同時打鍵方式。

単独打鍵と中指シフト（D/Kキー）で大半の文字をカバーしている。
親指シフト（スペースキー）は濁音の入力用、小指シフト（A/セミコロンキー）は主に小書き文字の入力用とした。

http://cf444409.cloudfree.jp/
![hitsuj.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2593534/d2328fd7-f4a7-e82b-471d-72639d6032e7.png)

## 入力例
<dl>
  <dt>「いぬ」と入力したいとき：</dt>
  <dd>1. K を単独で押す</dd>
  <dd>2. K と Q を同時押し</dd>
</dl>
<dl>
  <dt>「ぎゃく」と入力したいとき：</dt>
  <dd>1. スペース と I を同時押し</dd>
  <dd>2. S と ; を同時押し</dd>
  <dd>3. D と K を同時押し</dd>
</dl>

## つくった経緯とか
その昔、ローマ字入力より早くて楽ということで使い始めたNICOLA(親指シフト)だったけど、これには致命的な欠陥があることに気づく。だましだまし使って気にしないフリをしていても、避けて通れないのが親指のボジション問題だ。

一般に親指シフトするときは、左親指をスペースキー、右手親指を変換キーに置くのが普通だと思う。スペースキーの幅が小さいキーボードならマシかもしれないけど、そうでないと右親指がとても窮屈に感じる。
複数PCを使い分けることがある場合、いちいちキーボードの形状が気になるし、最適な専用キーボードを見つけてもそれを常に持ち歩くなんて馬鹿らしいことはやってられない。orz配列なるものを発見したときはこれで救われるかと思ったけど、かな/英数切り替えのたびにポジションを戻さないといけなかったりするのが地味に煩わしい。
親指を使わない新下駄配列がいいかもと思って試してみると、結構な期間がんばったのに、どうも中指と薬指の動きが混線するようで快適に扱えず、これは自分には無理だった。

そんなわけで、自分で配列をつくってみた。
ふつうのキーボードで使える汎用性があって、JP/USキーボードどちらでも困らないものを目指した。
求めていた原型として近いのは姫踊子草かな配列だったように思う（導入のハードルが高くて諦めた気がする）。
ただ一番快適に日本語入力できる気がしたのが蜂蜜小梅配列だったので、文字の並びはこちらを土台にさせていただいた。というかほぼ丸パクリした。本当にありがとうございます。
別に高速文字入力がしたいわけではなく、一度親指シフトを覚えたせいでもうローマ字入力には戻れない体になっただけなので、ローマ字入力よりマシならいっかというレベルを落し所にした妥協の産物でもある。拗音拡張だったり特定文字列のショートカットだったりはなんか覚えにくかったし、面倒だったので全部削った。実際なくてそんなに困らないし、むしろ複数の入力方法があるという選択肢をなくしたぶんわかりやすくなってよかったと思う。必要なら一応カスタマイズできる余地もあるし。

とりあえず Windows, macOS, Linux で使えるようにした。ちょっと適当な部分もあるけど、普段使いの日本語入力をするのに問題ないと思う。
UserAgentを用いた端末判定で、Chromeディベロッパーツールでのデバック時の注意点

# はじめに
以下のように、UserAgentの文字列を判定してユーザーの端末を判定することがよくある。
```php
<?php
    $ua = $_SERVER['HTTP_USER_AGENT'];

    if ((strpos($ua, 'Android') !== false) && (strpos($ua, 'Mobile') !== false) ||
      (strpos($ua, 'iPhone') !== false)) {
      //SPの場合
      
    } elseif ((strpos($ua, 'Android') !== false) || (strpos($ua, 'iPad') !== false)) {
      //TBの場合
      
    } else {
      //PCの場合
      }
  ?>
```

Google Chromeのディベロッパーツールのデバイスモードで使用デバイスを変更しながら動作確認を行なっていたところ、**「Responsive」モードでPCが返ってくることを期待したがSPの処理が返ってきた。**

この時、NetworkタブでリクエストのUserAgentを確認したところ、以下のようになっていた。
![スクリーンショット 2022-03-12 16.36.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/312111/6cca3b0f-d5de-0d90-6c78-3730bb713406.png)
```
user-agent: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Mobile Safari/537.36
```
「Android」と「Mobile」が入っているのでSP判定になっていた。
# 任意のUserAgentに変更する
右上の「︙」アイコン → More tools → Network conditions → User agent を編集
![スクリーンショット 2022-03-12 16.47.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/312111/5b2e05d0-b88b-1f7f-95be-6994d9d3b598.png)
![スクリーンショット 2022-03-12 16.52.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/312111/16d97d8d-4854-245b-b8c6-61f68d872a3e.png)
再読み込みをすると、「Android」と「Mobile」が消えており、指定したUserAgentになっていたので動作確認ができた。
```
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36
```
クラスについて

## クラスについて

概要
クラスとはオブジェクトを作るための設計図のようなもので、 オブジェクト指向プログラミングの中心となるものです。

ポイント
クラス: オブジェクトを作るための設計図。
<font color="blue">sample text</font>
インスタンス: 設計図を基に作られた個々の実体。

例えば、

     public class Human 
     { 
         public int Id; 
         public int Age; 
     } 

でクラスを作って、

    Human model = new Human(); 

でインスタンスを作る。

構造体との違いは「値型」か「参照型」か、継承できるかどうか。

クラスとインスタンス
「オブジェクト指向とは」で述べたように、 操作の対象となるものをオブジェクトといいます。 オブジェクトを作る場合、まず設計図が必要になります。 内部がどういう構造になっているのか、外部からどのような操作をすることが出来るのかを決めてやるわけです。 このようなオブジェクトの設計図のことをクラス(class)といいます。 それに対し、設計図を元に作られたオブジェクトの実体のことをインスタンス(instance)といいます。

**クラスの利用**
---
クラスを利用するためには、 インスタンスを作成しなければなりません。 そのためにまず、インスタンスを格納するための変数を定義します。 変数定義の仕方は以下のような構文になります。

    クラス名 変数名;

次に、new キーワードでインスタンスを作成し、用意した変数に格納します。

ここで注意すべきことは、C# において、変数というのはただの入れ物であって、 変数を宣言しただけではインスタンスは作成されません。 （空っぽの入れ物だけができる。） 以下のように、new して始めてインスタンスが生成されます。

    SampleClass className = new SampleClass();


そして、以下のように変数の後に「 . 」で区切ってメンバー名を書くことでメンバー変数やメンバー関数を利用できます。

    className.SampleMethod();
ASP.Net Core 公式チュートリアル実施中における躓きと解決策

# チュートリアル開始時点の筆者状況
次年度よりASP.Netを用いたWebアプリケーション開発プロジェクトへの参画が決まっている状態。
C#を用いた業務アプリケーションのMVVM開発経験はあるもののMVC開発の経験は無いため、
概要から学習しておきたいと思い公式チュートリアルに手を出し始める。

実施対象チュートリアル
https://docs.microsoft.com/ja-jp/aspnet/core/?view=aspnetcore-6.0

# チュートリアル: ASP.NET Core の概要
https://docs.microsoft.com/ja-jp/aspnet/core/getting-started/?view=aspnetcore-6.0&tabs=windows
## 「アプリを実行する」の躓き
公式チュートリアルでは次のコマンドを実行し、アプリが開始されたら[https://localhost:5001](https://localhost:5001)を参照するよう記載されているが、
筆者環境では[https://localhost:7298](https://localhost:7298)でアプリが開始された。
```
cd aspnetcoreapp
dotnet watch run
```
## 「アプリを実行する」の解決策
aspnetcoreapp\Properties\launchSettings.jsonに以下の記載がある。
```
  "profiles": {
    "aspnetcoreapp": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "https://localhost:7298;http://localhost:5012",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
```
上記記載の内applicationUrlについて、
```
      "applicationUrl": "https://localhost:5001;http://localhost:5000",
```
と修正したところ、[https://localhost:5001](https://localhost:5001)でアプリが開始されるようになった。
**何故初期設定が7298となっていたのかは不明のため、今後調査の必要あり。**
# パート 2: ASP.NET Core で Razor ページ アプリにモデルを追加する
https://docs.microsoft.com/ja-jp/aspnet/core/tutorials/razor-pages/model?view=aspnetcore-6.0&tabs=visual-studio
## 「EF の移行機能を使用して初期データベース スキーマを作成する」の躓き
PMCで次のコマンドを入力する工程で、Update-Databaseでエラーが発生してしまう。
```
Add-Migration InitialCreate
Update-Database
```
発生するエラー文は以下の通り。
```
Microsoft.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SNI_PN11, error: 50 - Local Database Runtime error occurred. 自動インスタンスを作成できません。エラーの詳細については、Windows アプリケーション イベント ログを参照してください。
)
```
イベントビューアーには以下のエラーログが登録されていた。
```
Product: Microsoft SQL Server 2019 LocalDB  -- Error 1706. An installation package for the product Microsoft SQL Server 2019 LocalDB  cannot be found. Try the installation again using a valid copy of the installation package 'SqlLocalDB.msi'.
```
エラー文を読む限りでは、Microsoft SQL Server2019 LocalDBが見つからないため、PMCのコマンドが実行できていない模様。
"SqlLocalDB.msi"を探してインストールして再度「Update-Database」コマンドを実行すると、イベントビューアーに以下のエラーが表示されるようになった。
```
Windows API 呼び出し RegOpenKeyExW はエラー コードを返しました: 2。Windows システム エラー メッセージ: 指定されたファイルが見つかりません。
。行: 1035 での応答。 
LocalDB 親インスタンスのバージョンが無効です: MSSQL14E.LOCALDB
```
どうやらRegOpenKeyExWというWin32APIの呼び出し中にエラーが発生している模様。
「コンピューター\HKEY_CURRENT_USER\Software\Microsoft\Microsoft SQL Server\UserInstances」にLocalDBの情報が登録されているが、
このレジストリがうまく読み取れていないものと思われる。
## 「EF の移行機能を使用して初期データベース スキーマを作成する」の解決策
WindowsTerminalで、以下のコマンドを実行しインスタンスを作成後、再度「Update-Database」を実行することで解決。
```
>sqllocaldb delete MSSQLLocalDB
>sqllocaldb create MSSQLLocalDB
```
React: useRef [アウトプット全くしてこなかったのでアウトプットする013]

`useRef`は前の職場で使うことをほぼ禁止されていたのですが、今の職場では割と使っているので新鮮な気持ちでアウトプットしていきます。

以下は公式に書いてある文

> useRef は、.current プロパティが渡された引数 (initialValue) に初期化されているミュータブルな ref オブジェクトを返します。返されるオブジェクトはコンポーネントの存在期間全体にわたって存在し続けます。
よくあるユースケースは、子コンポーネントに命令型でアクセスするというものです

```tsx
import React, { useRef } from "react"

export default function App() {
  const inputEl = useRef<HTMLInputElement>(null);
  const onButtonClick = () => {
    // ボタンをクリックするとインプット属性にフォーカスがあたる
    if(!inputEl.current) return;
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}
```

https://codesandbox.io/s/floral-sun-ms224q?file=/src/App.tsx

普通はinput欄をクリックしないと、フォーカスが効かないのですが`useRef`を使うことでinput欄にアクセスすることができています。

![react-useRef.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660329/84935700-de89-4b4d-3bb1-316b77919db1.gif)

Just Nowでもくもくかいに参加しているのですが、一瞬どんな仕組みかわからなくなって
「どこでこのinput欄にアクセスしているのですか？」と隣に座っているベテランエンジニアさんに質問してみたところ

```tsx
const inputEl = useRef<HTMLInputElement>(null);
```

ここでuseRefの変数を作ってそれを

```tsx
<input ref={inputEl} type="text" />
```

ここに渡すことで紐つけているという答えをいただけました!!!

なるほど....

https://ja.reactjs.org/docs/hooks-reference.html#useref

強くなりたい!!!!!!!!!
5Gにおけるメタバース用リアルタイム通信の検討が3GPPで始まった。

# 3GPP Rel-18 iRTCW :immersive Real-time Communication for WebRTC

> NTTがFacebookと3GPPにメタバースっぽいStudy ItemをSA4で立ち上げてますね！
> https://twitter.com/nickel0/status/1502214142870323200

3GPPとは、5Gの端末・基地局・サービスの仕様を作っている団体です。
3GPPでメタバース！？　面白そう。

3GPPの原本はこちら↓
https://www.3gpp.org/ftp/tsg_sa/TSG_SA/TSGS_95E_Electronic_2022_03/Docs/SP-220241.zip

# 3行でまとめ
* Facebook(Meta)が筆頭著者で、没入型リアルタイムコミュニケーションの5G APIの仕様を作る
* リアルタイムで3D video、空間audio、端末のセンサーデータを扱うためのAPI
* 他にも、眼鏡タイプのAR/MR系の検討を3GPPで行っている。


# 以下詳細　
immersive Real-time Communication for WebRTCのWork Item読み解き
## 2.2 Parent Work Ietm
* FS_5GSTAR Study on 5G Glass-type AR/MR Devices

親のWork Item(検討課題的なもの）：眼鏡タイプのAR/MR (拡張現実とMixed Rreality)　面白そう。

## 2.3	Other related Work Items and dependencies
他の関連するwork item
AR/MR関連の検討課題が色々あって楽しそうです。

* Feasibility study on AR call
* Media capabilities of AR devices (to be agreed)
* Stage-2 work on generic AR/MR media architecture (to be agreed)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2311625/6939e8ce-f8dc-6b16-3b9e-c179d781342a.png)

## 3. Justification

**Metaverse**や、アプリ間でXRをするためには、MTSI(電話)に代わる新しいリアルタイムの音声/映像の伝送サービスが必要だよね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2311625/3ff37c40-dc2f-2a19-a1b4-f99af3ad7ff9.png)
* 要求に応じた帯域、遅延、エラー率、容量のリアルタイム通信
* 3rd partyのアプリとAPIで連携できる自由なモジュール
* 3D videoや空間audioなどのimmersive data

## 4 Objective
* 5Gの通信を外部に公開するためのAPIを作る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2311625/79c50b75-d851-4b08-b5aa-9d18c61d7dc9.png)

* 3D videoや空間audioのサポート/センサー情報の扱い
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2311625/70312f9a-1f04-f353-85f5-38a3ed36442b.png)

* camera/ miceの入力のパラメータ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2311625/1b3bc6d5-052e-6cc5-4dd6-a91a9e8b4b5f.png)

* 5GシステムのQoS(サービス品質）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2311625/d980b5ab-b96b-dc72-9f87-2e1f952d6cfc.png)

## 5. Expected output
　Enabler for Immersive Real-time Communication / kyunghun@fb.com

## 6. Supporting member
Facebook, Dolby, Qualcomm, Tencent, NTT　等
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2311625/c2104417-c694-8154-9a49-a938416ef201.png)

# SA4の参加者
https://www.3gpp.org/ftp/TSG_SA/WG4_CODEC/TSGS4_117-e/Report/EoM_1st_draft

Facebook Kim Joel
Dolby stefan.bruhn, Frederic.Gabin, brian.lee
Qualcomm Bouazizi	Imed, Chien	Wei-Jung, Lo Charles, 
Tencent: Dawkins	Spencer
NTT : Eitoku Haruka, Inoue	Yoshihiro, Morita	Naotaka, Suzuki	Rihito, Suzuki	Rihito
VMware Cloud on AWSを利用したL2延伸

# はじめに
[VMware Cloud on AWS](https://www.vmware.com/jp/products/vmc-on-aws.html)(以下VMC)というサービスをご存じでしょうか。VMCはAWS基盤を使いVMware社がサービスしているvSphere基盤です。AWSをVMware仮想基盤として利用できます。今までオンプレでvSphereを利用してきたユーザにとっては使いやすく、理解しやすい基盤と言えるでしょう。今回は、VMCについて私見を述べたいと思います。

# 利用料
VMCは実は結構高いです(笑)
価格は[ここ](https://cloud.vmware.com/jp/vmc-aws/pricing)で知ることができます。例えば、i3というタイプを東京リージョンに建てようと思うと1台あたり9.816382USD / hour(2022/3/5時点の価格)掛かりす。i3タイプのスペックは Intel Xeon E5-2686 v4 (Broadwell) 36core(72 thread)、512 GiBメモリ、15.2TB の NVMe 対応 SSD ベースのインスタンスストレージとなっています。計算すると年間85,992USDなので、115円/USD換算で約1,000万円となります。3年前払いで購入すれば50%オフになるので、年間500万円程度にはなりますが、それでも単なるハードウェアとして考えるとかなりの価格だと思います。
ただしこの価格には、vSphere、vSAN、NSX-T、vCenter Server、VMware HCXライセンス及びVMware グローバル サポート料が含まれております。当然、ハードウェア保守も込みです。DC代、電気代なども含まれます。さらに、vSphere基盤のアップデートも自動で行われます。そう言った運用費も含めると一概に高い訳ではないのですが、安くはない価格帯ですね。

# VMCの選びどころ
1. 季節性のあるワークロードで一時的に使いたい
普段はオンプレで稼働してるんだけど、キャンペーンを実施する1か月だけサーバを増強したいと言った用途ですね。オンプレがvSphere環境な場合、シームレスにつながるのでクローンを作ったりvMotionしたりが自由にできるとというメリットがあります。

2. DR目的で使いたい
普段は最小台数で稼働しておいていざという時に本番サイズでの稼働と言ったことも可能なので、DR目的には相性がいいです。ただし、本当に災害が起きた時は同じことを考える人がたくさんいると思うので、AWSのリソースひっ迫を考慮する必要があるかもしれません。

3. 延命したい
現在、オンプレでvSphere基盤を利用しているがDCを解約してクラウド化したい。しかしIPアドレスの変更などをして移行するには時間が足りない！と言った話を時々聞きます。まぁ、一番いいのはもっと前から計画的にクラウド化して行くことだとは思いますが、こういう切羽詰まった状況でL2延伸ができるVMCは選択肢としてアリだと思います。

# L2延伸時に留意点
VMCの大きな特徴としてL2延伸が上げられます。VMCの選びどころの3番で上げたような事情の場合、L2延伸はとても便利です。ただし、永遠に使うものではないということは肝に銘じて置いて頂きたいです。L2延伸を利用する場合の留意点を以下に上げます。
1. L2延伸は移行時のみ利用すべし
L2延伸は使おうと思えばずっと延伸したままに出来なくもないのですが、やるべきではないと考えます。理由としてはL2延伸してると言うことはオンプレ側に資産が残っているということであり、長期的にDC運用とAWS運用を並行して行うのはコスト的にもデメリットが大きいですし、せっかくクラウド化をしようとしてるのに足かせになるからです。もし、どうしてもオンプレに残す必要があるものがあるのであれば、それは別セグメントに移動するなりして、VMCのL2延伸は早めに切るべきだと考えます。

2. 別セグメントとの通信は一旦オンプレに戻る
L2延伸とはその名の通り同一セグメントをVMCまで引っ張っているので、セグメントを超えようとすると当然、GWを跨ぐ必要があります。GWがオンプレに残っていると一旦、オンプレに通信が渡り、その後、再びAWS側の別のセグメントへと言った構成になってしまいます。 ただし、HCXを使ったL2延伸を利用する場合は、同一SDDC内の別セグメントへの通信であれば、オンプレに通信を戻さず通信する機能があります。この機能はSDDC内に限った話なので、AWSネイティブなサービスを利用する時には使えません。例えば、RDSを使いたいと思った時、通信はVMC->オンプレGW->VMware Transit Connect(VTGW)->RDSと言った迂遠な通信になってしまいます。

# まとめ
VMCでL2延伸利用を検討する時は、制限事項を理解した上で移行時の一時的な手段として利用しましょう。

# 参考情報
* [オンプレミスからVMware Cloud on AWSへのネットワークL2延伸の選択肢](https://aws.amazon.com/jp/blogs/news/options-for-extending-layer-2-on-premises-networks-to-vmware-cloud-on-aws/)
* [VMware Cloud on AWSを利用したディザスタリカバリの設計上の考慮点](https://aws.amazon.com/jp/blogs/news/design-considerations-for-disaster-recovery-with-vmware-cloud-on-aws/)
KPT~ノンアジャイル現場での振り返り~

## 目的
振り返りを実施して課題を共有し、
改善すべきことを明確にする。

---

## KPTとは
Keep    （うまく行ったこと・継続すること）
Problem （問題）
Try     （問題に対して挑戦すること）

全員が付箋に意見を書き出し、
ホワイトボードで共有。

---
## イメージ

![スクリーンショット 2022-03-12 14.35.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314423/15f41797-c13b-4b1e-a134-e427819fefb2.png)

---

## KPTとアジャイル

アジャイル開発者の
アリスター・コックバーン氏がKPTが手法を発案。

##### アジャイルとは
>「俊敏な」「すばやい」という意味の英単語で、要求仕様の変更などに対 して、機敏かつ柔軟に対応するためのソフトウェア開発手法。従来は要求仕様を満たす詳細な設計を行ったうえで、プログラミング開発や試験工程に移行するウォーターフォールモデルと呼ばれる手法が主流だったが、この方法では、開発途中での仕様変更や修正が困難で、技術革新や企業環境の変化に即応することが難しくなった。アジャイルでは、仕様や設計の変更があることを前提に開発を進めていき、徐々にすり合わせや検証を重ねていくというアプローチをとる。  

出典　ASCII.jpデジタル用語辞典ASCII.jpデジタル用語辞典について　情報  

--- 
## 他のMTGとの違い　

- 全員参加・全員発言
- 少人数向き
- プロジェクト単位
- PDCAのCAを担当

---
## ルール例
- 一つの付箋に一つのこと
- KPTそれぞれ記入時間5分
- 説明時間一人3分まで
- 同じものが出たら付箋を重ねて纏める。
- Tryは他の人のProblemに対して記入しても良い。
--- 

### Let's try it
DDD: エンティティ [アウトプット全くしてこなかったのでアウトプットする012]

ドメイン駆動設計に本を何回読んでも自分が本当に理解しているかわからないのでアウトプットしていきます。

今回はEntityについて

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660329/18392b39-dcbf-2232-96db-5ee7b1486a9b.png)

Entityは英語で「***実体***」という意味です。

https://codezine.jp/article/detail/10038

> DDDにおける「エンティティ」とは一意なものを表現する概念です。一意であるため、長期にわたって変化できるオブジェクトとなります。例えば「社員」というエンティティの場合、社員番号で社員を一意に識別することで、同じ人物であることを把握し、住所や所属といった属性を適切に変更できます。なお、一意に識別して変更を管理する必要がないものは「値オブジェクト（6章にて紹介）」として取り扱います。

`同一性`というキーワードが肝になります。
同一性とはどう言ったものでしょうか？
例えば東京都北区赤羽株式会社という会社に1976年11月16日生まれで45歳の西村博之という人が2人いるとします。
会社内でこの2人を区別するためには`社員番号`が必要になります。
この社員番号があれば両者の違いを知ることができるようになります。
これがEntityの`同一性`という考え方です。

　Entityの性質
1. 可変である
1. 同じ属性であっても区別される
1. 同一性により区別される

2と3は`例えば東京都北区赤羽~`の文でわかりました。
1はどうでしょうか
1は例えば西村博之の名前が有吉弘行に改名されたとしても社員番号で同一性が担保されているため、変更、更新することができるということです。また体重でもそうです。もしこの人が70kgだとして、もし70.1kgになったら全く別の人ということになったら困ります。しかしEntityでは同一性があるおかげでこの可変ということが守られているということになるんですね。



### 参考

https://www.amazon.co.jp/%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E9%A7%86%E5%8B%95%E8%A8%AD%E8%A8%88%E5%85%A5%E9%96%80-%E3%83%9C%E3%83%88%E3%83%A0%E3%82%A2%E3%83%83%E3%83%97%E3%81%A7%E3%82%8F%E3%81%8B%E3%82%8B%EF%BC%81%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E9%A7%86%E5%8B%95%E8%A8%AD%E8%A8%88%E3%81%AE%E5%9F%BA%E6%9C%AC-%E6%88%90%E7%80%AC-%E5%85%81%E5%AE%A3-ebook/dp/B082WXZVPC/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1FDYH7GFND8AO&keywords=%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E9%A7%86%E5%8B%95&qid=1647066883&s=books&sprefix=%E5%AE%9F%E8%B7%B5%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E9%A7%86%E5%8B%95%2Cstripbooks%2C227&sr=1-1
【Amazon SageMaker Studio Lab】オンラインでPython/機械学習しよう(無料)

# はじめに

今回は昨年12月に使用開始になった**SageMaker Studio Lab**というサービスを触ったので紹介する。
なお、AWSのアカウントは不要なのでそこはご安心を。

- 動作環境
・ OS : Windows10 pro
・ ブラウザ : Chrome

# SageMaker Studio Labとは？
pythonを無料でオンライン実行できる環境である。
同類のサービスでは**Google Colaboratory**が有名である。

以下が公式のリリースブログである。

https://aws.amazon.com/jp/blogs/news/now-in-preview-amazon-sagemaker-studio-lab-a-free-service-to-learn-and-experiment-with-ml/

申し込みは以下から行え、私の時は1日後だったかに承認完了メールが届いて使用できるようになった。

https://studiolab.sagemaker.aws/

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373060/75d24279-f19e-b130-0975-9789ffabfbd5.png" width=60%>


↓はTOP画面。(CPUは12時間、GPUは4時間連続実行可能)

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373060/9401c9cc-1641-28e0-8558-52714600ba66.png" width=80%>


# Google Colab vs SageMaker Studio Lab

じゃあGoogle Colabでいいやん・・・と思った方へ。
私的に感じた違いをいくつか。

### 1.GPUスペック(SageMaker Studio Labの勝ち)
まずは(無料版)Google ColabだがGPUガチャこそあるものの、だいたい使用可能なGPUは`Tesla K80`クラスである。
一方のSageMaker Studio Labは以下のように`Tesla T4`となっていた。
よって明らかに無料で使用できるGPUはSageMaker Studio Labの方が性能がいい。
※ただし、連続使用時間は4時間なので、12時間のColabの方が長い

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373060/bb9c6085-2422-5415-9459-70441f74d7a6.png" width=70%>

なお色々調べたら、どうやらAWSのGPUインスタンスである`EC2 G4に該当するスペックが使用できる`模様。`

https://aws.amazon.com/jp/ec2/instance-types/g4/

### 2.ストレージ(SageMaker Studio Labの勝ち)
`永続ディスクとして15GBが準備`されている。(無料のGoogleドライブと同じ)
また基本Google ColabではGoogleドライブと連携しなくてはならないのに対して、
SageMaker Studio Labでは直接アップロード可能。(アップ速度は。。まぁ・・)

※セッション終了時に環境のスナップショットが作成されるため、その他も終了時点から再開が可能


### 3.ターミナル & 仮想環境(SageMaker Studio Labの勝ち)
まずはターミナルが使用できるのがSageMaker Studio Labの強み。※colabでは使用不可。
さらにデフォルトでcondaが入ってるので、いきなり仮想環境を構築可能。

※というより`デフォルトがbaseではなく、studiolabという仮想環境になっている`

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373060/6a500d87-101e-b024-0ea3-c1ace1772991.png" width=70%>

### 4.共有機能(Colabの勝ち)
残念ながらこれはGoogle Colabのみになる。
ここはGoogleさんならではなので仕方がないが・・

#  SageMaker Studio Labで仮想環境を適応させるには？？
`conda create`で仮想環境を作成後、ターミナルで以下のように打てばいい

```:ターミナル
conda activate sample_env(作成した仮想環境名)
conda install notebook ipykernel
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373060/b7388dc4-5834-db3d-946a-77d5da8f3507.png" width=70%>


すると。。。以下のように作成した仮想環境が選べるようになる。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373060/41328d49-ed82-7746-ac05-2a34cff21596.png" width=60%>

後は、普通にその仮想環境で色々インストールしてから色々使い始めるのがいいと思う

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373060/b3a8c30e-8771-ce3f-cbca-fbeb186d3a7e.png" width=70%>


※どうも提供環境の完全リセットはなさそうなので、必ず仮想環境を作成してからお試しするほうがいいと思う。
issueでここら辺の要望があるらしいが・・

https://github.com/aws/studio-lab-examples/issues/75


# さいごに

SageMaker Studio Labに関して記事にしてみたが、個人的にはColabより断然使いやすいので、ローカルGPUで回せないようなものはこれをうまく活用してみようと思う。
まだリリース後4か月たたないくらいなので、使用者は少ないかもだが十分試してみる価値はあると思う。
それでは今回はここまで。

・SageMaker Studio Labのサンプルコード集
https://github.com/aws/studio-lab-examples

・Google Colab vs SageMaker Studio Lab
https://blog.roboflow.com/sagemaker-studio-lab-vs-google-colab/
【Python】パーフェクトPython・Scrapyで詰まったところまとめ

## 背景
パーフェクトPythonをやっていた時に、エラーが発生したところを忘備録も兼ねて、まとめていきます。
今回は、17章のScrapyです。

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

## 内容
Scrapyを用いて、スクレイピングをしてみようというセクション。
本通りにすると、以下のエラーが発生した。

```
ModuleNotFoundError: No module named '_lzma'
```

lzmaモジュールがないよとのこと。
Google先生に確認したところ、以下の回答を得る。

- brewを使って、xz libraryをダウロードする。
- pyenvにて、再度Pythonをインストールする

【参考記事】
https://gist.github.com/iandanforth/f3ac42b0963bcbfdf56bb446e9f40a33

pyenv内には、_lzmaが存在していないようである。
そのため、以下のコマンドを実行した。

```
brew install xz

pyenv install [Python Version]

```
[Python Version]に関しては、ご自身のバージョンで書き換えてください。
three.jsをはじめて扱ってみた！（環境構築から）

最近流行っていると話題の３D系のthree.jsをやってみる！
以下からvercelで公開中！
https://three-js-tikyuu.vercel.app/

## 環境構築手順(いろいろあるみたい)

①このサイト（https://github.com/mrdoob/three.js/releases）からSouce code zip をダウンロードしてくる
②その中から、buildとjsmファイルをとってくる
こんな感じで準備してあげる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/756524/340670e2-6499-0814-9850-9d8da2c669e7.png)

## 三大要素

①シーン
②カメラ
PerspectiveCamera（視野角、アスペクト比、開始距離、終了距離）
③レンダラー

## しらべもの

- https://threejs.org/docs/index.html?q=geometry#api/en/geometries/SphereGeometry
Amazon DynamoDB 料金計算時のメモ

料金計算に登場する機能ごとの確認。

色々調べたが、ここのページに分かりやすく、まとまっていた。

https://aws.amazon.com/jp/dynamodb/pricing/

# テーブル単位のリソース
## [DynamoDB on-demand capacity](https://docs.aws.amazon.com/ja_jp/ja_jp/amazondynamodb/latest/developerguide/HowItWorks.ReadWriteCapacityMode.html)
オンデマンドモード。いわゆる都度課金。

* リクエストの予測が難しい
* いつデータができるか不明
* 実験プロジェクト

## [DynamoDB provisioned capacity](https://docs.aws.amazon.com/ja_jp/ja_jp/amazondynamodb/latest/developerguide/HowItWorks.ReadWriteCapacityMode.html)
プロビジョニングモード。計画型。

* 予測可能性が高い
* アクセススパイクがない
* 計画的な利用を矯正

# アクセス高速化
## [DynamoDB Accelerator (DAX) clusters](https://aws.amazon.com/jp/dynamodb/dax/)
DynamoDBのインメモリ。
もともと高速だが、マイクロ秒単位の応答時間を必要とする特定のユースケースで利用。

# トレーサビリティ
## [DynamoDB Streams](https://docs.aws.amazon.com/ja_jp/ja_jp/amazondynamodb/latest/developerguide/streamsmain.html)
時系列にStreamいわゆるキューにした変更履歴を受けとることができるようになる。
24時間で揮発する。

# DynamoDB change data capture
Kinesis Data Streams for DynamoDB？

# 運用
## [DynamoDB Backup and restore](https://docs.aws.amazon.com/ja_jp/ja_jp/amazondynamodb/latest/developerguide/Backups.html)
バックアップとリストア。DBなら必須。

オンデマンド方式、PITR方式のどちらをバックアップ方式とするか、もしくは併用するか検討。

### オンデマンドバックアップデータストレージ
任意タイミングのフルバックアップ。DB全体の容量。

### ポイントインタイムリカバリ (PITR) データストレージ
増分バックアップになるので、35日分のデータ登録・更新量を計算し、計上。

:::note
ポイントインタイムリカバリ
日々増分バックアップ。
過去 35 日間の任意の時点にテーブルを復元。
:::

### テーブル復元の料金


## [DynamoDB Data export to Amazon S3](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DataExport.html)

他のAWSサービスで読み取り可能な形式によるS3への出力が可能。
`Backup and restore`とは違う。
STM32L010と内蔵ADCで電圧をシリアルに出力 3.300Vまで (ソフトウェアシリアル)(Keil)



x Mbed2


目的
主にNJL7502L等の微小な電圧を測る。

説明
adcの値(4096)に6600掛けて8192で割ると3300にピッタリなる。



![o_con264.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/d0b4bd97-a721-7c1a-2c87-b260787b2f7d.jpeg)



```c++



//SER_V3300_1

//電圧

#include "mbed.h"

//10の割り算 0から1028までは、正しい。主に0から999
#define DVI10(n) ((n*205)>>11)

char ch_hex_a_b[16];
char *ch_hex_a(int x)
{

        int x_bk;

        //x=1234;//debug

        ch_hex_a_b[4] = 0;

        if     ( x >= 9000 ) { x = x - 9000;   ch_hex_a_b[0] = '9';    }
        else if( x >= 8000 ) { x = x - 8000;   ch_hex_a_b[0] = '8';    }
        else if( x >= 7000 ) { x = x - 7000;   ch_hex_a_b[0] = '7';    }
        else if( x >= 6000 ) { x = x - 6000;   ch_hex_a_b[0] = '6';    }
        else if( x >= 5000 ) { x = x - 5000;   ch_hex_a_b[0] = '5';    }
        else if( x >= 4000 ) { x = x - 4000;   ch_hex_a_b[0] = '4';    }
        else if( x >= 3000 ) { x = x - 3000;   ch_hex_a_b[0] = '3';    }
        else if( x >= 2000 ) { x = x - 2000;   ch_hex_a_b[0] = '2';    }
        else if( x >= 1000 ) { x = x - 1000;   ch_hex_a_b[0] = '1';    }
        else                 {                 ch_hex_a_b[0] = '0';    }

        x_bk = x;

        x     =  DVI10(x);                           // 12 <- 123 / 10
        ch_hex_a_b[3] = '0' +  (  x_bk - (x*10)  );  // 3  <- 120 - 123
        x_bk  =  x;

        x     =  DVI10(x);                           // 1  <- 12 / 10
        ch_hex_a_b[2] = '0' +   ( x_bk - (x*10) );   // 2  <- 12 - 10

        ch_hex_a_b[1] = '0' + x;

        return(ch_hex_a_b);
	
} //ch_hex_a


//アナログ入力の設定
AnalogIn adc_vbat(A3); //PA_4


#define UART_DELAY 101 //  1/9600 98-105

DigitalOut TX(PA_2);

//仮想シリアルへの一文字出力 9600bps
int pc_putc(char ch)
{

    TX=1;
    TX=0;//Start
    wait_us(UART_DELAY);

    for(int ii=0; ii<8; ii++) { //Data x 8
        TX=(ch>>ii)&1;
        wait_us(UART_DELAY);
    }; //for

    TX=1;//Stop
    wait_us(UART_DELAY);

    return(0);

} //pc_putc

//文字列の表示 nana_seg
int pc_printf(char *str1) {

    //文字の中身がゼロか
    while(*str1){

        //一文字出力
        pc_putc(*str1 ++);

    } //while

    //戻り値
    return(0);

}//ns_printf


//メイン関数
int main() {

    int s;  //ADCの値
    //int n0; //温度　小数点以上

    //無限ループ
    while(1) {

        //adcの読み込み 0から4096
        s = (adc_vbat.read_u16()>>4);
//s=2048;
        //電圧に変換 ex 3.300 -> 3300 mVを出力
        s=(s*6600)>>13;

        //電圧の小数点以下の表示
        pc_printf(  ch_hex_a(s)  );

        //リターン
        pc_printf(  "\r\n"  );

        //1秒の待ち
        wait_ms(1000);

    } //while

} //main

//容量削減
void error(const char* format, ...){}



```
エンジニアの私が大学生に講義をするときに気を付けていること

# はじめに
年に1度大学生の前で、会社での仕事の内容やシステムエンジニアの働き方についての話をします。
続けていく中で意識するようになったことを書いておきます。

※この記事に書かれていることは、個人の感覚によるところが多いです

# 「学生はどんなことを聞きたいか」を考える
「聞き手を意識する」というのは大学生に対する講義に限らず、プレゼンにおいても大切なことです。
しかし、社会人から大学生への講義となるとこのことを意識していないと、いつの間にか「学生が聞きたいこと」ではなく「社会人として話したいこと」を考えていることがよくあります。
自分が社会人になったときに感じた、学生の時に想像していた社会人とのギャップを学生に伝えたい！という感情が前面に出てしまうんですね（笑）

私以外にも大学生に講義をする同僚が何人かいるのですが、その人たちの講義内容を見ても「社会人として伝えたいこと」的な内容（学生のうちに勉強しておいたほうがいい、とか報連相は大事、とか）がよく入っていたりするので、これは私だけに限った話ではないのかなと思います。
もちろん「社会人として伝えたいこと」的な内容が議論の余地もなくダメと言うわけではありませんが、少なくとも私が学生のころにそういう話を聞いたときは正直ピンときませんでした。
そのため、私が「学生はどんなことを聞きたいか」というのを意識したとき、「社会人として伝えたいこと」的な内容は入れないようにしています。
（この辺は完全に個人の感覚ですね。。。あと講義の内容にもよります。）

また上記に限らず、講義の本題の内容を考えるときも常に「学生はどんなことを聞きたいか」を意識することが大切です。
私は、「自分が学生だったらこの話を聞いてよかったと思うか」と自問しながら講義の内容を考えるようにしています。

**「話し手が話したいこと」＝「聞き手が聞きたいこと」とは限らない**というのは当然のことですが、意外と忘れがちです。

# 聞き手が講義に参加する機会を用意する
これも大学生に対する講義に限らず、プレゼンにおいても大切なことですね。
講義という形式でも一方的に話すのではなく、聞き手との対話やワークショップを多く取り入れて、聞き手も講義に参加するような進め方をするほうが聞き手は話を聞いてくれます。

私が講義で取り入れているのは「質問」と「ディスカッション」です。
ちょっとした質問をして手を挙げてもらったり、議題について少人数のグループを作って議論してもらったりして、学生にも参加してもらう講義になるようにしています。

ディスカッションは、話し手が休憩できるというメリットもあります。
長時間話していると喉が疲れてくるので、ディスカッション中に水を飲んだりして休憩することで、喉の調子をキープして最後まで話すことができます。

# わかりやす過ぎる内容にしない
難しくしろと言っている訳ではありません。
こちらが話す内容について、学生にも少し考えてもらうくらいの余地を与える内容のほうが、学生は話を聞いてくれます。

これは私の失敗談ですが、実際にこんなことがありました。
大学生への講義を繰り返していく中で、より分かりやすい講義にしようと資料や話の内容を大きく変更したときがありました。
しかし、予想に反して学生の反応はあまりいいものではなく、うつむいていたり、渡した資料だけ見ている学生が多くいました。
これは想像ですが、おそらく最初に少し話を聞いて「これなら貰った資料だけ見れば十分だな」と判断したのではないかと思っています。
あるいは、大した専門性がないから聞く価値がないと判断したのでしょう。

前の章の「聞き手が講義に参加する機会を用意する」とも若干関わってきますが、講義の内容がシンプル過ぎると「参加しなくてもいい」という判断をする学生が出てきます。
また、いくら相手が学生とはいえ、それなりに専門性のある話も入れないと聞き手に時間を割いて聞いてもらう価値のある講義にはなりません。

**わかりやすさを意識することは大切ですが、意識するあまり専門性が感じられない内容になってしまうと、聞き手が退屈して聞いてくれなくなります。**

# おわりに
当たり前と言われたらそれまでの内容ですが、私が今までの経験から気付いたことをまとめました。
次回の講義での目標は、アイスブレークで肩の力を抜いてもらえるような話をすることです！
（あと、冗談を言ってスベる。。。）
【WPF+Prism】入力項目のヘッダーを専用プロパティを用意せずにバインドする方法②（基礎編：コントロールのプロパティ拡張）

WPFを用いた開発をしている上で、既存のコントロールのプロパティの項目では足りなくなることがあると思います。
ここでは簡単にコントロールのプロパティを拡張する方法を紹介しようと思います。
# 添付プロパティ
コントロールのプロパティを拡張するには「添付プロパティ」という機能を利用します。
詳細については多くの方のブログ等にて説明されているので、ここでは割愛させていただきます。

## プロパティ拡張クラスの作成
まずは、プロジェクトを作成します。今回はPrism Blank Appで作成しました。
次に「ExtendProperties」というクラスを作成しました。
ExtendProperties.cs
```cs
using System.Windows;

namespace ExtendProperty
{
    public class ExtendProperties
    {

        [System.ComponentModel.Category(nameof(ExtendProperties))]
        [System.Windows.AttachedPropertyBrowsableForType(typeof(System.Windows.Controls.TextBox))]
        public static string GetTitle(DependencyObject obj)
        {
            return (string)obj.GetValue(TitleProperty);
        }

        [System.ComponentModel.Category(nameof(ExtendProperties))]
        [System.Windows.AttachedPropertyBrowsableForType(typeof(System.Windows.Controls.TextBox))]
        public static void SetTitle(DependencyObject obj, string value)
        {
            obj.SetValue(TitleProperty, value);
        }

        // Using a DependencyProperty as the backing store for Title.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.RegisterAttached("Title", typeof(string), typeof(ExtendProperties), new PropertyMetadata(default(string)));

    }
}
```

ExtendoPropertiesクラスには「Title」という添付プロパティを作成しました。
添付プロパティを作成する際にはコードスニペットの「propa」から作成しましょう。

また、ポイントとしてはプロパティのSetter, Getterに属性を付与しています。
こちらについては後ほど説明します。
## 拡張プロパティの確認
続いて先ほど作成した添付プロパティに値を設定できるか確認しましょう。

その前に、拡張プロパティの属性（Attribute）について確認しましょう。
先ほどのTitleプロパティのSetter, Getterには「CategoryAttribute」と「AttachedPropertyBrowsableForTypeAttribute」属性を付与しています。
「CategoryAttribute」は、デザイナに表示するプロパティのカテゴリを指定します。
「AttachedPropertyBrowsableForTypeAttribute」は、添付プロパティを表示するコントロールの型を指定しています。
※AttachedPropertyBrowsableForTypeAttributeは複数指定可能です。

今回はTextBoxに対して表示するようにしているので、MainWindowのGridにTextBoxを追加し、
TextBoxのプロパティをデザイナ上で確認してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2591086/8be3c805-86b7-24f9-a8d1-5978bcc4aa64.png)

プロパティに「ExtendProperties.Title」が追加されています。
プロパティ上から、項目に値を入力するとコード上では下記のようになりました。
```xml
<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:prism="http://prismlibrary.com/"
        xmlns:ExtendProperty="clr-namespace:ExtendProperty" x:Class="ExtendProperty.Views.MainWindow"
        prism:ViewModelLocator.AutoWireViewModel="True"
        Title="{Binding Title}" Height="350" Width="525" >
    <Grid>
        <TextBox ExtendProperty:ExtendProperties.Title="タイトル"/>
    </Grid>
</Window>
```
# まとめ
今回はコントロールのプロパティの拡張方法について紹介しました。
別の方の記事でも添付プロパティについての説明はあったのですが、実際の利用方法については見つけにくかったため今回の内容を掲載しました。

また、前回はDynamicObjectを用いたバインドを紹介させていただきました。
https://qiita.com/jakucho0926/items/7fbab51a2f7dbeb2d5ec

次回は、今回と前回の内容をふまえ、現実的な実装方法について掲載していこうと思います。

※記事の埋め込みについて、いい方法がありましたら教えていただけると助かります・・・。

#### 2022/03/14 追記
現実的な実装方法について投稿いたしました。
https://qiita.com/jakucho0926/items/070d43d015312a6042ee