OmniAICreator/Qiita-1.07M huggingface dataset:
OpenAIが2022/09/22に発表した高精度音声認識モデル「Whisper」を非エンジニアやMacユーザでも簡単に使え、GoogleSheetsやExcelに取り込めるGoogleColaboratoryをつくった

# 概要
OpenAIが2022/09/22に発表した高精度音声認識モデル「Whisper」を発表しました。
ただこのモデルはGPUを使うので、精度を試したりするのに気軽に実行できません。
特にGPUを積んでいるWindows機がないような、Macユーザは中々このモデルのすごさを自分の使いたい音声や動画で試せないのはもったいないと思います。
また個人的に、このWhisperの音声認識の恩恵を受けれるのは、非エンジニアで議事録などを書かれている方だと考えています。
そこで公式のGoogleColaboratoryを改造して、非エンジニアやMacユーザでも気軽に使え、日本語フレンドリーなGoogleColaboratoryを作成しました。
このGoogleColaboratoryを使うことで、普段議事録を作られている方の負担が少しでも減ればと思います。

# できること
最新のモデルで自分の録画や音声ファイルを音声認識させ、その結果をファイルの時間のポジションとともに、CSV,JSON, Markdown 形式でコピーできます。
CSV形式でコピーできるので、Google SheetsやExcelに取り込むことが出来ます。

# 使い方
このリポジトリにアクセスして、以下画像のアイコンをクリックしてください。
GoogleColaboratoryという、Googleが提供している無料でPythonが実行できて、GPUも利用できる環境のページへ遷移します。

https://github.com/akitana-airtanker/Whisper-Easy-Colab
![スクリーンショット 2022-09-25 17.21.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243031/79b90613-72b0-600e-051b-b0e129d7c0cc.png)

手順としては、
1. Google Driveに音声認識したい音声ファイルや動画ファイルをアップロードする（動画でもいい感じに変換してくれます）
1. GoogleColaboratoryに記載されている手順通りに実行する
    1. Google Driveへの接続
    1. アップロードしたファイル名を入力
    1. 変換の実行
    1. GoogleColaboratory下部に記載されている手順で、CSV,JSON, Markdown 形式でコピー

となります。
実際のやることについては、GoogleColaboratoryに記載していますが、手順ごとに実行ボタンを3回押すだけとなっています。
（コード部分を隠しているので、コードが見えているだけで辛い...と言う方でも実行できます）

# GoogleColaboratory とは

Googleが提供しているWebで機械学習やどが実行できる環境を提供している無料のサービスです。もちろんより安定したリソースを確保する場合は、有償のプロプランを契約されることをお進めします。
また Google Drive と GoogleColaboratory しか利用していないため、ある程度秘匿性が高い情報でも実施しやすいかと思っています。（もちろんGoogleを信用している限りは）

> Colaboratory（略称: Colab）は、Google Research が提供するサービスです。Colab では、誰でもブラウザ上で Python を記述、実行できるため、機械学習、データ分析、教育に特に適しています。具体的には、GPU などのコンピューティング リソースに料金なしでアクセスしながら、特別な設定なしでご利用いただけるホスト型の Jupyter Notebook サービスです。

> 本当に料金なしで利用できるのですか？link
はい。Colab は料金なしでご利用いただけます。

https://research.google.com/colaboratory/faq.html?hl=ja

# OpenAIとは

近年では、自然言語処理と画像生成を組み合わせたAI「DALL・E」や、大規模言語モデルの代名詞とも言える「GPT-3」などを開発している団体です。今回この団体が高精度で多くの言語に対応しているモデルを公開したために、話題になっています。

> OpenAI は、人工知能を研究する非営利団体である。人類全体に、害をもたらすよりは、有益性があるやりかたで、オープンソースと親和性の高い人工知能を、注意深く推進することを目的として掲げている[3]。

> 2015年12月に設立された。イーロン・マスクをはじめとする有力な実業家・投資家が参加していることから注目を集める[4]。
> 2016年4月に強化学習アルゴリズムの検証プラットフォームであるOpenAI Gymを発表した[5][6]。

https://ja.wikipedia.org/wiki/OpenAI

# 最後に
これで世の中から議事録を作成する手間が少しでも減らせればと思います。
読んでいただきありがとうございました。
多分これをやれば受かる！AWS Certified: SAP on AWS - Specialtyに１発で合格した勉強方法

AWS Certified SAP on AWS - Specialty (PAS-C01)に合格したので、勉強方法を備忘として書いておきます。参考になれば幸いです。

## 前提
AWSメインのクラウド基盤のエンジニア。たまにAzure、GCPも。（一応どちらもPro相当の資格を保持しています。）
一応Top Engineers(Service)、ALL Certificate Engineersに認定されてます。

勉強期間:１ヶ月くらい
私の場合、集中して長時間時間を取るということが苦手で、ほぼ毎日３０分〜４０分程度の時間をとってやっていました。

# 試験について
SAPの知識が何一つなかったので、用語がよくわからず苦労しました。
以下ポイントです。
- 一般的なAWSの知識はあったほうがよい。
サンプル問題を見るとなんとなくわかりますが、SAPを知らなくてもなんとなく解けるような問題があります。
- SAPの機能とかは理解しなくもよい。
以下試験ガイドに書いていますが、ワークロードの設計、実装、移行が出題範囲なので、詳細な機能などは理解不要です。
- Udemy等の教材はないので、公式ドキュメントや個人ブログを漁るしかない。
- マネージドサービス押しの他試験と違って、若干オンプレっぽい構成。（オーバレイIPとか）
EC2上での実装がメイン。RDSすら使わない構成がほとんど。
- 技術文書を読んでいるとOracle　Data　Recovery、SUSE　Linux、RHEL、Hana System Replicationとか各ベンダのサービスが結構登場するので、理解が大変。
- 移行パターン（同種間の移行、異種間の移行、停止時間の大小など）の理解が重要。
- SAP on AWSの一般的な構成、高可用性、災対（マルチAZ、パイロットライト、Act-Stnなど）の方式の理解が重要。
- オーバレイIP、SAPサポートの前提、インスタンスタイプ、バックアップの仕組みなどの理解が重要。

# 試験までに何をやるか
### 1.試験ガイドを読む
出題される分野、配分、問題の形式をしっかり読みましょう。
配分は以下のとおりです。

分野 1: AWS での SAP ワークロードの設計 30%
分野 2: AWS での SAP ワークロードの実装 24%
分野 3: SAP ワークロードの AWS への移行 26%
分野 4: AWS での SAP ワークロードの運用とメンテナンス 20%
合計 100% 

[試験ガイド](https://d1.awsstatic.com/ja_JP/training-and-certification/docs-sap-on-aws-specialty/SAP-on-AWS-Specialty_Exam-Guide.pdf)

### 2.サンプル問題を読む
サンプル問題を説いて完璧に解けるようになるまで理解します。
[サンプル問題](https://d1.awsstatic.com/ja_JP/training-and-certification/docs-sap-on-aws-specialty/SAP-on-AWS-Specialty_Sample-Questions.pdf)


### 3.SCSKさんが出しているブログ全7回を読む。
以下ブログ全7回を読みます。SAPを知らない人にはかなりおすすめです。
試験のポイントをかいつまんで解説してくれているので、まずはこのブログを読んでみることをおすすめします。

https://blog.usize-tech.com/aws-sap-on-aws-speciality-study1/

### 4.SAP on AWSのオンライントレーニングを受ける。
オンラインでいつでも受けれるトレーニングです。
こちらも一通り聞いて理解します。

https://explore.skillbuilder.aws/learn/course/external/view/elearning/12164/sap-on-aws-technical?pas=sec&sec=prep

### ５.SAPの技術文書に目を通す
以下に公開されているドキュメントを片っ端から読みます。そこまで物量は多くないかなという感じですね。
構築部分とかは結構読み飛ばしたりしました。
https://aws.amazon.com/jp/sap/docs/

### ６.SAP on AWSのブログに目を通す
SAP on AWSのAWSブログを読みます。
NRIネットコムさんがリンクを公開されているので、そちらを読むくらいでちょうどよかったです。
これも結構重要と感じました。
https://tech.nri-net.com/entry/aws_certified_sap_on_aws_specialty

### ７.練習問題を解く
練習問題を解いて完璧に理解します。

https://explore.skillbuilder.aws/learn/course/external/view/elearning/12528/aws-certified-sap-on-aws-specialty-official-question-set-pas-c01-japanese?pas=sec&sec=prep

# 最後に
SAPやったことない＆あまり情報がないので、苦労しましたが、なんとかこれで１２冠！
先人の方々に感謝です！
Vue.js computed(算出プロパティ)の検証

豚野郎です。
今度は算出プロパティについて書いていきます。
(LaravelはできるからそろそろVueもできるようにしないと・・・・・)


## 1. computed(算出プロパティ)
computedって何？ということで内容を調べてみましたが、
自分の言葉で、一言で説明できませんでした。
(理解不足ですみません。)

**そのため、今回は動きの検証として書いていきます。**

ググってみると「複雑な計算などに使える」という情報が結構出てきます。


## 2. 動き
実際の動きを`console.log()`で見ていきます。

実際に見ていきましょう。
以下の例は、画面に4と表示されます。

```js/main.js
(function() {
    'use strict';

    let vm = new Vue({
        el: '#app',

        data: {
            item: 1,
        },

        computed: {
            remaining() {
                console.log('テスト');
                var result = this.item * 4
                return result;
            }
        } 
    });
})();
```

```index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Vue</title>
    <link rel="stylesheet" href="css/styles.css">
</head>
<body>
    <div id="app" class="container">
        <span class="info">{{ remaining }}</span>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="js/main.js"></script>
</body>
</html>
```

`<span class="info">{{ remaining }}</span>`を記載されている時は、
`js/main.js`の`remaining: function () {処理}`の処理が通りました。
記載がない時は処理を通りませんでした。

これで、画面表示時に`{{ 算出プロパティ名 }}`等の記載がある時に
対象の算出プロパティの処理が走ることがわかりました。

補足ですが`function`を省略できるか試したところ、省略しても処理が走りました。
```js/main.js
        computed: {
            remaining() {
                console.log('テスト');
                var result = this.item * 4
                return result;
            }
        } 
```

## 3. 最後に
内容が薄いですが、ここまでにします。
少しずつ理解が深められたらいいなと思います。
なくならないExcel。自動化のススメ

# はじめに
Excelを例にした業務自動化のTipsをなるべく時系列で書きました。

# 一番伝えたいこと
業務整理、改善をしてから適切に自動化しよう

# Tips
## 業務の目的を知ろう
目的が曖昧だとあらゆる無駄を生み出す原因になります。
"何のため"にどんな操作をするのかを明確にしよう。

## 目的達成に必要な要素を洗い出そう
その業務に精通していなければ読解する必要が生じます。
ドキュメントはあればラッキーだと思ってください。
知っている人に聞くと早いことがよくあります。

## 依存関係を明確にしよう
ブック間参照、シートコピー操作、外部DB接続など
依存関係は明確に、分離できるものはして疎結合にしていこう。

## もっと簡単にできないか？
目的から逆算すると無駄なことはよくあります。
現状の手順にとらわれず、もっと効率の良い方法を模索しよう。
Excel関数を組み上げるだけで動的にできることは沢山あります。
VBAはモダンな外部プログラムに置き換えたほうが保守性が向上します。
とはいえ、やりすぎも良くないのでバランスが大切です。

## そのセル、シートは本当に必要？
構成、データフロー(Excel機能のことではない)を整理しよう。
データは可能な限り1方向で流れるようにしよう。
機械に優しくない閲覧優先のフォーマットの廃止、無駄な中間シートの生成をやめるなど。
具体例としてはセル結合といったExcelの悪しき機能は使わないでください。あれば廃止してください。

## 自動化が目的になっていないか？
自動化はあくまで手段です。
費用対効果を見積もり、優先順位をつけて取り掛かろう。

## 自動化すること、しないことを明確にしよう
人の判断が必要な操作と自動化できる操作が混在する場合があります。
操作を分解して順序を組み替えたりして運用しやすい手順を模索しよう。
運用が見えたら自動化前に合意形成しよう。

## ドキュメントに残そう
数日後のあなたは他人です。
取り決めたこと、明らかになった情報は必ずドキュメントに残そう。

## 自動化したら慣らし運転しよう
気づかなかった問題が見つかります。完璧なテストは書けません。

## そして運用、保守へ
定期的に振り返ろう。ドキュメントは更新しよう。

## おわりに
たとえ自動化に至らなくても、自動化を考慮した業務整理は様々な場面で活きてきます。
目の前に退屈な業務がある方は検討してみてください。
Metaquest2で物をつかむ

# 用途
Metaquest2で手で物をつかむ動作をしたいときに必要最低限何が必要なのかを調べたい場合。
公式のプレハブ使いまわすだけなのでコードなどは一切ないです。
また必要ない作業をしたくない場合は公式のサンプルを改造するだけでいいのでこれを見なくてもいいです。
ここではコントローラーで物をつかむことはカバーしていません、がたぶんHandのところがControllerに代わるぐらいだと思うので試してみてください(他力本願)
またMetaquest2を開発に使うにあたって必要な作業は[こちらのサイト](https://framesynthesis.jp/tech/unity/oculusquest/)などを参考にしながら整えてください。
# 環境
Unity 2021.3.1f1
URP template使用
# 結果
２つの場合がありますが必要な要素は一緒になります。なので後者は時間の無駄といえば無駄です。
### 最短の方法
Player側の準備
1. InteractionRigOVR-FullSyntheticで検索をかけて見つかったものをHierarchyに追加()
1. HandGrabInstractorを検索で見つけて1->InputOVR->Hands->LeftHand->HandInteractorsLeft下におく。この時HandGrabInstractorのHandRefコンポーネントのHandをInputOVRのLeftHandに設定する。

つかまれる物の準備

適当なゲームオブジェクトにRigidbody,Grabbable,HandGrabInteractableを追加するだけ。この時RigidbodyのGravityをオフにKinematicをオンにすると見やすいです。

### 公式のサイトの流れに従う場合
公式の流れに従って開発したい場合[この公式リファレンス](https://developer.oculus.com/documentation/unity/unity-isdk-input-processing/)を見ることになると思います。InputOVRにHandを追加するところまでは公式に従ってもらえればあとは上と同じ方法で物がつかめるようになると思います。また上も同じですが手で使う動作がつかむことだけの場合はHandInteractorsLeftは必要ありません。

# まとめ
久々に記事を書く＋備忘録程度の感覚なので見づらいし多分ニーズもないんですが一応書きました。何かの機能を実装しようとやる気出して調べたらぺったんするだけが最適解の時ってすごい悲しくなりますよね。おわり。
シェルスクリプトをWindowsでWSLなしで動かす？⇒BusyBoxがあるよ！

## BusyBox for Windows

[BusyBox for Windows (BusyBox-w32)](https://frippery.org/busybox/) は [Busybox](https://busybox.net/) の Windows 移植版です。トップページを見ると、どうやら 2021 年の 10 月頃に BusyBox-w32 から BusyBox for Windows に名前が変わっているような気がします。確かにもう 32 ビットの時代ではないですからね……。でも GitHub は [busybox-w32](https://github.com/rmyorston/busybox-w32) のようですが。ちなみに 64ビット版バイナリもあります。

## これの何がすごいのか？

- インストールは実行ファイル一つをコピーするだけ。環境を汚しません。
- ash 系のシェルを改良していくつかの bash の機能が追加されたシェルが含まれています。
- シェルスクリプトでよく使うコマンド（`sed` や `awk` 等）の多くが含まれています。

最新の[プレリリース版](https://frippery.org/files/busybox/prerelease/)（busybox-w32-PRE-4727-g182e489d9.exe）に含まれているコマンド

> [, [[, ar, arch, ascii, **ash**, **awk**, base32, base64, basename, **bash**, **bc**, bunzip2, busybox, bzcat, bzip2, cal, cat, chattr, chmod, cksum, clear, cmp, comm, cp, cpio, crc32, cut, date, dc, dd, df, diff, dirname, dos2unix, dpkg, dpkg-deb, du, echo, ed, egrep, env, expand, expr, factor, false, fgrep, **find**, fold, free, fsync, ftpget, ftpput, getopt, grep, groups, **gunzip**, **gzip**, hd, head, hexdump, **httpd**, **iconv**, id, inotifyd, install, ipcalc, jn, kill, killall, less, link, ln, logname, ls, lsattr, lzcat, lzma, lzop, lzopcat, **make**, man, md5sum, mkdir, mktemp, mv, **nc**, nl, nproc, od, paste, **patch**, pgrep, pidof, pipe_progress, pkill, printenv, printf, **ps**, pwd, **readlink**, **realpath**, reset, rev, rm, rmdir, rpm, rpm2cpio, sed, seq, **sh**, sha1sum, sha256sum, sha3sum, sha512sum, shred, **shuf**, sleep, sort, split, ssl_client, stat, strings, su, sum, sync, tac, tail, **tar**, **tee**, test, time, timeout, touch, tr, true, truncate, ts, tsort, ttysize, uname, uncompress, unexpand, uniq, unix2dos, unlink, unlzma, unlzop, unxz, **unzip**, uptime, usleep, uudecode, uuencode, **vi**, watch, wc, **wget**, which, whoami, whois, xargs, xxd, xz, xzcat, yes, zcat

Windows でシェルスクリプトを動かすには WSL の他に Cygwin や msys が Git for Windows があるのですが、それらはどうしてもインストール作業が必要になってしまいます。BusyBox-w32 は Windows ネイティブのバイナリファイル一つだけなので、シェルスクリプトとともに配布するだけでユーザーの環境を汚さず動作します。

シェルスクリプトというのはシェルがあるだけでは使い物になりません。シェルスクリプトから多くのコマンドを呼び出すからです。そのためシェルを Windows に移植するだけではシェルスクリプトは動くようにならないという問題があります。Busybox は元のプロジェクトから組み込み環境向けに一つのバイナリに基本的なコマンドを全て組み込んでいるものなので、それを Windows に移植したというのは、シェルだけではなく多くのコマンドも移植したということを意味しています。

`busybox.exe` 一つあるだけで基本的なコマンドを使用するシェルスクリプトが Windows 上で動くようになります。パッケージ管理ツールはない（実際には BusyBox 版 の `dpkg` コマンドや `rpm` コマンドが移植されているようですが使えるのかよくわからない）ので、基本的ではないコマンドは含まれていませんが、有名なプログラムは Windows ネイティブで移植されていることが多いと思います。したがって必要なコマンドの Windows 版をインストールすれば、そのようなコマンドを使うシェルスクリプトも動作するようになります。

シェルスクリプトを使いたいけど WSL などをインストール出来ないから使えないといって、仕方なくバッチファイルや PowerShell を使わなければいけないなんてことはありません。シェルスクリプトで書けば Windows 上でも動かすことが出来ます。
FlexBoxメモ

## justify-content
アイテムの水平方向での配置方法を設定できます。
- flex-start: アイテムをコンテナーの左側に配置します。
- flex-end: アイテムをコンテナーの右側に配置します。
- center: アイテムをコンテナーの中央に配置します。
- space-between: 複数のアイテムをその間に等しい間隔を空けて配置します。
- space-around: 複数のアイテムをその周囲に等しい間隔を空けて配置します。

## align-items
アイテムの垂直方向での配置方法を設定できます。
- flex-start: アイテムをコンテナーの上部に配置します。
- flex-end: アイテムをコンテナーの下部に配置します。
- center: アイテムをコンテナーの垂直方向中央に配置します。
- baseline: アイテムをコンテナーのベースラインに配置します。
- stretch: アイテムをコンテナーの大きさに合うように配置します。

## flex-direction
アイテムの配置方向を設定できます。

:::note warn
flex-direction: column のときは justify-content は垂直、align-items は水平の設定に変わる
:::

- row: アイテムを行のテキスト方向に配置します。
- row-reverse: アイテムを行のテキスト方向に逆順で配置します。
- column: アイテムを上から下に向かって配置します。
- column-reverse: アイテムを下から上に向かって配置します。

## order
個別のアイテムの表示順序を設定することができます。
orderに設定した数が小さい順に並び替えられます。
※orderを明示的に設定していない場合は0と認識する
(例)
並び替え前
1 番目のアイテム: order: 2
2 番目のアイテム: order: 3
3 番目のアイテム: order: 1
4 番目のアイテム: order: 3
5 番目のアイテム: order: 1

並び替え後
3 番目のアイテム: order: 1
5 番目のアイテム: order: 1
1 番目のアイテム: order: 2
2 番目のアイテム: order: 3
4 番目のアイテム: order: 3

## align-self
個別のアイテムに対して align-itemsの設定を反映できます。

## flex-wrap
アイテムを単一行に押し込むか、あるいは複数行に折り返してもよいかを指定することができます。
- nowrap: 全てのアイテムをひとつの行に配置します。
- wrap: 溢れるアイテムを他の行へ折り返します。
- wrap-reverse: アイテムを逆順にして他の行へ折り返します。

## flex-flow
flex-directionとflex-wrapを統合したものです。
空白を挟むことで２つの設定を行えます。
`flex-flow: row wrap` = `flex-direction: row` + `flex-wrap: wrap`

## align-content
複数行の行間を設定することができます。

:::note info
align-itemsはコンテナーに含まれるアイテム全体の配置を設定するもので、align-contentは行間の余白を設定するもの
一行だけの場合はalign-cotentは何も効果がない
:::

- flex-start: 行をコンテナーの上側に詰めて配置します。
- flex-end: 行をコンテナーの下側に詰めて配置します。
- center: 行をコンテナーの中央に詰めて配置します。
- space-between: 複数行をその間に等しい間隔を空けて配置します。
- space-around: 複数行をその周囲に等しい間隔を空けて配置します。

## おすすめの学習サービス
ゲーム形式で学習できて、おすすめです。
それぞれのプロパティに関する説明も丁寧に記載されているので、これ一つでマスターできると思います。

https://flexboxfroggy.com/#ja
【個人的備忘】LicensePlist

本家とGithubが一番分かりやすい

https://medium.com/swift-column/license-plist-c0363a008c67

Run Scriptに書くやつ

if [ $CONFIGURATION = "Debug" ]; then
${PODS_ROOT}/LicensePlist/license-plist --output-path プロジェクト名/Settings.bundle
fi
GA4のサンプルデータを使ってRFM分析もどきをしてみる

## RFM分析とは？
RFM分析とは、「最新購入日（Recency）」「購入回数（Frequency）」「購入金額合計（Monetary）」を元にしてユーザーを3次元でグループ化してランク付けを行う分析手法です。ユーザーグループに応じて、マーケティング施策を打っていこうというやつです。

| 指標名 | 指標説明 |
|:-----------|:------------|
|最新購入日（Recency）| 最近購入に至ったユーザーほど優良顧客として扱う| 
|購入回数（Frequency）|購入した回数が多いユーザーほど優良顧客として扱う| 
|購入金額合計（Monetary）|購入金額の多いユーザーほど優良顧客として扱う| 


## 今回やること
BigQueryのサンプルデータでGA4のEコマースのアクセスログデータセット「[**ga4_obfuscated_sample_ecommerce**](https://developers.google.com/analytics/bigquery/web-ecommerce-demo-dataset)」を用いて、各ユーザーランクにどれくらいのユーザーがいるのかを集計する。なお、あまり込み入った分析には踏み込まず、クエリ紹介を目的とする。


## 注意点
1. サンプルデータのテーブルは2020-11-01 〜 2021-01-31の3ヶ月分のデータであるため、2021-02-01からみた最新購入日との日数を評価する。

2. サンプルデータのevent_nameに「purchase」という購入を示すイベントがあるが、このレコードに購入金額を示す「ecommerce.purchase_revenue」が必ずしも入ってるわけではなかった。今回はそれが入っているもののみを購入とみなした。

3. RFM各指標は5グループに分割し、点数を振る必要があるが、今回は意図的にランク付けするのはやや面倒なので、NTILE関数を用いて各指標点数を分割し点数を付けた。
※ランクを定義する場合、例えば最新購入日からの経過日数であれば、14日以内：5点、28日以内：4点、60日以内：3点のように振り分ける。
※NTILE関数は例えば最新購入日からの経過日数を昇順で並び替えて、同じユーザー数になるように5等分し、ユーザーを振り分ける関数である。一般にデシル分析でよく用いられる。


## クエリ
```sql
WITH mst_purchase_log AS (
    SELECT
        PARSE_DATE('%Y%m%d', event_date) AS purchase_date
        , user_pseudo_id AS user_id
        , ecommerce.purchase_revenue AS purchase_revenue
    FROM `bigquery-public-data.ga4_obfuscated_sample_ecommerce.events_*`
    WHERE ecommerce.purchase_revenue IS NOT NULL
)
, mst_user_rfm AS (
    SELECT
        user_id
        , MAX(purchase_date) AS recent_date
        , DATE_DIFF('2021-02-01', MAX(purchase_date), DAY) AS recency
        , COUNT(*) AS frequency
        , SUM(purchase_revenue) AS monetary
    FROM mst_purchase_log
    GROUP BY 1
)
, mst_user_point AS (
    SELECT
        *
        , 6 - NTILE(5) OVER (
            ORDER BY recency
        ) AS recency_point
        , 6 - NTILE(5) OVER (
            ORDER BY frequency DESC
        ) AS frequency_point
        , 6 - NTILE(5) OVER (
            ORDER BY monetary DESC
        ) AS monetary_point
    FROM mst_user_rfm
)
SELECT
    recency_point + frequency_point + monetary_point AS total_point
    , recency_point
    , frequency_point
    , monetary_point
    , COUNT(DISTINCT user_id) AS uu
    , COUNT(DISTINCT user_id) / (SELECT COUNT(DISTINCT user_id) FROM mst_user_point) AS ratio
FROM mst_user_point
GROUP BY 1, 2, 3, 4
ORDER BY 1 DESC, 2 DESC, 3 DESC, 4 DESC
```


## アウトプット
![スクリーンショット 2022-09-25 16.35.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233689/6a8cd1fe-c218-e208-b4fa-d85f48c44a8c.png)


## 結果
ここからの分析は三次元のバブルチャートでマッピング、もしくは適当な2つの指標を組み合わせて2次元で表現して、ユーザーを「優良顧客」「安定顧客」「離反離脱」「非優良顧客」等に分類していきます。
そこで
- 安定顧客を常連にするには？
- 常連離脱予兆のあるユーザーを常連に戻すには？
- 新規離脱予兆のあるユーザーを安定ユーザーにするには？

等々考えて施策を打ってきます。
ですが、今回はサンプルデータですし、そこまで踏み込みません。
分析についての詳細は [NECさんのブログ記事](https://www.nec-solutioninnovators.co.jp/sp/contents/column/20220218b.html)に詳しく書かれておりましたので、ぜひご覧ください。

一応、合計ポイントごとのユーザー数の表を乗っけておきます。
![スクリーンショット 2022-09-25 16.59.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233689/b426a28d-ad5d-5a75-837f-3a3f29160d39.png)
コマンドから管理者権限付きのWindows Terminalを起動する

# はじめに
<!-- 発端や概要を記載 -->
コマンドからWindows Terminalを起動する方法を調べたので、備忘録として記録する。

# 環境
- Windwos10 64bit

# コマンド
## 通常の起動

```powershell
wt -d パス
```

## 管理者権限付きで起動

```powershell
powershell -NoProfile -ExecutionPolicy unrestricted -Command "Start-Process wt -Verb runas -ArgumentList '-d', 'パス'"
```

![2022-09-25 16_44_38-Window.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479615/7c3146e4-a817-2e90-3552-fe1832958f4e.jpeg)


# 参考にした記事
[Windows ターミナルのコマンド ライン引数 \| Microsoft Learn](https://learn.microsoft.com/ja-jp/windows/terminal/command-line-arguments?tabs=windows)
GiteaをAWSでなるたけ手抜き運用

趣味でやってるクローズドな開発用にGitea立ててみました

# 要件

- Gitリモートリポジトリのオープンなやつクローズドなやつ両方持ちたい
- イシューとかWikiとかはクローズドで書きたい
- インフラの面倒なことはなるべく手抜きで

# うまくいった構成

[Gitea](https://gitea.io/ja-jp/)をこんな感じで構成してみました

* HTTP/HTTPSは、ALB経由でサービスする
  * ALBをロードバランサーとしてはぜんぜん使ってないのですが（ターゲットグループにEC2 1台ずつしかいない）
  * リバースプロキシ的に使えて便利なのです
  * あと、証明書も良きに計らってくれるのがとても便利
* gitプロトコルは、SSH on SSMで利用する
  * プル・プッシュするひとごとにIAMユーザーが必要ですが
  * SSHすら開けなくてよいのでとてもセキュア

## Route53

giteaのトラフィックをALBへ流すレコードを追加する。

* レコード名 : gitea.my.domain
* レコードタイプ : A
* エイリアス : はい
* 値 : (ALBを指定する)

## ALB

もともと、HTTPはHTTPSへリダイレクトする設定にしてます。
以下のルールを追加。

* IF
  * ホストが gitea.my.domain
* THEN
  * 転送先: gitea-tg

## ターゲットグループ

* Name: gitea-tg
* Port: 3000
* 後述のEC2インスタンスをターゲットに入れておく

## EC2

- AWS EC2 t3.micro 
- ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-20220609
- セキュリティグループ
  - インバウンドで、ALBのセキュリティグループに対して、3000を許可
- ロール
  - SSMを許可するロールを設定

/etc/gitea/app.ini (抜粋)
```
[server]
SSH_DOMAIN       = gitea.my.domain
DOMAIN           = gitea.my.domain
HTTP_PORT        = 3000
ROOT_URL         = https://gitea.my.domain/
DISABLE_SSH      = false
SSH_PORT         = 22
LFS_START_SERVER = true
```

## 開発環境の設定

こんな感じで設定して、gitプロトコルでプル・プッシュができました。
aws cliのインストールも必要です。

~/.ssh/config
```
Host gitea.my.domain
        IdentitiesOnly  yes
        User my_user
        IdentityFile ~/.ssh/my_user_name
        HostName        (インスタンスid)
        Port 22
        ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
```


# ハマったこと

## Amazon Linux だとうまくいかなかった

Gitea起動するしWebは使えたのですが、gitでのプル・プッシュがうまく動きませんでした。
とってくるバイナリが違ったのかも。

## NLB よくわからなかった

NLBを使えば、HTTP/HTTPS以外も通せるらしいのですが。
ちょっと見にいってみて「わからん？」と、勉強不足な感じ。
既存サービスでALBを使ってもいるので、今回の構成にしました。


## Too many authentication failures

なんか色んなキーで繋ごうとトライして出るぽい？
IdentitiesOnly  yes を指定したら解消しました。


## SSHキーのタイプ指定が必要だった

手癖でなにもオプション付けずにssh-keygenしたら認証はねられました。
指定のタイプで改めてキー生成して登録したら通りました。
（Giteaの説明、Githubのガイドをご覧くださいになってて、いーのかしらって思ったケド）


# 所感

Giteaだけなら、Elastic IPとってRoute53から流すだけにするとお安いですが。
他のサービスもホストしたいのと、証明書の管理が忘れたころにやってきて面倒すぎるので、手間暇のコストと思ってALB使ってます。

# 参考にさせて頂いたサイト

ありがとうございました、大変助かりました！

https://qiita.com/xex-ken-xex/items/1040793b05b69d11fbae

https://mebee.info/2022/06/13/post-68721/

https://hyp.llc/tips/too-many-authentication-failures/
Firebase Hostingを使ってWebサイトのデプロイしてみた。

<h2>初めに</h2>
今回はFirebase Hostingを使ってWebサイトをデプロイしたいと思います。
<h2>1. Firebase Hostingの設定</h2>
FirebaseコンソールからHostingを選択し、「始める」ボタンをクリック。

![スクリーンショット 2022-09-26 9.06.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2854023/88ba5ff5-a57d-6eb6-8c90-34a88b6ab395.png)

<h3>1. Firebase CLIのインストール</h3>

```
npm install -g firebase-tools
```
Firebaseコンソール画面で「次へ」ボタンをクリックしてください。

<h3>2. Firebase Hostingの設定</h3>

<p>1. 任意のディレクトリを用意します。</p>

```
mkdire 任意のディレクトリ
cd 任意のディレクトリ
```
<p>2. Googleへのログイン</p>

```
firebase login
```
上記コマンド入力後、以下の内容が表示されるのでYを入力してEnterをクリック。
```
? Allow Firebase to collect CLI and Emulator Suite usage and error reporting inf
ormation? 
```
Enterをクリック後Googleのログイン画面に遷移するので、アカウントを選択する。

ログインに成功すると以下の内容が表示されます。
```
Success! Logged in as xxxxxx@gmail.com
```
![スクリーンショット 2022-09-25 15.57.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2854023/1b9bf567-8a8f-f66b-8dc3-281b7f7a1bef.png)

:::note info
既にログイン済みのユーザーは以下の内容が表示されます。
Already logged in as xxxxxx@gmail.com
:::

<p>3. プロジェクトの初期化</p>

```
firebase init
```
コマンド入力後以下の内容が表示されます。十字キーとスペースキーを使って、Hostingを選択してください。
```
? Which Firebase features do you want to set up for this directory? Press Space 
to select features, then Enter to confirm your choices.(Press <space> to select
, <a> to toggle all, <i> to invert selection, and <enter> to proceed)

選択する項目だけ表示させています。
◯ Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub
Action deploys
```
対象とするプロジェクトは[Use an existing project] を選択してください。
その後以下の手順で入力していってください。
```
? What do you want to use as your public directory? Enter
? Configure as a single-page app (rewrite all urls to /index.html)? N
? Set up automatic builds and deploys with GitHub? N
```
全ての項目入力後以下の内容が表示されていたら初期化完了です。
```
✔  Firebase initialization complete!
```
Firebaseコンソール画面で「次へ」ボタンをクリックしてください。

:::note warn
firebase init入力後エラーが表示される場合は
一度firebase logoutを実行後、再度firebase loginを実行してください。
firebase loginで既にログインされていた方はエラーが発生しやすいです。
:::

<h3>3. デプロイする</h3>
初期化完了後、任意のディレクトリにpublicフォルダが生成されています。<br>
publicフォルダの中にはindex.htmlが自動生成されているので、<br>
公開したいWebサイト(index.html)に置き換えを行ってください。

その後、以下のコマンドを実行

```
cd public
firebase deploy
```
以下のメッセージが表示されたらデプロイ完了です。
Firebaseコンソール画面で「コンソールへ進む」ボタンをクリックしてください
```
✔  Deploy complete!
Project Console: https://console.firebase.google.com/project/.....
Hosting URL: https://xxxxxx.web.app
```
Hosting URLがWebサイト公開URLになります。

:::note warn
index.html置き換え後デプロイしても表示画面が変更されない時は、一度キャッシュを削除してみてください。
:::

<p>非常に簡単にWebサイトを公開することができるので、ぜひ利用してみてください</p>
macとswitchとdiscordを繋いで動画音声配信する

しんどすぎた・・・
すぐできるだろうとたかを括っていたが、半日ほど試行錯誤してようやく満足いく形にできた。
おそらく、windowsではここまでの苦労はなかったであろう。。
macのセキュリティの関係で、いろいろ設定しないとPC音声が配信できない。しんどすぎる。
同じことをしようとして心が挫けそうなあなたに捧ぐ、本記事をご参照ください。

# 環境
1. <font color="blue">mac</font>
2. <font color="blue">キャプチャーボード</font>
　私はこれを使っています
　<a href="https://item.rakuten.co.jp/archss/2642-001368/?scid=af_pc_etc&sc2id=af_113_0_10001868&icm_agid=135083843412&gclid=Cj0KCQjw1bqZBhDXARIsANTjCPIk5m0NHfEqN4NBxi8YVYHACEKerJZ_KLh8c9elke52fDikdw6xB-saAsEVEALw_wcB&icm_acid=255-776-8501&icm_cid=15280804517&iasid=wem_icbs_">TreasLin USB3.0 HDMI ビデオキャプチャーボード</a>
3. <font color="blue">Nintendo Switch</font>

# macにインストールするもの
1. <font color="blue">OBS</font>(映像キャプチャソフト)
2. <font color="blue">LadioCast</font>(サウンドキャプチャ)
3. <font color="blue">Blackhole</font>(仮想オーディオデバイス)ダウンロードは<font color="red">BlackHole 2ch</font>(なんでもいいらしいけど)
4. <font color="blue">discord</font>(検証用にmacとは別の端末にそれぞれ別アカウントで入れる、iOSなど)

　まずはmacに各種インストールしてください。
　インストール自体に難しいところはないと思うので、省きます。
　(後日追加するかも)

# discord
　はじめにdiscordの設定をします。(再起動が必要なため)
　これはこちらの記事が参考になりました。
　<a href="https://note.com/mojibake_12/n/n4adb307ab2b1">【初心者向け】discord 画面共有時の 音声共有の方法 for Mac M1</a>
　記事ではM1のmacとありますが、intelのmacでも同様の設定が必要でした。
　これらの設定が終わったら、念の為discordで音声配信ができるか確認します。
　discordにログインし、部屋に入ってScreenを押下
<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2436967/c1d27a8b-bcf3-99b5-ad50-a6280f2212ed.png">
ブラウザでテキトーなyoutubeを開き(音が出てるものならなんでもOK)
別端末で音声が共有されているか確認する

# LadioCast
inputを<font color="blue">MiraBox Video Capture</font>に
outputを<font color="blue">BlackHoke 2ch</font>にする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2436967/3ef74d47-27ba-e2de-005a-905c26c0c748.png)

# OBSを起動する
その際、<font color="blue">LadioCastは並行して起動し続ける</font>必要あり。
OBSにて音声を配信する際は、先にLadioCastを起動する必要があるみたい。

OBS Studioより[Preferences]を開く
<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2436967/121fc913-29e5-1d32-dafa-0d4ddc633950.png">

[音声]より[デスクトップ音声]を[BlackHole 2ch]にして[OK]押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2436967/0afda92c-bc61-df26-e668-5b268260e493.png)

ソースより[映像キャプチャ]のコンテキストメニュー(右クリック的なやつ)を表示し
[ウィンドウプロジェクター(ソース)]を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2436967/ffe8ea4b-1c09-86d7-36b1-c3b6cfa5f5d5.png)
これをdiscordで共有します。
すると、映像と同時に音声も出力されるようになってます。
AxiosからMultiPartFileをSpringBootで受け取る

シンプルなミニマムコードが見つからなかったので備忘録に。。
初めての記事なのでなにか問題があれば補足よろしくお願いします。

## 1ファイルを受け取る場合
### フロントエンド
```sample.html
<input type="file" id="in_file">
<button onclick="onclick()">post</button>
```

```sannple.js
function onclick() {
    // input file から指定したファイルを取り出し。
    const in_file = document.getElementById('in_file');
    const file = in_file.files[0];

    // FormDataにappendする
    const formData = new FormData();
    formData.append('file', file);

    // header情報を指定
    const headers = { "content-type": "multipart/form-data" };
    // 事後処理(.then)・エラー処理(.catch)はご自由に
    axios.post('/postimg', formData, { headers });
}
```



headersは指定しなくても動いた。よくわからん。
ここが肝と謳っているいる記事もあったため、無いと後々困るかも。

発火はボタンからしているため、`getElementById`を使っているが、`onchange`の`event.target`から取り出してもよし。
とにかく`input type="file"`の要素からfile情報が取り出せればよい。

### バックエンド
SpringBoot側での受け取り。
```PostController.java
@RestController
public class PostController {
    @PostMapping("postimg")
    public void postimg(@RequestPart("file") MultiPartFile file) {
        System.out.println(file.getOriginalFilename());
    }
}
```
これでinputから選んだファイル名が表示されるはず。
`@RequestPart("file")`ではなく`@RequestParam("file")`でも動くには動いた。

### 受け取ったファイルを保存する場合。
これは.png受け取りの場合。
```output.java
@RestController
public class PostController {
    @PostMapping("postimg")
    public void postimg(@RequestPart("file") MultipartFile file) {
        System.out.println(file.getOriginalFilename());
        try {
    		File outfile = new File("test.png");
    		copyInputStreamToFile(file.getInputStream(), outfile);
    	} catch (IOException e) {
    	}
    }

	private static void copyInputStreamToFile(InputStream inputStream, File file) throws IOException {
		try (FileOutputStream outputStream = new FileOutputStream(file)) {
			int read;
			byte[] bytes = new byte[1024];
			while ((read = inputStream.read(bytes)) != -1) {
				outputStream.write(bytes, 0, read);
			}
			// commons-io
			// IOUtils.copy(inputStream, outputStream);
		}
	}
}
```
参考 https://mkyong.com/java/how-to-convert-inputstream-to-file-in-java/
もっと簡単なやり方あったら教えてください。


## 複数ファイルを指定・送信する場合。
### フロントエンド
```sample.html
<input type="file" id="in_file" multiple>
<button onclick="onclick()">post</button>
```

```sannple.js
function onclick() {
    // input file から指定したファイルを取り出し。
    const in_file = document.getElementById('in_file');
    
    // FormDataにappendする
    const formData = new FormData();
    
    for(let i = 0; i < in_file.files.length; i++) {
        formData.append('files', in_file.files[i]);
    }
    
    // header情報を指定
    const headers = { "content-type": "multipart/form-data" };
    // 事後処理(.then)・エラー処理(.catch)はご自由に
    axios.post('/postimg', formData, { headers });
}
```

FormDataの同じ名前(`'files'`)にappendすればよいらしい。

### バックエンド
Spring側。
```PostController.java
@RestController
public class PostController {
    @PostMapping("postimg")
    public void postimg(@RequestPart("files") MultipartFile[] files) {
        for(MultipartFile file : files) {
            System.out.println(file.getOriginalFilename());
        }
    }
}
```

引数の型を配列にすればよいだけ。
Listでも受け取れる。

以上。
[図で見てわかる] Flexbox覚え書き1 入れ子関係・親子関係

# 背景
CSSでFlexboxを入れ子にして使っていたら下の２点について混乱した。
* flexプロパティは親要素に設定するのか子要素に設定するのかどっちなのか
* 結局どこに`display:flex`や`flex:auto`を書けばいいのか

# 図にしてみた
何をどこに書けばいいかを図にしてみた。
プロパティが`flex:auto`のみの場合を考える。
### 1. 基本
* 親要素
  * 子要素に対する`display: flex`
* 子要素
  * 親要素に対する`flex:auto`などのプロパティ
  
![flexの入れ子.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2508186/02ecdbe6-4edd-d50f-5350-b278e240a286.png)

### 2. 親要素-子要素、子要素-孫要素の関係でflexを使う場合。
* 親要素
  * 子要素に対する`display: flex`
* 子要素
  * 親要素に対する`flex:auto`などのプロパティ
  * 孫要素に対する`display: flex`
* 孫要素
  * 子要素に対する`flex:auto`などのプロパティ

![flexの入れ子 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2508186/b2aee802-7f74-468b-11a0-c3d8e7f8d6e9.png)

# 結論
`display: flex`の中に`display: flex`を入れ子にして書こう

### 参考
progateのレッスンのFlexbox編にとてもわかりやすくまとまってました
https://prog-8.com/lessons/html/study/4
Next.jsでAPIからデータを取得する

# はじめに
next.jsのアプリケーションから自分が作成したapiサーバー(Golang)からデータを取得する処理を記載するために調べたことをまとめていきます。
個人用のメモとして残します。

# 使用技術
next.js
axios
React react-query 

# 調べたこと
## 1.axios
axiosとは、apiの通信で使用するもの。fetch関数のようなもの。
[vue.jsを使ってaxiosを学ぶ](https://reffect.co.jp/vue/vue-axios-learn#:~:text=%E3%81%AE%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95-,axios%E3%81%A8%E3%81%AF,%E8%A1%8C%E3%81%86%E3%81%93%E3%81%A8%E3%81%8C%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82)

･axiosの基本を確認できるサイト
[Getting Started with Next.js](https://docs.strapi.io/developer-docs/latest/developer-resources/content-api/integrations/next-js.html#create-a-next-js-app)
[axiosの使い方まとめ (GET/POST/例外処理)](https://www.sukerou.com/2019/05/axios.html)
[【Typescript】いろいろな型の指定方法：Axios編
](https://maasaablog.com/development/typescript/3455/)


･参考にしたコード
[【React / TypeScript】axios と QiitaAPI を使ったサンプルアプリ](https://qiita.com/tkmd35/items/6ab8c4e6e37178f81472)

･その他
[【JavaScript】初心者にもわかるPromiseの使い方](https://techplay.jp/column/581)

## 2. React react-query 
サーバーから取得したデータをキャッシュできる。データの管理が便利。

* postとdelete
[useMutation](https://react-query-v3.tanstack.com/reference/useMutation)
[React Queryを使いこなすために試したこと](https://zenn.dev/himorishige/articles/76e903bc5a1aa2)

## axiosの戻り値について
[【TypeScript】Axiosのリクエストとレスポンスに型をつける](https://zenn.dev/mkt_engr/articles/axios-req-res-typescript)
[【Typescript】axiosのREADME読んでみた Part4【React】](https://nomurabbit.hatenablog.jp/entry/20211227/1640532600)
[Typescript】いろいろな型の指定方法：Axios編
](https://maasaablog.com/development/typescript/3455/)

･React react-queryの基本を確認できるサイト
[初めてReact Queryを使う人のため設定方法と動作の理解](https://reffect.co.jp/react/react-use-query)
[【React】React Queryの基礎知識をまとめました(Stale, Cache, Prefetchingなど)](https://qiita.com/suzuki0430/items/fbcd0ce8ee10f91e3d92)

･ nextでreact-queryを使用するためには
[Next.js とReact Query でデータを表示したり更新する](https://tech.aptpod.co.jp/entry/2022/08/05/100000)
[Next.jsでuseQueryを使う方法を教えてください](https://qiita.com/ike81818/questions/7ef0455e6a1ed9bce5a2)

## 3. ディレクトリ構成で参考にしたコード
以下サイトは少々むずかしかったので、
簡略化して実装しました。

https://github.com/alan2207/bulletproof-react
GitHub PagesでGoogle検索に表示させたい

少し前にGitHub Pagesでサイトを公開したのですが、Google検索にどうしても引っかからない。
URL直接だとアクセスできますが、やはりGoogle検索で引っかかってほしいので対応することにした。

# 必要な作業
以下、2点の作業をするとGoogle検索に表示される。
- Google Search Consoleに登録
- サイトマップの登録

Google Search Consoleに登録に関しては参考サイトで十分だと思うので省略します。
サイトマップ登録については、直ぐに理解できなかったのでメモ。

# サイトマップの登録
どうやらGitHubには**Jekyll**という静的サイトジェネレータが備わってるらしく、その機能を使ってサイトマップを作成できるみたい。

私はhtml/cssをホスティングするだけの機能と思っていたので、その辺りの前提を知らず何すれば良いのかわからなかったです。

## _config.yml作成
まず以下のファイルをリポジトリのルートディレクトリに配置しコミット&プッシュ。

~~~yml:_config.yml
plugins:
  - jekyll-sitemap
~~~

そうするとリポジトリには、_config.ymlが追加されるだけですが、サイトの方に**sitemap.xml**が自動生成されます。
以下URLで確認可能。xmlファイルが表示されれば作成成功。
**https://{ユーザー名}.github.io/{リポジトリ名}/sitemap.xml**

## sitemap.xmlをGoogleに送信
次にGoogle Search Consoleのサイトマップにアクセスし、自動作成されたsitemap.xmlをGoogleに送信します。
ステータスが「成功しました」になってれば完了！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558865/0ed50826-bf6b-9f14-f970-6c777972a8e9.png)

数日待てばGoogle検索に表示されます^^


# 参考
https://www.bedroomcomputing.com/2020/04/2020-0408-googleconsole/
https://netchira.github.io/blog/githubpages/SEOsono1.html
http://faster-than-the-sol.blogspot.com/2020/10/github-listing.html
API Gateway + LambdaのAPIにIAM認証で署名付きリクエストを送る（javascript, typescript）

# 概要

APIGatewayのREST APIを使って構築したweb APIをIAM認証（accesskeyとsecretkeyを使った認証）で署名付きのリクエストを送信するサンプル。

参考にさせていただいた記事
* [API GatewayでAPIにIAM認証をかけて、Node.jsでSigV4署名ヘッダを作成してリクエストしてみる](https://dev.classmethod.jp/articles/api-gateway-iam-authentication-sigv4/)
* [AWS - Lambda function URLs を IAM 署名付きでリクエストしてみる](https://zenn.dev/umatoma/articles/d04d8417fa2e70)

IAMは対象のLamda関数のARNを指定した、 `lambda:InvokeFunctionUrl` のアクションのみを許可したユーザを作成しています。

javascriptとtypescriptのケース両方使うことがあるので、自分用のメモとして参考にさせていただいた記事のコードを少し書き直してます。

# 実装

## javascript

```bash
$ npm install --dev aws-sdk axios
```

```javascript
const core = require('aws-sdk/lib/core');
const aws = require('aws-sdk');
const axios = require('axios');

// アクセスキーとシークレットアクセスキーを設定
const accessKey = 'xxxxxxx';
const secretKey = 'xxxxxxx';
const credential = new aws.Credentials(accessKey, secretKey);


function main() {
  const serviceName = "execute-api";

  const url = "https://xxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/";

  const options = {
    url: url,
    headers: {}
  };

  const parts = options.url.split("?");
  const host = parts[0].substr(8, parts[0].indexOf("/", 8) - 8);
  const path = parts[0].substr(parts[0].indexOf("/", 8));
  const querystring = parts[1];
  const data = {
    /* payload */
  };

  const now = new Date();
  options.headers.host = host;
  options.pathname = () => path;
  options.methodIndex = 'post';
  options.search = () => querystring ? querystring : "";
  options.region = 'ap-northeast-1';
  options.method = 'POST';
  options.body = JSON.stringify(data);

  const signer = new core.Signers.V4(options, serviceName);

  signer.addAuthorization(credential, now);

  axios.post(url, data, options).then((r) => {
    console.log(r);
  }).catch((e) => {
    console.error("failed to request: ", e.response.status, e.code, e.response.data);
  });
}

main();

```

## Typescript

```typescript
import axios from 'axios'
import { Credentials } from 'aws-sdk'
import { SignatureV4 } from '@aws-sdk/signature-v4'
import { Sha256 } from '@aws-crypto/sha256-js'
import { HttpRequest } from '@aws-sdk/protocol-http'

const main = async () => {
  const accessKey = 'xxxxxxxxx'
  const secretKey = 'xxxxxxxxx'
  const creds = new Credentials(accessKey, secretKey)

  const serviceName = 'execute-api'
  const url =
    'https://xxxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/'
  const parts = url.split('?')
  const host = parts[0].substr(8, parts[0].indexOf('/', 8) - 8)
  const path = parts[0].substr(parts[0].indexOf('/', 8))
  const data = {
    /* payload */
  }

  const req = new HttpRequest({
    headers: {},
    hostname: host,
    method: 'POST',
    path: path,
  })

  const signer = new SignatureV4({
    credentials: creds,
    region: 'ap-northeast-1',
    service: serviceName,
    sha256: Sha256,
  })
  const signedHttpRequest = await signer.sign(req)

  try {
    const r = await axios.post(url, data, signedHttpRequest)
    console.log(r)
  } catch (e: any) {
    console.error(e)
  }
}

main()
```
GoでWebサーバーを作成する

# はじめに
Goでwebサーバーを作成するときに調べたことをまとめます

# プログラミングの基本
･オブジェクト指向
カプセル化、継承、ポリモーフィズム
[オブジェクト指向とは？誰でもわかるようにやさしく解説](https://www.sejuku.net/blog/5973#i)

･コンストラクタ
クラスをnew時点で実施されるもの

･インターフェース
持つべき関数を定義する
[インターフェースとは？](https://www.gixo.jp/blog/5159/#i-2)

･dto
>DTOとは、オブジェクト指向プログラミングでよく用いられる典型的なオブジェクトの設計パターン（デザインパターン）の一つで、関連するデータを一つにまとめ、データの格納・読み出しのためのメソッドを定義したオブジェクトのこと。

[IT用語辞典　DTO 【Data Transfer Object】](https://e-words.jp/w/DTO.html)

# Goの文法で調べたこと

･Goでのコンストラクタの使用方法
[Goでのコンストラクタの定義](https://qiita.com/Sekky0905/items/10c8ae9cee719d66fa84)

･Goのレシーバとは
[[Golang] 値レシーバとポインタレシーバ](https://tech.notti.link/4810dcb)

# net/httpsを用いてWebサーバーを立ち上げる

[GoでHTTPサーバー入門 [Handler][HandleFunc][ServeMux]](https://noumenon-th.net/programming/2019/09/12/handler/)

# JSONを返すapiを作成
[[初心者向け] Golang でシンプルな JSON API を作る](https://zenn.dev/tatsurom/articles/golang-simple-json-api)
【CSS】modal 擬似クラスが主要なブラウザで使えるようになったので試した。

## 概要
:modal 擬似クラスが主要なブラウザで使用できるようになったので、試してみた。

## 環境

macOS: Monterey
ver: 12.3.1

---

## 所感
今まで JavaScript 等で modal は対応していたが、:modal 擬似クラスが主要ブラウザで対応したので、便利になればと思い試してみた。（あまり調べてないのでいまいちうまく扱えなかった...）

## 使い方
2 種類の要素が使用可能

-   showModal メソッドを使用する dialog 要素
-   フルスクリーン モードになっている要素

今回、showModal メソッドを使用する dialog 要素の方のみ試した。
おおよそはコードを見ていただければ分かるかと思いますので割愛。（正直今までと、労力はあまり変わらないような..?）

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="xxjPEGQ" data-user="yuto_hyrax" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/yuto_hyrax/pen/xxjPEGQ">
  Untitled</a> by Yuto Maeda (<a href="https://codepen.io/yuto_hyrax">@yuto_hyrax</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

次はコンテナクエリと:has疑似クラスも試してみようかなと。

### 参考
-   [mdn web docs](https://developer.mozilla.org/en-US/docs/Web/CSS/:modal 'mdn web docs')
PythonでJsonの差分を確認する（備忘録

<h5>前置き</h5>
使用したのは標準ライブラリのdifflib。

2つのJsonファイルの差分を確認するPythonを作成しました。

微量な差分であれば今回のPythonは使えるかもしれません。
よって使う状況に応じ、差分を確認しやすいようどうぞご自身でPythonを書き換え下さい。

今回は自分への備忘録として。またこれがどなたかの参考に少しでもなれば幸いです。
長い前置きもここらで。
では。

---
<h5>差分を確認するJson</h5>

```sample1.json
{
    "Sample": {
        "Sample_A": [0, 1, 2],
        "Sample_B": {
            "a": 1,
            "b": 2,
            "c": 3,
            "d": ["a", "b", "c"]
        },
        "Sample_C": "HogeHoge"
    }
}
```


```sample2.json
{
    "Sample": {
        "Sample_A": [0, 1, 0],
        "Sample_B": {
            "a": 1,
            "b": 2,
            "c": 3,
            "d": ["a", "b", "ccc"]
        },
        "Sample_C": "Hoge"
    }
}
```

---
<h5>差分を確認するPython</h5>

```check_diff.py
import sys
import json
import difflib
import pprint as pp

#JsonファイルをList型に変換する
def conv_json_to_list(src_json):
    #まずjsonファイルを読み込み、dict変換
    with open(src_json, "r") as f:
        src_to_dict = json.load(f)
    
    #pprint.pformatによって dict型 -> String型 に変換
    #sort_dicts = False　にすることで、pprintによるformat後も、既存の辞書の順番を維持する。
    src_to_str = pp.pformat(src_to_dict, sort_dicts = False)
    #改行を区切りに String型 -> List型 に変換する
    src_to_list = src_to_str.split("\n")
    return src_to_list

#2つのJsonの差異を確認し、標準出力
def display_difference(src_json1, src_json2):
    #2つのJsonをList化し、差分を確認。
    diff_result = difflib.ndiff(conv_json_to_list(src_json1), conv_json_to_list(src_json2))
    #差異を標準出力
    for line in diff_result:
        if line[0:1] == "-":
            print("Src1: " + line)
        elif line[0:1] == "+":
            print("Src2: " + line)
        elif line[0:1] == "?":
            print("Diff: " + line)

if __name__ == "__main__":
    src_json1 = sys.argv[1]
    src_json2 = sys.argv[2]
    display_difference(src_json1, src_json2)

```
---

<h5>実行結果</h5>

```$ python check_diff.py sample1.json sample2.json```

```
Src1: - {'Sample': {'Sample_A': [0, 1, 2],
Diff: ?                                ^

Src2: + {'Sample': {'Sample_A': [0, 1, 0],
Diff: ?                                ^

Src1: -             'Sample_B': {'a': 1, 'b': 2, 'c': 3, 'd': ['a', 'b', 'c']},
Src2: +             'Sample_B': {'a': 1, 'b': 2, 'c': 3, 'd': ['a', 'b', 'ccc']},
Diff: ?                                                                   ++

Src1: -             'Sample_C': 'HogeHoge'}}
Diff: ?                          ----

Src2: +             'Sample_C': 'Hoge'}}
```
---
このように差分があるところが「^, -, +」等で表記されます。

詳しくは公式Documentをご参考ください↓
https://docs.python.org/3/library/difflib.html

以上でした〜！
補助記憶装置

# 問題３の気づき
平均アクセス時間を求める問題だった。
平均シーク時間と平均サーチ時間とデータ転送時間を足し合わせたものだ。
平均シーク時間は20ms
平均サーチ時間は一回転する時間の２分の1になる。
なので
一回転をする時間を求める。
その後に２分の位置をする。
データ転送時間は１トラックあたりの記憶容量は、１トラックでそれだけのサイズを読み込むことができることを意味する。
１トラックなので一回転になることも忘れないようにする。
つまり
記憶する部分は一回転より小さい場合
読み込む対象に記憶容量で割ればいい。
そうして一回転の時間をかけると読み込む時間がもとまる。

# 問題４の気づき
## ブロックの記憶容量を求める
一つのブロックにレコードが２０含まれている。
これで１ブロックの記憶容量が求まる。

## １トラックに格納できるブロック数
１トラック当たりの記憶容量を１ブロック当たりの記憶容量で割る。
すると１トラック幾つのブロックがあるかを求めることができる。

## 各対象データのブロック数
対象のデータサイズをブロック化因数で割る。
すると対象のデータを幾つのブロックで読み込むことができるかが求まる。

## 対象データを読み込むことができるトラック数
必要なブロック数が求まったのでそれから一周分で割ると求まる。
### ブロック化因数とは？
1つのブロックに含まれるレコードの数のことである。
出典 https://www.weblio.jp/content/%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF%E5%8C%96%E5%9B%A0%E6%95%B0#:~:text=%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF%E5%8C%96%E5%9B%A0%E6%95%B0%E3%81%A8%E3%81%AF%E3%80%811%E3%81%A4%E3%81%AE%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF%E3%81%AB,%E3%81%8C%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF%E9%95%B7%E3%81%AB%E3%81%AA%E3%82%8B%E3%80%82

### ブロック間隔とは？
ブロックとブロックの間にある、データが記録されない領域のことである。
出典 
https://www.weblio.jp/content/%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF%E9%96%93%E9%9A%94#:~:text=%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF%E9%96%93%E9%9A%94%E3%81%A8%E3%81%AF%E3%80%81%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF,%E3%83%87%E3%83%BC%E3%82%BF%E3%81%8C%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BE%E3%82%8C%E3%82%8B%E3%80%82

# 関連記事
https://qiita.com/masatom86650860/items/9641b746dd165d1a3491

# 出典
https://gihyo.jp/book/2022/978-4-297-12375-8
Vue.js watchプロパティ

豚野郎です。

今回はVue.jsのwatchプロパティについて書いていきます。
functionを書く方法と、functionを省略する方法があります。
参考：https://prograshi.com/language/vue-js/what-are-handler-deep-and-immediate-in-watch/

今回はfunctionを省略した方法を書いていきます。

初回に書いた双方向データバインディングはこちら↓
https://qiita.com/pig_buhi555/items/a3ad0e8f7a13c6d49234


## 1. 普通に使う場合
watchプロパティはデータの中を監視します。
そのため、データに変化があった時に処理が走ります。

以下の例の場合、sampleとテキストボックスに入力すると
「sampleと入力しています」と表示されます。

```js/main.js
(function() {
    'use strict';

    let vm = new Vue({
        el: '#app',

        // モデルにデータを保持
        data: {
            sample: 'test',
        },

        watch: {
            // sampleに何らかの変更があった場合
            sample(text) {
                if (text == 'sample') {
                    var sampleText = document.getElementById('sample_text');
                    sampleText.textContent = 'sampleと入力しています';
                }
            }
        },
    });
})();
```


```index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Vue</title>
    <link rel="stylesheet" href="css/styles.css">
</head>
<body>
    <div id="app" class="container">
        <input type="text" v-model="sample">
        {{ sample }}
        <div id="sample_text"></div>
    </div>
   <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script src="js/main.js"></script>
</body>
</html>
```

sample(text, old)に第二引数を入れれば、変更前の値を入れることもできます。
(この場合、old)


## 2. handlerを使う場合
ネストしたデータの変更を検知する際には、以下のように記載します。
(あまりいいサンプルソースではありませんが、お許しください・・・・)

以下の例では、3つのテキストボックスのどれかに「sample」と記載された時に
「sampleと入力しています」と表示されます。

```js/main.js
(function() {
    'use strict';

    let vm = new Vue({
        el: '#app',

        // モデルにデータを保持
        data: {
            samples: [
                {text: 'sample1'},
                {text: 'sample2'},
                {text: 'sample3'},
                ],
            },

        watch: {
            // sampleに何らかの変更があった場合
            samples:{
                handler(text) {
                    var sampleText = document.getElementById('sample_text');
                    if (text[0]['text'] == 'sample' || text[1]['text'] == 'sample' || text[2]['text'] == 'sample') {
                        sampleText.textContent = 'sampleと入力しています';
                    } else {
                        sampleText.textContent = '';
                    }
                },
                deep: true
            }
        },
    });
})();
```

```index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Vue</title>
    <link rel="stylesheet" href="css/styles.css">
</head>
<body>
    <div id="app" class="container">
        <div v-for="(sample, index) in samples">
            <input type="text" v-model="sample.text">
            {{ sample.text }}
        </div>
        <div id="sample_text"></div>
    </div>
   <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script src="js/main.js"></script>
</body>
</html>
```

deep: true：ネストされた値の変更も検知します。
immediate: true：初回読み込み時にhandlerが呼ばれます。
Campaign Memberのまとめ


+ [Campaign Member関係の数式](https://qiita.com/Keiji_otsubo/items/4175cdce138e980eb8de)
+ [CampaignのCampaignMemberRecordTypeIdの不思議な挙動](https://qiita.com/Keiji_otsubo/items/4175cdce138e980eb8de)
+ [Campaign member tracking](https://trailhead.salesforce.com/en/trailblazer-community/feed/0D54S00000Jdm8n)
git-secretsでコミットができなくなった場合の対処法

### 環境
ソースツリー

### 概要
git-secretsによって、コミットできなくなった場合の対処法の記事はたくさんあるが、
それでは対処できなかったので、備忘録として残しておく。今回は、一旦git-secretsを完全に取り除いてコミットさせるようにする。

### エラー内容
```
git: 'secrets' is not a git command. See 'git --help'.
```

## 解決手順
### ①git-secretsをアンインストールする。
```
$ brew uninstall git-secrets
```
これでコミットできるようになったかと思いきや、またしても以下のエラーが出る。
```
git: 'secrets' is not a git command. See 'git --help'.
```
調べていくうちに、各リポジトリの「.git/hooks」にある「commit-msg, pre-commit, prepare-commit-msg」の3つを消さなければいけないらしい。

## ② 削除する
該当のリポジトリに移動する。
```ruby:まずはviでファイルの中身を確認する
[*****@*****: (master +)リポジトリ名]$　vi .git/hooks/
```
開いてみると、commit-msg*　とpre-commit*とprepare-commit-msg*の3つが確認できた。

```ruby:該当のファイルを削除する
[*****@*****: (master +)リポジトリ名]$ rm -f .git/hooks/commit-msg*
```
```ruby:該当のファイルを削除する
[*****@*****: (master +)リポジトリ名]$ rm -f .git/hooks/pre-commit*
```
```ruby:該当のファイルを削除する
[*****@*****: (master +)リポジトリ名]$ rm -f .git/hooks/prepare-commit-msg*
```

私の場合、上記の作業でコミットできるようになった。
FlutterのunittestをgithubActionsにて実行してみた

# 結論
ymlファイルに書くのは一旦これで大丈夫そう
タイミング等は各々プロジェクト等に合わせて変更してください
githubactionsの公式ドキュメントも確認してみてください

https://docs.github.com/ja/actions

```dart.yml
name: Dart
on:
  push:
    branches: [ "master" ]
  pull_request:
    branches: [ "master" ]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Install Flutter
        uses: subosito/flutter-action@v2
        with:
          flutter-version: ${{ env.FLUTTER_VERSION }}
      - name: PubGet
        run: flutter pub get
      - name: Run tests
        run: flutter test


```

# Setup

githubの画面のActionsタブを押下し、new workflowを押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541882/9dbb2b83-6a12-5099-3c25-7536115c7849.png)

dartのconfigureを押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541882/103457bb-1ba0-307d-4baf-24dc5f96721a.png)

画面右上のコミットボタン押下。これでymlファイルの作成ができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541882/c6ad5ff3-06e3-c786-b043-379a071d7545.png)

自分のローカルにコミットとしたymlファイルをpullして書き換えます。
最初に書いてある内容のjobsの内容は消していいかもです。

# ymlファイルのそれぞれの意味

あんまり知らなくてもいい情報は調べてません

:::note info
on:
実行するタイミングだと思います。どのブランチにコミットorPullリクエストがきたか確認します。
:::

:::note info
runs-on:
実行環境です。こだわりがなければubuntu-latestのままで
:::

:::note info
uses:
わからない（無能）。githubactionsにて必要なコマンド等を定義するといいそうです。
:::

:::note info
name:
後でログを確認するときにいろいろまとめてくれます。ここでは何をしたいか定義すると見やすいです。
:::

:::note info
run:
実行したいコマンドです。
:::
Wordを使用するexeやらvbsがタスクスケジューラで動かない時

# はじめに
Visual StudioでMicrosoft Word XX.X Object Libraryとか追加したexe、またはvbsでwordを操作したりすることがあると思います。
exeとかvbs単体では正常に動くけど、定期的に実行させたくてタスクスケジューラに登録した途端に動かない！
人生そういうことばかりですよねMicrosoft…。

# 解決方法
ここに「Desktop」フォルダを作るだけ！
+ 32bitのWordを使っている場合
 C:¥Windows¥System32¥config¥systemprofile¥
+ 64bitのWordを使っている場合
 C:¥Windows¥SysWOW64¥config¥systemprofile¥

## だいたいはこれで解決すると思いますが、それでもNGの場合…
以下のフォルダにアクセス権限を持たせる
+ 32bitのWordを使っている場合
 C:¥Windows¥System32¥config¥systemprofile¥AppData¥Roaming¥Microsoft
 C:¥Windows¥System32¥config¥systemprofile¥AppData¥Local¥Microsoft
+ 64bitのWordを使っている場合
 C:¥Windows¥SysWOW64¥config¥systemprofile¥AppData¥Roaming¥Microsoft
 C:¥Windows¥SysWOW64¥config¥systemprofile¥AppData¥Local¥Microsoft

### 参考
[実行されないマクロの修正](https://www.ibm.com/docs/ja/elo-p/2.1.1?topic=issues-fixing-macros-that-are-not-running)