OmniAICreator/Qiita-1.07M huggingface dataset:
会社から置き忘れ傘を無くしたかった。Teachable Machineを使用した置き傘判定！

　こんにちは！自分の発想から色々と開発していますが、今回はTeachable Machineを使って傘を判別する事をやりたかったのですが、開発途中でなかなか上手くいかず、自分が試みたプランのみを披露します。もっと応用したかったのですが、、、それはまたの機会にし最後に理由を書きたいと思います。
# 1.なぜこれを考えたか
　人間誰しも忘れ物をしがちですが、特に日本の傘の廃棄量は世界で群を抜いているようです。

https://ecotopia.earth/article-2226/

　以前の職業はコンビニのSV（スーパーバイザー）をしており、巡回でお店に伺うとあの店頭に置いてある傘立てがいつも気になっていました。それは決まって雨上がり。コンビニに入る前はちゃんと傘立てに置くのに買い物を済ませる事に集中しもう傘を忘れて帰っていきます。もちろん忘れて行かれた傘たちはご主人が帰ってくるのを待っていますが99%帰ってきません。お店の人は所持者不明の傘はわざわざお金を払って事業用産業廃棄物として捨てます。なぜなら置き傘がバックヤード（商品やコンテナ置き場）を傘が席巻するからです。<br><br><dt>それは自社でも起こっています。<dt>
![20220604_171440.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668403/e5b9354f-4a08-7e69-99ee-74ec0c4f1d66.jpeg)

# 2.途中までの完成品はこちら
<blockquote class="twitter-tweet"><p lang="und" dir="ltr"><a href="https://t.co/rnZUzvG8bk">pic.twitter.com/rnZUzvG8bk</a></p>&mdash; imupion (@5cyyzToVdzLw0x4) <a href="https://twitter.com/5cyyzToVdzLw0x4/status/1533446149537157120?ref_src=twsrc%5Etfw">June 5, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 3.準備したもの
■Teachable Machine
■LINE
■enebular

# 4.いむぴょん家の傘でまずは実験
![スクリーンショット 2022-06-05 221203.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668403/c463f67f-08e9-f6cd-74b4-9993ec7c04dd.png)
■enebularを使ってLINEと連携しました。
<details><summary>手順を画像でおさらい</summary>

●LINE Developers
enebularからURLを取得。

:::note warn
警告
enebularの場合URLが60分で変更になり、継続して使用する場合はおすすめ出来ません。
:::

![スクリーンショット 2022-06-05 222224.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668403/1645ab93-4c0a-87a2-2e3c-927828b4ef5d.png)
※体験談：こいつのおかげで全然繋がらなく苦労させられました。

■http in（LINEBot）
![スクリーンショット 2022-06-05 221736.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668403/d5429e5a-c6d1-1414-ad4b-e5729d571e98.png)
■ function（LINEメッセージ解析）
![スクリーンショット 2022-06-05 222518.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668403/537680e2-ff91-1fca-efdf-a12136cd4edd.png)
■http request
![スクリーンショット 2022-06-05 222557.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668403/2b741b56-84d6-3e3a-a6c2-6d4315bd0573.png)
■Teachable Machine（こちらはノード追加が必要）
![スクリーンショット 2022-06-05 222632.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668403/ddcad81b-52b5-1569-c5af-1f3000465e39.png)
■function（結果取得）※上のfunctionノードと同じものを追加
![スクリーンショット 2022-06-05 222706.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668403/3599565a-c0fe-4828-49ba-f5f0c38c9ab9.png)
■LINE ReplayMessage(これもノードの追加が必要）
![スクリーンショット 2022-06-05 222730.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668403/c5339654-c8b3-539b-8553-ec406dc5239e.png)
作りは完成。
</details>

# 5.本来やりたかった事

　この後はまた別の記事に書こうと思いますが、最近ではゲリラ豪雨など凄いのですが、数時間で雨が止むことも多いです。出勤時は雨が降っていて、退勤時は雨が止んでいる事はまれではありません。そんなこんなで今回やり残した課題は自分の傘を登録し、それがどこにあるかを判別したり、ゆくゆくは社員全員を巻き込み全員の傘を登録し置き傘誰のだをやりたかったです。

また次回も出来る事を記事にしますね。
Pspiceの基本操作について

Good morning, and in case I don't seeya, good afernoon, good evening and goood night!
って好きなアメリカの女優が言ってて真似してみたかっただけです。
てなわけでおはこんばんちはポンコツ新社会人です。
先日はダウンロード方法の記事をあげました。
よかったら参考にして下さい。
そして本日からはいよいよPspiceの使い方を共有していきたいと思います。
この記事はPSpice® for TI: Introductionの動画を日本語記事化したものです。
# プロジェクトの作成
とりあえず基本の反転増幅回路をOPA2743を使用して作成してみましょう。
Pspiceを起動したら**File**→ **New**→ **Project**をクリック。
新しいプロジェクトを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486428/e847a6eb-aa1d-d3f5-b02d-8d6c13a72566.png)
新規プロジェクトの名前と保存場所を入力。
今回は反転増幅器の作成のためfile名は _Invert_Amp_　にした。
パスは好きなところで問題ありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486428/f33d708b-ffc8-7742-7e84-fe715f7ab280.png)
**Create blank Project**　にチェックボックスを入れてOKを選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486428/77a98a3b-3702-7c18-4d8b-1b848a2df18e.png)
すると以下のように空の回路図が開かれます。
ここに回路図を作成していく。
画面上ではそれぞれ以下の情報が載っています。
1.　 開いているプロジェクトのフォルダ、ファイル
2.　回路図　
3.　プロジェクトの操作
4.　部品のライブラリフォルダ
5.　部品検索
6.　回路図の操作

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486428/4728da60-c1b5-e85c-31b9-228c8d0bd49d.png)
# 回路図の操作
下にCheetSheetを書きだした。今後更新する予定です:construction_worker_tone5:(6/5/2022)
|Shortcuts|Command|
|:--:|:--:|
|Gnd|G or f|
|Label|N|
|parts|P|
|Run sim|F11|
|Text|T|
|Wire|W|
|No connection|X|
# シミュレーション


えー途中ではありますがいったん投稿します。
今後鋭意更新予定です。
asm("NOP").....
安全運転管理者業務を楽にしたい！teachablemachineとLine botを使用して アルコールチェックの自動記録してみよう

## 今回のチャレンジ
道路交通法が改正されて4月から安全運転管理者義務に酒気帯び有無の確認が追加されました。


https://uenishi-sr.jp/20220516/

10月には更にアルコールチェッカーを使用してのチェックと記録の保管も義務化されることを見越してアルコールチェックの自動記録にチャレンジしました。

参考にさせていただいた記事はこちら

https://atlabo-handson-08.netlify.app/#0

## 使用ツール
* アルコールチェッカー (Amazonで一番安かったもの)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668122/c1b131f5-e5a9-5c11-fe0b-e4f490663f0c.png)

* teachablemachine
https://teachablemachine.withgoogle.com/

* enebular
https://enebular.com/

* LINE Bot
https://developers.line.biz/


## teachablemachineの読み込み

![530D3E58-07EB-4141-ADC5-2B94D9218598.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668122/da98e9bf-c395-0c6f-2da5-34245bc786c5.gif)

teachablemachineにアルコールチェッカーの画像を登録していきます。

:::note info
緑　運転OK
:::

:::note warn
黄　再チェック(要確認)
:::

:::note alert
赤　運転NG
:::

今回はアルコールの数値ではなく、アルコールチェッカーに出てくる色によって運転できるかどうかを機械学習させます。

Amazonで1番安いアルコールチェッカーを購入しましたが、バッチリ反応します。


## enebularでフロー作成
![えねぶらー.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668122/e0e0319a-947a-754c-060d-c80833fa4b0e.png)

想定のフローは
* LINEBotでアルコールチェッカーの画像を受け取る。
* enebularで受け取り、teachablemachineで運転可能か判定。
* LINEBotに結果を返す。


## いざ送信


![5CE242FD-0498-4E22-A61D-2ACF4E129910.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668122/c5014d24-47b3-f74c-7276-a63a924eca1c.jpeg)

あれ？返答が来ない。
今回はここでタイムアップです。


# やりたかったこと
社用車を使用する人は大体直行直帰なので、出勤時間もバラバラなので、運転開始前にいちいち運転管理責任者へテレビ電話をするのが大変なので、目視確認を自動化できればと思い取り組みました。
最終的には社用車運転管理記録もスプレッドシートに自動記入まで出来そうと考えていました。
当社はまだギリギリ基準以下の人数なので義務化対象外ではありますが、いつ既定人数を越えるかわかりません。また、営業車を使用することがメインではないので、市販の高いツールを入れるよりも自前でどうにかなるとよいなと考えてます。

動かせるように修行してきます。
Amazon Elastic Kubernetes Service (EKS)

# 【Kubernetes】
Kubernetesを実務で扱っていきたい。

## Kubernetes
- 宣言的な構成管理と自動化を促進し、コンテナ化されたワークロードやサービスを管理するための、ポータブルで拡張性のあるオープンソースのプラットフォーム

## Kubernetesのコンポーネント
- Kubernetesをデプロイすると、クラスターが展開
- Kubernetesクラスターは、 コンテナ化されたアプリケーションを実行するノードと呼ばれるワーカーマシンの集合
    - すべてのクラスターには少なくとも1つのワーカーノードがある
    - ワーカーノードは、アプリケーションのコンポーネントであるPodをホスト
        - Pod：Kubernetes上の最小単位
        - １つ又は複数コンテナを持つ
        - ネットワークやストレージを共有リソースとして持つ
    - マスターノードは、クラスター内のワーカーノードとPodを管理
    - 複数のマスターノードを使用して、クラスターにフェイルオーバーと高可用性を提供
    - ワーカーノードは、アプリケーションワークロードのコンポーネントであるPodをホスト
    - コントロールプレーンは、クラスター内のワーカーノードとPodを管理
- 本番環境では、コントロールプレーンは複数のコンピューターを使用し、クラスターは複数のノードを使用し、耐障害性や高可用性を提供

## Amazon Elastic Kubernetes Service (EKS)
- クラウドまたはオンプレミスで Kubernetes アプリケーションを実行、スケールするマネージドコンテナサービス
- クラスターごとに単一のテナント Kubernetes コントロールプレーンを実行（クラスター間または AWS アカウント間では共有されない）
    - 複数の AWS アベイラビリティーゾーンで Kubernetes コントロールプレーンを実行およびスケーリングし、高可用性を確保
    - コントロールプレーンインスタンスを負荷に基づき自動でスケーリングし、異常なコントロールプレーンインスタンスの検出および置換を行う。
    - バージョンのアップグレードやパッチ適用も自動
    - オープンソースの Kubernetes ソフトウェアの最新バージョンを実行するため、Kubernetes コミュニティの既存のすべてのプラグインとツールを使用
    - Amazon EKS で実行されているアプリケーションは、標準の Kubernetes 環境で実行されているアプリケーションと完全に互換性
    - オンプレミスのデータセンターで実行されているか、パブリッククラウドで実行されているかは関係なし
    - 標準的な Kubernetes アプリケーションであれば、コードを変更することなく、簡単に Amazon EKS に移行

## 参考
- [Kubernetesとは何か?](https://kubernetes.io/ja/docs/concepts/overview/what-is-kubernetes/)
- [Kubernetesのコンポーネント](https://kubernetes.io/ja/docs/concepts/overview/components/)
- [Amazon EKS](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/what-is-eks.html)
androidで文字の置き換え(正規表現)を使ってみて

# はじめに
今回は　正規表現というものを使ったので記事にしてみます
いろいろなやり方があるので調べた時に混乱してしまうと思ったので
実装した時に一番わかりやすいやり方をメモとして残しておきます

# 正規表現

```
val regex = Regex("""\d+""")
```
もしくは
```
val regex = """\d+""".toRegex()
```
とすることでRegexクラスを使うことができます

正規表現では通常通りの文字列の指定で""を使用すると
バックスラッシュなどをエスケープすることが多くなってしまうので

"""で囲うことでそのままの文字列として扱われるので、エスケープ無しで使うことができます

例のコードにある \dというのは正規表現でいう
「すべての数字」という意味で　文字列に数字（0~9）が含まれているかどうかを見ることができます
それ以外にも正規表現用のコードがあるのでまとめてあるページをお借りしました
↓
[基本的な正規表現一覧](https://murashun.jp/article/programming/regular-expression.html
)

# 抽出
Regexが使用された文字列を抽出します
正規表現で指定した文字があった場合に　その文字を抽出するには
find、もしくはfindAllを使用します
```
val text = "1 aaaaa 2 bbbbb"
val regex = Regex("""\d""")

val extract = regex.find(text)
print(extract?.value)

val matches = regex.findAll(text)
matches?.forEach { it -> print("${it.value} ") }
```
それぞれ　結果は
findが１
findAllが　1 2
となります

# 置き換え

```
val text: String = ""
println(s.replace("", ""))
```
Stringの型の変数に.replaceを使うことで文字列から任意の文字を置き換えることができます
replaceの第一引数に位置き換え前の変更させたい文字を　第二引数に置き換えたい文字を入れます
"" と空文字を設定することによって第一引数に設定している文字を消すことができます

これは正規表現とは異なりますが　一番簡単な置き換えのやり方だと思います


正規表現と置き換えを合わせていきます
```

val text: String = """1 aaaaa, 2 bbbbb""".toRegex()
println(s.replace("""\d""", ""))
```
結果は　aaaaa, bbbbb　となります





# 終わりに
今回は　抽出や置き換えなど　簡単で使いやすいものを記事にしましたが、
正規表現を使うにあたって調べてみた感じ的にもっといろいろなことができそうな気がします
また、やっていて面白く感じるところが多かったので　正規表現の違う使い方も記事にできたらいいなと思いました
batファイルで共通設定ファイルを読み込む方法


仕事でbatファイルをよく使うので共通の変数を1つのテキストファイルにまとめて、その変数をbatファイルから読み込む方法を書きます。
サンプルとして「c:\設定.txt」という共通設定ファイルを用意しました。
行の先頭に「;」がある場合はコメントアウトとなる様にしています。

```ruby:共通設定ファイル（c:\設定.txt）
test_file=c:\test.txt
;dummy_path=c:\dummy.txt
out_dir=c:\out
```

```ruby:batファイル
@echo off
setlocal

rem 共通設定ファイル読込
for /f "eol=;tokens=1,2 delims==" %%i in (c:\設定.txt) do (
  set %%i=%%j
)

echo %test_file%
echo %dummy_path%
echo %out_dir%

endlocal
pause
```
```ruby:結果
c:\test.txt
ECHOは＜OFF＞です。
c:\out
続行するには何かキーを押してください．．．
```

先頭に「;」がある「dummy_path」は読込対象外のため、echoをするとエラーとなります。
バッティングスコア管理アプリをお喋り出来るようにする⚾

## バッティングスコアに機能を追加
この前記事で作成したアプリの機能を充実させるということで、より一層かっこいい感じにしようと思う。

https://qiita.com/long66tail/items/ab96b204c4ca7bea56b0

今回は、かっこよく英語で語らうようにしてみた。

## 完成作品
と、いうことで、打撃成績を”追加”したら、
「good job.Always put your best foot forward.（訳：お疲れ様。いつもベストを尽くしていこう）」
と言ってくれるようにした。

https://batting-statistic-c35a90.netlify.app/


## ソースコード

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

## 追加した発話機能
まずは、HTMLにボタンを押したときに発話するための「click="say"」を追加。

~~~HTML
 <div class="column">
      <button class="btn btn-primary" v-on:click="addNewItem" @click="say">追加</button>
 </div>
~~~

そして、発話のため"say"の機能を追加。
この時、言語設定の箇所を'en-US'とした。（'ja-JP'で英語を話させると残念な感じになる。）
ちなみに音声認識の機能も構築することが可能であるため、日本語で音声認識や発話をさせたいときは、'ja-JP'にする必要がある。

~~~javascript
    mounted() {
    // 音声認識の準備
    const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.msSpeechRecognition || null;
    this.recog = new SpeechRecognition();
    // this.recog.lang = 'ja-JP';
    this.recog.lang = 'en-US';
    this.recog.interimResults = false;
    this.recog.continuous = false;
      
    // 発話の準備
    this.speech = new window.SpeechSynthesisUtterance();
    this.speech.lang = 'en-US';
    window.speechSynthesis.onvoiceschanged = () => {
      const voices = window.speechSynthesis.getVoices();
      this.speech.voice = voices.find(voice => voice.lang == 'en-US');
      console.log(this.speech.voice);
    };
  },

//中略
    async say() {
      return new Promise((res) => {
      // this.speech.text = this.message;
        this.speech.text = "good job.Always put your best foot forward."
        this.speech.onend = () => res();
        speechSynthesis.speak(this.speech);
      });
    },

~~~  


## 感想
参考となるようなCodepenはこちら。
こういった参考を見つけることで、自力で作り込まなくても音声を発話させることが出来た。

https://codepen.io/ukkz/pen/xxqzQwP

今回のアプリには不要だと思ってつけなかったが音声認識をさせることも可能で、例えばアプリと対話するとか音声で動かすとか、そういったものが出来るようになるため、アプリによっては非常に便利だと思う。

興味のある人は、実際に確認できるCodepenを見つけたので試してみて欲しい。

https://codepen.io/AiHirano/pen/gWaqbo
Rubyの基本

## Rubyの基本
#### Rubyとは？
Rubyは、1995年頃に開発された**オブジェクト指向のスクリプト言語**。

C言語やJavaといったプログラミング言語は、**コンパイラ言語**と呼ばれており、プログラムを実行するために「コンパイル」という手続きを行うことで初めてそのプロジェクトを実行するができる。対して、Rubyのような**スクリプト言語**では、上記のコンパイルという処理が一切不要。そのままプロジェクトを実行することができる。

そのため、コンパイラ言語に比べてRubyはプログラミングを手軽に行えるのが特徴となっている。つまりRubyは、上から下へ書いた内容を実行する手続き型言語ではなく、実体（オブジェクト）を組み立てながら作る、**オブジェクト指向の中でも比較的容易に実装できるプログラミング言語**。

#### Rubyで何をすることが多いのか？
* ユーザー同士の交流ができるSNSサービス開発
* 人と人をつなぐことのできるマッチングサービス開発
* 動画や音楽などの配信サービス開発
* 業務効率化ツールやソフトの開発
* 機会を制御するためのソフト開発

## Ruby初心者におすすめする開発環境の構築
まずは、ここで言う開発環境とは、単純にRubyのプログラミングを行うための環境のこと。

プログラミングの開発では、「開発環境」→「テスト環境」→「本環境」のように順を追ってサービスの公開まで進む。開発環境とはつまり、エンジニアの方たちがサービスを作るために開発をする段階のことを言う。

初心者の方には「**統合開発環境（IDE）**」と呼ばれる開発環境の構築法を利用するのが一番簡単でおすすめ。

#### 統合開発環境（IDE）とは？
統合開発環境とはテキストエディタ、コンパイラ、デバッガを1つにまとめたもののこと。

一般的に、ソフトウェアやサービスを開発する際には、作業ごとに応じた複数のソフトウェアやツールを使い分ける必要がある。大まかに分けると、ソースコードを書くために必要なエディタや、ソースコードからオブジェクトコードを生成する際に利用するコンパイラ。他にも各CPU向けの実行コードを生成するために必要なリンカ。そして、作成したプログラムのバグを検出するために使用するデバッガなどである。

統合開発環境（IDE）とは、上記で説明したようなソフトウェアの開発で利用されるソフトウェアをまとめて1つの開発環境で統合・統一的に扱えるようにした開発環境。

#### Macへのインストール
* rbenv
* RVM
* そのシステムが持つパッケージ管理ツール

#### Rubyの実行方法
Rubyのプログラムを書いた実行ファイルの拡張子は、「.rb」。例として、この記事では「sample.rb」というRubyの実行ファイルを作成。これを以下のコマンドで実行します。

$ruby sample.rb
Pythonで関数のグラフを書く方法


#  x-y座標でグラフを書く方法
自分の覚書として書く。
##  一つのグラフ
下のグラフは`arrange`を用いて $y=\sin x$ のグラフを $x-y$ 平面に $\Delta x=0.01$ おきに $0$ から $2\pi $ までプロットしたものである。
`linspace`等を用いる方法もある。



```python
import numpy as np
import matplotlib.pylab as plt

x = np.arange(0, 2*np.pi, 0.01)
plt.plot(x,np.sin(x))
plt.title('y=sin x') 
plt.xlabel('x') 
plt.ylabel('y')
plt.show()
```


    
![python_bibouroku_4_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703946/d4a85cfd-86ea-29bf-32fa-c26fac3bdd79.png)
    


`plt.show`でグラフを表示する。

## 複数のグラフ


```python
import numpy as np
import matplotlib.pylab as plt

x = np.arange(0, 2*np.pi, 0.01)
plt.plot(x, np.sin(x),label="y=sin x")
plt.plot(x, np.cos(x), label="y=cos x")

plt.title('')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.show()

```


    
![python_bibouroku_7_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703946/9800698b-1a09-0d28-e211-4ae965a3d2a3.png)

    


グラフが複数になるとどのグラフだか判別するための凡例が必要。`plt.legend`で凡例を表示できる。そのとき`plot`の中でラベリングすることを忘れずに。
nullを含むarray列をunnestする際にnullレコードを保持したいときのメモ

# 概要

BigQueryでarray等の列をunnestする際に、その列のnullなレコードはunnestの処理時に残らない。


```sql:nullを含む列のunnest例
with
test as (
  select
    n,
    if(mod(n, 2) != 0, generate_array(1, n), null) as x
  from
    unnest(generate_array(1, 3)) as n
)

select
  n, x, y
from
  test, unnest(x) as y
```
![スクリーンショット 2022-06-05 23.06.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221698/7cc66ac7-faa3-34e1-eda5-6b0f7a9ec666.png)

このようなケースで、nullなレコードも残す方法について。

# やり方

```sql:nullレコードを残すunnest(array)
with
test as (
  select
    n,
    if(mod(n, 2) != 0, generate_array(1, n), null) as x
  from
    unnest(generate_array(1, 3)) as n
)

select
  n, x, y
from
  test, unnest(coalesce(x, [null])) as y
```

![スクリーンショット 2022-06-05 23.22.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221698/b900381a-cc93-ae4f-d16c-8e2ed2e23c17.png)



```sql:nullレコードを残すunnest(struct)
with
test as (
  select
    'normal' as n,
    [struct(1 as x, 'a' as y),
     struct(2 as x, 'b' as y)
    ] as v
  union all
  select
    'null' as n,
    null as v
)

select
  n, v, x, y
from
  test, unnest(if(array_length(v) > 0, v, [struct(cast(null as int), cast(null as string))]))
```

![スクリーンショット 2022-06-05 23.22.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221698/caac4afa-57c9-ea13-a8eb-13981a8a4c9e.png)
[Kotlin]QRコードを生成する(JetpackCompose)

# 概要
Androidアプリ上で文字列を表すQRコードを生成します。
# 本文
build.gradle(:app)にZXingを指定します(Sync Nowを押してください)
```kotlin
dependencies {


    implementation 'com.journeyapps:zxing-android-embedded:3.6.0'
}
```

MainActivityコード本体

```kotlin
import android.graphics.Bitmap
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.asImageBitmap
import com.google.zxing.BarcodeFormat
import com.journeyapps.barcodescanner.BarcodeEncoder

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Generate()
        }
    }
}

@Composable
fun Generate() {
    val data = "TestMessage"
    val size = 300
    var bitmap: Bitmap? = null

    try {
        val barcodeEncoder = BarcodeEncoder()
        bitmap = barcodeEncoder.encodeBitmap(data, BarcodeFormat.QR_CODE, size, size)
    } catch (e: Exception) {
        Log.e("TAG", "error")
    }

    if (bitmap != null) {
        Image(
            bitmap.asImageBitmap(),
            contentDescription = "content description",
        )
    }
}
```
# エラーを解決する
このままだと以下のようなエラーが出ると思います。
`Duplicate class android.support.v4.app.INotificationSideChannel found in modules core-1.7.0-runtime`

[動画](https://www.youtube.com/watch?v=BgPf82ElJdo)を参考にgradle.propertiesの一番最後に1行加えます(Sync Nowを押してください)
![スクリーンショット 2022-06-05 22.50.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/1794a95a-cf58-0aef-6968-29193364e35c.png)

```kotlin
android.enableJetifier=true
```

実行するとQRコードが生成されます。
![スクリーンショット 2022-06-05 22.53.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/cbddab0a-5e07-a8d5-1085-d44d958d178f.png)
RISC-Vって何？ 〜モジュール性とカスタム命令について〜

# はじめに

### ISA とは何か？
**ISA**とは命令セットアーキテクチャ（Instruction Set Architecture）のことです。

こちらは、ソフトウェアとハードウェアのインターフェースに関する決まり事を定めた概念で、CPUで実行される機械語の集合である命令セットや、レジスタ、データ型、アドレッシングモード、メモリマネジメント、割り込み処理・例外処理、入出力、、、について定義したものだそうです（参考: Wikipedia先生による[「命令セット」](https://ja.wikipedia.org/wiki/%E5%91%BD%E4%BB%A4%E3%82%BB%E3%83%83%E3%83%88)に詳しく記載されております)。

難しい話な可能性がございますので、CPU周りの設計を行ったんだな的な感じでとりあえず大丈夫だと思います。

### RISC-V のカスタマイズについて

RISC-V の注目すべき点の１つとして、 ISA のカスタマイズが容易であるという点が挙げられます。

Intel や ARM などのプロセッサは、使われなくなった legacy (遺産的) な ISA を含んでおります。
それに対し RISC-V は、１から用途に合わせて**ライセンスフリー**（無料で）で自由にISAを設計できるのです。

その為、RISC-V の登場によって、 特定のアプリケーションに特化したプロセッサのニーズが近年脚光を浴びております。
特定のアプリケーションに合わせて設計するプロセッサは、**ASIP** (Application Specific Instruction-set Processor)や、少し広義になると Domain Specific Processor などと呼んだりします。

今回はその RISC-V のカスタマイズ方法に関して、２つの機能についてお話をさせていただきます。

# モジュール性
RISC-V には**モジュール性**という、CPU がその命令セット群をサポートするかしないかを設計者が設定できる機能が備わっております。＜図１＞
言い換えてしまうと、「CPU で実行できる命令セットを用途に合わせて選択できる」という機能です。

なぜ拡張という機能があるかというと、たくさん命令を備えれば **汎用性** が備わったり、より **高速** にプログラムを実行できるようになります。また、 **コードサイズ削減** による **メモリ使用量の削減** にも繋がります。

しかし、組み込み機器など、 **コスト** （＝値段や回路面積）が限られたり、実行されるアプリケーションが限られるような状況では、その汎用性が **無駄** だったりします。しかし採用する命令セットを減らしすぎると、先ほども述べましたがコードサイズ（それに伴うメモリ使用量）が大きくなってしまいます。

以上のことから、用途に合わせた命令セットを選択して CPU を開発する必要があるのです。

＜図１＞
<img width="250" alt="riscv-isa.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1597214/877f0d1a-4787-5c86-db54-1e6ac9df67be.png">

RISC-V ISA 拡張表。ベースとなるのが RVI で、拡張の例としては整数乗算用のM拡張、アトミック命令用のA拡張、単精度浮動小数点用のF拡張、倍精度浮動小数点用のD拡張などが存在する。([^1] の p.i を参照)


# カスタム命令用のオペコードが存在している

RISC-V は **カスタム命令** 用のオペコード（＝命令を識別するために必要な値）が存在しており、演算内容を自由に定めた命令を追加することができます。

RISC-Vの命令長は（基本的には）３２bitで固定なのですが、そのうち下位７bitがオペコードとして存在しています。＜図2＞
そして、カスタム命令追加用として、専用のオペコード値 (custom0 ~ custom3) が予め用意されております。＜図3＞

カスタム命令を実装することで、特定のアプリケーションで頻出する複数命令を１つにまとめることで、命令の呼び出し回数が減り、コードサイズ削減できる上に、より高速で低消費電力な実行が可能となるのです。

＜図２＞
<img width="580" alt="riscv-isa.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1597214/9cf9d05c-0d83-30ba-7fd2-f03cab911162.png" >

RISC-V 命令フォーマット。オペコードは下位7bitに存在している([^1] の p.16 を参照)

＜図３＞
<img width="700" alt="riscv-isa.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1597214/57296ebc-c024-0168-9250-b33c02fd4459.png">

カスタム命令を追加できるオペコード。カスタム命令用オペコードは custom0 ~ custom3 の合計４つが定義されている。例えば cutom0 を使用する際は「0001011」、custom1 を使用する際はオペコード「0101011」を用いる。（[^1] の p.129 を参照）


# まとめ
以上のことから、モジュール性がありカスタム命令を追加しやすい設計となっている RISC-V の恩恵により、特定のアプリケーションに特化したプロセッサの開発が誰でもできるような環境になりました。

次回は RISC-V コンパイラの代表格である [riscv-gnu-toolchain](https://github.com/riscv-collab/riscv-gnu-toolchain) による 「RISC-V コンパイラにカスタム命令を追加する」という記事を書く予定かも(？)です。

ご質問やご指摘などございましたら、是非コメントしてください。


#  参考
- [The RISC-V Instruction Set Manual](https://riscv.org/technical/specifications/)
- [What is an ASIP?](https://codasip.com/2021/04/16/what-is-an-asip/)
- [Why RISC-V is Succeeding](https://semiengineering.com/why-risc-v-is-succeeding/)

[^1]: Andrew Waterman, Krste Asanovic, RISC-V Foundation "The RISC-V Instruction Set Manual, Volume I: User-Level ISA", Document Version 20191214 draft, Dec.2019
情報通信とトラヒック　電気通信学会　秋丸春夫・川島幸之助先生

```r

#p.45 非マルコフモデル
#M/G/1(m)

m=2
a=1
h=1
lam=a/h

pj=function(J){
return(dpois(J,a))  
}

C0=1
p0=pj(0)
Cvec=c(C0)
Cvec=c(Cvec,(C0-p0)/p0)

for(j in 1:(m-1)){
pvec=pj(c(1:(j))) 
pvec=pvec[length(pvec):1]
Cval=(Cvec[j]-pj(j)-sum(Cvec[2:length(Cvec)]*pvec))/p0
Cvec=c(Cvec,Cval)
}

C=1+sum(Cvec)
Pj=Cvec/(1+a*C)
B=1-C/(1+a*C)
M0=1-Pj[1]-B
L=sum(c(0:m)*c(Pj[2:length(Pj)],B))
W=Pj[1]*(a*m*C-sum(c(m-c(1:m)+1)*Cvec[2:length(Cvec)]))/lam

```

```r

#複合入力モデル
#集団到着モデル
#M^[X]/M/S(0)
#p.68

lam=0.5
mu=0.3
#g_iの分布
zeta=0.6
#サーバーの数
S=10

g=function(v){
return(dpois(v,1/zeta))
}

pthi=function(v){
return(1-sum(g(c(0:(v-1)))))  
}

#Broyden Quasi-Newton Algorithm p.213

f=function(XX){
P=XX
vec=c()
for(j in 1:S){
val=c()
for(i in 0:(j-1)){
val=c(val,pthi(j-i))
}
val=lam*sum(P[1:j]*val)-j*mu*P[(j+1)]  
vec=c(vec,val)  
}
return(vec)
}

X=rep(1,(S+1))/(S+1)

ite=10^3
H=diag(f(X))
eta=10^(-2)

for(l in 1:ite){
X_pre=X  
X[2:(S+1)]=abs(X[2:(S+1)]-eta*H%*%f(X)) 
s=(X-X_pre)[2:(S+1)]
y=f(X)-f(X_pre)
H=H+((s-H%*%y)/as.numeric(t(s)%*%H%*%y))%*%t(s)%*%H
print(sum(abs(f(X))))
}

#定常分布
X=X/sum(X)



```
【コマンド初心者】初歩的な疑問に自分で答える

Linux（CentOS）サーバに初めてSSHログインした際、色々とつまづいたり疑問に思ったことが有ったのでメモも兼ねて投稿します。

## あるはずのファイルが ls コマンドで表示されない。
:a: `ls -a`コマンドで隠しファイルが表示できます。
　


## ls -aコマンドを実行したら、「.」「..」という表示がある。

:a: カレントディレクトリと親ディレクトリを表しているだけなので、気にしないでOKです。
　


## findで検索をしたらエラーメッセージが大量に出た。

findで検索をしたら/home/example/': Permission denied みたいなメッセージが大量に出た。

:a: 閲覧権限のないディレクトリを含めて検索をかけているのでパーミッションエラーが出ているようです。下記のように`2> /dev/null`をつけるとエラーメッセージを非表示にできます。
```
書き方：find 検索対象のディレクトリ -name ファイル・フォルダ名 2> /dev/null

具体例：find / -name example.file 2> /dev/null
```
わかりやすい参考記事様です↓

https://qiita.com/ritukiii/items/b3d91e97b71ecd41d4ea



## あるはずのファイルがfindコマンドで出てこない。

hogehoge.exampleというファイルを探すために `find / -name hogehoge`を実行したが該当なしになった。

:a: そのコマンドだと完全一致検索になります。
拡張子まで含めて`find / -name hogehoge.example`とするか
以下のように部分一致検索（もしくは前方一致検索）をしてください。
`find / -name '*hogehoge*'`
　

## sudo suの意味がわからない。

:a: 「sudo su」コマンドを使うとrootユーザー（全権限を持つユーザー）に切り替えることができます。
まずはsudoから説明していきます。
sudo「一時的に、別のユーザーとしてコマンドを実行できるコマンド」です。例えば
`sudo -u ユーザー名 mkdir sample`
とすれば「ユーザー名」の部分に入れたユーザーとしてmkdirを実行できます。
そして、「-uオプション」と「ユーザー名」の部分を省略した場合、
rootユーザーを指定したことになります。つまり、
`sudo mkdir sample`
とすればrootユーザーでmkdirを実行できるということです。
ただし、rootユーザーになるのは実行時の１回だけです。
続けてrootユーザーで何かのコマンドを実行したい場合は改めてsudoを打ち込む必要があります。
なお、sudoを使う際にはパスワードを求められますが、これば自分のパスワードでＯＫです。


次にsuです。
su は「ユーザーを切り替えられるコマンド」です。例えば
`su ユーザー名`
とすれば、「ユーザー名」に入れたユーザーに切り替えられます。
この際、切り替え先のユーザーのパスワード入力を求められます。
そして、ユーザー名の部分を省略した場合はrootユーザーを指定したことになります。

つまり、「sudo su」は、
「ルート権限を使ってルート権限に切り替えるコマンド」ということになります。
`su root`の場合はrootユーザーのパスワードが必要ですが、
`sudo su`であれば自分のパスワードでrootユーザーに切り替えることができるのです。

ちなみに、元のユーザー（自分）に戻すには
`su 自分のユーザー名`
もしくは`exit`です。
　
## コピーしようとctrl＋Cしたら、「C^」と入力された。
tera termでコマンド上のテキストをコピーしようと思いctrl＋Cを押したら「C^」と入力された。

:a: ctrl＋Cは、windowsではコピーを表しますが、Linux等のコマンド上では「実行中のコマンドを終了させる」操作になります。コピーの方法は、使っているツールの種類と設定によると思いますが、tera termの場合、コマンド上のテキストをドラッグしただけでコピーが完了しています。ペーストは右クリックを押すだけです。
　
## rmでファイル削除ができない。
ファイルを削除しようと思い `rm something.example` してみたところ
```
rm: remove write-protected regular file something.example
```
と表示された。確認メッセージかと思いエンターを押したが削除できなかった。

:a:「y」を入力してからエンターを押してください。
「y/n？」といった確認メッセージが表示されない場合もあるようです。
　
## パスワードを打ち込んでるのに画面が反応してない。

:a: そういう仕様なので、入力し終わったらエンター押してください。
ES6のモジュールをブラウザ環境で動作させる

## モジュールとは
WEBアプリ開発のようにJavaScriptでゴリゴリとコードを書いていく場合、ある程度機能（役割）別にファイルを切り出して別ファイルとして管理したいような場合に、関連性を持たせて切り離されたコード群を「**モジュール**」と呼ぶ。
JavaScriptではES6から実装された機能になっている。

## モジュールの基本
モジュールは1つのファイルとして定義するのが基本で、外部からモジュールにアクセスするメンバには「**export**」を付与する。
なお、モジュール内のメンバはデフォルトでは非公開となる。

#### コード例
```js:js/mod.js
export let value = 100;

export function hello() {
  console.log('Hello');
}

const SECRET_VALUE = Symbol();
console.log(SECRET_VALUE);  // =>Symbol()

export default class {
    constructor(secret) {
        this.hoge = "hoge";
        this.foo = 234;
        this[SECRET_VALUE] = secret;
    }
    

    getSecret() {
        return this[SECRET_VALUE];
    }
}
```

別ファイルで定義されたモジュールをインポートする場合は「**import**」を付与する。
#### import構文
```
import {name,...} from module(./を忘れずに)
  name:インポートする要素
  module:モジュール(拡張子を抜いたパス)
```
1. モジュール全体をまとめてエクスポートする場合、「*(アスタリスク)」でインポートすることも可能。この場合は、as句で別名を指定する必要はある。
2. モジュール内の個々の要素に別名をつける
3. デフォルトとのエクスポートをインポートする
※下記では、「App」という別名でdefaultのエクスポートにアクセスしている。

#### コード例
```html:mod.html
<script type="module">  // typeで「module」を指定する
    import { value, hello } from './js/mod.js';
    import App from './js/mod.js';  // defaultのエクスポートにアクセス
    console.log(value);  // =>100
    hello();  // =>"Hello"

    const a = new App(1234);
    for (let key in a) {
        console.log(key);  // =>"hoge" =>"foo"
    }
    console.log(a.getSecret());  // =>1234
</script>
```

なお、上記はローカル環境では「Access to script at 'file:///C:/Users/xxx/js/mod.js' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https.」(CORSポリシーに引っかかっているからHTTPでアクセスしてね)といったエラーが出るので、ローカルサーバ等で検証する必要がある。
前職給与にこだわる人事は頭が悪すぎる

## 前置き
昔、とても気分の悪い目に遭ったことがある。

応用情報技術者とTOEIC600点を取得したが、
給与が上がらないため、あるSES会社の面談を受けた。

「当社なら、あなたを客先に**月額65万円**で売り込めます」
『それで、私には年収いくら払ってもらえるんですか？』

「前職給与は？ 前職給与は？」
『350万円ぐらいです』
「**じゃあ**、ウチは355万円で」

"じゃあ"の意味が分からない。
月額65万円ということは、年間780万円の売上が見込める。
じゃあ、その6割を基本給としてお支払いします、なら分かるが
売上が決まってるのに、前職給与がどうとか関係なくね？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2443317/16fa139f-5530-3e29-def9-ecb71e285c76.png)

なお、Google先生によると、平均年収は450～650万円らしい。

## 歴史は繰り返す
そして最近、また同じようなことが起こった。

一応、合格率10％台と言われるIT系の資格を3つ取得したが、
給与が上がらないため、ある会社の面談を受けた。

「前職給与は？ 前職給与は？」
『前職給与はXXX円ですが、貴社の年収テーブルに沿って
　同等レベルの技術者と、同等の給料に設定していただきたく』

:::note warn
結果
**前職給与＋500円（年収500円アップ）**
:::

人は多かれ少なかれ、能力に対して給与が不当に低い
と考えているから、転職を検討するというのに、
その不当に低い額をベースに決めてどうするんだ？
またすぐ辞めるだけだろ。

## 他社がどう関係あるのか ##
私も子供の頃、よくオカンとこんな会話をしたものだ。
『〇〇君は小遣いXXX円貰ってるんだって』
「**ヨソはヨソ！ ウチはウチ！**」

他社は他社でしょ？ 
なぜ、**他社の懐具合で決まった、他社が払っている給料**を
その人の価値を表す絶対基準として妄信するのか分からない。

いや、言いたいことは分かるよ。
日本の労働基準法だと、一度正社員として雇ってしまうと、
簡単に解雇できないし、簡単に給与も下げられない。
だから、1年目の給与はなるべく抑えたい、でしょ？

でも、あまりにも**やり方がヘタクソ**すぎて反吐が出る。

## 私が採用側だったらこうする ##
**案①：夢を見させる方法**
「当社の給与テーブルはこのようになっています」

|ランク|月給|
|:-:|:-:|
|C|65万円/月|
|D|60万円/月|
|E|55万円/月|
|F|50万円/月|
|G|45万円/月|
|H|40万円/月|

あなたのスキルはランクDからGの間になると思われますが、
現時点で正確に判定することは困難なため
試用期間中は**仮置きで**ランクGとさせてください。
期間満了時に、改めてランクを決定させてください。

上げる気がなくても、とりあえずこう言っておけば納得するだろ。
　

**案② ゲタを履かせる方法**
年収は前職給与と同じですが、入社祝い金を100万円支給します。
期待通りのパフォーマンスを発揮できれば、昇給100万円となり
2年目からの年収も、前職給与＋100万円となります。

海外では「サインアップボーナス」としてメジャーな手法。
「祝い金」としておくことで、歓迎している感を演出できる。

実際には難癖をつけて、昇給1000円とかにしておけばいい。

## 頭が悪すぎる方法 ##
「前職給与は？ 前職給与は？」
『600万円ぐらいです』
「**じゃあ**、ウチは600万500円で」

![agest.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2443317/4f519751-c828-c4fa-7242-2d6de9a7eed6.png)

わざわざ**ワンコイン分だけ**乗っかるように微調整。
これで頑張ろうと思える人間がいるなら見てみたい。
　

きっと、心理的にはこんな感じなんだろう。
600円の限定グッズがメルカリに750円で出品されていた。
「原価が600円だから、俺は600円しか払いたくない！」

いや、他人がいくらで調達したとか関係ないでしょ。
大事なのは、お前にとっていくらの価値があるかでしょ。

他社がXXX万円しか出していないから、ウチもXXX万円だ。
こんなやり方をしてたら、優秀な人は絶対に採用できない。


## 追記 ##
メルカリでは
前職給与の参照による「説明できない格差」があったことを
自ら公表した上で、是正するようにしたらしい。

>｢メルカリは約95%が中途採用です。面接などで個人の能力を判断して報酬オファーを出していますが、やはりどうしても前職の給与を考慮した金額になります。
>
>女性のほうが賃金が低いという社会的な構造があり、そこを断ち切ることができていなかった。
>
>女性のオファーをわざと低く出そうとする人はいませんが、一般的な転職のプラクティスを取り入れた結果、社会の性差を再生産してしまっていたんです｣

https://www.businessinsider.jp/post-275612
【TypeScript】 is (型述語: type predicates) について


## はじめに

タイトルの通り、typeofなどの型ガードに続き、**型述語**（type predicates）について学んだのでまとめておく。

## 結論

以下のような引数の型がstringか否かを返す関数があった場合に、`test is string`としている部分が**型述語**に当たる。
以下で、詳細をまとめる。

```ruby
function isString(test: any): test is string{
    return typeof test === "string";
}
```

### 詳細

**型述語**の仕様は以下の通りです。
```typescript
// 関数の返り値がtrueの場合、testがstringであるとTypeScriptは推論する
function isString(test: any): test is string{
    return typeof test === "string";
}

// また別のexample関数に渡されているfooという引数は、この時点ではany型である
function example(foo: any){
　　　　　　　　// isString関数の結果がtrueであった場合には、、
    if(isString(foo)){
        console.log("it is a string" + foo);
        // string型の変数fooからlengthは呼び出し可能であるためコンパイルエラーにならない。
        console.log(foo.length); // string function
    }
}

// ランタイムでもエラーなく実行可能
example("hello world");
```

また、もし`foo`から`toExponential` というメソッドを呼び出した場合は以下の通りコンパイルエラーとなる。

※`toExponential`　は数値を指数表記で表した文字列を返すもので、string型には存在しない

```typescript
function example(foo: any){
    if(isString(foo)){
        console.log("it is a string" + foo);
        console.log(foo.length);
        // toExponential　はstring型には存在しない為コンパイルエラーとなる
        console.log(foo.toExponential(2));
    }
}
```

では、型述語（test is string）でfooがstring型に推論されているif文の外で`toExponential` メソッドを呼び出した場合は、コンパイルエラーにはならないが、実際に引数に渡ってきた値がstring型の場合には`toExponential`メソッドが存在しないのでランタイムエラーとなる。

```typescript
function example(foo: any){
    if(isString(foo)){
        console.log("it is a string" + foo);
        console.log(foo.length);
    }
    // fooがstringだと推論されているif文の外なのでコンパイルエラーにはならない。
　　　　　　　　// が、実際に引数の型がstring型の場合にはtoExponentialメソッドが存在しないので、ここでランタイムエラーとなる。
    console.log(foo.toExponential(2));
}
```

また、もし以下のように`test is string`（型述語）を使用しない場合、

```typescript
function isString(test: any): boolean{
    return typeof test === "string";
}

function example(foo: any){
    if(isString(foo)){
        console.log("it is a string" + foo);
        console.log(foo.length);
　　　　　　　　　　　　　　　　　// fooがstringだと推論されているif文の中でtoExponentialメソッドを呼び出してもコンパイルエラーにはならない。
　　　　　　　　　　　　　　　　　// が、やっぱりstring型の引数にはtoExponentialメソッドが存在しないので、ここでランタイムエラーとなる。
        console.log(foo.toExponential(2));
    }
}
```

## おわりに

typeofよりも難しそうに思えたが、色々なケースを見て理解できた。これもエラーを事前に防ぐのに役立ちそうなので積極的に活用していきたい。
エンジニアが良本に出会う方法　3ステップ～他人の良本は自分にとっても良本なのか？～


技術の移り変わりは早くなっていき、ネットに情報が溢れる時代にあえて本を読む。

技術本のオススメやランキングですらネット上に溢れている。
コンテナ、仮想化、クラウド・・・様々なスタックが求められ、<B>個人によって技術スキルは多様化しているのに他人の良本は自分にとっても良本なのだろうか？
</b>

オススメ本を読んだがスキルにならなかった・・・
どうせなら自分にとって有益な情報を得たい、どうすれば良本に出合えるのか。


ラーメンや観光地を調べるように本を調べる
----

自分の志向に合うラーメンや観光地にいきつくためには、様々な物を試し、何度も調べたはずだが、なぜか本ではそのような事をする人は少ない（と思う）。

### 1. まずは王道を調査

初めて京都に行くのに清水寺や金閣寺に行かない人は少ないだろう。
それと同じようにまずは、その業界で、そのスキルでオススメされている本を読んでみる。
王道1冊読んでみることでこのあと読む本のバロメーターにもなる。

### 2. 図書館でひたすら本を借り、2,3冊/週のペースでサラッと読む

電子書籍は我慢で、図書館でひたすらに本を借りる。
最近の図書館はネットで予約も出来るし10冊、20冊と大量に借りることも出来る。
ここでは、とにかく大量に読む。
そして、<B>自分にとって参考になりそう</B>と思った本だけをメモしておく。


### 3. メモした良本だけをじっくり読む

自分に合った表現方法、自分のスキルに合った記載内容だけがリストアップされたメモ。
これに基づいてスキルを身に着けていく。
よくあるビジネス本で毎日5分のメモを取るとか、XXをするとか、全てやることは不可能だ。
ステップ2で抜粋して、自分に合ったものだけをピックアップして実施するほうが効率が良い。


---
あとはこれを繰り返してスキルを向上させていく。
私は、年間50冊ほど読んでいます。一緒に自分にとっての良本を探しましょう
Railsにおけるキャッシュストア比較表

# 比較表

主にメリット・デメリットを比較したり、利用シーンをまとめてみました。

| &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | &nbsp;FileStore&nbsp; | &nbsp;MemoryStore&nbsp; | &nbsp;MemCacheStore&nbsp; | &nbsp;RedisStore&nbsp; |
| :--- | :--- | :--- | :--- | :--- |
| <b>プロセス間共有</b> | ○ | ✗ | ○ | ○ |
| <b>スレッドセーフ</b> | ○ | ○ | ○ | ○ |
| <b>ホスト間共有</b> | ✗ | ✗ | ○ | ○ |
| <b>無料</b> | ○ | ○ | ✗ | ✗ |
| <b>expires_in可否</b> | ✗ | ✗ | ○ | ○ |
| <b>速さ</b> | やや速い | 速い | 遅い | 遅い |
| <b>削除アルゴリズム</b> | 手動で削除する必要あり | LRU（LRU: Least Recently Used） | LRU | LFUやLRUを選択 |
| <b>利用シーン</b> | 中規模サイトかつホスト数も少ない場合 | キャッシュデータが小さい時(20MB以下) | ホストが多い場合<br>大規模なアプリケーション | ホストが多い場合<br>大規模なアプリケーション |
| <b>注意点</b> | ディスクを圧迫 | メモリを圧迫 | キャッシュデータ制限 | | 
| <b>仕組み</b> | 特定のファイルに保存していく | スレッド毎にRAMに保存していく | Memcache serverに保存していく | Redis serverに保存していく |

# 速度面

```

遅い <——————————————————————————————————————————> 速い

RedisStore, MemCacheStore < FileStore < MemoryStore
```

# 価格面
```
安い <-————————————————————————————————————————> 高い

FileStore, MemoryStore < MemCacheStore, RedisStore
```

# 所感

## FileStoreとMemoryStore

キャッシュデータ量が小さく、ホストも多くない小規模アプリなら、速くて安いMemoryStoreやFileStoreが良さそうだと思いました。
しかし、これら２つはスレッドやプロセス毎にキャッシュを管理する必要があるため、キャッシュの更新を上手く管理しないとバグのオンパレードになると考えられます。

そのため利用するときは以下の2つかなと思います。
- 滅多に更新しないデータのみをキャッシュする場合に使用する
- 開発環境だけ使用する

## MemCacheStoreとRedisStore

MemCacheStoreやRedisStoreは大規模なデータ量を保持可能なのと、プロセスやホスト毎にデータを保存する訳ではないのでバグも起きにくいと考えられます。
そのため、本番環境でよく使われるのかなと思いました。
また、MemCacheStoreやRedisStoreはexpires_inオプションを使って有効期限を指定できます。

ネットワークを介すので実装する際は、そもそもキャッシュデータを取りに行くより実行したほうが速いということがないかは都度検討する必要がありそうです。

## RedisStoreの利点

RedisStoreはLRUやLFUを選択できるのと、ディスクに保持できる点が優れているみたいです。
LRUとLFUは以下のアルゴリズムのことです。

- LRU(Least Recently Used): 直近の利用が最も少ないキャッシュを削除するアルゴリズム
- LFU(Least Frequently Used): 利用頻度が最も低いキャッシュを削除するアルゴリズム

redis4.0からLFUがサポートされています。

# 参考

[Rails guide: Railsのキャッシュ機構](https://railsguides.jp/caching_with_rails.html)
[Railsアプリを66％スピードアップ ― Railsキャッシュの完全ガイド](https://postd.cc/the-complete-guide-to-rails-caching/)
[redis document](https://redis-documentasion-japanese.readthedocs.io/ja/latest/topics/lru-cache.html#eviction-policies)
Ruby コーディングテスト 便利メソッド一覧

※自分用メモ
Rubyによるコーディングテストまたは競技プログラミングにうまく使えそうなメソッド一覧


## irb上で処理速度を計測
```
irb(main):001:0> IRB.conf[:MEASURE] = true  
# または
irb(main):001:0> measure

[243,156,104,280,196,132,128,195,265,300,130].combination(5).select {|a| a.sum == 1000}
processing time: 0.000076s
```

## Array#combination(組み合わせ)
```
a = [1, 2, 3, 4]
a.combination(1).to_a  #=> [[1],[2],[3],[4]]
a.combination(3).to_a  #=> [[1,2,3],[1,2,4],[1,3,4],[2,3,4]]
```

## Array#permutation(順列)
```
a = [1,2,3]
a.permutation(2).to_a #=> [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]
```

## Array#product
```
[1,2,3].product([4,5])     # => [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]]
[1,2].product([1,2])       # => [[1,1],[1,2],[2,1],[2,2]]
[1,2].product([3,4],[5,6]) # => [[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5],[2,3,6],[2,4,5],[2,4,6]]
```
## Array#inject or Hash#inject
```
# 合計を計算する。
[2, 3, 4, 5].inject {|result, item| result + item }       #=> 14

[2, 3, 4, 5].inject(0) {|result, item| result + item**2 } #=> 54
```

## Integer#prime_division
```
require 'prime'
# 素数とその数を求める
12.prime_division #=> [[2,2], [3,1]]
10.prime_division #=> [[2,1], [5,1]]

Prime.each(20).to_a #=> [2, 3, 5, 7, 11, 13, 17, 19]
# 小さな値から順に N 個の素数を求める
Prime.take(10) #=> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
```


## Integer#lcm
```
# 最小公倍数を出す
4.lcm(3) #=> 12
```

## Integer#gcd
```
# 最大公約数を出す
18.gcd(27) #=> 9
```

## Integer#pow(冪乗を計算)
```
# 3の4乗を8で割ったあまりを出力
5.pow(3,  8)  # =>  5
```

## Array#tally
```
# 要素ごとの数を求める
[1,2,3,4,1,1].tally #=> {1=>3, 2=>1, 3=>1, 4=>1}
```

## Array#tranpose
```
# 行列の行と列を転移させる
[[1,2],[3,4],[5,6]].transpose
# => [[1, 3, 5], [2, 4, 6]]
```

## Integer#[]
```
# ビット変換し、ビットが立っていた場合1を返す
例： 6 ⇨ 110
6[0] #=> 0
6[1] #=> 1
6[2] #=> 1
```

## Object#tap
```

(1..10)                  .tap {|x| puts "original: #{x}" }
  .to_a                  .tap {|x| puts "array:    #{x}" }
  .select {|x| x.even? } .tap {|x| puts "evens:    #{x}" }
  .map {|x| x*x }        .tap {|x| puts "squares:  #{x}" }
```

## Enumetable#partition
```
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0].partition {|i| i % 3 == 0 }
 #=> [[9, 6, 3, 0], [10, 8, 7, 5, 4, 2, 1]]
```
Rustで競プロ時に型変換を手軽にできるスクリプトを作った

## おなやみ

`i32` -> `char`への変換や、何番目のアルファベットなどの変換が毎回出てくるたびに
うーん :thinking: って悩んでいて時間をとられていたのでスクリプト化しました。

## 成果物

github :octocat:  に公開してます。詳しくはREADMEに記載してます。
mac用に作成しています :apple:
Windows版も一応作ったのですが動作未検証です・・・すみません、、 :bow: 

https://github.com/okaponta/rust-kyopro-type-converter

## 使い方

リポジトリをクローンして

```zsh
git clone https://github.com/okaponta/rust-kyopro-type-converter.git
```

functionを読み込めば

```zsh
source /[クローンしたディレクトリへのパス]/convert.sh
```

使えます！！(以下の動画からは分かりませんが、クリップボードにもコピーされてます。)

![rust-kyopro-type-converter-demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561891/6ea92c80-1532-f413-38e8-303b2c062ecd.gif)

## おわりに

かんたんなスクリプトですがよければ使ってください〜！ :smile: 
こんなもの欲しいみたいな声もあればぜひご意見聞きたいです! :bow:
solr管理画面に環境バナーを表示させる

solrの管理画面（AdminUI）に環境情報を表すバナーを表示させる方法について

# 対象バージョン
8.2～

# 設定方法
solr.in.shに初期設定で`solr.enviroment`がコメントアウトで記載されています。
```bash
#SOLR_OPTS="$SOLR_OPTS -Dsolr.environment=prod"
```
コメントインして、環境に応じて値を設定します。設定できる値は「prod」、「stage」、「test」、「dev」となります。
```bash
SOLR_OPTS="$SOLR_OPTS -Dsolr.environment=dev"
```
設定した値に応じてバナー色が変わります。
|dev|stage|prod|
|---|---|---|
|![Solr-Admin_dev.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703844/eab4f203-5124-2948-6904-7fbc5fc643d9.png)|![Solr-Admin_stg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703844/bf77df55-fadd-df36-9c2c-64d9d0aba0cc.png)|![Solr-Admin_prod.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703844/1c67281a-7418-0238-05df-5e622d228085.png)|

バナーの色を変えたい、表示する文字を変えたい場合は`label`と`color`オプションで指定できます。
色の指定はCSSカラー色または16進数のカラーコードが使用できます。
```bash
SOLR_OPTS="$SOLR_OPTS -Dsolr.environment=dev,label=dev+hoge,color=yellow"
```
![Solr-Admin_devhoge.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703844/081af3df-9cc6-db0d-74a6-833975c313ab.png)

## 参考
[Environment banner in Admin UI](https://solr.apache.org/guide/8_2/taking-solr-to-production.html#environment-banner-in-admin-ui)
fmtlib(std::format)でwchar_tやchar16_tを使用する

# 環境
* fmt-8.1.1
* VisualStudio2019
# fmt::formatでchar以外の文字列をフォーマットする
```c++
#include <fmt/xchar.h>
std::wstring  wtext = fmt::format(L"{}",123);
std::u16string  u16text = fmt::format(u"{}",123);
std::u32string  u32text = fmt::format(U"{}",123);
```
fmt-8.1.1時点では```fmt/xchar.h```をインクルードすることでchar以外の型もフォーマットできます。
fmt-7.1.3以前であれば```fmt/format.h```でコンパイルできまます。
フォーマット文字列の型は出力したい文字列の型に合わせてください。
フォーマット文字列がwchar_tなのに引数にcharやchar16_tの文字列を渡すとコンパイルに失敗します。
```fmt::formatter```の特殊化をすれば使用することは可能です。
# ユーザ定義型をchar以外にフォーマットする
```c++
struct Point{
	int x,y;
}
template <> struct fmt::formatter<Point, wchar_t> {
	// 書式パース
	template<typename ParseContext>
	constexpr auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
		return ctx.end();
	}
	// フォーマット
	template<typename FormatContext>
	auto format(const Point& point, FormatContext& ctx) -> decltype(ctx.out()) {
		return format_to(ctx.out(), L"({},{})", point.x, point.y);
	}
};

```
```fmt::formatter```のテンプレート引数の第2引数に変換先のフォーマットを設定して下さい。
fmtlibのリファレンスだとわかりづらいですが、std::formatterのページに詳しい使用が書いてあります。
[cpprefjp](https://cpprefjp.github.io/reference/format/formatter.html)
サンプルではParseContextとFormatContextのようにテンプレート化していますが、私の環境では
```ParseContext```→```fmt::v8::basic_format_parse_context<wchar_t>```
```FormatContext```→```fmt::v8::buffer_context<wchar_t>```
として呼ばれていました。特に理由がなければテンプレートのままで良いと思います。
Genesis ブロックの The Times の記事タイトルはどこに埋め込まれているか

# はじめに
Bitcoin の Genesis ブロックには The Times の下記のような記事タイトルが含まれている、というのは Bitcoin にある程度精通している人であれば有名な話かと思います。
> The Times 03/Jan/2009 Chancellor on brink of second bailout for banks

それでは実際に該当のブロックのデータをブロックエクスプローラーで見に行ってみましょう

https://www.blockchain.com/btc/block/000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f

あれ、そのような文言は見つかりませんね。いったいブロックのどこに埋め込まれているのでしょうか。

# 結論
ブロック内にある Coinbase トランザクションに書き込まれている

# 解説
## ブロックチェーンの仕組み
ブロックチェーンはブロックと呼ばれるデータ構造のものが連なっているものです。ブロックとはどのようなデータを持っているでしょうか。ブロックはメタデータが含まれる Block Headers と誰から誰にいくら送金されたかを含むn個のトランザクションで構成されています。ブロック内のトランザクション数は可変で合計1MB以下であればトランザクションをいくつでも含むことができます。

## トランザクション
トランザクションにはインプットとアウトプットの2つが記述されています。インプットには送金元のアドレス（厳密にはUTXOのアドレス）が含まれており、アウトプットには送金先と送金額が記載されています。

## Coinbase トランザクション
各ブロックには必ずトランザクションリストの先頭に Coinbase トランザクションというものが含まれています。これはビットコインのマイニングによって得られる、マイナーへの採掘報酬のトランザクションです。Genesis ブロック内には1つのトランザクションしか存在しておらず、それが Coinbase トランザクションになります。Coinbase トランザクションはマイナー自身が作成していて、トランザクションのインプットには下記表[^1]のデータが含まれており、アウトプットには通常のトランザクションと同様にマイナーのアドレスと送金額が含まれています。
|Size|Field|Description|
|:----|:----|:----|
|32 bytes|Transaction Hash|All bits are zero: Not a transaction hash reference|
|4 bytes|Output Index|All bits are ones: 0xFFFFFFFF|
|1–9 bytes (VarInt)|Coinbase Data Size|Length of the coinbase data, from 2 to 100 bytes|
|Variable|Coinbase Data|Arbitrary data used for extra nonce and mining tags. In v2 blocks; must begin with block height|
|4 bytes|Sequence Number|Set to 0xFFFFFFFF|

ここで注目するのは Coinbase Data フィールドで、ここにはマイナーが 100 バイトまで任意の値（今だと部分的に決まったフォーマットあり）を入れることができます。実際にジェネシスブロックにある Coinbase トランザクションの内容を https://www.blockchain.com/btc/tx/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b で見てみましょう。Inputs にある Sigscript と呼ばれる下記値が Coinbase Data になります。
> ffff001d
OP_4
5468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73

ffff001d というのは difficulty bits、 OP_4 というのはビットコインで使用されている Script ですがここでは説明を割愛します。546... のところの値を　ASCII　コードの値としてみて下記のように　ASCII　文字に変換すると目的の記事タイトルが現れます。
```shell
$ echo '5468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73' | xxd -p -r
The Times 03/Jan/2009 Chancellor on brink of second bailout for banks
```

以上のことから、ブロックチェーンのジェネシスブロック自体に書き込まれているのではなく、ジェネシスブロック内の Coinbase トランザクションの Coinbase Data に ASCII文字を16進数エンコードされた値が含まれている。というのが正確なところでしょうか。

[^1]: https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch10.asciidoc
wasi-sdk + wasmer-python で C/C++ アプリを WASM でポータブルに動かすメモ

## 背景

C/C++ コードを Python からポータブルな形で呼び出したい...
WASI + wasmer-python でやってみます.

malloc/new しなかったり, C++ STL 使わないような場合は Emscripten 利用も検討ください.

wasmer-python と emcc で C/C++ コードを wasm にして python でポータブルに動かすメモ(制約多い)
https://qiita.com/syoyo/items/6f0b74014e55ecf0a02b

## 制約

* `main` を用意し, `main` 経由で処理しないといけない
* C++例外や thread は使えない
* Python 界とは直接はやりとりできず, 画像データを処理したいときなどは, ファイル経由でアクセスしないとだめっぽい(WASI の Rust runtime では stdin/stdout 上書きできるようだが, wasmer-python ではできない) 

## Emscripten に対しての利点

* malloc/new とか, C++ STL(+ libc)関連がある程度使えるので, より汎用な C/C++ コードを動かすことができる

## 方法

まず, wasi-sdk で C/C++ コードを WASI 形式(?) の WASM にします.

```c
#include <cstdio>
#include <cstdlib>

int main(int argc, char **argv)
{
  printf("argc %d\n", argc);
  for (size_t i = 0; i < argc; i++) {
    printf("argv[%d] = %s\n", i, argv[i]);
  }
  return 0;
}
```

以下のような感じでコンパイルしておきます.

```
/home/syoyo/work/wasi-sdk/wasi-sdk-16.0/bin/clang++ --sysroot=/home/syoyo/work/wasi-sdk/wasi-sdk-16.0/share/wasi-sysroot -fno-exceptions -o binding.wasm binding.cc
```

## wasmer-python で実行

そのままだと `wasi_snapshot_preview1` の `fd_close` とかのシンボルが見つからないエラーになります.
WASI 用のランタイムが用意されていますので, それを import するようにします.

https://github.com/wasmerio/wasmer-python/blob/master/examples/wasi.py

手順としては, StateBuilder で `main` 実行の情報(プログラム名, 引数, 環境変数, アクセスできるフォルダ)を設定します.

StateBuilder の情報と, ランタイムは WASI のバージョンに依存するので, WASI のバージョンから import_object を作り, `_start` を invoke します!

```py
from wasmer import engine, wasi, ImportObject, Function, Store, Memory, MemoryType, Module, Instance
from wasmer_compiler_cranelift import Compiler

store = Store(engine.Universal(Compiler))

wasm_bytes = open('binding.wasm', 'rb').read()

module = Module(store, wasm_bytes)
print(module)

wasi_version = wasi.get_version(module, strict=True)
print("WASI version", wasi_version)

wasi_env = \
    wasi.StateBuilder('wasi_test_program'). \
        argument('--myargs'). \
        environment('BORA', 'true'). \
        environment('DORA', 'false'). \
        map_directory('the_host_current_dir', '.'). \
        finalize()

import_object = wasi_env.generate_import_object(store, wasi_version)

instance = Instance(module, import_object)

# _start に引数を与えても反映されないので注意
result = instance.exports._start()
```

```
argc 2
argv[0] = wasi_test_program
argv[1] = --myargs
```

## データのやりとり

stdin/stdout 使えないので, 小規模なデータであれば環境変数 or 引数で指定, 画像データなどの場合は一度ファイルに落としてやりとり, となるでしょう.
(PIPE とか使えるんじゃろか?)

複数インスタンス起動したい場合はファイル名を変えたり, `map_directory` で調整でしょうか.

## main 返り値

wasmer-python では, 0 以外の場合は例外を出します :frowning2: 

`RuntimeError: WASI exited with code: 3`

返り値取得したいときは以下のような感じになるでしょうか.

```py
try:
    instance.exports._start()
except RuntimeError as e:
    print("err_code", str(e).split()[-1])
```

よりきちんとエラーメッセージをパースするなら `parse` https://pypi.org/project/parse/ を使うとよいでしょう.

## おまけ. wasmtime で動かす

https://github.com/bytecodealliance/wasmtime/blob/main/docs/WASI-tutorial.md

コマンドラインから動かせました :smile: 
Python から subprocess で起動とかでもいいかも.
SpringAOPでログ出してみた

# Spring AOP
## 本ページについて
「Spring徹底入門」を読んでいるところで、
気になっていたコア機能の1つであるAOPを試してみた。

## 前提
AOPを実現するために依存性を追加する。
### pom.xml/dependency
```xml
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-aop</artifactId>
</dependency>
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
</dependency>
```

## 実装
DIコンテナに格納されたBeanに対してProxyオブジェクトなるもので、Aopソースで設定したAdviceなるものを設定する、とのこと。
また、@Configuration定義ファイルに、Aopを実行可能なアノテーションを追記するらしい。

### Controller
```java
@GetMapping("/order")
public String getOrder() {
    return aopService.getOd();
}   
```

### AppConfig
```java
@Configuration
@ComponentScan("com.example")
@EnableAspectJAutoProxy
public class AppConfig {
    @Bean    
    AopService aopService() {
        return new AopService();
    }
}
```

### AOP
```java
@Aspect
@Component
public class MethodStartLoggingAspect {
    
    Logger log = LoggerFactory.getLogger(MethodStartLoggingAspect.class);

    @Before("execution(* *..*AopService.*(..))")
    public void logBeforeXxx(JoinPoint jp) throws IOException {
        log.info("メソッド開始" + jp.getSignature());
    }
}
```

## 実行結果
### リクエスト実行
```
$ curl http://localhost:8080/order
```
### コンソールログ
```
2022-06-05 11:56:26.296  INFO 11874 --- [nio-8080-exec-1] c.e.a.aop.MethodStartLoggingAspect       : メソッド開始String com.example.aopdemo.domain.AopService.getOd()
```

## 感想
* AOPを実行させたい対象はDIコンテナにBeanとして登録済みである必要がある
* Java Configurationファイルの作成は、普段は作成していないためなれなかった
* Pointcut式なるものが、独特な書式
ADBで画面録画をする際に画面サイズの指定方法


前にADBでの画面録画方法の記事を上げました。
この方法で録画をしたものは、画面のサイズが大きく、動画の容量が大きい為、プルリクエストなどに貼る際に、加工が必要だったりします。

https://qiita.com/yuta317/items/b4bce237e2637efafc3a

今回は録画をする際に画面サイズを指定すると動画の容量が小さくなる為、おすすめな方法を書いていこうと思います。

# 画面サイズの設定方法

```
 adb shell screenrecord --size 540x960 /sdcard/hoge.mp4
```

screenrecordの後ろに --size　録画する画面サイズ　を記載すると設定できます。

簡単に設定できるので試してみてください。
AlmaLinux OS 9にOpenJDK 17をインストール（Amazon Corretto）

# はじめに

Amazon Correttoを利用してAlmaLinux OS 9にOpenJDK17をインストール
親記事：[OpenJDKの各種インストール方法とEOLまとめ](https://qiita.com/witchcraze/items/b179202216aab50b7090)
参考：[Amazon Corretto Installation Instructions for Debian\-Based, RPM\-Based and Alpine Linux Distributions \- Amazon Corretto](https://docs.aws.amazon.com/ja_jp/corretto/latest/corretto-17-ug/generic-linux-install.html)

## サポート

本手法で導入した場合、[よくある質問 - Amazon Corretto | AWS](https://aws.amazon.com/jp/corretto/faqs/)より、2029-10がEOLになると思われる。
それ以降に報告された脆弱性や不具合への対応は実施されない可能性がある。

## LOG

### インストール

```shell-session
# cat /etc/redhat-release
AlmaLinux release 9.0 (Emerald Puma)

# rpm --import https://yum.corretto.aws/corretto.key
# curl -L -o /etc/yum.repos.d/corretto.repo https://yum.corretto.aws/corretto.repo
# yum install -y java-17-amazon-corretto-devel
... 略
```

### 各種確認

```shell-session
# which java
/usr/bin/java

# java -version
openjdk version "17.0.3" 2022-04-19 LTS
OpenJDK Runtime Environment Corretto-17.0.3.6.1 (build 17.0.3+6-LTS)
OpenJDK 64-Bit Server VM Corretto-17.0.3.6.1 (build 17.0.3+6-LTS, mixed mode, sharing)
```
AlmaLinux OS 9にOpenJDK 11をインストール（Amazon Corretto）

# はじめに

Amazon Correttoを利用してAlmaLinux OS 9にOpenJDK11をインストール
親記事：[OpenJDKの各種インストール方法とEOLまとめ](https://qiita.com/witchcraze/items/b179202216aab50b7090)
参考：[Debian ベースおよび RPM ベースの Linux ディストリビューションで Amazon Corretto 11 をインストールする手順 - Amazon Corretto](https://docs.aws.amazon.com/ja_jp/corretto/latest/corretto-11-ug/generic-linux-install.html)

## サポート

本手法で導入した場合、[よくある質問 - Amazon Corretto | AWS](https://aws.amazon.com/jp/corretto/faqs/)より、2027-09がEOLになると思われる。
それ以降に報告された脆弱性や不具合への対応は実施されない可能性がある。

## LOG

### インストール

```shell-session
# cat /etc/redhat-release
AlmaLinux release 9.0 (Emerald Puma)

# rpm --import https://yum.corretto.aws/corretto.key
# curl -L -o /etc/yum.repos.d/corretto.repo https://yum.corretto.aws/corretto.repo
# yum install -y java-11-amazon-corretto-devel
... 略
```

### 各種確認

```shell-session
# which java
/usr/bin/java

# java -version
openjdk version "11.0.15" 2022-04-19 LTS
OpenJDK Runtime Environment Corretto-11.0.15.9.1 (build 11.0.15+9-LTS)
OpenJDK 64-Bit Server VM Corretto-11.0.15.9.1 (build 11.0.15+9-LTS, mixed mode)
```