OmniAICreator/Qiita-1.07M huggingface dataset:
LINE BotとGASで年毎に家族写真を貯める


# 今朝の話
おうちの断捨離を進めているところなんですが、子供達の写真の管理の話になった。
アルバムを用意して物理で貯める、という案を夫が出してきたのでイヤイヤイヤ！ということでこの機会に電子化する方向に持っていくことにした。

# 構想
基本はどこかのアルバムサービスに依存するよりは、Googleドライブに入れたい
スキャンして保存、の流れが理想
スマホでスキャンもOK
うん、Googleドライブに普通にアップロードすれば良いよね。うちのスキャナーはフォルダ保存に対応しているし。
・・・・・
そういや夫はスキャナーからフォルダ保存覚えられないんだった！！まじかよ、、、

ということで、LINEに送ったものを自動で保存していくことにしました。

# 仕組み

ほぼほぼみんなやり尽くされているので簡単です。

- LINE Bot（MessageingAPI）でアクセスキーを取得
- GASのdoPostでWebHookを作る

前回やったときはwebhookはherokuで作ってたけど、最近はGASの方が慣れてきたので多分今やるならこちらの方が早い。

参考にしたのはここ

- https://www.yukibnb.com/entry/linemessagingapi_gas_save_image

変更箇所

- Momentライブラリは使わずにUtilitiesを使用

```javascript
var date = new Date(); //現在日時を取得
var formattedDate = Utilities.formatDate(date, "JST", "yyyyMMdd-HHmmss");
```

- ルートフォルダ以下に年（YYYY）ごとのフォルダを作成し、貯めるべきフォルダIDを取得するメソッドを新設。

```javascript
// 年ごとのフォルダIDを作成する
function getFolderPathOfYear(year){
  folder = DriveApp.getFolderById(ROOT_FOLDER_ID);
  childFolders = folder.getFolders();

  while(childFolders.hasNext()){
    childFolder = childFolders.next()
    if(year == childFolder.getName()){
      Logger.log(childFolder.getId())
      return childFolder.getId()
    }
  }  
  //見つからない場合作る
  newfolder = folder.createFolder(year)
  Logger.log(newfolder.getId())
  return newfolder.getId()

}
```

- 夫とのLINEのやりとりにLINE Botを招待したいため、画像じゃない場合にアラートは不要なので削除
- doPostだとLogger.logが出てくれないのでスプレッドシートにlogを吐き出す。（毎度やるもの）これじゃなくてログを出す方法があるなら教えて欲しい

```javascript
function logSpreadsheet(memo){
    // 現在開いているスプレッドシートを取得
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  
  // 現在開いているシートを取得
  var sheet = spreadsheet.getSheetByName("log")
  

  let lastRow = sheet.getLastRow();
  // 指定したセルの値を変更する
  Logger.log(lastRow+1, memo)
  sheet.getRange(lastRow+1,1).setValue(memo);
}
```

# 全量　＆　導入方法
多分以下の流れでそのまま使えるはず、、、、

- スプレッドシートに「log」を用意
- スプレッドシートから作成したAppScriptに全量コピペ
- LINE Developersからアクセストークンを取得
- 取得したトークンをAppScriptに貼り付け
- ドライブにルート用のフォルダを作成
- ルートフォルダのIDをAppScriptに貼り付け
- GAS公開
- URLをLINE Developersのwebhookに貼り付け

https://github.com/prettyhappycatty/line-to-drive/blob/main/line_to_drive.gs

# 補足

過去の紙媒体のものは普通にスキャナーから保存するつもり。
（というか、私はLINE経由せずにスキャナーから保存するような気がする）
携帯で撮った写真をLINEで送り合ったのが勝手にたまるのを期待しています。
上手くいけばいいな。
【Moq】関数内の処理が実行されたことを検査するテスト

# 関数内の処理が実行されたことを検査する  
Excelへの描画や画像描画など、関数の結果を直接検査することが難しい時のテスト手法です。

関数の実行は[Moqライブラリ](https://github.com/moq/moq4)の[Verify](https://github.com/moq/moq4/blob/b7b07279c45c29a201399a7fa93764892422e687/src/Moq/ISetup.cs#L114)を用いて確認することができます。
下記のコードにて、Broker.Sell()内でartが思ったとおりに作成されることを検査したいとする。

```csharp
public class Broker
{
	public void Sell()
	{
		// artを作らせる
		var canvas = new Bitmap(10, 100);
		var inspiration = "台北";
		var art = new Calligrapher().Draw(canvas, inspiration, 1, 1);

		// artを売る
		new Buyer().Buy(art);
	}
}

public class Calligrapher : IArtist
{
	public Bitmap Draw(Bitmap canvas, string inspiration, int x, int y)
	{
		// Bitmapにstringを描画する
		using var g = Graphics.FromImage(canvas);
		g.DrawString(inspiration, new Font("Arial", 12), Brushes.Blue, new Point(x, y));

		return canvas;
	}
}
```

Sell()の返り値がわかればそれを検査したいのだが、void型の場合は関数内部で実行されたことを確認する他ない。
テストは下記のようになる。

```csharp
[Test]
public void Test()
{
	// 実行を確認したい座標をSetup
	var mock = new Mock<IArtist>();
	mock
	.Setup(x => x.Draw(It.IsAny<Bitmap>, It.IsAny<string>, 1, 1))
	.Verifiable();

	var canvas = new Bitmap(10, 100);
	var inspiration = "テスト";
	new Calligrapher(mock.Object).Draw(canvas, inspiration);

	// 実態クラスで検査されたか確認
	mock.Verify();
}
```
こうすることでBroker.Sell()内部でCalligrapher.Draw()が（Setupした値で）実行されたことが確認できる。
もしSetupで設定した値で実行されない場合はmock.Verify()で例外がスローされる。



# 組み込みクラスの場合

下記コードで正しくBitmapが生成されたことをテストしたい。
Bitmapをピクセル単位で見ることなく実行されたことを確かめる。

```csharp
public class Calligrapher
{
	public Bitmap Draw(Bitmap canvas, string inspiration)
	{
		// Bitmapにstringを描画する
		using var g = Graphics.FromImage(canvas);
		g.DrawString(inspiration, new Font("Arial", 12), Brushes.Blue, new Point(1, 1));

		return canvas;
	}
}
```

テストでは入力・出力を確認すればよいので、今回はBitmap上に描画される座標が確かめられれば良い為、Moqでスタブを作って確かめる。
しかし現行コードだとDraw()の入出力はテスト側でスタブを作れるが描画する座標は確認できない。

```csharp
// 検査したい組み込みクラスをIFとして公開する
public class GraphicsRapper : IGgraphicsRap
{
	public void DrawString(Bitmap canvas, string char, Font font, Brushes color, Point point)
	{
		using var g = Graphics.FromImage(canvas);
		g.DrawString(char, font, color, point);
	}
}

public class Calligrapher
{
	private IGgraphicsRap _graphicsRapper

	// コンストラクタで入れる
	public Calligrapher(IGgraphicsRap graphicsRapper)
	{
		_graphicsRapper = graphicsRapper;
	}

	public Bitmap Draw(Bitmap canvas, string inspiration)
	{
		_graphicsRapper.DrawString(canvas, char, font, color, point);
		return canvas;
	}
}

[Test]
public void Test()
{
	//　検査したい条件をSetup. 検査したいの座標なので座標以外はIt.IsAny<>で型だけ指定する.
	var mock = new Mock<IGraphicsRap>();
	mock
	.Setup(x => x.DrawStinrg(It.IsAny<Bitmap>, It.IsAny<string>, It.IsAny<Font>, It.IsAny<Brushes>, new Point(1, 1)))
	.Verifiable();

	new Calligrapher(mock.Object).Draw("テスト");

	// 実態クラスで検査されたか確認
	mock.Verify();
}
```

こうすることでBitmpのようなIFのない組み込みクラスでも実行されたか検査することができる.
IFさえ作ってしまえば検査することは可能になる。

注意点としては、テストがメソッドの内部実装に依存してしまっているので実装を変更したらテストも修正しないとならない可能性があります。
JavaでBase64符号化・復号化を省メモリに行う

## 概要
Java 8からjava.util.Base64が導入されてBase64符号化・復号化が標準ライブラリで可能になった。
しかし、一般的な実装だと符号化前データの数倍のメモリが必要になるため、大きなデータを符号化・復号化したい場合にはメモリ使用量の問題が生じる。そこで標準ライブラリによる省メモリなBase64符号化・復号化の実装を考えた。

## 実装

```Base64Sample.java
public class Base64Sample {

    private static final int T_LEN = 16 * 1024;
    private static final int B_LEN = T_LEN * 3 / 4;

    // 符号化
    public static void encode(Path src, Path dst) throws IOException {
        try (InputStream is = Files.newInputStream(src);
                OutputStream os = Files.newOutputStream(dst)) {
            byte[] txt = new byte[T_LEN];
            byte[] bin = new byte[B_LEN];
            int r;
            while ((r = is.read(bin)) != -1) {
                int i = Base64.getEncoder().encode((r == B_LEN) ? bin : Arrays.copyOf(bin, r), txt);
                os.write(txt, 0, i);
            }
        }
    }

    // 復号化
    public static void decode(Path src, Path dst) throws IOException {
        try (InputStream is = Files.newInputStream(src);
                OutputStream os = Files.newOutputStream(dst)) {
            byte[] txt = new byte[T_LEN];
            byte[] bin = new byte[B_LEN];
            int r;
            while ((r = is.read(txt)) != -1) {
                int i = Base64.getDecoder().decode((r == T_LEN) ? txt : Arrays.copyOf(txt, r), bin);
                os.write(bin, 0, i);
            }
        }
    }
}
``` 
入出力がInputStream/OutputStreamであることが前提だが、固定のbyte配列で符号化・復号化することで、全データを一度に保持することを回避している。
注意すべきは復号化対象データの途中に"="が含まれる場合で、byte配列の末尾に来てしまうとエラーにならない。復号化対象が外部入力データなどの場合は別途チェックが必要。

## アンチパターン
あくまで大きなデータを符号化・復号化しなければならない場合のアンチパターンであることに留意。

### メモリ消費

```AntiPattern1.java
// 符号化
String encodedData = Base64.getEncoder().encodeToString(data);
// 復号化
byte[] decodedData = Base64.getDecoder().decode(encodedData);
```
一般的な実装なのだが、データ全体の符号化前byte[]、符号化後byte[]とStringをメモリに保持してしまう [^1]。もちろん、処理対象データがヒープサイズに対して十分小さければ全く問題ない。

[^1]: Encoder/Decoderも内部でnew StringやString#getBytesを使用する

### 処理速度
```AntiPattern2.java
// 符号化
OutputStream os = Base64.getEncoder().wrap(rawos)
// 復号化
InputStream is = Base64.getDecoder().wrap(rawis)
```
InputStream/OutputStreamで符号化・復号化するので省メモリではあるが、処理速度が遅い [^2]。メモリ消費を気にする必要があるほど大きいデータを処理するなら実用的でない。

[^2]: InputStream/OutputStreamの性質上1バイトずつ符号化・復号化するのでオーバヘッドが大きい
Symantec GhostでGhostCastリストアができない

PCの大量展開でお馴染みのSymantec Ghostですが、意外なところでハマったのでメモ。

# 環境
<dl>
<dt>マスターイメージ</dt>
<dd>Windows 10 Pro 21H1</dd>
<dt>作業マシン</dt>
<dd>Windows 10 Pro 20H2</dd>
<dt>GhostCastサーバ</dt>
<dd>Windows Server 2019 Standard</dd>
<dt>Ghostクライアント</dt>
<dd>Windows 10 PE 2004 Build 19041</dd>
<dt>Symantec Ghost バージョン</dt>
<dd>GSS 3.3 RU8</dd>

# 発生事象
ローカルストレージからの単体リストアは正常動作するが、GhostCastリストアができない。
Application Error 33000が発生して、Ghost64.exeが落ちてしまう。

# 対策
マスターイメージ生成時にsplit=0スイッチを使わない。
split=0スイッチは非公式（動作保証外）という扱いのようです。
splitスイッチを使わずに、約2GBで分割されたイメージを用いて再度試したところ、正常動作を確認しました。

WinPEを疑ってBoot Disk Creatorで作ったり、素のWinPEから作り込んだり色々試しましたが、
まさかローカルから正常にリストアできているマスター起因だとは思わず…
勉強になりました。

# 参考
[Alphabetical list of Ghost switches](https://knowledge.broadcom.com/external/article/152308/alphabetical-list-of-ghost-switches.html "Broadcom")

いつのまにかKBが公開されていました。もっと早く知りたかった…
[Unable to restore the non split ghost image file by ghost cast server due to Application Error 33000](https://knowledge.broadcom.com/external/article?articleId=230155)
[GhostCastサーバで分割されていないイメージファイルを復元するとApplication Error 33000が発生する](https://knowledge.broadcom.com/external/article/227922/ghostcastapplication-error-33000.html)
がんばってポートを使用しているプロセスを終了させる（Windows編）


#### どうしてこの記事を書くことになったのか
わたし「npm runとかした後にクラッシュして、ポートが使用中になり続けているときってどうやって消せるんでしょうか…（うまく状況を説明できていない）」
悩み事エスパーの先輩「そういうときに使うコマンドあるよ！」

```
lsof -i :8080
kill -9 <ポート番号>
```

わたし「あ、すみません…私Windowsなのでlsof使えないみたいです…」
悩み事エスパーの先輩「あっ、そうなんだ…」


## lsofの代わりを探す
```
$ netstat -nao | find "8080"
$ taskkill /pid <ポート番号>
```
あるいは

```
$ netstat -nao | find "8080"
$ taskkill /f /pid <ポート番号>
```

参考
[ポートで開いているプロセスを削除する方法（Windows, Mac）](https://qiita.com/yama9112/items/3603dbc900d1ac8f6ec2)


## プロセスをキルすると言えば…

わたし「このコマンド絶妙に覚えられないな…」
わたし「そういえばタスクマネージャーでプロセスっていう欄あるよね」
わたし「ポートを使用しているプロセスはさっきクラッシュしたNode.jsのプロセスだから、Node.jsを終了させればいいはず」
わたし「たくさんあってどれを消せばいいか分かんないけど…」
わたし「全部消すか！」

→無事、埋まっていたポートは解放され問題解消

タスクマネージャーで、ヘッダーを右クリックすると表示項目を変更でき、コマンドラインを表示させることで、全部消すという暴力的な手段に頼らなくても怪しいものからキルすることができます。（PIDなども出せるよ）
![スクリーンショット 2021-12-18 195758.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/756199/76d991f6-7107-39ba-a450-ff5bcdd91c6b.png)


### まとめ
使用頻度がさほど高くないためコマンドを覚えられず、不精ができる方法を見つけたので書きました。
まじめなエンジニアは普通にコマンドを覚えた方が幸せになれます。
~~この記事を書いた結果netstatをしっかり覚えてしまったらどうしようかな…~~
[SSL] Let'sEncryptでSSL化する | Nginx

## やりたいこと
- Let'sEncryptを利用して、無料でSSLサーバ証明書を発行しSSL化する
- CRONを設定して、サーバ証明書を自動更新する

## サーバ証明書
- ウェブサイトで HTTPS (SSL/TLS) を有効にするために必要なデジタル証明書

## Let'sEncryptについて
- ドメイン名を持っている人なら、誰でも無料でサーバ証明書を発行してくれる認証局
- 有効期限は９０日間

## Certbotについて
- 証明書を発行するための、クライアントソフト
- 設定も自動で編集してくれる

---
## 環境
- EC2 
- nginx/1.20.0
- certbot 1.11.0
- Nginxインストール済み、DNS設定済み

---
## 1. EPELパッケージをインストール
Certbotを利用するにあたりEPELをダウンロードする必要がある。
EPEL(Extra Packages for Enterprise Linux)

```shell
$ sudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
```

## 2. インストールしたEPELを有効化
```shell
$ sudo yum-config-manager --enable epel*
```

## 3. Certbotをインストール
nginxのSSL化に必要なパッケージもインストール

```shell
$ sudo yum -y install certbot python2-certbot-nginx
```
`$ sudo yum -y install certbot`  (普通にインストール)

## 4. サーバ証明書を発行
下記のコマンドで、証明書を発行してNginxの設定も自動で編集してくれる

```shell
$ sudo certbot --nginx
```
※ 証明書のみ発行したい場合
`$ sudo certbot certonly --nginx`

## 5.HTTPSが有効になったか確認

(1) Nginxの設定ファイル

```shell
$ view /etc/nginx/conf.d/hostname.conf
```


HTTPS通信に必要な設定が追記されている。

```shell:hostname.conf
    + listen 443 ssl; 
    + ssl_certificate /etc/letsencrypt/live/hostname.net/fullchain.pem;
    + ssl_certificate_key /etc/letsencrypt/live/hostname.net/privkey.pem;
    + include /etc/letsencrypt/options-ssl-nginx.conf;
    + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; 
    ...
    + server {
    + if ($host = hostname.net) {
    +    return 301 https://$host$request_uri;
    + } # managed by Certbot

    + listen 80;
    + server_name hostname.net;
    + return 404; # managed by Certbot
```

(2) Let'sEncryptから発行された証明書の有効期限を確認

```shell:fullchain.pem
$ sudo openssl x509 -in /etc/letsencrypt/live/hostname.net/fullchain.pem -noout -dates
```

証明書の有効期限は、90日後になっている。

```shell:出力結果
notBefore=Dec 15 02:21:26 2021 GMT #発行日  12月15日 
notAfter=Mar 15 02:21:25 2022 GMT  #有効期限 3月15日
```

(3) サイトを確認
証明書が適用されている
![SS 6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1990684/38ca3082-83c9-a71a-597e-380cd23995af.png)


## 6.証明書を自動更新設定
Let'sEncryptの有効期限は3ヶ月のため、証明書を
自動更新されるようにCRONを設定する
`CRON = 指定した時間に、指定したプログラムを動かしてくれる仕組み`

|*  |*  |*  |*  |*  |
|---|---|---|---|---|
|分  |時  |日  |月  |曜日|



毎日、12:00に`$ certbot renew -q`を実行
( -q | --quiet ) = エラーを除くすべての出力を行なわない。（エラーメッセージのみを出力）

```shell
$ echo "0 0,12 * * * root python -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew -q" | sudo tee -a /etc/crontab > /dev/null
```

設定を反映させるため再起動

```shell
$ sudo systemctl restart crond
```

crontabが編集されているか確認

```shell
$ sudo cat /etc/crontab
```

```:実行結果
0 0,12 * * * root python -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew -q
```






## 手動で更新する場合
証明書を更新する

```shell
$ sudo certbot renew
```

※ 証明書の更新は、有効期限から30日切っていないと更新できない
 
30日切っていなくても、強制的に更新する場合は
` $ sudo certbot renew --force-renew ` で可能


## Let'sEncrypt証明書の制限について
 
 - 登録ドメインごとの証明書数の制限は、1週間に50個まで。

公式サイト{`www.example.com の場合、登録ドメインは example.com です。
new.blog.example.co.uk の場合、登録ドメインは example.co.uk になります。`}

- 検証の失敗は、1時間につき5回まで。


公式サイト{`検証の失敗は、1アカウントごと、1ホスト名ごと、1時間毎に、5回までに制限されています。
この制限はステージング環境では緩和されているため、接続の問題をデバッグする場合には、こちらを使ってください`}
日の入りごろに自動で室内照明を点ける

# 日の入りごろに自動で室内照明を点ける

日の入り時刻が近くなったら、自動で室内の照明を点けるフローを作ります。
緯度と経度から日の入り時刻を算出できる、`node-red-contrib-schedex`ノードを使います。
照明を点ける仕組みは、SwitchBotを活用します。

# 作成例

![sample-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2303867/c40aaf8c-c0f3-90cf-198d-0686599d3f79.png)


# 用意するもの

- enebular
    - プロジェクトが作成済みであること
    - [node-red-contrib-schedex](https://flows.nodered.org/node/node-red-contrib-schedex)ノードがフローにインストールされていること
    - Herokuコネクションが作成済みであること
- Heroku
    - アプリが作成済みであること
- [SwitchBot](https://www.switchbot.jp)
    - SwitchBotアカウントが作成済みであること
    - SwitchBotアプリをスマートフォン等にインストール済みであること
    - SwitchBotクラウドサービスがオンになっていること
    - 照明の赤外線リモコンがSwitchBotハブに登録されていること
    - 照明を点ける手動実行のシーンが作成済みであること

SwitchBot APIを呼び出すフローの作り方は、[SwitchBot APIを呼び出すフローを作る](https://qiita.com/parkborn241/private/f2e43b4c486f620c3e29)の記事を参考にしてください。

# 手順

## SwitchBot

まず照明を点ける手動実行のシーンを作ります。
SwitchBotアプリの画面の指示にしたがって、手動実行のシーンを作ります。

ここで作ったシーンのIDを取得するAPIは下記です。

> GET https://api.switch-bot.com/v1.0/scenes

そしてそのシーンを実行するAPIは下記です。

> POST /v1.0/scenes/{sceneId}/execute

シーンの実行を`http request`ノードで実装します。

## enebular

事前に、日の入り時刻を知りたい地点の緯度と経度を、Googleマップ等で調べておきます。

1. フローに`node-red-contrib-schedex`ノードをインストールします。
2. 今回は、日が沈み切る前に照明を点けたいので、`node-red-contrib-schedex`ノードの [On time] 項目に`sunsetStart`と入力します。
3. [Latitude]と[Longitude]にも調べておいた緯度と経度を入力します。

また、日が沈み始める頃にはすでに室内もやや暗いので、オフセットして `-10`分くらいにセットしておきます。


## Heroku

HerokuのFree Dynoを使う場合は、Dynoが肝心な時にスリープしてしまわないように、対策する必要があります。

[Herokuにデプロイしたアプリを眠らせない方法](https://blog.enebular.com/samples/heroku-unsleep-free-dyno/)という記事の ”無料のスケジューラーを使う方法” を参考にしました。

日の入りごろにDynoが起動していれば良いので、数件のジョブを設定しました。2時間程度の幅のジョブを作ったので、日の入り時刻が遅くなっても少なくとも数ヶ月間は対応できるはずです。


![image-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2303867/68a9df64-7826-afe0-e78f-bb3b59115ec6.png)



最後に、作ったフローをHerokuにデプロイします。

これで日の入りごろに自動で照明が点きました​ :tada:
run_everyデコレータについて

# run_everyデコレータ

[新しいPythonエディタのαリリース](https://python.microbit.org/v/alpha)で使える最新の MicroPython (執筆時点では 2.0.0-2021-10-25)ですが、 `run_forever` デコレータが使えます。

デコレータとは、関数の前につける修飾で、関数の処理の前後に処理を付け加えるものです。

たとえば次のように使います。

```python
from microbit import display, Image, run_every

small = False

@run_every(s=1)
def heartbeat():
    global small
    if small:
        display.show(Image.HEART_SMALL)
    else:
        display.show(Image.HEART)
    small = not small
```

大きなハートと小さなハードが１秒おきに切り替わります。

![IMG_5577.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/1d8f958b-e3df-4a7a-3502-a12ed68238c7.gif)

# while ループと何が違うか

動きをみていれば、これは s=1 で指定した秒の間隔で関数 beart の呼び出しを繰り返すものと察しがつくでしょう。

繰り返すだけであれば while ループでもできます。

```python
from microbit import display, Image, sleep

small = False

while True:
    if small:
        display.show(Image.HEART_SMALL)
    else:
        display.show(Image.HEART)
    small = not small
    sleep(1000)
```

では、なぜこんなデコレータが用意されたのでしょうか。

run_everyデコレータは、MakeCodeの「ループ」にあるeveryブロックと同じ働きをします(これはまだ日本語化されてませんね)。なぜかループに分類されていますが、everyブロックが他のループブロックと違っているのは「バックグラウンド」で繰り返すことです。

![スクリーンショット 2021-12-04 12.33.35.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/a7199aab-7a42-2f24-1012-3bb8d053ef06.jpeg)

「バッググラウンド」で実行するとは、メインの処理とは独立に動作することです。つまり、メインの処理とは並行に動かせます。さらには複数のeveryブロックを並行に動かせます。run_everyデコレータは同じことが行えるので、MicroPython でも処理を並行で動かせるようになったのです。

次のもので試してみると、１秒おきに "func_1" が表示され、２秒おきに "func_2" が表示されます。

```python
from microbit import run_every, running_time

@run_every(s=1)
def func_1():
    print(running_time(), "func_1")

@run_every(s=2)
def func_2():
    print(running_time(), "func_2")
```

# MakeCode の「ずっと」と同じことがMicroPythonでもできる

MakeCode に「ずっと」という無限ループに相当するブロックがあり、MicroPythom では「while True」に例えられるたりしてますが、これも単なる無限ループと異なるのは」バックグラウンド」で実行されることです。

![スクリーンショット 2021-12-04 12.34.58.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106817/70fb6769-69a0-d3bc-3f7d-a10020645b79.jpeg)

ちょっと調べると「ずっと」内の処理を一回実行するごとに 20ms のスリープが入ることになっているようで、実際に試してもそのようになっていました。なので「ずっと」をMicroPythonで実現するには次のようにすればよいわけです。

```python
@run_every(ms=20)
def 適当な関数名():
    何か処理
```

# run_every の引数

run_everyデコレータには以下の引数を指定できます。組み合わせて使うこともできます。

|引数名|説明|デフォルト|
|---|--|--|
|days|日単位で実行間隔を指定|0|
|h|時単位で実行間隔を指定|0|
|min|分単位で実行間隔を指定|0|
|s|秒単位で実行間隔を指定|0|
|ms|ミリ秒単位で実行間隔を指定|0|

ちなみに、なにも指定しないと実行間隔が0になり、バックグラウンドでCPU使いまくりで制御がメイン戻ってこず、何もできなくなります。対処方法としてはMicroPythonファームウェアを再インストールするしかなさそうです。
Power Automate Desktopで編集リクエストを自動化

# はじめに

先日「[QiitaAPIをつかっていろんな記事の誤字を探す](https://qiita.com/t13801206/items/c20547ff3c3d60400161)」記事を投稿した
（トレンドフィードを軸に過去記事を探索して、記事中に「をを」のような**明らかに誤字とわかる文字列があったらURLを拾ってくる**、という内容）

誤字をみつけたら、**次は編集リクエストを出さねばならない**

使命感を表現↓（ Windows のキーボード入力検索から出てきた。著作権大丈夫？）

![ElmoFireGIF.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/c8c49bcd-8212-92b1-695f-50806652e9fa.gif)

（Win11のキーボード入力にGIF検索窓が追加されてる）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/9093d7c3-dc1b-a976-dde2-4b56ce1d80c5.png)

いちいち**手作業でリクエストを出すのは面倒くさい**ので**ロボットにやらせたい**🤖

# WindowsユーザーならPower Automate Desktop

無料です😊

https://powerautomate.microsoft.com/ja-jp/desktop/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/c783b723-f6ee-7891-e538-2dc3cb9b36b2.png)

# 実際にやってみた

先の記事で誤字を含む記事を２つピックアップさせていただき、実際に編集リクエストを出してみる

## 先に結果から

実行している様子のGIFアニメ

![Animation4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/c36f0163-344f-5fbd-da47-8c10489dba39.gif)

事前準備として、`編集リクエストURL`と`編集内容の書かれたテキストファイルのパス`をCSVにしておく

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/f5b16881-0022-fd7c-349a-225cb1c52579.png)

## フローの説明

1. ブラウザを開いて編集ページにとぶ
1. 編集内容を張り付ける
1. 差分を確認してキー入力**（ここだけ人のキーボード操作が介入する）**
1. 誤字修正の文言を添えて送信
1. 以下、ループ

完全自動にすると、間違いがあったときにご迷惑をおかけするので
差分ページまで自動で進んだら、ざっと目を通して`Ctrl+Q`が押されるまでフローを止めるようにした

# 感想

Power Automate Desktop 重すぎ🤷‍♂️

# 後日談

無事にリクエストを承諾いただきました😛

https://qiita.com/takeC74/items/52f45d3f30d56e01df3e#comment-63d2552060c5df0920cb


# 関連リンク

- [タイポについてまとめられていておもしろい記事](https://qiita.com/khsk/items/085db0947c650e2db463)
- Twitterで[Power Automate Desktop についてつぶやかれているヒヨコの方](https://twitter.com/TaikiYoshidaJP)
Databricks Notesbooksのリネージュをデータカタログで可視化してみる

この記事は [インフォマティカ Advent Calendar 2021 Day 19 ](https://qiita.com/advent-calendar/2021/informatica)の記事として書かれています。

# はじめに

[前回はSnowflakeのリネージュ](https://qiita.com/masatoshimada-max/items/735f1742c5652f3c8984)について解説しましたが、今回は、最新のCould NativeなData Lake/Houseソリューションである、Databricksについて、メタデータやリネージュを可視化してみます。
[インフォマティカのデータカタログ(EDC)](https://blogs.informatica.com/jp/2017/02/15/edc-necessary/)では、DatabricksのメタデータおよびNotebooksのリネージュを取得する事ができます。

# Delta Lakeのメタデータ

Database, Schema, Tablesをはじめとするデータ・オブジェクトを取得することができます。
またDelta Table内のデータに関して、プロファイリングと呼ばれるデータ特性やパータン、サマリーデータを閲覧できる機能を使う事で、容易にどんなデータが格納されているかをデータカタログから直接、確認することが出来ます。
※クリックして拡大表示できます

|![databricks_metadata.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110338/abc81968-ad08-80be-9a0d-0b312d1a96c2.gif)
|:-:|

# Notebooksのリネージュ
Databricksでは、Notebooksと呼ばれる実行可能なセル (コマンド) の開発環境で、PythonやSQL等の言語を使ってデータセットを加工・編集、閲覧することができます。
下記のイメージの例では、Pythonで書かれたNotebooksにおいて、Delta fileからDelta Tableを生成しているセルをデータカタログによって可視化したものになります。データカタログからは関連するデータオブジェクト、およびNotebooksのソースコードを直接確認することが出来ます。
※クリックして拡大表示できます

|![databricks_notebooks.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110338/df444a19-f756-3e3f-14ed-3f9efc9a096d.gif)
|:-:|

<BR>

また下記の例では、Delta fileからDelta Tableを生成しているセルも含めたデータ処理全体を、リネージュとしてデータ流通経路の全体像を可視化することが出来ます。これによりデータがどこから発生し、どこに向かうのか、その途中でどのような処理が行われているかを、ソースコードの閲覧も含めてインタラクティブに確認することが出来るようになり、将来的なデータ利用の要件変更やAI/MLで利用データの説明・証明に活用することができます。
※クリックして拡大表示できます

|![databricks_lineage.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110338/f075e714-5c02-d734-7b30-c33e0fa6160e.gif)
|:-:|


# まとめ

インフォマティカのデータカタログである、Enterprise Data Catalog(EDC)では標準的なメタデータの取得に加えて、リネージュの取得・描画に関する機能を強化しており、今回のDatabricks NotebooksのようにPythonやSQLのコードを読み取り、複雑になりがちなデータの流通経路を正確に把握する事が可能となります。
これらの機能をデータ分析やデータ加工の高度化に向けてご活用下さい。
Windowsのファイル名で禁止されている記号を置換する

## 実行環境
- Eclipse IDE for Enterprise Java Developers
- OS: Windows 10
- Java version: 11.0.9

## コード
```Main.java
    public static void main(String[] args) {
        // Windowsでファイル名として禁止されている文字は\/:?"<>|
    	String src = "\\_/_:_*_?_\"_<_>_|.txt";
    	Pattern illegalFileNamePattern = Pattern.compile("\\\\|/|:|\\*|\\?|\"|<|>|\\|");
    	String fileName = illegalFileNamePattern.matcher(src).replaceAll("-");
    	System.out.println("src        :"+src);      // \_/_:_*_?_"_<_>_|.txt
    	System.out.println("fileName   :"+fileName); // -_-_-_-_-_-_-_-_-.txt
    }
```

## ポイント
```
Pattern illegalFileNamePattern = Pattern.compile("\\\\|/|:|\\*|\\?|\"|<|>|\\|");
```
`\\\\`
↑ダブルクオート内でバックスラッシュ(\\)を使いたい場合は\\\\
正規表現(括弧)内でバックスラッシュ(\\)をエスケープするためにバックスラッシュ(\\\\)が必要
結果バックスラッシュ4つになる
`\\*`
`\\?`
↑*と?はメタ文字なので、メタ文字として使われないようにエスケープする
`\"`
↑ダブルクオートはそのままだと、comple("の文字列の終わりを表すダブルクオートになるので、エスケープする
`\\|`
↑パイプ(|)はメタ文字のため、\*や?と同様にエスケープする

## 文字クラスを使った書き方
```
Pattern illegalFileNamePattern = Pattern.compile("[\\\\/:*?\"<>|]");
```
文字クラス([])内では、*?|はエスケープが不要(\は要エスケープ)
こちらのほうが、エスケープが少なくて見やすい気がします
壁紙サンプル

[充電10％刻みでiPhoneの壁紙を変更する方法](https://qiita.com/ais/items/60e2186589cb1afc35a6)


壁紙の画像サンプルです
下記の画像ファイルを同一フォルダに置いてください

![0.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403764/a2cadb62-aff9-a497-71fe-57182f8fd8d9.jpeg)
![10.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403764/5c02264f-9924-a567-c938-11eb62692d2c.jpeg)
![20.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403764/63de0fc1-0d8c-55e2-e128-3b8a9686d589.jpeg)
![30.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403764/f6fb1d03-1ca8-4c4d-1182-c04b9c3afdd3.jpeg)
![40.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403764/c913dfb6-e2e1-2926-0631-3687081d4791.jpeg)
![50.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403764/ba486172-793d-27ab-2b78-d3c935ae814e.jpeg)
![60.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403764/e1ba72ca-8ebe-e273-ee9c-324a408e001a.jpeg)
![70.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403764/2f67fe59-1d45-8f98-891d-d746d00d5dfa.jpeg)
![80.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403764/bff239ed-6101-97c9-f431-8617e9310f3b.jpeg)
![90.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403764/3dda2efa-2a8f-2f76-8d61-b422d3f436c0.jpeg)
![100.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403764/f26dc30c-2c23-b5c5-a22a-a4798c87883a.jpeg)
![wait.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403764/028bb901-9a83-a292-c01a-ad2cd6f9fd3c.jpeg)
ターミナル開いたら、".zshrc:5: command not found: rbenv"がいっぱい出てきた。 for mac(備忘録)

#1.事件の経緯

・1ヶ月以上前にDockerで遊んでいた。
・１週間前くらいに、不要(かなって独断で判断した)ファイルをFinderから適当に消した。
・４日前くらいに、homebrewをリセットした後に、node.js で色々ファイルを作って遊んでいた。

#2.事件の内容

ターミナルを開いたら

![スクリーンショット 2021-12-18 19.18.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388076/4211ff7e-3592-4b6c-9799-84e0fdba7059.png)



いっぱい流れてきて、恐怖で**[control] + [c]**で止めた。
そしたら止まったけど、また起動し直したら、ズラーって**".zshrc:5: command not found: rbenv"**
が出てきた後に

![スクリーンショット 2021-12-18 19.18.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388076/a8c67c2a-dc48-b230-acc5-5544d6593727.png)

ってなった。

####「何の、、、？」

と思わず声が出た。何も覚えてない。

#3.挑戦した解決方法

####(1)ターミナルを再起動し直す
####(2)PCを再起動する
####(3)Dockerで遊んだ時にインストールしたiTerm２をゴミ箱に入れる

#4.本当の解決方法

とりあえずGoogle先生に「.zshrc:5: command not found: rbenv」で検索、
複数のサイトを漁ったところ
####.zshrcというファイルがいけないんじゃないかっ

てことが判明。

.bashfileとかは何となく知ってるけど、.zshrcって何？ってなったけど
とりあえずもう怖かったので、↓この記事を参考にして

https://qiita.com/benzene/items/865506483377ad4128ee

####(1)ホームディレクトリから、.zshrc を開いてみる

```
[ターミナル]
＄　open .zshrc
```

####(2).zshrc ファイルにiTerm2のPATHとかrbenvのPATHとか書いてあったので、全部消す

![スクリーンショット 2021-12-18 19.40.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388076/d3547572-7326-d6b5-d427-367f709a6224.png)



####(3)ターミナルに戻り、.zshrcの内容を読み込み直す

```
[ターミナル]
$ source .zshrc
```


#5.最後に

####とりあえずなおったからまぁいいや。

多分原因はdockeで遊んだ時にRubyとか触った覚えもあって、
その後にhomebrewの中身をリセットしたことで

「PATH通したいんだけど、Rubyがないよ。」
みたいな感じのエラーだったと思われる。

.zshrc　についてはまた勉強しよ。
【Rails】ログイン、ログアウトって結局なに？

# 概要
Railsのログイン関連処理について、
Railsチュートリアルの第８章をもとに整理。

## 環境
ruby 3.0.2
rails 6.1.4

## ログイン関連の用語

### HTTP
- ステートレスなプロトコル
- ブラウザページを移動した時に、ユーザーのIDを保持しておく手段が無い

### session
- 半永続的な接続
- コンピュータ間（ブラウザとサーバの間）に設定する
- HTTPプロトコルより上の階層のため、HTTPの特性とは別に接続を確保できる
- sessionメソッド：ブラウザを閉じると自動的に終了する一時セッションを作成。

### cookies
- ユーザーのブラウザに保存される小さなテキストデータ
- ページ移動しても破棄されないので、ユーザーID等を保存可能
- アプリケーションは、このcookiesのデータを使用してDBから情報を取り出せる
- cookiesメソッド：ブラウザを閉じても終了しないセッションを作成。

## ログイン機能の実装

### RESTfulなセッション
セッションをRESTfulなリソースとしてモデリングすることで、他のUserやPostなどのリソースを実装するのと同じように扱うことが可能。

- newアクション：新しいセッション作成のためのページ（ログインページ）を表示
- createアクション：セッションを作成して保存（ログイン）
- destroyアクション：セッションを破棄（ログアウト）

### その他のリソースとの違い
#### Usersリソース
- Userモデルを介してDB上の永続的なデータにアクセスする

#### Sessionリソース
- cookiesを保存場所として使う

→Modelを持つリソースの場合は、**DBから**情報を取ってくる。それに対し、セッションはModelを持っていないため、DBの代わりに**cookiesから**情報を取ってくる。

### ログイン、ログアウトって結局なに？
ログイン：**ブラウザ内の一時cookiesにユーザーIDを作成すること**
ログアウト：**ブラウザ内の一時cookiesからユーザーIDを削除すること**

Railsのsessionメソッドでは、それぞれ下記の記述で実現可能。

```ruby
# 例）id=1のユーザー情報をuserに格納している場合
user = User.first
# ログイン
session[:user_id] = user.id
# ログアウト
session.delete(:user_id)
```

アプリケーションの各ページでは、`session[:user_id]`が入っているか否かに応じて、ログイン状態を判別する。

## 最後に
間違い等ありましたらご指摘いただけますと幸いです！
【Next.js】Hunter×Hunterの休載期間をリアルタイム表示するWebアプリ【Vercel】

# なにこれ
[こんなの](https://how-long-h-h-suspned.vercel.app/)
ソースコード : https://github.com/nishiurahiroki/how_long_H-H_suspned

# なぜ作った
Hunter×Hunterが好きすぎるから(全漫画で一番)
~~愛故のイジり~~

# なぜNext.js
とにかくNext.js触ってみたかった。

# 気付き
主にNext.jsに関して、

- 環境構築が生のReact.jsより(create-react-appを使わない)遥かに簡単
  - モジュールバンドラーの用意とかがほとんど必要無い
- Vercelへのデプロイ、CIの設定がとにかく楽

等


何気に初SSRフレームワークだったが、とにかく直感的に使えるフレームワークだと感じた。
これを期にNuxt等もぜひ触ってみたいと思った。


# こだわった所
・現在時刻に関して、端末時間ではなく、Rest APIを用いてサーバー側の正確な時間を`getServerSideProps`内で取得する様にした。

```jsx
import {fetchNow} from '../utils/DateUtils'

export default function Index({ now }) {
 // ~ 中略
}

export async function getServerSideProps() {
  const now = await fetchNow()

  return {
    props : { now }
  }
}
```

# その他
・アドベントカレンダー一度は参加したくて頑張った、けど結果私事で色々ありすぎて内容こんなスカスカに。。。来年もっと頑張ります
・冨樫先生、いつまでも待ってます
【入門】インターフェースデザインの心理学 〜知ると役に立つ5つのポイント〜


心理学の観点からユーザーの注意を惹きつけるUIを紹介します。

ただいまアプリケーションのフロント部分を作っていまして、デザインで悩んでいた時に本屋でタイムリーな本に出会ったのでその一部を参考文献と共に紹介いたします。

###0.対象
現在サービス開発などに携わっており、アクティブなユーザーを獲得したいと思っている人などにおすすめの内容ですので一読いただけたら嬉しいです。

https://www.amazon.co.jp/%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%95%E3%82%A7%E3%83%BC%E3%82%B9%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%81%AE%E5%BF%83%E7%90%86%E5%AD%A6-%E2%80%95%E3%82%A6%E3%82%A7%E3%83%96%E3%82%84%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AB%E6%96%B0%E3%81%9F%E3%81%AA%E8%A6%96%E7%82%B9%E3%82%92%E3%82%82%E3%81%9F%E3%82%89%E3%81%99100%E3%81%AE%E6%8C%87%E9%87%9D-Susan-Weinschenk/dp/4873115574


###1.文字の大きさは理解度を左右する。
文字についてもよく問題になるのが、読者がストレスなく文章を読める**文字の大きさ**にするべきとされていました。
以下の画像を見ると分かると思うのですが、文字が小さいほうは理解度どうこうという前に理解しようとなりませんよね

https://gyazo.com/f11d5839ca11490cd1b9a654c72ab150
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880777/55a9de8a-3cc7-6269-3ebd-ef65ec0f94e7.png)



###２.長い行を選ぶか短い行を選ぶか？

ユーザーに提供したい体験の種類によって推奨される行の長さが異なるを知り驚きました。
読む速さは、**行が長い時**（1行100文字程度）が**最も早く読むこと**ができるのですが、一般的には**短・中程度の行の長さ**がユーザーに**好まれる**みたいです。(Dyson,2004)

個人的にもセンター現代文のような分を見ると長い文を見ると嫌な気分になります（ただ苦手なだけ）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880777/0ab4b400-d5b4-7541-a0f5-7f0e2945c56d.png)




###3.白の背景に黒の文字が一番読みやすい。

コンピューターの画面上の文字と背景には**十分なコントラスト**をつけることが推奨されていました。
**白の背景に黒の文字**が読みやすいですが、**黒の背景に白の文字**だと読みやすくはならないことがわかっているみたいです。
これはプレゼンの授業でみんなの発表を見ている時に実感したときある方もいられるんじゃないでしょうか
### 4.青と赤の色を一緒に使わない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/880777/800acf1e-50c1-7443-bef0-c0d7c4ee2646.png)

赤と青を一緒につかうと目への刺激が強いため、ユーザーの目に疲労がかかり避けたほうがいいとされていました。
また赤と青以外にも、**赤と緑**も近くに一緒に使うのを避けるべきとしていました。

### 5.ユーザーに負荷のかからないサービスを作る

人は進化の過程で何かを忘れるようにデザインされており、一度に平均して４つしか覚えられません。

ユーザーの記憶に依存するようなサービス設計だと、ユーザーにストレスががかるため、以前に入力した文字などを再入力させないようにする仕組みやドロップダウンメニューなどでユーザーの記憶に負担の書けないような機能を追加することを推奨しておりました。

## 最後に
最後まで読んでくださりありがとうございました。
この本を読んで感じたことを簡略してまとめると、使ってもらうサービスのUIを作るには

・ユーザーの認知的負荷を減らすデザイン設計をすること
・人間のやる気に作用するような仕掛けをとりいれる
・最も見てほしい箇所を視覚に訴えるように強調する

ことがユーザーに使ってもらえるためのUIとして大事だみたいな事がこの本には書かれていました。

しかし、今回取り上げた内容はほんの一部分のでもっと踏み込んでデザイン心理学を学びたい方は一度この本を手にとってみることをおすすめします！


ここまで読んでくださりありがとうございました。


### 引用サイト

https://www.amazon.co.jp/%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%95%E3%82%A7%E3%83%BC%E3%82%B9%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%81%AE%E5%BF%83%E7%90%86%E5%AD%A6-%E2%80%95%E3%82%A6%E3%82%A7%E3%83%96%E3%82%84%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AB%E6%96%B0%E3%81%9F%E3%81%AA%E8%A6%96%E7%82%B9%E3%82%92%E3%82%82%E3%81%9F%E3%82%89%E3%81%99100%E3%81%AE%E6%8C%87%E9%87%9D-Susan-Weinschenk/dp/4873115574


https://hi-in.facebook.com/uxdaystokyo/posts/1890181017807626

https://www.tandfonline.com/doi/abs/10.1080/01449290410001715714
DBデータ型について（PostgreSQL編）

#はじめに

業務でDB設計について考える機会があったので、その時調べたことを備忘録としてまとめてみます！
（PostgreSQLがメインで、ちょこちょこMySQLとの比較も出てきます）

<strong>*「なんだかデータ型の名前は聞いたことあるけど、ちゃんと理解できてないなぁ…」*
っていう、私のような方向けのあくまで**`初心者レベル`**ですので

「ここ違うよ」「詳しくはこうだよ！」、などありましたら、
何でもアドバイスいただけると嬉しいです、、！


## 1. まずは整数たち
|データ型|容量|説明|
|:---:|:-----:|:---:|
|smallint|2B|狭範囲の整数。<br>→容量を抑えたい時に使用。|
|integer|4B|典型的に使用する整数。|
|bigint|8B|広範囲の整数。<br>→integerでは足りない場合に使用。|
DBでint(2)などと表示されていたけど、
まさかsmallintのことを指しているとは、、無知。


#### ▼ちなみにMySQLはこちら
上記に加えて、下記データ型もありました。細かい！
（「TINYINT」の名前は聞いたことありましたが、PostgreSQLには存在しないんですね。）

|データ型|容量|説明|
|:---:|:-----:|:---:|
|TINYINT|1B|smallintよりさらに狭範囲の整数。|
|MEDIUMINT|3B|smallintとintegerの間。|

## 2. 小数含む数字
|データ型|容量|説明|
|:---:|:-----:|:---:|
|numeric|可変長|ユーザー指定精度。<br>→正確な計算を行えるため、通貨金額など<br>正確性が求められる場合に使用。<br>ただし、浮動小数点データに比べて処理が遅くなる。|
|real|4B|浮動小数点データ型。|
|double precision|8B|浮動小数点データ型。|


#### ▼ちなみにMySQLはこちら
PostgreSQLの「real」「double precision」ではなく、
浮動小数点データ型は下記が定義されていました。

|データ型|容量|説明|
|:---:|:-----:|:---:|
|FLOAT|4B|浮動小数点データ型。|
|DOUBLE|8B|浮動小数点データ型。|


## 3. 日付（＋時刻）
|データ型|容量|説明|
|:---:|:-----:|:---:|
|timestamp with timezone|8B|絶対時刻（ローカル時間）<br>→基本的にはアプリで処理しやすいこちらを<br>使用することが多いそう。<br><b>通称timestampz|
|timestamp<br>(without timezone)|8B|概念時刻（グリニッジ時間）|

#### ▼ちなみにMySQLはこちら
|データ型|容量|説明|
|:---:|:-----:|:---:|
|datetime|8B|サポート範囲は'1000-01-01 00:00:00' から <br> '9999-12-31 23:59:59'  **※月や日付に00を許容する**|
|timestamp|8B|サポート範囲は'1970-01-01 00:00:01' UTC から <br> '2038-01-19 03:14:07' UTC|



## 4. 文字
|データ型|容量|説明|
|:---:|:-----:|:---:|
|char(n)|1GB|空白で埋められた固定長。<br>n文字の固定長文字列型。<br>余白はスペースで埋められる|
|varchar(n)|1GB|上限付き可変長。n文字の可変長文字。<br>文字数を指定できるからデータ量の見積もり（節約）が可能|
|text|1GB|制限なし可変長。長さ制限がない文字列。|

#### ▼ちなみにMySQLはこちら
MySQLでは上記と同名のデータ型でも容量が異なり、
かつ、PostgreSQLにはない「TINYTEXT」「MEDIUMTEXT」「LONGTEXT」という型もあるみたいです、、！



## ＜参考＞
**・PostgreSQL 9.3.2文書**
https://www.postgresql.jp/document/9.3/html/index.html

**・MySQL**
https://dev.mysql.com/

**・MySQLとPostgresのデータ型対応表**
https://qiita.com/suin/items/85b1e3eebb99777b171d

**・timestamp with time zone型はタイムゾーン情報を持っていない**
https://qiita.com/yuba/items/7852a29d63d6279c6f6e

**・MySQLのDATETIME型とTIMESTAMP型の違いを検証してみた**
https://qiita.com/ykawakami/items/2449a24e3b82ff0cbab6

**・MySQLの数値型（int、tinyint、bigint、decimal、number、float）の解説**
https://blog.s-giken.net/367.html


# 最後に
ここで取り上げたデータ型はほんの一部なので、
気になる方はぜひ調べてみてもらえればと思います！

拙い文章を最後までお読みいただき、ありがとうございました！！
VRChatプレイヤーによるParticle System解説 ～Limit Velocity over Lifetime / Inherit Velocity Module編～

:::note warn
この記事はUnity 2019.4.29f1の記事です
:::
[Limit Velocity over Lifetime / Inherit Velocity Module編](https://qiita.com/abcde_kind/items/22d8d266302b08b852e1) <<  ここ  >> [Force over Lifetime, Color/Size/Rotation over Lifetime, by Speed Module編](https://qiita.com/abcde_kind/items/96710d4e401ca88abbb5)
# はじめに
この記事は**ちょっとParticle System触れるようになったけどまだまだ知らないパラメーターだらけで抵抗感がある人向け**にじゃあ全項目解説しようという記事です。

**パーティクル？シェーダー？憧れるけどよくわかんない…**という人は最近は[VRCUnity勉強会][link-1]などで初歩の初歩から解説してくれる講座などが解説されているのでそこに参加してみたりするといいでしょう。
[link-1]:https://discord.gg/mtvTTyM
その他にこの記事はアドベントカレンダーにしてParticle Systemの記事を増やしてパーティクルへの抵抗感を減らしてやろうという企みもあります。

##Limit Velocity over Lifetime / Inherit Velocity Moduleってどこ？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2386883/c87f7191-bad4-300d-c84b-b2b357ba925c.png)
この2つ
##Limit Velocity over Lifetime
###Separate Axes
デフォルト OFF
**下のSpeedをXYZに分けて制御するかどうか決めるパラメーター**
ONにするとSpeedがXYZに分かれるのとSpaceの項目が出てくる
###Speed
デフォルト 1 (0~3.402823e+38)
単位 m/s
**このスピードを超えたパーティクルはスピードが制限される**
このModuleの要
<font color=red>以降の説明ではここが0の前提で説明する</font>
####Space
**XYZ軸の基準をこのオブジェクトにするかワールドにするか決めるパラメーター**
Separate AxesをOFFにしてると出てこない
####Dampen
デフォルト 0 (0~1)
**スピードの減衰のかかり方の強さを決めるパラメーター**
Speedを0にした例だとこんな感じに速度が変わる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2386883/4292bd3f-963d-73ca-3dcf-a7ad84ff7196.png)
思ったより強くかかるから0.0いくつとかにすることもよくある
####Drag
デフォルト 0 (0~100,000)
**パーティクルの速度や大きさに比例して減衰のかかり方を調整するパラメーター**
と書いたがそれは下のMultiply by Size / VelocityをONにした時の話
じゃあこれは何なのかというとDampenと似たような性質を持ったパラメーターでこのパラメーターが大きくなればなるほど減衰のかかりかたが大きくなる
結構ゆるいかかりかたで数値を大きくして速度が遅くなっても限りなく0に近づくだけ(っぽい)
正直ふんわりしかわかんない
#####Multiply by Size
デフォルト ON
**Dragをパーティクルのサイズが大きくなるほど強くかかるようにするパラメーター**
大きくなるほど減衰が強くなるということは物理的に正しいとも言えるので花火とかのパーティクルに使うとそれっぽいんじゃないでしょうか
#####Multiply by Velocity
デフォルト ON
**Dragをパーティクルの速度が大きくなるほど強くかかるようにするパラメーター**
速くなるほど減衰が強くなるということは物理的に正しいとも言えるので花火とかのパーティクルに使うとそ
##Inherit Velocity
このParticle Systemが入ってるオブジェクト(エミッターとか呼ぶ)が動いた時に出ているパーティクルがその動きをどのような反映をするか決めるModule
###Mode
デフォルト Initial
**どの瞬間のエミッターの動きを適用させるか決めるパラメーター**
Initialの場合は各々のパーティクルが<font color=red>発生した瞬間のエミッターの動き</font>に影響されてそれ以降のエミッターの動きを無視する
Currentの場合はエミッターの動きに<font color=red>常に影響される</font>
###Multiplier
デフォルト 0 (-100,000~100,000)
単位 倍
**エミッターの動きの影響度を決めるパラメーター**
例えばエミッターが1m/sで移動してる時にこのパラメーターが2だとパーティクルに同じ方向に2m/sの速度が加算される
マイナスにして手とかにパーティクルを仕込むと動きが面白い
#おわり
というわけでLimit Velocity over Lifetime / Inherit Velocity Moduleの解説でした
個人的にうまく扱うと玄人っぽい不思議なパーティクルが作れるとこだと思ってます
次はForce over Lifetime, Color over Lifetime, Color over Speed Moduleの解説です
****
[Limit Velocity over Lifetime / Inherit Velocity Module編](https://qiita.com/abcde_kind/items/22d8d266302b08b852e1) <<  ここ  >> [Force over Lifetime, Color/Size/Rotation over Lifetime, by Speed Module編](https://qiita.com/abcde_kind/items/96710d4e401ca88abbb5)
jenkins swarm clientの自動起動・停止

# １．起動用シェルファイルを作成
/home/ec2-user/swarmd.sh

```
#!/bin/bash
cd /home/ec2-user
java -jar /home/ec2-user/swarm-client-3.29.jar -executors 2 -disableSslVerification  -master http://172.31.34.77:8080 -name swarm-node -username admin -password xxxxxx -mode exclusive &
```

# 2．unitファイルを作成
/etc/systemd/system/swarmd.service

```
[Unit]
Description=swarm connection daemon
After=network.target

[Service]
SuccessExitStatus=143
Type=forking
User=ec2-user
Group=ec2-user
ExecStart=/home/ec2-user/swarmd.sh
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s

[Install]
WantedBy=multi-user.target
```

# ３．サービスをenable・start

```
sudo systemctl daemon-reload
sudo systemctl enable swarmd
sudo systemctl start swarmd
```
iPhone充電％壁紙の作り方

[充電10％刻みでiPhoneの壁紙を変更する方法](https://qiita.com/ais/items/60e2186589cb1afc35a6)


壁紙の画像ファイルの作り方です
下記の画像ファイルをiPhone内の同一フォルダに置いてください

必要な画像ファイルは12枚
0.jpeg ←充電残量0から9％、新月
10.jpeg
20.jpeg
30.jpeg
40.jpeg
50.jpeg
60.jpeg
70.jpeg
80.jpeg
90.jpeg ←90から99％
100.jpeg ←100％、満月
充電時のファイル(見本ではwait.jpeg)

※用意した画像が少ない場合でも
画像ファイルを複製して12枚にして下さい
例)
〜20％　赤
〜40％　黄
〜90％　緑
100％、充電中　青


充電時のファイル以外は、基本的に
ファイル名が上記と同一の必要があります
ただし拡張子は同一であればjpgでもJPEGでも構いません(ショートカットの設定で変更可能です)


画像サイズが多少違ってもiPhone先生が何とかします

一方で、画面サイズと同一ピクセル数の画像を用意しても、壁紙にすると四辺がはみ出す事があります

これは「視差効果」という壁紙を立体的に見せかける機能が有効な場合に起きる現象です
[効果をオフ]()にもできます

壁紙を用意できたら、うまく壁紙が設定できるか試運転します

**

壁紙設定の試運転のやり方

②新規ショートカット
　❶バッテリー残量を取得
ここでテストしたい％を設定できるように[数字を追加]()する
　❷計算で、残量の1桁目を切り捨て
バッテリー残量ではなく数字を指定
　❸リストで壁紙のファイル名を作る
　❹ファイルを呼び出す
　❺壁紙を設定

右下の▶︎ボタンを押すと、指定した％の壁紙に変わります
![8D53E1FB-361C-4219-A199-EA986C69546B.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2403764/70aa3d1c-24e1-c039-1daa-ef154c9eca44.jpeg)


**

壁紙画像データ
[見本（月）](https://qiita.com/ais/items/0704130c62fcf835c50f)
jenkins jnlp agentの自動起動・停止



# １．起動用シェルファイルを作成
/home/ec2-user/jnlpd.sh

```
#!/bin/bash
cd /home/ec2-user
java -jar agent.jar -jnlpUrl http://172.31.34.77:8080/computer/jnlp/jenkins-agent.jnlp -secret xxxxyyyyzzz -workDir "/home/ec2-user" &
```

# 2．unitファイルを作成
/etc/systemd/system/jnlpd.service

```
[Unit]
Description=jnlp connection daemon
After=network.target

[Service]
SuccessExitStatus=143
Type=forking
User=ec2-user
Group=ec2-user
ExecStart=/home/ec2-user/jnlpd.sh
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s

[Install]
WantedBy=multi-user.target
```

# ３．サービスをenable・start

```
sudo systemctl daemon-reload
sudo systemctl enable jnlpd
sudo systemctl start jnlpd
```
AWS SESについてまとめておく

AWS検定の勉強をしていてわからなかったところを自分なりにまとめておく。

## AWS SES (Simple Email Service)
Amazon Simple Email Service 略して SES。
よくAWS検定の問題ではAWS SESとして表現される。
このSESは名前の通りで、アプリケーションでEメールを配信することができるサービスになる。

## 勘違いされる点
このSESはアプリケーションを利用しているユーザーへ向けてのEメールを配信するために使用される。

よく、AWSの管理者に通知やお知らせを配信するには？というニュアンスの問題で選択肢としてAWS SESが表示されているが、
管理者に何か通知をするためにはAWS SNSというサービスを使用する必要がある。

SESはあくまで``ユーザー向けのメール配信サービス``ということは覚えておきたい。
SATySFiでQuine

# SATySFiで[Quine](https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AF%E3%82%A4%E3%83%B3_(%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0))

やってるのを見かけなかったので．output，pdfともにquineになってるはずです．
↓のリンクを開いてpdfのコードをコピーするか，Chromeやお使いのOSに入っているpdf viewerで開いてコピーしてお手元のsatysfiコンパイラかplaygroundに食わせると同じ文字列が出力されるはずです．
[permlink](https://www.satysfi-playground.tech/share/bf8af907fafbf0dd440f09632552cf792cf46f273994114847623c7eb96a6a2f)

```
let code = `let code = $@$ let (ss,sl,su) = (string-sub,string-length,string-unexplode) let-rec s2cl s = if sl s == 0 then [] else ss s 0 1 :: s2cl (ss s 1 (sl s - 1)) let q s = let-rec qa cl = match cl with | [] -> su [] | c :: l -> let f d = string-same c (su [d]) in (if f 64 then s else if f 36 then su [96] else c) ^ qa l in let s = qa (s2cl s) in let () = display-message s in s let-inline \d _ = {} let gic l = get-initial-context l (command \d) let qb = (read-inline (gic 4pt) (embed-string (q code))) let (w, h, d) = get-natural-metrics qb let (w, h) = (w +' 12pt, h +' d +' 12pt) in page-break (UserDefinedPaper(w +' 12pt, h)) (fun _ -> (|text-origin = (6pt, 6pt); text-height = h;|)) (fun _ -> (|header-origin = (0pt, 0pt); header-content = block-nil; footer-origin = (0pt, 0pt); footer-content = block-nil;|)) (line-break true true (gic w) qb)` let (ss,sl,su) = (string-sub,string-length,string-unexplode) let-rec s2cl s = if sl s == 0 then [] else ss s 0 1 :: s2cl (ss s 1 (sl s - 1)) let q s = let-rec qa cl = match cl with | [] -> su [] | c :: l -> let f d = string-same c (su [d]) in (if f 64 then s else if f 36 then su [96] else c) ^ qa l in let s = qa (s2cl s) in let () = display-message s in s let-inline \d _ = {} let gic l = get-initial-context l (command \d) let qb = (read-inline (gic 4pt) (embed-string (q code))) let (w, h, d) = get-natural-metrics qb let (w, h) = (w +' 12pt, h +' d +' 12pt) in page-break (UserDefinedPaper(w +' 12pt, h)) (fun _ -> (|text-origin = (6pt, 6pt); text-height = h;|)) (fun _ -> (|header-origin = (0pt, 0pt); header-content = block-nil; footer-origin = (0pt, 0pt); footer-content = block-nil;|)) (line-break true true (gic w) qb)
```
【docker-compose】 railsで　Unknown MySQL server host 'db' (-2)が出た時の対処法

# 概要

ついさっきまで動いていたはずのmysqlコンテナが動かなくなりました。
`docker-compose logs`を実行すると以下のようになってました。

![スクリーンショット 2021-12-18 17.52.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461885/bfbc165c-5624-9fe2-97e6-525dc3ff075d.png)

# 試したこと①

なんとなく下記のエラーが怪しいのでは？と思い`ib_logfile`を削除してみましたがダメでした。

```
db_1     | 2021-12-18T08:42:07.483929Z 0 [ERROR] InnoDB: redo log file './ib_logfile1' exists. Creating system tablespace with existing redo log files is not recommended. Please delete all redo log files before creating new system tablespace.
```

**実行の手順**

```
$ docker-compose run db bash
```

```
$ cd /var/lib/mysql
```

```
$ rm ib_logfile0
```

ここで`ib_logfile1`も削除していればうまくいったかもしれません。



# 試したこと②

すでに存在するmysqlのコンテナや、イメージが多すぎてエラーが起こっているのではと考えました。

よって存在するコンテナを全て削除

```
docker rm `docker ps -a -q`
```

mysqlのイメージを削除

```
docker rmi <mysqlのイメージ>
```
そして再度build

```
docker-compose build
```

```
docker-compose up -d
```
しかしうまくいきません。

# 解決した方法

`docker-compose.yml`の`db`の`./db-data:/var/lib/mysql`に着目しました。

もう、`db-data`を一度最初から作るしかないと考えました。

自分のパソコン側の`db-data`というファイルの名前を`db-data.sub`にしました。

それによって`docker-compose up -d`で新たな`db-data`が作られました。

そして下記コマンドで元通りにできました。

```
docker-compose up -d

docker-compose run api rails db:create

docker-compose run api rails db:migrate

docker-compose run api rails db:seed
```

おそらく①で`ib_logfile1` `ib_logfile0`を消す方法が最も簡単だったかもしれません。

本番環境では使えないやり方だと思うので、本番環境で行うときは慎重になりたいですね、、、
固定翼機の離発着場所の選定について2021

Drone Birdでは、固定翼機を主力として災害地の写真撮影を行ってまいりました。
本年度はAEROBO Wing(エアロセンス社)を導入し、固定翼機の課題としていた、離発着を回転翼機とのハイブリット飛行ができる機体として、より現場の状況に則したフライトが可能となる環境を整えています。

その中でも、まだ主力にしている固定翼機の離発着において、各所で訓練をする中での課題や注意点についてまとめていきたいと思います。

#離着陸方法について
離陸角度については前回の記事で書きましたのでそちらを参照してください。
https://qiita.com/zeee_plus/items/543992308f0e7ee0074b

着陸方法には２つあります。
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322439/6302c2c1-142b-91b2-c07a-4018f19704cd.png)
### Linear Landing
Parrot DISCOやSensefly eBeeXなどの固定翼機は胴体着陸を行うため、その衝撃を最小限にしなければ、搭載しているカメラの故障につながりかねない。また、埃などがカメラのレンズに傷をつけかねない為、eBeeXはカメラが着陸時に上に向けるものの、万全でありません。
Linear Landingでは、着陸の地上と着陸の角度がつかないように、機体には優しい方法で衝撃を少なくするという方法です。

### Steep Landing
Linear Landingは衝撃の対策には有効な着陸ですが、着陸に必要な距離が長いことが求められます。
現場によっては、十分な距離を保つことが困難な場所もあります。そうした場合、着陸する角度をつけて行うことになります。
通常では選択しませんが、現地の下見することで計画を立てておくことですが、風向きによって、着陸する方角の変更を求められた時に選択せざるを得ないことも想定しておかなければなりません。

#場所の選定
固定翼機の離陸及び着陸場所は同一の場所でならないわけではなく、近傍の離陸する経路に対する障害になる構造物が安全な範囲において損するか否かということが基本的に考えなければならないということになります。
次に、待機するために描く円に障害物がない高さであったり、鳥などの攻撃をうけることのない高さかつ、ミッションの遂行でスムーズにできる位置での待機できる場所を考えた上で、離陸場所と待機場所を直線で結んだ経路に障害物がないかということになります。

当時の風が吹く方向によっては一旦、離陸したのちに、機体の鼻先が下降気味になる場合があり、２，３ｍまで降下して上昇することもあることから、そうした場合でも待機場所に行くための経路について余裕を見ておかなければなりません。

着陸に関しては、前述のように計画段階で機体に衝撃が少ないLinear Landingで計画することになりますが、撮影する範囲に近い場所を選び、飛行する総距離を短くすることは、さまざまなリスクに対する軽減にもつながる為、そのようにすることが望ましいです。場合によっては離着陸が安定的にできる場所あ確保されているのであれば、航路の沿線に監視員を置いて、撮影範囲から多少遠くなっても、選択肢として設定することも有効な方法になることもあります。

eBeeXは90分の飛行ができることから、連続で飛行できるメリットがあり、撮影する箇所が連続している場合は、バッテリーが予定の％を下回った場合に着陸させて、再度離陸することを繰り返しますが。離着陸の回数が少ないほうが良いように、StandardバッテリーかLong Distanceなのかを使い分けて、効率よくミッションを遂行する必要があります。
UE4とFlaskでAPI通信を利用した簡単なチャットボットデモの実装

#はじめに

初投稿です。今回UnrealEngine4の「**Varest**」を使用してブループリントから,postしてAPIサーバーから通信出来る様にしました。API通信はPythonのFlaskというwebアプリケーションを使用しております。サーバーからの応答は**AIML**という名前にしています。

![スクリーンショット (815).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2401903/1ffadd1c-d892-88dd-3485-e40f581b32b6.png)

##記法
以下では各名称を以下の様に略します。
UnrealEngine4➞UE4
ブループリント➞BP

##内容
API(Application Programming Interface)
ソフトウェア等をつなぐためのインターフェース
今回はUE4とFlaskを繋いでいます。

ルールベースxmlファイルで作成したものをflaskをつかって応答し,UE側からPOST通信します。またPython側で自然言語処理や機械学習のフレームワークを活用し,その結果をUE4に送信することもできます。(今後やっていきたい)

##環境

今回は以下のverで使用しております。
UE4　4.25
Python 3.7

##準備
マーケットプレイスから**Varest**をインストールします。
![スクリーンショット (813).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2401903/fbdb3d62-a170-86e2-85b1-274ba6650003.png)

またローカルのPython環境でflaskをインストールしていない方はpipしておきます。

```
$ pip install Flask
```

##BP(レベル)
以下の様に組みます

![スクリーンショット (817).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2401903/73e9e46c-ff99-ce12-fe3e-424e5ef8c851.png)

部分的にピックアップしていきます。
![スクリーンショット (834).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2401903/a3c2a8dd-303c-8b6f-d940-eb07bea42ec5.png)

![スクリーンショット (835).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2401903/e132d064-025a-0892-9248-626e4f2da4c8.png)


![スクリーンショット (836).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2401903/f71b5922-914a-22c9-93b1-01099d0aa1bd.png)




###変数
以下を(string)用意します。URLはhttp://127.0.0.1:5000/
等、ローカルで立上げるためのURLをデフォルトにしておく。またtextは簡潔に送るためのメッセージです。後ほどのxmlを参照して適宜変えてください。(今回は**こんばんは**にしています)

![スクリーンショット (819).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2401903/37eb877a-a2ea-b0b2-a6f6-550b9f129bee.png)


##flask
flask部分です。

```py:aiml.py
from flask import Flask, request, jsonify
import aiml
import time


kernel = aiml.Kernel()
kernel.learn("aiml.xml")
app = Flask(__name__)


#デフォルト
@app.route("/")
def hello():
    #return jsonify({"message":"AIML"})
    return "AIMLです。"

#レスポンス
@app.route("/post", methods=['POST'])
def post():
    text = request.form['text']
    print(text)
    response = kernel.respond(text)#xmlファイルの取得
    print(response)
    return jsonify({"message":response})

#ここは任意の番号
app.run(host="127.0.0.1", port=5300)
```
xmlファイルも下記に示します。
ルールベースになるので,汎用性があまりないです。今回は3番目の応答になります。

```xml:aiml.xml
<aiml version="1.0.1" encoding="UTF-8">

<category>
 <pattern>こんにちは</pattern>
 <template>ユーザさん，こんにちは,調子はどうですか。</template>
</category>
<category>
 <pattern>おはよう</pattern>
 <template>おはようございます。いい天気ですね</template>
</category>
<category>
 <pattern>こんばんは</pattern>
 <template>ユーザさん，こんばんは,夕飯は食べましたか。</template>
</category>

</aiml>
```

また,pyファイルとxmlは同ディレクトリ内に置いておいてください。

##最後に
pyファイルを実行後,UE4を起動し,jを押すと反応してくれます。get部分は何人かweb上にあげていた方はいたのですが,post部分はいなかったので(多分…)あげました。参考程度に
[初心者向け]ターミナルを使わずにHTMLを作る方法 for mac (備忘録)

[環境]MacBook
[概要]
・htmlでwebサイトを作ってみたいけど、どうやってファイルを作成すればいいか分からない人向け
・ターミナルコマンドがわからない人向け
・MacBook使い慣れてない人向け


--------------------

#1[テキストエディット]の設定をする

![txt-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388076/f9e934a7-1fad-742e-e40c-eef96c9bd73c.png)


・MacBook内で**[テキストエディット]**を探す

![スクリーンショット 2021-12-18 17.32.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388076/3778cac6-3ce4-ddb9-fcfc-69451166696f.png)


.**[環境設定]**を選択する

![スクリーンショット 2021-12-18 17.32.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388076/5525bbb3-3fcf-c478-6635-d1a61ab85936.png)

・**[標準テキスト]**に変更


![スクリーンショット 2021-12-18 17.36.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388076/6454c2fd-44c2-25f3-ec2f-15c3acd4d47b.png)


・**[HTMLファイルを、フォーマットしたテキストではなくHTMLコードとして表示]**を選択
・**[標準テキストファイルに拡張子.txtを追加]**のチェックを外す
・**[unicode(UTF-8)]**にチェックを入れる


#2HTMLファイルを作る

![スクリーンショット 2021-12-18 17.43.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388076/ba6f7012-2599-fd6b-456d-2b66236f8248.png)


![スクリーンショット 2021-12-18 17.42.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388076/b6d0eb71-f807-4088-8e0f-686691186399.png)


**[テキストエディット]**を開いて、**[新規書類]**を選択


![スクリーンショット 2021-12-18 17.44.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388076/33f3a548-d646-2836-f21d-503501db08d3.png)

[テキストエディット]の**[保存]**を選択

![スクリーンショット 2021-12-18 17.45.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388076/a36a9c4a-895d-de88-76a7-90f6b11b20b9.png)

:::note info
保存するときの拡張子名前を[.html]にする
:::

[保存]をする

![スクリーンショット 2021-12-18 17.47.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2388076/7f4b58f7-3a20-293c-16e9-741f0bd7dbbd.png)


####HTMLファイルの完成