OmniAICreator/Qiita-1.07M huggingface dataset:
ターン制で戦ってみた

# はじめに
ふと手に取った本をパラみして
ピンときた。やってみたい。

https://www.amazon.co.jp/%E5%B0%8F%E4%B8%80%E6%99%82%E9%96%93%E3%81%A7%E3%82%B2%E3%83%BC%E3%83%A0%E3%82%92%E3%81%A4%E3%81%8F%E3%82%8B%E2%94%80%E2%94%807%E3%81%A4%E3%81%AE%E5%AE%9A%E7%95%AA%E3%82%B2%E3%83%BC%E3%83%A0%E3%81%AE%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%82%92%E4%BD%93%E9%A8%93-WEB-DB-PRESS-plus/dp/4297127458/ref=sr_1_1?crid=3C05GGMUTKT6W&keywords=%E5%B0%8F%E4%B8%80%E6%99%82%E9%96%93%E3%81%A7%E3%82%B2%E3%83%BC%E3%83%A0%E3%82%92%E3%81%A4%E3%81%8F%E3%82%8B&qid=1651247272&sprefix=%E5%B0%8F%E4%B8%80%E6%99%82%E9%96%93%2Caps%2C163&sr=8-1

冒頭の章にあるターン制で戦うアプリのイメージだけ貰って
答えのソースは見ずに自分で組み上げてみることにした。

# できた

```Slime_VS_Hero.cpp
#include <iostream>
#include<windows.h>
#include <conio.h>

typedef struct{
	int hp;
	int max_hp;
	int mp;
}spec;

void screen(spec* d1,spec*d2,int comand) {
	
	printf("ゆうしゃ\n");
	printf("HP: %d / MP: %d", d1->hp, d1->mp);
	printf("\n\n");
	printf("／・Д・＼\n");
	printf("～～～～～");
	printf(" (HP %d/%d)\n", d2->hp, d2->max_hp);

	if (comand == 0) {
		printf(" たたかう\n");
		printf(" にげる\n");
	}
	else if (comand == 114) {
		printf(">たたかう\n");
		printf(" にげる\n");
	}
	else {
		printf(" たたかう\n");
		printf(">にげる\n");
	}

}

int main() {
	spec hero  = { 10,10,10 };
	spec* p_hero = &hero;
    spec slime = { 10,10,10 };
	spec* p_slime = &slime;
	
	while (hero.hp > 0 && slime.hp > 0) {

		screen(p_hero, p_slime,0);

		if (_getch() == 114) {
			system("cls");
			screen(p_hero, p_slime, 114);

			std::cout << "\nゆうしゃの攻撃!!\n";
			Sleep(1500);
			std::cout << "スライムに 1 のダメージ!!";
			slime.hp--;
			Sleep(2500);

			system("cls");

			screen(p_hero, p_slime,114);
			std::cout << "\nスライムの攻撃!!\n";
			Sleep(1500);
			std::cout << "ゆうしゃに 1 のダメージ!!";
			hero.hp--;
			Sleep(2500);
		}
		else {
			system("cls");
			screen(p_hero, p_slime, 113);

			std::cout << "\nゆうしゃは逃げ出した\n";
			Sleep(1500);
			std::cout << "\nしかし、逃げ切れなかった\n";
			Sleep(1500);
		}

		system("cls");
	};
		
	while (1) {};
	return 0;
}
```

# おわりに
答えを見ながらイメージを作っていく作業と
答えをイメージしてプロセスを自分で作っていく作業は全く別次元でした。
当然か(笑)

回復も出来ず、逃げることも出来ず、
戦い続ける事しか許されない勇者が少し可愛そうなので
どこかでアップデートしてあげるかも。

あとは答えのソースも確認して、
もっと綺麗に書けないか？とか
他にどのような書き方があるのか。

興味は尽きない。。
StrapiをHerokuで動かす

構築手順は公式通り

https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/deployment/hosting-guides/heroku.html#_11-deploy

## 注意点

Heroku上ではproduction modeで動作し、Content Type Builderからの追加が無効化されているため、スキーマ追加ができない

* セキュリティ上の理由
* スキーマ定義はローカルのファイルシステムに保存されるが、Herokuの再起動でファイルが削除されるため

ローカルで開発モードで起動し、

```
yarn develop
```

Content Type Builderの追加で生成されたファイルをherokuにpushする

```
git push heroku main
```
daisyUIを触ってみた話

# はじめに

とあるフロントエンドエンジニアのおすすめで、daisyUIを少し触ってみたので導入手順と感想を述べていきます。


# 導入

公式からコピペで作っていけます
https://daisyui.com/

`npm install`で準備して進みます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2332281/5b04ca82-1b5b-f12d-0391-a153dc043ca0.png)

今回はCDNとVue.jsで触ってみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2332281/a1a16d60-9620-f7b8-2ee5-2165e1b01c05.png)

## CDN

公式のままですが、これだけでいけます。

```index.html
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=devide-width, initial-scale=1.0" />
    <link
      href="https://cdn.jsdelivr.net/npm/daisyui@2.6.0/dist/full.css"
      rel="stylesheet"
      type="text/css"
    />
    <script src="https://cdn.tailwindcss.com"></script>
  </head>
  <body>
    <button class="btn">Hello daisyUI</button>
  </body>
</html>

```

ブラウザ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2332281/f0d3ce7e-2590-5aba-3f97-561e1b50447d.png)

## Vue.js

こちらも[公式で公開してるファイル](https://stackblitz.com/edit/daisyui-vue-vite "daisyui-vue-vite")をコピーすればいけます。
Viteで起動していきます。

```src/App.vue
<template>
  <button class="btn">Hello daisyui</button>
	<button class="btn btn-primary">One</button>
	<button class="btn btn-secondary">Two</button>
	<button class="btn btn-accent btn-outline">Three</button>
	<div class="dropdown dropdown-right">
  <label tabindex="0" class="btn m-1">Click</label>
  <ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-52">
    <li><a>Item 1</a></li>
    <li><a>Item 2</a></li>
  </ul>
</div>
</template>

```


```Terminal
[user@Mac vue]$npm run build

> node-starter@0.0.0 build
> vite build

vite v2.9.6 building for production...
transforming (10) node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js

🌼 daisyUI components 2.14.2  https://github.com/saadeghi/daisyui
  ✔︎ Including:  base, components, themes[29], utilities

✓ 11 modules transformed.
dist/index.html                  0.42 KiB
dist/assets/index.71f5a510.css   45.28 KiB / gzip: 7.72 KiB
dist/assets/index.ecd944e3.js    50.84 KiB / gzip: 20.56 KiB
[ziadon@Mac vue]$npm run serve

> node-starter@0.0.0 serve
> vite preview

  > Local: http://localhost:4173/
  > Network: use `--host` to expose

```

ブラウザ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2332281/bf1c6f40-aa1d-b7f4-c0e8-a14ff1080570.png)

各コンポーネントはこちらからコピーするだけで使えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2332281/5fa9b988-3055-4c64-0498-36c45b3cdcfe.png)

# おわりに

個人的にはBootstrapに負けないくらい使い勝手の良いものでした。
公式のサンプルコードのわかりやすさも含めると、daisyUIが優ってるかもしれませんね！
〈経験談〉AWS 認定ソリューションアーキテクト - アソシエイトの受験について

# 記事の概要/読み手の想定
**概要**
22年春に主題の資格をとりました。今後、資格取得を検討されている方の参考となる情報を展開したいと思います。AWSソリューションアーキテクトアソシエイトの資格に興味がある方、これからの勉強法を検討されている方を想定しています。

**記事の構成**
-1. モチベーション
-2. 使用した教材
-3. 試験当日の注意点
-4. おわりに 

----

# モチベーション
近年、否応なしに“クラウド”という単語を耳にするようになり、会社での開発業務でもAWSを使用しなければいけなくなってきていました。ただやみくもに使ってみて学習もよいですが、公認試験もあるのだからそのカリキュラムに沿って学習してみようと思ったのが始まりです。また、資格を持っているといえた方が人にアピールしやすいのではと思いました。


# 使用した教材
1. ＡＷＳ認定ソリューションアーキテクト－アソシエイト問題集
   (https://7net.omni7.jp/detail/1107220579)
2.  Udemy 【2022年版】AWS 認定ソリューションアーキテクト アソシエイト模擬試験問題集（6回分390問）

正直これだけで合格できると思います。2.で試験解きながら、わからなかったことを復習しつつ、最後に1．で体系的に学んだ感じです。
2．で40時間、1．で10時間くらいと思います。
2．について、取り組み初期はへこむと思います。
私の場合、一回目は40%程度しか正答率ありませんでした。着実に正答率あげていけば問題ないです。

また、試験6回分含まれていますが、一回解いて復習しているとかなり時間をとられます。
6回分やるのが本当はよいと思いますが、私は3回分だけを3～4周やりました。
だんだん正答率あげていく感じです。最終的に80%はとれるようになりました。
回答番号を覚えているとよくないので、次の回を一回やってまた戻って2周目をやるという感じですすめてました。


# 試験当日の注意点
オンライン受験を選択しました。来週試験があると思うとあらためて気合が入り最後の週で結構復習が捗りました。なので、最短で明日に試験予約することもできると思いますが、1週間後など、少し余裕をもって設定するのが良いかと思います。

試験当日は、1時間前からそわそわして、部屋の片づけ、IDの用意、PCアプリの起動チェックを行いました。
30分前になり、受付開始したのですが、試験官とのチャットルームにアクセスする途中でアプリが落ちる問題が解決できず、結局試験開始時間になっても接続できない状況になってしまいました。
結局、Chromeでアクセスしていたのですが、edgeに変更したら接続できました。
チャットで、試験に遅れているが大丈夫か？といった内容の英文を送信すると数分後に返信があり、
そこからIDのチェックや、試験を受ける部屋のチェックなどが始まりました。
15分遅れて試験開始されましたが、試験時間はしっかり確保されていました。
ただ、最初の数問は焦りがすごかったので、何かがあってもひとまず落ち着くことに集中することが大切と思います。

試験は順調に進めることができ試験時間いっぱい使いました。
最後の3分くらいでまたアプリが落ち、、、再接続してもらい結果合格が表示されました。
見直しで何問か回答を変えましたが、復習は大切と思います。
回答するときにチェックを入れれるので、チェックした試験項目を重点的に見直す作業になります。


# おわりに
感想文のような記事になってしまいましたが、参考になりましたでしょうか。
本試験の結果を課内に報告したところかなり好評でした。AWS活用は今後増えていく領域かと思いますので活躍できる幅も増えると思いますので、IT関連の業務を遂行されている方にはおすすめの資格と思います。

試験結果は試験終了時に表示されるものの、正式な連絡がくるまでに4日程度かかりました。
ほかの記事では次の日に連絡が来ていたという人もおり、ずっともやもやした日々を過ごしていましたが
心配なさらず待っていればよいと思います。
今後も他の試験に取り組もうと思っており、皆さんと励ましあいながら勉強したいと思います。
少しでも記事が参考になれば幸いです。
GoogleColaboratoryからスプレッドシートを操作するための認証が通らなくなった話

# はじめに
GoogleColaboratoryからスプレッドシートを操作する際、以下のような認証を実装していました。

```python
from google.colab import auth
from oauth2client.client import GoogleCredentials
import gspread

auth.authenticate_user()
gc = gspread.authorize(GoogleCredentials.get_application_default())
```

2022年の2月までは上記実装で動いていたのですが、2022/4/28に久しぶりに実行したところ、
下記のエラーが発生し、認証処理が通らなくなりました。

```
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-67cdf2a8c5fe> in <module>()
      4 
      5 auth.authenticate_user()
----> 6 gc = gspread.authorize(GoogleCredentials.get_application_default())

2 frames
/usr/local/lib/python3.7/dist-packages/gspread/utils.py in convert_credentials(credentials)
     59 
     60     raise TypeError(
---> 61         'Credentials need to be from either oauth2client or from google-auth.'
     62     )
     63 

TypeError: Credentials need to be from either oauth2client or from google-auth.
```

# 解決策
以下のような実装にすることで認証が通るようになりました。
```python
from google.colab import auth
from google.auth import default
import gspread

auth.authenticate_user()
creds, _ = default()
gc = gspread.authorize(creds)
```

# 原因
調べてみると、gspreadでは以前からoauth2clientが非推奨となっていたようでした。

https://docs.gspread.org/en/latest/oauth2.html

https://google-auth.readthedocs.io/en/latest/oauth2client-deprecation.html
[メモ]docker環境のPHPでPostgreSQLを使う際にcould not find driverが出る時の対応

## 対処法
DockerFileに追記
```
RUN apt-get update && apt-get -y install libpq-dev
RUN docker-php-ext-install pdo_pgsql
```
## 参考
https://chusotsu-program.com/docker-could-not-find-driver/
EmacsでGnuPGのパスワードをミニバッファで入力できるようにする

Emacsを使うと、GnuPGを用いてファイルを簡単に暗号化できます。拡張子を `.gpg` （例えば、 `test.gpg` ）にして保存すれば、パスフレーズを聞かれ、暗号化されます<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>。

また、 `plstore` というライブラリがあり<sup><a id="fnr.2" class="footref" href="#fn.2" role="doc-backlink">2</a></sup>、様々な場面でパスワードやアクセストークン等の秘密情報の保存に利用されます。

これらのGnuPGで暗号化する際、当然、パスフレーズを聞かれます。このパスフレーズをEmacsのミニバッファで入力できるようにしておくと便利です。

```el
(setq epg-pinentry-mode 'loopback)
```

もともとはUbuntuでパスフレーズを入力する際にとても時間がかかるようになった問題<sup><a id="fnr.3" class="footref" href="#fn.3" role="doc-backlink">3</a></sup>を解決しようとして、この設定にたどり着いたのですが、結果としてとても快適になりました。


# Footnotes

<sup><a id="fn.1" href="#fnr.1">1</a></sup> [Emacs (EasyPG) で秘密のメモを書く — ykrods note](https://www.ykrods.net/posts/2020/05/10/secret-memo-with-emacs-easypg/#id5)

<sup><a id="fn.2" href="#fnr.2">2</a></sup> [emacs/plstore.el at master · emacs-mirror/emacs](https://github.com/emacs-mirror/emacs/blob/master/lisp/plstore.el)

<sup><a id="fn.3" href="#fnr.3">3</a></sup> [GPGの暗号化/複合化が遅い問題](https://masatoi.github.io/2021/08/09/gpg)
AWSプライベートサブネット内のインスタンスにMySQLサーバーを設置（備忘録）

## プライベートサブネット内のインスタンスにアクセス

```
//プライベートキーのファイルを作成
$ nano myprivatekey.pem
```

別Windowが立ち上がるので、手持ちのプライベートキーをコピー＆ペーストし、Ctrl + x で保存しy及びEnterで終了。

```
//プライベートキーのファイルに400の権限を付与
$ chmod 400 myprivatekey.pem

//プライベートキーを使用してプライベートサブネット内のインスタンスにアクセス
$ssh ec2-user@[プライベートのIPアドレス]　-i myprivatekey.pem
```
ログインの確認をされるので'yes'でログイン。


## プライベートサブネット内のインスタンスにMySQLサーバーを設置
パグリックサブネットにnat gatewayを作成後、

```
//ルートに移動
$ sudo su

//不足しているパッケージのアップデート
$ yum update -y

//MySQLをDLしインストール
$ yum localinstall https://dev.mysql.com/get/mysql80-community-release-el7-5.noarch.rpm -y
$ yum install -y mysql-community-server
```
Amazon EC2 基礎用語

## AWSとは
Amazon Web Servicesの略で、クラウドコンピューティングサービスの一つ。

クラウドコンピューティングサービスとは、サーバーやネットワークなどをインターネットを通して貸してくれるいつでもどこでも始められるサービス。

AWSには、たくさんの色々なサービスがあり、そのサービスを組み合わせることであらゆるアプリケーションやインフラを実現することができる。

今回はその中でも最も有名なサービスでもあるEC2について書いていく。


## EC2とは
EC2とは、Amazon Elastic Compute Cloudの略で、サーバーに必要なもの一式をクラウドで借りられるAWSでもっとも有名なサービス。

レンタルサーバーの場合、サーバー機能やサーバーマシンを借りるが、
クラウドの場合は、借りた道具(CPUやメモリのスペックがいろいろ用意されている(インスタンスタイプ)や、OSやソフトウェアの種類がいろいろ用意されている(AMI))を使って自分でサーバーを作るようなイメージ。

サーバーやネットワークの運用はAWSが担当、
OSを含むインストールするソフトウェアすべての運用は自分で行う必要がある。
このようなサービスをアンマネージドサービスという。



## インスタンスとは
AWSクラウドに作る仮想サーバーのこと。
EC2では、AMIで何度も同じ構成のサーバーを作成できるため、作成したサーバーをインスタンスと呼ぶ。
AMIが金型で、それでできたインスタンス(サーバー)がたい焼き。ついでにいうとそのたい焼き屋さんの店のくくりがVPC。

ネカフェを例に言うと、
- ネカフェの店のくくりが、VPC(仮想のネットワーク領域)
- ネカフェの店の1つ1つの部屋が、インスタンス(サーバー)
- ネカフェの店の1つ1つの部屋の設計図が、AMI(フラットタイプ、チェアタイプの部屋があった場合、AMIは2つだけでいい。AMIをもとに2種類の部屋(インスタンス)を大量に作れる)
- ネカフェの店の男女共通スペースと女性専用スペースが、パブリックサブネット(男女共通スペース)とプライベートサブネット(女性専用スペース)なイメージ
- ネカフェの店の出入り口(受付)が、インターネットゲートウェイ



インスタンスにはさまざまな設定項目があり、
下記はインスタンスの設定項目。
#### AMI
下記に詳しい説明あり。

#### インスタンスタイプ
EC2インスタンスのマシンスペック。CPU・メモリ・マシンのタイプを設定する。

#### リージョン
サーバーを設置する地域を設定する。日本には、東京と大阪にある。他国のリージョンを使うことも可能。

#### ネットワーク
EC2インスタンスを配置するネットワーク。AWSのVPCから選択する。
＊VPCとはAWSアカウント専用の仮想ネットワーク、ネカフェの店のくくり。



#### サブネット
設置するネットワークの範囲。
ネカフェの店の男女共通スペースと女性専用スペース、または禁煙スペース喫煙スペースのイメージ。
VPCの中のどのサブネットに置くか選択する。(ネカフェのどのスペースの部屋にするか選択する。)

#### IAMロール
インスタンスのアクセス権限ポリシーを設定する。
他のサービスにアクセスするときに割り当てる必要がある


#### ストレージの容量・種類
サーバーマシンのストレージ。基本的にはEBSを選択する。
S3などの外部ストレージは選べない。


#### タグ
インスタンスに好きなタグをつけることができる。
Nameタグでインスタンスに名前をつけることができるのでつけておくといい。

### セキュリティグループ
プロトコルごとに、ポートorIPアドレス、またはその両方のフィルタリングを設定。

## AMIとは
仮想イメージのこと。Amazonマシンイメージの略。
インスタンスを作成するもととなる金型のようなもの。OSのみが入っているようなものからソフトウェアの設定まで終わっているものまでさまざまなAMIが用意されている。
そのため一度金型を用意してしまえば、同じインスタンスを簡単に増産することが可能になる。

また、AMIを自作した場合マーケットプレイスという場所で配布できる。
マーケットプレイスとは、AWSにてAMIを配布できる場所のこと。
インスタンスの作成に使用でき、現在、数千ものAMIが公開されている。


## EBSとは
AWSクラウド内で使用できるストレージ。
インスタンスのストレージとして使用される。
Amazon Elastic Block Storeの略で、EC2と組み合わせて使うブロックストレージボリューム。
そもそもストレージとは、データを記録したりする場所のこと。(HDDやSSDなど)
ブロックストレージボリュームとは、ディスクに保存する一般的な方式で、データをバイトのブロック単位で保存する。
EC2と同じくらい代表的なサービスでもあるS3との違いは、オブジェクトストレージと呼ばれる方式をとっているということ。

EBSでは、大容量に対応しているHDDと、速度は劣るがHDDに比べて安価なSSDを選ぶことができる。

## その他の基礎用語

####  Elastic IPアドレスとは
固定の変わらないIPv4アドレス

#### ELBとは
Elastic Load Balancingの略で、AWSが提供するロードバランサー。
負荷分散装置ともいい1つのサーバーに負荷が集中するのを防ぐために、
複数のサーバーやネットワークに振り分けるしくみ。

#### スナップショットとは
バックアップできる機能で、ある時点でのサーバーのディスク状態をまるごと保存したファイルやフォルダの集合。

####  Auto Scalingとは
サーバーへのアクセス状態によってサーバーの台数を増やしたり減らしたりを自動でやってくれる機能。



最後まで読んでくれてありがとうございました!!
Dockerコンテナ内でVueプロジェクト作成時のエラー(EAI_AGAINエラー)

## Date
create 2022/04/29

## Ver
Windows10	
WSL	
Docker	
npm 16	
Docker 20.10.14	
Docker Compose 2.4.1	

## エラー内容
Dockerコンテナ内でvueプロジェクト作成時、	

```
ERROR  command failed: npm install –loglevel error
```

とエラーが出力されログファイルを確認すると、「EAI_AGAIN」とDNS系のエラーが出力されていた。	

## 原因
Dockerコンテナ内でDNSが設定されていないことが原因だった。	
コンテナ内で以下のpingコマンドを実行すると接続ができなかった。	

```
# 接続できない
$ ping registry.npmjs.org
```

## 対応
コンテナにDNSの設定をする	
docker composeの場合、appコンテナのオプションにdnsを設定する	
今回はとりあえずGoogleのDNSを使用した	

```yml
dns:
- '8.8.8.8'
```
【投稿練習】『良い記事を書くためのガイドライン』を読んで

# 『良い記事を書くためのガイドライン』を読んで

## 前提
この記事は、Qiitaの投稿を練習するための記事になります。  
markdown記法も練習中。

## 結論
* 結論をここに記入する
  *  aaaaaaaa
  *  bbbbbbbb
  *  cccccccc
* 著作権には気を付けよう


## 参考
* [良い記事を書くためのガイドライン](https://help.qiita.com/ja/articles/qiita-article-guideline)
Ubuntu 20.04 LTS から Ubuntu 22.04 LTS のアップグレードを試みたらUnofficial software packages not provided by Ubuntuがあるといわれて詰まった

ゴールデンウィークで時間に余裕がある(?)ため、WSL2で動かしているUbuntu 20.04.4 LTSをUbuntu 22.04 LTSへアップグレードしようと思った。
まずは次の記事を参考にした：

https://zenn.dev/ryuu/articles/upgrade-ubuntu2204-wsl

いつもどおりパッケージのアップデートと依存解決を行う。
```
$ sudo apt update && sudo apt upgrade
```

ディストリビューションアップグレードの依存解決を行う。
```
$ sudo apt dist-upgrade && sudo apt install update-manager-core
```
異常なし。

relese-upgradeの設定ファイルをvimで覗いて編集。
```
$ sudo vim /etc/update-manager/release-upgrades
```
Prompt の値を ltsにするためだが、もともとなっていたので変更の必要はなかった。
```
Prompt = lts
```

アップデートを実行する。
```
$ sudo do-release-upgrade -d
```

なんか詰まった。
```
Get:38 http://ftp.jaist.ac.jp/pub/Linux/ubuntu jammy-security/universe Translation-en [6004 B]
Get:39 http://ftp.jaist.ac.jp/pub/Linux/ubuntu jammy-security/universe amd64 c-n-f Metadata [412 B]
Get:40 http://ftp.jaist.ac.jp/pub/Linux/ubuntu jammy-security/multiverse amd64 c-n-f Metadata [116 B]
Fetched 23.3 MB in 6s (3272 kB/s)

Checking package manager
Reading package lists... Done
Building dependency tree
Reading state information... Done

Calculating the changes

Calculating the changes

Could not calculate the upgrade

An unresolvable problem occurred while calculating the upgrade.

This was likely caused by:
* Unofficial software packages not provided by Ubuntu
Please use the tool 'ppa-purge' from the ppa-purge
package to remove software from a Launchpad PPA and
try the upgrade again.

If none of this applies, then please report this bug using the
command 'ubuntu-bug ubuntu-release-upgrader-core' in a terminal. If
you want to investigate this yourself the log files in
'/var/log/dist-upgrade' will contain details about the upgrade.
Specifically, look at 'main.log' and 'apt.log'.


Restoring original system state

Aborting
Reading package lists... Done
Building dependency tree
Reading state information... Done
=== Command detached from window (Fri Apr 29 22:53:41 2022) ===
=== Command terminated with exit status 1 (Fri Apr 29 22:53:52 2022) ===
```

https://salamann.com/wsl2_ubuntu-18-04to20-04

を参考にしたが、だめだった。次に

https://askubuntu.com/questions/1238620/i-was-unable-to-update-to-ubuntu-20-from-ubuntu-18-04

を参考に
```
$ grep Foreign /var/log/dist-upgrade/main.log
2022-04-29 23:13:55,012 DEBUG Foreign: nodejs
```
となったので、nodejsが邪魔だと発覚した。いらないので消した。
```
$ sudo apt-get remove nodejs
```
もういちどアップデートを実行すると、できた。めでたし。
HomebrewでインストールしたmysqlクライアントからDockerのMySQLサーバに接続する最短手順

# 前提

```
$ mysql --version
mysql  Ver 8.0.28 for macos12.2 on x86_64 (Homebrew)
$ docker run --rm mysql mysql --version
mysql  Ver 8.0.29 for Linux on x86_64 (MySQL Community Server - GPL)
```

# 手順

DockerでMySQLサーバを起動する。

```
$ docker run --rm -p 3306:3306 -e MYSQL_ROOT_PASSWORD=<rootのパスワード> mysql
```

ローカルのmysqlクライアントから**TCPで**サーバに接続する。

```
$ mysql --protocol=TCP -uroot -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 15
Server version: 8.0.29 MySQL Community Server - GPL

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 
```

# なぜ`--protocol=TCP`を指定するのか

`mysql`はデフォルトでlocalhostに接続しようとし、localhostに接続するときはデフォルトでUnixドメインソケットを使おうとする。しかしDockerとホストでファイルシステムが分かれているので、次のエラーになる。

```
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
```

そこで、プロトコルを明示的にTCPに設定して、暗黙のうちにUnixドメインソケットが使われることを回避する。

# 参考

- [MySQL :: MySQL 8.0 Reference Manual :: 4.2.4 Connecting to the MySQL Server Using Command Options](https://dev.mysql.com/doc/refman/8.0/en/connecting.html)
  - "The default host name is localhost"とあるので、`mysql`の`--host`オプションのデフォルト値もlocalhostになる
- [MySQL :: MySQL 8.0 Reference Manual :: 4.5.1.1 mysql Client Options](https://dev.mysql.com/doc/refman/8.0/en/mysql-command-options.html)
  - `--socket`オプションに渡す値の説明に"For connections to localhost, the Unix socket file to use"と書いてあるので、localhostに接続するときはデフォルトでUnixドメインソケットを使うと解釈できる
  - `--protocol`オプションに渡すことができる値として`TCP`や`SOCKET`がある
- [mysql locahost の接続では、unix socket かTCPかを明示しないとsock エラーで混乱した - それマグで！](https://takuya-1st.hatenablog.jp/entry/2019/03/11/115831)
認可コードフローのリフレッシュトークンを保存するだけのWebアプリケーション

# What?

例えば、YouTubeのプレイリストへの動画登録を自動化することを考える。この場合、OAuth2 認可コードフローで、自動化するアプリケーションにプレイリスト所有者のアカウントへのアクセスを認可させる必要がある(※1)。

ただし、発行されるアクセストークンは、一般的に有効期限が短い。その都度認可する必要があるのでは、自動化するメリットがない。よって、アクセストークンと一緒に発行されたリフレッシュトークンを永続化し、アプリケーションから読み出して利用できるようにする。

この記事では、Web APIの認可コードフローのリフレッシュトークンを発行・保存するだけのWebアプリケーションの構成について説明する(※2)。

(※1)認可を自動化することは原則できない。それはアプリにユーザID, パスワードを渡すことになるので認可コードフローの思想に反する（例え自分のアカウントのみを利用する想定であっても）。真っ当なWebアプリケーションは認可画面にbot対策が仕掛けられているはずである。よって、「自動化」とは書いたが、認可は手動で行う必要があるので、「半自動化」である。

(※2)利用したいAPIがクライアントクレデンシャルフローであれば、ユーザの認可は不要なので、Webアプリケーションを構築する必要はない。また、アプリがWebアプリケーションであれば、そのWebアプリケーションを使って認可をすればいいので、別途Webアプリケーションを構築する必要はない。アプリがバッチ処理などのクライアントの手を介さないものであれば、今回の構成は有効であると考えられる。

# システム構成図(例)

AWSで構成した。例は下記の通りである。

![スクリーンショット 2022-04-19 21.51.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79697/78b9f95f-8ac6-c44a-f6d6-08f116e2fb83.png)

赤字がWebアプリケーション部分である。アクセス頻度はリフレッシュトークンの有効期限次第であり、これは一般的には長いので、極めて少ない。よって、コストが最小となるように、API Gateway + Lambda構成とした。コスト面を気にしなければ、他の構成(EC2やECS+ALB)でも問題ない。

ストレージは、WebAPIを利用するアプリがRDSを使っているため、そのRDSを使い回しており、別のリソースでも問題ない。

必要なもの

1. 認可サーバのリダイレクト先としてブラウザからのアクセスを認可コードを受けられるリソース(図ではAPI Gateway)
1. トークンエンドポイントにリクエストできるリソース(図では左のLambda)
1. ストレージ(図ではRDS)
1. ストレージにアクセスできるリソース(図では右のLambda)

今回、Lambdaが2つあるのは、以下の制約からである。

(1)LambdaからRDSにアクセスするにはLambdaをVPCに配置する必要がある
(2)一方、VPCに配置したLambdaはインターネットにアクセスできないので、トークンエンドポイントにアクセスするには別のLambdaを定義する必要がある

EC2やECSであればリソースを2つ用意する必要はないし、ストレージがRDSでなく、DynamoDBのようなリージョンサービスであれば、普通のLambdaからアクセス可能である。
初期値鋭敏性について(ロジスティック写像)

初期値鋭敏性について紹介したいと思います。
非線形の数理モデルであるロジスティック写像を対象として、初期値鋭敏性を確認します。

ロジスティック写像については、[ロジスティック写像の紹介](https://qiita.com/reser_ml_memo/items/878927bf473bd025b16a)に掲載しています


ロジスティック写像は以下の漸化式のような形で表されます。

　　　　　　　　　　　$x_{n+1} = a x_{n}(1-x_{n})$

漸化式の形で書けますが、カオスと呼ばれる不規則な動き(以下の図)をします。
![logistic_a4_60.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2594605/d9334610-b6f1-bc93-68fb-ad0756652ef3.png)


では本題の初期値鋭敏性の話に入っていきます。
初期値鋭敏性とは、カオスの定義あるいは特性の一つになります[1]。
初期値鋭敏性を実際に見てもらうために、初期値$x_{0}=0.1$に微小の誤差を与えます。具体的には誤差を$10^{-10}$とします。
赤色：初期値$x_{0}=0.1$
青色：初期値$x_{0}=0.1+10^{-10}$
緑色：初期値$x_{0}=0.1+2\times10^{-10}$
黄色：初期値$x_{0}=0.1+3\times10^{-10}$


![初期値鋭敏性.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2594605/dfd18199-eecb-8503-3f16-1785271d7d8d.png)


$10^{-10}$という僅かな差ですが、途中から軌道が大きくずれます。これが初期値鋭敏性になります。

違った視点で、確認するために、誤差の変化を可視化します。
![error_table123.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2594605/7efe9a5b-f9a3-6318-f52a-d89fba61fd60.png)
n=20くらいまでは、誤差はかなり小さいですが、n=25くらいから誤差が大きくなり、n=30の時には誤差がかなり大きくなっていることがわかります。


以下、今回使用したコードです。
コードの書き方が微妙ですが、ご了承ください🙏
```
# ロジスティック写像のデータを生成する関数
def logistic(n,x_0,a):
    
    # 値を格納する
    x = np.zeros(n)

    # 初期値を設定
    x[0] = x_0

    for i in range(n-1):
        x[i+1] = a*x[i]*(1-x[i])
        
    return x
```
```
# 2つ目の図
gosa = 1e-10
init_bf = 0.1
init_af1 = init_bf+gosa
init_af2 = init_bf+(gosa*2)
init_af3 = init_bf+(gosa*3)

fig = plt.figure(figsize=(10, 4))
plt.rcParams['font.size'] = 10
plt.plot(logistic_v2(60,init_bf,4),marker = "o",color="r")
plt.plot(logistic_v2(60,init_af1,4),marker = "o",color="b",label="+1e-10")
plt.plot(logistic_v2(60,init_af2,4),marker = "o",color="g",label="+2e-10")
plt.plot(logistic_v2(60,init_af3,4),marker = "o",color="y",label="+3e-10")
plt.xlabel("n")
plt.ylabel("x")
plt.legend(loc="best")
plt.show()
```
```
# 3つ目の図
length = 60
error_list1 = []
error_list2 = []
error_list3 = []
for i in range(length):
    error_1 = \
    abs(logistic_v2(length,init_bf,4)[i]-logistic_v2(length,init_af1,4)[i])
    
    error_2 = \
    abs(logistic_v2(length,init_bf,4)[i]-logistic_v2(length,init_af2,4)[i])
    
    error_3 = \
    abs(logistic_v2(length,init_bf,4)[i]-logistic_v2(length,init_af3,4)[i])
    
    error_list1.append(error_1)
    error_list2.append(error_2)
    error_list3.append(error_3)

fig = plt.figure(figsize=(10, 4))
plt.rcParams['font.size'] = 10
plt.plot(error_list1,marker = "o",color="b",label="+1e-10")
plt.plot(error_list2,marker = "o",color="g",label="+2e-10")
plt.plot(error_list3,marker = "o",color="y",label="+2e-10")
plt.xlabel("n")
plt.ylabel("error")
plt.legend(loc="best")
```

引用文献
[1]：https://ja.wikipedia.org/wiki/カオス理論
ラズパイとAndroidスマホでルーター作った

## Androidスマホをラズパイでルーターつくった

引っ越しを控え、現宅のフレッツ光の移設手続きをしていたのですが、諸事情で1ヶ月以上回線が引けない状況になりました。
仕方ないので、ルーターを自作します。

## USBテザリングを有線LANに変換させてみた
Androidスマホで有線LANテザリングが出来るとベストなのですが、あいにく手元に対応しているスマホがありませんでした。
結果、RaspberryPiでブリッジしてあげることで、これを実現しました。

## 環境
- SHARP SH-M05 (Android 9)
- RaspberryPi Model2B
- 楽天モバイル(楽天回線)

## やり方
USBテザリングを、ラズパイの有線LANポートとブリッジする事で実現しました。
具体的には、SH-M05が、USBテザリングのEnable/DisableでUSBデバイスIDが変わることをトリガーとして、udevを使いブリッジをコントロールします。

```
Clients ---> [[eth0]-[br0]-[usb0]] ---> [Android 9] ---> The Internet(Rakuten Mobile MNO)
```

## LinuxからのSH-05のみえかた

DebianにSH-05を接続した際、以下のように認識されています。
```bash
root@raspberrypi:~# lsusb | grep Sharp
Bus 001 Device 007: ID 04dd:9ba2 Sharp Corp. SHM05
```

USBテザリングを有効にしたところ、デバイスIDが変化しました。
```bash
root@raspberrypi:~# lsusb | grep Sharp
Bus 001 Device 008: ID 04dd:9b9e Sharp Corp. SHM05
```
デバイスIDは、それぞれのモードの固定値のようで、再現性がありました。

また、USBテザリングを有効にした際、``usb0``という名前のNICが認識されており、DHCPでIPアドレスを取得しています。

## 実装

### interfaces
interfaces内で、内蔵NIC(eth0)をメンバーとしたブリッジ`br0`を作っておきます。

```bash /etc/network/interfaces.d/br0
auto br0
iface br0 inet dhcp
       pre-up /sbin/brctl addbr br0
       pre-up /sbin/brctl addif br0 eth0
       pre-up /sbin/ifconfig eth0 up
```

### udev
USBテザリングを有効にした際のベンダーID:デバイスIDをトリガーとして、ブリッジのコントロールを行います。
ここでは、1つのトリガーに対し複数の処理をしたい為、いったん任意のシェルスクリプトを呼び出すことにします。
```/etc/udev/rules.d/01-android.rules
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTRS{idVendor}=="04dd", ATTRS{idProduct}=="9b9e", ATTR{type}=="1", RUN="/root/bin/add.br0.sh"
SUBSYSTEM=="net", ACTION=="remove", DRIVERS=="?*", ATTRS{idVendor}=="04dd", ATTRS{idProduct}=="9b9e", ATTR{type}=="1", RUN="/root/bin/remove.br0.sh"
```

### デバイス接続時
`br0`に`usb0`をアタッチし、DHCPでアドレスを取得させます。
L2ブリッジだけが目的なので`dhclient`の意味はありませんが、メンテナンスをする際などに必要でしょう。
```/root/bin/add.br0.sh
#!/bin/bash
dhclient -r
brctl addif br0 usb0
sleep 1
dhclient br0
```
### デバイス切断時
接続時とは逆に、`DHCPCd`を終了させ、`usb0`をデタッチします。
```/root/bin/remove.br0.sh
#!/bin/bash
dhclient -r
brctl delif br0 usb0
```

## 使ってみた感想
1週間ほど使ってみているですが、思ったより安定しています。
ただ、所詮はLTEなホームルーターと変わり無いので、過剰な期待はしない方が良いかと思います。

## おわりに
今回、フレッツ光が1ヶ月以上の開通待ちとなり、レンタルWiFiを借りるのも惜しいので、手持ちのモノで作ってみました。
レンタルWiFiと違い、安くて、無線APも好きなモノがつかえますし、VLANもVPNも好きに出来るので、玄人にはなかなか良いのではないでしょうか。

コロナがきっかけで、築50年の築古マンションへ引っ越ししようとしています。
安くて広くて、Hackのし甲斐もあり、なかなかに楽しいです。 笑

Happy Hacking!!
【備忘録】Cosmos SDKでMissing placeholdersが出た時

```
Missing placeholders:

// this line is used by starport scaffolding # genesis/types/default
```

初めて見たエラーで、placeholderという言葉にピンと来ていなかったが、
`// this line is used by starport scaffolding # genesis/types/default`
というコメントを所定の位置に入れたら直った。

備忘録。
MongoDB 逆引き insert操作　初級

# 初級のinsert操作

### 
```
db.コレクション名.insert({name: "taguchi", age: 30})
db.コレクション名.insert({name: "fkoji", score:50, tags: ["web", "mobile"]})
```

### insertした内容を全件検索
```
db.コレクション名.find()
```
### insertした内容を条件をつけて検索
```
db.コレクション名.find({name: "taguchi"})
```

### insertした件数を確認
```
db.コレクション名.count()
```

### 特定のフィールドを「〜以上」「~より大きい」で検索
$マークをつけてgte(Greater Than or Equal)とつける。
```
 db.users.find({score: {$gte: 50}})
```
・「~より大きい」の場合はgt。
・「~より小さい」の場合はlt。
・「~以下」の場合はlte。
・「~と等しい」の場合はeq。
・「~と等しくない」の場合はen。

### 複数条件での検索
```
db.users.find({name:/t/, score: {$eq: 60}})
```

### 同じフィールド内での複数検索(or条件)
例)スコアが52か60の値を検索
```
db.users.find({score: {$in: [52,60]}})
```
Vue2系でProps地獄をやめてProvide/Injectをつかう

## はじめに
備忘録として整理しました。

ハンマーを持つと全てが釘に見えるので、引き出し増やす程度に見ていただければ幸いです。
後述するソースコードはvue2.6.14で動作確認しています。

## Vue3のProvide / Inject

以下[公式より引用](https://v3.ja.vuejs.org/guide/component-provide-inject.html)
> 通常、親コンポーネントから子コンポーネントにデータを渡すとき、props を使います。深くネストされたいくつかのコンポーネントがあり、深い階層にあるコンポーネントが浅い階層にあるコンポーネントの何かしらのデータのみを必要としている構造を想像してください。この場合でも、鎖のように繋ったコンポーネント全体にプロパティを渡す必要がありますが、時にそれは面倒になります。
> 
> そのような場合は、provide と inject のペアを利用できます。コンポーネント階層の深さに関係なく、親コンポーネントは、そのすべての子階層へ依存関係を提供するプロバイダとして機能することができます。この機能は 2 つの機能からなります: 親コンポーネントは、データを提供するためのオプション provide を持ち、子コンポーネントはそのデータを利用するためのオプション inject を持っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/417134/eaaf6361-127b-2cc9-a48f-89195732ae82.png)

## Vue2系での書き方
Vue3からの機能のように見えますが、実はVue2系でも使うことができます。
そのまま使うと親コンポーネントで更新した値が子コンポーネントに反映されません。
リアクティブではないためです。

### リアクティブに扱う方法1 インスタンスをprovideで渡してしまう
https://zenn.dev/lollipop_onl/articles/2481816f4a03a0f8c9da

こちらの記事では親のインスタンスごと子供に渡しているのですが、記載の通りそこそこなんでもできてしまって注意が必要です。
もし孫から親世代に変更したい場合はインスタンスごと渡しているので直接、もしくはメソッドから変更できます。
なんでもできてしまうので、方法2の方がおすすめです。

### リアクティブに扱う方法2 Object.definePropertyをprovideする
https://www.youtube.com/watch?v=xeIKd-CicK8

調べていたら見つけた動画です。英語ですが今回のやりたいことの解説をそのまましてくれています。


### 方法1と2のサンプルコード

せっかくなので、孫の変更を親にできないかためしてみました。
あんまりやると無法地帯になりそうですが、propsとemitが連鎖し続けるくらいならこっちのほうがわかりやすい、、、気がします。

ProviderCompを親世代、
KoCompを子世代、
MagoCompを孫世代としてます

```vue:ProviderComp.vue
<template>
<div>
  <pre>oya: {{value}} | {{value2}}</pre>
  <div>
    <button @click="countup">Count-up</button>
    <hr>
    <KoComp />
  </div>
</div>
</template>

<script>
import KoComp from "./KoComp";
export default {
  data() {
    return {
      value: 0,
      value2: 0,
    };
  },
  components: { KoComp },
  provide() {
    const provideValue = {}
    Object.defineProperty(provideValue, 'value2',{
      enumerable:true,
      get:()=>this.value2,
      set:(val)=>{this.value2=val} // injectした子孫から影響をうけつけるため。渡すだけならset不要
    })
    return {
      "oyaVM": this, // 方法1
      provideValue   // 方法2
    };
  },
  methods: {
    countup() {
      this.value++;
    },
  },
}
</script>
```

```vue:KoComp.vue
<template>
<div>
  <p> ko</p>
  <hr>
  <MagoComp />
</div>
</template>

<script>
import MagoComp from "./MagoComp";
export default {
  components: { MagoComp }
}
</script>

```

```vue:MagoComp.vue
<template>
<div>
  <p> mago {{oyaVM.value}} | {{provideValue}}</p>
  <button @click="countup">Count-up</button>
  <button @click="countup2">Count-up2</button>
  <hr>
</div>
</template>

<script>
export default {
  inject: ["oyaVM", "provideValue"], // 方法1も2もどちらも

  methods: {
    countup() {
      this.oyaVM.value++; // 方法1
    },
    countup2() {
      this.provideValue.value2++ // 方法2
    },
  },
}
</script>

```


<img width="400" alt="説明用画像" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/417134/4053d22a-f2ea-9602-6a91-3e4c22a59dd5.png"><img width="200" alt="うごかした画像" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/417134/381b83a1-eee1-fa87-a01f-7c3a883ab134.png">

## おわりに
コンポーネントを細かく分解していると階層が深くなって、だんだんPropsの多重バケツリレーが起きてしまいますがそれから解放してくれる便利な機能ですね。

ただデメリットとしては、どうデータがやり取りされているか、流れが追いにくいかもです。
逆引きMongoDB基礎(コレクションを作る)

## 基本的なコレクション操作のためのコマンド

### 現在のDB一覧を表示する
```
show DBs
```


### 新しいDBを作成して切り替える
```
use db名
```

### 新しいコレクションを作成する
```
db.createCollection("コレクション名")

```

### 作ったコレクションの一覧を見る
```
show.collections
```

### コレクション名を変更する
```
db.旧コレクション名.renameCollection(”新コレクション名”)
```


### DBを削除する
```
db.dropDatabase()
```
OpenStreetMap+Leaflet で「Map container not found.」と出るとき

## 問題

```html
<html>
<head>
  <!-- 必要な CSS と JavaScript を読み込んでいて･･･ -->
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.8.0/dist/leaflet.css"
        integrity="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ=="
        crossorigin=""/>
  <script src="https://unpkg.com/leaflet@1.8.0/dist/leaflet.js"
          integrity="sha512-BB3hKbKWOc9Ez/TAwyWxNXeoV9c1v6FIeYiBieIWkpLjauysF18NzgR1MBNBXf8/KABdlkX68nAhlwcDFLGPCQ=="
          crossorigin=""></script>

  <!-- サンプル通りにスクリプトを書いていて･･･ -->
  <script>
    //                ↓描画先指定 任意のワードにできる
    var map = L.map('map').setView([51.505, -0.09], 13);
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(map);
  </script>
</head>

<!-- id="map" の要素を用意しているのに･･･ -->
<body>
  <!--     ↓上で示した描画先指定 -->
  <div id="map" style="width: 800px; height: 600px"></div>
</body>

</html>
```

`Map container not found.` と言われてしまう･･･どうして･･･

![screen.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540894/4a86a1bb-5c1a-5e3b-7d96-d09b38521a5c.png)

## 解法 1

`window.addEventListener` により、ドキュメント読み込み完了後に、マップ設定のスクリプトが動くようにしてやれば OK です。

```html
  <script>
    window.addEventListener("load", function() {
      var map = L.map('map').setView([51.505, -0.09], 13);
      L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
      }).addTo(map);
    });
  </script>
```

## 解放 2

(コメントもらってだいぶ経った 2023/05/13 に追記)

@gacktomo さんより、コメントで頂いた方法です。

マップ描画のスクリプトを `body` の末尾、つまり当該描画先の要素の下にスクリプトを書いてやっても OK です。

```html
<body>
  <div id="map" style="width: 800px; height: 600px"></div>

  <script>
    var map = L.map('map').setView([51.505, -0.09], 13);
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(map);
  </script>
</body>
```

## 原因

HTML が全て読み込まれる前にスクリプトが走ってしまい、その結果書いたはずの `<div id="map">` が存在しない状態で動いて、というのが原因です。

`getElementById` なんかでも、あるはずの要素が `null` を返される場合、同じ原因であるかもです。

ちなみに Leaflet について、「CSS の後に JS の順で読み込まないと動かない」と他のページにて解説されていますが、JS の後に CSS にしても、なぜか私の環境と上記コードのバージョンだと問題無く動きました。

## 参考

この記事のコードは、Leaflet 公式のサンプルコードがベースです。

https://leafletjs.com/

https://leafletjs.com/examples/quick-start/
JNIをcallbackから呼び出す

# 概要
JNIをcallbackから呼び出す時、エラーが発生したためその対処法について

# callbackからJNIを使用するとエラーが発生する
以下のコードでJavaVMとJNIEnvを取得しておく。そのJNIEnvをcallbackから使用するとエラーが発生する。

```cpp:
#include <jni.h>
JavaVM* jvm;
JNIEnv* env;

jint JNI_OnLoad(JavaVM *vm, void* reserved) {
	jint jni_version = JNI_VERSION_1_6;
	if (vm->GetEnv(reinterpret_cast<void **>(&env), jni_version) != JNI_OK) {
		return JNI_ERR;
	}
	jvm = vm;
	return jni_version;
}

JNIEnv* getEnv() {
	return env;
}
```

# 対処法
JNIEnvはカレントスレッドのみで使用可能らしく、callbackから使用する場合には新しく取得する必要があるらしい。
callbackから使用する場合には以下のコードでJNIEnvを取得する。

```cpp:
JNIEnv* getCurrentThreadEnv() {
    JNIEnv* _env;
    jvm->AttachCurrentThread(&_env, NULL);
    return _env;
}
```
配列内のハッシュの平均値の求め方

# はじめに
Qiita初投稿です。
プログラミング初心者で、日々の学習ログとして投稿していきたいと思っています。
理解が不十分だったり、誤った記述などがあった際にはご教示いただけると幸いです。
# やりたいこと
書籍の情報が入った配列booksが定義されています。
```ruby
books = [{author: "宮沢賢治", title: "注文の多い料理店", price: 1800}, {author: "芥川龍之介", title: "羅生門", price: 2000}...]
```
書籍情報の一覧から全金額の平均値を求めたい。
平均は金額の合計を要素の数で割れば良いので、
金額の合計値をどう導き出すか、要素の数はどうすれば取得できるかがわかれば平均値を求めることができそうです。
# 使用するメソッド
要素数を取得するために使用するメソッドと、要素の合計を取得するために使用するメソッドを先に示します。
## length, size
[String#length　公式リファレンス](https://docs.ruby-lang.org/ja/latest/method/String/i/length.html)
要素数の取得に使用します。
lengthメソッドとsizeメソッドはエイリアスメソッドの関係にあります。つまり、どちらを使っても同じ結果が返ってきます。
`文字列.length`は文字数を返し、`配列.length`は配列の要素数を返してくれます。
## sum
[Array#sum 公式リファレンス](https://docs.ruby-lang.org/ja/latest/method/Array/i/sum.html)
要素の合計を返すメソッドです。
`[1, 2, 3].sum #=> 6`
配列内の数値の合計を返してくれます。

`[2.5, 3.0].sum(0.0) {|e| e * e }   #=> 15.25`
ブロックが与えられた場合、加算する前に各要素にブロックが適用されます。
上記の例では、配列に対して、二乗するように指定されているので、
(2.5 * 2.5) + (3.0 * 3.0) が計算されて、15.25という数値が返されています。
ブロック変数は任意の文字を指定することができます。

# 合計値の求め方
繰り返し処理で合計を求める方法と、上記のsumメソッドを使用する方法があります。

## 繰り返し処理で値を取り出す方法
```ruby
total = 0
books.each do |book|
  total += book[:price]
end
```
配列の中から、一つずつ値を取り出し、変数totalに加算していく方法です。
## sumメソッドを使用する方法
```ruby
books.sum { |book| book[:price] } 
```
sumメソッドにブロックを与えて、加算する前に:priceの値を取得するように指示しています。
こうすることで、配列に含まれたハッシュ内の値を取り出して加算することができます。
# まとめ
平均値を求めたいので、最終的なコードは以下のようになります。
```ruby
books = [{author: "宮沢賢治", title: "注文の多い料理店", price: 1800}, {author: "芥川龍之介", title: "羅生門", price: 2000}...]
price_average = books.sum { |book| book[:price]} / books.length
puts "平均価格：#{price_average}円"
```
# 参考にした記事
https://qiita.com/rllllho/items/94e8fde8266f14275961
AWSのEC2にApacheサーバーを設定してWebサーバーを立ち上げる（備忘録）

# Apacheサーバーのインストール

EC2サーバーにログイン後

```
//ルートに移動
$ sudo su

//不足しているパッケージの追加
$ yum update -y

//Apacheサーバーをインストール
$ yum install httpd -y

```

# Apacheサーバーを立ち上げWebサーバーを設置

```
//Apacheサーバーの起動
$ service httpd start

//Webサーバーを立ち上げるためのディレクトリを作成
$ cd /var/www/html

//先ほど作成したディレクトリにindex.htmlを作成
$ ls
$ nano index.html
```

別Windowが立ち上がるので"Hello World!!"を表示させるhtmlコマンドを入力する

```html
<html><h1>Hello World!!</h1></html>
```

Ctrl + x で保存すると、終了するかを確認されるので、yを押してEnterで終了する。

```
//Apacheサーバーを再起動
$ service httpd restart
```

ブラウザにEC2のパブリックIPアドレスをベタ打ちすると、先ほど作成したWebサイトが表示される。
[![Image from Gyazo](https://i.gyazo.com/b25483d829f54871110ff5b9cf5f522b.png)](https://gyazo.com/b25483d829f54871110ff5b9cf5f522b)
「[ERROR] [FATAL] InnoDB: Table flags are 0 in the data dictionary but the flags in file ./ibdata1 are 0x4800!」エラーの対処法


　この記事では、初学者である私がDockerを利用してRails, Nginx, MySQLの環境構築の際に直面したエラーを自己解決した方法を記載します。ググって色々な記事を参照したのですが解決しませんでした。結論から述べますと、MySQLのバージョン対応によるエラーでした。
各バージョンは以下になります。
* Rails: 7.0.2.4
* Nginx: 1.20.2
* MySQL: 5.7 → 8.0 (変更後)

今後、開発を進めていくうえで別の問題が発生しましたら追記する次第です。
同じ状況の方の一助となれば幸いです。
内容に誤り等ございましたらコメントよろしくお願いします。
PHPで時刻（00:00:00）を秒に変換する方法

##はじめに

仕事柄、頻繁に時刻であったり記録（●●分●●秒など）を扱う機会が多いです。

PHPで時間（時刻）を計算するには、UNIXタイムスタンプの値を操作することで求めることができますが、「時刻じゃなくて記録（36時間24分56秒などもあり）なんだよな～」、「一度秒にしてから四則計算してこんなことをしたいんだよな～」と思うことが多々ありました。

大したことは全くしていませんが、誰かの参考になれば幸いです。


##時間（00:00:00）から秒へ変換
```php:php
// 時間から秒へ変換(00:00:00→00000秒)
function hour_to_sec(string $str): int
{
    $t = explode(":", $str); //配列（$t[0]（時）、$t[1]（分）、$t[2]（秒））にする
    $h = (int)$t[0];
    if (isset($t[1])) { //分の部分に値が入っているか確認
        $m = (int)$t[1];
    } else {
        $m = 0;
    }
    if (isset($t[2])) { //秒の部分に値が入っているか確認
        $s = (int)$t[2];
    } else {
        $s = 0;
    }
    return ($h * 60 * 60) + ($m * 60) + $s;
}
```

秒に変換してしまえば後は煮るなり焼くなりしてお好きなように :)

念のため、再度時間表記（0:00:00）に戻すやり方も記載させていただきます。


##秒から時間(0:00:00)へ変換
```php:php

// 秒⇒時間：分：秒へ変換(0:00:00表記)
function sec_to_hour(int $sec): int
{
    $hours = floor($sec / 3600); //時間
    $minutes = floor(($sec / 60) % 60); //分
    $seconds = floor($sec % 60); //秒
    $hms = sprintf("%2d:%02d:%02d", $hours, $minutes, $seconds);
    return $hms;
}
```

後半に出てきた**sprintf**
**指定したフォーマット（形式）で文字列を生成**という感じですかね。
（たまにExcelの表記とかで見ますね）

(型指定子と呼ばれる部分)
**「%」**：第二引数から順番に入れていく部分
**「2」**：桁数（0ありなら03や05などで表記してくれる、無い場合は空白で埋めてくれる）
**「d」**：10進数の整数を指定

この部分を「%2d時%02d分%02d秒」とすれば「1時間23分45秒」などの結果を得ることもできます。


##備考
**ミリ秒**が発生するような場合は上記では**正確な結果が得られません。**
~~stropsで無理やり無くしても...~~
~~ミリ秒ぐらい別に誰も困らないと思っている自分~~

また時間を見つけて記載させていただきます...


##最後に
まだまだコードの書き方含めまして拙い部分が多々あるかと思います。

『もっとこんな方法もあるよ！』

『このやりかたの方が処理が速い』

などありましたら是非コメント欄にて教えていただければ幸いです。


##参考にさせていただいたサイト
>- [PHP 秒数を時分秒に変換](https://oc-technote.com/php/php%20%E7%A7%92%E6%95%B0%E3%82%92%E6%99%82%E5%88%86%E7%A7%92%E3%81%AB%E5%A4%89%E6%8F%9B/)
>- [【PHP入門】sprintf関数の使い方まとめ（0埋め、スペース埋め）](https://www.sejuku.net/blog/24090)
AWS SSH 認証のメモ（備忘録）

# 備忘録

```
// 秘密鍵をsshディレクトリに移動
$ mv ~/Downloads/[ファイル名] ~/.ssh/

// 秘密鍵の使用設定
$　chmod 400 ~/.ssh/[ファイル名]

// 秘密鍵を使用してEC2にログイン
$ssh -i ~/.ssh/[ファイル名] ec2-user@[EC2のパブリックIPアドレス]

//ログアウトする場合
$ exit

```
pythonで画像を実寸大印刷してみる

## はじめに

皆さん、「この画像を8cm × 4cmで印刷したい！」という時にどうすればいいかご存知でしょうか？
ちなみに私はわかりませんでした。

調べてみるとExcelでああしてWordではこうして・・と説明されるのですが面倒になって諦めました。
という訳で、pythonで実寸大印刷するコードを書いてみます。

※Windowsのみで動作します

## コード
```python
import win32print
import win32ui
from PIL import Image, ImageWin

class Printer:
    # 下記はプリンタの固有情報を取得するためのキー
    # http://chokuto.ifdef.jp/urawaza/api/GetDeviceCaps.html
    WIDTH_IN_PIXEL = 8
    HEIGHT_IN_PIXEL = 10
    WIDTH_IN_MM = 4
    HEIGHT_IN_MM = 6
    LOGPIXELSX = 88
    LOGPIXELSY = 90
    PHYSICALWIDTH = 110
    PHYSICALHEIGHT = 111
    PHYSICALOFFSETX = 112
    PHYSICALOFFSETY = 113
    
    # 印刷したいサイズ（mm）から画像サイズ（px）を導き出す
    def trans_mm_to_pixel(self, hDC, x_mm, y_mm):
        printable_area_px = hDC.GetDeviceCaps (self.WIDTH_IN_PIXEL), hDC.GetDeviceCaps (self.HEIGHT_IN_PIXEL)
        printable_area_mm = hDC.GetDeviceCaps (self.WIDTH_IN_MM), hDC.GetDeviceCaps (self.HEIGHT_IN_MM)

        px_px, py_px = printable_area_px
        px_mm, py_mm = printable_area_mm
        
        result = (x_mm * px_px / px_mm, y_mm * py_px / py_mm)
        
        return result
        
    # パスで指定した画像を指定した大きさで印刷する
    def print_image(self, image_path, x_mm, y_mm):
        printer_name = win32print.GetDefaultPrinter()
        
        hDC = win32ui.CreateDC ()
        hDC.CreatePrinterDC (printer_name)
        printable_area = hDC.GetDeviceCaps (self.WIDTH_IN_PIXEL), hDC.GetDeviceCaps (self.HEIGHT_IN_PIXEL)
        printer_size = hDC.GetDeviceCaps (self.PHYSICALWIDTH), hDC.GetDeviceCaps (self.PHYSICALHEIGHT)
        printer_margins = hDC.GetDeviceCaps (self.PHYSICALOFFSETX), hDC.GetDeviceCaps (self.PHYSICALOFFSETY)
        
        hDC.StartDoc(image_path)
        hDC.StartPage()
        
        bmp = Image.open (image_path)
        dib = ImageWin.Dib(bmp)
        scaled_width, scaled_height = self.trans_mm_to_pixel(hDC, x_mm, y_mm)

        # 中央に画像を印刷するように
        x1 = int ((printer_size[0] - scaled_width) / 2)
        y1 = int ((printer_size[1] - scaled_height) / 2)
        x2 = int (x1 + scaled_width)
        y2 = int (y1 + scaled_height)
        dib.draw (hDC.GetHandleOutput(), (x1, y1, x2, y2))

        hDC.EndPage ()
        hDC.EndDoc ()
        hDC.DeleteDC ()
```
画像印刷するコードは下記サイトを大いに参考にさせていただきました。
http://timgolden.me.uk/python/win32_how_do_i/print.html

実寸大で印刷するために、プリンタの印刷可能領域のmm値とpixel値から画像サイズを導出しています。

## 印刷してみる
正しい大きさで印刷できるか検証するために、ものさしの画像を印刷してみます。
<img width="200" alt="4cm.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130234/0bbcf51e-9135-af6e-2d1f-8c319f78a8ba.jpeg">
次のコードを実行すると自動的に印刷を開始します（OSでデフォルト指定されたプリンターが動作します）
```python
printer = Printer()
printer.print_image("4cm.jpg", 40, 40)
```

印刷結果
![print_result.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130234/0e84280c-1169-f602-dc31-9c7b9a88edf4.jpeg)

## おわりに
pythonで簡単に？実寸大印刷することができました。
私の家のプリンターでしか試していないためすべての環境で動作することは保証できませんが、是非お試しあれ。
Bracket Pair Colorizerは非推奨なのでvscode標準のBracket機能を使いましょう

今回は、Bracket Pair Colorizerが非推奨になった代わりにvscode標準機能になったので、後者を使うようにしましょう記事です。

# Bracket Pair Colorizerとは？

コードの括弧の色付けが入るvscodeの拡張機能の一つです。
コードの視認性が爆上がりする機能のためvscodeオススメ拡張機能の定番として、多くの人に愛されてきました。

https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer-2

## 非推奨になってからの流れ

※さっさと標準機能をオンする方法だけ見たい人はここの節は飛ばしてください。

ところがこの拡張機能、実は2021年6月に非推奨になっていたのをご存知でしょうか？
お知らせはこちらのコミットのCHANGELOG.mdから確認できます。このときはまだ標準機能が登場してなかったため代替の拡張機能が案内されていました。ただ案内されていた拡張機能の評判は乏しく結局使い続ける人が大多数だった記憶があります。

https://github.com/CoenraadS/Bracket-Pair-Colorizer-2/commit/d3f1467c5ebdcf4bfc47d357a48b26491da1e254#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4ed

非推奨になった原因は定かではありませんが、拡張機能を有効化するとvscodeのパフォーマンスが悪化する問題を解決できなかったこと、それによってメンテナンスする意欲がなくなってしまったのではないかと推測されています。

https://www.reddit.com/r/vscode/comments/n1xoss/why_was_the_brackets_pair_colorizer_extension/

この流れが続くのかと思われましたが2ヶ月後の8月、vscode公式から大ニュースが発表されました。
なんとBracket Pair Colorizerとほぼ同等の機能がvscode標準機能として搭載されること、そしてパフォーマンス改善がなされた上でというニュースでした。

https://code.visualstudio.com/updates/v1_60#_high-performance-bracket-pair-colorization

そのあともバージョンアップを重ね現在進行系で改善が続いています。標準機能として搭載することになった経緯や改善秘話を詳しく知りたい人はこちらの記事が詳しいです。

https://code.visualstudio.com/blogs/2021/09/29/bracket-pair-colorization

# vscodeで括弧の色付け機能をOnにする
vscodeバージョン1.67以降を使用している場合は、デフォルトでonになっているため**対応不要**です。

https://code.visualstudio.com/updates/v1_67#_bracket-pair-colorization-enabled-by-default

以下バージョン1.66以前使っている人向けの手順です。

`cmd`（windowsは`ctrl`）+`,`で設定を開き、
検索ボックスに`bracket`と入力し、`bracketPairColorization`にチェック/`bracketPairs`を`active`に変更

もしくは**setting.json**を開いて以下を追加する形でも可能です。

```diff_json:setting.json
{
+   "editor.bracketPairColorization.enabled": true,
+   "editor.guides.bracketPairs":"active"
}
```

するとこんな感じで設定されているはず。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/919803/97afdd73-92f0-398b-222b-ecc4cd76f8ff.png)


コードを開いて、括弧を選択すると色付けされていてどこからどこまでネストされているかが見やすくなります。
※画像は`tsx`ファイル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/919803/02689411-2a78-0068-95fd-e9e3cf1d454d.png)


Bracket-Pair-Colorizer-2のREADMEでも先頭で親切に案内されています。

https://github.com/CoenraadS/Bracket-Pair-Colorizer-2#-christmas-notice-%EF%B8%8F

もうメンテナンスされていない拡張機能を使うのはあまりよろしくないのと、vscodeのパフォーマンス的に優しいので、これからは標準機能を使っていこうねっていう話でした。


今回は以上です。
楽して使うTkinter（ウィジット編）

# 楽して使うTkinter（ウィジット編）

同じコードをコピペするというのはその場では簡単かもしれませんけれども後々地獄になりがちです。ちょっとした動作の変更をしたいのに直す場所が多数、しかも分散していて、とか目も当てられません。

ずぼらに楽をするには一か所直せばすべて直るくらいの勢いでスマートにやりたいものです。

今回はよくある疑問でよく目にする

- ラベルの文字って後からどうやって変えるのー？

あたりをやってみましょうか。

## じぶんLabelウィジットクラスを作る。


tk.Labelを継承して じぶんラベル を作ります。

じぶんウィジットなので好きなように作ります。ポイントは毎回毎回書いていてめんどくさいなっていう部分はフォローしておくこと。

自分自身が使いやすければ、少なくとも自分しか使わないなら。最悪動作するならば何も問題ありません。好きにやりましょう。

```python:label.py
import tkinter as tk

class Label(tk.Label):
    def __init__(self, root, cnf={}, **kw):
        super().__init__(root, cnf, **kw)

        # tkinterで動的に内容を変えるにはWidget変数を使う
        self.val = tk.StringVar()
        self["textvariable"] = self.val


        keys = kw.keys()

        # 引数でテキストが渡されていたらwidget変数に入れてやる
        if "text" in keys:
            self.set(kw["text"])

        # 引数で以下が渡されていない場合は左揃えになるように
        # 設定しておく。
        if not "anchor" in keys:
            self["anchor"] = "nw"

        if not "justify" in keys:
            self["justify"] = "left"

    def set(self, text):
        self.val.set(str(text))

    def get(self):
        return self.val.get()
```

わたしはラベルが中央ぞろえになるのがどうも苦手というか毎回面倒に思うので左に揃うようにしてみました。

あとはラベルの内容を変更・取得するための set, get を定義、ひとまずこんなもんでしょうか。

さらに突っ込むなら色だとかフォントだとかも弄っておくと楽かもしれませんねー。

## 使ってみよう。

作った label.py と同じ場所に適当なスクリプトをつくって試します。

```python
import tkinter as tk
import label
import random

root = tk.Tk()

l = label.Label(root, text="hello")
l.bind("<Button-1>", lambda x: print(l.get()))
l.bind("<Button-3>", lambda x: l.set(random.randint(1,10)))
l.pack(fill="x")

root.mainloop()
```

こんな感じ。機能を試すため、ラベルを左クリックでラベルの内容がコンソールに表示されて、ラベルを右クリックするとランダムに選ばれた数字がラベルに設定されますよ。

## 〆

今回ラベルウィジットに関してやってみたけど、これはエントリーとか他も大体一緒。とにかく楽をするためには、**お決まりの処理はまとめておく** こと。これはとっても大切、約束だよ！
chromeでAudioContextが動かない時の対処法

わかってそうなタイトルですが何が起こってるのか全然わかってません。ただ、こうしたら動きました。

```sample.js
const audioCtx = new AudioContext()
audioCtx.onstatechange = () => {
  if(audioCtx.state !== 'running')
    audioCtx.resume()
}
```
以下の記事を参考にしました。
https://developer.mozilla.org/en-US/docs/Web/API/BaseAudioContext/state

### AudioContext.stateについて

AudioContextには状態を表すstateプロパティがあり、以下の3つの値を取ります。

- **runnning**
正常に動いている状態

- **suspended**
一時停止状態

- **closed**
AudioContext.close()を呼び出した後に設定される状態

- (**interrupted**)
~~なんやこれ~~

chromeではユーザーアクションなしでAudioContextを作成するとデフォルトでstateに"suspended"が設定されるようです。

### 他に登場するもの
AudioContext.stateの他に上記のコードで登場するものの説明です。

- **AudioContext.onstatechange**
stateに変更があったときに呼び出さるイベントハンドラです。

- **AudioContext.resume**()
state === "suspended"のAudioContextを再び動くようにするメソッドです。

### 結論


上記のコードを記述することでaudioCtxが使えるようになったわけですが、AudioContextを作成したあとのどこかのタイミングでstateが変更されていると考えられます。そのおかげでonstatechangeにaudioCtx.resume()を記述して強制的にstateを"running"に戻せているわけですが、肝心の

***いつ、なんでstateが変更されるの？***

という疑問の答えについてはわかりません。

誰か教えて〜〜（トライさんの気分）（古）
はじめて読む8086用環境の構築（Windows用）

# はじめて読む8086用環境の構築（Windows用）

- 2021年に作成したメモを公開
- 著者の蒲地輝尚さんとすばらしいツールの製作者様に感謝
- 蒲地輝尚(1987)『はじめて読む8086』アスキー出版

## 1. ツール

### Neko Project 21/W

- 通常版をダウンロード
- GoogleDriveが開かれるから、右上のダウンロードをクリック

<https://simk98.github.io/np21w/download.html>

### FreeDOS(98)

- MS-DOSの代替
- FreeDOS(98)各種PC-98エミュレータ用ハードディスクイメージ（HDI形式）: fd98_hd_250m_20210303.zip をクリック

<https://bauxite.sakura.ne.jp/software/dos/freedos.htm>

<https://github.com/lpproj/fdkernel/releases/tag/test-20210226>

### DDEB

- `DEBUG`, `SYMDEB`の代替

<https://www.vector.co.jp/soft/dos/prog/se014328.html>

### DUMP for DOS

- `DUMP`の代替

<https://www.vector.co.jp/soft/dl/dos/util/se012414.html>

### Arrowsoft Assembler 2.0

- `MASM`の代替

<https://hp.vector.co.jp/authors/VA007890/dos/language.html>

### VAL

- `LINK`の代替

<https://hp.vector.co.jp/authors/VA007890/dos/language.html#VAL>

### EXE2COM

- `EXE2BIN`の代替

<https://hp.vector.co.jp/authors/VA007890/dos/language.html>

### CAT

- `DISKCOPY.COM`の代わりに編集するソフト

<https://www.vector.co.jp/soft/dos/util/se003729.html>

### 7-Zip

- ファイルの圧縮・解凍ツール
- `.lzh`や`.zip`を展開できるソフトがすでに導入されているなら不要

<https://sevenzip.osdn.jp/>

### DiskExplorer

- `.hdi`ファイルの編集ツール
- editd169.lzh (270,194 bytes) Ver1.69 をクリック

<https://hp.vector.co.jp/authors/VA013937/editdisk/index.html>

## 2. ハードディスクイメージ作成

1. ダウンロードした`.zip`や`.lzh`ファイルなどのを圧縮ファイルを7-Zip等で展開する
2. `ALPHA.ASM`と`CDUMP.ASM`を含む`8086`ディレクトリに、以下のものを入れる
   - `arrowasm`ディレクトリにある、`ASM.EXE`
   - `vallink`ディレクトリにある、`VAL.EXE`
   - `execom14`ディレクトリにある、`EXE2COM.EXE`
   - `dump045d`ディレクトリにある、`DUMP.COM`
   - `ddeb116b`ディレクトリにある、`DDEB.EXE`
   - `cat19`ディレクトリにある、`CAT.COM`
3. DiskExplorerでFreeDOS(98)の`.hdi`ファイルを、ANEX86 HDDプロファイルで開く
4. 開いた`.hdi`ファイルのルートディレクトリに、`8086`ディレクトリをドラッグアンドドロップしてコピーする

## 3. エミュレータの起動

- 2~3については、一度の設定で有効になるから、次回以降の操作は不要

1. np21のbinにある、`np21x64w.exe`を起動
2. Harddisk→IDE #0→Open→準備した`.hdi`を開く
3. Emulate→Reset
4. Boot Select Menuでは、基本的に286を選択。不都合なことがあれば386
5. `A:\>cd 8086` で`8086`ディレクトリへ移動。ここで操作を行う

## 4. 注意点

- `DEBUG`または`SYMDEB`は、`DDEB`と読み替える
- `MASM`は、`ASM`と読み替える
- `LINK`は、`VAL`と読み替える
- `EXE2BIN`は、`EXE2COM`と読み替える
- MS-DOSやFreeDOSは、現代のOSとは異なり、コンピュータの保護機能がない
  - つまり、誤った操作をすると、`.hdi`ファイルが破損してしまうことがある
  - 頻繁に`.hdi`ファイルをコピーするなどして、バックアップを取ることを推奨する
- 3章で編集する`DISKCOPY.COM`は無料で入手できないから、代わりにダウンロードした`CAT.COM`を使用する
  1. まず、`A:\>cat asdf`のように、存在しないファイルを引数に与えて、エラーメッセージを確認する
  2. `0x0501`番地から12バイトほどエラーメッセージの領域となっているから、そこを`DDEB`で編集する（`E 601 'hamachi'`等を入力）
  3. 編集が終わったら、先程のように、存在しないファイルを引数に与えると編集結果が確認できる
  4. 日本語入力には対応していないようだから、日本語を打つ場合は、`E 601`として、`93 5d 91 97 8c b3`（転送元）というふうに、バイナリを直打ちする

### DDEBに関する注意点

- `E`実行時、次のアドレスへ行くには、スペースキーを押す
- `E`を終了するには、エンターキーを押す
- `R`実行時、`AX`, `BX`, `CX`, `DX`, `SI`, `DI`, `BP`レジスタに`E`がついて、32bit幅となっているが、本のように、`E`抜きで16bit幅とみなして使う
- `IP`レジスタには、`R`を実行したときに表示されるアドレスである`XXXX:YYYY`の`YYYY`が入っていると考える
- レジスタを変更する場合は、`R <レジスタ> <16進数値>`とする
- `T=<数値>`と書いてある場合は、代わりに`R IP <数値>`とすることで正しく動作する