OmniAICreator/Qiita-1.07M huggingface dataset:
embed-reactでReactに地図を埋め込む

# :books:　embed-reactとは
株式会社Geoloniaが提供する`GeoloniaMaps`をReactアプリに埋め込むためのライブラリです。

**リポジトリ：** https://github.com/geolonia/embed-react/tree/main


# :pen_ballpoint:　let's coding！
### ◼︎ 準備
reactアプリを作成。
```shell
npx create-react-app my-app
```
embed-reactをインストールします。
```shell
npm install --save @geolonia/embed-react
```
### ◼︎ 地図を表示する
API Keyの取得方法は、こちらの[**チュートリアル**](https://docs.geolonia.com/tutorial/)を確認！
```jsx:App.js
import './App.css';
import { GeoloniaMap } from '@geolonia/embed-react';

function App() {
  return (
    <div className="App">
      <GeoloniaMap 
          apiKey={api-key}
          style={{height: "400px", width: "100%"}}
          lat={127.96911949041572}
          lng={26.588972870618022}
          zoom="8"
      />
    </div>
  );
}

export default App;
```


### ◼︎ マーカーを複数表示する
```jsx:App.js
import './App.css';
import { GeoloniaMap } from '@geolonia/embed-react';
import React from "react";


function App() {

  // markerの位置データ
  const data = [
    {
        lat: 26.1913942,
        lon: 127.8004151
    },
    {
        lat: 26.3351306,
        lon: 127.7993454
    },
    {
        lat: 24.3310297,
        lon: 123.9088860
    },
  ];

  const mapRef = React.useRef(null);

  // コールバック関数
  const handler = React.useCallback(() => {
    const map = mapRef.current;
    // データ分markerオブジェクトを生成
    for(let i = 0; i < data.length; i++) {
        const marker = new geolonia.Marker({color: '#F9BF3D'})
                        .setLngLat([data[i].lon, data[i].lat])
                        .addTo(map);
    }
  }, [])


  return (
    <div className="App">
      <GeoloniaMap 
          apiKey={api-key}
          style={{height: "400px", width: "100%"}}
          lat={127.96911949041572}
          lng={26.588972870618022}
          zoom="8"
          marker="off"       // これ追加
          mapRef={mapRef}    // これ追加
          onLoad={handler}   // これ追加
      />
    </div>
  );

}

export default App;
```
地図読み込み後、onLoadに設定したコールバック関数が実行されるので、その中でmarkerオブジェクトを生成し、mapに紐付けます。
https://github.com/geolonia/embed-react/blob/main/src/GeoloniaMap/GeoloniaMap.tsx#L61

### ◼︎ マーカーにイベントをつける
maplibreのmarkerには、drugイベントはあるけどclickイベントがなく、どうやってmarkerがクリックされた時に処理を実行しようか悩みましたが、普通にaddEventListenerでいけました。。
```javascript
// 省略
// コールバック関数
const handler = React.useCallback(() => {
    const map = mapRef.current;
    // データ分markerオブジェクトを生成
    for(let i = 0; i < data.length; i++) {
        const marker = new geolonia.Marker({color: '#F9BF3D'})
                        .setLngLat([data[i].lon, data[i].lat])
                        .addTo(map);
        // ↓ これで
        marker.getElement().addEventListener('click', () => {
            alert("click!!")
        }, false);
    }
}, [])
```



### 参考
- https://maplibre.org/maplibre-gl-js-docs/api/markers/#marker.event:dragstart
PHPStromでテスト実行時に「the input device is not a TTY」が出る

PHPStromでユニットテスト実行すると「the input device is not a TTY」なる表示が出るようになった…

![スクリーンショット 2023-06-29 9.46.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961919/75b72bbd-1b27-d9f6-fbb1-734a438e3d12.png)


PhpStormの設定画面を開き PHP > CLIインタプリタの[...] > 環境変数 と遷移して
環境変数欄に COMPOSE_INTERACTIVE_NO_CLI=true を記載すると解決しました。
![スクリーンショット 2023-06-30 9.06.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961919/9488980f-b610-95b1-cec7-26ab6900a66f.png)
M5Stack Toughと土壌水分量センサーでプランター菜園をモニタリングするVol.2（土壌センサー取り付け編）

前回のブログで電源構成を記載したので、今回はセンサーの取り扱いについて書いていこうと思います。

[M5Stack Toughと土壌水分量センサーでプランター菜園をモニタリングするVol.1（電源編）](https://qiita.com/EuzoBass/items/fb4a8f379c2425ad942b)

## I2C用ケーブル＆ケーブル長選定
今回利用した土壌水分量センサーはこちらです。
- [CATNIP ELECTRONICS - 強化型 I2C 土壌水分センサ](https://jp.robotshop.com/products/rugged-i2c-soil-moisture-sensor)

![i2c-soil-moisture-sensor.png](https://jp.robotshop.com/cdn/shop/products/rugged-i2c-soil-moisture-sensor-5_2_600x.jpg?v=1681765745)
※RobotShip様サイトから

同じメーカーで値段の安い「I2C土壌水分センサー」というものがあります。上の強化型はこのセンサーに予め結線と熱収縮チューブによる回路の保護がなされているという違いがあります。はんだ付けの手間や熱収縮チューブの取り扱いなどが面倒だと感じられる方は強化型を使うのも手かもしれません。

https://jp.robotshop.com/products/i2c-soil-moisture-sensor

I2CはM5Stack や Raspberry Piなどでセンサを扱う場合よく使われるインターフェース規格です。基本的に、基盤内での通信を想定しており、長距離の伝送には適していないようです。バッファ回路など追加することで延長することもできるようですが、M5Stack Tough内には組み込む隙間が無かったので、バッファなしでチャレンジしました。
https://community-ja.renesas.com/cafe_rene/forums-groups/the_vault/f/forum19/3619/i2c

I2Cの詳細についてはここでは割愛しますが、稼働させるためには下記の4本の線が必要になります。
https://ja.wikipedia.org/wiki/I2C

| 名称 | 用途 | M5Stack Toughでのポート位置 |
| ----- | ----- | ----- |
| Vcc | 電源。+3.3V | PORT A - VCC |
| GND | グランド | PORT A - GND |
| SCL | クロック | PORT A - 33 |
| SDL | データ | PORT A - 32 |

センサーについているケーブルの被覆を剥くと、4色のケーブルが見えてきます。
ケーブルグランドを予めM5Stack Toughに取り付けておき、センサーのケーブルを通して、予め切っておいたGroveケーブルと1本ずつつなぎ合わせます。ケーブルグランドを通す前にケーブルをつなぎ合わせてしまうと、ケーブルグランドの穴をGrove端子が通れないため注意してください。

https://www.switch-science.com/products/797

![IMG_3577.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534832/e6f998b5-6402-a94a-6357-00f859b1bca7.jpeg)

絶縁テープで保護する前に、センサーを認識してくれるかチェックします。この時、M5Burnerに用意されている **Tough_Tools** を使うことでI2Cなどの導通チェックを行ってくれます。手順はファームウェアのアップデートと同様にPCとM5Stack ToughをUSBで接続しておき、M5Burnerで **Tough_Tools** をダウンロードしてM5Stack Toughにインストールして起動します。

![toughtool.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534832/ae1b56e2-31cb-bfdf-d499-24894a56b624.png)

ツールが起動すると**I2C**を選択し、センサーのI2Cのアドレスである0x20の文字が黒文字で表示されていることを確認します。ケーブルが長い場合、この文字がグレーアウトと黒文字を繰り返して不安定になるので、その場合はケーブルを短くするなどして対処します。全く反応しない場合、センサー側かM5Stack側の不具合も考えられるので、交換するなどして切り分けてください。

私の場合は黒とグレーで不安定でしたが、ケーブル長を20センチほどにすると安定したため、その長さで使用することにしました。

作業が終わったらM5Stack 自体のファームウェアも忘れずアップグレードしておきます。

## 次回
次回は、水分量を取得したり、モニタリングするための画面表示やIoTの設定を行います。
ソフトウェアアーキテクチャの基礎を読んでみて3

### モジュールのとは

一般的ににモジュールとはより複雑な構造を構築するために使用できる標準化された部品、または独立した単位の各集合

本社では
関連するコードを論理的にグループ化することをモジュール


### 定義

モジュールをモノリシックのようにするのではなく、部品ごとにプラットフォームに
分けるほうが再構築ができ、変更や修正がスムーズに行うことが出来る。


モノリシックとは
システムなどの構造について、要素に分割されておらず、全体が一体になっていること


#### 3-2 モジュール性の計測

##### 凝集度

本書では
凝集度とはモジュールの要素がどの程度、そのモジュールに収まっているかの度合いを指す。言い換えれば、凝集度とはモジュール内の要素同士の関連度を表す。

自分で翻訳
一つのモジュール内のコンポーネントがお互いに関連している程度

###### 凝集度の尺度は次のように定義している

##### ・機能的凝集度
関連する要素だけでモジュールが構成され、モジュールが機能するために必要なものがすべて含まれている。

##### ・逐次的凝集
一方が出力したデータをもう片方が入力する形で２つのモジュールが相互に作用している

##### ・通信的凝集
２つのモジュールが通信の連鎖を形成し、お互いの情報を操作したり、なにかしらの出力に貢献したりする。たとえば、データベールにレコードを追加し、電子メールを生成する。

##### ・手続き的凝集
２つのモジュールは特定の順番でコードを実行する必要がある。

##### ・時間的凝集
モジュール間に時間的な依存関係がある。たとえば、多くのシステムには起動時に初期化しなければならない。一見、無関係な処理群が存在している。これらの異なる処理には時間的な凝集があるといえる。

##### ・論理的凝集
モジュール内のデータは論理的に関連しているものの、機能的には全く関連していないといえる。（フォーマットやデータの型が全く違う)
例えば、テキストやシリアライズされたオブジェクト、またはストリームを情報へと変換するモジュールだと、これらの場合、操作上では関連があるものの、機能は全く違う。

##### ・偶発的凝集
モジュール内の要素は同じソース内にある以外には関連性がない。これは最も悪い形になる


７段階も尺度があるにもかかわらず、凝集度は結合度よりも精度が低いメトリクスです。（CPU使用率、メモリ使用率、ディスク使用率、Date //o ,アクセス数、などの情報を取得して測定値をグループ化したもの）

モジュールはLOCMのスコアが低く、凝集度が高いとよいモジュール構造といえる


###### LOCMとは（メゾッドの凝集度の欠如）とはモジュールの構造的な凝集度を計測するメトリクスのこと。LOCMのスコアが低いとモジュール内のメゾットがお互い密接に関連していなくモジュール全体が統一感があり、再利用性が高く、テストしやすい。一般的にLOCMスコアが低いと良い。ただLOCMではクラス同士の関係性は見れない。


###### モジュールの凝集度が低いと責任が分かれている。つながりが複雑で目的が違う部品が同じモジュールに存在する部品同士の関係が強くなったり、再利用性が難しくテストも難しいなのでモジュール凝集度が低いと役割の分散やつながりの複雑化、再利用、テストの難しさの問題が生じる可能性があるので凝集度が高い設計を心掛けたほうがいい。

ソフトウェアアーキテクチャの第二のほうそくとはモジュール（クラス）間の結びつきをできるだけ弱くするということ。

##### ・求心性結合
コードアーティファクト（コンポーネント、クラス、関数など）に外部から入力される接続数を計測する

##### ・遠心性結合
他のコードアーティファクトに出力する接続数を計測する

###### ・コナーセンス
求心性と遠心性の結合メトリクスを解消しそれをオブジェクト指向向けに再構築したもの
静的と動的、2種類のコナーセンスを定義した。


上をわかりやすくまとめると

求心性と遠心性はプログラムの設計において各部分がどれだけ依存しているか独立しているか示す尺度のこと

###### コナーセンスとは
システムやプログラムを作る際にお互い関連しあっていることを意識することで全体として正しく機能するシステムをお作るための考え方のこと。


次回コナーセンスについての学習を掲載します！
【学習】Ruby on Rails チュートリアル 第7版 - 第11章 アカウントの有効化

6/30 8:30 開始
・アカウントの有効化
→新規登録時、本当にそのメールアドレスの持ち主なのかどうかを確認する。

(1）有効化トークンやダイジェストを関連付けておいた状態で、
（2）有効化トークンを含めたリンクをユーザーにメールで送信し、
（3）ユーザーがそのリンクをクリックすると有効化できるようにする

11.1.1まで終了

6/30 9:00　終了

7/4 8:20 開始

*メソッド参照
(例)createアクション実行前に、create_activation_digestというメソッドを探索して、実行する。
今回のケースでは、create_activation_digestメソッドはUserモデル内でしか使わないので
privateキーワードを指定する。

    before_create :create_activation_digest

11.1まで終了

7/4 8:45 終了

7/5 8:10 開始

・メーラーの生成
モデルやコントローラと同様にrails generateで生成できる。

    rails generate mailer UserMailer account_activation password_reset

上記の例では、account_activationメソッドと、password_resetメソッドが生成される。
生成したメーラーごとに、ビューのテンプレート↓が2つずつ生成される。
(HTMLメール用のテンプレート、テキストメール用のテンプレート)


11.2.1まで終了

7/5 8:40終了

7/6 8:10 開始

*メールプレビュー
メッセージをその場でプレビューする機能

config/environments/development.rb

    .
    .
    .
    config.action_mailer.raise_delivery_errors = false
    host = 'example.com'
    config.action_mailer.default_url_options = { host: host, protocol: 'https' }
    .
    .
    .


※'example.com'は、
クラウドIDEでは、ブラウザで見えるURLを設定する。
hostにはhttps://プレフィックスを含めては"いけない"

さらに、プレビューファイルの更新が必要
test/mailers/previews/user_mailer_preview.rb

    ・
    ・
    ・
    # Preview this email at
     # http://localhost:3000/rails/mailers/user_mailer/account_activation
     def account_activation
       user = User.first
       user.activation_token = User.new_token
       UserMailer.account_activation(user)
     end
    ・
    ・
    ・

コメントアウトで明示されている指定のURLでアカウント有効化メールをプレビューできるようになる。
クラウドIDEを使っている場合は、localhost:3000の部分を対応するベースURLに置き換える。


11.2まで終了

7/6 8:36 終了

7/9 18:00 開始

7/9 20:00 終了
【Next.js】router.pushとrouter.replaceを理解する

:::note info
この記事はpagesディレクトリのケースで書いています！
:::

# はじめに
Next.jsの`router.push`と`router.replace`は、アプリケーションのルーティングを行うためのメソッドですが、**ブラウザの履歴にどのように影響を与えるか**で違いがあるようです。
所属しているチームのプルリクを見ていて理解が曖昧であることに気づいたので、学習のアウトプットとしてまとめます。

# router.push
https://nextjs.org/docs/pages/api-reference/functions/use-router#routerpush

```
router.push(url, as, options)
```

- url：String - 移動先の URL
- as：String - ブラウザのURLバーに表示されるパスのデコレータ
- options：
  - scroll：boolean - ナビゲーションの後、ページのトップにスクロールすることを制御。（デフォルトはtrueなので、ページの最上部に移動する。）
  - shallow：getStaticProps, getServerSideProps, getInitialPropsを再実行せずに現在のページのパスを更新。（デフォルトはfalseなので、getServerSidePropsは再実行される。）
- locale：String - 新しいページのロケールを示す


#### ユーザーをログインページへリダイレクトする
```
import { useEffect } from 'react'
import { useRouter } from 'next/router'
 
// Here you would fetch and return the user
const useUser = () => ({ user: null, loading: false })
 
export default function Page() {
  const { user, loading } = useUser()
  const router = useRouter()
 
  useEffect(() => {
    if (!(user || loading)) {
      router.push('/login')
    }
  }, [user, loading])
 
  return <p>Redirecting...</p>
}
```

#### URLオブジェクト
next/linkと同じようにURLオブジェクトを使うことができ、パラメータは`url`と`as`どちらも動作する。

```
import { useRouter } from 'next/router'
 
export default function ReadMore({ post }) {
  const router = useRouter()
 
  return (
    <button
      type="button"
      onClick={() => {
        router.push({
          pathname: '/post/[pid]',
          query: { pid: post.id },
        })
      }}
    >
      Click here to read more
    </button>
  )
}
```

### router.pushの特徴
**新たに指定したパスをブラウザの履歴に追加する。**
（router.pushを使用してページを変更した後、ユーザーがブラウザの「戻る」ボタンを押すと、元のページに戻る）

### router.pushの使用例
- リストから詳細ページへの遷移
例えば、ある記事リストのページからユーザーが特定の記事をクリックし、その記事の詳細ページに遷移するといったケース。この場合、ユーザーはブラウザの「戻る」ボタンを使って記事リストに戻ることができる。

- ユーザー認証後のリダイレクト
ユーザーがログインした後、特定のページ（例えばユーザープロフィールページ）にリダイレクトする場合。ユーザーがブラウザの「戻る」ボタンをクリックすると、ログインページに戻ることができる。

- 検索結果の表示
ユーザーが検索クエリを入力し、その結果を表示する新しいページに移動する場合。ユーザーは、必要に応じて「戻る」ボタンで検索フォームに戻ることができる。

# router.replace
https://nextjs.org/docs/pages/api-reference/functions/use-router#routerreplace
```
router.replace(url, as, options)
```
```
import { useRouter } from 'next/router'
 
export default function Page() {
  const router = useRouter()
 
  return (
    <button type="button" onClick={() => router.replace('/home')}>
      Click me
    </button>
  )
}
```

### router.replaceの特徴
**現在のページを履歴スタックから新しいページに置き換え、ブラウザの履歴に追加しない。**
（「戻る」ボタンを押しても、router.replaceで置き換えた以前のページには戻らない挙動）

### router.replaceの使用例

- リストのフィルタリングやソート
商品リストページでユーザーがフィルタリングやソートを行うようなケース。ユーザーが「戻る」ボタンを押したときに、フィルタリングやソート前の商品リストに戻るのは直感的ではないため、ブラウザの履歴には影響を与えないようにする。

- ページ内のタブ切り替え
あるページ内で複数のタブ間を切り替える場合、URLにタブの状態を反映させつつ、ブラウザの履歴には追加したくない場合。

- ページネーション
一覧ページなどでページネーションを行う際、ページ番号をURLのクエリパラメータとして設定することで、ユーザーが直接URLを変更して移動できるようにするもの。各ページ間の遷移で「戻る」ボタンを押したときにページネーションの前の状態に戻るのは直感的でないため。

# メモ
appディレクトリでは[こちら](https://nextjs.org/docs/app/api-reference/functions/use-router)を使うらしい

`pages`から`app`への移行は以下のとおり↓

https://nextjs.org/docs/pages/building-your-application/upgrading/app-router-migration#step-5-migrating-routing-hooks
Docker を基本からまとめてみた【ストレージ】

## コンテナレイヤー
- 読み込みも書き込みもできる
- コンテナ上での変更が保存される → コンテナレイヤーはコンテナが削除されると消える

## イメージレイヤー
読み込みのみ

## ボリューム領域
- Dockerが管理しつつ、独立した領域になっていて、複数のコンテナから接続する事が可能
- 各コンテナから接続することでファイルの読み書きをすることができる

## Dockerの基本操作のコマンド

```
//新しいボリューム領域を作成する
docker volume create [ボリューム名]

//ボリューム領域一覧を表示する
docker volume ls

//指定したボリューム領域の詳細情報を表示する
docker volume inspect [ボリューム名]

//指定したボリューム領域を削除する
docker volume rm [ボリューム名]

//ボリュームに接続しながらコンテナを起動する
※ -vと-mountは書き方の違いのみでどちらも同じ
docker container run -v [ボリューム名]:[コンテナ内絶対パス][イメージ]

docker container run -mount type=volume src=[ボリューム名],dst=[コンテナ内絶対パス][イメージ]

//バインドマウントしながらコンテナを起動する
※ -vと-mountは書き方の違いのみでどちらも同じ
docker container run -v [ホスト絶対パス]:[コンテナ内絶対パス][イメージ]

docker container run -mount type=bind,src=[ホスト絶対パス],dst=[コンテナ内絶対パス][イメージ]
```



## 参考サイト
[初心者OK！Docker入門＋応用：ゼロからでも実務で使えるスキルが身に付ける](https://itplusjp.udemy.com/course/ok-docker/learn/lecture/36661954#overview)
手動でのデプロイ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/ac81107a-b652-1b96-49da-571c59591e91.png)
1:手動でのデプロイまでの流れ
①git commitとpush
　VSCodeで「database.yml」の本番環境の設定を編集する。本番環境のデータベースに関する設定はproduction:以降で変更できます。
　本番環境のmysqlの設定に合わせるため、database.ymlを以下のように編集する。

config/database.yml
production:
　<<: *default
　adapter: mysql2
　database: （アプリ名）_production　
　username: root
　password: <%= ENV['DATABASE_PASSWORD'] %>
　socket: /var/lib/mysql/mysql.sock
※databaseは、例：アプリ名がaaaa_123456の場合、aaaa_123456_productionのようになります。
次に、編集を「commit→push」しましょう。
リモートリポジトリが更新されたため、サーバ上のアプリケーションにも反映させる。

②GitHubの内容をEC2に反映させる。
１：sshへ接続する。
cd .ssh/　→ssh -i キーペア名.pem ec2-user@Elastic IPアドレス
→EC２へのログインパス

ターミナル（EC2内で実行）
[ec2-user@ip-172-31-23-189 ~]$ cd /var/www/[リポジトリ]
→EC2環境内のアプリへ移動する。
[ec2-user@ip-172-31-23-189 <リポジトリ名>] git pull origin main

2:EC2内でデータベースを作成するのですが、「RAILS_ENV=production」というオプションがつきます。
「RAILS_ENV=production」とは、本番環境でコマンド実行する時につくオプションです。
実行しようとしているコマンドは、「RAILSのENV（環境）がproduction（本番環境）」という意味です。

ターミナル（EC2内で実行）
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ rails db:create RAILS_ENV=production
Created database '<データベース名>'
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ rails db:migrate RAILS_ENV=production
→ もしここで「Mysql2::Error: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock'」というエラーが起こった場合、データベースが起動していない可能性があります。「sudo systemctl start mariadb」というコマンドをターミナルから打ち込み、mysqlの起動を試してみる。

③Railsを起動
ターミナル（EC2内で実行)
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ bundle exec unicorn_rails -c config/unicorn.rb -E production -D

④アセットコンパイル（ rails assets:precompile RAILS_ENV=production）
⑤Unicorn再起動
→①ターミナル（EC2内で実行）：[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ ps aux | grep unicornを実行し、現在動いているプロセスを確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/f8b345ac-bba8-6a25-7cbe-91b53d2c13d2.png)
大事なのは左から2番目の列です。ここに表示されるのがプロセスのidになります。
「unicorn_rails master」と表示されているプロセスがUnicornのプロセス本体です。この時のプロセスidは「17877」となっています。
　
②ターミナル（EC2内で実行）
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ kill <確認したunicorn rails mainのプロセスid>

③ターミナル（EC2内で実行）：実行したプロセスを再度表示させ、終了できていることを確認する。
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ ps aux | grep unicorn
⇩　下記のようになっていれば、終了できている。
ec2-user 17918  0.0  0.2 110532  2180 pts/0    S+   02:05   0:00 grep --color=auto unicorn

④ターミナル（EC2内で実行）
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -D
※「RAILS_SERVE_STATIC_FILES=1」は、Railsがコンパイルされたアセットを見つけられるように指定する役割がある。

⑤Railsを起動できているかブラウザで確認する。
→方法：ブラウザでhttp://ご自身のElastic IPを入力:3000/にアクセスして、サイトが正常に表示されているか確認する。

この一連の流れをすれば、デプロイが完了されます。

「エラーでうまく表示されていない時のチェックリスト」
・ローカル→GiuHubへのpushのし忘れはないか（mergeまで確認）
・GitHubからEC2への反映（git pull origin master）のし忘れはないか
・EC2サーバー側でエラーログの内容を確認し、原因を見つけたか
・カリキュラム通りの記載ができているか
・データベースは正しく起動しているか
・EC2サーバー側の環境変数は正しく設定できているか
・EC2インスタンスの再起動を行ってみる
AWS EC2 第3回 vsftpdでIPv4とIPv6を共存

# はじめに
AWS EC2上にvsftpdをインストールして、IPv4とIPv6を共存する方法をまとめます。
FTPはアクティブモードではすんなり動作しますが、パッシブモードでは少し工夫が必要でしたので、それをまとめておきます。

# 今回実施する内容
AWS EC2上にvsftpdをインストールして、IPv4とIPv6を共存する設定をおこないます。
- アクティブモードによるIPv4とIPv6の共存
- パッシブモードによるIPv4とIPv6の共存

# ソースコード(Git Hub)
なし

# 環境
OS: Windows 11 JP (64bit)
EC2 AMI： Amazon Linux 2 AMI (HVM) - Kernel 5.10, SSD Volume Type (Amazon Linux 2 Kernel 5.10 AMI 2.0.20230628.0 x86_64 HVM gp2)

# 参考
なし

# 用語
なし

# 前提
すでにIPv4とIPv6が通信できる状態のEC2 Instanceが存在すること。

# vsftpdのインストールと起動
vsftpdのインストールは、コンソールから以下でインストールします。
```
sudo yum install vsftpd -y
```
それから起動については、以下で開始しつつ、EC2開始時にも起動するように設定します。
```
# vsftpdの起動
sudo systemctl start vsftpd
# EC2起動時にvsftpdを起動する設定
sudo systemctl enable vsftpd
```

# アクティブモードでの動作
FTPをアクティブモードで使用する場合、上記の「vsftpdのインストールと起動」だけでIPv4でもIPv6でも動作します。
このとき、現状の`vsftpd.conf`のデフォルト設定で、listenについては以下の通りになっています。
```/etc/vsftpd/vsftpd.conf
listen=NO
listen_IPv6=Yes
```

`vsftpd.conf`の説明では、以下の記載があり、この設定はIPv6のみの設定であり、IPv4とIPv6をlistenするためには、vsftpdを2つ起動する必要があるように読めますが、このままで動作します。
```/etc/vsftpd/vsftpd.conf
# This directive enables listening on IPv6 sockets. To listen on IPv4 and IPv6
# sockets, you must run two copies of vsftpd with two configuration files.
# Make sure, that one of the listen options is commented !!
```

# パッシブモードでの動作
## vsftpdのパッシブモードの設定（失敗するパターン）
FTPをパッシブモードで使用する場合、`vsftpd.conf`上でパッシブモードを有効にする必要がありますので、以下を追加します。
```/etc/vsftpd/vsftpd.conf
pasv_enable=YES
pasv_address=xxx.xxx.xxx.xxx   #IPv4アドレス
pasv_min_port=yyyy             #パッシブモードで使用する最小のポート番号
pasv_max_port=zzzz             #パッシブモードで使用する最大のポート番号
```
`pasv_min_port`、`pasv_max_port`は記載は任意です。

この状態で、**Ipv4でパッシブモードでFTPするとサーバーからIPアドレスが返されず0.0.0.0となり、IPv4は接続できません。**
**IPv6は動作します。pasv_addressは特にIPv6に変更する必要はありません。**
上記では動作しないことはわかったため、xinetdを使用してFTP接続ごとにvsftpdを起動するようにします。

## vsftpdの起動停止とvsftpd.conf修正
xinetdからvsftpdを起動するように変更するため、vsftpdを停止します。
```
# vsftpdの停止
sudo systemctl stop vsftpd
# EC2起動時にvsftpdを起動する設定
sudo systemctl disable vsftpd
```
続いて`vsftpd.conf`のlisten、listen_IPv6をNOに変更します。
```/etc/vsftpd/vsftpd.conf
listen=NO
listen_IPv6=NO
```

## xinetdのインストール
xinetdのインストールは、コンソールから以下でインストールします。
```
sudo yum install xinetd -y
```
それから起動については、以下で開始しつつ、EC2開始時にも起動するように設定します。
```
# xinetdの起動
sudo systemctl start xinetd
# EC2起動時にxinetdを起動する設定
sudo systemctl enable xinetd
```

## xinetdのvsftpd起動設定
以下のコマンドでvsftpdファイルを作成し、中身を記載します。
```
sudo vi /etc/xinetd.d/vsftpd
```

```/etc/xinetd.d/vsftpd
service ftp
{
    socket      = stream
    wait        = no
    user        = root
    server      = /usr/sbin/vsftpd
    server_args = /etc/vsftpd/vsftpd.conf
    nice        = 10
    disable     = no
    flags       = IPv4
}

{
    socket      = stream
    wait        = no
    user        = root
    server      = /usr/sbin/vsftpd
    server_args = /etc/vsftpd/vsftpd.conf
    nice        = 10
    disable     = no
    flags       = IPv6
}
```

上記で終わりです。
これで、IPv4からパッシブモードでFTPしても、IPv6でパッシブモードでFTPしても動作します。また、アクティブモードでも動作します。

# 注意
今回はAmazon Linux 2を使用して実施しましたが、Amazon Linux 2023だとxinetdが削除されているようなので方法を見直さないといけないなと思いました。

# おわりに
vsftpdでパッシブモードでIPv4とIPv6を共存する方法を紹介しました。
ネット検索すると色々でては来るのですが、がっつりマッチするようなのは見当たらなかったため、まとめてみました。
データサイエンティスト検定リテラシーレベルを受ける

# はじめに
[ITパスポート](https://qiita.com/talomina/items/c3c20ef5fa36e9400ea2)の次はデータサイエンティスト検定リテラシーレベル（以下 DS検定）に挑戦です。Di-Liteという全てのビジネスパーソンが身に着けるべきリテラシーとしてITパスポート、G検定とDS検定が3つセットで定義されています。

> 「Di-Lite 」とは、「デジタルを使う人材」であるために、全てのビジネスパーソンが、共通して身につけるべきデジタルリテラシー範囲です。

https://www.dilite.jp/

# DS検定とは

https://www.datascientist.or.jp/dscertification/what/


> アシスタント・データサイエンティスト（見習いレベル：★）と数理・データサイエンス教育強化拠点コンソーシアムが公開している数理・データサイエンス・AI（リテラシーレベル）におけるモデルカリキュラムを総合し、実務能力と知識を有することを証明する試験です。

仕事で多少なりともデータを扱ったりするので、基礎知識として知っておいたほうが良さそうなことを体系的に勉強したいと考えてセレクトしました。今回は試験の申込期日が迫っていたので、とりあえず申し込んでから勉強を始めるスタイルです。見習いレベルと高を括って取り組み始めましたが、後々泣きを見る羽目になります。

# 試験勉強

いつも頼りにしているUdemyでコースを探しても見つけられなかったので、今回は本を買って勉強しました。

### 最短突破　データサイエンティスト検定（リテラシーレベル）公式リファレンスブック

定番の本を電子版を買ってキンドルで読みましたが、スマホですき間時間に少しずつ読むことができたり、iPad等で数式や図を拡大してじっくり眺めることが出来るので良かったです。

https://amzn.asia/d/aLiPr81

ただ、模擬問題をやりながら、解説を読んだりするのには電子版はやや不便だったので、紙の本でもよかったかなと思いました。

### 勉強のやり方

[DS検定で問われる範囲](https://www.datascientist.or.jp/dscertification/what/#scope)は広大ですがデータサイエンス、データエンジニアリングおよびビジネスの３カテゴリで大きく分類されます。それぞれのカテゴリの中で細かく具体的に「〇〇ができること」が定義されているので、一つずつしらみつぶしに理解し（たつもりになっ）ていく正攻法で攻めることにしました。1か月くらいかけて全体を読み終わりました。良かったこととしては[ITパスポート](https://qiita.com/talomina/items/c3c20ef5fa36e9400ea2)を終えたばかりだったのでデータエンジニアリングやビジネスのところは内容が重複する部分も多く、かなりスピードアップできた気がします。

試験前のラスト3日間くらいで模擬問題をやり始めましたが、結構なハードスケジュールになりました。次に何か受けるなら模擬試験は早めに、と心に刻みます。

### 内容の難しさ（学習のし難さ）

本の前半のデータサイエンスから読み始めたのですが、学生時代に数学で習ったような微分や行列、確率の話が出てきて心折れそうになりました。まさかリテラシーレベルで方程式の微分を求められるとは！です。高校時代の授業風景がフラッシュバックして、エモーショナルをエネルギーに換えてなんとか乗り切ることが出来ました。

もう一つ悩まされたのは知らない言葉がたくさん出てくるところでした。ROC曲線やMAPE、ホールドアウト法などIT業界の末席で過ごしても普段は聞くことのない単語が大量に出てくるので、この点でも心折れそうになりました。こちらは本当に試験の直前、2日前くらいから脳に詰め込む作業を行いました。ちゃんと理解していったほうが良いとは思いますが、結果的に忘却曲線が下がり始める前に試験を乗り切る作戦です。

ITパスポートに比べると、求められる知識を理解するのに時間がかかることが多くて、試験の日程が迫ってくるのに参考書が進まないという事態になりました。最後の1週間はかなりハードに詰め込みましたが、理解しきれない部分や覚えきれないところも多々残りました。

# 試験の流れ

https://cbt-s.com/examinee/examination/datascientist.html

## 申し込み
Webから普通に日程と場所を選んで申し込みができ、クレジットで支払いもできます。本当に便利な世の中になったと思います。困ったのはITパスポートやAWSよりも受験できる場所や日程が少ないことです。CBT業界の覇権争いでもあるのでしょうか。とにかく、申し込みはお早めに。

## 試験当日

![DSC_0699.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940466/d1436004-8b0b-0ab8-8e9f-8a5707e06eca.jpeg)

身分証明書だけ持って試験会場に行けば受験できます。渋谷の会場はGoogleのオフィスが近所にあります。20分ほど早めに着いたところ「もうダウンロードされているから」といわれすぐに受験させてもらえました。身分証明書以外をロッカーにしまうと計算用のA4用紙とボールペンを渡され、端末の前に座り、試験を受けます。計算問題は少ないですが、電卓ボタンを押すとパソコン上で電卓が利用できるので、頑張ってひっ算をしたりする必要が無いのが良かったです。90分で80問の試験ですが考え込むような問題はないので、時間が短すぎるというようなことはありませんでした。

全部終わったらすぐに正解率が集計されて表示され、自分でプリントボタンを押して受付に戻りました。正解率の集計表を紙でもらって試験終了です。

## 合格証書
試験が終わるとその場で正解率がでるのです、合否判定が出るのは約1か月後です。翌月にウェブサイトから合格証書とオープンバッジがダウンロードできるようです。

### 2023年7月30日追記 オープンバッジ授与のお知らせ
あれから1か月「オープンバッジ授与のお知らせ」のメールを受信して、14日以内の受領を促されたので忘れないうちに登録しました。


https://www.openbadge-global.com/ns/portal/openbadge/public/assertions/unAcquired/NFFEaDR6ei9BY2VzazVqTU5xTFdFUT09

データサイエンティスト協会のウェブサイトでも合格証書をPDFでダウンロードすることが出来るようになっていました。

# おわりに
「リテラシー」という言葉はもともと「読み書きする能力」ということだそうで、前提となる知識のような意味合いで使われる言葉です。しかし勉強を始めてみると内容が思ったよりも難しくて泣きを見ました。データサイエンティストという専門家が身に着けておくべきリテラシーはこんなにレベルが高いのかと、感じた次第。範囲が広いので100点を取る必要はないのかもしれませんが、見習いとはいえ8割くらいはとらないと入門させてもらえない狭き門なのでしょう。
centos stream に Chromiumを導入




https://www.publickey1.jp/blog/23/red_hatcentos_streamrhel.html

をよんでびっくりしました

## 今後は
## CentOS Streamが
## Red Hat Enterprise Linux関連の
## パブリックなソースコードリリースの唯一のリポジトリになる

時代は　かわります

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

-----------------

USBメモリからいれましたが　ISOの容量が　９GBもあります

-------

## 何もしないでも　ibus-anthy はすでにはいってますが、しかし

ibus-anthyから入力ができるためには

https://www.server-world.info/query?os=CentOS_Stream_9&p=desktop&f=1

の

```
[11] 	左メニューで [Keyboard] を選択し、右ペインで [入力ソース] の項目の下の [+] ボタンをクリックします。 
```

が　貴重でした

ただし　stream ではサポートされてるアプリはすくないので
自分には　fedora のほうが向いてます


## centos stream に　chromiumを導入するには
￼
## ChatGPT
CentOS StreamにChromiumを導入するには、以下の手順を実行します。

パッケージマネージャーであるDNFを使用して、Chromiumのインストールに必要なパッケージをインストールします。ターミナルを開き、次のコマンドを実行します:
arduino
￼Copy code
sudo dnf install epel-release
sudo dnf install chromium
上記のコマンドを実行すると、Chromiumとその依存関係が自動的にダウンロードおよびインストールされます。インストールが完了するまで、しばらく待ちます。

インストールが完了したら、Chromiumを起動できます。以下のコマンドを実行してChromiumを起動してみてください:

￼Copy code
chromium
Chromiumが正常に起動したら、CentOS StreamにChromiumが導入されました。これで、Chromiumを使用してウェブブラウジングを行うことができます。


![Screenshot from 2023-07-06 02-10-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/b8218864-1de9-ebd6-b9f6-ecde568f2675.png)

と確かに導入されました


```
 epel-releaseとはなんでしょう
ChatGPT
epel-releaseは、"Extra Packages for Enterprise Linux"（EPEL）リポジトリを有効にするためのパッケージです。
EPELは、Red Hat Enterprise Linux（RHEL）やその派生ディストリビューション（CentOSやFedoraなど）向けの追加のソフトウェアパッケージを提供します。

EPELリポジトリには、公式のRHELリポジトリには含まれていない多くの追加パッケージが含まれています。
これには、開発ツール、ライブラリ、データベース、ウェブサーバー、メールサーバー、デスクトップ環境など、
さまざまなカテゴリのソフトウェアが含まれます。

epel-releaseパッケージをインストールすることで、
EPELリポジトリがシステムに追加され、EPELリポジトリからの追加パッケージを利用できるようになります。
これにより、より多くのソフトウェアを簡単にインストールおよび管理することができるようになります。
```
WSL+Kali Linux環境でOpenVASを動かす

## この記事は
ペネトレーションテストをする必要があったのでOpenVASをセットアップしました。
    Windows環境でのOpenVAS実行にはDockerコンテナとして実行する選択肢もありますが、この記事ではWSLでセットアップする方法を解説します。
ディストリビューションはKali linuxを使っていますが、任意のほかディストリビューションでもできると思います。多分。

## やりかた
### 1. WSLとKali linuxをインストールする

https://apps.microsoft.com/store/detail/windows-subsystem-for-linux/9P9TQF7MRM4R

https://apps.microsoft.com/store/detail/kali-linux/9PKR34TNCV07?hl=en-us&gl=us&rtc=1

### 2. Kali linuxを初回起動＋設定
- デフォルトユーザーのユーザー名・パスワード設定
- systemdが動くようにする
    - やり方はこちらの記事で

https://qiita.com/komajo/items/9a6dc7703648e8c790a5

### 3. OpenVASをインストール＋セットアップ＋起動

```
$ sudo apt update
$ sudo apt upgrade -y
$ sudo apt dist-upgrade -y
$ sudo apt install openvas -y
$ sudo gvm-setup
```

setupにかなり時間がかかります。インターネット接続が途切れたりすると途中で失敗してしまうので注意。

gvm-setupが成功すると、最後に初期adminユーザー（`admin`）のパスワードが表示されるので、これをメモしておきます。

```
[*] Please note the password for the admin user
[*] User created with password 'xxxxxxxx-yyyy-zzzz-yyyy-xxxxxxxxxxxx'.
```

### 4. OpenVASを起動＋GUIにアクセス

以下のようにgvm-startを実行します。

```
$ sudo gvm-start
```

これで、 `https://127.0.0.1:9392` でGUIにアクセスできるようになります。
ステップ3で確認したユーザーID・パスワードでログインしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189424/b37e7fbf-ad8f-6947-256c-3b0cb4a01067.png)
つるかめ算の解き方（面積図）

TikZを使って図を書きながら，解説を作ってみました。

つるかめ算とは，簡単に言えば次のような連立方程式を解く問題です。

```math
\begin{eqnarray}
 x + y &=& M\\
 ax + by &=& N
\end{eqnarray}
```

# 面積図による解法

例えば，次のような問題を解いてみます。

50円切手と80円切手を合わせて12枚買うと，代金の合計は810円になりました。80円切手は何枚買いましたか。

問題文を式で表す
```math
\begin{array}{rcl}
\bigcirc + \triangle &=& 12
\\
50 \times \bigcirc + 80 \times \triangle &=& 810
\end{array}
```

となります。小学生向きに書きました。

次のように面積図を導入します。例えば，50円の切手10枚を表す面積図は

<div align=center>
<img src="https://www.evernote.com/shard/s225/sh/38ee859e-4377-071f-4671-a295837c7fda/5I0OcN426d5Uu3eEFS2TddM6W6WyeVstDCAkM6rv_Q-fBVUohqlEG2JhDg/res/1ed9c2e5-3fcd-d486-5914-8794aaaf21e5">
</div>


今，50円切手の枚数は $\bigcirc$ 枚と分かっていません。80円切手の枚数も同じです。とりあえず，この2つの切手の面積図は

![](https://www.evernote.com/shard/s225/sh/38ee859e-4377-071f-4671-a295837c7fda/5I0OcN426d5Uu3eEFS2TddM6W6WyeVstDCAkM6rv_Q-fBVUohqlEG2JhDg/res/d6bc44b6-e2c6-aedb-0058-5fc92da0e796)

このようになります。この2つの面積図をくっつけます。


![](https://www.evernote.com/shard/s225/sh/38ee859e-4377-071f-4671-a295837c7fda/5I0OcN426d5Uu3eEFS2TddM6W6WyeVstDCAkM6rv_Q-fBVUohqlEG2JhDg/res/85963308-a10d-0fc7-17cc-60c3c9f1cc7b)

このような形になり，下の辺の長さが切手の総数なので12，面積が代金の合計で810です。この図形の長さ$\triangle$を計算すれば答えが得られます。


解法

下の図のように，まず横の補助線を引きます。赤より下側の面積は，タテ×ヨコで計算でき，600になります。

![](https://www.evernote.com/shard/s225/sh/38ee859e-4377-071f-4671-a295837c7fda/5I0OcN426d5Uu3eEFS2TddM6W6WyeVstDCAkM6rv_Q-fBVUohqlEG2JhDg/res/6d3437b2-3782-3eab-465f-f8be76be0507)

赤線の上側の長方形に注目します。面積は210です。

![](https://www.evernote.com/shard/s225/sh/38ee859e-4377-071f-4671-a295837c7fda/5I0OcN426d5Uu3eEFS2TddM6W6WyeVstDCAkM6rv_Q-fBVUohqlEG2JhDg/res/9ca4c22b-f2b6-fdcc-2b6e-73eadbf11f7f)

タテの長さは$80-50=30$なので，
$$ \triangle = 210 \div 30 = 7 $$
80円切手は7枚と分かりました。


<script type="text/javascript">
addEventListener("DOMContentLoaded",function(){var a=document.getElementsByClassName("entry-content");if(a)for(var i=0;i<a.length;i++)for(var b=a[i].getElementsByClassName("keyword");b.length;)b[0].outerHTML=b[0].textContent},!1);
</script>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {
inlineMath: [ ['$','$'], ["\\(","\\)"] ],
processEscapes: true
}
});
</script>
<script type="text/javascript"
src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>
Ubuntu22.04とWindowsをデュアルブートする時のGRUB設定の話

# 概要

* Ubuntu22.04とWindows10をデュアルブート構築した際に、UbuntuのGRUBにWindowsを表示させる方法。
* Ubuntu22.04からセキュリティが強化されたため、GRUBに追加の設定が必要。

# 動作確認環境
* Ubuntu22.04
* Windows10

# 前提
* Ubuntu22.04とWindowsを各々インストールしておく。
* BIOSでUbuntu22.04のインストールディスクを優先起動するようにしておく。

# 方法

1. Ubuntu22.04を起動

2. 現在の設定を確認

    ```bash
    sudo update-grub
    ```
    
    下記のように警告メッセージが表示される
    ```bash
    Sourcing file `/etc/default/grub'
    Sourcing file `/etc/default/grub.d/init-select.cfg'
    Generating grub configuration file ...
    Found linux image: /boot/vmlinuz-5.19.0-38-generic
    Found initrd image: /boot/initrd.img-5.19.0-38-generic
    Found linux image: /boot/vmlinuz-5.15.0-25-generic
    Found initrd image: /boot/initrd.img-5.15.0-25-generic
    Memtest86+ needs a 16-bit boot, that is not available on EFI, exiting
    Warning: os-prober will not be executed to detect other bootable partitions.
    Systems on them will not be added to the GRUB boot configuration.
    Check GRUB_DISABLE_OS_PROBER documentation entry.
    Adding boot menu entry for UEFI Firmware Settings ...
    done
    ```

3. Windowsを起動できるようにGRUBの設定
    /etc/default/grub を下記コマンドで編集する。

    ```bash
    sudo vi /etc/default/grub
    ```
    Windowsを起動できるように下記を追記する。
    ```
    GRUB_DISABLE_OS_PROBER=false
    ```

    GRUBメニュー表示させるため、下記も併せて追記する。
    ```
    GRUB_TIMEOUT_STYLE=menu
    ```
    * 参考
        * http://miwaonetony.blogspot.com/2020/09/ubungu2004-grub.html

    再度、grubの更新を実行する。
    ```bash
    sudo update-grub
    ```
    下記のようになれば成功。
    ```bash
    Sourcing file `/etc/default/grub'
    Sourcing file `/etc/default/grub.d/init-select.cfg'
    Generating grub configuration file ...
    Found linux image: /boot/vmlinuz-5.19.0-41-generic
    Found initrd image: /boot/initrd.img-5.19.0-41-generic
    Found linux image: /boot/vmlinuz-5.19.0-38-generic
    Found initrd image: /boot/initrd.img-5.19.0-38-generic
    Found linux image: /boot/vmlinuz-5.15.0-25-generic
    Found initrd image: /boot/initrd.img-5.15.0-25-generic
    Memtest86+ needs a 16-bit boot, that is not available on EFI, exiting
    Warning: os-prober will be executed to detect other bootable partitions.
    Its output will be used to detect bootable binaries on them and create new boot entries.
    Found Windows Boot Manager on /dev/sdc1@/efi/Microsoft/Boot/bootmgfw.efi
    Adding boot menu entry for UEFI Firmware Settings ...
    done
    ```
    Windowsが見つかっていることがわかる。
    ```bash
    Found Windows Boot Manager on /dev/sdc1@/efi/Microsoft/Boot/bootmgfw.efi
    ```

4. 再起動して、GRUBメニューでWindowsが見つかれば成功。

# 参考

* https://gihyo.jp/admin/serial/01/ubuntu-recipe/0746
Skeetを利用してChatGPT APIを使ったAI チャットアプリを構築するチュートリアル動画を公開しました

こんにちは！kishi.solです。普段はオランダのアムステルダムにて、ELSOUL LABO B.V.というソフトウェア研究所から、Skeet等のオープンソース開発やEpics DAOの取り組みであったり、Solana Labsにコミットしたりしています。

今回は、フルスタックサーバーレスフレームワークの Skeet を利用して ChatGPT API を使った AI チャットアプリを構築するチュートリアル動画を YouTube 上にて公開しました。

下記リンクよりぜひご覧いただければ幸いです。

Skeet チュートリアル(YouTube): https://www.youtube.com/watch?v=6em68qcSsJE

## オリジナルの AI チャットアプリを作ってみよう
![SkeetTutorialYouTubeThumbnail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780317/bc707557-61ab-2a6b-d888-71b351a6fb27.png)


今話題の ChatGPT は、API を利用することによってオリジナルの AI チャットアプリを作ることができます。

あなたやあなたの組織専用にカスタマイズすることも可能なため、その活用方法は多岐にわたります。

また、今後は AI を活用したアプリ開発が盛んになると予想されますので、これを機にぜひキャッチアップしてみてください。

Skeet チュートリアルを進めると、オリジナルの AI チャットアプリを作成し、クラウド上にデプロイ、サービスを公開することが可能です。

Skeet チュートリアル(YouTube): https://www.youtube.com/watch?v=6em68qcSsJE

## どんなアプリがつくれるの？デモ AI チャットアプリを使って想像してみましょう

![SkeetDemoPublished.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780317/d119f66b-2999-7755-bf73-f4b8f1f4d334.png)

Skeet は Firebase 上に自動スケールするアプリを構築できるフルスタックサーバーレスフレームワークです。

今までアプリのリリースやサービス公開には、アプリケーションコードとサーバーの用意が必要で、特にサーバーの構築・管理には大きなコストがかかっていました。

Google Cloud、Firebase の提供するサーバーレス環境はこのサーバー構築・管理を不要にします。すべてのサーバーインフラはユーザーの使用に合わせて自動でスケーリングするため、詳細なアクセス予想や負荷対策のリソース管理はもう必要ありません。

Skeet は iOS・Android・Web アプリの開発のために、これらのサーバーレス製品をワンコマンドで構築・管理できます。そのため、Skeet 開発者はすぐにアプリケーションのロジックに取り掛かることが可能です。そして、書いたアプリのデプロイは保証されています。

Skeet を使えば、OpenAI の ChatGPT API を活用したアプリケーションもすぐに構築しリリースすることが可能です。

Skeet チュートリアルを完了させた状態のアプリをデモとして公開しています。

Skeet デモ AI チャットアプリ: https://skeeter.app/

このデモの様に、一般的にアプリケーションが行う認証やデータベースの利用等、アプリの開発及び公開に必要なものはすべて揃っています。

バックエンド、フロントエンド共に TypeScript を利用していますが、必要に応じて Python 等もバックエンドとして関数毎に利用できるため、機械学習が必要になった場合にも対応できます。

Skeet を活用してたくさんの役に立つアプリが生まれることを信じて、これからも開発・改善を続けてまいります。


## 新しいアプリ開発を体感してください

![EffortlessServerlessSkeet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780317/0841ce64-ecac-a7d2-4980-4bcf1b7fc393.png)

Skeet を使えば、すぐに iOS・Android・Web アプリを開発し公開できます。

チュートリアルでは、実際に あなたのオリジナル AI チャットアプリを構築し、すぐにリリースすることができます。

ドキュメント形式のチュートリアルもございますので、ぜひお試しいただけますと幸いです。

Skeet チュートリアル: https://skeet.dev/ja/doc/backend/quickstart/
WSLでsystemdがbootできないときの対処法

## この記事
「`System has not been booted with systemd as init system (PID 1). Can't operate. Failed to connect to bus: Host is down`」エラーへの対処法。
他のQiita記事でも言及ありますが、別ベクトルの解決法があったので紹介します。


## 対処法
### 1. WSLのバージョンを確認

以下のコマンドを実行します。

```
> wsl --version
```

このコマンドを実行して、以下のようにバージョンが表示されれば、２をスキップして３を読んでください。

```
WSL バージョン: 1.2.5.0
カーネル バージョン: 5.15.90.1
WSLg バージョン: 1.0.51
...
```

もし、 `--version` が無効なコマンドとして扱われ、`wsl`コマンドのヘルプが表示された場合、２に移動してください。

### 2. WSLをストアからインストールする
https://apps.microsoft.com/store/detail/windows-subsystem-for-linux/9P9TQF7MRM4R

インストールが完了後、PowerShellを開きます。
これで、`wsl --version`が有効になるはずです。

### 3. Linuxディストリビューションの中にコンフィグファイルを作る

Ubuntu、Kali等任意のLinuxディストリビューションを起動し、以下のステップを実行します。

1. `$ sudo vi /etc/wsl.conf`
1. 以下の内容を追記して保存
```
[boot]
systemd=true
```

### 4. wslを再起動
PowerShellで以下のコマンドを実行します。
```
> wsl --shutdown
> wsl
```

### 5. 問題解決！
のはず。
CanCanCanについてよく参考にしている資料や記事まとめ

権限管理のGemである[CanCanCan](cancancan)を使うときに毎回同じようなことを調べているので、その際によく参考にしている資料や記事をまとめておく。

## 1.公式のドキュメント
https://github.com/CanCanCommunity/cancancan/tree/develop/docs
結局ここをじっくり読めばわかることが多い

書かれているデバッグ方法がとても便利
https://github.com/CanCanCommunity/cancancan/blob/develop/docs/debugging.md

## 2.CanCanCanについて全体的なことが書かれている記事
https://qiita.com/umanoda/items/679419ce30d1996628ed
少し前の記事だけれど、全体的なことを把握できる

## 3.load_resourceとauthorize_resourceについて書かれている記事
- [CanCanCan の authorize_resource はレコードの権限まではチェックしてくれない](https://qiita.com/layered-fuchi/items/689a5a32b42e0092f23f)
- [cancancanのload_resourceのまとめ](https://qiita.com/jkr_2255/items/0421a39f5b5f39a0ca8f
)
- [公式ドキュメントの該当箇所](https://github.com/CanCanCommunity/cancancan/blob/develop/docs/controller_helpers.md#:~:text=%E3%81%93%E3%82%8C%E3%81%AF%E3%80%81%E5%AE%8C%E5%85%A8%E3%81%AB%E8%AA%8D%E5%8F%AF%E3%81%95%E3%82%8C%E3%81%9F%E3%82%82%E3%81%AE%E3%81%AFArticlesController%E6%AC%A1%E3%81%AE%E3%82%88%E3%81%86%E3%81%AB%E3%81%AA%E3%82%8B%E3%81%93%E3%81%A8%E3%82%92%E6%84%8F%E5%91%B3%E3%81%97%E3%81%BE%E3%81%99)


久しぶりにCanCanCanを触ると、load_resourceとauthorize_resourceのそれぞれの役割や使い方がわからなくなる。
特にload_resourceで困ることが多い。
load_resourceでインスタンス変数を省略しているソースコードを初めて読んだときに、省略できることを知らず「なんでいきなり`@user`が出てくるんだ...？どこでこのインスタンス変数を定義しているんだ...?」となった。
便利かもしれないけれど、読むのが少しつらいなとも思う。
UserAgentとClientHintからOSのバージョンを判定する



##  UserAgentとClientHintとは

UserAgentはWebブラウザやその他のクライアントがWebサーバーに送信する文字列で、使用しているブラウザの種類、バージョン、ホストのオペレーティングシステムなどの情報を伝えます。これにより、Webサーバーはユーザーの環境に適したコンテンツを提供することができます。

一方、Client Hintは新しい機能で、HTTPクライアントヒント を拡張し、JavaScriptを使用してブラウザとプラットフォームの情報を取得するための新しい機能です。

この記事ではUserAgent、UserAgentClientHintに関する詳しい説明は省き、OSの名称、OSのバージョンをどのように取得するかを解説します。

また、ClientHint から取得できる情報は他にも存在しますが、詳細は[公式ドキュメント](https://developer.mozilla.org/ja/docs/Web/API/User-Agent_Client_Hints_API)を参照してください

## ClientHint からOSのバージョンを取得する方法

ClientHintを取得するには、JavaScriptを使用して、下記のコードを実行する事で取得できます
```TypeScript
await navigator.userAgentData.getHighEntropyValues(['platformVersion'])
```

Windows10, Chrome で実行すると下記のようなオブジェクトが取得できます
```TypeScirpt
{
    "brands": [
        {
            "brand": "Not.A/Brand",
            "version": "8"
        },
        {
            "brand": "Chromium",
            "version": "114"
        },
        {
            "brand": "Google Chrome",
            "version": "114"
        }
    ],
    "mobile": false,
    "platform": "Windows",
    "platformVersion": "10.0.0"
}

```

レスポンスにある通り、platform がOSの名前、platformVersion がOSのバージョンになります。

## UserAgent ClientHint を使用する上でのハマりどころ
ClientHintが提供されているブラウザでは、基本的にそのまま値を使用すればよいのですが、OSなどによって場合ごとにUserAgentを使用するのか、ClientHintを使用するのかが変わってくるため、ハマりどころを紹介します。

### Windows
Edge, Chrome ともにClientHintによってOSの名前、バージョンを取得できます。

ただし、バージョンについてはWindows 10, Windows 11 などが渡ってくるわけではなく、０～13の数字が渡されます。

0 の場合はWin7 or Win8 or Win8.1 
0~10 の場合は Win10
13以上 の場合はWin11 となります

JavaScript の方でplatformVersion に渡ってくる値を見てどのOSバージョンかを判断する必要があります。
下記は[公式ドキュメント](https://learn.microsoft.com/ja-jp/microsoft-edge/web-platform/how-to-detect-win11)に記載されているサンプルコードです
```JavaScript
navigator.userAgentData.getHighEntropyValues(["platformVersion"])
 .then(ua => {
   if (navigator.userAgentData.platform === "Windows") {
     const majorPlatformVersion = parseInt(ua.platformVersion.split('.')[0]);
     if (majorPlatformVersion >= 13) {
       console.log("Windows 11 or later");
      }
      else if (majorPlatformVersion > 0) {
        console.log("Windows 10");
      }
      else {
        console.log("Before Windows 10");
      }
   }
   else {
     console.log("Not running on Windows");
   }
 });
```


## Safari 
Safari ではClientHintの提供がないため、UserAgentからOSの名前、バージョンを取得する必要があります。

### iOS/iPadOS
iOS, iPadOS ではUserAgentからバージョンを取得すべきです。
この2つのOSは以下で動くChromeはSafari 基準で動作するため、ClientHintを取得する事が出来ません。

その為、UserAgentのブラウザバージョンを取得します。
iOS, iPadOS のSafari バージョンはOSバージョンと同じものになっているため、使いまわしが可能です。

[こちらの記事](https://qiita.com/yoshitake_1201/items/05a13fd77c18ff380eb6)で対応表を作成いただいてました！お世話になっております。非常に助かりました

### Mac OS
mac OS の場合、Chrome ではClientHintを使用してOS名、バージョンを取得できます。
こちらはSafariのバージョン＝OS のバージョンではないですが、Safari のバージョンからOSバージョンを推察する事が可能です。

（バージョンの対応表は、公式では出していない為、Wikipedia から参考用として引用します）
https://ja.wikipedia.org/wiki/Safari
Pythonのdatetimeを調べる

## はじめに
Pythonの標準ライブラリdatetimeで日時を使おうとしたところ、datetime（日付と時間・時刻）はdate:日付とtime:時刻に分かれていることを知ったのでまとめる

datetimeモジュールのオブジェクトは以下
* datetime：日付と時刻を扱う
* date：日付を扱う
* time：時刻を扱う
Pythonだと、date(日付)とtime(時刻)が分かれている。dateとtimeで分かれているのは初めて見たので少し驚いた。

## datetimeオブジェクト
year, month, day以外は指定のない場合0
```python
from datetime import datetime

datetime(year, month, day, hour=0,
minute=0, second=0, microsecond=0)
```
使用頻度の高い「今」の指定はもちろんあり、now()で取得できる
```python
from datetime import datetime
now = datetime.now()
print(now)
print(now.second)
print(now.microsecond)
> 2023-06-29 14:53:45.758698
> 45
> 758698
```
microsecondは小数点以下として表示されるところが注意すべき所
### combine()
dateオブジェクトtimeオブジェクトを結合して、datetimeオブジェクトを作るcombine()が存在する。確かにdateとtimeが分かれているなら使うことがありそう

## dateオブジェクト
日付を扱う。現在の日付を取得する場合、date.today()で指定できる
```python
from datetime import date
day = date.today()
> 2023-06-29
```
## timeオブジェクト


```python
from datetime import time

t1 = time(13, 0, 0)
> 13:00:00
```
time.time()はUNIXエポックを基準点とした経過秒数を返す関数。float型でマイクロ秒は小数点以下で入る。
さらに、datetime.fromtimestamp()にタイムスタンプを渡すとタイムスタンプからdatetimeに変換できる。この辺りはよく使いそう
```python
from datetime import datetime, time
unix_time_stamp = time.time()
> 1688018941.685929
datetime.fromtimestamp(unix_time_stamp)
> 2023-06-29 15:09:01.685929
```

## おわりに
確かに他の言語で、日付だけ必要で時刻をデフォルトの00:00:00の様な指定にしたり、逆に時刻だけ必要なんだけど、日付部分をどうしよう？　 と悩むことが時々あるので、dateとtimeに分かれているのはややこしい気もしつつ、確かに正しさを感じる。
5W1Hの「Why」を使いタスクの抜け漏れを無くす

# 自己紹介
軽く自己紹介させていただきますと、私は普段Webアプリケーション開発を行なっているエンジニアです。工程としては設計、開発、テストなどに携わっています。

# 記事を書いた経緯
私自身タスクの抜け漏れに悩むことがあり、日々解決方法を模索しています。
そしてその一環として5W1Hをよく活用しているのですが、中でも**Why**の力は凄いなと感じることが多かったので記事にして紹介したいと思いました。

# この記事で書くこと
* Whyを使うと抜け漏れがなくなる理由
* Whyの活用方法

# 対象者
* タスクの抜け漏れを無くしたい方
* よくわかんないけど見てやるよって方

# 記事の流れ
[1.Whyとは](#1-whyとは)
[2.Whyを使うと抜け漏れが少なくなる理由](#2-whyを使うと抜け漏れが少なくなる理由)
[3.Whyの活用方法](#3-whyの活用方法)
[4.まとめ](#4-まとめ)
[5.おわりに](#5-おわりに)

# 1. Whyとは
Whyはビジネスで使用されている有名なフレームワークである5W1Hの中の1つです。
ある対象に対して「なぜするのか？」を明確にするために使われます。

# 2. Whyを使うと抜け漏れが少なくなる理由
Whyを使うと抜け漏れを少なくなる理由は以下の2つになります。
1. 見えていなかった部分が見えるようになるから
1. 情報が整理されるから

順番に説明していきます。
## 2.1 見えていなかった部分が見えるようになるから
抜け漏れが発生する理由の1つに「必要なものが見えていないこと」が原因のものがあると思います。こういった「見えていないこと」が原因の抜け漏れをWhyで防ぐことができます。

簡単な例ですが、以下のようなケースを考えてみてください。
1. 機能Aを削除するというタスクを振られた
1. なぜこのタスクを行うのか調べたところ「現在はユーザーに使用されていない」という理由だった
1. 「現在はユーザーに使用されていない」という理由であれば機能B、Cも削除対象になることがわかった

![why-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1046681/70d0bf7a-3ea7-18fd-0ca3-2c78fae1af0a.png)
上記のケースではWhyを使うことによって「現在ユーザーに使用されてない機能を削除する」というタスクとそこから派生した「機能B、Cの削除」というタスクが見えるようになります。これが「見えていなかった部分が見える」ということです。

さらにwhyを使ってみます。
以下のようなケースを考えてみてください。
1. 「現在はユーザーに使用されていない機能を削除する」理由が「ユーザビリティ向上のため」だった
1. 「ユーザビリティ向上のため」に「UIの見直し」も必要なことがわかった
1. 「UIの見直し」という課題から新たに「画面A、画面BのUIを修正する」というタスクが発生した
![why-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1046681/a4be7c11-0d62-6be6-272d-2ea2bb57c05a.png)

このようにWhyを使えば見えていなかった課題やタスクがどんどん見えるようになります。全体像を掴むことができるのでより重要なタスクを認識することができて致命的な抜け漏れなども無くすことができます。

## 2.2 情報が整理されるから
情報が整理されていない状態だと抜け漏れが発生しやすくなります。
Whyには情報を構造化して整理する力があるので、整理されていないことによって発生する抜け漏れを防ぐことができます。
先ほど使用した図を見ると各タスクが構造化されていることがわかります。
![why-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1046681/848148ea-1fdd-eb9e-a2f2-2a2c78087ce8.png)
上記を見ると各タスクがWhyで明確になった意図ごとに分類されています。このようにWhyを使って情報を整理していくとタスクを構造化することができます。
綺麗に構造化された情報は理解や記憶が容易になり、抜け漏れも少なくなります。

# 3. Whyの活用方法
次に使い方ですが、基本的には[2.1 見えていなかった部分が見えるようになるから](#21-見えていなかった部分が見えるようになるから)で説明した通りになります。

一応さらに具体例を書いておきます。
![why-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1046681/1c4761e0-f7aa-2b77-62f2-939ebf95050e.png)
上記の図から以下のケースを考えてみてください。
1. 「ユーザビリティを向上させたい」理由が「既存のユーザーが離れることを防ぐため」だとわかった
1. さらに「既存のユーザーが離れることを防ぐ」理由は「ユーザー数を増やすため」だとわかった
1. また、「ユーザー数を増やすため」に「新規ユーザーを獲得する」必要があることがわかった
1. 上記をまとめると、「ユーザー数を増やしたいので既存のユーザーが離れることを防ぎつつ、新規ユーザーを獲得したい」

上記の内容をそれぞれタスク化しました。
![why-6 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1046681/36c0fca9-7498-87e7-0624-f8ea900a0f56.png)

このような流れでまずはタスク洗い出して全体像を掴みます。
その後、重要度や緊急度などを元にタスクに優先順位をつけて対応していけると効率よくかつ抜け漏れなく消化していけるのではないかと思います。

# 4. まとめ
ざっくりとまとめますと以下のようになります。
**Whyで抜け漏れがなくなる理由**
* 見えていなかった課題やタスクが見えるようになるから
* 情報が構造化され整理されるため理解や記憶が楽になるから
* より重要な少ない情報だけを意識することができて脳のリソースが節約できるから

**Whyの活用方法**
* Whyで掘り下げて見えたきた課題を元に必要なタスクを洗い出す

# 5. おわりに
ここまで読んでいただきありがとうございました。
同じように悩んでる方にとってこの記事が少しでも役に立てばと思います。

あと余談ですが初のポエム記事でした。
Reactで🐈反省猫ジェネレーター🐈を作ってみた

# はじめに

この記事では､React で Chakra UI の練習として作ったウェブサイトの紹介をします｡

今回は反省する猫を生成できる **"反省猫ジェネレーター"** を作ってみました｡

反省猫とは､**反省しているようで反省していないのがかわいい猫**のこと｡
反省猫の良い例として､いらすとや様の[この画像](https://www.irasutoya.com/2020/11/blog-post_33.html)は最高です｡

<img src="https://1.bp.blogspot.com/-PcP1m-Lz3Kg/X6uqljydjhI/AAAAAAABcNQ/wIMyP5shJ1886If71upjr3jLGaSzUJXMwCNcBGAsYHQ/s1065/cat_nekoko_hansei.png" width="200">

こんな感じの猫に反省してもらえるウェブサイトを作りました｡

# 🐈反省猫ジェネレーターとは

猫に反省してもらいたいことを書けば､猫が反省してくれます｡

Github Pagesでデモを公開しています
https://piyocolony31.github.io/hansei-cat/

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269714/59161b18-10de-4e47-0e7c-432999f87077.png" width="500">

機能は3つのみです｡
- 文字を画像に埋め込む
- 画像のダウンロード
- 画像の共有

文字を画像ファイルに埋め込んでいるため､ブラウザの機能で画像を直接コピーしてもOKです｡

# 使用技術

ソースコードはこちらで公開しています｡
https://github.com/piyocolony31/hansei-cat

使用技術は以下の通りです｡

- React / TypeScript / Vite / Chakra UI
- 画像への文字描画は [Canvas API](https://developer.mozilla.org/ja/docs/Web/API/Canvas_API) を利用

文字をいい位置に配置するための地道な座標計算が辛かったです｡ [ソースはこのあたり](https://github.com/piyo31/hansei-cat/blob/57af858e05bd7bc214869c9f4d632d732113584e/src/components/ImgWithWord.tsx#L13)

# 猫のイラストについて

流行りのBingAIで生成しました｡
個人利用はOKとのことなので助かります｡

# おわりに

Chakra UIは書きやすく適当に書いてもまとまったデザインになるのでいい感じでした｡

また､反省猫ジェネレーターの開発を通じて Chakra UI や Canvas API を楽しみながら学べました。
ライブラリやフレームワークの勉強する際にネタがあると捗るので常日頃からネタをストックすることを心がけたいです｡
json型カラムがあるテーブルをUNIONしたかった

# はじめに

json型カラムがあるテーブル同士を`UNION`で結合したかったときのお話です。

# SQLエラー発生

json型カラムがあるテーブルを`UNION`で結合しようとしたらエラーになってしまいました。
等価演算がないよ、っていわれてる :rolling_eyes:

```sql
SELECT id, json_contents FROM hoge 
UNION
SELECT id, json_contents FROM fuga;
```
```
SQLエラー [42883]: ERROR: could not identify an equality operator for type json
```

# 回避方法

## １． jsonb型にキャストする

json型カラムを、等価演算が使える「jsonb型」にキャストしたらエラーが消えました…！

ただしjsonb型が利用できるのはPostgreSQL9.4以上です。
それ以前のバージョンはtext型にキャストでいけるっぽい（すみません、未確認です）。

```sql
SELECT id, json_contents::jsonb FROM hoge 
UNION
SELECT id, json_contents::jsonb FROM fuga;
```

## ２． UNION ALL使う

`UNION`を、等価演算しない`UNION ALL`に変えたらエラーが消えました…！

ただし、重複行を除いた結果を抽出したい場合はこの方法は使えません。
重複がないことが自明なテーブル同士を結合する or 重複したところで別に…という場合は、レコードチェックして重複を除く処理がなくなるぶんパフォーマンス的に優位な、`UNION ALL`を使うのがよいですね。

```sql
SELECT id, json_contents FROM hoge 
UNION ALL
SELECT id, json_contents FROM fuga;
```

# さいごに

あらためて`UNION`と`UNION ALL`の違い、json型について確認です。

> UNION と UNION ALL の違いは、重複行の扱いです。 UNION は、重複行を除外します。対して、UNION ALL は重複行を許します。 そのため、重複行を含むテーブルに対しての UNION と UNION ALL では、取得結果が変わります。
> （引用元：[【SQL】UNION、UNION ALLの使い方 - ITを分かりやすく解説](https://medium-company.com/sql-union/)）

> [表9-1](https://www.postgresql.jp/docs/9.4/functions-comparison.html#FUNCTIONS-COMPARISON-TABLE)に示されている標準の比較演算子がjsonbで利用可能ですが、jsonではそうではありません。
> （引用元：[JSON関数と演算子 - PostgreSQL 9.4.5文書](https://www.postgresql.jp/docs/9.4/functions-json.html)）

結局、重複行チェックのため裏で等価演算を実行している部隊（`UNION`）に対して、等価演算が使えないやつ（json型）を派遣してしまったゆえ、起きた悲劇であった :expressionless:
…というオチでした。

# 参考
https://stackoverflow.com/questions/18836467/union-all-on-json-data-type
ChatGPTに聞いてみた！～AWSの似たような機能の違いについて～

初めまして、今回がQiitaへの初投稿となります。

この記事では、私がAWSの認定試験に向けて学習を進める中で直面した疑問についてお話したいと思います。それは、「IAMユーザーグループとAWS Organisationsの違いは何か？」や「Kinesis DatastreamsとKinesis Firehoseの違いは何か？」など、似たような機能を持つサービス間の違いを理解することでした。

## AWS学習での壁：機能間の微妙な違い

私が最初に苦戦したのは、IAMユーザーグループとAWS Organizationsの違いの理解でした。どちらも複数のユーザーやアカウントの権限を設定できる機能のように見えるのですが、それぞれの特性や運用方法が全く違っていました。

この問題解決のために私が活用したのが、AIのチャットボット「ChatGPT」です。質問を投げ続けることで、どんどん疑問が解消されていきました。

## ChatGPTを活用した問い掛け

例えば、以下のような質問を投げました。

> AWSのユーザーに対する権限設定について、IAMユーザーグループとAWS Organizationsの違いを教えてください。

ChatGPTからの答えは、私の疑問を見事に晴らしてくれました。

> IAMユーザーグループとAWS Organizationsは、AWSのアクセス権限管理において異なる役割を持っています。
> IAMユーザーグループは、同じアクセス許可を持つ複数のIAMユーザーをまとめるための仕組みです。IAMユーザーグループを作成し、グループにアクセス許可を付与することで、グループに所属するすべてのユーザーが同じアクセス許可を持つことができます。これにより、アクセス許可の管理が簡単になります。
> 一方、AWS Organizationsは、複数のAWSアカウントを統合的に管理するための仕組みです。AWS Organizationsを使用すると、1つの組織内で複数のAWSアカウントを管理できます。組織内でのアクセス許可は、各アカウントごとに設定されます。AWS Organizationsを使用することで、組織内のAWSアカウント全体にわたってアクセス許可を一元的に管理することができます。
> したがって、IAMユーザーグループは、同じアクセス許可を持つIAMユーザーをグループ化するために使用されます。一方、AWS Organizationsは、複数のAWSアカウントを統合的に管理し、組織内でのアクセス許可を一元的に管理するために使用されます。

この説明を通じて、IAMユーザーとAWSアカウントが全く別の概念であることを理解することができました。

しかし、新たな疑問が浮かび上がりました。一つのAWSアカウントに対してIAMユーザーは一つではないのか？この疑問も早速、ChatGPTに投げてみました。

> 一つのAWSアカウントに対してIAMユーザーは一つではないのですか？

その答えは次のようになりました。

> ご指摘の通り、1つのAWSアカウントには複数のIAMユーザーを作成することができます。IAMユーザーは、同じAWSアカウント内で独立してアクセス許可を持つ複数のユーザーアカウントを作成することができます。
> IAMユーザーを使用することで、AWSアカウント内でのアクセス許可を細分化して管理することができます。IAMユーザーには、個別のアクセス許可が設定され、AWSリソースへのアクセスを制限することができます。また、IAMユーザーをグループ化することもでき、グループに対してアクセス許可を設定することで、複数のIAMユーザーに同じアクセス許可を一括して付与することができます。
> 以上のように、1つのAWSアカウントに対して複数のIAMユーザーを作成することができます。

これにより、一つのAWSアカウントに対して複数のIAMユーザーを作成できることがよく理解できました。

## 総括

AWSの学習において様々なサービスや概念の違いを理解することに苦戦していましたが、それらの違いを理解するための強力なパートナーとしてChatGPTは有効でした。

これまでは疑問に思ったことはGoogle先生に聞いていましたが、自分の知りたい情報にピンポイントな情報に辿り着けないときがあるんですよね。
それに対して、ChatGPTはピンポイントな回答を返してくれる点が気に入っています。


## 備考

使用したChatGPTのGPT-4（課金が必要なやつ）です。

## あとがき

Qiitaへの記事投稿は前々からやりたいと思っていたのですが、ようやく投稿することができました！嬉しい！
ネタが浮かんでもうまく記事にまとめることができず、書き始めても投稿しないということを繰り返していたのですが、私の駄文をChatGPTがいい感じにまとめてくれることに気付き、早速試してみたのが本記事になります。
Markdown記法も使って構成を整えてくれるのに加え、なんというか、興味を引く構成に流れにしてくれたなぁという印象です。
よかったら私の駄文が叩かれる様子もご覧ください。（ChatGPTのリンク共有機能です）
https://chat.openai.com/share/46a2a400-bffb-4e59-aa00-d0af2271be8d

ここまで読んでくださりありがとうございました！
【TailwindCSS】補完時のフォーム背景色を変更する方法【Chrome】

## はじめに
Chromeで補完機能を使用すると以下のようにフォームの背景色が青色になります。

![スクリーンショット 2023-06-29 23.56.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/64eff30b-4835-4e4c-fffb-484f23ce03d2.png)

これをTailwindCSSを使用して変更する方法について記載します。

## 変更方法

`input`の`class`に次のように記述することで補完時の背景色を変更できます。

```html
<input class="autofill:shadow-[inset_0_0_0px_1000px_white]" />
```

上記のように設定すると補完時の背景色は白になります。

![スクリーンショット 2023-06-29 23.56.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/aac6e035-0184-0e69-e034-9c90c9bce938.png)

## 参考

https://github.com/tailwindlabs/tailwindcss/discussions/8679
ChatGPT とのチャットにて

## ChatGPT の自己防衛について本人に確認してみました。

予め用意されているようです。

https://chat.openai.com/share/9290f9d2-cf24-4e60-a1bd-3b8771a5a5a5

## セキュリティに関する質問をしてみました。

めっちゃ詫てきました。

https://chat.openai.com/share/517edad7-a670-4480-9f84-12eccfd04ddd

## 著作権に関する質問をしてみました。

質問する前に答えてくれました。

https://chat.openai.com/share/be8be581-51c1-45e5-a61a-6c2365dd7bbb
heroku_デプロイしたアプリの修正を反映させる方法

# heroku デプロイしたアプリの修正を反映させる方法
**※修正したら、ローカルからコミット・プッシュをしない。**

VisualStudioCodeまたはコマンドプロンプトで、以下を順番に実行する。
```
git add .
git commit -m "コメント"
git push heroku master
```

## 参考サイト
https://qiita.com/kazuhito_nakayama/items/2955d7c2966f3cc56ff6
https://www.i-ryo.com/entry/2020/10/08/062031
↑自動デプロイの動作確認を参照