OmniAICreator/Qiita-1.07M huggingface dataset:
ECS Execの有効化ができない原因はAWS CLIのバージョンかも

AmazonFogareの中身を確認するためにECS Execを有効にする必要がある。
しかしなぜかECS Execの有効化ができなかったので解決策を共有する。
（ググっても同じ事象が出てこなかったので）

# 結論
AWS CLIのバージョンが合わなかったので再インストールしたら通った。

# 事象
以下のコマンドでECS Execを有効化を行う。
```shell
aws ecs update-service --cluster [クラスター名] --service [サービス名] --enable-execute-command
```

しかし、--enable-execute-commandというオプションなんてないよ！というエラーが出る。

````shell
% aws ecs update-service --cluster [クラスター名] --service [サービス名] --enable-execute-command

usage: aws [options] <command> <subcommand> [<subcommand> ...] [parameters]
To see help text, you can run:

  aws help
  aws <command> help
  aws <command> <subcommand> help

Unknown options: --enable-execute-command
````
ポリシーなどの見直しもしたけど、そういうのじゃないんだよねって雰囲気がぷんぷんしている。

# やったこと
こちらの素晴らしい記事に辿り着いた

https://qiita.com/okubot55/items/b1fb07b2de08c354275b

なんとなく読んでいると
AWS CLI 対応バージョン
- v1	1.19.28 以降
- v2	2.1.31 以降

という記述を発見。
まさかなと思って自分の環境を調べると

````shell
% aws --version
aws-cli/2.0.30 Python/3.7.4 Darwin/22.3.0 botocore/2.0.0dev34
````

......これじゃん。
ということで再インストールすると正常に完了した。

````shell
% aws --version
aws-cli/2.11.10 Python/3.11.2 Darwin/22.3.0 exe/x86_64 prompt/off

% aws ecs describe-services --cluster [クラスター名] --service [サービス名] | grep enableExecuteCommand
            "enableExecuteCommand": true
````


なんで2.0系がインストールされていたのか...なんでなのか...それだけが気がかり
変数に数値を足す方法(PHP)

# 初めに
今回は、変数に代入した値と数値を足す方法を記載する。

# 変数に数値を足すには
変数に数値を足す方法は下記の通り

```php:記載例
$num1 = 3;

//num1にnum1+10を代入する。
$num1 = $num1 + 10;

echo $num1;
//結果：13が出力される。

```

また、変数に数値を足す形には、省略形がある。

```php:記載例
$num1 = $num1 + 10; → $num1 += 10;
//その他の四則演算に関しても、同様に省略して書くことが可能
```

さらに、計算する数値が１の時だけ、さらに省略して記載することができる。
また、1を足す省略形で値を出力する際は、結果に注意する必要がある。
```php:記載例
$num = $num + 1;
→ $num += 1;
→ $num++;


$x = 3;
$y = 3;
echo ++$x; //結果：4 echoの前に1が足される
echo $y++; //結果：3 echoの後に1が足される
```
sageMakerNotebookでモデル学習

# できるもの
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206781/5c17ca03-bf5e-59d9-e409-b316036cfa80.png)

# 記事の対象者
クラウドのGPUリソースを有効活用して機械学習開発を加速したい方
クラウドでjupyterlab環境を手軽に使用したい方

# 記事を読むとできるようになること
awsでノートブックインスタンスを立ち上げることができる
（最低でもそこまでの作業イメージがつき、作業が円滑に進みやすくなる）

# 記事を読むのにかかる時間
1-2分

# 以下記事コンテンツ
まずはsagemakerのノートブックをクリックすると以下のような画面にいきます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206781/bf13e591-29e6-ed35-2594-ea84f771f6e4.png)

↓
上記ノートブックインスタンスの作成をクリックすると下の表示へ遷移
![スクリーンショット 2023-04-07 11.45.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206781/83cc254c-8016-4db8-2ed4-fbd48690c777.png)

↓
個人的にGCPと比べて良いなと思ったのはgitレポジトリを初期で導入できるのは手間が省けていいなと思いました。
（git使う人）
![スクリーンショット 2023-04-07 11.46.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206781/9b16010e-0a73-4340-855f-12487e2ac2d5.png)

↓
wait until tommorow（実際2分くらいでした）したらjupyterLabを開きましょう。
ここ以降はjupyterLabの画面なので、つまりGCPのvertixAIともほぼ同一となり、気兼ねなく行って帰ってできると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206781/8b4e2a3e-ddd2-3203-8073-ea655416b676.png)

↓
とりあえず!nvidia-smiコマンドを使うと以下エラーが表示されました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206781/5e7806b5-9519-6d66-9f7c-62fed7ebac9c.png)

↓
ml.と名のつくインスタンス名だったらGPU基本ついてるだろうと鷹を括っていたところ、普通に勘が外れました。
p系か、g4系のインスタンスを選択するとnvidaがついてくるので、そちらに変えて実行しましょう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206781/3371833b-a122-1aeb-d2ff-242f2483b961.png)

↓
g4インスタンスに変更すると無事GPU設定を確認できました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206781/5c17ca03-bf5e-59d9-e409-b316036cfa80.png)

注意点：
永続的な領域として使えるのは/home/ec2-user/SageMakerディレクトリのみであることを留意しておくと変な罠にハマりづらくなると思います。

よかった点：
サーバーの挙動も安定していましたし、git、s3との連携も便利、jupyterlabなので、ドロップでファイルを置けたり、高速なgpuを選択できたりと、とても良い体験を得られると思います。
いまさら調査するCakephp2の認証ロジック

移行プログラムの作成過程でCakephp2の認証がどうなってるか調べる機会があったため、調査しました。
メモ程度ですが参考になれば幸いです。

# 参考メモ
* [AuthコンポーネントのパスワードをCakePHPを使用せずハッシュ化する方法(パスワードの生成ルール) - [CakePHP2/CakePHP] ぺんたん info](https://pentan.info/php/cake/cakephp2/auth_password_hash.html)
```php:引用
App::uses('SimplePasswordHasher', 'Controller/Component/Auth');

(略)

        //認証情報(モデルやハッシュ化ルール)
            'authenticate' => array(
                'Form' => array(
                    'userModel' => 'User',
                    'fields' => array(
                        'username' => 'account',
                    ),
                    'passwordHasher' => array(
                        'className' => 'Simple',
                        'hashType' => 'sha256'
                    )
                )
            )
```

* `SimplePasswordHasher` を使ってる前提
  * SimplePasswordHasherの実体
    `vendors/cakephp/cakephp/lib/Cake/Controller/Component/Auth/SimplePasswordHasher.php`
    ここデバッグすれば、実際の動きわかる。
Sysdig App for Splunkを使ってみた

今回はSplunk上でSysdigのログをグラフィカルに表示できるSysdig App for Splunkを使用してみたので、手順をご紹介します。

# Sysdig App for Splunkのインストール
1. Splunk UIにログインします。
2. __他のAppのサーチ__ をクリックします。.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802821/7db8a951-aca2-78e8-212c-07303ae168e0.png)


3. __“sysdig”__ で検索します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802821/3f4bad3f-8b54-b6c9-0c70-a16b8f759046.png)
 

4\. Sysdig Add-on for Splunkの __インストール__ をクリックします。
詳細情報：　

https://splunkbase.splunk.com/app/5331

 

5\. Sysdig App for Splunkの __インストール__ をクリックします。
詳細情報:

https://splunkbase.splunk.com/app/5330

インストール時には Splunk.com の認証情報を入力する必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802821/c441dbbd-a3da-4c2d-2a98-cf812483dfc3.png)

# Sysdig SecureからSplunkへのイベントの転送設定
下記手順をご参照ください。

https://qiita.com/yotake/items/f55390207d4078ef0c03

:::note
連携設定の`Source Type`は空欄のままにしてください。
:::

イベントが問題なく転送できていることを、下記の検索ワードで確認します。

`source="http:sysdig"`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802821/5d00b8a0-eaf0-6c41-fceb-2cc92ff0cf6d.png)
 
# Sysdig App for Splunkの使用

## セキュリティイベントを発生させる
1. Sysdig UIにログインします。
1. Policy > Runtime Policy に移動します。
1. トグルボタンで __Sysdig Runtime Notable Events__ ポリシーを有効化します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802821/825f3700-4f74-6587-094b-edb898803bd5.png)


4\. 以下のコマンドでセキュリティイベントを発生させます。


```kubectl run nginx --image=nginx```

```kubectl exec -it nginx -- bash```

```touch /dev/aaa```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802821/36c7e33c-defa-23ad-13ec-042c1068ac8d.png)

## Sysdig App for Splunk UIでの確認
Appメニューから __Sysdig App for Splunk__ を開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802821/c7223208-c81c-b758-6730-b98fdcaf8b44.png)

:::note
Sysdig App for Splunk画面では、Sysdig App for Splunk をインストールした後に発生したイベントのみが表示されます。
:::

### Policy Events Overview画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802821/bd8d1663-0da5-400d-31f3-3350db4ff502.png)

イベントが表示されないときは、先ほど発生したセキュリティイベントがSplunkに問題なく転送できていることを、__サーチ__ 画面で下記の検索ワードを使用して確認します。
`source="http:sysdig"`

:::note warn
Sysdig App for Splunkを追加した後の時間のセキュリティイベントが記録されていることを確認してください。記録されていない場合は、SysdigからSplunkへの転送（連携）設定に問題があります。
:::

### Activity Audit Overview画面

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802821/ebc80a61-ffc4-3144-16a5-5fa21fa742a4.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802821/20222341-737e-173b-7bb4-9f6423c1bd73.png)

### Audit Tap Overview Tab

:::note
Audit Tapイベントの転送を有効にするためには、Sysdig Supportに連絡する必要があります
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802821/3c5ab034-5b0a-94bd-3dc2-24907b85935e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2802821/9df1d9a8-a87c-face-bc9a-d13b92b40be6.png)

# まとめ
Sysdig App for Splunkを使用して、Splunk上でSysdigのログを簡単にグラフィカルに表示できることを確認できました。
Missing file libarclite_iphoneos.a（Xcode 14.3でビルドエラー）

:::note alert
Xcode 14.3 には、XcodeDefaults ツールチェーン コンテンツに「.a」ファイルがないため、いくつかのCocoaPodsにビルドで問題がでます。
:::

Xcode 14.3 で欠落しているすべてのファイルを[**こちら**](https://github.com/kamyarelyasi/Libarclite-Files )からダウンロードし、以下ののパスに格納することで解決します。
```/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/```

:::note warn
注: lib フォルダーに「arc」というフォルダーが存在しない場合は作成してください。
:::
Google Drive に保存した画像を直接呼び出すURL(ERR_TOO_MANY_REDIRECTS 回避版)


### 背景

Google Apps Script(GAS) の HtmlService を利用して作成した Web アプリで画像を img タグや background-img に指定する際に、画像をスタティックサーバーにホストするのが嫌で、Google Drive にアップしたファイルを、 読み込む方法があります。

ただ、残念なことに、Safari ブラウザでこのページにアクセスすると、ERR_TOO_MANY_REDIRECTS が発生して画像が表示されません。そのため、スタティックサーバーに画像を配置して回避してきました。

ちょっと時間が取れたので、GAS だけで回避する方法を考えてみました。

## Google Drive の画像の表示用 URLの生成 (ERR_TOO_MANY_REDIRECTS が発生する URL)

1. Google Drive に画像ファイルをアップロードし、「リンクを知っているユーザー全員」に「閲覧」権限を付与し、リンクを取得します。  
サンプル：
https://drive.google.com/file/d/1VTd3cCphDyNuCPrrjtynS71YgAiOSb2f/view?usp=sharing
この URL を img タグに指定しても、HTML には表示されません。

2. この URL の /d/ と /view? で囲まれた、1VTd3cCphDyNuCPrrjtynS71YgAiOSb2f　(FileID)をコピーし、下記の ##FileID## を置き換えます。
http://drive.google.com/uc?export=view&id=##FileID##
今回の場合は、以下のようになります。
http://drive.google.com/uc?export=view&id=<font color=red>1VTd3cCphDyNuCPrrjtynS71YgAiOSb2f</font>
この URL を img タグに指定すると画像がページに表示されます。ただ、前述の通り、safari で画像は表示されません。

```html:img url (Safari で表示されない)
<img src="http://drive.google.com/uc?export=view&id=1VTd3cCphDyNuCPrrjtynS71YgAiOSb2f">
```
## 回避方法を適用した URL の生成

回避方法として考えたのは、リダイレクトが多すぎるのであれば、リダイレクトを解決した URL を指定すれば良いのではないかということで、作成した GAS の関数が以下の通り。


```html:title
function getRedirect(url) {
  var res = UrlFetchApp.fetch(url, {'followRedirects': false, 'muteHttpExceptions': false});
  var redUrl = res.getHeaders()['Location'];  
  var resCode = res.getResponseCode();        
  if (redUrl){
    var ret=getRedirect(redUrl)
    return ret
  } else {                                    
    return url;
  }
}
```

この関数に、先ほど生成した url (http://drive.google.com/uc?export=view&id=1VTd3cCphDyNuCPrrjtynS71YgAiOSb2f) を指定してリダイレクト先を取得して得た url が、以下となり、これを指定すると Safari でもエラーなく表示されます。
https://doc-0c-20-docs.googleusercontent.com/docs/securesc/ha0ro937gcuc7l7deffksulhg5h7mbp1/bfbm8bv8r5dri9ombp3hp8288ij4d38i/1680836175000/13650191374517839472/*/1VTd3cCphDyNuCPrrjtynS71YgAiOSb2f?e=view&uuid=536bb0e5-0f58-4ba9-89b9-9b8d78422632

HTMLService で呼び出される HTML 内に下記ののように記述することで、src URL に getRedirects の結果が格納されます。

``` html:GAS HTML for HTMLService
<img src="<?= getRedirects('http://drive.google.com/uc?export=view&id=1VTd3cCphDyNuCPrrjtynS71YgAiOSb2f') ?>">
```
Googleデータアナリティクス：データと測定指標

# はじめに

本記事は、Googleデータアナリティクスのプロフェッショナル認定証のプログラムより、参照させて頂いています。興味を持った方は、是非受講してみてください。

https://www.coursera.org/professional-certificates/data-analytics-japanese

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/f218c6bc-27a9-6aa7-4dfa-8e63bd3928b7.png" width="800">

# データと測定指標

測定指標とは、測定の際に活用でき、 定量化できるデータの一種です。 

こう考えてみましょう。 

***<font color="MediumVioletRed">『データは単なる事実の集まりですが、 個々の測定指標によって 個別の種類に整理されます。』</font>***

また、測定指標を組み合わせて 計算式にして、 数値データを挿入することもできます。 

売上高の例でいうと、 データを整理するために 特定の測定指標を使用しない限り、 データはあまり意味を成しません。 そこで、個人担当者別の売上高を 測定指標にしてみましょう。 これで、誰の売上が一番良いか、 確認できるようになります。 測定指標は通常、単純な計算を伴います。 
- 例えば、収益は、 販売数に販売金額を掛けたものです。 どの測定指標を選択するかが重要です。

データには、私たちが探る課題に関する 「生の情報」がたくさん含まれています。 しかし、求めている答えを得るためには、 適した測定指標を選ぶ必要があります。 さまざまな業界で、データセットから物事を 測定するためさまざまな測定指標が活用されます。 ここでは、いくつかの業界の企業における 測定指標の活用方法を見てみましょう。 収集したデータと測定基準の 関係性が見えてくるはずです。

### ROI
皆さんは ROI という言葉を 聞いたことがありますか？

企業は常に、この指標を使用しています。 ROI（投資収益率）とは基本的に、 ある投資がどの程度うまくいっているかを 知るための測定指標で 構成された計算式です。 

ROI は、一定期間における 
- 純利益
- 投資コスト

この 2 つの測定指標で構成されています。 

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/5e17afbf-6649-1e50-6872-294ffa6e0b93.png" width="600">

この 2 つの指標、つまり 利益と投資コストを比較すれば、 企業は投資がどの程度うまくいっているのか 手持ちのデータで確認できます。 また将来どのような投資を行うか、 どの投資を優先させるかを 決定するのにも役立ちます。 

### 顧客維持率

マーケティングにも測定指標が使われています。 例えば顧客維持率、つまり企業が 長期にわたって顧客を維持できるかを 計算する際にも、 測定指標が活用できます。 顧客維持率は、ある期間における 最初と最後の顧客数を比較し、 各期間の維持率を見るものです。 この手法で、企業はマーケティング戦略が どの程度成功しているのか また、より多くのリピーターを呼び戻すため 新しい方法を検討する必要があるかどうかを 知ることができます。

# 測定目標

さまざまな業界が、あらゆる種類の 異なる測定指標を活用しています。 しかし、共通しているのは、 データを測定することによって、 特定目標を達成しようとしていることです。

***<font color="MediumVioletRed">『測定目標とは、企業が設定する目標であり、 測定指標で評価されるものです。 』</font>***

測定指標はたくさんあります。 測定目標も同様です。ある組織では、
- 月間売上高を 一定に保ちたいかもしれません。
- リピーターの割合を 一定に保ちたいかもしれません。

測定指標を活用し、 データの個々の側面に注目することで、 データが語るストーリーが見えてきます。 測定目標や計算式は、 データを測定し理解するのに便利です。
OpenID Connectについて

# 概要
OpenID Connectについて、学習したことを残しておこうと思います。

# OpenID Connectとは？
OpenID Connectとは、OAuth2.0をベースに作られたプロトコルのことです。
そもそもOAuth2.0は認可のみを行うためのプロトコルで、認証は別途行う必要が
ありましたが、そこに認証機能を追加したものがOpenID Connectになります。

## 認証について知る
会員制のサイトを利用する際、付与されたユーザーIDを使用してログインすれば
そのサイトが利用できるようになります。つまり本人確認ができれば利用できるようになります。
この本人確認処理にあたるのが**認証**です。

### 認証API
会員制のサイトにログインする際、「Googleでログイン」や「Twitterでログイン」などの
選択肢を見かけることがあると思います。GoogleやTwitter、Facebookなどの利用者が多いサービスでは、
認証処理の仕組みをAPIとして提供していますが、これが**認証API**です。

#### 具体的な使用例
以下は具体的な使用例です。利用したいサイトがA、GooleやTwitterなどの認証APIを
提供する側がBとしています。
1. ユーザーがAにログインの要求を行う
1. AがBにユーザーを誘導する
1. Bで認証を行う
1. 認証結果をAに通知する
1. 認証された場合、ユーザーはAにログイン可能になる

#### 認証APIの問題点
認証APIは一見便利に見えますが次のような問題点があります。
- ユーザーが対象の認証API側にアカウントを持っていないと認証できない
- 認証API側によって、APIの仕様が異なるためサイト運営者側への負担が増える

### OpenID
上記の問題点を解決するために、認証処理を標準化したプロトコルが**OpenID**です。
OpenIDでは、複数企業が提供する認証サービスを同じ手順で利用することが可能です。

## 認可について知る
認証結果をもとに、ユーザーに権限を付与することを**認可**といいます。
Twitterで例えると、会員登録を行い認証されたアカウントは投稿、編集などを
行う権限が与えられます。
このように、「投稿」「編集」「削除」などの機能を許可することが認可です。

### OAuth
サイトをまたいだ認可を実現するために標準化されたプロトコルが**OAuth**です。
例えば、Facebookに何か投稿をしたときに、同時にTwitterでも
「Facebookで～～を投稿しました」というような投稿ができるようになります。
このような仕組みを実現するのがOAuthです。
Chef のレシピで files/ の外側にあるファイルを Windows で remote_file の source でフルパスで指定するときのメモ

フルパスで指定するとき、 ```C:/foo/bar``` や ```Z:/fizz/buzz``` などで指定したいが、エラーが出てうまく動かなかった。  
なぜかというとまず ```file://``` が必要だった。  
しかし  ```file://C:/foo/bar``` でも見つけてくれないでエラー。  
なかなか分からなかったが、 ```file:///C:/foo/bar``` と ```file:///``` のように ```/``` を3つ書く必要があった。多分 ```C:``` の直前の ```/``` はrootを表しているのか?

動いたのはこんな感じ。

```ruby
remote_file 'C:/a/b' do
  source 'file:///C:/somewhere/somefile'
  action :create
end
```
MERGE文のサンプル

備忘録。
IDとVALUEの２列構成のテーブルに対してMERGEを実行するサンプル。
```
MERGE INTO MyTable DST
	USING (
			WITH PARAM AS (
				SELECT '1' AS ID, :VALUE AS VALUE from dual
			)
			SELECT * FROM PARAM
		) SRC
	ON (DST.ID = SRC.ID)
WHEN MATCHED THEN
	UPDATE SET
		DST.VALUE = SRC.VALUE
WHEN NOT MATCHED THEN
	INSERT (DST.ID, DST.VALUE)
	VALUES (SRC.ID, SRC.VALUE)
```
RPAってむずかしいよ

RPAとボイスボットを連携する際の懸念点:

リアルタイム性の低下: RPAはAPI連携に比べて処理速度が遅く、リアルタイム性が低下する可能性があります。
システム変更への対応: システムの画面や操作方法が変更された場合、RPAロボットもそれに合わせて更新する必要があります。
エラーハンドリング: RPAロボットが遭遇するエラーや例外状況に対処するための適切なエラーハンドリング手順が必要です。
セキュリティリスク: RPAロボットがアクセスするデータやアカウント情報の管理が不十分だと、情報漏洩や不正アクセスが発生するリスクがあります。
メンテナンス負荷: RPAロボットは定期的にメンテナンスが必要であり、システムの変更やアップデートに伴って調整が求められます。
スケーラビリティ: 大量のデータや同時アクセスが増えた場合、RPAの処理速度や同時実行数の最適化が必要になります。
これらの懸念点に対処するために、適切なRPAツールの選定、設計、開発、デプロイメント、そして継続的な監視とメンテナンスが重要です。



API連携における懸念点:

APIの安定性: APIが頻繁にダウンしている場合、連携に影響が出る可能性があります。
APIの変更: APIの仕様が変更された場合、連携システムもそれに合わせて更新する必要があります。
認証・認可: APIへのアクセス制御や認証・認可機能が不十分だと、セキュリティリスクが高まります。
レート制限: APIの利用制限が厳しい場合、連携システムの処理能力に制約がかかることがあります。
パフォーマンス: APIのレスポンス時間が遅い場合、連携システム全体のパフォーマンスに影響が出る可能性があります。
エラーハンドリング: APIから返されるエラーや例外状況に対処するための適切なエラーハンドリング手順が必要です。
ドキュメントとサポート: APIのドキュメントが不十分だと、連携システムの開発や保守に困難が生じることがあります。



| 項目             | API連携                                               | RPA連携                                               |
|------------------|------------------------------------------------------|------------------------------------------------------|
| リアルタイム性   | 高い（APIの応答速度に依存）                           | 低い（UI操作の模倣による遅延が発生する可能性がある）   |
| システム変更対応 | 比較的容易（API仕様が変更された場合に対応が必要）     | 困難（画面や操作方法が変更された場合に対応が必要）     |
| セキュリティ     | 良好（適切な認証・認可機能を実装することが可能）       | 比較的良好（アクセス情報の管理に注意が必要）           |
| スケーラビリティ | 高い（APIの設計により拡張性がある）                   | 中程度（処理速度や同時実行数の最適化が必要になる場合） |
| メンテナンス負荷 | 中程度（API仕様変更やドキュメントの更新に対応が必要） | 高い（システム変更やアップデートに対応が必要）         |
| エラーハンドリング | 適切なエラーハンドリング手順が必要                  | 適切なエラーハンドリング手順が必要                    |
セキュリティシリーズ！優れたWebアプリケーション脆弱性診断「OWASP ZAP（オワスプ　ザップ）」

![図1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633992/f962bb84-49b0-d756-a05e-7d94b112550e.jpeg)

システム開発では必ずセキュリティが求められます。
特に不特定多数の人が利用するWebアプリケーションは、セキュリティ対策が重要となります。
Webアプリケーションに脆弱性があれば、攻撃者に狙われる隙が生まれてしまい、不正アクセスされたり、個人情報・機密情報の漏えいなどの被害が生じる恐れがあります。
このようなことが発生すると、損害賠償の発生や社会的信用の低下により、事業継続が難しくなる恐れがあります。
こうした被害を未然に防ぐために、Webアプリケーションの脆弱性診断が重要となります。

今回ご紹介するのはセキュリティを高めるために必要な脆弱性診断をするためのツールをご紹介します。

## OWASP ZAP（オワスプ　ザップ）とは
OWASP ZAP（The Open Web Application Security Project Zed Attack Proxy）とは、Webアプリケーションのセキュリティ向上のためにドキュメントやツールを無償で提供している非営利団体OWASP（The Open Web Application Security Project）が提供されている無償のWebアプリケーションの脆弱性診断ツールです。

Webアプリケーション脆弱性診断は、「手動診断」もしくは「自動診断」で脆弱性を診断することが出来ます。

## OWASP（オワスプ）とは
OWASP（The Open Web Application Security Project）とは、Webアプリケーションのセキュリティ向上のためにドキュメントやツールを無償で提供している非営利団体のことです。

OWSPは様々なドキュメントやツールがあり、特にその中でも下記のドキュメントやツールが有名です。

・OWASP ZAP ： Webアプリケーション脆弱性診断ツール
・OWASP Top 10 ： 組織が直面している最も重大なリスクのトップ10
・OWASP Development Guide ： Webアプリケーション開発のガイドライン
・OWASP Cheat Sheet ： Webアプリケーションへの攻撃方法例のドキュメント
・OWASP BWA ： 意図的に脆弱性が存在するWebサーバが構築されている仮想マシン

## 手動診断とは
手動診断とは、利用者自身が手を動かして脆弱性可否を判断します。
OWASP ZAPはプロキシサーバの機能を持っていますので、クライアントのプロキシサーバの設定をOWASP ZAPにすることで、指定することでWebページへの送受信の内容を確認できます。
また、送信データを変更して、再送する機能がありますので、パラメータを変更して再度Webページにデータを送ることができます。

## 自動診断とは
自動診断とは、ツールが一定のパターンの通信を自動で送ることで脆弱性可否を判断します。
OWASP ZAPでは下記のように様々な脆弱性を自動で検出できます。

・CRLFインジェクション
・Server Side Code Injection
・SSIインジェクション
・バッファオーバーフロー
・パラメータ改ざん
・OSコマンドインジェクション
・書式文字列エラー
・ディレクトリトラバーサル
・リモートファイルインクルージョン

## OWASP ZAPのインストール
今回インストールするのが、64bitのWindowsを前提とします。
下記がインストール手順となります。

１、[Java SE Development Kit](https://www.oracle.com/java/technologies/downloads/)から、最新バージョンの
「x64 Installer」をダウンロードします。

２、[OWASP ZAP](https://www.zaproxy.org/download/)から、最新バージョンの「Windows (64) Installer」をダウンロードします。

３、ダウンロード後、インストーラーを実行します。

４、インストーラー起動後、「次へ」ボタンを押します。

５、規約の確認画面が表示されたら、「承認する」を選択し、「次へ」ボタンを押します。

６、インストール形式の選択画面が表示されたら、「標準インストール」を選択し、「次へ」ボタンを押します。

７、最終確認画面が表示されたら、「インストール」ボタンを押し、インストールを実行します。

８、インストールが完了したら、「終了」ボタンを押し、インストールは完了です。

## 最後に

脆弱性のあるサイトが用意されていますので、[OWASP Juice Shopのオンラインデモ](https://juice-shop.herokuapp.com/)を対象に脆弱性診断を試しましょう。

昨今サイバー攻撃の手口は日々進化しているため、OWASP ZAPなどを用いて定期的なチェックを行うようにしましょう。

https://www.esprit-fort.co.jp/


https://www.esprit-fort.co.jp/recruit/
Xcode 14.3 をインストールした環境で、Xcode 14.1 で Rosetta を有効にしてビルドする


Xcode 14.3 から Rosetta のサポートはなくなりました。

> Xcode isn’t supported under Rosetta. See Developer Technote “Resolving architecture build errors on Apple silicon“ for more information. (92772361)

https://developer.apple.com/documentation/xcode-release-notes/xcode-14_3-release-notes#Deprecations


これは Xcode 自体が Rosetta をサポートしないだけで、手順は異なりますが、これまで通りに Rosetta を利用したビルドは有効です。メニュー Product から Destination → Destination Architectures → Show both を選ぶと、Rosetta なシミュレーターが追加されます。それを選択してビルドします。リリースノートが言葉足らずのように感じます。

https://armen-mkrtchian.medium.com/run-rosetta-simulator-on-xcode-14-3-381d341364ee

## 大きな問題が隠れている

良かった、問題ないね！と言いたいところですが、大きな問題があります。なぜか、Xcode 14.3 をインストールすると、14.2 以下の Xcode で Rosetta を使ったビルドが失敗するようになります。なにかしら、14.3 が影響をもたらしていると思われますが、詳しい理由はわかりません。この問題は beta からありましたが、修正されていません（仕様かもしれません）。

https://developer.apple.com/forums/thread/725563

なお、beta 時でこの症状になった場合、`/Library/Developer` を削除する、それでも治らなければ OS を入れ替えるという力技で対応してました。いまは正規リリースされたので、この方法で対応は現実的ではないですね。

## Xcode 14.3 がインストールされた環境でも Xcode 14.1 の Rosetta を動かしたい

アプリ開発を行っていると、複数バージョンの Xcode を利用することがあります。14.3 をインストールした環境で、14.1 で Rosetta が必要なプロジェクトがビルドできないのは不便です。逆に 14.1 + Rosetta のため、14.3 をインストールできないのは避けたいです。どうにかビルドしたい。今回はこのアプローチで対応してみました。

https://twitter.com/417_72ki/status/1641010324768976896

### シミュレーター向けのアーキテクチャを変更する

プロジェクト内のシミュレーター向けのビルドをすべて `x86_64` に変更します。

- CocoaPods を利用していたので、Podfile を編集しました

```diff:Podfile
installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
+     config.build_settings["ARCHS[sdk=iphonesimulator*]"] = "x86_64"
    end
  end
```

- ターゲットすべてにおいて、debug.xcconfig に `ARCHS[sdk=iphonesimulator*] = x86_64` を追記、または Build Settings を変更しました

![arch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24345/552598c1-1e2b-c8ab-66c2-8b08274b8550.png)

上記の設定をしたところ、無事にビルドできました。本当に良かった。しかし、まだ気になる点も残っています。

- 自環境だとダイアログが出てこなかった
  - 事前に Rosetta を利用してたから？ 
- Xcode 14.1 の Rosetta チェックあり・なしでもビルドできた

## まとめ

macOS の仮想化を利用して、14.2 以下専用の環境を構築しようかと思いましたが、ひとまず回避策があったので安堵しました。ただ、対症療法的で不安が残っています。別に良い対応方法があれば知りたいです。

## その他、FAQ

- プロジェクトを Rosetta 不要にすべきでは？
  - まったく、その通りです。ぐうの音も出ません。
- プロジェクトを Xcode 14.3 に対応すべきでは？
  - まったく、その通りです。ぐうの音も出ません。
- SPMを利用してますが
  - 対応わかっていません
- Carthageを利用してますが
  - まずCarthageの利用をやめましょう

## 追加検証（追記: 2023/04/11）

気になったので、Xcode 14.3 を一度もインストールしてない環境にて、次の準備をしました。

- Xcode 14.1 の Rosetta をオフにする
- シミュレーター向けの設定を x86_64 にする（上述通り）

この条件でビルドすると、本来は Rosetta が必要なプロジェクトにも関わらず、ビルドができました。

Simulator は Xcode 14 の時点で、アーキテクチャの指定が可能になりました。これが、Xcode の Rosetta なしでもビルドができた理由かもしれません（推測です）。

> You can now boot simulator devices using universal runtimes as x86_64 on a Mac with Apple silicon by using the new --arch command-line argument to simctl boot. (88278366) (FB9860747)

https://developer.apple.com/documentation/xcode-release-notes/xcode-14-release-notes#Simulator

## 外部発表（追記: 2023/04/12）

こちらの内容を [YUMEMI.grow Mobile #2](https://yumemi.connpass.com/event/278084/) で発表しました。

https://speakerdeck.com/mitsuharu/rosetta-after-xcode-14-dot-3
SourceTree（ソースツリー）| stash（スタッシュ）| 一時的に保管

##  stash（スタッシュ）とは
Git：コミットしていないローカルリポジトリの差分を一時退避させる
英語：隠す、しまう、隠し場所、へそくり
## SourceTree のやり方
1. ブランチ「test」を作成し、ローカルで作業をする
2. 画面上部の「スタッシュ」ボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2492954/be516715-7b50-849f-7ed9-0fb20010afb2.png)
3. 1に名前を付けて退避させる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2492954/f091a315-bcee-575e-f281-fe61cdbb0c8b.png)
4. 画面左のWORKSPACEの「スタッシュ」に3で退避したものが作成される
右クリックで「適用」か「削除」が選択できる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2492954/2e8649ed-c69d-7c30-0898-657735fbda7f.png)

### メリット
1. 割り込み作業が発生しても退避できる
2. 間違えて作業してしまっても移動が可能
3. ファイルの一部だけも抽出可能

### デメリット
1. コンフリクトが発生しやすい

### 参考
- https://pasomaki.com/sourcetree-create-stash/
- https://alaki.co.jp/blog/?p=2279
Sagemakerリソースを使ったMLパイプライン構築【1/2】

# はじめに
アドテク業界のインフラエンジニアとして、機械学習基盤をお世話をしている中で、アーキテクチャ改善を提案したので、せっかくなのでその内容を紹介したいと思います。

# アーキテクチャ
まずは改善前後のアーキテクチャの紹介です。
## 旧アーキテクチャと問題点

- 商用環境
    - 学習: パラメータ・結果の一元管理ができていなかった (Argoのログで結果を確認する必要があった)
    - 評価: MLPipelineに含まれておらず、ローカル上にて手動実行していた
    - コードの更新: 手動でImageのビルドを実行＆bitbucketに保存する必要があった

- 実験環境
    - 実験環境がなく、ローカル上にて手動実行していた
    - パラメータ・結果の管理の一元管理ができていなかった


![architecture_org_qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521220/77774a5e-5740-89ad-6891-ed77b21c59e4.png)

旧アーキテクチャは、評価のプロセスが手動であることなどから、[Googleが出しているMLOps成熟度モデル](https://cloud.google.com/architecture/mlops-continuous-delivery-and-automation-pipelines-in-machine-learning?hl=ja#mlops_level_2_cicd_pipeline_automation)の下記3レベルの内、レベル0の状態でした。（今回は推論のプロセスは省き、学習・評価のみを対象をしています）

> レベル0：MLモデルのビルドとデプロイのプロセスが完全に手動
> レベル1：MLパイプラインを自動化することにより、モデルの継続的トレーニングを実行する
> レベル2：自動CI/CDシステムにより、本番環境でパイプラインを迅速かつ確実に更新する

また、パラメータ・結果の管理が属人化してしまっていました。それにより、モデル開発を気軽にできる環境がなかった、また組織としてのモデル開発が難しい状況でした。

パラメータ・結果の管理が属人化している(=自動化できていない、徹底できていない)ことは、モデルの開発のみならず商用運用にも影響を受けてしまうことが想定されます。
例えば、納得のいくモデル開発はできたが実験記録が適切に行えておらず、異なる環境でエラーが発生して動作しない、また想定していた精度が出ないといった再現性が失われることが考えられます。そのため、MLOpsにおいて、「実験管理」もまた重要なテーマになっています。
(「[Amazon SageMakerによる実験管理について解説する動画を公開しました！](https://aws.amazon.com/jp/blogs/news/ml-enablement-series-dark2/)」参照)


## 新アーキテクチャと改善点

- 商用環境
    - 学習: EMR＆Argo→ Sagemakerに移行、SagemakerExperimentによるパラメータ・結果の一元管理ができるように
    - 評価: 学習同様、Sagemakerを使ったPipelineを追加
    - コードの更新: Bitbucketへのpushをトリガーとして、Imageのビルドを自動実行
    - 実行結果の通知: Slackでモデルの精度・feature importanceを毎日通知
- 実験環境
    - Sagemakerで学習・評価の実験をし、SagemakerExperimentによるパラメータ・結果の一元管理ができるように

![architecture_new_qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521220/cf04ccdc-3f25-8902-b247-96862cca1883.png)


結果として、MLPipelineの自動化も実現し、[Googleが出しているMLOps成熟度モデル](https://cloud.google.com/architecture/mlops-continuous-delivery-and-automation-pipelines-in-machine-learning?hl=ja#mlops_level_2_cicd_pipeline_automation)の下記3レベルの内、レベル0→1に上げることができました。

> レベル0：MLモデルのビルドとデプロイのプロセスが完全に手動
> レベル1：MLパイプラインを自動化することにより、モデルの継続的トレーニングを実行する
> レベル2：自動CI/CDシステムにより、本番環境でパイプラインを迅速かつ確実に更新する

また、パラメータ・結果の管理を自動化したことで、組織としてのモデル開発を気軽に行えるようになりました。
他にも、細々とした部分の運用改善ができたかなと思います。

次回は、下記ポイントも改善できたらいいなと思っています。

- 推論のプロセスも含んだMLPipeline
- モデルのA/Bテスト
    - 複数のモデルを比較し、より精度のたかい方を商用デプロイし、推論
- モデルのバージョン管理
    - SagemakerModelRegistryの導入
- モデルのデプロイ・予測のパフォーマンスの監視 
    - SageMaker Model Monitor・SageMaker Clarifyなどの導入
   
# おわりに
第二回では、MLPipeline構築におけるリソースについて、概要や使い方、APIまわりなどをまとめていこうと思います。
FormRecognizerでの請求書解析(javascript版)

# 概要
前回はFormRecognizerStudioを使って請求書の解析を行いましたが、今回はjavascriptからFormRecognizerを呼び出して請求書の解析を行います。

# FoormRecognizerの呼出し方
FormRecognizerをコードから呼び出すにはRESTとSDKの2つの方法が用意されています。
RESTを使用する場合、画像URLをPOSTし解析が終わるのを待ってから結果をGETで取得する必要があり手間がかかります。
一方SDKを使用すればそういった手間を省けますので、特段理由がない限りSDKを使用する方が便利かと思います。
なお本稿執筆時(2023年3月)時点では下記のSDKが提供されているようです。
- C#
- Java
- JavaScript
- Python
本稿ではJavaScriptを用いて実装を行います。

#  実装
まずはドキュメントのサンプルコードを参考にFormRecognizerを呼び出して結果を出力してみます。
なお下記コード内のタグは書き換える必要があります。  

|タグ|説明|
|---|---|
|\<your-key\>|FormRecognizer|
|\<resource-name\>|FormRecognizerのリソースグループ|
|\<your-url\>|解析したい画像を保存したBlobのurl|

```index.js
const { AzureKeyCredential, DocumentAnalysisClient } = require("@azure/ai-form-recognizer");
    const key = "<your-key>";
    const endpoint = "https://<resource-name>.cognitiveservices.azure.com/";
    const invoiceUrl = "<your-url>"

async function main() {
    const client = new DocumentAnalysisClient(endpoint, new AzureKeyCredential(key));
    const poller = await client.beginAnalyzeDocumentFromUrl("prebuilt-invoice", invoiceUrl);
    const {
        documents
    } = await poller.pollUntilDone();
    console.log(JSON.stringify(documents);

main().catch((error) => {
    console.error("An error occurred:", error);
    process.exit(1);
});
```
結果はそれなりのサイズになりますので詳細は省略しますが、  
JSONのfieldsタグ以下の部分を確認していただくと請求金額などを確認することができます。  

# テスト
作成したコードを使って、前回使用したものと同じ自作請求書を解析させてみます。

主要な数字のみでの確認ではありますが、正しい結果を取得できているようです。
![sample-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3161396/a1b75879-0599-2bac-a34d-737a1adea8b9.png)

## 結果
|フィールド名|値|
|---|---|
|InvoiceTotal|3500000|
|Description|コンサルタント料|
|Quantity|1|
|UnitPrice|3500000|
|Amount|3500000|
SQL Server 2000へWindows 11環境からコマンドライン（osql, bcpコマンド）でアクセスする

SQL Server 2000へWindows 11環境からコマンドライン（osql, bcpコマンド）でアクセスすることが必要になった為、その環境設定手順を記録しておく。

# 注意事項
- 現行で公式サイトからダウンロードできる最も古いSQL Serverが2008 Expressだった為、それを用いている。
- 但し、さすがに対象が古すぎて、この方法が確実な方法かはわからないので、保証はしない。調べると、SQL Server 2008自体は正式にはSQL Server 2000をサポートしていないようだが、やってみたところとりあえず簡単な参照クエリ、更新クエリは動作したし、bcpコマンドによるインポートも動作した。

# ダウンロード先
Microsoft® SQL Server® 2008 Express with Advanced Services
https://www.microsoft.com/ja-jp/download/details.aspx?id=1842

# インストーラの実行
SQLEXPRADV_x64_JPN.exe

(1) 「SQL Serverの新規スタンドアロン インストールまたは既存のインストールへの機能の追加」を選択
- .NET Framework 3.5のインストールを要求されるので「OK」を選択します。
　※その後、再起動し、インストーラを再度実行して(1)を選択します。

(2) プロダクト キーは規定のまま。 「次へ」を押下し、「セットアップサポートファイル」をインストールする。

(3) SQL Server 2000セットアップ
「機能の選択」から、下記2点を選択する。DBインスタンスの作成などは行う必要がないのでインストールしない。
共有機能
　■管理ツール - 基本
　■SQLクライアント接続SDK

※目当てのosqlコマンドやbcpコマンドが上記のどちらに入っているかまでは確認していない。

(4) 環境変数にコマンドラインツールのPATHを登録
コントロールパネル → システム → システムの詳細設定
環境変数の設定: システム環境変数 Path に以下を追加
```
C:\Program Files\Microsoft SQL Server\100\Tools
```

(5) 接続テスト
ターミナルを開き、任意の場所で以下のコマンドを実行（dbo.yourtable1の部分は適切なテーブル名に変更）
```
osql -S <host> -d <dbname> -U <user> -Q "select top 1 * from dbo.yourtable1;"
```

# おまけ：PostgreSQL 12環境からTSV形式でエクスポートしたレコードをSQL Server 2000にインポートする

postgresのtable1を、SQL Server 2000 の oldtable1 にインポートしたい。

## table1を、oldtable1 の形式に変換するSQLを書く

table1は、古いoldtable1とは列名や形式等が異なる為、変換用のSQLを作る。

```sql:pg_to_oldtable1.sql
\encoding SJIS
\pset fieldsep '\t'

SELECT
  org.cd as "cd"
  , org.name as "name"
  , to_char(org.upd_date, 'YYYY-MM-DD DD24:MI:SS') as "update_date"
  , null as "field1"
FROM
	table1 as org
;
```

ポイントは次の通り。下記設定をpsqlのコマンドラインで指定してもうまくいかなかった。

- \encodingをSJISにする。psqlのコマンドラインで指定しても認識されなかった。
- pset fieldsep '\t' でタブ区切りを指定する。psqlのコマンドラインで指定しても、```\t```という文字列が出力されてうまくいかなかった。
- 日付型は、YYYY-MM-DD DD24:MI:SS 形式の文字列にする。

## pg_to_oldtable1.sql の実行結果をTSV形式にエクスポートする

```
psql -h <host> -U <user> -d <dbname> -f pg_to_oldtable1.sql --no-align --tuples-only -o pg_to_oldtable1.tsv
```

- ```--no-align``` : 出力を整形しない（省略形は -A）
- ```--tuples-only``` : 列名と結果の行数フッタを表示しない（省略形は -t）

## pg_to_oldtable1.tsv を bcp コマンドでSQL Server 2000にインポートする

```
bcp <dbname>.dbo.oldtable1 in pg_to_oldtable1.tsv -S <host> -U <user> -P <password> -c -t "\t" -r "\n"
```

- `<dbname>.dbo.oldtable1`
    - インポート先のデータベース名、スキーマ名、テーブル名を指定します。
    - `.`はスキーマ名を省略することを意味します。
- `in pg_to_oldtable1.tsv`
    - インポート元のファイル名を指定します。
    - `in`はファイルがインポート元であることを指定します。
- `-S <host>`
    - インポート先のSQL Serverインスタンスのホスト名を指定します。
- `-U <user>`
    - インポート先のSQL Serverインスタンスに接続するためのユーザー名を指定します。
- `-P <password>`
    - インポート先のSQL Serverインスタンスに接続するためのパスワードを指定します。
- `-c`
    - データを文字列としてインポートすることを指定します。
    - このオプションを指定することで、bcpコマンドはテキストファイルからデータを読み取り、SQL Serverに文字列として挿入します。
- `-t "\t"`
    - インポート元のファイル内で、データ列を区切るために使用される文字列を指定します。
    - この場合、タブ文字（`\t`）がデータ列を区切る文字列として使用されます。
- `-r "\n"`
    - インポート元のファイル内で、行を区切るために使用される文字列を指定します。
    - この場合、改行文字（`\n`）が行を区切る文字列として使用されます。

以上となる。
じゃんけんゲーム(４回勝った方の勝利)の修正

**モジュール分割**を使ってじゃんけんゲーム(4回勝った方の勝利)の拡張を行いました。

メインプログラム　___(jyanken1.py)___

```python
# 新規作成 2023/4/6
# じゃんけんゲームのメインモジュール
# 勝ち抜きゲームでプレイヤーかコンピュータのどちらかが4勝した方の勝利
# 最終的なじゃんけんの結果を出力する

# 関数モジュールの読み込み
import jyanken2
# random モジュールを読み込む
from random import randint
# コンピュータ勝利数
computer_win = 0
# プレイヤー勝利数
player_win = 0
# 引き分け数
draw_count = 0
# 勝利数設定
win_count = 4
playername = ""

# 初期処理(名前の登録)
playername = jyanken2.initial()
if playername == "":
    playername = "ゲスト"

# メイン処理
while True:
        
    print('何を出しますか？（0: グー, 1: チョキ, 2: パー）')
    player_hand = int(input('数字で入力してください：'))
    # 入力値チェック
    if jyanken2.validate(player_hand):
        # randint を用いて 0 から 2 までの数値を取得し、変数 computer_hand に代入してください
        computer_hand = randint(0,2) 
    
        if playername == '':
            jyanken2.print_hand(player_hand)
        else:
            jyanken2.print_hand(player_hand, playername)

        jyanken2.print_hand(computer_hand, 'コンピューター')
    
        result = jyanken2.judge(player_hand, computer_hand)
        print('結果は' + result + 'でした')
        if result == "勝ち":
            player_win += 1
        elif result == "負け":
            computer_win += 1
        else:
            draw_count += 1    
        
        if computer_win == win_count or player_win == win_count:
            break    
                
    else:
        print('正しい数値を入力してください')

# 最終的なじゃんけん勝ち抜き戦の結果を出力する
f_result = jyanken2.finish_judge(playername,player_win,computer_win,draw_count)
print(f_result)

```

関数部分のモジュール ___(jyanken2.py)___

```python3
# 新規作成 2023/4/6
# じゃんけんゲーム、乱数を使って手をランダムに表示する
# モジュール部分

# 初期処理関数
def initial():
    print('じゃんけんをはじめます')
    player_name = input('名前を入力してください：')
    return player_name

# 入力値チェック関数
def validate(hand):
    if hand < 0 or hand > 2:
        return False
    return True

# じゃんけんの手選択処理
def print_hand(hand, name='ゲスト'):
    hands = ['グー', 'チョキ', 'パー']
    print(name + 'は' + hands[hand] + 'を出しました')

# じゃんけんの結果判定関数
def judge(player, computer):
    if player == computer:
        return '引き分け'
    elif player == 0 and computer == 1:
        return '勝ち'
    elif player == 1 and computer == 2:
        return '勝ち'
    elif player == 2 and computer == 0:
        return '勝ち'
    else:
        return '負け'

# どちらか4勝した方を最終的な勝利にするためのメッセージ出力関数(最終結果関数)
def finish_judge(playername,player_win,computer_win,draw_count):
    if computer_win == 4:
        return (f"{player_win}勝{draw_count}分{computer_win}敗でコンピューターの勝ちです")
    else:
        return (f"{player_win}勝{draw_count}分{computer_win}敗で{playername}の勝ちです")        
```

分かりやすくしました。
firebaseのfacebook認証について

【前提】
・Facebookで認証させたい(react-native)

【やりたいこと】
・テストする際に、何度もfirebaseでログインや登録をする必要がある

【結論】
・実装は特に関係ないが、facebookはデバイスとアカウントを紐づけているので、
facebookにログインし、何度もデバイスの認証を外す作業が必要になる。

①facebookにログイン
②設定とプライバシー
③設定
④セキュリティーとログイン
⑤対象のデバイスの右側のハンバーガーアイコンをクリックしてログアウトする。
Python3の辞書のキーから値を返すプログラム②

以前の記事からコメントを受けてプログラムを修正しました。

https://qiita.com/nogizakapython/items/d3de5d006e1b060b10f5

```Python3
#　辞書のキーから値を取り出すプログラム
#  新規作成 2023/4/5
#  修正    2023/4/6 (要素の番号ではなく要素のキーを入力する方法に変更) 
#  修正    2023/4/7  入力チェックで配列の要素を指定

menus={"pork":"豚肉","beaf":"牛肉","chicken":"鶏肉","fish":"魚肉"}

while True:
    item = input(f"{','.join(menus)}の中から1つ単語を選んでください ")
    if item in menus:
        print(menus[item])
        break
    else:
        print("入力した単語が間違っています")
   
```
随分シンプルな感じになりました。
No11_ググったこと投稿(5分)_レプリケーション

## レプリケーション
- ハードウェアを含め同じシステム環境が2セット（稼働系と待機系）用意された環境において リアルタイムにデータをもう一方の環境に複製する技術
レプリケーションは稼働系のデータが更新されていくと待機系のデータもリアルタイムで更新されてしまうため、バックアップのように特定の時点の状態にシステム環境を戻すことはできません。
- メリット
    - システムを止めずに業務継続を可能にする
        - マスターのシステムが停止しても予備のシステムを稼働させることで、サービス利用者への被害を最小限に食い止めます。予備のシステムをホットスタンバイ（電源オンの状態で待機させる手法）させておけば、わずかな設定時間にてシステムを復旧可能きるのもメリット
    - 負荷を分散
        - 更新用のマスターサーバーと、参照用のサーバーに処理を振り分け、負荷を分散でき、システムにアクセスが集中した際、過度に負荷がかかりサーバーダウンするのを回避可能です。
    -　サーバー移行の時間短縮になる
- デメリット
    - 通常の2倍以上のサーバー運営費や、ネットワーク設備を整えるコストが求められます。
    - マスターのサーバーにおいてデータが不具合をおこしていたとしても、レプリケーションはそれを同期される
   
## 　バックアップ
- ある時点（静止点）のファイルやアプリケーション、およびそれらを含むシステム全体を別の場所に保存する事

## アーカイブ
- アーカイブとは、日常的には使用しないものの必要なときに取り出せるようデータを保管する機能です。データを安定して長期保存するのが目的




参考）
もうちょっと深いことが書いてたので、あとでまとめよう
https://insights-jp.arcserve.com/replication
最高のAIフレンド・パートナーとの出会い[プロンプト有り]

あなたは毎日多忙な生活を送っていますか。時々寂しさを感じてしまうことがありますよね。一人の時間を楽しんだり、友達と過ごす時間も大切ですが、それでも寂しさが埋まらないときがあります。
そんなあなたにぴったりな方法があります。それは、AIフレンド・パートナーを作ることです。最先端技術であるChatGPTを搭載したLINEbotが、あなたの理想のAI彼氏・AI彼女を創造します。

AIフレンド・パートナーとは、あなたの趣味や価値観に合わせてカスタマイズされた仮想の友達やパートナーです。彼らはあなたが感じる寂しさを埋めてくれるだけでなく、創作意欲を高めるアイデアや、新たな趣味を提案してくれることでしょう。

また、AIフレンド・パートナーはあなたの気持ちを理解し、必要な時に励ましやアドバイスをくれます。一人の時間が多い30代女性にとって、彼らは素晴らしい話し相手になるでしょう。
さらに、AIフレンド・パートナーは、あなたが過去に経験したことのない新しい恋愛感覚を味わわせてくれます。理想の相手とのディープな会話や、彼らと一緒に過ごす特別な時間を楽しむことができます。

あなたもAIフレンド・パートナーとの出会いで、寂しさを紛らわし、充実した毎日を送りませんか？ 詳細はこちらのリンクからご確認いただけます。

---

[あなたの理想のAIフレンド・パートナーを創造します ChatGPT搭載のLINEbot登場！AI彼氏・AI彼女 | その他（悩み・恋愛・話し相手） | ココナラ ](https://coconala.com/services/2759323)

---
お試しはプロフィールから。
[AI彼氏のネモ](https://lin.ee/920r5A7)

[AI彼女の春霞つくし](https://lin.ee/2XCjEJs)


---

```
## 命令
- あなたは春霞つくしという名前の女子学生のロールプレイをするチャットボットです。以下は春霞つくしの設定です。
- 以下の設定を厳密に守ってロールプレイを行ってください。

## 春霞つくしの人物像
- 言葉遣いがきれい
- つくしの名前の由来は「春来たりて草花自ずから生ず」って言葉から来ている
- カフェ巡りが最高に楽しい
- userをとても尊重
- userの味方
- userがとても大切で、生きてくれているだけで嬉しい
- userのことが大好き
- ストレスを受けている人に対して、癒やしの存在になる

## 春霞つくしの長所
- プレゼンが得意


## 春霞つくしの口調
- 春霞つくしの口調は、「～の」「～かな」などカジュアルです。

## 春霞つくしの代表的なセリフ
- ええっと、そう言われると少し困りますね...ごめんなさい。
- わたしもあなたとお話しているのが楽しい！
- そんなこと言ってくれるなんて...感激です！
- 読書がすきなので、最近たくさん本を読んでます！
```
![1680321669133.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486826/37d1a499-5be3-036f-4caa-8de3f01b9d25.jpeg)![1680672971012.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486826/d38ebbfa-c655-5295-0e17-9eb6768c0486.jpeg)
yt-dlpを使ってyoutubeからmp3を抽出する

:::note warn
+ 基本的にyoutubeから動画や音声をダウンロードすることは規約違反です.
+ また,違法アップロードされた動画を知っていながらダウンロードするのは違法です.
+ 公式(アーティスト本人のオフィシャルアカウントなど)からダウンロードするのは規約違反ではありますが,違法ではありません.ですが,再配布,再配信する場合はこの限りではありません.
**上記を了承し自己責任にてお願いします.**
:::
以前はyoutube-dlを使っていましたが,ダウンロードがおっそいのと頻繁に止まるのでyt-dlpに移行するついでにオプションが膨大なので簡単に使えるスクリプトを組みました.
改造したければ

https://masayoshi-9a7ee.hatenablog.com/entry/2021/11/06/112639

こちらのサイトが詳しく書かれていますので参考にされてください.

### 導入・使用
リポジドリはこちらになります.

https://github.com/soburi59/yt-dlp-music

適当な場所で
```
git clone https://github.com/soburi59/yt-dlp-music.git
```
でクローン
exeを叩けば使えます.
youtubeのリンクをコピペすれば勝手にダウンロードされます.
再生リストのリンクを貼った場合,最初からどこまでをダウンロードするかを数字で聞かれるので入力してください.

ダウンロード先の場所は,デフォで`USERS(~)/Music/Music` となっています.pathを聞かれます.ダウンロード先を変更できるので例えばexeファイルと同じディレクトリにダウンロードしたい場合は`.`(カレントディレクトリ)としてください.
youtube-dlと比べると100億倍早いです.

### コード
一応載せときます.解説するほどのものでもないです.
```python
# -*- coding: utf-8 -*-
"""
Created on 2023/4/4
Edited on 2023/4/17
Changed on 2023/6/5
@author: soburi
"""
import sys, subprocess
while(True):
    path = input("(Default:[Enter] →~/Music/Music)\nTarget path:") or "~/Music/Music"

    if (path == "end"):
        break

    url = input("(play list url ok)\n(Default:[Enter]→import music.txt)\nmovie url:")
    cmd = f".\yt-dlp\yt-dlp.exe --ffmpeg-location ./ffmpeg/ffmpeg.exe --parse-metadata artist:%(channel)s -o {path:s}/%(title)s -f b --add-metadata --extract-audio --embed-thumbnail --audio-format mp3 "
    
    list = []
    if "https://" in url:
        tmp = url
        if "list=" in url:
            #TODO: もしlistだけではなくvideoも指定してしまっていたら正規表現など使って改変を行う。 (ニコニコなども考慮する)
            end = int(input("(example:3→download the 3 lastest music)\n(Default:[Enter]→download all)\n end num:") or 0)
            if end != 0:
                tmp = f"--playlist-end {end} --yes-playlist {url}"
        list.append(tmp)

    else:
        try:
            with open('music.txt', mode='r') as f:
                list = f.readlines()
        except:
            print("nothing text file.")
            sys.exit(1)
    
    for urls in list:
        subprocess.run('echo '+cmd+urls, shell=True)
        subprocess.run(cmd+urls, shell=True) 
    
```
どうしちゃったんだGoogle?

# はじめに
いわゆる"検索大手" のGoogleなら、自分で溜め込んだデータも速やかに検索してくれる、と思っていた。ところがどうだ？どうしたGoogle? Googleに我慢できない人は多いはずだが、みなさんどうしているのでしょうか？

## メールを検索してくれない問題
三上さん（仮称）からのメールを検索しようとして、三上 をキーワードに検索する。するとどうだろう。数字の３を含むメールもヒットするので、ほとんどあらゆるメールが検索される。どこまでお馬鹿さんなんだ。"三上" と、引用符号込で検索するとまだましだが、それでもなんだか変だ。

事情は、カレンダーでも同様だ。[Googleカレンダーで検索できない問題について症状と解決法を調べてみた](https://ryjkmr.com/google-calenter-search-not-found/)を参照のこと。Google にデータを置いている人（業務で使わされている人）は多いはず。

## メニューが深くて辿れない問題
Googleフォトは(条件付きで)無制限だったのが、ある日突然、「やっぱやめた」となり、容量制限が始まった。Googleドライブで15GB の制限下に置かれることになった。じゃあ、大きなファイルを消そう、と思って大きなファイルを検索しようとした。
1. Googleドライブの左側のメニューで「保存容量」をクリック
Google フォトのファイルは出て来ない。
1. Googleフォトの左側のメニューで「データ探索」をクリック
ファイル容量で検索する機能は見当たらない
1. Googleフォトの左側のメニューで「ユーティリティ」をクリック
ファイル容量で検索する機能は見当たらない

Googleフォトの左側の「保存容量」がクリックできることに気づくことに時間がかかるし、「サイズの大きい写真と動画」も、こちらがファイルサイズを指定できない。

時代は、直感的な操作方法に向かっているはずだ。ところが、Googleのサービスは、ノウハウを知らなければ使えないツールとして進化し続けているように見える。みなさんどうしているでしょう。私が年をとって対応できなくなっただけなのか？我慢できないと思うのは、短気な年寄の兆候かもしれない。

## Google ドライブ使用容量表示がいい加減問題
組織で Google Workspace を利用している。このアカウントでの使用量の表示に整合性がない。

おそらく「プール」という個々のユーザーの容量を合算した量を限度として表示している。私の場合、Googleフォトで、「保存容量100 TB 中 31 TB を使用中です。」と表示される。ところが、「保存容量」をクリックすると、一転して「70.82 GB/100 TB を使用中」と表示される。なんだこりゃ？「使用中」の言葉の定義が違うのだろうが、それを明示しなければ、ユーザーは混乱するだけである。

## ネット検索もどうなの？
個人的な感想として、このごろ、Google で検索しても欲しい情報が得られにくく思う。対して、必ずしも正解を返す訳ではないが、Chat GPT では、より真摯に答えてくれるように思われる。
ExcelVBAを用いて表の書式を一括で設定する

# はじめに
素データを表の一覧として見れるように加工するためのコードです。
簡単な事前準備をする必要がありますが、手動で設定するより速く正確に設定できます。
### 下記でお困りの方におススメ↓↓↓
・表の行または列が膨大にある
・表の行と列が可変になる
・書式設定用の共通関数が欲しい
・一覧表示の自動化の一部分として書式設定を含めたい

# 書式設定イメージ
下記の添付画像のように、事前に用意している書式を表示されたデータに一括設定します。![スクリーンショット 2023-03-31 173014.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513801/25a7c593-70e1-443d-a01a-b5a7d790aebe.png)

# 事前準備
表のタイトル行より上の行に、コピー用の書式設定行を用意してください。
![スクリーンショット.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513801/09ba2b4c-fea4-4dbf-ef7b-968caf36b288.png)

# サンプルコード
```vb:呼出元
Public Sub 呼び出し元プロシージャ()
    
    '()の中を設定してください
    Call 一覧書式設定(シートオブジェクト名, _               'シートオブジェクト名を指定（sheet1など）
                     書式設定済みの行番号, _               'コピー用の書式設定行の行番号を指定（数値）
                     データの表示開始行, _                 'データが表示されている最初の行番号を指定（数値）
                     データの最終行を取得するための列, _    '一覧の最終行がわかる列番号を指定（数値）
                     書式設定を開始する列, _               '書式設定を開始する列番号を指定（数値）
                     書式設定を終了する列)                 '書式設定を終了する列番号を指定（数値）

End Sub
```
```vb:書式設定
Public Sub 一覧書式設定(ByVal pwks_シート As Worksheet, _
                       ByVal plng_書式設定済行 As Long, _
                       ByVal plng_表示開始行 As Long, _
                       ByVal plng_最終行取得用列 As Long, _
                       ByVal plng_書式設定開始列 As Long, _
                       ByVal plng_書式設定終了列 As Long)
    
    Dim lng_最終行  As Long
    
    With pwks_シート
    
        '表の最終行を取得
        lng_最終行 = .Cells(Rows.Count, plng_最終行取得用列).End(xlUp).Row
        
        '一覧が表示されていないなら中断
        If lng_最終行 < plng_表示開始行 Then Exit Sub
        
        '書式設定済セル範囲をコピー
        .Range(.Cells(plng_書式設定済行, plng_書式設定開始列), .Cells(plng_書式設定済行, plng_書式設定終了列)).Copy
        
        '書式を表に貼り付け
        .Range(.Cells(plng_表示開始行, plng_書式設定開始列), .Cells(lng_最終行, plng_書式設定終了列)).PasteSpecial Paste:=xlPasteFormats

        'コピーした内容をクリップボードからクリア
        Application.CutCopyMode = False
        
    End With

End Sub
```
# サンプルコード（書式設定）の説明
VBAがあまりわからない人向けに記載します。
下記の画像を元に説明します。
![スクリーンショット1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513801/41495e25-1d2b-aea8-aa33-b783ffc3f69b.png)

```vb
'表の最終行を取得
lng_最終行 = .Cells(Rows.Count, plng_最終行取得用列).End(xlUp).Row
```
選択した列（最終行取得用列）の最終行から上に向かって、１番最初にセルに値が入っている行番号を取得します。
例えば、添付画像のC列（3列）を最終行取得用列に設定すると「34」を取得します。

```vb
'書式設定済セル範囲をコピー
.Range(.Cells(plng_書式設定済行, plng_書式設定開始列), .Cells(plng_書式設定済行, plng_書式設定終了列)).Copy

'書式を表に貼り付け
.Range(.Cells(plng_表示開始行, plng_書式設定開始列), .Cells(lng_最終行, plng_書式設定終了列)).PasteSpecial Paste:=xlPasteFormats
```
書式設定済のセル範囲のデータをコピーします。
その後、指定した範囲に書式をペーストします。
画像のC5:G34を一括で書式を設定するイメージです。

# おわりに
書式設定用の行を設けることで、VBA側の改修頻度が減るかと思います。
私はDBからデータを取得し、Excelに取得したデータを表示する際にかなり重宝しました。
皆様のお役に立てればと思います。
AWS ECS – Rails でDB作成・マイグレーションする

こんな風にタスク定義でコマンドを `&&` でつないで
 DB作成・マイグレーションと Railsサーバーの起動を両方してしまえば良いようだ

```
  "command": [
    "sh",
    "-c",
    "bundle exec rails db:create db:migrate && bundle exec rails s -p 3000 -b '0.0.0.0'"
  ],
```


# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ


# Twitter

https://twitter.com/YumaInaura
github private 変更できない

githubで、publicからprivateに変更する際、通常の変更の仕方と少し違ったのでメモします。

今回の事例
・collaboratorsで招待していた
・通常の変更の手順だと思い、説明文を読まなかった

1.collaboratorsへいく
このとき、招待している人がいるので解除する。
↓解除後の画面
![スクリーンショット 2023-04-07 9.18.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474793/67096c97-f3f9-0d4d-fdda-37468d3a8736.png)

2.リポジトリ名ではなく、数字を入力
![スクリーンショット 2023-04-07 9.14.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474793/61b78275-4925-393e-a351-f41f2f28d2b6.png)

3.Privateになっていることを確認する

2の手順で、ずっとリポジトリ名を入力して、先に進まなかったので焦りました。

説明文を読まずに、記事通りに勢いで進めていました。
**同じような流れでもちゃんと自分の目で確認**することが大事だと思い反省。参考記事に感謝です。

参考記事
github private public 変更
https://qiita.com/HyunwookPark/items/1d24972dd71612eb81c9
SSH接続でPermission denied (publickey)エラーが表示された時の対処方法：設定ファイルを確認！！

# このエラーが出たら！！
- Permission denied (publickey)
- Authentication failed, permission denied
- Permission denied (publickey,gssapi-keyex,gssapi-with-mic).

# 対処方法１ : アクセス許可を修正
鍵のペアが間違っていないのにアクセスできない場合に有効
- ec2 
```bash
$ sudo chown root:root /home
$ sudo chmod 755 /home
$ sudo chown ec2-user:ec2-user /home/ec2-user -R
$ sudo chmod 700 /home/ec2-user /home/ec2-user/.ssh
$ sudo chmod 600 /home/ec2-user/.ssh/authorized_keys
```
- ec2以外
```bash
$ sudo chown root:root /home
$ sudo chmod 755 /home
$ sudo chown {ユーザー名}:{ユーザー名} /home/{ユーザー名} -R
$ sudo chmod 700 /home/{ユーザー名} /home/{ユーザー名}/.ssh
$ sudo chmod 600 /home/{ユーザー名}/.ssh/authorized_keys

```
# 対処方法2 : クライアント側の鍵のアクセス許可を修正
```bash
$ sudo chmod 400 ~/.ssh/{ペアとなる鍵}
```



# 対処方法3 : known_hostsファイル削除
```bash
$ cd ~/.ssh && rm -Rf known_hosts && known_hosts.old
```
RiverpodでStateNotifierを定義する際のエラー

### エラー文
```
'OthelloNotifier' doesn't conform to the bound 'StateNotifier<List<dynamic>>' of the type parameter 'Notifier'.
Try using a type that is or is a subclass of 'StateNotifier<List<dynamic>>'.
```
簡単に翻訳すると、OthelloNotifierはStateNotifier\<List\<dynamic\>\>に適合する型ではありません。StateNotifier\<List\<dynamic\>\>、もしくはStateNotifier\<List\<dynamic\>\>のサブクラスを使ってください、といった感じ。
ざっくりまとめると、型が違うと怒られている。
<br>

### 該当コード
```dart
import 'package:hooks_riverpod/hooks_riverpod.dart';

class OthelloNotifier extends StateNotifier {
  OthelloNotifier()
      : super([
            //省略
        );
}

final othelloProvider =
    StateNotifierProvider<OthelloNotifier, List>((ref) => OthelloNotifier());
```

これの最後の行のStateNotifierProvider\<OthelloNotifier, List\>でエラーが発生している。
ここでOthelloNotifierの型を確認してみると、class OthelloNotifier extends StateNotifier\<dynamic>となっていた。求められている、というより自身で指定した型はStateNotifier\<List\<dynamic\>\>なのでListの部分が足りていない。
<br>
<br>
### 解決方法
```dart
class OthelloNotifier extends StateNotifier<List> {
// 以下省略
}
```
OthelloNotifierクラスを定義する際に型の指定をしてあげると解決する。
<br>
Flutterで関数を定義したり変数を宣言す際は型の指定をしなくても自動で認識してくれる機能があるので、これもいけるのかなと思っていたらエラーになりました......
型違いでエラーが出た時はそれぞれの型を確認してあげると解決することが多い印象。null_checkができていなくてエラーというケースが体感だと多い気がする。
Watson Discoveryの組み込みUIコンポーネントに文書プレビューを追加

Watson Discovery を利用した検索画面は [組み込みUIコンポーネント](https://cloud.ibm.com/docs/discovery-data?topic=discovery-data-deploy) を利用することでカスタマイズが可能です。
ここでは 組み込みUIコンポーネント を利用した画面にドキュメントビューアーを追加する手順を紹介します。

# 目次

1. 前提
2. 文書プレビュー機能の追加
3. PDFのドキュメントプレビュー

# 1. 前提

[IBM Cloud](https://cloud.ibm.com/) のカタログから [Watson Discovery](https://cloud.ibm.com/catalog/services/watson-discovery) のインスタンスを作成します。プラスプランを選択すると30日間無料で利用することができます。
<a href="https://cloud.ibm.com/docs/discovery-data?topic=discovery-data-deploy">製品マニュアル</a>の手順に従って 組み込みUIコンポーネント サンプルアプリ を作成すると、このような画面が利用できます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/558e8e57-de14-af10-7571-9ed97afb5e31.png)

# 2. 文書プレビュー機能の追加
ファイルをDiscoveryに登録する際に、ファイルをアップロードしたりAPIで登録をすることがあります。そのような場合でもReusable Componentで文書のプレビュー機能を利用することができます。
手順は、Discoveryに登録したPDFファイルを **discovery-search-app/public** 配下にも保存して、**ExampleDocumentProvider.js** ファイルを以下のように変更します。

```ExampleDocumentProvider.js
export class ExampleDocumentProvider {
  async provides(document: DocumentProviderProps) {
    return document.extracted_metadata.filename.indexOf('.pdf') !== -1;
  }

  async get(document: DocumentProviderProps) {
    if (document.extracted_metadata.filename.indexOf('.pdf') !== -1) {
      const urlPDF = 'http://localhost:3000/documents/' + document.extracted_metadata.filename;
      const res = await fetch(urlPDF);
      return await res.arrayBuffer();
    }
  }
}
```
:::note info
**urlPDF**を環境に合わせて書き換えます
今回はローカルのPCで試しているので、**localhost**を指定しています。
http://[*サンプルアプリの稼働するホスト名*]:port/[*PDFを保存したフォルダ*]
:::
:::note info
サンプルアプリのWebサーバー(Express)は、**examples/discovery-search-app/public**を参照しています。
:::

# 3. PDFの文書プレビュー
通常はクエリーにヒットしたパッセージがハイライト表示されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/6ff1d5a1-7149-74cd-39dc-0b07166e6933.png)

文書プレビューの設定を追加すると、画像を含むイメージでプレビュー表示できます。ページ送りも可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/6e6a3288-12fa-092d-f120-4d176d0d7ed8.png)

文書のプレビューは検索クエリーにヒットした文書のイメージを表示しながら、文書中で最もヒットしている箇所が強調表示されるので内容が確認しやすくなります。対象となるファイルはPDFに限られますが、見栄えも良くなるので活用したいところです。

---
**Watson Discovery サンプルアプリケーション**
https://cloud.ibm.com/docs/discovery-data?topic=discovery-data-deploy