OmniAICreator/Qiita-1.07M huggingface dataset:
MySQLサーバーへの接続(PHP編)①

MySQLi(MySQL improved extension)インターフェースを利用したMySQLサーバーへの接続サンプルプログラムを作成しました。

```HTML
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>TEST PHP Program</title>
</head>
<body>
  <?php
      // データベースへの接続
      try{
        $db = new mysqli('ホスト名','接続するユーザー','パスワード','データベース名');
        echo "<p>DBの接続に成功しました</p>";
      } catch (Exception $e){
        echo $db->connect_error;
        exit();
      }
      while(true){
        try{
          $db->close();
          echo "<p>DBのクローズに成功しました</p>";
          break;
        } catch (Exception $e){
          echo "DBのクローズに失敗しました";
        }
      }  


    
  ?>    
</body>
</html>
```

説明いたします。

```PHP
// データベースへの接続
      try{
        $db = new mysqli('DBサーバーのホスト名','接続するユーザー','パスワード','データベース名');
        echo "<p>DBの接続に成功しました</p>";
      } catch (Exception $e){
        echo $db->connect_error;
        exit();
      }
```

例外処理のtryブロックを使って

```PHP
$db = new mysqli('DBサーバーのホスト名','接続するユーザー','パスワード','データベース名');
```
を使い、mysqliオブジェクトを呼び出してインスタンスを作成します。

DBに接続できない場合、catchブロックを使い、エラーログを標準出力(ブラウザ画面上)に出力します。

```PHP
//データベースから接続解除
while(true){
        try{
          $db->close();
          echo "<p>DBのクローズに成功しました</p>";
          break;
        } catch (Exception $e){
          echo "DBのクローズに失敗しました";
        }
      }  
```
例外処理のtryブロックを使ってcloseメソッドを使ってDBサーバーとの接続を解除します。
解除しないとデータベースの接続数を使ってしまうため、while文でループして解除します。
解除したらループを抜けます。
間違えてディレクトリを削除してしまったときの対処法

ファイルを削除してしまったとき

```
rm -rf app/controllers/
```

```
git status
On branch main
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	deleted:    app/controllers/application_controller.rb
	deleted:    app/controllers/concerns/.keep

no changes added to commit (use "git add" and/or "git commit -a")
```

その変更をgit addしていなければ次のコマンドを実行。

```
git checkout -f
```

これで一つ前のコミットまでワークツリーの状態を戻せる。
Googleカレンダーをダークモード表示にする 簡易ブックマークレット(週表示のみ)

現時点では、GoogleカレンダーのPC Web版にダークモード対応がまだないようなので、
Googleカレンダー(週表示のみ)をダークモード表示にする 簡易ブックマークレットをつくってみました。
結構前に作ったものですが、今やっても使えたので、メモとして貼っておきます。


使い方：
ブラウザのブックマークのタイトルは適当にurl欄に次のコードをそのまま保存しておけば、ポチッと背景を暗くできます。
(一時的なものなので、リロードするたびに押さないとですが、、)


```js
javascript:document.querySelector('.v83gc').style.backgroundColor%3D'black'%3Bdocument.querySelector('.GENA3c').style.backgroundColor%3D'black'%3Bdocument.querySelector('.GENA3c').style.color%3D'white'%3Bdocument.querySelector('.Gk2izd').style.backgroundColor%3D'black'%3Bdocument.querySelector('.Gk2izd').style.color%3D'white'%3Bdocument.querySelector('header').style.backgroundColor%3D'black'%3Bdocument.querySelector('.jLjmyd').style.backgroundColor%3D'black'%3Bdocument.querySelector('.SaBhMc').style.backgroundColor%3D'black'%3Bdocument.querySelector('.YvjgZe').style.borderRight%3D'gray'%3Bvoid(0);
```

余談：
MacのカレンダーでGoogleカレンダーを同期してダークモードで表示していたのですが、
繰り返し予定を修正しようとすると、挙動がおかしくなることがあったので、
Web版のGoogleカレンダーでしかたなく。。
就活は遅くても3年の夏には始めよう

今就活に忙しい3年生が多いと思うので、この記事を投稿することにしました。
タイトルに3年の夏って書いてるのに今12月だし手遅れ感がありますが一応ね…。

目次
≫プロフィール
≫3年の夏～冬
≫問題点
≫結論
# プロフィール
地方理系私大(偏差値40くらい:angel_tone2:)
情報工学専攻の工学部
趣味で教員免許(情報・工学)を取得中
触ったことのある言語はC,python,Ruby,JS,Java
自作のポートフォリオや情報発信のブログなどは無し
最終的な内定は3つ(いくつかは選考辞退したのでもしかしたら増えたかも)
某デカいとこの孫会社に運良く内定をもらう
# 3年の夏～冬
3年の夏休みはとにかくオンラインでインターンシップと説明会に出まくりました。
東京で就職したくて、IT業界のみ、特に情報セキュリティ系分野に特化して就活していたため会社を選ぶのはそんなに難しくなかったです。
しかし勝手がわからなかったこの頃はとりあえず手あたり次第リクルートで予約しました。

ある時大学側からおすすめされた長期インターン(3日間)に参加したのですが、インターンに参加すると最終選考がセットでついてくるお得なパックだったらしくそのまま後日社長面接へ。
インターンでの評価もそんなに悪くなかったため、10月頃には既に内定を1つゲットしました。

また、こちらも大学に募集がかかっていた企業の長期インターン(5日くらい？)に参加し12月頃内定ゲット。
秋・冬季も長期・短期ともにインターンに参加しつつ選考を6社ほど平行で受けてました。
2月頃長期インターン(2週間)に参加し、現在就職予定の会社から内定をいただきました。
# 問題点
### 業界や分野は決まっていても、どこの企業がいい！までは決めていなかった
元々情報セキュリティ系の仕事がしたいなーくらいには考えていたのですが、どの企業に入りたい！という考えまでありませんでした。
具体的に何社か決めていれば、夏の時点でもっと早く行動できたと思います。
### 3年夏の過ごし方が悪かった
とりあえず何かしていないと不安で手あたり次第説明会に参加していました。
自己分析！とかグループディスカッションの練習！とか銘打っていますが、ESの添削や面接指導は大学のキャリア支援センターの方の指導を受けるほうが確実です。
また、業界説明はITだとほとんど同じような説明を毎回聞かされるだけなので参加するだけ無駄です。
説明会に参加しないと選考に参加できない又は早期選考特典があるなどのうまみがない限り出なくていいと思います。
また、新卒就活を支援するメンターも世の中には居ますのでよくわからない会社のセミナーに出るよりそちらを利用するほうが良いのではないでしょうか。
### もっと長期インターンに参加しろ
私が内定を獲得した三社はどれも長期インターンに参加した会社ばかりです。
逆に言うと1Dayインターンのみの企業は全部落ちました。グループディスカッションで1Dayインターンに参加した数を自慢してくる奴は大したことありません。昔の私のことです。

長期インターンだと会社の部長クラスやもっと上の方とお話をする機会があります。
コロナ禍で顔を覚えてもらいにくい時代ですが、こういった場面で顔合わせをしておき「あの子インターンで結構良かったよ」なんて言ってもらえれば面接官の心証は大きく変わるでしょう。
長期休みはバイトをしたい人もいると思いますが、時給が出るインターンもありますので、これを活用し就活しつつお金を稼ぐのもよいと思います。
# 結論
### 長期インターンに行け！！
これに尽きます。
具体的なタイムラインは
**3年夏まで**
　受ける企業をピックアップ、過去のインターンや面接の情報を収集
　企業の口コミを集めているサイトに登録し過去の面接の質問や通ったESを見ておくのも大事です。
　会社独自の適性検査やSPIが実施されるのかなど得られる情報がたくさんあります。
　長期インターンは参加時点で面接があったり、本人のスキルによって制限があることが多いので勉強するなりして参加条件を満たしておきましょう。
　応募数が多い場合は容赦なく落とされるので、求める応募者像のところもしっかり満たすように。
**3年夏**
　本格的に就活を始めましょう。
　狙っている企業の説明会にとにかく参加します。競合している会社も説明会も参加しておくと本命の企業研究に役立つと思います。
　長期インターンがあるなら迷わず申し込みましょう。参加条件はしっかり満たしてから。
　もし不安なら大学が紹介してくれる絶対内定くれそうな企業に1社応募しておいて、1つ内定を確保しておくと精神が健全になります。
**3年秋・冬**
　長期インターンに参加しましょう。夏に参加した会社が秋・冬期も募集していた場合絶対に参加したほうが良いです。
　確実に会社の人に顔覚えてもらえますし、実際そういう人が内定をもらっています。
　この時期になると早期選考をするところもちらほら現れます。
　選考とインターンの両立は難しいですが、何とか頑張りましょう。
**3年春休み**
　選考の時期です。
　おそらく長期インターンに参加したなら内々の選考連絡が来ます。
　応募されたら即申し込めるようESや面接の質問対策リストを作っておきましょう。
　大手企業なら人事採用担当へのインタビュー、などの名目で何を重視して採用しているのか書いてある場合があります。ネットの記事もチェックしましょう。
　企業の選考情報を集めた口コミサイトに最終選考での質問を書いてくれている人もいるので、そういった情報も加味しながら対策を練りましょう。
**4年春学期開始**
　これだけ早く動いていたらこの頃には多分内定があります。
　もし無かったらかなりヤバいので死ぬ気でやってください。
**内定Get！！**
　おめでとうございます。
　周りの初動が遅かった人たちがヒィヒィ言ってるのを見ながら高みの見物をしましょう。
　
本当はタイトル「大学三年生は長期インターンに行け！！！」にしようと思ったんですが、ドラゴン桜感がすごいのでやめました。
【11日目】Node.jsでDiscordに毎分ランダムでGIF画像を送る

# はじめに
こんにちは、なりかくんです。
今回は、Node.jsでDiscordに毎分ランダムでGIF画像を送るプログラムを作りたいと思います。

# GIF画像を取得する
今回は、GIF画像を取得するのにTenor APIのランダムGIFを使います。
このAPIでは、API Keyと検索文字を指定するだけでランダムにGIF画像を持ってきてくれるという優れたAPIです。
ドキュメントは以下のページに記載されていますので、ぜひ参考にしてみて下さい。

https://developers.google.com/tenor/guides/quickstart

今回作成した取得するコードは以下のコードになります。検索結果が見つかればGIFのリンクを返して、見つからなければnullを返すというコードです。
```js
function getGif(query) {
    return new Promise((resolve, reject) => {
        request({
            url: `https://tenor.googleapis.com/v2/search?q=${query}&key=<Your API Key>&random=true`,
            json: true
        }, function (error, response, body) {
            if (error) {
                reject(error);
            } else {
                if (body.results.length != 0) {
                    resolve(body.results[0].media_formats.gif.url);
                } else {
                    resolve(null);
                }
            }
        });
    });
}
```

# コード全体
では、今回作成したコードはこちらになります。
```js:tenor.js
const request = require("request");

function getGif(query) {
    return new Promise((resolve, reject) => {
        request({
            url: `https://tenor.googleapis.com/v2/search?q=${query}&key=<Your API Key>&random=true`,
            json: true
        }, function (error, response, body) {
            if (error) {
                reject(error);
            } else {
                if (body.results.length != 0) {
                    resolve(body.results[0].media_formats.gif.url);
                } else {
                    resolve(null);
                }
            }
        });
    });
}

async function main () {
    let result = await getGif("fun");
    if (!result) return;
    request({
        url: "WebHook URL",
        method: "POST",
        json: {
            "embeds": [{
                "image": {
                    "url": result
                }
            }]
        }
    });
}

main();
setInterval(main, 60000);
```

これを実行すると、60秒ごと（１分毎）にTenorからランダムに取得して送信するというプログラムが完成です。実際に動かしてみると以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549951/ff0ceb7d-7bd9-e8e2-183f-b020d6d05a38.png)

これを活用して何か作ってみるといいかもしれませんね。
以上です、最後までお読みいただきありがとうございました。
SSH で踏み台サーバーを介して接続する方法 (.ssh/config 設定方法)


SSH で踏み台 (Bastionとも呼ぶ)サーバーを介して最終的なサーバーに接続する際に、一気に目的のサーバーにアクセスするための方法です。

# Terminal でいっぺんにコマンドを打つ方法

`-o ProxyCommand=''` オプションの中に踏み台サーバーのアクセス情報を挟むことでアクセスできます。

```
ssh -o ProxyCommand='ssh -W %h:%p -i [踏み台サーバーSSH鍵パス] [踏み台ユーザー名]@[踏み台サーバーアドレス]' -i [最終目的サーバー秘密鍵パス] [最終目的サーバーのユーザー名]@[最終目的サーバーのアドレス]
```

# .ssh/config ファイルに記述して簡単アクセス

さきほどの踏み台アクセスのコマンドは長いです。覚えるの面倒です。

なので .ssh/config のテキスト設定ファイルに、最終目的サーバーへのショートカットアドレスを設定し、ProxyCommand を設定することで、より簡単にアクセスできる様になります。



```
# 踏み台サーバーの設定
Host bastion.host # ここは自分の覚えやすい様に設定する
    HostName        [踏み台サーバーアドレス]
    IdentitiesOnly yes # 秘密鍵認証の場合
    IdentityFile    "[踏み台サーバーSSH鍵パス]"
    User            [踏み台ユーザー名]
Host server.host # ここも自分の覚えやすい様に設定する
    HostName        [最終目的サーバーのアドレス]
    IdentitiesOnly yes # 秘密鍵認証の場合
    IdentityFile    "[最終目的サーバー秘密鍵パス]"
    User            [最終目的サーバーのユーザー名]
    ProxyCommand  ssh -W %h:%p bastion.host # 自分で設定した踏み台サーバーのHost名

```

上記の設定をすると


```
ssh server.host
```

で SSH 接続できます。

これだったら、覚えることができます。

上記の `bastion.host` や `server.host` の記述ですが、僕はよく

`[環境].[案件名]`とかで設定しています。

例えば、`prod.concretecms` や `dev.concretecms` などと設定すると、アクセスしやすいのではないかと思います。
認証についての整理

# 目的
自分の中で認証方式について誤解していた部分があったため、
一旦情報を整理して誤解を解消することを目的としています。

# 範囲
* 前提知識
* 単一要素認証/多要素認証とは何かとそれらの違い
* 追加認証とはなにか　←誤解があったのはここ
* 多段階認証と多要素認証の違い

# 前提知識
## 認証（Authentication）とは
簡単に言うと、何か情報にアクセスする際に行われる本人確認のこと。
役所の手続きで身分証明の提示を求められるのと一緒です。
鍵を使って家に入るのも該当します。

* NISTでの定義

https://csrc.nist.gov/glossary/term/authentication

### 認証に用いられる3要素
* 知識： something you know , e.g. password PIN
* 所有： something you have , e.g. device
* 生体： something you are , e.g. biometric

役所の例でいえば、”身分証明書”という所有物（顔写真付きであれば生体も）によって認証が行われます。鍵を使って家に入る行為も、家というリソースに対して鍵という所有物を使った本人認証そのものです。

### PasswordとPINの違い
端的に言えば、パスワードは文字列であり、PINは数列です。
数字のみのパスワードはPINと言ってもよいでしょう。

 * PASSWORD
     
https://csrc.nist.gov/glossary/term/password
  
 * PIN

https://csrc.nist.gov/glossary/term/personal_identification_number

# 単一要素認証（SFA）と多要素認証（MFA)

### 単一要素認証
先に述べた３要素のうち、１要素のみを使用する認証方式です。
家の鍵がコピーされたらおしまいです。

### 多要素認証
対して多要素認証は、３要素のうち２つ以上を使用する認証方式です。
家の鍵がコピーされても、指紋認証がついていれば安心です。（実はそうでもない）

https://csrc.nist.gov/glossary/term/mfa

* 誤解される例
パスワード（知識）＋秘密の質問（知識）　これは、知識しか利用されていないためSMAです。
* 正しいMFAの例
パスワード（知識） + SMSで携帯に送られてくるワンタイムパスワード（所有）
Authenticatorを利用した携帯電話（デバイス）での指紋認証（生体） 

# 追加認証（リスクベース認証）
簡単に言うと、「なんか認証の仕方がいつもと違うな？」ってなったときに、
再度認証を求められる認証方式です。
厳密には、risk adaptive access controlに基づき認証の強度を高めた認証方式のことです。

* RAdAC

https://csrc.nist.gov/glossary/term/risk_adaptive_adaptable_access_control

* Risk-based authentication

https://pages.nist.gov/800-63-FAQ/#q-b02

具体的（一例）には、以下のような場合に追加認証を行います。
* 普段使用しているPCとは別のあまり使用していないPCからログインしようとした場合
* 普段アクセスしている場所とは違う場所からログインしようとした場合
* ログイン時の操作（キーストローク）が普段と違う場合

※私は、単純に認証を2回やるものと勘違いしていました。そうではありません。

わかりやすい例としては、普段は玄関から出入りしているのに会社の飲み会で飲みすぎて遅くなってこっそり勝手口から入ろうとしたら、「誰！？」って嫁に言われるようなもんです。（わかりにくいか）

# 多段階認証と多要素認証の違い
多段階認証は、認証を複数の段階にわたって行うことです。
この場合、利用される要素数は関係ありません。ですので、要素数を1つしか使わなかった場合は、多要素認証とはならずSFAの多段階認証となります。
一方で、MFAは1段階で実現できるものも存在します。

* SFAの多段階認証
パスワード -> 秘密の質問　
* 1段階認証のMFA
デバイス＆顔 ※windows hello for businessとかがたぶんそう。

||多段階認証|多要素認証|
|--|----|---|
|要素数|不問（1要素だけも可）|2要素以上|
|ステップ|2回以上|不問（1ステップでもできる）|

* 多段階認証だからと言って、必ずしも多要素認証とは限らない。
* 多要素認証だからと言って、必ずしも多段階認証とは限らない。

ということになります。
ほんと紛らわしくて困っちゃいますね。

# 余談
多要素認証に関して、近年の高解像度化により画像から顔や指紋を再現することはそう難しいことではなくなってきています。なので、油断は禁物です。MFAバイパスなんていう脅威もあったりしますし、MFA Fatigueといった脅威もあったりします。
詳しくはここでは書きませんが、いずれにせよMFAがあるからと言って安心できるわけではありません。
Amazon S3 Glacier Deep Archiveからデータを復元する

## やりたいこと
タイトル通り、Amazon S3 Glacier Deep Archiveからデータを復元して取り出したいです。

## 基本

`restore-object`コマンドを使います。

次の例では、30日間 [awsexamplebucket] 内の [dir1/exa-1xxxxxxx/example.mp4] を復元します。（s3://awsexamplebucket/dir1/exa-1xxxxxxx/example.mp4）

```terminal
aws s3api restore-object --bucket awsexamplebucket --key dir1/exa-1xxxxxxx/example.mp4 --restore-request '{"Days":30,"GlacierJobParameters":{"Tier":"Standard"}}' --profile my-profile
```

`--key`のパラメータにはS3 URIのbucket名の後ろからの文字列（この例の場合`dir1/exa-1xxxxxxx/example.mp4`）を入れればOK。

## バケット内にオブジェクトがたくさんあって一気にやりたい場合

バケットの中にディレクトリ的なもの（S3には実際はディレクトリという概念は無いんですよね）が何件もある場合。

今回は、awsexamplebucketというバケットの/dir1/にexa-xxxxxxxxというディレクトリ的なものが複数あって、そのそれぞれの直下に１つexample.mp4が入っているという想定。

```
- awsexamplebucket
  - dir1
    - exa-1xxxxxxx
      - example.mp4
    - exa-2xxxxxxx
      - example.mp4
    - exa-3xxxxxxx
      - example.mp4
  - dir2
```

手始めに、オブジェクトの一覧は`aws s3 ls`コマンドで参照できるのでやってみる。

```terminal
$ aws s3 ls --profile my-profile s3://awsexamplebucket/dir1/
                           PRE exa-1xxxxxxx/
                           PRE exa-2xxxxxxx/
                           PRE exa-3xxxxxxx/
                           PRE exa-4xxxxxxx/
                           PRE exa-5xxxxxxx/
                           PRE exa-6xxxxxxx/
                           PRE exa-7xxxxxxx/
```

では、いよいよこれらのファイルを一気に復元します。
今回はシェルスクリプトでやります。

```test.sh
#!/bin/sh

aws s3 ls --profile my-profile "s3://awsexamplebucket/dir1" | awk '{print $2}' | while read file
do
  aws s3api restore-object --bucket awsexamplebucket --key dir1/${file}example.mp4 --restore-request '{"Days":14,"GlacierJobParameters":{"Tier":"Standard"}}' --profile my-profile
done
```

実行。

```terminal:terminal
sh test.sh
```

S3のコンソール画面を見ると、成功したらオブジェクトのページがこんな感じになって、復元がスタートします。
![スクリーンショット 2022-07-26 17.41.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/645077/45f939fa-2897-551f-4068-b76e1c074e81.png)

復元が無事に完了したらこんな感じになりました。
![スクリーンショット 2022-07-27 20.34.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/645077/793eda19-dfce-0800-1b53-2d162d8e3254.png)

めでたし。めでたし。

## 蛇足：署名付きURL

ちなみにDeep archiveのオブジェクトに署名付きURLを発行して、解凍前にアクセスしようとすると以下のようなエラーになりました。

```
<Error>
<Code>InvalidObjectState</Code>
<Message>The operation is not valid for the object's storage class</Message>
<StorageClass>DEEP_ARCHIVE</StorageClass>
<RequestId>省略</RequestId>
<HostId>省略</HostId>
</Error>
```

あるバケット内のオブジェクト全てに対して署名付きURLを発行するのもシェルスクリプトで行っていたので、メモメモ。

```sh
#!/bin/sh

aws s3 ls --profile my-profile "s3://awsexamplebucket/dir1/" | awk '{print $2}' | while read file
do
  aws s3 presign s3://awsexamplebucket/dir1/${file}example.mp4 --expires-in 259200 --profile my-profile
done
```
Pytorch ニューラルネットワーク実装ハンドブック S5-4 をGoogleColaboratory動かす 

### Pytorch ニューラルネットワーク実装ハンドブック Section5-4 
初めに
----------------------
下記の本でPytorchを学んでいるものです。
この本では記載されているソースコードをダウンロードし、自分の環境で実行して学ぶことができるのですが、少し古い本(2019年)であるためバージョンの関係でうまく動かない点がありました。

https://www.amazon.co.jp/PyTorch%E3%83%8B%E3%83%A5%E3%83%BC%E3%83%A9%E3%83%AB%E3%83%8D%E3%83%83%E3%83%88%E3%83%AF%E3%83%BC%E3%82%AF-%E5%AE%9F%E8%A3%85%E3%83%8F%E3%83%B3%E3%83%89%E3%83%96%E3%83%83%E3%82%AF-%E5%AE%AE%E6%9C%AC%E5%9C%AD%E4%B8%80%E9%83%8E-ebook/dp/B084JKYKMF/?_encoding=UTF8&pd_rd_w=UYb5L&content-id=amzn1.sym.79ec8dbb-a6ed-4b2c-b8a2-e2dc98848cba&pf_rd_p=79ec8dbb-a6ed-4b2c-b8a2-e2dc98848cba&pf_rd_r=X6DW60TMKX319VK535JJ&pd_rd_wg=SCKw9&pd_rd_r=b2e3bac0-bf4f-4057-bfb5-b5fb9e326ab2&ref_=pd_gw_ci_mcx_mr_hp_atf_m

色々と調べ、いくつかのでコードを書き換えたことで動かすことができたので、その変更点について整理し記載しておこうと思います。

## 環境

* MacBookAir
* GoogleColablatory

## 変更点
一番上で以下のようなコードになっていると思います
```
!pip install torch==0.4.1
!pip install torchvision==0.2.1
!pip install numpy==1.14.6
!pip install matplotlib==2.1.2
!pip install pillow==5.0.0
!pip install opencv-python==3.4.3.18
!pip install torchtext==0.3.1
```

`torch==0.4.1`　を　`torch==1.10.0` に
`torchtext==0.3.1`　を　`torchtext==0.11.0`に
`numpy==1.14.6` を `numpy==1.14.6`にそれぞれ変更してください

次に以下のコードにおいて
```
import torch
import torch.nn as nn
import torch.nn.init as init
import torch.optim as optim
import torch.nn.functional as F
#torchtextを使用
from torchtext import data
from torchtext import vocab
from torchtext import datasets

%matplotlib inline
import numpy as np
from matplotlib import pyplot as plt
```
`from torchtext import data` を `from torchtext.legacy import data`に
`from torchtext import datasets` を `from torchtext.legacy import datasets`にそれぞれ変更してください

以上になります

##
Workato：DocusignとBoxの連携してみた

# １．はじめに
DocusignとBox連携を行うレシピをWorkatoで作成してみました。
以下で紹介する内容では、Docusignの署名完了に伴い、Docusignで署名されたドキュメントがBoxの特定のフォルダにアップロードされます。
またBoxにアップロードされたドキュメントにメタデータが登録されます。

# ２．処理の流れ
Docusignの署名完了に伴い、Docusignで署名されたドキュメントがBoxの特定のフォルダにPDF形式でアップロードされその後メタデータが登録されます。
![Flow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266312/155b3b0e-959b-cf44-9aa2-649be3d539c7.png)

# ３．準備
１）メタデータテンプレートの準備

ファイルに付与するメタデータテンプレートを、Box上に用意します。
![Image20221213_001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266312/dac0b3f5-2b17-aa16-8445-7efd8fd41a65.png)

# ４．レシピ
## ４－１．コネクター
次のコネクターを使用してレシピを作成します。

|コネクター|用途|
|---|---|
|DocuSign|・署名完了したドキュメントを取得|
|Box|・特定のフォルダへPDFファイルをアップロード ・PDFファイルへのメタデータ付与|

## ４－２．レシピ作成
次のようなレシピを作成します。
![Image20221213_002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266312/8b8c75b4-9d63-c5bd-c790-dad0a0c610b6.png)


①トリガー
DocuSignで署名が完了した際にレシピが動作する処理を実装します。
![Image20221213_003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266312/5ba702cf-0274-5813-03fd-0f7aec16d67d.png)

②エンベロープ内ドキュメント取得
Docusignではエンベロープ（封筒）内に署名された複数のドキュメントが含まれます。
![Image20221213_004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266312/c15cb679-9ee6-99a5-aa0a-478599ff67ad.png)

③ドキュメントダウンロード
ドキュメントをダウンロードします。
![Image20221213_005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266312/0f64d0ea-0791-9048-565c-efd1333965cf.png)

④Boxアップロード
ダウンロードしたドキュメントをBoxの特定フォルダへファイルとしてアップロードします。
※画像では「契約書」フォルダをアップロート先に指定しています。またファイルの拡張子を「pdf」に変換しています。
![Image20221213_006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266312/e2b57e99-504c-f609-669a-b4df2124751a.png)

⑤メタデータ登録
Boxの特定フォルダへアップロードしたファイルにメタデータを登録します。
![Image20221213_007.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266312/45ee2f82-c105-8ce3-66c3-4642b2b98982.png)

![Image20221213_008.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266312/be4ed992-5d39-c28a-671a-2f84965b6b1a.png)

# ５．実行例
１）Docusignで署名を完了します。
![Image20221213_009.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266312/6630e53f-e8d9-19dd-e19b-d0956bd75bbb.png)

2 ）Boxの特定のフォルダにDocusignのドキュメントがファイルアップロードされ、その後メタデータが登録されます。
![Image20221213_010.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2266312/dd347a7f-6423-3843-6b06-dbde046e02dd.png)

# 6．おわりに
当レシピをもとに電子帳簿保存法の「電子取引」への対応対応が可能となります。
2024年1月に施行される改正電子帳簿保存法では、対象となる電子データが「電子帳簿等保存」「スキャナ保存」「電子取引」の３つに分別され且つ「電子取引」の電子データに対し紙保管が禁止されます。（ 特例が無い限りは「紙保存は禁止」2022年12月時点 ）
また電子データに「取引年月日」、「取引金額」、「取引先」、「訂正理由」、「訂正日」、「削除日」の属性（メタデータ）を付与する必要があります。

当レシピでは電子帳簿保存法の「電子取引」部分に対し、①Docusignの「電子取引」で発生した電子データをBoxに電子データ保管および②「取引年月日」、「取引金額」、「取引先」などのメタデータ付与を行っています。

＜参考情報＞
ご存知ですか？令和4年1月改正される電子帳簿保存法に今すぐ対応するためのポイント
https://www.ricksoft.jp/blog/articles/001321.html

電子帳簿保存法への対応として本レシピが活用できれば幸いです。
SSHについて

<h1>初めに</h1>

githubやBitbucket、クラウドサーバー接続の際に「SSH接続」なんてものをよく聞きます。
なんのためにssh接続を行うのか。そもそもssh接続とはなんなのかという疑問にを調べてまとめていきたいと思います。
ぜひ参考にしていただければと思います。

<h1>対象読者</h1>
・プログラミング初心者
・駆け出しエンジニア
・SSHってなんぞや？って方

<h1>SSHとは？</h1>
「Secure Shell」の略で、ネットワークに接続れた機器を遠隔操作し、管理するための手段です。
Secureとは安全という意味で、安全にネットワーク機器を遠隔操作する手段のことです。
つまり、リモートコンピューターと通信するためのプロトコル。

※従来のtelnet→パスワードでもなんでもそのまま送る。（平文をそのまま送る。）
※ssh→暗号化して送信。
※telnet→Telnetは、ネットワークに接続された機器を遠隔操作するために使用するアプリケーション層プロトコル。オフィスのデスクにいながら、マシンルームにあるサーバ、ルータ等の機器をパソコン上で操作できます。
※プロトコルとは→プロトコルとは コンピューター同士の通信をする際の手順や規格のこと。 情報を送り出す端末の選定、データの形式、エラーの対処などを取り決めた通信の約束事です。

<h2>メリット</h2>
ネットワーク上の全ての通信が暗号化されるため安全に通信が行えます。
認証の仕組みが多様化しています。（パスワード、公開鍵、ワンタイムパスワード等）

<h2>SSHを使う理由</h2>
現代において、各種サーバー機器は、ほとんどの場合操作する人から離れた場所にある。操作する人が安全にインターネット経由で接続できる手段が必要となります。
理由としては、第三者がサーバーにログインできてしまうと、サーバー内でよからぬ操作をれてします可能性がるからです。
sshを利用するとサーバーに安全に接続できます。

<h2>SSLとは？</h2>
似たような言葉で「SSL」というものがあります。
下記のような違いです。
ssh→サーバーに接続するのが目的でサーバーの管理者が相性者となります。
ssl→Webサイトを安全に表示し、Webサイトの閲覧者が対象者となります。

<h2>認証方法</h2>
離れた場所にあるサーバーへ安全に接続するため、サーバーへのログイン適正チェックの方法は複数用意されています。

<h2>パスワード認証方式</h2>
認証方法：パスワード
安全度：低い

<h2>メリット</h2>
設定が簡単です。

<h2>デメリット</h2>
パスワードがバレると詰みます。

<h2>公開鍵認証方式</h2>
認証方法：「公開鍵」など生成したファイル
安全度：高い

<h2>メリット</h2>
暗号化して通信を行い、暗号化した内容を解読するのに秘密鍵がないと解読できないからです。
そこまで設定も難しくないです。

<h2>デメリット</h2>
秘密鍵が漏洩したら詰みます。

<h2>公開鍵認証方式の流れ。</h2>
①クライアント側で秘密鍵・公開鍵を作成。
<br>②公開鍵をサーバー側に預ける。
<br>③ログインしようとする。
<br>④サーバー側で公開鍵で暗号作成。
<br>⑤サーバー側からクライアント側に暗号を渡す。
<br>⑥クライアント側で秘密鍵を複合。
<br>⑦複合した情報をサーバー側に渡す。
<br>⑧既存情報と一致することを確認する。
<br>
<br>
SSH鍵の作り方。
<br>
環境：Mac OS(M1チップ)※他環境の人は検索すると出ると思います。検索の仕方「ssh鍵　作り方（各種OS名）」

ルートディレクトリにて
cd ~/.ssh
ssh-keygen -t rsa
こちら打ちますと、パスワードが必要かどうか聞かれますが、
特に必要なければ全て「Enter」でOKです。

※ルートディレクトリとは→
windowsで言うところの「C:\」「D:\」Macやlinaxで言うと「/」の階層。一番上。「〜」はホームディレクトリなので間違いないようにお願いします。

SSH鍵が作成されたかの確認方法
ルートディレクトリにてls -aで表示されたディレクトリの中に、.sshがあれば成功です。

※ls -a ディレクトリを全て表示することができます。
lsコマンドだけだと隠されたディレクトリが表示されないので注意が必要です。

cat .ssh/id_rsa.pub
上記のコマンドで公開鍵の内容を見ることができます。
ちなみに.sshの中身ですが、.pubがついているのが公開鍵です。
id_rsa→秘密鍵
id_rsa.pub→公開鍵


<h1>クライアント側でAWSにリモート接続するまで。</h1>

ssh configの設定
$ cd ~/.ssh
$ vim config
以下の内容を書き込みます。
Host example.com
  HostName 111.22.333.44
  Port 12345
  User username
  IdentityFile ~/.ssh/id_rsa

example.com：ドメイン名
111.22.333.444：IPアドレス
12345：ポート番号
username：ユーザー名
~/.ssh/id_rsa：秘密鍵の絶対パス
です。


<h2>amazonEC2に接続（ログインするまでの手順）</h2>

ユーザー名やパスワード等がわかっているところからの手順になります。
上記のコマンドでキーペアを作成。
サーバー側で設定されているパスワードを使ってssh接続し、公開鍵の情報を追記します。
$ chmod パーミッション番号（権限まわり）　鍵のファイル名。
$ ssh -i "myaccesskey.pem(cerファイルでも同様)" ec2-user@ec2-00-000-000-000.ap-northeast-1.compute.amazonaws.com
"myaccesskey.pem"→鍵のファイル名。
ec2-user→ユーザー名。
ec2-00-000-000-000.ap-northeast-1.compute.amazonaws.com→ドメイン名。

<h2>パーミッションエラーがおかしいと怒られたら</h2>

$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/id_rsa
こちらで実行してみてください。
※パーミッションについては次回説明していきたいと思います。
※cerファイルとpemファイルについては次回説明していきたいと思います。

<h1>終わりに</h1>

調べているとSSHについてなんとなくわかるようになってきました。
簡単にまとめると
クライアント側で、鍵を二つ作ります。
公開していい鍵と、絶対公開してはならない鍵です。
公開鍵をサーバー側と共有します。
データをクライアント側からサーバー側に投げると、
サーバー側がデータを暗号化してクライアント側に返します。
その暗号は絶対公開してはならない鍵でしか読み解けません。

以上となります。ここまでありがとうございました。
clang-format コマンドを効率よく多数のファイルへ一括で施す

# 記事内容
clang-format コマンドをあるディレクトリ以下の特定ファイルに対して効率よく施すコマンドの紹介。

# 執筆同期
本内容に関して、ググっても分かりやすい例が無かった。

# コマンド例
```
find bench include src test -name *.c -o -name *.cc -o -name *.cpp -o -name *.h -o -name *.hh -o -name *.hpp | xargs clang-format -i -style=file --verbose
```

find の後に、対象となるディレクトリを指定する。これは複数でも良い。
そのあとに -name *.c などを記述する。これは名前の末尾が .c であることを意味する。
-o で -name *.hogehoge みたいなものを論理和として併記できる。コマンド例では c / c++ 系のソース・ヘッダー拡張子を列挙している。
| xargs で find で出てくる結果を clang-format コマンドに渡している。
-i は in-place update. -style=file はフォーマットをかけるファイルの親ディレクトリのうちの一つにある .clang-format をフォーマット指定として利用する。
--verbose でどのファイルが正常に処理されたか出力される。
Supabase GitHubでログイン - Oauth認証

# はじめに

supabaseを用いてシステムを開発している中で、サインインのプロバイダーとしてGithubを選べることを発見。
Oauth認証を実装したのでその時のメモ。

# 使ったもの

* Vite + SvelteKit + Typescript
    * @supabase/supabase-js
    * Flowbite-svelte
    * tailwind css
    * Svelte Icons
* supabase
    * auth
    * db
    * storage

※前提として、supabaseのプロジェクトが存在していること。

# 前準備

1. supabaseのプロジェクトページに入る
1. `Auth`のページに入り、`Providers`から、`GitHub`を見つける
　 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/3751b97f-5cb8-a0b0-505d-6dda8096ad6e.png)
1. それを開き、`RedirectURL`の欄をコピーしておく。

# 設定

1. GitHubにログインする
1. 右上の自分のアイコン > `settings`で設定画面を開く
1. サイドメニューの一番下、`Developers setting`を開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/d62eb48b-1549-ce2d-2686-ff9aca3c7dac.png)
1. `Oauth Apps`を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/ee11911e-124e-423c-3891-42e8d46ece5f.png)
1. `NewOauthApp`より、新規作成画面に入る。
1. 以下を入力し、作成する。
 　`Application name`: 好き名前を登録(自分はSupabaseとしました)
 　`Homepage URL`: 搭載予定のURLを登録
 　`Application description`: そのアプリの説明を記入(任意)
 　`Authorization callback URL`: 前準備でコピーした値を入力
1. 作成されたら、`ClientID`と`Client secrets`をコピーする
 　※ Client secretsは`Generate a new client secret`から作成すること。
1. コピーした`ClientID`と`Client secrets`を`Supabase`の`providers`に登録し、`save`する。
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/0372f782-bca4-2759-9ff0-40926d39832a.png)

EnabledになっていればOK

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/d5a070b2-f6fe-0c22-5c31-c012845cc9b0.png)


# フロント側

UIコンポーネントには[Flowbite-svelte](https://flowbite-svelte.com/)を利用しました。
導入方法は前の記事で公開しています。

https://qiita.com/doyaseizin/items/6e7e8571cc6c3d7ad2e8

```typescript
const GitHubSignIn = async () => {
  await supabase.auth.signInWithOAuth({
    provider: 'github',
  })
}
```

:::note info
2023/12/17追記
アイコンには`Svelte-icons`を使用しています。
https://svelte-icons.vercel.app/
:::


```vue
<Button color="light" class="w-full mt-5 btn btn-filled-surface" on:click={GitHubSignIn}>
  <span class="h-5 mr-3">
    <FaGithub />
  </span>
  GitHubでログイン
</Button>
```

実装完了！！

え、、めっちゃ簡単！！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/5f5c45b6-9fa5-1c47-c2b4-9d1e257a97af.png)

クリック後

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/4c9f7a0d-87c7-f670-5b49-d3b5c5839198.png)


`Authorize ---`のボタンをクリックしたらサインインが完了しました！
Webサーバの構築とゲーム実装

# 1.はじめに
本記事では、作成したゲームをWeb上に公開することを目的として
クイズ形式の会社紹介ゲームを作成しました。
また、作成に使用したゲームエンジンはRen’pyを使用しています。

# 2.Ren’pyとは
Pythonを基に記述が可能なヴィジュアルノベルエンジンです。
Pythonは現在、新卒研修でも取り扱われているため
親和性があると思い使用しました。
基本的にノベルゲームを作成するときによく使われます。


# 3.検証用Webサーバ構築
以下の流れに沿って、検証用のサーバを構築しました。
・仮想環境にCentOSをインストール。
・Apacheをインストールし、Webサーバを構築
・Ren’Pyにてブラウザ用にビルドしたゲームをWebサーバへ格納し、
　ゲームがプレイできることを確認

# 4.WordPressのインストール
ウェブ上に公開する方法として、以下を実施しました。
・さくらレンタルサーバを手配
・検証用サーバへWordPressをインストール
　（エニプラのホームページはWordPressで制作されているため）
・WordPress上で仮サイトを作成し、ゲームを実装

# 5.まとめ
今回は実際にエニプラのHOに公開まではできませんでしたが、
チーム内でサーバ構築についての理解を深めることができました。
また、今後の目標としてHPに実際にゲームを公開するところまでを
目指していきたいと思います。
パーソナライズ 化への第一歩 Part2 〜 カスタム拡張機能 (Db2編)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52151/84b0e90d-180a-c87f-c393-e2111060934c.png)

:::note warn
この記事で使用している **IBM App Connect**は [2023/04/18 でサービス終了](https://www.ibm.com/common/ssi/ShowDoc.wss?docURL=/common/ssi/rep_ca/9/760/JAJPJP22-0469/index.html)となります。
:::

顧客テーブルから情報を取り入れ、バーチャル・アシスタントとのやり取りをパーソナライズしてみます。

# IBM Cloud Functions を OpenAPI 仕様を使って呼び出す

Watson Assitant のカスタム拡張機能から IBM Cloud Functions を呼び出す方法を[詳細に解説した素晴らしい記事](https://medium.com/ibm-watson/watson-assistant-connecting-customer-care-to-ibm-cloud-functions-apis-298d777f72e2)がありますので、その内容をベースに今回の記事を作成します。

ところが、作業を進めていくと、その記事で説明されているにもかかわらず、現時点 (2022/11/16) の IBM Cloud Functions において見当たらない設定箇所があることに気がつきました。

見当たらない設定箇所というのは、IBM Cloud Functions で作成した<font color="deepskyblue">**ファンクション**</font> (マニュアルには**アクション**と記載されていますが、この記事では Watson Assistant のアクションと紛らわしいので<font color="deepskyblue">**ファンクション**</font>と記載します)を API 化し、OpenAPI 仕様を記述した OpenAPI 文書を出力するための手順です。
カスタム拡張機能は OpenAPI 文書を取り込むことで構成できるのですが、その肝心な OpenAPI 文書を作成できなくなりました。
以前(2022年初頭)、アクセスした時には存在していたので、大丈夫だと思っていたのが、なんと、当てが外れてしまいました :sweat_drops:

:::note warn
使用予定だった **API Gateway 機能**は [2022/08/31 の段階でサービス終了](https://cloud.ibm.com/docs/api-gateway?topic=api-gateway-whatis_apigw)となっていたようです。
:::

何か方法がないかと調査したところ、IBM App Connect が Db2 をサポートしていることがわかりました。
詳細は[公式オンライン・マニュアル](https://cloud.ibm.com/docs/AppConnect?topic=AppConnect-getting-started)に譲りますが、Qiita にも[解説記事](https://qiita.com/sawatatsu/items/6a9548ae447bff1a5f1a)を見つけることができます。

# IBM App Connect を使って IBM Db2 にアクセスする

結論から先にお話ししますと、構成はできたのですが、日本語処理がうまくいかず文字化けしてしまう現象に遭遇しました。
怪しそうな箇所は何度も見直したのですが、私のスキルでは解決できず、断念。
いよいよヤバい状況です :sweat_drops: :sweat_drops:

:::note warn
有識者の方、Db2テーブルに含まれる日本語レコードを IBM App Connect から取り出す場合、文字化けしない方法や Tips があればお知らせいただけますと幸いです :bow_tone1:
:::

(記録)
* Db2 上のテーブル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52151/93e67e22-d9b5-c7b9-2548-de9f0e44cf3f.png)

* App Connect 内のテストツールの出力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52151/03ff173f-7929-40f0-2832-97482d44a0ee.png)

* swagger.io からアクセスした時の出力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52151/26032d74-c3ca-58cc-0dcb-9c1d0cca72bd.png)

* New Watson Assistant のアクションからアクセスした時の出力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52151/eaf35b2a-7fe2-661d-1aa5-beffb626e3f4.png)

# いかがでしたでしょうか

なんとも手詰まりな状況です。ここで諦めるわけにはいきませんので、ちょっとお時間をくださいませ :bow_tone1::bow_tone1::bow_tone1:

# 参考情報

### 公式オンライン・マニュアル: (非推奨) API Gateway とは
https://cloud.ibm.com/docs/api-gateway?topic=api-gateway-whatis_apigw

### 公式オンライン・マニュアル: App Connect 入門
https://cloud.ibm.com/docs/AppConnect?topic=AppConnect-getting-started

### その他

https://medium.com/ibm-watson/watson-assistant-connecting-customer-care-to-ibm-cloud-functions-apis-298d777f72e2

https://medium.com/ibm-watson/watson-assistant-just-got-connected-a1f46dc9b130

https://qiita.com/sawatatsu/items/6a9548ae447bff1a5f1a
PageController & FrontController

![15.PageController & FrontController.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/11525/3b2d739f-701d-616b-476b-9d34a5e37f6c.png)

https://bliki-ja.github.io/pofeaa/PageController/

https://bliki-ja.github.io/pofeaa/FrontController/

Page Controller は個々の Web ページで何をするかを担うコントローラーだと、PoEAA では説明されています。静的な Web サイトの HTML ファイルをイメージするのは、開発者だけでなくユーザーにとっても理解しやすい単位設定です。

とはいうものの、[PRG (Post Redirect Get) パターン](https://qiita.com/furi/items/a32c106e9d7c4418fc9d)の Web MVC フレームワークが主流になったり、REST がパスで表されるものを HTTP メソッドで操作するイメージが広まった現在では、ページ単位よりもリソース単位で認識したほうが合っているでしょう。リソースというのは、URL の R のことです。

Page Controller は基本的に、ドメインモデル全体ではなく、機能と関係したモデル一部だけを扱います。Service Layer を設けた場合、ひとつの Page Controller が参照するのは、たったひつとつのドメインサービスです。それらのモデルを適切なビューに送り出すのが Page Controller の役目です。求められた形式が Web ページであれば Template View かもしれませんし、REST API であれば Transform View と JSON シリアライザかもしれません。

いっぽう、Front Controller のスコープは全ての HTTP リクエストです。PHP のフレームワークを知っている方なら、Web サイトのトップレベルに置かれた `/index.php` の内容をイメージすると早いでしょう。Web サーバーは全てのリクエストを、いちどそこに集中させます。PHP 以外のものでも、Web MVC フレームワークの多くは、実質的にそれと同じことを行っています。

Front Controller のもっとも重要な役目は、適切な Page Controller へのルーティングです。URL のパスやクエリパタメータ、あるいは HTTP メソッドを見て、適切なアクションへ誘導します。とはいえ、この仕組みを自作することはほとんどなく、ファイル配置、簡単な定義、あるいはアノテーションだけで、暗黙的に実現されている形が一般的です。

意識すべきなのは、HTTP ミドルウェアです。ルーティングの前、あるいはアクションの後に、セキュリティやキャッシュといった、サイトシステム全体に関わることを監視できるのが、Front Controller の持つ特権であり責務です。内部で起きたエラーをハンドリングするのもそうです。妥当なエラーページを表示したり、クラッシュログを開発者に送ったりします。

- - -
ちなみに Nginx の `location` は、ひとつのディレクティブのように見えますが、`location /` のように書いたときは指定したパス以下の全てに関わる設定になりますが、`location = ...` と `location ~ ...` のように書くとマッチしたパスにだけ適用される設定に化けます。
ファーストセッションのデータをDBに格納する

アプリケーション内部で流入元をベースにした分析を行ったのでメモ書き。

## 現状
- GAを使ってユーザーデータを収集している
- 登録画面へ複数流入元があり、それぞれのURLパラメータにユニークな文字列を使用している(URLで流入元が可能)
- 流入元に関するデータをDBに保持しておらず、登録画面以降のトラッキングができていない

## 課題
- 流入元の評価や、アプリケーション内部でのフェーズ管理のために、内部のトラッキングを可能とする必要がある。
- 複数流入経路を保有しているユーザーに対しては、ファーストコンタクト時の媒体を評価する必要がある。

## 対応策
- URLパラメータをDBに登録する
- 初回アクセス時のURLパラメータをDBに登録する
    - セッションが切れたら、次回セッションの初回コンタクトのURLを利用する

## 実装
 
コード例は以下の通り。
※特定URL以下にMiddlewareを噛ませています。(今後の要件次第ではチューニングが必要だが、現時点では不要と判断)

```UtmMiddleware.php
    public function handle($request, Closure $next)
    {
        // セッション未保存の場合のみセッションに保存する
        // utm_sourceは必須項目とし、それの有無で判別する
        if ($request->has('utm_source') && !$request->session()->has('utm_source')) {
            $params = [
                'utm_source' => $request->utm_source,
                'utm_medium' => $request->utm_medium,
                'utm_campaign' => $request->utm_campaign,
                'utm_term' => $request->utm_term,
            ];
            session($params);
        }
        return $next($request);
    }
```

```xxxController.php
    // セッションからパラメータ取得
    $tmp->utm_source = session('utm_source');
    $tmp->utm_medium = session('utm_medium');
    $tmp->utm_campaign = session('utm_campaign');
    $tmp->utm_term = session('utm_term');

    //後はいい感じにtmpをDBに入れる
```
MacでSourcetreeを使う

AWSのCodeCommitの設定が、SwichRole使うようになっていたので、
その設定方法のメモ

# 前提
gitでCloneができている状態（aws configureの設定が終わっている状態）

# リポジトリ登録

SourceTreeを開いて、Cloneしたフォルダをドラッグ＆ドロップ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3003663/40962e4d-4cb1-9b08-d46f-556408add8c2.png)

フォルダが表示されるのでダブルクリックで開く

# Gitの設定

リポジトリ　-> リポジトリの設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3003663/14822032-9237-3e8f-3d25-3d15d8899396.png)


リモートタブ -> Configファイルを編集...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3003663/3339d811-a135-e90f-e158-efc3a56d9c55.png)

以下、追加
```
[credential]
    helper = /opt/homebrew/bin/aws --profile (プロファイル名) codecommit credential-helper $@
    UseHttpPath = true
```

プロファイル名は、aws configureで設定したプロファイル名
awsのパスですが、ターミナルで、`which aws`を実行して出てきたパスを書きます。
【slack】グループメンションを飛ばす方法

## 概要
SQSとSNSを使い、slack上にグループメンションをする際にハマったことを備忘録として記す

## グループメンションを飛ばす方法
### 1.　グループIDを取得する
ブラウザ上でslackを起動し、以下部分にてgroup IDを取得する
```
https://app.slack.com/XXXXX/XXXXXX/XXXXXXX/user_groups/[group_id]
```

### 2. メンション形式を通知設定ファイルに記載
```
<!subteam^group_id>
```

### 3. SNSにてメッセージを作成
snsのコンソール上から[メッセージの発行]をクリックしtestメッセージを作成後、送信します
![スクリーンショット 2022-12-15 12.03.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430110/d5882c61-4569-ef73-4098-c3cf99d4f7cd.png)

slack上にメンションが飛んでくることを確認しました◎

## 参考文献
https://qiita.com/gimKondo/items/99ba9b05d14a6b49df68

https://qiita.com/tamorieeeen/items/de6c34760e2d8550f123

https://www.web-dev-qa-db-ja.com/ja/html/%E3%82%B9%E3%83%A9%E3%83%83%E3%82%AF%E3%83%81%E3%83%BC%E3%83%A0id%E3%81%A8%E3%83%81%E3%83%A3%E3%83%8D%E3%83%ABid%E3%82%92%E8%A6%8B%E3%81%A4%E3%81%91%E3%82%8B%E6%9C%80%E3%82%82%E7%B0%A1%E5%8D%98%E3%81%AA%E6%96%B9%E6%B3%95%E3%81%AF%E4%BD%95%E3%81%A7%E3%81%99%E3%81%8B%EF%BC%9F/829192007/
単一のバイナリファイルをミニマムにHomebrewで公開する方法

# 概要

homebrewでバイナリ実行ファイルを公開する方法についてまとめました。

下記のアドベントカレンダー記事でJSON整形コマンドを自作したという話をしましたが、
下記記事で作成したJSONを整形するバイナリファイルを例に用いて、
バイナリファイルを公開する方法について説明させていただきます。

Homebrewでミニマムにコマンドを公開する例として参考になればと思います。

https://qiita.com/tobita_yoshiki/items/375fcc79989a522eab45

# 1. バイナリファイルを公開

まずバイナリファイルをGithub Release等で公開します。

https://github.com/cacapouh/jsonfmt/releases/tag/0.0.1

# 2. brew createコマンドで雛形を作る

以下の`brew create`コマンドで雛形を作ります。 `--set-name`にはパッケージの名前を指定します。
引数には公開したいバイナリファイルのURL(1の手順で公開したURL)を指定します。

```
$ brew create --set-name=jsonfmt https://github.com/cacapouh/jsonfmt/releases/download/0.0.1/jsonfmt
```

上記のコマンドを実行すると、`jsonfmt.rb`というファイルがエディタで開かれます。

```ruby:jsonfmt.rb
# Documentation: https://docs.brew.sh/Formula-Cookbook
#                https://rubydoc.brew.sh/Formula
# PLEASE REMOVE ALL GENERATED COMMENTS BEFORE SUBMITTING YOUR PULL REQUEST!
class Jsonfmt < Formula
  desc ""
  homepage ""
  url "https://github.com/cacapouh/jsonfmt/releases/download/0.0.1/jsonfmt"
  sha256 "1b6855b02854192e996611c472bbd1eeb007e14416357cf43a410f024f07d9a1"
  license ""

  # depends_on "cmake" => :build

  def install
    # ENV.deparallelize  # if your formula fails when building in parallel
    # Remove unrecognized options if warned by configure
    # https://rubydoc.brew.sh/Formula.html#std_configure_args-instance_method
    system "./configure", *std_configure_args, "--disable-silent-rules"
    # system "cmake", "-S", ".", "-B", "build", *std_cmake_args
  end

  test do
    # `test do` will create, run in and delete a temporary directory.
    #
    # This test will fail and we won't accept that! For Homebrew/homebrew-core
    # this will need to be a test that verifies the functionality of the
    # software. Run the test with `brew test jsonfmt`. Options passed
    # to `brew install` such as `--HEAD` also need to be provided to `brew test`.
    #
    # The installed folder is not in the path, so use the entire path to any
    # executables being tested: `system "#{bin}/program", "do", "something"`.
    system "false"
  end
end
```

開かれたファイルですが、コメントや`test do`のところは消してしまって問題ないです。
今回のケースですと、`install`メソッドを以下のように書き換えるだけでOKです。

```ruby
def install
  bin.install "jsonfmt"
end
```

`bin.install`の引数にはバイナリ実行ファイル名を渡してやります。

# 3. 公開用のリポジトリを作成する

次にHomebrewパッケージ用のリポジトリを作成します。
リポジトリ名には、`homebrew-`というプレフィックスをつける必要があります。
JSON整形コマンドの例ですと、`homebrew-jsonfmt`という名前にしてリポジトリを作成しました。

https://github.com/cacapouh/homebrew-jsonfmt

リポジトリには、先ほど作成したRubyファイルを入れてやる必要があります。

上記のリポジトリでは、`Formula`というディレクトリの中に`jsonfmt.rb`を入れていますが、
リポジトリのルートのところに`jsonfmt.rb`を配置してやっても挙動は変わらないです。

```
.
└── Formula
    └── jsonfmt.rb
```

# 4. インストール

あとは、通常通りhomebrewでインストールしてやるだけです。

```
$ brew tap cacapouh/jsonfmt
$ brew install cacapouh/jsonfmt/jsonfmt
```

# おわりに

ご閲覧ありがとうございました！


# 参考になった文献
* https://docs.brew.sh/Formula-Cookbook
* https://qiita.com/sh0nk/items/6bbc241b7c0d9f18fcfa
Tcl/Tk for文でbind内の引数を渡す方法　/ How to operate binding in for loop

# 概要
　for文を用いてwidgetを作成した際、各widgetに対して異なる操作をする方法　
　How to operate "bind" function when I make widgets by for loop

## コード例　
　for文でボタンを作成 
　placing the button widget by for loop
```
set value {red blue}

foreach val $value {
    button ".bt$val" -text $val -fg gray -command "assign $val"
    pack .bt$val
}

proc assign {val} {
    puts $val
    .bt$val configure -fg $val
}

```


中括弧{} ではなくダブルクオート"" を用いることでローカル変数valが即時に(定義時に)評価されます。
tcl evaluate inside of quote "" while definition. brace {} deffer the evaluation.

## OOP例　
tclのバインドで気をつけなければいけないところは、バインドが参照するスコープはパブリックスコープということです。　
つまりローカル変数は参照できません。そのためクラスなどを用いるときは工夫が必要となります。以下に一例を載せますが、より良い方法があれば教えて欲しいです。(namespace の使い方などはあまり理解していないので良い参考文献等あれば知りたいです)

Note that the bind function of tcl/tk reffer the public scope. Therefore you can never reffer the local variable. Thus we have to think out how to implement. I show a example below. (If there is a better way, please ask me. and I want to know the detail of "namespace", so let me know the reference of that)

```
set value {red blue}

oo::class create Window {
    constructor {} {
        my make_button
    }

    method make_button {} {
	global value
        foreach val $value {
        button ".bt$val" -text $val -fg gray -command "assign \$window $val"
        pack .bt$val
        }
    }

    method change_fg color {
        .bt$color configure -fg $color
    }
}

proc assign {window color} {
    $window change_fg $color
}

set window [Window new]
```
ここで注意して欲しいのが、ローカル変数valは定義時に参照するのに対し、インスタンスwindowは呼び出しのタイミングで参照する必要がある。従ってバックスラッシュ"¥"を用いることで評価するタイミングをずらした。　
Note that I reffer the instance "window" at the time the bindng invoked, in constant I reffer the local variable val while definition. I use the backslash "¥" before $ so that prevent from evalating in defenition.

# まとめ
tcl/tkは世界的にはある程度使われているが、日本語のレファレンスが圧倒的に少ないデメリットがある。

tcl/tk のバインドはパブリックスコープを参照する都合上pythonのtkinterと比べクラスの扱いが難しくなっている。
そのため前述したnamespaceを活用した方法がよく見られる。そこについても調べていきたい。
TypeScriptのas const

## TypeScriptのas constの基本的な知識

```TS
const x = "hello" as const;
```

`as const`は `constant assertion` - `定数アサーション`とも呼ばれています。`as const`を使用すればTypeScriptのコンパイラが次のように認識しています
- xのデータ型は`"hello"`となります (`Type "hello"`)かつデータ型が拡張できなくて、例えば `"hello"`データ型から`string`に全く変換できません。
- Object literalが`readonly`となります。


### 別の例
TypeScriptでは下記の宣言を書けば:

```TS
const UserType = {
  ADMIN: 'ADMIN',
  NORMAL: 'NORMAL',
} as const;
```

`UserType`定数のプロパティが`readonly`になります。`UserType`のプロパティに新たな値をアサインするとコンパイラはエラーを報告します。こんな感じです。

![184150153-779c7872-f237-42a4-be52-8ec4bad7a3e0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135669/8dc2efd7-d70d-181a-9c7e-db27275e55af.png)

## readonlyとas constの異点

下記のコードを見てみましょう。

```TS
type UserDetail = {
  name: string;
  age: number;
};

type User = {
  readonly id: number;
  readonly detail: UserDetail;
};

const user1: User = {
  id: 1,
  detail: {
    name: 'User 1 Name',
    age: 10,
  },
};

const user2 = {
  id: 1,
  detail: {
    name: 'User 2 Name',
    age: 20,
  },
} as const;
```

`readonly`はプロパティにのみ使用できます。プロパティ値がオブジェクトの場合、そのオブジェクトのプロパティは変更可能です。

```TS
user1.detail = {} // こうすればTypeScriptのコンパイラがエラーを報告します。
```

こんな感じです。

![184151961-108c8d7f-12c8-4a32-b321-5a8dde39dc59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135669/63db46b3-b128-956d-55ae-bd6b85e6749c.png)

```TS
user1.detail.name = "New Name"; // detailオブジェクトのプロパティは変更可能ですのでコンパイラエラーが全く出ていません。
```

でも `as const`だったら全てプロパティ(親と子ども)が変更不可です。例えば

```TS
user2.detail.name = "New Name"; // as constで定義されてるuser2のdetailのnameプロパティを変更すればコンパイラエラーがは発生するはずです。
```

![Screen Shot 2022-12-14 at 17.05.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135669/d9113180-da74-4e02-219b-b67ca47a55f1.png)

## enumとas constを比較する

パフォーマンス的には同じですが、違うところがあります。下記の各例をみて確認しましょう。

```TS
// まずはLinksというenumを定義します
enum Links = {
  Link1 = 'test',
  Link2 = 'test2',
};
```

↑のようにすれば次のものが受け取れます。

### Linksという名前を持ってるValueがもらえる
これはプロパティ`Link1`, `Link2`と共にランタイムに存在するオブジェクトです。
また、`Link1`と`Link2`それぞれに対応する値は`test1`, `test2`です。


### Linksというタイプ
タイプはコンパイルタイムのみ存在する。↓のように書けば

```TS
interface Foo {
  link: Links;
}
```

`link`というプロパティ持ってる`Foo`インターフェースがもらえるし、その`link`プロパティが`Links.Link1`あるいは`Links.Link2`を持たないといけません。

### LinksというNamespace
LinksというNamespaceから`Links.Link1`と`Links.Link2`タイプがもらえるから↓のようにも全然書けます。

```TS
interface Bar extends Foo {
  link: Links.Link1;
}
```

`as const`を使用すると、上記(Value, タイプ, Namespace)を次のように書き換えることができます。

```TS
const Links = {
  Link1: 'test1',
  Link2: 'test2',
} as const;

type Links = (typeof Links)[keyof typeof Links];

namespace Links {
  export type Link1 = typeof Links.Link1;
  export type Link2 = typeof Links.Link2;
}
```

## さらに

```TS
const to: 'test1' = Links.Link1; // いつもOK
const from: Links.Link1 = 'test1';
```

enumは`string`のnominalサブタイプと見なされます。具体的には
- `string`から`Links.Link1`に**キャストできます**。
- `Links.Link1`から`string`に**キャストできません**。

`Links.Link1`と`string`をタイプ交換できたいなら`enum`を絶対に避けてください。

TypeScriptの`as const`については以上です。

お読みいただきありがとうございます。また次のブログでお会いしましょう。
livewire は 素のscript 内では Livewire で存在している

備忘録です。

livewire のドキュメントでは、 $wire.on と書かれていていますが、素の script 名では、
```
<script>
Livewire.on('createdLink', () => {
        alert(1);
});
</script>

```
で使えるようです。

https://laracasts.com/discuss/channels/livewire/livewire-and-alpine-js-wire-is-not-defined
AWS EC2内のDockerコンテナからローカルにファイルを持ってくる方法

## 今回はAWS上で展開しているDockerコンテナの中からファイルをローカルに持ってくる方法を説明します。
### 今回やりたいこと
- seleniumをheadlessモードで起動しているが、予期せぬエラーに見舞われてしまい現在どのページにいるのか判別できなくなってしまったので、スクリーンショットを撮り開いているページを確認したい。

## 大まかな手順
① Dockerコンテナ→EC2のディレクトリ
② EC2のディレクトリ→ローカルのディレクトリ

## 手順の説明
- まずEC2内のDockerコンテナからEC2にスクリーンショットを持ってきます。
    - スクリーンショットを保存する場所はコンテナ内のvolumesでマウントされているファイルを指定しておきましょう。(docker-compose downしてもスクショが消えないようにするためです。)
    - 次に以下のコマンドでコンテナID　を調べます。
    ```
    docker container ls -a
    ```
    - ここで目的のコンテナIDを取得し以下のコマンドでEC2内にコピーします。
    ``` 
    docker cp containerID:/コピー元のファイルパス コピー先のファイルパス
    例:docker cp e471545d21ad:/myapp/tmp/sample.jpg . 
    ```
- ここまででEC2内にスクリーンショットを持ってくることができました。
- 次にEC2からローカルにファイルをコピーします。
    - EC2にアクセスするためのkeyが置いてあるディレクトリに移動し、以下のコマンドを実行します。
    ``` 
    scp -i "example.pem" ec2user@IPaddress:/home/ec2user/sample.jpg ./
    ```
    - ここでこのコマンドを解説します。
    - ```scp```はssh + cpの略です。
    - ```ec2user@IPaddress:/home/ec2user/sample.jpg```はEC2内のファイルパスです。
    - ```./```はローカルのコピー先です。
- 上記のコマンドを実行し、EC2からローカルにファイルをコピーしてくることができました。

## まとめ
- プログラムによってはDockerコンテナ内にファイルが生成されてしまうこともあるかと思うので内容を確認したい際にはぜひ使ってもらえればと思います。
toC脳からtoB脳へ

HRBrain Advent Calendar 2022 カレンダー2の18日目の記事です。

https://qiita.com/advent-calendar/2022/hrbrain

## はじめに
こんにちは。
株式会社HRBrainで労務サービスのプロダクトマネージャーをしています @Moou0820 です。
中途入社して2か月が経ち、長い間toCのサービス開発に携わっていた私が初めてtoBサービスの開発に参加し、同じサービス開発でも根本的に考え方が違うな..と感じましたのでその事を書かせて頂ければと思います。

## 何が違うのか
まずtoCとtoB開発の違いですが、toCのサービスではユーザーの属性や利用タイミング等の仮説を立てた上で、定量的なログを計測し課題箇所の改修を行います。そのPDCAを回す事により、仮説を検証しそれを立証していきます。
逆にtoBサービスの場合、ユーザーの課題が既に有りそれを1つ1つ解決することでユーザーニーズに応えていくというプロセスになります。

入社して1か月が経った頃になんとなく今までのやり方では上手く進まない事に気づき、これまでのtoCのPdMスキルやマインドを一度捨て改めて考えなおす必要があると感じました。

## toB開発の難しさ
### ユーザーの業務理解が必要
課題が明確であってもその業務に携わってきたわけではありませんので、実際に使用する状況を理解する必要があります。
誰が、いつ、何の作業を、何のツールを使って作業しているのかといった業務フロー等の前提知識はもちろんのこと、その業務自体のドメイン知識も必要になります。
### 数字で判断出来ない
その機能が存在するという事がセールスに響く場合がありますので、定量の数字だけを見て削除等の判断をすることが出来ません。
### ヒアリング出来る母数が少ない
toCサービスとは違い、多くの方からフィードバックやヒアリングが出来るわけではありません。課題感や要望優先度にかなり差異が出てしまう事もあります。

これらの問題を開発チームでどう解決していくのかが私の悩みでもありました。
## 大切なのは周りと連携すること
toB開発に関して全てをプロダクト開発だけで解決出来ることはできません。
入社当初「ビジネスサイドと連携をしながら進めて下さい」と言うアドバイスを頂いていました。
ただ、今まで開発チームだけで課題から立証まで進めていた私には全く無い思考だったのでいまいち「連携」がどういうことかわかっておらず行動に移すまでかなり時間がかかってしまった気がします。

課題によってはセールスやカスタマーサクセスといったビジネス組織に相談し、一緒に動く事が必要で、その中でプロダクトとしての優先度や落とし所を決定し開発に着手していく。
この考えに気づけた事で少し目の前が開け、モヤっとしていた問題の糸口とtoB脳への一歩を踏み出せた気がします。

## 最後に
toCの新しい領域を切り開いていく開発とは違い、toBサービスの開発は決して派手なものでは無いと思います。
ですが、ユーザーの課題を確実に解決しそれを使って頂ける環境が必ずあり、リリースした機能に関してのフィードバックがすぐにいただける。
この環境はありがたく、新しい面白みを感じています。

最後まで読んで頂きありがとうございました。
素敵なクリスマスをお過ごしください ☆＊*

---
HRBrainでは引き続き仲間を募集しております。詳細は下記からご確認ください。
https://www.hrbrain.co.jp/recruit
Railsにおけるアソシエーションについて整理する

# アソシエーションとは、モデルを利用したテーブル同士の関連付けのことである。
アソシエーションをモデルに定義することで、そのモデルに紐づく別のモデルの情報へアクセスできるようになる。

## 1:1または1:多の関係
例としてTwitterのようなアプリを作成することを仮定してテーブル同士についての関係性を書いてみる。
### has oneの関係
例１
![スクリーンショット 2022-12-15 10.42.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884270/9c4572ec-3101-f9a7-d4f1-c4a5d137e9c3.png)
上記の状態のときusersテーブルAさんはtweetsテーブルに対して一度しかツイートを投稿できないとする。
つまり、usersテーブルからみて、tweetsテーブルは　**「1:1」**　の関係になり、このことを、**has oneの関係**といい、「User has one Tweet」の状態であると言える。
これは1:1の関係を表している。

### belongs toの関係
例２
![スクリーンショット 2022-12-15 10.43.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884270/bb6b16e7-6eb9-8d71-05ae-6268b2ba796e.png)
例１と反対の矢印を考えてみる。
この場合、大切なのは**従属関係**である。
tweetsテーブルからみてusersテーブルは確かに1:1の関係にあるが、**「投稿する人」（ユーザー）がいるから投稿内容ができあがる**のである。
つまり、従属関係の視点からみると、tweetsテーブルはusersテーブルに「1:1」の関係であるものの、usersテーブルに従う形になっているので、これを**belongs to**の関係といい、今回の場合は、「Tweet belongs to User」の状態であると言える。

### has manyの関係
例３
![スクリーンショット 2022-12-15 10.47.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884270/5f33dfea-503d-ac04-7eaf-b252db7e6448.png)
先ほどまでの例と違って、今度は一人が複数投稿できるものとする。
usersテーブルの視点で考えると、あるユーザーの作成した投稿は複数個ある状態である。
つまり、1人のユーザーは複数の投稿を所有している。
この状態のことをhas manyの関係といい、今回の場合は「User has many Tweets」の状態であると言える。
これは「1:多」の関係を表している。

### belongs toの関係
例４
![スクリーンショット 2022-12-15 10.48.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884270/c7bdf41e-b29b-ce20-bfc9-96ded9b5abef.png)
例２でもbelongs toの関係が出てきたが、　**tweetsテーブルからみて、usersテーブルは「1:1」の関係であり、従属関係はusersが主になっている。**　したがってこの関係もbelongs toとなり、」「Tweet belongs to User」の状態であると言える。

## 多対多の関係
次は、例としてチャットアプリを作成することを仮定してモデルについての関係性を書いてみる。
チャットアプリにはチャットルームがあり、チャットルームでは個人同士が自由にコメントできるとする。

:::note info
usersテーブルとmessagesテーブル
:::
どのユーザーが投稿したかを管理する必要があるため
![スクリーンショット 2022-12-15 11.02.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884270/beb1d85a-5666-f872-d7d2-eab3508ed17f.png)

:::note info
roomsテーブルとmessagesテーブル
:::
どのチャットルームで投稿されたメッセージなのかを管理するため
![スクリーンショット 2022-12-15 11.04.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884270/8946d08e-6f56-2f29-0811-7fb9801cf45f.png)

以上までが、これまでやってきた「1：多」の関係である。
では、これはどうだろうか。

:::note warn
usersテーブルとroomsテーブル
:::
ユーザーがどのチャットルームに属しているかを管理するため
チャットルームにどのユーザーが存在するかを管理するため
![スクリーンショット 2022-12-15 11.13.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884270/2999ae2d-b6c4-a1b8-89f5-dec1d6b82d78.png)
ここで注目すべきポイントは、usersテーブルとroomsテーブルの関係性が、これまでのような「1対多」ではないことである。
「多対多」は、関連するテーブルのidをお互いが複数持っている関係性のことである。たとえば今回のような、「ユーザーは複数のチャットルームに所属する」「チャットルームには複数ユーザーが所属する」という場合の関係性のことである。

これでは複雑になってしまうので、考え出されたのが **「中間テーブル」**　である。
中間テーブルとは、その名の通り2つのテーブルの中間にあるテーブルのことである。
中間テーブルは、多対多の関係にある2つのテーブルの間に挟まって、2つの組み合わせパターンだけをレコードとして保存する。
![スクリーンショット 2022-12-15 11.32.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884270/5c036ba3-618e-d2b7-9233-a6e8bc79a44e.png)
2つのモデルのみでは多対多のアソシエーションを組むことができないため、 中間テーブルを利用して多対多の関係を定義する。

なお、中間テーブルを介してhas manyの関係を築くためには、 **through**をつける必要があるので留意する。
S3からBigQueryに直接データを転送する

# はじめに

S3からCloudStorageへのデータのコピーの記事を書きましたが、そもそもS3からBigQueryに直接転送できるようでしたので早速試してみました。

https://qiita.com/uzresk/items/493c4ec369c94162d4c8

ちなみにS3 → CloudStorageはIAM Roleを使って転送できましたがこちらはアクセスキー・シークレットアクセスキーしか利用できないようです。

# S3にアクセスするポリシーの作成とアクセスキーの発行

S3にアクセスできるポリシーを作成します

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:Get*",
                "s3:List*",
                "s3:Delete*"
            ],
            "Resource": [
                "arn:aws:s3:::xxxxxxxxxxxxxxxxx",
                "arn:aws:s3:::xxxxxxxxxxxxxxxxx/*"
            ]
        }
    ]
}
```

IAMの画面から先ほど発行したポリシーを使ってアクセスキーを発行してメモしておきます。

# データ転送の設定

BigQueryの画面を開き、SQLワークスペースでテーブルを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/a2fb23fa-1b1d-2b5c-68a3-fc02c2c03b2a.png)


左メニューから「データ転送」を選択し、以下の情報を登録します

- 転送構成名：適当に入力
- データセット・テーブルに先ほど作ったテーブルを作成
- S3のURLを設定
    - 今回は多数のParquetデータだったので/*としています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/6abd44d5-9264-3365-35e0-4e481692f0ea.png)

保存すると実行され、少し経つと結果がが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/9902532d-a48c-9e4d-d1ac-2b13fd40fc98.png)

BigQueryのデータを確認してみるとちゃんと入っていることが確認できました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/15bf0ed1-3f8b-db20-848d-7de21cf2a290.png)