OmniAICreator/Qiita-1.07M huggingface dataset:
PostgreSQL 13でのreindexの活用方法をまとめてみた 

# はじめに
データベースのメンテナンスは、パフォーマンスと安定性の維持に欠かせません。その中でも、PostgreSQLでは**reindex**という強力なツールが提供されています。
本記事では、**reindex**の役割と重要性について解説し、具体的な手順とコード例を通じて、PostgreSQL 13における**reindex**の活用方法とパフォーマンス向上効果についてざっくり紹介します。

## reindexの実行前の準備
**reindex**を実行する前に、対象となるテーブルやインデックスの状態を確認することが重要です。以下のコマンドで確認できます。

```ruby:sql
SELECT schemaname, tablename, relname, relkind, relpages
FROM pg_stat_all_tables;
```
```ruby:sql
SELECT schemaname, indexname, relname, idx_scan
FROM pg_stat_all_indexes;
```


## テーブルのreindex
テーブルの再構築によるパフォーマンス向上
テーブルの**reindex**は、テーブル全体のデータを再構築し、インデックスや統計情報を最新の状態に更新します。
次のコマンドを使用して、テーブルの**reindex**を行います。

```ruby:sql
REINDEX TABLE <テーブル名>;
```
パフォーマンス向上効果の具体例を追記します。
以下の効果が期待できます。

インデックスの効率化: テーブルの再構築により、インデックスが最適な状態になります。これにより、クエリの実行速度が向上します。
統計情報の最新化: テーブルの再構築により、統計情報が更新されます。これにより、クエリプランナーがより正確な実行計画を立てることができ、クエリのパフォーマンスが向上します。

## インデックスのreindex
インデックス再作成によるパフォーマンスの最適化
インデックスの再構築は、インデックスを削除して再作成することで、インデックスの効率性を向上させます。
次のコマンドを使用して、インデックスの**reindex**を行います。

```ruby:sql
REINDEX INDEX <インデックス名>;
```
パフォーマンス向上効果の具体例を追記します。
以下の効果が期待できます。

インデックスの再構築: インデックスの再作成により、インデックスのフラグメンテーションが解消され、データのアクセス効率が向上します。
インデックスの最適化: インデックスの再構築により、クエリのパフォーマンスが向上します。特に、頻繁に更新されるテーブルのインデックスは定期的な**reindex**が推奨されます。


## システムカタログのreindex

システムカタログの再構築によるメンテナンス性向上
システムカタログの再構築は、データベースのメタデータを再作成し、クエリの最適化やデータの整合性の確保に役立ちます。
次のコマンドを使用して、システムカタログの**reindex**を行います。

```ruby:sql
REINDEX SYSTEM <カタログ名>;
```
パフォーマンス向上効果の具体例を追記します。
以下の効果が期待できます。

クエリの最適化: システムカタログの再構築により、クエリプランナーが正確な統計情報を利用して最適な実行計画を立てることができます。
データの整合性の確保: システムカタログの再構築により、データベースのメタデータが正常な状態に保たれます。これにより、データの整合性が確保され、安定性が向上します。


## REINDEX DATABASEの使用

データベース全体の再構築によるメンテナンス性向上
REINDEX DATABASEコマンドを使用すると、データベース全体の再構築が行われます。これにより、テーブルやインデックスの再構築が一括して行われ、データベース全体のパフォーマンスが向上します。
次のコマンドを使用して、REINDEX DATABASEを実行します。

```ruby:sql
REINDEX DATABASE <データベース名>;
```
REINDEX DATABASEの注意点とメリットを追記します。
**★注意点**
REINDEX DATABASEはデータベース全体の再構築なので、実行には時間とリソースがかかります。

**メリット:**
テーブルやインデックスの個別の再構築ではなく、一括して行うことで、メンテナンスの手間を削減できます。
データベース全体のパフォーマンス向上が期待できます。
(本番環境でも影響の少ない時間を考慮さえすれば、一番手軽にパフォーマンス向上が測れます。)

## CONCURRENTLYオプションの使用

インデックス再構築中のデータアクセスを許可する
CONCURRENTLYオプションを使用すると、インデックスの再構築中にテーブルへのデータアクセスを許可します。これにより、データベースの稼働中にもインデックスの再構築が行えます。以下のコマンドでCONCURRENTLYオプションを使用した**reindex**を行います。

```ruby:sql
REINDEX DATABASE CONCURRENTLY <データベース名>;
```
CONCURRENTLYオプションのメリットと制限事項を追記します。

**メリット:**
インデックスの再構築中でもデータベースへのアクセスが可能なので、生産環境での停止時間を最小限に抑えることができます。
非常に大きなテーブルや複数のインデックスがある場合でも、効率的に再構築を行えます。
(弊社では夜間にCONCURRENTLYオプションを使用してDATABSE単位で実行しています。)

**制限事項:**
CONCURRENTLYオプションを使用する場合、一部の制約があります。たとえば、一意制約や主キー制約を持つインデックスは再構築できません。詳細な制約については公式ドキュメントを参照してください。

## ★REINDEX DATABASE CONCRRENTLY実行時間例
テーブル数：492
レコード数(最大)：1587027
上記の環境で、2時間程度でした。
※データマップによるのであくまで参考程度でお願いします。

## ★落とし穴
REINDEXは対象のDBにログインした状態で行う必要があります。
シェルスクリプトなどで大量のDBの**REINDEX**を回す場合は以下をテンプレートにして頂くといいかもしれません。
```ruby:psql
psql -h <ホスト名> -d <データベース名> -c 'REINDEX DATABASE CONCURRENTLY "'<データベース名>'";'
```

# 結論
**reindex**を適切に実行することで、テーブルやインデックスの再構築が行われ、データベースのメンテナンス性とパフォーマンスが向上します。また、REINDEX DATABASEやCONCURRENTLYオプションの使用により、データベース全体の再構築や稼働中のメンテナンスを効率的に行うことができます。データベースの安定性とパフォーマンスを維持するために、定期的な**reindex**の実行を検討しましょう。
PythonでPDFの表をExcelの表へ変換する

# 前提条件
* Windows 10
* Python3
* Java
* pandas
* tabula-py

tabula-pyの公式ドキュメントは以下です。
https://tabula-py.readthedocs.io/en/latest/tabula.html

pandasの公式ドキュメントは下記です。
https://pandas.pydata.org/docs/

tabula-pyを利用するためにはJavaをインストールする必要があります。
~~Javaの環境構築について、ここでは割愛します。~~

Javaの環境構築について、以下の記事を書きました。

https://qiita.com/jinbei230525/items/29a1647f4a6584fc5dc8

サンプルのPDFは以下を使用します。
https://www.mhlw.go.jp/content/10906000/001094070.pdf

# 目的
tabula-pyを利用して、PDFの表を抽出し、Excelへ表として書き出す。

# 環境構築
```
pip install pandas tabula-py
```

# サンプル
```pdftable2excel.py
# -*- coding: utf-8 -*-

import pandas as pd
from tabula import read_pdf

dfs = read_pdf("https://www.mhlw.go.jp/content/10906000/001094070.pdf",	lattice = True)
excel = 'C:\\pdf\\新型コロナウイルス陽性者数とPCR検査等実施人数.xlsx'

with pd.ExcelWriter(excel) as writer:
# エクセルのシートにPDFの表を出力
    for i, df in enumerate(dfs):
        df.to_excel(writer, sheet_name = str(i))
```
csvへ追記保存する場合

```pdftable2csv.py
# -*- coding: utf-8 -*-

from tabula import read_pdf

dfs = read_pdf("https://www.mhlw.go.jp/content/10906000/001094070.pdf",	lattice = True)
csv = 'C:\\pdf\\新型コロナウイルス陽性者数とPCR検査等実施人数.csv'

for df in dfs:
    df.to_csv(csv, mode = 'a', encoding = 'shift-jis', index = False, header = False)
```
# 関連資料
https://qiita.com/jinbei230525/items/fc01e8cd4469302f5e1c

https://qiita.com/jinbei230525/items/f192d35be3d3a2c29f73

https://qiita.com/jinbei230525/items/e38b27f61587b2ac5eaf

# きっかけ
PDFにある表を抽出して、Excelとして保存し、2次利用したいことがあったので、本プログラムを書いてみた。
セキュリティの問題を見つけ警告する慈善団体から連絡が来た

# ある日、、

「[Repo Lookout](https://www.repo-lookout.org/)」という団体から、僕個人のemailに「君のサイト脆弱性あるよ」といった旨の連絡が来ました。

開くと本文には、確かに僕が書いたであろうprivateなgitリポジトリへのコミットメッセージが記載されていたので、事実であることはすぐに分かりました。

# 問題

どうやら、僕がずっと昔に作った個人のWebサイトに、.gitディレクトリ配下へWeb上からアクセスできてしまう問題があるようです。

当時、プロジェクト直下をそのままドキュメントルートに設定してしまっていたため起きていました。

見られて問題になるようなプロジェクトではなかったのは幸いです。

# Repo Lookout

この連絡を送ってきた団体は、脆弱性を突いて脅しをかけよう、といったような悪意のある団体ではなく、むしろその逆のようです。

このケースの脆弱性に特化して、世の中のWebサイトから同様の問題を持つサイトを検知し、所有者のemailへ修正を促す連絡をしているようです。

[公式サイト](https://www.repo-lookout.org/)には「**私たちはウェブをより安全な場所にしたいだけです。**」とあります。

ちなみに、連絡先のemailは、公開されてしまっている.gitの情報から入手しているそうです。

# おわり

常日頃セキュリティ対策とかいうクリエイティブとは関係ないことに時間使わないといけないほど悪の蔓延るインターネットですが、こういうカッケー団体もいるってことを皆に紹介したい話でした。

そして、（そんな間抜けは僕くらいかもしれませんが、）.gitディレクトリ（やその他非公開情報）がドキュメントルート下にうっかり置かれていないか気をつけよう…！
GitHubでプルリクエストをクローズする方法

## 概要
GitHubにおいて、プルリクエスト（マージリクエスト）をキャンセル（クローズ）する方法を記述します。

## 手順
1. GitHubでプロジェクトのリポジトリを開きます。
2. "Pull requests" タブをクリックします。
3. キャンセルしたいプルリクエストをクリックします。
4. プルリクエストの下部にある "Close pull request" ボタン（または "Close" ボタン）をクリックします。

## 解説
この操作を行うと、プルリクエストはキャンセルされ（クローズされ）、マージが行われません。ただし、プルリクエストそのものやその中のコメント、コミットは削除されません。これらは後から参照することができます。
なお、誤ったソースコードをマージ依頼した場合でも、プルリクエストをクローズしてから正しいソースコードで新たにプルリクエストを作成することが可能です。
JavaScript で画像・動画・音声アップロード時にプレビュー

画像・動画・音声ファイルをアップロードした時にクライアントのみでプレビュー表示までやってみる
サンプルは以下のページ

https://sueasen.github.io/javascript-exercise/work/filepreview/

- HTML
HTML に ファイルアップロードの `input` タグと プレビュー用の `img`, `video`, `audio` タグを準備
`input` タグの `onchange` で JavaScript の処理を実行、`this` に選択したファイル情報が入ってくる
あと `accept` 属性でファイル種類を限定（他のファイル入力できちゃうけど．．．）
    ```HTML
    <!doctype html>
    <html>

    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width,initial-scale=1">
      <link rel="stylesheet" href="./style.css">
    </head>

    <body>

      <hr>
      <h4>画像アップ・プレビュー</h4>
      <input type="file" accept='image/*' onchange="preview(this, 'previewImage');">
      <br>
      <img class="preview" id="previewImage">

      <h4>動画アップ・プレビュー</h4>
      <input type="file" accept='video/*' onchange="preview(this, 'previewVideo');">
      <br>
      <video  class="preview" id="previewVideo" controls="controls"></video>

      <h4>音声アップ・プレビュー</h4>
      <input type="file" accept='audio/*' onchange="preview(this, 'previewAudio');">
      <br>
      <audio  class="preview" id="previewAudio" controls="controls"></audio>

    </body>

    <script src="script.js"></script>

    </html>
    ```

- JavaScript
JavaScript でプレビュー表示、`FileReader` を使ってやる
    ```JavaScript
    /**
     * ファイル選択時の処理
     * @param {HTMLInputElement} obj 入力ファイル
     * @param {String} previewId プレビュー表示DOMのID
     */
    function preview(obj, previewId) {
        let fileReader = new FileReader();
        fileReader.onload = (function () {
            document.getElementById(previewId).src = fileReader.result;
        });
        fileReader.readAsDataURL(obj.files[0]);
    }
    ```
【Paiza問題集】データセットメニュー/動的配列

# Paiza問題集
Pythonで回答

## データセットメニュー/動的配列

### Step01 ランダムアクセス
```Python:Step01
"""
ランダムアクセス
https://paiza.jp/works/mondai/data_structure/data_structure__array_step1
"""

# 数字を受け取る
N, M = map(int, input().split())

# 数字列を受け取る
A = [int(x) for x in input().split()]

# 表示する
print(A[M-1])
```

### Step02 複数回のランダムアクセス
```Python:Step02
"""
複数回のランダムアクセス
https://paiza.jp/works/mondai/data_structure/data_structure__array_step2
"""

# 数字を受け取る
N = int(input())
# 配列に数字を入れる
A = [int(x) for x in input().split()]

# 数字を受け取る
M = int(input())
# 配列に数字を入れる
B = [int(x) for x in input().split()]

# 数字表示する
for i in range(M):
    print(A[B[i]-1])
```

### Step03 最大値と最小値
```Python:Step03
"""
最大値と最小値
https://paiza.jp/works/mondai/data_structure/data_structure__array_step3
"""

# 数字を受け取る
li = list(map(int, input().split()))

# 数字を昇順に並び変える
li.sort()

# 差を求めて表示する
print(li[2]-li[0])
```

### Final問題 動的配列
```Python:Final問題
"""
動的配列
https://paiza.jp/works/mondai/data_structure/data_structure__array_boss

プログラムの動作
・ 0 x : Aの末尾にxを追加する
・ 1 : Aの末尾を削除する
・ 2 : Aを半角スペース区切りで1行に出力する
"""

# 数字を受け取る
N, Q = map(int, (input().split()))

# 配列に数字を入れる
A = list(map(int, input().split()))


for i in range(Q):
    # 数列を受け取る
    query = list(map(int, (input().split())))

    # 0,1,2を判断する
    cmd = query[0]
    if cmd == 0:
        # 配列の末尾に追加
        A.append(query[1])
    elif cmd == 1:
        # 配列の末尾を削除
        A.pop()
    else:
        # 配列を表示
        print(" ".join(map(str, A)))
```
【Git】特定のファイルだけコミット前に戻したい

# はじめに
gitの操作でわからないとこがあったので記録しておきます

# やりかた
間違ったコミットの一つ前のコミットIDを見つけます
```:ターミナル
git log 戻したいファイルのパス
```

戻します
```:ターミナル
git checkout コピーしたコミットID 戻したいファイルのパス
```

# おわり
gitはまだまだ知らないことだらけなのでもっと勉強して知識を付けていきたいです。

# 参考記事
https://konbu13.hatenablog.com/entry/2014/12/01/070255#:~:text=git%20log%20%E3%81%A7%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE,git%20checkout%20%E3%81%A7%E6%88%BB%E3%81%9B%E3%81%BE%E3%81%99%E3%80%82
python maya create nurbs curvs and at to control sets

```python
import maya.cmds as cmds

def create_nurbs_curve(name):
    # Create a NURBS curve
    curve = cmds.curve(d=1, p=[(-1, 0, 0), (1, 0, 0)], k=[0, 1], name=name)
    return curve

def add_to_control_set(curve, control_set):
    # Add the curve to the control set
    cmds.sets(curve, add=control_set)

# Create a control set
control_set = cmds.sets(name="body")

# Create NURBS curves
curve1 = create_nurbs_curve("Curve1")
curve2 = create_nurbs_curve("Curve2")

# Add curves to the control set
add_to_control_set(curve1, control_set)
add_to_control_set(curve2, control_set)
```
Salesforce認定アプリケーションビルダー練習問題解説17

今回の内容は動画でも解説しています


https://youtu.be/HF2jegu0h6E

<iframe width="560" height="315" src="https://www.youtube.com/embed/HF2jegu0h6E" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

こんにちは
本橋孝昭です

Salesforce認定アプリケーションビルダーの公式練習問題があるのはご存じでしょうか

フラッシュカードで何度も解ける練習問題がございます


今回は
Platform アプリケーションビルダー試験に向けた学習 
認定 Platform アプリケーションビルダー資格の受験準備: Data Modeling and App Deployment (データモデリングとアプリケーションリリース) 

3問目を紹介します


https://trailhead.salesforce.com/ja/content/learn/modules/platform-app-builder-pt2/platform-app-builder-deployment?trail_id=platform-app-builder-certification-prep&trailmix_creator_id=welcome4&trailmix_slug=prepare-for-your-salesforce-platform-app-builder

https://trailhead.salesforce.com/ja/content/learn/modules/platform-app-builder-pt2/platform-app-builder-deployment?trail_id=platform-app-builder-certification-prep&trailmix_creator_id=welcome4&trailmix_slug=prepare-for-your-salesforce-platform-app-builder

![　アプリ００３.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/10bf8646-0d21-6bbc-7155-abb404ab740a.png)

正解はCです

これは管理パッケージと未管理パッケージの特徴を考えれば対応可能です
それぞれ以下のような違いがあります

参考リンク
https://help.salesforce.com/s/articleView?id=000385206&type=1

## 管理パッケージ

・App Exchangeなど商用の配布向けに便利
・パッケージをインストールしたユーザはそのパッケージのソースコードを見ることが出来ない
・管理パッケージ作成者は配布後にパッケージのアップグレードも可能


## 未管理パッケージ

・オープンソースの配布に便利
・パッケージをインストールしたユーザはそのパッケージのソースコードはインストール先で編集が可能
・管理パッケージ作成者は配布後にパッケージのアップグレードはできない


今回の場合
・ハッカソンセッション用のコンポーネントの配布（商用や販売目的ではない。パッケージ配布後に編集されることを考えている）

ということから正解は未管理パッケージであることが分かりますね


以下の内容にもこのように書かれていますね


＞未管理パッケージは通常、開発者にオープンソースプロジェクトを配布するため、またはインストール後にカスタマイズが必要なアプリケーションを一度だけ配布するために使用します

https://developer.salesforce.com/docs/atlas.ja-jp.packagingGuide.meta/packagingGuide/packaging_developing_unmanaged.htm

このようなことから未管理パッケージが正解ということがわかります


ほかのSalesforce認定アプリケーションビルダーの問題の解説などはこちらから

https://qiita.com/Takaa/items/6434c5838e23f409d01f
VSCodeで左右キーを押したときに補完を消す

VSCodeでは、補完が出ている状態で左右キーを押すと、補完ウィジェットがカーソルに追従してきます。

![1dybm-jnzd7.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678625/c568359d-7066-6d62-64b1-6707db29cc20.gif)
▲左右キーを押しても、補完が消えない

自分にとってはこの挙動は不便でした。左右キーを押して別の場所で入力しようとしているのだから、もう補完は出さなくていいです。
上の行や下の行に移動したくても、補完ウィジェットに上下の操作が取られてしまい、移動できません。

`Esc`キーを押せば補完ウィジェットは消えるのですが、わざわざ`Esc`まで指を伸ばしたくありません(怠惰)。

調べたところ、どうやらキーバインディングを自分で設定することでこの挙動を回避することができるようです。

## 左右キーを押したときに補完ウィジェットを消す

左右キーを押したときに、「補完ウィジェットを消す」「カーソルを左右に移動する」の2つのコマンドを実行するキーバインディングを設定してやればいいようです。
VSCodeでは、それぞれの操作は以下のコマンドに対応しています。

- 補完ウィジェットを消す操作：`hideSuggestWidget`コマンド
- カーソルを左に移動する：`cursorLeft`コマンド
- カーソルを右に移動する：`cursorRight`コマンド
- 複数コマンドを実行する操作：`runCommands`コマンド

これらをいい感じに組み合わせていけばいいみたいです。

### 設定方法

まず、VSCodeで`Ctrl+Shift+P`を押して、`Open Keyboard Shortcuts (JSON)`を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678625/93fe3009-6c79-25e8-ceb8-b5b8d5370d75.png)

するとJSONファイルが開くので、以下の内容を書き込みます。

```json
[
  {
    "key": "right",
    "command": "runCommands",
    "when": "suggestWidgetVisible && textInputFocus",
    "args": {
      "commands": [
        "hideSuggestWidget",
        "cursorRight"
      ]
    }
  },
  {
    "key": "left",
    "command": "runCommands",
    "when": "suggestWidgetVisible && textInputFocus",
    "args": {
      "commands": [
        "hideSuggestWidget",
        "cursorLeft"
      ]
    }
  },
]
```

これを保存したら設定は完了です。エディタに戻ると、無事左右キーで補完ウィジェットが消えるようになっていました。

![feg5h-jartl.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678625/d2590363-57c3-59d4-b559-27b8886265d8.gif)
▲カーソルを左右に移動すると補完ウィジェットが消えてくれる

## まとめ

- デフォルトでは、VSCodeで補完ウィジェットが出ている状態でカーソルを左右に移動すると、補完ウィジェットが追従してくる。
- この挙動を回避するにはKeyboard Shortcuts設定を上書きして、左右キーで補完ウィジェットを消すように設定すればよい。
gitでpushする時に毎回パスワードとユーザー名を入れるのを簡単にやめる方法

タイトルの通りなのですが、git上にpushする時にパスワードとユーザー名を毎回毎回入力するのが結構大変！
なんとかならないかなと思い、ネットを調べると鍵を新たに設定して...とか、URLを変更して....とかあるけど、うーん大変そう...
簡単にできないの？
はい！できました！
```
git config --global credential.helper 'cache --timeout=36000'
```
この1行をコマンドラインに入力すればよいのです！
これによって認証情報をキャッシュされ決めた時間ユーザー認証をしなくて良くなります！
(これを入力する前か後(どっちでも大丈夫！)に1回はユーザー名とパスワードを入れて認証を行う必要はあります！)
```
git pull
```
と入力して認証を済ませるのが楽ですかね？
1秒が3,600秒なのでこれだと10時間は認証をしなくて良くなります(時間は自分のスタイルに合わせて変更してください！(あまり長い時間にしすぎるとセキュリティ的に...ね？))
現場からは以上です！
データベースにアクセスできない!?

sqlit3でのエラー表示です。
```
SQLSTATE[HY000]: General error: 8 attempt to write a readonly database
```
このエラーはデータベースが読み取り専用モードであるため、書き込み操作が試行された場合に発生するエラーです。
このエラーの原因としては、データベースファイル自体が読み取り専用に設定されているか、データベースのパーミッションが適切に設定されていないかのいずれかが考えられます。
じゃあ直そう！
もう力技です。
すべての人に編集権限と閲覧権限を与えます
```
sudo chmod 777 <データベース名>
```
例えばdrink.dbなら
```
sudo chmod 777 drink.db
```
すると違うエラーが...
```
SQLSTATE[HY000]: General error: 14 unable to open database file
```
データベースファイルを開くことができない場合に発生するエラーです。
普通はパスが間違っているとか、ファイルが存在しないときとかに出ますが、今回はどっちでもないことは確定しています。
読み取り権限もあるし....
これ、通過するディレクトリにも権限必要なんです。
なので
```
sudo chmod 777 <ディレクトリ名>
```
呼び出している一番上のファイルがあるディレクトリからデータベースファイルまで通過するディレクトリ全てに同じように設定します。
これで解決！
MUI(Material UI)のAutocompleteでEncountered two children with the same keyのエラーが出る時の対処法

ReactのUIフレームワークであるMUI(Material UI)のAutocompleteコンポーネントで下記のエラーが出る場合の対処法です。

## Autocompleteのエラー内容
```
Warning: Encountered two children with the same key, ``.
Keys should be unique so that components maintain their identity across updates.
Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.
```
Autocompleteのoptionsのkeyに同一のものがあると言うエラーです。

コードは下記になります。

```tsx
const Home = () => {
  const [value, setValue] = useState()
  const options = [
    { id: 1, name: 'Ken', role: 0, age: 35 },
    { id: 2, name: 'Taro', role: 1, age: 42 },
    { id: 3, name: 'Tom', role: 2, age: 45 }
  ]
  return (
    <Container>
      <Autocomplete
        options={options}
        isOptionEqualToValue={(option, v) => option.id === v.id}
        getOptionLabel={(option) => option.name}
        onChange={(_e, item) => {
          return setValue(item)
        }}
        value={value || null}
        noOptionsText="見つかりません"
        renderInput={(params) => <TextField {...params} fullWidth />}
      />
    </Container>
  )
}

export default Home
```

## renderOptionにkeyを割り当てることで解決
Autocompleteコンポーネントの`renderOption`にkeyを割り当てることで解決しました。

```jsx
renderOption={(props, option) => {
  return (
    <Box component="li" {...props} key={option.id}>
      {option.name}
    </Box>
  )
}}
```
※`{...props} key={option.id}`のようにpropsを先に記述する必要がありました。

## 全体のコード

```tsx
import { Autocomplete, Box, Container, TextField } from '@mui/material'
import { useState } from 'react'

const Home = () => {
  const [value, setValue] = useState()
  const options = [
    { id: 1, name: 'Ken', role: 0, age: 35 },
    { id: 2, name: 'Taro', role: 1, age: 42 },
    { id: 3, name: 'Tom', role: 2, age: 45 }
  ]
  return (
    <Container>
      <Autocomplete
        options={options}
        isOptionEqualToValue={(option, v) => option.id === v.id}
        getOptionLabel={(option) => option.name}
        onChange={(_e, item) => {
          return setValue(item)
        }}
        value={value || null}
        noOptionsText="見つかりません"
        renderOption={(props, option) => {
          return (
            <Box component="li" {...props} key={option.id}>
              {option.name}
            </Box>
          )
        }}
        renderInput={(params) => <TextField {...params} fullWidth />}
      />
    </Container>
  )
}

export default Home
```
Dockerでnode.jsを動かすサンプル

以下は、Dockerを使用してNode.jsの簡単なWebアプリケーションをコンテナ化するサンプルです。このサンプルでは、Dockerfileを使用してイメージをビルドし、それを実行するコンテナを作成します。

1. プロジェクトのディレクトリを作成します。

2. 以下の内容で、Dockerfileをプロジェクトのルートディレクトリに作成します。

```Dockerfile
# ベースイメージを指定
FROM node:14-alpine

# アプリケーションディレクトリを作成
WORKDIR /app

# アプリケーションの依存関係をインストール
COPY package*.json ./
RUN npm install

# アプリケーションのソースコードをコピー
COPY . .

# ポートを公開
EXPOSE 3000

# アプリケーションを起動
CMD [ "npm", "start" ]
```

3. プロジェクトディレクトリに、Node.jsのWebアプリケーションのソースコードを含むファイルを作成します。

4. コマンドプロンプトまたはターミナルを開き、プロジェクトのルートディレクトリに移動します。

5. 以下のコマンドを実行して、Dockerイメージをビルドします。

```shell
docker build -t my-node-app .
```

`-t`オプションでイメージにタグを付け、`.`はカレントディレクトリにあるDockerfileを使用することを意味します。

6. イメージのビルドが完了したら、以下のコマンドを使用してコンテナを実行します。

```shell
docker run -p 3000:3000 my-node-app
```

`-p`オプションでホストのポートとコンテナのポートをマッピングし、`my-node-app`はビルドしたイメージのタグです。

7. ブラウザで `http://localhost:3000` を開くと、コンテナ内で実行されているNode.jsアプリケーションが表示されます。

このサンプルでは、Node.jsのWebアプリケーションをDockerコンテナにパッケージ化し、実行する方法を示しています。自分のプロジェクトに適応するために、Dockerfileとコンテナの実行コマンドをカスタマイズしてください。
特徴量エンジンKaskadaの宣言型クエリ言語 Fenl~時系列計算  Temporal Calculation

# はじめに

先日、以下の記事を発表しました。

https://qiita.com/yoshiyuki_kono/items/7dc7bdad5e02ff986f5d

新しいテクノロジーに触れる時はいつでも楽しいものです。
中でも新しいプログラミング言語（のパラダイム）を学ぶことは、特別に楽しいことです。

ということで、まだまだ勉強中ですが、公式ドキュメントの学習過程の記録として、以下の記事をまとめてみました。特に、日本語に置き換えるにあたっての用法が固まっていない分野として、自分にとって受け止めやすいのは何か？という観点からの試みとなっています。

Fenlとは何か、については、下記の記事を参照ください。

https://qiita.com/yoshiyuki_kono/items/e2056d884242901facfd

本稿情報のソースとして、下記ドキュメントを参照ください。

https://kaskada.io/docs-site/kaskada/main/fenl/temporal-aggregation.html

# 時系列計算  Temporal Calculation

## 背景：イベントベースのデータの課題を解決する
Kaskada はイベントベースの計算エンジンです。

それでは「イベント」とは、なんでしょうか？それは、時間に関連付けられた世界に関するあらゆる事象です。例えば、製品の購入や、サービスへの課金などは、イベントの典型と言えるでしょう。

イベントベースのデータの多くは、時間の経過とともに変化します。このような時間の経過とともに変化する一連のイベントから値を計算するということは、あるターゲットの計算結果が、時間の経過に従って変化する、と捉えることができます。

従来のデータ処理システムは、「特定のユーザーが何件購入したか?」など、データセットの現在の状態に関する質問に答えるように設計されています。
このアプローチにはいくつかの欠点があります。特定の質問に対する答えは、いつ尋ねられるかによって変わり、質問できるのは「今」だけです。

このような制約は、これまで主流であった多くのユースケースにとっては合理的でしたが、機械学習モデルをトレーニングするための特徴量サンプルを構築するというユースケースには向いていない部分があります。
ここでの、典型的な錯誤は、過去に入手可能な情報を説明することを目的としたトレーニング サンプルを構築するために、「現在」知られている情報を誤って使用してしまうことです（ターゲット漏洩）。

従来の計算の表現方法は、上記の課題には役に立ちません。
SQL などのクエリ言語や DataFrame などのデータ処理インターフェイスは、(時系列ではなく) 表形式のデータに関する要求に答えるように設計されています。
「商品購入時点において、購入先のベンダーに対して何件の詐欺報告が提出されているか?」というような質問は、一見単純な質問のようにも見えますが、従来の計算の表現方法では、複雑なウィンドウ処理やパーティショニング操作が必要になる場合があります。

イベントベースのデータやイベントベースのモデルを操作する場合、時間は重要な役割を果たします。イベント履歴における特定時点の特徴値を計算する機能は、Kaskada の中核機能の 1 つです。

Fenlは、クエリ言語に時間の概念を取り入れて設計されています。

Fenl 式は、単一の値を計算するのではなく、時間の経過とともに変化する特定の計算の結果を記述する時間ストリームを生成します。



## バリューストリーム
Fenl は、単一の値で質問に答えるのではなく、時間の経過とともに変化する答えを記述する一連の値を生成します。たとえば、「（このユーザーは）何回購入したか?」という質問に対する答えは、次の表のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/5336e7e3-4a16-56df-c792-d9ca58f03c7a.png)


この表は、2015 年に質問された場合の答えは「（このユーザーは）2 回購入した」となるが、2019年10月26日以降に、質問された場合は答えが「（このユーザーは）は4 回 購入した」となることを示します。

## 最終的な（現時点の）値に対するクエリ：`final-results`
質問に対する「最終的な(final)」回答、つまりすべての値が処理された後に生成される最後の回答を知ることは、しばしば重要になります。
Fenl は、こうしたユースケースに対する機能を提供します。この機能は、`final-results`と呼ばれます。結果の動作が`final-results`に設定されたクエリの結果は次のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176567/5df3f651-d1b2-c6fc-a612-2aa4b8999531.png)


Final クエリにより、クエリの「現在の」値を知ることができます。増分クエリとマテリアライザーションでは、常にFinal クエリが使用されます。

## 時間的に正しい結合

Fenl の中核機能の一つは、データセット間の時間結合を計算する機能です。
たとえば、「購入時に各購入ベンダーに対して何件の詐欺報告が提出されたか?」という質問（クエリ）が考えられます。

これは、以下の 1 行で書くことができます。

```javascript
FraudReport | count() | lookup(Purchase.vendor_id)
```
Dockerのwindows環境の構築

Windows環境でDockerをセットアップする手順は以下の通りです。

1. Dockerのインストール:
   DockerをWindowsにインストールするために、公式のDockerホームページ（https://www.docker.com/get-started）からDocker Desktop for Windowsをダウンロードします。ダウンロードが完了したら、インストーラを実行してDockerをインストールします。

2. Hyper-V有効化:
   DockerはWindows上でコンテナを実行するためにHyper-Vを使用します。Hyper-Vを有効化するために、Windowsの機能の管理からHyper-Vを有効にします。一部のエディションでは、BIOSの仮想化サポートを有効にする必要がある場合があります。

3. Docker Desktopの設定:
   インストールが完了したら、Docker Desktopを起動します。タスクトレイのアイコンから右クリックし、Settingsを選択します。設定画面で必要なオプションを構成します。一般的な設定には、リソース（メモリやCPU）の割り当て、共有ドライブの設定などがあります。

4. Dockerの動作確認:
   Docker Desktopが正常にインストールされたことを確認するために、コマンドプロンプトまたはPowerShellを開き、以下のコマンドを実行します。

   ```
   docker version
   ```

   バージョン情報が表示されれば、Dockerが正常に動作していることが確認できます。

5. コンテナの作成と実行:
   Windows上でDockerコンテナを作成して実行するには、Dockerイメージをダウンロードまたは作成し、`docker run`コマンドを使用します。公式のDockerハブ（https://hub.docker.com/）からイメージを検索し、必要なイメージを取得します。または、自分でDockerfileを作成してイメージをビルドすることもできます。

   例えば、以下のコマンドを使用してHello Worldコンテナを実行できます。

   ```
   docker run hello-world
   ```

   コンテナが正常に実行されると、メッセージが表示されます。

以上がWindows環境でのDockerのセットアップ手順です。これで、Dockerを使用してコンテナを作成し、アプリケーションを実行する準備が整いました。
Spring Boot3でどうしてもJPQL * ストアドファンクションを使いたくてFunctionContributorと向き合うことになったときの備忘録

## はじめに

[株式会社アルパカコネクト](https://alpaca-connect.com/)というWebサービスを運営しています。

このたび、弊社がバックエンドで使用しているSpring Bootを3.Xにアップデートすることになり、その際にHibernate 6.Xへのアップデートも必要となりました。

その際、
- JPQLを使い続けたい
- ストアドファンクションも使いたい（MySQL）

というニーズを満たすためにちょっと苦労したので、その備忘録になります。


## 朗らかに破壊的アップデート

ここでは触れませんが、javaxからjakartaへの以降を皮切りにHibernate周りも多数のアップデートが入り、JPAのブログで[ノリノリで解説](https://jpa-buddy.com/blog/hibernate6-whats-new-and-why-its-important/)されたりしています。

破壊的なアップデートもハイテンションに書けば許される感じがしていてナイスです。

しかし、いざストアドファンクションのマイグレーションを進めようとしたとき、記事のなかにはわずかにFunctionContributorの存在が匂わされているだけで、ググれどもググれども正解にたどり着けませんでした。

FunctionContributorの存在を知ったあとも公式ドキュメントらしいものにもたどりつけず、Stack Overflowなどの断片的な情報を頼りに実装まで進めることになりました。

頼みの綱のTwitterで検索しても１件しか引っかからなかったのは悲しかったです。

――ストアドファンクションを使わなければいいんじゃ、と思ったあなた。僕もそう思います。

けれども、そのためにFE資産を大量に修正する必要がでてくるので、BEだけのアップデート作業でなんとか済ませたかったんですよね……。

さて、前置きが長くなりましたが、始めます。

## before

Heibernate 5.x時代でJPQLとストアドファンクションを併用するために、以下のページのようにMySQLDialectを使用していました。

- [JPQLからデータベースのユーザー定義関数を利用する](https://qiita.com/rubytomato@github/items/bb05c75c918ba004575a)

しかし、Hibernate 6.XからはMySQLDialectがなくなってしまった、というのが今回の経緯です。おのれ。

## after

ざっくりと以下の2つが必要になります。

- FunctionContributorを使う
- META-INF以下に所定のフォルダ＆ファイルを作り、該当クラスを記述する

### 1.FunctionContributorの実装

```
public class MyFunctionContributor implements FunctionContributor {

  @Override
  public void contributeFunctions(FunctionContributions functionContributions) {
    functionContributions.getFunctionRegistry().registerNamed(
      "method_name",
      functionContributions.getTypeConfiguration().getBasicTypeRegistry()
        .resolve(StandardBasicTypes.STRING)
    );
  }
}

```

`registerNamed()`メソッドでストアドファンクションの名前を指定し、

`functionContributions.getTypeConfiguration().getBasicTypeRegistry()
   .resolve(StandardBasicTypes.STRING)`で解決時の型を指定します。

ここではStringに指定しています。

### 2.META-INF以下に所定のフォルダ＆ファイルを作り、該当クラスを記述する

上記のクラスを作って実装するだけではJPQLでクエリの発行までは行けても、マッピングの段階でエラーがでるようです。

現状、上記の実装はJAVAのSPIを使用しているようで、META-INFフォルダにファイルを作成する必要があります。

（拡張子なしのプレーンテキストファイル形式のファイルです）

#### ■パス
`/src/main/resources/META-INF/services/org.hibernate.boot.model.FunctionContributor`

#### ■ファイルの中身

上記パスで作成したファイルに、以下の記述を行います。

packageには、先程作成したMyFunctionContributorが置かれている場所を指定してください。

```
{package}.MyFunctionContributor
```

Hibernateが起動時にFunctionContoributorを使用しているクラスを見つけるために必要なようです。

僕の場合、これで実際のDBを使ってのテストが通るようになりました。


### 終わりに

「MyFunctionContributor」でぐぐっても **８** 件しか出てこなかったり、Twitterでも **1**件しかでてこなかったりするので、困ってるヒトはあまりいなさそうなんですが、
今後、Spring bootを3.Xにアップデートせざるを得なくなった方で、ストアドファンクションを使い倒している方の助けになれたら幸いです。
【Django】defaultの未設定によるmigrateエラーの対処について

## 何が起きたか
既にmakemigrationsとmigrateを行い、DBにデータを格納した後に新しいフィールドを追加したところmigrateエラーが発生しました。

## エラー内容
```
It is impossible to add a non-nullable field 'xxxx' to postproject without specifying a default. This is because the database needs something to populate existing rows.
Please select a fix:

 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)

 2) Quit and manually define a default value in models.py.

Select an option:
```

上記のようなエラーが発生。
内容としては…
**デフォルト値を設定せずに既存フィールドにxxxを追加することはできないよ。追加したければデフォルトの値を設定してね**
ということらしい。

## 対処方法
コンソールに表示された対処方法は2つ
**その１：今デフォルト値を入力してね**
**その２：makemigrationsするのやめてmodels.pyにデフォルト値を入力して再度試してね**
です。

:::note 
ちなみに、もう1つ対処方法があり、DBとmigrationsファイルを削除し再度クリエイトする方法があります。
こちらの方法は今回必要ないので行いません。
:::

今回は、２番のmakemigrationsを中断し、models.pyにデフォルト値を入力する方法を行います
。

対象となるモデルにデフォルト値をあたえます。
```python
text = models.CharFields(max_length=50, blank=True, null=True) 
```
或いは
```python
text = models.CharFields(max_length=50, default='') 
```
とします。
変更内容を保存し、再度makemigrationsを行ういます。

```python
Migrations for 'xxxxx':
  xxxxx\migrations\0003_testproject_text.py
    - Add field text to testproject
```
無事makemigratinsが完了しました。
DatabricksからGCPのCloud Translation Basicで翻訳を行う

作業の過程で使えるのかなと思った次第で。普通に使えました。

https://cloud.google.com/translate/docs/basic/translate-text-basic?hl=ja#translate_translate_text-python

# 事前準備

- Cloud Translation APIの有効化
- サービスアカウントの作成
- キーの取得: ローカルにjsonファイルをダウンロードします。ここでは、`credential.json`とします。

```json:credential.json
{
  "type": "service_account",
  "project_id": "my-project",
  "private_key_id": "...",
  "private_key": "-----BEGIN PRIVATE 
  ....
```

# ライブラリのインストール

```
%pip install google-cloud-translate==2.0.1
```

# キーファイルの格納

ここでは、[ワークスペースファイル](https://qiita.com/taka_yayoi/items/b0878db170c864d5bcf9)として格納します。

![Screenshot 2023-05-29 at 16.13.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/7132f3f5-e0da-2094-e7d4-c9c3d49f9c5f.png)

# 関数の定義

APIを呼び出す関数を定義します。`translate.Client.from_service_account_json`でワークスペースのパスを指定しています。

```py
def translate_text(target, text):
    """Translates text into the target language.

    Target must be an ISO 639-1 language code.
    See https://g.co/cloud/translate/v2/translate-reference#supported_languages
    """
    from google.cloud import translate_v2 as translate

    translate_client = translate.Client.from_service_account_json('/Workspace/Users/takaaki.yayoi@databricks.com/.../credential.json')

    if isinstance(text, bytes):
        text = text.decode("utf-8")

    # Text can also be a sequence of strings, in which case this method
    # will return a sequence of results for each text.
    result = translate_client.translate(text, target_language=target)

    print("Text: {}".format(result["input"]))
    print("Translation: {}".format(result["translatedText"]))
    print("Detected source language: {}".format(result["detectedSourceLanguage"]))
```

# 翻訳

```py
translate_text("ja-JP", "what is the difference between data warehouse and data lake?")
```

英語が日本語に翻訳されました。

```
Text: what is the difference between data warehouse and data lake?
Translation: データ ウェアハウスとデータ レイクの違いは何ですか?
Detected source language: en
```

料金に注意しながら活用します。

https://cloud.google.com/translate/pricing?hl=ja

### Databricksクイックスタートガイド

[Databricksクイックスタートガイド](https://www.amazon.co.jp/dp/B09V1YXFVQ/)


### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
Terraformで使うコマンド備忘録

# 初期化
```
terraform init
```

# プラン
```
terraform plan -var-file=./変数ファイル.tfvars #　-lock=falseをつければロック状態無視
```

# 実行
```
terraform apply -var-file=./変数ファイル.tfvars 
```

- しょーもないコマンドなんですけど久しぶりにいじったら忘れてたので
【TIPS】GitHub Copilotで使えるちょっと便利なTIPS【小ネタ】

GitHub Copilotをちょっと工夫して便利に使うTIPSです。

# コンテキスト情報をコメントで注入する

変換元となるテキストをコメントに入れることで、Copilotがその情報をもとに補完してくれます。
例えば、データベースのテーブル定義からLaravelのMigrationコードを生成する場合。

```tmp.php
<?php
declare(strict_types=1);

# 次のDDLをLaravel 9 のマイグレーションコードに変換してください
/*
    CREATE TABLE Games (
    GameID INT PRIMARY KEY,
    GameName VARCHAR(50) NOT NULL,
    Genre VARCHAR(50) NOT NULL,
    ReleaseDate DATE NOT NULL,
    ConsoleID INT,
    FOREIGN KEY (ConsoleID) REFERENCES GameConsoles(ConsoleID)
);
*/

return 
```
このように入力すると、以下のようにMigrationのコードが生成されます。
`return`と書いてるのは`return new class`を引き出すための誘導のためです。

```tmp.php
<?php
# (略）

return new class extends \Illuminate\Database\Migrations\Migration {
    public function up()
    {
        Schema::create('Games', function (Blueprint $table) {
            $table->integer('GameID')->primary();
            $table->string('GameName', 50)->nullable(false);
            $table->string('Genre', 50)->nullable(false);
            $table->date('ReleaseDate')->nullable(false);
            $table->integer('ConsoleID')->nullable(true);
            $table->foreign('ConsoleID')->references('ConsoleID')->on('GameConsoles');
        });
    }

    public function down()
    {
        Schema::dropIfExists('Games');
    }
};
```
与えたDDLをもとにコードを生成できました！
ちょっと手を加えなくてはいけないところはありますが、手動で書くより早く叩き台を作れますね。

# ちょっとした文字列の抽出・加工をやらせる
人力でやる場合は、正規表現を書いて抽出したり、スクリプトやオンラインツールで文字列の加工をやることが多いかと思いますが、GitHub Copilotにやらせればお使いのIDE上で手軽にできて便利です。

## 抽出の例

```
/* 
 * CREATE TABLE Games (
    GameID INT PRIMARY KEY,
    GameName VARCHAR(50) NOT NULL,
    Genre VARCHAR(50) NOT NULL,
    ReleaseDate DATE NOT NULL,
    ConsoleID INT,
    FOREIGN KEY (ConsoleID) REFERENCES GameConsoles(ConsoleID)
);
*/

# カラム名をカンマ区切りで書いて
# GameID,
```

カンマ区切りで出したい場合、最初の１ワードくらいを人間の手で書いてあげればあとは補完してくれます。
```php
# GameID,GameName,Genre,ReleaseDate,ConsoleID
```

この例では個数が少ないので人間が書いた方が早いかもしれないですが、件数が多くなるとCopilotを使った方が速くできそうです。
（純粋に、こういうだるいぽちぽち作業を自分の手でやりたくないので、機械にやらせたい）

## 加工の例
ついでに、snake_caseにもしてもらいましょう

```:補完前
# game_id,
```
```:補完後
# game_id,game_name,genre,release_date,console_id
```


# おわりに

GitHub Copilotにコードやコメントを書かせるのではなく、ちょっとした文字列の抽出・加工もやらせるというのは盲点だった方もいるのではないでしょうか。
また、ChatGPTでも同じようなコード生成や加工ができますが、GitHub　Copilot上でやれば、ウィンドウを切り替えたり、コピペせずにできるので便利です。

参考になりましたら幸いです。
皆様からのちょっとしたTipsもお待ちしております!
AtCoder用のDiscord Botを作った話

## これは何

https://github.com/ZOI-dayo/AtCoder_Discord_Bot

AtCoderの色々をしてくれるBotです

[maguro氏の記事](https://festival2023.npca.jp/bushi/maguro/)を見て、自分でも作ってみたかったのでDenoの練習代わりに作ってみました
(~~パクリです~~強い影響を受けています)

## 機能

- 当日のコンテストを通知(朝7時)
- コンテスト結果が出たとき、(設定したユーザーの)レート変動を通知
- 学校のAJLの順位変動を通知

AJL関係を入れている辺りからお察しかもしれませんが、「学校のPC部のDiscordサーバー」に導入することを想定して作ってます

機能が少ないので、なにか案があればコメントかissueかプルリクください

## 使い方

1. denoをセットアップ
1. Discord API Tokenを作っておく
1. [GitHub]をクローン
1. プロジェクト直下に.env.localファイルを作成し、`DISCORD_TOKEN=〇〇〇〇`と記述
1. `$ deno task start`

([僕の自鯖で動いているBotインスタンス](https://discord.com/api/oauth2/authorize?client_id=1105087451426463805&permissions=3072&scope=bot)もいるのですが、デバッグしてるときにバグって荒らしたり、いきなりサ終するかもなので、各々でホストすることをおすすめします)

## コマンド

設定などは、Discordのスラッシュコマンドで行うようにしています

- /atcoder set school {学校名} {中学/高校}
AJL用に学校を登録します
学校名は正式名称でお願いします(AJLのページにあるもの)
中高は手動選択です

- /atcoder set channel
Botがいろいろ送信するチャンネルを設定します
コマンドを打ったチャンネルが送信先として保存されます

- /atcoder register {AtCoderユーザー名}
これを実行すれば、以降のコンテスト結果通知で自分の結果が表示されるようになります

## 開発について

### 言語

AtCoderの色々をやってくれるBotなので、どうしてもスクレイピングやJSONからは逃げられそうにない...と思い、JS周辺から選ぶことにしました
で、DiscordのBotであってWebページでないので素のJavaScriptは使えないです
となるとNode.jsか? と思いましたが、せっかくなので使ったことのないDenoを触ってみることにしました

### Discord関連

discordenoというライブラリがあったのでそのまま利用しました
DiscordのBotは昔ちょっとだけ作ろうとしたことがあって、「Guildってサーバーのことだよな〜?」ぐらいの知識だったんですが、まあなんとかなりました

### スクレイピング

まず、AtCoderの一部のページは、URL末尾に「/json」をつけるとJSON形式でデータがもらえます
(ただ最近のDDoS騒動の影響で一部のページはログインしないと見れない+アクセス過多だと止められるので注意)
たとえば<https://atcoder.jp/contests/abc300/results/json>などです
これは`await (await fetch('https://atcoder.jp/contests/abc300/results/json')).json();`でOKです

そうでないもの(例えばコンテスト予定やAJL関係)は普通に`fetch('hoge').text()`を`new DOMParser().parseFromString(text, "text/html");`に放り込んでDOM操作です
そういえば、AJLの結果って<https://img.atcoder.jp/ajl2023/output_high_school.html>で見れるんですが、どうしてimg.atcoder.jpに配置されてるんでしょう...?謎

### データ保存

「どのチャンネルに送信するか」とか、「どの学校か」とかはBotが停止しても保存されててほしいですね
なので、まあ普通にJSONに書けばいいんですが、あまり使ったことなかったのでSQLiteに入れています
sqliteとかいうそのままな名前のライブラリがあったのでそれ入れて適当実装です

### 時間管理

例えば「コンテストがある日の朝7時に関数を実行」というやつです
日付指定で実行、という便利な関数が見つからなかった(あるのかもしれませんが)ので、`setInterval(() => {}, (予定時刻[ms]) - (現在時刻[ms]))`でなんとかしました

ただ、「コンテストのある日の朝7時」を取得するときに、「指定時間以前で最も近い日本時間0:00」を見つけ出す方法がよくわからなかった(date_fnsにstartOfDayという関数はあるのですが、世界標準時の0:00を返してきた)ので、DateTimeライブラリを自作しました

ゴミコードですが、まあ今回の用途では十分でした

### 開発環境

Denoか〜、Web系技術だからVSCodeが得意そうだな〜、と思い、これまた使ったことのなかったGitHub Codespacesを使ってみました

普通のFreeプランでは120CPU時間/月しかないので、最低ランクの2Coreマシンでも60時間/月しか使えないのがちょっと不安ですが、使用感はかなり良かったです
また小さなプロジェクトをやることになったら使ってみようと思います

## 感想

最初思ってたよりは結構コードを書く羽目になりました...ここら辺の見積もりをちゃんとできるようになりたいですね
いつもBotを作る時は途中で飽きてやめてしまうので、動作まで持って来れて良かったです
.gzのログファイルから、条件付きで行数カウントするコマンド

```
zcat access.log-xxxxx.gz | grep '27/May/2023:18:5' | wc -l
```

grep で絞り込んだ結果を、カウントしてくれます。
IPで絞り込むと、どれくらい来てるカナーと分かるかも？
【Power Automate Desktop】(UI要素エラー)：UI要素が見つかりません

自動化ツールである「Power Automate Desktop(以下、PAD)」を使って繰り返しの業務(もしくは操作)を楽にしようととしてフローを作る際に、Webページの操作でいつもぶつかる問題があると思います。その問題について解決できる方法の中で１つを紹介したいと思います。

## 初めに
PADで何かしらの要素にアクションをかけたい場合にはまず、要素を特定する必要があります。これにはマウス一回のクリックで対象UIが選択できるような仕組みがあるのですごく便利ですね。そのため、リンクをクリックしたりテキストボックスに文字を入力するなど、フローを作るのが簡単にできますが、そこで想定外のエラーが起こってしまうことが少なくはないです(少なくとも私にはそうでした)。ちゃんとUI要素を選択もしたし、セレクターのメニューまで開いて詳細を確認しても問題ないように見えたので原因探しに時間をかけたりした覚えがあります。

ちなみに、PADでのUI要素選択に関しては以下になります。
マウスのポインターでUI要素を当てると、領域のサイズによって赤い枠で表示されます。ここでCtrl + 右クリックで選択完了！これで簡単に特定ができると思いますが、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885338/703eea44-057d-ae97-cf54-4c16a1c1b5cc.png)

今回ではQuiitaのメインページをEdgeブラウザを開き、「公式コラム」のテキストを取得してメッセージボックスに表示する簡単なフローを作る中で起こる問題を解決するシナリオで進めていきたいと思います。

## エラー発生
Qiitaメインページを開き、取得するテキストを確認し、この要素をUI要素選択メニューからピックアップします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885338/5e421e35-0561-998b-7f8e-f0d19103709a.png)

完成したフローはこちら
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885338/6a32970d-43d8-63cb-aab3-b74a729c9840.png)

テストで実行してみたらエラーになりました。（？！）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885338/f99c92af-c6d5-d23e-b28f-0f3e6fe41b6f.png)

エラーの詳細はこちら
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885338/40a556a9-370c-fc49-83e4-b04c7c932b10.png)




## 解決方法
UI要素のセレクターをパッと見た感じ、特に問題はないように見えますが、設定にミスがあるはずなので、修正してみようと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885338/90cdc936-21b8-2cf0-04dd-7ec2c2ded29a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885338/fcb8db5b-991d-e20a-a23f-546119782478.png)


よく見たら、
フローを作成する際、UI要素選択で設定された条件にあるDivのidと、ブラウザで確認できるHTMLソースに定義されているDivのidが異なっていることがわかります。このidが動的に変わるので固定値ではUI要素指定条件に合わなくなりますね

```diff_html
- New2GlobalHeader-react-component-688cb473-f6e3-4901-b588-d0dc6c2b68f8
+ New2GlobalHeader-react-component-dee17d3c-0f05-43eb-be2b-622ba1337ba4
```

ですので、Divのid条件を外しておきます。
他の条件にも動的なidやclassなどが入っているかチェックしましょう。
（場合によってはこれが他の要素との競合とかが発生する可能性がゼロではないため、確認する必要があります）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885338/3f9b0dd0-d66f-fb55-f94d-df43d94b218a.png)

その後、再度のテストで確認したところ、無事にフローが最後まで動いてくれました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885338/972cb997-27fd-c422-f76a-8e52ab2d6376.png)



## 終わりに
簡単なフローから一度は詰まってしまうポイントについて書いていました。
もし、似たような問題で困っている方に少しでも役に立ったらいいなと思います。
以上！
Canonical URLとは何か？



`Canonical URL（カノニカルURL）`とは、ウェブページのコンテンツが複数のURLでアクセス可能な場合に、その中から主となるURLを指定するためのメソッドです。

検索エンジンはこれを見て、同じまたは非常に似たコンテンツを持つページ群から「正式な」または「標準的な」ページを理解します。そのため、検索エンジンのランキングにおける重複コンテンツの問題を解決する手段ともなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/987057/001fa3c6-207c-1a77-dd57-4bf44707a9ad.png)


## なぜ必要なのか？

ウェブサイト上に同じ内容のページが複数存在すると、それぞれが検索エンジンにインデックスされ、重複コンテンツとみなされます。

これは検索エンジンランキングに悪影響を及ぼす可能性があります。Canonical URLを使用すると、これらのページが本来一つのコンテンツを表していることを検索エンジンに伝えることができます。

## どのように指定するのか？

Canonical URLは、HTMLの`<head>`タグ内に`<link rel="canonical" href="https://www.example.com/sample-page/" />`のように記述します。ここで`href`属性には、そのページのCanonical URLを指定します。

## Canonical URLの注意点

Canonical URLの指定は効果的ですが、間違った使い方をすると逆に検索エンジンの評価を下げてしまう可能性もあります。
例えば、全く異なる内容のページに対して同じCanonical URLを指定するなどは避けるべきです。

また、Canonical URLは他のSEO対策と同様、その効果を感じるまでには時間がかかることも覚えておきましょう。

## 参考URL

https://bizturner.com/seo/how-to-use-canonical-url/
【Paiza問題集】標準出力/出力形式を指定して出力

# Paiza問題集

## 標準出力/出力形式を指定して出力

## Step01 2つの文字列を出力
```Python:step01
"""
2つの文字列を出力
https://paiza.jp/works/mondai/stdout_primer/stdout_primer__specific_format_step1
"""

# 入力を受け取る
S = input()
T = input()

# 文字を出力する
print(f"{S} + {T} = {S+T}")
```

# step02 文字列とN個の整数の出力
```Python:step02
"""
文字列とN個の整数の出力
https://paiza.jp/works/mondai/stdout_primer/stdout_primer__specific_format_step2
"""
# 数字を受け取る
N, A, B = map(int, (input().split()))

# 整数を表示する
for i in range(N):
    if i == N-1:
        print(f"({A}, {B})")
    else:
        print(f"({A}, {B})", end=', ')
```

# Step03 九九表を罫線入りで出力
```Python:Step03
"""
九九表を罫線入りで出力
https://paiza.jp/works/mondai/stdout_primer/stdout_primer__specific_format_step3
"""

# 九九表を表示
# 縦
for i in range(1, 10):
    # 横
    for j in range(1, 10):
        print(f'{i * j:>2}', end="")
        if j == 9:
            print()
        else:
            print(end=" | ")
    # 横の区切りを表示
    if i < 9:
        print(f'{"="}' * ((2 * 9)+(3 * 8)))
```

# Step04 ペアの数値の入った表を罫線入りで出力
```Python:step04
"""
ペアの数値の入った表を罫線入りで出力
https://paiza.jp/works/mondai/stdout_primer/stdout_primer__specific_format_step4
"""

# 数字を受け取る
H, W, A, B = map(int, input().split())

# 縦
for i in range(H):
    # 横
    for j in range(W):
        if j == W-1:
            print(f'({A}, {B})')
        else:
            print(f'({A}, {B})', end=" | ")
    # 区切りを表示
    if i < H-1:
        print("="* ((6 * W)+(3 * (W-1))))
```

# Final問題 ペアの数値の入った表を罫線入りで出力2 
```Python:Final問題
"""
【出力形式を指定して出力】ペアの数値の入った表を罫線入りで出力2 
https://paiza.jp/works/mondai/stdout_primer/stdout_primer__specific_format_boss
"""

# 数字を受け取る
H, W, A, B = map(int, input().split())

# 縦
for i in range(H):
    for j in range(W):
        if j == W-1:
            print(f'({A:>9}, {B:>9})')
        else:
            print(f'({A:>9}, {B:>9})', end=" | ")
    if i < H-1:
        print("=" * (22 * W + 3 * (W - 1)))
```
docker でexpressアプリケーションを作成して、imageをbuild します。

# expressアプリケーションを作成します。
localhost:3000ポートにHello worldを表示させるコードです。

```javascript:indexjs
    const express = require("express");
    const app = express();
    const PORT = 3000;
    
    app.get("/", (req, res) => {
      res.send("hello world");
    });
    
    app.listen(PORT, () => {
      console.log(`server is running on port ${PORT}`);
    });
```
ブラウザには、下記の様に表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654025/97b8252b-ffb0-3bf0-f17f-a8e57d7db468.png)

# Dockerfileを記述します。
```dockerfile:Dockerfile
    # ベースイメージを設定します。
    FROM node:lts-alpine
    # 実行ディレクトリを作成します。
    WORKDIR /usr/src/app
    #　ローカルのカレントディレクトリをapp/ディレクトリにコピーします。
    COPY . /usr/src/app/
    #　npm install を実行します。
    RUN npm install
    # Dockerのポートを設定します。
    EXPOSE 3000
    # コンテナを実行するコマンドです。
    CMD ["node", "index.js"]
    
```

# Imageをbuildする
```terminal:terminal
    docker build -t node-app:1.0 .
```
最後の.は、Dockerfileの場所を指定します。カレントディレクトリーの場合は、"."と記述する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654025/dd51fd87-f4b2-b56f-a650-b5d7b217895e.png)

# 最後に、imageファイルを実行して、shellから接続してみます。
```terminal:terminal
    docker run -d --name test -p 3000:3000 node-app:1.0
    docker exec -it test sh 
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654025/5d5f9972-f5a6-febf-b25c-f8a0d4b063a0.png)

実行したコンテナのappディレクトリにすべてコピーされていることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654025/63162044-d0f4-df42-dd5c-43dc860eae2e.png)

# 最後に
今回は、expressのイメージをビルドすることができました。次は、mysqlのコンテナを作成してみます。
pythonのctypesモジュールの注意点

# 0.環境説明
```
python: Python 3.9.0
gcc:gcc version 11.3.0 (GCC)
```
# 1.ctypesのドキュメント
[ctypes --- Pythonのための外部関数ライブラリ](https://docs.python.org/ja/3/library/ctypes.html)

# 2.dllファイルの作成方法
以下のサンプルコードをpython上で実行できるようにdllファイルに変換していきます
```c:dll_c.c
#include <stdio.h>
#include "dll_c.h"

void doPrint(){
    int value = 42;
    int* address = &value;//pythonでは実行しえない処理

    printf("Address: %p\n", (void*)address);
    printf("Value at address: %d\n", *address);
}
```
```c:dll_c.h
extern void doPrint();
```

シンプルさを得るために " __declspec(dllexport)"などの記法は割愛します。

以下のコマンドでdllファイルの作成を行います
```
gcc -shared -fPIC dll_c.c -o dll_c.dll
```

# 3.pythonでの実行方法

```python
import ctypes
import os
os.add_dll_directory(os.getcwd())

lib=ctypes.CDLL("dll_c")
doPrint=lib.doPrint
doPrint.restype=None
doPrint()
```

このコードの注意事項は
```python
os.add_dll_directory(os.getcwd())
```
の部分
この処理を行わないと
```
FileNotFoundError: Could not find module 'dll_c' (or one of its dependencies). Try using the full path with constructor syntax.
```
というエラーがでてしまう。これはエラー文にあるようなフルパスを用いた方法でも同様の結果が得られる。
[PATH通してるのにctypesで`FileNotFoundError: Could not find module (or one of its dependencies)`](https://qiita.com/koyayashi/items/2bb1bafc33249aa4d7f3#:~:text=import%20ctypes%20import%20os%20dll%20%3D%20ctypes.CDLL%28R%22pathtomylib%22%29%20%23,if%20os.path.isdir%28p%29%3A%20os.add_dll_directory%28p%29%20dll%20%3D%20ctypes.CDLL%28R%22mylib%22%29%20%23%20%E5%95%8F%E9%A1%8C%E3%81%AA%E3%81%97)

上記記事を読んでなんとか解決した。
どうやらPython3.3から上記処理を行わないとエラーを吐くようになった模様。

# 4. 補足1(実行環境について)
インタプリンタモード、またはJupyter NotebookなどのCが実行されるべきじゃないような場所で標準出力や入力を行うとクラッシュするかフリーズする。
[ctypes --- Pythonのための外部関数ライブラリ](https://docs.python.org/ja/3/library/ctypes.html)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557059/ad7a92cb-4199-6f9a-21f4-173adc7b3a19.png)

ctypesモジュールのドキュメントより。回避策はcoutを使う（未検証）かそもそもc言語側で標準出力を使用しない、通常環境でpythonを実行以外にないと思われる

# 5.補足2(依存関係について)
*__未検証なので不正確な情報あり__*

オリジナルで書いたコードが追加でdllファイルを求める場合はadd_dll_directory関数でそのdllファイルがある場所を追加したほうがいい


# あとがき
間違ってる箇所や追加したほうがいい箇所があった場合はコメントで書いてくれると嬉しいです。
以下に追記履歴を書きます
・gccのタグを追加(Visual Studioに回避する策も見られたので)
・コンパイルオプションにfPICを追加
Atcoder-cliとonline-judge-toolsの個人的ワークフロー

# はじめに
最近、挫折していたAtCoderに再トライしています。
その際に、[Atcoder-cli](https://github.com/Tatamo/atcoder-cli)と[online-judge-tools](https://github.com/online-judge-tools/oj)を使用しています。
忘れがちなので、ここに個人的なワークフローをメモします。

## ⓪【事前準備】環境構築
[ここは差異はないのでこちらを見ます。](https://writerman.hatenablog.jp/entry/2021/12/16/000655#:~:text=%E3%82%81%E3%81%BE%E3%81%97%E3%81%9F%E3%80%82-,%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89,-%23%20atcoder%2Dcli%E3%81%AE)(偉大な先人に感謝)

## ①コンテストをローカルにクローン
```
acc new abcN
```
Nは任意の数字。(筆者はAtCoder Beginner Contestによく参加するので)
URLのhttps://atcoder.jp/contests/ 以下に記述してある部分です。
## ②問題のディレクトリに入る
```
cd abcN
cd a
```
ACCともはや関係ない初歩ですが、焦って忘れるのでメモ。
ちゃんとカレントディレクトリを確認しましょう。
## ③提出するソースコードを作る
### Windows
```
New-Item main.py
```
### Linux
```
touch main.py
```
ACCはソースコードを生成しないので、自分で作成する必要があります。
~~ACCともはや関係ない~~
VS Code上のGUIで作ってもいいかもしれないです。

## ④問題を解く
頑張ってください。

## ⑤テストケースの検証
```
oj t -c "python main.py" -d ./tests/
```

## ⑥提出
```
acc submit main.py 
```


# 参考
https://writerman.hatenablog.jp/entry/2021/12/16/000655
HerokuにデプロイしたRailsアプリが「Heroku | Welcome to your new app!」と表示される際の対処法

## 概要
HerokuにデプロイしたRailsアプリが「Heroku | Welcome to your new app!」と表示される際の対処法を記述させて頂きます。
![スクリーンショット 2023-05-29 14.21.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2961835/a807a2fb-4503-0638-e446-365632b4738f.png)


## 原因
エラーメッセージによれば、`Bundlerはローカル環境（x86_64-darwin-22、Mac OS）で動作するように設定されたGemfile.lockを使っていますが、Herokuの環境はLinux（x86_64-linux）なので問題が生じています。`という内容です。

## 対策
Railsプロジェクトのディレクトリに移動します。そして、以下のコマンドを実行します。
```
bundle lock --add-platform x86_64-linux
```
このコマンドを実行すると、Gemfile.lockにHerokuのLinuxプラットフォームが追加されます。その結果、Gemfile.lockファイルの最下部に以下のような行が追加されます（他のプラットフォームがすでにリストされている場合もあります）。
```Gemfile.lock
PLATFORMS
  x86_64-darwin-20
  x86_64-linux
```
上記が完了したら、あとはコミット、プッシュを行えば解決致します。
aptコマンドが社内プロキシのユーザー認証に阻まれた時の対応方法 

# 社内プロキシ環境下でのLinux開発環境について
社内プロキシ、めんどくさいですよね。
とはいえ、情報セキュリティの観点から社内プロキシは必要不可欠なのでうまく付き合うしかありません。
Windows中心の業務環境ならpacファイル読ませて、ブラウザでユーザー認証を求められたら設定されているユーザー名とパスワードを入力すれば特に運用には困りません。
ですが、これが開発用のLinux端末となると話は別です。<b>aptコマンドがリポジトリに届かない！</b>
これではupdateどころかvimのインストールもままならないので、どうにかプロキシ認証を通します。

ちなみに、windowsPCでのプロキシに関する設定はpacファイルを用いるパターンが多いと思いますが、あくまでpacファイルはブラウザがWebサーバへアクセスする際にHTTP,HTTTPSプロトコルの伝送を中継してくれるプロキシサーバを指定するものです。
このあたり、WindowsPCでブラウザからインターネットに接続する時だけにプロキシのユーザー認証をしていると忘れがちになってしまいますね。
# 環境
Ubuntu 20.04 LTS
社内プロキシサーバーを経由する際はパスワードによるユーザー認証を要求する


# 手順
- aptコマンドに紐付けられているconfディレクトリ内を編集
```
$ sudo vi /etc/apt/apt.conf.d/proxy.conf
```
- 開いたconfファイル内に下記の内容を記述
```
Acquire::http::Proxy "http://{ユーザー名}:{パスワード}@{プロキシのIPアドレス}:8080";
Acquire::https::Proxy "http://{ユーザー名}:{パスワード}@{プロキシのIPアドレス}:8080";
Acquire::ftp::Proxy "http://{ユーザー名}:{パスワード}@{プロキシのIPアドレス}:8080";
```
- `apt update`するなりして、aptコマンドがリポジトリに届いていれば成功。

# 環境変数でのプロキシユーザー認証との違い
Linuxでのプロキシユーザー認証には他にもexportコマンドでの環境変数の設定方法がありますが、こちらはあくまでユーザー単位での認証となります。
`apt`コマンドはroot権限を必要としますので、環境変数によるプロキシのユーザー認証の範囲外になります。
ですので、コマンドのconfファイルにプロキシに関する情報を記載する必要があります。
Symfony CLI のインストールとプロジェクト作成

# はじめに
Symfony CLIの導入とプロジェクト作成について、その手順を確認します。

# 動作環境と前提事項
本記事は、以下の環境で動作確認しています。
```
OS: macOS Venture 13.3.1
Chip: Apple M1 Pro
```

### 前提事項
- `symfony cli`の導入には[Homebrew](https://brew.sh/index_ja) を使用します。ローカルに`Homebrew`がない場合は先にインストールしておいてください。

https://qiita.com/shota_tanaka/items/59eb2ca21afdbba3c1bb

- また、`Symfony CLI`を使用したプロジェクトの作成には`PHP`がインストールされている必要があります。手っ取り早くPHPをインストールする場合は`brew install php`を実行してください。

# Symfony CLI のインストール

[公式ドキュメント](https://symfony.com/download#step-1-install-symfony-cli)に従い`brew`コマンドでインストールします。
```shell
brew install symfony-cli/tap/symfony-cli
```

# Symfony プロジェクトの作成
こちらも[公式ドキュメント](https://symfony.com/doc/5.4/setup.html#creating-symfony-applications)に従いつつ、バージョン`5.4`の環境を作成します。
```shell
symfony new my_project_directory --version=5.4
```
> [OK] Your project is now ready

# サーバ起動
`Symfony`コマンドでサーバーを起動します。[[公式ドキュメント](https://symfony.com/doc/current/setup/symfony_server.html#getting-started)]
正しくインストールできていればWebサーバーが起動します。
```shell
symfony server:start
```
> [OK] Web server listening

# おまけ
`controller`の定義は[こちら](https://qiita.com/shota_tanaka/items/20bb8ebf2d4a9de60da8)を参考にしてみてください。

https://qiita.com/shota_tanaka/items/20bb8ebf2d4a9de60da8
フロントエンドとバックエンドの違い

ここでは、自身のアウトプットとして「フロントエンド」と「バックエンド」の違いを書いていきます。


フロントエンド
これはユーザーが直接見たり触れたりする部分を指します。具体的には、ボタンを押したり、情報を入力したりする部分です。これは"クライアントサイド"とも呼ばれ、プログラムはウェブブラウザで実行されます。フロントエンド開発では、HTML、CSS、JavaScript、TypeScriptなどの言語が主に使われます。フロントエンドエンジニアはこれらの言語を使ってウェブサイトやウェブアプリケーションの見た目を作ります。さらに、ユーザーインターフェイスのデザインや、SEOに配慮した設計も行います。

バックエンド
バックエンドは、サーバーサイドやデータベースシステムといった、ユーザーが直接見ることのない部分を指します。ユーザーが入力したデータの処理、データベースへの保存、検索結果の出力などを担当します。バックエンド開発には、Java、JavaScript、PHP、Python、Rubyなどの言語が使われます。バックエンドエンジニアはデータの処理を実装し、データベースの設計や構築、運用、保守を行います。バックエンドエンジニアになるには、APIの作り方やデータベースの知識を学ぶ必要があります。