OmniAICreator/Qiita-1.07M huggingface dataset:
モジュールとは

## はじめに
今回はオブジェクト指向でプログラミングを考える上でも大切になってくるモジュールについてまとめていきたいと思います。
初学者ゆえに解釈違いな部分などもあるかもしれないですが、何卒よろしくお願いいたします！

## モジュールとは何か
モジュールを使うと、**メソッドを共同利用**できます。また、クラスにてモジュールをインクルードすることで、モジュールに定義したメソッドをあたかもクラス自身に定義されたメソッドとして使えるようにします。

## クラスとの違いは何か
モジュールとクラスの違いは以下の2点が挙げられます。
・**インスタンスが生成でき、モジュールはインスタンスが生成できない**
・**クラスは継承でき、モジュールは継承できない**

## モジュールを使うメリットは何か
メリットとしては、モジュールをクラスに組み込むことで、**クラス定義にメソッドをコピー＆ペーストしたのと同じようにモジュールのメソッドをクラスで利用できるようになること**です。
これは、**特定のクラスで再利用したいメソッドがあり、それを一カ所に集めておきたい場面**で非常に便利です。
複数のクラスでメソッドを共同利用するには次の3つの手順を行います。

1. **モジュールを作る**
2. **モジュールにメソッドを定義する。**
3. **モジュールのメソッドをクラスで使う。**

ホイップクリームのトッピングを例として考えていきます。
このような場面でモジュールを使うと、ドリンクでもケーキでもトッピングできる部品を作る事ができます。ホイップクリームをトッピングするメソッドを作り、メソッドを共同利用してみます。
それでは書いていきましょう。

## 1. モジュールを作る
まず初めにモジュールを作ります。ホイップクリームをトッピングするWhippedCreamという名前のモジュールにします。
```ruby:module.rb
module WhippedCream
end
```
```
ruby module.rb
(何も表示されません。)
```

```ruby:モジュールの定義
module モジュール名
end
```

## 2. モジュールにメソッドを定義する
次にモジュールにメソッドを定義します。モジュールはクラスと同じようにメソッドを定義できます。引数や戻り値も同じように可能です。
WhippedCreamモジュールにインスタンスメソッドを定義してみましょう。
ここでは、ホイップクリームをトッピングるすことを想定したwhipped_creamメソッドを定義します。

```ruby:module.rb
module WhippedCream
    def whipped_cream
        @name += "ホイップクリーム"
    end
end
```

```
ruby module.rb
(何も表示されません。)
```

module.rbを実行しても何も表示されないのは定義された上げではメソッドは実行されないからです。ここはクラスとの類似点ですね。

## 3. モジュールのメソッドをクラスで使う
それではモジュールを使用する側であるDrinkクラスを実装します。
```ruby:module.rb
class Drink
    def initialize(name)
        @name = name
    end
    def name
        @name
    end
end

drink = Drink.new("モカ")
puts drink.name
```

```
ruby module.rb
モカ
```

このDrinkクラスにて、WhippedCreamモジュールのwhipped_creamメソッドが使用でき、@nameの末尾に"ホイップクリーム"を加えるのがゴールです。
モジュールのメソッドをクラス使用できるようにするには、**includeメソッド**が必要です。

```ruby:inculeメソッド
class クラス名
    include モジュール名
end
```

```ruby:module.rb
module WhippedCream
    def whipped_cream
        @name += "ホイップクリーム"
    end
end

class Drink
    include WhippedCream
    def initialize(name)
        @name = name
    end
    def name
        @name
    end
end

drink = Drink.new("モカ")
drink.whipped_cream
puts drink.name
```

```
ruby module.rb
モカホイップクリーム
```

`include WhippedCream`を実行すると、DrinkクラスのオブジェクトはモジュールWhippedCreamのメソッドである`whipped_cream`が利用できるようになります。
そのためdrinkオブジェクトの@nameを表示すると、その前の行で追加された`whipped_cream`メソッドが実行されるので、@nameは末尾にトッピングが追加された"モカホイップクリーム"となっています。

## まとめ
最後に@nameの動きとこのプログラムの流れをもう一度整理しましょう。
1. **Drink.rewメソッドの引数で"モカ"が渡され@nameに代入される。**
2. **ここで作られたDrinkクラスのオブジェクトは変数drinkに代入される。**
3. **次の行でdrinkオブジェクトのwhipped_creamメソッドが呼び出され、@nameの末尾に"ホイップクリーム"が追加されます。**
4. **@nameを取得すると、"モカホイップクリーム"となっています。**

## 最後に
結構Rubyの基礎学んでる時はスラスラ覚えられて楽しかったんですが、どうしてもクラスとかモジュールとか継承とか...etcの話になってくると、初学者にとって途端に難しくなるのでその点も踏まえて今回復習がてら書かせていただきました！
やはり記事に起こすことでササっと見直せますし、何がわかってなかったかが明確にされていいですね✨
今後もアウトプット中心の学習を心がけていきたいと思うのでどうぞ応援よろしくお願いいたします🙇

## 引用文献
https://gihyo.jp/book/2018/978-4-297-10123-7

http://ruby-for-beginners.rubymonstas.org/advanced/modules.html

https://qiita.com/kat0/items/c17850e002cbfc9c157d#%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%A8%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%81%AE%E9%81%95%E3%81%84
FileInputStreamでファイルを読み込む方法【Java】

Javaにはファイルの読み込みを行うFileInputStreamクラスがある。
・FileInputStreamクラスとは
・FileInputStreamクラスの使い方
・FileInputStreamクラスのreadメソッド

という基本的な内容から、

・バイトストリームから文字に変換する方法
・文字エンコードをUTF-8などに指定する方法

### 「FileInputStream」クラスとは
FileInputStreamクラスはファイルを読み込み、ファイルの内容を元にした処理や、新しいファイルの作成などを行うために使う。
FileInputStreamクラスを使うと、ファイルは「バイトストリーム」で読み込まれる。
※文字ストリームで読み込みたい場合は「FileReader」クラスを使用すること。

### 「ファイルをバイトストリームで読み込む」方法
初めにFileInputStreamクラスのコンストラクタの引数に読み込む「ファイルのパス」を指定。
次にInputStreamReaderクラスのコンストラクタの引数に「文字エンコードを指定」。
※文字エンコードの指定を間違えると正しく読み込めないので注意。

ファイルは「readメソッド」を使って、データを1バイトずつ読み込む。
readメソッドの戻り値はint型で、データの次のバイトを返す。
ファイルの終わりに達した場合は-1を返す。

```Main.java
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
 
public class Main {
    public static void main(String[] args) throws Exception {
        
        // テキストファイルの内容は”abc”です。
        try (FileInputStream fIStream= new FileInputStream("c:\\Test.txt")) {
            InputStreamReader iSReader = new InputStreamReader(fIStream, "UTF-8");
         
            int data;
            while ((data = iSReader.read()) != -1) {
                System.out.println(data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
```
```
//実行結果
97
98
99
```
このプログラムではテキストファイルをUTF-8で読み込んで、その内容を1バイトずつ表示している。
実行結果にはテキストファイルの内容の”abc”が文字コードで表示される。

読み込みが終わったら、closeメソッドを使用してファイルのリソースを閉じる必要があるので忘れないようにすること。
このプログラムではcloseメソッドの代わりにJava7から追加されたtry-with-resources文でリソースを閉じている。
try-with-resources文を使うには、try文を抜けたときにcloseしたいリソースを、try文の直後の括弧の中に記述。

### 「バイトストリームから文字に変換する」方法
テキストファイルを読み込んだ場合、そのままではバイトの数値が表示されるので、読めるように文字に変換する必要がある。
バイトの数値を文字に変えるには、char型にキャストするだけでOK。

```Main.java
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
 
public class Main {
    public static void main(String[] args) throws Exception {
        
        // テキストファイルの内容は”abc”です。
        try (FileInputStream fIStream= new FileInputStream("c:\\Test.txt")) {
            InputStreamReader iSReader = new InputStreamReader(fIStream, "UTF-8");
         
            int data;
            while ((data = iSReader.read()) != -1) {
                System.out.println(data);
                System.out.println((char) data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
```
```
//実行結果
97
a
98
b
99
c
```

### 参考サイト
https://www.sejuku.net/blog/20567
aws lambda を serverless-offline で実行した際のエラーを ChatGPT に調べさせたら秒で解決した

# つい、いましがたの話

- 既にデプロイ済みのaws lambda関数(Node.js)をserverless offline でローカル起動してみようとしたところ、ローカルサーバーの構築でエラーが発生しました。
- そういえばserverless offlineは、albが未サポートだったな〜と思ったのですが、これをChatGPTが特定できるのか試してみました。

# プロンプト


_Q. 既存の aws Lambda のプログラムを severless offline で実行すると、HttpServer.createRoutes でエラーが発生します。
原因を推測してください。_

_下記は serverless.yml の内容の抜粋です。_

```
functions:
  api:
    handler: handler.api
    events:
        - alb:
            listenerArn:
                Ref: ${self:custom.listers.${opt:stage, self:custom.defaultStage}}
            priority: 1
            targetGroupName: ${self:custom.targets.${opt:stage, self:custom.defaultStage}}
            conditions:
                host: ${self:custom.hosts.${opt:stage, self:custom.defaultStage}}
                path: /*
```

## 回答

_A. serverless-offlineプラグインはAWS Lambda関数をローカルで実行し、API Gatewayのシミュレーションを提供しますが、serverless.ymlファイルにあるalbイベントをサポートしていません。そのため、HttpServer.createRoutesでエラーが発生している可能性が高いです。_

_解決策として、serverless.ymlでhttpイベントを使用することをお勧めします。これにより、serverless-offlineプラグインはローカル環境での実行に適切なルーティングを作成できます。_

_serverless.ymlのfunctions.api.eventsを以下のように修正してみてください：_

```
functions:
  api:
    handler: handler.api
    events:
      - http:
          path: /
          method: ANY
          cors: true
```

_この変更により、すべてのHTTPメソッドに対応するルートが作成されます。ただし、本番環境でALBを使用する場合は、デプロイ時にhttpイベントをalbイベントに戻す必要があります。これは環境変数やステージに基づく条件付き設定を使用して行うことができます。_

---
フォローの内容も完璧です。
このまま、条件付き設定についても追いプロンプトを投げていけば良さそうです。

# 追いプロンプト

_Q. --stage オプションを使った条件付き設定を作成してください。
prod は本番環境
stg はステージング環境
local はローカル環境とします。_

## 回答
_A. serverless.ymlファイル内で--stageオプションに基づく条件付き設定を作成するために、以下のように変更してみてください。_

_まず、functions.api.eventsの定義を削除します。_

_次に、serverless.ymlの最後に次のカスタムセクションを追加します：_
```
custom:
  ...
  eventSettings:
    prod:
      - alb:
          listenerArn:
            Ref: ${self:custom.listers.prod}
          priority: 1
          targetGroupName: ${self:custom.targets.prod}
          conditions:
            host: ${self:custom.hosts.prod}
            path: /*
    stg:
      - alb:
          listenerArn:
            Ref: ${self:custom.listers.stg}
          priority: 1
          targetGroupName: ${self:custom.targets.stg}
          conditions:
            host: ${self:custom.hosts.stg}
            path: /*
    local:
      - http:
          path: /
          method: ANY
          cors: true

```
_これにより、各環境に対して異なるイベント設定が定義されます。_

_最後に、functions.api.eventsを以下のように更新して、カスタムイベント設定を使用します。_
```
functions:
  api:
    handler: handler.api
    events: ${self:custom.eventSettings.${opt:stage, self:custom.defaultStage}}
    ...

```
_これで、--stageオプションに基づいて、適切なイベント設定が選択されます。prodとstgステージでは、ALBイベントが使用され、localステージではHTTPイベントが使用されます。この方法で、他の環境にも独自のイベント設定を追加できます。_

---
完璧です。
新人の頃、こんな先輩に教わりたかったとすら思います。

# 所感

ChatGPTにプログラミングをさせる記事をよく見るのですが、
複雑な要件や条件を正確に伝えて、かつ精度の高いプログラムが生成されるようなプロンプトの作成は、むしろ難儀な気がします。

それに比べてインフラやCI/CDなどの設定ファイルは、比較的シンプルな要件でもそれなりに手数がかかるものです。
これらの構築にChatGPTを利用する方が「現時点では」業務の効率化に効くのではないかと思います。
1つのシンプルなコマンドで特定のPortのプロセスをkillする方法

# 結論

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217487/c48b1757-69a0-fbf2-2e3b-f72d82772472.png)

[kill-port](https://github.com/tiaanduplessis/kill-port)というnpmパッケージを使用する。

# 使い方

`8080`のPortのプロセスをkillしたい場合
```bash
$ npx kill-port 8080
```

複数のPortのプロセスをkillしたい場合
```bash
$ npx kill-port 9000 3000 5000
```

# 通常のやり方

ポートのプロセスを調べる
```bash
$ lsof -i :8080

COMMAND   PID   USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
node    36411 oekazuma   28u  IPv6 0xa9c4356a4d10c577      0t0  TCP localhost:8080 (LISTEN)
```

PIDをコピーし、プロセスをkillする

```bash
$ kill -9 36411
```

このやり方をやってる方が多いんじゃないでしょうか？
僕も今までこのやり方をやってました。
ただ、最初にPIDを調べて、そのIDをコピーしてkillコマンドを叩くって結構面倒です。

```bash
$ kill -9 $(lsof -t -i:8080)
```

こんな感じで一行で書くやり方もありますが、ちょっとコマンドが長いですし、覚えるのが大変ですので[kill-port](https://github.com/tiaanduplessis/kill-port)を使うのは有用そうです。
laravel テスト実行時にキャッシュを使わないようにする

# 概要

- テスト実行時にキャッシュを使わないようにする方法をまとめる。

# 前提

- テストが実行できる状態になっており、.env.testingを用いてテスト環境の設定を行っている。

# 方法

1. `config/cache.php`を開き、`stores`キーの配列に下記を追記する。

    ```config/cache.php
    'none' => [
        'driver' => 'null',
    ],
    ```

1. 追記後`config/cache.php`の`stores`キーの配列は下記の様になる。

    ```config/cache.php
    'stores' => [

    // ~~ 中略 ~~

        'none' => [
            'driver' => 'null',
        ],

    ],
    ```

1. 下記の内容を.env.testingに追記する。

    ```.env.testing
    CACHE_DRIVER=none
    ```

1. 下記を実行してキャッシュをクリアする。

    ```shell
    php artisan cache:clear
    ```

1. テストを実行するとキャッシュのドライバーが割り当てられない状態でテストが動く。
SQL SET型について

# SQL SET型について
SQLには、SET型と呼ばれるデータ型があります。SET型は、特定の値のセットから選択された値を持つ列を定義するために使用されます。
SET型は、ENUM型と似ていますが、ENUM型は単一の値のみを許容するのに対し、SET型は複数の値を持つことができます。
以下は、SET型を使用して列を定義する例です。
``` sql
CREATE TABLE mytable ( id INT, colors SET('red', 'green', 'blue') ); 
```
上記の例では、mytableという名前のテーブルが作成され、colorsという名前のSET型の列が含まれます。この列は、'red'、'green'、'blue'のいずれかの値を持つことができます。
SET型の列には、INSERTステートメントを使用して値を挿入することができます。例えば、次のようにします。

※INSERTステートメントは、データベーステーブルに新しいレコードを挿入するSQLコマンドです。
``` sql
INSERT INTO mytable (id, colors) VALUES (1, 'red, green'); 
```
上記の例では、idが1で、colorsが'red'と'green'の両方を含むSET型の値が挿入されます。
SET型の値は、SELECTステートメントを使用して取得することができます。例えば、次のようにします。

※SELECTステートメントは、データベースからデータを取得するSQLコマンドです。

``` sql
SELECT * FROM mytable WHERE FIND_IN_SET('red', colors); 
```
上記の例では、colors列に'red'の値が含まれているすべての行が返されます。
SET型は、特定の値のセットから複数の値を持つ列を定義する場合に便利です。ただし、SET型の使用は一般的ではなく、他のデータ型がより適切な場合が多いため、使用については注意が必要です。
## SET型の使用が適切な場合の例
SET型の使用が適切な場合の例として、例えば次のような場合が考えられます。
あるWebアプリケーションがあり、そのアプリケーションは、ユーザーが複数の興味関心を持っているかどうかを管理する必要があります。この場合、ユーザーが選択できる興味関心は限られており、アプリケーションはそれらの値のみを認識する必要があります。例えば、音楽、映画、本、料理などのカテゴリーがあるとします。
この場合、SET型を使用して、ユーザーの興味関心を格納する列を定義することができます。例えば、次のようにします。
```sql
CREATE TABLE users ( id INT, name VARCHAR(255), interests SET('music', 'movies', 'books', 'food') ); 
```
上記の例では、usersという名前のテーブルが作成され、interestsという名前のSET型の列が含まれます。この列は、'music'、'movies'、'books'、'food'のいずれかの値を持つことができます。
このように、SET型は、値のセットが限られている場合に便利です。アプリケーションが認識する値が限られているため、ユーザーが不正な値を入力することを防止することができます。また、SET型を使用することで、クエリをより簡潔に書くことができ、読みやすくなるという利点もあります。
## SET型の利点
SET型の利点は、以下の通りです。
1. 値が限定されているため、データの正確性が保証されます。
2. SET型を使用すると、列に許容される値が事前に決まっているため、不正な値を挿入することができません。これにより、データの正確性が保証されます。 
3. 省スペース化されたデータの保存が可能です。
4. SET型は、特定の値のセットから複数の値を持つ列を定義するためのデータ型です。そのため、多くの場合、同じ値を繰り返し保存する必要がなく、データをより効率的に保存できます。 
5. クエリがより簡潔になります。
6. SET型を使用すると、列に許容される値が事前に決まっているため、より簡潔なクエリを書くことができます。例えば、SET型の列に対してFIND_IN_SET関数を使用することで、特定の値がSET型の列に含まれるかどうかを確認できます。 
7. パフォーマンスが向上します。
8. SET型を使用すると、列に許容される値が事前に決まっているため、データの検証が簡単になります。これにより、パフォーマンスが向上し、クエリの実行時間が短縮されます。 
## SET型の欠点
SET型の欠点は、以下の通りです。
1. テーブルの拡張が困難です。
2. SET型は、特定の値のセットから複数の値を持つ列を定義するためのデータ型です。そのため、新しい値をセットに追加する場合、テーブルの拡張が困難になります。新しい値をセットに追加するには、テーブル構造を変更する必要があり、既存のデータを変更する必要があります。 
3. セット内の値の重複が許可されないため、制限的です。
4. SET型では、セット内の値が重複することができません。これは、一部のアプリケーションにとっては制限的であることがあります。例えば、複数のタグを付ける必要がある場合には、同じタグを複数回使用することができません。 
5. 可読性が低下する可能性があります。
6. SET型を使用すると、列に許容される値が事前に決まっているため、列の値を読み解くのが難しくなる場合があります。例えば、セット内の値が0から7までの整数である場合、数値で表示されるため、データを読み解くのが困難になります。 
7. 検索条件が複雑になる場合があります。
8. SET型を使用すると、列の値が複数の値を持つため、検索条件が複雑になることがあります。例えば、複数の値を持つ列を検索する場合、FIND_IN_SET関数を使用する必要があります。これは、パフォーマンスに影響を与える可能性があります。 

SET型は、特定の場合にのみ使用すべきであり、データの正確性を損なう可能性があるため、慎重に使用する必要があるそうです。
キーボードから入力する(InputStreamReader/Scanner)【Java】

Javaにはキーボードから文字を入力するための「InputStreamReader」や「Scanner」がある。標準入力を扱うことができるので上手く活用してみよう。

### 「標準入力」とは
標準入力とはキーボードから文字を入力すること。標準入力を使えばキーボードから入力した文字を表示させたり、文字によってプログラムの動作を分岐させることなどができる。

### 「InputStreamReader」でキーボードから入力する方法
キーボードから入力するには「InputStreamReaderクラス」、「BufferedReaderクラス」、「readLineメソッド」を組み合わせて使う。

次のプログラムで確認してみましょう。

```Main.java
import java.io.IOException;
import java.io.InputStreamReader;
 
public class Main {
 
    public static void main(String[] args) {
 
        InputStreamReader isr = new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(isr);
 
        System.out.println("キーボードから入力してください");
 
        String str = null;
        try {
            str = br.readLine();
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
 
        System.out.println("入力された文字は「" + str + "」です");
 
    }
 
}
```
```
//実行結果
キーボードから入力してください
Samurai
入力された文字は「Samurai」です
```
※このプログラムでは、「Samurai」と入力している。

### Scannerでキーボードから入力する方法
Scannerで入力を受け付け、nextメソッドで入力された文字を読み取る。
次のプログラムで確認してみましょう。

```Main.java
import java.util.Scanner;
 
public class Main {
 
    public static void main(String[] args) {
 
        System.out.println("キーボードから入力してください");
 
        Scanner scan = new Scanner(System.in);
 
        String str = scan.next();
 
        System.out.println("入力された文字は「" + str + "」です");
 
    }
 
}
```
```
//実行結果
キーボードから入力してください
Samurai
入力された文字は「Samurai」です
```
※このプログラムでは、「Samurai」と入力している。

### nextIntメソッドで数値を入力する方法
nextメソッドは入力された文字を文字列として読み込みますが、nextIntメソッドは数値として読み込む。
次のプログラムで確認してみましょう。
```Main.java
import java.util.Scanner;
 
public class Main {
 
    public static void main(String[] args) {
 
        System.out.println("キーボードから入力してください");
 
        Scanner scan = new Scanner(System.in);
 
        int num = scan.nextInt();
 
        System.out.println("入力された文字は「" + num + "」です");
 
    }
 
}
```
```
//実行結果
キーボードから入力してください
123
入力された文字は「123」です
```
※このプログラムでは、「123」と入力しています。

### 参考サイト
https://www.sejuku.net/blog/63188
日本でもGoogle Bard (現在はGemini)が利用可能に。日本国内で初めてBardに質問してみた（回答付き）。

# Bard降臨（現在はGemini）

2023年4月18日午前現在私が日本で1番最初のGoogleBard（現在はGemini）利用者かもです。つい先日までGoogle Bardは米国と英国でのみ利用可能でした。日本では待機リストにすら入れませんでした。けれど2023年4月18日10時頃時点でサイトを見てみると[waitlist]には入れるようになっていました。<p><a href="https://bard.google.com/?hl=en">Google Bard</a></p>
登録したい方は以下の画像の通り上記のリンク先で[Join waitlist]をクリックしてください。登録にはGoogleアカウントが必要です。

![スクリーンショット (772).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3291948/a96af16c-d0b2-05f4-db2d-7e395c886783.png)

# 日本で最初の利用かも

その後１５分足らずで再訪問するとGoogleBardが利用できるようになってました！GoogleのAIチャットボットを使いたい人は即登録を！待機リストの順番が後のほうになるとしばらく待機期間が必要かもしれませんので注意してください。音声入力が可能で日本語での入力は対応していないようです。英語の勉強になりますね！それと機密事項は入力しないように気を付けましょう。新世界を楽しんでください！
![Google Bard2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3291948/49be9ab8-0457-073c-091c-0ce30dd51879.png)

# 利用してみた

少し利用してみました。質問をした後にすぐ回答が来るところはチャットGPT にはない利点ですね。英語で質問すると回答してくれます。回答が満足できない場合やGoogleの検索サイトで深めたい場合などには回答の下に位置している[Google it]というボタンを押すとBardで質問したことを検索できます。内容を深めたい場合はおすすめです。
GoogleBardに以下のように質問してみました。What does the launch of Google Bard in Japan mean for Google？直訳すると日本での Google Bard の立ち上げは、Google にとって何を意味しますか?です。回答は以下の通りです！

![google bard.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3291948/ccb9fd1e-56a9-827a-b754-4d3ab3dc5ad4.png)

わたしが日本で最初のGoogleBardのユーザーかどうかも聞いてみました。
![GOOle.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3291948/2a818c55-6744-2542-0bbd-456e44cbcbf1.png)

新たなことがわかりました！[View other drafts]というボタンをクリックすると３つの違う回答が読めますね。ChatGPTだと1個しかないですがGoogle Bardは３つ違った回答が読めるようです。それと質問をした後、質問の右にあるペンの画像を押すと一度書いた質問を変更できます。ChatGPTだと質問内容の消去はできますが一度書いたら変えられなかったです。加えてBardでは過去の質問を閲覧したくなった時に読み直しはしづらいです。セキュリティの関係もありますが好みが分かれそうです。そのセキュリティは手動で変えられるのでそこまで気にしなくていいかもしれません。

![Google.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3291948/77763013-26ba-d77a-42eb-91bb1038e9b4.png)

# あとがき

今回の質問ではついていませんでしたが、回答としての説明の後に追加の説明（additinal information）が付加されている場合があるところがChatGPTと違うところですね。マイクの画像があるのでそこをおせば音声入力もできますね。それと回答が早い！英語のみ対応なのが残念ですが・・・。皆さんもいろいろ試してみてください！
pythonよく使うコード集

# この記事について

pythonでコーディングする時に、毎回検索するのが面倒くさいのでまとめる

## argparse

```python
import argparse

parser = argparse.ArgumentParser(description='')

parser.add_argument('arg1', help='Config file path')
parser.add_argument('-m', '--make_cert', action='store_true')
parser.add_argument('-x', '--extract', action='store_true')
parser.add_argument('-e', '--embedding', action='store_true')
parser.add_argument('-d', '--dummy_cert', action='store_true')
parser.add_argument(
    '-p',
    '--python_cmd_for_dummy',
    action='store',
    nargs="?",
    default='python',
    type=str,
    help="Python command for running dummy cert tool."
)

args = parser.parse_args()

```

## logging

```python

from logging import getLogger, StreamHandler, Formatter, INFO

logger = getLogger(__name__)
handler = StreamHandler()
handler.setLevel(INFO)
formatter = Formatter('%(asctime)s - %(levelname)s - %(filename)s - %(message)s')
handler.setFormatter(formatter)
logger.setLevel(INFO)
logger.addHandler(handler)
logger.propagate = False

```
Raspberry PiでVNC可能な開発デスクトップ環境について

# Raspberry PiでVNC可能なデスクトップ環境について
### 背景
Raspberry Pi のOSといえば公式の Raspberry Pi OS を使うことが一般的かと思います。
しかし、Raspberry Pi で ROS を導入しロボットを自作したかったので、Ubuntu OS LTS版を導入する必要がありました。
（※現在では Raspberry OSのような Debian ベースのOSにROSを導入する手法もあるようです。）
初心者の私としては、本体からでも、遠隔からでもデスクトップ環境を表示できた方が使いやすいと考え、Ubuntu OS でVNC接続できる環境を作ろうと始めました。
Raspberry Pi OS には標準でRealVNCのvncserverがインストールされており、ホストPCからはRealVNCのvnc viewerで遠隔操作することが一般的なようでした。
そのため、同様にRealvncでデスクトップ環境を表示し操作できるようにすることが目標でした。

### 課題
※ここではvncserverのインストールの説明については省略します。
Raspberry Pi でUbuntu OS LTSを導入するにあたり、server版（デスクトップ環境が入っていない）しかないことが最初の問題としてありました。
そのため、自身でデスクトップ環境をインストールする必要がありました。
ただ、Raspberry Pi において通常のUbuntuのデスクトップ環境を入れると重いので、より軽量なデスクトップ環境を選び導入していました。
その後問題となったのは、VNC接続したときにデスクトップ環境が表示されないエラーです。
画面が真っ黒で操作できなかったり、注意書きがされデスクトップ環境が利用できないエラーが発生しました。

### 原因
RealVNCを利用するにはデスクトップ環境の種類が影響するようです。
lxdeというデスクトップ環境であれば、問題なくVNCでデスクトップ環境を表示できるので、迷ったらlxdeを入れておくと良いと思います。
（Raspberry OS のデスクトップ環境もlxde）

sudo apt install lxde
というコマンドでインストールできると思います。
（詳細は他の記事を参考にしてください）

個人的な注意としてはlubuntuというデスクトップ環境をインストールしないように注意をした方が良いと思います。
lubuntuというディストリビューションがあり、こちらもlxdeのデスクトップ環境を利用できると記載しているサイトが多いかと思います。
ただ、Raspberry Pi で同様のコマンドを打ちインストールを行うとlxdeの次期バージョンであるlxqtのデスクトップ環境がインストールされてしまいます。
私は現状lxqtからlxdeに変えられていませんし、変えられたとしても面倒であると思うので、初めからlxdeのデスクトップ環境をインストールするのが楽かと思います。
Bing AIはChatGPTとどう違うの？

Bing AIはChatGPTとどう違うの？
同じGPT-4を採用しているChatGPTとBing AIですが、どんな時にどちらを使えばいいのでしょうか？ それぞれの強みと弱みをまとめました。

Bing AI

強み

● GPT-4が無料で使える
● Bingの検索技術と掛け合わせた最新情報の収集が可能
● テキストから画像を生成できる
● Edgeブラウザとの連携機能が豊富
弱み

● 1つのトピックに対して、20回までしか回答できない制限がある
● 回答のスピードがChatGPTのGPT-4より遅いことがある
ChatGPT

強み

● 回答スピードがBing AIより速い場合が多い（GPT-4において）
● 回答の回数に制限はなく、長時間同じトピックでやり取りをすることが可能
● 画像や動画など、テキスト以外のファイルも扱えるようになる予定（マルチモーダル機能）
● プラグイン対応により、他社サービスや最新情報にもアクセスできるようになる予定
弱み

● 有料プラン「ChatGPT Plus（月額約2,600円）」に課金しないとGPT-4が使えない（無料プランはGPT-3.5-turboまで）
Bing AIは検索エンジンBingの進化系というだけあって、ブラウザ上での検索や最新情報の収集に特化しています。また、ChatGPTでは毎月約2,600円の課金が必要なGPT-4を無料で使えるってところが大サービス感ありますね。

ただしChatGPTはめまぐるしい速度で新機能を実装していて、Bing AIと同じように最新情報の検索ができるようになることも発表済みです。課金さえしてしまえば、GPT-4との会話の数に制限がないことから、長時間AIを使って取り組みたいことがある場合はChatGPTを使うのがベターでしょう。
PostgreSQLでIntegerからEnumへ変換（キャスト）する方法

## 前提
以下のenumが定義されている
```sql
CREATE TYPE fruits AS ENUM ('リンゴ',
    'バナナ',
    'みかん',
    'いちご');
```

## IntegerからEnumへ

```sql
SELECT (ENUM_RANGE(NULL::fruits))[1];
# りんご

SELECT (ENUM_RANGE(NULL::fruits))[2];
# バナナ

SELECT (ENUM_RANGE(NULL::fruits))[3];
# みかん

SELECT (ENUM_RANGE(NULL::fruits))[4];
# いちご
```
Kubernetes 1.27: SIG Cluster Lifecycle の変更内容

[Kubernetes 1.27 の CHANGELOG](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.76.md) から SIG Cluster Lifecycle の取り組みについてにピックアップしました。

## 重大なアップグレードに関する警告 (Urgent Upgrade Notes)

- なし。

## 種類別の変更 (Changes by Kind)

### 廃止予定 (Deprecation)

- なし。

### APIの変更 (API Change)

- **`kubeadm`: 明示的にstatic podのプライオリティを `priorityClassName: system-node-critical` に設定しました。** ([#114338](https://github.com/kubernetes/kubernetes/pull/114338), [@champtar](https://github.com/champtar))

### 機能 (Feature)

- **kube-upが `CoreDNS` のバージョン `v1.9.3` を利用するようになりました。** ([#114279](https://github.com/kubernetes/kubernetes/pull/114279), [@pacoxu](https://github.com/pacoxu))

- **kubeadm: 新しいFeature Gate (アルファ機能) である `EtcdLearnerMode` が追加されました。これにより、etcd のメンバーを "learner" として参加することができ、"voting member" としてのみ昇格させることができます。** ([#113318](https://github.com/kubernetes/kubernetes/pull/113318), [@pacoxu](https://github.com/pacoxu))

- **kubeadm: kubeletの設定ファイルが `/etc/kubernetes/tmp/` に、`kubeadm-kubelet-config${RANDOM_SUFFIX}` という名前でバックアップされるようになりました。** ([#114695](https://github.com/kubernetes/kubernetes/pull/114695), [@chendave](https://github.com/chendave))

- **kubeadm: kubeadmが利用しているサンドボックスイメージと、コンテナランタイムが利用しているサンドボックスイメージが異なっていた場合、警告を表示するようになりました。** ([#115610](https://github.com/kubernetes/kubernetes/pull/115610), [@SataQiu](https://github.com/SataQiu))

### ドキュメント (Documentation)

- なし。

### バグ修正 (Bug or Regression)

- **kubeadm: 昇格前に準備されたetcdのスタティックマニフェストによる、etcdの"learner"におけるバグを修正しました。**([#115038](https://github.com/kubernetes/kubernetes/pull/115038), [@tobiasgiese](https://github.com/tobiasgiese))

- **kubeadm: CRIのチェックが必要のないフェーズサブコマンドだったとしても、CRIの検出が行われていた問題を修正しました。** ([#114455](https://github.com/kubernetes/kubernetes/pull/114455), [@SataQiu](https://github.com/SataQiu))
  - :pencil: 必要なかったとしてもCRIのチェックをして問題となるユースケースとはどんな物なんだろうとIssueを確認したところ、CRIチェックが必要なかったとしても `--cri-socket` のオプションが必須になっており、指定しなかった場合警告メッセージが出るので混乱する、と言うことでした。

- **kubeadm: apiserver が一時的にダウンしていた場合に、ノードの情報を(apiserverに)更新しようとして再試行を行う処理を改善しました。** ([#114176](https://github.com/kubernetes/kubernetes/pull/114176), [@QuantumEnergyE](https://github.com/QuantumEnergyE))

- **kubeadm: `kubeadm kubeconfig user`コマンドにおいて、`--config`フラグを必須からオプショナルに変更しました。** ([#116074](https://github.com/kubernetes/kubernetes/pull/116074), [@SataQiu](https://github.com/SataQiu))

- **kubeadm: アップロードされたkubelet の設定ファイルである `kube-system/kubelet-config` の `ConfigMap`が、ユーザのパッチを無視する問題を修正しました。** ([#115575](https://github.com/kubernetes/kubernetes/pull/115575), [@SataQiu](https://github.com/SataQiu)) 

- **ディスカバリフェーズにおいて、`kubeadm` がユーザが指定した kubeconfig を利用することができるようになりました。** ([#113998](https://github.com/kubernetes/kubernetes/pull/113998), [@SataQiu](https://github.com/SataQiu))

### その他 (Other (Cleanup or Flake))

- **kubeadm: 非推奨の `v1beta2` API を削除しました。kubeadm 1.26 の `config migrate` コマンドを使って `v1beta2` から `v1beta3` に移行することができます。** ([#114540](https://github.com/kubernetes/kubernetes/pull/114540), [@pacoxu](https://github.com/pacoxu))
- **`coredns` を `v1.10.1` にアップグレードしました。** ([#115603](https://github.com/kubernetes/kubernetes/pull/115603), [@pacoxu](https://github.com/pacoxu))
ransackのsearch_form_forでmethodがgetに固定されてしまっていた話

タイトルの通りですが、ransackのsearch_form_forでmethodをpatchに指定しているのに、ページを表示するとgetに固定されており、うまくいきませんでした。

```index.html.slim
= search_form_for @nantoka, url: nantoka_path, class: 'search-form', method: :patch do |f|
```


### 解決方法

以下のようにhtml: {}の中に入れることで解決しました。他の機能ではhtlの中に入れなくても普通に動くものもあったのですがなぜか...原因不明...
```
method: :patch
↓
html: { method: :patch }
```
Windowsログでリモートデスクトップされた履歴を確認

# やり方

リモートデスクトップされた側（ホスト側）の操作。

Windowsマーク右クリック ⇒ イベントビューアー 。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/622d931a-e231-146b-4274-af3ebbcce84e.png)

アプリケーションとサービスログ ⇒ Microsoft ⇒ Windows 。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/fad5fe77-59de-dcd5-d55a-5e617220edc9.png)

TerminalServices-LocalSessionManager ⇒ Operational 。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/770c5644-977d-f9c6-ee20-e6950101f949.png)

ユーザーや接続元IPアドレスの確認ができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/5d9698cd-df93-e118-1a5c-6e1b6c132368.png)

下記のようにソースネットワークアドレス **ローカル** となっているログもある。
これはリモートデスクトップではないので注意。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/50a3e98e-19c8-c6da-84a8-75fefb8def7f.png)

# 参考サイトさん

https://se-abeaver.com/remote-desktop-log/

# バージョン

Windows 10 Pro 22H2 19045.2846
laravel-pdfdomを導入してPDF出力機能を実装する

## はじめに
案件でPDF出力機能の実装が必要となったのでdompdfを導入した
他にもmPDFだったり他候補もあったが導入に苦戦したりとあったので結果dompdf導入となった
他のPDFツール以下を参考に。
https://qol-kk.com/wp2/blog/2022/08/09/post-3180/

## 導入手順
### ①dompdfをインストール
`composer require barryvdh/laravel-dompdf` コマンドを実行
そうするとcomposer.jsonのrequireにdompdfが追加される。
```composer.json
"require": {
        "php": "^8.1.13",
        "barryvdh/laravel-dompdf": "^2.0",
```

### ②Controller作成
`php artisan make:controller DompdfController`

```DomodfController.php
<?php

namespace App\Http\Controllers;

use Barryvdh\DomPDF\Facade\Pdf; // 追記

class DompdfController extends Controller
{
    public function generatePDF()
    {
        $pdf = PDF::loadView('dompdf.pdf');
        return $pdf->download('PDFダウンロード.pdf');
    }
}
```

### ③Viewを作成する
PDFで出力するファイルを作成しておきましょう。
resources/views 配下にdompdfディレクトリを追加し、そこにpdf.blade.phpを作成しましょう。
中身はプロジェクトによって異なるため、基本的な実装のみ記述します。

```pdf.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title>PDF出力</title>
    </head>
    <style>
    </style>
    <body>
        ここに中身を記述する
    </body>
</html>

```

### ④日本語フォントを導入する
`dompdf`を導入するだけだと日本語に対応していないため、日本語フォントを導入する必要があります。
いくつか日本語フォントは存在するため何でも大丈夫ですが、今回はIPAフォントを導入します。
https://moji.or.jp/ipafont/ipaex00401/

#### fontsディレクトリを作成し、フォントファイルを格納する
`storage`配下に`fonts`ディレクトリを追加し、ダウンロードしたttfファイルを格納します。
`storage/fonts/ipaexg.ttf`
![スクリーンショット 2023-04-18 10.10.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589286/9919b047-1973-2ed2-bee1-4879d7a5e03b.png)

#### bladeファイルに必要事項を記述し、日本語フォントを適用させる
ただファイルを格納するだけでは有効にすることができません。
bladeファイルに必要なことを記述し、適用させましょう。

```pdf.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title>PDF出力</title>
    </head>
    <style>
        /* dompdf日本語文字化け対策 */
        /* 基本の文字 */
        @font-face {
            font-family: ipaexg;
            font-style: normal;
            font-weight: normal;
            src: url('{{ storage_path('fonts/ipaexg.ttf') }}');
        }
        /* 全てのHTML要素に適用 */
        html, body, textarea {
            font-family: ipaexg, sans-serif;
        }
    </style>
    <body>
        ここに中身を記述する
    </body>
</html>
```

### ⑤ルートを記載する
最後にアクセスするためのルートを記載します。
`api.php`でもいいですが、今回は`web.php`に書いていきます。

```web.php
use App\Http\Controllers\DompdfController;

Route::get('dompdf/pdf', [DompdfController::class, 'generatePDF']);
```

これで、`http://localhost:8080/dompdf/pdf`へアクセスするとPDFが出力されるはずです。
以上。

## 参考
https://github.com/barryvdh/laravel-dompdf
https://itcrest.co.jp/laravel-dompdf/
結局どの言語から始めればよいのだろうか？？

# はじめに
私は都内でシステムエンジニアをしています
初めてプログラミングに出会った際はC++から始めました。
実際に今からエンジニアを目指す人に、何から始めればよいかと問われたときに、感覚ではなくデータをもとに勧めれたらという動機で調査しました
# 環境
- Node-RED
- Qiita API
# 方針
- Qiita APIより人気のタグを調査する
- Qiita以外のサイトではどのような言語が人気であるか調査する
- 調査したデータをもとに考察
# Qiita APIを用いた調査

tagを降順で表示
（tagだけを降順で抜き出したかった、、、）
結果については後ほど記載します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3321410/2395bfc6-e6c1-fb8f-7f72-f6a2e75e62ae.png)

```json
[{"id":"dcc09cfd6cc2598f","type":"inject","z":"a59ffd90d79f6d5f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":120,"y":800,"wires":[["abe9431729a192f6"]]},{"id":"abe9431729a192f6","type":"http request","z":"a59ffd90d79f6d5f","name":"","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://qiita.com/api/v2/tags?sort=count","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"credentials":{},"x":330,"y":800,"wires":[["9ccf6c3245fa7a58"]]},{"id":"9ccf6c3245fa7a58","type":"debug","z":"a59ffd90d79f6d5f","name":"debug 4","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":560,"y":800,"wires":[]}]
```

# その他のサイト

- [Github](https://octoverse.github.com/2022/top-programming-languages)
（GitHubは、ユーザのみなさんからヒントを得て作成された開発プラットフォームです。オープンソースプロジェクトやビジネスユースまで、GitHub上にソースコードをホスティングすることで数百万人もの他の開発者と一緒にコードのレビューを行ったり、プロジェクトの管理をしながら、ソフトウェアの開発を行うことができます。）

https://github.co.jp/
- [TIOBE](https://www.tiobe.com/tiobe-index/)
（プログラミングの人気を示す指標であり、Google、Bing、Yahoo!、Wikipedia、Amazon、YouTube、Baiduなどの検索エンジンの検索数のランキング）

https://cmc-japan.co.jp/blog/%E9%96%8B%E7%99%BA%E8%A8%80%E8%AA%9E%E3%83%A9%E3%83%B3%E3%82%AD%E3%83%B3%E3%82%B0/#:~:text=1.%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E8%A8%80%E8%AA%9E%E3%83%A9%E3%83%B3%E3%82%AD%E3%83%B3%E3%82%B0TOP20&text=2022%E5%B9%B412%E6%9C%88%E3%81%AB,%E3%81%AF%E4%BB%A5%E4%B8%8B%E3%81%AE%E9%80%9A%E3%82%8A%E3%81%A7%E3%81%99%E3%80%82&text=%E4%B8%8A%E3%81%AE%E8%A1%A8%E3%81%8B%E3%82%89%E3%80%811,%E3%81%84%E3%82%8B%E3%81%93%E3%81%A8%E3%81%8C%E3%82%8F%E3%81%8B%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82

# 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3321410/f5aa3680-2be8-7f6d-6539-513b0bf25f85.png)


これらの結果として特徴的な点はQiitaのみRubyが上位に入っている点です、世界的にみるとサーバー側の言語はPython,Javaなどが人気なことがわかります。（Pythonは機械学習などでよく用いられるためその分上位に入っている可能性は高いです）
日本人の初学者に言語を勧める際、サーバー側に強く興味がある場合はPython,Rubyを勧め、特段こだわりがない場合はJavaScriptからを学習を進めるとよいと考えます
RubyでAtCoder ABC279(A, B, C, D)を解いてみた

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

# A - wwwvvvvvv
https://atcoder.jp/contests/abc279/tasks/abc279_a
```ruby:a-279.rb
s = gets.chomp
puts s.size + s.count("w")
```

# B - LOOKUP
https://atcoder.jp/contests/abc279/tasks/abc279_b
```ruby:b-279.rb
# 修正前
s = gets.chomp
t = gets.chomp
n = t.size
for i in 0..s.size - n
    if s[i..i + n - 1] == t
        puts "Yes"
        exit
    end
end
puts "No"
```
すごく回りくどいことしてました...
```ruby:b-279.rb
# 修正後
s = gets.chomp
t = gets.chomp

puts s.include?(t) ? "Yes" : "No"
```
## 解説
tと一致する部分文字列があるかどうかを順に調べていき、一致するものがあればYesを出力して終了、最後まで一致するものがなければNoを出力します。

# C - RANDOM
https://atcoder.jp/contests/abc279/tasks/abc279_c
```ruby:c-279.rb
h, w = gets.split.map(&:to_i)
s_array = Array.new(h){ gets.chomp.chars }.transpose.sort
t_array = Array.new(h){ gets.chomp.chars }.transpose.sort

puts s_array == t_array ? "Yes" : "No"
```
## 解説
列について考えるためtransposeメソッドを使って行と列を交換しています。後は、s_arrayとt_arrayそれぞれをsortした結果が一致しているかどうかを調べればOKです。

# D - Freefall
https://atcoder.jp/contests/abc279/tasks/abc279_d
```ruby:d-279.rb
def f(n)
    return $b * n + $a / Math.sqrt(n + 1)
end

$a, $b = gets.split.map(&:to_i)
ans =  (0..10 ** 18).bsearch { |i| f(i) <= f(i + 1)}
puts [f(ans), f(ans + 1)].min
```
<追記>
コメントでいただいた別解になります。
```ruby:別解
a, b = gets.split.map(&:to_i)

h = (((a.to_r / (2 * b)) ** (2/3r)) - 1).to_i
f = ->(x) { b * x + a * (x + 1) ** (-0.5) }
puts (h - 5..h + 5).map { f.(_1) }.select { _1.instance_of?(Float) }.min
```
## 解説
<方針>
行った操作回数をnとすると、高橋くんが地面に到達できる時刻は`bn+a/√(n+1)`となります。

<実装方法>
bsearchメソッドを使って二分探索することで間に合います。また、下に凸のグラフとなるため、探すのは`f(i)<=f(i+1)`の部分となります。なお、aとbは関数定義でも使うために`$`をつけてグローバル変数にしています（A, Bのように定数にしてもできます）。

# 終わりに
D問題は最大が10^18+1と二分探索でも10^9くらいでTLEが微妙でしたが、間に合いました。三分探索という方法もあるみたいで、そっちの方が高速になりそうです。

https://qiita.com/shoya15/items/50fd17e37d7c64f2b166
QPushButton の配色をsetStyleSheetを使わず変更する

# はじめに

QWidget の配色を変更する場合...特にQPushButtonの配色を変更したい場合 色々やったが駄目
Qtアプリをダークモードで表示する方法を ChatGPT に聞いた結果 QPushButton の色も変えられるようになった！
これも Qt使いには当たり前過ぎなのかな？ 拾えなかったので共有

# 対象のstyleを変更

QtのQWidgetとそれの派生クラスには元々styleが設定されている
Win10では```windowsvista```が設定されていて このstyleが色の変更を許可してない模様
なので```fusion```か```windows```に変更すれば 任意の色を設定可能
ただし```windwos```だとかなり古臭いデザインになってしまうので```fusion```の方が適切かも
以下のプログラムでは QTextEdit と QPushButton の色を変更

```C++: main.cpp
#include <QtWidgets>

int main(int argc, char *argv[]) {
	QApplication app(argc, argv);
	try {
		QWidget w;
		QLayout *l = new QVBoxLayout(&w);
		QTextEdit *te = new QTextEdit(&w);
		QPushButton *pb = new QPushButton("push me", &w);
		QStyle *style = QStyleFactory::create("Fusion");

        w.setWindowTitle("foo");
		qDebug() << "styles:" << QStyleFactory::keys() << "fustion:" << style << "origin:" << pb->style();
		w.setLayout(l);
		l->addWidget(te);
		l->addWidget(pb);
		pb->setStyle(style); // これが肝らしい
		//te->setStyle(style); // QTextEdit は style を変更しなくても変色可能
		te->setProperty("idx", 0);
		te->setPlainText("piyopiyo\npicopico\npukapuka");
		w.connect(pb, &QPushButton::clicked, &w, [&]() {
			int idx = te->property("idx").toInt();
			QPalette p = te->palette();

			if (idx >= 3) {
				idx = 0;
			}
			switch (idx) {
			case 0:
				p.setColor(p.Text, Qt::blue);
				p.setColor(p.Window, Qt::red);
				p.setColor(p.Base, Qt::red);
				p.setColor(p.Button, Qt::red);
				p.setColor(p.ButtonText, Qt::white);
				break;
			case 1:
				p.setColor(p.Text, Qt::yellow);
				p.setColor(p.Window, Qt::green);
				p.setColor(p.Base, Qt::green);
				p.setColor(p.Button, Qt::green);
				p.setColor(p.ButtonText, Qt::yellow);
				break;
			case 2:
				p.setColor(p.Text, Qt::white);
				p.setColor(p.Window, Qt::blue);
				p.setColor(p.Base, Qt::blue);
				p.setColor(p.Button, Qt::blue);
				p.setColor(p.ButtonText, Qt::white);
				break;
			}
			te->setPalette(p);
			pb->setPalette(p);
			idx++;
			te->setProperty("idx", idx);
		});
		w.show();
		return app.exec();
	}
	catch (...) {
		qCritical() << "error!";
	}
	return -1;
}
```

「push me」を押下するとこんな感じで配色が変わる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570185/46f3c058-c0d0-4900-a672-e058ee23bbf1.png) ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570185/0d763b54-216a-0fce-9526-f61f627178a8.png) ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570185/5c90ecb9-749f-a7d3-1b89-cc3dc66ea275.png) ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570185/6ff69ec1-1b71-dc81-885f-96de9e86a47a.png)

コンソールへの出力情報は次の通り
```config: console
styles: QList("windowsvista", "Windows", "Fusion") fustion: QFusionStyle(0x2603576d400, name = "fusion") origin: QWindowsVistaStyle(0x2603575cbb0, name = "windowsvista")
```

# おわりに
長年のモヤモヤが漸く解消！
確認したのはWindows版の Qt5.15.2, Qt6.2.4, Qt6.5.0
QApplicationへスタイルを設定でもOK
Qt6.5.0 では QApplicationへ"fusion"を設定するとダークモードで表示してくれる
Databricksでジョブをスケジュール実行あるいは連続実行する

[Run jobs on a schedule or continuously \| Databricks on AWS](https://docs.databricks.com/workflows/jobs/schedule-jobs.html) [2023/4/14時点]の翻訳です。

:::note warn
本書は抄訳であり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

*スケジュール*トリガータイプを用いてDatabricksジョブを定期時に実行したり、*連続*トリガータイプを用いて常にアクティブなジョブ実行がされるようにすることができます。

指定された時間や期間でDatabricksジョブを自動で実行するためにスケジュールを使用することができます。分周期、時間周期、日次、週次、月次、あるいは指定された時間にジョブを実行するようにスケジュールを定義することができます。また、スケジュールのタイムゾーンを指定することができ、任意のタイミングでスケジュールされたジョブを停止することができます。

連続トリガーのジョブを実行する際、Databricksジョブはジョブのアクティブな処理が常に1つ存在することを保証します。以前のジョブ実行が成功した、あるいは失敗ステータスで終了した、あるいは現在実行中のジョブのインスタンスがない場合に、新たなジョブ実行がスタートします。

# ジョブスケジュールの追加

ジョブのスケジュールを定義するには:

1. サイドバーで**Workflows**をクリックします。
1. **Jobs**タブの**Name**カラムでジョブ名をクリックします。
1. **Job details**パネルの**Add trigger**をクリックし、**Trigger type**で**Scheduled**を選択します。
1. 周期、開始時間、タイムゾーンを指定します。オプションで、[Quartz Cron Syntax](http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html)でスケジュールを表示、編集するために**Show Cron Syntax**チェックボックスを選択します。
1. **Save**をクリックします。

また、[notebook UI](https://docs.databricks.com/notebooks/schedule-notebook-jobs.html)でノートブックジョブを直接スケジュールすることができます。

:::note
**注意**
- Databricksでは、cron表現で設定された秒数に関係なく、ジョブのスケジュールによって起動される後発のジョブ実行との間に最低でも10秒のインターバルを強制します。
- サマータイムを持つタイムゾーンやUTCを選択することができます。サマータイムのあるタイムゾーンを選択した際、[サマータイムが開始、終了する際](https://www.quartz-scheduler.net/documentation/faq.html#daylight-saving-time-and-triggers)に毎時のジョブがスキップされたり、1時間、2時間の遅れが生じることがあります。毎時(絶対時間)ジョブを実行するには、UTCを選択してください。
- ジョブスケジューラは低レーテンシーのジョブを意図したものではありません。ネットワークやクラウドの問題によって、ジョブ実行が数分遅れることがあります。このような状況では、サービスの可用性に応じてスケジュールされたジョブが即座に実行されます。
:::

# ジョブスケジュールの停止および再開

ジョブを一時停止するには、**Job details**パネルの**Pause**をクリックします。

停止したジョブのスケジュールを再開するには、**Resume**をクリックします。

# 連続ジョブの実行

1. サイドバーで**Workflows**をクリックします。
1. **Jobs**タブの**Name**カラムでジョブ名をクリックします。
1. **Job details**パネルの**Add trigger**をクリックし、**Trigger type**で**Continuous**を選択して**Save**をクリックします。

連続をジョブを停止するには、**Run Now**の隣の![](https://docs.databricks.com/_images/down-caret-blue.png)をクリックし、**Stop**をクリックします。

:::note
**注意**
- 不必要なリソース使用を避け、コストを削減するために、Databricksは24時間以内に5回以上連続で失敗した連続ジョブを自動で停止します。
- ある連続ジョブの実行インスタンスは1つのみとなります。
- ジョブの終了と、新規ジョブの開始の間には少々の遅れが生じます。この遅れは、60秒以内となります。
- 連続ジョブで[リトライポリシー](https://qiita.com/taka_yayoi/items/b3275a1983c51a8bbe1a#%E3%83%AA%E3%83%88%E3%83%A9%E3%82%A4)と[タスクの依存関係](https://qiita.com/taka_yayoi/items/b3275a1983c51a8bbe1a#%E3%82%BF%E3%82%B9%E3%82%AF%E3%81%AE%E4%BE%9D%E5%AD%98%E9%96%A2%E4%BF%82)を使用することはできません。
- 停止している連続ジョブで**Run now**を選択すると、新規のジョブ実行を起動します。ジョブが停止していない場合、例外がスローされます。
- お使いの連続ジョブに新たなジョブ設定が反映されるようにするには、既存のジョブ実行をキャンセルして自動で新規のジョブ実行をスタートさせます。また、アップデートされた設定を用いてジョブ実行を再開するために**Restart run**をクリックすることができます。
:::

### Databricksクイックスタートガイド

[Databricksクイックスタートガイド](https://www.amazon.co.jp/dp/B09V1YXFVQ/)


### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
人材派遣管理受発注システム

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2709131/1a45106b-4a21-b314-2054-8dfda27c672b.png)
◆会社向けのシステム
「案件、技術者、発注、受注、問合せ、見積、面談、契約、入金、出金、出勤管理、社員管理」
クライアント： 案件、発注、入金、見積、面談
わが社：技術者、問合せ（問合せ履歴）、契約，受注、社員管理、出勤管理、出金
Salesforce: フロー→アラート、APEX　バッチ、
Expercience:外部ユーザがうちのシステムが見えるデータを設定する
子のオブジェクト最終日付を参照する



+ [メンバーシップの日付を最後の商談レコードに設定する](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000PimvN)

フィールド ' Membership end date ' の値を商談レコードから、' Membership end date 'とも呼ばれる関連アカウント フィールドに取得したいと考えています。

アカウントの「メンバーシップの終了日」に値を設定するには、次の条件を満たす必要があります。

Account の「Membership end date」フィールドは、最新の商談レコードから入力する必要がありますWITH :

+「会員終了日」の値
+ 舞台セット「クローズドウォン」

:::note
アカウントの MAX ロールアップ サマリー フィールドを利用して、子供が成約した (ステージでフィルタ) 商談関連レコードに存在する日付フィールドの MAX を取得できます。

次のモジュールに従うことができます (日付についてでなくても): https://trailhead.salesforce.com/fr/content/learn/modules/point_click_business_logic/roll_up_summary_fields
:::
HTMLとCSSについて

CS系の選考をとっていてPython、Javaを最近は学んでいます。最近flaskを使ったwebの作成に興味をもちました。しかしながら、HTML、CSSの知識が素人レベルであることに気づいたので春休みを使って勉強していこうと思います。今回、勉強するにあたって使う教材は、kindle unlimitedの[ちゃんと知っておきたい人のためのHTML/CSS]です。
本日学んだのは、
基本的なタグの役割（div, h, p-paragraph, span, a-URL link, img, ul-list, li-elements of list, table-(tr, th, td), input, form)
htmlとhead(web tag name), body (main part of a web page).
header, main, footer
簡単なブログの一ページ
です。
Create a Custom Theme Layout Component


+ [Create a Custom Theme Layout Component](https://trailhead.salesforce.com/content/learn/projects/communities_theme_layout/create_component)

+ [can't find the Developer tab under settings. What's the work around?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000PeH0N)

「カスタム テーマ レイアウト コンポーネントの作成」で、設定の下に [開発者] タブが見つかりません。回避策は何ですか？

Developer tab ってなんだろう？

+ [I'm stuck at Create a Custom Theme Layout Component](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007cmL75SAE)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/e6f5a593-bece-7c73-d578-7e0dfb7a7d19.png)
[sh][Python] すべてのディレクトリに再帰的に"__init__.py"を作成する

Pythonでパッケージ等を作成しているときに、存在するすべてのディレクトリに再帰的に`__init__.py`ファイルを作成するスクリプト。

```sh
find . -name '__pycache__' -prune -o -type d -exec touch {}/__init__.py \;
```
【WSL2】Homebrewをインストールする方法+α

この記事では以下2点について記述しています。
①HomebrewをWSLにインストールする方法
②Docker(既にローカルにインストール済)をWSL上でも使用出来る状態にする方法

ローカルにインストール済のDockerをWSL上で使用する際に詰まったので+αとして記載させていただきます。

※WSL2の環境構築は<a href="https://qiita.com/asdf22/items/b12eacd5a7507b9646da">こちら</a>をご参照下さい。

<h1>【Homebrewについて】</h1>
ここで簡単にHomebrewについて解説させていただきます。
Homebrewとはアプリの管理ツールです。
インストールする事でbrewコマンドが使用出来るようになります。
brewコマンドで何かアプリをインストールすると他に必要なアプリやライブラリも一緒インストールしてくれます。

HomebrewはMacOSとLinuxOSに対応しています。
WindowsOSはWSL上インストールする必要があります。
※WindowsOSはHomebrewをWSL上でしか使えません。

<h1>【Homebrewをインストール】</h1>
■<a href="https://brew.sh/index_ja">こちら</a>からHomebrew本体をインストール
WSL上で実行します。

■下記コマンドを入力してpathを通す。
※testコマンドは特定のファイルが存在するかを判定するコマンド

```Ubuntu:Ubuntu
test -d ~/.linuxbrew && eval $(~/.linuxbrew/bin/brew shellenv)
```

```Ubuntu:Ubuntu
test -d /home/linuxbrew/.linuxbrew && eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv)
```

```Ubuntu:Ubuntu
test -r ~/.bash_profile && echo "eval \$($(brew --prefix)/bin/brew shellenv)" >>~/.bash_profile
```

■下記コマンドで「.profile」にもpathを通す
この状態だとUbuntuからログアウトすると再度pathを通す必要がある為下記コマンドを入力します。

```Ubuntu:Ubuntu
echo "eval \$($(brew --prefix)/bin/brew shellenv)" >>~/.profile
```

※自分の場合、Ubuntuからログアウトすると再度pathを通す必要があったのですがWSLのdefaultユーザ設定をインストールしたユーザに設定する事で何故か解消しました。

```PowerShell:PowerShell
ubuntu config --default-user hoge
```

<h1>【DockerをWSL上で設定】</h1>

ここでは+αの部分としてDocker(既にローカルにインストール済)をWSL上で使用出来る状態にする方法について記述します。

※前提:
・Docker Desktopがローカルにインストールされている事

■WSL上で使用出来る状態にする方法
・設定画面を開く
・ResourcesのWSL Integrationを開く
・Ubuntuを有効にする
・「Apply&Restart」を押下

※wslにdockerをインストールするコマンドは下記

```Ubuntu:Ubuntu
curl https://get.docker.com | sh
```

以上
コンテンツの消費 ながら行動の危険性

![pexels-scott-webb-311458.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3329690/c5d071ff-edd2-52b7-0904-71ee3e80480c.jpeg)
インターネットの発展により、私たちは音楽や動画、アプリなど、様々なコンテンツを自由に楽しむことができるようになりました。しかし、選択肢が増えすぎてしまうことで、意図せずに浅くながら行動をとってしまい、本来得られるはずの深い理解や学びを逃してしまうことがあります。

例えば、私たちが子供の頃に楽しんでいたテレビ番組は、特定の時間帯にしか放送されず、その時間に合わせて集中して見ていたため、より深い理解や学びを得ることができました。一方、現代のインターネット環境では、コンテンツが無制限に提供されているため、ついつい浅くながら行動をとってしまい、情報やストーリーに触れる機会を逃してしまうことがあります。

そのため、私たちはコンテンツの消費に真剣に向き合うことが大切です。具体的には、コンテンツを消費する前に、何を得たいのか、何を探しているのかという目的を明確にすることが重要です。また、消費する際には、ながら行動を避け、集中して見たり、聞いたりすることで、より深い理解や学びを得ることができます。これらの方法を実践することで、コンテンツの消費が意味のあるものになり、自分自身の成長や豊かな人生につながっていくことができます。
LastModified Date を変換して秒を表示する レポートでの数式


+ [最終更新日の日付形式を HH MM SS SSS に表示](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000Pinq9SAB)

数式フィールドまたは行レベルの数式を作成できますが、GMT で表示されます。これはテキストを返す必要があります。行レベルの数式は次のとおりです。

```
EXT(DAY(DATEVALUE(LAST_UPDATE)))+"/"+
TEXT(MONTH(DATEVALUE(LAST_UPDATE)))+"/"+
TEXT(YEAR(DATEVALUE(LAST_UPDATE)))+" "+
TEXT(HOUR(TIMEVALUE(LAST_UPDATE)))+":"+
TEXT(MINUTE(TIMEVALUE(LAST_UPDATE)))+":"+
TEXT(SECOND(TIMEVALUE(LAST_UPDATE)))
```
数字の出現回数を比較するコード

3ケタもしくは4ケタの整数で、2の出現回数と3の回数をくらべます。2の回数のほうが多いのが良い数、3の回数のほうが多いのが悪い数と定義します。2023までの整数で良い数と悪い数の出現回数の差をもとめてください。こういう問題です。

## まずは変数宣言パート

```c#
int yoi=0;
int warui=0;
string moji="";
int ni=0;
int san=0;
```

## 数字の良しあしを判定し、それを格納。

出現回数を数えるには数字をいったん整数型から文字列に変換する必要がありますね。
そして、それぞれの出現回数をかぞえます。`python`だと、`.Count()`でいけますが、`c#`だと下のようないささか冗長なことに。Linqつかうと簡潔にかけます。

```c#
for (int a=1; a<=2023; ++a){
moji=a.ToString();
ni=moji.Length - moji.Replace(2.ToString(), "").Length;
san=moji.Length - moji.Replace(3.ToString(), "").Length;
if(ni > san){
    yoi = yoi+1;
} else if (san > ni){
    warui=warui+1;
}
}
Console.WriteLine((yoi-warui).ToString());
```

### Linq使う場合

```c#
ni = moji.Where(c => c == >'2').Count(); 
san = moji.Where(c => c == >'3').Count(); 
```

## こたえ

22と出たけど、あってるのかな？

## 参考

[Youtube](https://youtu.be/nfFPeJ4redw)を参考にしました。ありがとうございます。こちらは`Python`ですね
Chrome または Edge でブックマークを用途別に切り替えて使う方法

Chrome用拡張機能を使います(Chrome拡張は Edge にもインストールできます)：

https://chrome.google.com/webstore/detail/bookmarks-bar-switcher/lcaelgondnfehcambmdhhfokjknhfahc

[https://chrome.google.com/webstore/detail/bookmarks-bar-switcher/lcaelgondnfehcambmdhhfokjknhfahc](https://chrome.google.com/webstore/detail/bookmarks-bar-switcher/lcaelgondnfehcambmdhhfokjknhfahc)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140610/4376e9f5-51d1-7c0a-329f-e9c0a141fc42.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140610/012bd791-d2a7-24fb-d3de-d52d84f40297.png)

## 使い方

「ブックマークバー」の右端にでている(下に書いたようにでてない場合もあります)「その他のブックマーク」、Edgeの場合は「その他のお気に入り」内にフォルダを作れば、その名前を指定して切り替えることができます。


「その他のブックマーク」が空の場合はブックマークバーに表示されません。ブックマークバーの何もないところを右クリックして「フォルダを追加」を選び「その他のブックマーク」を右クリックして「新しいフォルダ」を作ります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140610/0eee48e0-cb6b-5a23-4903-f64637dfc991.png)

以下のように「釣り」「英語学習」というフォルダを「その他のブックマーク」の下に作ってみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140610/83d54aa5-5441-ba31-a301-43d016df97e6.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140610/4d963e5f-320a-c255-1eed-541db1dc3af2.png)

以上です。
ブックマークをグルーピングしておけるわけですね。ブックマークグループを切り替えた後に普通にブックマークしていけばいいわけです。フォルダも可。

お試しあれ。
それでゃ！
Terraform Cloudの使い方

Terraform Cloud導入してみたので使い方のご紹介です。

#### 構成図
GitHubと連携できるので以下のような構成で試しました。プルリクでplan、masterへのmergeでapplyという動作です。GitHubとTerraform Cloudは親和性が高いのでこの環境を簡単に構築することができました。
![スクリーンショット 2023-04-14 9.09.40.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/984662/cef2ac4f-6efc-a4cd-7f70-5341bb2ba8be.jpeg)

#### 1.Workspaceの作成
①Coose Type：Version control workflowを選択
②Connect to VCS：GitHubと連携
③Coose a repository：リポジトリの選択（先にGitHubで作っておきましょう）
④Configure settings：Workspace等の入力
![スクリーンショット 2023-04-18 6.04.18.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/984662/b7c08fa5-defb-21dd-32a9-b6c164c3e1d9.jpeg)

#### 2.Variablesの設定
AWSのクレデンシャルを埋め込みます。クレデンシャルなので**取扱注意**しましょう。私は私用のアカウントで２要素認証にしてからやりました。**Variables**から画像の赤枠にアクセスキーとシークレットキーを入力します。
![スクリーンショット 2023-04-18 6.16.06.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/984662/d3d8d504-853f-6072-47cb-53168e497861.jpeg)

#### 3.自動applyの設定
冒頭で記述したプルリクでplan、mergeでapplyが動くように設定します。General Settignsから**Auto apply**を選択します。
![スクリーンショット 2023-04-18 6.18.18.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/984662/dbc0e6e9-1c8b-d03b-13c2-e3d5f6827e6a.jpeg)

#### 4.プルリクとmergeしてみる
AWS上にtest-vpcを作成します。

```terraform
variable "aws_access_key" {}
variable "aws_secret_key" {}

provider "aws" {
  access_key = var.aws_access_key
  secret_key = var.aws_secret_key
  region = "ap-northeast-1"
}

resource "aws_vpc" "test-vpc" {
  cidr_block = "10.0.0.0/16"
  tags = {
    Name = "test-vpc"
  }
}
```
※コードは下記記事より拝借しております
https://qiita.com/boccham/items/190f04bfbc9ffc0b5baf

**①プルリクでplan**
![スクリーンショット 2023-04-18 6.35.35.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/984662/be933de8-a412-c5e5-ae1c-77330bdb687f.jpeg)
![スクリーンショット 2023-04-18 6.35.46.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/984662/f3f4aae0-b2e2-5725-ef78-3b3cd0110289.jpeg)

**②mergeでapply**
![スクリーンショット 2023-04-18 6.38.32.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/984662/8839139a-84e9-b9b8-de7f-6b922ec7b25a.jpeg)

![スクリーンショット 2023-04-18 6.42.08.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/984662/426e1d0c-2508-bb8b-1e46-461aae28f021.jpeg)

AWS上で生成確認
![スクリーンショット 2023-04-18 6.44.09.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/984662/51100725-1b1b-9024-a7b7-4295c3956af4.jpeg)

以上です。削除も**Destruction and Deletion**からさくっとできます。もちろんstateもTerraform Cloud上で管理されます。Terraform CloudはTerraform界にも浸透しつつあるようなので、今後のスタンダードになっていきそうですね。

※参考記事
https://dev.classmethod.jp/articles/terraform-cloud/
https://qiita.com/boccham/items/190f04bfbc9ffc0b5baf
https://zenn.dev/isosa/articles/ca44f2efbfe36b