OmniAICreator/Qiita-1.07M huggingface dataset:
【Teamsバグ？Bot？】「Dynamics 365 アプリでレコードを検索して共有する」がすべてのチャットに返答される件

## 謎のDynamics 365 BOTが突然動き出した
2024/10/24の朝から起きてます

Teamsのグループチャットに謎の自動返答機能が表れた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524942/e9ac486f-d58c-3b9b-721f-762ccabd4af5.png)

## 原因
Dynamics 365 Salesと連携しているグループチャットにはこのBOTが追加されているようです。
※明確な原因究明はできておりません

## 解決策
一時的な解決策はあります。

メッセージ入力欄＞＋ボタン＞Dynamics365 を右クリック＞アンインストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2524942/4b801794-7432-6890-07db-b2d73069bc12.png)


ただし、再度営業案件などをグループチャットに連携すると再度Dynamics365さんが土足で上がり込んできます。

## 今後
どこかに設定があればそれで制御できるようになってほしい。
もしかしたら既にあるのかも...?
PowerPlatform管理センターの機能設定、Teams管理センター、アプリ詳細設定を確認したものそれらしき設定はなく。

## 公式サイト
プレビュー機能らしい
https://learn.microsoft.com/ja-jp/dynamics365/sales/teams-integration/share-dynamics-records-in-teams
AWS SessionManager の SSH接続を使いやすくする

## 前置き

- SessionManagerを用いたSSH接続が利用できる環境
- AWSアカウント複数持ちで、プロファイル毎に管理している場合
- InstanceIDが動的で、いちいち調べるのが面倒な場合
- とりあえず、同ネームタグの起動しているどのサーバーでもいいから接続したい場合

InstanceIDを調べずに、サーバー接続できるスクリプトのご紹介です。
このスクリプトを設定したら以下のコマンドだけでssm接続できます。

```bash
> ssh ssm.[プロファイル名].[ネームタグ名]
```

## 設定方法

**（Git For Windows の GitBashで検証しました。クライアント環境に合わせて調整してください）**

### ■ 1. ファイルを配置する

`[ユーザー]/bin/` フォルダに以下のコードをファイルとして配置する。
※パスの通ったフォルダであればどこでも大丈夫です。

```bash:ファイル名：aws-ssm.sh
#!/bin/bash

# AWS-SSM ProxyCommand
# Configure to ssh_config
# 
# ------------------------------
# Host ssm.*
#	ProxyCommand aws-ssm.sh %h %p
#   User ec2-user
# ------------------------------
#
# SSH Command: ssh ssm.[Profile].[NameTag]

HOST_STR=$1
HOST_ARR=(${HOST_STR//./ })
INSTANCE_ID=$(aws --profile ${HOST_ARR[1]} ec2 describe-instances --filters "Name=tag-value,Values=${HOST_ARR[2]}" "Name=instance-state-name,Values=running" --query "Reservations[0].Instances[0].InstanceId")
INSTANCE_ID=${INSTANCE_ID//\"/}
aws ssm start-session --profile ${HOST_ARR[1]} --target ${INSTANCE_ID} --document-name AWS-StartSSHSession --parameters "portNumber=$2"
```

### ■ 2. configファイルを追記する

`[ユーザー]/.ssh/config` ファイルに以下の記述を追記する

```bash
Host ssm.*
    ProxyCommand aws-ssm.sh %h %p
    User ec2-user
```

ユーザー・ポートや鍵の指定等は環境に合ったものへオーバーライド等して下さい。

```bash
Host ssm.[プロファイル名].*
    ＜＜その他設定＞＞
```

## 注意事項

「.」ドット区切りで分割しているので、既にプロファイル名やネームタグにドットが含まれる場合は別な記号で分割する様に調整が必要となります。

もっと効率のいいものがあれば教えて下さい。
uptime kuma 入門

# Uptime kuma 入門
## Uptime kumaとは？
Uptime Kumaは，シンプルで使いやすいウェブサービス監視ツールです．

### 主な機能
- サービス監視: HTTP(S)，TCP、DNS、Pingなど様々なプロトコルでウェブサイトやサーバーの稼働状況を監視できます．
- HTTPSの証明書監視：証明書の有効期限などの通知も行うことができます．
- ダッシュボード: 監視対象のステータスや応答時間などを視覚的に表示します．
- アラート通知: サービスがダウンした際に，Slack，Emailなど多様な方法で通知を受け取れます．
- カスタムステータスページ: ユーザー向けに監視対象のステータスを公開できるページを作成できます．

### 特徴
- オープンソース: GitHubで公開されており，無料で利用できます．
- シンプルな設定: デプロイ後，WebUIから簡単に監視設定が行えます．
- 多言語対応: インターフェースが多言語に対応しており，ユーザーフレンドリーです．
- 軽量: 必要最小限の機能に絞られているため，リソース消費が少なくデプロイが容易です．

## uptime kuma 稼働方法
ここではdockerを用いた稼働方法を説明します．
### 要件
- docker 
- 監視対象への疎通

### 起動方法
~~~ 
docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:1 
~~~

このコマンドで，起動したホストの3001番ポートでuptime kumaのインターフェースにアクセスできるようになります．

## 設定方法
### 初回起動
この画面のように，初回起動時はID/PWの登録を求められるので，任意のものに設定する．
![スクリーンショット 2024-10-24 13.50.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3291593/28f9c4c8-abaa-518a-81f4-18bc63393190.png)

### ホストの登録
ログインが成功するとこのような画面に入れます．

![スクリーンショット 2024-10-24 13.51.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3291593/d2f076a9-92c6-c6e8-4691-74a73bb96ccb.png)

左上の監視の追加から，監視タイプや対象のIPなどを設定します．
![スクリーンショット 2024-10-24 13.52.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3291593/6cf527b1-7074-883a-e44b-766bd29b50c9.png)

### 通知について
ホスト追加画面の”通知設定”右上から追加可能です．
Slack, LINE, Telegramなど幅広い通知が追加可能です．
追加したいものに沿って追加してください．

![スクリーンショット 2024-10-24 13.53.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3291593/5ed96552-02a6-ab7a-d060-8e76d8e1569c.png)

成功するとこのような通知がきます．
![スクリーンショット 2024-10-24 13.57.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3291593/9952fb5e-c87c-0c48-b2cf-7e47027f7178.png)

## 最後に
正常に登録できるとこのような画面になります．
証明書の期限切れや，サーバの疎通喪失などにいち早く気づくことが可能になると思われます．
![スクリーンショット 2024-10-24 13.55.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3291593/0bb6afd9-6090-2ee6-60e5-91de4d6b3457.png)
1. Pythonでのブラウザ制御のマスター：AIブラウザエージェントを構築する方法

![AI Agent.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916556/d7767e91-6353-2d7a-cecf-f9d5fa059714.jpeg)

Pythonは、シンプルで強力なプログラミング言語で、様々な用途に使われています。その中でも、ブラウザの自動制御は、ウェブ開発者や自動化エンジニアにとって非常に便利な機能の1つです。この記事では、Pythonを使ってAIエージェントを構築し、ブラウザを自動制御する方法について説明します。

Pythonでのブラウザ制御
Pythonでブラウザを制御するための一般的なライブラリとして、SeleniumやPlaywrightがあります。これらは、ブラウザ操作の自動化に非常に便利で、ウェブページの操作やデータの収集などを効率的に行うことができます。

from selenium import webdriver

driver = webdriver.Chrome()

# Googleを開く
driver.get("https://www.google.com")

# 検索ボックスに文字を入力
search_box = driver.find_element_by_name("q")
search_box.send_keys("Pythonブラウザ自動化")
search_box.submit()

# ページのタイトルを出力
print(driver.title)

# ブラウザを閉じる
driver.quit()
AIエージェントによるブラウザ操作
AIエージェントによるブラウザ操作を行うためには、AIモデルにブラウザ上の操作を学習させ、特定の条件に応じて自動的に動作するようにプログラムします。これにより、例えばユーザーの操作を模倣するボットを構築したり、特定のタスクを効率的に処理することが可能になります。
Pythonを使って、簡単にAIエージェントがブラウザを操作するコードを以下に示します。
from selenium import webdriver
from time import sleep

def ai_browser_agent(url, task):
    driver = webdriver.Chrome()
    driver.get(url)
    
    # タスクの種類に応じて処理を分ける
    if task == "search":
        search_box = driver.find_element_by_name("q")
        search_box.send_keys("AIブラウザエージェント")
        search_box.submit()
        sleep(5)
    
    print("AIエージェントによるブラウザ操作完了")
    driver.quit()

# エージェントの起動
ai_browser_agent("https://www.google.com", "search")
AIとブラウザ制御の未来
AI技術の進展により、ブラウザの操作はますます高度化しています。自動化エージェントを利用することで、複雑な操作やユーザーインタラクションを効率的に処理できるため、今後さらに多くの分野で活用されることが期待されます。
Read Full story in English: https://cookab.net/codes/mastering-browser-control-with-python/
【超簡単！】絶対に使わない逃げるリンクの作り方

## 初め
ふと、思ったんですね。踏めないリンクがあったらなって

## 作り方
### 使用言語
HTML,CSS,JavaScript

### コード
```index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <title>逃げるaタグ</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <a href="goal.html" id="nigeteruLink">クリックしてみて！</a>

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

```
```style.css
body {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
}
#nigeteruLink {
  position: absolute;
}
```
```script.js
const link = document.getElementById('nigeteruLink');

link.addEventListener('mouseover', moveLink);

function moveLink() {
    const x = Math.floor(Math.random() * (window.innerWidth - link.offsetWidth));
    const y = Math.floor(Math.random() * (window.innerHeight - link.offsetHeight));
    link.style.left = x + 'px';
    link.style.top = y + 'px';
}


```

## 完成動画


![ダウンロード.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799198/c5a66098-5d51-3b6c-8b66-c0c44ccb0f25.gif)


## おまけ
光の速さでマウスを動かしてクリアした人のためにリンク先のページも作っておきます
```goal.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <title>おめでとう！</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <p class="fade" id="message1">おめでとう！</p>
    <p class="fade" id="message2">でも、</p>
    <p class="fade" id="message3">暇なん？</p>
    <script src="goal.js"></script>
  </body>
</html>

```

```style.css
.fade {
  font-size: 30px;
  opacity: 0;
  transition: opacity 1s ease-in-out;
}

.visible {
  opacity: 1;
}

```

```goal.js
function fadeSequence() {
  const messages = [
      document.getElementById('message1'),
      document.getElementById('message2'),
      document.getElementById('message3')
  ];

  let current = 0;

  function showNext() {
      if (current > 0) {
          // 前のメッセージをフェードアウト
          messages[current - 1].classList.remove('visible');
      }
      if (current < messages.length) {
          // 次のメッセージをフェードイン
          messages[current].classList.add('visible');
          current++;
          // 次のメッセージを表示するまでの待機時間（表示時間 + フェード時間）
          setTimeout(showNext, 3000); // 3秒間表示
      } else {
          // 全てのメッセージを表示し終えた後の処理（必要に応じて）
      }
  }

  showNext();
}

// ページ読み込み後にシーケンスを開始
window.onload = fadeSequence;

```
気になる方は作って検証してみてください
Activeで指定したウィンドウを半透明に

メモしたいけど後ろのサイトも見たい。けど会社からツールダウンロードできない！！！

という人の為のScript書いてみました。

VBSがオワコン化ということなのでPowerShell勉強してるけどうーん、、、

```
# 必要なuser32.dllのメソッドを定義
Add-Type @"
    using System;
    using System.Runtime.InteropServices;
    public class User32 {
        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll", SetLastError = true)]
        public static extern int GetWindowLong(IntPtr hWnd, int nIndex);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);
    }
"@ -ErrorAction Stop

# 定数の設定
$GWL_EXSTYLE = -20
$WS_EX_LAYERED = 0x80000
$LWA_ALPHA = 0x2

# アクティブなウィンドウのハンドルを取得
$activeWindowHandle = [User32]::GetForegroundWindow()

# 現在のウィンドウの拡張スタイルを取得
$currentStyle = [User32]::GetWindowLong($activeWindowHandle, $GWL_EXSTYLE)

# レイヤードスタイルを設定
[User32]::SetWindowLong($activeWindowHandle, $GWL_EXSTYLE, $currentStyle -bor $WS_EX_LAYERED)

# 透明度を設定 (0: 完全に透明, 255: 不透明)
# 例えば、128を設定すると半透明になります。
$opacity = 128
[User32]::SetLayeredWindowAttributes($activeWindowHandle, 0, [byte]$opacity, $LWA_ALPHA)

Write-Output "The transparency of the active window has been set to $opacity."
```
UE5.3でRan・WalkのAnimationをリターゲットした際、勝手にアニメーションが移動してしまう問題の解決方法

### こうなってしまうときの解決策について
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257391/807efcd9-b559-2457-fff0-93a148c199ff.png)

メモです。
参考
[Retargeting Walk Animations makes character move out of 0,0,0 in UE 5.3](https://forums.unrealengine.com/t/retargeting-walk-animations-makes-character-move-out-of-0-0-0-in-ue-5-3/1294350/13)

### 解決策

#### 1.チェーンにルートが含まれているか確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257391/eb8b19b2-4a67-0653-d90d-b02de085740c.png)

#### 2.グローバル設定でルートを有効に
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257391/57126749-5237-ddfc-a655-b6bb4e3dbed7.png)
※無効にしても動かなくなるが完全にRootBoneがロックされてしまうため足をばたつかせているような変なアニメーションになる

#### 3.チェーンの詳細から平行移動を[Globally Scaled]に変更する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257391/81bf8203-d3f5-e13a-0366-eea163150b94.png)
※通常はNone


以上！！！！！！！！！！
![スクリーンショット 2024-10-24 133352.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2257391/227e948d-020d-a98f-c1bd-fd5156d201f8.png)
Databricksノートブックのビジュアライゼーションをダッシュボードに追加できるようになりました！

同僚の方に教えていただきました。

[ダッシュボードの作成またはダッシュボードへの追加](https://docs.databricks.com/ja/notebooks/dashboards.html#create-or-add-to-a-dashboard)

以前はノートブック上のビジュアライゼーションは、**ノートブックダッシュボード**というノートブック上のダッシュボードにしか追加することができませんでした。今回、ノートブック上のビジュアライゼーションをAI/BIダッシュボードに追加できるようになりました！

以下のようなダッシュボードがあるものとします。

![Screenshot 2024-10-24 at 13.08.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/c5f3f48b-dbf1-11b7-2f31-200ece46b0bc.png)

SQLノートブックを作成します。

:::note info
**注意**
本機能を利用するにはSQLセルでビジュアライゼーションを作成する必要があります。
:::

![Screenshot 2024-10-24 at 12.58.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/0561d446-78bd-b0ee-7bc9-2624964f7fb8.png)

以下のようなクエリーを実行します。

```sql
SELECT * FROM takaakiyayoi_catalog.japan_covid_analysis.covid_cases
```

![Screenshot 2024-10-24 at 12.58.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/be48164d-cd4f-403a-f6bf-d260adcee9fe.png)

円グラフを作成します。
![Screenshot 2024-10-24 at 12.59.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/b0752f8c-7610-a87e-a604-e7dd00945a4d.png)

ビジュアライゼーションのメニューに**ダッシュボードに追加**が表示されています！
![Screenshot 2024-10-24 at 12.59.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/b11e400a-1d15-85c2-0944-2ff8a43f48b8.png)

追加するビジュアライゼーションと追加先のダッシュボードを選択します。

![Screenshot 2024-10-24 at 13.09.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/f7933496-be1b-4e06-e5b5-700090e887a5.png)

取り込まれました！

![Screenshot 2024-10-24 at 13.09.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/fb9da727-19ed-9966-2fe8-c1b2d968cdcb.png)
![Screenshot 2024-10-24 at 13.10.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/cd99674b-9cc4-36a6-b33b-9f00615dcae0.png)

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
Google SpreadSheetを実態として持つBigQuery Tableに対してPythonでアクセスする方法

# はじめに
備忘録なので雑多書きです。

# アクセス条件
* BigQuery の実行権限があること
* BigQuery Tableへの読み込み権があること
* Tableの実態であるGoogle SpreadSheetへの読み込み権があること
* Scopeが設定されていること

上3つの詳細は省略。

## Scopeが設定されていること
```bash
$ gcloud auth application-default login --scopes=https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/drive.readonly
```

を実行し、認証を取得する。
`https://www.googleapis.com/auth/drive` は読み込みだけなら不要な気もするが、検証していない。

---

あとは省略。
【Tailwindcss】hover: dark: が使える！クラスの追加方法


## Tailwind 難しい

`Vue` で書いていますが、`HTML` なら同じです！

```vue
<template>
  <DashboardLayout title="テスト" class="flex flex-col gap-1">
    <div class="bg-red-500">
      色を付けたい
    </div>

    <div class="bg-accent">
      独自の色を付けたい
    </div>

    <div class="hover:bg-accent">
      ホバー時だけ、独自の色を付けたい
    </div>
  </DashboardLayout>
</template>

<style lang="scss">
.bg-accent {
  @apply bg-primary-500;
}
</style>
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3833190/b548b23f-585d-3078-ad75-833503b501f9.png" width="400px">

`hover:` や `dark:` が動かないぞ...  



## Tailwind 完全に理解した

https://tailwindcss.com/docs/hover-focus-and-other-states

`hover:` や `dark:` は `utilities to style elements` と言うらしい
つまり CSS で定義するのではなく Tailwind 側で登録してあげる必要がある

これには config で `addUtilities()` というものを使うらしい

```js:tailwind.config.js
import plugin from 'tailwindcss/plugin'

/** @type {import('tailwindcss').Config} */
export default {
  // ...

  plugins: [
    require('tailwindcss-primeui'),

    plugin(function ({ addUtilities }) {
      addUtilities({
        '.bg-accent': {
          background: 'var(--p-primary-500)',
          '@apply dark:bg-[var(--p-primary-700)]': '',
        },
      })
    }),
  ],
}
```

わーい、できちゃった

![Animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3833190/3a673776-b5eb-ea74-1483-603918547c7d.gif)

ちなみに `addUtilities()` の中で Utility を使いたいときは、`@apply` を頼るしかないみたい



## おわりに

`@apply` は非推奨だけど、色情報はまとめておいた方が良いと思う
個人的には `xx-red-500` 系を HTML に埋め込みたくない

Tailwind の config は複雑怪奇なので、もっと良いやり方があるかもしれない

- Plugins - Tailwind CSS
  - https://tailwindcss.com/docs/plugins
- I have a question about the structure of addUtilities plugin · tailwindlabs/tailwindcss · Discussion #13910 · GitHub
  - https://github.com/tailwindlabs/tailwindcss/discussions/13910
BigQuery データキャンバスを使ってみた：インタラクティブなデータ分析の始め方

## はじめに
現代のデータ分析では、インタラクティブな可視化とリアルタイムのデータ操作が求められています。Google Cloud の BigQuery データキャンバスは、SQL を使用してデータをクエリし、その結果を直感的に視覚化する強力なツールです。本記事では、BigQuery データキャンバスを活用して、簡単なデータセットを使ったインタラクティブな分析をどのように行うか、その手順を解説します。

---

### サンプルデータの準備

まず、BigQuery にサンプルデータを作成します。以下の SQL クエリを実行して、トランザクションデータを含むテーブルを作成します。

```sql
CREATE TABLE `プロジェクトID.データセット名.test_transactions` (
    TransactionID STRING,
    TransactionDate DATE,
    CustomerName STRING,
    ProductName STRING,
    Quantity INT64,
    UnitPrice NUMERIC,
    TotalPrice NUMERIC,
    PaymentMethod STRING
);

INSERT INTO `プロジェクトID.データセット名.test_transactions` 
(TransactionID, TransactionDate, CustomerName, ProductName, Quantity, UnitPrice, TotalPrice, PaymentMethod) VALUES
    ('T0005', '2023-11-03', '鈴木一郎', 'ゲームコンソール', 1, 30000.0, 30000.0, 'PayPay'),
    ('T0006', '2023-11-03', '高橋真理子', 'キッチンブレンダー', 1, 8000.0, 8000.0, '現金'),
    ('T0003', '2023-11-02', '佐藤健', 'スマートフォン', 1, 60000.0, 60000.0, '代金引換'),
    ('T0009', '2023-11-05', '小林幸子', 'カメラ', 1, 50000.0, 50000.0, '銀行振込'),
    ('T0001', '2023-11-01', '田中太郎', 'ノートパソコン', 1, 80000.0, 80000.0, 'クレジットカード'),
    ('T0007', '2023-11-04', '渡辺梨花', 'スマートウォッチ', 1, 25000.0, 25000.0, 'クレジットカード'),
    ('T0004', '2023-11-02', '伊藤翼', '電子書籍リーダー', 1, 20000.0, 20000.0, 'クレジットカード'),
    ('T0010', '2023-11-05', '吉田拓也', 'Bluetoothスピーカー', 1, 15000.0, 15000.0, 'クレジットカード'),
    ('T0002', '2023-11-01', '山田花子', 'ヘッドフォン', 2, 15000.0, 30000.0, '銀行振込'),
    ('T0008', '2023-11-04', '中村蓮', 'ワイヤレスイヤフォン', 2, 10000.0, 20000.0, 'コンビニ払い');
```

---

### データの分析手順

#### 1. BigQuery データキャンバスのセットアップ
- **Google Cloud Console** にアクセスし、BigQuery プロジェクトを開きます。
- データキャンバスを新規作成します。
![スクリーンショット 2024-10-24 12.57.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/80761e3b-3153-1691-67f3-3530d89ccbde.png)

#### 2. SQL クエリの実行
- テーブル `test_transactions` に対して、以下の SQL クエリを実行してデータをクエリします。例えば、トランザクションデータを月ごとに集計する場合のクエリは以下のようになります。

   ```sql
   SELECT
       FORMAT_DATE('%Y-%m', TransactionDate) AS Month,
       SUM(TotalPrice) AS TotalSales
   FROM
       `プロジェクトID.データセット名.test_transactions`
   GROUP BY
       Month
   ORDER BY
       Month;
   ```

#### 3. データの視覚化
- クエリ結果を基に、グラフやチャート、インサイトを作成します。例えば、月ごとの売上集計結果を折れ線グラフに表示できます。これらのグラフやインサイトはLookerStudioにエクスポートすることが可能です。

![スクリーンショット 2024-10-24 12.54.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/5c308b03-a7d7-cd7e-9d8e-e1d3e76c3d52.png)

#### 4. キャンバスの保存と共有
- 完成したキャンバスを保存し、他のメンバーとリアルタイムで共有します。これにより、分析結果をスムーズに共有し、フィードバックを受けられます。
![スクリーンショット 2024-10-24 12.58.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3364428/a74bcce0-c840-298d-e08b-1ddcd4bd7485.png)


## 終わりに
BigQuery データキャンバスは、SQL クエリとインタラクティブな視覚化を組み合わせることで、迅速なデータ分析を可能にします。キャンバスを活用してデータを分析・可視化することで、データに基づく意思決定をより効果的に行うことができます。データ分析の効率を上げるために、ぜひ活用してみてください。
プログラムを一人で書けるようになるには

## 1. 本記事のターゲット層
- 入門編からの抜け出し方が分からない人
- リファレンスを読むことが苦手な人
- 自力でコーディングを行えるようになりたい人
- SESにおいて保守案件から抜け出したい人

## 2. はじめに
先日、あることを質問されました。
**「新しい技術を身に着ける際はどうやっていますか？」**
長年やっていても自力でコーディングをすることが苦手であるということなんですね。

これは開発において、必要に迫られてリファレンスを読んで、自力でコーディングをする機会がないと仕方がないことだと思います。

しかし、独学で力量を磨くことは中々難しいですよね。日常においても疲弊し、余力もないほどに仕事を頑張っていると、なかなか難しいです。独学で勉強するにしても何をしたらよいか分からないことでしょう。

本を読めばいいのか？サイトを見ればいいのか？e-Learningサイトを利用すればいいのか？そのどれも違うと考えています。

たしかに、知識を身に着けるためには本を読んだり、サイトを見たり、e-Learningが必要でしょう。しかし、それで自力でリファレンスを読み、コーディングができるようになるわけではありません。

今回は、あくまで「私が思う」、自力でコーディングする力量を身に着ける方法を話したいと思います。

## 3. もっとも重要なこととは？
技術を身に着ける上でもっとも大事なことは、その技術を自分で試してみることにつきます。

それでは、自分でリファレンスを読み、理解した内容を自分で実装するためにはどうすればよいでしょうか？
その答えはまさに、**自分でリファレンスを読み**、**理解した内容を自分で実装する**ことになってしまいましす。

まあ、それでは話はそれで終了してしまいますねｗ

では、自分でリファレンスを読み、理解した内容を自分で実装するためにはどうしたらよいのでしょうか。

自分で作りたいものをイメージして、それを作るためには何が必要か考えることから始めます。

通常のシステム開発においても同じです。ただ、自分ではなく、**誰か**が作りたいものを作る違いがあるだけです。そのために、通常はヒアリングを行い、どのような技術が必要で、どのようなリソースが必要か考えていくわけです。

ただ、この記事を読んでいる方は、自力で何かを作ったことがないはずで、作りたいものがあれば苦労はしないと思います。**「でも作ったことがないからそれでも無理に決まっている！！」**と考えてはいませんか？

そんなことはありません。作りたいものがないから、何を作ればよいかイメージが沸かず、技術を活用しようとしてもそのイメージが沸かないだけなのです。サンプルソースを見ても、そこで使われているメソッドの使い方は分かるかもしれません。でも、イチから自分で実装しようとしても分からないはずです。

その理由こそ、「自分で考えて何かを作る」経験がないのが理由なのです。簡単なことからコツコツとやっていけば、必ず入門編を抜け出すことができます。

しかし、残念ながら時間は有限です。どこで自己学習の時間を作るかは、この記事を読んでいるあなたが決めるしかありません。出社してすぐの空き時間？昼休み時間？帰宅後？いずれにしてもどこかで時間を作るしかないのはたしかでしょう。

## 4. 何を作るか
今回、おすすめしたいのは商品管理システムです。余裕があればログイン画面にも挑戦すると良いでしょう。

＜システムイメージ＞
![](https://storage.googleapis.com/zenn-user-upload/2edd86ea8437-20241024.jpg)

簡単ですが、システムの画面構成、DB構成は上記をイメージしています。これらに基づき、「自分ができる範囲」でできることをやってみてください。

入門編を脱することを目的としているので、一般的な開発手順とは異なるかもしれませんが、気にしないで大丈夫です。「自力でコーディング」が行えるようになることがゴールであり、一般的な開発手順を身に着けることを目的としていないからです。


## 5. Let's Try!

(1) まずは開発環境を整えるところからはじめます。
言語は何にするか、DBは何を選択するか。ローカルに展開？それともコンテナを使いますか？
学びたいものを選択し、それに合わせた環境構築を行うところからスタートします。

(2) DBにテーブルを作ってみましょう

(3) 簡単な画面（ボタンのみでもOK）を作成して、プログラムからDBにアクセスを試みてください

(4) 次にプログラムで作成したテーブルからデータ取得を試みてみましょう
現時点ではデバッグで確認するだけでも良いです。

(5) 画面のパーツを作っていきましょう。
サンプルソースを探して、それをマネしてみるだけでもいいです。すべての技術は模倣から始まります。模倣したものを改変してみることで、何がどのような挙動をするのか、徐々に理解していくことができます。

(6) パーツにイベントを実装しましょう。
データはどのパーツが、どのような挙動を行ったときに取得しますか？あるいは登録はどのようなときに行いますか？

ボタンクリックでしょうか。画面が表示されたときでしょうか。そうしたことを考えながら実装してみてください。

あるいは先に画面遷移をする機能を実装するのもよいと思います。

(7) 入力チェックやエラー時の処理を作ってみましょう。
分からない部分は、気にしないでも大丈夫です。開発経験が増えていくことで「こういうことも必要なのか」と知っていくものだからです。

全てのことを完璧に理解して、全てのことを完璧に予測をして開発をしている人などいないと思います。

## 6. まとめ
いかがでしょうか。簡単なことかもしれないですが、いざ挑戦すると時間がかかったのではないでしょうか。

これを段々大規模に、複雑にしていくと、段々力量も上がっていきます。

そのさらに先にいくとオープンソースのプロジェクトにも挑戦できるようになることでしょう。

右も左も分からないのは私でもあります。ので分からないということ自体に慣れていくことも大事だと思います。
 
もしアドバイスをするならば
(1)”「諦める」ことに慣れる”ですかね。
”分かる”状態になるまで”分からない”。そんなものです。
 
分かるまでもがく、あがく。できることはそれだけです。

(2)自分の壁を突破するのは外から何かを持ってくるしかない。と知る。
これは自分の限界を超える、壁を突破するには
以下のように自分の外にある何かを利用するしかないということですね。
・（周囲の、交流会に参加して、社内の）人に聞く
・Googleで調べる
・本を読む
・AIに聞く
・（あれば）サポートを利用する
 
自分で考える、調べる。それでも分からないときはそれぐらいしか手段がありません。
Unityで他のオブジェクトのスクリプトの変数を参照したい

## Unityで他のオブジェクトのスクリプトの変数を参照したい
すでに多くのサンプルがありますが、説明を作成しました。
C# ScriptはGameObjectではComponentの扱いですから、GetComponentメソッドを使って取得し、参照することができます。

### 概要
1. 値保存と取得のコンポーネントとして、C# ScriptでMyComponentクラスを作成します。
1. GameObjectとGameObject2を作成し、MyComponentをアタッチします。
1. GameObjectでGameObject2の値を、GameObject2でGameObjectの値を取得します。

### スクリプトを作成します
1. C# Script
MyComponent

``` MyComponent.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MyComponent : MonoBehaviour
{
    public int myVar;   //設定値
    public GameObject otherObject;  //別のゲームオブジェクトを参照
    private MyComponent otherComponent; //別のゲームオブジェクトの中のMyComponent

    // Start is called before the first frame update
    void Start()
    {
        //別のゲームオブジェクトからMyComponentを取得する
        otherComponent = otherObject.GetComponent<MyComponent>();
    }

    // Update is called once per frame
    void Update()
    {
        //Dキーを押すと
        if(Input.GetKeyDown(KeyCode.D))
        {
            //自分の設定値と、別のオブジェクトの設定値を出力
            Debug.Log("myVar:" + myVar + " otherVar:" + otherComponent.myVar);
        }
    }
}
```
### 空のゲームオブジェクトを作成します
1. Create Empty
 GameObject
 GameObject2
1. GameObjectとGameObject2に、MyComponentスクリプトをアタッチします。
1. GameObjectのMyComponentの値を、以下に設定します。
MyVar：10
OtherObject：GameObject2

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3917213/dbb54e4d-3bb7-874e-ea45-6a548b589f8b.png)

1. GameObject2のMyComponentの値を、以下に設定します。
MyVar：20
OtherObject：GameObject

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3917213/82095ed5-289c-bf47-f037-2b74f28c131d.png)

### 実行

実行して、Dキーを押すとConsole画面に
myVar:10 otherVar:20
myVar:20 otherVar:10
が出力されます。
最初のmyVar:10はGameObjectのMyComponentの値、otherVar:20はGameObject2のMyComponentの値です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3917213/0835889e-f6c6-221d-2ff5-557c431a3b45.png)

### まとめ
他のオブジェクトのスクリプトの変数値を知りたい時は、
ゲームオブジェクトからコンポーネントを取得するとできます。
コンポーネントはスクリプトのクラス名
知りたい変数はpublicアクセスまたは、publicアクセスのメソッドを使って値を取得してください。

ゲームオブジェクトはGameObject.Findメソッドを使って取得することもできます。
Oh My Zshでlessのようなページャーの無効化する方法

## 概要
最近、Oh My Zshを使用し始めたのですが、git branchコマンドを実行すると、lessのようなページャーが使われ、スクロールして確認できるようになっています。これは、ブランチが多い場合に便利ですが、毎回 q を押して終了するのが面倒だと感じます。
その解決法についてまとめたいと思います。

## 解決法
### git branch
もし元の git branch の挙動、つまり一度に全てのブランチを表示して終了したい場合、ページャーを無効にする設定ができます。以下のコマンドで git branch でページャーを無効にできます。

```sh
git config --global pager.branch false
```

これで、ブランチの一覧がページャーなしで一度に表示されるようになります。

### git stash list
git stash list でも同じようにページャーが表示される場合、これもページャーを無効にできます。git stash コマンドに対してもページャーの設定を変更しましょう。

以下のコマンドを実行して、stash コマンドでもページャーを無効にすることができます。

```sh
git config --global pager.stash false
```

これで、git stash list もページャーを使わず、すべてのリストが一度に表示されるようになります。

### 全体のページャーを無効に
もし、全体的に git のページャーを無効にしたい場合は、以前の提案通り、以下のコマンドも考慮できます。

```sh
git config --global core.pager cat
```

これで、git stash list を含むすべての git コマンドでページャーが無効になります。


## 参考
- [Git の branch とかが less になるのをやめたい #Git - Qiita](https://qiita.com/shimon_haga/items/874fcb5450a1522710e8)
ノーコードアプリBubbleの感触、非エンジニアには難しいがエンジニアは楽になる

# はじめに
Bubbleというノーコード/ローコードでアプリを作るサービスがあり、ここ数週間、頻繁に触っています。
エンジニア経験は薄くたまに深く広くあり、Bubbleの入口に近いところにいる人として、今の段階の感触や、そこから思ったことを書いておきます。

https://bubble.io/

# 認知度
- 少なくとも日本では、あまり流行っていない模様
    - たぶん無料枠が実質ない（外部リリースは有料）から、触って遊んでみる勢が少なく、ビジネス目的の人が多い
- 世界はわからないけど、知られてはいるみたい
    - そもそも、ノーコード・ローコードというのがどの程度流行っているのかが、個人的に疑問ではある

# いいところ
- 本当に簡単にWebアプリを作れる
- たぶん技術的にある程度枯れていて、ものすごく大きなUIの変更がなさそう
    - 数か月・数年前のYoutubeやブログでも、大体読める
- プラグインの使用は、有料でも割とある（ビジネスチャンス）
- デザイン済みのシステムのテンプレがたくさんある（2024/10/24時点で1,250個）
    - 無料もわりとある（同、468個）
    - 例えば、ブログとかCRMとか予約システムとか
        - どこまで使えるかはわからないけど、そこからカスタマイズできる
            - 無料のテンプレ提供者は、このカスタマイズで稼いでいるのかも

# よくないところ
- 英語
    - （日本人のライバルが減るという視点ではいいところ:smirk:）
- 日本での知名度が低いから、紹介したり試したりしている日本語ブログ・記事が少ない
- １アプリごとに課金が必要
    - リリースしなければ無料、リリースは有料（$29/月≒5,000円弱）
- SEOは弱いらしい
- 例えば外部のAPIが何かの理由で使えなくなったなど、トラブル時にどうなるのか、そのエラーハンドリングやログは、「私の今の技術力では」わからない

# 使えそうな場面
毎月5,000円を出してもいいという条件をクリアした（多少お金かかってもいいから簡単に作りたいという）前提で
- 思い付きでちょっとやってみるサービス
- 仲間内での一時的ななにか
- すでに持っているウェブサイトに、新たな機能（予約とか）を付与する


# まとめ
**「月5,000円くらいなら全然いいですよ！難しいことをやれっていうわけではないんですよ！」**
という場面にエンジニアが登場して、サクッと作る、ということが、Bubbleでは想定されるのかなと思っています。

## ノーコードならば誰でも作れるかというと難しい
でも、ノーコードとかローコードとかいう言葉に踊らされて、「私、総務部の非エンジニアですが、作ってみます！:raised_hand:」というのは、結構難しいです。"コード"は確かに少ないかもしれないけど、知識がないと作れない。

プラモデルを作ることを考えてみると、設計書を見ながらパーツとパーツをくっつける技術は誰でもできるかもしれないけど、設計書がなかったらできないでしょう。
作りたいシステムを作るとき、設計書はないです。エンジニアの仕事は、自分で考えて設計書を（少なくとも頭の中で）作るところからです。「設計」→「構築」です。
そのあとのパーツとパーツをくっつけることが、システムではコーディングに当たる「構築」という作業で、そこがノーコードであっても、設計ができない非エンジニアはそこまで行けないという持論です。

この話はBubbleにおいても同じ。「構築」だけでなく、その前の「設計」が求められる。

## 「設計」はAIに任せれば・・・
今の段階では、自由な要件に対して「設計」がバチッとできるAIはないんじゃないかと思っています。Bubbleでは、ベータ版としてAIを使って、単独のページやアプリ全体を作る機能も提供されてはいるけど、まだまだ。

もしそこまでできたなら、"Bubbleである意味"があるのだろうか。

一般的に話を広げて、AIに向かって「こんなことできる、あんなことできるシステムを作って！」と言って設計から構築、保守までやってくれるのが最終ゴールだとして、そしたらその手段は、Bubbleであろうが、スクラッチ開発であろうが関係ない。

## そういう時代が来たら・・・
「こんなことできる、あんなことできるシステムを作って！」の時代は、突然は来ないです。

まず人間が「設計の設計＝プロンプトエンジニアリング」をやる時代が来ます。今、そこに差し掛かっている感じでしょうか。それはそのエンジニアが必要だし、やっぱ背景としてある程度の技術的な仕組みは知らないと難しいと思います。構築の後の保守・運用面もあるし。

そのあとに、「こんなことできる、あんなことできるシステムを作って！」の時代が来ます。AIが作って、人間に不具合を指摘されたらすぐAIが機能追加・バージョンアップします。そのときエンジニアはいらなくなるのでは。

# おわりに
Bubbleの話を書いてたつもりが、エンジニアの末路みたいな記事になってましたｗ でも数十年後には全然ありうると思いますけどね。

今日明日を生きる私は、もうちょっとBubbleの周辺のビジネスも模索していきます。Bubbleに限らず、「こんなこと、できるもんなの？」みたいなお話から、Xかなにかでご連絡いただければご相談に乗りますのでお気軽にどうぞ！

ではよき今の時代を！
docker-composeのtty, stdin_open


コンテナのターミナルや標準入力の設定に関するもの。
これらは主に対話的なアプリケーションやデバッグを行う際に役立つ。

```docker-compose.yml
...
    tty: true
    stdin_open: true
```
# tty
- 仮想端末を配置するコマンド
- `docker run -it <container_name>`の -i にあたる設定
- シェルスクリプトの実行や対話型のCLIツールを使う場合、ttyを有効にすると端末が割り当てられるため、正常に動作するようになる。
- 有効にすると、コンテナが実行されている間、常に仮想ターミナルがアタッチされる

# stdin_open
- 標準入力（stdin）をオープン状態する。
- これにより、ユーザーが標準入力を通じてコンテナに対話的に入力を送ることが可能になる
- コンテナに接続してコマンドを入力したい場合や、対話的なシェルを利用する場合に有効
Firefoxの完全アンインストール

# Firefoxの完全アンインストール

Firefoxを完全にアンインストールするには、以下の手順を実行してください。これにより、アプリケーション本体だけでなく、設定ファイルやキャッシュなどの関連データも削除されます。

### Windows11の場合
1. **Firefoxをアンインストールする:**
   - 「スタートメニュー」を開き、「設定」 > 「アプリ」 > 「アプリと機能」に移動。
   - リストから「Mozilla Firefox」を選択し、「アンインストール」をクリックして、画面の指示に従います。

2. **Firefoxの残存データを削除する:**
   - 以下のディレクトリを手動で削除します（`<ユーザー名>`には自分のユーザー名を入れてください）。
   - 設定ファイル:
     ```
     C:\Users\<ユーザー名>\AppData\Roaming\Mozilla\Firefox
     ```
   - キャッシュ:
     ```
     C:\Users\<ユーザー名>\AppData\Local\Mozilla\Firefox
     ```

3. **レジストリをクリーンアップする（オプション）:**
   - 「Windowsキー + R」を押して、「regedit」と入力してレジストリエディタを開きます。
   - 以下のキーを探し、Mozillaに関連するものを削除します。
     ```
     HKEY_CURRENT_USER\Software\Mozilla
     HKEY_LOCAL_MACHINE\Software\Mozilla
     ```

### macOSの場合
1. **Firefoxをアンインストールする:**
   - 「アプリケーション」フォルダを開き、「Firefox」をゴミ箱にドラッグします。

2. **残存データを削除する:**
   - Finderで「移動」メニューから「フォルダへ移動」を選択し、以下のフォルダを削除します。
   - 設定ファイル:
     ```
     ~/Library/Application Support/Firefox
     ```
   - キャッシュ:
     ```
     ~/Library/Caches/Firefox
     ```

3. **追加の残存データを削除する:**
   - プラグイン関連のファイルやその他のデータが残っている場合があります。以下のフォルダも確認して、Mozilla関連のデータを削除してください。
     ```
     ~/Library/Preferences/org.mozilla.firefox.plist
     ```

### Linuxの場合
1. **Firefoxをアンインストールする:**
   - ターミナルを開いて以下のコマンドを実行します。
     ```
     sudo apt-get remove --purge firefox
     ```
   - 他のディストリビューションを使用している場合は、適切なパッケージマネージャーのコマンドを使用します。

2. **残存データを削除する:**
   - Firefoxの設定ファイルやキャッシュを削除するには、以下のコマンドを実行します。
     ```
     rm -rf ~/.mozilla/firefox
     rm -rf ~/.cache/mozilla/firefox
     ```
サーバー側からZoom会議を作成する-2:認証コードの取得

# 概要
- [前回の記事](https://qiita.com/jansnap/items/ddf74157e47978515373)の続きです
- 認証コードを、WEBブラウザを使って取得します
- 有効期限が短いので、後続の「トークンの取得」を早めに行う必要があります


# WEBブラウザで、認証コードを取得

- 以下の形式のURLを、環境に合わせて書き換えてから、ブラウザで開くと、認証画面表示後に、URLに「code=abcd...」のように認証コードが付与されてリダイレクトされます
    - https://zoom.us/oauth/authorize?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI

## Client IDとリダイレクトURIをメモしておく

- 前回のZoom App Marketplace で作成したアプリの「Basic Information」画面を開きます
- 「App Credentials」に、「Client ID」があるので、安全な場所にメモしておきます

- 下にスクロールして、「OAuth Information」に、「OAuth Redirect URI」があるので、安全な場所にメモしておきます

## URLを生成して、ブラウザで開く
- 上記のClient IDとRedirect URIを使って、URLを生成し、ブラウザでひらきます
    - 例えば、Client IDが`12345`、Redirect URIが`https://example.com/redirect`だった場合は、 https://zoom.us/oauth/authorize?response_type=code&client_id=12345&redirect_uri=https://example.com/redirect というURLをWEBブラウザで開きます



## 認証コードをURLから取得

- 上記にアクセスすると、Zoomの認証画面に遷移するので「Allow」をクリックします

![ScreenShot 2024-09-12 10.41.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142577/a9f6013e-2ef3-25ea-5619-03dbd0239c3f.png)


- クリック後は、リダイレクト先のURLにリダイレクトされます
- その際に、URLの末尾に「?code=aabbcc」のように付与されたコードが、認証コードです
    - 例えば、 https://example.com/redirect?code=aabbcc の場合は、`aabbcc`が認証コードです


# 次回
- 次回は、上記で取得した認証コードを使って、リフレッシュトークンとアクセストークンを取得します
Nuxt3 & Firebase環境で、Cloud Functions 1 Genを2 Genへマイグレーションするときの手順

# 概要
- 最近Cloud Functionsが[Cloud Run Functions](https://cloud.google.com/functions?hl=ja)にアップグレードされた
- Nuxt3をFirebaseへデプロイすると、Firebase HostingとSSR等のためにCloud Functionsへデプロイされる
    - [手順](https://nuxt.com/deploy/firebase)
    - Nitroがやってくれている
- アップグレードされたCloud Functionsへマイグレーションしたいなと思い試したところハマったのでメモする

# 前提

- Nuxt3とFirebaseを利用している
- Cloud Functionsは1 Genを利用している


# マイグレーション手順

まず注意する点があります。Cloud Functions 1 Genをすでに利用している場合は、設定を変更しても2 Genとしてデプロイすることができません。

同じ名前の関数がある場合は、一度削除する必要があります。ただ、削除後デプロイという手順を踏むとサービスに影響を与えてしまうので（そのタイミングでフロントロードしようとするとエラーになる）、影響ないようにしたいです。

今回の手順は影響がないようにマイグレーションします。

## nuxt.config.tsを変更する

おそらくですが、[Nuxtの手順](https://nuxt.com/deploy/firebase)通りで1 Genを利用している場合、Cloud Functions上での関数名は `server` になっていると思います。先ほどあげたハマりポイントとして、この名前を変更してデプロイしないと、デプロイ途中で失敗してしまうので、これを変更します。

Nuxt3は内部でNitroを利用しているので、2 Genを利用するように修正します。

```diff_typescript:nuxt.config.ts
// ...
  nitro: {
    preset: 'firebase',
    firebase: {
+     serverFunctionName: 'nuxtServer', // こいつを足す
      nodeVersion: '20',
      gen: 2, // 2 genを利用するようにする
      region: 'us-central1'
    }
  },
// ...
```

このとき、`serverFunctionName`を指定することで、先ほど問題になるぞと書いたCloud Functionsの名前 `server` 問題を修正することができます。これでデプロイすると、`nuxtServer`という名前の関数が作成されるようになります。

https://nitro.unjs.io/deploy/providers/firebase#advanced

## firebase.jsonを変更する

次に、firebase.jsonを修正します。これもNuxtの手順通りに行っているのであれば下記のようになっているはずですが、変更します。

```diff_json:firebase.json
// ...
  "functions":
  [
    {
      "source": ".output/server",
      "codebase": "nuxt-server",
      "runtime": "nodejs20"
    }
  ],
  "hosting": [
    {
      "site": "dev-cabin",
      "public": ".output/public",
      "cleanUrls": true,
      "ignore": [
        "**/_nuxt/*.map",
        "firebase.*json",
        "**/.*",
        "**/node_modules/**"
      ],
      "rewrites": [
        {
          "source": "**",
-         "function": "server"
+         "function": "nuxtServer"
        }
      ]
    }
  ],
// ...
```

Firebase hosting側の`rewrites` -> `function` の名前を`nuxt.config.ts`の`serverFunctionName`で設定した名前に変更します。

## デプロイ

デプロイしましょう。

```bash
$ NITRO_PRESET=firebase yarn build && \
firebase --project ${PROJECT_ID} \
    --config firebase.json deploy \
    --only functions:nuxt-server,hosting \
    --force
```

これでデプロイできると思います。デプロイすると`nuxtServer`がCloud Run Functionsの画面に表示されていると思います。


## 1 Gen関数の削除

すべてのアクセスが、2 Genへ流れていることが確認できたら、1 Genを削除しましょう。これで完了ですー！


# 雑感

Cloud FunctionsからCloud Runベースになったのでまだまだわからないことが多いです
シャーロック・ホームズに学ぶ問題解決法

## はじめに

開発者にとって、トラブルシューティングは日常的な業務の一部であり、全部です。
しかし、その根本原因に**アタリ**がつかない、つまりは予期せぬ問題がしばしば発生します。
そんな時、シャーロック・ホームズの名言「全ての不可能を消去して、最後に残ったものが如何に奇妙な事であっても、それが真実となる」に倣ったアプローチが非常に有効です。
最近これを実感したのでここに書いておこうと思います。

## トラブルシューティングのプロセス

1. **問題の把握**
    - 問題が発生している現象を具体的に記録、把握します
        - この際後から見返せるように、スクリーンショットやログを残すことが重要です

1. **システム構成の理解**
    - 問題に関わるシステムやコンポーネントの全体像を理解します
    - いわゆる「メンタルモデル」と言われるやつを作る(、ないしは再確認する)作業ですね
        - 参照記事『[一流の人たちが頭の中に「メンタルモデル」をつくる訳　米マイクロソフトエンジニアが衝撃を受けた〈最前線の思考法〉](https://books.bunshun.jp/articles/-/8970)』

1. **仮説の立て方**
    - 問題の原因として考えられる仮説を立てます
    - この段階では、一件ありえなさそうなものも含めて**全ての可能性**をリストアップすることが重要です

1. **検証項目のリストアップ**
    - 立てた仮説に基づき、それぞれを検証するための項目を洗い出します
    - あくまで一例ですが、以下のような項目が考えられます
        - システム(プログラム)のロジック
        - データの整合性
        - 設定ファイルの確認
        - 通信の正常性
        - ユーザー権限の確認

1. **優先順位の設定**
    - 検証項目に対して、問題の状況やシステム構成から考えて最も原因となりそうなものから順に検証を開始します

1. **逐次検証**
    - 各項目を一つずつ検証し、不具合が存在するかどうかを確認します
    - この過程で、問題がない項目は除外していきます

1. **原因の特定**
    - 最後に残った要因が問題の原因であると特定します
    - はじめに疑ったものが原因であることもあれば、意外なものが原因であることもあります
        - これこそが「**全ての不可能を消去して、最後に残ったものが如何に奇妙な事であっても、それが真実となる**」の真髄です    

## 最近あった実際の例

### **問題の具体例**

とあるシステムの検証環境を作成した際、新規テストユーザーでアクセスできないという問題が発生しました。

### **解決にいたるまでのアプローチ**

1. **問題の把握**
    - 「テストユーザーでアクセスできない」という状況を詳しく調査します
      - ほかのユーザーでも発生しうる問題か？
      - エラー発生時どのような画面やレスポンスが返ってくるのか？
      - その事象が起きた際サーバーのログはどのようになっているのか？
      - ...etc

1. **システム構成の理解**
    - ログインやユーザー設定に関する全ての要素を洗い出します

1. **仮説の立て方**
    - データベースの不整合、APIの不具合、設定ミスなど複数の仮説を立てリストアップします

1. **検証項目のリストアップ**
    - DBでデータ不整合などが起きていないか確認します
      - このデータを確認する部分でも、実際にはさらにテーブルごとなどの粒度で細分化してリストアップすることができますが、今回は割愛します
    - 設定内容の見直し
    - APIのレスポンス確認

1. **優先順位の設定**
    - 直近でDBに手を加えていたこともあったので、問題が発生していそうなDBのデータ確認から調査開始します

1. **逐次検証**
    - 各項目を一つずつ検証していきます
        - ここで特にDBに問題があるわけではないということがわかりました

1. **原因の特定**
    - 設定漏れによって権限が正しく反映されていないことを特定し、設定を修正することで問題を解決しました

## まとめ

今回紹介したのは、問題の根本原因を突き止めるためのプロセス、あくまでその一例です。
その際、シャーロック・ホームズのアプローチを参考に、全ての可能性を排除していくことが重要だということを強調しました。

というのも人間は、皆どうしても先入観によって物事を判断してしまいがちですし、(熟練した開発者ならば)多くの場合、それで解決できてしまうのでしょう。
なぜならば過去の経験、あるいはその経験によって研ぎ澄まされた直感から問題の原因を素早く特定できるからです。

しかしながら、先入観によって隠されてしまった問題の根本原因を見逃さないためにも、このようなアプローチを意識することも有用なのではないかと、最近起きた事象を振り返りながら感じたのでした。

## 参考文献

- [シャーロック・ホームズ曰く「全ての不可能を消去して、最後に残ったものが如何に奇妙な事であっても、それが真実となる」](https://note.com/tossyz/n/n75a58ea2fd47)
    - この記事を書こうとした際、同じようなことを書いてるひとが既にいないか調べたところ、だいたい自分が言いたいこと全部書いてくださっている方がいらっしゃいました
    - 内容かぶってしまうので自分はもう書かなくてもいいかなと思いましたが、トラブルシューティングに焦点を当てることで、何とか自ら書く意義が出せたかなと思ってます:sweat_smile:
- [祖母が就寝するとDBインサートができなくなる](https://qiita.com/bohemian916/items/46f9f1e8bb32fc0a1f99)
    - 全く同じアプローチをとっているわけではないですが、似たエッセンスを感じられます
    - あとITミステリーとしてめっちゃ面白い
Airを使うとGO言語開発が楽に

## 発信しようとしたきっかけ
 個人開発、又は実務においてコードに変更を加えるたびにビルドをし直すのは面倒ですよね？
 そんな時GO言語では**Air**と呼ばれるソフトウェアを使うことが多いように思われます。
 主にインストールでつまづいたため備忘録として記事を残そうと思います。
 
 https://github.com/air-verse/air

## **Air**
APIサーバーを開発する際に「ソースコードの変更をする度にビルドする必要がある」
という問題を抱えていて開発効率を落としてしまいます。

そこで開発されたのがAirです。
開発者はGoのAPIサーバーを開発時に「コードの変更を監視して変更された際に自動的にビルドをし直しアプリケーションを再起動するホットリロードライブラリ」となっています。

ホットリロードとは、ソースコードを更新するたびにソースをビルドし直して実行するという手間を省くため、ソースコードを更新し、保存したら自動でビルドと実行を行うということです。

プロジェクトのルートディレクトリでairを実行し、放っておくだけでコードに集中できるというわけです。

## インストール方法
①インストール
```
go install github.com/air-verse/air@latest
```
②air.tomlファイルをデフォルト設定で作成します
```
go init
```
③airを起動する
```
hogehoge Desktop % air

  __    _   ___  
 / /\  | | | |_) 
/_/--\ |_| |_| \_ v1.61.1, built with Go go1.23.0
```

これが表示されたら無事起動完了です！
コードに変更を加える度にビルドが再度実行されます。
いい開発ライフを！

## インストールが失敗した場合


```
cannot install, GOBIN must be an absolute path
```
私がつまづいた箇所です。
GOBINはgoが実行可能ファイルをインストールするファイルの場所を示します。 PATH変数にGOBINの場所が含まれていないことが原因でした。
PATH変数に追加する方法は以下の通りです。尚以下はzshを想定して記述していきます。

①zshrcを開く
```bash
open ~/.zshrc
```
②環境変数にPATHを追加する
```
export GOBIN=$(go env GOPATH)/bin
```
③pathを反映させる
```
source ~/.zshrc
```

pathに追加する場合②を下記の書き方に変えてください。
```
export PATH="$PATH:$(go env GOPATH)/bin"
```
SelectとToArrayで配列を一気に変換【C#】

# 目次

- 初めに
- まずはfor文で変換
- 一気に変換！
    - Selectメソッドとは
    - ToArrayメソッドとは

# 初めに
今回は、配列の変換を簡潔に書く方法を紹介します。

# まずはfor文で変換

まず、LINQを使わずにfor文で変換する方法を見てみましょう。

```c#
string[] stringArray = { "1", "2", "3" };

int[] intArray = new int[stringArray.Length];

for (int i = 0; i < stringArray.Length; i++)
{
    intArray[i] = int.Parse(stringArray[i]);
}
```
冗長に見える反面、処理を追加しやすいというメリットもあります。

# 一気に変換！

```c#
string[] stringArray = { "1", "2", "3" };

int[] intArray = stringArray.Select(int.Parse).ToArray();
```
非常に簡潔で、可読性が高いですね:laughing:
デバッグはループのステップを確認できるfor文の方が簡単です。

```c#
int[] intArray = stringArray.Select(s => int.Parse(s)).ToArray();
```
ちなみに、こう書くこともできます。
メソッドグループを使うかラムダ式を使うかの違いです。これについても、後日デリケートの記事で触れようと思います。

最後に、Selectメソッド・ToArrayメソッドについても軽く解説します。

#### Selectメソッドとは
C#の機能であるLINQの一部です。
各要素に変換処理を行います。元のデータを変更せずに、`IEnumerable<T>`型のシーケンスを作ることができます。便利ですね:relaxed:

`IEnumerable<T>`型はforeachなどで要素を順に列挙することができます。インデックスで要素に直接アクセスできない点が配列との違いです！

#### ToArrayメソッドとは
C#の機能であるLINQの一部です。
`IEnumerable<T>`型を配列に変換してくれます！
Google CloudのIPaas Application Integrationを今更触った & サンプルがネット上に無かったので書く

Application Integrationっていう、ETLとかに使えるらしいプロダクトが追加されたのは知っていたが、実際に触ったことは無かった。
Cloud Workflowsと組み合わせて、サーバーレスで色々できるらしい。
ということで今回は、「Google Cloud StorageにアップロードされたJSONファイルを取得し、そのプロパティを抽出して、後段の処理で使うための変数に割り当てる」処理のサンプルを残しておきます。

## 構築の流れ

1. Google Cloudプロジェクトで、Application Integration APIを有効化する
1. Integration(フローの管理単位)を新規作成する
1. Integrationの中身(フロー)をGUIで作る
1. フローの詳細パラメーターをJSONで与える
1. テスト実行

この記事では「3」以降のみ説明します。

## 実際の手順

今回、値を読み出すファイル `upload.txt` の中身は、以下のようなJSONです。

```json
{
  "key": "value",
  "today": "Friday"
}
```

このファイルがGCSバケットにアップロードされているので、それを読み出して、A.I.の変数に割り当てます。


![B01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403229/f9aa5dd0-f175-c606-2a3d-e81f8fb9bb66.png)

いきなり完成図ですが、向かって右側がフローを追加するフィールド。
向かって左側が、定義した変数が並ぶフィールドです。
フロー(四角いやつ)をクリックすると、右側に詳細設定パネルが出てきます。
フローは、必ずトリガーではじまり、外部から情報を取得するコネクターや、情報を変化させるタスクを経由して進んでいきます。
制御構造については今回は触れません。

![B02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403229/70f9d491-db76-1fc9-be04-3d5d04bdf787.png)

GCSバケット内のJSONファイルを取得したいので、Cloud Storageコネクターを追加します。
すると、左ペインにローカル変数「connectionInputPayload」が追加されます。
コネクター自体のプロパティにも、GCPプロジェクトやリージョンなどの設定値を与えますが、バケット名、バケット内のオブジェクト名といった具体的な指定は、この変数でおこないます。
パッと見ではわけが分かりませんが、中ほどにグレーアウトして表示されているのが「スキーマ」のJSONです。
ここに書かれているルールに従って、「Default Value」欄にJSONを書きます。
ここでは、バケット名、ファイル名だけを書いています。

![B03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403229/a74e4250-ec2d-ee48-fe31-bb643bddeeb8.png)

次に、「Data Mapping」です。
読んで字のごとく、データを変数に割り当てる処理です。
GCSコネクターのドキュメントを読むと書いてあるのですが、コネクターを実行すると、
* Success
* Content

の2つの値をJSONで返してきます。
今回の場合は、以下のような内容です。

```
[
  {
    "Success": "True",
    "Content": "{\n \"key\": \"value\",\n \"today\": \"Friday\"\n}\n\n"
  }
]
 ```

要素数が1個の配列の中に、キーが2つあるハッシュ(オブジェクト)が入っています。
ここで注意してほしいのは、Contentの値は文字列であってオブジェクトではない、ということです。
ここを変換するために、次段の処理が必要になります。

![B04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403229/48f56a6b-9eef-1981-18db-994afa1cc1a1.png)

Data Mapping Editorの画面です。
変数、Input、Outputという項目があります。
使うのはInput、Outputだけです。
画面に記述しているように、Inputでは変数を受け取って、その変数に対して何らかの処理をし、Outputの変数に代入します。
ここでは、GCSコネクターの出力からJSON文字列を切り出して、変数JSONContentに割り当てています。

![B05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403229/2ce3ad89-1c69-ea24-915a-17bf291d2462.png)

先述した通り、文字列でしかないJSONをオブジェクトとして認識させるため、 `.TO_JSON()` 関数を適用します。
JSONに変換したので、プロパティである `.today` にアクセスできます。

![B06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403229/dfedcdaa-7c7a-bac0-21d3-41f297b69b87.png)

テスト実行画面です。
GUIのツールバーから「TEST」を押すとこの画面になります。
何も変更せず `TEST INTEGRATION` しましょう。

![B07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403229/644fd96b-1916-7e91-69f0-b1e0ff690eb3.png)

テスト実行結果の画面です。
変数 `ChildJSONContent` に、入れ子になっていたJSONの値(テキストファイルに書かれていたJSONの値)が取得できています。
MayaでテニスボールをモデリングするMEL

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/fed4930b-4504-29d4-6f8a-81aa5c45a63a.png)

この動画を参考にMELにしました。

https://www.youtube.com/watch?v=IfSis4ns8SY

# 手順
①プラトン立方体をサブディビジョン１で作る
②4頂点を移動
③16エッジを選択し、ベベルエッジ
④サブディビジョンを２回
⑤正規化して球状化の代わりに、スカルプトしてスケールで球状化
⑥エッジ選択で、ダブルクリックのループ選択をして、スケールでへこます。
6は、ラインを見やすくするためのもの。

# MEL

```c
polyPlatonic -primitive 1 -subdivisionMode 0 -subdivisions 1 -radius 1 -sphericalInflation 1;
rename "pPlatonic1" "ball";

select -r ball.vtx[13] ball.vtx[15] ;
move -r 0 0 -0.292893 ;
select -r ball.vtx[9] ball.vtx[11] ;
move -r 0 0 0.292893 ;

/*
select -r
ball.e[5] ball.e[7]
ball.e[24] ball.e[39]
ball.e[27] ball.e[37]
ball.e[13] ball.e[22]
ball.e[16] ball.e[20]
ball.e[29] ball.e[35]
ball.e[31] ball.e[32]
ball.e[0] ball.e[11];
*/

polyBevel3 -fraction 0.001 -offsetAsFraction 1 -autoFit 1 -depth 1 -mitering 0 -miterAlong 0 -chamfer 1 -segments 1 -worldSpace 1 -smoothingAngle 30 -subdivideNgons 1 -mergeVertices 1 -mergeVertexTolerance 0.0001 -miteringAngle 180 -angleTolerance 180 -ch 1 ball.e[0] ball.e[5] ball.e[7] ball.e[11] ball.e[13] ball.e[16] ball.e[20] ball.e[22] ball.e[24] ball.e[27] ball.e[29] ball.e[31:32] ball.e[35] ball.e[37] ball.e[39];

polySmooth ball;
polySmooth ball;
sculpt ball;

select -r ball.e[321] ;
select -add ball.e[320:321] ball.e[324:325] ball.e[328:329] ball.e[332:333] ball.e[336:337] ball.e[340:341] ball.e[344:345] ball.e[348:349] ball.e[352:353] ball.e[356:357] ball.e[360:361] ball.e[364:365] ball.e[368:369] ball.e[372:373] ball.e[376:377] ball.e[380:381] ball.e[384:385] ball.e[388:389] ball.e[392:393] ball.e[396:397] ball.e[400:401] ball.e[404:405] ball.e[408:409] ball.e[412:413] ball.e[416:417] ball.e[420:421] ball.e[424:425] ball.e[428:429] ball.e[432:433] ball.e[436:437] ball.e[440:441] ball.e[444:445] ;
scale -r 0 0 0;
```
３Dプリントすると、ぴったりハマって面白いと思う。

# 数学的な洞察

長さの決まった線を、おらずに曲げながら球面に添わせる最適解でも、テニスボールは登場する。
※一致するかどうかはわからない。

https://advancesincontinuousanddiscretemodels.springeropen.com/articles/10.1186/s13662-022-03731-7

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/eda516f5-c9f8-3dc8-7bae-8d6ce985597f.png)
Kong GatewayでWorkspaceを跨ぐロールを作成する

OktaでKong Gatewayと連携する場合、OktaのGroup名を`<KongのWorkspace名>:<KongのRole名>`とすることでGroupに所属するユーザとKongのロールをマッピングすることが出来る。
以下の図だと、Oktaの`default:super-admin`Groupに所属する2人のユーザはDev、ProdそれぞれにSuper Adminとしてアクセスできる。
![20241024100324.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/e073d953-be51-6def-ea1c-89e38ba8a73f.png)

しかし、実運用を考えると以下のように環境によってはSuper Adminを渡したくないケースが出てくる。
![20241024100451.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/e2e5b618-cae2-a657-6eeb-ac2abc08cff9.png)

Prod環境には権限を持たずにアクセスさせたい場合、Oktaの`default:super-admin`Groupに所属させるとマズいので、こういう場合は別のGroupとRoleを用意してあげる必要がある。
![20241024101009.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/bebba160-94c5-d369-6b3c-72c1837e6e4e.png)

この時、`dev-super-admin`のようなカスタムロールを作成するのだが、これが少し面倒でKong ManagerからだとWorkspaceを跨いで利用できるロールが作成できない。
エンドポイントのパーミッションを以下のようにしても基本的に作成したWorkspaceでしか権限を持たないロールとなる。
![20241024101235.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/7a4a8dfb-5b79-66b4-93ec-715b2943bb76.png)

これを回避するためにはAdmin APIを利用してロールのパーミッションを設定する必要がある。

実際に試してみる。
最初にロールを作成する。
ロールの作成は[API仕様](https://docs.konghq.com/gateway/api/admin-ee/latest/#/RBAC/post-rbac-roles-name_or_id-endpoints)より`/rbac/roles`にPOSTすれば作成できるので、以下のような感じで作成する。
```sh
curl -X POST -H "kong-admin-token: kong" \
   localhost:8001/rbac/roles \
   -H "Content-Type: application/json" \
   -d '{
        "name": "dev-super-admin",
        "comment": null
       }'
```
次にロールのエンドポイントのパーミッションを設定する。
こちらも[API仕様](https://docs.konghq.com/gateway/api/admin-ee/latest/#/RBAC/post-rbac-roles-name_or_id-endpoints)より`/rbac/roles/<ロール名>/endpoints`以下のフォーマットでPOSTすれば設定できることが分かる。
```sh
{
  "workspace": "string",
  "endpoint": "string",
  "negative": "string",
  "actions": "string",
  "comment": "string"
}
```
仕様に従って以下のように実行する。
```sh
curl -X POST -H "kong-admin-token: kong" \
   localhost:8001/rbac/roles/dev-super-admin/endpoints \
   -H "Content-Type: application/json" \
   -d '{
       "workspace": "*",
       "endpoint": "*",
       "negative": false,
       "actions":  [
         "delete",
         "create",
         "update",
         "read"
       ],
       "comment": null
      }'    
```
`"workspace": "*"`の部分がミソで、ロールに紐づくWorkspaceはUIでは設定出来ないがAdmin APIでは設定できるようになっている。
ここに`*`を設定することでWorkspaceをまたいだロールとすることが出来る。

以上で設定は終了となる。

このロールを割り当てたユーザでKong Managerにログインすると、他のWorkspaceが確認できる。
![20241024102249.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/bf820fea-1a74-a50a-077a-b586c21cba6a.png)

`Teams`->`Admins`で見ると当該ユーザの`Workspace Access`が`*`となっており、Workspaceによる制約がなくなっていることも確認できる。

![20241024102419.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/f4754fc8-ebfe-e4b4-3c01-a3ef2d88bbb1.png)

ということで、Admin APIを使えばWorkspaceを跨いだ権限設定が出来ることが確認できた。
CodeWars オススメ問題 #8

# はじめに

個人的に好きなアルゴリズム学習サイト「CodeWars」の問題をシェア。

週1くらいのペースで、全10回を目指す予定。

:::note
CodeWarsはいいぞ！の紹介は[こちら](https://qiita.com/kohki_takatama/items/2ae2808b931e943262b8)

CodeWarsの始め方は[こちら](https://qiita.com/javacommons/items/7c473cda7825ab99e08c
)
:::

今回は、**「知識があれば簡単だけど、知らないとわからない」** 内容です。

# オススメ問題

https://www.codewars.com/kata/55ad04714f0b468e8200001c/typescript

### 問題
数字が与えられるため、ASCIIコードで文字データに変換する

```ts
65 --> 'A'
97 --> 'a'
48 --> '0'
```

http://www3.nit.ac.jp/~tamura/ex2/ascii.html


### 難易度
分類は 8kyu です。
最も簡単なレベルですが、知識が必要とされます。

# オススメの回答
「評価が高い回答」の中から、学びの多い回答をピックアップしてご紹介。

:::note
<details><summary>模範解答</summary>

```ts
export function getChar(c: number): string {
  return String.fromCharCode(c);
}
```

`fromCharCode`は、ASCIIコード変換を行うメソッドです。

「ASCIIコード」「`fromCharCode`」この2つの知識があれば簡単な問題ですね。

</details>
:::





:::note
<details><summary>天才の解答</summary>

```ts
export const getChar = String.fromCharCode;
```

引数を明示しないことにより、大幅に短くなった解答です。

`getChar(引数)`は、そのまま`String.fromCharCode(引数)`を表します。

「追加の処理をしていない」ことが、引数を省略できるポイントですね。
「可読性の向上」にもつながるといえるでしょう。

「変数」と「引数」に関しては[別記事](https://zenn.dev/haneru/scraps/7c3e7af75417c3)にも書きました。

</details>
:::

# おわりに
以上、CodeWarsオススメ問題でした。


オススメ問題・解法など、ぜひコメントお待ちしております！
x api (twitter api) 値上げ？

# x api が値上げらしい


```

Since our initial launch a year ago, the Self Serve X API has been used by developers to support a wide range of use-cases. We are constantly working on improving our API offerings for developers and will be making the following changes:

Free tier

Developers on the Free tier will be able to Post 500 Posts per month using the X API. Additionally, you can read 50 Posts per month to test out the API.

Note: We will continue enabling verified services who post weather alerts, transport updates and emergency notifications without cost.

Basic and Pro tier

Annual Pricing

We are introducing discounted annual subscription plans for both Basic and Pro, along with updated monthly pricing for Basic.

Basic Monthly will increase from $100 to $200 USD
Pro Monthly will stay at $5000 USD
Tier	Annual Price	Monthly Price
Basic	$1800 USD (25% Discount)	$200 USD
Pro	$54000 USD (10% Discount)	$5000 USD
Updates to top-up functionality

The updated number of top-ups that can be purchased are revised to:

Basic: 1
Pro: 1

Please feel free to reach out to us with any questions or feedback.

X Developer Platform Team

```

↓フォーラム

https://devcommunity.x.com/t/upcoming-updates-to-the-self-serve-x-api-discussion-on-top-ups/227671


気になったのが、このトップアップ。

```
"Top-up" とは、特定の制限を超えた場合に追加のリソースや機能を購入することを指します。たとえば、APIの利用において、無料または定められたプランの制限（リクエスト数など）を超えた場合、追加で「トップアップ」を購入することで、さらに利用できるようになることが一般的です。

この文脈では、Basic プランと Pro プランでは、それぞれ 1 回のみトップアップが可能とされています。つまり、プランの利用限度を超えた場合に、1 回だけ追加の利用枠を購入できるという意味です。
```

自分は、topupを購入していないので問題無い。
現状3アカウントで運営しているが、2アカウントに減らそうかな。

それでも
100ドル x 3 = 300
200ドル x 2 = 400
になるからなぁ