OmniAICreator/Qiita-1.07M huggingface dataset:
【初心者向け】戻り値とは？いる場合といらない場合

# はじめに
こんにちは。私はプログラミング未経験で開発職に配属されてから2か月目の超初心者です。
基本中の基本である「戻り値」について、初めの頃は「メソッドから返される値らしいけどわかるようでわからないな～」という感じでした。

なので、Javaを勉強し始めた人が「戻り値」って何なのかをまずざっくりと知ることができる手助けになればという気持ちでこの記事を書くことにしました。


# わかっていなかったポイント
+ 戻り値がいる場合といらない場合の違い
+ 値を返さない（戻さない）とは具体的にどういう状況なのか


# 戻り値（返り値）とは
+ メソッドが呼び出されたときに **「呼び出し元に」返される値** のこと
+ メソッドで書かれている処理を実行し、最終的に返される値のこと

はじめは「値を返す」って、System.out.printlnなどの出力でも値が返ってくるってことじゃないの？？？と思っていたのですが、 **メソッドを呼び出した「呼び出し元に」値を返す** という意味です。

# 戻り値がいる場合といらない場合の使い分け
戻り値がある場合とない場合の最も大きな違いは、メソッドが呼び出された後に返される値の有無です。
使い分けのポイントは、 **呼び出し元で値を必要とするか** どうかです。

## 戻り値がいる場合
メソッドが呼び出された結果として、 **呼び出し元に値を返したい** 場合は、戻り値が必要です。
この場合、呼び出し元に戻ってから得られた値を利用して、処理を書くことができます。
戻り値があるメソッドは、呼び出されたときに呼び出し元に「この値を使って処理を進めてください！」と値を渡して（返して）あげるイメージです。

#### 戻り値が必要な例
呼び出し元が、戻り値を使って、
+ データの加工や計算を行いたい場合
+ データの検索を行うメソッド

#### 書き方
返したい値の型を、メソッドの宣言時に指定します。
例えば、int型の戻り値を返したい際には、メソッド名の前にintを指定して宣言します。
``` diff_java
アクセス修飾子 戻り値の型 メソッド名( 引数 ) {
    処理;
    return 戻り値;
}

//具体例：引数として受け取った2つの整数の和を計算するメソッド
public static int calculateSum(int num1, num2) {
    int sum = num1 + num2;
    return sum;
}
```


## 戻り値がいらない場合
何らかの処理を行うだけで **呼び出し元に値を返さない** 場合は、戻り値は必要ありません。
値を返さないことってあるの？とかつては思っていたのですが、以下のように「表示するだけ」「ファイルに書き込むだけ」といったものは、値を返しているのではなく、単なる処理実行になります。

#### 戻り値がいらない例
+ 何らかの操作を実行した結果を表示する（例：System.out.println）
+ データをファイルに書き込む（例：filewriter.write()）
+ 例外処理を行う（例：throw new ~~）
+ DBに接続する

#### 書き方
メソッド宣言の際に戻り値の型にvoidを指定します。
voidとは「空所」という意味で、このメソッドは戻り値を持たないということを示す役割をします。
``` diff_java
アクセス修飾子 void メソッド名( 引数 ) {
    処理;
}

//具体例：引数として受け取った文字列をコンソールに表示するだけのメソッド
public static void displayMessage(String message) {
    System.out.println(message);
}
```

# 戻り値を考える際のポイント
#### メソッドの目的を明確にする
戻り値を返すメソッドを宣言する前に、そのメソッドが何を行うのかを明確にする必要があります。そもそもメソッドから得られる値は呼び出し元で使う予定なのか、使うのであればどのような処理・値が必要なのかを考えます。

#### メソッドが返す値の型を決定する
戻り値が必要である場合は、戻り値の型を決定します。整数、真偽値、文字列など、さまざまなデータ型が存在するため、呼び出し元で必要とされているものに合ったものにします。
# まとめ

+  戻り値とはメソッドを呼び出した **「呼び出し元に」返す値**
+  `return 戻り値` と書く
+  メソッドの宣言時に、戻り値の型も指定する
+  戻り値とvoidの使い分けは **「呼び出し元が値を必要としているか」**
pom.xmlとは


## POM
:::note
Project Object Modelの略
プロジェクトのさまざまな情報を扱うためのオブジェクトモデル
:::

**pom.xmlでは、プロジェクトの設定をXMLのタグとして記述する**

## xmlってなに
:::note
eXtensible Markup Languageの略
データを構造化して記述するためのマークアップ言語
:::

マークアップ言語 : データに意味を持たせるためにタグや要素を使って構造を定義する言語のこと

XMLはテキストベースの形式でデータを表現して、データの階層構造や関係性を明確にできる

### XMLの特徴４つ

#### １，データを階層構造で表現できる
開始タグと終了タグで囲まれた要素が入れ子になり、複雑なデータ構造を表現できる


#### ２，新しい要素や属性を定義して独自のデータ構造を作成できる
さまざまな目的に合わせたカスタムデータ形式を作成できる

#### ３，プラットフォーム非依存


#### ４，データの構造を保持するため、異なるアプリケーション間でデータを交換する際に有用


## XMLの例

```xml
<person>
    <name>John Doe</name>
    <age>30</age>
    <address>
        <city>New York</city>
        <country>USA</country>
    </address>
</person>
```

personという要素があって、その中に名前、年齢、住所の情報が含まれている
要素間の階層構造やデータの意味がタグによって明示されている




# pom.xml
:::note
- Apache Mavenというビルドツールやプロジェクト管理ツールで使用される設定ファイル
→プロジェクトの設定情報をXML形式で記述するためのファイル
MavenはJavaプロジェクトのビルド、依存関係の管理、テスト、デプロイなどを効率的に行うために使われる

:::

### pom.xmlの役割

#### プロジェクトの基本情報

プロジェクトの名前、バージョン、説明などの基本情報を含んでいる
→プロジェクトがどのようなものかを識別し、他の開発者やツールと共有できる

#### 依存関係の管理
Mavenは外部ライブラリやフレームワークを簡単に統合できるようにするため、プロジェクトが依存するライブラリやモジュールの情報をpom.xmlに記述する
→必要なライブラリが自動的にダウンロードされて、プロジェクトに統合される

#### ビルド設定
プロジェクトのビルド設定、コンパイラのバージョン、ビルドの段階、テストの設定などを定義する
→プロジェクトのビルドやテストを簡単に行えるようになる

#### プラグインの設定
pom.xmlではビルドプラグインやテストプラグインなどの設定を行い、プロジェクトの特定のタスクを自動化できる
Mavenはプラグインを使用して様々なタスクを実行できる

#### リポジトリの設定
pom.xmlではカスタムリポジトリやミラーリポジトリなどを設定し、ライブラリのダウンロード元を指定する
Mavenは依存するライブラリを中央リポジトリなどからダウンロードする


:::note
**pom.xmlはMavenを使用してプロジェクトを効率的に管理するための重要な設定ファイル
プロジェクトの依存関係、ビルド設定、プラグインの設定などを一元管理し、開発者がプロジェクトを容易にビルド、テスト、デプロイできるようにしている**
:::
JavaScript の Selenium 実行環境 (Node.js (Mocha) から Selenium 実行)

JavaScript の Selenium 実行環境の構築する
Selenium のエクスポートでも選べる JavaScript のテストフレームワーク の Mocha を使ってやってみる
作った環境で使ったバージョンと手順の大枠はこんな感じ

- 環境、バージョン
    - Windows11
    - Node.js v18.15.0
    - npm v9.5.0
    - mocha v10.2.0
    - selenium-webdriver v4.11.1
    - chromedriver v116.0.0
- 手順
    1. Node.jsインストール
    1. Selenium実行環境構築
      2-1. Mocha, selenium-webdriver, chromedriver インストール
      2-2. 実行モジュール作成、実行

# Node.jsインストール

1. Node.js インストーラー取得(LTSの方を選択)
    https://nodejs.org/
1. インストーラ実行
    画面に従い進める、許可などは確認して同意、はいを選択
    途中でコマンドプロンプト、PowerShell 上がってくるので画面に従いキー入力
    Warning とか出ても気にしないでOK
1. インストール確認
    コマンドプロンプト or Powrshell で以下を入力してバージョン確認
    ```Powershell
    # Node
    node --version
    # Node Package Manager
    npm --version
    ```

# Selenium実行環境構築

## Mocha, selenium-webdriver, chromedriver インストール

1. 適当なフォルダを作る
    `C:\seleniumwork`
1. コマンドプロンプト or Powrshell で作ったフォルダに移動
    ```Powershell
    cd C:\seleniumwork
    ```
1. Mocha をインストール（以下のコマンド実行）
    ```Powershell
    npm i mocha
    ```
1. selenium-webdriver をインストール（以下のコマンド実行）
    ```Powershell
    npm i selenium-webdriver
    ```
1. chromedriver を をインストール（以下のコマンド実行）
    ```Powershell
    npm i chromedriver
    ```
1. 作成された package.json の確認
    ```json:C:\seleniumwork\package.json
    {
      "dependencies": {
        "chromedriver": "^116.0.0",
        "mocha": "^10.2.0",
        "selenium-webdriver": "^4.11.1"
      }
    }
    ```

## 実行モジュール作成、実行

1. フォルダの中に JavaScript `test.js` を作る
    Selenium IDE を使ってエクスポートしたファイルでやってもOK
    サンプルとして Google検索して実行するまでの script は以下
    ```JavaScript:C:\seleniumwork\test.js
    const { Builder, By, Key, until } = require('selenium-webdriver')
    const assert = require('assert')
    
    describe('test', function () {
      let driver
      let vars
      beforeEach(async function () {
        driver = await new Builder().forBrowser('chrome').build()
        vars = {}
      })
      afterEach(async function () {
        await driver.quit(); // ここをコメントアウトでブラウザを閉じなくなる
      })
      it('test', async function () {
        await driver.get("https://www.google.com/")
        await driver.findElement(By.name("q")).sendKeys('test')
        await driver.findElement(By.name("q")).submit()
      })
    })
    ```

1. package.json に実行スクリプト追加
    ```json:C:\seleniumwork\package.json
    {
      "dependencies": {
        "chromedriver": "^116.0.0",
        "mocha": "^10.2.0",
        "selenium-webdriver": "^4.11.1"
      },
      "scripts": {
        "test": "mocha test.js --timeout 0"
      }
    }
    ```
1. コマンドプロンプト or Powrshell で作ったフォルダに移動
    ```Powershell
    cd C:\seleniumwork
    ```
1. テスト実行（以下のコマンド実行）
    ```Powershell
    npm run test
    ```
1. Chromeが上がってきて処理が動けばOK
ハッカソンは個人参加とチーム参加どちらがいいの？

## はじめに
情報系の学科でCSを学習している学部2年のDot-P (@DotP_engineer) です:fire:

今回は、ハッカソンは個人参加するべきか、チーム参加すべきかについて話していこうと思います！

この記事はハッカソンにあまり参加したことがない人、個人参加しようか迷っている人向けに書いた記事になります。

ここで書くチーム開発は即席でチームを組むことを指します。

知人とチームで参加する予定がある方にはあまりこの記事が役に立たないかもしれませんが、ご了承ください:pray:

チーム開発と個人開発、それぞれのメリットとデメリットについて話していくので最後まで読んでいただければ幸いです。

## 自己紹介
工学部の情報系学科２年。　普段は、C言語やLinuxを触ることが多いです:penguin:

そのため、Webの知識については皆無に等しいです。

ハッカソンを通じて、ReactやTypeScript、Flaskなどを触ったので、ほとんど初心者といっても過言ではありません。

この記事を書いているのはちょうど3回目のハッカソンが終了したときで、内訳としては2回は即席でのチーム参加、1回は個人参加という具合です。

3回目のハッカソンで企業賞をいただきました:military_medal:

何回かハッカソン後の懇親会に参加し、そのなかで個人参加に不安を感じている方がかなり多いと感じたので、私なりに見解を書いていこうと思います。

国語は苦手なため、読みづらい文章かもしれませんが、誰か1人のためにでもなれば幸いです:muscle:

## SNS
・Twitter:  @DotP_engineer (←モチベーションの増加になるので、フォローしてね)
・Qiita: https://qiita.com/DotP_engineer
・Github: https://github.com/Dot-P 
・Atcoder: https://atcoder.jp/users/Dot_P (今年の2月から始めました！)


## チーム参加、個人参加のメリット・デメリット

前置きが長くなってしまいましたが、メリット、デメリットについて話してみたいと思います！
ざっとまとめるとこんな感じです。

|   | 個人開発 | チーム開発 |
|:-:|:-:|:-:|
| 技術力の向上  | ◎  | 〇  |
| プレゼンスキル  | ◎  | △  |
| 新たな発見  | 〇  | ◎  |
| コミュ力  | △  | ◎  |
| リーダブルコード  | △  | 〇  |
| 開発期間  | 長い  | 短い  |

### チーム開発

チーム開発では、主に協調性が磨かれます！

特に即席チームでは、異なるバックグラウンドやスキルセットを持つメンバーと共同作業することが一般的です。そのため、他者の視点を理解し、共感を示す必要があります。

相手に伝えたと思ったけれでも、伝わっていなかったというケースも多々あります。

私もチーム開発をした際、フロントエンドとバックエンドの間でうまく情報交換がなされておらず、結局作り直しになってしまったという経験がありました。そういった経験に対する反省が協調性を磨き、他の団体で開発するときにも生きています。

さらにチーム開発では新たな発見もできます！

先ほども言った通り、ハッカソンにはバックグラウンドが違うやスキルセットの異なる人が大勢いらっしゃいます。フロントエンドの知識しかない人がバックエンドの知識をかいつまむこともできますし、何なら教えてもらうことだって可能なわけです。

これは未知に踏み出すビックチャンスです！

恥ずかしながら私はフロントエンドとバックエンドをどう繋げるのかが分かっていませんでした。そのため、チーム開発したコードを見て教えてもらうことで初めて理解しました。

どんな技術があるのかなどを認知するにはハッカソンでのチーム開発にはもってこいです:v:


### 個人開発

個人開発のメリットはなんといっても技術力の向上です。一人であると、わからない箇所は基本的に自分で調べていかないといけないですし、公式ドキュメントを読む機会も増えます。

メンバー間での日程調整がない分、開発期間も長いです。設計から取り組むことができるので、力は申し分ない程度つけられると思います。

しかし、自分で意識して取り組まない限り、リーダブルなコードを書く力は身に着けられません。どうしても機能の実装、UI/UXが優先されてしまうためどうしてもないがしろにされがちです:cry:

これが一番大事なのですが、最後までやりきる覚悟は必要であると感じています。参加したものの、継続的に開発ができず前日にキャンセルする人が一定数いらっしゃいます。それ相応の覚悟で臨むことを強くおすすめします。

最後にまとめとして「こんな人におすすめだよ」ということを書いていこうと思います。

## こんな人におすすめ

### チーム開発

・フロントエンド、バックエンドのどちらも自信がない　(どっちかは触っていて、html、cssはできる)
・初めてハッカソンに参加するので不安に感じている
・協調性を身に着けたいと思っている
・チームにリーダーのような人がいる

### 個人開発

・人に頼らず、開発できるような力をつけたい
・フロントエンド、バックエンドのいずれかはできる
・プレゼンスキルを身に着けたい
・開発期間が十分とれる
・最後までやりきる覚悟がある

## まとめ
よく、「私はバックエンドしかできないので個人開発は...」という方がよくいらっしゃいます。しかし、ハッカソンに初参加するわけではないのならば一度個人で参加してみるとよいと思います！

使える技術の幅が広がり、チャレンジできるものも増えます。個人で最後までプロダクトを開発することで、一人で作れることに対する自信も持てます。

その自信が、あまり開発経験のない友達など周りの人を巻き込んで開発をするきっかけになり、もっと開発が楽しくなるはずです。

この記事を読んだ皆さんが素敵なエンジニアライフを過ごすことを願っています:laughing:

（終わり）
AWS Cognito徹底入門！簡単にユーザー認証を実装する方法

こんにちは！AWSの中でも非常に便利なサービスの1つであるCognitoについて、詳しく解説していきます。この記事を読めば、Cognitoの基本から実際の実装方法までをしっかり掴むことができるでしょう。

### 目次
1. AWS Cognitoとは？
2. 主要な機能
3. 主要な特徴
4. 利用シナリオ
5. 実際の実装方法
6. まとめ

---

### 1. AWS Cognitoとは？
AWS Cognitoは、Amazon Web Services（AWS）が提供する認証・認可サービスです。ユーザー管理とセキュアな認証プロセスを簡単に追加できます。

---

### 2. 主要な機能
#### 1. ユーザープール
ユーザーの登録やサインイン、パスワードリセットなどの基本的なユーザー管理機能を提供します。

#### 2. フェデレーションアイデンティティ
FacebookやGoogleなどのサードパーティプロバイダやSAMLベースの認証など、外部のアイデンティティプロバイダを利用して一時的なAWSの認証情報を提供します。

---

### 3. 主要な特徴
- ソーシャルアイデンティティプロバイダとの統合
- マルチプラットフォーム対応
- セキュリティの強化
- マルチファクタ認証
- カスタマイズ可能なユーザーエクスペリエンス

---

### 4. 利用シナリオ
- モバイルアプリやウェブアプリのユーザー認証
- 一時的なAWS資格情報の提供
- サードパーティとの連携

---

### 5. 実際の実装方法
Cognitoを利用したユーザー認証のサンプルコードを以下に示します。このコードはJavaScriptのSDKを使用したものです。

```javascript
const AmazonCognitoIdentity = require('amazon-cognito-identity-js');

const poolData = {
    UserPoolId: '<YOUR_USER_POOL_ID>',
    ClientId: '<YOUR_CLIENT_ID>'
};

const userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);

const authenticationData = {
    Username: '<USERNAME>',
    Password: '<PASSWORD>',
};

const authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails(authenticationData);

const userData = {
    Username: '<USERNAME>',
    Pool: userPool
};

const cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);

cognitoUser.authenticateUser(authenticationDetails, {
    onSuccess: (session) => {
        console.log('authentication successful', session);
    },
    onFailure: (err) => {
        console.error('authentication failed', err);
    }
});
```

このコードは基本的な認証の流れを示しています。実際の環境に合わせて適切に設定を行ってください。

---

### 6. まとめ
AWS Cognitoは、モバイルアプリやウェブアプリのユーザー認証を簡単に実装するための強力なツールです。この記事を参考に、ぜひ実際のプロジェクトでの利用を検討してみてください。
マルチテナントって？

# マルチテナントとは
一つのアプリケーションインスタンスを複数のユーザーや組織（テナント）が共有することを指します。各テナントは独自のデータセットを持ち、他のテナントのデータにアクセスすることはできません。



## マルチテナントの実装方法

### モデルベース
- **特徴:** 同じデータベースを使用し、テナントごとにデータを区別するための外部キー（例: company_id）を持つ。

    - **実装例:**
テナントモデル（例: Company）の作成。
各テナントごとのデータを区別するための外部キーの追加。
現在のテナントの設定（例: サブドメインを使用）。

- **サブドメインベース**
特徴: 各テナントが独自のサブドメインを持つ。
    - 実装例:
DNSでワイルドカードサブドメインの設定。
Railsのルーティングでサブドメインを制約として使用。
サブドメインのバリデーションの追加。


## サブドメインベースのマルチテナント
ここではサブドメインベースのマルチテナント実装手順例を書きます。

### 1. DNSの設定
ワイルドカードサブドメインを設定します。これは、ドメイン提供者の設定画面で行います。

### 2. サブドメインの制約を使用したルーティングの設定
`config/routes.rb`にサブドメインの制約を追加します。

```ruby:config/routes.rb
constraints(Subdomain) do
  resources :dashboard, only: [:index]
end
```

### 3.サブドメインのバリデーションの追加
Companyモデルにサブドメインのバリデーションを追加します。

```ruby
class Company < ApplicationRecord
  validates :subdomain, presence: true, uniqueness: true
end
```

### 4.サブドメインの制御
以下のようなSubdomainクラスを作成して、特定のサブドメイン（例: wwwやadmin）を除外する制約を設定します。

```ruby:lib/subdomain.rb
class Subdomain
  def self.matches?(request)
    return unless request.subdomain.present? && request.subdomain != 'www'
    request.subdomain.split('.').first != 'admin'
  end
end
```

このクラスを使用すると、www.yourdomain.comやadmin.yourdomain.comのようなサブドメインでのアクセスを特定のルーティングから除外することができます。


## ワイルドカードサブドメインとは、
DNS設定において、あらゆるサブドメインのリクエストを一つのIPアドレスやホストにマッピングするための特殊な設定です。具体的には、*（アスタリスク）を使用してサブドメインを表現します。

例えば、*.example.comというワイルドカードサブドメインを設定すると、user1.example.com、user2.example.com、anything.example.comなど、example.comの任意のサブドメインが同じIPアドレスやホストに解決されます。

### ワイルドカードサブドメインの利点:
#### 1.柔軟性: 
新しいサブドメインを追加するたびにDNSを更新する必要がなく、動的にサブドメインを生成・使用することができます。
マルチテナントアプリケーション: ユーザーや組織ごとに独自のサブドメインを提供するマルチテナントアプリケーションの実装に役立ちます。

#### 2.簡単な管理: 
一つのワイルドカードエントリで多数のサブドメインをカバーできるため、DNSの管理が簡単になります。

#### 3.注意点:
セキュリティの観点から、ワイルドカードサブドメインを使用する際は、不正なサブドメインのリクエストを適切に処理する必要があります。
SSL/TLS証明書を使用する場合、ワイルドカード証明書が必要になることがあります。
ワイルドカードサブドメインは、特定のニーズに合わせて適切に使用することが重要です。


### Railsプロジェクトでワイルドカードサブドメインを実装する際の具体的な手順を以下に示します。

#### 1. DNS設定
まず、ドメインのDNS設定でワイルドカードサブドメインを設定します。これは、ドメインを管理しているプロバイダの設定画面で行います。

例:

```
*.yourdomain.com  A  123.45.67.89
```

#### 2. Railsのルーティング設定
config/routes.rbでサブドメインを制約として使用します。

```ruby
constraints subdomain: /^(?!www)(\w+)/ do
  # ここにサブドメインでアクセスした際のルーティングを記述
end
```

#### 3. サブドメインの取得と利用
ApplicationControllerでサブドメインを取得し、それを利用してテナント（またはユーザー、組織など）を特定します。

```ruby

class ApplicationController < ActionController::Base
  before_action :set_tenant

  private

  def set_tenant
    subdomain = request.subdomain
    @tenant = Tenant.find_by(subdomain: subdomain)
    # もしテナントが見つからない場合の処理も追加すると良いでしょう。
  end
end
```

#### 4. モデルの設定
Tenantモデル（またはUser、Companyなどのモデル）にサブドメインのカラムとバリデーションを追加します。

```ruby
class Tenant < ApplicationRecord
  validates :subdomain, presence: true, uniqueness: true
end
```

#### 5. SSL/TLS証明書
ワイルドカードサブドメインを使用する場合、ワイルドカードSSL/TLS証明書を取得して、全てのサブドメインでHTTPSを使用することをおすすめします。
せんせー、マグネトエンセファログラフィー (MEG)ってなに？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/2c47de5a-d81a-78f9-53c1-4d31d8398c36.png)

キーンコーンカーンコーン...
授業が始まります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/be1492ca-910f-2708-d0fa-8fcfcf14af73.png)

せんせー、マグネトエンセファログラフィーってなに？

# マグネトエンセファログラフィーとは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/da229491-9c49-fb7a-a542-417180e256a7.png)

## MEGって何？

みんな、頭の中で考えることや感じることがありますよね。
その時、頭の中で小さな「電気」や「磁気」が動いているんです。
MEGは、その動きを見るための特別なカメラみたいなものなんです。

## どういうこと？

頭の中で考えたり、感じたりすると、脳という部分が働くんです。
そのとき、超小さい磁気の動きが起こる。MEGは、それをとても正確に見ることができるマシンなんです。

## どうしてそれがすごいの？

このMEGを使うと、どの部分の脳がどんな風に働いているのかを、実際に見ることができるからすごいんです。
それはちょっと、頭の中をのぞいてみるようなものです。

## だから、MEGってなに？

MEGは、頭の中でどう動いているのかを見るための、魔法のようなカメラなんです。

# まとめ

このように、MEGは、私たちの脳の動きを理解するためのとても価値あるツールなんです。
PipedreamでLINE BotのNode.js SDKを使う実験


`@line/bot-sdk`を読み込んで普通に実行することができました。

モジュールあるのでこんなことしなくてもいいんですけどね 

> ![スクリーンショット 2023-08-22 14.37.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/4a193609-340c-f27d-0c71-7338e4058f4f.png "スクリーンショット 2023-08-22 14.37.55.png")

## プッシュメッセージを試すコード

実験です

```js
import line from '@line/bot-sdk'

const config = {
    channelSecret: '',
    channelAccessToken: ''
};
const client = new line.Client(config);

const sendMsg = async (msg) => {

    const messages = [{
        type: 'text',
        text: msg
    }];

    try {
        const res = await client.broadcast(messages);
        console.log(res); 
    } catch (error) {
        console.log(`エラー: ${error.statusMessage}`);
        console.log(error.originalError.response.data);
    }
}

export default defineComponent({
  async run({ steps, $ }) {
    sendMsg('ほげほげああああ');
  },
})
```

これで無事にプッシュメッセージがいけました。

> ※ユーザーのメッセージ基点でWebhook受けて起動させてます。
> ![スクリーンショット 2023-08-22 15.15.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/3407b563-0677-bda0-a67e-3013ebb736de.png "スクリーンショット 2023-08-22 15.15.06.png")

### リプライメッセージの中で入れる場合

時間で起動するパターンも多分いけます（まだ検証できてない）が、リプライメッセージのワークフロー途中に入れた場合、ちゃんとリプライメッセージが送信されないとなぜかNode.jsコード内のプッシュも実行されないといった事象が発生していました。

リプライトークン関係ないと思うんだけどなんでしょうねぇ

> ![スクリーンショット 2023-08-22 15.12.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/30f717fe-8620-5a67-0b92-8fed8758fbef.png "スクリーンショット 2023-08-22 15.12.35.png")
wslでelixir その42

# 概要
wsl(wsl2じゃない)で、elixirやってみた。
練習問題、やってみた。
構想編。

# 練習問題
neosvrで、todoアプリを操作せよ。

# 方針
- websocketサーバー使う。
portは、50002
urlは、localhost
- ecto使う。
- postgres使う。
- desp.get

		{:ecto_sql, "~> 3.2"},
		{:postgrex, "~> 0.15"},
		{:socket, "~> 0.3"}

- クライアントは、transceiver(自作NeosVRオブジェクト)
- インタープリター方式
- コマンドは、4つ
in メモ
del id
up id メモ
disp

以上。
配列の交換

配列を一時的な変数を利用する事なく、要素の交換を行うには

```exchange.ruby
array[a], array[b] = array[b], array[a]
```

前までは新しく配列を作っていたが、こんな便利な方法があったとは！！

次からは、使っていこうと思います。
【Swift】ファイル間のイベント通知に便利！NotificationCenter

# 目次
[1.NotificatonCenterとは](#1-NotificationCenterとは)
[2.メリット](#2-メリット)
[3.使い方](#3-使い方)
[4.おわりに](#4-おわりに)

# 1. NotificationCenterとは
- 一言で言うと「<INS>**ファイル間でイベントを検知する仕組みのこと**</INS>」です。
- 登場人物は「<INS>**Borker(仲介人)**</INS>」、「<INS>**Publish(出版)**</INS>」、「<INS>**Subscribe(購読)**</INS>」の３人です。
- 図にすると以下のような感じになります![Notification.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3534617/b912c382-badb-3e70-6a01-1333a2d6ac23.png)
# 2. メリット
- 異なるオブジェクト間(ファイル間)でイベントが起こった際に別のオブジェクトへ通知する仕組みが簡単に実装できます。
- 監視したいイベントがあるファイルにpost、イベントの検知により処理をしたいファイルにaddObserverするだけで実装できます。
# 3. 使い方
### 配置方法 
- Publish：イベントを検知したいファイル処理に配置
- Broker : NotificationCenterクラス自身のこと
- Subscribe : イベント検知により処理を行いたい部分へ配置
- 具体例
    - イベントを送信したいファイル
    ~~~swift:sendViewController.swift
    let UIBtn = UIButton()
    UIBtn.addTarget(self, action: #selector(onClickBtn), for: .touchUpInside)

    @objc func onClickBtn() {
        print("UIButton Pushed")
        // 通知を送りたい箇所でこのように記述
        NotificationCenter.default.post(name: "UIButtonPushed", object: nil)
    }
    ~~~

    - イベントを受け取りたいファイル
    ~~~swift:recievedViewContoroller.swift
    override func viewDidLoad() {
        super.viewDidLoad()
        // NotificationCenterを登録
        NotificationCenter.default
            .addObserver(self, selector: #selector(recievedKnowtice()), name: "UIButtonPushed", object: nil)
    }

    @objc func recievedKnowtice() {
        print("recieved Pushed Knowtice")
    }
    ~~~

# 4. おわりに
本記事ではNotificationCenterについて解説いたしました。
イベントを送信したい部分と、受け取りたい部分にそれぞれpost, addObserverを記述するだけで簡単にオブジェクト間のデータの受け渡しが出来るとは画期的ではないですか？
他言語経験者の私からすると相当、画期的に思いました笑

目指せ脱初学者！
最後までご覧いただきありがとうございました♪
【解説】ChatGPTのクローラーBotを拒否する方法

# ChatGPTのクローラーBotを拒否する方法

ChatGPTのクローラーBotを拒否する方法をまとめていきます。プライバシーの観点からChatGPTなどAIクローラーに自サイト・ブログの情報を利用されるのは嫌なので拒否していきます。


CloudFlareによると、2023/08/22時点でChatGPTのクローラーBot（GPTBot）が20位で、結構Web上をクローリングしていることがわかります。

https://radar.cloudflare.com/traffic/verified-bots


&emsp;

方法としてはrobot.txtで拒否するか、.htaccessで拒否するかの2つがあります。簡単に違いは以下の通り。


| 方法 | robots.txt | .htaccess |
| --- | --- | --- |
| 対象 | 検索エンジンのクローラーやボット | すべてのクライアント（ボット、ブラウザなど）
| 動作 | ボットに特定のページへのアクセスを「お願い」する | 特定のIPやユーザーエージェントからのアクセスを強制的に拒否	
| 拒否 | 任意（ボットが無視することも可能）  | 強制的（対象クライアントはアクセスできない）
| 設置場所 | サイトのルートディレクトリ  | 対象となるディレクトリ	
| 技術 | テキストファイル（特定のユーザーエージェント対象）  | Apacheサーバーの設定ファイル（詳細なアクセス制御）


&emsp;


## 【方法1】robot.txtで拒否する

ご自身で管理しているrobot.txtに以下を追記します。robot.txtを設置していなければ、「robot.txt」のテキストファイルを作成、以下を記述、ルートディレクトリ配下に配置しましょう。

GPTBotはOpenAIのChatGPTが利用するクローラーBotで、CCBotは非営利団体Common Crawlが開発するクローラーBotでChatGPTが利用するビックデータを収集する団体なので同様に拒否します。

```
UUser-agent: GPTBot
Disallow: /

User-agent: CCBot
Disallow: /
```
&emsp;

公式サイトは以下

https://platform.openai.com/docs/gptbot

https://commoncrawl.org/big-picture/frequently-asked-questions/

&emsp;


動作確認はGoogleサーチコンソールのrobos.txtテスターで確認してください。

https://support.google.com/webmasters/answer/6062598?hl=ja


&emsp;


## 【方法2】.htaccessで拒否する

.htaccessで拒否する場合は以下の通りです。自分は.htaccessでその他bot含めて管理しているのでこちらで拒否しました。.htaccessに詳しくないのであれば、robot.txtで拒否した方がいいです。

```
#AI関連のbot

SetEnvIf User-Agent "GPTBot" deny_bot
SetEnvIf User-Agent "CCBot" deny_bot

<RequireAll>
    Require all Granted
    Require not env deny_bot
</RequireAll>
```


&emsp;


動作確認はPCのコマンドプロンプト、ターミナルからcurlコマンドで確認できます。
```
curl  -H "User-Agent: GPTBot" https://XXX.com/
```

&emsp;

403で拒否されていたら動作確認完了です。

```
<title>403 Forbidden</title>
```

&emsp;




以上！
AWS EC2インスタンスの開始／停止するシェルスクリプト

あるシステムで割高なEC2インスタンスを利用していて、DEVとSTGのEC2インスタンスを`普段は停止し、利用時のみ起動する`という運用にしています。

ただ、起動や停止をするだけのために、AWSにログインするのは面倒です（起動するためだけに、６桁のあれを入力したりするのはちょっと...）。
`コマンド１発でできればいいな〜`と思い、起動／停止するシェルスクリプトを作成したので、備忘録として残します。

## 作成したシェルスクリプト
AWSコマンドラインインターフェイスがインストール済み、かつ、defaultの認証情報プロファイルの設定が完了している前提で作成したシェルスクリプトです。
※作成時のAWS-CLIはv2.9.10です。

``` ec2-start-stop.sh
#!/bin/sh

INSTANCE_ID_DEV="i-dev11111111111111"
INSTANCE_ID_STG="i-stg22222222222222"

if [ $# -lt 2 ]; then
  echo "ERROR: Environment and SubCommand is required.\n"
  exit 0
fi

instanceid=""
if [ $1 == "dev" ]; then
  instanceid=${INSTANCE_ID_DEV}
elif [ $1 == "stg" ]; then
  instanceid=${INSTANCE_ID_STG}
else
  echo "ERROR: '$1' is unknown environment. Specify 'dev' or 'stg'.\n"
  exit 0
fi

subcommand=""
if [ $2 == "start" ]; then
  subcommand="start-instances"
elif [ $2 == "stop" ]; then
  subcommand="stop-instances"
else
  echo "ERROR: '$2' is unknown subcommand. Specify 'start' or 'stop'.\n"
  exit 0
fi

echo "Run Command: aws ec2 ${subcommand} --instance-ids ${instanceid}"
aws ec2 ${subcommand} --instance-ids ${instanceid}
```

## まとめ
久々にシェルスクリプト書いたら、構文を思い出せなくてショックだった。
Mac(M2) で古いバージョンのnodeをnodenv経由で入れる

# 概要

macにnodenv経由でnode`12.22.10`を導入しようとしたところエラーが発生
解消方法の備忘録

* rosseta を利用する
* rosetta のコマンド経由の導入
* nodenv install


## 今回の環境
mac 13.0(M2)
nodenv 1.4.1
node 12.22.10

# エラー概要

```zsh
$ nodenv install 12.22.10    
Downloading node-v12.22.10.tar.gz...
-> https://nodejs.org/dist/v12.22.10/node-v12.22.10.tar.gz

WARNING: node-v12.22.10 is in LTS Maintenance mode and nearing its end of life.
It only receives *critical* security updates, *critical* bug fixes and documentation updates.

Installing node-v12.22.10...

BUILD FAILED (OS X 13.0 using node-build 4.9.120)

Inspect or clean up the working tree at /var/folders/lx/59ywg_p95pjdkrhfg_0gzsgh0000gn/T/node-build.20230822140229.81515.UZLdgG
Results logged to /var/folders/lx/59ywg_p95pjdkrhfg_0gzsgh0000gn/T/node-build.20230822140229.81515.log

Last 10 log lines:
make: python: Command not found
make: python: Command not found
make: python: Command not found
make: python: Command not found
make: python: Command not found
make: python: Command not found
make: python: Command not found
make: python: Command not found
Missing or stale config.gypi, please run ./configure
make: *** [config.gypi] Error 1
```

どうやらビルドに失敗している様子であることがわかる
詳しく解説については割愛

# 対応

## rossettaを使用して開く

「rosettaを使用して開く」を使う

![スクリーンショット 2023-08-22 14.34.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542448/41bf8c80-8153-61be-89dd-e2958a464c7d.png)

自分の環境ではインストールに失敗しましたと発生
原因はrossettaが入っていないことが原因だった

Intel系のアプリの起動時にrossetta導入のアナウンスがあるらしいが自分の環境では表示されなかった
手動でrossetta導入する

### rossettaのコマンド経由の導入

以下コマンドでインストールを実行する
```zsh
$ softwareupdate --install-rosetta --agree-to-license
```

以下のリターンが確認出来れば導入完了
```zsh
Install of Rosetta 2 finished successfully
```

### 動作確認

「rosettaを使用して開く」を使い、再度ターミナルを起動する

```
$ uname -m
x86_64
```

## nodenv install


```zsh
nodenv install 12.22.10
Downloading node-v12.22.10-darwin-x64.tar.gz...
-> https://nodejs.org/dist/v12.22.10/node-v12.22.10-darwin-x64.tar.gz

WARNING: node-v12.22.10-darwin-x64 is in LTS Maintenance mode and nearing its end of life.
It only receives *critical* security updates, *critical* bug fixes and documentation updates.

Installing node-v12.22.10-darwin-x64...
Installed node-v12.22.10-darwin-x64 to /Users/ejirinaohiro/.nodenv/versions/12.22.10

Installing Yarn...
/Users/ejirinaohiro/.nodenv/versions/12.22.10/bin/yarn -> /Users/ejirinaohiro/.nodenv/versions/12.22.10/lib/node_modules/yarn/bin/yarn.js
/Users/ejirinaohiro/.nodenv/versions/12.22.10/bin/yarnpkg -> /Users/ejirinaohiro/.nodenv/versions/12.22.10/lib/node_modules/yarn/bin/yarn.js
+ yarn@1.22.19
added 1 package in 0.714s
Installed Yarn 1.22.19
```

成功！
せんせー、トポロジカル絶縁体ってなに？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/2c47de5a-d81a-78f9-53c1-4d31d8398c36.png)

キーンコーンカーンコーン...
授業が始まります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/be1492ca-910f-2708-d0fa-8fcfcf14af73.png)

せんせー、トポロジカル絶縁体ってなに？

# トポロジカル絶縁体とは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/da229491-9c49-fb7a-a542-417180e256a7.png)

## トポロジカル絶縁体って何？

みんな、皮膚の中心部は感じないけど、外側の皮膚はちょっと触れただけで感じますよね？
トポロジカル絶縁体も、その中心部は電気を流さないけど、外側は電気をよく流す特別な材料なんです。

## どういうこと？

この特別な材料は、中はとっても静かで電気を流さないです。
でも、外側の部分は電気がサッと流れるんです。
それはちょっと、中は安全な家で、外はたくさんの車が走っている道路のようなものです。

## どうしてそれがすごいの？

このような特性を持つ材料は、新しい電子機器やコンピュータを作る時にすごく役立ちます。
電気が特定の場所でしか流れないから、色んな面白いことができるようになります。

## だから、トポロジカル絶縁体ってなに？

トポロジカル絶縁体は、中は電気を流さないけど、外側は電気をよく流す、魔法のような材料なんです。

# まとめ

このように、トポロジカル絶縁体は、新しい電子機器や技術を作るためのすごく興味深い材料なんです。
ブレッドボード裏技集

- 上下に電源ラインが二つあるタイプの場合、上と下をバイパスしておくと楽。反対側も同様に - をバイパスしてある。上下で違う電圧を扱うことは皆無。
![P1050963.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821882/b82d5931-e299-d948-5beb-fb11cda00057.jpeg)

- LEDを設置。写真ではカソードをさしてアノードに抵抗をつけて + に設置。通電中に配線変えたり部品を刺したときにLEDが消えたり極端に暗くなった場合はショート等異常配線している可能性が大。直ちに電源断。
![P1050966.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821882/c629ffe0-8e04-3d51-3179-05038258936f.jpeg)
せんせー、フォトニックチップってなに？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/2c47de5a-d81a-78f9-53c1-4d31d8398c36.png)

キーンコーンカーンコーン...
授業が始まります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/be1492ca-910f-2708-d0fa-8fcfcf14af73.png)

せんせー、フォトニックチップっってなに？

# フォトニックチップっとは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194265/da229491-9c49-fb7a-a542-417180e256a7.png)

## フォトニックチップって何？

みんな、光るものが好きだよね？ランタンやキラキラと光る星など。
フォトニックチップは、この「光」を使って情報を送るための特別な板（チップ）のことを言います。

## どういうこと？

みんなが使うおもちゃのラジコンや、テレビをリモコンで操作する時、中には「情報を送るためのもの」があります。
通常、電気を使って情報を送るけど、フォトニックチップは「光」を使って情報を送るんです。

## どうしてそれがすごいの？

光はとっても速くて、たくさんの情報を一度に送ることができます。
だから、フォトニックチップを使うと、
もっとたくさんの情報をもっと速く送ったり受け取ったりすることができるんです。

## だから、フォトニックチップってなに？

フォトニックチップは、光を使ってたくさんの情報をすごく速く送ったり
受け取ったりするための魔法のような板なんです。

# まとめ

このように、フォトニックチップは、情報を送るときに光の速さと力を使うすごい技術の一部なんです。
拡大縮小機能のためにピッチインピッチアウトの実装

# 背景
WebView主体のアプリを実装しているのですが、画像を表示したときに拡大ができないことに気づいてしまったので対応です。

## MagnificationGestureで実装します
iOS17から非推奨となってしまった[MagnificationGesture](https://developer.apple.com/documentation/swiftui/magnificationgesture)を使います。
（iOS17リリースされてないし、まだ良いよね…？）

ちなみに公式からiOS17以降は[MagnifyGesture](https://developer.apple.com/documentation/swiftui/magnifygesture)使えと言われます。

# 実装
## Gestureの設定（指を離したときに拡大率を元に戻す）
ピッチインピッチアウトで指を離したタイミングで拡大率がデフォルトに戻ります。

```GestureTestView.swift
    // MARK: - Gesture Properties
    
    /// 最小のスケールを設定
    let minGestureScale: CGFloat = 1.0
    /// 最大のスケールを設定
    let maxGestureScale: CGFloat = 4.0
    
    /// 拡大Gestureの設定（指を離したときに拡大率を元に戻す）
    @GestureState var magnifyByDefault = 1.0
    var magnificationByDefault: some Gesture {
        MagnificationGesture()
            .updating($magnifyByDefault) { currentState, gestureState, transaction in
                // ジェスチャーの変化値を指定の範囲に制限
                let limitedValue = min(max(currentState, minGestureScale), maxGestureScale)
                
                gestureState = limitedValue
            }
    }

    // MARK: - View
    VStack {
        hogeView()
            // 拡大率を戻す場合
            .scaleEffect(magnifyByDefault, anchor: .center)
            .gesture(magnificationByDefault)
    }
```

## Gestureの設定（指を離したときに拡大率を維持する）
ピッチインピッチアウトで指を離したタイミングで拡大率が戻らないようにします。
`magnifyBy`を`@State`しています。

```GestureTestView.swift
    // MARK: - Gesture Properties
    
    /// 拡大Gestureの設定（指を離したときに拡大率を維持する）
    @State private var magnifyBy = 1.0
    /// 最小のスケールを設定
    let minGestureScale: CGFloat = 1.0
    /// 最大のスケールを設定
    let maxGestureScale: CGFloat = 4.0
    
    /// ジェスチャー倍率設定
    var magnification: some Gesture {
        MagnificationGesture()
            .onChanged { value in
                // ジェスチャーの変化値を指定の範囲に制限
                let limitedValue = min(max(value, minGestureScale), maxGestureScale)

                // 変化量を制限したジェスチャーの変化値を代入
                magnifyBy = limitedValue
            }
    }

    // MARK: - View

    VStack {
        hogeView()
            // 拡大率を維持する場合
            .scaleEffect(magnifyBy, anchor: .center)
            .gesture(magnification)
    }
```

## 課題
- ピッチインピッチアウトが画面中央に対してになるので、指で触れている箇所に対して行いたい（Safari、Chromeみたいな感じ）。
- 拡大した状態でViewを上下左右に動かしたい。
- MagnifyGestureで実装する。

# 参考
[MagnificationGesture](https://developer.apple.com/documentation/swiftui/magnificationgesture)
[MagnifyGesture](https://developer.apple.com/documentation/swiftui/magnifygesture)
[【SwiftUI】ピンチイン・ピンチアウトでViewを拡大縮小する](https://dev.classmethod.jp/articles/swiftui-pinch-in-out/)
WiX Toolset v4 準備編

# v3とv4の判別方法
1. `Candle.exe`と`Light.exe`が見えたらv3。それ以外がv4
1. XMLの頭に`<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">`と書かれていたらたぶんv3。v4は`<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">`らしい。
1. 2023年3月以前の記事はほぼv3


# 準備編
- CLI上で以下を入力。
```
dotnet tool install --global wix
```
以上！
Kingfisherの`|>`演算子について

# はじめに
Kingfisherを使っていて`|>`という演算子を初めてみて、Swiftにこの演算子はないはず！と気になったので調べてみました。

# 気になった実際のコード
https://github.com/onevcat/Kingfisher


Kingfisherにあるサンプルコード
``` swift
let url = URL(string: "https://example.com/high_resolution_image.png")
let processor = DownsamplingImageProcessor(size: imageView.bounds.size)
             |> RoundCornerImageProcessor(cornerRadius: 20)
imageView.kf.indicatorType = .activity
imageView.kf.setImage(
    with: url,
    placeholder: UIImage(named: "placeholderImage"),
    options: [
        .processor(processor),
        .scaleFactor(UIScreen.main.scale),
        .transition(.fade(1)),
        .cacheOriginalImage
    ])
{
    result in
    switch result {
    case .success(let value):
        print("Task done for: \(value.source.url?.absoluteString ?? "")")
    case .failure(let error):
        print("Job failed: \(error.localizedDescription)")
    }
}
```
この部分です
``` swift
let processor = DownsamplingImageProcessor(size: imageView.bounds.size)
             |> RoundCornerImageProcessor(cornerRadius: 20)
```

# 結論　カスタム演算子だった

Kingfisherの中を`|>`で検索してカスタムしているコードを見つけました。
``` swift
infix operator |>: AdditionPrecedence
public func |>(left: ImageProcessor, right: ImageProcessor) -> ImageProcessor {
    return left.append(another: right)
}
```
以下ChatGPT解説
#### infix operator |>: AdditionPrecedence
この行は、`|>` という新しい中置（infix）演算子を定義しています。AdditionPrecedenceは、この新しい演算子の優先順位を定義しており、+ や - のような加算・減算の演算子と同じ優先順位になります。

#### public func |>(left: ImageProcessor, right: ImageProcessor) -> ImageProcessor
この行は、新しく定義した `|>` 演算子の動作を定義しています。この関数は、ImageProcessor 型の left と right の二つの引数を受け取り、新しい ImageProcessor を返します。

#### return left.append(another: right)
この行では、left（左側のImageProcessor）の append メソッドを呼び出して、right（右側のImageProcessor）を追加（結合）します。その結果、連鎖的に画像処理を行う新しい ImageProcessor が返されます。

このカスタム演算子のおかげで、DownsamplingImageProcessor と RoundCornerImageProcessor のような異なる画像処理を簡単に組み合わせることができます。これにより、コードが読みやすくなり、連鎖的な画像処理の記述が簡潔になります。

# おわりに
この記事が演算子についてわかりやすくまとめてくれています。ありがとうございます！

https://zenn.dev/kyome/articles/48f551222b339c

ちなみに`|>`を使わない書き方
``` swift
let processor = DownsamplingImageProcessor(size: iconImageView.bounds.size)
            .append(another: RoundCornerImageProcessor(cornerRadius: 10))
```
Pardot : メール送信に関するテスト機能

[Pardotの質問と回答をまとめに戻る](https://qiita.com/Keiji_otsubo/items/a3ccd1370697dd914723)


+ [レンダリングテスト [ Marketing -> Emails -> Tests -> 見たいメールの名前 ]](https://apex.tricorn.net/products/pardot/faq/pd-function-email-test.html)

+ [【未解決】表示テストでの文字化けについて（Plain Text）](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007Ebu7b)

最近になって、メールテンプレート作成上の表示テストで「デスクトップメールクライアント」内の「Plain Text」だけ、日本語が文字化けしてしまいます。
Laravel10 + Inertia + React + Sailでhttp://localhost/が真っ白な場合

<br>
<br>

以下環境で`http://localhost/`にアクセスすると画面が真っ白だったので、原因を調べました。
```
"@headlessui/react": "^1.4.2",
"@inertiajs/react": "^1.0.0",
"@tailwindcss/forms": "^0.5.3",
"@vitejs/plugin-react": "^4.0.3",
"autoprefixer": "^10.4.12",
"axios": "^1.1.2",
"laravel-vite-plugin": "^0.8.0",
"postcss": "^8.4.18",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"tailwindcss": "^3.2.1",
"vite": "^4.0.0"
```
<br>

コンソールには
```
GET http://0.0.0.0:5173/resources/js/app.jsx net::ERR_ABORTED 404 (Not Found)
GET http://0.0.0.0:5173/resources/js/Pages/Welcome.jsx net::ERR_ABORTED 404 (Not Found)
```
と出ていたので、調べたところ`vite.config.js`に以下を追記しなければいけないようです。

<br>

```
export default defineConfig({
    plugins: [
        laravel({
            input: "resources/js/app.jsx",
            ssr: "resources/js/ssr.jsx",
            refresh: true,
        }),
        react(),
    ],
    // ここから
    server: {
        host: "0.0.0.0",
        hmr: {
            clientPort: 5173,
            host: "localhost",
        },
    },
    // ここまで
});
```
PyAutoGUIを仮想環境(Hyper-V)で活用：効率的なプログラム実行と並行作業の実現

# 概要
本稿では、PyAutoGUIを使用している最中に他の作業が出来ない（マウス、キーボードが使用できない）問題を、仮想環境(Hyper-V)を使用することで解決する手法を示す。

# 初めに
PythonのPyAutoGUIを使って作業の自動化をしている最中、こんなことをよく考えませんか？

**「プログラム実行中も他の作業がしたい」**

一度使用した方ならご存知の通り、PyAutoGUIは自動でカーソルまたはキーボードを自動で操作し作業の自動化を行える強力なライブラリですが、その反面実行中は基本的に他の作業が出来ません。

どうすればいいか考えて見た結果以下の結論に行き着きました。

**「「　仮想環境で使えば実現可能ではないか　」」**

ということで実際に試し、結果として上手くいきましたのでその方法を残すことにしました。

# 環境
以下は私の実行環境です。
- CPU : AMD Ryzen 7 3700X 8-Core Processor 3.60 GHz
- RAM : 16.0 GB
- Local OS : Windows 11 Home 22H2
- Virtual OS : Windows 11 Enterprise Evaluation
- Hyper-V マネージャー : 10.0.2262.1
- Python : 3.11.4
- PyAutoGUI : 0.9.54

なお、PythonとPyAutoGUIは仮想環境内のバージョンです。

# 仮想環境(Hyper-V)の導入
Windowsには標準で仮想環境を使用できる**Hyper-V**というソフトが用意されています。
詳しい内容はMicrosoft公式で紹介されていますので、以下のサイトを確認してください。

https://learn.microsoft.com/ja-jp/virtualization/hyper-v-on-windows/about/

## Hyper-Vのインストール（Home Editionのみ）
Home Editionでは標準でHyper-Vがインストールされていないため、手動でインストールする必要があります。

```shell:hyperv.bat
pushd "%~dp0" 
dir /b %SystemRoot%\servicing\Packages\*Hyper-V*.mum >hyper-v.txt 
for /f %%i in ('findstr /i . hyper-v.txt 2^>nul') do dism /online /norestart /add-package:"%SystemRoot%\servicing\Packages\%%i" 
del hyper-v.txt 
Dism /online /enable-feature /featurename:Microsoft-Hyper-V-All /LimitAccess /ALL
```

上記のバッチファイルを適当な場所に作成し、管理者権限で実行してください。インストール後、再起動するとインストールが完了します。

## Hyper-Vの有効化
次にインストールしたHyper-Vを有効化します。

設定 → アプリ → 下の方にある「Windowsのその他の機能」を選択します。

すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/835335/4e46ab91-1325-9db3-15a9-b625915c655e.png)
このようなウィンドウが表示されます。

ここの
- Hyper-V
- 仮想マシン プラットフォーム

の２つにチェックを入れ、再起動してください。

:::note info
サイトによっては

**『Windowsハイパーバイザープラットフォーム』**

にもチェックを入れるようにしているところもありますが、私の場合はチェックを付けなくても問題なく動いているため、個人の判断にお任せします。
:::

再起動後、「すべてのアプリ」にある「Windowsツール」を起動すると、画像のように「Hyper-V クイック作成」と「Hyper-V マネージャー」が追加されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/835335/315f9e65-f52f-e333-93e6-d03959cc2423.png)

「Hyper-V クイック作成」を起動すると以下の画像のウィンドウが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/835335/ce1e1115-1b2d-e7e2-9b33-e880c387ad01.png)

あとは「Windows 11 開発環境」を選択し、「仮想マシンの作成」をクリックすると仮想マシンの作成が開始されます。

:::note info
Windows 11 開発環境以外にもUbuntuやISOイメージを用意すれば他のOSの仮想マシンを作成できます
:::

大体10分から20分くらいほど掛かり、仮想マシンの作成は完了します。以下は起動後の画面です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/835335/1fe7fd14-3249-2dbb-0abc-0dd6448f4cf7.png)

あとは、通常通りにPythonをインストールし、必要なモジュール、ライブラリをインストールして任意のプログラムを実行してください。

# 実行例
![Promotion_Video.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/835335/a391bcaa-5e26-4465-7977-0d5ec6dcbde0.gif)

左は私が、右は仮想環境でPyAutoGUIが自動でテキストファイルに書き込みをしています（私のタイピングが遅いのはご愛嬌）。


試したところ、locateOnScreenによる画像認識も問題なく動いているため、ローカル環境と同じようにコーディング出来るかと思います。

:::note warn
仮想マシンのウィンドウにローカルのカーソルが入ってしまうと、そちらを仮想マシンのカーソルの位置だとプログラムが誤認識してしまいます。

プログラムの実行中は仮想マシンのウィンドウ上にカーソルをのせないように気をつけてください。
:::

# おわりに
今回は、仮想環境でPyAutoGUIを動かしプログラム実行中でも他の作業が出来る方法を紹介しました。

導入が少々手間ですが、一度導入すればあとは簡単に出来るので参考にしていただけると幸いです。
ChatGPT課金してみたメモ

# 課金してみた
だってCode Interpreterとかプラグインとか使いたいじゃん？
Custom Instructionsは無償版にも展開されていったけど、プラグインをフルで使えるのは有償ならではと思うし。
金額的にもソシャゲ課金だと思えばまあこんなもんか。
APIは従量課金なのでちょっとドキドキしますが、料金キャップ（いくらまでしか使えないとあらかじめ決めておく）の設定があるから、知らないうちに突如百万円の請求が！みたいなことにはならなさそう。

# ChatGPTはGoogle先生ではない
- 2021年9月だっけ？とにかく最新の情報は出てこない（プラグインを使えばある程度いけるのだけども）
- 知ったかぶりしてしれっと嘘をつく

調べもの系はあんまり向いてないっぽい印象。検索はやはりGoogle先生にお願いするのがいいかな。

※Fine Tuningできるようになったようです。それを使えばなにかしらいけるのかも
[GPT-3.5 Turboのファインチューニングが可能になりました！(OpenAI)](https://openai.com/blog/gpt-3-5-turbo-fine-tuning-and-api-updates)

# 仕事の助けにするために向いているもの

創るもの系。
- ブレストの相手
- レビュー
いわゆる「壁打ちの壁」「殴り合いの相手」「ラバーダック」の役はほんとに適任。どれだけでも辛抱強くつきあってくれる。
- コードを書いてもらう
したいことを投げて新規に書いてもらうでも、既存のコードを投げて添削や改良をしてもらうでも。
- 分析
データを投げたら中身の解説とグラフまで書いてくれる。
グラフはPowerBIとかでも書いてくれるけど、文章でつらつら説明するのはこちらならではだと思うので、合わせ技でいけばいいと思う。
- 要約や解説
これは文章だけじゃなくて「クソみたいにネストして長ったらしいExcelの関数式」「よくわかんないくらい込み入ってるSQL文」「コメントもなくスパゲティになって目が滑るコード」とかも含まれる。てかそっちの使用頻度のほうが高い。

つまり、

検索は検索ツールにまかせる
↓
検索結果と持っている情報をあわせて
↓
ChatGPTに渡していいものを作ってもらう

みたいな役割分担？


# ChatGPTにいいものを出してもらうコツ
## キャッチボールを繰り返す
LLMって会話をするものなので、

質問を投げる
↓
回答

で終わりだともったいないなという感じ。

質問を投げる
↓
回答
↓
「その回答についてどう思いますか？改善することはある？」とさらに聞く
↓
ブラッシュアップされた回答

コンサルとかコーチングとかでやる「なぜなぜ分析」的なのを繰り返す。
繰り返すときに、回答が逸れていったり発散したりしないように、聞き返すときの言い方や事象の定義を明確にする。

## ChatGPTさん健忘対策
ChatGPTさんは、何回か会話をしているうちに、最初のほうで聞いたことや自分が言ったことを忘れがちです。
「あなたが前に言った『～』について」とか、質問にまえの回答を含めると前と矛盾したことを言い出しにくい。
引用するぶん文章が長くなるので、もしAPIでやろうとするならトークン爆上がりして課金的にアレですが……。
こちらが言うことでずっとおぼえててほしいことはCustom Instructionsに入れておく。ここに入れたものは忘れない。

あと、重要なことは最後にもういちど念を押したほうがいいです。最初に「これをやってください」と書いても、最後に再度「これをやってください」と書く。ChatGPTさんの健忘は1個の質問のなかでも発揮されます。
落語の「平林」みたいに、何か言われるとその前に言われたことを忘れちゃう的な習性があるようです。

## Custom Instructionsでやっておくこと
- ChatGPTの人格（誰になって会話してもらうか） 
- それを読ませる対象が誰か 
- どんな形式で書いてほしいか（章立てで、箇条書きで、最後にまとめを書いて、など） 

というのを規定する。もしフォーマットが決まっているなら提示しておく。
立場と対象と出力してほしいものを明確にすることで、内容が明確になって、出力される内容が安定する感じがします。
たとえば「JTCの年配の社長さんと礼儀正しいコンサル」「中学受験する小6と実直な学者先生」とかの組み合わせで、けっこうわかりやすい解説をしてくれました。 

## ファイルを投げて頼むときのコツ
- 分析のしかたまで教えてください、と頼むときには「ステップバイステップで考察して」と唱えるとよい 
- 生データ丸投げよりは、不要行を削除しておくなど多少整えてから投げるほうがいいかも 
- 文字コードをUTF-8に変えられるものなら変えておく（Shift-JISでも読んではくれる） 
- 複数のファイルを投げたいときは、質問文に「今渡したファイルにはこんなファイルが入っています」と簡単に説明するといいっぽい。 

## いい回答をしてもらう頼み方
- 「章立てで」「箇条書きで」「表にして」「JSONで返して」など、回答形式を明確に指定する。議事録のようなフォーマットがあるならフォーマットを提示する。 
- 「ステップバイステップで」「順を追って」と唱えると、回答が丁寧になる。
- 複数の案を出してほしい、長文で回答してほしいときは「何個以上」「何文字以上」と具体的に数値で示す。 
- さらに質問をして会話のキャッチボールをするためのネタとして「会話の質をより高めるために、回答の最後に、この回答についてさらにどのような質問をすればいいかの提案として、質問例を○個以上列挙してください。」と会話文の最後に書くと、質問を提案してくれる。その質問を丸パクして会話を続ければオッケー。 
- 「2000年以降に出現した概念や用語については、各章の最後に注釈として解説し、参考文書へのリンクを提示してください」と頼むと用語解説もしてくれる。ただし提示されたリンクが古かったりインチキだったりすることもあり。
- 「これは何ですか？」という質問形式でなく「これをやってください」という具体的な命令形のほうが回答の品質が良くなる。
例： 
× マキャヴェリの「君主論」とはどのような内容ですか？ 
○ マキャヴェリの「君主論」を小学6年生向けに要約してください。 
- これはちょっと半信半疑レベルですが、丁寧に喋るとChatGPTの回答内容も丁寧になる傾向がある感じがします。

# 参考リンク
[プロンプト エンジニアリングの手法(Microsoft Learn)](https://learn.microsoft.com/ja-jp/azure/ai-services/openai/concepts/advanced-prompt-engineering?pivots=programming-language-chat-completions)
超スーパー参考になる。
これより前に書いた、いろいろ試してみたことが全部載ってました。MSすげえ。
よくわかんない教材より先にこっちを読んだらいいと思います。

# 続きを書きました
[課金したメモ2](https://qiita.com/Sumire_Neko/items/d136b8546d9fa8244da1)
WebViewをScrollViewで囲むとコンテンツが表示されない

# 悩み
VStackで囲んでいるとWebViewのコンテンツが表示されていたが、

```HomeView.swift
var body: some View {
    VStack {
        headerView()
        WebView()
    }
}
```

ScrollViewにするとWebViewのコンテンツが表示されなかった。

```HomeView.swift
var body: some View {
    ScrollView {
        headerView()
        WebView()
    }
}
```

# 解決
WebViewの`.frame`を設定すれば解決した。

```HomeView.swift
var body: some View {
    ScrollView {
        headerView()
        WebView()
            .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
    }
}
```
Laravel sail のシンボリックリンクで詰まった話

## はじめに
Laravel sail を使い開発をおこなっていて、画像を登録する機能の実装をしていたところ。

画像の保存ができているのに、表示ができない？？？

と少しはまってしまいましたので解決方法を共有いたします。

## 確認したこと
**まず確認することはファイルパスが間違っていないか。**

ファイルパスを確認したところ

```java:画像path
/storage/uploads/hogehoge.png
```
正しく保存ができていました。
念の為シンボリックリンクの再作成を行いました。
```java:laravel
rm public/storage
php artisan storage:link

ls -l public
```

**次にシンボリックリンクの確認をしましょう。**

シンボリックリンクの確認のためにLaravel/Public配下を確認したところ
**Storage/uploads**もしっかりと存在していた。

## 問題があった箇所
**Laravel Sailの使用**
>Laravel Sailを使用している場合、ホストマシンとDockerコンテナの間で適切にポートがマッピングされていることを確認してください。また、Dockerコンテナ内でシンボリックリンクが正しく作成されていることも確認してください。

との記事を発見し、確認してみました
```java:laravel
./vendor/bin/sail bash
```
```java:Docker
ls -la public
```
を実行し確認します。
すると
```java:Docker
lrwxr-xr-x  1 sail dialout   63 Aug 13 17:31 storage -> /Users/hoge/project/Laravel/storage/app/public
```
となっていました！！

## 解決策
以下のコードで既存のシンボリックリンクを削除し、
新しくシンボリックリンクを作成してあげれば
```java:Docker
rm public/storage  # 既存のシンボリックリンクを削除
ln -s ../storage/app/public public/storage  # 新しいシンボリックリンクを作成
```
```java:Docker
lrwxr-xr-x  1 sail dialout   21 Aug 22 04:08 storage -> ../storage/app/public
```
と正しいシンボリックリンクを作成できました！！

開発環境での動作確認もしっかりと画像が表示されました！

## 最後に
>Dockerコンテナ内からホストマシンのファイルシステムへのシンボリックリンクは、コンテナ内で正しく機能しない場合があります。特に、Docker for Macではこのような問題がよく発生します。

という文献も見つけました。
みなさんもMacで開発していてはまった時一度確認してみてください！

さぁ！今日も元気にコード書いてこ:v_tone1:
シェルスクリプト 指定した行数分出力を削除する

# はじめに
シェルをいじってると、ウィンドウが文字だらけになって面倒くさい。
かといって `clear` で擬似的に見えなくしても、スクロールバーが豆粒みたいになって使いづらい…
と、思ってる方向け。

あとはアニメーションに使えるかも

```bash:func.sh
#! /usr/bin/env bash

clear_screen () {
    local v
    for v in $(seq 1 $1); do
        echo -n $'\e[1A'$'\e[2K'
    done
}
```

:::note warn
エラー出力とかも丸ごと消してしまうので、
プログラムがある程度完成してから使ったほうがベター
:::

## 解説
下準備として、`for` に使う引数をローカル変数として宣言しておき、他の変数と干渉しないようにしておきます。

<dl>
    <dt>Ansi Escape Sequeces
    <dd>
$'\e[1A' とかの変なやつは、 Ansi Escape Sequences (長いので、AnsiES にする) です。カーソル移動、出力文字の消去、文字色変更、色々できます。
使った記法はたった２つです。

| 記法 | 内容 |
|:-:|:-:|
| \e[nA | カーソルを`n`行上に移動 |
| \e[2K | 行全体を消去 |

他の AnsiES は、下記のリンクを参照してください。
・[ANSIエスケープシーケンス チートシート](https://qiita.com/PruneMazui/items/8a023347772620025ad6 "Qiita　AnsiEs cheat-sheet")
これを見れば、AnsiES の記法が全て理解できます。
・[bashやzshなどのターミナル上で動作するアニメーションの作り方](https://orebibou.com/ja/home/201810/20181011_001/ "bash animation")
・[bashでコマンドが無い時にやる夫が動いて煽ってくる](https://orebibou.com/ja/home/201810/20181005_001/ "yaruo animation")
AnsiES を活用した、アニメーションのプログラムです。
</dl>

関数の解説に戻ります。
AnsiES の力を借りたことにより、 「カーソルを１行上に移動し、行全体を削除する」を for文で制御することができました。

## 使用例１　指定した行数分出力を削除

```bash:test.sh
#! /usr/bin/env bash
. ./func.sh

for i in {0..9}; do
    echo 'hello world' $i
done

clear_screen 4
```

```plaintext:実行結果
hello world 0
hello world 1
hello world 2
hello world 3
hello world 4
hello world 5
```

## 使用例２　フレームを再表示するアニメーション

```bash:dance.sh
#! /usr/bin/env bash
. ./func.sh

head=' (^o^) '

body=(
    ' __|__ '
    '/  |  \'

    ' __|__/'
    '/  |   '

    '\__|__ '
    '   |  \'

    '\__|__/'
    '   |   '
)

foot=(
    '  / \  '
    ' _\ /_ '

    '  / \  '
    ' _\  \_'

    '  / \  '
    '_/  /_ '

    '  / \  '
    '_/   \_'
)


echo "$head"
for i in {0..59}; do
    rand_num_1=$(($RANDOM % 4))
    rand_num_2=$(($RANDOM % 4))

    for j in {0..1}; do
        var_name=body[$(($rand_num_1 * 2 + $j))]
        echo "${!var_name}"
    done

    for j in {0..1}; do
        var_name=foot[$(($rand_num_2 * 2 + $j))]
        echo "${!var_name}"
    done

    sleep 0.1
    if [ "$input" = 'q' ]; then break; fi
    clear_screen 4
done
```

```plaintext:実行結果
自分で実行した方がわかりやすいかもです。
```

## 謝礼

リンクを貼らせてもらった方々に感謝いたします。

https://qiita.com/PruneMazui

https://orebibou.com/ja/
wslでファイルが見つかりませんのエラーが出た時

主はプログラミング超初心者でPCの操作自体が苦手なおっさんだ。

今回はUdemyの動画を視聴しながらDjangoの環境構築をしようとしたのだが、Linuxを推奨されていたので
Ubuntuをインストールをした際に起きたアクシデントを備忘録として記載してみる。

■環境
・Windows11
・WSL2
・Ubuntu-20.04.06

■流れ
マイクロストアにてUbuntu-20.04.06をインストール
↓
windowspowershellを管理者として実行
↓
wsl --installを記載し実行
↓
Ubuntu-20.04.06が開けるようになるので開きusernameの登録
↓
パスワードを設定　←ここを適当にしてしまい、後に設定変更できなくなる。
↓
sudo apt-get install python3-venvを実行したくてもパスワードが分からなくなり困る。

こんな流れだ。
焦ってUbuntuをアンインストールし、導入し直してみたらタイトル表記の内容が・・・

調べてみると先人の方も同じことをしたようで
wsl -l　でまず自分の規定になってるディストリビューションを確認。

wslconfig /u Ubuntu-〇〇(規定)　もしくは　wsl --unregister Ubuntu-〇〇(規定)　でなんとか問題解決

ただ単にアンインストールしてもだめなのね・・・と感じた出来事
Laravelの日付表示でタイムゾーン指定のアクセサをつくる

# Laravelのアクセサは便利
## アクセサてなに?
データベースから取ってきたデータが予め加工されてると表示時にごちゃごちゃせんでええので、楽やん?っていう発想

こういうのが余計なコードを増やさずに簡単にできます
```
夏休みの終わりは2023-08-31T23:59:59+09:00です。
```
こう
```
夏休みの終わりは2023年08月31日23時59分59秒です。
```

# そんなのmodelでちょちょいとやれば簡単さ
modelにこう指定してあげて
```
protected $casts = [
　　　　'ended_at' => 'datetime:Y年m月d日H時i分s秒',
];
```

bladeでは
```
夏休みの終わりは{{ $model->ended_at }}です。
```

とすれば簡単にできちゃいます。

# あれ?9時間違う気が・・・
```
夏休みの終わりは2023年08月31日14時59分59秒です。
```

そうです、この方式だとタイムゾーンを考慮せずになんでもかんでもUTCとして解釈されます


# そこでアクセサの出番です
Laravel9からアクセサとミューテタの書き方が変わりました
```
use Illuminate\Database\Eloquent\Casts\Attribute;
public function endedAt(): Attribute
{
    return new Attribute(
        // アクセサ
        get: fn($value) => 
　　　　　　　　　　　　　　　　　　　　Carbon::parse($value)->timezone('Asia/Tokyo')->format('Y年m月d日H時i分s秒')
    );
}
```

こうするとあら不思議
```
夏休みの終わりは2023年08月31日23時59分59秒です。
```

便利ですね、アクセサ。ミューテタも便利ですのでぜひドキュメントを見ながら使って見てください。
https://readouble.com/laravel/9.x/ja/eloquent-mutators.html

ところで
```
夏休みの終わりは永遠に来ないでほしい
```
python maya export import Set

https://github.com/aizwellenstan/python_maya_export_import_set

```python
# export import aiSet
import re, os, json
import maya.cmds as cmds
import pymel.core as pm
import maya.mel as mel

def export_json(filePath, data):
    with open(filePath, 'w') as f:
        f.write(json.dumps(data, sort_keys=True, indent=4 ,separators=(',', ':')))

def read_json(filePath):
    with open(filePath) as f:
        data = json.load(filePath)
        return data
    
def get_setMember(nameRegex):
    setInfo={}
    prog = re.compile(nameRegex)
    for s in pm.ls(et=pm.nt.ObjectSet):
        if prog.match(str(s)):
            attrs = [{
                'ln':attr.longName(), 
                'sn':attr.shortName(), 
                'at':attr.get(typ=True), 
                'uac':attr.isUsedAsColor(),
                'nn':pm.attributeName(attr, n=True),
                'value':attr.get()} for attr in s.listAttr(ud=True)]
            setInfo[str(s)] = {'attribute':attrs}
            setInfo[str(s)].update( {'member': [str(s) for s in s.members()]} )
    return setInfo

def rebuild_setMember(set_file):
    set_data = read_json(set_file)
    for k in set_data.keys():
        if pm.objExists(k):
            pm.delete(k)
        s = pm.sets(pm.ls(set_data[k]['member']), n=k)
        for attr in set_data[k]['attribute']:
            value = attr.pop('value')
            pm.addAttr(s, **attr)
            s.attr(attr['ln']).set(value)

set_data = get_setMember('set_*')


filePath = r'D:\set_member.json'

#export set
export_json(filePath, set_data)

#import set
#rebuild_setMember(filePath)
```