OmniAICreator/Qiita-1.07M huggingface dataset:
【Go言語】 unsafe.Pointerでカプセル化を破壊する

# 突然ですが…

外部のパッケージにこんな structがあったと思ってください：

```golang
package dokoka

type Nanka struct {
    data string
}

func New(d string) *Nanka {
    return &Nanka{data:d}
}

func (n Nanka) String() string {
    return "（´-`）.｡oO(" + n.data + ")"
}
```

そいでもって、別のパッケージからこの `data` にアクセスすると、

```golang
package main

import (
    "fmt"
    "dokoka"
)

func main(){
    n := dokoka.New("あれ")
    n.data = "これ"
    fmt.Println(n)
}
```

怒られます。こんなふうに↓

```
n.data undefined (cannot refer to unexported field or method data)
```

そりゃそうですよね。Go言語では小文字ではじまるフィールドは外部からはアクセスできないんですから。（いわゆるprivateフィールドというやつです）


# それでも…

どうしてもprivateフィールドにアクセスする必要がある！そんなこともありますよね。

そんな時には `unsafe.Pointer` という黒魔術を使うことで privateフィールドというカプセルを破壊することができちゃいます：

```golang
n := dokoka.New("あれ")
x := (*struct{ data string })(unsafe.Pointer(n))
x.data = "これ"
fmt.Println(n)  // （´-`）.｡oO(これ)
```

Go言語では普通、互換性のない型どうしの変換[^1]はできませんが、`unsafe.Pointer` は任意の参照型との変換ができるという特殊な特徴を持っています。
そのため、`unsafe.Pointer` を経由して同じ構造を持った構造体への参照に変換してやれば、あら不思議 privateだったフィールドにもアクセスできてしまいます。自パッケージ内で定義された構造体なら、privateフィールドでももちろんアクセスできますからね。（※ここでは匿名の構造体に変換しています）

[^1]: conversion。C言語にならってキャスト（cast）と呼ぶ人もいますが、Go言語での正確な呼び方はconversionです。

なお前提として、アクセスする対象の **正しいstructの構造を知っている必要があります**。structの構造が違っていたり変わったりすると、**破滅的な結果をもたらす**ので注意しましょう。


# なんでこんなことする必要が…？

ここからはこんなことをする事になった経緯なんですけどね、[go-simplejson](https://github.com/bitly/go-simplejson)っていう便利なパッケージがありましてね。とっても便利に使わせてもらっていたんです。
で、ある時、`encoding/json` にある `Decoder` の simplejson版がほしくなったわけです。

サクッと作ろうとしたら、simplejson の構造体は privateフィールドになってて、サクッと作れなかったんですよ↓

```golang
type Json struct {
    data interface{}
}
```

privateフィールドにアクセスする必要があったので、simplejson自体に Decoder を追加して [pull requestも送った](https://github.com/bitly/go-simplejson/pull/85) んですけど受理されず[^2]……とはいえ、forkしたバージョンを保守するのもめんどくさい……
だったら、カプセルの中にお邪魔して書き換えちゃえばいいか、と思って[別パッケージとして作り直した](https://github.com/Maki-Daisuke/go-simplejson-decoder)次第です。

こういう、「ちょっと今だけこのprivateフィールドにアクセスできたら問題解決するんですけど！」っていうことって、皆さんも経験したことあるんじゃないですか？そんな時にはこういうワザもあるということを覚えておくと便利ですよ。

でも、乱用はダメ、絶対！


[^2]: 自分に限らず他の人のPRもずっと放置されているので、外部からのPRを受け付けてないだけと思われます。


# まとめ

カプセル化の破壊は、要領・用法をまもって正しくお使いください。
【GCP】ログの見方

GCPのネットワークのかんしをするにはフローログをオンにしたほうがよさそう
https://japan.zdnet.com/article/35117391/
https://qiita.com/watarin/items/d867dcfac9cfd62abbc0

resource.type="gce_subnetwork"
jsonPayload.connection.src_ip="40.115.185.192"

こういう書き方で検索できる

CSVが圧倒的にみやすい

Saasはネットワークのログを追えない
【GCP】API関連についてまとめる

GCPはAPIがいろいろあって、便利なんだけど、仕組みがややこしい。。
なんでこんなにユーザーフレンドリーじゃないんだろう。
開発者が、運用側のことを考えずにシステムを投げてきた感じにちかい。

＝＝＝

そもそも、Goolge関連のAPIは、
「Cloud　API」と「Gsuite　API」にわかれる。

料金がかかるものは、紹介ページまでいけば記載があって、記載がないものは基本的にAPIの料金はかからない。

＝＝＝


Cloud　API関連
ラインナップ＝https://cloud.google.com/apis?hl=ja　（drive api とか　sheets apiはここに書いてない）
https://cloud.google.com/apis/docs/capping-api-usage?hl=ja&visit_id=637423966207247728-903137480&rd=1　⇛「Cloud Console で [API とサービス] の [ダッシュボード] ページに」でコンソールへ⇛確認したいAPIをクリック⇛learn more でドキュメントへ⇛料金の項目を見る⇛例：https://cloud.google.com/bigquery/pricing　こんな感じで料金がみれるみたい
ラインナップ＝https://cloud.google.com/apis/docs/overview?hl=ja

G Suite API
https://support.google.com/a/answer/6103110?hl=ja
ラインナップ＝https://developers.google.com/gsuite/aspects/apis/overview?hl=ja
ラインナップ＝https://developers.google.com/gsuite/products?hl=ja
このへんも一部ある＝https://cloud.google.com/pricing/list?hl=ja　⇛　ここのAPIをみて　https://cloud.google.com/healthcare/pricing?hl=ja　こんな感じで料金が書いてある

Google Maps Platform 
https://cloud.google.com/maps-platform/?hl=ja&utm_source=google&utm_medium=cpc&utm_campaign=FY18-Q2-global-demandgen-paidsearchonnetworkhouseads-cs-maps_contactsal_saf&utm_content=text-ad-none-none-DEV_c-CRE_351523603405-ADGP_Hybrid+%7C+AW+SEM+%7C+SKWS+~+Maps+%7C+EXA+%7C+Mapping+APIs-KWID_43700044579285507-kwd-301485311882-userloc_1009255&utm_term=KW_maps%20api-ST_maps+api&gclid=Cj0KCQiAzZL-BRDnARIsAPCJs73zp2Qu0ATYPnmaG6SXKGZcCGNx3Z6wvCjt6FTnzgUEIQ7d5pUcLlIaAqSHEALw_wcB
料金はかかるみたい＝https://cloud.google.com/maps-platform/pricing?hl=ja


公式ではないけど、関連するAPIをQiitaに書いてる人がいる
https://qiita.com/mikan3rd/items/ba4737023f08bb2ca161
Expressとexpress-graphqlで簡易なGraphQLサーバーを立てる

Expressとexpress-graphqlで簡易なGraphQLサーバーを立てることについては、
すべてGraphQL.js公式に書いてあります(じゃあなんでこの記事書くんだ)

Getting Started With GraphQL.js
https://graphql.org/graphql-js/
Running an Express GraphQL Server
https://graphql.org/graphql-js/running-an-express-graphql-server/

その前に、段階を踏んでGraphQLクエリが試せるこちらの記事を最初にやってみるのがおすすめです(npmモジュールは違うもの使ってる)

Web API初心者と学ぶGraphQL
https://qiita.com/SiragumoHuin/items/cc58f456bc43a1be41b4

下記コードも、GraphQL.js公式のものに少し処理(引数やらforやら)を加えているので、やっぱり公式を見ていただいた方がわかりやすいです(じゃあなんでうんぬん)

## 概要
・express,express-graphql,ngraphqlをインストール
・graphqlからbuildSchemaをrequireして、スキーマを定義
・クエリごとに関数を定義してrootオブジェクトにまとめる
・express-graphqlからgraphqlHTTPをrequireして、expressルーターにマウントする。
(shemaにbuildSchemaで定義したスキーマを、rootValueにrootオブジェクトを設定し、graphiql(クエリ試せるツール)はtrueにする)
・サーバーを立てる

## コード

```js:index.js
const express = require("express");
const { graphqlHTTP } = require("express-graphql");
const { buildSchema } = require("graphql");

const schema = buildSchema(`
  type Query {
    hello(persons: [String]): [Text]
  },
  type Text {
    text1: String,
    text2: String
  },
`);

const root = {
  hello: ({ persons }) => {
    let text = [];
    for (const person of persons) {
      let hash = {
        text1: "Hello world !",
        text2: `Hello, ${person}さん！`
      };
      text.push(hash);
    }
    return text;
  },
};

const app = express();
app.use(
  "/graphql",
  graphqlHTTP({
    schema: schema,
    rootValue: root,
    graphiql: true,
  })
);
app.listen(4000);
console.log("Running a GraphQL API server at http://localhost:4000/graphql");
```

クエリは、```node index.js```でサーバーを立てると、GraphiQLというクエリをブラウザ上で試せるツールが立ち上がるので、その入力欄に

```
query {
  hello(persons: ["tarou", "hanako"]) {
    text1
    text2
  }
}
```
と入力すれば、

```
{
  "data": {
    "hello": [
      {
        "text1": "Hello world !",
        "text2": "Hello, tarouさん！"
      },
      {
        "text1": "Hello world !",
        "text2": "Hello, hanakoさん！"
      }
    ]
  }
}
```

と返ってきます。

![スクリーンショット 2020-12-05 6.45.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555201/abb02f32-ef1d-267f-eac3-50e4affbe264.png)

curlだとこんなかんじ。

```
$ curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ hello(persons: [\"tarou\", \"hanako\"]) { text1 text2 } }" }' http://localhost:4000/graphql
```
readlineとは何か、どんな問題があるか

この記事は、[上智大学エレクトロニクス研究部Advent Calendar](https://qiita.com/advent-calendar/2020/sophia_ele_lab)第5日目の記事です。

## まえがき

コマンドのインストール時にエラーが発生する場合、 `readline` が絡んでいることが多いです。これは `readline` にバグがあるわけではなく、それだけ多くのコマンドに `readline` が使われているということの証です。しかし、この `readline` とは一体何者なのでしょうか。この記事ではそれを明らかにします。

## `readline` の役割

`readline` はラインエディタというものの一種で、ライブラリとして配布されています。その名の通り、ライン(行)をエディタ(編集するもの)という意味で、一般的にシェルがコマンドを受け付けるところで使われています。コマンドは基本的に1行しかないためこのような名前になっているわけです。

## `readline` の必要性

単に文字を入力するだけであればエディタまでリッチなものは必要ありません。しかし、高度なカーソル移動、履歴機能、さらに[インクリメンタルサーチ](https://wa3.i-3-i.info/word13753.html)といった機能を提供するためには、たくさんコードを書く必要があります。具体例として[rubyによるreadlineの実装](https://github.com/ConnorAtherton/rb-readline/blob/master/lib/rbreadline.rb#L8926)だと8,926行にも及びます。
そこで、共通化できる部分ライブラリ化してしまいみんなで共有しようということになったわけです。ライブラリ化は開発の手間が減るだけでなく、ユーザー側にもメリットがあります。使うコマンドによって動作が異なったら扱いにくくなってしまいますよね。共通化することで操作方法を統一できるため、ユーザーも操作を覚えやすくなります。

## `readline` の落とし穴

そんな素晴らしい `readline` ですが、ライセンスの問題で(主に)MacOSユーザーを悩ませています。
`readline` は `GPLv3` というオープンソースライセンスで公開されています。細かい説明は省きますが、このライセンスにはコピーレフトという特徴があり、 `readline` を利用してアプリケーションを開発する場合は、その開発したアプリケーションのソースコードを公開してねという約束になっています。
これが厄介で `MacOS` を開発しているAppleは自分たちが開発したコードを秘密にしておきたいので `readline` を利用してアプリケーションを開発することができません。そこで、コピーレフトではないラインエディタ `libedit` を利用することになりました。
このラインエディタは基本的に `readline` と互換性があると言われていますが、[履歴ファイルの形式](https://qiita.com/tomtsutom0122/private/6ef08eeb3163ad224bc9)や、キーボード操作のデフォルト設定が異なっています。そのため行編集ツールが `libedit` であると見抜ける人でないと(MacOSでCUIを使いこなすのは)難しいというのが現状です。

## `readline` をカスタマイズする

`~/.inputrc` を編集することでキーバインドの設定を変えることができます。細かい設定を解説すると分量が膨れ上がってしまうので、ここではいくつかの記事を紹介する程度に留めておきます。

- [.inputrcの便利設定](http://blog.digital-bot.com/blog/2013/08/30/more-useful-inputrc/)
- [readline を使うアプリケーションでの入力を便利にする .inputrc](https://orumin.blogspot.com/2017/09/readline-inputrc.html)

## 参考文献

- https://keens.github.io/blog/2016/02/14/readlinenotsukurikata/
最強のオペレーションレコーダー「ScreenToGif」

この記事は[Takumi Akashiro ひとり Advent Calendar 2020](https://qiita.com/advent-calendar/2020/takumi_akashiro "ひとり Advent Calendar 2020")の6日目の記事です。

## 前置き
つい数日前、アドカレ4日目の記事を書いていた俺は操作手順をスクショでとるのに難儀していた。

Win+GやOBSでデスクトップ全体を録画し、AfterEffectsで編集して色々隠し、
PhotoshopでトリミングしてGifを出力。取り直しも数回あった。

俺は数日間の記事を書くだけで、この無為な作業を繰り返し、
早くもこのAdventCalenderを始めたことを後悔し始めていた。

だがScreenToGifと出会って、救われた。

そんなわけで今日はタイトルの通り、ScreenToGifを紹介していく。

## ScreenToGif
ScreenToGif は画面を録画してGifアニメとして出力するフリーソフトです。

使用方法は簡単。
![06_01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294868/901d725e-c921-66c8-ab8d-6ce816a7bd03.gif)
これだけです。

録画した手順
![06_02.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294868/5c9abe93-4df5-359d-955f-67a01dac3ed0.gif)


これでもう、簡単な手順なら順序付きリストを書くまでもない！

と、ここまではいくつかの録画ツールでは達成できそうですが、
このツールの優秀な点をいくつか紹介します。

## 撮影するFPSの変更が簡単

操作手順のアニメーションってコマ数なくても成り立つことが多いです。
ぶっちゃけサイズの無駄です。

なので、撮影するFPSを変更したい……とは思うのですが、
大体録画ソフトのFPSの変更って、ソフト設定の深いところにあったりします。

(OBSの例。配信ソフトと比較すべきではないが、今のPCにはこれしかなかった。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294868/d391deb0-d1d8-12c7-287e-0829017f2e20.png)

たまに最低30fps必要な時もあるので、大体は30とか60で設定して
あとでffmpegに頼んだり、面倒なのでそのまま出してました。

ですが、ScreenToGifのfpsは使いたいところに置いてあります
録画する範囲の選択画面についてます。もうこれだけでプラス1億点したい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294868/9e572476-27bf-1570-9827-616f63b75d16.png)

## モザイク機能

写ってはいけないものが写りこんでしまうことは稀によくあると思います。
そこで活躍するのがこれ、「難読化」です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294868/cc351012-aab4-948e-a04a-8b8c8cb61b01.png)

修正したいフレームを選択して実行するだけで……
![06_03.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294868/5868736c-7784-507a-9c96-44830f68afdb.gif)

簡単にモザイクがかかります！

そうそう、こういうのでいいんだよ……こういうので…
プラス20億点！

## 締め

と、色々便利なScreenToGifは[こちらの公式サイト](https://www.screentogif.com/)で入手が可能です。
寄付可能なフリーウェアなので、ぜひ皆様もぜひ試してはいかがでしょうか。

## 雑記
あまりにもよかったので寄付をしようと思い立って、
[donationのページ](https://www.screentogif.com/donation)を見てたらSteamでウィッシュリストに入れたゲームを投げられる模様…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294868/0894edbf-23f9-79d0-9c5e-d8ff6729784e.png)

久しぶりにわくわくしながらSteamにクレジットを入金し、
アカウントを作って以来、**初めてのギフトを購入しようと試みました**が
Steamでフレンド以外にはギフトを投げられなかったので、仕方ないのでPaypalで金を投げました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294868/5ff6d401-6c70-a2e7-ca47-822023c3b08b.png)

ちょっと悲しい。
Excel関数のみで型番から要素逆引き

## こんな型番からこんな図を作りたい
![図0.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/801284ff-2040-e2c5-24fa-4ae9e00a2e78.jpeg)

## まず型番を構成する各要素表をつくる
![図2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/fcd6ca11-cdb3-c08f-c12f-8d567d78e3a6.jpeg)
計算表に出てきたL,Rは項目2,3の比率を指す。

ややこしいことに1:1のときは型番に姿を表さないので
要素表のL,Rには関数で`=""`と入力
（ただの空白セルだと、後の組み合わせ表で'vlookup'が`0`を返してしまうため）


## 次に要素表から組み合わせ表をつくる

組み合わせ表の作成はこれを使うと瞬殺できる
[全ての組み合わせを生成するマクロ - Qiita](https://qiita.com/akiraa/items/fdad7c0ab46026007766)
![図4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/29463cfa-b43b-8028-45da-fd07ad006609.jpeg)
計算表に引用する型番部分を組み合わせ表に追加する
ここは単純に
`=[@項目1]&[@項目2]&[@L]&[@項目3]&[@R]&[@項目4]&[@項目5]`
といった数珠つなぎでいい


途中で「比率」という項目も分解する
L,Rをそれぞれ`vlookup関数`で要素表から拾う
![図5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/2e7a03ca-7949-e1b7-3655-db22592953a3.jpeg)

## 計算表をつくる

![図6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/559d117e-888e-3023-8116-cb6092b8d901.jpeg)
`C9`セル（項目1）にこんな関数を入れる
![図7.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/33db0aff-12ca-2651-aa6f-42673db04766.jpeg)
組み合わせ表の`型番`(紫)のリストから`元の型番`(赤)を探して各要素の記号を返す、というもの

## 計算表の記号を説明文に変換する
逆引きした記号を見てもわからないので
`VLOOKUP`で内容を引っ張り出す。

最初に用意した各要素表をそれぞれ参照する
![図8.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/2626d23c-6683-3dba-45fb-8da9e7be6646.jpeg)

比率は要素表は記号と同値のため要素表は引用しない
![図9.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/16ab59ba-d3b1-32d4-f546-005f891a0f07.jpeg)

これらを全項目に広げると計算表のできあがり
![図3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/2b54c43c-37aa-eebf-a390-a6ca7fc42b7b.jpeg)

## 仕上げ：見やすいレイアウト構成に配置する
縦長の表ではなくフリー配置の図にも簡単に拡張できる

単純に`&`で繋げたり、改行したいところで`CHAR(10)`を入れればいい。
入力ボックス内の`Alt`+`Enter`による改行は見た目に反映されないので好きに区切ればいい。
![図10.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/c4625942-6280-ccfe-5c77-777786dcc42d.jpeg)
![図11.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/5a515604-2d8a-6bad-0fd0-0c1932b42475.jpeg)

完成
![図0.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/801284ff-2040-e2c5-24fa-4ae9e00a2e78.jpeg)
[zsh]補完機能を有効化する[Docker]

##成功：oh-my-zshから設定
https://matsuand.github.io/docs.docker.jp.onthefly/compose/completion/#zsh

自分の環境ではoh-my-zsh シェルがあったため、下記設定で対応

```~/.zshrc
plugins=(... docker docker-compose
)
```

```~/.zshrc
~~抜粋ここから~~
# Example format: plugins=(rails git textmate ruby lighthouse)
# Add wisely, as too many plugins slow down shell startup.
plugins=(git heroku docker docker-compose)

source $ZSH/oh-my-zsh.sh
~~抜粋ここまで~~
```
viなどで編集後、ターミナル再起動もしくは再読込

```
yutakaf@mi  ~/Desktop/git  docker ...
attach     -- Attach local standard input, output, and error streams to a running container
build      -- Build an image from a Dockerfile
builder    -- Manage builds
commit     -- Create a new image from a container's changes
config     -- Manage Docker configs
container  -- Manage containers
context    -- Manage contexts
cp         -- Copy files/folders between a container and the local filesystem
~~以下続く~~
```
タブでコマンドが補完されるようになった。

##失敗
https://docs.docker.jp/compose/completion.html#zsh
dockerのこっちのやり方だとうまくいかなかった。

コマンド補完自体はできるのだが、ディレクトリ補完が先に働き、うまく機能しなかった。

```
mkdir -p ~/.zsh/completion
curl -L https://raw.githubusercontent.com/docker/compose/$(docker-compose version --short)/contrib/completion/zsh/_docker-compose > ~/.zsh/completion/_docker-compose
fpath=(~/.zsh/completion $fpath)
autoload -Uz compinit && compinit -i
exec $SHELL -l
```

###経緯
Docker学習に伴い、作業した。
[macOS High SierraにDockerをインストールする。【旧バージョン】](https://qiita.com/whiteraccoon/items/108840e06f31a38b0f44)
macOS High SierraにDockerをインストールする。【旧バージョン】

##経緯
開発環境を構築するのを楽したいがため、Dockerを学習中。
開発に使用しているのが、学生時代に購入したmac miniなのでOSが古く、
インストールしようとするも、システム要件から除外されていたため、
旧バージョンを探してきてインストールした。

##環境
```shell
yutakaf@mi  ~/Desktop/git  sw_vers
ProductName:	Mac OS X
ProductVersion:	10.13.6
BuildVersion:	17G14042
```

##インストーラー(2020/12/5現在)
[Docker Desktop Mac](https://hub.docker.com/editions/community/docker-ce-desktop-mac)

![スクリーンショット 2020-12-05 5.25.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/648176/b01f5518-093f-9905-9495-e71cf1d795d8.png)

![スクリーンショット 2020-12-05 5.25.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/648176/ac8b8e67-9d5f-5460-18a4-fffb58b72aae.png)

####翻訳
Docker Desktop forMacは無料で利用できます。
Dockerデスクトップ-macOSはバージョン10.14以降である必要があります：つまり、Mojave（10.14）、Catalina（10.15）、またはBig Sur（11.0）。 Macハードウェアは、Intelプロセッサを搭載した2010以降のモデルである必要があります。

##リリースノートの確認
リリースノートがどこにあるかわからなかったため、探した。
[release-notes](https://docs.docker.com/docker-for-mac/release-notes/)

探してみると、Docker 19.03.13から非推奨になっているらしい。
[macOS10.13のDockerデスクトップは非推奨になりました。](https://docs.docker.com/docker-for-mac/release-notes/#bug-fixes-and-minor-changes-2)
[19.03.12をインストール。](https://docs.docker.com/docker-for-mac/release-notes/#docker-desktop-community-2305)

###インストール後

```
yutakaf@mi  ~/Desktop/git  docker version
Client: Docker Engine - Community
 Azure integration  0.1.15
 Version:           19.03.12
 API version:       1.40
 Go version:        go1.13.10
 Git commit:        48a66213fe
 Built:             Mon Jun 22 15:41:33 2020
 OS/Arch:           darwin/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.12
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.13.10
  Git commit:       48a66213fe
  Built:            Mon Jun 22 15:49:27 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.2.13
  GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683
```

無事起動も完了。

##参考
https://docs.docker.com/docker-for-mac/release-notes/
[旧バージョンのDocker for Macをインストールする](http://tec-shi.com/tips/461/)


##合わせて作業したい。
[zsh]補完機能を有効化する[Docker]
https://qiita.com/whiteraccoon/items/8f5786ea828f0224c117
俺の恋人 ~my covid~

この記事は [クソアプリ Advent Calendar 2020](https://qiita.com/advent-calendar/2020/kuso-app) の5日目の投稿です。昨日は[@takanakahiko](https://twitter.com/takanakahiko)さんの[カメラに映っている人間にスーツ着せるやつをデスクトップアプリにした](https://takanakahiko.hatenablog.com/entry/2020/12/04/233626)でした。ハードルが上がって辛い・・・

## 今年のクリスマスは中止になりました

私はそろそろ結婚したいです。そのため諸々の機会が増える12月には婚活を始めようと思っていましたが、流石にコロナウイルスの感染状況を鑑みると延期せざるをえなくなりました。でもやっぱりクリスマスは恋人と過ごしたい気持ちは諦めきれません。

なので代わりに**理想のCovidと過ごせる**アプリを作りました。それがこの [my covid](https://my-covid.web.app/) です。

## How to Use

使い方は簡単、パーツをクリックで追加して、ドラッグアンドドロップでコロナウイルスにパーツを載せていくだけです。

![Screen Shot 2020-12-05 at 4.04.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89256/9297eead-50ba-ee88-3dfe-cae25fa71560.png)


作った後はこのように画像が生成されます。

![Screen Shot 2020-12-05 at 3.58.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89256/48b3defd-4d32-90ff-d545-f5013db84726.png)

ちなみにトゲトゲはスパイクって言うらしいです。

## 理想のコロナウイルス を作ろう

そして生まれた僕の恋人、コロ奈ちゃんです。

![Screen Shot 2020-12-05 at 4.16.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89256/45d635a9-d9f9-33c6-103c-a83c39f38967.png)

https://my-covid.web.app/share.html?id=9CcE27hlNBIQ9Sfy8fGE

スパイクのないとてもおしとやかな方です。
こんなCOVIDとクリスマスを過ごせるだなんて僕は幸せものだな〜😊😊😊😊😊😊😊😊😊😊😊

## イカれたメンバーを紹介するぜ！

しかしクリスマス起因での交際は21日頃に「ごめん、やっぱり何か違った」など、突然変異してフラれることもあります。どうやらコロ奈ちゃんも突然変異するようです。

### 物理で殴るタイプのCOVID

ワクチンに勝ちたい

![Screen Shot 2020-12-05 at 4.18.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89256/9a174757-5e6a-11ce-4bce-67d887a00e0e.png)


https://my-covid.web.app/share.html?id=tg7aEBbrudN4Z305jCRD

### 既読COVID

今日も500人超えか〜という顔

![Screen Shot 2020-12-05 at 4.19.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89256/1f641e23-5d49-c4de-8b2c-749eb818d2d1.png)

https://my-covid.web.app/share.html?id=GfDoNhri4iOaMu3ZY3bI

### thinking COVID

思ったより感染スピード増えて焦ってる顔

![Screen Shot 2020-12-05 at 4.21.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89256/6ae71e74-3d86-6984-32c4-06c313a95342.png)

https://my-covid.web.app/share.html?id=fiQ5cQv8NPJTtJ992UzS

### グラコロナ

秋に感染者が増えた犯人説（[!Get the facts about COVID-19](https://corona.go.jp/)）

![Screen Shot 2020-12-05 at 4.25.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89256/b10cb62b-5b88-8858-9a90-722bf0fbf7b9.png)

### シャミ子（シャドウミストレス・コロナ）

これで勝ったと思うなよ〜（感染者数が一桁になったことを受けて）

![Screen Shot 2020-12-05 at 4.26.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89256/f6fbc832-7c07-c535-b81e-835a330903da.png)

https://my-covid.web.app/share.html?id=D6HUxM0E1eL4VMQKAhvs

### 震える症状が出るタイプのコロナ

なぜ仮想DOMという概念が俺達の魂を震えさせるのか

![Screen Shot 2020-12-05 at 4.27.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89256/1c91ef4e-c6a6-b537-3957-ba1e738fe6a2.png)

https://my-covid.web.app/share.html?id=fZ3ybOJjRKeWgaiV1Ye1

## まとめ

not stay night, but stay home.

おうちでCOVIDを作ろう！ https://my-covid.web.app/
Twitterのエゴサ結果をIFTTTでSlackに見やすく投稿する


# はじめに

「Twitterの検索結果をSlackに流すにはIFTTTを使えばいい！」って記事はたくさんヒットするんだけど、微妙に検索結果をフィルタリングしたり整形するのに手間取ったので備忘録として残しておきます

![Image from iOS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55365/7b921975-1964-4865-b49c-962a27341803.png)

# 方法

## IFTTTでTwitter→Slack連携

丁寧に紹介してくれている分かりやすい記事があるので、こちらを参照してください。

Twitterで特定の単語を含むTweetを自動で拾ってSlack通知する方法 | by 福本 晃之 | Teruhisa Fukumoto | Medium
https://medium.com/@teruhisafukumoto/how-to-notice-to-slackwhen-speciality-word-are-tweeted-f91a226c5d4e

## 検索結果をいい感じに整形する

ハッシュタグのみなら簡単ですが、いくつかフィルターしたい場合があるので紹介です。

- 複数キーワードの組み合わせや除外
  - 以下のページで設定をして、出てきた文字列をコピペ
  - https://twitter.com/search-advanced
- 検索結果にリツイートを含まない
  - exclude:nativeretweets


参考：【2020年版】Twitterの検索コマンド60種類全まとめ！ユーザー指定や日付指定など使い方を解説 | ヨノイブログ
https://yonoi.com/twitter-search-command/#excludenativeretweets


### Slack上でツイートをいい感じに展開する

IFTTTでは投稿のタイトルや本文の内容、リンク先などを細かく設定することができるのですが、正直重複する内容が多くて見えづらいように思います。なので、いつも見慣れているSlack標準の展開機能を使う形にしてみましょう。

設定は以下の画像を参照してください。初期状態では左のような状態なのですが、右図のように本文にあたる「Messege」のみに「LinkToTweet」を設定してください。そうすると冒頭の画像のように綺麗に展開されるはずです。

![befaf.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55365/5bf47eb2-dc6d-043f-885a-cd3cb1884610.png)

ただこの方法には課題があって、URLのOGPなどは表示してくれません。

その場合はこちらの記事などが参考になるんじゃないかと思います。
http://www.imyme9.com/entry/slack_twitter_eyecatch

# 最後に

所属するMyDearest株式会社ではVRゲーム『[ALTDEUS: Beyond Chronos](https://twitter.com/chronos_series)』の開発をしています。よかったら遊んでみてください！

僕のTwitterもぜひフォローしてくれると嬉しいです：[@nkjzm](https://twitter.com/nkjzm)
Rust で enum に対して手で PartialOrd を実装する方法について考えてみた

enum に対して PartialOrd を実装したいとします。このとき enum を構成する型すべてに PartialOrd が実装されているならば derive マクロで簡単に実現できます。
こんな感じ:

``` rust
#[derive(PartialEq, PartialOrd)] // NOTE: PartialOrd には PartialEq も必要。
enum Foo {
  A,
  B(usize),
  C(String),
}
```

しかし、PartialOrd を実装していない型が含まれる場合は derive することはできません。
これはビルドが通らない:

``` rust
use hoge_crate::NoPartialOrd; // PartialOrd を実装していない何か

#[derive(PartialEq, PartialOrd)]
enum Foo {
  A,
  B(usize),
  C(String),
  D(NoPartialOrd),
}
```

そんなときは手動で PartialOrd を実装します。
以下のようになるでしょう。

``` rust
use hoge_crate::NoPartialOrd;

#[derive(PartialEq)]
enum Foo {
  A,
  B(usize),
  C(String),
  D(NoPartialOrd),
}

use std::cmp::Ordering;

impl PartialOrd for Foo {
  fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
    // NOTE: ここで use しておくとコードが短くなって見通しがよい。
    use Foo::*;
    use Ordering::*;
    match (self, other) {
      (A, A) => Some(Equal),
      (A, B(_)) => Some(Less),
      (A, C(_)) => Some(Less),
      (A, D(_)) => Some(Less),
      (B(_), A) => Some(Greater),
      (B(a), B(b)) => a.partial_cmp(b),
      (B(_), C(_)) => Some(Less),
      (B(_), D(_)) => Some(Less),
      (C(_), A) => Some(Greater),
      (C(_), B(_)) => Some(Greater),
      (C(a), C(b)) => a.partial_cmp(b),
      (C(_), D(_)) => Some(Less),
      (D(_), A) => Some(Greater),
      (D(_), B(_)) => Some(Greater),
      (D(_), C(_)) => Some(Greater),
      (D(_), D(_)) => Some(Equal),
    }
  }
}
```

おっと、match の中で Foo の構成子の組み合わせをすべて列挙しているので長いです！あまり書きたくないですね。

明らかに冗長なので、条件を整理すれば短くできます。

``` rust
impl PartialOrd for Foo {
  fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
    use Foo::*;
    use Ordering::*;
    match (self, other) {
      (A, A) => Some(Equal),
      (B(a), B(b)) => a.partial_cmp(b),
      (C(a), C(b)) => a.partial_cmp(b),
      (D(_), D(_)) => Some(Equal),
      (B(_), A) | (C(_), A) | (C(_), B(_)) | (D(_), A) | (D(_), B(_)) | (D(_), C(_)) => Some(Greater),
      _ => Some(Less),
    }
  }
}
```

`Some(Less)` を返すアームと `Some(Greater)` を返すアームをまとめました。
行数は短くなりましたが、読みづらい上に書くのがめんどくさく、また、バグを埋め込みそうです。
もう少しいい感じに書きたいです。

そこで、`Foo` を受け取ってその構成子が何番目かを返す関数 (`f`) を導入して、こんな感じにしてみました。

``` rust
impl PartialOrd for Foo {
  fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
    use Foo::*;
    match (self, other) {
      (B(a), B(b)) => a.partial_cmp(b),
      (C(a), C(b)) => a.partial_cmp(b),
      (a, b) => f(a).partial_cmp(&f(b)), // デフォルトでは関数 `f` の返り値を使って `partial_cmp` する。
    }
  }
}

fn f(foo: &Foo) -> i32 {
  use Foo::*;
  match foo {
    A => 0,
    B(_) => 1,
    C(_) => 2,
    D(_) => 3,
  }
}
```

だいぶすっきりして読みやすくなりました！よさそう😊

欲を言えば関数 `f` を標準で提供してほしいですが、なさそうなのでこれで満足することにします。
統計検定2級合格への道　〜その⑤〜

### はじめに

*この記事は[統計検定2級合格への道　〜その④〜](https://qiita.com/sakaidamasaru/items/dd2959b9d3871c8a67f7)の続編です。*

この記事は「[改訂版 日本統計学会公式認定 統計検定2級対応 統計学基礎](https://www.amazon.co.jp/改訂版-日本統計学会公式認定-統計検定2級対応-統計学基礎-田中豊/dp/4489022271)」を参考に、私が学んだ内容をまとめたものです。

### 離散型確率分布

#### ベルヌーイ分布

注目している結果の起こる確率は一定で、各回の試行結果は互いに独立であるような試行（例えば、サイコロで偶数の目が出る、コインで表が出る、という試行）を**ベルヌーイ試行**という。
成功の事象と失敗の事象をそれぞれ1と0で表し、成功する確率を$p$とする。特に、1回のベルヌーイ試行で得られる結果の確率分布を**ベルヌーイ分布**とよぶ。

ベルヌーイ分布の確率関数は、以下のように表され、

```math
\begin{align}
P(X = 1) &\equiv f(1) = p \\
P(X = 0) &\equiv f(0) = 1 - p
\end{align}
```

その期待値と分散は、

```math
\begin{align}
\mu &=  p \\
\sigma^{2} &= p(1 - p)
\end{align}
```

となる。

#### 二項分布

成功確率*p*の*n*回のベルヌーイ試行を行ったとき、成功の回数が*x*回、失敗の回数が(*n - x*)回である確率は、以下のように計算される。

```math
P(X = x) \equiv f(x) = {}_{n}C_{x} p^{x} (1 - p)^{n - x}
```

この確率分布は**二項分布**とよばれ、パラメータ*(n, p)*が与えられると確率分布が決定できるので、記号$B(n, p)$で表される。

その期待値と分散は、

```math
\begin{align}
\mu &= np \\
\sigma^{2} &= np (1 - p)
\end{align}
```

となる。

#### ポアソン分布

ポアソン分布は、二項分布$B(n, p)$において期待値$np=\lambda$を固定し、試行回数と成功確率について$n \rightarrow \infty, p \rightarrow 0$のような極限をとったときに得られる確率分布として定義される。
ポアソン分布は、試行回数が大きく（$n \rightarrow \infty$）、起こりにくい（$p \rightarrow 0$）事象を解析するために用いられる。

ポアソン分布の確率関数は、

```math
\begin{align}
f(x) = {e^{-\lambda}\lambda^{x} \over x!}
\end{align}
```

と表され、その期待値と分散は、

```math
\begin{align}
\mu &= np = \lambda \\
\sigma^{2} &= np (1 - p) = \lambda
\end{align}
```

となる。(上記で、$np=\lambda$及び$p\rightarrow 0$を用いた)

#### 幾何分布

成功の確率が$p$であるベルヌーイ試行を、初めて成功するまで繰り返した時の試行回数$X$の確率分布を**幾何分布**という。
$x$回目に初めて成功する場合、それまでの$x-1$回は失敗したことになるため、
その確率は、

```math
\begin{align}
f(x) = p(1 - p)^{x - 1}
\end{align}
```

と表される。

幾何分布の期待値と分散は、

```math
\begin{align}
\mu &= {1 \over p} \\
\sigma^{2} &= {1 - p \over p^{2}}
\end{align}
```

となる。

### 連続型確率分布

#### 一様分布

区間[$a$, $b$]内のどの値も同じ起こりやすさをもつ、すなわち、確率密度関数が

```math
f(x) = \begin{cases}
    {1 \over b - a} & (a \leq x \leq b) \\
    0 & (otherwise)
  \end{cases}
```

で表される分布を**一様分布**とよぶ。

一様分布に従う確率変数を$X$とするとき、その期待値と分散は、

```math
\begin{align}
E[X] &= \int^{b}_{a} {x \over b - a} dx = {a + b \over 2} \\
V[X] &= \int^{b}_{a} {x^{2} \over b - a} dx - \Big({a + b \over 2}{\Big)}^{2} = {(b - a)^{2} \over 12}
\end{align}
```

となる。

#### 正規分布

```math
\begin{align}
f(x) = {1 \over \sqrt{2\pi\sigma^{2}}}\exp\Big\{ -{(x - \mu)^{2} \over 2\sigma^{2}} \Big\}
\end{align}
```

上記のような確率密度関数で表される分布を**正規分布**または**ガウス分布**とよぶ。
この関数は平均$\mu$を中心にして左右対称で$x=\mu$で最大値をとり、
標準偏差$\sigma$を用いて、確率変数$X$が$(\mu-\sigma,\mu+\sigma)$に入る確率は約68%、$(\mu-2\sigma,\mu+2\sigma)$に入る確率は約95%となるという性質をもつ。

確率変数$X$を、

```math
\begin{align}
Z = (X - \mu) / \sigma
\end{align}
```

と変換すると、$Z$は平均0、分散1の正規分布（**標準正規分布**）に従う。このような$X$から$Z$への変換を標準化という。

標準正規分布の確率密度関数は、

```math
\begin{align}
f(x) = {1 \over \sqrt{2\pi}}\exp\Big\{ -{z^{2} \over 2} \Big\}
\end{align}
```

と表される。

### おわりに

どんなデータも、基本的には正規分布で近似しとけば大体上手くいくと信じてます。
vimのマクロの内容をプレーンテキストで編集する

[CBcloud Advent Calendar 2020](https://qiita.com/advent-calendar/2020/cbcloud) の5日目の記事です。

vimのマクロとは、キーストロークを記録してそれを好きなタイミングで再生できるという機能です。
マクロ記録中にミスをして修正したいときや、複雑なマクロを組むときにプレーンテキストでマクロを組みたいときに使える方法を説明します。

# マクロの基本操作

- ノーマルモードでqa（aは任意のキー）を押すと記録開始。画面左下に"recording @a"と出る
- 記録したい操作をする
- qを押して記録を終了。画面左下の"recording @a"が消える
- ノーマルモードで@aを押すと記録したマクロを再生する

# マクロの記録
例を使って説明していきます。
下記のようなテキストがあり、param_typeとdescの位置を内容ごと入れ替えたいとします。
（単純な入れ替えならマクロ使うまでもないというツッコミは無しで...）

```ruby
params do
  requires :foo_id, documentation: { param_type: 'body', type: 'integer', desc: 'fooのID' }
  requires :hoge_note, documentation: { param_type: 'body', type: 'string', desc: 'hogeに関する備考' }
  requires :is_fuga, documentation: { param_type: 'body', type: 'boolean', desc: 'fugaかどうか' }
  # ...
```

任意のrequiresの行にカーソルを合わせ、qaで記録を開始していきます。
記録したい内容は下記です。

```
0/param_type # 行頭にカーソルを移動してparam_typeを検索
vt,d/desc # 検索した位置から「,」の1文字手前を選択して削除後、descを検索
vf';p0/{ # 検索した位置から2個目の「'」までを選択して↑の操作で削除した文字列をペーストして行頭に戻り「{」を検索
lpj # 検索した位置から1つ右にカーソル移動して↑で削除した文字列をペーストして次の行へ
```

# マクロ記録中に操作ミス発生
ところが、fによる検索の繰り返しキーを「;」ではなく間違えて「n」を押してしまいました。
そこで、qキーを押して一旦記録を終了します。
記録したマクロはレジスタに入っているだけなのでレジスタからペーストすることができます。

# 挿入モードでCtrl + r、<任意のキー>でマクロ内容をテキスト貼り付け
適当な場所で挿入モードにして、Ctrl + r、a（aはマクロを記録したキー）でレジスタaの内容を貼り付けします（ノーマルモードからの"apによる貼り付けだとわかりにくい形式になっちゃいます）
すると、下記テキストが貼り付けされます。

```
0/param_type
vt,d/desc
vf'n
```

あとはこれを編集して正しい形にします。
マクロ記録と貼り付けを繰り返せば少しずつマクロを作っていけます。

```
0/param_type
vt,d/desc
vf';p0/{
lpj
```

# テキストをレジスタにヤンクしてそのレジスタを指定してマクロ実行
前述のように、マクロはレジスタに記録されているので、この正しい形になったテキストをレジスタaにヤンクして@aでマクロ呼び出しができます。
ノーマルモードでこのテキストを選択後、"ayをしてレジスタaにヤンク、@aで実行します。

```
params do
  requires :foo_id, documentation: { desc: 'fooのID', type: 'integer', param_type: 'body' }
  requires :hoge_note, documentation: { param_type: 'body', type: 'string', desc: 'hogeに関する備考' }
  requires :is_fuga, documentation: { param_type: 'body', type: 'boolean', desc: 'fugaかどうか' }
  # ...
```

1行だけ入れ替えができました。後は10@a（10回@aを実行）のようにして一気に実行するだけです。

注意点としてはヤンクするときShift + vでヤンクすると最後の行の改行もヤンクされてしまい、jとその改行で2行分下に移動していまいますので選択はvで初めてjで止めてやる必要があります（最後のjを消してShift + vによるコピーでもいいです）
手早く健全にAOSPのコードを流用する

## 概要

アプリで機能を実装する時、AOSPの標準アプリで同じ機能を持っているケースがある。そういうとき、ライブラリを使わずにAOSPからコードを流用すると良いこともある。

- 余分なライブラリを入れなくて済む。素のAndroid APIだけで実装されているので。
- APIの使い方が上手く、参考になる。Androidの中の人たちが実装しているので。
- 単にライブラリを使うだけだとブラックボックスになっているAndorid Frameworkの仕組みの一端が知れる

ということで、AOSPからのコードの流用する手順を記す。

## 手順

1. 実装したい機能を持っていそうなAndroid標準アプリを思い浮かべる
2. [Android Code Search](https://cs.android.com/)で、AOSPのソースコードで、目的の機能を実装しているファイルを探す[^1]
3. 目的のファイルを自分のプロジェクトに取り込む
  - ライセンスは大体「Apache License Version 2.0」。
  - 以下の手順は、そのルールに準拠するためのもの。
4. コードを修正したら、そのファイルの目立つ箇所に変更点を記述する
5. 元のファイルのプロジェクト内のNOTICEファイルを探して、自分のプロジェクトにコピペする
6. Apache License Version 2.0の成果物を使っていること、Licenseの使用許諾書のコピーを利用者に示す

## ケーススタディ

### 0. 前提
端末の向きを変えた時、画面全体でなく一部のViewだけ回転させる機能を実装する。
そのViewは、ライブラリとして頒布する。
以下、イメージ。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/196890/fd2b5692-ac49-e400-3774-4579e360707a.gif" width="200" />


### 1. 実装したい機能やUIを持っていそうなAndroid標準アプリを思い浮かべる

カメラアプリ。
大体のカメラアプリでは、端末を回転させると画面全体でなくフラッシュアイコンなどの一部のViewだけが回転するから。

### 2. AOSPのソースコードで、目的の機能を実装しているファイルを探す

AOSPのカメラアプリのソースコードを探す。

1. [Android Code Search](https://cs.android.com/)にアクセス。
2. Android -> リポジトリ「platform-subproject」 -> packages -> appsを選択
  - 中を見るとCamera2とLegacyCameraがある。これがAOSPのカメラアプリ。
3. それっぽい単語"Rotate"でpackages/appsの中を検索
  - 「packages/apps/LegacyCamera/src/com/android/camera/ui/RotateLayout.java」が見つかる。コードを見ると、実現したい機能を実装しているViewであることが分かる。

### 3. 目的のファイルを自分のプロジェクトに取り込む

タイトルそのままのことを実施。必要に応じて、適宜修正を加える。
ファイルの先頭の方にあるCopyrightやApache License Version 2.0の部分は消したり修正しないこと。ライセンスのルール違反になる。

### 4. コードを修正したら、そのファイルの目立つ箇所に変更点を記述する

「目立つ」箇所というのは、Apache License Version 2.0の原文でそう書かれている。
正直、「目立つ」の基準はよくわからない。

とりあえず、もともとのライセンス文の少し下に変更点を書いておく。
以下、例。

```
/**
 * Changes from the original file
 *
 * - The original file was changed from Java to Kotlin.
 * - Refactored code
 * - ...
 */
```

### 5. 元のファイルのプロジェクト内のNOTICEファイルを探して、自分のプロジェクトにコピペする

ここでは、AOSPのpackages/apps/LegacyCameraからファイルを流用したので、この中にNOTICEファイルがないか調べる[^2]。

[Android Code Search](https://cs.android.com/)を使って探すと、LegacyCameraに直下にNOTICEファイルが見つかるので、自分のプロジェクトにコピペする[^3]。

### 6. Apache License Version 2.0の成果物を使っていること、Licenseの使用許諾書のコピーを利用者に示す

ライブラリプロジェクトなので、ライブラリのREADME.mdに以下の記述を含める[^4]。

```
This library includes the work that is distributed in the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).
```

## 実践例
https://github.com/KamikazeZirou/rotateview


[^1]: Androidのビルドできる環境を構築 -> Emulator起動 -> 標準アプリをリモートデバッグすると、検索よりも絞り込みが簡単だが、手早くはパクれない。
[^2]: NOTICEファイルがない場合は、自分のプロジェクトにコピペする必要なし。
[^3]: プロジェクトがアプリの場合は、アプリにNOTICEの内容を表示する画面を入れて、見れるようにすればよさそう。
[^4]: プロジェクトがアプリの場合は、アプリにApache License Version 2.0の内容を表示する画面を入れて、見れるようにすればよさそう。NOTICEと内容重複しているので、NOTICEの表示するなら、対応不要。
人勧センサが感知している時間を正確に計測したい

myjlabアドベントカレンダー4日目。徹夜して頑張ります。

## 前提
pythonを使用します。ラズパイと人勧モジュールセンサを所持している。接続された状態である。接続に関しては[こちら](https://chasuke.com/motionsensor/)を参考にしてください

##人勧モジュールセンサとは
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500962/a5ddc2fa-4552-5f9a-bad7-e21a33ad3043.png)

家電にたまについているようです。赤外線で熱源体を感知するセンサ。近くに生物が存在しているのか、いないのかという一次元の情報を取得できます。

装着されているねじを回して感知距離と検知時間(一度検知した情報を保持する時間)を調節できるのですが、細かい調節は不可能です。


## 感知されている時間を計測する
時間を計測するプログラムを書きます。

```sensor.py
import RPi.GPIO as GPIO
import time

start_time = None
time_list = []
array = [0]*7

GPIO.setmode(GPIO.BCM)
GPIO.setup(18,GPIO.IN) #18はセンサと接続しているpin番号の例

def calculate(x, y):
  delta_time = x - y
  delta_second = delta_time.total_seconds()
  return delta_second

try:
  while True:
    for i in range(7):
      array[i] = GPIO.input(18)
      time.sleep(1)
    if array[0] == GPIO.HIGH or array[1] == GPIO.HIGH or array[2] == GPIO.HIGH or  array[3] == GPIO.HIGH or  array[4] == GPIO.HIGH or array[5] == GPIO.HIGH or array[6] == GPIO.HIGH:
      if start_time is None:
        start_time = datetime.now()
      time.sleep(53)
    else:
      if start_time is None:
        time.sleep(53)
      else:
        finish_time = datetime.now()
        delta_second = calculate(finish_time, start_time)
        time_list.append(delta_second)
        start_time = None
        time.sleep(53)

except KeyboardInterrupt:
  print(time_list)
  GPIO.cleanup()
```
ここでみそとなるのはこの部分です。

```.py
for i in range(7):
      array[i] = GPIO.input(18)
      time.sleep(1)
    if array[0] == GPIO.HIGH or array[1] == GPIO.HIGH or array[2] == GPIO.HIGH or  array[3] == GPIO.HIGH or  array[4] == GPIO.HIGH or array[5] == GPIO.HIGH or array[6] == GPIO.HIGH:
      if start_time is None:
```
今回は7回繰り返して生物の有無を確認していますが、人勧モジュールセンサの感度には個体差があるので調整する必要があります。

##終わりに
安く手に入る人勧モジュールセンサですが、扱いには少し気を使ってあげる必要があります。取り扱いの説明書等も特にないので初めて使用する人の役に立てば幸いです。
k8sとGitOps

この記事は「[イエソド アウトプット筋 トレーニング Advent Calendar 2020](https://adventar.org/calendars/5888)」5日目の記事です。
GitOpsってk8sと親和性も高くて採用するとこういうところが嬉しいよねって話です。

# Reconciliation loop
k８sはマニフェストに定義されたあるべき状態を保つために、Reconciliation loopという考え方が用いられています。
ざっくり言えば以下の図のような形で観測と分析と実行を繰り返しています。

Observeは APIサーバに問い合わせて、適用されたマニフェストによって定義された"あるべき姿"を観測していて、Analyzeは現在の姿と先ほど取得したあるべき姿を比較します。そして、Actは差分があればその差を埋めるように命令を出して、クラスターをあるべき姿に保ちます。

![スクリーンショット 2020-12-05 1.33.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218049/0dc8bbc5-3040-d48e-a4e5-71046b73e34d.png)

# GitOps
GitOpsとは、gitのレポジトリを唯一の信頼できる状態として管理をし、その状態の変更を検知することによってオペレーションを実施するCI/CDにおける考え方の一つです。
GitOpsを実現するソフトウェアとしては「ArgoCD」や「Flux」などが有名です。
GitOpsを用いたCI/CDでよく利用されるアーキテクチャは以下の通りです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218049/e5cfe868-df1e-926c-523b-1db4b24754c7.png)

考え方としてはReconciliation loopと大きく似通っています。
Gitの状態を観測し、変更があればそれを検知し、Git(あるべき姿)とk8s(現在の姿)を比較して、差分があればその差を埋めるように命令を出してクラスターをあるべき姿に保ちます。

こうして見るとk8sとGitOpsの状態を保つための基本的な考えは同じであり親和性が高いと感じます。

# GitOpsを採用すると嬉しいこと

## gitを用いてクラスター状態の確認と更新を容易に行うことができる
gitは開発者が日々使い慣れているツールです。そのツールを利用してインフラのリソースを管理することによって開発者は比較的容易に、インフラの現在の状況を常に確認、更新をすることができます。

## k8s上で参照権限ユーザを管理しなくてよくなる
従来ですと仮に開発者からクラスターの中の状態を参照したいと言われた場合、参照権限のみを持つサービスアカウントを作成してRBACの設定をして提供するか、ダッシュボードツールを提供する必要がありました。
GitOpsを利用することでレポジトリの参照権限だけを管理すれば良くなるためk8s上でのサービスアカウントの管理の手間が減ります。

## PRを用いて承認フローを簡単に組み込める
例えばmasterブランチが本番環境と同期をしているとします。
プルリクエストを利用し、本番環境へのマージをレビューしてもらうようなフローを組むことで簡単に承認フローをデプロイプロセスの一環に組み込むことができます。

# 最後に
深夜に書いたので誤字・脱字など多いかもしれませんがご容赦ください。
来週も土曜日に何かしらのネタを書くのでよろしくお願いします。
学び直し Part2 MVC、scaffold

今日の教科書
[神戸プログラミングアカデミーチュートリアル](https://www.prog-ac.com/archives/1230)

#MVCについて
参考：[MVCモデルについて](https://qiita.com/s_emoto/items/975cc38a3e0de462966a)

##メモ
MVC、モデル・コントローラ・ヴーであることはわかっていた。
ただ流れの認識に齟齬があった。VからCにいき、Mでデータを処理してそのままVに渡しておわりかと思っていたが、その前にCからVに表示する命令があったり、VがMを参照する動きがあるのは知らなかった。学び直しはだいじ。

#scaffoldについて

参考：[覚えておくと超便利！Ruby on Railsのscaffoldの使い方【初心者向け】](https://techacademy.jp/magazine/7204)

##気になったポイント
###before_action :authenticate_user!について詳しく
[【Rails】before_actionの使い方を徹底解説！](https://pikawaka.com/rails/before_action)
`authenticate_user!`はdeviceのメソッドの一つ。
https://qiita.com/tobita0000/items/866de191635e6d74e392
全てのアクションの前にログインユーザだけが使えるようにしてくれるということ。

###1ユーザーにつき、1profileしか作れないようにする方法
当たり前だがこれができないと使えない。
newのアクションに

```
@profile = Profile.find_or_create_by(:user_id => current_user.id)
```
これを記載すれば良い。

####find_or_create_byについて
[https://railsdoc.com/page/find_or_create_by)
はじめの１件を取得しなければ作成する。

###アクション後自分の編集画面に飛ぶようにする方法
さらっと流してしまいがちだが何が起こっているのか知っておこう。

```
redirect_to edit_profile_url(@profile)
```
これをnewのアクション内に記入する。
####redirect_toについて
参考：[リダイレクトの設定](https://www.javadrive.jp/rails/controller/index5.html)
やっていることは編集(edit)へのリダイレクト。

>リダイレクトとは、別のURLを呼び出すリクエストを利用者のブラウザから送信してもらうように要求することです。最初に呼び出されたアクションから別のアクションを呼び出しているのではなく、利用者から新しいURLに対してリクエストを出しなおしてもらう点に注意して下さい。

挙動が特殊みたいです。あと、url以外にもアクションとかを設定することもできる。
###エラーメッセージ？を出す挙動について
 >editのアクションには下記を追加する
if @profile.user_id != current_user.id raise
ActionController::RoutingError.new(“Not authorized”)　end

これはログインユーザのidと呼び出したidが違った場合にエラーを通知する処理か。

####raiseと発生させたい例外クラスについて
参考：[Ruby on Railsのraiseの使い例外を発生させる方法を現役エンジニアが解説【初心者向け】](https://techacademy.jp/magazine/28226)
`raise`そのものはメソッド[詳細](https://docs.ruby-lang.org/ja/2.1.0/doc/spec=2fcontrol.html#raise)
制御構造？と呼ばれています。
そして`ActionController::RoutingError.new(“Not authorized”)　`は[組み込みライブラリ](https://docs.ruby-lang.org/ja/2.6.0/library/_builtin.html)と呼ばれていて、書くだけでエラー表示する動きをしてくれるようです。

#覚えておくと便利そうなもの
##コマンド
###rails generate scaffold モデル名 カラム名1:データ型1 カラム名2:データ型2:scaffoldの作成コマンド
##メソッド
###before_action :authenticate_user!:コントローラに設定して、ログイン済ユーザーのみにアクセスを許可する
###@profile = Profile.find_or_create_by(:user_id => current_user.id):newアクションに記入して1ユーザーにつき、1profileしか作れないようにする
###redirect_to:コントローラーのアクション内で自動的にページに切り替える
###raise 発生させたい例外のクラス.new("エラーメッセージ"):プログラムの中で意図的に例外（エラー）を発生させる
esbuildをプロダクトに導入して半分成功して半分挫折した話

# esbuild速え。。。大興奮だ！魔法のよう
これはやばい。やばいのきた。
JavaScript（TS含む）のトランスパイルがすこぶる高速なesbuildなるものがえらい急激に盛り上がってるようです。
いつだって開発のエコシステムに新しいものを取り入れるのはしんどさもありますが、
なんたってこのesbuildの触れ込みを見ると、●●のうん十倍〜100倍トランスパイルが速いだとか。
ちょうど自分が今やっているプロダクトが、ローカル開発でもCircleCIのデプロイビルドでも致命的に時間がかかっていたんで、
ここに挑戦する価値はもはや十分だと、ちょっと試してみました。

## プロダクトの構成ざっくり
- フロントもバックもNodeJS（Nuxtとか、expressとか、そんなとこ）
- というわけで、どちらもWebpack＆babelビルド（バックエンドはbackpack）
- どちらも全コードTypeScript
- フロントはjsx (パンダさんありがとう [vue-tsx-support](https://github.com/wonderful-panda/vue-tsx-support) vue3が本格onになるまで最高だと思ってます)

## 試そうと思った理由
- JavaScriptのビルド（その他cssとかもろもろそうだけど）のトランスパイルのビルド時間が長すぎて辟易としてた（Webpackのhardsourceキャッシュは壊れる事を意識する事自体が苦）
- ちょいと前に試した [vite](https://github.com/vitejs/vite) のローカル開発が、異常なくらいビルドが早くて、esbuildかなり気になってた（esbuildだけの成果じゃないとしても、もう異常なくらい速かったので気になった）
- 関わるPJが増えた（あっちの作業してて、別PJのちょっとしたレイアウト修正をやるためにNuxtとwebpack+babel起動してバンドル生成待ち、、を繰り返すのがいやだし、この体験をチームに引き継ぐのがすごいいやだった）
- プレーンなJSでWebを作るのは、もはや無理（反論みとめまへん。kintoneのプラグイン書いている時もクロスブラウザ意識したりとかしてると生産性落ちるので、結局babelってる）
- ★いまだに「JavaScriptは素晴らしい」という気持ちが強い。ビルドの遅さっていうネガティブなイメージで汚したくない

## 今回のプロダクトに導入した所感
### よかったこと
- バックエンド（NodeJSランタイム側）用のバンドルは、CiecleCIでのビルドに3分から5分くらい要していたのが5秒くらいになった。TSのtypecheckを別出ししたんでフェアにそれを加味したとしてもtypecheckは10秒程度なので、劇的というか魔法のように速くなった
- デグレは今のとこまったくなし
- babelからの差し替えもすっごい楽チン。webpackでts-loader挟んでたとこを置き換えただけ

### 残念だった（できなかった）事
- フロント（Nuxt2）のビルドに採用できなかった

## Nuxt（Vue + tsx）への導入の苦戦
### ぱっと利用できるビルドモジュールがない
[Nuxt ESBuild module](https://github.com/galvez/nuxt-esbuild-module) っていうのをまず試したものの、TS利用環境でそのまま利用するとimportの拡張子に「.ts（tsx）」とか記述しないとパス解決できなく、自前でbuild-moduleを作る事にしてここは解決できた。

### j(t)sx
ESBuild自体は、パラメータで指定したJSXFactory名をちゃんと理解してコードをトランスパイルしてくれるものの、
僕の愛しているわんだふるぱんださんの `VueTsxSupport なんか Not Foundだ` と実行時にエラーになる。（ちなみにVueTsxSupport固有の問題ではなく、vueのjsxでesbuild使う時の問題）
[こんな仕組み](https://www.npmjs.com/package/@vue/babel-sugar-inject-h) で、vue2の$createElementを注入してやる必要があるんだけど、
babel通すとESBuildの利用価値がほぼなくなるので、やるなら自前で書くしかないし、書いている間にプロダクションReadyなviteとか、Nuxtとかやってきそうな気がしてやめた。

### ES5（IE11向け）へのトランスパイルができない
いちおうtargetに `es5` を指定する事はできるんだけど、まだようやっと「本当はやるべきじゃないと思ってたけど、希望多いからやるかぁ」な感じらしく、「ごめんねまだ準備できてない」エラー吐いてプロセス落ちる。
[https://github.com/evanw/esbuild/issues/297](https://github.com/evanw/esbuild/issues/297)
じゃあ、ESBuildが処理した結果をbabelるかぁ、と思ってすぐ「それ意味なくね」と思ってやめた。

## 現時点採用する価値あるか
Nuxt3でも採用をうたっている、viteもすでに採用している、そのほかググると結構採用事例や予定のソースが多く、
今後デファクトになる可能性はとても高いと思ってるっていうのを踏まえた上で、
以下のような人はすぐにでも使う価値はとってもあると思う（babelからの差し替えも結構楽だし、Webpack併用でも十分効果出る）

- NodeJSオンリーのトランスフォームをしたい人
- IE11を考慮しなくて良い人（インハウス向けのWebとか、インハウス向けのkintoneカスタマイズとか、、）
- Vue（2系） with jsxをつこてないプロジェクト
- 今絶賛開発進行中のプロダクトを持ってて、ローンチの頃にはesbuildがes5へのトランスパイルを対応している事をどきどきしながら信じてみたいギャンブラー

## ていうか
Nuxt3 or viteのSSRプラグインの安定したの、はやくこないかなぁ。
Colaboratory から Snowflake にシュッとつないで作業開始する

この記事は[Snowflakeアドベントカレンダー](https://adventar.org/calendars/5085)と[ちゅらデータアドベントカレンダー](https://qiita.com/advent-calendar/2020/churadata)の5日目の記事になります。

## シュッとつなごう

Snowflake のアカウントをもらって、「えーとどれどれ？」って感じになると思うんですが、とりあえずColaboratoryを使ってつないでみるのが早いっす。
今日はものすごい簡単に Snowflake につなぐところをお見せします。

## シュッ

```
!pip install --upgrade snowflake-connector-python
```

![SnowflakeConnect_-_Colaboratory.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75613/2a313358-b781-d9e9-54ab-12372d5bafb5.png)

## シュシュッ

```
import snowflake.connector

user='HOGE_USER'
password='HOGE_PASSWD'
account='hogehoge.ap-northeast-1.aws'

ctx = snowflake.connector.connect(
    user=user,
    password=password,
    account=account
    )
cs = ctx.cursor()
try:
    cs.execute("SELECT current_version()")
    one_row = cs.fetchone()
    print(one_row[0])
finally:
    cs.close()
ctx.close()
```

![SnowflakeConnect_-_Colaboratory-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75613/d9485923-9522-358d-45fc-f394d958eee2.png)


# ついでにpandasも

じゃあ、ついでにpandasと組み合わせて使ってみましょう。

```
!pip install snowflake-connector-python[pandas]
```
![SnowflakeConnect_-_Colaboratory_と_個人LT_発表予定表_-_Google_スプレッドシート_と_新しいタブ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75613/bae7bf59-8008-3a6a-764f-680d410ec10a.png)

```
import pandas as pd
import snowflake.connector

user='HOGE_USER'
password='HOGE_PASSWD'
account='hogehoge.ap-northeast-1.aws'
warehouse='DEMO_WH'

ctx = snowflake.connector.connect(
    user=user,
    password=password,
    account=account,
    warehouse=warehouse
    )
cur = ctx.cursor()
try:
    sql = "SELECT * FROM SNOWFLAKE_SAMPLE_DATA.TPCH_SF1.REGION"
    cur.execute(sql)
    df = cur.fetch_pandas_all()
finally:
    cs.close()
ctx.close()

df
```
![SnowflakeConnect_-_Colaboratory-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75613/986f4e49-b4b4-d7ec-96d0-c635e0fa2b09.png)


# いかがでしたか？

Snowflake アカウントが手に入れば、さくさくっと作業環境ができあがるのではないでしょうか?
ぜひみなさん Snowflake を使ってみてください!
最初の1ヶ月間は**無料**ですし、そもそも、**常時起動しないから使わなければお金がかからない**ので、**クレジットカードを登録しちゃえば、格安のDWHが個人でも持てちゃう**んですよ！
~~Redshiftだとありえないっすよね~~
※学習用メモ デザインパターン:Facade編[PHP]

# Facadeパターンとはどういうものか

Facadeとは**建物の正面**という意味です。
このパターンは異なるサブシステムを単純な操作だけを持ったFacadeクラスで結び、サブシステム間の独立性を高める事を目的としています。(wikipediaより)


クラスやメソッドが多い際、どれを使えばよいか迷ったり、呼び出し順に注意する必要が生じます。
その際にFacadeパターンを用いることで、使用する側はその詳細を知る必要が無くなるので、シンプルな形で利用することができます。

[参考サイト]
https://ja.wikipedia.org/wiki/Facade_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3
https://qiita.com/i-tanaka730/items/911604bcd4136684ff1c
https://www.techscore.com/tech/DesignPattern/Facade.html/

# Facadeパターンを用いるメリット

・処理の窓口を少なくすることで、複雑なものを単純に見せることができる
・外部との結合が疎であるため、パッケージを部品として再利用しやすくなる

# サンプルコード

## 仕様

・所持していないモンスターの情報を取得したい
・全モンスターを取得するクラスと、現在自分が持っているモンスターを比較することで上記の情報を取得する。

所持していないモンスター情報を取得するクラス(Facadeクラス)

```SearchNotHaveMonsters.class.php
class SearchNotHaveMonsters {
    private $playerId = 0;

    public function __construct($playerId)
    {
        $this->playerId = $playerId;
    }

    // 所持していないモンスター一覧を取得
    public function searchNotHaveMonsters()
    {
        $monsters = new Monsters();
        $allMonstersData = $monsters->getAllMonsterData();

        $haveMonsters = new HaveMonsters($this->playerId);
        $haveMonstersData = $haveMonsters->getHaveMonstersData();

        return array_diff($allMonstersData, $haveMonstersData);
    }
}
```

モンスター情報を管理するクラス(DBの管理クラスのイメージ)

```Monsters.class.php
class Monsters {

    // 本来はデータベース
    private $monstersData = array(
        'スライム',
        'ゾンビ',
        'オオカミ',
        'トロール',
        'カラス',
        'オオガマ',
        'ドラゴン',
        'ふしちょう',
        'よろい',
        'まおう'
    );

    // モンスター一覧を取得
    public function getAllMonsterData()
    {
        return $this->monstersData;
    }
}
```

自分が所持しているモンスターを管理するクラス

```HaveMonsters.class.php
class HaveMonsters {

    private $playerId = 0;

    // 本来はデータベースから取得
    private $haveMonstersData = array(
        '1' => array(
            'スライム',
            'ドラゴン',
            'ふしちょう',
            'まおう'
        ),
        '2' => array(
            'オオカミ',
            'トロール',
            'オオガマ',
            'カラス'
        ),
    );

    public function __construct($playerId)
    {
        $this->playerId = $playerId;
    }

    // 所持しているモンスター一覧を取得
    public function getHaveMonstersData()
    {
        return $this->haveMonstersData[$this->playerId];
    }
}
```

## 使ってみる

```php
// playerIdが適当ですが・・・^^:
$playerIdOne = 1;
$playerIdTwo = 2;

$searchNotHaveMonsters = new SearchNotHaveMonsters($playerIdOne);

print_r($searchNotHaveMonsters->searchNotHaveMonsters());

$searchNotHaveMonsters = new SearchNotHaveMonsters($playerIdTwo);

print_r($searchNotHaveMonsters->searchNotHaveMonsters());

/* 結果
Array
(
    [1] => ゾンビ
    [2] => オオカミ
    [3] => トロール
    [4] => カラス
    [5] => オオガマ
    [8] => よろい
)
Array
(
    [0] => スライム
    [1] => ゾンビ
    [6] => ドラゴン
    [7] => ふしちょう
    [8] => よろい
    [9] => まおう
)
 */
```

# まとめ

・サンプルは割とコンパクトだが、あらゆるところへ影響してくる処理の際にこのパターンを用いると途中で状態を整理しやすくなり運用面でも効果がありそうと感じた。
・ラッパークラスにやや似ているような感じがしたが、結構近いのかもしれない。
AWS EC2 macOSインスタンス

![EC2macOS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/605817/5587a154-a121-4918-e101-89379e434dab.png)
#はじめに
Amazon EC2でのmacOSインスタンスが発表されて
やってみた！、つながったよ！との記事がポツポツとで始めてきたので
Mac好きとしては「ここは一つ試してみないと」
ということでやってみました　笑
でも、やってみたの記事はClassMethodさんの記事など多くありますので、
実際のインスタンス作成やVNCサーバーの起動、
クライアントからの接続はそちらを見ていただくとして、
自分なりにやってみて感じたこと困ったことなどつらつらと。
※2020年12月4日時点の話です
※自分のメモ書きでもあるので画像なしでスミマセン
※間違っていたらゴメンナサイ　教えてください〜

#前準備１
macOSは普通のインスタンスを立ち上げるのとは違って
専有ホスト(Dedicated Host)が必須。
で、専有ホストを管理コンソールのEC2のメニューやawscliなどから
確保する必要があるのですが、
私の場合、まず最初にQuata制限に引っかかりました。
AWS管理コンソールからmac1.metalが作れるリージョン
・北バージニア
・オハイオ
・オレゴン
・アイルランド
・シンガポール
のうちどれかを選択し、その左のアカウントのプルダウンから
マイService Quatasを選択
左ペインのAWS　サービスを選択しEC2で検索
Amazon Elastic Compute Cloud (Amazon EC2)を選ぶ
次の画面でmac1を検索すると
Running Dedicated mac1 HostsのQuataがわかります。
適用されたクォータ値が0の場合は、緩和申請が必要なので
クォータ引き上げリクエストを送ります。
ココの値が１以上になったら次に進みます。
※私の場合緩和されるまで、まるまる1日くらいかかりました。
※Quataはリージョン毎なのでシンガポールで緩和されても
　オレゴンでは緩和されていませんので注意。

#前準備2
晴れてQuata制限がとけたら、専有ホスト割り当てです。
私の場合、awscliで割り当てしようとしたのですが
なかなか専有ホストを確保できませんでした。(シンガポールを使っています)

```
$ aws ec2 allocate-hosts --instance-type mac1.metal --availability-zone ap-southeast-1a --auto-placement on --quantity 1 --region ap-southeast-1

An error occurred (InsufficientHostCapacity) when calling the AllocateHosts operation (reached max retries: 4): Insufficient capacity.
```

何度か時間をおいてトライしたら

```
$ aws ec2 allocate-hosts --instance-type mac1.metal --availability-zone ap-southeast-1a --auto-placement on --quantity 1 --region ap-southeast-1
{
    "HostIds": [
        "h-xxxxxxxxxxxxxxxxx"
    ]
}
```
となり無事確保できました。
自分を含め、やってみた系の方々が多かったんですかね？？？

#使えるようになるまで
EC2は普通のインスタンスを立てるのと同じ要領でできます。
AMIではCatalinaとMojaveが選べます。
管理コンソールの場合
ステップ 3: インスタンスの詳細の設定でのホストで
先ほど作った専有ホストを選びます。
選択しないと次に進めませんがｗ
GUIでmacOSを使う場合は
(使わずzshだけでOKという方もいるかもしれませんが〜)
ステップ 6: セキュリティグループの設定で
VNC用にカスタムで5900/TCPを追加しておくと楽ですね。
もちろんあとからでも追加できますが。

で、
ステップ 7: インスタンス作成の確認で確認し、起動！

。。。
管理コンソールでインスタンスの起動具合をみると
割とすぐにインスタンスの状態は起動中になるのですが
ステータスチェックがなかなか終わりません。
初期化が5分、チェック2つに10分くらい
実際sshできるようになるまで合計15分くらいかかりました。

#その他、気になったところとか
・シャットダウンも起動と同じように時間がかかる。
・VNC経由なので仕方がないかもですが
　macOS独自のGUIのエフェクトなどでガクつく。
　→LounchPadでマウスを使って別ページに切り替えるのは難しいｗ
・GUIは英語版です。当たり前ですが。
　日本語化しようとして
　System PreferencesのLanguage＆Regionで
　日本語設定して再起動したらステータスチェックで
　必要ファイルがないとおこられて起動できなくなりましたｗ
・xcodeを入れるにはEBSのサイズをデフォルトより多くとる必要あり。
・なんかいろいろ弄って再起動したらまた起動しなくなったw
・DedicatedHostは作成から24時間リリースできない。
　シンガポールの場合、1時間＄1．354かかります。
　今だと1日3000円から3500円程度でしょうか
　1，2ヶ月つけっぱなしにすると本体買えちゃいそうです。
　しばらく使うならRI検討ですかね。
・GUIログインしたらBig Surのアップデートの通知が。
　アップデートできるのかな？？？

#それでも
いろいろネガティブなことを書きましたが、
それでも15分+α程度でmac mini環境が触れるようになるのは
**<font color="red">素晴らしい、素晴らしすぎです！！！</font>**
近い将来Big SurやM1も予定されているようですし！

でわでわ