OmniAICreator/Qiita-1.07M huggingface dataset:
terraformでACMの証明書のうち特定のレコードのCNAMEレコードを作成する

terraformでACM証明書とCNAMEレコードを作成する時にいろいろと詰まったのでメモします。

## やろうとしていること

 - ACMで証明書を発行する
 - 検証方法はDNS
 - Route53のCNAMEレコードも作成します
    - ACMで発行する証明書のうち指定したレコードのみを作成したい

大きく2点ほど詰まったので、それぞれ説明します。

## aws_acm_certificateのdomain_validation_optionsの値が取得できない

以下のように指定していると、エラーが表示されて困っていました。

```terraform
name = aws_acm_certificate.cert.domain_validation_options[0].resource_record_name
```

```
Error: Invalid index
This value does not have any indices.
```

terraform 3.0.0 以降から`domain_validation_options`の戻り値がSetに変わったようです。

参考：

https://github.com/hashicorp/terraform-provider-aws/issues/10098

## domain_validation_optionsの特定の要素を抽出したい

特定の要素を抽出しない場合は以下のドキュメントを参考にすればできると思います。

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate_validation

特定の要素を抽出したい場合は以下を参考にしてください。

```terraform
locals{
  dvoList = toList(module.hogehoge.domain_validation_options)
  filter = [for i,v in local.dvoList : i if v.domain_name == "filter"]
}

resource "aws_route53_record" "ACM" {
  zone_id = "hogehoge"
  ttl = 60
  name = local.filter[0].resource_record_name
  type = local.filter[0].resource_record_type
  records = [local.filter[0].resource_record_value]
  allow_overwrite = true
}

resource "aws_acm_certificate_validation" "acm_validation" {
  certificate_arn         = module.acm.cert.arn
  validation_record_fqdns = [aws_route53_record.ACM.fqdn]
}
```

 - domain_validation_optionsがsetになったので、`tolist()`を使ってリストにした
 - for文を使って、レコードをフィルタ
    - 参考：https://www.terraform.io/docs/language/expressions/for.html#filtering-elements
 - `aws_route53_record.records`はset型なので、`[]`で囲む必要あり。
 - 同じく、`validation_record_fqdns`もset型なので、`[]`で囲む必要あり。

ちょっとterraform特有の書き方で苦戦しましたが、
同じく困ってる人いたら参考にしてください！
一日の中央値を求めるプログラム

#使い方
`$ gfortran -o medi1day sac_median_1day.f95`
`$ ./medi1day ファイル名`

```sac_median_1day.f95
program main
 implicit none
 integer i, a(40), max, npts, hour
 real b(70),c(2), dt, med
 real, allocatable :: x(:), y(:)
 character :: file1*80, arg*10, khd(48)*4
 
  if(iargc()>0) then
    call getarg (1, file1) !コマンドラインで引数
 endif
 
 max=10000000
 allocate (x(max),y(max))
 call arsac(file1,b,a,khd,x,max)
  npts = a(10)
  dt = b(1)
  call median(x, med, 8640000)
  med = med*1e-9 !nm/sからm/sへ変換
 write(*,*)med
end program main
!########################################################
subroutine arsac(fn,fhd,nhd,khd,y,maxy)
  real fhd(70),y(maxy)
  integer nhd(40),i,i1,i2,i3,npts
  character khd(48)*4,fn*80
  
  open(1,file=fn,access='direct',recl=632,status='old')
  read(1,rec=1)(fhd(i1),i1=1,70),(nhd(i2),i2=1,40),(khd(i3),i3=1,48)
  npts=nhd(10)
  close(1)
  open(1,file=fn,access='direct',recl=4,status='old')
  do i=1,npts
!     read(1,rec=i+158,end=100)y(i)     Mar.1 H.Aoyama
     read(1,rec=i+158)y(i)
  enddo
! 100 continue
  close(1)
  return
end subroutine arsac
!#####################################################
subroutine median(a, med, n)
  implicit none
  integer,intent(in):: n
  real,intent(inout):: a(n)
  real,intent(inout):: med
  integer i, m
  real am

!バブルソート（遅い）
!  do i = 1, n-1 !sort a
!     am = minval(a(i+1:n))
!     m  = minloc(a(i+1:n), 1) + i
!     if (a(i) > am) then
!        a(m) = a(i)
!        a(i) = am
!     endif
!  enddo

  call quicksort(a,1,8640001)
  
  if(mod(n, 2) /= 0) then !median of a(:)
     med = a((n-1)/2+1)
  else
     med = 0.5*(a(n/2)+a(n/2+1))
  endif
end subroutine median

!##############################################
recursive subroutine quicksort(a, first, last)
  implicit none
  real  a(*)
  integer first, last
  integer i, j
  real  x, t
 
  x = a( (first+last) / 2 )
  i = first
  j = last
  do
     do while (a(i) < x)
        i=i+1
     end do
     do while (x < a(j))
        j=j-1
     end do
     if (i >= j) exit
     t = a(i);  a(i) = a(j);  a(j) = t
     i=i+1
     j=j-1
  end do
  if (first < i - 1) call quicksort(a, first, i - 1)
  if (j + 1 < last)  call quicksort(a, j + 1, last)
end subroutine quicksort
```
CUIでのテキストマイニングって簡単になったなぁと感嘆

# プロローグ

[1年間に発売されたライトノベルのタイトルを、AIテキストマイニングで分析してみた｜岡田勘一［編集者・ライター］｜note](https://note.com/kanichi0203/n/n3149ba40c273)

が気になった。

この方は
[AIテキストマイニング by ユーザーローカル](https://textmining.userlocal.jp/)
というwebサービスを利用しているが、
やっぱCUIでやりたいじゃないっすか。ね。

# 参考にしたもの

[【コード公開】【Python】テキストマイニングしてみた〜ジョブズのスピーチでWordCloudを作ろう \| Analytics Board \| python特化のプログラミングサイト](https://su-gi-rx.com/archives/3031)

# source

[https://github.com/tknr/text_mining](https://github.com/tknr/text_mining)

本体はこんなに短い。

```py
#!/usr/bin/python
# coding: utf-8
from wordcloud import WordCloud

text_file = open("src.txt")
bindata = text_file.read()
txt = bindata

wordcloud = WordCloud(background_color="white",
    font_path="HackGenNerd_v2.5.1/HackGenNerd-Regular.ttf",
    width=800,height=600).generate(txt)


wordcloud.to_file("./result_wordcloud.png")
```


今回は
[小説・文学通販ランキング \- honto](https://honto.jp/ranking/gr/bestseller_1101_1202_011_029001000000.html?dspNo=100)
2021/09/05 時点 集計期間:1ヶ月 100位まで の書籍タイトルをターゲットにやってみました

# 結果
```
$ bash setup.sh
$ time ./text_mining 

real    0m4.377s
user    0m4.228s
sys     0m0.492s

```
![result_wordcloud.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369323/4cb5f1f6-ad3d-f8ca-6d3b-dee5eaca1bce.png)

散っとるのお。


# エピローグ
えー... 便利な世の中になったものです。
幡随院先生、逮捕状です

# 巡査 なんたら

A:○○くぅ～ん
B:なんスかうっとーしーなーもぉーっ
A:あいつさぁ、もっと簡単に出来るの知らなかったんだよ
B:何がぁ?
A:あんなのさぁ、コード書かなくたってさぁ、

[wordcloud · PyPI](https://pypi.org/project/wordcloud/)

```
wordcloud_cli --text mytext.txt --imagefile wordcloud.png
```

A:ほらな?出来るでしょ?
B:...出力見てみてよ、ほらぁ
A:何が?
B:全部□じゃん。日本語フォント食わせてないでしょ?
A:...ぐうぅぅぅっ
(A、Bの方にすがりながら退場)
小松菜奈とあいみょんを見分けたい

## やること
小松菜奈とあいみょんは、どこか似ています。

![ytrdscvfbgnhjmkl.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1940763/5e42dcb1-15a5-0c63-c94f-32c7fd55a4f6.jpeg)

異論のある方も多いでしょうが、「顔が似ている美人＆イケメン芸能人ランキング」でも堂々の三位に入っているのですから、世間的には「似ている」ことになっているのです。
そこで、[画像分類タスクに対する転移学習の方法（TRANSFER LEARNING FOR COMPUTER VISION TUTORIAL）](https://colab.research.google.com/github/YutaroOgawa/pytorch_tutorials_jp/blob/main/notebook/2_Image_Video/2_1_transfer_learning_tutorial_jp.ipynb)の実践編として、小松菜奈とあいみょんを識別するモデルを作っていきます。やっていることはこのチュートリアル通り(データ拡張の仕方に回転を加え、切り取り方を変えたくらい)なので、学習部分の詳細なコードはここでは省きます。

## データ収集
教師データとなる画像の収集にはicrawlerを用います。

```
pip install icrawler
```

```Python
from icrawler.builtin import BingImageCrawler
crawler = BingImageCrawler(storage={'root_dir': "nana"})
crawler.crawl(keyword="小松菜奈 顔写真", max_num=1200,min_size=(256,256))
```

ただし、この方法では複数人写った画像、別人の画像も入ってしまうので、手作業でそれを排除し、また顔が画像の中心にないものについてはスクリーンショットで修正したものに置き換えます。

こうして、小松菜奈、あいみょんの画像をそれぞれ(訓練用：192枚,検証用：30枚)用意しました。

## 学習の実行
訓練済みモデルresnet18をロードし、最後の全結合層を新しいものに取り替えてファインチューニングします。30エポック学習を繰り返すと、検証用データでの精度が最大で0.88ほどになりました。

![スクリーンショット 2021-09-05 16.10.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1940763/4e29a7ca-5f4f-e0f7-db5c-6392cc04ce5e.png)

![スクリーンショット 2021-09-05 16.15.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1940763/8fe28b6e-b2c4-53d1-81df-b3bb0ec0d837.png)

## 顔検出による改善
さて、ここからどうやって改善していけばよいでしょうか。

まず、クロールした顔写真の中には、顔がアップで写っていないものも多くあり、それらを放置していました。手作業でこれ以上修正するのは大変なので、dlibを用いて顔検出をし、適当に切り出して訓練データを洗練させていきました。(参考：[広瀬アリスさんとマーティン選手(ロッテ)は本当に似ているのか?](https://qiita.com/Droroba1990/items/376f0b14086214f622e9))

顔検出前
![スクリーンショット 2021-09-05 16.32.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1940763/476983e1-9563-79e2-b60a-4d7fee17c64b.png)



顔検出後
![スクリーンショット 2021-09-05 16.35.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1940763/acca1ee0-2c2c-a756-2ad1-76462c6f0772.png)

顔検出ができなかった画像については無視されているため、訓練用のデータ数はそれぞれ140程度に減りましたが、顔がアップになっているため、識別はしやすくなっていると思われます。前と同様に30epoch学習させると以下のようになりました。
![スクリーンショット 2021-09-05 17.30.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1940763/28a15580-71df-d9bd-4a6c-083f517618c6.png)

![スクリーンショット 2021-09-05 17.31.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1940763/bea20049-7116-b898-76f8-34357375a5b3.png "四枚目が誤識別")

accuracyは0.917と微増しましたが、思ったほどの改善ではありませんでした。また、epoch10付近から既に学習が停滞しているように見えます。

データ拡張の仕方を変えたり(切り取り方にランダム性を持たせる、明度・彩度・コントラストを変動させる)、最適化アルゴリズムを変えたりしましたが、さらなる改善はできないままGPUが使用制限を迎えてしまったので、今日はここまでとします。見込みのありそうな工夫があったら教えてください！

## おすすめ記事

[芸人のコント動画、「文字通り」切り抜いてみた](https://qiita.com/masaka_programming/items/b3d98131b04f1906cde4)

[ジャルジャルのネタのタイトル、マルコフ連鎖で生成する奴](https://qiita.com/masaka_programming/items/7f2db9a77c18c0000dc2)


## おまけ
![スクリーンショット 2021-09-05 22.11.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1940763/0905a29a-67fc-53ef-3804-531cd7be9ba6.png)

注：金属バット友保
CloudFormation

# cloudformation subscription filter lambda

[参考](https://qiita.com/Yuki_BB3/items/e563bd198820b6d03f90)

[参考](https://teratail.com/questions/339855)

[Validating a template](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-validate-template.html)
Laravelで"could not find driver"が発生する原因(MySQL)

##原因

PHPとデータベースサーバー間を接続するPDOドライバが見つからないこと。

##解決

php.iniファイル（９３９行目）のコメントアウトさせたコードを直す必要があります。
windowsであればwhereコマンド、Linuxであれば、whichコマンドでphp.iniのpathを調べてください。

```php:Command
where php.ini
//windowsの場合

which php.ini
//Linuxの場合
```
次に以下のコードを直します。

```php:php.ini
//extension=pdo_mysql
```

<div style="text-align: center;">
↓
</div>

```php:php.ini
extension=pdo_mysql
```

##結論
PHPとデータベースサーバー（今回はMySQL)を接続するPDOドライバが使えていなかった。
Java 『equals』と『 == 』 の違いについて

IF文で条件分岐を行うときに
『equals』と『 == 』を知らずに、『 == 』を使用すると
かなりの確率で不具合（バグ）が発生します。

例えば、下記の処理を実行すると
コンソールには、何が出力されるかわかりますか？

# プログラム
```java
public class Test {

  public static void main(String[] args) {

    String test1 = new String("100");
    String test2 = new String("100");

    if (test1 == test2) {
      System.out.println("同じです");
    } else {
      System.out.println("違います");
    }

    if (test1.equals(test2)) {
      System.out.println("同じです");
    } else {
      System.out.println("違います");
    }
  }
}
```

## コンソール結果

```bash
違います
同じです
```
gitコマンドの基本操作まとめ

## はじめに
周りにgit管理をGUIで行なっている人が多く、コマンド派の自分としては
「あれ、gitコマンドって意外と難しいの…？」
ってなったので、メモ程度ですが普段使っているコマンドをまとめてみました。
なお、筆者のgit歴は1年ほどで基本的なことしか書いていません。
初心者の方の理解向上に繋がれば幸いです。

## ブランチ
### 今いるブランチの確認
```
git branch
```
ローカルにあるブランチ一覧が表示されます。
`*`がついているところが今いるブランチです。
何もcommitしていないと表示されないので要注意です。

### ブランチの移動
```
git switch ブランチ名
```
指定したブランチに移動します。
移動前のブランチで作業中の内容（commit前）は新しいブランチについてきます。

```
git switch -c 新しいブランチ名
```
`-c`オプションを使うことで、新しいブランチを作成しつつそのブランチに移動できます。
移動前のブランチの内容と同じところからスタートします。

## バーション管理
### 状態確認
```
git status
```
ファイルの状況を確認します。
`Changes to be committed`：内容変更していてaddしたもの
`Changes not staged for commit`：内容変更していてaddしていないもの
ファイル名が出てこなければ、それは前回のcommitから変更がないということです。
addやcommit前にstatusを確認するようにするとミスが防げます。

```
git diff ファイル名
```
add前のファイルの差分を表示します。
これはコマンドで確認するよりもエディタで見る方が見やすいかもしれないです。

### 保存
```
git add ファイル名
```
指定のファイルをcommit対象に加えます。
複数のファイルを変更している場合でもcommitを切り分けるのに便利です。

```
git restore ファイル名
```
add前のファイルの変更内容をなかったことにします。

```
git reset ファイル名
```
addしたファイルをcommit対象から外します。
変更内容は残るので、間違えてresetした場合はもう一度addすればOKです。

```
git commit
```
addしたファイルをcommitします。
`git commit`をするとコミットメッセージを入力する画面になるので、
メッセージを入力して`:wq`で保存できます。

## 共有
### 自分の作業内容を他の人に共有したい時

```
git push origin ブランチ名
```
指定したブランチの内容をリモートの同じブランチ名のブランチに反映させます。
push先のブランチ名がローカルのブランチ名と異なる場合は、
以下のように":"で繋いで指定します。

```
git push origin ローカルブランチ名:リモートブランチ名
```

### 他の人の作業内容を自分のローカルに持ってきたい時

```
git fetch
git pull
```
fetchで他の人の差分を取得し、pullすることでその差分がブランチにmergeされます。

```
git fetch
git switch fetchしたブランチ名
```
他の人が出したプルリクを自分のローカルで挙動確認したい時など
リモートにはブランチがあるけどローカルには無いような場合には、
fetch後にswitchでそのままローカルにブランチが作れます。


## 最後に
初投稿だったので読みづらいところがあったかと思いますが、
最後まで読んでいただきありがとうございます。
改めて書くと自分の復習にもなりました。
間違いなどありましたらご指摘いただければと思います。
AI QUEST AIを使用した課題の導入

AI QUESTに参加しており、そこで学んだことを随時書き足していきます。  
メモ形式になっているため、わかりにくいところがあればコメントください！！(もちろん誤字脱字も！)

＜一連のプロセス＞
     0.   テーマの選定 
1. 要求定義
2. 要件定義
3. モデル開発(PoC)
4. 本番実装・運用計画
5. プレゼン

```
＜詳細のプロセス＞
1. 要求定義
・背景理解
・情報取得
・要求定義

2. 要件定義
・AI化業務の具体化
・項目の書き出し
・要件定義

3. モデルの開発
・データの前処理
・モデリング
・評価精度

4. 本番実装・運用計画
5. プレゼン
```

0.　導入テーマの選定

ゴール・課題の確認
＞課題が明確な時
AI導入を行うべきかを検討する
→企業の"課題"と"AIを使って本当に解くべき課題"にミスマッチがないかを検討
→"表面上の課題"かを見極める
("誰のために"、"どのようなメリットがあるか"、"サービスがどのようなインパクトをもたらすか"を質問する)

＞課題が不明確な時
・業務について大枠を理解する
→現場　:インパクトに小さい課題
→経営層:実現可能性が低い課題
を言及しやすい

・"課題がない"と言われている業務についても深堀りする
→意図しない課題を発見できるかもしれない(第3者目線で)

課題抽出のプロセス
1.現状の把握

2.現場へのヒアリング
各人へのヒアリングのポイント
→適切な人にインタビューを行う
→インタビューの目的や経緯も伝える
→「はい」か「いいえ」で答えられる質問を行う
→回答は可能な限り定量化する

3.過去事例の参照

4.データの確認
・必要なデータが揃っているか
・データの量
	・データ数
	・カテゴリ数
	・期間
・データの質
	・収集方法
	・欠損値の確認
	・外れ値の程度



1.　要求定義
このフェーズでは以下の3点を明確にする
・背景理解
・情報取得
・要求定義

想定すべき質問
1. そもそもAIによる予測・分類を何のために行うか 
2. 業務の全体像を鑑みて、どの工程をAIによる予測・分類を行うか 
3. AIで実現する精度目標をどのように設定するか 
4. AI実装に必要な対象データは何で、それらをどのように取得するか 
5. モデリングに際し、学習用データ評価用データはどのように分割するべきか 
6. 開発要件を踏まえた時に、どの指標で構築したモデルを評価するか 
7. AI導入によって、どの程度の想定効果が期待できるのか 

提案書作成について
1. プロジェクトの全体像
→会社の置かれている状況
→本取組の目的
     2. 位置付けとゴール
→ゴールはなんなのか
→実現後どうなるのか
     3.対象となる課題
→ゴール達成までの課題
複数あるなら列挙する
     4.課題に対するアプローチ
→課題にたいするアプローチ方法
     5.スケジュール
EXCEL VBAではSQLの正規表現に％を使う

EXCELVBAでSQLの正規表現を使うときにハマってしまったことをメモ。

EXCELVBAでは正規表現に✳︎ではなく％を使わなきゃいけないみたい。

```
誤
SELECT 列名 FROM テーブル名　WHERE 列名　LIKE '％　✳︎検索文字列✳︎'

正
SELECT 列名 FROM テーブル名　WHERE 列名　LIKE '％検索文字列％'
```

まずAccessのクエリでSQLを作り、データをちゃんとひっぱってこれることを確認してから、ExcelVBAにそのSQLをコピペしてたんですが、1件もヒットせず。特にエラーが出るわけでもないので、原因がわかるまで1〜2時間費やしてしまった（ ;  ; ）

初歩的なミスでした。
Linuxのバックアップ rsyncについて

今回はLinux系サーバーのバックアップによく使われるrsyncについての説明です。

rsyncとは、ファイルの同期を行うコマンドで、cpコマンドとは異なり差分確認を行う為、バックアップ等の処理を高速に行えます。
また、ネットワーク越しの同期も可能なので、バックアップ先にNAS等他のサーバーを指定することも出来ます。

書式は以下の通りです。

```
rsync <オプション> <コピー対象> <コピー先>
```

オプションについては、基本的には`-a`を付けておけば全てバックアップ出来ます。
`-a`オプションは権限情報やタイムスタンプ、リンク情報等もバックアップに含めるので、バックアップ時にはほぼ必須のオプションとなります。
利用方法次第では`-a`オプションの次くらいに必須になりそうなオプションとしては、`-v`オプションがあり、このオプションをつけることで詳細表示されるようになります。
`-v`オプションに`-h`オプションを追加するとさらに分かりやすく情報表示できるようになります。
また、`-u`オプションを付けると、ファイルやディレクトリに更新があった場合のみコピーするので、より高速に処理するようになります。

ネットワーク越しにバックアップする場合のディレクトリ指定書式は以下の通りです。
以下の書式はrsyncに限らず、ネットワーク接続する場合に共通した書式となります。

```
<接続先ユーザー名>@<接続先IPアドレスまたはFQDN>:<ディレクトリフルパス>
```

当然ですが、ネットワーク越しにバックアップを実行する場合、コマンド投入後に接続先のパスワードを聞かれます。

rsyncコマンドの注意点として、コピー対象の指定時に、ディレクトリで終わる場合、ディレクトリ名の後ろに「/」を付ける場合と付けない場合で挙動が変わります。
例えば`/home/user/`と指定した場合は、`user`ディレクトリ配下の前ファイルがコピー先に指定したディレクトリ直下に配置されますが、`/home/user`とした場合、コピー先ディレクトリ直下に`user`ディレクトリごとコピーされます。

```
$ls /home/user
a.txt
b.txt

#ディレクトリ名の後ろに「/」を付けた場合
$rsync -a /home/user/ /home/backup
$ls /home/backup
a.txt
b.txt

#ディレクトリ名の後ろに「/」を付けない場合
$rsync -a /home/user /home/backup
$ls /home/backup
user
$ls /home/backup/user
a.txt
b.txt
```

ちなみに余談ですがWindowsにもrsyncに代わるコマンドが存在していて、`robocopy`コマンドがそれに値します。
ただし、当然ながらオプションの指定方法等がだいぶ異なります。
今回は以上です。
関数型インタフェースとラムダ式

## 関数型インタフェースとは
実装が必要な抽象メソッドを1つだけ持つインタフェースのこと。

```java:Logic.java
interface Logic {
  void run(String name); // ← 抽象メソッドを一つだけもつ。
}
```

## ラムダ式
関数型インタフェースの実現を、簡潔なコードで行うための記述方法。
ラムダ式を使用すれば、新たにクラスを宣言せずにインタフェースを実現できる。
※ ラムダ式以外にも、匿名クラスを使用する方法もある。

ラムダ式を使用する場合と使用しない場合のコードで比較してみます。
☟のような、Logicインタフェースを使用するServiceクラスを定義します。

```java:Service.java
class Service {
  private Logic logic;

  public Service(Logic logic) {
    this.logic = logic;
  }

  public void do(String name) {
    this.logic.run(name);
  }
}
```

### ラムダ式を使用しない場合

```java:HelloLogic.java
class HelloLogic implements Logic {
  @Override 
  public void run(String name) {
    System.out.println("Hello, " + name); // 抽象メソッドを実装する。
  }
}
```

```Main.java
class Main {
  public static void main(String[] args) {
    Logic logic = new HelloLogic();
    Service service = new Service(logic);
    service.run("Qiita");
  }
}
```

### ラムダ式を使用する場合
※ HelloLogicクラスは無し

```Main.java
class Main {
  public static void main(String[] args) {
    Logic logic = (name) -> {
      System.out.println("Hello, " + name); // 抽象メソッドを実装する。
    };
    Service service = new Service(logic);
    service.run("Qiita");
  }
}
```

## 関数型インタフェースとラムダ式はどうして必要？
例えば☝のコードでいえば、次のように書いても同じ動作になります。

```java:Service.java
class Service {
  public void do(String name) {
    System.out.println("Hello, " + name);
  }
}
```

```Main.java
class Main {
  public static void main(String[] args) {
    Service service = new Service();
    service.run("Qiita");
  }
}
```

このコードで問題なのは、

1. 『処理の全体の流れ』を担当するクラス(`Service.java`)と
2. 『具体的なアルゴリズム』を担当するクラス(`HelloLogic.java`)が

ひとつになってしまっていることです。



逆に、『ラムダ式』の項で書いた２パターンのプログラムは、
『処理の全体の流れ』と『具体的なアルゴリズム』を分けて実装しています。
この実装方針は『GoF』デザインパターンの一つである『Strategy』パターンと呼ばれています。

『付け替え可能なアルゴリズムを実装する』デザインパターンともいわれるこのプログラミングのように
『具体的なアルゴリズム』が『処理の全体の流れ』の外で定義されていると
アルゴリズムだけを変更することが容易になります。

では、☟のコードではどうでしょうか。

```java:EchoHello.java
class EchoHello {
  public void run(String name) {
    System.out.println("Hello, " + name);
  }
}
```

```java:Service.java
class Service {
  private EchoHello echo;

  public Service() {
    this.echo = new EchoHello();
  }

  public void do(String name) {
    echo.run(name);
  }
}
```

```Main.java
class Main {
  public static void main(String[] args) {
    Service service = new Service();
    service.run("Qiita");
  }
}
```

たしかに『具体的なアルゴリズム』の実装を`EchoHello`クラスに外だし出来ていますが、
このコードの問題点は『全体の処理の流れ』のクラスと『具体的なアルゴリズム』のクラスが直接結びついてしまっていることです。
もし`EchoHello`クラスに何らかの変更があったときに、`Service`クラスも修正する必要性が出てくる可能性があります。

このコードを、関数型インタフェースを使用して実装することで、
アルゴリズム間に共通の型をもたせ、クラス間の直接の結びつきを避けることができます。
`Service`クラスからは`Logic`インターフェイスという型だけを意識すればよくなるので、
アルゴリズムを変更しても全体の処理を修正する必要はなくなります。

さらに、関数型インタフェースをラムダ式で実現すれば、クラスをやみくもに増やすことなく
Strategyパターンに沿ったプログラムを組むことができるというわけです。

## まとめ
関数型インタフェースとラムダ式を使用することで、
Strategyパターンに則った、変更に強いプログラムを
簡潔なコードで実装することができます。
MariaDB / MySQL のストアドプロシージャ/ストアドファンクション

いつも忘れるので備忘録。

# 環境

- Ubuntu 20.04
- MariaDB Server version: 10.3.31-MariaDB-0ubuntu0.20.04.1 Ubuntu 20.04


# ストアドプロシージャ

## 一覧確認

```

SHOW PROCEDURE STATUS;

```

または

```

SHOW PROCEDURE STATUS \G
```


名前だけ確認するには

```
SELECT ROUTINE_NAME FROM information_schema.ROUTINES WHERE ROUTINE_TYPE = 'PROCEDURE' AND ROUTINE_SCHEMA=("データベース名");
```

## 作成

```
DELIMITER //
CREATE PROCEDURE ストアドプロシージャ名( IN input TEXT )
BEGIN
 SELECT * FROM 会員 WHERE 会員番号=input;
END//
DELIMITER ;
```



## 内容確認

```

SHOW CREATE PROCEDURE ストアドプロシージャ名;
```

## 実行

```

CALL ストアドプロシージャ名("123-4567");
```

## 削除

```

DROP PROCEDURE ストアドプロシージャ名;
```


# ストアドファンクション

## 一覧確認

```

SHOW FUNCTION STATUS;

```

または

```

SHOW FUNCTION STATUS \G
```

名前だけ確認するには

```
SELECT ROUTINE_NAME FROM information_schema.ROUTINES WHERE ROUTINE_TYPE = 'FUNCTION' AND ROUTINE_SCHEMA="(データベース名)";
```


## 作成


```

DELIMITER //
 CREATE FUNCTION ストアドファンクション名(_会員番号 TEXT) RETURNS INT NOT DETERMINISTIC
 BEGIN
 DECLARE _アクセス年 INT ;
 SELECT アクセス年 INTO _アクセス年 FROM アクセス記録 WHERE 会員番号=_会員番号;
 IF _アクセス年 = 2021 THEN    RETURN 1;
   ELSE    RETURN 0;
 END IF;
 END//
DELIMITER ;
```

## 内容確認

```

SHOW CREATE FUNCTION ストアドファンクション名;
```

## 実行

```

SELECT ストアドファンクション名("123-4567");
+---------------------------------+
| ストアドファンクション名("123-4567")    |
+---------------------------------+
|                              1 |
+---------------------------------+
1 row in set (0.009 sec)
```

## 削除

```

DROP FUNCTION ストアドファクション名;
```
RailsでBootstrapのハンバーガーメニューが動作しない

Railsアプリ開発中に出会った問題についてまとめています。

今回は、`Bootstrap5`のハンバーガーメニューが正常に動作しない問題に直面しました。

開発環境
- Ruby 2.7.3
- Rails 6.1.4.1
- Bootstrap 5.1

調べたところ、Bootstrap 4系から5系で破壊的な変更が行われた影響で、`Bootstrap5ではRails6においてハンバーガーメニューが正常に動作しない`らしい。

そのため、正常に動作することが確認されている`Bootstrapのバージョンをダウングレードする`ことにした。

`Bootstrap4.6系でもハンバーガーメニューは正常に動作しない`ようなので、`Bootstrap4.5系`を利用した。
下記のコマンドでバージョンを更新できる。ダウングレードであっても`upgrade`と記述する点は注意したい。

```ruby:ターミナル
yarn upgrade bootstrap@~4.5.1
```

`Bootstrap4系`では`jquery`が必要になるため、こちらもインストール

```ruby:ターミナル
yarn add jquery
```

1度、`Bootstrap5系`の`Nav`コードを貼り付けて動作を確認している場合は、`Bootstrap4.5系`の`Nav`コードに変更する必要がある。

5系と4.5系のコードは下記のように異なっている。

```:Bootstrap5系
<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <div class="container-fluid">
    <a class="navbar-brand" href="#">Navbar</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarNav">
      <ul class="navbar-nav">
        <li class="nav-item">
          <a class="nav-link active" aria-current="page" href="#">Home</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">Features</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">Pricing</a>
        </li>
        <li class="nav-item">
          <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
        </li>
      </ul>
    </div>
  </div>
</nav>
```

```:Bootstrap4.5系
<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <a class="navbar-brand" href="#">Navbar</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarNav">
    <ul class="navbar-nav">
      <li class="nav-item active">
        <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Features</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Pricing</a>
      </li>
      <li class="nav-item">
        <a class="nav-link disabled" href="#">Disabled</a>
      </li>
    </ul>
  </div>
</nav>
```

# 今回学んだこと

プログラムは日々改良されているが、最新版が最適とは限らないことを学んだ。
安定して動作することを確認済みのバージョンを使用する方が、エラーが発生した際のコストが低くなると感じた。

`Bootstrap5系`になったことで、これまで必要であった`jquery`が不要になったのに、結局バグで使用できないのは残念。。。
[Ruby] AtCoder過去問 A - Cookie Exchanges

##はじめに
AtCoder過去問でA問題ですが、小さな見落としでかなり悩みました。
私がつまづいたところも含めて解説していきたいと思います。
よろしくお願いします。

問題はこちらから確認してください↓

https://atcoder.jp/contests/agc014/tasks/agc014_a


## A - Cookie Exchanges
今回はA問題ということで比較的初学者でも時間をかければそれなりに答えを出せるのではないのでしょうか。

こちら私がはじめに組んだプログラムです。
(このコードは間違っています。どこが間違っているか探して見てください）↓


```ruby
a, b, c = gets.split.map(&:to_i)

count = 0

if a == b && b == c
  puts -1
else
  while a.even? && b.even? && c.even?
    a_half = a/2
    b_half = b/2
    c_half = c/2
    a = b_half + c_half
    b = a_half + c_half
    c = a_half + b_half
    count += 1
  end
  puts count
end
```

1行目で入力を受け取ります。
続いて最終的に答えとなる変数count(クッキーを交換した回数)を用意して0を代入しておきます。

if文の中身を解説します。
まず、無限に処理をしてしまうものを除外し、問題に従って```-1```を出力するようにします

```ruby
if a == b && b == c
  puts -1
```

a, b, cが同じ数字だった場合、abcのどれも奇数になることは永遠にないからです。

条件分岐ができたら、上記のもの以外はwhile文でぶんまわし、最終的にwhileの条件式から外れたときに何回まわしたかが答え（クッキーを交換した回数）になります。


```ruby
else
  while a.even? && b.even? && c.even?
    a_half = a/2
    b_half = b/2
    c_half = c/2
    a = b_half + c_half
    b = a_half + c_half
    c = a_half + b_half
    count += 1
  end
  puts count
end
```

whileの条件式はa, b, cのいずれかが奇数になるまで繰り返してくださいってことです。
処理内容は問題文を読めばすぐに納得していただけると思いますが、一応解説すると。

クッキーの交換の仕方は
まずa(高橋), b(青木), c(すぬけ)の持っているクッキーの個数を半分にします。
aはb, cに半分ずつ渡す。
bはa, cに半分ずつ渡す。
cはa, bに半分ずつ渡す。
これが交換一回の処理です。誰か一人でも手持ちのクッキーが奇数になったら交換終了になるので、それまで繰り返すという処理です。


##解答
私の回答で間違っていたのはif文の条件式です。
私のif文をもう一度見てみます。

```ruby
if a == b && b == c
```

これはa, b, cが全て同じ数字なら無限にクッキーを交換してしまうので、無限に交換するときの条件式を書いて、```-1```を出力しています。
しかしながら、無限に交換するのは、同じ数字```且つ偶数の時```なのです。

全部奇数だったら交換すらできないので```0```を出力しなくてはいけないのですね。
なので下記のように、条件を追加します。

```ruby
if a == b && b == c && a.even?
```

これで全て奇数の時はelseの処理に振られ、count=0という結果を得られます。


```ruby
a, b, c = gets.split.map(&:to_i)

count = 0

if a == b && b == c && a.even?
  puts -1
else
  while a.even? && b.even? && c.even?
    a_half = a/2
    b_half = b/2
    c_half = c/2
    a = b_half + c_half
    b = a_half + c_half
    c = a_half + b_half
    count += 1
  end
  puts count
end
```

##最後に
A問題だからと舐めてかかって、かなり悩みました。
入力値に何を入れたときに間違った解答になったのかを教えてくれたらもっと早く気づけるのに。。。
node.js超入門ノート8(Sequelize導入編)

# 準備
以下のコマンドでインストールします。

```
npm install sequelize
npm install sequelize-cli
```

以下のコマンドでsequelizeを初期化します。

```
npx sequelize-cli init
```
config.jsonを以下のように修正します。

```json:config/config.json
{
  "development": {
    "database": "db-development",
    "dialect": "sqlite",
    "storage": "db-dev.sqlite3"
  },
  "test": {
    "database": "db-test",
    "dialect": "sqlite",
    "storage": "db-test.sqlite3"
  },
  "production": {
    "database": "db-product",
    "dialect": "sqlite",
    "storage": "db.sqlite3"
  }
}
```
MySQLを使用する際は以下ように修正します。

```json
{
    "username": 利用者名,
    "password": パスワード,
    "database": データベース名,
    "host": ホストのドメイン,
    "dialect": "mysql"
 }
```

postgresSQLを使用する際は以下ように修正します。

```json
{
    "username": 利用者名,
    "password": パスワード,
    "database": データベース名,
    "host": ホストのドメイン,
    "dialect": "postgres"
 }
```

# モデルの作成
ここではUserモデルを作成します。
以下のコマンドでモデルを作成します。

```
npx sequelize-cli model:generate --name User --attributes name:string,pass:string,mail:string,age:integer
```

以下のコマンドでマイグレーションを実行します。

```
npx sequelize-cli db:migrate --env development
```

# シーディング
ダミーデータ用意します。
以下のコマンドでシーディングのスクリプトファイルを作成します。

```
npx sequelize-cli seed:generate --name sample-user
```
作成されたファイルをもとに以下を記載します。

```javascript:seeders/sample-user.js
'use strict';

module.exports = {
  up: async (queryInterface, Sequelize) => {
    return queryInterface.bulkInsert('Users', [
      {
        name: 'Taro',
        pass: 'yamada',
        mail: 'taro@yamada.jp',
        age: 39,
        createdAt: new Date(),
        updatedAt: new Date()
      },
      {
        name: 'Hanako',
        pass: 'flower',
        mail: 'hanako@flower.jp',
        age: 28,
        createdAt: new Date(),
        updatedAt: new Date()
      },
      {
        name: 'Jiro',
        pass: 'change',
        mail: 'jiro@change.jp',
        age: 17,
        createdAt: new Date(),
        updatedAt: new Date()
      },
      {
        name: 'Sachiko',
        pass: 'happy',
        mail: 'sachiko@happy.jp',
        age: 6,
        createdAt: new Date(),
        updatedAt: new Date()
      }
    ]);
  },

  down: async (queryInterface, Sequelize) => {
    return queryInterface.bulkDelete('Users', null, {})
  }
};
```
以下のコマンドでシーディングを実行します。

```
npx sequelize-cli db:seed:all
```

https://qiita.com/Glider2355/items/71340196b8fd57d3af43
MariaDB(MySQL) でストアドファンクションでローカル変数を使う

# 環境

- Ubuntu 20.04 
- MariaDB Server version: 10.3.31-MariaDB-0ubuntu0.20.04.1 Ubuntu 20.04

# 背景

会員のアクセス記録から、最後のアクセスが今年中だったかどうかを知りたい。

アクセスした一覧を得る目的であれば、普通のSELECT文でもできる。
しかしながらこの条件だけではなく、複数の複雑な条件を AND / OR で論理演算した結果を個人ステータスに表示したい。

なので条件ごとに、True/False で値を返すストアドファンクションを作っておき、それを組み合わせることで実現したい。

特定の日付にアクセスしているかどうかについては、今年中にアクセスしていれば 1 , アクセスしていないと 0 を返すものを作ろうとした。


```

 SELECT アクセス年 FROM アクセス記録 WHERE 会員番号=_会員番号 ORDER BY アクセス年 DESC LIMIT 1;
```

とし、得られたアクセス年をローカル変数 _アクセス年 に入れ、

```

 IF _アクセス年 = 2021 THEN RETURN 1;
   ELSE    RETURN 0;
 END IF;
```

とするにはどうしたらいいかな？


# SELECT ... INTO 構文

MariaDB/MySQL の INTO 構文は 3 つの用法がある。
https://qiita.com/drafts/601832b2da00b451d55d

- SELECT ... INTO var_list
- SELECT ... INTO OUTFILE
- SELECT ... INTO DUMPFILE

この中の、

- SELECT ... INTO var_list

で、SELECT 結果を変数に入れられるそうだ。

# ストアドファンクションを作る



```

DELIMITER //
 CREATE FUNCTION IS今年のアクセス(_会員番号 TEXT) RETURNS INT NOT DETERMINISTIC
 BEGIN
 DECLARE _アクセス年 INT ;
 SELECT アクセス年 INTO _アクセス年 FROM アクセス記録 WHERE 会員番号=_会員番号;
 IF _アクセス年 = 2021 THEN    RETURN 1;
   ELSE    RETURN 0;
 END IF;
 END//
DELIMITER ;
```

# 実行

```

SELECT IS今年のアクセス("123-4567");
+---------------------------------+
| IS今年のアクセス("123-4567")    |
+---------------------------------+
|                              1 |
+---------------------------------+
1 row in set (0.009 sec)

```

# 注意

- ユーザ定義変数は @ をつけるが、ストアドファンクションで DECLARE で宣言するのはローカル変数なので @ をつけなくてもいいようだ。

- ユーザ変数を使った場合は、セッションを意識しないといけないのでユーザ定義変数にしないほうが良さそう。

cf., 「MySQLの SELECT &#8230; INTO 構文で結果を変数に書き込むときの注意 | while(isプログラマ)」
https://am-yu.net/2018/09/06/mysql_select_into_storedprocedure/


- ローカル変数はテーブルカラム名と同じだといけない。当然かな。
cf.,https://dev.mysql.com/doc/refman/5.6/ja/local-variable-scope.html

- クエリーは、単一行を返すようにしないといけない。
cf.,https://dev.mysql.com/doc/refman/5.6/ja/select-into.html
クリエイター（個人開発者）向け無料宣伝サービス『リツイッター』をリリース

# はじめに
このサービスを作ろうと思った目的
自分は色々な小さいウェブサービスを作っていますが、
作っても使ってもらえないということが多いです

使ってもらうためには宣伝すればよいのですが
個人開発したサービスに宣伝費をかけるのもまた違うと思います
お金をかけずに、相互で宣伝・応援しあえるサービスを作成しました

https://retwitter-service.web.app

# 使用した技術

### バックエンド
- ASP.NETCore(C#) WebAPI

### フロントエンド
- Vue.js 3.0
- Vuetify 3.0 Alpha

### データベース
- Firebase Realtimedatabase

# デプロイ先
### バックエンド
- Heroku

### フロントエンド
- Firebase

# 技術選定に関して
### バックエンド
無料枠で賄っているため、フロントエンドのみで解決したいなと思いましたが
今回はTwitterApiを使うのでバックエンドは必須です
GASを使うというのも考えましたが無料枠の上限が1日2万回コールだったため、微妙かなと思い却下しました
（1日2万回も使われねぇよ！というのはさておき・・・）

さくっと作りたかったのと、すでに資産があるのでC#にしました
Dockerを使ってHerokuにデプロイしています

### フロントエンド
ReactかVue.jsで悩みましたが
Vue.jsにしました

普段ビルドにはViteを使っている関係上、Vue3を強制されていました
Vue3はVue.jsの有名なデザインフレームワークVuetifyが長い間対応していなかったのですが
公式サイトを見てみるとVue3で使用できるVuetify3.0のα版が公開されていたので
こちらを使ってみようということでVue.jsにしました

### データベース
お手軽かつ、フロントエンド・バックエンド共に使用できる
FirebaseのRealtimeDatabaseを選びました
SQLが書けないので複雑なクエリは出来ないのですが
今回は複雑なことはしないのでコレにしました
FireStoreを使わないのは無料枠の関係です

フロントエンドからRealtimeDatabaseを参照することにより
APIの叩く数を減らすようにしています

# このサービスを作ってみて
新しい学びがあったかというと微妙なところで
Vue,RealtimeDatabase,C#に関しては他のアプリを作るときにも使用しているので淡々とやっているだけでした。

Vuetifyに関しては全く触れたことがなかったので、触れてよかったなって思いました
別のデザインフレームは使用したことがあり、BootstrapとMaterializeなのですが
それらとの違いはタグ指定かクラス指定か程度でした

あと、今回C#からがっつりRealtimeDatabaseを使用しましたが、結構使いやすいなと思いました
様々なクラウドサービスでPaaSが無料というのはあるのですが、データベースに関しては無料が少なく、あったとしても容量が少なすぎて使い物にならないものばかりです
RealtimeDatabaseは1GBまで無料で使用でき、ドキュメント型のDBなのでカラム定義せずともデータを突っ込めるので、サクッと作りたい方にはオススメだなと思いました

また、RealtimeDatabaseについて調べている最中にRestApiも使用できるということも知りました
コレについては別記事を書くかもしれません

最後になりますが
このサービスも使ってもらってなんぼなので、どうぞ使ってやってください
ESP32単体で使ってみる

#経緯
ESP32を超低消費電力で動作させたかったが
ESP32-DevKitCだとDeep-Sleepに入れても5～30mAは消費してしまったため
余計な部品抜きで動作させてみた

#実現手段
ESP32単体用のピッチ変換基盤らしきものを購入してそのまま使う　←そのままでは使えなかったが

#環境
電源：ESP32-DevKitCの3.3V電源
シリアル変換IC：CH340(KKHMF製)

#問題
いざ基盤に半田付けして、電源・RXD・TXDを繋いでみたが
TeraTerm上になにも出てこない
ESP32は電源が入ると前回電源がなんで落ちたかみたいな情報を吐き出すはず

#原因
購入したピッチ変換用の基板はそのまま使えなかった
電源(3.3V)とEN端子の間に10KΩ程度の抵抗を挟んでやらないと動作しない
ついでに、EN端子とGND間に0.1μFのコンデンサをつなぐといいみたい

逆にEN端子をGROUNDに落とすと再起動できるらしく
ESP32-DevKitCのBOOTボタンと同じ動作なのか？

#解決

ということでEN端子と3.3Vを47KΩ(代用)の抵抗で接続
RESETボタンは0.1μFのコンデンサをつないだところうまくいった。
![スクリーンショット 2021-09-05 195452.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1977949/5cb355c2-9279-9276-1fc2-4e1ebaac2767.png)


CH340シリアル変換器につないで動作確認↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1977949/89ebf645-6ad1-e4a0-5996-b309bad1dad0.png)
C# 文字数の調べ方

##0.0 はじめに
stringなど文字列の長さ（文字数）の調べ方

##1.0 １文字づつ数える（半角、全角区別なし）

Lengthをつかう

```C#:Test.cs
string text1 = "リンゴ";
string text2 = "リンゴx5個"; // x5は半角
string text3 = "リンゴ x5個"; // x5は半角、スペースあり
int textCount = text1.Length; // textCount = 3
int textCount = text2.Length; // textCount = 6
int textCount = text3.Length; // textCount = 7
```

##2.0 全角と半角を分けて文字数を数える
全角は２、半角は１とするbyte数で文字数を数える方法です。
Shift_JISでByteにエンコードすることとなりますが、実機で動作させるため「I18N.CJK.dll」と「I18N.dll」をプロジェクトにインポートする必要があります。

Goro Azumaさんのページ、下記をご参照ください。

https://qiita.com/azumagoro/items/42be0f33fd7a6cb345b9
マウスポインタの位置を確認する方法

マウスポインタがよく迷子になるので、すぐに見つけられるようにする方法です。

# 手順

1. コントロールパネルを開きます。
   「Winマーク」→「cont」と入力すれば出てきます。
   ![001.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230850/6eeed12d-f3b7-2ea9-29d1-210c02d0c16a.jpeg)


1. 「マウス」をクリックします。
   ![002.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230850/4f210beb-ac54-45e5-0020-f3043de368be.jpeg)


1. 「ポインターオプション」タブをクリックします。
   ![003.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230850/75a5ab68-63af-b4ca-4492-445f241b75e8.jpeg)


1. 「Ctrlキーを押すとポインターの位置を表示する」にチェックを入れて「OK」をクリックします。
   ![004.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230850/d174f9b2-f459-94c7-2115-1f0b328187d0.jpeg)


これでマウスポインタが迷子になっても、「Ctrl」キーを押せば場所が分かるようになります。
【C++】和をaccumulate/reduce()で算出するときにオススメするお作法

# はじめに
std::accumulate/reduce()には、「第三引数に生の`0`を渡すと、`int`として誤集計してしまう」という罠があります。
競プロでもプロダクトでも、これが発生するととても辛い気持ちになりそうです。
それにもかかわらず、これを防ぐ方法が日本語で見当たらなかったので、この記事を書きました。

現状広く知れ渡ったお作法ではありませんが、accumulate()を書いている全人類にオススメしたいです。

(2021.9.11 追記) C++17が書ける環境では黙ってreduce()を使いましょう。@yumetodoさんのコメントに感謝。

```c++
    float v[] = {1.1, 1.2, 1.4};
    // std::vector<float> v = {1.1f, 1.2f, 1.4f};
    // std::array v = {1.1f, 1.2f, 1.4f};
    float sum = std::reduce(std::begin(v), std::end(v)); // どの型でも無事3.7
    std::cout << sum << std::endl;
```

以下はC++17が使えず、C++11が使える人向けの記事です。

# お作法
accumulateの第三引数には、`std::remove_refrerence~`以下の部分を渡します。

```C++:
  vector<int> v = {1, 2, 4};
  int sum = accumulate(v.begin(), v.end(), std::remove_reference<decltype(*std::begin(v))>::type{}); // => 7
```
以上です。
std::vector以外にも普通の配列, std::*set, std::arrayでも使えます。

# accumulate の罠
お作法に従わないと以下の罠にハマる可能性があります。

```C++:悪い例
  vector<float> v = {1.1, 1.2, 1.4};
  float sum = accumulate(v.begin(), v.end(), 0); // 3.7になるはずが、3が出力される!
```

理由は、初期値に生の`0`を渡したせいで、リテラル的にintと解釈され、floatがintとして誤集計されてしまうからです。

この意図しないダウンキャストを防ぐために、`decltype(v)::value_type(0)`を渡すというのが今回のお作法です。

```C++:お作法を使った例
  vector<float> v = {1.1, 1.2, 1.4};
  float sum = accumulate(v.begin(), v.end(), std::remove_reference<decltype(*std::begin(v))>::type{}); // 無事3.7
```

これは「`v`というコンテナの要素型を`0`で初期化した値」で、実質`(float) 0`を渡したことになります。よって、floatとして集計され、無事に`3.7`が出力されました。

`float`以外の事例では、`int64_t`や`long long`をintとして誤集計してしまいオーバーフローしたといったことがあるようです。


# std::arrayじゃない方の静的配列の場合
stdじゃない方のarrayはdecltype()が使えないので、~~残念ながらお作法が適用できません。~~

(2021.9.11 追記)
`decltype(v)::value_type(0)` → `remove_reference<decltype(std::begin(v))>::type{}` とすることで対応できました。

# おわりに

C++強い勢はC++が強い


# 参考
- お作法の参考 https://stackoverflow.com/a/3221813 のImportant Note
- int64_tでの事例 https://airscarlet.com/atcoder-accumulate_64bit/
- accumulate https://qiita.com/haruyama480/items/a7ddfc50a03e1f6258dd
設計レビュー文化醸成の取っ掛かりにできそうなテンプレートを作ってみた

# 想定読者
- 設計しないでバグ生んでしまいがちのエンジニア
- 設計段階でレビューする文化がなくてまあまあバグ出ちゃう開発チームの一員

# なぜ
これを考える前の状態が

- とにかくQA段階でのバグが多かった
- PRレビュー時の手戻りが多かった
- そもそも設計段階でのレビューがなかった

でした。このままじゃまずいよね、となり、

- まずは設計の段階でレビューをしましょう
- ただスピードを維持するために必要最低限な要素を簡単にまとめられるようなテンプレート欲しい

ってことで最低限これは書いてほしい項目を考えて運用してみました。四週間ほど運用してみた結果、

- 設計段階で考慮漏れに気づけた
- できる人がどこまで考えてやっているかがチームに共有できた

など一定効果があったので残しておきます。

## 基本設計
### 背景
- JIRAなどのチケットURL
- 機能概要
- そもそもなぜこれは必要なのか(これがないと誰がどう困るか)

```
【レビュー観点】
- チケットURLがあるか
- この機能は誰が/何のために必要か、が他人が見て理解できるか
  - 「ユーザー」ではなくて最低限「ツイートをする人」くらいの粒度までは考えられているか
  - try 書いている内容でわからなければ、この機能は例えばどんな時に使用するか聞いてみよう
 ```
 
### 用語
- 機能に関連する用語
  - 〇〇とは？
  - ××とは？

```
【レビュー観点】
- 関連する概念などの意味があっているか
  - try 自分が意味わからなかった単語について設計者は知っているか質問してみよう
```

### 機能詳細
- 機能が完了したらできること
- 制約

```
【レビュー観点】
- 機能詳細に過不足はないか
  - 例えば、〇〇の場合はツイートができない、などの制約に漏れはないか
  - try 〇〇の場合はこれできる？みたいに聞いてみよう
```
## 詳細設計
### 実装イメージ
デザインのキャプチャがあれば貼る

### 影響範囲
- 既存の機能に影響があると思われる箇所を箇条書きする
- 懸念点とそれに対する対処方法を記述する
- 懸念はあったが、調査の結果影響ないことも記述する

```
【レビュー観点】
- 影響のある機能に漏れはないか
    - web
    - iOS/Android app
    - など
```

### TODO
- レビューしやすい単位を意識
  - エンドポイント作成の時、データの取得/更新/削除はTODOを分ける
  - 変更が大きくなりそうな場合によってはチケットを分割できているか
- 以下があればTODOごとに別途追記
  - 判定/処理などに使用するデータ(新規/既存共に)
  - 使用するライブラリ
  - 考慮すべき点


```
【レビュー観点】
- TODOを見たら誰でも実装できるくらいのレベルまで落とし込めているか
- 関連するデータの記述はあるか
- 懸念とその対応策について言及できているか(設計者が対応策わからなければレビューで解消するため、レビュー時になくても可)
```

### 構成
- ディレクトリ構造
- ファイル名
- そのファイルの役割

```
【レビュー観点】
- ファイル名/ディレクトリ名はわかりやすいか
- ファイルの役割は明確か
- 既存のファイルで置き換えることができる箇所はないか
    - try そのコンポーネントの責務は？と問いかけてみよう
```


# 終わりに
これで万事解決！なんてことはもちろんありませんが、設計レビューをやったほうがいいよね、と考えている誰か一人の参考になれば幸いです。
イベントソーシングについて学んだこと

# はじめに

イベントソーシングについて学んで分かったことをまとめています。

# イベントソーシングの概要

イベントソーシングを簡単に表現すると、アプリケーションに発生した出来事(イベント)を永続化する仕組みのことです。永続化したイベントを順次処理していくことでアプリケーション状態の復元を可能にします。
イベントソーシングを用いない場合の多くはモデルを永続化することになります。例えば、銀行口座システムで顧客Aの口座から10万円の引き出しがあった場合に、モデルを永続化する場合とイベントソーシングを使う場合の永続化のイメージは以下です。

- モデルを永続化する場合

![モデル永続化.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452292/925a2443-20bc-2c3b-e19c-0c9a709c90ca.png)

モデルを復元する場合は、単純にDBから情報を取ってきます。

- イベントソーシングを使う場合

![イベントソーシング.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452292/a9b28c0a-edec-bebc-9fba-951451a9592c.png)

アプリケーション上でモデル(顧客Aの口座情報)が必要な場合は、それまでに永続化されたイベントを順次処理してモデルを復元します。

# メリット

イベントソーシングの最大のメリットは、アプリケーションで行った出来事の全てを記録して特定の時点のアプリケーション状態を復元できる点です。
そのため、銀行のシステムをはじめとした、エンティティに発生した出来事(口座からの引き出し、預け入れなど)をいつでも追跡可能であることが求められるシステムでイベントソーシングを採用することで恩恵を多く受けることができます。加えてアプリケーションが、寿命の長いエンティティ(先述した銀行の口座などがこれにあたる)を扱っている場合にもイベントソーシングを採用するうまみがあります。

# デメリット

イベントソーシングはどんなアプリケーションでも汎用的に活用できる考え方ですが、従来の永続化とは扱うデータが異なるため、求められる永続化のデータ形式も異なります。これがデメリットであるといえます。ですので、イベントソーシングを適用しようとしてるアプリケーションが、イベントソーシングのメリットを受けられる特徴を持っているのかをしっかり吟味して採用することが重要です。

# まとめ

イベントソーシングについて学んだことをまとめました。
アプリケーションにイベントソーシングを採用しようとする際には、メリットを享受できるのかを吟味したうえで採用することが大事であることが分かりました。
オンラインゲーム(GunZ)のマップをWEBに移植してみた【Three.js】

### 一週間前の自分： 3dゲームの知識皆無。Three.js使ったことない

### 一週間後（今）：😎😎😎

ってことでタイトルにもある通り

**GunZ The Duel (or GUNZWEI)** っていう
昔流行ったオンラインTPSゲームのマップをwebに移植してみたので
デモ貼っておきます。
自分は今大学生ですが、昔GunZよくプレイしていました

GunZ, GUNZWEIを愛した人たちに届けばと思ってデモ置いていきます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576748/2fc6cb6f-269f-fb06-75d8-4540e2f5a976.png)

エピソードとか書こうと思いましたが
**みんなが見たいのは結果の部分**だと思うので先にそれをお見せします

# 移植したデモ、コード

WEBでThree.jsを使ってGunZのマップを描画したものです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576748/4d947408-668c-ed88-befe-408108abbe08.png)
デモURLが以下になります。（なぜかスマホでは見れなかった）
Demo URL: https://gunz.sigr.io/test/web-world/

あまりキレイとはいえないソースコードもあります
Codes: https://github.com/LostMyCode/three-gunz/tree/master/test/web-world

このプロジェクトのGithubリポジトリ
https://github.com/LostMyCode/three-gunz

### **デモ見ただけで十分**という方は見ていただいてありがとうございました！
少しでも興味を持っていただければ幸いです

# 補足

前提として投稿主は3Dゲームに関する知識皆無でした。（つい一週間前まで）
Polygon？Vertex？Geometry？Mesh？聞いたことだけあるけど何？状態

でも昔遊んだ GunZが今でも大好きで、web移植するという謎の挑戦をしてみることにしたのです。

## GunZはダウンロードして遊ぶオンラインゲーム
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576748/adec27c6-94a2-e141-de19-6cf722030a1c.png)

GunZはダウンロードしてプレイする形のガチなオンラインゲームです
独自のゲームエンジンで開発され、コードも大部分はC++なので**WEBと互換性**が全くなし。

**ゲームのマップファイルも独自のもので、そのまま3Dデザイナで開いたりすることは不可能でした。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576748/8a4b42de-c981-4045-322a-50eb12b539f9.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576748/e9e338af-b49f-9a6c-3c50-85f50bfa4f7d.png)

.RSや.bspはバイナリで、独自の形式のため読むのは困難だった。

# どうやって移植したのか？

GunZはエミュ鯖というものが存在します。
ゲームよくやる方はご存知の、個人が運営してるサーバーです。

GunZもソースコードがどこからかリークしたせいで
エミュ鯖が乱立したゲームでした。

**「あれ？ソースコードあるってことはどうやってマップファイルがロードされてるのかわかるんじゃ・・・？」**

こうしてこの移植プロジェクトは始まりました。

GunZのソースコードとにらめっこしながら
自分が使い慣れた言語であるNode.jsを使ってバイナリをひたすら読みます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576748/9fb31111-d3eb-d22d-1e9f-1cc92be4884a.png)

マップファイルを読めたからといって
それをThree.jsで表示できる保証なんてひとつもありませんでした。

ただ結果的に

**Node.jsでマップファイルのバイナリ解析 -> JSONにデータを書き出し（モデルの座標、頂点、頂点インデックスなどのデータ） -> Three.jsについて検索しまくって読み込ませる -> 完成**

という手順で成し遂げることができました。

ここまで約一週間です（**3Dゲームや3Dモデルの知識皆無の状態で**）

# やってみて感じたこと

**結論、本読んで学習するより実際作りたいもの作ってみるほうが爆速で学習できる！**

一週間前

- ポリゴン
- メッシュ
- ジオメトリ
- 頂点
- 頂点インデックス

こんなの知りませんでした。聞いたことあるだけ。

でも一週間経った今では 完全にじゃないけど前に比べたらかなり理解が深まった気がします
前より抵抗もなくて、3dモデルとかwebglにより関心を持ちました。

本読んでるときは学習って感じがしますが、
好きなもの作りながら思考しつつリサーチしてるときは楽しいので無敵です。


思いがけない方法でこれらを学ぶことになりましたが
**プログラミングってやっぱり楽しんだもの勝ち**ですね！

拙い文章ですが、読んでいただいてありがとうございました。
【Java】ArrayListまとめ

## ArrayListとは
複数の値を管理するための可変長配列。通常の配列は、あらかじめ要素数を決めておく必要があるのに対し、ArrayListは要素の追加・削除が自由にできるため、不特定量のデータを扱うことができます。

## 利用方法
#### ArrayListクラスのインポート

```java:Java
import java.util.ArrayList;
```

#### インスタンス化

```java:Java
ArrayList<型> インスタンス変数名 = new ArrayList<型>(初期サイズ値);
```
初期サイズ値は省略可能です。
型にはクラス名を指定しますが、リストの要素は参照型である必要があるため、基本型を扱うリストを作成したい場合は、ラッパークラスを用いて定義します。

```java:例
ArrayList<Integer> intList = new ArrayList<Integer>():
```

## ArrayListクラスのメソッド

#### addメソッド
リストの最後に1つデータを追加

```java:Java
インスタンス変数名.add(データ);
```

#### setメソッド
第1引数のインデックスを、第2引数の値に変更

```java:Java
インスタンス変数名.set(インデックス, データ);
```

#### getメソッド
データを1つ取得(配列と同様インデックスは0から開始することに注意)

```java:Java
インスタンス変数名.get(インデックス);
```

#### sizeメソッド
格納されているデータ数を取得

```java:Java
インスタンス変数名.size();
```

#### indexOfメソッド
引数で指定したデータをリストから検索し、見つかった場合はデータが格納されているインデックス番号、見つからなかった場合は「-1」を戻り値として返す。

```java:Java
インスタンス変数名.indexOf(検索データ);
```

#### removeメソッド
インデックスに対応する格納データを1つ削除する (間のデータが削除されると詰めて格納し直す)

```java:Java
インスタンス変数名.remove(インデックス);
```

#### clearメソッド
格納されているデータを全て削除する

```java:Java
インスタンス変数名.clear();
```

#### isEmptyメソッド
リストが空かどうかを判定し、空の場合「true」、データが1つでもある場合は「false」を戻り値として返す

```java:Java
インスタンス変数名.isEmpty();
```
Xcode12でSimulatorビルドが失敗する

# エラー内容など

- command phasescriptexecution failed with a nonzero exit code xcode12
- ARCHS[@]: unbound variable


# 対処方法

project.pbxprojを開いてVALID_ARCHSを削除する
（project.pbxprojはプロジェクト名.xcodeprojを右クリックして「パッケージの内容を表示」に含まれています）

```
VALID_ARCHS = "arm64 armv7 armv7s";
```

Xcode12 から非推奨になった（が、それ以前に作成したプロジェクトで残っている）。

Project や Target で `Build Settings > Architectures > Excluded Architecture` に arm64 を指定しても、VALID_ARCHS で指定されている arm64 が参照されるため、除外されない。
kmsconでcapslockにctrlを割り当てる

# 概要
ArchLinux（CLI環境）でemacsを使いたいと思い、いろいろ調べていましたが、kmsconを使った環境でcapslockをctrlに割り当てる設定に関して情報がなかったため自分で書いておくことにしました。

# kmsonとは
kmsconについての詳細は[こちら](https://wiki.archlinux.jp/index.php/KMSCON)を参照。
簡単に書くと、ターミナルエミュレーターの一種です。

# capslockにctrlを割り当てる
結論から書くと、`/etc/kmscon/kmscon.conf`に下記の設定を追加します。

```
xkb-options=ctrl:nocaps
```

これで再起動するとcapslockにctrlが割り当てられます。

kmsconはXと同様のキーマップ設定を行えますが、Xを使っているわけではないため、[xmodmap](https://wiki.archlinux.jp/index.php/Xmodmap)等を使った方法では変更するこができませんでした。
また、[loadkeysを使う方法](https://wiki.archlinux.jp/index.php/%E3%82%B3%E3%83%B3%E3%82%BD%E3%83%BC%E3%83%AB%E3%81%A7%E3%81%AE%E7%89%B9%E5%88%A5%E3%81%AA%E3%82%AD%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89%E3%82%AD%E3%83%BC)でもなぜかうまく変更することができませんでした。これは標準のターミナルエミュレーターに対しては有効かもしれませんが、kmsconには反映されないようです。

# 最後に
この記事が誰かの役に立てば幸いです。
複数APIへのリクエストをfetch関数で同時実行するプラクティス

# 複数APIへのリクエストをfetch関数で同時実行するプラクティス
## はじめに
JavaScriptでfetch関数を使用して、複数のAPIへのリクエストを同時に実行する際のベストプラクティスを探求していく。
今回は以下の２種類の方法を模索する。

* Promiseオブジェクトで実行
* fetch関数のコールバッグのthenメソッド内で次のAPIへのfetch関数で順次実行

## Promiseオブジェクトで実行
最初はfetch関数の戻り値をPromiseオブジェクトに設定し、実行する方法。

```JavaScript
var resultList = [];
let processA = fetch('https://wwww.aaa.com/bbb');
let processB = fetch('https://wwww.ccc.com/ddd');
Promise.all([processA, processB])
    .then((response) => {return response.json();})
    .then((data) => {
        resultList[] = data;
    })
    .catch(alert);
```

この方法は、各APIの実行結果が互いの実行結果に干渉しない場合に有効である。
fetchで値を取得するだけなら、この方法で充分である。

## fetch関数のコールバッグのthenメソッド内で次のAPIへのfetch関数を順次実行
次にfetch関数のコールバッグのthenメソッド内で次のAPIへのfetch関数を順次実行する方法。

```JavaScript
fetch('https://wwww.aaa.com/bbb')
    .then((response) => {return response.json();})
    .then((data) => {
        return fetch('https://wwww.ccc.com/ddd', data);
    })
    .then((response) => {return response.json();})
    .then((data) => {
        // 次の処理
    })
    .catch(alert);
```

この方法は最初のAPIの実行結果を次に実行するAPIのリクエストパラメータに指定する場合に有効な方法である。
Rest APIの概念では、各APIの実行結果は干渉せず、独立した内容であるべきである。
しかし実際には、トランザクション処理の都合上、順次実行が必要なケースもあるだろう。
そういったケースにはこちらのやり方の方がスマートだろう。

## 最後に
SPAやPWA等でもAPIの実行によるマイクロサービス化が流行する昨今で、今回のように複数のAPIを同時実行するケースは多々あるだろう。
今回の記事が問題の解決に役に立てば幸いである。

## 参考
* [Promiseオブジェクトのリファレンス](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise)
* [thenメソッドのリファレンス](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/then)
* [javascript : 複数のリソースをfetch（）する方法は？](https://www.fixes.pub/program/347281.html)
* [複数の非同期処理終了後(when&Promise.all)](https://skill-up-engineering.com/2020/01/26/%E8%A4%87%E6%95%B0%E3%81%AE%E9%9D%9E%E5%90%8C%E6%9C%9F%E5%87%A6%E7%90%86%E7%B5%82%E4%BA%86%E5%BE%8Cwhenpromise-all/)
* [複数のfetch関数を使って、複数のプロミスを取得する - Promise.all()](https://mycodingjp.blogspot.com/2020/05/fetch-promiseall.html)
* [JavaScript Promise の使い方 / 非同期処理 Async Function/ Fetch](https://www.webdesignleaves.com/pr/jquery/javaascript_03.html)
* [Promise でのエラーハンドリング](https://ja.javascript.info/promise-error-handling)
【Mac】rbenv versionsとruby -vでバージョンが違う時の解決法

ruby versionsの時
---
```
$ ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-darwin20]
```

ruby -vの時
---

```
$ ruby 2.6.3p62 (2019-04-16 revision 67580) [universal.x86_64-darwin20]
```

Rubyのバージョンが違うことがわかります。
この問題解決に２時間くらいかかったので投稿しようと思います。

解決策
---

```
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ source ~/.bash_profile
$ rbenv global 3.0.2
```

結論この３行を上から順番にターミナルに打つと問題解決できました。
めでたしめでたし
呪われたconfig.json

# 呪いの概要
とあるクイズアプリを作成中、discord OAuth2を使おうとし、`config.json`から**clientID**を取得したところ、下三桁が__870__から__800__に置き換わっていた。

```json:config.json
{
  "clientId": xxxxxxxxxx870
}
```

```js
const { clientId } = require('../config.json')
console.log(clientId)
// xxxxxxxxxx800
```

# 原因解明のために
## console.log()
まず、何が起こってるのか正直わからなかったため、とりあえず`console.log(clientID)`で表示してみたが、やはり下三桁が__800__になっていた。

## ファイルの新規作成
これはやばいと思い、とりあえずファイルを削除。
もちろん、変数を取得できないため、ビルドエラーを吐いた。
全く同じ内容を記述し、実行したところ、ビルドエラーは出なかったが、やはり、下三桁が__870__から__800__に置き換わっていた。

## キー名を変更
次に、キー名を変えたらどうなるのかと思い、ふざけて`abcdefg`に変更してみた。
特にエラーを吐くことなくビルドできたが、出てきた数値の下三桁は__800__になっていた。

```diff_jsonnet:config.json
{
- "clientId": xxxxxxxxxx870
+ "abcdefg": xxxxxxxxxx870
}
```

```diff_javascript
- const { clientId } = require('../config.json')
- console.log(clientId)
+ const { abcdefg } = require('../config.json')
+ console.log(abcdefg)
```

## 数値を変更
過去に、ユーザー管理用discord botを作ったときに、ユーザー名の文字列が原因で文字コードエラーが起こり、保存されていた文字列が全く違うものになっていた事件を思い出し、キーだけでなくバリューも変更してみた。
なんと、、、
ここで設定した値も下三桁が書き換えられていた。ここでの数値の下三桁は__343__だった。しかし、`console.log()`して出てきた数値の下三桁は、__400__という数値だった。
最初と同じように、下三桁以外は指定したものと全く同じなのに、下三桁が違う。

```diff_jsonnet:config.json
{
- "abcdefg": xxxxxxxxxx870
+ "abcdefg": xxxxxxxxxx343
}
```

## ファイル名の変更
キーとバリューを変更してもうまくいかなかったため、`ファイル名`を変更してみた。
`config.json` -> `data.json`

```diff_jsonnet:data.json
{
  "abcdefg": xxxxxxxxxx343
}
```
まぁ、結果は、、、
下三桁が400になっていた。

## intで入れる必要なくない？
よくよく考えたら、discord OAuth2で使うので、ここで取得した値はurlに埋め込まれる。
**_int型である必要なくない？_**
String型にしました。

```diff_jsonnet:config.json
{
- "abcdefg": xxxxxxxxxx343
+ "abcdefg": "xxxxxxxxxx343"
}
```

なんということでしょう！
さっきまで下三桁が__400__になっていた値の下三桁が__343__になってる！

# ~~まとめ~~
~~`config.json`のバリューに __int__ を使うのはやめとこう！~~

---

@masato_makino さんからのコメントによると、
__16桁__ の数値を超えた場合、誤差が発生するそうです。

ここで使おうとしていたのは、__18桁__
数字がおかしくなるのは、必然だったみたいです。

---

# 結論
16桁を超える数字を使うときは、intではなく、String型で保存するほうが良い。
AWS CloudWatchロググループで、KMSのARNを指定して作成したときにエラーが出た場合

# 概要
ClouddWatchのロググループ作成時に、暗号化のためKMS key ARN - optionalにKMSのARNを入力してもエラーになってしまう。

![スクリーンショット 2021-09-05 19.07.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44053/4ff5118e-7de0-b645-80ae-7a72ef616e19.png)

諦めかけていたところに、[CloudWatch LogsのログデータをKMSで暗号化する](https://dev.classmethod.jp/articles/encrypt-cloudwatch-logs-with-aws-kms-cmk/)に書いてあった以下のことを試してみました。

>AWS KMSの運用では

>鍵の管理者
鍵の利用者
の2種類のポリシーが必要です。

>CW Logsの暗号化では鍵の利用者向けポリシーが該当します。

>このポリシーの Principal に "Service": "logs.AWS-REGION.amazonaws.com" を>追加します。リージョンを含める必要がある点に注意ください。


試しにKMSのキーポリシーに、```"AWS": "arn:aws:iam::1234567890:user/udemy"```の1行を追加してから、再度ロググループ作成のところで、先ほど指定した同じKMS Key ARNを
設定してロググループを作成したら、エラーが表示されずにロググループを作成できました。

```json
        {
            "Sid": "Allow use of the key",
            "Effect": "Allow",
            "Principal": {
                "Service": "logs.ap-northeast-1.amazonaws.com",
                "AWS": "arn:aws:iam::1234567890:user/udemy"
            },
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
            ],
            "Resource": "*"
        }
```

公式ドキュメントにもそれらしき記載がありました。

[AWS Key Management Service を使用して CloudWatch Logs のログデータを暗号化する](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/encrypt-log-data-kms.html)

>ステップ 2: CMK で許可を設定する

>デフォルトでは、すべての AWS KMS CMK はプライベートです。リソースの所有者のみがその CMK を使用してデータを暗号化および復号できます。ただし、リソース所有者は、他のユーザーとリソースに CMK へのアクセス権限を付与することができます。このステップでは、CloudWatch サービスプリンシパルに、CMK を使用するアクセス権限を付与します。このサービスプリンシパルは、CMK が保存されているのと同じ AWS リージョンにある必要があります。

要するに、CMKを使用する権限を与えてなかったからエラーになったんですね。

>The specified KMS key does not exist or is not allowed to be used with LogGroup 'arn:aws:logs:ap-northeast-1:1234567890:log-group:session_log_test'

エラーメッセージにも「is not allowed to be used with LogGroup」と書いてあるので、権限周りを疑うべきでした。
Snowflakeで大きなレスポンスを返しているクエリーを見つける方法

性能ボトルネックの切り分けで、Snowflakeが大きなレスポンスを返していることが原因かどうかを切り分けるときに使った方法です。
以下の手順例では1MBより大きいレスポンスを返しているクエリーが何件あるかをチェックしています。

## 手順例

```sql
-- SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORYテーブルをSELECTできる権限をもつロールを使います。お使いの環境によって変えてください。
use ROLE ACCOUNTADMIN;

-- オプション：いつ時点からのデータをチェックしているかを確認
--公式ドキュメントでは1年間保持されると明記されています。参考：https://docs.snowflake.com/ja/sql-reference/account-usage/query_history.html
select min(START_TIME) from SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY ;

-- 1MBより大きいレスポンスを返しているクエリーが何件あるかをチェック
select count(*) from SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY where BYTES_WRITTEN_TO_RESULT > 1024 * 1024;


```