OmniAICreator/Qiita-1.07M huggingface dataset:
Unity AdsのGoogle Playのデータセーフティ設定

本記事は2022年4月頃に書きました。最新のGoogle Play Storeのポリシーと噛み合っていない可能性があるため、ご注意ください！

### 前書き
こんにちは、ユーゴです。
今回は、Unityでゲーム開発して、**Unity Adsを入れている**場合のGoogle Playでの**データ収集設定**について紹介します。
Google Playのプライバシーポリシーの設置義務化が2022年4月から始まり、エンジニアは対応に迫られていることかと思います。Google Playは年会費がかからず一括払いで簡単に登録でき、ダッシュボードの指示に従って楽に登録できましたが、「**プライバシーポリシーの設置**」「**データ収集の設定**」が追加され、これからはかなり敷居が高くなりそうです。私も個人開発をしている身として、大変な思いをしています。
データ収集の設定では様々な項目があり、どれを設定していいのかわかりにくいかと思います。
設定に失敗してリジェクトならまだしも、アカウント停止などの重い厳罰があったら怖い...と思う人も多いはずです。私もその一人でした。そんな皆様の手助けになればと、本記事を執筆いたしました。

なお、本記事に書いてあることを参考にして生じた如何なる損害に対し、**筆者は責任を負いかねます**。他のソースと比較して、多面的な視点から当記事の内容を判断してください。

# 1.データセーフティの回答
# 1-0.参考
回答していく前に、以下も参考にするといいでしょう。
・[Google Play data safety section for Unity Ads](https://docs.unity.com/ads/GoogleDataSafety.html)
・[Apple privacy survey](https://docs.unity.com/ads/ApplePrivacySurvey.html)
・[Unity Ads、Unity Analyticsを利用する開発者・パブリッシャー向けGDPR関連情報](https://blog.unity.com/ja/games/gdpr-monetization-services-jp)

# 1-1. データ収集とセキュリティ

「アプリは対象になる種類のユーザーデータを収集または共有しますか？」
→はい

「アプリで収集するユーザーデータはすべて、転送時に暗号化されますか？」
→はい

「自分のデータの削除をリクエストする方法をユーザーに提供していますか？」
→はい

## 1-2.データの種類&データの使用と処理
ここは厳密には2ステップですが、原文通りまとめて書いた方が見やすいのでまとめて書きます。
なお、開発者が特別な設定をすると項目が変わる箇所があるそうです。ただUnityAds差し込んだという人は問題ないですが、UnityDashboardで設定を変えている人などは原文に目を通してください。
|分類|収集する情報|収集|共有|一時的に処理されるか|必須か|目的|
|-|-|-|-|-|-|-|
|場所|おおよその現在地|はい|はい|いいえ|はい|アプリの機能<br>分析<br>広告、マーケティング<br>不正防止、セキュリティ、コンプライアンス|
|個人情報|ユーザーID|はい|はい|いいえ|はい|アプリの機能|
|財務情報|購入履歴|はい|はい|いいえ|いいえ|分析<br>広告、マーケティング|
|アプリのアクティビティ|アプリ インタラクション数|はい|はい|いいえ|はい|分析<br>広告、マーケティング<br>不正防止、セキュリティ、コンプライアンス|
|アプリのアクティビティ|その他の操作|はい|はい|いいえ|はい|分析<br>広告、マーケティング<br>不正防止、セキュリティ、コンプライアンス|
|アプリの情報、パフォーマンス|診断情報|はい|はい|いいえ|はい|アプリの機能<br>分析|
|デバイスまたはその他のID|デバイスまたはその他のID|はい|はい|いいえ|はい|アプリの機能<br>分析<br>広告、マーケティング<br>不正防止、セキュリティ、コンプライアンス|

# 2.まとめ
いかがでしたでしょうか。
なぜか検索してもUnity公式の原文が見つからず、サードパティの広告サイトからUnityの原文を見つけました。おそらく、他の方も検索で出てこなく苦労されているかと思い、記事を書きました。

私はこのように、痒いところに手が届くようなニッチな記事からUnityの基本的な使い方まで、様々なことを書いていこうと思います。よろしければご登録お願いいたします。
PyPi に自分で作ったモジュールを登録する

Pythonでパッケージを作って、PyPIに登録した時の作業メモ

今回の対象プロジェクト
[sasaco/FEMPython](https://github.com/sasaco/FEMPython)

## 目的
自作モジュールをPyPIへ登録してpip installでインストールします。今回は簡単なコードを実装して使います。

## 方法

基本的に[公式のチュートリアル](https://packaging.python.org/en/latest/tutorials/packaging-projects/)に従います。個人的なこだわりで、wslを使ったりgithubに上げたり、仮想環境をpyvenvで作ったりしてますが、今回はそういう事が無くても出来るようにしているつもりです。何回かコマンドを使う必要がある為、そこで引っかかるかもしれません。そこは他の記事にお任せします。または後日、更新します。

## 必要なディレクトリやファイルを作る

```
FEMPython/
├── LICENSE
├── pyproject.toml
├── README.md
├── setup.cfg
├── src/
│   └── FEMPython/
│       ├── __init__.py
│       ├── AdvancedElement.py
│       ├── BarElement.py
│       ├── ....
│       └── Solver.py
└── tests/
```

[公式のチュートリアル](https://packaging.python.org/en/latest/tutorials/packaging-projects/)のままです。これを任意の場所に作ります。僕はデスクトップにPyPIフォルダを作ってその中で作業しています。

## pyproject.tomlの編集

pyproject.toml は、ビルドツール（pip や build など）に対して、プロジェクトのビルドに必要な情報を伝えます。このチュートリアルでは setuptools を使用しますので、pyproject.toml を開いて以下の内容を入力してください。

```
[build-system]
requires = ["setuptools>=42"]
build-backend = "setuptools.build_meta"
```


## setup.cfgの編集

前はsetup.pyを作るのが公式だったようですが、今はsetup.cfgとpyproject.tomlを使うようです。中身は公式にお任せしますが、変更点についてだけ、お話します。赤枠で囲まれている所を変更します。

```
[metadata]
name = FEMPython
version = 0.0.1
author = sasaco
author_email = sasaicco@gmail.com
description = A small example package
long_description = file: README.md
long_description_content_type = text/markdown
url = https://github.com/sasaco/FEMPython
project_urls =
    Bug Tracker = https://github.com/sasaco/FEMPython/issues
classifiers =
    Programming Language :: Python :: 3
    License :: OSI Approved :: MIT License
    Operating System :: OS Independent

[options]
package_dir =
    = src
packages = find:
python_requires = >=3.6

[options.packages.find]
where = src
```

## buildする

次のステップは、そのパッケージの配布用パッケージを生成することです。これは Python Package Index にアップロードされるアーカイブで、pip でインストールすることができます。

### 最新版のbuildがインストールされていることを確認します。

```
python -m pip install --upgrade build
```

### 次に、pyproject.tomlがあるのと同じディレクトリから、このコマンドを実行します。

```
python -m build
```

このコマンドが完了するとdistディレクトリに2つのファイルを生成するはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142847/86ca5c40-c673-6007-5c2b-236ee901563e.png)

## PyPITestへの登録

まずはじめに、あなたのパッケージをPython Package Indexにアップロードしましょう

### 最新版のtwineがインストールされていることを確認します。

```
python -m pip install --upgrade twine
```

### PyPITestへの登録

```
python -m twine upload --repository testpypi dist/*
```

## PyPITestへの登録

最後に、あなたのパッケージをPython Package Indexにアップロードしましょう

```
python -m twine upload dist/*
```


# 参考
- [公式のチュートリアル](https://packaging.python.org/en/latest/tutorials/packaging-projects/)
- [自作モジュールをPyPIに登録する](https://qiita.com/tan0ry0shiny/items/c04ccdf840d198d2759e)
アセットのUnityインポート時デフォルト設定を変更する

アセットをUnity Editorにドラッグアンドドロップした後、毎回Inspectorで同じ設定変更を行っていました。  
これを自動化できないかと調べたところ、Preset Managerという仕組みでできるようだったのでまとめてみました。  
Unity 2018以降で使えるらしいです。

<details><summary>元々の動機：VRChatでのfbxインポート</summary>
VRChatではアバター向けのfbxファイルをインポートする度に以下の設定が必要です。これを毎回やるのが億劫な上、デフォルトの設定ではインポートにやたら時間がかかるのでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137387/d03b802f-2ff5-90b4-0a8b-5cdeba31cfdf.png)

</details>

以下では、fbxのインポート設定を変更する例を示します。たぶん他のファイルでも同様にできると思います。

## 1. プリセットを作成する

適当なfbxファイルをUnity Editorにドラッグアンドドロップで追加し、Inspectorを開きます。

デフォルトにしたい設定変更を行ってApplyした後、右上のボタンをクリックします。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137387/7ff6091a-4854-d021-c555-5ea5c2b5cbe2.png)

プリセットのウィンドウが開くので、 `Save current to...` をクリックして適当な名前で保存します。  
ここでは、`FBXImporter.preset`という名前でAssets直下に保存しました。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137387/0b179d83-2d6f-25ae-c71e-512b4e270559.png)

## 2. デフォルトのプリセットに設定する

1で作成したpresetファイルを選択し、Inspectorで`Add to FBXImporter default`をクリックします。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137387/8775f7b6-fb0f-7c83-eb37-dafb9d7d4c64.png)

この状態でメニューからEdit -> Project Settings...を開き、Preset Managerの項目を選択すると、FBXImporterの項目にPresetが設定されていることを確認できます。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137387/d0dc4bdb-690f-2ff2-d1e6-dbdf35ecb824.png)

([Unityマニュアル](https://docs.unity3d.com/2019.4/Documentation/Manual/class-PresetManager.html)によると、この状態でFilterに `glob:"Models/*.fbx"` のような記述を行うことで、特定フォルダー以下にのみプリセットを適用することもできるらしいです。)

## 3. ファイルを実際にインポートしてみる

この状態で新たにfbxファイルをUnity Editorにドラッグアンドドロップすると、プリセットで指定した状態でインポートすることができました。ヤッタネ！
StackyPiを試す

# 1. 概要
Raspberry Piの RP2040 をMCUとして搭載した開発ボード StackyPi を入手したのでまずは動かしてみる。
ホスト側はWindows11。

こんなパッケージされている。Raspberry Pi Zeroっぽくみえるが、Picoの親戚。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865486/7a26f4c9-80ad-36fd-630c-a6d481c419ae.png)

中身
SDカードスロットが便利に使えるか…？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865486/114fcc71-2cfa-1ed4-9702-4987d4b6a3e5.png)

# 2. 準備
## ハード
電源供給のためにUSB microBのケーブルが必要。

## 2.1 ソフト 
開発用のソースコード
https://github.com/sbcshop/StackyPi
今回は使わないが、READMEとか読んでおくとよし。

統合開発環境 (IDE) 
とりあえずThonny
https://thonny.org/

# 3. 動作確認する
Picoと同じでBOOTボタンを押しながら、電源供給開始（USBケーブルを挿す）する。するとドライブが見える。
何もせずに挿すと赤LEDが光るだけなので、README読まない人はここで挫折するらしい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865486/de03bc63-6eb5-ada7-3c93-3a6130d60fa6.png)

勝手にオープンされるドライブ。見覚えがある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865486/8c5fb003-c617-521c-0f39-bb3a5e078115.png)

中にあるINDEX.HTMをダブルクリックして、サイトを開く。

MicroPythonから先に進む。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865486/29072cf6-9fdf-8de2-a27c-0331478489b2.png)

ページ途中の以下の文/リンクからUF2 fileをダウンロードする。
試したときは、rp2-pico-20220117-v1.18.uf2 だった。
```
Download the MicroPython UF2 file.
```

さっき開いたドライブ RPi-RP2 にダウンロードしたファイルをドラッグしてコピーする。コピーが終わると、ウインドウは自動的に閉じる。これでPythonのコマンドが動くようになった。

## とりあえずLチカ
ThonnyからPythonコマンドを送信する。
右下のモードを「MicroPython (Raspberry Pi Pico) 」にしておく。
```
from machine import Pin
led = Pin(25, Pin.OUT)
led.value(1)
```

IDE上はこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865486/936249da-45ae-f289-b5f8-777f719251c1.png)

青く光ってる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865486/968ce80b-c546-a09f-9ceb-2dd6f8a8a05e.png)

# 4. 結論
あれ？Picoとやっていることが変わらないよ！
ちょっとボードを生かすことをしないといかんですね。
とりあえず起動しないとかの初期不良がないことは分かった。

以上
【備忘録・Rails】devise導入で使えるメソッド

## はじめに

こんにちは、だいごです。
今回は、deviseを導入することで使えるようになるメソッドをまとめていきます。
よかったらご覧ください。

## ヘルパーメソッド一覧

- **before_action :authenticate_user!**
- **user_signed_in?**
- **current_user**
- **user_session**

※モデル名がuserの場合を想定しています。　

ここからは一つ一つを詳しく解説します。

### before_action :authenticate_user!

ログイン状態によって表示するページを切り替えるdeviseのメソッド。
処理が呼ばれた段階で、ユーザーがログインしていなければ、そのユーザーをログイン画面に遷移させます。

```rb:messages_controller.rb
class MessagesController < ApplicationController
  before_action :authenticate_user!

  def index
  end

  def new
  end
end
```

上記のように記述した場合には、ログインしたユーザーのみメッセージ一覧と新規投稿に遷移することができます。
また、onlyオプションやexceptオプションを用いることで、特定のアクションのみに制限をかけることもできます。

```rb:messages_controller.rb
class MessagesController < ApplicationController
  before_action :authenticate_user!, only: :new

  def index
  end

  def new
  end
end
```

上記のように記載した場合には、メッセージ一覧には誰でも遷移することができ、
新規投稿にはログインしたユーザーのみ遷移することができます。

### user_signed_in?

ユーザーがログインしているか否かを判断できるdeviseのメソッド。
コントローラー、ビューを問わずに使用することができます。

```erb:application.html.erb
<%# 省略 %>

  <body>
    <header class="header">
      <div class="header__bar row">
        <h1 class="grid-6"><a href="/">MessageApp</a></h1>
        <% if user_signed_in? %>
          <div class="user_nav grid-6">
            <%= link_to "ログアウト", destroy_user_session_path, method: :delete %>
            <%= link_to "投稿する", new_message_path, class: "post" %>
          </div>
        <% else %>
          <div class="grid-6">
            <%= link_to "ログイン", new_user_session_path, class: "post" %>
            <%= link_to "新規登録", new_user_registration_path, class: "post" %>
          </div>
        <% end %>
      </div>
    </header>

<%# 省略 %>
```

上記のように記載した場合には、ログイン状態によってビューを変えることができます。

### current_user

ログインをしているユーザーの情報が取得できるdeviseのメソッド。
コントローラー、ビューを問わずに使用することができます。

```rb:messages_controller.rb
class MessagesController < ApplicationController
  
# 省略

  def create
    Tweet.create(message_params)
  end

# 中略

  private

  def message_params
    params.require(:message).permit(:name, :image, :text).merge(user_id: current_user.id)
  end

end
```
上記のように記載した場合には、メッセージと作成したユーザーを紐づけることができます。

### user_session

ユーザーのセッション情報を設定・取得することができるdeviseのメソッド。

## おわりに
今回はdeviseのヘルパーメソッドについてまとめました。
user_sessionに関しては使用したことがなかったため、今回は簡単な説明のみとなっています。
今後使用する機会があったら追記しようと思います。
ご指摘・コメントお待ちしてます。
ありがとうございました。

## 参考
https://qiita.com/tobita0000/items/866de191635e6d74e392
Laravelでcomposer updateでメモリオーバー

# [<font color="#333">composer updateでメモリオーバー</font>](#-1.composerupdateでメモリオーバー)
そもそも、AWSの無料枠で個人開発レベルのLaravelをデプロイしようとしたところで
中々メモリオーバーでタイムアウトにはならないはず。

まずは他にメモリを食っている原因を探ってみましょう。
例えば無料のセキュリティ対策ソフト
***clamAV***なんかはメモリ使用量が多く、無料利用枠のインスタンスだとclamAVが起動した
状態でcomposer update等を行うと十中八九メモリオーバーでしょう。

なので、その場合はclamAVの使用の有無の検討や対策が必要です。
ここがまず本質。
下記の記事などを参考にしてみてください。
面倒ではありますが、clamAVやApacheの再起動をいちいちする等の対策です。

https://inaba-serverdesign.jp/blog/20170919/clamav_scan_virus_manage.html

http://www.playstudy.net/blog/develop/amazonec2-clamav.html

# [<font color="#333">メモリ制限解除</font>](#-2.メモリ制限解除)
とはいえめんどくさいのでさっさと解決したい方はこちらを実行。
ターミナルでEC2のwebサーバー内にて
```
vim /etc/php.ini
```

下記の記述を探して「memory_limit」を-1に変更
```
; Maximum amount of memory a script may consume (128MB)
; http://php.net/memory-limit
memory_limit = -1
```
# [<font color="#333">スワップ生成</font>](#-3.スワップ生成)
それでもダメならスワップファイルを作成
スワップファイルとは簡単に言うと<font color="red">***使ってないメモリの内容を一時的にハードディスクにしまっておくファイル***</font>の事。
例えば10GBのファイルがメモリにあっても常に10GB MAXで使ってる訳ではありません。
使ってない分のスペースは勿体無いのでスワップファイルに一旦どかしてメモリの空きスペースを作ります。

それが下記の記述で行えます。
ちなみに sudo -iで実行権限を変更している前提です。
```
/bin/dd if=/dev/zero of=/var/swap bs=1M count=1024
/sbin/mkswap /var/swap

```
これで再度composer updateしてみてください。

できたらいつまでもハードディスクにスワップファイルがあってもその分使用してしまってるので削除した方が良いでしょう。
```
swapoff /var/swap
rm /var/swap
```
Spotify App の Setting での 'Not a valid SHA1 Fingerprint'エラー



# エラー

SHA1 fingerprint 入力欄は、(16進数表記で)20桁でないと、
> Not a valid SHA1 Fingerprint

エラーを吐く。
![スクリーンショット 2022-04-17 15.53.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305802/8889b888-f341-1cf7-5fb3-bd3601e1152f.png)

# 解決策
↓のspotify公式記事で書かれているコード実行で取得できるSHA1 fingerprintは32桁になった。

https://developer.spotify.com/documentation/android/quick-start/


↓こちらの方法で20桁のSHA1 fingerprintを取得できた。解決

https://www.petitmonte.com/java/fingerprint_android.html
Unity AdsのApp Storeのデータ収集の設定(Appのプライバシー)

### 前書き
こんにちは、ユーゴです。
Unityで作ったゲームで、**Unity Ads**を取り入れている場合のApp Storeでの**データ収集設定**について紹介します。データ収集の設定では様々な項目があり、どれを設定していいのかわかりにくいかと思います。設定に失敗してリジェクトならまだしも、アカウント停止などの重い厳罰があったら怖い...と思う人も多いはずです。私もその一人でした。そんな皆様の手助けになればと、本記事を執筆いたしました。
Google Playでも似たような回答があるので、Androidエンジニアの方も是非参考にしてみてください。

##### なお、本記事を参考にすることで生じた損害等について、一切の責任を負いかねます。他のソースと比較しながら、自己責任で情報を利用してください。

# データ収集の設定
まず、探し出すのが難しいですが、Unity公式がデータ収集の一覧表を作ってくれています。こちらが非常に参考になりました。本記事では記入ミスがあるかもしれないので、ご自身でも一度ご覧ください。
[Apple privacy survey](https://docs.unity.com/ads/ApplePrivacySurvey.html)

まとめると、以下のようになります。

|分類|収集するデータ|目的|個人情報に関連するか|トラッキングするか|
|-|-|-|-|-|
|位置情報|おおよその場所|サードバティ広告<br>アナリティクス|いいえ|いいえ|
|ユーザコンテンツ|カスタマーサポート|Appの機能|いいえ|いいえ|
|ID|ユーザID|Appの機能|はい|いいえ|
|ID|デバイスID|サードパティ広告<br>アナリティクス|はい|はい|
|購入|-|サードパティ広告<br>アナリティクス|はい|はい|
|使用状況データ|製品の操作|サードパティ広告<br>アナリティクス|いいえ|いいえ|
|使用状況データ|広告データ|サードパティ広告<br>アナリティクス|はい|はい|
|使用状況データ|その他の使用状況データ|サードパティ広告<br>アナリティクス|はい|はい|
|診断|パフォーマンスデータ|アナリティクス<br>Appの機能|はい|いいえ|
|その他のデータ|-|サードパティ広告<br>アナリティクス<br>Appの機能|はい|はい|

# 終わりに
いかがでしたでしょうか。Google Playでも似たような回答があると思うので、Androidエンジニアの方も参考にしてみてください。
AWS ALB スティッキーセッション メモ

## スティッキーセッションとは

* ロードバランサーがクライアント状態を管理するために使用する情報。
  * ロードバランサーを用いて負荷分散を行う場合に、セッション管理を行うWebアプリなどで毎回同じサーバーにアクセスさせるために利用する。

## AWS ALBのスティッキーセッション

* AWS ALB（Application Load Balancer）ではCookieを利用したスティッキーセッション機能を利用することができる。
* 次の2種類のスティッキーセッション機能を提供している。

### 期間ベースCookie

* ロードバランサーが生成した Cookie (`AWSALB`) を使用し、ターゲットグループ内の同じターゲットにリクエストをルーティングする。

* **フロー**

  1. ロードバランサーは、クライアントから最初のリクエストを受信した際、リクエストをターゲットにルーティングし、`AWSALB` という名前のCookie を生成し、ターゲットからのレスポンスにセットする。

     * ターゲットに関する情報をエンコードしてCookie を暗号化し、クライアントへの応答に Cookie を含める。

  2. クライアントは 、`AWSALB`Cookie を含めて後続のリクエストを行う。

  3. ロードバランサーは、 Cookieを含んだリクエストを受信し、同じターゲットにリクエストをルーティングする。

     ![ss_alb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586535/4742b950-4382-1123-1fd2-c3d3cd74b2f9.png)


### アプリケーションベースCookie

* アプリケーション側で生成した独自のCookieをALB設定に指定し、そのCookieを使用して、ターゲットグループ内の同じターゲットにリクエストをルーティングする。

  * 期間ベースよりもより柔軟なセッション維持が可能。

* **フロー**

  1. ロードバランサーはターゲットグループ内のターゲットに最初のリクエストをルーティングする。

  2. ターゲットは、ロードバランサーで設定したCookieと同じアプリケーションCookieをレスポンスに設定する。

  3. ロードバランサーは、ターゲットからアプリケーションCookie を受信すると、持続性情報をキャプチャする新しい暗号化されたアプリケーションCookieを生成する。

  4. クライアントは、両方のCookieをセットして後続のリクエストを行う。

  5. ロードバランサーは、アプリケーションCookieを復号し、設定した持続期間が有効かどうかを確認する。その後、Cookie内の情報を使用して、ターゲットグループ内の同じターゲットにリクエストを送信する。

     ![ss_app.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586535/18dc6a80-3a08-0c49-4798-f8e9d803a022.png)


## AWS CLIでの設定

* 期間ベースCookie

  ```shell
  aws elbv2 modify-target-group-attributes --target-group-arn ARN --attributes Key=stickiness.enabled,Value=true Key=stickiness.lb_cookie.duration_seconds,Value=time-in-seconds
  ```

  

* アプリケーションベースCookie

  ```shell
  aws elbv2 modify-target-group-attributes --target-group-arn ARN --attributes Key=stickiness.enabled,Value=true Key=stickiness.type,Value=app_cookie Key=stickiness.app_cookie.cookie_name Value=my-cookie-name Key=stickiness.app_cookie.duration_seconds Value=time-in-seconds
  ```

  

## 参考情報

* [Application Load Balancer のスティッキーセッション](https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/sticky-sessions.html)
「USBコントローラーのリソースの超過」が発生した話

同じような不具合がTwitterでも散見されたので備忘録として残します。

# 摘要
- 「USBコントローラーのリソースの超過」が発生した
- USBドライバを全て再インストールしたら直った
- キーボードとマウスをUSB接続した状態でドライバを消すと当然詰むので気をつけよう

# 異変発生
ある日、突如通知音とともに表示された警告が発生した。
![unknown.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165220/7ee94e1c-9ed3-252b-d9b7-0193be0170c2.png)

全く意味がわからないのでクリックしてみると、どうやらUSBコントローラーのリソースが超過したらしい。なるほどわからん。

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165220/7964446d-7f17-1b17-a0f0-04283c7c3f00.png)

とりあえず無視してDiscordでボイチャをしていると異変が。
なんとヘッドセットのマイクとイヤホンが同時に機能しないのだ。
筆者のPCには4極端子がないのでType-C接続のUSBサウンドカード(イヤホンジャックのないスマホに使うようなやつ)を利用していたのだが、どうやらUSBコントローラーのリソースが超過したことでType-Cで入力と出力を同時に処理することができなくなったらしい。

# 試行錯誤
USB接続し過ぎとか…？でも別にいつもと変えてないし…と思いながらググるとやはりUSB3.0は許容数が少ないから減らせという記述を見つけ、マウスとキーボード以外を外して見るも変化はない。

他のPCでは正常に動作することからサウンドカードの故障でもなさそうだ。

やはりドライバに問題が…と思い再インストールのためアンインストールする作業に入る。

そしてやらかす。

当たり前なのだが、USBドライバを削除したらUSB機器は使えなくなる。キーボードとマウスをUSB接続で利用していた筆者は泣く泣く電源ボタンを長押しすることになった。

結局リモートデスクトップで操作したのだが、それができない場合はBluetooth接続のものを使うとか、devcon.exeとshutdownコマンドをバッチファイルとかで駆使するしかないかもしれない。

# 解決
というわけでUSBドライバを全てアンインストールして再起動し、自動再インストールを行ったところ、1つだけなぜか自動インストールできないものがあった。
NVIDIAということは覚えていたのでとりあえずGeForce Experienceからドライバの更新を行ってみたら無事インストールされた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165220/364af0fe-a2ca-d0a9-a231-5385cf1d658d.png)
Type-C Port Policy Controllerという名前があまりにもそれらしい。
しかし何故にマザボのUSB端子にNVIDIAのドライバが必要なのだろうか…
ちなみにこのドライバだけアンインストール時に「このデバイスのドライバーソフトウェアを削除します」というチェックボックスがあったのでチェックしておいていた。

結局全て再インストールしてしまったので原因がどれだったのかはわからなかったが、やはりType-C Port Policy Controllerが怪しいなぁという感じ。
でもこれ単体でアンインストールしたときは直らなかったような気がするんだよな…

ドライバの破損の原因の心当たりは、昨日WindowsUpdateでフリーズしてぶっちぎったこと…ちゃんとdismとsfcで修復はしたんだが。
何はともあれ、リストアまで大袈裟な自体にならなくてよかった…
API Gateway - Lambda構成でのアクセス制御方法 メモ

* API Gateway - Lambda構成のサーバーレスアプリケーションにおけるアクセス制御方法についてメモする。



## IAMアクセス権限パターン

![api_gc_iam.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586535/a867d963-8b8f-3c27-766b-78ce76ca6b24.png)

1. IAM Credential sigv4 を作成し、sigv4を含めてAPIリクエスト
2. sigv4の権限を検証する。
3. 問題ない場合はLambdaをコールする。



## Amazon Cognito UserPoolを利用する

![api_gc_cognito.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586535/8784ed12-c51e-f44c-e6dd-a79f450633ab.png)

1. ユーザーサインアップ(トークン取得)する。
2. トークンを含めてAPIリクエストする。
3. トークン検証し、Lambdaコールする。

## Lambda Authorizer

![api_gc_auth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586535/4da177c6-fedb-815e-14b0-e9cf3517f06f.png)


1. クライアントから認証トーク ンやパラメータ付きのリクエストを行う。

2. Authorizer 関数をコールする。

   * Authorizer 関数内で認証認可ロジックを評価

   * 評価結果ポリシーを返却

     * 成功例

       ```json
       {
         "Version": "2012-10-17",
         "Statement": [
           {
             "Action": "execute-api:Invoke",
             "Effect": "Allow",
             "Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/"
           }
         ]
       }
       ```

       

     * 失敗例

       ```json
       {
         "Version": "2012-10-17",
         "Statement": [
           {
             "Action": "execute-api:Invoke",
             "Effect": "Deny",
             "Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/"
           }
         ]
       }
       ```

       

3. API Gateway が返却されたポ リシーを評価し、APIロジック用Lambdaをコールする。



## Private API

![api_gc_private.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586535/a12b6477-7300-2a52-b41f-e445c40fef41.png)


* 特定VPCからのリクエストのみを受け付ける場合、VPCエンドポイント経由アクセスする。

  * API Gatewayのリソースポリシーで制御する。

    ```json
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": "*",
                "Action": "execute-api:Invoke",
                "Resource": [
                    "execute-api:/*"
                ]
            },
            {
                "Effect": "Deny",
                "Principal": "*",
                "Action": "execute-api:Invoke",
                "Resource": [
                    "execute-api:/*"
                ],
                "Condition" : {
                    "StringNotEquals": {
                       "aws:SourceVpc": "vpc-1a2b3c4d"
                    }
                }
            }
        ]
    }
    ```

   

## 参考情報

* [API Gateway での REST API へのアクセスの制御と管理](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/apigateway-control-access-to-api.html)
【Java_for文】

現在、書籍にてJavaを学習中です。
この投稿はその備忘録になります。

## for文
for文とは、以下のように処理を指定した回数だけ繰り返す構文です。
```java
public class App{
 public static void main(String[] args){
  for (int i = 1; i < 10; i++){
   System.out.println(i + "回目の繰り返しです");
  }
 }
}
```
#### ■for (①; ②; ③)内のそれぞれが持つ意味
①初期化処理
`ループ変数`を定義する。

②繰り返し条件
このループを継続するか否かを判定する条件式を書く。

③繰り返し時処理
for文内のブロックを最後まで処理して『 } 』まで到達した直後に実行される文。
(通常は、インクリメント・デクリメント演算子を用いた加算・減算を書きます)

#### ■ループ変数のルール
①変数名は自由
ただし、すでに宣言されている変数名は使えない

②ブロック内で利用可能
ループ変数が使えるスコープはそのブロック内でのみ利用できます。


以上になります。
ローカル fluentd 検証環境構築方法 メモ


* 学習目的でfluentd検証環境をローカルにDocker を使用して作成した。備忘録としてメモしておく。


## コード

* FastAPI製テスト用APIへのアクセスログをfluentdで収集する。

### 構成

```
project	- app		-	api - main.py
					|_	Dockerfile
					|_	requirements.txt
		- fluentd	-	config	- fluent.conf
					|_	tmp
		- docker-compose.yml
```



### docker-compose.yml

* テスト用APIコンテナとfluentdコンテナの起動設定

```yaml
version: "3.5"

networks:
  container-link:
    name: docker.internal
services:
  app:
    container_name: "app"
    build: ./app
    volumes:
      - ./app/api:/usr/src/server
    logging:
      # ログ出力先にfluentdを指定
      driver: "fluentd"
      options:
        # fluentdサーバの宛先
        fluentd-address: "localhost:24220"
        # ログに付与するタグ
        tag: "docker.{{.Name}}"
    ports:
      - "8000:8000"
    networks:
      - container-link
  fluentd:
    image: fluent/fluentd:latest
    container_name: "fluentd"
    ports:
      - "24220:24220"
      - "24220:24220/udp"
    environment:
      - 'FLUENTD_CONF=fluent.conf'
    volumes:
      - ./fluentd/tmp:/fluentd/log
      - ./fluentd/config:/fluentd/etc
    networks:
      - container-link
```

### fluentdコンテナ

#### fluent.conf

* fluentd設定ファイル
* `<source>`：ログの待ち受け先を指定。今回の場合は24220番ポートを指定。
* `<match>`：ログの出力先を指定。今回の場合は標準出力（コンテナログ）を指定。

```conf
<source>
  @type forward
  port 24220
</source>

<match docker.**>
  @type stdout
</match>
```



### テスト用APIコンテナ

#### Dockerfile

* Python3.8イメージを基に依存ライブラリインストールとFastAPIアプリ起動用設定を記述

```dockerfile
FROM python:3.8

WORKDIR /usr/src/server
ADD requirements.txt .
RUN pip install -r requirements.txt

# uvicornのオプションに--reloadを付与し、
# main.pyの編集と同時に変更内容を反映させる。
CMD ["uvicorn", "main:app", "--reload", "--host", "0.0.0.0", "--port", "8000"]
```

#### requirements.txt

* 依存ライブラリ設定

```txt
fastapi
uvicorn
```

#### main.py

* パスパラメータに指定したユーザーIDをそのまま返却するテスト用API

```python
import uvicorn
from fastapi import FastAPI
app = FastAPI()

@app.get("/v1/users/{user_id}")
def users(user_id):
    user = {
        "user_id":user_id
    }
    return user


if __name__ == "__main__":
    uvicorn.run(app, port=8000, loop="asyncio")
```



## 動作確認

### 起動

```shell
docker-compose up
```

### リクエスト・レスポンス

```http
GET /v1/users/12345 HTTP/1.1
Host: localhost:8000
```

```
{
    "user_id": "12345"
}
```

### ログ出力

```
fluentd    | 2022-04-17 03:45:44.000000000 +0000 docker.app: {"container_id":"90f01401bb27c886a9fedc956978af3fd2775cde97176371feccc7da13eaa737","container_name":"/app","source":"stdout","log":"INFO:     172.21.0.1:59200 - \"GET /v1/users/12345 HTTP/1.1\" 200 OK"}
```



## 参考情報

* [fluent/fluentd](https://hub.docker.com/r/fluent/fluentd/)
attributes_forとは【rspec】

## attributes_forとは
プロジェクトファクトリからテスト用の属性値をハッシュとして作成するもの。

## buildとの違い
``user``と``post``のfactoryがあったとする。
```users.rb
FactoryBot.define do
  factory :user do
    name "test"
    sequence(:email) { |n| "test#{n}@test.com"}
    password "password"
  end
end
```

```posts.rb
FactoryBot.define do
  factory :post do
    content 'test content'
    association :user
  end
end
```

これらを用いた``build``と``attributes_for``で取得するデータの違いが以下の通り。

```rb
> FactoryBot.build(:post)
=> <Post id: nil, content: "test content", user_id: 8, created_at: nil, updated_at: nil> 

> FactoryBot.attributes_for(:post)
=> {:name=>"test", :email=>"test2@test.com", :password=>"password"}  
```
``build``はモデルオブジェクトとして返り、``attributes_for``はハッシュとして返ることが分かった。

## 参考記事
[【Rspec】attributes_forってなんだ...](https://qiita.com/__kotaro_/items/adbc355bfb550b8b2150)
CakePHP4.xで認証プラグインを入れようとするとInstallation failed, reverting ./composer.json and ./composer.lock to their original content.と出る問題を解決

久々にCakephpに触れる事になって、認証機能を入れるところでクックブック通りに

```
composer require "cakephp/authentication:^2.0"
```
と入れてみた所エラーが出てインストールできない。
エラーメッセージを解読して原因を見てみる。

```
Installation failed, reverting ./composer.json and ./composer.lock to their original content.
中略
Your requirements could not be resolved to an installable set of packages.
```
どうにも下段のメッセージが怪しいので調べてみるとインストールするパッケージのバージョンが合ってないぞと言う事らしい。

そこで下記のように試してみる。

```
composer require "cakephp/authentication:^2.*"
```
今のcakephpに合うバージョンを探してこいという指示の下でインストールを試みる。
```
55 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
```
インストールに成功！

今回に限らず、cakephpはクックブック通りに操作しても上手く行かない事が度々あります。
ドキュメントの整備がされていないのは困りものですね--;
gitの変更を取り消したい【状況別】

誤ってgit add/commitした時、叩くべきコマンドを忘れがちなので、復習＆備忘録として投稿します。

## ワークツリーの変更を取り消す

```bash
$ git checkout --ファイル名 #ファイルの変更を取り消す
$ git checkout --ディレクトリ名 #ディレクトリの変更を取り消す
$ git checkout --. #全ての変更を取り消す
```

**ステージの情報をワークツリーに上書きすることで**、ワークツリーの情報を元に戻す仕組み。

ここでは、git add や git commit していないことを前提としているので、ステージの情報が更新されていない。そのため、ステージの情報を用いて元に戻してる。

## git add を取り消す

```bash
$ git reset HEAD ファイル名 #ファイルの変更を取り消す
$ git reset HEAD ディレクトリ名 #ディレクトリの変更を取り消す
$ git reset HEAD. #全ての変更を取り消す
```

**リポジトリ（今いるブランチの最新のコミット）の情報をワークツリーに上書きすることで**、ステージの情報を元に戻す仕組み。
注意点は、ステージの変更は取り消されたが、ワークツリーの情報は取り消されないこと。

## git commit をやり直す（差し替える）

```bash
$ git commit --amend
```

一度コミットした内容を修正したい場合、
→ ワークツリーを変更
→ git add でステージ
→ git commit —amend
で直前のコミットを上書きすることができる。

注意点は**pushしたcommitはやり直しはできない**こと。
例えば、自分がpushしたリモートリポジトリの情報をAさんがワークツリーに取り込んで作業をしている場合、
自分がamendコマンドで修正を加え、pushすると、Aさんがpushする時にリモートリポジトリの履歴状態と内容が違うため、pushできなくなる。

復習したことで、理解が深まりました。
AtCoder Beginner Contest 248

## [A - Lacked Number](https://atcoder.jp/contests/abc248/tasks/abc248_a)

O(10)

```C++:C++
#include <bits/stdc++.h>
 
#define rep(i,n) for(int i=0; i<(n); ++i)
#define repx(i,x,n) for(int i=x; i<(n); ++i)
#define fixed_setprecision(n) fixed << setprecision((n))
#define execution_time(ti) printf("Execution Time: %.4lf sec\n", 1.0 * (clock() - ti) / CLOCKS_PER_SEC);
#define pai 3.1415926535897932384
#define NUM_MAX 2e18
#define NUM_MIN -1e9
 
using namespace std;
using ll = long long;
using P = pair<int,int>;
template<class T> inline bool chmax(T& a, T b){ if(a<b){ a=b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b){ if(a>b){ a=b; return 1; } return 0; }

int main() {
    string s;
    cin >> s;
    vector<int> A(10, 0);

    for(auto c:s){
        A[c-'0']++;
    }

    repx(i, 0, 10){
        if(A[i]==0) cout << i << endl;
    }

    return 0;
} 
```

## [B - Slimes](https://atcoder.jp/contests/abc248/tasks/abc248_b)

```C++:C++
#include <bits/stdc++.h>
 
#define rep(i,n) for(int i=0; i<(n); ++i)
#define repx(i,x,n) for(int i=x; i<(n); ++i)
#define fixed_setprecision(n) fixed << setprecision((n))
#define execution_time(ti) printf("Execution Time: %.4lf sec\n", 1.0 * (clock() - ti) / CLOCKS_PER_SEC);
#define pai 3.1415926535897932384
#define NUM_MAX 2e18
#define NUM_MIN -1e9
 
using namespace std;
using ll = long long;
using P = pair<int,int>;
template<class T> inline bool chmax(T& a, T b){ if(a<b){ a=b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b){ if(a>b){ a=b; return 1; } return 0; }

int main() {
    ll A, B, K;
    cin >> A >> B >> K;
    ll cnt=0;
    while(A<B){
        A *= K;
        cnt++;
    }
    cout << cnt << endl;

    return 0;
} 
```

## [C - Dice Sum](https://atcoder.jp/contests/abc248/tasks/abc248_c)

```C++:C++
#include <bits/stdc++.h>
 
#define rep(i,n) for(int i=0; i<(n); ++i)
#define repx(i,x,n) for(int i=x; i<(n); ++i)
#define fixed_setprecision(n) fixed << setprecision((n))
#define execution_time(ti) printf("Execution Time: %.4lf sec\n", 1.0 * (clock() - ti) / CLOCKS_PER_SEC);
#define pai 3.1415926535897932384
#define NUM_MAX 2e18
#define NUM_MIN -1e9
 
using namespace std;
using ll = long long;
using P = pair<int,int>;
template<class T> inline bool chmax(T& a, T b){ if(a<b){ a=b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b){ if(a>b){ a=b; return 1; } return 0; }

ll MOD = 998244353;

int main() {
    ll N, M, K;
    cin >> N >> M >> K;
    vector<vector<ll>> dp(N+1, vector<ll>(K+1, 0));
    dp[0][0] = 1;
    for(int i=0; i<N; i++){
        for(int j=0; j<K; j++){
            for(int k=1; k<=M; k++){
                if(j+k<=K) dp[i+1][j+k] = (dp[i+1][j+k] + dp[i][j]) % MOD;
            }
        }
    }
    ll res = 0;
    for(int i=1; i<=K; i++){
        res = (res + dp[N][i]) % MOD;
    }
    cout << res << endl;

    return 0;
} 
```
pagyを日本語化してみる

# はじめに
railsにページネーションを導入するにあたり、
kaminariより新しく諸々いい感じらしい評判を聞いたので
pagyを導入してみた。

https://github.com/ddnexus/pagy

# 実装について
初学者故、相当つまづいたがどうにか導入。

参考にした記事

https://qiita.com/white0221/items/d5a0386882943131df77

https://qiita.com/yama_diary/items/8eabcdad3bb88a8eae60



で、表示を日本語化したいものの導入記事が見つからなかったので
備忘録的に記事化したという流れです。

# pagy日本語化
下記内容順で書けばできる、はずです。。。
（自分は時間表示を既に日本語化していたので後半だけやりました）

```ruby:config/application.rb
module Hoge  #ちょっと前まではこのhogeすら何やら分かりませんでしたが。。。
  class Application < Rails::Application
    config.load_defaults 6.0
    config.i18n.default_locale = :ja  #追記箇所
  end
end
```
```ruby:pagy.rb
#以下を追記
require 'pagy/extras/i18n'
```

で、状況、必要に応じてlocalesに追記する感じ？
無くても日本語化してたからよく分かってません。。。
```ruby:config/locales/ja.yml
ja:
  views:
    pagination:
      prev: "前"
      next: "次"
```

# pagyでのi18nについての説明

https://ddnexus.github.io/pagy/extras/i18n#gsc.tab=0

***
間違い等あれば是非ご指摘いただけますと有り難いです。。。
unsigned で宣言すると必ず正の数になる

以下のコードのように
unsigned で宣言すると必ず正の数になる。
バグの発見に時間がかかってしまった。


```cpp
typedef unsigned long long  ull;
int main()
{
	ull a = 10;
	if (a - 100 >= 0) {
		cout << "Yes" << endl;
	}
}
```
svelte + typescript 開発環境をコマンド1発で爆速構築 (Vite)


## 結論

npm init vite@latestを実行し、プロジェクト名入力と選択をするだけです。
(Viteを事前にインストールする必要もないはず)

```
$ npm init vite@latest
✔ Project name: … svelte-test // プロジェクト名入力
✔ Select a framework: › svelte // svelteを選択
✔ Select a variant: › svelte-ts // typescriptを選択

Scaffolding project in /Users/apple/svelte-test...

Done. Now run:

  cd svelte-test
  npm install
  npm run dev
```

あとは書かれているコマンドを実行するだけです。
```
  cd svelte-test
  npm install
  npm run dev
```
http://localhost:3000 にアクセス

![Svelte___TS___Vite_App.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/900110/395003c1-1449-bd27-f387-1d5be5fd32c3.png)

## 感想
合計コマンド4発でしたごめんなさい。

ホットリロードもとても早いので最高です。

## 参考
この記事ではtailwindも導入しています。
https://www.section.io/engineering-education/svelte-with-vite-typescript-and-tailwind-css/


## prettier導入
pretiierを入れたい場合は、こちらも実行しましょう。
```
npm i -D prettier-plugin-svelte prettier
```

[参考]
https://zenn.dev/miruoon_892/articles/f5e56b7fcc0702b4aef2
忘れがちな参照関係の特徴

## 自分自身に参照関係を設定できる

取引先責任者 → 取引先責任者のように自オブジェクトに参照関係を設定できます。

ドキュメントには

>たとえば、Bugというカスタムオブジェクトをそれ自体とリンクさせ、
2つの異なるバグが同じ問題にどのように関連しているかを示すことができます。

と書いてありますが、
同じ階層のオブジェクトがリレーション持ってると、扱い難しそうだな〜と思いました。

上記のBugの例なら、Bug管理用の親オブジェクトを作ってそこで管理してあげたほうが、プログラムでも扱いやすそうに感じます。


## 項目作成時のオプション系

- 参照関係項目を必須にすることができる
- 参照しているレコードが削除される時の動作を、どれか1つから選べる
    - 参照しているレコードはそもそも削除できないようにする
    - 参照関係項目の値を削除する
    - 自身も削除する
        - カスケード削除をSalesforceに問い合わせて有効にしてもらう必要がある
        - カスタムオブジェクトに参照関係項目を作成する必要がある
        - 参照先は標準・カスタムオブジェクトどちらでもいい

## 参考文献

[Object Relationships Overview](https://help.salesforce.com/s/articleView?id=sf.overview_of_custom_object_relationships.htm&type=5)
Steamlitでスマホのカメラを動かすだけのアプリを作る

# 目次
ざっくりと以下の様な事が書いてあります。
1.背景：カメラで撮った写真を使って何かしたいです
2.目的：スマホのカメラを使う為だけのアプリをデプロイします
3.結果：スマホのカメラが起動しました
4.方法：我妻先生のコードを参考に最小限のコードでデプロイしました
5.考察：画像データがどのように移動しているのかがコードを通してざっくり分かりました
6.課題：感情分析アプリやOCRを使った文字認識アプリに応用したい
# 1.背景：カメラで撮った写真を使って何かしたいです
具体的には本棚をカメラで撮った画像の文字認識をして、リストを作成したいです。、
# 2.目的：スマホのカメラを使う為だけのアプリをデプロイします
[前回の記事(Streamlit Cloudで画像認識AIアプリをデプロイする(2020.4.12))](https://qiita.com/tan0ry0shiny/items/c14f02fb1a3d00734348)を参考にStreamlit Cloudにデプロイします。GitHub経由でデプロイします。

# 3.結果：スマホのカメラが起動しました
アプリのURLへ移動するとこのような画面が現れます。
![Screenshot_2022-04-17-14-26-01-021_com.android.chrome.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2496939/557ca42a-a354-24b7-e9c2-68e60a108600.jpeg)
ここで、カメラで撮影をタップすると
![Screenshot_2022-04-17-14-26-31-349_com.android.chrome.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2496939/6f9e19e3-eb82-0139-df37-da659969773b.jpeg)
こうなりました。無事、カメラが起動しているのが分かります。

# 4.方法：我妻先生のコードを参考に最小限のコードでデプロイしました
GitHub経由でデプロイするんですが、ディレクトリには
1. app.py：カメラを起動するためのコード
1. requirements.txt：インストールするライブラリが記述されています

基本的にはこの２つで良いです。私は、開発環境にGoogle Colaboratoryを使うので、app.pyとrequirements.txtを作るコードが記述されているcamera_app.ipynbも入れています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2496939/4645665f-1cf2-d825-429e-61ef4b0fe79f.png)

# 5.考察：画像データがどのように移動しているのかがコードを通してざっくり分かりました
カメラを起動するためのコードは以下だと思われます。streamlitのライブラリの便利さが良く分かります。
```camera_app.ipynb
if ...中略...:
    ...
elif img_source == "カメラで撮影":
    img_file = st.camera_input("カメラで撮影")

if img_file is not None:
    with st.spinner("推定中..."):
        img = Image.open(img_file)
...中略...
```
カメラで撮った写真はimg_fileに移り、```Image.open```で画像からデータへ変換されるものと考えられます。```st.camera_input```はjpegなどの画像ファイルを返す記述がされていそうです。

# 6.課題：感情分析アプリやOCRを使った文字認識アプリに応用したい
当面の目的は文字認識アプリにする事ですが、Streamlitを使った感情分析アプリの作り方が乗っている記事を見かけたので、作り方の分かっている物から作りたいと思います。まだ、Streamlitのルールに慣れる意味合いもあります。
laravel-openapiを使ってみる 本当に触りだけ

# 概要

- laravel-openapiというライブラリを使ってみたので使った時のメモと導入方法を残す。

# できるようになること

- `routes/`直下や`app/Http/Controllers/`直下を見に行って勝手にOpenApiのフォーマットのドキュメントを出力してくれる。

# 導入方法

1. 下記コマンドを実行してライブラリをインストールする。

    ```terminal
    $ composer require vyuldashev/laravel-openapi
    ```

1. `config/app.php`を開き、`providers`の配列に下記の様に追記を行う。

    ```config/app.php
    'providers' => [
        /*
         * Package Service Providers...
         */
        Vyuldashev\LaravelOpenApi\OpenApiServiceProvider::class,
    ];
    ```

1. 下記コマンドを実行して設定ファイルを生成する。（`config/`直下にlaravel-openapi専用の設定ファイルが`vendor/`直下のライブラリのディレクトリからコピーされて作成される。）

    ```terminal
    $ php artisan vendor:publish --provider="Vyuldashev\LaravelOpenApi\OpenApiServiceProvider" --tag="openapi-config"
    ```

# 準備

1. 下記コマンドを実行してContentController.phpを作成する。

    ```terminal
    $ php artisan make:controller ContentController
    ```

1. 作成されたContentController.phpに下記の様に修正する。（Requestをそのまま帰すだけの関数を定義）

    ```app/Http/Controllers/ContentController.php
    <?php
    
    namespace App\Http\Controllers;
    
    use Illuminate\Http\Request;
    use Vyuldashev\LaravelOpenApi\Attributes as OpenApi;
    
    #[OpenApi\PathItem]
    class ContentController extends Controller
    {
        /**
         * リクエストをそのまま帰す
         *
         * @param Request $request
         * @return Request
         */
        #[OpenApi\Operation]
        public function index(Request $request) : Request
        {
            return $request;
        }
    }
    ```

1. `routes/api.php`を下記のように記載して先に作成したコントローラーの関数へのルーティングを定義する。

    ```routes/api.php
    use App\Http\Controllers\ContentController;

    Route::get('/content/index',[ContentController::class, 'index']);
    ```

# 使ってみる

1. 下記コマンドを実行して先に登録したAPIルーティングをOpenApiのフォーマットでターミナルに出力する。

    ```terminal
    $ php artisan openapi:generate
    ```

1. 下記のように出力された。

    ```openapi.json
    {
        "openapi": "3.0.2",
        "info": {
            "title": "Laravel",
            "version": "1.0.0"
        },
        "servers": [
            {
                "url": "http:\/\/localhost"
            }
        ],
        "paths": {
            "\/api\/content\/index": {
                "get": {
                    "summary": "リクエストをそのまま帰す"
                }
            }
        }
    }
    ```

1. ターミナルに出力されたOpenApiのフォーマットのAPI情報をファイルに出力したい場合は下記のようにすればファイルに出力する事ができる。（`$ php artisan openapi:generate`コマンド実行してもjsonファイルは出力されないですよね・・・？）

    ```terminal
    $ php artisan openapi:generate > OpenApi形式でAPI情報を出力するファイル名.json
    ```

# 参考文献

- [公式ドキュメント](https://vyuldashev.github.io/laravel-openapi/)
- [Github](https://github.com/vyuldashev/laravel-openapi)
C#の証明書読み込み

# はじめに
HttpClientでクライアント証明書を使うとか、証明書を.NETのプログラムで読み込む話。

# 証明書ストアからの読み込み
System.Security.Cryptography.X509CertificatesのX509Storeを使うと、証明書ストアから読み込みできる。
例えば、個人証明書を読み込む場合は以下のようになる。

```csharp

using System;
using System.Security.Cryptography.X509Certificates;

namespace clientcert
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 証明書ストアの現在のユーザ（Windowsアカウント）の「個人」を開く
            X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
            store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
            // 証明書を選ぶ（絞り込む）、まずは有効期間内のもの
            // 最後のtrueは証明のパスが正式なもののみ取り出す指定なので、オレオレの場合はfalseにする
            X509Certificate2Collection col_all = store.Certificates;
            X509Certificate2Collection col_date = col_all.Find(X509FindType.FindByTimeValid, DateTime.Now, true);
            // 次に署名者の名前（CA証明書のCNなど）で絞り込む
            X509Certificate2Collection col_issuer = col_date.Find(X509FindType.FindByIssuerName, "TestRoot", true);

            // 見つかった証明書を出力
            // X509Certificate2のオブジェクトなので、HttpClientとかでクライアント証明書として使える
            foreach (X509Certificate2 cert in col_issuer)
            {
                Console.WriteLine(cert.ToString());
            }
        }
    }
}
```
cert.Issuer は普通に文字列なので、Findで絞らず、自分で文字列を比較するなどでも問題ない。
オレオレ証明書で、ルート証明書をインポートしていない場合、Findの最後の引数をfalseにしないと出てこなくなるので注意。


# ファイルからの読み込み
証明書ストアに入れないで読み込む場合、また、Windowsサービスから使うなど、ユーザが異なる場合はファイルから読み込むこともできる。
一般的にはpkcs12ファイル（.p12, .pfx）だと思うので、その想定。

```csharp
using System;
using System.Security.Cryptography.X509Certificates;
using System.IO;

namespace clientcert
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // ファイルをバイト列として読み込む
            // ファイル全体を読んで、全部読めなかったら（ファイルサイズと読み込んだサイズが違ったら）エラーにしている
            byte[] file_data = null;
            try
            {
                // 証明書のファイル名はここで指定
                using (FileStream fs = new FileStream("client01.pfx", FileMode.Open, FileAccess.Read))
                {
                    file_data = new byte[fs.Length];
                    int read_size = fs.Read(file_data, 0, file_data.Length);
                    if (read_size != fs.Length)
                    {
                        Console.WriteLine("Read error: size=" + read_size);
                        return;
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                return;
            }

            // クライアント証明書のパスワード
            string cert_pass = "password";

            // ここまで来たらX509Certificate2のインスタンスが作れる
            X509Certificate2 cert2 = new X509Certificate2(file_data, cert_pass, X509KeyStorageFlags.EphemeralKeySet);
            Console.WriteLine(cert2.ToString());
        }
    }
}
```

使い方によっては X509KeyStorageFlags.EphemeralKeySetのところを変える必要があるかもしれない。
情報処理安全確保支援士 講習会がめちゃくちゃ楽しかった

# 情報処理安全確保支援士 講習会がめちゃくちゃ楽しかった
講習名：リモート講習（実践講習Ａ）

実用的な情報のみ興味がある方は、[こちら](#学び)のみご確認ください。  

## おさらい
情報処理安全確保支援士は登録手続き後、資格維持のため年１回のオンライン講習と３年に１回の集合講習に参加する必要があります。  
今回は後者の集合講習に参加してきました。尤も、このご時世なためオンライン開催です。

## 参加前の心情
各状況が提示され、それに対してどういった対応が適切かチームでディスカッションし、発表するというもの。  
設問は事前に開示され開催までに自分の意見をまとめておく必要がありますが。
「あ～大丈夫かな～。俺の意見稚拙じゃないかな～。あ～」  
と不安があり
「自分はペーペーだけど、セキスペでしょ？めちゃくちゃお堅いおじさまが出てきて、その人が無双して終了なんじゃない？緊張する～」
という精神状態でした。

## 顔合わせとディスカッション
自分を含め4人のグループでした。30代～40代の世代で構成されており、みんなさん優しく本当にありがたかったです。  
進行中の雰囲気もよく、建設的に話ができました。  
また、皆さん仕事の畑が違うこともあり、知識を補完し合えたのもとても有意義でした。  

「この設問の前提条件やばいよね。」  
「実環境でやったら、怒られるレベルじゃないですねw」  
「Twitter見てたら、発表でめちゃくちゃ詰められたって書いてあってビビッてますw」  
「いやぁ。それはさすがに誇張してるでしょｗ」

## 発表
課題の一つに、セキュリティインシデントの調査、対応を上司に報告するロールプレイがありました。  
報告内容や報告タイミングはグループ内で決めるとのことで、内容をまとめ、発表者に託しました。

発表者「以上が報告と対応案です」
上司役「何故このタイミングなのですか？報告が遅いのでは？」
私(あわわわわ)
発表者「インシデント対応はCSIRTに権限が委ねられていますので、暫定対応終了を優先させました」(設問にはそんなこと書いていない)
上司役「対応に予算を使いましたね。それは事後報告なのですか？」
私(詰められとるやん)
発表者「今期の予算内で行いました。問題ありません」
## フィードバック
CSIRTは事前に取り決めていれば決められた範囲で行動でき、予算を使うことができる。  
よって、それを想定して言い切ってくれたことは逆に良かった。とフィードバックを受けました。  
結果的に100点の返しだったようです。  
ただ、現実的にはCSIRTが存在しない会社もあり、あったとしてもそこまで権限がある組織はほとんどないとのことです。

また、発表以外のディスカッション内容も講師陣は聞いていたようで、私の発言がピックアップされお褒めに預かった時は~~めちゃくちゃ~~ ちょっと嬉しかったです。
# 学び
細かい調査方法や着眼点は省きます。  

* [攻撃者が悪用するWindowsコマンド](https://blogs.jpcert.or.jp/ja/2015/12/wincommand.html)  
* [CSIRT](https://www.nca.gr.jp/outline/index.html)は事前に取り決められている場合において、権限や予算を取り決めた範囲で上司の指示を待たず使う事ができる。
* 各種ログの保管期間は「なんとなく」ではなく、基づく根拠を持って決めるべき。以下を参照するなど  
JPCERT/CC 1年分推奨  
NISC 1年以上推奨  
不正アクセス禁止法の時効 3年
などなど。関連記事 [「結局アクセスログってどれくらい保存しておけばいいの？」に答える関係法令](https://qiita.com/yamotuki/items/628f9bf399cc9b59f3cb)
# 終わりに
10:00～17:00の長丁場でした。  
気負っていましたが、思いのほか皆さんと対等に話すことができ、正直楽しかったです。  
集合しての講習であれば、みんなと飲みに行きたかった...
Linuxコマンド psのみかた

# ps -Fで出力される情報まとめ
linux初心者どころか、パソコン詳しくない私が頑張って調べた内容ですので、悪しからず。

## psコマンドとは？
>OSで実行されているプロセスの一覧を表示するlinuxコマンド
>プロセスとは、**Linuxにおける実行中のプログラムやアプリケーションの最小単位**のこと

最小単位と言われてもという感じではある。。。

## -Fオプション
プロセスを完全なフォーマットで表示するとのこと。
勉強にはちょうどいいかなということで、出力する内容を詳しく見ていきます。

## 出力内容
```terminal
UID        PID  PPID  C    SZ   RSS PSR STIME TTY          TIME CMD
kamiyama    10     9  0  2514  5116  10 12:24 pts/0    00:00:00 -bash
kamiyama    67    10  0  2654  3296   4 12:47 pts/0    00:00:00 ps -F
```

- UID　＞　プロセスを所有しているユーザー
- PID　＞　プロセスの識別番号
- PPID　＞　親プロセスの識別番号
- C　＞　プロセスのCPU利用状況
- SZ　＞　プロセスが確保しているメモリサイズ[kB]
- RSS　＞　実メモリの使用サイズ
- PSR　＞　プロセスが現在割り当てられているプロセッサ
- STIME　＞　プロセス開始時刻
- TTY　＞　端末名
- TIME　＞　総実行時間
- CMD　＞　コマンド

## ちなみによく使うのは-auxだとか、、、
出力はこちら
```terminal
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   1756  1084 ?        Sl   12:24   0:00 /init
root         8  0.0  0.0   2124   348 ?        Ss   12:24   0:00 /init
root         9  0.0  0.0   2124   364 ?        R    12:24   0:00 /init
kamiyama    10  0.0  0.0  10056  5116 pts/0    Ss   12:24   0:00 -bash
kamiyama    68  0.0  0.0  10616  3288 pts/0    R+   12:59   0:00 ps aux
```
- USER　＞　プロセスを所有しているユーザー(UID)
- PID　＞　プロセスの識別番号
- %CPU　＞　CPU使用率
- %MEM　＞　実メモリ使用率
- VSZ　＞　仮想サイズを含めた使用サイズ[kB]
- RSS　＞　実メモリの使用サイズ
- TTY　＞　端末名
- STAT　＞　プロセスの状態
- START　＞　プロセス開始時刻(STIME)
- TIME　＞　総実行時間
- COMMAND　＞　コマンド(CMD)


## STATの内容について
STATの内容について検索してみましたが、記事によって書いている内容が微妙にちがってややこしかったです。
とりあえず、自分の環境で　man ps して出てきた結果はこんな感じでした。

```terminal
PROCESS STATE CODES
       Here are the different values that the s, stat and state output specifiers (header "STAT" or "S") will display
       to describe the state of a process:

               D    uninterruptible sleep (usually IO)
               I    Idle kernel thread
               R    running or runnable (on run queue)
               S    interruptible sleep (waiting for an event to complete)
               T    stopped by job control signal
               t    stopped by debugger during the tracing
               W    paging (not valid since the 2.6.xx kernel)
               X    dead (should never be seen)
               Z    defunct ("zombie") process, terminated but not reaped by its parent

       For BSD formats and when the stat keyword is used, additional characters may be displayed:

               <    high-priority (not nice to other users)
               N    low-priority (nice to other users)
               L    has pages locked into memory (for real-time and custom IO)
               s    is a session leader
               l    is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)
               +    is in the foreground process group
               
```
> ほかの記事をみて重要そうなのは以下のSTAT
> - R　＞　稼働中
> - S　＞　割り込み可能なスリープ中
> - D　＞　割り込み不可なスリープ中
> - T　＞　終了処理中
> - Z　＞　すでに実体がないゾンビプロセス
> - W　＞　実メモリ上にはなく、スワップアウトしている

> - N　＞　優先度低い（プロセスの優先度を示す値。範囲は-20〜19で、値が大きいほど優先度が低いらしい。）
> - &lt;　＞　優先度高い
> - s　＞　セッションリーダ
> - l　＞　プロセス生成中
> - +　＞　フォアグラウンドのプロセスグループ

## まとめ
同じ内容でもカラム名が違うのがややこしい。
もっとも、慣れてくると確認するところが決まってくるのかもしれませんが。

### 参考
一番詳しそうだったページ。

https://linuxjm.osdn.jp/html/procps/man1/ps.1.html
CMake で WinUI3 App を書いてみるテスト


書いてみるといいつつFred Emmott(fredemmott)さんのサンプルを動かしてみます。

https://github.com/fredemmott/cmake-cpp-winrt-winui3 を clone します。
(checkout された master のhash は[d6c0454ead1](https://github.com/fredemmott/cmake-cpp-winrt-winui3/tree/d6c0454ead1af90ea6e3f5dd89c0366ddd00df9b) でした。)

とりあえず cmake を走らせます。clone した `cmake-cpp-winrt-winui3` のディレクトリに移動し、`cmake -Bbuild .` を実行します。(`build`ディレクトリ以下に関連ファイルを生成する)

残念ながらCMake のエラーが発生しました。
```
CMake Error at src/CMakeLists.txt:15 (add_custom_target):
  Error evaluating generator expression:

    $<TARGET_RUNTIME_DLLS:DemoApp>

  Expression did not evaluate to a known generator expression
```

CMake の `TARGET_RUNTIME_DLLS` は 3.21 からサポートされてるとのこと。手元のCMake は 3.20 だったので、少し古かったです。

```
cmake_minimum_required(VERSION 3.20)
```
と指定されていますが、正しくは 3.21 ですね。というわけで CMake 3.21 に更新して cmake を再実行します。今度は通りました。

折角なのでビルドまで進めます
```cmake --build build``` でビルドします。
特に問題なくビルドが通り、`build/src/DemoApp.exe` が生成されました。

これを実行しますが、Windowが表示される前に終了してしまいました。
どうも初期化時の下記のコードで `::MddBootstrapInitialize()` が失敗しています。
```
            const HRESULT hr{ ::MddBootstrapInitialize(c_majorMinorVersion, c_versionTag, c_minVersion) };
            if (FAILED(hr))
            {
                exit(hr);
            }
```

[実行時に Windows App SDK フレームワーク パッケージを参照する](https://docs.microsoft.com/ja-jp/windows/apps/windows-app-sdk/reference-framework-package-run-time) には以下のように記述されています。
> アプリが展開テクノロジに msix を使用していない場合 (スパースパッケージまたはアンパッケージ化されている場合)、Windows app sdk の機能 (WinUI 3、app ライフサイクル、mrt.dll Core、および DWriteCore) を呼び出す前に、使用するために Windows app sdk を初期化する必要があります。 Windows App SDK 1.0 安定版では、プロジェクトのビルドの一部として初期化に必要なコードを生成するプロジェクトプロパティ <WindowsPackageType>None</WindowsPackageType> を設定できます。 これにより、msix を使用していないアプリは、実行時に Windows App SDKフレームワークパッケージに対する依存関係を取得できます。

このプロジェクトではmsix は使っておらず、フレームワークの初期化を自力で行っており、その初期化処理でエラーとなっていました。

MddBootstrapInitializeあたりをキーに検索すると、
[Unpackaged C++ sample app MddBootstrapInitialize call reports unhandled exception in KernelBase.dll](https://github.com/microsoft/WindowsAppSDK/issues/2138) というissue が見つかりました。
Unpackaged なアプリの場合は別途 WindowsAppRuntimeInstall.exe を使ってランタイムをインストールする必要があるそうです。
>We should probably update the docs for MddBootstrapInitialize to point to this too, and provide a better error message (or at least debug output).

と言われていますし、エラーメッセージは要改善ですね。

何はともあれ、
https://docs.microsoft.com/en-us/windows/apps/windows-app-sdk/downloads
から今使っているWindows App SDKは 1.0.0 に対応する Redistributable をダウンロードします。
そうすると、Microsoft.WindowsAppRuntime.Redist.1.0.0.zip という名前のファイルが降ってきました。
zip 内には `WindowsAppSDK-Installer-x64/WindowsAppRuntimeInstall.exe` があるので、これを実行してランタイムをインストールします。

再度`build/src/DemoApp.exe`を実行すると、、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1410370/48a3fe86-3815-4c86-8748-5968d25557d2.png)
無事起動しました！

ということで、CMake のみでWinUI3 App を動かせることが確認できました:grinning:
【TypeScript】メソッド（関数）を含むオブジェクトの型定義

初歩的な内容ですが、TypeScript でメソッド（関数）を含むオブジェクトの型定義について書いておきます。

### 1. メソッドを含むオブジェクトの型定義

#### 1-1. サンプルコード

```sample.ts
type SampleType = {
  name: string;
  age: number;
  greeting: () => string;
}
```

`greeting: () => string;` のところが、メソッドとなります。

#### 1-2. メソッドの型定義のパターン

戻り値がない場合は、次のように指定します。
```typescript
  greeting: () => void;
```

引数を含む場合は、次のように指定します。
```typescript
  greeting: (name: string, age: number) => string;
```

とても簡単ですが、答えに辿り着くまでに少々時間が掛かったので、同じことに迷う方が減るように書いておきました。

### 2. 補足

以下は、おおよそ個人的見解ですが、参考のため書いておきます。

#### 2-1. データ型が不明なクラスの型定義

本来、あるべき形ではないと思いますが、使用しているクラスのデータ型が不明の場合についてです。
以下のサンプルでは、クラスに対して後付けで型定義をしています（これで安全かどうかは要検討です）。

```sample.ts
// クラスの実態（この型が不明！の場合）
class SampleClass {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  greeting(): string {
    return `私の名前は${this.name}です。年齢は${this.age}歳です。`
  };
}

// クラスの型を定義する（既知の内容を元に定義する）
type SampleType = {
  name: string;
  age: number;
  greeting?: () => string; // メソッドが存在するか不明の場合
}

// 定義した型（SampleType）を用いてインスタンスを生成
const taro: SampleType = new SampleClass('taro', 30);

// メソッドの存在有無を確認の上で実行する
if (taro.greeting) {
  console.log(taro.greeting()); // 私の名前はtaroです。年齢は30歳です。
}
```

#### 2-2. 関数の型指定の方法

関数の型は、以下の `typeof greeting` のように「`typeof 関数名`」の形で定義することもできます。

```sample.ts
// 使用される関数
function greeting(name: string, age: number): string {
  return `私の名前は${name}です。年齢は${age}歳です。`;
}

// オブジェクト内のメソッドとして定義
type SampleType2 = {
  greeting: typeof greeting;
}
```

使用する場面があるかは分かりませんが、次のように定義することもできます。

```sample.ts
// 使用される関数
function greeting(name: string, age: number): string {
  return `私の名前は${name}です。年齢は${age}歳です。`;
}

// 関数の引数と戻り値の型を取得
type SampleParameters = Parameters<typeof greeting>; // 引数の型
type SampleReturnType = ReturnType<typeof greeting>; // 戻り値の型

// オブジェクト内のメソッドとして定義
type SampleType = {
  greeting: (...param: SampleParameters) => SampleReturnType;
}
```

以上です。間違い等あればご教示いただけると幸いです。