OmniAICreator/Qiita-1.07M huggingface dataset:
Turing.comからのスカウトメール

## Turing.comからスカウトメールが届いた。
うまい話などそうそう転がっていないのだ、一瞬でも気を抜いたらやられる。
(やられるといっても個人的に短期間だけ自分に絶望するだけ)
あったことも聞いたこともない会社からのメールなどスパム以外ないのではないかと思う。
ただどこからメールアドレスが出たのか気になるので調べてみた。

メールの内容は下記
```
Hi ○○ ○○, ,
I saw your profile online and wanted to reach out! You might be a great fit for many of the remote software engineering roles that top U.S. companies are hiring for on Turing. 
Turing is based in Palo Alto, California, U.S.A., also known as “Silicon Valley”. We connect exceptional software engineers from around the world to top U.S. and Silicon Valley companies that are hiring for full-time remote software positions. 
```

Google翻訳によると
あなたのプロフィールを見てシリコンバレーで働くのに
最適かもしれない、一緒に働こうぜってことっぽい

## Githubアカウント名宛に送られてきている！！
[Hi ○○ ○○]はGithubのアカウント名だった。
GithubはPrivateリポジトリを一つ使っているがプロフィールも何も書いていない
一時期Pubulicもあったな、そういえば。

よくよくメールを見ていると
1月20日と3月1日にもメールを受信している、そして今日3月22日。
ちょうど忙しい時期だったので見逃していたようだ。

## Google is my friend
こちらのサイトさんが参考になりました。
2022.02.25 [Turing.comからのオファー](https://zenn.dev/tantan_tanuki/articles/cd3ffac8d80292)

Githubのメールについてはコミット時にメールアドレスがわかるぽい?
2021-03-27 [Git/GitHubのメールアドレス周りについて調べた](https://kamatimaru.hatenablog.com/entry/2021/03/27/175644)
2017-10-12 [GitHubのメールアドレスが漏れる？コミット時のメールアドレスにnoreplyを設定](https://ryoichi0102.hatenablog.com/entry/2017/10/12/000713)

私はコミットはしておらず、SSG(gatsby)用にリポジトリを作成していたことがあったくらい。。。
いまはプライベートのみしか無いのでちょっとテストしてみた

## Publicを作成しgit cloneで確認してみた

testのリポジトリを作成しcloneして内容を確認してみた
[git log]ではメールアドレスの表示はなかった
コミットの場合はgot logで表示されるようだ

ただ今回はコミットではない！
地道にファイルを見ていったところ下記にアドレスの記載を発見した
[test\.git\logs\refs\heads\main]
```
>git clone https://github.com/○○ ○○/test.git
Cloning into 'test'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.

>cd test

test>git log
commit 4b8740a7e2c7sads342sda36bc808a03870313 (HEAD -> main, origin/main, origin/HEAD)
Author: ○○ ○○ <54393851+○○ ○○@users.noreply.github.com>
Date:   Tue Mar 22 15:49:50 2022 +0900

    Initial commit

test>type test\.git\logs\refs\heads\main
0000000000000000000000000000000000000000 663f6291d4acf650df79asdi8u887d541fd0f7sdasda9 ○○ ○○ <○○○○○○○@gmail.com> 16472345659 +0900  clone: from https://github.com/○○ ○○/test.git

```

どうやって変更したらいいのか調査中。それまではすべてPrivateでリポジトリ作成しよう。。。

<hr>
2022/3/23追記

[GitのAuthorとCommiterを変更する方法をご紹介！](https://qumeru.com/magazine/519)
こちらを参考にした。
[.git/config]ファイル内のメールアドレスを変更すれば良いようだ。

## メールアドレスの変更方法
2022/12/22 追記
以下コマンドでローカルPCなどの設定値が確認できる。
今回確認する項目は「user.name」と「user.email」になる。

```
>git config --list
※実行結果は省略
```

変更する際のコマンドは以下となります。
ユーザ名の変更は私は実施しなかった。

メールアドレスはnoreplayのメールアドレスがあるのでそちらが良いのかと思います。
こちらが参考になりました。[GitHubのメアドをnoreplyに設定する](https://qiita.com/Suzuki09/items/e0a7a2628e30b1b8363b)


```
#ユーザ名の変更コマンド
>git config --global user.name ****
※****は任意のユーザ名を記載

# メールアドレスの変更コマンド
>git config --global user.email ****@****
※****は任意のメールアドレスを記載
```
Blenderで別の画像を重ね合わせる方法

## 概要

すでに存在しているマテリアルの上に、一部だけ別の画像を重ね合わせる方法を紹介します。
たとえば、下記のように地球のマテリアルの上に葉っぱを重ね合わせます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/a277c5a4-d302-53e7-0c9f-cbbcf315a4f7.png" width="400">

わかりやすい方法としては、メッシュを複製して分離して別オブジェクトにする方法があります。しかし、この方はメッシュが別管理になり修正が面倒になります。

ここでは、メッシュはそのままで、別の画像を重ね合わせる方法を紹介します。

## この方法のポイント

- 元のマテリアルをグループ化して再利用可能にする
- 重ね合わせたい部分について、元のマテリアルのUVマップとは別に、重ね合わせ用のUVマップを作成する
- 重ね合わせたい部分について、RGBミックスで異なるUVマップのカラーをミックスする

## 手順

具体例を通して説明します。

- UV球を追加します。
- Shadingワークスペースを開き、マテリアルを新規追加し、ベースカラーに地球の画像テクスチャを指定します（下図）。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/a6c26617-7797-df93-3b26-3eed3736decb.png" width="400">

- プリンシプルBSDFノードより左側の部分（今回は画像テクスチャノードだけ）を選択し、`Ctrl + G`（グループ作成）でグループ作成します。特に編集しないので、`Tab`で戻ります。作成したグループに名前をつけます。ここでは`base`とします（下図）。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/84aff9fe-e87b-efb7-4cc0-1c5fdc67343b.png" width="300">

※ 今回は、画像テクスチャノードだけですが、もっと複雑なノード構成でも可能です。

- マテリアルを追加し、同じマテリアルを選びます（下図）。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/4244895b-95be-96a9-79f4-afd6dcb5b260.png" width="240">

- コピーを作りたいので、上図の「`2`」のボタン、もしくはその2つ隣の「新規マテリアル」のボタンを押します（下図）。これにより、このマテリアルを修正しても元のマテリアルは変更されなくなります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/6dfb5cac-7ab1-03a5-bc08-b5e8a4b1fe8b.png" width="200">

- Shadingワークスペースのまま、3Dビューポートで編集モードに入り、重ね合わせしたい部分を選択します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/bf7f0d1b-97c6-c0f4-6eae-a9d4b68b85a6.png" width="300">

- 編集モードのまま、マテリアルプロパティで`Material.001`を選択していることを確認し「割り当て」ボタンを押します（下図）。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/7ec6cf4d-3261-e3ac-d568-7614549ff5c3.png" width="200">

- オブジェクトモードに戻ります。
- 画像テクスチャノードとRGBミックスノードを追加し、下記のようにノードを組みます。左下の画像テクスチャノードが重ね合わせたい画像です。画像で重ね合わせしたくない部分のアルファは0とします。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/931982a4-e0ac-cb9e-0cbe-7b65e96a0ba5.png" width="600">

- このままでは、思った通りの画像が出ないので、新しくUVマップを作ります。
- UV Editingワークスペースを開き、重ね合わせしたい画像を開きます。
- 右下のオブジェクトデータプロパティのUVマップの「`+`」ボタンを押し、新しいUVマップを作ります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/332e7042-1d78-b30e-ef38-480cf1232513.png" width="300">

- 重ね合わせしたい部分がうまく表示されるように、UVを編集します（下図）。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/400ca363-0987-eea6-31c8-380de0431eb0.png" width="300">

- Shadingワークスペースに戻り、`Shift + A`（追加）→入力→UVマップでUVマップノードを追加し、対象のUVマップに新しく作成したUVマップを指定します。そして画像テクスチャノードと接続します（下図）。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/bc9de33f-d852-0247-599d-cc8f46c1ad38.png" width="300">

これにより、下記のように一部だけ重ね合わせしたマテリアルになります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13955/a277c5a4-d302-53e7-0c9f-cbbcf315a4f7.png" width="400">

## 補足

今回は、RGBミックスノードで、カラーをミックスしました。シェーダーミックスノードを使えば、シェーダーを重ね合わせできます。ただし、シェーダーミックスノードは、Eeveeしか使えないのでご注意ください。

以上
Stripe Billingで、プラン変更時の比例配分で減額した請求の元データを取得する

Stripeを利用したサブスクリプションでは、プラン変更時に「変更した時から、本来の契約期間終了日までの未使用分」を値引きすることができます。

https://stripe.com/docs/billing/subscriptions/prorations

この時、請求書には、「Unused time on Starter plan after 05 Apr 2022」のように明細が記録されます。

![スクリーンショット 2022-03-22 15.48.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/d3b34ba5-1810-0071-303d-22581926f0be.png)

一見便利な仕組みですが、ユーザーによっては「なぜ値引きされたか」や「何に対して値引きされたか」を知りたいとサポートに問い合わせされるケースもあります。

ここでは、UI上でユーザーがより詳細な請求内容を確認できるようにする方法として、「**どの請求書に対して比例配分が行われたか**」を調べる方法を紹介します。

# 請求書の`proration_details`で対象の請求書IDが取得可能

請求書のデータをAPIから取得すると、`proration_details`がレスポンスに含まれています。

```js
{
  proration_details: {
    credited_items: {
     invoice: 'in_xxxx',
     invoice_line_items: ['li_xxxx']
   }
 },
  ...
}
```

このデータを利用することで、何に対しての比例配分だったかを調べることができます。

# `proration_details`から対象の請求書データを取得するコードサンプル

以下のコードでは、請求書の明細１行ごとに対応する請求書を取得できます。

```js
const getCreditedInvoice = async (prorationDetails) => {
  if (!prorationDetails || !prorationDetails.credited_items) return null;
  const creditedInvoiceId = prorationDetails.credited_items.invoice;
  const creditedInvoice = await stripe.invoices.retrieve(creditedInvoiceId);
  return creditedInvoice
};


const id = 'in_xxx';
const invoice = await stripe.invoices.retrieve(id);
await Promise.all(invoice.lines.data.map(async line => {
  console.log(await getCreditedInvoice(line.proration_details));
}));
```

もし、明細の行まで指定したい場合は、以下のような関数を追加しましょう。

```js
const getCreditedInvoice = async (prorationDetails) => {
  if (!prorationDetails || !prorationDetails.credited_items) return null;
  const creditedInvoiceId = prorationDetails.credited_items.invoice;
  const creditedInvoice = await stripe.invoices.retrieve(creditedInvoiceId);
  return creditedInvoice
};

const findCreditedInvoiceLineItems = async (prorationDetails, invoice) => {
  if (!prorationDetails || !prorationDetails.credited_items) return [];
  if (!invoice || !invoice.lines.data) return [];
  const creditedInvoiceLineIds = prorationDetails.credited_items.invoice_line_items;
  const targets = invoice.lines.data.filter(line => creditedInvoiceLineIds.includes(line.id));
  return targets;
};

const id = 'in_xxx';
const invoice = await stripe.invoices.retrieve(id);
await Promise.all(invoice.lines.data.map(async line => {
  const invoice = await getCreditedInvoice(line.proration_details);
  console.log(await findCreditedInvoiceLineItems(line.proration_details, invoice));
}));

```

# attributeの違い

|Invoice line item attribute|Description|
|:--|:--|
|proration_details.credited_items.invoice|クレジットされた請求書の明細を含む請求書のID|
|proration_details.credited_items.invoice_line_items|クレジットされた請求書の明細のID（複数）|


# [PR] Stripe開発者向け情報をQiitaにて配信中！

- [Stripe Updates]：開発者向けStripeアップデート紹介・解説
- ユースケース別のStripe製品や実装サンプルの紹介
- Stripeと外部サービス・OSSとの連携方法やTipsの紹介
- 初心者向けのチュートリアル(予定)

など、Stripeを利用してオンラインビジネスを始める方法について週に２〜３本ペースで更新中です。

-> [Stripe Organizationsをフォローして最新情報をQiitaで受け取る](https://qiita.com/organizations/stripe)
Oracle Cloud お役立ちリンク集 - 技術学習/セミナー/事例集etc…

:::note info
インフォメーション
2022/3/22時点の情報です
:::

# はじめに
Oracle Cloud関連の技術資料集、各種セミナーや事例集などのリンクを毎度探すのは面倒だったのでこれを機に一度情報のとりまとめをしてみました。
筆者が調べてわかる範囲なので不足があるかもしれませんがご参考になれば幸いです。

# 技術関連のドキュメント/動画　URLリンク

### [Oracle Cloud Infrastructure 活用資料集](https://oracle-japan.github.io/ocidocs/)
OCIの技術資料集となっており、サービス別で技術資料や、セミナー動画がアップロードされています。
OCI全体の概要資料からサービス別の詳細資料まで網羅されているので、これからOCIに触れる人やOCI勉強中の方は必見です。
注意点として公開されている資料は最新情報ではないので、各種制約やオプションについてアップデートされている可能性があります。


### [Oracle Cloud Infrastructureドキュメント](https://docs.oracle.com/ja-jp/iaas/Content/home.htm)
OCI各サービスのマニュアル集です。
上記のOracle Cloud Infrastructure活用資料集に記載のないような詳細な情報や、
作業手順を確認する用途で使用される方が多いと思います。
※主要なサービスについては日本語ですが、サービスによっては英語しかないものがあるようです…


### [チュートリアル: OCI を使ってみよう](https://oracle-japan.github.io/ocitutorials/)
OCIにおけるスタンダードな操作を一通り習得できるチュートリアル・リファレンスです。

オーソドックスな仮想インターネット(=VCN)の構築や仮想マシン インスタンス(=Compute)の構築から、
モニタリングサービスやオートスケールといった応用レベルのコンテンツも多数あるのでクラウド初心者からクラウドの開発/運用担当者など幅広い方に参考になるかと思います。
Always Freeという無償環境で色々操作できるので、目を通すだけでなく、実際に操作してみることをおすすめします。


### [オラクルエンジニア通信](https://blogs.oracle.com/oracle4engineer/)
OCIのアップデート情報、事例記事、ウェビナーリンク等をまとめたブログとなっています。
日々アップデートされていくOCIの最新技術を追うには最適なブログかと思います。


### [セミナー情報](https://blogs.oracle.com/oracle4engineer/post/oci-seminar)
Oracle Cloud InfrastructureやOracle Databaseをはじめとする、さまざまな製品についてのウェビナーリンクのページです。
最新サービス情報および最新活用事例、製品の技術情報、業務部門やIT部門、ITエンジニアまで幅広いターゲットとしているので気になるものがあれば参加をおすすめします。


### [Youtubeチャンネル「Japan Oracle Developers」](https://www.youtube.com/c/JapanOracleDevelopers)
クラウドエンジニア向けの各種イベントやセミナーのアーカイブが掲載されています。
"OCI スキルアップ セミナー"という再生リストはOCIについて勉強になるコンテンツが多いので時間がある際にでも視聴をおすすめします。

### [書籍「Oracle Cloud Infrastructure 徹底入門」](https://www.shoeisha.co.jp/book/detail/9784798169033)
OCIに興味があるエンジニア向けの業務システムを設計、構築するために必要な知識を一冊で学ぶことができる書籍とのこと。
書籍ベースで勉強したい方は必見です。
(筆者はまだ購入もしていないので、近々購入してみようかと検討しています)

# 運用関連の技術ドキュメント　URLリンク

### [リージョン別サービス提供状況](https://www.oracle.com/cloud/data-regions/#apac)
OCIの各リージョンにおけるサービス提供状況などが確認可能です。
東京リージョンではサービス提供しているものの、大阪リージョンではサービス提供していないものもあるので要確認かと思います。
(例.Oracle Cloud Infrastructure to Microsoft Azure Interconnectなど)


### [OCI Status(=サービス稼働状況)](https://ocistatus.oraclecloud.com/)
OCIの各リージョンにおける各サービスの稼働状況ダッシュボードです。
障害発生時などはこちらも確認して障害原因の切り分けなどに利用してください。
※東京/大阪リージョンを確認する際はAPACタブを選択してください


# その他のドキュメント　URLリンク

### [お客様活用事例](https://blogs.oracle.com/oracle4engineer/post/oci-customer-reference)
日本国内のOCI事例集です。
案件毎に利用サービス名や業種の記載があるので、OCI事例を探す際に便利かと思います。


### [Oracle Cloud Days 2021アーカイブ](https://www.oracle.com/jp/cloud/events/cloud-days/on-demand/)
2021年11月9日（火）～12日（金）に開催したセッションのオンデマンド動画ページです。
Oracle Cloud Daysは日本オラクルの最大オンラインイベントとなっており、
既存のITシステムのModernizationを実現された事例、データの利活用によりビジネス・イノベーションやDXを実現された事例、最新のクラウドテクノロジーを活用してビジネスの成長を実現された事例などが紹介されていました。


### [オラクルのニュース](https://www.oracle.com/jp/news/)
経営情報や各種事例などオラクルに関する最新ニュースが掲載されています。


# 終わりに
Oracle Cloudは学習コンテンツが充実し始めているなとリンク集をまとめていて感じました。
特にOCIを今後勉強する必要がある方はそれぞれのリンクにどういったコンテンツがあるのか一度目を通すことをおすすめします。

筆者が見つけられていない、有益なサイトが他にもあるかもしれませんがそれはご了承ください…
パワーポイント(PPT)をPDFに素早く変換する方法｜KUROKO blog｜プレゼンを思考するメディア

 https://ppt.kuroko.me/blog/ppt-to-pdf/
別名で保存でファイル形式をpdfにするだけだけど
ネット上にはなんか怪しいのがいっぱいあるな－(^_^;)
Rails 日付日時の入力を簡単に実装するヘルパーメソッド

Railsにて新規アプリケーションを作成しており、日付と日時を合わせて入力できるヘルパーメソッドを使用しましたのでアウトプットさせて頂きます。

記録機能を実装する上で新規記録時に日時と時間をフォーム形式で入力させたかったので
以下のような記述で入力ページを作成しました。<br>(完成はしていなく日時と時間の欄をアウトプットする)

```app/views/コントローラー名/new.html.erb
<%=form_with model: @record, url:records_path,local: true do |f| %>
  <div class="record-box">
    <h1 class="page-heading">食事を記録する</h1>
      <div class="field">
        <%= f.label :datetime, '日時(必須)', class: 'control-label' %><br>
        <%= f.datetime_field :datetime, class: 'form-control' %>
      </div>

      <div class="field">
         <%= f.label :age_id, '年齢(必須)', class: 'control-label' %>
         <%= f.collection_select(:age_id, Age.all, :id, :name, {}, {class:"select-box"}) %>
      </div>

        <%= f.submit "記録する" ,class:"btn" %>
  </div>
<% end %>
```

form.labelにはカラム名、表示させたい文字、クラス名を設定しました。
form.datetime_fieldにはカラム名、クラス名を設定しました。
```
<%= f.label :datetime, '日時(必須)', class: 'control-label' %><br>
<%= f.datetime_field :datetime, class: 'form-control' %>
```

モデルとコントローラーを作成することが前提ですが、
以下のような見た目になりました。(cssはほぼノータッチ)
![スクリーンショット 2022-03-22 15.39.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2520356/4cdbd047-0cf7-4409-18bc-9adb64ef1919.png)

調べてみると意外に簡単でしたので今後も活用していきたいと思います。

アドバイスやご指摘等ございましたらぜひお願いします！！

以上
Pythonでzipを展開する（Bandcampでダウンロードしたアルバムをアーティスト/アルバム名に展開）


書いた理由：
Bandcampでアルバムを大量にダウンロードしたが、zip内に直でmp3が置かれている。
「アーティスト名/アルバム名」フォルダに展開したい。

```python:ZipOpener.py
# coding: utf-8

from zipfile import ZipFile
import os
import glob

#zipファイル名は「アーティスト名 - アルバム名.zip」を想定
delimiter = " - "

current_dir_name = os.path.dirname(__file__)
file_names = glob.glob(current_dir_name + "/*.zip")

for file_name in file_names:
    print(file_name)

    artist_name, album_name = file_name[:-4].split(delimiter, 1)
    tgt_dir = os.path.join(current_dir_name, artist_name, album_name)

    with ZipFile(file_name, 'r') as zip:
        zip.printdir()
        zip.extractall(tgt_dir) 
```

使い方：
1.ZipOpener.pyをダウンロードしたzipファイルと同じディレクトリに置きます。
2.ZipOpener.pyを実行します。

注意点：
delimiterで区切られていないファイルがあるとエラーを吐きます。
不安な場合、zip.extractall(tgt_dir) をコメントアウトして実行するとすぐ問題のファイルが分かります。

今度やりたいこと：
マルチスレッドでやってみたい
ZABBIXのアラートに対応手順のリンクを貼ってアラート対応を迅速化する

# 内容

下記記事でOSSを利用した業務効率化を記載しました。

https://qiita.com/Toru_Kubota/items/f62910c0b5566c6cffcc

各システムの対応手順はPleasanterなどにまとめているのですが、件数が多くアラート発生後、該当の手順を探すと時間がかかったり対応を間違えてしまうことがあります。そこでZABBIXのアラートメールにPlesanterのリンクを追加しました。
アラートメールのリンクをクリックすると該当情報ページに直ぐに行けるため対応迅速化に繋がりました。ZABBIXのホスト情報の設定とメディアタイプの設定から行えます。

![zabbix-pst1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/6ca5b4db-42e1-962c-808c-8be7925d6fec.png)

# 環境
* ZABBIX Server Ver 5.0.14

# 設定方法

* メディアタイプのメッセージテンプレート変更

設定⇒メディアタイプ⇒該当のものを選択⇒メッセージテンプレートを選択します。
メッセージの中に{HOST.DESCRIPTION}を追加します。
下記ホスト設定の「説明」欄に該当します。

![zabbix-pst2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/18a27e6b-6941-157b-8ad3-25e40593073b.png)


* ホスト設定の変更
ホスト設定の説明欄にPleasanterのリンクを入力します。
アラート発生時、ここに入力した項目が表示されます。

![zabbix-pst3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/ef30a398-3fc7-95ce-455d-8858239b8e48.png)

* アラートメール確認
下記の様な形式でアラートメールを受信します。

![zabbix-pst4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/9892c950-c615-8c35-1db7-4546bcb723ec.png)
Python: プロトコルクラスの代わりにジェネリック型を返す

## 概要
あるプロトコルを満たすオブジェクトを受け取り、そのオブジェクトを返す関数を考える。この関数の引数及び戻り値の型は、プロトコルクラスそのものより、プロトコルクラスを上界としたジェネリック型にしておくと都合が良い。

## 具体例
次のようなプロトコルを使ってソート関数を定義する。
ソート関数は破壊的で、利便性のためにソート結果を返すとする。

```py
class Sortable(Protocol):
    def __len__(self) -> int:
        ...

    def swap(self, i: int, j: int) -> None:
        ...

    def less(self, i: int, j: int) -> bool:
        ...


def sort(c: Sortable) -> Sortable:
    ...
    return c
```

この時、上のソート関数のように戻り値の型がプロトコルクラスになっていると、受け取ったオブジェクトに対する操作が制限されてしまう。

例えば、次のような`get`メソッドを持つオブジェクトをソートすると、戻り値の型が`Sortable`なので`get`メソッドが見つからない。

```py
class WeightedList:
    def __len__(self) -> int:
        ...

    def swap(self, i: int, j: int) -> None:
        ...

    def less(self, i: int, j: int) -> bool: 
        ...

    def get(self, i: int) -> str: 
        ...


items = WeightedList()
...
sort(items).get(10)  # -> "Sortable" has no attribute “get”
```

もちろん今回の場合は二行に分けて、

```py
sort(items)
items.get(10)
```

などとすれば問題ないのだが、lambda式の中では使えない。


## 解決策
戻り値の型をプロトコルクラスではなく、受け取ったオブジェクトの型と一致させれば良い。
つまりプロトコルを満たすジェネリック型を受け取り同じ型を返す関数として定義する。

```py
T = TypeVar("T", bound=Sortable)

def sort(c: T) -> T:
    ...
    return c


items = WeightedList()
...
sort(items).get(10)  # sort(items)は WeightedList を返すので get を使える
```

デメリットとしては、型変数の名前をシンプルな`T`などとしていると、何を受け取る関数なのか自明でなくなってしまう。
![pycharm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62253/8fe4f343-7ed0-3688-804c-2a3bf3468d01.png)
「`Sortable`を継承している任意の型」と一目で分かる良い名前があれば良いのだけれど・・・。

## ところで
この`TypeVar`における`bound`の使い方は、ドキュメントには説明されていません。
[`TypeVar`](https://docs.python.org/3.10/library/typing.html#typing.TypeVar)の項には、

> a type variable may specify an upper bound using bound= `<type>`. This means that an actual type substituted (explicitly or implicitly) for the type variable must be a subclass of the boundary type, see PEP 484.

と書かれていて、「an actual type ... must be a subclass of the boundary type」今回の例だと`WeightedList`は`Sortable`のサブクラスである必要があるように読めます。

厳密に言えば、`WeightedList`は`Sortable`の[構造的部分型(structural subtyping)](https://docs.python.org/3.10/library/typing.html#nominal-vs-structural-subtyping)であってサブクラスではありません。
エラーになるかと思いましたが、mypyではエラーになりませんでした。

ついでなので、[PEP 484 の該当部分](https://peps.python.org/pep-0484/#type-variables-with-an-upper-bound)を見てみると、

> A type variable may specify an upper bound using bound= `<type>` (note: `<type>` itself cannot be parameterized by type variables). This means that an actual type substituted (explicitly or implicitly) for the type variable must be a subtype of the boundary type.

となっていました。「an actual type ... must be a subtype of the boundary type」つまり構造的部分型でも問題ないようです。
【Salesforce】レポートでログイン履歴を表示したい

# 問題

![ログイン履歴.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492812/3c87dc91-cfe7-c088-38be-93f6b873b2cc.jpeg)

上記のログイン履歴で出力すると全期間が出るが、先月だけの表示をしたい。

# 解決策

![ユーザの項目.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492812/a57813be-6d5b-fa2a-8d21-8cf1cb91684a.jpeg)

レポートでユーザを指定するとログイン履歴も表示できる。

もちろん条件指定も可能。

# 根拠

![カスタムレポートタイプ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492812/c4d7fd1a-3894-8df9-e53a-6897a81ec74d.jpeg)

カスタムレポートタイプでログイン履歴が無い。

![レポートタイプ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492812/206e317a-138e-f2cf-c32c-21514c95e8d7.jpeg)

レポートタイプでもログイン履歴が無い。

小林「じゃーログイン履歴はレポートで出せないんすね～」と思ってたら出せた。
こういうのやめてほしい。

# 参考リンク

[1][ログイン履歴の監視](https://help.salesforce.com/s/articleView?id=sf.users_login_history.htm&type=5)

[2][Salesfoceのログイン履歴の確認方法とは？レポート表示や注意点など紹介](https://frogwell.co.jp/blogs/salesforce-login/)

[3][SFDC：Login Historyでログイン履歴を参照する](https://tyoshikawa1106.hatenablog.com/entry/2014/11/09/150436)
matlabで配列を書き出してPythonで読み込む

そんなこともありますわな

マトラボ変数をMatファイルで書き出してScipyで読み込みます

# matlabでmatファイルを書き出す
matファイルはHDF5的な書き出しができて、なおかつファイルサイズもお手頃で素敵です。

保存したい変数を次のように用意するとして

```sample.m
p = rand(1,10);
q = ones(10);
```
保存はこう
```sample.m
save('sample.mat','p','q')
```
別に変数一つずつ保存してもらってもいいし、まとめて保存しても良いです。
変数はpythonで読むときのkeyにもなります。

# Pythonで読み込む
Scipyで読み込むと楽です。

```sample.py
from scipy.io import loadmat

mat = loadmat("sample.mat")

p = mat["p"]
q = mat["q"]

"""
mat

{'__header__': b'MATLAB 5.0 MAT-file, Platform: PCWIN64, Created on: Thu Mar 17 20:56:18 2022',
 '__version__': '1.0',
 '__globals__': [],
 'p': array([[ 9.20610261e-01+5.33716017e-04j,  1.48098207e-01+1.37103097e-03j,
         -6.05423217e-02+4.97786550e-04j, ...,
         -1.29067978e-02-1.75805343e-05j, -5.98711507e-03+1.70542157e-06j,
         -3.41703417e-02-2.97162334e-06j],
        [ 7.78413766e-01+2.07434704e-01j, -5.29508081e-01-3.98614515e-02j,
         -2.22033326e-03+1.92038018e-01j, ...,
         -1.43717870e-01+5.92793752e-01j,  6.08463911e-01-1.28892855e-01j,
         -4.48988646e-01-4.41817629e-01j],
        [ 6.53348627e-02-1.16482903e-01j,  1.20795314e-01-1.22166736e-01j,
          2.05349556e-01+5.95030609e-01j, ...,
         -3.88507368e-01+2.14046387e-01j, -6.56241982e-02+8.11742302e-02j,
         -6.18053104e-01-4.76789143e-01j],
        ...,
        [-4.96542729e-04-3.06323181e-05j,  1.37027067e-03+8.29222340e-05j,
         -5.08556043e-04-2.42244334e-05j, ...,
         -1.79536450e-05+5.10806267e-07j,  8.69602806e-07-2.13918906e-07j,
         -2.44910908e-06-5.23879227e-08j],
        [ 4.87682061e-04+2.54058950e-05j,  1.36103872e-03+6.73835019e-05j,
          5.01392178e-04+2.19939364e-05j, ...,
         -1.88442556e-05+1.33598648e-06j,  5.54320250e-07-8.69686817e-07j,
         -2.99690101e-06-8.20490071e-07j],
        [-4.49789492e-04-2.01375169e-05j,  1.33779474e-03+2.64936269e-05j,
         -5.04687513e-04-1.14785598e-05j, ...,
         -1.89231039e-05+3.94031712e-07j,  5.47719410e-07-5.93547698e-07j,
         -2.13166913e-06-8.44838064e-07j]])}
 'q': array([1,1,1,1,1...1,1,1])}

"""
```

以上です
Docker + Next.jsでAPIを叩く時のプチハマり


以前構築した Docker + Nginx + Node.js環境でAPIを叩く時にプチハマりしたことを書きます。
環境は↓

https://qiita.com/YasuhaF/items/b42de23a7517406dddd6

## やりたいこと
`getServerSideProps`内と`NextPage`内それぞれでAPIを叩きたい。

## やったこと
#### NextPage内
エンドポイントが`localhost:8080/api/get-hoge`であるとする。

```ts
const res = await fetch('http://localhost:8080/api/hoge',
{
  method: 'GET',
  // 略
});
```

こちらはうまくいきました。が、

#### getServerSideProps内
```.ts
const res = await fetch('http://localhost:8080/api/hoge',
{
  method: 'GET',
  // 略
});
```

こっちは
`Server Error / Error: connect ECONNREFFUSED` ~~って出ちゃいました
調べていると、クライアントサイドとサーバーサイドで叩くドメインを変えないいけないようなので、

```ts
const res = await fetch('http://host.docker.internal:8080/api/hoge',
{
  method: 'GET',
  // 略
});
```

これでできました。

## 参考

https://github.com/vercel/next.js/discussions/17585
Docker + Nginx + Node.js で開発環境構築

## はじめに
業務でNext.jsに触れる機会があったのでDockerで開発環境構築をやってみたいと思ったので書いていきます。実際にはMySQLも含みますがサーバーサイド側のため割愛します。

*ローカル開発環境構築の想定のため、セキュリティは本番環境を想定していません。

## やりたいこと
`docker-compose`で`Nginx`コンテナをリバースプロキシとして`Node.js`コンテナへリクエストを投げる環境の構築

##環境構築
Docker for Macをインストール済みかつNext.jsでプロジェクト作成済みを想定


#### docker version

```terminal
$docker --version
Docker version 20.10.6, build 370c289
```

#### ディレクトリ構造
```terminal
├── docker-compose.yml
├── node
|   ├── Dockerfile 
├── nginx
   ├── default.conf 
  
```

#### docker-compose.yml
```yml
services:
  nginx:
    image: nginx:1.21-alpine
    container_name: next-nginx
    ports:
      - "80:80"
    depends_on:
      - node
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
  node:
    build: ./node
    container_name: node
    volumes:
      - {プロジェクトルーティング}/:/usr/src/app/
```

#### Dockerfile
curl使ってAPIとの連携確認できたら便利かなと思い入れています。

```Dockerfile
FROM node:16-alpine

RUN apk --no-cache add curl

WORKDIR /usr/src/app/
```

#### default.conf

```conf
server {
    listen 80;
    server_name node.docker.internal;

    root /var/www/public;

    access_log /var/log/nginx/access.log;
    error_log  /var/log/nginx/error.log;

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass 127.0.0.1:3000;
    }
}
```

#### /etc/hosts
```terminal
127.0.0.1 node.docker.internal
```

## docker-compose up
```terminal
$docker-compose up -d --build // imageダウンロードとかbuildのログがいっぱいでてきます。
$docker-compose ps
    Name                   Command               State                           Ports
--------------------------------------------------------------------------------------------------------------
nginx      /docker-entrypoint.sh ngin ...          Up      0.0.0.0:80->80/tcp,:::80->80/tcp
node       docker-entrypoint.sh npm r ...          Up      3000/tcp, 5000/tcp,
```
うまく起動できたようなので次はnodeコンテナに入り`npm run dev`を実行します。

```terminal
$docker-compose exec node sh
$npm run dev
```

これで`node.docker.internal:80`をたたくとプロジェクトが表示されていると思います。
Finder の殺し方

# 殺り方
macOS の Finder.app は、デフォルトだと終了させることはできないが、以下のコマンドをターミナル[^1]で実行すると終了させることができる。

[^1]: ターミナルの開き方がわからない場合は、[ターミナルの開き方](#ターミナルの開き方) を参照すること。

```shell:Shell
defaults write com.apple.Finder QuitMenuItem -boolean true
killall Finder
```

すると、Finder のメニューバーにアプリを終了する項目が表示されるようになる。

![](https://raw.githubusercontent.com/noraworld/developers-blog-media-ja/master/how-to-kill-finder/Screen%20Shot%202022-03-22%20at%2014.05.05.png)

# メリット
筆者は頻繁に command + tab でアプリケーションを切り替えるのだが、そのときにいちいち Finder が一覧に出てくると、一回分多く tab を入力しなければいけなくて煩わしい。

しかし、この方法で Finder を終了させておくと command + tab を押したときに Finder が出てこないので便利である。

# ターミナルの開き方
command + space を押して Spotlight を開き、`terminal.app` と入力してエンターキーを押すとターミナルが開く。

![](https://raw.githubusercontent.com/noraworld/developers-blog-media-ja/master/how-to-kill-finder/Screen%20Shot%202022-03-22%20at%2014.13.20.png)
BAS(Battery Service)を実装してみよう

# nRF SDK時代
BAS(Battery Service)のように定期的に呼び出す関数を実装する場合、nRF SDKではほぼ書き方が決まっていました。おそらくほとんどの人はapp_timer_start()という低精度タイマーを使ったタイマー割り込みによる実装をしていたと思います。
これはSDKに付属しているサンプルプロジェクトにそのように記述されているというのもありますが、バッテリー残量の更新程度ならそんなに緻密な割り込み精度は必要がないという設計理論の元にそういう設計をしているわけです。

:::note
別に中の人に確認したわけではないけれど、きっとそうだと信じたい・・・
:::

# Zephyrでの実装方法
ZephyrはRTOSということもあって実装方法が多岐に渡っています。いや、これだと語弊があるので言い直すと、手段がいっぱい用意されているので好きにして、と言ったところでしょうか。パッと思いつくだけでも以下のようなやり方があります。
## mainループ内での実装
main関数内で初期化が終わったあとに出てくるwhile無限ループ句(別にforでもなんでもいいですが)の中に実装するというのが一番ポピュラーな実装ではないかと思われます。具体的には

``` main.c
void main(void)
{
    // Initialize
    hoge();

    // Main loop
    while (1)
    {
        bt_bas_set_battery_level(battery_level);
        k_sleep(K_SECONDS(10));
    }
}
```
こんな感じになると思います。mainループは専用のキューを持っているので上記のような記述であれば専用スレッドとなります。
## タイマースレッドでの実装
nRF Connect SDK(以下、NCS)にもタイマーというのはもちろんありますが、nRF SDK時代にあった低精度タイマーという概念はありません。タイマーで実装する場合はこんな感じになると思います。

```main.c
static void bas_handler(struct k_timer *timer)
{
    bt_bas_set_battery_level(battery_level);
}
K_TIMER_DEFINE(timer_bas, bas_handler, NULL);

void main(void)
{
    // Initialize
    hoge();

    // Battery Timer
    k_timer_start(&timer_bas, K_NO_WAIT, K_SECONDS(5));
}
```
タイマースレッドはシステムキュー上で実行されるため、他にシステムキュー上で待つ何かがあると実行されなくなりますが、システムキュー上で無限待ちのセマフォを組んだりすることはないのでタイマー処理でも大丈夫だと思います。

:::note
一例としてI2CやSPIを非同期処理にするとコールバックがシステムキュー上に返ってきます。
:::

## ワーカースレッドでの実装
タイマースレッドでの実装とほぼ一緒ですが、タイマースレッドでの実装と違うのはユーザーキューを指定することができるという点です。デフォルトで使うとシステムキューに投げるので、それだとタイマースレッドでの実装と一緒です。
# mainスレッドがおススメ
一応おススメ順という形で並べては見たのですが、ここまで見比べてみても分かるようにmainスレッドで実装するのが圧倒的にコード量が少ないです。
(ワーカースレッドはさらにユーザーキューを宣言する必要があります)
よほどこだわりがあるのでなければmainスレッド内に実装するのがおススメですし、なによりも分かり易いですよね。
## 余談
なんでこんなことを説明したかというと、NCSを触り始めて割と初期段階で疑問に思うことなんですよね。サンプルを漁るとmainスレッドで実装したサンプルがあるはずですが、いやいや俺はそんなのじゃなくてnRF SDK時代のようにタイマーで実装したいんだよ、とか厨二が発動しちゃったりするわけですよ、ええ(笑)。
もう少し理解が進んでくるとタイマーじゃなくてスレッド(タイマーもスレッドですがここでのスレッドはワーカースレッド)で実装できるんじゃね？とか思いついたりするわけです。
実際にやってみると確かに実装できますし、あまりにもあっさりできるので拍子抜けするくらいなのですが、じゃあこれっていったい何が違うの？という疑問に発展するわけです。
結論としては使っているキューが違うだけで、そのキュー内でデッドロックさえしなければ何を使っても変わらない、なのですがなかなかそこまで辿り着くのは時間がかかります(笑)。
Pythonの関数をGUIで管理、テスト可能なOSSライブラリ「Logicbook」を開発した話

# Logicbookとは

**Logicbook**はPythonの関数を独立してGUI上で管理・テストするためのオープンソースライブラリです。
Reactのコンポーネント管理ライブラリ「Storybook」のPython関数版のようなイメージです。

#### Reference

詳しいドキュメントは[こちら](https://ruihirano.github.io/logicbook/)にあるので興味がある方は一度使ってみてください。
Githubはこちら [https://github.com/RuiHirano/logicbook](https://github.com/RuiHirano/logicbook)

![example_join.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251551/589140c7-ee59-061e-1303-d2f1f6d1057c.png)


## 開発しようと思ったきっかけ

現在。私は3年ほど大学発ベンチャー会社のソフトウェア開発に関っており、Webアプリを5人ほどのチームで開発しています。Webアプリは基本的にfrontendはreactを用いてbackendのAPIにはpythonを使用してます。

初めの方はfrontend,backendともにどちらも最小限のテストコードしか書いておらず、それでも保守管理にはそこまで問題はなかったのですが、規模が大きくなるにつれてバグだったりエラーが多発するようになっていました。

また、チームの人数も少しずつ増えると実装する機能をそれぞれに分散するため、チーム内のプログラミング能力の差によってコードの書き方に大きく違いがでてしまうという問題もありました。しかも、新しい人が加わると既存コードの説明をするために何回も打ち合わせを繰り返しておりサポートに大きな時間を割かれていました。

こういった経緯から **「既存コードをうまく説明可能な状態で保守管理できる方法」** はないのかなと思い始めました。
Reactについては「Storybook」というOSSでコンポーネント管理ツールがあり、とても便利に活用しています。

しかし、Pythonに関しては調べてもそのようなライブラリが見当たりませんでした。
そこで、どうせなら自身でOSSとして開発しようと思い、**Logicbook**の開発を始めました。

**Logicbook**は「Storybook」を意識していて、開発においてかなり参考にしています。
現在はまだβ版ですが、今後も開発を続け正式リリースできることを目標としています。


# Logicbookでできること

GUIでできることはREADMEやソースコードの確認、関数の実行、テストの自動実行などいくつかあります。

![example_join.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251551/589140c7-ee59-061e-1303-d2f1f6d1057c.png)

### Example
Exampleの項目では実際の関数に対して任意の入力を行いどのような出力がされるかを確認できます。複雑な関数でも一つ一つの関数の入力と出力のみを意識するだけで扱えるため、挙動を理解しやすくなります。

![example_movie (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251551/996da313-c7a1-0519-8e84-ace672028f18.gif)


### Test
Testの項目ではファイルに変更が加わり保存されたタイミングで自動的にテスト実行されます。(GUIの「RUN TEST」をクリックしても実行できます。)
テスト結果に応じて色分けされて表示されるので、視覚的にわかりやすいと思います。

![test_movie.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251551/3773624d-2a21-fc41-2ab4-fc71ed25cc1b.gif)


# Tutorial in less than 5 minutes.

最新のpip3系であればpypiからインストールできます。
```
pip install logicbook
```
### 初期化
```
cd YourProject
logicbook init
# Your Project Name: [プロジェクト名]
# Your Src Path: [srcまでの相対ディレクトリパス]
```
Src Pathはlogicsというlogicbookで管理する設定を記述するためのフォルダを作成するパスです。
デフォルトは/でプロジェクトルート直下に作成されます。srcなどの下の階層に作成したい場合は「src」などと相対パスで入力してください。

### サーバーの立ち上げ

```
cd YourProject
logicbook start
```

上記のコマンドの後、http://localhost:8000 を表示してください。Logicbook UIが表示されていれば成功です。

![example_join.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251551/589140c7-ee59-061e-1303-d2f1f6d1057c.png)

その他、詳しい方法については[ドキュメント](https://ruihirano.github.io/logicbook/)を参照してください。

# おわりに
Pythonで関数を独立させて管理、テストできるOSSライブラリは今まであまりなかったかと思います。

Pythonはわかりやすく書きやすい反面、厳密な型定義がなくtestを書く人も少ないためバグが発生しやすい言語でもあります。将来的には**Logicbook**で一つ一つのロジックを管理しながら開発していくのが当たり前になり、コード管理の一つのアプローチになればいいと考えてます。

まだβ版で正式リリースに向けて開発中なので、興味ある方は一度使ってみて、意見や要望などをいただけたら幸いです。
また、コントリビューターとして一緒に開発していただけるメンバーも募集しているので参加してもらえると嬉しいです。

Logicbook開発者： 平野　流
[C++] true の数を数える小技


bool値を+で足し合わせると、true の個数を出せる。

```cpp
const auto num = true + true + false ; // 2
```

無論、変数でも使える。
```cpp
void func(
  const bool val_0,
  const bool val_1,
  const bool val_2
)
{
  const auto num = val_0 + val_1 + val_2 ;
}

```

# 解説

足し算を行う際に、bool は int へキャストされる。
この際、false は 0 に、true は 1 に、変換される。

```cpp
true + true + false => 1 + 1 + 0
```

結果として、true の数が出てくる。
AWSのec2-userにログイン出来なかった話

## 概要
local環境からawsに構築したEC2へ接続が出来なかった時の対処法について備忘録として記す

## 発生したエラー

```
# ssh ec2-user@IPaddress
Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
```

## 対処法

```
# ssh -i 鍵.pem ec2-user@IPaddress
```

※鍵.pemはEC2作成時に指定した鍵のこと。KMSで管理されているはず。

## 結論
`ssh`コマンドの`-i`オプションで鍵を指定して接続すれば問題なく繋がった。
`-i`で鍵を指定しても上手くいかない場合は、`-vvv`オプションを付与して接続時の詳細を確認すると良い。

## まとめ
今回接続が上手くいかなかった時に検討したものは以下である。
* 作成したEC2にグローバルIPが割り当てられているのか
* セキュリティグループのインバウンドグループで自分のIPが通るように設定しているか
* port22が空いているか
* EC2作成時に指定した鍵が手元に存在するか
* EC2作成時に指定した鍵の権限が設定されているか
フラグに応じてbool値を反転させる時の、簡潔な書き方


以下のコードを考える。
* ゲームの以下の様なケースを想定。
  * 状態異常やステージギミック等で移動方向が反転
  * 2重に反転すると元に戻る

```cpp
double CalcMove( ... )
{
  bool is_reverse = false ;
  if ( character.reverse_flag ) { is_reverse = !is_reverse ; }
  if ( stage.reverse_flag     ) { is_reverse = !is_reverse ; }
  if ( gimmick.reverse_flag   ) { is_reverse = !is_reverse ; }

  const auto sign = ( is_reverse ? -1 : +1 ) ;
  return sign*org_val ;
}
```

フラグ毎に条件分岐をしており、少々冗長な記述になっている。

これは、以下の様に、`!=`で繋ぐ形で、書き換える事が出来る。

```cpp
double CalcMove( ... )
{
  const bool is_reverse
    = ( false != character.reverse_flag != stage.reverse_flag != gimmick.reverse_flag ) ;

  const auto sign = ( is_reverse ? -1 : +1 ) ;
  return sign*org_val ;
}
```

また、true の数を数えて偶奇を判定する方法もある。
```cpp
double CalcMove( ... )
{
  const auto ary = { character.reverse_flag, stage.reverse_flag, gimmick.reverse_flag } ;
  const bool is_reverse = ( std::ranges::count( ary, true )%2 == 1 ) ;

  const auto sign = ( is_reverse ? -1 : +1 ) ;
  return sign*org_val ;
}
```


いずれにせよ、簡潔には書けるが、意図が伝わり辛くなる事には留意。
使う場合は、コメントを残すなどした方がベター。
[Docker]Reactの環境構築をコマンド1発で終わらせる

# はじめに
「DockerでReactの環境構築をしたい、そして楽をしたい」と思いました。

# 手順

### 1. リポジトリをclone

```
git clone https://github.com/4649rixxxz/qiita-react.git
```

### 2. Reactアプリケーションの作成

```
cd qiita-react
qiita-react % make create-project
```

### 3. サーバの立ち上げ

```
qiita-react % make app
/usr/src/react-app # npm start
```

http://localhost:3000 にアクセスしてみると...おめでとうございます！！

# 工夫点
Makefileを使うことによって

1. イメージのビルド
2. コンテナの作成
3. React環境の構築 

上記のすべてをコマンド「create-project」で行うようにした点です。

# その他のコマンド

### コンテナの起動とサーバの立ち上げ

```
make start
```

上記のコマンドはコンテナの起動に加えて、「npm start」もしてくれます。

### コンテナの停止

```
make stop
```

# TODOリスト

新しい言語やライブラリなどを学ぶ時は「TODOリスト作りたい！」となると思います。
[こちら](https://youtu.be/pCA4qpQDZD8)おすすめです。

# さいごに
Makefile最高。
useQuery で取得した変数を 別の useQuery の variables に代入する方法

備忘録。

下のコードのようなことをしようとしても、怒られたり、動かなかったりする。

```javascript
const {data: data1, loading: loading1, error: error1} = useQuery(SOME_QUERY1)
const {data: data2, loading: loading2, error: error2} = useQuery(SOME_QUERY2, {
  variables: {hoge: data1.someQuery1.hoge}
})
```

そのような場合は、useLazyQuery と useEffect を使う。

```javascript
const {data: data1, loading: loading1, error: error1} = useQuery(SOME_QUERY1)
const [fetchSecondData , {data: data2, loading: loading2, error: error2}] = useLazyQuery(SOME_QUERY2)

useEffect(() => {
  if (data1.someQuery1.hoge) {
    fetchSecondData({variables: {hoge: data1.someQuery1.hoge}})
  }
}, [data1])

if (loading1 || loading2) return <div>loading</div>
if (error1 || error2) return <div>error</div>

return(
  <>data2.someQuery2.hoge</>
)
```

https://github.com/trojanowski/react-apollo-hooks/issues/197
rustでatcoderのインタラクティブな問題やるときの注意

## 概要
https://atcoder.jp/contests/abc244/tasks/abc244_c

今回インタラクティブな問題がでてこれを解こうとしたがTLEに引っかかりまくって全くうまくいかなかった
flushしてるはずなのになんで！？とずっと思っていた
結論から言うと出力ではなく入力側で引っかかっていた、つまりproconioを何とかする必要があった。
ちなみに問題の中にflushしろと書いてあるが出力はいつも通りprintln!()でも問題ない。

追記
公式にも解説ったんだね
https://atcoder.jp/contests/abc244/editorial/3625


### 解決法

```rust:
let mut stdin = LineSource::new(BufReader::new(io::stdin()));
macro_rules! input(($($tt:tt)*) => (proconio::input!(from &mut stdin, $($tt)*)));
```

上記2行を追加すればOKである。あとはいつも通りinput!マクロを使えばよい。
なお、上位陣の解答丸パクリしただけ。

とはいえ簡単に理解しなきゃいけないなーと思いマクロとproconioのドキュメントを少し読んでみた

### proconioに関して
https://docs.rs/proconio/0.4.3/proconio/source/index.html
の中にある
「This is usually no problem in judging (except interactive problem?).」
思いっきり書いてあるー！はてなマークになってるけど完全に確定だからー！

とはいえなんで問題になってるかはよくわからん。
OnceSourceでは EOFが必要と書いてあるがatcoder側ではEOFがないのかもしれない。そんなことある？
なにはともあれLineSourceにしてあげることが必要であるようだ。
ちなみに結論ではマクロを使っているが、下記のようにすればマクロなしでも動く。
後述するが今回のマクロは一々fromとか書かなくていいようにしただけである

```rust
fn main() {
  let mut source = LineSource::new(BufReader::new(io::stdin()));
  input!{
  from &mut source, //ここに追加、&mutを付ける
  n:usize,
}
```

追記
input!の実装について詳しく見ているところがあった・・・が結局よくわからず。うーん
https://blog.ymgyt.io/entry/proconio_input_macro

### マクロに関して
この方の記事がわかりやすかった
https://qiita.com/k5n/items/758111b12740600cc58f#tt

＄が変数名を表すのでttが変数、ttが型である。。。同じでややこしい
ttは難しく自分もあまり理解できていない。上のリンクを読んで感覚をつかんだだけ
input!($tt)が記述されると

```
proconio::input!(from &mut stdin, $($tt)*))
```

を実行するという意味合い。単純にfromを含めていつものinputを実行してねというだけ

###最後に
上位陣はどっからこういう知識を仕入れてくるのだろう
第4回 ネットワーク・モデル

ネットワーク・モデルの必要性
---
現在、インターネットでは、TCP/IPという
プロトコルを使い、世界中を接続できるよ
うになっている。

過去の歴史の中で、もともとTCP/IPという
ルールはなかった。メーカーによる独自の
規格が存在し、異なるメーカーの製品間で
通信できないことが多かった。

ただ、それでは、各社の事業において、「
通信ができない」という理由で、競合に後
手になることもあり、だから統一した規格
が必要。となった。

そこで考え出されたのがネットワーク・モ
デル。他ベンダと相互通信可能にするため
のモデルを指しており、代表的なモデルが
OSI参照モデルである。


OSI参照モデル
---

<table>
<tr>
<th>第7層</th>
<td>アプリケーション層</td>
</tr>
<tr>
<th>第6層</th>
<td>プレゼンテーション層</td>
</tr>
<tr>
<th>第5層</th>
<td>セッション層</td>
</tr>
<tr>
<th>第4層</th>
<td>トランスポート層</td>
</tr>
<tr>
<th>第3層</th>
<td>ネットワーク層</td>
</tr>
<tr>
<th>第7層</th>
<td>アプリケーション層</td>
</tr>
<tr>
<th>第2層</th>
<td>データリンク層</td>
</tr>
<tr>
<th>第1層</th>
<td>物理層</td>
</tr>
</table>

[Table04-02:OSI参照モデル7階層]
仕事でよく使うDockerコマンド

最近、docker環境内でSLAMの環境を構築したので、そのときに使用したdockerコマンドをメモしておく。


# dockerコマンド

## Dockerfileからdockerイメージを作成
```
docker build -t [保存したいイメージ名]:[保存したいタグ名] [Dockerfileがあるディレクトリパス]
```
## dockerイメージをもとに、dokerコンテナを起動する。
  - オプションrmをつけてコンテナ終了時にそのコンテナを自動的に削除する。
  - オプションitをつけて、ターミナル入力を可能にする
  - vオプションと、$(pwd):/homeをつけて、docker環境内の/homeディレクトリ内から、ホスト側（dockerを起動している端末側）の現在いるディレクトリに接続して、ファイルを共有する事が出来る。これをホスト側のファイルをコンテナ側にマウントするという。利用例としては、エッジ開発時など容量の少ない端末上で開発環境を整えたいときなどに、ソースコードをホスト側に置き、docker内にビルドする（docker内に実行ファイルを作る）などの事が出来る。マウントは複数ヶ所にできる。
  - nameオプションでコンテナをイメージとタグに名前をつけることが出来る。
  
```
docker run --rm -it -v $(pwd):/home --name [コンテナ名] [イメージ名]:[タグ名]
```

## 実行中のコンテナを一覧表示
```
docker ps
```
## 過去に実行したコンテナすべてを表示
```
docker ps -a
```
## 保存されているdockerイメージの一覧表示
```
docker images
```
## 実行中のコンテナから一時的に抜ける（コンテナは起動したまま）。
```
Ctrl + p -> Ctrl + q
```
## 上のコマンドで抜けたコンテナ環境に再度入る
```
docker attach [コンテナID or コンテナ名]
```
## コンテナを停止する
```
docker stop [コンテナ名]
```
## コンテナを削除する
```
docker rm [コンテナID]
```
## dockerコンテナの保存
- タグ名にはlatestなどの名前をよく用いている
```
docker commit [起動時に名付けたコンテナ名] [保存したいイメージ名]:[タグ名]
```
## 保存されたか確認
```
docker images
```
## ファイルをホストからコンテナへコピーする
```
docker cp file-path [コンテナID]:path
```
## dockerイメージをtarファイルに出力(testimage.tarファイルに保存してみる）　
    - 他の端末に作り上げたdocker環境を移すときなどに使用する
    - docker環境のバックアップにも使える
```
docker save -o [dockerイメージ名] ~> testimage.tar
```
## tarファイルをdockerイメージに戻す（解凍）
```
docker load <- testimage.tar
```
## dockerプロセスを切る
```
exit
```
## 再度、exitで切ったプロセスを開始
```
docker ps -a -> docker restart [container ID]
```


# 参照
- [saveコマンドとloadコマンド](https://www.memotansu.jp/docker/596/#toc5)
- [cpコマンド](https://noumenon-th.net/programming/2019/03/29/docker-cp/)
- [docker run　公式リファレンス](https://docs.docker.jp/engine/reference/run.html)
- [commitコマンド](https://qiita.com/mats16/items/712575dc50513dfdf0a2)
- [exitコマンドとdetachコマンドの違い](https://tech1313.hatenablog.com/entry/2020/06/16/160844)
Salesforce1導入ダッシュボード

元の質問

[Salesforce1導入ダッシュボード](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000FTTZ2)


ちょと古いアプリです。データが１件も表示されないという質問。とりあえず私もインストールしてみました。
確かに何にも表示されないですね。

では、ダッシュボードの基になるレポートを拝見。

ありゃぁアプリの名前が古いように思います。
Salesforceforに変更(アンドロイドとiOSに対応させるためにこの形を選択します)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/6daf48f3-a53f-41bc-4849-381f8b2d25f6.png)

おお、機能してますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/cfd7be68-4e2b-40cc-39ed-6d8ade2738a7.png)


しかし、ログイン数が間違っているとの回答です。
これ以上は分からん。
UseQuery を複数使う場合

備忘録。

Apollo の useQuery を使う時、複数の data で名前がかぶってしまう問題があります。

```javascript
const {data, loading, error} = useQuery(SOME_QUERY1)
const {data, loading, error} = useQuery(SOME_QUERY2)
```

このような場合は、次のようにコードを書けば、複数の data があっても名前がかぶることはありません。

```javascript
const {data: data1, loading: loading1, error: error1} = useQuery(SOME_QUERY1)
const {data: data2, loading: loading2, error: error2} = useQuery(SOME_QUERY2)

// 呼び出しは、data1, loading1, error1 などでする
```

https://github.com/trojanowski/react-apollo-hooks/issues/120
検証ルールの例外


# 指定された段階で製品ラインアイテムをOppに追加できないことです。[確率]フィールドを更新する必要があるというエラーが表示されますが、ラインアイテムを追加しようとするとこれは不可能です。 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/22ad72dc-f25e-899b-a8fa-f47283f24b8b.png)

確率フィールドが無い。
[Validation rule exception](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000G2eyD)

ISCHANGED( StageName ), を入れてこの画面以外だったらというルールに変更している。思い付かんかった。

回答

```
AND( 
ISCHANGED( StageName ), 
OR( 
ISPICKVAL(StageName, 'Proposed and Quoted'), 
ISPICKVAL(StageName, 'Design Review'), 
ISPICKVAL(StageName, 'Customer Evaluation'), 
ISPICKVAL(StageName, 'Shortlist'), 
ISPICKVAL(StageName, 'Negotiation') 
), 
OR(
$Profile.Name = "Customer Relationship Manager/Network Services", 
$Profile.Name = "New Business Sales", 
$Profile.Name = "Sales", 
$Profile.Name = "Sales Manager"
), 
NOT(ISCHANGED(Probability__c ))
)
```

元の式

```
AND( 
OR( 
ISPICKVAL(StageName, 'Proposed and Quoted'), 
ISPICKVAL(StageName, 'Design Review'), 
ISPICKVAL(StageName, 'Customer Evaluation'), 
ISPICKVAL(StageName, 'Shortlist'), 
ISPICKVAL(StageName, 'Negotiation') 
), 
OR(
$Profile.Name = "Customer Relationship Manager/Network Services", 
$Profile.Name = "New Business Sales", 
$Profile.Name = "Sales", 
$Profile.Name = "Sales Manager"
), 
NOT(ISCHANGED(Probability__c ))
)
```

# 類似の例題

+ [キャンペーンメンバーとリードのインポート時に　カスタムフィールドを使ってバイパスする方法](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000FU7HASA1)

# 別の例題

+ [エラーメッセージの編集](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000G2Usq)
gitを使ったバージョン管理　シンプル版



ブランチを切る（ブランチ新規作成時のみ）
```
git branch f1 master
git checkout f1
```

:::note
ここでは開発ブランチ名を「f1」とする
:::

リモートリポジトリの最新の内容をローカルリポジトリに反映する
（作成済みのブランチで開発する場合のみ）
```
git fetch origin --prune

git checkout master
git merge origin/master

git checkout f1
git merge origin/f1

git merge master
```

※最終行で、マスターブランチの変更内容を開発ブランチに反映している



開発する


ステージング
```
git add .
```

コミット
```
git commit -m "@@@"
```
@@@は任意のコメント


プッシュ(ブランチ作成後初回）
```
git push -u origin f1
```

プッシュ（ブランチ作成後2回目以降)
```
git push origin f1
```

開発完了後、masterブランチへのマージ
```
git checkout master
git merge f1
```

コンフリクト発生時
まずコンフリクトを解消する
その後、ステージング、コミット
``` 
git add .
git commit -m "@@@"
```

ブランチ削除、プッシュ
```
git branch -d f1
git push origin master
git push --delete origin f1
```

その後本番環境にデプロイ
【Sourcetree】GitHubで管理したくないファイルの追跡停止方法

## はじめに
GitHubでポートフォリオを管理しているのですが、毎回パスワードが記述されたapplication.propertiesというファイルがGitの管理下になってしまいスタッシュに入れるという作業をしていたので、便利な方法がないかと探していたところ書籍にあったので忘備録として残しました！

## Gitの学習方法の参考
コマンドラインではなくSourcetreeだと何となくでGitを使えてしまうので、改めてGitについて学習中です。
学習方法としては、下記の記事を参考にしています。
https://qiita.com/kaitaku/items/6cd2c8d4883ff66979d4

https://blog.takanabe.tokyo/2014/12/git%E5%85%A5%E9%96%80git%E5%88%9D%E5%AD%A6%E7%BF%92%E8%80%85%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E5%8A%B9%E7%8E%87%E7%9A%84%E3%81%AA%E5%AD%A6%E7%BF%92%E6%96%B9%E6%B3%95%E3%82%92%E8%80%83%E3%81%88%E3%81%A6%E3%81%BF%E3%81%9F/

## 管理したくないファイルの指定方法

「**.gitignore（ギット・イグノアー）**」というテキストファイルにGitで管理したくないファイルを指定することで管理対象から外すことができる。

### ファイルの書き方
```
▷コメントの書き方
	先頭に「#」をつけることでコメントと識別される
	例）#コメント

#特定のファイルを無視する　例）「memo.txt」を無視する
memo.txt

#特定の拡張子がついたファイルを無視する　例）「.properties」を無視する
.properties

#例外として無視しないファイルを指定する　例）「application.properties」は無視しない
!application.properties
⇒先頭に「！」をつけることで無視しないファイルを設定できる

#特定のディレクトリ以下を無視する　例）testディレクトリ以下を無視する
test/
```

## 「.gitignore」への記述方法
 1.Sourcetreeの画面右上の「設定」アイコンをクリックし、「高度な設定」を開く
 2.「リポジトリ限定無視リスト」にある[編集]ボタンを選択し、[.gitignore]ファイルを開く
3.「.gitignore」ファイルにGitHub上で取り扱いたくないファイルを指定する
4.ファイルを保存し、[高度な設定]の[OK]ボタンを押下する
![55F1C5C1-D659-4476-B895-31962F30DAC5_1_105_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1516225/32c01e92-1da7-77ed-3582-749a07e66c07.jpeg)

## 既にコミットしてしまったファイルを無視する方法
### 1.以下の手順で全てのファイルを表示する
[ワークスペース]内の[ファイルステータス]を開く
　↓
[すべて表示、パス順]のプルダウンを押下
　↓
[すべてのファイル]を選択し、現在管理されているファイルを表示させる
### 2.除外したいファイルを右クリックし、追跡を停止させる（ここでは仮にbuild.gradleファイルとする）
![529037EF-491D-40C3-9A7A-C192F96063EB_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1516225/2da0bbf4-794d-1ae1-52fd-10deab26a500.jpeg)
### 3.追跡をやめた旨をコメント欄に記述し、コミットする
コメントの例としては、「build.gradleの追跡停止」のようにどのファイルの追跡停止をしたかわかるように記述する。
### 4.「.gitignore」に無視したいファイル名を指定する
**「.gitignore」への記述方法**と同じで順でファイル名を指定する
### 5.[.gitignore]ファイルをコミットする

## さいごに
「.gitignore」ファイルに指定するだけで毎回スタッシュに入れる作業がなくなった＋誤ってGitHub上にパスワードの入ったファイルをコミットする可能性もなくなり個人的には大満足です。  
最後までご覧いただきありがとうございましt。

## 参考
わかばちゃんと学ぶGIT使い方入門（C&R研究所　湊川あい著）
Tableau CRM Data Prep Specialist 

[まとめページ](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)


# Step 4

**We can't validate the 'Create Seed Bank Agencies' node was created correctly. Check the required fields, field types, node name, and alias are correct."**

[Tableau CRM Data Prep Specialist - Stuck on Challenge 4 (Create Seed Bank Agencies)](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000G2mUx)

**can't find the 'Load Agency Detail' node in the dataflow**

[Tableau CRM Data Specialist Challenge #4 - can't find the 'Load Agency Detail' node in the dataflow](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000FxW2P)

# Step 8

**We can't find the 'Load Seed Orders' node in the dataflow. Confirm the node name matches the name as described in the challenge.**

[Error in challenge 8 in Tableau CRM Data Preparation Specialist Superbadge](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000H0MVy)



# その他

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/e2b00e61-1c44-ce5e-c0e1-f4e46dd9864e.png)


[私は次のことを完了しようとしています：TableauCRMをパーソナライズする](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000GeOTZ)
第3回 プロトコルと帯域幅

プロトコル
---
通信で使用するルールのことをプロトコルと
いう。プロトコルには何種類かあり、代表的
なものが、「TCP/IP」である。


帯域幅
---
ケーブルの性能や規格を説明するときに使
う用語。本来の意味は、周波数の幅という
意味合い。

現在はデータ転送速度を示す。1秒間に何ビ
ット送ることが可能か、という意味を表す。

参照URL：
http://www5e.biglobe.ne.jp/~aji/3min/03.html
Githubとの接続でremote errorがでる

# 起きたこと

`git fetch`しようとしたら怒られた

```sh
$ git fetch
fatal: remote error: 
  The unauthenticated git protocol on port 9418 is no longer supported.
Please see https://github.blog/2021-09-01-improving-git-protocol-security-github/ for more information.
```

# 原因

[エラーメッセージに書いてあるページ](https://github.blog/2021-09-01-improving-git-protocol-security-github/)に書いてあるとおり、暗号化されていないgitプロトコルが廃止されたため。

リモートURLがgitプロトコルになっていた
```sh
$ git remote -v
origin	git://github.com/hoge-dev/hoge.git (fetch)
origin	git://github.com/hoge-dev/hoge.git (push)
```

2022/03/15より永続的に廃止となったようなので、今回の怒られが発生した模様。

# 対策

Pullしかしていない運用で鍵の登録がめんどくさかったので、プロトコルをhttpsにして対応

```sh
$ git remote set-url origin https://github.com/hoge-dev/hoge.git
```

```sh
$ git remote -v
origin	https://github.com/hoge-dev/hoge.git (fetch)
origin	https://github.com/hoge-dev/hoge.git (push)
```

めでたし、めでたし。

※鍵が登録済みでPushもするならプロトコルはsshでいい

```sh
$ git remote set-url origin git@github.com:hoge-dev/hoge.git
```
MySQLのSELECT文でカラムの指定とWHEREを使った取得条件の指定方法

![career-g308e58de3_1280.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530779/17d8e21d-fbf5-43b6-fc75-175aaf928d79.png)

データベース多少使っていたものの余り意味を理解していなかったほぼド素です。

前回MySQLでデータベース（以下DB）を作成したので今回はSELECT文について[Envader](https://envader.plus/)の環境を用いてデータの操作を学んでいきます。

https://qiita.com/Terralien/items/1fed6a191f6f8a7da15a

## SELECT文について
SELECT文はSQL文のうちDML（Data Manipulation Language）データ操作言語の一つです。

読んで字のごとくですがDBからデータを取得してくる際に使用します。
```sql
SELECT カラム名 FROM テーブル名;
```
:::note warn
SQL文お約束の末尾に`;`（セミコロン）を忘れないようにしましょう。
:::
### 主なDML
* SELECT データ取得
* UPDATE データ更新
* DELETE データ削除
* INSERT データ挿入


### 操作方法１. カラムの指定
`*`（アスタリスク）を使用して指定したテーブル内のすべてのカラムを取ってくる場合。
```sql
SELECT * FROM テーブル名;
```
複数のカラムを取得する場合はカラム名を`,`(カンマ）で区切ります。

```sql
SELECT name, mail, salary FROM テーブル名;
```

### 操作方法２. WHEREを使った取得条件の指定
`WHERE 絞り込み条件`とすることで該当するデータを取得できます。
```sql
SELECT カラム名 FROM テーブル名 WHERE 絞り込み条件;
# 社員テーブルから長宗我部さんを絞り込んでみます
SELECT * FROM employee WHERE name="長宗我部";
```
比較演算子を使って絞り込むことができます。

```sql
SELECT * FROM employee WHERE salary<=300000;
```

| 比較演算子 | 使用用途 |
|:-:|:-:|
| = | ~と等しい |
| < | ~より小さい |
| > | ~より大きい |
| <= | ~以下 |
| >= | ~以上 |
| <>または  != | ~と等しくない |


## 使ってみた
ここまでしっかり理解できているかどうか、[MySQL SELECTの基本①](https://envader.plus/course/2/scenario/1037/ex)の演習問題２を解いてみます。

まずはDBに接続しPasswordを入力します。
`mysql>`が表示されたら`use`コマンドを使用してDBを指定します。
```sql
use food_app
```
>userテーブルに存在するレコードの中でidが5の人のemailアドレスを答えなさい。

とのことなのでカラム名を`email`、テーブル名を`user`、条件を`id=5`とした以下のSELECT文を入力。

```sql
select email from user where id=5;
+----------------------+
| email                |
+----------------------+
| horikawa@example.com |
+----------------------+
1 row in set (0.00 sec)
```

:::note
SELECTやWHEREを小文字で入力することもできます。現場の状況にあった使い方をしましょう。
:::

このように条件に合うメールアドレスを取得できました。
メールをコピペして解答欄に貼り付け提出し、無事正解となりました。

## 学んだこと
とりあえずタイトル通りのことは一通りできました。
単純なコマンドですが何回も繰り返し打たないとド忘れしそうな気がします。

### 次回学ぶこと
SELECT文後半となるLIMITと並べ替えを学びます。

## 参考にした資料
https://udemy.benesse.co.jp/development/system/intro-sql.html

https://www.dbonline.jp/mysql/select/index1.html

https://envader.plus/course

https://pixabay.com/images/id-3449422/