OmniAICreator/Qiita-1.07M huggingface dataset:
Node.js・TypeScriptとは

# はじめに
Node.js・TypeScriptについての記事を書きます。
間違っていたらコメント等での指摘をお願いします。


以下、本を参考にしつつ学習していきます。
[TypeScriptとReact/Next.jsでつくる実践Webアプリケーション開発](https://amzn.asia/d/fcAmzbB)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3086650/bb190771-a894-8ba0-8a24-37de5a942778.png)

# Node.jsとは
以下、[公式](https://nodejs.org/ja)から引用
**Node.js はスケーラブルなネットワークアプリケーションを構築するために設計された非同期型のイベント駆動の JavaScript 環境です。**

Google Chromeに搭載されているJava Scriptの実行エンジンV8を利用し、作られている。
つまりNode.jsは言語ではなく、
**JavaScriptの実行環境**

これまでサーバーサイドはPHPやJavaといった言語で開発して、
フロントエンドはJava Scriptで開発していた。
Node.jsの登場により、フロントエンドの言語をそのままサーバーサイドで実装可能になったため、
サーバーサイドとフロントエンド間のコードの共通化も可能になった。

2023/07/11追記
以下がすごくわかりやすい！

https://qiita.com/non_cal/items/a8fee0b7ad96e67713eb

:::note info
**Node.jsとは**
JavaScriptをサーバーサイドで実行できる実行環境
:::

## 特性
- **ノンブロッキングI/O**
ノンブロッキングI/Oという多くのRequestを遅延が少なく処理できる。
入出力していても別の処理ができる。
詳しくはまた調べる。

https://wa3.i-3-i.info/word1617.html

- **npm**
パッケージマネージャー、パッケージシステム。
パッケージの依存関係を管理し、必要な他のパッケージをまとめてインストールしてくれる。

https://softwarenote.info/p1294/#:~:text=npm%E3%80%90Node%20Package%20Manager%E3%80%91%E3%81%A8,%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%97%E3%81%A6%E3%81%8F%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82

また、利用するライブラリとバージョン指定をpackage.jsonで記述するだけで、組み込むことが可能。

:::note info
**ノンブロッキングI/Oとは**
入出力をやっている最中も他の処理を並行して進められるI/O（入出力処理、入出力処理をする部品）のこと
:::

:::note info
**npmとは**
パッケージの依存関係を管理し、必要な他のパッケージをまとめてインストールしてくれる
:::

# AltJS(Alternative JavaScript)とは
コンパイルすることでJava Scriptが生成されるプログラミング言語
※言語から言語にコンパイルすることはトランスパイルとも呼ぶ
TypeScriptもAltJSのひとつ

:::note info
**AltJS(Alternative JavaScript)とは**
コンパイルすることでJava Scriptが生成されるプログラミング言語
:::

# ビルドツール
**ビルドシステム**
ソースコード上で読み込んでいるモジュールの依存を解決し、実行可能なJavaScript形式に変換する仕組み
（サーバーサイド・フロントエンド両方で使われている）

## webpack
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3086650/08298cdf-b4fd-f05a-e2a7-dae534e1f635.png)

Node.jsでサーバーサイドで動かすモジュールバンドラーツール
webpackの開発は事実上終了しており、後継（Turbopack）を開発中
バンドル＝１つのファイルにまとめること
Requestが一度でいいので、速度があがる。またCSSや画像もひとつにできる。

https://webpack.js.org/

https://qiita.com/kamykn/items/45fb4690ace32216ca25

https://www.publickey1.jp/blog/23/javascriptwebpackturbopack.html

https://zenn.dev/oreo2990/articles/8581ad93276f0c

# TypeScriptとは
- 静的型付け言語
- JavaScriptと同じ構文ならびにライブラリが使用できる

https://www.typescriptlang.org/

## 主なフレームワーク
- **AngularJS**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3086650/0d0fb568-f691-ffb8-46b8-8b6cfe005c39.png)

https://angularjs.org/

- **React**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3086650/fea1847a-f9d8-6bac-94a8-dd790606b765.png)


https://ja.legacy.reactjs.org/

- **Vue.js**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3086650/35804ea1-c908-0e65-5cc0-f8c4a1602832.png)

https://ja.vuejs.org/

JSで使えるフレームワークはTypeScriptでも使える
（TypeScriptは略するTS?）

# まとめ
おもしろそう（単純＆語彙力、笑）
徐々に記事内容を追加します。
AWS上でEC2を使ったDocker環境の構築

# はじめに
AWS上にDockerを利用できる環境を構築したので備忘として残していきたいと思います。

# 目次
1. Amazon EC2　にLinux環境を用意
1. EC2のセキュリティグループの設定
1. EC2インスタンスを作るまでの流れ
1. EC2をSSHで操作

## Amazon EC2にLinux環境を用意
### EC2コンソールの起動
リージョンは東京リージョンを選択。
![スクリーンショット 2023-07-10 15.35.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294959/4697fa38-3eea-bba1-af6b-4f1b9eba28b6.png)

「EC２」を検索して、EC２コンソールを起動する。
![スクリーンショット 2023-07-10 15.40.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294959/f2e98ec6-6d63-30db-59d8-e3c0c1448c2c.png)

### インスタンス作成
#### インスタンスの起動
![スクリーンショット 2023-07-10 16.20.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294959/8e762e76-9380-ecd1-336b-6f42be302cd5.png)

#### AMI・インスタンスタイプ
+ AMI 　　　　　　　　：　Ubuntu Server 22.04 LTS （HVM）,SSD Volume Type
+ インスタンスタイプ　：　t2.micro

#### キーペアの作成
SSH接続する際に必要となるキーペアを用意する。
キーペアを持っているとEC2インスタンスにログインし全ての操作が出来てしまうため、第三者に漏洩しないように注意する。

#### ネットワーク設定

以下のセキュリティグループのルールを追加する。
| タイプ | プロトコル | ポート範囲 | ソース |
|:-:|:-:|:-:|:-:|
| SSH  | TCP  | 22  | 0.0.0.0/0  |
| HTTP  | TCP  | 80  | 0.0.0.0/0  |
| HTTP  | TCP  | 80  | ::/0  |
| HTTPS  | TCP  | 443  | 0.0.0.0/0  |
| HTTPS  | TCP  | 443  | ::/0  |
| カスタムTCPルール  | TCP  | 8080-8082  | 0.0.0.0/0  |
| カスタムTCPルール  | TCP  | 8080-8082  | ::/0  |
| カスタムTCPルール  | TCP | 30000  | 0.0.0.0/0  |
| カスタムTCPルール  | TCP  | 30000  | ::/0  |

:::note info
0.0.0.0/0 は全てのIPアドレスからインスタンスにアクセスすることを許可される。
:::

#### ストレージ設定
デフォルトでは8GBとなっているため、20GBに変更。

#### インスタンスを起動
インスタンスを起動する。

## EC2インスタンスにSSH接続する
### IPアドレスの確認
作成したインスタンスの「パブリック IPv4 アドレス」を確認し控えておく。

:::note info
パブリック IPv4 アドレスはEC2インスタンスを起動-停止するたびに変更となる。
:::

### SSHで接続する
ターミナルを開く
ダウンロードしたキーペアのパーミッションを読み取り専用に変更する。
例）Documentsフォルダに「docker_ec2.pem」というファイル名で置いた場合
```
$ chmod 400 ~/Documents/docker_ec2.pem
```
接続する
XXX.XXX.XXX.XXXの部分はEC2インスタンスのIP（パブリック IPv4 アドレス）を入力する。
```
$ ssh ubuntu@XXX.XXX.XXX.XXX -i ~/Documents/docker_ec2.pem
```
初回のみ以下のように問われるため、「yes」と入力する。
```
Are you sure you want to continue connecting (yes/no)?
```

# まとめ
これで、UbuntuのサーバをAWS上に構築し、操作できるようになりました。
次回、このサーバにDocker　Engineをインストールしていきます。

# 参考文献
この記事は以下の情報を参考にして執筆しました。
- [さわって学ぶクラウドインフラ　docker基礎からのコンテナ構築](https://www.amazon.co.jp/%E3%81%95%E3%82%8F%E3%81%A3%E3%81%A6%E5%AD%A6%E3%81%B6%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E3%82%A4%E3%83%B3%E3%83%95%E3%83%A9-docker%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E6%A7%8B%E7%AF%89-%E5%A4%A7%E6%BE%A4-%E6%96%87%E5%AD%9D/dp/4296106422?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=docker%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E6%A7%8B%E7%AF%89&qid=1623188221&s=books&sr=1-1&linkCode=sl1&tag=infranote-22&linkId=0af07033c1b663ab6279d327681c5eee&language=ja_JP&ref_=as_li_ss_tl)
AWS Lambdaの環境変数をCodeエディタから見られるようになった

最近のAWS UpdateでAWS LambdaコンソールのCodeエディタから見られるようになりました。

https://aws.amazon.com/jp/about-aws/whats-new/2023/06/aws-lambda-copying-environment-variables-console-code-editor/

今まではコンソールから環境変数を確認する際は「設定」→「環境変数」に見に行く必要があったのですが、今回のUpdateによりコード編集中にコンソールから移動する必要がなくなりました。

# やってみる
簡単ですが、試してみます。

環境変数の設定自体は従来通り「設定」→「環境変数」から行います。
![image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/060421f5-4c9e-961e-77df-70013463be6d.png)

「コード」タブに移動し、「Tools」→「Show Environment Variables」を押下します。
![image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/dabb717f-ef4f-86a8-5efc-497b93038ea5.png)

するとコードエディタの隣にEnvironment Variablesタブが開かれ、環境変数の確認ができます。

![image3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/d807aa60-47ad-45f3-fab4-1e80854f2304.png)

リファレンスにもある通り、Winの場合は「'Ctrl-Shift-E'」, Macの場合は「'Command-Shift-E'」がショートカットキーとして存在しています。

# まとめ
簡単ですが、AWS Lambdaの環境変数周りのアップデートでした。
正直、コンソールのコードエディタからLambda関数をいじることはそんなに無いとは思うのですが、便利になる系アップデートでした。
Jupyter notebookで使いたいpython libraryをインストールする

2年ぶりくらいにJupyter notebookを使おうとしたものの、やり方に困ってしまった。
ベストな方法かはわからない。

## 問題

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534442/48a9a425-5054-67e3-76f1-c59bdc30ba6e.png)

## 解決方法

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534442/29a75662-be07-fb9f-9c08-4327c40c0bba.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534442/1ce63b74-49e3-c6ee-9e89-29356c97adae.png)
grepでorで検索（プロセス置換）

# 実行結果を使ってOR検索したい

```プロセス置換```という用語を忘れて、なんて検索していいかわからなかったので、メモ。

[grepでOR検索](https://www.yoheim.net/blog.php?q=20160302#t3)と検索すると、
```bash
grep -e 【検索文字列】 -e 【検索文字列】 【ファイル名】
```
等が出てくる。実行結果で検索したい場合、```-e```が邪魔。

```-f```の[リスト検索](https://it-ojisan.tokyo/grep-f/)に、リダイレクトの結果を使いたかったけど、やり方と調べ方を忘れていたので、メモ

# 実行結果を使いたい(プロセス置換したい)
```<(command)``` をファイル名の代わりに使えばOK。やり方調べるのにキーワードがわからず、bashのヘルプから探し出しました。

# dockerのイメージから、コンテナがあるものを検索
がやりたかったこと。


```bash
 docker images | grep -f <(docker ps -a| awk '{print $2}'| sort -u)
```

とりあえず、メモとして残す。
AKS + helm + gitlab + gitlabrunner でのエラーと解決策

AKS上に、helm２を使用して、gitlab + gitlab runnerを構築した際に、詰まったことを記載する。

* 環境
    - AKS v１.24
        - Kubernetes RBAC ture
    - helm v2.１７.０
    - gitlab v不明
    - gitlab runner v16.0.2

## 問題１

~~~ powershell
 helm init
~~~

を実行後、helm list、helm install 実行時にエラーが発生する。
※ helm list, helm install 以外にもtillerからAKSへアクセスしようとするコマンド全てで同じエラーとなる。


実行例
~~~ powershell
$ helm install --name gitlab-shared-runner gitlab/gitlab-runner --set gitlabUrl=https://gitlab.example.com:32443/ --set privileged=true --set runnerRegistrationToken=xxxxxxxxxxxxxxx
Error: release gitlab-shared-runner failed: namespaces "default" is forbidden: User "system:serviceaccount:kube-system:default" cannot get resource "namespaces" in API group "" in the namespace "default"
~~~

### 解決策

tillerの権限不足が原因で、エラーが出ている。
helm initを実行する際に、適切な権限が付与されたサービスアカウント名を指定して実行する必要がある。

参考URL

https://www.skyarch.net/blog/helmgke%E3%81%AA%E3%81%A9rbac%E3%81%8C%E6%9C%89%E5%8A%B9%E3%81%AA%E7%92%B0%E5%A2%83%E3%81%A7helm%E3%82%92%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B%E3%81%AB%E3%81%AF%EF%BC%9F/

コマンド例

~~~ powershell
helm init --service-account helm
~~~


## 問題２

gitlab runner をデプロイしたのに、CIを実行しても「pending」のままJobが開始されない。
runnerは登録されているはずなのに、CI上からは「実行可能なrunnerがない」と言われる。

### 解決策

AKSやgitlabの設定の問題ではなく、gitlab runner の helm Chartが誤っている可能性が高い。
value.yamlを最小構成で実行し直してみるなど、Chartの修正を行ってみるのが良い。


## 問題３

gitlab からCICDを実行した際、30秒ほど接続中の後、エラーが発生する。

~~~ powershell
Running with gitlab-runner 16.0.2 
  on kubernetes-runner
Preparing the "kubernetes" executor
Using Kubernetes namespace: gitlab-runner
Using Kubernetes executor with image ubuntu:16.04 ...
Using attach strategy to execute scripts...
Preparing environment
ERROR: Job failed (system failure): prepare environment: setting up credentials: Post "https://172.30.0.1:443/api/v1/namespaces/default/secrets" dial tcp 172.30.0.1:443: i/o timeout. Check https://docs.gitlab.com/runner/shells/index.html#shell-profile-loading for more information
~~~

### 解決策？

gitlab runnerからkubernetes APIに接続しに行くところで落ちていると思われる。
hostの接続先をvalue.yamlにて指定することで解消可能と思われる。が、未確認です。
macを初めて買って思うこと

# 筆者のガジェット歴
* 高校生時代に初めて家にデスクトップPCが設置される
OSはWindows7
* 初スマホも高校生時代
当然のごとくAndroid（そこからずっとAndroid）
* 大学生ではクソデカノートPCを購入
OSはWindows8
* 同じく大学生時代にバイト代を貯めてiPad Airを購入
* 研究室・大学院生時代で、Linuxを少し触る
* 社会人になってからはChromeBookを購入

そんな感じで一応iOSは触ったことあるけど、基本的にはごりごりWindows&Androidユーザーの筆者がこの度初Mac、Macbook Airを購入した。
そこで驚いたこととか感動したこととかを書き綴る。

# 初期設定が終わるまで
まずPCを開くと、

__ジャーーーーーーーーーーーーーーーーン！！！！！！！！！！！！！！！！！！！w__

という爆音。
心臓が止まりかけた。
Youtubeの『おすすめ初期設定』みたいな動画を見ながら恐る恐る設定をいじる。
画面下部のDockなるものを小さくして、マウスオーバーしたときだけ拡大するように設定したらなんかすごくMacっぽさが出てきた。いいぞ。
次に忌まわしきCaps Lockを葬る設定を行う。
Windowsの場合、Ctrl2Capという公式ソフトにいつもお世話になっていたのだが、Macの場合システム設定からcaps lockの割り当てを変更できる。
commandというキーをコピペする際に使用するらしいので、caps lockにはcommandになってもらった。
あとはトラックパッドの設定。
タップで反応するようにしたり、3本指でドラッグできるようにしたり。
この辺はChromebookでのジェスチャー操作に近かったのですぐに慣れることができた。

# 驚いたこと
### ウィンドウの共通操作がwindowsと全部違う
フルスクリーンにしようとしたら別の仮想デスクトップになるし、最小化しようとしたらDockの右側に吸い込まれていくし、✗で閉じたと思っても実は裏で動いてたりする。

### メニューバーの仕様
Windowsの場合、アプリケーションの上にメニューバーがくっついてる。
一方Macの場合、メニューバーは画面上部に張り付いていて、その内容がアクティブなアプリケーションによって変わる。

# 感動したこと
### Touch IDの精度が高い
完全に個人の体感だが、他のノートPCの指紋認証よりも精度が高く、失敗する頻度が低い気がする。

### ホームディレクトリがUnixライク
MacOSがUNIXをベースとしているので当たり前なのだけど、ホームディレクトリ構成が同じくUNIXをベースとしているLinuxと似ている。
馴染みやすいし、コマンドラインも使いやすい。
<details><summary>2023/07/13 コメントのご指摘より訂正</summary>

~~MacOSがLinuxをベースとしているので当たり前なのだけど、ホームディレクトリがめちゃめちゃLinux。~~
</details>


### 時間表示が見やすい
Windowsだとアプリのショートカットと時間表示がタスクバーという形で一体となっている。
そのため画面を広く使いたいと思ってタスクバーを非表示にすると時間が見えなくなってしまう。
MacだとDockとメニューバーという形で分離しているため、作業スペースを確保しながら必要な情報を見ることができる。

# さいごに
XCodeでMacOS/iOS向けアプリを開発できることが、Macの強みだと思うので、次回はXCodeを使ってみた感想でもあげようかと思う。
実は、無料のSSL証明書がある

# 以下のような株アプリを作ってる

https://stonehills.tokyo/financer/

## SSL証明書 の種類</p>

SSL証明書にはVerisignやGeoTrustといったものが
有名だが、実は無料の証明書がる。

その名も Let's Encrypt (SSL暗号化しましょう）

certbotという名称のパッケージで配布されている

<!-- wp:heading -->
<h2 class="wp-block-heading">certbotインストール</h2>
<!-- /wp:heading -->

<!-- wp:preformatted {"fontSize":"small"} -->
<pre class="wp-block-preformatted has-small-font-size">$ sudo apt install -y certbot</pre>
<!-- /wp:preformatted -->

<!-- wp:heading -->
<h2 class="wp-block-heading">証明書作成(自己証明書)</h2>
<!-- /wp:heading -->

<!-- wp:preformatted {"fontSize":"small"} -->
<pre class="wp-block-preformatted has-small-font-size">$ sudo certbot certonly --webroot -w /var/www/html -d &lt;domain_name>
  &lt;mail address>
</pre>
<!-- /wp:preformatted -->

<!-- wp:heading -->
<h2 class="wp-block-heading">ApacheへのSSL設定</h2>
<!-- /wp:heading -->

<!-- wp:preformatted {"fontSize":"small"} -->
<pre class="wp-block-preformatted has-small-font-size">$ sudo vi /etc/apache2/sites-available/default-ssl.conf

SSLCertificateFile      /etc/letsencrypt/live/&lt;domain_name>/cert.pem
SSLCertificateKeyFile   /etc/letsencrypt/live/&lt;domain_name>/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/&lt;domain_name>/chain.pem
</pre>
<!-- /wp:preformatted -->

<!-- wp:heading -->
<h2 class="wp-block-heading">SSL有効化</h2>
<!-- /wp:heading -->

<!-- wp:preformatted {"fontSize":"small"} -->
<pre class="wp-block-preformatted has-small-font-size">$ sudo a2ensite default-ssl
$ sudo a2enmod ssl
$ sudo systemctl restart apache2</pre>
<!-- /wp:preformatted -->

このサイト、letsencrypt使ってるよ

https://stonehills.tokyo/financer
[Symbol]timestampから日時を取得したい！

この記事は以前NEMLOGで投稿した記事を加筆したものです。
内容自体は大事だと思うので自分用のメモとして残しておきます。

## はじめに
SymbolブロックチェーンのCatapult RESTを使ってブロックの日付を取得したいと思ってハマったことについて書こうと思います。


## timestampから日付を取得したい！
まずは[SymbolBlockExplorer](https://symbol.fyi/blocks/1)を使って1番目のブロックを確認してみると「Timestamp」に「2021-03-16 09:06:25」が表示されています。
なのでCatapult RESTを使えば簡単に日付を取得できると思ったのが間違いの始まりでした。。

まずは、
SymbolのリファレンスとAPIドキュメントを参考にしてURLを作成して叩いてみます。
↓
[https://symbolnode.blockchain-authn.app:3001/blocks/1](https://symbolnode.blockchain-authn.app:3001/blocks/1)

叩いてみると様々な情報が表示されると思いますが、今回は"timestamp"に注目します。

**"timestamp":"0"**

期待していた値と大分違います。。"2021-03-16 09:06:25"みたいなのが返ってくると思ってました。。
というか"0"ってなに？？？

## 日付を取得するにはネメシスブロックのタイムスタンプが必要
"timestamp":"0"について調べていくと目指せ北海道さんの記事に答えがありました！
(NEMLOGの記事なのでリンクは張りません。。一部引用します。)

>タイムスタンプ（timestamp）は、ネメシスブロックからの時間経過を示し、ミリ秒単位で計算される。

なるほど。先程上で叩いたURLがネメシスブロックだったためにタイムスタンプが"0"だったんですね。

余談ですが**ネメシスブロック**って何？って思って調べ始めました。。
1番目のブロックのことですね！カッコいい言い方すると「原初のブロック」です。
他のチェーンでは**ジェネシスブロック**と呼ばれるものですね。

さて、ここまでわかったのでネメシスブロックのタイムスタンプがいつなのかを調べる必要があります。
[SymbolBlockExplorer](https://symbolnode.blockchain-authn.app:3001/blocks/1)を開いて「Symbol Time」に表示されている「**1615853185**」をメモっておきます。
これがネメシスブロックのタイムスタンプです。

ちなみにテストネットの場合は「1667250467」です。値が違うのでお間違えなきよう。。

「1615853185」はUTC秒と呼ばれるものなので日付に変換すると「2021-03-16 09:06:25」になります。
これがタイムスタンプの基準となります！ここまで調べるのにまる１日かかりました。。

あとは適当なブロックのタイムスタンプを計算すればOKです！
試しにブロック:90000で確認してみます。
↓
http://localhost:3000/blocks/90000

timestampの値は「2785638884」です！単位はミリ秒です。
先程メモっておいたSymbol Time「1615853185」は単位が秒なのでミリ秒に直します。
1615853185 * 1000 = 1615853185000

timestampの値にネメシスブロックのタイムスタンプを足します。
2785638884 + 1615853185000 = **1618638823884**
これを日付に直せば「**2021-4-17 14:53:43:884**」となります。
日付に直すためのツールは[https://yu-yum.net/epoch/](エポックミリ秒こんばーた)を使用させていただきました。

さて、実際に[https://symbol.fyi/blocks/90000](SymbolBlockExplorer)を確認してみましょう！
Timestampには「2021-4-17 14:53:44」が表示されていますが多分四捨五入されているのでしょう。。
変換手順自体はこれで問題ないはずです。

## まとめ
Symbol-sdk v2系が非推奨（deprecated）になっているため、Catapalt REST APIを使って情報を取得したい人が増えてくると思いますが、timestampの件はハマりそうだなと思うのでメモで残しておきます。

この記事が誰かの役に立ちますように……(/･ω･)/
3dsMaxでテスクチャを貼る方法

やり方忘れないためのメモです(Max2021です)
<br>
<br>
Material Editorを開く(Mキーでショートカット)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843707/27de145a-da1b-ddf3-de3c-ddbd917e2f99.png)
↓
Generic Maps
↓
Base Color
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843707/29702579-a703-9d4f-4d2a-7e5a3d43a9af.png)
↓
 Bitmap Parameters
↓
Bitmap
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2843707/162816e1-c335-507c-b954-40bc7d8d4f97.png)
あとはフォルダが開くのでテスクチャのファイルを選択すればおｋ
<br>
<br>
<br>
参考にさせていただきました↓
https://www.ipentec.com/document/3ds-max-set-image-texture-to-geometory-objects
個人的Pythonプロジェクト作成手順（VSCode, Poetry, flake8, black, isort）

# 個人的Pythonプロジェクト作成手順

新しくプロジェクト（リポジトリ）を作成したいときにやることをまとめておく記事です。変更があったらなるべく更新していきたいと考えています。

パッケージ管理をPoetryで行い、VSCodeでLinter, Formatter (flake8, black, isort) を使用する設定を行うことで、ファイルの設定を行ったときに自動でコード整形等が走るようにします。

あくまでプロジェクト作成時に行う作業について記述するため、PythonやPoetryのインストールについては（ほとんど）触れません。

## 使用するモジュール
仮想環境、パッケージ管理
- Poetry

formatter
- black
- isort

Linter
- flake8

エディタにはVSCodeを使用します。
上記のformatter, linterの設定も記述します。

## Poetryプロジェクトの作成
```
# 新規プロジェクト
poetry new <project name>
# 既存プロジェクトに追加
poetry init
```
initの場合はプロジェクト名やら互換性のあるPythonバージョンの指定やら聞かれる。

＊PythonのバージョンはOSにインストールされているPythonが使用される。
指定したい場合は事前にバージョンを合わせておく。
私の場合はanyenv + pyenvを使用

```
# 新しいバージョンのインストール
pyenv install <Pythonのバージョン>
# 使用するバージョンの指定
pyenv global <Pythonのバージョン>
```

## 仮想環境の作成
VSCodeを使用する場合、仮想環境作成前に以下の設定をしておく
```
poetry config virtualenvs.in-project true --local
```
この設定をしておくことで、仮想環境がプロジェクトと同じディレクトリに作成されるため、
VSCodeがPythonのインタプリンタを認識してくれる。
localオプションをつけることでその設定がプロジェクト内のpoetry.tomlファイル内に記述され保存される
（github等を使用して別PCで作業する時でも同様の設定が引き継がれる）。

仮想環境作成は以下のコマンド
```
poetry install
```




## 依存パッケージの追加
```
poetry add <package name>

# 開発用パッケージ　
poetry add -D <package name>
```

ここでlinter, formatterをインストールしておく。
```
poetry add -D flake8 black isort
```

## VSCodeの設定
以下の拡張機能をインストール
- Black Formatter
- Flake8
- isort
- Python

vscodeのsetting.jsonに下記を記述。
```json
{
  "editor.formatOnSave": true,
  "python.formatting.provider": "none",
  "python.linting.flake8Enabled": true,
  "editor.codeActionsOnSave": {
    "source.organizeImports": true
  },
  "python.linting.flake8Args": [
    "--max-line-length",
    "150",
    "--ignore=W293 E203"
  ],
  "editor.formatOnType": true,
  "[python]": {
    "editor.defaultFormatter": "ms-python.black-formatter",
    "editor.formatOnSave": true
  }
}
```


## 仮想環境で実行
```
poetry run python <python file>
or
poetry shell
python <python file>
```

下はpoetry 仮想環境のシェルを立ち上げる。


## 参考
https://qiita.com/ksato9700/items/b893cf1db83605898d8a

https://medium.com/music-and-technology/poetry%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%A8%E4%BB%AE%E6%83%B3%E7%92%B0%E5%A2%83%E4%BD%9C%E6%88%90%E5%85%88%E3%81%AE%E5%A4%89%E6%9B%B4-96e1bab83725#:~:text=%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88%E3%81%A0%E3%81%A8%E4%BB%AE%E6%83%B3%E7%92%B0%E5%A2%83,virtualenvs%2F%60%20%E3%81%AB%E4%BD%9C%E3%82%89%E3%82%8C%E3%82%8B%E3%80%82
【Python】勤怠入力アプリ作成

勤怠入力のデスクトップアプリを簡易的に作成しました。
随時、更新をしていきます。

### 入力前
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759758/4c30934a-9d63-8c6b-22d8-ee0feb7425e9.png)

### 入力後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759758/0380ecb9-a87d-636e-d1bb-8d3cc834f75b.png)

### ソース
```python
import tkinter
from datetime import datetime

def days_func():
    '''日付を取得しラベルにセットする。'''
    import datetime
    t_delta = datetime.timedelta(hours=9)
    JST = datetime.timezone(t_delta, 'JST')
    now = datetime.datetime.now(JST)
    d_week = {'Sun':'日', 'Mon':'月', 'Tue':'火', 'Wed':'水', 'Thu':'木', 'Fri':'金', 'Sat':'土'}
    key = now.strftime('%a') # 曜日を取得
    w = d_week[key] # 辞書で値を取得。
    days_today = now.date().strftime('%Y/%m/%d') # 指定したformatに従って日時の文字列を返す。
    lbl_days = tkinter.Label(text=str(days_today + str(f' ({w})')))
    lbl_days.place(x=10, y=20)

def btn_click():
    total_value.delete(0, tkinter.END) 
    start = start_value.get()
    last = last_value.get()
    rest = rest_value.get()
    FMT = '%H:%M:%S'
    tdelta = datetime.strptime(last, FMT) - datetime.strptime(start, FMT)
    tdelta_cgange = str(tdelta)
    tdelta_1 = datetime.strptime(tdelta_cgange, FMT) - datetime.strptime(rest, FMT)
    total_value.insert(0, str(tdelta_1))

def btn_clear():
    """
    テキストに入力された値を削除
    """
    start_value.delete(0, tkinter.END) # 削除の処理
    last_value.delete(0, tkinter.END)
    rest_value.delete(0, tkinter.END)
    total_value.delete(0, tkinter.END)

# 画面作成
tki = tkinter.Tk()
tki.geometry('450x350')
tki.title('勤怠入力')
tki.configure(bg='SpringGreen2')
# メッセージを表示
lbl_massage = tkinter.Label(text='勤務時間を入力して下さい。')
lbl_massage.place(x=150, y=60)

days_func()

start_lbl = tkinter.Label(text='出勤時間')
start_lbl.place(x=50, y=100)
last_lbl = tkinter.Label(text='退勤時間')
last_lbl.place(x=50, y=130)
rest_lbl = tkinter.Label(text='休憩時間')
rest_lbl.place(x=50, y=160)
total_lbl = tkinter.Label(text='労働時間')
total_lbl.place(x=50, y=190)

# テキストボックス
start_value = tkinter.Entry(width=30)
start_value.place(x=140, y=100)
last_value = tkinter.Entry(width=30)
last_value.place(x=140, y=130)
rest_value = tkinter.Entry(width=30)
rest_value.place(x=140, y=160)
total_value = tkinter.Entry(width=30)
total_value.place(x=140, y=190)

# ボタン
btn = tkinter.Button(tki, text='合    計', font=("MSゴシック", "10", "bold"), fg="red", relief= "ridge",command=btn_click)
btn.place(x=170, y=220)
btn = tkinter.Button(tki, text='ク リ ア', font=("MSゴシック", "10", "bold"), fg="red", relief= "ridge", command=btn_clear)
btn.place(x=170, y=260)

tki.mainloop() # アプリを起動
```
chatGPTを用いてpythonでテキスト＋イメージを新規イメージ保存

## はじめに

pythonをchatGPTを用いてコードを書かせる。
プロンプトエンジニアリングを実際に使用することで向上させたいと思っています。

## 目的

常に目的は同じです。自動化推進です。
楽したいは正義でしょう。

## 今回

画像にテキストを埋め込みそのまま画像として保存したい。
chatGPTへ出力依頼。

```
プロンプト参考.txt

//当方メモレベルです。。
pythinでテキスト　AAAA　とpngファイルをまとめて画像として保存するプログラムを記述してください。
なお上記コードで各処理を関数で処理するようにプロのコーダのように記述してください。また適切なコメントアウトをおこないより可読性に優れたコード構成をしてください
またデバッグしやすいようにデバッグプリント関数を追加してください
```

非常に適当ですね。（いやいい塩梅です。このぐらいでいいのです。）
結果が大事です。出力しながら学習しましょう。

## 出力結果

```
text_plus_image.py

from PIL import Image, ImageDraw, ImageFont

# テキストとPNG画像を組み合わせて画像として保存する関数
def create_image_with_text(text, image_path, output_path):
    # 画像の読み込み
    image = Image.open(image_path)

    # 画像にテキストを描画する
    draw = ImageDraw.Draw(image)
    font = ImageFont.truetype("arial.ttf", 24)  # フォントとサイズを指定する
    text_width, text_height = draw.textsize(text, font=font)
    text_position = ((image.width - text_width) // 2, (image.height - text_height) // 2)
    draw.text(text_position, text, font=font)  # テキストの位置と色を指定する

    # 画像を保存する
    image.save(output_path)

    # デバッグプリント関数
    print("画像が保存されました:", output_path)


# メインの処理
def main():
    text = "test"
    image_path = "image.png"
    output_path = "output.png"

    create_image_with_text(text, image_path, output_path)


if __name__ == "__main__":
    main()
```

今回もなかなかいい速度で対応してくれました。
ここまで3分。しかしエラーが発生するので、
すこし修正しましょう

## 修正箇所
・フォントの指定
どうやら前もありましたが、フォント指定は下手くそ？
font = ImageFont.truetype("arial.ttf", 24)
これでOKでした。

・色の値がうんたらかんたら・・
潔くここは削除（今回は不要だったため）
問題なく動作。

最終的に約10分でOK。実際はここから融合させたため
もう少しかかりますが、十分ヒントがあるため
問題なく融合も完了

## 雑感
やはりchatGPTは優秀です。
どんどんコーディングも進むし、コメントも的確、可読性も良い。
何よりコードの記述方法に迷いがあったが逆にAIがしてくれることで
これをコピーすれば、あまりに変なコードにはならない（だろう。。

OUTPUTを継続していきましょう。
go + dockerでホットリロード機能を付ける

[DockerでGo言語の開発環境を作る方法](https://qiita.com/tkms13/items/74a9ea4b41302323c4b1 "go docker")でDocker+goの開発環境を作りました。今回はさらにホットリロード機能をつけていきます。
# Dockerfileを修正
まず、Dockerfileに変更を加えていきます。Dockerfileの中身は以下の記事で取り上げたものをベースにしています。

https://qiita.com/tkms13/items/74a9ea4b41302323c4b1

```docker
FROM golang:1.19.1-alpine3.16![スクリーンショット 2023-07-08 202755.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3439167/54c6704b-3ded-2479-6c9e-b478adf86990.png)


WORKDIR /app

COPY backend/go.mod .
COPY backend/go.sum .
COPY backend/*air.toml .

RUN go mod download
RUN apk add --no-cache gcc
RUN apk add --no-cache musl-dev

COPY ./backend .

RUN go install github.com/cosmtrek/air@latest

CMD ["air"]
# CMD ["go", "run", "./cmd/api"]
```
# .air.tomlを作成
次に以下の場所に.air.tomlを作成します。

project
├backend
│ └Dockerfile
│ └.air.toml　←新規作成
│ └cmd/
│ 　└─api/
│ 　　└─main.go
└docker-compose.yml

.air.tomlは以下のとおりです。

```
# .air.toml
# Config file for [Air](https://github.com/cosmtrek/air) in TOML format

# Working directory
# . or absolute path, please note that the directories following must be under root.
root = "."
tmp_dir = "tmp"

[build]
# Just plain old shell command. You could use `make` as well.
cmd = "go build -o ./tmp/main ./cmd/api"
# Binary file yields from `cmd`.
bin = "tmp/main"
# Customize binary.
full_bin = "APP_ENV=dev APP_USER=air ./tmp/main"
# Watch these filename extensions.
include_ext = ["go", "tpl", "tmpl", "html"]
# Ignore these filename extensions or directories.
exclude_dir = ["assets", "tmp", "vendor"]
# Watch these directories if you specified.
include_dir = []
# Exclude files.
exclude_file = []
# This log file places in your tmp_dir.
log = "air.log"
# It's not necessary to trigger build each time file changes if it's too frequent.
delay = 1000 # ms
# Stop running old binary when build errors occur.
stop_on_error = true
# Send Interrupt signal before killing process (windows does not support this feature)
send_interrupt = false
# Delay after sending Interrupt signal
kill_delay = 500 # ms

[log]
# Show log time
time = false

[color]
# Customize each part's color. If no color found, use the raw app log.
main = "magenta"
watcher = "cyan"
build = "yellow"
runner = "green"

[misc]
# Delete tmp directory on exit
clean_on_exit = true
```
以上で準備は終了です。

# 起動する
以下のとおりのコマンドを実行します。
```
docker compose build
```

```
docker compose up
```
以下のような表示がされれば成功です。
![スクリーンショット 2023-07-08 202755.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3439167/d089d495-8064-de47-0335-94d639981c9d.png)


# 参考資料
https://github.com/cosmtrek/air/tree/master

https://zenn.dev/ajapa/articles/bc399c7e4c0def
【個人開発】一番簡単なアプリアイコンの作り方

# はじめに
アプリアイコンは、アプリの顔とも言える重要な要素です。この記事では、アプリアイコンを簡単に作る方法を紹介します。

# 作り方
私は大抵、Keynoteでアプリアイコンを作ります。画像編集ソフトの多くは多機能ですが、Keynoteは最小限の機能しかなく使うハードルがとても低いです。

## サイズを設定する
iOSアプリのアイコンに必要な最大サイズは、1024x1024です。Keynoteでサイズを設定するには、以下の手順を踏みます。

1. ツールバーの「書類」をクリック
2. 「スライドサイズ」を「カスタムのスライドサイズ...」に変更
3. 幅と高さを1024に設定

![スクリーンショット 2023-07-10 21.33.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366249/23bb41cb-2046-68ff-d239-a25f72254883.png)

![スクリーンショット 2023-07-10 21.33.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366249/490d51c2-008f-9076-1af0-1c6673d3825a.png)


## 不要なテキストボックスを削除する
デフォルトで配置されているテキストボックスを削除します。

## 背景をグラデーションにする
背景をグラデーションにすることで、目立ちやすくなります。グラデーションの設定は、以下の手順を踏みます。

1. ツールバーの「フォーマット」をクリック
2. 「現在の塗りつぶし」を「グラデーション塗りつぶし」に変更
3. 好きな色を選択

![スクリーンショット 2023-07-10 21.55.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366249/2be95409-ac3a-9673-ddb9-174d5c79c1a2.png)

## 図形を配置する
Keynoteには、様々な図形が用意されています。これらを組み合わせて、アプリアイコンを作ります。この時に、ツールバーの「表示」から「オブジェクトリスト」を表示すると、図形の重ね順の変更がやりやすくなります。

![スクリーンショット 2023-07-10 21.56.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366249/a1c8e8c9-67d7-68b0-94d5-3225da017c2d.png)

## 影をつける
影をつけることで、立体感が出て目立ちやすくなります。影の設定は、以下の手順を踏みます。

1. 影をつけたい図形を選択
2. ツールバーの「フォーマット」をクリック
3. 「シャドウ」を「ドロップシャドウ」に変更
4. 好きな影の設定を設定

影の色には黒は使用せず、背景色に似た色で暗い色を使用すると、自然な仕上がりになります。

![スクリーンショット 2023-07-10 21.56.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366249/1ba74ffb-a45d-4790-a59e-620ffef421e5.png)

## Xcodeでアプリアイコンを設定する
Keynoteのサイドバーから、スライドをXcodeのAssets.xcassetsのAppIconにドラッグ&ドロップします。するとスライドが画像に変換されて、アプリアイコンに設定されます。とても簡単ですね。

![video_20230710-1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366249/da9042be-c300-c1ad-a9f4-e2cf81f8e5a7.gif)

# おわりに
アプリアイコンを簡単に作る方法を紹介しました。この記事が参考になったという方は、いいね❤️とTwitterのフォローしていただけると嬉しいです😆
Linux 版 Unity Editor で UI表示がおかしくなったときメモ


## こんな現象にハマっていませんか？

* Unity Editor でタブ内のテキストが妙にボヤケている。ウィンドウのメニュー (File/Edit/Asset/...) は鮮明なのに。
* Unity Editor の Play ボタンが表示されていない。だけど Play ボタンがありそうな場所をクリックすると、Playモードに入れる。
* 一旦ゲームして落ち着こう！と思ったが、Steamも起動しない。

この投稿は、そのような現象に陥った私が復旧するまでにたどった調査メモです。
それぞれのシステムの設定や状態によっては、この解決策が必ずしも適切でないことにご注意ください。

## 環境

* Ubuntu 22.04
* NVIDIA GeForce 3060
* Unity Editor 2022.3.4f1, 2021.3.4f1


## GPUのドライバーは正しく読み込まれていますか?

私の場合はこれが原因でした。GPUの状態を確認したら、そもそもGPUを読み込めていないことがわかりました。
例えば、NVIDIA の GPUの場合には、`nvidia-smi` コマンド等でこれを知ることができます。

```zsh
% nvidia-smi
NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.
```

## 最近何かをアップデートしませんでしたか?

最近のパッケージ変更履歴は、dpkg.logに記録されています。

```zsh
% cat /var/log/dpkg.log
2023-07-01 09:20:43 startup archives unpack
2023-07-01 09:20:43 upgrade accountsservice:amd64 22.07.5-2ubuntu1.3 22.07.5-2ubuntu1.4
2023-07-01 09:20:43 status half-configured accountsservice:amd64 22.07.5-2ubuntu1.3
2023-07-01 09:20:43 status unpacked accountsservice:amd64 22.07.5-2ubuntu1.3
2023-07-01 09:20:43 status half-installed accountsservice:amd64 22.07.5-2ubuntu1.3
︙
```

私の場合には、Linuxカーネルがアップグレードされたことで、NVIDIAのドライバーの読み込みに失敗していたようでした。

```zsh
% awk '$3 == "install" {print $1 " " $4"="$5}' /var/log/dpkg.log
︙
2023-07-08 linux-signatures-nvidia-6.0.0-1018-oem:amd64=$5
2023-07-08 linux-signatures-nvidia-6.1.0-1015-oem:amd64=$5
︙

% awk '$3 == "upgrade" {print $1 " " $4"=""$5"}' /var/log/dpkg.log
︙
2023-07-08 linux-signatures-nvidia-6.0.0-1018-oem:amd64=$5
2023-07-08 linux-signatures-nvidia-6.1.0-1015-oem:amd64=$5
︙

% uname -r
6.1.0-1015-oem
```



## カーネルを戻して解決

とりあえず、過去のカーネルに戻してみます。

まず、過去のカーネルで起動するように、Grubを編集して、

```/etc/default/grub
/etc/default/grub  
# If you change this file, run 'update-grub' afterwards to update
# /boot/grub/grub.cfg.
# For full documentation of the options in this file, see:
#   info -f grub -n 'Simple configuration'

GRUB_DEFAULT=0
# GRUB_TIMEOUT_STYLE=hidden # ** Grub を非表示にする設定を無効化 **
GRUB_TIMEOUT=5              # ** PC起動時にGrubを5秒間表示する  **
︙

% sudo update-grub
```

再起動後のメニューで Advanced Option -> もともと使っていたカーネルを選択して起動します。
※ わからない場合は、リストの下の方にある (recovery) がついていないカーネル


起動できたら、新たにインストールされたカーネルを削除して、nvidiaのドライバーを再インストール

```zsh
% sudo apt remove linux-image-6.1.0-1015-oem
% sudo apt autoremove
% sudo apt install nvidia-driver-535
```

これで、Unity Editor UI も Steam も正常になりました。
UITabBarについてのメモ

SwiftでUITabBarのアイコン選択時にアイコンの色と大きさの変更、タイトルを太字にする方法

１. UITabBarControllerDelegateをクラス宣言に追加する。
→UITabBarのアイテムが選択されたときに通知を受け取ることができるようになる。

```swift
class ViewController: UIViewController, UITabBarControllerDelegate {
}
```

２. UITabBarControllerDelegateのメソッド`tabBarController(_:didSelect:)`を実装する。
このメソッドは、タブバーのアイテムが選択されたときに呼び出される。

```swift
class ViewController: UIViewController, UITabBarControllerDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // UITabBarControllerのdelegateを設定
        tabBarController?.delegate = self
    }
    
    func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
        // 選択されたタブのインデックスを取得
        if let selectedIndex = tabBarController.viewControllers?.firstIndex(of: viewController) {
            // タブバーのアイテムを取得
            if let tabBarItem = tabBarController.tabBar.items?[selectedIndex] {
                // 選択時のアイコンの色を変える
                tabBarItem.selectedImage = tabBarItem.selectedImage?.withTintColor(.red)
                
                // アイコンのサイズを変更
                let iconSize = CGSize(width: 30, height: 30) // 好みのサイズに変更してください
                tabBarItem.selectedImage = tabBarItem.selectedImage?.scaled(to: iconSize)
                
                // タイトルを太字にする
                tabBarItem.setTitleTextAttributes([NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 12)], for: .selected)
            }
        }
    }
}

extension UIImage {
    func scaled(to size: CGSize) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
        defer { UIGraphicsEndImageContext() }
        draw(in: CGRect(origin: .zero, size: size))
        return UIGraphicsGetImageFromCurrentImageContext()
    }
}
```

- `tabBarController(_:didSelect:)`・・・選択されたタブのインデックスを取得し、対応するタブバーのアイテムを変更している。

- `tabBarItem.selectedImage = tabBarItem.selectedImage?.withTintColor(.red)`・・・アイコンの色を変更。ここでは赤色に変更している。

- `tabBarItem.selectedImage = tabBarItem.selectedImage?.scaled(to: iconSize)`・・・アイコンのサイズを変更。`iconSize`変数で指定したサイズに変更している。

- `tabBarItem.setTitleTextAttributes([NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 12)], for: .selected)`・・・タイトルを太字にしている。
PythonとBottleを使用してフォームの値を取得すると文字化けが発生する件の対処法

HTMLで書いたformの値を、PythonのBottleフレームワークを使用して取得した時、
文字化けが発生した。対処法についてメモ。

## コードについて
HTMLとPythonは以下の通り
```HTML
<form action="/add" method="POST">
	<input type="text" name="content">
	<input type="submit" value="送信する">
</form>
```
```Python
@route('/add', method="POST")
def add():
	content = request.forms.getunicode('content')  # ここに注目
	store(content)
	return redirect('/')
```

## 文字化けを直す方法
フォームの値を取得する時、`getall関数`を使用すると文字化けが発生した。
`getunicode`関数に変更すると、文字コードをutf-8に変換して取得できる。


## 参考サイト
https://thinkami.hatenablog.com/entry/2017/04/09/180835
manのインストール

https://www.opensourcetech.tokyo/entry/2018/12/03/man%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%EF%BC%88%E3%83%9E%E3%83%8B%E3%83%A5%E3%82%A2%E3%83%AB%EF%BC%89%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6

## RHELの場合(英語のman）
```
# yum install man-db man-pages
```

## 日本語 man（RHEL7 or 8以降は日本語manはない）
```
# yum install man-pages-ja
hardhatのバージョンによるスマコンのデプロイ方法の違い

## はじめに
hardhat v2.14.0まではethers.js v5系が使われていましたが、
hardhat v2.15.0からはethers.js v6系が使われ始めたようです。

ethers.jsのバージョンの違いにより、hardhatを使ったデプロイ方法が変わっているので、備忘録としてのメモです。

## hardhat v2.14.0まで

```javascript
const TestToken = await ethers.getContractFactory("TestToken");
const testToken = await Token.deploy("TestToken", "TES"); // 引数にConstructorに渡す値を指定できる
await testToken.deployed();
console.log("コントラクトアドレス: ", testToken.address);
```

## hardhat v2.15.0から

```javascript
const testToken = await ethers.deployContract("TestToken", ["TestToken", "TES"]); // 第二引数の配列で、Constructorに渡す値を指定
await testToken.waitForDeployment();
console.log("コントラクトアドレス: ", testToken.target);
```

## まとめ
ethers.jsのV6系も使って慣れていこうと思いました。
[小ネタ] mavenのdockerコンテナ「で」docker imageをビルドする。

小ネタです。

ビルド環境を配布したいときや、CI/CDでmavenを使うことってありますよね！
そんなとき便利なのが[maven - Official Image](https://hub.docker.com/_/maven)です。
ただ、ちょっと困るのがdocker imageをmavenで作成したいとき…
そんな時はdood (Docker outside of Docker)を使ってdocker imageをビルドすることができます！

例えば、下記のような書き方が出来ます。

これができる理由として
- doodはsockをマウントして、docker-cliをインストールするだけで使えること
- docker runでヒアドキュメントが使えること（`-i`オプションだけついていることが肝）

などがあげられます。

Dokerfileでもcommitでもdockerを入れて固めておくと便利です。

今回は、[fabric8io/docker-maven-plugin](https://github.com/fabric8io/docker-maven-plugin)の[run-java](https://github.com/fabric8io/docker-maven-plugin/tree/master/samples/run-java)をビルドしてみます。
~~とりあえず動けばというノリです~~
~~~
$ docker run -i --rm \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -e DEBIAN_FRONTEND=noninteractive \
    maven:3.8.6-openjdk-8 bash << EOC
su
apt-get update
apt install -y apt-transport-https ca-certificates curl gnupg 
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
sh -c 'echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian bullseye stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null'
apt update
apt install -y docker-ce-cli

# todo maven build
# .e.g.
# maven clean install ...

mvn -version
docker ps 
docker images

git clone https://github.com/fabric8io/docker-maven-plugin.git
cd /docker-maven-plugin/samples/run-java

mvn package docker:build
docker images 

EOC

...etc....
[INFO] DOCKER> [samples/dmp-sample-run-java:latest]: Created docker-build.tar in 60 milliseconds
[INFO] DOCKER> [samples/dmp-sample-run-java:latest]: Built image sha256:5f2ee
[INFO] DOCKER> samples/dmp-sample-run-java:latest: Removed dangling image sha256:33ee9
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  50.960 s
[INFO] Finished at: 2023-07-11T12:39:42Z
[INFO] ------------------------------------------------------------------------
REPOSITORY                    TAG                     IMAGE ID       CREATED                  SIZE
samples/dmp-sample-run-java   latest                  5f2ee4b8470a   Less than a second ago   479MB
...etc...

$ docker run -it --rm samples/dmp-sample-run-java
exec java -XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=40 -XX:+ExitOnOutOfMemoryError -cp .:/opt/* HelloWorld
Hello world !
~~~
【Django】Typeエラー「Object of type 'bytes' is not JSON serializable」の原因と解決方法

# エラー概要
Djangoで`TypeError　Object of type 'bytes' is not JSON serializable`が表示されました。本記事ではそのエラー対応について記載します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710373/5d69a74e-cc48-d5fd-c3e1-fe39e4f0d607.png)

# 前提
以下のコードがあるとします。

```python
def filter_company_rank(request):
    query_set = CompanyRank.objects.all()

    # フリーキーワードで検索する
        # 省略

    return get_list_data_table(query_set)

def get_list_data_table(query_set):
    
    data = query_set.select_related(
        'company_rank_id'
    ).values(
        'company_rank',
        'update_date',
        'update_user_id__username',
    )
    return JsonResponse(json.dumps(data))

def get_all_data(request):
    result = filter_company_rank(request)
    return result
```

上記のコードでは、フリーキーワードでユーザーが入力したキーワードがDBにあるかどうか検索して表示する関数を書いています。
ここで、`return JsonResponse(json.dumps(data))`のままだと上述のエラーが発生しました。

# 原因
原因は、QuerySetオブジェクトがデフォルトのJSONシリアライザによって直接シリアライズできなかったためです。
QuerySetとは、データベースからのクエリ結果を表すための特殊なオブジェクトで、以下のようなオブジェクトを指します。

```
<QuerySet [<CompanyRank: CompanyRank object (1)>]>
```

JSONシリアライザは通常、プリミティブなデータ型（整数、文字列、リストなど）や辞書形式のオブジェクトに対しては動作しますが、QuerySetオブジェクトはそのままではシリアライズできません。詳細は公式ドキュメントを参照ください。
    [json --- JSON エンコーダおよびデコーダ](https://docs.python.org/ja/3/library/json.html)

また、`json.dumps()`を使用した場合、`data`オブジェクトをJSON形式の文字列に変換することはできますが、そのままではシリアライズされたオブジェクトとして扱われません（ここがポイント）。

### シリアライズとは
データを直列化してバイト列やテキストなどの形式に変換すること。
Pythonの`json`モジュールを使用してオブジェクトをJSON形式にシリアライズする場合、シリアライズ可能なオブジェクトはJSONに変換できます。ただし、シリアライズ不可能なオブジェクトはエラーが発生します。

反対に、JSON形式のデータをPythonのオブジェクトや文字列に変換することをデシリアライズと言います。


# 解決策
QuerySetオブジェクトをリストに変換してからJSONレスポンスに渡すことで、シリアライズ可能なデータとして扱うことができます。

```py
return JsonResponse(json.dumps(data))
```

を

```py
return JsonResponse(list(data), safe=False)
```

にすると正常にレスポンスが返ってきます。

ちなみに、以下でも成功しました。

```py
return HttpResponse(json.dumps(list(data)), content_type='application/json')
```

ただし、`json.dumps()`の結果を文字列として直接返しています。また、`JsonResponse`は Django のビルトインのレスポンスクラスであり、自動的に正しい`Content-Type`ヘッダーを設定してくれますし、簡潔に記載できるので、`JsonResponse`の使用の方が推奨されると思います。

# 備忘録
## `non-dict objects to be serialized`が出た場合
以下の場合`In order to allow non-dict objects to be serialized set the safe parameter to False.`というエラーが発生します。

```py
return JsonResponse(json.dumps(list(data)))
```

これは、`JsonResponse`がデフォルトでは辞書型のオブジェクトを受け取り、それをJSON形式にシリアライズしてレスポンスとして返すためです。`safe`パラメータを`False`に設定することで、辞書以外のオブジェクトもシリアライズすることができるようになります。これにより、リストやクエリセットなどの辞書以外のオブジェクトも正常にシリアライズされます。

## 文字列をシリアライズできない他の例
以下は文字列をシリアライズできない例です。
冒頭と同じエラーがでます。

```py
 return JsonResponse(json.dumps(data), content_type='application/json')
```

```py
 return HttpResponse(json.dumps(data), content_type='application/json')
```

```py
 return HttpResponse(json.dumps(data))
```
Generative AI In Logistics 

急速に拡大する生成 AI の分野は、物流<を含む多くの業界に革命を起こす可能性があります。。 物流における生成 AI 市場の成長は、次の主要な成長要因によって促進されると予想されます。

正確な予測と在庫計画の需要

生成 AI を利用して製品の需要を予測することは、物流会社がサプライ チェーンを最適化し、在庫切れや過剰在庫を回避するのに役立ちます。 また、物流ルートやスケジュールの計画にも使用できるため、輸送コストが削減され、配達時間が短縮されます。

事前メンテナンスの要件

生成 AI を使用して機器の故障の可能性を予測できるため、物流会社は予防メンテナンスを計画し、予定外の停止を回避できます。 これにより、企業のコストが節約され、物流業務の信頼性が向上します。

より効率的でコスト効率の高い物流ソリューションに対する需要の高まり

物流業界は絶えず進化するため、コスト効率が高く、より迅速な物流ソリューションに対する需要が高まっています。 ルーティング、スケジュール設定、在庫管理などの物流タスクの多くは、生成 AI を利用して自動化でき、物流会社がこの需要に対応できるようになります。

クラウド コンピューティングの採用の増加

クラウド コンピューティングの人気が高まっており、物流分野で生成 AI を実装するためのプラットフォームが提供されています。 クラウド コンピューティングにより、物流企業は高価なハードウェアやソフトウェアに投資することなく、生成 AI モデルやアプリケーションにアクセスできるようになります。

物流における生成 AI の市場は、今後数年間で大幅に拡大すると予想されています。 正確な予測と供給計画の需要、予知保全の必要性、コスト効率が高くより迅速な物流ソリューションに対する需要の高まり、クラウド コンピューティングの採用増加が、この成長を促進する主な要因です。

前述の要因に加えて、物流における生成 AI 市場の成長は以下の要因によって促進されると予想されます。

拡大する電子商取引分野

電子商取引分野の拡大には、より効率的で信頼性の高い物流ソリューションが必要です。 注文処理、出荷、返品など、電子商取引の物流に関わる業務の多くは生成 AI によって自動化でき、物流会社がこの需要に応えることができます。

持続可能性をより重視

物流業界ではサステナビリティの重要性が高まっています。 生成 AI は、サプライ チェーンとフリート管理を最適化することで、物流企業が環境への影響を軽減するのに役立ちます。

テクノロジーの革新

テクノロジーの継続的な開発により、ますます洗練された生成 AI モデルの作成が可能になります。 これは、生成 AI を使用した倉庫や輸送ネットワークの仮想複製の作成など、物流における生成 AI の新しい応用につながります。

物流における生成 AI の市場は、物流業界を変革する可能性を秘めた急速に拡大している分野です。 正確な予測と供給計画に対する需要の増加、予知保全の要件、コスト効率が高くより高速な物流ソリューションに対する需要の増加、クラウド コンピューティングの採用の増加、電子商取引業界の成長、持続可能性の重視の高まり、および技術の進歩が主な要因です。 この成長の原動力となっています。

https://marketresearch.biz/report/generative-ai-in-logistics-market/
SQLite3のエラーの解決方法

pythonのBottleフレームワークを使用してデータベースの処理を書いた時、
エラーでハマったので記録として残す。

# near "(": syntax error　について
## エラー文
以下のようなエラーが出た。
```
sqlite3.OperationalError: near "(": syntax error
```

## 書いていた処理
```Python
# 既にデータベースとテーブルは作成済み
def store(content):
	conn = sqlite3.connect(dbname)
	c = conn.cursor()
	print(content)
	insert = 'insert into data(status) values(?)'  # ここがおかしい
	c.execute(insert, (content,))
:
:
```
## 原因
insert文の`into (data)`がおかしい。よくわからないコードを書いている。。。

## エラーの見方
`(`の近くでエラーが発生しているという意味なので、
`(`付近を確認して、変な書き方のコードがないか確認する。


# Incorrect number of bindings supplied...　について
## エラー文
以下のエラーが発生した。
```
Incorrect number of bindings supplied. The current statement uses 1, and there are 4 supplied.
```

## 書いていた処理
```Python
# 既にデータベースとテーブルは作成済み
def store(content):
	conn = sqlite3.connect(dbname)
	c = conn.cursor()
	print(content)
	insert = 'insert into data(status) values(?)'
	c.execute(insert, (content))  # ここがおかしい
:
:
```
## 原因
execute文がおかしい。正しくは以下の通り。
※`content`の後に`,`が必要。
```Python
c.execute(insert, (content,))
```

## エラーの見方
insert文の?の数と、execute文の第二引数に指定した値の数が合わないという意味。
プリペアードステートメント(?)を使用する場合、タプルで値を渡さないといけない。
**タプルの要素が1つの場合、末尾に`,`が必要！**


# 参考サイト
・insert文の書き方
　https://products.sint.co.jp/topsic/blog/sql-insert

・Incorrect number of bindings supplied...の対処法
　https://techracho.bpsinc.jp/baba/2010_07_16/2130

・プリペアードステートメントの書き方
　https://dev.classmethod.jp/articles/query-with-mysql-connector-python/

・要素が1個のタプルの解説
　https://note.nkmk.me/python-tuple-single-empty/
【Laravel】リソースコントローラーについて

## はじめに

アプリケーションを作成していく中で必要な考え方として

CRUD「クラッド」という考え方があります。以下の頭文字を取ってCRUDと呼ばれています。

| C | create | 新規作成 |
| --- | --- | --- |
| R | read | 表示 |
| U | update | 更新 |
| D | delete | 削除 |

リソースコントローラーは、CRUDを細かく以下のように７つに分けてURIやルート名などを自動で生成してくれるという機能になります。

| 動詞 | URI | メソッド名 | ルート名 | 名称 |
| --- | --- | --- | --- | --- |
| GET | /photos | index | photos.index | 一覧の表示 |
| GET | /photos/create | create | photos.create | 新規作成 |
| POST | /photos | store | photos.store | 保存 |
| GET | /photos/{photo} | show | photos.show | 表示 |
| GET | /photos/{photo}/edit | edit | photos.edit | 編集 |
| PUT/PATCH | /photos/{photo} | update | photos.update | 更新 |
| DELETE | /photos/{photo} | destroy | photos.destroy | 削除 |

Laravelリソースルーティングは、通常の作成、読み取り、更新、削除（”CRUD”）ルートを**１行のコードでコントローラに割り当てる**ことができます。

## コントローラを作成する方法

```php
php artisan make:controller PhotoController --resource
```

コントローラーを作成する時にオプションとして`--resource`というオプションを入力すると、自動的に必要なメソッドを作成してくれます。自動的に作成されるメソッドの表は先ほども表記しましたが以下になります。

## リソースコントローラーの表

| 動詞 | URI | メソッド名 | ルート名 | 名称 |
| --- | --- | --- | --- | --- |
| GET | /photos | index | photos.index | 一覧の表示 |
| GET | /photos/create | create | photos.create | 新規作成 |
| POST | /photos | store | photos.store | 保存 |
| GET | /photos/{photo} | show | photos.show | 表示 |
| GET | /photos/{photo}/edit | edit | photos.edit | 編集 |
| PUT/PATCH | /photos/{photo} | update | photos.update | 更新 |
| DELETE | /photos/{photo} | destroy | photos.destroy | 削除 |

## ルートは一行で記述できる

リソースコントローラーを作成した後にルート側も設定する必要があり、先ほどもお伝えしましたがルートを以下のように１行で書くことができます。

```php
use App\Http\Controllers\PhotoController;

Route::resource('photos', PhotoController::class);
```

## 以上

Laravelではリソースコントローラと表記されていています。

一般的にはRestfulと呼ばれています。

リソースコントローラーを使いこなせればアプリケーションを簡単に素早く的確に作成できるので興味がある方は使ってみてください。
ゲストログイン機能のパスワード生成でエラーが出た時の対処法

## はじめに
ゲストログイン時のパスワード生成の際に時折エラーが出るので
原因を追求し解決しました。

## 現状のコード
ランダム英数字でパスワードを生成したいと思い下記のコードを記述していました。
```ruby:
user.password = SecureRandom.urlsafe_base64
```
なぜエラーになるか原因を探すため`SecureRandom.urlsafe_base64`について
調べたところ、ランダムに、大文字英字、小文字英字、数字、<font color="Red">記号の-(ハイフン)」 
「_(アンダースコア)」</font>を生成していることに気づきました。
記号はバリデーションに含めてなかったため、パスワード内に記号が生成される度に
エラーが発生していました。

## 解決方法
* ランダム英数字混合のパスワードにしたい
上記内容で別表現の方法を見つけました。

```ruby:
user.password = SecureRandom.alphanumeric
```
`SecureRandom.alphanumeric`は、英数字62種類の中から、
ランダムに生成してくれます。
さらに、引数で文字列のサイズを指定できる。

```ruby:
user.password = SecureRandom.alphanumeric(8)
```
上記では引数に(8)を指定し文字列を8に指定しました。

## まとめ

`SecureRandom.urlsafe_base64`では記号も含まれることを知らず
エラー原因の解決に時間がかかり悩んでいましたが、
無事、解決ができました。
検索力は大事だなと改めて痛感しました。
【SwiftUI】TextでDateの範囲を表示する

# はじめに
Textに使ったことのない機能があったので使ってみました

# サンプルアプリ
![IMG_3399.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/fbba20a8-3bff-c7ec-5c14-ed54dbc90a07.png)

# 実装
```swift
import SwiftUI

struct ContentView: View {
    let tomorrow = Calendar.current.date(byAdding: .day, value: 1, to: Date())!

    let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: Date())!

    var body: some View {
        Text(yesterday...tomorrow)
    }
}
```

# おわり
知らない機能でした

# 参考記事
https://medium.com/devtechie/swiftui-4-text-view-deep-dive-part-1-671e8f8c9852
fmt.Printfの表示時にpanicしてもrecoverされる

# TL; DR

```go
package main

import "fmt"

type Foo struct{}

func (f *Foo) String() string {
	panic("boom")
}

func main() {
	fmt.Printf("%s", &Foo{})
}
```

```:結果
%!s(PANIC=String method: boom)
```

# はじめに

おなじみ `fmt.Printf` では、 `%s` を使うことで文字列形式で値を出力できます。
`%s` は、`string` や `[]byte` だけでなく、**`Stringer` の実装（`String() string` メソッドを実装している型）に対しても使用可能**です。Stringerを `%s` すると自動的に `String` が呼び出され文字列化されてから出力されます。

# Stringがpanicしたら？

ここで、`String` メソッド内でpanicした場合の挙動が冒頭のコードです。

```go
func (f *Foo) String() string {
	panic("boom")
}

func main() {
	fmt.Printf("%s", &Foo{})
}
```

panicが発生するため文字列は得られませんが、代わりにエラーメッセージが表示されます。この際、**fmt.Printf自体は成功しています**。

```:結果
%!s(PANIC=String method: boom)
```

別の値を一緒に表示してみると分かりやすいです。
panicはせず、panicした際のエラーメッセージが `%s` の部分に出力されています。どうやら内部で recoverされて処理が継続しているようです。

```go
func main() {
	fmt.Printf("%s: %s", "print foo struct", &Foo{})
}
```

```
print foo struct: %!s(PANIC=String method: boom)
```

# 処理系の実装を見に行く

裏を取るために `fmt` パッケージを読みます。

`fmt.Printf` で `%s` 形式で Stringerを出力すると、この分岐に入ります。

https://cs.opensource.google/go/go/+/refs/tags/go1.20.5:src/fmt/print.go;l=672

```go
// ...
case Stringer:
	handled = true
	defer p.catchPanic(p.arg, verb, "String")
	p.fmtString(v.String(), verb)
	return
```

`String` 呼び出し時にpanicした場合、deferの `catchPanic` でrecoverされ、エラーメッセージを文字列として出力しています。これにより、panicをfmtの呼び出し元まで伝播させることなく次の処理に進められます。

# おわりに

`fmt` パッケージはHello worldにも出てくるので簡単なイメージがありましたが、まだまだ知らない仕様があることを痛感しました。精進せねば...
リモート会議でスマホ画面を画面共有する方法

長らくWebアプリケーションを開発するエンジニアとして働いておりましたが、スマホアプリの開発も行っているプロジェクトへ参画することになりました。リモート環境での勤務です。
自分の手元のiPhoneでちょっとおかしい挙動をする現象があり、現場のリーダーの方へその挙動を見てもらうことになりました。
リモート会議で、アプリの挙動を共有したい。さて、どうする？
といったシチュエーションで、私がとった行動は
「PCのカメラをONにして、スマホの画面をカメラに映るようにみせる！！」
という素人感丸出しの行動だったわけですが、その後、イマドキのやり方を教えていただきました。

### 想定する読者
- スマホアプリ開発に関連する案件に最近関わりはじめた方
- Webアプリケーション開発にて、スマホ画面を（静的スクリーンショットではなく）動的に共有する必要のある方
- リモートワーク環境の方

### 前提条件
- Macを使っていること
- Macと手元のスマホがケーブルで繋がっていること

### 手順
- QuickTime Playerを起動する。
- 起動直後、「ファイルを開く」モーダルが開き、動画ファイルを開くような画面になりますが、キャンセル。
- メニュー → 編集 → [新規ムービー収録]を選択。
- PCのカメラが有効になり、おそらく自分の姿が映る。録画スタート用の赤い丸のボタンの隣りの三角マークから、手持ちのスマホを選択。（下記の場合はiPhone）

![スクリーンショット 2023-07-10 19.53.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221909/65ae6733-b0bb-1470-097c-d3f46d7e8b75.png)

- 無事、スマホの画面が表示されます。この画面をリモート会議の画面共有エリアで共有しましょう！　　録画はしなくてよし！

[自分のスマホでみたQiitaトップ画面]
![スクリーンショット 2023-07-10 19.54.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221909/37c71765-7c58-d2da-cf44-1a919cc6fc30.png)
WhisperでDrive内の動画からテキストを抽出してみた(Google Colaboratory)

# はじめに
最近OpenAIのサービスが急速に普及してますね。
最新技術に触れたいなあということで趣味で動画からテキストを抽出するアプリを作ってみました。

使う技術は、
・FFmpeg
・OpenAI Whisper
のたった２つです。

Whisperの仕様上、25MB(大体20分くらいの動画)以下の音声ファイルしか文字起こしはできませんが、誰でも簡単に無料でできます。

下にColaboratoryのサンプルコードも載せてるので、「はよ教えてくれや！！」って方は、コピーして使ってください。

※この記事では簡略化のために、必要最低限のコードだけ載せています。

では、早速行きましょう〜〜！

## 1. Google ColaboratoryとGoogle Driveを繋げる
まずGoogle Drive内に保存された動画を取得するために、Google Colaboratory(以下、Colab)がGoogle Drive(以下、Drive)にアクセスできるよう設定します。

```
#Google Driveにアクセスするために必要な操作
from google.colab import drive
drive.mount('/content/drive')
```

## 2. 動画から音声を抽出する
ここでは、FFmpegという動画や音声を変換するソフトウェアを使って、動画から音声を抽出します。

```
#FFmpegから音声を抽出
!ffmpeg -i "movie_path" -vn "output_audio"
```

movie_path: Drive内の動画のパス
output_audio: 音声抽出後のファイル名(なんでもよい)

## 3. 音声からテキストを抽出する

```
!whisper {current_audio_path} --model medium --language Japanese -o "output_text_folder"
```

今回はmodelを"medium"に設定しています。精度的には本当は"large"がいいんですが、RAMの使用容量を超しちゃう可能性があるので、"medium"で我慢してます。

上記のコードで文字起こしをすると、複数のテキストファイルを出力してくれます。それらテキストファイルを入れるフォルダ名を -o の後に指定することができます。



以上、動画からテキストを抽出する方法をお伝えしました！

下にコードを貼っておくので、是非使ってみてください〜


[【Google Colaboratoryで動画からテキストを抽出する方法】](https://colab.research.google.com/drive/1OwpkG_jVnV7qC9Ovv4jdw3blV42lRfUB?usp=sharing)