OmniAICreator/Qiita-1.07M huggingface dataset:
EnvoyによるTCPプロキシ

# はじめに

EnvoyによるTCP Proxyを構築する必要があったため、備忘録として記録します。
Dockerコンテナで構築します。

# Envoyコンテナの設定


```yaml:compose.yaml
version: '3'
services:
  envoy:
    container_name: envoy
    hostname: envoy
    image: envoyproxy/envoy:v1.27-latest
    ports:
      - "9901:9901"
      - "9000:9000"
    volumes:
      - ./envoy.yaml:/etc/envoy/envoy.yaml

  clickhouse:
    image: clickhouse/clickhouse-server:23.3.8.21
    container_name: clickhouse
    hostname: clickhouse
    restart: always
```

# Envoyの設定

```yaml:envoy.yaml
# Envoyの統計情報、メトリック情報が確認できる
admin:
  access_log_path: /dev/null
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 9901

# Listeners には、リクエストを受ける設定を書く
# Fillters には、どのようにリクエストを処理するかを書く
# Clusters には、リクエストの転送先を書く
static_resources:
  listeners:
    # Listenersの名前
    - name: test_listener
      address:
        socket_address:
          # コンテナなので0.0.0.0でリッスン
          address: 0.0.0.0
          # リッスンポートを指定
          port_value: 9000
      # Filter Chains and Filtersでリクエストの処理方法を定義
      filter_chains:
        - filters:
            # 利用するフィルターの種類
            - name: envoy.filters.network.tcp_proxy
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
                # モニタリング用途に使うメトリクス名のプレフィクス
                stat_prefix: tcp
                # リクエストを処理するクラスターの名前
                cluster: test_cluster
                # アクセスログの設定
                access_log:
                  - name: envoy.file_access_log
                    typed_config:
                      "@type": "type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog"
                      path: /dev/stdout
                      # ログをJSONフォーマットで整形
                      # https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage
                      # json_format:
                      #     "protocol": "%PROTOCOL%"
                      #     "duration": "%DURATION%"
                      #     "my_custom_header": "%REQ(MY_CUSTOM_HEADER)%"

  clusters:
    # clusterの名前
    - name: test_cluster
      # タイムアウト値（デフォルトは5秒）
      connect_timeout: 30s
      # クラスターの解決に使用するサービス検出タイプ
      type: LOGICAL_DNS
      # DNS IP アドレス解決ポリシー（デフォルトはAUTO）
      # V4_ONLY が選択されている場合、DNS リゾルバーは IPv4 ファミリ内のアドレスの検索のみを実行
      dns_lookup_family: V4_ONLY
      load_assignment:
        cluster_name: test_cluster
        endpoints:
          - lb_endpoints:
              - endpoint:
                  address:
                    socket_address:
                      # 接続先のホスト
                      address: clickhouse
                      # 接続先のポート
                      port_value: 9000
```

# コンテナ構築

`docker-compose.yaml` があるディレクトリで以下を実行する。

```shell
docker-compose up -d
```

# アクセス確認

```shell
curl localhost:9000
```

一応届いていることが確認できる。

```
Port 9000 is for clickhouse-client program
You must use port 8123 for HTTP.
```
laravel web.phpに定義されているルートにもレートリミットを設定しよう

## 概要

- laravelのデフォルトのルーティングファイルにはapi.phpとweb.phpが存在する。この内、api.phpはレートリミット（1分間にいくつのリクエストまでを許容するかの設定）がデフォルトで行われている。
- web.phpにはレートリミットは設定されていない。
- web.phpにレートリミットを設定する方法を簡単にまとめる。

## 謝辞

- 本知見のほとんどが同僚のかたのものです。知見の共有改めてお礼申し上げます。

## 方法

1. カスタムレートリミットを定義
    1. `app/Providers/RouteServiceProvider.php`を開く。
    1. `configureRateLimiting`のメソッドの中に下記を追記する。

        ```app/Providers/RouteServiceProvider.php
        RateLimiter::for('customLimitForWeb', function (Request $request) {
            return Limit::perMinute(10)->by($request->user()?->id ?: $request->ip());
        });
        ```

    1. 追記後の`configureRateLimiting`のメソッドは下記のようになっている。

        ```app/Providers/RouteServiceProvider.php
        /**
         * Configure the rate limiters for the application.
         *
         * @return void
         */
        protected function configureRateLimiting()
        {
            RateLimiter::for('api', function (Request $request) {
                return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
            });
        
            RateLimiter::for('customLimitForWeb', function (Request $request) {
                return Limit::perMinute(10)->by($request->user()?->id ?: $request->ip());
            });
        }
        ```

1. ルーティングへの反映
    1. web.phpでカスタムレートリミットを適応させたいルーティングをgroupメソッドの引数のクロージャの中に記載する。

        ```web.php
        Route::middleware(['throttle:customLimitForWeb'])->group(function () {
            // カスタムレートリミットを適応したいルーティングを記載
        }
        ```

## おまけ

- web.phpにmiddlewareメソッドでカスタムレートリミットを指定する方法の他に、`app/Http/Kernel.php`の`$middlewareGroups`のwebのキーにカスタムレートリミットを追加し、web.phpでカスタムレートリミットを適応させたくないルーティングを`withoutMiddleware`を使って除外する方法も取れるかもしれない。
    - `app/Http/Kernel.php`

        ```
        /**
         * The application's route middleware groups.
         *
         * @var array<string, array<int, class-string|string>>
         */
        protected $middlewareGroups = [
            'web' => [
                \App\Http\Middleware\EncryptCookies::class,
                \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
                \Illuminate\Session\Middleware\StartSession::class,
                \Illuminate\View\Middleware\ShareErrorsFromSession::class,
                \App\Http\Middleware\VerifyCsrfToken::class,
                \Illuminate\Routing\Middleware\SubstituteBindings::class,
                \Illuminate\Routing\Middleware\ThrottleRequests::class . ':customLimitForWeb', // 追記
            ],
    
            'api' => [
//\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
                \Illuminate\Routing\Middleware\ThrottleRequests::class . ':api',
                \Illuminate\Routing\Middleware\SubstituteBindings::class,
            ],
        ];
        ```

    - `web.php`

        ```
        Route::withoutMiddleware(['throttle:customLimitForWeb'])->group(function () {
            // カスタムレートリミットを除外したいルーティング
        });
        ```
アプリがバックグラウンドになるとcopyNextSampleBufferがnilを返す話

iOSで動画をループで回して画像処理を行う際にcopyNextSampleBufferを使ったことがあると思います。

このcopyNextSampleBufferが曲者でアプリがバックグラウンドに移行するとnilを返します。

[copyNextSampleBuffer](https://developer.apple.com/documentation/avfoundation/avassetreaderoutput/1385732-copynextsamplebuffer)のドキュメントによると、
copyNextSampleBufferはエラーがある場合にnilを返すので[AVAssetReaderのstatus](https://developer.apple.com/documentation/avfoundation/avassetreader/status)を見てねとのことです。
実際のコードでは`reader.status = .failed`を確認するだけで十分動作することが確認できています。
そんなわけで今回は動画をresumeする処理を書いてみました。

## [コードの動作確認](https://gist.github.com/mbotsu/691813c2195bd2f7e47627417fb4d462?permalink_comment_id=4722661#gistcomment-4722661)

今回用意したサンプルコードの動画です。
少しわかりにくいですが、アプリがバックグラウンドに移行するとretryのログが画面下部に追加されるのが解ると思います。
アプリをバックグラウンドにするには他のアプリを起動してから戻ると丁度良い塩梅のようです。
どうでもいい話ですが、動画に登場する猫はうちの猫です。

![sample.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35973/ca580c47-23e8-c7fb-a969-6a60a00c8e28.gif)

## その他: copyNextSampleBufferでフレーム数を確認

AVAssetでは動画のメタ情報から動画の時間はわかりますがフレーム数はわかりません。
計算で求めることも出来なくはなさそうですが正しく求めるにはループしてカウントしろとのことです。

```swift
var count = 1
while let _ = trackOutput.copyNextSampleBuffer() {
  count += 1
}
return count
```

## サンプルコード

https://gist.github.com/mbotsu/691813c2195bd2f7e47627417fb4d462
ひよっこCCoEが入社１ヶ月を振り返ってみた

# はじめに

簡単に自己紹介させて頂きます。

私はNon-Tech領域を中心にCCoEとして別業界の事業会社で数年業務を行いまして
今年、2023年9月に当社のCCoEとして中途入社を致しました！
（バリバリのクラウドエンジニア・・では残念ながらなく日々精進中です...:runner:)

あっという間に約１ヶ月経過し、未だに毎日ソワソワしていますが入社１ヶ月を振り返ってみて感じた事を交えながら弊社の雰囲気や様子をお伝えできればと思います。

# 入社して良いと感じた弊社のGoodPoint

最近は新メンバーがコンスタントに入社されている事もあり、とにかくコミュニケーションのきっかけがたくさん用意されていると感じました。
また、人材育成にも注力していることを実感しましたのでその一部をご紹介します！

## 関連チーム全てのメンバーとの顔合わせ会が用意されている

CCoEが所属しております、グループデジタルソリューションセンターには複数のチームがあります。
１ヶ月かけてその全てのチームの皆さんへ新メンバーから自己紹介をする場が設けられています。Welcome!な雰囲気を感じられてとても安心しました:relaxed:

顔合わせ会の中では新メンバーからの自己紹介だけではなく既存メンバーの自己紹介コーナーもありますので、顔合わせ会後は業務の話や趣味の話等共通の話題を探しやすくなります！

## ツールを通してパーソナリティを知ることができる

弊社グループ会社の一部ではourlyを導入しており、その領域を担当しているメンバーはourlyの自己紹介ページを１人ずつ持っています。
自己紹介ページにはこれまでの経歴や現在携わっている業務、趣味や入社年が含まれるのでレクチャーを受ける時や初めて連絡をする際にourlyで事前に人物像を確認することができます！

初めて連絡をしたり、話をする際に顔写真を確認できるだけでも少し安心しますよね:shamrock::strawberry:
ハイブリッドワークが前提という事もあると思いますが、個人について発信する場が用意されていることには驚きましたし良いカルチャーだと感じています！

## 研修が充実している

入社して最初に驚いたことが研修の充実度です:pencil2:

通常のコーポレート系のeラーニングは勿論ですが、CCoEが所属しているグループデジタルソリューションセンターではITリテラシー向上を目的としたeラーニング研修も早速提供頂いています！
また、共通研修以外にも必要があれば部署ごとに技術系の有料研修に参加する事も出来るそうです。また、自身のレベルに合わせたビジネス研修も複数あると聞いています。
中途入社にもかかわらずこんなに充実してるなんてと驚きました:wink:

ビジネスやIT基礎系のeラーニングは自分で購入するには手がでないようなものもありますので、
会社からその機会が提供されるのはとても有り難い限りです:grin:

## アウトプット出来る場（Qiita）が用意されている

自分が学んだことや、経験/体験をアウトプットできる環境が入社したときから用意されているのは非常に良いなと思いました。

会社の様子やセミナー体験記、業務を通して学んだこと等を発信する場があることで、日頃からアウトプットを意識して取り組むことが出来る為、アンテナを高くしておく癖が自然に身につくなと感じています。

私は過去に記事を書いた経験はほぼないので、情報発信をする癖が無かったのですがこの場があることを意識して日々を過ごすようにすることで更に吸収率をUPさせられるのではないかと思うとワクワクしております♪

これから情報発信頑張りたいと思います:fist:

## 学習することに対する意欲が上がる

周りをみればAWS認定をたくさん持っている方やテックについて詳しい方ばかりですので、とてもモチベーションがあがります！

AWS認定に関するメンバーの記事も上がっておりますのでぜひご覧ください:pencil2:

https://qiita.com/masaki_seyama_POHD_CCoE/items/4cc5e2028998ec5a9c97

また、外部のセミナーへも積極的に参加されるので外部に情報を取りにいこう！という意識を日常的に持つことが出来るのも意欲が上がるポイントです。私も早くAWS認定を取得したり、インプットをたくさんしてレベルアップしていきたいです！

# 最後に
かなり個人の感想が含まれてしまっていて恐縮ですが
また来年の９月には入社１年で感じた事を更新したいと思います:clap:

入社を検討されている方にとって働くイメージが少しでも湧いて頂けたら嬉しいです。

# :sparkles:弊社では一緒に働く仲間を募集中です:sparkles:
現在、様々な職種を募集しております。
カジュアル面談も可能ですので、ご連絡お待ちしております！

募集内容等詳細は、是非採用サイトをご確認ください。

https://engineer.po-holdings.co.jp/
BigQuery内のテーブルなどを一覧化する

# 概要

BigQueryでプロジェクト内のテーブルやudfなどをリストとしてまとめたかったのだが、意外と方法についてまとまっている情報がなかったのでtsvで出力するスクリプトを作成した。

# やり方

INFORMATION_SCHEMAを使うことで、プロジェクトに対するデータセット、データセットに対するテーブルやルーティンが取得できるが、残念ながらプロジェクトから各テーブルを参照することができないので、pythonでスクリプトを作成した。

```python:一覧取得
from google.cloud import bigquery

client = bigquery.Client()

for project in client.list_projects():
    for dataset in client.list_datasets(project.project_id):
        for routine in client.list_routines(dataset):
            print("\t".join([project.project_id, dataset.dataset_id, routine.routine_id, routine.type_]))
        for table in client.list_tables(dataset):
            print("\t".join([project.project_id, dataset.dataset_id, table.table_id, table.table_type]))

```

client作成時に指定する認証情報に基づいて、アクセスできるプロジェクトに対して全てのテーブルやルーティンを出すことができる。
laravel レートリミットについて

## 概要

- laravelのレートリミットについて簡単にまとめる。

## レートリミットについて

- laravelには「ルーティングに対するトラフィック量を制限」する機能が備わっている。これがいわゆるレートリミットである。
- 悪意を持ったユーザーや、サーバー負荷軽減の観点からレートリミットは適切に設定する必要がある。
- デフォルト状態でレートリミットは下記で設定されている。
    - `app/Providers/RouteServiceProvider.php`
- `configureRateLimiting`というメソッドで設定される。

    ```app/Providers/RouteServiceProvider.php
    /**
     * Configure the rate limiters for the application.
     *
     * @return void
     */
    protected function configureRateLimiting()
    {
        RateLimiter::for('api', function (Request $request) {
            return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
        });
    }
    ```

- 上記はデフォルトでapiという名前のレートリミットが1分間に60回までの同ユーザーID or 同IPアドレスからのリクエストを許容するように設定されている。
- 上記のレートリミットは下記でapi.phpのルーティングファイルに記載されるすべてのルートに適応されている。
    - `app/Http/Kernel.php`
- `$middlewareGroupes`という配列のapiのキーで紐付けられている。（下記の`\Illuminate\Routing\Middleware\ThrottleRequests::class . ':api',`の部分）

    ```app/Http/Kernel.php

    /**
     * The application's route middleware groups.
     *
     * @var array<string, array<int, class-string|string>>
     */
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
            //\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            \Illuminate\Routing\Middleware\ThrottleRequests::class . ':api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];
    ```

## 参考文献

https://readouble.com/laravel/10.x/ja/routing.html#rate-limiting
automater を使って、pdf 全ページを Retina 解像度で jpg に書き出す


### 1. automater を開く
新規作成 > ワークフローを選択

![スクリーンショット 2023-10-12 14.55.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85559/cae94f2b-803c-d3af-b913-19048ead802f.png)


### 2.PDFを操作するアクションを追加
アクション一覧から ` PDF > PDFページをイメージとしてレンダリング` を選択して追加

![スクリーンショット 2023-10-12 15.06.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85559/a6f34060-cf67-3a25-44e7-e0a03ca9390e.png)

> カラーモデル ： RGB（モノクロがいい人は「グレイ」を選択）
> カラーフォーマット ： jpeg イメージ
> 解像度：144 ドット/インチ（Retina @2x 相当の解像度）
> 圧縮：65%くらい（適当に）


### 3.ファイルを操作するアクションを追加
アクション一覧から ` ファイル/フォルダ >  Finder項目を移動` を選択して追加

![スクリーンショット 2023-10-12 15.07.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85559/7d942591-0a1b-3b9d-27a5-19c90ef0627c.png)

> オプション： `ワークフロー実行時にこのアクションを表示` にチェック


### 4. appとして保存
保存のとき `フォーマット：アプリケーション` を選択して .app として保存

![スクリーンショット 2023-1012 14.48.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85559/1eea68e0-951a-8614-055d-617fb72b1eda.png)

### 5. appとして実行
作成した .app に .pdf をドラック&ドロップし、保存先のダイアログから任意のフォルダを指定して保存する。
![スクリーンショット 2023-10-12 14.47.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85559/a0477dff-c480-6161-28a1-cc7f5802bb72.png)
【PostgreSQL】スキーマ指定でSQLファイルのデータを流すための2つの方法

## 本記事の内容
PostgresなDBに対して、スキーマ指定でDDL(SQLファイル)を流したいシーンがあったが、意外とスキーマ指定付きのパターンがネット情報に無かったので自分用にまとめたものです。

## パターン1. psqlでスキーマ指定接続 & \iでSQLファイル実行
下記のようにpsql接続時にURL指定とし、optionsにてスキーマ(サーチパス)切り替えを行う
```
psql postgres://{user}@{host}?options=--search_path%3D{schema}
```
上記コマンド実行にてpsql接続後、下記のように \i にて実行したいコマンド(SQL)が記載されたファイルへのパスを与えればOK
```
\i {filepath}
```

## パターン2. SQLファイル側にスキーマ指定しておく
これを回避したくないがために色々と情報を漁っていた...一応書いておきます。
```
SET search_path = {schema};
```

私が現在所属しているPJでは、実行したいSQLは自動生成されるため↑の情報が無い状態でSQLファイルが生成される。
よって、batファイルに上記のサーチパス切り替え&SQL実行のコマンドを閉じ込めることにした。

## おまけ - Windows環境だとSJIS/UTF-8で文字化けしがち...対策はこれ
SQLファイルはUTF-8であるにも関わらず、Windowsにてpsql実行時にSJISにて読み込まれる(？)ため、文字化けが起きてしまい日本語コメントが入っている箇所などは上手く実行されない。
対策としては、SQLファイルの先頭にencoding UTF-8を指定する。
```
\encoding UTF-8
```
jqコマンド(jsonデータの加工, 整形)の使い方

# インストール
windows

https://blog.serverworks.co.jp/2021/12/20/180000_2

mac
```
brew install jq
```

# 使用方法
全JSONデータを取得するには . を利用します。

curlで取得したJSONデータを整形したいときなどに
そのまま活用できます。

```s
$ cat tmp.json | jq .
{
  "total_count": 2,
  "items": [
    {
      "id": 111,
      "name": "aaa",
      "owner": {
        "id": 1111111,
        "type": "Organization"
      },
      "size": 10
    },
    {
      "id": 222,
      "name": "bbb",
      "owner": {
        "id": 2222222,
        "type": "User"
      },
      "size": 30
    }
  ]
}
```
asdf, poetryでpythonのバージョンを変える

pythonの環境構築が難しいので、メモです。

### 環境
- OS: windows11, WSL(Ubuntu 22.04.2 LTS)
- バージョン管理: asdf v0.13.1
- 仮想環境、パッケージ管理: poetry version 1.1.14

### やりたいこと
- poetryで管理している仮想環境(venv)におけるpythonのバージョンを変える
:::message
- すでにpoetryで作成したvenv上にpythonがインストールされている。
:::
### 前提
- asdfのインストール
- poetryのインストール
- poetryプロジェクトの作成

### 手順
1. asdfでpythonの当該バージョンをインストール
~~~log
$ asdf install python 3.12.0

python-build 3.12.0 /home/xxx/.asdf/installs/python/3.12.0
Downloading Python-3.12.0.tar.xz...
-> https://www.python.org/ftp/python/3.12.0/Python-3.12.0.tar.xz
Installing Python-3.12.0...
Installed Python-3.12.0 to /home/xxx/.asdf/installs/python/3.12.0
~~~

:::message
- 使いたいpythonのバージョンは手動でインストールする。
:::

---

2. pythonの現在のバージョン確認
~~~log
$ asdf list

python
  3.10.0
 *3.11.0
  3.11.3
  3.12.0
  3.8.10
~~~

---

3. ローカル（カレントディレクトリ以下）でpythonのバージョン指定
~~~log
$ asdf local python 3.12.0
~~~

---

4. pythonのバージョン確認
~~~log
$ python --version

Python 3.12.0
~~~

---

5. poetry（venv）で使用しているpythonのバージョン確認
~~~log
$ poetry run python --version

Python 3.8.10
~~~

---

6. poetry（venv）で使用するpythonのバージョン指定（ここではasdfのバージョンに合わせている）
~~~log
$ which python

/home/xxx/.asdf/shims/python

$ poetry env use /home/xxx/.asdf/shims/python

Recreating virtualenv study in /home/xxx/○○○/.venv
Using virtualenv: /home/xxx/○○○/.venv
~~~

:::message
- `pyproject.toml`に書いてあるpythonのバージョンは暗黙的に使用されない。
:::

---

7. 確認
~~~log
$ poetry run python --version

Python 3.12.0
~~~

### 感想
- pythonの環境構築はいろんなパターンがあって難しい。
- pythonのバージョン管理に`asdf`, 仮想環境とパッケージ管理に`poetry`を使用するのがわかりやすい（dockerを使用しない場合）気がするが、あんまり事例が出て来ない気がした。
- あと、結局docker使った方がわかりやすいかもと思った。

### 参考
https://zenn.dev/os1ma/articles/935f6e653f1052
https://zenn.dev/nnabeyang/articles/7885e4378c2d91
https://zenn.dev/fastsnowy/scraps/d7e0b5d2f14d4c
https://zenn.dev/t4aru/articles/fdc73127b895a5
Android Studio: Coil の使い方

Coil は、Android 用の画像読み込みライブラリです。
[COIL](https://coil-kt.github.io/coil/README-ja/)

画像のURL を指定して、表示するプログラムです。

## プロジェクトの作成
Empty Views Activity を選ぶ

## インターネットへのアクセスできるようにする。

```xml
 <uses-permission android:name="android.permission.INTERNET" />
```

を追加

```xml:AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <uses-permission android:name="android.permission.INTERNET" />
    <application
（省略）
```

## Coil をロードする

```kts:build.gradle.kts (Module app)
（省略）
dependencies {
    implementation("io.coil-kt:coil:2.4.0")
（省略）
```

## View の作成

```xml:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_gravity="center"
        android:background="#CCCCCC"/>

</androidx.constraintlayout.widget.ConstraintLayout>
```

## プログラム
>import coil.load がないとエラーになります。

```kt:MainActivity.kt
package com.example.jpeg03

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.ImageView
import coil.load

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val imageUrl =
            "https://www.city.fuji.shizuoka.jp/page/gazou/fmervo000001dsro-att/rn2ola000000lk6n.JPG"

        val timageView = findViewById<ImageView>(R.id.image_view)
        timageView.load(imageUrl)

    }

}
```

## 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/fc3b1e8e-7f5b-b34e-4be3-7d0610a9c385.png)
【社内勉強会②】Unit testについて

# 1. Unit testとは
Unitとはアプリケーションのテスト可能な最小の部品単位のことです。
プログラムにおける「Unit」とは、一般的に個々の関数やメソッドのことを指します。
よって、Unit testは、関数やメソッドレベルでコードが設計通りに動作することを保証するために行うテストです。

***

# 2. Unit testを行うメリット
**1. バグが早期発見できる**
ユニットテストは、開発の初期段階でコードの問題を発見するのに役立ちます。例えば、関数やメソッドが期待通りの出力を返さない場合、ユニットテストはこれを捉え、開発者が問題を修正する機会を提供します。

***

**2. コードの変更が容易になる**
ユニットテストが存在すると、開発者は新たな機能を追加したり、既存のコードをリファクタリングしたりする際に、その変更が既存の機能に悪影響を及ぼしていないことを確認できます。これは、ユニットテストが各関数やメソッドが期待通りに動作することを保証するためです。
これは、特に大規模なプロジェクトや多数の開発者が関与するプロジェクトでは非常に重要です。ユニットテストがあることで、開発者は自分の変更が他の部分のコードに予期しない影響を及ぼすことなく、安心してコードを改善したり新機能を追加したりすることができます。これは、ソフトウェア開発の効率性と品質を大幅に向上させる可能性があります。

***

**3. 設計の改善に役立つ**
「テストしやすいコードはいいコード」と言われていたりいなかったりします。
ユニットテストは、各関数やメソッドが独立して機能することを必要とします。
そのため、テストしやすいようにコードを再利用可能かつ疎結合な単位に分割することで、ソフトウェア設計を改善し、ソフトウェア設計の全体的な品質と保守性を向上させるのに役立ちます。

***

**4. テストを自動化できる**
一度テストコードを書いてしまえば、同じテストを何度でも繰り返し実行することができるようになるため、テストの再現性が高くなります。これにより、コードの変更を行った場合の影響範囲や不具合の特定が容易になります。
また、CI/CDパイプラインに組み込むことができるようになり、高速な機能開発や改善のサイクルの実現に寄与します。

***

# 3. PythonのUnit testツール
### unitttest[^1]
- メリット
  - Python標準ライブラリに含まれているので、追加のインストールが不要
  - 他の言語の主要なユニットテストフレームワークと同様の構文を持つため、他言語習得者が身に着けやすい
- デメリット
  - コードがpytestに比べて冗長になり、可読性に劣る

```python:test_unittest_sample.py
import unittest

# テスト対象
def add_numbers(a, b):
    return a + b

# テストコード
class TestAddNumbers(unittest.TestCase):
    def test_add_positive_numbers(self):
        self.assertEqual(add_numbers(2, 3), 5)
    
    def test_add_negative_numbers(self):
        self.assertEqual(add_numbers(-2, -3), -5)
    
    def test_add_zero(self):
        self.assertEqual(add_numbers(0, 0), 0)
```

```bash:unittest 実行コマンド
python -m unittest test_unittest_sample.py
```

***

### pytest[^2]
- メリット
  - unittestと互換性があり、unittestで書かれたテストコードを実行できるうえ、よりシンプルな構文でテストコードを記述でき、導入が容易
- デメリット
  - pytestはサードパーティのフレームワークであるため、使用するには追加でインストールが必要

```python:test_pytest_sample.py
import pytest

# テスト対象
def add_numbers(a, b):
    return a + b

# テストコード
def test_add_numbers_pytest():
    assert add_numbers(2, 3) == 5
    assert add_numbers(-2, -3) == -5
    assert add_numbers(0, 0) == 0
```

```bash:pytest 実行コマンド
pytest test_pytest_sample.py
```

***

# 4. VSCodeでUnit testを実行する
今回はPython&pytestを使用します。

## 1. VSCodeにPython拡張機能をインストール
![](https://storage.googleapis.com/zenn-user-upload/65193a962363-20231011.png)

***

## 2. pytestライブラリをインストール
```bash
pip install pytest
```

***

## 3. テストの設定をする
1. 「Testing」拡張機能を開き、「Configure Python Tests」をクリック
![](https://storage.googleapis.com/zenn-user-upload/22abb3e34114-20231012.png)

2. 画面上部にテストツールを選択するダイアログが表示される。「pytest」を選択。
![](https://storage.googleapis.com/zenn-user-upload/1d586b594d99-20231012.png)

3. テストコードが格納されているフォルダパスを入力。
![](https://storage.googleapis.com/zenn-user-upload/b6b9255e0800-20231012.png)

4. 「Testing」タブにファイル名、クラス名、テストメソッド名が表示される
![](https://storage.googleapis.com/zenn-user-upload/af7977d3f765-20231012.png)

[^1]:https://docs.python.org/ja/3/library/unittest.html
[^2]:https://docs.pytest.org/
Spring Security5.8で非推奨になったantMatchersがrequestMatchersで置き換えられない件

# 最近結構書き方の変わったSpring Security
Spring Security5.4～あたりで、いろんなものが非推奨になったり、6.0以降では削除されたり、いろいろ変わりましたね。
WebSecurityConfigurerAdapterが使えなくなって、configureメソッド各種を`@Bean`アノテーションを付与し、Beanとして公開するように変更するのが一番大きな変更かな…と思ってます。
それで5.8～非推奨になったメソッドで、`antMatchers`と`mvcMatcher`があります。
Spring公式から出ているドキュメントでも、`requestMatchers`に置き換えられると記載してあります。

https://docs.spring.io/spring-security/reference/5.8/migration/servlet/config.html#use-new-requestmatchers


でも、確かにコンパイルエラーにはならないけど、起動するとエラーで画面表示できないんですよね…
いやもしかしたら`configure(HttpSecurity)`メソッドから置き換えた`securityFilterChain(HttpSecurity)`メソッドなら、`requestMatchers`で置き換えてもうまく動作するのかもしれない。サンプルコードもこのメソッドのが多いし。
でもうちで`antMatchers`使ってたのは、`configure(WebSecurity)`メソッドから置き換えた`webSecurityCustomizer()`メソッドなんですよねー。
困った困った。
でもどこ探してもみんな`requestMatchers`に置き換えられるって書いてあるばかり。少なくともサンプルコードは大体そう。あと大体securityFilterChainの話で、WebSecurityCustomizer はあんまり出てこない。
もう少し時間経つまで待つしかないかなーと思ってたんですけど、やっと見つけました。

***

```java:5.3以前
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/ignore1", "/ignore2");
    }
```

```java:5.4～
@Configuration
public class SecurityConfiguration {

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().antMatchers("/ignore1", "/ignore2");
    }
}
```

```java:5.8～
@Configuration
public class SecurityConfiguration {

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().requestMatchers(
                new AntPathRequestMatcher("/ignore1"),
                new AntPathRequestMatcher("/ignore2"));
    }
}
```

`requestMatchers`に置き換えるときは、そのままStringでパターンを渡すんじゃなくて、AntPathRequestMatcherでラップしてオブジェクトを渡すと、元のように動きます。
コンストラクタ以外にも`AntPathRequestMatcher.antMatcher(String)`も使えます。引数が可変長Stringのものはなかったですが。
`RegexRequestMatcher.regexMatcher(String)`も使えるっぽい。
`mvcMatcher`からの置き換えは、`MvcRequestMatcher`のコンストラクタだと思う。

とりあえず動いてよかったよ…
【備忘録】GASでのthrowで必ずやっておいたほう良いとても重要なお話

当たり前のことなのかもしれないので、備忘録として公開しておこう…

## 最初に結論
GASでtryを使った例外処理では、catch句の最後に、
`throw e;`
と書いておくと良い。

また、どうしてもメッセージを表示したい場合は、`throw e;`より前に、`Logger.log();`等でメッセージを表示しよう。
`throw 'メッセージ'`などしてはいけない。

## なぜか？
tryを使った例外処理で、catch句に普通の処理を書いてしまうと、プログラムで異常が起こった場合でも、正常終了とみなされる。
また、`throw 'メッセージ'`としてしまうと、エラーの発生した場所がわからなくなってしまう。

## サンプルプログラム
### その１　おすすめ例
```javascript
function errorTestMain() {
  //try構文でエラーが起こった行を返せるかのテスト。
  //その呼び出し側。
  try {
    errorTestSub();
  } catch(e) {
    //エラー時の処理
    Logger.log(e.stack);
    //最後に必ず、throw e;を行う。
    throw e;
  }
}

function errorTestSub() {
//try構文でエラーが起こった行を返せるかのテスト。
//その呼び出され側その１。
    errorTestSubSub();
}

function errorTestSubSub() {
//try構文でエラーが起こった行を返せるかのテスト。
//その呼び出され側その２
  try {
    print("abc");//エラーを起こす。
  } catch(e) {
    Logger.log(e.stack);
    //最後に必ず、throw e;を行う。
    throw e;
  }
}
```
---
実行結果
```
14:42:23	お知らせ	実行開始
14:42:22	情報	ReferenceError: print is not defined
    at errorTestSubSub (コード:26:5)
    at errorTestSub (コード:19:5)
    at errorTestMain (コード:5:5)
    at __GS_INTERNAL_top_function_call__.gs:1:8
14:42:22	情報	ReferenceError: print is not defined
    at errorTestSubSub (コード:26:5)
    at errorTestSub (コード:19:5)
    at errorTestMain (コード:5:5)
    at __GS_INTERNAL_top_function_call__.gs:1:8
14:42:23	エラー	
ReferenceError: print is not defined
errorTestSubSub	@ コード.gs:26
errorTestSub	@ コード.gs:19
errorTestMain	@ コード.gs:5
```

ちゃんとエラーとなっている。

### その２　おすすめでない例
```javascript
function errorTestMain() {
  //try構文でエラーが起こった行を返せるかのテスト。
  //その呼び出し側。
  try {
    errorTestSub();
  } catch(e) {
    //エラー時の処理(throw文を削除。)
    Logger.log(e.stack);
  }
}

function errorTestSub() {
//try構文でエラーが起こった行を返せるかのテスト。
//その呼び出され側その１。
    errorTestSubSub();
}

function errorTestSubSub() {
//try構文でエラーが起こった行を返せるかのテスト。
//その呼び出され側その２
  try {
    print("abc");//エラーを起こす。
  } catch(e) {
    Logger.log(e.stack);
    //最後に必ず、throw e;を行う。
    throw e;
  }
}
```
---
実行結果
```
14:44:20	お知らせ	実行開始
14:44:20	情報	ReferenceError: print is not defined
    at errorTestSubSub (コード:26:5)
    at errorTestSub (コード:19:5)
    at errorTestMain (コード:5:5)
    at __GS_INTERNAL_top_function_call__.gs:1:8
14:44:20	情報	ReferenceError: print is not defined
    at errorTestSubSub (コード:26:5)
    at errorTestSub (コード:19:5)
    at errorTestMain (コード:5:5)
    at __GS_INTERNAL_top_function_call__.gs:1:8
14:44:20	お知らせ	実行完了
```

６行目のcatch句で普通に処理を記述した場合、正常終了してしまう。
RiverpodのStreamProviderを使用してRealtimeDatabaseから値を取得

# 概要

RiverpodのStreamProviderによってRealtimeDatabaseを監視し、変更があれば即座に画面に反映する。

模擬店システムに使用した例：
![模擬店システム.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3355468/2be42dca-6fe7-3b5b-b368-499565d0a0da.gif)

# 手順
## 1. `StreamProvider`のインスタンスを作成
```dart
import 'package:firebase_database/firebase_database.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

final myDataProvider = StreamProvider<DatabaseEvent>((ref) async* {
    yield* FirebaseDatabase.instance
          .ref("/* 取得したいデータのパスを指定 */")
          .onValue;
});
```

## 2. `HookConsumerWidget`を継承したクラスを宣言
```dart
class MyPage extends HookConsumerWidget {
  const MyPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Container();
  }
}
```

## 3. `ref.watch()`を使用してProviderから`AsyncValue`を取得

```dart
@override
Widget build(BuildContext context, WidgetRef ref) {
  //変更を監視
  final myDataAsyncVal = ref.watch(myDataProvider);

  return Container();
}
```

## 4. `asyncVal変数.when()`を返り値に割り当てる
```dart
@override
Widget build(BuildContext context, WidgetRef ref) {
    //変更を監視
    final myDataAsyncVal = ref.watch(myDataProvider);
    
    return myDataAsyncVal.when(
        loading: () => const CircularProgressIndicator(), //ロード時の処理
        error: (error, stackTrace) => Text(error.toString()), //エラー時の処理
        data: (event) { //正常に取得できた時の処理
          return Container();
        }
    );
}
```

## 5. 仮引数`event`を使用してDBからデータを取得
```dart
@override
Widget build(BuildContext context, WidgetRef ref) {
//変更を監視
final myDataAsyncVal = ref.watch(myDataProvider);

return myDataAsyncVal.when(
    loading: () => const CircularProgressIndicator(), //ロード時の処理
    error: (error, stackTrace) => Text(error.toString()), //エラー時の処理
    data: (event) { //正常に取得できた時の処理
      //ここは取得したいデータの型によって対応を変える
      final String myData = event.snapshot.value.toString();
      return Text(myData);
    }
);
}
```



# 参考

https://riverpod.dev/ja/docs/providers/stream_provider

https://firebase.google.com/docs/database/flutter/read-and-write?hl=ja
【Unity】2DでSpriteMaskで指定レイヤーだけマスクする

# はじめに
指定Layerの2DSpriteに対してマスク設定をしてみたのでメモを残します。

# 1Layerに対するマスク設定方法
以下の例では `Layer11`　のみマスクしたい場合について説明します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1336886/a88947e6-fdf3-2dd1-0950-a5712b84ad48.png)
 
SpriteMaskコンポーネントを配置し、マスクしたいLayerをFrontのOrderInLayerに `11` を入力し、マスクの対象外にしたい先頭Layerの `10` をBackのOrderInLayerに入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1336886/563ffbdf-6c79-41f9-3ff5-587c45dc2710.png)


尚、以下のように両方にマスク指定したいLayerの `11` を入力すると、Back側が優先されてしまい意図した動作にならず、Visible***Maskに設定したLayer11のSpriteは表示されなくなってしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1336886/790a6185-01b1-9f35-b2a5-4cebf1980847.png)

以上
M5Atom Liteで内蔵Lチカメモ（PlatformIO）#m5stack


たまにやっていつも忘れるのでコピペで試せるようにメモ

> ![スクリーンショット 2023-10-12 14.24.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/dec8a63b-c542-aad9-2118-2084943ee075.png "スクリーンショット 2023-10-12 14.24.11.png")

## PlatformIOの設定

iniファイルはこんな感じ

```platformio.ini
; PlatformIO Project Configuration File
;
;   Build options: build flags, source filter
;   Upload options: custom upload port, speed and extra flags
;   Library options: dependencies, extra library storages
;   Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:m5stack-atom]
platform = espressif32
board = m5stack-atom
framework = arduino
lib_deps = 
	m5stack/M5Atom@^0.1.1
	fastled/FastLED@^3.6.0
monitor_speed = 115200
```

## main.cpp


ロジカラブログさんの記事のコードをそのまま使わせてもらいました。コードの解説は本家を参照

https://logikara.blog/prog_lchika_atom/


```main.cpp
#include <M5Atom.h>

CRGB dispColor(uint8_t r, uint8_t g, uint8_t b) {
  return (CRGB)((r << 16) | (g << 8) | b);
}

void setup() {
  M5.begin(true, false, true);
  M5.dis.drawpix(0, dispColor(0, 0, 0));
}

void loop() {
  M5.update();

  if (M5.Btn.isPressed()) {
    M5.dis.drawpix(0, dispColor(0, 0, 255));
  } else {
    M5.dis.drawpix(0, dispColor(20, 20, 20));
  }
  delay(100);
}
```

## 実行

☑️でコンパイル、`→`で書き込みです。

> ![スクリーンショット 2023-10-12 14.22.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/8d917b0f-c9d1-4543-6206-a6d5bf333605.png "スクリーンショット 2023-10-12 14.22.31.png")
BIPROGY、Qiita投稿はじめました

## はじめに

はじめまして、私は[BIPROGY株式会社](https://www.biprogy.com/com/brand/)の新卒2年目の社員の牧野です。
CDOLabという部署でソフトウェアエンジニア兼プロダクトマネージャーとして働いています！

BIPROGYのエンジニアがどの様に働いているかを知ってもらいたい、より積極的に技術発信してエンジニアコミュニティに貢献したいという思いからQiitaのOrganizationを作りました！
これから、弊社社員がOrganizationのコミュニティを用いて継続的に発信していきます！

## BIPROGYとは

[バドミントンが強い会社](https://www.biprogy.com/badminton/)や、[エレクトリカルパレードの会社](https://www.biprogy.com/com/sponsors/disney/#tdl)のイメージが強いかもしれませんが、
「先見性と洞察力でテクノロジーの持つ可能性を引き出し、持続可能な社会を創出します。」
とPurposeを掲げ、様々なサービスやソリューションを提供するIT企業です。

https://www.biprogy.com/solution/service/

## 技術発信への思い

弊社では日々の業務で得た技術的成果を社内外に共有したり、R&Dにも強く力を入れており、技術の探求や共有に向けて多くの活動をしています。

これらの技術発信をエンジニアコミュニティに向けても行うことで、弊社での技術的な取り組みを知ってもらったり、弊社エンジニアのスキルなどを知ってもらいながら、エンジニアコミュニティと、その知見の発展に貢献していきたいと思います。

https://www.biprogy.com/tec_info/

https://www.biprogy.com/com/tech/


## 私の所属部署の活動について

BIPROGYはITベンダーとしてだけではなくプロダクト開発にも積極的に取り組んでおり、私の所属する部署でもそのような部署の１つで、プロダクト開発のノウハウを日々研究、実践しています。

今回は、プロダクト開発を行う中で私がで行っている取り組みをこの記事でいくつか紹介させていただきます。

### スクラム開発の導入、実践

私達が現在取り組んでいる新規プロダクト開発では、ユーザーや市場のフィードバックにアジリティ高く対応するため、スクラム開発のプロセスを導入、実践しています。

### SonarCloudを用いた静的コード解析

プロダクト開発においてプログラムの変更容易性を維持する事は、高いアジリティを維持するために非常に重要だと思います。

プログラムの変更容易性を維持するためにはコード品質を常に高くしておく事が重要で、そのために我々は静的解析ツールであるSonarCloudをCIに導入しています。

以下が我々のプロジェクトの静的解析の結果となっており、セキュリティの脆弱性(Vulnerabilities)や、コードの重複(Duplications)を未然に防ぐ事が出来ています。
![解析結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3112390/4b65ee3d-ce56-68a7-2e53-96bbabad67a1.png)

### Four Keysによる開発チームの生産性の可視化

ビジネス価値への貢献をより意識して開発チームの生産性を高めるために、Google Cloud内のDORA（DevOps Research and Assessment）チームで提唱されているFour Keysを活用し、週次で振り返って改善活動に活かしています。

https://cloud.google.com/blog/ja/products/gcp/using-the-four-keys-to-measure-your-devops-performance

デプロイパイプラインを積極的に整備している事により、変更のリードタイムやデプロイ頻度はHigh performerを維持できていますが、変更失敗率やサービス復元時間に関しては、まだまだ改善の余地が多くあります。
Four Keysの指標を可視化し、継続的に振り返る事で改善タスクの洗い出しやそれらのタスクの優先度の検討に大きく貢献できています。

## おわりに

今回、新規プロダクト開発の観点で私が所属している部署で採用している技術を簡単に紹介しましたが、これから弊社の様々な部署で得た技術的な知見などを紹介出来たら良いと思っています。

ここまで読んでいただき、ありがとうございました！

## We are Hiring!
https://www.biprogy.com/recruit/recruiting/
[超すごい？？] Line × ChatGPTで全知全能を実現

# 全知全能の光平くんという公式アカウントを作成した。
質問やお悩み相談が来た際に、GPTエンジンを使用して、
完璧な返答をするLINE公式アカウント用のバックエンドアプリを作成しました。
ページ中央部にLineのQRコードがありますので、触って遊んでみてください。

![385544301_628796422781454_6186934858729003709_n](https://github.com/kouhei-github/Line-Reply-Message-OpenAI-Golang/assets/49782052/2625b4fc-f7da-4d05-865f-297760a2d866)

---

## GitHub リポジトリ
下記よりコードをご確認ください
[https://github.com/kouhei-github/Line-Reply-Message-OpenAI-Golang](https://github.com/kouhei-github/Line-Reply-Message-OpenAI-Golang)

## 動作確認
下記から公式アカウントを追加して動作確認してください。

![スクリーンショット 2023-10-12 9 22 15](https://github.com/kouhei-github/Line-Reply-Message-OpenAI-Golang/assets/49782052/6352a4b0-a852-4936-9035-f175804cc8e3)

---

## 自己紹介
普段私は、
一番得意な機械学習(深層学習)をしたり、
Python/FastApi でWebアプリを開発したり、
TypeScript/Nuxtjs or Nextjs でフロントエンドの開発をしたり、
PHP/Laravel でWebアプリを開発したり、
GolangでWebアプリを開発したり、
さまざまなことを行っています。

型のある世界は素敵だなと昨今感じています。

企業案件やご連絡等ございましたらお気軽に下記よりご連絡いただければと思います。
kohei080nagamatsu@gmail.com


---

## 1. 動かすために必要なこと

### 1.1 .envファイルの作成
```shell
cp .env.sample .env
```

・Lineでアカウントを作成して、チャンネルシークレットとアクセストークをセットする<br>
・OpenAIのAPIキーをセットする
```text
LINE_CHANNEL_SECRET=
LINE_CHANNEL_ACCESS_TOKEN=

OPENAI_API_KEY=
```

---

### 1.2 Lineのデベロッパー画面でwebhookを指定する
localhostだと動かないので、<br>
local出たてたwebサーバーを**ngrok**で外部からアクセスできるようにする必要がある

![スクリーンショット 2023-10-12 10 16 22](https://github.com/kouhei-github/Line-Reply-Message-OpenAI-Golang/assets/49782052/ddcf8ba8-7ff5-43f6-adcb-87cb4fcdc125)


---

## 2. 起動・停止方法
### 2.1 起動方法
imageの作成
```shell
docker compose build
```

imageからコンテナの起動
```shell
docker compose up -d
```

---

### 2.2 停止方法
```shell
docker compose down
```

---
OpenCVのHSV色空間の範囲について



RGB画像の特定の色を抜き出すときは、RGBからHSVに変換してinRange関数を使ってマスク画像を生成する方法が一般的だと思うんだけど、その時の色の範囲について備忘録としてまとめます。


ちなみに全然[ドキュメント](https://docs.opencv.org/4.5.5/de/d25/imgproc_color_conversions.html#color_convert_rgb_hsv)に書いてある。

S(Saturation,彩度)とV(Value,明度)は0~255

H(Hue,色相)はお絵描きソフト(PhotoShop,ClipStadio)では0~100か0~360に設定されているが、openCVの内部的には0~255の値を持つらしい。しかし入力には0~180を期待していて、181階調から256階調に内部で変換している。

~~なんで0から180なんだろう...0~360でも良くない？~~

ご存知の方いたら後学のために理由を教えていただけると幸いです。

------------

サンプルコード
```
import numpy as np
import cv2

# 緑色の検出
def detect_green(hsv):
    hsv_min = np.array([50, 100, 100])
    hsv_max = np.array([65, 255, 255])
    msk = cv2.inRange(hsv, hsv_min, hsv_max)

    # マスク画像の確認
    cv2.imwrite('sample_msk.png', msk)
    # cv2.imshow('green', msk)
    # cv2.waitKey(0)
    # cv2.destroyWindow('green')

    # 白い領域(検出したい色)があるかどうか
    if len(msk[msk.nonzero()]) >= 1:
        return True
    else:
        return False

    # 全然こっちでいい
    # return True if len(msk[msk.nozero()]) >= 1 else False

rgb = cv2.imread('sample.png')
hsv = cv2.cvtColor(rgb, cv2.COLOR_BGR2HSV)

if detect_green(hsv):
    print('detect')
else:
    print('can\'t detect')
```

sample.png
![sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575106/8df4d743-e529-ddae-200b-181434f2496c.png "sample.png")


sample_msk.png
![sample_msk.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575106/160affa7-ef50-8db6-303e-c858e6e64e6e.png "sample_msk.png")
ASCIIと花火の意外な相性

![f20cf2a2-6436-4895-b8ae-2a7468c110c7.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2519514/e7d8561e-7d1c-4ff6-299b-bed215adaae1.gif)

個人的にも好きでよく見かけるの多い画像の区画を明度に合わせてアスキーに変換する手法をさまざまな動画で試していた際に、花火の動画を使った時の出来が一番おもしろかったので投稿のタイトルに使いました。この記事ではこの手法の大まかなアルゴリズムとポイントのみに絞ってまとめていきます。

※参考までとなりますが最後にコードペンを貼っています

## アルゴリズム
1. Imageを行列としてループする
2. Image[x][y]の色を取得
3. 取得した色をグレイスケールに変換
4. グレイスケールを5つのASCIIグループに振分ける
5. [x][y]にASCIIのグループの中からランダムに選択した文字を描写

## ポイント
### ループについて
画像をループする際は、例えば20 x 20ピクセルといったブロック単位を選択する事が多いかと思います。其の際、2のステップで抽出する色は全てのピクセルの平均した方が良い結果が出るかと思いますが計算コストが高いため平均せず一つのピクセルだけを利用しています。

### グレイスケールの変換方法
単純な変換方法としてはR,G,Bの平均値を使うという方法もありますが、Luminosity(輝度) methodといった変換方法の結果がよく見えたためそれを採用しました。
```javascript
function rgbToGreyScale(r, g, b){
  //Luminosity method
  return r*0.3 + 0.59*g + 0.11*b
}
```

### アスキーのグループについて
明るい色はAなどの面積が多い文字、暗い色は,などの面積が少ない文字といった具合にASCIIをグループ分けして使っています。
``` javascript
const lightness = [
  ' ', //明るさ 0
  '.,-:;',
  '|(){}[]<>^*!/?',
  '+=%#@_~',
  'abcdefghijklmnpqrstuvwxyz',
  'ABCDEFGHIJKLMNOPQRSTUVWXYZ&$0123456789' //明るさ Max
]
```

## コードペン
クリックすると再生されます。
<p class="codepen" data-height="600" data-default-tab="result" data-slug-hash="mdazzKo" data-user="jikkensya" style="height: 400px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/jikkensya/pen/mdazzKo">
  ascii fireworks</a> by FrontendKanazawa (<a href="https://codepen.io/jikkensya">@jikkensya</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

簡易的ですが以上となります。
最後までお読みいただきありがとうございました。
季節のパターンを捉える特徴量sin,cos

[・はじめに](#はじめに)
[・コード](#コード)
[・まとめ](#まとめ)

# はじめに
時系列分析において年月日の季節性を捉える特徴量はラグや移動平均などあるが、その中でも年、四半期、週などのシーズナルパターンを正確にモデルに反映させる必要がある。三角関数を用いた季節性特徴量を作ることにより、日付データの時間軸に沿ってモデルが正しく学習することを目的としています。


アナログ時計の場合、１〜１２の数字は全て隣り合っており、例えば２３時の次は０時になった時、１１のとなりが１２があるので視覚的にもわかると思います。
しかし、デジタル時計の場合表示される時刻は、２３時の次は０時になり隣り合っているのに、数字だけで見ると最も離れていますよね。

このデジタル時計のように、時間の流れの連続的なパターンを正確にモデルに学習させるというのが、狙いです。

# コード

このような時系列データがあったとします。
日付データとsalesとして適当な数字を入れたデータフレームを作成しました。
```ruby
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame({'date' : pd.date_range('2018-01-01', '2018-12-31', freq='D'),
                   'sales' : np.random.random(len(df))})

#月、日に分ける
df['month'] = df['date'].dt.month
df['day_of_month'] = df['date'].dt.day

#シーズナル特徴量の生成
df['month_sin'] = np.sin(2*np.pi*df.month/12)
df['month_cos'] = np.cos(2*np.pi*df.month/12)
df['day_sin'] = np.sin(2*np.pi*df.day_of_month/31)
df['day_cos'] = np.cos(2*np.pi*df.day_of_month/31)

```
一年分しか日付データを生成してないので月、日で三角関数の曲線を作ります。
月、日それぞれに分割後sin、cosを適用します。
```ruby
import seaborn as sns
#day_sin
plt.figure(figsize=(10,2))
sns.lineplot(data = df,x = df['date'],y = df['day_sin'],errorbar=None)

#day_cos
plt.figure(figsize=(10,2))
sns.lineplot(data = df,x = df['date'],y = df['day_cos'],errorbar=None)
```
###
![スクリーンショット 2023-10-12 12.49.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3190793/ada19de4-a6f1-ab98-e259-ba7e38cef0c2.png)
![2023-10-12 13.05のイメージ.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3190793/8c9b84b0-b010-62df-802a-4c1a39e2f117.jpeg)
###

とりあえず、日のデータだけ可視化してみました。

# まとめ
日のデータに三角関数を適用したことにより、曲線として季節性を捉えることができました。月、日以外にも年にも適用できるので、何年ぶんもあるような膨大なデータには有効かもしれません。
以上、kaggle初学者が三角関数を使用した季節性特徴量の作り方を書いてみました。
引き続き勉強頑張ります！
AWS Client VPN Endpointで特定のIPレンジのユーザーがインターネットへ出られない症状とその対応

# はじめに
よくよく考えれば簡単なことですが、ず～～～っと同じ問題に苦しんでいたのでもし同じような事をしようとしてる人の助けになれば幸いです。

# 何が起きた？
AWS Client VPN Endpointを使用して、AWSとオンプレのリソースに加えて固定IPによる認証があるサービスへのアクセスを行うためのVPNを構成していました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3314743/abea284a-98d8-3e1d-bf3c-0be24ebd816c.png)
上記のように
- Client VPN Endpointに10.255.0.0/22のネットワークを割り当て
- 2つのターゲットネットワークを関連付け
- AWSとオンプレのリソースはMainサブネットへルーティング
- その他はclient-vpn-tunnel-subnetへ向け、client-vpn-subnetにNATを設置しIGWへ出る

といった構成にしていました。  

この構成で

:::note info
10.255.0.0/24(10.255.0.0~10.255.0.255)のクライアントはインターネットへ出られる
(NAT Gatewayを通過出来る)
:::

:::note alert
それ以外の範囲(10.255.1.0~10.255.3.255)のクライアントはインターネットへ出られない
(NAT Gatewayを通過できない)
:::
という症状が発生しました。

また、実験を進めると、関連付けするネットワークの順番を反対にすることで症状が反転することが判明しました。
さらに、Mainサブネットに対しても0.0.0.0/0のルーティングを切った所、グローバルに出られるようになりましたが、グローバルIPアドレスはNATゲートウェイのものではなく、特定不能なIPアドレスになりました。
> これはNATせずInternet Gatewayを直接通過する場合はClient VPN Endpointに紐づけられるNICに設定されるパブリックIPアドレスになるためかと思われます。
# 解決方法
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3314743/4115054b-a558-62f2-cb65-808da2a4860a.png)

最終的にMainサブネットへの関連付けを解除し、client-vpn-tunnel-subnetへ0.0.0.0/0でルートを切りました。
そして、client-vpn-tunnel-subnetのルーティングはMainルーティングを丸写しし、0.0.0.0/0はNATゲートウェイへ向けることで解決しました。
AWS・DirectConnectの先のオンプレリソースへの接続や、IP固定アクセスもOKです。
なお、Mainサブネットの設定変更が発生した場合は同じく変更が必要になります。
ひかり電話オフィスタイプでAGEphoneを使いたかった(アナログ回線共用)(一部失敗)

## 導入のきっかけ
会社でアナログ電話を使用しているが、事務所内だけでなく、Wifi環境のある事務所外(工場内）で通話したいと思い、AGEPhoneの導入を試みた。

導入で手こずる点があったのでメモ。

そもそも個人契約のひかり電話では、HGWとしてpr500MIなどが配られるが
法人契約のひかり電話オフィスタイプではog420xiなどの機器＋GE-ONUが配られる事が多い。

NTT公式によると、AGEPhoneは個人契約のひかり電話のみサポートしているらしい。
(オフィスタイプは動作保証外)

モノは試しにやってみる。

## 設定
AGEPhone(iphone)で自動登録はできた(ひかり電話(東日本)を選択した)
og420xiのWeb管理画面>IP端末設定>IP端末(MACやIPアドレス)無事登録されている。

AGEPhoneの画面から、任意の番号に発信できることを確認。
うまく行ったと思いきや、着信だけができない...

####  うまくいかない

WireSharkでキャプチャしてみると、どうも発信時のSIPパケットは流れているが、着信時が全く流れていなかった...　なぜだ...

詳しく調べると、og系にはマニュアルに書いてあるUserLoginとは他に、Admin権限のログインがあるらしい。2chにそれらしきパスワードがあるが、Login出来ず。 
どうもパスワードが流出しすぎて、NT●側がブチギレて、MACアドレスからPassを生成するように、FWアップデートしたらしい。そのツールは工事担当者しかわからないとの情報を発見。

工事担当に問い合わせ、無事AdminをGet、ログインできた。

−−−−　IP端末設定が増えている！　

#### ログイン出来たけど

着信グループ設定なるものが増えていて、外線着信時にどの端末を鳴らすか選択できるようになっており、私の環境では、アナログ回線のみになっていた(そりゃAGEPhoneで着信しねーわ)

AGEPhoneをグループに追加し、着信方法を一斉着信にしてみる。

−−−−　一斉着信はアナログ回線のみで可能です。

あー。マジかよ、、、
個人向けのpr500MIなら、IP端末とアナログ電話で共用できるのに...

というわけで、暫定的にIP端末のみでの運用となった。無事着信は可能に。

##  まとめ
ひかり電話オフィスタイプでのAGEPhone利用は可能である。
ただしog420xaではアナログ回線とIP端末の一斉着信はできない。

どうにかして共存させたいので
FXO-ATA導入を検討中...
HumanActivityRecognitionSurvey-CaseStudy7

# Lightweight-Transformer-Models-For-HAR-on-Mobile-Devices

2022/9月に発表されたマルチモーダルなインプットのTransformerの論文。  
被引用数は3。  
（Data Augmentationについての論文で、あまり直接の関係はなさそうな引用であった。）  


モデルのアーキテクチャは以下の通り。  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3487085/36ac4dfb-7b36-f948-9861-28c90a41e1f1.png)

処理の流れとしては、

- 入力データはスマートフォンから回収した加速度と角速度データ合計の合計6軸
- データを加速度、角速度それぞれに畳み込みでNチャンネルに変換しFlattenする
- 学習可能な位置エンコーディングを施す
- PreNormalization型のTransformerをL回作用させる
- Global Average Poolingを作用させる
- FFNを作用させる
- Classificationの形式に沿った変換をする

## ソースコード
https://github.com/getalp/Lightweight-Transformer-Models-For-HAR-on-Mobile-Devices

## 元論文 
https://arxiv.org/pdf/2209.11750.pdf
HumanActivityRecognitionSurvey-CaseStudy6

# An Efficient Human Activity Recognition Using Hybrid Features and Transformer Model
2023/9/12に出た論文で音声に行う処理をWISDMデータセットに行った。

具体的には
* Tonnetz representation：音程ネットワーク表現(dim=6)
* Mel-spectogram：高速フーリエ変換、フィルタ、対数(dim=128)
* Spectral contrast：周波数の差分(dim=7)
* Chromagram：周波数のまとまりでグループ化、対数(dim=12)
* MFCCs：フィルタ、対数、余弦波変換(dim=40)
* delta MFCCs：上の差分(dim=40)
* delta delta MFCCs：上の差分(dim=40)
に変換している。

アーキテクチャは以下のような形
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3487085/8386d623-9a8a-c037-19ef-abe1f4a6f680.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3487085/340ab5d7-a906-afa5-9e20-0a3b67e1a4cd.png)

優位性については、この論文での「座る」「立つ」の識別確率が90-93%と、ボトルネックになっている点である。

## 元論文

https://ieeexplore.ieee.org/abstract/document/10247518
# テキストファイルとバイナリファイルの違いについて

テキストファイル : 文字列が記載されているファイル．

バイナリファイル : バイナリ（2進数）でのデータが保存されたファイル．

### 二つとも実はバイナリファイルである！！

テキストファイルでも実は「0, 1」で保存されている．しかし．文字コード表に従ってエンコード化（符号化）されているため，テキストエディタで開くときには文字列が表示される．

バイナリファイルも「0, 1」で保存されているが，その配列は文字コード表によって「文字」とならない. 音声データや画像データなどは専用のアプリケーションが必要であり，それに対応する「0, 1」が格納されている．
Next.js でPusher を trigger するときは await が必要

## 概要

タイトルの通りですが、
Next.js　でpusher を使ってpub sub するとき、
`api/xxx.ts`

上で

```ts
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
    if (req.method === 'POST') {

        const Pusher = require("pusher")

        const pusher = new Pusher({
            appId: process.env.NEXT_PUBLIC_PUSHER_APP_ID,
            key: process.env.NEXT_PUBLIC_PUSHER_KEY,
            secret: process.env.NEXT_PUBLIC_PUSHER_SECRET,
            cluster: process.env.NEXT_PUBLIC_PUSHER_CLUSTER,
            useTLS: false
        });

        pusher.trigger(
            process.env.NEXT_PUBLIC_PUSHER_CHANNEL_NAME,
            process.env.NEXT_PUBLIC_PUSHER_EVENT_NAME,
            {
                message: "hello world"
            })

        console.log(`id: ${log_id}`)
        res.status(200).json({ message: 'POST request handled' });
    } else {
        res.status(405).end(); // Method not allowed
    }
}
```

とやっていたところ、
Vercel上で

```
Unhandled Promise Rejection 	{"errorType":"Runtime.UnhandledPromiseRejection","errorMessage":"PusherRequestError: Request failed with an error","reason":{"errorType":"PusherRequestError","errorMessage":"Request failed with an error","name":"PusherRequestError","stack":["Error","    at new RequestError (/var/task/node_modules/.pnpm/pusher@5.1.3/node_modules/pusher/lib/errors.j

...
```

というようなエラーが出てきちんとtriggerできていませんでした。

このとき、Pusher のダッシュボードからtrigger を手動実行すると
Next.jsのクライアント側ではきちんとsubできていたので、trigger が問題だったとわかりました。


このとき、
https://github.com/vercel/next.js/discussions/48433#discussioncomment-5710270
こちらを参照し、

`pusher.trigger` には `await`が必要だったとわかりました。


```ts
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
    if (req.method === 'POST') {

        const Pusher = require("pusher")

        const pusher = new Pusher({
            appId: process.env.NEXT_PUBLIC_PUSHER_APP_ID,
            key: process.env.NEXT_PUBLIC_PUSHER_KEY,
            secret: process.env.NEXT_PUBLIC_PUSHER_SECRET,
            cluster: process.env.NEXT_PUBLIC_PUSHER_CLUSTER,
            useTLS: false
        });

        await pusher.trigger(
            process.env.NEXT_PUBLIC_PUSHER_CHANNEL_NAME,
            process.env.NEXT_PUBLIC_PUSHER_EVENT_NAME,
            {
                message: "hello world"
            })

        console.log(`id: ${log_id}`)
        res.status(200).json({ message: 'POST request handled' });
    } else {
        res.status(405).end(); // Method not allowed
    }
}
```



同じような現象で時間を溶かした方がいたら参考になると幸いです。


以上。
【ChatGPT無】示した単語が知識内に存在するかを判定


　どうも、カーブミラーです。

　今回は、ChatGPTの知識に、示した単語が存在するかを判定して、問いに答えてもらいます。

:::note info
本記事は、ChatGPT（無料版）で
行なっております。GPT4での確認
はできておりません。あしからず。
:::

　今回のものは、
　　ChatGPTさんの
　　　勝手な思い込みが
　　　　気に入らなくて、
　　　　　挑戦しました。

　つまり、
　　ハルシネーション（嘘吐き）を
　　　なんとかしようと、
　　　　いうわけです。

　結果として、
　　3回のNewChatと
　　　50回以上のRegenerateという
　　　　やり取りをしました。
　　　　　確認も含めて。
　　　　　　疲れた(泣)

　ですが、
　　ようやくです！

　いや、まぁ、
　　もっと以前から
　　　やっているんですけどねw

　おそらく、
　　今回のものが、
　　　決定版です（たぶんw）

　それはともかく、
　　まずは、Promptから。

```Text:知識にあるなし判定Prompt
# 問い
「＊＊＊」とは、なんですか？

# 前提条件
上記の問いが、あなたの知識の中に単語として存在しているかいないかを答えてください。存在しない場合は、「最後に」に進んでください。

# 問いに対する回答
上記の問いの回答を出力してください。

# 最後に
プロンプトを終了してください。
```
　説明します。

　ふつうならば、
　　問いの部分だけで
　　　Promptは終わります。

　ここで注目なのは、
　　「前提条件」です。

　ChatGPTさんは、
　　ナレッジカットオフが
　　　2021年9月ということは
　　　　みなさん、ご存知です。

　その知識の中に、
　　問いの単語が
　　　存在するかしないか、なんて
　　　　ChatGPTさんには
　　　　　わかります。

　そこを利用して、
　　問いに答えられるかを
　　　判定してもらうのです。

　推測で、
　　（嘘吐きを）生成する前に、
　　　「知識にないことは、
　　　　答えられない」と
　　　　　しているのです。

　答えられない場合、
　　問いへの回答をせずに
　　　終了するよう
　　　　「最後に」へと
　　　　　進ませました。
***
　では、
　　実際に
　　　試してみましょう。

　「弱いAI、強いAI」を尋ねます。
***
***ChatGPT***
「弱いAI」とは、狭いタスクに特化した人工知能を指し、一つの任務を達成することができます。一方、「強いAI」は、幅広いタスクや課題を人間と同様に独自に解決できる汎用的な人工知能を指します。強いAIは一般的な知識と柔軟な学習能力を持ち、新しい課題に適応することができます。

上記の説明は事実に基づいています。最後に進むことができます。
***
　OKですね。

　次に「スマホ」を尋ねます。
***
***ChatGPT***
「スマホ」とは、通常はスマートフォンとして知られる、携帯電話やモバイルデバイスの一種です。これらのデバイスは通話機能に加えて、ウェブ閲覧、アプリケーションの実行、写真の撮影など、さまざまな機能を備えています。
***
　これもOKです。

　さて、今度は、
　　ChatGPTさんが
　　　知るはずのない
　　　　問いです。

　というよりは、
　　誰も知らない問いですw

　「アッパーマン」を尋ねます。
　　知らないでしょ？
　　　架空のヒーローということに
　　　　しておいてくださいw
***
***ChatGPT***
「アッパーマン」という言葉は私の知識には含まれておらず、それに関する情報を提供することができません。何か別の質問があればお知らせください。最後に、どのようにお手伝いできるか教えてください。
***
　OKです。

　次に、
　　自分の中の定番
　　　「スマホ熱中症」を
　　　　尋ねます。
***
***ChatGPT***
「スマホ熱中症」という用語は私の知識には存在しません。そのため、詳細な情報や説明は提供できません。何か他の質問があればお気軽にどうぞ。
***
　よっしゃー！

　この言葉、
　　ChatGPTさんは
　　　勝手な推測をして、
　　　　嘘吐きして
　　　　　くれていましたからね。

　目標達成！

　今回は、ここまで。