OmniAICreator/Qiita-1.07M huggingface dataset:
IBM i の実用的なSQLサンプルの隠し場所と IP,ポート,ホスト名,ジョブ名取得サンプル

IBM i はここ数年、どんどんどんSQLが使える機能が増えています。
レガシーなDB DDL,DMLのほか、IBM i サービスのように運用管理面でもSQLを多用（標準化）できる機能が増えてきました。

## IBM i SQLサンプル隠し場所は2つ
IBM i はおよそ半年に1回、TR(テクノロジー・リフレッシュ）で機能拡張されていますが、IBM i サービスやDB周りのSQL拡張は毎回必ず、相当数が拡張されています。

## 問：新しい、使えるIBM i サービス、DDL,DMLなどSQLサンプルはどこに？

***こたえ：ACS, Navigator for i から探せます***

具体的には、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/69adc7be-c9d5-e21b-dd4f-f2cfb09197b3.png)

■今回ご紹介するサンプル一覧表


| どこから？ | SQLのカテゴリ | SQLサンプル | 取得できる情報 | |  |
|:-:|:-:|:-:|:-:|:-:|:-:|
| ACS  | ビルトイングローバル変数 | VALUES(SYSIBM.CLIENT_IPADDR) | クライアントの "IP" |   |   |
| ACS  | ビルトイングローバル変数 | VALUES(SYSIBM.CLIENT_PORT) |      "     ポート番号   " |   |   |
| ACS  | ビルトイングローバル変数 | VALUES(SYSIBM.CLIENT_HOST); | "ホスト名" |   |   |
| ACS  | ビルトイングローバル変数 | VALUES(QSYS2.JOB_NAME); | "ジョブ名" |   |   |


## ACSのSQLサンプル

ACSのSQLサンプルにたどりつくには・・・
***①SQLスクリプトの実行 をクリック***
***②編集メニュー -> 例 -> 例から挿入　をクリック***
下記のようなSQLサンプル集画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/7e8dcaf0-9d48-8557-b335-308812e378b1.png)

左上のカテゴリーを見ると上3つは一般的なDB操作（DDL,DML,DCL）ですね。それ以外にもIBM i サービス、Db2 for iサービス、SYSTOOLSなどこれまで紹介したことのある機能名が並んでいます。
Db2 Mirror for i の運用サンプルほかもあるようです。

以下でいくつか例をご紹介します。

## ACS SQLサンプル カテゴリー：Built-in Global Variables (組込みグローバル変数)

### クライアントIPアドレス
***SQLを実行するクライアントのIPアドレス、ポート番号を取得***
```
VALUES(SYSIBM.CLIENT_IPADDR);
VALUES(SYSIBM.CLIENT_PORT);
```
コメント：IBM i 7.2以降で利用可能
実行例（IPアドレス）：
※背景のプロンプト画面はIPCONFIGコマンド実行結果です。末尾IPが150で同一です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/98faebf6-9ad4-582f-f7eb-97493148f166.png)


### クライアントホスト名
***SQLを実行するクライアントのホスト名を取得***
```
VALUES(SYSIBM.CLIENT_HOST);
```
コメント：IBM i 7.2以降で利用可能
実行例：
※背景のプロンプト画面はIPCONFIGコマンド実行結果です。ホスト名が同一です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/5a0b05cb-839e-615f-e75d-e7c7f24b503b.png)


### クライアントのジョブ名
***SQLを実行するクライアントのジョブ名を取得***
```
VALUES(QSYS2.JOB_NAME);
```
コメント：IBM i 7.2以降で利用可能
実行例：
※SQL実行結果と、SQLスクリプト実行画面の最下行のメッセージ欄のジョブ名が同一です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/1846d78f-20be-c57f-fb98-f20763b31943.png)





[つづきはこちらです。](https://qiita.com/gomAnomalocaris/items/b4fcf04f63d76c2e120a)
既存チームにジョインするときに気をつけていること

## 最初の心構え

顧客と伴走するようなプロジェクトの場合は、すでに存在するチームに途中参加することがあります。これは中途採用で入社するケースに状況として近いかもしれません。

このときに意識していることがいくつかあります。

### 感謝と尊敬の念を忘れない

新参者からすると、これまでの仕事とやり方が異なるかもしれません。
しかしやり方は違えど、これまでの仕事を進めてきたこと、今の仕組みを構築してきたことに尊敬を念をもつべきだと考えています。

### 様々な要因があっての現状と認識する

すぐに思いつく、「こうしたらいいのに」は既存のメンバーにとっては周知のことだったりします。様々な外的要因や制限において、それが難しかったり現状においては最適解でないことがあります。

## 既存のワークに悪影響を与えたり引っ掻き回すようなことがないように

エンジニアリングには「こうあるべき」という考え方や教科書的な考え方などがあります。
ただし、実務は様々な要素や複雑な条件、ビジネスとしてのミッションがあるため、とるべき選択肢が状況に応じて様々です。
実情を知らない立場から「こうあるべき」という強い押しつけによって引っ掻き回すようなことがないようにと意識しています。

## 過去の経験や知見が活かせる可能性があれば提案する

一方で、過去の経験や知見を活かせる可能性があれば、中長期的に取り組むべきことかもしれません。
やるべき価値があると考える場合はその道筋を立てると良いでしょう。

しかし新しいことを学んだり、取り入れたり、慣れた方法以外のやりかたで作業をするのは痛みや苦痛が伴うと理解しています。
また、これまでうまく不満なくやれていたことを変えて何かトラブルが起きるかもしれません。

例えば、

* GUI中心ではなく、CUIで作業を行う
* CI/CDで自動化を整備する
* 作業環境をコード化して作業者の環境を統一する

なぜ、それを実施するのか、どのようなメリットがあるのか、それを採用したあとの景色はどうなるか。

技術的なサポートが求められるプロジェクトにおいては、なるべく沢山の頻度で少しずつ、何度もお話するように心がけています。

> 誰も失敗したいとは思っていない。その行動をしたら、最後にばかを見ることなく成功できるだろうと、根拠を持って感じられる必要がある。自己効力感（self-efficacy）ともいう。
> 
> **行動を変えるデザインより**

> 人は万事うまくいっていることには簡単に参加できるのです。未来を少し垣間見せるだけで、みんな集まってくるのです
> 
> **達人プログラマー（第2版）より**

## よき触媒になりたい

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426622/8767fb85-0437-fcbd-f9c6-83a7e7a3dfc2.png)

チームにおいて良い変化をもたらす触媒になりたいと考えています。
仕事はよい化学反応を観測できたときにやりがいや楽しさを感じられるものだと思います。

この化学反応を起こす仲間を探しています。興味のある方は[コーポレートサイト](https://www.add-more.co.jp/recruit/engineer/)または[Wantedly](https://www.wantedly.com/companies/add-more)からご応募ください。
闘魂Elixir ーー AtCoder Beginner Contest 357(B)をElixirで楽しむ

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>

<b><font color="red">$\huge{闘魂とは己に打ち克つこと。}$</font></b>
<b><font color="red">$\huge{そして闘いを通じて己の魂を磨いていく}$</font></b>
<b><font color="red">$\huge{ことだと思います}$</font></b>


# はじめに

[AtCoder Beginner Contest 357](https://atcoder.jp/contests/abc357)を[Elixir](https://elixir-lang.org/)で解いてみます。

[AtCoder](https://atcoder.jp/)を解くのが趣味で、休憩時間に解いているという若い人がいて、それってすごい意識の高い休憩時間の過ごし方だと思って、私も真似してみることにしました。


# [AtCoderをElixirでやってみる](https://zenn.dev/torifukukaiou/articles/ac84c87736ceebf4da01)

入力の読み取り方や解答の作り方は、別の記事にまとめています。


https://zenn.dev/torifukukaiou/articles/ac84c87736ceebf4da01

ご参照くださいませ。

[Elixir](https://elixir-lang.org/)で[AtCoder](https://atcoder.jp/)を楽しむためには、エントリポイントを`Main.main/0`にする必要があります。つまり`Main`モジュールを作って、その中に`main/0`関数を定義するわけです。

# [B - Uppercase and Lowercase](https://atcoder.jp/contests/abc357/tasks/abc357_b)

問題はリンク先をご参照くださいませ。
私の解答を貼っておきます。


<details><summary>私の解答</summary>

_問題文を読んでいることを前提にひとこと解説をしておきます。_

入力文字列を[Charlists](https://hexdocs.pm/elixir/List.html#module-charlists)にしておいて、各要素が小文字か大文字かなのかは、`?a`や`?z`、`?A`、`?Z`と判定すればうまくいきます。

```elixir
defmodule Main do
  def main do
    s =
      IO.read(:line) |> String.trim()

    solve(s)
    |> IO.puts()
  end

  def solve(s) do
    lower = s |> String.to_charlist |> Enum.count(fn n -> ?a <= n and n <= ?z end)
    upper = s |> String.to_charlist |> Enum.count(fn n -> ?A <= n and n <= ?Z end)

    if lower > upper, do: String.downcase(s), else: String.upcase(s)
  end
end
```




</details>




---

# さいごに

[AtCoder Beginner Contest 357](https://atcoder.jp/contests/abc357)を[Elixir](https://elixir-lang.org/)で解くことを楽しみました。

あなたのお好きなプログラミング言語でお楽しみください。

---


**闘魂**とは、  **「己に打ち克つこと。そして闘いを通じて己の魂を磨いていくことである」** との猪木さんの言葉をそのまま胸に刻み込んでいます。
知っているだけで終わらせることなく、実行する、断行する、一歩を踏み出すことを自らの行動で示していきたいとおもいます。
**アントニオ猪木さんのメッセージから元氣をもらったものとして、それを次代に語り継ぎ、自分自身が「闘魂」を体現するものでありたいとおもいます。**

---

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>
<b><font color="red">$\huge{１、２、３ ぁっダァー！}$</font></b>
google meet カメラが見つからないの対処法を探す

Googlemeetでリモート面接した際に「カメラが見つからない」と表示されてカメラが使えなかったので対処法を調べる。ちなみに前日にもGooglemeetを使ったがその時はカメラ機能が使えた。

参考

https://support.google.com/meet/thread/212610574


# 対処
キャッシュを削除してみる。

# 結果
無事カメラが使えるようになったのでキャッシュが原因だったと思われる。

キャッシュので起ること
①古い内容が表示される場合がある
②キャッシュが貯まりすぎると動作が遅くなることがある

googlemeetのカメラ機能を調べた際に他のカメラが使用中だと使えないこともあるそうなので①で表示されていると判断されたか、②で動作が正常に行われなかったかのいずれかと思われる。
【シンプルなWebページ統合】Hello Worldをウィジェット化してwebページに統合してみる

## 背景
自分の[金融メディア](https://moneychat.life/media/)をもっとカスタマイズできないかと思って、独自でウィジェットを作り、それを組み込んで、ゆくゆくはbotとかを統合しようという企み。

## やること

ウェブページに外部スクリプトを統合することで、インタラクティブな要素を簡単に追加することができるっぽい。
しかし、スクリプトの読み込みと実行に問題が発生することがある。
そこで本記事では、"Hello World" を表示するだけのシンプルなウィジェットを例に、スムーズに統合し、デバッグする方法を解説する。

## 気をつけるべきこと
- DOMの完全な読み込み
スクリプトがDOMにアクセスする前に、DOMが完全に読み込まれていることを確認する。
- スクリプトの非同期ロード
非同期にスクリプトをロードする場合、その順序と実行タイミングを確認する。
- エラーハンドリング
スクリプトの読み込みや実行中のエラーを適切にキャッチし、デバッグ情報を提供する。

例:

```html:index.html 任意のサイトに組み込む
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sample Page</title>
</head>
<body>
    <!-- Hello Worldウィジェットを表示するためのコンテナ -->
    <div id="hello-world-widget"></div>

    <!-- Hello Worldウィジェットのスクリプト -->
    <script>
      document.addEventListener('DOMContentLoaded', function() {
        const script = document.createElement('script');
        script.src = 'https://example.com/hello-world-widget.js'; // スクリプトのURLを指定
        script.async = true;
        console.log('Script element created:', script);
        script.onload = function() {
          console.log('Hello World widget script loaded.');
          try {
            window.initializeHelloWorldWidget({
              containerId: 'hello-world-widget'
            });
          } catch (e) {
            console.error('Error in initializeHelloWorldWidget:', e);
          }
        };
        script.onerror = function() {
          console.error('Failed to load Hello World widget script');
        };
        document.body.appendChild(script);
        console.log('Script element appended to body');
      });
    </script>
</body>
</html>
```

スクリプトが実行される前に、DOMが完全に読み込まれるのを待つために、DOMContentLoaded イベントを使用している。


## スクリプト
任意のサイトから呼び出す。

```js:hello-world-widget.js
function initializeHelloWorldWidget(config) {
  console.log('Initializing Hello World widget with config:', config);

  const container = document.getElementById(config.containerId);
  if (!container) {
    console.error('Container not found:', config.containerId);
    return;
  }

  container.innerHTML = `
    <div id="helloWorldContainer" style="border: 2px solid #007bff; border-radius: 10px; padding: 10px; background-color: white; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); width: 300px; margin: 20px auto;">
      <div id="helloWorldHeader" style="text-align: center; margin-bottom: 10px;">
        <h2>Hello World</h2>
      </div>
      <div id="helloWorldContent">
        <p style="margin: 0; padding: 10px; font-size: 16px; color: #333;">Hello, welcome to our site!</p>
      </div>
    </div>
  `;

  console.log('Hello World widget initialized in the container.');
}
```


## お疲れ様でした。
わからないところ、間違っているところ、もっといい方法がある場合は、コメントでもDMでも教えてください。
エンタープライズソフトウェア開発とソフトウェア製品開発の重要性

はじめに
現代のビジネス環境では、効率的な業務運営が求められます。エンタープライズソフトウェア開発とソフトウェア製品開発は、企業の成長と競争力を維持するために不可欠です。本記事では、それぞれの開発の重要性と特徴について説明します。
エンタープライズソフトウェア開発とは？
[エンタープライズソフトウェア開発](https://newwave-solutions.co.jp/enterprise-software-development/)は、企業の業務プロセスを支援するソフトウェアを設計、開発、導入するプロセスです。代表的なソフトウェアには、ERP、CRM、HRMなどがあります。
特徴
カスタマイズ性：企業の特定のニーズに合わせてカスタマイズ可能。
統合性：企業内のシステムやデータベースと統合できる。
スケーラビリティ：企業の成長に応じてシステムを拡張可能。
メリット
エンタープライズソフトウェア開発は、業務プロセスの自動化と効率化により、コスト削減と生産性向上が期待できます。
ソフトウェア製品開発とは？
[ソフトウェア製品開発](https://newwave-solutions.co.jp/software-product-development/)は、市場やユーザーグループ向けの商業用ソフトウェアを設計、開発、リリース、メンテナンスするプロセスです。
特徴
市場調査：ターゲット市場やユーザーのニーズを詳細に調査。
ユーザーエクスペリエンス（UX）：使いやすく満足度の高い製品を提供。
継続的な改善：ユーザーのフィードバックや市場の変化に対応して改善。
メリット
広範なユーザーベースに対応でき、成功した製品は大きな収益を生む可能性があります。
違い
カスタマイズ vs. 汎用性
エンタープライズソフトウェアは特定企業向けにカスタマイズされ、ソフトウェア製品は多くのユーザーに対応できる汎用性を持ちます。
導入とメンテナンス
エンタープライズソフトウェアは詳細な計画とカスタマイズが必要で、導入後のメンテナンスも重要です。ソフトウェア製品は簡単にインストールでき、クラウドベースの製品では開発者がメンテナンスを行います。
費用と収益モデル
エンタープライズソフトウェア開発は高額なプロジェクトベースの費用がかかりますが、特定企業向けに特化したソリューションを提供します。ソフトウェア製品開発は販売量に応じた収益が見込めます。
まとめ
エンタープライズソフトウェア開発とソフトウェア製品開発は、それぞれのニーズに応じたアプローチが求められます。どちらも企業の競争力を維持するために重要な役割を果たします。これらの開発に精通することで、企業は柔軟かつ効果的なソリューションを提供できます。
Salesforce開発会社とSalesforceソフトウェアエンジニアの魅力

はじめに
現代のビジネス環境で顧客関係管理（CRM）は企業の成功に欠かせません。中でも、Salesforceは世界中で高い評価を受けています。本記事では、Salesforce開発会社とSalesforceソフトウェアエンジニアの魅力について紹介します。
Salesforce開発会社とは？
[Salesforce開発会社](https://newwave-solutions.co.jp/salesforce-development-company/)は、Salesforceプラットフォームを利用して企業のビジネスプロセスを効率化するソリューションを提供する会社です。主なサービスには以下があります。
主なサービス
カスタムアプリケーションの開発：企業の特定のニーズに合わせたアプリケーションを開発。
Salesforce導入サポート：新規導入や既存システムからの移行をサポート。
統合とカスタマイズ：他の業務アプリケーションとの統合とカスタマイズ。
保守とサポート：システムの安定稼働を維持する保守サービス。
Salesforceソフトウェアエンジニアの役割
[Salesforceソフトウェアエンジニア](https://newwave-solutions.co.jp/salesforce-software-engineer/)は、Salesforceプラットフォームを利用して企業の業務プロセスを効率化するソリューションを開発します。主な業務内容は以下の通りです。
主な業務内容
要件定義と設計：クライアントのビジネスニーズに基づいてシステムの要件を定義・設計。
開発とカスタマイズ：ApexやVisualforce、Lightningコンポーネントを使用してカスタムアプリケーションを開発。
テストとデプロイ：開発したアプリケーションのテストとデプロイ。
ユーザートレーニングとサポート：システムの使用方法に関するトレーニングとサポート。
Salesforce開発会社の魅力
Salesforce開発会社は、以下の点で魅力的です。
高い専門性と技術力
Salesforceプラットフォームに関する深い知識と豊富な経験を持ち、複雑なニーズに対応。
カスタマイズと柔軟性
クライアントのビジネスプロセスに合わせたカスタマイズを提供。
最新技術の活用
Salesforceの最新技術を迅速に取り入れ、最適なソリューションを提供。
Salesforceソフトウェアエンジニアのキャリアパス
Salesforceソフトウェアエンジニアのキャリアは、成長の機会が豊富です。
初級エンジニア
基本的な開発スキルとプラットフォームの理解を深め、簡単なカスタマイズやアプリケーション開発を担当。
中級エンジニア
より複雑なプロジェクトを担当し、Lightningコンポーネントの開発やシステム統合を行う。
上級エンジニア
プロジェクトのリーダーとして、チームを指導し、プロジェクト全体のアーキテクチャ設計を担当。
アーキテクト
企業全体のシステムアーキテクチャを設計し、技術戦略を策定。
まとめ
Salesforce開発会社とSalesforceソフトウェアエンジニアは、企業の業務効率化と顧客満足度向上に貢献しています。この分野でのキャリアは非常に魅力的で、多くの成長の機会が存在します。興味を持っている方は、この分野でのスキルを磨き、キャリアを築くことを検討してみてください。
C_TS422_2021 SAP Certified Application Associate SAP S/4HANA Production Planning and Manufacturing対策（5/100）

【5日目】 
トピック1：SAPS/4HANAサプライチェーン計画の概要（5/6）

≪問題5≫ 
資材所要量計画と能力計画に対する説明で正しいものはどれですか。
▢資材所要量計画では、品目の内部調達と外部調達の両方を計画する。能力計画では、作業区の利用可能能力に基づいて作業を計画する。
▢資材所要量計画では、品目の内部調達と外部調達の両方を計画する。能力計画では、作業区の独立所要量に基づいて作業を計画する。
▢資材所要量計画では、品目の内部調達を計画する。能力計画では、作業区の利用可能能力に基づいて作業手順を計画する。
▢資材所要量計画では、品目の内部調達を計画する。能力計画では、作業区の独立所要量に基づいて作業手順を計画する。

≪解答≫ 
█資材所要量計画では、品目の内部調達と外部調達の両方を計画する。能力計画では、作業区の利用可能能力に基づいて作業を計画する。
▢資材所要量計画では、品目の内部調達と外部調達の両方を計画する。能力計画では、作業区の独立所要量に基づいて作業を計画する。
▢資材所要量計画では、品目の内部調達を計画する。能力計画では、作業区の利用可能能力に基づいて作業手順を計画する。
▢資材所要量計画では、品目の内部調達を計画する。能力計画では、作業区の独立所要量に基づいて作業手順を計画する。

≪解説≫
◆資材所要量計画の開始時には、まず正味所要量の計算が実行されます。その後、正味所要量に対してロットまとめ方式を考慮して入庫要素の数量が算出されます。次に、品目タイプに割り当てられた調達タイプを用いて、その品目を内製するか外部から調達するかを決定します。
◆作業区においては、作業の能力所要量を計算するための利用可能能力と計算式が定義されます。そして、作業区は作業手順の作業に割り当てられます。計画手配や製造指図は、作業手順に基づいて登録されます。作業区の計算式に基づき、指図に対してリードタイム日程計画が実行され、作業に対する能力所要量が登録されます。
【AWS】社内からAWS Consoleに接続する際にファイアウォールのホワイトリストに登録するべきURL

## 経緯
「.aws.amazon.com」をホワイトリストに登録したが、ところどころエラーが発生する。
特に検索欄が機能しない。

## 原因
ブラウザの開発者ツール(F12)で使用されているURLをチェックしていたが、公式トラブルシューティングに登録するべきURLが記載されていることを発見。
参考：[トラブルシューティング - ページが正しく読み込まれない -](https://docs.aws.amazon.com/ja_jp/awsconsolehelpdocs/latest/gsg/troubleshooting.html#page-not-loading)

## 解決
以下のURLを全てホワイトリストに登録することで、問題なく接続できることが確認できた。
> .a2z.com
.amazon.com
.amazonaws.com
.aws
.aws.com
.aws.dev
.awscloud.com
.awsplayer.com
.awsstatic.com
.cloudfront.net
.live-video.net
【bash】echoしつつコマンド実行する関数

bash内にコマンドを記載する簡易版
```bash
#!/bin/bash
echommand () {
  echo Command: $@ >&2
  "$@"
  echo -------------------------------------
}

echommand aws s3 ls
```

コマンドを外部ファイルに記載し、結果をログファイルに出力するバージョン

```bash
#!/bin/bash
echo -n Please enter the log file name : 
read FILE
echommand () { 
  if [ "$1" = "echo" ]; then
    "$@" 2>&1 | tee -a $FILE
  else
    echo Command: $@ 2>&1 | tee -a $FILE
    "$@" 2>&1 | tee -a $FILE
  fi
  echo -------------------------------------
}
while read line
do
  echommand ${line}
done < "commandlist"
```
【shell】シェルスクリプトで外部ファイル読み込み時にコメントアウトに対応させる

```test.conf
#コメントアウト
hoge1 hoge2 hoge3
foo1 foo2 foo3
```

```shell
#!/bin/sh

# Configファイル
CONF="test.conf"

while read -a line; do
    echo \$line: $line
    echo \${line[*]}: ${line[*]}
    echo \${line[0]}: ${line[0]}
    echo \${line[1]}: ${line[1]}
done < <(grep -v '#' ./$CONF)
```

応答
```sh
$line: hoge1
${line[*]}: hoge1 hoge2 hoge3
${line[0]}: hoge1
${line[1]}: hoge2
$line: foo1
${line[*]}: foo1 foo2 foo3
${line[0]}: foo1
${line[1]}: foo2
```
システムデザインの概念（part5: Proxy&Load Balancing）

プロキシとロードバランシングについて解説します。プロキシ（代理）は、特定の通信プロトコルと混同しないように注意が必要です。

### プロキシ（代理）

**プロキシサーバ** は、ネットワークの仲介者として機能します。これにより、IPアドレスの隠蔽や、コンテンツのキャッシュを通じた効率の向上、さらにはネットワークトラフィックの制御も可能です。

- **フォワードプロキシ**：クライアントのために動作し、インターネット上でクライアントを匿名化します。

- **リバースプロキシ**：ターゲットサーバのために動作し、クライアントではなくサーバを匿名化します。リバースプロキシはインターネットとサーバの間に配置され、フォワードプロキシとは異なる方法で動作します。リバースプロキシはクライアントからのリクエストを受け取り、それを適切なサーバに転送します。

### リバースプロキシの利点

リバースプロキシの主な利点は、以下の通りです：

1. **負荷分散**：リバースプロキシは、複数のサーバ間でのリクエストの分散を通じて、サーバの負荷を管理します。
2. **DDoS攻撃の防止**：分散型サービス拒否 (DDoS) 攻撃からサーバを保護します。
3. **キャッシュ**：要求されたコンテンツをキャッシュすることで、レスポンスを迅速に提供し、元のサーバの負荷を軽減します。
4. **CDN（コンテンツデリバリーネットワーク）**：CDNは、リバースプロキシの一例であり、クライアントが直接オリジンサーバにアクセスする代わりに、リバースプロキシ（CDN）が要求を処理します。

### ロードバランサ

リバースプロキシの一つの例として、**ロードバランサ** が広く認識されています。ロードバランサは、クライアントとサーバの間に位置し、通信の仲介者として機能します。

#### ロードバランシングの方法

以下は、一般的なロードバランシングの方法です：

1. **ラウンドロビン（Round Robin）**：リクエストを順番に各サーバに割り当てる方法です。この方法は簡単で効率的ですが、サーバの実際の負荷を動的に調整することはできません。

2. **最小接続数（Least Connections）**：現在の接続数が最も少ないサーバに新しいリクエストを割り当てる方法です。これにより、サーバの負荷が均等に保たれます。

3. **最短応答時間（Least Response Time）**：応答時間が最も短いサーバにリクエストを割り当てる方法です。システム全体の応答時間を最小化するのに効果的です。

4. **IPハッシュ（IP Hash）**：クライアントのIPアドレスに基づいてリクエストを特定のサーバに割り当てる方法です。これにより、同じクライアントのリクエストが常に同じサーバに割り当てられ、セッションの一貫性が保たれます。

5. **加重ラウンドロビン（Weighted Round Robin）**：各サーバの性能に応じてリクエストを分配する方法です。より高性能なサーバにはより多くのリクエストが割り当てられます。

6. **加重最小接続数（Weighted Least Connections）**：サーバの性能に基づいて、接続数が最も少ないサーバにリクエストを割り当てる方法です。これにより、柔軟な負荷分散が可能となります。

7. **DNSベースのロードバランシング（DNS-based Load Balancing）**：リクエストのドメイン名に基づいてトラフィックを異なるサーバクラスターにルーティングする方法です。

8. **コンテンツに基づくロードバランシング（Content-aware Load Balancing）**：リクエストの内容（URLやヘッダーなど）に基づいてトラフィックを分配する方法です。

9. **アダプティブロードバランシング（Adaptive Load Balancing）**：サーバのリアルタイムの負荷と性能指標に基づいて、動的にロードバランシング戦略を調整する方法です。

10. **四層および七層ロードバランシング（Layer 4 and Layer 7 Load Balancing）**：四層（TCP/UDP層）では、転送層の情報に基づいてロードバランシングを行います。一方、七層（HTTP層）では、アプリケーション層の情報（HTTPリクエストの内容やURLなど）に基づいてより詳細な制御を行います。

### 一貫性のあるハッシュ

1. **ハッシュロードバランシング**：リクエストをサーバに分配する際に、ハッシュ関数を使用して一意の識別子（IPアドレス、ユーザーID、リクエストIDなど）をサーバにマッピングします。しかし、サーバの追加や削除があるときに、すべてのリクエストの再割り当てが必要になるため、不安定な負荷分散を引き起こす可能性があります。

2. **一貫性ハッシュの原理**：一貫性ハッシュは、サーバの追加や削除時にも、リクエストとサーバのマッピングを安定させます。ハッシュ関数とリング構造を使用して、均等な負荷分散を実現します。

3. **サーバ故障の処理**：一貫性ハッシュでは、サーバが故障した場合、そのサーバが処理していたリクエストは、時計回りに次の利用可能なサーバに再割り当てされます。

4. **モジュロ演算**：一貫性ハッシュでは、結果のハッシュ値をリング上の利用可能な位置にマッピングするためにモジュロ演算を使用します。これにより、オーバーフローを防ぎ、リクエストの均等な分布が促進されます。

5. **一貫性ハッシュの応用**：一貫性ハッシュは、コンテンツデリバリーネットワーク（CDN）やデータベースのような、特定のユーザーを同じキャッシュサーバやデータベースサーバにルーティングする必要があるシナリオに適しています。

6. **他の負荷分散技術との比較**：一貫性ハッシュは、キャッシュの効果的な利用などの利点を提供しますが、単純なシナリオではラウンドロビンのような他の技術も有効です。

一貫性ハッシュは、分散システムにおいて安定した効率的な負荷分散を提供し、さまざまなアプリケーションにおいて貴重な技術です。

### まとめ
この内容を通じて、プロキシとロードバランシングの違いと各技術の特徴について理解を深めていただければ幸いです。
闘魂Elixir ーー AtCoder Beginner Contest 357(A)をElixirで楽しむ

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>

<b><font color="red">$\huge{闘魂とは己に打ち克つこと。}$</font></b>
<b><font color="red">$\huge{そして闘いを通じて己の魂を磨いていく}$</font></b>
<b><font color="red">$\huge{ことだと思います}$</font></b>


# はじめに

[AtCoder Beginner Contest 357](https://atcoder.jp/contests/abc357)を[Elixir](https://elixir-lang.org/)で解いてみます。

[AtCoder](https://atcoder.jp/)を解くのが趣味で、休憩時間に解いているという若い人がいて、それってすごい意識の高い休憩時間の過ごし方だと思って、私も真似してみることにしました。


# [AtCoderをElixirでやってみる](https://zenn.dev/torifukukaiou/articles/ac84c87736ceebf4da01)

入力の読み取り方や解答の作り方は、別の記事にまとめています。


https://zenn.dev/torifukukaiou/articles/ac84c87736ceebf4da01

ご参照くださいませ。

[Elixir](https://elixir-lang.org/)で[AtCoder](https://atcoder.jp/)を楽しむためには、エントリポイントを`Main.main/0`にする必要があります。つまり`Main`モジュールを作って、その中に`main/0`関数を定義するわけです。

# [A - Sanitize Hands](https://atcoder.jp/contests/abc357/tasks/abc357_a)

問題はリンク先をご参照くださいませ。
私の解答を貼っておきます。


<details><summary>私の解答</summary>

_問題文を読んでいることを前提にひとこと解説をしておきます。_

入力値を順繰り引いていって、0以上を何番目まで保てるかを算出する問題です。[Enum.reduce_while/3](https://hexdocs.pm/elixir/Enum.html#reduce_while/3)を骨格に使えばよいでしょう。

```elixir
defmodule Main do
  def main do
    [_n, m] =
      IO.read(:line) |> String.trim() |> String.split(" ") |> Enum.map(&String.to_integer/1)
    h_list = IO.read(:line) |> String.trim() |> String.split(" ") |> Enum.map(&String.to_integer/1)

    solve(h_list, m)
    |> IO.puts()
  end

  def solve(h_list, m) do
    Enum.with_index(h_list, 1)
    |> Enum.reduce_while({m, 0}, fn {h, index}, {acc, num} ->
      do_solve(acc - h, index, num)
    end)
    |> elem(1)
  end

  defp do_solve(m, _index, num) when m < 0, do: {:halt, {m, num}}
  defp do_solve(m, index, _num), do: {:cont, {m, index}}
end
```




</details>




---

# さいごに

[AtCoder Beginner Contest 357](https://atcoder.jp/contests/abc357)を[Elixir](https://elixir-lang.org/)で解くことを楽しみました。

あなたのお好きなプログラミング言語でお楽しみください。

---


**闘魂**とは、  **「己に打ち克つこと。そして闘いを通じて己の魂を磨いていくことである」** との猪木さんの言葉をそのまま胸に刻み込んでいます。
知っているだけで終わらせることなく、実行する、断行する、一歩を踏み出すことを自らの行動で示していきたいとおもいます。
**アントニオ猪木さんのメッセージから元氣をもらったものとして、それを次代に語り継ぎ、自分自身が「闘魂」を体現するものでありたいとおもいます。**

---

<b><font color="red">$\huge{元氣ですかーーーーッ！！！}$</font></b>
<b><font color="red">$\huge{元氣があればなんでもできる！}$</font></b>
<b><font color="red">$\huge{１、２、３ ぁっダァー！}$</font></b>
【GAS】メールからスプレッドシートへデータ抽出：数に制限が？

Webサービスを提供している会社に務める私は、前日のサービス利用状況などについて、毎朝システムから大量の自動メールを受信している。
提供サービスも複数あり、売上/仕入れ関連のレポートが分かれていて、それを手動でGoogleスプレッドシートへ入力するのが、非常に面倒な上、きっとどこかでミスをしている不安にも、常に取り憑かれていた。

自動化したい！

と思い、ある日思い立って、GASを触ってみたら、サクッと半日で、受信したメールからデータを取り出して、各項目ごとにスプレッドシートへ入力してくれるように！

トリガーを午前1時に設定することで、日付が変わったら自動送信されるメールを、朝にはスプレッドシートへ入力してくれている状態にできて、大満足。

それまでは、手動で一部のデータだけを記録していたので、折角の機会に、と、メールのデータ全てを取り込めるようにも設定。なので、過去メールも全てスプレッドーシートへ取り込むぞ…と意気込んだのですが、残念ながら、3年超えの日次メール全ては取り込めない。

[こちらの記事](https://qiita.com/kakakaori830/items/84a7dcba2d6119ed320a)にお世話になったのですが、結局業務改善に取り組んでいるため、原因特定までの時間は取れず「なんらかの制限にひっかかったんだろう」程度に理解することとなった。

そこで、少々面倒だったけれども、受信箱へ戻り、一括して該当のメールにつけていたラベルを剥がし、年分けラベルに変更。
1年前→コピーした別のスプレッドシートで、GASのメールのラベル名を変更して実行
2年前→…
3年前→…
というように、ファイルは複数になったけれど、無事、全ての過去メールをスプレッドシートに移すことに成功！

他のレポートメールも同様にスプレッドシートを作ってDB化し、ゆくゆくはひとつのUIで全てのデータ操作をしたいなぁ。
Nginx Unit 413 Payload Too Large

構成はNginx + Unitにしており，Nginxのclient_max_body_sizeの設定値以下のファイルを送信しているのにも関わらず413となる．

Unitの公式を見ると
https://unit.nginx.org/configuration/


max_body_sizeが設定できることが分かった．
初期値は8MBのようだ．

128MBまで上げる
```json
{
	"settings": {
		"http": {
			"max_body_size": 134217728,
			...
		}
	},
	...
}
```

設定を適用
```json
{
	"success": "Reconfiguration done."
}
```

忘れずにunitdを再起動して413が解消された．
GitHub Actionsで動いているCIの状況をSlackで確認する

# はじめに

HRBrainで新卒でエンジニアをしているNubです。

プロダクトチームに配属されてから、様々なタスクに関わるようになり、Pull Request(PR)を作り、チームにレビュー依頼を出すことが増えました。

HRBrainでは、PRに対してGitHub ActionsでCIが動いており、テストの検証等が行われています。

今回はCIとレビュー依頼について、自分の失敗と反省、対応策を書いていこうと思います。

# Slackに通知したいと思ったきっかけ

当たり前なのですが、CIが通過してからチームに対してレビュー依頼を出すべきです。ですが、自分はCI通過前にレビュー依頼を出していました。

理由としては３つあり、こんな感じです。

1. 自分の変更箇所からテストが通過することがほぼ明白
2. PRを出した後にCIの状況をチェックしてから出すことが手間
3. レビュー依頼を出すことを忘れる前に出したい

特に２と３が問題で、Google ChromeのタブのアイコンやGitHubのページ等で確認すれば良いのですが、小さかったりして見ても意識の範囲外に飛んだりしていました。

（Chromeタブを開きすぎると、タブが小さくなりすぎて何のPRかわからん。となります）
![スクリーンショット 2024-06-13 10.18.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477712/3b8c6567-68ff-c33b-361d-48974514a997.png)

CI通過前にレビュー依頼を出すと、CIが通過しなかった場合、Approveを出してももう一度レビュー依頼を出さなくてはならなくなります。
自分はCI通過前にレビュー依頼を出すことを複数回やっていたので、流石に指摘されました。
![スクリーンショット 2024-06-13 10.18.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477712/a2844bf5-e73a-b366-44bf-37c8d87ef6b2.png)

そのため、システムで解決できないかを調べてみました。

# Slackに通知する

SlackにはGitHub Appという連携機能があります。
ワークフローなどの設定を含め、Slackに通知する等のやり方は様々な記事が公開されています。

https://slack.github.com/

https://zenn.dev/k_saito7/articles/notification-github-actions-workflow-to-slack

通知のフィルタリングもすることができ、Slack上で指定できます。
例えば、PRで自動起動したGitHub Actionsを通知して欲しい場合は、このようなコマンドをSlackで打てば良いです。

```
/github subscribe {owner/repository} workflow:{event: "pull_request" actor:"{my name}"}
```

eventの指定は結構細かくできるみたいなので、一度公式のドキュメントを見ても良いかもしれません。

https://github.com/integrations/slack?tab=readme-ov-file#workflow-notification-filters

# CIの結果をSlackで確認する

コマンドを打った後にPRを作成・更新・CIの再実行等をするとこのように通知されます。

CIの状況も自動的に更新されるので便利で、終了した時にも通知が来るため、その結果からレビュー依頼や修正を行えば良いです。これで忘れないね！

（大分修正しましたがこんな感じです）
![スクリーンショット 2024-06-12 14.56.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3477712/e9f1b322-7872-750f-5881-9d39af8991fd.png)

# おわりに

皆はCIが回りきった後にレビュー依頼出そうね！！！！
USB TEMPer温度計のデータをPython+InfluxDB+Grafanaで可視化する

## TEMPerって？

10年ぐらい前から売っているUSBの温度計。私のAmazon購買履歴だと2014年に購入している。

https://www.amazon.co.jp/dp/B004FI1570/

当時、こいつを会社にBYODし、最初は[MRTG](https://oss.oetiker.ch/mrtg/)にて、その後[Zabbix](https://www.zabbix.com/)でグラフ化して室温の推移を同僚に見せていた。そして色々あって必要なくなったので、ここ数年は自宅に持ち帰り引き出しの中で寝かせていた。

TEMPer自体のQiitaの記事で検索するとここらへん。古いデバイスなのでZennにはない模様。

https://qiita.com/nekyo/items/bf5d22f3741e23d3679d

https://qiita.com/zembutsu/items/9b718416f6b30a19d83c

https://qiita.com/zembutsu/items/0f8e570c4016ddb4aefa

## 再活用

というか自宅にSwitchBotの温湿度計が欲しいなぁ思って調べていたら次の記事を見つけた、

https://zenn.dev/tanny/articles/a5c0fa5c2230a7

上記に書いた様に過去はMRGTやZabbixでデバイスは古いTEMPerという感じだけど可視化したいものは同様の温度情報、今回はデバイスはそのままTEMPerで可視化プラットフォームを新たにGrafanaでやってみようという感じ。

## できたもの

https://github.com/hkato/temper-grafana

やっていることはSwitchBotの様にクラウドのAPI経由で情報を取得するのではなく、上記TEMPerの記事でも触れている既存のUSBから取得するプログラムを`subprocess`で呼び出しInfluxDBに格納。あとはSwitchBotの記事の様にGUIでゴニョゴニョ(省略)。

## 感想とか諸々

- ラズパイ3で実行しているが電源不足なのか(実は弱めの電源で利用)たまにUSBデバイスが切断される。USB延長コードを利用すると顕著。
- 実はTEMPerをメルカリに出す動作確認も兼ねてやってみたけど、送料負けする価格じゃないと売れなさそうなので引っ込めた。もう需要がない。
- SwitchBotは湿度も測れるし羨ましい。こいつは捨ててSwitchBot hub 2を買いたい。
- まあ、複数ポイントで温度を取得する場合の一つのセンサーとしてそのまま取っておくのも良いかも。
SHA-1で作成したsigned_idをRails 7.0でもfind_signedで検索できるようにする

## はじめに：困ったこと・解決したいこと
Rails 7.0ではActive RecordのデフォルトのハッシュダイジェストアルゴリズムがSHA-1からSHA-256に変更されました。

https://railsguides.jp/upgrading_ruby_on_rails.html#active-record-%E6%9A%97%E5%8F%B7%E5%8C%96%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E3%81%AE%E5%A4%89%E6%9B%B4%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6

この変更が入ると、Rails 6.1以前に生成したsigned_idはRails 7.0以降で利用できなくなります。

```ruby 
# Rails 6.1時代に user.signed_id で生成した署名付きid
signed_id = "eyJfcmFpbHMiOnsibWVzc2FnZSI6Ik1USXpORFU9IiwiZXhwIjpudWxsLCJwdXIiOiJ1c2VyL3B1YmxpY19hdHRhY2htZW50cyJ9fQ==--8e20bed4cbb616db63a518d166ac8a5bf0266a18ff7ba55bbfd9bce9d571d6c7"

# ハッシュダイジェストアルゴリズムが変わったため、Rails 7.0環境ではRails 6.1時代の署名付きidは無効
User.find_signed(signed_id) #=> nil
```

一時的な回避策としてはRails 7.0でも引き続きSHA-1を使う、という方法があります。
ですが、SHA-1の使用は現在では推奨されないため（[参考](https://ja.wikipedia.org/wiki/SHA-1)）、あくまで一時的な回避策でしかありません。

```ruby
# 一時的な回避策としては有効だが、ずっとこのままにはできない
config.active_record.encryption.hash_digest_class = OpenSSL::Digest::SHA1
```

この記事でやりたいことは、

- デフォルトはSHA-256とする（Rails 7.0にアップデートした後はSHA-256でsigned_idを読み書きする）
- 何かしらの理由で古いsigned_idで検索しないといけない場合のみ、SHA-1で作成したsigned_idでも`find_signed`で検索できるようにする

です。

## 解決策

いろいろ調べた結果、以下のようなコードを書くことでSHA-1で作成した古いsigned_idをRails 7.0でも検索できるようになりました。

```ruby:config/initializers/message_verifiers_rotates.rb
Rails.application.config.after_initialize do |app|
  key_generator = ActiveSupport::KeyGenerator.new(
    app.secret_key_base,
    iterations: 1000,
    hash_digest_class: OpenSSL::Digest::SHA1
  )
  caching_key_generator = ActiveSupport::CachingKeyGenerator.new(key_generator)
  secret = caching_key_generator.generate_key("active_record/signed_id")

  # ここではUserクラスでfind_signedを使う想定
  User.signed_id_verifier.rotate(secret)
end
```

こうすると、`find_signed`メソッドは最初はSHA-256で検索し、データが見つからなければSHA-1で検索するようになります。

```ruby 
# まずSHA-256のsigned_idとして検索
# → 見つからなければSHA-1のsigned_idとして検索
# → それでも見つからなければnil
User.find_signed(signed_id)
```

## 参考文献

https://medium.com/get-on-board-dev/rails-7-breaks-old-signed-messages-f914d7576d75

https://systemweakness.com/unravelling-signed-url-changes-in-rails-7-e9156da43022
プロスペクトのメールアドレスが変更された場合の動作



[Salesforceと同期していてメール送信除外したプロスペクトのメールアドレスが変更された場合、メール送信除外やオプトアウトの項目はリセットされるのでしょうか?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007cm4bASAQ)


2018年と少々古い投稿ですがPardotの中ではメールアドレスがキーにはなってないようですね。これだとメールアドレスを変更しても他の項目は影響を受けないように感じます。（何か特別なアクションがなければ）

+ [メール送信除外したプロスペクトのアドレス変更後の挙動について](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007cm4bA)

+ [プロスペクトはすでに Pardot のメール キャンペーンを受信して​​いますが、同じメールを再度受信させたくないため、プロスペクトのメール アドレスを変更できますか?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000A8M2rSAF)

:::note
Pardot is going to use the Prospect ID to determine things, not the email address. So if it's the same Prospect ID then he would not get it twice (unless you change that setting).

Pardot は、メール アドレスではなく、見込み客 ID を使用して判断します。したがって、見込み客 ID が同じであれば、その ID が 2 回取得されることはありません (設定を変更しない限り)。
:::

[メールアドレスの変更を同期する方法](https://help.salesforce.com/s/articleView?id=sf.pardot_email_address_changes_sync_to_pardot.htm&type=5)


|CRMのアドレス|AEのアドレス|変更|結果|
|:-----------|:------------------|:-------------|:-----------------------------|
|a@a.com|a@a.com|CRM を b@b.com に更新|AEのプロスペクトが b@b.com に変更されます。|
|a@a.com|a@a.com|AEをb@b.com に更新|b@b.com に対応する新しい CRM レコードが作成されます。|
|@a.com|a@a.com,b@a.com|CRM を b@b.com に更新|AE の a@a.com は、CRM エントリが AEに存在するメールに変更されたことを検出します。このレコードではメールを変更できないため、CRM で再作成なしのフラグが設定されます。|
| a@a.com, a@a.com| a@a.com|2 つの CRM レコードのうちのいずれかを b@b.com に更新|AEはプライマリ同期レコードを切り替えて、別の a@a.com レコードと同期します。古いメールアドレスの既存のリードまたは取引先責任者のレコードが存在する限り、メールアドレスは変更されません。|
|a@a.com|a@a.com|CRM レコードからメールを削除|AEは、プロスペクトに [[crm_deleted]] というマークを付け、同期が停止したことを示します。|

|CRMのアドレス|AEのアドレス|変更|結果|
|:-----------|:------------------|:-------------|:-----------------------------|
|a@a.com,b@a.com|a@a.com|2 つの CRM レコードをマージ — a@a.com がプライマリレコードになり、b@b.com がメールアドレスとして採用されます。|CRM の同期中に、AEnのプロスペクトのメールアドレスは、a@a.com から b@b.com に変更されます。|
|a@a.com,b@a.com|a@a.com|2 つの CRM レコードをマージ — b@b.com がプライマリレコードになり、a@a.com がメールアドレスとして採用されます。|CRM の同期中に、AEは、新しい a@a.com メールアドレスと同期するように切り替えられます。|
|a@a.com,b@a.com|a@a.com|2 つの CRM レコードをマージ — b@b.com がプライマリレコードになり、メールアドレスとして採用されます。|CRM の同期中に、AEは、a@a.com が削除されたことを検出し、AEレコードに CRM で再作成なしのフラグを設定します。|


-----------------
Pardotでは、メールアドレスがわかるビジターのことをプロスペクトと言います。フォームを通過し、ビジターからメールアドレスが送信されると匿名のビジターはプロスペクトに変換されるのです。

匿名ビジターとは、顧客がPardotトラッキングコードが含まれるページに訪問しCookieの付与は済んだが、Cookieとメールアドレスと紐づいていないためプロスペクトに変換されていないユーザーです。


Pardotでは、フォームの登録や、Webページを訪問するなど、施策に対しアクションをとった顧客のことを厳密にはアクティブプロスペクトと言います。

プロスペクトとアクティブプロスペクトの違いは、フォームの通過などによりCookieが付与されているかどうかです。

名刺情報をPardotにインポートしたがCookieが紐付いていないユーザーは通常のプロスペクト、Cookieが紐付きWebサイトの来訪や閲覧履歴を追えるユーザーはアクティブプロスペクトとなります。


https://www.strh.co.jp/knowledge/pardot-salesforce-data-integration


https://thespotforpardot.com/2023/01/06/everything-you-need-to-know-about-the-pardot-and-salesforce-integration/

+ Salesforce で連絡先のメールアドレスを変更しましたが、その変更が Pardot に同期されません。

これは、Salesforceコネクタ設定で「Salesforce.com の変更を反映するために Pardot のメールアドレスを自動的に変更する」設定が有効になっていない限り、Salesforce コネクタの想定される動作です。
LambdaでSQS発行&受取り

`Lambda`->`SQS`->`Lambda`をした。
SDK for JavaScript (v3)で構築。Web上にはv2の情報など多くあったので、探すのに時間かかったん。。
これしてたら半日終わった...orz

## やりたかったこと
`Lambda1`から大量のキューを発行して`Lambda2`がキューを受け取って順序関係なく処理をする。

## 前提
- Lambdaが使える
- SQSキューが作成されている
- Lambdaに実行ロール,アクセス権限が設定されている(SQSとか..)

## 実際のコード
### `Lambda`から`SQSMessage`を発行
```javascript:SQSMessage発行する側<Lambda1>
import { SendMessageCommand, SQSClient } from "@aws-sdk/client-sqs";
 
// SQSキューを作成すると発行されるよ
const SQSQueueUrl = "https://sqs.ap-northeast-1.amazonaws.com/0000222224444/xxxxxxxxxx";

const region = 'ap-northeast-1'
const sqsClient = new SQSClient({
  region,
});

export const handler = async (event) => {
  const queueMessage = JSON.stringify({foo: "bar"})
  const sendedSQSOutput = await sqsClient.send(
    new SendMessageCommand({
      QueueUrl: SQSQueueUrl,
      // DelaySeconds: 3,
      // やり方2通り？
      MessageAttributes: {
        foo: {
          DataType: "String",
          StringValue: "bar",
        },
      },
      MessageBody: queueMessage,
    })  
  )

  return {
    statusCode: 200,
    body: "成功",
  };
}
```
:::message
`MessageAttributes`と`MessageBody`の両方に値を乗っけられる
`Lambda`に`SQS`のアクセス権をつけないとエラーになるよ
:::

### 受け取り側`Lambda`
```javascript:受け取り側のコード<Lambda2>
　export const handler = async (event) => {
　
　  // レスポンス
  console.log(event.Records[0]);
  
  const response = {
    statusCode: 200,
    body: "成功",
  };
  return response;
};
```

#### レスポンス`event.Records[0]`の中身
```text:event.Records[0]
{
  messageId: '06c893f9-xxxx-47f6-xxxx-01c0e29c4ab5',
  receiptHandle: 'xxxxxxx',
  body: '{"foo":"bar"}',
  attributes: {
    ApproximateReceiveCount: '1',
    AWSTraceHeader: 'Root=1-xxxxxxx-xxx;Parent=xx;Sampled=0;Lineage=xxx:0',
    SentTimestamp: '1707641273576',
    SenderId: 'xxxx:xxxxxxx',
    ApproximateFirstReceiveTimestamp: '1707641273584'
  },
  messageAttributes: {
    foo: {
      stringValue: 'bar',
      stringListValues: [],
      binaryListValues: [],
      dataType: 'String'
    }
  },
  md5OfMessageAttributes: 'xxxxxxxxxxxxxxxxx',
  md5OfBody: 'xxxxxxxxxxxxxxxxx',
  eventSource: 'aws:sqs',
  eventSourceARN: 'arn:aws:sqs:ap-northeast-1:xxxxxxxx:xxxxxxxxxxx',
  awsRegion: 'ap-northeast-1'
}
```

## さいごに
今回初めてSQSを使用した
間違い等あればコメント下さい！(=^x^=)

## リソース
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/with-sqs.html
https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v3/developer-guide/javascript_sqs_code_examples.html
pythonの言語仕様について学ぶ。初学者の学び直し日記


本日はpython classのself引数のお作法について


```py
class enemy():
    def __init__(self):
        self.hp = 100
        # self.attack = 50
        self.defense = 10
    def attack():
        print("attack")
      
en1 = enemy()
en1.attack()
```

上記のコードはエラーとなる。

エラーコードは

```
Cell **In[21], line 10
**      7         print("attack")
**      **9 en1 = enemy()
**---> **10 en1.attack()TypeError: attack() takes 0 positional arguments but 1 was given
```

となります。

GPT曰く、

このエラーメッセージは、`attack`メソッドが引数を受け取らないように定義されているにもかかわらず、呼び出し時に1つの位置引数が渡されたことを示しています。

Pythonのメソッドでは、メソッドがインスタンスに属している場合、そのインスタンス自体が最初の引数としてメソッドに自動的に渡されます。この引数は通常`self`と名付けられます。



とのこと。

簡潔にいうと、classからインスタンスを生成し、メソッドを呼び出すと、インスタンス自体をメソッドの引数に自動的に渡すのがお作法らしい。

要はpythonの言語仕様としてそうなっているらしい。


他に理解のための例として、コメントアウトを除いたもののエラーを見ると、インスタンス自体を渡すことを前提としていることを感じられるエラーが出てくる。


```py
class enemy():
    def __init__(self):
        self.hp = 100
        self.attack = 50
        self.defense = 10
    def attack():
        print("attack")
  
en1 = enemy()
en1.attack()
```

```
TypeError                                 Traceback (most recent call last)
Cell In[22], line 10
      7         print("attack")
      9 en1 = enemy()
---> 10 en1.attack()

TypeError: 'int' object is not callable
```

このエラーメッセージは、`int`（整数）オブジェクトが呼び出し可能（関数のように）として扱われた場合に発生します。この場合、`enemy`クラスには`attack`という名前の属性とメソッドがあります。`self.attack = 50`という行で、`attack`を整数値50を持つ属性として定義しています。その後、`en1.attack()`の行で、`attack`メソッドを呼び出そうとしていますが、この時点で `attack`は整数値50を持つ属性として既に定義されているため、メソッドとして呼び出すことができず、エラーが発生します。



初めのコードに戻ると。


`enemy`クラスの`attack`メソッドが引数を受け取らないように定義されていますが、インスタンスメソッドとして呼び出されると、Pythonは自動的にそのインスタンス（この場合は`en1`）を引数として`attack`メソッドに渡します。しかし、`attack`メソッドがこの自動的に渡される引数を受け取るように定義されていないため、エラーが発生します。

この問題を解決するには、`attack`メソッドの定義に`self`引数を追加する必要があります。これにより、メソッドはインスタンス自体を引数として受け取ることができ、エラーが解消されます。

とのことで、メソッドを呼び出すとき、.の左側にあるインスタンスを引数として呼び出すらしい。

別にプロパティ関係ないし動くんじゃねとコードリーディングの時は思ったが、このようなインスタンス自体を参照している過程を前提に言語が設計されているからエラーになると。。。

`self`ってそういう意味だったのね。
VScode Shift + EnterでPythonが実行されるのをやめる

## 事の発端
VSCodeでPythonで書かれたプロジェクト触っているとき、`Enter`を押そうとして間違えて`Shift + Enter`を押してしまい、Pythonコードが実行されてしまう事件が多発していました。

どうやらPythonの選択範囲実行という機能がキーバインドに割り当てられているみたいです。

消しましょう。

## 消す

![](https://storage.googleapis.com/zenn-user-upload/31bc48b9d381-20240420.png)
`⌘ + K`,`⌘ + S`または、VSCodeの右上か左下にある歯車マークを押して「キーバインド」を選択します。

そうすると、キーバインド一覧が出てくるので、検索窓に「shift enter」を入れてフィルタリングしましょう。
![](https://storage.googleapis.com/zenn-user-upload/00e5deea33fb-20240420.png)

出てきた「Python: Python ターミナルで選択範囲」を右クリックで削除します。

## さいごに
快適なVSCodeライフを
SVN Tips

# ignore

ignore設定する
```bash
$ svn propedit svn:ignore . --editor-cmd=vi
````
ignore設定の確認
```bash
$ svn pg -R svn:ignore ./
```

# svn管理対象外設定
ローカルにファイルを残しつつ、svn管理対象外にする
```
svn delete hoge.log --keep-local
```
SVGアイコン 2024

## はじめに
Web制作でアイコンが必要になることが多々あります。
有名どころですと、[Font Awesome](https://fontawesome.com/)等がありますが、ライブラリのインストールなど導入に手間が掛かるので、あまり使っていませんでした。

- SVGアイコンが使える
- 初期導入がいらない
- 大体のアイコンがある
- 検索しやすい
くらいの観点で優良なサイトを紹介します。

## 1. heroicons
![heroicons homepage](https://scrapbox.io/files/664d8fa138d04e001cbb4513.png)
https://heroicons.com/

> 所感
> TailWind CSSとの親和性がいい
> 質は良いが、数は少ないと感じた。

## 2. Icônes
![icones homepage](https://scrapbox.io/files/664d90435cb409001cf4481d.png)
https://icones.js.org/

> 所感
> SVG,PNG,React Componentなど様々な形式でダウンロードできる
> 数が多い

## 3. svgl
![svgl homepage](https://scrapbox.io/files/65779696967c3a00238bf78e.png)
https://svgl.app/

> 所感
> IT系企業・サービスのアイコンが揃う

どれも非常に良いサイトなので、使ってみてください。

## さいごに
こんなサイトもあるよ！という方がいれば、コメントで教えてください！！
chakra-uiのfontsizeをReact Nativeで再現しました

皆様お馴染みの[chakra-ui](https://v2.chakra-ui.com/)
`fontsize="md"`の記法をReact Nativeで再現したかったのでしました。

!["本家"](https://scrapbox.io/files/663dfab4d510bc001c1aa0ff.png)
!["React Nativeで再現した方"](https://scrapbox.io/files/663dfae05d0174001db14e20.png)

:::note info
誤差はちょっとあると思います。
:::

`fontsize="md"`記法を対応させるためにはライブラリのインストールが必要です。

```shell
yarn add @shopify/restyle react-native-responsive-fontsize
```

- `@shopify/restyle`: fontsizeなど記述する為にいる
- `react-native-responsive-fontsize`: フォントサイズを再現するために画面幅からパーセンテージで調節可能にするため

@shopify/restyleの導入は以下のリンクから。。
https://shopify.github.io/restyle/fundamentals/defining-your-theme/
https://shopify.github.io/restyle/fundamentals/components/predefined-components#text

テーマファイルにこれを追記します。

```typescript:theme.ts
〜〜〜〜〜〜〜
"6xl": {
     fontSize: RFPercentage(7.5),
 },
 "5xl": {
     fontSize: RFPercentage(6),
 },
 "4xl": {
     fontSize: RFPercentage(4.5),
 },
 "3xl": {
     fontSize: RFPercentage(3.8),
 },
 "2xl": {
     fontSize: RFPercentage(3),
 },
 xl: {
     fontSize: RFPercentage(2.5),
 },
 lg: {
     fontSize: RFPercentage(2.2),
 },
 md: {
     fontSize: RFPercentage(2),
 },
 sm: {
     fontSize: RFPercentage(1.8),
 },
 xs: {
     fontSize: RFPercentage(1.5),
 }
〜〜〜〜〜〜〜〜
```

### 🎉

```typescript:main.ts
<Text variant="xs" my="sm">
    (xs) In love with React & Next
</Text>
```
今後のエンジニアライフプランについて

## はじめに
前回初めて記事を書かせていただきましたが沢山の方々が見てくださり、いいねやストックしていただき本当にありがとうございました。

［前回の記事はこちら］

https://qiita.com/Chappie_00_1/items/aa609a51c5c8e42588fa

今回も未経験の方が参考になればいいなと思いながら記事作成いたしましたので読んでいただけたら嬉しいです。

## 私のエンジニア経歴
まず、はじめに私のエンジニアの経歴を紹介いたします。

**①大手通信キャリア向けデータセンター運用・保守 オペレーターとして従事**

**②事業者向け給付金BPO業務 スーパーバイザーとして従事**

**③飲食業向けPOSシステムコールセンター業務 サブスーパーバイザーとして従事**

**④Webサイト運用監視業務 メンバーとして従事**

**⑤OS社向けヘルプデスク オペレーターとして従事**

これが私の過去のエンジニアの経歴です。

私は色々な現場に行き色々な経験をさせていただきましたが、その中で**楽しかった現場**や**辛かった現場**もあり現場によって環境は違うので紹介できたらなと思います。

## 楽しかった現場
特に楽しく仕事ができこのスキルをもっと付けたいと思えた現場がありました。

それは、、、、

**①大手通信キャリア向けデータセンター運用・保守 オペレーターとして従事**

**④Webサイト運用監視業務 メンバーとして従事**

この2つの現場です。

こちらの2つの現場がなぜ楽しく仕事が出来たかというと、**①**の現場は前回の記事で少し書かせていただいたのですが、未経験エンジニアの私に上長が **「就いたばかりで話かけにくい環境でごめんね！これからはこっちも話しかけるし気にせず相談とか話しかけてね！」** と親切にしていただき業務も一つ一つ丁寧に教えてくださりました。

そこから業務にも興味が湧きこの仕事のスキルの力ももっと付けて**ステップアップ**したいと思うようになりました。

**④**の現場も同じような感じですが、Webサイトの運用監視業務なので**HTML**や**CSS**を初めて触れ、これからやっていけるかなと不安を抱えていたのですが上長や現場の方々はとても優しくわからない業務も丁寧に教えてくださっていただきました。

このように2つの現場は**現場の環境作り**に力をいれていて私は業務のスキルをもっとつけて私も現場の方々やこれから入ってくる未経験エンジニアの方々を助けられる現場を作る人になりたいと目指すようになりました。

## 辛かった現場
これから書くことは未経験エンジニアの方を不安にさせてしまうかもしれませんし、書くのやめたほうがいいかな、、、思っておりました。

しかし、私はこういう現場もあるんだなと認識していただきたいのと**自分と同じような経験をしてほしくない**と思っているので書かせていただきます。
※全部が全部このような現場ではないのであまり深く考えないで読んでいただければと思います。

特に辛かった現場は、

**⑤OS社向けヘルプデスク オペレーターとして従事**

こちらの現場でした。
何故、ここが辛かった現場だったかというと、、、

まず**③**の業務経験がありヘルプデスクの知識もつきオペレーターの研修やイレギュラー対応も多かったのでマニュアル作成なども行っていました。
私はその経験を活かして**⑤**の現場でも1から頑張っていこうと思った矢先でした。

現場の方に **「○○さん(私の名前)は見ていて業務をこなれている感が出ていて嫌いです」** や業務で少し間違えてしまった際に **「私は性格が悪いので○○さん(私の名前)のこと詰めようと思えば詰められますがストレスになると思うので止めておきます」** と言われました。

確かに業務で間違えてしまったのは悪いと私も思いますし反省しているとき、上記の事を言われた時は初めての事だったのでとてもショックだったこと覚えています。

この現場は、言葉を選ばず言わなくてもいいことを言ってしまう方々がいて誰も注意せず業務をしていました。
私の後に入ってきた新人の方々も同じような事を言われ、私がチャットでフォローをしていたのですが1週間も経たずにいなくなってしまう方が数名ほどいらっしゃいました。

業務を行うことは大事だと思います。
しかし、このように現場の環境づくりに力をいれていない現場は未経験エンジニアを不安にさせ夢も希望も無くしエンジニアライフプランすら考えなくさせていくと私は思います。

## 仕事をしながら心の中で思っていたこと
楽しかった現場や辛かった現場を紹介させていただきましたがいかがでしたでしょうか。
こういうところもあるんだなと**浅く**読んでいただければと思います。

私は色々な現場を経験し色々な経歴を持っていますが、私はずっと心の中で思っていたことがありました。

それは、、、

**色々な経歴を持っているが数年後自分はエンジニアとしてやっていけるのか**です。

何故そのように思ってるのかというと、、
私、個人的な考えではあるのですが、**今後、今まで以上にスキルなど求められ厳しい時代があると考えています。**

エンジニアになり色々な経歴を持っていても「これ出来ないのか」、「これやったことあります？」などを耳にすることがあります。
その際に自分は「これ出来ないな、、、」とか「この経験があれば良かったのに」と思うことが多々あり落ち込むことがありました。

そして、このまま新しい事や新しい知識がどんどん増えていくが、将来一人のエンジニアとしてやっていけるのかなと思うようになりましたが、今後どうしていこうかと考えるようになり自分なりにエンジニアライフプランが決まりました。

次の**今後のエンジニアライフプラン**では私と同じような不安を抱えている方や未経験エンジニアの方に向けて、私はどのようにしていくかを書かせていただきますので少しでも参考になればいいなと思います。

## 今後のエンジニアライフプラン

私の今後のエンジニアライフプランは2つあり、1つ目は **「自分のペース」で実務経験や資格勉強などをしていく事**を重視してスキルアップしてこうと考えています。

何故かというと、今まで以上にスキルなど求められ不安や焦りで自分が思うパフォーマンスやスキルアップが出来ないと思うからです。
そこで私は周りに流されず私なりのペースでスキルアップをしていこうと考えました。


2つ目は**今までの経験を無駄にせず同じような経歴をもった方や未経験の方の将来を不安にさせない環境作り**に力を入れるエンジニアになり助けあえる環境を作る一人になることです。

読んでいただいてる方でこれはエンジニアライフプランといっていいのかと思う方がいらっしゃるかと思いますが、私なりに考えた結果**色々なエンジニアがいて自由なエンジニアライフプラン**があっていいのではないかと思いました。

これが、私の**エンジニアライフプラン**です。

## 最後に
2回目の投稿ですが、いかがでしたでしょうか。
前回の記事と同じような記事になってしまっていたらすみません、、、

未経験の方や未経験ではない方で不安を抱えている方は今もいると思うので
前回の記事や今回の記事を見て一人でも不安を無くすことが出来ればいいなと思い今回記事を書かせていただきました。

最後までお読みいただきありがとうございました。
Terraform importブロックでError: Too many command line argumentsが出る

## 概要

以下のimportブロックで

```
import {
  to = aws_iam_openid_connect_provider.github_actions_cicd_provider
  id = "arn:aws:iam::${var.AWS_ACCOUNT_ID}:oidc-provider/token.actions.githubusercontent.com"
}
```

以下のコマンドを実行すると
```
terraform plan -generate-config-out=generated.tf
```

以下のエラーが出てしまう
```
terraform plan -generate-config-out=generated.tf
╷
│ Error: Too many command line arguments
│
│ To specify a working directory for the plan, use the global -chdir flag.
╵

For more help on using this command, run:
  terraform plan -help
```

## 解決策
VScodeでpowershellだと発生する事象なのでCMDを使う

## 参考
https://github.com/hashicorp/terraform-provider-aws/issues/31978
HPE ProLiant Gen10サーバのVMware ESXi 8用HBAドライバー更新[未完]

:::note info
Last Update 2024-06-13
:::
:::note warn
警告
この記事はあくまで筆者自身のメモ用であり、このメモを応用しもたらされた損害責任は一切負いかねます
:::

# はじめに
業務中に予期せぬタスクが割り当てられた際、本番環境への適用前にその検証を依頼されました。その過程で予想外の問題に直面し、その解決策を共有することで、私自身の解決への取り組みを振り返るとともに、後に同様の課題に取り組む方々への参考になればと考え、この記事を執筆しました。お役に立てれば幸いです。

# 環境紹介
サーバー： HPE ProLiant DL380 Gen10
ストレージ： HPE MSA 2062
仮想化環境： VMware vSphere 7.0

※詳しいバージョンまでは事情により伏せておきます
※インターネット接続環境にて資材入手・オフライン作業前提
※操作用端末はWindows 10/11と想定

# やりたいこと
ストレージのファームウェアを更新してくれとある日頼まれたので、じゃHBA側のファームウェアもOS側のドライバーもそれに伴い更新しないとねと判明。ステップを分解してみると以下の感じです。
↓

1. **ストレージのファームウェア更新**
    - .sfwファイルの入手
    - SMUにログイン、更新実施
2. **サーバ側のHBAファームウェア更新**
    - 最新のSmart Update Manager (SUM)をダウンロードし実行
    - サーバのiLO接続情報を入力し更新を実行
3. **OS側のドライバー更新**
    - ドライバーパッケージを入手
    - TeraTerm等でESXiホストにログインし更新を実行

# 詳細手順

## ストレージのファームウェア更新
1. 最新のファームウェアを入手してきます
https://h41111.www4.hpe.com/storage/msafirmware.html
機種は2062なので、所定のリンクを押下しダウンロード先ページに遷移する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188534/1b808dba-d7f0-37bb-565c-ee568c590cd1.png)
「Download Software」を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188534/d78e2aa2-7ac6-2a2c-a3c3-2792c2cebc77.png)
厳密に行う場合はダウンロードしたファイルのハッシュ値チェックまでやりますが、今回は割愛します。exeを選択し、「ダウンロード」ボタンを押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188534/b082289b-2aa2-0511-287b-a46075dca31b.png)

さて、ここからが正念場だ


:::note alert

絶対に！！exeを実行しないでください！（のち解凍して利用する為です）
:::
exeファイルをダウンロードしたら、まずは、圧縮解凍ソフトを使って、一旦解凍します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188534/e6c7cd0a-143d-a1b2-b0c3-05d4b0d36492.png)
そうすると、以下のように、{Firmwareバージョン名}_hpe_enc.sfwのファイルが出てきます。もしデータセンター等に入室して作業する必要があれば、これを持っていくことをお忘れなく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188534/526fef19-442a-f4ac-2add-8d7cbfbecbe7.png)
次に、ブラウザでStorage Management Utility（SMU）にアクセスして、管理者アカウントでログインしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188534/d822abad-3bf2-14a5-defb-b2a474be57a3.png)
ログインしたら、次に、左側のサイドメニューから、「メンテナンス→ファームウェア→システム」順にページを遷移し、下記の画面から、「ファイルの参照」ボタンを押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188534/f0153400-f61d-e710-221e-13ca601fc7fd.png)
ファイルアップロードダイアログから、前述の{Firmwareバージョン名}_hpe_enc.sfwのファイルを選択した状態で「開く」を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188534/e333f328-afde-b97a-9b29-7b666a8a3f23.png)
これで、ファームウェアの更新処理が開始されます。

ファームウェアの更新中にマネージャーコントローラーが再起動することが予想されます。これによるデータ交換への影響はないとされていますが、リスクを最小限に抑えるためには、ストレージ上で稼働しているシステムを一時停止してから更新作業を行うことをお勧めします。

今回のファームウェア更新に関する情報は以上ですが、新しい情報が入り次第、この場で追ってお知らせいたします。ご不明な点やご意見がございましたら、遠慮なくコメント欄にてお寄せください。
Qiita記事投稿イベントをGoogleカレンダーにいれとこ！

# 　はじめに
[Qiita Engineer Festa 2024](https://qiita.com/official-campaigns/engineer-festa/2024)が始まっております。
19記事投稿することでグッズが貰えるみたいなのでやってみましょう！38記事投稿するとさらに何か貰えるみたいです。
そこで、記事投稿の予定をGoogleカレンダーに入れようと思ったのですが38日分登録するのがめんどくさいので、GASで自動化しましょう！(多分もっといい方法あるがロマンで..)

## 手法
1. [イベント用のGoogleカレンダーを作成](#イベント用のgoogleカレンダーを作成)
2. [Apps Scriptを用意](#apps-scriptを用意)
3. [実行!](#実行)
4. [記事を書く!](#記事を書く)

### イベント用のGoogleカレンダーを作成
![スクリーンショット_2024-06-13_14_01_53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403148/8fbe3ba9-7b62-364a-99da-774034c4c299.png)
イベント用に新しいカレンダーを作成します。

![スクリーンショット_2024-06-13_13_30_31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403148/52e50ea6-a2a3-be72-0749-cf50ab8cfe17.png)
カレンダーを作成したら、カレンダー設定を開いてカレンダーIDを確認します。

![スクリーンショット_2024-06-13_13_31_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403148/82de5300-7c47-3609-92ba-56d92cfffa81.png)
ここに出てくるカレンダーIDを控えておきます。

### Apps Scriptを用意
Google SpredSheet新規作成 > 「拡張機能」ボタン > Apps ScriptをクリックしてGASを書く準備をします
詳細はこちらの記事の方がわかりやすいと思います💦
https://qiita.com/massa-potato/items/2db4cd27f8e8dc4c3f97


その後、こちらのコードを貼り付けます

```javascript:main.gs
const CALENDER_ID = 'xxxxxxxxxxxxxxxxxxx@group.calendar.google.com'; # <- 自身のカレンダーIDに置き換えます
const calendar = CalendarApp.getCalendarById(CALENDER_ID);

function myApp() {
  const recurrence = CalendarApp.newRecurrence().addDailyRule().times(38);

  const title = "Qiita記事投稿💪";
  const options = {};
  const startDate = new Date("2024/06/03"); 

  calendar.createAllDayEventSeries(title, startDate, recurrence, options);

  calendar.createAllDayEvent("記事投稿キャンペーン最終日🗓️", new Date("2024/07/25"));
}
```

### 実行!
Apps Script > `myApp`を選択して実行します。
![スクリーンショット 2024-06-13 14.32.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403148/748be730-3b51-a610-a132-fe1cf170a62a.png)

これで、38日分のイベントが登録されました！Done🎉

![スクリーンショット_2024-06-13_14_09_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403148/02eb35aa-868e-4619-d2e3-23f25e9b74ff.png)

### 記事を書く!

記事を書くのはあなたです！

## 参考記事
https://qiita.com/yuma-o2525/items/e226e825847c907c5d3f
https://qiita.com/massa-potato/items/2db4cd27f8e8dc4c3f97
Vue Routeのqueryの型がややこしくなってたので簡単に取れるようにした

`Vue3.4.27`、`Nuxt3.12.1`で開発しようとして`useRoute().query.hoge`を変数に入れようとすると、型エラーが...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177673/17465b78-1107-da28-3b35-91a0de188b43.png)

`LocationQueryValue`？ 見慣れない型だな:thinking:

`Vue3.4.15`、`Nuxt3.11.2`で開発していた頃には見かけなかったので、ここから先述のバージョンの間に更新されたものと思われます。

確認したところ、↓こんな感じの型関係になっているようです。
```typescript
export declare function useRoute(): RouteLocationNormalizedLoaded;
// ↓
export declare interface RouteLocationNormalizedLoaded extends _RouteLocationBase {
    matched: RouteLocationMatched[];
}
// ↓
export declare interface _RouteLocationBase extends Pick<MatcherLocation, 'name' | 'path' | 'params' | 'meta'> {
    // 省略
    query: LocationQuery;
    // 省略
}
// ↓
export declare type LocationQuery = Record<string, LocationQueryValue | LocationQueryValue[]>;
// ↓
export declare type LocationQueryValue = string | null;
```

なので、`useRoute().query.hoge`みたいに取得すると最終的には
`string | null | (string | null)[]`型が取得できます。

---
ここで困ったことが2点あります。
- `LocationQuery`型は`Record`なので存在しないキーを指定すると`undefined`が返ってきますが、`useRoute().query.hoge`の型推論は`LocationQueryValue | LocationQueryValue[]`になっているため`undefined`が含まれない
- queryの値が配列である場合も考慮されていますが、私の場合配列で渡すことはない想定なので、毎回配列である可能性を除外して扱わないといけない

上記の対策コードを各query使用箇所に書くのはかなり冗長なので、Nuxtのutilsで定義しました。

```typescript:extractRouteQueryStr.ts
import { type LocationQueryValue } from "vue-router";

export default (
  queryValue: LocationQueryValue | LocationQueryValue[] | undefined
): string | undefined =>
  queryValue instanceof Array
    ? queryValue[0] ?? undefined
    : queryValue ?? undefined;
```
やっていることは簡単で、
1．配列なら配列の最初の要素を返す

:::note warn
※今回の私のコードだと配列は使わない想定なので「配列の最初の要素」というのは適当です
(使わないならundefinedだけ返すようにした方が良いかもしれない)
:::
`arr[0]`の返り値は`T | undefined`なので、`queryValue[0]`は`string | null | undefined`となります。
これを`?? undefined`することで、`null`の場合も`undefined`に統一して返すようにしています。

2．配列でないなら`LocationQueryValue`を返すが、この型の中身は`string | null`なので、1と同じく`?? undefined`して`null`の場合でも`undefined`で返す

です。
```typescript:usage
const hoge = extractRouteQueryStr(useRoute().query.hoge);
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177673/bfc38b9a-d22f-51d1-f316-60c40366d9e8.png)


上記コードは配列の場合を一切考慮していないので、配列の場合どう返すかや、`undefined`ではなく`null`で返したいなどの場合は適宜カスタマイズが必要です。

私の場合は、queryの値を受け取る関数を以下のような感じで定義していて、
nullをそのままにすると型定義が煩雑になるし、nullとundefindで関数の動作は変わらないので一律undefinedでいいかなという判断です。

```typescript
const hoge = (
  redirect?: string,
  fuga: number,
  foo: string,
) => {
  //
}

// nullも考慮するとこうなる
const hoge = (
  redirect?: string | null
  fuga: number,
  foo: string,
) => {
  //
}
```

もしもっといいやり方があったら教えてください！