OmniAICreator/Qiita-1.07M huggingface dataset:
AWS Glueの概要とジョブの実行環境について簡単に

# はじめに
ETLツールであるAWS Glueについて、業務で使用することがあり、この記事で調べたことをまとめます。
Glueについては様々な機能があり、全てをこの記事で説明することは難しいので、この記事ではGlueのジョブに焦点を当てて説明していきます。
Glueのジョブは実行環境としてSparkやRayがあり、データエンジニアリング初学者の筆者としてはそもそもSparkやRayとはどういったもので、何が違うのかといったところから分かっていなかったため、そのあたりの話を含めて説明していきます。
# AWS Glueとは
AWS Glue は、フルマネージドかつサーバーレスなETLサービスです。様々なソースからのデータの抽出、変換、ロードを効率的に行うことができます。


以下のページを参照すると、Glueのコンポーネントは以下のようになります。

https://docs.aws.amazon.com/glue/latest/dg/components-key-concepts.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3903963/c68160f7-f02c-43ae-0901-2e3003bf1c28.png)


**クローラー**
クローラーにデータストアを指定することで、自動的にスキーマを検出してメタデータをデータカタログに作成します。
**データカタログ**
データカタログでは、ETL処理したいデータのメタデータを管理しています。
また、ETLのジョブやワークフローに関するデータもここで管理します。
メタデータは、元データ（データストア）からGlueのクローラーで抽出してきたものになります。
**ETLジョブ**
データの抽出、変換、ロードを行うプロセス。PythonまたはScalaで記述され、Glueのサーバーレスエンジンにて実行されます。
**トリガー**
スケジュールやイベントに基づいて機械的にジョブを実行することができます。

ジョブの部分が個人的には理解が難しく、かつ重要であると思われたため、自分のアウトプットのためにも、この記事では以下でGlueのジョブについて詳しく説明していきます。

# Glueのジョブについて
Glueのジョブは、実行環境として以下があります。
- Spark
    - PySpark(PythonでSparkを利用するためのAPI)を使ったPythonスクリプトなど、Spark向けのコードを用意することで、Sparkシステム上で分散処理ができる。PysparkをAWSが拡張したawsglueライブラリもある。Scalaでの実装も可能。
- Ray
    - 2023/5提供の新しい機能。Sparkと同様Pythonで並列処理を実現できる。Sparkと比べ学習コストが低く、Pandasなどよく使われているライブラリを組み合わせることができる
- Python Shell
    - 単純に、Pythonのスクリプトを実行するだけのジョブ。並列実行はできないため、大量のデータの処理には不向き
    
Python Shellは最も単純だが複雑な処理ができない（シングルノードでの処理しかできない）、一方でSparkは複雑な処理が可能だが実装が難しく学習コストがかかる。Rayはその中間で実装がしやすくかつパフォーマンス面もある程度良い、といったようなイメージをしています。

上記3つについて、大量データ処理時にも問題なく並列でスケーリングできるSparkもしくはRayが選択されることが多いと考えられるため、SparkとRayに焦点を当てて以下でそれぞれについて説明していきます。

# Spark
Sparkは、Hadoop技術をベースとして、その課題点を解決するためにApache Sparkプロジェクトによって作られた分散並列処理のフレームワークです。

Apache Sparkプロジェクトは、Spark本体以外にも様々なライブラリを提供されており、これらはGlueでも使用できるものも多いため、関連するApache Sparkの知識が必要になることがあります。

ただ、GlueではSparkのサーバーを自分で構築しなくても、PySparkを使いPythonスクリプトを用意することで、SparkによるETLを実現できます。
より詳細に言うと、Sparkの実行環境の管理はGlueサービスが実施するので、利用者は直接制御することなく、利用したい環境の指示（処理スペック、並列度、リトライ回数など）をするだけで利用できます。
実装手段としては、PySpark、PysparkをAWSが拡張したawsglueライブラリ、Scalaがあります。

# Ray
 Sparkと同じ分散並列処理のフレームワークですが、Pythonでシンプルに記述できるように設計されており、またPandasなどよく使われるライブラリと組み合わせで使用できます。
これまでのPythonでの分散並列処理の実装は難しいものであったが、Rayの登場によってPythonによる分散並列処理が容易に実装できるようになった、そういった立ち位置にあるものがRayであると理解しています。

Ray Core (分散処理機能)、Ray Dataset (データの格納) 、Modin (pandas をRayで実行するためのもの) が利用できる環境がGlueによって提供されています。

 


 # SparkとRayの違い
Rayは、タスク指向であり、一連の独立したタスクを同時に実行するタスクの並列処理に優れています。
一方Sparkはデータ指向で、大規模なデータの対しての並列処理（ETL、データ分析、ストリーミング）に優れています。
どちらが優れているということではなく、タスク指向であるRayとデータである指向Sparkはそれぞれ別々で、用途に応じて使い分けることになりそうです。

https://docs.databricks.com/ja/machine-learning/ray/spark-ray-overview.html

# 最後に
本記事ではAWS Glueについて、その概要について触れた後、ジョブの実行環境について簡単に説明しました。SparkとRayのそれぞれの特徴や違いについては、実際実装してみたりしないと理解が進まないところもあるかと思いますので、次回以降の記事で実装踏まえてその詳細について説明できればと思います。
【Google検索を超えた？】AI検索エンジン Perplexityの特定のサイト内検索を検索バーで利用する



## はじめに

### この記事でできること

- Perplexityのサイト内検索をChromeで直接利用できるようになります


### この記事の対象者

- Perplexityを使用している人
- 最新情報で生成AIを使いたい人
- 公式ドキュメントを読むのが面倒臭い人


### 動作環境・使用するツールや言語

- Windows11
- Chrome 130.0.6723.70
- Perplexity 2024年11月


## Perplexityの紹介
Perplexityとは、従来の生成AIが苦手としていた「最新情報に基づく回答」をWEB検索結果から情報を取得することで可能にする新しい検索エンジンです。

Google検索でも最近AI回答を並立させていますが、Perplexityはより生成AIの回答をメインにしている検索エンジンです。

https://www.perplexity.ai/ja/hub/faq/what-is-perplexity

## Perplexityのサイト内検索

そのままでも十分に強力ですが、やはりSEOの強いサイトを参考にする傾向にあるため、情報源が二次情報になる傾向があります。

Perplexityでは、検索対象を特定のサイト内・ドメイン内に絞る機能が用意されています。
これによって、公式ドキュメントの特定バージョンなど、より確度の高い情報を生成することができます。

おまじないは`/site:{対象url} {検索キーワード}`です。

以下は、PerplexityでPython 3.13.0の変更点について、そのまま検索したものと、サイト内検索を利用したものです。

```:検索キーワード
/site:docs.python.org/3.13/ Python3.13.0の変更点
```
### そのまま検索
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3755504/f75ce109-a4f2-a107-7fd1-e208a5a97434.png)
情報ソース源が二次情報になっています。

### サイト内検索
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3755504/ad147ed4-751f-6e5a-46f2-ab5696f99bde.png)
公式ドキュメントから生成されています。


## Chromeの検索エンジンにPerplexityの特定サイト検索を追加する
サイト内検索は便利ですが、おまじないを毎回打つのは面倒です。
**短いキーワードで公式ドキュメントから検索できるようになったら便利ですよね？**

なのでブラウザ側で検索クエリを設定します。

### Chromeの検索エンジンにPerplexityを追加する
まず、Perplexity本体を検索エンジンに追加してみましょう。
以下の記事通りすればできるはずです。

https://zenn.dev/acntechjp/articles/87b9c8ffb318e3

## Perplexityの特定のサイト内検索を追加する
次はいよいよ特定サイトを対象に追加します。ここでは例としてPython3.13.0を登録してみましょう。

### 設定画面を開く
Chromeの設定画面からPerplexityを追加するところまで同じです。

### 検索エンジンを追加する
検索エンジンの追加画面を開き、以下のようにしてください。
- **名前:** 分かりやすい名前にしましょう。今回は`Perplexity(Python3.13.0)`にします
- **ショートカット:** 先程の手順では`pa`が検索ショートカットだったので`papy`にします
- **URL:** 次をコピペします
```:Python公式ドキュメント内検索
https://www.perplexity.ai/?q=/site:docs.python.org/3.13/ %s
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3755504/60e10bfb-fb54-d104-f943-3dac99464e03.png)

既に特定のサイトが決まっている場合は以下の`{特定サイトURL}`を書き換えてください。
名前やショートカットも任意のものに変更してください。
```:任意の特定サイト内検索
https://www.perplexity.ai/?q=/site:{特定サイト} %s
```
できたら**追加**してください

### 追加できたかテスト
うまくいったかどうかをテストしましょう。
1. **検索バーにpapyと入力してスペースキー(またはタブ)を入力**


    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3755504/1cb85376-d196-291f-2083-bce864034e06.png)


2. **Perplexity(Python3.13.0)を検索となればOKです**


    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3755504/e645846c-58ee-838f-0f8a-8cddfbc139ea.png)

3. **検索キーワードを入力**

    検索キーワードを入力します。Pythonの導入について検索してみましょう。

    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3755504/93e918de-6f44-51b1-9e0d-025b378a96b7.png)

    通常であれば`"何を導入したいですか？"`と聞かれる所ですが……


4. **検索結果を確認する**
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3755504/94ad36aa-9108-3cef-7c90-74cdd76e033a.png)

    **Python3.13であることを分かった上で**、導入について教えてくれました！参照元も公式ドキュメントが優先されています！


## おわりに

Perplexity、本当に便利です。検索バーに常駐させることでワンアクション少なくなって非常に捗っています。
皆さんもぜひ好きなように検索してみてください！

検索結果の共有もできるのでチーム内でも公式ドキュメントに触れる機会が増えるかもしれません。
立ち上がれVM，邪知暴虐のメンテナンスモードに立ち向かう-ESXi環境編-

# VMが再起動しない
ある日のこと，ESXiをメンテナンスモードにしてシャットダウンしてみた．
「よし，メンテ完了！じゃあ作業再開だ！」と意気揚々とVMを操作するも，なぜかVMが動かない．

「あれ？このVM自動起動設定いれてたよね？」と思ったら，原因はESXiがまだメンテナンスモードのままだったこと．
まぁ，そりゃそうだよね，とモードを解除してリトライ．……が，それでもVMは立ち上がらない．

「え，なんで？再起動くらい普通にしてくれてもいいじゃん……」とちょっと困惑．
軽くググってみたけど，これといった解決策は見つからず．

ならば，自分で解決策を作るしかない！ということで，今回の冒険が始まりました．

# 解決作
自動起動設定されたVMだけを，再起動したかったのでESXiから再起動設定されたVMの識別できないかぁ？と思って調べたところ
```
#ESXiの再起動設定されたVM名置き場
hostsvc/autostartmanager/get_autostart
```
という場所に再起動されたVMのリストが格納されていた．
ここから，VMのIDが取得できることに気づいたので後は簡単
適当にpythonでメンテナンスモードを解除するプログラムと，自動起動設定されたVMを起動するプログラムを作って，ESXiの再起動時にメンテナンスモード→自動起動設定されたVMを起動するようにすれば，ESXi起動時にメンテナンスモードも解除されてVMが自動起動されました．
```python
# メンテナンスモードを解除する関数
def exit_maintenance_mode(hostname, username, password):
    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    while True:
        try:
            client.connect(hostname, username=username, password=password)
            stdin, stdout, stderr = client.exec_command('vim-cmd hostsvc/maintenance_mode_exit')
            output = stdout.read().decode().strip()
            error = stderr.read().decode().strip()
            
            # メンテナンスモード解除の結果をチェック
            if "vim-cmd" not in output and not error:
                print(f"メンテナンスモードの解除に成功しました： {hostname}")
                break  # 成功したらループを抜ける
            
            print(f"Output: {output}")
            print(f"Error: {error}")
        except Exception as e:
            print(f"接続失敗（{hostname}）。再試行します。Error: {e}")
        finally:
            client.close()
            time.sleep(60)  # 再試行まで待機する
```
```python
# 自動起動設定されたVMを起動する関数
def start_autostart_vms(hostname, username, password):
    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    try:
        client.connect(hostname, username=username, password=password)
        stdin, stdout, stderr = client.exec_command('vim-cmd hostsvc/autostartmanager/get_autostart')
        output = stdout.read().decode().strip()
        error = stderr.read().decode().strip()
        
        if error:
            print(f"Error: {error}")
            return
        
        auto_start_vms = []
        for line in output.split("\n"):
            if "vim.VirtualMachine:" in line:
                vm_id = line.split("'")[1].split(":")[1]
                auto_start_vms.append(vm_id)
        
        for vm_id in auto_start_vms:
            print(f"Starting VM: {vm_id}")
            client.exec_command(f'vim-cmd vmsvc/power.on {vm_id}')
        
    except Exception as e:
        print(f"Error: {e}")
    finally:
        client.close()

```

# 終わりに
実はこれ，もうちょっと課金してvCenter Serverを導入すれば解決していた問題だったかもしれない．
というわけでESXiとセットでvCenter Serverもいかがでしょうか？
Top 9 PDF Generator APIs in 2024

Source: [Best PDF Generator APIs](https://www.compdf.com/blog/best-pdf-generator-apis?utm_source=qiita_20241120&utm_medium=pdfgeneratorapi)

## ComPDFKit PDF API
ComPDFKit is dedicated to providing comprehensive PDF SDK solutions, enabling developers to flexibly create outstanding products. And ComPDFKit API currently offers over 40 document processing tools, with plans to continuously expand its features.

Pricing
ComPDFKit API offers two types of monthly subscription plans and flexible pay-as-you-go pricing options. If you opt for an annual subscription, you can enjoy a 20% discount. It’s worth saying that ComPDFKit API provides a 30-day free trial, in which you can process over 1,000 documents without any limitations in this period.

## PSPDFKit (Nutriend) PDF API
PSPDFKit(Nutriend) Generator PDF API supports users to make PDF files from HTML templates. Users can customize CSS styles, add unique images and fonts, and keep headers and footers on the page to create personalized documents.

Pricing
PSPDFKit(Nutriend) does not list models or prices on its website. Therefore, if you want to know the quote, you will need to contact them. In addition, they also provide a free account to test the performance of the product, but it should be noted that the size of the document processed with the free account cannot exceed 5MB.

## Adobe Document Generation API
Adobe Document Generation API helps users generate PDF documents through its cloud-based REST API and external storage REST API. To use the service, you need to first create a Word template and then combine JSON data to generate PDF.

Pricing
Although Adobe Document Generation API does not provide specific pricing details, it provides two pricing plans: Free Plan and Enterprise Plan. Each plan includes different services. Please note that the free plan has a limit of up to 500 documents generated per month.

## Apryse PDF Generator API
Apryse PDF Generator API helps users generate PDF files efficiently by combining office template framework and JSON data. It supports various office document types like Docx, XLSX, and PPTX.

Pricing
Apryse does not list pricing information in detail on its website. If you are interested in this service or want to test the product, you need to fill out their online form to get in touch. In addition, they did not mention whether they offer a free trial plan.

## PDF Generator API
The PDF Generator API is a highly popular tool that offers a flexible REST API and a template editor to help you generate PDF files. To use this tool, you first need to create a template, then provide the template ID and JSON data via the API to generate a PDF.

Pricing
PDF Generator API offers five different pricing plans based on the number of documents you generate each month. It’s important to note that the charges are calculated based on the number of “merge” operations involved in generating each document. This means if you extract data from five different sources to create a single PDF, you will be charged for five merges, not just for one document.

Read More on Source Post …
lambda

```
from datetime import datetime, timezone, timedelta  # 确保导入了 timedelta

# ... 其余代码 ...

def format_timestamp(timestamp_str):
    """
    将时间戳字符串转换为日本标准时间（JST）格式
    """
    if timestamp_str:
        try:
            # 解析时间戳，包含时区信息
            timestamp = datetime.strptime(timestamp_str, '%Y-%m-%dT%H:%M:%S.%f%z')
            # 创建日本时区（UTC+9）
            jst_timezone = timezone(timedelta(hours=9))
            # 转换为日本时区
            jst_time = timestamp.astimezone(jst_timezone)
            return jst_time.strftime('%Y-%m-%d %H:%M:%S %Z')
        except ValueError as e:
            print(f"时间戳解析错误: {e}")
            return 'N/A'
    else:
        return 'N/A'

```
未経験から勉強のためにWebアプリケーションを作成した話


hi guys
フロントをnuxtで
バックをnextでっていう指令を受けたので勉強のためにアプリケーション作ったよ
完成品はこんな感じだよ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3527006/5aecb4ea-3c37-60be-2f79-58f89764f142.png)


**この記事の目的**
- 作成したアプリの概要を共有
- 使用した技術スタックや機能要件を解説
- 開発中に苦労した点や改善すべき部分を振り返る



---

## 作成したアプリケーションの概要

### **アプリの目的**
テナント・商品・注文・売上を管理できる **簡易管理システム** を開発しました。このシステムは、複数のテナントを所有するオーナーが各テナントの情報や売上状況を一元管理できるツールとして利用されることを想定しているよ

### **主な機能**
1. **アカウント管理**
   - ユーザーの作成・編集・削除
2. **テナント管理**
   - テナントの作成・編集・削除
   - オーナーごとのテナント表示
3. **商品管理**
   - 商品の登録・編集・削除
   - テナントごとの商品表示
4. **注文管理**
   - 注文の作成・削除
   - 注文履歴表示
5. **売上管理**
   - 全期間の総売上表示
   - テナントごとの売上表示
   - 期間を指定した絞り込み機能

---

## 技術要件

### **フロントエンド**
- **Nuxt.js**
  - モダンなフロントエンドフレームワーク
- **Tailwind CSS**
  - スタイリングの効率化を図るために採用
- **TypeScript**
  - 型安全なコーディングでバグを減らす

### **バックエンド**
- **Next.js**
  - APIエンドポイントの実装に利用
- **Prisma**
  - データベースとのやりとりを簡素化
- **TypeScript**
  - フロントエンド同様、型安全を確保

### **データベース**
- **MySQL**

---

## 機能要件

アプリは以下の要件を満たすように設計しました。

### **基本設計**
- ユーザーごとに複数のテナントを管理可能
- テナントには複数の商品を紐づけ可能
- 商品に紐づく注文を管理

### **画面要件**
1. **アカウント管理画面**
   - ユーザー情報のCRUD操作
2. **テナント管理画面**
   - オーナーごとにテナントを表示し、CRUD操作可能
3. **商品管理画面**
   - テナントごとに商品を表示し、CRUD操作可能
4. **注文管理画面**
   - 注文履歴を表示し、CRUD操作可能
5. **売上管理画面**
   - 全期間・期間別・テナント別の売上表示

---

## 改善すべき部分

いっぱい改善案があるけど、最低限必要な部分

### **1. バリデーション**
現状、フロントエンド・バックエンドの両方で入力バリデーションが不十分な箇所があります。特に以下を改善したいです：
- フロントエンドでのリアルタイムバリデーション
- サーバーサイドでの詳細なエラーメッセージ

### **2. UI/UX**
- デザイン性に乏しい
- 操作性を高めるために、以下を追加予定：
  - **検索機能**
  - **ページネーション**

### **3. ログイン機能**
- 現在は認証機能が未実装であり、誰でもシステムにアクセスできる状態です。
- ClerkやJWTを使った認証機能の実装を検討しています。clerkが簡単だからそっち予定

### **4. テスト**
- 手動テストのみで動作確認を行っており、自動テストは未実装です。
- JestやCypressを用いたテストを導入予定です。

---

## 苦労したポイント

1. **バックエンドとフロントエンドのデータ連携**
   - Prismaで関連データ（例：テナント情報を持つ商品）を取得する際の設定に時間がかかりました。
2. **型定義**
   - TypeScriptの型エラーに悩まされることが多く、型の設計には工夫が必要でした。
3. **CORSエラー**
   - フロントエンドとバックエンド間の通信で何度もCORSエラーが発生し、その都度調整が必要でした。

---

## 学びと感想

- Nuxt.jsとNext.jsは割と直感的で使いやすかったです。ルーティングの機能便利！
- 今後は改善点を一つ一つ修正し、さらなるスキルアップを目指していきたいです。
初めてAnsible使った人が、初めてAnsibleを使う人に向けて説明する

今年度、業務でansibleを使用することが度々ありましたが、
私自身は若手エンジニアであり、***ansibleを触るのは人生で今年が初でした。***
得た経験のアウトプットのためにも、この記事でansibleの知見についてまとめます。

<br>
<br>




<br>
<br>

## Ansibleについて
Ansibleは、***サーバーやネットワーク機器などの管理を自動化***するためのツールです。
yaml形式で記述することにより可読性が高く、学習も容易（らしい）です。

<br>
<br>

## Playbookについて
Ansibleでやりたいことを、「***Playbook***」というファイルに書きます。
Playbookは「指示書」みたいなもので、あるサーバに「このソフトをインストールして、設定を変更する」という作業を実施したい場合、その手順をPlaybookに記載します。

<br>
<br>

## インベントリファイルについて
インベントリファイルは、Ansibleが「***どのコンピュータ（サーバー）に対して操作をするか***」を指定するリストです。
Ansibleで管理する***コンピュータの名前やIPアドレス、グループ分け***などを設定します。

<br>
<br>


# 業務で学んだこと
以下の3項目について、業務で関わることが多かったので説明いたします。

・ansible実行用サーバと配布されるサーバの関係
・インベントリファイルの書き方
・ローカルホストにPlaybook流す方法

<br>
<br>

## 1. Ansible実行用サーバと配布されるサーバの関係
Ansibleを使う場合、主に以下2つのサーバーが関係します。

##### Ansibleを実行するサーバ（管理用サーバ）
<dd>Ansibleを実行するサーバ。このサーバにAnsibleがインストールされていて、管理対象のサーバ（配布サーバ）に対して設定やコマンドを送信する</dd>

##### 配布されるサーバ（管理対象サーバ）
<dd>これらはAnsibleで設定や操作を行う対象のサーバ。AnsibleがSSHで接続して操作します。</dd>

<br>
<br>

ざっくりまとめると、Ansibleを利用するためには、以下の2点の準備が必要です。

* Ansibleを実行するサーバ（管理用サーバ）と配布されるサーバ（管理対象サーバ）が***SSH接続***を行えること
* Ansibleを実行するサーバ（管理用サーバ）に***Playbook資材***が格納されていること

<br>
<br>

またAnsibleを使用するには、基本的に管理用サーバ（Ansibleを実行するサーバ）にAnsible自体をインストールする必要がありますが、管理対象サーバ（操作対象のサーバ）にはAnsibleを実行するための特別なソフトウェアやエージェントをインストールする必要はありません。

<br>
<br>


## 2. インベントリファイルの書き方
インベントリファイルは、***Ansibleが操作するサーバーをリスト化したファイル***です。このファイルに管理対象サーバのIPアドレスやホスト名、グループを定義します。

つまり「Aシステムのサーバ群に対して、一括でユーザー作成を行いたい！」といった時、
Aシステムのサーバ群のIPアドレスやホスト名をインベントリファイルに記載することで、想定通りのサーバ達に向けてユーザ作成を行うAnsibleを実行することができます。

<br>

<br>

基本的なインベントリファイルの例を作成してみました。
インベントリファイルは通常、/etc/ansible/hostsや指定したフォルダに保存します。


```ini
# インベントリファイルの例

# グループ1: Linuxサーバ
[Linux]
web-server1 ansible_host=192.168.1.10
db-server1 ansible_host=192.168.1.11

# グループ2: Windowsサーバ
[Windows]
win-server1 ansible_host=192.168.2.10
win-server2 ansible_host=192.168.2.11

# 共通の設定（すべてのホストに適用される）
[all:vars]
ansible_ssh_user=root               # Linuxサーバ用のSSHユーザー
ansible_ssh_private_key_file=/path/to/private_key  # SSH接続に使う秘密鍵のパス
```



<br>
<br>

## 3. ローカルホストにPlaybookを流す方法
***Ansible管理用サーバとAnsible管理対象サーバが同一***の場合、
つまりAサーバで「Aサーバにユーザ作成するPlaybook」を実行したい場合には、インベントリファイルに他サーバと同様に***IPアドレスなどを記載するだけでは上手くいかない***ことがありました。

ローカルホスト（Ansibleを実行しているサーバー）にPlaybookを流すには、インベントリファイルにそう指定する必要があったようです。

<br>

#### ①インベントリファイルで指定
インベントリファイルに`localhost`を追加し、ローカルホストを指定する方法です。

```ini
# インベントリファイル（例: /etc/ansible/hosts）

[local]
localhost ansible_connection=local

```

`ansible_connection=local`を指定することで、ローカルホストでAnsibleがSSHを使わず直接操作できるようになります。

<br>
<br>

#### ②コマンドラインで指定
上記とは別の方法になりますが、コマンドラインでlocalhostを指定して、直接Playbookを実行することもできるようです。

```bash
ansible-playbook -i localhost, playbook.yml
```
このコマンドでは、インベントリファイルを指定する代わりに、`-i localhost`を使ってローカルホストを指定しています。

<br>
<br>

# まとめ
* ***Ansible管理用サーバ***と***管理対象サーバ***は、Ansibleが管理対象サーバに設定を適用するために連携する関係です。
* ***インベントリファイル***は管理対象サーバの情報を記述するファイルで、グループ分けやホストの追加ができます。
* ローカルホストにPlaybookを流す方法は、インベントリで`localhost`を指定するか、コマンドラインで直接指定する方法があります。


<br>
<br>

### 参考資料
https://e-words.jp/w/Ansible.html
https://www.miraiserver.ne.jp/column/about_ansible/
Google CloudRunにREST APIアプリをデプロイする

### Google CloudRunにREST APIアプリをデプロイしました
##### ChatGPTに教えてもらいながら作業してました。
なので、ChatGPTのログをシェアします。
Cloud Runは、課金してなくてもとりあえず動きそうです！
https://chatgpt.com/share/673da57a-9c48-8002-925d-2c07670fed90
https://chatgpt.com/share/673da67f-9fcc-8002-9209-dc957dbfbba9

- Github
https://github.com/sinzy0925/youtube

# 私の備忘録

```bash
pip install fastapi uvicorn python-dotenv pymongo youtube_transcript_api
```

```python
import os
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from pymongo import MongoClient
from dotenv import load_dotenv
from youtube_transcript_api import YouTubeTranscriptApi
import json

load_dotenv()

app = FastAPI()

# CORSミドルウェアを追加して、他のドメインからのリクエストを受け入れられるように設定
origins = [
    "http://localhost",
    "http://localhost:8080",
    "http://127.0.0.1:8000",
]
app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,  # 許可するオリジンを指定
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 字幕を取得する関数
def get_transcript(video_id: str):
    try:
        # 字幕を取得 (日本語字幕を優先)
        transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=['ja'])

        text = ""
        if transcript:
            for item in transcript:
                text += item["text"]
        else:
            print("字幕が見つかりませんでした。")

        text1 = {"text": text}
        # 字幕のリストを返す
        return json.dumps(text1, ensure_ascii=False)
    except Exception as e:
        print(f"字幕の取得に失敗しました: {e}")
        return {"error": "字幕の取得に失敗しました"}

# videoIdをクエリパラメータとして受け取るエンドポイント
@app.get("/transcript")
async def get_video_transcript(videoId: str):
    res = get_transcript(videoId)
    return res
```
    

- ローカルでアプリ起動
`uvicorn app.main:app --reload`
- 稼働確認
アプリが `http://127.0.0.1:8000` で起動します。
- curlで確認
`curl "http://127.0.0.1:8000/transcript?videoId=動画ID"`
######
- コンテナ
- ビルド
`docker build --no-cache -t my-fastapi-app .`

- docker起動
`docker run -d -p 8080:8080 my-fastapi-app`

- 稼働確認
アプリが `http://127.0.0.1:8080` で起動します。

- 異常時に確認
`docker logs <container_id>`
######

- 実行中および停止したコンテナをリスト表示
`docker ps -a`

- 不要なコンテナを停止
`docker stop <container_id>`

- 不要なコンテナを削除
`docker rm <container_id>`


######
- イメージにタグを付ける
- Google Cloud Container Registry (GCR) にプッシュするためには、タグを付ける必要があります
`docker tag my-fastapi-app gcr.io/cloudrun01/my-fastapi-app:latest`

- イメージをプッシュ
- タグ付けが完了したら、次にそのイメージをGCRにプッシュします。
`docker push gcr.io/cloudrun01/my-fastapi-app:latest`

######
- Cloud Runにデプロイ
- 次に、Cloud Runに新しいバージョンをデプロイします。gcloud run deployコマンドを実行します。
`gcloud run deploy my-fastapi-app \
  --image gcr.io/cloudrun01/my-fastapi-app \
  --platform managed \
  --region asia-northeast2 \
  --allow-unauthenticated
`

- 本番稼働確認
https://my-fastapi-app.run.app/transcript?videoId=tRgpuON_CsI
[OutSystems] String_SplitのDelimitersの罠にハマった

## はじめに
株式会社メディアテック所属の @mt-h2 です。
普段は OutSystems を利用したローコードでシステム開発を行っています。

今回は実装時にハマった小ネタになります。

:::note info
対象バージョンは OutSystems 11 となります。
:::

## 何があった
OutSystems の [TextAPI](https://success.outsystems.com/ja-jp/documentation/11/reference/outsystems_apis/text_api/) に用意されている [String_Split](https://success.outsystems.com/ja-jp/documentation/11/reference/outsystems_apis/text_api/#String_Split)
こちらを利用しようとしたところでハマりました。

公式ドキュメントでは、引数の Delimiters について以下のように記載されています。
> Contains all the characters that should be considered as separators.

DeepL翻訳したところ、以下となりました。
> 区切り文字とみなされるすべての文字を含む。

んん？
当初この意味がよく分からず、まぁいいかと気にせずいました。

実装では以下のような文字列に対して、「区切り文字列」の前後の文字を取得しようとしていました。
- 最初の文字列区切り文字列最後の文字列
  - 最初の文字列
  - 最後の文字列
  - ↑この2つを取得したい

まずは何も考えず以下のようにしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803085/dc947d07-a586-d590-97f9-55452c138d8a.png)
この結果、以下のようになると予想していました。

```
・String_Split.List[0].Text.Value = "最初の文字列"
・String_Split.List[1].Text.Value = "最後の文字列"
```

しかし、実際は以下のようになりました。

```
・String_Split.List[0].Text.Value = "最初の文字列"
・String_Split.List[1].Text.Value = ""
・String_Split.List[2].Text.Value = ""
・String_Split.List[3].Text.Value = ""
・String_Split.List[n].Text.Value = ""
・String_Split.List[LastIndex].Text.Value = "最後の文字列"
```
何故か空文字の配列が複数あります。

諸々調べたところ、Delimiters に指定した文字はその文字列を1つの塊として Split されるのではなく、**指定した文字列を1つずつ Split する**挙動のようでした。

上記で言うと、区 で Split、切 で Split、 り で Split... と実行されているようです。
これにより謎の空文字配列が生成されていました。

ここで改めて公式ドキュメントを確認すると、この説明の意図する事がそこにあったのだと理解しました。
ニホンゴムズカシイ...

これを前提に、今回は以下のように区切り文字を1文字に Replace したうえで Split する事で対応しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3803085/e48abb12-c67d-ff6b-17f0-d29608038ace.png)

## あとがき
理解の難しい公式ドキュメント（某msdn等）が多々ありますが、理解していたつもりがこう言った状態に陥る事があるので少しでも理解できない事があれば、実装前にサッと検証すべきだと思った寒空でした。

## さいごに
株式会社メディアテックでは絶賛 [開発メンバを募集中](https://www.mediatech.jp/recruit) です。
ローコード開発だけではなく、RPAやBIエンジニア諸々多数の募集をしておりますので、みなさまのご応募をお待ちしております。
帯域と遅延を保証する方法

# 常に無駄な時間がありそのため未処理のトラフィックが発生する
>ルーターがフロー仕様がどのようにして特定のリソース予約の集合で表現するかという問題が生じる。例えばルーターが1Gbpsで動作するリンクを持ち、平均パケット・サイズが1000ビットであれば、一見したところ、1秒あたり、100万パケット処理できるように思われる。しかし、この考えは正しくない。なぜなら、`負荷がかけられた際に発生する統計的な変動によって起こる無駄なCPU時間が常に存在`するからである。仮にリンク容量を１ビットでも無駄にするとトラフィックを処理しきれないとすると、リンクが数ビット分の`アイドル状態になっただけでも未処理のトラフィックは発生`し、そのトラフィックは２度と処理できないことになる。
p391

* M/M/1の式を使う
* 例では結果600μsかかってしまう
* 少しの遅延でも未処理のトラフィックが発生してしまう

# 帯域を保証
>(R,B)トークン・バケツでシェイピングを行うトラフィック源と、WFQを備えたルーターを想定している。それぞれのフローに対するWFQの`重みWは、トークン・バケツのレートRで十分流せる大きさ`とする。例えば、フローの送信レートが1Mbpsであり、ルーターと出力リンクが1Gbpsの容量を持つと、フローに対する重みは、その出力リンクに対するルーター上の全フローの重み総和の1/1000より大きくなければならない。これにより、`フローに対して最小帯域を保証`することができる。もし十分な大きな`送信レートを確保できない場合は、そのフローを受け入れる`ことはできない

# 遅延を保証
>フローが遭遇するキューによる遅延の最大値は、トークン・バケツのバーストのサイズによって決まる。２つの極端なケースを考えてみよう。もしトラフィックが平滑で、いかなるバーストも存在しなければ、パケットはルータに到着後すぐに出力リンクへ出ていくことになる。この時キューによる遅延は発生しない。一方、トラフィックがバーストにより蓄えられた場合、`最大バースト（大きさB）が一度にルーターへ到着する可能性`がある。この場合、キューにおける遅延の最大値Dは、この`バーストを保証された帯域で流すのに要した時間、すなわちB/R`となる（ここでもパケット化の影響は無視する）。この`遅延が大きすぎると、フローはネットワークからさらなる帯域を要求`しなければならない
p392

# 
> トークン・バケツによってバースト性を制限するとともに、公平キューイングによって帯域がフローごとに互いに独立になるようにしている。これにより、`各フローは競合する他のフローがルーター上でどのように振る舞うかに関わらず、帯域と遅延を保証`することができる。
P392

# 感想
トークン・バケツでシェイピング、WFQを組み合わせて帯域と遅延を保証することだけしかわからかなkった。
細かな内容は理解できなかった。
今まで学んできた体感品質QoEを高める工夫を組み合わせて保証していた。
alarm lambda

```
import json
import boto3
from datetime import datetime, timezone

# SNS クライアントを初期化（メール通知用）
sns_client = boto3.client('sns')

# SNS トピック ARN をご自身のものに置き換えてください
SNS_TOPIC_ARN = 'arn:aws:sns:your-region:your-account-id:your-topic-name'

def lambda_handler(event, context):
    # デバッグ用にイベントを出力
    print("Received event: " + json.dumps(event))
    
    # CloudWatch Alarm からのイベントを解析
    alarm_data = event.get('alarmData', {})
    alarm_name = alarm_data.get('alarmName', '')
    state = alarm_data.get('state', {})
    reason = state.get('reason', '')
    region = event.get('region', '')
    timestamp = state.get('timestamp', '')
    metrics = extract_metrics(alarm_data.get('configuration', {}))
    
    # 日付と時刻のフォーマットを調整
    occurrence_time = format_timestamp(timestamp)
    
    # 比較のために小文字に変換
    reason_lower = reason.lower()
    alarm_name_lower = alarm_name.lower()
    
    # 第一段階のフィルタリング：reason に特定のキーワードが含まれるかチェック
    if ('no datapoints' in reason_lower) or ('insufficient data' in reason_lower) or ('unknown' in reason_lower):
        # メール A - データ不明
        subject = '【データ不明】アラームが発生しました'
        message = f'''発生時間：{occurrence_time}
発生アラーム名：{alarm_name}
発生メトリクス：{metrics}

理由：
{reason}

詳細はdevops環境のAWS Cloudwatchコンソールでご確認ください。'''
        send_email(message, subject)
    else:
        # 第二段階のフィルタリング：alarmName に特定のキーワードが含まれるかチェック
        if 'warning' in alarm_name_lower:
            # メール B - 警告
            subject = '【警告】アラームが発生しました'
        elif 'danger' in alarm_name_lower:
            # メール C - 危険
            subject = '【危険】重大なアラームが発生しました'
        else:
            # メール D - アラーム状態
            subject = '【アラーム状態】アラームが発生しました'

        message = f'''発生時間：{occurrence_time}
発生アラーム名：{alarm_name}
発生メトリクス：{metrics}

理由：
{reason}

詳細はdevops環境のAWS Cloudwatchコンソールでご確認ください。'''
        send_email(message, subject)

def extract_metrics(configuration):
    """
    メトリクス情報を抽出して文字列にフォーマット
    """
    metrics = configuration.get('metrics', [])
    metric_list = []
    for metric in metrics:
        metric_info = metric.get('metricStat', {}).get('metric', {})
        namespace = metric_info.get('namespace', '')
        metric_name = metric_info.get('name', '')
        dimensions = metric_info.get('dimensions', {})
        dimensions_str = ', '.join([f"{k}={v}" for k, v in dimensions.items()])
        metric_list.append(f"{namespace}/{metric_name} ({dimensions_str})")
    return '; '.join(metric_list)

def format_timestamp(timestamp_str):
    """
    タイムスタンプ文字列を日本時間にフォーマット
    """
    if timestamp_str:
        # タイムスタンプをパース
        timestamp = datetime.strptime(timestamp_str, '%Y-%m-%dT%H:%M:%S.%f%z')
        # 日本時間に変換
        jst_time = timestamp.astimezone(timezone.utc).astimezone(timezone(offset=timezone(timedelta(hours=9))))
        return jst_time.strftime('%Y-%m-%d %H:%M:%S %Z')
    else:
        return 'N/A'

def send_email(message, subject):
    response = sns_client.publish(
        TopicArn=SNS_TOPIC_ARN,
        Message=message,
        Subject=subject
    )
    print('Email sent! Message ID:')
    print(response['MessageId'])
```
Google Homeで家のセキュリティを組んでみよう！

## google Homeのスクリプトが便利になっている。
最近、住んでいるエリアで闇バイトによる殺人などもあり、子供を守るために何かできないかと、google homeを導入して、夜中庭に立ち入る人がいたら家の中でアラームを鳴らす仕組み導入しました。

導入にあたり、google homeのスクリプトが便利で警告内容もテキストを書けばそのまま音声にしてくれるなど便利だったので、紹介です。

## 導入したもの
導入したものは以下です。ほぼメルカリで入手したりポイントで購入して、全部で４万円ほどでした。
- [Google Nest hub](https://store.google.com/jp/product/nest_hub_2nd_gen?hl=ja)
- [Google Nest Mini](https://store.google.com/jp/product/google_nest_mini?hl=ja)
- [Google Home Doorbell](https://store.google.com/jp/product/nest_doorbell_battery?hl=ja)


## どのように導入するのか？
1. googleアカウントで、google homeを設定する
2. googleのデバイス類をGoogle homeに登録していく
3. ブラウザから[google home](https://home.google.com/)を開き、自動化タブを選択
4. 新たに追加からスクリプトエディタが出てくるので、組みたいように組む
    -  ![スクリーンショット 2024-11-20 17.17.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266357/96224c5d-5f83-8f1e-34f3-e8f5c4666048.png)


## 実際組んでみた具体例
Google Home Doorbellで夜11時から朝6時の間で庭に動く物体を検知したら、Google Nest hubとGoogle Nest Speakerで家主に連絡します。
```yaml

metadata:
  name: emergencie when someone into yard
  description: Scripted automation

automations:
  starters:
    - type: device.event.MotionDetection
      device: 玄関のドアホン - 玄関
  condition:
    type: time.between
    before: 06:00
    after: 23:00
    weekdays:
      - MON
      - TUE
      - WED
      - THU
      - FRI
      - SAT
      - SUN

  actions:
    - type: home.command.Notification
      title: 夜中に家に入っている人がいます。
      body: 夜中に誰か庭に侵入しています。
      members:
        - ownself@gmail.com
        - myfamily@gmail.com
    - type: assistant.command.Broadcast
      message: 侵入者です。対応してください。侵入者です。対応してください。侵入者です。対応してください。侵入者です。対応してください。侵入者です。対応してください。侵入者です。対応してください。侵入者です。対応してください。侵入者です。対応してください。
      devices:
        - キッチン - キッチン
        - 寝室 - 寝室

```

## 実際動かしてみるとこんな感じ

https://youtube.com/shorts/F5y95NF41rI?feature=share


## 後一歩足りないと思うこと。
スクリプトのauto complete機能はかなりちゃんとできてるので、初心者でも迷わずにできるので好印象でした。

ただ、google home door bellはトリガーを組んでも、音声をしゃべらせることができず、侵入者に警告するには別のスピーカーを用意する必要があったり、テキストを音声にはできても、警告音を鳴らすなどはできないようです。

その他、トリガーはたくさん用意されているのですが、アクションできることがまだ少ないので、今後に期待したいと思っています。

## 今後
今後は、自分たちに知らせるだけではなく、侵入者に警告したり、顔認証によって警告の有無を決定していくように改善予定です。
【誰でも使える！】効果的なミーティングを実現する5つのテクニック


## はじめに
無駄なミーティングが多い、意見がまとまらない、そもそも何のための会議か分からない…。  
そんなミーティングの課題に悩むエンジニアやマネージャーは少なくないはずです。

この記事では、実際の現場で試して効果があった「効果的なミーティングを実現する5つのテクニック」を共有します。  
時間を有効活用し、成果を最大化するヒントを探している方に役立つ内容です。

---

## 1. アジェンダは「30秒で伝えられる」形にする
- **ポイント:** アジェンダが曖昧だと、ミーティングが脱線しがちです。  
  「30秒で説明できるアジェンダ」を用意し、全員が理解した状態でミーティングを始めましょう。
- **具体例:**  
  - 悪い例: 「次回リリースについて話し合う」  
  - 良い例: 「次回リリースのスコープを決定する（選択肢A or Bを議論）」

---

## 2. 必須メンバー以外は招待しない
- **課題:** メンバー全員を呼びがちですが、全員が議論に参加する必要はありません。  
- **解決:** 以下の3つの基準でメンバーを選定します。
  - 決定に関与する人
  - 必要な情報を提供する人
  - 進捗を共有する必要がある人
- **メリット:** コンパクトなミーティングが実現し、全員の集中力も向上します。

---

## 3. 発言者を明確に割り振る
- **理由:** 無秩序なミーティングでは、結局声の大きい人の意見だけが通りがちです。  
  発言者を事前に割り振ることで、全員の意見を公平に引き出せます。
- **具体例:** 
  - アジェンダごとに「担当者」を設定する。
  - 会議中にモデレーターを置き、議論を制御する。

---

## 4. タイマーを活用して時間を管理
- **課題:** 予定の時間をオーバーしてしまう。  
- **解決策:** タイマーを活用して「各アジェンダの時間配分」を厳守します。
- **ツール例:**  
  - Trello + Pomodoroタイマー  
  - Googleカレンダーのリマインダー機能

---

## 5. ミーティング後のアクションアイテムを明確化
- **目的:** ミーティングが終わった後も行動が伴わない場合、時間の無駄になります。  
- **実践:** ミーティング終了時に以下を確認します。
  - **何をするか:** アクションの具体内容
  - **誰がやるか:** 担当者
  - **いつまでに:** 期限を設定

---

## まとめ
この記事では、ミーティングを効率化する5つのテクニックを紹介しました。  
これらを実践することで、無駄な会議が減り、チーム全体の生産性が向上します。

あなたの現場で実践した結果や、別のアイデアがあればコメントで教えてください！  
イイねやストックもぜひお願いします！
AppleシリコンのMacでのC#実行環境

# まず最初に
2024年8月31日、Visual Studio for MacがVer17.6を最後にサービス終了してしまいました。
MacでC#を勉強している私にとってかなり衝撃的でした。
でも結局Visual Studio Codeになんか色々入れるということでMacでのC#実行環境を確保できたので記事に書きます。
# 余談(失敗談)
気合いでVisual Studioを実行しようとして失敗した話です。無視して構いません。
## Whiskyを使ってみた話
MacでVisual Studioが使えなくなると聞いて最初に試したのが「[Whisky](https://getwhisky.app/ja/)」というオープンソースのソフトを使って無理やりWindows用のVisual Studioを実行することでした。
しかし、Appleシリコンとの相性が悪く、セットアップすらできずにプロセスがフリーズしてしまいました。その後もWhisky以外の様々なソフトを使って試しましたが結局結果は変わらず、Visual StudioをMacで動かすのは不可能という結論になりました。
# 実際にVisual Studioを使った実行環境を構築する
実行環境を構築します。
## 必要なもの
- Visual Studio Code
- .NET Core
- Visual Studio Codeの拡張機能諸々
## Visual Studio Codeのインストール
[Microsoftの公式ダウンロードサイト](https://code.visualstudio.com/download)からインストーラーをダウンロードできます
`.zpi`ファイルがダウンロードされますが、Safariだと`.zip`ファイルが非対応なのでダウンロードする際はChromeやFireFoxなどの`.zip`対応のブラウザを使いましょう。
`.zip`ファイルを展開するとVisual Studio Codeのアプリケーションが出てきて、それを`Application`フォルダに移動したら完了です
## .NET Coreのインストール
### .NET Coreとは？
.NET は、さまざまな種類のアプリケーションを構築するための、無料のクロスプラットフォームのオープン ソース開発者用プラットフォームです。(Microsoft公式)
要は、アプリケーション開発に必要なものを提供してくれるということです。
### 実際にインストール
[Microsoftの公式サイト](https://dotnet.microsoft.com/en-us/download/dotnet)からダウンロードできます。
.NET8.0と.NET9.0の2つが選べます。8.0のような偶数番号は長期サポート版ですが8.0も9.0もサポート期間にあまり変わりはありません。
Mac版を選ぶと、`.pkg`ファイルがダウンロードされます。
![dotnet-installer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3888231/3741ef05-c070-1bdf-fb36-5888bd387038.png)
実行するとインストール先や種類などが聞かれるので、適当な場所に決めてインストールしてください。
## Visual Studio Codeの拡張機能
C#を利用する前にVisual Studio Codeにいくつかの拡張機能を入れると便利です。
### C#
.NET Coreでの開発をサポートしてくれます。プロジェクトの管理、デバッグなどの機能がついてます。
![c-sharp-extantion.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3888231/96ead871-72ba-e59c-d8cf-bb37fdd13c31.png)
### Japanese Language Pack
Visual Studio Codeは基本的に英語です。Japanese Language PackはVisual Studio Codeを日本語化してしくれます。![japanese-extention.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3888231/32280248-dd7f-a191-5035-eb567c66cb3f.png)
### C# Dev Kit
通常のC#拡張機能の上位互換です。具体的には、デバッグの種類が富んでいたり強力なコード補完が可能になります。通常のものよりリソース消費が多くなるので、スペックに難がある場合は推奨しません。
C# Dev Kitを入れると、IntelliCodeなどの拡張機能も同時にインストールされます。![c-sharp-dev-kit-extention.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3888231/18c878a7-61b7-2228-c259-7dc2306e89e7.png)
## プロジェクトを作る
Macのターミナルで以下のコマンドを実行します

    mkdir new-project
    cd new-project
    dotnet new console
このコードは、`new-project`ディレクトリを新たに作成してそこにC#プロジェクトを作成します。
### フォルダを開く
Visual Studio Codeのメニューにある「ファイル」->「フォルダーを開く」から先ほど作った`new-project`を開きます。
![newproject-window.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3888231/79ae6b81-082f-8ed6-5034-db4a5a16f90b.png)

すると、このような画面が出てくるので、下のターミナルで

    dotnet run
を実行します。

    Hello, Wirld!
と出てきたら成功です。
# 参考文献
https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp

https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.vscode-dotnet-runtime

https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit

https://code.visualstudio.com/download
Tips #022 キャンバスアプリでマスタから値をLookUpしたいゾ

Prev Tips

https://qiita.com/Novskiiiiiiiiii/items/f5f330dd26da5c8a5ddd

キャンバスアプリでテキスト入力フィールドに部門コードを入力した際に、
部門マスタからルックアップしてラベルに部門名を表示させる方法をメモしておく。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3891071/4b2b0d04-17ee-dda1-53dd-7ae5dfb5d8dc.png)

こんな感じで、部門コード 7719 を入力した時に、部門マスタから部門名を取ってきて
ラベルに表示させたい。

仕組みは非常にシンプル。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3891071/0ccd2bb8-a3af-c2ab-df96-8c78b8f2c3d4.png)


    LookUp(マスタ名, マスタの照合項目 = フォーム上の入力フィールド.Text, 表示させたいマスタの項目)

フォーム上で様々なマスタと連携させたいという要望はよくある話かと思うのでこれを活用しよう。

以上

続編はこちら

https://qiita.com/Novskiiiiiiiiii/items/d3c4a919add7898777ae
京都初！24時間無人システムのコワーキングスペース

## 働く場所の新常識、いつでも利用可能な快適な空間 ##

![place_kyoto.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784576/a10dcc76-6762-8068-eada-8164cec29493.jpeg)

2024年11月、世界的な観光都市である京都の中心に新しくオープンした「＋C KYOTO」2号店は、仕事と余暇を同時に楽しむことができるワーケーションスペースとコワーキングオフィスとして注目を集めています。この空間は、京都を訪れる観光客とリモートワーカーに最適化された施設とサービスを提供し、多様な働き方と余暇を融合させた体験を提供します。

京都は旅行するには美しい街ですが、働く人々にとっては自分専用の作業スペースが少ないという不便さがあります。他の国のように電源コンセントをすぐに使えるカフェなどのスペースが限られています。

「プラス C 京都」では、さまざまなニーズに応えるために、旅行者とリモートワーカーを考慮した空間設計を導入し、休息と業務をバランスよく楽しめるように、個別の作業スペースやモニター、ミーティングスペースなど最適な設備を完備しています。

また、京都のメインエリアに位置し、京都初の24時間無人運営サービスを実施しています。兵庫県尼崎市に1号店をオープンし、運営ノウハウを基に京都2号店で無人キオスクシステムを導入しました。

現在、「＋C KYOTO」では日本での利用者のために、別途韓国語対応のスタッフを配置し、利用の不便さを感じさせないようサポートを充実させています。

「＋C KYOTO」の所在地は、京都府京都市中京区姉小路通寺町西入姉大東町546、3階にあります。





出典: [ニュースタイムズ](https://newstimes.jp)
ConoHa VPS でのkusanagi環境の「All-in-One WP Migration」のあれこれ

## 概要
ConoHa VPS で、kusanagi環境のWordPressを利用する中で、「All-in-One WP Migration」を利用する際のメモ

### 問題となる事象
「All-in-One WP Migration」をインストール後、有効化するとエラーが出ます

### 対処方法
#### 「wp-content/ai1wm-backups」が作成できないエラー
wp-contentのパーミションを775に変更することで解消

#### 「/wp-content/plugins/all-in-one-wp-migration/storage」が作成できない旨、その中にファイルを生成できない旨のエラー

FTPかコマンドで「/wp-content/plugins/all-in-one-wp-migration/storage」を作成し、
所有者「kusanagi」
グループを「www」
パーミションを「775」
に設定

上記作業後、プラグイン一覧画面を更新すると、エラー表示が消えます


## その他の課題
### ConoHa VPS kusanagiでの容量制限の対処方法
以下が参考になりました。
https://pecoegg.com/800
MAMPのアップデート録

# 初めに
MAMPが起動しなくなったのでいろいろ調べて回りました、どうにかなったので備忘録として書きました。環境はmacです。

#### MAMPアプリ内エラーが出る
アプリを開いてスタートするとこのようなエラーが出ます。
再起動やポートなど確認するでも特に変わりないので調べるとアップデートが必要とのこと。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3509676/6b1e66a1-c69e-7507-1f52-720fd94cd513.png)

調べるとやることはシンプルなようで[MAMPの公式](https://www.mamp.info/)に飛んでインストールするだけらしい。

#### 注意点
MAMPフォルダはあらかじめバックアップを取る
以上


#### 参考

https://www.webdesignleaves.com/pr/plugins/mamp_error_apache.html

https://www.webdesignleaves.com/pr/plugins/mamp-update.html

#### 追記
MAMPをインストールの後、MAMP.appの行方がわからずかなり焦っていましたが、よく見るとインストールされたMAMPフォルダに入ってて安心しました。
ディレクトリ的には
/Application/mamp/mamp.app
なのですが
自分がインストール前の状況だと
/Application/mamp.appと/Application/mamp/の
アプリとフォルダを分けていたので
インストール後は/Application/mamp.appの右クリックで情報を見ると
６系でアップデートできてねーじゃん！と焦りました。
ちゃんと確認は必要ですね…
雑な記事ですが以上です。
EvaDBで非構造化データを検索しよう - DBにもAIの力を -

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110418/c5b641b4-df8e-b956-7eef-749a5163c0e1.png)

https://github.com/georgia-tech-db/evadb

## 何ができるのか

**画像**や**動画**、**PDF**などの**非構造化データ**を
DBレコードと同じように**SQLクエリ**で扱うことができます。
すごい便利そうですね！

非構造化データ置き場所としての接続先は下記などが可能です。
- **ローカルファイルストレージ**
- **AWS S3バケット**

## どのように使用するのか

まずEvaDBを使用するにはPythonインタプリタが3.9以上であることが必要です。
pythonにて下記のようにインストールします。

```Shell
# Python仮想環境を作成します。
python -m venv evadb-venv

# 仮想環境の立ち上げ：MacOSの場合
source evadb-venv/bin/activate
# 仮想環境の立ち上げ：Windowsの場合
evadb-venv\Scripts\activate.bat

# 関連ライブラリの更新とEvaDBの最新化
pip install --upgrade pip setuptools wheel
pip install --upgrade evadb
```

EvaDBは既存のDBに接続してINDEXを作成し、そこにデータソースを読み込んで使用します。



接続は下記のようにDBカーソルを取得します。
```python
import evadb
cursor = evadb.connect().cursor()

# クエリの実行
cursor.query("SHOW FUNCTIONS;").df()
```

ストレージから検索先のデータをどうロードするかというと下記のクエリを実行
```
# 動画かつS3の場合の例：AWS S3上のmnist.mp4という動画をMNISTVidというテーブルへ保存
LOAD VIDEO 's3://bucket/eva_videos/mnist.mp4' INTO MNISTVid;

# 画像かつローカルの場合の例：
LOAD IMAGE 'reddit-images/*.jpg' INTO reddit_dataset;
```

これ、どこに保存されているかというと、デフォルトではevadb_dataというローカルフォルダに保存されているそうです。このフォルダ管理が運用時の肝になりそうですね。

公式に記載されているサンプルですが、例えばあるサイトのレビューとして画像やPDF、動画データからネガティブなレビューがあるかを下記で検索しています。
```SQL
# 
SELECT
    ChatGPT("Respond to the review with a solution to address the reviewer's concern",
    review)
FROM
    postgres_data.review_table
WHERE
    ChatGPT("Is the review positive or negative?", review) = "negative";
```

詳しくは公式ドキュメントに。
https://evadb.readthedocs.io/en/latest/index.html

## 今後への期待

まだバージョンが0.3.10となっているため正式リリースとはなっていないようですが、今後のロードマップとして多様なデータソースへの対応やSKLearnとの連携などデータサイエンス分野連携も予定されているようです。

HuggingFaceにある学習モデルを使用したり、トレーニングをさせることなどもできるようなので次世代のDBとして期待できるように思いました。
DockerでJavaの実行環境をさくっと作る

あくまで検証やちいさなプログラムを実行する目的として、Javaのポータブルな実行環境をDocker Composeでサクッと構築します。

## 環境
```
$ cat /etc/debian_version 
12.8
```

```
$ docker --version
Docker version 27.3.1, build ce12230
```

## Dockerでの環境構築
まず[MicrosoftのOpenJDK](https://learn.microsoft.com/ja-jp/java/openjdk/containers)イメージを使って、Docker Composeファイルを記述します。

```compose.yaml
services:
  app:
    image: mcr.microsoft.com/openjdk/jdk:21-ubuntu
    volumes:
      - .:/app
    working_dir: /app

```

適当にHello Worldするプログラムを配置します。

```Main.java
public class Main {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}
```

あとは、以下のコマンドでコンパイルして実行します。

```sh
$ docker compose run --rm app sh -c "javac Main.java && echo 'compiled!' && java Main"
```

## 参考
- [JavaのDockerイメージ何選ぶ？ \| フューチャー技術ブログ](https://future-architect.github.io/articles/20211220a/)
自動車修理に 3D プリントを使用する利点は何ですか?

技術の進歩に伴い、3Dプリント技術は自動車修理分野での応用が広がっています。特に3Dスキャナーとの組み合わせにより、修理プロセスが効率的かつ正確で経済的になっています。  

**1. 部品の精密な再現**  
旧型車や生産終了車両の修理では、適切な部品の入手が困難な場合があります。3Dスキャナーを使用して破損した部品の3Dデータを取得し、3Dプリンターで精密な代替部品を迅速に製造することが可能です。例えば、クラシックカーの希少部品もスキャンとプリントで正確に再現できます。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/f8b87d7a-36b7-4ebc-c6f6-a2f4d8477d14.png)

**2. 修理コストの削減**  
従来の部品製造には金型が必要で、コストが高額になります。一方、3Dプリントは金型を必要とせず、直接プリントすることで廃材を削減し、小ロット生産の費用を抑えることができます。また、修理工場は大量の在庫部品を抱える必要がなく、必要に応じて部品をプリントすることでさらにコストを削減できます。  

**3. 修理期間の短縮**  
部品の発注には数週間かかる場合がありますが、3Dプリントなら数時間で部品の製造が可能です。例えば、3Dスキャナーでモデルを迅速に生成し、プリンターで部品を作成すれば、修理時間を大幅に短縮し、車両を早期に復帰させることができます。  

**4. カスタマイズ設計の実現**  
3Dプリントは車両所有者の個別ニーズにも対応します。ユニークな装飾部品や機能部品のデザインをカスタマイズでき、車両に個性を加えることが可能です。  

**5. 環境に優しい持続可能性**  
3Dプリントは材料利用率が高く、廃材を削減します。また、リサイクル可能な材料を使用することで、自動車修理業界に環境に配慮したソリューションを提供します。  

**3Dスキャナーとプリントの連携**  
3Dスキャナーは自動車修理で重要な役割を果たします。破損部品をスキャンしてデジタルモデルを生成し、プリント部品が元の部品と完全に一致するようにします。また、修理工場はデジタル部品ライブラリを作成し、将来の修理に役立てることができます。  
![7e0f791b5735cd27edf57e096d3c1509.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/c2f7adf3-530d-6c4c-0de9-234f90a578aa.png)
![d1c5e2f5eb51a92ddc3e590f28ef187d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/7e098032-eefe-9b76-c4c9-52e645c941ff.png)

https://www.revopoint3d.com/


**まとめ**  
3Dプリントと3Dスキャナー技術の組み合わせは、自動車修理の方法を革新しています。部品の精密な再現からカスタマイズ設計まで、この技術は修理を効率的かつ経済的で環境に優しいものにします。将来的に、3Dプリントは自動車修理の標準装備となるでしょう。あなたも3Dプリントを使った修理の便利さを体験したことがありますか？ぜひ体験談をお聞かせください！
Power Apps で SharePoint リストのユーザーまたはグループ列 (複数選択を許可) でフィルターをする


# はじめに

以下のように、担当者とは別に共同担当者を設定し、Power Apps のアプリ上、自分が担当者の場合、もしくは、自分が共同担当者に入っている場合、データを参照したり編集できるようにしたいケースあると思います。

この際、共同担当者は案件により人数が変わるかもしれないため、ユーザーまたはグループ列で複数選択を許可します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/6a762e10-3f55-c9e0-6011-1234309ba66e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/fcc59b7a-67fe-c5a6-cd28-22b59a5d963c.png)

この際、Power Apps 側でフィルターするアプローチについて、悩まれる方もいると思うため、方法を整理しておこうと思います。

# アプローチ

まず、以下のようなイメージになるかなということで、式を書いてみましたが、共同担当者.Email といった感じで指定することができませんでした。ユーザーまたはグループ列で複数選択を許可すると Power Apps での扱いが少し難しくなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/9931fc77-4fc4-3b64-7004-df53a3253317.png)

イメージとしては、ユーザーまたはグループ列で複数選択を許可すると、イメージとしては以下のような構造で、ユーザーに関する複数の情報を持つことになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/4d3332cc-4d90-74f5-66fe-fad7b83553be.png)

解決策は以下のような感じです。

まず、以下のようにして、SharePoint リストの情報をコレクションに格納し、複数行ある共同担当者の Email 列だけ取り出して、Concat 関数で一つの文字列にします。一つの文字列にするにあたって、今回は、カンマ (,) で結合しています。そして、その文字列を AddColumns 関数で新しい列 (共同担当者Email) に代入します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/5944542e-a03d-c380-d7d0-7d58b027f67d.png)

共同担当者Email という新しい列は、アドレス1,アドレス2 といった文字列になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/d16fc662-d5ec-6adc-2eef-ddda590528aa.png)

そして、作成されたコレクションに対して以下のような式でフィルターをします。
共同所有者Email はアドレスが結合された文字列のため、その文字列に自分のメールアドレスが入っているか in 演算子で判定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/cde9f577-2987-1290-70c7-81d8331164b5.png)

こちらで、ユーザーまたはグループ列 (複数選択を許可) である、共同担当者列に自分が含まれているデータをフィルターして表示することができました。
【Salesforce】条件によって値が定まるロジックを数式側に持たせる

Salesforceでシステム開発を行っていて、条件分岐系のロジックを数式項目で実装すると管理しやすくなるな、と思ったのでシェアします。

レコード保存時、「担当部署」選択リスト項目の値に応じて、宛先を動的に切り替えてメールアラートを送信する、という要件がありました。
大した要件ではないので素直にトリガーフローを作成して、その中で条件分岐のロジックを実装する、というのはあるあるだと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1336848/c3a1461a-2d66-a7c8-127d-e83be75ad822.png)

これでも良いっちゃ良いんですが、分岐の数が増えたりするとフローがごちゃついて管理が大変になってきます。

ここで、条件分岐のロジックを数式に持たせるのはどうでしょう。

メリット1：変更に強い
仕様変更があっても、フロー（やApexなど）の実装部分に手を加える必要がない。
修正箇所が直感的に理解でき、場合によっては非エンジニアでも対応可能。

メリット2：デバッグしやすい
今回の例だと実際にトリガーフローを起動してメール送信しなくても、どの宛先に送信しようとしているかはレコードの詳細画面から数式の値として確認できる。


以下、サンプルの実装です。
~~~Apex:対応部署メールアドレス（数式） CurrentDivisionMailAddress_formula__c
case( CurrentDivision__c
    , "部署A", "bushoA@test.co.jp"
    , "部署B", "bushoB@test.co.jp"
    , "部署C", "bushoC@test.co.jp"
    ,          "bushoD@test.co.jp"
)
~~~

メールアラートの宛先はメールアドレス項目のみ設定可能なので
数式のテキスト値を別項目にコピーする処理が必要です。
今回の対応では、フローを2つ用意しました。
（フロー1と2をまとめてしまっても期待どおり動くかどうかは未検証です。）

フロー1：アドレスコピー用
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1336848/57505386-8aea-e4f8-34ce-ea2d144681de.png)

フロー2：メールアラート送信用
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1336848/d8d61630-8922-0b11-9ff4-47b1fbd6fb22.png)

フロー1、2の順番で実行しないと意味がないので、フローのプロパティからトリガー順序を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1336848/e58ada75-fc6f-9670-e38f-ad8e8ff8178b.png)


ロジックの複雑さ加減にもよるので何でもかんでも数式化する必要はありませんが、結構採用頻度の高いテクニックだと思います。

こちらの記事も根っこは同じ思想ですね。
（数式を活用してできるだけ簡潔に業務要件を整理する）

[「〇年縛り契約」→「次回契約更新月」を数式で表現する](https://qiita.com/kagehikozaemon/items/99bbf1ba17a0b279bd55)
フロー仕様

# 送信元が宛先、経路上の全てのルーターに対しての許容できるリソースを知らない
>フローを受け入れるか拒絶するかはを決めることは、フローが要求しているリソース（帯域、バッファ、容量、CPUサイクル）とルーターの持つそれらの許容量を比較すれば良いという単純な問題ではない。それはもう少し複雑である。まず、必要な帯域がわかっているアプリケーションもあるかもしれないが、`ほとんどのアプリケーションはバッファ容量やCPUサイクルについて知ることができない`。このため、最低でも、`フローを表現し、その表現をルーターのリソースに変換するため、何らかの別の方法が必要`となる。

# アプリケーションごとにフローの許容が違う
>最後に、フローのパラメータを変更しようとするアプリケーションもあれば、そのようなことを求めないアプリケーションもある。例えば、通常は１秒間に３０フレームで動作する動画ビューワが１秒間に`３０フレームをサポートするのに十分な帯域がなければ、１秒間に２５フレームに落とそうとする`かもしれない。同様に、１フレームあたりのピクセル数や、音声の帯域、その他の属性を適合させようとするかもしれない。

# 送信者がフロー仕様をつけて経路のパラメータを変更させる
>多くの関係者（送信元、宛先、経路上の全てのルーター）がフローの交渉に関わってくるので、フローは、交渉可能な特別なパラメータを用いて正確に表現されなければならない。それらのパラメータの集合を`フロー仕様(flow specitication`と呼ぶ.典型的には、`送信元（例えば、ビデオ・サーバーなど）が利用したいパラメータを記述したフロー仕様を生成`する。その仕様がルート上に伝搬すると、それぞれの`ルーターはそれを検査し、必要に応じてパラメータを修正`する。この修正はフローを`減らすことのみが可能で、フローを増やすことはできない`。（低い転送レートにすることはできるが、高い転送レートにすることはできない)。宛先に到着するとパラメータが確立される。

https://bookplus.nikkei.com/atcl/catalog/23/03/16/00728/

# 感想
フロー仕様をつけてルーターなどの通るものに対してバイトorパケットのパラメータの特徴を知らせて対応してもらう
undefined method os_version' for nil (NoMethodError) エラーの解消手順

# Fastlane Snapshot 使用時のエラー対処法

Fastlaneを使用してスクリーンショットを自動生成する際、次のようなエラーが発生しました。
`undefined method os_version' for nil (NoMethodError)`

```詳細.
/opt/homebrew/Cellar/fastlane/2.225.0/libexec/gems/fastlane-2.225.0/fastlane_core/lib/fastlane_core/device_manager.rb:135:in latest_simulator_version_for_device': [!] undefined method os_version' for nil (NoMethodError)
              .os_version
              ^^^^^^^^^^^
```

## 原因
エラーの原因は、Fastlaneが対象のシミュレーターを見つけられないことに起因しています。この問題は、`Snapfile`やXcodeの設定で、シミュレーターが正しく指定されていない場合、またはサポートされていないデバイスが指定されている場合に発生することが多いです。

### おもな原因
- Fastlane がデフォルトで「Mac」をデバイスとして選択している。
- Xcode のベータ版を使用していたり、特定の設定が正しくないこと。

## 解決方法
このエラーを解決するために、以下の手順を試してください。

1. **サポートされているデバイスの設定確認**
   - `Snapfile` (または `Fastfile`) 内でのデバイス指定方法が正しいことを確認します。以下のように設定されている必要があります：
     ```ruby
     devices(["iPhone 16"])
     ```
   - 上で指定したデバイスが、Xcode の上部タブ内の `Window` -> `Devices and Simulators` で表示されるデバイスまたはシミュレーターの一覧に表示されていることを確認します。

   ![デバイス一覧の確認](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3525158/4df14f38-f616-7518-7cf5-d5de276c17bf.png)

   - デバイス一覧は `xcrun simctl list devices available` コマンドでも確認可能です。

2. **Macを削除**
   - XcodeのUITestsのTargets内にある「Supported Destinations」から「Mac」を削除します。これにより、Fastlaneがシミュレーターを正しく認識できるようになります。
   - **BEFORE:**
   ![Macが含まれている状態](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3525158/2d227571-eebe-af90-b2b9-3e47d7758f8e.png)

   - **AFTER:**
   ![Macを削除した状態](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3525158/2812599d-f76e-306d-abb7-f74bc7f296f3.png)

   - その後、再度 `fastlane snapshot` を実行して、エラーが解消されたかを確認します。

3. **Fastlaneのアップデート**
   - Fastlaneの最新バージョンを確認し、アップデートすることも重要です。以下のコマンドを使用して、gemからアップデートすることができます：
     ```bash
     gem update fastlane
     ```
   - また、Homebrewを使用してFastlaneをアップデートする場合は、次のコマンドを実行します：
     ```bash
     brew upgrade fastlane
     ```

## 参考資料
このエラーについての詳細な議論や解決策が含まれているGitHubのリンクも参照してください：
- [Pull Request #21911](https://github.com/fastlane/fastlane/pull/21911)
- [Issue #22150](https://github.com/fastlane/fastlane/issues/22150)
- [Pull Request #22246](https://github.com/fastlane/fastlane/pull/22246)

## まとめ
Fastlaneを使用したスクリーンショット生成中のエラーは、特にシミュレーターの指定に注意することで多くの場合解決できます。問題が解消しない場合は、環境設定やFastlaneのバージョンを再確認することをお勧めします。
RESTの長所と短所と他のAPIとの違いについて

# RESTとは何か？

REST（Representational State Transfer）は、Webサービスやアプリケーションを設計するためのアーキテクチャスタイルです。シンプルで柔軟な通信の仕組みを提供することで、広く使われるようになりました。**特に、HTTPを利用したAPI設計でよく採用されています。**

# RESTの特徴

**RESTの主な特徴は、そのシンプルさと標準化された通信手法です。以下はRESTの重要なポイントです：**

**リソースベースの設計**：RESTでは、すべての情報は「リソース」として扱われます。リソースには一意のURI（Uniform Resource Identifier）が割り当てられており、HTTPメソッドを使ってリソースにアクセスします。

**HTTPメソッド**：RESTでは、HTTPの標準メソッドを利用してリソースを操作します。例えば：

**GET**: リソースの取得（読み取り）

**POST**: 新しいリソースの作成RESTとは何か？

REST（Representational State Transfer）は、Webサービスやアプリケーションを設計するためのアーキテ

**PUT**: 既存のリソースの更新

**DELETE**: リソースの削除

**ステートレス**：RESTは「ステートレス」であるべきというルールを持ちます。これは、サーバーがクライアントの状態を保持せず、各リクエストが独立していることを意味します。これにより、スケーラビリティが向上し、システム全体の構成が**シンプル**になります。

**クライアント・サーバーアーキテクチャ**：RESTはクライアントとサーバーを明確に分離します。クライアントはユーザーのインターフェースを提供し、サーバーはリソースを管理します。この分離によって、**サーバーとクライアントが独立して開発・保守できるメリットがあります**。

# REST APIの実例

たとえば、図書館のシステムで「本」というリソースを管理するREST APIを考えてみましょう。

**GET /books**: 全ての本の一覧を取得します。

**GET /books/{id}**: 特定のIDを持つ本の情報を取得します。

**POST /books**: 新しい本を追加します。

**PUT /books/{id}**: 特定の本の情報を更新します。

**DELETE /books/{id}**: 特定の本を削除します。

このように、REST APIは直感的で理解しやすい構造を持っており、HTTPメソッドを用いてリソースに対する操作を簡潔に表現することができます。

# RESTの利点と欠点

**利点**

シンプルでわかりやすい：HTTPの標準を使うため、理解しやすく、使いやすいです。

スケーラビリティ：ステートレスであることから、サーバーの負荷分散が容易です。

広く使われている：多くのプログラミング言語でサポートされており、既存のWeb技術と親和性が高いです。

**欠点**

複雑なトランザクションには向かない：複数のリソースを一度に操作するトランザクション処理には不向きです。

HTTPに依存：RESTは基本的にHTTPを利用するため、HTTPプロトコルの制約を受けます。

# RESTと他のAPIスタイルの違い

REST以外にも、Web APIを設計するためのアーキテクチャスタイルとしてGraphQLやgRPCがあります。GraphQLはクライアント側が必要なデータを明確に指定できる一方、RESTではサーバー側が返すデータが固定的です。また、gRPCは高パフォーマンスでバイナリプロトコルを利用するため、リアルタイム性が求められる環境で適しています。

# まとめ

RESTはシンプルで使いやすく、スケーラビリティが高いため、WebサービスのAPI設計に非常に適しています。現在でも広く採用されており、多くの開発者にとって理解しやすい標準的な方法です。特に、データをリソースとして操作し、HTTPメソッドを活用することで、直感的な設計が可能になります。

**最後までよんでいただきありがとうございます。
@y-t0910をフォロー,いいねしていただけると嬉しいです！**