OmniAICreator/Qiita-1.07M huggingface dataset:
Next.jsとCloudFunctionsでGoogleReCAPTCHAを設置する方法

皆さんセキュリティ対策ってどのようにされていますか？

私はセキュリティについてそこまで詳しくないので、個人で開発する際にはGoogleReCAPTCHAを多用しております。

とても便利ですし、なんと言っても簡単！

そんなGoogleReCAPTCHAをNext.jsで使用する方法をお教えします。

素のReactでも同じように出来ますので、ぜひ活用ください。

それでは説明していきます！

# ReCAPTCHAの設定

[こちら](https://www.google.com/recaptcha/about/)の「V3 Admin Console」から、新しいサイトを登録してください。

・ラベルは何でもよいです
・タイプはV3を選んでください
・ドメインは使用するドメインをご入力ください。
例： localhost, example.vercel.app

登録するとサイトキーとシークレットキーが表示され、後で使うのでどこかにメモしておいてください。

# パッケージのインストール

Next.jsのプロジェクトで``react-google-recaptcha-v3``をインストールして下さい。

```bash
npm i react-google-recaptcha-v3
```

``_app.tsx``にて、``GoogleReCaptchaProvider``でラッピング


```_app.tsx
import { GoogleReCaptchaProvider } from "react-google-recaptcha-v3";

// 省略

return (
    <GoogleReCaptchaProvider
       reCaptchaKey= "サイトキーをここに入れる"
       language="ja"
    >
        <Component {...pageProps} />
    </GoogleReCaptchaProvider>
)
```

そしたらトークンを発行してみましょう！

```recaptcha.tsx
import { useGoogleReCaptcha } from "react-google-recaptcha-v3";

const { executeRecaptcha } = useGoogleReCaptcha();

const handleReCaptchaVerify = async () => {
        if (executeRecaptcha) {
            const token = await executeRecaptcha("example");
            console.log(token)
        } else {
            alert("エラーが発生しました")
        }
    };
```

ボタンのクリックイベントとかで``handleReCaptchaVerify ``を実行してみましょう。

コンソール画面で長い文字列が出力されればOK！

次は、ここで発行したキーをもとにReCAPTCHAの検証を行ってみましょう。

# CloudFunctionsの設定

https通信を行うので、ご自身の好きなパッケージを使ってください。

この記事では``axios``を使います。

```index.ts
exports.VerifyRecaptcha = functions.region("asia-northeast-1").https.onRequest(async (req, res) => {
    // フロントで発行したトークンを受け取る
    const token = req.query.token;

    // 
    await axios
        .post(
            `https://www.google.com/recaptcha/api/siteverify?secret="シークレットキーを入れる"&response=${token}`,
        )
        .then((result) => {
            console.log(result.data)
        })
        .catch(() => {
            throw new functions.https.HttpsError("internal", "Internal Server Error");
        }))
```

```bash
{
    success: true,
    challenge_ts: '2021-08-28T07:22:42Z',
    hostname: 'localhost',
    score: 0.9,
    action: 'example'
}
```

このようなデータが出力されればOK！

``success``が``false``なら認証失敗となり、``score``が大体``0.5``以下であればスパムの可能性が高いです。

なので、セキュリティをどれだけ強くするかによってそこは変えてみてください。

ちなみにCloudFunctionsでなくても、AWSのLamdaでも実装出来ます。（検証はしていない）

いかがだったでしょうか？

セキュリティ対策を全て自分で行うとなるとかなり面倒ですよね。

なので、GoogleReCAPTCHAが気になる方はぜひ使ってみてください！

以上、「Next.jsとCloudFunctionsでGoogleReCAPTCHAを設置する方法」でした！

Thank you for reading
【DynamoDB】AWSのDynamoDB設定項目について調べてみた

#はじめに
前回は、Lambdaの記事を作成しましたが、
今回は、DynamoDBの設定項目について記載していこうと思います。

最終的には、LambdaからDynamoDBへの読み書きを行えたらなと思っています。

AWS初学者ですので、謝った内容を記載してしまっていたらすみません。
参考程度にお願いします。（業務などで使用する場合は公式を参考にしてください。）

##DynamoDBとは
>Amazon DynamoDB は、規模に関係なく数ミリ秒台のパフォーマンスを実現する、key-value およびドキュメントデータベースです。

>これはフルマネージド型でマルチリージョン、マルチアクティブで耐久性があるデータベースであり、セキュリティ、バックアップと復元、インターネット規模のアプリケーション用のインメモリキャッシュが組み込まれています。

>DynamoDB は、1 日に 10 兆件以上のリクエストを処理することができ、毎秒 2,000 万件を超えるリクエストをサポートします。

１日に１０兆件、毎秒２０００万件のリクエストをサポート・・・。
これをすぐに利用できる何て化け物ですね(笑)

##設定項目

DynamoDBを利用する上で変更することができる設定項目について記載します。

###テーブル名
DynamoDBには、DBを作る必要がなく、いきなりテーブルを作成します。
テーブル名はそのままの意味でテーブルの名前を設定します。

###パーティションキー
いわゆる、プライマリキーの事ですね。
idとかを設定するのが一般的なのでしょうか。

###ソートキー
ソートキーは、テーブルのプライマリキーの 2 番目の部分として使用できます。
ソートキーにより、同じパーティションキーを共有する全ての項目をソートまたは検索できます。
設定は任意になります。

例えば、以下のようなアーティストのテーブルを作成したとします。

| name（プライマリキー） | music | release |
|:-:|:-:|:-:|
| いきものがかり  | ブルーバード  | 2007年  |
| いきものがかり  | じょいふる  | 2006年  |

プライマリキーを`name`にすると、いきものがかりだけでは複数の曲がヒットします。
この時、ソートキーを`music`に指定すると、一つのレコードを取得できます。

パーティションキーだけでは絞り込めない時に、ソートキーを利用するっぽいです。

###キャパシティーモード
オンデマンドとプロビジョンドの２つのモードがあります。

・**プロビジョンドモード**
読み取り/書き込みキャパシティーを事前に割り当てることで、
コストを管理および最適化します。

プロビジョンドモードでは、読み込みキャパシティユニット（RWU）と、
書き込みキャパシティユニット（WCU）を指定します。

WCUを５、RCUを１０にしたとすると、
１秒間に５回の書き込み、１０回の読み込みが行えます。
料金はキャパシティユニットの個数により変わります。

キャパシティユニットの設定値を超えたリクエストが来た場合にはエラーが発生します。

・**オンデマンド**
アプリケーションが実行する実際の読み取りと書き込みの料金を支払うことで、
請求を簡素化します。

１００万のリクエスト毎に料金が発生するそうで、
事前にキャパシティの設定を行うことなく利用が可能ですが、
料金がプロビジョンドより高いのがデメリットになります。

###Auto Scaling
プロビジョンドモードでのみ指定可能な機能になります。

以下のリクエスト料のサービスがあったとします。

|| リリース時 | 5年後|
|:-:|:-:|:-:|
| 書き込み  | 50 回/秒  | 100 回/秒  |
| 読み込み  | 100 回/秒  | 200 回/秒  |

上記のリクエスト料に対してのキャパシティユニットは以下の通りです。

|| リリース時 | 5年後|
|:-:|:-:|:-:|
| WCU  | 50  | 100  |
| RCU  | 100  | 200  |

リリース時は、５０WCUと１００RCUで足りますが、
2年後はリクエスト料が増えていることが想定できるので、
毎年、もしくは、毎月キャパシティユニットを変更する必要が出てきます。

最初から１００WCUと２００RCUにしても良いのですが、
リリース時から数年間は無駄な料金を支払う可能が出てきます。

ここで便利なのが、Auto Scalingで、上限と下限を指定すれば、
その中で自動的にキャパシティユニットの量を調整してくれます。

Auto Scalingを利用すれば、運用の効率が上がるということです。

###ターゲット使用率
Auto　Scaling利用時に設定する項目になります。

この設定項目では、どのようにキャパシティユニットを調整してくれるかを指定します。

ターゲット使用率を７０％、
WCUとRCUの下限は１０、上限は１００にした場合で説明します。

２０２０年１月１日（１ヶ月前）のWCUとRCUが以下の状態だとし、
２０２０年２月１日（現在）のWCUとRCUの値を決定する場合。

|  | 2020年1月1日 | 2020年2月1日 |
|:-:|:-:|:-:|
|  WCU |  40 |  ? |
|  RCU |  60 |  ? |

ターゲット使用率は７０％なので、２月１日のキャパシティユニットの７０％の値が、
１月１日のキャパシティユニットの数になるように調整します。

つまり、WCUは`40 / 0.7 = 57.14`、
RCUは`60 / 0.7 = 85.71`となります。

２月１日は、先ほどの値を切り上げして、
５８WCUと８６RCUあれば良いという結果になります。

以下の通りです。

|  | 2020年1月1日 | 2020年2月1日 |
|:-:|:-:|:-:|
|  WCU |  40 |  58 |
|  RCU |  60 |  86 |

ターゲット使用率を上手く調整し、
想定よりも少しリクエストが多く来ても耐えれるようにしましょう！

###暗号化
mazon DynamoDB に保存されたすべてのユーザーデータは、
保管時に完全に暗号化されます。デフォルトでは、Amazon DynamoDB が暗号化キーを管理し、
暗号化キーの使用に料金はかかりません。


#さいごに

以上が主な設定項目になります。

重要な設定項目は、パーティションキーやキャパシティモード、暗号化でしょうか。
少しでもこの記事が参考になれば嬉しいです。

次の記事では、LambdaからDynamoDBに書き込みを行なったりする記事を作成しようかな。
Componentのローカルステート管理方法について

Reactで状態管理をする方法についてまとめてみる

Reactの実務経験は無いので、誤りがあれば指摘いただければ幸いです！

## 状態管理の手法

- useState
- useReducer

## useState

関数コンポーネントの中でローカルなstateを使うことができるフック
`useState`は現在の state の値と、更新関数のペアを返します


`Todos` Component

```javascript
const Todos = () => {
  const [title, setTitle] = useState("")

  const handleSubmit = (e) => {
    e.preventDefault();
    const data = {
      id: new Date().getTime(),
      title,
      created_at: new Date()
    };
    setTodos((prevData) => [...prevData, data]);
    setTitle("");
  };

  return (
    <>
      <h2>Todos</h2>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          onChange={(e) => setTitle(e.target.value)}
          value={title}
        />
      </form>
      <ul>
        {todos.map((todo) => (
          <TodoItem todo={todo} key={todo.id} />
        ))}
      </ul>
    </>
  );
};
export default Todos;

```

コンポーネント単位で管理しているため、親子関係になっていればpropsとしてstateを渡し、他のコンポーネントでデータを反映させることは可能。

親子関係がなく、それぞれが独立したコンポーネントの場合、後述する `Redux` `useContext` 等の `props`以外の情報共有手段が必要になる。

公式
https://ja.reactjs.org/docs/hooks-state.html

codesandbox
https://codesandbox.io/s/usestate-todo-app-2i51b?file=/src/components/TodoItem.jsx:105-113


## useReducer

`useState`では、 現在の`state`とstateを更新するための関数が返ってきていました。

`useReducer`は、第一引数に関数（reducer）、第二引数に`state`の初期値を渡すと、現在の`state`と`dispatch`メソッドとペアで返ってきます。

`dispatch`は、`reducer`に　`action`を　`dispatch`し、`reducer`に伝えます。
`action`を受け取った`reducer`は、`action.type`で分岐して処理する内容をきめている。

ざっくり書くと、
一つ前の `state`　と　`dispatch` された `action`を使って新しいstateを生成するための 「関数」 です。


公式サイトより↓

```javascript
// state初期値
const initialState = {count: 0};

//　action.type によって処理する内容を決める
function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}
```

`onClick={() => dispatch({type: 'decrement'})}`  のように、 `action`を　　`dispatch`すると

`reducer` 関数の中で、 `action.type` の分岐が実行される。　

```javascript
    case 'decrement':
      return {count: state.count - 1};
```

codesandboxで、簡単なフォームを作ってみました。
このサンプルでは、 `use-immer`　を使用しています。

codesandbox
https://codesandbox.io/s/usereducer-form-mjnzj?file=/src/App.js


Flux　In-Depth Overview
https://facebook.github.io/flux/docs/in-depth-overview#structure-and-data-flow


公式　　useReducer
https://ja.reactjs.org/docs/hooks-reference.html#usereducer
[シリーズ] VirtualBox のインストールについて


# 概要

当方は VirtualBox と Vagrant をセットで導入している.
そこで Vagrant が実行できたバージョンの VirtualBox のインストール手順を記している.

|コンテンツ|実践時期|一言|
|:--|:--|:--|
|[[01] VirtualBox 5.2 系のインストール手順](https://qiita.com/robozushi10/items/6673ff8225c357f8f073)|2021/05|ホストOS は Ubuntu 18.04 であった.<br/>Vagrant は 2.2.14 であった.|
|[[02] VirtualBox 6.0.X 系のインストール手順](https://qiita.com/robozushi10/items/73e3c55da686951ea4d0)|2021/05|ホストOS は Ubuntu 20.04 であった.<br/>Vagrant は 2.2.16 であった.|
[02] VirtualBox 6.0.X 系のインストール手順

|本シリーズのトップページ|
|:--|
|[[シリーズ] VirtualBox のインストールについて](https://qiita.com/robozushi10/items/edea49b473219d22816b)|

# 概要

Ubuntu 20.04 に **VirtualBox 6.<font color=#33aaaa>0</font>.X** 系をインストールする手順である.
また、2021/05 時点で Vagrant 2.2.16 が使用可能なことも確認している.

なお、2021/05 時点では **VirtualBox 6.<font color="red">1</font>.X** 系を使うと Vagrant が使えなかったので、
**VirtualBox 6.<font color=#33aaaa>0</font>.X** 系をインストールした.


# 環境

```
  Operating System: Ubuntu 20.04.2 LTS
            Kernel: Linux 5.4.0-66-generic
      Architecture: x86-64
```

# 手順

## 1. VirtualBox 6.1.X をアンインストールする.

2021/05 時点の情報ではあるが、
VirtualBox のバージョンが 6.1.x 系であれば **アンインストール** する.
なお、VirtualBox 6.2 以降の動作については不明である.

```bash
$ sudo apt-get remove --purge virtualbox
```

## 2. VirtualBox 6.0.X をインストールする

恐らくだが、6.0.X 系をインストール方法は以下を参考にすれば良いと思う.

・https://kazuhira-r.hatenablog.com/entry/2019/09/29/003818
・https://linuxhint.com/install_virtualbox_6_ubuntu/

```bash
$ sudo apt install virtualbox-6.0
```

もしもセキュアブート用のキーが指定されれば適当に決めておくこと.
ここでは「abc123」としておく.

PC を再起動させると(下図のような)青画面になるので、
「Enroll key」から `abc123` と入力すれば良い.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1246056/bb18bbf6-b83a-1da8-18d1-c1b6ad26ca22.png)

## 3. インストールされたことを確認する

次のコマンドで 6.0.X 系であることを確認する.

```bash
$ virtualbox --help
```

以上.

このあと、VirtualBox の操作性を上げるために Vagrant を導入する.

このあと、VirtualBox の操作性を上げるために Vagrant を導入する.
プログラミング学習を始めるにあたって

##プログラミングとは

プログラミングとは「プログラム」を作ることを指します。

プログラムとはコンピュータに対して、こうしろ、ああしろ、という命令を書きだしたものです。
そしてプログラミングとはその「プログラム」を作ること、
ですからそうした命令文（コード）を作文することと言えます。

スマートフォンなどに慣れ親しんでいる昨今ではなかなか考えにくいことかもしれませんが、
コンピュータは命令したことしか実行しません。
つまり使う人間に忖度して動いてくれるようなことはないのです。
例えば半角の「1」と全角の「２」を足せ、と命令しても忖度して「3」と返してくれるようなことはないのです。
もちろんそういうことを行わせたいのであれば、
半角と全角でも計算できるようにコードを記述すること（コーディング）が必要になります。

コーディングは翻訳に似ています。
我々が英語を話そうとするとき、ネイティブな人でない限りは一度日本で話したいことを考えるでしょう。
そしてその日本語にあう英文を考えて話すということを無意識に行っていると思います。
プログラミングも同じで、コンピュータが理解できる言語にこうした翻訳作業を行う必要があります。




##プログラミング言語とは

先ほど述べたコンピュータが理解できる言語には種類があります。
メジャーなものからマイナーなものまで列挙すればキリがないのですが、
例えば我々が今回扱うC#や、C言語、C++、java、javascript、python、VBなどなど、、、
こうした「コンピュータが理解できる言語」を「プログラミング言語」といいます

ただし細かいことを言うとこれは少し誤った認識で、
本当にコンピュータが理解できるのは01000101...といったデジタル信号です。
ですが当然これは人間が理解するのは極めて大変な作業になるため、
その橋渡しとしてこうしたプログラミング言語は存在します。

プログラミング言語は、その多くが英語で記述されています。
なので我々のような未経験の人間がプログラミングを行おうとすると、
「日本語→英語→プログラミング言語（→デジタル信号）」という流れでコーディングすることになります。

日本ではプログラマーが遅れているとか、数が少ないとか言われておりますが、
これの原因は上の「日本語→英語」が障害となっているケースが多いのではないか思います。
ですがプログラミング言語はそもそも英語で記述されていますから、
逆を言えば「日本語→英語」ができればコーディングは比較的簡単な作業です。
あとはプログラミング言語のルールに沿ってそれを記述していくことを覚えればよいのです。
さようなら、discord.py?

とあるネコ型ロボットのお話の「最終回」と違って、これには次号がないようです。discord.pyの開発が、今日でいったん終わりました。Danny氏([@Rapptz](https://github.com/Rapptz/))は開発者の座を退き、リポジトリはアーカイブされました。開発中のバージョン2.0が来るかはわかりませんが、来たとすれば最後のバージョンとなるでしょう。

今後は、第三者が作ったフォークプロジェクトが多数生まれ、それを使うことになりそうです。

一度でも、機械翻訳でもいいので、以下の文章を読むことをお勧めします。

https://gist.github.com/Rapptz/4a2f62751b9600a31a0d3c78100287f1
AirSim　トラブル集

### 経緯
AirSim for Unityをつかってあそびました．
いろいろトラブルがあったので備忘録として．

### 環境
macOS Big Sur 11.5.2
Unity 2020.3.12f1


### 導入
AirSimの導入方法は[こちらの記事](https://qiita.com/tyo/items/9d7bfadde958484fa7d6)を参照しました．Macでも同様の手順です．

#### ビルドしたのに動かず落ちる
ファイル-ビルド設定-品質からいろいろいじくった
https://qiita.com/yoship1639/items/7339a6201b44a24fbdfe


#### ビルドが”Build GI ata” で止まる
GI(global illumination)が原因だった．不要なのでウィンドウ-レンダリング-ライティングから，リアルタイムグローバルイルミネーションとベイクしたグローバルイルミネーションのチェックをはずした．
VoTTv2から出力したアノテーションをYOLOv5学習用に変換するスクリプト


遅れ馳せながら`YOLOv5`の転移学習をオリジナルのデータを使って実施してみたのですが、あまりの手軽さに驚きました。

ネット上には`YOLOv5`の転移学習に関する優れた事例や紹介記事が多数ありますので、ここではその内容については触れませんが、AIに関する知識が無い人でも、手順通りに実施すればオリジナルのAIモデルが作れてしまいます。すごい。

殆どの作業が自動化されているので、特に問題となるような事は少ないのですが、それらの事例をトレースした際に「ちょっと面倒だな」と感じたデータセットの変換処理に関して、より作業を簡略化できるように`python`スクリプトを作成しました。


私はアノテーションツールとして[`VoTT v2.2.0`](https://github.com/Microsoft/VoTT/releases)を使用したのですが、出力されるデータセットのファイル形式が`YOLOv5`用のファイル形式に対応していないため、別途変換する必要があります。

変換の方法はいろいろあるみたいですが、代表的な方法としては以下が挙げられます。

 * [roboform](https://public.roboflow.com/)というサイトの[変換サービス](https://roboflow.com/convert/vott-json-to-yolov5-pytorch-txt)を利用する
 * 有志の方々が開発したスクリプトを利用させてもらう

私の場合は、ネット上にデータを上げるのは少し気が引けたので、有志の方々が開発したスクリプト（[ssaru氏](https://github.com/ssaru/convert2Yolo)や[Ryo-Kawanami氏](https://github.com/Ryo-Kawanami/xml2yolo)）を利用させてもらったのですが、今回使用したケースでは`hoge.mp4#t=0.033333.xml`というようなドットが複数含まれるファイル名で問題が発生しました。

上記プログラムを一部書き換えれば適切に処理できることも確認したのですが、ディレクトリの指定方法などをより簡便に行いたかったので、勉強も兼ねて`YOLO`用の変換スクリプトを自分で作成することにしました。

## 1. VoTT v2 によるデータセット（Pascal VOC形式）の生成

まずは`VoTT`でタグ付けを行いデータセットを生成します。その際に、出力形式として「`Pascal VOC`」を選択してエクスポートしてください。

![01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264410/2d546054-4c8f-1089-c18e-619c6295d84a.jpeg)

`VoTT`で指定した出力先に下記のような構成でデータセットが生成されていると思います。以下の例では`****-PascalVOC-export`が変換データの解析を行う際のターゲットディレクトリとなります。

```
.
└── ****-PascalVOC-export
    ├── Annotations
    │   └── ****.xml
    ├── ImageSets
    ├── JPEGImages
    │   └── ****.jpg
    └── pascal_label_map.pbtxt
```

## 2. 変換スクリプトによるYOLO形式ファイル（*.txtと*.yaml）の生成

作成したスクリプトを用いてアノテーションデータ（*xml）の変換を行います。

https://github.com/toritamantaro/vott2yolo_py

よろしければダウンロードしてご利用ください（動作は保証できませんが・・・）。

`dataclasses`を利用しているので`Python3.7`以降の環境が必要です。また`lxml`と`pyyaml`を利用しているので`pip`等で導入してください。

### 2.1 使用方法
VoTTで出力したディレクトリをターゲットとして指定します。

ターゲットディレクトリが　`I:\origin_data\hoge-PascalVOC-export` の場合、実行例は下記のようになります。（デフォルトの変換ファイル出力先は`.\yolo_out`です）

```commandline
$ python vott2yolo_cv.py -t I:\origin_data\hoge-PascalVOC-export
```

その他のオプションは下記にてご確認ください。

```commandline
$ python vott2yolo_cv.py -h
```

### 2.2 出力ファイル

指定したディレクトリ（`.\yolo_out`）に、`YOLO`形式のアノテーションデータ（`*txt`）と`data.yaml`が生成されます。

以下は出力される`data.yaml`の例です。
ファイル名や内容を適宜修正してご利用ください。

```data.yaml
names:
- hoge
- fuga
nc: 2
train: data/train/images
val: data/valid/images
```

お疲れさまでした。
Sassを導入する方法 / コンパイル方法 【簡単！】

こんにちは。しゃねこです。
はじめてQiitaの記事を書くので下手だと思いますがお許しください
追記：Linux向けにも書こうと思います

# Sassとは？
Sassは簡単に言うとCSSをより便利にしたようなものです。
Sassを正式に言うとSyntactically Awesome StyleSheetとなり、文法的にすごいスタイルシート　という意味になります。
その名の通り変数が使えたりなど本当に構文的にすばらしく、CSSをよく使う人は絶対に使ったほうがいいです。

## SASS記法とSCSS記法
SassにはSASS記法とSCSS記法があります。
SASS記法はRubyのような構文で、SCSS記法はCSSのような構文です。
現場ではよくSCSS記法が使われるとかなんとか..((

まあわかりやすいですしSCSS記法をつかっていきますね。

# 導入方法
今回はWindows10/11の、Wingetコマンドで導入します。
あらかじめ[アプリインストーラー](https://www.microsoft.com/store/productId/9NBLGGH4NNS1 "MSストアへのリンク")をインストールしてください

```bash
winget install ruby
shutdown -r -t 0
gem install sass
```

上から順にコマンドを解説します。

```
wingetでRubyをインストール
再起動
Rubyに付属のgemコマンドでsassをインストール
```

# コンパイル方法
ここまできたらおそらくsassはインストールできたでしょう。
あとは簡単です

```bash
sass scssのパス:生成したいファイル名
```

sassを適当に書いて、コマンド打って（（
![スクリーンショット 2021-08-28 160816.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406718/78c8830f-5ebf-828e-0a7d-98b8cc4c4de1.png)
はいできた!　すでに生成されてたなんて言わないｄ(((
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406718/1dbe9603-ba4c-29ca-523c-2f4271885105.png)


SCSS記法については近いうち書こうと思います。
ありがとうございました！
【SwiftUI】AppDelegate.swift がない！ 対処法

#参考

この記事は以下の2つのサイトを参考にしました。
これらの記事を見る方が、よく理解できると思います。

https://dev.classmethod.jp/articles/xcode12_change_appdelegate/

https://qiita.com/antk/items/4bd97f0baa770ecef870

#目的
SwiftUI で AppDelegate.swift(Swift×UIKit) のような機能を追加する
(おまけ) Swift での AppDelegate.swift って何のためにあるのか解説

#対処法

①〜③ を行う。

```swift:SampleApp.swift

import SwiftUI

@main
struct SampleApp: App {
　　　　　　　　// ① : 既存のAppDelegateを利用することができるようになる
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    var body: some Scene {
        WindowGroup {

            // SceneDelegate.swift の代わりとなる
            // ② : 最初に表示したい画面のファイル名を書く。例えば FirstViewApp.swift の場合
            FirstViewApp()
        }
    }
}

class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {

        // ③ : ここに AppDelegate.swift の処理を書く。
        // 今回は省略

        return true
    }
}

```


#(おまけ) Swift での AppDelegate.swift って何のためにあるのか解説

「アプリの状態に応じて自動で呼ばれる関数」の集まり。
Swift でアプリを作成する際、デフォルトで作成される。

↓参考にした記事

https://qiita.com/penkopenko/items/cc8f48af792c353cd9f3
基本情報技術者　ネットワーク編④

#初めに
前回の[続き](https://qiita.com/reo0612/items/10ddc417e1cb01a9e8ea)です。

#データの誤り制御
コンピュータは0か1しか理解できず、その組み合わせによって
音楽を表現したり、テキストを表現したりしています。

そして、コンピュータ同士がデータをやり取りする際も、この0か1で送信・受信しています。

ですが「0なら0」「1なら1」というはっきりとしたデータではなく
あくまでも単なる電気信号のみで、この信号の波形を確認し、0か1かを判断しています。

しかし、電気信号なので伝送距離が伸びれば信号は減衰しますし
別の電気的な干渉を受ければ波形は乱れてしまいます。

こうして生まれるのがデータの誤りです。

#パリティチェック
送信するビット列に対して、`パリティビット`と呼ばれる検査用のビットを付与することでデータの誤りを検出していきます。

これを`パリティチェック`と呼びます。
付与する方法には2種類あります。

###・偶数パリティ
以下のようなビット列があったとして

```
1001000
```
偶数パリティでは、`ビット列の1の数が偶数`になるようにしていきます。

```
0 1001000
```
なのでこの場合は`0`を付与しています。

###・奇数パリティ
対して、奇数パリティは`ビット列の1の数が奇数`になるようにしていきます。

```
1 1001000
```
なのでこの場合は`1`を付与します。

ですが、パリティチェックでは「`1ビットの誤り`」を検出する事だけです。

なのでビット列の1が奇数個であれば
データの誤りを検出できますが

```
0 1001000
↓
// 検出可能
0 100100①
```
偶数個であれば検出できません。

```
0 1001000
↓
// 検出不可
0 100000①
```
これではどのビットが間違っているかも分からないので誤り訂正も行えません。

###・水平垂直パリティチェック
どの方向にパリティビットを付与するかによって誤りを検出する方法です。

例えば、ABCという文字列があったとして
これを文字コードで表現したら以下のようになります。

```
A B C
↓ ↓ ↓
1 0 0
0 1 0
0 0 1
0 0 0
0 0 0
0 0 0
1 1 1
```
このビット列の水平・垂直方向にパリティビットを付与していきます。

今回は`偶数パリティ`を用いていきます。

```
A B C
↓ ↓ ↓
1 0 0  1 // 水平パリティ
0 1 0  1
0 0 1  1
0 0 0  0
0 0 0  0
0 0 0  0
1 1 1  1

0 0 0  0 // 垂直パリティ
```
ビット列を並べた時の各ビット位置単位で付与するのが`水平パリティ`で
ビット列単位で付与するのが`垂直パリティ`です。

この2つのパリティを組み合わせて使うのが`水平垂直パリティ`です。

縦横両面から誤りを検出できるので、1ビットの誤りであれば
間違っている位置を特定することができ、訂正することができます。

例えば以下のように◯の部分が誤りだったら
縦横から誤りを検出することができるので位置を特定できます。

```
A B C
↓ ↓ ↓
1 0 0  1
0 1 0  1
0 ① 1  1
0 0 0  0
0 0 0  0
0 0 0  0
1 1 1  1

0 0 0  0
```
ただし、2ビット以上の誤りが発生すると検出はできますが位置の特定が出来なくなります。

```
A B C
↓ ↓ ↓
1 0 0  1
0 1 0  1
① ① 1  1
0 0 0  0
0 0 0  0
0 0 0  0
1 1 1  1

0 0 0  0
```

#CRC(巡回冗長検査)
ビット列を特定の式(生成多項式)で割り
その余りをチェック用のデータとして付与する方法です。

```
// この計算で得られた余りがチェック用のデータとなる
送信するデータ(ビット列) ÷ 生成多項式
```
これを`CRC(Cyclic Redundancy Check)`と呼びます。

まず、データを送信する側は計算で得られた余りを
元々のビット列にくっつけて、それをまとめて送信データとします。

こうすることで、そのデータは計算に用いた生成多項式で
割り切れるはずの値に変わります。

```
// まとめて送信データとする
送信するデータ + 余り
```
そして受信した側は、送信側と同じ生成多項式を使って計算していきます。

```
受信したデータ ÷ 生成多項式
```

データに問題がなければ割り切ることができ、余りが出ません。
余りがあればそのデータに問題があることが分かります。

この方法ではデータの誤り訂正は出来ませんが、連続したビットの誤り(バースト誤り)など
複数ビットの誤りを検出することが可能です。

#おわりに
今回はここまでです。

間違っている部分や気になるところがあればコメントして下さい。
Firebase Emulator画面が真っ白になったときの対処法

Google FirebaseのLocal emulator suiteにて、ストレージのエミュレータ画面にブラウザでアクセスすると画面が真っ白になり何もできませんでした。
そこで、ターミナルで起動中のemulator suiteのログを見ると以下のエラーが発生していました。

>
⚠  Permission denied because no Storage ruleset is currently loaded, check your rules for syntax errors.

storage.rulesは適切に配置されていたので、このエラーメッセージは腑に落ちませんでした。

また、エラーメッセージをGoogleで検索しても、同様のケースは見られませんでした。よって、Firebaseコミュニティの皆さんのために、解決策をシェアします。

# 解決策

試行錯誤の後、ruleのバージョンを2に明示的に指定することにより、エミュレータが正常に動くようになりました。

```:storage.rules
rules_version = '2';
...
```

今回、諸用で久々にFirebaseを触りました。Firebaseの機能の更新はサイクルが早いので、いろんなことが変わってますね。

なお、この解決策はEmulator Suiteの他のFirestoreなどのサービスにも当てはまるのではないでしょうか。同様のエラーを発見したときは是非試して見てください。

以上、お読みいただきありがとうございました。
Maxima 手習い（Maxima で積分）

ずっと以前から数式処理ソフトには憧れがあったのですが面倒臭そうなイメージがあってあまり調べてはいませんでした。
もう微分積分の計算方法を忘れつつあるので、せめて計算機で積分を計算できるように、やりかたを調べておこうと思いました。

お題はこんな積分です。

```math
\int \sqrt{x + \sqrt{x + \sqrt{x + ...}}} dx
```

被積分関数を f とすると、上記の ... の部分もまた f と同じになるので

```math
f = \sqrt{x + f}
```

と書けるはずです。Maxima でも同じく被積分関数を定義してみます:

```maxima
integrand: f = sqrt(x + f);
```
wxMaxima で実行すると、数式を綺麗に表示してくれます。
![i1_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412308/e41091bb-89df-4d65-cfe9-763ede759273.png)

根号があると気持ち良くないので、この両辺を二乗して全体を ... = 0 の形の式に直すと:

```math
f^2 - x - f
```

と変形できます。maxima 上でも、被積分関数の左辺 first(integrand) と 右辺 second(integrand) それぞれの二乗の差をとる式変形を以下のように書けます:

```maxima
first(integrand)^2-second(integrand)^2
```

soluve を使って、この二次方程式の解を得ることができます。これで非積分関数 f を x の関数として得ることができました。

```maxima
solutions: solve(first(integrand)^2-second(integrand)^2, f);
```
![i2_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412308/e26a88a1-e22c-5ad0-1814-8f3c4e8e5f44.png)

ラベルを solutions と複数形にしているのは、二次方程式の２つの解が結果として得られるためです。以下のようにプロットして見ると一方は x > 0 のときに負の値をとるので前者は不適格なのだろうと思うことができますが、リスト上から不適格な解を取り除く方法を知らない Maxima 初心者なのでこのまま計算を進めることにします...

```maxima
draw(map(lambda([solution], gr2d(key=string(solution), explicit(second(solution), x, 0, 20))),
         solutions));
```
![plot_solutions.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412308/c73c3c81-06d8-a169-eb8d-45710ad772dc.png)

得られた２つの解それぞれを x で積分してみます。

```maxima
map(lambda([solution], expand(integrate(second(solution), x))),
    solutions);
```
![i3_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412308/116356a2-2730-0fe7-9f36-b2b817f43954.png)

後者の結果が求めたい計算結果となりました。

手順をまとめて書くと、以下です:

```maxima
integrand: f = sqrt(x + f);
solutions: solve(first(integrand)^2-second(integrand)^2, f);
map(lambda([solution], expand(integrate(second(solution), x))),
    solutions);
```
なぜJavaはOSに依存しないのか

＜目次＞
・「 OS に依存する」とは


##◆　「 OS に依存する」とは
　OS によって動作が異なる（動くか動かないか含め）ということを指します。「 Java がOS に依存しない」とは、どの OS でも同じく正常に動作する、ということです。

では Java はどのような特徴により依存しないようになっているのでしょうか？
~~依存しないための条件として、以下3つが挙げられます。~~

~~①　OSがその言語をサポートしていること~~
~~②　その言語で行いたい処理を、各OS上でサポートされている範囲内で書くことができ、期待通りの動作が行えること~~
~~③　その言語で書いたプログラムのコンパイル結果がOS独自に定義されており、各OS上で再コンパイルしないで動作させることができること~~

【 2021-08-29 追記（訂正）】

Java では JVM（Java仮想マシン）と呼ばれる仮想マシン（ソフトウェア）が、各OSの違いを吸収するという役割を果たしています。

Java で作成されたプログラムは、実行前にコンパイラと呼ばれる言語プロセッサがソースファイル（.java）からコンピュータが実行できる「クラスファイル(.class)」を生成します。
そのソースコードはコンピュータが理解できる「バイトコード（0と1の羅列）」に変換されています。
後述しますが、そのバイトコードが対象のOSで実行可能な形式のコードである「マシンコード」に変換されて実行されます。（ソースコードに対してネイティブコードとも呼ばれます）

ソースコードを実行可能なファイルへコンパイルする必要があるプログラミング言語をコンパイラ型言語といい、C言語やJavaが代表的なものですが、
C言語の場合はC言語用のコンパイラが「WindowsであればWindows用の機械語」へ、「LinuxであればLinux用の機械語」へそれぞれOSに合わせてコンパイルします。
これはコンパイラがいずれかのプラットフォームに依存している状態です。

対してJavaでは、各OSに用に作られたJVMがOSに合わせたマシンコードに変換し、最後に変換された命令をOSが命令を実行するようになっています。
この仕組みによって異なるOSの環境下であっても、その環境ごとに合わせてソースファイルを作成することなく実行することができます。

JVMは後述するJREの中にあり、APIとセットになっています。

####・JRE ( Java Runtime Environment )
  Javaで作成されたプログラムを実行するために必要なソフトウェアです。
Java実行環境やJavaランタイムなどとも呼ばれます。
Java で作成されたアプリケーションは JVM 上で実行されますが、実際には JRE を各 OS にインストールすることで Java アプリケーションが実行できる環境が構築できます。
 JRE は対応する Java SE のバージョンに合わせて、バージョン番号（JRE8や13など）が付けられます。後述するJDKに含まれます。

####・JDK ( Java (SE) Development Kit )
　Javaで開発・実行するための総合的なプログラムセットです。Javaア開発環境とも呼ばれます。
JREに加えてプログラムをコンパイルするためのプログラムやデバックするためのプログラムなどが含まれます。JREと同じく、対応する Java SE のバージョンに合わせて、バージョン番号（JDK8や13など）が付けられます。

ちなみにJava SEはStandard Edition、つまりJavaの基本機能をまとめたものです。これを基にしてサーバーサイドの機能を追加したものをJava EE ( Enterprise Edition ) と呼びます。



参考文献
この記事は以下の情報を参考に執筆いたしました。
-Let'sプログラミング ” Java SEとJDK、JRE、JVMの違いに関する解説 ”
https://www.javadrive.jp/start/install/index5.html
-SAMRAI ENGINEER Blog　” 【Java入門】JVMとは？わかりやすく解説！ ”(2017-03-23)
https://www.sejuku.net/blog/19871
-Tech Teacher Blog ” JVMって何？これからJavaを始める人でも分かるように解説します！ ”(2020-06-29)
https://www.tech-teacher.jp/blog/java-jvm/
-SAMRAI ENGINEER Blog　” JavaのJREとは？JDKとの違いやインストール方法まで解説 ”(2019-05-29)
https://www.sejuku.net/blog/63551
-SAMRAI ENGINEER Blog　” 【Java入門】SEとEEの違いは？JRE・JDKとは？を初心者向けに解説 ”(2019-07-03)
https://www.sejuku.net/blog/12902
Grafana で変数を使う

変数の代入
picc = 'sample_cc.jpg' としてみます。
![variable_aa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/b21b17fc-4e0c-2b33-f9ac-3a1697669bb8.png)

代入された変数の一覧
pica, picb, picc が代入されています。
![variable_bb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/a1f36323-4cb3-9f0d-9b33-0255270e0f37.png)

変数の使い方
${pica} というようにして使います。
![variable_cc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/30c2569b-9bcc-2206-0255-eb65663c2f9c.png)
RabbitMQ に cerelyから接続する際のguest アカウントでの接続エラー

# 問題

以下のpython スクリプトで rabbitMQに接続しようとしたが、


```
# tasks.py

import celery
import time
import random

app = celery.Celery('tasks', broker='amqp://quest@localhost',
                    backend='amqp://quest@localhost')  # AMQP advanced message queuing protocol

@app.task
def build_server():
    print("wait 10sec")
    time.sleep(10)
    server_id = random.randint(1, 100)
    return server_id
```


下記のエラーで返された。

```
$ celery -A tasks worker --loglevel=info

amqp.exceptions.AccessRefused: (0, 0): (403) ACCESS_REFUSED - Login was refused using authentication mechanism AMQPLAIN. For details see the broker logfile.
```

rabbitMQのlogを見ると以下  /var/log/rabbitmq配下

```
=ERROR REPORT==== 28-Aug-2021::13:19:01 ===
Error on AMQP connection <0.287.0> (127.0.0.1:42252 -> 127.0.0.1:5672, state: starting):
AMQPLAIN login refused: user 'quest' - invalid credentials
```


# 環境

celery 5.1.2 -> 4.1.1
python 3.6
ubuntu 18.04
RabbitMQ 3.6.10
Erlang (SMP,ASYNC_THREADS) (BEAM) emulator version 9.2

# やったこと

* celery を 5.1.2から4.1.1に変更
　そもそもceleryの5.1.2では、AMQPプロトコルに対応してないとのことだった。

* rabbitmqのユーザー確認

```
sudo rabbitmqctl list_users
Listing users
guest	[administrator]
```

* ユーザーパス変更

```
$ sudo rabbitmqctl change_password guest guest
Changing password for user "guest"
```

* このページが参考になる
https://www.rabbitmq.com/install-debian.html#default-user-access

#　解決

guestじゃなくて questじゃねーか！！！
AtCoderログ：0095 - ABC 160 C

# 問題

https://atcoder.jp/contests/abc160/tasks/abc160_c

## 問題文
> $1$ 周 $K$ メートルの円形の湖があり、その周りに $N$ 軒の家があります。
> $i$ 番目の家は、湖の北端から時計回りに $A_i$ メートルの位置にあります。
> 家の間の移動は、湖の周りに沿ってのみ行えます。
> いずれかの家から出発して $N$ 軒すべての家を訪ねるための最短移動距離を求めてください。

## 制約
> ・$2 \le K \le 10^6$
> ・$2 \le N \le 2×10^5$
> ・$0 \le A_1 < \ldots < A_N < K%
> ・入力中のすべての値は整数である。

## 収録されている問題セット
- [[BfB-E]\(AtCoder Problems Boot camp for beginners Easy 100\)](https://kenkoooo.com/atcoder/#/training/Boot%20camp%20for%20Beginners/1) #012

# 回答
## 回答1 (AC)
$i-1$ 番目の家と $i$ 番目の家の距離は $A_i-A_{i-1}$ なので、$i$ 番目の家を出発して時計回りにそれぞれの家を訪ね、最後に $i-1$ 番目の家を訪ねるときの移動距離は $K-(A_i-A_{i-1})$ となります。後は $i$ を変化させたときの最小値を求めれば良いでしょう。ただし $i \ge 2$ でなければならないので、$i=1$ の場合は別扱いが必要なことに注意してください。コードは以下のようになりました。

```C++:abc160c-1.cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
  int k, n;
  cin >> k >> n;

  vector<int> a(n);
  for ( int i=0; i<n; i++ ) {
    cin >> a.at(i);
  }
  
  int dmin = a.at(n-1)-a.at(0);
  for ( int i=1; i<n; i++ ) {
    dmin = min( dmin, k-(a.at(i)-a.at(i-1)) );
  }
  
  cout << dmin << endl;
}
```

# 調べたこと
## [AtCoder の解説](https://atcoder.jp/contests/abc160/tasks/abc160_c/editorial) → [ユーザ解説](https://blog.hamayanhamayan.com/entry/2020/03/29/034804)
回答1と同じ方針でした。

## [AtCoder の解説](https://atcoder.jp/contests/abc068/tasks/abc068_b/editorial) → [コンテスト全体の解説](https://img.atcoder.jp/abc160/editorial.pdf)
回答1と同じ方針でした。

# リンク
## 前後の記事
- 前の記事 → [AtCoderログ：0094 - ABC 074 B](https://qiita.com/RoadLynton/items/c4eb75ae4f0ac8f4a125)
- 次の記事 → [AtCoderログ：0096 - AGC 014 A](https://qiita.com/RoadLynton/items/82e9b4ceb9e9384130f5)
GoogleスプレッドシートからAPIを自動作成できる「SSSAPI」を使ってみた

# SSSAPIとは
Googleスプレッドシートの内容をJSON形式で取得できるノーコードのwebAPIサービス。
β期間中はstandardプランが無料で利用できることもあり試してみることにした。
[SSSAPIはこちら](https://sssapi.app/)

2021/08/28時点の料金体系は下記の通り

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150628/6a5f9d52-72bb-0b8c-31e6-1ab66be908e3.png)

## 準備するもの

2021/08/28時点の内容です。

* Googleアカウント
* Googleスプレッドシート

## SSSAPI利用手順

[SSSAPIサイト](https://console.sssapi.app/home)にてGoogleアカウントでログインする。
APIListから`+AddAPI`をクリックしAPIを登録する。
以上。これだけ！
APIの登録方法はシンプル。ナビに沿ってSSSAPIやスプレッドシートを操作するだけ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150628/245efbfb-0e33-de36-4ed8-c5813a9502e7.png)

<details><summary>ナビに記載されている手順</summary>
<div>
<ol>
<li>`+AddAPI`をクリックする</li>
<li>APIの追加ダイアログより`対象のシートを読み込めるように、共有設定で以下のアカウントを閲覧権限で追加してください`の共有アカウントをコピーする</li>
<li>スプレッドシートの共有設定で↑の共有アカウントをペーストして閲覧者で設定する</li>
<li>APIの追加ダイアログでAPI名とスプレッドシートURLを入力してOKボタンをクリックする</li>
</ol>
</div>
</details>

# 気づき・感想

## 1.スプレッドシートの先頭行がkeyとなる

SSSAPIはスプレッドシートの先頭行をkeyとするため、先頭に見出し行があることが前提となります。
また表形式データでは列名が日本語名になっていることがあります。
API化するためにはシートのフォーマットやデータの整備が必要となります。
詳細は→[スプレッドシートの書き方](https://sssapi.app/help/spreadsheet_format)

## 2.スプレッドシートに複数のシートがある場合

SSSAPIはGoogleスプレッドシート内の__シート単位__で登録する。
（GoogleスプレッドシートURLのパラメータ`gid=XXXXX`がシート単位で異なる。）
ただ、共有設定はGoogleスプレッドシートに対して設定されるので２回目以降は省略可能となる。

## 3.接続元の制限方法

承認済ドメインを設定することでAPI単位で接続元URLを指定することができる。
[承認済ドメインとは](https://sssapi.app/help/allow_domain)

またアクセストークンを使った認証を設定することもできる。
アクセストークンはアカウントのsettingにて発行する。

## 4.ダッシュボードの機能

Googleスプレットシートのリンクがあり、データの閲覧や編集がワンクリックで楽にできる。
スプレットシートを変更した後はUpdateをクリックしないと実行結果に反映されない。

アクセスログは見れない←プランの問題？
現時点でアクセスログを取るには中継用のHTTPサーバーやロードバランサ等を別途作成してアクセスログを取るような代替方法が必要かもしれません。

# 参考サイト

* [SSSAPI本家](https://sssapi.app/)
* [ノーコード・コードレスでGoogleスプレッドシートからAPIを作成できる「SSSAPI」β版がリリース](https://digital-shift.jp/flash_news/FN210824_2)
* [GASでもできるけど、スプシをAPI化するサービスを作ってみた。そして、そのときハマったこと。](https://qiita.com/kira_puka/items/b61f8cd682161afb55a9)
お名前ドットコム＋ACMでメール認証申請したら楽だった話

# 状況
お名前ドットコムでドメインを取得（Whois情報公開代行 メール転送オプションを申し込む。合計1,300円／年）
↓
AWS　Certificate Managerを使用して証明書の申請（Email認証）
↓
認証確認がお名前ドットコムの会員に登録されているメールアドレスに届く。
↓
認証するで完了。

# Whois情報公開代行 メール転送オプションがない場合
ひと手間必要です。
AWS　SESでメールの設定をしS3バケットからメールのファイルをダウンロード。
この時ファイルも複数あるため確認作業が必要になります。
生データのような形式で英語の文面からリンクに該当する部分を探し
ブラウザに貼り付けて認証します。

# ACMでの証明書認証はDNSがおすすめ
今後ACMで証明書認証するならDNSがおすすめです。
理由としては毎年の認証確認作業が自動化されているので運用が楽＆確実です。

事故が起きるとすればRoute 53などに設定されているDNS認証用のCNAMEレコード（乱数っぽい）が
よくわからずに削除されてしまって自動更新に失敗するというものがあるようです。
[DNS によって検証されたドメインの更新](https://docs.aws.amazon.com/ja_jp/acm/latest/userguide/dns-renewal-validation.html)

# 参考情報
[AWSCertificate Managerとは？](https://docs.aws.amazon.com/ja_jp/acm/latest/userguide/acm-overview.html)
なぜ画面に表示される「ぐるぐる」は必要なのか

## ゴール
ローディング中に良く見かける「ぐるぐる」ってなぜ必要か？を理解する。

## やったこと
Reactで開発していく中でよく使うコンポーネントの一つである、「ぐるぐる」コンポーネントを使い回せるよう作成した。使っているCSSのライブラリはTailwind CSS。

```typescript
export const Loading: React.FC = () => {
  return (
    <div className="w-full h-full flex justify-center">
      <div className="flex self-center">
        <div>Loading...</div> {/* ここにローディング中に表示したい文字やアイコンなど */}
      </div>
    </div>
  );
};
```

あれ、でもなぜこのぐるぐるは必要なんだっけ、、？と疑問が湧いたので調べてみることにした。

## そもそもなぜこのぐるぐるが必要なのか
ぐるぐるを調べると名称は「プログレスインジケータ」らしい。ではこの「プログレスインジケータ」がなぜ必要か。調べていくと以下二つの理由がありそうだということがわかった。

①ユーザーがアプリ内での混乱を防ぐ
②ユーザーが感じる待ち時間が短くなる



### ①ユーザーがアプリ内での混乱を防ぐ
以下二つの例を見比べてみる。

#### プログレスインジケータなし
![スクリーンショット 2021-08-28 14.20.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462620/1f38508d-faa9-a996-2fba-46a34b4c3f70.png)

#### プログレスインジケータあり
![スクリーンショット 2021-08-28 14.21.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462620/91ffc472-ec14-17f9-97cc-39a1b2486772.png)


例えばある通販サイトを開いた際の挙動だったと想像してみる。
ただ真っ白い画面が表示されて数秒変化なかったら、自分だったら離脱してしまいそう。
でも「プログレスインジケータ」がある画面であれば、5~10秒くらいは待てそう。（サイトによってはもう少し待てるかも）
一つコンポーネントを追加しただけなのに、UXは劇的に向上する。


### ②ユーザーが感じる待ち時間が短くなる
ある調査では

> WebサイトがローディングしているときにCTAすることによって、ユーザーの体感スピードが上がる
ref: https://www.webprofessional.jp/how-to-take-advantage-of-the-psychology-of-speed-perception/

という結果が出たそう。記事中のCTAという言葉はweb上ではインタラクションと言い換えても大きく齟齬はなさそう。インタラクションとは

> 人間（利用者）によるコンピュータやソフトウェアへの働きかけ（操作など）と、対になる応答（表示の変化など）の組み合わせ、および、その連続や反復のこと
ref: https://e-words.jp/w/%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%A9%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3.html

つまりローディング中に「Loading...」とソフトウェアから人間に応答することによって、ユーザーの体感スピードが上がる、ということが言えそう。

上記二つの理由から「プログレスインジケータ」が必要そうだと考えられる。

# まとめ
- 「プログレスインジケータ」でユーザーが画面描画を待つ体感時間は短くなる
- もっと範囲を広げるとユーザーにわかるように何かを応答(表示)することはユーザー体験のために大事

# 参考記事
- https://goodpatch.com/blog/progress-indicator
- https://www.webprofessional.jp/how-to-take-advantage-of-the-psychology-of-speed-perception/
- https://e-words.jp/w/%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%A9%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3.html
Apple Silicon (M1)ベースのMacでCocoapodsを使う方法

Apple Silicon (M1)ベースのMacだとCocoapodsで大量のエラーが吐かれて面食らったので、そのときの対処メモです。[ここ](https://medium.com/p-society/cocoapods-on-apple-silicon-m1-computers-86e05aa10d3e)の記事を参考に、Rosetta 2で動作するIntelバージョンをインストールすることで解決しました。

#Intel版Cocoapodsのインストール方法
1. Rosetta 2でffiをインストール

    ```
    sudo arch -x86_64 gem install ffi
    ```

1. Cocoapodsをインストール

    ```
    sudo gem install cocoapods
    ```

1. Rosetta 2でpodを実行

    ```
    arch -x86_64 pod init
    ```

これで問題なくpodが使えるようになりました。

#便利技
いちいちタイプするのが面倒なのでエイリアスを張ると便利。

1. .zshrcファイルを開く

    ```
    vim ~/.zshrc
    ```

1. 一行追加

    ```
    alias intel="arch -x86_64"
    ```

1. 設定反映

    ```
    source ~/.zshrc
    ```


こんな感じで使えるようになります。

```
intel pod update
```

#注意点
Intel版をインストールした後に、グローバルにgemをアップデートするとマズいようです。アーキテクチャの混在により、Rubyのgemシステムを壊してしまう可能性あり。
Cocoapodsをアップデートする必要がある場合は、次のように個別にアップデートするのが良さそうです。

```
sudo gem update cocoapods
```


#参考
[How to install Cocoapods on Apple Silicon M1 computers?](https://medium.com/p-society/cocoapods-on-apple-silicon-m1-computers-86e05aa10d3e)
Ubuntu 20.04 で WeChatを使う

「Ubuntu 16.04/18.04 で WeChatを使う」
https://qiita.com/nanbuwks/items/bc6c3c171b7a3be981c9
ではいろいろ試した結果、WineHQ を使って WeChat を使うことに落ち着きました。

その後筆者は Ubuntu 20.04 を使うようになりましたが、それに際し Kindle を使うために Ubuntu 付属のWineではなく、WineHQ ( Wine公式サイトで頒布サれている公式パッケージ ) を専ら使用しています。
「Kindle for PC 1.26.0 x Wine5 x Ubuntu20.04」
https://qiita.com/nanbuwks/items/042235c6a07d37f1af86

上の記事では Wine5と書いてますが、2021/08/28現在確認した所 wine-6.0.1 にバージョンアップしていました。
この Wine と、Ubuntu 20.04 の組み合わせで WeChat を試してみました。



# 環境

- Ubuntu 20.04
- wine-6.0.1
- WeChat 3.3.5
- テスト日 2021/8/27


# インストールするが起動しない

まずは
https://pc.weixin.qq.com/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/9b211752-1274-3150-10c3-3af049fc2b4d.png)

より Windows版アプリケーションをダウンロード

ダウンロードした WeChatSetup.exe を
ダブルクリックすると、以下の画面が出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/34b2675b-ae9a-f9a5-a81e-4ec006810e67.png)
「OK」を押して

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/4797d5ff-a1f5-8b6d-6266-e331f27a6f9b.png)

「Install」 ボタンを押して
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/8a8ff849-49b0-df4a-5a78-70817cdcd659.png)

「Run」すると画面が消えて音沙汰がない。

# 32ビットの動作設定


「Ubuntu 16.04/18.04 で WeChatを使う」
https://qiita.com/nanbuwks/items/bc6c3c171b7a3be981c9
で行ったのと同じようにして、

``` 

$ export WINEARCH=win32
$ export WINEPREFIX=~/.wine32
```
として、

```

$ wine WeChatSetup.exe 
```

として再度インストール。インストールはうまくいったようだけれど、以下のエラーで止まる。

```

X Error of failed request:  GLXBadFBConfig
  Major opcode of failed request:  152 (GLX)
  Minor opcode of failed request:  0 ()
  Serial number of failed request:  321
  Current serial number in output stream:  321
```

ぐぐってみたところ、以下の指定をするといいということだったので指定してから

```

$ export MESA_GL_VERSION_OVERRIDE=4.5
```

再度起動

```

$ wine WeChatSetup.exe 
```

以下の画面が出てきて、ログインできました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/3ac45243-f1da-f92d-15fa-ac64392a0434.png)


# 問題点

- Ubuntu16.06/18.04時代にはキーボードから入力ができなくてコピペで何とかしていたが、今回は入力欄には表示できないけど入力はできるようだ。

- UbuntuのメニューにWeChatは出てくるけれども、GLXBadFBConfig に引っかかるので以下のようにして起動する。

```

$ export MESA_GL_VERSION_OVERRIDE=4.5
$ cd
$ cd .wine/drive_c/Program\ Files\ \(x86\)/Tencent/WeChat/
nanbuwks@nanbuwks-ThinkPad-X230:~/.wine/drive_c/Program Files (x86)/Tencent/WeChat
$ wine WeChat

```

- Docker でするべきかな・・・

「Ubuntu上のDocker環境でWeChat/微信を使う」
https://qiita.com/Abemii/items/61d4ec8e10ad78ccbf58
4.2(易) 確率変数の和の平均，分散

## 1.方針

Wは0か一の値しか取らないので，確率変数：

```math
Z=WX+(1-W)Y
```

とは，確率pでW，1-pでYの値をとる．

## 1.答案

Zの分布関数は，

```math
\begin{align}
F_Z(z)&=P[Z\leq z]\\
&= P[WX+(1-W)Y\leq z]\\
&= P[W=1,Z\leq z]+P[W=0,Y\leq z]\\
&= pP[X\leq z]+(1-p)P[Y\leq z]\\
&= pf_X(z)+(1-p)f_Y(z)
\end{align}
```

3行目=4行目はWがX,Yと独立であることより成立．確率密度関数は，

```math
f_Z(z)=pf_X(z)+(1-p)f_Y(z)
```

期待値は，

```math
\begin{align}
\mathbb{E}_{Z\sim f_Z}[Z]&= \int zf_Z(z)dz\\
&= \int z\{pf_X(z)+(1-p)f_Y(z)\}dz\\
&= p\int zf_X(z)dz+(1-p)\int zf_Y(z)dz\\
&= p\mu+(1-p)\mu=\mu
\end{align}
```

分散は，

```math
\begin{align}
Var(Z)&= \int (z-\mu)^2f_Z(z)dz\\
&= \int(z-\mu)^2\{pf_X(z)+(1-p)f_Y(z)\}dz\\
&= p\int(z-\mu)^2f_X(z)dz+(1-p)\int(z-\mu)^2f_Y(z)dz\\
&= p\sigma^2+(1-p)\sigma^2=\sigma^2
\end{align}
```

## 2.方針

### 和の期待値＝期待値の和

---

```math
\mathbb{E}_{X,Y\sim f_{X,Y}}[X+Y]=\mathbb{E}_{X\sim f_X}[X]+\mathbb{E}_{Y\sim f_Y}[Y]
```

---

(証明)

```math
\begin{align}
\mathbb{E}_{X,Y\sim f_{X,Y}}[X+Y]&= \int\int(x+y)f_{X,Y}(x,y)dxdy\\
&= \int\int xf_{X,Y}(x,y)dxdy+\int\int yf_{X,Y}(x,y)dxdy\\
&= \int x\{\int f_{X,Y}(x,y)dy\}dx+\int y\{\int f_{X,Y}(x,y)dx\}dy\\
&= \int xf_X(x)dx+\int yf_Y(y)dy
\end{align}
```

### 和の分散=分散の和＋共分散×2
---

```math
Var(X+Y)=Var(X)+Var(Y)+2Cov(X,Y)
```

---

(証明)

```math
\mu_X=\mathbb{E}_{X\sim f_X}[X],\ \mu_Y=\mathbb{E}_{Y\sim f_Y}[Y]
```

と置くと，

```math
\begin{align}
Var(X+Y)&= \mathbb{E}_{X,Y\sim f_{X,Y}}[(X+Y)^2]-(\mathbb{E}_{X,Y\sim f_{X,Y}}[X+Y])^2\\
&= \mathbb{E}_{X,Y\sim f_{X,Y}}[X^2+2XY+Y^2]-(\mu_X^2+2\mu_X\mu_Y+\mu_Y^2)\\
&= (\mathbb{E}_{X\sim f_X}[X^2]-\mu_X)^2+(\mathbb{E}_{Y\sim f_Y}[Y^2]-\mu_Y)^2+2\{\mathbb{E}_{X,Y\sim f_{X,Y}}[XY]-\mu_X\mu_Y\}\\
&= Var(X)+Var(Y)+2Cov(X,Y)
\end{align}
```

問題では，二つ目の分散に関する公式を使う．

## 答案

Var(U)をwで平方完成して，

```math
\begin{align}
Var(U)&= Var(wX+(1-w)Y)\\
&= \mathbb{E}_{X,Y\sim f_{X,Y}}[\{wX+(1-w)Y\}^2]-\{\mathbb{E}_{X,Y\sim f_{X,Y}}[wX+(1-w)Y]\}^2\\
&= \mathbb{E}_{X,Y\sim f_{X,Y}}[w^2X^2+2w(1-w)XY+(1-w)^2Y^2]-\{w\mu_X+(1-w)\mu_Y\}^2\\
&= w^2(\mathbb{E}_{X\sim f_X}[X^2]-\mu^2)+(1-w)^2(\mathbb{E}_{Y\sim f_Y}[Y^2]-\mu_Y)^2\\
& \ \ \ +2w(1-w)\{\mathbb{E}_{X,Y\sim f_{X,Y}}[XY]-\mu_X\mu_Y\}\\
&= w^2Var(X)+(1-w)^2Var(Y)+2w(1-w)Cov(X,Y)\\
&= w^2\sigma^2+(1-w)^2\sigma^2+2w(1-w)\rho\sigma^2\\
&= 2\sigma-2(1-\rho)(w-\frac{1}{2})^2+\frac{1}{2}(\sigma^2+\rho)
\end{align}
```

ゆえ，w=1/2の時，Var(U)は最小値：

```math
\frac{1}{2}(\sigma^2+\rho)
```

を取る．

## 参考文献

- 『[現代数理統計学の基礎](https://www.kyoritsu-pub.co.jp/bookdetail/9784320111660)』(久保川達也　著)
[Python]Seleniumで取得したスクリーンショットの比較(差分確認)方法 メモ

* 画面テストで期待値画像と取得したスクリーンショット画像を比較する方法を調べたため、その内容をメモしておく。
  * それぞれのハッシュ値を比較し、差分があるかを確認する。

## 構成

```
root_dir 	-	screenshot_compare.py
			|_	image_comparison	- 	actual_img.png
									|_	expected_img.png
```



## コード`screenshot_compare.py`

1. `image_comparison`ディレクトリに期待値画像`expected_img.png`を保存

2. Seleniumで対象ページ(標準入力でURL指定)にアクセスし、スクリーンショット取得`actual_img.png`

3. 期待値画像とスクリーンショットのハッシュ値を比較し、差分があるかを確認

```python
import sys
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
import hashlib
# 標準入力から対象ページのURLを取得
args = sys.argv
target_url = args[1]

options = Options()
options.add_argument('--headless')

# ハッシュ計算
def hash_it(path):
    with open(path, 'rb') as f:
        hasher = hashlib.md5()
        hasher.update(f.read())
        return hasher.hexdigest()


directory = "./image_comparison"
# スクリーンショット
actual_img = "{}/{}".format(directory, "actual_img.png")
# 期待値
expected_img = "{}/{}".format(directory, "expected_img.png")


with webdriver.Chrome("./chromedriver.exe", options=options) as driver:
    # ページ上のすべての要素が読み込まれるまで待機
    wait = WebDriverWait(driver, 15)
    # ドライバが設定されるまでの待ち時間を設定する。
    driver.implicitly_wait(10)
    driver.get(target_url)
    wait.until(EC.presence_of_all_elements_located)

    # ウィンドウサイズ調整
    w = driver.execute_script("return document.body.scrollWidth;")
    h = driver.execute_script("return document.body.scrollHeight;")
    driver.set_window_size(w, h)

    # スクリーンショット取得※ページ全体を保存
    driver.save_screenshot("image_comparison/actual_img.png")

    # ブラウザクローズ
    driver.quit()
    # 取得結果と期待値を比較
    actual_img_hash = hash_it(actual_img)
    expected_img_hash = hash_it(expected_img)
    try:
        assert actual_img_hash == expected_img_hash
        print("Images match.")
    except AssertionError:
        print("Images do not match. {} and {}".format(
            actual_img_hash, expected_img_hash))

```



## 動作確認

* 正常系（差分なし）

  ```shell
  python screenshot_compare.py https://www.correct_example.com
  Images match.
  ```

  

* 異常系（差分あり）

  ```shell
  python screenshot_compare.py https://www.incorrect_example.com
  Images do not match. de04f78148d64ab0ced3adef4975277d and 5b4b490ab46938f920ebac3570950e87
  ```

  

## 参考情報

* [Image Comparison in Selenium WebDriver](https://www.youtube.com/watch?v=Udu1TPE6MmE)
競プロをはじめてみた

#なんで始めたか

とにかくコードを書く練習がしたかった
ちょっとやってみたら意外と楽しかった

#C++を選んだ理由

ちょっとだけCがかけた
競プロ的にはオーソドックスで、解答例のコードもC++は多いらしいと聞いて

#環境

vscodeのVimカスタム

仕事でVimを使う機会があって楽しかったので引き続き使ってみることにした

#目標

AtcoderのABCの3問目Cが解けないクソザコなのでとりあえず解けるようにはなりたい
シングルトンパターンの使い所を学ぶ

# シングルトンパターンの使い所を学ぶ

デザインパターンの１種として「シングルトンパターン」というものがある．
シングルトンパターンとは，「インスタンスが１個しか生成されないことを保証する」ことを指す．

具体的にコード例を挙げてみる．

```php
class Singleton {
    // インスタンス化されているか判断されているかに使用するメンバ変数
    private static $instance;

    // コンストラクタをprivateにして外部からアクセスできないようにする
    private function __construct(){
        echo "インスタンスを生成したよ";
    }

    // すでに自クラスがインスタンス化されているかを判断する
    public static function getInstance() {
        if ( !isset(self::$instance) ) {
            self::$instance = new Singleton();
        }

        return self::$instance
    }
}
```

シングルトンパターンを実装する上で必要なのは3つのステップ  
1. インスタンス化されているかを判断するための変数を用意
2. private コンストラクタを実装
3. 外部に公開するためのgetInstanceメソッドの中に，自クラスがインスタンス化されていない時だけ新たにインスタンス化するメソッドを実装

この3つのステップを踏めばシングルトンパターンの実装はできる．  

ちなみに呼び出したいときは，常にgetInstanceを呼ぶ．  

```php
// $singleton1と$singleton2は同じインスタンスが返っている
$singleton1 = Singleton::getInstance();
$singleton2 = Singleton::getInstance();
```

これが基本的なシングルトンパターンの実装方法である．
# シングルトンパターンを実装することのメリット

## 無駄なインスタンス化によるエラーを防ぐことができる
たくさんのクラスが複雑に継承してある場合，無駄なインスタンス化によって思わぬエラーが発生することがある．  
シングルトンパターンを使えばそんな予期しないエラーを未然に防ぐことができる．

## メモリの消費量が抑えられる
無駄なインスタンス化が減ることで，メモリが圧迫されず，より軽量な設計が可能になる

## 継承やインターフェースを実装できる
シングルトンパターンは継承やインターフェースを実装することができる．これのどこがメリットなのかはのちに解説していく  

# staticとの違い
ここまで学んで一つ疑問に思ったのが，static修飾子つけるのと何が違うのかということだった
つまり，最初に説明したようになるべくインスタンス化したくないクラスを作るのであればstaticつけてしまえば終わりじゃんと思った

しかし，メリットをよく見返してみるとstaticとの違いが見えてきた．
staticとシングルトンパターンの違いは大きく分けて2つ

1. 1つしかインスタンス化されないことが「保証」される
2. 継承，インターフェースが実装できる

以上2つがstaticとシングルトンパターンの違いだと考えられる．

## 1つしかインスタンス化されないことが「保証」される
どんなにコメントなどで「このクラスはインスタンス化しないこと」，などと書いていても実装するのは人であるため，その法則が守られる保証はない．それによって様々な実装方法が存在する状況になり，コードの可読性も下がり，バグの温床にもなり得る．しかし，シングルトンパターンを用いればそのクラスは１度しかインスタンス化されないことが**保証**されているため，そのようなことが起きにくくなる．

## 継承，インターフェースが使える  
シングルトンパターンを用いたクラス自体にももちろん，継承やインターフェースを実装することができます．これは大規模なサービスになればなるほど威力を発揮するもので，継承元のクラスやインターフェースによってクラスが管理できるためサービス全体をみた時の拡張性が広がる場合がある．

# シングルトンパターンのデメリット
## 拡張性に問題が出る場合がある  
staticの違いの部分でシングルトンパターンを用いることができれば，拡張性が広がる場合があると述べたが，一方で狭まってしまう場合もあり得る．その原因となるのが将来的にそのクラスが本当に１つのインスタンスを生成することで役割を果たせるのか予測が困難ということがある．だからこそ，シングルトンパターンの使い所を十分に理解し，本当に必要な場面でのみ扱うことが重要である．  

## ユニットテストがやりにくい
ユニットテストを行う際はクラス間が疎結合であることが前提になっている．つまり，クラスが依存関係にないということである．
具体的に考えてみると，あるクラスに変更を加えた際に，他のクラスにも影響が出ることが前提として設計されていたら一つのクラスを改修しただけなのに影響範囲が大きくなってしまう．そのため，テスト工数も多くなり開発全体で考えたらクラスが疎結合である方が効率が良い．
シングルトンパターンを採用すると理論的には独立しているはずのクラス間の関係に暗黙的な依存関係が生まれてしまう．そのため，ユニットテストを実施する際に邪魔なものになる．

# シングルトンパターンの使い所
ここまででシングルトンパターンは，使い所を間違えると将来的に致命的な技術的負債になり得るということがわかった．  
そこで，実際にシングルトンパターンをどのタイミングで使うべきなのか考えてみる．  

上記のメリット，デメリットから考えると以下の条件を満たす場合にのみシングルトンパターンを使うべきであると考えられる．  

* 動的なクラスでない場合  
引数やSetterなどにより，値が変化することが考えられる場合は将来的に一つしかインスタンス化できない状況が足枷になることがあり得る．
* そのクラスがどのアプリケーションに呼び出されるか意識しない場合  
そのクラス自身が他のクラスなどに依存せずに，呼び出され先を意識しないで済むかを考える．
* 継承やインターフェースをしたり，されたりするか  
staticではできないこと，シングルトンパターンの特徴の一つ
* 他のアプリケーションは常にこのクラスの1つのインスタンスを必要としているか  
やはり，1つのインスタンスしか生成できないことが将来的にデメリットになる場合が多いためとても重要な条件  

上記の場合を**全て満たす場合にのみ**シングルトンパターンを適用する意味が生まれる．  

# まとめ
シングルトンパターンは使うと便利なデザインパターンであるが，本当に必要なときにのみ使うべきであることがわかった．
つまり，シングルトンパターンを**使う理由がある時のみ**に使うべきであるということである．

上記の使い所をしっかり理解した上で，シングルトンパターンを使うことで将来の技術的負債を生まないようにしたい．
Azure Cosmos DB の Jupyter Notebook 機能による脆弱性対応について

# はじめに

この記事は、[こちら](https://zenn.dev/ymasaoka/articles/addr-vulnerability-cosmosdb-notebook) で公開しているものの転載です。  

https://zenn.dev/ymasaoka/articles/addr-vulnerability-cosmosdb-notebook

# 脆弱性の概要

Azure Cosmos DB を活用している 3,300 を超えるユーザーにおいて、Azure Cosmos DB の読み取り/書き込み用プライマリキーが Azure Cosmos DB の Jupyter Notebook 機能の欠陥によって流出し、外部の攻撃者によって、Cosmos DB 内にあるデータの完全読み取り/書き込み/削除が実行可能の状態になっていました。
現在は、2021/8/27 現在、Jupyter Notebook 機能はいったん無効化され、脆弱性については修正プログラムが適用された模様です。  

Jupyter Notebook 機能については、2019 年にプレビュー提供が開始され、2021 年 2 月以降では、[29 のリージョン](https://docs.microsoft.com/ja-jp/azure/cosmos-db/enable-notebooks#supported-regions) で新規作成された Azure Cosmos DB アカウントは Jupyter Notebook 機能が自動適用されているものになります。日本の Azure リージョンでは、西日本リージョンが対象に含まれています。東日本リージョンについては、含まれておりません。

Microsoft / Wiz 社の発表では、`この脆弱性による不正な顧客データへのアクセスは Wiz 社のセキュリティ研究者以外では利用された形跡はない`としています。
ただし、Microsoft 社もこの機能の欠陥によって読み取り/書き込み用のプライマリキー情報が流出したことによる顧客データ流出はないものの、下記の公式情報を参考にキーの再生成を行ってください、とのことです。キー情報が流出してしまった可能性もゼロではないからと思われます。  


# 読み取り/書き込み用プライマリキーの再生成方法

公式では、キーのローテーション機能で対応可能とのことです。
2021/8/28 時点で、英語版と日本語版とでは情報の更新差分があるようですので、可能な方は英語版の公式ドキュメントを参照していただければと思います。(ブラウザの翻訳機能を活用すれば読み取りは可能と思います)

■英語版ドキュメント

https://docs.microsoft.com/en-us/azure/cosmos-db/secure-access-to-data?tabs=using-primary-key#primary-keys

■日本語版ドキュメント

https://docs.microsoft.com/ja-jp/azure/cosmos-db/secure-access-to-data?tabs=using-primary-key#primary-keys

他にも、Azure CLI に `az cosmosdb regenerate-key` コマンドが用意されています。こちらのコマンドを使用して、読み取り/書き込みのプライマリのキーを再生成することも可能です。  

https://docs.microsoft.com/ja-jp/cli/azure/cosmosdb?view=azure-cli-latest#az_cosmosdb_regenerate_key

https://docs.microsoft.com/ja-jp/azure/cosmos-db/secure-access-to-data#primary-keys


# Microsoft 公式発表

今回の脆弱性の内容、および対処方法、その他について案内されています。

https://msrc-blog.microsoft.com/2021/08/27/update-on-vulnerability-in-the-azure-cosmos-db-jupyter-notebook-feature/


# Microsoft 社からメールが送信された人は対応が必要の模様

この脆弱性については、Microsoft 社で報告が行われた後に調査が行われ、調査期間中に影響を受けたと思われる顧客に対しては、以下のようなメールが送信されている模様です。

![](https://storage.googleapis.com/zenn-user-upload/7c9a6db92de4da4a8f805066.png)

https://twitter.com/sagitz_/status/1431045786712920074


# 今回の脆弱性の詳細について

Wiz により公開される予定になっていますので、興味がある方はこちらのサイトをウォッチしておいてください。  

https://www.wiz.io/blog


# 関連リンク

- [Update on the vulnerability in the Azure Cosmos DB Jupyter Notebook Feature - Microsoft Security Response Center](https://msrc-blog.microsoft.com/2021/08/27/update-on-vulnerability-in-the-azure-cosmos-db-jupyter-notebook-feature/)
- [ChaosDB: How we hacked thousands of Azure customers’ databases](https://www.wiz.io/blog/chaosdb-how-we-hacked-thousands-of-azure-customers-databases)
- [Microsoft Azure cloud vulnerability is the 'worst you can imagine'](https://www.theverge.com/2021/8/27/22644161/microsoft-azure-database-vulnerabilty-chaosdb)