OmniAICreator/Qiita-1.07M huggingface dataset:
tsconfig.jsonの設定

# 概要
TSファイルをJSファイルにコンパイルするための設定ファイルです。TSプロジェクトのルートディレクトリに`tsconfig.json`を設置します。`tsconfig.json`が存在するディレクトリは、ルートディレクトリです。`tsconfig.json`にはルートファイルとプロジェクトをコンパイルするのに必要なコンパイラのオプションを設定します。

# tsconfig.jsonの実行
入力ファイルを指定せずにtscを実行します。
[microsoft/TyeScript](https://github.com/microsoft/TypeScript/blob/main/package.json)のpackage.jsonに以下の記載がありました。
```
    "bin": {
        "tsc": "./bin/tsc",
        "tsserver": "./bin/tsserver"
    },
```
※間違っていたらすみません。

# tsconfig.jsonのオプション
全オプションは多岐にわたるので、個人的に今回使用する分を記していきます。

```tsconfig.json
{
  "compilerOptions": {
    "target": "es2021",
    "module": "esnext",
    "moduleResolution": "node",
    "jsx": "react",
    "strict": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true
  }
}
```

### compilerOptions
コンパイルする際のオプションです。ここにオプションを書いていきます。

### target
どのバージョンでjsを出力するのか指定します。指定するバージョンは[node.green](https://node.green/)で確認します。`node -v`でバージョンを確認して調べます。`v18.15.0`だとES2021が100%対応していましたので、今回は指定しています。

### module
出力するjsのモジュールの仕組みとして何を使用するかを指定する。
※ECMA Script ESNext ＝ 未来のJavaScript。まだ実質使えないものも含めた、来年出る最新のECMAScriptのバージョンを `ESNext`と呼ぶようです。

https://www.slideshare.net/putan/javascriptjavascript-esnext

### moduleResolution
tscのモジュール解決の方法を指定します。

### jsx
tsxファイルをjsxやjsにコンパイルする際の出力の形式を指定します。

### strict
`strict`自体は特定の機能を有効にするものではないです。このオプションをtrueにすると、下記のオプションが全てtrueになります。

`--noImplicitAny`
`--noImplicitThis`
`--alwaysStrict`
`--strictBindCallApply`
`--strictNullChecks`
`--strictFunctionTypes`
`--strictPropertyInitialization`

### forceConsistentCasingInFileNames
import時にファイルパスの文字列で大文字小文字を区別するかどうかを指定します。
デフォルトfalseです。

#### 参考

https://js.studio-kingdom.com/typescript/project_configuration/tsconfig_json

https://qiita.com/ryokkkke/items/390647a7c26933940470
WindowsでCUIを使ってOSを再起動する方法

## 概要

リモートPCの再起動を実行したときに再起動が完了せず
リモートデスクトップ接続もできない状況になった。  
opensshでの接続は可能だったためSSHで接続してCUI  
を使ってOSを再起動したときの記録のメモである。

## 再起動方法

### shutdownコマンド

基本はshutdownコマンドを使えばよい。
下記のコマンドは10秒後に再起動を実行するコマンドである。  
```
shutdown -r -t 10
```

### winlogon.exeを停止する

shutdownコマンドで再起動することができない場合は、  
最後の手段としてwinlogon.exeを停止する。
windlogon.exeはtaskkillでは止められないため、  
wmiコマンドか、Sysinternalsにあるpskillコマンドを使うと停止することができる。  

#### 1. wmiコマンドを使う方法

wmiコマンドを使うと、タスク停止することができる。
```
wmic process where "name='winlogon.exe'" delete
```

##### 2. pskillを使う方法

pskillを使えば、リモートのPCのタスクも停止できるようだが、  
リモートのWindows 10で試したがうまくいかなかった。
```
pskill \Computer-Name winlogon
```

## 参考

[タスクマネージャーで特定のプロセスを強制終了できない時の対処法 – Windows10](https://itojisan.xyz/trouble/21597/#4_wmi)

[PsKill v1.16](https://learn.microsoft.com/ja-jp/sysinternals/downloads/pskill)

[プロセスの終了が出来ない場合のコマンド](https://pc-more.fimplex.com/article/process-kill-command/)

[A system shutdown is in progress.(1115)](https://www.teimouri.net/a-system-shutdown-is-in-progress-1115/)
ChangeNotifierProvider で分かったことメモ

ChangeNotifierProviderを利用してとUI側から値を変更できる

* runappで走らせるwidgetにproviderscopeを囲う
* ChangeNotifierProvider定義
* notifyListenersで変更を通知
* consumerwidgetにすると引数２にwidgetRefが追加できる 
* view??UI側??でref.watchとかref.readとかを使用する

↓使用例
```dart
// model側
// UI側からUserNotifierを監視・操作できるようにする
final usersProvider = ChangeNotifierProvider((ref) => UserNotifier());

class UserNotifier extends ChangeNotifier {
  String name = "";

  void changeUserName(String newName) {
    name = newName;
    notifyListeners(); // リスナーに変更を通知
  }
}

// view側
class UserPage extends ConsumerWidget {
...
...
//第2引数はConsumerWidgetを継承するときにつける
Widget build(BuildContext context, WidgetRef ref) {
  // UserNotifierが使用できる
  UserNotifier user_model = ref.watch(usersProvider);

  return Center(
    child: Column(
      children: [
        Text('${user_model.name}'),
        TextField(
          onSubmitted: ((value) => user_model.changeUserName(value)),
        )
      ],
    ),
  );
}
...
```
表示のみ:　`StateNotifierProvider`
どうしてもデータの更新が必要：`ChangeNotifierProvider`
のような使用が推奨されている。
>可能な限り StateNotifierProvider を使用してください。
ChangeNotifierProvider の使用はミュータブルなステート管理を行う必然性がある場合に限定してください。

https://riverpod.dev/ja/docs/providers/change_notifier_provider
MySQLインストール備忘録　macOS

MySQLインストールやってみます。

Homebrewがインストールされているか確認します

```ruby:入力
brew -v
```

```ruby:結果
Homebrew 4.0.9
Homebrew/homebrew-core (git revision d8c9940ad94; last commit 2023-03-25)
Homebrew/homebrew-cask (git revision b036a0f836; last commit 2023-03-24)
```

問題なさそうなので、MySQLのインストール準備をします。

```ruby:入力
mysql --version
```

```ruby:結果
command not found: mysql
```
インストールされていないことを確認しましたので、早速インストール実施します。
```ruby:入力
brew install mysql
```

```ruby:結果
We've installed your MySQL database without a root password. To secure it run:
    mysql_secure_installation

MySQL is configured to only allow connections from localhost by default

To connect run:
    mysql -u root

To start mysql now and restart at login:
  brew services start mysql
```
うまくいきました！


それではサービスを開始してみます。事前にパスワードの設定は完了しています。
```ruby:
brew services start mysql
```

```ruby:
mysql --user=root --password
```

```ruby:
mysql> 
```
うまくいきました！

稼働確認が完了したので、ログアウトしサーバーを停止したいと思います。
```ruby:
exit
```
```ruby:
Bye
```
```ruby:
brew services stop mysql
```

```ruby:
Stopping `mysql`... (might take a while)
==> Successfully stopped `mysql` (label: homebrew.mxcl.mysql)
```

とりあえず、インストール＆稼働確認完了しました。
jupyter上からchatgptを使い，ノーコードで機械学習モデルを作成してみた

昨日の[記事](https://qiita.com/DDDDai/items/e56501b3cdb24c88d80d)でjupyter上からマジックコマンドchat gptを利用できるようになったので，コードを書かずにどこまで機械学習モデルを構築できるのか実験してみました．

実験の目標は機械学習の入門でよく使われるデータであるタイタニック号の生存者を予測する2値分類モデルを3種類(xgboost,lightgbm,catboost)構築しそれぞれの精度を比較するところまでにしようと思います．

# STEP1 データのダウンロード
まずはタイタニックのデータをダウンロードする関数を作ってもらいます．
![スクリーンショット 2023-03-25 23.12.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319390/ab71d70b-b422-8a7f-1ea3-9b2b6c9061d2.png)
回答をそのまま実行すると．．
![スクリーンショット 2023-03-25 23.21.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319390/38eb9cf8-67ed-a54a-18b2-2f901105a66a.png)
早速エラー．　
どうやら古いバージョンを想定したコードを返してきた模様．エラー改修してもらいます．
![スクリーンショット 2023-03-25 23.30.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319390/90a98724-79f9-7281-6155-21015a1cff77.png)

今度は実行成功なるか？？
![スクリーンショット 2023-03-25 23.30.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319390/88e4da8d-e0fa-3bc5-47f2-9c2ea059b02d.png)

できた！！これだけですごく感動してしまう．．．
# STEP2 モデル構築・結果確認

次にダウンロードした．データに対して，必要な前処理をよしなに実施し，学習モデルの構築精度検証までを実装するコードを書いてもらう．

![スクリーンショット 2023-03-26 0.05.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319390/de525192-4d64-680a-8953-b06fad68ab88.png)
得られた回答はこちら
![スクリーンショット 2023-03-26 0.05.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319390/661535c3-b429-30be-0ab8-cad4197ee27d.png)
上記のコードだとデータに存在しないカラムがあるためエラーが出てしまうのだが，ここで，コンテキストの上限に達成したため，`%%ai_continue`を使えなくなってしまう．．
そのため，カラム名のエラーなどを人力で解決せざる終えなくなってしまった．．．完全ノーコードならず．．．
仕方なく少しの修正施しエラーを解消し実行した結果が下記
![スクリーンショット 2023-03-26 0.11.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319390/6ad52559-8113-0a04-1f3f-0f18214bf260.png)
catboostの精度が最も良かった模様．

# 感想
1. やはりGPTはすごい！！エラーが多少あるとはいえ，トータルで見てもかなりコーディングスピードが上がる
1. ただ，現状jupyterのマジックコマンドを使用する必要性はそこまで感じられない．一番のボトルネックが`%%ai_continue`の制限にすぐ到達してしまうことだ．コードが途中段階の場合は以降のコードを自力で作成する，もしくは新規の会話で再度目的と進捗を報告し，続きを実施してもらうなどの処理をしなければならず，windowを行き来する不自由さを許容してでもchatgptのwebサイトとノートブックを跨いでやった方が生産性は圧倒的に高い．

ガッツリGPTにコード任せたいときはchatgptのwebページ，　ちょこっと何か聞きたい時にはマジックコマンドという形の使い分けが現状のベストだと思う
[python] dequeの使い方


# はじめに
経路問題をとくための方法としてdequeが良く使われている。なのでちょっとまとめてみた。
dequeはスタックのようにも、キューのようにも使うことができる。
pop, pushが頻繁な問題において、listよりも優れた速度を示す、らしいです。

# Code
## import
```python
from collections import deque

dq = deque()
print(dq)
# deque([])
```

## append() : 右に値を追加
```python
dq.append(5)
dq.append(6)
print(dq)
# deque([5,6])
```

# appendleft()：左に値を追加
```python
dq.appendleft(4)
dq.appendleft(3)
print(dq)
# deque([3,4,5,6])
```

## extend()：右に値を順番に追加
```python
dq.extend([7, 8, 9])
print(dq)
# deque([3,4,5,6,7,8,9])
```

## extendleft()：左に値を順番に追加
```python
dq.extendleft([2, 1, 0])
print(dq)
# deque([0,1,2,3,4,5,6,7,8,9])
```

## remove() : 特定の値を削除
```python
dq.remove(7)
dq.remove(8)
dq.remove(9)
print(dq)
# deque([0,1,2,3,4,5,6])
```

## pop() : 右の値を削除し、その値を返す
```python
popValue = dq.pop()
print(popValue)
# 6
print(dq)
# deque([0,1,2,3,4,5])
```

## popleft() : 左の値を削除し、その値を返す
```python
popValue = dq.popleft()
print(popValue)
# 0
print(dq)
# deque([1,2,3,4,5])
```

## rotate() : deque中の値を回転
```python
print(dq)
# deque([1,2,3,4,5])
dq.rotate(1)
print(dq)
# deque([2,3,4,5,1])
dq.rotate(1)
print(dq)
# deque([3,4,5,1,2])
dq.rotate(-1)
print(dq)
# deque([2,3,4,5,1])
```
PHP基礎_お問い合わせフォームDB連携

# 前回の続き
## データベース（phpmyadmin）連携
### データベースと連携し、フォーム内容をデータベースに反映させる。
以下、前回の内容から追記したコード
※入力された情報が引き継がれ（index.php→check.php→thanks.php）、
データベースに反映させたい情報があるページにコードを記載する（以下thanks.phpに記載）
```
<?php 
    $nickname = $_POST['nickname'];
    $email = $_POST['email'];
    $content = $_POST['content'];

    // step1:データベース接続
        // phpmyadmin の phpkiso へ接続する
        // アカウント名
        // パスワード
        // phpからデータベースへアクセスするために使う、phpが用意した技
    $dsn = 'mysql:dbname=phpkiso;host=localhost';
    $user = 'root';
    $password='';
    $dbh = new PDO($dsn, $user, $password);
    $dbh->query('SET NAMES utf8');

    // step2:SQL文の実行
    $sql = 'INSERT INTO `survey`(`nickname`, `email`, `content`) VALUES ("'.$nickname.'", "'.$email.'", "'.$content.'")';
    $stmt = $dbh->prepare($sql);
    $stmt->execute();
?>
```
## データ内容を表示する
### データベースに反映した情報を見た目に表示する
データベースに取り込んだ情報を見た目に表示させ、管理しやすくする。
今回はview.phpを作成し、以下のコードを記入した。

```
<?php

// phpmyadminのデータを見た目に表示する

    $dsn = 'mysql:dbname=phpkiso;host=localhost';
    $user = 'root';
    $password='';
    $dbh = new PDO($dsn, $user, $password);
    $dbh->query('SET NAMES utf8');

        // 取得するとき　select文
    // fetchAll() データベースのデータを全権取得し、配列に格納する技
    // PDO phpコード上のデータベースという意味
    // FETCH_ASSOC 連想配列のかたちで
    // var_dump 配列・変数の中身を検証する関数　＝　検証する行為　＝　デバックする

    $sql = 'SELECT * FROM `survey`';
    $stmt = $dbh->prepare($sql);
    $stmt->execute();
    $records = $stmt->fetchAll(PDO::FETCH_ASSOC);
    // var_dump($records);


    foreach($records as $record){
        echo $record['id'] . '<br>';
        echo $record['nickname'] . '<br>';
        echo $record['email'] . '<br>';
        echo $record['content'] . '<br>';
        echo '<hr>';
    }

    // $test = ['id'=>1, 'mickname'=>'たろう'];
    // var_dump($test);

?>
```
# 一連の流れ
inde.php　問い合わせ内容を入力
![スクリーンショット 2023-03-25 23.59.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/fec27a50-7b1f-94f5-5396-5e1d6c0a05e5.png)

cehck.php 内容の確認画面
![スクリーンショット 2023-03-25 23.59.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/745f0faf-fded-aded-ac1f-61bfcb95a8d9.png)

thanks.php 問い合わせありがとう画面　
※ここでデータベースに問い合わせ内容が反映される
![スクリーンショット 2023-03-25 23.59.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/8bd2a867-e4a7-2c2e-c506-475f9682e53d.png)

phpmyadmin に問い合わせ内容が反映されている（phpmyadminはこの記事以降に投稿します）
![スクリーンショット 2023-03-26 0.00.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/3bb550c3-37c9-3655-271f-3d0aeb54ba5a.png)

view.php データを見た目に表示させる
![スクリーンショット 2023-03-26 0.00.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/46f87f56-f9ed-c390-59f2-80d90e79024a.png)
抽象クラスと抽象メソッド

## 抽象クラスと抽象メソッドとは
抽象クラスはインスタンス化できないクラスのこと。何らかのクラスの基底クラスになるのでクラスの雛形の役割を持つ。メソッドにabstract修飾子をつけると抽象メソッドになる。抽象メソッドは具体的な処理を持たないメソッド。
抽象クラスを継承したクラスは抽象メソッドをオーバーライドしなければならない。
具体的な処理は継承先のクラスで実装する。
抽象クラスをインスタンス化することはできない。


```java
abstract class Animal { //抽象クラス
    abstract void cry(String voice); //抽象メソッド
}
```
```java
class Cat extends Animal { //継承
    @Override
    public void cry(String voice) { //オーバーライド
        System.out.println(voice + "と鳴きます");
    }
}
```
## メリット
抽象クラスは複数のクラスの基底クラスになる。そのクラス間でクラスの作りを統一できるので、クラスの設計図のようなものではないかと思っている。

**[メリット]**
・共通の処理を書くことができる
・必ずオーバーライドしないといけないので、各クラスでメソッド名が統一でき、ロジックが共通化できる
・必ずオーバーライドしないといけないので、開発者の実装忘れを防ぐことができる

**(例)**
動物が鳴くというcryメソッドを共通の処理として抽象クラスに抽象メソッドとして記述。
CatクラスとDogクラスでcryメソッドをオーバーライドするので、似たような処理を同じメソッド名で実装できている。
このようにクラスは違うけど、やることの方向性が似ていれば、抽象クラスを使ってクラスの作りを統一化でき、「お互い似たような処理をしていますよ」と開発者に知らせることができる。
```java
abstract class Animal { //抽象クラス
    abstract void cry(String voice); //抽象メソッド
}
```
```java
class Cat extends Animal { //継承
    @Override
    public void cry(String voice) { //voiceの中身が「にゃー」
        System.out.println(voice + "と鳴きます"); //にゃーと鳴きます
    }
}

class Dog extends Animal { //継承
    @Override
    public void cry(String voice) { //voiceの中身が「わん」
        String voice_2 = "ワン" + voice
        System.out.println(voice_2 + "と鳴きます"); //ワンわんと鳴きます
    }
}
```
抽象メソッド以外にも、そのクラス独自のメソッドを実装しても良い。

## インタフェースとの違い
同じようなものにインタフェースというのがある。インタフェースも抽象メソッドを持ちオーバーライドしなければならない。

|抽象クラス|インタフェース|
|:--|:--:|
|extendsでクラスへ継承する|implementsでクラスに実装する|
|コンストラクタ、フィールドを持てる|コンストラクタ、フィールドを持てない|
|多重継承ができる|多重継承ができない(インターフェース同士では可能)|

## 終わり
抽象クラスを実装することによって、実装ルールを定め書き方を統一できるということですね。
抽象クラスを使えば、担当者ごとに書き方が異なり、同じような処理なのに書き方が全く違うというのを防ぐことができます。
以上です:slight_smile:
【React】manifest.jsonについて

## manifest.jsonについて

Reactアプリケーションをcreate-react-appで作成するとpublicフォルダにmanifest.jsonというファイルが存在します。
このmanifest.jsonを編集することでスマートフォン等で「ホーム画面に追加」した際のアイコンやUI等に関する設定をすることができます。

初期状態は以下のようになっています。

```sample-pwa/public/manifest.json
{
  "short_name": "React App",
  "name": "Create React App Sample",
  "icons": [
    {
      "src": "favicon.ico",
      "sizes": "64x64 32x32 24x24 16x16",
      "type": "image/x-icon"
    },
    {
      "src": "logo192.png",
      "type": "image/png",
      "sizes": "192x192"
    },
    {
      "src": "logo512.png",
      "type": "image/png",
      "sizes": "512x512"
    }
  ],
  "start_url": ".",
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#ffffff"
}

```

### 主要なプロパティについて
#### `short_name`および`name`
アプリケーションの名前を設定します。
`short_name`はホーム画面、ランチャー等やアプリケーション名が表示されるスペースが狭い場合に表示されます。

#### `icons`
アイコンを設定します。
`src`,`type`,`sizes`を設定する必要があります。
アイコンはホーム画面、アプリランチャー、タスクスイッチャー、スプラッシュ画面などで使用されます。
スプラッシュ画面は後述のdisplayにfullscreenかstandaloneを指定する必要があります。

#### `start_url`
ホーム画面に追加したアイコンをタップしてアプリケーションを起動した際に最初に表示する画面を指定します。
何も設定していない場合には、ユーザーが「ホーム画面に追加」した際に表示していた画面が表示されるようです。
`/?utm_source=pwa`を追加することでGoogle Analyticsでアプリの起動頻度を追跡することができます。

#### `background_color`
スプラッシュ画面の背景色を指定します。

#### `display`
ホーム画面から起動した際のUIを指定します。
`fullscreen`,`standalone`,`minimal-ui`,`browser`のいずれかを設定します。
`standalone`はネイティブアプリケーションのような表示、`browser`はブラウザで表示した際と同じUIとなります。
前述の通り、スプラッシュ画面は`fullscreen`か`standalone`を指定する必要があります。

#### `orientation`
表示する画面を指定し、固定することができます。
`landscape`（横向き）か`portrait`（縦向き）を指定します。

#### `scope`
スコープを設定します。
スコープ外のページにはdisplayを`standalone`に設定していても以下のようなツールバーが表示されるようになります。
![IMG_8A85C8417A23-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/52e5face-9d92-30fc-dbe3-fddef002934f.jpeg)

#### `theme_color`
ツールバーとタスクスイッチャーの色を設定します。

#### `description`
アプリケーションの説明を追加することができます。

### 設定できているかの確認方法
manifest.jsonに記述して想定通り設定できているかどうか確認するには、スマートフォン等で実際に「ホーム画面に追加」してみて確認する他にPCではディベロッパーツールの「アプリケーション」で設定の状況やエラー等を確認することができます。
![スクリーンショット 2022-03-07 0.56.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/de8ebfb8-1b7c-e54d-e7dd-30a32ab652f8.png)
【Zsh】Zshの配列はインデックスが1から始まる...

# はじめに
今のMacのデフォルトログインシェルがzshなので、
ここ最近はzshを使うようになったのだけれど、
なんか配列に値を格納しようとしたらエラーが...

# zsh: array: assignment to invalid subscript range
配列の格納を下記のように書いたらこのエラーが発生
```zsh
% array[0]="test"
zsh: array: assignment to invalid subscript range
```
「添字(インデックス)の範囲が不正です」的な意味ですね。

今まで普通に0から指定していたはずだけどなーと思い、
念の為bashに切り替える

## bashで実行
```bash
bash-3.2$ array[0]="test"
bash-3.2$ echo ${array[0]}
test
bash-3.2$ 
```
はい、普通に通りましたね。

一瞬配列自体が廃止されたのかと疑いましたが、
zshは高機能なイメージなのでそれはないだろうと...

## zshでrangeを変えて実行
```zsh
% array[1]="test"
% echo ${array[1]}
test
% 
```
通りました。
結果zshはインデックスが1からスタートするタイプでした。
(cshと同じですね)

## 文字を使用したインデクスが使えなくなった!?
bashでは以下のように配列のインデックスに数字だけでなく、文字を指定することも可能でした。
```bash
bash-3.2$ array[a]="test"
bash-3.2$ echo ${array[a]}
test
```
しかし、zshでは

```zsh
% array[a]="test"
zsh: array: assignment to invalid subscript range
```
同じく"invalid subscript range"となるので、
ダメもとで、大文字にしてみたり、"b"を入れてみたりしたけど変わらず。

まぁインデックスを文字指定することはほぼなかったですが、
指定方法が変わったとかでなく、本当に廃止されてしまったのか気になりますね。
　
### 【2023/3/26更新】 使えました

コメントで教えていただき、
無事解決しました。

zshでは事前に連想配列として変数を宣言しておく必要があるようです。

```zsh
#typeset
% typeset -A array
% array=(name "太郎")
% echo ${array[name]}
太郎

% unset array
% echo ${array[name]}
%

#local
% local -A array
% array=(name "ピカ太郎")
% echo ${array[name]}
ピカ太郎

% unset array
% echo ${array[name]}
%

#dclare
% declare -A array
% 
% array=(type "電気")
% echo ${array[type]}
電気

```

#### 宣言してない場合
宣言する前に同じ形式で変数に値を入れてみると

```zsh
% array=(name "ピカ太郎")
%
%
% echo ${array[name]}    
 
```
~~エラーにはなりませんが、参照しても何も入っていない。~~
コメントにて指摘頂きましたが、この認識は誤りでした。
上記はただの配列の書き方でしたね。
エラーにならないのも当然です。。。

また配列のインデクスの指定で使われる[]は算術式として評価されるそうです。
要するにif文などと同様で[]はあくまで**testコマンド**ということですね。
結果以下のように書けました。
```zsh
% array=(name "ピカ太郎")
#${array[1]}:name
#${array[2]}:ピカ太郎

% echo ${array[1 + 1]} #[]の中が計算され、${array[2]}となる
ピカ太郎
```

### 参考

typesetのオプションAヘルプ
>　 -A     The names refer to associative array parameters; see
                     `Array Parameters' in zshparam(1).	

associative(連想の)でAオプションと覚えておきます。
Win11の記憶域スペースは作り方によって「シンプル」の動作が変わる

# 環境
- Windows 11 pro 22H2

# 「設定」から「記憶域スペースの管理」
「シンプル（回復性なし）」を選ぶと、いわゆるストライピング(raid0）として動作する。

# 「コントロールパネル」から「記憶域の管理」
「シンプル（回復性なし）」を選ぶと、いわゆるスパニング(JBOD)として動作する。

# あとがき
PowerShell使わないとストライプならないよ、という記事しか見つけられなかったのだけど、実際に試してみたらそんなことなかったのでメモ書き。記憶域はドライブの管理を簡単にするという目的での機能だと思うのに、その設定や手順がややこしすぎて、目的を見失っている感がある。
【Mac】vueコマンドを打つと「command not found: vue」が出た時の対処法

# 現象
Vue-cliをyarnでインストール後、vueコマンドを打つと以下のエラーが出る。
zsh: command not found: vue

# 環境
macOS Big Sur 11.7.2
Node.js 14.16.0
npm 7.6.3


# 原因
Vueコマンドファイルの配置ディレクトリパスがPATH環境変数に含まれていない

# 解決法
Vueコマンドファイルの配置ディレクトリパスをPATH環境変数に追加

以下のコマンドを実行
```　sh
$ yarn global bin             
/Users/kyo-k1187/.yarn/bin
```

上のコマンドで帰ってきたbinディレクトリに、vueコマンドファイルがあるか確認
lsコマンドを打ってvueファイルがあることを確認します。

```
$ ls /Users/kyo-k1187/.yarn/bin
create-vite	cva		vue
```

VueコマンドファイルがあるディレクトリパスをPATH環境変数に追加

```
$ export PATH=$PATH:/Users/kyo-k1187/.yarn/bin
```

以下のコマンドを実行し、vue-cliのバージョンが返ってくることを確認

```
$ vue --version
@vue/cli 5.0.8
```

上記設定は開いているターミナルでのみ有効であり、永続的にvueコマンドを叩けるようにしたい場合は以下を実行します。

ホームディレクトリにある.zshrcファイルを編集します。

```
$ vi ~/.zshrc
```

以下の行を追加して保存します。

``` .zshrc
export PATH=/Users/kyo-k1187/.yarn/bin:$PATH
```

ターミナルを再起動し、以下コマンドを実行してvue-cliのバージョンが返ってくることを確認します。

```
$ vue --version
@vue/cli 5.0.8
【Python】Atcoder勉強記録⑤

# atcoder復習
下記にatcoderで解いたB問題を記載します。
勉強の記録として残します。是非参考にしてください。
[解いた問題一覧](https://kenkoooo.com/atcoder/#/table/kenbo0224)

# 1.問題①
[B - Tournament Result](https://atcoder.jp/contests/abc261/tasks/abc261_b)（<font color="SpringGreen">Difficulty74</font>）

### 解答
```python
N = int(input())
a_list = []
for _ in range(N):
    a = input()
    a_list.append(a)

flg = True

for i in range(N):
    for j in range(N):
        if a_list[i][j] == '-':
            continue
        else:
            if a_list[i][j] == 'W':
                if a_list[j][i] != 'L': # L以外
                    flg = False
            if a_list[i][j] == 'L':
                if a_list[j][i] != 'W':
                    flg = False
            if a_list[i][j] == 'D':
                if a_list[j][i] != 'D':
                    flg = False

if flg:
    print('correct')
else:
    print('incorrect')
```
### 解説
入力された文字をlistにセットして二重ループで文字の内容を確認する。
二次元配列のデータにアクセスして次の文字を確認して正しい文字かどうかを判断する。
a_list[i][j] == a_list[j][i]で文字を判断する。iは外側のループで固定でjは内側のループで文字をそれぞれ確認する。
文字が-の場合はjのループを次の行にする。
最後にif文でflgのデータを見て表示する文字を決める。

# 2.問題②
[B - First Query Problem](https://atcoder.jp/contests/abc283/tasks/abc283_b)（<font color="SpringGreen">Difficulty35</font>）

### 解答
```python
N = int(input())
num_list = list(map(int, input().split()))
Q = int(input())
ans_list = []
for i in range(Q):
    q_list = list(map(int, input().split()))
    if len(q_list) == 3:
        n = q_list[1] # 置き換えの位置
        m = q_list[2] # listの最後の要素
        num_list[n - 1] = m
        n_1 = q_list[1]
    else:
        n_1 = q_list[1]
        ans = num_list[n_1 - 1]
        ans_list.append(ans)
for j in ans_list:
    print(j)
```
### 解説
num_listを置き換かえながらデータを表示していく
q_listがの要素数が3だったnum_listを置き換えるようにする。
q_listの最後の要素を置き換える。置き換えの位置はq_listの二番目の要素を取得してその場所にあるデータを置き換える。
q_listが3以外の場合はnum_listの要素にアクセスして値を取得する。
ans_listにセットして最終的にfor文で格納したデータを表示する。

# 3.問題③
[C - Cash Register](https://atcoder.jp/contests/abc283/tasks/abc283_c)（<font color="SpringGreen">Difficulty88</font>）

### 解答
```python
S = input()
ans = len(S)
cnt = 0
for i in S:
    if i == '0':
        cnt += 1
    else:
        cnt = 0
    if cnt == 2:
        cnt = 0
        ans -= 1
print(ans)
```
### 解説
最初ansに入力した文字列の文字数を格納する。格納した文字をfor文で確認して文字が0だった場合は確認フラグにプラス1をする。
それ以外の場合は確認フラグを0に戻す。
0が二つ(確認フラグが2)になった場合はansの文字数を1引いていく。
最終的に集計したansを表示する。
Rubyのincludeとは

### includeとは
+ モジュールをクラスに含める際に使用される。クラスはモジュールのメソッドを利用できるようになる。
→  `include モジュール名`
+ クラスに複数含めることが可能。
+ クラスのようにインスタンス化はできない。

### include?とは
+ 対象のオブジェクトに検索したい文字列が含まれているかどうかを検証し、trueまたはfalseを返す。
→  `オブジェクト.include?(検索文字列)`
SSMSでクエリ結果をファイルに保存したい

SSMSでクエリ結果をファイルに保存したい場合、以下の手順で設定を行います。

① ツール > オプション を選択する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105859/c59a6619-e2fd-ee0f-1714-a51ded9a4095.png)

② クエリ結果 > SQL Server > 全般 を選択し、「結果の既定の出力先(D)」を「結果をファイルに出力」に設定する。「クエリ結果の既定の保存先(E)」には、ファイルを保存するフォルダを設定し、OKを押下する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105859/cfb0ff26-b44f-882f-5396-f83e39dee5a8.png)

※1 後述しますが、入力したフォルダは既定の保存先にすぎません。実際にはSQL実行のたびにフォルダ選択が可能です。

※2 クエリ結果 > SQL Server > 結果をテキストで表示 から 出力形式の細かい設定が可能。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105859/14e5274e-7b71-bd65-fd2e-f54ca0d6a020.png)

---

設定が終わったので、実際に動かしてみましょう。ここでは例として、以下のようなSQLを実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105859/2913e675-a453-396e-2ab7-42757487bab5.png)

SQL実行後、ファイルダイアログが開くので、任意の名前を入力し、ファイルを保存します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105859/e0ee62f1-3501-f5d7-6741-628dcb457428.png)

ファイルの拡張子はrptとなっています。見慣れない拡張子ですが、**実態は単なるフラットファイルです。** そのため、任意のテキストエディタで中身を確認することが可能です。ここではsakuraエディタを使って、さきほどのファイルを確認すると、実行したSQLの結果が保存されていることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105859/f9aa9eba-3ca1-79f6-6d57-88f0e165a687.png)

---

__環境情報:__

![SSMS_Version.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105859/7db5027f-0274-33c6-42f7-c86596eb2687.png)
LINE公式アカウントの作成～Messaging API試行【発声練習】

# 背景
ある目的があり，個人利用のLINEアカウント宛に定期的にメッセージを送りたい．

# できたこと
LINE Messaging APIを叩くことで，新規作成したLINE公式アカウントから個人利用のLINEアカウント宛に，メッセージを送信した．

# やったこと
- LINE公式アカウントの作成
- LINE Messaging APIのお試し
- (Embeddable Pythonを用いた環境構築)
    - 本記事では説明しない．

# LINE公式アカウントの作成
Web上に大量に転がっている情報を参照した．
- https://first-contact.jp/blog/article/linebot/
   - タイトル: LINE BOTの作り方～アカウントの作成とQ&Aの登録方法～
   - ｢LINE BOTの作り方 -Messaging APIで開発編-｣項以降を参考にした． 
   
- https://udemy.benesse.co.jp/development/app/line-bot-making.html
    - タイトル: LINE BOTの作り方とは？Messaging APIを利用した作成法3選
    - ｢LINE BOTの作り方②LINE Messaging APIで開発｣項以降を参考にした．

- https://kubogen.com/web-programing-245/
    - タイトル: PythonとLINE Messaging APIでLINE BOTを作ってみた
    - 前半部分を参考にした．

# LINE Messaging APIのお試し
Pythonで叩きたかった．
｢LINE公式アカウントの作成｣にも記載した下記サイトを，引き続き参考にした．
- https://kubogen.com/web-programing-245/
    - タイトル: PythonとLINE Messaging APIでLINE BOTを作ってみた
    - 後半部分を参考にした．

上記のサイトでは，LINE BOTの構築を目標としている．したがって，

1. FlaskでのWebサーバ立ち上げ
1. ユーザのテキスト送信を検知
1. (何らかのプロセス)
1. ユーザへ返答テキスト送信

の順に処理するプログラムが記載されているが，今回の私の目的においては最後2つの処理さえ実装すれば良い．

｢ユーザへ返答テキスト送信｣については，下記コードを作成した．

```hoge.py
line_bot_api = LineBotApi(ACCESS_TOKEN)

# どうせ自分しかユーザがいないので，broadcastメソッドを使う．
line_bot_api.broadcast(TextSendMessage(text='本日は晴天なり'))
```

十分に理解はできていないが，私の個人利用のLINEアカウントにメッセージが届いたので，まずは良しとする．
![51663.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323977/d02ddae6-b574-9153-f0e2-06f20bdd175d.jpeg)
｢(何らかのプロセス)｣はこれから考えていく．
【App Runner】M1 Macで作成したコンテナイメージをデプロイする際の注意点

# 本題
M1 Macで作成したコンテナイメージを使って、AppRunnerのデプロイを試みたところ、エラーが出てデプロイに失敗しました。

デフォルトでは、M1 MacのDockerでデプロイしたコンテナイメージのplatformはarm64です。
arm64のコンテナイメージはAppRunnerではサポートされておらず、このイメージをデプロイしようとするとエラーが出てデプロイに失敗します。
そのため、コンテナイメージをデプロイする際に、AppRunnerがサポートするplatformを指定する必要があります。
linux/amd64はAppRunnerでサポートされているので、これをplatformに指定すればデプロイできます。
``` Dockerfile
FROM --platform=linux/amd64 node:14

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
COPY package*.json ./

RUN npm install

# Bundle app source
COPY . .

EXPOSE 3000
CMD [ "node", "index.js" ]
```
proxmoxのWEB GUIをCloudflareを使って外からアクセスできるようにする

## 経緯
proxmoxというサーバー仮想化ソフトウェアがある。
自宅でAWSのEC2のように仮想マシンが建てれて便利なのだが、管理画面に外からアクセスするのが大変という問題がある。
自宅でアクセスする際も`https://サーバーのip:8006`にアクセスする必要があり、分かりにくいのとオラオラ証明書なのでどうにかしたかった。
そこでCloudflare Tunnelsとnginx、Cloudflare Accessを使って自宅の外にいるときもアクセスできるようにした。

## nginxのセットアップ
proxmoxは既に構築されているものとする。
proxmoxはHTTPSを無効化することが出来ないため、8006番で待ち受けているproxmoxのWEB GUIをnginxを使って80番ポートにリバースプロキシを設定する。

proxmoxはDebianベースのため、aptでnginxをインストールする。
`/etc/nginx/nginx.conf`を開き、`http {`の中に以下を追加する
```
server {
        listen 80;
        server_name _;
        location / {
                proxy_set_header Host $http_host;
                proxy_pass https://localhost:8006;
        }
}
```
設定を確認し問題なければ反映する
```
nginx -t
nginx -s reload
```

## Cloudflare Tunnelsの設定
80番のWEB GUIをCloudflare Tunnelsで拾う。
[公式ドキュメント](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/tunnel-guide/remote/)に従ってDashbordのAccess→Tunnelsから作成する。

基本的にはドキュメント通りで良いが、`Service`の`Type`は`HTTP`、`URL`は`localhost:80`とする。

## Cloudflare Accessの設定
このままではだれでもアクセスできるため、Cloudflare Accessで認証を追加する。
Dashbordの`Access`
→`Applications`
→`Add an application`からApplicationsを追加する。
その後`Tunnels`から対象のTunnelを選択し`Configure`
→`Public hostname`
→対象のhostnameを選択し`Configure`
→`Additional application settings`
→`Access`
→`Protect with Access`を有効にし、先ほど作成したApplicationを選択する

## おわり
これで認証付きのprxmox WEB GUIが認証付きで外からアクセスできるようになっているはずだ。
port 22: Operation timed outエラー（インスタンスの接続性チェックに失敗しました）

# EC2インスタンスに接続したい


いつものようにターミナル上でssh接続しようとしたところ
```
@rooter .ssh % ssh tester
ssh: connect to host 54.64.74.26 port 22: Operation timed out
```

とエラーが出る。同じエラー文が先日あったのでまたこのパターンかと思ってインスタンスを確認しに行ったらこの前とは違ったみたいです。

**インスタンスの接続性チェックに失敗しました**
![be0cf067f75b5d8bdc4eeedd36e78a80.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1962714/75291a46-ec7f-2459-c17f-5e908cb45f35.png)

該当のインスタンスの（ステータスチェック）のところを見ると、「インスタンスの接続性チェックに失敗しました」と書かれています。

原因としてはいくつかあるみたいですが、今回はメモリが圧迫されていたせいだと思われます。（実際にssh接続してたときもやたらと重くて、コマンドを打っても全然反応がなかったりした）

# 対策
このエラーの対処法は単純で、「インスタンスの状態」→「インスタンスの停止」で一度ストップさせます。
その後「インスタンスの開始」を押して（停止の直後に開始ボタンを押すと開始が失敗することがあります）しばらく待っていると緑の文字で「**接続性チェックに合格しました！**」と出ます。

# あとがき
「接続性チェックに失敗しました」と出るのは色々な原因が考えられるかと思いますが、まずはこれを試していただけるといいかなと思います。（簡単ですし笑）
docker-composeでネットワークが見つからない時の対処法



# network HOGE declared as external, but could not be found

新しくCloneしてきたやつをupしようとしたら変な表示が出た。

```
$ docker-compose up

network HOGE declared as external, but could not be found
```

# インストールするとか

いろいろ不足してるパッケージとか探したが、何も見つからなかった。

# 対処法

```
docker network create HOGE
```

HOGEのところにエラーで出たネットワーク名を入れればOK。

新たに作成して、もう一度`docker-compose up`をする。

# まとめ

めっちゃ時間取られてしまった。
[Laravel9 × SES] X-SES-CONFIGURATION-SETヘッダをメールに追加する方法



## X-SES-CONFIGURATION-SETとは？
X-SES-CONFIGURATION-SETは、Amazon Simple Email Service（SES）の機能の1つで、SESメール送信に関連する構成セットを識別するために使用されるヘッダ
このヘッダを使用することで、メールがユーザーに確認されたかどうかや、メール内のリンクが押下されたかなど、マーケティングに必要な情報を入手することができます。

取得できる情報としては以下の通り
#### 取得できるイベント
+ メールの受信
+ メールの拒否
+ メールの配信
+ メールの開封
+ メールのクリック
+ メールの返信
+ メールのBounce
+ メールのComplaint
+ メールのDelivery Delay


また、取得した情報をDBやログファイルに格納したり、SNSと連携することができます。
#### 出力先
+ CloudWatch
+ Amazon SNS
+ Firehose

#### 注意すべき点
X-SES-CONFIGURATION-SETヘッダを追加してメールを送信する場合、SES上でX-SES-CONFIGURATION-SETは削除されるため、**送信されたメールにはX-SES-CONFIGURATION-SETヘッダは存在しません**

![名称未設定ファイル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236873/d3559c5c-5cf3-3a70-4541-248a8e90aa0c.png)
上の図の通り、SESを経由する際にX-SES-CONFIGURATION-SETヘッダは削除されるため、ヘッダが付与されているかを確認するためには、AWS SESに送られる前に確認する必要があります。
その場合には、.envファイルの**MAIL_MAILER**をlogに変更すれば、SESに送られるメール情報を確認できます。

```bash:.env
MAIL_MAILER=log //メールを送信せず、メールの情報をログファイルに格納する
```

## 使用方法
### SESで追跡用のタグを作成する
タグの作成方法については、わかりやすい記事があったので、こちらを参考にしてください。

https://dev.classmethod.jp/articles/amazon-ses-open-click-tracking/

### LaravelでX-SES-CONFIGURATION-SETを追加
まずは、ヘッダ追加用の関数を追加したクラスを作成します。
```bash:
php artisan make:mail CustomMailable
```


```php:app/Mail/CustomMailable.php
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Symfony\Component\Mime\Email;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class CustomMailable extends Mailable
{
    use Queueable, SerializesModels;
    // SESの追跡用ヘッダー追加
    public function addSESHeader()
    {
        // Laravel9　以降の場合
        return $this->withSymfonyMessage(function (Email $message) {
            $message->getHeaders()->addTextHeader(
                'X-SES-CONFIGURATION-SET', '作成したタグ名'
            );
        });

        // Laravel8 以前の場合
        return $this->withSwiftMessage(function ($message) {
            $message->getHeaders()->addTextHeader(
                'X-SES-CONFIGURATION-SET', '作成したタグ名'
            );
        });
    }
}
```

次に、送信したいメールのMailクラスを作成し、ヘッダ追加用の関数を加えます。
```bash:
php artisan make:mail TestMail
```

```php:
<?php

namespace App\Mail\Api;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use App\Mail\CustomMailable; //追加

class TestMail extends CustomMailable //継承元をCustomMailableに変更する
{
    use Queueable, SerializesModels;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct()
    {

    }

    /**
     * Build the message.
     *
     * @return CustomMailable
     */
    public function build()
    {
        return $this->from(config('mail.from.address'), 'テストメール')
            ->subject('テストメールです！')
            ->text('テストメールの本文です')
            ->addSESHeader(); //追加
    }
}

```
後は、通常のメール送信と同じようにメールを送れば、X-SES-CONFIGURATION-SETヘッダが追加されたメールが飛びます。


## 参考資料
https://docs.aws.amazon.com/ses/latest/dg/monitor-using-event-publishing.html

https://tech.innovator.jp.net/entry/2017/08/31/183021
3/25 Ruby入門remained クラスなどなど編

# 個人的リマインド用

## クラス
```
class User(大文字から始める)
    def initialize(name)
        @name(インスタンス変数) = name
    end
    
    def sayHi
        puts "hi #{@name}"
    end
end

tom = User.new("tom") ← インスタンス化
tom.sayHi

bob = User.new("bob")
bob.sayHi
```
インスタンス変数はインスタンス内ならどこでもアクセスできる

## インスタンス変数へ外部からのアクセス attr_accessorとself
```
class User(大文字から始める)
    attr_accessor :name (外部からアクセスできるように)
        #setter: name=(value)　→ (外部から)tom.name("tom")
        #getter: name →　(外部から)p tom.name
    getterだけ定義したい時はattr_reader :name

    def initialize(name)
        @name(インスタンス変数) = name
    end
    
    def sayHi
        #self(メソッド内で書ける、そのメソッドを受け取っているインスタンス自身を
　　　　　　　　 指す。今回はtomのこと（レシーバーという）)
        puts "hi #{@name}"
        puts "hi #{self.name}で書き換え可能(selfも省略可)"
    end
end

tom = User.new("tom") ← インスタンス化
tom.sayHi

bob = User.new("bob")
bob.sayHi
```
## クラスのメソッドをインスタンス化せじ直接呼び出す
```
class User
    @@count(クラス変数) = 0
    VERSION(クラス定数) = 1.1

    def initialize(name)
        @@count += 1
        @name = name
    end

    def self.info
        puts "#{VERSION}: User class. #{@@count} instances(インスタンスした数)"
    end

User.info
p User::VERSION(外からも呼べる)
```
## クラスの継承
```
class AdminUser(子クラス, Sub Class) < User(親クラス, Super Class)
    継承したクラスのメソッドも使えるし、上書きもできる(オーバーライド)
end
```
## メソッドのアクセス権 public, protected, private
newした時に呼ばれるinitializeメソッドと、クラスの外に書いたメソッドは自動的にprivateになる

```
class User
    //クラス内からならprivateも呼び出せる
    //レシーバーを指定できないからselfを書かないように

    private
        def sayPrivate
            puts "Hi"
        end
end
```
User.new.sayPrivate(できない)
Sub classでもprivateを使えたり、オーバーライドできるので注意

## moduleで名前空間(名前が被らないように)
```
module Movie
    VERSION = 1.1
    
    def self.encode
        puts "encode"
    end

    def self.loading
        puts "loading"
    end
end

Movie.encode
Movie.loading
p Movie::VERSION
```

## moduleのもう1つの役割であるミックスイン
継承関係のない別々のクラスに同じメソッドを持たせたい時、その機能を持ったmoduleをつくる
```
module Debug
    def info(selfをつけずに単にインスタンスメソッドにしてあげると、
　　　　　　　　それを他のクラスのインスタンスメソッドとしてはめ込むことができる)
        puts "#{self.class} debug"
    end
end

class Player
    include Debug
end

class Monster
    include Debug
end

Player.new.info → "Player debug"
```

## 例外処理

```
x = gets.to_i

begin
    p 100 / x
Rescue => ex(例外が格納)
    p ex.message(エラーのメッセージを表示)
    p ex.class(エラーのクラスを表示)
    puts "stop!"(自分でメッセージを表示)
ensure(エラーが起こっても続ける時)
    puts "__END__"
end

※自分で例外処理を作る場合
class MyError < StandardError(rubyの標準クラスを継承) end
begin
    if x == 3
        raise MyError
    end
    p 100 /x
rescue MyError
    puts "Error 3!"
rescue => ex(例外が格納)
    p ex.message(エラーのメッセージを表示)
    p ex.class(エラーのクラスを表示)
    puts "stop!"(自分でメッセージを表示)
ensure(エラーが起こっても続ける時)
    puts "__END__"
end
```
PythonのTkinterでFrameをスクロールする

# はじめに
Pythonの標準ライブラリに含まれるGUIライブラリのTkinterを使っていて、「Frameウィジェットをスクロールしたい！」というタイミングで少しハマったので、まとめます。

コピペしてすぐに動作確認可能なサンプルコードを載せています。

# Frameウィジェット

[Frameウィジェット](https://tkdocs.com/shipman/frame.html)は、LabelやButtonを配置することで複雑なウィジェットを構築することが可能です。

# Scrollbarウィジェット

Tkinterのいくつかのウィジェットは、[Scrollbarウィジェット](https://tkdocs.com/shipman/scrollbar.html)を取り付けることで、ウィンドウより大きな仮想領域にビューをスライドできるようになります。

# FrameにScrollbarを直接取り付けることはできない

TkinterでScrollbarを直接取り付ける（Scrollbarの親ウィジェットとして設定する）ことが可能なウィジェットの例は、以下です。

- Canvas
- Listbox
- Entry
- Spinbox
- Text

...そう、FrameにScrollbarを直接取り付けることはできないのです。

これはTkinterの仕様です。

# じゃあどうするのか

FrameをCanvasに埋め込み、そのCanvasにScrollbarを取り付けることで、Frameをスクロールしているように見せることができます。

Scrollbarが実際にスクロールする対象は、Canvasです。

以下、コピペしてすぐに動作確認可能なサンプルコードです。

```python
import tkinter as tk

root = tk.Tk()
root.geometry("900x600")
canvas = tk.Canvas(root)
frame = tk.Frame(canvas)

# Canvasを親とした縦方向のScrollbar
scrollbar = tk.Scrollbar(
    canvas, orient=tk.VERTICAL, command=canvas.yview
)

# Frameを親とした動作確認用のLabel
label = tk.Label(frame, text="動作確認用ラベル")

# スクロールの設定
canvas.configure(scrollregion=(0, 0, 900, 900))
canvas.configure(yscrollcommand=scrollbar.set)

# 諸々を配置
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
canvas.pack(expand=True, fill=tk.BOTH)
label.pack(expand=1)

# Canvas上の座標(0, 0)に対してFrameの左上（nw=north-west）をあてがうように、Frameを埋め込む
canvas.create_window((0, 0), window=frame, anchor="nw", width=900, height=900)

root.mainloop()

```

Canvasクラスのcreate_window()メソッドにより、Canvasに他のウィジェットを埋め込むことができます。

埋め込むウィジェットの実体は、[Canvas Window オブジェクト](https://tkdocs.com/shipman/create_window.html)といいます。

Canvasに埋め込んだウィジェットは、Canvasのスクロールと連携してスクロールします。
S3のオブジェクトを更新したらLambdaレイヤーの更新も必要？

# 答え
### YES
※結論だけ知りたい人は戻るボタンをPUSH!
# 実験（変更前）
・下記のディレクトリ構造でファイルを作成

>ffmpeg.zip/
>　└ bin/
>　 　└ ffmpeg

・該当のZIPアーカイブをS3に格納し、Lambdaレイヤーを作成。
![スクリーンショット 2023-03-25 20.49.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778864/5c906f47-9da3-a1b7-fa1a-ee4f2ae23c04.png)

・Lambda関数のコードを記述
・printでディレクトリを表示するだけの関数
~~~python:lambda_function.py
import json
import os

print("Contents of /opt/bin directory:")
print(os.listdir('/opt/bin'))

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }
~~~

・Lambda関数にLambdaレイヤーを設定
![スクリーンショット 2023-03-25 20.52.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778864/68e95c57-8300-0929-3b4c-0b6a4c67cc97.png)

テスト！
![スクリーンショット 2023-03-25 21.17.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778864/fc294b26-e884-56b2-15c4-75ce91e7cb45.png)

CloudWatchLogsの結果、想定通りffmpegが表示されました。
![スクリーンショット 2023-03-25 20.54.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778864/c08932fe-bb17-c34f-ab2f-74986f677af0.png)

# 実験（変更後）
・下記のディレクトリ構造に変更。binディレクトリを消しただけ。

>ffmpeg.zip/
>　 └ ffmpeg

・既存のffmpeg.zipを削除し変更後の同名のZIPアーカイブをS3に格納。

・この後にLambda関数をテストしてもCloudWatchLogsに何も表示されない。

・Lambdaレイヤーを更新S3のURLなど全て以前と同様。バージョン2であることを確認![スクリーンショット 2023-03-25 21.29.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778864/b7977ae3-0eb6-92b4-4bd7-5ddf2caf0856.png)

・Lambda関数のLambdaレイヤーを更新。バージョン2を設定。
![スクリーンショット 2023-03-25 21.28.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778864/f8aa8e72-96eb-cdba-6c0c-70dc00f00fe6.png)

・テスト！
・binディレクトリは消えているので想定通りのエラー
![スクリーンショット 2023-03-25 21.31.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2778864/ee5dc0b5-efb8-9c0f-d03a-2d6117d7c1c0.png)

# 結論
### S3のオブジェクトを更新したらLambdaレイヤーの更新もしよう！（大事なことなので2回言いました。）
ChatGPTで繰り返し処理を使い丁寧な文章を自動生成する

# はじめに
繰り返し処理を明示的に指定することで、ChatGPTが文章の生成とフィードバックを自動で行うという話を聞いたので実際に試してみました。

# 実際にやってみた
## その1. 隣の客はよく柿食う客だ
入力の文章とロジックを指定してあげます。
```
以下の処理の基づいて回答を行ってください。

入力 = "隣の客はよく柿食う客だ"
丁寧ポイント = 文章の丁寧さを100点満点で判定(入力))

ループ(丁寧ポイント < 100):
  分析結果 = 丁寧な文章にするためにはどこを修正するべきかをコメント(入力)
  回答文 = 丁寧な文章に変換(入力, 分析結果)
  丁寧ポイント = 文章の丁寧さを100点満点で判定(回答文))
  分析結果、回答文、丁寧ポイントを出力(分析結果, 回答文, 丁寧ポイント)

  入力 = 解答文
```
```
入力: "隣の客はよく柿食う客だ"
丁寧ポイント: 60点

分析結果:

「よく」を「しばしば」と言い換える。
「柿食う」を「柿を召し上がる」と丁寧な表現にする。
「客だ」を「お客様です」と丁寧な表現にする。
回答文: "隣のお客様はしばしば柿を召し上がるお客様です"
丁寧ポイント: 90点

分析結果:

一部の表現がまだ丁寧でないため、「隣のお客様は」を「隣にいらっしゃるお客様は」と変更する。
回答文: "隣にいらっしゃるお客様はしばしば柿を召し上がるお客様です"
丁寧ポイント: 100点

最終的な丁寧な文章: "隣にいらっしゃるお客様はしばしば柿を召し上がるお客様です"
```
それっぽく動いてくれました。

## その2. 見ろ、人がゴミのようだ。
今度はムスカさんの言葉を引用してみます。2回目なので前回のロジックを流用してもらいました。
```
入力を"見ろ、人がゴミのようだ。"に変えて再度回答をお願いします。
```
```
入力: "見ろ、人がゴミのようだ。"
丁寧ポイント: 40点

分析結果:

「見ろ」を「ご覧ください」と丁寧な表現にする。
「人がゴミのようだ」を「人々がまるでゴミのようです」と丁寧かつ優しい表現にする。
回答文: "ご覧ください、人々がまるでゴミのようです。"
丁寧ポイント: 80点

分析結果:

「人々がまるでゴミのようです」をさらに丁寧に表現するため、「人々がまるでゴミのように見えます」と変更する。
回答文: "ご覧ください、人々がまるでゴミのように見えます。"
丁寧ポイント: 100点

最終的な丁寧な文章: "ご覧ください、人々がまるでゴミのように見えます。"
```
ゴミという言葉は残しつつ、丁寧な形に修正してくれました。

## その3. さすがディオ！おれたちにできない事を平然とやってのけるッ そこにシビれる！あこがれるゥ！
文章を長くかつ癖のある文章にしてみます。
```
入力を"さすがディオ！おれたちにできない事を平然とやってのけるッ そこにシビれる！あこがれるゥ！"に変えて再度回答をお願いします。
```
```
入力: "さすがディオ！おれたちにできない事を平然とやってのけるッ そこにシビれる！あこがれるゥ！"
丁寧ポイント: 40点

分析結果:

「おれたち」を「私たち」と丁寧な表現にする。
「平然とやってのける」を「簡単にこなしてしまう」と丁寧な表現にする。
「シビれる」を「感嘆する」と丁寧な表現にする。
「あこがれるゥ」を「憧れます」と丁寧な表現にする。
回答文: "さすがディオ！私たちにできないことを簡単にこなしてしまう。そこに感嘆する！憧れます！"
丁寧ポイント: 90点

分析結果:

より丁寧な表現にするため、「さすがディオ！」を「ディオ様はさすがです！」と変更する。
回答文: "ディオ様はさすがです！私たちにできないことを簡単にこなしてしまう。そこに感嘆する！憧れます！"
丁寧ポイント: 100点

最終的な丁寧な文章: "ディオ様はさすがです！私たちにできないことを簡単にこなしてしまう。そこに感嘆する！憧れます！"
```
こちらも2回の繰り返しで丁寧な文章を作成してくれました。
## その4. 『任務は遂行する』『部下も守る』。「両方」やらなくちゃあならないってのが「幹部」のつらいところだな。覚悟はいいか？オレはできてる
更に文章を長くしてみます。
```
入力を"『任務は遂行する』『部下も守る』。「両方」やらなくちゃあならないってのが「幹部」のつらいところだな。覚悟はいいか？オレはできてる"に変えて再度回答をお願いします。
```
```
入力: "『任務は遂行する』『部下も守る』。「両方」やらなくちゃあならないってのが「幹部」のつらいところだな。覚悟はいいか？オレはできてる"
丁寧ポイント: 45点

分析結果:

「『任務は遂行する』『部下も守る』」を「『任務を遂行する』と『部下も守る』」に丁寧な表現にする。
「やらなくちゃあならない」を「なさなければならない」と丁寧な表現にする。
「幹部」の前後の「」を削除する。
「つらいところだな」を「大変な部分ですね」と丁寧な表現にする。
「覚悟はいいか？」を「覚悟はできていますか？」に丁寧な表現にする。
「オレはできてる」を「私はできています」と丁寧な表現にする。
回答文: "『任務を遂行する』と『部下も守る』、両方なさなければならないことが幹部の大変な部分ですね。覚悟はできていますか？私はできています。"
丁寧ポイント: 100点

最終的な丁寧な文章: "『任務を遂行する』と『部下も守る』、両方なさなければならないことが幹部の大変な部分ですね。覚悟はできていますか？私はできています。"
```
まさかの一発OKでした。

# まとめ
繰り返し処理を明示的に指定することで、ChatGPTが生成とフィードバックを自動で何度も行ってくれることが分かりました。
時間があればプログラムの自動生成とデバッグを自動で行ってくれるか試してみたいと思います。
Java(Spring)_子クラスでトランザクション管理が効かない場合の対処法

## 前提
対象技術：Java(Spring)

以前、Java(Spring)のシステムでトランザクションが効かないという問題が発生しました。
その問題の内容と、問題を解決した方法について紹介をさせていただきます。


## 発生した問題
```java:java
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public class SamplDetailServiceImpl extends SamplServiceImpl {

    public Foo getFoo(String fooName) {
        // do something
    }
}
```
上記のような、ServiceImplを継承したSamplDetailServiceImplクラスが、呼び出し元のクラスパス内に存在する想定で
```java:java
@Autowired
private SamplService　samplService;

samplService.registerFooList(fooList);
```
上記のように実行をした場合に、
親クラスのSamplServiceImplで実装されているregisterFooListメソッドでトランザクションが効かないという問題です。

ちなみに親クラスの実装は、
```java:java
public class SamplServiceImpl implements SamplService {

    public void registerFooList(List<Foo> fooList) {
        // do something
    }
}
```
上記のような実装を想定します。

## 解決方法
原因は、実際に呼び出している実装クラスで「直接呼び出されていないメソッド」を呼び出した場合、
トランザクションが効かないという事象が発生してしまいます。

そこで、SamplDetailServiceImplの実装クラスを
```java:java
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
public class SamplDetailServiceImpl extends SamplServiceImpl {

    public Foo getFoo(String fooName) {
        // do something
    }
    
    @Override
    public void registerFooList(List<Foo> fooList) {
        super().registerFooList(fooList);
    }

}
```
上記のように、実際に呼び出している実装クラスで、親クラスの実装を直接呼び出すようにすることで、
トランザクションを有効にすることができます。
北陽電機製2D-LiDAR（UTM-LX-30）をROSで動かす方法

# 1. はじめに
ROS初心者が北陽電機製の2D-LiDARをROSで動かす方法の議事録
環境は以下のとおり
Ubuntu 18.04 LTS
ROS

# 2. UTM-LX-30をPCに接続
ターミナルを開き以下を実行し接続デバイスを確認
```
dmesg
```
ttyACM0の名前で接続されていることがわかる。

```
[ 2822.168000] usb 3-1: new full speed USB device using uhci_hcd and address 2
[ 2822.328000] usb 3-1: configuration #1 chosen from 1 choice
[ 2822.440000] cdc_acm 3-1:1.0: ttyACM0: USB ACM device
```

# 3. シリアルデバイスにアクセス権限を与える
ターミナルで以下を実行
```
sudo chmod 777 /dev/ttyACM0
```

# 4. 北陽電機の製品ページへ
順番に実行する。

https://sourceforge.net/p/urgnetwork/wiki/ROS_jp/


# 参考文献
https://sourceforge.net/p/urgnetwork/wiki/serial_jp/

https://www.robotech-note.com/entry/2018/07/23/ubuntu%E3%81%A7USB%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%AB%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%EF%BC%88/dev/ttyACM0%E7%AD%89%EF%BC%89%E6%8E%A5%E7%B6%9A%E6%99%82%E3%81%AB%E8%87%AA%E5%8B%95%E3%81%A7%E6%9B%B8
WSL2起動時にdockerなどのサービスを同時に起動する(systemd利用)

WSL2を使う際、以前はいちいち`sudo service docker start`などと打たなければならず不便だったが、気づけばWSLのアップデートにより、いくつか設定を追加すればこの辺の問題が解消されることに気づいたのでメモ。

## 前提条件

[wsl-configの公式ドキュメント - systemdのサポート](https://learn.microsoft.com/ja-jp/windows/wsl/wsl-config#systemd-support)を見ると、
バージョン0.67.6以降のWSL2でsystemdを有効に出来ることが分かる。

PowerShellなどで

```powershell
wsl --version
```
などと打って上記の条件を満たすことを確認する。

ちなみに今回検証を行った環境はWindows11で、

```
# wsl --version
WSL バージョン: 1.1.3.0
カーネル バージョン: 5.15.90.1
WSLg バージョン: 1.0.49
MSRDC バージョン: 1.2.3770 
Direct3D バージョン: 1.608.2-61064218
DXCore バージョン: 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp
Windowsバージョン: 10.0.22621.1413
```

といった感じ。また、使ったディストリビューションはストアから入手したUbuntu22.04LTSであり、
サービスを起動する対象してDocker(Community Edition)を[docker-docs](https://docs.docker.com/engine/install/ubuntu/)に記載の手順に従ってインストールしている。

## 設定の実施

先程の[wsl.confに関するドキュメント](https://learn.microsoft.com/ja-jp/windows/wsl/wsl-config#systemd-support)に記載している通りにすればOK.

対象のWSL2ディストリビューションに入り、例えば`sudo vim /etc/wsl.conf`などとして`wsl.conf`に以下のような内容を追記・設定する。（※無ければ新規作成する）

```conf:/etc/wsl.conf
[boot]
systemd=true
```

次に、`systemctl`コマンドで使いたいサービスを`enable`にしておく。
今回の例ではdockerを自動起動するようにしたいので、

```sh
# bashなど
sudo systemctl enable docker
```

などとする。

今回はdockerの自動起動を例にしているが、例えば[Qiita - systemctl コマンド](https://qiita.com/sinsengumi/items/24d726ec6c761fc75cc9) などを参考にし、他のサービスの設定を同様に行うことが出来る。

最後に[systemdのサポート](https://learn.microsoft.com/ja-jp/windows/wsl/wsl-config#systemd-support)を参考に、以下のいずれかを実行する：

```powershell
# 全てのdistroのシャットダウン
wsl --shutdown

# 対象のものだけシャットダウン
wsl -t <対象のディストリビューション名>
```

これで次回起動時から`systemctl enable`したサービスが自動起動する。

実際に設定を行ったディストリビューションを再起動し、

```sh
# bashなど

# dockerサービスの例
sudo systemctl status docker

# ● docker.service - Docker Application Container Engine
#      Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
#      Active: active (running) since Sat 2023-03-25 20:29:51 JST; 11min ago
# TriggeredBy: ● docker.socket
#        Docs: https://docs.docker.com
#    Main PID: 585 (dockerd)
#       Tasks: 14
#      Memory: 148.4M
#      CGroup: /system.slice/docker.service
#              └─585 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
```

などのように、自分で`sudo systemctl start docker`とか`sudo service docker start`とかをやらなくても勝手に立ち上がっていることが確認できる。

## 参考

一応他のやり方もあるので紹介。

wsl-configの設定のドキュメントを読み進めると、[ブート設定](https://learn.microsoft.com/ja-jp/windows/wsl/wsl-config#boot-settings)という項目があり、WSLの開始時に実行するコマンドを指定できるとのこと。

ドンピシャな例としてdockerをWSL起動時に一緒に立ち上げる例が上記ドキュメント内で示されている。

```conf:/etc/wsl.conf
# Set a command to run when a new WSL instance launches. This example starts the Docker container service.
[boot]
command = service docker start
```

ただし、ドキュメントにも記載の通り、Windows11以降かWindows Server2022以降でないと使用できないとのこと。

個人的にはsystemctlが使える場合はそちらでやる方がWSLに依らない一般的な手法を使えるため良いような気がしたが、
これもどこかで使い道があるかもしれないのでメモしておく。
【tableタグ】サイズ調整

# tableタグ　サイズ調整したい

下記のように書くと、画面いっぱいに表示されてしまう…
中心にまとめたいなぁ、、、

```php
<h2>投稿一覧</h2>

      <table class="table">
        <thead>
          <th>画像</th>
          <th>タイトル</th>
          <th>カテゴリー</th>
          <th>本</th>
          <th>本文</th>
        </thead>
        <tbody>
          <% @spots.each do |spot| %>
        <tr>
          <td><%= image_tag spot.image, size: '150x100'%></td>
          <td><%= spot.name %></td>
          <td><%#= spot.category.try(:name) %></td>
          <td><%= spot.quality %></td>
          <td><%= spot.introduction %></td>
        </tr>
          <% end %>
        </tbody>
      </table>
```



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111780/ffa0a02f-856d-3aac-e7eb-424164968fad.png)


ということで調べていきました！

```php
<h2>投稿一覧</h2>
-------ここから-------
<div class="container text-center">
  <div class="row">
    <div class="col-md-12">
-------ここを追加--------
      <table class="table">
        <thead>
          <th>画像</th>
          <th>タイトル</th>
          <th>カテゴリー</th>
          <th>本</th>
          <th>本文</th>
        </thead>
        <tbody>
          <% @spots.each do |spot| %>
        <tr>
          <td><%= image_tag spot.image, size: '150x100'%></td>
          <td><%= spot.name %></td>
          <td><%#= spot.category.try(:name) %></td>
          <td><%= spot.quality %></td>
          <td><%= spot.introduction %></td>
        </tr>
          <% end %>
        </tbody>
      </table>
----これも追加-----
    </div>
  </div>
</div>
-----ここまで追加-----
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3111780/fa511af2-9c9a-761d-d3b4-e4fbd625d394.png)

こんな感じに中心にコンパクトに表示されました★
仮想マシン内に、外部のサイトから入手できるgzipをダウンロードする方法

## 前提
OS：Ubuntu20.04.3LTS
仮想化ソフト：Oracle VM VirtualBox

Linux系の仮想マシンの中に、gzipなどのファイルを外部のURLからダウンロードし、
仮想マシン内に取り入れる方法について、紹介します。

Linux系の仮想マシンを使用している場合は、ホストマシン上のファイルを仮想マシン上に移動させたりすることが難しいです。
そこで以前私は、仮想マシンでcurlでURLを叩いてファイルをダウンロードしようとしましたが、
直接素のHTMLが返却されただけで、ファイルのダウンロードができなかった経験があります。


## 仮想マシンで外部からファイルをダウンロードする簡単な方法
Gitを使用することで、簡単に仮想マシン内にファイルをダウンロードすることができます。

システムの本番環境サーバとして仮想マシンを使用されている場合は、Gitがインストールされていると思います。使用中のレポジトリの中に、
別のPCでダウンロードした対象のファイルを忍ばせます。そしてgit push

そして、仮想マシンでgit pullをすれば、欲しいファイルを仮想マシン内に入れ込むことができます。
あとは好きな場所にファイルを移動させたり、ファイルを展開するなどは通常の手順と同じです。
家庭内LANのドメインについて

## 家庭内LANでもドメインを使いたいが、どんなドメインなら良いか？

家庭内のLANで使うマシンにドメイン名を付ける際、プライベートIPアドレスのように使えるドメインみたいなものがあるかどうか、調べてみました。

ずっとプライベートIPアドレスを指定して接続していましたが、やっぱりドメインを使いたいと思い立ち、調べてみました。

## 現状では.homeなら良さそう

結論から言うと、現時点では「.home」なら良さそうです。

JPNICの記事によると、ICANNでは.homeと.corpについて、以下のように扱っているそうです。

https://www.nic.ad.jp/ja/newsletter/No57/0800.html

> .home、.corpについては、特に名前衝突の影響が大きいことが考えられるため、無期限に新gTLDとしての追加を保留

無期限という対処を解除されてしまったら、.homeも危ういことになってしまうのですが、名前衝突の影響が特に大きいドメインだということになっているので、無期限ではなく、恒久的に追加をしないでもらえたらいいなと思っています。

## .localは使わないほうが良い

過去に家庭内のLANで使うドメインの例として、.localを見かけた記憶がありました。私も実際、最初は.localを使っていました。

しかし、.localはmDNS（マルチキャストDNS）で使われるので、mDNSを使うのであれば、使用しないほうが良いとのことでした。

.localがmDNSで使われていることについては、RFC6762「Multicast DNS」に書かれています。

https://datatracker.ietf.org/doc/html/rfc6762


## 【使用しているルーター次第】家庭内LANの名前解決は、ルーターで行う

せっかく家庭内LANでドメインを使うようにしたので、名前解決をできるようにします。

私はヤマハのRTX810を使っているのですが、このRTX810には静的DNSレコードを登録する機能があります。
そのため、新たにDNSサーバーを立てることなく名前解決を行えます。

なお、各PC・スマートフォンなどのDNSサーバーはネットワーク構築時からRTX810にしてあるので、今回は静的DNSレコードをRTX810に登録するだけで済みました。

### RTProの当該ページ

http://www.rtpro.yamaha.co.jp/RT/manual/rt-common/dns/ip_host.html

### 対応機種

RTX5000, RTX3500, RTX1300, RTX1220, RTX1210, RTX830, RTX810

## RTXシリーズでの静的DNSレコードの設定方法

`ip host`コマンドで登録します。1番目の引数にドメイン名を含んだホスト名、2番目の引数でIPアドレス（IPv4、IPv6）を指定します。

```:例
# ip host red.home 192.168.1.3
```

登録したレコードを削除するには`no ip host`コマンドを使用します。

```:例
// IPアドレスは省略可能
# no ip host red.home

// IPアドレスを付けても動作する
# no ip host red.home 192.168.1.3
```