OmniAICreator/Qiita-1.07M huggingface dataset:
【超簡単】MongoDBにデータをcsvインポートする方法【MongoDB Compass】

この記事ニーズあるのかなと思いつつ、備忘録も兼ねて共有


準備
-
`MongoDB Compass`というMongoDBクライアントをインストール

https://www.mongodb.com/try/download/compass

手順
-

#### STEP1 接続
`MongoDB Compass`を開いて、`Connection String`でmongoDBに接続します

|<img width="400" alt="接続" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425910/b7eee67b-fb4d-82e8-5f1f-191543dfca55.png">|
|:--|


`MongoDB Atlas`を利用していて接続できない場合は以下

https://qiita.com/at_sushi/items/e39817403701e766b81b


#### STEP2 csv作成
インポートするcsvを作成してください。
なんでもいいんですが、個人的にはgoogleスプレッドシートで作成するのが好きです

|<img width="400" alt="csv1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425910/18ae9b50-d6ef-cdde-70f7-44b0d18f2ab0.png">|
|:--|



|<img width="400" alt="csv2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425910/65e79388-a05e-d28b-46f6-6277ecf9b023.png">|
|:--|


#### STEP3 csvインポート

レフトメニューから追加対象のコレクションを選択し、`ADD DATA` => `Import File`
|<img width="400" alt="import1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425910/50a26ac9-e54b-21b3-dd57-859ecd50346e.png">|
|:--|

先程作成したcsvをアップロードします。
csvのほうを選択して、右下の`IMPORT`をクリック
|<img width="400" alt="import1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425910/2333e238-934a-60b5-c648-b51b95bbb35b.png">|
|:--|

無事インポートが完了しました :tada: :tada: :tada: 

|<img width="400" alt="import1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425910/9a056490-a0d8-035e-7ad9-8f446f382daf.png">|
|:--|
モノレポでGitHub Actionsをいい感じにやるチップス

# 概要
本記事では前回モノレポ化したリポジトリに対して、GitHub ActionsでCIを実行するチップスを解説します。

https://qiita.com/watta10/items/46fb2fd62ff03ce4928f

## 前提
- 対象とするリポジトリmonorepoは5つのフォルダ（システム）からなるモノレポ構成
    - hoge1-be
    - hoge1-fe
    - hoge2-be
    - hoge2-fe
    - database
- 作業ブランチはpushed_branch


# 特定のフォルダに変更があればworkflowを実行する
イベントトリガーのpushにファイルパスのパターンを設定できます。
以下の場合は `hoge1-be` か `hoge2-be` のどちらかに変更があるpushがされた場合にworkflowが実行されます。

```
on:
  push:
    paths:
      - hoge1-be
      - hoge2-be
```

モノレポではバックエンドやフロントエンドのリポジトリが混在している場合があります。
バックエンドの変更をpushしたときに、都度フロント用のCIを実行する必要はあまりないと思います。

https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#on



# git checkout
モノレポでは単純にgit checkoutすると全てのフォルダがcheckoutされてしまいます。
こういった場合に有効なのがgit sparse-checkoutです。

しかし、GitHub Actionsでよく使われる[actions/checkout@v3](https://github.com/actions/checkout)ではsparse-checkoutに対応していません。

そこで、以下のようなsparse-checkoutを実行します。
`--no-checkout` をつけることでファイルの実体をcheckoutせずにcloneが可能です。

checkoutしたいフォルダに対して　`git sparse-checkout add` を実行します。
```
git clone -b pushed_branch --filter=blob:none --no-checkout --depth 1 --sparse https://github.com/account/monorepo.git .

git sparse-checkout add hoge1-be
git sparse-checkout add hoge2-be

git checkout
```

実際には `pushed_branch` がpushされた任意のブランチ名になるので、ブランチ名を取得するステップを追加します。
また、ルートに存在するファイルが必要な場合は `git sparse-checkout init --cone` を追加します。
```
- name: Set branch name
  id: vars
  run: echo ::set-output name=pushed_branch::${GITHUB_REF#refs/*/}

- name: Git checkout
  run: |
    git clone -b ${{ steps.vars.outputs.pushed_branch }} --filter=blob:none --no-checkout --depth 2 --sparse https://${GITHUB_ACTOR}:${{secrets.GITHUB_TOKEN}}@github.com/${GITHUB_REPOSITORY}.git .
　　　　　　　　git sparse-checkout init --cone
　　　　　　　　git sparse-checkout add hoge1-be
　　　　　　　　git sparse-checkout add hoge2-be
　　　　　　　　git checkout
```


# 変更したファイルにのみlintを実行する
git cloneの際に `--depth 2` としておけば前回との差分が取得できます。
これをlinterのパラメーターに引き渡すことで特定のファイルのみに対してlintを実行できます。
```
<some-linter> `git diff HEAD~ HEAD --name-only --diff-filter=AMRT | tr '\n' ' '`
```


# パッケージなどをキャッシュする
モノレポとは直接関係ないですが、設置に時間がかかるパッケージなどはキャッシュすると実行時間を短縮できます。
これには[actions/cache@v2](https://github.com/actions/cache)を使います。

以下はyarnを利用しているフロントエンドでのキャッシュを設定します。
プロジェクトのnode_modules、globalのキャッシュをpathに指定し、yarn.lockのハッシュをキーとします。

`yarn install` などの実行前にこのステップを追加することで保存済みのキャッシュを復元します。
キャッシュの保存はjobの最後に自動で実行されます。
```
 - name: Get yarn cache directory path
   id: yarn-cache-dir-path
   run: echo "::set-output name=dir::$(yarn cache dir)"
 
 - uses: actions/cache@v2
     id: yarn-cache
     with:
       path: |
         hoge1-fe/node_modules
         ${{ steps.yarn-cache-dir-path.outputs.dir }}
 
       key: ${{ runner.os }}-hoge1-fe-yarn-${{ hashFiles('**/yarn.lock') }}
```


# まとめ
以上、モノレポでGitHub Actionsをいい感じにやるチップスを説明しました。
workflowのトリガーでフォルダの指定とgit sparse-checkoutで対象ファイルを絞ることが設定できれば、あとは一般的なCIと変わりません。


# 参考
- https://zenn.dev/mizchi/articles/gha-run-test-only-changed 
- https://stackoverflow.com/questions/67136614/cache-node-modules-in-github-actions
VSCodeショートカット

VSCodeの利用を再開したので、
備忘録、記事の練習のために書きます。

Windows。
随時追加予定。
対応するかっこへ移動は欲しい

個人的必須プラグイン
・Indent-rainbow、Bookmarks

◎：よく使う
|頻度|覚えた|番号|分類|ショートカット|概要|覚え方|
|:-----------|:------------:|------------:|:------------:|:------------|:------------|:------------|
|◎|ok|1|always|Ctrl＋,|設定画面|ちょい待って|
|◎|ok|2|always|Ctrl＋K, S|ショートカット|KeyboardShortcut|
|◎|ok|3|always|Ctrl＋Shift＋P|コマンドパレット|Palette|
|◎|ok|4|always|Ctrl＋Shift＋E|ワースペ|workspacE|
|◎|ok|5|always|Ctrl＋@|ターミナル||
|◎|ok|6|**always**|**Ctrl＋1**|**エディタ**|**1番使う**|
|◎|ok|7|editor|Ctrl＋K,←|左エディタに移動（エディタフォーカス時||
|◎|ok|8|editor|Ctrl＋K,→|右エディタに移動（エディタフォーカス時||
|◎|ok|9|always|Ctrl＋P|ファイルを開く|oPen|
|◎|ok|10|always|Ctrl＋W|閉じる|Waste|
|◎|ok|11|terminal|Ctrl＋C|localhost終了||
|◎|ok|12|bookmark|Ctrl＋Alt＋K|ブックマークON|booKmarK|
||||||||
初投稿！

皆さん、はじめまして！ 

AI Dynamics JapanでPR/Marketingを担当している <b>Tech Lady</b> (@tech_lady731)です。 
これから、AI Dynamics Japanの主任エンジニアである <b>みきを</b>(@michelle0915) と共に、Qiitaでいろいろ発信していくこととなりました。 
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2583928/b6d8933c-5d08-33a4-abb3-8b2ae95d923f.png" width="９０%">


二人の大まかな発信内容ですが、<b>みきを</b> (@michelle0915)は、自社のプロダクト開発への拘り、AI開発全般に役立つノウハウや技術の紹介から、次世代を担うエンジニアが気を付けるべき無添加食材や歯磨き粉の選び方など生活お役立ち情報を！非エンジニアの <b>私</b> (@tech_lady731)は、初心者目線でAIソリューションに触れたときの感想や意見、エンジニアの皆さんの開発裏側レポート、プロダクトローンチ時のPRなど、ビジネスサイド観点からQiitaの皆さんともいろいろ意見交換していけそうな情報を発信していけたらと思っています。 

少しでも多くの方に <b>”フォロー＆いいね”</b> いただけると嬉しいです。
どうぞ、よろしくお願いいたします！ 
 


-----P.S.-----
Qiitaと合わせて、下記SNSもぜひフォローお願いいたします！ 
 
<b>Facebook</b>
AI Dynamics Japan : @aidynamics.jp  

<b>Twitter</b>
Tech Lady: @tech_lady731　※Qiita執筆に伴いアカウント開設しました！
CircleCIのconfig.ymlのバリデーションチェックをローカルで行う

macならbrewでinstall
```bash
$ brew install circleci
$ circleci update
```

```bash
$ circleci config validate -c ./.circleci/config.yml
Config file at ./.circleci/config.yml is valid.
```
`-c` がオプションない場合はデフォルトで `.circleci/config.yml` のパスが使われる様です。

https://circleci.com/docs/2.0/local-cli/
React Native Google Sign In Android版 when Release

react-native-google-signinを使ってAndroid/Releaseで失敗する問題に直面してやっと解決したので同じ不具合の方がいるかと思い記事を書きます。

下記を事前に読んで下さい。
https://github.com/react-native-google-signin/google-signin/blob/master/docs/android-guide.md

結果としてフィンガープリントSHA-1, SHA-256が足りなかったのが原因でした。
`cd android && ./gradlew signingReport`
を実行して一番上部に表示されるReleaseのSHA-1, SHA-256を追加してましたが、それだけでは足りなかったです。

GooglePlayConsoleにもSHA-1, SHA-256があるのでそれもFirebaseに追加しましょう。
設定->アプリの完全性->アプリ署名->アプリ署名鍵の証明書
にSHA-1, SHA-256があります。

Readmeには英語で書いてるですが、GooglePlayConsoleには日本語表記で見落としがちです。

内部アプリ共有をでテストを実施する場合はまた別のSHA-1, SHA-256が必要です。
設定->内部アプリ共有->内部テスト版証明書
【ノート】rbenv

# install
brew update
brew install rbenv ruby-build
rbenv --version
brew upgrade rbenv
rbenv init


# how to use
rbenv install -l
rbenv install 2.5.0
rbenv versions
rbenv global 2.5.0

# check
curl -fsSL https://github.com/rbenv/rbenv-installer/raw/main/bin/rbenv-doctor | bash
【ノート】git

# ファイルの出入り
$ git init
$ git add .
$ git commit -m "first commit"
$ git status

git remote add origin 【リモリポURL】

$ git remote origin <URL>
$ git push origin 【ブランチ名】
// check remote repository URL
$ git config --get remote.origin.url    

# チェック
$ ssh -T git@github.com
$ git remote -v
// 変更有無の確認
$ git status -sb

# 修正
#### 直前のコミットを取り消す
$ git reset --soft HEAD^
#### リモートリポジトリURL書換
$ git remote set-url origin [新しいリモートリポジトリURL]
git branch -m <古いブランチ名> <新しいブランチ名>
#### ブランチ名の変更
git branch -m <古いブランチ名> <新しいブランチ名>

# ブランチ
// check all branches
$ git branch 
// make sample1 branch
$ git branch sample1
// enter sample1 branch 
$ git checkout sample1
// branch
https://kakakakakku.hatenablog.com/entry/2020/04/08/151627



# 問題解決
### error : failed to pushsome refs to 'リモリポURL'
→　リモートの最新情報と異なる
→　$ git merge origin main
→　error : refusing to merge unrelated history
→　同じ元（根、祖先）を持っていないブランチ同士はマージ付加
→　git merge --allow-unrelated-histories origin/main

### プッシュした後、コードいじってやっぱその段階に戻したい
```
$ git status -sb
#dev
M app.rb
$ git restore .
```
【Oracle Cloud】Cloud Guard Threat Detectorの設定

# 1. はじめに
Oracle Cloud Infrastructure(以下OCI)のCloud Guardの新しい機能でThread Detectorというセキュリティ脅威に関連するユーザのふるまい検知の機能が加わりましたので、以下に記載します。
# 2. Cloud Guard Threat Detectorとは
Thread Detectorについてお話する前に、まずMITRE ATT&CK (マイター・アタック)というセキュリティフレームワークについて説明したいと思います。このMITRE ATT&CKは、MITRE社という米国の連邦政府が資金を提供する情報セキュリティ専門の非営利組織によって管理・考案され、敵対戦術とテクニックに関するナレッジベースになります。つまりセキュリティリスクといっても多種多様でセキュリティリスク毎にその対策が異なりますので、それぞれの脅威にどのように検知、対応したらよいのかをMITRE社が実際の観測に基づいてナレッジベース化したフレームワークです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2592805/f07515da-00ba-7202-57b7-0e461c797bb6.png)
https://attack.mitre.org/matrices/enterprise/cloud/iaas/

このフレームワークに従ってOCIを利用しているユーザがどのように検知するのかというのを体系化したものが、今回のCloud Guard Threat Detectorです。
元々Cloud Guardは主にOCI上のセキュリティ的な設定ミスを見つけることができるサービスですが、Cloud Guard Threat Detectorは機械学習を使ってユーザアカウントに対してふるまい検知を行い、脅威を検出するサービスになっています。日々、ユーザーのふるまいをラーニングしていくことで通常のふるまいを学習し、いつもと異なるユーザのふるまいがあれば、それを検知することができるサービスになっています。例えば、複数のテナントや地域にまたがる可能性のあるパスワードスプレーのような攻撃をより適切に検知することができます。

この機械学習の進捗に沿って以下の画像の表のように折れ線グラフでユーザごとのリスクスコアがでてきますのでセキュリティリスクの傾向を見ていくことができます。また、このCloud Guard Threat Detectorの利用は課金無し(無償)で利用可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2592805/d6e4d1bb-c19d-054d-f0c1-681413f15d6d.png)

**◆Cloud Guard の新しい機能：**
 - マシーンラーニングを活用した脅威検出サービス
 - 標的型脅威モデルの実行
 - MITRE ATT&CK®フレームワークに準拠
 - 単なる異常ではなく、悪意のある行動を検出
 - 目撃情報の重要性と信頼性を評価
 - 攻撃の進行状況に応じてグローバルなリスクスコアを付与
 - レスポンダ自動化のトリガーとなる問題を作成
 - 継続的な改善のためのフィードバックを追跡

# 3. Cloud Guard Threat Detectorの設定
 
Cloud Guard Threat Detectorの設定はシンプルで「OCI Threat Detector Recipe」のディテクタレシピをコンパートメントに割り当てるだけで、サービスが有効になります。

メニューからアイデンティティとセキュリティ->ディテクタ・レシピを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2592805/7c1fba1b-fca2-945f-36f1-359b62fab919.png)

クローンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2592805/541a5787-6f75-454a-fd46-ea6e8efd0bd5.png)

「クローニング」で「OCI OCI Threat Detector Recipe(Oracle管理)」を選択、
「名前」を入力し、「コンパートメントの割当て」でコンパートメントを選択して、「クローン」をクリックすることで、ディテクタ・レシピに追加されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2592805/63dc7cde-6509-da29-98e6-c9eee40bd62e.png)

最初はリスクスコアが安定しませんが、ユーザのふるまいを日々ラーニングしていくことで通常のふるまいを学習し、セキュリティリスクを検知可能です。以下はユーザごとのリスクスコアです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2592805/f5c59630-9bd5-4a5f-d563-11a791c1b794.png)
# 4. まとめ
Cloud Guard Threat Detectorはユーザのふるまいを機械学習し、内部のセキュリティの脅威を防ぐCloud Guardの新しい機能です。ディテクタレシピにThreat Detector Recipeを追加ことでマシーンラーニングによる内部のリスク検知が可能となります。無償で利用できる機能ですので多層防御の観点でもうまく活用頂くことをお勧めします。
可逆圧縮アルゴリズムと非可逆圧縮アルゴリズム

## 可逆圧縮アルゴリズム
可逆圧縮アルゴリズムとは、圧縮したファイルなどを圧縮する前に戻せるアルゴリズムのことを言います。
たとえばメールで圧縮したエクセルファイルとかを送ったことありませんか?
zipファイルとかです。これは可逆圧縮アルゴリズムが使われています。なぜなら、圧縮したファイルを圧縮する前に戻せますからね。

### ランレングス符号化(RLE)
ランレングス符号化は、単純なアルゴリズムで今も広く使われています。
ランレングス符号化は、[ある値］×[その値が連続して繰り返されている回数］で表示するアルゴリズムです。
例えば、```ccsaassss55ssaaaaaaa```という値をランレングス符号化を使って圧縮してみましょう。
すると、```c2s1a2s452s2a7```になります。もとは、20文字だったものが、14文字に圧縮できました。
しかし、このアルゴリズムは時として、圧縮前の文字数より圧縮後の文字数が増えてしまうことがあります。
それがデメリットです。

### ハフマン符号化
このアルゴリズムを知るには、まず符号化を知らねばなりません。
符号化とは、データを「0」と「1」の2進数に置き換えることです。
コンピュータが扱う最小単位のことをビット（bit）といい、1ビットで表現できるのは0と1だけです。2ビット、3ビット…と増えていくと倍々に表現できる数も増えてきます。

話しは戻ってハフマン符号化とは、データが現れる出現頻度に注目した圧縮方法です。
例えば、```DACDBCDBCD```という数字を圧縮しようと考えます。
まず、出現頻度を表にして考えてみましょう。
| A | B | C | D |
|:-:|:-:|:-:|:-:|
| 1 | 2 | 3  |  4 |

このような表現ができるかとおもいます。出現回数が多い順にビット列0、ビット列1、ビット列10、ビット列11を与えていくんです。
すると、```0111010101010```というふうに表現できます。13ビットで表現できます。
もし、出現回数を考えずにAから順に0, 1, 10, 11とビット列を与えていくと、```11110111101111011```18ビットで表現しないといけなくなります。
このようにビット数を減らして圧縮する方法がハフマン符号化というアルゴリズムです。

## 非可逆圧縮アルゴリズム
非可逆圧縮アルゴリズムは、可逆圧縮アルゴリズムの逆で圧縮してしまったら、圧縮前に戻せないアルゴリズムのことです。
その例を何個か見ていきましょう。
### 画像圧縮
画像圧縮はどのように行われいるかというと、めちゃくちゃ簡単にいうと、人間の目では違いが分からない色を消すことによって、圧縮しているんです。コンピュータは約1677万色の色を表現できます。それに対して人間が理解できる色は、700～800万色なので、半分くらいの色は消しても画像を見ることに問題はないんですね。
### 音声圧縮
音声圧縮も画像圧縮と考え方は変わりません。人間には聞き取れない音波的なものがあるみたいです。それを消すことによって音声圧縮をしているみたいです。
### 動画圧縮
動画というのは文字通り、画像が動いているものになります。つまり、何万枚の画像が高速で動くことによって動画をなしているんですね。
そこでどう圧縮するのかというと、1枚1枚の画像の中で変化する部分と変化しない部分の差分をとり、それを記憶しておくことで圧縮が可能になります。

どの圧縮方法も専門的な話は個人的に難しかったので分かる方がいらっしゃいましたら、ご教示いただけると幸いです。

【参考記事】

https://medium-company.com/%E3%83%8F%E3%83%95%E3%83%9E%E3%83%B3%E7%AC%A6%E5%8F%B7%E5%8C%96-%E5%9F%BA%E6%9C%AC%E6%83%85%E5%A0%B1%E6%8A%80%E8%A1%93%E8%80%85%E8%A9%A6%E9%A8%93/#i

https://www.amazon.co.jp/%E3%81%8A%E3%81%86%E3%81%A1%E3%81%A7%E5%AD%A6%E3%81%B9%E3%82%8B%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E3%81%AE%E3%81%8D%E3%81%BB%E3%82%93-%E9%88%B4%E6%9C%A8-%E6%B5%A9%E4%B8%80-ebook/dp/B06Y5FS8ZL/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=3DCY7NE79D52C&keywords=%E3%81%8A%E3%81%86%E3%81%A1%E3%81%A7%E5%AD%A6%E3%81%B9%E3%82%8B%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0+%E3%81%AE%E5%9F%BA%E6%9C%AC&qid=1649209891&sprefix=%E3%81%8A%E3%81%86%E3%81%A1%E3%81%A7%E5%AD%A6%E3%81%B9%E3%82%8B%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0+%E3%81%AE+%E5%9F%BA%E6%9C%AC%2Caps%2C230&sr=8-1
CakePHP4 ORM "FROM サブクエリ"

## 環境

PHP 8.1.4RC1
CakePHP 4.3.6

## CakePHP4 の ORM で "FROM サブクエリ" を作る

やりたいこと

```sql
SELECT base.id
FROM (SELECT h.id FROM hoges h) base
LEFT JOIN moges m ON base.id = m.id
```

をORMで生成する。

次のコードは最初に書いたもの。

```php:\App\Model\Table\HogeTable
public function getData()
{
    // SELECT h.id FROM hoge h をつくる
    $this->setAlias('h');
    $subquery = $this->find()->select('h.id');

    // サブクエリをFROMに指定する
    $this->belongsTo('m', [
        'className'  => 'Moge',
        'bindingKey' => ['id'],
        'foreignKey' => ['id'],
        'joinType'   => 'LEFT',
    ]);
    $this->setAlias('base');
    $data = $this->find()
                 ->from(['base' => $subquery])
                 ->contain('m')
                 ->select('base.id')
                 ->all();
}
```

これを実行するとこうなる。

```sql
SELECT base.id AS base__id
FROM (SELECT h.id AS h__id FROM hoges base) base
LEFT JOIN moges m ON base.id = m.id
```

```base```に```id```というカラムがない（```h__id```になっている）
サブクエリの別名も```base```になっている。

### 問題点

* カラムの別名は未指定だと、ルールに従い自動で付与される。
* クエリを発行しないとテーブルの別名は上書きされる。

どーーしてもサブクエリと違う別名を使いたいのであれば
サブクエリを確定（発行）してしまうか、別の```Table```オブジェクトを使う。

```php
$this->setAlias('h');
$subquery = $this->find()->select(['id' => 'h.id'])->sql();
// SQL発行 => SELECT h.id AS id FROM hoges h
```
ただこれを```from```に指定すると
```SELECT base.id FROM SELECT h.id AS id FROM hoges h LEFT JOIN moge m ON ```
となる（括弧がつかない）し、結果的に文字列を扱うなら最初から無理にORMでやらなくてもよくない？

### 対処法

というわけで、解決？策。

```php:\App\Model\Table\HogeTable
public function getData()
{
    $sub = clone $this;
    $sub->setAlias('h');
    $subquery = $sub->find()->select(['id' => 'h.id']);

    $this->belongsTo('m', [
        'className'  => 'Moge',
        'bindingKey' => ['id'],
        'foreignKey' => ['id'],
        'joinType'   => 'LEFT',
    ]);
    $this->setAlias('base');
    $data = $this->find()
                 ->from(['base' => $subquery])
                 ->contain('m')
                 ->select('base.id')
                 ->all();
}
```

結果

```sql
SELECT base.id AS base__id
FROM (SELECT h.id AS id FROM hoges h) base
LEFT JOIN moges m ON base.id = m.id
```

### 余談

調べたら```autoAlias(false)```というものを見かけたが、2015年の記事だし、そんなものはなかった。
pip installしたaws-cdkを入れなおす

aws-cdkのバージョンを上げようとして、aws-cdk.xxxのモジュール間のバージョンがずれてしまうことありませんか？僕はあります。

スマートな解決方法がわからなかったので、一度全削除して入れなおすことにしました。

### アンインストール
```sh
pip list | grep aws-cdk | awk -F' ' '{print $1}' | xargs -i pip uninstall -y {}
```

### インストール
1系を使いたいのでメジャーバージョンを指定しています。
```sh
sudo npm i -g aws-cdk@~1.x
```

grep, awk, xargsはshell芸の基礎だなー(あとsed)
AWS CLIインストールした際にエラーの対処方法

### AWS CLIインストール時にawscliが機能しないエラーが発生、解決方法をメモ

#### エラーメッセージ
```
C:\>  aws --version
Traceback (most recent call last):
  File "C:\Program Files\Python38\Scripts\aws.cmd", line 50, in <module>
    import awscli.clidriver
ModuleNotFoundError: No module named 'awscli'
```

#### 環境
Windows10 x64

#### 手順
AWSインストールガイドに従ってインストールしました。
```
C:\> msiexec.exe /i https://awscli.amazonaws.com/AWSCLIV2.msi
```
[AWS CLI インストールガイド](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html)

#### 原因
Pythonはawscliインポート時に、awscliモジュールが見つかりませんでした。

#### 対策
「システム」PATH変数のawscliとPythonの順序を変更

**変更前**
```
C:\Program Files\Python\Python38\
C:\Program Files\Python\Python38\Scripts
C:\Program Files\Amazon\AWSCLIV2\
```

**変更後**
```
C:\Program Files\Amazon\AWSCLIV2\
C:\Program Files\Python\Python38\
C:\Program Files\Python\Python38\Scripts
```
コマンドプロンプトを閉じて再度開くとバージョンが正常表示しました。
```
C:\> aws --version
aws-cli/2.5.2 Python/3.9.11 Windows/10 exe/AMD64 prompt/off
```
リードのまとめ


+ [リード変換時の数式](https://qiita.com/Keiji_otsubo/items/9cc97f21f873d43952a1)
+ [リードコンバージョンタブに[商談]列がありません](https://qiita.com/Keiji_otsubo/items/d058eb72a5dc6cd3abf9)
+ [LeadのConvert buttonが表示されない](https://qiita.com/Keiji_otsubo/items/c369fdfce56932b1e18f)
+ [Joined report on lead and contact history](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000G4j1I)
Phaser3.jsで、CPU対戦4人UNOを作りました。

Phaser3.jsで、CPU対戦4人UNOを作りました。
とりあえず、遊べます。
CPUはめっちゃ弱いです。
スコアの履歴登録等、細かい点は順次実装していきます。
https://www.new-doumeishi.me/vsUno_/


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156369/b3578c15-eb60-8b8b-ed39-16df94ea0b06.png)
Reactをなぜアプリに使うのか？？

![スクリーンショット 2022-04-06 10.21.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1037046/c4f08276-d386-478e-982c-7e3a025d08ac.png)
アプリの設計は非常に複雑ですから、それを簡単にできるものなら何でも歓迎です。そこで、Reactの出番です。Reactは、ユーザーインターフェースの作成を容易にするために設計された、JavaScriptコードとコンポーネントのライブラリです。オープンソースのフレームワークとして、PaypalやNetflixなど、今日の市場で最大級のアプリの作成に使用されています。

このフレームワークが人気を博している理由はいくつかありますが、最大の理由は、宣言型のビューを提供していることでしょう。新しい情報が入ってくると、即座にきれいに更新されるインタラクティブなアプリを作ることができます。データがアプリに届くと、すぐに更新されます。Facebookのコメント欄を見ると、画面を更新しなくても新しいコメントが出てくるのがわかります。もともとFacebookが開発したReactは、現在、FacebookとInstagramの開発者が共同で運営しています。

ReactがJavaScriptを使用していることは知っていますが、なぜそれがそれほど重要なのでしょうか？それは、JavaScriptが世界で最も使われているプログラミング言語の1つだからです。実際、970万人の開発者がJavaScriptを使用しており、広く普及している構築プラットフォームとしては最適な選択と言えます。

このプログラミング言語とHTMLを混ぜ合わせることで、Reactに必要なことは何でもできるようになるのです。JavaScriptに慣れている人であれば、学習のハードルはかなり低いでしょう。Reactに飛び込んですぐにアプリのプログラミングを始められます。

・コンポーネントを単独で編集できる
ほとんどのプログラミングは、一つのことを変更すると、プログラム全体を適応させる必要があります。このため、アプリの一部分を変更しようとすると、整理しなければならない大混乱に陥り、多くの問題が発生します。しかし、Reactではそのようなことはありません。ダウンワードフロー型のプログラミング手法なので、何かを変更しても、その上流にあるものには影響を与えません。
また、コンポーネントの変更や編集も、他のコンポーネントに影響を与えることなく行うことができます。これにより、作業スピードが格段にアップします。ひとつの変更に合わせて、すべてのコードを調整する必要はもうありません。アプリの不具合を修正したり、定期的なメンテナンスを行う際にも、コンポーネントが分かれているため、プロセス全体が高速化されます。

・JavaScriptライブラリが複数のソースから入手可能
Reactはオープンソースなので、多くの開発者がReactの改良に取り組んでいます。様々な機能に使用できるコードを含むJavaScriptライブラリを利用できます。これらのライブラリには、さまざまな機能のためにあらかじめ書かれたコードがたくさんあり、それらを手に入れるだけで使うことができます。既存のコードを利用できるのであれば、最も基本的な機能をコーディングする必要はありません。プロセス全体がスピードアップし、イライラすることもなくなります。

誰もが似たようなコードを必要としているのですから、車輪の再発明ではなく、賢く働くことを大切にしてほしいと思います。基本的なアイデアを管理するコードを使うことは、より良い方法であると言えます。

・仮想DOMが情報の高速読み込みを助ける
通常、アプリやWebサイトは、HTMLを使ってDOM（ドキュメント・オブジェクト・モデル）を更新します。これは長い間、唯一の方法でした。機能的には問題ありませんが、サイトを利用する人が増えると、この方法ではどんどん時間がかかってしまいます。サイトの利用者が増えれば増えるほど、ページを更新するのが面倒になります。以前は、コメントやその他のデータなど、瞬時に更新する必要があるものを更新するには、この方法しかありませんでした。

仮想DOMは、実際のDOMをコピーするだけで、ReactJSを使って瞬時に更新させることができます。ページ全体をリロードするのではなく、変更される情報だけをロードします。つまり、ページやアプリ全体の動作が格段に速くなるのです。小さな機能なので、1人や2人にとっては大きな違いはないかもしれません。しかし、大勢の人が同じページを使用している場合、その差は驚くほど大きくなります。

Reactは、アプリやサイトの作成だけでなく、そのアプリの日常的な機能を実現するためのプロセス全体を劇的に高速化しました。開発者は、プロトタイプアプリの作成をスピードアップできるだけでなく、完全なアプリを半分の時間で立ち上げることができるようになりました。これは、コードを再利用できることによるものです。アプリやサイトが一般的に使用されるようになると、仮想DOMにより、ユーザーインターフェイスもより良いユーザー体験を提供します。

（読んでくださり、ありがとうございました。）
Ruby で Array や Hash のメソッドを使いこなしたい

Ruby には、多くのメソッドが用意されています。
私もそうでしたが、他の言語は知っていて Ruby を知らない場合、Ruby のメソッドを使いこなせていないことがあります。
他言語経験者が、知っておくべき Ruby の Array, Hash のメソッドをユースケース毎に書きたいと思います。

## 特定の要素を取得する (Enumerable#find)

特定の条件を満たす要素を取得する場合、
ループと if 文を駆使して探すことを考えるかもしれませんが、

```ruby
tasks.each do |task|
  next unless task[:state] == 'finished'

  found = task
  break
end
```

`find` 一行で取れます。

```ruby
found = tasks.find { |task| task[:state] == 'finished' }
```

## 特定の要素を削除する (Hash#delete_if)

特定の条件を満たす要素を削除する場合、、、(以下略

```ruby
schedules.each do |key, schedule|
  schedules.delete(key) if schedule.empty?
end
```

`delete_if` 一行で削除できます。

```ruby
schedules.delete_if { |_key, schedule| schedule.empty? }
```

:::note warn
注意
`delete_if` は元の Hash から要素を削除します。
元の Hash を変更したくない場合は `reject` を使います。
:::

## 要素内の値を取り出して新たな Array を作る (Array#map)

Array の要素が Hash になっていて、その Hash の一要素だけの Array を作る場合、、、(以下略

```ruby
start_times = []
schedules.each do |schedule|
  start_times.push(schedule[:start_at])
end
```

`map` 一行でできます。

```ruby
start_times = schedules.map(&:start_at)
```

## 特定の要素を削除した新たな Array を作る (Enumerable#each_with_object)

Array の要素が Hash になっていて、その Hash の一要素だけの Array を作りたいけど、その Array に入れる条件もある場合、、、(以下略

```ruby
start_times = []
schedules.each do |schedule|
  unless schedule[:status] != 'finished'
    start_times.push(schedule[:start_at])
  end
end
```

一行ではありませんが、`each_with_object` でスッキリ書けます。

```ruby
start_times = schedules.each_with_object([]) do |schedule, result| 
   result << schedule[:start_at] unless schedule[:status] == 'finished'
end
```

# 結論

Ruby でループ書く時は、既存のメソッドでできないか調べるべし！


### リファレンスマニュアル

ここにあるメソッドをサラッと使えると生産性が上がるはず。

- [Array](https://docs.ruby-lang.org/ja/latest/class/Array.html)
- [Hash](https://docs.ruby-lang.org/ja/latest/class/Hash.html)
- [Enumerable](https://docs.ruby-lang.org/ja/latest/class/Enumerable.html)
oauthlibでGoogle認証を実装する方法

## はじめに
検索したけど見つからなかったので、備忘録として。

## レシピ
* Python >= 3.7
* oauthlib >= 3.2.0

### Code

必要というか、メインの部分だけ。

```python
import os
import requests
from typing import Optional
from requests_oauthlib import OAuth2Session

class GoogleAuthService:
  GOOGLE_CLIENT_ID = os.getenv("GOOGLE_CLIENT_ID")
  GOOGLE_CLIENT_SECRET = os.getenv("GOOGLE_CLIENT_SECRET")
  OAUTH_URL = "https://accounts.google.com/o/oauth2/auth"
  TOKEN_URL = "https://oauth2.googleapis.com/token"
  USER_INFO_URL = "https://www.googleapis.com/oauth2/v1/userinfo"
  SCOPES = ["profile", "email"]
  
  def get_authorization_url(self) -> str:
      # ここでGoogle認証画面に遷移するためのURLを取得する
      # OAuthにない任意のパラメータをもたせたい場合は、 state を使うとよい
      # ex)
      #   # name を渡したい場合
      #   exp = int(datetime.utcnow().timestamp()) + 30
      #   encoded = jwt.encode({"exp": exp, "name": "hoge"}, "secrets", algorithm="HS256")
      #   state = encoded.decode("utf-8")
      #   redirect_url, _ = self._client().authorization_url(self.OAUTH_URL, state=state)

      redirect_url, _ = self._client().authorization_url(self.OAUTH_URL)
      return redirect_url

  def fetch_token(self, code: str) -> str:
      # Googleからリダイレクトして来たときにURLに付与されている code を使って token を取得する
      token = self._client().fetch_token(
          self.TOKEN_URL,
          client_secret=self.GOOGLE_CLIENT_SECRET,
          code=code,
      )
      return token["access_token"]

  def get_user_info(self, access_token: str) -> Optional[dict]:
      # access_token を使って、ユーザ情報を取得する
      endpoint_url = f"{self.USER_INFO_URL}?access_token={access_token}"
      response = requests.get(endpoint_url)
      if response.status_code == 200:
          return response.json()

      return None

  def _client(self) -> OAuth2Session:
      return OAuth2Session(
          self.GOOGLE_CLIENT_ID,
          scope=self.SCOPES,
      )  
```

あとは、これらのメソッドを呼び出すように実装を足すくらい。

* Googleとのリダイレクトを行うフロントエンド
  * Reactとか？
* フロントエンドとやり取りをするバックエンドのエンドポイント
  * Flaskとか？

気が向いたら、サンプルコードをGithubにあげる。

ちなみに、Github認証は、以下の部分を変更したら同じコードを使って行うことが可能。

* `GOOGLE_CLIENT_ID`
* `GOOGLE_CLIENT_SECRET`
* `OAUTH_URL`
* `TOKEN_URL`
* `USER_INFO_URL`
* `SCOPES`
Athenaで削除とタイムトラベル

# Athenaで削除とタイムトラベルをやってみる
[公式ドキュメント](https://docs.aws.amazon.com/athena/latest/ug/querying-iceberg-creating-tables.html) を参考にやってみた

## 事前準備

リージョン：東京
S3バケット作成：demo-iceberg-uehara-t

## Athenaで作業

### ICEBERGのテーブル作成

```sql:テーブル作成
CREATE TABLE iceberg_table (
  id int,
  data string,
  category string) 
PARTITIONED BY (category, bucket(16,id)) 
LOCATION 's3://demo-iceberg-uehara-t/athena_iceberg' 
TBLPROPERTIES (
  'table_type'='ICEBERG',
  'format'='parquet',
  'write_target_data_file_size_bytes'='536870912',
  'optimize_rewrite_delete_file_threshold'='10'
)
```

![スクリーンショット 0004-04-06 9.51.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/7291b7f1-c691-e4f3-e016-dcff7d0c3943.png)

### データインサート

```sql:インサート
insert into iceberg_table
values (1, 'ABC', 'CAT'),
(2, 'DEF', 'CAT'),
(3, 'GHI', 'DOG');
```

![スクリーンショット 0004-04-06 9.51.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/76da5b40-0f65-60f3-042b-aa122a4ae828.png)

### select *

```sql:select *
SELECT * FROM iceberg_table order by id;
```

![スクリーンショット 0004-04-06 9.53.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/574370b9-5069-23b7-4ed5-ec27638bb16d.png)

### 削除

```sql:削除
DELETE FROM iceberg_table WHERE ID=2;
```

![スクリーンショット 0004-04-06 9.54.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/f8e3b388-e585-b5c2-5fd6-1ffadf472b89.png)

### select *

```sql:select *
SELECT * FROM iceberg_table order by id;
```

![スクリーンショット 0004-04-06 9.55.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/7a058f64-2b68-6bc8-1a93-b2183f1fdb37.png)

### タイムトラベル

```sql:タイムトラベル
SELECT * FROM iceberg_table FOR SYSTEM_TIME AS OF (current_timestamp - interval '1' minute)
```

![スクリーンショット 0004-04-06 9.55.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27932/2781b986-3800-839c-89df-57348760b24e.png)

# 注意点

* MSCK repair
Icebergテーブルはテーブルレイアウト情報を追跡するため、Hiveテーブルの場合のようにMSCK REPAIR TABLEを実行する必要はなく、サポートされていません。

* Iceberフォーマットは現在Parquetのみ対応

* [サポートデータタイプ](https://docs.aws.amazon.com/athena/latest/ug/querying-iceberg-supported-data-types.html)
自作キーボード Mint60 を作ってみた

## これまでのキーボード遍歴

- HHKB Lite2 for Mac
    - 初めてのHHKB
    - 打鍵感がサクサクして最高
- Realforce
    - windowsを使っていたのでFnキーもあるフルキーボード
- その後HHKB Professional, HHKB Professional Hybridなど何台かHHKBを購入
    - 総額いくら使ったんだろう...

---
## HHKB Professional

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28792/81c631bb-124e-5d5e-2a63-13d130e6ba07.png)
(https://www.pfu.fujitsu.com/direct/hhkb/detail_pd-kb820ws.html)

---
## なぜキーボードにこだわりだしたか

- Emacsを使ってホームポジションからほぼ指を動かさなくてもほとんどの操作ができる喜びを知る。
- しかし、左手小指を酷使しすぎてemacs小指問題が発生したため、HHKBを試す。指負担が激減
- タイプミスも減り、気持ちよく打てることを知る
- ついでにキーのリマップにもこだわり始める
    - [セミコロンエンターとか](https://qiita.com/yohm/items/75ff8d8b159375c83b1f)

---
## キーボードに求めるもの

1. サクサクした打鍵感
    - パンタグラフ式のペタペタしたキーボードは合わなかった
2. 親指で押せるキーが多い
    - 日本語ー英語切り替えなどを親指でできると効率的
3. 左右分割型
    - 手を閉じた位置に置くと肩がこる
4. （できれば）英語キー配列
    - 記号の位置など英語配列の方が打ちやすい

市販のキーボードでこれらを満たすものがない => そうだ自作しよう！

---
## Mint60に出会う

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28792/7e44e618-63cd-e582-3ee1-47687a4ac502.png)

https://lilakey.com/products/mint60-starter

完成品ではないが、自作キーボード初心者用のキットになっている。これならできる！

---

## 組み立てがめんどくて２年が経過する

---
## ついに組み始める

今年の正月に一念発起して組み立て始める。妻に手伝ってもらいながら。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">お正月休みを利用して、ついに <a href="https://twitter.com/hashtag/%E8%87%AA%E4%BD%9C%E3%82%AD%E3%83%BC%E3%83%9C%E3%83%BC%E3%83%89?src=hash&amp;ref_src=twsrc%5Etfw">#自作キーボード</a> の <a href="https://twitter.com/hashtag/Mint60?src=hash&amp;ref_src=twsrc%5Etfw">#Mint60</a> を組み立てました。久しぶりにはんだ付け。<br>妻と娘にも手伝ってもらい家族総出でなんとか完成！ <a href="https://t.co/tihhlVcyr5">pic.twitter.com/tihhlVcyr5</a></p>&mdash; Yohsuke Murase ようちゃんたこ (@yohm13) <a href="https://twitter.com/yohm13/status/1478529041108185089?ref_src=twsrc%5Etfw">January 5, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

---
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28792/46489ff7-e651-ba51-255b-01f482e92dd8.png)


---
## 組んでみた感想

- 中学校でやった以来のはんだづけ。ど素人だが、だんだん慣れてうまくつけられるようになってきた。
- 一人でやると心が折れる。二人でやると、ハマった時に助け合えるし心が折れない。
- Mint60は初心者にも易しいキットで説明が丁寧。youtubeにも動画があるのでそちらを何度も見た。
- 完成したと思ったら一列キーが認識しなくて、はんだづけをやり直すというハプニングもあり。
- まる二日かかってようやく完成！

---
## 使ってみると

- 左右分割式のキーボードは本当にいい！腕が疲れない！
- キーの打ち心地も悪くない（HHKBには若干劣るし、音はうるさいが許容範囲）
- キー配列も最高。親指をうまく使えるし、上段は標準的な英語配列になっている。キーのリマップもやりやすい。

---
## ど素人でもできました。ぜひみなさんも自作キーボードの世界へ！
jqで特定の要素のみを変更してフィルタリングせずにもともとの形式のまま出力する

## やりたいこと
- user01の.modeをtrueに変えたい

## 使うメソッド
- map()
    - ListをMapへ変換
- select()
    - 特定の要素のみを指定
- !=
    - 要素を置換する
- //
    - a // b で a ? a : b と評価される演算子
- .

## サンプル

```json
[
  {
    "name": "user01",
    "majour_version": 1,
    "mode": false
  },
  {
    "name": "user02",
    "majour_version": 2,
    "mode": false
  },
  {
    "name": "user03",
    "majour_version": 2,
    "mode": false
  }
]
```

## 第一形態
とくに変わらないけれど、登場人物を全部当てはめる

```bash
cat test.json | jq '. |= map((select(0)) // .)'
```

```json
[
  {
    "name": "user01",
    "majour_version": 1,
    "mode": true
  },
  {
    "name": "user02",
    "majour_version": 2,
    "mode": false
  },
  {
    "name": "user03",
    "majour_version": 2,
    "mode": false
  }
]
```

## 第二形態
登場する.modeをすべてtrueに変える

```bash
cat test.json | jq '. |= map((select(1).mode |= true) // .)'
```

```json
[
  {
    "name": "user01",
    "majour_version": 1,
    "mode": true
  },
  {
    "name": "user02",
    "majour_version": 2,
    "mode": true
  },
  {
    "name": "user03",
    "majour_version": 2,
    "mode": true
  }
]
```

## 最終形態
狙ったuser01のmodeのみをtrueにすることができた

```bash
cat test.json | jq '. |= map((select(.name == "user01").mode |= true) // .)'
```

```json
[
  {
    "name": "user01",
    "majour_version": 1,
    "mode": true
  },
  {
    "name": "user02",
    "majour_version": 2,
    "mode": false
  },
  {
    "name": "user03",
    "majour_version": 2,
    "mode": false
  }
]
```

ちなみに、最初ifで頑張っていたんだけれど、フィルタリングされてしまうので期待した出力にはならなかった

こんな感じ

```
if .name == "user01" then .mode=true else empty end
```


## 参考
https://tamakiii.hatenablog.com/entry/2019/11/21/001343
curlのHostに任意の値を設定してリクエストを送る方法

リクエストヘッダー「Host」に、実際とは異なるホスト名・ポート番号を指定したリクエストを送る方法です。

ここでは2つの方法を記載しますが、どちらの方法でも `google.com:80` に `Host: localhost:1234` というヘッダーを送信します。

1. Hostヘッダーを指定する
   ```sh
   $ curl http://google.com -H "Host: localhost:1234"
   ```
2. `--connect-to` 引数を指定する
   ```sh
   $ curl --connect-to localhost:1234:google.com:80 http://localhost:1234
   ```
Python3: Google Cloud Functions で加算


フォルダー構造

```text
$ tree
.
├── main.py
└── requirements.txt
```

```py:main.py
def sum_up(request):
	request_json = request.get_json()
	aa = 0
	bb = 0
#	
	if 'aa' in request_json:
		aa = int(request_json['aa'])

	if 'aa' in request_json:
		bb = int(request_json['bb'])
#
	sum = aa + bb
	rvalue = {}
	rvalue['sum'] = sum
	rvalue['aa'] = aa
	rvalue['bb'] = bb

	return rvalue
```

```text:requirements.txt
# Function dependencies, for example:
# package>=version
```

## ローカルでテスト ##

サーバーの起動

```bash
functions-framework --target=sum_up
```

curl でテスト

```bash:curl_post_local.sh
curl -X POST $HOST \
 -H "Content-Type: application/json" \
 -d '{"aa": 32, "bb": 58}'
echo ""
```

Httpie でテスト

```bash:http_post_local.sh
HOST="http://localhost:8080"
http $HOST \
  aa=12 bb=45
```

## Cloud Functions でテスト ##

デプロイ

```bash
gcloud functions deploy function-apr06 \
--entry-point=sum_up \
--trigger-http \
--runtime=python39 \
--region asia-northeast1
```

curl でテスト

```bash:curl_post_cloud.sh
HOST="https://asia-northeast1-project-apr06.cloudfunctions.net"
curl -X POST $HOST/function-apr06 \
 -H "Content-Type: application/json" \
 -H "Authorization: bearer $(gcloud auth print-identity-token)" \
 -d '{"aa": 123, "bb": 546}'
```

Httpie でテスト

```bash:http_post_cloud.sh
HOST="https://asia-northeast1-project-apr06.cloudfunctions.net"
http $HOST/function-apr06 \
  "Authorization: bearer $(gcloud auth print-identity-token)" \
  aa=23 bb=56
```

Python でテスト

トークンの取得

```bash:get_token.sh
gcloud auth print-identity-token > access_token.txt
```

```py:client.py
#! /usr/bin/python3
#
#	client.py
#
#					Apr/23/2022
#
# ------------------------------------------------------------------
import  sys
import  requests
# ------------------------------------------------------------------
sys.stderr.write("*** 開始 ***\n")
#
with open('access_token.txt') as ff:
	access_token = ff.read().strip()
#
host="https://asia-northeast1-project-apr06.cloudfunctions.net"
url_aa=host + "/function-apr06"
#
headers = {'Authorization': 'bearer {}'.format(access_token)}
#
payload = {}
payload["aa"] = 16
payload["bb"] = 48
#
rr = requests.post(url_aa,json=payload,headers=headers)
#
print(rr.text)
print(rr)
#
sys.stderr.write("*** 終了 ***\n")
# ------------------------------------------------------------------
```
phpインストールと、composerを使用してphpunitをインストールする

（自身の備忘録用です）
※OSはLinux

### phpをインストール
```
yum install epel-release
rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
yum install --enablerepo=remi,remi-php70 php php-devel libzip-devel php-mbstring php-pdo php-gd php-xml

# バージョン確認
php --version
```

### comporserをインストール
```
# インストーラーを取得
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php
# PATHが通ってる場所へ移動
sudo mv composer.phar /usr/local/bin/composer

# 実行確認
composer
# 実行問題なければインストーラーは消す
$ php -r "unlink('composer-setup.php');"
```

### composer.jsonを更新する（例：phpunit）
```
# composer.jsonに追加：　
#   phpunitなのでdevオプション付き、本番環境などにinstallしたいライブラリはdevオプションは外す
#   ※require実施後はcomposer.jsonに追加されていることを確認する
composer require --dev phpunit/phpunit
composer require [--dev] [installしたい任意のライブラリ]
# インストール実施
conposer install 

# phpunitバージョン確認
./vendor/bin/phpunit　--version
自然言語処理モデルBERTの検証(5)-GLUEベンチマーク(その3)

##### [前回] [自然言語処理モデルBERTの検証(4)-GLUEベンチマーク(その2)](https://qiita.com/mingchun_zhao/items/59541fc369ebf03830cb)

## はじめに

GLUEタスク検証の続きです。
前回と同じ手順で、一つずつ実行しテスト結果を確認します。

## GLUEタスクの種類

- (済)CoLA: 入力文が英語文法として正しいか判定
- (済)SST-2: 映画レビューの感情解析(ポジティブ、ネガティブ)
- (今回)MNLI: 2つの入力文が意味的に含意/矛盾/中立か判定
- QQP: 2つの質問文の意味が等価か判定
- QNLI: Q&A
- STS-B: ニュースの見出し文の類似度を5段階で評定
- MRPC: 2つの文が等しいか否かを判定
- RTE: 2つの入力文の含意を判定
- SQuAD: Q&A
- NER: 語の役割(人/組織/場所など)を特定
- SWAG: 入力文に後続する文を4つの選択肢から選ぶ

## MNLI: 2つの入力文が意味的に含意/矛盾/中立か判定

[自然言語処理モデルBERTの検証(3)-GLUEベンチマーク(その1)](https://qiita.com/mingchun_zhao/items/9269538a0434335fe87d)の手順で、
下記「GLUEからタスクを選択」を除いては、そのまま実行できます。

### 手順「GLUEからタスクを選択」のみglue/mnliに変更

ドロップダウンメニューから`glue/mnli`を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/88554bd2-c6ab-46d9-19ff-5eca174d51c8.png)

### 残りの手順もそのまま実行

ファインチューニングに時間かかりました(50分程度)。
テスト結果、

```
premise   : tf.Tensor([b'Equally important, each area includes a place where, in hallowed and sensible military phrasing, you can go for rest and recreation.'], shape=(1,), dtype=string)
hypothesis: tf.Tensor([b'The areas lack any sort of recreational or resting places.'], shape=(1,), dtype=string)
This premise CONTRADICTS the hypothesis
BERT raw results: tf.Tensor([-4.600829  -2.5035274  5.752845 ], shape=(3,), dtype=float32)

premise   : tf.Tensor([b"'Best case scenario.'"], shape=(1,), dtype=string)
hypothesis: tf.Tensor([b'This went wrong in every way.'], shape=(1,), dtype=string)
This premise CONTRADICTS the hypothesis
BERT raw results: tf.Tensor([-3.9747162  -0.77916163  4.6576896 ], shape=(3,), dtype=float32)

premise   : tf.Tensor([b'The strong regional identity of the south has repeatedly foiled attempts to spread Hindi and make it the national language here.'], shape=(1,), dtype=string)
hypothesis: tf.Tensor([b'The south supported Hindi as the national language.'], shape=(1,), dtype=string)
This premise CONTRADICTS the hypothesis
BERT raw results: tf.Tensor([-2.2312791 -1.5064766  3.6466644], shape=(3,), dtype=float32)

premise   : tf.Tensor([b'White has none of these things.'], shape=(1,), dtype=string)
hypothesis: tf.Tensor([b'White had every single thing.'], shape=(1,), dtype=string)
This premise CONTRADICTS the hypothesis
BERT raw results: tf.Tensor([-3.4551892 -2.157375   4.804791 ], shape=(3,), dtype=float32)

premise   : tf.Tensor([b'However, attitudes have changed, and diving is now a legal and welcomed activity, provided you dive with an approved and registered organization.'], shape=(1,), dtype=string)
hypothesis: tf.Tensor([b'Because of a change in attitudes, everyone welcomes diving.'], shape=(1,), dtype=string)
This premise ENTAILS the hypothesis
BERT raw results: tf.Tensor([ 1.8908477  0.9796005 -2.2114544], shape=(3,), dtype=float32)
```

2つの入力文が意味的に、含意(ENTAIL)/矛盾(CONTRADICT)/中立(NEUTRAL)、
か判定してくれました。

## おわりに

他のタスクも同じ要領で実行中で、次回結果共有いたします。
お楽しみに。

##### [次回] [自然言語処理モデルBERTの検証(6)-GLUEベンチマーク(その4)](https://qiita.com/mingchun_zhao/items/131aad66e8a849229140)
システム用の特殊なユーザの扱い


元の質問

[Automated User cannot do a chatter post using Apex connect API](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000FxxARSAZ)

Automated UserからAPIにアクセスできないようです。

これを読む限りは制限はないみたいですが...

[Chatter Connect APIは、この組織またはユーザータイプでは有効になっていません](https://developer.salesforce.com/forums/?id=906F000000099mOIAQ)

Automated UserにAPIを有効にする権限を与える方法があるかもしれません、ではどうやって権限を付与するか？

何か方法がありそうです。

+ [Automated Userにアクセスするにはどうすればよいですか？](https://developer.salesforce.com/forums/?id=9062I000000IWbIQAW)
+ [自動化されたプロセスのユーザープロファイルのアクセス許可](https://salesforce.stackexchange.com/questions/210710/automated-process-user-profile-permissions)
Watson Knowledge Catalog for CP4D vs IBM Cloud (CP4DaaS)


Watson Knowledge Catalog for CP4D と IBM Cloud上のWatson Knowledge Catalogでは使える機能が若干異なります。
また、IBM Cloud上のWatson Knowledge Catalogは使用するプランによって使える機能が異なります。

マニュアルに比較表があったのでご紹介します。


### Watson Knowledge Catalogのプラン別機能比較（CP4DaaS版）

https://dataplatform.cloud.ibm.com/docs/content/wsj/getting-started/wkc-plans.html?audience=wdp

### Watson Knowledge Catalog for CP4D と DP4DaaS版の機能比較

https://dataplatform.cloud.ibm.com/docs/content/wsj/getting-started/feature-matrix.html?audience=wdp#wkc

上記リンクには、Watson Knowledge Catalog だけではなく Watson Studio、Watson Machine Learning、DataStage  の比較もあります。

:::note warn
マニュアルのサイトは日本語と英語で書いていることが異なることがあります。
そのため、最新情報を確認する場合は、なるべく英語のページで確認することをお勧めします。
ブラウザーの言語を英語にすると英語のページが表示されます。
:::


<br><br>

# お断り
このサイトの掲載内容は私自身の見解であり、必ずしも所属会社の立場、戦略、意見を代表するものではありません。 記事は執筆時点の情報を元に書いているため、必ずしも最新情報であるとはかぎりません。 記事の内容の正確性には責任を負いません。自己責任で実行してください。
GitHubへのプッシュ時にfatal: remote origin already exists.と表示された場合の解決策

# はじめに

こんにちは、かずやです。

この記事を読んでいるみなさんは、以下のエラーのせいでGitHubへリポジトリをpushできずお困りかと思います。

```
$ fatal: remote origin already exists.
```

本記事ではこのエラーの解決方法を順を追って紹介してまいります。

記事のとおりにコマンドを実行していけば、上記のエラーを解消しGitHubへpushできるはずです。

# 問題

`fatal: remote origin already exists.`と表示されてしまい、リポジトリをGitHubへpushできない

# 解決策

以下の3ステップでこのエラーを解消できます。

## ①originを削除する

`fatal: remote origin already exists.`は「すでにoriginが存在している」という意味です。

この状態を解消するために`git remote rm origin`というコマンドを入力してoriginを一度削除してください。

```
$ git remote rm origin
```

## ②再度originを登録する

originを削除できたら再びoriginを登録してみましょう。

```
git remote add origin https://<GitHubアカウント名>/リポジトリ名/.git
```

今度はエラーが発生せずにコマンドが実行されるはずです。

## ③GitHubへpushする

ここまで来ればあとは簡単です。

GitHubへリポジトリをpushしましょう。

```
git push -u origin master
```

無事にGitHubへpushできました。

# エラーの深掘り

そもそも`git remote add origin ~`は何を実行しているのか、エラーの中身を深掘りしてみます。

結論から申し上げると、`git remote add origin ~`は`.git/config`ファイルに[remote "origin"]を設定するコマンドだそうです。

実際に見てみましょう。

```
$ cat .git/config
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
[branch "master"]
[remote "heroku"]
        url = https://git.heroku.com/secret-river-25498.git
        fetch = +refs/heads/*:refs/remotes/heroku/*
[remote "origin"]
        url = https://github.com/kazuyainoue0124/toy_app.git
        fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
        remote = origin
        merge = refs/heads/master
```
上記のとおり。

すでに[remote "origin"]の設定が存在していたため、`fatal: remote origin already exists.`のエラーが発生したんですね。

だから`git remote rm origin`でoriginの設定を削除してエラーを解決できました。

# 最後に

いかがでしたか？

記事の手順に沿ってコマンドを実行していけば`fatal: remote origin already exists.`のエラーを解消し、無事にGitHubへpushできたはずです。

皆様の参考になれば幸いです。
functions-framework の使い方

Ubuntu 21.10 でのインストール方法

```bash
sudo pip3 install functions-framework
```

こちらで作成したものを、ダウンロードしてローカル環境でテストします。
[Python3: Google Cloud Functions の使い方](https://qiita.com/ekzemplaro/items/aa05bbe647a845437449)

フォルダー構造

```text
$ tree
.
├── main.py
└── requirements.txt
```

```py:main.py
def hello_test(request):
    """Responds to any HTTP request.
    Args:
        request (flask.Request): HTTP request object.
    Returns:
        The response text or any set of values that can be turned into a
        Response object using
        `make_response <http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>`.
    """
    request_json = request.get_json()
    if request.args and 'message' in request.args:
        return request.args.get('message')
    elif request_json and 'message' in request_json:
        return request_json['message']
    else:
        return f'Hello World!'
```

実行

```bash
functions-framework --target=hello_test
```

## Curl でテスト　##

```bash:curl_get.sh
HOST="http://localhost:8080"
curl $HOST
echo ""
```

```bash:curl_post.sh
HOST="http://localhost:8080"
curl -X POST $HOST \
 -H "Content-Type: application/json" \
 -d '{"message": "こんにちは Apr/06/2022"}'
echo ""
```

## Httpie でテスト ##

```bash:http_get.sh
HOST="http://localhost:8080"
http $HOST
```

```bash:http_post.sh
HOST="http://localhost:8080"
http $HOST \
  message="おはようございます。 Apr/06/2022"
```
XAudio2とMediaFoundationを使ったWAV/MP3再生その1

<!-- XAudio2とMediaFoundationを使ったWAV/MP3再生その1 -->

# はじめに
C#のSystem.Media.SoundPlayerやWindowsAPIのPlaySoundでは音声の同時再生ができません。
XAudio2を使えば同時再生ができるので再生するまでの手順をまとめます。
また、Media Foundationを使ってMP3の再生を行います。  
その1ではまずXAudio2を使ってWAVを再生します。  
その2ではMedia Foundationを使ってMP3を読み込み、そのデータをXAudio2で再生します。

XAudio2とMediaFoundationを使ったWAV/MP3再生その2  
https://qiita.com/ryo_shiraishi6352/items/d4a40521bdb09c838e9d

# 参考にしたサンプル
本記事は以下のサンプルを参考に参考にしています。  
https://github.com/walbourn/directx-sdk-samples/tree/main/XAudio2/XAudio2BasicSound  
WAVの読み込み部分は以下のWAVFileReader.cppをそのまま使わせてもらいます。  
https://github.com/walbourn/directx-sdk-samples/blob/main/XAudio2/Common/WAVFileReader.cpp

# 動作環境
Windows10 + Visual Studio Community 2022  
Windows7以前ではフラグの指定方法などが異なり動かない可能性が高いので注意してください。

# XAudio2の初期化
XAudio2を使用するには以下のヘッダファイルとlibファイルを必要とします。
```cpp
#include <xaudio2.h>
#pragma comment(lib,"xaudio2.lib")
```

XAudio2の初期化をするにはCOMの初期化、XAudio2の初期化の順に行います。
```cpp
CoInitializeEx(nullptr, COINIT_MULTITHREADED);

IXAudio2* pXAudio2{ nullptr };
XAudio2Create(&pXAudio2, 0);
#if defined(_DEBUG)
XAUDIO2_DEBUG_CONFIGURATION debug{ 0 };
debug.TraceMask = XAUDIO2_LOG_ERRORS | XAUDIO2_LOG_WARNINGS;
debug.BreakMask = XAUDIO2_LOG_ERRORS;
pXAudio2->SetDebugConfiguration(&debug, 0);
#endif
```

# マスターボイスの作成
マスターボイスはIXAudio2オブジェクトから生成します。
```cpp
IXAudio2MasteringVoice* pMasteringVoice{ nullptr };
pXAudio2->CreateMasteringVoice(&pMasteringVoice);
```

# WAV読み込み
WAVの読み込みはWAVFileReader.cppにあるDirectX::LoadWAVAudioFromFileExを使用します。  
DirectX::WAVData waveDataはstd::unique_ptr<uint8_t[]> waveFileが実体なので
waveFileを破棄すると使えなくなります。
```cpp
std::unique_ptr<uint8_t[]> waveFile{ nullptr };
DirectX::WAVData waveData{ 0 };
DirectX::LoadWAVAudioFromFileEx(path, waveFile, waveData);
```

# ソースボイスの作成
マスターボイスはIXAudio2オブジェクトから生成します。
```cpp
IXAudio2SourceVoice* pSourceVoice{ nullptr };
pXAudio2->CreateSourceVoice(&pSourceVoice, waveData.wfx);
```

# 音声再生
読み込んだ音声データをSubmitSourceBufferでセットしてStartで再生します。
```cpp
XAUDIO2_BUFFER buffer{ 0 };
buffer.pAudioData = waveData.startAudio;
buffer.Flags = XAUDIO2_END_OF_STREAM;
buffer.AudioBytes = waveData.audioBytes;
pSourceVoice->SubmitSourceBuffer(&buffer);

pSourceVoice->Start(0);
```

# 終了まで待機
再生状況を確認してBuffersQueuedが0になるまでプログラムが終了しないように待機します。  
BuffersQueuedはバッファの残数を返しています。  
今回では1つのバッファしか処理させていないので最初は1で再生が終わると0になるのでそれで判定しています。
```cpp
while (true)
{
    XAUDIO2_VOICE_STATE state{ 0 };
    pSourceVoice->GetState(&state);
    if (state.BuffersQueued == 0)
    {
        break;
    }
    Sleep(10);
}
```

# XAudio2の終了
作られた順番に破棄していきます。
```cpp
pSourceVoice->DestroyVoice();
pMasteringVoice->DestroyVoice();
pXAudio2->Release();
CoUninitialize();
```

# おわりに
チュートリアルとほぼ同じ手順でXAudio2を使ってWAVファイルの再生を行いました。
その2ではMedia Foundationを使ってMP3の再生を行います。  
今回のコードは以下のところにおいています。  
https://github.com/ryo-shiraishi6352/Articles/blob/main/XAudio2Play.h
cscの作法 その97

# 概要
cscの作法、調べてみた。
dll使ってみた。

# dllの取得

- nugetでlitjsonを探す
- lithson.nupackをダウンロード
- 拡張子をzipにして解凍
- dll/.net20/からLitJSON.dllをコピー

# サンプルコード

```
using System.Collections;
using System.IO;
using System;
using System.Text;
using LitJson;

namespace Test 
{
	class test0 {
		static void Main() {
			Console.WriteLine("hello world!");
			string jsonFileName = "todo.json";
			string fileText = "";
			FileInfo fi = new FileInfo(jsonFileName);
			using (StreamReader sr = new StreamReader(fi.OpenRead(), Encoding.UTF8)) {
				fileText = sr.ReadToEnd();
				Console.WriteLine(fileText);
				LitJson.JsonData json = LitJson.JsonMapper.ToObject(fileText);
				Console.WriteLine(json["todo"][0]["task"]);
			}
		}
	}
}


```

# コンパイル手順

```
csc lit.cs /reference:LitJSON.dll

```

# 実行結果

```
>lit
hello world!
{"todo":[{"task":"test0","assignee":"A"}]}
test0

>
```

以上。
Power Query workout - File.Contents

どのように動作しているのか知らずとも多くの機会で利用する Power Query の関数。それが File.Contents。でも、想像より複雑にかつ合理的な動作をしているはずなのである。

Power Query でファイル( binary )を読み込むときの動作には、
- 可能な限り少ない読み込みで完了すること
- ソースデータのファイルフォーマットごとで適した動作をしていること

という特徴があって、

```text
Csv.Document(
    File.Contents( ... )
)
```

のような利用であるけれども、File.Contents でファイルを取得し Csv.Document で解釈するという理解では Power Query の特徴を表しきれない。File.Contents で binary 読込完了 → 次の処理(ステップなど) ということではなく、次以降の処理を勘案し File.Contents での binary 読込 がコントロールされるのだ。

# ウォームアップ

https://docs.microsoft.com/en-us/powerquery-m/file-contents

**構文と例**

```text:File.Contents&#x20;(Power&#x20;Query)
File.Contents(
    path as text,
    optional options as nullable record
) as binary
```

> Returns the contents of the file, path, as binary. The options parameter is currently intended for internal use only.

*path* 引数は絶対パスを表現する文字列でファイルシステムよりファイル (*binary*) を取得する動作をする。単独で利用することは少ない。

# 鍛錬
**フラットファイル データソース がわかりやすい**
改行文字を区切りとして テーブル でいうところの行として読み込むとき、可能な限り必要な部分を読み込む動作を観察。
テキストファイルや CSV ファイルなどは、4096 byte ごとで読み込むことがわかっているから、改行文字含め 4096 byte を 1 セット(1 行) 10 セット(10 行)の ソールファイル を読み込む経過を観察。 

テーブルとして読み込み、行ごとの処理( Table.AddColumn ) を意図的に遅らせ( Function.InvokeAfter )、その時の時刻( DateTime.LocalNow )を記録。このとき、Process Monitor で ReadFile を記録。
```text:SourceQuery&#x20;(Power&#x20;Query)
let
    Source = File.Contents(SourceFile),
    BinaryToLines = Lines.FromBinary(Source),
    ListToTable = Table.FromColumns({BinaryToLines}),
    AddedColumn2 = Table.AddColumn(
        ListToTable,
        "Column2",
        each Function.InvokeAfter(
            ()=>DateTime.ToText(
                {[Column1], DateTime.LocalNow()}{1},
                "hh:mm:ss.fffffff tt"
            ),
            #duration(0,0,0,1)
        ),
        Text.Type
    ),
    SelectColumn2 = Table.SelectColumns(
        AddedColumn2,
        {"Column2"}
    )
in
    SelectColumn2
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193509/73768684-afaa-799e-6993-a6acea60f07a.png)
意図的に遅延させた行ごとの処理( Table.AddColumn ) に一致するように ReadFile が行われる。
```text:Query1&#x20;(Power&#x20;Query)
// Query1
let
    Source = SourceQuery,
    First5Rows = Table.FirstN(Source,5)
in
    First5Rows
```
このクエリ(SourceQuery)の先頭 5 行だけ読み込む( Table.FirstN ) とすれば、ReadFile は 5件で済む。
```text:Query2&#x20;(Power&#x20;Query)
// Query2
let
    Source = SourceQuery,
    Last5Rows = Table.LastN(Source, 5)
in
    Last5Rows
```
最後 5 行だけ読み込む( Table.LastN ) とすると、ReadFile は 10 件。ただし、遅延させた行ごとの処理( Table.AddColumn ) 5 行分は ReadFile 10 件 すべて完了してからになる。
```text:Query3&#x20;(Power&#x20;Query)
// Query3
let
    Source = SourceQuery,
    Skip5Rows = Table.Skip(Source,5)
in
    Skip5Rows
```
先頭 5 行をスキップ( Table.Skip ) したとき、先頭 5 行分では 遅延させた行ごとの処理( Table.AddColumn ) は発生しない。スキップ完了以降の処理については、遅延させた行ごとの処理( Table.AddColumn ) 通りに ReadFile が発生する。

# その他
https://powerbi.connpass.com/

- [Power BI 勉強会 - connpass](https://powerbi.connpass.com/)
- [Power BI Desktop を使い始めるには](http://qiita.com/PowerBIxyz/items/6c4735cb5b5712e70981)
- [Excel で Power Query を使い始めるには](http://qiita.com/PowerBIxyz/items/52e563037b855a099ca9)
MacBook Pro 2015でWindowsがUEFIネイティブでインストールできない

# tl;dr
回復ドライブを作ってそこから起動してShift+F10を押してどこかしらに置いてあるsetup.exeを実行する.
またはrEfindを用意しUEFI:NTFSで起動する．

# 原因
MacBook ProのUEFIがこいつだけUEFI2.X非対応っぽい．
2013 lateは対応してるのに...

# その後
ちゃんと起動はするので延命できるよ！やったね！