OmniAICreator/Qiita-1.07M huggingface dataset:
Intel MacのParallelsにWindows11をインストールする


Parallelsのver17ではWindows11に対応してている。というのは知っていたのですがTPMとかどう対応するのだろう？と思っていたので試してみたました。なお、[TPMやCPU要件を満たさない環境でもWindows11をインストールする方法が公開された](https://pc.watch.impress.co.jp/docs/news/1356709.html)ので今となってはあまり意味がないかもしれません。

今回はIOSダウンロードでクリーンインストールしてみました。

## IOSファイルをダウンロードする

[こちら](https://www.microsoft.com/ja-jp/software-download/windows11)からWindows11のISOファイルをダンロードしておきます。7G程度のようです。

## インストール

Parallelsで新規作成を選択。
DVD/イメージファイルからWindowsをインストールを選択。

![スクリーンショット 2021-10-10 8.43.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55188/06a3d0d1-e939-f010-8222-e52f9b105633.png "スクリーンショット 2021-10-10 8.43.30.png")

ダウンロードしたIOSイメージを選択（自動で見つけてくれます）。


![スクリーンショット 2021-10-10 8.43.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55188/70e9995f-ee1e-b9e9-23e0-c7aedea38c84.png "スクリーンショット 2021-10-10 8.43.37.png")

ライセンスキーを入力。ここではテストなので「最短でインストールするために〜」のチェックを外す。


![スクリーンショット 2021-10-10 8.44.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55188/554e0be2-ffa2-f562-e0da-dc1ff336b4ae.png "スクリーンショット 2021-10-10 8.44.10.png")

Windowsのエディションを選びます。

![スクリーンショット 2021-10-10 8.44.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55188/110de434-58ea-096d-f6ea-470104470c20.png "スクリーンショット 2021-10-10 8.44.29.png")

用途を選びます。適当でいいかと思います。

![スクリーンショット 2021-10-10 8.44.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55188/68cc571f-e409-0935-b45a-4496a6c1dee5.png "スクリーンショット 2021-10-10 8.44.38.png")

VMの名称などを決めます。
ここで、「インストール前に構成をカスタマイズ」をチェックするのが肝です。

![スクリーンショット_2021-10-10_8_44_51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55188/6ef7414d-2a7f-29ca-a548-de1e5e2d6fd1.png "スクリーンショット_2021-10-10_8_44_51.png")

そうすると構成画面がでるのでハードウエアのところでTPMを追加します。

![スクリーンショット 2021-10-10 8.45.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55188/aac19322-2bd1-44a2-f5ae-ba65922fc467.png "スクリーンショット 2021-10-10 8.45.35.png")

ダイアログがでるので「追加」します。

![スクリーンショット 2021-10-10 8.45.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55188/f76db27a-24c9-fe66-9eda-f0e0176b0db5.png "スクリーンショット 2021-10-10 8.45.40.png")

構成画面が閉じます。

![スクリーンショット 2021-10-10 8.45.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55188/63579fce-bb9e-5ec5-cfd5-696ed53a0b2c.png "スクリーンショット 2021-10-10 8.45.52.png")

続行するとWindows11のインストールが開始されます。

![スクリーンショット 2021-10-10 8.46.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55188/9daef6bd-233f-b2cc-db05-8f0e1e008c02.png "スクリーンショット 2021-10-10 8.46.49.png")

インストール成功です。

![スクリーンショット 2021-10-10 8.11.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55188/d69461df-51f0-7edf-b181-54614c049891.png "スクリーンショット 2021-10-10 8.11.22.png")

とりあえず以上。
そのうちアップデートも試してみたいと思います。
【JavaScript】変数と参照の振り返り③　等価性とtrue or falseについて


#はじめに

Udemyの[【JS】ガチで学びたい人のためのJavaScriptメカニズム](https://www.udemy.com/course/javascript-essence/)の講座の振り返りです。

前回の記事

https://qiita.com/nao0725/items/f5b18b61718e96e629b1

#目的

* 変数についての理解を深める


#本題
###1.厳格な等価性と抽象的な等価性

厳格な等価性：a === b
抽象的な等価性： a == b

違いは**型の比較をするかどうか**にあります。

例①

```javascript
 function printEquality(a,b){
// 厳格な等価性で比較　数値と文字列で不一致（false）
  console.log(a === b);
  // 抽象的な等価性　中身は一緒なので一致（ture）
  console.log(a == b);
 }
 
//文字列
 let a = "1";
//  数値
 let b = 1;
 printEquality(a,b);
```

例②

````javascript
function printEquality(a,b){
// 厳格な等価性で比較　数値と文字列で不一致（false）
  console.log(a === b);
  // 抽象的な等価性　中身は一緒なので一致（ture）
  console.log(a == b);
 }
 
//文字列
 let a = "1";
//数値
 let b = 1;

// 　下記の場合厳格な等価性ではfalse(trueは型がBoolean)
 let c = true;
 printEquality(b,c)
//  もし暗黙的な型変換から厳格な等価性をするとtrueになる
 console.log ( b === Number(c)); 
````


例③

````javascript
 function printEquality(a,b){
// 厳格な等価性で比較　数値と文字列で不一致（false）
  console.log(a === b);
  // 抽象的な等価性　中身は一緒なので一致（ture）
  console.log(a == b);

// 下記の場合は厳格な等価性がfalse, 抽象的な等価性はtrue
// 文字列と数値なので厳格にはfalse
 let e = "";
 // Number("")とコンソールで出力すると0と出力されるので抽象的にはture
 let f = 0;
 printEquality(e,f);

//  nullやundifinedも0とみなしtrueで返す
// 基本的には厳格な等価性を使うべき
````


###2.falseyとtruethy

falseになる値の例

```
false,null,undifined,NaN,0,0n,""
```

上記以外はすべてtureになる

````javascript
// 0なのでfalseと等価
let a = 0;
console.log(Boolean(a));

let b = ""
console.log(Boolean(b));

let c = NaN;
console.log(Boolean(c));

 let d = 0n;
 console.log(Boolean(d));
 //  上記はすべてコンソールでfalseとして出力される

 let e = parseInt("");
 console.log(e);
//  上記はparseIntで整数として定義しているが空文字は数字に置き換えられないので、
// 出力結果はNan(Not a Number)となる
// よって下記の場合はfalseと出力される
 console.log(Boolean(e));

// 変数がfalseyかどうかif文で確認する
// もしaを下記のif文にかけて実行するとfalseなので"bye"と出力される
 if(a){
   console.log("hello");
 } else {
   console.log("bye");
 }
````````

今日はここまで！

#参考にさせて頂いた記事

* [【JS】ガチで学びたい人のためのJavaScriptメカニズム](https://www.udemy.com/course/javascript-essence/)
[C#]MVVMの実装方法

はじめての投稿です
# 概要
C# のMVVMの実装方法について忘れてしまった。
初歩的なところから再勉強したメモ

# 結果
これが一番わかりやすかった
[世界で一番短いサンプルで覚えるMVVM入門 | 趣味や仕事に役立つ初心者DIYプログラミング入門](https://resanaplaza.com/%E4%B8%96%E7%95%8C%E3%81%A7%E4%B8%80%E7%95%AA%E7%9F%AD%E3%81%84%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%81%A7%E8%A6%9A%E3%81%88%E3%82%8Bmvvm%E5%85%A5%E9%96%80/)

# 詳細
詳細というか、補足説明みたいな感じで、
上記記事の内容をUML図でみたいので作成してみた。
![mvvm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246658/f615086a-5a56-3030-3ad9-420d8056e92d.png)

余談１
いつも、インスタンスってどうやって表すのだろうと調べるけど中々説明している記事にたどり着かない。
集約とかコンポジションで表すそうな。下記参考サイト参照。

余談２
plantumlでのスコープって□とかで表示されるけど、結局わかりづらい。
わざわざprivate とか追記してしまう。みんなわかるのかな。

# 参考にしたサイト
- [世界で一番短いサンプルで覚えるMVVM入門 | 趣味や仕事に役立つ初心者DIYプログラミング入門](https://resanaplaza.com/%E4%B8%96%E7%95%8C%E3%81%A7%E4%B8%80%E7%95%AA%E7%9F%AD%E3%81%84%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%81%A7%E8%A6%9A%E3%81%88%E3%82%8Bmvvm%E5%85%A5%E9%96%80/)
- [【コードで分かるUMLシリーズ】クラス図の書きかた（集約とコンポジションの意味の違い） - Qiita](https://qiita.com/azuki8/items/49e1add6ea838cd13734)
JavaScriptでタイマー処理とイベントリスナーを組み合わせて使う

#はじめに
JavaScriptの処理を初めて記述した。さらに、addEventListener()と組み合わせて、タイマーをスタートして、状態が遷移したらタイマーを止めるという処理を作成した。今後も使うことがあると感じたため、メモを残したい。同じようなことをしたい方の参考になれば幸いである。

#やりたいこと
JavaScriptでサイトに挿入した動画が何割が再生されたかをリアルタイムで計算して出力したい。apiで動画が再生された、止まったなどの状態と長さ、現在の再生位置は取得できる。長さ、現在の再生位置から再生された割合を計算する。動画は画面の読み込み時に自動で再生される。

#実現方法
addEventListenerとsetIntervalを用いた。タイマー処理を画面の読み込みと同時にスタートする。apiで動画の状態を取得し、動画の再生が完了していたら処理を停止する。今回は1秒ごとに再生された割合を表示をする。

#処理の流れ
諸事情でイベント名や変数名は実際のものと異なるものでメモを書く。処理の流れのイメージが伝わればと思う。

####①タイマー処理を始める。
```js
ratio = currentTime / TotalTime; //現在の再生位置 ÷ 全体の長さ。それぞれapiで取得
let timer = setInterval(console.log(ratio), 1000);
```

####②動画の再生が完了したかを取得し、タイマー処理を取り消す
```js
//動画オブジェクト.addEventListner(動画の再生が完了されたイベント名, やりたいこと);
video.addEventListner("done", function(){
	clearInterval(timer);
})
```

#ひとこと
処理を始めるべきイベントを取得→タイマーを設定→タイマー処理→処理を終えるべきイベントを取得→完了という流れは今後も使いそうだと思った。「普通はこのように書く」や「より良い書き方はこうだ」みたいなのを見つけたら、改めて記事を書きたい。
レンダリングされたサイトをスクレイピングしたかった

## やりたいこと

 - メルカリの検索条件を指定して検索、出力されたページの商品名と出品金額を取得したい
 - Chromeのヘッドレスモードを使用して取得したい

### まずは普通に取得してみる
```python:mercari.py
# メルカリ上で動的レンダリングされた商品情報を取得し、すべてのページから商品名、価格、タイトルを取得する。
from selenium import webdriver
from time import sleep
from selenium.common.exceptions import *

options = webdriver.ChromeOptions()
# options.add_argument('--headless')

browser = webdriver.Chrome('chromedriver.exe',options=options)

# mercari：指定条件を検索したURLにアクセス
url = 'https://jp.mercari.com/search?status=on_sale&page=1&t1_category_id=5&category_id=5'

# アクセスしたらちょっと待ってHTMLソースを出力する。
browser.get(url)
sleep(3)
print(browser.page_source)
```

#### 実行結果(抜粋)  
```html:実行結果  
<li data-testid="item-cell" class="ItemGrid__ItemGridCell-sc-14pfel3-1 iYYoci">
<a class="ItemGrid__StyledThumbnailLink-sc-14pfel3-2 gVKnJ" href="/item/《商品ID》">
<mer-item-thumbnail item-name="《取得したい商品名》" src="https://static.mercdn.net/c!/w=240/thumb/photos/《商品ID》_1.jpg?1633771836" alt="《取得したい商品名》のサムネイル" size="fluid" price="1000" radius="" mer-defined="">
</mer-item-thumbnail>
</a>
</li>
```

楽勝。

### ヘッドレスモードを使用して再実行する  
```html:実行結果  
<li data-testid="item-cell" class="ItemGrid__ItemGridCell-sc-14pfel3-1 iYYoci">
<a class="ItemGrid__StyledThumbnailLink-sc-14pfel3-2 gVKnJ" href="/item/《商品ID》">
<mer-item-thumbnail src="https://static.mercdn.net/c!/w=240/thumb/photos/《商品ID》_1.jpg?1622755102" alt="のサムネイル" size="fluid" price="1650" mer-defined="">
</mer-item-thumbnail>
</a>
</li>
```
mercari.pyのoptionsでコメントアウトしていた行を外して実行した結果…
情報が何か足りない…item_name属性が消えてしまった…

### ソースコード修正
[こちらのサイト](https://www.fixes.pub/program/368707.html) によると、Chrome起動時のオプションが足りないっぽいので追記。   

```python:mercari.py
# メルカリ上で動的レンダリングされた商品情報を取得し、すべてのページから商品名、価格、タイトルを取得する。
from selenium import webdriver
from time import sleep
from selenium.common.exceptions import *

options = webdriver.ChromeOptions()
options.add_argument('--headless')
# 追記！----------
options.add_argument("--window-size=1920,1080")
options.add_argument("--disable-gpu")    
options.add_argument(
    "user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36")
# 追記！----------
browser = webdriver.Chrome('chromedriver.exe',options=options)

# mercari：指定条件を検索したURLにアクセス
url = 'https://jp.mercari.com/search?status=on_sale&page=1&t1_category_id=5&category_id=5'

browser.get(url)
sleep(3)
print(browser.page_source)

```

```html:実行結果(リトライ)
<li data-testid="item-cell" class="ItemGrid__ItemGridCell-sc-14pfel3-1 iYYoci">
<a class="ItemGrid__StyledThumbnailLink-sc-14pfel3-2 gVKnJ" href="/item/《商品ID》">
<mer-item-thumbnail item-name="《商品名》" src="https://static.mercdn.net/c!/w=240/thumb/photos/《商品ID》_1.jpg?1633817344" alt="《商品名》のサムネイル" size="fluid" price="4480" radius="" mer-defined="">
</mer-item-thumbnail>
</a>
</li>
```
ヘッドレスモードでも取れた！

あとは、タグ・属性なりから必要な情報を切り出してリスト化してやればミッションコンプリート。
最初はhrefたどってもうひと踏ん張りしないといけないものだと思っていたので軽い修正で助かりました。
Railsで出てくるparams[:id]ってなんだ？paramsについて深く理解してみる

##はじめに
どうも、未経験からエンジニア転職を目指しているもきおです。

Ruby on Railsを学習しているとよくコントローラーにおいてparamsってやつが出てきますよね？
例としてはこんな感じ

```ruby:users_controller.rb
def show
  @user = User.find(params[:id])
end
```

でもshowの他にeditとかcreateとかでも出てきてしかも記載の仕方がちょくちょく変わっている。
自分自身もとりあえず見様見真似でnewの時はこの記載、showはこの記載みたいな感じで記載してまあエラー起きず動いたら満足って感じでコードを書いてました。

今回はparamsについて理解を深めたのでただコピペでなくちゃんと理解をした上でparamsを使用できるようこの記事に書き記しておきます。

※createに関してのparamsの記載は後日別記事にて記載してます。

https://qiita.com/mokio/items/50f5ee5011bc423c36ae

##paramsってなんぞ？
paramsとは<font color=red>**送られてきた値を受け取るためのメソッド**</font>のことです。っていっても分からないので例を見てみましょう。


![スクリーンショット 2021-10-09 7.55.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1089852/8e2e0485-a2a0-490a-9bcd-6d2811cdce3b.png)
ユーザー一覧はこんな感じのURLになっています。URLの最後が**users**となってますね



![スクリーンショット 2021-10-09 7.55.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1089852/88c2cf5f-7f87-a606-b1a8-f9e0e9be2974.png)
ユーザー一覧で一番上のid:1のkkkkというユーザーの詳細画面(Show)を押すと

![スクリーンショット 2021-10-09 7.57.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1089852/a5583074-d383-4340-82ef-53e0f0ea0608.png)
するとURLの最後に**/1**が追加されました。


![スクリーンショット 2021-10-09 8.01.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1089852/d2e916a4-1836-6ac0-ff5a-51748c5f767d.png)
ここでターミナルを見てみると黄色い枠にidに1が代入されている事がわかります。
このように<font color=red>**paramsは送られて来た値を受け取る事ができます。**</font>



```ruby:users_controller.rb
def show
  @user = User.find(params[:id])
end
```

このparamsにおいてユーザーの:idを取得している事がわかります。
これはidに紐ずくユーザー情報を全て取って来ているので次のような事もできます。

**View index.htm.erb**
![スクリーンショット 2021-10-10 5.42.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1089852/ad9f5d60-b813-a10d-a38f-422477b3fd64.png)
今までこのような記載だったのを
![スクリーンショット 2021-10-10 5.41.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1089852/55c5b4e8-c3fe-4b9f-4751-7b1a1eee317a.png)
nameをキーとしてユーザーネームも渡してあげます。

![スクリーンショット 2021-10-09 8.24.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1089852/0c7d5bec-7335-4ad8-69a4-a330eb1d79e2.png)
するとidの後に名前も挿入されることが分かります。少しparamsが理解できてきたのではないかなと思います。

##あとがき
今回でparamsの理解を少し深める事ができました。
この記事が少しでも良いと感じていただけましたらLGTMポチっとしていただけると幸いです。
Raspberry Pi Imagerを使って簡単にインストールメディア作成

久しぶりにRaspberryPiにOSをインストールしようと思ったら、SDカードフォーマッターやbalenaEtcherを使わずにRaspberry Pi Imagerで簡単にインストールできたので、その時のめも

# Raspberry Pi Imagerのダウンロード

ラズベリー財団のページに行きます。

https://www.raspberrypi.org/

ページが開いたら、上のメニューの「Computers」-「SOftware」で、Raspberry Pi Imagerのダウンロードページへ行きます。

|![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/2f7fa71d-be27-09f0-15b8-fb9a4f24169f.png)|
|:--|

ブラウザの幅を狭くしていると以下のように赤枠で囲んだ右上のところをクリックして、メニューの選択肢を表示します。

|![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/62362787-7898-86a2-7ad1-16dd86b398a3.png)|
|:--|

|![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/eeff4947-0bf2-27ab-a872-6ecf0b36d704.png)|
|:--|

# Raspberry Pi Imagerのダウンロード

今回は、Windows10を使ったので、「Download for Windows」の釦を押しRaspberry Pi Imagerをダウンロードします。

|![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/aec853d6-4c42-e3c1-c63b-474221f4102f.png)|
|:--|

|![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/897a9a21-16b3-1fcc-9b3e-ed6c32f0d611.png)|
|:--|

# Raspberry Pi Imagerのインストール

ダウンロードを完了したファイル（今回はimager_1.6.2.exe）を起動してインストールを開始します。

|![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/36537c03-3c4f-ff90-98bb-ec422d28910c.png)|
|:--|

|![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/e9218111-3253-731d-3cc4-f6cb29f29c4e.png)|
|:--|

# Raspberry Pi Imagerを使ってSDへ書き込み

起動後、以下のような画面になるので、インストールするOSとインストールするメディアを選択します。
※この時のメディアはPC側で認識済みのものが表示されます。

|![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/8fcf3326-33d9-0746-2ca4-0685bc0366ef.png)|
|:--|

## OSの選択

今回は、Raspberry Pi OS(32-bit)を選択しました。

|![8-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/f229e5e5-3e4d-9637-82ea-b8a04e633db2.png)|
|:--|

|![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/f5106d91-cee4-dc29-85aa-25190114616d.png)|
|:--|

## 書き込むメディアの選択

|![8-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/9e09e72e-7d54-4550-ee51-974cbe32e750.png)|
|:--|

|![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/2b134eae-9803-32f9-5ab4-738cf2134be9.png)|
|:--|

## メディアへ書き込み

|![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/2fa2acd6-8f63-b2a0-355a-74ff4d796ded.png)|
|:--|

|![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/f7f1c38d-1aaf-0073-c817-7131e35a072c.png)|
|:--|

|![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/f9515c45-1478-fb6b-7464-08a6ef343b19.png)|
|:--|

# メディアへの書き込み終了
|![14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28184/76969b56-4999-461f-3472-0155a3eac84a.png)|
|:--|

# OSのインストール

ここは以前と変わらないので省略。
作ったメディアをRaspberry Piに挿して起動後、地域設定、キーボード設定、パスワードやWifiなどのネットワークの設定などをおこなうとインストールが完了します。

# OSのアップデート

とりあえず、OSのアップデートをしてみる。
今回はautoremoveに１つ削除パッケージがあっただけ。

```
$ sudo apt update
$ sudo apt full-upgrade -y
$ sudo apt autoremove -y
$ sudo apt clean
$ sudo reboot
```
# SSHを使えるようにする。

GUIを使うことはあまりないので、普段使っているPCからSSHでログインできるようにSSHを有効にしておく。
【Unity】パッケージマネージャ トラブルシューティング

# [Addressable]ArgumentException: An item with the same key has already been added. Key:****** が発生した際にKey:******を含むファイルが存在しない。
Unity2019.4.23f1で発生
本来であれば、重複したAddressableAssetSettingsの定義を片方削除するとエラーを解除できるのですが、そもそもキーを含むファイルが存在しないケースが発生しました。
⇨Unity再起動でエラーから復旧しました。
[Go] KeyLogWriter (crypto/tls) を使って TLS 通信を Wireshark で復号化する

一般にブラウザや curl で同様に TLS のダンプをしたい時は、`SSLKEYLOGFILE` 環境変数に TLS master secrets 情報を書き出すファイルを指定し、Wireshark などの外部アプリケーションにこのファイルを食わせることで capture した暗号化通信データを復号化し、手元で生の HTTP リクエスト情報 (over TLS) を手軽に解析できることが知られています。

https://please-sleep.cou929.nu/decrypting-tls-traffic-packet-capture.html

https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format

https://everything.curl.dev/usingcurl/tls/sslkeylogfile

## KeyLogWriter (crypto/tls)

Go でも同様に `crypto/tls` package がサポートしている `KeyLogWriter` を使うことで TLS master secrets 情報を書き出すことができます。

参考: https://pkg.go.dev/crypto/tls#example-Config-KeyLogWriter

```go
// 出力先ファイルを指定
w, err := os.OpenFile("tls-secrets.txt", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)

client := &http.Client{
	Transport: &http.Transport{
		TLSClientConfig: &tls.Config{
			KeyLogWriter: w,
		},
	},
}

// 以降この client で行われた通信は Wireshark で復号化して解析可能になる
```

Wireshark で TLS master secrets ファイルを読み込む方法については上記のリンク内でも詳しく説明されているので、そちらを参照ください。
ALBだけで特定URLへのリダイレクトを完結させる方法

AWS環境にてリダイレクトの設定をRoute53や、.htaccessを使わずに
ALBだけで完結させたかったのでメモ。サイトはSSL（https）化済。

リダイレクトはALBのリスナーから設定する。

###ALBでの設定
**①http**
こっちは**https**に飛ばす設定。リダイレクト先はデフォルト。

```
デフォルトアクション リダイレクト先 https://#{host}:443/#{path}?#{query}
```

**②https**
こっちは存在しないページに対して特定のURLに飛ばす設定。リダイレクト先を直書き。
今回はサブディレクトリのページに飛ばしたかったので、サブディレクトリを入れています。

```
１ 転送先 対象のインスタンス
デフォルトアクション リダイレクト先 https://ドメイン名:443/サブディレクトリ名/?
```

サブディレクトリの場合、最後に「/」がないとダメ。入れないと、リダイレクトのループが発生する。
リダイレクトもブラウザでキャッシュしてしまうことがあるらしく、それを外したい場合はChromeだと、
検証→Network→**Disable cache**にチェック。

ここまでページ遷移が細かく追えるChromeすごい...
にゃーたす 〜2021SPAJAM予選作品〜

#目次
[SPAJAMとは](#SPAJAMとは)
[参加経緯](#参加経緯)
[使用したツールや技術等](#使用したツールや技術等)
[参加者の役割について](#参加者の役割について)
[作ったアプリ](#作ったアプリ)
[感想](#感想)

#SPAJAMとは
SPAJAMとは、モバイルアプリハッカソンです！
このハッカソンは、アイデア出し（アイデアソン）から始まり、開発、作品発表までを２日間で行う、という内容になっています。

予選で優秀だったグループが本選（温泉地で開催）に出場できます。

#参加経緯
大学の授業や研究では様々なプログラミング言語や情報系の基礎知識を学んだり、論文を読んだりと、インプットすることが多かったです。

大学、大学院で得たものをどこかで発揮したいと思っていたので、以前から存在を知っていたSPAJAMに先輩を誘って参加しました。

#使用したツールや技術等
###Flutter(フレームワーク)

:::note info`
FlutterGoogleが開発したモバイルアプリケーションフレームワークです。主に、AndroidやiOSなどのアプリケーション開発に利用されています。
:::

###Dart（言語）

###Illustrator(デザインソフト)
アプリのアイコンロゴ作成に使用しました。

###ClipStudioPro(イラストソフト)
アニメーションを作成するために使用しました。

#参加者の役割について
<dl>
<dt>自分</dt>
<dd>デザイン、イラスト、フロント、バック（少々）</dd>
<dt>先輩</dt>
<dd>フロント、バック</dd>
</dl>

自分は特にフロント側の処理を、先輩はバック側の処理を担当していました。ただ、2人ともコードを書けるため、お互い支え合いながら開発しました。また、自分はイラストやデザインを趣味でやっているため、そちらの方も並行して担当しました。

#作ったアプリ
`「にゃーたす」`
という新感覚のTo do リスト（タスク管理）アプリです！

簡単に説明すると、増えすぎたやりたいことをねこ（可愛い）が食べて減らしてくれます。詳しくは後ほど説明します。

![にゃーたす.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2057557/a5df9a40-8d3c-ab67-adaa-7cb7be2f3ea3.gif)

###ロゴ
時間に追われ、かなり短時間で作成しました。
「可愛らしい」と「シンプル」と「わかりやすい」を軸にしています。
![title2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2057557/17817c67-f3cb-11a5-2e07-60cb62e95716.png)


###コンセプト

やりたいこと（やってみたいこと）が多すぎる
↓
タスクに追われて焦り、結局何もしない（だらだらと現実逃避してしまう）
↓
タスクを減らすことで、焦らなくなり遂行しやすくなるのでは？
↓
にゃーたすの出番


![にゃーたす _ねこ×タスク管理_-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2057557/f331abe6-21d1-2fb0-86e2-74fb1976c119.png)



###機能説明

「タスクを減らす」というのを「ねこがタスクを食べて減らす」に発想を転換しました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2057557/e5e6c537-bd4b-cd0b-7eb8-fda5ec8fad90.png" width="40%">　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2057557/bdaba36a-ef00-3abd-9476-f17fc57c4eb8.png" width="40%">

- 青になっているタスク（上の画像ではプログラミング）は完了済のタスク
- 右下のプラスマークからタスクを追加
- 「食べるにゃ」ボタンでタスクを減らせる
- タスクに鍵を付けて猫に食べられないようにすることができる


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2057557/08de3a61-930d-3135-3508-692243ec415c.png" width="40%">

- ねこをタップすると、今までに食べたタスクを確認できる。これらを元に戻すこともできる。
- 「クリアー」ボタンで全削除ができる

###システム構成

![にゃーたす _ねこ×タスク管理_-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2057557/c87bb6d5-9403-e906-a041-02ec779e1eb2.png)


firebaseでデータを管理しました。

###改善点や今後の課題

- タスクが完了した時の表現をわかりやすくしたい
- 日毎にタスクをリスト化
- 「食べる」から「手でどかされる」に変更してみる

#感想
夏休み中の開催ということで、事前に勉強会をしたり対策をしてハッカソンに臨むことができました。チームメイトと限られた時間で、自分たちのできることをフルに発揮できたと思います。（睡眠時間はほとんど確保できませんでしたが…）

本選出場権を得ることはできませんでしたが、高いクオリティの作品を作っているチームと一緒に競えたのでとてもいい経験になりました。
LaravelのRequestを使ったuniqueバリデーションで自分自身を除く方法

こんにちは、JeffTechです。

# 説明
Laravelのユーザー情報編集のRequestにて、メールアドレスをunique設定しました。

しかし、メールアドレスを変更せずに他の項目を変更し、編集ボタンをクリックすると「すでにこのメールアドレスが登録されています」とのバリデーションが出てしまいました。

理由は簡単で、自身のメールアドレスがすでにDBへ登録されているため、Laravel側で重複していると判断されてしまったためです。

今回はその解決法を説明します。

# この記事で実現できること
- Requestにて自分自身を除く方法

# 実装
今回は`Usersテーブル`のカラム名が`email`であるパターンで説明していきます。

`unique:ユニークチェックをしたいテーブル名,ユニークチェックをしたいカラム名,ユニークチェックを除外したい値,ユニークチェックを除外したいカラム名`
という感じで記述していきます。

## ログインユーザーのメールアドレスを重複バリデーションから除きたい場合

```php:UserUpdateRequest.php
<?php

namespace App\Http\Requests\Admin;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;

class UserUpdateRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }
    public function rules()
    {
        return [
            'name' => ['required', 'between:2,150'],
            'email' => ['required', 'string', 'email:strict,dns', 'max:255', 'unique:users,email,'.Auth::user()->email.',email'],
            'support_end_at' => ['required', 'date', 'date_format:Y-m-d'],
        ];
    }
}

```

ログインユーザーのメールアドレスを重複バリデーションから除きたい場合は、

- ユニークチェックをしたいテーブル名：`users`
- ユニークチェックをしたいカラム名：`email`
- ユニークチェックを除外したい値：`Auth::user()->email`
- ユニークチェックを除外したいカラム名：`email`
となります。

ちなみに、`Auth::user()->email`とすることで、ログインユーザーのメールアドレスを取得できます。

## 管理画面などで、ユーザー一覧から選択したユーザーのメールアドレスを重複バリデーションから除きたい場合

```php:UserUpdateRequest.php
<?php

namespace App\Http\Requests\Admin;

use App\Models\User;
use Illuminate\Foundation\Http\FormRequest;

class UserUpdateRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        $user = User::find($this->id);
        return [
            'name' => ['required', 'between:2,150'],
            'email' => ['required', 'string', 'email:strict,dns', 'max:255', 'unique:users,email,'.$user->email.',email'],
            'support_end_at' => ['required', 'date', 'date_format:Y-m-d'],
        ];
    }
}

```

一方で、管理画面などで、ユーザー一覧から選択したユーザーのメールアドレスを重複バリデーションから除きたい場合は、

- ユニークチェックをしたいテーブル名：`users`
- ユニークチェックをしたいカラム名：`email`
- ユニークチェックを除外したい値：`$user->email`
- ユニークチェックを除外したいカラム名：`email`
となります。

まず、`$user = User::find($this->id);`で選択したユーザーの情報を変数$userに格納します。
その後、そのユーザーのメールアドレス情報を`$user->email`で取得します。

# 最後に
少しでも役に立った！という時は、いいねをポチッとして
フォローしてくださると嬉しいです、、、笑

役に立たなかった時は、怒らないでコメント頂けますと幸いです笑

Twitterもやってますので、よかったら見てみてくださいね！
https://twitter.com/jefftechsaku
PythonでLTSpiceのAC解析結果をグラフ化する

LTSPpiceでSIMした結果をPythonで扱うltspiceモジュールを使ってAC解析結果をグラフ化する備忘録


解析したのは、この回路をSIMした出力ファイルDraft1.raw
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527090/765b2565-46d1-403a-bc9f-bc2ed7483fe3.png)

ltspiceモジュール公式ページのサンプルが過渡解析用だったのでAC解析結果の複素数を処理するコードを足している。
LTSpice上でカーソル当てるようにして結果を閲覧したいのでplotly expressでグラフ化した。
plotly expressでグラフ化する都合上pandasも使っている。

```python
import ltspice
import pandas as pd
import plotly.express as px
import numpy as np

filepath = 'Draft1.raw'
l = ltspice.Ltspice(filepath)
l.parse()


V1 = l.get_data('V(out)')

df = pd.DataFrame(
  data={
    'freq':l.getFrequency(),
    'Gain':20*np.log10(abs(V1)),
    'Phase':180/np.pi*np.angle(V1)
  }
)


fig_g = px.line(data_frame=df,x='freq',y='Gain',
              title = 'AC analysis bode plot',
              log_x=True, log_y=False)
fig_g.show()
fig_p = px.line(data_frame=df,x='freq',y='Phase',
              title = 'AC analysis bode plot',
              log_x=True, log_y=False)
fig_p.show()
```
実行結果はこれ。Jupyterlab上で表示した結果のスクショ。カーソルを当てたところの値を表示してくれるplotlyは神だと思う。
ただ、matplotlibと比べるとグラフを書くのに最低限必要なコードが増えるので、コード量少なくてもグラフを書けるplotly expressは大変有り難い。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527090/7ed7ac68-a055-5774-bb1b-767a5be7a34f.png)

グラフのカスタマイズに関する情報はこの2つぐらいを参照
温度や電圧を振ったときのグラフをプロットするfacetの扱いに関するサンプル
https://plotly.com/python/facet-plots/

plotly expressの描画オプションに関する日本語情報
http://oyoyonochichi.coolblog.jp/Python/plotly/express_line2.html
pip installをしたときにGitのsubmoduleがインストールされない問題

# はじめに
Github上で開発をしている際に開発しているmoduleとは別のRepositoryのmoduleを利用したい場合があります．
そのようなときに`submodule`を利用します．一方で，単純にsubmoduleを加えるだけだと`pip install`をした際にsubmoduleが追加されないという問題が発生します．その対処法について簡単に説明します．



# 問題設定
Sphere関数という関数を作成し，それをsubmoduleとして利用したいケースを想定します．
例として[submodule_practice_parent](https://github.com/nabenabe0928/submodule_practice_parent)というrepositoryを用意しました．

> submodule_practice_parent/
　├ submodule_practice_parent/
　│　　└ \_\_init\_\_.py
　│　　└ func.py  <=== これを使いたい
　├ requirements.txt
　└ setup.py

`submodule_practice_parent.func.sphere`という関数が実際に利用したい関数です．

次に[submodule_practice_child](https://github.com/nabenabe0928/submodule_practice_child)というrepositoryを用意します．この `run.py` の中から `submodule_practice_parent.func.sphere`を呼び出せるようにします．

> submodule_practice_child/
　├ submodule_practice_parent/ <== submodule
　├ submodule_practice_child/
　│　　└ \_\_init\_\_.py
　│　　└ run.py
　├ .gitmodules
　├ requirements.txt
　└ setup.py


`submodule_practice_parent`は以下のコマンドによって`submodule_practice_child`のsubmoduleになっていると仮定します．

```
git submodule add https://github.com/nabenabe0928/submodule_practice_parent submodule_practice_parent
```

# 対処法
解決の手順を順番に書いていきます．
1. `submodule_practice_parent` の中に `setup.py`がなければ作る
2. `submodule_practice_child` の `setup()` の引数である `install_requires` にsubmoduleを指定する
コード例は以下の通り．

```python
import setuptools


requirements = []
with open("requirements.txt", "r") as f:
    for line in f:
        requirements.append(line.strip())

requirements.append(
    "submodule_practice_parent "
    "@ git+ssh://git@"
    "github.com/nabenabe0928/submodule_practice_parent"
    # "@v0.0.1#egg=submodule_practice_parent"  <== versionがあるなら指定する
    "#egg=submodule_practice_parent"
)

setuptools.setup(
    name="submodule_practice_child",
    version="0.0.1",
    author="nabenabe0928",
    author_email="user@gmail.com",
    url="https://github.com/nabenabe0928/submodule_practice_child",
    packages=setuptools.find_packages(),
	python_requires='>=3.8',
    platforms=['Linux'],
    install_requires=requirements,
    include_package_data=True
)

```

# テスト
実際にうまくいくかどうか試してみます．
今回はmoduleがpublicになっていないので，Localにcloneしてからうまくいくか試します．

```sh
# テスト用の新しい環境を作成
$ conda create -n package_checker python=3.8

# pipのパスを確認 (今回は `package_checker` のpipか確認)
$ which pip
/home/user/anaconda3/envs/package_checker/bin/pip

$ git clone https://github.com/nabenabe0928/submodule_practice_child

$ cd submodule_practice_child/

# submodule_practice_child を install
$ pip install .

# 念の為，別のディレクトリに移動
$ cd <適当なディレクトリ>

$ python
>>> from submodule_practice_child.run import start 
>>> start()
55
```

`module not found`なしにうまく実行されました．

# submoduleのVersion変更

```sh
$ cd submodule_practice_parent
$ git checkout <target branch> && git pull
$ cd ~/submodule_practice_child
$ git add submodule_practice_parent
$ git commit -m "[version] Update the submodule_practice_parent to the latest"
```
sedで複数行を置換、挿入したいとき【sed, Shell】

# やりたいこと
次の2つのファイル(文字列)がある

```shell:source
hogehoge hugahuga
hogahoga hugehuge
```

```shell:target
AAAAAA
BBBBBB
CCCCCC
FLAG
DDDDDD
EEEEEE
```

このときに`target`の`FLAG`の部分を`source`の内容で置き換えたい。
つまり、

```shell:result
AAAAAA
BBBBBB
CCCCCC
hogehoge hugahuga
hogahoga hugehuge
DDDDDD
EEEEEE
```

こんな感じ。
これが少し面倒で、詰まったので書き残す。

# 結論
これでOK

```shell:
str=`cat source | # 挿入する文字列を読み込み
        sed -r 's/$/\\\\n/' | # 各行の末端に改行文字を入れる
        sed -r '$s/\\\\n//' | # 最終行の改行文字に関しては必要ないので取り除く
        while IFS= read -r line # 1行ずつ読み込み
        do
            echo -n "$line" # echo -nで各行を改行しないで出力->1行にまとめる
        done`
cat target |
    sed -r "/^FLAG$/s/.+/$str/" # sedで必要な部分に挿入(置換)
```

# 解説1/3

まずは次のやり方が思いつくと思う。

```
str=`cat source`
cat target | sed -r "/^FLAG$/s/.+/$str/"
```

しかしこれでは上手くいかない。
というのも、どうもsedは置換後の文字列(`$str`)が複数行だと上手く置換してくれずにエラーを吐いてしまう

```
sed: -e expression #1, char 28: unterminated `s' command
```

つまり`$str`が複数行で無ければいい。

# 解説2/3
`source`の内容は複数行なのに`$str`は複数行ではいけない。
矛盾しているようだが、次の`sed`の仕様を使えばいける。

```shell:
$ cat target | sed -r '/^FLAG$/s/.+/hogehoge hugahuga\nhogahoga hugehuge/'
AAAAAA
BBBBBB
CCCCCC
hogehoge hugahuga
hogahoga hugehuge
DDDDDD
EEEEEE
```
つまり改行文字`\n`は有効なのである。

従って、`source`の内容を1行に変換しつつ、元の改行位置に`\n`を入れた`$str`を用意すればOK

# 解説3/3
複数行を1行にまとめる方法に関しては、固定行数であればいくつかあるが任意の行数となるとなかなか難しい。今回は次の方法を採った。

```shell:
$ cat source | while IFS= read -r line ; do echo -n "$line" ; done
hogehoge hugahugahogahoga hugehuge
```
つまり`while read`で行ごとに読み込み、`echo -n`で各行を改行なしで出力している。
`IFS=`と`-r`に関しては、デフォルトだと先頭・末端のスペースやバックスラッシュを取り除く`while read`の仕様対策。

あとは、1行にまとめる前に各行の末端に改行文字`\n`を入れておけばOK(エスケープする必要はあるが)
RSpec レコードが作成、削除されているかをテストする方法

# RSpecとは
Railsでweb開発をする時に、想定通りにアプリが動いているかを
テストするための```テストフレームワーク```です。
```実務ではコードレビューはRSpec```でやります。
スクールみたいにコードを見るわけではないみたいです。
理由はコードが何百行とかになると、いちいちコードレビューができないからです。

# Request spec
RSpecでテストをする時に、URLでリクエストを送ったとき、想定通りの挙動になっているかを検証するテストです。
"GET/articles/:id"みたいなURL指定でのテストになります。

# レコードが作成されているかのテスト
これはcreateのテストでよく使います。今回はstaffsモデルにします。
URLは　POST"/staffs/"です。

```staffs_spec.rb
describe "POST /staffs" do
#都合により省略
it "staffのレコードが作成される" do
expect {subject}.to change {Staff.count}.by(1)　#ここです。
end
end

```
expectの部分がレコードが作成されているかのテストです。
```staffのレコードが1増えることを期待したテストです。```

# レコードが削除されているかのテスト
削除されているかをテストするとなると、書き方が少し変わります。
URLは "DELETE /staffs/:id"です。

```staffs_spec.rb
describe "POST /staffs/:id" do
#都合により省略
it "staffのレコードを削除" do
  expect {subject}.to change {Staff.count}.by(-1)
end
end
```
expectの部分がレコードが削除されているかのテストです。
```staffのレコードが1減ることを期待したテストです```
Kubectlのコマンド補完とエイリアスは設定すべし！！

エイリアスは設定してたけど・・・コマンド補完は設定してなかったので・・・設定してやったぜ！！

# コマンド補完とエイリアスを設定

bashを利用している場合は、以下の設定をすればkubectlのコマンド補完を使えるようになります！！

```
# コード補完が使えるようにする
$ echo "source <(kubectl completion bash)" >> ~/.bashrc

# エイリアスの設定とエイリアスでコード補完を使えるようにする
$ echo "alias k=kubectl" >> ~/.bashrc
$ echo "complete -F __start_kubectl k" >> ~/.bashrc

# 設定をターミナルへ反映
$ . ~/.bashrc
```

ターミナルに反映後は、タブを押すとサブコマンドの候補が表示されるようになります。

```
$ k get {タブ押下}
apiservices.apiregistration.k8s.io                            events.events.k8s.io                                          podtemplates
certificatesigningrequests.certificates.k8s.io                flowschemas.flowcontrol.apiserver.k8s.io                      priorityclasses.scheduling.k8s.io
clusterrolebindings.rbac.authorization.k8s.io                 horizontalpodautoscalers.autoscaling                          prioritylevelconfigurations.flowcontrol.apiserver.k8s.io
clusterroles.rbac.authorization.k8s.io                        ingressclasses.networking.k8s.io                              replicasets.apps
componentstatuses                                             ingresses.networking.k8s.io                                   replicationcontrollers
configmaps                                                    jobs.batch                                                    resourcequotas
controllerrevisions.apps                                      leases.coordination.k8s.io                                    rolebindings.rbac.authorization.k8s.io
cronjobs.batch                                                limitranges                                                   roles.rbac.authorization.k8s.io
csidrivers.storage.k8s.io                                     mutatingwebhookconfigurations.admissionregistration.k8s.io    runtimeclasses.node.k8s.io
csinodes.storage.k8s.io                                       namespaces                                                    secrets
csistoragecapacities.storage.k8s.io                           networkpolicies.networking.k8s.io                             serviceaccounts
customresourcedefinitions.apiextensions.k8s.io                nodes                                                         services
daemonsets.apps                                               persistentvolumeclaims                                        statefulsets.apps
deployments.apps                                              persistentvolumes                                             storageclasses.storage.k8s.io
endpoints                                                     poddisruptionbudgets.policy                                   validatingwebhookconfigurations.admissionregistration.k8s.io
endpointslices.discovery.k8s.io                               pods                                                          volumeattachments.storage.k8s.io
events
```

ってな感じ。

# 参考サイト

* https://kubernetes.io/ja/docs/reference/kubectl/cheatsheet/

# まとめ

Enjoy the Kubernetes using with command line tools!!
Kubernetes Operatorでよくわからない事象が発生したときの対応集

（随時追加）

##### CRやCRDの削除がTerminatingのまま終わらない

Operatorをインストールしたりアンインストールしたりを繰り返していたときに発生した。CRの削除が何かしらの理由でハング状態になった。finalizerを消すことで削除が完了する。

```
$ kubectl edit ${CRD} ${CR} -n ${namespace}
* metadataのfinalizer行を削除して保存
```

##### operator-sdk run bundle時に「Failed to run bundle: error waiting for CSV to install: csv failed: reason: "UnsupportedOperatorGroup", message: "OwnNamespace InstallModeType not supported, cannot configure to watch own namespace"」

宛先ネームスペースにあるOperatorGroupと不整合が発生している。OperatorGroupを更新または削除すると解消する。ただし他のOperatorに影響がないことは確認すること。

```
$ kubectl get operatorgroup -A
$ kubectl delete operatorgroup ${name} -n ${namespace}
```
Qiita API v2を使ってContributionっぽいものを計算してみた

Qiita のマイページを見てたら、いつの間にか Contribution っていう値が出てた。（いつの間にかじゃない）
これって何だろうと思うと同時に、意外と使えるんじゃないかと。

私は「インプットを増やすならアウトプットしないといけない」と思っている。アウトプットしてアウトプットして、自分の中が空っぽになってもアウトプットして、アプトプットするために勉強して初めてインプットが出来ると。
なので、例えばチームの中でみんなで Qiita にアウトプットして、その Contribution の値で競えば、アウトプットの促進、ひいてはインプットの促進になるんじゃないかと。
そのための射幸心を煽るツールとして、Contribution って使えるんじゃないかと。
多分 Contribution って、Qiita の中の人が「その人の活動の具合」を測るために色んなパラメータを上手い具合に計算して、いい感じの値になるように絶妙に調整された値なんじゃないかと。（煽りすぎ）

決して自分が適当に好きなことを Qiita に吐き出してるのを正当化してる訳では無いです。

# Qiita API v2

で、多分 Contribution って自分の投稿数とか計算してるんだろうと。
じゃあそれを取ってくるにはどうしたら良いかと探すと、[Qiita API v2](https://qiita.com/api/v2/docs) ってのがあった。これこれ。
GET を投げると JSON で返ってくるってことは、[requests](https://requests-docs-ja.readthedocs.io/en/latest/) でパッパと書けるな。

API トークンってのが必要らしいけど、[このベージ](https://qiita.com/settings/tokens/new)から、「個人用アクセストークン」ってのを作れば良い。
トークンが無いと１時間あたり60回までしかAPIを叩け無いけど、トークンを付ければ１時間あたり1000回までになる。

# Contribution とは

じゃあ Contribution って実際どうやって計算してるのかと調べると、まさしく[Contributionとは](https://help.qiita.com/ja/articles/qiita-contribution)というページが有った。

すげぇちゃんと計算してる。

しっかり計算してみるかと、ここに挙がっている値を全部 Qiita API v2 で取ってこようと思ったのだが、

全然取れない。

もちろん投稿数とか LGTM 数とか取れるんだけど、例えば「編集リクエストが承認される」なんて全然無理っぽい。

じゃあ、Qiita API v2 で取れる範囲で計算しようじゃないかと。ということで、「なんちゃって Contribution」というのを、以下で定義した。

```
なんちゃってContribution = 投稿数 + LGTM数 + 0.5 * ストック数
```

この `0.5` ってのが、LGTM とストックの重要度を比較するのに丁度良い塩梅なんじゃないかと。

# 作ってみた

ということで、作っております。

https://github.com/tetutaro/qiita_contribution

特徴

* 複数ユーザーの情報を取ってきて、ランキング形式で出力（射幸心！）
* 念の為、API を余分に発行しない限り、Contribution 以外にも取れる情報を出力
* 一定の期間に作られた投稿だけをカウントすることが可能
    * 特定の期間だけで競い合いたい、という場合に
    * 最終更新日が start 以降、作成日が end 以前という甘い設定だけど
        * 作成日が start 以前であっても、最終更新日が start 以降だったらカウント
        * 作成日が end 以前であれば、最終更新日が end 以降であろうともカウント
    * LGTM, ストックは上記でカウントする投稿に対して行われたものだけを合計
* Contribution は最終的に四捨五入してるっぽいので、四捨五入してる
    * 浮動小数点の誤差とか考えんのメンドイんで、適当
    * Python の round() は[偶数丸め](https://ja.wikipedia.org/wiki/%E7%AB%AF%E6%95%B0%E5%87%A6%E7%90%86#%E5%81%B6%E6%95%B0%E3%81%B8%E3%81%AE%E4%B8%B8%E3%82%81%EF%BC%88round_to_even%EF%BC%89)なんだよ

# 作ってみた感想（Qiita API v2 への愚痴）

作ってはみたものの、すげー重い。

ちゃんと調べてないけど、たぶん記事一覧とか持ってっくる時に、本文まで全部持ってきちゃうから。
１回のAPIでの通信量が多すぎることが怖いので、pagenation あたりの記事数もそんなに増やせない。
通信量も通信回数も多くて、全然速くならない。

たぶん Qiita API って、こういう目的では作って無くて、普段の Qiita でやることを API で済ますことが出来るように、って考えて作られたからだと思う。

なので要望（愚痴）を書き記しておく。
（いえ〜い、Qiita の中の人、見てる〜？）（見てない）

* `GET /api/v2/users/:user_id/items` と `GET /api/v2/item/:item_id` に「本文とか要らないからメタ情報だけくれ」っていうパラメータが欲しい
* `GET /api/v2/users/:user_id/items` に、`created_at` もしくは `updated_at` で絞り込みが出来るパラメータが欲しい

# まとめ

アウトプット！射幸心！
Windows PowerShell ログの取り方

##前書き
ども、こんにちは。そこいらにいるぺーぺーのインフラエンジニアです。
まあググれば、すぐ出てくるけど、ここに書置きしてても別に問題はないかなといった経緯です。

##ログ取得開始

```PowerShell:PowerShell
#[C:\work\logs\testtest.txt]はログ保存したい場所と保存したいファイル名を指定している。
Start-Transcript  C:\work\logs\testlog.txt -Append
```

##ログ取得開始【日付あり】
```PowerShell:PowerShell
#日付を定義
$time = Get-Date -Format "yyyyMMdd-HHmm"
Start-Transcript -Path  " C:\work\logs\$time.log" -Append
```


##ログ取得終了

```PowerShell:PowerShell
Stop-Transcript
```

##あとがき
おつかれさまなのだ！(๑╹ω╹๑ )
見やすい、分かりやすい方を見ればいいと思うのだ。(๑╹ω╹๑ )！！


参考

https://forsenergy.com/ja-jp/windowspowershellhelp/html/87d44e27-77bf-4152-abd7-5336b51e4755.htm


https://qiita.com/satton6987/items/e22b4d21aab850902cff
Android Studio で Alt+F* が効かないとき

KotlinでAndroid開発を勉強中の初心者です。
Android Studioは趣味でたまに触る程度ですがなかなかこの問題が解決しなかったので備忘録的に書き残します。

# 問題
AndroidStudioで一部のショートカットが機能ませんでした。
具体的につまづいた箇所は規定値 `Alt+F12` の `Terminal` を開くショートカットです。
`Alt+6` の `Problems` は動くのに `Alt+F12` は反応しない。
Google先生に頼み聞いても「オススメのショートカット」とかのページしか出てこずめちゃくちゃ困りました。
未確認ですがおそらく Android Studio のベースである **IntelliJ IDEA** も対象じゃないかなと思います。

# 結論

:::note
**GeForce Experience** が悪さしていた！
:::

原因はこいつでした。そりゃ検索しても出てこないわけですね。
どうやら GeForce Experience は `Alt+F*` 系の入力を割と上位でキャッチするようで、そもそも Android Studio 側に届いていなかったみたいです。
結果的に GeForce Experience のオーバーレイ機能を停止することで解決しました。

#GeForce Experience とは
ほとんどみなさんご存じかと思いますが一応ご説明させていただきます。
GeForce Experience は、NVIDIA GeForce 系統のグラフィックボード使っているパソコンには大抵ついてるGPUの最適化ソフトウェアです。
ドライバとかの管理や更新に必要ですが、ゲーマー向けの機能も提供してくれています。録画とかスクショとか配信とかを簡単にできます。
僕もむかしゲームしているとき、インスタントリプレイが便利でちょくちょく使っていました。ゲーム以外の時にも撮り続けているのに気づきリソース食われるのがきついのでそれ以降使っていません。ちなみにショートカットは `Alt+Z` です。

#手順
Qiitaを見るような方なら勘で済ませそうな気もするような単純作業です。

- GeForce Experience を開きます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/739387/a9319c25-3819-55b0-b70e-b30a62c8abba.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/739387/3d4b9814-b06d-7840-ffbf-64ec0f608387.png)

- オーバーレイを無効にする
右上の設定マークを押し、**ゲーム内のオーバーレイ**をオフにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/739387/d6560d0e-433c-133f-d4cb-0dd6a6c84a8f.png)

これで設定は完了です。

# ほかに試したこと
<dl>
<dt>キーボードの故障</dt>
<dd>ここでチェックできます。（ https://anysweb.co.jp/keycheck/ ）</dd>
</dl>

# あとがき
やっぱりこの類のソフトはどっかで変に干渉しちゃうなぁという感じです。
GeForce Experience は普段から使ってる人もいると思うのでユーザーとしてどっちを切るかということですね。
ちなみに Android Studio 側、GeForce Experience 側のどちらもショートカットの割り当てを変更することは可能です。
スクリプトをバッチでたたく方法

#まえがき
どもこんにちは、そこらへんにいるぺーぺーエンジニアです。
仕事の効率化でよく使うので、備忘として残そうかなという経緯です。


## スクリプト（ps1）の作成 (๑╹ω╹๑ )

```powershell:powershell

#[Cドライブ]に[work\logs]フォルダを作成する。
mkdir C:\work\logs

#{コマンド[hostname]の出力結果を[C:\work\logs]フォルダ内の[testlog.txt]ファイルに保存する。}という処理内容を[test.txt]ファイルとして新規作成、保存する。
echo "hostname >> C:\work\logs\testlog.txt" >> C:\work\test.txt

#[test.txt]を[test.ps1]に名前変更（正確にはファイル拡張子を変更）する。
mv C:\work\test.txt C:\work\test.ps1
```

## バッチ（bat）の作成 (๑╹ω╹๑ )

```powershell:powershell
#{[C:\work\test.ps1]をpowershellで実行する。]という処理内容を[testbat.txt]ファイルとして新規作成する。
echo "@echo off" ` "REM [C:\work\test.ps1]をpowershellで実行する。" ` "powershell C:\work\test.ps1" >> C:\work\testbat.txt

#[testbat.txt]ファイルをバッチ（bat）ファイルに拡張子を変更する。
mv C:\work\testbat.txt C:\work\testbat.bat
```

## バッチ（bat）のショートカットファイルの作成 (๑╹ω╹๑ )

```powershell:powershell
#以下の4行をそのまま[powershell]上にコピー&ペーストし、実行する。
$WshShell = New-Object -ComObject WScript.Shell
$ShortCut = $WshShell.CreateShortcut("C:\work\testbat.bat.lnk")
$ShortCut.TargetPath = "C:\work\testbat.bat"
$ShortCut.Save()

##上記の一部を解説するよ (๑╹ω╹๑ )
###[CreateShortcut]で指定しているパスは、作成するショートカットファイルを指している。
###[TargetPath]で指定しているパスは、ショートカットファイルを作成する元ファイルを指している。

#[C:\work\testbat.bat.lnk]が作成されていることを確認する。
ls C:\work
```

## バッチ（bat）のショートカットファイルの設定 (๑╹ω╹๑ )

```notepad:デスクトップGUI操作
1. [C:\work]フォルダにあるショートカットファイル[testbat.bat]のプロパティを開く。
2. [ショートカット]タブ内の[詳細設定]をクリックする。
3. [管理者として実行]にチェックを入れる。
4. [OK]をクリックする。
5. [適用]及び[OK]をクリックする。 
```

補足：Windows PowerShell で上記の設定ができないかどうか調査中。
何か見つかり次第、追加の方法として追記する。

## バッチ（bat）のショートカットファイルの実行！！ (๑╹ω╹๑ )

```powershell:powershell
#バッチ（bat）のショートカットファイルの実行！！ (๑╹ω╹๑ )
C:\work\testbat.bat.lnk

#[このアプリがデバイスに変更を加えることを許可しますか？]のGUI画面が表示されるので[はい]をクリックする！(๑╹ω╹๑ )

#[C:\work\logs]フォルダに[testlog.txt]ファイルが作成されていることを確認する。
ls C:\work\logs

#[testlog.txt]ファイルを開き、[hostname]の出力結果があることを確認する。
C:\work\logs\testlog.txt
```

##あとがき
おつかれさまでしたなのだ！ (๑╹ω╹๑ )
気づいたら深夜2時だと…！？(´Д⊂ヽ
手探りしながら手順を書いていたので、こちらお試しになられて手順通りにうまくいった方いましたら、コメントお願い致します。
YOLOv5をJetson Nano2G(4G)で動かして、物体を検知するから応用まで　その3

[YOLOv5をJetson Nano2G(4G)で動かして、物体を検知するから応用まで　その2]
(https://qiita.com/ShimoyamaAi/items/57a9f0b5c3996b651bce)
の続きです

今回はPyTorch　TorchVisin の導入です

###更新履歴
2021年10月　初版

##3.PyTorch導入
依存関係のインストールを行います

```
sudo apt-get install python3-pip libjpeg-dev libopenblas-dev libopenmpi-dev libomp-dev
sudo -H pip3 install future
sudo pip3 install -U --user wheel mock pillow
sudo -H pip3 install testresources
```
セットアップ用のツールの導入

```
sudo -H pip3 install --upgrade setuptools
sudo -H pip3 install Cython
```
グーグルからダウンロードします

```
sudo -H pip3 install gdown
gdown https://drive.google.com/uc?id=12UiREE6-o3BthhpjQxCKLtRg3u4ssPqb
```

インストールします

```
sudo -H pip3 install torch-1.9.0a0+gitd69c22d-cp36-cp36m-linux_aarch64.whl
rm torch-1.9.0a0+gitd69c22d-cp36-cp36m-linux_aarch64.whl
```

##4.TorchVisin導入
TorchVisin　をインストールします

```
sudo apt-get install libjpeg-dev zlib1g-dev libpython3-dev
sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev
sudo pip3 install -U pillow
```
グーグルからダウンロードしインストールします

```
gdown https://drive.google.com/uc?id=1tU6YlPjrP605j4z8PMnqwCSoP6sSC91Z
sudo -H pip3 install torchvision-0.10.0a0+300a8a4-cp36-cp36m-linux_aarch64.whl
rm torchvision-0.10.0a0+300a8a4-cp36-cp36m-linux_aarch64.whl
```


[次回、いよいよYOLOv5に取り掛かり導入を行います]
(https://qiita.com/ShimoyamaAi/items/a4846de8c72c610d541f)
【Go】Goのwebフレームワークginを使ってHello World(Part1)

# 自己紹介
Qiita初投稿なので軽く自己紹介です。
新卒から3年ぐらいはDBA周りを経験してだらだら無駄な時間を過ごしてましたが、
2年前ぐらいにjavaをメインにしたweb系の会社に転職してからようやく自己学習を始めた出遅れ感満載のエンジニアです。

# Goを勉強しようと思った背景
注目言語だからちょっと挑戦してみたかったというのもありますが、
平行処理がすごい楽と知人から聞いたのでどんなもんなんだと興味本位で勉強したいと思ったからです。
webフレームワークを使おうと思った理由としては、自身がweb系が得意としているので、主にjava(Spring)との違いが感じやすいかと思ったからです。

# 環境
<ul>
<li>Mac(M1): BigSur 11.5.2</li>
<li>Go: go1.17.2 darwin/arm64</li>
<li>エディタ: GoLand</li>
<li>DB: MySQL 8.0</li>
<li>パッケージ管理:Go Modules0</li>
</ul>


# とりあえずのHello World
ginを追加して

```
go get github.com/gin-gonic/gin
```

main.goを書いて〜

```Go:main.go
package main

import (
	"github.com/gin-gonic/gin"
	"work-study-go/web/route"
)

func main() {
	engine:= gin.Default()
	// route.goのDefineRoutesを呼び出す
	route.DefineRoutes(engine)
	// ここでポートを指定する。
	engine.Run(":3000")
}
```

ルーティングのコード書いて〜
※個人的にルーティングの定義は分けたかったので分けています。

```Go:route.go
package route

import (
	"github.com/gin-gonic/gin"
	"net/http"
)

func DefineRoutes(r gin.IRouter) {
	r.GET("/", func(ctx *gin.Context){
		// HTTPステータス200,レスポンスのdataに"Hello World"を返却
		ctx.JSONP(http.StatusOK,gin.H{
			"message": "ok",
			"data": "Hello World",
		})
	})
}

```


<b>実行してみる<b>

```
go run main.go
```

Curlで叩いてみる。

```
curl http://localhost:3000/
```

route.goに定義したレスポンスの内容が返却されてますね。

```
 % curl http://localhost:3000/
{"data":"Hello World","message":"ok"}
```

# まとめ
初めてSpringを触った時はHello Worldを表示するだけでもちょっと詰まったのですが、
意外と特に詰まることなく簡単に実装できました。
※HTMLも全然わかってないのにいきなりThymeleafを使ったからですが。。。
まだ勉強中なので至らない点が多々ありますが、これを基にしてwebアプリを作っていきたいと思います。
その過程でまた投稿していくので、これからGoを勉強していく方に少しでも参考になればと思います。
ProRes vs DNxHR vs GoPro CineForm vs Grass Valley 比較

## はじめに

Notionページの方が情報が多くまとまっているので、Qiita版よりそちらを見ることをおすすめします。

Notionページ：[ProRes vs DNxHR vs GoPro CineForm vs Grass Valley 比較](https://kdrs.notion.site/ProRes-vs-DNxHR-vs-GoPro-CineForm-vs-Grass-Valley-e444e10bd3a54c6bbe61f2c41319e7cf)

## ビットレート比較

動画A、Bそれぞれを1920×1080にリサイズして書き出し。

ビットレートの詳細情報をMediaInfo(ソフトウェア)と、`ffmpeg -i <inputfile>`コマンドで確認。

大まかにビットレートが近ければ、代用になると考えて良いでしょう。定性的な見た目の比較まではやってません。

### 動画A

[動画A.mp4](https://s3.us-west-2.amazonaws.com/secure.notion-static.com/0e7f5163-4262-4818-8d5b-29e53f52e864/%E5%8B%95%E7%94%BBA.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAT73L2G45O3KS52Y5%2F20211009%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20211009T153635Z&X-Amz-Expires=86400&X-Amz-Signature=6cf7dd6845b9c60f5092b9cc7b00d315bde9741bab9c22b8f73a4536c4cc6c60&X-Amz-SignedHeaders=host&response-content-disposition=filename%20%3D%22%25E5%258B%2595%25E7%2594%25BBA.mp4%22)

- ProRes 422：97.2 Mbps
    
- ProRes 422 HQ：185 Mbps
    
- DNxHR HQ：43.9 Mbps
    
- DNxHR HQX 10-bit：134 Mbps
    
- DNxHR HQX 12-bit：130 Mbps
    
- GoPro CineForm YUV 10-bit 品質=高：61.6 Mbps
    
- GoPro CineForm YUV 10-bit 品質=最高：117 Mbps
    
- Grass Valley HQ Q=4 M=100：78.4 Mbps
    
- Grass Valley HQX Q=0 M=100：108 Mbps

### 動画B

[動画B.mp4](https://www.notion.so/signed/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Ffe7bb469-cf2f-4a45-8c93-2ca3a5621cb4%2F%E5%8B%95%E7%94%BBB.mp4?table=block&id=67bb3040-2701-4fbd-a42b-c8f2cee06bb9&spaceId=43809b80-6fbe-492b-a2a1-552a3b79f3e6&name=%E5%8B%95%E7%94%BBB.mp4&userId=061813e9-db94-4b86-a723-6691f5cc528c&cache=v2)

- ProRes 422：139 Mbps
    
- ProRes 422 HQ：215 Mbps
    
- DNxHR HQ：115 Mbps
    
- DNxHR HQX 10-bit：220 Mbps
    
- DNxHR HQX 12-bit：220 Mbps
    
- GoPro CineForm YUV 10-bit 品質=高：116 Mbps
    
- GoPro CineForm YUV 10-bit 品質=最高：231 Mbps
    
- Grass Valley HQ Q=4 M=100：120 Mbps
    
- Grass Valley HQX Q=0 M=100：199 Mbps

## 考察

- ProRes 422に近いのはGoPro CineForm YUV 10-bit 品質=高
- ProRes 422 HQに近いのはDNxHR HQX 10-bit(及び12-bit)

## ダウンロード

以下からできます。品質を目視で確認したいときに。

[コーデック比較 - Google Drive](https://drive.google.com/drive/folders/1nVvLMz2N6Tc7VzowAq6MgnjrVxGXsxZQ?usp=sharing)

## 補足

### ビットレートモード

DNxHR系はDavinci ResolveではVBR(可変ビットレート)を指定できるので、全てそちらを指定しています。Adobe系のエンコーダはCFR(固定ビットレート)しか指定できません。

### アルファの書き出し

上記の中で、DNxHR系とGrass Valley系はアルファの書き出しが出来ます(DNxHR HQX 10-bitを除く)。

### コーデックの参考元

- Apple ProRes
    - [Apple_ProRes_June_2014_loc_ja_JP.pdf](https://www.apple.com/support/assets/docs/products/finalcutpro/Apple_ProRes_June_2014_loc_ja_JP.pdf)
- [D](https://en.wikipedia.org/wiki/DNxHR_codec)NxHR
    - [DNxHRコーデック-ウィキペディア](https://en.wikipedia.org/wiki/DNxHR_codec)
- GoPro CineForm
    - [CineForm - Wikipedia](https://en.wikipedia.org/wiki/CineForm)
    - コーデック配布場所（ソフトに付属）：[GoPro STUDIO（スタジオ）2.5　｜GoPro(ゴープロ)日本総代理店タジマモーターコーポレーション](https://www.tajima-motor.com/gopro/goprostudio/index.html)
- Grass Valley
    - [WHITE PAPER -HQXの紹介- - HQX_Whitepaper_J.pdf](https://pro.grassvalley.jp/catalog/edius/pdf/HQX_Whitepaper_J.pdf)
    - コーデック配布場所：[ダウンロード Grass Valley Codec Option(無償版)](https://pro.grassvalley.jp/download/gv_codec_option.htm)
ReactのRefをTypeSafeに独自実装する際のまとめ

タイプセーフにReactのRefを独自実装する際、毎回忘れて調べなおしているので覚書

```tsx
import { forwardRef, ForwardRefRenderFunction, useImperativeHandle } from 'react';

export interface HogeElement {
  bar: string;
  buzz: () => void;
}

export interface HogeProps {
  bizz: string;
}

const HogeRefFunction: ForwardRefRenderFunction<HogeElement, HogeProps> = ({
  bizz,
}, ref)=> {
  useImperativeHandle(ref, () => {
    return {
      bar: '参照等',
      buzz: () => {
        // 処理群
      }
    }
  })
  return <div>{bizz}</div>;
}
export const Hoge = forwardRef(HogeRefFunction);
```

### 各種命名規則
- HTMLライクにするため、文末にElementを記述 `HogeElement`
    - HTMLDivElement的な勢い
- Propsを文末に記述

#### 備考
RefFunctionとコンポーネントを命名しておき、無名化を防ぐ
最終的に型は求まるため、forwardRefでwrapすれば完成
エクサウィザーズプログラミングコンテスト2021(AtCoder Beginner Contest 222) 参戦記

# エクサウィザーズプログラミングコンテスト2021(AtCoder Beginner Contest 222) 参戦記

## [ABC222A - Four Digits](https://atcoder.jp/contests/abc222/tasks/abc222_a)

1分で突破. 書くだけ.

```python
N = int(input())

print('%04d' % N)
```

## [ABC222B - Failing Grade](https://atcoder.jp/contests/abc222/tasks/abc222_b)

2分で突破. 書くだけ.

```python
N, P, *a = map(int, open(0).read().split())

print(len([a for x in a if x < P]))
```

## [ABC222C - Swiss-System Tournament](https://atcoder.jp/contests/abc222/tasks/abc222_c)

16分半で突破. 素直にシミュレーションすればいいのだけど、それがそれなりに大変だという. 勝数は大きいほど上位で、番号は小さいほど上位と逆なので、勝数をマイナスにして処理した.

```python
N, M = map(int, input().split())
A = [input() for _ in range(2 * N)]

a = [(0, i) for i in range(2 * N)]
for i in range(M):
    t = []
    for j in range(N):
        c, d = a[j * 2]
        e, f = a[j * 2 + 1]
        c, e = -c, -e
        x = A[d][i]
        y = A[f][i]
        if x == y:
            t.append((-c, d))
            t.append((-e, f))
        elif (x == 'G' and y == 'C') or (x == 'C' and y == 'P') or (x == 'P' and y == 'G'):
            t.append((-(c + 1), d))
            t.append((-e, f))
        else:
            t.append((-c, d))
            t.append((-(e + 1), f))
    a = sorted(t)
print(*(i + 1 for _, i in a), sep='\n')
```

## [ABC222D - Online games](https://atcoder.jp/contests/abc222/tasks/abc222_d)

22分半で突破、TLE1. TLEするよねーと言いながら流してる辺りがダメ(笑). ナイーブに書くと *O*(*NM*<sup>2</sup>) なので見るからに駄目なのだが、毎回 imos すれば *O*(*NM*) ですんだ.

```python
from itertools import accumulate

m = 998244353

N = int(input())

a = list(map(int, input().split()))
b = list(map(int, input().split()))

dp = [0] * 3002
for i in range(a[0], b[0] + 1):
    dp[i] = 1

for i in range(1, N):
    t = [0] * 3002
    for j in range(a[i - 1], b[i - 1] + 1):
        t[max(j, a[i])] += dp[j]
        t[b[i] + 1] -= dp[j]
    dp = list(accumulate(x % m for x in t))
print(sum(dp) % m)
```