OmniAICreator/Qiita-1.07M huggingface dataset:
IBM Cloud: VPCのWindows仮想サーバーへのログイン方法

# 概要
IBM CloudのVirtual Private Cloud（VPC）にて、Windowsの仮想サーバーを作成した際のGUIログイン方法を記載します。

# 前提
以下を満たしていることを前提とします。
- VPCにWindowsサーバーを作成している。
- Windowsサーバー作成時にssh鍵を指定し、その秘密鍵を保持している。
- Windowsサーバーに浮動IPアドレスを付与している。
- IBM Cloud CLIをインストールした環境がある。
- IBM Cloud CLIの`vpc-infrastructure`プラグインをインストールしている。

:::note warn
注意
Windowsサーバー作成時には、鍵登録を一つにしてください。
複数登録した場合、鍵の名前順最初の1つでしかパスワード発行できません。複数人で共有する際は、パスワード発行後に安全な方法で共有してください。

:::



# Windowsサーバーへのログイン手順
CLIにてWindowsサーバーログインに使用するパスワードを発行したのち、RDPソフトにてログインを行います。

## ログイン用パスワード発行
初めに、CLIにてログインします。
```
$ ibmcloud login -apikey [APIキー] -g [リソースグループ] -r [VPCのリージョン]
```
以下のコマンドにて、WindowsサーバーIDを指定し、パスワードを発行します。実行結果の最下部記載のパスワードを使用します。

※VPC等にセキュリティ設定を行なっていない場合、このパスワードとIPアドレスが分かれば誰でもログインできてしまうので、取り扱いには細心の注意を払って下さい。（**ランダムなIPアドレスにアタックしている攻撃者は当てずっぽうでもログイン可能です**）

```
$ ibmcloud is instance-initialization-values [仮想サーバー・インスタンス ID] --private-key @[秘密鍵へのパス]/id_rsa
Getting instance initialization values for xxxxxxxxxxxxxxx
 under account IBM as user 123456@gmail.com...

Keys                 ID                                          Name         Fingerprint
                     xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx        ssh-key   SHA256:uZEMLCUSNnxxxxxxxxxxxxxxxxxxxxxxxxxxx

Encrypted password   DFTOZRemkyvNaC....
...
...
......=
Encryption key       ID   Name   Fingerprint
                     -    -      SHA256:uZEMLCUSNnxxxxxxxxxxxxxxxxxxxxxxxxxxx

Password             xxxxxxxxxxxx   ###このパスワードを使用
```

## RDPソフトでのログイン
次にRDPソフトを起動します。RDPソフトには、Microsoft [Remote Desktop](https://apps.apple.com/jp/app/microsoft-remote-desktop/id1295203466?l=en&mt=12)を使用しています。

アプリを起動し、プラスボタンをクリックします。
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2199676/c02c9afb-6223-dd99-ba48-9702446db99b.png width=70%>

設定画面が表示されるので、`PC name`に浮動IPアドレスを入力します。設定は保存されるので、オプションで`Friendly name`を入力すると管理が容易になります。最後に`Add`を入力します。
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2199676/9de3cb2d-4624-6e3c-20e0-beff009dc35c.png width =70%>

作成した設定をダブルクリックし、`Username`に`Administrator`、`Password`に先ほど発行したパスワードを入力します。
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2199676/8d3ed893-d916-60be-5736-ce4fefaa429b.png width=80%>

無事ログインできました。（起動直後はサーバーマネージャーが起動します）
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2199676/0e3787df-1c37-5819-98f8-b458847a4a53.png width=70%>

# パスワードが発行できない場合
上記コマンド実行にてエラーが発生した場合、秘密鍵をPEMファイルへ変換して指定すると解決する場合があります。
```
$ ssh-keygen -p -m PEM -f ~/.ssh/key.pem
$ ibmcloud is instance-initialization-values [WindowsサーバーのID] --private-key @~/.ssh/key.pem
```
Cloud FunctionsのHTTP起動の認証について


Google CloudのCloud Functionで起動トリガーをHTTPにした場合、誰でも処理を起動できないようにHTTPアクセスに対してデフォルトで認証が必要となります。この記事では、PythonでCloud FunctionsにHTTP（認証あり）接続を行う方法を紹介します。 
　なお、基本的には[googleドキュメント](https://cloud.google.com/functions/docs/securing/authenticating?hl=ja#functions-bearer-token-example-python)のプログラムによるトークン生成を参考にしていますが、使用しているライブラリを「urllib」→「requests」に変更しています。（個人的な趣味の問題）

# 下準備
HTTPトリガーのCloud Functionsを準備します。これはサンプルなので関数などはデフォルトのままで準備してもらえば大丈夫です。僕はPython3.9をランタイムとして選択しました。![キャプチャ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541501/405256ac-5ba2-67b2-5c5d-529aefff73e0.jpeg)

# HTTP接続（認証なし）
Pythonのrequestsモジュールを利用して、作成したCloud FunctionsのトリガーURLにGETでアクセスします。
```python
import requests

def make_no_authorized_get_request(target_url):
    response = requests.get(target_url)

    return response


if __name__ == "__main__":
    result = make_no_authorized_get_request(
        "ここに作成したCloud FunctionsのトリガーURLを記載"
    )
    print(result.text)
```
実行結果は以下の通りです。
```html
<html><head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>403 Forbidden</title>
</head>
<body text=#000000 bgcolor=#ffffff>
<h1>Error: Forbidden</h1>
<h2>Your client does not have permission to get URL <code>/function-2</code> from this server.</h2>
<h2></h2>
</body></html>
```
permissionエラーが出力されました。

# HTTP接続（認証あり）
次に認証ありの場合で実装していきます。
```python
import requests

import google.auth.transport.requests
import google.oauth2.id_token

def make_authorized_get_request(target_url):
    auth_req = google.auth.transport.requests.Request()
    id_token = google.oauth2.id_token.fetch_id_token(auth_req, target_url)

    headers = {
        "Authorization": f"Bearer {id_token}"
    }
    response = requests.get(target_url, headers=headers)

    return response


if __name__ == "__main__":
    result = make_authorized_get_request(
        "ここに作成したCloud FunctionsのトリガーURLを記載"
    )
    print(result.text)
```
結果が以下の通りです。
```terminal
Hello World!
```
おーうまくできました。

ちなみに、GETメソッドをパラメータありで実行することも簡単です。
```python
import requests

import google.auth.transport.requests
import google.oauth2.id_token

def make_authorized_get_request(target_url):
    auth_req = google.auth.transport.requests.Request()
    id_token = google.oauth2.id_token.fetch_id_token(auth_req, target_url)
    headers = {
        "Authorization": f"Bearer {id_token}"
    }
    params = {
        "message":"sample message"
    }
    response = requests.get(target_url,headers=headers, params=params)

    return response


if __name__ == "__main__":
    result = make_authorized_get_request(
        "ここに作成したCloud FunctionsのトリガーURLを記載"
    )
    print(result.text)
```
実行結果は以下の通りとなり、paramsで指定した値を取得できました。
```terminal
sample message
```

# 最後に
[googleのドキュメント](https://cloud.google.com/functions/docs/securing/authenticating?hl=ja#functions-bearer-token-example-python)だとmake_authorized_get_requestの引数が、２つ（service_url、audience）あるんですが、なんか理由があるんですかね・・・誰か教えてください。
PythonプログラムからGmail送信

# はじめに
Pythonプログラムからgmailを送信する方法をご紹介します。
認証は簡単ですし程よく無視できるので、自分しか使用しない場合にGmailでの通知は非常に便利です。
最後にプログラム全文を載せています。

#### 使用するライブラリ
組み込みなので `pip install`の類は不要です。

```Python
import smtplib
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
```

`main()`から各メソッドを呼び出します

```Python
def main():
    img_path = 'sample.png'
    message = setup_mail()
    message = attach_img(message, img_path)
    send_mail(message)
    return
```

```Python
def setup_mail():
    message = MIMEMultipart()
    message["Subject"] = "メールの件名です"
    message["To"] = '送信先@hogehoge.com'
    message["From"] = '送信元@gmai.com'
    message.attach(MIMEText('メール本文', "html"))
    return message
```

smtplibモジュールを使ってgoogleにログインし、`send_message`メソッドに、情報を添加した`MIMEMultipart()`を渡すことでメールを送信します。

```Python
def send_mail():
    account = 'hogehge.gmail.com'
    password = 'パスワード'
    server = smtplib.SMTP("smtp.gmail.com", 587)
    server.starttls()
    server.login(account, password)
    server.send_message(message)
    server.quit()
```

画像を添付する場合は、画像を読み込み`MIMEImage`に渡します。

```Python
def attach_img(message, img_path=None):
    if img_path is None: # 画像のpathを渡さなかった場合、画像を添付しない
        return
    with open(img_path, 'rb') as f:
        img = f.read()
    image = MIMEImage(img, name=img_path)
    message.attach(image)
    return
```

#### Google の二段階認証設定方法
送信元のGoogle アカウントで以下へアクセスして二段階認証をオン
<https://myaccount.google.com/signinoptions/two-step-verification>  
次に、以下よりメールを選択、生成をクリック  
<https://myaccount.google.com/apppasswords>

パスワードを控えておきます。  
send_mail()内のpasswordとして使用します。

#### 以下プログラム全文
```Python
import smtplib
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart

GMAIL = '' # 上記でパスワードを発行したアカウントアドレスを記入
PASSWORD = ''
MAIL_TO = ''

def main(mail_to, subject, mail_body, img_path=None):
    message = setup_mail(subject, mail_to, mail_body)
    attach_img(message, img_path)
    send_mail(message)
    return


def setup_mail(subject, mail_to, mail_body):
    message = MIMEMultipart()
    message["Subject"] = subject
    message["To"] = mail_to
    message["From"] = GMAIL
    message.attach(MIMEText(mail_body, "html"))
    return message


def send_mail(message):
    server = smtplib.SMTP("smtp.gmail.com", 587)
    server.starttls()
    server.login(GMAIL, PASSWORD)
    server.send_message(message)
    server.quit()


def attach_img(message, img_path):
    if img_path is None:
        return
    with open(img_path, 'rb') as f:
        img = f.read()
    image = MIMEImage(img, name=img_path)
    message.attach(image)
    return

if __name__ == '__main__':
    main(MAIL_TO, 'タイトルです', '本文です')
    # 画像添付
    main(MAIL_TO, 'タイトルです', '本文です'img_path='sample.png')
```
ESP32-CAMが技適取ってないのでWT-ESP32-CAMを使って魔改造してみた

ESP32-CAMというとても安価なカメラモジュールがあります。
カメラ性能も200万画素とそこそこ高くとてもいい製品なのですが、
技術基準適合証明（技適）が取れていませんので日本では使用できません。。。
残念(^_^;)
![IMG20220412142748.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/4901176a-2d74-209c-cdff-5dc5db453e25.jpeg)

そこで今回は、中国製のWT-ESP32-CAMというモジュールを使用して、
カメラサーバを構築してみました！！
![IMG20220412134557.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/657c09ae-c2e1-98eb-b284-dfb889ccf23e.jpeg)


しかしただカメラで映像を映すだけも面白くない・・・
どうせなら他の人がやってないことをやろう＼(^o^)／


そうだ！カメラで見ながらなんか操作できたら面白いかも！！


カメラサーバーに接点を出力できる機能をつけよう！！



待てよ・・・

けどESP32-CAMのデフォルトの機能って接点出力（デジタル出力）の
機能もないし、ましてやIPを叩けば簡単に入れる。。。

遠隔で操作できるならLogin機能が無いと危なくないか・・・(^_^;)


ということでログイン機能付き＆接点出力もできるように
#### 魔改造してみました！！


## ハードウェア
- WT-ESP32-CAM
- アンテナ（組み合わせ技適が取れているもの）
- リレー4個
- ブザー1個
- スイッチ1個
- タクトスイッチ1個

## 機能
- Wi-Fi通信
- ブラウザから操作可能（デジタル出力、カメラ映像表示）
- デジタル出力時は、ブザーとLED点灯が3回行われた後に出力
- ログイン機能
- AP機能（機器の初期設定時に接続）
- ログインID、パスワード、IP変更

## 出来上がった試作品
![IMG20220412145446.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/a9ca1fec-231c-0f66-3178-94efe5c30acb.jpeg)
***
#### ログイン機能
カメラにアクセスしようとしても、ログインIDとパスワードを入れないとアクセスできません。
![コメント 2022-04-12 154552.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/6395292f-8d24-249f-c044-ded230d7e026.png)
***
#### 操作画面もカスタマイズ！
操作画面には色々といらない機能もあったので
必要な機能のみ残しました！背景も白に変更！
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/582a2855-76a7-bae7-6735-71f87a223ec7.png)
***
#### 接点出力も可能に！！
「かめら1」のトグルボタンを押すと接点出力がONになります！
![コメント 2022-04-12 154308.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1339052/c08010df-03a1-a9b0-d4e6-a24c975a2b94.png)
↑　かめら1のデジタル出力をONにした状態
***


めちゃめちゃ安くでWebカメラ機能もあってデジタル出力もできる試作品が完成しました。
次回はPCB基板におこしてみたいと思います！
Webテンプレートエンジンとは？【個人的なお勉強アウトプット】

HTMLのテンプレートに、バックエンドなどでやりとりしたロジックやデータを表示するためのソースコードを埋め込み、合体させるもの。

## メリット
HTMLの中にロジックも埋め込むと複雑になり可読性がかなり低くなる。
テンプレートエンジンを使うと、HTMLとロジック部分を切り離すことができるので、どちらかの変更がしやすくなる。
例えばHTMLを変えたいときはHTMLだけ、表示するデータを変えたければデータがまとまったjsonファイルを。

# 参考記事
https://pyteyon.hatenablog.com/entry/2019/08/23/135834
https://www.codegrid.net/articles/template-engine-1/
MariaDBを軽率にapt upgradeしたら起動しなくなった件

そんなの聞いてないよぉ(つд⊂)ってなったので覚書
10.3.30以上を初めから使ってる場合は影響ないっぽい


**追記：MariaDB10.3.31リリースノートには壊れる(壊れてないけど)書いてあった**

# 環境
### アップグレード前
Debian 10.9
MariaDB 10.3.2x

### アップグレード後
Debian 10.12
MariaDB 10.3.35

# アップグレード後のエラーログ

### /var/log/mysql/error.log

```
2022-04-12 14:37:09 0 [Note] InnoDB: Using Linux native AIO
2022-04-12 14:37:09 0 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
2022-04-12 14:37:09 0 [Note] InnoDB: Uses event mutexes
2022-04-12 14:37:09 0 [Note] InnoDB: Compressed tables use zlib 1.2.11
2022-04-12 14:37:09 0 [Note] InnoDB: Number of pools: 1
2022-04-12 14:37:09 0 [Note] InnoDB: Using SSE2 crc32 instructions
2022-04-12 14:37:10 0 [Note] InnoDB: Initializing buffer pool, total size = 128M, instances = 1, chunk size = 128M
2022-04-12 14:37:10 0 [Note] InnoDB: Completed initialization of buffer pool
2022-04-12 14:37:10 0 [Note] InnoDB: If the mysqld execution user is authorized, page cleaner thread priority can be changed. See the man page of setpriority().
2022-04-12 14:37:10 0 [ERROR] InnoDB: corrupted TRX_NO 10002001a69c0f4
2022-04-12 14:37:10 0 [Note] InnoDB: Retry with innodb_force_recovery=5
2022-04-12 14:37:10 0 [ERROR] InnoDB: Plugin initialization aborted with error Data structure corruption
2022-04-12 14:37:10 0 [Note] InnoDB: Starting shutdown...
2022-04-12 14:37:10 0 [ERROR] Plugin 'InnoDB' init function returned error.
2022-04-12 14:37:10 0 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
2022-04-12 14:37:10 0 [Note] Plugin 'FEEDBACK' is disabled.
2022-04-12 14:37:10 0 [ERROR] Unknown/unsupported storage engine: InnoDB
2022-04-12 14:37:10 0 [ERROR] Aborting
```

# 応急処置
10.3.2xまでダウングレードしてバージョンをホールドする様にしておく

ダウングレード
```
apt install mariadb-server-10.3=1:10.3.29-0+deb10u1 mariadb-server-core-10.3=1:10.3.29-0+deb10u1
```

バージョン固定
```
apt-mark hold mariadb-server-core-10.3 mariadb-server-10.3 mariadb-client-10.3 mariadb-client-core-10.3 mariadb-common
```

# 現状の本対応
1.アップグレード前にDB全体のダンプを取る
2.DB初期化する
3.mariadbを10.3.30以上にアップグレードする
4.DBをインポートする

運用中のDBでやりたくないね？

エラーログに出てくる
> InnoDB: Retry with innodb_force_recovery=5

これやるとほんとに壊れそう・・・


# 参考情報
[MariaDB10.3.31リリースノート](https://mariadb.com/kb/en/mariadb-10331-release-notes/)
[Bug#996028: #996028 InnoDB: corrupted TRX_NO after upgrading to 10.3.31](https://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg1823558.html)
[fix InnoDB: corrupted TRX_NO after upgrading to 10.3.31](https://dba.stackexchange.com/questions/303041/fix-innodb-corrupted-trx-no-after-upgrading-to-10-3-31)
高度試験の勉強方法（午前）

# 先にまとめ
注意：ここに書いている内容は個人差あり。
1. （午前1）過去問、応用情報ドットコムをまわす。6割超えると思ったらすぐ止める。
1. （午前2）直近6回分から、直近1回に出題された問題を除くものを解く。

# 午前1
* 試験区分によらず、応用情報の80題から30題が出る。
* 試験時に考えればもう6割は超える、と感じたら勉強しない。なるべく早めに午後に力を入れる。
* 男は黙って免除を受けずに午前1から（時代錯誤）。

# 午前2
* 直近6回分をA4に2ページを集約して印刷する。
* あとで思い出せるレベルの簡単な解説を自分で調べて書く。
* 繰り返し出題されたか確認する。
* 直近6回分の内、直近の1回に出題された問題に関する解説は浅くて良い。（どうせ出ないから）
* 受験区分の専門分野に関する問題を重視する。
* 午前は予選というか暗記ゲーなので、試験当日まで放置で良い。

# あとは試験区分ごと（随時切り出し予定）

## 情報セキュリティスペシャリスト（情報処理安全確保支援士）
* 午後1にも役立つ、基本的な知識多め。
* 応用までに勉強すべき基本的なこと（脅威とその対策等）が身についていれば、午前2は勉強なしでも。

## ネットワークスペシャリスト
* 午前であっても、勉強しないと受からない。
* 思ったよりもネットワーク（専門分野）の問題多い。
* 知らないものは知らん、にならないように注意。過去問まわすのは変わらない。

## データベーススペシャリスト
* 午前であっても、勉強しないと受からない。
* 計算ではないけど、その場で考える系問題も多い。
* ダーティリード？知らんがな、ではなく、知ってるくらいにはなりたい。

## システムアーキテクト
* この区分だけは、過去問からの出題率低いと思う。地味に6割超えるかどきどきする。
* 全く同じ問題、ではなく、何かしら視点が違う。
* ブラックボックステストとホワイトボックステストは当たり前すぎる。
* アジャイルのこともたまには思い出してあげて。
* この区分は、午前2を勉強しても午後問題には役立たない。

## ITサービスマネージャ
合格していないけど、とりあえず切り出し済み。

https://qiita.com/seigen2414/items/9cb87dd3b3c5b4f67536

## プロジェクトマネージャ
* まだ取れていないけど、困ったときは野村。
【世界一わかりやすい】Atcoder ABC247 C・D問題 Python3解説

**ABC247**の**C,D**問題を、**Python3**で解説します！

ょゎょゎな筆者でもわかる、読みやすさを重視した、**初心者**向け解説です(´・ω・｀)

ゆっくり見ていってね(｀・ω・´)ｷﾘｯ

# C問題 『1 2 1 3 1 2 1』

問題ページ：[C問題 - 1 2 1 3 1 2 1](https://atcoder.jp/contests/abc247/tasks/abc247_c)

### 考え方

$S_n=S(n-1)+n+S(n-1)$ であることより、**再帰的**に解けば効率が良い(｀・ω・´)

$i = 1$ から $n$ まで、順に $S_i$ を求め、値を保存しておこう(｀・ω・´)

### コード

```python3:C.py
n = int(input())

S = [[1]] #S_0は1で定義しておく

for i in range(1, n):
    #i=1~nまで、順にS_iを求め、Sに保存していく
    S.append(S[i-1] + [i+1] + S[i-1])

print(*S[n-1]) #「*リスト」でリストの要素をスペース区切りで出力できるよ
```

# D問題 『Cylinder』

問題ページ：[D問題 - Cylinder](https://atcoder.jp/contests/abc247/tasks/abc247_d)

### 考え方

$x=1$ の時、筒に入れたボールを、$(x, c)$ の形で、右に追加していく。

$x=2$ の時、筒のボールを左から順に取り出していく。
取り出しすぎたら、取り出しすぎたボールの個数を更新して、左から戻す。

筒の中身は、**deque**を使えば、右からも左からも $O(1)$ で取り出すことができる(｀・ω・´)

>dequeについて（他サイトより引用させていただきました）
https://note.nkmk.me/python-collections-deque/

### コード

```python3:D.py
q = int(input())

from collections import deque
balls = deque([]) #ここにx=1の時、筒に入れたボールを、(x, c)の形で、右に追加していく

for i in range(q):
    query = list(map(int, input().split()))
    if query[0]==1: #x=1の場合
        x = query[1]
        c = query[2]
        balls.append([x, c]) #(x, c)の形で、右に追加

    else: #x=2の場合
        c = query[1]
        s = 0 #取り出したボールの数を0で初期化
        ans = 0 #答えを0で初期化
        while c>s: #cを超えない限りボールを取り出す
            b = balls.popleft() #左から取り出す
            s += b[1] #取り出したボールを追加
            ans += b[0]*b[1] #答えを追加
        balls.appendleft([b[0], s-c]) #取り出しすぎた分を左から戻す
        ans -= b[0]*(s-c) #取り出しすぎた分を答えから引く

        print(ans)
```

# まとめ

最後まで見てくれてありがとう(´・ω・｀)
これからも自分の勉強がてらABCのC,D問題とか、過去問の解説上げてくかも。
来週も頑張ろうね(｀・ω・´)ｷﾘｯ
Windowsにおけるpython開発環境2022

# 概要
Anacondaが商用有償化した中で、Windows上のpython開発環境はどうしたら良いか、色々確認してみたら、結局はシンプルな答えに落ち着いたって話。

# Minicondaの採否
Anacondaの代替策として、minicondaを紹介しているWebページは、見た。
でも、レポジトリの設定を変更しなければ、有償化の対象になるようだし、その設定変更までするのが面倒って考えた。

数値計算が高速化されていることを求めないなら、minicondaじゃなくて良い、と考えた。

# Python本体のインストール
なるべく新しい版が使いたいこともあり、www.python.orgからダウンロードしてきたものをインストールすることとした。

インストール時に、環境変数pathに追加するかのチェックボックスがあるが、これは好みでどっちでも良い。
他にインストールしているpythonが無かったりするなら、チェックをONにすれば良い。

pathに追加しなかった場合には、最近のバージョンに同梱されているpyコマンドを使って、指定の版のpython.exeを起動しても良いし、インストールしたものの実行ファイルのディレクトリーを一時的にpathの先頭に追加する下記の様なバッチファイルを用意して使っても良い。

```
set path=C:\Users\USERNAME\AppData\Local\Programs\Python\Python310;C:\Users\USERNAME\AppData\Local\Programs\Python\Python310\Scripts;%path%
```

# proxy設定
現状なぜか、proxyの指定をpipコマンドの引数で指定してもうまくいかないようだ。
解決方法は他の人も書いているように、環境変数でproxyのアドレスを指定すれば良い。
pipを使う度に入力するのは面倒なので、下記の様なバッチファイルを用意して、必要に応じて実行すれば良い。

```
set HTTP_PROXY=http://123.4.5.6:8080
set HTTPS_PROXY=http://123.4.5.6:8080
```

# Spyderのインストール
Anacondaを使いたい人のその理由の一つは、開発環境としてSpyderを使いたいから、という場合も多いだろう。

spyderのサイトから、インストール用のファイルをダウンロードして、それでインストールしてみたんだが、ちょっと古いpython.exeが同梱されていた。
別途インストール済みのpython.exeをspyderで使うように指定することは可能なんだが、そうするとそっちのpython.exeに対して、spyder関連のモジュールのインストールが必要であった。

なので、インストール済みのpython.exeに対して、pipコマンドでspyderをインストールすることにした。

Spyderのwebサイトには、pipでインストールするのは良く分かった人だけにしろ、的なことが書いてあったが、特に問題は無かった。
下記コマンドでインストールし、pythonの実行ファイルのディレクトリーに入った、sypder.exeを右クリックして「スタートメニューにピン留め」とでもしておけば良い。

```
pip install sypder
```

# Jupyter Notebook, Jupyter labのインストール
pythonの実行環境としては、jupyterも使いたい。

これも関連モジュールと合わせて、pipでインストールした。

```
pip install numpy pandas jupyter jupyterlab
```

jupyter labの起動用のバッチは、下記のようなものを用意しておけば良い。
ここでは、開かれるフォルダーを指定するため、そこにcdした上で、jupyter labを起動している。(configで開くフォルダーを指定している場合は、そちらが優先されると思われる。)

```
set path=C:\Users\USERNAME\AppData\Local\Programs\Python\Python310;C:\Users\44277\AppData\Local\Programs\Python\Python310\Scripts;%path%

cd C:\Users\USERNAME
C:\Users\USERNAME\AppData\Local\Programs\Python\Python310\Scripts\jupyter.exe lab
```

## MeshMagickのインストール
python開発環境としては、MeshMagickは不要だが、ちょっとひっかりかけたので、他のプログラムでも同様の場合があるかも知れないので、簡単にだけ。

MeshMagickのインストールの失敗例は、検索するといくつか出てきて、minicondaを使ってくれ、と回答されている。
但し、MeshMagickのインストール方法の説明ページに書かれている方法を、少し修正してPython 3.9環境で実行すれば、問題なくインストール出来た。

~~これは、安易にminicondaに逃げる必要は無い、という実例だ。~~

よくよく調べると、現時点(20022/4/19)ではVTKモジュールのPython 3.10対応版がpip用のものは提供されておらず、conda用には提供されているが一番の原因のよう。(MeshMagicの場合は3.9環境で通常のpipでうまくいかないという問題もあるが)

フリーのFEMやシミュレーションなどのソフトで、pythonベースでvtkモジュールを使っているもの(Salomeなど)は同様にpython 3.10環境では、通常の方法ではうまくいかない可能性があると思われる。

# まとめ
結局のところ、www.python.orgからインストーラーをダウンロードして実行したら、後はpipで入れていけばいいってだけになった。

こんな風で済んだのは、pythonのwindowsへの対処が進んできた結果だと言えるので、関係者には感謝です。
10回目　スイッチ

ハブ、スイッチ、ルータの違いについて解説する
![スイッチ1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606732/babb3887-bf78-a554-d55f-e579b90851dc.png)

第一分岐点　中継器の種類
第二分岐点　使用されるデータの形や宛先の違い

### はじめに
1物理層・・・LANケーブルや光ケーブル
ハブ、（リピーターハブ）
2データリンク層・・・LANやMACアドレス
L2スイッチ,（スイッチングハブ）
3ネットワーク層
ルータ、（L3スイッチ）・・・WANやIPアドレス
と分けて説明することそのため、「スイッチ」という言葉でなく１＝ハブ、２＝スイッチ、３ルータという階層で使われるものという考え方で分けて説明する。

![スイッチ2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2606732/d4229ac6-2586-e973-4a4f-1fc3d073fbc1.gif)

#### ハブとスイッチの違い
ハブでは接続した機器すべてにデータを送信していた。そのため、単純に接続するための窓口を増やすことを目的としている。
第2層のデータリンク層
スイッチは複数の相手にデータを送信できる。
宛先のMACアドレスにたいして自身の持つMACアドレステーブルを参照して振り分けを行う必要なポート間だけでデータのやり取りをおこなうため、データのコリジョンが起こりにくい。

#### スイッチとルータの違い
「特定の相手にデータを転送する」という点では、同じだが扱うデータの形が違い、スイッチではフレーム、ルータではパケットというデータの形を用いる。
IPアドレスが住所だとすると、MACアドレスは指名（本人）と考えると分かりやすい。
スイッチはLANを構成するために使用され、宛先のMACアドレスを見て振り分けを行う。VLANというネットワークをグループ分けする機能をもつ。

ルータは目的の相手と通信するために宛先のIPアドレスを見て判別する。直接的に接続されていない機器も識別でき、最適なルートの計算する。

### まとめ
ハブとスイッチでは、ハブが接続しているすべての機器にデータを転送しているのに対して、スイッチは特定の機器の間で通信を行うことができる。

スイッチとルータでは、スイッチがMACアドレスを識別しているのに対して、ルータはIPアドレスを識別している。各々の中継器ではエラーの検出や経路の決定が行われる。
BigQueryでstring_aggを利用するときは結果の再現性に注意しよう

# 概要

`string_agg`を利用した際に集計の再現性が取れずに詰まってしまったので、備忘のため掲載。

# 本題

`string_agg`は文字列値を結合して返す集計関数である。
グループ集計で利用する場合は以下のように扱う。

```sql:srting_aggの利用例
select
    corpus,
    word_count,
    string_agg(distinct word) as word_set
from `bigquery-public-data.samples.shakespeare`
group by 1, 2
```

ただし上記の場合、実行ごとに結合する値の順序が異なる。
それによって、結果が再現できず、後続の処理があると問題が生じる場合もある。

そのため、結果の再現性を持たせるため、order byで結合順を指定すると良い。

```sql:好ましい例
select
    corpus,
    word_count,
    string_agg(distinct word order by word) as word_set
from `bigquery-public-data.samples.shakespeare`
group by 1, 2
```

# 参考

- [STRING_AGGの仕様](https://cloud.google.com/bigquery/docs/reference/standard-sql/aggregate_functions?hl=ja#string_agg)
esxcli vsan storage diskgroup unmount コマンドについて

```
[root@localhost:~] esxcli vsan storage diskgroup unmount --help
Usage: esxcli vsan storage diskgroup unmount [cmd options]

Description:
  unmount               Unmount vSAN disk or disk group.

Cmd options:
  -d|--disk=<str>       Specify the hdd to unmount from vSAN usage.e.g.:
                        mpx.vmhba0:C0:T1:L0
  -m|--evacuation-mode=<str>
                        Specify an action to take upon unmounting the disk group
                        from vSAN (default NoAction).
                            EnsureObjectAccessibility: Evacuate data from the
                        disk to ensure object accessibility in the vSAN cluster,
                        before unmount the disk
                            EvacuateAllData: Evacuate all data from the disk
                        before unmounting it
                            NoAction: Do not move vSAN data out of the disk
                        before unmount it
                        Only valid with --ssd specified.
  -s|--ssd=<str>        Specify a disk group's fronting ssd to unmount the ssd
                        and each backing hdd from vSAN usage.e.g.:
                        mpx.vmhba2:C0:T1:L0
  -u|--uuid=<str>       Specify a vSAN UUID of the disk or fronting ssd to
                        unmount for use by vSAN.e.g.:
                        5291022a-ad03-df90-dd0f-b9f980cc005e
```
【備忘録】axiosでpostリクエストをしたときparamsがうまく取り出せない

小１時間ハマったのでメモ。

```react:React
const createUser = async () => {
    await axios
      .post(`${process.env.NEXT_PUBLIC_ENDPOINT}/admin/create_user`, {
        params: {
          nameSei: nameSei,
        },
      })
      .then((response) => {
        // 処理
         }
      })
      .catch(() => {
        //処理
      });
  };

```

このとき、ユーザー作成するため、Railsでストロングパラメーターを使おうと思い
`params.permit(:nameSei)`すると何故かストロングパラメーターが通らない。

色々な書き方を試しまくって、最終的に`params[:params].permit(:nameSei)`でいけることがわかった。
オンプレミス Oracle Database から Autonomous Database へデータベース・リンクを作成

本記事ではオンプレミス環境の Oracle Database から Autonomous Database へデータベース・リンクを作成する手順について説明します。ネットワーク的にオンプレミス・データベースから Autonomous Database へ直接接続できることを前提としています。

# Wallet の準備
  クライアントとなる Oracle Database にWallet をインストールします。Autonomous Database のホーム画面から「DB Connection」ボタンをクリックします。

![Wallet](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181284/b6ae075d-d5a7-14c4-0f32-2eb502ac3fc2.png)

「Download Wallet」ボタンをクリックします。
![Download](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181284/dce05c0f-f01f-f066-fc21-ce9183ac042e.png)

Walletのパスワードを指定して「Download」ボタンをクリックすると Wallet が zip ファイルとしてクライアントにダウンロードされます。

# Wallet の配置
ダウンロードした Wallet の zip ファイルを任意のディレクトリ内に展開し、そのディレクトリを環境変数 TNS_ADMIN に指定します。sqlnet.ora ファイルの DIRECTORY 項目を Wallet が保存されたディレクトリに変更してください。その後、データベース・インスタンスを起動します。

```SHELL:
$ export TNS_ADMIN=$HOME/wallet.atp
$ sqlplus / as sysdba

SQL*Plus: Release 19.0.0.0.0 - Production on 火 4月 12 13:18:53 2022
Version 19.12.0.0.0

Copyright (c) 1982, 2021, Oracle.  All rights reserved.

アイドル・インスタンスに接続しました。

SQL> STARTUP
ORACLEインスタンスが起動しました。

Total System Global Area 1577054664 bytes
Fixed Size                  8896968 bytes
Variable Size             989855744 bytes
Database Buffers          570425344 bytes
Redo Buffers                7876608 bytes
データベースがマウントされました。
データベースがオープンされました。
```

# DATABASE LINK の作成
  データベース・リンクの作成は CREATE DATABASE LINK 文を使います。下記の例では tnsnames.ora ファイルのエントリを使わずに直接接続句を記載しています。接続ユーザー名は Autonomous Database 管理者の ADMIN にしています。作成後に Autonomous Database 上のテーブルを検索しています。

```SQL:
SQL> CREATE DATABASE LINK cloud_link1 CONNECT TO ADMIN 
IDENTIFIED BY パスワード 
USING '(description= (retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1522)(host=adb.ap-tokyo-1.oraclecloud.com))(connect_data=(service_name=boofmainbg1vvmn_db000000000000_high.adb.oraclecloud.com))(security=(ssl_server_cert_dn="CN=adb.ap-tokyo-1.oraclecloud.com, OU=Oracle ADB TOKYO, O=Oracle Corporation, L=Redwood City, ST=California, C=US")))';

データベース・リンクが作成されました。

SQL> SELECT COUNT(*) FROM DATA1@cloud_link1;

  COUNT(*)
----------
    999998
```

# Data Pump ダンプファイルの転送を試す
  データベース・リンクが作成できたので、オンプレミスの Oracle Database 上にある Data Pump ダンプファイルを Autonomous Database のディレクトリ・オブジェクトに転送できるか試しました。結果としては以下のようにエラー（ORA-24444）が発生し、転送できませんでした。このため、オブジェクト・ストレージを使った移行手順が必要です。

```SQL:
SQL>  BEGIN
  2     DBMS_FILE_TRANSFER.PUT_FILE('DATA_PUMP_DIR', 'scott.dmp', 'DPDIR1', 'scott.dmp', 'CLOUD_LINK1');
  3   END;
  4   /
 BEGIN
*
行1でエラーが発生しました。:
ORA-24444: TTC RPC
(OFILXFR)はデータベース上で構成されているセキュリティ・ポリシーで許可されていま
せん
ORA-02063: 先行のエラー・メッセージを参照してくださいline(CLOUD_LINK1)。 ORA-06512:
"SYS.DBMS_FILE_TRANSFER", 行77
ORA-06512: "SYS.DBMS_FILE_TRANSFER", 行185
ORA-06512: 行2
```

このため Autonomous Database へのファイル転送は DBMS_CLOUD パッケージの PUT_OBJECT プロシージャを用いる必要があります。[公式](https://oracle-japan.github.io/ocitutorials/database/adb303-datapump/)で説明されている手順でファイル転送を行います。
IAMロールの作り方（Amazon SP-APIチャレンジ②）

2022/04/12 時点の情報です

# 前提

申請したチャレンジ①はこちら

https://qiita.com/kiwiiii/items/fd5ca0f94dad120c4d1d

上記画面からの申請で、大丈夫だったみたいで、Marketplace Developer Supportからメールが届きました。



>ご担当者様
>
>Amazon Selling Partner API（SP-API）開発者プロフィールを記入いただき、ありがとうございます。
>
>SP-APIへのアクセスリクエストが承認されました。 これで、リクエストしたロールに基づいて、SP-APIへのグローバルなマーケットプレイスアクセスが可能になります。
>
>
>SP-APIでは開発者IDを使用する必要はありません。開始するには、SP-APIを呼び出す権限のあるアプリケーションを登録するときに指定するIAMロールを作成する必要があります。SP APIセキュリティモデルではAWS認証情報が使用されるため、アマゾンウェブサービス（AWS）アカウントが必要になります。AWSカスタマーでない場合は、無料のAWSアカウントを作成できます。詳しくは、AWS無料利用枠をご覧ください。 https://aws.amazon.com/free/

AWS無料利用枠をどう使えば、IAMロールが作れるか、これだけではわからないので、調べながら実施してみます。



# IAMロールを作るために、AWSアカウントが必要
なぜかこれを理解できなくて、「なぜAWS無料利用枠が必要なのか？何をするために？」と困惑していました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627227/37fdad99-dd01-78e4-05d2-92422e0f5eca.png)

無料利用枠の検索ワードに「IAM」とかを入力するのではなく、右上の「サインアップを完了」をクリックする必要がありました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627227/ba3a3d84-92e0-a565-719d-58bec7e3f71c.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627227/7169af4c-6914-d865-657e-861a43d46ac8.png)

## 【公式】AWSアカウント作成
公式が手順書いてくれてました
https://aws.amazon.com/jp/register-flow/




AWSカスタマーになる＝AWSアカウントを作る　だそうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627227/8af0f71b-db85-89c6-56e6-7bfb3297ead3.png)

## メール届きました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627227/d0d10077-abcb-328e-ba3b-d77894599943.png)

## 公式の手順通り入力したら、作成できました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627227/6bea9bcb-bca0-e9a0-0240-73c124e722dc.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627227/0759a5b5-d006-d162-351b-fa20b24f01ac.png)

# ルートユーザでログインする
>まだサインインしていない場合は、AWSマネジメントコンソールにサインインし、console.aws.amazon.com/iamでIAMコンソールを開きます。

ログインは…ルートユーザでいいのか？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627227/00d39349-115d-6423-5cc5-95391af3065b.png)

メアド→画像認証→パスワード　と順に確認して、コンソールに到達！（ここまで2時間）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627227/e104d836-9fe4-9e96-f7a5-5e667647c96b.png)

サービスからIAMに行く、がわからなかったので検索
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627227/ff35d275-de69-e744-d876-21b66f438a4e.png)

# IAMでMFAを追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627227/4c9ca4a8-ce1d-a57b-b669-9f9396cafef4.png)

https://qiita.com/viptakechan/items/6d19aee635b2ab189e47


# 登録
ヘルプとこちらのサイトのおかげでIAM作成できた…？
コンソール到達してから、設定する箇所で1時間弱かかりました。
https://www.watchittrend.com/preparation-using-sp-api/


入力補助がけっこう追加されてたかも…

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627227/ab8d9d9f-b25e-93d0-43f7-a7ec0e928ab9.png)

続く。
AutoEncoderを理解する。(2022.4.12)

# 背景：いい加減ちゃんと理解した感じが欲しい
人工知能に関わる事象を全体的に振り返ろうと思いG検定の学習をし始めました。そこで、何回も目にしたことがあるAutoEncoderについての記述がありました。見るたびに思うのですが、いい加減、実装できるだろうと思い、いろいろ探して実装し、理解を深めました。
# 目的：およそ10年越しにAutoEncoderを理解します
# 結果：AutoEncoderを実装して、異常検知のメカニズムの理解が深まりました
# 構造：簡単なAutoEncoderの構造と動きを確認しました
具体的なコードは以下になります。また、[全体のコード](https://github.com/cedro3/others2/blob/main/autoencoder.ipynb)と合わせてご参照下さい。
```Python
encoded = Dense(encoding_dim, activation='relu')(input_img)
decoded = Dense(784, activation='sigmoid')(encoded)
autoencoder = Model(input=input_img, output=decoded)
autoencoder.compile(optimizer='adadelta', loss='binary_crossentropy')
```
これを図示すると以下の様になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2496939/da38f50c-2597-8142-3047-0d3174a06129.png)
この図は入力が784次元のデータを32次元に圧縮している事を表しています。そして、圧縮した物は潜在変数Zとします。その後、潜在変数Zは再び784次元に復元されます。復元されたデータは入力したデータと比べて、損失を算出します。損失が小さくなるように学習を繰り返し、重みを最適化していきます。今回の損失関数はbinary_crossentropyで最適化にはadadeltaを使っています。

# 方法
cedro3さんのコードを使わせて頂きました。また、ソニーの小林さんの解説動画[「実践Deep Learning：Autoencoderを用いた教師なし異常検知」](https://www.youtube.com/watch?v=vFpZrxaq5xU)も大変参考になりました。
# 感想：深層生成モデルの理解に向かって進んでいる気がします
10年前は全く意味不明だったAutoEncoderでしたが、現在、明確な実感と共に理解した感じがあります。当時、松尾先生が言っていた事で意図が汲み取れないものもありますが、今回理解した事を元に進める感覚があります。また、この記事を書く時に調べたものにVAE(Variational Auto Encoder)があります。今回の物と何が違うのかというと、「潜在変数Zに確率分布を想定するかどうか」くらいしか分かっていません。次回は、確率分布を想定する事でどうなるのかまで理解できればと思っています。そこまで理解が進むと去年やっただけに終わった深層生成モデルの理解にも進めそうな気がしています。
# 参考
1. 小林(2020.4)、[実践Deep Learning：Autoencoderを用いた教師なし異常検知](https://youtu.be/vFpZrxaq5xU)：工学的な解説
1. cedro(2020.4)、[Keras AutoEncoder で異常検知をやってみる](http://cedro3.com/ai/keras-autoencoder-anomaly/)
1. cedro(2020.4)、[Keras AutoEncoder で異常検知をやってみる(colab)](https://github.com/cedro3/others2/blob/main/autoencoder.ipynb)

# 次回の記事
[Variational AutoEncoder【PyTorch】を簡単に理解する。（2020.4.14）](https://qiita.com/tan0ry0shiny/items/d39ba293e0b44d9ed28c)
カスタムオブジェクトレコードに大量のメールを送信できますか？

Apexでコードを書いてもカスタムオブジェクトでは不可能だというのが、私にの認識でした。

しかし、フローで強引にやればできるようなことが回答されていました。

+ [Can I send mass emails to custom object records?](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000Gf1VW)

しかし、今の私にはできないですね。

[Sending emails to multiple users using flows(Salesforce)](https://stackoverflow.com/questions/69491139/sending-emails-to-multiple-users-using-flowssalesforce)
sfdx force：data：soql：queryは、認識されない内部または外部コマンドエラーを返します


[sfdx force：data：soql：queryは、認識されない内部または外部コマンドエラーを返します](https://developer.salesforce.com/forums/?id=9060G0000005TUGQA2)

これが影響しているかもしれません。

[Can't create sample data with CLI](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000FRYgDSAX)

CLIに入力されているデータの値のスペースにあるようです。たとえば、（sfdx force：data：record：create -s Account -v "Name = Marriott"）は、レコードを適切に作成します。ただし、（sfdx force：data：record：create -s Account -v "Name = Marriott Marquis"）および（sfdx force：data：record：create -s Account -v "Name ='Marriott Marquis'"）はエラーをトリガーします。
非同期処理　自分の為の議事録

### Promise について

非同期処理時の結果を保持するやつ!（一言で言うと）
結果は 3 つ種類ある

- 「Pending」 ：初期の状態、または処理待ち
- 「Fullfilled」 ：処理が成功して完了
- 「Rejected」：処理が失敗した

この 3 つの状態を処理していく事ができる！

### Promise の生成方法

```js
// 脳死
let something = new Promise(function (resolve, reject) {
  // something code
});

// アロー関数使用（イケイケ？）
let something = new Promise((resolve, reject) => {
  // something code
});
```

### then メソッド

処理が成功して完了した時、もしくは処理が失敗した時の状態を受け取る

- 「Fullfilled」：処理が成功して完了 (resolve)
- 「Rejected」：処理が失敗 (reject)

以下に例文を記載

```js
const validation = (password) => {
  return new Promise((resolve, reject) => {
    if (password.length >= 10) {
      resolve({
        password: password,
      });
    } else {
      reject("パスワードは10文字以上で入力してください");
    }
  });
};

let password = "1234567890";

validation(password).then(
  (result) => console.log(result), //バリデーションが成功した時の処理（resolve）
  (error) => console.log(error) //バリデーションが失敗した時の処理(reject)
);
```

```
// 実行結果
{ password: '1234567890' }
```

- resolve の時
  この時は password の文字列が then の引数である result に渡される

- reject の時
  この時は reject 内で記述した文字列が then の引数である error に渡される

### catch メソッド

rejected ステータスを受け取る
エラー時専用メソッド！
以下に記載例

```js
const something = new Promise((resolve, reject) => {
  reject("Faild");
}).catch((error) => console.log(error));
```

### Promise チェーン（最後の内容）

処理が成功した際、処理が失敗、さっきのエラーが出た際に結果だけ見るなんてほぼない！
何かの処理を続けたりするのが多い（気が s..）
そんな時にチェーンで記述すれば次の制御を記述する事ができる！

```js
const something = new Promise((resolve, reject) => {
  reject();
})
  .then(() => {
    // resolveの時
    console.log("resolve");
  })
  .catch(() => {
    // errorの時
    console.log("error");
  })
  .then(() => {
    //rejectの時
    console.log("reject");
  });
```

```
// 実行結果
error
reject
```

今回は reject されたから rejected ステータスを受け取る catch と then の 2 つ目が反応する。
これをうまく使えればいいね〜

###　まとめ
3 つの状態毎に処理を記載できる！

```
・Promiseはステータスによって処理を制御する
・fullfilledとrejectedステータスのPromiseオブジェクトを受け取るthenメソッド
・rejectedステータスのPromiseオブジェクトを受け取るcatchメソッド
```

以上！解散！！
WSL2にUbuntuインストールしてtftpサーバーとして動作させたいのでメモ。

それでまずデフォルトでインストールしても
networkが有効では無いのをどうにかしたいです……


インストール方法は
色々やったけど
MS　STORE　を”ここに入力して検索”に入れて
出てきたMS　STOREにUbuntuを検索して出てきたものを
選択してインストール。

インストール終わってユーザー名test　パスワードtest
とかしてとりあえずアップデートをしようとして
sudo apt update
でアップデートが出来なくて止まりました……

どなたかWSL２上のUbuntuでnetworkを有効にする方法をご助力頂けないでしょうか？
FlowからのInvocable ApexのDebug Logの作り方

# Flowから呼び出したApexクラスのDebugをしたいとき
- テストクラス作るのは面倒な時
    - そもそもCollection変数とかを渡した時にどんな変数が来ているのか想像つかない
- サクッとできるはずのApex Classなのに想像以上にハマってしまう時

## 設定からDebug Logを作成するようにする
- デバッグログを下記の通りに設定する
    - 追跡対象エンティティ種別: `ユーザ`
    - 追跡対象エンティティ名: `Flowを実行するユーザ`
    - デバッグレベル: Apex Codeを最も詳細にしておく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/484310/25a34ff8-1fd8-2427-641f-d9bfec198f67.png)

- フローでデバッグする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/484310/7de63e81-820d-a802-31ef-07d75ca254fc.png)

- デバッグログページを更新する
    - これで演算子が `/aura` のログが作成されているはず。 (Class名とか出たらいいんだけど、、知ってる人いたらご教示ください。) 

- 上記で更新されないこともしばしばある。そんな時は開発者コンソールを開いて`Logs`タブを確認。そうすることでリアルタイムにDebug Logが作成されるので対象ログを探す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/484310/516f5b8e-f59f-ec1c-6181-07111872ee5f.png)



## 対象のデバッグログを突き止めたら:
- VSCodeからもDebugのReplayができます。
    - `SFDX: Toggle Checkpoint` にてチェックポイントをつける
    - `SFDX: Update Checkpoints in Org`で組織側にチェックポイントを同期
  - `SFDX: Turn On Apex Debug Log for Replay Debugger`でデバッガーをStartさせる
  - `SFDX: Get Apex Debug Logs`で対象のログを確認 (上記例だと`/aura`で検索すれば早い)
  - `SFDX: Launch Apex Replay Debugger with Current File` これでデバッグが開始できるので、各変数の中身を確認できる。

上記の手順は最初面倒過ぎましたが、何度もやってると慣れますw

## 参考 (英語)
https://metillium.com/2021/04/log-flow-messages-to-debug-logs/
metabaseの操作で参考になったサイト

[【Metabase】『カスタム質問』（CustomQuestion）の使い方・実行手順【データ可視化・BIツール】](https://getech-lab.toniemon.com/metabase-custom-question/)
データベースのデータ操作をするための、カスタム質問についてシンプルに説明されています。

[簡単・便利！オープンソースのデータ分析ツール「Metabase」](https://blg.dai-it-system.com/2021/12/metabase/#)
システム構成からDockerを利用したmatabaseの環境構築、データ可視化の作成方法を例を使って説明されています。


[MetabaseにあるQuestion（チャート・グラフ・テーブル）の可視化種類のまとめ](https://qiita.com/suzuki-navi/items/c1ee94d66e77d2dbfdcb)
metabaseで可視化できるグラフの種類について、まとめられています。

[Native query has 2000 limit even for aggregated data #12729](https://github.com/metabase/metabase/issues/12729)
Metabaseを利用したとき、１つのデーブルのRowの行数が2000行までしかグラフに反映できないそうです。
How to get the group members user details (Like user id, username) from Data loader?


+ Create an Apex class.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/419b7c98-59bd-06f4-6ab0-fce4a3c3096f.png)

+ The Apex class name is getUserListClass.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/f327e9cc-a71f-d5a1-ce3e-390e437f362a.png)

+ Copy and paste the following.

```
public class getUserListClass {
    
    public static List<User> getUserList(String GroupId){
        List<GroupMember> GroupMemberList1 = [SELECT Id, GroupId, UserOrGroupId, Group.Name FROM GroupMember WHERE Group.Id =: GroupId ];
        
        Set<Id> UserIdSet = new Set<Id>();
        Set<Id> GroupIdSet1 = new Set<Id>();
        Set<Id> GroupIdSet2 = new Set<Id>();
        Set<Id> GroupIdSet3 = new Set<Id>();
        
        for (GroupMember GM1 : GroupMemberList1) {
            String id_str = (String)GM1.UserOrGroupId;
            if (id_str.left(3) =='005') {
                UserIdSet.add(GM1.UserOrGroupId);
            } else {
                GroupIdSet1.add(GM1.UserOrGroupId);
            }
        }
        
        if ( GroupIdSet1.size() >0) {
            
            List<GroupMember> GroupMemberList2 = [SELECT Id, GroupId, UserOrGroupId, Group.Name FROM GroupMember WHERE Group.Id =: GroupIdSet1];
            for (GroupMember GM2 : GroupMemberList2) {
                String id_str = (String)GM2.UserOrGroupId;
                if (id_str.left(3) =='005') {
                    UserIdSet.add(GM2.UserOrGroupId);
                } else {
                    GroupIdSet2.add(GM2.UserOrGroupId);
                }
            }
            
            if ( GroupIdSet2.size() >0) {
                List<GroupMember> GroupMemberList3 = [SELECT Id, GroupId, UserOrGroupId, Group.Name FROM GroupMember WHERE Group.Id =: GroupIdSet2];
                for (GroupMember GM3 : GroupMemberList3) {
                    String id_str = (String)GM3.UserOrGroupId;
                    if (id_str.left(3) =='005') {
                        UserIdSet.add(GM3.UserOrGroupId);
                    } else {
                        GroupIdSet3.add(GM3.UserOrGroupId);
                    }
                }
            }
            
        }
        
        List<User> UserList = new List<User>();
        if( UserIdSet.size() >0) {
            UserList = [SELECT Id FROM User where Id =: UserIdSet];
        }
        
        return UserList;
        
    }
}
```

+ Open excute anonymous window

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/ff19b847-d0d9-ada9-9b3e-5280597e1b88.png)


Use 18 digit Id

```
List<User> UserList = getUserListClass.getUserList('00G2x000000uOKDEA2');
IF(UserList.size() >0 ){
    for (User u : UserList){
        system.debug(Logginglevel.INFO,'-- List -->  '+ u.Id );
    }
}
```

+ Final result

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/4a99904e-da5c-ef3e-de7e-4021026c7842.png)
Slackで所属channel一覧を出すsnippet

# 背景
チームにjoinするメンバーに自分が入ってるchannel一覧を伝えたいです。
APIで取得しようとすると、直接とるAPIがなく、後述するようにコストが高いです。
したがってブラウザのDOMからそのまま抜き出すのがシンプルだと考えました。

# js snippet
slackのウェブページにて、下記をchrome consoleに入れて実行します

```
Array.from(document.querySelectorAll(".c-virtual_list__scroll_container div.p-channel_sidebar__static_list__item")).filter(x => x.firstChild.className == 'p-channel_sidebar__channel').map(x => `#${x.innerText}`)
```

※public channelとprivate channelの両方を取得します

# APIでやるなら
https://api.slack.com/methods/conversations.list#markdown

上記を要約すると、
https://api.slack.com/methods/conversations.info
にてすべてのpublic channelを取得した後に、
https://api.slack.com/methods/conversations.members
をchannelごとに呼び出し、自分が入っているかどうかを判定する必要がありそうです。
Gmailで取得したメールに条件を付け判断してチャットワークに自動投稿する

例えばドメインやSSL更新のメール受信だけに頼ってる場合他の営業メールなどに埋もれてしまい抜けやすいのと、
毎度メールチェックするのもめんｄ・・工数かかるので、更新メールが来たらさくっと共有して事務とのやり取り行うように
GAS使ってメール監視するようにした。

# チャットワークAPIキーを確保（１）
チャットワークアカウント事に[APIキーを取得](https://help.chatwork.com/hc/ja/articles/115000172402-API%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%82%92%E7%99%BA%E8%A1%8C%E3%81%99%E3%82%8B)できるので事前に取得しておく。

# チャットワークで投下したいスレのIDを確保（２）
URLの末尾に「!rid00000000」って記載されてる数字の部分。

# GASでコード作成
[google app script](https://script.google.com/home)で新規プロジェクトでコード作成。

## ライブラリを追加
ChatWorkClient for Google Apps Scriptというライブライを追加します。
これを追加することでチャットワーク系の関数を利用できるようになります。
「ライブラリを追加」をクリックしスクリプトIDに下記を入力
```
1nf253qsOnZ-RcdcFu1Y2v4pGwTuuDxN5EbuvKEZprBWg764tjwA5fLav
```
検索するとChatWorkClientがヒットするので最新バージョンを追加して追加をクリック。
すると左ナビのライブラリの下にChatWorkClientが表示されるのでこれでOK

## コード記載

脳死で利用するならCW_TOKENに（１）を、CW_ROOMに（２）を記載。
msgbodyはそのまま利用すればto all宛てに検索対象としたメール件名と本文をinfoタグでくくった状態のものが自動投下される。
チャット投下されるのはAPIキーを取得したアカウントから発言する形になります。

```
function mailCheckDomain() {
  //チャットワークトークン・ID
  const CW_TOKEN = "xxxxxxxx"; // チャットワークAPIキー
  const CW_ROOM = "YYYYY"; // チャットワークの投下したいスレID

  //Gmailから特定条件のスレッドを検索しメールを取り出す
  var strTerms = 'subject:ドメイン有効期限 OR ドメイン登録期限 OR 利用ドメイン'; // 検索したいメール条件
  var myThreads = GmailApp.search(strTerms, 0, 20); //条件にマッチしたスレッドを取得
  var myMsgs = GmailApp.getMessagesForThreads(myThreads); //スレッドからメールを取得する→二次元配列で格納

  //チャットワークAPI
  var client = ChatWorkClient.factory({
    token: CW_TOKEN
  });
  Logger.log(myMsgs);
  //各スレッド×メール
  for (var i = myMsgs.length - 1; i >= 0; i--) {
    var msgsInThread = myMsgs[i];
    for (var j = 0; j < msgsInThread.length; j++) {
      var msg = msgsInThread[j];

      //未読のみ
      if (msg.isUnread()) {
        //メールを既読にする
        msg.markRead();

        //メッセージ作成
        var msgBody = "[toall]" +
                      "[info]" +
                          "[title]" + msg.getSubject() + "[/title]" +
                          msg.getFrom() + "[hr]" +
                          msg.getPlainBody().slice(0,700) + "[hr]" +
                          msg.getDate() +
                      "[/info]";

        //チャットワークに送る
        client.sendMessage({
          room_id: CW_ROOM,
          body: msgBody
        });
      }
    }
  }
}

```

# 注意点
これは対象のメールで「未読なもの」をあえて対象にして、対象としたものを「既読とする」ように仕込んでます。
こうすることで基本受信したメールは目視することなくチャットワークの特定すれに投下される形になります。
Gmailでこれが発火する前に既読にしてしまった場合は対象外になるので注意です。
ウチは該当メールをフィルタで受信トレイスキップしてラベルつけて別管理してGmail上では基本確認しないようにしてます。


といった形でたまたま現状利用してるのがチャットワークだったのでその例を挙げましたが、
GAS使って旨い事すればslack投下だろうが、スプシに記載とか何とでもできるとは思いますがその辺は割愛。
Yahoo JapanのOauthでエラー


# エラー内容
```bash
exceptions.YahooOauthError: [
    Yahoo API Error]endpoint:https://userinfo.yahooapis.jp/yconnect/v2/attribute status_code:403 
    message:{"error":"invalid_request","error_description":"Client is not allowed"}
```

# 原因
[デベロッパーネットワークのアプリケーションの管理](https://e.developer.yahoo.co.jp/dashboard/)で、 **属性取得APIで追加して取得する情報** が有効になっていない。


# 対応
**属性取得APIで追加して取得する情報** を有効にする。
![スクリーンショット 2022-04-07 21.15.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50056/5c5fe86e-5f47-4a32-0e87-435b2c599c4f.png)
【パブリッシャー】レポートの保存/読込みをしてみる

[Sharperlight](https://sharperlight.jp/)パブリッシャーには、公開クエリをファイルとして保存したり、そのファイルを読み込む機能が備わっています。早速使ってみます。
[Sharperlight](https://sharperlight.jp/)アプリケーションメニューから**パブリッシャー**を起動します。
右クリックメニューを開き、エクスポート/インポートのサブメニューを開きます。
現在選択中の公開レポートを保存する場合は、**保存**を、既にファイルとして保存されている公開クエリを読み込む場合は、**読込み**を選択します。
![2022-04-12 Figure 01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/c262d9b7-fe6a-06e1-eb19-9c6f714b24bd.png)
**保存**を選択した場合は、**パブリッシャーを保存**ダイアログが表示されるのでフォルダを選択し、名前を付与して保存します。拡張子は、**.pbq**となります。
**読込み**を選択した場合は、**読込み**ダイアログが表示されるので、拡張子 **.pbq**のファイルを選択し読込みます。
:postbox:[Sharperlight](https://sharperlight.jp/)
Laraveのセッションのデータベース利用【個人的なお勉強アウトプット】

## 参考図書
https://www.amazon.co.jp/dp/B07CLLW4MX/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1

## ファイル修正
```config/session.php
'driver' => env('SESSION_DRIVER', 'database'),
```

```.env
SESSION_DRIVER=database
```

## セッション用のテーブル作成
セッション用のテーブルは使用が決まっていて、それに従った形で用意しなくてはならない。
`php artisan session:table`

セッション用テーブルはsessionsという名前で、id,user_id,ip_address,user_agent,payload,last_activityというフィールドがある。
これらの情報がセッションを確立するために必要
STM32CubeMX を M1 Macにインストール

ダウンロードしたパッケージにjreが同梱されていますが、セキュリティバイオレーションでjavaが起動できないのでjreを削除して、OSにインストールされているjreを利用します。

```shell
ln -s `echo $JAVA_HOME` jre
```

これで　SetupSTM32CubeMX-6.5.0.app が起動できます。
Laraveのセッション利用【個人的なお勉強アウトプット】

## 参考図書
https://www.amazon.co.jp/dp/B07CLLW4MX/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1

## セッションとは？
クライアントとサーバーの接続維持のための仕組み。
例えば、ログインしている状態の保持、カート情報の保持とか

もともとWebで使われている技術は連続した接続を考えていない。
それを、クッキーとデータベースを利用して実現している。
クライアントごとに異なるIDをクッキーとして保管する（セッションID）。
そのセッションIDに関連付けてデータベースに保存する。
セッションから情報を取り出すときは、クライアントのセッションIDをつかってデータベースからデータを検索して取り出している。

## Laravelのセッション利用
クッキーとデータベースを組み合わせてセッション管理をするのが基本。
Laravelはデータベースの他に、ファイルやメモリキャッシュなどをつかってセッションを保存する手段をもっている。
デフォルトではファイルの利用。とはいえ本格稼働時にはデータベースにしたほうがよい。
ファイルだと、クライントごとに作成されて数が膨大になるし、セッションごとに異なるファイルを読み書きするため、処理速度もそれほど速くない。

## セッション操作の基本
### 値の保存
`<Request>->session()-put(キー,値)`

### 値の取得
`$変数 = <Request>->session()->get(キー);`

## 実例
フォームからテキストを送信するとセッションに保存して、保存された値を`session_data`に表示する
```resources/views/hwllo/session.blade.php
@section(`content`)
<p>{{$session_data}}</p>
<form action="/hello/session" method="post">
@csrf
<input type="text" name="input">
<input type="submit" name="send">
</form
@endsection
```

```app/Http/Controllers/HelloController.php
public function ses_get(Request $request){
$ses_data = $request->session()->get('msg');
return view('hello.session', ['session_data' => $sesdata]);
}

public function ses_put(Request $request){
$msg = $request->input;
$request->session()->put('msg', $msg);
return redirect('hello/session');
}
```

ルート情報の記載
```routes/web.php
Route::get('hello/session', 'App\Http\Controllers\HelloController@ses_get');
Route::post('hello/session', 'App\Http\Controllers\HelloController@ses_put');
```
Rでデータフレームを複製し、同一列に異なる情報を載せて結合させる

## やりたいこと
Rで
| ID | Intention（T1） | Competency（T1） | Intention（T2) | Competency（T2） |
|:-:|:-:|:-:|:-:|:-:|
| 1 | 4 |  1 | 5 |  2 |
| 2 | 3 |  3 | 3 |  4 |
| 3 | 2 |  4 | 3 |  3 |

となっているデータフレームを

| ID | Intention(T1) | Competency(T1)| Intention（T2) | Competency（T2） | 調査タイミング |
|:-:|:-:|:-:|:-:|:-:|:-:|
| 1  |  4 | 1  |  5 | 2  |  1 |
| 1  |  4 | 1  |  5 | 2  |  2 |
| 2  |  3 | 3  |  3 | 4  |  1 |
| 2  |  3 | 3  |  3 | 4  |  2 |
| 3  |  2 | 4  |  3 | 3  |  1 |
| 3  |  2 | 4  |  3 | 3  |  2 |

にしたい

:::note info
T1,T2 は調査タイミングのことを指します。
:::

## 背景
- R で DID（差の差分析）を行うために、調査タイミングの情報を載せたデータを作成したい
- 経済系の分析ではそもそもデータフレームに調査期間に関する列があるためこの作業を行う必要はないが、心理や教育系だとそうではないケースもあるらしい

## コード (RStudio Cloud)
やっていることは、もとのデータセットを2つコピーして、それぞれ同一名の列を追加し、異なる値を代入した後結合させるということです。
``` R
# もととなるデータをコピー
## T1（調査タイミング1）のデータとみなして作成
test.1 <- test　#コピー
test.1$wave <- NA 
test.1$wave <- 0 #wave列に0を代入

# test.1 をコピー
## T2（調査タイミング2）のデータとみなして作成
test.2 <- test.1　#コピー
test.2$wave <- NA
test.2$wave <- 1 #wave列に1を代入

# test.1 と test.2 を結合
test.bind <- rbind(test.1, test.2)
```
:::note info
RStudio Cloud を用いています。
:::

## 追記(2022/04/13)
本記事にいただいたコメントにて、**RStudio Desktop** や **base-R** では新しい列を追加する際に最初に NA を入れる必要がないとご指摘をいただきました。そのため、 RStudio Cloud 環境以外の方は下記コードで同じ結果が得られるかと思います。WolfMoonさま、ご指摘いただきありがとうございました。

``` R
# もととなるデータをコピー
## T1（調査タイミング1）のデータとみなして作成
test.1 <- test　#コピー
# test.1$wave <- NA #不要
test.1$wave <- 0 #wave列に0を代入

# test.1 をコピー
## T2（調査タイミング2）のデータとみなして作成
test.2 <- test.1　#コピー
# test.2$wave <- NA #不要
test.2$wave <- 1 #wave列に1を代入

# test.1 と test.2 を結合
test.bind <- rbind(test.1, test.2)
```

### 参考
http://nmizojp.blogspot.com/2014/10/r.html

https://bioscryptome.t-ohashi.info/r/dataframe-bind/
PHPのexec関数でエラーメッセージを取得する

PHPの[exec関数](https://www.php.net/manual/en/function.exec.php)では返り値や引数でコマンドの出力を取得できるが、エラーは取得できない。
```php
// 存在しないディレクトリをlsする.
// $resultと$outputともに空
$result = exec('ls my-directory', $output);
```
なぜかというと、**execコマンドで拾えるのは標準出力からの出力のみ**で、エラーの場合たいてい標準エラー出力からの出力になるため。エラーを拾うには最後に`2>&1`をつけて標準エラー出力の内容を標準出力にリダイレクトする。
```php
$result = exec('ls my-directory 2>&1', $output);
```
```
// $result
"ls: cannot access 'my-directory': No such file or directory"

// $output
[
     "ls: cannot access 'my-directory': No such file or directory",
   ]
```

`2`は標準エラー出力、`1`は標準出力を指すファイルディスクリプタで、`2>1`だと`1`がファイル名だと解釈されるので`&`を付ける。

## 参考
https://stackoverflow.com/questions/345794/how-to-retrieve-php-exec-error-responses
https://stackoverflow.com/questions/818255/in-the-shell-what-does-21-mean