OmniAICreator/Qiita-1.07M huggingface dataset:
なぜS3のバケット名はグローバルで一意でないといけないのか

## きっかけ
S3を使ってCDNの機能を作る時にバケットを作成するが、IAMの情報でS3のバケットにアクセスするのにそのバケット名がグローバルで一意にならなければいけない理由がわからなかったのでまとめました。

## s3のバケット名の概要
**グローバルな名前空間**:
S3のバケットはグローバルに一意な名前空間を持ちます。つまり、S3に作成された全てのバケット名は、AWSの全リージョンにわたって一意である必要があります。これにより、どの地域からでも特定のバケットにアクセスしやすくなります。

**DNSに基づいたアドレッシング**:
S3バケットはDNS（ドメインネームシステム）に基づいてアドレス指定されます。バケット名がURLの一部として使用されるため、一意でなければなりません。例えば、バケット名が my-unique-bucket であれば、そのバケットのURLは my-unique-bucket.s3.amazonaws.com になります。

**シンプルな管理とアクセス**:
一意のバケット名により、開発者や管理者は特定のバケットに簡単にアクセスし、管理できます。名前が重複すると、どのバケットがどのユーザーに属しているのかを区別することが難しくなります。

**セキュリティとプライバシーの確保**:
一意のバケット名は、名前の衝突や誤ったデータアクセスを防ぐのに役立ちます。これにより、ユーザー間でのデータの混在や不正アクセスを防ぐことができます。

## まとめ
IAMの情報はあくまでS3にアクセスできるか否かを定義するもので、s3のバケット名はDNSでURLの一部になるためグローバルで一意にならなければいけないことがわかりました。
nuxtの開発を通じてコンポーネント指向開発の重要性に気づいた話

# はじめに

前回・前々回とフレームワークっておいしいの？をお題としてコンポーネント開発に触れてきました。
https://qiita.com/jun2/items/ae09f35c307711ac4dd5
https://qiita.com/jun2/items/5408fbbd1ed393bedd4e
開発を行っていく中でコンポーネント指向での開発を行うことでプロジェクトを跨いだ効率化が図ることができることがわかってきました。
上記2記事のまとめ編に近いものになりますが、コンポーネント指向での開発を検討している方の後押しになればと思います。

# コンポーネント指向でのメリット

私なりに感じたメリットとしては以下のとおりです。
* UI動作に統一感が出る。
* 軽微なロジックを何度もコピペする必要がない
* テストの範囲を少なくすることができる
* 上記より開発スピードがとても早い


それぞれ解説していきます。
## UI動作に統一感が出る

開発者によって好みがあると思うのですが、例えば日付入力ボックスの右側にクリック時にカレンダーが開くアイコンをつけたい人、アイコンはつけずに入力ボックス押下時にカレンダーをつけたい人などあると思います。
社として作る人が限られている場合はこれらはルールなりレビューなりで統一することができますが、作る人はバラバラ、部署もバラバラ、レビューする人もバラバラ、ルールがなかなか定着しにくい風潮、など色々と事情がある場合統一していくことは難しいです。
部品開発を行い、タグを書くだけで実装できるのであれば作る人の好みは現れにくいものと思います。

## 軽微なロジックを何度もコピペする必要がない

冒頭の記事でも記載しましたが、例えば
* フォーカスアウト時にカンマ編集する(フォーカスイン時にカンマをとる)
* 日付入力時に和暦変換表示する
* 大文字小文字を小文字に統一する
* 電話番号・郵便番号・メールなどのバリデーション形式チェック
など部品化しておくことで本体のロジックには記載せずに純粋なビジネスロジックだけを表現することができます。

## テストの範囲を少なくすることができる

これが一番大きいです。
「軽微なロジックを何度もコピペする必要がない」に記載したロジックはテストする必要があります。
カンマが2個以上になったら（私がよくハングするパターン笑）・・・、スラッシュ付きの日付の場合は・・・など軽微なロジックといえど細かい条件を与えてテストする必要があります。
コンポーネントとしてすでに担保できているのであれば、狙った機能が動いているか？（パラメータなどの設定にて正しく設定できているか）を見れば良いだけとなります。
当然ながらコンポーネントとしては細かい条件のテストは必要です。

## 上記より開発スピードがとても早い

これらメリットを感じた上で開発を行ってみると確かに開発は早いですし、コーディング量そのものがぐっと減ることが実感できます。
ただ一方でコンポーネント開発の初期コストは必要です。
私自身もコンポーネントの仕様を拡張していくことに時間を大きく取られました。
また、リードエンジニアが率先してやる、コンポーネント開発の専門部隊なりワーキンググループにて開発が行われるなどの体制も必須です。
みんなで良くしていきましょう！というスタンスでうまくいく企業様であればそれはそれで素晴らしいことだと思います・・・が、積極的な人材が多数いるような状況というのは恵まれた環境であると思います。


一度作ったもの再利用はコピペすることで確かに実行することができます。
が、もともと汎用性を求めて作ったコンポーネントの再利用性は非常に高いものであると思います。
頭ではわかっていてもなかなか今のやり方を変えていくには勇気が必要なものではあります。
なかなか踏み出せない方の助力に少しでもなればと思います。
アップデートしたらWSLが起動しなくなった（2023/11）

最近の問題らしく解決方法に中々たどり着けずに苦労したので、取り急ぎ共有します。

# 問題

Windowsアップデートに伴うWSLのアップデート（？）を適用したら以下のようなエラーでLinuxが起動しなくなりました。

```
Installing, this may take a few minutes...
WslRegisterDistribution failed with error: 0x8007019e
Error: 0x8007019e Linux ? Windows ??????????????????
```

そもそもwsl自体がうんともすんとも反応しなくなっています。

```
wsl -v
WSL はアップグレードを終了しています...
更新に失敗しました (終了コード: 1603)。
Error code: Wsl/CallMsi/E_ABORT
```

`0x8007019e`については、「Windowsの機能の有効化」からWSLを有効にしろ、という情報しか出てこず、通常はその手順で解消するようですが、ここら辺を確認したうえで再起動やWSLの再インストールしてもダメでした。

# 解決方法

少し前にリリースされたWSL2.0.9の問題のようです。
https://github.com/microsoft/WSL/issues/10764

以下のコメントを参考に[WSL2.0.5](https://github.com/microsoft/WSL/releases/tag/2.0.5)をインストールすることで問題が解決しました。
https://github.com/microsoft/WSL/issues/10764#issuecomment-1815485695

> Press Win+R and type "regedit"
> Navigate to Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
> Look for "WslService" -> Right click on folder icon -> Delete
> Restart PC
> Install https://github.com/microsoft/WSL/releases/tag/2.0.5
Matplotlibで日本語を表示する

## 問題の背景

matplotlibでグラフを描画した際にタイトルや軸のラベルが日本語だと文字化けしてしまうという問題があった。
クライアント向けの資料などにグラフを使用する際にt不便なので、日本語を表示する方法を調べた。

## matplotlibに日本語に対応しているフォントがあるか確認する方法


```python

import matplotlib

#matplotlibのディレクトリを確認する。
print(matplotlib.matplotlib_fname())

#matplotlibに追加されているフォントの一覧を取得する。
fonts = set([f.name for f in matplotlib.font_manager.fontManager.ttflist])
print(fonts)

# 日本語で使用できるかを確認する方法

# フォントの表示
for i, font in enumerate(fonts):
    plt.text(0, i, f"日本語：{font}", fontname=font)
    
# 見やすいように軸を消す
plt.ylim(0, len(fonts))
plt.axis("off")
    
plt.show()

```

実行した結果が以下のようになる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1090582/c5f45563-e8f6-366b-3d0b-261abc65b7a5.png)


私の環境ではIPAexGothicというフォントが日本語に対応しているとわかったので、これを指定していく。
やり方としてはmatplotlib.pyplotをインポートした際に下に以下のコードを追記するだけである。

```python

import matplotlib.pyplot as plt
plt.rcParams['font.family'] = "IPAexGothic"

```


## matplotlibに日本語対応のフォントが追加されていなかった場合

以下の記事がわかりやすかったので参考にしていただきたいが、私の方でも簡単に解説する


https://qiita.com/mikan3rd/items/791e3cd7f75e010c8f9f




　
　
   
1.まず以下のサイトからIPAexGothicをダウンロードする。



  
https://moji.or.jp/ipafont/ipaex00401/



  　
2.次に現在のGoogleColaboratory（もしくはJupyternotebook）のファイルと同じディレクトリに

fontsというフォルダを作成し、先ほどダウンロードしたフォルダの中に入っている、「ipaexg.ttf」を移動させる。

　
 
　
  
3.最後に以下のコードを書く


```python
from matplotlib import font_manager

font_manager.fontManager.addfont("/content/drive/MyDrive/fonts/ipaexg.ttf")
matplotlib.rc('font', family="IPAexGothic")


```

あとは本記事の上にある、フォントが追加されていた場合の手順を踏めば良い。
UE/Niagara   SubUV を適用した MeshRender の UV を編集する

# 要約
Material において、Particle SubUV ノードは使わずに下記画像の右を代わりに使う

SubUV を適用した MeshRender の UV を編集するには下記マテリアルを適用し、Paricle SubUV Properties ノードの TextureCoordinate0,1を編集する
![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362049/e7839d12-a964-c459-96e0-5ec4a20512d3.png)







# 説明
UE/Niagara で 各Renderモジュールで SubUV を適用した場合、SpriteRenderモジュールでは、Texcoord[0],[1]ノードのUVが自動でSubUV用に変換される(上記画像のParticle SubUV PropertiesノードのTextureCoordinate0,1ピンと同じになる)が、MeshRenderモジュールでは変換されない

そのため、MeshRenderモジュールで SubUV を設定しただけでは SubUV は使えない

この場合、Texture Sampleノードの代わりに Particle SubUVノードを使えば SubUV を使えるが、この UVsインプットピンは機能していない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362049/23b9a8b6-1ef2-2a9e-7536-ba8ed4dc294f.png)
[公式ドキュメント](https://docs.unrealengine.com/5.0/en-US/particle-material-expressions-in-unreal-engine/#particlesubuv) より引用

そこで、Particle SubUV ノードのHLSLコードを見て組んだのが下記画像のノード群
これはHLSLコードの内容とまったく同じ

Texture Sampleノードはそのままで、SubUV用に変換されたUVを持ってくる方法

UVを編集する場合は、Paricle SubUV Properties ノードの TextureCoordinate0,1を編集する

Niagara の 各Renderモジュール の SubUV の SubUVBlendingEnabled をオンにしなければ、TextureCoordinate1 と Blend は使わなくて良い(下記画像のLerpと下のSourceTexture を消す)


|Particle SubUV Properties ノード|Niagara の Renderモジュール の SubUV で設定した値を受ける|
|---|---|
|TextureCoordinate0 ピン|Niagaraで指定したSubUVに基づいて変換されたUV|
|TextureCoordinate1 ピン|TextureCoordinate0 の一つ先の連番フレームのUV|
|Blend ピン|Niagara の Blend が ON の時、連番フレーム間で動的に0~1が出力される。OFFの時は常に0|

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362049/ee8d23ab-af7b-9ac3-9c48-58928d7a92ee.png)


# Particle SubUV ノードのHLSLコード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362049/bbe50d16-ad94-9418-7214-5f19d89e1ddf.png)
GPTが書いたコードをKernel#evalで動かす

# はじめに
最近Rubyを入門しています。
Rubyの特徴として挙げられる"メタプログラミング"を活かしたアプリを作成しました。

## `Kernel#eval`とは

Rubyの`eval`メソッドは、文字列として与えられたRubyコードを実行するために使用されます。これは、Pythonの`exec`やJavaScriptの`eval`など、他の言語における同様の機能に類似しています。

#### 基本的な使い方

```ruby
code = "1 + 2"
result = eval(code)
puts result # 出力: 3
```

上記の例では、`code`変数に格納された文字列がRubyの式として評価され、その結果が`result`変数に代入されます。

# つくったもの
[Github](https://github.com/daisuke0926dev/eval_generate_and_run)

![無題の動画 ‐ Clipchampで作成](https://github.com/daisuke0926dev/eval_generate_and_run/assets/90462400/89de786e-4ee8-429f-9e2c-b7c8b2011cd1)

### コード(一部抜粋)

```python
instructions = <<~HEREDOC
命令:
以下を満たすjsonデータを返してください
JSON:
[eval_code:evalで実行できるコードで最後に標準出力で会話形式の回答を出力すること
]
参考:
HEREDOC
  
question = input
prompt = question + instructions + api # api にapiの使い方を文字列で代入しておく
client = OpenAI::Client.new(access_token: ENV['OPENAI_KEY'])
response = client.chat(
    parameters: {
      model: "gpt-4-1106-preview",
      messages: [
        {"role": "system", "content": "あなたはITエンジニアです。"},
        {"role": "user", "content": prompt }
      ],
      response_format:{"type":"json_object"},
      max_tokens: 300,
    },
)
# response内容のうち、メッセージ部分を格納
response_content = response['choices'][0]['message']['content'

# メッセージ部分のうち、evalで実行させる部分をJSONで受け取る
response_content = JSON.parse(response_content)

# evalでコードを実行
eval(response_content["eval_code"])
```

# 今後の展望
アップデートごとにGPTの扱えるトークン数が増えています。候補のAPIを数多く渡すことで、より多様なリクエストに対応できるようになります。
例えばLineAPIを渡してみたり、slackのAPIを渡してみたり。。。
if letとguard文の使い方

## 想定されるシナリオ
 `if let`と`guard let`は、オプショナル型の値を取り出すための構文です。これらの違いは、値がnilの場合の処理の流れにあります。

 `if let`は、オプショナル型の値がnilでない場合にその値を取り出し、そのスコープ内で利用します。値がnilの場合、`else`ブロックが実行されます。

 例：
 ```swift
 if let someString = b {
     // 値があるときは、この処理を実行する
     print("Optional Value \(b)")
 } else if b == nil {
     // 値がnilのときは、この処理を実行する
     print("b is nil")
 } else {
     print("b has a value")
 }
 ```

 `guard let`は、オプショナル型の値がnilでない場合にその値を取り出し、その後のコードで利用します。値がnilの場合、`guard`ブロック内の`else`ブロックが実行され、その後のコードは実行されません。

 例：
 ```swift
 func say(value: String?) {
     // nilだとreturnする
     guard let value = value else {
         return
     }
     print(value)
 }
 ```
 これらの構文を適切に使い分けることで、コードの可読性と安全性を向上させることができます。

## Playgrandでそのまま実行できるコード
if letの処理を書いてみました。この場合だと、変数bに`nil`が入ってるので、分岐処理で`b is nil`とログに出力されます。
Optional型を使っているので、`String`と`nil`を変数に代入することができます。

## using if let
```swift
var a: String?
a = "Hello"
var b: Optional<String>
b = "Hello"
b = nil
// if letは、オプショナル型の値を取り出すための構文です。
if let someString = b {
    // 値があるときは、この処理を実行する
    print("Optional Value \(b)")
} else if b == nil {
    // 値がnilのときは、この処理を実行する
    print("b is nil")
} else {
    print("b has a value")
}
```

## using guard let
`function`を定義して、実行しないと使えなかったので、`say`という関数を作りました。
```swift
func say(value: String?) {
    // nilだとreturnする
    guard let value = value else {
        print("nilだよ!")
        return
    }
    print(value)
}

let arg: String? = nil
say(value: arg)
```

## 最後に
１年前は、理解できなかった。`if let`と`guard let`の使い方の解説でした。他の言語だとこんなのないような...
Swift独特ですね。
複数回のランダムアクセス Python3編

https://paiza.jp/works/mondai/data_structure/data_structure__array_step2

>要素数 N の数列 A と要素数 Q の数列 B が与えられます。 1 ≦ i ≦ Q の各 i について、i 行目に A の B_i 番目の値を出力してください。

という問題。
さっそく覚えた内包表記をつかってAとBの配列を作ってごにょごにょやる(言い方）

```py
N = int(input())
A =[int(x) for x in input().split()]
Q = int(input())
B =[int(y) for y in input().split()]
for i in B:
    print(A[i-1])
```

Qをつかうならその次のfor文はこんな感じに。
わかりやすいのはどっちかな？　多分上？

```py
for i in range(Q):
    print(A[B[i]-1])
```

内包表記を使うときれいに1行にまとまるね〜。
BlenderのSVGインポートでトポロジーが汚すぎる問題をIllustratorが解決した話

＼ こんにちは ／

<a href="Ateam Finergy Inc. × Ateam Wellness Inc. Advent Calendar 2023">Ateam Finergy Inc. × Ateam Wellness Inc. Advent Calendar 2023</a>の１日目の記事になります。

今年中途で入社したばかりの新入りデザイナー、@maya_ch が担当します！

## :thought_balloon: まずは自己紹介

もともとはエンタメ業界でマルチにクリエイティブをしておりました。
クリエイティブといってもたくさんあるかと思いますが、本当にたくさんのことをしてきました。

時には曲を、
時には撮影から映像の制作を、
時にはデザインを、
時にはゲーム開発までしてきました。

活動におけるモットーは、「 **技術は誰かの体験に。** 」です。
日々の活動を通して、世の中をもっと楽しくするためのクリエイティビティに努めています！

今年から中途で入社したエイチームでも、
周年イベントや表彰式などでの企画・演出を含む体験型クリエイティブを担当しています。

## :thought_balloon: 背景

以下のnoteにてエイチームの社内イベントで制作した3Dアニメーションの制作裏側を解説してるのですが、簡単な説明にまとめてしまったので、今回はさらに深掘りをしていきたいと思います！

https://ateam-note.a-tm.co.jp/n/n56dce240249f

ここで活用した技術や苦労した点をもっと語りたい。そんな気持ちで書いています。


## :thought_balloon: 本題

まずは制作した動画をご覧ください。

<iframe width="512" height="384" src="https://www.youtube-nocookie.com/embed/yHNZEbW9u8Q?si=1qshfi0EtjhpjwU1" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>


今回はこちらの映像で使用した3Dテキストの制作について書いていきます。


### :zap: 失敗例

まず、ロゴのSVGデータを
Blenderのデフォルトインポート機能で読み込みました。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524010/47da96a3-9b06-cd25-4f51-9b3a33547f32.png)


一見問題なさそうにみえますね、、、、、、
でもよくみると、、、、、、、、、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524010/23d28dd5-78cb-bd21-a18f-7654853baf1b.png)

えっ

・・・・・・:thinking:？？？？？？

ま、まぁ動作には問題ないかもしれない。まだ舞える。いけるはず。。。。
厚みとか丸みをつけたらわんちゃんいけるのでは。


[ ソリッド ]
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524010/6e01ebd8-e2f2-964e-914d-5c45244d925b.png" width="384px">


えっ

・・・・・・:cry:

[ サブディビジョンサーフェース ]
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524010/5193f3d5-064b-fbbf-8dbe-1ed746a1b61e.png" width="384px">


あ、完全にわかった。完璧に理解した。

**みたらわかる。無理なやつやん。**

---
### :sunny: あっさりと解決した

数時間の戦いの末、
社内の3Dに明るい天才クリエイターに相談したらあっさりと解決してくれました。

> そもそもこれ、Blenderで頑張る必要ある？

その発想はなかった。私は頑張る気満々でした。

天才クリエイターはAdobeのIllustratorを起動し、ささっと3D化。

#### [ 効果 ] → [ 3Dとマテリアル ] → [ 膨張 ]

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524010/92a6a902-f91d-b896-7643-000f554259f1.png)

できとる。完璧にできとる。。。

いやまって！Blenderに入れた時のトポロジーはどうなの？？

ってことで、Illustratorで作った立体をobj形式で書き出してBlenderへインポート。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524010/570b10ee-330b-b2b6-5113-a820386a3e69.png)

ポリ数は多いけど、、圧倒的に綺麗！！！！！！！！！

※ ポリ数を綺麗に削減する方法もあるのですが、ここでは割愛しますね。


## :thought_balloon: まとめ

:::note
- 無理にBlenderで頑張る必要はない
- Illustratorで3D書き出しすれば一発で解決できた
:::

うまくいかない時は視野を広げて、時には他のツールで試すことも大切ですね！

みなさんもBlenderでロゴを3D化したり、3Dテキストを扱うことがあればぜひお試しください！

映像の中にはまだまだ解説したいことが多いので、少しずつ書いていきたいと思います。
それでは、最後まで読んでいただきありがとうございました！
AWS DAS合格(更新)記(2023/11/20投稿)

# はじめに
この度AWS認定のDASを受験してきましたので、勉強した内容と受験した感想を書いておきます。
今回は更新目的の受験になります。

尚、AWS DAS試験は2024年4月9日に廃止が決定しておりますので、この記事はそれまでに期限が来る人向けの内容になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440403/c7fccfa5-324a-ac60-f9a1-7af546d0b380.png)
https://aws.amazon.com/jp/certification/certified-data-analytics-specialty/

# 前提
* AWSのデータ分析基盤は実務経験あります
* AWS認定は全て取っています(詳細は[こちら](https://qiita.com/handy-dd18/items/d21d914bf1c475d777f2))　※PASは[こちら](https://qiita.com/handy-dd18/items/18e8a856906f97bbb964)
* AZ-900/AZ-104/AZ-700/AZ-305/AZ-204/DP-900/AZ-500/DP-203は取得済み
* Google Cloud認定は5つ取ってます

# 学習内容
今回は以下の順番で勉強を進めました。

* [①試験対策本（要点整理から攻略する『AWS認定 データ分析-専門知識』）](https://amzn.asia/d/0EDX7Qx)
* [②Udemy模擬問題](https://www.udemy.com/share/103WTI3@DLZU6b6U5xsrRAeMb_7ky9kpHMfBbC5Imo4V2jOgco3XU6_JXmiC-JOhGpWBpWt-/)

## 試験対策本
前回受験にはまだ発売されていなかったですが、以前もAWSの資格勉強で使ったことがある著者の方の対策本が今年の6月26日に発売されていましたので、まずはそれで勉強しました。

自分はある程度実務で触っているところがあったので、その部分は読み飛ばしつつ、普段触る機会のないEMRやKinesis周りをザっと見返して、どのような機能があるかを覚え直しました。

AWSサービスの仕組みや実際に利用されるユースケース等が図や実際のコンソール画面を元に説明されていて、非常にわかりやすかったです。


## ②Udemy
次にUdemyの模擬試験講座を購入して、最初の1回分だけ解きました。
英語でしたが、今まで購入した模擬試験講座に比べると解説が多かったので、忘れている内容の再確認にはちょうど良かったです。
1回分しか解いていないので内容の類似性はそこまで確認できませんでしたが、似たような問題はいくつか出ているのが確認できたので、3回分やればもっと安心して解けたのかもしれません。

- [AWS Certified Data Analytics Specialty Practice Exams
](https://www.udemy.com/share/103WTI3@DLZU6b6U5xsrRAeMb_7ky9kpHMfBbC5Imo4V2jOgco3XU6_JXmiC-JOhGpWBpWt-/)

# 受験した感想
結果からいうと思ったよりも難しかったです。
たまたまかもしれませんが、特に自分が苦手としているストリーミング系が多く出てきたり、過去受験した時からアップデートされた内容が含まれてたり(LakeFormation等)して、3時間ギリギリまで時間を使って解いていました。
もう少しKinesisとEMR周りは学習しておけばよかったなと思いました。

# 受験結果
得点としては思ったよりも取れていました。
どうしてもわからない問題は「AWSが出すならこの選択肢が正解じゃないか」という勘で回答していたので、恐らくそれがうまい具合に当たったんじゃないかなと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440403/9ffeb563-729f-840a-b0b6-e5c533e11e77.png)

# おわりに
これで無事来年のAll Certの申し込みができそうで安心しました。
冒頭にも書きましたが、AWS DAS試験は来年4月に廃止され、今度はAWS DEA試験が新しく出てくるそうなので、次は新試験を受験してみたいと思います。(できれば年内中に)

この記事がどなたかの参考になれば幸いです。
JavaScriptにおける配列の種類と値の取り出し方について

# JavaScriptにおける配列の種類と値の取り出し方について

## 配列(一次元配列)とは
- 複数の変数を格納するための変数のこと。
- 0番から採番される。
-値を取り出す時は[]で番号を付けて指定する。

```
let fruits = [ "apple" , "orange" , "banana" ];
console.log( fruits ) ;　// ["apple", "orange", "banana"]
console.log(fruits[0]);　//apple
console.log(fruits[1]);　//orange
console.log(fruits[2]);　//banana
```

## 多次元配列とは
- 配列の中に配列やオブジェクトが格納されており、入れ子状態となっている配列のこと。
- 0番から採番されるのは配列と同じ。取り出し方も同様。
- テーブル形式でデータを管理したい時によく使われる。
```
let likeFruits = [ ["ゴリラ",5,"apple"], ["チンパンジー",3,"orange"] , ["さる",8,"banana"] ];
console.log(likeFruits[1]);　// ["チンパンジー", 3, "orange"]
```

取り出した要素を変数に格納し、更に細かく取り出すことも可能。

```
let likeFruits = [ ["ゴリラ",5,"apple"], ["チンパンジー",3,"orange"] , ["さる",8,"banana"] ];

let animal = likeFruits[0];　
console.log(animal);　　// ["ゴリラ", 5, "apple"]
console.log(animal[0]);　//ゴリラ　
console.log(animal[1]);　//5
console.log(animal[2]);　//apple
```
別の変数に格納せず、そのまま取り出すことも可能。

```
let likeFruits = [ ["ゴリラ",5,"apple"], ["チンパンジー",3,"orange"] , ["さる",8,"banana"] ];

console.log(likeFruits[0][0]);　//ゴリラ
console.log(likeFruits[0][1]);　//5
console.log(likeFruits[0][2]);　//apple
```

## 連想配列とは
- 添え字（キー）と値（バリュー）がセットになっている。
-キーは好きな文字列を指定出来るｌ
- jsでは、値だけではなく関数を収めることも可能なのでオブジェクトとも呼ぶ。
```
let likeFruits = {name : "ゴリラ" , number : 5 , fruit  : "apple" } ;
```
上記の例だと「name」が添え字（キー）、「ゴリラ」が値（バリュー）と呼ぶ。


*連想配列の値の取り出し方*
` 配列名.キー ` もしくは ` 配列名[ "キー" ] ` で値を取り出すことが可能。
```
let likeFruits ={name : "ゴリラ" , number : 5 , fruit: "apple" };
console.log(likeFruits.name);　//ゴリラ
console.log(likeFruits[ “ fruit ” ]);　//apple
```

配列の中に連想配列を格納することもできる。
` 配列名[採番] ` で連想配列全体を取り出すことが可能。
` 配列名[採番].キー ` もしくは `配列名[採番][ "キー " ] ` で個別の値を取り出すことができる。
```
let likeFruits = [ 
    {name : "ゴリラ" , number : 5 , fruit: "apple" } ,
    {name : "チンパンジー" , number : 3 , fruit: "orange" },
    {name : "さる" , number : 8 , fruit: "banana" } ];

console.log(likeFruits[0]);　// {name : "ゴリラ" , number : 5 , fruit: "apple" }
console.log(likeFruits[0].name);　//ゴリラ
console.log(likeFruits[0]["fruit"]);　//apple
```

配列の中に配列や連想配列を格納できるように、連想配列の中に連想配列を格納することも可能。
```
let students = { "3年" :
    { "A組" : {
        "1列目" :  [ { "Aさん" :{
            name :"Aさん",
            age :18,
            h:160,
            w:60,
            sex:"女性",
        }}]
        },Bさん...,Cさん...]
        }
    }
}
```

### 余談
*jsonとは*
連想配列の塊と考えられる。

*意外と身近な連想配列の例*
キー：値の形になっているものと考えると意外と身近なものにも配列や連想配列が見られる。
例：CSS
width : 100% ;
widthがキー、100%が値…と考えられる。

例：CSV
CSVとは……データをカンマ「,」で区切られたファイル
データを「,」で区切ったデータの塊なので、配列と考えられる。


漠然と「配列」や「json」といった単語に苦手意識があったので、「配列」と「連想配列」と「多次元配列」の基礎を復習がてら改めてまとめてみました。
WEBアプリやGASを使ってToDoアプリやメモアプリを作ろうとするとデータの保持は避けられない問題なので基礎を抑えた上で繰り返し書くことで少しずつ慣れて行こうと思います。
企業情報漏洩ニュースまとめ - InSpec でテスト自動化し予防する

https://www.nikkei.com/article/DGXZQOUB305A40Q3A031C2000000/

> 代理店同士をつなぐシステムで東京海上社員による設定ミスがあった。287の代理店が管理する他の生損保を含む顧客情報を、本来アクセス権限を持たない一部の代理店が閲覧できる状態に

---

https://atmarkit.itmedia.co.jp/ait/articles/2310/23/news011.html

> 『Ansible』定義からサーバ種別を判別してデータ投入やリカバリーなどの操作をする、設定が終わったら『Serverspec』などのテストツールでテストするといった流れ

>人の手による作業が介在することでスピードが遅くなるなど自動化の効果が薄れてしまう。
>作業漏れやミスにつながりやすくなっていた。

>テストを自動化することで、運用負荷の軽減はもちろん、「問題、不具合発生から再発防止までのループを素早く回せる」というメリットもある。

>「インフラ構築における問題としてサーバの設定漏れがある。初期設定が間違っている、初期設定はよかったが一時的に設定を変更した後で戻し忘れる、設定した後の確認が漏れるといったことはあり得る。こうした問題に『ダブルチェックを頑張ります』といった対応を取りがちだが、それをずっと続けることは大変だ（橋本氏は“しんどい”と表現した）。人間は間違うものだ。どうやって機械的に作業の保証するのかが重要となる」

---

https://www.itmedia.co.jp/news/articles/2311/13/news133.html

> 名簿などが少なくとも20年7月～23年8月までネット上で閲覧可能な状態となっていた。この期間中、少なくとも3種類のランサムウェア攻撃を受け、暗号化されたファイルがあることも確認

---

https://atmarkit.itmedia.co.jp/ait/articles/2310/19/news001.html?_gl=1*1v6d6si*_ga*ODA3MjAyMTI1LjE2OTk5NTk3NTM.*_ga_JZCZP0LYY7*MTY5OTk2OTMyOS4yLjEuMTY5OTk2OTM2NS4yNC4wLjA.#l_ighsdgg004.jpg&_ga=2.77501597.969430252.1699960718-807202125.1699959753

> 構成管理と脆弱（ぜいじゃく）性スキャンの自動化

https://www.itmedia.co.jp/news/articles/2310/12/news048.html

> ・ソフトウェアやアプリケーションがデフォルト設定のままにである
> ・不適切な設定

---

上記のような情報漏洩の対策に共通しているのは、テストやスキャンの自動化です。

InSpecで、脆弱性・設定ミス・設定漏れのテストを自動化することができます。

https://www.chef-sec.com/inspec_cis-stig_security_scan/

https://qiita.com/navitime_tech/items/2ad207e7fdff5b3ed727
PlasticSCMのGUIからワークスペースが消えた時の対応

PlasticSCMのGUIを使っていると、ローカルに存在するはずのワークスペースがたまに表示されなくなることがあります。表示されるようにするための対応をメモしておきます。

1. 表示させたいワークスペースの.plastic/plastic.workspace を開いてGUID（ハイフンが混ざっている36文字）をコピーする。
1. 1. %LOCALAPPDATA%/plastic4/plastic.workspace をメモ帳などで開く。
1. 行を追加して次のように記述する（区切りはタブ） `[コピーしたGUID] [リポジトリ名] [ワークスペースの絶対パス]`
1. 保存する。
1. PlasticSCMのGUIを再起動すると、ワークスペースが表示されるようになります。
ランダムアクセス Python3編

今日のお題はここから
https://paiza.jp/works/mondai/data_structure/data_structure__array_step1

> 要素数 N の数列 A と数値 M が与えられます。A の M 番目の値を出力してください。

今までの問題をやっていたら意外と！簡単にできてしまった。

```py
N,M = map(int,input().split())
A = list(map(int,input().split()))
print(A[M-1])
```
Aの配列に入れるところを、ループでやってみる
今までは、`arr= input().split()`と配列に入れていた部分を、
下のようにそのままループにしてしまえる。

```py
A =[]
for x in input().split():
    A.append(int(x))
```
そしてこれはもっと簡単にできて

```py
A = [int(x) for x in input().split()]
```
こんな感じになる（なーんと！）
内包表記（ないほうひょうき）と呼ぶらしい。

一瞬書きにくいかもだが、
入れたい配列 = [(処理) for文の1行目]
でできる。
[]がappendの代わり、と思えばいいだろう。

ちなみにこれはif文も追加できる。
たとえば、ｘ＝2のときだけ追加したいとかだと、

```py
A = [int(x) for x in input().split() if x=="2"]
```
と、if文の条件文だけ後ろに追加すればOK。
以前コメントを頂いた方の[書かれたコード]([https://qiita.com/Atsulabo/items/30771f66ff2b86ea98c4#comment-e08c005290ee1f509a12)にもあったので
覚えておこう！(こっちは二重に［］を使っててそれを1行で書いててすごいです）
microCMSのAPIをNuxtから呼び出す

```demo.vue
<ul>
  <li v-for="item in contents" :key="item.id">
    {{ item.id }}
  </li>
</ul>

<script>
import axios from 'axios'
export default {
async asyncData() {
  const test = await axios.get(
    'https://XXXXXXXXXXXX.microcms.io/api/v1/menu',
      {
        headers: {
          'X-MICROCMS-API-KEY': 'XXXXXXXXXXXX',
        },
      }
    )
  const contents = test.data.contents
  return { contents }
  },
}
</script>
```

最後のreturn {contents}がポイント。
{ }で囲うのは、contentsの中身が配列のインデックス:タイトルという形でオブジェクト形式になっているため。これが直感的でないし、return文を一行で書くときに人によっては{}を省略する／しないクセがあると思うので、**複数人プロジェクトでは必ず統一したい。**

ただこれだとapiキーが隠蔽されていないので、最後はきちんと隠蔽処理をする。
処理の方法はどんどん変わっていっているので、その時の最新をググる。
k8sのコントロールプレーンをELBでヘルスチェックさせてみる

# はじめに
以前k8sをkubeadmで構築した際に、コントロールプレーンのヘルスチェックはHAProxy+keepalivedで実現させていたが、AWSのNetwork LoadBalancerで実現できるか確認してみようと思います。

# 構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478546/480aac74-492b-3a40-0abc-78b1be7c0720.png)

### サーバ環境情報
- Ubuntu 22.04
- kubeadm/kubectl/kubelet 1.28.03
- runc 1.1.9
- containerd 1.7.5
- cni-plugin 1.3.0


# 実際にやってみる
### Kubernetesをまずインストール
コントロールプレーン3台に入れていく。
```
#各種設定
cat <<EOF | tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

modprobe overlay && modprobe br_netfilter

cat <<EOF | tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

sysctl --system

#Containerdインストール
wget https://github.com/containerd/containerd/releases/download/v1.7.5/containerd-1.7.5-linux-amd64.tar.gz
tar Cxzvf /usr/local containerd-1.7.5-linux-amd64.tar.gz 
wget -P /usr/local/lib/systemd/system/ https://raw.githubusercontent.com/containerd/containerd/main/containerd.service
systemctl daemon-reload 
systemctl enable --now containerd

#runcインストール
wget https://github.com/opencontainers/runc/releases/download/v1.1.9/runc.amd64install -m 755 runc.amd64 /usr/local/sbin/runc

#cni-pluginインストール
wget https://github.com/containernetworking/plugins/releases/download/v1.3.0/cni-plugins-linux-amd64-v1.3.0.tgz
mkdir -p /opt/cni/bin
tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-v1.3.0.tgz

#Containerd設定
mkdir -p /etc/containerd
containerd config default | tee /etc/containerd/config.toml
sed -i -e 's/sandbox_image = "registry.k8s.io\/pause:3.8/sandbox_image = "registry.k8s.io\/pause:3.9/g' /etc/containerd/config.toml
sed -i -e 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
systemctl restart containerd

#Kubernetesインストール
apt-get update
apt-get install -y apt-transport-https ca-certificates curl
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
apt-get update
apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl

```

### ELBを作る
ターゲットグループ
```
ターゲットタイプ：インスタンス
ターゲットグループ名：お好きなように
プロトコル：TCP
ポート番号：6443
IPアドレスタイプ：IPv4
VPC：指定したもの
ヘルスチェックプロトコル：TCP
ターゲット：コントロールプレーン3台

```

ロードバランサー
```
タイプ：Network
ロードバランサー名：お好きなように
スキーム：Internet
IPアドレスタイプ；IPv4
VPC：指定したもの
マッピング：所属するAZとサブネット（パブリックサブネットを選択）
セキュリティグループ：6443ポートを許可するSG
リスナー：TCP/6443/作成したターゲットグループ

```

### ヘルスチェックを確認
ターゲットグループにぶら下がっていることと、インスタンスへの疎通が取れている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478546/848c2f49-5123-c665-8a00-56e9836e4b36.png)


### コントロールプレーンの起動
その他引数の指定はお好みで。
```
kubeadm init --control-plane-endpoint "<NLBのDNS名>:6443"
```
Speedtest Tracker の設定について

## この記事の目的

[Speedtest Tracker](https://hub.docker.com/r/henrywhitaker3/speedtest-tracker)の設定で、アクセス集中を避けるように設定してみたら、
結果が非常に良くなったため紹介します。

## 設定変更でどのような結果になったか

以下の図の左半分が設定変更前、右半分が設定変更後です。

![SpeedtestTracker_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566576/904676ea-b038-4d7c-33f0-2e93e8833b37.png)

## Speedtest Tracker のアクセス集中回避設定

画面右上の`Settings`をクリックし、`Settings`画面内の`Schedule`で`53 * * * *`とする。

![SpeedtestTracker_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566576/e073aa59-d6d8-585b-b224-67ab41dfd499.png)

![SpeedtestTracker_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566576/b7354870-1626-3de7-a206-d8bc1eabc341.png)

`53`の部分は**31**以上の素数であれば何でも良いです。

`59`だと測定途中に、`0`のアクセス集中に巻き込まれる可能性があるため、`59`は避けて`53`にしています。
WebアプリとDBサーバー間の通信がthe Internetを経由しないように構成する

船井総研デジタルのよもぎたです。

# サマリ
[前回の記事](https://qiita.com/t_ymgt/items/765d268e1c27a0b801ba)で、Azure App Service 上のWebアプリから外部へのアクセスが固定のNAT Gatewayから出ていくように構成しました。今回は逆に、内部の、WebアプリからDBサーバーへの通信がMicrosoftネットワークで完結するように構成したいと思います。

# 構成の概要
App Service上のWebアプリについては、前回の記事と同様に構成します。
DBサーバーは、今回はAzure SQL Serverを使います（Managed Instanceではありません）。サービスエンドポイントを構成してWebアプリの仮想ネットワークと通信できるようにします。

そのうえで、DBサーバーへアクセスするテストアプリを作成し、その通信のDBの監査ログから通信相手のIPアドレスを確認して、それがNAT Gwのものではないことを確認したいと思います。

# おことわり
App Service上のWebアプリとSQL Serverのプロビジョニング、DBのテスト用テーブルとその中身の作成については割愛させていただきます。


# サービスエンドポイントを構成する
SQL Serverを選択し、左のメニューからセキュリティの配下のネットワークを選択します。次に、右のペインのパブリックアクセスタブの仮想ネットワークのセクションで「仮想ネットワークルールの追加」をクリックします。そうすると右に仮想ネットワークルールを構成するタブが表示されますので、そこでサブスクリプションを選択し、App Serviceが統合されている仮想ネットワークとサブネットを選択して「OK」をクリックします。

![20231117-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2822136/823fd1e5-78f9-7966-6f68-6ef868480d6f.png)

簡単ですが、キモとなるのはここです。

# SQL ServerとDBの監査を構成する
まずはSQL Serverの監査を構成します。監査の記録は今回はストレージアカウントに保管することにします。ストレージアカウントを作成して書き込みができるように構成します。

SQL Serverの監査は、左のメニューのセキュリティの配下の「監査」から構成します。右のペインで「Azure SQL 監査を有効にする」のトグルスイッチをOnにします。続いて、監査ログの保存先としてストレージを選択して、サブスクリプションとストレージアカウントを選択します。ストレージ認証は今回はストレージアクセスキーを選択しました。

![20231117-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2822136/d0f13557-9e29-d745-f7d1-eee77aaf007e.png)

右ペインの上の保存を実行してSQL Serverの監査の構成は完了です。

つづいて、SQL DBの監査を構成します。SQL DBを選択し、左のメニューのセキュリティ配下の監査を選択します。右のペインで「Azure SQL監査を有効にする」のトグルスイッチをOnにして、監査ログの保存先のストレージアカウントを設定します。最後に右ペイン上の保存を実行します。

![20231117-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2822136/a3cbe658-4e50-b7f4-b674-bda703cb624a.png)

これで監査の準備が整いました。つづいて、テストアプリからDBにアクセスしてから監査ログを参照します。

# 監査ログを参照する
SQL DBを選択し、左のメニューのセキュリティ配下の監査を選択して、右ペインの上の監査ログの表示を選択します。

![20231117-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2822136/7411c0c2-ca6a-ff4a-6271-845ffbcef557.png)

すると監査レコードという画面に切り替わり、イベントのサマリが表示されます。しかし、ここで表示される内容だけではアクセス元のIPアドレスまでは分かりません。そこで、「クエリエディターで実行」をクリックして、より詳細な情報を確認したいと思います。

![20231117-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2822136/f2568335-587b-4ad1-cbb5-90842baa88af.png)

クエリエディターを起動するには認証が必要になります。Entra IDかSQL認証が選べます。認証をパスすると、Azure Portalでよく見かける形式のクエリとその実行結果の画面構成になります。しかもご丁寧にサンプルのクエリ文まで入力された状態です。今回はこのサンプルをそのまま実行することで、SQL DBへの接続元のIPアドレスまで確認することが出来ます。

![20231117-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2822136/72174df0-f8c6-c285-eb8f-60d0c8fe9bcb.png)

クエリを実行すると、監査ログが結果の下に表示されます。少し右にスクロールすると、`client_ip`の列があります。今回の目的は、Webアプリの送信元がNAT Gwではなくて、App Serviceの送信アドレスであることを確認することです。結果として、`client_ip`列にはApp Serviceの送信アドレスのうちのひとつが出力されていましたので、NAT Gwを通らず（外に出て行かずに）Microsoftネットワーク内で通信していることが確認できました。

ちなみに、監査したこと自体も監査ログに記録されます。そのことを実際に見せられれば、そうあるべきだよな、それが正しい姿だよな、とパッと分かるけれど、盲点でした。

なお、Webアプリの送信元アドレスは、Webアプリの左メニューの設定配下のネットワークを選択し、右ペインの送信トラフィックのセクションで確認できます。

![20231117-07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2822136/bd18b062-2159-b565-33f5-0499ab3744d9.png)

# 最後に
今回も、仕様としては、理屈としてはこうなっているはず、というのを確認してみました。ドキュメントをそのとおりきちんと読んで構築しているつもりですが、やはり実際に確認してみると納得感、安心感を得られます。

最後までお読みいただきありがとうございました。
NovelAIは何がすごかったのか？

# はじめに
こんにちは、たこらいすです。画像生成AIを利用して同人活動を行っています。
今回は「NovelAIは何がすごかったのか？」と題し、技術的な観点から解説を行います。
NovelAIは画像生成AIのStableDiffusionをファインチューニングし、アニメ風のイラスト作成に特化したものです。
2022年11月に公開され、現在までに250万人が利用しています。最近ではNovelAI Diffusion Anime V3が公開され、その高い品質が話題となりました。

NovelAIの技術的な改善点については”NovelAI Improvements on Stable Diffusion”という記事が、公式にMediumに投稿されています。
（参照:https://blog.novelai.net/novelai-improvements-on-stable-diffusion-e10d38db82ac）
本記事はこれを参考に解説したものです。

# 解説

#### CLIPの最後から二番目の層の隠れ状態の使用
CLIPはテキストと画像を扱うことができるマルチモーダルで、多くの画像生成AIに活用されています。
Stable DiffusionではCLIPの最後の隠れ層を用いて画像生成を行っていました。
しかし、[Imagen](https://arxiv.org/abs/2205.11487)では最終層ではなく、その一つ前の層、つまり最後から二番目の隠れ層を使用しています。この手法が良い結果をもたらすという意見が他にもあったため、NovelAIもこのアプローチを取り入れてトレーニングを行うことにしました。
結果としてよりプロンプトを解釈する能力が高まり、制御性が向上しました。
実際に、NovelAIはStableDiffusionやWaifuDiffusionなどのモデルと比較して、より直感的なプロンプト制御が可能になった印象があります。

#### Custom Batch Generation
StableDiffusionなどのモデルは正方形の画像を生成するようにトレーニングされているため、不自然な切り取りが多く発生します、例えば以下のように人間は頭部や、脚が欠けた状態で生成されてしまいます。また、本来のサイズである512×512のサイズと大幅に異なるサイズの画像を生成するとパターンの繰り返しが生じたり、小さいサイズの画像では識別不能な画像が生成されたりします。
この問題を解決するためNovelAIでは**Custom Batch Generation**という手法を用いて、様々なサイズの画像の学習を行いました。
custom Batch Generationは**aspect ratio bucketing**（アスペクト比バケッティング）という手法を用いている。aspect ratio bucketingは、画像を固定サイズにスケールして余白を追加する従来の方法ではなく、異なるサイズの画像をバッチ化して処理する手法です。
##### 1\. バケットの作成
幅を256から1024ピクセルまで64ピクセルずつ増やしながら、それに合った最大の高さを見つけてバケットを作成します。このとき、幅と高さの積が512x768ピクセルを超えないようにします。
##### 2\. 画像のバケットへの割り当て
各バケットの解像度をNumPy配列に保存し、各解像度のアスペクト比（縦横比）を計算します。
データセットの各画像についてもアスペクト比を計算し、最も近いバケットを選びます。
##### 3\. データセットの分割
複数のGPUで効率よく訓練するために、データセットを均等なサイズの部分集合に分割します。
##### 4\. 画像の処理
選ばれたバケットから画像を取り出し、バケットの解像度に合うように画像を調整します。このとき、画像のアスペクト比を保ちつつ、バケットの解像度に合わせてサイズを変更します。完全に合わない場合はランダムに切り取りを行います
##### 5\.バッチの要求
バッチが要求されると、重み付けされた分布からバケットをランダムに選び、その中から画像を取り出します。この重み付けにより、小さいバケットが早く空になりすぎるのを防ぎます。

#### トークン数の拡張
StableDiffusionnoのトークン数は75個のCLIPトークンに最初と最後のトークンを加えた77個でした。これはCLIPによる制限が原因です。
NovelAIではトークン数を3倍に拡張しました。
1\. プロンプトのバッチ内で最も長いプロンプトを見つけ、その長さを75の倍数に切り上げます。
2\. バッチ内の他の短いプロンプトは、最長のプロンプトと同じ長さになるようにCLIPの文章終了トークンで埋められます。
3\. バッチの合計長さが225トークンを超える場合、225トークンの長さに切り詰められます。
4\. その後、バッチは75トークンごとの個別のチャンクに分割されます。
5\. 各チャンクは個別にCLIPのテキストエンコーダを通過し、その結果は結合されます。

#### ハイパーネットワーク
ハイパーネットワークは、モデルの重み（パラメータ）を変更または生成することで動作します。NovelAIのハイパーネットワークでは、大きなネットワーク内の複数のポイントに小さなニューラルネットワーク（線形層または多層パーセプトロン）を適用し、隠れた状態を修正するというものです。
ハイパーネットワークによって、NovelAIはより複雑で詳細な「プロンプト」に基づいてテキストを生成できるようになっています。
GAS基礎の基礎の基礎

# はじめに
この記事は「[Ateam LifeDesign Advent Calendar 2023](https://qiita.com/advent-calendar/2023/ateam-life-design)」で完走賞を狙って25記事書いているうちの1日目の記事です。今年も完走目指して頑張るぞ！

# GASってなぁに？
GASとはGoogle Apps Scriptの略でGoogleが提供してるアプリケーション開発のプラットフォームです。ウェブブラウザ上で動作するので、開発環境構築せずともアプリケーションが作れるので便利。またGASを使うと、様々なGoogle製品上（GmailやGoogleカレンダー、スプレッドシートやドライブなど）で処理をおこなったり、それらサービスを連携させることが、とてもとても簡単にできます。またAPIを使って外部サービスとの連携や簡単なウェブアプリケーションを作って公開することもできます。

個人的に触ってて一番感動したのはウェブアプリケーションでした。感動ポイントはデプロイの容易さ。GASで作ったウェブアプリケーションは script.google.com 上にボタン一つでデプロイすることができます。なので自分で追加で公開用のサーバを用意する必要がないままアプリケーションを公開することが出来ます。もちろんいろいろ制限はありますが、でもほんとすごい。

それぞれ具体的にどんなものが作れるのか例をあげて紹介していきます。

## 具体例
### Google製品上でのスクリプトや製品同士の連携
- Googleフォームを使った予約システム。
    - 予約が完了するとメールが送信され、Googleカレンダーに登録される。
    - また予約が埋まった枠はフォームから選択肢として削除される。
- スプレッドシートを使った在庫管理システム。
    - シート管理してる商品の中で在庫が一定数以下になったらメールでアラートを送信。


### 外部サービスとの連携
- スプレッドシートに記載されたURLリストへスクレイピングをして実行結果をシートに記述
- GASとLINEのMessagingAPIを連携し簡単なチャットボットの作成
- スプレッドシートに記載された内容を定期的に確認し、不備があれば担当者へSlackで通知する
- Googleフォームで回答された内容をトリガーに、一定の条件だった場合のみSlackで通知する

# 作り方
それでは実際にGASに触れていきましょう。
GASには「コンテナバインド型」と「スタンドアロン型」の2種類の作り方があります。
コンテナバインド型はGoogle製品（スプレッドシートやドキュメントやフォームなど）に紐付けて作る方法、スタンドアロン型はそれらとは完全に独立してスクリプトだけを切り離した作り方です。スタンドアロン型の場合はライブラリとして切り出して他のスクリプトから共通して呼び出すという使い方もできます。

:::note warn
基本的に双方大きな違いはありませんが（使えるメソッドが若干異なる程度）
コンテナバインド型の場合は、スクリプトの書かれたGoogle製品を共有すると一緒にスクリプトも共有されてしまうため、スクリプトを隠しておきたい場合はスタンドアロン型を選択するほうが良いです。
:::

## コンテナバインド型の作り方
まず紐づけを行いたいGoogleサービスを開いて（今回はスプレッドシートを例にあげます）「拡張機能内」から「Apps Script」を選択します。

![スクリーンショット 2023-11-16 22.30.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200812/8ee41bbf-8e64-f8d6-46b9-db3a86285d9c.png)


すると、エディタが出てくるのでここにコードを記述していきます。

![スクリーンショット 2023-11-16 22.29.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200812/7454e2d2-98c3-4eb7-3d34-660cf44d636a.png)



## スタンドアロン型の作り方
Googleドライブにアクセスし、左上の「新規」ボタンをクリック。「その他」から「Google Apps Script」を選択します。
![スクリーンショット 2023-11-16 22.25.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200812/91ef5344-ea41-0232-e2d7-cb79943d0e08.png)

コンテナバインド型同様、エディタが出てくるのでここにコードを記述していきます。

![スクリーンショット 2023-11-16 22.29.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200812/7454e2d2-98c3-4eb7-3d34-660cf44d636a.png)

## とりあえず Hello World　しておく

まずはエディタにスクリプトを記述し保存アイコンをクリック。

```javascript:
function myFunction() {
  Logger.log("Hello World");
}
```

![スクリーンショット 2023-11-16 22.37.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200812/c55819c5-91d7-61de-51f7-787a0e3a9af8.png)

「実行」を押すと無事にHello World完了。

![スクリーンショット 2023-11-16 22.37.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200812/6312f75d-68a7-91fe-889a-43a9e695a715.png)

# 最後に
いかがでしたか？なんか簡単にいろんなものが作れそうっていうのが伝わるといいなと思います。
明日はGASを使う上で比較的よく利用するセルの操作について見ていこうと思います。
ハスケル子「それ、f-string(f文字列)使ってみたらどうですか？」

# お仕事中ワイ

ワイ「ちょいちょい、ちょいっと！」
ワイ「あっ」
ワイ「ま～た読みずらいコードを錬成してしまったで」
```python
def format_name(last: str, first: str, kana_last: str, kana_first: str) -> str:
    return last + " " + first + " (" + kana_last + " " +  kana_first + ")"
```
ワイ「↑なんで文字列の結合って」
ワイ「整形後がどうなるかパッと見でイメージしずらいんやろな～」

ハスケル子「**それ、f-string(f文字列)使ってみたらどうですか？**」

ワイ「ファッ！？」
ワイ「えくすとりーむ！！？」

ハスケル子「ちょっと何言ってるかわかんないです」

ワイ「せやな」
ワイ「ほんで、なんやったっけ？」

# f-string(f文字列)とは

ハスケル子「f-string(文字列)です」
ハスケル子「`Python3.6`で導入された機能で」
ハスケル子「文字列に変数や式の結果を展開してくるものです」

ワイ「ふむふむ」
ワイ「ちょっとようわかれへんけど」
ワイ「文字列の整形が見やすくなるってこと？」

ハスケル子「そうですね」


# f-string(f文字列)に書き換えてみる

ハスケル子「例えば、さっきのコードは――」
```diff_python
def format_name(last: str, first: str, kana_last: str, kana_first: str) -> str:
+    return f"{last} {first} ({kana_last} {kana_first})"
-    return last + " " + first + " (" + kana_last + " " +  kana_first + ")"
```
ハスケル子「↑こんな風に書き換えることができますね」

ワイ「おお、なんかめっちゃ見やすくなったで！」

ハスケル子「ですよね」
ハスケル子「文字列リテラルの前に`f`または`F`を付けてあげて」
ハスケル子「変数を展開したい位置に`{変数}`って書いてあげるんです」

ワイ「なるほどな」
ワイ「ん？そういえばさっき」

> ハスケル子「文字列に変数や**式の結果**を展開してくるものです」

ワイ「↑こう言ってたってことは――」
```python
print(f"1 + 2 + 3 = {1 + 2 + 3}")
```
ワイ「↑こんなんとか」
ワイ「それから――」
```python
def format_name(last: str, first: str, kana_last: str, kana_first: str) -> str:
    return f"{last} {first} ({kana_last} {kana_first})"

print(f"ワイは{format_name('豆蔵', '太郎', 'マメクラ', 'タロウ')}と申しますやで！")
```
ワイ「↑こんなこともできるってこと？」

ハスケル子「ですね」
ハスケル子「ただ、先輩の理解が珍しく良いので心配になってきました」
ハスケル子「今日はもう帰ってゆっくり休んでください」
ハスケル子「お疲れ様でした」

ワイ「いや、失礼やろ！」


# まとめ

文字列の整形は`f-string(f文字列)`で可読性を高められる

ワイ「↑ってことやな！」

ハスケル子「ですね！」

**〜おしまい〜**

# おまけ

他の言語にも似たものがある
AI-102試験対策のまとめ「スマートトリミングされたサムネイルの作成」

## はじめに
Azure AI Engineer Associate(AI-102)取得に向けた勉強でまとめた内容を本記事では投稿しています。
試験範囲の内容を私が勉強していく中で、
・忘れてしまっていた内容
・他の知識と絡めて理解した方が良い内容
・Microsoft Learnの読解に苦戦した内容
などをできるだけ分かりやすく簡潔にまとめることを意識しています。
Azureの勉強を一から始め、AI-102取得を目指している方の参考になれば幸いです。
※本記事の内容が必ず試験に出るわけではないこと、ご注意ください
※勉強しながら投稿しているため、追加で学んだことがあれば随時投稿内容を更新します。

## 試験対策のまとめ
### スマートトリミングされたサムネイルの作成
* Azure AI Vision APIではスマートトリミングを使用してサムネイルを作成可能
* 画像内の主な被写体が写っている領域(関心領域)を識別し、それに基づいて画像をトリミングする

#### **サムネイル生成APIの呼び出し**
1. 下記のコマンドを用意
```Bash
curl -H "Ocp-Apim-Subscription-Key: <subscriptionKey>" /
-o <thumbnailFile> /
-H "Content-Type: application/json" /
"https://westus.api.cognitive.microsoft.com/vision/v3.2/generateThumbnail?width=100&height=100&smartCropping=true" /
-d "{\"url\":\"https://learn.microsoft.com/azure/ai-services/computer-vision/media/quickstarts/presentation.png\"}"
```
2. 必要に応じて、コマンドに次の変更を追加
    1. `<subscriptionKey>`の値をキーに置き換え
    1. `<thumbnailFile>`の値を、返されたサムネイル画像を保存するファイルのパスと名前に置き換え
    1. 要求URL(`westus`)の最初の部分を独自のエンドポイントURL内のテキストに置き換え  
    ※2019年7月1日以降に作成された新しいリソースでは、カスタムサブドメイン名が使用される
    1. 必要に応じて、要求本文の画像URL(`https://learn.microsoft...`)をサムネイルの生成元である別の画像のURLに変更
3. コマンドを貼り付けて実行

* 参考
    - https://learn.microsoft.com/ja-jp/azure/ai-services/computer-vision/concept-generating-thumbnails#examples
    - https://learn.microsoft.com/ja-jp/azure/ai-services/computer-vision/how-to/generate-thumbnail

## 次の試験対策のまとめ
* **AI-102試験対策のまとめ「Custom Visionプロジェクトの移動」**

https://qiita.com/fsd-jume/items/26096f2a5c1d4dadd5d7

## 学習内容をまとめたページの一覧

https://qiita.com/fsd-jume/items/65aba5d5514e023fd66d
LeetCode 22. Generate Parentheses

問題は[こちら](https://leetcode.com/problems/generate-parentheses/description/?envType=study-plan-v2&envId=top-100-liked)
難易度はmedium
# 問題概要
n組の括弧が与えられたとき、整った括弧の組合せをすべて生成する関数を書きなさい。

整う、とは左から読んでいく時に、左括弧 "(" が常に右括弧 ")" よりも多いか同じだけあることである。

>Example 1:
>>Input: n = 3
>>Output: ["((()))","(()())","(())()","()(())","()()()"]

>Example 2:
>>Input: n = 1
>>Output: ["()"]

# 答え
```
class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        def generate(p, left, right, parens=[]):
            if left:
                generate(p + '(', left-1, right)
            if right > left:
                generate(p + ')', left, right-1)
            if not right:
                parens += p,
            return parens
        
        return generate('', n, n)
```
generate()は再帰関数。leftとrightが０になるまで呼ばれる。
p: 答えとなる括弧の文字列の一つ。関数が呼ばれるたびに右か左の括弧をひとつ付け足す。
left: 使わなければならない残りの左括弧の数。
right: 残りの右括弧の数。関数が呼ばれるたびleftかrightのどちらかがひとつ減る。
parens: 最終的に答えとなる答えのリスト。leftとrightの両方が０になった時のpが追加される。

例えば括弧が２組の時、最初に引っかかるのはif leftだけなので
>generate( '(', 1, 2 ) 

が呼ばれる。

generate( '(', 1, 2 )の次は if left と if right > left に引っかかるので
>generate( '((', 0, 2 )
>generate( '()', 1, 1 )

が呼ばれる。


# コード改良
```
class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        def generate(p, left, right):
            if right == 0:
                yield p
                return

            if left > 0:
                yield from generate(p + '(', left - 1, right)

            if right > left:
                yield from generate(p + ')', left, right - 1)

        return list(generate('', n, n))
```

一応yieldも使える。意味はあるのだろうか？
画面フローでの数式


# SUBSTITUTE

+ [SUBSTITUTE in screen flow with reactive input only substituting one of a character.](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007QeadvSAB)

複数の値がマッチしても、１つしか置換されないらしい。

+ [既知の問題:Formula Variable in Flow using Substitute function not working with special characters as field value](https://issues.salesforce.com/issue/a028c00000j5kUbAAI/formula-variable-in-flow-using-substitute-function-not-working-with-special-characters-as-field-value)


+ [Salesforce Flow で使用可能なすべての数式を探す方法](https://automationchampion.com/2023/05/16/list-of-all-available-formulas-for-salesforce-flow/)
[備忘録] Cudaについて

# cuda入れようと思ったけどかなり苦戦した

機械学習系のことをやるためにcudaを入れようとしたらかなり苦戦したときのTipsまとめ．

まず大前提としてcuda入れるときの手順は
- nvidia関連（もちろんcuda含む）のドライバを全部消す．
- cudaインストール

という感じで最初に既存の環境を完全に削除しないとめんどくさいことになる．
そして僕の場合グラボ付きのノートPCでやってたんで RTX3060シリーズなんですけど，ドライバの自動インストールされたときの番号が違ってて混乱したのもあってめんどくさいことをしてしまっていました．

## nvidia関連の削除

コマンドは↓
```bash:uninstall nvidia-driver and cuda
sudo apt-get --purge remove "*cuda*" "*cublas*" "*cufft*" "*cufile*" "*curand*" \
 "*cusolver*" "*cusparse*" "*gds-tools*" "*npp*" "*nvjpeg*" "nsight*" "*nvvm*"
sudo apt-get --purge remove "*nvidia*" "libxnvctrl*"
sudo apt-get autoremove
```
ここのコマンドは[公式ページ](https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#removing-cuda-toolkit-and-driver)から引っ張ってきてます．

他にも簡略化されたコマンドが出回ってましたが，なんかエラーはいて進めなくなってたので公式のこれが一番確実だとは思います．

ちなみにどんなエラーをはいていたかというと，
[このサイト](https://askubuntu.com/questions/1062171/dpkg-deb-error-paste-subprocess-was-killed-by-signal-broken-pipe)に書いてあるようなエラーでオーバーライトできないにゃといった内容のもの．解決策もサイト内に書いてありますが一応メモ↓
```bash:solution
sudo dpkg -i --force-overwrite /var/cache/apt/archives/"エラーでオーバーライトできないって言われた.debファイル" # 例：nvidia-340_340.107-0ubuntu0~gpu18.04.1_amd64.deb
sudo apt -f install
```
このへんまでやったら一回reboot．

## cudaのインストール

この記事を書いたときの最新は12.3だったのでそれのコマンドを掲載しとく．
バージョン指定したいときは最後のcuda-toolkit-12-3の数字を好きなバージョンに変えればよし．
一応[バージョン12.3の公式](https://developer.nvidia.com/cuda-downloads?target_os=Linux&target_arch=x86_64&Distribution=Ubuntu&target_version=22.04&target_type=deb_network)（自分のインストールしたいバージョンのページを参照することをおすすめする．）
```bash:install cuda12.3
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb
sudo dpkg -i cuda-keyring_1.1-1_all.deb
sudo apt-get update
sudo apt-get -y install cuda-toolkit-12-3
```
これでインストールするとnvidiaのドライバも自動でインストールされる．
一応この手順でエラーを出さなければcudaのインストールはできてるはず．

確認用のコマンドは↓
```bash:nvcc version
/usr/local/cuda/bin/nvcc -V #バージョン確認

nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2023 NVIDIA Corporation
Built on Mon_Apr__3_17:16:06_PDT_2023
Cuda compilation tools, release 12.1, V12.1.105
Build cuda_12.1.r12.1/compiler.32688072_0
```
私の場合12.1が入ってるのがわかります．いちいち/usr/local...とか打ちたくないならパスを通してください．

## おまけ（PyTorchでちゃんと認識できてるかの確認）

私はPyTorchでcudaを使いたかったのでインストールしたので，ちゃんとそっちから認識できるか確認．仮想環境を立ち上げてから下のコマンドで認識できてるかわかる．
```bash:cuda check
>>>import torch
>>>print(torch.cuda.is_available())
#True
```

Pythonの仮想環境に関しては[こっち](https://qiita.com/yatapark/items/3e7b39db69485122593b)で説明してるので良ければ．
Set Up Case Escalation and Entitlements


[Set Up Case Escalation and Entitlements](https://trailhead.salesforce.com/content/learn/projects/set-up-case-escalation-entitlements)

# Enable Entitlements and Set Up Service Contracts

+ [Set Up Case Escalation and Entitlements Create Service Contracts with Entitlements](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000OpyMxSAJ)
+ [Create Service Contracts with Entitlements](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007Pi6i4)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/5ec643a3-6844-bed6-2d19-78fbdf27125f.png)


:::note
It looks like this is an on-going issue, since Jan 2023. See here - It's not updating the page layouts for the Cases, that we did in the first section of the module. There's no true resolution. https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000OpyMxSAJ
:::


# Create an Entitlement Process

+ [Support Levelがない](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007XISG3)

:::note
Did you follow the instructions below to create the field?
 
https://trailhead.salesforce.com/content/learn/projects/set-up-case-escalation-entitlements/create-entitlement-process

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/9160343e-2a7a-bb62-38e6-d6aa4b7e5b81.png)
:::

+ [Create Support Processes](https://trailhead.salesforce.com/ja/content/learn/projects/set-up-case-escalation-entitlements/create-support-processes-cases)

+ [新しいサービス契約を保存しようとすると、なぜ保存ボタンが表示されないのかわかりません。](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V000078QnlV)

:::note
I checked in other playground and it works.
:::
JavaScript 配列




## 配列の初期化
```
result = [];
```

```
var result = [];
```

```
let result = [];
```

```
const result = [];
```


## 配列の要素取得

```
result[インデックスの値]
```

## 配列に、値の追加格納

```
result.push(格納したい内容)
```
mongodbのトランザクション対応でハマった

ローカルホストでmongodbのトランザクションを使いたいってなったら、レプリカセットを設定しないとダメで、下記のように設定した。

```
version: '3.8'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/usr/src/app
      - /usr/src/app/node_modules
    depends_on:
      - mongodb
    environment:

  mongodb:
    environment:
      - AUTH=no
    command: [--replSet, my-replica-set, --noauth, --bind_ip_all]
    build:
      context: .
      dockerfile: ./docker/mongodb/DockerFile
    ports:
      - "27017:27017"
    volumes:
      - mongodb_data:/data/db
      - ./docker/mongodb/init/db_init.js:/db_init.js
    restart: always
  mongo-express:
    image: mongo-express
    container_name: mongo_express
    restart: always
    ports:
      - "8081:8081"
    environment:
      ME_CONFIG_MONGODB_SERVER: mongodb
    depends_on:
      - mongodb

volumes:
  mongodb_data:
```

```
# テスト用データベース
TEST_DB_URI=mongodb://localhost:27017/lifelogAppTest
```

```
FROM mongo:6.0.6
# エントリーポイントスクリプトを追加
ADD mongo_docker_entrypoint.sh /entrypoint.sh
EXPOSE 27017
# エントリーポイントを設定
ENTRYPOINT ["/entrypoint.sh"]
```

```
#!/bin/bash
# MongoDBを起動
mongod --replSet my-replica-set --noauth --bind_ip_all &

# MongoDBが起動するのを待つ
echo "Waiting for MongoDB to start..."
sleep 10

# initスクリプトを実行
mongosh /db_init.js

# コンテナが終了しないように待機
wait
```

上記だと、dockerネットワーク内ではうまくいくが、レプリカセットを設定するときにdockerネットワーク内の名前で指定しちゃってるので、dockerネットワーク外からlocalhost指定で繋げないってことが起こった。それで外からyarn testで繋げなくて落ちる。

それでtestのたびに
```
docker-compose upの状態で
$ docker exec -it habitt-api-app-1 /bin/sh
で中に入ってから
yarn test
```
をやってる。


```
$ docker exec -it container-mongodb-1 /bin/sh
で、mongoshしてから
var rsconf = rs.conf();
rsconf.members[0].host = "localhost:27017";
rs.reconfig(rsconf, { force: true });
```
すると、docker-compose外からでもいけるけど、またmongodb:27017に戻さないとダメ。
もっとうまいやり方があったら教えてほしい。
ZTNet で ZeroTier を Self Hosting する

## この記事の目的

reddit の [selfhosted](https://www.reddit.com/r/selfhosted/) スレッドを見ていたら、
[ZeroTier](https://www.zerotier.com/download/) の使い勝手を格段に向上させる[ツール](https://github.com/sinamics/ztnet)を見つけたため紹介します。

## [ZTNet](https://github.com/sinamics/ztnet) でできること

- 自前の(self hosting)server で ZeroTier が使用できるため、何端末でも無料で使用できます。([非商用の場合](https://docs.zerotier.com/pricing/#basic))  
  (ZeroTier 公式の [ZeroTier Central](https://my.zerotier.com/) を使った場合、非商用でも無料で使えるのは 👉 10 端末まで)
- 端末リストのソートがとても簡単。🎉  
  (ZeroTier Central では端末名と端末 ID でしかソートできませんが、ZTNet では端末名、IP アドレスなど表示されている全ての項目でソートができます。)

## ZeroTier/ZTNet のユースケース

正直、逸般の誤家庭でない限り、[Tailscale](https://tailscale.com/) で十分だと思います。

ただし、[flash RAM が 16MB しかないような OpenWrt 端末では Tailscale をインストールするのは不可能](https://openwrt.org/docs/guide-user/services/vpn/tailscale/start#installation_on_storage_constrained_devices)なこと、  
Docker 運用している [Prometheus](https://hub.docker.com/r/prom/prometheus) や、[Portainer Agent](https://docs.portainer.io/admin/environments/add/docker/agent) では、Tailscale の IP アドレスやホスト名は使えないため、  
このような場合は [ZeroTier](https://www.zerotier.com/) を使用しています。

OpenWrt 機器を含め、多くの機器がネットワーク上で動作していて、それらを NAT 越しで接続する必要がある場合、是非 [ZeroTier](https://www.zerotier.com/) / [ZTNet](https://ztnet.network/category/installation) を試してみてください。

## 補足 1: ZeroTier の OpenWrt へのインストール方法

https://openwrt.org/docs/guide-user/services/vpn/zerotier

https://www.freeshell.de/~pcfreak/mdwiki/#!content/linux-generic/zerotier/zerotier-layer3-routing-openwrt.md#Configure_the_routing_within_OpenWRT/LEDE

https://github.com/mwarning/zerotier-openwrt/wiki

## 補足 2: ZeroTier と Tailscale の比較

Tailscale による資料です。

https://tailscale.com/compare/zerotier
【WebSpeechAPI】Siriに無視されるので『活舌強化アプリ』つくりました。

# オタクは早口
私は、オタク特有の早口に加え、活舌が悪い。
Siriにも3回に1回くらい無視されている。くやしいよ私。
**『活舌（かつぜつ）強化アプリ』で特訓して見返してやりたい。**

# どんなのつくろう
:::note info
【目標】早口言葉使って活舌を鍛えられるアプリをつくりたい。
　■ 発話を聞き取り、言えているかどうかを判定してほしい（Web Speech API）。
　■ スマホの振動を感知し、イライラ度を表現したい（Web Sensor API）。
:::

# 技術・環境
Vue.js（JavaScriptライブラリ）
Web Speech API（発話の聞き取り）
Web Sensor API（スマホの加速度を取得）
Bootstrap（Web制作サポートツール）
CodePen（アプリ制作環境）
Netlify（完成アプリ公開環境）

# これで私も「立て板に水」
紹介動画をご覧ください。

https://twitter.com/xe_ay51938/status/1726380509117522251

##  詳しくはこちら
### CodePen
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="XWOVyqw" data-user="XE-AY" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/XE-AY/pen/XWOVyqw">
  【HW】活舌強化アプリ</a> by XE-AY (<a href="https://codepen.io/XE-AY">@XE-AY</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>


### Netlify
PCでも動作しますが、スマホがおすすめです（Android推奨）。
**【お題：上級編】にも、ぜひチャレンジしてみてください！おまけがあります！**

https://6558a4253b89145a07e541b4--stellular-torte-56f576.netlify.app/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3563752/6f71a3b0-59e3-153c-2ae6-d01f2bd7eeda.png)

# 言えてた、完全に言えてた
Web Speech API初体験だったが、それっぽいものができた。楽しい！

今後の課題としては以下。
* お題の早口言葉をランダム表示にしたい（もっとバリエーションが欲しい）
* イライラ度によって「落ち着いて！」などのメッセージを出したい

これで繰り返しトレーニングすれば、もっと流暢に話せるようになるはずだ。
**ちなみに、Siriにはまだ2回に1回くらい無視されている。**