OmniAICreator/Qiita-1.07M huggingface dataset:
初心者向け）Herokuへデプロイ時にcollectstaticを実行したくない場合の設定

### 外部クラウドに静的ファイルをおいた場合、デプロイ時にエラーが出るんです

Herokuの内部には静的ファイル（staticとかmediaとか）を置くべきではない、っていうかおいておくと再デプロイ時やDynoの再起動で消えてしまうみたいです。そんな場合はAWSやGCPにバケットを設定してそこにデータを置いとくのが定石のようです。

で、そんな設定でHerokuにデプロイするとエラーが発生してしまいますね。

```
!     Error while running '$ python manage.py collectstatic --noinput'.
```

インターネッツを検索するとその対応策がすぐに見つかるんですが、私の場合なんだかうまくいきませんでした。

```
$ heroku config:set DISABLE_COLLECTSTATIC=1
```

対策の内容を読むと、環境変数のDISABLE_COLLECTSTATICを１に設定しとけってことですが、heroku CLIからコマンドを打ってもエラーが出てしまいました。

追記）
検索して多数ヒットする上のコマンドでは、対象のアプリ名がないのでおかしいなーと思ってました。実際エラーになるわけで、正式なコマンドは以下の通りだと思われます。

```
$ heroku config:set -a [webアプリ名] DISABLE_COLLECTSTATIC=1
```

なので環境変数ならばHeroku　ダッシュボードから設定できたことを思いだしてやってみたらうまく動きました。

Heroku　ダッシュボードのSettings画面にあるConfig Varsに以下のように環境変数のDISABLE_COLLECTSTATICをとその値１を設定します。

![スクリーンショット 2021-10-23 11.04.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739706/b7410f42-11f6-cbe6-4407-d6cdc69b1d89.png)


頑張ってクラウドに静的データが置けるようになったのに、デプロイ時にエラーが発生して困っている人（それは私です）の役にたてば良いなという情報です。

現場からは以上です。
rails sできなくなった件

問題：「rails s」している途中で、ターミナルを閉じてしまい、再度開こうとしても起動中であるとのこと。

解決：
①ps aux | grep アプリ名でプロセス番号を確認
②killコマンドでサーバーを強制停止
以上の手順で解決。
②は「kill -9 プロセス番号」を入力すること。

改善：
今度からは、「control + c」で確実に終了していくようにする。
raspberry pi 1 model bで、navit その2

#概要

raspberry pi 1 model bで、navitやってみる。
gpsをつなぐ。

#rohmのu-blox 6m なgpsをつなぐと

/dev/ttyACM0
と、認識する。

#gpsdをインストールする。

```
sudo aptitude install gpsd gpsd-clients

```

#設定

```
sudo nano /etc/default/gpsd

```
```
DEVICES="/dev/ttyACM0"

```

#確認

```
gpsmon
```


以上。
正しい知識を！「プログラミング的思考」とは

『文 部 科 学 省 小学校プログラミング教育の手引（第一版）平成３０年３月』より、

>「プログラミング的思考」とは
”自分が意図する一連の活動を実現するために、どのような動きの組合せが必要であり、一つ一つに対応した記号を、どのように組み合わせたらいいのか、記号の組み合わせをどのように改善したらより良いより意図した活動に近づくのか、といったことを論理的に考えていく力”



と書いてあります。

https://programingo.com/
知れ！プログラミング教室（スクール）なんてそろばん塾と同じ！

最近、プログラミング教室に通わせることのメリットを聞かれます。

プログラミング教室はそろばん塾のようなものです。


そろばんは、学校の授業科目にはありません。

でも、計算が早くなるとか、集中力がつくか・・・

あと、全国検定があって成果を評価できる...

というメリットで通っている子が多いと思います。



では、プログラミング教室は？

プログラミング教室も授業科目の成績アップに直接使えるものではありません。


何ができるかというと、<b>考えたことを標準化（理路整然）として表現することができる</b>ようになります。

これは、物事を学習して人に伝達する上で非常に重要です。


将来大学等で論文を作成するときに必要とされる技術です。



https://programingo.com/addmember/
raspberry pi 1 model bで、navit


#概要

raspberry pi 1 model bで、navitやってみる。
aptitude updateが、できないので、対処した。

#環境

raspbery pi 1 model b(element14)
raspbian 2016-11-25 jessie with pixel

#/etc/apt/sources.listを編集する

```
#deb http://raspbian.raspberrypi.org/raspbian/ jessie main contrib non-free rpi
deb http://raspbian.raspberrypi.org/raspbian/ stretch main contrib non-free rpi


```

以上。
obnizボタンを押すと画面に『格言』を表示

##はじめに
obnizのボタンを押し、格言APIが表示されるIoTを作成しました。

APIはこちらを参考に引っ張ってきました。
https://zenn.dev/protoout/books/public-apis-api-get/viewer/01

##前提条件
・Node.jsのインストール
・axiosのインストール
・obnizにボタンをつける

##本題
完成は下記コード

```javascript
//obnizのボタンを押すとadviceを返します
var Obniz = require("obniz");
//APIを叩ける
const axios = require('axios');

var obniz = new Obniz("XXXX-XXXX"); //obnizIDを入力
obniz.onconnect = async function () {
    let button = obniz.wired("Keyestudio_Button", {signal:0, vcc:1, gnd:2});
    while (true) {
        obniz.display.clear();
        await button.stateWait(false);
        main();
    }
}

const main = async()=>{
    try{
        const res = await axios.get('https://api.adviceslip.com/advice');
        console.log(res.data.slip.advice);
        obniz.display.print(res.data.slip.advice);
    } catch (error){
        console.error(error);
    }
}
```

obnizのボタンが押されると、`stateWait()`が`false`となり、
`main()`が実行される仕様となっています。

`main()`に関して
`console.log`ではAPIのデータで欲しい情報を記載します。
今回のデータでは`slip`オブジェクト内の`advice`というkeyに出力したい情報(value)があるため、このようなコードになっています。
（語弊があるかもしれませんが、ご了承ください。
　その際は、ご指摘いただけると幸いです。）

##おわりに
落ち込んだ時とかやる気を出したいときに使ってください
英語の格言なので何いっているかわかりません...笑

今後は英語→日本語に翻訳して出力されるよう工夫したいと思います。
ありがとうございました。
モダンJavaScriptを0歳のところから学習していく【初心者】

こんにちは！
テックキャンプでJavaScriptのカリキュラムはありましたが、習ったと言ってもサラッとした内容だったので２、３日前からUdemyでモダンJSを学習中です。そのアウトプットとして記事を書いていきたいと思います。超絶初心者なので間違ってたら言ってください。
何も知らない赤ちゃん状態です。

# var let const
マジ初歩の初歩の変数宣言からやっていきます。

## var
従来のJavaScriptでは変数宣言が行えるのはvarのみでした。
var変数は上書きも再宣言も可能です。

```javascript
var name = '裏梅';
name = '羂索';
var name = '漏瑚さん';
```

var変数は上書きも変数宣言も可能なのでプロジェクトが肥大化する中で、意図しない上書きや変数宣言を発生させてしまうというエラーも起こってしまっていたようです。

## let

ES2015で追加された変数です。
letは上書きが可能ですが、再宣言は不可能です。

```javascript
let name = 'パンダ';
name = '猪巻棘';
```
## const

こちらもES2015で追加された変数です。
constは上書きも再宣言も不可能な変数です。

```javascript
const name = '乙骨憂太';
```
constは一度設定された文字列や数値が変わらないことが保証されるのですが、オブジェクトや配列は値を変えることができます。

```javascript
const yuji = {
	magic: '黒閃',
	age: 16
};
yuji.magic = '逕庭拳';
yuji.runk = '２級呪術師';
```

このようにオブジェクトのプロパティの上書き、追加はconstで行うことができます。

変数定義の際にvarを使用するのではなくlet,constを利用することができるので実際の現場では情報が増えてかなり楽ですよね。letを利用しているときは「再代入する予定のある変数なんだな」とかconstなら「今後この値は再代入も再変数定義も行わないんだな」と。constかletで情報整理ができるので楽ですね。
Rubyはこのような変数の定義をしないので、paizaのスキルチェックなんかやってると「あれ？なんで急に再代入されてんの？」みたいな時もあります。Rubyは短くかけて自由度の高い言語ではありますがそんなデメリットもありますね。

# テンプレート文字列

これもES2015で追加された機能のようです。
簡単にいうと文字列の中にJavaScriptを放り込めるようにできる機能です。

## 従来の書き方

```javascript
const name = '七海建人';
const magic = '十劃呪法';

message = '私の名前は' + name + 'です。術式は' + magic + 'です。'
console.log(message);
```

## テンプレート文字列

```javascript
const name = '七海建人';
const magic = '十劃呪法';

message = `私の名前は${name}です。術式は${magic}です。`
console.log(message);
```

テンプレート文字列を利用した方が記述量も少なくてスッキリしてますね！！
テンプレート文字列はバッククオーテーションで囲んで変数の利用には${}を使います。
Rubyだとシングルやダブルクオーテーションで囲んで#{}でしたね。

# アロー関数

従来の書き方だと、

```javascript
function gojo (str) {
  return str;
}
console(gojo('ボク最強だから'));
```

アロー関数でかくと

```javascript
const gojo = (str) =>{
 return str;
}
console(gojo('ボク最強だから'));

もしくは
const gojo = (str) => str;
console(gojo('ボク最強だから'));
```
アロー関数は1行の単一処理の場合、記述を省略することができます。

今日の内容は流石にJSの初歩の初歩の内容だったのでテックキャンプのカリキュラムでも記載あることばかりでした。しかし、忘れていた内容も多かったのでおさらいという意味でも取り組めて楽しかったです。
今日の学習で四足歩行から二足歩行になるまで成長したと思いたいバブ。
FT_Progではまった事

FTDIのUSBチップのEPROMを操作できるFT_ProgというWindowsのプログラムがあります。このプログラムではUSBのディスクリプションを書き換えることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/2b2f60da-074b-bd35-b7b9-3c0fe449417c.png)

チップの挙動の確認のためにFT_ProgでVIDを0x0403から0x0400に書き換えてみました。

書き込んでUSBをさし直すと0x0400で認識されるので、ドライバーがロードされない警告音がでます。

さて元に戻そうとしたところFT_Progで認識できなくなっています。FT_ProgはFTDIのドライバーがインストールされているデバイスにしかアクセスできないようです。

果て困りました。

結論から言うとこれをやってしまうとWindows上では元に戻すことができません。

これはWindowsのライブラリのFT_OPENEXはドライバーがインストールされているデバイスしか開けないためです。WindowsのUSBフレームワークの制約なのではないでしょうか。

とりあえず認識できるようにするにはMacやFreeBSD(Linux)でEPROMを消去するか書き直す必要があります。消去すると元々入っていたシリアルなどのディスクリプタの内容は復元できません。

別の問題になりますが、EEPROMの中にはチェックサムがあって、それが正しくないとEEPROMの値が使われないようです。何らかの問題でチェックサムが壊れた状態で、FT_Progで書き込みをしてもチェックサムが正常に戻らないようです。

この場合もFT_Progでは修正できないので、EEPROMの値を消すプログラムを作って実行するのが良さそうです。

FT_Progでの操作はくれぐれもお気をつけください。

追記：

VIDを0x0400にした場合、そのデバイスにFTDIのドライバーを更新してやればFT_Progが使えるようになるのかもしれませんが、やり方わかりません。
Cross-site Scripting (XSS) の定義と分類

Cross-site Scripting (XSS) にはなぜ「cross-site」という表現が使われるのか？とふと疑問に思い、この背景を含め、XSSの一般的な定義について改めて調査した。

### 定義

[CWE-79](https://cwe.mitre.org/data/definitions/79.html)（参考：[JVNによる翻訳](https://jvndb.jvn.jp/ja/cwe/CWE-79.html)）では以下のような説明（ざっくりと要約している）となっている。

* 信頼できないデータがWebアプリケーションに入力され、それが適切に無害化されずに他者に提供されるWebページに出力されることで、他者のブラウザ上で悪意のあるスクリプトが正規のドメインのコンテキストで実行されてしまうこと。

### 分類

CWE-79ではXSSを以下の3つに分類している。

* Type 1: Reflected (Non-Persistent) XSS
	* HTTPリクエストのデータがそのままHTTPレスポンスに反映されて引き起こされるもの。典型的にはパラメータ付きURLがメール等で配布されることで被害者に渡る。
* Type 2: Stored (Persistent) XSS
	* 悪意のあるデータがDBやログ等に保存され、それが被害者に表示されることで引き起こされるもの。
* Type 0: DOM Based XSS
	* クライアントスクリプトがユーザー入力をWebページ（のDOM）に出力する際に発生するもの。（データがブラウザの外に出ない。）

一方でOWASP（参考：[Type of XSS](https://owasp.org/www-community/Types_of_Cross-Site_Scripting)）では、上記の3分類は重複があるとして脆弱性の所在に基づいた以下の分類との組み合わせ（Reflected or Stored x Server or Client）とすることを提案している。

* Server XSS
	* サーバーサイドの脆弱性によりHTTPレスポンスにスクリプトが埋め込まれる。
* Client XSS
	* クライアントサイドの脆弱性によりDOM更新時に不安全なJavaScript呼び出しが行われる。
	* DOM based XSSはこの一種（データソースがサーバーではなくDOMとなるパターン）となる。

例えば、Java (Servlet) で作られた掲示板システムでDBに保存されたユーザーの投稿をHTMLに出力する際に無害化がされていなかった、というケースはStored Server XSSに該当する。

### Cross-Siteと呼ばれる背景

いくつかのサイトに背景に関する説明があったが、いずれも以下のような内容であった。

* 当初は攻撃元サイトと攻撃先サイトの間でのcross-originアクセスを悪用した攻撃のことを指していたが、次第にブラウザに対するインジェクション攻撃として定義が拡張されていった。

参考

* [The origins of Cross-Site Scripting (XSS)](https://blog.jeremiahgrossman.com/2006/07/origins-of-cross-site-scripting-xss.html)
* [Wikipedia (英語版) - Background](https://en.wikipedia.org/wiki/Cross-site_scripting#Background)
* [Wikipedia (日本語版)](https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%82%B9%E3%82%B5%E3%82%A4%E3%83%88%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0)

### （蛇足）関連用語

XSSに似た用語としてHTML Injectionがしばしば登場するが、これには明確な定義は存在しないようである。CWEではHTML InjectionはStored XSSと同義とされている一方で、OWASP（参考：[Injection Theory](https://owasp.org/www-community/Injection_Theory)）ではXSS全体がHTML Injectionの一種となっている。
【JavaScript】関数とオブジェクト⑧　アロー関数とthis


#はじめに

Udemyの[【JS】ガチで学びたい人のためのJavaScriptメカニズム](https://www.udemy.com/course/javascript-essence/)の講座の振り返りです。

前回の記事

https://qiita.com/nao0725/items/2b448eda7996990b5d79

#目的

* 関数とオブジェクトについての理解を深める

#本題
###1.アロー関数とthis

アロー関数ではthisが使えない？？

####例1

``````javascript
window.name = 'ルフィ';

const person = {
    name: 'ゾロ',
    hello: function() {
        console.log('Hello ' + this.name);
    }
}
// ここではhello ゾロと出力される
person.hello();
`````

 thisにするとどうなるのか

``````javascript
window.name = 'ルフィ';

const person = {
    name: 'ゾロ',
    hello: () => {
        console.log('Hello ' + this.name);
    }
}
// hello ルフィと出力される！なぜ？
person.hello();
`````
`````javascript
window.name = 'ルフィ';

// personオブジェクトがグローバルコンテキストに定義されている
// thisはwindowオブジェクトを参照する
const person = {
    name: 'ゾロ',
    hello: () => {
        // アロー関数はthisを取らない
        // スコープチェーンを辿ってthisを探しに行く
        console.log('Hello ' + this.name);
    }
}
person.hello();
``````

####例2

オブジェクトのメソッドの中で呼ぶ場合

```javascript
window.name = 'ルフィ';

const person = {
    name: 'ゾロ',
    // helloを無名関数に直す（ES6からfunction省略できる！）
    hello(){
        console.log('Hello ' + this.name);
        // 実行するとエラーになる
        // 呼び出しの後に関数が宣言されてないから
        a();
    }
}
person.hello();
// このアロー関数ををオブジェクトの中で呼ぶ
const a = () => console.log("Bye " + this.name);
`````
アロー関数を前にもっていく

````javascript
window.name = 'ルフィ';
// この関数のレキシカルスコープがグローバルスコープになる
// ここでのthisはwindowオブジェクトになる
const a = () => console.log("Bye " + this.name);

const person = {
    name: 'ゾロ',
    hello(){
        // ここのthisは通常通り呼び出し元のpersonのnameを取る
        console.log('Hello ' + this.name);
        // ここで4行目のアロー関数が呼び出される
        a();
    }
}
// hello ゾロ
// Bye ルフィと出力される
person.hello();
``````

####例3

関数式を書いた場所で出力する値が変わってくる

`````javascript


window.name = 'ルフィ';
const person = {
    name: 'ゾロ',
    hello(){
        console.log('Hello ' + this.name);
        // もしここにアロー関数を定義したらthisの参照先はpersonになるので
        //  出力結果はBye ゾロになる
        const a = () => console.log("Bye " + this.name);
        a();
    }
}
person.hello();
``````

####例4

関数の中にアロー関数入れた場合

`````javascript
window.name = 'ルフィ';
const person = {
    name: 'ゾロ',
    hello(){
        console.log('Hello ' + this.name);
    }
}

function b() {
    // thisの参照先はwindowオブジェクト
    const a = () => console.log("Bye " + this.name);
    a();
}
// 出力結果はBye　ルフィ
b();
```````

今日はここまで！

#参考にさせて頂いた記事

* [【JS】ガチで学びたい人のためのJavaScriptメカニズム](https://www.udemy.com/course/javascript-essence/)
useRef + forwardRef での型解決

forwardRefを使って作成したコンポーネントのrefをいい感じにexportしたい。

調べたけどわざわざコンポーネントとRefの２つに分けてexportする方法しか調べられなかったけど、ひとまずはこれでワークするのでメモしておく。

```tsx
// my-button.tsx
import { Button } from "@3rd-party-lib";
export { Button as MyButtonRef };
export const MyButton = React.forwardRef<Button, Props>((props, ref) => {
  //...
  return <Button ref={ref}>{...}</Button>
});

// app.tsx
import { MyButton, MyButtonRef } from "~/MuButton";
const App = () => {
  const ref = useRef<MyButtonRef>(null);
  // ...
  return(
    <div>
      <MyButton ref={ref}>Awesome</MyButton>
    </div>
  )
}

```
Amplify Loggerの使い方

AWS Amplifyの utilitiesに loggerがある。
https://docs.amplify.aws/lib/utilities/logger/q/platform/js/


## 使い方


```javascript
import { Logger } from 'aws-amplify';

const logger = new Logger("my-logger");
logger.warn("warning message");
```

デバッグコンソールにはこのように出力される。

```terminfo
[WARN] 56:32.69 my-logger - warning message
```


注意点としては、インスタンスに指定されているレベル以上のログしか出力されないということ。
ログレベルは上から順に以下のようになっている。

- ERROR
- WARN
- INFO
- DEBUG
- VERBOSE


デフォルトのログレベルはWARN。
例えば、以下のようなloggerがある場合、WARN・ERRORのログでないと出力されないので `logger.info` を実行してもログは出力れない。

```javascript
import { Logger } from 'aws-amplify';

const logger = new Logger("my-logger");
logger.info("this is info message");  // これはconsoleに出力されない
```

INFOレベルのログを出したい場合は以下のようにインスタンス生成時にログレベルを指定しておく必要がある。

```javascript
import { Logger } from 'aws-amplify';

const logger = new Logger("my-logger", "INFO");
logger.info("this is info message");  // これならconsoleに出力される
```

## グローバルログレベルによる出力制御

また、グローバルログレベルを指定することで、インスタンスのログレベルを上書きすることができる。


```javascript
import { Logger } from 'aws-amplify';

const logger = new Logger("my-logger");
logger.info("this is info message");  // これはconsoleに出力されない

window.LOG_LEVEL = "INFO"; // グローバルログレベルを指定

logger.info("this is info message again!");  // これはconsoleに出力される
```


実践的な使い方としては、インスタンス作成時はデフォルトのログレベルにしておいて、環境ごとにグローバルログレベルを指定して出し方を変えるというやり方のほうが良さそう。

```javascript
const logger = new Logger("my-logger");

if (env === "development") {
  window.LOG_LEVEL = 'DEBUG';
else if (env === "staging")
  window.LOG_LEVEL = "INFO";
}

logger.debug("develop の環境のみで出力されるメッセージ")
logger.info("stagingとdevelop の環境で出力されるメッセージ")
logger.warn("production, staging, develop の環境で出力されるメッセージ")
```

こうしてやれば開発環境ではデバッグログを出したいが、本番ではWARN以上のログしか出したくない、という場合にもコードをいじらずにログを出せるので便利。


## 余談

もともとはこちらがやりたかったのだけど、CloudWatchProvider をセットすることで amplify loggerを通してCloudWatchにログを流せるみたい。

https://github.com/aws-amplify/amplify-js/pull/8309

ブログにも同じ記事を載せました。
https://jacoyutorius.hatenablog.com/entry/2021/10/23/072319?_ga=2.37304928.1379295306.1634940857-427508824.1591822362
ずっとFPGA初心者（その14：チャタリング検出(失敗?)）

# FPGAでチャタリング回数を検出できないかトライ
件名の失敗記録かもしれない。[その１](https://qiita.com/infinite1oop/items/4b0f03b97ed859fbd954)と同じOdyssey MAX10 FPGA Eval KitおよびQuartus利用。

## 何を期待していたか？
ボタン押下時、チャタリングが発生し、つまり、ロジック的にHighおよびLowを繰り返しがそれなりに発生するはず、、、その繰り返し数（Lowの回数）をLEDで表現しよう、、、と考えていた。

### コード
```vhdl
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all; -- necessary for conv_std_logic_vector

entity ChatTest is
  port (
    BTN0, BTN1 : in  std_logic;
    LED0, LED1, LED2, LED3, LED4, LED5, LED6, LED7 : out std_logic);
end;

architecture RTL of ChatTest is

signal LED: std_logic_vector(7 downto 0) := "11111111"; -- Off
signal CNT : integer := 0;  -- ①

begin
  LED0 <= LED(0); LED1 <= LED(1); LED2 <= LED(2); LED3 <= LED(3);  -- ②
  LED4 <= LED(4); LED5 <= LED(5); LED6 <= LED(6); LED7 <= LED(7);  -- ③

  process (BTN0)  -- ④
  begin
    if (BTN0'event and BTN0='0') then
--    if (BTN0='0') then  -- ⑤
      CNT <= CNT+1;       -- ⑥
    end if;
  end process;

  process (BTN1)  -- ⑦
  begin
    if (BTN1'event and BTN1='0') then
      LED <= not conv_std_logic_vector(CNT,8);  -- ⑧
    end if;
  end process;

end RTL;
```

- ①：ボタン押下数用カウンタ
- ②、③、④、⑦：同時処理
- ②、③：LEDピンへの代入
- ⑥：ボタン押下時にカウンタインクリメント
- ⑦、⑧：別ボタン押下時にカウンタ値をLEDに表示(LED0:LSB,LED7:MSBのビット表記)
- ⑤：これは文法エラーとなる

（ピンアサインメントは省略）

ボタン押下を続けても、チャタリングの様子をうまく検出できなかったような気がする。結果は次のとおり。

|押下回数|カウンタ値|
|:-:|:-:|
|1回目|2|
|2回目|3|
|3回目|5|
|4回目|6|
|5回目|8|
|6回目|13|
|7回目|18|
|8回目|19|

もっと激しい変化（カウンタ値の増加）を期待していたが、1回の押下で最大で5回の繰り返し（6回目と5回目との差分="13-8"および7回目と6回目との差分="18-13"）のみであった。

ちなみに、カウンタ値のLED表示の様子は下記のとおり。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634816/74c67f4c-beee-956d-823e-ff3da7b8c3ce.png", width=70%>

### 結論的には
オシロスコープと組み合わせて（波形を見て）、チャタリングの様子を確認する必要ありと判断。

## おまけ
FPGAでのチャタリング除去回路については、ネットで調べるとある程度見つかるようだ。そのうちトライしてみたい。
SHEのM1〜M5の生成

車載分野の仕事でSecure Hardware Extensions（SHE）を参照することがあり、その中に製品内の暗号鍵を更新する機能があるのですが、そこではM1〜M5の5つのパラメータが出てきます。

Secure Hardware Extensionsはこちら。鍵更新の説明は4.7.7節と4.9節。
https://www.autosar.org/fileadmin/user_upload/standards/foundation/19-11/AUTOSAR_TR_SecureHardwareExtensions.pdf

暗号鍵はセキュアに受け渡しをする必要があるため、新しい暗号鍵の生データを書き込むだけというような単純な仕様にはなっていません。新しい暗号鍵を別の暗号鍵で暗号化したデータや、そのデータに対するCMAC値などを受け渡しすることになっており、それがM1〜M5にあたります。

このM1〜M5を計算するツールが欲しいと思っていたのですが、意外と見つからなかったので、簡単なものを自作しました。

今回作ったスクリプトはこちら。
https://github.com/fukuda123/crypto/blob/main/20211023-she_m12345gen/m12345gen.py

使い方は、①Python3とPyCryptodomeをインストールし、②必要に応じてスクリプト内のいくつかの変数を変更し、③スクリプトを実行します。実行結果として、以下のようにM1〜M5の値が表示されます。

```
M1 = 00000000000000000000000000000141
M2 = 2b111e2d93f486566bcbba1d7f7a9797c94643b050fc5d4d7de14cff682203c3
M3 = b9d745e5ace7d41860bc63c2b9f5bb46
M4 = 00000000000000000000000000000141b472e8d8727d70d57295e74849a27917
M5 = 820d8d95dc11b4668878160cb2a4e23e
```
MELSEC-Qのデバイス設定

MELSEC-QのPCパラメータ デバイス設定 についての話です。

デバイス設定は活用していますか？人によってはラッチ設定以外触ったことがないというかもしれません。

使用できるデバイスの個数は可変なので使い方によって個数を増やしたり減らしたりすると便利ですという話。
全体の容量は決まっているが個々のデバイスの点数は変えれます。
そのため使わないデバイスがあるのであれば減らしてよく使うデバイスに点数を振ると便利です。
ホームセンターで売ってる仕切りの位置が変えれる小物ケースのイメージですね。

各デバイスの説明はここに書いています
[MELSEC-Qのデバイス解説](https://qiita.com/fa_yoshinobu/items/266c4cbd5514c3a388c2)

#デフォルト設定(Q06UDVCPUの場合)
下記はデフォルトの場合です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2146151/830dcf97-3fa7-1e76-2580-e3ccabd77a91.png)
例ではQ06UDVCPUを想定しています。ファイルレジスタは拡張SRAMカセットを使用せずに内蔵を全点(384K点)ZRに割り付けています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2146151/2ee7ce85-fa2c-8b82-ade9-fd0c40cbdcda.png)

#ケース1 増加:M,L 減少:F,V,S,T,SB,SW
M,Lを増やして私が思う使用頻度が少ないデバイスを減らしています。

Fは使うことが少ないです。
Vはループ内でパルス命令を処理する場合しか使わないので減らします。
SはSFC使わないので減らしています。(0点にすると警告がでてめんどくさいので最小設定です)
Tは1点につき1.125Word+2Bitを使用します。(T/C/STも同様)
そのためタイマ使用量を減らすと空きがたくさん増えます。
SB/SWは512点あればMELSECNET/H通信ユニット2枚分なので十分かと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2146151/8852463e-9ea7-6dca-5cde-0e35e47e6674.png)

#ケース2 増加:M,L,B,V,T,C,D,W 減少:F,S,SB,SW,ZR
もっと欲張りなケースです。
ビットデバイスとワードデバイス両方ともたくさん欲しいという場合ですね。
ポイントはデータレジスタ,リンクレジスタを0点にして他のデバイスに振って、
拡張データレジスタ,拡張リンクレジスタを使ってるところです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2146151/a71178c2-6358-b073-5e1b-afa31d8e8c5a.png)

#拡張データレジスタ,拡張リンクレジスタとは
ZRが大量にあっても使わないけどD,Wがたくさんほしいということはあるかもしれません。
ファイルレジスタをD,Wとして使う機能がユニバーサルモデルから追加されています。

拡張データレジスタ,拡張リンクレジスタを使う場合はデータレジスタ,リンクレジスタは0点にした方が良いです。
マニュアルにも書いてありますが、内部デバイスと拡張デバイスの境界線をまたぐような処理をするとまずいからです。（境界をまたいでの指定はOPERATION ERROR(エラーコード: 4101)になります。）
[SH-080802 QnUCPUユーザーズマニュアル(機能解説・プログラム基礎編)/4.8 拡張データレジスタ(D)，拡張リンクレジスタ(W)参照]
[SH-080804 MELSEC-Q/Lプログラミングマニュアル（共通命令編）/3.6 プログラミング時の注意事項]

残念なのは拡張データレジスタ,拡張リンクレジスタに自動割付デバイス設定はできません。そういう仕様だそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2146151/7041f934-305f-7fcb-c918-56de5c0d5822.png)


#ラッチ（1）,ラッチ（2）
ラッチ（1）はラッチ操作でクリア可能なラッチ範囲
ラッチ（2）はラッチ操作でクリア不可能なラッチ範囲

ということでラッチクリア操作可能か否かで区分されるようです。
ラッチクリアは古いCPUであればCPUのユニット前面スイッチ(L.CLR)でクリアすることが出来ましたがユニバーサルモデルはリモート操作のみになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2146151/4339ff14-ae6d-2db6-85a5-96109c632ae5.png)
Windows Subsystem for Android 備忘録

# 2022/10/21 追記

Microsoft Storeで Amazon Appstoreが提供されるようになりました。
よって下記のインストール手順は必要なくなりました。

ただ、動作させたいアプリが Amazon Appsotreで提供されていない場合、野良apkのインストールを adb経由で行わなければならない点は変わらないと思います。

# 本題

誰かの役に立つかもね。

ついに Windows Subsystem for Androidが公開されましたね。

Windows Insider Program Betaの限定公開ぽいけど、下記サイト辺り拝見したらそれっぽく動くようになりました。Thanks!

(という性質の記事なので、地雷踏んでもめげずに自分でどうにか出来る人だけやってね)
(責任取れねぇずら)

# インストール

- 最初に参考にさせて頂いた記事

https://halfcoin.blog.fc2.com/blog-entry-129.html

- 実際に動作させる為に実行した諸々が記載されてる記事

① Insider Program 非経由で WSAをインストール

https://www.xda-developers.com/how-to-run-android-apps-on-any-windows-11-pc/

② WSAで使う adbの準備

https://www.xda-developers.com/install-adb-windows-macos-linux/#adbsetupwindows

③ adb経由で apkインストール

https://www.xda-developers.com/how-to-sideload-android-apps-on-windows-11/

# 調べたこと

上記の通り、WSAで起動したアプリを adbで触れるかどうかが大切だったので、その辺分かった事を備忘録として残します。

- (私は iOS/Android共にマルチウィンドウ機能に触った事が無いので、技術的に正確なワードを使えていない可能性がありますので、詳しい方はどしどし指摘して下さい。)

- まず、Windows Subsystem for Androidでは、バックグラウンドで起動する Android Emuratorは 1つのみ。
    - だから`adb connect`する先は**Windows11の Windows Subsystem for Androidアプリ**の設定画面に表示される IP:PORTだけで OK.

- 複数の Androidアプリを起動した場合、それぞれのアプリが Android上において別ウィンドウで起動してる事になってる。
    - んで、Android内部では**それぞれのウィンドウに DisplayIDが付与**してある。

    

- その上で、Windows 11上の 1ウィンドウに対して Android上の 1アプリがまるっと描画されてる、という形になっている。

    - そんな状況になっているので、複数アプリ起動してる状況だと単に`adb shell input touchscreen tap 1 1`とかしてもどのアプリも反応しない。

    - 必要なのは`./adb.exe shell input touchscreen -d <DisplayID> tap 1 1`の -d オプション。

        - じゃあ DisplayIDはどうやって取得するんじゃ？という話で、
`./adb.exe shell dumpsys | Select-String "mDisplayInfo=DisplayInfo"`でアプリに対応する DisplayIDに見当は付けられました。
(もっと簡単な方法があったら教えて)

    - 後はぱぱぱっと DisplayID取り出して、-d オプションに渡してあげれば、指定アプリにイベント送れます。

## 追記後使用感  

- WSA起動後は、ディスプレイ全体が Androidのモニタとして利用される。
    - その弊害か、[開発者モード] -> [ポインタの位置]オプションを有効化すると WSAがクリックイベント全部吸ってしまって、Windowsとしての操作が概ね出来なくなる(Androidアプリのウィンドウ上以外のクリックが効かなくなる)ので気を付ける事。
    - キーボードイベントは Windowsが処理出来るらしく、Alt + Tabとかでアクティブウィンドウの変更とかすると、そのウィンドウ上だけはクリックイベントが無事に処理される(っぽい)。

- adbに connectするエミュレータの Port番号は[Android用Windowsサブシステム設定] -> [開発者]タブ -> [開発者モード]の説明欄 に表記されるようになった。

- 開発者向けオプションの最下辺りにある[アクティビティのサイズ変更を許可][フリーフォーム ウィンドウを有効にする][デスクトップ モードに強制的に切り替え][マルチウィンドウでのサイズ変更不可を有効にする]がそれぞれどのような挙動を設定するものなのか分からないけどとても気になる。誰か教えて。

# また 1つ、Windowsが便利な OSになってしまった…

個人的には Hyper-V好きなので、Noxとか Bluestackとか (VirtualBoxとか)の為に Hyper-Vを OFFにせざるを得なかった今まではちょっとぐんにょりしてたけど…

今日でサードパーティ製の仮想化ツールとはオサラバだ！！！

＼＼＼アプリ強制終了／／／

ん～～～～～～～、楽しいね！

これからもっと安定して便利になっていくと思うので、それも楽しみにしつつ今得られる便利を満喫していきましょう！
[terraform]Error: Unable to find remote state の解決例

## 出現したエラー文

```terminal
% terraform plan
aws_acm_certificate.root: Refreshing state... [id=arn:aws:acm:ap-northeast-1:433411958845:certificate/4db953e8-c43c-450b-bcb6-7ad4df85af1d]
aws_acm_certificate_validation.root: Refreshing state... [id=2021-09-29 15:42:40 +0000 UTC]
aws_route53_record.certificate_validation["michi-tonodeai.com"]: Refreshing state... [id=Z01310772SIZK0R0THIAO__ef4e7925349877fd30a5f544529b6303.michi-tonodeai.com._CNAME]
╷
│ Error: Unable to find remote state
│ 
│   with data.terraform_remote_state.network_main,
│   on data.tf line 1, in data "terraform_remote_state" "network_main":
│    1: data "terraform_remote_state" "network_main" {
│ 
│ No stored state was found for the given workspace in the given backend.
```

## 原因
エラー文的に~/network/mainディレクトリ内に記述がない、またはミスがあるように見える。
実際はエラーを吐いているファイル内、特に指定箇所の中かっこ内にタイプミスがあった。

## 解決方法
エラー文の指定箇所の近くの記述に誤りがないか探してみる。
ミスがなければ指定ディレクトリ（今回で言えば~/network/mainディレクトリ）の中のファイルの記述を確認する。
[terraform]Error: Failed to query available provider packages の解決例

##　出現したエラー文

```terminal
% terraform init                  

Initializing the backend...

Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.

Initializing provider plugins...
- terraform.io/builtin/terraform is built in to Terraform
- Finding latest version of hashicorp/teraform...
- Finding hashicorp/aws versions matching "3.42.0"...
- Installing hashicorp/aws v3.42.0...
- Installed hashicorp/aws v3.42.0 (signed by HashiCorp)
╷
│ Error: Failed to query available provider packages
│ 
│ Could not retrieve the list of available versions for provider hashicorp/teraform: provider registry registry.terraform.io does not have a provider named registry.terraform.io/hashicorp/teraform
│ 
│ All modules should specify their required_providers so that external consumers will get the correct providers when using a module. To see which modules are currently depending on hashicorp/teraform, run the following command:
│     terraform providers
╵
```

## 原因
エラー文を見るとproviderの指定が間違っているように見えるが、実際はdata.tfの中身のタイプミスによるエラーだった。

```terraform:data.tf
# ↓この行をミスしていた。正しくは"terraform_remote_state"だった。
data "teraform_remote_state" "network_main" { 
  backend = "s3"

  config = {
    buket  = "social-game-tfstate"
    key    = "${local.system_name}/${local.env_name}/network/main=v1.0.0.tfstate"
    region = "ap-northeast-1"
  }
}
```


## 解決方法
terraformのファイル(.tfファイル)のミスを修正し、再度`terraform init`を実行する。


## 調査で見つけた今回以外の例
バージョンアップに伴う題名のエラーの場合は下記の方法で直ることがあるようです。
https://discuss.hashicorp.com/t/terraform-0-13-terraform-init-fails-because-of-provider-required-by-state/13132
（Angular）Entry module not found: Error: Can't resolveでapp.component.cssが怒られる

pj作成の際にscssを選択したにも関わらず、app.component.tsのstyleUrlsは何故かcssになっており、Entry module not found: Error: Can't resolveと怒られます。

```app.component.ts
  styleUrls: ['./app.component.css']
```

scssで初期化した際は、正しくは下記です。

```app.component.ts
  styleUrls: ['./app.component.scss']

```
matlabで始めるディープラーニング　画像分類 part2

こちらの[記事](https://qiita.com/kaito_111/items/ea9241fcb8c784429df1?utm_campaign=post_article&utm_medium=twitter&utm_source=twitter_share)でモデルの構築を行いました。

今回は、作ったモデルをテストデータを用いて検証する方法を書きます。

前回のコード

```matlab:sample.m
%% データの読み込み
imds = imageDatastore('./pictures', 'IncludeSubfolders', true, 'LabelSource', 'foldernames');

%% データの分割
[trainData, testData] = splitEachLabel(imds, 0.6, 'randomized');

%% ニューラルネットワーク読み込み
net = vgg16;

%% ネットワーク層修正
layers = net.Layers;
numClasses = numel(categories(imds.Labels));
layers(39) = fullyConnectedLayer(numClasses);
layers(41) = classificationLayer;

%% ネットワークのインプットサイズに合わせて画像リサイズ
inputSize = net.Layers(1).InputSize(1:2);
augTrainData = augmentedImageDatastore(inputSize, trainData);
augTestData = augmentedImageDatastore(inputSize, testData);

%% 学習オプション
options = trainingOptions('sgdm', ...
    'MiniBatchSize',10, ...
    'MaxEpochs',6, ...
    'InitialLearnRate',1e-4, ...
    'Shuffle','every-epoch', ...
    'ValidationData', augTrainData, ...
    'ValidationFrequency',3, ...
    'Verbose',false, ...
    'Plots','training-progress');

%% 学習
netTransfer = trainNetwork(augTrainData, layers, options);
%% テストデータで予測

[predLabels, scores] = classify(netTransfer, augTestData);
```

検証はこちらの続きから書いていきます。

```
%% テストデータを用いてモデル精度の検証
testDataLabels = testData.Labels;
correct = nnz(testDataLabels == predLabels);
DataCount = numel(testData.Labels);
accuracy = correct / DataCount;

%% 可視化
% 真のラベルと予測したラベル
confusionchart(testDataLabels, predLabels);
```

``accuracy``こちらの中に正答率が格納されます

画像のように縦軸を真のクラス、横軸を予測したラベルとして分布表が現れます。
![スクリーンショット 2021-10-23 2.52.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/712534/a9c8d705-895d-8e0e-dfa0-b89e4d75d7ef.png)


#### 今後やること
この記事の修正を行い、もう少し詳しく書いていきます。 
ブログへ移行しましたので、興味ある方はぜひ見てください.


## ブログへ移行
[part1](https://o-kailog.com/mldp1/)
[part2+少し詳しく](https://o-kailog.com/mldp2/)
Pipenvの仮想環境でコマンドの実行履歴を表示できないエラーの対処

## エラー内容
Windows10のコマンドプロンプトで`pipenv shell`を実行して仮想環境に入ると、上下キーによるコマンド履歴が利かなくなる。本来であれば、上下キーを押すと過去に実行したコマンドを順番に表示することができるのだが、仮想環境内では上下キーを押しても何も表示されない。仮想環境を出ると上下キーは復活する。

実行環境：

* Windows10 Home バージョン21H1 OSビルド19043.1237
* Pipenv version 2021.5.29

## 解決方法
`pipenv run cmd`を代わりに実行する。

## 解説
「pipenv command prompt history」で調べると、以下のissueがヒット。
[up/down arrow history doesn't work on pipenv shell on windows](https://github.com/pypa/pipenv/issues/876)
その中で、[このリプライ](https://github.com/pypa/pipenv/issues/876#issuecomment-401634800)を試したところ解決した。
以下はその日本語訳。

> (いくつか試してみて)やっと分かりました。`pipenv run cmd`を実行すると、その環境が使えるようになり、そこからIDEを起動することもできるようになります(VS Codeなら`code .`)。また、VS Codeの中のターミナルからもpipenvで入れたものを確認できます。
>
>**そして**、コマンド履歴も利きます(上矢印で)。
>
>とりあえずこれが利かせる方法のようです。何か欠点があるかは気になりますが。

[Windowsの pipenv shellでも履歴機能が使いたい](https://qiita.com/kangetsu121/items/615ea332a6b9b6767f35)にはPowerShellを使う回避策も紹介されている。一応参考までに。

## まとめ
Pipenvで入った仮想環境で上下キーが利かないときは、`pipenv run cmd`を試してみるといい。対症療法ではあるが、ひとまずなんとかなると思われる。
seleniumでURLを入力し,そのページを開こう！

#前置き：
C言語だと出力はprintf入力はscanfというのをすぐに学習しましたが、
pythonは出力であるprintだけ知って入力を知らないままでした...
ちょうどselenium関係でコードを書くとき必要になったので勉強していきます





#準備：
まずpythonでの入力ですが、input関数というものを使います。
以下使用例です。

```input.py
#基本的な使い方
url = input()
print(url)

#入力の指示文を表示させる
url2 = input('ここにURLをペーストしてね')
print(url)

```
とりあえずこんな感じでしょうか、

seleniumのインストールは今回割愛します。

#サンプルコード
input関数についてinputしたところで、実行できたコードを以下に載せます

```scraping.py
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import chromedriver_binary
import time

# ブラウザを開く。
driver = webdriver.Chrome()

#1秒待機
time.sleep(1)

#URLを入力
url = input('URLを入れてください')

#検索
driver.get(url)

```
一応これで無事に走ってくれると思います。
boto3でECSを使ってブログ開設するまでを自動化

# 開発前の状態

* 今後の仕事でAWSを触ると聞き，知識ゼロなのでヤバみを感じた
* とりあえず本を買って勉強して雰囲気は掴んだ気になっている
    * https://www.amazon.co.jp/Amazon-Web-Services-基礎からのネットワーク-サーバー構築/dp/4822237443
* GUIぽちぽちすればやりたいことはできると感じたが，さらなるステップアップをするためにはどうしたらいいか悩んだ
* これまでの仕事でAnsibleなどによる環境構築自動化や，dockerなどのコンテナ技術のありがたみは非常に実感していた
* なので，
    * 環境設定をすべて自動化し
    * EC2上での作業を予めDockerImage化しておいてデプロイところまで頑張ってみたいと思った

# コード

https://github.com/fugashy/aws_network_and_server_sample

## やっていること

* VPCからECSのサービス開始までを全自動化
    * VPC，Subnetなどを依存関係に注意して作成していく
    * EC2としてはECS Optimized AMIを使用
        * ecs-agentが動いている
    * 最終的には，以下のような構造になる
        * VPC
            * PublicSubnet
                * WebServer（Wordpress）
            * PrivateSubnet
                * DB Server（MariaDB）
* 用がすんだらEnterキーを押してすべてKill
    * 課金の元になるEC2やNAT，EIP含めすべて削除
    （途中でなにかしらの異常でコケたら手動で消す必要がある）

# 結果や感想

* PublicIpにブラウザからアクセス，WordpressとDBの接続を完了できた．
![Screen Shot 2021-10-23 at 0.04.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374528/6728e2c4-fcf0-33a1-18b0-e033fc845106.png)
* インフラをプログラムしてる感じが新鮮だった
* boto3では依存に気を使って削除する必要があるため，各種リソースの依存関係をデバグの過程で体感できた．
* 特にECS with boto3については情報が見つかりにくかったので，client APIやAWSの各種ドキュメントの調査をする機会が得られた
    * この過程でECSの用語（クラスター，タスク，サービス）をつかめてきた

# 今後やりたいこと

* 環境変数に含まれるセンシティブな情報はS3から取得するようにする
* ECSタスク起動イベントをひろって，LAMBDAからNATを停止する処理を入れる
* メトリクスについて理解を深める
* SMMエージェントを使ってみる
    * https://dev.classmethod.jp/articles/ecs-instance-ssm-pre-install/
* CloudFormationでやってみる
Ruby Leet文字列に変換

# はじめに
新しく学んだLeet文字列の変換

## Leet文字列とは

たとえば、「Warez」という語を leet で表記すると、「W@rez」や「W4r3z」などとなるように、一部のアルファベットを形の似たアラビア数字や記号などに変化させる。

表記法は、「for」や「to」をそれぞれ似た発音の「4」や「2」で代用したり、同様に「you」を「u」と置き換えたり、複数形の「s」を「z」に変えたり、「cks」または「ks」で終わる単語を「x」に差し替えたり、故意に綴りを誤って表記したり、大文字と小文字を混在させたりするなど、多様である。

## 問題

| 変換前 | 変換後 |
|:------|:------|
| A | 1 |
| B | 2 |
| C | 3 |
| D | 4 |
| E | 5 |

## コード

結論から言うとこのコードで実装することができました。
次に一つ一つの解説をしていきます。

```Ruby:qiita.rb
word = gets.chomp.split('')
word.each do |w|
  case w
  when 'A'
    print '1'
  when 'B'
    print '2'
  when 'C'
    print '3'
  when 'D'
    print '4'
  when 'E'
    print '5'
  else
    print w
  end
end
```

## 解説

まずはじめに入力を受け付ける`gets.chomp`
入力された文字列を`splitメソッド`を使う。
`splitメソッド`とは文字列を分解し配列にするメソッドです。

```Ruby:qiita.rb
word = gets.chomp.split('')
```

これで`変数word`に分解された文字列が配列として代入することができました。

次は実際に変換して出力するコードを書いていきます。

`変数word`は配列なので、`each文`を使い出力します。
しかしそれだけでは、ただ配列にした意味がありません。
そこで`case文`を使います。

`case文とは`
「if」文では複数の条件式を組み合わせて複雑な分岐を行う事ができますが、一つの値に対して複数の候補の中で一致するものを探すような場合には「case」文を使用する。



```Ruby:qiita.rb
word.each do |w|
  case w
  when 'A'
    print '1'
  when 'B'
    print '2'
  when 'C'
    print '3'
  when 'D'
    print '4'
  when 'E'
    print '5'
  else
    print w
  end
end
```
これで全ての条件式を通し該当するものは変換されて該当しないものは変換せずに出力することができました。

## 終わりに

自分の学習用ですので説明が分かりづらいところもあると思いますが、参考にしていただけると幸いです。
npm run devのエラー改善

Laravelでトップ画面をsassで作ろうとしたところ、
下記のようなエラーが出てしまいました。

```
ERROR in ./resources/sass/app.scss
Module build failed (from ./node_modules/css-loader/index.js):
ModuleBuildError: Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
ValidationError: Invalid options object. Sass Loader has been initialized using an options object that does not match the API schema.
```

どうやらNode.jsをインストールできていなかったことが原因だったみたいなので、
インストールを実行。

※インストール用のURLはこちら
https://nodejs.org/ja/download/

そのあと、npm run devを実行しても、もう一度エラーが出たので、下記を実行。

```
npm uninstall --save-dev sass-loader
npm install --save-dev sass-loader@7.1.0
```

これは、npmのsass-loaderのバージョンをアップグレードするものだそうです。

これにより、Compiled successfullyの文字が出て完了です。
[AtCoder][ABC168D] BFS探索における経路復元

## 概要

重みづけなしグラフにおける最短経路はBFSを使うことで求めることができる。
またそのときの経路の復元方法を説明する。

手順としてはBFSをしつつ１つ前の頂点を配列に記憶する。

```cpp:BFS適用
vector<int> prev(N, -2); // -2は経路未確定を示す
prev[0] = -1; // -1はこれ以上戻れないことを示す
queue<int> q;
q.push(0);
while (!q.empty()) {
    int current = q.front(); q.pop();
    for (int next: E[current]) {
        if (prev[next] >= -1) continue;
        prev[next] = current;
        q.push(next);
    }
}
```

経路を復元するには-1にあたるまでprev配列を戻っていけばよい。

```cpp:経路復元
int current = 3; // 頂点3までの最短経路を復元する。
while (current != -1) {
    cout << current << " ";
    current = prev[current];
}
```

## 練習問題

この問題を解いてみる。
[ABC168 D - .. (Double Dots)](https://atcoder.jp/contests/abc168/tasks/abc168_d)

内容としてはグラフが与えられるので頂点1から各頂点への最短経路を求めて、各頂点から１つ前の頂点を出力する。

```cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;

int main() {
    int N, M;
    cin >> N >> M;
    vector<vector<int>> E(N, vector<int>());

    for (int i=0; i<M; i++) {
        int a, b; cin >> a >> b;
        a--; b--;
        E[a].push_back(b);
        E[b].push_back(a);
    }

    vector<int> prev(N, -2);
    prev[0] = -1;
    queue<int> q;
    q.push(0);
    while (!q.empty()) {
        int current = q.front(); q.pop();
        for (int next: E[current]) {
            if (prev[next] >= -1) continue;
            prev[next] = current;
            q.push(next);
        }
    }

    for (int a: prev) {
        if (a == -2) {
            cout << "No" << endl;
            return 0;
        }
    }

    cout << "Yes" << endl;
    for (int i=1; i<N; i++) {
        cout << prev[i]+1 << endl;
    }
}
```
podman でマルチアーキテクチャ/マルチプラットフォーム対応コンテナイメージを作成する

# これは何?

podman を使ったマルチプラットフォーム対応イメージ作成のメモです

# 結論

[qemu-user-static](https://github.com/multiarch/qemu-user-static) を初期化した後、manifest 付きでビルドし、push します.

dockerhub に push する場合、下記のようになります. `--format` 指定をしない場合、 dockerhub でプラットフォームが表示されません.

```console
podman run --rm --privileged docker.io/multiarch/qemu-user-static --reset -p yes
podman build --platform linux/amd64,linux/arm64 --format docker --manifest hogehoge .
podman login --username foo docker.io
podman manifest push --format v2s2 hogehoge docker://docker.io/foo/hogehoge
```

# 確認した環境

Windows 10 21H1 の WSL2
podman 3.4.1

# 注意点

podman の version が古いと `--platform` に同時に複数のプラットフォームを指定できません。
次のように複数回 `--platform` を指定してください。

```console
podman build --platform linux/amd64 --platform linux/arm64 --format docker --manifest hogehoge .
```

# 参考

https://zenn.dev/tnk4on/articles/6067d7e827c471
Docker コンテナ関連のコマンド一覧

PowerShell開いてDocker開いてUbuntu のコンソール内に入ったとします。
以下のコマンドはWindows や macOS のコンソールで共通で使用するものです。
コンテナ（Ubuntu）の中のコンソールでは使いません。

|コマンド  |目的  |
|---|---|
| docker-compose up -d |Docker コンテナを起動する  |
| docker-compose exec app bash | コンテナの中のコンソールに入る |
| docker-compose ps -a | コンテナの一覧を見る |
| docker-compose down | コンテナを終了・破棄する |

DockerのLinuxの起動手順は

```
cd ~\(Linuxのファイルとして使ってるワークスペース)\(Linuxとして使うファイル)
docker-compose up -d
docker-compose exec app bash	
```

`docker-compose down`はコンテナ内で`exit`を入力後に使います
①コンテナ内で`exit`を入力するとコンテナのコンソールから出ていきます。
②次に`>`の後ろに`docker-compose down`を入力します。
コンテナ内のコンソールから出ているため、コピペできます
TTGO T-Display で MicroPython を使ってみた

# 目的

- MicroPythonを自分の TTGO T-Display で使ってみる。
- T-Display の TFT で何か表示できるようにする。


# thanks to

https://kreier.github.io/t-display/
https://github.com/kreier/t-display
https://qiita.com/ganessa/items/8938e8e0ac6118ace9b1
https://blog.goediy.com/?p=905

# setup

- install python3
- install esptool.py

```bash
$ pip install esptool
```

- download firmware 

https://github.com/kreier/t-display/releases/download/v0.1/firmware.bin

- burn it

```bash
$ esptool.py --port /dev/cu.SLAB_USBtoUART flash_id
$ esptool.py --port /dev/cu.SLAB_USBtoUART erase_flash
$ esptool.py --chip esp32 --port /dev/cu.SLAB_USBtoUART --baud 460800 write_flash -z 0x1000 firmware.bin
```

# demo run

- execute `thonny.app`
- open device `MicroPython (ESP32)`
- open script `ttgo_hello.py` or `hello_world.py`
- run the script.

# memo
- another method for uploading script:

```bash
$ pip install adafruit-ampy
$ ampy -p /dev/cu.SLAB_USBtoUART put main.py 
```

# 追記

こちらのページの情報でもセットアップできた。

https://www.instructables.com/TTGO-color-Display-With-Micropython-TTGO-T-display/

この方がフォントが私好みだった。`main.py`はほんの少し書き直させてもらった。

```main.py
import machine, display

tft = display.TFT()

tft.init(tft.ST7789,bgr=False,rot=tft.LANDSCAPE, miso=17,backl_pin=4,backl_on=1, mosi=19, clk=18, cs=5, dc=16)

tft.setwin(40,52,320,240)

for i in range(0,241):
    color=0xFFFFFF-tft.hsb2rgb(i/241*360, 1, 1)
    tft.line(i,0,i,135,color)
    tft.set_fg(0x000000)
    tft.ellipse(120,67,120,67)
    tft.line(0,0,240,135)
#    tft.font(tft.FONT_Default, rotate=0)
    tft.font(tft.FONT_DejaVu18, rotate=0)
#    tft.font(tft.FONT_DejaVu24, rotate=0)
#    tft.font(tft.FONT_Ubuntu, rotate=0)
#    tft.font(tft.FONT_Tooney, rotate=0)
    text="ST7789 with micropython!"
    tft.text(120-int(tft.textWidth(text)/2),67-int(tft.fontSize()[1]/2),text,0xFFFFFF)
```
Udemy「ネットワークエンジニアを目指す初心者はここから始めよう！「ゼロから学ぶネットワーク基礎」1022

IP概要
・IPとはInternet Protocolのこと。
・インターネット層（ネットワーク層）に相当する。
・レイヤー3プロトコルのデファタクトスタンダードとなっている。
・IP Version4(IPV4)とIP Version6(IPV6)の２つがある。
・IPと書く場合はIP Version4を指すことが多い。

通信方法
・IPパケットにアドレスを入れて通信する。
・送信元アドレス、Sourceアドレスは自分のこと。
・宛先アドレス、送信先アドレス、Destinationアドレスは相手のこと。
・宛先アドレスが存在する方向にだけIPパケットを送信する。
・宛先が違うIPパケットは自分には届かない。


IPパケット（１）
・標準的なサイズは20バイト（OptionとPaddingを除く）になる。
・32ビットずつ縦に書くことがある。
・Optionは可変長、32ビットに満たない場合はPaddingで調整する。
・PAYLOAD（ペイロード）は上位レイヤーのデータ部分を意味する。


IPパケット（２）
・Version 
　・IPのバージョンを示す。IP Version 4であれば4が入る。
・IHL(Internet Header Length)
　・ヘッダの長さを32ビット単位で示す。通常は５が入る。
・Type of Service(ToS）
　・IPパケットの重要度の応じて優先度を付ける時に使う。
　・Quality Of Service(QoS)で使われる。
・Total Length
 ・IPパケット全体の長さ（IPヘッダおよびデータ）をオクテット単位で示す。
・Identification
　・フラグメントされたIPパケットを戻す時の識別子。同じ識別子は同じIPパケットと判断する。


フラグメント
・フラグメント（断片化）とはペイロードのサイズが大きく、リンク層プロトコルで運べるサイズを超えている場合にペイロードを複数に分割しえそれぞれにIPヘッダをつけること。
・最終的には再度、１つのIPパケットに戻す。
・元が同じIPパケットを判別するための識別子がIdentificationとなる。


IPパケット（３）
・Flags
 ・先頭１ビットは使用しない（０が入る。）
・２ビット目はDFと呼び、０はフラグメント可能、１はフラグメント禁止を意味する。
・３ビット目はMFビットと呼び、２ビット目が０の時、０はフラグメントされた最後のIPパケットを意味し、１の場合はさらにフラグメントされたIPパケットが続くことを意味する。
・Fragment Offset
　・フラグメントされたIPパケットの位置を示す。Identificationで同じグループを判断し、Fragment Offsetから正しい配置を知ることで元のIPパケットに戻せる。
・Time to Live(TTL)
　・IPパケットの寿命を示す。0〜255の値が入り、IPパケットを転送する際には１を減らす。
　・０となったIPパケットは破棄される。


IPパケット（４）
・Protocol
　・上位レイヤーで使われているプロトコルを示す。
　・代表的なところでは１はICMP、６はTCP、17はUDPを意味する。
・Header Checksum
　・IPヘッダの誤り検査に使われる。　Ethernetフレームとは違い、IPパケットではヘッダ部分のみが検査対象になる。
・Source Address
　・送信元を示すIPアドレスが入る。
・Destination Address
　・宛先を示すIPアドレスが入る。


IPアドレス概要
・ネットワーク全体の中で自分の所在を示す。
・32ビット（二進数32桁）の長さを持つ。
・8ビットずつドットで区切り、十進数表記する。
　・0.0.0.0〜255.255.255.255の範囲になる。
　・8ビットの塊の部分を第○オクテットと呼ぶことがる。
・IPアドレスはユニークである。
・所属グループと自分を表す２階層になっている。

11000000101010000000000000000001
      　　　　↓
11000000.10101000.00000000.00000001
   　　　　　　↓
         192.168.0.1

クラスフル
・約42億個ものアドレスを扱いやすいように５つのクラス（グループ）に分ける。

クラスA   0.0.0.0 〜  127.255.255.255
クラスB 128.0.0.0 〜  191.255.255.255
クラスC 192.0.0.0 〜  233.255.255.255
クラスD 224.0.0.0 〜  239.255.255.255→マルチキャスト用
クラスE 240.0.0.0 〜  255.255.255.255→将来のために予約

・IPアドレスはグループと自分自身の２階層
 ・ネットワーク部＋ホスト部

クラスA 8ビット＋24ビット
クラスB 16ビット＋16ビット
クラスC 24ビット＋8ビット

クラスの見分け方
・二進数に変換して先頭4ビットを見る。
クラスA 　　 0.0.0 〜 127.255.255.255
クラスB 128.0.0.0 〜 191.255.255.255
クラスC 192.0.0.0 〜 223.255.255.255
クラスD 224.0.0.0 〜 239.255.255.255
クラスE 240.0.0.0 〜 255.255.255.255
↓
クラスA 0   0000000
クラスB 128 1000000
クラスC 192 1100000
クラスD 224 1110000
クラスE 240 1111000
PythonのOpen3D環境構築とチュートリアル実行

こんばんは～
今回はPythonのPointCloudを処理できるライブラリ　***Open3d***の環境構築をしていきたいと思います！

きっかけは普段C++×PCLでポイントクラウドをいじりまくっているんですが、
PythonでのPointCloud処理が必要になったのでついでにいろいろやってみました～って感じです

# Open3dとは
Pythonを用いてPointCloudのデータを処理できる非常に優秀なライブラリです
C++でのPCLみたいなことがPythonでできちゃうのでとても好きです
ちなみにC++×Oped3Dも可能です

docはこちら

http://www.open3d.org/docs/release/index.html


# Python 3.6 or 3.7 or 3.8　環境構築
Open3Dは、2021/10/22現在，Pythonの最新バージョン```Python 3.9.*```に対応していません．対応バージョンは```Python 3.6 3.7 3.8```です．そこで，これらのバージョンをインストールしつつきれいに管理しましたっていう記事がこちらです．

https://qiita.com/kosei1515/items/98cadf2322981290b835

今回は```Python 3.6```の仮想環境を，```C:\venv\Python36```フォルダに構築した状態を仮定して進めます
Python3.6の環境構築ができてない人や，いろんなバージョンを管理したいと思っている人も是非この記事を参考にしてください！

# Open3D install
まずは仮想環境に入ります．コマンドプロンプトを開き，仮想環境のScriptsフォルダにあるactivate.batを実行します

```
C:\venv\python36\Scripts\activate.bat
```

そうするとこんな感じでpython3.6の仮想環境上でコマンドを入力できます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633039/9ec004d0-2441-1cf6-6ee8-27a4206ba2b0.png)

続いてOpen3Dをインストールします

```
pip install open3d
```

これでインストールが完了します
この後チュートリアルを実行するのですが，その際に```numpy```, ```matplotlib```, ```opencv-python```を使うと書いてあったのでこちらもついでにインストールしました

```
pip install numpy matplotlib opencv-python
```

ここでひとまず仮想環境から抜けます

```
deactivate
```

# Open3D-masterのクローン
今回はデスクトップにクローンします
公式に以下のような記述があったのでクローンする際には必ず以下のコードを実行します

> Make sure to use the ```--recursive``` flag when cloning Open3D.

```
cd ~\DeskTop
git clone --recursive https://github.com/intel-isl/Open3D

# You can also update the submodule manually
git submodule update --init --recursive
```

これができたらもう一度仮想環境に入り，jupyter-notebookを起動します．

```
cd Open3D-master
C:\venv\python36\Scripts\activate.bat # your python 3.6 environment
jupyter-notebook
```

すると以下のようなライブラリがサイト上で起動します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633039/50a35077-0abf-ca5a-91c0-d5ed2ae8c322.png)

この中の```exmples```にDocにあるチュートリアルのプログラムが詰まっています！
例えば、Geometryのpointcloud.ipynbを実行してみます
(場所  ```examples\python\geometry```)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633039/2b85cb6e-7f63-28ae-6f88-b1859a9c0559.png)
こんな感じにいろんな処理をしたPointCloudが表示されます

以上です!
おつした～
ほかにもMeshやKD-Treeなどいろんなチューリアルがあるのでぜひ試してみてください！

# 関連
scoop

https://qiita.com/kosei1515/items/98cadf2322981290b835

pcl

https://qiita.com/yuzsh/items/42bb8ac904f5e9837599
i18n の hash をフラットにする

## やりたいこと

https://github.com/svenfuchs/rails-i18n/blob/v6.0.0/rails/locale/ja.yml の翻訳ファイルを [i18n](https://github.com/ruby-i18n/i18n) を使って読み込むと、以下のような hash を取得できます。

```rb
require 'i18n'

I18n.load_path << 'rails/locale/ja.yml'
I18n.locale = :ja
I18n.t('.')
#=>
# {:activerecord=>{:errors=>{:messages=>{:record_invalid=>"バリデーションに失敗しました: %{errors}", :restrict_dependent_destroy=>{:has_one=>"%{record}が存在しているので削除できません", :has_many=>"%{record}が存在しているので削除できません"}}}},
#  :date=>
#   {:abbr_day_names=>["日", "月", "火", "水", "木", "金", "土"],
#    :abbr_month_names=>[nil, "1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
#    (省略)
#  :datetime=>
#   {:distance_in_words=>
#     {:about_x_hours=>{:one=>"約1時間", :other=>"約%{count}時間"},
#      :about_x_months=>{:one=>"約1ヶ月", :other=>"約%{count}ヶ月"},
#      (省略)
#    :prompts=>{:second=>"秒", :minute=>"分", :hour=>"時", :day=>"日", :month=>"月", :year=>"年"}},
#  :errors=>
#   {:format=>"%{attribute}%{message}",
#    :messages=>
#     {:accepted=>"を受諾してください",
#      :blank=>"を入力してください",
#      (省略)
```

これを以下のようなフラットな hash に変換したいです。

```rb
{
  "activerecord.errors.messages.record_invalid" => "バリデーションに失敗しました: %{errors}",
  "activerecord.errors.messages.restrict_dependent_destroy.has_one" => "%{record}が存在しているので削除できません",
  "activerecord.errors.messages.restrict_dependent_destroy.has_many" => "%{record}が存在しているので削除できません",
  "date.abbr_day_names"=>["日", "月", "火", "水", "木", "金", "土"],
  "date.abbr_month_names"=>[nil, "1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
  # 省略
  "datetime.distance_in_words.about_x_hours.one" => "約1時間",
  "datetime.distance_in_words.about_x_hours.other" => "約%{count}時間",
  "datetime.distance_in_words.about_x_months.one" => "約1ヶ月",
  "datetime.distance_in_words.about_x_months.other" => "約%{count}ヶ月",
  # 省略
  "datetime.prompts.second" => "秒",
  "datetime.prompts.minute" => "分",
  "datetime.prompts.hour" => "時",
  "datetime.prompts.day" => "日",
  "datetime.prompts.month" => "月",
  "datetime.prompts.year" => "年",
  "errors.format" => "%{attribute}%{message}",
  "errors.messages.accepted" => "を受諾してください",
  "errors.messages.blank" => "を入力してください",
  # 省略
}
```

例えば言語ファイル (YAML) を複数に分割している場合に、すべての翻訳データを列挙するためにこのようなフラットな hash を取得したいです。

## 方法

ネストした hash を再帰的に処理してフラットな hash に変換するためのメソッドを用意します。

```rb
def flatten_nested_hash(hash, previous_key: nil, flat_hash: {})
  hash.each do |key, value|
    current_key = [previous_key, key.to_s].compact.join('.')
    
    if value.is_a?(Hash)
      flatten_nested_hash(value, previous_key: current_key, flat_hash: flat_hash)
      next
    end
    
    flat_hash[current_key] = value
  end
  
  flat_hash
end

flat_hash = flatten_nested_hash(I18n.t('.'))
flat_hash['datetime.distance_in_words.about_x_hours.other']
#=> "約%{count}時間"
I18n.t('datetime.distance_in_words.about_x_hours.other')
#=> "約%{count}時間"
```
【Excel関数】文字列の中からJAN(13桁の数字)だけを複数抽出したい&そのJANをコンマ区切りで並べたい（MID/FIND/TEXTJOIN）

#1.やりたいこと
①下表からJANのみ抜き出したい
②抜き出したJANを「JAN, JAN, JAN, …」とコンマ&半角スペース区切りで羅列したい

<img width="300" alt="1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/2acff896-f43e-8a1a-0392-6a11c1def479.png">
（実際に使った表はJANが50件ほど。今回はサンプルとして5件にした。）

#2.やったこと
##①余分な行を削除（手作業）
<img width="300" alt="3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/19e5ec52-9f66-c101-9d2e-f071d70185ec.png">
本当はこの作業も自動化したいのだけれど、今回は手作業でやりました。
VBAを使えばできるのかな？？要勉強。

##②関数を入力
<img width="400" alt="5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/d6651bc7-c4ce-234d-e6c2-ce21164f49ef.png">
◆使った関数◆（例：セルA2の場合）
`=MID(A2, FIND("45",A2),13)`
「セルA2中の文字列"45"を見つけて、そこから"45"を含む13文字を抽出するよ」

|関数書式|意味|意味引用元|
|:--|:--|:--|
|MID(文字列, 開始位置, 文字数)|文字列の任意の位置から指定した分の文字を取り出す|『30時間で~』p196|
|FIND(検索文字列, 対象, 開始位置)|文字列を検索する（大文字と小文字を区別する）|[Excel関数](http://www.excel-list.com/find.html)|
※『30時間で~』＝『30時間でマスターExcel2019』（実教出版株式会社）

◆こちらの記事を参考にしました◆

https://ja.extendoffice.com/excel/formulas/excel-extract-word-beginning-with.html

##③抜き出したJANをコンマ&半角スペース区切りで羅列する
<img width="700" alt="7.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/e65cebe8-2d56-7e80-e30b-c77584c0dbf7.png">
◆使った関数◆
`=TEXTJOIN(", ",TRUE,F2:F6)`
「セル"F2:F6"の文字列の間に区切り記号と半角スペース", "を挿入しながらすべて連結するよ」

|関数書式|意味|意味引用元|
|:--|:--|:--|
|TEXTJOIN(区切り記号, 空の文字列を無視, 文字列1, 文字列2, ..., 文字列252)|区切り記号を挿入しながら複数の文字列を連結する|[できるネット](https://dekiru.net/article/14504/)|

##④関数の入ったセルをコピー&値貼付け
<img width="700" alt="8.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/b2f7c213-71bb-745f-ac4c-b8dbd6790421.png">
関数の入ったセル（上図のみどり色の点線枠）をコピー　
↓
セルH2で右クリック
↓
値り貼付けのオプションで「値（V）」（上図の赤枠）をクリック
↓
値として貼付け完了！


これで目的のJAN一覧が取得できました。

#3.できなかったこと
##①「①余分な行を削除」の自動化。
今回は手作業で不要な行を選択→一括削除したけれど、もっと件数が増えた場合、手作業は厳しい。
「不要な行やセルを削除する」ための関数、あるいはVBAがあるのなら、使えるようになりたい。
VBAならばそのような機能がありそう。
追って調べる。

##②桁数のみで抽出
今回は全て「45」から始まるJANだったので、「45から始まる13文字」と指定することで抽出できた。
今後、JANに限らず「〇桁の数字を抽出したい」という場面に遭遇する可能性あり。
「〇桁の数字」という条件で抽出することは可能なのだろうか？
VBA？？
【Flutter】誕生日から年齢、月齢を求める

誕生日から年齢を求めることはなんとかできますが、月齢を計算するのはなかなか大変ですよね。。
とっても簡単に取得できるパッケージがありました！作ってくれた人ありがとうございます😭
age_calculator

http://47.240.41.80/packages/age_calculator

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

void main() {
  DateTime birthday = DateTime(1997, 3, 5);

  DateDuration duration;

  // 今日が 2021-03-08　の場合。。
  duration = AgeCalculator.age(birthday);
  print('Your age is $duration'); // Your age is Years: 24, Months: 0, Days: 3

  final year = duration.years;
  final month = duration.months;
  final day = duration.days;
  return '$year歳$monthヶ月$day日'; // 24歳0ヶ月3日

  //Find out your age on any given date
  duration = AgeCalculator.age(birthday, today: DateTime(2030, 5, 1));
  print('Your age is $duration'); // Your age is Years: 33, Months: 1, Days: 26

  // Find out when your next birthday will be at 2021-03-08
  duration = AgeCalculator.timeToNextBirthday(birthday);
  print('You next birthday will be in $duration');
  // You next birthday will be in Years: 0, Months: 11, Days: 25

  // Find out when your next birthday will be on any given date
  duration = AgeCalculator.timeToNextBirthday(birthday,
      fromDate: DateTime(2021, 3, 2));
  print('You next birthday will be in $duration');
  // You next birthday will be in Years: 0, Months: 0, Days: 3

  // Find out the difference between two dates
  duration = AgeCalculator.dateDifference(
    fromDate: DateTime(2021, 1, 2),
    toDate: DateTime(2025, 5, 2),
  );
  print('The difference is $duration');
  // You next birthday will be in Years: 4, Months: 4, Days: 0

  // Add time to any date
  DateTime date = AgeCalculator.add(
      date: DateTime(2021, 1, 2),
      duration: DateDuration(years: 5, months: 2, days: 1));
  print(date);
  // 2026-03-03 00:00:00.000
}
```


他にも次の誕生日とかも簡単に求めることができます！！！
コードは公式からお借りしました！！
作ってくれた方本当に感謝ですーーーーーーー！！！！！！！