OmniAICreator/Qiita-1.07M huggingface dataset:
あるWebサービスの開発メモ・本番環境

- [あるWebサービスの開発メモ・目次ページに戻る](https://qiita.com/ishi32/items/152a1ecf7eeee7a8fb57)

## 本番環境へのデプロイ

本番環境は当面 Vercel の東京リージョンを使う予定です。

Vercel への具体的なデプロイ方法については、本サービスの開発環境構築について記載した記事 [「Docker + ... の導入手順」](https://qiita.com/ishi32/items/c7baded80262cd1fe429) に記載しましたのでそちらを確認してください。

開発中は適当なタイミング (理想はローカルPCでの自動テストに合格した後) でデプロイすることになります。現状では git push が成功すれば Vercelデプロイに自動で進みます。理想はプルリクエストを送出後のマージをトリガーすることだと思っています。

## Vercel CDN について

今回、Vercel 東京リージョンを採用しているので、オリジンサーバは東京に収容されています。Vercel でホストすると Vercel CDN を利用できるため、ユーザのロケーションに応じて、最適な Vercel のエッジロケーションに収容されているキャッシュサーバが応答してくれるはずです。グローバルアクセスであっても低レイテンシーが期待できます。

## 本番環境 = 開発環境？

しばらくは開発環境イコール本番環境なのですが、サービス開始前に開発環境とは別に本番環境をつくるんだと思います。Vercel 上には本番プロジェクトと開発用プロジェクトがあって、それぞれ別の Github リポジトリに紐づくことになると思います。

## 名前解決

サービス開始時には正式の URL から 本番環境のサービスにアクセスできるようにしますが、これは DNS に Vercel が指定する A レコードと CNAME レコードを設定することで実現できます。

弊社では普段は aws Route53 を利用していますが、本サービスのドメイン .site は Route53 では利用できませんでした。

そのため本サービスでは CROUDFLARE の DNS で名前解決を行なっています。CROUDFLARE からの接続はクセがありますので、CROUDFLARE の DNS を使われる場合は以下を注意してください。

### CROUDFLARE + Vercel CDN で発生するリダイレクトエラー

CROUDFLARE のデフォルト設定の場合は、クライアントからサービスにアクセスするとリダイレクトエラーが発生して接続できません(2022年5月現在)。公式ページには以下の記述があります。

- [リダイレクトループエラーのトラブルシューティング](https://support.cloudflare.com/hc/ja/articles/115000219871-リダイレクトループエラーのトラブルシューティング)

ここに記載されている解決方法の２で解決しました。

- SSL / TSL タグの [概要] タグをクリック
- フレキシブル が選択されている場合は フル に変更する

ラジオボタンを操作すると即設定が変更されますので注意してください。

## バックエンドについて

バックエンドはサービス開始時点は Supabase を使います。Supabase も本番環境では東京リージョンを使いますので、フロントエンドと近距離で連携できます。

また、バックエンドも本番環境と開発環境でプロジェクトを分けて利用する予定です。
[Laravel] テスト中のエラー 'SAVEPOINT trans2 does not exist'

`laravel 8.75`にて

## エラー

__コマンドテスト中の一幕。__

コマンド画面にて突如現れしエラー。
`SQLSTATE[42000]: Syntax error or access violation: 1305 SAVEPOINT trans2 does not exist`

![testerr.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990851/5a144f2e-5757-2248-3dec-20af9ee4cd1e.jpeg)

テストを書いてただけなのに......

## 解決？

__テストファイルの`use RefreshDatabase;`コードを削除した。__
(画像は削除する前)
![testerr-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/990851/8b987d55-4171-6612-92b7-08113de60715.jpeg)


Commandファイルでもトランザクション処理を書いていたので、`use RefreshDatabase`内の処理と重複してしまったようだ。

ていうか`use RefreshDatabase`の内部ってただのTransactionなのか......？

ちょっと面倒だけど、`モデル::truncate()`を使えばまあ困りはしないので一応解決。
QuickSightの接続パターン入門


# はじめに
手元のCSVファイルをQuickSightに登録するパターン、データベースの上のデータをQuickSightに登録するパターンを簡単にまとめてみました。

# CSV ファイルをQuickSightに登録するパターン
## 直接 QuickSight にアップロード
直感的で一番シンプルですが、データの更新はできません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107953/8f2743a7-151d-0f23-555c-e38055a12d2c.png)


## S3 にアップロードして、QuickSight へ インポート
マニフェストファイルを用意する手間はありますが、データの更新に対応しています。
https://docs.aws.amazon.com/ja_jp/quicksight/latest/user/supported-manifest-file-format.html
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107953/18242dd2-8bcb-db22-4396-b295fe0cff76.png)


## S3 にアップロードして、Athenaでデータセットを作って、QuickSightに登録
Athenaを用意する手間はありますが、データの更新に対応しています。前述のマニフェストパターンよりもより柔軟です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107953/0b9ea8b2-ddcb-81c1-9f64-6e26e9d2bdde.png)

# データベース内のデータをQuickSightに登録するパターン
## QuickSight と RDS を接続
一番楽です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107953/93062198-a271-8ef4-aa59-3891173a137a.png)

## QuickSight からインターネット経由で、社内のDBに接続
見た目は楽ですが、社内のDBを外部公開（IP制限可能）する必要があり、社内ポリシー上、難しい場合もあります。
https://docs.aws.amazon.com/ja_jp/quicksight/latest/user/regions.html
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107953/0e656618-4ddb-d7dd-fad7-9e458794e764.png)


## AWSと社内をVPNで接続し、QuickSight からプライベートにDBに接続する
VPNを設定する手間がありますが、AWSを社内LANの延長として利用できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107953/1eb9e037-6476-07fa-f404-da6e69637146.png)

## 社内のバッチ処理で CSVファイルを生成・S3へのアップロードを行う
直接DBと接続できないので、CSV生成とアップロードを自動化するパターンです。
S3アップロード後、QuickSightに登録する方法は、前述のCSVパターンのどれかを利用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/107953/1b3bb392-9bf8-2920-cbbe-b41f0197a450.png)
ADALM-PLUTOを有線LANに接続する


Analog DevicesのSDR学習キットを使って、FM受信をした記事（[ADALM PLUTOでFM受信してみる](https://qiita.com/0x20FE/items/0e229a4c31889903d019)）を書きましたが、USB接続ではアンテナも近くにもってくる必要があり邪魔。そこで、Ethernet接続に切り替えました。

これで、リビングでも快適に開発できるようになりました。

##必要な部材
###  USB On-The-Go ケーブル
PLUTOはスマホやタブレットと同様にPCからみてDEVICEとして動作しますが、LANアダプタを接続するためにHOSTに変換するためのOTGケーブルが必要です。OTGケーブルはタブレットにキーボードやUSBメモリ、Ethernetアダプタを接続するものが出回っています。ちょっと古いものはUSB1.0 にしか対応していないものもあるので、しっかり確認する必要があります。今回はBuffaloのBSMPC11C01BKを使いました。
[UDB On-The-Go](https://en.wikipedia.org/wiki/USB_On-The-Go) wikipedia
### USB Ethernet アダプタ
おうちに転がっていたBuffaloのLUA3-U2-AGTはうまくいかず。LUA4-U3-AGTE-BKに代えたところうまく接続できました。
##必要な設定
Windows PCに接続し、USBドライブのconfig.txtのIPアドレスを書き換えてEject.
[設定のカスタマイズ](https://wiki.analog.com/university/tools/pluto/users/customizing) AD Wiki

でも、gatewayはここでは設定できないのかな。

```
[NETWORK]
hostname = [名前]
ipaddr =   [IPアドレス] 
ipaddr_host = [PC側のIPアドレス(元のまま）]
netmask = 255.255.255.0


[USB_ETHERNET]
ipaddr_eth =
netmask_eth = 255.255.255.0
```

## 接続テスト
真ん中にコネクタにUSB-OTGケーブルを挿し、そこにUSB EthernetアダプタをさしてHUBに接続。あと電源を接続したあとで、PCからipaddreに向けてPINGを打って返事があることを確認し、SSHで接続を確認する。
## 利用上の注意
PySDRの場合はadi.Pluto()でIPアドレスを指定すること。

```python:pySDRの場合
import adi
sdr = adi.Pluto('ip:192.168.2.1')
```
（参考）
[PySDR: A Guide to SDR and DSP using Python](https://pysdr.org/content/pluto.html)　5. PlutoSDR in Python
Finderからワンクリックで動画をYouTubeのshorts用（アスペクト比9:16）にする

# TL;DR
ここ数年流行りのYouTubeのshortsの条件は、動画が1分以内でかつアスペクト比が9:16であること。
今回は、Finderから動画を9:16にするworkflowをAutomatorで作成した。動画本体のアスペクトは変えずに、左右上下に黒いボックスを付け加えて動画の画面サイズだけ9:16にする。

# 手順
① Automatorを開く
Automator→新規→クイックアクション
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316390/f5690d03-687c-0557-2de4-3a8f546d19ac.png)

`シェルスクリプトを実行`をダブルクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316390/656dde30-c9fb-5936-5e30-bc4604efe15c.png)


② 条件設定
`ワークフローが受け取る現在の項目`を`ムービーファイル`にする
`イメージ`はお好きに
`検索対象`を`Finder.app`にする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316390/ae4c6cfd-9464-6c1a-ae9f-95b818467bcd.png)


③ シェルスクリプトを実行
シェルスクリプトの中に以下のソースをペースト
```
name="$1"
/usr/local/bin/ffmpeg -i "$1" -pix_fmt yuv420p -vf "pad=width=max(iw\,ih*(9/16)):height=ow/(9/16):x=(ow-iw)/2:y=(oh-ih)/2" "${name%.*}_shorts.mp4"
```
`入力の引き渡し方法`を`引数として`に変更。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316390/88a7952b-baf7-b8ec-c2c0-f82c415b2623.png)


④ 通知用AppleScript
これはなくてもいいが、完了したときに通知させる。
`AppleScriptを実行`をダブルクリック
```
on run {input, parameters}
	display notification "変換処理が完了しました" with title "動画をshorts用に変換する"
	return input
end run
```
をペーストする。


⑤ 保存
cmd+Sで名前をつけて保存する。このworkflowは` /Users/$USER/Library/Services/`の下に保存される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316390/66459ab5-e507-fced-91ff-32348203114b.png)


# 使い方
Finderから右クリック→クイックアクション→保存した名前のワークフローをクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316390/729a6bbe-ea86-6f0f-4f4c-1b3b424c0066.png)

元の名前_shorts.mp4 という動画ファイルが出力される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316390/ec8a2634-e8b4-3810-3e8f-b18bd4474aed.png)

もとの動画に左右上下に黒いボックスがついた9:16の動画のできあがり！
イラレだけでバナーを作る（基礎編）

https://www.amazon.co.jp/%E6%80%9D%E3%82%8F%E3%81%9A%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E3%81%97%E3%81%9F%E3%81%8F%E3%81%AA%E3%82%8B-%E3%83%90%E3%83%8A%E3%83%BC%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%81%AE%E3%81%8D%E3%81%BB%E3%82%93-%E3%82%AB%E3%83%88%E3%82%A6-%E3%83%92%E3%82%AB%E3%83%AB/dp/4295013277/ref=asc_df_4295013277/?tag=jpgo-22&linkCode=df0&hvadid=553931731904&hvpos=&hvnetw=g&hvrand=5451431662226726309&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=20636&hvtargid=pla-1599255612688&psc=1&th=1&psc=1

こちらの本、デザインのコツは書いてあるのですが、HOW TOは記載がないので、イラレの操作に躓いた時に調べた内容の備忘録兼ねて公開します。

⑴アートボードからはみ出た画像やオブジェクトを消す方法

    切り取りたいオブジェクトの上に、
    切り抜きたい大きさのオブジェクトを配置し、COMMAND＋７
    レイヤーの順番を整えて完成

⑵ガイド線の引き方　ロックの方法

    表示→ガイドを表示
    基本はガイドをロックして運用する
    ガイドを削除する際は、SHIFT＋COMMAND＋Wクリックでパスに変換してからdeleteでガイドロックを解除しないまま消去。

⑶急にイラレが白黒になってしまった　戻らない

    COMMAND+Yで元に戻る

⑷文字にグラデーションを適用する

    https://esolab.co.jp/design/illustrator-gold_character/#:~:text=%E3%80%8C%E3%82%B9%E3%82%A6%E3%82%A9%E3%83%83%E3%83%81%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%83%A1%E3%83%8B%E3%83%A5%E3%83%BC%E3%80%8D%E3%82%92%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF,%E3%81%AE%E6%96%87%E5%AD%97%E3%81%AE%E5%AE%8C%E6%88%90%E3%81%A7%E3%81%99%EF%BC%81
    が何故かうまくいかず他の方法を試すことにしました。

    結論、⑴の応用でできました。
    切り取りたいオブジェクト（ゴールドのグラデ）の上に、
    切り抜きたい大きさの文字列を配置し、COMMAND＋７で切り取り
    レイヤーの順番を整えて完成


⑸写真素材を切り抜いて使う

    ⑴の応用でできました。
    切り取りたい写真素材の上に、
    切り抜きたいオブジェクトを配置し、COMMAND＋７で切り取り
    レイヤーの順番を整えて完成

⑹文字を下揃えにする　助詞を小さくする

    助詞の「の」や「に」だけ小さくすると中央に文字が揃ってしまって違和感を感じていたのを無くす方法。
    ウィンドウ→文字→ハンバーガーメニュー→文字揃え→仮想ボディの下／左で完了。
    文章の途中で文字の等級を変更しても違和感がなくなり満足

⑺イラレで擬似的に傍点を打つ方法

    https://twitter.com/coro46/status/1103668488860651521
    自分は、割注設定（わりちゅう）の文字揃えを中央にしたら整いました。
    わりちゅう・・・って読み方変ですね。

⑻文字を斜めにする方法

    オブジェクト＞変形＞シアー 数値を入力し、角度を選ぶ（１５度など）

⑼写真のシルエットを切り抜く

    フォトショで一旦切り抜いてから配置する。
    オブジェクト選択ツールでオブジェクトを選択
    レイヤーのfxの隣のレイヤーマスクをクリック
    

(10)オブジェクトに効果をつける
    
    アピアランスで塗りの下に効果（Fx)を追加する
    粒状フィルムを適用でのっぺり感を消せました


(11)オブジェクトに影をつける

    「効果」→「スタイライズ」→「ドロップシャドウ」
    切り抜いた画像ののっぺり感を消せました

(12)黒背景、白背景を透過画像に変更する
    
    黒背景はフォトショで加工
    https://nextpage505.com/quick-mask-mode/
    白背景は透明パネルで描画モードを乗算に変更でOK

(13)リボンをたなびかせる

    長方形と三角形を使ってリボンを作る、パスファインダー刈り込み等
    効果→ワープ→旗で角度などを選んでいい感じにリボンを靡かせる
    文字列も同様の処理可能

(14)画像の反転

    リフレクトツールを使います　ショートカット：O

(15)イラレのパス・ゴミとり

    【オブジェクト】→【パス】→【パスの削除】で全てのチェック項目にチェックを入れてOKをクリック

(16)アピアランスで文字の縁取

       http://www.illustratorphotoshop.design/illustrator/illustrator_appearance02/
アピアランスに新規線を追加していく（一番後ろ）

(17)文字の影をパスの変形を使って疑似的につける

      https://www.youtube.com/watch?v=ZdG5p0zL7so
      効果＞パスの変形＞変形＞移動1,1、コピー12
(18)
(19)
(20)

※今後追記します。
【Rails】エラーメッセージを表示させたい！

# はじめに
文章を投稿するときに、空文字にしてエラーをバリデーションで検知、それをエラーメッセージとして表示させたい。

# 前提
| No |    項目     |   内容    |
|---:|-------------|------------|
| 1  |      OS       |   Mac     |
| 2  |       Ruby      |   2.6.3   |
| 3  |       rails      |      6.0.4 |

# 実装
# 1. バリデーションを実装
まず最初に、投稿内容にvalidationをかける。項目は空欄と5000文字以上。
```言語名:app/models/post.rb
validates :content, presence: true, length: { maximum: 5000 }
```

# 2. コントローラーの設定
postコントローラーのnewアクションに、**current_userが投稿したオブジェクト(@post)** を渡す。これがエラーメッセージの情報を格納するための箱となってくれる。
```言語名:app/controllers/posts_controller.erb
def new
 @post = current_user.posts.build
end
```
　
# 3. テンプレートを設定
次に、newアクションのデフォルトで呼び出されるnewテンプレートに、エラーメッセージ表示させるパーシャルを追加する。
```言語名:app/views/post/new.html.erb
<div class="row">
<%= form_with(model: @post) do |f| %>
 　# エラーメッセージ表示
  <%= render 'shared/error_messages', object: f.object %>

　　　　#　　ここから下は今回のテーマとは関係ないため無視して良い
  # 投稿内容記載フォーム 
  <div class="field">
    <%= f.text_area :content, placeholder: "記事を書いて..." %>
  # Postリクエスト
  </div>
  <%= f.submit "Post", class: "btn btn-primary" %>
<% end %>
</end>
```
newテンプレートの投稿フォームを未入力で送信したときにvalidationによってエラーが発生し、その情報が@postに格納される。
それが、error_messagesパーシャルに渡されて、エラー内容表示をするための材料として扱われる。
このとき、**object: f.object**によって材料を渡している。変数objectに対して、f.objectを渡す。


`筆者はこのobjectに情報を渡し方を間違えて表示がうまくできなかった。@postをPost.newとしてしまい、そこには当然エラーメッセージは格納されないため、エラー表示が出なかった。`

渡されたオブジェクトを使って描画していく。
```言語名:app/views/shared/_error_messages.html.erb
<% if object.errors.any? %>
  <div id="error_explanation">
    <div class="alert alert-danger">
      The form contains <%= pluralize(object.errors.count, "error") %>.
    </div>
    <ul>
    <% object.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
    </ul>
  </div>
<% end %>
```
これでエラーメッセージを表示できるようになった。
![スクリーンショット 2022-08-12 17.07.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2684787/9dea0a55-68cd-6613-c1a3-48bd02e7fe57.png)

# さいごに
今回行った実装手順を書きにまとめる。
1. バリデーションをかける。
2. そのエラー内容をコントローラーの@postに格納する。
3. テンプレートに渡された変数にform_withを使い、@post.object（エラー内容情報）をエラーメッセージ用パーシャルに渡す。@post.objectのエラー内容や、エラー個数を呼び出してレンダリングする。
pwgenでパスワードを自動生成する方法

## はじめに
備忘録
タイトルの通りです。
実行環境はmacOSのターミナル（zsh）です。
どなたかのお役に立てれば幸いです。
## pwgenをインストールする
```zsh
% brew install pwgen
```
:::note warn
brewコマンドを利用するためにはHomebrewをインストールする必要があります。
:::
https://brew.sh/index_ja
## パスワードを生成する
### 8文字のパスワードを生成（デフォルト）
```zsh
% pwgen
```
### 16文字のパスワードを生成
```zsh
% pwgen 16
```
### 32文字のパスワードを1つ生成
```zsh
% pwgen 32 1
```
### 特殊文字（記号）を含むパスワードを生成
```zsh
% pwgen -y
```
### ランダム性の高いパスワードを生成
```zsh
% pwgen -s
```
### 生成したパスワードを1行ずつ表示
```zsh
% pwgen -1
```
### 16文字 & 特殊文字 & ランダム性の高いパスワードを3つ生成して1行ずつ表示
```zsh
% pwgen -y -s -1 16 3
```
# ブログもあります
https://kyit.net/how-to-use-pwgen/
Jenkins 操作

# はじめに
Jenkins の操作について、備忘録的なものを残す。
# 操作
## UI
### ダッシュボード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477044/0657f10d-d8c9-93af-8468-6285787f2818.png)
### プロジェクト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477044/ac7dca42-3d52-9484-3b7d-b4277d5f9696.png)
### 設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477044/55808c77-042e-ab1c-4b21-193b50039605.png)
### 設定の下に Shell 追加する箇所がある
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477044/46e1fab0-8af2-872b-5a52-89019dd1187c.png)
### コンソール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477044/3ec69ed4-8f37-1256-ecb7-30edf8f8a44d.png)
### パラメータ設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477044/40150f61-28f8-7244-1f54-4b3e3d580591.png)
### parameter 設定した場合、Build 時に value が正しいか聞かれる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477044/ab5b3e20-db0a-cbdd-a758-7ae42f1fcbde.png)
### Choice を選択した場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477044/b0440263-b361-4741-e016-950094795f57.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477044/7f4b73f7-14d1-cf1e-51bb-05d70d6cfa37.png)
### Boolean を選択した場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477044/7bcadc11-f2c1-d8a0-b51b-58a6da7382d7.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477044/8ff67406-921a-d6a1-5535-1612e76119d6.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477044/23bb6382-0a12-4e81-38a7-e6f184d0c978.png)




## コマンド
```
// Jenkins のコンテナに入る
$ docker exec -ti condescending_boyd bash
```
### お試しコマンド
以下のコマンドを Jenkins の Shell に追加して、Build を実行すると結果が得られる。
#### 結論: Jenkins の Build job 実行すると、ファイルや変数はコンテナを参照する。
```
// コンテナの中でお試しコマンド
NAME=fmyuk
$ echo "Hello, $NAME. Current date and time is $(date)"
```
```
// /tmp/info に出力
$ echo "Hello, $NAME. Current date and time is $(date)" > /tmp/info
$ cat /tmp/info
```
```
// /tmp/script.sh を作成して Jenkins で Build 実行すると結果が得られる。
// Terminal で以下を実施
$ vi /tmp/script.sh
#!/bin/bash
NAME=$1
LASTNAME=$2
echo "Hello, $NAME $LASTNAME"

$ sh /tmp/script.sh
```
[UE5]ブループリントでPythonファイルの実行

Unreal Engine5のブループリントで.pyファイルで書いた関数を呼び出す方法です。
****
**準備**
１）Unreal Engine5のインストール
２）UE5を起動し、プロジェクトを新規する
３）(右上の) Settings　→　Plugins　→　`Python Editor Script Plugin`をチェックする
![MicrosoftTeams-image (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727189/4ab90193-f454-b21c-e0d7-6ff7d07b699f.png)
４）UE5再起動

プロジェクト内で一番下のところで下記の図通りでPythonファイルが実行可能になります。
<img width="400" alt="mojikyo45_640-2.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727189/f5b0abed-b313-1163-ac73-3881e9ee4923.png">

****
***Step1 ブループリントを開く***
Content Drawerの空白の箇所で右クリックして、`Editor Utility Widget`を作成する。
![無題3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727189/573f1fbb-adef-6ddd-64bc-efaa8a3d2bee.png)
新規のEditor Utility Widgetをダブルクリックして、Widgetの設計画面に入れ、ここで、一つ制御ボタンを作る。
![MicrosoftTeams-image (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727189/756f4758-4fdf-bb6b-4458-2039d517fc6e.png)

ボタンのディテールで一番下の`On clickedイベント`を左クリックし、ブループリントでイベントノードが作成できる。
![無題5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727189/3323b7e7-eb94-d0a5-f53c-0c5c7a73d8f4.png)
****
***Step2 Pythonコマンドを実行しましょう***
まずは、好きな場所で下の図のようなPythonファイルを作りましょう。
```
print('Hello World!')
def foo():
    print('This is a function called foo.')
```

ブループリントでPythonの実行方法は3つあってここで、`Execute Python Command`をクリックします。
On clickedイベントのノードを左クリックしながら、少しドラッグしてドロップする。
検索ボックスで「python」を入力して、いつくかのファンクションが表示される。
![MicrosoftTeams-image (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727189/f43c1404-1733-ce26-1e64-78e9ff426ac1.png)

`Execute Python Command`を選んで、Python Commandで下記のようなコードを入力してください。
![無題8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727189/f4ad050f-1951-a15b-1919-2b987c154cdc.png)
こちらではPythonコマンドを入力するところです。
書き方はPythonファイルの記述方法とほぼおなじです。
`import sys`はPythonファイルの保存パスを追加します。
```
import sys
sys.path.append('C:/***上記のPythonファイルの保存ディレクトリ***/')
# import 上記のPythonファイルの名前（例はmyprint.py）
import myprint
myprint.foo()

# 連続実行したい場合は下記のコードが必須です。
import importlib
importlib.reload(myprint)
```
:::note warn
警告
パスの書き方に注意してください。
X: C:\Users\yourname\Documents\Python
○: C:/Users/yourname/Documents/Python
:::
****
***Step3 実行してみましょう***
実行前には、ブループリントの左上のコンパイルのクリックを忘れないでください。
![MicrosoftTeams-image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727189/f4fbfe53-aa29-6121-28e1-cd847fd77ebd.png)


UEのDefault画面に戻って、Content Drawerを開いて、さっき作成したEditor Utility Widgetで右クリックして`Run Editor Utility Widget`をクリックする。
![無題9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727189/5da25a8d-1e57-dd45-931f-81dfb9b3da74.png)
その後、EUWのウィンドウが表示され、ボタンを押すと、Output Logでprint分の文字列が出力される。
<img width="350" alt="Pythonファイル" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727189/8237bd73-8ae8-3007-606c-091016d7ca88.png"> <img width="400" alt="Python関数" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727189/c2957e50-adf4-360b-680d-1886900b9abf.png">
STM32G031J6M6とmbrd-os 6でタイミング系を使うと落ちるのでちょつとだけ頑張ったレス


目的
なんか気持ち悪い
進捗か止まっていたのは、タイミング系のせい?
なんか頑張ってみる
今のところ原因不明で継続テーマ


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/63231563-38f9-3d86-e979-423d2363f54e.png)



```c++

        ThisThread::sleep_for(5s);

```

で

```c++

++ MbedOS Error Info ++
Error Status: 0x80FF0100 Code: 256 Module: 255
Error Message: Fatal Run-time error
Location: 0x8003349
Error Value: 0x0
For more info, visit: https://mbed.com/s/error?error=0x80FF0100&tgt=NUCLEO_G031K8
-- MbedOS Error Info --
HAL_RCC_OscConfig ERROR



```

-------------------------------------

```c++

time_t seconds = time(NULL) + (60 * 60 * 9); // JST


```

で

```c++

++ MbedOS Error Info ++
Error Status: 0x80FF0100 Code: 256 Module: 255
Error Message: Fatal Run-time error
Location: 0x8003C51
Error Value: 0x0
For more info, visit: https://mbed.com/s/error?error=0x80FF0100&tgt=NUCLEO_G031K8
-- MbedOS Error Info --
Cannot initialize RTC with LSE



```

----------------------------------------

```c++


Timer t;


int main()
{


省略

    t.start();

    int ii;
    while(1) {

        auto s = chrono::duration_cast<chrono::seconds>(t.elapsed_time()).count();
        sprintf( buf, "%llu\r\n", s );

        ii=0;
        while(buf[ii] != 0) {

            HAL_UART_Transmit(&hlpuart1, (uint8_t *)&buf[ii], 1, 10);
            ii++;
            
        } //while

} //main


```

で

![o_con655.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/cc5dc1e0-6efc-2d01-8d25-8e0567eeac91.jpeg)


タイマーだとタイミングを取れそう
翻訳では、騒がしいタイマーと言ってあまり良くないらしい
割り込み系のタイマーを頑張ってみよう


----------------------------

stm767ziを使うと上手く動く


```c++



/* mbed Microcontroller Library
 * Copyright (c) 2019 ARM Limited
 * SPDX-License-Identifier: Apache-2.0
 */

#include "mbed.h"

#define WAIT_TIME_MS 500 
DigitalOut led1(LED1);

int main()
{
    printf("This is the bare metal blinky example running on Mbed OS %d.%d.%d.\n", MBED_MAJOR_VERSION, MBED_MINOR_VERSION, MBED_PATCH_VERSION);

    while (true)
    {
        led1 = !led1;
        thread_sleep_for(WAIT_TIME_MS);
    }
}



```


```c++

/* mbed Microcontroller Library
 * Copyright (c) 2019 ARM Limited
 * SPDX-License-Identifier: Apache-2.0
 */

#include "mbed.h"


// Blinking rate in milliseconds
#define BLINKING_RATE     500ms


int main()
{
    // Initialise the digital pin LED1 as an output
    DigitalOut led(LED1);

    while (true) {
        led = !led;
        ThisThread::sleep_for(BLINKING_RATE);
    }
}



```


```c++


/* mbed Microcontroller Library
 * Copyright (c) 2019 ARM Limited
 * SPDX-License-Identifier: Apache-2.0
 */

#include "mbed.h"
#include "platform/mbed_thread.h"


// Blinking rate in milliseconds
#define BLINKING_RATE_MS                                                    170


int main()
{
    // Initialise the digital pin LED1 as an output
    DigitalOut led(LED1);

    while (true) {
        led = !led;
        thread_sleep_for(BLINKING_RATE_MS);
    }
}




```
Memo - Python Parallel and Concurrent Programming

## Threading

### to run the function in a new thread (non-daemon)
```
import threading
thread_variable = threading.Thread(target=function_name)
thread_variable.start()
```

### to call the function back to the main thread
```
thread_variable.join()
```

### to run the function in a daemon thread
> When the main thread exits, the daemon thread(s) will automatically exits.

```
thread_variable.daemon = True
thread_variable.start()
```

### to set a mutual exclusion
```
lock_variable = threading.Lock()
```

#### to protect "my" access
> Will wait if someone else is accessing

```
lock_variable.acquire()
```

#### to protect "my" access without waiting
> Will give up immediately if not available

```
lock_variable.acquire(blocking=False)
```

#### to release "my" access
```
lock_variable.release()
```

#### to use Reentrant lock
> This allows to lock multiple times in the same thread. It has to unlock as many as locking. Useful in a recurrsion.

```
rlock_variable = threading.RLock()
rlock_variable.acquire()
rlock_variable.release()
```

#### to lock conditionally
```
lock_condition_variable = threading.Condition(lock=a_variable)
```

##### to wait until being notified by other threads
```
lock_condition_variable.wait()
```

##### to notify another thread
> Should call before exiting a thread

```
lock_condition_variable.notify()
```

##### to notify all other threads before exiting a thread
> Should call before exiting a thread

```
lock_condition_variable.notify_all()
```

## to use Read/Write lock
```
from readerwriterlock import rwlock
rwlock_variable = rwlock.RWLockFair()
```

#### to lock for reading
```
read_lock_variable = rwlock_variable.gen_rlock()
read_lock_variable.acquire()
read_lock_variable.release()
```

#### to lock for writing
```
write_lock_variable = rwlock_variable.gen_wlock()
write_lock_variable.acquire()
write_lock_variable.release()
```

### to use Semaphore
> Semaphore manages a counter representing the number of release() calls minus the number of acquire() calls.

```
lock_variable = threading.Semaphore(1)
```

## Thread Pool

> Maintain a collection of threads and re-use them.

```
from concurrent.futures import ThreadPoolExecutor
pool = ThreadPoolExecutor(max_workers=5)
pool.submit(function_name)
pool.shutdown()
```

### Future

```
from concurrent.futures import ThreadPoolExecutor
pool = ThreadPoolExecutor(max_workers=5)
future = pool.submit(function_name)
future.result()
```

## Multiprocessing

### to start the function in a new process
```
import multiprocessing
process_variable = multiprocessing.Process(target=function_name)
process_variable.start()
```

## Process Pool
> Main a collection of threads and re-use them.

```
from concurrent.futures import ProcessPoolExecutor
pool = ProcessPoolExecutor(max_workers=5)
pool.submit(function_name)
pool.shutdown()
```
GKEの認証を新しいプラグイン gke-gcloud-auth-plugin に変更する

GKEを利用していたら、Googleから、

> [Action Required] Install a new plugin binary to support Kubectl access to GKE clusters

と題されたメールが届きました。
ざっくり読むと、GKEのバージョンがv1.25になるタイミングで認証方式を変えるため、今後は認証に新しいプラグイン `gke-gcloud-auth-plugin` を使いなさいとのこと。
そしてそのプラグインのインストール方法などが記されていました。

最近久しく `kubectl` を叩いてなかったので、試しに実行したら確かに警告が出ます。

```
$ kubectl get pods              
WARNING: the gcp auth plugin is deprecated in v1.22+, unavailable in v1.25+; use gcloud instead.
To learn more, consult https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke
```

警告に記されているページを見たら、メールよりもさらに詳しく説明されていました。

https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke


それに従って認証方式を変更します。`gcloud` は既にインストールされている前提です。

```
$ gcloud components install gke-gcloud-auth-plugin
```

```
$ gke-gcloud-auth-plugin --version
```

でバージョンも正常に出力されました。

次に `kubectl` で `gke-gcloud-auth-plugin` を使えるように設定します。
`.zshrc` または `.bashrc` などに以下の1行を追加。

```
export USE_GKE_GCLOUD_AUTH_PLUGIN=True
```

追加した設定を反映させます。

```
$ source .zshrc
```

`gcloud` を最新にします。

```
$ gcloud components update
```

最後にクラスターの新しい認証情報を取得します。

```
$ gcloud container clusters get-credentials CLUSTER_NAME
```

これで `kubectl` を実行しても上記の警告は出なくなりました。
めでたしめでたし:beer:
D-Link DBA-1210PのopenWrt化の手順

__※dap-2610pを所持していることが前提です。__
- dap-2610pで全mtdバックアップを取得する。→[取得スクリプト](https://openwrt.org/docs/guide-user/installation/generic.backup#create_full_mtd_backup)

- dba-1210pのUARTは シールド側からTX,GND,3.3V(接続しない),空き,RX　※クロス接続する。
    - コンソール入力不可の場合、High Current I/Oの変更を試す。
        - FTDIの場合：[EEPROM設定ツール](https://ftdichip.com/wp-content/uploads/2022/05/FT_Prog_v3.12.29.638-Installer.zip)
    - 設定変更してもダメな場合は、ハードを改造
        - R164(pulldown 500Ω)を除去、pullup10kΩを追加
        - 部品が小さいので間違ってR163(直列:56Ω)を除去してしまった場合はショートする
- 念の為、dba-1210pの全mtdバックアップを取得する。
    - 標準OSには root passが設定されているが 起動中に f [Enter]で failsafe モードに入り、以下のコマンドを実行して、root passをクリアする。
mount_root
passwd -d root
rebootするとログイン可能になる。
上記スクリプトで全mtdバックアップを取得する。
- dba-1210のu-bootからflashにdap-2610pのu-boot, u-boot環境変数を書き込む。serveripはtftpサーバのPCのアドレス
```bash:コマンド
setenv serverip 192.168.1.90
tftpboot 0x84000000 mtd6_APPSBL.backu &&　sf probe && sf update 0x84000000 0xf0000 0x80000
tftpboot 0x84000000 mtd5_APPSBLENV.backup && sf probe && sf update 0x84000000 0xe0000 0x10000
```
- 電源OFF/ONを行い、u-bootでqを2回押してプロンプト(#)を表示させる。
- tftpサーバのIPアドレスを、192.168.0.90に変更する。
- dba-1210向けfirmwareを書き込む。
    - firmware：[dap-2610pベースにbuildしたファイル](https://github.com/hobata/dba1210p)
    - openWrtのdap-2610pファームは、何故かEthernetが正常動作しない
```bash:コマンド
set signature wapac30_dkbs_dba1210
setenv serverip 192.168.0.90
saveenv
tftpboot 0x84000000 f1210-7.bin && sf probe
sf update 0x84000000 0x180000 0xdc0000
sf update 0x84000000 0x1780000 0xdc0000
```
- 電源OFF/ON
[React]外部module読み込んだ時にstyleつけたい。。

next:  12.0.4
react: 17.0.2

# 背景
外部のmoduleをinstallしてそこに自分で作ったスタイル当てたい！
今回の例で言うとカレンダーを使いたかったので[react-calendar](https://www.npmjs.com/package/react-calendar)を`npm install`
用意されてるpropertyでは微妙だったのでスタイルを自分でカスタマイズしたい！

# 問題
このように外部モジュールを読み込んだ時にcssはグローバルで定義しないと当たらない。（多分）
でも毎回globalなcssに書くのはファイルが大きくなるし、component使わないところに読み込まれるのも違和感がある。

デフォルトであるmodules cssなどはscope化されるのでstyleを当てることができない。
困った。

# 解決法
[styled-jsx](https://github.com/vercel/styled-jsx)使えばファイルには切り出せる。
ちなみにnextにはデフォルトで入ってるのでmoduleのinstallは必要ない

```component.jsx
<>
  <Module>...</Module>
  <style jsx global>{`
    .module {
      color: white
      ...
    }
  `}</style>
</>
```

:::note warn
styled-jsxもscope切られるのでglobalで定義しないと無理です。
他に良い方法があれば知りたい
:::

# エラー解消
tsいわく`jsxはStyleHTMLAttributesに存在しない`とのこと
issueあった。https://github.com/vercel/styled-jsx/issues/90

最終的にはcustom.d.tsを自分で作って定義すれば良い
```src/types/custom.d.ts
import 'react';

// styled-jsxの型定義
declare module 'react' {
  interface StyleHTMLAttributes<T> extends React.HTMLAttributes<T> {
    jsx?: boolean;
    global?: boolean;
  }
}
```
```tsconfig.json
"compilerOptions": {
  // 追加
  "typeRoots": ["node_modules/@types", "./[適当なpath]/types"]
}
```
画像の背景を削除する 7 つの方法 - 簡単な手順

## 1. Photoshopの消しゴムツールを使う

写真をPhotoshopで開く
背景レイヤーをダブルクリックして通常レイヤーにする 
ツールバーで背景消しゴムを見つけます。ショートカット キーは e です。
消しゴムの硬さとサイズを調整し、不要な背景を手動で消去します。


## 2. Photoshop のマジック ワンド ツールを使う

ctrl+J で背景レイヤーを複製します。
ツールバーの魔法の杖ツールを選択し、ショートカット キーは W です。
切り取る必要のある部分をクリックすると、魔法の杖が自動的にそれらをフレームに収めます。
Alt キーを押して選択範囲を減らし、Shift キーを押して選択範囲を増やします。
削除をクリックして、選択を削除します。

## 3. Photoshop のクイック選択ツールを使う

ツールバーでクイック選択ツールを見つけます。
削除するパーツを左クリックします。
角括弧「[」、「]」を押してズームアウトし、ブラシをズームアウトします。
Alt キーを押して、クイック選択ボックスを超えた部分を変更し、調整を行います。
削除するには、削除を押します。

## 4. Photoshop の多角形なげなわツールを使う

多角形なげなわツール、ショートカット L を選択します。
マウスをオブジェクトの端に沿って移動すると、オブジェクトが自動的にフレーミングされます。
最後に、マウスを開始位置に置き、閉じた円を形成します。
Ctrl+J を押してレイヤーをコピーします。

## 5. Photoshop の Channel Tool を使う

ディテール除去背景に最適
[チャンネル] パネルに移動し、白黒のコントラストが最も強いチャンネルを選択し、そのチャンネルを複製します。
ctrl+L を押してレベルを調整し (Image-Adjustments-Levels)、黒と白のコントラストを上げます。
Image-Adjust-Invert に移動し、全体的なレベルを調整して、文字全体を黒くします。
Ctrl キーを押しながらチャンネルをクリックし、RGB をクリックしてカラー モードに戻り、[削除] をクリックします。


## 6.オンラインカットアウトツール
Photoshopで背景を削除するのは面倒だと思いませんか?
引き続き、使いやすいオンライン[背景除去ツール](https://www.fotor.com/jp/features/background-remover) をお勧めします。
画像をインポートするだけで、システムは背景をすぐに自動的に削除します。

## 7.パワーポイントを使う
新しい PowerPoint を作成し、写真をインポートします。
「画像形式」で「背景の削除」オプションを見つけます。
切り抜きが不完全な場合は、「Mark Reservation Area」をクリックして手動で調整します。
最後に「変更を保持」をクリックします。
Heroku CI で Postgres のセットアップに失敗するようになった

2022年8月からHerokuCIでのテスト実行時にデータベースのセットアップに失敗するようになった。

## 環境

- Rails 6.0
- Postgres (Heroku Postgres)

## 事象

`heroku_ext schema` とは・・。

```
rake aborted!
ActiveRecord::StatementInvalid: PG::RaiseException: ERROR:  Extensions can only be created on heroku_ext schema
```

## 原因

2022年8月1日から、新しく作られる全ての Heroku Postgres データベースでは heroku_ext schema がインストールされる、というようなことが書いてある。
https://devcenter.heroku.com/changelog-items/2446

## 対処法

ひとまず `schema.rb` の先頭を以下のように変更したところ失敗しなくなった。
この方法がなぜ有効なのかは調査中。

```diff
ActiveRecord::Schema.define(version: 2022_07_29_062012) do

  # These are extensions that must be enabled in order to support this database
-  enable_extension "plpgsql"
+  connection.execute('CREATE EXTENSION IF NOT EXISTS "plpgsql" WITH SCHEMA "heroku_ext"')
  ...
end
```

## 補足

- Heroku ReviewApps でも発生するらしい
NCMBでスクリプト利用時のシグネチャ作成処理での注意点

ニフクラ mobile backendではアプリケーションキーとクライアントキーの2つを使って、リクエストデータを署名（シグネチャ生成）します。署名処理は簡単に書くと、次のようになります。

- リクエストメソッドを取得
- FQDNを取得
- リクエストしたAPIのパスを取得
- クエリストリングの取得
- アプリケーションキーを設定
- シグネチャメソッドを設定
- シグネチャバージョンを設定
- タイムスタンプを設定
- それぞれの値を「&」で連結
- 署名用文字列の作成

大雑把に言うと、必要な情報を集めて文字列にし、それをクライアントキーでハッシュ化するということになります。詳しくは[REST API リファレンス : シグネチャの生成方法 | ニフクラ mobile backend](https://mbaas.nifcloud.com/doc/current/rest/common/signature.html)にてご覧ください。

このシグネチャ作成処理は公式、非公式を問わずSDKでは隠蔽しています。そのため、普通に開発している限りはあまり気にすることはないかと思います。しかしSDKが提供されていない言語でNCMBにデータを登録したり、検索したい場合もあるかと思います。そうした時に（多分）役立つかも知れません。

## スクリプト利用時の注意

NCMBでは以下の機能があります。今回の件はスクリプト機能に対するものです。

- データストア（クラウドデータベース）
- ファイルストア（ファイルストレージ）
- プッシュ通知  
- 会員管理
- スクリプト

## スクリプトの特徴

スクリプト機能はいわゆるFaaS（Function as a Service）になります。クラウドサービス上にコード（Node.jsまたはRuby）をアップロードして実行できる仕組みです。

このスクリプトでは、実行時に以下の情報を一緒に送信できます。

- ヘッダー
- クエリーストリング
- リクエストボディ

**この時、署名作成に関係するのはクエリーストリングのみになります。**

## クエリーストリングを利用するタイミング

そして注意点です。クエリーストリングを署名に使うのは **GET リクエストの場合のみ** です。POST/PUT/DELETEの際にもクエリーストリングは追加できますが、署名作成には利用しないので注意してください。

スクリプト以外の機能を使う際には、GET以外にはクエリーストリングを使っていないため、スクリプトでも省かれているのだと思います。

## まとめ

ということで、スクリプト機能を使うための署名処理を作る際には、GETの場合だけクエリーストリングを署名作成に利用してください。他のメソッドの時に使うと、署名が間違っているというエラーになります。

[REST API リファレンス : シグネチャの生成方法 | ニフクラ mobile backend](https://mbaas.nifcloud.com/doc/current/rest/common/signature.html)
DPI とは

## 勉強前イメージ

通信のパケットをなんやかんや・・・

## 調査

### DPI とは

Deep Packet Inspection の略でパケットの検査の手法の一つになります。

deepではないインスペクションはルーターなどやファイアウォールなどの装置が通信するパケットを監視します。
データを解析したり侵入や攻撃などのパケットが検出されたりすると
そのパケットを破棄して通信を遮断したり通知したりします。

deepなインスペクションはOSI参照モデルのアプリケーション層などのプロトコルのデータを確認して検査を行います。
データの内容に踏み込んで解析することでヘッダ情報だけじゃわからない挙動を検知することができます。
また、インスペクションでは不可能だったダイナミックにTCP/UDPのポート番号が変わることに対応できたりします。

## 勉強後イメージ

ファイアウォールの中の機能ってやつなのかな。。。
Deep Packet Inspection とただの Inspectionがある・・・・
Inspectionもいろいろありそうやけどね。

## 参考

- [ディープパケットインスペクション 【DPI】 Deep Packet Inspection](https://e-words.jp/w/%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%91%E3%82%B1%E3%83%83%E3%83%88%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%9A%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3.html)
- [インスペクション 【inspection】](https://e-words.jp/w/%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%9A%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3.html)
データの誤り制御

# データは１と０の波形からなっている
はっきりした１と0のデータが流れているわけではない。
信号の波形でこの範囲の値は１、０と判断されている。
これが乱れることがある。
* 伝送距離が伸びる
* 横から別の電気的な干渉

この波形の乱れが起きることをデータの誤りと言う。
データの誤りを防ぐ方法がある。
* パリティチェック
* CRC(巡回冗長検査)

しかし```100%確実に防ぐ手段はありません```。

# パリティチェック
ビット列に```パリティビット```と呼ばれる。
検査用のビットを付加させることでデータの誤りを検出する。
検査ようのビットを付加させる方法が２つある。
### 偶数パリティ
ビット列の中の1の数が偶数になるようにする。

### 基数パリティ
ビット列の中の1の数が基数になるようにする。

#### 例
Aの文字コードを偶数パリティで付加しておくるとする。
そうすると１が奇数になってデータの誤りが検出される仕組みだ。

## パリティチェックの注意点
* １ビットの誤りを検出するだけ
* 偶数個ビット誤りは検出できない。
* どのビットが誤りかもわからない。

## 水平垂直パリティチェック
データの誤りが１ビットの場合のみ誤りを特定できる。
### 特定方法は
データ列を縦に並べる。
データ列の１ビットごとに偶数の場合は偶数に合わせて１か０を付加させる。
これを```水平パリティ```
データ列の最後（下)に偶数の場合は偶数にして１か０を付加させる。
これを```垂直パリティ```
これを組み合わせて使うのが```水平垂直パリティ```と言う。

### 注意点
２ビット以上の誤りは誤りは検出できるが、誤り位置の特定はできない。

## CRC（巡回冗長検査)
### 特徴
* ```データ誤り訂正は行えない```。
* ```連続したビットの誤り(バースト誤り)を検出```する
* ```複数ビットの誤りを検出```する

### 検出方法
ビット列を```特定の式（生成多項式と呼ばれる)で割る```。
その割り算の結果で余りが出る。
その```余を元のビット列にその余をくっつける```。
そのくっつけられたビット列で```生成多項式を割り切ることができる```。
こうすることで```誤りを検出```する。

#### 気づき
ビット列の割り算を基にしているのか。
でもなんで割り算にしているのか？
なんか数学の話になりそうだから先にいく。

出典 キタミ式イラストIT塾　基本情報技術者　令和03年
maven を使ってみた時のメモ


maven を使った時のことをメモしておきます
自分用メモです

# 環境

```
$java --version
openjdk 18.0.2 2022-07-19
OpenJDK Runtime Environment Homebrew (build 18.0.2+0)
OpenJDK 64-Bit Server VM Homebrew (build 18.0.2+0, mixed mode, sharing)

$mvn --version
Apache Maven 3.8.6 (84538c9988a25aec085021c365c560670ad80f63)
Maven home: /usr/local/Cellar/maven/3.8.6/libexec
Java version: 18.0.2, vendor: Homebrew, runtime: /usr/local/Cellar/openjdk/18.0.2/libexec/openjdk.jdk/Contents/Home
Default locale: en_JP, platform encoding: UTF-8
OS name: "mac os x", version: "12.5", arch: "x86_64", family: "mac"
```

# やってみる

```
# 雛形生成
mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

# mvn package
cd my-app
mvn package

(以下略)

ERROR] Source option 5 is no longer supported. Use 7 or later.
[ERROR] Target option 5 is no longer supported. Use 7 or later.
```

以下の GitHub issue を参考に `pom.xml`　に追記

[Source option 5 is no longer supported. Use 6 or later. #400](https://github.com/jflex-de/jflex/issues/400)


```
  <properties>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>
```

```
mvn package
```

これで成功

# Tips

## settings.xml を指定して使いたい

`-s` オプションで指定する

```
# help
mvn  --help

・・・・
 -s,--settings <arg>                    Alternate path for the user
                                        settings file

# カレンとディレクトリのファイルを指定
mvn install -s settings.xml

```

## パッケージの所在

`~/.m2/repository` 配下に配置されていた

## 通信できない場合にタイムアウトさせたい

リポジトリにアクセスできない(HTTPS 通信ができない)状況でタイムアウトすることを期待したが、2、3分ほど待ったものの、エラーが発生しなかった
明示的に `settings.xml` に追記をすることでタイムアウトするようになった

[Mavenでリポジトリへの接続タイムアウトを設定する](https://kazuhira-r.hatenablog.com/entry/20130623/1371978072)
【Git】git diff の使い方

## リモートとの差分

```
$ git diff HEAD..リモート名/ブランチ名
```
```
$ git diff リモート名/ブランチ名..HEAD
```

## 直近のコミットの差分

```bash
git diff HEAD^..HEAD
```

## ブランチ間の差分

```bash
git diff ブランチA..ブランチB
```

## コミット間の差分

```bash
git diff 変更前のSHA..変更後のSHA
```

## 特定のファイルの差分
```bash
git diff -- ファイルパス
```
```bash
git diff ブランチA..ブランチB -- 対象のファイルパス
```


## ファイル名のみ出力

```bash
git diff --name-only
```
NCMB Flutter SDKがサブクエリに対応しました


FlutterはDartで書かれたフレームワークになります。元々iOSやAndroidといったスマートフォン向けでしたが、今ではWebやWindows、macOSといったマルチプラットフォームで動作します。Flutter/Dartを覚えることで、多くの環境に対してアプリケーション開発が可能になります。

NCMBでは公式SDKを提供していませんが、非公式に開発を進めているFlutter SDKがあります。だいたいの機能は実装してきましたが、今回サブクエリに対応しました。より複雑なデータ取得方法に利用できますので、覚えておくと便利な場面があるかも知れません。

[ncmb | Dart Package](https://pub.dev/packages/ncmb)

# インストール

`flutter pub get ncmb` でインストールできます。

# 使い方

任意のファイル上でライブラリを読み込みます。

```dart
import 'package:ncmb/ncmb.dart';
```

そしてNCMBオブジェクトを初期化します。

```dart
NCMB('APPLICATION_KEY', 'CLIENT_KEY');
```

# サブクエリについて

データストアのクラス同士でデータを連係させる場合、二つの方法が用意されています。

- ポインター
- リレーション

ポインターは1対n、リレーションはn対nのデータ関係性において利用が可能です。しかし、データ連係を行わずに各クラスにデータを投入してしまっている場合もあるでしょう。そこで使ってみたいのがサブクエリです。

# 通常の方法

例えば以下のようなデータを考えてみます。

## Groupクラス

| name |
|--------|
| Group 1 |
| Group 2 |
| Group 3 |

## Memberクラス

| Group | name |
|--------|--------|
| Group 1 | Test 1 |
| Group 1 | Test 2 |
| Group 1 | Test 3 |
| Group 2 | Test 4 |
| Group 2 | Test 5 |
| Group 2 | Test 6 |

リレーションやポインターがない状態ですと、例えば以下のような検索方法が考えられます。

```dart
var groupQuery = new NCMBQuery('Group');
groupQuery.equalTo('name', 'Group2');
// データ取得（クエリ実行）
var group = await groupQuery.fetch();
var memberQuery = new NCMBQuery('Member');
memberQuery.equalTo('Group', group.name)
// データ取得（クエリ実行）
var members = await memberQuery.fetchAll();
print(members);
```

この場合の問題点としては、クエリを2回実行しているということです。そのため、APIの消費量はもちろん、ネットワークの遅延も発生します。

# サブクエリの利用

サブクエリを使った場合、次のようなコードになります。データを取得する `fetchAll` は1回しか実行していません。

```dart
var groupQuery = new NCMBQuery('Group');
groupQuery.equalTo('name', 'Group 2');
var memberQuery = new NCMBQuery('Member');
memberQuery.select('group', 'name', groupQuery);
// データ取得（クエリ実行）
var members = await memberQuery.fetchAll();
```

見て分かる通り、グループについては検索を実行していません。その状態でメンバークラスのselectメソッドを使います。そうすることでグループの検索結果を用いて、その条件にマッチするデータを取り出すことができます。

ポインターやリレーションでも同じような操作はできますが、より柔軟な検索が可能です。

# まとめ

mBaaSのようなNoSQL型のデータベースを使いつつもデータをリレーショナルに管理したいという要望は根強くあります。そうした時にはポインターやリレーションを使ったり、さらにサブクエリを使うことで柔軟なデータ抽出が実現できるでしょう。

NCMBのDart/Flutterパッケージは[ncmb | Dart Package](https://pub.dev/packages/ncmb)にて公開しています。ぜひ試してみてください！

[ncmb | Dart Package](https://pub.dev/packages/ncmb)
docker きほんのき

## 背景
Dockerの書籍（Docker&Kubernetesのきほんのきほん） という本を先輩にお借りしてかなり勉強になったので、整理するために残しておきたい。

Dockerの用語、container, image, network, volume, Dockerfile, docker-composeをなんとなくしか知らなかったので、それを明確にしていきたい。

## Dockerとは
一言で表すと、**「データやプログラムを隔離できる仕組み」** 

### データやプログラムを隔離できると何が嬉しいのか
パソコンや物理サーバーでプログラムを実行する場合、複数のプログラムが動いている。
それらのプログラムにはそれぞれの実行環境があり、その実行環境では同一のライブラリを参照している場合がある。

仮にAとBというプログラムで参照しているZライブラリがある。Aをアップデートする都合上、Zライブラリをアップデートしたい。しかし、ZライブラリがアップデートされるとBプログラムは動かなくなる。などの共有部分の依存問題がある。

そこで、**AとZ, BとZのようにプログラムを隔離することで、同じ箇所を参照することがなくなり、共有部分の依存関係を調整する必要がなくなる。**

## Container
Container(コンテナ)は **データやプログラムを隔離する箱のようなもの**
隔離する箱がわからない場合は、本記事の「データやプログラムを隔離できると何が嬉しいのか」を読むとわかるかも。

コンテナには様々な実行環境をいれることができる。（webサーバ, メールサーバ, dbサーバなど）
実行環境は１コンテナに対して 1つずつor一緒でも 作れる。

コンテナはimageという設計書のようなものを元にして作ることができる。また、コンテナからimageを作ることもできる。

## image
imageは**コンテナを作るための設計書**。
Docker Hubというimageがたくさんまとまっている場所から簡単にpullすることができる。
公式で公開しているimageや個人開発者が公開しているimageがあるので、使用用途を考えてpullする。

ホストのOSが異なっていても簡単に環境構築できるのは、imageをもとに実行環境を作れることが理由の一つとなっている。

## network
imageをもとにコンテナを作ったとして、それぞれが結びつかなければ意味がない。
実はコンテナはDocker EngineというDockerの実行環境の上に載っている。Docker Engineでは、imageを元にコンテナを作ったり、コンテナ同士の接続も行う。その**コンテナ同士の接続を担うのがNetwork**である。

仮に、AというWebサーバのコンテナと、BというDBサーバのコンテナを接続したい場合、
1. Nというネットワークを作成（コンテナ作成時にネットワークを設定するため）
1. BのDBサーバコンテナをNネットワークを利用するオプションを付けて作成
1. AのWebサーバコンテナをNネットワークを利用するオプションを付けて作成

これによって、Docker内でAとBのコンテナが接続した状態を作ることができる


## volume
volumeは**コンテナで利用するストレージ**。画像だけではなく、ディレクトリやhtmlファイルなども対象となる。
ホスト上にあるディレクトリやファイルを、コンテナ内の指定したpathにマウントしたり、Docker Engine上にストレージとして新しく作成することができる。
また、volumeはコンテナのライフサイクルとは別になっているため、コンテナが削除されても残っている。

**volumeの種類は以下3種類ある**
- ホスト上にあるデータやファイルを参照(バインドマウント)
  - 例えば、ホスト上のhtmlファイルをマウントして、そのhtmlファイルを変更した場合、マウントしたコンテナにも反映される。マウントするホスト上のpathが間違っていると、volumeの作成に失敗する。
- Docker Engine上のファイルを参照（volumeマウント）
  - docker engineにvolumeがある限り永続化させることができる。あまり触らないファイルなどをこちらに入れることが多い。volumeが消えると一緒に消える。
- 一時的にメモリとして、Docker Engine上で参照（tmpfsマウント）

## Dockerfile
Dockerfileは**イメージを作成することができる**。
既存イメージに変更を加えたい時や、コンテナをビルドする時にコマンドを実行する事ができる。
imageを作成する時にわざわざコマンドを毎回打たなくても、Dockerfileにそのコマンドを書けば、Dockerfileをビルドするだけでよくなる。

## docker-compose
docker-composeは**コンテナ、イメージ、ネットワーク、ボリュームをまとめて起動/停止できる。いわば手順書**。
これがないと、コンテナの数だけイメージのpullやネットワーク/ボリュームの作成をやらないといけない。もちろん停止する場合も一つずつやる。

それが辛いので、その手順書`docker-compose.yml`で管理して、起動コマンドを１つ実行することで、楽に起動/停止を行える。
また、Dockerfileでビルドしたimageを`docker-compose.yml`で読み込むことも可能。

## 余談
### LinuxOSであることが必須
Dockerはよく、「OSっぽいもの」ごとにコンテナを隔離できるという説明がある。
また別の記事で詳しくまとめたいが、簡単述べると、ホスト側もDocker側もLinuxで統一することで、OSで必要な機能を一部しか使わなくて良くなり、軽量かつOSっぽいものでコンテナを作ることができる。

ちなみにOSはカーネルと呼ばれる、ハードウェア命令を下すものと、機械語に翻訳などをする周辺の機能の２つに分かれており、Docker上ではハードウェアに命令を下すわけではないので、周辺の機能だけを搭載されている。（からOSっぽいものと言われている。）

#### 余談の余談 いやいや、MacOSでDocker使ってますけど
その場合はdocker desktop for mac で無理やりLinuxOSっぽい環境をMacOS上に作っているか、 Virtual boxでLinuxOSの仮想マシン上でDockerを使っていると思います。なので、結局LinuxOS上でDockerが動いているんですね。
Flutter for Webのデバッグとビルド環境で変数の型が違う件


[プッシュ通知の送信履歴の表示について · Issue #1307 · NIFCLOUD-mbaas/UserCommunity](https://github.com/NIFCLOUD-mbaas/UserCommunity/issues/1307)、こちらの件で調査してはじめて知ったのですが、Flutter for Webで型判別をしていると微妙にハマります。

## 前提条件

ニフクラ mobile backendのデータストア（クラウドデータベース）では、文字列や数字、真偽値、配列、オブジェクトなど様々な形式を扱います。かつNoSQL型データベースなのでフィールド名も自由に付けられます。そのため、型指定する言語とは相性があまり良くなかったりします。

特にオブジェクトでデータが入っている中でも、ニフクラ mobile backendでは以下の型が特殊になります。

- 日時型  
`{__type: "Date", iso: "日付文字列"}` という形でデータが入っている
- 位置情報型  
`{__type: "GeoPoint", latitude: 緯度の数値, longitude: 経度の数値}` という形でデータが入っている
- リレーションデータ
`{__type: "Pointer", className: "対象クラス名", objectId: "対象データのキー"}` という形でデータが入っている

このあたりを判別するために、入っているデータの型を調べる必要がありました。

## やっていたこと

最初のコードです。

```dart
// データの型を調べる
if (value.runtimeType.toString() == '_JsonMap' ||
        value.runtimeType.toString() ==
            '_InternalLinkedHashMap<String, dynamic>') {
	var map = value as Map;
	if (map['className'] != null) {
		// リレーションデータ
	}
	if (map.containsKey('__type') && map['__type'] == 'GeoPoint') {
		// 位置情報型
	}
	if (map.containsKey('__type') && map['__type'] == 'Date') {
		// 日時型
  }
} else {
	// それ以外
}
```

`value.runtimeType.toString()` の値ですが、デバッグ環境では以下のようになります。 `_InternalLinkedHashMap<String, dynamic>` になるのはスマホの場合だった覚えがあります。

```
userSettingValue is _JsonMap
deliveryExpirationTime is String
deliveryNumber is int
action is String
badgeIncrementFlag is bool
error is _JsonMap
target is List<dynamic>
```

## ビルド環境での実行

いわゆる `flutter build web` をやって生成されたコードでの実行結果です。 `minified:F5` とか `minified:bR` といった謎の文字列が入ってきます。この結果として、if文がうまく動かずに不具合が起きていました。

```
createDate is minified:bR
updateDate is minified:bR
acl is minified:n1
dialog is bool
error is minified:F5
objectId is String
deliveryTime is minified:F5
target is minified:r<dynamic>
```

## 修正後

あまり良くはないのですが、Mapとして評価してエラーになるかどうかで判別することにしました。

```dart
try {
	var map = value as Map;
	if (map['className'] != null) {
		// リレーションデータ
	}
	if (map.containsKey('__type') && map['__type'] == 'GeoPoint') {
		// 位置情報型
	}
	if (map.containsKey('__type') && map['__type'] == 'Date') {
		// 日時型
	}
	_fields[name] = value;
} catch (e) {
	_fields[name] = value;
}
```

`is` で判別できそうな気もするのですが、過去にうまくいかなかった覚えがあるんですよね…（そのために `runtimeType.toString()` を使っている覚えが）。ビルド環境によって変数の型が異なるのも面倒なので、今回のやり方の方がシンプルかなと思っています。

他に良い方法があれば、ぜひコメントで教えてください！

NCMBのDart/Flutterパッケージは[ncmb | Dart Package](https://pub.dev/packages/ncmb)にて公開しています。ぜひ試してみてください！
トラストアンカー とは

## 勉強前イメージ

アンカー？

## 調査

### トラストアンカー とは

英語でTrust Anchorと書き、トラストポイントも呼ばれています。
インターネットで使用される [PKI](https://qiita.com/miyuki_samitani/items/73adf345bd8ec5213431) のような電子的な認証を行う際に使用される基点のことを指します。
認証の手続きを行う者が信頼を置くところに設定します。
複数の設定することもあります。

トラストアンカーは不特定多数とやり取りを行う通信に信頼を担保します。
例としてPKIであれば認証局証明書で示されていて、予め指定する認証局の証明書がトラストアンカーになります。

## 勉強後イメージ

初めて知った・・・

## 参考

- [トラストアンカーとは](https://www.nic.ad.jp/ja/basics/terms/trust-anchor.html)
AccessのVBAで全角ダブルクオテーションを扱いたい時はChr(&H8167)

# サンプル

```vb:半角ダブルクオテーションを全角ダブルクオテーションに置換サンプル
Dim tester_ As String
tester_ = Replace("だぶるくおてーしょん""", """", Chr(&H8167))
```

VBEは全角ダブルクオテーションを勝手に置換するので、コードで指定する必要あり。
例えばVBE上で ```"”"``` と入力すると ```""""``` に書き換えられてしまう。

# 参考サイトさん

https://vba-create.jp/vba-chr-quotation-full/

# バージョン

Windows 10 Pro 21H2 OSビルド 19044.1889
Microsoft Access for Microsoft 365 MSO (バージョン 2207 ビルド 16.0.15427.20166) 32 ビット

TODO:ダブルクオテーションは2種類あるので、それも網羅する。
TODO:16進数で指定しない場合についても書く。
Windows10のバッチで現在時刻を元にしたyyyymmdd_hhnnssという名前のフォルダー作成

# やり方

```bat:batと同じフォルダーにyyyymmdd_hhnnssの名前のフォルダー作成サンプル
rem timeは予約語
rem 半角スペースを0に置換した上でtime2という名前の変数に格納
set time2=%time: =0%

rem 変数内容確認
echo %time2%

rem dateは予約語
rem フォルダー名をbkpathという名前の変数に格納
set bkpath=%date:~0,4%%date:~5,2%%date:~8,2%_%time2:~0,2%%time2:~3,2%%time2:~6,2%

rem フォルダー作成
md %bkpath%

rem コマンドプロンプト一旦止めてechoとか確認
pause
```

```time``` と ```date``` から位置を指定して文字列切り出し⇒結合でフォルダー名を組立、という基本方針。 
ただしtimeは **0埋めされていない** 為、事前に半角スペースを0に置換する処理をかます。

# 参考サイトさん

https://atmarkit.itmedia.co.jp/ait/articles/0405/01/news002.html

# バージョン

Windows 10 Pro 21H2 OSビルド 19044.1889
Jupyter Notebookで複数のカーネルを起動して作業するときの注意点(カーネル異常終了)

# 1.この記事の内容

Jupyter Notebookで重い処理を実行するとカーネルが異常終了することがあります．  
この要因はメモリ不足であることが多いのですが，複数のカーネルを起動で作業する際に「さっきまで動いていたのに，なぜ？」というように処理を変えていなくても突然異常終了が起きることがあります．

![jupyter-kernel-termination.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/983907/8c61cca0-4739-12be-bf2c-55f551f0ac1d.png)

# 2.作業上の注意点

カーネルが起動した状態では，メモリ上にデータが残ります（当たり前）．  
つまり，複数のカーネルを起動して作業するときに異常終了が発生したときは，他のカーネルを終了（shutdown）すれば，メモリを解放できます．

![jupyter-kernel-shutdown.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/983907/1117961a-34d5-cdb3-75ca-10db300d6aa3.png)


# 3.さいごに

ときどきこれに気づかず，デバッグしてしまう自分への戒めの意も込めて記事に残しました．
PHP基礎

PHPの基本的な記述ルール
①拡張子は「xxx.php」
②コードの書き方
<?php xxx; ?>と書く。
※ちなみにphpはhtmlに埋め込んで書くことも可能
ex)
```
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <title>PHP基礎</title>
  </head>
  <body>
    <?php echo 'Hello world!'; ?>
  </body>
</html>
```
※参考にさせていただいたサイト
https://www.sejuku.net/blog/107646
紙ベースレシピをデジタルベースレシピに

# 自己紹介
初めまして！私は某スーパーマーケットのお惣菜部門の責任者をしています。
自分で商品を作ったり、その商品をお店に出したり、材料を発注したり、何を何個作るか計画をするお仕事です。
色々なものがデジタル化されている昨今ですが、まだまだアナログな側面がたくさんありますので、それをＤＸ化できないか考えて実装してみました。

## レシピを紙からデジタルに
私が働いてる場所はチェーン店化されていますので、どの店も同じ味が出せるようにレシピがマニュアル化されています。
ただこのレシピ、**全て紙ベース！**
ざっと１００枚以上の膨大な量から作りたいものを探すという手間がすごいです。
今回はこれをデジタルにしてみようとなりました。

## 使用ツール
・Glide
を使ってレシピアプリを作成してみました。
テンプレートのアプリがあり、それを編集するだけでアプリが作れる凄いツールです。
https://www.glideapps.com/

## 実装してみた
今回は名前検索機能、カテゴリー検索機能があればよいなと思い実装してみました。
https://s-app-34ch.glideapp.io

![ezgif.com-gif-maker (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2724112/43349db4-1589-131e-8877-85b78fd0d2f5.gif)

実際のレシピは社外秘なので、ちゃんとごはんレシピさんからレシピはお借りしました。
https://www.mv-tokai.co.jp/recipe-search/

## 使ってみての感想
実際に使っていただき感想をもらいました。
:thumbsup:　肯定意見
・検索機能がとても便利！（30代女性A）
・デジタルだとズームができるから老眼に優しい（50代女性B）

:thumbsdown:　改善意見
・見やすいようにタブレット化したら？その場合置く場所はどうする？（30代女性C）
・若い人は使いやすいけど、私たちは辛い（60代女性D）

:point_up:　プラスワンな意見
・ネットに繋がっているなら、スプレッドシートをレシピ事につけてもらってそこに全店が自由に書き込めるようにすると、作り方のアドバイスなどが全店共有されて便利では？（30代男性E）
・働く仲間に外国人が多くなっているから翻訳機能付きだとさらに良くない？（30代男性F）

と様々な意見をいただきました。これらを改善してさらに良いものを作りたいと思います。

## 最後に
実際にアプリを見せて聞いてみた中で一番多かった意見は、凄い！！でした笑
やっていることはGlideに既存にある物をただ編集しただけで、時間もかからないし、コードを書いたり勉強したりする必要もないんですよね。
でもそれを知らない人からすると凄いものを作っている人扱いされ、後日何か作ってもらおうか考え中であると伝えられました。
自分の出来ることを他人に伝える事によって、その人からもアイディアをいただけるということを学んで、何か作る時には自分ひとりの脳よりも他人を巻き込んで多数の脳を使うのが効率も良いし、よりよいものを使えるなと思いました。

このアプリを使って、これをまとめてほしい等ありましたらお気軽にコメントまでお願いします!