OmniAICreator/Qiita-1.07M huggingface dataset:
AWS cloud9でサーバー起動時に"Your version of SQLite (3.7.17) is too old. Active Record supports SQLite >= 3.8."というエラーで困った

## エラー内容
rails new で新しくアプリを作成し、ブラウザのホストを許可した後、rails sでサーバーを立ち上げた時に以下のエラーが発生！
![スクリーンショット 2022-08-03 15.47.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759696/9e2668d6-0478-4714-16fd-0a799f5e59a8.png)

## 解消方法
こちらの記事に助けていただきました👇
https://mebee.info/2021/01/13/post-27973/　
https://qiita.com/nosniklim/items/58154b3ba6ab9a26230c

### エラー文からの考察
```
Your version of SQLite (3.7.17) is too old. Active Record supports SQLite >= 3.8.
```
SQLiteのバージョンが古い！と怒っているようです。
どのようにバージョンを更新すればいいのでしょうか？

### SQLite３をアップデート
怖いかもしれませんが、私はこれで解決したので信じてついてきてください！
①アプリのディレクトリに移動し、以下を順番に実行
```
ec2-user:~/environment/"アプリ名" $ wget https://www.sqlite.org/2021/sqlite-autoconf-3360000.tar.gz
ec2-user:~/environment/"アプリ名" $ tar xzvf sqlite-autoconf-3360000.tar.gz
```
②sqlite-autoconf-3360000というディレクトリに移動し、以下を順番に実行
```
ec2-user:~/environment/"アプリ名" $ cd sqlite-autoconf-3360000 //ここでディレクトリを移動
ec2-user:~/environment/"アプリ名"/sqlite-autoconf-3360000 $ ./configure --prefix=/opt/sqlite/sqlite3
ec2-user:~/environment/"アプリ名"/sqlite-autoconf-3360000 $ make
ec2-user:~/environment/"アプリ名"/sqlite-autoconf-3360000 $ sudo make install
```
③バージョンを確認
```
ec2-user:~/environment/"アプリ名"/sqlite-autoconf-3360000 $ /opt/sqlite/sqlite3/bin/sqlite3 --version
```
出力結果：3.36.0（私の場合）
④再度アプリのディレクトリへ移動し、以下を順番に実行
```
ec2-user:~/environment/"アプリ名"/sqlite-autoconf-3360000 $ cd ../ //アプリのディレクトリに戻る
ec2-user:~/environment/"アプリ名" $　gem uninstall sqlite3　
```
👆gem uninstall sqlite3　を実行した際、「どれを消しますか？」みたいなことを英語で聞かれます。私は「全て消す（英語）」を選択しました。
その後、以下を実行
```
ec2-user:~/environment/"アプリ名" $　gem install sqlite3 -- --with-sqlite3-include=/opt/sqlite/sqlite3/include --with-sqlite3-lib=/opt/sqlite/sqlite3/lib
```
⑤rails sしてエラーが解消されているか確認すると、エラーが出ず、いつものブラウザに戻っているはずです。
![スクリーンショット 2022-08-03 15.43.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759696/fd58bb50-ce6e-46ba-9874-c8a60573cf46.png)

## まとめ
初めてのエラーでしたが、先人たちの記事のおかげで解決することができました！！
EKS managed nodeのデフォルト時間同期設定

結論からいうと、EKSのManaged nodeはデフォルトでchronyによるAmazon Time Sync Service (以下、TSC)との時間同期設定がされている

```bash
# Make sure Amazon Time Sync Service starts on boot.
sudo chkconfig chronyd on

# Make sure that chronyd syncs RTC clock to the kernel.
cat <<EOF | sudo tee -a /etc/chrony.conf
# This directive enables kernel synchronisation (every 11 minutes) of the
# real-time clock. Note that it can’t be used along with the 'rtcfile' directive.
rtcsync
EOF
```
ref: [EKS amiのinstall-worker.sh](https://github.com/awslabs/amazon-eks-ami/blob/7dc3326f2a529e34e1aab765d507df1c8db58c8e/scripts/install-worker.sh#L82-L90
)


なお、chronyとは、NTPクライアント・サーバー実装がされたソフトウェアのこと。 Amazon Linux２にはデフォルトでインストールされていて、TSCとの同期設定がされている。

VPCで実行されているすべてのインスタンスは、IPアドレス`169.254.169.123`または IPv6アドレス`fd00:ec2::123`のNTPサーバーを介してTSCを利用できるようになっている。

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/set-time.html

`chronyc sources`をつかったAmazon Linux2のNTPソース設定状況を確認例

```
chronyc sources -v

  .-- Source mode  '^' = server, '=' = peer, '#' = local clock.
 / .- Source state '*' = current best, '+' = combined, '-' = not combined,
| /             'x' = may be in error, '~' = too variable, '?' = unusable.
||                                                 .- xxxx [ yyyy ] +/- zzzz
||      Reachability register (octal) -.           |  xxxx = adjusted offset,
||      Log2(Polling interval) --.      |          |  yyyy = measured offset,
||                                \     |          |  zzzz = estimated error.
||                                 |    |           \
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^* 169.254.169.123               3   4   377    15  +4132ns[+5647ns] +/-  470us
^- ipv4.ntp3.rbauman.com         2  10   377   613   -301us[ -298us] +/- 2726us
^- i160-16-113-133.ntp-sv.d>     3  10   377   652   +211us[ +213us] +/- 3509us
^- time1.jp.danielmarks.dev      4  10   377   725  -2700ns[-8057ns] +/- 1239us
^- 40.74.139.173                 2  10   377   650   +279us[ +281us] +/-   46ms
```

`chronyc tracking`をつかったchronyからの時間同期メトリクスチェック例

```
chronyc tracking

Reference ID    : A9FEA97B (169.254.169.123)
Stratum         : 4
Ref time (UTC)  : Wed Aug 03 06:13:29 2022
System time     : 0.000000007 seconds fast of NTP time
Last offset     : -0.000000119 seconds
RMS offset      : 0.000000694 seconds
Frequency       : 0.648 ppm fast
Residual freq   : -0.000 ppm
Skew            : 0.013 ppm
Root delay      : 0.000401040 seconds
Root dispersion : 0.000277376 seconds
Update interval : 16.2 seconds
Leap status     : Normal
```
GASでSlack Bot Appを使ってメッセージ投稿する

Slack Appの作り方とbotの設定については省略します。

# GASでのSlackメッセージ送信
定型なので以下

```actionscript
function sendSlackMessage(message, channel) {
  Logger.log("Send Slack Message");
  var url = "https://slack.com/api/chat.postMessage";
  var bot_token = PropertiesService.getScriptProperties().getProperty("slackbot_token");

  var payload = {
    "token":bot_token,
    "channel" : channel,
    "text" : message
  };

  var options =
  {
    "method" : "post",
    "payload" : payload
  };

  UrlFetchApp.fetch(url, options);
}

function sendSlackMessageMain() {
  var message = "投稿したいメッセージ";
  sendSlackMessage(message, "投稿したいCH名");
}
```
ここで注目したいのは、tokenです。
これは、slack appのbot tokenを指定します。
ただし、gsファイルの中に直接ぶっこむのはよくないので、propertyとして値を設定し、それを流用します。

スクリプトプロパティという値を追加できるので、そこにslack App の bot tokenを入れます。

![スクリーンショット 2022-08-03 15.18.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1026740/5a673bfe-c2f4-c147-8795-d4acbe254544.png)
すると、
```actionscript
var bot_token = PropertiesService.getScriptProperties().getProperty("slackbot_token");
```
の形で使えるようになります。便利ですね。
sendSlackMessageMain()を実行するときの関数として指定すればメッセージ投稿ができるようになりまs
N: Repository ...changed its 'Version' value from '11.3' to '11.4'というエラーがラズパイで出た



参考

http://sheepdogjam.cocolog-nifty.com/blog/2020/10/post-8e0689.html

# 結論

何もせずに再度update実行すると表示され無くなるので、無視してもいいのかも
気になる人は以下を実行してもよさそう
```
apt --allow-releaseinfo-change update
```

# 何が起きたのか

![スクリーンショット 2022-08-03 14.34.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363815/72bf67be-db0e-7a4b-11c7-425baf40257f.png)

# 環境

http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_lite_arm64/images/raspios_lite_arm64-2022-04-07/
```
イメージ
2022-04-04-raspios-bullseye-arm64-lite.img.xz	2022-04-05 00:47	270M

デバイス
RaspberryPi4B-4GB

発生確認日時
2022-08-02	 
```
戻り値がどこに値をreturnするのかようやくわかったので忘れないうちに書いとく

Pythonのreturnを永遠に勘違いしてましたがようやく大体理解できたので書いてきます。

戻り値とは
PythonのDocumentationでは
「return 文では、関数から一つ値を返します。 return の引数となる式がない場合、 None が返ります。関数が終了したときにも None が返ります。」
とありますが、僕が一生悩んでたのは
どこに返すん？
ってところですね。
いろんなチュートリアルで呼び出し元に戻す、とかいってありますが、戻してどうすんねん？ってなってました。

そこがようやく解決したのでここに書いときます。

解決

一般的に関数は

def func(引数)
    処理・・・
    return(引数)
print(func)

見たいな感じかと思いますが、どうやら呼び出し元はこの
print(func())の所みたいですｗ。

はい、盛大な勘違いを起こしてました。

これ、コードの流れ的にdef funcが先に来てそうってのもあって
「処理内容をまた関数の頭に持ってきてどうすんねん！」
って思ってたのですが
実際の流れは

パソコンが関数を認識
↓
関数呼び出し(print(func()))
↓
パソコンが関数発動
↓
処理完了
↓
処理内容をprint(func())に戻す

の流れです。
返すってのはそういう事みたいです。

以上です。
windows 10で英字キーボードをmacみたいに使う

## はじめに
**WindowsでもMacと同じように英字キーボード使いたい！**
というのも, 今のメインPC買うときこだわってmacをUS配列にしてるんですよね.
それで, 研究で使うWindows機のほうでもキー配列で悩みたくないなあと思ってAnkerの2000円くらいのUS配列キーボード使って作業しようと思った次第です.
それで調べはしたものの割と記事がなかったので備忘録もかねて書いておこうと思います.
## 英字キーボードの配列にする
まず, 現在使用しているキーボードの配列を日本語配列のものから英字配列のものに変更します.
windowsの設定を開き, 時刻と言語をクリック.
![WindowsUS設定1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1748646/0695a369-72f1-1d4f-0806-54ed5a7e8097.png)
サイドバーの中から言語を選択して優先する言語の日本語からオプションをクリック
![WindowsUS設定3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1748646/3a26e51f-2767-eebc-fcd4-cf08765ddaea.png)
レイアウトを変更する, をクリックして英字キーボードのレイアウトを選択.
![WindowsUS設定4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1748646/782f72b0-8b3c-ff39-8e0f-c58058f73f4f.png)
あとは言われるがままに再起動なりするだけです. 簡単ですね.
## 再起動後
**日本語入力できないんだが？**
今までcaps lockを使って日本語入力と英字入力を分けていたわけですがそれができなくなりました.
調べてみたところ, [Alt]+[`]で入力の切り替えができるよう.
しかしながら私が求めるのはmacで使っているキーボードとの互換性. 普段は[Command]+Spaceかcaps lockを使って入力の切り替えをしていたのでそれに対応させたい.
~~どうもIMEをいじるとできる様子.~~
無理でした. Windows + spaceはすでにIMEの切り替えにつかわれており, ショートカットに設定するのは無理なよう. 悲しいですね.
caps lockでも無理なのかは検証していかないといけないところですね. 

## 後日談
PowerToysが最強だった.
microsoft storeでpowertoysと検索するとmicrosoft純正のいろいろできるアプリを入手可能. 絶対これでやったほうがいい.
JS配列にあれば削除なければ追加

### コード
[live demo](https://codepen.io/kensoz/pen/BawgZGr)
```typescript
const arr = [1,2,3,4]
const x = 5

// indexOf()による判断
const index = arr.indexOf(x);
// index < 0: なければ，追加
// index >= 0: ある，削除
index < 0 ? arr.push(x) : arr.splice(index, 1)

console.log(arr)
// [1,2,3,4,5]
```
Notion：シンプルテーブル⇄データベース変換

Notiionでシンプルテーブルとデータベース変換で、少し迷ったのでここにまとめます。

# ブロックハンドル`⋮⋮`に変換コマンドがある
もともと右上メニュー`•••`にあったコマンドの位置が、ブロックハンドル`⋮⋮`をクリックして表示されるコンテクストメニューに表示されるようになっている。 

* データベースからシンプルテーブルに変換
<img width="400" alt="シンプルテーブルに変換" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2713376/71706ac6-6ec4-7abf-7cd3-7d36e53a9006.png">

* シンプルテーブルからデータベースに変換
<img width="400" alt="データベースに変換" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2713376/eeb7187d-467b-d7ce-1aa8-d3ce6ff661ed.png">

# データベースからシンプルテーブルに変換できない場合がある。 
やっと見つけたブロックハンドル`⋮⋮`からの変換ですが、データベースの状態によっては表示されません。 

* ビューのレイアウトがテーブル以外のデータベース
* 1つ以上の複数のビューを持つデータベース
* プロパティの種類でアドバンスドを指定しているプロバティが1つ以上あるデータベース

なので、シンプルテーブルへ変換したい場合は、


* 複数のビューがある場合は、テーブルレイアウトのビューだけにして他を削除
* プロパティでアドバンストを使用しているプロパティは削除

上記のような作業をして、レイアウトがテーブルのビュー1つだけを持ち、プロパティでアドバンストを使用していないデータベースにする必要があります。
ファイルサイズ変更のLinuxコマンド


境界値テストでよくファイルのサイズを変えたいなと思うので備忘録として
## convert (画像の拡大、縮小)
画像動画の大きさを変更する
```shell
convert -geometry 600x600 元のファイル名.png 変更後のファイル名.png

convert -geometry "60%" 元のファイル名.png 変更後のファイル名.png
```

pngからjpgに変更などもできる。変更後のファイルの拡張子を好きなものにすればよい

縦横比を維持してくれるが強制的に変えたいときは ! を付ければよい
```
convert -geometry 600x400! 元のファイル名.png 変更後のファイル名.png
```


## mogrify (上書きでリサイズ、拡大縮小)
1280x1080に変更したい場合
```
mogrify -resize 1280x1080 変えたいファイル名.png
```

## 動画のリサイズ　拡大縮小
```
ffmpeg -i 変更元の動画名.mp4 -s 1280x720 変更後の動画名.mp4
```
## truncate (ファイルサイズの変更　データ量)

```shell
truncate -s サイズ ファイル名
```
サイズは1024の累乗で指定する場合 K, M, G, T, P, E, Z, Y  
1000の累乗はKB, MBなどと指定

5M 5MBなどと指定する
Pythonのクラス学習。オブジェクト指向と継承

## 初めに。
どうもpython歴4か月の者です。少し前に`クラス`についての勉強しました。
今度はオブジェクト指向についてまとめて行こうと思います。
中々苦手意識とは消えないもので…､さらに概念的な要素含まれており説明できるか不安ですが、頑張ります。


-  恐縮ですが今回は[前回記事](https://qiita.com/The_Boys/items/1ceef44d7b2c5ce5dacb)のコードや考え方を踏襲致します。

- 環境:windows

## 学習

### 参照コード　参考は[こちら](https://qiita.com/The_Boys/items/1ceef44d7b2c5ce5dacb)

```python
class Student:                                #クラスの定義

    def __init__(self,name,math,english):     #コンストラクタ(初期化)メソッド。
        self.name = name                      #アトリビュートの設定
        self.math = math                      #アトリビュートの設定
        self.english = english                #アトリビュートの設定
    
    def avg(self):                            #avgメソッド
        return (self.name+"さんの平均点は"+  str((self.math + self.english)/2))

a001 = Student("sato",50,70)    #インスタンスとアトリビュート(変数)の代入。クラス呼出(実行)
a002 = Student("tanaka",40,90)
a003 = Student("yamakawa",50,60)
```
## 学習
### オブジェクト指向とは？
`オブジェクトを作成/利用してコードを書くこと`
- オブジェクト：実体。インスタンス。
- 利点：変更に強い。個々に修正するのではなく大元の関数/クラスを変更すれば各々の変数も変更できる。

なんとなく`クラス/関数`に似ているな…とぼんやり感じて頂ければ幸いです。

#### ステップ①
まずは[この記事](https://blog.codecamp.jp/object-orientation-explanation)の｢オブジェクト指向の用語を解説｣まで読んでください。
その後に参照コード(できれば記事も)と下記画像を結び付けてイメージを沸かしてください。今回やりたかったのはこれでです。

![2022-08-03_14h55_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2719278/4e485bcf-54a4-56e3-0aac-83cb089b816f.png)

この相乗効果によりクラスとオブジェクト理解が深まれば幸いです。

### 継承について。

ついでに継承も学習しましょう。同様のコードで一括で理解できればお得感ありますので。

#### 用語確認
あるクラスで使用した部分を別のクラスに持ち越して使用する事。名前の通り継承。`Aクラスで使用したものをBクラスで継承（使用） `する事。
- 親クラス：継承される側。上記の例でいう`Aクラス` 
- 子クラス：継承する側。  上記の例でいう`Bクラス`

実際に具体例を確認してみましょう。上の<font color="red">**参照コード**</font>を親クラスとして、下の<font color="blue">クラス Keisho</font>を子クラスとします。

```python
class Keisyo(Student):                                #クラスの定義
    def add_sum(self):                                #add_sumメソッド
        return (self.name+"さんの合計点は"+  str((self.math + self.english)))
```
- 引数に注目してください。`子クラス(親クラス)`　という図式です。
- __init__が省略されています。⇒便利!!この部分が継承されているという訳です。

それでは実際に継承されたクラス<font color="red">Keisho</font>を使用してみましょう。

```python
class Keisyo(Student):                                #クラスの定義
    def add_sum(self):                                #add_sumメソッド
        return (self.name+"さんの合計点は"+  str((self.math + self.english)))

a001 = Keisyo("sato",50,70)     #インスタンス作成とアトリビュート(変数)の代入。クラス呼出(実行)
a002 = Keisyo("tanaka",40,90)   #インスタンス作成とアトリビュート(変数)の代入。クラス呼出(実行)
a003 = Keisyo("yamakawa",50,60) #インスタンス作成とアトリビュート(変数)の代入。クラス呼出(実行)

print(f"{a001.add_sum()}\n{a002.add_sum()}\n{a003.add_sum()}")
print()
```
継承してるとは言えど、新たにインスタンス作成はしなければなりません。

出力結果
```ts
satoさんの合計点は120
tanakaさんの合計点は130
yamakawaさんの合計点は110
```


## 終わりに
継承の部分が少し自分でも理解が足りず説明しきれていない感触でした。
説明/補足追加予定ですので、より分かりやすく説明できるよう善処致します。


### 参照

https://blog.codecamp.jp/object-orientation-explanation

https://qiita.com/hyodo1026/items/085e0b5212520eca7d77
ライブラリ・バンドラ・Web Componentsを使わずコンポーネント指向開発（Singleton Components v2）

（検討中につき随時更新していこうかと）
## 経緯
コンポーネント指向ってだけなら、もしかして
アレ（React）もコレ（Web Components）も必要ないんじゃ、、、と。

static render() 版の末尾で検討を続けているもので
https://qiita.com/_tt/items/18f682304e66a6cb8521
現状までを整理し実装してみました。

## サンプル実装
React チュートリアルを Singleton Components v2 で実装してみた
https://codesandbox.io/s/youthful-fire-kelbs7?file=/index.html

以下はこのサンプルを元にしています

## 方法
##### 1. コンポーネント単位でファイル分割するため、エントリポイントを type="module" とする
```index.html
<script type="module" src="./src/index.js"></script>
```
##### 2. リスナ関数を持つコンポーネントは、グローバルスコープでコンポーネントを呼び出せるようにする
エントリポイントの一番最初で ComponentManager を import する。
```src/index.js
import "./components/ComponentManager.js";
//...
```
```src/components/ComponentManager.js
window.components = new Map();
```

##### 3. コンポーネントはシングルトンで実装する
※複数必要な場合は getInstance(id) などとする（例：src/components/Square.js）
```src/components/Game.js
class Game {
  static getInstance() {
    return instance;
  }
  //...
}
const instance = new Game();
export const { getInstance } = Game;
```

##### 4. 親コンポーネントの render() のみ、あらかじめレンダリング先の HTMLElement を受け取り render() でそこに埋め込む
※ render() 再実行**可**
```src/index.js
//...
(() => {
  Game.getInstance().init(document.querySelector("#root")).render();
})();
```
```src/components/Game.js
class Game {
  //...
  render() {
    this._parent.innerHTML = /* html */ `
      <div class="status">
        <!-- ... -->
      </div>
    `;
  }

  constructor() {
    this._parent = null;
    //...
  }
  init(parent) {
    this._parent = parent;
    //...
  }
  //...
}
```

##### 5. 子孫コンポーネントの render() はHTML文字列を return し、上位コンポーネントの render() 内で埋め込んでもらう。
子孫コンポーネントの render() は再実行**不可**、再実行したい場合は最上位コンポーネントの render() をコールする。
```src/components/Board.js
class Board {
  //...
  render() {
    return /* html */ `
      <div class="board-row">
        <!-- ... -->
      </div>
    `;
  }
  handleClick() {
    //...
    // this.render() ←NG　↓OK
    Game.getInstance().render();
  }
  //...
}
```

##### 6. イベントハンドラはHTML属性を使い、addEventListener を使わない
リスナ受け渡しのため、上記２で準備した window.components を使う
```src/components/Square.js
class Square {
  //...
  render() {
    return /* html */ `
      <button
        class="square"
        onclick="window.components.get('${Square.name}').getInstance().handleClick()"
      >
        ${this._player}
      </button>
    `;
  }
  //...
  init() {
    window.components.set(Square.name, Square);
  }

  handleClick() {
    //...
  }
  //...
}
```

##### 7. コンポーネントの初期化は init() で行い、子コンポーネントの init() は親コンポーネントの init() でコールする
```src/components/Game.js
class Game {
  //...
  init(parent) {
    //...
    Board.getInstance().init();
  }
  //...
}
```

## 課題
1. 宣言的UIと言うには```${Component.getInstance().render()}```ではなく```<Component />```でないといけないのかな？（記事から宣言的UIを削除）
2. グローバルスコープに変数を用意するのに抵抗感がある（window.components）
3. HTMLのリスナ指定が冗長（window.components を window.listeners にすれば少し短くなるが）
4. 子孫コンポーネントの再レンダリングでも親コンポーネントの render() を使う点、負荷や表示に問題が出そうな気も。もう少し規模の大きい実装を試してみると問題点が分かるかも

## 補足
トランスパイルプロセスを追加すれば Typescript もいけるかと
scpが遅い？ならrsyncや

# 結論
ファイル転送はrsyncで行うと爆速
- 結論コマンド
```:terminal
rsync -avP localfile remote:dir/
```


# 背景
今まではイントラ内でサーバーにファイル転送をしようとした際にscpを使っていました。転送速度がかなり遅く(120.0KB/sほど)1GBを超えるようなファイルはとてもじゃないけど送れませんでした。

- 以前のコマンド
```:terminal
scp localfile remote:dir/
```

# 解説
- -P 転送の進行状況を表示する + 転送を中断したファイルを保持する
- -a アーカイブモード（「-rlptgoD -no-H -no-A -no-X」相当）
- -v 動作内容を表示する
詳しくはmanもしくはhttps://atmarkit.itmedia.co.jp/ait/articles/1702/02/news031.html
Pythonのselfについてメモ



```python:hello.py
class HelloForEver:
    def __init__(self, num):
        #構造体(クラス)の中のnにnという変数を定義している。(プロパティ)
        #nがメンバ（プロパティ）
        self.num = num
    def readline(self):
        if self.num > 0:
            return (self.num*8)
#インスタンスを生成
f = HelloForEver(3)
print(f.readline())
```

"self"にはコンストラクタで生成したインスタンスを渡している。
ex.
`f = HelloForEver(3)`
とすると、
`self = f`
となり、
class内の
`self.num`は`f.num`になる。
これによって、インスタンスごとにプロパティ（Cでいうメンバを生成している）

参考文献：
 https://utokyo-ipp.github.io/
[Zabbix]SNMPトラップを受けた際の障害＆復旧設定例

ZabbixにおいてSNMPトラップに関してZabbixサーバで受信した際に、条件式の設定で障害として発生させることができる。

「障害の発生だけでなく、復旧の情報に関するトラップが飛んできたときになんとか復旧させれるような設定ができないか」
と悩んだ末に、下記の式をあみだしました。


```SNMPトラップ　障害→復旧設定
障害: {snmptrap[正規表現].regexp(正規表現)}=1 and {snmptrap[正規表現].nodata(1s)}=0

復旧: {snmptrap[正規表現].count(1s,正規表現)}>0
```

例えば
障害：電源が壊れました
復旧：電源が復旧しました

というような情報を含むトラップがあったとしたら

```
障害: {snmptrap[電源が壊れました].regexp(電源が壊れました)}=1 and {snmptrap[電源が壊れました].nodata(1s)}=0

復旧: {snmptrap[電源が復旧しました].count(1s,電源が復旧しました)}>0
```

このように設定します。

使われる機会は少ない気がしますが、備忘録として残しておきます。
WSL上のプロジェクトをVSCodeで開くショートカットアイコンの作り方

# はじめに
WSL上のプロジェクトをVSCodeで開くのに、いったんVSCode起動して「最近使用した項目を開く」で開いたりしてませんか？
そんなあなたに少しだけ時短する技をお伝えします。
# 作り方
- Windowsメニューのアプリ一覧から、デスクトップにVSCodeのアイコンをドラッグアンドドロップしてショートカットをコピる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68254/550b1a8e-1d0e-160a-a8d3-b1447ffaae7b.png)

- プロパティを開き、「リンク先」を下記のように変更する。
```text
"C:\****\Code.exe" 
  ↓
"C:\****\Code.exe" --remote wsl+Ubuntu /開きたいWSLのパス
 ※LinuxディストリビューションがUbuntuの場合です。

例）
"C:\****\Code.exe" --remote wsl+Ubuntu /home/user/projects/example-app
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68254/edef1140-921a-938b-26b9-2911798fe5d3.png)

- ショットカットアイコンの名前をプロジェクト名にでも変更しておく

# 起動
- ショートカットアイコンをダブルクリック
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68254/a7a07891-5729-6434-f856-f4c4bd6ad469.png)

# おわりに
最近IntelliJを使うことができない過酷な職場環境なため、すっかりVSCodeばかり使うようになってしまいました。
[備忘録] リスト, イテラブル, イテレーター ああっ訳がわからん！

# なにがわからん

```Python
l = [1, 2, 3, 4]
next(l) # TypeError: 'list' object is not an iterator
```

リストってイテレーター（イテラブル）じゃないん？

# イテレーターとイテラブル

**違います。** リストはイテラブルなオブジェクトだけどイテレーターじゃありません。

> 『イテレータ』は『イテラブルなオブジェクト』の中の1つでイテレーションした状態を記憶しておくことができるオブジェクト（イテレータ型のオブジェクト）です。[^1]

[^1]:[Pythonのイテラブル(iterable)とイテレータ(iterator)](https://dot-blog.jp/news/python-iterable-iterator/#:~:text=『イテレータ』は『イテラブルなオブジェクト』の中の1つでイテレーションした状態を記憶しておくことができるオブジェクト（イテレータ型のオブジェクト）です。)

### こう書けばOK

```Python
l = [1, 2, 3, 4]
next(iter(l))
```

### もしくはこう

```Python
l = [1, 2, 3, 4]
next(o for o in l)
```

# えっ、`[a for a in iterable]` って中身だけで成り立つの！？

はい。

```Python
str(type(d for d in arr)) # <class 'generator'>
```

---

すっきり！
最小公倍数 、 最大公約数を求める(Python)

今回は[hmath](https://caleb7023.hmath.pro/)で使用されているgcd(list), lcm(list)の計算方法をご紹介します。
**gcdは最小公倍数**を表し、
**lcmは最大公約数**を表します。
## プログラム
[hmath](https://caleb7023.hmath.pro/)内では次のプログラムで計算しています。
```ruby:gcd_lcm.py
def gcd(*args):
    if len(args) <= 1:
        return args[0]
    n, k, *others = args
    if k > n:
        n, k = k, n
    while k != 0:
        k, n = n % k, k
    return gcd(n, *others)

def lcm(*args):
    args_max = max(args)
    n = 1
    while True:
        for k in args:
            if args_max * n % k != 0:
                n += 1
                break
        else:
            return args_max * n
```
最後まで見ていだきありがとうございました。
ぜひ活用してみてください。
POSTMANで単純なAPIの繰り返し実行をする

# やりたいこと
とあるAPIのデータ作成で大量データが必要になったので自動化したかったので、それをPOSTMANで作れないかと模索中…

つまり、下記みたいなAPIがあり
POST /users/{{userId}}
userIdを
0001
0002
0003
…
000N
みたいな感じでN回叩きたいケースがあった。

実際はこんな感じで等間隔で実行されるイメージ
POST /users/0001
POST /users/0002
POST /users/0003
…
POST /users/000N

# POSTMANのRunnerを使う
## Collectionに登録
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601431/78df9744-e0e9-3f88-8951-ccc2f270a805.png)
### URL
```console
http://localhost:3000/users/{{userId}}
```
Pre-request Scriptに下記を登録

### 初回の1回目
```javascript
postman.setEnvironmentVariable("counter", 1);
console.log(ret)
pm.collectionVariables.set("userId", ret);
```
これはPOSTMANの環境変数に初期値を設定するために実行、ここでは通常通り、Sendを実行し、環境変数をセットする

### 初回の2回目以降
```javascript
postman.setEnvironmentVariable("counter", num + 1); // ここで環境変数をインクリメントする
var num = Number(environment.counter);
var ret = ( '0000' + num ).slice( -4 );
pm.collectionVariables.set("userId", ret);
```

## Runnerで実行
Iterations や Delayを設定し、Start Runを実行。
とりあえずこれで繰り返し実行は簡単にできる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601431/d5249f94-c144-d2f6-c286-809b5518b784.png)
Git壊した

git でpushしようとしたら、commitもpullもできないのでワーキングツリーをきれいにできなかった。
branchもmainとmasterがごちゃごちゃになっていて、よくわからないフォルダとつながっていた

解決法
フォルダごと消してclone、gitにあげられていないファイルはコピーして上書き
conflicting declaration ‘typedef struct LZ4_stream_t LZ4_stream_t’

# LZ4_stream_t が二重定義される問題

自分メモ用。
Ubuntu18.04LTS + ROS melodic + PCL 1.8 環境で既知のバグ。

ある日、自分の研究コードをcatkin buildをするとエラーが発生。

```
/usr/include/lz4.h:196:57: error: conflicting declaration ‘typedef struct LZ4_stream_t LZ4_stream_t’
typedef struct { long long table[LZ4_STREAMSIZE_U64]; } LZ4_stream_t;

In file included from /usr/include/flann/util/serialization.h:9:0,
                 from /usr/include/flann/util/matrix.h:35,
                 from /usr/include/flann/flann.hpp:41,
                 from /usr/include/pcl-1.8/pcl/kdtree/flann.h:50,
                 from /usr/include/pcl-1.8/pcl/kdtree/kdtree_flann.h:45,
                 from /usr/include/pcl-1.8/pcl/search/kdtree.h:44,
                 from /usr/include/pcl-1.8/pcl/search/pcl_search.h:44,
                 from /usr/include/pcl-1.8/pcl/segmentation/conditional_euclidean_clustering.h:44,

/usr/include/flann/ext/lz4.h:196:57: note: previous declaration as ‘typedef struct LZ4_stream_t LZ4_stream_t’
 typedef struct { long long table[LZ4_STREAMSIZE_U64]; } LZ4_stream_t;

/usr/include/lz4.h:249:72: error: conflicting declaration ‘typedef struct LZ4_streamDecode_t LZ4_streamDecode_t’
 typedef struct { unsigned long long table[LZ4_STREAMDECODESIZE_U64]; } LZ4_streamDecode_t;

/usr/include/flann/ext/lz4.h:249:72: note: previous declaration as ‘typedef struct LZ4_streamDecode_t LZ4_streamDecode_t’
 typedef struct { unsigned long long table[LZ4_STREAMDECODESIZE_U64]; } LZ4_streamDecode_t;


```

# 解決法

```
$ sudo mv /usr/include/flann/ext/lz4.h /usr/include/flann/ext/lz4.h.bak
$ sudo mv /usr/include/flann/ext/lz4hc.h /usr/include/flann/ext/lz4hc.h.bak

$ sudo ln -s /usr/include/lz4.h /usr/include/flann/ext/lz4.h
$ sudo ln -s /usr/include/lz4hc.h /usr/include/flann/ext/lz4hc.h
```

何も考えずこの4行をターミナルにコピペするだけで全てが解決する。
元のファイルをバックアップに退避して、同名のリンカーを配置する。
この4行に圧縮した解決策、基本的だけど簡潔に投稿されてて、投稿主は本当に天才だと思う。

偉大なる参照記事:
https://github.com/ethz-asl/lidar_align/issues/16
AWS Synthetics Canaryで実際に動くlambdaのArnを調べる


コンソールからだと見つけられないのでAWS CLIから`jq`で調べる。
フィルターは(それほど長いわけではないが) 別ファイルにして実行

```bash
$ aws synthetics describe-canaries | jq -f canary-lambda.txt`
[
  {
    "Name": "example-canary",
    "Function": "arn:aws:lambda:ap-northeast-1:xxxx:function:example-canary-xxxxx:1",
    "Role": "arn:aws:iam::xxxx:role/example-canary-ExecutionRole",
    "Code": {
      "SourceLocationArn": "arn:aws:lambda:ap-northeast-1:xxxx:layer:example-canary-xxxx:1",
      "Handler": "index.handler"
    },
    "RuntimeVersion": "syn-nodejs-puppeteer-3.4"
  }
]
```

```canary-lambda.txt
[
  .Canaries[] 
  |
  { 
    Name: .Name,
    RuntimeVersion: .RuntimeVersion,
    Function: .EngineArn,
    Role: .ExecutionRoleArn,
    Code: .Code
  }
]
```
【どっちが早い？】標準UPSERT機能 vs DataLoaderのアップデートローダー機能【DataSpiderのDr.Sumアダプタ】

# やりたいこと
DataSpiderというETLツールにDr.Sumアダプタ機能を追加することで、Dr.Sumへの書込みが可能になります。
Dr.Sumアダプタ機能には標準の書込み機能があり、「キーと一致する行は更新」する設定ができます。
一方、Dr.Sumへ書き込む際にDataLoaderというオプション機能を使うと、同様に「キーと一致する行は更新」することができます。
今回はこの2つの「キーと一致する行は更新」して書き込む方法（一般的にいうとUPSERT）の違いを調査してみようと思います。

![アイキャッチ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2254022/0d9b2307-0189-f152-93d6-d9a69faa8867.png)

# 結論
結論からいうと、2つの違いは以下です。
・書き込み（更新/挿入）アイコンの「キーの値と一致する行は更新」
書き込み先のテーブルにUPDATEを全行に対して行い、無ければINSERTしています。そのため、件数が多いとその分処理が遅くなります。
・書き込み（DataLoader）アイコン
インポート処理がSQLのレイヤではなくDr.Sum内部で完結しており、全件一括で処理しているため高速なインポートがを実現しています。

では、Dr.Sumのログを確認しながら各処理の中身を見ていきます。

# UPSERTって？
データベース用語として良く使われる用語で、UPDATEとINSERTを組み合わせた造語らしいです。
テーブルへレコードの書き込みを行う際、キー項目を見て「キー項目があれば更新（UPDATE）、無ければ挿入（INSERT）」する操作を指します。

![upsert.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2254022/91b87bc8-5e23-5145-d25c-390eb87b2b56.png)

# 調査！
サンプルデータとして、次の4パターンで実験してみます。UPDATEする行数も固定しておきます。
・3列のテーブルに対し10件UPSERT（UPDATE：3件、INSERT：5件、変更なし：2件）
・3列のテーブルに対し50000件UPSERT（UPDATE：10000件、INSERT：10000件、変更なし：30000件）
・10列のテーブルに対し10件UPSERT（UPDATE：3件、INSERT：5件、変更なし：2件）
・10列のテーブルに対し50000件UPSERT（UPDATE：10000件、INSERT：10000件、変更なし：30000件）

### ロジック
・書き込み（更新/挿入）アイコンの「キーの値と一致する行は更新」で書き込み

![標準UPSERT.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2254022/161dfcb4-d39e-a603-4004-57f42415d780.png)

・DataLoaderで書き込み

![DataLoader.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2254022/75f56725-7ce7-150a-7cdc-abe4bc216577.png)

### 実験方法
上記ロジックで、それぞれ4パターンの処理を実行し処理速度を調べてみます。
DataSpiderの実行履歴から、書き込みアイコンの処理にかかった時間を処理時間とします。

![実験方法.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2254022/3d24d76d-b0f8-d499-fd29-3bf24abfcae9.png)


# 結果
結果は表のとおりです。

![result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2254022/ecf2eb3f-0b11-4a11-8e1f-7bbc3262b8b1.png)

結果から50000行UPSERTとなると、標準のUPSERT機能だとかなり遅くなっていることがわかりますね。
これはなぜでしょうか。Dr.Sumのログを見つつどんな処理が流れているのか見てみます。

### 標準UPSERTはなぜ遅い？

10列10行のデータを標準UPSERTを行ったときのログがこちらです。

![2022-08-01_00h03_18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2254022/3bbfa70d-63ab-3fce-a2ee-fd4ee64386a3.png)

insertデータを除くと、書き換えたデータは5件中3件だけにも関わらず、update文は5件実行されています。
データが書き換わっているか否かにかかわらずテーブルの件数分SQLが実行されているため時間がかかってしまうようです。

### DataLoaderはなぜ早い？
同様にSQLを見てみます。

![SQL.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2254022/00bb8dfa-0e6b-71bf-8dbd-0a39d6cb4098.png)


このログを見ると、INSERTやUPDATEといったSQLは実行されていないようです。「IMPORT」ログも見てみます。

![updateload_import.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2254022/5f4d1b41-01b3-3e74-f28a-05d772c6ca01.png)

IMPORTログを見てみると、bulk insertで一括インサート処理が行われているようです。
SQLのレイヤではなく、インポート処理が内部で完結しているため高速な処理ができているようですね。

# まとめ
今回は、DataSpiderのDr.SumアダプタのUPSERT機能について調査しました。
標準のUPSERT機能とDataLoaderを使ったUPSERTで処理速度を比較し、ログを頼りにどんな処理を行っているのか調査しました。
結果として、標準のUPSERT処理では全行に対してUPDATE・無ければINSERTを行っているのに対し、DataLoaderはそもそもSQLベースでの処理ではなくDr.Sum内部で一括処理を行っているため高速な処理を実現しているようです！すごい！
Power Apps で作ったアプリを Teams のタブにピン留めする。 

時間が空いてしまいましたが、社内の組織変更などが落ち着きましたのでQiita再開します。
役職名もプロフィールの通りになったのですが、引き続き皆様のTeamsとPower Platform 利活用支援をさせていただきます。
それとセキュリティと ~~電気工事~~ も…。

# なんで Power Apps のアプリを Teams から起動するの？

Microsoft Teams は Skype for Business / Lync の流れをくんでいる製品のため、チャットや会議のアプリと思われがちですが（これは間違っていない）むしろチームコラボレーションを強力に推し進めるための「プラットフォーム」としての側面が大きいです。
コラボレーションのために作ったアプリ（＝部課やプロジェクト単位で使うようなアプリ）を作ったら、Teamsのチーム／チャネルにあるタブにピン留めしておけばより利用しやすいというメリットがあります。
Dataverse for Teamsという Teams から使うことを想定した環境で作成されたアプリでなくても、普通にPower Appsホーム画面から作成したアプリもTeamsのタブから利用することができます。

# 前提条件（管理者向け）

・管理者がTeamsからPower Appsを利用することを認めていること
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2095776/997d1a11-7704-e374-919a-9841636eaa2b.png)

・組織全体の設定でカスタムアプリのアップロードを許可していること
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2095776/81f316b6-a525-f745-fc3c-6215cfa12951.png)

ちなみにセットアップポリシーのカスタムアプリの部分はオフでも大丈夫です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2095776/f61f87ee-6e2c-5135-7b88-6ebef27992c3.png)

# アプリをTeamsに追加する（市民開発者向け）

①まず、アプリを作って、公開します。共有権限を必要な人に付与します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2095776/00b5171d-06c4-4abd-823e-dd08efb92515.png)


②以下のいずれかの個所からTeamsへ追加します。

その１…アプリの選択画面の上部
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2095776/2338265f-6c33-8765-fa85-12350f816027.png)
その２…アプリを選択して三点リーダから選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2095776/44e2b645-21f5-2efd-cbd7-ba054b0860ca.png)
その３…アプリを起動して右上のアイコンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2095776/d474239f-30cf-9301-b9bf-3c1b03e32bf0.png)

③Teamsに追加をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2095776/5e696a32-7978-fa6e-d8b1-67b98ac75916.png)
※ちなみにアプリをダウンロードをクリックすると「マニフェスト」を含むZIPファイルがダウンロードできます。これをアップロードすることでもTeams展開が可能ですが、ここではダイレクトにTeamsに追加してみます。

④追加の右のｖをクリックして、「チームに追加」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2095776/fa0612af-000b-565d-33b2-1bb621c47f5c.png)

⑤ピン留めしたいチームのチャネルを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2095776/4d002bb4-5ab6-c995-f81b-4e0b0403b6f0.png)

⑥保存をクリックすれば完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2095776/75c08de3-c610-97bd-52eb-d8384d186b85.png)

快適なPower Apps on the Teams を満喫ください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2095776/20fdad51-cec8-d7c6-40af-77ff1e7420ba.png)
"WSLでMagentaを使ったピアノ耳コピの自動化"をDockerfileに落とし込んだ

## 元ネタ

https://qiita.com/burugaria7/items/4005724c5d1b5228327e

この内容をDockerfileに落とし込んで、簡単に使えるようにしてみました。

- 参照

    https://magenta.tensorflow.org/onsets-frames

## ソースコード

github上に置いてあります。

https://github.com/hisashisatake/onsets-frames

## 使い方

Dockerfileを配置したディレクトリに移動して、以下のコマンドでビルドします。

    $ docker build -t magenta ./


ビルドが終わったら、docker runで実行できます。

    $ docker run -v [任意のフルパス]:/opt/of magenta [任意の.wavファイル名]

.wavファイルをホストとコンテナで共有するために、VOLUMEを使います。VOLUMEにバインドされるコンテナ側のディレクトリは"/opt/of"固定です。

任意のフルパスはVOLUMEの実体となり、その中に.wavファイルを配置して解析させます。任意の.wavファイル名を省略した場合、デフォルトでmagenta.wavを参照します。

- 例) 任意のフルパスを~/docker/magenta/ofにする
    
    あらかじめ、~/docker/magenta/of/wavを作成しておき、magenta.wavを配置して、以下のコマンドを実行します。

        $ docker run -v ~/docker/magenta/of:/opt/of magenta

    必要に応じて、/opt/of/train上にモデルデータがダウンロードされ、解析を開始、~/docker/magenta/wav上にmagenta.wav.midiが生成されます。

- 例) 任意の.wavファイル名を指定する

    任意のフルパスは~/docker/magenta/ofとして、任意の.wavファイル名を指定します。あらかじめ、~/docker/magenta/of/wav上にexample.wavファイルを配置します。

          $ docker run -v ~/docker/magenta/wav:/opt/wav magenta example.wav

    解析が開始され、~/docker/magenta/wav上にexample.wav.midiが生成されます。

## イメージ

Docker Hubにアップしてあります。このイメージを使えば、ビルドは必要ありません。さらに導入が簡単になります。

https://hub.docker.com/repository/docker/hisashisatake/onsets-frames

## イメージの使い方

基本的には同じです。データの受け渡し用にVOLUMEを設定し、任意のパスに関連付けます。

以下の例では~docker/magenta/ofがVOLUMEの実体になるので、~docker/magenta/of/wavを作り、その中にmagent.wavを配置します。

    $ docker run -v ~/docker/magenta/of:/opt/of hisashisatake/onsets-frames:python3.7-bullseye-slim
初心者　MySQL8に挑戦する 15

# 神様、仏様、エラー様。

　今日は、写経のかわりに、自分のアプリの、firestoreをMySQLに入れ替える、というのをやってみた。

　やった、エラーが出たぞ。これで何かわかるか。

　と、もうはやエラー頼み。でもよく見ると、やだ、ただの、MySQLは寝ています、だ。
　
- $ mysql restart

 お、またエラーだ、・・・違うじゃん、ただの打ち間違い。

- $ mysql.server restart

　はい、繋がった。けど、データを拾えない。

![スクリーンショット 2022-08-03 13.11.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1646810/21041b72-4fd2-e486-7cf2-602135ee1000.png)

　もし拾ったデータが空ならぐるぐるする、が、ぐるぐる回っている。つまり、繋がっている。そして「拾ってみよう」とはしている。でも、いっぱい入っているデータを一つも拾えない。

　エラーはない。警告メッセージもない。

## どこかに北極星は見えないのか？

https://qiita.com/dongri727/items/81409786b29a3ec14813

https://qiita.com/dongri727/items/1e624c3595f4a0dcc79b
【Python】Try文でエラー回避を無限ループ

＜初めに＞
pyautoguiの画像検索を使用している際に、
座標取得できるまで、無限ループさせたかったので以下のコードにたどり着いた

＜コード＞
↓このコードコピペで使用できます
```
    #座標検索
　　#(img=検索画像, target_range=画像検索範囲(left,top,width,height)※タプル型です)
    def search(img, target_range):
        n = 0
        #座標が取得出来るまで無限ループ
        while True:
            try:
                if n == 0:
                    p = pyautogui.locateOnScreen(img, grayscale=True, confidence=.6, region=target_range)
                    x, y = pyautogui.center(p)
                else:
                    print(f'座標取得リトライします:{n}回目')
                    p = pyautogui.locateOnScreen(img, grayscale=True, confidence=.6, region=target_range)
                    x, y = pyautogui.center(p)
            except:
                print('except通った!!')
                time.sleep(2)
                n+=1
            else:
                break
        return x, y
```
＜コード基礎知識＞
def = 関数
while True: = 繰り返し文（無限ループ）
try = エラーが出るかもしれない文を書くところ
except = try文内でエラーが発生したらexcept内の文を処理する
else = tryが回ったら処理するところ(exceptが回ったら処理しない）
return = def(関数)の戻り値

＜コード詳細＞
```
    #座標検索
    def search(img, target_range):
        n = 0
        #座標が取得出来るまで無限ループ
        while True:
```
def search(img, target_range)
⇒　関数名(画像パスが入っている変数, 画像検索範囲が入っている変数）
　　img = 画像パス
　　target_range = (left, top, width, height)のタプル型数値が入っている

while True:
⇒　繰り返し処理（無限ループ）

```
try:
    if n == 0:
    p = pyautogui.locateOnScreen(img, grayscale=True, confidence=.6, region=target_range)
    x, y = pyautogui.center(p)
```
try:
⇒　エラーが出るときに備えて入れている(エラーがでたら次のexpectで処理)

if n == 0:
⇒　画像検索一回目の場合は以下の処理をする

p = pyautogui.locateOnScreen(img, grayscale=True, confidence=.6, region=target_range)
⇒　pyautogui.locateOnScreen() = pyautoguiの画像検索モジュール
　　img = 画像パス
　　graiscale=True = 画像をグレーにするかしないか
　　confidence=6 = 画像検索精度
　　region=target_range = 画像検索範囲(画面上に類似の表示があるときに使用）

x, y = pyautogui.center(p)
⇒　画像検索できたら座標がここにはいる
```
else:
    print(f'座標取得リトライします:{n}回目')
    p = pyautogui.locateOnScreen(img, grayscale=True, confidence=.6, region=target_range)
    x, y = pyautogui.center(p)
```
else:
⇒　変数nが0以外のもの全て以下の処理をする
　　※今回は、一回目の画像検索以外はリトライなので条件分岐(if文)を使用

print
⇒　スクリプト処理内容表示

p = pyautogui.lo....
x,y = pyautogui.cen...
⇒　上記と同じ処理
```
except:
    print('except通った!!')
    time.sleep(2)
    n+=1
```
except:
⇒　try文内でエラーが出たらexcept内の処理が回る

print
⇒　表示

time.sleep
⇒　スクリプト一時停止

n+=1
⇒　無限ループの回数をカウント(今回の処理では2回目以降はリトライとする為導入)
```
    else:
        break
return x, y
```
else:
⇒　try文のelseは、try文が起動した最後の処理(exceptではbreakは起動しない)
　　※breakはtry文のif n == 0:のブロック末に入れても同じ処理が行われる

rerun
⇒　def(関数)の戻り値

＜終わりに＞
except内に画像検索を入れていたが、それだと最大2回までしか画像検索できないと思い
このスクリプトを作成
処理の詳細も細かく書いたつもりなので、Python初心者の方にも読みやすいサイトを目指します（＾＾）
AWS Security Specialty 認定更新の記録


# 概要
SCS資格を更新してきました。
やったことと感想を残します。

# About me
インフラエンジニア6年目で、AWS環境の設計構築保守などを主に行っています。

AWS認定資格は全冠済です。

# About SCS

### AWS Certified Security - Specialty

https://aws.amazon.com/jp/certification/certified-security-specialty/
試験ガイド、サンプル問題を見ればどんな資格なのかがわかります。


>第 1 分野: インシデントへの対応 12%
第 2 分野: ログ記録とモニタリング 20%
第 3 分野: インフラストラクチャのセキュリティ 26%
第 4 分野: アイデンティティ管理とアクセス管理 20%
第 5 分野: データ保護 22%

といった感じで、保守で行うような基本知識を問われつつ
AWSサービスを使ったセキュリティ設計時の知識が必要です。

セキュリティと一言で言っても
- TLS、証明書関連、IaC周りの前提知識
- Configなどを使ったアカウントセキュリティや、評価方法
- Networking上の攻撃対策、Firewall設定
- リソース上で扱うデータ自体の暗号化/管理手法
- IAMや鍵などの権限関係

など多岐に渡って問われます。
ただ、実際に作ったことがなくでも学習で補完はできます。

# 今回やったこと

前回の対策を復習しました。
https://qiita.com/shinon_uk/items/67fab096f9b85c47de55

自分用の、問題集を解いたときのメモを見返すのが何より効率の良い学習方法でした。


あとはBlackbeltを読みました。わかりやすい。
例　KMS
https://aws.amazon.com/jp/blogs/news/webinar-bb-kms-2018/

あとは、触ったことがあまりないものは予めAWSコンソールで触ってみると、一気に見られるので良いです。
TerraformなどのIaCで構築してみると、必須項目とそうでないものが嫌でもわかるのでこちらもおすすめです。


# 結果
わからない問題が少しありましたが更新出来ました。
やはりオプションやパラメータをしっかり見ておくべきですね。
Linux ブートプロセスの流れについて（自分用メモ

一般的なLinuxシステムでは、BIOS、ブートローダ、カーネル、initの順にブートプロセスが進行します。  

・BIOS（Basic I/O System）
 最もハードウェアに近い部分を司るシステムで、物理的なハードウェア（マザーボード）上に書き込まれています。 コンピュータの電源を入れると、まずBIOSが起動し、記憶装置（HDD）等に関して最低限の認識をして起動デバイスの優先順位を決定します。その後、優先順位に従って各デバイスの先頭セクタにあるMBR（ブート用の特殊領域。ブートローダが格納されている）を読み込み、得られたブートローダに制御を移します。ブートローダが得られない場合は次のデバイスのMBRを読み込みます。 起動デバイスの優先順位は、BIOSセットアップ画面で任意の順序に設定変更できます。BIOSセットアップ画面はコンピュータの起動時に特定のキー（DEL、F2など）を押すことで呼び出せます。 最近のシステムではUEFI（Unified Extensible Firmware Interface）への移行が進んでいます。

  ・ブートローダ
 LinuxシステムではGRUBが該当します。 MBRに格納されている第一段階部分と、記憶装置内の別の場所に格納されている第二段階部分があります。 このように分かれている理由は、MBRには厳しいサイズ制限があるためです。 ブートローダは記憶装置内のカーネルをロードし、カーネルに制御を移す役割を果たします。 第一段階のブートローダはMBRの先頭446バイトの領域にインストールされます。 

  ・カーネル 
カーネルは起動されると、高度にハードウェアを認識・制御し、ルートファイルシステムのマウントなど様々な初期化処理を行います。 ブートローダはカーネルと初期RAMディスク（initramfs）の内容をメモリ上に展開し、カーネルはメモリ上に展開された初期RAMディスク内の、ファイルシステムへアクセスするために必要なドライバやスクリプトを使用してルートファイルシステムをマウントします。その後、initという特別な最初のプロセスをルートファイルシステムから起動します。 カーネルイメージと、カーネルのバージョンに対応する初期RAMディスクは「/boot」ディレクトリに格納されます。初期RAMディスクは展開してイメージ内のディレクトリ、ファイルを参照することができます。

  ・init 
最初に起動されるプロセスで、PID（プロセス ID）は必ず1です。「SysVinit」と呼ばれる従来のinitプログラムを採用しているシステムでは、「/sbin/init」が起動されます。 initプロセスは設定ファイル「/etc/inittab」の記述に基づいて、自動起動するべきプロセスを立ちあげるなど、アプリケーションレベルの初期化を行います。 以降、initプロセスは全てのプロセスの先祖（直接・間接的な呼び出し元）として存在し続けます。 なお、最近のシステムではinitプログラムとして、初期化処理を高速化したUpstartやsystemdを採用している場合があります。その場合は基本的に「/etc/inittab」ファイルは使用されません。


「/etc/inittab」を設定ファイルとして使用する従来のinitプログラムは「SysVinit」と呼ばれるものです。
Upstartやsystemdは、従来のSysVinitと比べてシステム起動時の初期化作業が高速化されています。

Upstartは「/etc/event.d/rc-default」ファイルの「telinit 2」の部分を編集することでデフォルトのランレベルを設定できます。

ただし、UpstartはSysVinitと互換性があるため、「/etc/inittab」ファイルを新規に作成し、先述のSysVinitの場合と同じように記述することでデフォルトのランレベルを設定することもできます。その場合、「/etc/inittab」ファイルのランレベルが優先されます。

systemdでは、「/lib/systemd/system/runlevel[0-6].target」ファイル([0-6]部分はランレベルを指定)のシンボリックリンクを「/etc/systemd/system/default.target」として作成することでデフォルトのランレベルを設定できます。
VMware Fusion (M1)で「Loading initial ramdisk...」と出た後にフリーズする

ふと思い立ってVMware Fusion (M1)にKali Linuxをインストールしてもうまく動作せず悩んでいました。いろいろ試したところ、メニューからAdvanced Optionで5.16 Kernelを選択すると動作します。ARM版だからかと思ったのですが、実績はありそうなのでかなり悩みました。

## 環境

- MacBook Air M1 (macOS 12.4 Monterey)
- Kail Linux 5.18.0
- VMware Fusion Tech Preview 21H1

## 症状

起動時に「Loading initial ramdisk...」と出た後フリーズする

![スクリーンショット 2022-08-03 12.27.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14768/d718abbf-7265-0fd5-0411-205412912a79.png)

## 解消方法

これを書いた前の週の2022/7/28にリリースされたVMware Fusionの新しいバージョン（Tech Preview 22H2）を利用します（それだけ。

https://blogs.vmware.com/teamfusion/2022/07/just-released-vmware-fusion-22h2-tech-preview.html

以下のように5.15+で起動しないバグがあった模様です。

> *Boot bugs
There were several bugs that blocked successful booting of 5.15+ kernels. Working with the community we addressed issues in the Linux kernel, as well as in our own code to accommodate for the nuances of working with multiple architectures using a single code base. Distributions that have picked up those public changes, such Debian, Fedora and Kali, successfully boot and provide a delightful experience when combined with our latest graphics drivers, Mesa library patches and open-vm-tools.

## その他

Ubuntu 20.04, 22.04はまだ動作しないようです :frowning2:

> Some Notes
....
Ubuntu 20.04.4 and 22.04 for arm64 are not currently booting (Ubuntu 20.04.4 builds from July 5 and onward) We are working to resolve this.
仮想マシンのコマンドとsystemd・SysVinitの違いについて（自分用メモ

仮想マシンを一時停止
virsh suspend {ドメイン名|ID|UUID}

仮想マシンを再開
virsh resume {ドメイン名|ID|UUID}

docker run [オプション] イメージ名

例）Dockerイメージ「ubuntu」を使って新規コンテナ「ubuntutest」を作成・起動して、コンテナの標準入出力に接続する
# docker run -it --name ubuntutest ubuntu
-iオプション（キーボードなどからの標準入力を受け付ける）と、-tオプション（疑似端末を割り当てる）を使用することで、起動したコンテナの標準出力に接続（アタッチ）できます。
また、--nameオプションで任意のコンテナ名を付けられます。コンテナ名の指定が無い場合はランダムな文字列が生成されコンテナ名となります。

上記の例ではexitコマンドで抜けてコンテナが停止していますが、Ctrlキーを押しながらP、Qを続けて押すと（Ctrl+P、Ctrl+Q）、コンテナを停止せずに一時的に抜けることができます（デタッチ）。

CPUが仮想化支援機能をサポートしているかどうかを調べるには、「/proc/cpuinfo」のflagsにおいて"vmx"(Intel VT)または"svm"(AMD-V)という値があるかどうかを確認します。
例）Intel VT-xの場合
egrep ‘(vmx|sxm)’ /proc/cpuinfo



「/etc/inittab」を設定ファイルとして使用する従来のinitプログラムは「SysVinit」と呼ばれるものです。
Upstartやsystemdは、従来のSysVinitと比べてシステム起動時の初期化作業が高速化されています。

Upstartは「/etc/event.d/rc-default」ファイルの「telinit 2」の部分を編集することでデフォルトのランレベルを設定できます。



systemd
・Unitという単位で管理される
・スクリプトを実行できない
・cgroupsというLinuxカーネルの機能によってプロセスのリソースを管理できる
・Upstartと同様に、各サービスを並列起動することができる。そのため、順次起動していくSysVinitに比べて高速なシステム起動や停止が行えます。

SysVinit
・スクリプトを実行できる
・プロセスをPIDで管理



UpstartはSysVinitと互換性があるため、「/etc/inittab」ファイルを新規に作成し、先述のSysVinitの場合と同じように記述することでデフォルトのランレベルを設定することもできます。その場合、「/etc/inittab」ファイルのランレベルが優先されます。


systemdはSysVinitを置き換える新しいinitの仕組み。


systemdで扱う処理はUnitという単位で管理します。Unitは設定ファイルであり、Unitの設定に従ってsystemd自体が処理を実行します。SysVinitのようにスクリプトを実行するわけではありません。
Unitには各機能ごとに拡張子が割り当てられており、拡張子を見ることでどういった機能のためのUnitかが判別できるようになっています。


また、SysVinitではプロセスをPIDによって管理していましたが、systemdではcgroupsというLinuxカーネルの機能によってプロセスのリソースを管理できます。

systemdはUpstartと同様、各サービスを並列起動することができます。そのため、順次起動していくSysVinitに比べて高速なシステム起動や停止が行えます。
システム起動時に最初に実行されるUnitは「/etc/systemd/system/default.target」。「default.target」をSysVinitでのランレベルに相当するUnitへのシンボリックリンクとして作成することで、期待するサービス群を起動できるようになります。

シンボリックリンクとは、Windowsでのショートカットのようなもので、元ファイルの場所を指し示すリンクの事。シンボリックリンクが持っている情報は「元ファイル（ディレクトリ）がどこにあるのか」というパス情報のみです。
シンボリックリンクを作成するにはlnコマンドに「-s」オプションを付加して作成します。（書式：ln -s 元ファイル リンクファイル）


ターゲットは「/lib/systemd/system」配下に格納されています。また、SysVinitとの関連がわかりやすいように、runlevel0.target〜runlevel6.targetまでのシンボリックリンクも用意されています。


各サービスの稼働状況や起動設定を管理するにはsystemctlコマンドを使用します。systemctlコマンドの書式

systemctl サブコマンド [ Unit名 ]
※Unit名に拡張子がない場合、.serviceの拡張子を持つUnitが指定されたものとみなされます


自動起動設定がどのターゲットに対して有効となるかは、各Unit定義ファイルに記述されています。httpd.serviceファイルの中では、以下のとおりmulti-user.targetで有効となるよう[WantedBy]項目に記述されていることがわかります。

サービスの自動起動を無効にすると、作成されたシンボリックリンクが自動で削除されます。
superとsuper()

# thisと差
thisは現在のクラスのメンバー変数を指し、superは相続クラスのメンバー変数を指す。

現在のクラス: this.変数
相続クラス: super.変数

# Overriding
overridingは親クラスを受け継いだメソッドを子クラスで再利用することだ
条件 : メソッド名, リターンタイプ ,パラメータの個数が同じでなければならない

 ```
public class index{
   public static void main(String[] args){
      Parent parent = new Parent();
      parent.sum();

      Child child = new Child();
      child.sum();
   }
}

public class parent{
   int sum;
   public int sum(int x, int y){
      sum = x + y;
      
      return sum;
   }
}

public class child extend parent{
   int sum;
@Overriding
   public int sum(int x, int y){
      sum = x + y + x;

      return sum;
   }
}
 ```
# super
superとは親クラスのメンバー変数を指す。
 ```
public class parent{
   int x;
   int y;

   public parent(){
      x = 10;
      y = 5;
   }

   public parent(int x, int y){
      this.x = x;
      this.y = y;
   }
}

public class child extends parent{
   public child(){
      super.x = 1;
      super.y = 2;
   }
 ```
# super()
super()は相続したクラスのConstructorを呼び出す
```
public class parent{
   int x;
   int y;

   public parent(){
      x = 10;
      y = 5;
   }

   public parent(int x, int y){
      this.x = x;
      this.y = y;
   }
}

public class child extends parent{
   public child(int x, int y){
      super(x, y);
   }
} 
```
# 規則
this()、super()呼び出し時に一番最初の行に書かなければならない規則がある。
PowerAutomateで配列の値をキー、キー（添字）を値とするマップをつくる

前回に続きPowerAutomateで配列を操作するときに必要になったテクニックの紹介です。

# Problem

文字列の配列について、その値をキーに、キー（添字）を値とするマップ（辞書）を作りたい。
例によってPowerAutomateにはこのようなオペレーションをシンプルに行うための関数は存在しない。
「Apply to each」アクションと配列変数を使う方法はフロー内で場所も時間もとってしまうので避けたい。

イメージ：
変換前　`Array<String>`
変換後　`Map<String,Integer>`

# Solution

`range()`関数と`json()`関数を活用します。

まずは例示のための配列を作成します：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/b9f97396-dbb0-5ac7-4ef1-d3fa8a9ce224.png)

```json
[
  "foo",
  "bar",
  "baz"
]
```

次に`range()`関数が生成する整数列を選択アクションで処理します。整数列は変換対象の配列と同じ長さを持ちます。
この整数を使って変換対象の配列から要素を取り出して、JSONオブジェクトのプロパティ・リテラル（`'"key": "value"'`）を作成します：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/b8e87443-1be7-8ea7-2de6-f15104d32e56.png)

* From: `range(0, length(outputs('Compose_arrayX')))`
* Map: `concat(outputs('Compose_arrayX')[item()], ':', item())`

こうして作成したリテラルを`','`で繋げ、`'{'`と`'}'`で囲い、`json()`関数でJSONリテラルとしてパースします：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/7247c77d-377a-8284-5051-e268fc5b1b82.png)

* Inputs: `json(concat('{', join(body('Select_property_literal'), ','), '}'))`

以上です。
実行すると、このように変換ができていることがわかります：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/c841dd04-addb-f94c-66ca-69bfb517ea6c.png)

```json
{
  "foo": 0,
  "bar": 1,
  "baz": 2
}
```

## 応用：オブジェクトの配列をオブジェクトのマップに変換する

これを応用すると、オブジェクトの配列を（オブジェクトに含まれる任意のプロパティ値をキーとする）オブジェクトのマップに変換するフローも作成できます。

まずは例示のための配列を作成します：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/82587508-7257-1511-509a-44148e4f66e2.png)

```json
[
  {
    "key": 1,
    "value1": "arrayA_item1_value1",
    "value2": "arrayA_item1_value2"
  },
  {
    "key": 2,
    "value1": "arrayA_item2_value1",
    "value2": "arrayA_item2_value2"
  },
  {
    "key": 3,
    "value1": "arrayA_item3_value1",
    "value2": "arrayA_item3_value2"
  }
]
```

次にJSONオブジェクトのプロパティ・リテラルを作るところですが、ここでは`range()`関数を使っても使わなくてもOKです。今回は使わない例：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/8a4465bc-0870-ff23-67f0-6e8b253783b1.png)

* From: `outputs('Compose_arrayX')`
* Map: `concat(item()['key'],':',removeProperty(item(), 'key'))`

こうして作成したリテラルを`','`で繋げ、`'{'`と`'}'`で囲い、`json()`関数でJSONリテラルとしてパースします。ここは先ほどと一切替わりありません：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/7247c77d-377a-8284-5051-e268fc5b1b82.png)

* Inputs: `json(concat('{', join(body('Select_property_literal'), ','), '}'))`

実行した結果は次の通り：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/3b36755c-cbbf-4a89-19a6-bac729008782.png)

```json
{
  "1": {
    "value1": "arrayA_item1_value1",
    "value2": "arrayA_item1_value2"
  },
  "2": {
    "value1": "arrayA_item2_value1",
    "value2": "arrayA_item2_value2"
  },
  "3": {
    "value1": "arrayA_item3_value1",
    "value2": "arrayA_item3_value2"
  }
}
```
【データモデル】製品スタートアップ時のカスタム処理設定

[Sharperlight](https://sharperlight.jp/)のデータモデルには、様々なプロセスをいろいろなタイミングで実行させる機能が備わっています。今回は、その中でも使用頻度の高い Startup時のプロセスについて例を挙げて紹介してみたいと思います。
システムを展開する時に、接続対象データベースに対してある必須テーブルを作成したい場合を例としてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/e814e374-974d-65d2-f4e2-94305d342616.png)
英語ですいません:bow_tone1:

Sharperlightスタジオを起動して、使用するデータモデルを開きます。スタジオウィンドウ下部の`Processes`を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/4b006cb9-056b-c3db-b845-3cdc8b594883.png)
上部表示領域にイベント一覧が表示されます。その一覧から`OnStartup`を選びます。
`OnStartup`は、Sharperlightのいずれかのアプリケーション、例えばクエリビルダなどでこの対象データモデルがアクセスされた時点で作動するイベントです。
このイベントには、様々なスクリプトを設定することができます。ここでは、テーブルを作成するSQLスクリプトを設定してみます。
`OnStartup`をダブルクリックして、中央表示領域にプロセス一覧を表示しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/cf352bcd-5ea5-93b2-6a5f-929211d52d27.png)
もちろん！まだなにもありませんね。
トップノードで右クリックメニューを表示して、`New Folder`を選択しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/09888dfb-2aa2-3c7b-d982-505489c485cc.png)
追加されたフォルダーのプロパティの**Code**と**Description**を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/f55d3013-fee8-ef4b-51d7-cf05feb09d1d.png)
追加したフォルダー上で右クリックメニューを表示して、`New SQL Command`を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/dbd7415c-0c22-4e12-60f7-5b922dd2b748.png)
新しくSQLコマンドがフォルダ内に作成されるので、ここでも**Code**と**Description**を記入します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/0adfe328-4007-b953-7ea5-fe738b184375.png)
追加したSQLコマンドを選択すると、下部領域にテキストフィールドが表れます。
ここにテーブル作成用のSQLスクリプトを記入します。
実行時にエラーが出ないように、テーブルの存在をチェックし、存在しない場合のみ作成するようにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/527bb67e-3a13-ccc4-bd5a-998304dc4010.png)
下部の`Pop Out Edit`ボタンで、テキストウインドウを大きく開くことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/a062322a-b1ed-1fa2-277a-13cb052a63f8.png)
これで設定は終了。データモデルを保存します。

Sharperlightクライアントセットアップで、対象データベースとこのデータモデルの接続が設定されるので、このSQLスクリプトが実行される場合は、その接続が使用されることになります。よって接続情報で使用したアカウントがテーブル作成可能なアカウントである必要があります。

実行タイミングの一例として、クエリビルダを起動します。
この製品フィルターに、`OnStartup`を設定したデータモデルを選択した時点で、`OnStartup`プロセスが実行されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/648f4ec5-08c9-1d85-a549-c8ecdc353b56.png)
このように、Sharperlightデータモデルを客先や現場に導入する場合など、データモデルをインストールし、クライアントセットアップでデータベースとの接続を確立するだけで、意識することなくバックエンドでシステムに必要な初期設定を実行することができるというわけです。