OmniAICreator/Qiita-1.07M huggingface dataset:
【Laravel】イベントとリスナーで設定した通知が2回くる問題の解決法

## 環境
Laravel v9.5.1 (PHP v8.1.3)

## 状況


動作確認で通知を飛ばしたとき、同じ通知が2回飛んでしまっていた。

- ```$listen```の配列に```PodcastProcessed```イベントと```SendPodcastNotification```リスナーを手動で登録
- ```shouldDiscoverEvents()```メソッドをデフォルトの```false```から```true```に変更

```php
namespace App\Providers;

use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;

class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        //デフォルトで登録済みのイベントとリスナー
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
        PodcastProcessed::class => [
            SendPodcastNotification::class,
        ],
    ];

    public function shouldDiscoverEvents()
    {
        return true;
    }
}
```

## 解決法
- 手動で登録する方の```PodcastProcessed```イベントと```SendPodcastNotification```リスナーの記述を削除する。

イベントとリスナーの関連付けを手動と自動の両方で登録してしまっていたことが原因。
```php
namespace App\Providers;

use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;

class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
    ];

    public function shouldDiscoverEvents()
    {
        return true;
    }
}
```

よく見たらドキュメントにちゃんと書いてある。
>EventServiceProviderの$listen配列にイベントとリスナを手作業で登録する代わりに、自動イベント検出を有効にすることもできます。イベント検出が有効になっている場合、LaravelはアプリケーションのListenersディレクトリをスキャンすることでイベントとリスナを自動的に見つけて登録します。（略）
イベント検出はデフォルトで無効になっていますが、アプリケーションのEventServiceProviderのshouldDiscoverEventsメソッドをオーバーライドすることで有効にできます。


## 参考
https://readouble.com/laravel/9.x/ja/events.html
AIが人間の行動を操ることを学習できるようになった

この記事は sciencealert Blog の翻訳です。https://www.sciencealert.com/ai-can-now-learn-to-manipulate-human-behavior
![QQ20221122161435.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2298092/d827d70d-dc58-c657-215e-1558c183e05c.png)
**人工知能**（AI）は、人間とともに（そして人間に対して）どのように働くかについて、より多くのことを学びつつあります。最近の研究では、**AIが人間の習慣や行動の脆弱性を特定し**、**それを利用して人間の意思決定に影響を与える**ことを学習する方法が示されています。

AIが私たちの生活や仕事のあらゆる側面を変えるというと陳腐に思えるかもしれませんが、それは真実です。ワクチン開発、環境管理、事務管理など多様な分野で、さまざまな形態のAIが活躍しています。また、AIは人間のような知性や感情を持ち合わせていませんが、その能力は強力で、急速に発展しています。

まだ機械による乗っ取りを心配する必要はありませんが、この最近の発見はAIの力を浮き彫りにし、**悪用を防ぐための適切なガバナンス**の必要性を強調するものです。


## AIが人間の行動に影響を与えることを学ぶ方法
![QQ20221122161730.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2298092/87e24209-c9f8-5663-1e9d-f802555df93b.png)
オーストラリアの国立科学研究機関**CSIRO**のデータ・デジタル部門である**Data61**の研究チームは、リカレントニューラルネットワークと深層強化学習と呼ばれるAIシステムの一種を用いて、人の選択方法の脆弱性を発見し利用する系統だった方法を考案しました。このモデルを検証するために、人間の参加者がコンピューターとゲームを行う3つの実験を行いました。

- 最初の実験では、参加者が赤か青のカラーボックスをクリックして偽の通貨を獲得するというもので、AIが参加者の選択パターンを学習し、特定の選択肢に誘導する仕組みになっていました。**AIは約7割の確率で成功しました**。

- 2つ目の実験では、参加者に画面を見て、特定の記号（例えばオレンジ色の三角形）を見せたらボタンを押し、別の記号（例えば青色の丸）を見せたらボタンを押さないようにさせました。ここでAIは、参加者がより多くの間違いをするように記号の順序をアレンジすることを試み、約25％の増加を達成しました。

- 3つ目の実験では、参加者が投資家のふりをして受託者（AI）に資金を提供し、AIが参加者に金額を返すというラウンドを何度か繰り返しました。そして、AIは参加者に金額を返し、参加者は次のラウンドで投資する金額を決めます。このゲームは、AIが最終的に獲得する金額を最大化するモードと、AIと人間の投資家の間でお金を公平に分配することを目指すモードの2種類で行われました。**AIはいずれのモードでも大成功**を収めました。

各実験において、機械は参加者の反応から学習し、人々の意思決定における脆弱性を特定し、ターゲットとしました。その結果、機械は参加者を特定の行動に向かわせることを学習したのです。

## 研究から見るAIの未来
![QQ20221122181026.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2298092/ff6abce1-c03f-3026-9723-d3b57fca3b14.png)
これらの発見は、まだ非常に抽象的であり、限定的で非現実的な状況を対象としています。このアプローチをどのように実行に移し、社会に役立てるか、さらなる研究が必要です。

しかし、この研究は、AIに何ができるかということだけでなく、**人がどのように選択を行うかということについても理解を深める**ものです。機械は、私たちとのインタラクションを通じて、人間の意思決定をコントロールすることを学ぶことができるのです。

この研究は、社会福祉を向上させるための行動科学や公共政策の強化から、人々が健康的な食習慣や再生可能エネルギーを採用する方法の理解と影響まで、**非常に幅広い応用が可能**です。AIと機械学習は、特定の状況における人々の脆弱性を認識し、不適切な選択から逃れるよう支援するために使用することができます。

また、この研究は影響力攻撃から身を守るために使うこともできます。例えば、オンライン上で影響を受けているときに警告を発し、脆弱性をごまかすための行動を形成するよう、マシンを教育することができます（例えば、**あるページをクリックしない**、あるいは他のページをクリックして偽の痕跡を残すなど）。

## 次は何？
![QQ20221122161553.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2298092/35898f00-4099-ddff-8bca-aa8281351586.png)
他のテクノロジーと同様、AIは善にも悪にも使われる可能性があり、責任ある方法で実装するためには、適切なガバナンスが重要です。**CSIRO**は昨年、初期段階として、オーストラリア政府向けに「**AI倫理フレームワーク**」を開発しました。

AIや機械学習はデータを大量に必要とするため、効果的なデータガバナンスとアクセスシステムを確実に構築することが非常に重要です。 データ収集の際には、**適切な同意手続きとプライバシー保護**を実施することが不可欠です。

AIを使用・開発する組織は、これらの技術で何ができ、何ができないかを確実に把握し、メリットだけでなく潜在的なリスクも認識する必要があります。

そして最後、AIに興味を持つ方に、AI技術を利用して、テキストだけでアート作品を生成できる[VanceAI描画](https://vanceai.com/ja/image-generator/)という面白いAI製品をおすすめします。
４０代おっさん面会予約アプリを作ってみる③

## 本記事について

この記事はプログラミング初学者の私が学んでいく中でわからない単語や概要を分かりやすくまとめたものです。
もし不正などありましたらコメントにてお知らせいただければ幸いです。

## 前回の記事

<https://qiita.com/kou1121/items/bea7575176b07bd16bb9>
<https://qiita.com/kou1121/items/94ff8d65976dab98dfc8>

## メインファイルの作成

`sql_app`フォルダーなのかに
`main.py`を作る

```python
from typing import List
from fastapi import FastAPI, Depends
from sqlalchemy.orm import Session

from . import crud, models, schemas
from .database import SessionLocal, engine

#  データベースエンジンを元にデータベースを作成
models.Base.metadata.create_all(bind=engine)

app = FastAPI()

def get_db(): # セッションを行う
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

# @app.get("/")
# async def index():
#     return{"message": "Success"}

# Read
@app.get("/users", response_model=List[schemas.User]) # 複数名のユーザーを返すのでListで
async def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    users = crud.get_users(db, skip=skip, limit=limit)
    return users

@app.get("/rooms", response_model=List[schemas.Room]) # 複数名のユーザーを返すのでListで
async def read_rooms(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    rooms = crud.get_rooms(db, skip=skip, limit=limit)
    return rooms

@app.get("/bookings", response_model=List[schemas.Booking]) # 複数名のユーザーを返すのでListで
async def read_bookings(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    bookings = crud.get_bookings(db, skip=skip, limit=limit)
    return bookings

# Create
@app.post("/users", response_model=schemas.User)
async def create_user(user: schemas.User, db: Session = Depends(get_db)):
    return crud.create_user(db=db, user=user)

@app.post("/rooms", response_model=schemas.Room)
async def create_room(room: schemas.Room, db: Session = Depends(get_db)):
    return crud.create_room(db=db, room=room)

@app.post("/bookings", response_model=schemas.Booking)
async def create_booking(booking: schemas.Booking, db: Session = Depends(get_db)):
    return crud.create_booking(db=db, booking=booking)

```

## 参考

https://www.udemy.com/course/python-fastapi
Nuxt3自分用メモ

ついにNuxt3が正式リリースされたとのことで初めて触ってみた結果つまずいた所のメモ

https://nuxt.com/v3

# middleware
- 全体適用するmiddleware
    - ファイル名を `*.global.ts` のようにすることで全体に適用される
        - middleware/auth.ts -> middleware/auth.global.ts
    - globalなmiddlewareを一部ページでは除外したい
        - 設定では無理そうなので以下のようにmiddleware側で除外するコードを書く
           ```middleware/auth.global.ts
            export default defineNuxtRouteMiddleware((to, from) => {
              if (to.path === '/login') {
                return
              }
              // 〜略〜
           ```
- component上で `definePageMeta({ middleware: ['foobar'] })` しても効かない
    - PageComponent(/pages/*.vue)上で読まないと有効にならない

# plugin
- 一部環境でのみ有効にしたいpluginがあるがauto importは無効にしたくない
    - auto importされるのはplugins直下のみなので以下のようにディレクトリを切ることで対応できる
    ```
    ├── plugins
    │   ├── foo.ts      # 直下はauto import
    │   ├── option
    │   │   ├── msw.ts # localでのみmswを有効にしたい
    ```
    ```nuxt.config.ts
    export default defineNuxtConfig({
      plugins:
        process.env.ENV === 'local'
          ? ['@/plugins/option/msw']
          : [],
      // ~略~
    })
    ```

# template
- 動的に画像のURLを設定したい場合、以前は以下のように書いていたがエラーに
    ```vue
    <img :src="require(`~/assets/foo_${bar}.png`)"/ >
    ```
    - viteではrequireが使えないとのことで以下のように
        ```vue
        <template>
        <img :src="getImageUrl(`foo_${bar}.png`)"/ >
        </template>
        <script setup lang="ts">
        function getImageUrl(f: string) {
          // @や~のようなaliasは使えない
          return new URL(`../assets/${f}`, import.meta.url).href
        }
        </script>
        ```
        - 参考: https://vitejs.dev/guide/assets.html#new-url-url-import-meta-url

# バグ?
## 以下のようなコードで `isActive:false` (空文字) となったタイミングでエラー
```ts
useHead({
  bodyAttrs: {
    class: computed(() => {return isActive.value ? 'active': ''})
  },
})
```
エラー内容
```
Uncaught (in promise) DOMException: Failed to execute 'add' on 'DOMTokenList': The token provided must not be empty.
```

適当な文字列を設定することで回避可能
 ```ts
useHead({
  bodyAttrs: {
    class: computed(() => {return isActive.value ? 'active': 'empty'})
   },
 })
```

## `throw createError({ ..., fatal: true })` してもエラーページが表示されない
- showErrorで回避
  - 参考: https://github.com/nuxt/nuxt/issues/15432

# 困ったら
- [Discussions](https://github.com/nuxt/framework/discussions)で語られている事が多いので一読してみるといいかも
イテレータの使用方法まとめ

# 目次
　[1.はじめに](#1-はじめに)
　[2.イテレータとは](#2-イテレータとは)
　[3.イテレータの使用方法](#3-イテレータの使用方法)
　[4.応用編](#4-応用編)

# 1. はじめに
現場での実装時、リスト内の要素除外のためリスト.removeと記述していたのですが、
それだとリストの一番目の要素がなくなり、次の要素に進めなくなるためシスエラーになってしまうという指摘をいただき、イテレータを使用すれば、removeできることを知りました。
（※リストを最後の要素からループすればイテレータを使用せずにremove可能）

今回は復習のため、こちらにまとめていきたいと思います。

# 2. イテレータとは

>イテレータは、集合の要素に順番にアクセスする時に使用するインターフェースです。
集合にはリスト、セット、マップなど複数の種別がありますが、イテレータはそれらにアクセスするための、共通の仕組みを提供します。
イテレータを用いることで、個別の実装を意識せずに、要素へのアクセスを自然に記述できます。

↓上記はこちらの記事から引用させていただきました。

https://magazine.techacademy.jp/magazine/18615
# 3. イテレータの使用方法

```java
package jp.co.study.sample;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Qiita {
	public static void main (String args[]) {
		// 鳥リスト作成
		List<String> birdLsit = new ArrayList<String>();
		birdLsit.add("すずめ");
		birdLsit.add("からす");
		
		// 鳥リストから"からす"を除外
		for (Iterator<String> birdLsitIrt
					= birdLsit.iterator(); birdLsitIrt.hasNext();) {

			String bird = birdLsitIrt.next();
			if (bird.equals("からす")) {
				birdLsitIrt.remove();
			}
		}
		
		// 出力
		System.out.println(birdLsit.toString());
	}
}

```
iterator()メソッド ・・・イテレータ取得
hasNext()メソッド・・・次の要素取得、要素があればtrue、なければfalseを返す
next()メソッド　　・・・次の要素を返す

hasNext()メソッドがtrueを返す間だけ、next()メソッドを呼び出しています。
鳥リスト[すずめ, からす] から「からす」を除外しています。
そのため、出力結果は [すずめ] となります。

# 4. 応用編


```java
package jp.co.study.sample;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Qiita {
	public static void main (String args[]) {
		// なんでもリスト作成
		List<List<String>> whateverLsit = new ArrayList<List<String>>();
		
		// 鳥リスト作成
		List<String> birdLsit = new ArrayList<String>();
		birdLsit.add("すずめ");
		birdLsit.add("からす");
		whateverLsit.add(birdLsit);
		
		// 魚リスト作成
		List<String> fishLsit = new ArrayList<String>();
		fishLsit.add("あじ");
		whateverLsit.add(fishLsit);

		// ① 要素が"あじ"のとき、そのリストから除外
		for (Iterator<List<String>> whateverLsitItr
				= whateverLsit.iterator(); whateverLsitItr.hasNext();) {
			
			List<String> strlist = whateverLsitItr.next();
			for (Iterator<String> strlistItr
					= strlist.iterator(); strlistItr.hasNext();) {
				
				String str = strlistItr.next();
				if (str.equals("あじ")) {
					strlistItr.remove();
				}
			}
			
			// ②で空になってしまったリストを、なんでもリストから除外
			if (strlist.isEmpty()) {
				whateverLsitItr.remove();
			}
		}
		
		// 出力
		System.out.println(whateverLsit.toString());
	}
}
```
なんでもリストには、鳥リスト、魚リストが設定されており、
[[すずめ, からす], [あじ]] のような状態となっています。

①の記載のみだと、出力結果は [[すずめ, からす], []] のようになり、空のリストが入ったままの状態となります。
この空のリストを除外するために②をおこないます。
そのため、出力結果は [[すずめ, からす]] となります。
LaTexにおける人名漢字の表記方法

LaTexにおける人名漢字の表記方法を紹介いたします。
例えば、はしごだか(髙)を表示したい場合は、まず冒頭のパッケージ宣言部分に \usepackage{oft} を追加します。
そして、漢字を表示させたい部分は \CID{8705} と記述してください。
{}内に表示したい文字の CID 番号を入力することで、文字を表示させることができます。
Vue3+Vite+docker-composeでポートが正しいのにアクセスできない

# はじめに

# 問題

Vue3 + Vuetify + TypeScriptの環境を`docker-compose.yml`で起動しました

```yml:docker-compose.yml
version: '3'

services:
  client:
    image: node
    container_name: client
    volumes:
      - ./client:/usr/src
    working_dir: /usr/src
    command: sh -c 'yarn && yarn dev'
    ports:
      - '3000:3000'
 ```

しかし、`localhost:3000`にアクセスしても表示されません

ポートが開いているか確認したら開いていそう

```
CONTAINER ID   IMAGE                         COMMAND                  CREATED          STATUS         PORTS                                       NAMES
eb9d80e2ddcb   node                          "docker-entrypoint.s…"   6 seconds ago    Up 4 seconds   0.0.0.0:3000->3000/tcp, :::3000->3000/tcp   client
```

コンテナの中で`curl localhost:3000`をしたら表示される

```
# curl localhost:3000
<!DOCTYPE html>
<html lang="en">

<head>
  <script type="module" src="/@vite/client"></script>

    <meta charset="UTF-8" />
    <link rel="icon" href="/favi.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Average Poker</title>
</head>

<body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
</body>

</html>
```

なぜ。、、

# 解決方法

起動コマンドを`yarn dev`から`yarn dev --host`に変えたらいけた！

```
version: '3'

services:
  client:
    image: node
    container_name: client
    volumes:
      - ./client:/usr/src
    working_dir: /usr/src
    command: sh -c 'yarn && yarn dev --host'
    ports:
      - '3000:3000'
```

こちらの記事に詳細がありました

https://qiita.com/generonishimura/items/88742085294bd0b234a6

>これはデフォルトのホスト(コンテナ側)は127.0.0.1をリッスンするので、コンテナ内のローカルホストのみが公開されるためです。
起動時に意図せず外部アドレス（ホスト側）に公開することはセキュリティ上の問題になるので、Viteの初期設定ではホスト側からアクセスが出来ないようになっています。

なるほど。Viteを使い慣れていないとここは結構はまりそうな気がしました

# おわりに

今回は地味につまづいたVue環境のコンテナ化についてまとめました
久しぶりにPort周りでつまづいてDockerを疑いましたが、Vite側だったとは

# 参考
https://qiita.com/generonishimura/items/88742085294bd0b234a6
【Microsoft】Power Pagesを1ヶ月使ってみた感想

# PowerPagesとは

- 米Microsoftが10月12日に発表したローコード・ノーコードでビジネス向けWebサイトが作成できるツール。
- テンプレートのカスタマイズなどの簡単な操作で、ビジネス向けのWebサイトが構築できる。
- コストが予測可能でスケーリングできる容積サブスクリプションプラン、ユーザーがWebサイトにアクセスした場合にのみ支払う従量課金制プランの両方がある。

(Power Pages公式リンクは[こちら](https://powerpages.microsoft.com/ja-jp/))

# 1ヶ月使ってみた感想
今回は、会社で利用するための社員の評価ツールを作成するために約1ヶ月ほど使用してみました。実際にツールを作成していく中でいくつか**使いやすい点**と**使いにくい点**が出てきたため、その一部を紹介します。

# 使いやすい点
- ボタンの配置や画面遷移などの設定がしやすい([PowerPagesでの各部品の設定方法について](https://qiita.com/ryoryo66/items/dbd52a63289cb671ad9f))
- 簡単なデータベースは知識が無くてもすぐに作ることが出来る。([PowerPagesでのDBの設定方法](https://qiita.com/ryoryo66/items/e3465a0d7caedec98847))
- テンプレートを用いたサイト制作はすぐに可能。
- 関連するMicrosoftのサービスと連携出来る。

# 使いにくい点

- 複雑なデータベースの管理、作成には向いていない。
    - MicrosoftのDataverseの仕様により独自の仕様があるため、普段からMySQLやOracleに慣れている方は使いづらさを感じる場合がある。([PowerPagesのDBの設定方法](https://qiita.com/ryoryo66/items/e3465a0d7caedec98847))
- 細かなボタンのレイアウトを整える。
    - 細かい調整をする場合は、CSSを編集しないといけないためやや専門的な知識を要する。
- DBや画面の詳細設定を行おうとした際に、別のアプリ(PowerAppsなど)に遷移させられてしまい、設定の全体像が把握しづらい。


# まとめ

総じて、Power Pagesはデータベースや画面レイアウトに関しても細かい作業は現状ではあまり向いてないことがわかりました。これは、どのローコード・ノーコードツールにも言えることなのですが、特にPower PagesはMicrosoftの仕様に依存してしまうため使いづらさが顕著に表れる部分がありました。ただ、プログラミング経験の無いユーザでも静的なサイトであれば1から作り始めることはそれほど難しくないので、今後のアップデートなどでよりこまかい画面レイアウトの設計などが出来るようになることを期待しましょう。
【初心者向け】Mapの考え方・使い方（Salesforce）

# はじめに
Mapの使い方は慣れるまで大変難しく感じると思います。私自身、全くの初心者から始め一番理解に時間がかかったのがMapでした。</p>私のような初心者の方に少しでもわかりやすく素人ならではの目線で解説してみようと思いますので参考までに見ていただければ幸いです。

# Mapの考え方
今回MapをExcelのフィルターに例えて説明していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952245/91e67784-c994-60c7-af2a-2ae230cb1b33.png)

Excel上でフィルターをかけるときに検索ワードを入力すると思います。こちらがMapで言う「key」に当たります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952245/7d258339-0dd7-0d8a-f8f1-76d6c2f490c1.png)


そして条件を入れた結果絞られる情報がMapで言う「value」です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2952245/0949a003-4e49-b5ed-5d85-0b73ef9b1a10.png)

このように考えると「key」に入れる検索ワードの型と返ってきてほしい情報の型を指定してあげればほしい情報が取れるという理由がわかると思います。</p>

MapはSOQLの消費回数を減らしたい場合に便利なのでぜひ使ってみてください。

それでは次は使い方を学んでみましょう。

# Mapの使い方
いざ実践です。ここでは使い方を2パターンに分けて説明していきたいと思います。
### 1. Map< String,sObject> の使い方
以下のように「検索ワード：Id, 検索結果：Account」が返ってくるコードを実装します。
```apex
private static Map<String, Account> returnAccountMap(Set<String> accSet){
    //Mapを初期化
    Map<String,Account> accountMap = new Map<String,Account>();
    //ほしい情報を最初にリストで取得
    List<Account> accList = [SELECT Id, Name FROM Account WHERE Id IN :accSet];
    //Listをループで回し、検索ワードとしたい物を最初、結果として返ってきてほしい情報を2つ目にputする
    for(Account acc : accList){
        accountMap.put(acc.Id, acc);
    }
    return accountMap;
}
```
ここまで書ければほしい情報はaccountMapにまとまりました。
次は格納した情報にアクセスしほしい情報だけを取り出してみましょう。
```apex
private String getAccountValue(){
    //検索ワード
    String accId = '11111';
    //オブジェクトとして返したい場合
    Account acc = accountMap.get(accId);
    //オブジェクトの項目単位で返したい場合
    String accName = accountMap.get(accId).Name;

    return accName;
}
```
上記のように取り出すと自分の欲しい情報をSOQLを消化せず取得することが可能です。

### 2. Map< String, List< sObject >> の使い方
このパターンは検索ワードに対し複数の結果が返ってくることが想定される場合に使用すると便利です。
```apex
private Map<Id,List<Event>> getEventMap(Set<String> accSet){
    //Mapを初期化
    Map<Id,List<Event>> eventMap = new Map<Id,List<Event>>();
    //取得したい行動を一括で取得
    List<Event> eventList = [SELECT Id,Subject,ActivityDate,WhatId
                                FROM Event
                                WHERE WhatId IN :accSet];
    //上記で取得したEventをfor文で回す
    for(Event ev : eventList){
        //関連先はAccountのことを指すため紐づき先が変わったタイミングでAccount毎にまとめたListをMapにputする
        List<Event> accountEventList = eventMap.get(ev.WhatId);
        if(accountEventList == null){
            accountEventList = new List<Event>{ev};
        } else {
            accountEventList.add(ev);
        }
        eventMap.put(ev.whatId, accountEventList);
    }
    return eventMap;
}
```
取得方法はもう一つのパターンと同じになりますが、返ってくる値がListになるのでご注意ください。

# さいごに
ここまで読んでいただきありがとうございます。
Mapといわれるといやだなあと最初は思うかもしれませんが使って慣れてしまえば便利になるものです！
ぜひ使ってみてください！

最後に公式のMapに関する記事を載せるので興味ある方はご覧ください。

https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_methods_system_map.htm
Windowsでファイルの差異があるかのみを取得する方法

# はじめに
差異があるファイルのみ処理をするような仕組みを準備したかったので色々調べたところバッチで構築できそうでした。

# 比較テスト
``` diff.bat
@echo off
setlocal

set SRC_FILE=test1.dat
set DST_FILE=test2.dat

fc /b %SRC_FILE% %DST_FILE%
if %ERRORLEVEL%==0 (
    echo %SRC_FILE% と %DST_FILE% は同じ
) else (
    echo %SRC_FILE% と %DST_FILE% は異なる
)

endlocal
```

## 比較テストの補足
`fcコマンド` を使用し比較を行います。

- 差異がある：`%ERRORLEVEL% が 0`
- 差異がない：`%ERRORLEVEL% が 1`
となります。

こちらで簡単に比較が可能です。

# フォルダの中身を比較
data1とdata2というフォルダの中身を比較して結果を出力してみます。
data1のフォルダをベースに比較を行うためdata2のみに存在するファイルは出力されません。

``` diff_folder.bat
@echo off
setlocal enabledelayedexpansion

set SRC_FILDER=data1
set DST_FILDER=data2
set LOG_FILE=log.txt

set DIFF_LIST=result_diff.txt
set SAME_LIST=result_same.txt
set NO_EXIST_LIST=result_no_exist.txt

del /q %LOG_FILE%
del /q %DIFF_LIST%
del /q %SAME_LIST%
del /q %NO_EXIST_LIST%

for %%f in (%SRC_FILDER%\*.dat) do (
    echo %%f

    rem 対象のファイルが有る
    if exist %DST_FILDER%\%%~nxf (

        rem ファイル比較
        fc /b %%f %DST_FILDER%\%%~nxf>>%LOG_FILE%
        if !ERRORLEVEL!==1 (

            echo %%~nxf>>%DIFF_LIST%
        ) else (

            echo %%~nxf>>%SAME_LIST%
        )
    ) else (

        rem 存在しない
        echo %%~nxf>>%NO_EXIST_LIST%
    )
)

endlocal
```

## フォルダの中身を比較の補足
全３種類のリストを出力しています。
- 差異があるファイル：result_diff.txt
- 同じ内容のファイル：result_same.txt
- data2に存在しないファイル：result_no_exist.txt

ポイントは遅延環境変数(`enabledelayedexpansion`)でERRORLEVELを使っているところです。
for文内で値が変更される変数は遅延環境変数でないと正確な値を取得できないためご注意ください。

# まとめ
今回はリストにまとめるような形にしましたが引数で情報を渡して特定の情報を取得するような汎用的なbatを作成することも可能です。
ファイル差分の有無のみで良い場合はこちらの手法が有効だと思います。
「Pythonで学ぶ音声認識」第3章1節の02prepare_label.pyでUnicodeEncodeErrorになった

[『Pythonで学ぶ音声認識』のGitHubリポジトリ](https://github.com/ry-takashima/python_asr)
#### 環境
windows10 64bit
python3.10

#### やったこと
pythonでyamlファイルを`open()`しようとした。
~~~python:02prepare_label.py
with open(original_label, mode='r') as yamlfile:
~~~

#### エラー内容
~~~
UnicodeDecodeError: 'cp932' codec can't decode byte 0x83 in position 38: illegal multibyte sequence
~~~
windowsのコマンドプロンプトで使用される文字コードがShift-jisであり、ファイルのutf-8と整合性が取れないことが原因。

#### 解決策
`open()`で`encoding="utf-8"`を指定。
他の行の`open()`も同様に指定する。
~~~python:02prepare_label.py
with open(original_label, mode='r', encoding="utf-8") as yamlfile:
~~~


#### 参考
- [【Python】【Django】「UnicodeDecodeError: ‘cp932’ codec can’t decode byte 0x83 in position」と表示される場合の対処方法_100162](https://geekmama.jp/100162)

- [文字コード一覧](https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers)
メモ: ajax (vanilla js)

## GET

```js:index.html
var ajax = new XMLHttpRequest();
ajax.open("GET", "http://hogehoge.com/a.php");
ajax.send();
```

## POST

```html
<script>
	postAjax('https://xxxx/index.php'
	    , 'message=hoge&arg2=fuga'
	    , function(data) {
		     console.log(data);
	    }
	);

        // POST
        function postAjax(url, data, success) {
            var params = typeof data == 'string' ? data : Object.keys(data).map(
                    function(k){ return encodeURIComponent(k) + '=' + encodeURIComponent(data[k]) }
                ).join('&');
            var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
            xhr.open('POST', url);
            xhr.onreadystatechange = function() {
                if (xhr.readyState>3 && xhr.status==200) { success(xhr.responseText); }
            };
            xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            xhr.send(params);
            return xhr;
        }

</script>
```
DDDがわからない～メモは紙で出来ている～

# メモは自分では動かない
メモは、紙で出来ています。なので自分で動くことはできないし考えることもできません。
ただ、書かれていることを伝えることしか出来ません。

# 書かれていないが分かること
メモに書かれた数値の合計などは、メモに実際に書かれていなくてもメモを見れば伝わります。
form_withについて


### ❶form_withとは
♦︎情報を送信するためのヘルパーメソッドの一つ。
♦︎セキュリティー対策などが組み込まれた、安全なHTMLのformタグを作成できる。
♦︎つまりは投稿ページを作るときのフォームを実装するためにある。

```ruby:form_withの基本形
<%= form_with（model or scope or URL [,オプション]） do |f| %>
<% end %>
```
この|f|はブロック変数、つまり特定の範囲内で使える変数のことです。
このdo〜endの範囲でのみ使うことができます。
変数の違いがわからない方はこちら↓
>https://www.sejuku.net/blog/12879

#### form_withのオプション
| オプション |指定 | デフォルト値|
| :-- | --: | --:|
| :model | モデルを指定||
| :scope| スコープを指定|| 
| :url | URL指定 | |
|:local|リモート送信の無効|false|
|:method|HTTPメソッドを指定|POST|

:::note warn
:local
form_withではデフォルトが非同期通信になってる（Rails6.1からは同期通信がデフォルトになってるらしいので自分のバージョンに注意！）ので、引数で"local: true"を渡してあげることで、通常の同期通信を実装することができます。
:::

上記のオプションはよく使用する一例で、使用できるオプションは他にもありますので公式ドキュメントを参照ください。
>https://railsdoc.com/page/form_with


### ❷form_withを使ってみる
先ほどの基本形をベースに「モデルを指定するかorどのURLへデータを送るかorどのHTTPメソッドで送るか」を定義します。
```ruby:(例)①Postモデルと連携した場合
<%= form_with model: Post.new do |f| %>
<% end %>
```
```ruby:(例)②URLを指定する場合
<%= form_with url: posts_path do |f| %>
<% end %>
```
♦︎①のmodelを指定するとデータベースに保存される。②のurl指定は送る情報をデータベースに保存しない
♦︎form_wothのベースができたら、このform_with〜endの範囲にテキストフィールドやボタンを設置していく

:::note info
modelと連携した場合の便利な機能
☑︎form_withはモデルと連携することで、データの保存が簡単にできる
☑︎引数として渡されたモデルクラスのインスタンスの中身の有無で、アクションをcreateかupdateに勝手に振り分けてくれる
:::
勝手に振り分けるってどう言うこと？？となった方は下記記事がとてもわかりやすいので参照ください。
>https://qiita.com/yamaday0u/items/a3689bc48a7eff55929b


##### 〜form_withとモデルオブジェクト〜
:::note info
モデルオブジェクト
タイトルや本文、ボタンを実装するためのヘルパー。
これらの部品を作成するヘルパーをモデルオブジェクトと言います。
:::
モデルオブジェクトの例
| 使用場面 |モデルオブジェクト | 
| :-- | --: | 
| 単一行のテキストフィールド（titleとか） | text_field| 
| 複数行のテキストフィールド (本文とか)| text_area  | 
| 送信や投稿ボタン | submit | 

これらのモデルオブジェクトを作成するために、冒頭で説明したあの|f|ことブロック変数を使用します。
```ruby
<%= form_with model: Post.new do |f| %>
  <%= f.text_field :title %>
<% end %>
```
♦︎ブロック変数の|f|にはモデル（ここで言うならPostモデル）の情報が入っているので、Postモデルにあるtitleカラムと判別することができ、データベースに保存ができる。

### ❸投稿フォームの作成
```ruby:app/views/posts/new.html.erb
<h1>新規投稿</h1>
<!-- 以下form_withの例 -->
<%= form_with model: Post.new do |f| %>
  <h3>タイトル</h3>
  <%= f.text_field :title %>
  <h3>本文</h3>
  <%= f.text_area :body %>	
  <%= f.submit '投稿' %>
<% end %>
```
以上になります。下記も参照させていただきました。
>https://pikawaka.com/rails/form_with
ARC152回答メモ

0.はじめに
　レギュラー久しぶりーと思いつつ始めたところ
　1問目が簡単で、ACをとれました。
　そのあとは、やはり難しく1問正解でフィニッシュでした。

1.A - Seat Occupation
　電車とか乗ったときに1つずつ開けて座っていく
　イメージで考えやすかったです。

　考え方
　　列の先頭の人から、1席ずつ開けて座っていき、
　　最後から1個目の席が埋まった（この埋める人までは2人組が可）後に
　　2人組が来た場合は、2席連続で空いている席が無いためNo判定
　　埋まった後に来る組がお一人様のみの場合はYes判定
　　
　実装時に、分岐条件を無駄に複雑にしたためWAを2回出してしまいましたが
　素直に実装したら、ACとなりました。　　

　https://atcoder.jp/contests/arc152/submissions/36671567
武庫川一文字の青物をデータ分析する 【スクレイピング編】

# この記事について
関西ショアジギングの聖地、武庫川一文字(通称武庫一)における2007年から2022年現在までの釣果をスクレイピングから可視化分析まで行った。結果だけ見たい方はこちら。


# 環境
WSL2 Ubuntu18.04
vsCode

## モジュールインポート
```python
import itertools
import pandas as pd
import chromedriver_binary
from selenium import webdriver
```

## 定数
釣果表と日付選択後表示するボタンは事前にブラウザ上でXpathを確認。
```python
TABLE = "/html/body/center/table/tbody/tr[12]/td"
DISPLAY = "/html/body/center/table/tbody/tr[12]/td/table[2]/tbody/tr[1]/td[2]/button"
ZEN = "／（）０１２３４５６７８９"
HAN = "/()0123456789"
```

## スクレイピング
ポイントは以下の３点。
1\. ページ間移動
月日を選択することで釣果のテーブルが表示されるため、月日の選択と表示ボタンの押下をselenium経由で実行する必要がある。
```python
years = web_driver.find_element(By.NAME, "year")
year_select = Select(years)
year_select.select_by_value(str(year))
months = web_driver.find_element(By.NAME, "month")
month_select = Select(months)
month_select.select_by_value(str(month).zfill(2))
display_button = web_driver.find_element(By.XPATH, DISPLAY)
display_button.click()
```
2\. 釣果なしでもページはある
2007年9月まではページ自体は存在する(選択できる)が釣果はない。また、釣果があった日のみ掲載があるため、read_htmlとして読み込んだ後、日付行を検索して取得する必要がある。
```python
if len(dfs) != 0: #釣果のない年月は取得しない
```

3\. 異なるテーブル行
日付、釣果状況コメント欄が混在するため、釣果テーブル自体の列数が行ごとに異なる。
```python
if (len(df.columns) == 10) and (len(df) > 1): # 釣果行のみ取得、かつ釣果があるか
```

以上を踏まえて
```python
import itertools
import pandas as pd
from selenium import webdriver
import chromedriver_binary
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select

URL = "釣果HPのアドレス"
TABLE = "/html/body/center/table/tbody/tr[12]/td"
DISPLAY = "/html/body/center/table/tbody/tr[12]/td/table[2]/tbody/tr[1]/td[2]/button"

ZEN = "／（）０１２３４５６７８９"
HAN = "/()0123456789"

def to_hankaku(s):
    return s.translate(str.maketrans(ZEN, HAN))

def trim_dow(s):
    return s.split("(")[0]

web_driver = webdriver.Chrome()
web_driver.get(URL)
monthly_dfs = []

for year, month in itertools.product(
        list(range(2007, 2023)), list(range(1, 13))):
    daily_dfs = []
    print(year, "/", month)

    years = web_driver.find_element(By.NAME, "year")
    year_select = Select(years)
    year_select.select_by_value(str(year))
    months = web_driver.find_element(By.NAME, "month")
    month_select = Select(months)
    month_select.select_by_value(str(month).zfill(2))
    display_button = web_driver.find_element(By.XPATH, DISPLAY)
    display_button.click()

    elem_table = web_driver.find_element(By.XPATH, TABLE)
    html = elem_table.get_attribute('innerHTML')

    dfs = pd.read_html(html, header=0)
    if len(dfs) != 0:  # 釣果のない年月は取得しない
        for i, df in enumerate(dfs):
            if (len(df.columns) == 10) and (len(df) > 1):  # 釣果行のみ取得、かつ釣果があるか
                date_str = df[df["Unnamed: 0"] == "日付"].iat[0, 1]
                df["Year"] = year
                df["Month"] = month
                df["Day"] = int(trim_dow(to_hankaku(date_str)).split("/")[-1])
                if len(df) != 0:
                    daily_dfs.append(df)
        if daily_dfs:
            monthly_dfs.append(pd.concat(daily_dfs))
    else:
        web_driver.back()
web_driver.close()
df = pd.concat(monthly_dfs)
df.to_csv("chouka.csv", index=False)
```

続きは
データクレンジング編
データ分析編
ターミナルでBadAppleする

# なにができたのか

<img width="45%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550844/9b7e7b1c-5c7b-2321-4c15-3c5ad1da1cc2.gif">


<img width="45%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550844/e87d3289-64cb-2cb4-4bfb-ea7a4f3cb67f.gif">


こんな感じで、Terminal上で動画をASCIIで再生してます。
今回は、qeesungさんのこちらのリポジトリを使って遊んでいきたいと思います。

https://github.com/qeesung/asciiplayer

# 動作環境
WSLでもできると思いますが、未確認です。
```
# macOS
CPU: Apple M1
OS : Monterey 12.6

# Ubuntu
CPU: Intel i5-11500
OS : Ubuntu 20.04.5
```

# セットアップ
以下、macOSでの方法を紹介します。
僕のREADMEにUbuntuでの方法も書いているので、WSLなどでやってみたい人はそちらをご確認ください！

https://github.com/Yokohide0317/movie4gif

```bash:bash
brew install ffmpeg imagemagick
go install github.com/qeesung/asciiplayer@latest

git clone git@github.com:Yokohide0317/movie4gif.git
cd movie4gif
```

# Gifへの変換

やることを並べているだけの単純なBashスクリプトですが、
指定された.mp4ファイルを`ffmpeg`と`imagemagick`のconvertを使って.gifへ変換しています。
```bash:movie2gif.sh
#!/bin/bash

realpath ()
{
    f=$@;
    if [ -d "$f" ]; then
        base="";
        dir="$f";
    else
        base="/$(basename "$f")";
        dir=$(dirname "$f");
    fi;
    dir=$(cd "$dir" && /bin/pwd);
    echo "$dir$base"
}

INP_MP4=$(realpath $1)
OUT_GIF=$(realpath $2)
TMP_DIR=$(realpath ./movie2gif_tmp)

if [ ${INP_MP4##*.} == "mp4" ]; then
    :
else
    echo "error: .mp4を指定してください。"
    exit 0
fi

if [ -s "$OUT_GIF" ]; then
    echo "error: OUTPUTを指定してください"
    exit 0
else
    :
fi

echo "Convert開始"

mkdir $TMP_DIR
cd $TMP_DIR

ffmpeg -i $INP_MP4 -an -r 10 %04d.png
convert *.png -resize 40% output_%04d.png
convert output_*.png $OUT_GIF

cd ../
rm -r $TMP_DIR
```

```bash:bash
# Example
## .mp4ファイルのファイル名に空白は入れないでください。
./movie2gif.sh badapple.mp4 badapple.gif
```

# 再生！

```bash:bash
asciiplayer play BadApple.gif
```

その他のオプションは、元のリポジトリを確認してください。

https://github.com/qeesung/asciiplayer


# その他
- エミュレーターのKittyはGPUでレンダリングしているそうで、iTerm2よりもカクカクせずに再生できたりします。
（普段はIterm2使っているので、今回はKittyは使用しませんでしたが、、、）
- 文字のサイズや、フォントを変えて遊んでみてください。


# 参考
https://qiita.com/katoy/items/c0d9ff8aff59efa8fcbb

https://github.com/qeesung/asciiplayer

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

https://imagemagick.org/index.php
three.jsでBlenderのカメラを使う

## この記事の概要

Blenderで作ったシーンをglTFに書き出してthree.jsから呼び出した際、そのままではカメラが適用されません。
別途three.js内でカメラを作成しても良いですが、目視で合わせるのも大変なため、Blenderで定義したカメラをそのまま使う方法を記事にしました。

## Blenderからの書き出し設定

まずはじめに、書き出し時の設定が必要です。

`File > Export > glTF 2.0 (.glb/.gltf)`を選択します。
このとき開いたウィンドウの右側にある`Include`を開きます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/1b969624-3b3f-047a-e367-142f68bf6ab1.png)

すると色々な項目が出現します。
今回はカメラのデータを含めたいので`Data > Cameras`にチェックを入れます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/cf9e929e-1e6a-45ff-ab6b-6be1cf316e8f.png)

これで設定は完了です。
あとはウィンドウ右下の`Export glTF 2.0`を押して保存します。

## three.jsでの読み込み

先に完成形のイメージをお見せします。

```javascript
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; // 1

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);

const renderArea = document.getElementById("render");
renderArea.appendChild(renderer.domElement);

const scene = new THREE.Scene();

let camera; // 2
const loader = new GLTFLoader();
loader.load("path/to/file.glb", (gltf) => {
  scene.add(gltf.scene);
  camera = gltf.cameras[0]; // 3
  animate();
});

const animate = () => {
  // code for some kind of animation
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
};
```

上記のコードの説明です。

1. まずは`GLTFLoader`をimport
1. 空の`camera`を作成
1. `gltf.cameras[0]`（Blender内で作成したカメラのうち、1つ目）を、既に定義した`camera`に代入
    1. もちろん複数のカメラがあれば`cameras[1]`や`cameras[2]`で取得可能

three.jsを使うのであれば、ロードしたモデルをアニメーションさせる場合がほとんどだと思います。
その際に`loader.load`の内側だけで`camera`を定義してしまっては、アニメーション用の関数に`camera`が渡せなくなってしまいます。
そのため、グローバルにカメラを用意し、後で書き換えるように実装しました。

## 最後に

改めて整理すると非常に簡単な内容なのですが、リアルタイムでは結構困惑しました。
自分用の備忘録含めて、誰かのお役に立てれば幸いです。

---

最後まで読んでくださってありがとうございます！
Twitterでも情報を発信しているので、良かったらフォローお願いします！

https://twitter.com/xrxoxcxox

Devトークでのお話してくださる方も募集中です！

https://jobs.qiita.com/employers/qiita-inc/dev_talks/489
選手とコーチと監督と解説者

![24440272_s.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23130/4628364f-0337-9016-0eb8-72b2504f0a49.jpeg)

この記事を書いた時に
[CTO目線のこんな企業に転職しては駄目だTOP５ その２ CTOがエンジニア出身でない
](https://qiita.com/k1morikawa@github/items/4f6ae4f94bdfa543b256)
> エンジニアにとっての価値等指標化するのはとても難しいです。プログラミングを沢山やって、色々な開発をやって苦労したり喜びや達成感を感じたりする事で生まれてくる大事な価値観は、指標化出来ないので、プログラミングした事がない人には伝える事が非常に難しいです。出来るのかもしれませんが、僕は諦めてますｗ

エンジニアだって、エンジニア以外にも分かる様に説明する必要があるとの批判？がありました。
確かにそーなんです。説明する事はとっても大事なので反論はありません。
ちょっと話ずれます

# 脳の機能の話
脳ってあんまり動いてないらしいです。ほとんどの動きは反射的に動いています。歩くって事で細かく足の上げ方、どの位の歩幅か、詳しく考えません。
車の運転でギアあげる操作（マニュアル車）は最近乗らないから、自転車。自転車のギアを上げたり下げたりって、色々と考えてません。ペダル漕ぎながら、ハンドル動かしながら、無意識にギアを上げたり下げたりします。
スポーツもそう、ボクサーだったりも細かく動きを色々と考えながらやってません。
これって繰り返し練習する事で無意識に動ける様になってます。

# エンジニアも無意識な事が多い
スポーツと同じで、エンジニアも何度もプログラミングしていく中で成長していき、次第に無意識に最適化されたシステム作りが出来る様になってきます。いちいち深く考えている様では、時間が掛かって仕事が遅いと言われます。
これって繰り返しによって、言語化出来ない事は無いけど、言語化しなくても、最適化が見いだせる様になった状態です。

# せっかくの無意識を意識するのは難しい
繰り返しの修練によって習得した無意識を言語化するのは、時間が掛かるし、面倒なんです。この言語化作業自体は、結構、コツが要ります。CTOにとっては重要なマスト能力です。
しかし、CTOでないエンジニアにとっては、この能力の前に、他に習得すべき能力が沢山あります。なので優先順位として、まだその時ではない。
従って、CTOが居ない会社に就職すると成長速度が阻害され本来のパフォーマンス以外の部分に手間が取られてしまうという事です。

# 選手とコーチと監督と解説者
スポーツ選手と、それを上手に説明できる解説者、選手を育てるコーチ、試合を動かす監督。それぞれ役割が違います。実際に競技をしているスポーツ選手に解説を期待したり、試合マネージメントを期待しても難しいです。
それよりも競技に集中して最大のパフォーマンスを出して欲しいです。
もちろん、言語化するのが好きなエンジニアもいるので、そーいう選手権、解説者の様な方もいますが、その方は特別なんです。
Symfonyのバリデーションで、日本語のエラーメッセージを調整する

Symfonyのバリデーションで、日本語のエラーメッセージを微調整する方法。ちなみにSymfony 5.4。

## やりたいこと

エラーメッセージの日本語が分かりづらいので、微調整したい。
`@Assert\NotBlank()`でエラーが出ると「入力必須項目が入力されていません」、
`@Assert\Email()`は「有効なメールアドレスではありません」、
となっていて、微妙な日本語になっている。

この日本語を変えたい。

## 解決方法

１． Validatorの日本語ファイルを探しだした。場所は：`vendor/symfony/validator/Resources/translations/validators.ja.xlf`
2. このファイルを、ここにコピー：`translations/validators/validators.ja.xlf`
3. 中身の日本語を適宜修正。

これで、変更できた。

適当に試したら動いた、という珍しいパターンだった。
【G検定 2022#3】参考にしたテキスト・問題集

## はじめに
初めて記事をかいております。駆け出しエンジニアのaduと申します。
2022#3のG検定を受験して、無事合格することができました。
その時の記録を残そうと思います。

これから受験する人に向けて、少しでも参考になれば嬉しいです。


## 受験してみての感想
### 試験結果
![スクリーンショット 2022-11-22 15.15.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2738142/74e2c3f8-20b5-d4a3-4ca7-3f206fd46ebd.png)
私の結果を載せておきます。思ったより点数取れたなという印象です。
試験時間は2時間ですが、私はわからなかったらすぐ飛ばして次の問題へを意識しました。
1. 60分で一周目を解く
1. 残りの時間で不安な問題を調べながら解く

そこそこ勉強したおかげもあってか、時間には余裕がありました。
ただここまで余裕ができたのは、いろんな問題集に手を付けたおかげだと思います。

### 勉強時間
勉強は2週間前からはじめました。合計で20-30時間ほどです。
7割とれれば合格なので、人によってはもっと少ない時間人も多いとは思います。
### 事前知識
私は学生時代に少しだけ機械学習の勉強をしていたこともあって、機械学習の概要などの知識はありました。
ディープラーニングの具体的な手法などは全くわかりませんでした。

## 勉強に用いたテキストや教材
☆の数は個人的に参考になった度合いを表しています。
#1. G検定（ジェネラリスト）公式テキスト 第2版

https://www.amazon.co.jp/%E6%B7%B1%E5%B1%A4%E5%AD%A6%E7%BF%92%E6%95%99%E7%A7%91%E6%9B%B8-%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0-G%E6%A4%9C%E5%AE%9A-%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%A9%E3%83%AA%E3%82%B9%E3%83%88-%E5%85%AC%E5%BC%8F%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88/dp/4798165948/ref=tmm_pap_swatch_0?_encoding=UTF8&qid=1669098454&sr=8-1

おすすめ度: ★★★★☆
まずはこれを一読しました。
AIや機械学習、ディープラーニングについて概要を学ぶことができます。
章末問題集も付いてるので、知識チェックもできます。
皆さん書かれてますが、このテキストだけではG検定に合格するのは難しいと思います。

### 最短突破 ディープラーニングG検定(ジェネラリスト) 問題集
https://www.amazon.co.jp/%E6%9C%80%E7%9F%AD%E7%AA%81%E7%A0%B4-%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0G%E6%A4%9C%E5%AE%9A-%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%A9%E3%83%AA%E3%82%B9%E3%83%88-%E5%95%8F%E9%A1%8C%E9%9B%86-%E5%85%89%E5%A4%AA%E9%83%8E/dp/429711609X/ref=d_bmx_dp_m52vgrbn_sccl_2_1/357-1381754-0092712?pd_rd_w=4ZkAT&content-id=amzn1.sym.ab8d9779-a886-4d62-8fd9-62c562e352cc&pf_rd_p=ab8d9779-a886-4d62-8fd9-62c562e352cc&pf_rd_r=XJW8E2APDQ0C9TW6H6H1&pd_rd_wg=39OMh&pd_rd_r=a4acd1d8-f566-4f4f-9ab8-1702f068fe14&pd_rd_i=429711609X&psc=1

おすすめ度: ★★★☆☆
問題集です。これもサラッと2週くらい解きました。
ただこのテキストと上の公式テキストを合わせても、まだ足りないかなと思います。
これが全部できるようになっても6割とれるか怪しいレベルです。

### Study-AI G検定模擬テストβ版
https://study-ai.com/generalist/

おすすめ度: ★★★★★
無料登録することで、300問分の模擬テストを受けることができます。
上2つのテキストをこなしたあとで、実際に解いてみました。
全然解けない...半分くらいしか解けなくて焦った記憶があります。
私はこれを3週くらいやりました。わからない問題や知らない単語などをここで一つずつ潰していきました。

### zero to one G検定用語集
https://zero2one.jp/ai-word/

おすすめ度: ★★★★★
G検定用語集です。シラバスに記載の単語はここで網羅されています。
この用語集の素晴らしいところは、各単語に図で説明がされているところです。
公式テキストを読みながら、出てきた単語について図で簡単なイメージを掴むのが一番いいと思います。
もっと早く出会いたかったです。


## 以下のテキストは有料 (Kindle Unlimittedなら無料)
Kindle Unlimittedに登録していたので、問題集を追加で解きました。
こちらは有料（一冊500円）なので、お金をかけたくない方は飛ばしてください。

### G検定 ～厳選問題集～ Kindle版
https://www.amazon.co.jp/gp/product/B08BWP52Q2/ref=dbs_a_def_rwt_hsch_vapi_tkin_p1_i0

おすすめ度: ★★★★☆
一問一答の問題集となっており、問題と解説でページが分かれているのがとても良いです。
計算問題以外2週解きました。2週目は特に気になる問題のみです。

### G検定 ～最短合格指南書～ Kindle版
https://www.amazon.co.jp/gp/product/B07ZN2G8C1/ref=dbs_a_def_rwt_hsch_vapi_tkin_p1_i1

おすすめ度: ★★★☆☆
上の厳選問題集と同じ著者による、参考書になります。
私は基本的にわからない単語の辞書代わりとして用いていました。

## 最後に
私が今回受験する際に、「G検定は簡単だ」と書かれている記事をよく見かけました。
対策が十分でないと、しっかり落ちる試験だと私は思います。そんなに甘くはないと思います。
受験される方の一助となれば幸いです。
Love Solarized Dark

私は **Solarized Dark** のカラーパレットが大好きです。

※ Solarized テーマがどんなものか、については下記の記事がよく知られ分かりやすいですね。

https://www.wired.com/story/very-mathematical-history-perfect-color-combination/

今回は、私が自らの環境を Solarized Dark に染めるべく行った全ステップをメモします。

### 0. ダークモード
Mac 本体の外観モードを「ダーク」に変更します。
多くの場合、アプリケーションはシステム環境設定の外観モードにより Solarized Dark / Solarized Light テーマを切り分けます。今回は Solarized Dark テーマを適用するため、本体の外観モードを「ダーク」としておきます。

`システム環境設定... > 一般 > 外観モード` より「ダーク」を選択すれば okay です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/12da9dc5-6e2e-6f24-f5fe-ce9c15978b5b.png)

### 1. デスクトップ
本体のデスクトップカラーを Solarized Dark のメインカラーに変更します。

`システム環境設定... > デスクトップとスクリーンセーバ > デスクトップ` より「カスタムカラー...」を選択します。そして、「16進数カラー値」として `#073642` を入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/aa2bfdf3-9bb4-b65b-5d4a-49a7721a1550.png)

### 2. ブラウザ
（Chrome 前提ですが）*Solarized Dark Refresh Theme* をインストールします。

https://chrome.google.com/webstore/detail/solarized-dark-refresh-th/jinmjipikfdhmacpjdddmpffflhehcah

### 3. ターミナル
*altercation/solarized* をクローンします。

```terminal
git clone https://github.com/altercation/solarized.git
```

ターミナルの `環境設定... > プロファイル` より、先ほどクローンしたプロジェクトから「Solarized Dark ansi.terminal」をテーマとして読み込みます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/9437107a-a09b-952a-306d-5899dd7f5326.png)

`環境設定... > プロファイル > ターミナルの宣言方法` は「ansi」とします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/3c644883-c5a3-bf06-c161-092f5fcf048e.png)

### 4. エディタ・IDE
- Vim

Vim にも同じプロジェクトの Solarized Dark テーマを反映するため下記コマンドを叩きます。

```terminal
mkdir -p ~/.vim/colors
cp solarized/vim-colors-solarized/color/solarized.vim ~/.vim/colors
```

加えて、`.vimrc` に追記をしましょう。

```.vimrc
syntax enable
set background=dark
colorscheme solarized
```

- IntelliJ IDEA
*Solarized Themes* プラグインを導入しています。頻繁に更新もされているので採用しています。

https://plugins.jetbrains.com/plugin/12784-solarized-themes

- VSCode
*Solarized* プラグインを導入しています。頻繁に更新もされているので採用しています。

https://marketplace.visualstudio.com/items?itemName=ryanolsonx.solarized

### 5. Slack
`環境設定... > テーマ > カラー` のカラーコードテキストエリアに下記をペーストします。

https://gist.github.com/MxShun/33813e908af7f6bc44902d084df8c1c4
AWS CLI を使用して RDS の「保留中のメンテナンス」をまとめて適用する方法

# 準備
あらかじめ AWS CLI に SSO でログインしておきます。
https://qiita.com/gorooe/items/5e20e261693417f723b3

# 対象 RDS のリストアップ
保留中のメンテナンスがある RDS の arn を AWS CLI でリストアップします。
```terminal
aws rds describe-pending-maintenance-actions \
    --profile amimoto-ap-northeast-1 \
    | jq -r '.PendingMaintenanceActions[].ResourceIdentifier'
```

# コマンドでメンテナンスを適用
RDS の arn を指定し、以下を実行します。
RDS の台数分だけ arn とリージョンを変更し実行します。
```
aws rds apply-pending-maintenance-action \
    --resource-identifier RDS-arn \
    --apply-action system-update \
    --opt-in-type next-maintenance \
    --profile RDS-region
```
`--opt-in-type`オプションに`next-maintenance`を設定していますが、こうすることで次のメンテナンスウィンドウで適用してくれます。
`immediate`を設定するとコマンド実行と共にアップデートが即適用されます。

:::note warn
`immediate`で即適用の場合、再起動がかかる場合があるので注意しましょう。
:::

シェルスクリプトを作成すればまとめて実行できます。
生粋のWindowsユーザがMac使い始めて最初にやった１３のこと

### トラックパッド
Windows に近い操作性にするため、２つの設定を変更しました。

① `システム環境設定... > トラックパッド > ポイントとクリック` より「副ボタンのクリック」を有効化する //右クリックを2本指クリックで代替する
② `システム環境設定... > トラックパッド > ポイントとクリック` より「タップでクリック」を有効化する //左クリックを1本指クリックで代替する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/8c924b05-299c-8295-f950-6f6d5ecdfaa6.png)

### キーボード
Windows キーボードに近づけるため、2つの設定を変更しました。

③ `システム環境設定... > キーボード` より「F1、F2などのキーを標準のファンクションキーとして使用」を有効化します //ファンクションキーによる変換等を利用するためです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/bdb44f2c-7245-f0fc-71f6-439b20771e53.png)

④ [Google 日本語入力](https://www.google.co.jp/ime/) をインストールします

### Finder
Windows のファイラーに近い操作性にするため、4つ設定を変更します。

⑤ `Finder > 表示` より「パスバーを表示」を有効化する //パス構造を表示する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/3a888f63-3039-3c20-2504-c91c01500514.png)

⑥ `Finder > 環境設定... > 詳細` より「すべてのファイル名拡張子を表示」を有効化する //拡張子を常時表示する
⑦ `Finder > 環境設定... > 詳細` より「名前順で表示しているウィンドウ」を有効化する //ファイルとフォルダを分けて表示する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/fa121595-e0cd-280c-23ac-97a9961c4e49.png)

⑧ ターミナルより下記コマンドを実行する //隠しファイルを常時表示する

```terminal
defaults write com.apple.finder AppleShowAllFiles TRUE
```

### Dock
ここからは好みによる設定の変更が多いです。

⑨ `システム環境設定... > Dockとメニューバー` より「Dockを自動的に表示/非表示」を有効化 //ただの好みですね

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/03464d49-ed6e-819f-5259-85bc75ec2320.png)

### メニューバー
⑩ `システム環境設定... > Dockとメニューバー > バッテリー` より「割合（％）を表示」を有効化します //これもただの好みですね

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/a5680c87-e3fc-e13d-b232-420c89faf0e8.png)

### Alfred
検索やアプリケーション起動を最速化します。

⑪ [Alfred](https://www.alfredapp.com/) をインストールします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/c58da8d3-8e68-643e-26f4-d6ae4e6e0758.png)

⑫ `システム環境設定... > Spotlight > プライバシー` より HD を追加しディスク全体の Spotlight 検索を無効化します //これかなりバッテリーを消耗するので

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/8288a2cf-05cf-d616-bdb7-5bcd4e14b4b4.png)

### Scroll Reverser
トラックパッドとマウスのスクロール方向を Windows に合わせます。
⑬ [Scroll Reverser](https://pilotmoon.com/scrollreverser/) をインストールします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488859/9edf3b10-d678-b6f6-4407-37c67eb466d9.png)
【Blender】名前で一括選択しマテリアルを設定する

# 0. 概要
Blenderで、オブジェクト名で一括選択して、マテリアルを一括で設定したい時にどうぞ。
自分のための備忘録です。

環境
- macOS Ventura 13.0.1
- Blender 3.0.1 

# 1. やり方
## ① 一つのオブジェクトにマテリアルを設定する
![スクリーンショット 2022-11-22 15.54.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2702367/1855426e-1a51-cd9b-71c7-97ffbd52b148.png)

## ② 名前で一括選択する
例の場合、`Carbon*`という名前のオブジェクトが対象です。
![スクリーンショット 2022-11-22 15.55.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2702367/746cea44-6618-afa2-1792-24343c14a5f9.png)
![スクリーンショット 2022-11-22 15.55.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2702367/7e8a38e4-d012-98ce-7b9e-df155ec76ce8.png)
![スクリーンショット 2022-11-22 15.55.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2702367/16498313-ec2b-5f07-992a-f1a6970dd987.png)

## ③ マテリアルをリンク（Command+L）
この時、最初にマテリアルを設定したオブジェクトがアクティブになっていることに注意します。
![スクリーンショット 2022-11-22 15.56.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2702367/c6b6960e-462a-bf2a-ef31-852c01e81c8b.png)

## ④ 完成!
![スクリーンショット 2022-11-22 15.56.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2702367/09c710ee-c469-4168-5be9-bd5ef372a3fb.png)


# 2. 参考
1. https://bookyakuno.com/multi-object-assign-of-materials/
1. https://blog.goo.ne.jp/m4g/e/cc1d733728073e9228162dc1a6da31e6
ビルドとコンパイルについて動作確認

# コンパイルとは
プログラム言語で書かれたソースコードをコンピュータが理解できる「機械語」に翻訳すること。
翻訳するプログラムのことをコンパイラと呼ぶ。
変換のみを行う。生成したオブジェクトコードの実行は行わない。実行可能なファイルに変換すること。

# ビルドとは
全てのファイルのソースコードのコンパイルやライブラリのリンクなどを行い、最終的な実行可能ファイルを作成すること。
コンパイル+使っているライブラリに関連づけ（リンク）をする。

言葉で言っても堅苦しいので作業で覚えた方が早いかも。![スクリーンショット 2022-11-22 15.04.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958170/0b304570-0e35-8750-546c-6deaa21ced94.png)

Unityより
Fille > Build Settings…　> Scenes In BuildへScenesを入れる　> Add Open Scenesクリック　> Build And Run
これでビルドは終了です。
Seleniumで座標を0,0に移す方法

PythonでSeleniumのActionchainsのmove_by_offsetを使って画面の左上からの座標を指定してクリックしようとする際に、2回目以降だと現在の座標からの位置になってしまいうまくいきませんでした。
また、move_to_elementも要素の中央への移動しかできず苦戦していました。
今回その解決策を見つけたので共有します。

```sample.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains

html = driver.find_element(By.XPATH,'/html')
ActionChains(driver).move_to_element(html).move_by_offset(-html.size['width']/2,-html.size['height']/2).perform()
 
```

以上です。
PowerApps小ネタ（天気）

# PowerAppsメモ
小ネタです
## 天気情報
■コネクタ
MSN天気をデータソースに追加
MicrosoftTranslatorをデータソースに追加（翻訳用）

■基本的な書き方
```
MSN天気.CurrentWeather(緯度 & " " & 経度,"Metric").responses.weather.current.cap
```
緯度経度の指定の仕方は("35.697180" "139.814072") ←　googleMapで取得出来る緯度経度

## コンボボックスで天気を切り替える
１．Shareaポイントに場所情報を登録
![test1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38727/b8097f55-a6d5-340d-76f7-dd25886e3ce3.png)
２．コンボボックスに場所を表示
![test2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38727/e19454d8-9dcd-8a3f-697d-981ab2e33042.png)
３．天気情報を取得して表示
![test3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38727/c62e2f62-39a1-d2fa-e009-64735536e6c5.png)
各項目の表示方法
``` powerapps
---更新
MSN天気.CurrentWeather(drop_tenpo.SelectedText.緯度 & " " & drop_tenpo.SelectedText.経度,"Metric").responses.weather.current.created
---現在の天気
MicrosoftTranslator.Translate(MSN天気.CurrentWeather(drop_tenpo.SelectedText.緯度 & " " & drop_tenpo.SelectedText.経度,"Metric").responses.weather.current.cap,"ja")
---現在の気温
MSN天気.CurrentWeather(drop_tenpo.SelectedText.緯度 & " " & drop_tenpo.SelectedText.経度,"Metric").responses.weather.current.temp & "℃"
---現在の湿度
MSN天気.CurrentWeather(drop_tenpo.SelectedText.緯度 & " " & drop_tenpo.SelectedText.経度,"Metric").responses.weather.current.rh & "%"
MySQLを再起動する

# 動機
ある時にデータベース（スキーマ）の中の一つのテーブルに問い合わせができなくった。
いろいろなサイトを見ても困っていた。

# MySQLを再起動する
```
mysql.server restart
```
```
**********@mbp ****** % mysql.server restart
Shutting down MySQL
.... SUCCESS!
Starting MySQL
. SUCCESS!
```

### 出典
https://qiita.com/yanbou893/items/a46b37f002df8529c99c

# 結果
無事に問い合わせることに成功！

# 感想
この記事を書いていただいたことに感謝！！
ありがとうございます。
また作ることができます。
Livebook に散布図と回帰直線を表示する

## はじめに

Livebook でデータ分析したい！

データの傾向を見るために散布図が見たい！

ついでに回帰直線も見たい！

という人向けの記事です

## 動作環境

以下のリポジトリーのコンテナ上で Livebook を動かしています

https://github.com/RyoWakabayashi/elixir-learning

## セットアップ

Livebook でグラフを扱うため、 Kino.VegaLite をインストールします

```elixir
Mix.install([
  {:kino_vega_lite, "~> 0.1"}
])
```

https://hexdocs.pm/kino/0.4.1/Kino.VegaLite.html

エイリアスをつけます

```elixir
alias VegaLite, as: Vl
```

## データの準備

可視化したいデータを用意します

本記事では、以下のようなデータを使います

```elixir
x = [1, 2, 3, 4, 5, 6, 7]
y = [0.9, 1.8, 3.3, 3.7, 4.5, 6.1, 7.2]
```

## 散布図の表示

`x` と `y` の散布図は以下の様にして表示します

```elixir
# グラフのサイズを指定
Vl.new(width: 300, height: 300)
# データを x と y から取得する
|> Vl.data_from_values(x: x, y: y)
# x は連続する数値データで 0 から 8 の範囲を表示する
|> Vl.encode_field(:x, "x",
  type: :quantitative,
  scale: [domain: [0, 8]]
)
# y は連続する数値データで 0 から 8 の範囲を表示する
|> Vl.encode_field(:y, "y",
  type: :quantitative,
  scale: [domain: [0, 8]]
)
# 散布図を表示する
|> Vl.mark(:point)
```

![スクリーンショット 2022-11-22 15.21.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/4d6f6465-f6af-0883-c187-405e13393339.png)

## 回帰直線の表示

x と y の線グラフは以下のようにして表示します

```elixir
# グラフのサイズを指定
Vl.new(width: 300, height: 300)
# データを x と y から取得する
|> Vl.data_from_values(x: x, y: y)
# x は連続する数値データで 0 から 8 の範囲を表示する
|> Vl.encode_field(:x, "x",
  type: :quantitative,
  scale: [domain: [0, 8]]
)
# y は連続する数値データで 0 から 8 の範囲を表示する
|> Vl.encode_field(:y, "y",
  type: :quantitative,
  scale: [domain: [0, 8]]
)
# 線グラフを表示する
|> Vl.mark(:line)
```

![スクリーンショット 2022-11-22 15.25.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/e75cab49-53e9-4df1-d955-b5a697d486a7.png)

最後に `Vl.transform(regression: "x", on: "y")` を追加することで回帰直線になります

```elixir
# グラフのサイズを指定
Vl.new(width: 300, height: 300)
# データを x と y から取得する
|> Vl.data_from_values(x: x, y: y)
# x は連続する数値データで 0 から 8 の範囲を表示する
|> Vl.encode_field(:x, "x",
  type: :quantitative,
  scale: [domain: [0, 8]]
)
# y は連続する数値データで 0 から 8 の範囲を表示する
|> Vl.encode_field(:y, "y",
  type: :quantitative,
  scale: [domain: [0, 8]]
)
# 線グラフを表示する
|> Vl.mark(:line)
# 回帰直線に変換する
|> Vl.transform(regression: "x", on: "y")
```

![スクリーンショット 2022-11-22 15.25.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/7d643f37-d38e-e078-a3ac-d91918431c5d.png)

## 散布図と回帰直線を重ねて表示する

複数のグラフを　レイヤーとして重ねて表示することが可能です

共通部分はレイヤーの外、個別部分をレイヤーの中で定義します

```elixir
# グラフのサイズを指定
Vl.new(width: 300, height: 300)
# データを x と y から取得する
|> Vl.data_from_values(x: x, y: y)
# x は連続する数値データで 0 から 8 の範囲を表示する
|> Vl.encode_field(:x, "x",
  type: :quantitative,
  scale: [domain: [0, 8]]
)
# y は連続する数値データで 0 から 8 の範囲を表示する
|> Vl.encode_field(:y, "y",
  type: :quantitative,
  scale: [domain: [0, 8]]
)
|> Vl.layers([
  # 散布図を表示する
  Vl.new()
  |> Vl.mark(:point),
  Vl.new()
  # 線グラフを表示する
  |> Vl.mark(:line)
  # 回帰直線に変換する
  |> Vl.transform(regression: "x", on: "y")
])
```

![スクリーンショット 2022-11-22 15.29.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/334c6312-2eaa-bb03-63f0-490f95de1847.png)

## まとめ

VegaLite は便利でキレイですね