OmniAICreator/Qiita-1.07M huggingface dataset:
Power Automateを利用して一斉送信のメールアドレスを管理する

こんにちは。
デジタルツールを使用して業務改善を目指しているデジタル初心者です。
小売業に勤務していますが、今はお店ではなく裏方の事務仕事をしています。
日々の業務の中にには毎週同じ作業を繰り返していることが多々あります。少しでも効率化出来ないかと
いうことで、今回は **RPA** にチャレンジします。

## powerAutomateを使ってExcelのメールアドレスリストへ添付フィル付きのメールを一斉送信する
実際の作成物はこちらです。

https://twitter.com/wi80L3bJzscufZJ/status/1701239341001920800



## 作成の経緯
同僚Uさんという部署内で事務的な業務を担うベテラン社員ですが、パソコン操作はあまり得意ではない方がいます。今の業務歴は5年くらいで、慣れたパソコン操作は問題ありませんが、新しいことも求められると戸惑ってしまうようでそんな時は質問を受けたりしています。
Uさんは週1回、倉庫の在庫データと販売データをまとめたファイルを関係者に一斉送信しています。送信先も多いうえに（宛先は80名程度いるようです。）、人事異動などにより宛先の追加・削除が定期的に発生します。人事異動自体は年2回と頻度は決して多くありませんが、担当の変更で発生する変更人数が1回あたり多いときで15～20人発生しています。
その上で不定期で「この人も宛先に追加して」「この人退職したから宛先から外して」
という依頼が月に2～3件は発生するようです。
その度にUさんは宛先が多すぎて
<font color="Red">**「誰を追加・削除しているんだか段々わからなくなってきた！」**</font>
と時々叫んでいます。
結局正しいリストに修正完了するまで
<font color="Red">**「削除依頼したのにまだメールが来る」**</font>
<font color="Red">**「頼んだのにまだメールが来ない」**</font>
などで3週間はかかっているとのことでした。
そんなUさんの助けになればと想い作成に取り組みました。

**作成したツールは【PowerAutomate Desktop】を使用しました。**

フローは以下の通りです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3485813/ba8ca690-0a8d-ec66-8740-beb036b20696.png)

ソースコードはこちらです。
```
SET MailAccount TO $'''------@-----'''
Folder.GetSpecialFolder SpecialFolder: Folder.SpecialFolder.DesktopDirectory SpecialFolderPath=> SpecialFolderPath
Excel.LaunchExcel.LaunchAndOpenUnderExistingProcess Path: $'''C:\\Users\\992058\\Desktop\\研修②\\一斉送信用メールアドレスリスト.xlsx''' Visible: True ReadOnly: False Instance=> ExcelInstance
Outlook.Launch Instance=> OutlookInstance
Excel.GetFirstFreeColumnRow Instance: ExcelInstance FirstFreeColumn=> FirstFreeColumn FirstFreeRow=> FirstFreeRow
LOOP LoopIndex FROM 2 TO FirstFreeRow - 1 STEP 1
    Excel.ReadFromExcel.ReadCell Instance: ExcelInstance StartColumn: $'''A''' StartRow: LoopIndex ReadAsText: False CellValue=> ExcelData
    Excel.ReadFromExcel.ReadCell Instance: ExcelInstance StartColumn: $'''B''' StartRow: LoopIndex ReadAsText: False CellValue=> ExcelDataAddress
    Outlook.SendEmailThroughOutlook.SendEmail Instance: OutlookInstance Account: MailAccount SendTo: ExcelDataAddress Body: $'''いつもお世話になっております
研修用のテストメールを送信いています
お手数をおかけしますがご了承お願いいたします

''' IsBodyHtml: False Attachments: $'''C:\\Users\\999999\\Desktop\\研修②\\一斉送信用メールアドレスリスト.xlsx'''
END
Excel.CloseExcel.Close Instance: ExcelInstance
Outlook.Close Instance: OutlookInstance
```

**[SET MailAccount TO $'''------@-----''']**　のところにはメールアドレスが入ります。
**[ ''' IsBodyHtml: False Attachments: $'''C:\\Users\\999999\\Desktop\\研修②\\一斉送信用メールアドレスリスト.xlsx''']**　
の999999は社内PCのアカウント名のため文字修正しています。

## 実際に使ってもらったUさんの反応

Uさんに実際に使ってもらった感想を聞いてみました。


- 送信先をエクセルで管理して送信できるのは便利で助かる（◎）
- 送信が一人に付き1回で、人数分繰り返されるのは送信済トレイが同じメールで一杯になって不便（×）
- ファイル添付まで自動でできるのは助かるけど、ファイルの作成も自動でやってくれたらもっと助かるんだけど・・・（課題）

Uさんのフィードバックをまとめると下記のようになります。
- 私の作成したフローでは1回あたり1名のメール送信のため、送信作業が80回繰り返していまい、<font color="Red">**【一斉送信ではない】**</font>ものになってしまった
- Uさんの毎週のルーチンは①倉庫データの作成のためのデータ抽出（複数のシステム）②データをまとめたエクセルファイルの作成③作成したファルの一斉送信で、私のフォローは③の宛先管理と、<font color="Red">**Uさんの一連の作業の一部改善にとどまったものでしかできなかった**</font>
-
まだまだ手放しで喜んでもらえるレベルにはほど通りと認識しました。

### 次へのステップ
Uさんのリクエストにもあるように、添付するエクセルファイルも毎週同じ作業の繰り返し（更新）なのでエクセルの自動化にもチャレンジしていきたいと思います。
Salesforce のファイルをダウンロードする Python コード (Simple Salesforce 利用)

## 背景
Salesforce のファイルを外部から取り出したい、と言う要望はままあるのですが、Python ライブラリの Simple Salesforce を活用した実装の参考例です。

https://github.com/simple-salesforce/simple-salesforce

ダウンロードしたいファイルの ContentVersion レコードの Id がわかるならば手っ取り早いのですが、往々にして ContentDocumentId しかわからない事が多いので、ContentDocumentId から紐解く処理にしています。



:warning: エラー処理を全く考慮しておらず、そのまま業務使用することは想定しておりませんので、あらかじめご了承ください。

## 環境
* pip 追加インストール
    * python-dotenv==1.0.0
    * requests==2.31.0
    * simple-salesforce==1.12.5
* python 3.11.5

## コード
まず```.env```ファイルを作成し、Salesforce にログインするユーザー名とパスワードを設定します。(変数名はコード内を参照)
また、次のコードの最初にある contentDocumentId にダウンロードしたいファイルの ContentDocumentId をセットしてください。

```python
# ダウンロードしたいファイルの ContentDocumentId をセットします
contentDocumentId = '[対象ファイルの ContentDocumentId]'

# .env の Salesforce のユーザー名/パスワードを環境変数化
from dotenv import load_dotenv
load_dotenv('./.env')

import os
import requests
from simple_salesforce import Salesforce

# 環境変数から Salesforce のユーザー名/パスワードを読み込みセット
SALESFORCE_USERNAME = os.environ.get('SALESFORCE_USERNAME')
SALESFORCE_PASSWORD = os.environ.get('SALESFORCE_PASSWORD')

# Salesforce へログイン
sf = Salesforce(username=SALESFORCE_USERNAME,password=SALESFORCE_PASSWORD, security_token='')

# 該当する ContentVersion のレコードを取得
query = f"SELECT Id, PathOnClient FROM ContentVersion WHERE isLatest = True AND ContentDocumentId = '{contentDocumentId}'"
results = sf.query(query)

# ダウンロード用の URL を組み立て
url = f"https://{sf.sf_instance}{results['records'][0]['attributes']['url']}/VersionData"
print(url)

# ファイル名をセット
fileName = results['records'][0]['PathOnClient']
print(fileName)

# requests を使ってファイルを取得
response = requests.get(url=url, headers={'Authorization': 'OAuth ' + sf.session_id, 'Content-Type': 'application/octet-stream'})

# 成功すれば実行フォルダにファイルを作成
if response.ok:
    with open(fileName, 'wb') as f:
        f.write(response.content)

```
ちなみに、対象ファイルの ContentDocumentId は URL から見つけるのが手っ取り早いです。(069 から始まる 18 桁の Id)
![ContentDocumentIdの見方.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535779/60e95e0c-3310-334d-c44e-27e6e746740f.png)

## 実行結果
実行環境にもよりますが、次のように実行フォルダにファイルが生成されていれば成功です。
![SimpleSalesforceFileDownload.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535779/165b1e30-9d25-dd5a-6233-502abb969a0d.png)

応用する事で、特定のレコードに添付されたファイルをすべてダウンロードしたりもできるようになるでしょう。
以上、Salesforce のファイルをダウンロードする Python コード (Simple Salesforce 利用)、でした。
IMEのリランカでGPTが使えるか試してみる

# はじめに
Rinna から提供されている gpt モデルを使って遊んでみています。
[Rinna Gpt2 モデルを onnx データにしたので](https://qiita.com/shinjimorimitsu/items/b61aa693f8e2988c8590)、これをIME(かな漢字変換)に応用できるか試してみます。今回はリランカで使ってみることを想定します。

(もちろん、入力の続きを生成するのが、もっとも単純に思いつく応用ですが、それは至極当然なので…)

# リランカ (Reranker) って?

[日本語入力を支える技術](https://www.amazon.co.jp/%E6%97%A5%E6%9C%AC%E8%AA%9E%E5%85%A5%E5%8A%9B%E3%82%92%E6%94%AF%E3%81%88%E3%82%8B%E6%8A%80%E8%A1%93-%E2%80%95%E5%A4%89%E3%82%8F%E3%82%8A%E7%B6%9A%E3%81%91%E3%82%8B%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF%E3%81%A8%E8%A8%80%E8%91%89%E3%81%AE%E4%B8%96%E7%95%8C-WEB-PRESS-plus-ebook/dp/B07JHN88S7/ref=tmm_kin_swatch_0?_encoding=UTF8&qid=1694427727&sr=8-1) の P.245 のリランキングのフェーズで使ってみようということです。つまり単語グラフを作って2単語接続情報からバックワードビタビとフォワードA*で、Nベストを作り、それの評価機として使うということです。このフェーズだと、とんでも候補はに除外されている前提です。

# 何を計算するのか

GPTの出力の logits には、次トークンだけではなく、入力されたトークンに対しても計算されているようです。直前のトークンに対する logits から、softmax で、そのトークンの確率を計算します。それをP(Wn|W1...Wn-1) と思って、すべてかけると文章の確率が　π P(Wn|W1...Wn-1) として計算してみます。

| 入力 | _ | 庭 | で | 犬 | を | 飼 | う | `<eos>` | log(total) |
|---|---|---|---|---|---|---|---|---|---|
| token ID | 9 | 3383 | 19 | 1651 | 18 | 11915 | 307 | 2 | |
| softmax/total | | 0.000018 | 0.053874 | 0.003065 | 0.250974 | 0.344746 |  0.193827 | 0.000025 | -34.306927 |

[計算に使ったプログラム](https://github.com/mori32/codesnipets/tree/main/reranker-test)

# 同音異義語を比較してみる

| 入力 | log(total) | Best? |
|---|---|---|
| 庭で犬を飼う | -34.306927 | 〇 |
| 庭で犬を買う | -38.451576 | |
| 庭で犬をかう | -43.358597 | |

| 入力 | log(total) | Best? |
|---|---|---|
| 店で犬を飼う | -35.116959 |  |
| 店で犬を買う | -34.593872 | 〇 |
| 店で犬をかう | -45.241699 | |

| 入力 | log(total) | Best? |
|---|---|---|
| 登校時間が、いつもよりとても速い | -50.598568 | |
| 登校時間が、いつもよりとても早い | -47.688759 | 〇 |

| 入力 | log(total) | Best? |
|---|---|---|
| 彼の足は、いつもよりとても速い | -45.206917 | 〇 |
| 彼の足は、いつもよりとても早い | -46.757721 | |

# まとめ

- GPTを、文の生成に使うのではなく、既知の文の確率を計算できるのか試してみた。
- 同音異義に対して、正しい方が高確率になるか確認してみた。
Rustでメモ化再帰実装

## 概要

標準ライブラリの`std::collections::HashMap`を使用して結果をメモしていく。
基本的には他言語と変わらないが参照を渡していくことを忘れない様にする。



```rust
use std::collections::HashMap;

fn fib(n: u64, memo: &mut HashMap<u64, u64>) -> u64 {
    if n == 0 || n == 1 {
        return n;
    }
    if memo.contains_key(&n) {
        return memo[&n];
    }
    let result = fib(n - 1, memo) + fib(n - 2, memo);
    memo.insert(n, result);
    result
}

fn main() {
    let mut buffer = String::new();
    std::io::stdin().read_line(&mut buffer).unwrap();
    let n = buffer.trim().parse::<u64>().unwrap();

    let mut memo = HashMap::new();
    println!("{}", fib(n, &mut memo));
}
```
UnityのScript開発にVisual Studio Codeを使用

# 環境

* OS: Windows Home 11
* Unityエディター: 2022.3.9f1(LTS)

# 前提

* Unity開発環境のセットアップが完了していること
  * https://qiita.com/yiwa81/items/0f00e5e931d74e1e1d65

# Visual Studio Codeのセットアップ

## インストール

以下からセットアップバイナリをダウンロードする。
* https://code.visualstudio.com/download
  * 例: System Installer > x64

ダウンロードしたセットアップバイナリ（2023/09/03時点では VSCodeSetup-x64-1.81.1.exe）をダブルクリックして、インストールする。

## 拡張機能の追加

Visual Studio Codeを起動する。
左ペインの拡張機能のマークをクリックし、検索窓で以下の拡張機能を検索し、インストールする。
* C# (Base language support for C#)
  * C#の基本機能
* C# Dev Kit
  * C#の先進的な開発機能。フォーマッタも同梱
* C# XML Documentation Comments
  * XML形式のドキュメントコメント入力を容易化
* Unity (Integrates Visual Studio Code with Unity)
  * MicrosoftによるUnity拡張（Debugger、コード補完等）
* ~~Unity Code Snippets (Kleber Silva)~~
  * ~~Unity用のコード補完機能~~
* Japanese Language Pack for VS Code
  * （任意）UIの日本語対応
* Vim (Vim emulation for Visual Studio Code)
  * （任意）Vimのキーバインド対応

## 設定

自動フォーマットを設定する。
* 左ペインの設定のマーク（歯車）をクリックし、「設定」を選択
* 検索窓で「Editor: Format」と入力
* 以下の項目にチェックを付ける
  * Editor: Format On Paste
  * Editor: Format On Save
  * Editor: Format On Type

# Visual Studio Code 向け .NET SDK のセットアップ

以下からセットアップバイナリをダウンロードする。
* https://dotnet.microsoft.com/ja-jp/download/dotnet/sdk-for-vs-code

ダウンロードしたセットアップバイナリ（2023/10/01時点では dotnet-sdk-7.0.401-win-x64.exe）をダブルクリックして、インストールする。

# UnityエディターでVisual Studio Codeの使用を設定

Unityエディターを開き、以下の設定を行う。
* Edit > Preferences を選択
* Preferencesの画面で、External Tools > External Script Editor として Visual Studio Codeを選択
CSS Modulesで「composes」を書くとunknownPropertiesと出る

Visual Studio CodeでNext.jsのプロジェクトを作成し、CSS Moduleで`composes`を書くと警告が出てきます。
![スクリーンショット 2023-09-11 22.33.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163786/41378353-e5a7-8a5d-65fa-3eef758d2a55.png)

composesにマウスを当てるWarningが書かれています。
`不明なプロパティ: 'composes'css(unknownProperties)`
CSS側に存在しないプロパティがあるとのことです。
![スクリーンショット 2023-09-11 22.34.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163786/9f95ad7b-e80e-7986-1386-5dc996b92003.png)

対策としてVisal Studio Codeのバリデータを設定することができます。

左下の歯車マークからsettingsをクリック
![スクリーンショット 2023-09-11 22.42.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163786/a425d216-231c-5757-18ce-3ac6b4bd9f4f.png)

検索窓からこちらを入力、Add Itemをクリック
CSS › Lint: Valid Properties
![スクリーンショット 2023-09-11 22.43.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163786/1b2758b9-3372-11a8-fa29-1304e0ed413a.png)

composesを登録します。
![スクリーンショット 2023-09-11 22.44.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163786/f2588c15-7521-d7a6-75bf-d173f6aa8f5f.png)

警告がなくなりました。
![スクリーンショット 2023-09-11 22.45.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163786/fc816a9f-1fd8-64c0-55be-a038a40a4097.png)

以上です。
ARMのLXDでlxdcliを用いてgo+python開発環境を作る

## 目的
以前、dockerで同じ様な環境を作ったが開発環境としては物足りない部分があった。LXD上で構築すれば解決すると考えた

## 構築
lxdfile

```bash
CONTAINERNAME ubuntu-go
FROM ubuntu/23.04


RUN export DEBIAN_FRONTEND=noninteractive
RUN timedatectl set-timezone Asia/Tokyo && hostnamectl set-hostname ubuntu-go
RUN apt-get -y update

RUN dpkg --configure -a
RUN echo "\n\n\n" | apt-get -y install openssh-server
RUN apt-get -y install docker docker.io docker-compose nano curl

RUN echo -e "root:password" | chpasswd
RUN echo -e 'PermitRootLogin  yes' >> /etc/ssh/sshd_config


RUN systemctl enable ssh
RUN systemctl restart ssh
RUN systemctl start ssh


RUN apt-get -y update && apt-get -y install python3-pip nano
RUN mkdir .pip
RUN touch .pip/pip.conf
RUN echo "[global]" >> .pip/pip.conf
RUN echo "break-system-packages = true" >> .pip/pip.conf
RUN wget https://go.dev/dl/go1.20.4.linux-arm64.tar.gz
RUN mkdir -p /usr/local/go/bin
RUN tar -C /usr/local -xzf go1.20.4.linux-arm64.tar.gz
ENV PATH $PATH:/usr/local/go/bin
RUN export PATH=$PATH:/usr/local/go/bin
RUN echo "export PATH=$PATH:/usr/local/go/bin" >> ~/.bashrc
```


## 確認
go
```bash
root@ubuntu-go:~# go
Go is a tool for managing Go source code.

Usage:

        go <command> [arguments]

The commands are:

        bug         start a bug report
        build       compile packages and dependencies
        clean       remove object files and cached files
        doc         show documentation for package or symbol
        env         print Go environment information
        fix         update packages to use new APIs
        fmt         gofmt (reformat) package sources
        generate    generate Go files by processing source
        get         add dependencies to current module and install them
        install     compile and install packages and dependencies
        list        list packages or modules
        mod         module maintenance
        work        workspace maintenance
        run         compile and run Go program
        test        test packages
        tool        run specified go tool
        version     print Go version
        vet         report likely mistakes in packages

Use "go help <command>" for more information about a command.
```

python
```bash
root@ubuntu-go:~# python3
Python 3.11.4 (main, Jun  9 2023, 07:59:55) [GCC 12.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
```
Vue.jsのリアクティブなデータの定義でハマったのでメモ

Vueでリアクティブなデータを宣言するときにハマったのでメモします。

Vueでdataを宣言する書き方は

```
data() {
  return {
    count: 0,
    message: "Hello",
  };
}
```
と
```
data: {
  count: 0,
  message: "Hello",
}
```

の2種類あります。
この違いをわからずになんとなくで使っていたためにハマってしまいました。

結論から書くと
前者の書き方(returnを使う方)が推奨のようです。
後者の書き方ではリアクティブなデータが反映されません。

今回は、リアクティブなデータを使用したいのに後者の書き方をしていたため、
データの値が変化しても反映されず、なんでだ〜〜となってしまいました。

Vue3からはComposition APIを使って、もっと簡単にデータを定義できるので
これで悩むことは無くなるのでしょうか。
ただ、`ref()`をつけ忘れてハマる未来が見えるので気をつけようと思います。
TCP（トランスポート層）アプリケーションプロトコル（アプリケーション層）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/3b63e99c-a34c-c8ef-2282-e28f2b052cdf.png)
　IPはパケットが最終的に宛先に届いたkどうかを保証しません。しかし、実際の通信においては、パケットが宛先に間違いなく届くことが望まれます。パケットが確実に届くことを保証するプロトコルをTCPがあります。

１：TCPとUDP
　TCP(Transmission Control Protocol)は、コネクションを形成して、信頼性のある通信を実現するためのプロトコルです。コネクションを形成すると、相手と情報を交換しながら通信することができます。例えば、パケットが正しく届いたという返事を相手から受け取ることができます。他にも、エラーが含まれていた場合にはパケットの再送を指示することもできます。この結果、信頼性のある通信（すべてのパケットを正しく相手に届ける通信）が実現できます。

　UDP（User Datagram Protocol）は、コネクションを形成せず、信頼性のない通信を実現するためのプロトコルです。相手と情報交換することなく、いきなり相手にパケットを送りつけます。相手は、いきなり送られてきたパケットを受け取れない場合もあります。したがって、確実に相手にパケットが届く保証はありません。しかし、TCPで行ったような面倒な情報交換をしませんから、次から次へとパケットを送信することができます。つまり、高速に通信を行うことが可能です。映像・音声データは、データが一部欠落してもノイズが少し入るくらいで、映像・音声の品質には深刻な影響を与えません。データが欠落することよりもパケットを絶え間なく送ることのほうが大切なのです。

２：ポート番号
　ポート番号は、アプリケーションプロ線との会話をするための窓口の番号です。役所の窓口と同じ位置付けです。役所では、窓口ごとに役割が決まっていて、住民票窓口で税の問い合わせはできません。ポート番号も同様でポートごとに対応するアプリケーションプロセスが決まります。

　サーバ側では、アプリケーションプロセスは、ウェルノウンポートと呼ばれる番号のポートで接続を待ちます。下記に代表的なウェルノウンポートを記載します。

代表的なウェルノウンポート
サービス（プロトコル）：FTP ポート番号：２０、２１
サービス（プロトコル）：SMTP ポート番号：２５
サービス（プロトコル）：HTTP ポート番号：８０
サービス（プロトコル）：POP３ ポート番号：１１０
サービス（プロトコル）：HTTPS ポート番号：４４３

３：アプリケーションプロトコル
　アプリケーションプロトコルは、アプリケーションがデータのやり取りをするプロトコルです。アプリケーションごとにさまざまなプロトコルがあります。代表的なアプリケーションプロトコルを下記にまとめます。

プロトコル：DOMAIN(DNS)　サービス概要：ドメイン名とIPアドレスの変換
プロトコル：HTTP　サービス概要：Webサービス提供
プロトコル：FTP　サービス概要：ファイル転送
プロトコル：SMTP　サービス概要：電子メール配送（メールサーバ間での配送、パソコンからのメール送信）
プロトコル：POP3　サービス概要：パソコンへの電子メールのダウンロード（パソコンからのメール受信）
プロトコル：IMAP　サービス概要：メールサーバ上でメールを送受信する。
プロトコル：SNMP　サービス概要：ネットワーク上の機器を管理し、動作情報を収集する。情報を収集する側（管理する側）をマネージャ、ネットワーク上の機器（管理される側）をエージェントという。
プロトコル：SSH　サービス概要：遠隔ログイン。暗号通信を行うため安全である。ユーザ認証をパスワ　
　　　　　　ードで行う方法に加え、公開鍵を用いて行う方法もリヨできる。
プロトコル：NTP　サービス概要：時刻を合わせる（時刻を同期させる）
AngleSharpでBASIC認証+スクレイピング

C#初学者向けに私が詰まったポイントと解決のために閲覧したWebページを貼っておきます。

** やりたいこと**
 BASIC認証のあるサイトに対してC#でスクレイピング

**コード**
```C#
internal class scraping
{

    public async void Scraping()
    {
        var uri = new Uri(@"http://kaiin:naisho@leggiero.sakura.ne.jp/xxxxbasic_auth_testxxxx/secret/kaiin_page_top.htm");
        var client = new HttpClient();

        // 認証情報の指定がない場合は string.Empty になる
        if (!string.IsNullOrWhiteSpace(uri.UserInfo))
        {
            // 認証情報が指定されていたらヘッダーを設定
            var bytes = Encoding.UTF8.GetBytes(uri.UserInfo);
            var base64 = Convert.ToBase64String(bytes);
            client.DefaultRequestHeaders.Authorization = new("Basic", base64);
        }

        // まずは、スクレイピングするデータを取得
        var doc = default(IHtmlDocument);
        var stream = await client.GetStreamAsync(uri);
        var parser = new HtmlParser();
        doc = await parser.ParseDocumentAsync(stream);
        Console.WriteLine(doc.Body.InnerHtml);

    }

    static void Main(string[] args)
    {
        scraping scraping = new scraping();
        scraping.Scraping();
        Thread.Sleep(10000);
    }
}
```

詰まった（詰まっている点）
* awaitの挙動。上のコードではMain関数で10秒待っているので大丈夫ですが、`Thread.Sleep(10000)`を外すとスクレイピング開始度同時に終了する
* BASIC認証の方法
    * https://blog.xin9le.net/entry/2021/03/08/234336
*スクレイピング部分のコードの書き方
    * https://qiita.com/settings/notifications
    *https://qiita.com/matarillo/items/a92e7efbfd2fdec62595
*セレクタAPI
    * https://standards.mitsue.co.jp/resources/w3c/TR/selectors-api/
【伝説級】面白すぎる2024年問題【正答率0%】を解く

# 問題

自然数 $(a,b,c)$ すべて求めよ。
```math
a! - b^2 + 4^c = 2024 \tag{0}
```

出典は PASSLABO さん。

https://www.youtube.com/watch?v=bDQGEQkSSWg

# mod 2 で考える
まず $2$ を法とする合同式で考えると与式は
```math
a! - b^2 \equiv 0\pmod{2} \tag{1}
```
となり，
```math
a! \equiv b^2 \pmod{2} \tag{2}
```
となる。
|$a$|$a! \bmod 2$|
|:--:|:--:|
|$a = 1$|$1$|
|$a \ge 2$|$0$|

|$b$|$b^2 \bmod 2$|備考|
|:--:|:--:|:--:|
|$0$|$0$|$b$ が偶数のとき|
|$1$|$1$|$b$ が奇数のとき|

より，$a = 1$ のとき $b$ は奇数，$a \ge 2$ のとき $b$ は偶数となる。

まず，$a = 1$ のときを考える。

```math
4^c - b^2 = (2^c)^2 - b^2 = (2^c - b)(2^c + b ) = 2023 = 7\times17^2 \tag{3}
```

より，以下の３つの場合を考えれば良いが，３つとも $c$ が自然数にならず不適である。

|$①$|$2^c - b$|$1$|$7$|$17$|
|:--:|:--:|:--:|:--:|:--:|
|$②$|$2^c + b$|$2023$|$289$|$119$|
|$(② + ①)/2$|$2^c$|$1012$|$148$|$68$|

よって $a \ge 2$ でなくてはならない。また $b$ は偶数となる。

自然数 $m$ を用いて $b = 2m$ とおくと

```math
a! - 4m^2 + 4^c = 2024 \tag{4}
```

となる。

# mod 4 で考える
$(4)$ に対して $4$ を法とする合同式で考えると

```math
a! \equiv 0 \pmod{4} \tag{5}
```

となる。

|$a$|$a! \bmod 4$|
|:--:|:--:|
|$a = 1$|$1$|
|$a = 2$|$2$|
|$a = 3$|$2$|
|$a \ge 4$|$0$|

であるから $a \ge 4$ となる。

# mod 3 で考える
$(4)$ に対して $3$ を法とする合同式で考えると，$a \ge 4$ であるから

```math
\begin{cases}
a! \equiv 0 &\pmod{3} \\
-4m^2 \equiv -m^2 &\pmod{3}\\
4^c \equiv 1 &\pmod{3} \\
2024 \equiv 2 &\pmod{3}
\end{cases} \tag{6}
```

より

```math
-m^2 + 1 \equiv 2 \pmod{3} \tag{7}
```

となり，

```math
m^2 \equiv -1 \equiv 2 \pmod{3} \tag{8}
```

となる。しかし，$m^2 \not\equiv 2 \pmod{3}$ なので不適である。

|$m$|$m^2 \bmod 3$|
|:--:|:--:|
|$0$|$0$|
|$1$|$1$|
|$2$|$1$|

以上より，題意を満たす自然数 $(a,b,c)$ は存在しない。

```plantuml
@startuml
<style>
root {
  Padding 0
  Margin 0
}
title {
  fontSize 64
  fontStyle normal
  fontColor red
}
</style>
title ホンマか？？？\nホンマに正答率０％？
@enduml
```

※ちなみに上の拡大文字は PlantUML を使っています。


# 今後の課題
- 数式番号，自動で付けられないかなあ？？？
【Django】ORMのvalues_listメソッドの引数"flat=True"の使い方とは？サンプルコード解説

# 概要
DjangoのORMでは`values_list`メソッドがありますが、これの引数には`flat`があります。
本記事ではこの`flat`の意味と大事になるケースを紹介します。

# サンプルコード

以下記事にて、以前紹介した下記のコードで`flat=True`を使っていたのですが、改めて使い方を確認。
[【Python】終端記号を考慮して100文字までカットするコード](https://qiita.com/Ryo-0131/items/eb989fddc07988ff412d)

このコードでは、`PuncCd`モデルから取得した複数の終端記号の中で該当する最後のものにより文章を区切っています。

```py
from xxx.models import PuncCd

def truncate_comment_at_last_punc(comment):
    last_punc_location = None
    punc_cd_values = PuncCd.objects.values_list('punc', flat=True)
    for punc_value in punc_cd_values:
        location = comment.rfind(punc_value)
        if location == -1:
            continue
        if last_punc_location is None or location > last_punc_location:
            last_punc_location = location

    truncated_comment = None
    if last_punc_location is not None:
        truncated_comment = comment[:last_punc_location + 1]

    return truncated_comment

comment = "ここにコメントが入ります"
comment_100 = truncate_comment_at_last_punc(comment[:100])
```

上記で、もし`flat=True`としない場合、以下のエラーになります。

```
'must be str, not tuple' 
```

なぜかというと、`rfind`メソッドは文字列に対して動作するため、タプルではなく文字列を渡す必要があります。しかし、`values_list`で`flat=True`を使用しない場合、`punc_cd_values`はタプルのリストであり、タプルは文字列ではないため、`rfind`メソッドがタプルに対して呼ばれると `'must be str, not tuple'`エラーが発生するのです。

## `flat=True`とは？
Django ORM（Object-Relational Mapping）の`values_list`メソッドに対する引数。
この引数を指定することで、`values_list`メソッドはクエリセットから取得したデータを平らな（フラットな）リストとして返します。
リストとして扱いたい場合に活用できます。

例としては、以下のようになります。

### `flat=True`の場合

```py
country = Country.objects.values_list("country_name", flat=True)
print(country)

# 出力
# <QuerySet ['日本', 'スペイン', 'ドイツ', 'コスタリカ']>
```

### `flat=False`の場合

```py
country = Country.objects.values_list("country_name", flat=False)
print(country)

# 出力
# <QuerySet [('日本',), ('スペイン',), ('ドイツ',), ('コスタリカ',)]>
```

上記のように、`False`にするとそれぞれのオブジェクトがタプルの要素となっていることがわかります。
各値をタプル内にラップされたリストにしたい時は、`False`が使えます。この場合は、値にアクセスするためにインデックスを使用する必要があります。

逆に、単純な値のリストが得たい場合は`True`を使うと良いでしょう。
`True`にすることで、各カラムの値がリストの要素として一括りになります。
Playwright コードスニペット - イベント編

## はじめに

よくあるブラウザ操作について、Playwrightでどのように実装するかをサンプルコードとともに紹介します。

## 新しいタブを開く

`BrowserContext` クラスの [`waitForEvent("page")`](https://playwright.dev/docs/api/class-browsercontext#browser-context-wait-for-event) メソッドを使用します。

```typescript
import { test, Page } from "@playwright/test";

test("新しいタブを開く", async ({ context, page }) => {
  const newTabPromise: Promise<Page> = context.waitForEvent("page");
  // 新しいタブを開く操作
  await page.getByRole('button', {name: "新しいページ"}).click();
  const newTab: Page = await newTabPromise;
  await newTab.waitForLoadState("domcontentloaded");
  // 新しいタブでの操作

});
```

## ダイアログを開く

`Page` クラスの [`waitForEvent("dialog")`](https://playwright.dev/docs/api/class-page#page-wait-for-event) メソッドを使用します。

```typescript
import { test } from "@playwright/test";

test("ダイアログを開く", async ({ page }) => {
  // ダイアログを開く操作
  await page.getByRole("button", { name: "ログアウト" }).click();
  page.on("dialog", async (dialog) => {
    await dialog.accept();
  });
  // ログアウトしたことを確認
});
```

## ファイルのダウンロード

`Page` クラスの [`waitForEvent("download")`](https://playwright.dev/docs/api/class-page#page-wait-for-event) メソッドを使用します。

```typescript
import fs from "fs";
import { Download } from "playwright";
import { test, expect } from "@playwright/test";

test("ファイルのダウンロード", async ({ page }) => {
  const downloadPromise: Promise<Download> = page.waitForEvent("download");
  // ファイルのダウンロード操作
  await page.getByRole("button", { name: "ダウンロード" }).click();
  const download: Download = await downloadPromise;
  const filePath: string = "downloaded.txt";
  await download.saveAs(filePath);
  // ダウンロードしたファイルの存在確認
  expect(fs.existsSync(filePath)).toBeTruthy();
});
```

## ファイルのアップロード

`Page` クラスの [`waitForEvent("filechooser")`](https://playwright.dev/docs/api/class-page#page-wait-for-event) メソッドを使用します。

```typescript
import fs from "fs";
import { FileChooser } from "playwright";
import { test, expect } from "@playwright/test";

test("ファイルのダウンロード", async ({ page }) => {
  const fileChooserPromise: Promise<FileChooser> = page.waitForEvent("filechooser");
  await page.getByRole("button", { name: "ファイル選択" }).click();
  const fileChooser: FileChooser = await fileChooserPromise;
  const filePath: string = "toUpload.txt";
  await fileChooser.setFiles(filePath);
  await page.getByRole("button", { name: "アップロード" }).click();
  // アップロードが完了したことを確認
});
```


<!-- zenn article id: 1728e285b4c2e5 -->
Windows11でBluetoothデバイス(XPPen Deco MW)を検出できない

# 症状
Bluetoothデバイス(XPPen Deco MW)をWindows11に接続しようとしたが、検出することができない。

# 解決策
「Bluetoothデバイスの検出」の設定を規定→詳細に変更する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3328036/5af7ae96-7b6f-a110-c446-ede402bf6419.png)

# 参照
https://support.microsoft.com/ja-jp/windows/windows-%E3%81%AE-bluetooth-%E3%81%AE%E5%95%8F%E9%A1%8C%E3%82%92%E8%A7%A3%E6%B1%BA%E3%81%99%E3%82%8B-723e092f-03fa-858b-5c80-131ec3fba75c


~~Windows11きらい……~~
CBAS（データ分析実務スキル検定）PM級　リベンジしてきた

以前挑戦して見事に惨敗したCBASのPM級にリベンジしてきました。
その時書いた記事はこちら
[データ分析実務スキル検定（CBAS）を受けてきました](https://qiita.com/Mizu0214sw/items/c0b414b4c1029317b57c)

# 試験概要
本題に入る前に、ざっくりCBASについて説明をしておこうと思います。

CBAS（データ分析実務スキル検定）とは、「デジタル時代のビジネスパーソンに求められる実践的なデータ分析スキルを可視化し、評価するための検定試験」です。(公式サイトより)
実際に受けた感想としては、この試験はデータ領域を初めて学習する人、もしくは実務レベルまでいかなくともある程度データ分析に関して知識がある人におすすめできるかなと思います。

また、問題数や試験方式は以下の通りになります。
問題数：60問
試験方法：CBT方式
試験時間：90分
合格ライン：97点満点で64点以上
受験料：11,000円（税込み）

回答方式は基本的に4～5択の単一回答ですが、時々複数回答の問題も含まれているので消去法が使えない分時間がかかるところもあります。さらに、5,6問ほどExcelを使用して答えを求めてくる問題もあるので、Excelでの計算にもある程度慣れておいたほうが良いかもしれません。

# 使用教材
　　「データ分析実務スキル検定　公式テキスト」
　　　　[Amazonリンク](https://www.amazon.co.jp/gp/product/B09HGYN6TR/ref=ppx_yo_dt_b_d_asin_title_o01?ie=UTF8&psc=1 "教材リンク")
　　「Udemy：「データ分析実務スキル検定 PM級」合格への道」
　　　　[Udemyリンク](https://www.udemy.com/course/cbas-prep/)

　学習の流れとしては8割はUdemyで講義を繰り返し見るのを繰り返して、所々見ても分からなかった箇所はテキストを読んだりネットで調べたりしながら不明点は解消していく感じで進めてました。元々Udemyはかなりおすすめされていた教材ですが、実際今回使ってみて「これを完璧に理解できれば余裕で合格できるな」と感じるくらいかなり有用な教材だと思いました。

1点Udemyの講義を購入する際に注意しなければならないのですが、今回リンクを貼った講義は出題範囲全てを網羅しているわけではなく計算が必要な問題・グラフを読み解く問題をメインで解説しているものになります。なので、一部解説しきれていない部分もありますので、そこはテキストやそれ以外の教材で学習することになります。


# 受験結果は...
さて、実際に受験してきたわけですが2回目の結果は...

見事「**合格**」でした！リベンジ成功！
点数の内訳としては、
　
　97点満点中、67点（合格評価点：64点）

　セクション分析　：正答率
　　1.業務目的に応じた適切なKPIツリーの作成：33%
　　2.データの取り扱いに関する利用規約、法令等の理解：100%
　　3.データ分析に必要な前処理の理解：100%
　　4.SQLの基礎の理解：100%
　　5.データ可視化手法の基礎の理解：60%
　　6.基礎集計を通じたデータの全体像や質の確認：64%
　　7.業務目的に応じた適切なコーディング：54%
　　8.基礎的な統計手法の理解：50%
　　9.主要な機械学習の概要と使い分けの理解：80%
　　10.予測モデルの評価と改善手法の理解：75%
　　11.施策の評価と効果検証の理解：75%

ちなみに前回はこんな感じでした。
97点満点中、54点（合格評価点：64点）

　セクション分析　：正答率
　　1.業務目的に応じた適切なKPIツリーの作成：33%
　　2.データの取り扱いに関する利用規約、法令等の理解：100%
　　3.データ分析に必要な前処理の理解：100%
　　4.SQLの基礎の理解：100%
　　5.データ可視化手法の基礎の理解：40%
　　6.基礎集計を通じたデータの全体像や質の確認：73%
　　7.業務目的に応じた適切なコーディング：85%
　　8.基礎的な統計手法の理解：25%
　　9.主要な機械学習の概要と使い分けの理解：50%
　　10.予測モデルの評価と改善手法の理解：25%
　　11.施策の評価と効果検証の理解：25%

こうやって見ると、後半の8～11の項目については正答率が上がってますね。
ただコーディングを結構間違えていたり全体像を捉えるのが下手になっていたりと、所々油断が見られました。
あとやっぱりKPIツリー作成は低いですね...普段からもっと意識しなければ...

僕は統計が超が付くレベルで苦手なので、分散や確率などの計算は正確に覚えて使えるようにしたつもりですが、まだまだ足りないようなのでもっと練習します...笑


# 感想
　今回は無事合格することが出来ました！
ただ点数だけ見ても合格ラインぎりぎりだったので、次は今回5～60%の正答率だったセクションを中心に復習をして8～90点台を目指したいですね。CBASはPM級のほかにシチズン級もあるので、そっちにもいつか挑戦してみようと思います。
kintoneのフィールドコードを一括変更

# Tisさんの[フィールド情報/データ一括更新プラグイン](https://www.tis2010.jp/bulksettings/)にて
アプリをCSVなどで一括で登録した時にフィールドコードが自動で登録されるが、
ラベルとフィールドコードを揃えたい。。
kintoneベンダーの多くの方はフィールドコードまで整理されると思います。

私はフィールドコードとラベルは同じ日本語派です。
プログラマの方で英語表記にされる方もいらっしゃいますね。

![スクリーンショット.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/511519/581ac5ac-556e-8dd9-9256-5f3fba898811.png)


# ラベルとコードの往復でぽちぽちコピペするのもいいが...
アプリでjQueryが使える状態にしておいてください。
（何を言っているかわからない方は使わないほうがいいです。）
コメントに親切な方が誰でも使えるようにjs置いてくださっています！(2023/9/22)

この画面を開いてF12でコンソールを開きましょう。
本記事の掲載日時点での動作確認となってますのでご注意〜

## コンソールハック！

```js:フィールドラベルとコード同期.js

$('div.label').each((i,label) => {
    let value = $(label).find('input').val();
    //ここでラベルの括弧の処理をつけたりと必要に応じて書き換えます。
    value = value.replace(/(\(|\)|（|）)/g, "_");
    $('div.code input').eq(i).val(value);
});

```

![マイビデオ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/511519/7acf1467-712e-460c-f40a-9a2a353867a1.gif)


これでポチッと更新すれば一瞬でラベルとコードを揃えることができます。
重複確認などは対応していないので事前のデータクレンジング時点で精査しましょう。
計算フィールドで同じ名前を使えば、削除の手間が省かれる / Tableau Prep

Tableau Prepで途中計算を作る場合、計算フィールドで途中式を使って計算し、次にそれを使って計算フィールドを作成し、わからなくなっちゃうから不要になったら削除、あるいは最後に途中式ばかりを一気に削除とかしていませんか？

実は、計算フィールドの名前に、同じものを使うと、ステップごとに値が上書きされていくので、途中計算がそのままの名称でできます！

## よくやってしまいがちなこと

Profitを四捨五入した数値にしたい場合に、計算式でProfit2と称して四捨五入した値を求めて、そのあとオリジナルのProfitを削除し、フィールド名を変更する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/3cc1b5f4-d551-a459-332a-353ca7b95281.png)

処理自体は間違っていないけど、フィールドを追加して、削除してを繰り返すので、どのフィールドを残すかだんだん混乱してきます。そんなときに、フィールドの上書きがお勧めです。


## 実はこれだけでOK

実は同じフィールド名を指定できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/6e6a0894-d578-f56b-abf8-7a073bf695cd.png)

フィールド名が同じ場合に、以下のような警告はでますが、OKで解決です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531257/8d041f4e-8d96-47ae-57f9-087a4940c45c.png)


## 感想
フィールド削除は、フィールド名の変更処理がいらないので、2ステップは削減でき、すっきりわかりやすいです。
【Swift】文字列内の"(ダブルクォーテーション)をエスケープするのがめんどくさい

# はじめに
SwiftでJSONを文字列で定義しようとするとこんな感じになります

![スクリーンショット 2023-09-11 21.51.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/4e2d7784-c20f-90b7-389d-1020ed8e3a55.png)

これを解決するためにバックスラッシュでエスケープします

![スクリーンショット 2023-09-11 21.51.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/70bd7e00-f3ff-119d-451e-63cf170edb5d.png)

ただ、これがめんどう！！

これをしなくていい方法があります

# やりかた
`#`で囲むだけでOK!
```swift
let text = #"{"name": "Taishin", "age": 22}"#
```

![スクリーンショット 2023-09-11 21.52.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/7217132d-db32-a362-0039-7cdbc51a72ba.png)

# おわり
めっちゃ簡単ですね
[MR Dev Tips #16] UnityEvent について

UnityEvent について。具体的なサンプルの方が分かりやすいと思うので、MRTK のソースコードを例示しながら検証をしてみたいと思います。


# イベント (Event) とは
> クラスやオブジェクトは、何か重要なことが起こった場合にイベントを使用して他のオブジェクト、またはクラスに通知を送ることができます。イベントを送信するクラスを Publisher (発行者)、イベントを受信するクラスを Subscriber (購読者) と呼びます。
> 
> [イベント (C# プログラミングガイド)](https://learn.microsoft.com/ja-jp/dotnet/csharp/programming-guide/events/) より引用

その他、「観測対象 (Subject) 」/「観測者 (Observer) 」などと呼ばれたりします。イベントに関する用語も UnityEvent と C# event で呼び方が異なる部分があります。

 
# UnityEvent とは
UnityEvent は、追加のプログラミングやスクリプトの設定を行う必要なく、編集時からランタイムへ 永続的 なコールバックを提供する方法です。Unity Editor (GUI) を使って、イベント発生時の処理 (リスナー) を追加することができます。また、スクリプトから動的に非永続なコールバックを追加することも可能です。

リスナー (Listener) は、データの保持の方法によって、以下2種類に分類されます。

- 永続リスナー ( Inspector 上から追加可能で、Scene データとして保存される )
- 非永続リスナー ( スクリプトから動的に追加することができるリスナー、Scene データとして保存されない )

[UnityEvent](https://docs.unity3d.com/ja/2021.2/ScriptReference/Events.UnityEvent.html)

## イベントの定義方法
個人的に身近な例だと、UnityEvent は MRTK v2 の ``Interactable.cs`` 内で使用されています。

```Interactable.cs
public UnityEvent OnClick = new UnityEvent();
```

## リスナーの追加
**永続リスナー**

Inspector ウィンドウ で イベントが定義されているコンポーネント に移動して、リスナーを登録します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/2cdb9c25-2845-6679-f0af-f879cbb260ca.png)


**非永続リスナー**

```UnityEventSample.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Microsoft.MixedReality.Toolkit.UI;

public class UnityEventSample : MonoBehaviour
{
    private Interactable interactable = null;

    void Start()
    {
        // Interactable コンポーネントの取得
        interactable = GetComponent<Interactable>();
        // イベントリスナーの追加
        interactable.OnClick.AddListener(Listener);
    }

    void Disable()
    {
       // イベントリスナーを取り除く
       interactable.OnClick.RemoveListener(Listener);
    }

    // イベントリスナーとして登録する関数
    void Listener()
    {
        Debug.Log("Click");
    }

}
```

実際に MRTK v2 の空のシーンに ``PressableButtonHoloLens2_64×64`` を追加して、上記のスクリプト ``UnityEventSample.cs`` をアタッチして、ゲームを再生すると、リスナーが追加されていることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/31ed9d65-1550-ad4e-ae61-ab24271ea518.png)


## イベントの実行
イベントに追加したリスナーを実行するには ``UnityEvnet.Invoke()`` メソッドを使用します。このメソッドを実行することで、登録されているリスナーが実行されます。MRTK v2 の ``Interactable.cs`` では、``PressableButtonHoloLens2`` のイベントを ``PhysicalPressEventRouter`` を介して ``Interactable`` へ送信しています。



**コンポーネント ( PressableButtonHoloLens2 : PressableButton )** ``IMixedRealityTouchHandler.OnTouchStarted() → IsTouching() → TouchBegin()``
↓
**コンポーネント (PhysicalPressEventRouter)**
``OnHandPressTouched()``
↓
**コンポーネント (Interactable)**
``TriggerOnClick() → SendOnClick()``

```Interactable.cs
protected void SendOnClick(IMixedRealityPointer pointer)
{
  OnClick.Invoke();
}
```

``OnClick.Invoke()`` が実行されると、リスナーとして登録された関数が実行されます。


# Refs
https://learn.microsoft.com/ja-jp/dotnet/csharp/programming-guide/events/
https://learn.microsoft.com/ja-jp/dotnet/standard/events/
SQL基礎構文まとめ

### 概要

SQLについて学習した内容をまとめました。
基礎的な事ばかりですが、ITのエンジニアには業務で直接扱うことが無かったとしても重要な知識だと感じたので、忘れた頃に見直せるようにまとめてみました。

まず、1.SELECT、2.FROM、3.WHEREについて下記の例を元に補足していきます。
```sql
-- 例）
SELECT id,name
FROM foods
WHERE type='果物';
```
### 1.SELECT
検索する際に使用するSQLです。
データを取得するにあたって、どの列（カラム）を持ってくるかをこの句の後に指定します。
例えば、「id,name,type」の列を持っているテーブルに対して例文のように「id,name」だけを指定した場合「type」は取得されません。
また、ここで*(アスタリスク)を指定することで全項目を指定できます。
```sql
-- 例）
SELECT * FROM foods;
```

### 2.FROM
検索するテーブル名を指定します。
必ずFROM句の前にSELECT句を記載します。

### 3.WHERE
特定したフィールド（Excelでいうセル）の行（レコード）を検索します。
例文では「種類」列に「果物」と言う文字列が格納されているセルを特定しています。
IDが「3」nameが「オレンジ」typeが「果物」みたいな列があったとしたら、[3,オレンジ]のような行が結果として出力されます。

要するに例文では食材テーブルから種類が果物の行のIDと名前を検索しています。

##### 比較演算子
WHERE句で「type='果物'」と記載している部分について、
「=」というのは等しいと言う意味ですが、他にも比較を行うための記号や構文はあるのでその例をいくつか記載しておきます。
| = | 等しい |
|:-:|:-:|
| <>もしくは!= | 等しくない |
| < | 小なり |
| > | 大なり |
| <= | 以下 |
| >= | 以上 |

### 4.ORDER BY
```sql
-- 例）
SELECT id,name FROM foods WHERE type='果物' ORDER BY id;
```
ORDER BY の後に指定したカラムの並べ替えを行ってくれます。
また、例文で言う最後の「id」の後にスペースを開けて「DESC」と記載すると降順で並び替えてくれます。「ASC」と記載もしくは何も記載しない場合は昇順です。
こちらは複数のカラムで並び替えが可能です。
```sql
-- 例）
SELECT id,name FROM foods ORDER BY id ORDER BY name;
```
最初に指定しているカラムが第１ソートとして指定され、そこから２つ目３つ目と順番に優先されます。

### 5.NOT
```sql
-- 例）
SELECT * FROM foods WHERE NOT type='果物'
```
指定した条件以外のものを取得します。<>や!=などの不等号も使用可能です。

### 6.AND
```sql
-- 例）
SELECT * FROM foods WHERE type='果物' AND id>=10;
```
複数の条件を満たすものを取得します。
例ではtypeが果物かつidが10以上のものを検索しています。

### 7.OR
```sql
-- 例）
SELECT * FROM foods WHERE type='果物' OR name='いちご';
```
どちらかの条件を満たすものを取得します。
例ではtypeが果物もしくはnameがいちごのものを検索しています。

### 8.IN
```sql
-- 例）
SELECT * FROM foods WHERE name IN('いちご', 'メロン', 'すいか');
```
こちらもORと同じく複数の条件と指定していずれかを満たすものを取得します。
ですが、条件が多い時 name=〇〇 OR name=〇〇 OR name=〇〇 OR・・・みたいに記載していくよりもすっきりします。

また逆に、```NOT IN('いちご', 'メロン', 'すいか')```のように記載することで、どの条件も満たさないものという条件にすることができます。

### 9.COUNT
```sql
-- 例）
SELECT COUNT(id) FROM foods;
```
いわゆる「集計関数」のひとつです。
指定したカラムのNULL以外のレコード数を数えます。
()の中で*(アスタリスク)を指定することで、単純に全体のレコード数を取得することができます。
また、WHERE句と併用することで、条件に絞った件数を取得することができます。
```sql
-- 例）
SELECT COUNT(*) FROM type='果物'; -- ※果物の件数を取得
```

### 10.GROUP BY
```sql
-- 例）
SELECT type FROM foods GROUP BY type;
```
指定したカラムを基準にして、レコード全体をグループ化します。
例ではtypeを基準にグループ化して、typeカラムだけを取得しているので、
出力結果としては
```text
肉
野菜
果物
```
のような形になると思われます。

COUNTのような集計関数と一緒に使うことで、グループ化したカラムの集計を行うことができます。
```sql
-- 例）
SELECT type, COUNT(*) FROM foods GROUP BY type;
```
このように記載することで
```text
肉　　3
野菜　14
果物　9
```
のようにそれぞれグループ化したものの件数を集計することができます。

参考：
比較演算子について
https://www.postgresql.jp/document/8.0/html/functions-comparison.html
IN句について
https://medium-company.com/select-in/
JavaScriptでfizzbuzz

<h1> JavaScriptでfizzbuzzやってみた

1~100の数字で3で割れるものを「fizz」、5で割れるもの「buzz」、
どちらでも割れる場合は「fizzbuzz」を数値の後に出力。

さっそく書いてみる
```JavaScript:main.js
for(let i = 0; i < 100; i++) {
 if(i % 3 === 0 && i % 5 ===0 ){
  console.log(`${i} fizzbuzz`);
 } else if(i % 3 === 0){
  console.log(`${i} fizz`);
 } else if(i % 5 === 0){
  console.log(`${i} buzz`);
 }else{
  console.log(i);
 }
}
```
結果
![スクリーンショット 2023-09-11 21.49.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520084/0773dee3-8045-3b94-faf3-09e24f60692d.png)


もっと良い書き方がありそうだがとりあえず完成。
せんせー、マイクロRNA治療ってなに？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/2c47de5a-d81a-78f9-53c1-4d31d8398c36.png)

キーンコーンカーンコーン...
授業が始まります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/be1492ca-910f-2708-d0fa-8fcfcf14af73.png)

せんせー、マイクロRNA治療ってなに？

# マイクロRNA治療とは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/da229491-9c49-fb7a-a542-417180e256a7.png)

## マイクロRNA治療とは何でしょうか？

マイクロRNA治療は、マイクロRNA（miRNA）という小さなRNA分子を利用して、細胞内の特定の遺伝子の発現を調節し、疾患の治療を目指す新しいタイプの医療技術です。miRNAは、自然に私たちの体内で遺伝子の表現を微調整している重要な役割を果たしています。

## どのように機能するのでしょうか？

マイクロRNA治療は、特定のmiRNA分子を導入し、細胞内での遺伝子発現を制御することによって機能します。これにより、異常な遺伝子発現が引き起こす疾患の症状を改善したり、進行を遅らせたりすることが可能になります。

## どのような疾患に効果がありますか？

マイクロRNA治療は、がん、心血管疾患、神経変性疾患などの様々な疾患に対する潜在的な治療法として研究されています。miRNAは特定の遺伝子の発現を調節できるため、特定の疾患に関連する遺伝子の異常な発現を正常化することが期待されます。

## どのようなリスクや課題がありますか？

マイクロRNA治療には、未知の副作用や安全性に関する懸念があります。また、正確な配送方法や、体内でのmiRNAの安定性も重要な課題となっています。この治療法はまだ初期段階にあり、多くの研究が必要です。

# まとめ

マイクロRNA治療は、miRNAを利用して遺伝子の発現を調節し、疾患の治療を目指す新しいアプローチです。これにより、特定の疾患に関連する遺伝子の異常な発現を正常化することが期待されますが、まだ多くの課題と未解決の問題があります。
【プラクティス紹介】1分でさらっと分かる「プラグマティック・ペルソナ」

![persona.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3526800/9eac087a-2ec2-96fa-f9d4-991818e783a9.jpeg)


## プラクティス名（別名）
プラグマティック・ペルソナ　（プロトペルソナ、偽のペルソナ）

## プラクティスの目的・狙い
* 代表的なユーザの人物像を具体化し、関係者間で合意形成しやすくする
* ユーザの気持ちを想像しやすくする

## どんな時に使うか
* 新アプリや新機能の企画検討段階で、想定するユーザ像が絞れていない時
* 関係者がそれぞれ異なるユーザ像を想定しており、判断や会話がすれ違う時

## 実施手順
1. メインユーザとなりそうな架空の人格の画像（写真等）を用意し、名前をつける
1. その人物の属性（年齢/性別/年収/家族構成/職業/性格/生活/etc...）を想像でよいので考える
1. 属性を持ち寄っただけだと一人の人間としてみた時に矛盾していることがあるので、それを解消する

「ペルソナ」はターゲット像を絞り込み、企画や施策の妥当性を検討するためのマーケティングの手法。関係者間で想像しているユーザ像がバラバラだと判断やコミュニケーションがすれ違い、円滑に進まないため、先にイメージを統一しておく。本来、ペルソナは実データや調査に基づき作成するため、それなりに時間も費用もかかる。プラグマティック・ペルソナはそれを簡易的に、手間をかけずに実施する手法。想像で作成している分、実際のユーザ像とズレがある可能性は当然あり、ズレが分かってきたらペルソナを適宜修正することが前提となる。

## アレンジ例
* ユーザ像として複数の方向性がある場合はムリに一人にまとめずに、ペルソナ自体を分ける

## アンチパターン
* ユーザパターンを網羅的にカバーしようとして、ペルソナの数が増えすぎる
（そもそも手間をかけないためにこの手法を採用したのに本末転倒）

## 参考情報
以下の記事で勉強させていただきました。敬意と感謝をこめて紹介させていただきます。

https://qiita.com/i09sakai/items/90b87390809f0de84814

https://qiita.com/s_maeda_fukui/items/d161738ab284a203abe6



## こぼれ話（私的コメント）
アジャイルプラクティスとして「プラグマティック・ペルソナ」を捉え直すと、マーケティングのツールというより、ユーザ視点でプロダクトを眺めてみるという意味合いが強そうです。ペルソナを立てる過程で「この情報はAさんみたいな初心者が必要とするだろう。ただAさんは初心者であるがゆえにここまでたどり着けないかもしれない。・・・とするとそもそもこれって企画倒れじゃね？」といった致命的な問題に気が付いたりもします。
またペルソナ自体の妥当な属性が思いつかないようであれば「そもそもユーザについて何も知らない」ということが再認識できるでしょう。

　[アジャイルプラクティス一覧へ戻る](https://qiita.com/kakashi_h5/items/20584998c5ca4594b9ea)
よく使うLinuxコマンドのアレって、何の略だっけ..

## はじめに
- Linuxコマンドのアレって、何の略だっけ..をまとめてみました。

## よく使うLinuxコマンド18選
| コマンド名 | 何の略？　| 基本的な意味 |備考|
|:-:|:-|:-|:-|
| cd | **C**hange **D**irectory | ディレクトリを変更する |
| pwd  | **P**resent **W**orking **D**irectory  | 現在の作業ディレクトリのパスを表示する |  **P**rint **W**orking **D**irectoryの略であるとする説もあります。 |
| ls  | **L**i**S**t | ファイルやディレクトリの一覧を表示する | **L**ist **S**egment の略であるとする説もあります。|
| mkdir  | **M**a**K**e **DIR**ectory | 新しいディレクトリを作成する |   |
| rmdir  | **R**e**M**ove **DIR**ectory | ディレクトリを削除する |   |
| cat  | conc**CAT**enate | ファイルの内容を表示する | 複数のファイルをつなげた内容を表示するという意味のコマンドだが1つのファイルの内容を使う目的でもよく使う。  |
| less  | **LESS** |ファイルの内容をページ単位で表示する |・ファイルの内容をページ単位で表示する別コマンドに`more`があります。<br>・`more`コマンドで表示されたテキストを反対方向にスクロールさせて表示させたいとして登場したのが`less`。<br>・`more`とスクロール方向が**反対**というところから意味的に`more`と**反対**の意である`less`と命名。半ばジョークともいえる名称のコマンド。<br>・機能は`more`よりも多いとされ`less`さえ知っていればページ表示に関してはさほど困らない。`less`の方が`more`より多機能であることから、**Less is more.(機能面においてlessの方がmoreよりも優れている)**  ともいわれる。|
| tail  | **TAIL** | ファイルの末尾から指定した行数分を表示する |   |
| touch  | **TOUCH** | 既存のファイルのタイムスタンプを更新する | 中身が空のファイルを作る目的でも使う |
| rm  | **R**e**M**ove | ファイルやディレクトリを削除する |   |
| mv  | **M**o**V**e | ファイルやディレクトリの移動 | ファイルやディレクトリの名前の変更する目的でも使う |
| cp  | **C**o**P**y | ファイルやディレクトリをコピーする |   |
| ln  | **L**i**N**k | リンクを作成する |   |
| find  | **FIND** | ファイルやディレクトリを検索する |   |
| chmod  | **CH**ange **MOD**e | ファイルやディレクトリの権限を変更する |   |
| chown  | **CH**ange **OWN**er | ファイルやディレクトリの所有者を変更する |   |
| ps  | **P**rocess **S**tatus | 実行中のプロセスの一覧を表示する |   |
| kill  | **KILL** | プロセスを終了させる |   |

## 英単語例文集
- 少し難しいと思われる単語をまとめてみました。

| 単語 | 品詞 | 意味 | 使われているコマンド |
|:-|:-|:-|:-|
|  present | 形容詞 | 「現在の」の意。<br>例：「現住所」なら「present address」 | **p**wd |
| concatenate  | 動詞  | 「数珠つなぎにする、つなぎ合わせる」の意。<br>例：「2つのPDFファイルを1つにした」なら「I concatenated two PDF files into one.」 | **cat** |
|  tail | 名詞 | 動物なら「しっぽ」。船なら「船尾」と言うように「最後の部分」を表す。ファイルの場合は、ファイルの最後の部分が該当。  | **tail** |

## 参考にした記事
https://magazine.techacademy.jp/magazine/6455
https://en.wikipedia.org/wiki/Less_(Unix)
https://www.abbreviations.com/abbreviation/concatenate
【TypeScript】keyof型演算子の便利な点

業務の中で、keyof型演算子についてインプットしたので、整理しました。

#### `keyof`はオブジェクトの型からプロパティ名を型として返す型演算子
```typescript
type Person = {
  name: string;
};
type PersonKey = keyof Person;
// type PersonKey = "name"
```
2つ以上のプロパティがあるオブジェクトの型に`keyof`を使った場合は、すべてのプロパティ名がユニオン型で返されます。
```typescript
type Book = {
  title: string;
  price: number;
  rating: number;
};
type BookKey = keyof Book;
// 上は次と同じ意味になる
type BookKey = "title" | "price" | "rating";
```

#### `keyof`のメリット
:::note info
keyofのメリットは、保守性が上がる点です。オブジェクトの型とは別にプロパティ名のユニオン型を定義していると、オブジェクトの型のプロパティを変更したときに、そのユニオン型のほうも修正が必要になります。keyofを使って、オブジェクトの型からキーを導出するようにしておけば、変更箇所はオブジェクトの型のところだけになります。
:::

##### `keyof`を使わない場合
```typescript
type UserData = {
  name: string;
  age: number;
}

type UserProps = "name" | "age";

function displayUserInfo(user: UserData, prop: UserProps) {
  console.log(user[prop]);
}

// この後、`UserData`に新しいプロパティを追加したいと考えた場合、
// `UserProps`も同時に更新する必要があります。
```

##### `keyof`を使う場合
```typescript
type UserData = {
  name: string;
  age: number;
}

type UserProps = keyof UserData;

function displayUserInfo(user: UserData, prop: UserProps) {
  console.log(user[prop]);
}

// この場合、`UserData`のプロパティを変更するだけで、
// `UserProps`の型も自動的に更新されます。
```



https://typescriptbook.jp/reference/type-reuse/keyof-type-operator
せんせー、メソスコピック材料ってなに？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/2c47de5a-d81a-78f9-53c1-4d31d8398c36.png)

キーンコーンカーンコーン...
授業が始まります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/be1492ca-910f-2708-d0fa-8fcfcf14af73.png)

せんせー、メソスコピック材料ってなに？

# メソスコピック材料とは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/da229491-9c49-fb7a-a542-417180e256a7.png)

## メソスコピック材料とは何でしょうか？

メソスコピック材料とは、ナノスケール（1億分の1メートル）とマイクロスケール（1万分の1メートル）の間のスケール、つまりメソスケール（1千分の1メートル程度）で特性が決まる材料のことを言います。このスケールの材料は、特殊な性質を持ち、様々な技術分野で利用されています。

## どのように作られるのでしょうか？

メソスコピック材料の製造は、ナノテクノロジーと微細加工技術を利用して行われます。これにより、特定の構造やパターンを持つ材料を作成することができます。材料の精密な設計と制御によって、独特の性質や機能を持った材料が生まれます。

## どうしてそれがすばらしいのでしょうか？

メソスコピック材料は、その特殊な構造により、光学的、電子的、機械的性質が通常の材料とは異なる場合があります。これにより、新しい種類のデバイスや技術の開発が可能となり、科学と工学の多くの分野で革新をもたらします。

## どのような用途がありますか？

メソスコピック材料は、光学デバイス、センサー、エネルギー貯蔵デバイスなど、さまざまな高技術産業で利用されます。また、新しいタイプの太陽電池や触媒材料の開発にも利用され、環境に優しい技術の開発に貢献しています。

# まとめ

メソスコピック材料は、特殊な性質を持ち、その特性がメソスケールで決まる材料の一群です。これらの材料は高度な製造技術によって作られ、多くの革新的な技術と製品の開発に用いられています。
tqdmの中でprintすると表示が崩れる時の対処法

久しぶりに記事を書いてみました。
Pythonでプログレスバーを簡単に表示するためにtqdmモジュールを使用する機会がありました。
tqdmモジュールは簡単に使用できますが、printした場合に表示が崩れてしまいます。
今回はtqdm中にprintで表示が崩れないようにする対処法を備忘録として残しておきます。

## tqdmの使い方

まず初めにtqdmの使い方を簡単に紹介します。

```Python:main.py
from tqdm import tqdm
import time

for i in tqdm(range(10)):
    time.sleep(0.5)
```

![スクリーンショット 2023-09-11 19.39.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958368/1832b3bf-3e32-e35a-3504-c333db80bc1e.png)

試してみるとプレグレスバーが徐々に進むと思います。

## printして表示を崩す

次はプレグレスバーの表示が崩れるところを確認します。
```Python:main.py
from tqdm import tqdm
import time

for i in tqdm(range(10)):
    print(i)
    time.sleep(0.5)
```
↓のようにプレグレスバーが都度表示されます。

![スクリーンショット 2023-09-11 19.45.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958368/ba2ba168-da1e-5d24-9124-ecff274cb369.png)
プレグレスバーの制御する位置がprintされることで新しい行になり表示が崩れてしまいます。

## tqdm.writeで解決
表示が崩れないようにする方法としてtqdm.writeがあります。
tqdm.writeを使用するとプレグレスバーの上に出力されるため、表示が崩れません。

```Python:main.py
from tqdm import tqdm
import time

for i in tqdm(range(10)):
    tqdm.write(str(i))
    time.sleep(0.5)
```
![スクリーンショット 2023-09-11 19.56.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958368/9541d302-a15b-66fc-7c0a-ae140d4794f9.png)

問題なく表示されるかと思います。

## まとめ
今回はtqdmの簡単な使い方とprintでの表示崩れ対策をまとめてみました。
少しでも役に立つ内容があれば嬉しいです。
せんせー、ホログラフィックストレージってなに？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/2c47de5a-d81a-78f9-53c1-4d31d8398c36.png)

キーンコーンカーンコーン...
授業が始まります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/be1492ca-910f-2708-d0fa-8fcfcf14af73.png)

せんせー、ホログラフィックストレージってなに？

# ホログラフィックストレージとは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/da229491-9c49-fb7a-a542-417180e256a7.png)

## ホログラフィックストレージとは何でしょうか？

ホログラフィックストレージは、デジタルデータを光の三次元的なパターンとして記録・読み取りする技術です。この技術は、データを非常に高速にアクセスできる大容量のストレージシステムを実現することを目指して開発されました。

## どのように機能しますか？

ホログラフィックストレージは、レーザービームを2つの異なるビームに分け、その交差点にデータをエンコードすることで動作します。データは、これらのビームが交差する点にある特殊な光学メディアに記録されます。読み取り時には、参照ビームだけが使われて、記録されたデータを再構成します。

## なぜそれがすばらしいのでしょうか？

ホログラフィックストレージ技術は、従来のストレージソリューションよりもはるかに高いデータ密度と速度を提供する可能性があります。これは、大量のデータを短時間で保存して取り出すことが可能になり、情報の管理とアクセスがより効率的になることを意味します。

## どのような用途がありますか？

ホログラフィックストレージは、データセンター、企業、研究機関など、大規模なデータストレージソリューションが求められる場所で使用される可能性があります。また、映画産業やヘルスケア分野でも、大量のデータを安全かつ効率的に管理するために利用される可能性があります。

# まとめ

ホログラフィックストレージは、光の三次元的なパターンを利用してデジタルデータを高速に記録・読み取りする革新的な技術です。この技術は、データの高密度記録と迅速なアクセスを可能にし、将来的にはデータストレージの新たな標準を築く可能性があります。
StreamlitでBIしよう！

# はじめに
Streamlitでドリルダウンを作成することでBIのようなことができる記事を書きました。

https://qiita.com/inoshun/items/3b84e0634db8342f3ec4

今回はPyGWalkerというPythonライブラリをStreamlitで使用していきます。

# PyGWalkerとは
以下の記事を参考に二番煎じのようなことをします(;'∀')

https://qiita.com/hima2b4/items/dfdfb77cf3a588f4131a

PyGWalkerはStreamlitと親和性が高いと公式がおっしゃっています。

https://docs.kanaries.net/pygwalker/use-pygwalker-with-streamlit.en

ただ、今回はどのようなデータでもBIできるようにスクリプトを作成しました。

# スクリプト

```python
import pandas as pd
import pygwalker as pyg
import streamlit.components.v1 as components
import streamlit as st

# Streamlitページの幅を調整する
st.set_page_config(layout="wide")
# タイトルを追加する
st.title("PyGWalker")

# データフレームの用意
df = None

# ファイル選択
with st.sidebar:
    uploaded_files = st.file_uploader("Choose a CSV file", type=["csv"])
    if uploaded_files is not None:
        df = pd.read_csv(uploaded_files)

# pygwalkerで表示
pyg.walk(df, env='Streamlit')
```

```
$ streamlit run <アプリ名>
```
でStreamlitアプリを起動してください。

![pyg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/821a8db2-c12d-dadb-e1dc-f4f4a83a15b5.png)

なんかエラーが出てますが気にしなくてOKです(;´･ω･)
ではcsvファイルを読み込んでみます。
今回は有名なタイタニックのデータを読み込ませます。
![tat.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/f043683b-7cfe-7a33-6694-47add922617f.png)

反映されましたね！！！
あとは左にあるカラム名を`X-Axis`と`Y-Axis`にドラッグアンドドロップすればいいだけです。
必要に応じてフィルタリングなどしてください。

![tat.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524375/cd018720-ae1f-c4db-a491-d95c9120e8b8.png)

今回は参考記事と同じようにグラフを作成してみました。

# まとめ
今回はStreamlitでBIを行ってみました！
使い方もめちゃくちゃ簡単です。
詳しくは参考記事をご覧ください！
それでは！！！
CircleCiの処理を追う

# CircleCiの処理を追う

## 目次

- [1. はじめに](#1-はじめに)
- [2. CircleCIの基本概念](#2-circleciの基本概念)
  - [ワークフロー、ジョブ、ステップの定義](#ワークフロージョブステップの定義)
  - [`config.yml` の役割とサンプル](#configyml-の役割とサンプル)
- [3. 環境のセットアップ：Spin up environment](#3-環境のセットアップspin-up-environment)
  - [スピンアップとは？](#スピンアップとは)
  - [DockerとCircleCIの関係](#dockerとcircleciの関係)
  - [イメージの選択とカスタマイズ](#イメージの選択とカスタマイズ)
- [4. 環境変数の設定：Build Environment Variables](#4-環境変数の設定build-environment-variables)
  - [環境変数のソースとその優先度](#環境変数のソースとその優先度)
  - [CircleCIのUIでの設定](#circleciのuiでの設定)
  - [`config.yml` での定義とサンプル](#configyml-での定義とサンプル)
- [5. 実際のデプロイ処理](#5-実際のデプロイ処理)
  - [Capistranoの基本](#capistranoの基本)
  - [CircleCIとCapistranoの連携](#circleciとcapistranoの連携)
- [6. 環境変数のセキュリティ](#6-環境変数のセキュリティ)
  - [環境変数のマスキング](#環境変数のマスキング)
  - [ベストプラクティス](#ベストプラクティス)
- [7. まとめ](#7-まとめ)

## 1. はじめに

CircleCIは、自動化されたCI/CDツールとして人気を博しています。本記事では、CircleCIの処理の流れや内部で何が行われているのかを詳しく追ってみます。

## 2. CircleCIの基本概念

### ワークフロー、ジョブ、ステップの定義

- **ワークフロー**：ジョブの実行順序や、一連のジョブがどのように連動して動くかを定義します。
- **ジョブ**：特定のタスク群を実行するための設定です。例えば、テストやデプロイなどのタスクを定義します。
- **ステップ**：ジョブ内で実行される具体的なコマンドやタスクを指します。

### `config.yml` の役割とサンプル

`config.yml`はCircleCIの設定を定義する中心的なファイルです。以下は一例です。

```yaml
version: 2.1

orbs:
  ruby: circleci/ruby@0.1.2

jobs:
  build:
    docker:
      - image: cimg/ruby:2.7.6
    steps:
      - checkout
      - ruby/install-deps
```

## 3. 環境のセットアップ：Spin up environment

### スピンアップとは？

スピンアップは、Dockerイメージを基に新しいコンテナを起動するプロセスを指します。このコンテナ内でジョブが実行されます。

### DockerとCircleCIの関係

CircleCIのジョブは、指定されたDockerイメージ内で実行されることが多いです。これにより、必要なソフトウェアやツールがプリインストールされた環境で、一貫性を持ってタスクを実行できます。

### イメージの選択とカスタマイズ

`cimg/ruby:2.7.6` はCircleCIが提供する公式のRubyイメージの一例です。自分自身でカスタムイメージを作成することも可能です。

## 4. 環境変数の設定：Build Environment Variables

### 環境変数のソースとその優先度

CircleCIでの環境変数は、以下のソースから取得されます：

1. CircleCIのUIでの設定
2. `config.yml`での定義
3. GitHubリポジトリやその他の外部ソース

### CircleCIのUIでの設定

CircleCIのダッシュボードには、プロジェクトごとの環境変数設定セクションがあります。ここでの設定は、セキュリティのために非表示になります。

### `config.yml` での定義とサンプル

`config.yml` での環境変数の設定例：

```yaml
jobs:
  build:
    environment:
      FOO: "bar"
```

この例では、`FOO`という環境変数に`"bar"`という値が設定されます。

## 5. 実際のデプロイ処理

### Capistranoの基本

CapistranoはRuby製の自動デプロイツールです。`deploy.rb`や環境別の設定ファイルに、デプロイに関する詳細な設定やタスクを定義します。

### CircleCIとCapistranoの連携

CircleCIのジョブの中

で、`cap <環境名> deploy`のようにCapistranoを呼び出すことで、自動デプロイを行います。環境変数はCapistranoの設定にも適用されるため、非常に柔軟にデプロイフローを構築できます。

## 6. 環境変数のセキュリティ

### 環境変数のマスキング

セキュリティ上の理由から、特定の環境変数（例: APIキー）はログに表示されないようマスキングされます。

### ベストプラクティス

環境変数には機密情報を含むことが多いため、これらの情報が漏洩しないよう、定期的にアクセスキーやトークンをローテーションすることが推奨されます。

## 7. まとめ

CircleCIを最大限に活用するには、その内部の動作や設定方法を深く理解することが不可欠です。本記事を通じて、その基本的な流れやベストプラクティスについて理解を深める手助けとなれば幸いです。