OmniAICreator/Qiita-1.07M huggingface dataset:
deep_dup

### deep_dup 複製したオブジェクトを作り出す
>deep_dupメソッドは、与えられたオブジェクトの「ディープコピー」を返します。Rubyは通常の場合、他のオブジェクトを含むオブジェクトをdupしても、含まれている他のオブジェクトを複製しません。このようなコピーは「浅いコピー（shallow copy）」と呼ばれます。たとえば、以下のように文字列を含む配列があるとします。
```rb
irb(main):001> array     = ["string"]
irb(main):002> duplicate = array.dup
irb(main):003>
=> ["string"]
irb(main):004> duplicate
=> ["string"]
irb(main):005> duplicate.push "another-string"
=> ["string", "another-string"]
irb(main):006> array
=> ["string"]
irb(main):007> duplicate.first.gsub!("string", "foo")
=> "foo"
irb(main):008> array
=> ["foo"]
irb(main):009> duplicate
=> ["foo", "another-string"]
```

>上で見たとおり、Arrayのインスタンスを複製して別のオブジェクトができたことにより、一方を変更しても他方は変更されないようになりました。ただし、配列は複製されましたが、配列の要素はそうではありません。dupメソッドはディープコピーを行わないので、配列の中にある文字列は複製後も同一オブジェクトのままです。

>オブジェクトをディープコピーする必要がある場合は次のようにdeep_dupをお使いください。

#### rails console で行う
```rb
irb(main):001:0> array = ["string"]
=> ["string"]
irb(main):002:0> duplicate = array.deep_dup
=> ["string"]
irb(main):003:0> duplicate.first.gsub!("string", "foo")
=> "foo"
irb(main):004:0> array
=> ["string"]
irb(main):005:0> duplicate
=> ["foo"]
```
オブジェクトが複製可能でない場合、deep_dupは単にそのオブジェクトを返します。
```rb
irb(main):010> number = 1
=> 1
irb(main):011> duplicate duplicate = number.deep_dup
(irb):11:in `<main>': undefined method `deep_dup' for 1:Integer (NoMethodError)

ruby 3.1.6p260
```
https://railsguides.jp/active_support_core_extensions.html#deep-dup
手動テストの手順そのままでテストコードを実装しない

# はじめに 

[テスト自動化あるある言いたい by T-DASH Advent Calendar 2024](https://qiita.com/advent-calendar/2024/t-dash03)の24日目の記事です。
テスト自動化にあたって、既存の手動テストをもとに、E2EフレームワークやXUnitなどでテストコードをつくっていくのが主な流れです。それ自体はいいのですが、手動テストの手順をそのままテストコードに落とし込むと問題になるケースがあるので、それのまとめです

# 忙しい人向けのまとめ

* 手動テストの手順をそのままテストコードに落とし込むと、手動のときの問題点が引き継がれる、場合によってはその問題が強化される
* 手動では時間的な制約でできなかったことを、テストコードにする際、見落としてしまう
* 前提が手動から自動に変わるので、最適解が変わることを意識する必要がある

# パターンの網羅性周り

前提が手動から自動に変わる際、パターンの網羅性を見直した方がいいです。

* 手動前提だと、時間の都合上、一部のパターンしかできていなかった
* 手動でも、がんばって全パターンを網羅していた

このどちらの場合でも、

1. パターンが網羅しつくされているかどうか
2. 網羅性のテストに必要な範囲をなるべく小さくできないか

の観点で見直すとよいです。

## parameterized testを使う

自動テストのメリットのひとつは、数をたくさんこなせることです。なので、パターンは可能な限り網羅しつくしたいです。手動のときは数をこなそうとすると、制約が多すぎて現実的でないことがままあります。
JUnitであれば、ファイル、コードなどの様々な形で入力ソースを定義できるので、それらで全パターンを定義できます。ラジオボタンやセレクトボックスの値をEnumで管理するケースが多く、EnumSourceを使えば簡単にパターンを網羅したテストを作成できます。

https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests

また、assumptionの機能もつかえば、細かな分岐も対応しやすいです。
https://junit.org/junit5/docs/current/user-guide/#writing-tests-assumptions

## テスト対象のコードを見直す

一方で、網羅性の担保だけを考えていると、テストの実行時間がどんどん増えてしまいます。一回の実行時間が伸びれば伸びるほど、繰り返し実行されづらくなり、開発の足を引っ張るなどの問題がでます。
「速く、たくさんの数をこなす」ことが自動テストのメリットです。テストコードの実行時間を短くするには、テストで使われるコードの範囲を必要最低限にすることです。
手動テストで全パターンを網羅していたとしても、

* 特定のクラスのテストコードに帰着できないか
* controller + view or repository + controllerなど、使用するレイヤーを減らせないか

テスト対象のコードを減らす（小さくする）ことを検討するとよいです。

# 自動テスト用の専用の環境を用意する

E2Eテストフレームワークを試すために、既存のstagingや開発環境をそのまま使うことがままあると思います。
手動テストで運用している場合、そういった形をとることも多いのでE2Eテストもそこからはじめようとするのも、よくあるケースでしょう。
本当に試すだけであれば問題ありませんが、その状態で自動テストを増やそうとするとまずうまくいきません。自動テスト用のためのデータが変更されないことを担保できないため、自動テストの結果が安定しません。
数がすくないうちは、自動テスト用のデータをチームに周知などの運用で回避できますが、増えれば増えるほど、そんな運用では機能しなくなってきます。自動テストを安定させるためには冪等性（同じ入力すれば、毎回同じ結果になる）の担保が重要です。そのためには専用の環境を用意し、テストデータもテストの実行前後でいれかえるなどして、同じ状態でテストできるようにしましょう。
MacにSalesforceデータローダーをインストールする

データローダーのインストールをしようとしたら手順通りにいかずつまづいたので記録として残します。
M2Mac(Sequoia15.2)に記事作成時点での最新バージョン、v63.0.0をインストールします。


# JDKのインストール

![sf-dl-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075648/599d6be4-ff30-4e9a-d9e7-bff3158b9cae.png)

https://www.azul.com/downloads/?os=macos&package=jdk#zulu

[データローダーガイド](https://developer.salesforce.com/docs/atlas.ja-jp.dataLoader.meta/dataLoader/loader_install_mac.htm)でZulu OpenJDKが案内されているので、そちらをインストールします。
最新版は23ですが、VSCodeの拡張機能「Salesforce Extension」が11・17・21をサポートとしているため、21をインストールします。

# データローダーのインストール

https://developer.salesforce.com/tools/data-loader

上記のページから最新版zipをダウンロードします。

![sf-dl-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075648/682dd168-0b15-6f22-f891-6c51cf63eba5.png)

installer.commandを実行するとエラーが表示されます。
が、ガイド記載の手順通り【Controlキーを押しながら installer.commandファイルをクリックし、メニューから[開く]を選択】しても表示変わらず開けないので、

![sf-dl-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075648/d6ea1dae-5078-3396-2016-b01d78cb21ad.png)

システム設定 > プライバシーとセキュリティと開き、セキュリティの欄から開きます。

![sf-dl-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075648/988ab6fc-b670-a749-9cdf-ab6d74590a7b.png)

いざ開いて実行してみるとここから進みません:thinking:
どのディレクトリでやってもダメ。

## 解決法

![sf-dl-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075648/a560d078-60c3-0015-f5e5-d8f242860d9f.png)

最初の「Do you want to install Data Loader in the current folder (/Users/xxx/Downloads/dataloader_v63.0.0)? [Yes/No]」でNoと入力し、インストールパスをカレントではなくデフォルトにすることでインストールできました。
【React】 #3 カウントダウンタイマーアプリを作成

# はじめに
現在、Reactを習得するために、23種類のReactアプリ開発に取り組んでいます。
今回はその第三弾として、Reactでカウントダウンタイマーアプリを作成しました。

https://qiita.com/xYasi/items/0e223b8be80006ef9933

# 要件
一般的なタイマーの仕様を満たすことを目標にしました。
具体的には、以下の要件を満たすことを目指しています：

+ 分と秒を設定できること
+ スタートボタンを押すとカウントダウンが開始されること
+ カウントダウン中はストップボタンを押してタイマーを停止できること
+ タイマー未設定の場合はスタートボタンを無効化すること
+ タイマーが0になると音が鳴ること

# 作成したアプリのイメージ
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3947973/bbd835f5-5b48-0291-8e8a-3e2b5d757bdb.jpeg" width=60%>

# アプリ紹介動画
<iframe width="200" height="400" src="https://www.youtube.com/embed/ZRKYS3QSxbU" title="React タイマー" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

# 利用技術
+ React
+ TypeScript
+ Vite
+ Tailwind CSS
+ use-sound

# 意識したポイント
## Timerの管理をuseEffectで実装
タイマーの実行状態と時間をuseEffectで管理し、依存配列に変更があった場合に発火するようにしました。  
無限ループが発生しないように注意して実装しています。
```react:useTimer.tsx 一部抜粋
  const [time, setTime] = useState<number>(0);
  const [isRunning, setIsRunning] = useState(false);

  useEffect(() => {
    if (!isRunning) return;
    const intervalId = setInterval(() => {
      if (time === 0) {
        setIsRunning(false);
        play();
      } else {
        setTime((prev) => prev - 1);
      }
    }, 1000);

    return () => {
      clearInterval(intervalId);
    };
  }, [isRunning, time]);
```

## アラームについてはuse-soundを利用
アラーム音を鳴らすために、`use-sound`というライブラリを使用しました。
シンプルで使いやすく、実装も非常に簡単でした。
https://www.npmjs.com/package/use-sound

# おわりに
前回と同様にuseEffectを利用してインターバルを管理していますが、
今回はTimerとisRunningの状態も管理する必要があり、依存配列に追加することで、
少し難易度が高く感じました。

# Github
GitHubにコードをアップロードしていますので、よかったら確認してみてください。

https://github.com/yasi1989/react-timer
Fortranを使ってNまでの素数を求めるプログラムを最速実行する

# 概要
ネタ投稿です．コンパイル時に計算すれば実行は最速にならざるを得ません．

# 環境
- Windows 11 64 bit
- gfortran 11.2
- Intel Fortran classic 2021.4.0

# Nまでの素数の計算
Nまでの素数の計算は，プログラミングの例題であったり，実行速度の比較であったり，記述力（どれだけ短く書けるか）の比較に使われたりします．

Fortranでも色々な書き方はできますが，実行速度としてはイマイチという評価になっているようです．一方で，他の言語では，コンパイル時に評価される機能を使って高速化をしている例があるので，コンパイル時に色々やってよいのであれば，Fortranでもコンパイル時計算を行うことで高速化できるはずです．

Arjen Markusは，コンパイル時にNまでの素数を`parameter`として計算する実装を示し，mecej4によってその修正版が作られました．その実装を下記に示します．
```Fortran
program prime_numbers
    use, intrinsic :: iso_fortran_env
    implicit none

    integer(int32), parameter :: N = 10000
        !! 素数を探索する範囲の上限
    integer(int32), parameter :: rootN = int(sqrt(real(N)))
        !! Nの平方根

    integer(int32) :: i, j
    integer(int32), parameter :: candidates(*) = [2, (i, i=3, N - 1, 2)]
        !! 素数の候補となる整数
        !! 2の倍数は最初から除いておく
    integer(int32), parameter :: multiples(*) = [((i*j, i=j, N/j, 2), j=3, rootN, 2)]
        !! 倍数
        !! 計算する範囲を段階的に縮小
    integer(int32), parameter :: primes(*) = pack(candidates, &
                                                  [(all(candidates(i) /= multiples), &
                                                    i=1, size(candidates))])
        !! multiplesに存在しない値（＝素数）をcandidatesから抜き出し

    print *, primes
end program prime_numbers
```

まず，`candidates(*) = [2, (i, i=3, N - 1, 2)]`において，`2`と`3`から`N-1`までの奇数を作成します．

次の`multiples(*) = [((i*j, i=j, N/j, 2), j=3, rootN, 2)]`では，`N`までの倍数を計算します．反復がちょっとわかりにくいのですが，`i`と`j`の範囲を絵にしてみると，かなり理解しやすくなります．下の図中の緑のセルが，`N=100`として実行したときの`i`と`j`の取り得る値です．
![multiples](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224040/df118115-9d7a-9785-c904-ba717221aca0.png)

最後に，`pack`を用いて，`candidates`から`multiples`に存在しない値（＝素数）を抜き出します．

この処理はすべてコンパイル時に行われるため，作成された実行ファイルを実行すると，`print *, primes`によって計算済みの素数が表示されます．計算は一切行われないので，最速で実行されます．もちろん，`N`が大きくなるとコンパイルに時間はかかりますが，プログラムの実行速度の比較においてコンパイル時間は勘定されないのが通例ですから，何の問題もありません:smile:．

Fortranに組み込みの集合演算があれば，`multiples`中の重複の解消と，`pack`関数中のループを削除できそうなのですが，その未来は訪れないような気がします．

# まとめ
コンパイル時計算は色々便利に使えそうな気がします．
Gitのコミットで一時的にemail, nameを設定する方法

## 経緯

Gitでコミットしようとしたところ以下のエラーになりました。

```bash
$ git commit -m "commit message"
 Author identity unknown
 
 *** Please tell me who you are.
 
 Run
 
   git config --global user.email "you@example.com"
   git config --global user.name "Your Name"
 
 to set your account's default identity.
 Omit --global to set the identity only in this repository.
 
 fatal: unable to auto-detect email address 
```

コミットするためにはユーザー情報の設定が必要というエラーです。メッセージの通り`$ git config --global`でemail, nameを永続的に登録すればコミットできるようになります。

しかし、筆者の場合は社内の共有環境でしたので、`--global`を使用して**自分の情報が永続的に登録されるのは避けたい**状況でした。

## 解決策

以下のように、コマンド実行時に`GIT_AUTHOR_NAME`, `GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_NAME`, `GIT_COMMITTER_EMAIL`といった環境変数でemail, nameを指定することで、コマンドを実行できます（プッシュ時も同様です）。

```bash
GIT_AUTHOR_NAME="Your Name" GIT_AUTHOR_EMAIL="your-email@example.com" GIT_COMMITTER_NAME="Your Name" GIT_COMMITTER_EMAIL="your-email@example.com" git commit -m "Commit Message"
```

## 参考

https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0

https://git-scm.com/book/ja/v2/%E4%BD%BF%E3%81%84%E5%A7%8B%E3%82%81%E3%82%8B-%E6%9C%80%E5%88%9D%E3%81%AEGit%E3%81%AE%E6%A7%8B%E6%88%90
米田の補題 #7 圏の定義② 射の合成

# 米田の補題は、圏論でもっとも重要な定理です（繰り返し）
圏論は、数学の基礎理論です。いままで、[万物の理論](https://amzn.to/3ZLmCJH)
といわれていましたが、[数理科学 11月号](https://amzn.to/4iz6NgM)では、なんと　<font color="Red">万物・万事・万人</font>のための数学理論とまでいわれるようになりました
このAdventCalendar は、体験的に圏論の最も重要な定理である米田の補題を体験的に理解してもらうためにかいています

参考にしているのは、[圏論の道案内](https://amzn.to/4iH2Rus)です

# 射の合成
４つある圏の定義の２番目です。

射f の余域[B]と　射g の域[B]がおなじだとfとg は一意に合成できます。

```mermaid
graph LR;
a[A]-.->|f|b[B]-.->|g|c[C];
d[A]-.->|g∘f|e[C];
f[A]-.->|射1|g[C];
f[A]-.->|射2|g[C];
f[A]-.->|射3|g[C];
```

**同じと一意**に注意です。対象と射と同様に単純ではありません
対象は、内部構造をもっていないと思うのが暗黙の前提になってしまいがちです。でも、内部構造の違いがあるものでも、射fの余域と射gの域では、同じものとみなすことがありえます。また、射fと射gの合成が一意になるのはなかなか強い条件です。fの域Aからgの余域Cへの射は、複数あってもいいからです。そのどれが gとf の合成 g∘f かを導き出す必要があります。（なお、慣例上　f -> g は、ひっくり返して、g∘f と書きます。記法は様々で結構面倒です）
不確実を確実にする過程がここでも見え隠れします。量子コンピュータ的発想は意外とあちこちに顔をだします。
では、米田の補題川柳です


**米田の補題川柳　次と前つながれば直いけるはず**
合成が一意なことを無視すれば、応用はすぐ思いつきます。
東京 -> 静岡 -> 名古屋
は、東京 -> 名古屋　と直接いけます。
２箇所の穴あけ加工なら、バラバラでなく一括で、２箇所あけるとかです。
数学的に扱いたいなら、一意性を確保するため、工夫が必要です。だから、川柳には、いけるはずと書いています。そのまま一意にならないのが正常です。

場所の移動の場合は、移動でなくて距離とかんがえると、経路が同じ距離の計算なので、一意になります。では、部品加工の場合はどうでしょうか？
Databricks AI/BIダッシュボードからカスタマイズされたGenieスペースをリンクできるようになりました！

以前こちらの記事を書きました。

https://qiita.com/taka_yayoi/items/a341abb5dd0cb191c589

ダッシュボードからシームレスにGenieにアクセスできる便利機能なのですが、以下のようなコメントも残していました。

> ただ、現時点ではこのGenieスペースでは、instructionを指定できないので回答が英語になりがちなのが。すみません。

それが、気づいたら作成済みのGenieスペースをダッシュボードに紐づけられるようになっていました！これで、指示がカスタマイズされたGenieスペースとダッシュボードを組み合わせることができます。

マニュアルはこちらです。

https://docs.databricks.com/ja/dashboards/index.html#enable-a-genie-space-from-your-dashboard

早速ウォークスルーします。

Genieスペースを作成しておきます。後で使うのでURLをコピーしておきます。

![Screenshot 2024-12-23 at 17.37.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/549a77dc-06a2-1cf2-e08e-7fb02d1c7036.png)

ダッシュボードを作成し、**公開**ボタンを押してダイアログを表示させます。以前は自動生成されるGenieしか選択できなかったのですが、新たに**Link existing Genie space(既存のGenieスペースをリンク)** が増えてます！

![Screenshot 2024-12-23 at 17.30.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/db09e086-10ec-26c8-e09f-dfb7f1ea1c9e.png)

そちらを選んで、上でコピーしておいたGenieスペースのURLを貼り付けます。

![Screenshot 2024-12-23 at 17.31.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/65339d30-cd58-be1f-1019-06ba24a9a95d.png)

これで、カスタマイズされたGenieスペースとダッシュボードを紐づけることができました。是非ご活用ください！

![Screenshot 2024-12-23 at 17.32.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/e4854205-fbdf-1dab-a122-afd628bd7e72.png)

### はじめてのDatabricks

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

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
LambdaでURLコンテンツを読み取って記事を自動生成する実装方法

## はじめに

LambdaとAmazon Bedrockを組み合わせることで、URLから記事を自動生成する機能を簡単に実装できます。この記事では、URLのコンテンツを読み取り、AIを活用して新しい記事を生成する方法について、Lambdaの実装手順を詳しく解説します。

## 目次

- Lambda関数の実装
- URLコンテンツの取得処理
- Bedrockを使用した記事生成
- エラーハンドリング

## Lambda関数の実装

まず、URLからコンテンツを取得し、Bedrockを呼び出すLambda関数を実装します。

```typescript
import {
  BedrockRuntimeClient,
  InvokeModelWithResponseStreamCommand,
} from '@aws-sdk/client-bedrock-runtime'
import { Context, Handler } from 'aws-lambda'
import fetch from 'node-fetch'

type EventType = {
  url1: string
  url2: string
  title: string
  summary: string
  role: string
  personName: string
}

const modelId = 'anthropic.claude-3-5-sonnet-20240620-v1:0'
```

このコードでは、必要なライブラリをインポートし、イベントの型定義とモデルIDを設定しています。

## URLコンテンツの取得処理

URLからコンテンツを取得する処理は以下のように実装します。(GenUのコードを一部参考にしました)

```typescript
async function fetchWebContent(url: string): Promise<string> {
  const response = await fetch(url)
  const html = await response.text()
  const content = html.replace(/<[^>]*>/g, '')
  console.log(`Extracted content from ${url}:`, content.substring(0, 500) + '...')
  return content
}
```

この関数では：
- fetch APIを使用してURLからコンテンツを取得
- HTMLタグを除去してプレーンテキストを抽出
- ログ出力用に最初の500文字を表示

## Bedrockを使用した記事生成

Bedrockを使用して記事を生成する核となる処理は以下の通りです。プロンプトに指示文とブログの内容を含めてください。

```typescript
const payload = {
  anthropic_version: 'bedrock-2023-05-31',
  max_tokens: 1500,
  messages: [
    {
      role: 'user',
      content: [{ type: 'text', text: prompt }],
    },
  ],
}

const command = new InvokeModelWithResponseStreamCommand({
  contentType: 'application/json',
  body: JSON.stringify(payload),
  modelId,
})

const apiResponse = await client.send(command)
```

このコードでは：
- Bedrockに送信するペイロードを構築
- ストリーミングレスポンスを使用して効率的にデータを取得
- レスポンスを適切に処理して記事を生成

## エラーハンドリング

エラー処理は以下のように実装します：

```typescript
if (item.internalServerException) {
  throw item.internalServerException
} else if (item.modelStreamErrorException) {
  throw item.modelStreamErrorException
} else if (item.throttlingException) {
  throw item.throttlingException
} else if (item.validationException) {
  throw item.validationException
}
```

主な例外処理：
- 内部サーバーエラー
- モデルストリームエラー
- スロットリングエラー
- バリデーションエラー

## まとめ

LambdaとBedrockを組み合わせることで、URLからコンテンツを取得し、AIを使用して新しい記事を生成する機能を実装できます。主なポイントは：

1. URLからのコンテンツ取得と前処理
2. Bedrockモデルの適切な設定
3. ストリーミングレスポンスの処理
4. 適切なエラーハンドリング

この実装を基に、様々なユースケースに応じたカスタマイズが可能です。例えば、異なるAIモデルの使用や、より複雑なコンテンツ処理なども検討できます。

---

参考リンク

https://docs.amplify.aws/

https://docs.aws.amazon.com/bedrock/

https://docs.anthropic.com/claude/

https://github.com/aws-samples/generative-ai-use-cases-jp
古いUbuntuでパッケージをインストール

サポート外バージョンのUbuntuで、どうしてもインストールしたいパッケージがあったので、なんとかする方法。

参考にしたのは「[How to install software or upgrade from an old unsupported release?](https://askubuntu.com/questions/91815/how-to-install-software-or-upgrade-from-an-old-unsupported-release)」なので、迷ったらこちらを参照することをおすすめ。

## 古いレポジトリを利用する方法

[古いレポジトリ](https://old-releases.ubuntu.com)が存在するので、それを利用する。

#### １. `/etc/apt/sources.list`を探し出す

- 変更するので、万が一のためにバックアップしておく

#### ２. ファイル内の次のURLを変更する

- `us.archive.ubuntu.com` → `old-releases.ubuntu.com`
- `security.ubuntu.com` → `old-releases.ubuntu.com`

なお、上記URL内の「us」の部分は違う場合があるらしいので、適宜対応してください。

#### ３. `sudo apt-get update` すると読んでくれる
電源復旧後にデスクトップPCをWoLで起動ができない

# はじめに
一般的によく利用されるデスクトップPCやノートPCにはWoL(Wake-up on LAN)という機能が備わっており、WoLにより、同じネットワーク内の別のPCの電源を遠隔でONできます。
今回、同じネットーワーク内のデスクトップPCに対するWoLに失敗した事例を紹介します。

# 事例紹介
### 構成
+ デスクトップPC（WoL設定済)
+ ノートPC (WoL実行用)

### WoLの設定について
WoLの設定方法はいろいろな記事に記載されていますので、ここでは主な設定項目のみとし、詳細は割愛します。
+ BISOの設定でWoLを有効化
+ 高速スタートアップの無効化
+ ドライバアダプタ電源の管理で
　「このデバイスで～できるようにする」
　「Magic Packet～できるようにする」にチェック
+ ドライバアダプタ詳細設定で「wake On Magic Packet」有効化

### WoL実行(成功)
デスクトップPCに上記WoLの設定を施し、同一ネットワーク内のノートPCからWoLを実行したところ、無事デスクトップPCが起動し、そのままリモートデスクトップ接続ができました。この日の作業後、デスクトップPCをシャットダウンして、一日を終えました。

### WoL実行(失敗)
次の日、「さあ今日もWoLでデスクトップPCを起動して作業しよう」と思って昨日同様にノートPCからWoLを実行したところ、なぜかデスクトップPCの電源がつきませんでした。
仕方なくデスクトップPCの電源ボタンを押して、再度WoLの設定周りの確認をしましたが、特に変化はなし(マシンのUpdateが走るとここらへんの設定が初期化されることもあるみたいです）。
再度デスクトップPCをシャットダウンしてWoLを実行したところ、今度は成功しました。なぜ、、
成功したときと失敗したときの違いは日付けを跨いだくらいだけどなぁと思っていましたが、**デスクトップPCがつながっている電源が毎晩停止する**という特殊なことになっていることを思い出しました。
試しに**デスクトップPCの電源をコンセントから抜き挿ししてみると、WoLによる起動失敗を再現することができました！**

# その後のおはなし
私の利用環境では「デスクトップPCがつながっている電源が毎晩停止する」という特殊な条件は外せません。
どうにかできないかを製造元に問い合わせてみましたが、どうにもならないとの回答でした。残念。。。

### 打開案
電源復旧後も何とかしてWoLで起動させたいため、打開案を考えました。
ですが、いろいろな事情があってまだ実施には至っていません。
もし解決できた方がいれば、教えていただけると非常にありがたいです。
+ デスクトップPCをUPS(無停電電源装置)につなぐ
+ デスクトップPCのBIOS設定でAC電源復旧時電源ONを有効にする
+ 物理的にスイッチONしてくれる機器を設置する

### 電源復旧後のWoLは本当に不可能なのか？
最後の悪あがきで、他のデスクトップPCでも電源復旧後のWoLができないかを確認してみました。
すると、別のデスクトップPCは電源復旧後のWoLに成功することがわかりました！
製品によってできたりできなかったりするんですね。

# まとめ
今回は電源復旧後にデスクトップPCに対してWoL実行したところ、失敗した例について紹介しました。
ただ、すべてのデスクトップPCができないというわけではなく、**製品によってできるものとできないものがある**ということがわかりました。
この記事の内容が、新たにデスクトップPCの購入を検討している方の助けになれば幸いです。
Cloudflare Workers & D1 + Vue.jsでつくった名言スライドショーをCloudflare環境へデプロイする

https://qiita.com/fujino_tech/items/acddd92f52471c63ad3f

前回までのあらすじ。

好きな言葉や明言を表示してくれるWebページをつくった筆者。

ほぼ使う用途のないツールをつくること、十数個目とかの筆者はめずらしくこのツールはプロダクション環境へデプロイすることを思いつく。

というか、開発環境とプロダクション環境の切り分け方法を勉強したくてやってみることにする。

はたして、目論見通りデプロイできるのだろうか……。

# 結論

デプロイできました。

開発環境とプロダクション環境の切り分けもできました。

開発環境とプロダクション環境で違う要素は、

- フロントエンド側から見たリクエスト先のAPIのURL
- API側から見たリクエストオリジンのURL

です。

これを切り分けて、デプロイ前後でコードの書き換えを不要にしました。

では、これの実現方法です。

:::note
これが正解の方法かは不明です。実用的かもわかりません。
:::

# コードの書き換え

## フロントエンド

フロントエンド側はstaticなHTMLファイルですので、Node.js環境であれば使える`process.env`は使えません。

よって、環境を判断する要素として、`window.location.hostname`を用いました。

```js
const isDevelopment = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
```

https://developer.mozilla.org/ja/docs/Web/API/Location/hostname

これを用いて、APIのURLを切り替えます。

```js
const apiUrl = {
    development: "http://127.0.0.1:8787",
    production: "https://****.****.workers.dev"
}
const url = isDevelopment ? apiUrl.development : apiUrl.production;
```

production時のURLはWorkersアプリを`npx wrangler deploy`でデプロイして発行されたURLが必要ですので、デプロイしておきましょう。

フロントは以上です。

## サーバーサイド（API実装側）

https://developers.cloudflare.com/workers/configuration/environment-variables/

> For local development with wrangler dev, variables in wrangler.toml are automatically overridden by any values defined in a .dev.vars file located in the root directory of your worker. This is useful for providing values you do not want to check in to source control.

こちらを参考にdev.vars`ファイルを作成し、そちらへ以下を記述します。

```.dev.vars
IS_DEVELOPMENT="true"
```

そして、これをコードから参照します。

```ts
interface Env {
	DB: D1Database;
	IS_DEVELOPMENT: string;
}

export default {
	async fetch(request, env, ctx): Promise<Response> {
		const isDevelopment = env.IS_DEVELOPMENT === 'true';
		const allowOrigin = isDevelopment ? '*' : 'https://****.pages.dev';
  
		console.log("allowOrigin -> ", allowOrigin);
  
		if (request.method === 'GET') {
			if (request.url.endsWith('/v1/words')) {
               /* 略 */
			}
		}
		return new Response('Hello World!');
	}
} satisfies ExportedHandler<Env>;
```

production環境時のURLはフロントエンドをCloudflare Pagesにデプロイして発行されたURLとなるので、一度デプロイしておきます。

フロントエンドとサーバーサイドで互いのURLが必要ですので、簡易的な実装状態でデプロイして、それぞれを再デプロイする必要があります。


# デプロイ

フロントエンドとサーバーサイドのそれぞれのデプロイ方法は以下のドキュメント等をご参考に。

フロントエンド
https://developers.cloudflare.com/pages/get-started/git-integration/


サーバーサイド
https://developers.cloudflare.com/workers/wrangler/commands/#deploy

また、`--remote`フラグをつけたSQLコマンド実行でプロダクション環境のデータベースへデータを流しこんでおく必要もあります。

```
npx wrangler d1 execute prod-d1-tutorial --remote --file=./schema.sql
```

# 動作確認

ローカルで動作確認したときと同様の動きをすることを確認しました。

コンソールにもエラー文などはありませんでした。

# 終わりに

これでデプロイ完了です。

かつ、開発環境とプロダクション環境でAPIのURLを変更することもできましたので、開発がしやすくなりますね。

では、ここまで読んでいただきありがとうございました。
インターネットにつながらない環境でDifyを使用するメモ (APIサーバとの連携編)

# はじめに

インターネットにつながらない環境でDifyを使用するメモです。
インターネットにつながらない環境でDifyの基本的な使い方のメモはこちらです。

https://qiita.com/kitazaki/items/4d4b4290ad2a4be482b4

今回はインターネットにつながらない環境の中でDifyと外部(APIサーバ)を連携させる方法について説明します。
APIサーバにはNode-REDを使用する前提で説明します。

![スクリーンショット 2024-12-23 17.25.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/2bb631ef-9823-2a70-37c9-f363dbaf5c05.png)


# 環境準備

インターネットにつながらない環境にDifyを構築するメモはこちらです。

https://qiita.com/kitazaki/items/c17ab374cd4072b04963

インターネットにつながらない環境にNode-REDを構築するメモはこちらです。

https://qiita.com/kitazaki/items/c6758069fe9be8d15214

Node-REDをDifyと同じサーバ(またはVM)の上で起動することも可能です。
その場合、Node-REDを起動する時にDifyと同じdockerネットワーク(docker_default)を指定します。

```bash
sudo docker run -d -v /home/ユーザー名/.node-red:/data -p 1880:1880 --net=docker_default --name node-red nodered/node-red:latest
```


# API接続

DifyとNode-REDをREST APIで接続します。

### Node-RED

サンプルとしてシステムの状態をOKまたはNGで応答するフローを作成します。
フローの全体像です。

![30.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/0abbd50a-74c9-0797-ee35-8ba7944fe58a.jpeg)

以下のノードを使用します。

- http in
- change
- http response

「http in」ノードのURLに名前(パス)を入力します。例として「/node-red」とします。

![33.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/88cb6287-6dc5-cf79-90e9-413997c7ebf9.jpeg)

「change」ノードはシステムの状態を設定します。
対象の値はJSONata式(ランダムで「OK」または「NG」を応答する例)で設定します。

```json:JSONata
$shuffle(["OK","NG"])[0]
```

![31.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/cf055249-dbf6-4b91-ef40-0d53081b1416.jpeg)

![32.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/fc67a473-b8cf-a904-296a-57ea75b0b6ad.jpeg)

「http response」ノードはそのままで、設定する必要はありません。


### Dify

サンプルとしてAPIサーバへシステムの状態を問い合わせて、応答結果(OKまたはNG)に応じてシステムの状態を回答するワークフローを作成します。
ワークフローの全体像です。

![40.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/1987203a-857d-f08e-aff5-7c45546dc6e8.jpeg)

以下のノードを使用します。
「開始」ノードの右側に「HTTPリクエスト」「LLM」「終了」ノードを追加します。

「開始」ノードはそのままで、設定する必要はありません。

「HTTPリクエスト」はAPIのURLにNode-REDのURLを入力します。

![51.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/553cb6e8-2461-9745-8e8f-0d2fbaea29ea.jpeg)

Node-REDをDifyと同じサーバ(またはVM)の上でコンテナを起動した場合の例です。

```text
http://node-red:1880/node-red
```

「LLM」ノードはコンテキストのSYSTEMにプロンプトを入力します。

![52.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/e3aea58f-d59a-e34b-2c6a-8b39603fb049.jpeg)

```text
システム状態がOKの場合は正常です。
システム状態がNGの場合は異常です。
システム状態を回答してください。

#システム状態
/HTTPリクエストの変数{x}body
```

「終了」ノードは出力変数にLLMの変数{x}textを選択します。

![https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_72479_756ef3ae-ee77-fab7-e843-97420a1bd950.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/1d1a9dc0-dc02-c472-2b0f-bdc38e2589e7.jpeg)

### 実行結果

「実行」を選択します。
システム状態がOKの場合の応答例です。

![41.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/432d955f-7dee-302a-7341-dbd94da81777.jpeg)

システム状態がNGの場合の応答例です。

![42.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/24cfae08-83e1-6462-a2a0-800abbebb78b.jpeg)
米田の補題 #6 対象と射の例　自然数　

# 米田の補題は、圏論でもっとも重要な定理です（繰り返し）
圏論は、数学の基礎理論です。いままで、[万物の理論](https://amzn.to/3ZLmCJH)
といわれていましたが、[数理科学 11月号](https://amzn.to/4iz6NgM)では、なんと　<font color="Red">万物・万事・万人</font>のための数学理論とまでいわれるようになりました
このAdventCalendar は、体験的に圏論の最も重要な定理である米田の補題を体験的に理解してもらうためにかいています

参考にしているのは、[圏論の道案内](https://amzn.to/4iH2Rus)です

# 圏の例としての自然数
対象の中に圏の構造をしっかりもっていて、自然数全体として一個の対象となることもできるのが自然数です。圏の例としては、自然数をまず、念頭におくのがいいでしょう。数学的には順序構造をもてばいいのですが、体験的にわかりやすい対象として、条件のきつい自然数が面白いです。

```mermaid
graph LR;
a[3]-.->|足す2|b[5];
d[自然数]-.->|足す2|d[自然数 対象はひとつ];
```

射の定義も簡単になります。上記の例では、自然数の２が射の値（射の識別の値）になります。自然数の値は、それ自体が、射の値になっています。
射全体[域:３、射の値:2、余域:5]

そして、対象がひとつの場合にも対応しています

# 自然数は、連番として、よくつかいます
受付順に連番をつかうことは、よくあります。普段から私達は自然数をつかうのになじんでいます。ものを数えるには日常よくおこないます。幼稚園児もできるのではないでしょうか？　受付で連番が連番としきちんとならんでいると、何番目の人をチェックするときには非常に簡単です。人の名前の順番になっていて、連番が乱れていると、連番で探すのは非常に大変です。順番は重要です。そして、次の値がわかっているのがすごいです。2の次は3です。1.5の次はなんでしょうか？　自然数をそのまま使う連番を私は、**完全連番**とヨンでいます。これからときどき、完全連番ということばをつかうことがあります。なお、自然数は、ゼロから始まるものとします。普段、数えるときは、１からはじめますけど、数学的な数の構造を考えるときには、ゼロからがこのましいのです

**米田の補題川柳 自然数ゼロからはじめ次々と**
順番に物事がたんたんと処理されるといいのですが、実際上はそうもいきません。プロジェクトではあちこちブレます。実際の作業は、ブレを少なくする過程ではないでしょうか？　不確実を確実にするのと似ていますね。量子コンピュータの発想は幅広く使える気がしませんか？
ポインター、構造体

## はじめに

A Tour of Goについて勉強になった箇所をまとめる。

### ポインター

・```&```は、ポインタを引き出す
・```*```は、ポインタの指す先の変数を示す（デリファレンス）

```Go
package main

import "fmt"

func main() {
	i, j := 42, 2701

	p := &i         // point to i
	fmt.Println(*p) // read i through the pointer
	*p = 21         // set i through the pointer
	fmt.Println(i)  // see the new value of i

	p = &j         // point to j
	*p = *p / 37   // divide j through the pointer
	fmt.Println(j) // see the new value of j
}
// 42
// 21
// 73
```

### 構造体

ドット( . )を用いてアクセスする

```Go
package main

import "fmt"

type Vertex struct {
	X int
	Y int
}

func main() {
	v := Vertex{1, 2}
	v.X = 4
	fmt.Println(v.X)
}
// 4
```

・```Name:```構文を使って、フィールドの一部だけを列挙することができる
・```&```を頭に付けると、新しく割り当てられたstructへのポインタを戻す

```Go
package main

import "fmt"

type Vertex struct {
	X, Y int
}

var (
	v1 = Vertex{1, 2}  // has type Vertex
	v2 = Vertex{X: 1}  // Y:0 is implicit
	v3 = Vertex{}      // X:0 and Y:0
	p  = &Vertex{1, 2} // has type *Vertex
)

func main() {
	fmt.Println(v1, p, v2, v3)
}
// {1 2} &{1 2} {1 0} {0 0}
```
EXCELセルをダブルクリックで飛ぶ時の対処法

# セルを編集しようとしたらどっか行った

皆さんはそのような経験あるでしょうか？私はしょっちゅう起こしてイライラしてました。
そんなときの解決方法を探すためネットの海に潜ると下記のような記事を見つけました。

https://www.wakarutodekiru.com/blog/technic/3771.html

おお、解決やな。
だがしかし、記事にある通りフィルハンドルの機能を失うことになるという大きなデメリット...
設定変更するの結構手間だし、F2押すのは慣れないので...
__設定を変更するショートカットを作ろう!__

## ショートカット作成
ということで選ばれたのは bat と powershell.
以前にexcelファイルが入ったフォルダをまとめてPDFに変換をするショートカットを作ったことがあったので行けるかなと思いコーディング開始!

``` microsoftshell:setting.ps1
$excelRunning = Get-Process -Name "EXCEL" -ErrorAction SilentlyContinue

if ($null -eq $excelRunning) {
$excelApp = New-Object -ComObject Excel.Application
$newexcel = $true
} else {
$excelApp = [Runtime.InteropServices.Marshal]::GetActiveObject("Excel.Application")
$newexcel = $false
}

$currentSetting = $excelApp.CellDragAndDrop

if ($currentSetting -eq $true) {
 $excelApp.CellDragAndDrop = $false
 } else {
 $excelApp.CellDragAndDrop = $true
 }

if( $newexcel -eq $false) {
 [System.Runtime.InteropServices.Marshal]::ReleaseComObject($excelApp) | Out-Null
 Remove-Variable excelApp } else {
 $excelApp.Quit()
 [System.Runtime.InteropServices.Marshal]::ReleaseComObject($excelApp) | Out-Null
 Remove-Variable excelApp }
```

<details> <summary> 解説 </summary>

1行目でExcelが実行中かを確認します。実行中でない場合エラーになってしまうため　
`-ErrorAction SilentlyContinue` を書いてエラーを無視かつ出力もなしで`$excelRunning`は`null`になります。
3行目からのif文はexcelが起動していない場合は起動する。すでに起動している場合はそのまま利用(今回の場合は設定の変更のため起動していればなんでもいい)する。

今回変更する設定の`CellDragAndDrop`がonかoffかをbooleanで判定し逆にする。

最後のif文は新しく起動した場合タスクの終了をするためのものです。
起動した状態でしか設定変えたと思うことないでしょうけど一応。
</details>

### bat作成
設定変更できるものの即実行じゃないと、ということでpowershellを呼び出すbatも作ります。
といってもこれだけです。
``` bat:setting.bat
 @echo off

powershell -ExecutionPolicy Unrestricted -File %~dpn0.ps1 %*

exit
```

同じフォルダに同じ名前のbatとps1ならコピペでOK。
わからないとか、できないなら絶対パスで。
ちなみに`-ExecutionPolicy` の変更はこのbatの実行終了までしか有効じゃなかったはずなのでご安心を。 

今回変更した設定↓

https://learn.microsoft.com/ja-jp/office/vba/api/excel.application.celldraganddrop

ほかの設定も探せば変えられると思うので設定したいものがあればぜひ。
以上powershell　と　バッチファイルを使用してExcelの設定を変更する方法でした。
Raycastで快適ウィンドウ操作！



## はじめに
Raycastは、Spotlightの代替として注目を集めるMac専用の生産性向上ツールです。この記事では、Raycastの「Window Management」機能を活用してウィンドウ操作を効率化する方法を紹介します。

---

## 1. Raycastの概要

### Raycastとは？
[Raycast](https://www.raycast.com/)は、キーボード操作を中心に、アプリやファイルへのアクセス、システム操作を効率化するツールです。  

### 特徴
- **高速検索機能**: アプリやファイル、システム設定を即座に検索可能
- **プラグイン拡張**: 多彩な機能を拡張できるプラグインが豊富
- **直感的操作**: シンプルなUIと分かりやすい設定画面

---

## 2. Window Management機能の概要

### Window Management機能とは？
Raycastの「Window Management」機能は、アプリケーションのウィンドウを素早く操作するための拡張機能です。マウス操作を減らし、キーボードだけで以下のような操作が可能になります。

- ウィンドウの位置変更（画面の左半分、右半分など）
- ウィンドウのサイズ調整
- ウィンドウのディスプレイ間移動

### なぜ便利なのか？
- **作業効率アップ**: マウス操作を排除し、集中力を保ちながら作業可能
- **複数ディスプレイ環境に最適**: ウィンドウを簡単に移動できる

---

## 3. Hotkey(ショートカット)の設定方法

### 設定手順
1. **Raycastを開く**  
   Raycastのアイコンをクリックしてアプリを起動します

2. **設定を開く**  
   右上の歯車アイコンをクリックして設定画面を開きます

3. **Window Managementを検索**  
   左側の「Extensions」タブを選択し、検索バーに「Window Management」と入力します

4. **Hotkeyを設定する**  
   設定画面で各操作に対応するHotkeyを自分好みに割り当てます

![Window Management.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3903827/6e8575e8-4a53-2258-1ad5-534d3c786b37.png)


### ポイント
- 他のアプリとショートカットキーが競合しないように設定しましょう
- 頻繁に使う操作は覚えやすいキーを選ぶのがおすすめです

---

## 4. おすすめHotkey設定

以下は私が設定しているHotkeyとその活用シーンです。

### **Left Half**
- **Hotkey**: `^ + N`  
- **動作**: ウィンドウを画面の左半分に配置します
- **活用シーン**: コーディングや資料作成時に、エディタを左側に配置

---

### **Right Half**
- **Hotkey**: `^ + ,`  
- **動作**: ウィンドウを画面の右半分に配置します 
- **活用シーン**: チャットツールやブラウザを右側に表示

---

### **Maximize**
- **Hotkey**: `^ + M`  
- **動作**: ウィンドウを画面全体に拡大します
- **活用シーン**: 集中して作業したいときや、大きな画面での操作が必要なとき

---

### **Next Display**
- **Hotkey**: `^ + U`  
- **動作**: ウィンドウを次のディスプレイに移動します
- **活用シーン**: 複数ディスプレイ環境で効率的に作業したいとき

---

## 5. 総括

RaycastのWindow Management機能を活用することで、日々の作業効率が向上します。特に、キーボードショートカットを自分好みに設定することで、時間短縮と快適な操作性を実現できます。

初心者でもすぐに使い始められるこの機能、ぜひ一度試してみてください！

---

## 参考リンク
- [Raycast公式サイト](https://www.raycast.com/)
ゼロから始めるSnowflake（4/10）

# データベースオブジェクトの階層構造

Snowsightを利用したデータベースオブジェクトの参照および作成方法を学ぶ．また，`SHOW`コマンドを使用してオブジェクト情報にアクセスし，データのクエリを実行する．

## Snowsight オブジェクトブラウザ

Snowsightのオブジェクトブラウザは，データベース，スキーマ，テーブル，ビューなどのオブジェクトを検索・選択するためのツールである．

### 主要機能

1. **左メニューからアクセス**
   - 左側メニューの**データ**をクリックし，**データベース**を選択する．
   - オブジェクトブラウザが表示される．
   - オブジェクト名をクリックすると，詳細が表示される．

2. **ノートブックでの利用**
   - ノートブックの左上の**データベースタブ**をクリックして，並行してオブジェクトブラウザを利用可能．

## 手順

### Snowsightオブジェクトブラウザでのアクション

1. **新しいデータベースの作成**
   - `+ データベース`ボタンをクリックし，名前を**GARDEN_PLANTS**としてデータベースを作成する．

2. **スキーマの管理**
   - 作成したデータベース内の`PUBLIC`スキーマを削除する．
   - 以下の3つのスキーマを新規作成する：
     - **VEGGIES**
     - **FRUITS**
     - **FLOWERS**

## コードの実行方法

本演習ではSnowsightのノートブックを使用する．ノートブックはSQLとPythonのコードをセル内で実行可能である．以下のコード例を試してみる：

```sql
SELECT 'hello';
```

- **hello**はシングルクォーテーションで囲む．
- SQL文の末尾にはセミコロンを付ける必要がある．

## `SHOW`コマンド

`SHOW`コマンドを使用してデータベースやスキーマの情報を取得する．以下は例である：

1. **データベース一覧の表示**
   ```sql
   USE ROLE learner_rl;
   SHOW DATABASES;
   ```

2. **スキーマ一覧の表示**
   ```sql
   USE DATABASE GARDEN_PLANTS;
   SHOW SCHEMAS;
   ```

3. **サンプルデータベースの利用**
   ```sql
   USE DATABASE snowflake_sample_data;
   ```

Snowflakeのサンプルデータセットを利用し，TPC-DSやTPC-Hの標準データをテスト用に活用できる．

## 実行ステータスの理解

ノートブック内でのセルの実行ステータスは，色によって示される．

- **青い点**：セルは変更されたが未実行．
- **赤**：エラー発生．
- **緑**：正常に実行完了．
- **灰色の点滅**：実行待機中．

これらを理解し，効率的にコードを実行することが重要である．
【非同期処理】async await ← 理解しよう

# この記事について
この記事はこんな人におすすめです！

:::note info
- 非同期処理についてあまり知らない人
- 初心者の人
- なんとなく使っていて、意味まで分からない人
:::

# 1.非同期処理って？
まず、非同期処理について少し知っておきましょう。
では、皆さんが今行っていることってどのくらいありますか？
- 呼吸をする
- 体温を維持する
- 心臓を動かす

結構ありますね。これら全て**同時に行っていること**じゃないですか？
この**同時に行うこと**を**非同期処理**と言います。

# 2.普通にプログラムを書いてみよう
まずはこのプログラムを見てください。
```python:普通のプログラム
import time

def do_kanji_homework():
    print('Starting Kanji homework')
    time.sleep(4)                       # 漢字をする
    print('Kanji homework done')

def do_math_homework():
    print('Starting Math homework')
    time.sleep(2)                       # 算数をする
    print('Math homework done')

def main():
    do_kanji_homework()
    do_math_homework()

main()
```
このプログラムは、漢字と算数の宿題をするプログラムです。
このプログラムを実行するとこうなります。
```bash
Starting Kanji homework
# 4秒後
Kanji homework done
Starting Math homework
# 2秒後
Math homework done
```
これでは、1度に1つしか宿題ができません。これでは非効率です！
1度に2つの宿題が出来たら、その分時間がかかりません。
ということで、asyncとawaitの出番です！

# 3.同時に宿題をしよう
早速、asyncとawaitを使ってみましょう。
後でちゃんと意味は解説するので、安心してください。
```python:非同期処理を使ったプログラム
import asyncio

async def do_kanji_homework():
    print('Starting Kanji homework')
    await asyncio.sleep(4)
    print('Kanji homework done')

async def do_math_homework():
    print('Starting Math homework')
    await asyncio.sleep(2)
    print('Math homework done')

async def main():
    await asyncio.gather(
        do_kanji_homework(),
        do_math_homework()
    )

asyncio.run(main())
```
色々増えましたが、これを実行すると...
```bash
Starting Kanji homework
Starting Math homework
# 2秒後
Math homework done
# さらに2秒後
Kanji homework done
```
なんと宿題を2つ同時に開始し、4秒で全て終わらせることができました！

# 4.解説
## asyncio
非同期処理をするためのライブラリです。
### asyncio.sleep
```time.sleep()```の非同期バージョンだと思ってください。
### asyncio.gather
非同期関数を同時に開始する。
さっきの例だと、```do_kanji_homework```と```do_math_homework```を
同時に開始しています。
### asyncio.run
main関数を実行するための物。
## asyncとawait
### async
非同期関数の頭につける物。
漢字、算数の宿題をする関数とmain関数に使われている。
### await
非同期関数の中で非同期にしたい物の頭につける。
漢字、算数の宿題なら```asyncio.sleep```に、
mainなら```asyncio.gather```。

# おわり
非同期処理やasync、awaitについての理解は深まりましたか？
非同期処理はプログラムの中でも重要なもので、
覚えておくととても便利です。
この記事を読んでも分からなかったなら、
実際に記事に書かれていたコードを実行してみたり、
自分なりに変えてみたりすると意味が分かるかもしれません。

最後まで読んでいただきありがとうございます。
コメント、いいねしてくれると励みになります:cheese::cake:
ジャストワンを作成しよう！part1(AWS + Python)

## ジャストワンというボードゲームをwebアプリで作成しました。
はじめに
awsでのアプリ開発は初めてなのでコードや構成はがばがばなので参考程度にどうぞ

### ジャストワンって何？
ルール説明
ルールとしてはシンプルです。
回答者とヒント役に分かれてヒント役のヒントを元に回答者がお題を当てるというゲームになっています。
しかし、ヒント役のヒントが被ってしまったらヒントを出せないというのがこのボードゲームの面白いところになっています。
詳しくは「ぼくボド」さんのサイトをご参考ください。
https://boku-boardgame.net/just-one

それでは開発環境をご紹介します。
### 開発環境
#### AWS
サーバー部分はAWSを使用。
構成図は以下です。
ApiGatewayからLambdaを実施してdynamodbへのpost,get処理をするようになっています。

s3にはhtml,css,javascriptなど配置して静的ホスティングにて実現しています。
dynamodbはプレイヤー情報、ゲーム情報などを格納しています。
cloudwatchはlambdaのログ,ApiGatewayのログ確認のために使用しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3241637/f8f9f65c-0fc3-8f79-ad98-30bb3615fcbd.png)

### 完成形
完成形の紹介
タイトル画面
こちらに名前を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3241637/065cfccb-9b25-ecd3-a9cd-e000f12599fb.png)

こちらでルーム作成、ルームに参加ができる仕組みです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3241637/a5746cc7-bcd4-d1b1-49ed-412d0f06033b.png)

画面遷移後は名前が表示されるようになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3241637/9821cea0-ece5-d820-95e6-a794901633ee.png)
プレイヤーが揃うとこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3241637/8ac1b0dd-ba02-c0ed-598a-70e6795be787.png)
ゲーム開始するとこんな感じでお題が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3241637/c8ccb512-2c92-1e81-d61f-b6bcff5788eb.png)
回答者画面はこんな感じ（ゲーム開始すると1名だけ選ばれる）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3241637/d3092657-880c-5a52-822b-1434ada502a0.png)
画面遷移後は全員のヒントが表示されるようになっています。
こっからかぶっていないヒントを選択して完了ボタンを押すと回答者が回答できるようになっている仕組みです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3241637/08c37713-d680-69e7-817f-9a27dddc8db4.png)
回答者画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3241637/89476b37-3c39-a6b4-ebc8-aad12ad81a05.png)
最後回答後の画面
答えは「トラック」なんですけども画面に表示されてないですね。。。
最後に答え合わせできる画面になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3241637/c9360e0b-99d8-dac5-9e79-e5a21d315a5a.png)

以上、ざっくりこんな感じで作成しました。
次回はコード修正等も行いつつ作成過程について記事を更新していこうと思います。

以上！次回もお楽しみに！！
なろうapiを使ってみた。

リクエストモジュールを使って、なろうapiを使ってみる。1
#パラメータで、ncode指定とlim指定 0000000は、小説のncode

import requests

url = "https://api.syosetu.com/novelapi/api/"

params = {"ncode":"0000000","lim":500}   

#ncodeを指定する。limはデータ量設定

response = requests.get(url,params,timeout=3)

print(response.text)

リクエストモジュールを使って、なろうapiを使ってみる。2
#　パラメータ ofで、タイトルと、更新時間を指定　 0000000は、小説のncode
#　https://dev.syosetu.com/man/api/   に仕様がある。仕様があっても
試す必要があるよね


import requests

url = "https://api.syosetu.com/novelapi/api/"

params = {
    "of": "t-nu",
    "ncode": "0000000"
         }

response = requests.get(url,params,timeout=3)

print(response.text)

#of パラメーターを指定して、必要なものだけを取得する。↓下記を目指した。

ほしいタイトルと、更新日時を取得できた。
MPG Z790 CARBON WIFI のSATAポート利用環境下でPCの起動・停止に時間がかかる暫定的対処

初めての投稿 & 個人的備忘録のため読みにくいです。申し訳ありません。
あとQiitaでの場違い投稿になってしまい重ねて申し訳ありません。

:::note info
あくまで暫定的な対処法になります。自己責任での対応としてください。
:::

## 該当PC環境
① Windows11
② MPG Z790 CARBON WIFI 
③ ↑のSATAポートを利用している


## 不具合事象例
① 起動に時間がかかる
② 停止に時間がかかる
③ SATAに接続しているストレージが突然or負荷時に切断される


## 暫定的対処_概要
SATA接続ポートの変更 & ASM1061 (ASMedia ASM1061)の無効化 
<font color=#FF0000>**【注意】SATAポートが合計6ポートから2ポート使えなくなります。
4ポートでの運用となってしまいます。**</font>


## 手順①（SATA接続ポートの変更）
①パソコンをシャットダウンしSATAポートの接続を変更してください。
上部4つのポートのいずれかに接続しなおしてください。(図中のSATA5~8)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356799/b33368af-ff5e-0ff9-7ac9-b8ce3b4bc46e.png)

## 手順②（ASM1061の無効化 ）
※BIOSに行ける人は手順⑦から実施してください。
作業手順はWindows11になります。

① [ Windowsスタート ] から[ 設定 ] に移動する
②左側の [ システム ] をクリックし [ 回復 ] をクリック
③ [ PCの起動をカスタマイズする ] の [ 今すぐ再起動 ] を実行

ｰ再起動が実施され起動後、水色の画面になるｰ

④ [ トラブルシューティング ] を選択
⑤ [ 詳細オプション ] を選択
⑥ [ UEFIファームウェアの設定 ] を選択後 [ 再起動 ] を実行

-BIOS設定画面に切り替わる-

⑦ 上部の [ Advanced(F7) ] を選択
⑧ 左側の [ SETTINGS ] を選択
⑨ [ Integrated Periphererals ] を選択
⑩ SATA Configuration の [External SATA 6GB/s Controller Mode ] を選択 [ Disabled ] に変更
⑪ 右上の [X] 選択し、Save Configuration and exit? の画面で [ yes ] を実行

-システムは再起動され通常動作に戻る-

## 依存性確認
ASM1061はマザボのブロックダイアグラムからSATA_A1、SATA_A2のみの制御を行っているため、他コンポーネントに影響が発生しにくい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356799/11d82511-0a05-5456-5faa-dcfe7f297781.png)

## あとがき
自分の環境では上記設定変更で回復し安定して動作できています。
あと、ASM3242の方もちょっと挙動が怪しい可能性がありそう、、
当マザボは当時のハイエンド寄りのマザボでしたが、割とピーキーな性能
(Gen5NVMe使うとハイエンドグラボのパフフォーマンスが下がってしまう等)
なので購入する際はよく仕様書を読み込みましょう。。
ASM1061はインテル・ライゼン関わらず不具合・不安定報告があるみたいなので勘弁してほしいですね.....

ここまで拝見いただきありがとうございました。


## 参考文献
MPG Z790 CARBON WIFI 仕様書(pdf)
https://download-2.msi.com/archive/mnu_exe/mb/MPGZ790CARBONWIFI.pdf

WindowsからBIOSに移動
https://faq.tsukumo.co.jp/index.php?solution_id=1379

MSI UEFI BIOS
https://jp.msi.com/blog/uefi-bios

ここのサイトの日本語版and丁寧版と思っていいかもしれない。似たような記事
https://forum-en.msi.com/index.php?threads/mpg-z790-carbon-wifi-boot-problems.388698/
2024年4月初開催　DroneBird全体合宿 in 加賀の総括

# イントロ
今般の合宿訓練の目標は、個人個人の能力を自ら発見すること、つまり震災で我々が活動するにあたって、どのようなチーム編成で実行するのかということも重要であるが、それ以前に自分自身の能力がどのレベルにあるのかということを認識することで、少ない人数で、効率的効果的な配置を行って任務のプランが建てられるということを前提として、その認識を、災害時にチームを編成するメンバーがその人の能力を理解するということも、災害現場において極めて重要であり、任務が能力過多になっている場合や、その人物の代役が必要になった時などに、メンバーでの合意形成が柔軟に行える強い組織となることが想定目的と言っていいだろう。

そうした訓練を行いつつも、訓練中に出る成果は、単なる練習を行ったフォトグラメトリーでは、練習という一義的な意味として残すものとなるが、今般は、練習場所を提供していただいた小学校のグランド敷を拠点として、加賀市の協力の元、地域で問題となっている防風林の松が虫による被害を受けていることについて、訓練で撮影した成果を用いて、その対策を検討することに活用していただくというミッションが与えられた。

# 機体
DroneBird所有のドローンで訓練に投入されたものはAereROBO Wing (VTOL)AeroSense社製（写真）![437575009_7959308364112009_87283884059591948_n.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322439/7e9d6250-0734-043a-6c97-e805053dccfc.jpeg)
とeBeeX![254579239_4930019410374268_5439640047766284114_n.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322439/2d7a5184-7760-ffb2-9563-421f4e3c5d14.jpeg)
とeBeeGeo(Plane)sensefly社製である。また参加者個人で所有する機体、DJI Phantom4, SONY Airpeak S1などは、訓練中の模様を撮影するなどに使用され、訓練に合わせて、小規模なミッションを設定し個人のレベルに合わせて内容を実行して、それぞれの目的と成果の達成を目指した。

# 一日目
VTOLを見たことのないメンバーに向けての取り扱いと注意事項及びその計画の立案を専用のソフトウェアの操作時の画面を表示しながら、機体のキャリブレーションを実際に行い、非常に繊細なセンサーの取り扱いや機体の反応、画面でのエラー表示、ユニークな右翼左翼が完全に取り付けられているかの確認方法や、上昇法のマルチコプター用のプロペラの脱着方法の難しさの説明など。実際に機体が扱える技術者メンバーとなることを目標として、初段の説明を中心に行うことから始まった。

実際の撮影は２００ｍの幅で海岸沿いに５ｋｍの距離が撮影することから、VTOL機ではなくeBeeXでの撮影の計画及び実行が選択された。固定翼は日本の地形では、都市部での運用が難しい機体ではあるが、１度飛び立てば９０分近いフライトが可能であるという特性から、DroneBirdの活動において、主力的に使用している機体であるとともに、普段からマルチコプターを運用するメンバーから固定翼機が実際に運得ようすることを目の当たりにすることで、自身が監視員となってもの、オペレーターがどのような操作を行っているのか知っていることも、監視員の作業中に一般人からの質問がなされた場合に、丁寧でより詳しい説明をすることも、災害現場で被災者に安心を与えられることに繋がるといったことが期待されている。また、片道５ｋｍのフライトを２０往復程度行うことにより、オペレーターから目視外になる条件が１０％程度見込まれる計画として、目視外飛行になる場合の電波塔の建て方と注意点や、電波範囲内になった場合のオペレーションやセッティングの注意点、天候風向きとフライト方向と計画、ランディング方法とランディングの角度設定と注意点などの説明がなされ、テイクオフは、飛行させて経験のないメンバーが熟練したメンバーからの指導を受けて、フライトを行った。

# 懇親会
各自取得した写真を合宿の夜にＢＢＱを囲みなら、画像の確認を行うとともに、合宿で参加できなかったメンバーをオンラインのZoom会議を設置して、意見交換を行うとともに、合宿で使用している環境や機材の紹介や参加しているメンバー紹介、課題についてのディスカッションを行った。

# 二日目
加賀市の公民館で会議室が提供され、撮影した写真のオルソ化工程の説明や、ドローン操縦者として知っておかなければならないＧＮＳＳの仕組みや作成されたオルソ画像をOpen Airial Mapにアップロードする手順及び注意事項などが説明された。

最初に想定されたミッションはすべて追行され、各メンバーの課題設定とチームとしての目標が達成された。活動の詳細についてはＳＮＳで発信し、取得されたオルソデータもまた、オープンデータとして公開されているものを加賀市に提供されることで今回のミッションを終了した。
普段は関東及び関西で訓練するという活動であるが、普段チャットで会話するメンバーが一同に会して有意義な時間を過ごすということは、深い意味を持ち今後の活動に生かされるであろう。
Vector形式の画像素材を生成AIに編集してもらう

お疲れ様です。Androidエンジニアのオクダです。

figmaなどのデザインツールからsvgで出力できることから、
アプリの画像をVector形式で利用することも増えてきました。

Vector形式だと縮尺を考えずに利用できる一方で、以下のときが面倒ですよね。
- 素材が更新され、画像のアスペクト比が変わったとき
- 素材が更新され、画像の表示位置が変わったとき

開発に伴って素材を差し替えたら、表示が崩れるのはよくあることかと思いますが、
Vector形式の画像でも実は簡単に直せます。
Vector形式の描画は座標で管理されているので、生成AIに適切な指示を与えれば良いのです。

### 例
今回の例は、画像をもう少し上に表示したいという内容です。

![Screenshot 2024-12-23 at 15.12.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631718/088dd543-44b5-c81d-b129-648972426e37.png)

以下の指示を与えました。
```
vector形式の画像素材の位置調整をしてください。
描画の位置を20%ほど上に上げてほしいです。

<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#30A800" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
        
    <path android:fillColor="#FF000000" android:pathData="M17.6,11.48 L19.44,8.3a0.63,0.63 0,0 0,-1.09 -0.63l-1.88,3.24a11.43,11.43 0,0 0,-8.94 0L5.65,7.67a0.63,0.63 0,0 0,-1.09 0.63L6.4,11.48A10.81,10.81 0,0 0,1 20L23,20A10.81,10.81 0,0 0,17.6 11.48ZM7,17.25A1.25,1.25 0,1 1,8.25 16,1.25 1.25,0 0,1 7,17.25ZM17,17.25A1.25,1.25 0,1 1,18.25 16,1.25 1.25,0 0,1 17,17.25Z"/>
    
</vector>
```

得られた回答は省きますが、生成されたコードを貼り付けると表示位置を上にできました。

![Screenshot 2024-12-23 at 15.15.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3631718/0f9bc0f9-c375-421b-9514-770573edaa61.png)

なるほど、位置を上にするだけならgroupタグで括ってからtranslateYで調整するだけで良いんですね。
アスペクト比を変えるときはもう少し工夫が必要だったと思いますが、
どちらにせよ、いい感じに仕上げてくれるので、
生成AIのおかげで開発が楽になってくれて嬉しいです。
新卒で入った会社を辞めて転職した話

## はじめに
自分は2018年に新卒入社し、6年ちょっと働いて今年(2024)の夏に転職をしました。
ここでは転職理由とか、転職活動でどんなことをしたか、転職してからどう変わったとかつらつらと書こうと思います。技術的な内容は記載しない予定です。

## 前提
はじめにかくようなことではないですが、正直、自分は
お仕事大好き！技術大好き！
エンジニアとして成長するために日頃から◯◯してます！
資格勉強を最近やっています！

などのモチベーションは残念なことにまっったくありません。

自分の生活のために、推し事のために、美味しいものを食べるために、たまに贅沢をするために働いています。お休み最高〜と思っているような人間です。

Twitter（現X）で昔流れてきた下の画像をたまに見返すのですが、この3つの円が重なっている部分を仕事にできる人は「天職」を見つけた人なんだろう。と思っています。自分は3つどころか、赤と青の夢もないんだな〜と気持ちがしんどくなることもありました。が、転職活動をする際は、「嫌なこと・苦痛なこと」をしてお金を稼ぐのではなく「8時間拘束されても苦ではない」ことでお金を稼げればよい。と割り切って活動してました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418704/dc98f769-0fe6-a8d9-a5c0-fce2e82b55bd.png)
↑参照：https://x.com/sen_u/status/1294898191523954690?t=mf_IqVSuCs39bkSTpN_b4Q&s=19

## 転職のきっかけ
一つ前に記事で少し触れていましたが、自分のキャリアについて考えることが多々ありました。
今このタイミングで転職をしたい！というよりかは、この会社に10年後もいるのかなと考えた時に、そのイメージがあまり湧かないと思い始めたのが2021年の終わり…（現在2024年w）
そこではじめて、転職という選択肢が自分の中に生まれました。

新卒で入社した会社以外の経験がないことに、もったいなさを感じたのと、冒頭にも記載しましたが、あまり仕事に対してのモチベーションがない中で次の会社で働こうと決めたのは今働いている会社のサービスに惹かれたからですかね。
やりたいこともあまりイメージはつかないまま企業探しをするのは大変でしたが、「仕事のことは好きになれないかもしれないけど、会社のサービスのことを好きになれれば仕事が楽しくなるかもしれない（願望）」と考えながらの方が企業探しはしやすかったです。

## 転職活動
転職活動で行ったこと
| No | 内容               |
|----|--------------------|
| 1  | 転職サイトへの登録   |
| 2  | 自己分析             |
| 3  | 会社探し             |
| 4  | 自分の会社について知る |


2は一言で自己分析と書いていますが、自分のやりたいこと、やりたくないこと、自分はどんな仕事に向いているか改めて考えるだけではなく、客観的に自分の市場はどんなもんなのかも調べたりしていました。
3と4はほぼ同時並行でした。自分の今の環境より良くなるのか、悪くなっても妥協できるのかの比較をしていました。
1年ほど転職活動をしましたがなかなか決まらず、焦ってエージェントも利用しました。しかし、最終的には自分に合わないと感じ、再び自力で転職活動を続けました。

## 転職してから大きく変わったこと
・開発手法
前の職場ではウォーターウォール開発をしていましたが、新しい会社ではスクラム開発をしています。
徐々に慣れつつありますが、今のところ前の会社のやり方の方が好みではあります。
ただ、毎週スプリントを切ってやることを決めているので、何かしらの成果を出さなきゃいけないという気持ちは前よりも大きく持てている気がします。
好みかもしれませんが、SPをなんとなくその場で決めてそのままスプリントに進んで、間に合った、間に合わなかったでレトロを反省するよりももう少し慎重に見積もりをしたいなと思ったり、問い合わせや案件相談でちょろっと相談したいです！ちょっと調べてみます！すぐにできるのでやっちゃいます！などの当初予定（スプリントとしての確保）していないものは緊急度が高くない限りスプリントを優先で着手をしてはいけないような雰囲気があるのがまだ慣れていないのかもしれないです。

・人間関係
チームの人とはほとんど顔を合わせていないので、雑談が少ないです。もちろん仕事に支障があるわけではないのでこちらから何かをするわけでもないという。
あとは前の会社では「同期」がいたので、ちょっとした相談もしやすかったなあと思うことが多々あります。
お酒があまり得意ではありませんが、飲み会があれば二次会に参加して、顔を覚えてもらうことを意識しています。

## まとめ
2024年は自分にとって転職という大きなイベントがあった年でした。
新しい環境で多くの人と関わり、学び、経験することがありましたがまだまだ今の会社で活躍をしているとは胸を張って言えないので、来年も引き続き自分自身をアップデートしていきたいと思います。
systemd-networkdでGREトンネルを張る方法について記していきます

はい、こんにちはtuna2134です。

HomeNOCさんとBGP接続をする際に、GREトンネル張ろうとしたら、ubuntuなのでnetplan使ったんですよ。しかしEncapsulationLimitを無効化することができなかったので、代替案としてsystemd-networkdを使うことにしました。

## Config(netdev)
早速ですが、コンフィグです。ネットワークのデバイスの定義をここでするとおもいます。
```
[NetDev]
Name=gre0
Kind=ip6gre

[Tunnel]
Independent=true
Local=自分のIPv6
Remote=相手のIPv6
EncapsulationLimit=none
```
好きな名前で保存してください。例：`gre0.netdev`

## Config(network)
アドレスの定義です
```
[Match]
Name=gre0

[Network]
Address=自分のIP(Prefix付きで)
```
これを好きな名前で保存してください。例：`gre0.network`

## 最後に
netplan早く対応してほしいなー。対応してくれていたらこんなことしなくてもよかったのに、、、と思いました。
複数のGA4プロパティにカスタムディメンションを一括作成

:::note warn
本記事は2022年7月時点での内容になります。最新情報については公式サイトなどを確認願います。
:::

[GA4で複数プロパティを自動作成](https://qiita.com/ricardinho/items/0e9b27892e65408fbb27)にて、GA4のプロパティを一括作成する方法を紹介しました。今回はその続きで、各プロパティにカスタムディメンションを一括作成する方法を紹介します。

手順は以下になります。

1. カスタムディメンションのリストを作成
2. 対象のGA4プロパティ一覧を読み込む（今回は省略）
3. カスタムディメンションのリストを読み込み一括作成

# カスタムディメンションのリストを作成

作成するカスタムディメンションの一覧をGoogle Sheetに作成します。

- シート名：customdimensions
- A列：カスタムディメンション名
- B列：スコープ（EVENT、USER）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939399/fa5083a1-39b8-962b-e5e7-de96a40af336.png)


# Google Apps Scriptの作成
今回もGoogle Analytics Admin APIをを使用しますが、この設定方法は[前回の記事](https://qiita.com/ricardinho/items/0e9b27892e65408fbb27)を参照願います。

## 対象のGA4プロパティ一覧を読み込む
こちらはGoogle SheetにGA4プロパティの一覧を作成し、そのシートを読み込むだけなので、今回は省略して、Google Apps Script内の配列変数に直接入れます。

## カスタムディメンションの一覧を読み込む
先ほどGoogle Sheetに作成したカスタムディメンションの一覧を読み込む関数getCustomDimensionsFromSheet()を作成します。

このgetCustomDimensionsFromSheet()関数は下記の属性を含めた変数の配列を返します。

```
const FILEKEY ="abcdefghijklmno"; // GoogleSheetのキー（URLの一部分） 例：https://docs.google.com/spreadsheets/d/abcdefghijklmno/edit#gid=0

function getCustomDimensionsFromSheet(){
  var sheetName = "customdimensions";
  var spreadsheet = SpreadsheetApp.openById(FILEKEY);
  var sheet = spreadsheet.getSheetByName(sheetName);
  var lastRow = sheet.getLastRow(); 
  var ar = sheet.getRange(2,1,lastRow,2).getValues();
  var ret = [];
  for(var i =0; i < ar.length; i++){
    if(ar[i][0] == null || ar[i][0] ==""){
      break;
    }
    var a = {
    "displayName": ar[i][0], 
    "parameterName": ar[i][0],
    "scope": ar[i][1] //"EVENT"
    }
    ret.push(a);
  }
  return ret;
}
```

例：
- displayName: “customer_status”
- parameterName: “customer_status”
- scope: “USER”

## GA4プロパティにカスタムディメンションを作成

上記で取得した情報をGA4プロパティに1つずつ作成します。ここでは1つのカスタムディメンションを作成する関数createCustomDimension()を作成します。

```
function createCustomDimension(propertyId, customDimensionData){
/* 
propertyId = 3234568;
customDimensionData= {
  "displayName": "customer_status",
  "parameterName": "customer_status",
  "scope": "USER" //"EVENT"
}
*/
  var ret = AnalyticsAdmin.Properties.CustomDimensions.create(customDimensionData, 'properties/' + property);
  return ret;
}
```

最後に、上記をGA4プロパティ個数×カスタムディメンション個数分繰り返すmain()関数を作成します。

```
function main(){
  var properties = [
    3234568,
    3234555,
    3234542,
    3234609,
    3234553,
    3234563,
    3234584
  ]; // 今回はGAプロパティIDの読み込み箇所のスクリプトは省略して配列に直接入れています
  for(const property of properties){
    var cds = getCustomDimensionsFromSheet(property);
    for(const cd of cds) {
      try{
        console.log(createCustomDimension(property, cd));
      }catch(e){
        console.log(e);
      }
    }
  }
}
```

上記の関数を実行すると、各GA4プロパティにカスタムディメンションが作成されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3939399/4f81a0ed-77ad-4e41-3565-918b41f7530a.png)