OmniAICreator/Qiita-1.07M huggingface dataset:
Deno KVで短縮URL【Deno URL Shortener】

<p class="codepen" data-height="456" data-default-tab="result" data-slug-hash="LYgzdxp" data-user="04" style="height: 456px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/04/pen/LYgzdxp">
  Untitled</a> by John Doe (<a href="https://codepen.io/04">@04</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

```typescript
import { serve } from "https://deno.land/std@0.177.0/http/server.ts";

const kv = await Deno.openKv()

serve(async (req: Request) => {
    const id = new URL(req.url).pathname.slice(1)
    if (req.method === 'GET') {
        const { value } = await kv.get([id])
        return value ? Response.redirect(value) : new Response('404 Not Found', { status: 404 })
    } else if (req.method === 'POST') {
        await kv.set([id], await req.text())
        return new Response('201 Created', { status: 201 })
    }
})
```

URLの更新手順

```bash
curl https://sht.deno.dev/abc -d https://deno.com/blog/kv
```




管理画面で確認できます


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/f274d42a-0047-1b65-cbf5-2af6acb23553.png)
【React】下にフリックして閉じられるモーダルコンポーネントを作ってみた

その昔 Vue.js 製の SwipeableDrawer という物を作りました。↓
https://qiita.com/dsflon/items/11a7cf780b3b42d10016

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390283/86b070ab-83cd-a303-356b-8217280ac716.gif" width="250">

これは、とあるレストラン予約サービスのUIに採用され、ちょっとだけ評価されました。
https://restaurant.ikyu.com/101099/plan11927887
（:iphone: で見てね）

## これの React 版を作ったというお話です
案件でこのUIを利用する可能性があり、重い腰を上げて現代版に作り直しました。

### デモ
https://dsflon.github.io/SwipeableDrawer.React/
（:iphone: で見てね）

### github
https://github.com/dsflon/SwipeableDrawer.React

## 使い方
こちら↓に本体があるので、
https://github.com/dsflon/SwipeableDrawer.React/tree/main/src/components/SwipeableDrawer
適当なところに配置して、下記のようにimportして使います。

```tsx
import { useState } from 'react';

import { SwipeableDrawer } from '~/components/SwipeableDrawer';

export default function Home() {
  const [opened, setOpened] = useState(false);

  const beforeEnter = () => {
    console.log('beforeEnter');
  };

  const afterEnter = () => {
    console.log('afterEnter');
  };

  const beforeLeave = () => {
    console.log('beforeLeave');
  };

  const afterLeave = () => {
    console.log('afterLeave');
  };

  const scrollDrawer = () => {
    console.log('scrollDrawer');
  };

  return (
    <>
      <button
        onClick={() => setOpened(true)}
      />

      <SwipeableDrawer
        opened={opened}
        speed={300}
        easingType = 'easeOutCubic'
        onClose={() => setOpened(false)}
        onBeforeEnter={() => beforeEnter()}
        onAfterEnter={() => afterEnter()}
        onBeforeLeave={() => beforeLeave()}
        onAfterLeave={() => afterLeave()}
        onScroll={() => scrollDrawer()}
      >
        <div>
          contents
        </div>
      </SwipeableDrawer>
    </>
  );
}
```

あとは煮るなり焼くなり、よければ、どうぞ。

## 余談
- モーダル裏をスクロールさせない方法っていまやjs不要なんですね、助かる
  https://myb63.com/blog/css-modal-scrollnone
- 現在最新と思われるiOS16.4.1、android13 でしか検証していません :bow:
RichTextエディター

# CKEditor / 商用利用については有償
CKEditor4
https://ckeditor.com/docs/ckeditor4/latest/features/index.html

CKEditor5
https://ckeditor.com/docs/ckeditor5/latest/installation/index.html

改行コードと先頭のPタグと末尾のPタグを除外
```CKEditor4版.php
RichTextEditor.prototype.getValue = function () {
  var val = CKEDITOR.instances[this.TEXTAREA.id].getData();
  val = val.replace(/\r?\n/g,"");
        val = val.replace(/^<P>/i, "");
        val = val.replace(/<\/P>$/i, "");
  return val;
};
```
```CKEditor5版.php
RichTextEditor.prototype.getValue = function () {
  var val = myEditor.getData();
  val = val.replace(/\r?\n/g,"");
        val = val.replace(/&nbsp;/ig, "");
        val = val.replace(/<P>/ig, "");
        val = val.replace(/<\/P>/ig, "");
  return val;
};
```

# Quill

https://quilljs.com/

```php
<!-- Include stylesheet -->
<link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">

<!-- Create the editor container -->
<div id="editor">
  <p>Hello World!</p>
  <p>Some initial <strong>bold</strong> text</p>
  <p><br></p>
</div>

<!-- Include the Quill library -->
<script src="https://cdn.quilljs.com/1.3.6/quill.js"></script>

<!-- Initialize Quill editor -->
<script>
  var quill = new Quill('#editor', {
    theme: 'snow'
  });
</script>
```

# Summernote / 商用利用でも無償 ライセンス
jQuery ベースで作成されている。
https://summernote.org/

Bootstrap5ではうまくいかないようようです。
Bootstrap4まで利用する必要があるようです。
```php
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Summernote</title>
  <link href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
  <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
  <link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.css" rel="stylesheet">
  <script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.js"></script>
 {{--  日本語化化 --}}
<script src="https://cdn.jsdelivr.net/npm/summernote@0.8.20/src/lang/summernote-ja-JP.js"></script>　
</head>
<body>
  <div id="summernote"><p>Hello Summernote</p></div>
  <script>
    $(document).ready(function() {
        $('#summernote').summernote();
           lang: 'ja-JP' // 日本語化
    });
  </script>
</body>
</html>
```

# その他 参考できるサイト
https://begien.com/article/62/view

https://qiita.com/mima_ita/items/bacf3ca3c078d1e6c70f
Apacheでのアクセスログの確認

<p>自作サーバを作ったのとアクセスやセキュリティについて確認したかったのでメモ</p>
<h1>環境</h1>
<p>OS:CentOS</p>
<p>WEBサーバソフト:Apache</p>

<h1>アクセスログの確認</h1>
<p>コマンドを残しておきます</p>
<p>まず、ディレクトリに移動</p>
<p>$ cd  /var/log/httpd</p>
<p>$ ll</p>
<p>httpなら</p>
<p>$ tail -f access.log</p>
<p>httpsなら</p>
<p>$ tail -f ssl_access.log</p>

<h1>SSH アクセスログの確認</h1>
<p>$ last</p>
<pこれだけでわかります。></p>

<p>かんたんでやさしい。SSHとかはセキュリティ強化しなきゃね。</p>
自分の3Dプリンタ関連記事まとめ

記事が多くなってきてリンクの管理が面倒になってきたのでインデックスページを作りました。

# Marlin時代
- [基本設定](https://qiita.com/tanutanup/items/6b5e6f480f2a2d1a1f2c)
- [BLTouch](https://qiita.com/tanutanup/items/b3d6d973e286503a8620)

# Klipper時代
## 本運用
- [基本設定編](https://qiita.com/tanutanup/items/cbb0d0cabd8d976f0e38)
- [BLTouch編](https://qiita.com/tanutanup/items/1da1edd8185b12224e9c)
- [フィラメントセンサ編](https://qiita.com/tanutanup/items/46b141d64c47779d34fa)
- [ディスプレイ編](https://qiita.com/tanutanup/items/10eeb5d4b38bc625ea3b)
- [続・ディスプレイ編](https://qiita.com/tanutanup/items/976238f440bc52fb1d08)

## 色々なテスト・トライ
- [マクロ前編](https://qiita.com/tanutanup/items/05f9cb7b1600e6a7f985)
- [マクロ後編](https://qiita.com/tanutanup/items/433b3701a39a6fe7d37b)

# 創意くふう関係
- [カイゼン of 3Dプリンタ](https://qiita.com/tanutanup/items/f06ef4b516fb2708dded)
【Python】箇条書きを表形式に変換する【ありがとうChatGPT】

# できること（入力例と出力例）
* 箇条書きのテキストを表形式に変換する
    * 今回の例だと、1列の箇条書きを4列の表に変換
```text:入力例
テキスト1行目
テキスト2行目
テキスト3行目
テキスト4行目
テキスト5行目
テキスト6行目
テキスト7行目
テキスト8行目
テキスト9行目
テキスト10行目
テキスト11行目
テキスト12行目
```

```text:出力例
テキスト1行目|テキスト2行目|テキスト3行目|テキスト4行目
テキスト5行目|テキスト6行目|テキスト7行目|テキスト8行目
テキスト9行目|テキスト10行目|テキスト11行目|テキスト12行目
```

# やり方（Pythonコード）
```python:1列の箇条書きを4列の表に変換
# テキストを1行ずつ読み込む
with open('input.txt', 'r') as f:
    lines = f.readlines()

# バッファにためる行数を設定する
n = 4

# バッファの初期化
buffer = []

# テキストを4行ごとに区切ってパイプ記号で区切られた1行のテキストに変換する
for i, line in enumerate(lines):
    # バッファにテキストをためる
    buffer.append(line.strip())
    # バッファにためたテキストがn行になった場合には、パイプ記号で区切って1行のテキストに変換して出力する
    if len(buffer) == n:
        print('|'.join(buffer))
        # バッファを空にする
        buffer = []

# テキストの行数が4で割り切れない場合には、最後にためたバッファをパイプ記号で区切って1行のテキストに変換して出力する
if len(buffer) > 0:
    print('|'.join(buffer))
```

# （参考）ここに至るまで（ChatGPTとの会話内容）
今回、ChatGPTくんが書いたコードがそのまま使えました。会話内容を紹介します。

まず最初に入力例と出力例を示し、どんな処理を行われているか言語化してもらいました。
```text:ChatGPTへの質問
以下の入力例と出力例を参考に、行われている処理を解説してください。

#入力例
テキスト1行目
テキスト2行目
テキスト3行目
テキスト4行目
テキスト5行目
テキスト6行目
テキスト7行目
テキスト8行目
テキスト9行目
テキスト10行目
テキスト11行目
テキスト12行目

#出力例
テキスト1行目|テキスト2行目|テキスト3行目|テキスト4行目
テキスト5行目|テキスト6行目|テキスト7行目|テキスト8行目
テキスト9行目|テキスト10行目|テキスト11行目|テキスト12行目

#処理
```
```text:ChatGPTからの回答
この処理は、複数行のテキストを与えられた場合に、4行ごとに区切ってパイプ記号(|)で区切られた1行のテキストを出力する処理です。

具体的には、与えられたテキストを1行ずつ読み込みながら、1行目から4行目までのテキストをバッファにためていきます。5行目以降のテキストが与えられた場合には、これまでためた4行のテキストをパイプ記号で区切って1行のテキストに変換し、出力します。そして、バッファを空にして、次の4行のテキストをためる準備をします。最後に、与えられたテキストが4行未満の場合には、最後にためたバッファをパイプ記号で区切って1行のテキストに変換し、出力します。

この処理を実装するためには、ループ文や条件文を使って、適切にテキストを読み込み、バッファにため、パイプ記号で区切った1行のテキストを出力する必要があります。また、テキストを1行ずつ読み込む方法や、文字列を区切る方法、条件文やループ文の使い方など、プログラミングの基礎知識が必要となります。
```

そのあとで、pythonコードで出力してもらいました。
```text:ChatGPTへの質問
この処理を行うpythonのコードを出力してください
```
```text:ChatGPTからの回答
以下は、与えられたテキストを4行ごとに区切ってパイプ記号で区切られた1行のテキストに変換するPythonコードの例です。

# テキストを1行ずつ読み込む
with open('input.txt', 'r') as f:
    lines = f.readlines()

# バッファにためる行数を設定する
n = 4

# バッファの初期化
buffer = []

# テキストを4行ごとに区切ってパイプ記号で区切られた1行のテキストに変換する
for i, line in enumerate(lines):
    # バッファにテキストをためる
    buffer.append(line.strip())
    # バッファにためたテキストがn行になった場合には、パイプ記号で区切って1行のテキストに変換して出力する
    if len(buffer) == n:
        print('|'.join(buffer))
        # バッファを空にする
        buffer = []

# テキストの行数が4で割り切れない場合には、最後にためたバッファをパイプ記号で区切って1行のテキストに変換して出力する
if len(buffer) > 0:
    print('|'.join(buffer))

このコードでは、まずopen()関数を使って、ファイルからテキストを読み込んでいます。次に、バッファにためる行数をnで設定し、バッファを初期化します。その後、enumerate()関数を使って、テキストを1行ずつ読み込みながら、バッファにテキストをためていきます。バッファにためたテキストがn行になった場合には、join()メソッドを使ってパイプ記号で区切って1行のテキストに変換し、print()関数で出力します。最後に、テキストの行数が4で割り切れない場合には、最後にためたバッファをパイプ記号で区切って1行のテキストに変換して出力します。
```



# （参考）Python使ったことないよ！っていうあなた
Google Colaboratory使えば簡単なのでスーパーオススメです。

# おわりに
今回、ググって良いやり方が出なかったので、ChatGPTに聞いてみたのですが、そもそもPython使わずExcelでも出来そうな気もする…
良いやり方をご存知の方、教えてください！

ちなみにChatGPTにExcelのやり方を教えてもらったんですが、なんかうまくいきませんでした。
Excelで四角にバツの図形（⛝）を描く

# はじめに
Excelで以下のような四角（四角形）にバツの（バッテンした、対角線を足した）図形を描く方法です。  
![shikaku_batsu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/09d12642-688f-693e-25b7-9389f2cfe60c.png)

:::note info
**使用するテクニック**
Altキーを押しながら図形を移動させると、セルの隅に吸着します。  
![altkeyexcel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/a4cfa1bf-cef7-09ae-25d1-ee3d0c717dd3.png)
:::

# 実際に描く
## その1 長方形1つと線2つで作成する
`長方形`を1つ、`線`を2つ用意した上でAltキーを押しながら移動し、最後にグループ化します。  
![excel_batsu.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/bb144ef2-c5b4-b0eb-5e24-3e01b9468476.gif)  
正方形にしたい場合は、作成後に高さと幅を同じにします。高さと幅は図形を右クリックしたときに出てくる[図形の書式設定]から変更できます。  
![seihoukei.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/bf540bb3-9e40-7ac7-ae43-5547e4b6211e.png)

## その2 フリーフォーム1つで作成する
`フリーフォーム`でラフ図を作成した後、図形を右クリックし[頂点の編集]を選択します。頂点が移動できるようになるのでAltキーを押しながら頂点を移動します。最後に適当なセルをクリックして頂点の編集を終了します。
![excel_batsu2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/1d55a612-bfe9-e637-ed5f-2ce5dce8b0a3.gif)

# 番外編 PowerPointで描く
PowerPointで四角にバツの図形（⛝）を描く方法です。「描画オブジェクトをグリッド線に合わせる」を有効にして作成します。以下の手順で有効にします。  
![pp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/9e24f2b7-f7cd-cde0-c3a7-bce2c3fcc3ef.png)  
あとは普通に図形を移動して作成します。Altを押す必要はありません。  
![ppanime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/e8b29b66-22db-f2ff-fa41-fa5f5bf89859.gif)
Rustでプログレスバーを表示する

現在フリーランスエンジニアとして活動していて、今今携わっている案件ではRustとTauriを使ってExcelファイルを出力するデスクトップアプリを開発しています。

メンテナンス作業を行うために簡単なバッチ処理を実装しているのですが、バッチ処理の進捗状況を表示するためにプログレスバーを利用しようと思い、Rustでプログレスバーを表示する方法を調べました。

Rustにもプログレスバーを表示するためのクレートがいくつかありますが、今回は最もダウンロード数が多く、開発も活発そうな`indicatif`を使用します。

https://docs.rs/indicatif/latest/indicatif/index.html#

早速、`indicatif`を使ってプログレスバーを表示するサンプルコードを載せます。

```toml:Cargo.toml
[dependencies]
indicatif = "0.17.3"
```

```Rust:Rust
use std::thread;
use std::time::Duration;

use indicatif::{ProgressBar, ProgressStyle};

// プログレスバーの長さを指定してプログレスバーを作成
let pb = ProgressBar::new(100);
// プログレスバーで表示する文字列を指定
pb.set_style(ProgressStyle::default_bar()
    .template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta}) \n {msg}")?
    .progress_chars("#>-"));

for _ in 0..100 {
    thread::sleep(Duration::from_millis(5));
    // プログレスバーの進捗位置を繰り上げる
    pb.inc(1);
}
// プログレスバーを終了しメッセージを設定する
pb.finish_with_message("正常終了しました。");
```

```
  [00:00:05] [########################################] 100/100 (0s) 
 正常終了しました。
```

ちょっとハマったこととして、`pb.finish_with_message("正常終了しました。");`を呼び出しているのに、完了後のメッセージである「正常終了しました。」を表示しなかったというのがありました。

結局原因はプログレスバーのテンプレート文字列の設定（`.template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta}) \n {msg}")?`）で当初`{msg}`を含めていなかったのが理由で、挿入したら無事メッセージを表示できるようになりました。
pandasを使って、2つのTBLの差分を比較する (mergeを使って)

## やりたいこと
pythonのライブラリであるpandasを使って、
2つのTBLの差分を比較して相違点を洗い出したい。
## コード
```python
## csv読み込み
a1 = pd.read_csv("test.csv")
a2 = pd.read_csv("test2.csv")
## a1とa2をマージさせる
a_merge = pd.merge(a1,a2,how="outer",on="カラム1",indicator=True)
## value_countsでそれぞれの数を数える
a_merge["_merge"].values_counts()
```
## 概要
ここでの肝は`indicator`を使うこと。
使うことにより、`_mergeカラム`ができるのが大事。
このindicatorはleftやouterなどの結合で、どれぐらい紐づいているかを判別するオプションみたいですね。
試しに2つをマージして、`_merge`をみてみます。
`both`,`left_only`,`right_only`3つの表示が出てきます。
これにより左にしかないもの、右にしかないものを見ることが可能になります!
最終的に、以下を実行すれば違うところが目に見えてわかるので便利かもしれにゃい。
```python
a_merge[a_merge["_merge"] == "left_only"]
a_merge[a_merge["_merge"] == "right_only"]
## left_onlyはは左にしかないものを出してくれる。right_onlyは右
## このため、２つの相違点が洗い出すことができる。
```
参考：
https://qiita.com/mk_GF/items/2c47dfed15520d34f7d4
Couldn't find database client: mysql, mysql5. Check your $PATH and try again

```
$ docker-compose run hoge rails dbconsole
```
 エラー。

エラー内容
```
Couldn't find database client: mysql, mysql5. Check your $PATH and try again.
```

<h2>解決</h2>

dockerfileにmariadb-clientを追記
```
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs mariadb-client
```

再度実行
```
docker-compose run hoge rails dbconsole
```
いけた。
neosでlogix その130

# 概要
neosでlogixやってみる。
練習問題やってみた。

# 練習問題
websocketで、fizzbuzzを実行せよ。

# 写真

![2023-05-02 08.23.51.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/9df77b62-1b3a-cc32-b171-06fda52f3f1a.jpeg)

# サーバーは、これ。

https://qiita.com/ohisama@github/items/25e8a51f4a21ad7a81ab

# 手順
- websocketサーバーを起動。
- transceiverを実行する。


以上。
プリザンターのプロセス機能とクライアントスクリプトで確認メッセージと成功メッセージを表示する

# はじめに
プロセス機能はワークフローを作成するにあたってとても便利です。状況項目によってボタンを表示しなかったり、表示したり・・・。ボタンをクリックすることで状況項目を変えて、担当者にメール送信をしたり・・・。色々なことができます。しかも、これがノーコードで作成することができます。今回の記事では、プロセス機能を使って確認メッセージと成功メッセージを同時に表示するため、一部スクリプトで実装していきます。プリザンターのプロセス機能では、実行種別が「作成または更新」とした場合に成功メッセージは表示できますが、確認メッセージを表示することができません。そのため、スクリプトで確認メッセージを表示する処理を実装していきます。

# ソースコード
```JavaScript
try {
    // 更新ボタンのHTML要素の内容を書き換える(onclick属性の内容を書き換える)
    $('<button id="UpdateCommand" class="button button-icon validate ui-button ui-corner-all ui-widget applied" type="button" accesskey="s" onclick="sampleComfirm($(this));" data-icon="ui-icon-disk" data-action="Update" data-method="put"><span class="ui-button-icon ui-icon ui-icon-disk"></span><span class="ui-button-icon-space"> </span>更新</button>').replaceAll('#UpdateCommand');    
    // 更新ボタンがクリックされた時に呼び出される処理
    function sampleComfirm (element) {
        // 確認ダイアログボックスを表示する
        var checked = confirm("確認メッセージです");
        // OKがクリックされたときの処理
        if (checked === true) {
            // 更新処理が走る
            $p.send(element);
        }
    }
} catch (ex) {
    console.log(ex.stack)
}
```
実行種別が「作成または更新」とした場合、新規でボタンは追加されずデフォルトのボタンに処理が追加されます。この場合、成功メッセージのみ定義することで更新ボタンを押したときに成功メッセージを表示することができます。この時、確認メッセージを定義しても表示されないため、これをスクリプトで実装していきます。まず、このままだとただ更新処理が走ってしまいますので、replaceAllメソッドを使って更新ボタンのonclick属性の値(呼び出しメソッド)を変えていきます。
## onclick属性
onclick属性に設定されている値は「ボタンがクリックされた際に呼び出されるメソッド」を設定します。今回のスクリプトでは後に設定しているsampleComfirmメソッドを呼び出すという意味を表しています。デフォルトでは$p.send($(this));が設定されていますので開発者ツールを開いて確認してみてください。

sampleComfirmメソッドが呼び出されたら、確認メッセージですという内容で確認ダイアログボックスが表示されます。そして、OKがクリックされたら、更新ボタンのonclik属性にデフォルトで設定されている$p.send($(this));が実行されます。そうすることで確認ダイアログボックスを表示しながら、成功メッセージも表示させることができます。

# さいごに
今回はデフォルトのHTML要素をスクリプトを使って書き換え、呼び出しメソッドを任意のメソッドに設定したのち、任意のメソッドに任意の処理を実装するという便利な仕組みを作ることができました。デフォルトのボタンで任意の処理が実装できるのであれば、同じようなボタンを追加して、デフォルトのボタンを削除するという処理が必要なくなりますので、便利ですね。皆様も試してみてください！
X-NUCLEO-GFX01M1で温度計を作る(MCP9701)(STM32G071)(ILI9341)(浮動小数点)


x MCP9701-E/TO 販売コード 103199

x 過去ログを見よ　とりまarduinoのところにいろいろある 


目的
テキストのテスト
A2に温度センサーを接続した。


![o_cop485.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/dca6abcc-9d09-77b9-05ee-85ead65e2b08.jpeg)




```c++




//ili9341_mcp9701_071

//インクルド
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

//設定
#define TFT_RST A1
#define TFT_DC 3
#define TFT_CS 4

//液晶の定義
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

//初期化
void setup() {

  //シリアルの初期化
  Serial.begin(9600);
  Serial.println("ILI9341 Test!"); 

  //液晶のリセットピンの設定
  pinMode(TFT_RST, OUTPUT);
  digitalWrite(TFT_RST, HIGH);
  //digitalWrite(TFT_RST, LOW);

  //液晶の初期化
  tft.begin();

  //画面のクリア
  tft.fillScreen(ILI9341_BLACK);
  
}//setup


//無限ループ
void loop(void) {


  //センサーの値を読み込む
  analogReadResolution(12); // ADC 12bit mode
  int s = analogRead(A2);   // センサーの読み取り値

  //センサーのADC値を電圧に変換
  float v = s * ( 3.3 / 4096.0 );

  //センサーの電圧を温度に変換
  float t = (v - 0.4) * (1.0 / 0.0195);
  int d1 = t;
  int d01 = (t * 100) - (d1 * 100);
  

  //温度の表示

  //クリア
  tft.fillRect( 0 ,0 , 24*5 , 24 , ILI9341_BLACK);

  //表示位置を0,0にする
  tft.setCursor(0, 0);

  //テキストの表示
  tft.setTextColor(ILI9341_WHITE);    tft.setTextSize(3);
  tft.print(" ");
  tft.print(d1);
  tft.print(".");
  if( d01 >= 0 && d01 <= 9 ) { tft.print("0"); }
  tft.print(d01);
  tft.print(" ");
  
  delay(1000); //1秒待つ

}//loop




```
Fusion 360のアドインの作り方_準備編

# はじめに
はじめに、なぜ自分がこの記事を書こうと思ったのかについて説明したいと思います。
自分は卒業研究の関係で、Fusion360のアドインの開発をすることになったのですが、調べても調べても日本語の記事がなく、英語の記事もあまりなく、本当に苦労しました。
一方で、Fusion360では学問分野をはじめ、広く使用されるCADアプリケーションです。にもかかわらず、ものにすればとても大きな恩恵を享受できるアドイン開発が浸透していなく、とても歯がゆい気持ちを持っていました。
そこで、日本語で詳しく解説した記事を書くことで、アドイン開発へのハードルを下げ、より多くの人に開発してもらい、恩恵を享受してもらいたいと思い、今回の執筆に至りました。
この記事では、アドインを作る上での事前知識や準備について説明したいと思います。


# まず、アドインってなに？
Fusion360には、デフォルトのCAD機能に加え、スクリプトやアドインという拡張機能を実装することができます。例えると、Excelのマクロのような感じです。

デフォルトだと、歯車を自動生成してくれるようなものがあります。


スクリプトとアドインの違いについて、前者は一回のみ実行してくれるのに対し、後者は実行停止をしない限り起動し続けるという感じです。簡単なアプリケーションのようなものを実装したい場合は、アドインで実装するといいかもしれません。



# アドインの作り方
ここでは、Macを用いる場合の作り方を説明します。Windowsで作る時も、プロジェクトが保存されるディレクトリが違うだけで、それ以外は同じです。

ユーティリティのスクリプトとアドインをクリックして、
![スクリーンショット 2023-05-02 17.19.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192889/db9226e3-f9f4-0850-d906-4cb819a3bfb7.png)


マイアドインの作成ボタンを押すと、
![スクリーンショット 2023-05-02 17.20.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192889/e5aa7c3c-b428-9f34-9604-bcf74b729e85.png)



このような画面が出てきます。プログラミング言語をC++とPythonの2つから選び、プログラムの名前をつけます。サンプルコードも充実しているので、Pythonの方がおすすめです。フォルダの場所は、後で編集するときのために覚えておきましょう。
![スクリーンショット 2023-05-02 17.20.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192889/79837aed-7e1e-b9c6-76f8-645c96f4e93e.png)

作成ボタンを押すと、このように新しく追加されます。ここの編集ボタンを押すと、コードの編集ができます。編集環境はVisual Studio Codeです。インストールされていない場合、最初にインストール作業が自動で行われます。
![スクリーンショット 2023-05-02 17.21.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192889/c78b6ec7-6608-17b5-04f3-5d8e2344dd87.png)




# Fusion360 API
スクリプトやアドインを作るための[Fusion360 API](https://help.autodesk.com/view/fusion360/ENU/?guid=GUID-A92A4B10-3781-4925-94C6-47DA85A4F65A)が公開されています。


クラスライブラリは、Fusion 360 API Reference ManualのObjectsに書いてあります。全部で700ほどありますが、おそらく使うのはせいぜい100〜200なので、安心してください笑
![スクリーンショット 2023-05-02 16.18.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192889/1b927c24-dc62-97c2-4c3d-1cd81e49fe06.png)

また、サンプルコードも載っているので、参考にすると良いと思います。
![スクリーンショット 2023-05-02 16.19.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192889/447177cd-de1e-0702-4fc8-273ce3002970.png)



# デフォルトのコード
アドインのプログラムを作成し、編集を押すと、デフォルトで以下のようなコードが書かれた、プログラム名と同じ名前のpythonファイルが開かれます。run関数はアドイン実行時に呼ばれる関数で、stop関数はアドイン停止時に呼ばれる関数です。このスクリプトがアドイン実行時に最初に呼ばれます。このスクリプトを、ここではMainスクリプトと名付けておきましょう。
![スクリーンショット 2023-05-02 17.22.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192889/22e30392-3518-1ca8-a619-b8375122d9ca.png)

ディレクトリ構造は、以下のようになっています。プログラム名のフォルダの中に、Mainスクリプトファイルといくつかのフォルダがあります。Mainスクリプトに書いてある、commandsやfutilはこれらのフォルダ内やこれらのフォルダの中にあるpythonファイルなどを指しています。
ぶっちゃけ、自分で一からプログラムを作るなら、Mainスクリプトのファイル以外、消してもらって構いません。

![スクリーンショット 2023-05-02 17.42.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192889/4e8ffb80-a93d-9f09-9ec0-df65b1cc30f6.png)

いかがだったでしょうか。次の記事からは、アドインの作り方について、もっと詳しく解説していきたいと思います。


# 次の記事
https://qiita.com/narumy/items/4bebadd96e0b3764d3b1
AWS 1年間無料利用枠 まとめ

## はじめに
AWS各種サービスの1年間限定無料枠をまとめた早見表です。
2023年5月に確認したものです。ぜひ個人利用の際にご活用ください。

## １年間限定無料
| サービス名 | 対象 | メモ |
| --- | --- | --- |
| EC2 | t2micro, t3micro<br>750時間/月 | インスタンス１つに限定して利用すれば無料で利用可能。 |
| ECR | 500MB/月 | Dockerイメージの保存 |
| ELB | 750時間/月 |  |
| OpenSearch Service | 750時間/月<br>single-AZ t2.small.search または t3.small.search インスタンス | ログ分析、リアルタイムのアプリケーションのモニタリング、ウェブサイト検索などの実行を簡単にするマネージドサービス。 |
| Data Pipeline  | ３の低頻度の前提条件<br>5個の低頻度のアクティビティ | データソース間で信頼性の高いデータ処理やデータ移動を行うことを支援するウェブサービス |
| Amazon MQ | 750/月<br>シングルインスタンスの mq.t2.micro またはmq.t3.micro | オープンソースメッセージブローカー向けのフルマネージドサービス |
| App Sync | 250,000クエリまたはデータの変更/月 | GraphQL API を開発、セキュア化、および実行 |
| Amazon Connect | 90分/月 | 顧客窓口を構築できるシンプルなクラウド型コンタクトセンター |
| RDS | 750時間/月 | MySQL、MariaDB、PostgreSQL データベースを実行する Amazon RDS シングル AZ db.t2.micro、db.t3.micro、および db.t4g.micro インスタンスの使用時間 |
| Amplify ホスティング | 15GB | 構築やデプロイ、ストレージ、データの転送など細かく無料枠が設定されているので注意 |
| API　ゲートウェイ | 100万回のAPIコール/月 | スケールを問わない API の公開、維持、監視、保護。 |
| Amazon Pinpoint | 5000/月の無料利用対象ユーザー<br>1,000,000件/月の無料プッシュ通知<br>1,000,000件/月のイベント<br>15,000件のアプリケーション内メッセージAPIリクエスト/月 | モバイルアプリケーション向けのターゲットプッシュ通知サービス |
| Amazon GameLift | 125時間/月のオンデマンドインスタンスの使用<br>EBS汎用ストレージ 50GB | c3.large、c4.large、c5.largeが対象 |
| IOT Greengrass | 3台のデバイス | インターネットに接続されたデバイスでローカルのコンピューティング、メッセージング、データキャッシュ、同期を行う。 |
| IoT Core | 50万件/月 | クラウドにデバイスを接続 |
| IoT Events | 2500/月 | IoT センサーやアプリケーションで発生したイベントを容易に検出し対応できるようにする |
| IoT Things Graph | 5000ステップ/月 | さまざまなデバイスやウェブサービスを容易に視覚的に接続して IoT アプリケーションを構築できるサービス |
| Amazon Comprehend | 50K単位のテキスト/月<br>(500万文字)(APIごと) | 継続的なトレーニングが行われている、フルマネージド型自然言語処理 |
| Amazon Lex | 10,000件/月 | 音声やチャットテキストに対応するチャットボットを構築。 |
| Amazon Polly | 500万文字/月 | テキストを生きた話し声に変換 |
| Amazon Rekognition | 5000件/月の画像分析 | 深層学習に基づく画像認識 |
| Amazon Transcribe | 60分/月 | 自動音声認識を使用した音声のテキスト変換機能 |
| Amazon Translate | 200万文字/月 | 機械翻訳 |
| Augumented AI | 1年間で500オブジェクトまで無料<br>1月あたり42件 | 人による ML 予測のレビューに必要なワークフローを簡単に構築 |
| AWS OpsWorks for Chef Automate | 7500ノード時間/月 | Chef サーバーと Chef Automate による設定管理 |
| AWS OpsWorks for Puppet Enterprise | 7500ノード時間/月 | Puppet Enterprise を使用した設定管理 |
| Amazon Elastic Transcoder | 20分のオーディオトランスコーディング<br>20分のSDトランスコーディング<br>10分のHDトランスコーディング | 完全マネージド型メディアトランスコーディングサービス。 |
| Amazon Interactive Video Service | 100時間/月 | ライブのインタラクティブな動画ストリームをセットアップ |
| Amazon Cloud Directory | １GB/月 | 複数の階層を持つデータ向けのディレクトリ構築サービス |
| S3 | 5GBの標準ストレージ<br>20,000件のGetリクエスト<br>2000件のPutリクエスト | ストレージ |
| EFS | ５GB  | EC2 インスタンス用共有ファイルストレージサービス。 |
| EBS | 30GB<br>200万I/O<br>１GBのスナップショットストレージ | ブロックレベルストレージボリューム。 |
クラス設計　Interface Segregation（インターフェイス分離の原則）　〜トレードオフを考えよう〜

今回は、リスコフの置換原則に続く、インターフェイス分離の原則についてです。

https://qiita.com/F_Yoko/items/fdb012be7b123acec46a

# インターフェイス分離の原則
これは、「クライアントは自分が使わないメソッドへの依存を強制されてはいけない」ということです。

つまり、自分の必要な分だけ用意しましょうということです。
環境に配慮しましょうということです。←違う

例えば、ドラえもんのどこでもドアは扉を開くと好きなところに行けるというインターフェイス（メソッドやプロパティ）を持っています。

もし、ここにタケコプターのインターフェイスが混ざったら、どこでもドアがどこか遠くへ飛んでいってしまう訳です。それでは大迷惑です。

ですので、どこでもドアにタケコプターのインターフェイスは余計なので、分離しましょうということです。

しかし、rubyのメソッドは使うタイミングでしか呼び出されないので当てはまらないらしいです...


この原則をrubyに適用するならば、
「クラスをどれくらいの大きさにするべきか」という話になるとか。

まあクラスが大きい場合、モジュールに切り出すわけですが、どれをどれくらいに、どんな基準で切り出すかというまた別問題が出てきます。

また、切り出しすぎるとそれはそれでプログラマーの負荷が高まるということにもなります。

簡単にいうと以下のメリットがそれぞれあります。

:::note 
__クラス数を少なくする__
=> コードが概念的にシンプルになる
__クラス数を多くする__
=> コードがモジュール化されるため部分修正が容易になる
:::

この辺りのバランスが必要なわけですね。このインターフェースの分割については後日別記事にまとめたいと思います。
【Blender】非表示にしたボーンが再表示されない時の対処法

【症状】ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
Hキーで非表示にしたボーンを、「H + Altキー」で再表示させようとしても再表示されない。

以下、著者が実際に体験した症状の具体例↓↓
・ウェイトペイントを行っている際、HeadボーンをHキーで非表示に。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3326415/0fae0eb3-080c-c2d7-1874-5d8010b3118a.png)
Hキーで非表示↓↓
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3326415/87e3e5fb-dd36-9566-b130-7b42f6fc6915.png)
しかし、「H + Altキー」で再表示させようにも、再表示されない。困った。。。


【対処法】ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
1.面右上のアウトライナーから、再表示させたいボーンの「Armature」を探す。
2.見つけたら、その中に「Armature」があると思うので、その下の階層の中から再表示させたいボーンを探す。（著者の場合は、「J_Bip_C_Head」が対象のボーンとなる）
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3326415/3ddf5116-a51c-8f03-c26d-2965ba87e229.png)
3.対象のボーンの上にカーソルを持っていき右クリック。その中の「Unhide（再表示）」をクリック。![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3326415/028c41da-0c4c-4d7a-f062-19a693a3862e.png)
4.このままだと非表示にしたボーンはまだ表示されないので、ボーンを選択した状態で編集モードにする。すると、以下のようにHeadボーンが表示される。
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3326415/5c9596ba-6330-5912-3271-9630b250742d.png)!
5.あとはそのままオブジェクトモードに戻れば、再表示が完了！！
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3326415/9f6e45a1-dcb0-30d4-a6af-6d6ae17d5c22.png)

以上、お疲れさまでした。
STM32G071と温度センサーMCP9701で温度をシリアル出力(浮動小数点使用)


x MCP9701-E/TO 販売コード 103199

目的
安価に温度を測る。

センター　400mV
ステップ　19.5mV 1℃


![o_cop484.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/9cda4f8f-b303-7659-9706-79d16db13dcc.jpeg)






```c++


//SER_MCP9701_float_071_1

#include <Arduino.h>

//初期化処理
void setup()
{

  //シリアルの初期化
  Serial.begin(9600);

} //setup

//メインループ
void loop()
{

  //センサーの値を読み込む
  analogReadResolution(12); // ADC 12bit mode
  int s = analogRead(A2);   // センサーの読み取り値

  //センサーのADC値を電圧に変換
  float v = s * ( 3.3 / 4096.0 );

  //センサーの電圧を温度に変換
  float t = (v - 0.4) * (1.0 / 0.0195);

  //温度の表示
  Serial.println(t);

  //1秒の待ち
  delay(1000);

} //loop



```
neosでlogix その129

# 概要
neosでlogixやってみる。
練習問題やってみた。

# 練習問題
websocketで、zundokoを実行せよ。

# 写真
![2023-05-02 08.02.30.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/abf3a1aa-0e5a-aaea-b3b3-7efc16c069f0.jpeg)

# サーバーは、これ。

https://qiita.com/ohisama@github/items/632dc159e9b565255320

# 手順
- websocketサーバーを起動。
- transceiverを実行する。


以上。
M2 MacBookの初期設定の備忘録

初投稿です．新しいMacBookを買ったので設定しました．自分用の備忘録として記録します．PCは以下のものを用いています
- Macbook Pro 14インチ， 2023
- Apple M2 Pro
- Ventura 13.3.1

Finderなどの基本的な設定は[こちらの動画](https://youtu.be/Zd3Fmropvtk)を参考にしました．
# Homebrewのインストール
　はじめにパッケージ管理アプリをインストールしました．[ホームページ](https://brew.sh/)にあるようにターミナルで以下を実行します．
```
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
次に以下のようにパスを通します．
```
$ (echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> /Users/hogehoge/.zprofile
$ eval "$(/opt/homebrew/bin/brew shellenv)"
```
とても丁寧に説明されている[この記事](https://blog.kikagaku.co.jp/homebrew-install-howto)を参考にしました．正しくインストールできているかは`brew --version`で確認します．Homebrewでインストールできるアプリは`brew search "hogehoge"`で調べることができます．


# Gitのインストール
元からインストールされているがHomebrewで管理したいためインストールします．
```
$ brew install git
```
パスを通すことで反映させます．
```
$ echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.zshenv
$ source ~/.zshenv
```
コミットログに残るユーザ情報の設定をします
```
$ git config --global user.name "hogehoge"
$ git config --global user.email "hogehoge@gmail.com"
```
# エディタのインストール
vimが好きなのでvimをインストールしました．
```
$ brew install vim
```
vimの設定は[こちらの記事](https://qiita.com/ysm001/items/8ae97cfdaae3f5fe79f4)を参考にしています（まだ終わってない）．自分用vimの設定もそのうち備忘録に残していきたいと思います．

# 汎用アプリのインストール
## Google Chrome
```
$ brew install --cask google-chrome
```
## Slack
```
$ brew install --cask slack 
```
## Zoom
```
$ brew install --cask zoom
```
## Discord
```
$ brew install --cask google-chrome
```
## LINE
[こちらの記事](https://zenn.dev/ss49919201/articles/ddfa4626d51ab5)を参考にしました．
app storeのアプリを管理するツールmas-cliをインストールします．
```
$ brew install mas
```
アプリは以下のように検索できます．ここではLINEを検索します
```
$ mas search LINE    
```
LINEに相当するコードを入力することで以下のようにインストールできます
```
$ mas install 539883307     
```
# おわりに
この記事はまだ途中ですが仮に参考にしていただけると幸いです．
REST web APIのサービス設計について

# RESTfulとは
「RESTで求められる原則に従っている」こと

## REST原則

REST原則には6つの要素が求められる

***クライアント/サーバー***
画面とデータで関心事を分離
クライアント側がトリガー、サーバー側は受け身

***階層化システム***
多層アーキテクチャー構成

***コードオンデマンド***
クライアントコードをダウンロードして実行できる(リリース後にクライアントコードを変更できる)

***統一インターフェース***

・リソースの識別(URIを用いてサーバーに保存されたデータを識別する)
・表現を用いたリソースの操作(断面情報を利用してサーバー上のデータを操作する)
・自己記述メッセージ(メッセージ内容が何であるか、ヘッダーに記述されている)
・アプリケーション状態エンジンとしてのハイパーメディア(HAYEOAS)
    HATEOAS：レスポンスに現在の状態を踏まえて関連するハイパーリンクが含まれている

***ステートレス***
サーバーはリクエストだけでコンテキストを理解できる

***キャッシュ制御***
クライアントはレスポンスをキャッシュできる

## REST API 設計レベル
LEVEL 0：HTTPを使っている
LEVEL 1：リソースの概念を導入(リソースごとにURLを分割)
LEVEL 2：HTTPの動詞を導入(LEVEL 1に加えてHTTPメソッドを活用)
LEVEL 3：HATEOASの概念を導入(LEVEL 2に加えてレスポンスにリソース間のつながりが含まれている)

# URI設計について
- 短く入力しやすい(冗長なパスを含まない)
- 人間が読んで理解できる(省略しない)
- 大文字小文字が混在していない(すべて小文字)
- 単語はハイフンで繋げる
- 単語は複数形を利用する
- エンコードを必要とする文字を使わない
- サーバー側のアーキテクチャが反映されていない
- 改造しやすい
- ルールが統一されている

# 主要なHTTPメソッド
|メソッド名|説明|
|---|---|
|GET|リソースの取得|
|POST|リソースの新規登録|
|PUT|既存リソースの更新/リソースの新規登録|
|DELETE|リソースの削除|

# レスポンスのデータフォーマット
主要なレスポンスフォーマットは3種類

***XML***
- テキスト形式
- タグで記述
- タグは入れ子にできる
- タグに属性を付けられる

***JSON***
- テキスト形式
- JavaScriptを元にしたフォーマット
- ***XMLに比べてデータ量を減らせる***
- オブジェクトは入れ子にできる

***JSONP (JSON with Padding)***
- テキスト形式
- データフォーマットのようにみえるが「JavaScript」のコード
- ***クロスドメインでデータを受け渡すことができる***

# データの内部構造で意識すること
- エンベロープは使わない
- オブジェクトはできるだけフラットにする(レスポンス容量を減らす)
- ページネーションをサポートする情報を返す
- プロパティの命名規則はAPI全体で統一する(スネークケース、キャメルケース等)
- 日付はRFC3399(W3C-DTF)形式を使う
- 大きな数値(64bit整数)は文字列で返す

# 参考文献
https://www.udemy.com/course/rest-webapi-development/
数学ゴールデン（漫画）の整数問題を力技で解いてみた

気になりすぎたので解いてみた。漫画内にヒントはあるが、なかなか厳しい。
（下記、厳密な証明になっているかは微妙だが、要点は書けているつもり。）

# 問題

(5巻18話の問題)
黒板に1から100までの整数が1つずつ書かれており、黒板から2つの整数$a, b$を選んで消し、新たに$\gcd(a^2b^2+3,a^2+b^2+2)$を書くという操作を繰り返し行う。
書かれている整数が1個になるまで繰り返す(★)とき、その整数は平方数でないことを示せ。

# 解法の概略

3や4で割った余りの世界でどうなるかを実験する
→3で割った余りの表を生成すると、規則性が見える。

実験※
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="ZEqXJjL" data-user="kob58im" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/kob58im/pen/ZEqXJjL">
  Untitled</a> by kob58im (<a href="https://codepen.io/kob58im">@kob58im</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

※: ↑ Chat GPTで下記指示して書いてもらったコードをベースに作成
write a JavaScript code for calculating gcd.
write a JavaScript code to generate 10 x 10 table.

| $\gcd(a^2b^2+3,a^2+b^2+2)$ | a=3の倍数でない | a=3の倍数  |
|---|---|---|
| b=3の倍数でない | 3の倍数でない | 3の倍数 |
| b=3の倍数  | 3の倍数       | 3の倍数でない |

3の倍数でない・・・0
3の倍数・・・1
と置き換えてみると、下記のように加法的な性質をもつ

|  | A=0 | A=1  |
|---|---|---|
| B=0 | 0 | 1 |
| B=1 | 1 | 0 |

これを繰り返し操作すると、どの順序で実行しても

1 2 3 4 5 6 7 8 9 ... 100に対しての繰り返し操作★は、
(0+0+1+0+0+1+0+0+1)×11 + 0 mod 2を計算するのと等価であり、これは1となるので、最後に残る数は3の倍数となる。
3の倍数が平方数であるためには、9の倍数である必要があるため、$\gcd(a^2b^2+3,a^2+b^2+2)$が 9の倍数である必要がある。

3の倍数となりえる組み合わせは、3の倍数 と 3の倍数でない ものを$a,b$としたときである。
$(3m\pm 1)^2(3n)^2+3\mod 9 = 3$であり、$\gcd(a^2b^2+3,X)$が9の倍数になることはない。
従って、<b>最後に残る数は平方数ではない。</b>
AWS Amplifyを利用してReactコードを自動生成してみる

## やりたいこと

AWS AmplifyでFigmaと連携することでReactコードを自動で生成することができる。どのくらい実用的なのか調査を兼ねて触ってみる。

Figmaについては今回の記事のために簡単な使い方を覚えた程度。雑に作ります。

## 試したこと

- AWS Amplifyのセットアップ
- Figmaで[25:00 - Time to focus! (pomofocus.io)](https://pomofocus.io/app)の見た目に寄せたレイアウトを作成
- Figmaで作成したレイアウトからReactコードを自動生成
- npm startでローカル環境で表示

## 環境構築について

参考文献に記載した記事のとうりに進めていけば問題なく動作する。

難易度は高くないが、若干手間が多い。

## 実際につくれたもの
![rapture_20230502054555.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/781232/3fe99b03-93cb-8d0a-82de-15cd9f8a8d3f.jpeg)

画像を入れていた部分が入っていないのと、tasksの部分がずれてしまった。
また、PC用のサイズでフレームを作成したはずだが、Add Tasks付近がはみでて1ページに収まらなかった。

上記の点に関しては自分のFigmaの理解不足が大きいと思う。（Add TasksのあたりはAuto Layoutがうまく聞かなくて無理やり配置してしまったため）

## 感想

個人利用の非常に簡単なUIを作成したり、見た目の確認や認識合わせなど、利用できる部分は多々あるように思います。踏み込んだところまでUIを作りこんだり、改善を行っていないため、Amplify特有の癖があるかもしれません。

いずれにせよ、デザインからフロントエンドへの実装が簡略化されていることは明らかなので非常に有用なサービスだと思います。

## 今後試したいこと

- AmplifyではなくChatGPTを利用してコードに変換する方法を提案されている記事があったため、そちらとの精度の比較。[OpenAI API を使ったデザインからコード生成する Figma プラグイン - Gaudiy Tech Blog](https://techblog.gaudiy.com/entry/2023/04/28/085840)
- Amplifyで特有の癖がアプリケーション開発に与える制約などの把握

## 参考

[【入門】Figmaで作ったデザインをReactアプリに連携する - Qiita](https://qiita.com/KNR109/items/ab88c8f9a014fdccfba3#)
TypeScriptを使うときのメモ

kintone + TypeScriptの開発時にイチから作るときの手順をメモします。

[TypeScriptでkintoneカスタマイズ開発をしてみよう](https://cybozudev.zendesk.com/hc/ja/articles/360023293091-TypeScript%E3%81%A7kintone%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA%E9%96%8B%E7%99%BA%E3%82%92%E3%81%97%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86)

が確度の高い情報ですが、babelはもう使わないよなあというところで。

```console
git init
npm init
npm i typescript ts-loader
npm i webpack webpack-cli
npm install -D @webpack-cli/generators
kintone-customize-uploader init
```

`kintone-customize-uploader init`は、
あらかじめ`npm i -g @kintone/customize-uploader`しておく必要がある。
そのままだとPowerShellの実行ポリシーに引っかかる場合があるので
`Set-ExecutionPolicy -ExecutionPolicy RemoteSigned` しておく必要もある。

customize-manifest.jsonは適度に修正。
[TypeScriptでkintoneカスタマイズ開発をしてみよう](https://cybozudev.zendesk.com/hc/ja/articles/360023293091-TypeScript%E3%81%A7kintone%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA%E9%96%8B%E7%99%BA%E3%82%92%E3%81%97%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86)
の記事を読んだらよいかと。

package.jsonにスクリプト追加
```json
    "get-fields": "kintone-dts-gen --base-url https://****.cybozu.com/ -u %MY_KINTONE_ID% -p %MY_KINTONE_PASSWORD% --app-id xxx -o ./src/fields.d.ts"
```

フィールドが更新されたら `npm run get-fields` することとなる。

```json
    "upload": "kintone-customize-uploader --base-url https://tasou.cybozu.com/ --username %MY_KINTONE_ID% --password %MY_KINTONE_PASSWORD% src/dest/customize-manifest.json"
```

カスタマイズをいれたいときは `npm run upload` する。あるいは `npm run upload -- --watach` する。
kintoneカスタマイズの開発環境構築の覚書き

# 概要
kintoneカスタマイズの開発環境を構築するための資料のまとめ。
チーム開発で新しく参加される方向け。
kintoneカスタマイズの情報は、`cybozu developer network`を見れば良いが情報量が多いので迷わないように最低限の情報だけをまとめる。

# 対象
Webフロントエンドエンジニア
kintone触ったことない
kintoneカスタマイズ全く知らない

# kintoneの開発環境の準備

## 前提条件
kintoneが導入済み

## やること

1. kintoneのアカウントの払い出し
2. 作業用のkintoneスペースの作成
3. 作業用のkintoneアプリの作成

### 説明

#### 1. kintoneのアカウントの払い出し
管理者がアカウントを作成する

#### 2. 作業用のkintoneスペースの作成
開発用として専用のスペースを作成する
スペースに1.で作成したアカウントを追加

#### 3. 作業用のkintoneアプリの作成
開発用のkintoneアプリを作成
kintoneアプリに必要な権限を付与する。
kintoneカスタマイズの作業にはkintoneのアプリ管理権限の付与が必要。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214523/474cb220-b2c5-e1cb-1bda-958b21e39455.png)

# kintoneカスタマイズ環境の準備
kintoneカスタマイズに関する参考資料のリンクと、カスタマイズのサンプルなどをまとめる。

## コーディングガイドライン
https://cybozu.dev/ja/kintone/docs/guideline/

## kintoneカスタマイズ参考資料リンク

* [cybozu developer network](https://cybozu.dev/ja/)
* [cybozu developer network とは](https://cybozu.dev/ja/getting-started/about/)

## 開発者ライセンス
APIを試す等に必要。
https://cybozudev.zendesk.com/hc/ja/articles/200720464

## チュートリアル
まずチュートリアルをやってもらう。

* [JavaScript を使用した kintone のカスタマイズ](https://cybozu.dev/ja/kintone/getting-started/what-is-kintone-customize/)

https://cybozu.dev/ja/tutorials/

## カスタマイズサンプル
基本的にはチュートリアルで良い。後は現場で現状のカスタマイズされたソースコードを読んでもらう。

## コーディング環境など

### Gitの利用
必要に応じてGitを利用する

### ライブラリ
適宜ライブラリを利用する

* [kintone-rest-api-client](https://cybozu.dev/ja/kintone/sdk/rest-api-client/kintone-javascript-client/)

### webpack
適宜`webpack`等を導入する

[目指せ！JavaScriptカスタマイズ中級者（１） 〜webpack編〜
](https://cybozudev.zendesk.com/hc/ja/articles/360040220451)


# プラグイン開発
kintoneプラグインの基本的な情報とチュートリアルをまとめる。

## kintoneプラグインの基本情報
プラグインとは何か、プラグイン化のメリットなど。

https://cybozudev.zendesk.com/hc/ja/articles/360017819551

## プラグイン開発環境
Node.jsをインストールしてwebpackを利用した開発環境を構築する

[プラグイン開発支援ツール群の案内](https://cybozudev.zendesk.com/hc/ja/articles/360000975763)


[kintone プラグイン開発手順](https://cybozudev.zendesk.com/hc/ja/articles/203455680)

プラグインの開発は、下記の流れです。


1. プラグイン作成に必要なファイルの準備します
2. マニフェストファイル(manifest.json)の作成
3. パッケージツール(plugin-packer)を利用してパッケージング
4. 作成したプラグインファイルを kintone 環境にインストール


3.のplugin-packreを利用した初回のパッケージングの際に、PPKファイルが同時に作成されます。
2回目以降のパッケージングには初回に作成されたPPKファイルを指定してパッケージングすれば同じプラグインとして作成されます。

リリース版と別にプラグインをパッケージする際は、PPKを新規に生成することで別のプラグインとして生成可能です。


以下パッケージ手順より抜粋。

>実行したディレクトリに、プラグインファイル (plugin.zip) と秘密鍵ファイル (ppkファイル) が生成されます。
>秘密鍵ファイルのファイル名は、プラグインIDと同じです。
>下記の例では、プラグインIDが「faabchdodajloackbgnipilddblmkejp」です。
>秘密鍵ファイルは、2回目以降のパッケージングで利用するので、なくさないようご注意ください。


Web 版の plugin-packerもあります。
https://plugin-packer.kintone.dev/index-ja.html
spring トランザクション・2重サブミット対策

# トランザクション処理
実装しないと全体としての処理が失敗しても、データが登録されたままとなってしまいデータの一貫性がとれない状況となってしまう。
## @Transactional
Springでは@Transactionalを登録・更新処理に適用して使用するのが一般的。

# 2重サブミット対策
対策しないとリロードするたびに、直前のリクエストが再実行されてしまう。
↓
リダイレクトを活用したPRG（Post-Redirect-Get）パターンにより対策する。
Postの後に、サーバ側からリダイレクトにより直前のポストリクエストを実施

## リダイレクトとは
レスポンスを受け取ったブラウザに指定したURLを読み込ませる方法。(300番代のリダイレクト処理をサーバで返答する。)

### 実装
コントローラのハンドラーメソッドの戻り値に「redirect:」から始まる戻り値を指定する。
VSCodeでタスクを再実行するコマンド

そんな機能はないのかと思っていたのですが、たまたまショートカットの設定をみていたらコマンドを見つけて嬉しかったので、とんでもなく久しぶりに記事を残します！


```
タスク:最後のタスクを再実行
workbench.action.tasks.reRunTask
```

こんなのありましたか？
数年前に探した時はなかった覚えがあります。


タスクの実行と合わせて自分は以下の設定にしました。

```json
{
  "key": "cmd+t",
  "command": "workbench.action.tasks.runTask"
}
{
  "key": "shift+cmd+t",
  "command": "workbench.action.tasks.reRunTask"
}
```


小さな事ですがVSCodeのタスクでテストを実行している人は、かなり操作感が改善されるんじゃないかと思います！
お前らはjsのvarとletの違いを分かってない

JavaScriptのvarとletは、変数を宣言するためのキーワードですが、いくつかの重要な違いがあります。

## スコープ
varは関数スコープを持ちます。これは、varで宣言された変数が関数内でアクセス可能であることを意味します。一方、letはブロックスコープを持ち、letで宣言された変数はそのブロック内でのみアクセス可能です。
``` Javascript
function testVar() {
  if (true) {
    var x = 10;
  }
  console.log(x); // 10
}

function testLet() {
  if (true) {
    let y = 20;
  }
  console.log(y); // ReferenceError: y is not defined
}
```
## ホイスティング
varで宣言された変数は、関数またはグローバルスコープの先頭に巻き上げられます。これは、変数が宣言される前に参照できることを意味します。ただし、その時点では未定義として扱われます。letで宣言された変数も巻き上げられますが、初期化前にアクセスしようとするとReferenceErrorが発生します。
``` Javascript
console.log(a); // undefined
var a = 10;

console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 20;
```
## 再宣言
同じスコープ内で、varを使用して既存の変数を再宣言することができますが、letでは再宣言が許されません。
``` Javascript
var c = 30;
var c = 40; // No error

let d = 50;
let d = 60; // SyntaxError: Identifier 'd' has already been declared
```
## グローバルオブジェクト
varで宣言されたグローバル変数は、グローバルオブジェクト（ブラウザではwindowオブジェクト）のプロパティとなります。letで宣言されたグローバル変数は、グローバルオブジェクトのプロパティにはなりません。
``` javascript
var e = 70;
console.log(window.e); // 70 (in a browser environment)

let f = 80;
console.log(window.f); // undefined (in a browser environment)
```
これらの違いを理解し、適切な変数宣言キーワードを選択することが重要です。一般的には、letやconstを使用してブロックスコープを活用することが推奨されています

## 最後に
この内容はchat gpt(4)に聞いたものをそのままコピペして作成しました。
![スクリーンショット 2023-05-02 15.42.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689222/6b953d8f-9b5c-984b-42fd-480d23d4cea4.png)
【解決済み】pipによるパッケージのインストールに失敗する(Could not find a version that satisfies the requirement)

## OUTPUT

# 問題: MediaPipeのインストールに失敗

MediaPipeは、機械学習を利用したリアルタイムの画像や動画解析に用いられるオープンソースのフレームワークです。しかし、pipを用いてMediaPipeのインストールが失敗する現象が発生しています。この問題はPython 3.18の環境で発生しています。

```
> pip install mediapipe
ERROR: Could not find a version that satisfies the requirement mediapipe (from versions: none)
ERROR: No matching distribution found for mediapipe
```

## 原因: Pythonバージョンとの非互換性

インストールしようとしているパッケージが、現在のPythonバージョンに対応していないことが原因です。

## 調査方法: PyPIから対応バージョンを確認

対応するPythonバージョンは、[PyPI](https://pypi.org/)から確認することができます。

【疑問点】より効率的なコマンドを使って調べる方法はあるのでしょうか？

1. `python -V` で自身の環境のPythonバージョンを確認します。
2. PyPIでインストールしたいパッケージを検索します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17098/f87158be-bd93-b9ea-7efe-67521c5d8b6a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17098/cfa265b9-c21d-7c82-a0fe-e6fc28bede68.png)

3. 「ファイルをダウンロード」タブを開くと、「Built Distributions」に「cp311」というバージョン情報が表示されます。ここで「cp311」はPython 3.11を意味しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17098/b3812d2a-eda5-5793-e3e4-096b71545116.png)

## 解決策: pyenv-winでPythonバージョンを切り替える

[pyenv-win](https://qiita.com/noppe78/items/6de6a11116850a0a81a7) を使用して、対応するPythonバージョンに切り替えることで問題を解決できます。
現在の yyyyMMdd (年月日) をフォルダ名にして作成する batファイル

- 仕事の時に、作業録とかを手元に残しておく用途で使用してます

```bat
@echo off
setlocal enableextensions

REM 現在の日付を取得する
for /f "tokens=1-3 delims=/ " %%a in ("%date%") do (
   set year=%%a
   set month=%%b
   set day=%%c
)

REM フォルダ名を作成する
set folderName=%year%%month%%day%

REM フォルダを作成する
mkdir %folderName%
```
ターミナルからEC2インスタンスに.sshフォルダがないとエラーが出てまたSSHアクセスしようとするとPermission denied出て苦戦した

# はじめに
AWS学習の過程でEC2インスタンスにターミナルからアクセスするのに苦戦したので解決するまで記事に残します。

# `.ssh`フォルダがない
pemファイルをsshフォルダに移動しようと`mv ~/Downloads/[ファイル名].pem ~/.ssh`を実行すると以下のエラーになった
```zsh
zsh: no such user or named directory: .
```

### 解決方法
単純に`.ssh`フォルダを作成してあげることで解決

```zsh
mkdir ~/.ssh
```

再度`mv ~/Downloads/[ファイル名].pem ~/.ssh`を実行すると移動できた


# `Permission denied (publickey,gssapi-keyex,gssapi-with-mic).`のエラー
`chmod`で権限変更が完了し、いざEC2にアクセスしようと`ssh`コマンドを実行すると以下エラーが発生
```zsh
Warning: Identity file /Users/[ユーザー名]/.ssh/[ファイル名].pe, not accessible: No such file or directory.
ec2-user@[パブリックIPアドレス]: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
```

色々エラー解決を試行錯誤していると単純にpemファイルの拡張子が`.pem`ではなく`.pe,`になっていたことが原因と判明
原因のコマンド: `ssh -i ~/.ssh/sample.pe, ec2-user@[パブリックIPアドレス]`

正しく直してSSHアクセスすると

```zsh

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
```

無事にアクセス出来た
dockerで分析環境を作る

## 目的
dockerを使って、ローカル環境を極力汚さずに分析できる環境を作る。

## コンテナの作成
```dockerfile
FROM jupyter/datascience-notebook
USER root

# 追加ライブラリをインストール
RUN pip install --upgrade pip && \
    pip install --no-cache-dir \
    torch \
    torch-geometric \
    gpy \
    gpyopt \
    streamlit \
    plotly

CMD /bin/bash
```

```docker-compose.yml
version: "3"
services:
  datascience-notebook:
    container_name: container-pyai
    build: .
    volumes:
      - ./work:/home/jovyan/work
    ports:
      - 9999:8888
    restart: always
    command: start-notebook.sh
```

作業ディレクトリ直下の`/work`ディレクトリをコンテナ内の`/home/jovyan/work`と共有している。
`docker-compose up -d --build`でビルド＆起動。


## 使用方法
３つの使い方が可能。

- JUPYTERLABで実行する場合
`docker logs pyai-container`コマンドでトークン名を確認する。
`http://localhost:9999/lab?token={トークン名}`にブラウザからアクセス。

- VSCodeのJUPYTER NOTEBOOKで実行する場合
ctrl+shift+pより'specify jupyter server for connection'を開く。
existingに`http://localhost:9999/lab?token={トークン名}`を入力。
インタプリタをコンテナ内部のpython(/opt/conda/bin/python)に変更しておく。

- コンテナにアタッチして実行する場合
remote developmentを用いて、作成したコンテナにアタッチする。
.ipynbだけでなく、.pyファイルをデバッグすることも可能。
[Python3] 多重継承 Mixinについて

メモ:
 Pythonの多重継承において、super().__init__()とすると、classを定義するときに一番左に書いた引数のclassの__init__()が呼ばれる。
```python:test_mixin01.py 
class Father:
  def __init__(self):
    self.param="messages from father"
  def print_messages(self):
    print(self.param)

class Mother:
  def __init__(self):
    self.param="messages from mother"
  def print_messages(self):
    print(self.param)

class Son(Father, Mother): #see this line
  def __init__(self):
    super().__init__()
    self.print_messages()

class Daughter(Mother, Father): # see this line
  def __init__(self):
    super().__init__()
    self.print_messages()

def main():
  son=Son()
  daughter=Daughter()

if __name__ == "__main__":
  main()
```
実行結果はこちら
```shell
% python test_mixin01.py 
messages from father
messages from mother
```
より詳しくみるために、4つの親を持つclass Kidsを動かしてみる。
```python:test_mixin03.py 
class Father:
  def __init__(self):
    self.param="messages from father"
  def print_messages(self):
    print(self.param)

class Mother:
  def __init__(self):
    self.param="messages from mother"
  def print_messages(self):
    print(self.param)

class GrandFather:
  def __init__(self):
    self.param="messages from grand father"
  def print_messages(self):
    print(self.param)

class GrandMother:
  def __init__(self):
    self.param="messages from grand mother"
  def print_messages(self):
    print(self.param)

class Kids(Father, Mother, GrandFather, GrandMother): #see this line
  def __init__(self):
    super(Kids, self).__init__() #see this line
    self.print_messages()
    super(Father, self).__init__() #see this line
    self.print_messages()
    super(Mother, self).__init__() #see this line
    self.print_messages()
    super(GrandFather, self).__init__() #see this line
    self.print_messages()

def main():
  kids=Kids()
  print(Kids.mro()) #see this line

if __name__ == "__main__":
  main()
```
結果はこちら、
```sell:
% python test_mixin03.py
messages from father
messages from mother
messages from grand father
messages from grand mother
[<class '__main__.Kids'>, <class '__main__.Father'>, <class '__main__.Mother'>, <class '__main__.GrandFather'>, <class '__main__.GrandMother'>, <class 'object'>]
```
多重継承をするとclassを定義するときの引数の順番でメソッドの解決が行われる。メソッドの解決順序は.mro()で調べることが可能。
上の例だと、

```
Kids -> Father -> Mother -> GrandFather -> GrandMother
```
となる。
例えば、Motherの__init__()を実行したいのであれば、Motherを継承しているFatherをsuper()の引数に指定する。つまり
```python:
super(Father, self).__init__() 
```
とする。
【Swift】NWPathMonitor, NotificationCenterを使って、オフラインのときにアラートを表示する

# はじめに
オンライン・オフラインで起動する画面を条件分岐する処理は実装した経験はあった。
今回、アラートを使って、通信状況をユーザーに伝える機能を実装したので、備忘録として記録。

以下の処理を実装した。
①オンライン, オフラインを`AppDelegate`で監視する
②通信環境が切り替わったら、`ViewController`に`NotificationCenter`を使って、通知を受け取る

# 実装
①オンライン, オフラインを`AppDelegate`で監視する

`NotificationCenter`を使って、オンライン、オフラインを`ViewController`に通知。

``` swift:AppDelegate.swift
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        Network.shared.setUp()
        Router.shared.showRoot(window: UIWindow(frame: UIScreen.main.bounds))
        
        return true
    }
}
```

``` swift:Network.swift
import Network
import Foundation

class Network {
    static let shared: Network = .init()
    private let queue = DispatchQueue(label: "バンドル名(被らなければ何でもOK)")
    private let monitor = NWPathMonitor()
    
    private init() {}
    
    func setUp() {
        monitor.pathUpdateHandler = { path in
            if path.status == .unsatisfied {
                DispatchQueue.main.async {
                    NotificationCenter.default.post(name: .offlineNotifyName, object: nil)
                }
            } else {
                DispatchQueue.main.async {
                    NotificationCenter.default.post(name: .onlineNotifyName, object: nil)
                }
            }
        }
        
        monitor.start(queue: queue)
    }
    
    func isOffline() -> Bool {
        return monitor.currentPath.status == .unsatisfied
    }
}

```

②通信環境が切り替わったら、`ViewController`に`NotificationCenter`を使って、通知する

`NotificationCenter.default.addObserver`でオンライン、オフラインの状態を`AppDelegate`から受け取る
``` swift:ViewController.swift
final class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        NotificationCenter.default.addObserver(
            self,
            selector: #selector(offline),
            name: .offlineNotifyName,
            object: nil
        )
        
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(online),
            name: .onlineNotifyName,
            object: nil
        )
    }
}

@objc private extension ViewController {
    func online() {
       // アラートを閉じる
    }
    
    func offline() {
       // アラートを表示する
    }
}

```

# プレビュー
<img width="200" src="https://gyazo.com/0775da78c1aaf9b7e0844fbe7a87fd3f/raw">

# まとめ
APIを叩く処理を行う前に、ユーザーにアラートを表示すると親切かも

# 参考リンク
[NotificationCenter | Apple Developer Documentation](https://developer.apple.com/documentation/foundation/notificationcenter)
[NWPathMonitor | Apple Developer Documentation](https://developer.apple.com/documentation/network/nwpathmonitor)
[【Swift】NWPathMonitorを使ったネットワーク監視方法について - Qiita](https://qiita.com/kogepan159/items/09478dfa3d3007130297)
[【Swift】NotificationCenterの使い方 - Qiita](https://qiita.com/ryo-ta/items/2b142361996657463e5f)