OmniAICreator/Qiita-1.07M huggingface dataset:
Teams自動投稿フローを作成したら連続投稿する現象が起こったので解決するよ【PowerAutomate】

# はじめに
先日、以下のような記事を投稿しましたが、発展版となります。

https://qiita.com/MAsa_min/items/2f61a6fb1b19e882761d

上記のフローを実際に稼働させていたところ、新規フォルダを作成するとそのアナウンスが、さらに新規フォルダ内にファイルをアップロードするとそのアナウンスが投稿される使用であると判明しました。

つまり、**以下の状況のいずれでもフローが開始**し、チャネルにアナウンスがされます。
- ファイルがアップロードされる
- 新規フォルダが作成される
- 新規フォルダ内にファイルがアップロードされる

例えば、フォルダを新規作成（1回目のアナウンス）し、新規作成したフォルダ内にファイルを3つアップロード（3回アナウンス）すると、**合計4回**アナウンスされてしまいます。

フォルダが作成された時はフォルダのアナウンスだけでいいので、その点を改良しました。

# フロー
試行錯誤した結果、以下のようなシンプルなフローに改良できました。条件式を追加しただけです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3493004/e9563346-7aaa-bcf9-fc6b-1d59348d4777.png)

### 条件式
条件式を以下のように設定するだけです。
アップロードされたファイルor新規作成したフォルダの親フォルダのパス（条件式左側）がトリガーとして監視しているフォルダのパス（条件式右側）と一致するかどうかを判別しています。
一致していれば（True）、以降のフローが続きチャネルにアナウンスします。一致しなければ（False。例えば新規作成したフォルダ内へのファイルアップロード）、何もしません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3493004/8fef6ca5-25dd-a94b-5ed9-f5bd347b92c0.png)

これでファイルのアップロードもしくはフォルダの新規作成の場合のみチャネルにアナウンスがされます。
新規作成したフォルダ内にファイルをいくらアップロードしようとも、条件式で弾かれるのでチャネルにアナウンスがされることは無くなりました。

# さらに発展版
ファイルがアップロードされた場合と、フォルダが新規作成された場合でアナウンスの内容（本文）を変えたい場合もあると思います。その場合は、さらに条件式を追加しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3493004/be46c7fd-cced-6f91-f8ab-ac36e8bb435a.png)

### 条件式
1段目の条件式で、フォルダであるかどうかを判別するようにすればオッケーです。
フォルダである場合（True）、以降のフローが続きチャネルにアナウンスがされます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3493004/a9814a4e-cdfc-5443-4ce2-79ecf91ed064.png)

フォルダでない場合（False。ファイルの場合）、2段目の条件式に入り、先述の親フォルダのパスとトリガーで監視しているフォルダのパスを比較します。

あとは投稿アクションの中身をそれぞれで書き分ければ、ファイルがアップロードされた場合と、フォルダが新規作成された場合でアナウンスの内容（本文）を変えることができます。

# おわりに
フローを作成してドヤ顔で実装しましたが、問題点が出てきたので解決しました。
まぁ、一発でうまくいくことは無いですよね！

それでは、次の記事でお会いしましょう('ω')ノ
pythonはファイルのために、再帰処理を書かなくていいらしい


（この記事は、眠たい私がハイになりつつ書いたため、テンションがおかしいですがお許しください）

このディレクトリの中のファイル、権限とかを全部書き換えたいなあ…
でも再帰処理とかめんどいな〜
とか思っているそこの君！　os.walkを知っているかい！
# os.walkとは
ディレクトリツリーをたどって、すべてのフォルダ、ファイルをなぞることを、for文だけで実装できるようにしてくれる素晴らしいメソッド

# os.walkの引数、戻り値
### 引数
```top```
最初のディレクトリ、一番最初になぞることとなる
ここから下のディレクトリ、ファイルをなぞることになる

### 戻り値
```dirpath```、```dirnames```、```filenames```
それぞれ「現在のディレクトリ(topからのパス）」「サブディレクトリ(名前だけ)」「直下ファイル(名前だけ)」となっている

# os.walkの使い方

まず、このようなディレクトリ構造があるとき
```bash
$tree ./test
./test
├── test1
│   ├── test4
│   │   └── text5.txt
│   └── text1.txt
├── test2
│   ├── text2.txt
│   └── text3.txt
└── test3
    └── text4.txt
```

Cとかなら再帰処理などを挟んで、とやかくやらないと全部のファイルを触らなければいけないところを…

```python:Test.py
import os

if __name__ == "__main__":

    for root, dirs, files in os.walk("./test"):
        print("現在ディレクトリ->",root)
        print("サブディレクトリ->",dirs)
        print("直下ファイル->", files)
        print("-----")
```
実行結果
```
現在ディレクトリ-> ./test
サブディレクトリ-> ['test2', 'test1', 'test3']
直下ファイル-> []
-----
現在ディレクトリ-> ./test/test2
サブディレクトリ-> []
直下ファイル-> ['text3.txt', 'text2.txt']
-----
現在ディレクトリ-> ./test/test1
サブディレクトリ-> ['test4']
直下ファイル-> ['text1.txt']
-----
現在ディレクトリ-> ./test/test1/test4
サブディレクトリ-> []
直下ファイル-> ['text5.txt']
-----
現在ディレクトリ-> ./test/test3
サブディレクトリ-> []
直下ファイル-> ['text4.txt']
-----
```

なんとfor文だけですべて完結させてくれる！すっげえ！
なんて革新的！


# 使用例
1. Linuxのファイル,ディレクトリ所有者変更スクリプト
```python3
import os
import pwd
import grp

def change_owner_recursively(path, user, group):
    # ユーザIDとグループIDを取得
    uid = pwd.getpwnam(user).pw_uid
    gid = grp.getgrnam(group).gr_gid

    for root, dirs, files in os.walk(path):
        # ディレクトリの所有者変更
        os.chown(root, uid, gid)
        
        # ファイルの所有者変更
        for file_name in files:
            file_path = os.path.join(root, file_name)
            os.chown(file_path, uid, gid)

if __name__ == "__main__":
    directory = input("ディレクトリのパスを指定してください: ")
    user = input("新しい持ち主のユーザ名を指定してください: ")
    group = input("新しい持ち主のグループ名を指定してください: ")
    
    change_owner_recursively(directory, user, group)
    print(f"所有者が'{user}:{group}'に変更されました。")

```

pythonって、素晴らしい言語だな…
MacからWindowsへ移行しても問題なかった

# はじめに
最近、Macが高いのとの、飽きてきたので、Windowsへ移行することにした。その時の、設定メモ。基本的に、Macでの操作感を維持したいので、それを前提に設定した。

あと、最低限の設定で済ませたかったので、MacとWindowsをいつでも行き来できるような設定にとどめた。多分、設定は1～2時間程度でできそうなのがメリット。

## 環境
### キーボード
HHKB Pro Type-S 無刻印（手放せない）
https://www.amazon.co.jp/dp/B01DVRXF0A/

### タッチバッド
トラックパッド使っていたが、マルチフィンガー操作もそこそこデフォルトで使えるので、このタッチバッドで慣れそう。
https://www.amazon.co.jp/dp/B0CHHQ5GTX/

## 準備
### PowerToysインストール
キーマップとショートカットの設定の変更するために必要

https://learn.microsoft.com/ja-jp/windows/powertoys/

## キーの設定

### WinキーをCtrlへ変更
Winキーはそんなに使うことないのと、Winかけ合わせのショートカットをCtrlの掛け合わせ（Macでいうところのcmd）のショートカットに変更できる。

これにより英語キーボードのIME変換をMacの時はCmd+SpaceだったのをCtrl+Spaceで実行できる。

### Win+Shift+Sのスクリーンショットの再マップ
スクリーンショットがWin+Shift+Sが使えなくなるので、マックの時Cmd+Shift+4のスクリーンショットをCtrl+Shift+4で利用できるようにする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/a45b3b71-877f-6534-edaa-eeb6e4a8c6b8.png)

## IMEの切り替え

言語オプションを選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/cfa586a8-85d6-987b-f893-3b5e35936a40.png)

Microsoft IMEのオプションからキーとタッチのカスタマイズを選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/49658cc5-5231-2093-25ec-1803b4305137.png)

Ctrl+Space（Shift+Spaceはお好みで）を設定する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/c5a050bb-a94c-a86b-567d-90d2463b97d4.png)

## Powershellの設定
PowershellでWSL2を使う事にしたので、Item2を使ってい経緯もあり、その設定を踏襲する。
Powershellを開き、「Ctrl+,」で設定を開く。操作を選択して、ショートカットの修正をする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18766/0bab25a2-2128-7ea2-0e6c-7ed4412d8e29.png)

### ショートカットの設定例
私の場合は、次の変更をする。基本、以下の設定をするとItem2とよく使うショートカットと同等の操作ができる。

* 「タブの複製」を削除
* タブを閉じる ctrl+shift+w
* ウインドウを分割する(split down) ctrl+shift+d
* ウインドウを分割する(split right) ctrl+shift+s
  (win+shift+sのスクリーンショットとぶつかるショートカットだった）
* 前回使用したウインドウにフォーカスを移動する ctrl+[
* 前のウインドウに順番にフォーカスを移動する ctrl+]
* 新しいタブ ctrl+t
* 次のタブ ctrl+shift+]
* 前のタブ ctrl+shift+[

## エディター
WSL2でubuntuをインストールして、その上でneovimをインストールして次の設定をした。
https://qiita.com/kiyotaman/items/84783a1c5304d892b4a7

# まとめ
20年ぶりぐらいにWindowsへ仕事用のPCを移行することに決めて、思ったよりスムーズにいき個人的には満足。今後、ローカルPCでAIを動かしたいとなると、メモリーも結構必要で、Macでメモリー増設すると高すぎる問題がこれでなくなる。

また、世の中的にIntelからARMへの移行が進み、標準のメモリー搭載量が64Gぐらいになって、20万円以下のPCがどんどん出てきたら、iPhoneからAndroidへ移行して、Macはもういらないかもーってなるのかなと勝手に想像している。

それと、ollama使ってローカルでLLMを使いたいならWindowsの方が断然いいと思うので、Macユーザーの方は、Windowsも併せて使えるとよいのかなと思った。

とりあえず、サクサクに動くのでいい感じ。
＃42　SOLID - Interface Segregation Principle

### Introduction

We have already introduced the first three principles of SOLID, and now let's begin with the I - Interface Segregation Principle.

To revise the Liskov substitution principle, [go here](https://qiita.com/nxted_sapporo/items/b3282bd6473cb8925cfe).

### Interface Segregation Principle (ISP)

> No code should be forced to depend on methods it does not use

This principle is quite stright forward which means you should not put all the methods you need to a single interface. Splits to different interfaces.

Let us keep using the Shape interface that we previously created while introduce [Open-closed principle](https://qiita.com/nxted_sapporo/items/4fb297659479f417e615) with further explanation. The naming maybe a little confusing, so lets rephrase it as 2DShape.
```javascript
    public interface 2DShape {
     public int sum();
     public int area();  // relevant
     public int volume(); // irrelevant
    }
```
We add two new functions to 2DShape this time, `area()` and `volume()`. It is good to have `area()` in 2DShape interface for calculate 2D area. Now assume that we want to extend our program to support 3D shapes and add `volume()` method for volume calculation.

We clearly know that a 2D shape have no volume. You may already have the answer, `volume()` should be seperated and implemented in an interface call 3DShape.

ISP may look simple but vary important when handling a large-scale project. It can keep the project decoupled which easier to change, refactor and have further updates.

That is all about the Interface Segregation Principle and we will introduce the last principle of SOLID in the next article.

### References

- <https://en.wikipedia.org/wiki/Interface_segregation_principle#cite_note-ASD-1>
デザイン思考

■ChatGPT
・後半

◯ ChatGPTの新しい使い方

①プロンプトの利用
#役割
あなたは、掃除機の開発担当者です。

#指示
掃除機を使うユーザーが、掃除機を使うときのステップをできるだけ細かく洗い出してください

#ユーザーの状況
xxx

②画像の状況説明や前提条件として#指示に依頼する。

③人の行動をステップで分ける

④アンケートや会話の内容から、人の本音(深層心理)を考える


■デザイン思考
前提の目的(役割)は？

物を中心に考える    : ポテトチップスのアイデアを考えて
人を中心に考える    : ポテトチップスを食べる人の不満を考えて
人の状況から考える  : オフィスでポテトチップスを食べる人の不満を考えて

お客様観点
・どこに不満を感じているか
基本情報技術者試験（2024年9月試験）

# 概要
2024年9月2日に受験した基本情報技術者試験について（合格基準を超えていたのでおそらく合格しています）
本記事を投稿した動機としては、自分のための簡単な振り返りと今後受験する方の何か参考になるかもしれないと書いていきます

## 本記事で触れること
1. [基本情報技術者試験とは](#1-基本情報技術者試験とは)
1. [参考物](#2-参考物)
1. [試験を受けてみて](#3-試験を受けてみて)

### 1. 基本情報技術者試験とは
基本情報技術者試験（FE: Fundamental Information Technology Engineer Examination）
受験料: 7500円
合格ライン: 各種類の試験６割

CBT方式による２種類の試験を受ける形式（2023年4月改定以降）
- **試験A（60問）**
90分の試験であり、４択の択一で計算問題や言葉の意味を問う問題も含まれています
※指定された講習を受講し、終了することによって免除されることができます
　受講するには受講費を支払う必要があり、ため私は免除しませんでした

- **休憩（10分）**

- **試験B（20問）**
100分の試験であり、Aと同じく４択の択一で基本的にプログラミングのコードに関する問題、4問ほど情報セキュリティに関する文章問題が出題されます

### 2. 参考物
**- [基本情報技術者試験ドットコム](https://www.fe-siken.com/fekakomon.php)**
**とても有用**
サンプル問題も提供してくれるし過去の試験から抽出して問題を出題してくれるのでかなり助けられると思います。さらに、問題の解説や用語についても詳しい解説や一部、図を用いて解説してくれるのでかなり参考になります。一度試験範囲を頭に入れて抜けている点やさらなる知識獲得、問題なれ目的で利用するのが良いと思います

**- 情報処理教科書 出るとこだけ！基本情報技術者試験「科目B」**
**正直まずまず**
自分は事前にプログラムコードの知識があり、トレースの能力もある程度あったため、参考にはなったけどそこまで、、、というのが正直な感想でした。でも初学者の方にはかなりわかりやすく順を追って問題を解説してくれているのでとても参考になると思います

**- かやのき先生の基本情報技術者試験**
**とても有用**
自分はとても重宝しました。他の参考書と比較して、文章と図での解説のバランスがとても良かったので私はこの参考書を使用していました。とりあえず１周して基本情報技術者試験ドットコムやっておけば午前問題は安泰かなと思います。

### 3. 試験を受けてみて
1. 事前知識があれば
私は受験する前に、ITパスポートを取得し、大学でもプログラミングの授業を受けていたためそこまで苦労はしませんでした。勉強時間的には毎日2時間ほどを2ヶ月程度で７割〜８割でした

1. 難しかった点
個人的に難しいと感じたのは、単純に広い出題範囲でした（時間を掛ければ...）
試験Bは、出題されるのは独自のプログラミング言語ですがC言語やPythonなどと基本的には通ずるので、勉強するならば試験Bのためというよりかは仕事などで使用する言語を勉強する方が良いかなと思います。
どの程度、プログラムコードを理解し追従することができるのかが求められているような印象でした

1. 勉強が足りない
自分としては、基本的に毎日問題に触れる、復習するなどをして対策していたため、満点近く行けるのではと自信を持っていたのですが、結果は７〜８割程度でした。理由としては、どんなに勉強をしても試験範囲が広すぎて完璧な対策ができなかったことが大きいのかなと思います。試験を通して、私が今回で得た教訓として伝えることができるのは**”やっておいて無駄にはならないので、早く勉強を始め、できるだけ勉強する”**というありきたりなものになります（こういう資格試験では最も大切なのかなと感じました）

1. AP（応用情報技術者試験）
基本情報技術者試験（FE）の次のステップとしてよく挙げられるのが応用情報技術者試験かなと思います。私も次の資格として目指していますが、FEを取得しても、APで何か免除になるなどのメリットはなく、単純に試験範囲が被っていて勉強の負担が少なる程度です。ただしAPをとると次の高度資格試験の一部が免除されるので、中にはFEを取らずにAPを取得する人もいるそうです。

### 参照
[IPA 情報処理推進機構サイト](https://www.ipa.go.jp/shiken/kubun/fe.html)
E2Eテスト（playwright)の使い方メモ

# playwrightで自作アプリのE2Eテストをしてみた

### この記事の目的
初学者が、自作したアプリのE２Eテスト手順の備忘録として作成しています。
誤りや、不足がありましたら、ご指摘ください。

### テスト対象
https://github.com/se1987/household_budget.git

### テストシナリオ
**1.** Home画面にアクセスすると、入出金一覧表が表示される
**2.** 収支入力をクリックして、入力フォームへ遷移する
**3.** 日付、タイプ、カテゴリ、金額、説明を入力し、取引を追加する
**4.** 追加した取引がリストに表示されていることを確認する

## playwrightの初期設定

- **playwrightインストール**
※フロントエンドのpackage.jsonがあるディレクトリ階層で実施
```bash
npm init playwright@latest
```
- **生成されたplaywright.config.tsの設定**

```typescript
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './e2e',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: 'html',
  use: {
    trace: 'on-first-retry',
  },
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
  ],
});
```

## playwrightでテストコード生成
下記のコマンドを実行
```bash
npx playwright codegen
```
↓以下の画面が表示されます
![コマンド実行後にこの画面が出ます](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535387/a17e6937-746e-a351-47a0-545927ce2d22.png)

URLをテスト対象のものに変える
![スクリーンショット 2024-09-09 13.31.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535387/e864c3e1-7fb6-27b8-32d3-a1433e46189c.png)

画面のボタンをポチポチしていくとテストコードが作成されます
![スクリーンショット 2024-09-09 13.28.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535387/fd42229b-01e8-df64-3a36-38d00a757569.png)

ただ、今回作成されたのは、ボタンクリックや表示されている項目のみで、入力フォームへの入力を行うコードは、手動で作成しました↓

```typescript
  // 日付入力
  await page.fill('input[name="date"]', '2024/9/9');

  // 区分選択
  await page.selectOption('select#type', '収入');

  // 項目入力
  await page.selectOption('select#category', '給与'); // 項目が入力フィールドである場合

  // 金額入力
  await page.fill('input#amount', '1000000'); // 金額入力フィールドに入力
```

**[ 感想 ]**
Excelのマクロの記録のような機能なので、生成されたコードもそのままでは使用しないほうがよさそうです。
テストコードを書くときに、どのように画面内のフィールドを指定するか確認するために使うのが良いということを学びました。

## テスト実行
```bash
npx playwright test
```
ブラウザを表示させて確認したい場合
```bash
npx playwright test --headed
```

## 結果の確認
```bash
npx playwright show-report
```

無事にテストパスしました！
![スクリーンショット 2024-09-12 9.37.05（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535387/9c7c28b6-e478-f64c-ec12-d515700e0e08.png)

最後まで、読んでいただき、ありがとうございます。
Chrome, Edge バージョン128 getBoundingClientRectの返却値変更

# 事象
document.body.zoom=1.2など、プログラム的にブラウザの表示率を調整しています。
（様々なモニタ解像度から最適な表示をするための工夫）

最新版のChromeに更新されたら
JqueryUIのdatepicker、autocomplete
bootstrap-datetimepicker
のポップアップ（吹き出し）は呼出元のフォームコントロール（日付入力欄など）の直下から、かなりずれてた位置に表示されてしまっています。

**JqueryUIの表示例**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3881362/e3ed6ca9-51b8-f1ae-d277-b41b4c7c9a4d.png)


# 原因
Chromeバージョン128でgetBoundingClientRectのAPI戻り値は、プログラムで調整したzoom率を反映した情報となっています。
以前はオリジナルな値となっています。

最新のW3C標準仕様
https://drafts.csswg.org/css-viewport/#zoom-om
>The getBoundingClientRect, getClientRects, and IntersectionObserver APIs must return rects with scaled lengths.

JqueryUIなどのJSフレームワークのoffset関数は、getBoundingClientRectにてLEFTやTOPの座標を計算しており、内部的に矛盾が出ているようです。

# 参考デバッグ情報（LEFT属性）
**旧バージョンChrome**
$( "#datepicker" ).offset().left
93.98436737060547

$( "#ui-datepicker-div" )のHTML上のSTYLE.LEFT
93.9844px

$( "#ui-datepicker-div" ).offset().left
93.98436737060547
➡三つともほぼ一緒で表示ズレはない

**新バージョンChrome**
$( "#datepicker" ).offset().left
112.78125

$( "#ui-datepicker-div" )のHTML上のSTYLE.LEFT
112.781px

$( "#ui-datepicker-div" ).offset().left
135.33334350585938
➡112.781の約1.2倍（bodyのzoom率通り）となるためズレる

# 暫時対処例
offsetに乗算されているzoom率を除算してオリジナル座標に戻させる
```javascript
var originalOffset = $.fn.offset;
$.fn.offset = function() {
  var originalResult = originalOffset.apply(this, arguments);
  originalResult.top = originalResult.top / document.body.style.zoom;
  originalResult.left = originalResult.left / document.body.style.zoom;
  return originalResult;
｝
```

# 恒久対処
JqueryUIなど、JSフレームワーク側の対処が期待されますが動向不明
(QA) 新しいH/Wに移行したら5250アプリケーションのパフォーマンスが激悪くなりました

主題のご質問がありました。

・5250の端末ジョブなどが3桁あるシステム
・旧POWER8からPOWER10サーバーにリプレースした
・コア数その他は十分検討されており新サーバーも問題無かった
・稼働テスト検証は十分になされており問題はない、との結果のものと本番切り替えをしたのちに上記の現象が発生した。


原因

以下のライセンスが新システムに未導入だったことが原因でした。

5250 Enterprise Enablement

※5250対話型ジョブを実行するためには上記のライセンスが別途必要なシステムでした。

新旧でチェックが漏れていたのでしょうか・・・
上記ライセンスが必要ないシステムもありますので、移行の際には新旧抜け漏れチェックお願いいたします・・
フローの制限および考慮事項


+ [【ヘルプ】フローの制限および考慮事項](https://help.salesforce.com/s/articleView?id=sf.flow_considerations.htm&type=5)
+ [フローで発生する最も一般的なトランザクションごとの制限](https://trailhead.salesforce.com/content/learn/modules/flow-implementation-1/avoid-flow-limits?trail_id=distribute-and-implement-flows)

|制限の種類|制限|
|:---------------------------------|:-----------------------------------|
|SOQL| トランザクションあたり 100 回の SOQL クエリ、 トランザクションごとに SOQL クエリによって 50,000 件のレコードが取得されます|
| DML|トランザクションあたり150 DMLステートメント、 ステートメントによって作成、更新、または削除されるレコードは 10,000 件|
|CPU | トランザクションあたり10秒のCPU処理時間|

# 大量のレコード

SOQL および DML の制限に達しないようにするには、フィルターを使用して、フローで取得および更新するレコードの数を最小限に抑えます。

スケジュール トリガー フローを四半期ごとに実行するように設定することはできません。そのため、このスケジュール トリガー フローは毎日実行されます。決定要素は、現在の日付が四半期の初日であることを確認します。そうである場合は、レコードの更新要素が組織内のすべての連絡先の [今四半期に連絡済み] チェックボックスをオフにします。フィールドがすでにオフになっているレコードのフィールドもオフにします。ただし、組織に 10,000 件を超える連絡先が含まれている場合、このフローは失敗します。[今四半期に連絡済み] がオンになっている連絡先のみを更新するようにフローを更新しましょう。

# ループ

これらの制限に達しないようにするには、レコードの取得、レコードの作成、レコードの更新、またはレコードの削除の要素をループ内に配置しないでください。代わりに、それらをループの外側に配置します。

+ レコードの取得:ループ の前
+ レコードの作成、レコードの更新、レコードの削除:ループ の後

# 他の自動化によって開始されたフロー

フローが別の自動化によって開始された場合、そのフローはその最初の自動化のトランザクションの一部として実行されます。上記のガバナー制限はすべてトランザクションごとであるため、他の自動化によって実行されるものはすべて、トランザクションごとの制限にもカウントされます。

たとえば、Pyroclastic の組織には、処理に 9 秒の CPU 時間を要する複雑な Apex クラスがあります。次に、Apex クラスは自動起動フローを呼び出します。フローの実行には 2 秒の CPU 時間を要するため、トランザクション全体が 10 秒の制限を超えるため、フローは (Apex クラスとともに) 失敗します。Apex クラスに含まれる SOQL クエリ、DML ステートメント、取得されたレコード、または影響を受けたレコードが多すぎる場合も、フローは失敗します。

この制限を回避する最善の方法は、自動化を可能な限り効率的にすることです。Apex クラスの実行に 9 秒の CPU 時間を要する場合、簡素化または改善できる可能性が高くなります (Apex クラスにとって 9 秒は長い時間です)。9 ～ 10 秒かかるフローについても同様です。他の方法がすべて失敗した場合は、待機要素 (条件の待機、時間の待機、または日付までの待機) のいずれかを追加して、新しいトランザクションを開始します。

# メール

+ [メール認証を挟むと、レコードトリガーフローが起動しなくなる。](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000PY4TZ)

:::note

この設定が既に有効になっているので、うまくいかないのかもしれませんね。 

Experience Cloud ユーザ、パートナー、顧客のメールアドレス変更時に確認が必要 (更新、適用済み)
https://help.salesforce.com/s/articleView?id=release-notes.rn_identity_email_verification_experience_cloud.htm&release=232&type=5

以下でもフローを使ってユーザのメールアドレスを変更しようとしていますが、機能してないようです。 


https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000NQwPMSA1
:::
Power AppsのGalleryでアイテム別に色を設定する

Power AppsでGallery表示を使う時、個別に色をかえたくなる時があります。

例えば貸出管理アプリの場合、貸出状態であればグレーアウトや赤系の色にしたい。
備品が戻っていたら緑や青系に設定したい。

今回の貸出状態はrental列で管理、値はtextで「貸出/返却」とします。

Gallery全体は指定できません。代わりに四角形を置くのも良いでしょう。再配列で最背面に移動します。文字（貸出状態）を表示させても良い。
`Text=ThisItem.貸出状態.Value`
あるいは
`Item=Choices([@DBの名前].rental)`
で文字を表示させる。

`Fill=If(Subtitle1.Text= "貸出",RGBA(225,200,200,1),RGBA(220,245,220,1))`
と書くことで、rentalの値によって四角形の色を変えられる。
FlaskをDocker上で動かしたときにアクセスができない問題

<!-- FlaskをDocker上で動かしたときにアクセスができない問題 -->

Dockerを用いて、Flaskで作ったアプリを自宅のサーバ上で動かし、常駐させようと考えたが、その際にハマったことについてまとめておく。

## 環境

- Ubuntu 24.04
- Docker 24.0.5
- Flask 3.0.0

## 問題

とりあえず、以下のようなDocker関連のファイルを作成した。

```Dockerfile
# Dockerfile
FROM python:3.10.5-alpine3.16
WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
```

```yaml
# docker-compose.yml
version: '3.8'
services:
  app:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - ./app:/usr/src/app:rw
    environment:
      TZ: Asia/Tokyo
    command: ["python3", "main.py"]
    tty: true
```

```requirements.txt
Flask == 3.0.0
```

そして、以下のような`main.py`を作成した。

```python
from flask import Flask

app=Flask(__name__)

@app.route("/")
def hello():
    return "Hello!\n"

if __name__=="__main__":
    app.run()
```

ディレクトリは以下のような構成とした。

```bash
.
├── app
│   └── main.py
├── Dockerfile
├── docker-compose.yml
└── requirements.txt
```

そして、いつものように`docker-compose build`から`docker-compose up`でコンテナを立ち上げたが、LANからアクセスできなかった。

これは、Flaskのデフォルトのホストが`localhost`になっているためで、サーバ外部からサーバの`localhost`にアクセスすることはできないということである。

そこで、`app.run()`の引数に`host="0.0.0.0"`を追加した。これで、外部からのアクセスを許可することができるはずである。

```python
if __name__=="__main__":
    app.run(host="0.0.0.0")
```

しかし、これでもアクセスができなかった。本来なら`http://[サーバのIPアドレス]:5000`(5000はFlaskのデフォルトのポート番号)でアクセスできるはずだが、これができない。ファイアウォールの問題かと思ったのだが、5000番ポートの開放をしてもアクセスはできず、別に原因があることがわかった。

## 解決

いろいろ調べた結果、Docker側のポート設定が必要だということがわかった。

`docker-compose.yml`を以下のように修正する。

```yaml
# docker-compose.yml
version: '3.8'
services:
  app:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - ./app:/usr/src/app:rw
    environment:
      TZ: Asia/Tokyo
    command: ["python3", "main.py"]
    tty: true
```

これにより、5000番ポートを通じてアクセスすることができるようになった。

また、`app.run()`の引数にもポート番号を指定する必要があるので、以下のように修正する。

```python
if __name__=="__main__":
    app.run(host="0.0.0.0", port=5000)
```

これで、LANから`http://[サーバのIPアドレス]:5000`へアクセスできるようになった。

```bash
$ curl -i [サーバのIPアドレス]:5001
HTTP/1.1 200 OK
Server: Werkzeug/3.0.4 Python/3.10.5
Date: Mon, 99 Sep 9999 99:99:99 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 6
Connection: close

Hello!
```

## まとめ

以上のことにより、無事自宅内のLANからアクセスできるFlaskアプリを用意することができた。

Flaskの動作にDockerを用いる際には、ポートの設定に注意することが重要だということがよく分かった。

## 参考

[Flaskで立てたサーバーが外部からアクセスできない場合に確認すべきこと #Python - Qiita](https://qiita.com/YukiYamam/items/02d35640331524f119ea)

[Flaskを使って外出先からURL経由でRaspberryPiを操作する - West Gate Laboratory](https://westgate-lab.hatenablog.com/entry/2020/01/12/231253)

[dockerコンテナ上のflaskへの接続](https://teratail.com/questions/pb00mugjgixirf)
Eclipse Coverage java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 51966

■現象
EclipseでJunitのカバレージを実行する時、下記のエラーが発生しました。
java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 51966

■環境
Jmockit：1.49
Eclema:3.1.9

■原因
カバレージのPluginのEclemmaのバージョンの問題

■解決方法
Eclemmaの3.1.2のバージョンをインストールすれば解決できます。

Eclemmaのダウンロードサイト：
https://www.eclemma.org/download.html

ダウンロードしたZipファイルを解凍し、featuresとpluginをeclipseにコピーし、「eclipse.exe -clean.cmd」のコマンドでEclipseを起動します。
Power Appsでドロップダウンを使いFilter制御

Power Appsのギャラリーでアイテムを表示する。次にやりたいことはアイテムの絞り込み、Filterです。設計者が絞り込みを行う以外にも、使用者が絞り込みを行うこともあるでしょう。だから使用者が使うであろう項目を入れつつ、楽に設計したい。

Filterの項目をドロップダウンで選択するのも一つの方法。ファストフードのメニューはバーガー、ドリンク、サイドメニューで切り替えたいでしょう。これらをボタンで配置するよりは、ドロップダウンを使いたくないですか。

ドロップダウンのItem指定は直接各方法もありますが、Distinctでデータベースから借用するのが手っとり早い。そして絞り込みをなくす方法も準備しておいた方がよい。今回の記事のポイントはココです。

Dropdownの設定
`Item=Distinct(List,Category)`
`AllowEmptySelection=true`
動作のポイントは、同じ選択肢を二回選ぶと空白になります。

Galleryの設定
`Item=Filter(Table,
　Or(IsBlank(Dropdown.SelectedText.Value),Category=Dropdown.SelectedText.Value))`
Orの中がブランクか、選択した文字で検索したtrueのみが表示されます。ブランクの場合は必ずtrueが返ります。

たったこれだけの設定で、全選択との切り替えができてしまいます。
Dockerレジストリへのログイン

[Artifact Registry for Docker への認証を構成する](https://cloud.google.com/artifact-registry/docs/docker/authentication?hl=ja)が初見でよく理解できなかったため、前提となるDockerレジストリの認証周りの情報を整理した上で、噛み砕いたものをアウトプット。


# Dockerレジストリ

![Dockerレジストリ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59542/e6a0c7fd-dacd-cb13-0c4d-43c65f24c93c.jpeg)

Dockerイメージを保存・配布するシステム。
具体的なサービス名としては、DockerHub, GCP の Artifact Registryなど。
Dockerレジストリは複数のリポジトリから構成され、リポジトリは複数のイメージを管理する。
同名のイメージのバージョンはタグで管理される。


# docker loginコマンド
`doceker push`や`docker pull`コマンドを実行するために、操作対象のdockerレジストリにログインするコマンド。
```
docker login <オプション> <dockerレジストリのURL>
```

**オプション**
`-u`: ユーザ名を指定
`-p`: パスワードを直接指定
`--password-stdin`: Linuxコマンドのパイプでパスワードを指定するときに使う。シェルのhistoryにパスワードが丸見えで残ったりしないので安全。

# 認証情報ヘルパー(credential helper)
dockerレジストリの認証情報(ユーザー名, パスワード)を外部ストア(Macのキーチェーンとか)を利用して管理(保存・取得)するためのプログラム群。
プログラム名は `docker-credential-xxx` という名前で統一されている

例. 
- docker-credential-osxkeychain: Macのキーチェーンで管理されている認証情報
- docker-credential-gcloud: gcloudコマンドで管理されている認証情報

`docker login`実行時に認証情報をオプションで指定しない場合、`~/.docker/config.json`に記載されている「どのレジストリへログインするときにどの認証情報ヘルパーを使うのか」の設定に基づいて、認証情報ヘルパー経由で外部ストアから認証情報を取得してレジストリへのログインを試みてくれる模様。

## コマンド
### `docker-credential-xxx store`
外部ストアに認証情報を保存する。
`docker-credential-gcloud` の場合は、gcloudコマンドにおける現在アクティブなユーザーアカウント or アクティブなサービスアカウントの認証情報が使われるため、自らstoreコマンドを実行することはないはず。

gloudコマンドでの認証については、[gcloudコマンドまとめ](https://qiita.com/WisteriaWave/items/12f92387ec58bae670e4)の `gcloud auth login` や `gcloud auth activate-service-account` を参照

### `docker-credential-xxx get`
外部ストアから認証情報を取得する。

設定に基づき、指定したレジストリへのログインに使われる具体的な認証情報(ユーザ名、パスワード)を知るには、以下のコマンドを実行する

```
echo https://<config.jsonに登録したレジストリ> | docker-credential-<config.jsonに登録した認証情報ヘルパーのサフィックス> get
```
 
例.
```
echo https://us-central1-docker.pkg.dev | docker-credential-gcloud get
=>
{
  "Secret": ".............................",
  "Username": "_dcgcloud_token"
}
```

# `~/.docker/config.json`
dockerの認証情報の設定ファイル。
```
# 例.
# - デフォルトで認証情報ヘルパーdocker-credential-desktop を使う
# - Dockerレジストリが us-east1-docker.pkg.dev である場合、認証情報ヘルパーdocker-credential-gcloudを使う
{
    "credsStore": "desktop",
    "credHelpers": {
      "us-east1-docker.pkg.dev": "gcloud"
     }
} 
```
【vercel】Next.jsプロジェクトのデプロイに失敗する

### 事象

[Next.jsのチュートリアル](https://nextjs.org/learn/dashboard-app/setting-up-your-database)にしたがってプロジェクトを作成し、 Vercel に連携させデプロイしようとしたところ、下記エラーが発生し、ビルドに失敗してしまいました。
```
No Next.js version could be detected in your project. Make sure `"next"` is installed in "dependencies" or "devDependencies"
```

### 原因

ルートディレクトリで設定したパスの直下に`package.json`がなかったことが原因でした。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3881444/a86f9011-59e0-593c-9dd7-542f5d0c6fa1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3881444/9b4eb8fd-9206-4382-9623-c427ffba112b.png)


### 対応方法

設定画面からルートディレクトリを修正して再デプロイを行います。

1. srtting > general からルートディレクトリを修正します。
このとき、入力値はフォルダ名を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3881444/28c6c3f2-c527-3c53-a686-59e899b3c191.png)

2. Deploymentsに戻り、「・・・」を押下して「redeploy」を選択します。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3881444/6e431ecb-555d-555c-2912-b299c7e5eeab.png)

3.  デプロイが成功しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3881444/bc04d244-dec3-57e9-dac8-166c518db086.png)

### 参考
[Qiita - 【エラー解決】No Next.js version could be detected in your project. Make sure `"next"` is installed in "dependencies" or "devDependencies"](https://qiita.com/acu8/items/fb1424afb846192128f9)
[stack overflow - No Next.js version could be detected in your project. Make sure `"next"` is installed in "dependencies" or "devDependencies"](https://stackoverflow.com/questions/74297132/no-next-js-version-could-be-detected-in-your-project-make-sure-next-is-inst)
【ChatGPT＋Code Interpreter】で画像内のパネルを認識できない？　また改善です。


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

　今回は、画像内のパネルを認識できない問題について、また改善です。

:::note info
本記事は、ChatGPT（有料版）
で行なっております。画像は
あります。　あしからず。
:::
　ニュースはないので、
　　さっそく本題です。

　昨日（2024/09/08）の記事で
　　画像内のパネルを認識できる
　　　ようにしました。
[【ChatGPT＋Code Interpreter】で画像内のパネルを認識できない？　報告と改善](https://qiita.com/kabumira/items/901eeda6797c61fd05ca)

　少なくとも
　　昨日の時点では
　　　大丈夫でした。

　しかし、
　　新たに行なったところ、
　　　うまくイカないことが判明。

　それなりの時間を掛けて
　　調整してきました。

　とりあえず
　　完璧ではないか、という
　　　改善を提示します。
***
　手順は
　❶GPT-4oであることを確認
　❷元画像をアップロード
　❸Prompt入力
```Text:吹き出しに赤枠Prompt（Ver 3）
・PillowとSciPyを使用してください。

### 画像内の最も大きな白い領域を検出し、赤枠で囲む処理の指示

1. **画像の読み込み**：
   - 指定された画像をRGB形式で読み込みます。

2. **白色の定義**：
   - 「白色」は、RGB値がそれぞれ210以上のピクセルとして定義します。

3. **白色領域の検出**：
   - 白色のピクセルで構成される領域（連続したピクセルのグループ）をすべて検出します。

4. **最も大きな白色領域の選択**：
   - 検出された白色領域の中で、ピクセル数が最も多い領域を特定します。

5. **赤枠の描画**：
   - 最も大きな白色領域の周囲に赤い枠（太さ10px）を描画します。

6. **結果の保存**：
   - 枠線が描かれた画像を保存します。
```
　❹送信
　❺ダウンロードリンクが表示
***
　この手順で作成できたのがこちら。
 ![image_with_red_box.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/7603ec71-2284-6e6b-8542-ad9755e8253d.png)
![new_image_with_red_box.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/d77a2417-e423-e06e-8c25-53802e40fec3.png)
![fourth_image_with_red_box.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/2bf9fe53-fcad-4e14-9935-5025822684c9.png)

　しかし、
　　白い領域が画像に多い場合は、
　　　これでは別の場所に
　　　　赤枠が出てしまいます。

　そこで
　　調整が必要になります。

　上記Promptの
　　“RGB値がそれぞれ210以上”を
　　　“RGB値がそれぞれ220以上”に
　　　　してください。

　ようするに
　　白の定義を
　　　厳しくしてやるわけです。

　この調整で
　　出来上がったのがこちら。
![third_image_with_red_box_new_threshold.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457238/1fb59fb7-1bef-be4f-8542-c9228b98db69.png)

　みなさんの
　　作品制作の糧に
　　　なれば、幸いです。

　今回は、ここまで。

　文字入れは
　　また明日の予定です。
JuliaのBase.Threadsによる並列化: @spawn と @threads (とBase.Semaphore)

# Juliaの並列化手法について
今まで`@threads`を用いた簡素な並列化ばかり行ってきてしまったのですが、ここにきて、使用メモリに応じてスレッド数を自動で変更できる機構を作成しようと思い、`@spawn`を用いてこれを実現しようと試みました。


# 通常のfor文
次のような、正弦波をプロットするコードを作成してみました。
```julia
using Plots

total_items = 101

θ_list = range(-π、π,total_items)

f(i) = sin(θ_list[i])

y = zeros(total_items)

for i in 1:total_items
  y[i] = f(i)
end

plot(θ_list, y)
```
これを回すと`y`に値が代入されていき、正弦波が出力されます。

# `@threads`を用いた並列化
for文の頭に`@threads`を追記するだけで、Juliaを立ち上げる際に指定した並列数`N0`
```bash
julia -t N0
```
で並列化を行ってくれます。
```julia
using Plots
using Base.Threads

total_items = 101

θ_list = range(-π,π,total_items)

f(i) = sin(θ_list[i])

y = zeros(total_items)

@threads for i in 1:total_items
  y[i] = f(i)
end

plot(θ_list, y)
```
もちろん`JULIA_NUM_THREADS`を用いても構いません。

# `@spawn`を用いた並列化
まず、サンプルコードを記述します。
`N_trunc`は`N0 >= N_trunc`とし、Julia実行時に指定した並列数よりも小さな並列数で計算を回してくれます。
```julia
using Plots
using Base.Threads

total_items = 101

θ_list = range(-π,π,total_items)

f(i) = sin(θ_list[i])

y = zeros(total_items)

N_trunc = 4

chunk_size, remainder = divrem(total_items, N_trunc)
sizes = [chunk_size + (i <= remainder) for i in 1:N_trunc]
start_indices = [1; cumsum(sizes[1:end-1]) .+ 1]

tasks = []
for id in 1:N_trunc
    task = @spawn begin
        start_id = start_indices[id]
        stop_id = start_id + sizes[id] - 1
        for i in start_id:stop_id
            y[i] = f(i)
        end
    end
    push!(tasks,task)
end

fetch.(tasks)

plot(θ_list, y)
```

## 説明
ここでは、1スレッドごとに担当する**分配された配列**のことを**チャンク**と呼ぶことにします。

1. `divrem()`関数を用いて、for文の回数（ここでは`total_items`回）を大雑把に`N_trunc`分割し`chunk_size` とします。また余りの値も`remainder`に格納します。
    ```julia
    julia> divrem(total_items, N0)
    (25, 1)
    ```
2. 続いて、`N_trunc`に分割した際のチャンクの長さをリスト`sizes`として生成します。
    ```julia
    julia> sizes = [chunk_size + (i <= remainder) for i in 1:N_trunc]
    4-element Vector{Int64}:
     26
     25
     25
     25
    
    ```
    このとき、`(i <= remainder)`の部分により、割り切れなかった余りの分を、最初の数チャンクに対して等分配するように自動化されます。
1. それぞれのチャンクの最初の`index`を保持するリスト`start_indices`を生成します。
     ```julia
    julia> start_indices = [1; cumsum(sizes[1:end-1]) .+ 1]
    4-element Vector{Int64}:
      1
     27
     52
     77
    ```
ここまでで、タスクを分配する準備ができましたので、for文を用いてタスクを生成します。
```julia
tasks = []
for id in 1:N_trunc
    task = @spawn begin
        start_id = start_indices[id]
        stop_id = start_id + sizes[id] - 1
        for i in start_id:stop_id
            y[i] = f(i)
        end
    end
    push!(tasks,task)
end
```

最後に`fetch.(tasks)`を実行すれば並列化された計算が始まります。

このような流れで、同等の並列化が、並列数を削減して行うことが可能となります。

# （追記）Base.Semaphore による並列化
@antimon2 さまより、`Base.Semaphore`を用いた手法をご提案いただきました。
詳しくかみ砕けていないため急ぎ早にはなりますが、例えば次のようなコードですと、同等の方法で並列化数に制限がかけられそうです。
```julia
using Plots
using Base.Threads

total_items = 101

θ_list = range(-π,π,total_items)

f(i) = sin(θ_list[i})

y = zeros(total_items)

sem = Base.Semaphore(N_trunc)

for i in 1:total_items
    @spawn begin
        Base.acquire(sem) do
            y[i] = f(i)
        end
    end
end

plot(θ_list, y)
```

# 最後に
またもう少し賢い手法を見つけたら、引き続き更新していきます。
オープンソースプロジェクトに参加した話

# Coggleのオープンソースの多言語翻訳プロジェクトに参加しました

## 1. 本記事のターゲット層
(1) オープンソースプロジェクトに参加してみたい人
(2) オープンソースプロジェクトにどうやって参加しているのか知りたい人

## 2. イントロダクション
今回、初めてオープンソースプロジェクトでプルリクを行い、マージまで進められたので、その体験談を話したいと思っています。

なぜそのような話をするかというと、日本にもっとオープンソースに参加する技術者を増やしたい。そしてオープンソースに参加することで、高レベル技術者を増やしたいと考えているからです。

Githubは2023年あたりから初めて触り始めたGithub初心者です。普段何をしているかというと、ゲームや映画が好きで、空き時間はそれらに時間を費やしています。そんな人間でもオープンソースプロジェクトに参加していけるんですよ。ということは今回はお伝えできればなと思います。

Githubはどのように使っているかというと、サンプルソースコードを読んだり、関心があるプロジェクトをBookmarkに登録してソースコードを眺めたり、空き時間（昼休みや通勤途中など）に個人的なコーディングをすることに使っています。ZennやQiitaの記事を管理することにも使っています。

## 3. きっかけについて
今回のプロジェクトに参加するきっかけは、普段使っているCoggleというマインドマップツールで多言語翻訳プロジェクトを行っていることを知ったからです。

頭の中を整理したり、あるいは複雑な経路でたどることが困難な処理を追うときに、普段からこのツールを使っています。ツールを使ってマインドマップを描くことで、何年かあとでも考えていたことをすぐに思い出せるので便利です。

実際、このツールを使い始めてからノートを使わなくなりましたし、複雑なことを思い出さなければいけなくなったときにすぐに思い出すことができました。あちこち資料を漁ったり、人に聞いたり、ぐぐったり、思い出す努力をすることに時間をかけなくて済みました。

多言語翻訳プロジェクトをGithubで行っていることを知ったのは、このCoggleというツールの請求ページに書いてあったので知りました。

## 4. そもそもどうやって参加するのか
どうやって参加するのかをお伝えする前に、この参加に至る前にどのようなことを考え、どのようなことを調べていたのかについても説明したいと思います。

ロジカルシンキングには前提条件を合わせることが必要です。前提条件が違うと結論も異なるからです。

今回、参加しようと思う前に、Githubを知ってからオープンソースプロジェクトに参加をして、技術を磨くチャンスを得たいとは常々思っていました。そこで、Githubで暇があれば情報収集をしていました。例えば、Xで面白そうなオープンソースのツールがあれば、レポジトリのソースを眺めてみたり、試しに動かしてみたり、デバッグでソースコードを追ったりしていたわけです。

その中で、オープンソースに変更を加えたいとき、みんなどのようにしているのか知ることができました。
(1)変更を加えたいレポジトリをForkする
(2)Forkしたレポジトリに変更を加えてCommitする
(3)変更したForkレポジトリからオープンソースのレポジトリにpull requestを行う
(4)オープンソースのContributorsがpull requestを承認すると、レポジトリにマージされます

参加が不安な場合は、まずはissueに質問を投げたり、答えられるものを探してissueを解決することに貢献してみるとよいと思います。何回かすると、英語でやりとりすることに慣れてくることでしょう。

私の場合、DeepL、Chat-GPTなどに日本語で内容をかき、英語に翻訳してもらっています。Chat-GPTの場合は「以下の内容を英語に翻訳してください」、メールでやり取りしたいことがある場合は「以下の内容を英語のメール向けに翻訳してください」などとお願いをするといいでしょう。

## 5. どうやって参加したのか
前述したとおり、私もissueに参加することから始めました。そして英語でやりとりすることに不安を覚えなくなり、issueでやりとりすることにも不安を覚えなくなったとき、あるときたまたま[Coggle](https://coggle.it/)で多言語翻訳プロジェクトをオープンソースでやっていることを知り、挑戦しようと思いました。普段から自分が使っているツールなので、よく知っているため、心理的な参入ハードルも低かったというのもあります。

多言語翻訳プロジェクトのレポジトリをForkして、Readmeの内容をよく読み、日本語翻訳ファイルを作成してCommitし、pull requestを投げてみました。最初はマージしてもらえるか不安でしたが、翌日にはマージされており、安心したことを覚えています。

今回は簡単な内容でしたが、そのうち、複雑な変更も加えられるようになれたらと思います。

いずれにしても英語でのやりとりになれる。知らないプロジェクトに参加するというのは、小さな一歩ではありますがとても良い経験になったと思います。
コピペでデスクトップフローを作る方法

検証用でデスクトップフローのアクションをたくさん作らないといけない時の方法を教わったのでメモします。ふらりさん、ありがとうございました( *´艸｀)

1. アクションを Ctrl ＋ C でコピーします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/02c13d60-4e0f-abbc-6842-7bd0267d63db.png)

2. Excelなどに Ctrl ＋ V で貼り付けします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/b64296d4-752e-fb15-0daf-b6c906fa76c6.png)

3. フローに追加したい分だけ Excel に複製します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/653656e6-a7e1-8c15-73f4-6d8f8400686f.png)

4. Excel の行を全部コピーします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/8d1c5c71-e836-f73e-2b6e-834322589540.png)

5. デスクトップフローの編集画面に戻って Ctrl ＋ V を押します
※ここでうっかり応答がなくなってもめげずに待ちます

6. 1万行のフローができます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3032705/8830f886-de2b-2111-3af9-4398e7282e97.png)
[Laravel] migrationで外部キー設定にハマった

## これはなに
- 業務上で得た知識をメモるだけ
- 他人が読む前提で書いていません

## 何にハマったのか
- 既存テーブルに外部キーを設定したいが以下エラーが出てしまう
```
foreign key (`<外部キー設定カラム>`) references `<参照先テーブル名>` (`id`):
Cannot find an index in the referenced table where the
referenced columns appear as the first columns, or column types
in the table and the referenced table do not match for constraint.
Note that the internal storage type of ENUM and SET changed in
tables created with >= InnoDB-4.1.12, and such columns in old tables
cannot be referenced by such columns in new tables.
Please refer to http://dev.mysql.com/doc/refman/5.7/en/innodb-foreign-key-constraints.html for correct foreign key definition.
```

Please refer ~ って書いてあるリンク死んでるんだけど、、、

## 疑ったところ
- 色んな人が記事書いていたので怪しそうなところを確認
    - indexが貼られていない？
        - 貼ってるよ
    - DBのエンジンが違う？
        - どちらもInnoDBだよ
    - 参照先テーブルと外部キー設定するテーブルのcharsetが違う？
        - どちらもutf8mb4だよ
        - ローカルのDB構築はStagingデータが元だったのでめっちゃ疑ってしまい余計に時間食った
    - 参照先テーブルとカラム定義が違う？
        - ここでした
        - 小手先でそれっぽく定義合わせたつもりだったけど漏れがあった
        - 参照先は10桁・符号なしだったが外部キーカラムは11桁・符号ありだった

## 確認コマンド
- テーブルのエンジン・charset確認
```
show create table project_contracts;
```
- DBのcharset確認（character_set_serverがサーバーのデフォルト文字セット）
```
show variables like 'character_set_server';
```
- InnoDBエラー確認
```
show engine innodb status;
```

## 修正結果
~~~
    public function up(): void
    {
        Schema::table('<外部キー設定テーブル名>', function (Blueprint $table) {
            // カラムの桁数を10桁に変更し符号なしを付与
            // 参照先テーブルがunsignedIntegerなので合わせないと外部キーが設定できない
            $table->unsignedInteger('<外部キー設定カラム>')->comment("xxxxID")->change();
            
            // 外部キー制約を追加
            $table->foreign('<外部キー設定カラム>')
                ->references('id')
                ->on('<参照先テーブル名>');
        });
    }
~~~

## まとめ
- 外部キー設定する際は定義が一致しているかちゃんと確認しないとダメなんだな〜
パソコンのチュートリアルサイトを作って公開する方法(是非皆さんも作ってみて下さい)

今回はサイト作成の練習として
パソコンのチュートリアルサイトを
作って公開してみようと思います。

完成品は下記の URL で体験できます。

[パソコンのチュートリアルサイト](https://uni928.github.io/SephirothPCTutorial/page1.html)
[スマートフォンのチュートリアルサイト](https://uni928.github.io/SephirothSmartPhoneTutorial/page1.html)

自分のホームページや SNS で活動している人は
ネタとして一緒にパソコンのチュートリアルサイトを作ってみませんか？

これから作り方を説明していきます。

***

サイトを作る

まずはサイトを作っていこうと思います。
基本的には「テキスト」「説明画像」「次へ前へボタン」の
3個を各ページに配置したいと思います。

下記のソースを編集して
自分なりのパソコンのチュートリアルサイトを
作ってみて下さい。

下記のソースを改変するだけなら
html の初歩の知識だけで作成する事が出来ます。

10 ページ以上作ると良いと思います。
まずは page1.html から page10.html まで作ってみましょう。

```html:基本のコード(page2.html)
<html>
  <head>
    <title>パソコンのチュートリアルサイト | 会社名</title>
    <meta name="description" content="パソコンのチュートリアルサイトです。"/>
  </head>
<body>
エクスプローラーというアプリを開こう</br></br>
これから</br>・エクスプローラーというアプリを習得する。</br>・ブラウザで検索できるようになる</br>という流れを目指します。</br></br>まずはエクスプローラーというアプリについて習得します。</br>まずは画面の一番下のバーのフォルダのアイコンを左クリックします。</br>するとエクスプローラーが起動します</br>
<img src="page2_image.png" alt="説明画像" width="600" height="350">
</br></br>
<a href="page1.html"><< 前へ</a>  <a href="page3.html">次へ >></a>
<script>

</script>
</body>
</html>
```

今回はサイト作成の体験のため、
スクリーンショットをペイントで編集して説明画像を作り、
html ファイルをメモ帳で編集する事を推奨します。

エクスプローラーとペイントとメモ帳を使うことが出来るならば
この項目はクリアできます。

作ったサイトは一旦ブラウザで確認しましょう。

***

GitHub にアップロードする

次に作ったパソコンのチュートリアルサイトを
GitHub に公開します。

[参考サイト](https://www.pc-koubou.jp/magazine/28571)

***

皆が使えるようにする

次に皆が使えるようにしましょう。
下記の参考サイトの
5. ページの公開
の部分を参考にして
他の人が使える状態にしましょう。

[参考サイト](https://prog-8.com/docs/github-pages)

ReadMe にはサイトの URL を載せて
説明用の文章も URL 付きで載せておくと良いでしょう。
URL は page1.html の URL を載せます。

***

宣伝しよう

次に自分の所有している
ホームページや SNS で
作ったサイトを URL 付きで宣伝しましょう。

パソコンのチュートリアルサイトを作るのは
ホームページや SNS のネタとして
面白い部類だと思います。

***

以上パソコンのチュートリアルサイトの
作り方を紹介しました。

サイト作成をした事が無い人にこそ
この体験をして頂きたいと考えております。

パソコンのチュートリアルサイトではなく
スマートフォンのチュートリアルサイトでも構いません。
とにかく作成する事が大切と考えております。

あなたの作成したチュートリアルサイトが
パソコンやスマートフォンを使える人を
増やすきっかけになるかもしれません。
それは素晴らしい事ではありませんか？

この記事を見て
サイト作成に挑戦頂けたならば
これ以上嬉しい事はありません。

この記事が皆さんのサイト作成をする
きっかけになれますように。

閲覧ありがとうございました。

***

余談

この記事を見てスマートフォンの
チュートリアルサイトを作成した方は
是非コメント下さい。

内容が良ければ母に使ってもらいます。

自分でも作るつもりではいますが
私は良質なスマートフォンのチュートリアルサイトを
切望しています。

これは愚痴になってしまいますが
スマートフォンは操作が難しい割に
操作方法について検索したとしても
順番にみる事である程度操作できるようになるようなサイトは
見つかりませんでした。

私のこの記事の
「テキスト」「紹介画像」「次へ前へボタン」の形式でいいので
そんなサイトが増えて欲しいと切望しているのです。

操作が難しいスマートフォンの
説明ページは絶対に需要があると思っていますし、
何より作るのが簡単な部類のハズなのです。

説明ページで最も大事なのは
サイト作成の技術ではありません。
あなたの説明力のハズです。

何卒よろしくお願いします。

スマートフォンのサイトを作る場合は
下記のコードを改変する事を推奨します。

```html:基本のコード(page2.html)
<html>
  <head>
    <title>スマートフォンのチュートリアルサイト | 会社名</title>
    <meta name="description" content="スマートフォンのチュートリアルサイトです。"/>
    <style>
      html {
        font-size: 200%;
      }
    </style>
  </head>
<body>
タッチを習得しよう</br></br>
タッチは指を一瞬触って</br>すぐに指を離す作業を言います。</br></br>
<img src="page2_image.png" alt="説明画像" width="600" height="350"></br></br>
<a href="page1.html"><< 前へ</a> <a href="page3.html">次へ >></a>
<script>

</script>
</body>
</html>
```
Mac間でParallelsのライセンスを付け替える方法 & Pro版でできること


# 背景
- Intune & Jamf学習用に[中古のMacを2台手に入れた](https://qiita.com/minoden_works/items/e8e284455ce2162e2eb8)ので、ライセンスの付け替えが柔軟かを試したい。
- ついでにPro版とStandard版の違いについても振り返る。

# 手順
- コントロールセンターを開いて「アカウントおよびサブスクリプション」を選択する。
- 各VMウインドウではこのメニューがでないので注意。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/e65e3d66-1ec6-295f-8127-253ab774d4be.png)

- 「マイサブスクリプション」ウインドウが開き、右上のメールアドレスのアカウントに紐づいた現在のサブスク状態が表示される。
- 上のApp Store版のほうは14日の試用期間で利用したライセンスとなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/9b235008-557b-ef50-063b-59a55208aaea.png)

- [ヨドバシ](https://www.yodobashi.com/product/100000001007301617/)で買ったPro Editionのライセンスが表示されていることを確認する。
- 右下の「アクティベート」をクリックする。
- 「このMacでアクティブ化」をクリックする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/8db26b24-31bf-4b33-14f0-5f6b63b59a61.png)


# Pro版だと何ができるの
- [こちら](https://kb.parallels.com/jp/123296/)と[こちら](https://oopsoop.com/compare-editions-of-parallels-desktop/)が分かりやすいのでご覧下さい。
- 1VMにつき4vCPU、8GBメモリという制約がなくなります。
- 体感的にも6vCPU以上にすると明らかにヌルサクになりました。GPUも早くなったような（気のせい？）
- 限界の8vCPUに設定すると、警告がでますが大きな問題は出ていません。
- 1VMでMac Miniのポテンシャルを使い切りたいのであれば、Proのサブスクで毎年更新する必要があるということですね。

# ただしコスト増
- Proは1年更新のサブスク契約オンリーとなります。
- [My Parallels](https://my.parallels.com/login)で現在のライセンス状態が確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/5f4bf432-580f-ae10-8d50-4d8a4e0f68db.png)

- 自動更新設定もできますが、ヨドバシで新規1年だと9000円程度なのに対し継続だと12900円（税込み）になってしまうようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/790864/45e52df0-11e3-b478-2a0e-160ad3756e19.png)

- 毎年新規購入してライセンスをつけかえる工数と比較して、社内の経理部と相談して決めるのがいいと思います。
- 量販店での新規購入はメールでシリアル番号が送付されるわけではなく物理パッケージが届くので、そのあたりの手間も考慮しましょう。

# 逆に買い切り版でいい場合
- 複数VMで同時に使うような用途であれば、4vCPU制限があってもいいと思うので、[買い切り版](https://www.yodobashi.com/product/100000001008054070/)がオトクだと思います。3～4年使えると思います。
- 以前のエントリにも書いたようなサーバーとして使うなら買い切りにして、VMごとの細かいネットワーク管理はUnifi Gatewayなどのルーター側で行うのがいいと思います。

https://qiita.com/minoden_works/items/151418b89e3eaf84f759

# App Store版はあまりメリットなし
- MacのApp Store版は内容はStandardと同じです。しかも買い切りではなくサブスク版。
- メリットとしては14日のトライアル期間があるので、お試しをした後は無効化して、買い切りかProのサブスクに移行するのが妥当です。
GenServerをできるだけ簡単に使ってみる

# 検討内容
- 名前指定で値の設定、取得をする
- 同じ関数内で検証
  - 別名でも検証 
- 別のタスクで検証
- 別の関数で検証


 # ソースを書く
### GenServer本体
 
 ```elixir:lib/worker.ex
defmodule Worker do
  use GenServer

  def start_link(name) do
    GenServer.start_link(__MODULE__, "", name: name)
  end

  def init(stack) do
    {:ok, stack}
  end

  def handle_call({:set, val}, _from, _stack) do
    {:reply, :ok, val}
  end

  def handle_call({:get}, _from, stack) do
    {:reply, stack, stack}
  end

  def set(name, val) do
    GenServer.call(name, {:set, val})
  end

  def get(name) do
    GenServer.call(name, {:get})
  end
end
```

### 検証ソース
 ```elixir:lib/genserver_experiment.ex
defmodule GenserverExperiment do
  @moduledoc """
  Documentation for `GenserverExperiment`.
  """

  @doc """
  Hello world.

  ## Examples

      iex> GenserverExperiment.hello()
      :world

  """
  def hello do
    Worker.start_link(:ymn)
    Worker.set(:ymn, "hoge")

    Worker.get(:ymn)
    |> IO.inspect()

    Worker.start_link(:y)
    Worker.set(:y, "fuga")

    Worker.get(:y)
    |> IO.inspect()

    Task.async(fn -> Worker.get(:ymn) end)
    |> Task.await()
    |> IO.inspect()

    hoge()

    :world
  end

  def hoge() do
    Worker.get(:ymn)
    |> IO.inspect()
  end
end
```

# 実行結果

```
"hoge"
"fuga"
"hoge"
"hoge"
```
# ソース(github)

https://github.com/ymn-t-yamanashi/genserver_experiment
SageMaker Code Editorの紹介

# はじめに

こんにちは。弥生R&D室のsiidaです。R&D室ではSageMakerを使用して機械学習 (ML) のプロジェクトを進めています。SageMakerはMLのための様々な機能が搭載されたサービスであり、データ分析からモデル訓練、ひいてはワークフローの構築まで、SageMakerの中で完結させることができます。

SageMakerは元々JupyterLabのIDEを備えていましたが、こちらはNotebookの実行に最適化されたIDEであるため、データ分析であればともかくモデリングやMLシステムの構築には不向きな点がありました。

そこでCode Editorの出番です。こちらは[VSCode](https://github.com/microsoft/vscode#visual-studio-code---open-source-code---oss)を元に作られたIDEで、事実上ブラウザで動作するVSCodeとして扱うことができます。ターミナルもVSCode同様の扱いとなっているため、あえてターミナルを全画面に表示することでiTermのようなローカルのターミナルと同じように操作することもできます。Vim派のユーザーにもおすすめなツールです。

本日はこのCode Editorの使い方を紹介します。

# Code Editorの使い方

![02_studio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127680/60250e63-efb6-9d93-f72a-1e858b44a0f0.png)

まずはSageMaker Studioを立ち上げます。Studioの立ち上げ方は、[こちらの記事](https://qiita.com/siida36/items/f6e4ba4a03b641fc5fea)をご覧ください。その後、画面左上の"Applications"から"Code Editor"を選択します。

![03_codeeditor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127680/d9cad9b5-ad54-003f-f455-4233237cf2b4.png)

画面右上の"Create Code Editor Space"を選択します。

![04_create_space.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127680/861ae7f0-b2fd-0d13-8392-c7deacb45398.png)


適当な名前（ここでは"codeeditor-test"）を入力し、"Create Space"を押します。

![05_run_space.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127680/b6fea915-dc71-01cb-7bd9-73aa04d08567.png)

しばらく待つと、スペースが作成されます。その後"Instance", "Image", "Storage"などの設定を確認し、"Run Space"を押します。

今回はデフォルトのままで実行しましたが、各種設定を変更することで、より高性能なインスタンスでCode Editorを使用できます。GPUインスタンスを選択することもできるため、Code EditorからLLMを実行することも可能です。

![06_open_codeeditor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127680/9f6092ab-9cb9-26f7-23d9-0ce5e1e4f7e3.png)


しばらく待つとインスタンスが立ち上がるため、"Open Code Editor"を押します。

なお、高性能なGPUインスタンスなどは人気が高いため、割り当てに失敗することもあります。アドホックな対処法としては、失敗しても何度も"Run Space"を実行し続けることで、いずれ割り当てられることを狙うというものがあります。かなり乱暴なやり方ですが。。。

![07_top.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/127680/e6104928-7f68-a249-1fab-52825d8504be.png)

Code Editorが立ち上がると、あとはVS Codeと同様に扱うことができます。お好きなように環境構築しながら作業にお使いいただけます。

ちなみに、私が作業をする場合には大体次の項目を設定します。

- "Clone Git Repository"でCode Editor上にリポジトリをクローン（2回目立ち上げ以降は"Open Directory"でローカルリポジトリにアクセス）
- Themeをダークテーマに設定（画面左下の歯車アイコンから設定可能）
- ターミナルを起動（画面左上の三本線アイコンから選択）

そのほか、Code Editorの詳細な使い方については、AWSの提供する[ユーザーガイド](https://docs.aws.amazon.com/sagemaker/latest/dg/code-editor-use.html)をご覧ください。 

※終了する際には、Studioの管理画面から"Stop Space"を押してスペースを停止してください。

# まとめ

- Code EditorはSageMakerが提供する、ブラウザ上で動くVS CodeライクなIDEです。
- Code Editorを使用するには、まずSageMakerドメインが必要です。
- ドメイン作成後 "Applications and IDEs" から "Studio" を選択し、作成したドメインを指定してSageMaker Studioを起動します。
- SageMaker Studioでは "Applications" から "Code Editor" を選択し、スペースを作成することでCode Editorに接続できます。

---

本記事は下記の記事と同じ内容です。 アクセス解析を目的としてマルチポストしています。

[https://tech-blog.yayoi-kk.co.jp/entry/2024/09/11/110000]



弥生では一緒に働く仲間を募集しています。 ぜひエントリーお待ちしております。

https://herp.careers/v1/yayoi/requisition-groups/2363876d-7695-46ea-9e6a-0bc64d11b6bc
InDesign CC 2024 プラグインでダイアログを使う

inDesignでダイアログを表示させる場合、内容を表示するだけのときと、ダイアログにtextareaなど、値を入力し、その値を使ってその後の処理を行うときで全く異なるダイアログを生成する必要があったため、メモ

## 環境
- inDesignCC(2024)
- Visual Studio Code
    - plugin: [ExtendScript Debugger v2.0.3](https://marketplace.visualstudio.com/items?itemName=Adobe.extendscript-debug)

## 1, ダイアログに内容を表示しておくだけの場合
```javascript
function RsDialog(text) {
  // ScriptUIダイアログを作成
  var dialog = new Window("dialog", "Results Dialog");

  // テキストエリアを追加
  var textarea = dialog.add("edittext", [0, 0, 640, 200], 'ここにテキストを入力...', {multiline: true});
  textarea.text = text;

  // OKボタンを追加
  var okButton = dialog.add("button", undefined, "OK");

  // ダイアログを表示
  okButton.onClick = function () {
    // テキストエリアの内容を取得
    dialog.destroy();
  };
  return dialog;
}
  
  // 実行
  (function(){
    new RsDialog('come').show();
  })();

```

## 2, ダイアログに入力項目を入れておく場合
１の方法で入力項目をダイアログに設置した場合、入力値は取得できるが、背景で開いているドキュメントの要素にアクセスできなかった。
ダイアログに入力された値をドキュメントに反映させるため、以下の方法を用いた

```javascript
var selectedMode = 0;
var inputContent = '';

function myDialog() {
  var myDialog = app.dialogs.add({name:"My Dialog"});
	with(myDialog){
    with(myDialog.dialogColumns.add()){
      // ラジオボタンの追加
      with(dialogRows.add()){
        with(borderPanels.add()){
          var myButtons = radiobuttonGroups.add();
          with(myButtons){
              radiobuttonControls.add({staticLabel:"チェック１", checkedState:true});
              radiobuttonControls.add({staticLabel:"チェック２"});
          }
        }
      }
      // EditTextの追加
      with (dialogRows.add()) {
        var myEditText = textEditboxes.add({editContents: "", minWidth: 200});
      }
    }
  }

	var myReturn = myDialog.show();
	if (myReturn == true){
		selectedMode = myButtons.selectedButton;
        inputContent = myEditText.editContents;
		myDialog.destroy();
		myFunction();
	}
	else{
		myDialog.destroy();
    };
}

function myFunction() {
  var doc = app.activeDocument;
  alert(selectedMode + '\n' + inputContent);
}


// 実行
(function(){
  myDialog();
})();
```
ローカル上でAzure Blob Storageを利用する方法

# はじめに
Azure環境でAzure Blob Storageを利用することになりました。開発プロセスにおいて、Azureテナントに構築されたAzure Blob Storageを直接参照する方法も考えられます。しかし、単体テストやセキュリティの観点からは、最適な選択ではないと考えています。そこで、Azure Blob Storageをローカル環境で構築できる方法について調査しました。その結果、Dockerを使用することでローカル環境にAzure Blob Storageを構築できることがわかりましたので、共有します。

# Dockerファイルの作成
Docker上に定義したAzuriteを利用する。
Docker上で立てたAzuriteを参照、コンテナの作成、ファイルアップロードする場合、Microsoft Azure Storage Explorerを使用する。

## docker-compose.ymlの作成
```
version: '3.4'
services:
  azurite:
    image: mcr.microsoft.com/azure-storage/azurite
    container_name: azurite
    ports:
      - "10000:10000"
    volumes:
      - /azurite:/data
    environment:
      - AZURITE_ACCOUNTS=xxx;xxx
```

# 参考記事
### ローカルでの Azure Storage の開発に Azurite エミュレーターを使用する
https://learn.microsoft.com/ja-jp/azure/storage/common/storage-use-azurite?tabs=visual-studio%2Cblob-storage

### エミュレーターをストレージ エクスプローラーに接続する
https://learn.microsoft.com/ja-jp/azure/storage/common/storage-explorer-emulators?source=recommendations
Roadmap.shで学ぶFlutter - Material / Cupertino widgets -

# 導入
[roadmap.shのFlutter](https://roadmap.sh/flutter)のWidgetsの要素の最後です。
roadmap.shは基本的に紫のマークがついているものを進めていけばいいことになっていますが、Material widgetsもCupertino widgetsもよく利用するWidegetであるので、今回学習対象としました。

# Material widgets
Material widgetsは、Googleのデザインビジュアル言語であるMaterial Designを実装するFlutterウィジェットのセットです。
これらはAndroidとiOSの両方のデバイスで一貫した見た目と操作感を提供するように設計されています。

一般的なMaterial widgetsには以下のものがあります。

- ElevatedButton
- Scaffold
- AppBar
- TextField
- Drawer
- SnackBar
- BottomNavigationBar
- IconButton

これらのウィジェットは、Material Designのガイドラインに従った馴染みのある見た目と操作感を提供するために、Flutterアプリでよく使用されます。

# Cupertino widgets
Cupertino widgetsは、Appleの**iOSユーザーインターフェースの見た目と操作感を模倣**するFlutterウィジェットのセットです。
iOSとAndroidの両方のデバイスで一貫した見た目と操作感を提供するように設計されており、`CupertinoButton`、`CupertinoAlertDialog`、`CupertinoSlider`などのウィジェットが含まれます。
これらは、iOSのデザイン美学に準拠する必要があるクロスプラットフォームアプリを構築する際に役立ちます。

# 終わりに

今回は簡単にですが、Material / Cupertino widgetsについて触れてきました。特にCupertino widgetsはiOSユーザにとって、ユーザーフレンドリーなデザインで、親しみのあるアプリを作成するのに役立ちます。
これからもこれらのWidgetsを工夫してアプリ開発を行なっていきたいです。