OmniAICreator/Qiita-1.07M huggingface dataset:
App Store ConnectでiOSアプリのアプリ内課金の審査に落ちた話

初めてアプリ内課金を実装して審査依頼をしたところ、リジェクト（泣）
```
Guideline 2.1 - Performance - App Completeness

We are unable to complete the review of your app because one or more of your in-app purchase products have not been submitted for review.

Next Steps

To resolve this issue, please be sure to take action and submit your in-app purchases and upload a new binary in App Store Connect so we can proceed with our review. 

Resources 

Learn more about how to offer in-app purchases in App Store Connect Developer Help.
Please see attached screenshots for details. 

```

App Store ConnectのApp内課金とサブスクリプションが選択されていなかったことが原因。
![スクリーンショット 2023-04-21 6.32.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2706870/1ce09429-8484-808e-944a-430b72114fe0.png)

選択したら無事審査通りました！
Excelで指定した月の最終日を取得し、土日を除いた日付を計算する方法

## はじめに
Excelを使った日付の操作は、ビジネスやデータ分析において一般的によく利用されます。
特に、特定の条件に合致する日付を取得する関数は、よく使われる機能の一つです。
この記事では、指定した月の最終日を取得し、土日を除外する関数の作成方法について紹介します。

## 条件の明確化:
まずは、求める条件を明確にします。本記事で解決するべき条件は以下の通りです。

- 指定した月の最終日を取得する
- 土曜日と日曜日を除外する
- 最終日が土曜日または日曜日の場合は、直前の平日を取得する

## 関数例
今回は2パターン紹介します。
※Excel関数のシンタックスハイライトをどうやって設定すればいいのか分からなかったので、とりあえずvbを指定しています・・・

### パターン1

```vb
=WORKDAY(EOMONTH(指定した月の日付, 0)+1, -1)
```

### パターン2

```vb
=IF(WEEKDAY(EOMONTH([指定月のセル],0),2)<=5,EOMONTH([指定月のセル],0),IF(WEEKDAY(EOMONTH([指定月のセル],0),2)=6,EOMONTH([指定月のセル],0)-1,EOMONTH([指定月のセル],0)-2))
```


## 関数の補足

### EOMONTH関数の活用
条件を満たすためには、Excelの組み込み関数であるEOMONTH関数を活用します。
この関数は、指定した日付を含む月の最終日を取得することができます。

### WEEKDAY関数を使った曜日の判定
取得した最終日の曜日を判定するためにWEEKDAY関数を使用します。
この関数は、指定した日付の曜日を数値で返してくれます。

### IF関数を用いた条件分岐
WEEKDAY関数を使って判定した曜日に基づいて、土曜日と日曜日を除外するための条件分岐を行います。
IF関数を使用し、土曜日と日曜日の場合は直前の平日を、それ以外の場合はそのままの最終日を返すようにします。

## おわりに
本記事では、指定した月の最終日を取得し、土日を除外する関数の作成方法を紹介しました。

この関数を使うことで、例えば、プロジェクトの期限日を計算する際に土日を除外したい場合や、休暇の申請期限を設定する際に土日を考慮したい場合などに便利です。

日々の業務の参考になれば幸いです。
オブジェクト指向の考え方（その２：抽象化と階層化）

# 抽象化について
抽象化と聞くと、ぼんやりとした状態のものをイメージしやすいが、オブジェクト指向においての抽象化とは、モノ（オブジェクト）から詳細な部分を抽出あるいは排除し、特長だけを導出しシンプルにした状態のことを指す。

「抽象度の視点と粒度を変えながら物事を事柄に置き換えて分類して考える」ことであり、オブジェクト指向の中核をなす最も重要な概念。




# 階層化
階層化によって分類する方保には、
- 「〜である」という、汎化特化（継承）関係である。is-a(king-of)階層
- 「部品からなる」という、集約関係である、part-of階層

の２種類が存在する。

[ is-a ]
![オブジェクト指向-2 2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580819/e4b768f1-9266-b996-c032-dc87ce8ebc23.jpeg)

[ part-of ]
![オブジェクト指向-3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580819/eecc9729-ed58-9b0e-1fa1-c03d4c9a17d3.jpeg)



# オブジェクト分類の注意点
何も考えずオブジェクト分類（＝分析）を行った場合、人によって異なった結果が出る場合がある。

![オブジェクト指向-4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580819/2b3ce195-c3d5-4c59-7f21-df58529da802.jpeg)

![オブジェクト指向-5.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580819/3ae2aa8f-3785-af68-36c1-7735b9f78ebd.jpeg)

どちらも理想的な形にはなっているが、用途によって理想できてはない場合がある。
期待された効果を得るために、扱われ方（＝要求）を理解して、抽象化を行う必要がある。


***
前の回はこちら → [オブジェクト指向の考え方（その１：オブジェクト指向とは）](https://qiita.com/TkyI/items/4b83635ea2ecaacb5b40)

続きはこちら → [オブジェクト指向の考え方（その３：カプセル化）](https://qiita.com/TkyI/items/732078cd3ceb5ad0e306)
AWSアーキテクチャを考えるときに大事なこと(AWS Summit 2023 アーキテクチャ道場 2023！レポート)

# はじめに
この記事はAWS Summit 2023の4/21(金)に発表された[AWS-28]アーキテクチャ道場 2023！のレポートです。
私はAWS Summitのコンテンツの中でアーキテクチャ道場が一番好きなのですが、今年のSummitでもやはり学びが多かったです！
熱が冷めないうちに今後の自分に向けた備忘録として残しておこうと思います。

今回のアーキテクチャ道場 2023！の中では2つのお題(マルチプレイ可能なオンラインゲーム、モバイル通信事業者のユーザー管理サービス)があり、それぞれについてAWSのソリューションアーキテクトの方が設計し、レビューワーの方がフィードバックする、という形式を取っています。
そして、セッションの最後にレビューワーのAWSチーフテクノロジスト内海さんの総評がAWSアーキテクチャを考える上で非常に重要なこととして私に刺さりまくったので、今回はそこにフォーカスして共有します。

いきなりですが、まずは結論です。

# 結論
## 1. 良い設計の流れ
### まずはシンプルな設計をしてから、問題を考えてそれを解決できるアーキテクチャにブラッシュアップしていく

## 2. 二段階で設計してみる(抽象度の高い設計->具体的な設計)
### まずはAWSサービスなど特定の実装方法に依存しない抽象度で骨組みとなるアーキテクチャを作る
### 次にAWSサービスを利用した場合の具体的な実装方法を反映したアーキテクチャを作る

# 詳細
以下、２つの詳細です。

## 1. 良い設計の流れ
* まずはシンプルな設計をしてから、問題を考えてそれを解決できるアーキテクチャにブラッシュアップしていく
### 利点
* 必要最低限のところからスタートして、想定課題とその解決策を反映するとオーバーエンジニアリングが起きにくい
* アーキテクチャ決定の背景や流れが説明しやすい

### 例
* まずは左側のようにシンプルなアーキテクチャからスタートする。
* そこから可用性・応答性能などの想定課題を出していって、それらの解決策を反映していき、左側のようなアーキテクチャにブラッシュアップしていく
![例1_ .png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536303/f9bdb421-2efc-f99a-ead8-ea42dab90241.png)

## 2. 二段階で設計してみる(抽象度の高い設計->具体的な設計)
* まずはAWSサービスなど特定の実装方法に依存しない抽象度で骨組みとなるアーキテクチャを作る
* 次にAWSサービスを利用した場合の具体的な実装方法を反映したアーキテクチャを作る
### 利点
* 実装に依存しない抽象的なアーキテクチャがあることで、設計意図が明確になり、変化が速いAWSサービスのアップデートに追従しやすい

### 例
まずは左側のアーキテクチャのように特定のサービスに依存しないような設計を考える。
![例2_ ２段階で設計.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536303/d7dd8bf5-14dc-fcfc-9cd7-113095fa4d6f.png)

# 思ったこと・感じたこと
* 個人的には2つ目の内容、2段階で設計してみることは特に重要だと感じました。変化が速いAWSサービスのアップデートの中でも自分たちが取り入れるべきものが明確になるためです。
* また、どんなところにアンテナを張ってアップデートを追っていくかの指針にもなるため、自分たちのチームで実装したサービスに対して後追いでも抽象度の高いアーキテクチャを作ることもとても意味があると感じました。
* 自分の心にすごく余裕があったり、冷静に考えられるときは無意識にやっていたこともありますが、必要に迫られて効率的にやろうとすると大事なことをすぐ忘れて目の前のタスクに取り組んでしまいがちです。アーキテクチャを考えるときには何度もこの記事を見返して一度立ち止まって落ち着いて取り組もうと思います。
* やはりアーキテクチャ道場!は最高に楽しい＆学びがある！
lsコマンド結果にダブルクォーテーションをつけてコピペしたい



## ユースケース

<aside>
💡 lsで表示される結果にそれぞれダブルクォーテーション（”ファイル名”のように）をつけて表示させる

</aside>

地味にこんなときがあると思う。

1. 特定フォルダ内のファイルをlsコマンドでリスト化
2. 表示されたそのファイル郡を、Python等のスクリプトにコピペする
3. ファイル群をリスト化して、色々処理させる

ただ、リスト化させるだけではクォーテーションはつかないので、スクリプトにそのまま貼り付けると一々`””`（ダブルクォーテーション）を打たなければいけない➔**面倒**

## やり方

今回のケースの解決策はこちら

```bash
ls | sed 's/.*/"&"/’ | xclip -sel clip
```

### lsコマンド

言わずもがな、みんな大好きlsコマンド

### sedコマンド

`man sed`で説明を見たら以下のように書いてあった。

>sed  はストリームエディタである。ストリームエディタは、入力ストリーム (ファイルまたはパイプラインからの入力) に対して基本的なテキスト変換を行うために用いられる。sed は 編集スクリプトを使える (ed のような) エディタと いろいろな面で似ているが、sed は入力に対して 1 パスだけで動作するので、より効率的である。また sed はパイプラインのテキストに対してフィルタ動作を行うことができ、この点は他のタイプのエディタとはっきり違う。

</aside>

要は入力されたテキストデータに対して、文字列の置換や抽出が行えるとのこと。

`'s/.*/"&"/'`はそれぞれ、

- **`s`**コマンドは、置換（substitute）を意味し、正規表現を使ってテキストを置換する。
具体的に**`s/パターン/置換文字列/`**という形式で使うみたい。
    
    ```bash
    # echoで"Hello, world!"という文字列を出力し、sedで、s/world/John/のパターンにマッチする"world"を"John"に置換
    $ echo "Hello, world!" | sed 's/world/John/'
    Hello, John!
    ```
    
- `.`は、任意の1文字を表す。
- `*`は、直前の文字の0回以上の繰り返しを表す。つまり、`.*`で全ての文字列を対象にできる。
- `&`は、マッチした文字列全体を指す。ダブルクォーテーションで囲まれた`"&"`は、マッチした文字列全体をダブルクォーテーションで囲むためのもの。

これでlsコマンドで表示されるファイル名のリストを取得➔それぞれのファイル名をダブルクォーテーションで囲んだ文字列に置換して出力ができる

### xclipコマンド

CLI上のコマンドをクリップボードにコピーしたり、クリップボードの内容を取得したりすることができる。

`xclip -selection clipboard`でも同じ意味だが、長いので`xclip -sel clip`

実行したら、クリップボードにコピーされているはず。これでこのままスクリプトに貼り付けたらOK！！
AWS FargateでCDK Typescriptを使ってCodeDeplyを作成する。

# AWS FargateでCDK Typescriptを使ってCodeDeplyを作成する。

CDKでFargateのCodeDeployを作成したので、記事を書きます。
本番環境にデプロイするときは、Codedeploy使ったほうがいいですよね。
またCDKで記述しておけば、後々らくです。

### 手作業に対するCodeDeployのメリット

* 公開する前に、同じ環境で、動作確認ができる。
* 一部の人に最初に公開し、問題ないか確認できる。
* すぐに切り戻しができる。
* ある程度、好きなタイミングで公開できる。

### 前置き

* すでにCDKでFargateを作成していること。今回の記事はCodeDeploy部分の解説です。
* CodeDeployの動きなどは自分で調べてください。
* サービスの命名はきちんと適切なものに変更してください。

## サービスの修正

```Typescript

    const loadBalancedFargateService = new ecsPatterns.ApplicationLoadBalancedFargateService(this,srvName, {

......
      deploymentController: {
        type: ecs.DeploymentControllerType.CODE_DEPLOY
      }
    });
```
クラスタのサービスにdeploymentControllerのCODE_DEPLOYを指定します。
この修正は、サービスが再作成になるので、注意が必要です。


## ターゲットグループの追加

```Typescript
    const targetgroup2 = new elbv2.ApplicationTargetGroup(this, 'srv-target-green', {
      targetType: elbv2.TargetType.IP,
      targets: [fargateService],
      port: 80,
      targetGroupName: 'tgt-green',
      healthCheck: { path: '/health' },
      vpc: vpc,
    })
```

今まであるターゲットグループと同じように作成します。


## ロードバランサのlistener作成

```Typescript
    const listener2 = loadBalancedFargateService.loadBalancer.addListener('http-listener', {
      protocol: ApplicationProtocol.HTTP,
      port: 80,
      defaultTargetGroups:[targetgroup2],
    });
```
ターゲットグループと同じようにlistenerももう一つ作成します。以前のポートとは違うポートを指定します。
今回はHTTPSに対してHTTPを作成しました。テスト接続用のlistenerになります。
前で作成したtargetgroupを指定します。

## ApplicationとDeploymentGroupを作成

```Typescript
    // create code deploy ecsApplication
    const ecsApplication = new codedeploy.EcsApplication(this, 'ecs-application', {
      applicationName: 'application',
    });
    // create code deploy deploymentGroup
    const deploymentGroup = new codedeploy.EcsDeploymentGroup(this, 'deployment-group', {
      application: ecsApplication,
      deploymentGroupName: 'deplgp',
      deploymentConfig: codedeploy.EcsDeploymentConfig.ALL_AT_ONCE,
      service: fargateService,
      blueGreenDeploymentConfig: {
        blueTargetGroup: loadBalancedFargateService.targetGroup,
        greenTargetGroup: targetgroup2,
        listener: loadBalancedFargateService.listener,
        testListener: listener2,
      },
    });
```

EcsApplicationの作成は名前を適当に指定します。
EcsDeploymentGroupの作成は、前で作成した諸々を指定します。


## 最後に

* あとはタスクを更新し、更新したものからデプロイを作成すればデプロイできるはずです。
* ポイントポイントで書いたので、継接ぎですが、動かなかったら、すいません。
* デプロイ自体の設定はデフォルトを使用しているので、時間等は自分で指定してください。
Pythonで二分探索を実装してみた

# 概要
今日はPythonで二分探索を実装＆実行してみました。以下のページを参考にしました。
https://codezine.jp/article/detail/9900?p=2

# ソースコード
ソースコードは以下の通りです。上記のページのコードはPython2用だったので、Python3用にprint文の書き方を修正しました。その他は同じです。
```binary_search.py
# coding: UTF-8

def binary_search(list, item):
    low = 0                        # lowとhighを使ってリストの検索部分を追跡
    high = len(list) - 1
    while low <= high:             # 1つの要素に絞り込まれるまでの間は...
        mid = (low + high) // 2
        guess = list[mid]          # 真ん中の要素を調べる
        if guess == item:          # アイテムを検出
            return mid
        if guess > item:           # 推測した数字が大きすぎた
            high = mid - 1
        else:                      # 推測した数字が小さすぎた
            low = mid + 1
    return None                    # アイテムが存在しない

my_list = [1, 3, 5, 7, 9]          # テストしてみる

print(binary_search(my_list, 3))   # 結果は1：リストは0始まりなので、
                                   # 2つ目のスロットのインデックスは1
print(binary_search(my_list, -1))  # 結果はNone:Pyhonにおいて「nil」を意味し、
                                   # アイテムが検出されなかったことを示す
```

# 実行
以下の通りPython3で実行しました。無事動いているようです。
```
$ python3 binary_search.py 
1
None
```

何かの役に立てばと。
PowerCMSX + nginx 環境における Ubuntu 20.04 → 22.04 更新と PHP 8.0 → 8.2 更新

# はじめに
## 対象読者
* [PowerCMS X](https://powercmsx.jp/) ユーザーで、
* PowerCMS X の ver. が 3.1 / 2.71 以上で、
* Ubuntu 20.04 で、
* PHP 8.0.x で、
* nginx 環境の人

### 補足
* PowerCMS X ユーザーでなかったとしても PHP 8.0.x → PHP 8.2.x 更新手順については参考になるかとは思います
* また PHP 8.0.x でなく 8.1.x からの更新でも同じはずです
* なお PowerCMS X は ver. 3.1 / 2.71 から PHP 8.2 に対応しているので、本体の ver. には要注意です

https://powercmsx.jp/release_note/ver3_10.html

## この記事でやること
* Ubuntu 20.04 を 22.04 へ更新しつつ、
* PHP 8.2.x を nginx で動作させて PowerCMS X における実行まで見届ける


# 手順
## Ubuntu 20.04 → 22.04
### apt update && apt upgrade
* まず以下コマンドを実行して手元の状態を最新にしておく

```sh
apt update
apt upgrade -y
```

### 再起動
* 最新にしたら、一度再起動の実行

```sh
shutdown -r now
```

### do-release-upgrade
* おそらく Ubuntu 起動時に `do-release-upgrade` をおこなえと表示されているので、その通りにコマンドを実行

```sh
do-release-upgrade
```

* あとは、対話形式で、既存の設定を残すか上書きするか、といったことを問われ続けるので、それに答えて対応を進める
* それなりに時間がかかるので、一時間くらい継続して対応できる時におこなうのをオススメ

### 再起動
* 最後まで終了したら、また再起動の実行

```sh
shutdown -r now
```

## PHP 8.0 → 8.2
### 前置き

* 以前、以下コマンドを実行して PHP 8.0 をインストールしている場合、既に 8.2 が追加されているはず

```sh
apt install software-properties-common
add-apt-repository ppa:ondrej/php
```

### 確認
* 以下コマンドで確認

```sh
php -v
```

### インストール
* もし `8.2.x` になっていなかったら、次の手順に従ってインストール
* なっていたら不要

```sh
apt install software-properties-common
add-apt-repository ppa:ondrej/php
apt install php8.2
apt install php8.2-gd php8.2-fpm php8.2-mbstring php8.2-mysql php8.2-xml php8.2-zip
```

## path 確認
* 以下の path にファイルが存在していることを確認

```sh
/run/php/php8.2-fpm.sock
```

## owner, group の設定
* もし nginx ユーザーを `www-data` 以外のもの ( たとえば `nginx` など ) にしている場合は、上記 `php8.2-fmp.sock` の `owner`, `group` をそれに準じて `chown` してください。例えば以下のように

```sh
chown nginx:nginx /run/php/php8.2-fpm.sock
```

* また、以下の設定を書き換え

```ini:/etc/php/8.2/fpm/pool.d/www.conf
; 前略

user = nginx
group = nginx

; 中略

listen.owner = nginx
listen.group = nginx

; 後略
```

## max_input_vars の設定
* PowerCMS X 公式によると `'max_input_vars'の推奨値は2000以上` とのことなので、それに合わせて書き換えます。サーバスペック等に応じて必要な値を。

```ini:/etc/php/8.2/fpm/php.ini
; 前略

max_input_vars = 2000

; 後略
```

## PHP-FPM 再起動
```
systemctl restart php8.2-fpm.service
```

## apache2 無効化
```
systemctl disable --now apache2
```

## nginx
### 設定書き換え
* 以下のように 8.2 へ書き換える

```nginx
    # 前略

    fastcgi_pass unix:/run/php/php8.2-fpm.sock;

    # 後略
```

### 再読込
* さいごに nginx の再読込をおこなうと、ダッシュボードが表示されるようになるはず

```sh
nginx -s reload
```

## 確認
* 以下の php を実行したときにインストール ver. が確認できる
  * いくつかのモジュール等は必須でないのでアラートが表示されていますが、必須のものだけ動いていればヨシ

```sh
https://example.com/pt-check.php
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/e2f312b4-1efa-0e10-5027-5f9a1d0c98a7.png)


# おわりに
## 感想
* 以下関連記事にある、以前の PHP 7 → 8 移行の内容をほぼ使い回していますが、すんなりいきました。良かったです

## 関連記事
* [PowerCMSX稼働サーバをUbuntu18.04→20.04へ更新する際の注意とPHP7.4インストール手順](https://qiita.com/Hi_Noguchi/items/861fda70afb593562ab4)
* [PowerCMSX+Ubuntu20.04+nginx環境におけるPHP7→8移行](https://qiita.com/Hi_Noguchi/items/7fa4e90a38b1a112d4d7)
ServiceNow の Reference型のカタログ変数で、任意のカラムの値で検索できるようにする

# 概要
下記画像のように、Reference型のカタログ変数で、参照先テーブルのDisplay値以外のカラムの値を使って検索を行う方法について記述します。
![rc1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707437/e3028111-952b-3293-7845-46874958067d.png)

# 手順
今回はCompany [core_company] を参照するReference型変数を例にとり、カスタムで作成したカラム「会社コード」の値を使って検索が出来るようにします。

①カタログ変数の「Variable attributes」フィールドで、下記のように値を設定します。
![rc2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707437/817c2a8b-d814-fb1b-12b3-020592a3aa02.png)

各属性の目的：
- ref_auto_completer=AJAXTableCompleter :
属性「ref_ac_columns」で指定したカラムをプルダウンに表示するのに必要。
- ref_ac_columns=u_company_code :
プルダウンに表示したいカラムを物理名で指定する。「;」（セミコロン）で区切って複数指定も可能。 例：ref_ac_columns=u_company_code;phone;city
- ref_ac_columns_search=true :
属性「ref_ac_columns」で指定したカラムの値を使って検索をするのに必要。
　

②これにより、会社コードでの検索が可能になります。
![rc3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707437/a247882c-f34d-9e5e-afb8-12e606568d06.png)
![rc4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707437/a1b366a2-27aa-2965-fcc9-b8c3405eeebc.png)

Display値での検索も今まで通り可能です。
![rc5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707437/801d083c-ae7d-0574-8368-2bd212736b61.png)

# 参考リンク
[サービスカタログ変数の属性](https://docs.servicenow.com/en-US/bundle/tokyo-servicenow-platform/page/product/service-catalog-management/reference/variable-attributes.html "ServiceNow 製品ドキュメント")

弊社ブログへも[同様の記事を投稿](https://alpcom.co.jp/blog/20230919/?utm_source=Qiita&utm_medium=post&utm_campaign=ysi&utm_id=20230919)しております。
TERNスタックをざっくりと説明してみる

## はじめに
TERNスタックは、MERNスタックをベースに、MongoDBをTigrisに置き換えた最新のWeb開発スタックです。この記事では、TERNスタックの概要とそのメリット、実際の構成要素、そして始め方を簡単に説明します。

## TERNスタックとは

TERNスタックは、Tigris、Express.js、React、およびNode.jsの組み合わせで構成されるWeb開発スタックです。MERNスタック（MongoDB, Express.js, React, Node.js）からTigrisに移行することで、サーバーレスNoSQLデータベースと検索プラットフォームを利用できるようになります。

## 何が良いのか

Tigrisを採用することで、以下のメリットが得られます。

- コードファーストアプローチ
- データベースブランチング
- 手動クラスタリングやシャード管理が不要
- ACIDトランザクションのサポート
- 全文検索機能の統一
- より低いランニングコスト

## 実際の中身

![TERNスタック.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3338130/c1ae6ddc-f771-d8de-6b09-5ebf889899ca.png)
)

TERNスタックの構成要素は以下の通りです。

- ブラウザ: JavaScriptまたはTypeScriptで記述されたReact
- サーバー: JavaScriptまたはTypeScriptで記述されたExpress.js
- データベース: Tigris TypeScript SDKを使用したTigrisデータベース

## TERNスタックを構築してみたい、という方へ

TERNスタックを試すためには、以下が必要です。

1. Node.js LTS以上がインストールされていること
2. Tigris Cloudアカウントまたは自己ホストされたTigrisインスタンス
3. サンプルリポジトリをクローンし、MERNブランチに切り替える

その後、MongoDB接続文字列を更新し、Tigris SDKを使用するように変更します。これで、TERNスタックへの移行が完了します。

## まとめ

TERNスタックは、MERNスタックからMongoDBをTigrisに置き換えた最新のWeb開発スタックです。サーバーレスNoSQLデータベースと検索プラットフォームを利用できることで、開発効率と運用コストの削減が期待できます。

## 参考にした資料
- 3分で分かる。MERNスタックを簡単に説明してみる: https://qiita.com/Kage_/items/ffb0c213bfc36eae3592
- TERN Stack example repository: https://github.com/tigrisdata-community/tern-stack-example.git
- MERN Stack guide: https://www.tigrisdata.com/blog/tern-stack/
[Django] 管理画面にバリデーションを実装する

## はじめに（前提）
- [Django公式チュートリアル](https://docs.djangoproject.com/ja/4.0/intro/tutorial01/)のソースを元にしています。
- 管理画面側のモデルにバリデーションを実装する方法をまとめています。

## モデル
- Question
- Choice(←今回バリデーションを実装するモデル)

## やりたいこと

- `VOTES`が負数の場合に、バリデーションエラーを実装したい。
    - 現状は負数の場合でも保存されてしてしまう。

![スクリーンショット 2023-04-21 17.41.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728622/0d90deae-4f0b-7ce1-9ebd-c08f40413f5e.png)


## 実装

- 実装したいモデルの`Class`に`clean`メソッドを追加する

```python
# models.py
class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

    def __str__(self) -> str:
        return self.choice_text

    # この行以下を追加
    def clean(self):
        if (self.votes < 0):
            raise ValidationError({"votes": "投票数は0以上で入力してください。"})
```

できた！
![スクリーンショット 2023-04-26 15.20.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728622/2d51ef11-7f06-d536-cbd1-a4d09948631b.png)


### 補足
以下のように記載してしまうと、参考画像のように、バリデーションエラーメッセージが`CHOICE TEXT`の下に表示されてしまう。

```python
raise ValidationError("投票数は0以上で入力してください。")
```

エラーメッセージの表示位置を固定するために`{"field_name": "error_message"}`としている。

**[参考画像]**
![スクリーンショット 2023-04-21 17.59.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728622/f68981ce-d5ff-90eb-e5e5-eca4618a6f3d.png)


## 参考
https://stackoverflow.com/questions/24802244/custom-validation-in-django-admin


## 終わりに
- まだDjangoについて勉強し始めたばかりなので、「こっちの書き方の方が良いよ」などあればコメントください。

以上
【Python】Webスクレイピングで環境によって期待結果が異なる件への対応（Edge）

# 事象
あるサービスから、WebスクレイピングしてデータをExcelに出力するプログラムを作ってる時、実行環境や実行タイミングによって、Excelに出力された値が異なる事象が発生。
データを取得する画面は、同じで、一度発生するとその特定のレコードが毎回画面上の値と異なって出力される。
当記事は、この問題に対する調査記録。

# 事象整理
まずは事実を整理。
- 実行する環境（PC）によって、Excelに出力された値（取得された値）が異なる事象が発生する
- 事象が発生するデータと同じ画面から取得したデータは、そのような事象は発生しない
⇒画面項目差異による影響ではない
- デバッグ実行しながらであれば、事象は発生しない（通しで実行した時にのみ発生する）
⇒プログラムが悪さしているわけではなさそう
- 事象が発生するデータのみを対象にすると事象は発生しない
⇒対象データが悪いわけではない
- ヘッドレスモードで起動したときは正常に取得される
（ようにみえる。タイミングによって発生する可能性があるため） 
⇒プログラムが悪さしているわけではなさそう

# プログラムの内容
プログラムが原因ではなさそうなので、Seleniumに関わる箇所のみにフォーカスする。

- SeleniumWebDriverの起動オプションは以下。
    ```python
            options = EdgeOptions()
            options.use_chromium = True
            options.add_argument('--no-sandbox')
            options.add_argument('--disable-gpu')
            options.add_experimental_option('excludeSwitches', ['enable-logging'])
            options.add_argument("--inprivate")
            options.add_argument("--disable-cache")
    ```
- 不完全なページのロードを回避するため、画面遷移後に3秒待機。
また、implicity_waitを設定し、上記で3秒待機後に画面最下部の要素が発見されてから処理を実行
- 画面遷移はSeleniumWebdriver、データの取得はBeautifulSoupを利用

# 試したこと
事象発生の要因に対して、それぞれ調査。

1. 【仮説１】ページがロードしきってない状態で処理が走ってしまった？
    【アプローチ】画面遷移後の待機時間を6秒に延長してみる
    【結果】事象解消せず。次の仮設を検証してみる。

1. 【仮説２】処理中にたまったゴミが悪さをしている？
    【アプローチ】webdriverの利用ディレクトリを指定して、どんな感じかを観察してみる。
　　　　　　　EdgeOptionsに以下を設定。
    ```python
    options.add_argument("user-data-dir=D:\\SeleniumTest\\")
    ```
    【結果】特に怪しい箇所なし。次の仮設を検証してみる。
　　→結果、変わらず。また、処理終了後に上記ディレクトリのデータも消えなかった。

1. 【仮説３】Edgeの拡張機能が悪さをしてたりする？
    【アプローチ】拡張機能が悪さしている可能性もあるので、無効にして起動してみる
　　　　　　　EdgeOptionsに以下を設定。
    ```python
    options.add_argument("--disable-extensions")
    ```
    【結果】結果変わらず。


# 結論
色々試したけど、画面表示しながら事象を解消することはできず！

画面表示していることでリソースを消費して、画面のロードに不都合が発生しているのかも・・・
ヘッドレスモードで起動することで今のところちゃんと出力されそうなので、こちらで対応することにする。
nimで競プロをするときに、HashSetがTLEする・遅い理由(のひとつ)

## 追記

1.6.14では**修正**されている。(いつ修正されたのかは要調査)

## バージョン

nim: 1.0.6

## 要約

よくわからないけど、intの`hash`が悪いので以下を書いてintの`hash`プロシージャを上書きしておく。
参考元: https://github.com/nim-lang/Nim/issues/11764#issuecomment-611186437

```nim
proc hiXorLo(a, b: uint64): uint64 {.inline.} =
  {.emit: "__uint128_t r=a; r*=b; `result` = (r>>64)^r;".}
proc hashWangYi1*(x: int64|uint64|Hash): Hash {.inline.} =
  const P0 = 0xa0761d6478bd642f'u64
  const P1 = 0xe7037ed1a0b428db'u64
  const P5x8 = 0xeb44accab455d165'u64 xor 8'u64
  Hash(hiXorLo(hiXorLo(P0, uint64(x) xor P1), P5x8))
proc hash(x: int): Hash =
  x.hashWangYi1()
```

## 経緯

AtCoderで不可解なTLE(計算量(オーダー)的にはTLEしなさそう)が起きたので、Dropboxに上がっているテストケースを見ながら試行錯誤したところ、`HashSet`の初期化が悪さをしていそうだった

abc290 c - Max MEX: https://atcoder.jp/contests/abc290/tasks/abc290_c 
TLEした提出: https://atcoder.jp/contests/abc290/submissions/40700254

## 説明(できない)

よくわかっていない。故、詳しい事情がわかる人は教えて欲しい。
それらしいissueは見つけたので、がっつり解明してやるという気概がある人は是非。
issue: https://github.com/nim-lang/Nim/issues/11764

## ちなみに

理由がわからないけど解決策がわかったという記事は書いていいのだろうか。

## 参考

この記事と同じ?内容のissue: https://github.com/nim-lang/Nim/issues/11764#issuecomment-611186437
Scaled Professional Scrum (SPS) を取得した

## きっかけ
- 前回の記事でProfessional Scrum Master I (PSM I) を取得したことを記載した。 [^1]
  - ただしこれは一番初めに取る資格であり、保有者数が圧倒的に多く、2023年4月末時点で約57万人もいる。 [^2]
  - 次点でのProfessional Scrum Product Owner I (PSPO I) でも約17万人。 [^2]
  - これでは差別化出来ない、と思った。
- 差別化を図るには以下のいずれかの方策を取る必要がある。
  - より深掘りする。（Professional Scrum Master II (PSM II) を取得する。）
  - 役割を追加する。（Professional Scrum Product Owner I (PSPO I) を取得する。）
  - 領域を拡大する。（Scaled Professional Scrum (SPS) を取得する。）
- そして私は以下の理由から三番目の方策を選択した。
  - スクラムマスターやアジャイル開発の話をすると、（質問しやすいのと、質問しないよりマシと言う判断からだと思いますが）決まって大規模開発への適用事例の質問が出るので、「当然、対応しております」と打ち返してみたかった。
  - 取得者数も全世界で6,000人以下なので差別化するにはちょうどよかった。 [^2]
  - LeSSとも非常に類似しており、親和性がよく、応用がききやすい。
  - 採用率の比較的高い（と世間では言われている）SAFeは（私にとっては）重厚すぎた。[^3]

## 前提条件勉強方法について
- Professional Scrum Master I (PSM I) に合格している事。
  - いきなりスケーリングは出来ない。
  - スケールすると言っても結局はスクラム。
- PSM I の頃より英語に抵抗がないこと。
  - さすがにこのレベルになってくると日本語圏での情報が少ない為、英語圏のサイトから情報を取得してくる必要がある。
    - 英語圏でもこのレベルになると取得している絶対数が少ないので検索キーワードを工夫するなどしないと情報が出てこない。（やはり先にPSM Iが引っかかってしまう）
## 勉強方法について
- 基本はProfessional Scrum Master I (PSM I) の時と変わらない。[^1]
- まずは[Nexusガイド](https://www.scrum.org/resources/nexus-guide "The Nexus Guide")を読む。
- [公式のサンプル問題](https://www.scrum.org/open-assessments/nexus-open "Nexus Open") があるのでそれを解く。
  - が、これは罠。実際の試験ではこれと同じレベルの問題は数問（5問程度）しかでない。
  - 本番の試験ではもっと難しい問題が出る。
- それ以外にも海外の個人サイトなどでサンプル問題の掲載があるのでそれも解く。
  - 代表的な２つのサイトを以下に掲載する。

https://mlapshin.com/index.php/scrum-quizzes/scaled-scrum-quiz/

https://www.techagilist.com/practice-exams/sps-practice-test/sps-practice-exam-practice-mode-questions/

- おそらくそれでも足りないので、あとはUdemyやAmazonで問題集が出ているのでそれを解く。


## 結果
- 正答率87.5%（40問中35問正解）で、無事に合格した
  - あと2問間違えていたら不合格だった。
  - 正直、解いている最中は「落ちたな」と思っていた。
    - 運よく山勘が当たっただけ。
    - サンプル問題と実際の問題の難易度に乖離があり過ぎるのが最大の問題。
  - 受験料が$250 USD per attempt で Passing score: 85% は割と鬼畜だと思う。
    - どう対策しても本番の難易度は再現できないので、究極は（受験料は高いけど）一度は落ちる覚悟で問題の難易度を確かめて、それから自身にあった対策方法を検討するのがよいのかもしれない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2953203/11796f64-6cb8-43d8-8847-8f5eecfacfa5.png)

[^1]: Professional Scrum Master I (PSM I) を取得した : https://qiita.com/tatsu_sekine/items/65c4ba1f8f724b03f172

[^2]: Professional Scrum Certified Count : https://www.scrum.org/professional-scrum-certifications/count

[^3]: [State of Agile](https://stateofagile.com/ "State of Agile")  のThe 16th Annual State of Agile Reportによればスケーリングの際の手法の採用率はLeSS:6%、Nexus:3%に対して、SAFeが53%で、とぶっちぎり。とは言え、Full, Portfolio, Large Solution, Essentialとで分けたらどの程度の割合になるのかは気になった。
pandas.DataFrame.assignで列名として文字列を指定する方法（コード例）

## 背景

`pandas.DataFrame.assign`において、列名として文字列を指定したい場面がありました。以下のドキュメントに方法は書いてあるのですが、キーワードとして引数として入力する例のみがコード例として紹介されています。

https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.assign.html

本記事ではドキュメントと可変長引数（`**kwargs`）の扱い方を参考に`pandas.DataFrame.assign`において、列名として文字列を指定する方法をコードとして紹介します。

## コード例

まずは対象となるデータフレームを用意します。

```python:データフレームの準備
import pandas as pd

df = pd.DataFrame({"絵文字": ["🍎", "🦍", "📯"]})
df
```

|    | 絵文字   |
|---:|:---------|
|  0 | 🍎       |
|  1 | 🦍       |
|  2 | 📯       |

以下、`pandas.DataFrame.assign`で列名として文字列を指定する方法（コード例）です。

```python:pandas.DataFrameのassignで列名として文字列を指定する方法（コード例）
df.assign(**{"名前": ["リンゴ", "ゴリラ", "ラッパ"], "普通名詞": True})
```

|    | 絵文字   | 名前   | 普通名詞   |
|---:|:---------|:-------|:-----------|
|  0 | 🍎       | リンゴ | True       |
|  1 | 🦍       | ゴリラ | True       |
|  2 | 📯       | ラッパ | True       |

## 補足

紹介した方法を活用すると、例えば以下のような書き換えが可能になります。

```diff_python:書き換えの例
- df = pd.DataFrame({"絵文字": ["🍎", "🦍", "📯"]})
- df["名前"] = ["リンゴ", "ゴリラ", "ラッパ"]
- df["普通名詞"] = True
+ df = pd.DataFrame({
+     "絵文字": ["🍎", "🦍", "📯"]
+ }).assign(**{
+     "名前": ["リンゴ", "ゴリラ", "ラッパ"],
+     "普通名詞": True
+ })
```

メソッドの連結により、論理ステップ数が一つで最終的に実現したいデータフレームを生成できます。メソッドの連結は、以下のpandasのアンチパターンや良い書き方を解説した記事においても勧められています。

https://www.aidancooper.co.uk/pandas-anti-patterns/

> Instead of sequentially mutating a pandas DataFrame, a better approach is to transform it by chaining pandas methods.
> 引用：[4 Pandas Anti-Patterns to Avoid and How to Fix Them](https://www.aidancooper.co.uk/pandas-anti-patterns/)

さらに、列名を文字列として扱う場合、変数化も可能になります。

```diff_python:列名（文字列）の変数化の例
+ column_icon = "絵文字"
+ column_name = "名前"
+ column_is_common_noun = "普通名詞"

- df = pd.DataFrame({
-     column_icon: ["🍎", "🦍", "📯"]
- }).assign(**{
-     column_name: ["リンゴ", "ゴリラ", "ラッパ"],
-     column_is_common_noun: True
- })
+ df = pd.DataFrame({
+     "絵文字": ["🍎", "🦍", "📯"]
+ }).assign(**{
+     "名前": ["リンゴ", "ゴリラ", "ラッパ"],
+     "普通名詞": True
+ })
```

コード中の他の箇所で列名を扱う際に便利になります。
rails c でデータベースにSQLを送る方法

# はじめに
Railsでは、ActiveRecodeがデータベースにSQLを送ってくれるので、自力でSQLを書く機会は少ない。
その中でもバックエンドエンジニアとしてSQLへの理解が重要なので、以下の方法で確認することをオススメしたい。

# 方法
- `rails c`でコンソール起動
- 以下のコマンドでデータベースにSQLを送信
```:コンソール
ActiveRecord::Base.connection.select_all("SQL文を書く'").to_a
```

以下は実行例（tasksテーブルのtitleカラムに"テスト"の文字列を含んだレコードを全て取得）

```:コンソール
ActiveRecord::Base.connection.select_all("SELECT * FROM tasks WHERE title LIKE 'テスト'").to_a
```
実行結果
![スクリーンショット 2023-04-21 17.44.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2674841/d11d8ab9-ddd0-cdf6-c30b-b7f99c947b6f.png)

## 追記
`select_all`メソッドよりも、`execute`メソッドの方が汎用的であるとのコメントをいただいた。
そのため、以下の通り`execute`メソッドを利用して実行した。（⚠️検索するRailsアプリが異なっているので、モデル名や応答結果が異なる）

```:コンソール
ActiveRecord::Base.connection.execute("SELECT * FROM posts WHERE title LIKE 'タイトル'").to_a
```

実行結果
![スクリーンショット 2023-04-22 午後0.51.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2674841/aadf68a7-ae11-32da-0db7-608dc330387f.png)

### `select_all`と`execute`メソッドの違い

- `select_all`メソッド
SELECTクエリを実行し、データを取得するために使用される

- `execute`メソッド
UPDATE、INSERT、DELETEなどのSQL文を実行し、データを更新するために使用される

データベースから取得したい処理に応じて使い分けが必要だと思った。
汎用的に使うのであれば、`execute`メソッドを利用したい。
Disconnection to FortiGate Cloud log server

Due to disconnection to FortiGate Cloud log server, a lot of logs forward to FortiGate Cloud were lost.
Those logs were not forwarded again. 
However, this engineer did not understand the seriousness of this situation, and his response was dishonest and overbearing.
He hated to be too much work, did not undrestand our customer's angriness.
He needs to be trained in customer relations.
a-Shellアプリでgitコマンドを使用する方法

※本記事は2023/04/21時点に投稿した[ブログ記事](https://7rikazhexde-techlog.hatenablog.com/entry/2023/04/21/170239)を転記した内容になります。

# 追加情報

## 2024/07/30

`pkg install git`で追加できるようです。内部的に後述するbinファイルを追加するスクリプトが実行されるようです。

```bash
$ pkg install git
Downloading git
The git command cannot be included with
a-Shell. Would you like to create a
script at $HOME/Documents/bin/git that
wraps lg2 with the following contents?
#!/bin/sh
lg2 "$@"
Keep in mind that git and lg2 options
are not 100% compatible, and they also
do not use the same configuration files
or environment variables.
Create $HOME/Documents/bin/git? (y/n [n]) y
Creating $HOME/Documents/bin/git
Creation complete
Done
```

# 経緯
* a-Shellアプリでgitコマンドを使用したところデフォルトではサポートしていませんでした。
* 調べたところ、[a-Shell-commands](https://github.com/holzschu/a-Shell-commands)からgitコマンドを追加できることがわかりました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1832768/f7430d72-756b-c66c-fbb5-683a62b18488.png" width="320px">

# 使用手順
* 本記事ではcurlコマンドで取得する方法を紹介します。コマンドの追加方法については[a-Shell公式のpurpose](https://github.com/holzschu/a-Shell-commands#purpose)を確認ください。
* 以下のコマンドをa-Shellアプリを起動して実行してください。gitコマンドを実行するシェルスクリプト([git](https://github.com/holzschu/a-Shell-commands/releases/download/0.1/git))をa-ShellのbinフォルダにDLします。
* URLが無効な場合は[a-Shell-commands](https://github.com/holzschu/a-Shell-commands)にアクセスし、「Releases 1」> 「Show all 61 assets」> 「git」からURLをコピーして置き換えてください。
```sh
mkdir ~/Documents/bin #binフォルダを作成済みの場合は不要
cd ~/Documents/bin
curl -L https://github.com/holzschu/a-Shell-commands/releases/download/0.1/git -o ~/Documents/bin/git
```

# gitコマンドの実行結果
**gitコマンドファイル(シェルスクリプト）追加後**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1832768/58bdceb3-ba71-5486-91b5-df6d4e52d55a.png" width="320px"> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1832768/399c4a33-943e-65bd-7d03-15b23fe2370d.png" width="320px">

# まとめ
* a-Shellアプリでgitコマンドを追加する方法を紹介しました。
* 本記事ではgitコマンドについて紹介しましたが、他にも[a-Shell-commandsのlatest](https://github.com/holzschu/a-Shell-commands/releases/tag/0.1)を確認するとシェルスクリプトとwasmファイルが格納されています。
* [ffmpeg.wasm](https://github.com/holzschu/a-Shell-commands/releases/download/0.1/ffmpeg.wasm), [tree.wasm](https://github.com/holzschu/a-Shell-commands/releases/download/0.1/tree.wasm), [which](https://github.com/holzschu/a-Shell-commands/releases/download/0.1/which)もDLしましたが、問題なく使用できました。(※DL後はアプリの再起動が必要です。)
GitHub Actions の job で処理を実行した後に diff が生じていたら Pull request を作成する


## はじめに

GitHub Actions で処理を実行した後に diff が生じたら Pull request を作成する方法を調べて検証していたのでまとめました。

## GitHub Actions 実行後に diff が生じたら Pull request を作成する

### 利用する action

Pull request を作成するために `create-pull-request` action を利用します。

https://github.com/peter-evans/create-pull-request

https://github.com/marketplace/actions/create-pull-request

`create-pull-request` action 以外にも様々 action は存在していますが、
diff があれば commit → pull request 作成まで行ってくれるのは `create-pull-request` action がシンプルかつ簡単に実現できました。

### 作成する yml

今回は、以下条件等を実現する Yaml を作成します

- 実行条件
  - スケジュール実行: cron "0 0 \* \* 6" (土曜日 00:00 UTC)
  - 手動実行
- 権限
  - contents: `write`
  - pull-requests: `write`
- ジョブ定義
  - 実行環境: `ubuntu-latest`
  - 実行内容
    - 最新の default branch のコードを取得する
    - Node.js の install
    - `yarn install` を実行する
    - `yarn run xxxx` を実行する
    - `peter-evans/create-pull-request` を利用し Pull request を作成する
      - Pull request の title や commit メッセージ、 reviewer の定義は必要であれば行う

```yml:.github/workflows/create_pr.yml
name: Create a pull request if there is a difference

on:
  schedule:
    - cron: "0 0 * * 6"
  workflow_dispatch:

permissions:
  contents: write
  pull-requests: write

jobs:
  create_pr:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: main
      - uses: actions/setup-node@v3
        with:
          cache: "yarn"
      - run: yarn install
      - run: yarn run xxxx
      - uses: peter-evans/create-pull-request@v5
        with:
          commit-message: Update xxxx file
          delete-branch: true
          title: Update xxxx file
          reviewers: mziyut
```

### 実行結果

定義した yml が実行され diff が生じている場合は ↓ のような Pull request が作成されます。

![create_pr .png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55950/896382b7-2e74-6336-d593-f84f123d13ba.png)

## 最後に

今回は Node.js の実行結果を対象にしていますが、 Node.js 以外でも Git に diff が生じていれば利用出来ます。
`gh` コマンドなどを利用し、他 repository から差分を持ってきたり等の活用も出来そうです。

## References

- [peter-evans/create-pull-request: A GitHub action to create a pull request for changes to your repository in the actions workspace](https://github.com/peter-evans/create-pull-request)
- [Create Pull Request · Actions · GitHub Marketplace](https://github.com/marketplace/actions/create-pull-request)
- [Assigning permissions to jobs - GitHub Docs](https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs)
Db2 on CP4D 4.6.2 導入と構成 - 2.(準備)zen-databases-coreと通信するために

## Db2 on Cloud Pak for Data 4.6.2 導入と構成
シリーズ"Db2 on CP4D 4.6.2 導入と構成"は　2023年02月の経験をベースに　次のようなCloud Pak for Data (以下CP4D)4.6.2環境へ　Db2を導入デプロイする手順をご紹介します。　
- Managed OpenShift cluster (ROKS) on IBM Cloud (VPC/"Gen2")
- OpenShift Container Platform (OCP) 4.10 , OpenShift Data Foundation (ODF) 4.10
- Cloud Pak for Data (CP4D) 4.6.2 

本シリーズの目次は[こちら](https://qiita.com/mi-shimo/items/be803376088b482e2954)です。
ここでは　zen-databases-coreと通信するためにネットワークポリシーを作成します。

## 2.(準備)zen-databases-coreと通信するために
デフォルトのネットワーク・ポリシーによって拒否(deny)が使用されている場合、zen-databases-core サービスと通信できるようにするために、ネットワーク・ポリシーを作成しましょう。

### 手順
作業は踏み台マシンでおこないます。

(1) 環境変数シェルスクリプトを次のようにして実行して環境変数を定義してOpenShiftクラスターにログインしましょう。 ここで実行している$OCLOGINはcpd_vars.sh内で環境変数として定義しています。
```    
# source ./cpd_vars.sh
# $OCLOGIN
```
シリーズ"Db2 on CP4D 4.6.2 導入と構成"で使用している環境変数登録用のシェルcpd_vars.shについては[Db2 on CP4D 4.6.2 導入と構成 - 前提, 環境変数定義シェルcpd_vars.sh](https://qiita.com/mi-shimo/items/161e887624224c73e697#%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0%E5%AE%9A%E7%BE%A9%E3%82%B7%E3%82%A7%E3%83%ABcpd_varssh)をご参照ください。

(2) zen-db-core-np.yaml ファイルを作成します。
```
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: access-to-zen-database
  namespace: zen
spec:
  podSelector:
    matchLabels:
      component: "zen-database-core"
  policyTypes:
  - Ingress
  ingress:
  - {}
```
(3)  (2)で作成したzen-db-core-np.yaml を適用して ネットワーク・ポリシーを作成します。
```
# oc create -f zen-db-core-np.yaml
networkpolicy.networking.k8s.io/access-to-zen-database created
#
```

### 参考文書
- [Opening the zen-database-core port with a network policy in Db2](	https://www.ibm.com/docs/en/cloud-paks/cp-data/4.6.x?topic=install-opening-zen-database-core-port-network-policy)
- [シリーズ"Db2 on CP4D 4.6.2 導入と構成"目次](https://qiita.com/mi-shimo/items/be803376088b482e2954)
【備忘録】RailsAPIとフロントをつなぐ際のCORSの対処

# 前書き
Railsで作成したAPIとVueをつないでみようとした時のこと。

フロント側からaxiosでAPIを叩いてみたけれど、データが取れないでいた。

ブラウザの開発者ツールを開くと、なにやらCORS云々でデータが取れないのだとか。

以下に、RailsAPIとVueをつなぐ際のCORSに関する対処を備忘録として書いておく。

# 対処方法①

`Gemfile`に以下を記述し、bundle installする。

```:Gemfile
    gem 'rack-cors'
```
<br>
<br>


`config/initializers/cors.rb`から許可する相手やメソッドなどを設定することができる。

```Ruby:config/initializers/cors.rb
    Rails.application.config.middleware.insert_before 0, Rack::Cors do
      allow do
        origins "localhost:8080"
    
        resource "*",
          headers: :any,
          methods: [:get, :post, :put, :patch, :delete, :options, :head]
      end
    end
```

# 対処方法②

`config/application.rb`に以下の内容を記述する。

```Ruby:config/application.rb
config.action_dispatch.default_headers = {
      'Access-Control-Allow-Credentials' => 'true',
      'Access-Control-Allow-Origin' => 'http://localhost:8080',
      'Access-Control-Request-Method' => ['GET', 'POST', ……]  # '*'とすれば、全てのメソッドを指定
    }
```
<br>

* 関連リンク
    * [rack-cors](https://rubygems.org/gems/rack-cors)
    * [Rails による API 専用アプリケーション](https://railsguides.jp/api_app.html)



# 終わりに

今回、CORSに関する躓きに気づくまでなかなか時間がかかってしまいました。

ブラウザの開発者ツールをしっかり活用していく癖をつけられるようにしていければと思います:D
Db2 on CP4D 4.6.2 導入と構成 - 前提, 環境変数定義シェルcpd_vars.sh

## Db2 on Cloud Pak for Data 4.6.2 導入と構成
シリーズ"Db2 on CP4D 4.6.2 導入と構成"は　2023年02月の経験をベースに　次のようなCloud Pak for Data (以下CP4D)4.6.2環境へ　Db2を導入デプロイする手順をご紹介します。　
- Managed OpenShift cluster (ROKS) on IBM Cloud (VPC/"Gen2")
- OpenShift Container Platform (OCP) 4.10 , OpenShift Data Foundation (ODF) 4.10
- Cloud Pak for Data (CP4D) 4.6.2 

本シリーズの目次は[こちら](https://qiita.com/mi-shimo/items/be803376088b482e2954)です。
ここでは　本手順書の前提と環境変数定義cpd_vars.shについて記述します。

## 前提

### 参考文献	
[Db2® on Cloud Pak for Data](https://www.ibm.com/docs/en/cloud-paks/cp-data/4.6.x?topic=services-db2)
<!-- [Db2 high availability disaster recovery (HADR)](
https://www.ibm.com/docs/en/cloud-paks/cp-data/4.6.x?topic=availability-db2-high-disaster-recovery-hadr) -->

### 環境			
- IBM Cloud 東京 リージョン  jp-tok-3 	
    クラスターリソース	
    - フレーバー bx2.16x64 16vcpu,64GB メモリー
    - 8 master, worker node (うち一つがDb2専用ノード)

 - 踏み台マシン (IBM Cloud へ接続可能なLinuxマシン) 
   導入S/W
	- RHEL 8.6
	- podman
	- OpenShift command-line interface (oc)
	- Cloud Pak for Data command-line interface (cpd-cli)

### インストール済み Cloud Pak for Data 環境
Managed OpenShift cluster (ROKS) in IBM Cloud (VPC Gen2") with OCS support.
1. IBM Entitle Registry (パブリックNW  (AirGap環境ではない))
2. Express Installation mode
    - "IBM Cloud Pak foundational services"と"IBM Cloud Pak for Data platform operator"はnamespace  ibm-common-serviceにインストール
3. CP4D Namespace: zen
4. Cloud Pak for Data control plane がインストール済み
5. ODF の Storage class である ocs-storagecluster-cephfs , ocs-storagecluster-ceph-rbd が使用可能

## 環境変数定義シェルcpd_vars.sh
IBM Cloudに接続可能な踏み台マシンはCP4Dに関連する環境変数を定義して使用しています。シリーズ"Db2 on CP4D 4.6.2 導入と構成"で使用している環境変数登録用のシェルcpd_vars.shは次です。
```
# cat cpd_vars.sh
export OCP_URL=https://c115-e.jp-tok.containers.cloud.ibm.com:31714
API_token=sha256~0NE(skip)

export PROJECT_CPFS_OPS=ibm-common-services
export PROJECT_CPD_OPS=ibm-common-services
export PROJECT_CATSRC=openshift-marketplace
export PROJECT_CPD_INSTANCE=zen
export STG_CLASS_BLOCK=ocs-storagecluster-ceph-rbd
export STG_CLASS_FILE=ocs-storagecluster-cephfs
export IBM_ENTITLEMENT_KEY=eyJ(skip)
export VERSION=4.6.2
export OCLOGIN="oc login --token=${API_token} --server=${OCP_URL}"
export CPDOCLOGIN="cpd-cli manage login-to-ocp --token=${API_token} --server=${OCP_URL}"
export PATH=${HOME}/cpd-cli-linux-EE-12.0.2-39:${HOME}/.local/bin:${HOME}/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin

#
```
シリーズ"Db2 on CP4D 4.6.2 導入と構成"では 多くの`oc`コマンドを実行しています。`oc`コマンドを実行するために、OpenShiftクラスターに次のようにしてcpd_vars.sh内に定義された$OCLOGINを使用してログイン(`oc login`)しておきます。
```
# source ./cpd_vars.sh
# $OCLOGIN
```

### 参考文書 
- [Setting up installation environment variables](https://www.ibm.com/docs/en/cloud-paks/cp-data/4.6.x?topic=information-setting-up-installation-environment-variables)
- [シリーズ"Db2 on CP4D 4.6.2 導入と構成"目次](https://qiita.com/mi-shimo/items/be803376088b482e2954)
VSCodeショートカットキー

久々に開発の業務をすることになったけど、IDEがVSCodeなので、
ショートカットキーが覚えれないので、備忘録として登録していきます。（随時更新予定）

intellijのショートカットを覚えてきたのに、また最初からやり直しとは、、、ｗ

# 前提
|  | |
|:-:|:-:|
| OS  | Windows  |
|   |   |

# ショートカットキー

| 内容 | キー | 補足 |
|:-:|:-:|:-|
| ファイル名検索  |  ctrl + p |   |
| grep  |  ctrl + shift + f |   |
| 参照元にジャンプ  |  F12 |  拡張機能「ruby」をインストールして、「Intellisense」を[rubyLocate]にする必がある |
| 1つ前にジャンプ  | alt + ←  |   |
TouchDesignerでStable Diffusionを回す！

# 概要
この記事は、DotSimulateという方が作ったStable Diffusion WebUIのAPIを叩くtoxを使うまでの導入についてです。月10ドルで、toxの更新や画像生成のおもしろい情報がPatreon課金者のみのDiscordでやり取りされています。
toxの中身は公開しないので、紹介と導入の記事です。

https://www.patreon.com/user?u=80175670

TouchDesignerで生成すると
- 生成画像の連番を動画にしやすい
- 入力画像にインタラクティブ要素を入れやすい

という、入出力で遊べるメリットを感じました。

WebUIのBatch countを上げて複数バリエーションを出してこのプロンプトでいけそう→TouchDesignerで試す
みたいな使い分けをしています。

## 参考例
#### カメラ入力

https://twitter.com/komakinex/status/1640718118002778112

#### 3Dシーンと切り替え
カメラアングルを固定して画像生成し、背景を切り替えました

https://twitter.com/komakinex/status/1647480143051657216

#### オーディオビジュアルライブ
Stable Diffusionで生成したものを素材に使ったオーディオビジュアルライブをしました。
######
<iframe width="1280" height="720" src="https://www.youtube.com/embed/zrEjnQ5onWY" title="さざれ場 #002 - komakinex (My First SOLO A/V Live Performance)" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>


## 環境
OS：Windows10
CPU：i7 10700
GPU：RTX 3070（8GB）
TouchDesigner：2022.32660、2022.32120

ちなみにVRAMが8GBだとtoeファイルを2つ立ち上げた状態で画像生成できないのが難点です。


# 手順

すごい簡単に使えます。
toxを置いて、`Launch-api.bat`でAPIを呼ぶだけ。


### 1. TouchDesignerとStable Diffusion WebUIをインストール
Stable Diffusion WebUIの導入はこちら

https://qiita.com/komakinex/items/51f8826f686121133618


### 2. batファイルの作成
以下のように`Launch_api.bat`を作成して、`webui-user.bat`と同じ`stable-diffusion-webui`フォルダ内に置きます。`--api`さえ書いてあればOKです。

```bash:Launch_api.bat
@echo off

set PYTHON=
set GIT=
set VENV_DIR=
set COMMANDLINE_ARGS=--api --他のオプション
git pull

call webui.bat
```

`Launch_api.bat`を叩いてWeb UIと同じように、以下が表示されたら準備完了です。

```
Running on local URL:  http://127.0.0.1:7860

To create a public link, set `share=True` in `launch()`.
```


自分はこれもバッチファイルを作ってます。
```bash:sd_api.bat
call どこかanaconda3\Scripts\activate.batのパス
call activate 環境の名前
cd stable-diffusion-webuiのパス
call Launch_api.bat
```

スタートメニューに登録しとくと使い分けしやすくて便利。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144702/45e0a50b-b39c-7a9b-d4e3-fe3bb51a18fd.png)

バッチファイルをスタートメニューにピン留めする方法

https://jm1xtk.com/cnt/120_pindome/index.php



### 注意
toxからはモデルの切り替えができません。
`Launch-api.bat`で立ち上げた後、[http://127.0.0.1:7860/](http://127.0.0.1:7860/)にアクセスしてWebUIから変更できます。

# おまけ：別PCやスマホからAPIを叩いて画像生成する

これの通りにやったらよろしい。

https://blogcake.net/sd-webui-smartphone/

`--api`のところに`--listen`を追加するだけ。

同じネットワークにつながった別PCで`http://(サーバー側PCのIPアドレス):7860`にアクセスするとWebUIが立ち上がるはずです。
`https`だと繋がらないので要注意。
GCCでビルドするときにundefined referenceが出て困った

# Undefined reference が出た
出たな…とおもって、コード見直してみたり
作られたライブラリファイルみたり、
makefileの指示書き換えてみたけど解決しない

# cppとcの混在のせいだった
cppからcの関数を参照しているとき、関数の宣言に
```
#ifdef __cplusplus
extern "C" {
#endif

//ここに関数の宣言

#ifdef __cplusplus
}
#endif
```

こんな感じでリンケージを指定して、「これはC言語の定義ですよ」と教えてあげないといけないようだ。
C#VB.NET Excel を XPS に変換する

データをより良く保存または転送するために、ExcelをXPSに変換するなど、さまざまなフォーマット変換が必要な場合があります。XPSフォーマットは、Microsoftによって開発された電子文書用の標準形式です。PDFと同様に、XPS形式はWindowsオペレーティングシステムで広く使用され、電子文書の作成や共有に使用されます。この記事では、コードでExcelからXPSへの変換方法を紹介します。無料の.NETコンポーネント(Free Spire.XLS for .NET)を使用するだけで、簡単な手順で変換を完了できます。以下に、具体的な方法とサンプルコードを示します。
## Free Spire.XLS for .NETをインストールする
**方法1**：[NuGet](https://www.nuget.org/packages/FreeSpire.XLS)でFree Spire.XLS for .NETをインストールする
Visual Studioを開いて新しいプロジェクトを作成します。次に、「Solution Explorer」で「References」を右クリックし、「Nuget Manage Packages」を選択します。Free Spire.XLS for .NETを検索してインストールします。
**方法2**：手動でSpire.xls.dllを追加する
[Free Spire.XLS for .NET](https://jp.e-iceblue.com/download/free-spire-xls-for-net.html)をローカルにダウンロードしインストールします。次に、Visual Studioて新しいプロジェクトを作成し、右側の「Solution Explorer」で「References」を右クリックし、「Add Reference」>「Browse」を選択して、インストールパス下のBINフォルダのdllファイルを見つけ、「OK」をクリックして、プログラムに参照を追加します。
## 方法とサンプルコード
* Workbook インスタンスを作成します。
* Workbook.LoadFromFile() メソッドを使用してサンプルドキュメントをロードします。
* Workbook.SaveToFile(string, FileFormat) メソッドを使用して、Excel を XPS に変換します。
**C#**:
```C#
using Spire.Xls;

namespace ExceltoXPS
{
    class Program
    {
        static void Main(string[] args)
        {

            //Workbookインスタンスを作成する
            Workbook workbook = new Workbook();

            //Excelサンプルドキュメントをロードする
            workbook.LoadFromFile(@"sample.xlsx", ExcelVersion.Version2010);

            //ExcelをXPSに変換する
            workbook.SaveToFile("result.xps", FileFormat.XPS);
        }
    }
}
```
**VB.NET**:
```VB
Imports Spire.Xls

Namespace ExceltoXPS
    Class Program
        Private Shared Sub Main(ByVal args() As String)

            'Workbookインスタンスを作成する
            Dim workbook As Workbook = New Workbook

            'Excelサンプルドキュメントをロードする
            workbook.LoadFromFile("sample.xlsx", ExcelVersion.Version2010)

            'ExcelをXPSに変換する
            workbook.SaveToFile("result.xps", FileFormat.XPS)
        End Sub
    End Class
End Namespace
```
![2023-04-20_143743.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2811193/562637e8-7595-c2cc-eef3-7ab1d4cc7547.png)
Djangoスタートアップ　その11(Webアプリ三層構造構築編)

# 作成するWebアプリの構造
![ApplicationModel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092613/3c8a3f57-f22f-06bd-ad03-b02d617bc3e3.png)


## Nginx
Webサーバー。静的コンテンツ(サーバー上のファイル)を高速に配信するように設計されている

## gunicorn
WSGIサーバー
### wsgi(Web Server Gateway Interface)
WebサーバーとWebアプリケーションを接続するためのインターフェース。webサーバー(Nginx, apache, cgiなど)とPython製のWebアプリケーション(Django, Flask, Zopeなど)の組み合わせの制限を吸収する役目であったり、Webアプリケーションの速度向上を担う。

## PostgreSQL
リレーショナルデータベースサーバー。大規模なデータベースを扱うときに便利

# gunicornの設定＆起動
- 仮想環境の起動
- gunicornがインストールされているか確認
```
which gunicorn
```

gunicornを起動(プロジェクトディレクトリをカレントにする)

```
gunicorn --bind 0.0.0.0:8000 (wsgi.pyが入っているディレクトリ名).wsgi
```

# 自動起動設定
OS起動時に自動的にgunicornが立ち上がる設定をする。

## 方法
サービスファイル`gunicorn.service`を記述して、`systemd`で常時起動させる

```:/etc/systemd/system/gunicorn.service
[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/(プロジェクトディレクトリ)
ExecStart=/home/ubuntu/venv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/home/ubuntu/(プロジェクトディレクトリ)/(プロジェクトディレクトリ).sock (プロジェクトのwsgi.pyがあるディレクトリ名).wsgi:application

[Install]
WantedBy=multi-user.target
```
gunicornを起動

```
sudo systemctl start gunicorn
sudo systemctl enable gunicorn
```
❓ シンボリックリンクが張られるメリットは？
A. /etc/いかに設定ファイルを置くと、アプリケーションとは別に管理することになる。
　　symlinkを張ることでプロジェクトと一緒に管理できる

# Nginxの設定＆起動
gunicornはPythonを実行するソフトウェアであるため負荷が大きい。そのためHTML,CSS,Javascript等静的ページをNginxに配置することで、必要な時だけPythonを呼び出す構成にする。

## Djangoアプリ用のファイル作成
```:/etc/nginx/sites-available/(プロジェクトディレクトリ名)
server {
        listen 80;
        server_name (ドメイン名 or グローバルIP);

location = /favicon.ico {access_log off; log_not_found off;}

location /static/ {
root /home/ubuntu/(プロジェクトディレクトリ名);
}

location / {
include proxy_params;
proxy_pass http://unix:/home/ubuntu/(プロジェクトディレクトリ名)/(プロジェクトディレクトリ名).sock;
}
```
シンボリックリンクを作成
```
sudo ln -s /etc/nginx/sites-available/(プロジェクトディレクトリ名) /etc/nginx/sites-enabled/
```
作成したファイルの内容が正しいか確認
```
sudo nginx -t
```

Nginx再起動
```
sudo systemctl restart nginx
```

## Ubuntuファイアウォールの設定
ファイアウォールで80ポートに穴をあける

（もし開放していたら）試験的に開放していた8000ポートを閉じる
```
sudo ufw delete allow 8000
```

Nginxのアクセスを許可する
```
 sudo ufw allow ’Nginx  Full’
```

## 問題発生
![download.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1092613/4e6048f1-6197-f19d-4a47-e5d02694cf05.png)

`/var/log/nginx/error.log`を確認。すると
```
unix:/home/ubuntu/(プロジェクトディレクトリ名)/(プロジェクトディレクトリ名).sock failed (13: Permission denied)
```
となっていたため、

以下のファイルを次のように編集
```:/etc/nginx/nginx.conf
- user www-data
+ user root
```
で解決

# AWSの設定＆確認

AWS > EC2 > インバウンドルールに80ポートの開放を追加

`http://(グローバルIP)`でアクセスできるか確認

----
補足 : Nginxの設定`sites-available`, `sites-enabled`の解説
https://qiita.com/tomokon/items/e782636c1e5ec6b5dfdc


参考記事
https://ja.wikipedia.org/wiki/Nginx
https://pala-ghe.com/aws-ec2-django-2-gunicorn-nginx/
オブジェクト指向の考え方（その１：オブジェクト指向とは）

新入社員も入ってきたので、少しずつ書き留めていいこうかと。。

# オブジェクト指向とは

現実世界に存在するモノ（オブジェクト）に対して、
- 情報（属性／プロパティ／フィールド）
- 動作（機能／処理／振る舞い／メソッド）

の要素を定義し構造化すること。
そして、オブジェクト自身が、情報と動作に責務を持って管理を行うこと。

※　元々オブジェクト指向は、現実世界をシミュレーションするために考え出されたもの


# なぜオブジェクト指向なのか

認知科学では、人が事象を認知する場合、３つの方法を行っていると考えられる。
-　外延：要素による認知（これは何なのか？）
-　内包：意味による認知（これは何ができるのか？）
-　属性：構造による認知（これは何でできているのか？）

オブジェクト指向では、これらのアプローチをすべて利用し、それぞれ、**インスタンス・クラス・属性**という形で事象を捉える。
その単位をオブジェクトにすることで認知性が高まり、人間が頭で考える形のままモデリングからプログラミングまで一貫して開発が勧められることが可能になる。
その結果、「関心を分離して複雑さを解消する」ことに繋がる。


# オブジェクトとは

**オブジェクト**は「人間が認知できる対象における、具象的あるいは抽象的な事象やモノ」を指す。
厳密に言うと、「他のオブジェクトtの境界線と明確な責務を持ち、かつ、個別に識別できるモノ」。

たとえば、水や空気などは、明確な境界線が存在せず変化するので、通常オブジェクトにはせず、属性とする。
「単体で存在し、ほかのオブジェクトとの関係がないものは、オブジェクトとして意味を成さない」と言う考え方。

オブジェクトは関係するオブジェクトが存在してはじめてオブジェクトになり得る。
そのオブジェクト同士の関係が**ロール**(役割)に該当し、役割を持つと言うことは、「情報に対する責務」と「動作に対する責務」を備えている。

オブジェクト指向におけるオブジェクトとは、**動作・情報・識別性**という３つの特性を持っている「モノ」と定義できる。


***
続きはこちら → [オブジェクト指向の考え方（その２：抽象化と階層化）](https://qiita.com/TkyI/items/cb27bd2db95204499bc4)
ChatGPTは安価な魅力か、高価な投資か？

OpenAIの最新の進化であるGPT-4は、AI業界の主要プレイヤーである。しかし、技術の高度さから、コストに関する懸念が多くの人々を悩ませている。この記事では、Business Insiderの報道に基づいて、ChatGPTが安価か高価かについて検討していきます。

AI技術の進化が著しい中、OpenAIが開発したChatGPTは、さまざまな用途で注目を集めています。しかし、その運用コストに対する懸念もあります。そこで今回の記事では、提供者（マイクロソフトやOpenAI）と利用者である企業の視点から、ChatGPTのコストについて検証し、その実態を明らかにしていきたいと思います。ChatGPTが安価か高価か、そしてどのように活用すべきか、皆さんにわかりやすく解説してまいります。

## （OpenAIやマイクロソフトが）ChatGPTの提供にかかる費用

OpenAIのChatGPTの運用コストは1日に70万ドル（9,000万円）以上かかる可能性がある

https://www.businessinsider.com/how-much-chatgpt-costs-openai-to-run-estimate-report-2023-4

Business Insiderの記事によると、OpenAIが開発したChatGPTの運用コストは、高価なサーバーによって1日最大70万ドル（9,000万円）にもなると報じられています。これは、ChatGPTがユーザープロンプトに基づく応答を計算するために膨大な計算能力を必要とするためです。

しかしながら、マイクロソフトは運用コストを削減するために、秘密裏にAIチップ「Athena」を開発しているとの情報があります。このプロジェクトは、マイクロソフトがOpenAIと10億ドルの取引を行い、OpenAIが自社のモデルをMicrosoftのAzureクラウドサーバーで独占的に運用することを要求した数年後に始まりました。

Athenaチップの開発背景には、マイクロソフトがGoogleやAmazonに遅れをとっている独自のチップ開発を追いつくと同時に、より安価な代替手段を模索していたことがあります。現在、MicrosoftのAIモデルは、Nvidiaのグラフィックスプロセッシングユニットとして知られるチップで動作していますが、これをより低コストなチップに置き換えることを目指しています。

この報道によると、現在300人以上のマイクロソフト社員がチップの開発に従事しており、マイクロソフトとOpenAIが内部で利用するために来年早くもリリースされる可能性があるとされています。ただし、マイクロソフトはコメントを控えています。

---

OpenAIとマイクロソフトは、ChatGPTの運用コストを抑えるために様々な取り組みを進めています。例えば、マイクロソフトが開発中のAIチップ「Athena」は、高価な現行のチップに代わるものとして期待されており、コスト削減に繋がる可能性があります。また、両社は最適なサーバー設定やアルゴリズムの改善にも注力し、運用効率を向上させる試みを続けています。

一方で、AI技術を活用する企業にとっても、コスト削減は重要な課題となっており、次の章では、これらの企業がどのようにOpenAIやマイクロソフトの提供する技術を活用しつつ、コストを抑える方法を模索しているのかを解説していきます。

## （企業が）ChatGPTの利用にかかる費用

ChatGPTは無料で利用できるものの、企業がChatGPT PlusやGitHub Copilotなどの有償サービスを多くの従業員に提供する場合、コストが急速に増大する可能性があります。企業が効果的にChatGPTやOpenAIのサービスを活用するためには、コストと利益のバランスを適切に管理することが重要です。

OpenAI APIの利用に関しても、1トークンあたりの費用は安価に見えますが、最新のGPT-4-32kを使用すると、1回の応答で最大約300円が発生することがあります。これは、トークン数が増えるほど、コストもそれに応じて高くなるためです。

![token.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/61189/881d75d2-49b5-e47c-0997-ad3663ac669d.png)
※1回のやり取りのデータが少なくても、会話のように何回もやり取りすることで想定しない金額になることがあります。分析やレポーティングの実行で300円は高くないものの、会話の1ターンごとに300円かかり10往復で3000円もかかっていたなんて事もあり得ます。

ChatGPTやOpenAIは非常に安価なサービスと言えますが、使い方を間違えると大きなコストが発生することもあります。企業は、コスト削減のために、使用する機能やサービスを選別し、適切な範囲で利用することが求められます。また、APIを使って自社サービスに組み込む際には、効率的な実装方法やリクエスト数を最適化することで、コストを抑えることができます。

コストを比較するときには、トークンの費用だけでなく開発費用も考慮する必要があります。ChatGPTやOpenAIのサービスを利用することで、開発期間を短縮し、リソースを節約することができます。この点を含めて、総合的なコストパフォーマンスを判断することが重要です。

## まとめ

結論として、ChatGPTやOpenAIのサービスは、適材適所で利用することが重要です。企業は、自社のニーズに合わせてサービスを選択し、コストと利益のバランスを考慮しながら活用することで、最大限の効果を得ることができます。