OmniAICreator/Qiita-1.07M huggingface dataset:
foreground通知

Swiftでは、1つのファイルに複数のクラスや拡張を記述できますが、基本的な慣習として、1つのファイルには一般的に1つのクラスが記述され、それに関連する拡張が同じファイルに含まれることが多いです。

しかし、CommonViewControllerの通知に関連する処理だけを別のファイルに拡張として記述することもできます。その場合、ファイルを分割することでコードがシンプルになります。

CommonViewController.swift:

```swift
import UIKit

class CommonViewController: UIViewController {

    // 通知以外の共通処理をここに記述

}
```

CommonViewController+Notification.swift:

```swift
import UIKit

// MARK: - Notification Handling
extension CommonViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        setupNotificationObservers()
    }

    deinit {
        removeNotificationObservers()
    }

    private func setupNotificationObservers() {
        // 通知の設定
        NotificationCenter.default.addObserver(self, selector: #selector(appDidEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(appDidEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
    }

    private func removeNotificationObservers() {
        // オブザーバーの解除
        NotificationCenter.default.removeObserver(self)
    }

    @objc private func appDidEnterForeground() {
        // フォアグラウンドに入った時の共通処理
        print("アプリがフォアグラウンドに入りました")
    }

    @objc private func appDidEnterBackground() {
        // バックグラウンドに入った時の共通処理
        print("アプリがバックグラウンドに入りました")
    }
}
```

このようにして、通知に関する処理を別ファイルに分離することができます。これにより、コードの見通しが良くなり、保守性が向上します。

またCommonViewControllerを継承した他の画面のViewControllerで、通知の処理を共有することができます。継承によって、CommonViewControllerの通知処理が他の画面にも引き継がれ、フォアグラウンドやバックグラウンドの検知が可能になります。

例えば、以下はCommonViewControllerを継承した別の画面での実装です：

```swift
class YourSpecificViewController: CommonViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // 画面固有の処理を実装
    }

    // CommonViewControllerの通知処理がここで共有される
}
```

CommonViewControllerの通知処理は`YourSpecificViewController`でも共有され、`YourSpecificViewController`がフォアグラウンドやバックグラウンドに入ると、CommonViewControllerの通知メソッドも呼ばれます。このように簡単に共通の処理を他の画面で利用できます。
Java学習 演算子

# 演算子
演算子には「代数演算子」と「比較演算子」がある。
どちらの演算子でも、使用する記号も演算の行い方もRubyと同じ。

## 代数演算子
### 種類
|演算子  |使い方  |意味    |
| :---: |:----: | :---: |
|+      | a + b | 加算   |
|-      | a - b | 減算   |
|*      | a * b | 乗算   |
|/      | a / b | 除算   |
|%      | a % b | 剰余   |

### 使い方
```java
class Main {
    public static void main(String[] args) {
        System.out.println(1 + 2);
        System.out.println(10 - 5);
        System.out.println(2 * 3);
        System.out.println(100 / 4);
        System.out.println(11 % 3);
    }
}
```
下記は出力結果
```
3
5
6
25
2
```

## 比較演算子
### 種類
|演算子  |使い方   |意味                     |
| :---: |:-----: | :--------------------: |
|==     | a == b | aとbが等しい場合true      |
|<      | a < b  | aがbより小さい場合true    |
|>      | a > b  | aがbより大きい場合true    |
|<=     | a <= b | aがb以下の場合true       |
|>=     | a >= b | aがb以上の場合true       |
|!=     | a!= b  | aとbが等しくない場合true  |

# まとめ
Javaで使用する演算子の種類(記号と意味)はRubyと同じ。
使い方もRubyと同じ。
おみくじを改良しました

おみくじを改良しました

```Ruby
########################################
# おみくじプログラム           #########
########################################

#乱数を発生させる
num = rand(100)
flag1 = 0
while flag1 == 0 do
  # 0以下の整数と整数以外が入力されたら例外処理で再度整数入力を促す
  begin

    if num >= 0 then
      flag1 = 1
    else
      raise StandardError.new()
    end
  rescue => e
    e = "0以下の整数および整数以外は入力できません"
    puts e
  end
end
# 5で割る
ans = num % 5
# 5で割った余りでおみくじの結果を表示する。
if ans == 0
    puts("大吉")
elsif ans == 1
    puts("中吉")
elsif ans == 2
    puts("吉")
elsif ans == 3
    puts("小吉")
elsif ans == 4
    puts("凶")

end

```
C言語で文字列を表示

# C言語表示する方法

```c
#include <stdio.h>
int main(void){
    return 0;
}
```
上がC言語に原型となる形です。
そこから
# printf("")を利用します。
```c
printf("〇〇");
```
プログラムをつけくわえます
```c
#include<stdio.h>
int main(void){
    printf("〇〇");
    return 0;
}
```
〇〇の中に文字をいれることでPCに表示していきます。

# また今度会いましょう
Proxmox VEのCPU Pinning(Affinity)

# CPU Pinningとは
プロセスに割り当てるコアを限定することでパフォーマンスの向上を図ること。仮想マシンが複数相乗りするProxmox VEの場合、各VMが全体のコアをばらばらに参照するのではなくコアをきっちり分けた方がCPUのキャッシュが効率的に機能しやすい。またAMDのRyzenの場合複数CCXのモデルが存在し（59XX、79XX等）CCXを跨ぐと遅延が出やすいため、その場合にも有効ではないかと考えられる（要検証）
この設定はそのプロセスに対して設定されているだけであり、他のプロセスにとっては排他的になっているわけではないので他にPinningされていないVMがある場合はそのコアは使われてしまう点注意

# コアのID等確認

cat /proc/cpuinfoでCPUの各コアの番号を確認できるが見づらいので、awkスクリプトを作成した。

```bash
gawk -F'[\t]*: ' '/^physical id/ {ps_id=$2} /^processor/ {id=$2} /^core id/ {core_id=$2} /^$/ {printf "physical:%s\tcore:%s\tid:%s\n",ps_id,core_id,id}' /proc/cpuinfo
```

実行すると下記のように出力される（AMD Ryzen 5700Xの場合）
このCPUはCCXは1つ、物理コアは8つである。16スレッドの内14スレッドをVMに割り当てる。使用するコア番号は1〜7にした。隣のid列の番号で1〜7、9〜15が今回の利用対象となる

```
physical:0      core:0  id:0
physical:0      core:1  id:1
physical:0      core:2  id:2
physical:0      core:3  id:3
physical:0      core:4  id:4
physical:0      core:5  id:5
physical:0      core:6  id:6
physical:0      core:7  id:7
physical:0      core:0  id:8
physical:0      core:1  id:9
physical:0      core:2  id:10
physical:0      core:3  id:11
physical:0      core:4  id:12
physical:0      core:5  id:13
physical:0      core:6  id:14
physical:0      core:7  id:15
```

# VMへの設定

管理画面で設定。CPUアフィニティという欄で範囲指定に"-"と","が使用できる

![0006-01-12 8.24.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65278/864e4b7b-d4ff-02dd-7aa0-ed74c41d4efd.png)

# 反映しているかの確認

VMのプロセスIDをまず特定する。引数にVMの名前が含まれているので、それを元に抽出。

```
root@sv01:~# ps ax | grep Windows10-Game
 929664 ?        SLl    5:21 /usr/bin/kvm -id 107 -name Windows10-Game,debug-threads=on -no-shutdown -chardev socket,id=qmp,path=/var/run/qemu-server/107.qmp,server=on,wait=off -mon chardev=qmp,mode=control -chardev socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5 -mon chardev=qmp-event,mode=control
```

混じっているが、/usr/bin/kvmのプロセスが該当のもの。この場合idは929664。
次にpinningの設定を確認する

```
root@sv01:~# taskset -p 929664
pid 929664's current affinity mask: fefe
```

`fefe`となっている部分は16進数で、これを2進数にしたものが設定となる。[変換サイト](https://hogehoge.tk/tool/number.html)を利用して、`1111111011111110`ということがわかる。値は後ろから順番に並んでいる（一番右がid0で一番左がid15）
![スクリーンショット 0006-01-16 4.57.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65278/fb32c8ae-cbf4-56c9-7423-3726e6447ded.png)

試しにaffinityの欄を消して、再起動したところ下記の通り全体指定となった
```
root@sv01:~# taskset -p 926835
pid 926835's current affinity mask: ffff
```
イギリス最大の冤罪事件：富士通の会計システムが引き起こした悲劇

皆さん、イギリスの富士通の冤罪事件ご存じですか？
https://news.yahoo.co.jp/pickup/6487790

## 事件の概要

2000年から2014年の間に、イギリスで700人以上の郵便局長が横領や不正経理の無実の罪を着せられました。これは富士通が開発した会計システム「ホライゾン」の欠陥が原因で、この事件は「イギリス史上最大の冤罪事件」とも呼ばれています。

「ホライゾン」システムでは、送金の中断、突然の電源断、画面のフリーズなどの障害・不具合が多発していました。
バグでデータと現金残高の不一致が生じ、無実の郵便局長たちは窃盗や不正経理の罪を着せられ、離婚や破産、自殺する人もいました。

## 事件の影響とその後の対応

現在も公聴会が開かれており、ポスト・オフィスと富士通、そして英政府がシステムの欠陥を知っていたのかが焦点となっています。また、被害者への補償についても議論されています。

## プログラム開発者としての教訓

このような事例は、プログラムを作る人間として、その責任の重さを改めて認識する機会となります。プログラムの欠陥が人々の生活に深刻な影響を及ぼす可能性があるため、品質管理とテストは非常に重要です。

富士通に限らず、全てのIT企業がこの事件から学び、同様の事態を未然に防ぐための対策を講じるべきです。この事件は、IT業界全体にとって大きな教訓となります。

## エンジニア、プログラマーとして冤罪を防ぐためにできること

2023年、イギリスで富士通が開発した会計システムの不具合により、数百人の郵便局長が冤罪で逮捕されるという事件が発生しました。この事件は、プログラムの誤りが重大な社会的被害をもたらす可能性があることを示す、非常に深刻な問題です。

エンジニア、プログラマーとして、このような事件を防ぐためにできることは何でしょうか。

### 1. プログラムの品質を徹底的に検証する

最も重要なことは、プログラムの品質を徹底的に検証することです。プログラムの誤りを防ぐためには、単純なテストだけでなく、さまざまな角度からテストを実施する必要があります。また、テストの実施は、開発者だけでなく、独立した第三者機関が行うことも重要です。

### 2. プログラムの安全性を確保する

プログラムの安全性を確保することも重要です。プログラムが悪意のある攻撃を受けないように、脆弱性を排除する必要があります。また、プログラムが誤った入力を受け付けないように、入力チェックをしっかりと行うことも重要です。

### 3. プログラムの使用目的を理解する

プログラムの使用目的を理解することも重要です。プログラムがどのような目的で使われるのかを理解することで、プログラムの誤りがもたらす影響を予測し、対策を講じることができます。

### 4. 倫理的な責任を自覚する

エンジニア、プログラマーとして、倫理的な責任を自覚することも重要です。プログラムの誤りが重大な社会的被害をもたらす可能性があることを認識し、常に安全で正確なプログラムを開発するよう努めることが必要です。

富士通の事件は、エンジニア、プログラマーにとって大きな警鐘となりました。今後は、このような事件が再び起こらないように、プログラムの品質と安全性の確保に努めることが重要です。

# まとめ
エンジニア、プログラマーとして冤罪を防ぐためには、以下の4つが重要です。

プログラムの品質を徹底的に検証する
プログラムの安全性を確保する
プログラムの使用目的を理解する
倫理的な責任を自覚する
具体的には、以下の点に注意する必要があります。

単純なテストだけでなく、さまざまな角度からテストを実施する
脆弱性を排除し、誤った入力を受け付けないようにする
プログラムがどのような目的で使われるのかを理解し、影響の予測と対策を講じる
プログラムの誤りが重大な社会的被害をもたらす可能性があることを認識し、常に安全で正確なプログラムを開発する
富士通の事件は、プログラムの誤りが重大な社会的被害をもたらす可能性があることを示す、非常に深刻な問題です。エンジニア、プログラマーは、このような事件を防ぐために、常にプログラムの品質と安全性の確保に努める必要があります。
Basic認証についてまとめてみました。

## はじめに
私がいる現場のシステムでは、検証環境にのみBasic認証が利用されております。
テストのために一部の画面やBLに対してこれをを外したりすることもあったので、
そもそもBasic認証（基本認証と呼ばれることも）とは何だろう？と思いまとめてみました。

## Basic認証とは
Webサーバーで利用できる簡易的な認証方式で、
主にWebサイトの特定のページや階層に対するアクセスを制限するために利用します。
また、IDとpasswordを入力するだけで認証することができます。

## Basic認証の特徴
- Base64でエンコードして送信してやりとりする
- Base64なのでセキュリティ的には弱い
- 「`.htaccess`」と「`.htpasswd`」を作って、ログイン情報に関するコードをそれぞれに記述するだけで設定可能

よく利用されるシーンとしてはクライアントに公開目前のサイトや、
仲間内メンバーなどでしか使わない簡易的なサイトなどが多いようです。

## メリット
- ログイン情報がブラウザに記憶される
- Cookie情報が残っている限りは認証が有効
- アクセス制限がディレクトリ単位で可能
⇒特定の画像やPDFファイル、ビジネスロジックにかけることも可能です
- ファイルを置くだけでも設定可能
⇒レンタルサーバーなどで利用制限がある場合はファイル作成自体ができないこともあるので注意

## デメリット
- セキュリティが弱い
⇒Base64でエンコードして送信しているので、データが暗号化されないままやり取りされます。
- 同一サーバー内のディレクトリのみで複数のサーバーに横断することは不可
- 検索で表示不能（クローラーもアクセスできなくなる）
⇒SEOとしての効果は期待できません。

## Basic認証設定の流れ
認証をかけたいディレクトリに.htaccessファイルと.htpasswdファイルを作成します。

AuthType: 認証方式を指定
AuthName: 任意の認証名
AuthUserFile: .htpasswdファイルの場所
require: 認証範囲（valid-userですべてのユーザーに認証を表示させる）

```.htaccess
AuthUserFile /home/hogehuge/.htpasswd
AuthName "input ID and Password"
AuthType Basic
require valid-user
```
IDとパスワードのセットで記載します。
複数行記載すれば、複数のID,passwordを使用可能です。
```.htpasswd
userId:password
```

## まとめ
これを設定する側としてファイルを作成したり修正することが今後あるかはわからないですが、
認証方式の1つとして理解することができたことはよかったと思います。
もしBasic認証についてざっと知っておきたい方がいらっしゃれば、
本記事を参考にしていただけると幸いです。
HTMLでJavaScriptを読み込む方法

# はじめに
HTMLでJavaScriptを読み込む方法について学んだので，アウトプットしていきます．

# 方法1：JavaScriptをHTML内に記述する
`script`タグ内にJavaScriptのコードを書いていく．HTMLの読み込みが途中で止まらないように，`body`タグの最後に書くことが奨励されている．
```html
<body>
    <header></header>
    <main></main>
    <footer></footer>
    <script>
        //ここにJavaScriptのコードを記述
    </script>
</body>
```

# 方法2：JavaScriptを外部ファイルとして読み込む
`script`タグの`src`属性にJavaScriptファイルを指定する．
```html
<body>
    <header></header>
    <main></main>
    <footer></footer>
    <script src="hogehoge.js"></script>
</body>
```

### 参考サイト
https://techplay.jp/column/577
Rubyで予期しない型の問題を回避するために

Rubyでは予期しない型の問題を回避するために、いくつかのアプローチがあります。これらはプログラムの堅牢性を高めるために重要です。

1. **型チェックの実施**: 明示的に引数の型をチェックして、期待される型でない場合はエラーを投げるか、適切な処理を行う。

   ```ruby
   def multiply(a, b)
     raise TypeError, "aは数値でなければなりません" unless a.is_a?(Numeric)
     raise TypeError, "bは数値でなければなりません" unless b.is_a?(Numeric)
     
     a * b
   end
   ```

2. **`respond_to?` メソッドの使用**: オブジェクトが特定のメソッドを持っているかどうかをチェックする。これは柔軟性を保ちつつ、メソッドの存在を確認するのに役立つ。

   ```ruby
   def add(a, b)
     unless a.respond_to?(:+) && b.respond_to?(:+)
       raise NoMethodError, "a と b は加算可能でなければなりません"
     end

     a + b
   end
   ```

3. **ダックタイピング**: Rubyの哲学に基づき、オブジェクトのクラスよりも、そのオブジェクトがどのように振る舞うか（どのメソッドに応答するか）に注目する。

   ```ruby
   def print_length(obj)
     if obj.respond_to?(:length)
       puts obj.length
     else
       puts "#{obj} には長さがありません"
     end
   end
   ```

4. **Optional Typing or Soft Typing**: 最近のRubyのバージョンでは、RBSやSorbetのようなツールを使用して、オプショナルな型注釈を提供することができます。これは静的型チェックを可能にし、型の問題を早期に発見するのに役立ちます。

5. **単体テスト**: Rubyアプリケーションに対して厳密な単体テストを行うことで、予期しない型の問題を発見しやすくなります。テストフレームワーク（RSpecなど）を使用して、さまざまな入力タイプに対する関数の振る舞いをテストします。

これらの方法を組み合わせることで、Rubyプログラムの型に関連する問題を効果的に回避できます。重要なのは、プログラムがさまざまな入力に対してどのように反応するかを理解し、期待される振る舞いを保証することです。
Rubyにおける予期しない型の問題(Javaと比較)

予期しない型の問題は、特に動的型付け言語でよく見られます。Rubyの例を使って、このような問題を示します。

### Rubyにおける予期しない型の問題

Rubyでは、変数の型が実行時まで決定されないため、予期しない型の値が渡されると、エラーが発生するか、または意図しない振る舞いが起こり得ます。

```ruby
# Ruby の例
def multiply(a, b)
  a * b
end

puts multiply(5, 3)    # 期待通りの乗算: 出力は 15
puts multiply("5", 3)  # 文字列の繰り返し: 出力は "555"
```

上記の例では、`multiply` メソッドは2つの引数を乗算します。最初の呼び出しでは、両方の引数が整数なので、期待通りの乗算結果が得られます。しかし、二番目の呼び出しでは、一方の引数が文字列であるため、Rubyは文字列を繰り返す動作をします。この挙動は意図していない可能性があり、バグの原因になりえます。

### 静的型付け言語での対応

対照的に、静的型付け言語ではこのような問題が発生しにくいです。Javaで同じ関数を書くと、型の不一致によりコンパイルエラーが発生します。

```java
// Java の例
public class Example {
    public static int multiply(int a, int b) {
        return a * b;
    }

    public static void main(String[] args) {
        System.out.println(multiply(5, 3)); // 整数の乗算: 出力は 15
        // System.out.println(multiply("5", 3)); // コンパイルエラー
    }
}
```

このJavaの例では、`multiply` メソッドは整数のみを引数として受け入れるため、文字列を渡そうとするとコンパイル時にエラーになります。これにより、実行前に問題を発見しやすくなります。

### 結論

動的型付け言語では、実行時に異なる型が渡されることによる予期しない動作やエラーが発生しやすいです。これに対して、静的型付け言語ではコンパイル時に型のチェックが行われるため、この種の問題を未然に防ぐことができます。
動的型付け(Ruby)と静的型付け(Java)の違い

RubyとJavaの違いを説明する際、動的型付け（Ruby）と静的型付け（Java）の違いが重要なポイントです。これらの違いを理解するために、両方の言語で同じ機能を実現する簡単な例を用いて説明します。

### 動的型付け: Ruby

Rubyは動的型付け言語です。これは、変数の型が実行時に決定されることを意味します。型の宣言は必要ありませんし、同一の変数に異なる型の値を代入することも可能です。

```ruby
# Ruby の例
def add(a, b)
  a + b
end

puts add(5, 3)    # 整数の加算: 出力は 8
puts add("5", "3")  # 文字列の連結: 出力は "53"
```

この例では、`add` 関数はどのような型の引数でも受け入れ、それらを足し合わせます。整数が渡されれば足し算をし、文字列が渡されれば連結します。これはRubyが実行時に型を決定するため可能です。

### 静的型付け: Java

Javaは静的型付け言語です。つまり、変数の型はコンパイル時に決定され、一度決定した型の変数に異なる型の値を代入することはできません。

```java
// Java の例
public class Example {
    public static int add(int a, int b) {
        return a + b;
    }

    public static void main(String[] args) {
        System.out.println(add(5, 3)); // 整数の加算: 出力は 8
        // System.out.println(add("5", "3")); // コンパイルエラー
    }
}
```

このJavaの例では、`add` メソッドは整数のみを引数として受け入れます。文字列を渡そうとすると、コンパイル時にエラーになります。Javaでは、すべての変数の型がコンパイル時に決定されるため、実行時に型の不一致によるエラーが発生する可能性が低くなります。

### 結論

- Ruby（動的型付け）では、変数の型が柔軟であり、実行時に変更が可能ですが、予期しない型の問題が発生するリスクがあります。
- Java（静的型付け）では、変数の型が厳格であり、型の不一致によるエラーをコンパイル時に検出できますが、柔軟性が低いです。

このように、動的型付けと静的型付けの違いは、柔軟性と安全性のバランスをどのように取るかということに関連しています。
Apache Cassandra® 4.0の発表

<font color="Grey">*[Announcing Apache Cassandra® 4.0](https://aiven.io/blog/announcing-apache-cassandra-4-0)の翻訳です。*</font>

2021年12月16日

# Apache Cassandra® 4.0の発表

AivenはApache Cassandra® 4.0をサポートするようになりました。これは2015年にリリースされたApache Cassandra® 3.0以来のメジャー・バージョンアップです。

Apache Cassandra 4.0は、安定性の向上、パフォーマンスの改善、高速化で特に注目されています。Cassandra 4.0は、読み取りと書き込み操作のスループットを最大25%高速化し、Zero Copy Streamingを活用してデータを最大5倍高速にストリーミングします。


## 最新情報


Cassandra 4で導入された主な機能を紹介します：


* 仮想テーブルによるメトリックの強化
* 完全なクエリ・ロギングによるワークロード再生
* コンプライアンス強化のための監査ロギング
* ゼロ・コピー・ストリーミング


\*まだ利用できませんが、近日中にAiven for Apache Cassandraに含まれる予定です。


すべての新機能の詳細は、Cassandra 4.0のWebページに記載されています：  

<https://cassandra.apache.org/doc/4.0/cassandra/new/index.html>


## Apache Cassandra 4.0の始め方


これらの機能を利用するには、Apache Cassandra 4.0にアップグレードしてください。すでにAiven for Apache Cassandra 3を使用している場合は、簡単にインプレース・アップグレードを実行して最新バージョンの使用を開始できます。


まだAiven for Apache Cassandraを使用していませんか？30日間の無料トライアルで最新のCassandraバージョンをお試しください。


## まとめ


Aivenのサービスをまだご利用でない方は<https://console.aiven.io/signup>から無料トライアルにお申し込みください！


また、[changelog](https://aiven.io/changelog)や[blog](https://aiven.io/blog)のRSSフィード、または[LinkedIn](https://www.linkedin.com/company/aiven/)や[Twitter](https://twitter.com/aiven_io)のアカウントをフォローし、製品や機能関連の最新情報をご確認ください。
【Django REST Framework, React】新規登録でトークンが見つからない問題

# 起きている問題
新規登録を実行した時に、なぜかログイン状態が保持されず、ログイン画面まで戻ってしまう。
（ログアウト状態では、ログイン画面に自動的に遷移するように設定してある）


デベロッパーコンソールは下記↓
```
SignupComponent.js:31 Token saved: undefined
```

ネットワークタブの```users/```のResponseは下記。
見ての通り、レスポンスボディに```token```フィールドが含まれていません。↓
```
{"id":5,"username":"abcde","email":"abcde@gmail.com"}
```

また、Djangoのログに ```Generated token for user {username}: {token.key}``` の出力が確認できません。

# 原因考察
```views.py```の```signup_view```には、下記のように設定してあります。
```python
logger.debug(f"Generated token for user {username}: {token.key}")
```

しかしDjangoのログに ```Generated token for user {username}: {token.key}``` の出力が確認できないことから、Djangoの ```signup_view``` からのレスポンスデータにトークンが含まれていないことにあると考えられます。

これは、トークンの生成またはレスポンスデータへの含め方に問題がある可能性があります。

### Djangoシェルでのトークン生成テスト
Djangoのシェルを使用してトークン生成を手動でテストしてみます。
```
docker exec -it mangabot_backend_1 python manage.py shell
```

```python
from django.contrib.auth import get_user_model
from rest_framework.authtoken.models import Token

user = get_user_model().objects.get(username='your_username')
token, created = Token.objects.get_or_create(user=user)
print(token.key)
```
これらのステップを踏んだ結果、正常にトークンが生成されたので、Djangoのトークン生成自体には問題がありませんでした。

トークンがシェルで正常に生成されているにもかかわらず、APIを通じてフロントエンドにトークンが渡らない場合、問題は ```signup_view``` 関数またはその周辺のコード（例: シリアライザー、ビューセット、ルーティングなど）にある可能性があります。

# 解決
**結論：** シリアライザの定義が原因だった。

下記のように、```CustomUserViewSet``` が ```CustomUserSerializer``` を使用している場合、このシリアライザの定義がレスポンスデータの形式に直接影響を与えます。

```views.py
class CustomUserViewSet(viewsets.ModelViewSet):
    queryset = get_user_model().objects.all()
    serializer_class = CustomUserSerializer
```


 ```CustomUserSerializer```を確認していきます。（元々のコード）↓


```serializers.py
class CustomUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = get_user_model()
        fields = ('id', 'username', 'email', 'password')
        extra_kwargs = {'password': {'write_only': True}}

```

上記の ```CustomUserSerializer``` は ```id, username, email, password``` フィールドを持つように定義されています。

しかし、このシリアライザには ```token``` フィールドが含まれていないため、新規ユーザー登録のレスポンスにトークンが含まれない原因となっています。

トークンをレスポンスに含めるには、```CustomUserSerializer``` にトークンフィールドを追加する必要があります。
以下のように変更します。

```python
class CustomUserSerializer(serializers.ModelSerializer):
    token = serializers.SerializerMethodField()

    class Meta:
        model = get_user_model()
        fields = ('id', 'username', 'email', 'password', 'token')
        extra_kwargs = {'password': {'write_only': True}}

    def get_token(self, obj):
        token, created = Token.objects.get_or_create(user=obj)
        return token.key
```

無事レスポンスデータにトークンが含まれるようになり、新規登録ができました！
pythonでhex読み込み

Pythonで16進エディタを作りたかったのですが、まずはバイナリデータを表示するところまでです

```py
def print_hex(filename, length=256):
    """ 指定されたファイルの最初の 'length' バイトをヘックス形式で表示 """
    with open(filename, 'rb') as file:
        data = file.read(length)
        hex_data = data.hex()  # バイナリデータを16進数の文字列に変換
        formatted_hex = ""
        for j in range(0, len(hex_data), 32):  # 16バイト（32文字）ごとに処理
            line = ""
            for i in range(j, min(j + 32, len(hex_data)), 2):  # 各バイト（2文字）ごとに処理
                byte_hex = hex_data[i:i+2]
                line += byte_hex + " "
            formatted_hex += line.strip() + "\n"  # 末尾の空白を削除し、改行を追加
        print(formatted_hex)

print_hex('test.txt')
```
InternetExplorerの終焉とJavaアプリケーションとアプレットの意味

[マイクロソフトはInternet Explorerのメインストリームサポートを2022年6月に終了することを発表した](https://docs.microsoft.com/en-us/lifecycle/faq/internet-explorer-microsoft-edge#:~:text=Internet%20Explorer%20is%20a%20component,systems%20starting%20June%2015%2C%202022.)。その時点で、IE11デスクトップアプリケーションは使用できなくなり、Microsoft Edgeにリダイレクトされます。

Microsoft Edgeがこの責任とそれ以上のことを引き受けることができるようになったため、Internet Explorer 11デスクトップアプリケーションは、Windows 10の特定のバージョンにおいて、2022年6月15日に引退し、サポートを終了します。

1995年に発売されたInternet Explorerは、今日の消費者市場では長い間無用の長物となっていたが、多くの古い企業向けソフトウェアやウェブサイトはIEでしか動作しない。マイクロソフトの委託調査によると、企業は平均して1,678のレガシー・アプリケーションを使用しており、それらのアプリケーションの多くはJavaで構築されている。

# これはJavaアプリケーションにとって何を意味するのだろうか？
一般に信じられていることとは裏腹に、Javaは死滅したとはいいがたく、実際には2番目に人気のあるプログラミング言語である（2018年にはJavaScriptの後塵を拝している）。エンタープライズ・アプリケーションは、内部であれサードパーティであれ、Java AppletまたはJava Swingクライアントとしてデプロイされたクライアントを含むことがまだ多い。

これらのアプリケーションにアクセスするために残された唯一の方法は、各クライアントマシンにローカルJavaをインストールし、Internet Explorer 11またはEdgeのインスタンスを「Internet Explorerモード」にしておくことだ。

# 2021年以降のJavaアプリケーション
Javaはサーバー側とクライアント側のアプリケーションに優れた環境を提供するが、最近のエンタープライズ・アプリケーションはHTML5標準への移行が進んでいる。これは、幅広いブラウザ、デバイス、環境にわたる幅広い互換性を活用することで、ユーザーの要望を満たし、セキュリティを向上させるためです。

Internet Explorer 11では毎月セキュリティアップデートが提供されますが、Microsoft Edgeでは数時間とは言わないまでも、数日以内に脆弱性に対するセキュリティパッチが提供されます。

同様に、Chrome、Chromium、Firefox、Safariのような他の最新ブラウザは、Javaアプレットやアプリケーションと互換性がありませんが、セキュリティやアップグレードやパッチの頻度の点で望ましい選択肢でしょう。

# CheerpJでJavaアプリケーションを自動的に変換し、モダンブラウザ上で実行
Javaアプリケーションのフロントエンドを完全に書き直すことは、（アプリケーションがサードパーティの場合）しばしば不可能であったり、コストや時間的な問題から現実的でなかったりします。

モダンブラウザ上でJavaフロントエンドにアクセスしたいと考えている組織にとって、新しいアプローチは、WebAssemblyとJavaScriptのおかげで、変更されていないフロントエンドを自動的にHTML5に変換することである。

Leaning Technologiesが開発したツールCheerpJは、[既存のJavaクライアント・アプリケーションをHTML5に変換・移行する唯一のソリューション](https://cheerpj.com/)である。あらゆるSwingクライアント、Javaアプレット、Javaライブラリに使用できる。ソースコードに変更を加えることなく、Javaアプリケーションを最新のブラウザで使えるようにすることで、Javaアプリケーションの寿命を延ばし、時間、コスト、リソースを節約することができます。

# なぜCheerpJなのか？
CheerpJは、Java 8（Oracleフォーム、EBS、Swing、AWT、多数のフレームワークやライブラリでテスト済み）、ファイルシステムへの読み書きアクセス、ネットワーク、印刷、その他多くのシステム機能との幅広い互換性を持っています。

CheerpJはいろいろな使い方ができますが、最も標準的なのは、先読み変換です。この場合のCheerpJの使い方は、とても簡単です：

・CheerpJ AOTコンパイラを使って、アプリケーションのすべての.jarアーカイブを変換します：

・CheerpJライブラリを統合するために、Javaクライアント・アプリケーションをホストしているHTML(またはJSPやその他の動的ページ技術)を修正する；

・この修正されたページをHTTPサーバーで配信してください。これで、どのモダンブラウザでも動作するようになります。

CheerpJは、すべてのアプリケーション・コンポーネント（変換されたアプリケーションとランタイム）が静的であるため、サーバー側のサポートを必要としません。

# まとめ
マイクロソフトが企業をIEから完全に引き離そうとしていることは明らかです。CheerpJを使えば、あなたがすでに知っていること、そしてより重要なことは、あなたのチームが知っていることを使って仕事をすることができます。

[CheerpJがJavaクライアントアプリケーションをより安全でアクセスしやすいものにするためにどのように役立つかをご覧ください。](https://cheerpj.com/)

https://leaningtech.com/legacy-modernisation-jp/

引用元：https://cheerpj.com/the-demise-of-internet-explorer-and-what-it-means-for-your-java-applications-and-applets/
Pythonで「集合への要素の追加と集合からの要素の削除」の動作を確認してみた

# 概要

Pythonで「集合への要素の追加と集合からの要素の削除」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/python/set/index4.html

# 実装

以下のファイルを作成しました。
```sample.py
colorset = {"Red", "Green", "Blue"}
colorset.add("White")
print(colorset)

colorset = {"Blue", "Red", "Green"}
# "White" を追加
colorset.add("White")
print(colorset)
# "Black" を追加
colorset.add("Black")
print(colorset)

colorset = {"Red", "Green", "Blue"}
colorset.remove("Green")
print(colorset)
#colorset.remove("White")

colorset = {"Red", "Green", "Blue"}
colorset.discard("Green")
print(colorset)
# 削除しようとした値が存在しない場合でもエラーにはならない
colorset.discard("White")
print(colorset)

colorset = {"Red", "Green", "Blue"}
color = colorset.pop()
print(color)
print(colorset)
color = colorset.pop()
print(color)
print(colorset)

colorset = {"Red", "Green", "Blue"}
colorset.clear()
print(colorset)
```

以下のコマンドを実行しました。
```
$ python3 sample.py 
{'Blue', 'Red', 'White', 'Green'}
{'Blue', 'Red', 'White', 'Green'}
{'Green', 'Blue', 'Red', 'White', 'Black'}
{'Blue', 'Red'}
{'Blue', 'Red'}
{'Blue', 'Red'}
Blue
{'Red', 'Green'}
Red
{'Green'}
set()
```

# まとめ

何かの役に立てばと。
graph signal processing toolbox で「名前 'signal.internal.sigcasttofloat' を解決できません。」のエラーの対処

## 結論
signal processing toolbox を入れよう！

## 原因
signal.hogehoge はsignal processing toolbox の関数であるため，この toolbox をインストールしていないと，使用できない．

ちなみに，以下のコードで再現できる．
```matlab
N = 64;
G = gsp_ring(N);
G = gsp_compute_fourier_basis(G);
```

`gsp_compute_fourier_basis()`内で`signal.internal.sigcasttofloat()`が用いられている．
`display: flex;`で要素が潰れてしまうのを回避する

# 困ったこと

`display: flex;`で横並びになっているボタンが3つあります。

![スクリーンショット 2024-01-12 2.56.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730996/6e4005d8-4cb9-4457-9094-9cdd9e4824ce.png)

この状態からウインドウ幅を小さくすると

![スクリーンショット 2024-01-12 3.00.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730996/5a4bb95e-2ec7-b2dc-1c47-1f11f5b70d3a.png)

ボタンが潰れないように表示したいです。

# 解決策1
`min-width`を設定する

ボタン1つが200px, 左右余白が10pxずつとすると、
潰れない最小の幅は 200 * 3 + 10 * 2 で 620pxとなります。

これを `min-width` に設定すると

![スクリーンショット 2024-01-12 3.03.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730996/042f5f77-d6d5-e9df-e86c-78ab98ba0e87.png)

ウインドウ幅を縮めてもボタンが潰れずに表示できました。

# 解決策2

ボタン要素に`flex-shrink: 0;`を設定する

![スクリーンショット 2024-01-12 3.06.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730996/02a9d737-eb8c-c083-d784-6baa9036afe6.png)

潰さないように表示できました

# `flex-shrink`とは

 フレックスアイテムの縮小係数を設定するプロパティ

 デフォルトで `flex` は子要素がコンテナに収まるように自動で縮小して調整してくれます

 自動で縮小しないために`flex-shrink: 0;`を指定します。
【YAMAHA】文字化けの修正

コンフィグ等のステータスは正常に表示されるのに、説明の部分のみ文字化けする場合　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　

teratermの文字設定を変更する　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　UTF-8 → SJIS
【YAMAHA】デフォルトゲートウェイの設定方法

●グローバルIPの払い出しが固定でなくDHCPの場合のインターネット接続時の設定　　　　　　　　　　　　　　　　　　　　　　　　　　　※接続ポートがlan2の場合　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　ip route default gateway dhcp lan2　　　　

●固定の場合は[dhcp lan2]をIPに変更

設定後は[show ip route]で確認できる　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　宛先ネットワーク 　ゲートウェイ 　　　　　インタフェース 　種別 　付加情報
default 　　　　　　27.138.160.1 　　　　 LAN2(DHCP) 　static
27.138.160.0/22 　　27.138.160.160 　　　LAN2               implicit
192.168.1.0/24 　  　192.168.1.254 　　　  LAN1               implicit
192.168.2.0/24      　　　192.168.2.254            　　　　LAN1/2　　　            implicit
【コマンド】各メーカーのter len 0

cisco →terminal length 0
Cisco ASA →terminal pager 0
Cisco WLC →config pager disable
paloalto → set cli page off
juniper SSG → set console page 0
YAMAHA RTX → console lines infinity
sonicwall → no cli pager session
fortigate→ config system console
　　　　　 set output standard                                                                                                                             

Extream →　無効:disabe clipaging
                   有効:enable clipaging
【YAMAHA】SSH接続の設定

手順　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　1.ログイン用ユーザーの作成　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　※ログインユーザーがない場合は作成不要　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　2.暗号化のための鍵作成　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　3.SSHサービスの有効化

1.ログイン用のユーザー作成
login user ①(user01) ②(pass01)

①ユーザー　②パスワード

※作成時のメッセージは以下になります。

パスワード未設定
"Password is not set. Please set the password in order to enhance thesecurity."
パスワード強度 弱
"Password Strength : Weak"
パスワード強度 中
"Password Strength : Fair"
パスワード強度 強
"Password Strength : Strong"
パスワード強度 最強
"Password Strength : Very strong"

2.暗号化のための鍵作成
sshd host key generate

3.SSHサービスの有効化
sshd service on

●作成するとconfig内に以下の内容が追記されます。
login user admin *
sshd service on
sshd host lan1
sshd host key generate *
sshd encrypt algorithm aes128-ctr aes192-ctr aes256-ctr aes128-cbc aes192-cbc a
es256-cbc 3des-cbc blowfish-cbc cast128-cbc arcfour
【Allied】スタックポートからスイッチポートへの変更

工場出荷時は、AT-x510-28GTX、AT-x510-28GPXはポート27、28が、AT-x510-52GTX、AT-x510-52GPXはポート51、52がスタックポートとして動作しているため、スイッチポートとして利用できない。
スイッチポートとして利用するには、以下の手順を実施する必要がある。

1.コンフィグレーションモードにて、no stack 1(スタック番号) enableコマンドを実施
　※機器のスタック番号については、show stackコマンドで確認

2.コマンド実施後、機器の再起動

有効にする場合は、コンフィグレーションモードでstack enable
Kubernetes完全ガイド 第2版を読んでみた（輪読会用のメモ）1-2章

## 第1章
### Dockerコンテナとは
+ Dockerイメージを元に実行されるプロセスです。Dockerイメージがあれば環境の影響を受けずに様々な環境上でコンテナを起動させる

### Dockerコンテナの設計
主に気をつける点
+ 1コンテナにつき1プロセス
    + 1つのイメージの中に複数のプロセスを立てる方法は非推奨
+ Immutable Infrastructureなイメージにする
    + 不変のインフラを意味し、「環境を変更する際は古い環境は廃棄して新たに作る」「一度作られた環境は変更されないことを徹底する
+ 軽量なDockerイメージにする
    + コンテナ実行時、ノード上に使用するDockerイメージが存在しない場合は、外部からイメージをダウンロードして取得するため軽量に保つことが大事
+ 実行ユーザをroot以外にする
    + コンテナ内でプロセスを起動する実行ユーザの権限を最小化にして、リスクを減らす

### Docker fileの関連
（省略）

## 第2章
### Kubernetesを使うと何ができるのか
 + 複数のKubernetes Nodeの管理
 + コンテナのスケジューリング
 + ローリングアップデート
 + スケーリング／オートスケーリング
 + コンテナの死活監視
 + 障害時のセルフヒーリング
 + サービスディスカバリ
 + ロードバランシング
 + データの管理
 + ワークロードの管理
 + ログの管理
 + Infrastructure as Code
 + その他エコシステムとの連携や拡張

 コンテナオーケストレーションエンジンであるKubernetesを利用することで、これらの課題は自動化可能かつシンプルなオペレーションによって解決できる

### 宣言的なコードによる管理
 + Kubernetesは、YAML形式やJSON形式で記述した宣言的なコード（マニフェスト）によって、デプロイするコンテナや周辺リソースを管理できる
     + Infrastructure as Code

### スケーリング／オートスケーリング
    
 + Kubernetesはコンテナクラスタを形成して、複数のKubernetes Nodeを管理している
 + 同じコンテナイメージを元にした複数のコンテナ（レプリカ）をデプロイすることで、負荷分散や耐障害性の確保が可能
    クラスタ　>ノード>pod>コンテナ

### スケジューリング
 + コンテナをKubernetes Nodeにデプロイする際には、どのKubernetes Nodeに配置するかを決定することを「スケジューリング」という。
     + AffinityとAnti-Affinity機能を使用することで、コンテナ化されたアプリケーションのワークロードの特徴や、Kubernetes Nodeの性能差を意識してスケジューリングを行うことがでる。
         + 例えば、「ディスクI/Oが多い」コンテナを「ディスクがSSD」のKubernetes Nodeに配置する、といった制御が可能

### リソース管理
 + コンテナ配置のための特別な指定がない場合には、Kubernetes NodeのCPUやメモリの空きリソースの状況に従ってスケジューリングが行われるため、ユーザはどのKubernetes Nodeにコンテナを配置するのかを管理する必要はありません


### セルフヒーリング
 + 耐障害性という観点では、Kubernetesにとって重要なコンセプトの一つでもある、セルフヒーリング
     + Kubernetesは標準でコンテナのプロセス監視を行っており、プロセスの停止を検知すると、再度コンテナのスケジューリングを実行することで自動的にコンテナを再デプロイされる
     + クラスタのノード障害が起きたり、ノード退避を行ったりして、そのノード上のコンテナが失われた場合であっても、サービスに影響なくアプリケーションを自動復旧できるように作られている

### ロードバランシングとサービスディスカバリ
 + あらかじめ指定した条件に合致するコンテナ群に対してルーティングを行うエンドポイントを払い出すことができる
     + コンテナのスケール時にエンドポイントとなるServiceへのコンテナの自動追加や削除はもちろん、コンテナの障害時における切り離しや、コンテナのローリングアップデート時における事前の切り離しなども自動的に実行してくれます

※一部のサービスを順次更新していく手法
 + Serviceにサービスディスカバリの機能があることにより、それぞれのマイクロサービスが定義された複数のマニフェストを元に、システム全体を簡単に連携させることが可能


### データの管理
+ Kubernetesは、バックエンドのデータストアにetcdを採用している
    + etcdはクラスタを組むことで冗長化ができるため、コンテナやServiceに関するマニフェストも冗長化されて保存されている
+ コンテナが利用する設定ファイルや認証情報などのデータを保存する仕組みも用意されており、コンテナで共通の設定やアプリケーションから利用されるデータベースのパスワードなどの情報を、安全かつ冗長化された状態でKubernetes上に集中管理できる

※etcdはオープンソースとして配布されているキーバリュー・ストアであり、配布されたシステムが実行し続けるために必要不可欠な情報を保持、管理するために使用される

引用元：Kubernetes完全ガイド 第2版
【TTL】自動ログインマクロ(Ciscoルータ用_SSH)

;=====================================================================
; 接続情報
HOSTADDR = '192.168.33.100'
USERNAME = 'username'
PASSWORD = 'password'
;=====================================================================

; コマンドオプション組立て
COMMAND = HOSTADDR
strconcat COMMAND ':22 /ssh /2 /auth=password /user='
strconcat COMMAND USERNAME
strconcat COMMAND ' /passwd='
strconcat COMMAND PASSWORD

; 接続
connect COMMAND

end

参考　https://qiita.com/clustfe/items/e873f2216724fd7b96fc
【TTL】configの高速リストアマクロ

送信遅延を0の状態で実行できるconfigのリストアを高速実行するためのマクロです。　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　下記の内容をttl拡張子で保存して、teratermのマクロで実施です。　　　　　　　　　　　　　　　　　　　　　Ciscoでは、実証済み

※banner等のメモのリストはできません。

;--------------------------------------------
; プロンプト設定
;--------------------------------------------
prompt = '#'

;--------------------------------------------
; 投入Configファイルの選択 [キャンセル]なら終了
;--------------------------------------------
filenamebox '投入Configファイルを選択して下さい。' 0
if result = 0 then
  end
endif

config = inputstr

;--------------------------------------------
; 投入Configファイルの確認 [いいえ]なら終了
;--------------------------------------------
strconcat msg config
strconcat msg ' を投入しますか？'
yesnobox msg 'Tera Term'

if result = 0 then
  end
endif

; ファイルを開く
fileopen fHandle config 0

;--------------------------------------------
; 読み込んだファイルを1行ずつ投入
;--------------------------------------------
:loop
  wait prompt
  filereadln fHandle line

  ; ファイルの最終行なら終了処理へ
  if result goto fclose

  sendln line
  goto loop

; 終了処理
:fclose
  fileclose fHandle
【WordPress】WordPressの編集ログインパスワード忘れ対策

Wordpressの新規投稿をするために、編集画面にログインしようとしたときにパスワード忘れをした時の対策。もしくは、変更したり忘れてないのに違うと表示された際の対策。

登録ユーザーに対して有効なメールアドレスや設定が実施済みの場合はパスワード忘れのページで変更作業をすれば良いが登録できていないメールが飛ばない場合はAWSコンソールからSSH接続で以下のコマンドで変更可能。

①sudo wp user listで登録ユーザの確認

②sudo wp user update 1 --user_pass=passwordで登録されているユーザーのパスワードを変更する。wp user update の後にユーザのインデックス番号、pass=の後に任意のパスワードを入力　　　　　　　　　　　　　　　　　　　　　　　

【注意】wordpress上でメール設定プラグインでサーバを設定しているが正常に機能していないとエラーとなり変更ができない。
【TTL】ME初期設定TTLマクロ

作成途中ではあるが、下記のTTLマクロ構文を利用するとMEの初期設定を自動的に実施できる。

;●起動から待機時間90秒後に空エンターの送信
wait 'Starting image'
pause 120
sendln ''

;●ログイン
wait 'Username'
sendln 'cisco'
wait 'Password'
sendln 'Cisco'

;●特権モードへ移行
waitrecv '>' 17 17
sendln 'en'
wait 'Password'
sendln 'Cisco'

;●ter len 0の設定
waitrecv '#' 17 17
sendln 'ter len 0'

;●バージョン確認及びMEバージョンへの切り替え
waitrecv '#' 17 17
sendln 'sh ver'

;の場合は、MEへ切り替え
;

;タイムアウト15秒
timeout = 15

;文字列 "NOT MOBILITY" か "ERROR" を待つ。
wait 'NOT MOBILI' 'ERROR'

; "NOT MOBILITY" が来たなら、:ok へジャンプ
If result=1 goto NOTMOBILITY

; "ERROR" が来たなら、:error へジャンプ
If result=2 goto error

;"MOBILITY" が来たなら、タイムアウトで:MESETTING へジャンプ。
if result=0 goto MESETTING

endif

;MEに切り替え後に初期設定へジャンプ
:NOTMOBILITY
waitrecv '#' 17 17
sendln 'ap-type mobility-express'
goto MESETTING

;●ME初期設定開始
:MESETTING
timeout = 0

wait 'autoinstall?' 'Administrative User Name'
if result=1 then
goto AUTO
elseif result=2 then
goto USERNAME
endif

:AUTO
sendln ''

wait 'Enter Administrative User Name'

:USERNAME
sendln 'admin'

wait 'Enter Administrative Password '
sendln 'Isms0630cs'

wait 'Re-enter Administrative Password'
sendln 'Isms0630cs'

wait 'System Name'
sendln 'test'

wait 'Name' 'Country'
if result=1 then
goto Name

elseif result=2 then
goto Country

endif

:Name
sendln 'admin'

wait 'Enter Password for AP'
sendln 'Isms0630cs'

wait 'Re-enter Password for AP'
sendln 'Isms0630cs'

wait 'Enter Enable Password for AP'
sendln 'Isms0630cs'

wait 'Re-enter Enable Password for AP:'
sendln 'Isms0630cs'

wait 'Enter Country Code list'

:Country
sendln 'J4'

wait 'Configure a NTP server now? [YES][no]:'
sendln 'no'

wait 'Configure the system time now? [YES][no]:'
sendln 'no'

wait 'Management Interface IP Address Configuration [STATIC][dhcp]:'
sendln 'STATIC'

wait 'Management Interface IP Address:'
sendln '192.168.1.1'

wait 'Management Interface Netmask:'
sendln '255.255.255.0'

wait 'Management Interface Default Router:'
sendln '192.168.1.254'

wait 'Create Management DHCP Scope? [yes][NO]:'
sendln 'NO'

wait 'Employee Network Name (SSID)?:'
sendln 'test-WiFi'

wait 'Employee Network Security? [PSK][enterprise]:'
sendln 'PSK'

wait 'Employee PSK Passphrase (8-63 characters)?:'
sendln 'Isms0630cs'

wait 'Re-enter Employee PSK Passphrase:'
sendln 'Isms0630cs'

wait 'Enable RF Parameter Optimization? [YES][no]:'
sendln 'no'

wait 'Configuration correct?'
sendln 'yes'
sendln ''

;●ユーザログイン
wait 'User:'
sendln 'admin '

wait 'Password'
sendln 'Cisco'

;●クライアントAPへのIP設定

;マクロの終了
end
【TTL】Fortigateインターネット接続確認

Fortigateが8.8.8.8へ疎通が取れることを確認します。疎通ができない場合は、再起動をします。

; コマンドオプション組立て
connect "192.168.4.254:22 /ssh /auth=password /user=admin /passwd=Zaq12wsx"

;8.8.8.8への疎通確認
wait 'Home-Fortigate'
sendln 'execute ping 8.8.8.8'

wait 'from 8.8.8' 'sendto failed'

; "from 8.8.8" が来たなら、:end
If result=1 goto end

;"sendto failed" が来ない場合、タイムアウトで:reboot へジャンプ。
if result=2 goto reboot

endif

:reboot
wait 'Home-Fortigate'
sendln 'execute reboot'
wait '(y/n)'
sendln 'y'

:end
wait 'Home-Fortigate'
sendln 'exit'
【Windows】カレントディレクトリ内のファイル、サブフォルダを表示するコマンド

windowsにて 「tree /f」のコマンドを実行すると下記のようにカレントディレクトリ内のファイル、サブフォルダが一覧で表示される

:\店舗
├─新宿店
│ │ 売上.xlsx
│ │ 確定経費.xlsx
│ │
│ ├─1月
│ └─2月
├─池袋店
│ │ 売上.xlsx
│ │ 確定経費.xlsx
│ │
│ ├─1月
│ └─2月
└─渋谷店
│ 売上.xlsx
│ 確定経費.xlsx
│
├─1月
└─2月
初めて教職の模擬授業してみた話

## はじめに

皆さんこんにちは！　@mabuproです。
今回は大学で模擬授業をしたので色々と載せておこうと思います。

## 概要

対象：普通科高校（情報）1年 or 2年
時間：50分

## 生徒役の人たちに配布した資料たち

<script async class="docswell-embed" src="https://www.docswell.com/assets/libs/docswell-embed/docswell-embed.min.js" data-src="https://www.docswell.com/slide/5P93N4/embed" data-aspect="0.7729"></script><div class="docswell-link"><a href="https://www.docswell.com/s/mabupro/5P93N4-2023-12-21-170022">アルゴリズム基礎概念-順次探索法と二分探索法 by @mabupro</a></div>

https://drive.google.com/file/d/1HJ3OSOu2tnp9P-PEKzmBmz6AOrAsJMDC/view?usp=sharing

https://drive.google.com/file/d/1oi5Y4KTRCHK_z8zyloU8SPy7XlJv_68l/view?usp=sharing

## 工夫した点

- **導入でアルゴリズム体操を取り入れてみた**
    - 知ってる人が多いだろうと予想
- **誕生日をあてるゲームを入れてみた**
    - 授業中にグループワークの時間が欲しかった
    - せっかくなので楽しみながら、仲良くやりたい
    - 紙を使って、頭の中だけでなく実際に2分探索を目で見て、手を動かして理解する
    - 順次やランダムと比べてみて、2分探索の効果を実感する
- **資料づくりはシンプルだけど分かりやすくしてみた**
    - 図をなるべく大きくしながら配置してみた

## 苦労した点

- アルゴリズム体操を使ってみようと思ったが、中々アルゴリズムの原則に当てはめながら、次のワークに繋げるところ
- とにかく、アルゴリズムが嫌いになって欲しくないので、面白さを出すためにどうしたらいいのか考えるところ
- まだまだ参考資料が少ないので、授業内容をどこをやるかを考えるところ

## 反省点

- この内容でも、やはり難しいと思う人はいるのでごちゃごちゃした解説を何とか改善してみたい
- 時間割り当てがまだまだ不十分なので、ワークの時間配分は注意したいところ
- 模擬授業では滅茶苦茶に緊張したので慣れる

## あとがき

正直難しい。現役の先生たちすごすぎる。
ただ、教えるとなると必然的に調べることも多くなるので、勉強にもなる。今後も機会があれば授業？は続けていきたい


X(Twitter)もあるので、まだまだフォロー数とかも少ないのでぜひフォローしていって下さい。
https://twitter.com/mabupro_tec
vimの基本操作について

# vimとは
vim（ヴィム）とはテキストエディタのことで、ファイルの作成・編集・削除などを行うことができます。
vimは一般的なテキストエディタと異なり、マウスは使わずキーボードのみですべての操作を行う必要があります。

## vimtutor

vimの使い方は、"vimtutor"というチュートリアルにて確認することができます。

```
vimtutor <ENTER>
```
上記コマンドを入力することで、チュートリアルが開かれます。
このチュートリアルを読み、実際に手を動かすことでVimの基本的なコマンドを学ぶことができます。

# 基本コマンド

## モード
vimは4つのモードを使い分けて利用します。

|モードの名前|起動方法|主な機能|
|---|:-:|---|
|ノーマルモード|ESC|コマンドの入力モード <br> カーソルの移動や他のモードへ移動が可能|
|インサートモード|i|テキストの挿入や編集、削除が可能|
|ビジュアルモード|v|テキストの選択 <br> vコマンドを入力後にカーソルを移動することでテキストの選択が可能|
|コマンドラインモード|: , /|ファイルそのものに対する操作 <br> ファイルを上書き保存したり強制終了することが可能|


## カーソルの移動
ノーマルモードではカーソルの移動もコマンドを利用して行います。
カーソルの移動を行うコマンドのことを「モーションコマンド」と言います。

|コマンド|実行内容|
|:-:|---|
|k|上方向にカーソルを移動|
|h|左方向にカーソルを移動|
|l|右方向にカーソルを移動|
|j|下方向にカーソルを移動|
|e|単語の末尾にカーソルを移動|
|w|次の単語の先頭にカーソルを移動|
|0|行頭にカーソルを移動|
|$|行末にカーソルを移動|
|gg|ページの最上行にカーソルを移動|
|G|ページの最下行にカーソルを移動|
|(ページ数) G|指定したページにカーソルを移動|
|H|ウインドウの一番上にカーソルを移動|
|M|ウインドウの真ん中にカーソルを移動|
|L|ウインドウの一番下にカーソルを移動|

`Cntrl + G` コマンドを実行するとファイル上の現在の位置を確認することもできます。

## ファイルの編集

|コマンド|実行内容|
|:-:|---|
|vim (ファイル名)|vimの起動|
|:q!|保存せずに終了|
|:wq|保存して終了|
|:w (ファイル名)|別のファイルに保存 <br> ビジュアルモードでテキストを選択後にコマンドを実行すると、選択内容のみ別のファイルに保存可能|
|:r (ファイル名)|別ファイルの中身を挿入|

## テキストの編集
### 挿入
下記コマンドを実行することで、インサートモードに移動し、テキストの編集が可能になります。

|コマンド|実行内容|
|:-:|---|
|i|カーソルの左にテキストを挿入する|
|I|行頭にテキストを挿入する|
|a|カーソルの右にテキストを挿入する|
|A|行末にテキストを挿入する|
|o|下の行にテキストを挿入する|
|O|上の行にテキストを挿入|

### 置換
下記コマンドを実行することで、テキストを削除し、別のテキストを挿入することができます。

|コマンド|実行内容|
|:-:|---|
|r|カーソル上のテキストを入力したテキストに置換|
|R|1文字以上のテキストを入力したテキストに置換 <br> 置換が終了したら `ESC` でノーマルモードに戻す
|ce|カーソル上のテキストからその単語の末尾までを削除して置換|
|cc|カーソル上の行を削除して置換|
|c$|カーソル上のテキストから行末までを削除して置換|
|:s/(変更前)/(変更後)|カーソルがある行の最初の(変更前)のテキストを(変更後)のテキストに置換|
|:s/(変更前)/(変更後)/g|カーソルがある行の(変更前)のテキストを(変更後)のテキストに置換|
|:%s/(変更前)/(変更後)/g|ファイル内の(変更前)のテキストを(変更後)のテキストに置換|
|:s/(変更前)/(変更後)/gc|ファイル内の(変更前)のテキストを(変更後)のテキストに置換 <br> ただ、置換するときに1つ1つのテキストを確認する|

### 削除

|コマンド|実行内容|
|:-:|---|
|x|1文字削除|
|d|削除コマンド <br> モーションコマンドを合わせて利用する|
|dw|カーソル上のテキストから次の単語まで削除|
|de|カーソル上のテキストから単語の末尾まで削除|
|d$|カーソル上のテキストから行末まで削除|
|dd|行全体を削除|


## 操作の取消
コマンドによる操作の取消もコマンドにて行います。

|コマンド|実行内容|
|:-:|---|
|u|前回の操作を取消|
|U|業全体の変更を取消|
|Ctrl + R|取消を取消|

## コピー＆ペースト

|コマンド|実行内容|
|:-:|---|
|y|コピー <br> ビジュアルモードでテキストを選択後に `y` コマンドを実行する|
|yy|行全体をコピー|
|p|コピーしたテキストのペースト|

## 検索

|コマンド|実行内容|
|:-:|---|
|/|前方に語句を検索|
|?|逆方向に語句を検索|
|n|検索中の語句の次を検索|
|N|検索中の語句を逆方向に検索|
|CTRL-O|元の場所に戻る|
|CTRL-I|場所を次に移動|
|%|対応する括弧の検索|

### オプション
検索時のオプションを設定することもできます。

|コマンド|設定内容|
|:-:|---|
|:set (xx)|オプションを設定|
|:set ic|検索時に大文字小文字の区別しない|
|:set is|検索フレーズに部分マッチしている部分を表示する|
|:set hls|マッチするすべてを強調表示する|
|:set no(xx)| オプションを無効にする （例:set noic）|
|:nohlsearch|マッチの強調表示をやめる|
|/(検索文字)\c|1つの検索コマンドだけ大文字小文字の区別をやめる|


## 外部コマンドの実行
vimで外部コマンドを利用することもできます。

|コマンド|実行|
|:-:|---|
|:!(外部コマンド)|外部コマンドの実行|
|ENTER|外部コマンドの終了|
|:!dir , :!ls|ディレクトリの一覧を取得|

# 最後に
まだまだたくさんのコマンドがありますが、基本的なコマンドはこの辺りになるかなと思います。
今回記載したコマンドはすべて `vimtutor` で確認することができます。

ぜひ確認してみてください＾＾
【Cisco】modeボタンが押された時に出力されるもの

CISCOスイッチがmodeボタンが押下されるとflash内に「express_setup.debug」が出力される

------------------ show flash: ------------------
Directory of flash:/

591 -rwx 147 Jul 14 2022 19:22:48 +00:00 express_setup.debug
Summitコマンド


■ファイル確認
   ls

■ファイル削除
   rm [ファイル名]

■more削除
　 無効:disable cli paging
　 有効:enable cli paging

■コンフィグ確認
　 show configuration

■初期化
   unconfigure switch all
   Restore all factory defaults and reboot? (y/N) Yes
CloudflareにデプロイしたSvelteKitアプリケーションで、本番だけコンテンツが2回レンダリングされる

## 起こったこと
:::note warn
※**解決方法**はわかっていますが、原因がどこにあるのかはよくわかっていません。
:::


SvelteKitで作ったWebページをCloudflare Pagesにデプロイし、カスタムドメインで表示した。
その際、CloudflareのSpeed Optimization機能でAuto Minifyの「HTML」にチェックを入れた。

![Auto Minifyの「HTML」にチェック](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1677134/dca957a5-a62b-5942-1281-4997282c5dc4.png)

この状態で、`src/routes/+layout.svelte`を

```svelte
<script lang="ts">
	let { children } = $props();
</script>
{@render children()}
```

ライブラリのバージョンを

- "@sveltejs/adapter-cloudflare": "^3.0.1",
- "@sveltejs/kit": "^2.3.0",
- "svelte": "5.0.0-next.33",
- "vite": "^5.0.11"

のようにした状態でページを見ると`{@render children()}`の部分が重複して表示された。
（`{@render children()}{@render children()}`と書いたときと同じように二度表示された。）

## 解決方法
![Auto Minifyの「HTML」にチェック](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1677134/dca957a5-a62b-5942-1281-4997282c5dc4.png)

HTMLのチェックを外すだけ。

## 補足情報
HTMLのチェックに関してはSvelteKit2に変更する前から入れており、その時点では二度表示されることはありませんでした。

SvelteKit2＆Svelte5に上げたことが原因なのかどうかはわかりません。

また、全く同じソース（ライブラリのバージョンを含む）でVercelにデプロイしたときは二度表示されませんでした。

さらにいうと、Cloudflareがデプロイごとに作成してくれるプレビュー環境やpages.devのURLで確認できる環境についてはこの現象は起こらず、本番URLのみで起こりました。

2024/01/11時点でSvelte5はまだalpha版です。
もしかしたら今後解消されるかもしれませんが、同じようになった方は一旦HTMLのチェックを外してみることをおすすめします。
チーム開発を上手くすすめるために


## 概要

この記事では、チーム開発を上手くすすめるために必要なことを筆者の体験をベースに重要だと考える要素についてまとめています。

## 前提

筆者は iOS 開発者として働いていますが、仕事とは別で個人的にアプリ開発したり、チーム開発をしたりしています。その中で、仕事でない時のチーム開発を上手くすすめるために必要なことをまとめています。筆者はハッカソンへの出場や趣味での iOS アプリ開発で何回かチーム開発をしてきましたが、その中で上手くいかなかったことの原因を思い返すと、モチベーションの低下などほとんどが似たような要素に起因していると考えていますのでその対処法についてこの記事でまとめていきたいと思います。

## メンバー集め

まずは、チーム開発をするためにはメンバーが必要です。メンバーを集める際には、以下のような観点を考えると良いと思います。

1, メンバーの技術力・スキル  
仲良しで集まって自由に開発するのも楽しくて良い部分も多くあるかと思います。ただ、リリースを目的にしたり、比較的難易度の高いものを開発目的にする場合は、自分にないスキルを持ったメンバーを集めたり、技術力の高いメンバーを集めることで、お互いのモチベーションになったり違う視点からのアイデアが出たりするので、後述する中だるみ時期を回避したり普段の開発を上手くすすめるためには重要な要素ではないかと考えています。

2, 目的の共有  
開発が長引いてくるとよく陥る現象として、モチベーションの低下があります。そのため、開発を始める前に目的を共有したり、プロジェクトに参加することで達成したいことなどを最初にヒアリングすることで、途中でやることがなくなったり、やろうとしてもハードルが高すぎてそこまでやる気にもなれないといった状態におちいって、メンバー間での熱量の差が生じることを防ぐことにつながると思います。ですので特に、普段開発しているけどデザイナーにチャレンジしてみたいや、普段はフロント開発をしているけど、今後のキャリアのためにサーバー開発もしてみたい、けど仕事では簡単にはアサインされないからチャンスもあまりない、ゼロから色々自分でベースの部分をつくってみたいな人は仕事以外でのこういったアプリ開発を通して、欲しいスキルを磨いたり経験を少しでも積むことができるので、そういった人を集めることで、メンバーのモチベーションを維持することができると思います。（1 と少し矛盾する部分もありますが）

## メンバーへの期待値、メンタリティ

メンバーが揃い、アプリ開発がスタートしたら、最初の期間は新鮮さも相まって順調に進むことが多いです。しかし、開発が長引くにつれて、メンバーのモチベーションが低下することがあります。特に、メンバーの中には仕事の忙しさなどで進捗が出せない場合もあります。

このような状況では、自分自身のメンバーに対する期待値を高く設定しすぎないことが重要です。期待値が高すぎると、感情的な対立やチーム内での不和を引き起こすことがあります。なので当然のことですが、メンバーに感謝の気持ちを持ち、彼らが忙しい中で時間を割いてくれていることを理解することが何より大切です。

また、進捗を促進するための話し合いや工夫は必要ですが、メンバーそれぞれが抱える生活や仕事の問題に対して共感と理解を示すことも重要です。自分が正しいという思い込みを持たずに、常に相手の立場に立って考え、支援を提供する姿勢がチームの健全な関係を築く鍵です。

## アジャイル開発

アジャイル開発は、プロジェクトを小さな単位に分割し、それぞれを短期間で完了させることを目指します。スクラムはこの手法の一例で、スプリントと呼ばれる短期間（通常は 1〜2 週間）の中で、決定されたタスクを完了させます。スプリントの間に、進捗状況を TODO、WORKINPROGRESS、DONE などで可視化するツール（例：JIRA や Trello）を利用することで、効率的にタスクを管理し、柔軟に要件や優先順位を調整しながら目標に近づきます。

ただし、アジャイル開発の鍵は、手法だけではなく、メンバーのメンタリティにもあります。アジャイルなメンバーは、自分の強みを活かしながらチームのニーズを把握し、必要なタスクを自ら見つけ、積極的に行動します。また、固定観念にとらわれずに新しい方法を探求し、チームにとって最適な解決策を模索します。このメンタリティをチームに共有し、お互いを助け合いながら進めることで、アジャイル開発の真の効果を発揮できます。

## 開発効率性

リリースを目指すと、開発は長期間にわたり続くことがあります。本業が忙しい中での開発時間の確保は困難な場合もあるため、効率性を追求することが重要です。以下に、私の経験に基づくよく使われて簡単に導入可能な効率的な開発方法を紹介します。

1,静的解析ツールの導入  
lint のようなツールを導入することで、コードの可読性を高め、レビューを容易にします。これにより、不要な行の削除やコードスタイルの統一が可能になります。

2, テスタブルなコードの書き方  
複雑な処理を小さな関数に分割し、オブジェクトの責務を明確にすることで、処理の流れが追いやすくなります。DI や SOLID 原則を参考にしてください。

3, ORM の導入  
データベース操作に ORM を用いることで、SQL を直接書く必要がなくなり、バグの減少やテーブル変更への柔軟な対応が可能になります。

4, CI/CD の導入  
CI/CD を利用することで、マージ後の自動配信や静的解析ツール、テストの自動化が実現できます。UI テストの自動化にはスナップショットテストなどが有効です。

## スコープの重要性

チームビルディングでは、目的やメンタリティを共有しますが、最終的な成果物と締切を明確にすることも同様に重要です。開発初期には多くのアイデアが浮かび、様々な機能や画面を実装したいという欲求が湧きますが、それらを全て取り込むことは現実的ではありません。範囲が広がりすぎると、プロジェクトの完成が遅れ、チームが燃え尽きてしまうリスクがあります。

## オンサイトの重要性

開発が長引くと、プロジェクトに中だるみの時期が訪れることがあります。このような時には、オンサイトでのミーティングが非常に効果的です。オンサイトで直接会話することで、普段は Slack などで行っているコミュニケーションがより深くなり、普段聞き逃されがちな細かな点についても話し合うことができます。これにより、チームとしての結束力が高まり、モチベーションの回復に繋がります。
IsaacSim/Gymで環境のローデイングが遅い時の解決策

# トラブル
IsaacSimのスタンドアロンモードやIsaacGymでシミュレータが起動してから環境を読み込む際、2,3分かかる問題に悩まされた。コンソールには"Dublicated Actions detected"的なエラーメッセージ。


# 解決策
Nucleusのローカルサーバーが作成されておらず、サーバーとの接続待ちがタイムアウトするまで時間がかかっていたらしい。
↓に従って作成すれば数秒で起動するようになった。
https://zenn.dev/sotahi/articles/2ee0fcf7bc4e7b#3.-nucleus-%E3%81%AE%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%92%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E7%92%B0%E5%A2%83%E3%81%AB%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B

ローカルサーバーを作成したくない場合は、タイムアウトの設定を変える方法もあるらしい。(詳しくは見てません！)
https://github.com/NVIDIA-Omniverse/OmniIsaacGymEnvs/issues/92
https://forums.developer.nvidia.com/t/extremely-slow-loading-times-isaac-sim-2023-1-0/272375


![スクリーンショット 2024-01-12 0.25.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618834/8ed2687e-f2e0-f152-b628-6c28b8d2765b.png)
DBUnit備忘録

## DBUnitとは
DBUnitは、Javaプロジェクトにおいてデータベースへの更新などのUTを支援するためのフレームワークです。
データベースのテストデータのセットアップ、比較、および期待値の検証を簡単に行うことができます。これにより、データベース関連の機能やクエリが正しく動作するかどうかを確認できます。
私が以前参画していた現場ではテストデータ、期待値をExcelシートで管理していました。
最近になりネットで調べたところ、それらしい記事はいくつも出てくるのですがどれもその現場で使っていたものとは違う方法で実装していました。
管理しやすく見てわかりやすかったので今となってはもっとしっかり勉強しておくべきでした...。
わかったらまた記事更新します。

## DBUnitのインストール
DBUnitを使用するには、まず依存関係をビルドツールに追加する必要があります。例えば、Mavenを使用している場合は、`pom.xml`ファイルに依存関係を追加します。その後、適切なJUnitとDBUnitのバージョンを指定し、必要な設定を行います。

```xml
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.dbunit</groupId>
    <artifactId>dbunit</artifactId>
    <version>2.7.0</version>
    <scope>test</scope>
</dependency>
```
## Excelシートでデータ投入
エクセルでデータを投入する場合は以下のように１行目をカラム名として下にテストデータを入力します。
| ID | NAME | AGE | SALARY | JOB |
|:-:|:-:|:-:|:-:|:-:|
|  1 |  a |  20 |  200000 |  employee |
|  2 |  b |  26 |  270000 |  ｍanager |
|  3 |  c |  38 |  350000 |  areaManager |


## 注意点
1. **Excelシートのクリーンアップ**: 
一度データを入力したセルを削除してもDBではそのセルが空白として認識されてしまいます。解消方法は一度シートを削除するしかなかったです。（行削除とかでもダメ）

2. **テストデータの整合性**: 
テストデータはテストケースごとに適切に整合性が保たれていることを確認しましょう。不整合があると、正確なテストが行えません。
 
3. **既存データを退避してくれない**: 
基本的にはDBUnitではテスト実行時にはDBにある既存データを退避してからテストデータ投入して、テスト終了後には既存データを戻してくれるのですが、何度かデータを退避してくれないことがありました。
どうしてもテストコードに問題がないのに期待値と合わない場合はこの可能性を疑った方がいいかもしれません。

## まとめ
DBUnitはデータベースユニットテストを簡素化し、効果的に行うためのツールです。注意点を踏まえて正しく使用することで、信頼性の高いデータベース関連のテストを実施できます。Junitさえわかっていれば学習コストもあまり高くなく、テストデータの可視性が高まるのでおすすめです。
Flutter でスナックバーが何度も表示されてしまう

こんにちは、普段は Android のアプリエンジニアをしているものです。
最近は Flutter とスマートコントラクトの開発がマイブームです。


ところで突然ですが、皆さんは rebuild に悩んだことはありませんか。
例えば rebuild が走るたびに複数回エラーのスナックバーを表示してしまったり、です。
StateNotifier を経由して画面遷移をするときにも、 State に遷移先の情報を保持しておくと複数回走ってしまったときにおかしな挙動をしてしまうことがありますね。
Jetpack Compose だったら `LaunchedEffect` などを使って recompose を凌げますが、 Flutter にはそれがなくて困りました。
なぜこんなことに・・・

そもそも何が問題なのでしょうか。

# 問題点
問題点はシンプルで
「 Widget 側で、同じイベントを意図せず複数回受け取ってしまうこと」です。
同じイベントってなんでしょうね。
ここでは Event の `インスタンス` が同じなら同じイベント、異なるなら異なるイベントと定義しておくと狙い通りの挙動になります。

# 解決策
解決策は、「同じイベントを複数回流さないこと」です。
`SingleEvent` を作りました。

```dart:single_event.dart
class SingleEvent<T> {
  var _done = false;
  final T value;

  SingleEvent(this.value);

  T? get() {
    if (_done) {
      return null;
    }
    _done = true;
    return value;
  }
}
```

`SingleEvent` のインスタンスが同じとき、`get()` を二度目以降は null が返ります。
新しい `SingleEvent` のインスタンスを作れば get() すると最初の一回は non-null が返ります。

使い方は下記です。
軽くシチュエーションを説明すると、クレデンシャルがあれば Register 画面に進めて、なければ Exception をセットしています（スナックバーを表示するため）


```dart:home_state.dart
enum HomeAction {
  toRegister;
}

@freezed
class HomeState with _$HomeState {
  const factory HomeState({
    @Default(null) SingleEvent<HomeAction>? action,
    @Default(null) SingleEvent<Exception>? exception,
  }) = _HomeState;
}
```


```dart: home_notifier.dart

  Future<void> onTappedRegister() async {
    final result = await fetchCredentialUseCase(null);
    result.when(
      success: (data) {
        if (data != null) {
          state = state.copyWith(action: SingleEvent(HomeAction.toRegister));
        } else {
          state = state.copyWith(
            exception: SingleEvent(NoCredentialException()),
          );
        }
      },
      error: (error) {},
      exception: (exception) {
        state = state.copyWith(exception: SingleEvent(exception));
      },
    );
  }
  
```

こうすれば rebuild がいくら走っても大丈夫です。
Widget 側が意図せず複数回、同じ値を受け取ってしまうことはありません。


※奇妙な解決策に思われるかもしれませんが、ネイティブの Android アプリ開発だと珍しくない方針だと思います。


https://stackoverflow.com/questions/51757164/how-to-create-livedata-which-emits-a-single-event-and-notifies-only-last-subscri

こちらの回答にも同じようなものがあります。↓

```kotlin
/*Used as a wrapper for data that is exposed via a LiveData that represents an 
 event.*/

open class Event<out T>(private val content: T) {

  var hasBeenHandled = false
    private set // Allow external read but not write

  /**
   * Returns the content and prevents its use again.
  */
  fun getContentIfNotHandled(): T? {
    return if (hasBeenHandled) {
      null
    } else {
      hasBeenHandled = true
      content
    }
  }

  /**
    * Returns the content, even if it's already been handled.
  */
  fun peekContent(): T = content
}
```

LiveData でも同じ問題がありましたね・・・

とはいえなんだかトリッキーな気がして、これを初めて見たときから気持ちが煮え切らないです。
もっとベストプラクティスがあるよ！という方はぜひコメントで教えてください！

それでは。