OmniAICreator/Qiita-1.07M huggingface dataset:
Minecraft:Bedrock Editionのパケットを解析するためのクライアントソフトウェアを開発した話

はじめましてHmy2001です。

**約3年前**にMinecraft:Bedrock Editionのパケットを解析するためのクライアントソフトウェアを
開発したのですが、そこでいろいろあったことを紹介したいと思います。

クライアントソフトウェアはJavaで開発し、[GitHub](https://github.com/hmy2001/MCBEClient)にて公開されています。

https://github.com/hmy2001/MCBEClient

#Minecraft:Bedrock Editionのパケット
Minecraft:Pocket Edition v0.15.0 alpha (リリース日時:2016年6月 **とても昔！**)から
パケットの暗号化機能が追加されました。
楕円曲線暗号とAESアルゴリズムを用いています。

楕円曲線ディフィー・ヘルマン鍵共有(ECDH)でお互いの公開鍵を共有し、
得られた共有鍵を用いてAESアルゴリズムでパケットを暗号化し通信するといった感じです。

#Javaの採用
楕円曲線暗号とAESアルゴリズムが言語ライブラリでサポートされていて、高速で動作するJavaを採用しました。
あと、いちばんキレイに書けそうだったので採用しました。

#JRakNetの採用
開発初期の方は言語ライブラリであるDatagramSocketやDatagramPacketを用いて開発していましたが、
RakNetプロトコルのEncapsulatedPacketの管理が難しく、
完成まで時間がかかると感じたためJava用RakNetライブラリを探しました。
Githubでリサーチしたら[JRakNet](https://github.com/JRakNet/JRakNet)というものがあったため採用しました。

しかし、JRakNetはサーバーに接続することができてもBedrock Editionのパケットをやり取り出来ないという
致命的な不具合を抱えていました。
この問題を修正し、接続できるようにしました。
(もちろんPull-Requestを出し、無事マージされています)

#Gsonの採用
BedrockEditionのクライアントデータはJsonを用いて送信するため、Goggle製のJsonライブラリの[Gson](https://github.com/google/gson)を採用しました。
Jacksonもあったんですが、イマイチ扱い方がわからなかったので不採用となりました。
#開発中にあったこと
### ECDSA証明のJavaライブラリ出力形式とサーバー側(実機)の受入形式のアンマッチによる通信不可能の発生
* Javaライブラリ出力形式はDER(ASN.1)形式(100-101  Bytes)
* サーバー側(実機)の受入形式はプレーン形式(96  bytes)
上記の形式アンマッチにより、通信が不可能だということがわかったので、DER(ASN.1)形式からプレーン形式となる96  bytes分を
抜き出すことにしました。
これによりうまく通信が行えるようになりました。

(**他にも色々あった気がするけど忘れちゃった**)

#最後に
Githubにて公開してますのでぜひ使ってみてください。
オフラインモードのサーバーに接続する際のみ使えます。(パケット解析目的で使用してください)
なお、最新バージョンには対応していないので、コントリビュートは大歓迎です！

https://github.com/hmy2001/MCBEClient
SpringBoot + gradle で log4j を 2.15.0-rc2 にする

# TL;DR

- あえて spring-boot-starter-log4j2 を入れてなければ Logback なので関係ありません
- 入れてるなら build.gradle の ext に以下を書き足してください

```gradle
ext
{
  set('log4j2.version', '2.17.0')
}
```

- 気づいた？そう 2.17.0 になってるんです。すでに 2.15.0 にした人も 2.17.0 にする必要があるそうなので、皆さん 2.17.0 にしましょう。

## Maven 使ってる人へ

この記事は gradle 使ってる人向けなので Maven 向けの情報は記載してないです

# 自分が対象なのかを調べる

プロジェクトのルートで下記のコマンドを実行してみてください

```shell
$ gradle dependencies | grep log4j
```

`org.apache.logging.log4j:log4j-core:2.13.3` とか 2.15.0 よりも下のバージョンが出てきてしまったあなたは対象です。TL;DR を読んで build.gradle に加筆してください。

加筆し終わった後に再確認して、`org.apache.logging.log4j:log4j-core:2.13.3 -> 2.15.0` とかになってれば大丈夫です。

# rc2 どこ行った？

Maven Central Repository から引いているなら 2.15.0 はもう rc2 になっています。
確証が欲しければ [pom](https://repo.maven.apache.org/maven2/org/apache/logging/log4j/log4j/2.15.0/log4j-2.15.0.pom) をみて `tag` をページ内検索してください。

むしろ、`2.15.0-rc2` とか書いても、そんなものは[存在しません](https://repo.maven.apache.org/maven2/org/apache/logging/log4j/log4j/)。

# うちエンタープライズだし外部アクセスは全部API経由なんだけど、そんなヤバいんですか？

やばいです。踏み台とか関係ないです。log が出る不正リクエストで任意コードが実行されます。情報抜き取りまでいかないまでも破壊はそう難しくないです。

会社で伝わりやすそうな数値基準でヤバさを伝えるなら Red Hat のサイトの [CVE-2021-44228](https://access.redhat.com/security/cve/cve-2021-44228) をみてください。10.0 Max のスコアで 9.8 です。

# Spring の対応待ちじゃダメなの？

[次回のリリースまで対応はなさそうです。](https://github.com/spring-projects/spring-boot/issues/28958)

# log4j2.formatMsgNoLookups じゃだめなの？

そのオプションは 2.10 以降に追加されたものなので、それより前のバージョンだと効きません。
Figmaで複数ページPDF資料を制作する際に役立つかもしれない、3つのTips

こんにちは。あさマック [@mixplace](https://twitter.com/mixplace) です。主にWebアプリケーションのフロントエンド開発をしているエンジニアですが、ここ最近はUIデザイン領域にも重きを置きています。デザイニングとエンジニアリングの狭間にいる民として、サービスの体験をデザインする難しさを楽しさと噛みしめている今日この頃です。

ここ最近、いくつかの案件を担当させていただいているなかで、Webサービスの紹介冊子（PDF）を制作する機会がありまして、Figmaを選定して制作を行いました。
いわゆる複数ページもののPDFファイルですね。

今回は、紹介資料をFigmaでデザインしていて、どうしたら良いかわからずハマったことを3点のTipsとして自身の備忘を兼ねてご紹介します。

この記事は、[Figma Advent Calendar 2021](https://qiita.com/advent-calendar/2021/figma) の10日目の記事としてお送りします。

# 1. 用紙サイズに合ったFrameを作成したい

**ポイント:** 用紙サイズを72dpiでmm→pxに単位を変えてFrameを作成する

一般的なスライド作成/DTPソフトウェアにおいては、単位がmmやcmで表現しますが、Figmaはpxです。
この際に悩むのが、Frameのサイズです。

ありがたいことにFigmaではFrameを作成する際、よく使うサイズがプリセットで登録されており、Paperカテゴリにある「A4」をクリックすると、595px × 842px のFrameが作成されます。
このFrameをPDFでExportすると、A4の用紙サイズである 21.0cm × 29.7cm で書き出されます。

![スクリーンショット 2021-12-10 12.29.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49488/afcc8700-db1b-325c-add4-e3c9a8125885.png)

初見だと「Frameのサイズが小さすぎないか？」と違和感や不安を感じられるかもしれませんが、これはFigmaがFrameを72dpiとして扱っているためです。

A4以外の用紙で制作することもあるかと思いますので、以下にまとめました。

## 用紙サイズとピクセル数の早見表
ピクセルの単位は72dpiです。

| 用紙サイズ | 幅 × 高さ (mm) | 幅 × 高さ (px) |
| ---- | ----- | ----- |
| A3 | 297 × 420 | 842 × 1191 |
| A4 | 210 × 297 | 595 × 847 |
| A5 | 148 × 210 | 420 × 595 |
| B4 | 257 × 364 | 729 × 1032 |
| B5 | 182 × 257 | 516 × 729 |
| はがき | 100 × 148 | 283 × 420 |
| 名刺 | 55 × 91 | 156 × 258 |

ほか、用紙サイズのmm←→ピクセル数の単位を調べるには、以下のWebページが参考となります。
https://www.benricho.org/size_scale/pixel.html

# 2. 各Frame毎にページ番号を順に打ちたい

**ポイント**: [Paginate](https://www.figma.com/community/plugin/805217025770129636/Paginate) プラグインを使って打つ

[Paginate](https://www.figma.com/community/plugin/805217025770129636/Paginate) プラグインを用いることで、Component化しているテキストオブジェクトを選択するだけでページ番号に置き換えてくれます。

![スクリーンショット 2021-12-10 20.18.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49488/3edd836d-0a29-4554-faed-017577b78a0a.png)


# 3. 複数ページをまとめたPDFファイルを作成したい

**ポイント:** macOSのプレビューアプリで結合できるが、テキストオブジェクトの扱いに注意が必要

Frame内でデザインが終われば、Frame毎にPDF形式でExportするだけです。
Fileメニューの“Export Frames to PDF...”を使っても良いでしょう。

ただし、Figmaでは複数ページを1つのPDFファイルに結合して書き出す機能は標準では存在しません。

Macをお使いの方であれば、[プレビューアプリを使って複数のPDFファイルを1つのPDFに結合する](https://support.apple.com/ja-jp/HT202945)ことができます。

ただ、PDFを結合して保存するとテキストオブジェクトの選択とコピーが出来なくなる場合が高確率で発生しました。（これはmacOSのプレビューアプリの仕様と思われます。）

テキストオブジェクトは選択できるよう担保したかったため、やむなくAdobe Acrobatを利用してPDFを1ページに結合しましたが、
Exportされるファイルを個別最適化して書き出せる「Tiny Image Compressor」というFigma プラグイン（有償、14日間トライアル）を使うのも良いでしょう。
複数ページを1 PDFファイルとして書き出したり、CMYKで出力することもできる万能なFigma プラグインです。

![スクリーンショット 2021-12-10 12.29.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49488/e7d77bae-97b0-0679-fdc1-923f2dd82e7b.png)

# あとがき

「PowerPointやGoogle Slidesで作るよりも正確精緻に仕上げたい、だけどIllustratorやInDesignを使うには大層だ。」というシチュエーションはあるかと思います。

また、デジタルプロダクトを開発運営している事業者の場合、Figmaでプロトタイピングを行っていることも多いかと思います。
プロダクトのプロトタイプからサービス資料まで一環したものを1つのツールで完結して作れることは、サービスが目指す世界観やブランディングの観点でも一貫性が持て、またデザイン成果物が一ヶ所に集まる点でもメリットがあると感じました。

今回は“FigmaでPDF資料制作するのも手段の1つとして存在する”ということをお伝えしたく、記事とさせていただきました。

それでは明日以降も [Figma Advent Calendar 2021](https://qiita.com/advent-calendar/2021/figma) をお楽しみください！See you next time!
N予備校プログラミングコースの感想（9ヶ月目）

# N予備校プログラミングコースの感想（9ヶ月目）

## 目次
1. 自己紹介
1. N予備校に入学したきっかけ
1. N予備校プログラミングコースの感想
1. 終わりに

## 自己紹介
みなさんこんにちは！kenton116です。
N予備校でプログラミングを学んでいます！
プログラミングコースは今年からの受講です。

## N予備校に入学したきっかけ
N予備校に入学したきっかけは、去年N予備校の1年間無料開放キャンペーンがあったことでした。
プログラミングもScratchで少し始めていて本コースもやってみようと思っていました。
が、１９時からの１時半の授業となかなか厳しいスケジュールで、結局１年間受講せずに終わってしまいました。
でも、やっぱりN予備校のプログラミングは受講してみたくて、今年もN予備校を続けることにしました。

## N予備校のプログラミングコースの感想
N予備校の特徴は、なんと言ってもコメント機能とslackです。
コメントは講師の先生が拾ってくれます。
また、みんながコメントで雑談をしたり、質問したりできるのがとても便利でモチベーションがもつ理由だと思います。
slackは講師の先生がすぐに質問に答えてくれたり、みんなで楽しく雑談したりできます。
「みんなと一緒にプログラミングしている！」っていう感覚がオンライン授業なのに感じられるのが、N予備校のとても素晴らしいところです。

そして、その授業を楽しむためには「予習」が大切です。
予習は、次の授業のテキストを読んでもう先にプログラミングすることです。最初は抵抗がありましたが、slackの皆さんと予習するとモチベーションが下がらずがんばれます！そして、授業の時も余裕があるので先生に質問できます。
この好循環がN予備校を楽しむ秘訣だと思います！

## 終わりに
N予備校のプログラミングコースはオンライン授業ですが、モチベーションを保ちながらプログラミングを学ぶことができるとても素晴らしいコースです。
始めてから９ヶ月、時々挫折しそうになりながらも頑張っています。完走できるよう頑張っていきますよ！
Launch images are deprecated in iOS 13.0. Use a launch storyboard or XIB instead.

# 1. Xcodeの警告内容

Xcode iOS アプリで下記の警告が発生しました。

( 開発環境 )
macOS Monterey Ver 12.0.1
Xcode Ver 13.1

(　警告メッセージ画像　)
![スクリーンショット 2021-12-10 15.11.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1189425/6adf40ab-9d39-723e-e34a-10b0f4a2a229.png)

（ 警告メッセージ原文 ）
Launch images are deprecated in iOS 13.0. Use a launch storyboard or XIB instead.
'UILaunchImages' has been deprecated, use launch storyboards instead.

( 翻訳 )
起動イメージはiOS13.0で非推奨になりました。 
代わりに、起動ストーリーボードまたはXIBを使用してください。
「UILaunchImages」は非推奨になりました。
代わりに起動ストーリーボードを使用してください。

下記の Launchimage は非推奨との事です。

![スクリーンショット 2021-12-10 15.38.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1189425/e2d4411e-5392-977d-e163-d032e76cbaa2.png)


# 2. Xcode iOS アプリ修正内容（その1）

【修正内容】Launchimageの削除。

(1) 文字列"Launchimage" で検索する。

![スクリーンショット 2021-12-10 15.46.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1189425/6f88c8c9-9116-dfc2-09c7-d8019d5c2ebc.png)

![スクリーンショット 2021-12-10 15.49.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1189425/9edc0120-c827-21d8-5127-39d29c15041d.png)

(2) Asset Catalog Launch Images Set Name の文字列 "Launchimage" を削除する。

![スクリーンショット 2021-12-10 15.51.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1189425/d94bf43a-0637-3f6f-1308-06e6b1095334.png)


#3. Xcode iOS アプリ修正内容（その2）

【修正内容】storyboardを追加登録。

(1) メニュー [File] - [New] - [File...] を選択する。

(2) [Launch Screen] を選択し、[Next]ボタンをクリックする。

![スクリーンショット 2021-12-10 16.38.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1189425/9bb4c36b-056a-b1ed-1fdc-0fa23b2c6a8c.png)

(3) Info.plistに、"Launch screen interface file base name"のKeyを追加し、
上記で作成したstoryboard名"Launch Screen"文字列をValue値に設定する。

![スクリーンショット 2021-12-10 20.10.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1189425/776e41af-a2da-5360-b7a2-5d5f57a5938d.png)


# 4. 注意事項

( 発生現象　)
上記のアプリ修正を行うと、
self.view.frame.size.width
self.view.frame.size.height
の値が同じ機種なのに
修正前と変化する事がわかりました。

（ 前提条件 ）
私の修正前のアプリは、
StoryboardやXIBを未使用で
コードのみで画面を表示していました。

( 備考 )
以下のiPhone12,iPad(8th)の値は実機ですが、
iPadPro,iPadMiniの値は、Xcode（Simulator）のものです。


iPhone12の場合
修正(前) 375 x 812 比率(縦÷横)=2.165...
修正(後) 390 x 844 比率(縦÷横)=2.164...

微妙に増えてますね。
比率(縦÷横)は、ほぼ同じです。

iPhone8の場合
修正(前) 320 x 568 比率(縦÷横)=1.775
修正(後) 375 x 667 比率(縦÷横)=1.778...

iPad(8th)の場合
修正(前) 768 x 1024 比率(縦÷横)=1.333...
修正(後) 810 x 1080 比率(縦÷横)=1.333...

iPadProの場合
修正(前)  768 x 1024 比率(縦÷横)=1.333...
修正(後) 1024 x 1366 比率(縦÷横)=1.333...

おやおや、
iPadMiniの場合は比率(縦÷横)も変化しています。

iPadMiniの場合
修正(前) 768 x 1024 比率(縦÷横)=1.333...

:::note warn
修正(後) 744 x 1133 比率(縦÷横)=1.522...
:::


やれやれ

画面デザインのアプリ修正が必要となりました。
こちらの修正の方が、かなり面倒な作業となります。


以上です
[初学者向け]AWSを利用するのに最低限必要なCIDRの知識。

#はじめに
~~私は三○矢サイダーを飲むと異様に肩が痛くなります。なんでなんでしょうか。~~
私がAWSで初めてVPCを作成した際に、真っ先に躓いた部分がCIDRでした。
　
IPアドレスは分かる、サブネットマスクも分かる。
この訳の分からない「/」の付いたCIDRって、なに……？


#調べてみた。

ネットワークの入門系の書籍を何冊か読んでみましたが、CIDRに関しては言及を避けているか、言葉を尽くしたせいで却って曖昧になっているような内容が多いように感じました。
例「クラスレスアドレッシング？　はぁ、そうですか」
私の理解が足りていないだけかもしれませんが。

なので、自分なりに理解しやすいよう解釈してみました。

#※あくまで個人の解釈です。
CIDRはサブネットマスクの「表記法」の一つ、と捉えてみます。

サブネットマスクって、なに……？　
という方は安定の佐々木真氏のサイトが分かり易いかと思います。

>参考
>[サブネットマスク（subnet mask）とは](https://wa3.i-3-i.info/word11975.html)


「/n」の部分でやっていること自体はサブネットマスクと同じです。
「/n」という表記は、
IPアドレスの左からn番目までの数字が**ネットワーク部**で、
以降は**ホスト部**ということを表しています。
`n=ネットワーク部の桁数`
という表現もできますね。

サブネットマスクの1とか0とか255とかの、目の痛くなるあれを読みやすくしたのがCIDR表記とも言えます。

```:例
CIDR表記「/16」を変換すると、
サブネットマスク（10進数）：/255.255.0.0
サブネットマスク(2進数)：/11111111111111110000000000000000
CIDR表記「/24」を変換すると、
サブネットマスク(10進数)：/255.255.255.0
サブネットマスク（2進数）：/11111111111111111111111100000000
```
IPv4は2進数だと32桁です。
「/16」を例に取ると、
左から16桁まで（2進数表記で1の部分）がネットワーク部、
17桁から32桁まで（2進数表記で0の部分）がホスト部となります。

言い換えると、「/n」のnの値が小さいほど（ホスト部の桁が大きいほど）、割り振り可能なIPアドレスの数が多くなります。

``` :例
10.0.0.0/16の場合、65536個のIPアドレスが使用可能。
10.0.0.0/24の場合、256個のIPアドレスが使用可能。
```

::: note info
/22を基準にしてIPアドレス数を覚えると便利かもしれません。
/21が2048個
/22が1024個
/23が512個
といったように、後は倍々となります。
:::

#AWSを例にとってみる。


AWSでは、VPC（仮想ネットワーク）の作成時にネットワークの範囲を指定します。
そのときに使われる用語が「CIDRブロック」なのですが、要は「サブネット」のことです。
VPCで大きくサブネット（ネットワーク）を取った上で、VPCに配置したサーバーごとにネットワークを小さく切り分けていきます(サブネット化)。


```:例
○：VPCの方がサブネットが大きい
VPCのCIDRブロックが10.0.0.0/16
EC2のCIDRブロックが10.0.0.0/24
×：VPC内の機器の方がサブネットが大きい
VPCのCIDRブロックが10.0.0.0/24
EC2のCIDRブロックが10.0.0.0/16
```

CIDR表記を使うと、サブネットを切り分けるときに分かり易い！


#おわりに

うーん、まだまだ理解が足りていないです。
やっぱりIP周りの知識は基礎なだけにもっと深めなきゃなぁ、と思いました。

この記事が少しでも役立てば幸いです。
cbindではNULLとデータフレームを結合できない

cbind関数はRでデータの前処理に頻繁に使用する関数で、その役割としては行数の等しいデータフレームや行列同士を結合します。
私は、for文のなかにいれて複数の同種類のファイル同士を結合させるときによく使います。
この記事ではfor文中でcbindを使うときの注意点を記録しておきます。
カレントディレクトリにあるcsvファイルをすべて読みこんで列方向に結合（つまり行ではなく列が増えていく）していきたいとします。
例えばこういうコードを書いたとしましょう。

```sample.R
lfs <- list.files(pattern=".csv")
df_out <- NULL
for(i in lfs){
    df_tmp <- read.csv(i, header=T)
    df_out <- cbind(df_out, df_tmp)
}
```

こうしてしまうと、「引数に異なる列数のデータフレームが含まれています」というエラーになります。一回目のループでつまづきます。

エラーの原因は、NULLとデータフレームをcbindで結合させようとしたことです。cbind関数ではNULLと結合できるのはベクトルか行列です。read.csvで読み込んだものは自動的にデータフレームになりますので、それらは結合できない、というわけです。なのでこうすれば動きます。

```sample.R
lfs <- list.files(pattern=".csv")
df_out <- NULL
for(i in lfs){
    df_tmp <- read.csv(i, header=T)
    df_mtx <- as.matrix(df_tmp)
    df_out <- cbind(df_out, df_mtx)
}
```

as.matrixでデータフレームを行列に変換するだけです。ちなみに、cbindはNULLとベクトルなら結合できますので、最初のコードで
df_out <- cbind(df_out, df_tmp[,1])
などとすると、df_tmp[,1]はベクトルになるので、エラーはでません。
<備忘録>RailsアプリをHerokuデプロイでエラー

RailsアプリをHerokuデプロイ時に２つのエラーが発生しました。
今回はそのうちの１つをメモとして残します。
# 環境
* macOS      Monterey 12.0.1
* Ruby       3.0.3
* Bundler    2.2.32
* Rails      6.1.4.1

# heroku push　でエラー発生

`$git push heroku main`
で、以下のエラーが発生しデプロイに失敗。

```text:エラーメッセージ
remote: ###### WARNING:
remote: 
remote:        You have not declared a Ruby version in your Gemfile.
remote:        
remote:        To declare a Ruby version add this line to your Gemfile:
remote:        
remote:        ```
remote:        ruby "2.7.4"
remote:        ```
remote:        
remote:        For more information see:
remote:          https://devcenter.heroku.com/articles/ruby-versions
```

エラーメッセージによると、
『Rubyのバージョンを宣言していません。Gemfileに追加してね』
とのこと。

どうやら、`Gemfile`にRubyのバージョンを記載しないといけないみたいです。

記載してみましょう。


## GemfileにRubyのバージョンを宣言
```ruby:Gemfile
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
#Rubyの任意のバージョンを記載
ruby '3.0.3' 
```

`Gemfile`を更新したので`bundle install`を実行します。

```
$ bundle install
```

無事更新できました。

## Herokuへデプロイ
Herokuへデプロイします。

```
$ git add -A
$ git commit -m "add Ruby version in Gemfile"
$ git push heroku main
```


以上、Herokuデプロイ時エラー発生の対応でした。
「すき家の牛丼(店内) メニュー」をサクラエディタの置換を使ってmarkdown表に変換してみた。

オリジナル

https://www.sukiya.jp/menu/in/gyudon/100100/index.html

以下、牛丼(店内)のメニューだけです。
全メニューをスクレーピングのおすすめのページを紹介してもらうと助かります。メニューサイトの複数ページを集計したいです。
写真があるから、メニューなのかもしれませんね。

#markdown表(2021-12-10現在)
| my追番 | カテゴリー | size | 税込価格(円) |
| --- | --- | --- | --- |
| 001 | 牛丼(店内) | ミニ  | 290 |
| 002 | 牛丼(店内) | 並盛  | 350 |
| 003 | 牛丼(店内) | 中盛  | 480 |
| 004 | 牛丼(店内) | 大盛  | 480 |
| 005 | 牛丼(店内) | 特盛  | 630 |
| 006 | 牛丼(店内) | メガ  | 780 |

#markdown(csv to markdown)の前  
my追番,カテゴリー,size,税込価格(円)
001,牛丼(店内),ミニ,290
002,牛丼(店内),並盛,350
003,牛丼(店内),中盛,480
004,牛丼(店内),大盛,480
005,牛丼(店内),特盛,630
006,牛丼(店内),メガ,780

#サクラエディタ Ver 2.4.0 (Beta5)のマクロ
テキストファイルから、抽出を使わず置換です。

```
//キーボードマクロのファイル
ReplaceAll('^(?!.*(</dt>|dd class="price"><em>)).+$', '', 28);// すべて置換
ReDraw(0);// 再描画
ReplaceAll('(.*)</span></em></dt>(.*)|(.*)</a></dt>(.*)', '', 28);  // すべて置換
ReDraw(0);// 再描画
ReplaceAll('^\\r\\n', '', 28);  // すべて置換
ReDraw(0);  // 再描画
ReplaceAll('</dt>\\r\\n', ',', 28);   // すべて置換
ReDraw(0);  // 再描画
ReplaceAll('(.*),(<dd class="price"><em>)(.*)(</em>円</dd>)', '$1,$3', 28);  // すべて置換
ReDraw(0);  // 再描画
```

#参考
https://qiita.com/mrrclb48z/items/aeb26b1b9a69ce19a421
Docker(-compose) 同一pathにmountをする設定を複数書いたときの挙動



## はじめに
この記事は MicroAd Advent Calendar 2021 の 12 日目の記事です。

## 疑問

webサーバーのリプレイスの際にコンテナ化を行っていました。
何個か設置している静的ファイルはイメージ化して、データボリュームとしてwebサーバのコンテナに共有する想定。

色々試してる中で、１つのディレクトリに複数のボリュームのファイルの中身を設置(mount)したいと思う場面がありました。
ただ、その場合の挙動が想像がつかず、「各ボリュームのファイルが競合していたらどうなる？ディレクトリの中にボリュームのファイルをいい感じに設置してくれる？」という疑問になったので確認してみました。

## 確認

### ファイル構成

``` docker-compose.yml
version: "3"
services:
  ab:
    image: busybox:latest
    volumes:
      - a_volume:/test/
      - b_volume:/test/
```
a_volumeの中には`a`, `ab`
b_volumeの中には`b`, `ab`
というファイルを作成しています

## 実行
上記の`docker-compose.yml`を実行
エラーが発生したのでマウントも実行されなかった。
```ERROR: Duplicate mount points: [a_volume:/test:rw, b_volume:/test:rw]```

##　終わりに

疑問を持ったので試したわけですが、エラー一つで終わってしまうと少し悲しいものがあります・・・
とはいえ、他の人もほとんど記事に書いていないエラーを踏めたのでいい勉強にはなりました。

もしかして、Dockerの裏ではoverlayFSが動いてるらしいのでlinuxの`mount`コマンドと同じ挙動をしている？
と次の疑問を持ってしまったのでmountコマンドの動作を確認してみましたが、どうやら違うようです。
同じmountpointに複数のディレクトリをbindしてもエラーが出ず、変更を加えた後`unmount -a`を実行すると最後にmountしたディレクトリにだけ変更が適応されていました。何も分からない。　

linuxとdockerと和解するのはまだ時間がかかりそうです。
Professional Data Engineerを受験したので結果と勉強方法をまとめました

# はじめに

本記事は[NI+C Advent Calendar 2021](https://qiita.com/advent-calendar/2021/niandc_teamgcp)の10日目の記事となります。
弊社ではGCPの認定資格取得のための勉強会も行っており、3日目の記事である[新人社員が Google Cloud 認定資格の Associate Cloud Engineerを合格するまで](https://qiita.com/yyyimai/items/613f705f409674f2edd2)も弊社内の取り組みとなっております。

本記事はGCPのProfessional資格である「Professional Data Engineer」の勉強記および受験記となります。
なんとブログ執筆日の今日に試験を受けてきましたので現地レポート感ある感じで執筆しています。

# そもそもどんな資格か

GCPの[公式ページ](https://cloud.google.com/certification/data-engineer)には以下の記載がされています。

>Professional Data Engineer は、データを収集、変換、公開して、データに基づいて意思決定できるようにします。Data Engineer には、セキュリティとコンプライアンス、スケーラビリティと効率性、信頼性と忠実性、柔軟性とポータビリティに特に重点を置いて、データ処理システムの設計、構築、運用化、保護、モニタリングを行う能力が必要です。また、既存の機械学習モデルの活用、デプロイ、継続的なトレーニングもできなければなりません。

平たく言えば、Google Cloudが提供するマネージドサービスを利用し、ストレージシステムの構築やデータパイプライン設計、機械学習モデルの運用を行う知識があるかを確認する試験となります。
GCPの基本的な機能はもちろん、専門的な話も問題の中に出てきます。

# 受験者のスキルセットは

GCPの認定資格としてはProfessional Cloud ArchitectとAssociate Cloud Engineerを持っています。
Professional Data Engineerの問題で出てくるような業務経験はなく、SQLやデータパイプラインについても特段詳しいといったわけではないので、自分の中ではハードルが高い試験となっています。

# どうやって勉強したか

主に以下の内容で勉強を行いました

- 公式ページにある試験ガイド確認
- 模擬試験によるテスト/ワード確認

## 公式ページにある試験ガイド確認

公式ページにある[試験ガイド](https://cloud.google.com/certification/guides/data-engineer)は、Professional Data Engineerに出てくる範囲が記載されています。こちらの内容が何かわからないとまずいので、ワードレベルでは確認を行いました。
本件の内容に関して調べた中で欲しい記事が見つからないことが多々あったため、別途投稿するかもしれないです。

## 模擬試験によるテスト/ワード確認

公式ページにある[模擬試験](https://docs.google.com/forms/d/e/1FAIpQLSd4j4bcgbYenBRFIL6Kb0cvXp13qCQ-z6JzowgDxRaPITn56g/viewform)より難易度が高い内容が実際の試験で出題される感触だったので、模擬試験は必ず確認したほうがいいです。
模擬試験を全部覚えるってことではなく、あくまでも模擬試験を受けた中でワードや解説が飲み込めない範囲を確認するといったことをメインに行いました。

# 試験問題の感触

試験問題はBigQueryと他ソリューションの組み合わせがメインでした。
試験ガイドのセクション1が5割近く出ていた印象です。サービス理解のみでは解けないと思いながら受けていました。ユースケースに沿った問題といったものはないので、ほとんど4択です(2つ選びましょうみたいな問題は3問程度)

また、セクション3の部分の機械学習系は数問出ていましたので、自信がある人はチャレンジするといいかもしれないです(自分は全くわからなくてひたすら首を捻っていました)

# で、試験結果は？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283423/1f044d25-7930-121a-aa99-e5f7b1555615.png)



試験結果としては、なんとか合格しました！
あまり自信がなく、ちょっとした記念受験感もあったので正直かなり驚きました。
資格試験に合格ができてよかったですが、自分の中でちゃんと理解できている部分とそうでない部分もあるため、引き続き勉強を継続していきたいです。
Pythonのdatetime比較でハマった話

# この記事について
唐突ですが、[以前作成した社内ボット](https://qiita.com/Hiroki1928/items/e3e18636c1da955023f1)が動かなくなりました。。。
原因を調べてみると、Pythonのdatetime型の比較処理が原因だったので、まとめてみました。

# 修正の変遷
- get_atom関数を実行してみるとこのようなエラーが出ました。

```
>python main.py
Traceback (most recent call last):
  File "main.py", line 36, in <module>
    main()
  File "main.py", line 14, in main
    msg_arr = atom.get_atom()
  File "C:\Users\XXX\Documents\XXX\slack-qiita-bot\bot\atom.py", line 21, in get_atom
    tdatetime = dt.strptime(d_atom['entries'][i]['published'], '%Y-%m-%dT%H:%M:%SZ')
  File "C:\Users\XXX\anaconda3\envs\qiita_slack_bot\lib\_strptime.py", line 577, in _strptime_datetime
    tt, fraction, gmtoff_fraction = _strptime(data_string, format)
  File "C:\Users\XXX\anaconda3\envs\qiita_slack_bot\lib\_strptime.py", line 359, in _strptime
    (data_string, format))
ValueError: time data '2021-11-28T10:59:10+09:00' does not match format '%Y-%m-%dT%H:%M:%SZ'
```

- 該当箇所のフォーマットを修正してみました
    - QiitaのUI変更に伴い、atomの表記が変わったのではないかと思っています
    - どちらにしても、タイムゾーンの処理をさぼっているのは間違いないですね

```diff
- tdatetime = dt.strptime(d_atom['entries'][i]['published'], '%Y-%m-%dT%H:%M:%SZ')
+ tdatetime = dt.strptime(d_atom['entries'][i]['published'], '%Y-%m-%dT%H:%M:%S%z')
```

- 今度は違うエラーが出ました  

```
>python main.py
Traceback (most recent call last):
  File "main.py", line 36, in <module>
    main()
  File "main.py", line 14, in main
    msg_arr = atom.get_atom()
  File "C:\Users\XXX\Documents\XXX\slack-qiita-bot\bot\atom.py", line 26, in get_atom
    if not from_time <= tdatetime <= to_time:
TypeError: can't compare offset-naive and offset-aware datetimes
```

- [こちらの記事](https://qiita.com/takaki@github/items/b1a380a0a644170f5885)によると、タイムゾーンが含まれているdatetimeとタイムゾーンが含まれていないdatetimeは比較できないようです。  
実際にdatetimeを格納している変数を比較すると確かに違います

```
2021-12-10 17:29:39.265024
2021-12-10 18:29:39.265024
2021-11-28 10:59:10+09:00
```

- タイムゾーンが含まれていないdatetimeにもタイムゾーンを追加します

```diff
- if not from_time <= tdatetime <= to_time:
+ if not from_time.astimezone() <= tdatetime.astimezone() <= to_time.astimezone():
```

- 正常に比較できたようです

```
2021-12-10 17:41:06.174746+09:00
2021-12-10 18:41:06.174746+09:00
2021-11-28 10:59:10+09:00
```

## まとめ
datetime型のタイムゾーンはちゃんとに処理しましょう
【保存版】『炎上』に対して 個人や企業ができること

#対処フロー
ミスに早期に気づき、対応を迅速に行えるかが、SNS上で批判の集中砲火を受けるか回避できるかにかかっています。
論調を適切に把握し、早期に対応を行うことができれば、SNS炎上から称賛に繋がり可能性があります

>1.炎上に対して事実の確認を早期に行うこと
2.「何が批判の原因となっているのか」「批判されている内容は事実か」「誤解だとすれば、本当はどうだったのか」
3.ユーザーが何に対して批判を行っているのか理解できなければ、謝罪対応も適切には行えません。
　　逆に「本質がわかっていない」という更なる批判につながる可能性もあります。
4.事実の確認と論調の把握ができ、判断材料が揃った段階で、謝罪の方法や今後の対応を検討する
5.どのように信頼を回復していくのか、
6.二度と同じ過ちを侵さないためにどのような対策を講じることができるのか

#３大NG行動
まず1つめは<b>「個人的な反論をしないこと」</b>です。組織として取るべき炎上対策にブレが生じやすくなると同時に、感情に任せた反論となれば、火に油を注ぐことになります。注意したいのは、匿名の書き込みですら特定される恐れがあること。実際に、炎上している会社を擁護する反論を社員が匿名で掲示板に書き込んだところ、投稿の発信元が露呈して大炎上につながったケースもあります。

2つめは<b>「苦しい言い訳をしないこと」</b>。以前、従業員がハンバーガーのバンズの上に寝転がっている写真をTwitterに投稿して炎上しました。その際、企業の公式サイトで「発注ミスで廃棄処分だった」と釈明しましたが、これに対してネット上では、「そんな大量な廃棄が出るわけがない」、「その場しのぎの言い訳だ」などとして、炎上が長引いてしまいました。たとえそれが事実であったとしても、まずは謝意を全面に出すことが求められます。

3つめは、<b>「鎮静後に気を抜かないこと」</b>。コンビニ大手チェーンにおいて、店舗内のアイス冷凍庫に入った写真がネット上に公開され、炎上したことがあります。本社が公式に謝罪し、テレビ報道もされて一旦は沈静化しましたが、そのわずか1か月後に、別のアルバイトスタッフによる不適切なつぶやきから新たなネットリスクが発生。そのスタッフのFacebookから、学校や交友関係が明るみになり、未成年で飲酒・喫煙していることまで判明し、再炎上しました。炎上を招いた企業に対して、ネットユーザーは一定期間厳しく監視する傾向にあるため、鎮静後も気を抜いてはいけません。
なお、事態が鎮静化した後もインターネット上に炎上の記録が残り、批判的な書き込みが目に付く状態が続くこともあります。その際、「外部の専門会社に委託して検索順位を下げること」は、炎上対策としておすすめできません。恣意的に押し下げたことが表面化すると、さらなる炎上を招くからです。ホームページや公式SNSアカウントなどで地道な投稿とプロモーションを続けてネット上のコンテンツを増やし、自然と炎上に関するページの検索順位が下がる「逆SEO対策」こそ、正しい炎上対策の一環といえます。



###① 重要な情報のやり取りをしない
守秘義務や秘密保持契約など規則に基づき漏えいさせてはいけない事柄をSNSに投稿してはいけません。
もし情報が漏えいした場合、担当者の解雇だけでなく、損害賠償に発展する可能性もあります。

SNSでやりとりする情報は、基本的には「すべて公になってしまう」と考えましょう。


###② 事実かどうか不確かなものは発信しない
ウラが取れない情報を発信しないのはもちろん、
他者の利害にかかわっている場合はより一層注意が必要です。

事実は思った以上に不確かなものであると認識しておきましょう。


###③ 他人のプライバシーや個人情報を発信しない
この場合の個人情報とは、人物を照合できる可能性がある情報すべてを意味します。「だれかをどこかで見た」という情報も他人のプライバシーに触れる情報になるので避けるべきです。

また、重要な情報を送る相手の確認も決して怠れません。たとえばDM（ダイレクトメール）など普段公開されないやりとりでの送信先のミスや、相手がなりすましアカウントである危険性も考えられるためです。

###④ センシティブな世間の関心事に むやみに干渉しない
SNSをにぎわせる話題には触れないほうが懸命と言えます。
投稿の内容が会社のマイナスになる可能性はないか重ねて吟味しましょう。


#企業の炎上が起きた時の 3つの心構え
焦りからひとたび判断を間違えると、一般ユーザーからますます怒りや不満を買ってしまう場合さえあるのです。

###① なによりもまずは、落ち着く
炎上のショックで取り乱してはいけません。慌てて行った運用の判断が「その場しのぎの取りつくろい」とユーザーから判断されてしまうと、あとで正しい対処や情報がわかったとしても、そのときには事態がより複雑化している場合があります。

他の心構えにもつながりますが、まずは冷静になることが大切です。


###② 「すぐ削除」が必ずしも良いとはいえない
万一アカウントで炎上が起きた場合、「問題の投稿を急いで削除しないと！」と思いがちです。

たしかに早めの対応は重要ですが、ほかの対応なしに投稿削除だけを先んじて行うと、
SNSユーザーは「隠ぺい・ごまかし」と捉えることがあります。
そうなると、炎上が加速する恐れがあります。



###③ 謝罪も、全体の指針が決まってから
炎上時はすべての対応に一貫性が求められます。
というのも、対応や発言が二転三転してしまうと、
「誠実でない・信憑性がない」とユーザーの猜疑心を掻き立ててしまうためです。
担当者は不用意な謝罪を控え、炎上を事実をすばやく関係部署間で周知し、
全体で対応を考えましょう。



#理想的な炎上対応フローの例

###ソーシャルメディアの活動を停止する
炎上したアカウントは必要最低限な情報発信にとどめ、解決の目途が立つまで一旦停止させましょう。
この場合の「停止」とはアカウントやコンテンツの「削除」ではなく、むやみな投稿をストップして様子を見ることをいいます。


###弁明や謝罪、今後の対応策や発表は方針が決まってから
一貫した対応がユーザーの信頼につながります。
弁明や謝罪といった今後の対応策は担当者が冷静に判断し、対応しましょう。
DeviseのUserテーブルにカラムを追加する

###環境
ruby 2.6.3
rails 2.6
cloud9

Gem：devise

###この記事の目標
Devise(Gem)でUserテーブルを作成し、ユーザーネームを新規登録（Sign up)で登録できるようにする


#1 DeviseでUserテーブルを作成

Deviseを使用するとユーザーテーブルを簡単作成してくれます。
まず初めにモデルを作成。

Deviseを使用する場合のモデル作成コマンド(今回はUserモデル）

```ruby
$rails g devise User
```


※通常のモデル作成コマンド

```ruby
$rails g model モデル名
```
記述方法が違うので注意



**コマンドを実行すると作成される**
**ファイル**
1.モデル（User)
2.マイグレーションファイル

**カラム**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2309717/2d17e3ae-e480-aabc-1668-6a9eff7dbe83.png" width="80%">


#2 任意のカラムを追加する

ユーザーネームを保存するためのカラム（name）がないので追加します。

１で作成したマイグレーションファイルを開く
※ファイルの場所は　dbファイル内　migrate/作成日時


　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2309717/608796f1-f375-315a-9347-c52d431f4435.png" width="80%">
マイグレーションファイルに　t.string :name　を追加しました。

```ruby:db/migrate/ 作成日時
データ型　：追加するカラム名
```

#3 データベースにマイグレーションする

```
$ rails db:migrate
```

コマンド実行後にルーティングを確認します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2309717/0ee14b74-b0ee-cb2c-655d-e9d410ac22d4.png" width="100%">
routes.rbに　ルーティングが自動追加されました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2309717/f5bdf235-d034-7126-4668-84cf836bc908.png" width="100%">


#4 strong parametersを設定する

追加したnameカラムをsign up時に変更許可する設定を行います。

Deviseのコントローラはライブラリで用意されているため直接変更ができません。
そのためapplication_controllerに記述します。

```ruby:application_controller
  before_action :configure_permitted_parameters, if: :devise_controller?
```


before_action :configure_permitted_parameters, 
　→後ろのif文の条件だったら実行の前にconfigure_permitted_parametersアクションを実行する　

ではif: :devise_controller？とは何か？
　→deviseのコントローラーが呼び出されたら（動いたら）

まとめると、
deviseコントローラーが動く前にconfigure_permitted_parametersアクションを実行しましょう　という意味になります。

次に、configure_permitted_parametersアクションの内容を記述します。

```ruby:application_controller
protected
  
  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys:[:name])
  end
```


```ruby
devise_parameter_sanitizer.permit(:deviseの処理名, keys: [:許可するカラム名])
```

devise_parameter_sanitizer
　→sanitizerメソッドはUserモデルのパラメーター（情報）を取得するメソッド

permit(:sign_up, keys:[:name])
　→sign_up時にnameのデータ操作を許可
　
before_actionからまとめると、
deviseコントローラーが呼び出された時、nameの変更を許可しますよ　といった感じになります。

#5 viewの変更
nameを使用する準備ができました。
しかしまだ入力部分がありませんので修正していきます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2309717/9f5da68a-9da5-257e-efcd-2df8683d1904.png" width="30%">

deviseであらかじめ準備されているviewのカスタマイズを行います。

```
 $ rails g devise:views
```

実行したら作成されたdevise/registrations/new.html.erbフォルダを変更していきます。

```ruby:devise/registrations/new.html.erb
<h2>Sign up</h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= render "devise/shared/error_messages", resource: resource %>

#↓追加
  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name, autofocus: true %>
  </div>
'
'
```

ブラウザで確認します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2309717/634d0142-458f-5cfb-cb97-a18d1c0e3752.png" width="30%">

Nameが追加されました！


**Deviseであらかじめ準備されているコントローラやビューの変更は通常とコードが異なるので注意**
Breast Cancer Datasetの列を入れ替える


https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/
からデータを入出する

<pre>
> wget https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/wdbc.data


StatusCode        : 200
StatusDescription : OK
Content           : {56, 52, 50, 51...}
RawContent        : HTTP/1.1 200 OK
                    Accept-Ranges: bytes
                    Content-Length: 124103
                    Content-Type: application/x-httpd-php
                    Date: Fri, 10 Dec 2021 09:53:46 GMT
                    ETag: "1e4c7-2ed02fd9c0780"
                    Last-Modified: Mon, 05 Feb 1996 ...
Headers           : {[Accept-Ranges, bytes], [Content-Length, 124103], [Content-Type, application/x-httpd-php], [Date,
                    Fri, 10 Dec 2021 09:53:46 GMT]...}
RawContentLength  : 124103
</pre>

Anacondaでwgetでファイルがとってこれない場合があるので、その場合はGUIからダウンロードするか、この辺りを参照する。

https://ja.stackoverflow.com/questions/43077/anaconda-%E3%82%92-wget-%E3%81%A7%E6%AF%8E%E5%9B%9E%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%97%E7%9B%B4%E3%81%95%E3%81%AA%E3%81%84%E3%81%A8-conda-%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%8C%E4%BD%BF%E3%81%88%E3%81%AA%E3%81%84

↓このようなデータ構成になっているので、２列目の M (malignant) を一番後ろの列に持っていきたい場合がある。

<pre>
> more .\wdbc.data
842302,M,17.99,10.38,122.8,1001,0.1184,0.2776,0.3001,0.1471,0.2419,0.07871,1.095,0.9053,8.589,153.4,0.006399,0.04904,0.05373,0.01587,0.03003,0.006193,25.38,17.33,184.6,2019,0.1622,0.6656,0.7119,0.2654,0.4601,0.1189
</pre>

このようなプログラムを書く

<pre>
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt

import sys
args = sys.argv 

df = pd.read_csv('wdbc.data', index_col=0)

print(len(df))
print(len(df.columns))

dataExchange = df.iloc[:, [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,0]]
print(dataExchange)

dataExchange.to_csv('tmp.csv')
</pre>

↓　このラインで２列目のM(またはB）を最後の列に持ってきている。

<pre>
dataExchange = df.iloc[:, [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,0]]
</pre>

結果

<pre>
> more .\tmp.csv
842302,17.99,10.38,122.8,1001,0.1184,0.2776,0.3001,0.1471,0.2419,0.07871,1.095,0.9053,8.589,153.4,0.006399,0.04904,0.05373,0.01587,0.03003,0.006193,25.38,17.33,184.6,2019,0.1622,0.6656,0.7119,0.2654,0.4601,0.1189,M
</pre>

参考

https://it-ojisan.tokyo/pandas-dataframe-exchange/

https://github.com/RuoAndo/time-series-analysis-with-Python/blob/master/pandas/1.py
作図するツール

# 作図するツールのリンク
* [robo-compas](https://www.robocompass.com/app) 教育用。子供が作図するときに見せるといいかも
* [Straightedge and Compass](https://www.geogebra.org/m/NDWRz5nG) 惜しい。分度器はあるけど、定規がない。できれば線に沿って図りたい
* [GeoGebra](https://www.geogebra.org/calculator) 作図ができる。計測もできる。めちゃめちゃすごい。最近のツールの進化に驚く（できるできないではなく、すごいツールが普通に使えてしまうことに）。年かな。。。
【Vue.js】TodoList 編集機能を追加

# 概要

[前回のtodoList](https://qiita.com/Quest_love33/items/30d7473ed9a760e0a8f9)に加えて編集できる機能を追加した。


# まずは全体像

* html

```html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="css/main.css">
    <title>Vue3</title>
</head>
<body>
    <div id="app">
        <h2>Todoリスト</h2>
        <form action="">
            <input type="text" v-model="newItem">
            <button @click.prevent="addItem">登録</button>
        </form>
        <hr>
        <ul>
            <li v-for="(todo, index) in todos">
                <input type="checkbox" v-model="todo.isDone">
                <span :class="{done: todo.isDone}">{{ todo.item }}</span>
                <!-- 更新 -->
                <div v-if="todo.isActive">
                    <span >
                        <input type="text" v-model="todo.item">
                    </span>
                    <button @click="updateDone(index)">完了</button>
                </div>
                <button @click="deleteItem(index)">削除</button>
                <button v-show="!todo.isActive" @click="updateItem(index)">修正</button>
                <hr>
            </li>
     
        </ul>
        <pre>{{$data}}</pre>

    </div>
    <script src="https://unpkg.com/vue@3.1.5"></script>
    <script src="js/main.js"></script>



</body>
</html>
```

* js

```js
const app = Vue.createApp({
    data(){
        return {
            newItem:'',
            todos: [],
        }
    },
    methods:{
        addItem(){
            if(this.newItem === '') return //入力欄が空だった時処理を終了
            let todo = {
                item: this.newItem,
                isDone: false,
                isActive: false
            }
            this.todos.push(todo)
            this.newItem = '' //todo登録後に入力欄を空にする
        },
        deleteItem(index){
            this.todos.splice(index, 1) //第一引数は削除する配列, 第二引数は削除する範囲

        },
        updateItem(index){
            this.todos[index].isActive = true
            this.todos[index].item = this.todos[index].item
        },
        updateDone(index){
            this.todos[index].isActive = false
        }
    }
})

app.mount('#app')
```

* css


```css
#app li > span.done {
    text-decoration: line-through;
}

#app ul{
    list-style: none;
}
```

# 追加した点

* ボタンイベントのmethodsを二つ追加。
    * updateItem(index)
        * 修正する時のボタン
    * updateDone(index)
        * 修正が完了した時のボタン
* dataプロパティにisActiveプロパティを追加
    * v-ifにisActiveをセット
    * 修正ボタンを押した時にtrueに変更
        * 修正可能なinput要素を表示する
        * 修正完了ボタンを表示する。
        * 修正ボタンをv-showでfalseにして非表示にする。
1年ぶりにAmazonTranscribeの機能を調べてみた

# はじめに  
この記事は株式会社ナレッジコミュニケーションが運営する [クラウドAI by ナレコム Advent Calendar 2021](https://qiita.com/advent-calendar/2021/knowcom-cloudai) の11日目にあたる記事になります。
今回は1年前に少し触って記事を書いたAmazonTranscribeというサービスの新機能について確認してみたいと思います。
過去の記事は[こちら](https://qiita.com/izu_know/items/7454ca01ff5228c23e72)です。

## Real-time transcription
こちらは以前から大きく変わった箇所があります。
以下の画像にある自動言語認識別機能です。
![2021-12-10_17h02_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/380837/bf30a02c-f367-4e70-a370-55df4c42430c.png)
この機能は最短で音声データの最初の3秒でどの言語が使われているかを把握しその言語で文字起こしを始めてくれるというものです。
まだすべての言語対応しているわけではないのですが[こちら](https://docs.aws.amazon.com/transcribe/latest/dg/lang-id.html)のドキュメントでサポートされる言語にストリーミングの記載がある言語が対応しているようです。

こちらの自動言語認識別機能はすべてのリージョンで使用できるわけではなく現在は以下のリージョンであれば使用できるようです(2021/12/10現在)
・米国東部（オハイオ）
・米国東部（北バージニア）
・米国西部（オレゴン）
・アジア太平洋（ソウル）
・アジア太平洋（シドニー）
・アジア太平洋（東京）
・カナダ（中央）
・ヨーロッパ（フランクフルト）
・ヨーロッパ（アイルランド）
・ヨーロッパ（ロンドン）
・南アメリカ（サンパウロ）

## Amazon Transcribe Call Analytics
こちらはコールセンターや電話応対の多い部署での使用に役立つ機能となっています。
![2021-12-10_17h51_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/380837/9dd9cd36-0d78-2f5a-dc60-cc30683f32d7.png)

主な機能として
■21言語でタイムスタンプ付き音声案内通話文字起こし
■問題の検出。話者の交代時に、顧客が電話をかけている理由を表す最短の単語列を拾い出します。設定やトレーニングなしでそのまま使用できます
■会話特性に基づく通話の分類:
・特定の語句の照合
・非通話時間の検出
・中断の検出
・顧客とエージェントのセンチメントを分析
■通話特性:
・顧客やエージェントの話す速さと声の大きさ
・非通話時間の検出
・中断の検出
■文字起こししたテキストに対応する音声ファイルから機密データを削除。
といった機能があります

顧客との会話の際に顧客が何を必要としているかを通話の文字起こしの中から自動で検出することがで検出された顧客の問題は文字起こし上で太字で強調されわかりやすく表示されます。
この機能は対応者にとってもありがたい機能ですがもし顧客が応対者以外の対応を求めた際にも有用となります。

対応を引き継ぐことになった人が顧客の問題に対してどういったアプローチを行っていたのかということがわかるので別のアプローチから顧客の問題を解決するための指標になるためです。
会話が終わった後には会話全体の1/4ごとに顧客と対応者のセンチメントがどういったように移行したかということがわかるようにもなっています。

顧客のセンチメントが会話のどのあたりから肯定的に変わっていたのかということが分かれば別の顧客対応時に参考にすることが可能です。

文字起こししたテキストをWordに変換することのできるツールもありそのツールを使用することでさらに全体の会話の中で顧客と対応者、誰も喋っていない時間がそれぞれ何%ほどあったのかということも分かります。

現在この機能は以下のリージョンで利用可能です。(2021/12/10現在)
・米国西部 (オレゴン)
・米国東部 (バージニア北部)、
・カナダ (中部)、
・欧州 (ロンドン) 
・欧州 (フランクフルト) 、
・アジアパシフィック (ムンバイ)
・アジアパシフィック (シンガポール)
・アジアパシフィック (ソウル)
・アジアパシフィック (シドニー)
・アジアパシフィック (東京)。

#まとめ
今回は前回記事を書いてからAmazonTranscribeにどういった機能の追加が行われたのかということを調べてみました。
大きく２つの機能だけ記載しましたがこの２つの機能だけでもかなり大きなアップデートが行われていると感じました。
実際に試せていないので気になっているのですが自動言語認識別機能を使用した際に複数の言語が混じっていた際は主要言語以外はどういった扱いになるのかということについても調べていきたいと思います。

###参考記事
[https://aws.amazon.com/jp/transcribe/](https://aws.amazon.com/jp/transcribe/)
[https://aws.amazon.com/jp/blogs/news/extract-insights-from-customer-conversations-with-amazon-transcribe-call-analytics/](https://aws.amazon.com/jp/blogs/news/extract-insights-from-customer-conversations-with-amazon-transcribe-call-analytics/)
[https://aws.amazon.com/jp/about-aws/whats-new/2021/11/amazon-transcribe-language-identification-streaming-transcription/](https://aws.amazon.com/jp/about-aws/whats-new/2021/11/amazon-transcribe-language-identification-streaming-transcription/)
コードレビューするときに心がけていること

# はじめに

以前に比べて人の書いたコードをレビューする機会が増えたので、普段レビューするときにどういったところを見ているか、何を考えているかを一度言語化して形に残しておこうと思います。

# コードの中身について

「レビュー時に指摘できること ＝ 自分が書くときに気を付けられること」で、それ以上の指摘は出来ないと思います。レビューのやり方に悩んでいる人は、**まず自分が良いコードを書けるようになりましょう**。その上で本記事のように一度言語化をしてみると頭が整理できて良いと思います。
以下に自分が意識していることを列挙してみました。「[リーダブルコード](https://www.oreilly.co.jp/books/9784873115658)」と被っている箇所も多いので、そちらも参照ください。

- **誤字脱字 (typo)**
    - 放置する理由がない。
- **コードの見た目**
    - 一時変数への代入や横に長い行に改行を挟む、コードの「縦のライン」を揃えるなど。
- **命名**
    - `data`, `result`などの抽象的な名前は避ける。
- **深いネスト**
    - 早期return・ガード節に直す。
- **適切な単位でメソッド、クラスに切り出す**
    - 長過ぎるメソッド、クラスはそれだけで読むのがコスト。切り出して適切な名前を付けましょう。
- **処理が冗長でないか**
    - 例： 求める結果に対してループが多すぎる、必要のない処理をループ内で行っている、不要な処理を早期returnで弾いていない、など。
- **不要なコードが残っている**
    - 削除差分に関連する使われなくなったコードは放っておくと埋もれてしまうので、不要なら**今**消しましょう。
- **コメント**
    - 単純な記述不足、記述とコードの乖離、言い回しが分かりにくいなど。
- **関連する機能への影響**
    - 修正対象に依存した別機能に影響がないか。
- **ユーザー入力値のバリデーションがない**
- **テストコードがない**
- **分かりやすい/親切なUI/UXであるか**

# 心持ちの話

## 性悪説的にコードを読む

性善説的にコードを読んでしまうと、「XXさんが書いたコードならまずバグらないだろうしヨシ！」といった具合にザルめいたレビューになる恐れがあり、バグを生む可能性が高くなります。
コードレビューに臨む際は、「**他人の書いたコードには大抵何かしらバグがあるし処理も改善の余地がある**」という想定でいた方が良いです。仮にバグもなく書き方も完璧なコードだったとしても、そういった心持ちでいたほうがレビュワー自身もコードを真剣に読むようになると思います。

## 分からないことはすぐ聞く

レビュー依頼を受けたコードや周辺機能に自分が詳しいとは限りません。もちろんコードや（あれば）資料を読みはしますが、それでも実装の背景や意図が読み取りきれない場合もあります。そういった場合は**長時間悩む前に開発者に質問しましょう**（このとき「自分はどう理解したか」も添えると吉）。書いたコードに一番詳しいのは開発者自身のはずなので、欲しい答えが返ってくるはずです。

# まとめ

- まずは自分自身が良いコードをかけるようになろう。
    - リーダブルコードを読もう。
- 性悪説的にコードを読もう。
- 分からないことは開発者に聞こう。
テストコードの書き方の基本を抑える

# テストを書こう
テストは必要だと思ってるけどどうすればいいのかわからない人のためのあれそれです。

# 大事なこと
- ユニットテストですべてを確認しようとしない。
    - ユニットテストで確認できるのは関数が規定した動作を行うかどうかだけです。
    - システムとして正しいかどうかはユニットテストだけでは確認できません。

# 対象を決める
パッケージやクラス、モジュールの単位でテストする対象を決めましょう。
新しく作った機能、修正があった機能が基本はターゲットになると思います。
慣れないうちは入力と出力がわかりやすい関数を選ぶと良いでしょう。

# ツールを用意する
世に存在するすべてのプログラミング言語にはテストツールが作られています。
テストツールには様々な機能がありますが、
共通して テストケースを作成し、テストケース毎の検証結果を出力する機能があります。
テストケースは 条件を設定して関数を呼び出し、結果を想定している結果と比較するというセットをいいます。

# 面倒なものはモックにする
データベースやsmtp等、用意すると面倒くさいもののインターフェースを叩く実装のテストはモックを活用しましょう。
大体のテストツールにはモックアップの仕組みが用意されています。
大雑把に、 内部で呼ばれている関数を別の関数に置き換えることができます。

データベースに接続するのであればDBに対するSQLがあっていれば問題が有りません。
そのSQLがシステムを正しく動作させるかは次の段階で行うことです。

基本的に外部のインフラを使うようなものはモックアップすると楽です。

# テストケースの作り方
プログラムは入力・状態・出力を持ちます。
入力は引数です。
状態は環境変数等、入力によって変化しうるパラメータです。
出力は入力と状態によって決まる返り値です。
この3つが適切に把握できていればテストコードは簡単に書けます。

## 入力を決める
### 対象の条件分岐を網羅する入力を考える
まず、switch、ifなどの条件分岐を探します。
すべての分岐をチェックできるよう入力を上げていきます。
下記のようなコードの場合、xが4以下,5以上の場合をそれぞれ抽出します。

```c
if(x<5){}
```

enumを文字列に変換するような実装の場合、面倒でもすべてのenumをパターンとして抽出したほうが良いです。
よくバグが発生しますし、目視での抽出が難しいです。


### 条件分岐の境界を確認する
文字数によるバリデーションだったり、数字のmin/max等の条件がある場合、min,min-1やmax,max+1などのルートが変わる境界の確認を行いましょう。
境界値は>= や> などの取り違えが非常に発生しやすいです。

```c
# x=4,5を抽出する
if(x<5){}
# y=１，２を抽出する
if(y>=2){}
```

## 状態を決める
### アプリケーションの状態を決める
in-memory cacheや呼び出し回数の保持などアプリケーションの内部状態で処理が変わる部分があるのであれば、状態を抽出しておきます。
状態を変更する関数をテスト対象実行前に呼び出すであったり、テストコードから無理やり書き換えたりなどを行って状態を作り込んでいきます。

### モックのステータスを決める
DBがエラーを起こした場合などのパターンもチェックする必要があります。
モックの機能で返り値の編集や例外を発生させるなどができますので必要なモックの状態を作り込みましょう。
APIの404(NotFound)や409（Conflict)等、外部とのやり取りで処理が変わる部分を網羅していきます。

## 確認観点を決める
### 入力に対する出力をチェックする
関数の返り値を想定した値と比較します。
テストツールでassertってあったらだいたいこの比較を行っています。
 
### アプリケーションの状態の変化をチェックする
試験対象の関数がアプリケーションの状態を変更するものであることがあります。
その場合、関数実行後のアプリケーションの状態が想定されたものと一致するかを比較しましょう。

### モックの呼び出し状況をチェックする
モックツールは呼び出された回数や呼び出されたパラメータを保持しています。
これらのパラメータを確認するようにしましょう。

# テストコードを活用しよう
機能改修を行う際に、先に想定する動作のテストを書いてから、実装を修正していくやり方を行ったり（＝テスト駆動開発）
改修によって変更したところ以外が動かなくなっていないかを確認したりします。
脆弱性を生み出しかけた話

#忘れもしない2021年夏
ITエンジニアになって１年と半分が過ぎて仕事にも慣れてきた時でした。
その時の業務は開発しているサービスのページに広告を表示して、そこを叩いたらあらかじめ設定されていたページへとばすものでした。

順調に実装を進めていって、問題がないか動作を確認していました。
その時は検証用の環境にデプロイをして確認をしていました。検証用の環境は自分以外にチームのメンバーも見れます。

その時にメンバーのベテランエンジニアさんからありがたいお言葉をもらいました。
「これ広告以外にも飛ばされね？」

実はパラメータには飛ばされる先のURLを仕込んでいて、広告をクリックしたときにそのURLに飛ばすようにしていました。
（あとから知ったのですがこの脆弱性を利用して意図しないリダイレクトを行わせることをオープンリダイレクト攻撃といいます）

この時は結構ヒヤッとしました。


#対策
オープンリダイレクト攻撃には対策として以下の2点があります

####そもそもパラメータで渡さない
穴があるなら埋めればいい。
外部パラメータで渡すのをやめれば、攻撃の穴を防ぐことができます。

####URLのホワイトリストを作る
あらかじめリダイレクトを行うURLをホワイトリストとしてサーバ内に置いておき、リダイレクトを行う際にチェックを行う方法です。

#それから
この一件があってからセキュリティに向き合おうと思って勉強を始めました。
今はまだまだ知識はないかもしれませんが、この頃に比べたら多少の知識がついたのと、セキュリティに意識をした開発を進められているのかなと思います。
余談ですがセキュリティの勉強を始めた頃、どの本もなかなかの分厚さがあって苦労しました。
そこで偶然、IPAの「安全なウェブサイトの作り方」という資料（**無料**）を見つけたのでこれからセキュリティを勉強する方にはおすすめです。
ページ数も100ページほど短く、簡潔でわかりやすく、１年ごとに改訂があるので新しい情報を得ることができます。

#参考
安全なウェブサイトの作り方
https://www.ipa.go.jp/security/vuln/websecurity.html
HTML Paserで連続ダウンロード

# はじめに
Automation 360の「ブラウザ／ファイルをダウンロード」は1個のファイルをダウンロードします。
ダウンロード用Webページに複数の落としたいファイルがあって、それらを全てダウンロードするときはループさせなければならない。
ダウンロードファイルのURLが規則的な名前になっていたらいいですが、そうでない場合ちょっと面倒。
そういった場合、HTML Paserパッケージを使うと楽に実現できる場合があります。

# 郵便番号データを落としてみる
サンプルとして以下から郵便番号データ(zipファイル)をダウンロードします。
https://www.post.japanpost.jp/zipcode/dl/kogaki-zip.html

大まかな流れは以下。
(1) 郵便番号データのWebページを表示。
(2) WebページのHTMLを読み出す。
(3) 読みだしたHTMLをHTML Paserにかけてダウンロードファイルの一覧をリスト変数で作る。
(4) リスト変数をループさせ、その中でファイルダウンロード。

先に完成品のイメージをつけておきます。
![htmlpaser01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632535/ad4c4e7f-7d89-24d7-3d35-fbc7cba33d80.jpeg)

# HTML Paserの入手
HTML PaserはAutomation 360に標準で入っていないためBot Storeから入手します。
https://botstore.automationanywhere.com/bot/a2019-html-parser-package

Automation Anywhere社が提供しているもので無償です。

# HTML Paserの使い方
HTML Paserパッケージにはいくつかのアクションがありますが、ここではSearch with Selectorを使いました。
![htmlpaser02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632535/57fd80a6-b915-28e2-336f-b857ced1e0c7.jpeg)

変数\$prompt-assignment\$には「ブラウザ: ソースコードを取得」を使い、WebページのHTML全体を読み込んでいます。

ブラウザ上で「右クリック／ページのソースを表示」して、HTMLソースを先に見ておきます。
![htmlpaser03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632535/74f6b52f-0c11-358a-47e0-3f7f20154031.jpeg)

ダウンロードしたいzipファイルは、
\<tr class="arrange-c"\>タグの下の\<td\>の下の\<a\>タグで定義されている事がわかります。
このとき、Search with SelectorアクションのSelector欄で以下のように指定します。

```
tr.arrange-c>td>a
```

また、List of Elements of type Dictionary欄に解析結果を出力するリスト変数を指定します。
これでSelector欄の条件にあったタグの情報がリストに入りますのでループで処理できます。
ここではparseListという変数に格納しています。

# ループ処理
ループでparseList変数の各項目に対して回します。このとき、「現在の値を変数に代入」で辞書変数を指定します。ここではListItemDicとしています。
![htmlpaser04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632535/b2ba004d-4c33-aa93-039c-a826035bebd7.jpeg)

少し難しいのはListItemDicはディクショナリ（辞書）形式になっている点です。
検出した箇所全体はhtmlというキーに入っています。すなわち\$ListItemDic{html}\$です。
例えばループの最初では「\<a class="inline" href="kogaki/zip/01hokkai.zip">北海道\</a>」が入っています。
\$ListItemDic{html}\$から「文字列: テキストを抽出」を使いzipファイルをURLを作り、それを「ブラウザ／ファイルをダウンロード」にかけたのが一番最初の画像です。

# ちょっとしたハマりどころ
- 「ブラウザ: 開く」と「ブラウザ: ソースコードを取得」の間に遅延入れておかないと、ソースコードを取得でエラーになりやすい。
- 「ブラウザ: ソースコードを取得」はChomeしか使えない。

#  さいごに
ここまで書いておいて今さらですが、
こういうのって、いわゆる「ダウンローダー」を使った方が楽かもしれません。

何でもかんでもRPAでやるのではなく、適材適所で柔軟にやりましょう。
備忘録: JavaScript fetchの結果がReadableStreamで読み込めない場合

## fetchした時の結果がstringなら
```
fetch(url)
.then((res) => res.text())
.then((data) => console.log(data))
```

## fetchした結果がjsonなら
```
fetch(url)
.then((res) => res.json())
.then((data) => console.log(data))
```

## 参考にした記事
https://stackoverflow.com/questions/40385133/retrieve-data-from-a-readablestream-object
K8s の YAML ファイルを書くために VScode 拡張機能を使用する@Windows10 Home

#はじめに
拡張機能が豊富な VScode を使用して Kubernetes の YAML ファイルを楽に書くのが目的 
※1. 今回が初めての投稿となるので多少見にくい場合があるがそこはご愛顧…
※2. 随時更新

#インストール
インストールはすでに済ませている方はスキップしてください。

私は下記の記事を参考にインストールしました。

https://eng-entrance.com/texteditor-vscode

▼インストール先 URL

https://azure.microsoft.com/ja-jp/products/visual-studio-code/

▼自宅 PC 環境
CPU：第10世代 インテル Core i7 
ストレージ容量：M.2 SSD：1TB 
メモリ容量：16GB
 OS：Windows 10 Home 64bit

#Kubernetes 拡張機能のインストール
■手順
1. VScode を起動して「拡張機能」より Kubernetes と入力
2. インストールしよう
3. 再起動して左下に Kubernetes のロゴがあることを確認する

:::note warn  
注意
依存性の関係で「Install dependencies」が出てくる場合は
「Install dependencies」をクリックしインストールしてください。
::: 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612700/754cf3c3-b3b9-494f-1237-c30699313747.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612700/7929c5d2-8447-d0ae-c1dd-88c8e7e551bc.png)

#使ってみよう!
■手順
1. 作業開始から「新しいファイル」をクリックし、プレーンテキストを開く
2. 右下にある「プレーンテキスト」をクリックして、YAML を選択する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612700/388ced99-71fe-58a7-7d66-8e4e38a70b3e.png)

3  試しに **pod** と打ち込んでみる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612700/dd25ca86-c37e-7ecb-72b8-5b45f4b496ba.png)

4 ほぼ完成に近い状態でコードが出力されたぞ!!

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612700/4c4ba57e-9633-c368-af87-845bb4edfe4c.png)

他にも「deployment」なども出力候補がありまだまだ使える機能が多そうだ

#最後に
とりあえず yaml ファイルを書くためのエディタは用意できた
随時情報を更新していき、皆様に少しでも有益な情報を提供できるように勉強します
新卒1年目が1週間でAZ-104(Microsoft Azure Administrator)合格

# はじめに
新卒1年目の私が、勉強期間1週間でAZ-104(Microsoft Azure Administrator)に合格したため、何を使って学習を進めたのか記載する。
※この記事は個人の経験で語っているため、合格を保証するものではありません。

# 自身のAzure経験
[Microsoft Learn Student Ambassador](https://studentambassadors.microsoft.com/)として2020年7月から活動していたため、Azureを用いた開発経験はある程度（ハッカソンで利用した程度）持っている状態でした。
また、AZ-900を取得済みで、多少Azureに関する知識がある程度でした。

# 勉強方法
[Microsoft Learn](https://docs.microsoft.com/ja-jp/learn/)と[Udemy](https://www.udemy.com/)を活用して勉強しました。
試験申し込みを先に行い、勉強は1週間前からスタートさせました。

## Microsoft Learn
- [【一夜漬けシリーズ】AZ-104: Microsoft Azure Administrator【約41時間】](https://docs.microsoft.com/ja-jp/users/tottokug/collections/8xz4sz838p2dww)
    - 正直、この内容をすべて理解できれば十分

## Udemy
- [AZ-104: Microsoft Azure Administrator 模擬問題集](https://www.udemy.com/course/az-104-microsoft-azure-administrator-practice-test-jp/)
    - 試験前日に最終確認として行う

# 試験後の所感
合格することのみが目的であれば、過去問を繰り返し解くのみで合格は可能だと思います。
しかし、それでは実力が身に付かないため、開発経験の少ない方は[参考書](https://www.amazon.co.jp/%E5%90%88%E6%A0%BC%E5%AF%BE%E7%AD%96-Microsoft%E8%AA%8D%E5%AE%9A%E8%A9%A6%E9%A8%93AZ-104-Microsoft-Azure-Administrator%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%EF%BC%86%E6%BC%94%E7%BF%92%E5%95%8F%E9%A1%8C-ebook/dp/B09HT3HX8W)や[Udemy](https://www.udemy.com/)、[Microsoft Learn](https://docs.microsoft.com/ja-jp/learn/)を用いて学習を進めることをお勧めします。
Windows10 21H2で英語配列のBluetoothキーボードを追加して日本語キーボードと共存させる設定

## はじめに
眠っていたTablet PCに、日本語キーボードを繋いだら、以前に使っていた英語配列のキーボードの設定が原因で英語配列として認識されてしまいました。試行錯誤して同時に接続して共存させる方法を見いだせたので、情報を共有させていただきます。

## 前提
* Windows 10 Home 20H2, 21H2
* 日本語キーボードで正しく動くように設定してある
* Bluetoothの英語配列キーボードを追加する
* レジストリを編集する

※ まっさらな状態からの動作確認はしていません。
※ Windows10 Home 21H2にアップしても有効でした。

## こだわりどころ
* Tablet PCでスクリーンキーボードを常に日本語モードで起動できる<br>(デフォルトキーボードが存在しないので)
* レジストリの編集を必要最小限にとどめる

## レジストリ編集手順
### デフォルト設定を変更する
* システム標準のキーボード設定：2つ削除して1つを変更

```:レジストリ
  HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\i8042prt\Parameters
```
  キー|値：変更前|値：変更後
  -|-|-
  LayerDriver JPN|kbd106.dll|(変更なし)
  OverrideKeyboardIdentifier|PCAT_106KEY|PCAT_101KEY
  OverrideKeyboardSubtype|2|キーを削除
  OverrideKeyboardType|7|キーを削除

### 追加したキーボードを英語設定にする
* デバイスマネージャでBluetoothに出てくるキーボードのプロパティの詳細から「デバイスインスタンスパス」をコピーして下記に連結

```:レジストリ
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\
```
* `FriendlyName`でデバイスを確認し、`ContainerID`の値をコピーして検索
* `Service`が`kbdhid`であることを確認する(違っていれば次を検索)
* その下にある`Device Parameters`を選択
* 以下に2つのキーをDWORDで追加

  キー|値
  -|-
  KeyboardTypeOverride|4
  KeyboardSubtypeOverride|0

* 以上の編集が終わったらWindowsを再起動

## 試したこと
* Bluetoothキーボードのデバイスインスタンスパス(`BTHENUM`以下)の`Device Parameters`にキーを追加しても認識されなかった
* 「HIDキーボードデバイス」のデバイスインスタンスパス(`HID`以下)の`Device Parameters`への設定のみが反映されることが確認できた
* 「HIDキーボードデバイス」の`Device Parameters`への設定がない場合は`LayerDriver JPN`の値によって動作モードが設定される
* 「HIDキーボードデバイス」が複数あったので、特定に手間取った<br>(特定後`FriendlyName`を追加してキーボード型番を設定した)
* BluetoothのデバイスインスタンスとHIDデバイスの対応がよくわからなかった<br>(結局`ContainerID`で検索するしか思いつかなかった)
* 英語配列をデフォルトにする場合は、下記の組み合わせにすると共存できた<br>(英語キーボードには設定をしない)
  * デフォルト設定 

```:レジストリ
  HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\i8042prt\Parameters
```
  キー|値
  -|-
  LayerDriver JPN|kbd101.dll
  OverrideKeyboardIdentifier|PCAT_106KEY

   * 日本語キーボード`HID`以下の`Device Parameters`追加設定（DWORD)

  キー|値
  -|-
  KeyboardTypeOverride|7
  KeyboardSubtypeOverride|2


## 参考
[Windows10(1909, 20H1, 20H2)でHHKB英語版とパソコン内蔵日本語キーボードを共存させる方法](https://gadgetsmartphone.net/windows101909%E3%81%A7hhkb%E8%8B%B1%E8%AA%9E%E7%89%88%E3%81%A8%E3%83%91%E3%82%BD%E3%82%B3%E3%83%B3%E5%86%85%E8%94%B5%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%82%AD%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89%E3%82%92/)
[Windows で US 配列と JIS 配列を共存させたい](https://tyheeeee.hateblo.jp/entry/2018/08/21/Windows_%E3%81%A7_US_%E9%85%8D%E5%88%97%E3%81%A8_JIS_%E9%85%8D%E5%88%97%E3%82%92%E5%85%B1%E5%AD%98%E3%81%95%E3%81%9B%E3%81%9F%E3%81%84)
他にもいろいろ参考にさせていただきましたが、私の環境では上記の2例を含めて、どの方法でもうまくいきませんでした。(たぶん`OverrideKeyboardIdentifier`が変更されていたから)

## 終わりに
Bluetoothなので手順が複雑になりますが、何とか設定個所を特定する方法が見つかったので良しとしましょう。USB接続であればもっと簡単なのですが...
英語キーボードをベースにすると、スクリーンキーボードの配列が、直前に使用した物理キーボードのモードに依存して切り替わるので、見た目も似ていて誤入力の原因になりそうでした。日本語キーボードよりキー数が少なくてすっきりしたレイアウトだったので、そちらの方が良かったのですが、勝手に切り替わらないようにする設定を見つけられなかったので諦めました。

## 追記
* 設定の確認・変更・復元するツールを下記に公開しています。(2022/8/16)
    * https://gitlab.com/e4rfx/dula
* 設定を確認するPowerShellスクリプトを公開しました。良かったら参考にしてください。(2022/3/5)

https://qiita.com/e4rfx/items/5eb658d3faff1a4c93ab
2022年の私の勉強テーマ選定(前半)

## 前提条件
 
私事なのですが、毎年この時期に気になるテーマ(言語だったりフレームワークだったりテクノロジーだったり)を２，３個選んで翌年の「学習目標」に設定して勉強してたりします。
もちろん、それだけを勉強するわけではないのですが、軸になるように考えつつ毎月勉強してます。
今まではひっそり一人でやってましたが、初めて公開してみます。
というわけで、来年の勉強テーマは、フロントエンド＋バックエンドでやろうかと考えてます。

## 参考：普段使っている言語(仕事＋プライベート)
・VB(.Net-froms,VBS,VBA,WSH,ASP) / C#(.Net-froms)
・PHP / Python / SQL(PLSQL)
 まぁ、大体仕事用ですねｗ
 DB廻りとか、バックエンド多め＋Windowsクラサバ

## 2021年に勉強した言語
<dl> 
 <dt>Go言語 </dt>
<dd>面白い言語です。<br />
まだまだ引き続き勉強を続けたい。  </dd>
</dl>

<dl>
<dt>TypeScript</dt>
<dd>フロントエンドの勉強したくて始めました。</dd>
</dl>

## 2022年の勉強テーマ
さて、来年は何を勉強しようかな。
フロントエンドの何かと言語一つの習得を目標にしてみたい。
というわけで、本題です。

## 今気になっている言語と特徴
<dl><dt>Rust</dt><dd>wikiによると性能、メモリ安全性、安全な並行性<br />TIOBE Index for December 2021で27位</dd></dl>
<dl><dt>Julia</dt><dd>wikiによると高速、<br />他言語(c言語,FORTRAN,Python)との連携が容易、科学技術計算が得意！？<br />TIOBE Index for December 2021で35位</dd></dl>
<dl><dt>v言語</dt><dd>Go言語に似ている。<br />TIOBE Index for December 2021で順位なし</dd></dl>

## 今気になっているフロントエンドフレームワーク
・Vue.js
・angular
・React

後半でそれぞれ詳細を調査して2022年に備えます。
（続く・・・）