40
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWSでAIエージェント構築に入門! StrandsをAgentCoreにデプロイしてみよう

Last updated at Posted at 2025-10-04

この記事は人力で書きました。

このイベント用の手順書ですが、本記事を読めば1時間ぐらいで誰でも試せます!

Claude Codeなど、AIエージェントを「使う」人はかなり増えてきました。

もはや、AI使うのは全員やって当たり前。
僕らは一歩進んで、AIエージェントを「作る」方にも入門しましょう。100倍楽しいですよ🙌

当日までの事前準備

AWSアカウントの作成

新規作成推奨。既存アカウントを使う際は自己責任でお願いします。

※最近は機能制限つきの完全無料プランも出てきますが、「有料(Paid)」を選んでください。

今回の課金は数十円レベルの想定です。(100%保証はできないので、自己責任でお願いします)

GitHubアカウントの作成

既に持っている方は既存アカウントをお使いください。

前説

AIエージェントの構築には、クラウドサービスを使うと便利です。

スクリーンショット 2025-10-04 18.47.25.png

Strandsを使えば、Pythonで簡単にAIエージェントが書けます。

スクリーンショット 2025-10-04 18.27.44.png

開発したAIエージェントは、AgentCoreを使えばサーバーレスで安くデプロイできます。

スクリーンショット 2025-10-04 18.29.20.png

0. 環境構築

0-1. 開発環境のセットアップ

GitHubリポジトリの作成

  • サインイン後、トップページ左上「New」より新規リポジトリを作成
    • Repository name: tokyo-ai2025
    • Choose visibility: Private
    • Add README: On

GitHub Codespacesの起動

  • リポジトリ作成後、画面右上の緑色ボタン「Code > Create codespace on main」

必要なファイルの作成

  • コードスペース画面下部のターミナルで以下コマンドを実行
touch .env
  • 作成されたファイルに以下を記載する
.env
# AWS認証情報
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-west-2

コードスペースではファイルに入力した瞬間、自動で上書き保存されます。
1行目と2行目の値は、この次の手順で埋めます。

0-2. AWSアカウントのセットアップ

IAMユーザーの作成

このハンズオンは、すべて米国(オレゴン)リージョンで行います。
最初に画面右上のリージョンを切り替えておいてください。

  • 「IAM」を検索してアクセス
  • サイドバー「ユーザー」より新規ユーザーを作成
    • ステップ1
      • ユーザー名: codespaces
    • ステップ2
      • 許可のオプション: ポリシーを直接アタッチする
      • 許可ポリシー: AdministratorAccess にチェック
    • 後はそのまま進む

IAMアクセスキーの作成

  • IAMユーザー作成後、作ったユーザー名をクリックして開く
  • 概要セクションより「アクセスキーを作成」
    • ステップ1
      • ユースケース: ローカルコード
      • 「上記のレコメンデーションを理解し、アクセスキーを作成します。」にチェック
    • 後はそのまま進む
  • 作成後、コードスペースの .env の1行目にアクセスキーを、2行目にシークレットアクセスキーをそれぞれ貼り付ける
.env
# AWS認証情報
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE #サンプル
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY #サンプル
AWS_DEFAULT_REGION=us-west-2

この認証情報は、管理者権限を持っているため慎重に扱ってください。

もし誤って公開GitHubリポジトリにPushしたりすると、秒で悪い人に検知されて、あなたのAWSアカウントを悪用される恐れがあります。

Bedrockのモデル有効化

※この手順は、2025/10/8以降は一部不要になる可能性がある旨、AWSよりアナウンスされています。

  • AWSマネコンで「Amazon Bedrock」を検索してアクセス
  • サイドバー「モデルアクセス」より「モデルアクセスを変更」
    • ステップ1:以下のモデルにチェックを入れる
      • Claude Sonnet 4
      • Claude 3.7 Sonnet
    • ステップ2:Anthropic用にユースケースの詳細を追加
      • 対象のユーザーは誰ですか?: 社内の従業員
      • ユースケースの詳細を入力してください: hands-on
    • 後はそのまま進む

1. Strands Agents入門

  • コードスペースで画面下部のターミナルを利用
  • 以下コマンドで、新規ディレクトリを作りそこに移動
mkdir 1_strands
cd 1_strands

1-1. 三行エージェント

  • 新規ファイルを作成
touch 1_agent.py
  • 以下コードをファイルに貼り付け
1_strands/1_agent.py
# 必要なライブラリをインポート
from dotenv import load_dotenv
from strands import Agent

# .envファイルから環境変数を読み込む
load_dotenv()

# エージェントを作成して起動
agent = Agent()
agent("東京AI祭って何?")

すいません盛りました。 .envが無ければ三行なんです。

モデルを指定しない場合、デフォルトではBedrockのClaude Sonnet 4が利用されます。

  • 以下コマンドで、必要なモジュールをインストールしてから実行
pip install strands-agents python-dotenv
python 1_agent.py

答えてくれますが、東京AI祭のことは知らないようです。

申し訳ございませんが、「東京AI祭」について具体的な情報を持っておりません。
このイベントについて詳しく知りたい場合は、以下の方法で最新情報を確認されることをお勧めします:

1. **インターネット検索**で「東京AI祭」を調べる
2. **公式ウェブサイト**やSNSアカウントを探す
3. **AI関連団体**や**東京都の公式サイト**で情報を確認する
4. **技術系メディア**やニュースサイトをチェックする

もしこれがAI技術に関するイベントでしたら、一般的にそのような祭典では以下のような内容が含まれることが多いです:
- AI技術の展示・デモンストレーション
- 専門家による講演やパネルディスカッション
- ワークショップや体験コーナー
- 企業や研究機関の最新AI研究の発表

具体的な詳細については、公式情報源で最新の情報をご確認ください。

参考:Bedrockの他モデルはもちろん、OpenAIのモデルなども呼べます!

1-2. ツールを持たせてみる

最新情報を答えてもらえるように、Web検索機能を「ツール」として追加してみましょう。

まず、Web検索サービスTavilyにサインアップ(アカウント作成)してください。
GitHubアカウントを連携すれば秒で完了です。

表示されるAPIキーをコピーして、 .env ファイルに追記します。

.env
# AWS認証情報
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE #これはサンプル
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY #これはサンプル
AWS_DEFAULT_REGION=us-west-2

# Tavily認証情報
TAVILY_API_KEY=tvly-oWHrOGmzokwl123drrXNlFBHL2EXAMPLE #これはサンプル
  • 新規ファイルを作成
touch 2_tool.py
  • 以下コードをファイルに貼り付け
1_strands/2_tool.py
# 必要なライブラリをインポート
import os
from dotenv import load_dotenv
from strands import Agent, tool
from tavily import TavilyClient

# .envファイルから環境変数を読み込む
load_dotenv()

# Web検索関数をツールとして定義
@tool
def search(query):
    tavily = TavilyClient(api_key=os.getenv("TAVILY_API_KEY"))
    return tavily.search(query)

# ツールを設定したエージェントを作成
agent = Agent(tools=[search])

# エージェントを起動
agent("東京AI祭って何?")
  • 以下コマンドで実行
pip install tavily-python
python 2_tool.py

検索ツールを使って回答してくれます。

東京AI祭について調べてみますね。

Tool #1: search
東京AI祭は、**日本最大級のAIテックカンファレンス**です。以下が主な特徴です:

## 基本情報
- **開催日程**: 2025年10月4日(土)〜10月5日(日)
- **会場**: Abema Towers(東京都渋谷区)
- **主催**: 東京AI祭実行委員会
- **参加費**: 無料

## コンセプト
国内外のAI企業と専門家が集結し、最新の知見とネットワーキングの場を創出するイベントです。AIに携わる全てのエンジニア、クリエイター、学生、ビジネス担当者が最新トレンドを吸収し、イノベーションを拓く2日間として位置づけられています。

## 主なコンテンツ
1. **ハッカソン** - 国内最大級のAIハッカソン(Weights&Biasesが全面協力)
2. **生成AIコンテスト** - 国内最大級の生成AI作品コンテスト
3. **トークセッション** - 国内外のAI企業・専門家による講演
4. **ブース出展** - 約20社の国内外AI企業による展示
5. **プレイベント** - 月に数回実施される関連イベント

## 実績
昨年度は総企画参加人数と当日参加人数で大きな成果を上げており、AI業界における重要なイベントとして認知されています。

「創る・競う・学ぶ」をテーマに、AI分野の最新動向を知りたい方や業界の人脈を広げたい方にとって貴重な機会となるイベントです。

もしAIエージェントの回答が途中で止まってしまう場合は、BedrockのClaudeモデル呼び出し分間クォータが上限に達し、Strandsが裏でリトライをかけ続けている可能性があります。
そのときは他のモデルに変更してみてください。

(代替候補のモデルID)

  • us.anthropic.claude-3-7-sonnet-20250219-v1:0
  • us.amazon.nova-premier-v1:0 ※モデルアクセスの有効化が必要

1-3. 他の人が作ったMCPサーバーからツールを拝借する

AWSドキュメントなどを検索できる「AWS Knowledge MCPサーバー」を使ってみましょう。

スクリーンショット 2025-10-04 19.48.33.png

  • 新規ファイルを作成
touch 3_mcp.py
  • 以下コードをファイルに貼り付け
1_strands/3_mcp.py
# 必要なライブラリをインポート
from dotenv import load_dotenv
from strands import Agent
from strands.tools.mcp import MCPClient
from mcp.client.streamable_http import streamablehttp_client

# .envファイルから環境変数を読み込む
load_dotenv()

# MCPクライアントを作成
mcp = MCPClient(
    lambda: streamablehttp_client("https://knowledge-mcp.global.api.aws")
)

# MCPクライアントを起動しながら、エージェント作成&呼び出し
with mcp:
    agent = Agent(
        model="us.anthropic.claude-3-7-sonnet-20250219-v1:0",
        tools=mcp.list_tools_sync()
    )
    agent("Bedrock Agentcoreのランタイムってどんな機能?一言で説明して。")

AWSドキュメントを検索すると推論回数が増えるため、Bedrockの初期クォータが緩めのSonnet 3.7を利用しています。

  • 以下コマンドで実行
pip install uv strands-agents-tools
python 3_mcp.py

以下のようなレスポンスが出力されます。

AWS Bedrock AgentCoreのランタイムについて調べたいですね。AWS Bedrock Agentについての情報を検索してみます。

Tool #1: aws___search_documentation
AWS Bedrock AgentCoreランタイムについての情報が見つかりましたので、詳細を確認するために主要なページを読んでみます。

Tool #2: aws___read_documentation
AWS Bedrock AgentCore Runtimeを一言で説明すると:

AWS Bedrock AgentCore Runtimeは、任意のフレームワークやモデルを使用したAIエージェントを安全かつスケーラブルに実行するための、セキュアでサーバーレスな目的特化型の実行環境です。
主な特徴は:
- フレームワークに依存しない設計(LangGraph、Strands、CrewAIなど対応)
- 最長8時間までの長時間実行サポート
- セッション分離による安全性の確保
- 100MBの大型ペイロード処理能力
- 使用量ベースの料金体系
- 組み込み認証機能
- エージェント特化の可観測性

1-4. マルチエージェントにしてみる

監督者がサブエージェントをツールのように呼び出す「Agent-as-Tools」パターンを使います。(一番オーソドックスで実装も簡単)

スクリーンショット 2025-10-04 20.22.36.png

  • 新規ファイルを作成
touch 4_multi_agent.py
  • 以下コードをファイルに貼り付け
1_strands/4_multi_agent.py
# 必要なライブラリをインポート
from dotenv import load_dotenv
from strands import Agent, tool
from strands_tools import calculator

# .envファイルから環境変数を読み込む
load_dotenv()

# サブエージェント1を定義
@tool
def math_agent(query: str):
    agent = Agent(
        model="us.anthropic.claude-3-7-sonnet-20250219-v1:0",
        system_prompt="ツールを使って計算を行ってください",
        tools=[calculator]
    )
    return str(agent(query))

# サブエージェント2を定義
@tool
def haiku_agent(query: str):
    agent = Agent(
        model="us.anthropic.claude-3-7-sonnet-20250219-v1:0",
        system_prompt="与えられたお題で五・七・五の俳句を詠んで"
    )
    return str(agent(query))

# 監督者エージェントの作成と実行
orchestrator = Agent(
    model="us.anthropic.claude-3-7-sonnet-20250219-v1:0",
    system_prompt="与えられた問題を計算して、答えを俳句として詠んで",
    tools=[math_agent, haiku_agent]
)
orchestrator("十円持っている太郎くんが二十円もらいました。今いくら?")
  • 以下コマンドで実行
pip install strands-agents-tools
python 4_multi_agent.py

マルチエージェントが協働して回答してくれます。

この問題を数学で解いた後、結果を俳句にします。
まずは計算してみましょう:

Tool #1: math_agent
太郎くんの所持金を計算しましょう。
太郎くんは最初に10円持っていて、そこに20円もらったので、合計金額を計算します。

Tool #1: calculator
太郎くんは今30円持っています。では、この答え(30円)を俳句にしてみましょう:

Tool #2: haiku_agent
## 太郎くんの三十円
三十円
夢広がる
駄菓子屋で

問題の答えは30円です。その結果を俳句にしました:
三十円
夢広がる
駄菓子屋で

2. AgentCore入門

これまでは作ったエージェントをデプロイしたいとき、インフラはLambdaにすべきかECSにすべきか、認証やストリーミングはどうしよう、そして監視は…など細かい悩みが尽きませんでしたが、AgentCoreはこれをまるっと解決してくれる救世主です!

便利なSDKやCLIツールも提供されています。

  • 新規ディレクトリを作って、そこに移動
cd /workspaces/tokyo-ai2025

mkdir 2_agentcore
cd 2_agentcore

2-1. トレースの有効化

このハンズオンは、すべてオレゴンリージョンで行います。
最初に画面右上のリージョンを切り替えておいてください。

  • AWSマネコンで「CloudWatch」を検索してアクセス
  • サイドバーの「トランザクション検索」より、「Enable Transaction Search」をクリック
  • 「Check this option to ingest spans as structured logs」にチェックを入れて「Save」

2-2. コードにAgentCore SDKを装着

Strandsで書いたエージェントを、AgentCoreのSDKでラップしてAPIサーバーにします。

スクリーンショット 2025-10-04 20.27.18.png

AgentCoreビルド用のディレクトリを作り、そこに新規ファイルを作成

mkdir backend
cd backend

touch tavily_agent.py
  • 以下コードをファイルに貼り付け
2_strands/backend/tavily_agent.py
# 必要なライブラリをインポート
from strands import Agent
from strands.tools.mcp.mcp_client import MCPClient
from mcp.client.streamable_http import streamablehttp_client
from bedrock_agentcore.runtime import BedrockAgentCoreApp

# AgentCoreランタイム用のAPIサーバーを作成
app = BedrockAgentCoreApp()

# エージェント呼び出し関数を、APIサーバーのエントリーポイントに設定
@app.entrypoint
async def invoke_agent(payload, context):

    # フロントエンドで入力されたプロンプトとAPIキーを取得
    prompt = payload.get("prompt")
    tavily_api_key = payload.get("tavily_api_key")

    ### この中が通常のStrandsのコード ----------------------------------
    # Tavily MCPサーバーを設定
    mcp = MCPClient(lambda: streamablehttp_client(
        f"https://mcp.tavily.com/mcp/?tavilyApiKey={tavily_api_key}"
    ))

    # MCPクライアントを起動したまま、エージェントを呼び出し
    with mcp:
        agent = Agent(
            model="us.anthropic.claude-3-7-sonnet-20250219-v1:0",
            tools=mcp.list_tools_sync()
        )

        # エージェントの応答をストリーミングで取得
        stream = agent.stream_async(prompt)
        async for event in stream:
            yield event
    ### ------------------------------------------------------------

# APIサーバーを起動
app.run()

2-3. AgentCoreランタイムにデプロイ

AgentCoreランタイムへ簡単にAIエージェントをデプロイできる「スターターツールキット」を使います。

スクリーンショット 2025-08-03 23.14.45.png

  • 新規ファイルを作成
touch requirements.txt
  • 以下を記入
2_agentcore/backend/requirements.txt
strands-agents
bedrock-agentcore
  • 以下コマンドを実行
# .env の内容をターミナルの環境変数に設定
export $(cat /workspaces/tokyo-ai2025/.env | grep -v ^# | xargs)

# AgentCoreのスターターツールキットをインストール
pip install bedrock-agentcore-starter-toolkit

# デプロイ準備
agentcore configure --entrypoint tavily_agent.py
  • ウィザードでは全て Enter でOK
🔐 Execution Role
Press Enter to auto-create execution role, or provide execution role ARN/name to use existing
Execution role ARN/name (or press Enter to auto-create):
✓ Will auto-create execution role

🏗️  ECR Repository
Press Enter to auto-create ECR repository, or provide ECR Repository URI to use existing
ECR Repository URI (or press Enter to auto-create):
✓ Will auto-create ECR repository

🔍 Detected dependency file: requirements.txt
Press Enter to use this file, or type a different path (use Tab for autocomplete):
Path or Press Enter to use detected dependency file:
✓ Using detected file: requirements.txt

🔐 Authorization Configuration
By default, Bedrock AgentCore uses IAM authorization.
Configure OAuth authorizer instead? (yes/no) [no]:
✓ Using default IAM authorization

🔒 Request Header Allowlist
Configure which request headers are allowed to pass through to your agent.
Common headers: Authorization, X-Amzn-Bedrock-AgentCore-Runtime-Custom-*
Configure request header allowlist? (yes/no) [no]:
✓ Using default request header configuration
Configuring BedrockAgentCore agent: tavily_agent

🧠 Memory Configuration
✓ Short-term memory is enabled by default
  • Stores conversations within sessions
  • Provides immediate context recall

Optional: Long-term memory
  • Extracts user preferences across sessions
  • Remembers facts and patterns
  • Creates session summaries
  • Note: Takes 60-90 seconds to process

Enable long-term memory extraction? (yes/no) [no]:
✓ Using short-term memory only
  • デプロイを実施
# デプロイ
agentcore launch

1分ほど待つと、あなたのAIエージェントがAgentCoreランタイムにデプロイされます。

IAMロールとかECRリポジトリとか、全部自動で作ってくれるので超便利!
これだけで、AIエージェントをサーバーレス基盤上でホストしてくれます。

デプロイ完了後、表示される Agent ARN の値をメモ帳などにコピーしておきましょう。

2-4. 動作確認

PCのローカル上で、Pythonライブラリ「Streamlit」を使ってフロントエンド画面を作成し、AgentCore上のStrands Agentsを呼び出してみましょう。

スクリーンショット 2025-10-04 22.25.42.png

  • 新規ファイルを作成
cd /workspaces/tokyo-ai2025/2_agentcore
touch frontend.py
  • 以下コードをファイルに貼り付け
2_agentcore/frontend.py
# 必要なライブラリをインポート
import os, boto3, json
import streamlit as st
from dotenv import load_dotenv

# .envファイルから環境変数をロード
load_dotenv(override=True)

# サイドバーで設定を入力
with st.sidebar:
    agent_runtime_arn = st.text_input("AgentCoreランタイムのARN")
    tavily_api_key = st.text_input("Tavily APIキー", type="password")

# タイトルを描画
st.title("なんでも検索エージェント")
st.write("Strands AgentsがMCPサーバーを使って情報収集します!")

# チャットボックスを描画
if prompt := st.chat_input("メッセージを入力してね"):
    # ユーザーのプロンプトを表示
    with st.chat_message("user"):
        st.markdown(prompt)

    # エージェントの回答を表示
    with st.chat_message("assistant"):
        # AgentCoreランタイムを呼び出し
        agentcore = boto3.client('bedrock-agentcore')
        payload = json.dumps({
            "prompt": prompt,
            "tavily_api_key": tavily_api_key
        })
        response = agentcore.invoke_agent_runtime(
            agentRuntimeArn=agent_runtime_arn,
            payload=payload.encode()
        )

        # ストリーミングレスポンスを処理
        container = st.container()
        text_holder = container.empty()
        buffer = ""

        # レスポンスを1行ずつチェック
        for line in response["response"].iter_lines():
            if line and line.decode("utf-8").startswith("data: "):
                data = line.decode("utf-8")[6:]

                # 文字列コンテンツの場合は無視
                if data.startswith('"') or data.startswith("'"):
                    continue

                # 読み込んだ行をJSONに変換
                event = json.loads(data)

                # ツール利用を検出
                if "event" in event and "contentBlockStart" in event["event"]:
                    if "toolUse" in event["event"]["contentBlockStart"].get("start", {}):
                        # 現在のテキストを確定
                        if buffer:
                            text_holder.markdown(buffer)
                            buffer = ""
                        # ツールステータスを表示
                        container.info("🔍 Tavily検索ツールを利用しています")
                        text_holder = container.empty()

                # テキストコンテンツを検出
                if "data" in event and isinstance(event["data"], str):
                    buffer += event["data"]
                    text_holder.markdown(buffer)
                elif "event" in event and "contentBlockDelta" in event["event"]:
                    buffer += event["event"]["contentBlockDelta"]["delta"].get("text", "")
                    text_holder.markdown(buffer)

        # 最後に残ったテキストを表示
        text_holder.markdown(buffer)
  • 以下コマンドで起動
pip install streamlit
streamlit run frontend.py
  • 右下に出るポップアップの「ブラウザーで開く」ボタンをクリック
    • 閉じてしまった場合は、ターミナルの http://localhost:8501 をクリックすればOK

スクリーンショット 2025-10-04 21.14.47.png

サイドバーに、先ほどメモしたARNとTavilyのAPIキー(.envからコピー可能)を入力して、質問してみましょう。

2-5. 運用監視

簡易Langfuse的な機能(LLM版Datadogのようなもの)が自動で付いてるので便利です。

スクリーンショット 2025-10-04 22.28.40.png

AgentCoreオブザーバビリティでトレース確認

  • マネコンで「Bedrock AgentCore」を検索し、サイドバー「エージェントランタイム」から tavily_agent をクリック
  • 上部の「エージェントの詳細」を展開して「オブザーバビリティを表示」をクリック
  • 「Traces view」タブからトレースIDをクリックすると、エージェントの動作履歴をドリルダウンして確認できます

スクリーンショット 2025-10-04 21.18.23.png

CloudWatchログの確認

うまく起動せず、トレースすら見られないときはサーバーログを見ましょう。

  • マネコンで「CloudWatch」を検索してアクセス
  • サイドバー「ロググループ」から /aws/bedrock-agentcore/runtimes/tavily_agent-<ランダム文字列>-DEFAULT をクリック
  • 「すべてのログストリームを検索」から、直近のサーバーログを確認できます

次のステップ: フロントエンドのデプロイ

今回はフロントエンドをPCのローカルで動かしましたが、Streamlit Community Cloudを使えば無料でホストして他の人に公開できます。余裕がある人は試してみましょう。

公開したアプリは、URLを知っている人が誰でもアクセスできてしまうため、あなたのAWS利用料が増える恐れがあります。コストとセキュリティに注意しましょう。

お片付け

参加後は必ずアンケートにご回答ください!

AWSアカウントは使い捨て運用がおすすめです。
ハンズオンが終わったら、不要なAWSアカウントは解約してしまいましょう。
(解約すると同じメールアドレスが使えなくなるので、捨てアド以外の方は解約前にメルアド変更しましょう)

参考まで、今回作成されたリソースは以下です。

  • 使った分だけ課金されるもの
    • AgentCoreランタイム
  • ほぼ課金されないもの
    • IAMユーザー
    • IAMロール
    • ECRリポジトリ
    • CodeBuildプロジェクト

おまけ

今回のようなAIエージェント構築を、図解フルカラーで優しく学べる入門書を今週出版しました!

Strands以外にも、定番のLangGraphや、TypeScriptでエージェントを書けるMastraなど、王道フレームワークを一通り学べます!

Next.jsを用いたフロントエンドの開発方法や、Amplify Gen2を使ったAWSへのデプロイまで紹介。LangfuseやRagasを使ったLLMOpsも解説しています。

image.png

40
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
40
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?