OmniAICreator/Qiita-1.07M huggingface dataset:
SREのクラスチェンジ先はCCoEなんじゃね？論者が通りますよ〜

#  はじまりはじまり〜

　この記事は[ディップ株式会社 Advent Calendar 2022の](https://qiita.com/advent-calendar/2022/dip-dev) の初日投稿です！
ついに今年も始まりましたねー！みんながどんな記事を投稿するかとても楽しみ＆読み切れるよう頑張るｗ
折角なのでコードとかOSS検証の技術記事を書きたいとこだったんですが、今年を振り返ってみて、やっぱ**CCoE駆け出し**が大きかったと思い、それを記事にします。

　なお、貼ってある画像は[DreamStudio](https://beta.dreamstudio.ai/dream)で生成しました。
Stable Diffusion系の画像精製ツールですね。これで大喜利ネタ書こうかと思いましたがあんまり面白いの作れなかったのでヤメヤメ

# さてさて

　僕は普段SREをやっている者で、はしくれながらCCoE活動もやっております！！
さて、突然ですが、ゲームでRPGとかである**クラスチェンジ**ってワクワクしませんか？どんな能力使えるようになるのかなー、逆に何が弱点になるかなーって考えたりしますよね。僕はIT業界で、インフラ関連に20年強携わってきて、最近見えてきた事があるんです。
**そう、SREはCCoEにクラスチェンジしていくんじゃないかってこと**

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2334211/4f70183c-7696-7428-4088-748aac4287d8.png" width=25%>

```
※注意書き
クラスチェンジって書いてあるのでCCoE＞SREなの！？って読んじゃうかもだけどその意図は全く無いです。物理サーバーがクラウドに変わったような"変化"という意味で使っています
```

# なんの話やねん？

　繰り返しクドいですが僕は定常業務でCCoE活動を啓蒙していくタスクをもっていまして、なんでこれを始めたかっていうと、インフラの仕事してて、これ改善出来ないか？って課題が溜まっていったので、その時にたまたまCCoEってのがあるよってのを聞いてそれをやってったら解消しないかなって思って~~勝手に~~自己申告で始めたってのがあります。
(という意味では事実婚みたいなもので、正式なロールでは無かったりするけどｗ)
そんで、続けてくなかでSREとCCoE活動の親和性の高さに気づいてったわけです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2334211/0eb9cf1c-90ee-77d4-f326-b719de4e0482.png)

- **1.　色々な情報にアクセスできる**
 開発チームの人は自分の担当するプロダクト外の範囲に入り込むのは難しいと思うけど、SREって兼任だったり、緊急時の対応のためだったり比較的、どこでもアクセス出来る権限をもってたりすると思う。データを取得して可視化するのに障壁が少ないと思いました。

- **2.　運用回避の数だけ課題を良く知ってる**　~~涙の数だけ強くなれるよ！~~
 なんだかんだ運用回避が降ってくることから、システム的なつらみ、イケてないところをよく知っていると思う。運用回避に流されるとプロダクトとして課題として扱われなくなったりするけど、SRE的にはXXとYYは実は関連してて、ZZすると両方同時に解決できるんだけどなーなんてことを知ってたりする。

- **3.　鼻が効く**
 人によりきりじゃないかーー！と言われるかもだけどｗ、SREはダッシュボードから未来を予知するスタンド能力が備わってるジョブであるはずなので、ダッシュボードからシステムの動きを読み取る経験値に長けてるはずです。なので、CCoE活動に必須なダッシュボードとの親和性が高いような・・？

とまぁ、さらに昨今のDXの話なんかでも出ててデータドリブンの仕事にシフトしていくのにCCoEはうってつけだと思っているのです。

```
これまで：　DBのディスク容量が枯渇しそうだーあとXX日までに対処するIssue切って対応しなきゃ！（アラートドリブンでタスクが産まれる
　　　　　　　　　　　　　　　　　　　　　　　　　　　　↓
これから：　S3のアクセス権限まずそうなのがXX個あるー対処するIssue切って対応しなきゃ！（メトリックドリブンでタスクが産まれる
```

みたいにシフトしていくのかと。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2334211/9e772f3c-1e2c-c023-89a3-98b8487df023.png" width=50%>

今年の後半戦ずーっとダッシュボード用のバッチ量産してた気がするｗ
**バッチ書きもSREの仕事の範疇だし、なんかそういうとこも親和性があるよね**

# SREと大きく違ってそうなとこ

　あともう一個CCoEで大事だと思ってるのは、**Exit**があることだと思ってる。
スクラムマスターみたいにいずれ組織に浸透してったら役割を終えることになる。SREは結局浸透してっても最終的には運用者というロールは残るものだと思ってて、それとの差、逆に**浸透させる事からの逆算で中長期計画が建てられる**事がCCoEの良いところだと思う。終わりがあるから、計画を建てられる、これはここ数年学んだ事で最も大きかった。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2334211/163e9a91-695c-56d4-41e7-d7e747bafafd.png" width=25%>


# これから、など

　まだ駆け出しで大した規模も無いんだけど、僕はこの活動自体をとても気に入ってるので引き続きやっていきたいな！って思ってます。来季は正式なロール化によるポータルの設立＆教育関連のコンテンツを立ち上げることを目標にがんばるぞー

軽く宣伝ですが、ぼっちでもCCoE始めるのにとっても心強かったGoogle主催の研究会のお知らせをしておきます。
[Jagu’e’r CCoE 研究分科会](https://jaguer.jp/ccoe-class-room-7/)
なろう！CCoE！！あ、SRE頑張りすぎてクラスチェンジ前に転生しちゃダメよｗ

明日は2日目！
 @dai_chiさんの [バックエンドエンジニアだった僕が、Terraformを習得するまで](https://tech-note.bikunbikun.com/entry/2021/12/04/162742) です。
僕も現職からTerraform使い始めたので自分のこと振り返りながら読むの楽しみです！
Oculus Interaction SDKを使ってみました ～ Grab・Poke改善編 ～

前回「[Oculus Interaction SDKを使ってみました ～ Poke編 ～](https://qiita.com/b0bmat0ca/items/e233e0bc9f165c76fee0)」、前々回「 [Oculus Interaction SDKを使ってみました](https://qiita.com/b0bmat0ca/items/d9da45209939cffcf361)」で、Oculus Interaction SDKを利用して「ものを掴む」「ものをつつく」の基本的な動作を実現しました。

しかしながら、このままだといくつか不都合な点があります。
Oculus Interaction SDKのHandGrabPoseコンポーネントでは、指の可動範囲を制限して、ものを握った見た目を維持することができるのですが、このままの設定だと以下のように指が握っているものを貫通します。
![Grab_before.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729904/3f25efe5-5a30-0bea-6b02-60deeaf2a2d9.png)

また、Poke機能でものをつついた時に以下のように指が貫通してしまいます。
![Poke_before.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729904/4ff687e6-e0a0-a27b-e181-54324b9b7045.png)

これをうまく解決してくれるのが LeftHandSynthetic と RightHandSynthetic です。
今回は、この導入方法についてまとめます。

:::note warn
前回の設定が行われている前提の手順となります。
これらの設定は、OculusIntegrationのサンプルシーン(Oculus > Interaction > Samples > Scenes > Example)を参考にさせて頂きました
:::

# LeftHandSynthetic と RightHandSynthetic の導入
1. OVRHands の下にLeftHandSyntheticとRightHandSyntheticを配置します
![Common1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729904/ff38e6f4-0ddc-1149-4c3a-2cdd84b11b6a.png)
1. OVRHandsのLeftHandSyntheticとRightHandSyntheticにそれぞれ、LeftHand、RightHandを設定します
![Common2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729904/3f1aee6f-8bc6-c747-5682-733f81012449.png)
1. OVRHandsのLeftHand、RightHand配下にあるLeftHandVisual、RightHandVisualをそれぞれ無効化します
![Common3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729904/b626fc57-5d22-4194-8ac3-a4dec3721ad9.png)

# 掴む(Grab)設定編
1. OVRHandsのLeftHand、RightHandの配下にあるHandGrabInteractorのさらに配下、HandGrabVisualを有効化して、それぞれLeftHandSyntheticとRightHandSyntheticを設定します
![Grab1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729904/0614b80b-aedf-6440-e2a4-f20f9329ca73.png)
1. これで、HandGrabPoseコンポーネントの制限が効くようになります(握りしめていますが、HandGrabPoseで指定した制限により、握った形が維持されています)
    1. Fingers Freedom の「Locked」は指定した形で動かない設定です
    1. Fingers Freedom の「Constrained」は指定した形以上に指がめりこまない設定です
![Grab2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729904/de95dc97-6ad8-9d61-baf7-5db519d0b978.png)

# つつく(Poke)設定編
1. OVRHandsのLeftHand、RightHandの配下にあるHandPokeInteractorのさらに配下、HandPokeLimiterを有効化して、それぞれLeftHandSyntheticとRightHandSyntheticを設定します
![Pork1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729904/6ebd2b0e-5b7d-b7f2-5520-d40cc43a5e24.png)
1. これで、つついた時に指が貫通しなくなります
![Pork2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729904/e396a9e0-217d-8791-9f4e-b733cc44404b.png)

Oculus Interaction SDKは、まだまだいろいろできそうなので、検証していきます。
BigQueryでジェネリックプログラミング

以前に以下の記事で特定の要素が配列の中に含まれているかどうかを判定するUDFを紹介しました。

https://qiita.com/shiozaki/items/b2f95ba3db6c5761aa20

しかし、このUDFにはINT64という型情報があからさまに含まれているため、他の型に対応した関数を作りたくなった場合には、ARRAY_STRING_INCLUDEやARRAY_FLOAT_INCLUDEのような関数を作成する必要があります。
1つの関数だけで複数の型に対応させるにはどうすればよいでしょうか？
そのためには、 `ANY TYPE` という特殊な型を使います。
この型を使うことで任意の型を受け取ることができます。

```sql
CREATE TEMPORARY FUNCTION ARRAY_INCLUDE(arr ANY TYPE, val ANY TYPE)
RETURNS BOOL AS ((
  SELECT LOGICAL_OR(elem = val) FROM UNNEST(arr) as elem
));
```

一見すると、動的型付けのような動作をするような見た目ですが、C++のtemplateのように静的情報のみで型チェックが行われます。
そのため、以下のような型チェック違反になるようなコードは、クエリの実行前のdry runのタイミングでエラーが検知されます。

```sql
SELECT ARRAY_INCLUDE([1, 2, 3], "hoge")
-- Invalid function ARRAY_INCLUDE No matching signature for operator = for argument types: INT64, STRING. Supported signature: ANY = ANY Analysis of function Templated_SQL_Function:ARRAY_INCLUDE failed at [6:8]
```

配列などのいわゆるコンテナ型を使ったUDFを書く時には積極的に活用していきたい機能です。
バックエンドエンジニアだった僕が、Terraformを習得するまで

## はじめに
バックエンドエンジニアとしてこの業界に入った自分が、転職を機にDBエンジニアとなりDBの構築、運用、監視を担当することになりました。
過去にはAWSのマネジメントコンソールからポチポチしてリソースを作ることはしてました。
ただ、設定などに関しては動けばよし！みたいなノリで作っていて、詳しいことを理解しないまま作っていたのですが、Terraformを使って作ろうとすると、細かい設定について理解をしていないとすんなり作れなかったのです。Terraform自体も初めて触るのでそこそこ使えるようになるまでに僕がしたこと、参考にしたサイトなどをまとめていきます。

## 記事を読むべき人
- AWSを理解したい
- Terraformに興味がある
- これからTerraformを利用する

## 解決できる課題
- Terraform何もわからないがわかるようになる
- AWS何もわからないがわかるようになる

## 課題の原因
- Terraformだけを理解しても何もできない。

## 習得の流れ〜概要〜
- まずは手を動かそう
- もっと手を動かそう
- ドキュメントを読み込もう
- 更に手を動かそう

## 習得の流れ〜詳細〜
### まずは手を動かそう
エンジニアならとにかく手を動かして覚えよう
僕は書籍を使ってやりました
[実践Terraform AWSにおけるシステム設計とベストプラクティス](https://amzn.to/3gHxLaR)
2019年初版なので最新のTerraformバージョンを利用するとできないことも多いので
しっかりとバージョンを合わせて実施しました。

### もっと手を動かそう
書籍通りに書いて構築したら、今度は設定値を変えたりしてみます
エラーが出てきたら内容を読んでなにがだめだったのかを理解して解消していきます。
ここで明確に気づくのがAWSの知識がないと設定値などに対してよくわからない状態になります。
僕の場合は実務の中でAWSに触れたり、勢いでクラウドプラクティショナーを取得したりで知らない人よりは知っているレベルだったので、AWSについて調べることは少なかったかなと思います。
AWSについての理解が足りなくてもとにかくTerraformの設定値をいじるために
AWSについて調べて設定してを繰り返します。

### ドキュメントを読み込もう
[Terraform Language Documentation](https://developer.hashicorp.com/terraform/language)
Terraformの公式ドキュメントです。
三項演算子についてなども書いてあるので、必要に応じて読み込むと知識が増えます。

[Terraform Registry](https://registry.terraform.io/)
リソースやdataについて纏められている。覚えなくてもいいが常に必要になる。

### 更に手を動かそう
主に構築をすることをしていたが、できたらConfigration Driftを起こして解消することも試すといい。
Configration Drift（インフラストラクチャの乖離）はTerraformで構築した後に、AWSのマネジメントコンソールから対象のリソースの設定（例えばインスタンスタイプなど）を変えてから
Terraformにてplanを実行すると出てきます。
チーム開発をしていると他メンバーがマネジメントコンソールから変更したりも起きうるので先々に体験しておくと対応の幅が広がります。
僕は利用頻度は少ないですが`pull`などのコマンドも実際に試して何ができるのかの理解も深めておくといいです。

## 実務への影響
初めてTerraformを利用してみたけど、Terraformに対しては詰まるところは少なかったと思います。書籍の勉強だけで書く・読むができるようになっていたのがよかったと思います。
何よりもAWSの理解が足りなくて、既存のコードに対しても書いてあることがどのように構築されるのかがわからなくて調べることが多々ありました。

## まとめ
Terraformの理解を深めることで、AWSの理解が深まります。
Terraform自体は基本を抑えておくだけでも大丈夫かなと。
それよりも一番は利用するプロバイダーの理解が足りないことで躓くことが多いかなと思います。
僕の場合はAWSの理解を補うために資格取得を目標にして理解を深めていこうと考えています。
GiNZAで複数文章を１文ずつに分解する

# はじめに
長文を１文ずつに分解するのに標記の方法を試したので、メモとして。

# やりたいこと
例えば、次のような文章を１文ずつに分解したい。

>明日、銀座でランチしましょう。イタリアンはどうですか？おすすめの店があるのですが。今日の夜までに返事くださいね！電話でもメールでもOKです。

これをGiNZAで簡単にできそうでしたのでcolabで試してみました。

https://megagonlabs.github.io/ginza/


https://colab.research.google.com/?hl=ja




# 内容
従来型モデルを使う方法とtransformer使って性能を向上させたモデルを使う方法の2種があるようです。後者の方が誤りが少ないようですが、その分、モデルのダウンロードやGPU環境の準備（ただしCPUでも出来る）などがあるので、実行するハードルがちょっと上がります。

## GiNZA + 従来型モデルを試す。
 

```terminal
!pip install ginza ja_ginza
```

```python
import spacy

nlp = spacy.load('ja_ginza')
doc = nlp('明日、銀座でランチしましょう。イタリアンはどうですか？おすすめの店があるのですが。今日の夜までに返事くださいね！電話でもメールでもOKです。')
for sent in doc.sents:
    print(sent)
```

結果は下記になりました。


```terminal
明日、銀座でランチしましょう。
イタリアンはどうですか？
おすすめの店があるのですが。
今日の夜までに返事くださいね！
電話でもメールでもOKです。
```

## GiNZA + Transformersモデルを試す

公式ページによるとメモリ16GB以上必要とのこと。

```terminal
!pip install -U ginza ja_ginza_electra
!pip install -U ginza https://github.com/megagonlabs/ginza/releases/download/latest/ja_ginza_electra-latest-with-model.tar.gz
# GPUを使う場合。CPUで実行したい場合は下記は実行しないこと
!pip install -U "spacy[cuda110]" 
```

```python
import spacy

nlp = spacy.load('ja_ginza')
doc = nlp('明日、銀座でランチしましょう。イタリアンはどうですか？おすすめの店があるのですが。今日の夜までに返事くださいね！電話でもメールでもOKです。')
for sent in doc.sents:
    print(sent)
```

GPU実行時の結果は下記になりました。

```terminal
明日、銀座でランチしましょう。
イタリアンはどうですか？
おすすめの店があるのですが。
今日の夜までに返事くださいね！
電話でもメールでもOKです。
```

CPU実行時の結果は下記になりました。ワーニングが出ますが同じように結果はでます。
```terminal
/usr/local/lib/python3.7/dist-packages/torch/amp/autocast_mode.py:198: UserWarning: User provided device_type of 'cuda', but CUDA is not available. Disabling
  warnings.warn('User provided device_type of \'cuda\', but CUDA is not available. Disabling')
明日、銀座でランチしましょう。
イタリアンはどうですか？
おすすめの店があるのですが。
今日の夜までに返事くださいね！
電話でもメールでもOKです。
```

# 所感など
- 「従来型」はライブラリもそこまで不要で、CPU環境でも実行でき、実行に重いデータのダウンロードが不要なため、気軽に試せる。
- 一方で「GiNZA + Transformersモデル」はモデルのサイズが圧縮ファイルで800MB近くもあり、メモリも16GBバイト以上必要など実行のハードルが少しだけある印象。長文で実施した場合、文書量が多いとき、トークンまで分解するときなどは、「GiNZA + Transformersモデル」でGPU活用が良さそうですが、近いうちに多いデータ量で試してみたい。

# 参考


https://megagonlabs.github.io/ginza/

# 実行環境

https://colab.research.google.com/?hl=ja
Stripe.js + Google Map APIで、オートコンプリート付きの住所入力フォームを埋め込む方法


本人確認やソーシャルギフトなど、決済以外の場面でユーザーに住所を入力してもらう場面は複数存在します。

Stripeが提供するJSライブラリ[Stripe.js]()を使うと、住所入力フォームを簡単に埋め込むことができます。

今回はこの住所要素の埋め込み方と、Google Map APIを利用してオートコンプリートを設定する方法を紹介します。

## オートコンプリートがデフォルトで有効になるケース

Stripe.jsの住所入力フォームは、「PaymentElementと併用している場合」など一部のケースでは自動的にオートコンプリートが有効化されます。

```jsx
        <Elements
          stripe={loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_API_KEY)}
          options={{
            clientSecret: 'pi_xxxx_secret_xxxx'
          }}
        >
          <PaymentElement />
          <AddressElement
            options={{
              mode: 'billing',
              allowedCountries: ['JP'],
            }}
          />
        </Elements>
```


![スクリーンショット 2022-11-21 13.20.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/be132584-4893-5330-9016-de74c07b995d.png)

https://stripe.com/docs/elements/address-element/collect-addresses?platform=web&client=react#autocomplete

## オートコンプリートがデフォルトで有効にならないケース

決済フォーム以外で利用する場合は、オートコンプリートがデフォルトでは動作しません。

```jsx
        <Elements
          stripe={loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_API_KEY)}
        >
          <AddressElement
            options={{
              mode: 'billing',
              allowedCountries: ['JP'],
            }}
          />
        </Elements>
```

![スクリーンショット 2022-11-21 13.19.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/fb35dd1e-9cd5-0a20-6d0a-04f05bb32eef.png)

## Google Map APIキーを設定する方法

`AddressElement`のオートコンプリートは、Google Map APIキーを設定することで、単独でも利用できます。

```jsx
        <AddressElement
          options={{
            mode: 'billing',
            allowedCountries: ['JP'],
            autocomplete: {
              mode: 'google_maps_api',
              apiKey: 'xxxxx',
            }
          }}
          onChange={e => {
            if (e.complete) {
              console.log(e.value)
            }
          }}
        />
```

フロントエンドにAPIキーを設定するため、実装をデプロイする前に、APIキーを保護しましょう。

Google Map APIの保護は、「APIキーを保護する」から「HTTPリファラー」を設定します。

![スクリーンショット 2022-11-21 13.58.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/26d2c78d-17a6-4d1a-1d34-d77cb1c71ab3.png)

APIキーを利用するサイトのドメイン・アドレスを指定することで、APIキーを安全に利用できます。

![スクリーンショット 2022-11-21 13.58.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/1c02f6c6-57df-fbd0-783c-42a2f07a1e19.png)



## 関連記事

https://stripe.com/docs/elements/address-element

https://stripe.com/docs/elements/address-element/collect-addresses

https://stripe.com/docs/js/element/address_element

## [PR] Stripe開発者向け情報をQiitaにて配信中！

- [Stripe Updates]：開発者向けStripeアップデート紹介・解説
- ユースケース別のStripe製品や実装サンプルの紹介
- Stripeと外部サービス・OSSとの連携方法やTipsの紹介
- 初心者向けのチュートリアル(予定)

など、Stripeを利用してオンラインビジネスを始める方法について週に２〜３本ペースで更新中です。

-> [Stripe Organizationsをフォローして最新情報をQiitaで受け取る](https://qiita.com/organizations/stripe)
メモ：AzureMLのベースDockerイメージ

AzureMLで使われる事前構築済みDockerイメージの情報メモです。

学習用イメージ：[Azure/AzureML-Containers: Docker containers for running training scripts on AzureML](https://github.com/Azure/AzureML-Containers)
推論用イメージ：[Prebuilt Docker images - Azure Machine Learning | Microsoft Learn](https://learn.microsoft.com/en-us/azure/machine-learning/concept-prebuilt-docker-images-inference)
CREATE TEMP TABLEを含むクエリの費用をBigQueryのJOBS_BY_***で確認するときの注意点

BigQueryでクエリの費用やスロット利用量を確認するために、 `JOBS_BY_***` を活用することが多いです。

https://cloud.google.com/bigquery/docs/information-schema-jobs

しかし、CREATE TEMP TABLEを含むクエリの費用を計算するときには注意が必要です。

例えば、以下のクエリを実行するとします。

```sql
CREATE TEMP TABLE hoge AS (......);
CREATE TEMP TABLE fuga AS (......);
SELECT ... FROM hoge JOIN ......;
```

この時、 `JOBS_BY_***` には以下の4行が記録されます。

| job_id                    | parent_job_id | statement_type         | total_bytes_billed          | query                               |
|---------------------------|---------------|------------------------|-----------------------------|-------------------------------------|
| <乱数 or ジョブの作成時に指定したID> ※① | NULL          | SCRIPT                 | <以下の3つの数値の合計>                  | SQLの全文                              |
| script_<乱数>               | ①             | CREATE_TABLE_AS_SELECT | 1つ目のCREATE TEMPでスキャンされたデータ量 | CREATE TEMP TABLE hoge AS (......)  |
| script_<乱数>               | ①             | CREATE_TABLE_AS_SELECT | 2つ目のCREATE TEMPでスキャンされたデータ量 | CREATE TEMP TABLE fuga AS (......); |
| script_<乱数>               | ①             | SELECT                 | 最終行のSELECTでスキャンされたデータ量      | SELECT ... FROM hoge JOIN ......;   |


最初のstatement_typeがSCRIPTな行はSQLの実行全体に関する情報を提供しています。
この行のtotal_bytes_billedは2つのCREATE TEMP TABLEと最後のSELECEでスキャンされたデータ量の合計になります。
その後の3行は個別のSQL文の実行に関する情報を提供しています。

このような記録の仕方をしているため、単純に `SUM(total_bytes_billed)` を行ってクエリの実行費用を出すと、二重にカウントされることになります。
そのため `WHERE statement_type <> 'SCRIPT'` のようなWHERE句を追加して二重にカウントを避ける必要があります。

なお、この挙動はtotal_bytes_billedだけではなく、total_slot_msなどの他の指標についても同様です。
contact form7でデータをDBに保管する際、シリアルナンバーを付けたいとき

## シリアルナンバーをメールに載せるプラグインはすぐ見つかる・・・
シリアルナンバーのDB保管はここの手順でクリア。
https://gluckhacker.com/contact-form-7_serial_number/

serialプラグインが既に更新停止してるので注意。
またバージョン0.7.0以前だと利用できないので、最新版を使うこと。

serialプラグインの編集時、wordpressのエディタだとどう打ってもエラー扱いされて保存できず・・・
結局FTP安定っぽい。
G's EXPANSION Laravel講座を受講してみた

# はじめに
”セカイを変えるGEEK”を育てるG's ACADEMYが提供する拡張プログラム【G's EXPANSION Laravel講座】を受講しました。
拡張プログラムはG's ACADEMYの生徒でなくても受講できます。
今回の講座ではPHPのフレームワークである「Laravel」を学んだので、その内容についてまとめます。

https://gs-exp-laravel-2022.peatix.com/view

# 講座の概要
講座は２ステップで進みます。
1. オンデマンド動画（自己学習）
2. ライブ授業（講師のガイドに従って一緒にコードを書く）

### ①オンデマンド動画での自己学習
講座に申し込むと動画教材と資料が配信されます。動画は2本でそれぞれ50分ほど。資料には実際に使うコードなどが書いてあります。
オンデマンド動画では「本の管理アプリ」の作成を通じて以下のことを学びました。
1. Laravelの環境構築　
2. CRUD処理（登録・表示・更新・削除）

特にオンデマンド動画で学んだ環境構築はライブ授業でもそのまま使いますので、何度もやっておくことをお勧めします。私はライブ授業までに環境構築を5回以上やりました。このくらいやっておくと体が覚えてくれるのでスムーズにライブ授業に入れると思います。

### ②ライブ授業
オンラインでのライブ授業が2回あります。1回あたり2.5時間ほど。
単なる座学ではなく、受講者もその場でコーディングをしてアプリの完成を目指します。
ライブ授業では「チーム管理のアプリ」の作成を通じて以下のことを学びました。
1. リレーションデータベース
2. メール送信機能
3. 画像アップロード機能
4. Gateを使ったログイン認証切り分け
5. ページ毎のCSS、jsの実装
6. CRUD処理（登録・表示・更新・削除）をより簡単に実装する方法


# 講座の内容紹介
### ①オンデマンド動画の内容
**環境構築**
今回の講座ではAWS Cloud9上にLaravelの開発環境を作って、そこにコードを書いていきます。
※AWS Cloud9とはブラウザ上でアプリ開発を行えるクラウド上の統合環境です。

https://aws.amazon.com/jp/cloud9/

動画の中で環境構築はこんな流れで進めていきます。
    1. Cloud9でのプロジェクト立ち上げ
    2. PHPのセットアップ
    3. Laravelのインストール
    4. データベースの作成
    5. Laravelプロジェクトの初期設定
    6. phpMyAdminの設定


なお、Cloud9/Laravelでの環境構築をやってみたい方はG's ACADEMY校長の山崎先生のこちらの動画がとても参考になりますのでこちらもどうぞ！

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

**ログイン認証の実装**
Webアプリに欠かせないログイン認証の機能ですが、これを自力で実装しようと思ったらとても大変です。しかしLaravelにはログイン認証を簡単に実装できる機能があります。
例えばLaravel 9.xでは次のようにターミナルに数行のコマンドをうちます。
```
$ php artisan migrate
$ composer require laravel/ui
$ php artisan ui vue --auth
$ npm install
$ npm run dev
$ npm run dev
```
これだけでこんなログイン画面が実装できます。これは便利！
![スクリーンショット 2022-11-29 16.31.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394908/58163f7f-e44f-2c82-a91f-a5843ca9cb71.png)
<font color="DarkGray">emailとパスワードを登録済みのユーザーがログインできる仕様</font>

**簡単なCRUD機能の実装**
「本の管理アプリ」の作成を通じてCRUD処理（データの作成、読み出し、更新、削除）を学びます。
実際にやることはこんな感じ。
    1. マイグレーションファイルを使ってデータベースにテーブル作成
    2. MVC（モデル、ビュー、コントローラー）の作成
    3. ルーティングの設定
    4. Bladeファイルの作成
    5. コントローラーにCRUD処理を実装


### ②ライブ講義の内容
2.5時間×2回のライブ講義（オンライン）があります。
ライブ講義ではその場でAWS Cloud9にLaravel開発環境を構築して、そこにコーディングしていきます。

1回目の講義では「チームの作成・管理アプリ」の作成を通じて、リレーションデータベースについて学びます。
ログインユーザーを登録するusersテーブルと、チームの情報を登録するteamsテーブルとの間に「中間テーブル」を持たせます。

![スクリーンショット 2022-12-07 11.28.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394908/b941d1bc-abd1-5a28-a536-54268ec75394.png)
<font color="DarkGray">ログインユーザーがオーナーになってチームを作成し、オーナー以外のユーザーは自由にチームに参加ができる、というアプリ</font>

少し高度なリレーションデータベースの実装を行いました。オンデマンド動画で学んだことの復習も含めてやっていくのでここで理解が深まります。

2回目の講義では
・メール送信機能
・画像のアップロードと表示
・ユーザー権限によるページ表示の変更
・CRUD処理実装のショートカット版
をやります。
これまでの講義でやってきたCRUD処理をより簡単に実装するショートカット方法を学べるので、開発がグッと楽になります。

# 成果物
ライブ授業は結構な速度で進んでいきます。授業当日はまずは動くアプリを作ることに集中。授業後もしばらくはアーカイブ動画を見たり資料を閲覧したりできるので何度もやって身につけていくといいと思います。
私はこの講座で学んだことをベースにしてLaravelを使って「写真の共有＆タグ付けアプリ」を作成しました。ローンチして私自身が所属する少年サッカーチームの保護者の間で使ってもらっています。
![20220901_卒制企画書.001.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394908/6798afd8-92d6-1d24-15c7-82c0c0e4039b.jpeg)

# 最後に
私自身は今回のLaravel講座で手を動かしながらアプリ実装をすることで、Laravelを使ったアプリ開発についてかなり理解が深まりました。

・特定の言語を学んでいるが違う言語に挑戦したいエンジニア
・独学しているが、実践する講座でレベルアップしたい駆け出しエンジニア

のような方々にとってもおすすめできる講座だと思います！
amazon linux certbot セットアップ & renew

## セットアップ
```sh
sudo yum install certbot-nginx
sudo certbot --nginx -d example.com
```

## crontab
```
sudo vim /etc/crontab
0  13  *  *  *  root  certbot renew --no-self-upgrade
```

## manual
```
certbot renew --no-self-upgrad
```
IIJ BootCamp Git をハンズオンしてみる(事前準備 Docker for win)

37歳ですが、IIJの新入社員研修向け資料をやってみます。

# 概要
・Docker desktop for windowsをインストール
・Nginx (Webサーバ)入りのコンテナをrun
・コンテナを削除

# 参考文献
[1] IIJ 研修 https://eng-blog.iij.ad.jp/archives/15297
[2] 事前準備 https://iij.github.io/bootcamp/init/hello-bootcamp/
[2] GitHub入門 https://iij.github.io/bootcamp/development/github/

# 事前準備
https://iij.github.io/bootcamp/init/hello-bootcamp/

## 私の環境
Linux環境
・ミニPC
・Ubuntu server 20.04
Docker Desktop環境
・メインPC + Terminal
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2311625/dee34497-6846-8c98-2809-0e2a2af725e7.png)

以前Docker環境は建ててありました。
https://qiita.com/kanegae/items/673351b1568835aaad48
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2311625/0afe01e8-8b8e-dfb4-5a57-e11ac769a548.png)

## Docker desktop for windowsのインストール
>PowerShell やコマンドプロンプトを開き、docker versionコマンドが実行できれば成功です

Power shellで　`docker version`　を打ってversiongが表示されたのでOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2311625/10ef0cc8-823b-ed7e-9528-db4456ad4c6d.png)

## hello-world コンテナを動かす

動いた。
```
PS C:\Users\skane> docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
```

## Nginx を立てて手元で HTML を書き換える

VIMがWinだと使えないので、メモ帳でhtmlファイルを書いた。
%CD%の表記だとエラーになったので、フルパスで書いたら通った。
~~~
$ vim content/index.html
vim: The term 'vim' is not recognized as a name of a cmdlet, function, script file, or executable program.
$ docker run --name test-nginx -p 8080:80 --mount type=bind,source=%CD%/content,target=/usr/share/nginx/html,ro -d nginx
docker: Error response from daemon: invalid mount config for type "bind": invalid mount path: '%CD%/content' mount path must be absolute.
~~~

修正後
~~~
$ docker run --name test-nginx -p 8080:80 --mount type=bind,source=C:\Users\skane\content,target=/usr/share/nginx/html,ro -d ngin
・・・
nable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
~~~
ブラウザでHello worldが見れた！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2311625/f5684c33-852b-8207-ec3c-31ce0650b9b1.png)

## Docker コンテナのお掃除
stopしてrm。
~~~
$ docker stop test-nginx
$ docker rm test-nginx
~~~
test-nginxがなくなった。
~~~
docker images
REPOSITORY                                               TAG       IMAGE ID       CREATED         SIZE
nginx                                                    latest    88736fe82739   13 days ago     142MB
vsc-helloworld-django-6e218a36343300c01753310ec3140281   latest    6a0fb9e7ba50   3 months ago    1.27GB
hello-world                                              latest    feb5d9fea6a5   14 months ago   13.3kB
~~~

昔作った djangoのイメージファイルが大きいので消しておこう。
CUIからうまく消せなかったので、GUIから消した。
すっきり。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2311625/11a2b8d0-2262-350d-6bbd-fd55561be23a.png)


次回は GitHub入門にチャレンジ。

https://iij.github.io/bootcamp/development/github/
cc.fovea.cordova.purchaseを使ってる人はすぐcordova-plugin-purchaseに切り替えよう

2022年11月1日から、AndroidアプリでBilling Library 3は使えなくなりました。具体的には、アプリファイルをGoogle Play Consoleにアップデートすると、Billing Libarary 4以降にアップデートしてくれとエラーがでるようになりました。

ただ、 `cc.fovea.cordova.purchase` は最新バージョンでもBilling Libarary 3を採用してるんですよね。どうしようかなと調べてみたところ、 `cc.fovea.cordova.purchase` は `cordova-plugin-purchase` にリネームされていました。

https://www.npmjs.com/package/cordova-plugin-purchase

こちらは、今年2月16日に、Billing Libarary 4にアップデートされた、v11.0.0がリリースされていますのでBilling Libararyまわりでエラーがでた人は、 `cordova-plugin-purchase@11.0.0` 以降を利用するようにしてください。

それではまた。
Linodeのインスタンスタイプを変更する

# Linodeのインスタンスタイプ

Linodeのインスタンスは、Shared CPU(共有)、Dedicated CPU(専有)、High Memory(ハイメモリー)、GPU、様々なインスタンスタイプがあります。
インスタンスを運用中に変更したい場合、Linodeではリサイズすることが可能です。
例えば、スペックが不足している際のスケールアップや、コストの削減のスケールダウンしたいなど、様々な要件に合わせてインスタンスタイプを変更することができます。

インスタンスタイプを変更する際には、選択するインスタンスタイプによって手順が異なるため、今回はその手順を紹介します。

どようなインスタンスタイプを選択したらよいのかはこちらの記事を参照ください。

https://qiita.com/isss802/items/c53315615a7e087cc41a

# Linodeのインスタンスタイプの変更について

Linodeの各インスタンスのメニューからResizeを行うことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49877/d3898be4-9d27-441f-b45c-3be9acea165d.png)

Linodeのインスタンスには各プランごとにディスクが付与されているため、インスタンスタイプを変更する際には、ディスクの増減対応を行う必要があります。

現在のインスタンスタイプからスケールアップする際には、自動的にディスクの拡張を行うことができます。
尚、自動の拡張に対応していないOSの場合には、手動で対応する必要があります。

スケールダウンする際には事前にディスクのリサイズ対応が必要となります。

またスケールダウンを行う際には、構築しているアプリケーションの動作要件を下回らないように適切なインスタンスタイプを選択してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49877/2dfae91a-d508-9743-a850-f97eb5270610.png)

## インスタンスのスケールアップ

インスタンスのメニューから「Resize」を選択し、スケールアップの対応をします。

スケールアップの際にはインスタンスはシャットダウンされて、自動的に再起動が行われます。

:::note warn
インスタンス変更中はサービスダウンが伴うため、変更する際には注意が必要になります。
:::

起動したあとには自動的に「/dev/sda」が拡張されています。（Debianの場合）

```
root:~# df -h
Filesystem      Size  Used Avail Use% Mounted on
udev            3.9G     0  3.9G   0% /dev
tmpfs           796M  460K  796M   1% /run
/dev/sda        135G  2.2G  133G   1% /
tmpfs           3.9G     0  3.9G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           796M     0  796M   0% /run/user/0
```

## インスタンスのスケールダウン

インスタンスのスケールダウンを行う際には、ディスクの縮小対応を行う必要があります。

:::note warn
スケールダウンする対象に付与されているディスク容量を下回るように、ディスクの使用率を下げます。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49877/8e6c9562-7345-d285-ab7d-e01ed351913f.png)

対象のインスタンスをシャットダウン「Power Off」にします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49877/f9bce361-b9bc-3e3c-d143-6c7f02e912fa.png)

インスタンスの設定画面から「Storage」のメニューを選択し、対象のディスクのリサイズを行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49877/ef5b288d-7535-03d5-9922-4e992de685a0.png)

今回は、160GBから80GBに変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49877/967e422a-e0a4-0662-e2a9-2beb517b717b.png)

なお変更の際に、設定したディスク容量より多くのディスクを使用している場合には変更はできません。

インスタンスのメニューから「Resize」を選択し、スケールダウンを行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49877/b8dec3fa-00ff-cfa1-da32-6d06b4940c64.png)

インスタンスを起動して、ディスク変更が正しく行われていれば変更は完了です。

```
root:~# df -h
Filesystem      Size  Used Avail Use% Mounted on
udev            2.0G     0  2.0G   0% /dev
tmpfs           394M  440K  393M   1% /run
/dev/sda         79G  2.2G   73G   3% /
tmpfs           2.0G     0  2.0G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           394M     0  394M   0% /run/user/0
```

# まとめ

Linodeのインスタンスは運用途中でのインスタンスタイプ変更に関しても柔軟に対応することが可能です。
Linodeの特徴として、インスタンスの費用の中にディスクが付与されており、価格的にメリットがありますが、インスタンスタイプ変更の際にはディスク容量を検討することが必要となります。



# 関連記事
アカマイ・テクノロジーズ合同会社の Qiita では Linode 関連など開発者向けの記事を記載しています。

https://qiita.com/organizations/Akamai
[Ionic] 数字入力のInput要素には、増減ボタンをつける方が便利になることがある話。

人数やアイテム数入力のための `input[type=number]` 要素を用意する時、ユーザは基本的に1から多くて3程度の数字を入力するというシチュエーションはよくあります。そういう場合、いちいちオンスクリーンキーボードを立ち上げるのはユーザにとって合理的な手段とは限りません。

そこで選択肢にあがるのが、増減ボタンをつけるという方法です。

![スクリーンショット 2022-11-29 午後4.48.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100460/bdb1bc46-6e6d-9ecd-fd80-4820bed0d869.png)

では実際にこのマークアップをしてみましょう。

```html
<ion-list>
  <ion-item class="add-remove" lines="none">
    <ion-label slot="start">消費本数</ion-label>
    <ion-buttons slot="start" tabindex="1">
      <ion-button slot="icon-only" (click)="remove()"
      ><ion-icon name="remove-circle-outline"></ion-icon
      ></ion-button>
    </ion-buttons>
    <ion-input
            type="number"
            class="ion-text-center"
            placeholder="0"
            [(ngModel)]="changeTo.number"
            name="changeTo.number"
            required
            tabindex="2"
    ></ion-input>
    <ion-buttons slot="end" tabindex="1">
      <ion-button slot="icon-only" (click)="add()"><ion-icon name="add-circle-outline"></ion-icon></ion-button>
    </ion-buttons>
    <ion-text slot="end" i18n>本 / 在庫数 {{ thread.number.purchase - thread.number.used }}本</ion-text>
  </ion-item>
</ion-list>
```

ポイントは、 `ion-item` 内のをタップすると `ion-input` の値を変えるとフォーカスあたるSafariの不具合を防ぐために、 `tabindex` を用意することです。

https://github.com/ionic-team/ionic-framework/issues/21982#issuecomment-734999212

また、 `[slot=start]` `[slot=end]` はmdデザインで大きな空白が用意されているので、margin値をCSSで調整します。

```css
.md {
  .add-remove {
    ion-buttons[slot=start] {
      margin-right: 8px;
    }
    ion-buttons[slot=end] {
      margin-left: 8px;
    }
    ion-text[slot=end] {
      margin-left: 8px;
    }
  }
}
```

これでユーザは小さな値の増減をオンスクリーンキーボードを出現させず、画面タップだけで実現できるようになりました。

それではまた。
avifはオンデマンドな画像変換には向かないって言う話

## 最初に理由から言うと
webpと比較すると画像変換にかなり時間がかかるためです

## まずは各ブラウザの対応状況
https://caniuse.com/avif
![スクリーンショット 2022-11-19 18.05.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322555/1138802d-8232-26cc-4f98-6ae100574fe5.png)
iOS16からsafariもavifに対応したことによって、ほとんどのブラウザでavifが使えるようになりました

## 実際の比較
比較に使った画像はこれです
![cat-7536508_1920.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322555/79d27c23-fc24-0f39-1033-f2d1cefbade5.jpeg)
1920x1280のjpegで315kbあります
オンデマンドで画像変換及びリサイズしている環境は以下です
```
AWSのCloudFront+Lambda@Edge
nodejsのsharpで変換
変換時の引数は基本デフォルトです
sharpのバージョン:0.29.3
Lambdaのメモリ:1536kb
```

### サイズによる比較
![スクリーンショット 2022-11-29 16.41.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322555/5888fdb7-2225-df6c-a7ad-28a6903c734b.png)
sharpのqualityはデフォルトなのでwebpは80、avifは50です
やはりavifはファイルサイズはかなり小さくなっています
しかし画像変換にかかる時間がかなり伸びています
画像のレスポンスで7秒かかるのはちょっと厳しいです

### クオリティによる変移
![スクリーンショット 2022-11-29 16.44.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322555/61267826-5060-eb42-0aa4-3670a155cd0b.png)
デフォルト値から10まで下げて比較しています
クオリティが高いほど差が広がることがわかります

### 【おまけ】クオリティによるファイルサイズの変移
![スクリーンショット 2022-11-29 16.45.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322555/fc583426-07aa-fb0f-2ac7-e03d042a9fba.png)
クオリティが高くなるほど差が少なくなっていくことがわかります

## 最後に
sharpのバージョンアップや、別のライブラリだとまたちょっと変わるのかもしれませんが
自分はavifの対応は一旦様子見かなと思いました
もしくはオンデマンドではなくバッチ等で変換するのであれば有りかなとは思いました
NetBSDでもmruby

ちょっと書き足したので、NetBSD Advent Calendar 2022に登録しました。

NetBSD/armでもmrubyを動かしてみました。

母艦はFreeBSD/arm64のBastilleBSDのjailです。NetBSDは9.99.107でmrubyは3.1です。 

ストレージ系のドライバがまだないので、mdを使ったインストーラのイメージに寄生します。

pkgsrcでのクロスビルドも考えたのですが、mrubyにはクロスビルドの仕組みがあるので、それを使うことにしました。

まず、NetBSDのtoolをbuild.shで作ります。このあとにcrt0.oなどを用意するためにreleaseをビルドします。

これを元にmrubyをビルドします。

```ruby:build_config/netbsd.rb
MRuby::CrossBuild.new('cross-netbsd-arm') do |conf|
  conf.toolchain :gcc

  BIN_PATH = "/usr/home/hiroki/netbsd-tools/earmv4/bin"
  SYSROOT_PATH = "/usr/home/hiroki/netbsd-src/obj/destdir.evbarm/"
  conf.cc.command = "#{BIN_PATH}/armv4--netbsdelf-eabi-gcc"
  conf.cc.flags << "--sysroot=#{SYSROOT_PATH}"
  conf.archiver.command = "#{BIN_PATH}/armv4--netbsdelf-eabi-gcc-ar"
  conf.linker.command = "#{BIN_PATH}/armv4--netbsdelf-eabi-gcc"
  conf.linker.flags << "-static --sysroot=#{SYSROOT_PATH}"

  conf.gem core: "mruby-bin-mirb" do |spec|
    spec.linker.libraries = %w(edit termcap)
  end

  conf.gembox 'default'
end
```

実行環境はダイナミックリンクが使えないので、スタティックでリンクしています。またバイナリはstripしてサイズを小さくします。バイナリサイズは1918108バイトでした。

これで出来上がったmrubyの実行ファイルをramdisk.fsに入れてINSTALLなカーネルをビルドしてu-bootでロードできるイメージを作ります。

![INSTALL_mruby.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/4c47d018-18a2-a74a-ae8b-3ee2433679b6.png)

INSTALLなカーネルは内部のramdisk.fsをmdとしてマウントしてシングルユーザでsysinstを起動するようになっています。

ramdisk.fsはreleaseのビルドでできるのですが、けっこう苦労しました。mdのデフォルトのサイズは3Mでパンパンで入らないので、大きくしました。

listにmrubyのバイナリファイルを追加して、build.shでrelaseを流したところ、3Mに収まらずnbmakefsがエラーになりました。

releaseのフルビルドはけっこう時間がかかるので、結局nbmakefsを直接たたいてramdisk.fsを作りトライ＆エラーしました。

```
% cd distrib/evbarm/instkernel/ramdisk/obj
% /usr/home/hiroki/netbsd-tools/earmv5/bin/nbmakefs -t ffs -B le -s 6144k -F work.spec   -N /usr/home/hiroki/netbsd-src/etc -o bsize=4096,fsize=512  -o optimization=space,minfree=0  -f 15 ramdisk.fs.tmp work  && mv -f ramdisk.fs.tmp ramdisk.fs;
```

実機でイメージをtftpしてbootmして実行してsysinstを抜けてshでmrubyを実行してみます。

```を
# cat /tmp/fib.rb
def fib n
  return n if n < 2
  fib(n-2) + fib(n-1)
end

puts fib(32)
# /bin/mruby /tmp/fib.rb
```

ORION(armv5 500MHz)なのですが21秒くらいでけっこう早いし、十分実用になると思います。

STR91xx(armv4 250MHz)でも試したしたところ40秒でクロック相当で妥当なところだと思います。
Ubuntu 22.04 - ネットワーク設定

ネットワークまわりの設定

## 環境
Ubuntu 22.04 LTS

## 設定
デフォルトのコンフィグファイルは無効化しておきます。Ubuntu は上から順にファイルを読み込んでいるようなので、デフォルトファイルがあるとうまく設定できません。
```
$ sudo mv /etc/netplan/00-installer-config.yaml /etc/netplan/00-installer-config.yaml.org
```
コンフィグファイルを作成/編集します
```
$ sudo vi /etc/netplan/99-config.yamal
```
`i`でインサートモードに入って、次の通りに入力します
（インターフェースやネットワークアドレスは自分の環境に置き換え）
```
network:
  version: 2
  renderer: networkd
  ethernets:
    ens160:
      dhcp4: false
      addresses:
        - 192.168.1.99/24
      routes:
        - to: default
          via: 192.168.10.254
      nameservers:
        addresses: [8.8.8.8]
```
`Esc`して`:wq`で保存します
```
$ sudo netplan apply
```
念のため、IP Address/Route を確認しておこう
```
$ ip address
$ ip route
```
Minecraftのサーバをウェブコントロールパネルで操作できるようにしよう

# まえがき
気づけば4年連続ぐらいで書いてます。
今回は Minecraftのサーバをウェブコントロールパネルで操作できるようにしようかと思います。

# PufferPanelをインストール
PufferPanelはオープンソースのサーバ管理ツールです。

インストールします。
```
# curl -s https://packagecloud.io/install/repositories/pufferpanel/pufferpanel/script.rpm.sh | sudo bash
# yum install pufferpanel
# systemctl enable pufferpanel
```
インストールができたら、ポートを開けます。
デフォルトは8080なので、
```
# firewall-cmd --add-port=8080/tcp --permanent
# firewall-cmd --reload
```
ユーザーを追加します。
```
# pufferpanel user add
```
管理人を作成する場合は ? Admin (y/N)のときに「y」を入力します。

http://ip:8080 にアクセスして先程作ったアカウントでログインします。

# サーバを起動する
前に、左側のテンプレート一覧からテンプレートをインポートします。
minecraft-vanillaとminecraft-spigotを選択してインポートします。
「minecraft-」まで入れれば色々出てくるので、そこから選べます。

テンプレートを追加したら、サーバ一覧からサーバを追加します。
今回はVanilla - Minecraftを選択。
サーバ名を適当に入れます。
ユーザー名はそのままでいいと思います。
「EULA Agreement」を有効にして必要なら設定を変更します。
複数サーバを管理する場合は、ポートを変えておくといいと思います。

作成が完了するとコンソールの画面が出てると思うので、赤のインストールボタンをクリックします。
`Server installed`と出れば、緑の起動ボタンをクリックします。

`Done (69.432s)! For help, type "help"`が出ればサーバに接続できます。

Spigotの場合ビルドが始まるので、しばらく時間がかかりますね。

ip:設定したポート(デフォルトは25565)にマイクラからアクセスします。
サーバにアクセスできて遊べれば問題なしです。

# 終わりに
もともとはTwitterがやばいってことでMastodonを構築する予定でしたが、全てが面倒になってしまった結果、こちらになりました。
確かConoHaのサーバ作成時に選択できるマイクラのやつは、バニラ環境しか対応していなかった記憶があるので、今回のやつを使えば、SpigotとかForgeとかもできるみたいです。
誰かの参考になれば。
~~こいつ毎年誰に向けてかわからない記事書くよな~~

# 参考&スペシャルサンクス
+ [PufferPanel - Open Source Game Server Managemen](https://docs.pufferpanel.com/en/2.x/index.html)
他にもデータベースの設定とか書いてあります。
+ [CentOS 7 firewalld よく使うコマンド](https://qiita.com/kenjjiijjii/items/1057af2dddc34022b09e)
+ 見てくれた人
+ #ｺﾉﾊﾁｬﾝｶﾜｲｲﾔｯﾀｰ!
Nuxt.js(SSR)アプリをrender.comにデプロイする方法 (Freeプラン→Starterプラン)

Nuxtアプリをrender.comにデプロイすることは非常に簡単です。

しかし、それは無料プランだけ。

無料プランから有料プランに移行する際にコマンドを変更しなければいけないことに気づかず、ちょっと手間をとってしまったので、解決策をシェアしておきます。

## 原因
以下のstartコマンドではダメでした。(無料プランならこれでOK)
```
npm run start
```

## 解決策
startコマンドを以下に変更する
```
npm run start -- --hostname 0.0.0.0
```

## 補足
buildコマンドはこちら
```
npm install && npm run build
```
CronJobの動作検証にcreate jobコマンド

# 概要
CronJobの動作を、設定した時刻とは別の任意のタイミングで確認する方法

CronJobをデプロイして、とりあえず動作確認したいときや、jobを再実行したいときなど、マニフェストに定義した時刻ではない任意のタイミングで実行したいことがあるが、そんなとき`kubectl create job --from`が便利

# コマンド
```shell
kubectl create job ad-hoc-job --from=cronjob/base-cronjob
```

# 解説
`create job`実行時に`--from`フラグでcronjobを指定すればjobとして起動できる
Leetcode 2225. Find Players With Zero or One Losses

# 2225. Find Players With Zero or One Losses

https://leetcode.com/problems/find-players-with-zero-or-one-losses/

## アプローチ
### Hashmap

```java
class Solution {
    public List<List<Integer>> findWinners(int[][] matches) {
        
        HashMap<Integer, Integer> t1 = new HashMap<>();
        HashMap<Integer, Integer> t2 = new HashMap<>();

        for (int i = 0; i < matches.length; i++) {
            t1.put(matches[i][0], t1.getOrDefault(matches[i][0], 0) + 1);
        }

        for (int i = 0; i < matches.length; i++) {
            t2.put(matches[i][1], t2.getOrDefault(matches[i][1], 0) + 1);
        }

        List<Integer> r1 = t1.entrySet().stream().filter(obj -> t2.containsKey(obj.getKey()) == false).map(Map.Entry::getKey).collect(Collectors.toList());
        List<Integer> r2 = t2.entrySet().stream().filter(obj -> obj.getValue() == 1).map(Map.Entry::getKey).collect(Collectors.toList());
        List<List<Integer>> result = new ArrayList<>();
        Collections.sort(r1);
        Collections.sort(r2);

        result.add(r1);
        result.add(r2);

        return result;
    }
}
```
MFC から SVG クラスのクリップパス呼び出しコードサンプル

## MFC から SVG クラスのクリップパス呼び出し
クリッピングを複数行い、それに重なる形で四角形を描画するサンプルコードです。
Gdiplus::GraphicsPath オブジェクトをリセットしていますが、クリップしたい部分を一度に入れてしまってもかまいません。
SVG 出力のサンプルとして複数のパスを使うときのパターンを示しておきたいため故意に分けてクリップを設定しています。

MFC(GDI+)  で複数のクリップを設定する際には Gdiplus::Graphics::SetClip 関数の第二引数でクリップのマージ方法を指定することができます。本サンプルコードでは SVG への出力に合わせて "Gdiplus::CombineModeUnion" を設定しています。

MFC(GDI+) の場合以下のようになります。
```cpp
    Gdiplus::Point poly[4];
    int nPoints = 4;
    poly[0] = Gdiplus::PointF(100,100);
    poly[1] = Gdiplus::PointF(100,200);
    poly[2] = Gdiplus::PointF(200,200);
    poly[3] = Gdiplus::PointF(200,100);
    Gdiplus::GraphicsPath path;
    path.AddPolygon(poly, 4);
    pGraphics->SetClip(path);

    poly[0] = Gdiplus::PointF(200,200);
    poly[1] = Gdiplus::PointF(200,300);
    poly[2] = Gdiplus::PointF(300,300);
    poly[3] = Gdiplus::PointF(300,200);
    path.Reset();
    path.AddPolygon(poly, 4);
    pGraphics->SetClip(path,Gdiplus::CombineModeUnion);
    Solic
	
    Gdiplus::SolidBrush	brush(Color(255, 0, 0, 255));
    pGraphics->FillRectangle(brush, brushGdiplus::Rect(150,150,100,100));

    pGraphics->ResetClip()
```

SvgImage に書き出すと以下のようになります。

```cpp
    CPoint pn[4];
    pn[0] = CPoint(100, 100);
    pn[1] = CPoint(100, 200);
    pn[2] = CPoint(200, 200);
    pn[3] = CPoint(200, 100);
    CString csClipName = pImage->AddClipPath(pn, 4);

    pn[0] = CPoint(200, 200);
    pn[1] = CPoint(200, 300);
    pn[2] = CPoint(300, 300);
    pn[3] = CPoint(300, 200);
    pImage->AddClipPath(pn, 4, csClipName);

    pImage->AddRect(150, 150, 100, 100, 0, 0);
    pImage->AddAttrFill(RGB(0, 0, 255), FALSE);
    pImage->AddAttrClip(csClipName);
```
社内で自動化コンテストを企画した話 




◆◆◆◆◆◆
### 目次

- はじめに 
- 自動化コンテストって何？ 
- 社内参加者の募集
- コンテスト作品  
- まとめ 


◆◆◆◆◆◆





## ◆はじめに

皆様はじめまして。AIQVE ONE Advent Calender9日目を担当する@mi_373です。
私は社内でテスト自動化の推進業務を担当しています。 
筆者が所属するAIQVE ONE株式会社 ではゲームなどのソフトウェアテストをもとにしたテスト自動化サービスを提供しています。  
テスト自動化とは、手動で実行していたテストを機械に自動的にさせることを指しています。弊社では独自で開発したテスト自動化ツールを利用してアプリゲームの自動操作を可能にしており、効率的なテストを実現しています。  
私のお仕事は、自動化とはどんなものなのかを社内へ周知し、活用してもらうことが主な仕事です。

私の記事では、今年テスト自動化の推進活動の一環で社内で行ったイベント「自動化コンテスト」について活動した内容を記事としてお伝えしようと思います。 
今回行ったコンテストは市場にあるアプリを使用した自動化が主であるため、タイトル名をはっきり記載できず詳細がわかりずらい箇所があると思います。
こちらは予めご了承いただけますと幸いです。
 


## ◆自動化コンテストって？ 

今回企画した自動化コンテストは、弊社で独自開発した[テスト自動化ツール「Garbo」](https://www.aiqveone.co.jp/news/2022/491/)を使用して、”面白い自動化” をコンセプトに自由な発想・独自の目線で面白いと思う自動化スクリプトを組んで発表するというコンテストです。
なので普段のテスト自動化とは少し考え方が変わると思いますが、目的としてあくまで楽しくいろいろな発想を持って自動化を行ってもらうために考えたテーマでした。
社内企画ということもあり、自動化させる題材などはあえて指定せずに募集を行いました。 

日々テスト自動化の推進業務を進めていくにあたり、自動化ツールはあるものの普段業務内で活用できない案件の場合は直接ツールを触れる機会がない社内メンバーも一定数いると感じています。そういったメンバーに自動化へ対する知識の補填や学習してアウトプットする機会にしてもらいたいと思い、社内イベントとして企画しました。  
どうしても日々の業務で関りがないと部署間で隔たりができてしまいがちですが、 わからないことは他部署同士で相談ができたりとメンバー間での交流の場としてもとても良い機会だと考えました。 


 

## ◆社内参加者の募集

募集当初はこういったイベントの企画は初めての試みでもあり、もちろん自由参加としていたので参加者が集まるか不安でした。
しかし、思っていたよりも多くの人がこの企画に応募してくれました。 
応募の動機として、「この機会に自動化をしてみたい」「興味はあったけど実務でする機会がない」「どんな自動化ができるのかツールを触ってみたい」…などなど。 
応募する理由は様々ですが、いずれにしても”自動化”に興味や関心を持っているメンバーが多いことに、テスト自動化・QAツールの活用を推進する身としては安堵したことを覚えています。 


## ◆コンテスト作品
参加者には制作する期間は2ヶ月ほど設けました。
そうして制作されたスクリプトと資料から、コンテストのテーマに沿った内容であるかやクオリティなどを評価します。 
イベントでは事前に各チームの「”面白い”自動化」のテーマで作成したスクリプトとプレゼン資料が発表され、当日にコンテスト結果の発表を行いました。
各チームが自動化した市場アプリの具体的なタイトルの詳細は控えさせていただきますが、
たとえば麻雀ゲームのアプリ内で対戦相手一人を”機械”で自動操作させて、他三人（人間）と麻雀させるという自動化をしたものもありました。AIのように動く自動化スクリプトを組み、実際にプレイできるようにスクリプトを工夫して試みていることにも好感が持てる作品です。 

他にも、
・絵を描くアプリで「自動で特定の絵を描かせる」
・ひたすら連打させて進むアプリで、「人間ではできない速さで連打させる」
・野球をするゲームで「画像をキャプチャしてボールをタイミングよく打たせる」
・キャラクターがランダムで出てくるアプリ（画面）で「特定のキャラクターをキャプチャする」
などなど・・

通常自動化では難しいとされるタイミング要素を織り交ぜたものであったりと、さまざまな角度で考えられた面白い自動化の作品が多く発表されました。 どの作品もプレゼン資料の中で実際に動いている動画を確認することができ、どうやったら思うような動きになるのかスクリプトが試行錯誤されているのがわかってよく考えて作られていました！ 



## ◆まとめ 

今ある自動化ツールでどんな動作をさせることができるか、業務の観点とはまた別の視点でスクリプトを組んだり操作してみたことで、参加者本人たちによい経験になったと思います。また、日ごろからスクリプトを組むメンバーからも面白い視点であったと知見が増え、お互いに今後の業務のヒントができて良い相乗効果が生まれたのではないかと思いました。 
なによりこのイベントを企画したことで社内全体が自動化についてより興味を持ってもらう機会を作れたことに、「企画してよかった」と思いました。 
今後もこういったチャレンジができるイベントや勉強会の企画を通して、テスト自動化の推進活動に務めていきたいと思います！

イベント記録のような記事になってしまいましたが、ここまで読んでいただきありがとうございました。
キーワード駆動テスト、keyDriverを使ってみた

# 概要
自動テストツールに喰わせるテストケースには、Cucumberで使われるGherkinで記述したものや、Gaugeで使われるMarkDownで記述したものなどありますが、
今回紹介するのは、テストで実行するアクションをテストケースに記述して利用するキーワード駆動のテストツールになります。
[キーワード駆動っぽいテストができるツールを開発した話](https://zenn.dev/eyasuyuki/articles/a20301d34adce0)で見かけたツールをホテル予約サイトで試してみました。
宿泊の条件（人数や朝食の有無、オプションプランなど）で提示される合計金額が正しいかの検証です。
# 準備
JDK11での動作を確認しています。
ビルドされたjarファイルを[ここから](https://github.com/eyasuyuki/keydriver/releases/tag/v0.3.0)入手します。ソースコードも公開されていますので、頑張ってビルドもできるかもしれません。
また、利用中のChromeに対応したWebDriverへのPathを通しておきます。
jarファイルとExcelに記述したテストケースとを、同じフォルダに置き、WindowsのPowerShellから、
```
java -jar keydriver-0.3.0.jar ホテル予約サイト.xlsx 
```
ビルドされたjarファイルが、keydriver0.3.0.jar の場合
テストを始める前に、ホテル予約サイト.xlsx を作成します。
# テストケースの作成
現在利用可能なキーワードは、[こちら](https://github.com/eyasuyuki/keydriver/blob/main/doc/Keyword.md)に詳細があります。
今回テスト対象にした[予約サイト](http://example.selenium.jp/reserveApp_Renewal/)は、Selenium練習用のサイトです。
1. 予約フォームに、宿泊初日 / 連泊日数 / 宿泊人数 / オプションプラン / 代表者指名を入力
2. 「次へ」ボタンを押す
3. 合計金額の検証をする
といったテスト内容としました。
![keyword001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/939617/468121f4-543f-1f69-0ea6-2bff97a53001.png)
宿泊初日の入力を、最後に入力しているのは、カレンダーコントロールだったので、画面上の他の要素を隠してしまい、場合によっては、入力などの操作ができなくなってしまったことの回避策です。
この程度のテストケース修正ならば、Gherkinで記述した場合も、さほど手間ではないですが、テスト実施したいことや、テストに至るまでの操作等をある程度まとめてキーワードにしておける点、キーワード駆動テストの恩恵を受けやすい気がします。テストコードの開発は発生しますが。
今回テストに使ったキーワードは、以下のものだけです。

|キーワード|利用箇所|
|:--|:--|
|open|予約サイトを開く|
|select|セレクトメニューから、連泊数や宿泊人数を入力|
|input|インプットボックスに文字入力|
|clear|入力前に、初期値をクリアする場合|
|click|クリック操作|
|assert|画面上の文字列を検証|

テスト対象やテスト内容に因っては、利用するキーワードは他にも使いたいものがあるかもしれません。筆者が会社員時代にネットワークカメラのWeb画面を検証していた時にも、同じようなキーワード駆動のテストを自作していましたが、対象となるハードウェア固有の機能に関係したキーワードが存在していました。

# 総括
紹介したツールは、今後の追加開発も予定されているようでした。
自動テストが普及するにつれて、自動テスト環境で使うデータやテストシナリオが、常にテストで有効なものに維持する労力は増えると考えます。
キーワードとして、テストコードからビジネルロジックを分離することで、そういった労力を軽減させることも見込める点、キーワード駆動の自動テスト環境が、効果的な手段の1つになるように感じます。
ECS Execで実行中のコンテナに乗り込む

※こちらはAWS CLIが導入済みの場合に読むドキュメントです。

**AWS CLI 用の Session Manager プラグインをインストールする**

[(オプション) AWS CLI 用の Session Manager プラグインをインストールする](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html)

**インストールされたか確認するコマンド**

```bash
$ session-manager-plugin
```

### サーバーに入るときのコマンド

```bash
$ aws ecs execute-command \
 --cluster クラスター名 \
 --task タスク名 \
 --container コンテナ名 \
 --interactive \
 --command "bash"
```

 

オプションについて

--cluster クラスター名を指定する

 --task タスク名を指定(サービスの一覧からタスクタブでタスク名を確認)←乱数みたなやつです！

--container コンテナ名を指定する

— command mac環境は”bash”を指定

**コンテナ名の確認方法**
タスク定義画面より「コンテナの定義」で確認できる


### エラー時

リージョンが設定されていないときのエラー

```bash
You must specify a region. You can also configure your region by running "aws configure".
```

AWS CLIのユーザー設定確認コマンド

```bash
# 一括での確認
$ aws configure list
# 単体での確認
$ aws configure get region
```

### 環境設定

環境設定コマンド（アクセスキー, シークレットキー, リージョンの設定等）

```
$ aws configure
```

環境設定コマンド（一時的）

```bash
# リージョン東京を指定
$ export AWS_DEFAULT_REGION=ap-northeast-1
```

### 参考記事
https://dev.classmethod.jp/articles/ecs-exec/#toc-11

https://qiita.com/okubot55/items/b1fb07b2de08c354275b
laravel Eloquentモデルを用いて最も大きいIDのレコードを取得する

# 概要

- 最も大きいIDのレコードを取得する方法をメモ的にまとめる。

# 方法

- orderByでidの降順にして最初のものを取得する。

    ```php
    $user = new User();
    $user->orderBy('id', 'desc')->first();
    ```

- `latest()`か`ordest()`メソッド利用する。（ただこれは「最も新しいID」のレコードを取得するというよりは、特に設定しなかった場合created_atの値でソートしている。逆に「レコード作成日時が最も新しいレコード」を取得したい場合はこちらを使ったほうが意味的に合っている。）

    ```php
    $user = new User();
    $user->latest()->first();
    ```

# 参考文献

https://readouble.com/laravel/6.x/ja/queries.html#ordering-grouping-limit-and-offset
【Python】ひっそりとPython 3.11で追加された`enum.StrEnum`について解説【小ネタ】

Pythonの`enum`モジュールにはこれまでにも`int`と`Enum`のミックスインで、`.value`を使わなくてもオブジェクト自体が`int`(のサブクラス)として扱える`IntEnum`がありました。

Python3.11からそれらに加えて、`str`と`Enum`のミックスインである`StrEnum`が実装されました。

https://docs.python.org/ja/3/library/enum.html#enum.StrEnum

- 3.10のドキュメントではカスタムミックスインクラスの実装例として`StrEnum`が記載されていましたが、ビルトインになったことで記載がなくなったようです。
  - https://docs.python.org/ja/3.10/library/enum.html#others

`IntEnum`と同じく、`.value`を使わなくてもオブジェクトそれ自体が`str`のサブクラスなので`str`との比較が可能です。

```py
Python 3.11.0 (main, Oct 24 2022, 18:26:48) [MSC v.1933 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from enum import auto, StrEnum
>>> class Hoge(StrEnum):
...     FOO = "FOO"
...     BAR = "BAR"
... 
>>> Hoge.FOO
<Hoge.FOO: 'FOO'>
>>> Hoge.BAR
<Hoge.BAR: 'BAR'>
>>> Hoge.FOO == "FOO" 
True
```

また、識別子を自動的につけてくれる`auto`関数もサポートされています。
値はアトリビュート名を小文字にしたものになります。

```py
>>> class Fuga(StrEnum): 
...     FOO = auto()
...     BAR = auto()
... 
>>> Fuga.FOO
<Fuga.FOO: 'foo'>
>>> Fuga.BAR             
<Fuga.BAR: 'bar'>
```

小文字にしてしまうのは「余計なお世話」感もあります。

しかし識別子を管理するものとして使うのが`enum`の役割で、値に意味を持たせない使い方=ユニークでありさえすればなんでも構わないということなのでしょう。
  - `Enum`のサブクラスなのに`auto`を使えなくしてしまうとリスコフの置換原則に違反するため、仕様を決めないといけないということもありそうです。
  - その値自体が文字列として意味があるのであれば[`typing.Literal`](https://docs.python.org/ja/3/library/typing.html#typing.Literal)を使う方がいいということなのでしょう。

ご興味のある方は使ってみては?
supabase-js ネストしたテーブルでソート

# はじめに

Baas(Backend As A Service)で何かサービスを構築してみたいと思い、
firebaseを触ってみようと思ったところ、Firebase の代替と謳われているsupabaseを発見。

簡単なTodoアプリを公式を参考に構築していた際、
条件によってネストしたテーブルでソートを実装した時のメモ。


簡単なTodoアプリの構築に関してはこちらで解説しております。

https://qiita.com/doyaseizin/items/8820a095a433d09f300d

https://qiita.com/doyaseizin/items/d6e0237b700448cc1826

https://qiita.com/doyaseizin/items/2afe8df35e0a7adc7e00

https://qiita.com/doyaseizin/items/fad493559bd5fad22f02


# 使ったもの

* Vite + Svelte + Typescript
    * @supabase/supabase-js
    * tailwind css

* supabase
    * auth
    * db
    * realtime

## 前提

次のような1:多のテーブルがあったとします。

#### authorテーブル
|項目|型|
|----|----|
|id|uuid|
|name|text|

#### bookテーブル
|項目|型|
|----|----|
|id|uuid|
|author_id|uuid|
|name|text|
|publish_at|date|

`book`の`publish_at`順でソートしたいときの処理を考える。

## 実装

```javascript
  const { data, error } = await supabase
    .from('author')
    .select('*, books(*)')
    .order('publish_at', { foreignTable: 'books', ascending: true })
```

`ascending`で昇順降順を切り替えられる。
2022年10月から課金されるようになったCloud Storageの料金について

# 初めに

弊社ではFirebaseに関わるGCP関連の状況や使い方について定期的に調査するチームFirestarterがあるんですが、そこで今までにない課金があることに気付いたので共有します。

結論としては、2022年10月からFirestoreのバックアップをStorageに保存するときに保存のデータ量での従量課金が有償化されたようです！
Firebaseの料金が急に上がったなぁという人はここに引っかかっていると思われます。

![スクリーンショット 2022-11-29 15.19.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/341912/e816ca09-4c69-3ee5-b74f-aa5978d83c71.png)

GCPコンソールの"お支払い"からレポートを選択し、プロジェクトとSKUで検索すると出てきます。
以下の公式ページの内容がこれに当たりそうです。

https://cloud.google.com/storage/pricing-announce?hl=ja#replication



# どうやって把握したか？

まず、あるプロジェクトで急に料金が上がっていたのがきっかけです。
その後、以下のことを調査して何が原因か探っていきました。

- 特殊なStorageの使い方をしているか？
    - 特にそんなことはありませんでした。マルチリージョンのBucketを作ってるわけでもなくどこかに転送をしているわけでもないプロジェクトでした。
- バックアップをとっているか？
    - ほとんどのプロジェクトでバックアップは取っているのでこれだけではわかりませんでした。
- 使っているStorage容量と料金がリンクしているか？
    - gsutilコマンドを使えば容量はわかるんですがGCPコンソール上では把握できないのでここは実際にはしてないです。
- Firestoreのインポート/エクスポートを確認
    - GCPコンソールからFirestoreのインポート/エクスポートのページにいくと今まで行ったエクスポートの詳細が確認できます。ここの容量と料金の対象となっている容量が一致していたのでビンゴ！

# 終わりに

料金改定されてもなお、まだまだお得感を感じるFirebaseですが、こういった料金改定がたまに発生するので、いろいろ把握しておくのが非常に重要だと思います。

Firestoreのバックアップはよく利用されるパターンなので、影響受けている人は多いと思いますが、他にも料金に変更があるので注意が必要かもしれません！

ちなみに、2023年4月1日にも料金改定が予定されているので見ておいた方がよさそうです！

先程貼った以下のリンクには2022年10月1日と2023年4月1日の変更が合わせて説明されています。

https://cloud.google.com/storage/pricing-announce?hl=ja



今回の件を発見したFireStarterはFirebaseについていろいろ調べているチームなんですがFirebaseに関わる本も出しているので、興味ある人は是非見てみてください！

https://www.amazon.co.jp/gp/product/B0BMQ1BYLS/
for ... in の使い方

自分の備忘録です。

# JavaScript　for...inの使い方
繰り返し処理の一つ
配列に対して使用する。
配列の要素を一つずつ取り出し、要素を構成するkeyを変数に持って処理をする

# 例

コード
``` javascript
let array = {key1: value1,key2:value2};
for(let str in array){
 console.log(str);
 console.log(array[str]);
}
```

出力
```output
key1
value1
key2
value2
```

# 私の場合の利用場面
kintoneのカスタマイズに利用
kintoneではフィールドコードをハッシュの形で利用する為、
for inの利用でフィールドコードを取得できることを利用する場面がある。
contact form 7でフォームにキャッシュが残るとき

## フォーム修正中に起きている場合・・・
入力値は期限をセッションとした上でcookieに保存されています。
つまりブラウザを開きなおすか、ある程度の時間（30分程度）が経てばクリアされます。

ので、オートコンプリート等ではないので誤った対策をしないよう・・・。

フォーム周りの改修中は連続でテストするので、何で自動入力されるんだって思いがちですよね。
あとはこれによって削除したはずのDB列が復元されたり。
【C#】メソッド名と変数は同じだと思っていたのでおさらい

# 初めに

メソッド名も変数も自分で名前を決めれるので、同じだと思っていました。
よく考えれば全くの別物。
コードを書いている時に「メソッド(ここのカッコの中は何が入るんだっけ?)」と思い(この時はメソッド を変数と思っていた)、「変数カッコの中、変数　カッコ　何入る」とかたくさん調べても全く出てこない。
以前に変数についてまとめた記事を見返したら、変数は初めに宣言する必要があるとまとめてあった。
自分が疑問に思ったメソッドのコードを見返しても定義してない訳ですよ。
しかも変数は変数名の後ろに()つけないよね。
おかしいな〜と思ったら、変数ではなくメソッドだったらしい。

めっちゃ基礎を間違えていて少しヒヤッとした。


# メソッド名と変数の違い

__メソッド名__
メソッド名(引数)、引数が無い場合は()をつけて空で書く

__変数__
変数の宣言　　　<型名> <変数名>;
初期化の場合　　<型名> <変数名> = <初期値>;
変数を使用する際には必ず、【変数の宣言】または【初期化】を行う。


# メソッド、変数とは
__メソッド__
一連のステートメントが含まれているコードブロックのこと。何回も使い回し可能。

__変数__
様々な値が入る箱に名前をつけた物のこと。



# おさらい
ざっくり解釈すると、メソッドは関数名のことで変数は値の名前である。
関数名(メソッド名)には、引数が無い時は空の()をつけて、引数がある時は、メソッド名（引数）とする。
変数は、初めに初期化か変数宣言をして使う。