OmniAICreator/Qiita-1.07M huggingface dataset:
#Scratch 3.0 のキー入力イベントをブラウザのコンソール（開発者ツール）の JavaScript からランダムに繰り返し発生させてみる

今回の内容は、以下のツイートの動画に出てくるような仕組みなどを実現できるものです。

https://twitter.com/youtoy/status/1521303536239525889

ブラウザの操作をページ外部から自動で行う仕組みは「[Microsoftさんの Playwright](https://github.com/microsoft/playwright)」や「[Googleさんの Puppeteer](https://github.com/puppeteer/puppeteer)」などがあります。
今回は、そういったものを使うまでもない簡単なキー入力の処理を、ページ外のプログラムから実行するという方向の話です。

## 仕組みの概要
今回の仕組みは、開発者ツールのコンソールから JavaScript のプログラムを実行する構成になっています。冒頭の動画での処理は、Chrome の開発者ツールのコンソールを開き、そこにこの後に掲載している JavaScript のプログラムを貼り付けて実行することで実現しています。

## 実行するプログラム
### Scratch
冒頭の動画上でも出ていますが、Scratch の音を鳴らすメインの処理は以下となります。
![Scratchのプログラム](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/236a6217-6132-bbb2-c67e-611fad809227.png)

### JavaScript
開発者ツールのコンソールで実行したプログラムは以下の通りです。即時実行関数で処理しています。また、キーのイベントは上と左右の矢印キーの 3つを用いていて、それを 1秒ごとにランダムに実行しています。

```javascript
(function loop() {
  const events = [
    new KeyboardEvent("keydown", { key: "ArrowRight" }),
    new KeyboardEvent("keydown", { key: "ArrowLeft" }),
    new KeyboardEvent("keydown", { key: "ArrowUp" }),
  ];
  const keydownArrow = document.dispatchEvent(
    events[Math.floor(Math.random() * events.length)]
  );

  setTimeout(function () {
    keydownArrow;
    loop();
  }, 1000);
})();
```

これで冒頭に掲載していた動画のように、JavaScript のプログラムから Scratch上でのキーイベントを発生させることができます。処理の停止はブラウザのページのリロードや、ページを閉じたりすることで対応できます。

#### キー入力 1回分の処理を実行
キー入力に関するシンプルな動作確認のみを行う際には、以下の短いプログラムを使うのが便利です。1回だけキーを押すイベントを発生させるという内容です。

```javascript
document.dispatchEvent(new KeyboardEvent("keydown", { key: "ArrowUp" }));
```

#### 繰り返し処理の簡単なテスト
こちらも動作確認用です。以下は `setTimeout` を使った繰り返し処理の動作テストに使ったものです。コンソールに1秒ごとに「test」という文字列が出力される処理になります。

```javascript
(function loop() {
  setTimeout(function () {
    console.log("test");
    loop();
  }, 1000);
})();
```

## 参考情報
以下のリストは、今回の内容に関連する情報が掲載されたページをまとめたものです。

- [KeyboardEvent - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/KeyboardEvent)
- [KeyboardEvent.key - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/KeyboardEvent/key)
- [EventTarget.dispatchEvent() - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/EventTarget/dispatchEvent)
- [カスタムイベントのディスパッチ](https://ja.javascript.info/dispatch-events)
- [setInterval() - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/setInterval)
- [任意の Web ページで JavaScript のスニペットを実行する - Microsoft Edge Development | Microsoft Docs](https://docs.microsoft.com/ja-jp/microsoft-edge/devtools-guide-chromium/javascript/snippets)
- [Run Snippets of JavaScript - Chrome Developers](https://developer.chrome.com/docs/devtools/javascript/snippets/)
- [JavaScript でキーボード入力を代行させる / JavaScript | PersonWriter's Room](https://ameblo.jp/personwritep/entry-12456996738.html)
- [IIFE (即時実行関数式) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN](https://developer.mozilla.org/ja/docs/Glossary/IIFE)
都道府県の型を例にGoで組み込み型を拡張する


ユーザーの都道府県を扱うアプリケーションを作成していたときに、

いままで
``` prefecture.go
const (
	PrefectureHokkaido   = "hokkaido"
	PrefectureAomori     = "aomori"
    :
)
```

というような県の定数をstring で宣言していていた。
この場合はUIに返すときには日本語に変換する必要があり愚直にmapを定義して変換していた。

``` prefecture.go
var prefectureToJpName = map[string]string{
	"hokkaido":  "北海道",
	"aomori":    "青森県",
	"iwate":     "岩手県",
    :
}
```

致命的な問題はなかったのだが、

- コードの量が増える
- 関連のあるものなのにコードが散らばってしまう

などの課題があった。

# 組み込み型として扱う

``` prefecture.go
type Prefecture string 

const (
	Hokkaido Prefecture  = "hokkaido"
	Aomori   Prefecture  = "aomori"
    :
)
```
上記のように型定義を行うことで一見変わらないように見えるが、組み込み関数を定義することができる。

つまり、いままでmap型で独立して存在していた日本語変換が
``` prefecture.go
func (p Prefecture) ToJapanese() string {
  switch s {
    case Hokkaido:
        return "北海道"
    case Aomori:
        return "青森"
　　　　　　　       :
  }
}
```

というように拡張することができる。
Prefecture自体の実体はstring だが、ToJapanese という日本語変換の組み込み関数を持つ型になっている。

さらにこのように型を定義することによってさらに拡張ができるようになる。
例えば、県から県の所在グループを取得したいとなったときに、

``` prefecture.go
      :
type PrefectureGroup

const (
  Hokkaido PrefectureGroup = "hokkaido"
  Tohoku PrefectureGroup = "tohoku"
  Kanto PrefectureGroup = "kanto"
      :
)

func (p Prefecture) GetGroup() PrefectureGroup {
  switch p {
    case Hokkaido:
        return "hokkaido"
    case Aomori, Iwate, Miyagi, Akita, Yamagata, Fukushima:
        return "tohoku"
　　　　　　　        :
  }
}
```

というように拡張することができる。
PrefectureGroupも同様にToJpanaese などと拡張することもできる。

このように型として定義し、組み込み型で拡張することで
課題であった

- コードの量が増える
- 関連のあるものなのにコードが散らばってしまう

を解決でき、アプリケーションコードの見通しが良くなる。
なにより良いところはこのようなコードの書き方がより **Goらしい** ということだ。（Goらしいことでなにが嬉しいかというのは参考にもある実用Goにかかれています。）

## 補足

実際にプロダクトで都道府県を扱うとなると、
構造体として日本語なども格納しておくとより楽に扱えて良い。
https://github.com/diverse-inc/jp_prefecture
このリポジトリのように実装するのがベストに近い気がする。

## 参考

このtips は[実用 Go言語 ―システム開発の現場で知っておきたいアドバイス](https://amzn.to/3F7tVj5) 2.2.1 「メソッドを追加して組み込み型を拡張する」を参考に自分の体験を踏まえて書きました。
【Rails】Aws::S3::Errors::RequestTimeTooSkewed　への対処

## S3へのリクエストタイムが違いシードが流せない
Railsの本番環境でシードデータを入れる時に、
S3とのtimeがかけ離れているというニュアンスのメッセージが出現した。

```
[sirius@ip-10-0-11-191 diary_app]$ rails db:seed RAILS_ENV=production
Start inserting first seed "user" ...
rails aborted!
Aws::S3::Errors::RequestTimeTooSkewed: The difference between the request time and the current time is too large.
```
EC2インスタンス上では`JST`(日本標準時)を指定しているので、`date`でそれ確かめてみると、たしかに、実際の時間が10:00なのにインスタンス40分近くずれていることがわかった。

これがシードデータを流すときに、S3バケットにアクセスした際に時間差がおおきすぎるのでエラーが生じたのだろう。

```
[sirius@ip-10-0-11-191 diary_app]$ date
2022年  5月  3日 火曜日 10:45:36 JST
```
おそらくサーバーが一定の時間停止していたことが原因でズレたと推測するが、どのタイミングでずれたのか調査中である。

## 解決策(サーバー再起動)
解決策はとても簡単で、EC2サーバーを立ち上げ直せばうまくいく。
AWSダッシュボードより、EC2インスタンスを`停止`してから⇨`開始`して起動し直す。
![スクリーンショット 2022-05-03 10.46.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954882/d65a1f32-b009-d509-6c1b-2dc21cc97141.png)

そうしてEC2上で
```
[sirius@ip-10-0-11-191 diary_app]$ date
2022年  5月  3日 火曜日 10:10:00 JST
```
とすると40分先に進んでいた時刻が戻っていることがわかる。

これで`rails db:seed RAILS_ENV=production`とするとうまくいった。

#### 参考ページ
・[Rails の S3 連携で Internal Server Error となる](https://curecode.jp/tech/rails-aws-s3-time-error/)
Laravelのタイムゾーンを日本時間に変更する

# ”UTC”から”Asia/Tokyo”に変更

LaravelのタイムゾーンはデフォルトでUTCになっているため、ログに残る時間やcreated_atが日本時間より9時間遅れた時間が記録されてしまう。
`config/app.php`ファイルの記述を変更すればよい

## 変更前

```config/app.php
'timezone' => 'UTC',
```

```
$ php artisan tinker
>>> echo Carbon\Carbon::now();
2022-05-03 01:40:21⏎
```

## 変更前

```config/app.php
'timezone' => 'Asia/Tokyo',
```

### キャッシュクリア
```
$ php artisan config:clear
```
### 確認

```
$ php artisan tinker
>>> echo Carbon\Carbon::now();
2022-05-03 10:40:49⏎
```
コンピュータシステムの理論と実装をやりました

表題のとおりです。  
無事やりきったので、振り返りつつ感想文を書いてみたいと思います。

プロジェクトを実施した際のリポジトリはこちらです。
https://github.com/r-mutax/nand2tetris

# 本の紹介
NANDの組み合わせから論理回路を組み上げミニマムなCPU（ハードウェア）を作り、作成したCPUのアーキテクチャで動くアセンブラ、バーチャルマシン、コンパイラまでを作り上げて、簡単なゲームを作成しよう！といった趣旨の本です。  
NANDから最後にはテトリスを作ろう！という意味が込められたnand2tetrisというプロジェクトを進めていきます。  
プロジェクトにテトリスとついていますが、通常通りプロジェクトを進めていって最後にできるのはピンポンゲームなので、テトリスを作りたい場合は自分で作る必要があります。
https://www.oreilly.co.jp/books/9784873117126/

# なぜ読もうと思ったか？
[低レイヤを知りたい人のためのCコンパイラ作成入門](https://www.sigbus.info/compilerbook)に挑戦していたんですが、コンパイラ作成にだんだん詰まってきたので、気分転換＆もっと低いレイヤの勉強を使用ということでやってみました。

# 感想
大体5ヶ月位やっていました。
平日は業務プログラミングで疲弊していたので、基本休日にやっていましたが、やらない週もありました。
# よかったところ
論理回路から組み上げて、コンパイラまで行くのでコンピュータを動かす仕組みを一通り体験できて非常に面白かったです。  
一個一個の階層では、その階層の仕組のみに注力できて、作業がしやすかったです。
最終的に複雑なソフトがきちんと動くのを見るのは不思議な感覚です。

## むずかしかったところ
本書で使用しているHDL言語の書き方について悩みました。
とはいえ、nand2tetrisをやっている人は世界中にいて、適当に検索すればGithubなりStackOverflowなり出てくるのでそこまで困りません。

# 振り返り
簡単に振り返ってみます。
## 第1章 ~ 第5章 ハードウェア編
1章から5章ではハードウェア側の実装をします。
NAND素子から初めて、NOT/AND/ORを作り、ALUを作り、順序回路を作り、CPUまで作っていきます。
プロジェクトの名前はnand2tetrisで、ハードウェアのプリミティブな構成要素はnandだけのような名前になっていますが、実際はD-フリップフロップ（DFF）も使います。
シミュレータ上ではありますが、メモリと演算装置を備えたCPUを動かすところまで組み上げます。

## 第6章 アセンブラ
第1章 ~ 第5章で作成したCPUを動作させるためのHackというアセンブリ言語を読み込んで、機械語を吐き出すアセンブラを作り上げます。
6章以降はソフトウェア編になるのですが、プロジェクトの課題は任意のプログラム言語を使用することができます。
本書の課題ソースとして、入力用テキストが用意されているので、テキストファイル（6章の場合はアセンブリ）を読み取って、要求された出力ができたら成功です。
機械語の出力はバイナリではなくて0,1だけのテキストファイルでよいので、デバッグも難しくないです。

## 第7章 ~ 第8章 バーチャルマシン
Hackアセンブリ ~ 高級言語の間としてスタックマシンとして動作するバーチャルマシン（VM）言語を作成します。
VM → アセンブリへの変換ソフトを作成します。
間にVMを挟むことで、様々なプログラム言語のコンパイラを作る際に、VMへの変換をかませるようにしたら、アセンブラを使い回すことができます。
正直Hackのアセンブリはすごい組みにくいので、VMがあると開発がかなり楽になると思います。
HackのCPUはレジスタが実質2個しかないので、アセンブリを組むのにかなり苦労しました。

## 第9章 高水準言語
本書で使用するJack言語の紹介の章。
JackはJavaライクでクラスも配列もあります。ちょっとビビりますが、10章以降にこのプログラム言語のコンパイラを作ります。
正直、Jackのスキルを身に着けたいわけではなかったので、9章は全体に目を通して課題を飛ばしました。

## 第10章 ~ 第11章 コンパイラ
字句解析 ~ 構文解析 ~ VM言語への変換を行うコンパイラを作ります。
構文木のような構造のアウトプットをXML形式で出力することで、WEBブラウザなどで簡単に中身を確認できるというのは、目からウロコでした。
構文解析がうまくできれば、VMコードの出力はそこまで難しくなかったです。
11章のプロジェクトをクリアして、用意されたJackプログラムのコンパイルができるようになると、簡単なピンポンゲームがプレイできるようになります。

## 第12章 OS
他の方の記事でも言及されていますが、12章で作成するのはOSというよりも標準ライブラリのようなイメージが近いです。
Jack言語での実装をするので、紹介されているアルゴリズムを見て実装は見送りました。

## 第13章 さらに先へ
全体を通して、HackアーキテクチャとJack言語の今後の展望（追加で実施できる改良のアイデア）をいくつか説明してくれます。

# おわり
全体を通して、かなりの低いレイヤから体験できるので、かなり自信がつきました。
一個一個の階層は想像以上にシンプルなのに、組み合わせて動かすと非常に複雑なプログラムもすんなり動いてしまうので、手品か何かのように感じて面白かったです。
書籍「Pytorch&深層学習プログラミング」6章補足 決定境界表示プログラムの解説

# はじめに
書籍「Pytorch&深層学習プログラミング」の著者です。

[Amazonリンク](https://www.amazon.co.jp/dp/4296110322)
[サポートサイトリンク](https://github.com/makaishi2/pytorch_book_info/blob/main/README.md)

6章p.227-p.228では、学習データの散布図と、学習の結果得られたロジスティック回帰モデルを基にした決定境界のグラフを重ね描きしています。

<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206130/5883cd7f-7f34-eb80-4fa9-c89ee6664995.png' width=500>


しかし、このプログラムの解説は省略しています。決定境界のグラフは説明変数が2個の時しか描画することができませんが、実際の分類問題で説明変数が2個しかないことはまずありません。つまり、決定境界グラフは、実用の観点であまり意味がないです。しかし、グラフを見ることがロジスティック回帰の動作イメージを持つにはとても適しているという理由で、このように可視化の結果のみ示す形にしています。
とはいえ、なぜこのプログラムで決定境界が表示できるのか知りたいという質問は何度か受けているので、その質問に答えるための解説記事をアップしました。

# 数学的な説明
そもそも「決定境界とはなにか」を、書籍p.209の図6-7を使って説明します。

<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206130/813964ef-94e7-f6ba-a930-2b1248c8c9d6.jpeg' width=500>

上の図で**nn.Linear**とは、説明変数$x_1$と$x_2$を入力とする1次関数です。
その出力$u$にシグモイド関数$f(u)$をかけた結果が、予測値ypであり、ypの値が0.5より大きいかどうかで、予測結果が1か0かを判断するのが、ロジスティック回帰の処理方式でした。
シグモイド関数のグラフを見ればわかるとおり、「**シグモイド関数の結果が0.5より大きいかどうか**」は入力段階の$u$の言葉で言い換えると「**uが正か負か**」という話と同じです。
つまり、「**nn.Linearの結果がちょうどゼロになる点の集合**」が、今求めたい決定境界を満たす値の条件ということになります。更に今回は、決定境界はモデルの構造から直線であることがわかっています。

ちなみに、同じ二値分類モデルでも、サポートベクターマシンや、ディープラーニングモデルなどの場合、決定境界は直線にはなりません。その場合、決定境界の描画方法は今回と比較してはるかに複雑になります。著者の別書籍「Pythonで儲かるAIをつくる」の解説用に書いた、下記の記事がその場合の方法を説明したものとなります。
[アルゴリズムが一目でわかる！ Pythonによる決定境界表示](https://qiita.com/makaishi2/items/2d0dd015ac1cbd86dd3f)

話が脱線しましたが、今回は目的が直線であることがわかっているので、「**nn.Linearの結果がちょうどゼロになる点**」　を2つ見つけて、その点を直線で結べばそれが求める決定境界の直線ということになります。

この条件を数式で表現してみましょう。変数$x_1$の重みを$w_1$、変数$x_2$の重みを$w_2$、バイアスを$b$で表します。
すると、線形関数の出力$u$は、次の式で表されます。

$u = w_1 x_1 + w_2 x_2 + b$

決定境界上の点ではこの値がゼロなので

$0 = w_1 x_1 + w_2 x_2 + b$

$w_2$がゼロでないという前提を付けた上で、この式を$x_2$について解くと次の結果になります。

$x_2 = -\dfrac{w_1 x_1 + b}{w_2}$

# プログラム実装

この数式が、線形関数の属性によってどう表されるかを考えます。まず、線形関数内の2つの変数weightとbiasを操作しやすいように、外部変数に代入します。

```py
# パラメータの取得
bias = net.l1.bias.data.numpy()
weight = net.l1.weight.data.numpy()
```

すると、上の数式の$b$が、変数``bias``になります。
また、$w_1$が``weight[0,0]`` に、$w_2$が``weight[0,1]``になります。

そこで、上の数式を用いて、「ある$x_1$の座標値を入力に該当する決定境界上の$x_2$の座標値を求める関数」を``decision(x)``とすると、この関数は次の形で実装されることになります。

```py
# 決定境界描画用 x1の値から x2の値を計算する
def decision(x):
    return(-(bias + weight[0,0] * x)/ weight[0,1])
```

最初に描画領域の$x_1$の最小値、最大値を求め、今定義した関数を使って対応する$x_2$の値を求める実装は次のようになります。 
ここでは今までの説明と違い、変数名を$x_1$→　$x$、$x_2$→$y$に変えている点に注意して下さい。

```py
# 散布図のx1の最小値と最大値
xl = np.array([x_test[:,0].min(), x_test[:,0].max()])
yl = decision(xl)

# 結果確認
print(f'xl = {xl}  yl = {yl}')
```
ここで得られた　``xl``と``yl``を使い、以下のコードにより、決定境界の直線は表示できることになります。

```py
# 決定境界直線
plt.plot(xl, yl, c='b')
```

以上が、6.10節の実装コードのうち、書籍で説明していない部分の解説となります。
webサーバとアプリケーションサーバの違い

## WEBサーバとアプリケーションサーバの違い
今までわかった振りをしてきましたが、基礎から学び直す機会がありましたので、知識定着のためにまとめておきます。

### WEBサーバとは
クライアントからのHTTPリクエストを受け取り、アプリケーションサーバーの処理が必要なリクエストは、アプリケーションサーバに転送する。
静的なコンテンツ（HTMLや画像）であれば、WEBサーバがレスポンスを返す。
「Apache HTTP Server」や「NGINX」などがある。


### アプリケーションサーバとは
APサーバと略されることもある。Tomcat(Java)、(Apache(PHP)、)Unicorn(Ruby)などがある。
（PHPの場合は、ApcheがWEBサーバがAPサーバも兼ねている）
単体で使用されることはなく、WEBサーバから転送されたリクエストを、RubyやPHPなどのプログラムにより処理をして、レスポンスをWEBサーバに返す。

### 参考にしたサイト、書籍
https://anken-hyouban.com/blog/2020/01/12/application-server/
https://gihyo.jp/book/2010/978-4-7741-4235-7
インターネットブレイクアウトに関して

## 概要
かんたんに言うと、ルーターやファイアーウォールの負荷を下げるため、安心のあるサービス（office,zoom1、、）だけインターネットに直接つなぐというもの

## サービスの識別方法
①宛先IPアドレスで識別する
②HTTPのヘッダ情報や証明書のコモンネーム、SNIで識別する
GitLab でファイルを編集する

GitLab ファイルを編集する方法です。
オウナーでなければ、招待を受けてプロジェクトのメンバーになる必要があります。

ここでは、オウナーか、メンバーがファイルをオンラインで編集する方法を紹介します。

まず、編集するファイルを表示します。
![gitlab01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/50f0bea4-c265-46fe-5030-6fc54d65f98e.png)

Open in Web IDE となっていたら、Edit に変更します。
>右下矢印をクリックして変更します。
![gitlab02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/4af81a33-706b-db7a-22ec-3cff9bd0322e.png)

Edit をクリックします。
>Edit file　と表示され、編集モードに入っていることが分かります。
![gitlab03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/3d254c2f-f6f2-6aa7-c8fb-d3ac09636030.png)

一行、挿入します。
>この例では、
>▼ucd コメントの追加 その5 May/3/2022
>と挿入しました。
![gitlab04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/5efe7cdb-fc8d-e8ec-60f5-4536b3e6d691.png)

左下の Commit Changes をクリックしました。
![gitlab05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/8b83054d-fa87-d50d-735b-5bcabdc0e708.png)

編集結果が反映され、表示モードになります。
![gitlab06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/6c2563db-f418-32d6-1dc4-3983a60bcac8.png)
VSCodeでタグやコメントの色・スタイルをカスタマイズする

## はじめに
VSCodeでは配色テーマが数多く存在し、デフォルトにインストールされているもの or マーケットプレイスからインストールしたものを自由に設定することができる。

自由であるがゆえに配色難民になることもあり、私自身「One Dark Pro」「Night Owl」「Monokai Pro」「Black Ocean」など転々としてきた。
そんな私も現在はデフォルトでインストールされている「**Dark+**」とちょっとした配色のカスタマイズに落ち着いている。

「このテーマ好きなんだけど、このタグの色気になるんだよなあ」と悶々としている方には良い解決策になるかと思います。

## コメントの色を変更する
Dark+ではコメントアウトはデフォルトでは緑ぽい色になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2649099/a31dc12a-e787-957a-d67d-e65d29cd4691.png)

このままでも良いとは思うのですが、ちょっと目立ち過ぎていて気になるのでグレーぽい色に変更します。

### setting.jsonを開く
VSCodeを開いたら、コマンドパレットを開きます。
（Windows/Linux:ctrl + Shift + P  Mac:command + Shift + P）

「setting」と入力すると「Preferences Open Settings(JSON)」が候補に出るので選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2649099/064234af-08d8-df88-24d1-7b08cb39cc38.png)

すると、setting.jsonファイルが開かれます。

### コメントの設定を記述する

1つ目の中括弧内最終行に以下を記述します。


```json
"editor.tokenColorCustomizations": {
    "comments":{
        "foreground":"#7e7e7e",
        "fontStyle": "italic"
    },
```

setting.jsonを保存すると、コメントの色とstyleが変わりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2649099/01c6e935-0a56-2c24-af02-580975ba1c8d.png)

ちなみにfontstyleをboldとすると太字になります。

## 特定のタグの色を変更する

例えばHTMLにPHPを埋め込んだコードの場合、Dark+ではHTMLタグとPHPの開始・終了タグが同じ色になってしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2649099/9c171fec-bff1-6325-aeb0-e8d306f06d8b.png)

これがなかなか辛いので、PHP開始・終了タグの色を変更します。

### タグの名称確認

先ほど設定した「editor.tokenColorCustomizations」カッコ内に書いていくのですが、その前にPHPタグの名称を確認します。

コマンドパレットを開き「inspect editor」と入力すると「Inspect Editor Tokens and Scopes」が候補に出るので選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2649099/600f3933-4629-9316-f1fc-ae3586534cec.png)

タグにカーソルを合わせると情報が出るので、foregroundの下記赤線部分をコピーします。

「<?php」と「?>」で名称が異なるので、それぞれコピーします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2649099/6986b4be-fa92-47f2-3417-71e2f46169ea.png)

### setting.jsonに記述
再度setting.jsonを開き、「textMateRules」内に設定を以下のように記述します。
```json
"editor.tokenColorCustomizations": {
    "comments":{
        "foreground":"#7e7e7e",
        "fontStyle": "italic"
    },
    "textMateRules": [
      {
        "scope":[
          "punctuation.section.embedded.begin.php"
        ],
        "settings": {
          "foreground": "#ff8000",
          "fontStyle": "italic"
        }
      },
      {
        "scope":[
          "punctuation.section.embedded.end.php"
        ],
        "settings": {
          "foreground": "#ff8000",
          "fontStyle": "italic"
        }
      }
    ]
  }
```

setting.jsonを保存するとPHPの開始・終了タグの色が変わりました。
かなり見やすくなりました。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2649099/15f9e9c7-34db-acda-42dd-6be83389ba07.png)


是非お試しくださいませ！
rbenvインストールで詰まったこと

[こちら](https://qiita.com/hujuu/items/3d600f2b2384c145ad12)の記事を参考にrbenvをインストールしようとしました。
（rubyインストールは[こちら](https://www.sejuku.net/blog/3958)を参考）

Homebrewがインストールされている状態でmacのターミナルで下記を実行しました。

```
$ brew update
```

すると、次のようなエラーが出ました。

```
Error: 
  homebrew-core is a shallow clone.
To `brew update`, first run:
  git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow
This command may take a few minutes to run due to the large size of the repository.
This restriction has been made on GitHub's request because updating shallow
clones is an extremely expensive operation due to the tree layout and traffic of
Homebrew/homebrew-core and Homebrew/homebrew-cask. We don't do this for you
automatically to avoid repeatedly performing an expensive unshallow operation in
CI systems (which should instead be fixed to not use shallow clones). Sorry for
the inconvenience!
```


`brew update`を実行するには、最初に(first run)、次のコマンドを実行する必要があるようです。
```
  git -C / usr / local / Homebrew / Library / Taps / homebrew / homebrew-core fetch --unshallow
```

実行してみた結果

```
git: 'usr' is not a git command. See 'git --help'.

The most similar command is
	push
```

うまくいきませんでした。

`usr`がおかしいとのことですが、これはコマンドではありません。どうやらスペースが入ってしまったことが原因のようです。

次はこれを実行
```
git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow
```

これでとりあえずうまくいったようです。

改めて

```
brew install rbenv
```

またエラーが出ました。
今度は

```
Error: Can't create vendor-install-ruby lock in /usr/local/var/homebrew/locks!
Fix permissions by running:
  sudo chown -R $(whoami) /usr/local/var/homebrew
Error: Failed to install Homebrew Portable Ruby (and your system version is too old)!
```
と出ており、権限を修正しろ、と出ます。言われた通り、次を実行。

```
sudo chown -R $(whoami) /usr/local/var/homebrew
```

その後、改めて

```
brew install rbenv
```

rbenvのインストールは進んだのですが、最後の最後で

```
Error: The following directories are not writable by your user:
/usr/local/share/zsh
/usr/local/share/zsh/site-functions

You should change the ownership of these directories to your user.
  sudo chown -R $(whoami) /usr/local/share/zsh /usr/local/share/zsh/site-functions

And make sure that your user has write permission.
  chmod u+w /usr/local/share/zsh /usr/local/share/zsh/site-functions
```

まだ権限が足りないようです。

以下の２つを実行しました。

```
sudo chown -R $(whoami) /usr/local/share/zsh /usr/local/share/zsh/site-functions

chmod u+w /usr/local/share/zsh /usr/local/share/zsh/site-functions
```

そうしてその後ようやく
```
brew install rbenv
```
が実行できました。バージョンを確認してみると

```
rbenv --version
```
結果
```
rbenv 1.2.0
```

こうしてようやく`rbenv`がインストールできました。
VScode を再インストールする。

# 経緯
　私的に所有しているパソコン３台の全てに VSCode(Visula Studio Code) が入っている。しかし、それぞれの VSCode で設定やインストールしている拡張機能が異なる為、最近使いづらく感じて、統一したいと思うようになった。拡張機能や settings.json ファイルをちまちま編集して統一する程、私は細かい人間ではないので、パソコン３台全てからソフトを消して再インストールすることを考えた。

### ＰＣ（パソコン）環境
　私が所有しているＰＣは下記の３つである。なお、カッコ内はOSを記している。
- ディスクトップＰＣ（Windows10）
- ノートＰＣ（Winsows10）
- ディスクトップＰＣ（Ubuntu 20.04.4 LTS）

Windows10 のＰＣ２台は同じようにできるだろう。
この記事では、 Windows10 と Ubuntu20.04 での操作を分けて書いていこうと思う。

# VSCode のアンインストール
#### Windows10
　過去の設定を残したくない場合、３つ[^1] 消さないといけない。
【手順】
１． <INS>VSCode のアプリをアンインストール</INS>
　「プログラムの追加と削除」から[VSCode] と検索しアンインストールする。

２．<INS>拡張機能の削除</INS>
　「C:\Users\[ユーザー]\.vscode」をフォルダ毎削除する。

３．<INS>ユーザー設定の削除</INS>
　[C:\Users\[ユーザー]\AppData\Roaming\Code] をフォルダ毎削除する。
GUI操作しながらフォルダを探している人で、AppData が見当たらない場合は、隠しフォルダを表示[^2]させよう。


#### Ubuntu20.04
Windows の場合と同じ。過去の設定を残したくない場合、３つ消さないといけない。
【手順】
１． <INS>VSCode のアプリをアンインストール</INS>
　今回は、ＧＵＩ操作でアンインストールした。アプリUbuntu Software を起動し、アプリ内の "Installed" 欄から VSCode を選んで、"Remove" ボタンを押す。
２．<INS>拡張機能の削除</INS>
ターミナルを開いて、下記のコマンドを実行。
<pre> $ rm -rf ~/.vscode </pre>
３．<INS>ユーザー設定の削除</INS>
ターミナルを開いて、下記のコマンドを実行。
<pre> $ rm -rf ~/.config/Code </pre>
# VSCode のインストール
#### Windows10
　[このページ](https://www.javadrive.jp/vscode/install/index1.html)を参考にしてインストール。
#### Ubuntu20.04
　[このページ](https://invisiblepotato.com/ubuntu01/#vnc-viewer%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB-pc%E6%93%8D%E4%BD%9C)を参考にしてインストール。

# VSCode のセットアップ
　自分用にカスタマイズしよう！
### 拡張機能追加
１．日本語化
* https://marketplace.visualstudio.com/items?itemName=MS-CEINTL.vscode-language-pack-ja

２．インデントを見えやすくする。
* https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow

３．Python
* https://marketplace.visualstudio.com/items?itemName=ms-python.python

４．Gitのバージョン管理を可視化
* https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph

５．WSL
* https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl

### 同期をオンにする
　同期をオンにして、他のＰＣにインストールした VSCode と同期できるようにする。
　[このページ](https://qiita.com/Nuits/items/6204a6b0576b7a4e37ea)を参考にして同期を設定。
　所有している３台のＰＣの内、ディスクトップＰＣ（Windows10）の設定を最初に行えば、残り２台のPCの VSCode の設定で同期をオンにすることで同じ様になる。設定の途中で「マージまたは置換」を聞かれるが、私は最初に設定したPCと同じ設定を他２台にしたかったので「ローカルを置換」を選択した。



### 参考
[^1]: https://kazupon.org/vscode-how-to-completely-uninstalll/
[^2]: https://1-notes.com/windows10-view-appdata/
HTTPメソッド GETとPOSTの違い

恥ずかしながら、今まで勘違いしていたのですが、それに気付く機会がありありましたので、これを機に勉強しなおして備忘録としてまとめておきます。
## 今まで勘違いしていたこと
名前の通り、getは何かを取得、postはフォームデータ等の何かを送信する、ためのものだと思っていましたが、間違いではないのですが、それだけではありませんでした。
getでも送信処理はできるし、postでも何かを取得することができる、また、DBに登録するしないや、レスポンスとして返す値はサーバが決めることなので、HTTPメソッドとは別次元の話であるということがわかりました。

### 勘違いに気付くきっかけ
参画したプロジェクトのHTTP通信関連のサービスクラスを覗いてみたら、全てpostメソッドで書かれていました。
おや？フォームデータを送信する処理じゃないのに、なんでpostなんだ？と思い調べてみて、勘違いに気付きました。

### 特に大きな違い
パラメータの渡し方の違いが大きいかと思います。
#### get
クエリパラメータで渡します。
クエリパラメータとは、URLの最後に？で付加するあれです。これを使って、サーバーにパラメータを渡します。
クエリパラメータを付与した状態で、ブックマークに登録できるので、保管はしやすいが、パラメータを第三者に見られるため、機密性の高い情報を送信するときはgetは使用するべきではない。

#### post
body部に含めて渡します。bodyに含めることで、第三者に見られる可能性が低くなり、セキュリティ面ではgetより高い特徴があります。ただ、postなら安全という話ではなく、機密性の高い情報であれば、暗号化は必須。


### メリデメ

| |  GET  |  POST  |
|---- | ---- | ---- |
| パラメータの渡し方|  クエリパラメータ  |  body  |
| セキュリティ|  他人に見られやすいため、低い  |  比較的高い  |
|パラメータの保管|しやすい|しにくい|

参考にしたサイト、書籍
https://qiita.com/kanataxa/items/522efb74421255f0e0a1
https://gihyo.jp/book/2010/978-4-7741-4235-7
15分ルールで学習効果を高める（日本語訳）

以下は、[Supercharge your learning with the 15-minute rule](https://www.intercom.com/blog/15-minute-rule/)の日本語訳です。

# Supercharge your learning with the 15-minute rule
<b>どんなチームで仕事をしていても、何年経験を積んでいても、どうしても行き詰まる問題にぶつかることがあります。</b>

このような場合、2つの選択肢があります。

- 解決策が見つかるまで、根気よく問題に取り組んでみてはいかがでしょうか
- 行き詰まりを自覚したとき、助けを求めることができる

どちらの選択肢も、状況に応じて異なるタイミングでアピールし、どちらにも利点がある – この2つは、それぞれ異なる学習方法です。 前者では、すでに解決された問題に貴重な時間を費やすことになり、後者では、自分で学ぶ機会を逸してしまうかもしれません。

## "15分ルール "を守る
そこで登場するのが「15分ルール」です。15分かけて、できる限り問題を解決する。15分経っても答えが出ない場合は、必ず誰かに聞いてください。

自給自足の大切さを学びつつ、必要なときには救命いかだを手に入れなければならないという、とてもシンプルな格言のようですが、これを守ることで実際に自分自身の成長を加速させることができます。

> "問題を把握しようともせずにバグをエスカレートさせ続けていたら、自分で問題を解決する方法を学ぶことはできなかっただろう"

私がジュニアカスタマーサポートエンジニアだった頃、ジェフ・ガードナーはカスタマーサポートチームのリーダーとして、このシンプルなルールを教えてくれました。もし、私がお客様の問題で行き詰まった場合、彼は「助けを求める前に、まず15分かけて答えを見つけろ」と言いました。15分経っても答えが見つからない場合は、彼に助けを求めなければなりませんでした。

ジェフが私を助けたくなかったわけではありません。でも、もし私が問題を解決しようとせずにバグをエスカレートさせ続けていたら、自分で問題を解決する方法を学ぶことはできなかったでしょう。

## 解決への道筋をナビゲートする

15分の時間をかけることで、何を探すかだけでなく、どのように探すかを知るスキルを身につけることができます。カスタマーサポートや製品エンジニアリングのチームで最も価値のあるスキルの1つは、社内のコードベースやドキュメントをナビゲートすることです。このようにして、多くの場合、時間をかけて探せば答えがそこにあることを学ぶことができるのです。

> "助けを求めるときは、少なくとも問題の全容を把握すること"

さらに重要なのは、助けを求めるときに、少なくとも問題の全容を把握することができるということです。コードベースを探したり、古い会話を検索したり、Slackを徹底的に調べたり、社内文書を熟読したりしても、まだ足りないかもしれません。しかし、90％の確率で貴重な情報を得ることができ、それはあなたを助けてくれる人と話すときに役に立ちます。

## 聞くことが重要
自分自身で問題に取り組むことと、チームメイトに助けを求めることのバランスを取ることは、自分自身にとっても、チーム全体にとっても、さまざまなメリットをもたらします。多くの人は、難しい問題に取り組み、自分自身を試しながら問題を解決し、満足感を得ることを楽しみます。

> "問題を解決しようとしてウサギの穴に消えていくのは簡単すぎるが、実は、あなたの時間は高価なのだ"

しかし、一日中探してもブロックが解除できない状況もあります。問題を解決しようとウサギの穴に消えていくのはあまりにも簡単ですが、実は、あなたの時間は高価なものなのです。

しかし、他の人が10分で解決できる問題に3時間費やしても、賞は与えられません。このような場合、15分ルールは、一歩下がって自問自答することを促します。"この問題を解決するのは、本当に自分でよいのだろうか？"

## 15分ルールはチーム全体にどのように役立つのか
問題解決に重点を置くチームで働く人にとって、15分ルールは本当に有益なものです。

- 新入社員には「自立」を教えています。
- 新入社員は自立を教えられ、行き詰まったときにはセーフティネットがあることを誰もが知っています。
- 若手社員は先輩社員から指導を受け、問題解決の論理を学びます。
- 先輩は、チームの仕事ぶりを非公式に評価し、フィードバックしてくれる。

私はサポートエンジニアとしてこのスキルを学びましたが、このスキルには、お客様が回答を得るまで長く待たされることがないという利点もあります。しかし、製品エンジニアになった今でも、15分ルールは定期的に使っています。同僚の時間を尊重しつつ、本当に必要なときには助けを求めることを恐れてはいけないということを教えてくれるからです。このバランスを保つことが、自己の成長を促す一番の近道なのです。

キャリアアップを目指す方、ぜひご連絡ください。[募集中の職種](https://www.intercom.com/careers)を見る
LTEドングルを使ってpovoをNEC UNIVERGE IX2215に収容する

# 目的
モバイル回線をフレッツのバックアップ回線としてルーターに収容したい。
スマホのUSBテザリングやモバイルルーターは常時稼働に向かないので個人的にNG
↓
何とかしてLTEドングルを使いたい。

# 目標
- povoをNEC UNIVERGE IXシリーズのルーターに収容する
- IPv4,IPv6のデュアルスタック

# 用意する物
- povoのSIM
- USBポートが付いてるUNIVERGEルーター (今回はIX2215, Ver.10.7)
- Speed USB STICK U03 or 富士ソフトのFS040U

出回ってる中古端末はNDISモードが多いが、ルーターに接続するには**モデムモード**のLTEドングルが必要となる。

U03はAU回線を契約して窓口に問い合わせる必要がある。
FS040Uは富士ソフトに問い合わせてデバイスを送ると、モードを変更して送り返してくれるらしい。

ルーターのファームウェアがVer.9以前だと動かないかも。

# 作業手順
1. ドングルをPCに接続してAPNを登録する
2. ルーターに繋いでコマンド投入

以上

## APN登録
ルーターで設定出来るAPNはIPv4のみである。
IPv6を通したいので、ATコマンドを使ってAPNを登録する。
PCに接続してシリアルポートのそれっぽいデバイスを9600bpsで開く。(Tera Tarm等)

### ドングル接続の確認
正常に接続されると、ATと入力したらOKが帰ってくる。
キー入力しても入力した文字が表示されないので、エコー設定`ATE1`を投入すると入力文字が表示されるようになる。
```
AT ← 入力した文字は標準で表示されない
> OK
ATE1
> OK
```

### 現在の設定の確認
登録されているAPNの一覧が表示される。
上書きしても良さそうな番号をメモって次に進む。
ルーターから指定出来る番号が1～9なので、その範囲から選ぶと良い。
```
AT+CGDCONT?
> +CGDCONT: 1,"IPV4V6","kwx2.au-net.ne.jp","0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0",0,0,0,0
```

### 設定の書き込み
1番にAU標準のAPNが入っていたので、今回は2番に登録する。
```
AT+CGDCONT=2,"IPV4V6","povo.jp"
> OK
```

### 書き込んだ設定の確認
```
AT+CGDCONT?
> +CGDCONT: 1,"IPV4V6","kwx2.au-net.ne.jp","0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0",0,0,0,0
> +CGDCONT: 2,"IPV4V6","povo.jp","0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0",0,0,0,0
```


## ルーターの設定
povoはユーザー・パスワード無しで通信できるキャリアなので、PPPプロファイルの中身は空でOK。
IPv4アドレスはIPCPによる自動取得、IPv6アドレスは自動設定とする。

mobile numberの値で、先ほど登録したAPNの番号(CID)を指定する。
指定する番号は次の形式で、nの位置に登録した番号(今回は2)を入れる。
`\*99***n#` (n=CID)



まずUSBデバイスを起動する。
```
interface USB0
  no shutdown
```
pppプロファイルを作成する。
povoは認証が無いのでchapの指定だけすればOK。
```
ppp profile ppp_povo
  authentication accept chap
!  authentication myname user@povo.jp
!  authentication password user@povo.jp povo
```
USB-Serialとしてモバイル回線を設定する。

```
interface USB-Serial0.0
  encapsulation ppp
  auto-connect
  idle-time 0
  ppp binding ppp_povo
  ip address ipcp
  ip tcp adjust-mss auto
  ip napt enable
  ipv6 address autoconfig
  mobile number *99***2#
  no shutdown
```

以上でキャリアからIPが振ってくる。
ip routeを変更して、フィルター周りは適当に設定してください。

# まとめと補足
直接ATコマンドを叩くことで、専用ツールが無くてもIPv6に対応したAPNを設定できる。
IPv4だけで良いなら、ルーターのプロンプトでサンプル通りに`mobile cid <CID> pdp ip apn povo.jp`と書けばOK。

Yamahaのルーターにこの記事の情報を流用しようとしている方は注意。
2022年5月時点でRTX810+U03+povoの環境ではエラーが発生して動作しなかった。
個人的な予想だが、SIMに電話番号が書き込まれていない事が原因と思われる。
スマホの端末設定から電話番号を確認出来ないSIMは要注意。


# 参考にした文献
[UNIVERGE IXシリーズ　設定事例集](https://www.support.nec.co.jp/View.aspx?id=3170102600)
[Docomo 取扱説明書 L-05A 付録](https://www.docomo.ne.jp/binary/pdf/support/manual/l05a/L-05A_J_08.pdf#page=9)
共有サーバーで仮想環境構築のためにvenvするときにディスク容量をなるべく使わない方法

Dropboxなんかのなかで仮想環境切って、開発していると、仮想環境ごとにscipyやらが容量を食って、Dropboxが満杯になってしまう。

そんなとき、開発コードはDropboxにおいておきながら、仮想環境はローカルに設定すれば、ローカルのディスク容量を食ってくれるので、便利。

たとえば、Dropbox上で仮想環境を切るときに、ローカルを指定する。

```shell
cd ~/Dropbox/my_project
mkdir ~/venv
python3 -m venv ~/venv/env_name
```

アクティベートはローカルを指定する。

```shell
source ~/venv/env_name/bin/activate
```

他環境からアクセスする場合にすぐにインストールできるように、パッケージのリストを書き出すことを忘れずに。

```shell
(venv)pip freeze > requirements.r
```
斜めのバウンディングボックス！ MMRotateのつかいかた（画像推論）　

# 斜めの物体でも検出できる

従来物体検出のボックスは水平のものだけでした。

[**mmrotate**](https://github.com/open-mmlab/mmrotate)では回転する物体（車や船など）の斜めのボックスを検出できます。

[image from mmrotate]
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/51c68ecd-827c-68a5-f504-10e0c4027489.jpeg", width=800>

# 使い方

インストール。

```shell
pip install openmim
mim install mmrotate
git clone https://github.com/open-mmlab/mmrotate.git 
```

モデルの重みをダウンロード。
重みのリンク一覧は[mmrotateのリポジトリ](https://github.com/open-mmlab/mmrotate)にあります。

```shell
wget https://download.openmmlab.com/mmrotate/v0.1.0/rotated_retinanet/rotated_retinanet_obb_r50_fpn_6x_hrsc_rr_le90/rotated_retinanet_obb_r50_fpn_6x_hrsc_rr_le90-ee4f18af.pth
```

推論。
使用するモデルの構成ファイルと重みを設定して推論します、
構成ファイルはリポジトリにあります。

```shell
python demo/image_demo.py \
        "demo/demo.jpg" \
        configs/rotated_retinanet/rotated_retinanet_hbb_r50_fpn_1x_dota_oc.py \
        rotated_retinanet_hbb_r50_fpn_1x_dota_oc-e8a7c7df.pth
```

🐣
****
フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com

Core MLやARKitを使ったアプリを作っています。
機械学習／AR関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
[GitHub](https://github.com/john-rocky)
xmlのshapeタグって意外と自由度が高いっていう話 part2

# 初めに
今回からxmlの`shape`タグで使えるものをシリーズ化して紹介していこうと思います。
間は空いてしまいましたが、二個目は`corners`と同じくらい使われているであろう`stroke`です。

## 本文
こちらは枠線をつけることができ、要素として`dashGap`、`dashWidth`、`width`、`color`を指定することがきます。
`dashGap`、`dashWidth`は破線を作りたいときに使用するもので、`dashGap`は破線の幅を、`dashWidth`は破線ごとの長さを指定することができます。
通常の`width`では太さを指定することができ、`color`はその名の通り色のしてができます。
こちらを使用することでできるのが下記のものです。

```xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <stroke android:dashGap="8dp"
        android:width="4dp"
        android:color="@color/white"
        android:dashWidth="8dp"/>
</shape>
```

![スクリーンショット 2022-04-28 12.42.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638092/01342939-2982-111c-e393-884a195744e8.png)

## 最後に
間が空いてしまった`shape`タグで作れるViewシリーズですが、次回は未定ですが更新は早いうちにすると思います。
次の記事が投稿でき次第こちらにも次の記事にもシリーズの導線を置いていこうと思うので、どなたかの力になれれば幸いです。
前回の記事はこちら：https://qiita.com/ryuji_sato/items/e5f232de15032fc84ee4
脳筋が岡山県内のジムを検索するサービスを開発しました(ポートフォリオ、Rails+AWS+Docker)

## はじめに

・この記事はポートフォリオとして開発した、岡山県内のジム検索サービス「Gymseek」の紹介記事です。
・現在はAWSの無料会員期間終了のため、サービスを閲覧することはできません。

![150344970-bab35ab6-8556-427d-9775-44233e3da39a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2086069/fa16a097-41d8-0809-9cb8-89c922161283.png)

https://github.com/omeinu/gymseek

## 目次
- 自己紹介
- 利用方法
- 使用技術
- AWS構成図
- 機能一覧
- ER図

## 自己紹介

初めまして！
私は、元消防士の駆け出しエンジニアです。
２９歳で岡山→東京へ上京しました。

エンジニアとして働き始めて１ヶ月が経ちましたので、ここらで転職用に開発したポートフォリオを記録に残しておこうと思い、初めて記事を書かせていただきました。

## 利用方法

トップページの「さっそくジムを探す」から、すぐに自分に合った条件でジムを探すことができます。

![スクリーンショット 2022-05-03 5.57.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2086069/7d5a8e91-9498-a267-d1a1-135f588357bf.png)

詳細検索機能を使って、自分に合ったジムを探すこともできます。


![スクリーンショット 2022-05-03 6.24.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2086069/69c6e5a8-2e2f-ed8c-6c1f-5304a499af2c.png)

検索したジムをクリックすると、ジムの詳しい情報や、GoogleMapでジムの場所を確認することができます。

![スクリーンショット 2022-05-03 6.27.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2086069/d0b0ca4e-512f-2243-9394-e223382a4261.png)

(GCSの期限切れ？のため綺麗に表示されませんでした)

![スクリーンショット 2022-05-03 6.27.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2086069/1221271c-688b-81ab-aa60-777df1cfae8b.png)

アカウント登録することで、自分のお気に入りのジムを登録することができます。

![スクリーンショット 2022-05-03 6.41.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2086069/426e4c8f-d2d2-c732-35fd-a6fa99de0efb.png)


## 使用技術

- フロントエンド
HTML/CSS
javascript
Bootstrap 4.3.1

- バックエンド
ruby 2.5.1
Rails 5.2.4
Google Maps API

- インフラ
Docker/docker-compose
nginx
mysql 5.7
AWS(EC2, RDS, ROUTE53, S3, VPC)

- その他使用ツール
Visual Studio Code
draw.io(ER図作成)
MySQL Workbench(AWS構成図作成)

## AWS構成図

![AWS構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2086069/5dacc3ba-87bb-43c3-d69e-58d2735c7baa.png)

## 機能一覧

- ログイン機能(device)
アイコン設定
ゲストログイン
メール送信によるパスワード再設定

- ジム検索機能(ransack)
- アイコン画像保存(carrywave, S3)
- 口コミ機能

- ページネーション(kaminari)
- Google Maps API
- 画像リサイズ(Minimagick)
- 静的ページ表示(high_voltage)
- テスト(Rspec, rubocop)

## ER図

![ER図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2086069/550a2d59-0ad7-9915-ba7b-3ff159e9cb59.png)
Mbedで自作のprintfが使いたい(STM32L010)



x @Kurogaraさんの記事を非営利、研究調査で引用して移植しました。



目的
さらに容量に余裕がある場合
ちょつと違うがぞくに言うsprintfを使うというやつ
そもそも、標準シリアルを使えというのは、なし


![o_con379.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/2c483562-1e19-db4d-8e34-eed4c8b0000a.jpeg)




参考


https://qiita.com/Kurogara/items/3136665cc3b0d34fce3a



```c++


#include "mbed.h"

//Serial pc(USBTX, USBRX); // tx, rx
//Serial pc(SERIAL_TX, SERIAL_RX); //767
RawSerial pc(PA_2, PA_3); //010

int ns_printf(char* fmt, ...) {
      char buff[256];
      va_list args;
      va_start(args, fmt);
      int return_status = vsnprintf(buff, sizeof(buff), fmt, args);
      va_end(args);
      char *s = buff;
      while (*s) pc.putc(*s++);
      return return_status;
}


int main() {

    char *ss1; //文字のポインター
    int ii; //ループカウンター

    //無限ループ
    while(1) {


        ss1="Hello World !\r\n";
        ii=0; //ループカウンター
        while(ss1[ii]!=0){
            
            //一文字出力
            pc.putc(ss1[ii]);ii++;
                        
        } //while

        ns_printf("%d\n\r",1234);

        //1秒の待ち
        wait_ms(1000);
        
    } //while
} //main

//容量削減
void error(const char* format, ...){}




```
Mbedでitoa「整数を文字列」がない?　(STM32L010)



目的
少し容量に余裕が出てきた人むけ


参考

![o_con378.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/46c4cf30-72f0-385f-5f04-3823cfa84124.jpeg)



Where is itoa() ?



https://os.mbed.com/forum/bugs-suggestions/topic/2319/?page=1#comment-19606



```c++



#include "mbed.h"

//Serial pc(USBTX, USBRX); // tx, rx
//Serial pc(SERIAL_TX, SERIAL_RX); //767
RawSerial pc(PA_2, PA_3); //010

/*
** reverse string in place 
*/
void reverse(char *s) {
char *j;
int c;
 
  j = s + strlen(s) - 1;
  while(s < j) {
    c = *s;
    *s++ = *j;
    *j-- = c;
  }
}

/* itoa:  convert n to characters in s */
 void itoa(int n, char s[])
 {
     int i, sign;
 
     if ((sign = n) < 0)  /* record sign */
         n = -n;          /* make n positive */
     i = 0;
     do {       /* generate digits in reverse order */
         s[i++] = n % 10 + '0';   /* get next digit */
     } while ((n /= 10) > 0);     /* delete it */
     if (sign < 0)
         s[i++] = '-';
     s[i] = '\0';
     reverse(s);
 }


int main() {

    char ss1[16]; //文字列
    int ii; //ループカウンター

    //無限ループ
    while(1) {

        itoa(1234,ss1);
        ii=0; //ループカウンター
        while(ss1[ii]!=0){
            
            //一文字出力
            pc.putc(ss1[ii]);ii++;
                        
        } //while
        pc.putc('\r');
        pc.putc('\n');

        //1秒の待ち
        wait_ms(1000);
        
    } //while
} //main

//容量削減
void error(const char* format, ...){}




```
alias メモ

##docker redmine
#接続
alias rema='docker exec -it redmine bash'
alias redb='docker exec -it redmine-db bash'

#再起動
alias rere='cd /usr/local/redmine && docker-compose down && docker-compose up -d'
#データベースの更新(redmine)
alias redb1='bundle exec rake db:migrate RAILS_ENV=production'
#データベースの更新(プラグイン)
alias redb2='bundle exec rake redmine:plugins:migrate RAILS_ENV=production'
#キャッシュのクリア
alias redb3='bundle exec rake tmp:cache:clear RAILS_ENV=production'

##docker redmine plugin
alias kase='vim /usr/local/redmine/data/plugins/kanban/app/models/constants.rb'

#redmine plugin削除
cd /usr/local/redmine/data/plugins/
rm -fr redmine_editor_preview_tab
2022/5/3主にITとかセキュリティの記事

未感染者にも及ぶ「Emotet」被害 - なりすまされ、約10万件のメール
https://www.security-next.com/136270

クライアントソフトなど複数製品に脆弱性 - 米Zoom
https://www.security-next.com/136265

スマホ向け主要プロセッサのAppleロスレス処理に脆弱性 - 2021年12月に修正
https://www.security-next.com/136277

経産省など セキュリティ対策徹底を サイバー攻撃に注意喚起(5/1)
https://ab.jcci.or.jp/article/63461/

【重要】弊社社員を装った不審なメール (なりすましメール) に関する注意喚起のお知らせ　ノアドット(5/1)
https://nordot.app/893306469486280704

サードウェーブに誤情報提供しライセンス契約　マカフィーに損害賠償命じる判決(4/29)
https://www.zaikei.co.jp/article/20220429/670479.html

ハーモニーOSで巻き返しを図るファーウェイ。ファーウェイのスマホは復活できるのか(5/1)
https://tamakino.hatenablog.com/entry/2022/05/01/080000

EU、Apple Payが独禁法に違反しているとしてAppleを告発する構え(4/28)
https://gunosy.com/articles/e8x1Y

サバゲ―施設で軍事訓練、IT強者は「サイバー攻撃」　ウクライナ・リビウのいま(5/1)
https://www.dailyshincho.jp/article/2022/05010600/

誰一人取り残さないデジタル・ガバメントへの一歩目(4/30)
https://agora-web.jp/archives/2056242.html

Microsoft、IE11の早期無効化を推奨(5/1)
https://www.zaikei.co.jp/article/20220501/670596.html

すでに6G通信の2030年本格運用を前提に戦略を展開―ファーウェイ、サムスン(4/30)
https://news.nicovideo.jp/watch/nw10867422

Twitterで交流する相手を「制限」するには？ 知っておくべき6つの設定(5/1)
https://wired.jp/article/how-to-limit-who-can-contact-you-twitter/

三井住友銀行システム障害、全面復旧　GWの決済に影(5/1)
https://www.nikkei.com/article/DGXZQOUB303Q70Q2A430C2000000/

三井住友銀行、システム障害ほぼ解消　ＡＴＭ通常通りに(5/1)
https://news.yahoo.co.jp/articles/39463ef484850360b0a4d21068d6322a708feb06

マイナカード普及にAppleの壁、iPhone搭載めど示せず(5/1)
https://www.nikkei.com/article/DGXZQOUA251M80V20C22A4000000/

５G　３０年度末で人口カバー率９９％必達目標(5/1)
http://economic.jp/?p=96202

メルカリの不正利用は「16億円」規模に。ユーザーが気を付けるべき点は？(4/30)
https://news.yahoo.co.jp/byline/yamaguchikenta/20220430-00293919

ネット検索から高額請求　モバプリの知っ得(5/1)
https://ryukyushimpo.jp/style/article/entry-1508173.html

安全保障に関わる技術流出防止へ きょうから規制強化 経産省(5/1)
https://www3.nhk.or.jp/news/html/20220501/k10013607481000.html

日本は人材の国外流出を止められるか、アメリカで暗号資産を利用する人の傾向【日曜日に読みたいコラム9本】(5/1)
https://finance.yahoo.co.jp/news/detail/20220501-00168093-coindesk-bus_all

北から暗号資産を受け取って軍事機密をハッキング、韓国陸軍の現役大尉を逮捕(4/29)
http://www.chosunonline.com/m/svc/article.html?contid=2022042980060

Spring Bootとは？Java開発の主要フレームワークを解説！(5/1)
https://and-engineer.com/articles/YkG6zxEAACIAnH8J

サーバーレスって何？(5/2)
https://xtech.nikkei.com/atcl/nxt/mag/nnw/18/041800014/042000057/

攻撃の高度化と人材不足に対応(5/2)
https://xtech.nikkei.com/atcl/nxt/mag/nnw/18/041800134/042000008/

SASE
複数の機能を一元的に提供するサービス(5/2)
https://xtech.nikkei.com/atcl/nxt/mag/nnw/18/041800134/041800002/

CSPM
クラウドの設定をチェックする仕組み(5/2)
https://xtech.nikkei.com/atcl/nxt/mag/nnw/18/041800134/041800003/

SOAR
セキュリティー事故に自動対応する機能(5/2)
https://xtech.nikkei.com/atcl/nxt/mag/nnw/18/041800134/041800004/

SOC
サイバー攻撃を検知・分析する組織(5/2)
https://xtech.nikkei.com/atcl/nxt/mag/nnw/18/041800134/041800005/

UEBA
振る舞いから異常を検知する機能(5/2)
https://xtech.nikkei.com/atcl/nxt/mag/nnw/18/041800134/041800006/

IRM
ファイルの利用を制限する仕組み(5/2)
https://xtech.nikkei.com/atcl/nxt/mag/nnw/18/041800134/041800007/
【PHP】CakePHP４の導入



# 事前準備

### Composerのインストール
・[公式サイト](https://getcomposer.org/doc/00-intro.md#installation-windows)からComposer-Setup.exeをダウンロードしてインストール

### PHPインストール
・[公式サイト](https://www.php.net/downloads)からダウンロードしてインストール


※CakePHP4を使用する際にintlが必要になるため、php.iniでintlのコメントを外します。
```
extension=intl
```

### XAMPPインストール
・[公式サイト](https://www.apachefriends.org/jp/index.html)からダウンロードしてインストール

# CakePHP4のインストール
コマンドプロントで下記のコマンドを実行して、XAMPPの作業ディレクトリに
CakePHP4をインストールします。
```
// 作業ディレクトリに移動
cd C:/xampp/htdocs
// cakephp4をインストール
composer create-project --prefer-dist cakephp/app:4.* アプリ名
```

# Hello Worldを表示させる

Model、View、Controllerは指定の作業ディレクトリも追加していきます。
```
//Controller
C:\xampp\htdocs\my_app_name\src\Controller
//Model
C:\xampp\htdocs\my_app_name\src\Model
//View
C:\xampp\htdocs\my_app_name\templates
```

Hello Worldを画面に出したい場合は、Controllerのファイルと
Viewを追加すれば、`http://localhost/アプリ名/main/index`に表示させることができます。

```php:MainController.php
<?php

namespace App\Controller;

class MainController extends AppController
{
    public function index()
    {

    }
}
?>
```

```php:Main\index.php
<?php 
echo "Hello World";
?>
```

# アプリの作業ディレクトリ変更
1. XAMPPを開いて、ApacheのConfigから「httpd.conf」を選択します。
![xampp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431502/18620f69-8706-c09a-4c8f-2ac2287ba89a.png)

2. DocumentRootとDirectoryが本場所になるため、指定場所に変更します。
   （デフォルトは DocumentRoot "C:/xampp/htdocs"）

![httpd.conf変更.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431502/aec0764e-bf63-6bb8-f948-7f05b3bf05cc.png)






# Viewの作業ディレクトリ変更
app.phpの'templatess'を指定場所に変更することで
viewの作業ディレクトリを変更できます。
![appphp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431502/90f245b7-713e-6b80-a77e-9dd15752184f.png)



# データベースの設定変更
アプリ名\confing内にあるapp.php、app_local.phpを変更します。
Datasources内にあるdefaultのusername、password、databaseを変更します。

![database.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431502/3da9b742-b145-dc16-15b2-fa5c5147436c.png)
# 参考
https://book.cakephp.org/4/ja/index.html
Laravel リソースコントローラ

備忘録

# リソースコントローラとは
簡単に言うと、CRUD処理を持つコントローラを楽に作成できる機能です。

# 作成
```
php artisan make:controller 〇〇Controller --resource
```
上記のように、コントローラ作成のコマンドに" **--resource** "オプションを付けることで作成できます。

# コントローラの中身
実際に作成してみると、以下の様なコントローラができます。
```php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        //
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        //
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        //
    }
}
```

また引数のid部分を、[ルートモデル結合](https://qiita.com/rikua0023/items/68dd46c0aa455d866b0f)で他モデルを引数で与えたいときは、
```
php artisan make:controller 〇〇Controller --model=△△ --resource
```
のように記述すると、$idの部分が△△モデルになって作成されます。

# ルーティング
さらにルーティング記述もかなり楽になります。
```php:web.php
Route::resource('users', UserController::class);
```
上のルーティングを記述するだけで、以下のルーティングをしてくれます。
なんならルート名まで定義してくれます。

動詞| URI    | アクション | ルート名 |
|---|---|---|---|
|GET | /users|index	|users.index|
|GET	|/users/create	|create	|users.create|
|POST|/users|store|users.store|
|GET	|/users/{user}|show|users.show|
|GET	|/users/{user}/edit|edit|users.edit|
|PUT/PATCH|/users/{user}|update|users.update|
|DELETE|/users/{user}|destroy|users.destroy|

([Laravelドキュメント](https://readouble.com/laravel/8.x/ja/controllers.html#resource-controllers)　よりほぼ引用)

また、特定のルーティングのみにしたい、除きたいときは以下のように記述すれば可能です。
```php:web.php
Route::resource('users', UserController::class)->only([
    'index', 'show' //indexとshowのみ
]);

Route::resource('users', UserController::class)->except([
    'create', 'store', 'update', 'destroy' //create,store,update,destroyは除く
]);
```

# 最後に
他にも掲示板リソースがチャットリソースを複数持っているなどの、
あるリソースが複数のリソースを持つ場合のルーティングも簡潔に済ますことが可能だったりします。
詳しくは[Laravelドキュメント](https://readouble.com/laravel/8.x/ja/controllers.html#resource-controllers)を参照してください。
LaravelのFormValidationで外部キー制約を持った親テーブルへのアクセス制御がしたい

### やりたいこと

子テーブルを持つ親テーブルにアクセスさせないようにしたい。

### 理由

親テーブルを削除するときに、外部キー制約によるエラーをDBに近いところでやりたくない。

### 仕組み

1. リクエストされた`user_id`がusersテーブルに存在することを確認します。
    1. `exists:users,id`
2. postsのuser_idカラムには、リクエストした`user_id`が存在しないことを確認します。
    1. `unique:posts,user_id`
3. 結果：usersには存在しているけど、postsには存在しない`user_id`の場合のみvalidationを通す。

```yaml
/**
 * @return array
 */
public function rules()
{
    return [
        'user_id' => 'required|exists:users,id|unique:posts,user_id',
    ];
}
```

調べてもなかなか出てこなかったので、記事にまとめました。

この仕組を理解すると、他にもいろいろ組み合わせることでできることがあるんじゃないかといった視点を持つことにつながるので勉強になりました。
Google ログインの不具合で Google Play で公開した Android アプリが急に削除されたときの対応

# はじめに
株式会社データインサイトの山元です。弊社ではポイ活アプリや開業準備支援アプリなどの複数プロダクトをいずれも Flutter で開発しており、Androidアプリを Google Play に公開しています。

https://play.google.com/store/apps/details?id=jp.datainsight.charta_quest&hl=ja_US&gl=JP

https://play.google.com/store/apps/details?id=jp.datainsight.junbapp&hl=ja_US&gl=JP

# Google Play アプリのステータス: 削除済み
ある日突然、「Google Play Support <no-reply-googleplay-developer@google.com>」より以下タイトルのメールが届きました。
> ご対応のお願い: アプリ（{アプリ名}）のアクセス手順をご提供ください

Google Play の審査担当者が申請されたアプリを審査する際に、何かしらの理由でアプリに Google ログインが出来ず、審査を進められないときに却下されて来るメールなのですが、今回は申請に対する却下ではなく既に公開済みのアプリに対して急に削除処理をするという、なんとも悍ましい対応をされた時の話です。

Play Console を見てみると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2528515/3ce599fd-fd57-a5b5-be36-e8aed828408a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2528515/0b37ce85-58ee-ac7e-b79c-08c0f2321a5d.png)

って、えマジで消したの！？ってなりますが、落ち着いてください。
発生事由が本記事と同じであれば、数時間で解消されます。（詳細後述）

# なぜ発生したか
結論、Google ログイン側の問題でした。正しい EMAIL / PW を使って Google ログインを試みても、「Something went wrong. Please try again.」的なメッセージが出るケースが、ごく稀にあるようでそのタイミングと審査が被ったようです。

ちなみに当方が本件に出くわした流れは以下のとおりで、同一アプリの複数バージョンに対する審査が並行でなされ、イレギュラーケースに繋がったのかもしれません。
1. バージョン 1 を申請
2. 審査前に一部アップデートしたため、バージョン 2 を申請
3. 両バージョンともアクセス手順の件で却下
4. 案内したアクセス手順自体に誤りは無かった（しかし審査担当者が、存在しないアカウントを使ってログインを試みた）ため言葉尻を微修正して再申請（「アプリのコンテンツ」⇒「アプリのアクセス権」に記載した内容を修正。何かしら修正しないと再申請できない）
5. バージョン 2 の申請が通る（バージョン 1は、バージョン 2 が通ったためリリースされない）
6. 数日後、公開済みのバージョン 2 のみ今回の件で却下され急に削除される

# どうすればよいか
「アプリのコンテンツ」⇒「アプリのアクセス権」に記載してあるログイン手順を更新して、すぐに再申請しましょう。
この問題自体が過去に同じデバイスで同じアプリに Google ログインして、アプリにキャッシュが残っている場合に発生することが多いようなので、このエラーが出た場合は Google 認証サーバー側に何かしらの問題があるため時間を置いて再度お試しくださいといった案内文を添えておきましょう。

確実に回避したい場合は、Google ログイン以外の認証方法を審査で使用するように案内してください。


# さいごに
最後までお読みいただきありがとうございました！
調べても中々情報が見当たらず対処に困ったので記事にしました。かなりイレギュラーケースと思われますが、もし同じケースになった人がいれば迅速な対応が命なので迷わず再申請しましょう。

それでは、締めに弊社紹介です。
Data Insight Inc.では "地図×データで新しい未来をつくる" ことを目指して、
様々なデータとテクノロジーを活かした取り組みを進めています。
さらなる事業拡大のためにデータサイエンティスト、エンジニア、デザイナーの仲間を募集中です。
ご興味いただけた方は、遠慮なくご連絡いただければ嬉しいです！

https://datainsight.jp/recruit
画面に出力されるコマンドの結果を記録したい

# やりたいこと
こんにちは。iwayu987です。
みなさん、　Qiitaで記事を読むとコマンドと出力結果が並んでたりするのをよく見ますよね
```
$なんかコマンド
コマンドの結果が画面に出力される
```
これです。
これを作るとなると元ネタとなるコマンドと出力結果が必要になりますが、画面に出力している以上シェルを閉じれば見られなくなります。
コマンドはhistoryから見られますが、出力結果はどうしましょう。
さすがに毎コマンドで出力先をテキストファイルにするのはしんどすぎます。

# 調べたこと
「Bash ログ保存」で調べて以下の記事に辿り着きました。

https://atmarkit.itmedia.co.jp/flinux/rensai/linuxtips/090termnallog.html

scriptコマンドを使えばしたいことができそうです。

# やってみた

scriptコマンドで記録を開始して、ループバックアドレスに3回pingを打ってから記録を終了します。
画面での表示は以下の通りです。
```
iwayu987@penguin:~$ script
Script started, output log file is 'typescript'.
iwayu987@penguin:~$ ping 127.0.0.1 -c 3
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.139 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.102 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.089 ms

--- 127.0.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2042ms
rtt min/avg/max/mdev = 0.089/0.110/0.139/0.021 ms
iwayu987@penguin:~$ 
exit
Script done.
```
なお、output log file is 'typescript'.とあるように、引数なしでscriptコマンドを実行するとtypescriptというファイルが作成されて書き込まれます。

typescriptファイルの中身を見てみましょう。

```
iwayu987@penguin:~$ cat typescript 
Script started on 2022-05-03 01:24:40+09:00 [TERM="xterm-256color" TTY="/dev/pts/0" COLUMNS="194" LINES="45"]
iwayu987@penguin:~$ ping 127.0.0.1 -c 3
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.139 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.102 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.089 ms

--- 127.0.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2042ms
rtt min/avg/max/mdev = 0.089/0.110/0.139/0.021 ms
iwayu987@penguin:~$ 
exit

Script done on 2022-05-03 01:25:08+09:00 [COMMAND_EXIT_CODE="0"]
```

分かりにくいですが、2行目からがtypescriptファイルの中身になっています。
画面上での表示と比較しても遜色ありません。
このコマンドを使えば当初の目的が果たせそうです。

# 補足
既にカレントディレクトリにtypescriptファイルがある状態で、引数なしでscriptコマンドを実行すると中身が完全に上書きされてしまうので注意が必要です。