OmniAICreator/Qiita-1.07M huggingface dataset:
無縫的に視覚データ探索をスケーリング: PyGWalkerがSnowflakeと出会う

データ分析の分野では、今日のアナリストは単に堅牢な計算能力を求めているわけではありません。彼らは没入感のあるインタラクティブ性とシームレスなユーザーエクスペリエンスの両方を提供するツールを探しています。ビッグデータの地平線が拡大し続ける中で、アナリストがその広大なデータの中に深く潜り込み、迷子にならずに探索できるツールの需要が増しています。

![pygwalker-snowflake.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583226/041f3310-54da-4f47-ec7f-1dbaf2ec8652.png)


PyGWalkerを紹介します。これは、PandasのデータフレームをJupyterノートブック内で魅力的なインタラクティブな視覚化に変換するために設計された動的なPythonライブラリです。多くの人々は、TableauやPowerBIのようなプラットフォームの信頼性のあるオープンソースの代替手段としてこれを知っています。しかし、PyGWalkerの潜在能力を、クラウドデータの巨人であるSnowflakeとともに利用すると、真の魔法が明らかになります。これにより、効率的で詳細でインタラクティブなデータ探索のための類例のないシナジーが生まれます。

### インテグレーションへの簡単なダイブ
#### インストールでステージを設定する
PyGWalkerとSnowflakeの強力な組み合わせを利用するには、必要なライブラリをインストールしてください：

```bash
pip install --upgrade --pre pygwalker
pip install --upgrade --pre "pygwalker[snowflake]"
```

#### 接続をステッチする
PyGWalkerの真の美しさは、Snowflakeのリザーバから直接データをフェッチし、それらを魅力的なプロットに変換する能力にあります。このためには、ライブラリとSnowflakeとの間にコネクタが接続を橋渡しします。

```python
import pygwalker as pyg
from pygwalker.data_parsers.database_parser import Connector

conn = Connector(
    "snowflake://user_name:password@account_identifier/database/schema",
    """
        SELECT
            *
        FROM
            SNOWFLAKE_SAMPLE_DATA.TPCH_SF1.ORDERS
    """
)
walker = pyg.walk(conn)
```

接続文字列に関する注記: Snowflakeは、特定の設定に応じてアカウント名形式を選択するか、より詳細なアカウントロケータ形式を選択するかの2つのバリエーションの接続文字列を提供しています。

公式ドキュメントでの接続文字列形式の詳細

```text
snowflake://<user_login_name>:<password>@<orgname>-<account_name>
```

### インタラクティブ探索が解き放たれる
単体のPyGWalkerを使用することで、アナリストはデータフレームから視覚的なストーリーを作成することができますが、Snowflakeとの統合により、その能力が何倍にも増幅されます。この統合により、データが単に表示されるだけでなく、それが生き生きとし、インタラクティブで没入感のあるものとなります。あなたが扱っているのが控えめなデータセットであれ、ビッグデータの巨大なものであれ、PyGWalkerは反応性と明瞭さを保証します。

さらに、Snowflakeの効率的なデータ処理能力は、PyGWalkerの視覚化機能を補完しています。アナリストは大きなデータセットを容易に取り扱い、その洞察を精確に視覚化することができます。トレンド、異常、パターンを特定しようとしている場合でも、このシナジーにより常にコントロールすることができます。

### 結論
データ分析ツールの進化は、データサイエンスの常に変わりゆく風景の証です。個々のツールは大きな約束を提供していますが、それらを統合することで革命的な結果がもたらされます。PyGWalkerとSnowflakeの連携は、この事実の証拠です。

ビッグデータの深みとインタラクティブな視覚化の繊細さを結婚させるソリューションを探しているなら、これ以上探す必要はありません。PyGWalker-Snowflake統合は、データが単なる数字でなく、語られるべきインタラクティブな物語である未来を約束しています。

### 参考

- PyGWalker Snowflake API ドキュメント: [https://docs.kanaries.net/pygwalker/api-reference/snowflake](https://docs.kanaries.net/pygwalker/api-reference/snowflake)
- PyGWalker Github リポジトリ: [https://github

.com/Kanaries/pygwalker](https://github.com/Kanaries/pygwalker)
- Kanaries ウェブサイト: [https://kanaries.net/](https://kanaries.net/)
Gitの競合を解決する方法と、表示の読み解き方

# 競合の表示の読み方

例えば以下の様な競合の表示が出力されたとします。

```
<<<<<<< HEAD:.gitignore
=======
index copy.php
>>>>>>> ohana:.gitignore
hogehoge/hoge.php
<<<<<<< HEAD:.gitignore
=======
hogehoge/bara.php
>>>>>>> ohanachimain:.gitignore
hogehoge/kosumosu.php
<<<<<<< HEAD:.gitignore
hogehoge/bara.php
www/hogehoge/.htaccess
hogehoge/momiji
www/hogehoge/sumire.php
=======
hogehoge/kaede.php
>>>>>>> ohana:.gitignore
```

<<<<<<< HEAD:.gitignore から ======= までのセクションは、現在のブランチ（おそらく mainブランチ）の変更を表しています。

======= から >>>>>>> ohana:.gitignore までのセクションは、もう一方のブランチ（ohanaブランチ）の変更を表しています。

そのため、以下の様な表示が出た場合は

```
<<<<<<< HEAD:.gitignore
=======
index copy.php
>>>>>>> ohana:.gitignore
hogehoge/hoge.php
<<<<<<< HEAD:.gitignore
hogehoge/suisen.php
=======
hogehoge/bara.php
>>>>>>> ohanachimain:.gitignore
```

- HEAD:.gitignoreには無いindex copy.phpという行がohana:.gitignoreには存在している
- hogehoge/hoge.phpの行は両方のブランチに存在している
- HEAD:.gitignoreではhogehoge/suisen.phpになっている行がohana:.gitignoreではhogehoge/bara.phpになっている

という意味になります。

# 解決方法
競合を解決するには、どちらの変更を採用するか、または両方の変更を組み合わせて採用するかを決定していく必要があります。

競合のマーカー (<<<<<<<, =======, >>>>>>>) は不要なので削除して、残したいコードのみが表示される様にしていきます。

例えば以下の様になっていたら

```
<<<<<<< HEAD:.gitignore
=======
index copy.php
>>>>>>> ohana:.gitignore
```

mainブランチの.gitignoreには記載がないけれども、ohanaブランチの.gitignoreにはindex copy.phpと書いてあると書いてある

という意味になります。

.gitignoreにindex copy.phpという行を残したいなら、競合のマーカー (<<<<<<<, =======, >>>>>>>) を削除して、おけばOKです。
生成AIリテラシー教育読本(小学校高学年向け)

# 生成AIのきほん

## 生成AI（せいせいAI）って何？

生成AI（せいせいAI）は、コンピューターの特殊なプログラムで、人間のように文章や絵、音楽などを作ることができます。このプログラムはたくさんの情報を学ぶことで、新しいものを作り出せます。

例えば、「GPT-3」とか「DALL-E」という名前の生成AIは、人間と同じくらい、またはそれ以上に上手に文章や絵を作ることができます。

でも、生成AI（せいせいAI）は使い方によっては問題を起こすこともあるので、注意が必要です。たとえば、ウソの情報を広げたり、他人の作品をコピーしたりすることがあります。

## 生成AI（せいせいAI）の歴史と進化

生成AI（せいせいAI）は、コンピューター技術が進化するにつれて、どんどん賢くなってきました。最初はシンプルなルールに従うだけのプログラムだったけど、時間とともに、コンピューターはたくさんの情報を学ぶようになり、もっと複雑な仕事もできるようになりました。そして、最近では「GPT-3」や「DALL-E」という賢い生成AIが登場しました。

## 生成AI（せいせいAI）の影響

生成（せいせい）AIは、私たちの生活や学校、仕事にも影響を与えています。たとえば、報告書を自動で書いたり、個々の好みに合わせて絵や音楽を作ったり、先生が教材を簡単に作ったりできます。でも、生成（せいせい）AIを使うときは、ウソの情報が広がらないように、また他人の作品をコピーしないように注意が必要です。そして、コンピューターが人間の仕事を奪わないように、適切なルールや教育が必要です。


# 生成AI（せいせいAI）の問題点

生成AI（せいせいAI）はすごい技術ですが、問題点もあります。

1. **間違った情報を広める**：生成（せいせい）AIは本物そっくりの文章や画像を作ることができます。だから、偽のニュースや情報を広めることができてしまいます。
2. **著作権（ちょさくけん）に反する場合がある**：他人が作った作品をコピーしたり、似たようなものを作ったりすることがあります。これは著作権（ちょさくけん）を守るためのルールに反しています。
3. **倫理的（りんりてきな）な問題**：生成（せいせい）AIが人間のように考えたり感じたりするわけではありません。だから、人間が大切に思う価値観や感情を理解することはできません。

# 生成AI（せいせいAI）の未来

生成（せいせい）AIはまだ発展途中の技術です。これからどんな風に変わっていくかはわかりませんが、以下のような可能性が考えられます。

1. **より高度な生成能力**：生成（せいせい）AIはさらに進化して、より複雑でリアルなコンテンツを作ることができるようになるかもしれません。
2. **個々のニーズに合わせたサービス**：生成（せいせい）AIは個々の人の好みやニーズに合わせたサービスを提供することができるようになるかもしれません。
3. **新しい職業の出現**：生成（せいせい）AIを使って新しい仕事や職業が生まれる可能性もあります。

でも、これらの可能性を追求するときは、上で述べた問題点に注意しなければなりません。生成（せいせい）AIの未来は、私たち全員が一緒に考えていくべき課題です。
noUncheckedIndexedAccess を有効にする際は "strict": true も指定する

noUncheckedIndexedAccess を有効にしても配列アクセスでエラーにならなかったので、その現象が起きた際のメモです。

## "strict": true を指定する

たとえば、以下のコードでは長さが `2` しかない配列の添字に `5` を指定しているため `undefined` となり、その次の行で実行時エラーになってしまいますが、これを TypeScript のエラーとして検知したいわけです。

```typescript:Hello.tsx
const arr: string[] = ["foo", "bar"];
const item = arr[5];
console.log(item.toUpperCase());
```

このようなコードを書いた場合、 `"strict": true` が指定されていない場合、エラーが発生しません。

以下のように `"strict": true` を指定すると、`'xxxx' is possibly 'undefined'.` というエラーが発生するようになります。

```diff_json:tsconfig.json
 {
   "compilerOptions": {
     "noUncheckedIndexedAccess": true,
+    "strict": true,
     (中略)
   },
   "include": ["src/**/*"]
 }
```

```bash
src/Hello.tsx:31:15 - error TS18048: 'item' is possibly 'undefined'.

31   console.log(item.toUpperCase());
                 ~~~~
```

これは、"strict": true を指定すると `strictNullChecks` が ON になることによる効果かと思われます。

https://typescriptbook.jp/reference/tsconfig/strictnullchecks

皆さんも noUncheckedIndexedAccess を有効にする際は "strict": true が指定されているかどうかチェックするようにしてみてください。
Cloud Dataflowのクラシックテンプレートを作成する

# 前提
- classic template使うと、parameterを変えて使いまわせる
- API呼び出しなどが可能
- shiftjis_to_utf8 を使った

# テンプレート
https://cloud.google.com/dataflow/docs/concepts/dataflow-templates?hl=ja

# 実装

```py
import apache_beam as beam
from apache_beam.io import ReadFromText, WriteToText
from apache_beam.options.pipeline_options import PipelineOptions
from apache_beam.coders.coders import Coder


class ShiftJisCoder(Coder):
    def encode(self, value):
        return value.encode('shift_jis')

    def decode(self, value):
        return value.decode('shift_jis')

    def is_deterministic(self):
        return True


class CustomOptions(PipelineOptions):
    @classmethod
    def _add_argparse_args(cls, parser):
        parser.add_value_provider_argument(
            '--input',
            help='Path of the file to read from')
        parser.add_value_provider_argument(
            '--output',
            help='Output file to write results to.')


custom_options = CustomOptions()
pipeline_options = PipelineOptions(options=custom_options)
p = beam.Pipeline(options=pipeline_options)
lines: ReadFromText = p | 'Read' >> ReadFromText(
    custom_options.input, coder=ShiftJisCoder())
lines | 'Write' >> WriteToText(custom_options.output)
p.run()
```

template化

```sh

python -m shiftjis_to_utf8 \
    --runner DataflowRunner \
    --project YOUR_PROJECT \
    --staging_location gs://BUCKET/staging \
    --temp_location gs://BUCKET/tmp \
    --template_location gs://BUCKET/templates/shiftjis_to_utf8 \
    --region asia-northeast1

```

templateを使ったジョブの実行

```sh
gcloud dataflow jobs run test_template_job \
        --gcs-location gs://BUCKET/templates/shiftjis_to_utf8 \
        --parameters input=gs://BUCKET/input/some_file,output=gs://BUCKET/output/sample_result
```

# 参照
https://cloud.google.com/dataflow/docs/guides/templates/creating-templates

https://www.case-k.jp/entry/2019/10/13/182718
AWS EC2のAmazon Linuxに複数のJavaをインストールして切り替える方法

こんにちは。

定期的な記事投稿を目指して再開したQiita。やっぱり間が飽きがちですが、気を取り直して本日はAWS EC2環境の最新OSでJavaをインストールする方法についてご紹介します。

今回インストールするJavaはAWSが提供する無料のJavaランタイムで、複数のバージョンをインストールして切り替える方法についても合わせてご紹介します。

# STEP 0
ところでAWSのJavaランタイムって何？
この記事では、Amazon CorrettoのことをAWSのJavaランタイムと表現しました。

Amazon　Correttoについては本家サイトをご覧いただくのが一番早いですが、無料のOpen Java Development Ket（JDK）です。Amazonが社内の本番サービスに使用していてJava SE標準と互換性があるとのことで、導入しやすそうです。

本家サイトはこちら↓

https://aws.amazon.com/jp/corretto/?filtered-posts.sort-by=item.additionalFields.createdDate&filtered-posts.sort-order=desc

# STEP 1
JDKはDNFで導入しますので、まずはAmazon Linux 2023のDNFパッケージインデックスを最新にしましょう。

```
sudo dnf update
```

# STEP 2
続いてJDKをインストールしてゆきます。といっても１コマンドで簡単です。

### Java 8の場合
JRE
```
sudo dnf install java-1.9.0-amazon-corretto
```

JDK
```
sudo dnf install java-1.9.0-amazon-corretto-devel
```

### Java 11の場合
JRE
```
sudo dnf install java11-amazon-corretto
```
JDK
```
sudo dnf install java11-amazon-corretto-devel
```

### Java 17の場合
JRE
```
sudo dnf install java17-amazon-corretto
```
JDK
```
sudo dnf install java17-amazon-corretto-devel
```

### Java 21の場合
JRE
```
sudo dnf install java21-amazon-corretto
```
JDK
```
sudo dnf install java21-amazon-corretto-devel
```

インストールできたら次のコマンドでjavaのバージョン等を確認してみてください。

```
java -version
```

# STEP 3
Javaのバージョン切り替えは次のコマンドで行います。

```
sudo alternatives --config java
```

このコマンドを入力すると次のような感じで、選択を聞かれます。
お好きなJavaをSelection列の番号で回答します。

```
There are 2 programs which provide 'java'.

  Selection    Command
-----------------------------------------------
*+ 1           /usr/lib/jvm/java-21-amazon-corretto.x86_64/bin/java
   2           /usr/lib/jvm/java-11-amazon-corretto.x86_64/bin/java

Enter to keep the current selection[+], or type selection number: 2
```

以上です！
快適なJavaライフをお楽しみください。
FirebaseCloudMessage 同一プロジェクトで複数アプリを登録し webプッシュした時にはまったこと

1つのプロジェクトに複数アプリを登録できます。
マルチプラットフォームな場合のみに限らず、同じ構成のwebアプリが複数ある場合など。

今回はドメインの違う複数アプリを登録し、webプッシュしようとしました。

普通は別ドメインの複数webアプリ登録ってしないんだろうか。でも30個しかプロジェクト作れないし。


## コンソールに表示されたエラー ##
後からかこうとするとどうやって解決したか忘れてるのでうろ覚え…

### An error occurred while retrieving token. DOMException: Failed to execute 'subscribe' on 'PushManager': Subscription failed - no active Service Worker ###
firebase-messaging-sw.jsの存在と中身を確認。firebase系importとfirebase.initializeApp(アプリ毎の設定)、messaging.setBackgroundMessageHandlerが必要になると思います。
<br>

### Uncaught (in promise) DOMException: Registration failed - missing applicationServerKey, and manifest empty or missing ###
最初のアプリでmanifest.jsonのlinkタグ入れなくても動いた気がするけど気のせい…？とりあえずhtmlに```<link rel="manifest" href="manifest.json">```的なのを入れましょう。
またmanifest.jsonの中身は下記の感じで、固定数字っぽいです。(調べたらsenderid入れるみたいなのも見たけど、固定派が多かった。公式ページのどこに書いてあるか探せなかった…)
``` manifest.json
{
  "gcm_sender_id": "103953800507"
}
```
<br>

### Registration failed - A subscription with a different applicationServerKey (or gcm_sender_id) already exists; ###

これがはまってしまいました。applicationServerKeyってなんなのか。何をkeyにしているのか。。

pushManager.subscribeの第二引数を入れて解決しました。
``` fcm.js
navigator.serviceWorker.ready
    .then((registration) => {
        return registration.pushManager.subscribe({userVisibleOnly: true, applicationServerKey: myVapidKey});
    })
```
myVapidKeyにはアプリごとのウェブプッシュ証明書の公開鍵が入っています。
firebaseのウェブの構成→ウェブプッシュ証明書の鍵をアプリごとに作る。
アプリごとに公開鍵をvapidKeyとして使う。


これでとりあえずうごきました。合っているのかわからないけど…
【Google Cloud】サービスアカウント周りのIAMロール

## はじめに
Google Cloudのサービスアカウントキーを取得するため必要十分なIAMロールを知りたかったので、公式ドキュメントをもとに調査した

結論から言えば<roles/iam.serviceAccountAdmin>があれば事足りはするが余剰な権限も含まれている。

#### 用語の整理
IAM権限：Permissions。アクセス権における最小単位（例：iam.serviceAccounts.create）
IAMロール：Permissionsの集まり。Google Cloud側で管理される事前定義ロールとユーザー側で管理するカスタムロールの２種類がある。



## サービスアカウントに関する権限一覧
Google Cloudのサービスアカウント周りの事前定義ロールには下記のものがある。


roles/iam.serviceAccountAdmin : サービスアカウントの作成・管理

roles/iam.serviceAccountCreator : サービスアカウントの作成

roles/iam.serviceAccountDeleter : サービスアカウントの削除

roles/iam.serviceAccountKeyAdmin : サービスアカウントキーの作成・管理・ローテーション

roles/iam.serviceAccountOpenIdTokenCreator : OIDCトークンの作成

roles/iam.serviceAccountTokenCreator : サービスアカウントを借用する

roles/iam.serviceAccountUser : サービスアカウントとして操作を実行する

roles/iam.serviceAccountViewer : サービスアカウント、キーの読み取りアクセス

roles/iam.workloadIdentityUser : フェデレーションにおけるサービスアカウントの借用

参考：https://cloud.google.com/iam/docs/understanding-roles#iam.serviceAccountAdmin

## roles/iam.serviceAccountViewerロールではキーのダウンロード不可！
上記の感じだと、roles/iam.serviceAccountViewerロールで既存のキーの読み取りでキーを取得できるかなと思っていたが、できず。そもそも、キーファイルのダウンロードはキー作成時にしかできないみたい。
なので、キーファイルのダウンロードを行うためには必然的にキーを作成する権限が必要そう。

## roles/iam.serviceAccountKeyAdminロールでキーのダウンロード可能
roles/iam.serviceAccountKeyAdminに変更して再度実行してみた。
![スクリーンショット 2023-10-24 11.56.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3580229/e763a399-d200-4b73-413f-0016a43e25fb.png)
無事キーの作成とダウンロードができた。

## おわりに
開発環境でサービスアカウントキーを取得する必要がある場合などは上記のロール付与で対応できそう。本番環境ではカスタムロールを使用して余剰権限をなくす必要がある。
そもそも、サービスアカウントを使用してのアクセス自体Google Cloudがあまりおすすめしていないので他のアクセス方法についても学びたい。
從台灣出國留學：追尋國際發展之路


在這個全球化的時代，越來越多的台灣學生夢想著能夠走出國門，到國際學校深造。然而，這一個跨足國界的冒險並非一帆風順，它需要準備充分，其中一個關鍵因素就是SAT考試。本文將帶您一探從台灣出國留學的過程，特別聚焦在應對SAT考試和美國簽證的重要步驟。

1. SAT：邁向美國大學的第一步

當談到從台灣出國留學時，SAT（Scholastic Assessment Test）往往是學生們的首要考慮。SAT是美國大學入學申請的重要組成部分，它評估學生的閱讀、寫作和數學能力。準備SAT考試需要時間和耐心，通常包括參加培訓課程、閱讀考試指南，以及練習模擬試卷。這一階段的努力是為了確保獲得令人滿意的分數，進一步提高進入美國大學的機會。

2. [美國簽證](https://www.apexcharity.org/news/3/94)：關鍵的通行證

獲得[SAT](https://www.apexcharity.org/news/3/84)考試的高分後，下一步是申請美國簽證。台灣學生通常需要申請F-1學生簽證，這個過程需要仔細的規劃和文件準備。學生需要提供入學許可證明、財力證明以及簽證申請表格等文件，並參加面試。獲得F-1簽證後，就可以合法入境美國，開始新的學業生活。

3. [出國留學](https://www.apexcharity.org/news/3/83)：挑戰和機會同在

一旦獲得美國簽證，台灣學生將迎來新的生活挑戰和機會。他們將融入不同文化和教育體制，學習更多國際視野下的知識，並建立全球性的人際關係。[國際學校](https://www.apexcharity.org/news/3/82)提供了一個多元化的學習環境，讓學生能夠培養跨文化溝通和國際合作的能力。

在結論中，從台灣出國留學是一個具有挑戰性但充滿機會的決定。這需要學生付出艱苦努力，包括應對SAT考試和成功申請美國簽證。然而，這一過程將為他們帶來無限的成長和學習機會，幫助他們實現更廣泛的夢想和目標。無論前路如何，這將是一個難忘的冒險，將改變他們的一生。
定時帰る術-Linux cron管理（crondのデフォルト動作流れ）

cronのデフォルト動作がネット上にもあまりないから、毎回調べるのが定時に変えられないので、世の中の残業がなくなるように、川口の調査流れを共有することにした。（間違ったらごめんなさい）



* サービス管理：systemdに管理されているため、systemctl系のコマンドが実行できる。status/start/stop/restart等々
* サービスログ格納先：/var/log/cron
↑がrsyslogより管理されている、/etc/rsyslog.confで確認/変更できる
```
cat /etc/rsyslog.conf
# Log cron stuff
cron.*                                                  /var/log/cron
```

* 定義ファイル：   
* システム用
/etc/anacrontab：デフォルトのログローテーション
/etc/crontab：デフォルトの場合は、何も設定されていない
* ユーザ別
/etc/cron.d：ジョブ格納場所
/var/spool/cron：cron定義ファイルの格納場所

* よく使うコマンド
crontab -e : ログインしているユーザのcronを変更
（viと同じ感覚で編集できるのが、ありがたい）
crontab -u snow -l ：ユーザSnowのcrontabを表示
crontab -ir：ログインしているユーザのcronを全部削除
(**川口的には、↑は危ないと思って、定時に帰りたいなら、覚えなくてもいいだろう**)

* デフォルト動作
①enabledされているため、crondが起動され、/etc/rsyslog.confのcron.*   /var/log/cronより、/var/log/cronにログをはく
②/etc/cron.d配下を探して、毎時1分ごとに↓2ファイルを実行する。
```
[root@test ~]# ls /etc/cron.d/
0hourly  raid-check
```
③/etc/cron.d/0hourlyより、毎時1分ごとに/etc/cron.hourlyをrun-partsする。（run-parts：ディレクトリ配下に格納されてるジョブ全部実行する）
```
[root@test ~]# ls /etc/cron.hourly
0anacron
```
④/etc/cron.hourly/0anacronの中、/usr/sbin/anacron -sでanacronを実行する。
⑤④で実行したanacronを/etc/anacrontabをみて、↓をrun-partsする。
/etc/cron.daily
/etc/cron.weekly
/etc/cron.monthly
```
[root@test ~]# ls /etc/cron.daily/ /etc/cron.weekly/ /etc/cron.monthly/
/etc/cron.daily/:
logrotate

/etc/cron.monthly/:

/etc/cron.weekly/:
```
⑥⑤でrun-partsされた /etc/cron.daily/logrotateは、/usr/sbin/logrotate /etc/logrotate.confで、/etc/logrotate.dをローテーションする。

・anacronのデメリット
①anacronにて、遅延時間があり、想定時間にジョブが実行されない場合がある
②1日単位でしか指定できない
↑によって、cronを使うことが多い

やり方的にも単純：
①「/etc/anacrontab」に記載されている内容をコメントアウトする。 
②必要な内容だけを/etc/crontabに転記する。
（cronとanacronの書き方が全然違うため、要注意。）
（具体的な書き方はgoogleに聞いてみればと思って、いろいろな例をコピペで持ってくるのは面倒くさいから、やりません）
（**面倒くさいことは一切やりません。**）
・cronのメリット
①指定時間に実行できる。
②分単位で設定できる。
JavaのSingleton

- **一つのJVM、Javaサーバーの中でオブジェクト(インスタンス)が1つだけ生成され、共有するように設計するデザインパターンである。**
- **オブジェクトを2つ以上生成できないようにprivate生成者を使用し、外部で任意にnewキーワードを使用できないように防ぐ。**

<br>
< Singleton を使用する理由 >

- ほとんどのSpringアプリケーションはWebアプリケーションで、通常、複数の顧客が同時にリクエストを行う。
- 顧客が要請するたびにオブジェクトを作らなければならないが、そうするとメモリの浪費が激しい。

1. Singleton パターンでない場合
    - 呼び出すたびに新しいオブジェクトを生成する。
    ```jsx
    package hello.hellospring;
    
    import hello.hellospring.member.MemberService;
    import hello.hellospring.member.MemberServiceImpl;
    import org.assertj.core.api.Assertions;
    import org.junit.jupiter.api.Test;
    
    public class SingleToneTest {
    
        @Test
        void notSingleTone() {
            AppConfig appConfig = new AppConfig();
    
            // 呼び出すたびに新しいオブジェクトを生成する。
            MemberService memberService1 = appConfig.memberService();
            MemberService memberService2 = appConfig.memberService();
            System.out.println(memberService1);
            System.out.println(memberService2);
            Assertions.assertThat(memberService1).isNotSameAs(memberService2);
        }
    }
    ```


2. Singleton パターンの場合
    - オブジェクトが**1つだけ生成され、それを共有する。**
    - メモリの無駄を省くことになる。
    - 以下の例の他にもSingletonパターンを具現する方法は色々ある。
        ```jsx
        package hello.hellospring.singletone;
        
        public class SingletoneService {
        
            // 1。 static領域にオブジェクトを1つだけ生成しておく。
            private static final SingletoneService instance = new SingletoneService();
        
            //2。 publicで作成し、オブジェクトインスタンスが必要な場合、このstaticメソッドを通じてのみ照会することができる。
            public static SingletoneService getInstance() {
                return instance;
            }
        
            // 3。 生成者をprivateと宣言し、外部からnewキーワードを使ってオブジェクト生成をすることを防ぐ。
            private SingletoneService() {
        
            }
        }
        ```
        ```jsx
        package hello.hellospring;
        
        import hello.hellospring.singletone.SingletoneService;
        import org.assertj.core.api.Assertions;
        import org.junit.jupiter.api.Test;
        
        public class SingleToneTest {
        
            @Test
            void singleToneTest() {
                SingletoneService singletoneService1 = SingletoneService.getInstance();
                System.out.println(singletoneService1);
                SingletoneService singletoneService2 = SingletoneService.getInstance();
                System.out.println(singletoneService2);
                Assertions.assertThat(singletoneService1).isSameAs(singletoneService2);
            }
        }
        ```
ヤマハルーター NVR700Wで APNを簡単切り替え

ヤマハのNVR700Wを利用して提供元が異なるSIMを利用するので、APNを簡単に切り替えたいという話があり、コード化してみました。

### マクロ
引数 部分は順番に APN, ユーザID, パスワード です。
この部分の設定を上書きします。
```
macro change_apn <<EOM
  disconnect wan1
  wwan select 1
  wwan auth myname $2 $3
  wwan access-point name $1
  save
EOM
```

### トグル切り替え
今回は2個の切り替えだったので、順番に入れ替わればいいかな、と。
ダミーデータとして、DOCOMO(Mopera),AU(5G)の設定を入れています。
```
embedded file switch_apn.lua <<EOF
  ret, apn = rt.command("show config wwan 1 | grep access-point")
  if string.match(apn, /\S+$/) == "mopera.net" then
    rt.command("@change_apn uad5gn.au-net.ne.jp au@uad5gn.au-net.ne.jp au")
  else
    rt.command("@change_apn mopera.net mopera mopera")
  end
EOF
```

### トリガー
アナログですが、Download ボタンで切り替えを実行するようにしました。

```
operation button function download execute lua emfs:/switch_apn.lua
```

---

### 参考
[YAMAHA (RTPRO): マクロの設定](http://www.rtpro.yamaha.co.jp/RT/manual/rt-common/setup/macro.html)
[YAMAHA (RTPRO): Lua スクリプト機能](http://www.rtpro.yamaha.co.jp/RT/docs/lua/)
[YAMAHA (RTPRO): EMFS](http://www.rtpro.yamaha.co.jp/RT/docs/emfs/index.html)
DockerでGradioアプリを作ってデプロイするだけでしんどかった件~JSONエラーと422エラー~

# 最初に

今回は表題の通り、DockerでGradioアプリを作った際、詰まったことについて記載します。
エラー内容は以下の二つです。
- 422 (Unprocessable Content)
- Unexpected end of JSON input

両方ともローカルで実行している時には再現しませんでした。
ホスティング先でのみ再現します。

# 422 (Unprocessable Content)
pydanticのバージョンを固定します。
pydantic==1.10.11

Issueに情報が転がってました。

https://github.com/gradio-app/gradio/issues/4591

# Unexpected end of JSON input
## FastAPIでラッピングしちゃう(推奨)

```
io = gr.Interface(title="テキストとファイルの入力",description="テキストとファイルを入力して処理を実行します。",
    inputs=[
        gr.inputs.Textbox(label="APIキー"),
        gr.inputs.File(label="動画ファイル"),
        gr.inputs.Dropdown(label="モデル",choices=models),
    ],
    outputs=[
        gr.outputs.Textbox(label="文字起こしデータ"),
        gr.outputs.Textbox(label="議事録データ"),
    ],
    fn=excute,
    )
        
app = FastAPI()
app = gr.mount_gradio_app(app, io,path="/")
```
参考

https://qiita.com/misohagi/items/caf7f9878421cdd89253


## 解決しなかったShare=True
IssueにはLanchのプロパティにShere=Trueを指定することで解決するとありましたが、解決に至りませんでした。

https://github.com/gradio-app/gradio/issues/4591



# 終わり
デバッグをしている時にGradioはReactかNextのコードを自動生成して、
コードをフロントとバックに分けてるっぽいことに気づきました。
ホスティング先では、その繋ぎ目で問題が発生していました(根本原因は不明、デバッガ上の話)。

Gradioでタイトルは異なりますが、同じような困り事はたくさんあるようで、
今回は遊びのツールでしたが、仕事で使うのはきびしいなぁと感じました。
[Super convenient] Web Chart Function with One Tag

# Background
There are many chart functions used on the web such as google chart and chart.js. However, you cannot use it unless you are familiar with JavaScript. There may be people who think the hurdles are high due to individual differences.

When using an Excel chart, you can create a chart by simply selecting a data table and selecting the graph type. I think it would be great if there was a way to do this on the web. See the jsp example below.
# Example
Even though it's JSP, it's mostly HTML. Only 4 lines are related to java.
```jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="efw" uri="efw" %>
<!DOCTYPE HTML>
<HTML>
<HEAD>
	<title>chart テスト</title>
	<efw:Client lang="jp"/>
</HEAD>
<BODY>
<table>
<tr><td>
<!--ここはデータ表-->
	<table border=1 id="chart1_data" data-format="$#,##0" data-legend="bottom">
		<caption>Chart Caption</caption>
		<tr><th>Row0Col0</th><th>col1</th><th>col2</th><th>col3</th></tr>
		<tr><td>row1</td><td>$1,000</td><td>$700</td><td>$300</td></tr>
		<tr><td>row2</td><td>$900</td><td>$700</td><td>$600</td></tr>
		<tr><td>row3</td><td>$800</td><td>$600</td><td>$500</td></tr>
		<tr><td>row4</td><td>$700</td><td>$500</td><td>$400</td></tr>
		<tr><td>row5</td><td>$1,000</td><td>$800</td><td>$700</td></tr>
	</table>
</td><td>
<!--ここは縦棒グラフ-->
	<efw:Chart id="char1" data="chart1_data" type="column"/>
</td></tr></table>
</BODY>
</HTML>
```
This 4-line java program will display a google chart as shown in the evidence below. Isn't it easy? Isn't the color matching similar to Excel?
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/2d77db8c-58a7-b710-4dfb-da953501f0b4.png)
# Get Jar
It can be downloaded from maven.
```xml
<dependency>
    <groupId>io.github.efwgrp</groupId>
    <artifactId>efw</artifactId>
    <version>4.07.000</version>
</dependency>
```
# efw Chart tag
How to use the above explanation is efw's Chart tag. Although complex charts cannot be created, commonly used Excel-like charts can be created with a single tag. For detailed API information, see the link below.
https://github.com/efwGrp/efw4.X/blob/master/help/tag.chart.md
Chart type, data settings, title, legend, scale, format, etc. The functions that can be realized can be seen from the diagram below.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3476221/ce450baf-68bc-fc04-9a7d-5cebe09eda65.png)
Also, since Google Chart cannot be used when you are not online, we have also included chart.js, which can be used offline. Switch by mode.

Please try it if you are interested. The above evidence program can be downloaded from the link below.

https://github.com/efwGrp/qittaSamples
Spring Container

- 従来は開発者がAppConfigを使用して直接オブジェクトを生成し依存性を注入していましたが、これからは**SpringContainer**を使う。
- 一般的に**ApplicationContext**(インターフェース、多形性が適用される)をSpringContainerという。
    - BeanFactoryもあるが、直接使用する場合はほとんどないためだ。
- XML ベースまたは**Annotation ベースのJava設定クラス**、Groovy など、さまざまな形式の設定情報が受け入れられるよう柔軟に立つようになっている。
 ![스크린샷 2023-09-10 19.02.08 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3567846/c86a1cbc-1b38-6554-2566-38ec077600b5.png)

最近では、A**notationベースのJava設定クラスを活用した方法を多く使用し、その他多く使用される方法としてはXMLを使用した方法がある。**


< XML を使って作成 >

- レガシープロジェクトがXMLになっている場合も多く、コンパイルなしでBean設定情報を変更できるメリットもあるので、学んでおくとよい。
- Generic Xml Application Contextを使用しながら、xml設定ファイルをめくるとよい。

appConfig.xml
```
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="memberService" class="hello.hellospring.member.MemberServiceImpl">
        <constructor-arg name="memberRepository" ref="memberRepository"/>
    </bean>

    <bean id="memberRepository" class="hello.hellospring.member.MemoryMemberRepository">
    </bean>

    <bean id="orderService" class="order.OrderServiceImpl">
        <constructor-arg name="memberRepository" ref="memberRepository"></constructor-arg>
        <constructor-arg name="disCountPolicy" ref="discountPolicy"></constructor-arg>
    </bean>

    <bean id="discountPolicy" class="discount.RateDiscountPolicy">
    </bean>


</beans>
```
```jsx
package hello.hellospring;


import hello.hellospring.member.MemberService;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class XmlApplicationContextTest {

    @Test
    void test1() {
        ApplicationContext ac = new GenericXmlApplicationContext("appConfig.xml");
        MemberService memberService = ac.getBean("memberService", MemberService.class);
        Assertions.assertThat(memberService).isInstanceOf(MemberService.class);
    }
}
```
console.log() の代わりにdevtoolsのLogpointsを使う

# Logpointsを使おう

Webフロントエンドの開発をする際、デバッグ目的で「特定の処理が実行された」ということを確認するために `console.log()` を使うことは多いと思います。しかし、Google Chrome や Microsoft Edge で利用可能な [Logpoints](https://developer.chrome.com/docs/devtools/javascript/breakpoints/#log-loc) を利用することで、 `console.log()` を使わずともコンソールにメッセージを出力することが可能です。

# なぜLogpointsを使うの？

Logpoints を使うのには以下のメリットがあります。

- デバッグや動作確認のためにコードを変更する必要が無い
- `console.log()` を誤ってcommitに含めてしまう心配が無い
- `console.log()` を入れた後に再ビルドやホットリロードを待つ必要が無い

# どうやってLogpointsを使うの？

logpoints は以下のように使用します。

1. Chrome (または Edge) で devtools を開きます

1. `Sources` タブを選択します

1. ログを出力したいファイルを開きます。なお、ファイルを開く時は [Command menu](https://developer.chrome.com/docs/devtools/command-menu/#open-files) を使うと便利です

1. ログを出力したい箇所の行番号で右クリックして、 `Add logpoint...` を選択します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12152/37cb168e-23e1-d8d2-7c19-adff9f5b7ae9.png)

1. 出力するメッセージや変数などをLogpointのフィールドに入力します。複数の値を渡す場合はカンマで区切ります。 (`console.log()` のパラメータに指定する値をそのまま入力するイメージです)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12152/762cdf3c-8746-b914-09f6-e5a2c9a20e16.png)

これで準備が完了です。Logpoints が設定された箇所のコードが実行されると、コンソールにメッセージが出力されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12152/66c585cd-7a74-19bc-3021-6bac07c88157.png)
Java の SuppressWarnings の種類を列挙した

### SuppressWarnings アノテーションとは
Java の SuppressWarningsアノテーションは、コンパイラに警告を抑制するよう指示するために使用されます。

### 種類

以下は、SuppressWarningsアノテーションで使用可能な値の一部です。
動作確認は各自でお願いします。

#### “all” 
すべての警告を抑制します。

#### “boxing”
ボクシング変換に関する警告を抑制します。

#### “cast”
キャストに関する警告を抑制します。

#### “dep-ann”
使用されている非推奨のAPIに関する警告を抑制します。

#### “deprecation”
非推奨のAPIに関する警告を抑制します。

#### “fallthrough”
switch文でのfallthroughに関する警告を抑制します。

#### “finally”
finallyブロックが正常に終了しなかった場合に関する警告を抑制します。

#### “hiding”
変数隠蔽に関する警告を抑制します。

#### “incomplete-switch”
switch文でcaseが不足している場合に関する警告を抑制します。

#### “javadoc”
Javadocコメントが不完全または不正確な場合に関する警告を抑制します。

#### “nls”
非ネイティブ文字列リテラルに関する警告を抑制します。

#### “null”
nullチェックに関する警告を抑制します。

#### “rawtypes”
型安全性が保証されていないジェネリック型の使用に関する警告を抑制します。

#### “resource”
リソースが正しく閉じられていない場合に関する警告を抑制します。

#### “restriction”
制限付きAPIの使用に関する警告を抑制します。

#### “serial”
シリアルバージョンUIDが定義されていない場合に関する警告を抑制します。

#### “static-access”
静的フィールドまたはメソッドへのアクセスに関する警告を抑制します。

#### “synthetic-access”
合成アクセサーへのアクセスに関する警告を抑制します。

#### “unchecked”
ジェネリック型のキャストまたはインスタンス化に関連する警告を抑制します。

#### “unqualified-field-access”
未修飾フィールドへのアクセスに関連する警告を抑制します。

#### “unused”
使用されていないコード要素（変数、メソッド、フィールド）に関連する警告を抑制します。
【悲報】エンジニア、気がついたらExcelばかり触っていた


オフィスに到着し、メールのチェックを行う。

Excelで作られたWBSとスケジュールを見て、進捗を確認。会議の準備をする。

会議の議事録を取るためにExcelを開く

それを元にExcelで仕様書を作成する。

WBSを更新していく。

客先との認識すり合わせはExcelファイルで作成されたQAシートをもとに行われる。

仕様が固まったら、Excelで要件定義書を作成していく。

その後Excelで画面設計書とDB設計書を作成する。

Excelファイルに作成手順をまとめ、開発作業の一部を発注する。

どこの会社にどんな内容を発注したのかをExcelファイルにまとめる。

発注先から届いたExcel形式のQAシートに解答を入力する。

客先との定例会でまた議事録を取りWBSを更新する。

プログラムが納品されたら、テスト仕様書をExcelテンプレートに則って作成していく。

テスト結果を受け取りExcelにまとめる。

Excelで作られた納品書に納品物の詳細を入力していく。

客先に納品を終えると、Excelで作成された管理表に納品済みの処理記載をする。

Excelを開いてばかりである。

# andmore

他にもこんな記事書いてます。

https://qiita.com/SZR/items/8524fe3a22a2faa47b7a

https://qiita.com/SZR/items/3e3a02e6c316438fe5a3

https://qiita.com/SZR/items/1c8a7be4267071f6c295

https://qiita.com/SZR/items/dce75a3d08c5170d4365

https://qiita.com/SZR/items/396533c1b1e14489a782

https://qiita.com/SZR/items/f46822b009fa47e1ca53

https://qiita.com/SZR/items/401a1f839723d89bd7f2

https://qiita.com/SZR/items/176586cde17ea0e9828a

https://qiita.com/SZR/items/a000cbaa583dcd2a344b

https://qiita.com/SZR/items/1d8edaf95fa2f5bbe821

https://qiita.com/SZR/items/1debe21a6759d0067ad7
Workato×Slackで爆速アポ調整！アプリ開発事例

## はじめに
当社のグループ会社に、人材派遣を行っている会社があります。
（以降、S社と表記します）
S社の業務の一つに、問い合わせのあったお客様に対してアポイント依頼と日程調整を兼ねたメールを送付する といった業務があります。
その一連の業務について、Workato×Slackで効率化を実現したのでご紹介します。

「顧客接点のチャネルが多岐にわたり情報が散在…漏れなく対応したい」
「営業担当のスケジュール確認に手間取っている」
「業務スピードを上げたい」

営業活動について日々このような思いを抱えている方は、参考にしてみてください。

## S社のアポ調整の流れ
お問い合わせ発生から打ち合わせまでは、４つの工程に分けられます。

＜Step1＞ LPサイトに訪問されたお客様が、ご相談フォームに会社名／氏名／求める人材等の情報を入力して送信

＜Step2＞ Slackのチャンネルに内容が転送される

＜Step3＞ 新着の問い合わせが届くと、**窓口担当**がお客様に宛てて日程調整メールを送信

＜Step4＞ お客様と何度かメールをやり取りし、打ち合わせの日程が確定すると**営業担当**にパスして打ち合わせへ

![全体フロー.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3570108/bce53603-cdf1-8b6d-6f23-c6891f1b688a.jpeg)

全体の流れは至ってシンプルですが、＜Step3＞の「**窓口担当**がお客様に宛てて日程調整メールを送信する」作業は、細かい工程を必要とします。

## S社の日程調整メールの特徴
窓口担当は、まず問い合わせを受けたら、過去に取引があるお客様かを確認します。
担当付きなら引き続き営業担当者に任せますが、新規顧客の場合は直近の予定に空きがある営業部員が担当になり得ます。

**営業担当がいる場合**
![営業担当がいる場合.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3570108/dce74da4-c847-dd2f-5c9e-88e3ea51b5f2.jpeg)

**営業担当がいない場合**
![営業担当がいない場合.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3570108/c1443527-0fe3-6277-2a35-8e31af85061e.jpeg)


さらに、それぞれのパターンでメールの文面も変えます。

![メールの文面の違い.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3570108/e8395f0e-c091-cbbd-11b9-fd4b6c82d3c9.jpeg)

効率だけを重視するなら、調整さんのようなアプリから発行される一律のリンクをメールに貼り付ければ、簡単に日程調整できる時代です。
しかし、S社ではお問い合わせをしてきたお客様に対して、ばら撒き感のない丁寧なメールを送りたいという考えがあり、逐一営業担当のスケジュールをチェックし候補日程を提示しています。

## 課題
これらを担っていた窓口担当の作業は大変でした。
・kintoneで顧客検索
・Googleスプレッドシートで問い合わせに応じたメール文面作成
・Googleカレンダーで営業部員の予定チェック
・Gmailでメール送信

各アプリケーションを行き来しなければならないですし、
複数名のスケジュールを確認する手間が発生しており、
**高い業務負荷**と**リードタイムの長期化**の課題がありました。

## Workatoで解決
ソリューションとして、Slackアプリを開発することにしました。

理由は、S社はコミュニケーションにSlackを使っており、慣れ親しんだSlack上の操作だけで業務を完結できれば、手軽で効果を感じやすいと思ったからです。

また、WorkatoではTeamsやSlackといったコミュニケーションツール上で動くbotの開発基盤が充実しているので、開発しやすいこともポイントでした。

## 作ったのはこんなアプリ
大きく分けて、２つの機能を実装しました。

**自動でデータベース検索機能**
特定のチャンネルにて、指定キーワードが含まれる新着メッセージをきっかけに、
顧客データベースの検索結果が表示されます。
![自動で検索機能.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3570108/f57b5a38-c901-2ed8-aa88-347f1c05ec32.jpeg)

**メール送信機能**
ボタンクリック＆フォーム操作だけで担当者の空き予定から日程を選べて、問い合わせのあった顧客にアポ調整のメールを送信できます。
![メール送信機能.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3570108/1cd382a5-8f3c-0be2-9cab-6a3a05053c1f.jpeg)



## 導入効果
**①リードタイム50%減**
問い合わせを受信して日程調整メールを送信するまで1件あたり6分ほどかかっていたのが、3分に短縮されました。

**②業務負荷の軽減**
複数のアプリケーションにアクセスしに行かずとも、Slackだけで業務が完結できるので
窓口担当の業務負荷が軽減されました。

**③メール誤字・誤送信解消**
手作業のオペレーションで発生しがちだった、お客様情報の転記ミスが発生しにくくなり、
メールの誤字や誤送信の解消に繋がりました。

**④マニュアルが不要になり引継ぎも楽に**
workbotによるガイダンスで業務が行えることによって業務の難易度が下がったので、業務担当者の交代時にも引継ぎがしやすくなりました。

また、こういう使い方もできるのでは？というアイディアとなりますが
窓口担当／営業担当と役割を分けず、営業担当が自分で日程調整する場合にもこのアプリを使えます。
営業担当が外出先でスマホから操作できるので、どこにいてもスピード感をもって顧客対応ができます。

## 終わりに
今回はSlack、kintone、Googleカレンダー、GoogleSheets、Gmailを連携しました。
Workatoはこの他にも様々なアプリケーションと連携できるので、夢が広がりますね。

同じような業務をしていて、もっと営業活動を効率化したいなと感じている方へのヒントになれば嬉しいです。

以下の記事で、実際にWorkatoの画面をお見せしながら、レシピの作成を紹介しています。
[・Workatoを使ってGmailで受信したメールをGoogle Sheetsに自動記載するレシピを作成](https://bstyle-value-technologies.blogspot.com/2024/07/workato-gsuite.html)
【経験談】４年目ウェブエンジニアの失敗と教訓

エンジニアやってて失敗したこととその教訓を記します。

私について

- IT企業新卒入社４年目
- ウェブサービスの開発エンジニア
- 大学院でNLPを研究
- Python歴６年、Java歴４年

# Singleton
とあるプロジェクトでスレッドセーフでないものをリリースしてしまいました。リクエストAの処理中、それとは別のリクエストBに対するAPIのレスポンスが変数に格納されていることに気づきました。その後理由はシングルトンなデザインパターンになっていなかったからだと判明しました。単に機能要件を満たすだけではなく、大規模アプリケーションにおいては、エンジニアとして常にスレッドセーフであることを意識しながらコーディングするきっかけになりました。


# NullPointerException
これはどのエンジニアも一度は経験することだと思います。とあるプロジェクトのリリース後、`NullPointerException`が頻発していることに気づきました。理由はAPIのレスポンスがnullであったのにも関わらず値をとりにいこうとしたからです。本来、APIがnullを返すような仕様はないと思っていましたが、とあるまれな条件を満たすとAPIのレスポンスがnullになる仕様であったためです。これは仕様管理者もリリース前には気づきませんでした。このようなケースは今後もあるはずなので、保険も兼ねて、APIのレスポンスがどのようなAPIレスポンスが返ってきても問題ないよう、エンジニアとして`null`チェックは必ず入れましょう。


# 依頼主との擦り合わせ
とあるプロジェクトでリダイレクト設定の依頼がありました。リクエストURLが`https://xxxx/yyyy/`の場合どこどこへリダイレクトさせたいという内容でした。私は本番環境のApacheに変更を加え、`https://xxxx/yyyy/`というリクエストが来た場合、指定された場所へリダイレクトすることを無事確認しました。それから３日後のこと、依頼主から連絡がありました。内容は`https://xxxx/yyyy/`は確かにリダイレクトされるが、`https://xxxx/yyyy/zzzz`のようなケースはリダイレクトさせないでほしいとのことでした。私はてっきり`https://xxxx/yyyy/zzzz`も要件に入っているものだと勘違いしておりました。要件の詳細な定義が抜けていました。事前に考えられるだけパターンを用意して、このケースはリダイレクトさせる・させないといった認識の擦り合わせをするべきでした。教訓としては、依頼主と仕様の擦り合わせをする際に、依頼主側のプロジェクト背景まで聞いておくとこのようなミスを防げると思いました。
SSL証明書

[まとめページに戻る](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)
[まとめN～Z](https://qiita.com/Keiji_otsubo/items/92f92bb9f668ca9688be)




+ [SSL証明書失効について](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007O2Snw)

:::note
Salesforce 組織の 1 つ以上の証明書の有効期限が近づいています　というメールが届いていませんか？
もしそうであれば、以下が参考になると思います。

https://help.salesforce.com/s/articleView?id=000385781&type=1

https://nebulaconsulting.co.uk/insights/how-to-renew-an-expiring-salesforce-certificate/
:::

+ [Trailblazer Communityが表示できない](https://qiita.com/Keiji_otsubo/items/4c0f31701719b55e13f1)


# SSL証明書のルート証明書

+ [SSL証明書のルート証明書について](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX000000lLYb)

 2024年10月21日現在、ap44.salesforce.comの SSL 証明書のルート証明書は [DigiCert Global Root CA] であることを確認しました。ただし、Mozilla は2025 年からこのルート証明書を段階的に「信頼できない」ものとして扱う予定であると理解しています。Salesforce は、今後 1 ～ 2 年以内にこのルート証明書を変更する予定はありますか? ルート証明書を変更する予定がある場合、どのルート証明書が使用されるかについて事前に発表はありますか? 

 :::note
 お問い合わせいただきありがとうございます。幸い、 https://knowledge.digicert.com/general-information/digicert-root-and-intermediate-ca-certificate-updates-2023に記載されているように、Mozilla では DigiCert Global Root CA 証明書の信頼解除は 2026-04-15 まで予定されていません。Salesforceは、それよりかなり前に新しいルート証明書に移行する必要があり、その前に証明書変更グループや、おそらくこのグループなどの他のグループに移行を発表する予定です。

現時点では、DigiCert Global Root CA ルート証明書は引き続き Mozilla によって Web サイトの使用に信頼されていますが、ご存知のとおり、2026 年 4 月 15 日に変更される予定です。
:::
ユーザーの最終ログイン時間を調べる

◆ケース
・ユーザーからメールのCcに不要なメンバーが含まれているとの削除依頼が来る場合
・本当に削除してよいか確認するケース

sys_userのリストを見て、「最終ログイン時刻」フィールドに日付が入力された列を見る。
最終ログインが古いユーザーであることやActive＝True/Falseを確認する。

![find_real_file.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190712/72e7b002-9f5d-d043-78a6-369ab2301e9f.png)
react ダイアログ

```react
import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import MyTableDialog from './MyTableDialog';

const ParentComponent = () => {
  const [isDialogVisible, setIsDialogVisible] = useState(false);
  const [valueToPass, setValueToPass] = useState('この値を渡す');

  const openDialog = () => {
    setIsDialogVisible(true);
  }

  const closeDialog = () => {
    setIsDialogVisible(false);
  }

  return (
    <div>
      <Link to={{ pathname: '/dialog', state: { value: valueToPass } }}>ダイアログを開く</Link>
      <MyTableDialog showDialog={isDialogVisible} onClose={closeDialog} valueToPass={valueToPass} />
    </div>
  );
};

export default ParentComponent;







import React from 'react';
import { useLocation } from 'react-router-dom';

const MyTableDialog = () => {
  // useLocationフックを使用してlocationオブジェクトを取得
  const location = useLocation();
  
  // location.state.valueから値を読み取る
  const valueToUse = location.state.value;

  return (
    <div>
      <p>ダイアログ内の値: {valueToUse}</p>
      {/* ダイアログ内で値を使用 */}
    </div>
  );
};

export default MyTableDialog;



import React, { useState, useEffect } from 'react';
import { Checkbox, Dropdown } from '@fluentui/react';
import { useLocation } from 'react-router-dom';

function App() {
  const [isChecked, setIsChecked] = useState(false);
  const location = useLocation();

  // URLパラメーターから初期値を設定
  useEffect(() => {
    const params = new URLSearchParams(location.search);
    const paramValue = params.get('yourParameterName');

    if (paramValue === 'true') {
      setIsChecked(false); // 逆に設定する例
    }
  }, [location.search]);

  // ... 以前のコンポーネントコード

  return (
    <div>
      <Checkbox label="切り替え" checked={isChecked} onChange={handleCheckboxChange} />
      <Dropdown label="選択してください" options={isChecked ? options2 : options1} />
    </div>
  );
}

export default App;






import React, { useState } from 'react';
import { Checkbox, Dropdown } from '@fluentui/react';

function App() {
  const [isChecked, setIsChecked] = useState(false);
  const options1 = [
    { key: 'A', text: 'Option A' },
    { key: 'B', text: 'Option B' },
  ];
  const options2 = [
    { key: 'C', text: 'Option C' },
    { key: 'D', text: 'Option D' },
  ];

  const handleCheckboxChange = (event, isChecked) => {
    setIsChecked(isChecked);
  };

  return (
    <div>
      <Checkbox label="切り替え" checked={isChecked} onChange={handleCheckboxChange} />
      <Dropdown label="選択してください" options={isChecked ? options2 : options1} />
    </div>
  );
}

export default App;



```
【Salesforce】フローを保存して、ページを更新してください。エラーを解決したい

# 問題

フロー作った
↓
デバッグしよー
↓
テストレコードの [レコードタイプ] を編集
↓
![スクリーンショット 2023-10-24 093506.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492812/0f6653bc-de92-6790-7964-27a4aa31d6f5.png)
↓
(; ･`д･´)

# 解決策

なし

Salesforce既存バグらしい

# 参考リンク

[Exception when editing the Record Type field on the Flow Debug and on the View Tests UI
](https://issues.salesforce.com/issue/a028c00000mNUAeAAO/exception-when-editing-the-record-type-field-on-the-flow-debug-and-on-the-view-tests-ui)
CLIツール開発におけるGoとRustの比較

CLIツール開発におけるGoとRustの比較
**パフォーマンス**：
- GoとRustは、そのパフォーマンスで知られています。
- ベンチマークテストによると、Rustは多くのタスクでGoよりも速いことが示されています。 Rustは実行速度を最適化するためにいくつかのデザインのトレードオフを行っており、最適な実行速度を実現しています。一方、Goはシンプリシティを最適化し、それに対して実行時のパフォーマンスを少し犠牲にしています。

**特徴**：
- Goはそのシンプリシティで知られ、バイナリやパッケージ管理などの主要な特徴を備えています。
- Rustはゼロコストの抽象化、エラーメッセージ、ムーブセマンティクス、データ競合防止、パターンマッチングなど、さまざまな特徴を提供しています。

**開発の容易さとスピード**：
- Goは読みやすさがあり、学習とコーディングが容易です。また、自動型推論やgo.fmtなど、コードの一貫性を保ち、フォーマットにかかる時間を減らすのに役立つ多くの機能を含んでいます。
- Rustには借用（borrowing）や所有権（ownership）など、理解が難しい高度なコンセプトがあります⁹。学習曲線が急であるとされています。

**保守**：
- 保守には、プログラムが正常に動作し続けることを確認するために必要なすべてが含まれます。 Goのコードは全体的にシンプルであるため、Goを使用する場合、Rustに比べてコードベースの保守が容易になります。

**ユースケース**：
- Goは、Webアプリケーション、システムツール、ネットワークサーバーの開発に一般的に使用されています。シンプリシティ、拡張性、高パフォーマンスで知られており、幅広いプロジェクトに適した選択肢です²。
- Rustは、高性能なシステム、ゲームエンジン、および低レベルの制御が必要なアプリケーションの開発に一般的に使用されます。 Rustの安全性とパフォーマンスへの焦点、低レベルの制御と組み合わさった特性は、高性能で信頼性のあるアプリケーションの開発に理想的です。

まとめ
GoとRustの選択は具体的なニーズに依存します。使いやすさと開発のスピードを優先する場合、Goが適しているかもしれません。高いパフォーマンスを必要とし、学習曲線が急であっても問題ない場合、Rustが選択肢になるかもしれません。
GraphQLとOpenAPIを比較する時は「REST API」に注意する


  [自ブログ](https://blog.hedrall.work/posts/2023-10-24-no-more-rest)からの引用です。
  
  ## 概要

あるとき、`GraphQL`を実務で利用している友人と飲みながら、彼が携わっているシステムに関して、`GraphQL`や`BFF層`がそのチームにとって本当に必要なのか？を議論したことがありました。

個人的には、`GraphQL`は複雑性を増したり、フロントエンドスピシフィックなアーキテクチャを生み出したりするため、`GraphQL`を利用する明確な理由がなければ、基本的に`OpenAPI`を利用したプラクティスの方がよりシンプルだと考えています。

その際に、彼から「でも、RESTは使いにくいよね」という反応がありました。
私はよく他の`GraphQL`, `gRPC`利用者からも同じような反応を受けることがあるのですが、`REST`という言葉は本質的な観点を見落としている可能性があると感じています。

本記事では、なぜ`REST API`という用語に注意した方が良いのか？と、APIエンドポイントの技術選定に関する正しい観点を整理します。

## APIモデリングのパラダイム

APIのエンドポイントを開発する上で、エンドポイントのモデリング方法(どのように整理するか？)に関しては主に2つのパラダイムがあります。

1. リソース
2. 関数

`1`はリソースによる整理で、クライアントがリソースごとアクセスできるように整理します。 <br/>
`2`の場合は関数で整理する方法で、API側はクライアントのニーズに合わせてエンドポイントを整理します。

この2つはAPIエンドポイントのモデリング方針を決める上で基盤的な概念です。大まかな使いわけとしては、APIとクライアントが一体のシステムの場合は`2`のように機能ごとにモデリングすると便利なことが多く、クライアントがAPIと別のシステムになる場合、またはクライアントが不特定多数になる場合は、個別のクライアントのニーズに答え切ることが難しいため、`2`のリソースでの整理が多くなります。

## `REST`の再認識

1つ、Googleの[ポスト](https://cloud.google.com/blog/ja/products/api-management/understanding-grpc-openapi-and-rest-and-when-to-use-them)を引用します。

> 最も使用頻度の低い API モデルは REST です。REST という単語が広く使用（あるいは乱用）されていても、この方法で設計されている API は非常に少数です。

実は、この記述を意外に感じた方も少なくないのではないでしょうか？<br/>
現実には`REST`なAPIはほとんど存在しません。それにもかかわらず、実際の現場ではよく`REST`という用語をよく耳にすると思います。<br/>
このように、概念が間違った使われ方をしているために、正しい認識や議論が阻害されれている状況があると感じます。<br/>

では、`REST API`とは本質的にどんな物でしょうか？`REST`に関する正確な定義は、(私も詳しくないので)他の多くの情報元に譲るとして、重要な点の一つとしては、(REST)原則に則って**リソースで整理**する点です。

例えば、`id=100`のユーザを取得したければ、クライアントがAPIの実装をよく知らなくても、`GET: /user/100`にアクセスすればよいということになります。
このように、REST APIではサーバーとクライアントの示し合わせの必要性が低くなるため、`OpenAPI`などの`IDL`の利用価値がそれ程高くありません。

## RPCとは？

では、`OpenAPI`を利用したプロジェクトのほとんどが`REST`ではないとしたら、実際はどのような概念を使っているのでしょうか？<br/>
一般的に、`OpenAPI`で管理されているAPIエンドポイントのほとんどが、`RPC`エンドポイントとしてモデリングされています。

`PRC`とは、ネットワークの先にあるシステムのプログラム(手続き)を呼び出すことです。例えば、ユーザの取得用に`GET: /getUser?id={xxx}`や`GET: /search?userId={xxx}`のようなエンドポイントを公開します。
つまり、`RPC`は`リソース`ではなく、`関数`でAPIエンドポイントを整理します。

`RPC`エンドポイントの整理方法はAPI側次第なので、クライアントに対してどんなAPIエンドポイントが利用できるか？を教えてあげる必要があります。そのため、`OpenAPI`のような`IDL`を利用することで、インターフェイスを効率よく交換することができる様になります。

このように、`REST`はリソースで明示的に整理されるので`OpenAPI`の利用価値がそれほど高くない一方で、`RPC`の場合は`OpenAPI`などの`IDL`を利用しないと server - client 間のインターフェイスの調整が難しいため、`OpenAPI`を`REST`と呼ぶのはある意味矛盾した表現にもなります。

## なぜ、OpenAPIをRESTと呼ぶとよくないのか？

`OpenAPI`を`REST`と表現する場合、`REST`と`RPC`の特徴の区別を曖昧にするからです。<br/>
これは前述の、`リソース`と`関数`のどちらでモデリングするか？という重要な観点を曖昧にし、APIの技術選定において大きな認識の齟齬を生むことがあります。

例えば、あるシステムのバックエンドとフロントエンドを同じ組織で開発をしている場合は、本来一体であるシステムがたまたまネットワークで分断されているためにHTTPを利用しなければならないだけであって、両者が向き合っているドメインや抱えるニーズは全く同じなので、`RPC`を利用することで仮想的に一体のシステムとして開発を進めることができ、認知不可を軽減し、開発効率を高めることができます。

一方で、クライアント側が不特定多数の顧客で、多様なニーズに合わせて機能提供する必要がある場合には、より汎用的かつ明示的に`リソース`で整理する方が良いかもしれません。

その他にもたくさんのパターンが考えられますが、`リソース`と`関数`のどちらでモデリングするかは選定のベースラインになります。

また、`GraphQL`や`gRPC`などの他のAPIプロトコルと比較検討する際も、`リソース`と`関数`の観点が重要です。
冒頭に述べた「RESTはなぁ〜」という議論は本質的でなく、`OpenAPI`と比較する場合はそもそもほとんどが`RPC`になるため、`リソース`でモデリングしたいのか？`RPC`でモデリングする場合どちらの技術の方が現況にマッチするか？といった観点が重要になります。

## まとめ

本記事では、`REST`と`RPC`の違いに関して整理し、`OpenAPI`を不用意に`REST`と呼ぶことは、重要な論点を曖昧にするために好ましくないことを説明しました。<br/>
API構築は一連の開発業務の中でもコアな部分になるため、`リソース`と`関数`の観点を意識して状況にあった技術選定を検討していけると良いと思います。
GitLab APIでページネーションを使用して全件データを取得する

ある要件でプロジェクトの一覧をAPIで取得する必要がありました。
実行してみたところ20件しか値がとれていないことに気づきました。調べたところデフォルトでは20件しか結果が返されず、全件取得するにはページネーションを使用する必要があることがわかりました。
ここでは全件取得するまでの過程を記載します。

# GitLab APIの使用例
ここではprojects APIを例に説明します。

プロジェクトの一覧を取得するためにはProjects APIを使用します。
フォーマットは以下になります。
`curl --header "PRIVATE-TOKEN: ${TOKEN}" "${HOST}/api/v4/projects`

ただしデフォルトでは結果は20件しか表示されません。
以下のURLの`Offset-based pagination`に`page` と `per_page` のデフォルト値について記載されています。

https://docs.gitlab.com/ee/api/rest/#pagination



## 結果が何ページに渡るのかを確認するには
結果が20件以上ある場合は、レスポンスが全部で何ページあるのかを取得し、そのページ毎に値を取得するという処理が必要になります。

結果が何ページあるのかを確認するには、レスポンスヘッダーに含まれる　`x-total-pages` の値を確認します。
レスポンスヘッダーを取得するには以下のように `--head` を指定します。

`curl --head --header "PRIVATE-TOKEN: ${TOKEN}" "${HOST}/api/v4/projects`


## 全ページの結果を取得するには
特定のページの値を取得するには
`curl --header "PRIVATE-TOKEN: ${TOKEN}" "${HOST}/api/v4/projects?page=2"`
というようにページ番号を指定します。（上記は2ページ目を取得している例）

上記のようにページ番号を直接指定していくことで取得は可能ですが、手作業で一つ一つ指定するのは大変です。
そこで以下のような処理を実装することで一度に全件の結果を取得することができます。

- x-total-pagesの値を取得する
- ページの数分ループを回し、各ページの値を取得する
- 結果をCSV等に追記していく

以下にサンプルコードを記載します。
```
#プロジェクトの一覧を取得するために、レスポンスヘッダーを取得
COMMAND=`curl --head --header "PRIVATE-TOKEN: ${TOKEN}" "${HOST}/api/v4/projects?per_page=$PER_PAGE"`

#レスポンスヘッダーからx-total-pagesの値を取得し、改行を削除、ページ数を取得
PAGES=`echo "$COMMAND" | grep "x-total-pages" | sed 's/x-total-pages: //' | tr -d '\r'`

COUNT=1
#ページの数分ループを実施、ループ内ではページを指定してプロジェクト一覧取得のAPIを実行
while [ $COUNT -le $PAGES ]; do
  echo "count = $COUNT"
  curl --header "PRIVATE-TOKEN: ${TOKEN}" "${HOST}/api/v4/projects?per_page=$PER_PAGE&page=$COUNT" | jq -r ".[] | [.id ,.name] |@csv" >> result.csv
  ((COUNT++))
done
```

# 参考URL

Projects API
https://docs.gitlab.com/ee/api/projects.html

Bash script to deal with the Gitlab API pagination
https://gist.github.com/gohoyer/73f9ed7919954df55990b61afd716b2e
NVIDIA Morpheusの必要性

NVIDIA Morpheusのモデルはあまりないことに気付きましたが、いくつかの優れたトレーニング スクリプトなどがここで提供されています: https://docs.nvidia.com/morpheus/models_and_datasets.html

実際の GitHub リポジトリで読んだ内容を要約しました。上記のページからリンクできます。https://docs.google.com/spreadsheets/d/1iBdMkFLxzO3JZtCHds5ElVhfNw44EmSDemILSXPrnps/edit?usp=sharing 現在、予測するために BERT モデルをトレーニングしています。 Morpheus リポジトリで提供される AWS Cloudtrails データセット内のマスクされたトークン。異常かどうかの予測も含まれます。

GPU を使用してゼロトラスト アーキテクチャを促進します。 サンプリングではなくすべてのデータを調べるのがサイバーセキュリティのあるべき姿のようですが、少なくとも日本の企業はGPUの使用コストを懸念してこれに足を引っ張っているように見えますが、彼らはそれを尋ねることを怠っています。 「ハッカーによって侵害された場合の代償はいくらですか?」 競争の激しい業界の新興企業や中小企業にとって、それはビジネスを失うことを意味する可能性があります。

サイバーセキュリティを軽視しないでください。 現在、ハッカーは AI で武装しており、これに対抗する唯一の方法は、GPU と独自の AI の力を防御に利用することです。
OpenZitiとNVIDIA Morpheusの相乗効果

英文原文は https://www.linkedin.com/pulse/synergies-between-openziti-nvidia-morpheus-nobutaka-kim%3FtrackingId=GlLjvBRqS%252BODlN2bI7Chsw%253D%253D/?trackingId=GlLjvBRqS%2BODlN2bI7Chsw%3D%3D　

Ziti: 認証と認可 (OpenZiti: https://openziti.io/)

Ziti は、ゼロ トラスト ネットワーキング モデルの一部として認証と認可を処理するように設計されています。 安全な認証されたハンドシェイク プロセスを使用して接続を確立し、ポリシーベースのアクセス制御を使用して、特定の ID がアクセスを許可されるサービスを決定します。

Morpheus: 継続的な監視と異常検出 (https://developer.nvidia.com/morpheus-cybersecurity)

Morpheus は継続的な監視と異常検出を専門としています。 機械学習モデルを使用してネットワーク トラフィックと動作をリアルタイムで分析し、異常なアクティビティや潜在的に悪意のあるアクティビティを特定します。

相乗効果

Ziti の認証および認可機能と Morpheus のリアルタイム監視の相乗効果により、堅牢で包括的なセキュリティ ソリューションを構築できます。 具体的には、Ziti は、認証され許可されたクライアントのみがネットワークにアクセスできるようにします。一方、Morpheus は、これらの認証されたクライアントを継続的に監視して、異常な動作を検出します。

この多層アプローチは、さまざまな種類の脅威から保護するために複数層のセキュリティ制御を提唱する「多層防御」の原則とよく一致しています。

職務の分担

Morpheusの役割

Morpheus は主に、機械学習モデルを通じてネットワーク動作の異常を検出することに重点を置いています。 異常が検出されると、Morpheus はさらなる調査のためのアラートを生成できます。 ただし、通常、ネットワーク ポリシーの適用やクライアント セッションの終了は処理しません。

ジティの役割

一方、Ziti にはポリシーを適用するための機能が組み込まれています。 Morpheus (またはその他の監視システム) によって警告された場合、Ziti は違反しているクライアントの資格情報を取り消し、それによってネットワークへのアクセスを終了できます。

自動応答のための統合

より自動化された応答のために、Morpheus と Ziti を統合できます。 Morpheus が異常を検出すると、Ziti への API 呼び出しをトリガーして、ネットワーク ポリシーを更新し、クライアントのアクセスを取り消す可能性があります。

ワークフロー例

Morpheus は異常な動作を検出します。機械学習モデルは、異常なネットワーク トラフィックやクライアントからのアクションにフラグを立てます。

アラートの生成: Morpheus はアラートを生成し、API 呼び出しまたは Webhook を通じて Ziti に通知します。

Ziti でのポリシーの適用: Ziti はアラートを受信し、アクセス ポリシーを更新して、違反しているクライアントの資格情報を取り消します。

セッションの終了: クライアントのセッションが終了し、ネットワークから切断されます。

この統合されたアプローチにより、セキュリティ インシデントへのリアルタイムの対応が可能になり、ネットワーク全体のセキュリティ体制が強化されます。

脚注

"Zero Trust Architecture", OpenZiti Blog, source. 

"Morpheus: AI-Driven Security", NVIDIA Blog, source. 

"Synergizing Security Solutions", Cybersecurity Journal, source. 

"Defense in Depth", National Institute of Standards and Technology, source. 

"NVIDIA Morpheus: Real-Time Cybersecurity", NVIDIA Official Website, source. 

"Policy-based Access Control", OpenZiti Documentation, source. 

"Integrating Security Solutions for Better Protection", Cybersecurity Journal, source.