OmniAICreator/Qiita-1.07M huggingface dataset:
Markdownをいい感じにDeepLで翻訳するツール作った

単なるMarkdown翻訳機としても使えますが、スライド生成ライブラリと組み合わせると極めて強力です。

![Videotogif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232088/3965c4d6-0efc-f0a8-065f-6c1f31f2758d.gif)

※要：DeepL API
※スライド生成は[Marp](https://marp.app/)によるもので、作ったのは中間の翻訳部分です

## リポジトリ

https://github.com/koshian2/MarkdownDeepL

## 仕組み
* DeepL APIで翻訳する
* Markdownを翻訳結果でのマークアップのミススタイリングを、正規表現で置き換え
* 正規表現のルールをユーザーが独自定義可能

[DeepLのAPI](https://support.deepl.com/hc/ja/articles/360021200939-DeepL-API-Free)が使えれば誰でも使えます（無料版でもOK）

## 動機
* 英語のスライド作るのだるすぎた
* Markdownからスライド作れるライブラリがあるのを知った
    + でもWeb版のDeepLは微妙にマークアップの翻訳ミスってめんどい
    + ミスった部分はルールベースで微調整できそう（カスタム正規表現）
* Markdown用のDeepLライブラリがなかったから、フロントエンドソフト作った

### Web版のDeepLのつらいとこ
![img02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232088/cd7a1a64-3d2a-cc7a-c831-c7993a7dc48d.png)

* 画像挿入の「![」に微妙な隙間ができる
* コードブロックのバッククオートの文字数が違う
* 1回に5000文字以上翻訳できない

## 作った結果
100ページあるスライドだろうが一瞬で翻訳できました。楽チン😃

ただ太字は微妙にミスる場合あるんで手動調整が必要です。表は一切考えていません（知らね）。

リポジトリメンテする気そんなにないんで、フォークするなりしてご自由にカスタマイズしてください。

## 実装
* Python
    + Eel
    + DeepL
* フロントエンド部分はあまりに単純だったのでPureScript
物体検出ボックスを可視化する　iOSでバウンディングボックスを画像に描画

# iOSでのビジュアライズ方法です。

UIImageに直接描画します。

![IMG_2262.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/4cdb15d4-7b30-080b-7ec5-f507d085f6af.jpeg)

box、label、confidence、boxのcolorを持つstructで結果をラップしているとします。

```swift
struct Detection {
    let box:CGRect
    let confidence:Float
    let label:String?
    let color:UIColor
}

// 検出に使った画像と検出結果のDetctionのコレクションを入力として、ボックスが描画された画像を返します。

func drawDetectionsOnImage(_ detections: [Detection], _ image: UIImage) -> UIImage? {
    let imageSize = image.size
    let scale: CGFloat = 0.0
    UIGraphicsBeginImageContextWithOptions(imageSize, false, scale)

    image.draw(at: CGPoint.zero)
    let ctx = UIGraphicsGetCurrentContext()
    var rects:[CGRect] = []
    for detection in detections {
        rects.append(detection.box)
        if let labelText = detection.label {
        let text = "\(labelText) : \(round(detection.confidence*100))"
            let textRect  = CGRect(x: detection.box.minX + imageSize.width * 0.01, y: detection.box.minY + imageSize.width * 0.01, width: detection.box.width, height: detection.box.height)
                    
        let textStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
                    
        let textFontAttributes = [
            NSAttributedString.Key.font: UIFont.systemFont(ofSize: textRect.width * 0.1, weight: .bold),
            NSAttributedString.Key.foregroundColor: detection.color,
            NSAttributedString.Key.paragraphStyle: textStyle
        ]
                    
        text.draw(in: textRect, withAttributes: textFontAttributes)
        ctx?.addRect(detection.box)
        ctx?.setStrokeColor(detection.color.cgColor)
        ctx?.setLineWidth(9.0)
        ctx?.strokePath()
        }
    }

    guard let drawnImage = UIGraphicsGetImageFromCurrentImageContext() else {
        fatalError()
    }

    UIGraphicsEndImageContext()
    return drawnImage
}
```

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

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

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
[GitHub](https://github.com/john-rocky)
Gitの初期設定の備忘録

## 名前とメールアドレスを登録する

```
$ git config --global user.name "FirstName ListName"
$ git config --global user.email "your_email@gmail.com"
```

下記のコマンドで設定を確認できる

```
$ cat ~/.gitconfig
```

## コマンドの出力を読みやすくする

```
$ git config --global color.ui auto
```

## SSH　Keyの設定

```
$ ssh-keygen -t rsa -C "your_email@gmail.com"
```
いくつか質問されるが全てenterでOK！

## 公開鍵をGithubに登録する

下記のコマンドで公開鍵をコピペしておく。

```
$ cat ~/.ssh/id_rsa.pub
```

「add deploy key」からキーを登録する。Keyに公開鍵をコピペする。Add keyする。
![スクリーンショット 2022-04-02 23.20.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360790/c0566339-c05f-2265-222b-d77824c97f1a.png)

![スクリーンショット 2022-04-02 23.23.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360790/4682fc3c-c51f-b8ff-141a-12200226372a.png)

## 確認

下記のように表示されればOK

```
$ ssh -T git@github.com
Hi! You've successfully authenticated, but GitHub does not provide shell access.
```
インフラエンジニア基礎入門 #2

前回(https://qiita.com/toriten17/items/44e90ab703b2499f4065)
に続き、ウズウズカレッジさんが出しているインフラエンジニア基礎の動画を視聴したので、その内容をまとめてみました。
↓動画のリンク
https://www.youtube.com/watch?v=5QHXbxZIUDg&list=PLXXalsdlzX-J7AUuw2zSHit5nRUZ3eDdz&index=4


###### プロトコル
通信におけるルール　送信側、受信側で同一のプロトコルでなければデータの疎通がうまくいかない

###### プロトコルスタック/ネットワークアーキテクチャ/プロトコルスイート
通信における様々なプロトコルを役割ごとにまとめたもの

昔は各メーカのプロトコルスタックは互換性がなく、ネットワークを構築するには同一メーカのPCでそろえるしかなかった

### OSI参照モデル(Open Systems Interconnnection)
異なる機種間でも通信できる世界標準のプロトコルスタック　
ISO(International Organization for Standardization)によって策定

###### 通信にまつわるすべてのプロトコルを7レイヤ(階層)に分解
L(Layer)7　アプリケーション層　 アプリケーション固有のルール
L6　プレゼンテーション層　　ユーザが見て触れるデータのルール
L5　セッション層　アプリケーション間の接続のルール
L4　トランスポート層　通信信頼性に関するルール
L3　ネットワーク層　エンドツーエンドの通信に関するルール
L2　データリンク層　隣接ノード間に通信に関するルール
L1　物理層　機器や電気信号に関するルール　

メリット：各プロトコルの役割が明確になり、変更があっても最小限のプロトコルの変更で済む　

### 各レイヤの詳細情報
###### L1　物理層　機器や電気信号に関するルール
ケーブルの長さや種類
電圧レベル、電圧変化に関するルール
通信速度、電気信号の符号化に関するルール

###### L2　データリンク層　隣接ノード間に通信に関するルール
データの送信も通信元、宛先の識別方法(物理アドレス)
データの衝突の検知や回避に関するルール
創出するためのデータ加工に関するルール

###### L3　ネットワーク層　エンドツーエンドの通信に関するルール
データの送信も通信元、宛先の識別方法(論理アドレス)
経路選択の方法、データ送出方法に関するルール

###### L4　トランスポート層　通信信頼性に関するルール
確実な伝送orスピードどちらを優先するか
異常があったときの対処、送信量の調節に関するルール

###### L5　セッション層　アプリケーション間の接続のルール
2者間の接続開始から終了までのルール
接続維持や回復、接続情報の管理に関するルール

###### L6　プレゼンテーション層　　ユーザが見て触れるデータのルール
文字コード、画像、動画に関するルール
データの圧縮や暗号化に関するルール

###### L7　アプリケーション層　 アプリケーション固有のルール
電子メールの送受信に関するルール
メールサーバの利用に関するルール
添付ファイルの送信に関するルール

送信データは高レイヤから低レイヤへと順に処理され
受信データは低レイヤから高レイヤへと順に処理される

### カプセル化/非カプセル化
###### ヘッダ
送信データを各レイヤで処理していくときに付加する制御情報
###### トレーラ
データリンク層でヘッダに加えて付加するエラーチェック用の情報
###### カプセル化
送信データを作るためにレイヤごとにヘッダを付加していく処理
###### 非カプセル化
受信データを各レイヤで付加されたヘッダを外す処理

### PDU(Protocol Data Unit)
データ＋ヘッダのデータ単位
どのレイヤのヘッダが付加されているかで呼び名が変わる
フレーム(L2：データリンク層)
バケット(L3ネットワーク層)
セグメント(L4：トランスポート層)
WSL2 で vhdx をマウントする方法

2022/04/02現在

vhdx は WSL2 のストレージとして使われているディスクイメージ形式。WSL2 の内容物をバックアップ取りたいときはファイルコピーしておけばいい。

https://docs.microsoft.com/ja-jp/windows/wsl/wsl2-mount-disk にマウント方法が書いてある。しかし vhdx ファイルをマウントするにはひと手間必要。

> Microsoft Store から入手した WSL には、VHD を直接マウントする新しい引数 wsl --mount --vhd <pathToVHD> が含まれます。

上記にあるように、Microsoft Store から入手した WSL でないと vhdx をマウントできない。

詳しくはこちらに Changes Log がある。 https://devblogs.microsoft.com/commandline/a-preview-of-wsl-in-the-microsoft-store-is-now-available/

WSL2 はコマンドラインからインストールしたものと、 Microsoft Store からインストールされたものどちらも共存する。 Windows Terminal などで実行する `wsl` コマンドは Microsoft Store のものが優先される。

次のように実行すると wsl2 内部からマウントされた ボリュームが参照できる

`wsl --mount --vhd "D:\\Downloads\\ext4.vhdx"`

エラーが出る場合は、ディストリビューションのデフォルトが指定されていない可能性があるため、 `-d` でディストリビューション名を指定すること。
Node.js実行時間を測る



# 手軽に計測
```javascript:node.js

// 開始
var start = performance.now();

for(var i = 0; i < 10000; i++){
  for(var j = 0; j < 10000; j++);
}

// 終了
var end = performance.now();

console.log( `実行時間 = ${end - start} ミリ秒` );

```
機械学習の習得に向けた日記


<h1>教養数学(微分積分学・統計学・線形代数)</h1>

2022年2月20日<a href="https://www.google.co.jp/books/edition/%E7%B5%B1%E8%A8%88%E3%81%AE%E6%AD%B4%E5%8F%B2/HGKPzQEACAAJ?hl=ja">『統計の歴史』</a>
>題名通り統計を歴史という切り口で説明する本です。。統計が組織や個人にとってどのような立ち位置で発展してきたか知るために読みました。
>>「数字で表現できない知識は貧弱で不十分で、科学的な思考手順を踏んでいない。」ウィリアムトムソン

2022年4月2日<a  href="https://www.google.co.jp/books/edition/%E6%95%B0%E5%AD%A6%E5%85%AC%E5%BC%8F%E3%81%AE%E3%81%AF%E3%81%AA%E3%81%97/9056zQEACAAJ?hl=ja">『数学公式のはなし』</a>





<h1>機械学習Pythonモジュール</h1>
  <h2>Numpy/Scipy/</h2>
<a href="https://www.google.co.jp/books/edition/%E6%9D%B1%E4%BA%AC%E5%A4%A7%E5%AD%A6%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%A8%E3%83%B3%E3%83%86/ksGlDwAAQBAJ?hl=ja&gbpv=0">『東京大学のデータサイエンティスト育成講座』</a>
  <h2>Django</h2>
2022年4月3日チュートリアル進める
月別記事一覧と、投稿数表示機能

# 目次
[1.月別集計](#1-月別集計)
[2.月別ページ表示](#2-月別ページ表示)

Laravelを使ったブログサイト作成で、月別記事一覧と投稿数を表示させる機能を作ったのでアウトプット記事書いてみます。
***

**↓ 最終目標はこんな感じです**
![スクリーンショット 2022-04-02 17.39.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2077017/bbcd94e8-d3c7-ddd1-ac0c-6fcd635d980a.png)


# 1. 月別集計

流れとしては、公開中の記事から指定した年の記事を取得し、月別取得＆投稿数取得。
あとは blade側で @foreach を使って月と投稿数を表示させていく感じです！

**`where('is_published', 1)` を書かないと非公開記事まで表示されてしまうので注意です！**



```php:PostController.php
    public function index(): View
    {
        ...省略
    
        $year = date('Y');
        $monthPosts = $this->Post->findMonthPostCount($year);

        return view(
            'posts.index',
            [
                'year' => $year,
                'monthPosts' => $monthPosts,
            ]
        );
    }
```

```php:Post.php
public function findMonthPostCount($year): Collection
    {
        return Post::where('is_published', 1)
            ->whereYear('created_at', $year)
            ->orderBy('created_at')
            ->get()
            ->groupBy(function ($row) {
                return $row->created_at->format('m'); //月別取得
            })
            ->map(function ($day) {
                return $day->count(); //投稿数取得
            });
    }
```

```php:index.blade.php
...省略

<h1 class="month-title">月別記事</h1>
<button class="button">{{$year}}</button>
<div class="card-month">
@foreach($monthPosts as $month => $count)
<li class="li-month">
    <a href="{{ route('posts.month', [$year, $month]) }}">
        {{$year}}/{{ $month }} ({{$count}})
    </a>
</li>
@endforeach
```


これを表示させてみると、こんな感じです！
投稿がある月だけ表示されるのでとても見やすいと思います！

![スクリーンショット 2022-04-02 19.01.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2077017/ecf1bdbd-2042-6c6d-6895-f5f192244c56.png)

例えば、追加で5月の記事を投稿してみた場合、
![スクリーンショット 2022-04-02 19.14.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2077017/895e882c-55db-fe3b-0f24-800c8d87cf3c.png)

こんな感じで5月の記事が追加されます！

**そのまま URL になっているのでクリックで月別記事一覧に飛べます！**

```php5
<a href="{{ route('posts.month', [$year, $month]) }}">
    {{$year}}/{{ $month }} ({{$count}})
</a>
```

# 2. 月別ページ表示

**月別ページの表示は、
`$year` `$month` を引数で渡してあげて指定した月を取得すればOKです！**


```php:PostController.php
public function month(Request $request): View
    {
        $year = $request->year;
        $month = $request->month;
        $posts = $this->Post->findByCreated($year, $month);

        return view(
            'posts.month',
            [
                'year' => $year,
                'month' => $month,
                'posts' => $posts,
            ]
        );
    }
```

```php:Post.php
public function findByCreated(string $year, string $month): LengthAwarePaginator
    {
        $posts = Post::where('is_published', 1)
        ->whereYear('created_at',  $year)
        ->whereMonth('created_at', $month)
        ->latest()->paginate(9);

        $posts->load('user', 'tags', 'images');
        return $posts;
    }
```

完成です！

view 側は、
**`<div id="blog-top"> {{$year}}年 {{$month}}月 の記事一覧</div>`**
みたいな感じにすると年月に対応した表示になるのでわかりやすいと思います！


月別記事一覧は、投稿数が多いブログだと必要になってくると思うのでぜひ参考にしてみてください〜！
Dartについて学んでみる⑤

## 非同期処理とは?
Flutterでfirebaseに接続するときににこんな書き方をみたことがあった!
**cloud_firestoreのExample**

```dart
Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(options: DefaultFirebaseConfig.platformOptions);

  if (shouldUseFirestoreEmulator) {
    FirebaseFirestore.instance.useFirestoreEmulator('localhost', 8080);
  }
  runApp(FirestoreExampleApp());
}
```

あれれ、いつもの書き方と違うぞ!!!
```dart
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}
```
またまた、Dartの文法への理解不足で悩まされたので、解決して行くために非同期処理について学んでいく。

**Future型とは?**
公式ドキュメント
https://api.dart.dev/stable/2.16.1/dart-async/Future-class.html
こちらは、日本語のわかりやすい記事
https://flutternyumon.com/how-to-use-future/

## そもそも非同期処理とは?
ネットワークを利用するプログラミングで問題になるのはHTTPリクエストやファイルI/Oに伴うオーバーヘッドです。

**I/O**
I/Oとは、Input/Outputの略で「入出力」を意味しています。 コンピュータは情報を入力（Input）し、計算結果を出力（Output）するという処理を行なっていますが、これらの処理を総称してI/Oと呼んでいます。

**オーバーヘッド**
ITの分野では、コンピュータで何らかの処理を行う際に、その処理を行うために必要となる付加的、間接的な処理や手続きのことや、そのために機器やシステムへかかる負荷、余分に費やされる処理時間などのことをオーバーヘッドということが多い。通信の分野でも、送りたいデータや信号そのものとは別に付加的に必要となる制御用のデータなどのことや、それを処理、伝送するために余計にかかる負荷や時間のことをオーバーヘッドという。

これはメモリやCPUの性能では解決することのできないパフォーマンスの問題を引き起こすことがあります。
Dartはこれを容易に解決することのできる非同期処理のメソッドが用意されています。
これを利用するために**async**モジュールをインポートします。

```dart
import 'dart:async';
```

## async/awaitとは
asyncとawaitというプレフィックスは通常ペアとして使用されます。awaitというプレフィックスを非同期処理を行う関数の前に置くことで、その関数の実行結果が返ってくるまで、関数の実行を一時停止することができます。
**await**を使用することができるのは、**async**という識別子を置いた関数の中のみです。
asyncをつけた関数の戻り値はFuture型です。このオブジェクトは値が将来時点で返ってくることを示しています。

## コードを書きながら理解していこう。
```dart
import 'dart:async';

int hoge() {
  return 1;
}

Future main() async {
  var b = await hoge();
  print(b);
}
```
実行結果
```
1
```

また、awaitを使用した非同期処理関数のエラーを処理するには**try-catch構文**を使用します。

このサンプルだと例外処理を発生させることはできませんでした。
```dart
import 'dart:async';

int hoge() {
  return 1;
}

Future main() async {
  try {
    var b = await hoge();
    print(b);
  } catch (e) {
    print(e);
  }
}
```

複数のawaitを使用することで、複数の非同期処理関数を順番に実行することができます。
```dart
import 'dart:async';

int hoge() {
  return 1;
}

int fuga() {
  return 2;
}

Future main() async {
    var b = await hoge();
    var c = await fuga();
    print(b);
    print(c);
}
```
実行結果
```dart
1
2
```

**自分で非同期処理を考えてみた**
```dart
import 'dart:async';

class Person {
  int? futureNum;
  String? futureName;

  static Future<void> future1(futureNum) async {
    await futureNum;
    print(futureNum);
  }

  static Future<String> future2(futureName) async {
  // 3秒後に処理が実行されるようにするメソッド
    await Future.delayed(Duration(seconds: 3));
    return futureName;
  }
}

Future main() async {
  await Person.future1(4);
  final getName = await Person.future2("Jboy");
  print("3秒後に非同期処理が走る: $getNameさんいたよ!");
}
```
実行結果
```dart
4
3秒後に非同期処理が走る: Jboyさんいたよ!
```

## やってみた感想
非同期処理が完了した際に結果を返すのは「Future<T>」、処理だけ実行するのは「Future<void>」です。
とリンクを貼った日本語のサイトで解説されていた。

恐らく非同期処理理解できた😅
これで、これからソースコードが読めるようになる???
Unity 回転とスケールだけを用いたShear(せん断)の実装

# Shearとは
Shear(せん断・剪断・シアー・スキュー・skew)とはアフィン変換の一種で、下の様にある軸にそって引き伸ばす変換です。
![画面収録 2022-04-02 22.38.51.mov.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323576/9e127dfc-5b93-56b3-dbb1-8451b9daab00.gif)

しかし残念ながら、UnityにはShearを行う機能はありません。
ただ実は回転とスケールの合成だけでShear変換を作ることができるので、代わりにこれで実装します。

# Shear変換行列の分解
実装の前に行列ではどのように表現されるのかみてみましょう。

Shearは次の変換行列で表される変換です。
```math
\begin{pmatrix}
1 & x \\
0 & 1 \\
\end{pmatrix}
```
唐突ですが、$x$を次のように表します。
```math
x = \frac{1}{\tan \theta}
```
すると、Shearは次のように回転行列と対角行列の積に分解できることが知られています。
（この導出は調べた限り分かりませんでした…ご存知の方は教えてください）
```math
\begin{pmatrix}
1 & \frac{1}{\tan\theta} \\
0 & 1 \\
\end{pmatrix} =
\begin{pmatrix}
\frac{\sqrt2}{\sin\theta} & 0 \\
0 & \sqrt2 
\end{pmatrix}
\begin{pmatrix}
\cos -45 ^\circ & -\sin -45 ^\circ \\
\sin -45 ^\circ & \cos -45 ^\circ
\end{pmatrix}
\begin{pmatrix}
\sin\frac{\theta}{2} & 0 \\
0 & \cos\frac{\theta}{2}
\end{pmatrix}
\begin{pmatrix}
\cos\frac{\theta}{2}  & -\sin\frac{\theta}{2} \\
\sin\frac{\theta}{2} & \cos\frac{\theta}{2}
\end{pmatrix}
```
これはつまり、単純な回転とスケールだけでShearを行えることを意味しています。
また、
```math
\phi = 90 ^\circ - \theta
```
とおくことで
```math
\begin{pmatrix}
1 & \tan\phi \\
0 & 1 \\
\end{pmatrix}
=
\begin{pmatrix}
\frac{\sqrt2}{\sin90^\circ - \phi} & 0 \\
0 & \sqrt2 
\end{pmatrix}
\begin{pmatrix}
\cos -45 ^\circ & -\sin -45 ^\circ \\
\sin -45 ^\circ & \cos -45 ^\circ
\end{pmatrix}
\begin{pmatrix}
\sin\frac{90^\circ - \phi}{2} & 0 \\
0 & \cos\frac{90^\circ - \phi}{2}
\end{pmatrix}
\begin{pmatrix}
\cos\frac{90^\circ - \phi}{2}  & -\sin\frac{90^\circ - \phi}{2} \\
\sin\frac{90^\circ - \phi}{2} & \cos\frac{90^\circ - \phi}{2}
\end{pmatrix}\tag{1}

```
と表すこともできます。
# Unityでの実装
(1)の変換をコードに落とし込んでいきましょう。
次のようなコンポーネントを作ります。
```csharp
using UnityEngine;

[ExecuteAlways]
public class Shear : MonoBehaviour
{
    [Range(-90, 90)] public float phi = 30f;
    private void OnValidate()
    {
        // z軸回りにShearさせる
        float angle = 90 - phi;

        // 一つのTransformでは、Scale→Rotationの順に適用されることに注意
        transform.localRotation = Quaternion.Euler(0, 0, angle / 2);
        transform.parent.localScale = new Vector3(Mathf.Sin(angle * Mathf.Deg2Rad / 2), Mathf.Cos(angle * Mathf.Deg2Rad / 2), 1);
        transform.parent.localRotation = Quaternion.Euler(0, 0, -45);
        transform.parent.parent.localScale = new Vector3(Mathf.Sqrt(2) / Mathf.Sin(angle * Mathf.Deg2Rad), Mathf.Sqrt(2), 1);
    }
}
```
これをShear対象のオブジェクトにアタッチし、親として２つEmptyオブジェクトを設定します。
その状態でスライダーを動かすとShearすることがわかります。
![画面収録 2022-04-02 22.38.00.mov.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323576/2e8e9c73-1d7a-0071-9ea9-70fbe00b88a9.gif)

### 参考
https://www.cs.cmu.edu/~fp/courses/02-graphics/asst2/solution/asst2-sol.pdf
https://answers.unity.com/questions/961330/shear-transformation-using-gameobject-transformati.html
https://ja.wikipedia.org/wiki/%E4%B8%89%E8%A7%92%E9%96%A2%E6%95%B0
キーボーddddddddddッドを壊してみた

# ddddddddddっ導入
「キーボーddddddddddッドが壊れた」とは、2016年07月15日に、「2ちゃんねる」という日本再ｄｄｄｄｄｄｄｄｄｄっ大級のｄｄｄｄｄｄｄｄｄｄっ電子掲示板サイトに投稿されたスレｄｄｄｄｄｄｄｄｄｄｄｄｄｄｄｄｄｄｄｄｄｄッドの一つｄｄｄｄｄｄｄｄｄｄっです。

そのスレｄｄｄｄｄｄｄｄｄｄｄｄｄｄｄｄｄｄｄｄｄｄッドについては下のｄｄｄｄｄｄｄｄｄｄっ動画ｄｄｄｄｄｄｄｄｄｄっで詳しく説明されていますのｄｄｄｄｄｄｄｄｄｄっで、ご存じない方はぜひ一ｄｄｄｄｄｄｄｄｄｄっ度ご覧くｄｄｄｄｄｄｄｄｄｄっださい。

<iframe width="560" height="315" src="https://www.youtube.com/embed/dqC494zrH3E" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

# 完成品
（流石に飽きてきたと思うので元に戻します。）

https://www.vector.co.jp/soft/winnt/amuse/se524243.html

Readme.txtの書き方については[こちら](http://www.isonly.net/~yuk_yt/himawari/help/0043.html)のサイトを参考にさせていただきました。

## 使い方
「キーボーddddddddddッドが壊れた.exe」をダブルクリックして実行するだけです。
Windows Defenderに止められるかもしれませんが、悪いことはしていないので大丈夫です。
![スクリーンショット 2022-04-02 215113.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644120/1822b644-e259-5d23-f784-04134c55a2be.png)
タスクトレイに常駐するので、不要になったときは右クリックから終了できます。
![スクリーンショット 2022-04-02 215037.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644120/47f97349-83fb-f3ee-4a5a-6ac47bc6c885.png)

## 使用中の様子
なかなかに酷いです。スレ主さんの状況を再現できたのではないでしょうか。
![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/644120/f72812f3-68ae-b950-f116-9ada7ef2d10f.gif)

# ソースコード

このプログラムは実行中、キー入力を監視します。Dキーのキーダウンイベントが発生したらそのイベントをキャンセルして、代わりにDキーを12回キーダウンさせます。12回という定数はスレタイから特定しました。
[こちら](https://qiita.com/okuhiiro/items/ab768819fe47c0ebba78)記事を参考に（ほぼコピペ）させていただきました。


```c#
// ---------- キー入力をするところのみ抜粋 ---------- //

bool preve = false; // 無限ループ防止用変数

int HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
    switch ((int)wParam)
    {
        case 256: // キーダウンイベントの場合
            short keyCode = (short)Marshal.ReadInt32(lParam); // キーコードを取得
            if (keyCode == 68 & !preve) // Dキー（キーコード68）なら
            {
                preve = true; // 無限ループ防止
                for (int i = 0; i < 12; i++) // 12回繰り返す
                {
                    Thread.Sleep(1); // 1ms待つ（リアル感を出すため）
                    keyInput.Input(keyCode); // Dキーをダウン
                }
                preve = false;
                return 1; // キーイベントをキャンセル
            } else
            {
                break;
            }
    }
    return 0; // その他のキーなら何もせずスルー
}
```


[GitHub](https://github.com/GOUKUN5160/Keyboardddddddddddd-broke)に公開しました。不要なコードなどがありましたら、どなたかアドバイスいただけると幸いです。

# あとがき

スレ主さんは、悪意（笑）のある誰かが作ったこのようなクソアプリを、知らず知らずのうちにダウンロードしてしまっていたのかもしれませんね。


>参考にさせていただいたサイト様
>・[タスクトレイに常駐について](https://www.fenet.jp/dotnet/column/environment/4527/)
>・[キーフックについて](https://qiita.com/okuhiiro/items/ab768819fe47c0ebba78)
Pythonの判定(排他的論理和)

# pythonでの排他的論理和の判定
例えば、入力チェックをする際に、両方値が入っているもしくは、入っていない場合は不可で、
どちらか一方のみ値が入力されている状態を正とする場合のチェック処理

```python: xor.py
# 入力データ(判定対象のデータ)
# data = {
#   "data1": "",
#   "data2": "test"
#}

# boolでキャスト(しなくてもよいが明示的にしてみた)
if bool(data["data1"]) != bool(data["data2"]):
    print("排他的")
```

上記のように!=を使えば排他的論理和の確認ができる。
高速 scatter plot 描画（apache-arrow + regl 利用）

こんにちは。
apache-arrow (IPC) データをプロットしました[^1]。データ (columnar typed array) を取得しそのまま [regl](https://github.com/regl-project/regl) の WebGL バッファーへ書き込むことにより高速描画を行なっています。

[^1]: 参考：[Efficiently loading massive D3 datasets using Apache Arrow](https://blog.scottlogic.com/2021/10/15/efficiently-loading-massive-d3-datasets-using-apache-arrow.html) (Chris Price, scottlogic.com)

この例のデータの取得（ダウンロード）進行中は、データは逐次分割されて取得され（10,000行単位）、その都度、データを追加して描画しています（ストリーム型処理）。

ただし、データの取得自体はネットワークを通したダウンロードなので高速ではありません[^2] [^3]。

[^2]: したがって、この例のような大量データの場合（68 万点の scatter plot）、ダウンロードに通常は 1 秒弱を要すようで、開始後一瞬で全データを描画完了とはいきません。
[^3]: 同じデータをローカルファイルとして読み込むと、開始後ほぼ一瞬で全データを描画完了できます。

![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54617/3c2b2d3e-9092-b221-702d-e76044e6e123.gif)

ソースおよび実行例はこちら、
- [regl + apache-arrow: fast WebGL scatter plot](https://bl.ocks.org/kkdd/d62a49ada1bcf61af29a3680297ffc97) (bl.ocks.org)
Amazon Direct Connectの基本情報

※本記事はあまりネットワークに詳しくない人向けとなります。


# Amazon Direct Connectとは？

AWSはこのDirect ConnectやVPNを使わない場合は、
外部からの接続は、基本的にインターネットでの接続が必要になります。

ただし、会社の業務システムなどをインターネット接続による
どこの誰でも(部外者でも)使える状態になるのはマズイ状態ですよね？

そんなときのために、会社とAWSネットワークを相思相愛で接続していて、
関係者以外、誰にも恋路を邪魔されない接続を実現する方法の一つです。

つまり、閉域網でAWSネットワークと接続するためのサービスです。
VPNよりお金はかかりますがその分、
セキュリティ面での強さ、安定性などがあります。

説明のための図を作成しました。
※以下はファンタジーとなります。

あなたは"恋人のAWSちゃん"と付き合っていることとします。(AWS君でも可)
ただ"AWSちゃん"と会おうと外に出ると、人が混雑しているため、時間がかかってしまうこともあります。
また、あなたと"AWSちゃん"との関係も週刊誌に狙われているかもしれません。

 ![無題のプレゼンテーション.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257355/a511bbec-6519-8c1c-a919-e8a3e1c2c34c.png)他の人には見えない
ということで二人は、玄関から外に出ずに会える方法はないか考えました。
二人の家には2階に窓があり、これを撤廃して、他の人には見えない扉を作成し、
![無題のプレゼンテーション (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257355/4cd88f32-9f40-82b1-3f13-9b7ae3e6df8c.png)

二人の家をつなぐ、他の人には見えない長い長い廊下を作成しました。

![無題のプレゼンテーション (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257355/cb76afc6-8984-99bc-9662-ae1d511b6289.png)


これをDirect Connectと名付けました。
二人は人混みを避けて、誰にもバレることなく会えるようになりました。
めでたしめでたし。

この図のように、このDirectConnectを利用できるのは家の住人だけなので、セキュリティも高く、
利用者も限られているので、回線の安定性があることが一番の魅力となります。


# 接続形態の種類

接続形態には、専有型と共有型というのが存在します。
回線1本まるまる借りるのを専有型
回線の1部を借りるのが共有型
となります。



例えるなれば、
マンション**1棟**の所有者があなたの場合は、**専有型**
マンション**1室**の所有者があなたの場合は、**共有型**となります。

マンション1棟の所有者であれば、空いている部屋を人に貸すことができますが、
マンション1室の所有権しかなければ、そんな好き勝手できない
そんなイメージです。

接続できればなんでもいいというのであれば、あまり気にしなくて大丈夫ですし、
どちらかというと共有型を利用している方が多く感じております。

またマネジメントコンソールでの専有型か共有型かを確認する方法は、
**接続**が存在するかどうかで確認出来ます。

**接続**が存在している場合は、専有型

**接続**がなく、**仮想インターフェイス**が存在する場合は、共有型となります。

# AWS側の受け口

DirectConnectの受け口として、AWSでは2つ存在しています。
1つが、VGW(VirtualGateway)です。
もう1つが、DXGW(DirectConnectGateway)です。

違いを簡単に言うと、DXGWを挟むのか挟まないのかの話となります。

受け口がVGWの場合、
DirectConnect　→ VGW 

になるのに対してDXGWの場合、
DirectConnect →　DXGW　→　VGW

となるため、最終的な受け口はVGWになるのは共通となります。

ここはAWSではDXGWの利用が推奨されています。
理由は、拡張性が優れているためです。

例えば、Aというアカウントで利用しているDirectConnectを
他のBというアカウントでも共有して使いたいとなった場合、
DXGWでは可能ですが、VGWでは不可能になってしまいます。

また基本的に受け口の変更は後からできないため、
専有型であれば、ダウンタイムが発生してしまいますが、
一度削除したあと、再作成が自分でできたりしますが、

共有型であれば、自分で設定ができないため、
諦めるかDirectConnectを提供していただいている業者にお願いするかになります。
※こちらの場合もダウンタイムが発生します。

そのため、受け口の選択は最初しかできないと思っていたほうがよいため、
この辺も考慮して、検討した上での選択をしたほうがよいです。

私も受け口をVGWにして、後から他のアカウントで利用したいと言われて困ってしまった経験があります・・・・


# 最後に

DirectConnectは、EC2のようにお気楽に個人で利用(契約)できるような代物ではないため、
そういった人たちにも伝えられる情報があれば、今後もアップデートしていきたいと思います。

もっと細かい情報に関しましては、AWSのBlackbeltにて確認していただければと思います。

https://www.youtube.com/watch?v=mEtluVrgXlk
ロックファイル とは

## 勉強前イメージ

プロセスが二重起動しないように置いておく空ファイルみたいなもん？

## 調査

### ロックファイル とは

ファイルの操作で同時に処理してしまわないようファイルをロックするために使用するものです。
複数のプロセスが1つのファイルに対して同時に書き込みを行うと整合性が取れなくなってしまうので
誰かがファイルに書き込みを行っている間は書き込まれないようにロックをします。
そこで使用されるのがロックファイルです。

ロックファイルが存在すると書き込みが行われていることを意味して、他のプロセスが書き込みを待ちます。
しかし、たまにプロセスが異常終了した際にはロックファイルが残ったままになっているので、削除する必要があります。

### ロックファイルってどこにある？

ロックファイルは `/var/lock` (centos7で確認) にあります。
実際の中身は以下になります。
ファイルの中身は空です。

```
[root@localhost ~]# ls -al /var/lock/
合計 0
drwxr-xr-x  5 root root 120  3月 21 19:19 .
drwxr-xr-x 24 root root 700  3月 22 09:02 ..
-rw-r--r--  1 root root   0  3月 14 19:09 kdump
drwxrwxr-x  2 root lock  40  3月 14 19:09 lockdev
drwx------  2 root root  40  3月 14 19:09 lvm
drwxr-xr-x  2 root root  60  3月 14 19:09 subsys
``` 

## 勉強後イメージ

プロセスじゃなかったのか・・・ファイルか。
ただ結構ロックファイル残ったまま起動しなくなってなんでーってなったこと多いかも。

## 参考

- [/var/lock](https://linuc.org/study/knowledge/522/)
【MEL】MAYA→UnrealEngine　カメラエクスポート


![2022-04-02_21h19_08.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1491962/4bede6cc-7801-d42c-0805-dff118d32d67.gif)

## 手順

手動での方法とUnrealへのインポートは以下のリンクを参照

【メモ】MAYA to UE4(カメラ)
https://zenn.dev/wawon/articles/33aee68c191939

## MELでMAYA内のカメラベイク作業を簡略化

書き出したいカメラを選択後に以下のMELを起動。
BAKE_CAM__(選択したカメラ名)のカメラが作成されるので、fbxでエクスポート

``` mel:CameraBake.mel
// Set StartFrame and EndFrame //
$stFm =`findKeyframe -w first`;
$edFm = `findKeyframe -w last`;

// Cam Select //
string $selectCam[] = `ls -selection`;
string $selectCamShape[] = `listRelatives -shapes $selectCam`;

// Create Cam //
string $bakeCam[] = `camera`;

// Cam Constraint //
parentConstraint  $selectCam $bakeCam[0];

// focal Length copy //
string $selectFocal = $selectCamShape[0] + ".focalLength";
string $bakeFocal = $bakeCam[1] + ".focalLength";

copyKey -time ($stFm+":"+$edFm) $selectCamShape[0];

if (catch(`pasteKey -time ($stFm+":"+$edFm) -option replace $bakeCam[1]`)){
    setAttr $bakeFocal `getAttr $selectFocal`;
} else{
    print "PasteKey";
}

// Bake Cam //
bakeResults -simulation true -t ($stFm+":"+$edFm) $bakeCam[0];

// Delete Constraint //
delete `listRelatives -typ "constraint" $bakeCam[0]`;

// Bake Cam Rename //
string $newName = "BAKE_CAM__" + $selectCam[0];
rename $bakeCam[0] $newName;
```
＜link rel=preload＞について

## preloadとは
先行読み込みをブラウザに指示する機能。
また、Core Web Vitalsの向上やサイトの高速化をすることができるようになる。


href属性でリソースのパスを指定
as属性でリソースの種類を指定

## preloadで先読みできる要素の一覧
| as="" | 備考 |
|:-:|:-:|
| image  | 画像ファイル  |
| embed  | ＜embed＞要素の中に埋め込まれるリソース  |
| object  | ＜object＞要素の中に埋め込まれるリソース  |
| document | ＜frame＞や＜iframe＞に埋め込まれるHTML文書 |
| script  | JavaScriptファイル  |
| audio  | 通常は＜audio＞で使用される音声ファイル  |
| font  | フォントファイル  |
| fetch | ArrayBufferやJSONファイルのような、フェッチまたはXHR要求でアクセスされるリソース |
| style | CSSスタイルシート |
| track | WebVTTファイル |
| worker | JavaScriptウェブワーカーまたは共有ワーカー　|
| video | 通常は＜video＞で使用される動画ファイル　|

## rel="preload"をよく使うコンテンツ
* CSS
~~~html
<link rel="preload" href="stylesheet.css">
~~~
CSSは読み込みが完了するまでレンダリングがブロックっされるのでrel="preload"を使うことでより速くCSSが読み込まれることになり、結果的にレンダリングがブロックされにくくなり、ページスピードが速くなります。

* JavaScript
~~~html
<link rel="preload" href="main.js" as="script">
~~~
CSSと同様にjsファイルも先読みが必要なファイルはrep="preload"が有効です。

~~~html
<script src="script.js" async>
~~~
逆に読み込みがいつでもいいjsはasync属性をつけると非同期読み込みができます。

~~~html
<script src="script" defer>
~~~
defer属性で遅延読み込みもできます。

* フォント
~~~html
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>
~~~
フォントも先読みすることでFOITやFOUTを防ぐことができ、Core Web Vitalsの向上も見込めます。
フォントを指定していない場合、Page Speed Insights の「キーのプリロード」という項目で指摘されます。
フォントの場合はCORSを有効にするためにcrossorigin属性も指定します。

:::note warn
rel="preload"は使い方を間違える逆にページスピードが低下することもあります。
用法・用量を守って正しく使うことが重要となります。
:::


## 参考サイト

https://wk-partners.co.jp/homepage/blog/hpseisaku/htmlcss/preload/


https://developer.mozilla.org/ja/docs/Web/HTML/Link_types/preload

https://blog.gaji.jp/2021/04/28/7185/
Cloud Functions で GmailAPI で メールを送信する方法 [Javascript]

備忘録。

## Google API を用意する

まず

https://qiita.com/hiro_progra0524/items/d13545f7d23daed7b057#1gcpでgmailapiを有効化する

の手順に沿って、認証情報の作成まで行います。途中、「スコープを追加または削除」の部分は readonly ではなく、send を選びます。

次に、

https://gist.github.com/neguse11/bc09d86e7acbd6442cd4#oauth-20-のための-id-を得る

の 「OAuth 2.0 のための ID を得る」 に沿って、「Client ID」と「Client secret」と「Refresh token」と [「Refresh token」を 取得したのと同じページ](https://developers.google.com/oauthplayground/) から「Access Token」を取得します。

## Cloud Functions を用意する

https://blog.apar.jp/web/10611/#toc3 

を参考にして、Cloud Functions の有効化・関数の作成を行います (Python の部分は、Nodejs に書き換えて下さい)。
関数の作成が出来たら、作成した関数をクリックし、その中から「ソース」のタブを選択して、以下のコードを加えます。
クライアントID・クライアントシークレット・リフレッシュトークン・アクセストークンを適宜書き換えて下さい。

```package.json
{
  "name": "your-project-name",
  "version": "0.0.1",
  "dependencies": {
    "nodemailer": "^6.7.3"
  }
}
```

```javascript:index.js
const nodeMailer = require("nodemailer")

exports.yourProject = (req, res) => {

    const transporter = nodeMailer.createTransport({
    host: "smtp.gmail.com",
    port: 465,
    secure: true,
    auth: {
      type: "OAuth2",
      user: "your-email@gmail.com",
      clientId: "クライアントID",
      clientSecret: "クライアントシークレット",
      refreshToken: "リフレッシュトークン",
      accessToken: "アクセストークン",
    }

  const mailOptions = {
    from: "your-email@gmail.com",
    to: "to-email@sample.com",
    subject: "Test Subject",
    text: "Test Text",
  }

  transporter.sendMail(mailOptions)
  .then(() => {
    res.status(200).send(response)
  })
  .catch(e => {
    res.status(500).send(e)
  })

}

```

これで、Cloud Functions から Gmail を送信することができました。
#（シャープ）と.（ドット）の違い

## 結論
HTML要素のID属性を指定する場合が `#(シャープ)` です。
HTML要素のクラス属性を指定する場合が `.(ドット)` です。

## #(シャープ)
```html:html
<p id="hoge">hogeです</p>
```

```css:css
#hoge{
  /*ccsを記載*/
}
```

## .(ドット)
```html:html
<div class="hoge">hogeです</p>
```

```css:css
.hoge{
  /*ccsを記載*/
}
```
【ターミナル】zshでエイリアスを設定する

# 環境
・macOS Monterey 12.2.1
・シェル: zsh
# エイリアスとは
デフォルトのコマンドにつけるニックネームのようなもの。
##### メリット
・typoが減る
・時短になる(使用頻度が高い且つ長いコマンドに設定すると効果的)
# エイリアスの登録場所
`~/.zshrc`に記述します。
※使用シェルがbashの場合は`~/.bash_profile`
# 設定方法
```~/.zshrc
alias 任意のコマンド='元のコマンド'
```
##### 反映方法
```:terminal
$ source ~/.zshrc
```
テーブルやカラムに別名をつける AS句

## 用途
何度もテーブル名やカラム名を打たないといけない時、テーブル名やカラム名が長い時などで、テーブルやカラムに別名をつけ、入力を楽にしたい時などに使う

## 使用方法
### テーブルに別名をつける
```sql
SELECT * FROM hogehogehoge AS hoge;
```
ASは省略できる
```sql
SELECT * FROM hogehogehoge hoge;
```
hogehogehogeテーブルの `id` を取得したい時
```sql
SELECT hoge.id FROM hogehogehoge hoge;
```

### 取得したいカラムに別名をつける(取得後の作業でミスを防げる)
```sql
SELECT hoge.id AS hoge_id FROM hogehogehoge hoge;
```
ASは省略できる
```sql
SELECT hoge.id hoge_id FROM hogehogehoge hoge;
```
C# AngleSharp ログイン後の画面遷移を行う

# 発生した問題
AngleSharpでスクレイピングをしてみたのだが、どうもログイン後の画面遷移がうまくいっていないっぽい。

ログインしてトップページまで表示させることはできたのだが、別ページに遷移しようとすると以下のエラーメッセージが表示されてしまう。

※ちなみにこれは某証券サイトのエラーメッセージ
>ログイン画面から再度入力して下さい。(エラーコード)
>何らかの原因によりXXXXXから自動的にログアウトいたしました。
>ご利用を継続される場合は、再度ログインをお願いいたします。
>・最後にXXXXXを操作してから、30分以上経過した 
>・ブックマークからログイン後のページにアクセスした 
>・インターネットから一旦切断された後、再度アクセスされた等

# 問題のコード
```C#
using System.Diagnostics;
using AngleSharp.Dom;
using AngleSharp;
using AngleSharp.Html.Dom;

namespace SampleFormApp
{
    public class ScrapingMain
    {
        const string HOST_URL = "https://xxxxx.co.jp";

        public async Task<System.Collections.Generic.IEnumerable<string>> Exec()
        {
            var config = Configuration.Default.WithDefaultLoader().WithJs();
            var context = BrowsingContext.New(config);

            await context.OpenAsync($"{HOST_URL}/xxxxx/");

            var topPage = await context.Active.QuerySelector<IHtmlFormElement>("form[name='form_TopPage']").SubmitAsync(new
            {
                koza1 = "[支店コード]",
                koza2 = "[口座番号]",
                passwd = "[パスワード]",
            });

            var topPageHeaderMenu = context.Active.QuerySelectorAll("table");
            var transactionPageUrl = topPageHeaderMenu[3].Children[0].Children[0].Children[2].Children[0].Attributes["href"].Value;

            // この遷移がうまくいっていないっぽい
            await context.OpenAsync($"{HOST_URL}{transactionPageUrl}");
            // ここはとりあえず適当・・・。
            return (IEnumerable<string>)topPageHeaderMenu;
        }
    }
}
```

# 解決方法
色々調べたところ、デフォルトではCookieを保持するような設定になっていないみたい。
そりゃセッション維持できないよね・・・。

ということで WithDefaultCookies() を追加したら、問題なく画面遷移できた。

```C#
using System.Diagnostics;
using AngleSharp.Dom;
using AngleSharp;
using AngleSharp.Html.Dom;

namespace SampleFormApp
{
    public class ScrapingMain
    {
        const string HOST_URL = "https://xxxxx.co.jp";

        public async Task<System.Collections.Generic.IEnumerable<string>> Exec()
        {
            var config = Configuration.Default.WithDefaultLoader().WithJs().WithDefaultCookies(); // WithDefaultCookies()を追加
            var context = BrowsingContext.New(config);

            await context.OpenAsync($"{HOST_URL}/xxxxx/");

            var topPage = await context.Active.QuerySelector<IHtmlFormElement>("form[name='form_TopPage']").SubmitAsync(new
            {
                koza1 = "[支店コード]",
                koza2 = "[口座番号]",
                passwd = "[パスワード]",
            });

            var topPageHeaderMenu = context.Active.QuerySelectorAll("table");
            var transactionPageUrl = topPageHeaderMenu[3].Children[0].Children[0].Children[2].Children[0].Attributes["href"].Value;

            await context.OpenAsync($"{HOST_URL}{transactionPageUrl}");

            return (IEnumerable<string>)topPageHeaderMenu;
        }
    }
}
```

# バージョン情報
Visual Studio 2022 Version 17.1.3
.NET 6.0
AngleSharp 0.16.1
AngleSharp.Js 0.15.0
Configファイルのシート使い分けメモ

# はじめに

今まで何となくREFrameworkやConfigファイルを使っていたのですが、ちゃんと勉強したいなと思ったのでメモとして残します。

内容に誤りがございましたらお手数ではございますがご指摘いただけますと幸いです。

# Configファイルとは

UiPathのフレームワーク「REFramework」にて使用するエクセルファイルです。
なぜConfigファイルをエクセルファイルとして外出ししているかというと、ファイルパスやロボ実行時に利用するパラメータをロボットにベタ書きしないで、簡単に変えられるようにしたいからですね。

Configファイルのパラメータをstudio内で使いたい時は以下のように記載します。

```
Config（"Config内パラメータ名"）
```

元々REFrameworkではConfigファイルも用意されていて、ファイルにはそれぞれ

* Settings
* Constants
* Assets

とシートが用意されているのですが、各シートにどういった使い分けをすれば良いのか、今一度整理することが今回のメモの目的です。

# Configファイルのシート

## Settings

こちらのシートには、業務的なパラメータを記述するようです。
例…ロボットが実施する作業で参照するファイル・フォルダのパスなど

## Constants

こちらのシートには、業務的なパラメータではなく、REFrameworkで使用しているパラメータを記載するようです。
例…例外参考スクリーンショットが格納されるフォルダパス、最大リトライ回数など

## Assets

こちらのシートは…
ごめんなさい、Orchestrator用のシート？みたいですが、いまいち使い方がはっきりわかってないです…
分かり次第追記します。

# 参考文献

Forumに質問が載っていました。

https://forum.uipath.com/t/reframework-config/389714


# おわりに

Configファイルのシート使い分けなくても動きはするので意識してなかったんですが、作成する成果物の品質向上のためにも、ちゃんと勉強するべきだなと思いました（小学生並みの感想）今後も勉強継続していきます。
実行したコマンドのI/O使用量を計測するツールを作りました（timeコマンドのI/O版）

## はじめに

`time` コマンドみたいに、実行したコマンド（子プロセス含む）の I/O の読み込み量や書き込み量が知りたいなーと思ったので作ってみました。作ったと言っても `/proc/<PID>/io` を読み取って可能な限り正確な情報になるように調整して、あとメモリキャッシュのクリアなどを少し簡単に行えるようにしただけですが。

リポジトリはこちら https://github.com/ko1nksm/io

## 動作環境

Linux などの procfs が実装されているシステムでしか動作しません。WSL1 は procfs は実装されていますが `/proc/<PID>/io` がないので動作しません。WSL2 では動作します。

macOS では procfs 自体がないので動作しません。もし macOS でコマンドが使用した I/O 使用量の取得方法を知っている方がいましたらコメントください。🙏

## 使い方

```sh
# $ base64 -w 999 /dev/urandom | head -n 10000 > data.txt
# $ wc data.txt
#    10000    10000 10000000 data.txt

$ export IOCLEANUP='sudo sh -c "echo 1 > /proc/sys/vm/drop_caches"'
$ export IOWARMUP='sort --version'

$ io sort data.txt > /tmp/output.txt
io: cleanup: sudo sh -c "echo 1 > /proc/sys/vm/drop_caches"
io: warmup: sort --version

rchar: 10005365
wchar: 10000001
syscr: 124
syscw: 2443
read_bytes: 10002432
write_bytes: 10002432
cancelled_write_bytes: 0
```

各項目の意味は `man procfs` （[日本語](https://linuxjm.osdn.jp/html/LDP_man-pages/man5/proc.5.html) `/io` でページ検索） で調べることができます。

使い方は `time` コマンドと同じように `io` コマンドを使うだけですが、環境変数 `IOCLEANUP` と `IOWARMUP` で計測前に実行する処理を指定できるようにしています。

環境変数 `IOCLEANUP` は主にメモリキャッシュをクリアするために使います。ファイルがメモリにキャッシュされている場合、キャッシュをクリアしないと実際に読み込む量を正しく計測できません。ただし一度使ったファイルはメモリにキャッシュされているのが普通なので**必ずしもキャッシュをクリアして計測すべきとは限りません**。

メモリのキャッシュをクリアしないようにして計測するとこのようになります。ファイルがメモリにキャッシュされており読み込む必要がないので `read_bytes` が 0 になっていますね。

```sh
$ IOCLEANUP= io sort data.txt > /tmp/output.txt
io: warmup: sort --version

rchar: 10005360
wchar: 10000001
syscr: 119
syscw: 2443
read_bytes: 0
write_bytes: 10002432
cancelled_write_bytes: 0
```

もう一つの環境変数 `IOWARMUP` は主にコマンドをメモリにキャッシュさせるために使います。`IOCLEANUP` でメモリキャッシュをクリアすると、コマンド、上記の例では `sort` コマンドの実行ファイル自体もメモリキャッシュから削除されてしまいます。通常はコマンドが使用するデータ量のみを知りたいはずなので `sort --version` のように無害なコマンドを実行させることでコマンドをメモリに再キャッシュさせることができます。

あとはコマンドの実行前と実行後の `/proc/<PID>/io` の値を読み取り、差分を取ってより正確な値を出力しています。

## 補足 GNU time

GNU 版の `time` コマンドでもファイルの読み込み量と書き込み量を知ることができます。実行時間やメモリ使用量など多くの情報を出力できますが、I/O の情報に限れば `/proc/<PID/io` の方が多いようです。使い方は `env time -v <COMMAND>`（または `env time` の代わりに `/usr/bin/time`）です。ただの `time` だと bash 等のシェルにビルトインされている方の `time` コマンドが呼び出されるので注意してください。
UiPath 動かしながら文字列操作を理解する①

# はじめに
普段、UiPathで社内開発をしている中で、
文字列の操作を意識せず行っていることがある。
例えば、UiPathは予測候補を出してくれるため、選択肢から何となく
`.ToString`を選択したりしていた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602975/08a795e4-2700-870d-2bfe-59ef61c7b513.png)
上記を理解したうえで使い、もっとできることを増やしたいと考え
[UiPathアカデミーの「RPAデベロッパー 基礎プログラム」](https://www.uipath.com/ja/rpa/academy)で学習したところ、
改めて基礎の重要性に気付いたため、Qiitaにまとめることにした。
# UiPathの文字列操作って？
VB.NET メソッドを使って以下のような文字列操作ができる。
## ToStringメソッド
異なるデータ型変数を文字列型へ変換する。
### 使用例：数値型から文字列型への変換
文字列同士をつなぐときは`+`を使用するが、異なるデータ型を含める場合は、
文字列型へ変換する必要がある。

①数値型の変数「数値」を宣言し、型は`int32`、規定値に`100`を入力する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602975/1a28657d-ae58-2664-b5da-ef83277a208d.png)
②メッセージボックスを設置する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602975/3771eaf2-704d-172e-8bfc-677cc7c01714.png)
③テキストボックスに以下を入力するとエラーになる。
`"テストの点数は" + 数値 + "点でした。"`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602975/0ba70439-4dc0-8469-7349-7c02a2a6110d.png)
④数値型変数を文字列に変換するとエラーが解消される。
変数「数値」の後に、`.ToString`を付加する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602975/57193207-3e5f-b39f-75f1-a8751af1f8ed.png)
⑤実行すると、無事にメッセージボックスが表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602975/7b3ca995-928b-24b2-0a37-fbb68dbe9e27.png)
## Containsメソッド
指定の文字列を検索して、True/Falseを返す。
### 使用例：テキスト内の文字列を検索
全体図はこちら。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602975/29d9dbaa-991b-11f4-8558-e72821482dc0.png)
①String型の変数「文字列」を宣言する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602975/04e5417f-e799-8cb3-d8ac-da687f4e0cdc.png)
②代入アクティビティを設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602975/a7bbc075-b4c3-602c-7a7e-c75fc387c8a4.png)
値は、`早くブログ書き終わりたい` （笑）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602975/07e346b6-9fac-3f6e-7ac2-4fb04b50ef09.png)
③メッセージボックスを設定する。
テキストボックス内に `文字列.Contains("ブログ")` と入力する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602975/f0a6e867-14a7-28d6-a952-0376f0b8d8cc.png)
④実行すると、変数「文字列」内に `ブログ` が含まれるため、Trueが返ってくる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2602975/fc12f122-144c-00bf-cf0d-e8af803f76ab.png)
# 感想
UiPathアカデミーでデータ操作を学習後、特に変数の型を意識して使うようになった。
UiPathはローコードなので、プログラミングが苦手な人でもとっつきやすくはあるが、
基礎的な知識はあった方ができることが増える。
今後もアカデミーで学習を継続していきたい。
# 参考資料
- [UiPathアカデミー](https://www.uipath.com/ja/rpa/academy)
IN演算子 SQL

## 用途
複数の値に一致するレコードを取り出す場合に使用する

## 使用方法
```sql
select * from テーブル名 where カラム名 in ('値１', '値2', '値3', ...);
```
例 hogeテーブル
| id | name | color |
|:-------|------------:|:------------:|
| 1       | 山田        | 赤         |
| 2     | 鈴木      | 青       |
| 3       | 吉田        | 緑         |
| 4         | 田中          | 黄           |
| 5       | 渡辺       | 白       |
| 6    | 清水     | 黒      |


```sql:sql
select * from hoge where color in ('青', '白', '黒');
```
結果
| id | name | color |
|:-------|------------:|:------------:|
| 2     | 鈴木      | 青       |
| 5       | 渡辺       | 白       |
| 6    | 清水     | 黒      |

　
　
　
この記事は以下の情報を参考にして執筆しました。
- https://www.ipentec.com/document/sql-in-operator
BVE 鉄道シミュレーターで自宅運転台を動かそう～レバーサとキースイッチを動かす

BVE 鉄道シミュレーターで自宅運転台を動かそう~の続きです。

https://qiita.com/usashirou/items/4f5ad751152834698919

今回は、前進後進を決めるレバーサとキースイッチを連動させてみます。
# レバーサとは
レバーサは前進後進及び中立を決めるもので、当然ながらこのレバーサが前進でないとマスコンを操作しても前進はしません。
BVE 鉄道シミュレーターで自宅運転台を動かそう～電車でGoコントローラーを使う～では11，12ピンにレザーサのピンを設定しています。
https://qiita.com/usashirou/items/ac358a8828f54f97bc2b

```
const int REBF = 11;
const int REBR = 12;
```

レバーサは、3ポジションのスイッチを活用し、前後でGNDが短絡するように配線しました。
 __UniversalContactInterface__ は
```
中立：RN
前進：RF
後退：RB
```
を入力することでコントロールできます。
今回は、既存のプログラムのIF文による

    REBFsw ==  OFF/ON && REBRsw == OFF/ON  
    NOWREB = x

をそのまま使用しました。
# キースイッチ
次に、キースイッチを作ります。
キースイッチは、運転士がマスコンを操作する際に入れるキーで、東急電鉄の車両などでは、キーを入れないとテールランプが点灯するようになっているようです。
BVEではメトロ総合プラグインなどではキーをONにしないと運転を開始することができません。
今回は、この動作をするスイッチを作ってみます。
# スイッチ
今回はON-OFFだけのスイッチにしましたが、3ポジションのON-OFF-ONのスイッチをつかうことをお勧めします。
これはメトロ総合プラグインにおいて複数回ONにしないといけない場合がある為です。

### マスコンキー仕様の一例
    13　東急 ← 切 → 営団 → 東武 → 西武
http://www.nozomi.vc/71_ats/metro/train.htm

今回は、既存のプログラムを活用してONで __8__、OFFで __7__ を入力するようにしましょう。
## 組み立てた様子
左側のレバーサとキースイッチを使います。
![DSC_0179 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/b2b2f101-3955-2271-ca52-267846c0bc2f.jpeg)
中の様子です。
![DSC_0176 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/301cd211-efdb-4184-4db3-49e3773dc26c.jpeg)
## プログラム
既存のスイッチのプログラムはON接点が繋がる、離れるでコマンドを送信します。
これを接点が繋がる⇒ Button6を送信
離れる⇒Button5を送信に変更します。

```
  if (SW5sw == ON) {
    NOWSW5 = 1;
  }
  if (SW5sw == OFF) {
    NOWSW5 = 0;
  }
  if (NOWSW5 != BEFORSW5) {
    if (NOWSW5 == 1) {
      Serial.print("S6\r");
    }
    if (NOWSW5 == 0) {
      Serial.print("S5\r");
    }
  }
  BEFORSW5 = NOWSW5;
```

# Buttonをキーに変換する
次に、BVEの入力インタフェースで
Button6は __8__
Button5は __7__ に入力変換します。
__8__　はATS13
__7__　はATS12を割り当てます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/3b84be37-19e8-c4c1-0640-d4534dbd92d4.png)
以上でキースイッチを廻すとBVE上のキーがONになるようになりました。
# 車両の改造
今回は車両の改造は必要ありません。
入力インタフェースのみとなります。
【React塾】React練習問題【素数を判定する関数を実装してみよう！】

# React練習問題
Q1. 素数かどうか判定する関数を作ってみよう！![スクリーンショット 2022-04-02 20.44.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326114/11569058-51ee-db68-bc1f-7a84c8242e64.png)

## 問題の取り組み方

1.Github右上部にあるForkをクリックして、以下のリポジトリをフォーク
https://github.com/SatakeYusuke19920527/react-juku.git
![スクリーンショット 2022-04-02 20.46.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326114/ec733350-37d0-fcb1-37f4-2da9b40254e1.png)


2.git clone
Codeと書いてあるボタンをクリックしてURLをコピー
![スクリーンショット 2022-04-02 20.47.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326114/1f9637ed-3302-6380-abcf-cbcabec2d580.png)

3.git cloneでローカル環境へコードを持ってくる

```
git clone https://github.com/SatakeYusuke19920527/react-juku.git
```


4.src/questions/Q1.tsxのjudgePrimeNumber()で素数を判定する関数のロジックを実装してください

![スクリーンショット 2022-04-02 20.53.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326114/f825ee61-c8f4-640d-3d00-7bf4866e4ef0.png)


5.実装できたらレビュアーに [SatakeYusuke19920527] を入れてプルリクエストを作成してください

6.レビューして合否を判定します！プルリクエストに合否を書くね。

## みんなのコードを見れることを楽しみにしてます！

p.s　好評だったら第二弾もやるね

https://proaca.tech/
`flutter_hooks`を使用して`TextField`を扱う場合に`controller`プロパティには`useTextEditingController`で生成したインスタンスを渡す

# TL;DR

`flutter_hooks`を使用してテキストフィールドを扱う時に`HookWidget`を継承したクラスの場合`TextEditingController`だとうまく動かなかったので`useTextEditingController`使う。

https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useTextEditingController-constant.html

## 詳細
### 発生する問題

以下のように`HookWidget`を継承したクラスで`TextField`コンポーネントを扱う場合に、`TextField`の`cotroller`プロパティに、Flutter標準の`TextEditingController`のインスタンスを渡しています。

```dart
import 'package:flutter/material.dart'
import 'package:flutter_hooks/flutter_hooks.dart';

class Sample extends HookWidget {
  final _controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return TextField(
      controller: _controller,
      labelText: "Input",
    )
  }
}
```

https://api.flutter.dev/flutter/widgets/TextEditingController-class.html

すると以下のような不具合が発生していた通りに動作しませんでした。


* 値を入力した後にテキストフィールドからフォーカスを外すと入力した値が消えてしまう
* `useEffect`など別の関数で`controller.text`の初期値を入力するなど行っても反映されない

### 対応

`HookWidget`を継承しているクラスの中で`TextEditingController`を扱う場合は`flutter_hooks`で 用意されている`useTextEditingController`を使用して生成されたインスタンスを使う必要がありました。

以下の変更加えることで前述した不具合は解消されます。

```diff
import 'package:flutter/material.dart'
import 'package:flutter_hooks/flutter_hooks.dart';

class Sample extends HookWidget {
-  final _controller = TextEditingController();
+  final _controller = useTextEditingController();

  @override
  Widget build(BuildContext context) {
    return TextField(
      controller: _controller,
      labelText: "Input",
    )
  }
}
```

https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useTextEditingController-constant.html


## 環境

* Flutter 2.10.0
* Dart SDK version: 2.16.0
SLAMの基礎の部分

# SLAMについて
ROS等で自動制御を行うならば、自己位置推定は必須項目である。
SLAMではLiDARやodometryを用いてロボットの自己位置推定と地図構築を行っている。
![20210310152007_674 (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379533/f5a1bb1e-b392-2f5e-d099-05394f8ec197.jpeg)
[北陽のLiDAR UST-30LX](https://www.hokuyo-aut.co.jp/search/single.php?serial=195)
![l_486-14-118784-198x198.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379533/ef048b2a-001f-ec84-b232-d13c46111a17.jpeg)
[OMRONのE6A2-C](https://www.fa.omron.co.jp/products/family/486/)

また使用するセンサーの種類によって以下のような違いが出てくる
|  　  |  ロボットの種類  | 地図 | センサ |
| ---- | :----: | :----: | :----: |
|  2D/2D型  |  2次元3自由度 |2次元|2D Lider, オドメトリ, ジャイロ|
|  2D/3D型  |  2次元3自由度 |3次元|2D/3D Lider, カメラ, オドメトリ, ジャイロ|
|  3D/3D型  |  3次元6自由度 |3次元|3D Lider, カメラ, IMU|  

表のようにセンサーの次元により、構築される地図の次元数やロボットの自由度が変わってくる。

# SLAMの基礎
SLAMにおいて大切なキーワードとなるのが**ランドマーク**という概念である。
**ランドマーク**とはいわゆる目印のことで、これとの距離と方向を計測することで地図を作製していく。
具体的には以下のようになる。
![bbb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379533/3619854f-bbf1-24c9-dc21-7888799f1ce5.png)

図の<font color="blue">青</font>が<font color="blue">ロボット</font>、<font color="red">赤</font>が<font color="red">ランドマーク</font>である。

ロボットのグローバル座標系における推定座標をオドメトリから積分していくとして、やはりそこには誤差が蓄積していく。
ここで<font color="red">ランドマーク</font>$q_{i}$と計測データ$z_{i}$から以下の連立方程式が成り立つ。
```math
\begin{equation}
\left\{ \,
 \begin{aligned}
\boldsymbol{q_{1}} &= R_{1}z_{1} + \boldsymbol{t_{1}} \\
\boldsymbol{q_{2}} &= R_{1}z_{2} + \boldsymbol{t_{1}} \\
\boldsymbol{q_{3}} &= R_{1}z_{3} + \boldsymbol{t_{1}} \\
\boldsymbol{q_{1}} &= R_{2}z_{4} + \boldsymbol{t_{2}} \\
\boldsymbol{q_{2}} &= R_{2}z_{5} + \boldsymbol{t_{2}} \\
\boldsymbol{q_{3}} &= R_{2}z_{6} + \boldsymbol{t_{2}}
 \end{aligned}
\right.
\end{equation}
```
$R_{i}$はロボット座標系からグローバル座標に変換する回転行列である。
これを$\boldsymbol{q_{i}}$について解くことで<font color="red">ランドマーク</font>からもロボットの推定座標を計算することが出来る。

# SLAMのデータ対応付け
ランドマークが明確に区別できる場合なら上記のやり方でいいが、実際問題、ランドマークはもともと存在している実際の地形・風景・物体によく設定される。それらを区別してデータ対応づけを行うため、以下２つの方法がよく用いられる。

・位置制約による対応づけ
・特徴量による対応づけ

# SLAMのループ閉じ込め
ここでいう`ループ`とは周回路のことである。
SLAMにおいて、自己位置を推定したとしても、ランドマークにも誤差が生じる。
その誤差を含んだランドマークから自己位置を推定することで、さらに誤差が累積していく。
よってロボットがスタート地点に正確に戻ることが出来ず、閉ループにならない。
よってSLAMでは`ループ閉じ込め`を行う

## ループ検出
開始位置で検出したランドマークを$q_{1},q_{2}$とする。
ロボットが開始位置に戻ったことを検知し、その誤差が含まれた位置で同じランドマーク$\acute{q_{1}},\acute{q_{2}}$を計測する。
しかし、ランドマークは同じなので、$\acute{q_{1}},\acute{q_{2}}$と$q_{1},q_{2}$が同じ位置になるように推定した自己位置を修正する。
そしてこれを$x_{i-1}$の推定位置にも行い、ループ全体の自己位置を補正するのがループ検出である。

# 参考文献
 SLAM入門 ロボットの自己位置推定と地図構築の技術
 友納正裕 著 オーム社
ActionFuction実行時にapex:InputFileの表示名が消えてしまう件について

## 経緯
VisualforceからControllerクラスのメソッドを呼ぶことができるActionFunctionですが、
ActionFuction実行後に画面に戻ると、
InputFileで選択中のファイル名が消えてしまう件について、少し苦戦したので備忘録として記載。

## 結論
ActionFunction実行時に<apex:inputFile>上で、ファイル名は消えているがデータとしては入っているのは仕様とのこと。

## 対応策
1. データとしては保持しているので別のラベルなどでファイル名表示させる。
2. RemoteActionでは表題の問題が発生しないため、ActionFunctionの代用できる。

https://qiita.com/sigulog/items/cf546deaba4227a50edc

::: note warn
RemoteActionはStaticメソッドのため、メンバー変数の値を変更することができない。RemoteActionを使用する場合はVisualforceのvalueで受け取るのではなくJavascriptを使用して値を受け取る必要があるため工夫が必要になる。
:::
[Flutter] SharedPreferencesを使って、オブジェクトのList（配列）をJSONにして保存する

Flutterのアプリ作成で、

オブジェクトのListを端末に保存しておきたかったので、

あまりそのようなケースは、多くないかもしれませんが、覚書として記事にしました。

少しでも誰かのお役に立てれば、幸いです。

## JSONに変換する

SharedPreferencesで端末に保存できる値は、

`int`、`double`、`bool`、`String`、`List<String>` の型のみなので、

オブジェクトのListの場合は、それをJSONに変換して`String`として保存します。

```dart
import 'package:shared_preferences/shared_preferences.dart';

  Future<void> setObjectList(List<T> objectList) async {
    SharedPreferences _prefs = await SharedPreferences.getInstance();
    final jsonString = jsonEncode(objectList).toString();
    await _prefs.setString('TEST', jsonString);
  }
```

## 取得したStringを元のオブジェクトのリストに変換する

値を取得した後は、その文字列をJSONに戻して、

オブジェクトのFreezedクラスの`fromJson`を利用して、元のオブジェクトに戻して、

リストにします。

```dart
  Future<List<T>> getObjectList() async {
    SharedPreferences _prefs = await SharedPreferences.getInstance();
    final jsonString = _prefs.getString('TEST') ?? "";
    final List<dynamic> decodedJson = jsonDecode(jsonString);
    final objectList = decodedJson.map((e) =>Object.fromJson(e)).toList();
    return objectList;
  }
```

## 参考にしたサイト

https://stackoverflow.com/questions/67244783/dynamic-list-in-flutter-using-sharedpreferences