OmniAICreator/Qiita-1.07M huggingface dataset:
[Laravel] CSRF対策について

# はじめに

Laravelの学習中、formタグを使用する際には以下のように@csrfの記述が必須であることがわかりました。

```
<form method="POST" action="/profile">
    @csrf
    ...
</form>
```
この場合@csrfを書かないでPOSTした場合は419エラーになリます。
CSRFとはなにか？なぜ記述する必要があるのか初学者視点で解説したいと思います。

この記事の対象者としては

* CSRFが何か、なぜ対策が必要なのかわからない方
* Laravel初心者の方

を想定しております。
# CSRF（クロスサイトリクエストフォージェリ）とは

CSRFは、攻撃者がユーザーの意図しないリクエストを行わせることによって、Webサイト上での操作を不正に行う攻撃手法です。攻撃者は、被害者が認証済みの状態で悪意のあるWebページにアクセスすることを誘導します。

### 攻撃手法

①攻撃者は攻撃用Webページを準備し、ユーザがアクセスするよう誘導する。
②被害者が攻撃用のWebページを開くと、そのページ内には攻撃者が用意した不正なリクエストが含まれている。
③ブラウザは被害者のクッキーを自動的に付与し、不正なリクエストが攻撃対象のWebサイトに送信される。
④攻撃対象のWebサイトは、ユーザーが意図しない操作を実行してしまう。

### 被害の例

ユーザーがオンラインバンキングシステムAにログインしているとします。このユーザーは、定期的に送金を行うためのフォームを使用します。しかし、攻撃者がユーザーが訪れる可能性のある悪意のあるWebページを作成し、その中には攻撃者が用意した不正な送金リクエストが含まれているとします。

ユーザーが攻撃者のWebページにアクセスすると、そのWebページ内のリクエストがオンラインバンキングシステムAに自動的に送信され、ユーザーが意図しない形で資金が移動してしまいます。ユーザーがログイン済みであるため、システムはリクエストを正当なものと認識し、不正な送金が実行されてしまいます。

**CSRF攻撃の対策をしていないと、攻撃者は不正に取得したセッションIDを使用して、ユーザのアカウントで操作を行ったり、データを変更したりすることが可能になります。**

# なぜ@csrfと記述するだけで攻撃を防げるのか？

Laravelでは、"POST"、"PUT"、"PATCH"、"DELETE"のHTMLフォームを定義するときはいつでも、CSRF保護ミドルウェアがリクエストを検証できるように、フォームに非表示のCSRF_tokenフィールドを含める必要があります。

Laravelではビューで**formの内部に@csrfと記述**するだけで自動的にCSRFトークンを生成し、フォームの隠しフィールドに埋め込むことができます。

```
<form method="POST" action="/hoge">
    @csrf
    <input name="hoge" value="{{ $hoge }}">
    <button type="submit">送信</button>
</form>
```

トークンはリクエストが処理される前に生成され、その後、フォームなどの入力フィールドに埋め込まれます。これにより、**送信されるリクエストに正しいトークンが含まれ、セッションに入っているトークンの値と一致しているか**サーバーで検証されることになります。

このCSRFトークンはセッションが再生成されるたびに変更されるため、悪意のあるアプリケーションはこのトークンへアクセスできません。

また、現在のセッションのCSRFトークンには、リクエストのセッションまたはcsrf_tokenヘルパ関数を介してアクセスできます。

```
use Illuminate\Http\Request;

Route::get('/token', function (Request $request) {
    $token = $request->session()->token();

    $token = csrf_token();

    // ...
});
```



# まとめ

この記事では、LaravelにおけるCSRF攻撃とその対策方法について解説しました。CSRF攻撃はユーザーの意図しないリクエストを利用して不正な操作を行う手法であり、formの中に@csrfを記述することによって、Laravelは自動的にCSRFトークンを生成し、悪意のあるリクエストを防ぎます。
n個前の行と比べる　LAGのPARTITIONのメモ

前日との差など出したい時。 1行前と比べるのに使う　LAG

:::note info
LAG (表示させたいカラム, n個前, なかった時の値) OVER( [PARTITION BY グループ毎に分けたい場合そのグループにするカラム] ORDER BY　並び替えカラム)
:::

リファレンスにのってるもので、**PARTITION** あるなしなどテスト
https://docs.snowflake.com/ja/sql-reference/functions/lag

```sql
CREATE OR REPLACE TABLE sales(emp_id INTEGER, year INTEGER, revenue DECIMAL(10,2));

INSERT INTO sales VALUES 
    (0, 2010, 1000), 
    (0, 2011, 1500), 
    (0, 2012, 500), 
    (0, 2013, 750);
INSERT INTO sales VALUES 
    (1, 2010, 10000), 
    (1, 2011, 12500), 
    (1, 2012, 15000), 
    (1, 2013, 20000);
INSERT INTO sales VALUES 
    (2, 2012, 500), 
    (2, 2013, 800);
```

## PARTITION なし
```sql
SELECT 
    emp_id,
    year,
    revenue, 
    LAG(revenue, 1, 0) OVER (ORDER BY year) AS pre
FROM sales 
ORDER BY year;
```
**OVER (ORDER BY** で指定したカラムの並び順で一つ前のものが表示
年度が変わっていても無視、とりあえず**year**順に並んで、その一つ上のものが表示される
![スクリーンショット 2023-06-01 15.57.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47236/8d30b5ed-86a7-a552-d7be-8604296e610b.png)

## PARTITION あり
### PARTITION BY yearの場合
```sql
SELECT 
    emp_id,
    year,
    revenue, 
    LAG(revenue, 1, 0) OVER (PARTITION BY year ORDER BY year) AS pre
FROM sales
ORDER BY year;
```
yearが違く、最初の行だと、なかった時の値 0 が入るようになる
![スクリーンショット 2023-06-01 16.04.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47236/c39f56a0-d093-c175-62d8-8d7f015815d8.png)

### PARTITION BY emp_idの場合
```sql
SELECT 
    emp_id,
    year,
    revenue, 
    LAG(revenue, 1, 0) OVER (PARTITION BY emp_id ORDER BY year) AS pre
FROM sales
ORDER BY year;
```
emp_id毎にyear順で並び、emp_idが違く最初の行だと なかった時の値 0 が入る
![スクリーンショット 2023-06-01 16.06.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47236/a1dda387-2d67-7e95-21e1-2d368895acf7.png)
初めてのPowerBI

# 目次
- 初めに
- Power BIとは
- 最後に

# 初めに
前回までPower Appsを利用したアプリケーションの作成をしてきましたが、今回はそのアプリを使って登録されたデータを可視化し分析できるようにしたいと思いました。
そこで、今回はそんなレポートの作成をするのにPower BIを利用したいと思い、初めてのPower Appsと同様に学んだことをまとめるためにこの記事を書きました。
初めてのPower Appsについては[こちら](https://qiita.com/gun_lee/items/b4bd64253fdab3f8e461)に書いてあります。

# Power BIとは
Microsoft Power BIとは、Microsoftが提供しているローコード開発ツール **「Power Platform」** の中の一つであるアプリケーションです。

Power BIでは、Excelなどといったデータを直感的な操作でデータを可視化し分析するレポートを作成することができるアプリケーションです。

大きな特徴として、データの加工、レポートの見た目の作成、グラフ作成が直感的な操作で行うことができ、専門知識がなくても簡単にできるのが大きな特徴です。
多少関数や変数といった知識は必要ですが、Power BI同様Microsoftが提供しているExcelと同じような方法なのでExcelに慣れている人であれば簡単にできると思います。

Power BIをうまく利用することで企業が今まで集めてきたデータを求めている形で可視化することができ、それを活用して今後の動きを考え実施させるBI(Busines Intelligence)ができるようになります。

Power BIには以下の3種類に分かれています。

- Power BI Desktop(無料版)
- Power BI Pro(組織向け共有機能)
- Power BI Premium(AIを利用した高度な操作)

今回は組織内で共有したいと思っているので有料版のPower BI Proにします。
個人で利用したい人は無料版で良いと思います。

# 最後に
今回はPower BIについて学習してきました。
次回はPower BIを利用して前回までPower Appsで作成したアプリケーションを使って集めたデータを分析するレポートを作成していきたいと思います。
既存のRailsアプリケーションにDockerを導入する方法

## 概要
この記事では、既存のRailsアプリケーションにDockerを導入する方法について記述致します。

## 前提条件
- Dockerがインストールされていること
-  Docker Composeがインストールされていること
- Railsアプリケーションが作成済みであること

## 手順
### 1. Dockerfileの作成
プロジェクトのルートディレクトリに`Dockerfile`という名前のファイルを作成します。そして、以下の内容を記述致します。

:::note warn
下記、`1行目のrubyの末尾`には、`使用バージョン`、`myapp`のところには、`お使いのアプリ名`に変更し、記述して下さい。
:::

```Dockerfile:Dockerfile
FROM ruby:2.7.1

RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs

RUN mkdir /myapp
WORKDIR /myapp

COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock

RUN bundle install
COPY . /myapp
```

### 2. Docker Composeの設定
次に、`docker-compose.yml`ファイルをプロジェクトのルートディレクトリに作成致します。
以下は、dbに`PostgreSQL`を使用している場合の例です。

```yaml:docker-compose.yml
version: '3'
services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
```
###  3. Docker Composeのビルドと起動
以下のコマンドを実行し、Docker Composeをビルドし、起動致します。

```bash:
docker-compose build
docker-compose up
```

## まとめ
以上で、既存のRailsアプリケーションにDockerを導入する手順を記述させて頂きました。
この手順により、開発環境を容易に構築・共有することが可能になります。
DHCPで割り振られたディスプレイのない計算機のIPアドレスを知る

## 問題

使用しているネットワークによっては，固定IPアドレスをコンピュータに割り振ることができず，DHCPでIPアドレスを取得しなければならない場合があります．計算専用機のようにディスプレイが必要ないコンピュータでは，ディスプレイでIPアドレスを直接確認できないので困ります．IPアドレスが分からないディスプレイが無いコンピュータからcronを使って定期的にIPアドレスを書いた電子メールを送るという手段もありますが，メールサーバが必要になるため，この手段は使いたくありません（外部のSMTPサービスもアカウント情報を設定ファイルに書く必要があるので使いたくないです）．ではどうやってIPアドレスを知ればよいのでしょうか．

## 手法

ディスプレイが無いコンピュータからディスプレイ付きで使用しているLinuxマシンにpingを打ち，そのログを見ることでIPアドレスを知る方法があります．

これを実現するには，次の2項目を実現しなければなりません．
- IPアドレスがわからないコンピュータからpingをディスプレイ付きで使用しているLinuxマシンに自動的に打つ．
- ディスプレイ付きで使用しているLinuxマシンにpingが打たれたことを確認出来る．

使用ディストリビューションはDebianです．使用しているディストリビューションによって，インストールコマンドやファイルの場所などが異なります．


### ディスプレイがないコンピュータの設定

cronを使って定期的にpingを打たせればよいでしょう．次の行を/etc/crontabに追加すればよいです．
```
0 7 * * * root /bin/ping -c 4 IPアドレス
```
これで毎朝7時にpingを打ちます．

また，マシンの起動時にpingを打ちたければ
```
@reboot root sleep 300 && /bin/ping -c 4 IPアドレス
```
と/etc/crontabに追加します．起動してすぐだとネットワークが確立していないかもしれませんので，sleepで少しまってからpingを打ちます．．

### ディスプレイ付きで使用しているLinuxマシンの設定

pingが打たれたことを確認するために，pingのログをiptablesを使って取ります．

- iptablesの設定は，シャットダウンのたびに忘れてしまうので，忘れないようにiptables-persistentをインストールします．
```
sudo apt install iptables-persistent
```
- iptablesに設定を加えます．
```
sudo iptables -I INPUT -p icmp --icmp-type echo-request -j LOG --log-prefix "PING RECEIVED: "
``` 
- 念のためiptablesの設定を確認します．
```
sudo iptables -L
```
- iptablesの設定を保存します．
```
sudo netfilter-persistent save
```
- これで __/var/log/kern.log__ にpingリクエストのログが残ります．つまり，IPアドレスを知りたいときにkern.logを見れば良いとうことです．しかし，Debian12ではログの管理がsystemd-journaldに変わって/var/logの下にlogファイルが保存されなくなりました．Debian12の方は，
```
sudo journalctl -k
```
のコマンドでpingのログを見ましょう．
deviseを導入し、新規登録画面へ遷移するためのpath

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/e4d53c97-0bbe-6251-84c5-e8d9b9d46e4a.png)
１：deviseを導入し、新規登録ボタンをクリックしたら、新規登録画面へ遷移するための設定。
<%= form_with model: @user, url: user_registration_path, class: 'registration-main', local: true do |f| %>
と記述する。
rails routesコマンドを実行し、pathの確認をすると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/2e38f22b-d0be-8b5d-0fd7-e13552232cf5.png)
今回、フォームからの新規登録情報を送信して、registrations#createを実行し、保存したいため、Prefix：user_registrationをpathとして、registrations/new.html.erbのurlにuser_registration_pathを記載することでログイン情報を保存できる。
Auto Encoderの特徴抽出(色付きMNIST)


AEの学習には基本的に下記のリンクに書いてあります。
   
[tensorflowを用いてAuto Encoderの特徴抽出の実装(MNIST)](https://qiita.com/teterote/items/14bc4f8d07364caaab25)

今回は上記の実験に比較して、MNISTのデータを変更して学習した結果を示します。


MNISTをランダムでRGBの色ごとに着色していきます
```python
(X, y) , (test_images, test_labels) = tensorflow.keras.datasets.mnist.load_data()
#(X.shape) (y.shape)  (60000, 28, 28) (60000,)

label=np.random.randint(0,3,(X.shape[0])) 
choice_color=[np.identity(3)[i] for i in label] 
choice_color=np.array(choice_color)
#(choice_color.shape)(60000, 3)
Color_MNIST= [MNIST_3[i]*choice_color[i]  for i in range(X.shape[0])]
Color_MNIST=np.array(Color_MNIST)
#(Color_MNIST.shape) (60000, 28, 28, 3)
```

## 通常のMNIST
![ダウンロード - 2023-06-01T145819.762.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/623871/298e312c-84f2-0ac3-9b7a-faa4812c1faa.png)

## RGB_MNIST
![ダウンロード - 2023-06-01T145752.940.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/623871/e5e0c24e-e42f-0871-869f-9a514ec9fd90.png)

RGBに着色した、MNISTのデータセットができました。
それをAEで学習を行います。
# 実験結果
#### 形状ごと
![ダウンロード - 2023-06-01T145124.394.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/623871/62e561e6-2873-acfc-7318-a95ac131c7de.png)
#### 色ごと
![ダウンロード - 2023-06-01T145128.408.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/623871/2a10a4c8-a618-b231-87d0-54fce7821746.png)
#### プロット
![ダウンロード - 2023-06-01T145132.420.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/623871/0930c754-91e3-cd29-b5d2-17b279247cc9.png)

# 結論
色の情報を優先して特徴を抽出していることが確認ができた。
cscの作法 その322

# 概要
cscの作法、調べてみた。
sqlite、やってみた。

# 環境
windows10 64bit

# サンプルコード

```
using System;
using System.Text;
using System.IO;
using System.Data.SQLite;


namespace App
{
	public class Program {
		public static void Main(string[] args) {
			SQLiteConnection.CreateFile("db0.sqlite");
			Console.WriteLine("ok0");
		}
	}
}


```

# コンパイル手順

```
>csc lite0.cs /reference:System.Data.SQLite.dll

```

以上。
データベースを基本からまとめてみた【A5:SQL Mk-2使い方備忘録】

## データベース定義変更

①左上の『ファイル』の『開く』を選択し、該当のデータベースを選択する
②ターゲットデータベースを選択し、下の▼（SQLのオプション）で、実行位置『先頭から全て』を選んで、▷SQLの実行を押す
PowerShell のキーバインドを Vim にする

### やりたかったこと
- PowerShell のコマンドラインを Vim コマンドで操作したい
- `jj` を `Esc` として扱う
- ついでに PowerShell を便利にしたい

### 方法
PowerShell 起動時に実行されるスクリプトファイルの場所を確認
```powershell
$PROFILE
```
ファイル内に以下を記述する
```shell
Set-PSReadLineOption -EditMode Vi
```
`jj` で `Esc` を呼び出したい場合には以下を追記する
```shell
Set-PSReadLineKeyHandler -Chord 'j' -ScriptBlock {
  if ([Microsoft.PowerShell.PSConsoleReadLine]::InViInsertMode()) {
    $key = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
    if ($key.Character -eq 'j') {
      [Microsoft.PowerShell.PSConsoleReadLine]::ViCommandMode()
    }
    else {
      [Microsoft.Powershell.PSConsoleReadLine]::Insert('j')
      [Microsoft.Powershell.PSConsoleReadLine]::Insert($key.Character)
    }
  }
}
```
括弧や引用符の補完などを行いたい場合は以下を参考にさらに追記する

https://qiita.com/AWtnb/items/5551fcc762ed2ad92a81

他によい方法があったらぜひ教えてください。
Unityでプログラム上から動画を撮る方法[Windows & Mac]

## 前提
- 使用フレームワークでサポートされているプラットフォームがWindowsとMacのため、AndroidとiOSでの動作はサポートされていません。
- mp4はWindowsのみの対応

## FrameCapturer
https://github.com/unity3d-jp/FrameCapturer

## Unityへのインストール方法
- https://github.com/unity3d-jp/FrameCapturer にアクセス
- Usageの`FrameCapturer.unitypackage`をダウンロードして実行

## 動画撮影の前準備
- 空のゲームオブジェクトを作成
- Add Component から MovieRecorder の追加
- CaptureControlをManualに設定する
- 操作をするソースに設置をしたMovieRecorderを操作できるようにする

## 使い方
```
using UTJ.FrameCapturer;

public class Sample : MonoBehaviour
{
    [SerializeField]
    MovieRecorder m_movieRecorder;
```
上記のような形でMovieRecorderを取得してる前提で記述します。

### 録画の開始
```
// 録画中かどうかの確認
if (!m_movieRecorder.isRecording)
{
    // 録画開始
    m_movieRecorder.BeginRecording();
}
```
- ファイル名についてはBeginRecording時にyyyyMMdd_HHmmssで名前が設定される。
- このファイル名の取得方法自体はフレームワークには無かった。アウトプットフォルダ名は取得できる。

### 録画の停止
```
// 録画中かどうかの確認
if (m_movieRecorder.isRecording)
{
    // 録画停止
    m_movieRecorder.EndRecording();
}
```

### 出力先フォルダの取得
```
// 出力先のフォルダを取得
string GetOutputDir()
{
    return m_movieRecorder.outputDir.leaf;
}

// 出力先フォルダのフルパスの取得
string GetOutputDirFullPath()
{
    return m_movieRecorder.outputDir.GetFullPath();
}
```
- GetFullPathはoutputDirの設定で`Absolute`と`Current`の場合は相対パスのみ返却する設定みたいです。

### 録画終了した後に動画ファイルが生成完了したかの確認方法
FrameCapturer側のソースを見る限りで言えば生成完了の通知用のものが見当たらないので
updateなどでFileinfoを使ってファイルサイズが有るのかの確認することで生成完了を検知する。
```
var strFilePath = ""
FileInfo fileinfoData = null;
// フォルダ内データの取得
var files = Directory.GetFiles(GetOutputDirFullPath(), "*.*", SearchOption.AllDirectories).ToList();
if (files.Count > 0)
{
    strFilePath = files[0];
}
// 存在チェック
if (File.Exists(strFilePath))
{
    fileinfoData = new FileInfo(strFilePath);
}
// ファイルサイズの確認
if(fileinfoData != null && fileinfoData.Length > 1024)
{
    // ファイル生成確認後の処理
}
```
- FileInfo.Lengthはbyte単位で帰ってくる。ソース上では1kbyte以上の場合に生成されたという判定にしている。

## おわりに
- 2017年のフレームワークなんで若干古いですが、問題なく使用はできました。
- 生成したファイル名までのフルパスの取得の方法などあれば良いのかなとは思いました。
- iOSの場合は[こちら](https://qiita.com/fuziki/items/042c3c5a9333beee6a07 "")の方の記事が参考になると思います
PostgreSQLのDBサーバーがよく分かってなかった話

# Docker上でpostgresのコンテナを建てる
PostgreSQLをインストール済みのMacbook Proにて、Rancher Desktopを用いてdockerコンテナ上にpostgresのDBサーバーを建てようとした。
```console:dockerコマンド
$ docker run -d --name postgres_postgresdb -e POSTGRES_USER=user -e POSTGRES_PASSWORD=pass -e POSTGRES_DATABASE=postgresdb -e POSTGRES_INITDB_ARGS="--encoding=UTF-8" -p 5432:5432 postgres
```
上のコマンドを実行した結果、正常にdockerコンテナが作成されたのを`$ docker ps`にて確認した。

じゃあ中に入ってみるか。
`$ psql postgres://user:pass@localhost:5432/postgresdb`でDBにアクセスすると、以下のエラーが出た。
```console:出たエラー
psql: エラー: "localhost"(127.0.0.1)、ポート5432のサーバーへの接続に失敗しました: FATAL:  role "user" does not exist
```
あれ？dockerコマンドの引数でuserを指定したよな…
`POSTGRES_USER`じゃなくて`PG_USER`だったっけ？と思って変えてみたけど結果は同じ。

## 何も考えずにおかしな方向へfixを試みる

エラーコードでググってみたらuser追加しろとかDB追加しろとか言われた

ググった結果出てきたやつ:
https://stackoverflow.com/questions/15301826/psql-fatal-role-postgres-does-not-exist
https://stackoverflow.com/questions/17633422/psql-fatal-database-user-does-not-exist

```console:user作成のコマンド
$ /opt/homebrew/Cellar/postgresql@15/createuser -s user
```
:::note warn
注意
createuserの存在するディレクトリは、postgresのインストール方法やバージョンにより異なる。
上のコマンドを使ってuser作成を行う場合は`$ which postgres`などを用いてインストールディレクトリを確認すること。
:::
何も考えずにコマンドを実行…
見かけ上は接続できて喜んでたけど
このあたりで「これってローカルで建ってるサーバーに対して操作行ってるじゃん」と気づく。

試しに`$ docker rm -f postgres_postgresdb`したら、コンテナを終了・削除しているのにDBへ接続できてしまった。

## 原因：思考停止

結局のところ、homebrew経由でpostgresが実行されていたため、ローカルですでにpostgresのDBサーバーが建っていた。

```console
$ brew services list
Name          Status  User          File
postgresql@15 started user          ~/Library/LaunchAgents/homebrew.mxcl.postgresql@15.plist
```

`$ brew services stop postgres`した結果、dockerのコンテナで建ってるpostgresに無事アクセスできた。最初の`$ docker run -d [なんたら]`コマンドは何も間違ってなかった。

ローカルでサーバーが建っているって感覚なかったなぁ…。
言われてみりゃその通りだが…。
そしてpostgresDBをローカルで建てるためにいらんコンピュータリソースを使ってたんだなぁと恥ずかしくなった。
RubyでAtCoder ABC251(A, B, C)を解いてみた

# はじめに
Webエンジニアを目指して、RubyやRailsをいじってます。
今回は、RubyでAtCoder ABC251のA, B, Cを解きました。備忘録として解き方をまとめていきたいと思います。

# A - Six Characters
https://atcoder.jp/contests/abc251/tasks/abc251_a
```ruby:a-251.rb
s = gets.chomp
puts s * (6 / s.size)
```

# B - At Most 3 (Judge ver.)
https://atcoder.jp/contests/abc251/tasks/abc251_b
```ruby:b-251.rb
_, w = gets.split.map(&:to_i)
a = gets.split.map(&:to_i)

puts [*1..3].map{|i| a.combination(i).map(&:sum) }.flatten.uniq.count{ |weight_sum| weight_sum <= w}
```
## 解説
問題文の通りに、要素から1～3個それぞれ取得しその合計がw以下となるものを求めることで解くことができます。

# C - Poem Online Judge
https://atcoder.jp/contests/abc251/tasks/abc251_c
```ruby:c-251.rb
n = gets.to_i
array = Array.new(n){ gets.split }

hash = {}
array.each_with_index do |(str, score), index|
  next if hash[str]
  hash[str] = [index + 1, score.to_i]
end
puts hash.values.max_by{ |index, score| score }.first
```
## 解説
問題文の通りに、オリジナルの提出のうち得点が最大のもの（複数あれば最も提出が早いもの）が何番目か求めることで解くことができます。

https://qiita.com/shoya15/items/50fd17e37d7c64f2b166
８年続いたアプリを新アプリに移行した話

「スマホをやめれば魚が育つ」というアプリを新しく刷新することにした。理由はユーザー本人が自分に対して使用アプリを制限できるフレームワークをAppleが解禁したからだ。ScreenTime APIの中のFamilyControls。このフレームワーク自体はiOS15からあったのだが、名前のとおり親が子のスマホを制限することに特化していた。そしてiOS16になって初めてユーザーが自分自身のiPhoneに使用制限をかけれるようになったのだ。これはアプリが他のアプリを制限できるという、機能的にはiPhoneが誰かにハックされたような現象を起こすことができる。
```swift
//子供のスマホを制限する許可をリクエスト(iOS15~)
AuthorizationCenter.shared.requestAuthorization(for: .child)

//ユーザー自身のスマホを制限する許可をリクエスト（iOS16~）
AuthorizationCenter.shared.requestAuthorization(for: .individual)
```
「スマホをやめれば魚が育つ」では擬似的にアプリから離れさせないように監視してスマホをやめさせるというというのを実現していた（実際には不完全で100%は無理だった）。アプリの起動時と終了時に呼ばれるデリゲートメソッドを駆使して無理矢理にユーザーがアプリを離れたことを察知する。これをトリガーとして収集していたアイテムを消してしまう。ユーザーはアイテムが欲しいので頑張ってスマホを閉じたままほかの作業をする。

同様の機能をもつ第一人者的なアプリでForestがある。仕事効率化カテゴリの有料アプリでは世界的にトップランクに君臨するスーパーアプリだ。このアプリはユーザーがスマホを離れていればいるほど植物が育つというものだ。
[Forest](https://apps.apple.com/jp/app/forest-%E9%9B%86%E4%B8%AD%E5%8A%9B%E3%82%92%E9%AB%98%E3%82%81%E3%82%8B/id866450515
)

私はこのアプリがリリースされた直後から絶対需要があると注目していた。しかしそのときはまったくプログラム技術が無く、数年かけていくつかのアプリをリリースしたのち、ようやく似たようなものが作れそうだと思えて１年弱かけて制作したのが「スマホをやめれば魚が育つ」（以下スマやめ）だ。

Forestはネイティブで製作されている。スマやめはUnity製だ。Forestを超えたくてもっとゲーム性の高い内容にしようとしてUnityを選んだのだ。しかしアプリの終了と起動の察知がキモの機能なのでUnityとネイティブの連携には本当に苦労した。Appleはアプリ側からユーザーがiPhoneを使っているかいないかを察知することを正式には許可していないのだ（プライバシー的な問題だろうと納得していた）。どう抜道を探しても離脱の判定は98%ほどの正確さにとどまってしまっていた。これはForestも同じだった。

で、先述のiOS16がリリースされて前提が一変した。コロナを経てiPhoneやデジタル機器との関係をより規律のあるものにしたいという社会のニーズにAppleが応えたのだ。このことはApple公式の動画でも語られている。
[What's new in Screen Time API](https://developer.apple.com/videos/play/wwdc2022/110336/)

で、がんばってできたのがこれ。
[新・スマホをやめれば魚が育つ](https://apps.apple.com/jp/app/%E6%96%B0-%E3%82%B9%E3%83%9E%E3%83%9B%E3%82%92%E3%82%84%E3%82%81%E3%82%8C%E3%81%B0%E9%AD%9A%E3%81%8C%E8%82%B2%E3%81%A4/id1669133971)

疲れたのでおしまい、技術的なことは私の他の記事見てね。UnityとSwiftUIの連携がもうダメかと泣きたくなるほど難しかったよ。
Bootstrap-Datepickerで複数のformatを指定する

# 環境

- Bootstrap-Datepicker ver.1.9を使用(1.10でも動作確認済)

# やりたいこと

複数のformatで入力したい。
例えば、'yyyy/mm/dd' でも 'yyyymmdd' でも入力可能にしたい。
しかし、設定ではformatは1つしか設定できない。

# 解決方法

※moment.js を使用（現在開発が終了しています。新規プロジェクトの場合、同等の別ライブラリを使ってください）

```javascript
format : {
	// 入力欄の表示の際の整形処理
	toDisplay(data, format, language) 
	{
		return moment(date).format('YYYY/MM/DD');
	},
	// 入力値のDateへのパーズ処理
	toValue(data, format, language)
	{
		// YYYY/MM/DDでもYYYYMMDDでも受け付ける
		const m = moment.utc(date, ['YYYY/MM/DD', 'YYYYMMDD']);
		const dt = m.isValid()? m.toDate() : null;
		return dt;
	},
}
```

上記のように、toDisplay関数とtoValue関数を設定する。

https://bootstrap-datepicker.readthedocs.io/en/stable/options.html#format

toDisplayは、入力欄に表示したい日付文字列を返すようにする。
toValueは、入力欄の文字列を日付に変換して返すようにする。nullを返すと当日として扱われる。

# 注意点

```javascript
	const m = moment.utc(date, ['YYYY/MM/DD', 'YYYYMMDD']);
```

上記部分で「utc」としているのは、入力値をUTCとして処理しないと、Bootstrap-Datepicker内部ではDateオブジェクトからgetUTCMonth()とかして月の数値を求めており、時差の分ずれてしまうことがある為。

utcにしないと、例えば`'2023/04/01'`と入力しているのに`2023/03/31`がカレンダー上で選択される。
1x1のGIF・PNGファイル（透過/base64）



# GIF形式（39bytes）

```
data:image/gif;base64,R0lGODlhAQABAGAAACH5BAEKAP8ALAAAAAABAAEAAAgEAP8FBAA7
<img src="data:image/gif;base64,R0lGODlhAQABAGAAACH5BAEKAP8ALAAAAAABAAEAAAgEAP8FBAA7" alt="" height="1" width="1"> 

```

# PNG形式（68bytes）
　
```
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQI12NgYAAAAAMAASDVlMcAAAAASUVORK5CYII=

img='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQI12NgYAAAAAMAASDVlMcAAAAASUVORK5CYII=';

```
【Android】Activity起動時にviewサイズを取得する

# 概要
Activity起動時にviewサイズを取得する方法について解説。

# 方法1: onGlobalLayoutを使用

`addOnGlobalLayoutListener`でレイアウト変更時のリスナーを追加。
`onGlobalLayout`メソッド内でViewサイズの計測を行う処理+リスナーの削除を行う。

```MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
	super.onCreate(savedInstanceState)
	setContentView(binding.root)

	binding.view.viewTreeObserver.addOnGlobalLayoutListener(object : OnGlobalLayoutListener {
		override fun onGlobalLayout() {
			Log.i("", "width:" + binding.view.width + ", height:" + binding.view.height)
			binding.view.viewTreeObserver.removeOnGlobalLayoutListener(this)
		}
	})
}
```

# 方法2: postを使用
`post`を用いることで、先ほどの処理より簡潔&直観的に記述できる。
```MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
	super.onCreate(savedInstanceState)
	setContentView(binding.root)

	binding.view.post {
		Log.i("", "width:" + binding.view.width + ", height:" + binding.view.height)
	}
}
```

# 方法3: onWindowFocusChangedを使用
この方法だとフォーカスが変更されるたびに呼び出されるようなので、個人的にはあまりおすすめしない。
```MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
	super.onCreate(savedInstanceState)
	setContentView(binding.root)
}

override fun onWindowFocusChanged(hasFocus: Boolean) {
	super.onWindowFocusChanged(hasFocus)
	Log.i("", "width:" + binding.view.width + ", height:" + binding.view.height)
}
```

# 参照
https://stackoverflow.com/questions/18861585/get-content-view-size-in-oncreate
【ChatGPT無＋Windowsバッチ】作ったBackupバッチ完成（手直しあり）


　どうも、カーブミラーです。

　前回のこちら

[【ChatGPT＋Windowsバッチ】目標達成まで、時間が掛かる（悲）　最後に注意点あり。](https://qiita.com/kabumira/items/184bd67950895ad9ec22 "")

　は、少し煮込みが甘かったですかね？


　今回は、最終的にできあがったものをお見せいたします。
　でも、単なるBackupバッチですからね。
　期待しないでくださいまし。
***
　まずは、目標ですね。

　年・月・日を取得して、
　　Backupディレクトリの下に、
　　　"bk"+"yyyymmdd"ディレクトリ作成
　そこにカレントディレクトリにある
　　テキストファイル（.txt）と
　　　JavaScriptファイル（.js）をコピー

　それで、ChatGPTに尋ねながら
　　最終的な状態になるまで、煮詰める。

　煮詰まったら、まとめて編集して
　　最終的プロンプトにする。

　以下は、その最終的プロンプトです。
```batch:プロンプト
次の流れで、Windowsのバッチファイルを作成してください。

1. 日付の表示形式を "yyyy/mm/dd" に一時的に変更する。
2. 日付の取得と加工:
   - 日付を取得し、スラッシュを削除する。
   - 先頭に "bk" を追加した修正された日付を作成する。
3. ディレクトリの作成:
   - 修正された日付を名前とするディレクトリを作成する。
4. ファイルのコピー:
   - 現在のディレクトリにあるテキストファイルを作成したディレクトリにコピーする。
   - 現在のディレクトリにある JavaScript ファイルを作成したディレクトリにコピーする。
```

　このプロンプトから
　　Backupバッチが生成されるので、
　　　Backup.batにコピペして、
　　　　修整します。

　修整したのは、
　　「日時を取得」のところで、
　　日本式にしたのに、
　　どうしても米国式で、
　　年月日を取得をしようとする部分だけ。

　"yyyy/mm/dd"（日本式）なのに
　　"mm/dd/yyyy"（米国式）で取得

　ここを日本式に、手直し。
　それとBackupディレクトリに作ることを
　　盛り込んでいなかったので、
　　　手で追加。

　最終的なBackupバッチです。
```batch:Backup.bat
REM バックアップバッチファイル
REM  chatGPTが作成したものを少し修正

@echo off

REM 日付の表示形式を"yyyy/mm/dd"に一時的に変更する
setx DATEFMT "yyyy/MM/dd"

REM 日時を取得
for /F "tokens=1-3 delims=/" %%a in ('echo %date%') do (
    set "year=%%a"
    set "month=%%b"
    set "day=%%c"
)

REM 日時からスラッシュを削除、先頭に"bk"を追加（Backupは自分で入れた）
set "date_without_slash=%year%%month%%day%"
set "modified_date=bk%date_without_slash%"
set "directory_name=Backup\%modified_date%"

REM ディレクトリ作成
mkdir "%directory_name%"

REM 日付の表示形式を戻す
setx DATEFMT ""

REM テキストファイルをコピー
copy *.txt %directory_name%

REM JavaScriptファイルをコピー
copy *.js %directory_name%
```
となりました。

　ね、期待したほどではなかったでしょうw
　自分でもこんなに時間を掛けるつもりは
　　なかったんですけどねぇ（悲）
***
　でもでも
　記事を書き終わって
　　気付いてしまったのです。
　Google BardやBingでやれば、
　　もっと早く出来上がっただろう、と。

　でも、それだとChatGPTを使う意味が
　　ないではありませんか！
　いや、まぁ、そっちで記事を書けば、
　　それはそれで、あり、なんですけどね。
　　　Bingは、中身GPT4なんですから。

　ということで、
　　今回のお題はこれで終わりです。
　　いずれ、またやる……かも。
docker composeとは

## docker-composeとは

複数のDockerコンテナを定義し、管理するためのツール
→複数のコンテナで構成されるアプリケーションを簡単に構築・実行・管理するために使用される

## 使い方

### Docker composeファイルの作成

Docker compose：YAML形式の不カイルで定義された設定を使用

プロジェクトのルートディレクトリに docker-compose.yml という名前のファイルを作成して、コンテナの構成や設定を記述する


### コンテナの定義

Docker composeファイル内で、各コンテナの設定を定義
　EX)コンテナのイメージ、ポートのマッピング、環境変数などを指定


### サービスの起動

docker composeを使ってコンテナを起動するときにこのコマンドを使う
```
docker-compose up
```
→Docker composeファイルに定義されたコンテナが起動される
☆コンテナのイメージが存在しない時は自動的にダウンロードされる


### サービスの停止
起動したコンテナを停止するためにこのコマンドを使う

```
docker-compose down
```

→Docker composeファイルに定義されたコンテナが停止される


## docker composeを使うメリット

:::note
複雑なアプリケーションの構築や複数のコンテナの管理を簡素化できる
:::
16進数を10進数にする

## １６進数

0~9A~Fで数値を表す

| 10進数 | 16進数 |
| --- | --- |
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 7 |
| 8 | 8 |
| 9 | 9 |
| 10 | A |
| 11 | B |
| 12 | C |
| 13 | D |
| 14 | E |
| 15 | F |
| 16 | 10 |
| 17 | 11 |
| 18 | 12 |

9から10になるように
Fから10になる

# 計算方法

問　28(16進数)を10進数にする

答　(16×2) + 8 = 40となる

なぜなら

10(16進数)　=　16(10進数)

20(16進数)　=　32(10進数)

30(16進数)　=　48(10進数)

つまり

(16×二桁目の値)　=　10進数の値

となるので

**先に二桁目を計算したあと、一桁目の数字を足すと計算しやすい**

## 計算例

28(16進数)

(16×2) + 8 = 40

4B(16進数)

(16×4) + B = 75 　※B=11

EA(16進数)

(16×E) + A = 234　※E=14,A=10
CodeBuildでのS3キャッシュのタイムスタンプの扱いを調べてみる

CodeBuildでのS3キャッシュで保存しているファイルのタイムスタンプが、CodeBuild前回実行時の日時を保存されているかどうかを実際に動かして確認してみました。

前回の記事の続きです。

https://qiita.com/suzuki-navi/items/6ba9c3e6eda4baa01e6f


# わかったこと

- S3キャッシュから復元されるファイルは、前回ビルド実行時のファイルタイムスタンプを維持している
- 実際にはキャッシュ対象をtar.gzで固めたものがS3に保存されている
- ただしtar.gzの中のディレクトリ構成は独自フォーマットになっており、tar.gzから手動で復元するのは困難


# ついでにわかったこと（はまったポイント）

`buildspec.yml` でのキャッシュさせたいパスの書き方に注意です。ディレクトリの中をサブディレクトリも含めて丸ごとS3にキャッシュさせるには以下のように `**/*` という記述が必要です。

```yaml
  cache:
    paths:
     - 'var/**/*'
```


# S3キャッシュの設定方法

1.​
CodeBuildのマネジメントコンソールでCache type: S3を選択し、S3バケットを指定します。S3バケットのプレフィックスも指定可能です。プレフィックスを指定しないとファイルがバケット直下にできます。S3にはファイルが1つに固められます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490207/66d8921d-c77f-d708-b35d-69899a63c93a.png)

2.​
`buildspec.yml` にキャッシュしてほしいファイルやディレクトリを指定します。

```yaml
version: 0.2
phases:
  pre_build:
    commands:
      - ...
  build:
    commands:
      - ...
  post_build:
    commands:
      - ...
cache:
  paths:
   - 'var/**/*'
```

キャッシュしてほしいパスの書き方に注意です。ディレクトリの中をサブディレクトリも含めて丸ごとS3にキャッシュさせるにはディレクトリ名の後ろにワイルドカードを並べて `var/**/*` という記述が必要です。ディレクトリ直下のファイルだけでよく、サブディレクトリの中はキャッシュ不要の場合は `var/*` と書きます。ディレクトリ名の `var` だけだとなにもキャッシュしてくれません。


# やってみたこと

前回と同様に `buildspec.yml` に `find . -ls` を記載するほか、 `touch` コマンドの実行もファイルパスをいろいろ変えながらCodeCommitを複数回実行してみました。

`buildspec.yml` のサンプルです。途中で `touch` コマンドがありますが、ここでtouchするファイルのディレクトリやファイル名を毎回変えてみて試しました。

```yml
version: 0.2
phases:
  pre_build:
    commands:
      - echo begin
  build:
    commands:
      - find . -ls
      - mkdir -p var
      - find . -ls
      - touch var/test.txt
      - find . -ls
  post_build:
    commands:
      - echo end
cache:
  paths:
   - 'var/**/*'
```
Ruby silver 模擬問題解説6

Ruby silverの模擬問題を抜粋して解説をしていきます。

下記コードの実行結果を4択から選ぶ問題になっています。
```ruby
0x65.chr(Encoding::UTF_8)
```

1.“e”
2.“あ”
3.エラーとなる
4.“A”

まず、0x65は16進数表記で数値としては101を表しています。

次に'.chr'メソッドはASCⅡコードで表示された数値を文字列に変換するメソッドになります。
['.chr'公式リファレンス](https://docs.ruby-lang.org/ja/latest/method/Integer/i/chr.html)

ただ、今回の場合は引数にUTF-8エンコーディングに対応する文字を返すと指定されています。
```ruby
.chr(Encoding::UTF_8)
```
101のUTF-8のエンコーディングは'e'になりますので、解答としては1番になります。
ディレクトリ移動で使うコマンド

## 現在のディレクトリの表示
```
pwd
```

## ディレクトリの一覧表示
```
ls
```

## ディレクトリの移動
```
cd [ディレクトリパスを書く]
```

## 上位ディレクトリへの移動
```
cd
```

## ホームディレクトリへの移動
```
cd ~
```
Arduino > String to interger > toInt() のマニュアルに無いふるまい

String toInt() のマニュアルに無いふるまい　忘備録


入力 String: 44
Value:44

入力 String: -44
Value:-44

入力 String: +44
Value:44

入力 String: 44-22
Value:44

符号も変換してくれる。

計算は出来ない。

が、便利ですね
WSL上でVSCodeをインストールして開くまでの手順

## wslでVSCodeを開く

### wslディストリビューションを起動

WSLディストリビューション（ubuntuなど）を起動
ターミナルを開いてディストリビューションを起動

### wslディストリビューション内でVSCodeをインストール

以下のコマンドを使用
```shell
sudo apt update
sudo apt install code
```
### VSCodeを起動

以下のコマンドを使用

```shell
code
```
トレイトとは？クラスとどう違うのか

Laravelの学習中にAuth関連の機能を調べていると、トレイトという概念が登場しました。トレイトとは一体何なのか、どのように機能し活用できるのか疑問に思いました。

本記事では、トレイトとは何なのか、クラスとの関係はどのようなものなのかを初学者の視点からわかった範囲で解説します。

## クラス・トレイトとは
まず、クラスとトレイトの定義を以下に示します。

**クラス（Class）**
クラスはオブジェクトの設計図のようなものである。オブジェクトの属性（データ）や振る舞い（メソッド）を定義する。クラスは同じ種類のオブジェクトを作成するためのテンプレートとして機能する。

**トレイト（Trait）**
トレイトは、PHPのような単一継承言語でコードを再利用するための仕組みである。トレイトは複数のクラスで共通のメソッドやプロパティを提供することができ、クラスが複数のトレイトを利用することで、複数の機能を組み合わせることができる。

**トレイトは、クラスの継承では実現が難しい場合や、複数のクラスで共通の機能を再利用したい場合に特に役立ちます。**

### 具体例

以下にAnimal Classを作成しました。
このクラスでは動物の設計図を表しています。eat()メソッドとsleep()メソッドを持ち、それぞれ食事と睡眠の動作を表しています。

```
class Animal {
    public function eat() {
        echo "The animal is eating.";
    }

    public function sleep() {
        echo "The animal is sleeping.";
    }
}
```


次に、SwimTraitというトレイトを作成します。
このトレイトはswim()メソッドを持ち、動物が泳ぐという機能を提供しています。

```
trait SwimTrait {
    public function swim() {
        echo "The animal is swimming.";
    }
}
```

これらのクラスとトレイトを組み合わせて動物の特徴を表現してみます。

```
class Dolphin extends Animal {
    use SwimTrait;
}
```
```
class Dog extends Animal {

}
```

上記の例では、DolphinクラスがAnimalクラスを継承しているだけでなく、SwimTraitというトレイトを利用しています。これにより、Dolphinクラスはeat()メソッドとsleep()メソッドを持ちつつ、swim()メソッドも利用することができます。

一方、dogクラスはトレイトによる追加の機能を持っていません。ただし、DogクラスはAnimalクラスから継承したeat()メソッドとsleep()メソッドを利用することができます。

このように、トレイトを使うことで異なるクラスに共通の機能を再利用できます。この例では、SwimTraitを利用して泳ぐ機能を追加したDolphinクラスを作成しました。

## LaravelのAuth関連の機能で使用されているトレイト

Laravelでは、ユーザー認証やアクセス制御のためにAuthトレイトが提供されており、クラスに認証機能を追加することができます。例えば、以下のようにUserControllerクラスにAuthトレイトを追加すると、ユーザーの認証やアクセス制御に関する機能を簡単に利用できるようになります。
```
use Illuminate\Foundation\Auth\AuthenticatesUsers;

class UserController extends Controller　{
    use AuthenticatesUsers;

    // UserController固有のメソッドを記述する
}
```
Authトレイトには、ログイン、ログアウト、パスワードリセットなどの機能が含まれています。Authトレイトを利用することで、UserControllerクラスに認証機能を追加することなく、既存のコードを再利用できます。

## トレイトを使用するメリット

### コードの再利用ができる
トレイトを使用することで、複数のクラスで共通の機能を再利用できます。同じ機能を複数のクラスに実装する必要がなくなり、コードの冗長性を減らすことができます。

### 単一継承の制限を回避できる
PHPでは、クラスの継承は1つの親クラスに限定されますが、トレイトを使用することで複数のトレイトを同時に利用できます。これにより、異なる機能を組み合わせた柔軟なクラスの設計が可能になります。

### 機能のカプセル化 
トレイトは独立したコードのまとまりであり、機能を明確にカプセル化することができます。特定のトレイトを利用することで、その機能の有効化や無効化が容易になります。


**LaravelのAuthトレイトのように、共通の認証機能を複数のクラスで利用する場合には、トレイトが非常に有用です。**

## トレイトを使用するデメリット

### 名前の衝突（Name Collision）
複数のトレイトが同じメソッド名やプロパティ名を持つ場合、名前の衝突が発生する可能性があります。この場合、どのメソッドやプロパティを使用するかが曖昧になり、予期しない結果につながる可能性があります。

### 可読性の低下
トレイトを多用すると、クラスの機能がどのように構成されているのか把握しにくくなる場合があります。トレイトは複数のクラスで共通のコードを提供するため、クラスの全体像が分散される可能性があります。

### 静的解析の困難さ
トレイトを使用すると、コードの静的解析が難しくなる場合があります。静的解析ツールは、クラスの階層構造やメソッドのオーバーライド、トレイトの使用方法などを正確に解析する必要があります。

### コードの複雑化
トレイトを多用すると、クラスの機能が複雑化し、メンテナンスやデバッグが困難になる可能性があります。トレイトの使用は慎重に行う必要があります。

## まとめ

トレイトの使用により、コードの再利用性と柔軟性を向上させることができます。しかし、名前の衝突や可読性の低下などのデメリットにも注意が必要です。安易に多用すると訳分からなくなりそうなので気をつけようと思います。
pstファイル（Outlookデータファイル）のBOXへの保存

pstファイルをBOXに保存しようとしたら「ファイル名が無効かまたは長すぎます」というエラーが出て保存できない。

<A HREF="https://support.box.com/hc/ja/articles/360044195433-Box-Sync%E3%81%A8Box-Drive%E3%81%A7%E7%84%A1%E8%A6%96%E3%81%BE%E3%81%9F%E3%81%AF%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF%E3%81%95%E3%82%8C%E3%82%8B%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E7%A8%AE%E9%A1%9E" target=_blank >BOXのサポートページ</A>を見ると、pstファイルは『Box SyncとBox Driveでブロックされるファイルの種類』に含まれている模様。

ただ、「これらのファイルの種類は、Boxウェブサイトを通じてBoxにアップロードして保存できますが、Box Syncには認識されません。 同期対象フォルダにある場合でも同期されません。」となっているので、
<b>エクスプローラー経由のコピーではなく、ブラウザー経由のコピーなら保存可能。</b>

outlookメールアーカイブ(pst)のBOXへの保存が無事できた^^
WordPress6.3で色々ゴタゴタした話

問題：WordPressをアップデートしたらショートコードが動いてない
--

「なんか、サイトによくわからない英語が表示されてるんですが」
見てみると独自ショートコードが実行されずまんま出力されている

（あ・・これあかんやつや）

経験上このタイプのトラブルはWordPressの仕様変更などに起因していて、往々にして少しの修正では済まないし、場合によっては実質対応が不可能な場合さえある。



原因：ブロックテーマでは剥き出しのショートコードは動かなくなった
--

同じショートコードを使っていても、ブロックテーマではないサイトでは問題なく動いている、ブロックテーマのサイトでもWordPressのアップデートがまだのサイトでは動いている、WordPressのブロックテーマ周りの仕様変更がどうやら原因のようだ。
一部ショートコードが動かなくなったサイトでも、同じショートコードが動いているところもある、違いはどうやら、テンプレートエディタで直接設置されたブロックであるかどうかというところのようだ。

対応：テンプレートはテンプレートパーツを組み合わせて編集するルールに
--

調べたところ、テンプレートエディタに書かれた剥き出しのショートコードを動かないようにしたのはセキュリティ上の懸念があってのことということなので、無理矢理これを動かせるようにするのはあまりよろしくないようだ。

テンプレートパーツブロックに入れることでショートコードが実行されるようなので、テンプレートエディタで剥き出しになっているブロックをテンプレートパーツに入れてショートコードを動くようにした。テンプレート編集の際は、まずテンプレートパーツを作ってテンプレートはそれを組み合わせて作るというルールを徹底してもらうことにしてショートコードが実行されない問題は解決。

かと思った。

問題：まだ動かないショートコードがいる
--

とりあえずショートコードの実行自体はされるようになったようだとホッとしたのも束の間、意図しない出力をするやつ、出力がされないやつ、やっぱり実行されないやつがいる。見たところサーバーサイドレンダーを使っているものやループのコンテキストに依存したショートコードが動いていないようだ。

原因：ブロックテーマではdo_shortcodeの後にdo_blocksが実行される
--

ブロックテーマではdo_shortcodeがdo_blocksより先に実行される。これがどういうことを意味するかというと、ブロックがrender_callbackでショートコードを出力しても実行されないし、逆にrender_callbackが受け取るcontentsはすでにショートコードが実行されてしまっているということである。

```php:wp-includes/block-template.php
	$content = $wp_embed->run_shortcode( $_wp_current_template_content );
	$content = $wp_embed->autoembed( $content );
	$content = do_blocks( $content );
	$content = wptexturize( $content );
	$content = convert_smilies( $content );
	$content = shortcode_unautop( $content );
	$content = wp_filter_content_tags( $content, 'template' );
	$content = do_shortcode( $content );
	$content = str_replace( ']]>', ']]&gt;', $content );
```
参照：[get_the_block_template_html](https://developer.wordpress.org/reference/functions/get_the_block_template_html/)


ブロックテーマでなければ、do_blocksが全部終わった後に適用されるthe_contentフィルタフックのdo_shortcodeでまとめて実行されていた。なので、render_callbackでループを書いてcontents内のショートコードをグローバル変数を変えながら実行したり、あるいはショートコードを出力して、親ブロックのコンテキストでそのショートコードを実行するなんてことができていたのだが、これができなくなってしまった。


対応：独自ショートコードをWordPressのショートコードから独立して処理
--

とりあえず、原因特定まではそれほど時間が掛からなかったが、これはWordPressの処理を読み直さなければ適切に対処ができない、時間がかかる問題だということも同時にわかった。
なので一旦は応急処置でrender_callbackとショートコードを組み合わせて使わないブロックに置き換えた。見た目が少し変わってしまったところもあるものの、内容としては同じものが表示されている状態までは復旧できた。
表向きは問題は解決したわけが、ここからが本番。

フィルタフックでどうにかできないものかと、ブロックテーマでコンテンツがどのように出力されているのかWordPressのコードを追ってみたがこれはどうにもなりそうになかった、そもそもフィルタフックがほとんどなかった。

独自ショートコードの登録を遅らせるなども試みたが、ショートコードを実行したいタイミングの後でまたショートコードを実行したくないタイミングがあったりして断念した。

結局、独自ショートコードをWordPressのショートコードとして登録することはせず、独自ショートコードの実行を自前で実装してcore/template-part及びthe_contentのフィルタフックで処理するというおよそ力技な方法で対処した。
実のところ、hrefとかclassとかでショートコードが使えるようにhtmlの属性値内のショートコードを実行したい需要もあったので丁度良かった。


まとめ
--

今回のWordPress6.3のブロックテーマでのショートコードの扱いに関する変更への対応は、ブロックのrender_callbackでの入出力に絡んだところで問題が起きた場合は簡単な対処方法はないようだ。
Power Automateでアクションをコピー&ペーストする

# 結論
コピーはアクションのメニュー項目から行えます。
ペーストはアクションの選択項目から行えます。

# 手順
### コピー
1. コピーしたいアクションの右上にある3つの点をクリックします。
1. 表示されたメニュー項目の中から「クリップボードにコピー」をクリックします。
![power_automate_コピペ_投稿版1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3071987/33dd2220-6add-bc74-8ea9-e5292603962a.png)
### ペースト
1. 「新しいステップ」などをクリックしてアクションの選択項目を表示します。
1. 選択タブの右にある「自分のクリップボード」をクリックします。
1. コピーしていたアクションが表示されているため、それをクリックするとアクションがペーストできます。
![power_automate_コピペ_投稿版2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3071987/28032823-22fe-5506-ca12-2ec4648ea50c.png)

以上です。
【Heroku】デプロイ時エラー error: failed to push some refs to 



# ◼️はじめに
Herokuにデプロイした際に
`error: failed to push some refs to `
のエラーが発生したので記録しておきます。


# ◼️やったこと
1.新しくHerokuのurlを取得
```
$ heroku create
```
2.Gemfileに以下のgemを追加
```:Gemfile
gem 'net-smtp'
gem 'net-imap'
gem 'net-pop'
```
3.インストール
```
$ bundle install
```
4.Heroku buildpackを追加
```
$ heroku buildpacks:set heroku/ruby
$ heroku buildpacks:add --index 1 heroku/nodejs
```
5.HerokuにPostgreSQLのアドオン追加
```
$ heroku addons:create heroku-postgresql
```
6.Herokuにデプロイ
```
$ git push heroku master
```

# ◼️エラー発生
`git push heroku master` をするとエラーが発生
![スクリーンショット 2023-06-01 11.23.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3468263/fb88d6ad-681c-5df6-8e73-1e8a802a34fd.png)

## ▼原因
stackのバージョンが違うためエラーが出ている

## ▼対応
1.stackのバージョンを確認
```
$ heroku stack
```
2.heroku-22になっていることが判明
![スクリーンショット 2023-06-01 11.53.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3468263/e39133ea-6b01-7e74-0599-9092fc0334eb.png)
3.以下コマンドでheroku-22からheroku-20へ変更する
```
$ heroku stack:set heroku-20
```


# ◼️エラー発生②
`heroku run rails db:migrate`をするが再度エラー発生
Bootstrap記載漏れやJavascripを消去したりする中でこのエラーに出会う

![スクリーンショット 2023-06-01 12.07.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3468263/0b72765b-0dfd-9504-0815-e24fd70b41a4.png)

## config/database.yml ファイルの記述に注目
PostgreSQLの場合
```
default: &default
  adapter: postgresql // ここがPostgreSQL
  encoding: unicode
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
```
となるところを、rails newの時にPostgreSQLを指定していないと以下の記載になるそうです。
```
default: &default
  adapter: sqlite3 // ここがSQLite3
  encoding: unicode
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
```
そのため以下原因に辿り着きました。
(通っているスクール(Dpro)のメンターさんにご教授頂きました🙇)

## ▼原因
Railsアプリをrails newしたとき、DBをPostgreSQLにするオプションを忘れていたのが原因...
まだまだ慣れておらず単純なことを失念しておりました...

## ▼対応
1.SQLite3 から PostgreSQL へ変更するコマンドを実行
```
$ rails db:system:change --to=postgresql
```

2.以下、を行いデプロイ完了
`rails db:migrate`
`git add .`
`git commit`
`git push heroku master`
`heroku run rails db:migrate`

# ◼️最後に
初めてのHerokuデプロイで、エラーがいくつも発生し時間を費やしてしまいましたが、
エラー原因は単純なことでした。
初歩的なミスをなくしていけるように精進します。

# 参照
Heroku
https://devcenter.heroku.com/ja/articles/stack
Rails 6 で DB を SQLite3 から PostgreSQL に変更するのはコマンド一発
https://k-koh.hatenablog.com/entry/2020/08/14/144129
Delphi　procedureってなに

## Delphi procedureとは

:::note

特定のタスクや操作を実行するための独立したブロックまたはサブルーチンを定義するために使用されるキーワード

:::

Delphiの「procedure」は、関数（function）と対比されるもの
→値を返さずに特定の処理を実行



### 戻り値のない処理
特定の処理やタスクを実行するだけ
戻り値を返値を返す必要がない場合に使用

### パラメータの受け渡し
引数（パラメータ）を受け取ることができる
パラメータを使用することで、procedure内で必要なデータを渡せる

### 再利用性とモジュール性
特定の処理をまとめて独立したブロックとして定義する
→コードの再利用性とモジュール性を高められる
複数の場所で同じ処理を行う必要がある場合や、大きなプログラムを論理的な単位に分割する場合に便利

## Delphiでのprocedureの簡単な定義

~~~delphi
procedure ShowMessageDialog(Message: string);
begin
  // メッセージを表示する処理
  ShowMessage(Message);
end;
~~~

"ShowMessageDialog"という名前のprocedureが定義されている
→このprocedureは、引数として文字列のメッセージを受け取り、それを画面に表示する処理を行う
sqlalchemyでpandasのdatetime型をMySQLに1行ずつInsertする方法

# 解決したい問題
sqlalchemyでMySQLにpandasのdatetime型を1行ずつInsertしたい場合があるかと思います。
そのときに、pandasのdatetime型をそのまま挿入しようとするとエラーになります。

例えば以下のようなサンプルコードを考えます。
```python
from sqlalchemy import create_engine, Table, MetaData, Column, DateTime
import pandas as pd

# pandasのdatetime型の列を持つDataFrameの作成
df = pd.DataFrame(pd.to_datetime(["2023-01-01 00:00:00"]), columns=["sample_datetime"])

# sqlalchemyの設定
engine = create_engine('mysql+mysqlconnector://root:root@mysql_host/test_database')
metadata = MetaData()
table = Table('sample_table', metadata, Column('sample_datetime', DateTime))
metadata.create_all(engine)

# データを挿入
with engine.connect() as connection:
    for _, row in df.iterrows():
        connection.execute(table.insert().values(**row))
```
このとき、以下のようなエラーが表示されます。
```
sqlalchemy.exc.ProgrammingError: (mysql.connector.errors.ProgrammingError) Failed processing pyformat-parameters; Python 'timestamp' cannot be converted to a MySQL type
[SQL: INSERT INTO sample_table (sample_datetime) VALUES (%(sample_datetime)s)]
[parameters: {'sample_datetime': Timestamp('2023-01-01 00:00:00')}]
```

# 解決法
解決方法は至ってシンプルで、`astype(str)`によってdatetime型の列をstr型に変換すればうまくいきます。
```python
df["sample_datetime"] = df["sample_datetime"].astype(str)
```

# 検証環境
- Python 3.9.12
- sqlalchemy 1.4.42
- MySQL 5.7

# 備考
なお
```python
df.to_sql('sample_table', engine, if_exists='append', index=False)
````
のように記載して、一括してDataFrameをInsertするとエラーは発生しませんでした。
あくまで、DataFrameを1行ずつ処理したい場合の対処法ですので、ご留意ください。
ABC303に参加しました

## 概要

　今回はAtcoder Beginner Contest 303（2023年5月27日21:00~22:40）に参加したので振り返りがてら記事を書きます。

## A問題
https://atcoder.jp/contests/abc303/tasks/abc303_a


### コメント
- 愚直にif文で場合分けした
- どっかで見た、「1をl、0をoにあらかじめ置換しておいてSとTが一致するか判定」というのもよいなと思った

### 自分の実装
```Python:ABC_303_A.py
N = int(input())
S,T = input(),input()
ans = 1

for i in range(N):
  if (S[i] != T[i]):
    if((S[i] == "1" and T[i] == "l") or (S[i] == "l" and T[i] == "1")):
      ans = 1
    elif((S[i] == "0" and T[i] == "o") or (S[i] == "o" and T[i] == "0")):
      ans = 1
    else:
      ans = 0
      print("No")
      exit()
        
if ans == 1:
  print("Yes")
```

## B問題
https://atcoder.jp/contests/abc303/tasks/abc303_b


### コメント
- NとMが高々50だったので、2重ループの計算量でも特に問題なさそう
- 自分と隣り合ったことがある人の情報を記録する行列relationを用意して、隣り合ったことがあれば1、そうでなければ0になるようにして、最後にその数をカウントするという方針をとった
- 対称性を考えて2で割るのを忘れずに

### 自分の実装
```Python:ABC_303_B.py
N,M = map(int,input().split())
a = [list(map(int, input().split())) for l in range(M)]
relation = [[1] * N for i in range(N)]
count = 0

for i in range(N):
  relation[i][i] = 0

for i in range(M):
  for j in range(N-1):
    relation[a[i][j]-1][a[i][j+1]-1] = 0
    relation[a[i][j+1]-1][a[i][j]-1] = 0

for i in range(N):
  for j in range(N):
    count += relation[i][j]
    
print(count//2)
```

## C問題
https://atcoder.jp/contests/abc303/tasks/abc303_c


### コメント
- 制約が $\leq 2×10^5$ となっていて計算量を考える必要が出てきそうだなとか考えていた
- 問題の指示を愚直に実装していけたかなーって思ったらWAでハマる
- 途中でアイテムを使用した場合に配列からRemoveしてないことに気づいて直すもTLEで手詰まり
- 解説を見てSetを使えば行けるらしいことを知る

### 自分の実装(TLE)
```Python:ABC_303_C.py
N,M,H,K = map(int,input().split())
S = input()
xy = [list(map(int, input().split())) for l in range(M)]
current_tak = [0,0]

for i in range(N):
  if(N <= H):
    exit()
  
  else:
    if (S[i] == "R"):
      current_tak[0] += 1
      H -= 1
    elif (S[i] == "L"):
      current_tak[0] -= 1
      H -= 1
    elif (S[i] == "U"):
      current_tak[1] += 1
      H -= 1
    elif (S[i] == "D"):
      current_tak[1] -= 1
      H -= 1

    if (current_tak in xy) and (H >= 0) and (H < K): #こいつがTLEの原因っぽい
      H = K
      xy.remove(current_tak)
    elif (H < 0):
      print("No")
      exit()

if (H >= 0):
  print("Yes")
```

## 感想
計算量の壁にぶち当たる
そろそろC++も手を付けていきたい
Listとsetの計算量の違いに関しては、この記事がとても分かりやすかったです。
https://qiita.com/kitadakyou/items/6f877edd263f097e78f4
テスト

import PySimpleGUI as sg
import cv2
import threading
import time
import os

# 各カメラの設定を保存する辞書
cameras = {
    'camera1': {'interval': 10, 'folder': './'},
    'camera2': {'interval': 10, 'folder': './'},
    # 必要なだけカメラを追加
}

def capture_image(camera_id, folder):
    cap = cv2.VideoCapture(camera_id)
    ret, frame = cap.read()

    if ret:
        filename = os.path.join(folder, f'{camera_id}_{time.time()}.jpg')
        cv2.imwrite(filename, frame)

    cap.release()

def capture_images():
    while True:
        for camera_id, camera_info in cameras.items():
            capture_image(camera_id, camera_info['folder'])
            time.sleep(camera_info['interval'])

def start_capturing():
    threading.Thread(target=capture_images, daemon=True).start()

# レイアウトを定義
layout = [[sg.Text('Camera1 Folder'), sg.Input(key='-FOLDER1-'), sg.FolderBrowse()],
          [sg.Text('Camera1 Interval'), sg.Input(key='-INTERVAL1-')],
          [sg.Text('Camera2 Folder'), sg.Input(key='-FOLDER2-'), sg.FolderBrowse()],
          [sg.Text('Camera2 Interval'), sg.Input(key='-INTERVAL2-')],
          [sg.Button('Start Capturing')]]

# ウィンドウを作成
window = sg.Window('Camera App', layout)

while True:
    event, values = window.read()

    if event == sg.WINDOW_CLOSED:
        break
    elif event == 'Start Capturing':
        cameras['camera1']['folder'] = values['-FOLDER1-']
        cameras['camera1']['interval'] = int(values['-INTERVAL1-'])
        cameras['camera2']['folder'] = values['-FOLDER2-']
        cameras['camera2']['interval'] = int(values['-INTERVAL2-'])
        start_capturing()

window.close()
UiPath サーバーレス(Cloud - Serverless)で実行できない場合の解決方法

# はじめに
今回の記事は、
サーバーレスで実行する際に、エラーでハマったので、その解決方法を備忘録として書いたものとなります。同じエラーで悩んでいる方の手助けになれると嬉しいです。

# 前提条件
使っているのはAutomation Cloud Community Editionです。

# エラー内容
Orchestratorのマシン設定で、サーバレスマシンを作成し、実行したところ
エラーが発生し、詳細には以下の内容が記されていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218396/1ace9175-e2a5-23f4-9ac4-c4842c2763cb.png)
ロボットユニットがない？的なエラーメッセージが出ています。

ちなみに
ロボットユニット(RU)はCommunity Editionであれば、300RU/月が無料で付与されます。

使ってないから残っているはずなのになぜ？と疑問でした。

# 試行
Orchestratorを色々といじっていたのですが、解消しなかったので、
まっさらなところから再度やってみようと思いました。

環境を作って、ログを書くだけのプロセスを作り、
サーバーレスで実行したところ、普通に動きました。

# 解決
試しに作った環境と元々使っていた環境を色々と見比べて気づきました。
「元々使っていた環境に、ロボットユニットが割り当てられていない！」

どうやら、
最近作った環境では、デフォルトでロボットユニットが割り当たるが、
サーバーレスという概念が存在しない状態のときから使っている環境では、
ロボットユニットを手動で割り当てないといけないみたいです。

# 割り当てる手順
1. Automation Cloudで「管理」を開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218396/a5b10155-bf26-a672-f91a-63672cdd6962.png)

2. 対象テナントを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218396/96167a7d-c0e1-5d5d-3fec-cb1c040cbea7.png)

3. 「ライセンス」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218396/e384d4e4-8df6-6c01-d99c-60b650469c13.png)

4. 「割り当てを編集」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218396/f5e21f64-040c-ae08-3150-4ed8f81586de.png)

5. ロボット ユニットの割り当て数を設定し、保存
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218396/5bf3079e-8f01-e14d-a675-c32761a8377e.png)

上記設定後、サーバーレスで実行したら無事に動きました。
めでたしめでたし。

# まとめ
サーバーレスで実行できない場合、設定でロボットユニットの数を確認してみてください。
古くから使っている場合は、デフォルトで0になっているのでご注意ください。
StableDiffusionの大事なポイント・キーワードまとめ

## 概要
今回は、画像生成AIであるStableDiffusionを学習していく中で、個人的に大事だなと思った内容やポイントを整理してみました。(個人メモ的な感じです)

※今後も何か気付きがあれば、随時追加していこうと思います！

## プロンプト

### 品質系のワードは最初の方に書く

> **品質ワード（品質呪文）**は、画像の全体的な品質を決定するために使用する言葉です。品質呪文と呼ばれることがあります。
 
特に決まった順番などはないが、品質系ワードはプロンプトの先頭に書くのが一般的らしい。

```
masterpiece
best quality
beautiful detailed
8k 
```

### ポジティブプロンプト・ネガティブプロンプトを理解する

- ポジティブプロンプト：画像の中に描いてほしいものを指示する。
- ネガティブプロンプト：画像の中に描いてほしくないもの・除外したいものを指定する。

### 単語の順序に気をつける

最初の方に書かれた単語の方が生成するイラストに対しての影響力が強く、
後半に書かれた単語の方が影響力が弱くなる(無視されやすい)。

### プロンプトの仕様 (強調構文)

- `(テキスト)`
    - ()で囲んだ要素の注目度が1.1倍上がる。より要素が意識・強調される。
- `[テキスト]`
    - []で囲んだ要素の注目度が1.1倍下がる。重視しないようになる。

## LoRA

参考資料
- [【Stable Diffusion】LoRAとは何なのか？導入方法や使い方をわかりやすく紹介！【KoreanDollLikeness】](https://yuuyuublog.org/koreandolllikeness/#toc1)

> LoRA（Low-Rank Adaptation）は、モデルに追加学習するための仕組みのひとつです。
LoRAを一言で簡単に説明するなら、**モデルデータだけでは再現できないキャラクターや構図、シチュエーションや背景を簡単に再現する技術**のことです。
> 

LoRAを使用することで、特定のキャラクター・背景に特化したイラストを生成することができる！

## Seed

### 気に入った構図が生成できたら、Seedを固定してみる

Seed値とは、生成画像ごとに割り当てられている固有の番号のこと。

比較的顔や手が崩れていないものだったり、自分がいいと思う構図の画像が生成できた時は

Seed値を固定してプロンプトを微調整してあげると、比較的キャラの構造を保ったまま違い画像を生成することができる。
VSCodeでダブルクォーテーションの中の文字列を一発で選択したい

# はじめに
プログラミング学習中の[@kat_log](https://twitter.com/kat__log "Twitter")と申します。

VSCode使用中に、ダブルクォーテーションの中の文字列を一発で選択する方法のご共有です。

ダブルクォーテーション内の文字列にハイフンとかが含まれている場合に便利です！
（`"1234-56-789"`など…！）

![Screenshot 2023-06-01 at 12.01.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1455073/d681e339-dfe1-92dc-04b8-7ab776d646aa.png)

# 結論
標準でショートカットキーは無い?ようで、以下の拡張機能を入れるとできます!
めちゃ便利です!

https://marketplace.visualstudio.com/items?itemName=chunsen.bracket-select

# 使い方
以下ショートカットキーにて選択できるようになります!

Windows:`alt`+`a`キー
Mac:`⌥(オプション)`+`a`キー

ちなみに、ダブルクォーテーションだけでなく`()`、`{}`、`[]`、`""`、`''`に対しても使えます!

# おわりに
お読みいただきありがとうございました。
どなたかの参考になれば嬉しいです。
楽&生産性上げていきましょう〜😄

# 参考

https://jp.quora.com/vscode%E3%81%A7%E3%82%AF%E3%82%A9%E3%83%BC%E3%83%86%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E5%86%85%E3%82%92%E4%B8%80%E7%99%BA%E3%81%A7%E9%81%B8%E6%8A%9E%E7%8A%B6%E6%85%8B%E3%81%AB%E3%81%97%E3%81%9F%E3%81%84%E3%81%AE
python(Flaskアプリ)からGoogle OAuthするための開発環境、本番環境の話

いつも苦労するので備忘録として

pythonからGoogle OAuthする方法ですが、検索すると情報が古かったり、サービスアカウント使うやりかただったりして、個人のユーザーに対してサービス提供する為のやり方がいまいち分からなかったりしたのでまとめ。

必須事項
- GCP使ってAPIキーを取得する
    - Google_Client_IDとGoogle_Client_Secretは必須です
- redirect_uriは、帰ってくるURLを入れてください。これはGCPに設定したものと同じである必要があります

## OAuthするためのURIを生成する
```python
GOOGLE_DISCOVERY_URL = (
    "https://accounts.google.com/.well-known/openid-configuration"
)
def get_google_provider_cfg():
    return requests.get(GOOGLE_DISCOVERY_URL).json()
    
def get_google_request_url():
    google_provider_cfg = get_google_provider_cfg()
    authorization_endpoint = google_provider_cfg["authorization_endpoint"]
    google_client = WebApplicationClient(os.environ.get("Google_Client_ID"))
    request_uri = google_client.prepare_request_uri(
        authorization_endpoint,
        redirect_uri=os.environ.get("redirect_uri"),
        scope=['https://www.googleapis.com/auth/calendar.readonly','email','https://www.googleapis.com/auth/spreadsheets.readonly','https://www.googleapis.com/auth/documents.readonly','https://www.googleapis.com/auth/presentations.readonly'],
        approval_prompt='force',
        access_type="offline"
    )
    return request_uri
```

こんな感じでget_google_request_urlを使ってURLを作ってアクセスします

## リダイレクト後の処理を書く
受け取った情報からトークンを取得する必要があります
ルートの設定(/google/callback)は、自分の環境に合わせて書き換えてください
ちなみに、この設定の場合はリダイレクトURLはこちらになります
http://localhost:5000/google/callback

```python
@bolt.route("/google/callback", methods=["GET"])
def google_auth_callback(app_id):
    # Googleから返却された認証コードを取得する
    code = request.args.get("code")
        
    #トークンを取得するためのURLを取得する
    google_provider_cfg = get_google_provider_cfg()
    token_endpoint = google_provider_cfg["token_endpoint"]

    # トークンを取得するための情報を生成し、送信する
    google_client = WebApplicationClient(os.environ.get("Google_Client_ID"))
    token_url, headers, body = google_client.prepare_token_request(
        token_endpoint,
        authorization_response=request.url,
        redirect_url=request.base_url,
        code=code,
        approval_prompt='force',
        access_type='offline'
    )
    token_response = requests.post(
        token_url,
        headers=headers,
        data=body,
        auth=(os.environ.get("Google_Client_ID"), os.environ.get("Google_Client_Secret"),
    )
    google_access_token = token_response.json().get('access_token')
    google_refresh_token = token_response.json().get('refresh_token')
```

以上の処理でgoogle_access_tokenとgoogle_refresh_tokenがとれます
google_refresh_tokenは一度しか取れないので注意してください(開発時に何度も取得すると思うのですが、revokeしないとrefresh_tokenは付与されないのです)

## ローカル実行時の注意
ローカルで実行する場合は環境変数に
export OAUTHLIB_INSECURE_TRANSPORT=1
これを設定してください。
これをやらないと
google_client.prepare_token_request
のところで、httpsじゃないと駄目ですよと怒られます。

逆に本番環境でこれを入れると、それはそれで怒られます。