OmniAICreator/Qiita-1.07M huggingface dataset:
cloudflare tunnelで自宅サーバー（動的IP）を運用したい、しかもdocker composeで

# 問題

- ドメインは持っている
- サーバー借りると高い
- 自宅サーバーなら電気代だけだ
- 動的IPなので、IP変わるタイミングが怖い
- ルーターのポートを開けたくない

# 解決

CloudflareのZero Trustの機能の一部であるtunnelをつかう。

https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/

## 簡単な流れ

Cloudflare提供のCloudflare間との直接接続ができるソフト（`cloudflared`）を自分のサーバー側に入れる。この接続ソフトにより通信が保たれる。
Cloudflareに登録済みのドメインにおいてサブドメインを指定し、このサブドメインでの接続はCloudflareから直接サーバーへ通信が発生してルーターへのポートフォワード設定等なしにデータが送受信できる。

### ざっくりとした流れ

![Untitled-2024-04-26-1623.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16757/b0e9f41b-1db9-ecd2-8906-08aab3d67581.png)

### docker compose内

![zUntitled-2024-04-26-1623.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16757/84a77b90-d357-b3a3-3f14-7db6592cd87a.png)

# 設定の仕方

流れはここを見れば大抵分かるが、

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


1. まずはドメインを持っていること
1. Cloudflareにそのドメインを設定し、ドメインのDNSをCloudflareのものにすること（無料で出来る）
1. CloudflareのZero Trustを別で登録（無料で出来る）
1. Tunnelの設定をする（この過程でdockerの設定がある）

> このtunnelサービスを使うにあたってCloudflareに支払いを行うことはない

![Screenshot 2024-04-26 at 16.39.24.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16757/8daa4c6e-a534-2a29-9102-91f7167adeb6.jpeg)

docker composeでやるので、ここで表示されるdockerコマンドは実行せずにtokenの部分だけをコピーして下のようなdocker-compose.ymlに設定する。

```yml:docker-compose.yml
services:
  frontend:
    image: YOUR_OWN_IMAGE
    restart: unless-stopped

  tunnel:
    image: cloudflare/cloudflared
    restart: unless-stopped
    command:
      - tunnel
      - --no-autoupdate
      - run
    environment:
      - TUNNEL_TOKEN=TOKENTOKENTOKENTOKENTOKENTOKEN
```

ここで言う`frontend`は何でも良くて、同じcompose内での通信なので`ports`の項目もなくて良い。
例えばfrontendがnextjsで3000番ポートで通信を待っている状態でも

```yml
  frontend:
    image: YOUR_OWN_IMAGE
    restart: unless-stopped
    ports:
      - 3000:3000 # しなくていい！！！！！
```

とかしなくていい。tunnelサービスからfrontendサービスへはそのまま繋がる。

![Screenshot 2024-04-26 at 16.43.01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16757/918f177c-d5d3-2002-870e-8b016d2c0dbc.jpeg)

ここで重要なのは

- サブドメインは自分が指定したいもの
- ドメインは自分が持っているものを選択

で当たり前だが、serviceの`Type`と`URL`はcompose内での事を書かないといけない。

compose内のtunnelサービスがcloudflaredであり、これがCloudflareと通信している。そして`サブドメイン`.`ドメイン名`と通信が来た時に、このサービスから見てどこにつなぎたいかを設定する。

ここでは`frontend`へはtunnelサービスからみて`http://frontend:3000`で繋げられるので、そのように`Type`と`URL`を設定する

- Type => HTTP
- URL => frontend:3000

* 動画では`No TLS Verify`を選択しているが、`Type => HTTP`なのでその設定はない

# 結果

と、これだけで自宅サーバーをいきなり公開できる。
[1.20.4]Spigot Pluginで「水ブロック」がクリックされたことを検知する

# 結論
```kotlin:kotlin
    @EventHandler
    fun onPlayerInteract(event: PlayerInteractEvent) {
        if (event.action != Action.RIGHT_CLICK_AIR && event.action != Action.RIGHT_CLICK_BLOCK) return
        val block: Block? = player.getTargetBlockExact(5, FluidCollisionMode.SOURCE_ONLY)
        if (block != null && block.type == Material.WATER) {
            //ここに処理
        }
    }
```

# 詳細
ガラス瓶で水を汲んだことを検知しようとした際に発生。
`PlayerInteractEvent.clickedBlock()`では水が検知できない。

代替手段として、`getTargetBlockExact()`を使用。

用意された関数通りの使い方をしているので詳細はJavaDocに任せる
- [LivingEntity.getTargetBlockExact()](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/LivingEntity.html#getTargetBlockExact(int,org.bukkit.FluidCollisionMode))
- [FluidCollisionMode](https://hub.spigotmc.org/javadocs/spigot/org/bukkit/FluidCollisionMode.html#enum-constant-summary)

最大距離は4だと検知漏れがあった。

`CauldronLevelChangeEvent`とか`PlayerBucketEvent`とかはあるのに`PlayerGrassBottleFillEvent(仮称)`がないのはなんで...
選択したファイルの場合はどこから利用できるんだろうか？


「選択したファイルの場合」をトリガーにしてフローを作ったのですが...

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/2076a77f-25da-a59a-4525-0b9cee8ea21d.png)


さて、この腐っているシステムですがどこから起動できるんだろうか？
SharePoint Online のファイルを指定して右クリックしても、リストの時みたいにフローが出てこないですね。

本当にみんな使いこなしている？　何かやるたびに確実に動きません。　本当、できたら使いたくないわ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/ce453ed9-6a5a-fae5-80d4-5ae20df6a415.png)


# 自働化なんてないよ！！！

https://blog-tips.sekenkodqx.jp/2023/11/21/power-automate-trigger-for-a-selected-file-sharepoint/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/5a122bbc-5bd3-4ba1-8f3a-caaf601a4237.png)

# 本当か？

関係ないと思いつつ、すべて表示をクリックして自動化を触ってみる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/28dd4cbd-314e-4bc0-bd97-61d19d5cdc62.png)

実際には意味ないけどルールをポチポチしてみる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/2b73dcc7-bf71-46f2-a69c-3089e3cbaa8e.png)


おお、なんかメニューが増えた。どうなってるの？この腐ったシステムは...

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/a06fe8bc-bd48-4ed3-8f59-c2d80d134f9d.png)

https://support.microsoft.com/ja-jp/office/%E3%83%AA%E3%82%B9%E3%83%88%E3%81%BE%E3%81%9F%E3%81%AF%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%82%92%E8%87%AA%E5%8B%95%E5%8C%96%E3%81%99%E3%82%8B%E3%83%AB%E3%83%BC%E3%83%AB%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B-151ea008-7fa6-409b-b0bd-b04a3b3cacd5
デバッグのやり方

## デバックのやり方
1. ログに出す
2. 画面に出力する
3. コンソールに出す
4. Symfonyのツールバーを使う





### 1. ログに出す
```php
$startDateTime = new \DateTime();

log_info('$startDateTime',[$startDateTime]);
// $startDateTime ["2024-04-16T06:30:00+09:00"]
```
→Entity等のオブジェクトは出力できない（省略して表示される）ので注意

### 2. 画面に出力する
```var_dump();```
→Entity系を出力するとリレーション系も大量に出力されるので要注意

```dd();``` / ```dump(); die();```
※ ddはdump and dieの意

### 3. コンソールに出す
js系のログは```console.log(文字列);```を使用する
```js
$.ajax({
        url: '{{ url('recommend', {'type': 1}) }}',
        type: 'GET',
    }).done(function(data) {
        console.log('Success');
        // 成功した時の処理
    }).fail(function() {
        console.log('Failed');
    });
```
#### コンソールの確認方法
Google Chromeの検証ツールを使用
※ 右クリックで「検証」選択 or F12押下

### 4. Symfonyのツールバーを使う
以下の設定が必要
```.env
APP_ENV=dev
APP_DEBUG=1
```
⇒devよりprodのほうが早い


※ 表示されない場合：app/config/eccube/packages/dev/に以下を配置
```web_profiler.yaml
web_profiler:
    toolbar: true
    intercept_redirects: false

framework:
    profiler: { only_exceptions: false }
```
【Next.js】Vercelにデプロイ時のビルドエラー

## 内容

モダン開発を学び始めて半年の駆け出しフロントエンドエンジニア志望の者です。

今回、3ヶ月ほどかけて開発してきたアプリをデプロイしまして、
エラーがちょこちょこ発生したため、解決した手段を記述しておきます。


## 【1つ目】 Cannot find module エラー

Next.jsでローカルではビルド成功するのに、Vercelで"Type error: Cannot find module"が発生しました。

> Type error: Cannot find module '@/components/{コンポーネント名}' or its corresponding type declarations.


### 原因

原因は、下記2点が考えられました。
* importパスの大文字小文字が誤っている
* 過去にファイル名を修正したキャッシュが残っている


importパスに誤りはなかったので、gitのキャッシュが考えられました。

VercelにデプロイするGitHubのリモートリポジトリは、
ファイル名の大文字小文字変更を拾ってくれないみたいです。（設定次第でなんとかなるらしい）

ファイル名の変更が反映されていないままになっているため、エラーになったと考えられました。


### 解決方法
もっといい方法があるのかもしれませんが、
ファイル名を変更した可能性が高そうな src/pages, src/components の
ディレクトリごと削除、再度pushしました。

※ rm する前に それぞれバックアップは残してください
```
git rm -r src/pages/
git rm -r src/components/
git push
```

復元して再push

```
git add .
git commit -m "復元して再push"
git push
```


## 【2つ目】 ReferenceError: localStorage is not defined エラー

localStorage を使用した場合に起こりました。
クライアントサイドで使用する場合は、条件付きで使用しないと怒られちゃうみたいです。
（ブラウザのWebストレージ機能なのだから、そりゃそうか）

### 解決方法

クライアントサイドであることを確認し、ブラウザ環境でのみ localStorage を操作するように、と修正しました。
これで、サーバーサイドでのエラーを回避できます。

```
if (typeof window !== 'undefined') {
 const item = localStorage.getItem('key')
}
```


これで無事デプロイできました！

ビルド時のエラー無視の方法（Typescriptの型エラーとか）も設定次第でできそうですが、
どれくらいの設定なら許容なのだろう。。とりあえず今回はやりませんでした。


次は、作成したアプリについてまとめようと思います！
データベースで共通の属性を使い回すときのテーブル設計方法

素人につき用語の誤りや分かりづらい記述がありましたら申し訳ございません。

appsheetというノーコードツールで売上管理データベースを作ってみようとしているのですが、テーブル設計（データモデリング？）で疑問があり質問させていただきます。

例えばある商品を仕入れて販売するまでの情報をデータベース化したいと考えたとします。
するとモノの流れに応じて「商品マスタ」テーブルや、「発注管理」テーブル、「入出庫管理」テーブル、「売上管理」テーブルなどが必要となると思いますが、商品に色やサイズ（SKU)があり、一部の色やサイズだけ発注されたり、入出庫が分割される可能性がある場合は、それぞれのテーブルに紐づくSKU単位の詳細テーブルを作って管理することになると思います。
その場合、”色”や”サイズ”という属性は別途「SKUマスタ」とテーブルを作って格納、各詳細テーブルはそれを参照することにすればいいと思うのですが、こういう場合は各々の詳細テーブルがそれぞれ「SKUマスタ」テーブルを参照するようにするのか、例えば「商品詳細マスタ」テーブルが「SKUテーブル」を参照し、「発注管理商品詳細」テーブルは「商品詳細マスタ」テーブルを参照、「入出庫管理詳細」テーブルは「商品詳細マスタ」テーブルを参照…という感じに段階を追って参照していくようにしたほうがいいのか、どちらがいいのでしょうか？ あるいはどちらでもいいのでしょうか？
結果は同じだと思うのですが、各テーブルが各々参照したほうが早そうな遅そそうな…。



（各詳細テーブルが直接SKUマスタを参照する場合）

「商品マスタ」→「商品詳細マスタ」←「SKUマスタ」
　　↓
「発注管理マスタ」→「発注管理詳細マスタ」←「SKUマスタ」
　　↓
「入出庫管理マスタ」→「入出庫管理マスタ」←「SKUマスタ」
　　↓
「売上管理マスタ」→「売上管理マスタ」←「SKUマスタ」


（商品マスタだけがSKUマスタを参照する場合）

「商品マスタ」→「商品詳細マスタ」←「SKUマスタ」
　　↓
「発注管理マスタ」→「発注管理詳細マスタ」
　　↓
「入出庫管理マスタ」→「入出庫管理マスタ」
　　↓
「売上管理マスタ」→「売上管理マスタ」
*他の詳細マスタテーブルは矢印を遡って「SKUマスタ」を参照する。


よろしくお願いします。
Python文法まとめ【if】

# はじめに
Pythonの基礎的なことをまとめています。
Google Colabで実行できます。
[Colabの使い方(Python.jp)](https://www.python.jp/train/experience/colab.html "Python.jp 入門講座")

# 条件分岐
~~~Python:サンプル
number = 5

if number % 2 == 0:
  print('偶数です。')
else:
  print('奇数です。')
~~~
変数`number`が偶数か判定するコードです。

~~~
if 条件式:
  処理
~~~
が基本形です。

`%`は計算結果の`あまり`を返します。
`==`は、左辺と右辺が等しいかどうかを判定します。

# おわり
お役に立てたら幸いです。
ActiveModel::ForbiddenAttributesErrorの解決法

## はじめに
Railsアプリケーションにおいて、`ActiveModel::ForbiddenAttributesError`が発生するという問題に直面することがあります。これはストロングパラメータが適切に設定されていない場合によく起こります。本記事では、このエラーの解決方法をQ&A方式で紹介します。

---

### Q1: エラーの内容は？
A1: `ActiveModel::ForbiddenAttributesError`は、許可されていないパラメータをマスアサインメントしようとした際にRailsが発するエラーです。

### Q2: ストロングパラメータは正しく設定されていましたか？
A2: はい、コントローラーでは`staff_params`というメソッドを使ってストロングパラメータを設定していました。このメソッド内で`require(:staff)`と`permit`を用いてパラメータの許可を行っていました。

### Q3: パラメータの中身を確認しましたか？
A3: はい、`binding.pry`を用いてパラメータが正しく渡されていることを確認しました。

### Q4: `load_and_authorize_resource`を削除すると登録できるようになりましたか？
A4: はい、`load_and_authorize_resource :class => 'Staff'`を削除するとエラーが解消され、正常に登録できるようになりました。しかし、これではCanCanCanによる権限制御ができません。

### Q5: `load_and_authorize_resource`の書き換えは？
A5: `load_and_authorize_resource :class => 'Staff', except: [:create]`に書き換えました。また、`create`アクション内で`@staff = Staff.new(staff_params)`としてパラメータを持たせました。

### Q6: 最終的な解決策は？
A6: `Staffs::RegistrationsController`の`create`アクションで`load_and_authorize_resource`を使わず、`Staff`インスタンスを明示的に新しいストロングパラメータと共に作成し、`authorize!`メソッドを使用して手動で認可チェックを行いました。

---

## 解決までのステップバイステップ

### ステップ1: ストロングパラメータの確認
最初に、ストロングパラメータが正しく設定されているかを`staff_params`メソッドを確認します。

```ruby
private

def staff_params
  params.require(:staff).permit(:company_id, :name, :email, ...)
end
```

### ステップ2: パラメータの存在を確認
`binding.pry`を挿入し、パラメータが正しく渡されていることをコンソール上で確認します。

### ステップ3: CanCanCanの挙動を確認
`load_and_authorize_resource`の記述を一時的にコメントアウトして、エラーが解消されるかテストします。

### ステップ4: CanCanCanの設定を変更
`create`アクションの自動ロードをスキップするために、`load_and_authorize_resource`のオプションを調整します。

```ruby
load_and_authorize_resource :class => 'Staff', except: [:create]
```

### ステップ5: 認可チェックの実装
`create`アクション内で手動で認可チェックを行います。

```ruby
def create
  @staff = Staff.new(staff

_params)
  authorize! :create, @staff
  ...
end
```

## まとめ
Railsにおける`ActiveModel::ForbiddenAttributesError`は、ストロングパラメータの不適切な設定によって引き起こされることが多いですが、CanCanCanと組み合わせて使用する際には、その自動ロード機能が原因でエラーが発生する場合があります。適切なパラメータ許可と明示的な認可チェックを行うことで、この問題を解決できます。
Spring Boot: ビューの複数データをコントローラのListで受けた例

# この記事で分かる事
SpringBootを使用したWebアプリケーション開発において、ビューから送信された（キーが同じ）複数のデータをコントローラのListクラスで受け取る際、どのような形で格納されるか、表にまとめています。
表を見る事で、コントローラのデータハンドリングを適切に指定できます。

# リクエストとList内データのまとめ
・条件
リクエストはhoge=valueの形式で送ります。
コントローラのListクラスの型はList\<String> hogeで宣言しています。
hoge<br>(デバッグで見た値)はEclipceのデバッグ機能で表示された値を記載しています。


| リクエストの状態＼List                                          | hoge<br>(デバッグで見た値) | hoge.size()<br>(実行結果)      | hoge.get(0)<br>(実行結果)        | 
| --------------------------------------------------------------- | -------------------------- | ------------------------------ | -------------------------------- | 
| keyがリクエストに無い                                           | null                       | NullPointerException at size() | NullPointerException at get(int) | 
| key、value共に有りが1ペア<br>（hoge=value1）                    | [value1]                   | 1                              | value1                           | 
| key、value共に有りが2ペア<br>（hoge=value1、<br>　hoge=value2） | [value1, value2]           | 2                              | value1                           | 
| keyはあるが、valueは無し<br>（hoge=)                            | []                         | 0                              | IndexOutOfBoundsException        | 
| keyは2つあるが、どちらもvalueは無し<br>（hoge=<br>　hoge＝）    | [null, null]               | 2                              | null                             | 

# 感想
表の3行目まではイメージ通りでしたが、最後の２つ
「keyはあるが、valueは無し」
「keyは2つあるが、どちらもvalueは無し」
の結果について次の点で以外だと感じました。
・リクエストが(hoge=)の場合、hoge.size()とhoge.get(0)共にエラーとなると予想しましたが違った事
・リクエストが(hoge=)の場合と(hoge=  ,hoge=)の場合で結果が違う結果になる事

リクエストにはvalueが存在するデータのみ送る方が分かりやすいと思いました。
【UE5.3】SunPositionCalculatorプラグインで夜にならない

## 初めに
SunPositionCalculatorプラグインを使用すると地理的に正確な太陽の位置を指定できるようになるので、日照シミュレートなどに使えるかと思います。
[UE公式ドキュメント](https://dev.epicgames.com/documentation/ja-jp/unreal-engine/geographically-accurate-sun-positioning-tool-in-unreal-engine?application_version=5.3)に具体的な使用方法が書かれているのでここでは説明は割愛させていただきます。
「日照シミュレートに使用できる」と記載しましたが、UE5.3ではバグがあり東京の夏ごろを指定すると夜の時間帯でも夕方に見えるようになってしまいます。
今回はこちらの修正方法を紹介したいと思います。
UE5.3以外では確認していませんが、もしかすると以前のバージョンでも同じバグが発生している可能性もあります。

## 環境情報
Windows 11
UE 5.3.2

## 問題の事象
今回の検証ではVRテンプレートを用いてBP_SunPositionをレベル上に配置してDetailsから必要な設定を行っています。

具体的な設定は下記の通りです

・Latitude：東京タワーの緯度です
・Longitude：東京タワーの経度です
・TimeZone：UTCが基準になるのでJSTで考えると+9時間になります
・North Offset：北方向の設定なので今回は特に設定していないです
・Year：2023
・Month：8
・Day：1
・Hours：23
・Minutes：0
・Seconds：0

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/eb5d588c-659e-2422-478d-f5bfed12dc8c.png)

2023/08/01 23:00の東京タワー近辺のシミュレーションです。画像の通り指定している時間は完全に夜ですが、どう見ても夕方の空になっています。↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/4d6e386f-df3a-4af5-dd1b-6f798eac9073.png)

一応2023/01/01 23:00にすると若干夜っぽくなりますがまだ明かりが見えています。↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/8eb9b162-cd65-00bd-65e8-ae6e49f3803b.png)

## 修正方法
BP_SkySphereのUpdateSunDirectionでSunHeightに設定する値が大きくなってしまっているのが問題の原因です。
夜の場合は-1に近い値が設定される必要があるのですが、想定より大きい値が設定されてしまっています。
昼の場合は問題ないので、MapRangeUnclampedからの値が0より小さい際に2～3ぐらいの値を乗算してClampで-1～+1に収まるようにして値を補正しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/53fc18ba-552e-9543-21ee-ff4c131dfe1b.png)

こちらの対応で2023/08/01 23:00の場合にしっかりと夜の空になっています。今後のエンジンのアップデートで修正されるとは思うので応急処置として使えるのではないでしょうか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/12dcd5cb-189f-0bdb-7be2-68f14296f142.png)
(java silver)配列

## JavaSilverでメモしたところ備忘録として残しておこうと思います。

# 配列の宣言・初期化について

### 配列の宣言
```java
//データ型[] 配列変数名
int[] num;

//もしくは、データ型　配列変数名[]
int num[];
```
### 配列の作成
```java
//配列変数名 = new データ型[要素数]
num = new int[3];

//初期化
int[] num = new int[3];
```

#### []の位置は変数名の後ろでもコンパイル可
```java
int[] num; //もしくは
int num[];

//二次元でも三次元でも同じ

int[][] num;
int num[][];

int[][][] num;
int num[][][];
```
#### []は分けて書いてもコンパイル可
```java
int[] num[];
int[] num[][]
```
#### 変数とインスタンスの次元は一致させる
```java
int[] array = new int[2][2];  //コンパイルエラー
```
#### 扱える要素数に浮動小数点は指定できない
```java
int[] array = new int[2.5];  //コンパイルエラー
```
#### 二次元配列を作成するとき、一次元目の要素数は省略できない
```java
int[][] araay = new int[][3];//コンパイルエラー

int[][] araay = new int[2][];//OK
```
#### {}(初期化子)で代入する際は次元数に合わせて{}をつける
```java
int[][][] array = {{1,2,3},{4,5,6}};//コンパイルエラー
int[][][] array = {{{1,2},{2,3}},{{4,5},{5,6}}};//OK
```
#### 配列の宣言時は要素数を指定できない
```java
int[5] num; //コンパイルエラー

int[] num; //OK
```
#### 配列インスタンスを生成するときは必ず扱える要素数を指定する
```java
//宣言と配列の作成
int[] array;
array = new int[]; //NG

int[] array;
array = new int[3]; //OK
```
```java
//初期化
int arrayB = new int[]; //NG

int arrayB = new int[3]; //OK
````

#### newと初期化子{}を使う場合は要素数を指定できない
```java
int[] array = new int[3]{100,200,300}; //NG

int[] array = new int[]{100,200,300}; //OK
```
#### 初期化子{}は変数宣言と同時にしか使用できない
```java
int[] array;
array = {100,200,300}; //NG
int[] array;
array = new int[]{100,200,300}; //OK
```
Swiftにおけるメタタイプ

## はじめに：

本記事ではSwift言語の中でもあまり知られていない非常に強力な機能の1つ、メタタイプを理解しましょう。メタタイプの深さ、その秘密を明らかにし、実用的な応用をしていきましょう。

## メタタイプの紹介：

Swiftプログラミングでは、メタタイプは型そのものを表す特別な型です。ランタイムに型について推論し、動的な振る舞いや高度な型操作を可能にします。しかし、メタタイプとは具体的に何でしょうか？

根本的には、Swiftにおけるメタタイプは単純に型の型です。ええ、その通りです。Swiftでは、すべての型には対応するメタタイプがあります。メタタイプは、Swiftの型システム内での型のユニークな識別子を表します。メタタイプは、次の疑問に答えます「この型の型は何ですか？」

ある意味、ある型自体を表す特別な型です。
「型の型」は「メタタイプ」と呼ばれ、ある型のメタタイプはその型に関連する全ての型情報を保持します。具体的には、ある型のメタタイプはその型のクラスオブジェクトを指します。

Swiftのメタ型はTypeという名前の型で表現されます。例えば、あるクラスMyClassのメタ型はMyClass.Typeです。

## メタタイプの種類：
Swiftは、次の3つの主要な種類のメタタイプを提供します：

### インスタンスメタタイプ（SomeType.self）：
- このメタタイプは、インスタンスなしで型自体を指します
- `.self` 構文を使用してアクセスされます
- ```swift 
    let stringType: String.Type = String.self
   ```

### クラスメタタイプ（SomeClass.Type）：
- クラス型に特化しています
- クラス自体の型を表し、クラスのインスタンスではありません
- クラス名に `.Type` を追加してアクセスされます
- ```swift 
    class MyClass {}
    let myClassType: MyClass.Type = MyClass.self
   ```

### プロトコルメタタイプ（SomeProtocol.Protocol）：
- プロトコルの型を表すために使用されます
- プロトコル名に `.Protocol` を追加してアクセスされます
- ```swift 
    protocol MyProtocol {}
    let myProtocolType: MyProtocol.Protocol = MyProtocol.self
   ```

## メタタイプの比較：
これらのメタタイプを簡単なアナロジーを通して比較してみましょう。インスタンスメタタイプはレシピ、クラスメタタイプはシェフ、プロトコルメタタイプはガイドラインと考えてください。

### インスタンスメタタイプ（SomeType.self）：
レシピのように、型の構造と機能を定義します。
### クラスメタタイプ（SomeClass.Type）：
シェフが料理を作るための材料とレシピを決めるように私たちがクラス自体、そのプロパティ、およびメソッドを定義します。
### プロトコルメタタイプ（SomeProtocol.Protocol）：
ガイドラインに似ており、型が従う必要がある要件を概説します。

## メタタイプの実用的な使用例：
メタタイプは、Swift開発においてさまざまな実用的な応用があります：

### 動的な型チェック：
- 実行時にインスタンスの型を判断します
- ```swift 
    let object: Any = "Hello, Swift!"
    if object is String {
        print("It's a String!")
    }
  ```

### ファクトリーメソッド：
- 型のインスタンスを動的に作成します
- ```swift 
    func createInstance(of type: Any.Type) -> Any {
        return type.init()
    }
  ```

### リフレクションとインスペクション：
- 型とそのプロパティを動的に調査および操作します
- ```swift
    let propertyCount = Mirror(reflecting: someInstance).children.count
    print("Number of properties: \(propertyCount)")
   ```
### `.self`、`.Type`、および`.Protocol`の重要性：

- `.self`：インスタンスメタタイプを示し、型自体を参照するために使用されます
- `.Type`：クラスメタタイプを参照し、クラスに特化しています
- `.Protocol`：プロトコルメタタイプを表し、プロトコルに使用されます

## 結論：
要するに、Swiftでは「型の型」は「メタタイプ」と呼ばれ、ある型のメタタイプはその型に関連する全ての型情報を保持します。具体的には、ある型のメタタイプはその型のクラスオブジェクトを指します。SwiftのメタタイプはTypeという名前の型で表現されます。例えば、あるクラスMyClassのメタ型はMyClass.Typeです。では、ハッピーコーディング！
OCI証明書サービスにインポートした証明書の自動更新スクリプト

# 概要
Let's Encryptで発行した証明書をOCI証明書サービスにインポートした後、自動更新のスクリプトを作成しました。

# 前提条件
- OCI CLIがインストールされ、設定済みであること
- Let's Encryptで発行した証明書がOCI証明書サービスにインポートされていること
- Let's Encryptで発行した証明書の自動更新用の仕組みが別途構築されていること

# スクリプト

```
#!/bin/bash

file1="/etc/letsencrypt/live/******.***/cert.pem"
file2="/tmp/cert.pem"

if cmp -s "$file1" "$file2"; then
    echo "No need to update certificate."
else
    echo "Start updating the certificate."
    oci certs-mgmt certificate update-certificate-by-importing-config-details \
     --certificate-id ocid1.certificate.oc1.ap-tokyo-1.******* \
     --certificate-pem "$(cat /etc/letsencrypt/live/******.***/cert.pem)" \
     --private-key-pem "$(cat /etc/letsencrypt/live/******.***/privkey.pem)" \
     --cert-chain-pem "$(cat /etc/letsencrypt/live/******.***/chain.pem)" 
    cp "$file1" "$file2"
    echo "Certificate update complete."
fi

```

説明：
Let's Encryptで発行した証明書とバックアップした証明書を比較します。
差分がなければ、何も行いません。
差分がある場合は、OCIの証明書を更新した後、現行の証明書をバックアップファイルにコピーします。

`oci certs-mgmt certificate update-certificate-by-importing-config-details` に関する詳細については、公式ドキュメントをご参照ください。

スクリプトの定期自動実行設定は別途構築する必要があります。

# 参考資料：
https://docs.oracle.com/en-us/iaas/tools/oci-cli/3.43.0/oci_cli_docs/cmdref/certs-mgmt/certificate/update-certificate-by-importing-config-details.html
[1.20.4]Spigot PluginでCustom BiomeのNamespaceを取得する

# 結論
<details open><summary>Java Code</summary>

```java:java
    public BiomeBase getBiomeBase(Location location) {
        World bukkitWorld = location.getWorld();
        if(bukkitWorld == null)
            return null;

        int x = location.getBlockX();
        int y = location.getBlockY();
        int z = location.getBlockZ();
        net.minecraft.world.level.World nmsWorld = ((CraftWorld) bukkitWorld).getHandle();
        return nmsWorld.getNoiseBiome(x >> 2, y >> 2, z >> 2).a();
    }
    public MinecraftKey getBiomeKey(Location location) {
        DedicatedServer dedicatedServer = ((CraftServer) Bukkit.getServer()).getServer();
        IRegistry<BiomeBase> registry = dedicatedServer.aZ().d(Registries.at);

        return registry.b(getBiomeBase(location));
    }
```

</details>
<details><summary>Kotlin Code</summary>

```kotlin:Kotlin
    private fun getBiomeBase(loc: Location): BiomeBase {
        val bukkitWorld = loc.world
        val x = loc.blockX
        val y = loc.blockY
        val z = loc.blockZ
        val nmsWorld: net.minecraft.world.level.World = (bukkitWorld as CraftWorld).handle
        return nmsWorld.getNoiseBiome(x shr 2, y shr 2, z shr 2).a()
    }

    fun getBiomeKey(loc: Location): MinecraftKey? {
        val dedicatedServer = (Bukkit.getServer() as CraftServer).server
        val registry: IRegistry<BiomeBase?> = dedicatedServer.aZ().d(Registries.at)
        return registry.b(getBiomeBase(loc))
    }
```
</details>

# 未来のためのメモ
<dl>
  <dt>dedicatedServer.aZ()</dt>
  <dd>MinecraftServer.registryAccess()</dd>
  <dt>dedicatedServer.aZ().d()</dt>
  <dd>RegistryAccess.ownedRegistryOrThrow()</dd>
  <dt>Registries.at</dt>
  <dd>Registries.BIOME</dd>
</dl>




# 参考
- [[1.17] Getting custom biomes and dimensions by namespace](https://www.spigotmc.org/threads/1-17-getting-custom-biomes-and-dimensions-by-namespace.513957/)
- [NMS mapping browser
](https://nms.screamingsandals.org)
Rustのmodについて

# まえがき
Rustを使う中で`mod`が良くわからなかったのでまとめる
間違い、不正確な点等あれば修正してください

# mod 
> モジュールは関数、構造体、トレイト、`impl`ブロック、さらには他のモジュールなどの要素の集合です。
> [モジュール - Rust By Example 日本語版](https://doc.rust-jp.rs/rust-by-example-ja/mod.html)]

`mod`キーワードを使ってモジュールを宣言できる
`pub`キーワードを使うと外部のスコープからもアクセスできる
```rust
mod example_mod {
	fn test() {
		println!("test");	
	}

	pub fn public_test() {
		println!("public test");
	}
}
```

# ファイルを分ける
```
. 
├── main.rs 
└── my_mod.rs
```

以上のような構成があったとする
この時、`main.rs`から`my_mod.rs`内の関数などにアクセスするには以下のようにする

```rust:my_mod.rs
fn test() {
	println!("test");
}

pub fn public_test() {
	println!("public test");
}
```

```rust:main.rs
// このように宣言すると、`my_mod`という名前のファイルを探す
// また、`my_mod`という名前で中身にアクセスできる
mod my_mod

fn main() {
	// このようにアクセスできる
	my_mod::public_test();

	// もちろん公開していない関数等にはアクセスできない
	// my_mod::test();
}
```

# use
以下のディレクトリ構成を仮定する
```
. 
├── utils
	├── utility.rs 
	├── nested.rs 
├── main.rs 
└── my_mod.rs
```

`utility.rs`から`nested`を使用することを考える
```rust:nested.rs
pub fn util_fn() {
	println!("Utility!");
}
```

```rust:my_mod.rs
mod nested

pub fn test() {
	nested::util_fn();
}
```

この時、`use`キーワードを使うとパスを新しい名前にバインドできる

```rust:utility.rs
mod nested;
use nested::util_fn;

pub fn test() {
	util_fn();
}
```

`as`を使うと完全な別名にバインドすることもできる
```rust:utility.rs
mod nested;
use nested::util_fn as util;

pub fn test() {
	util();
}
```

# ディレクトリをまたぐ / pub mod
以下のディレクトリ構成を仮定する
```
. 
├── utils
	├── utility.rs 
├── main.rs 
```

ここで、`main.rs`から`utility.rs`のモジュールを使いたい場合を仮定する
この時、`main.rs`から直接`mod utility`することはできない
代わりに、`ディレクトリ名.rs`を作成して経由してやる必要がある 

```
. 
├── utils
	├── utility.rs 
├── main.rs 
├── utils.rs
```

それぞれのファイルの中身を以下のようにする
```rust:utility.rs
pub fn test() {
	println!("test");
}
```

```rust:util.rs
pub mod utility;
```

```rust:main.rs
mod util

fn main() {
	util::utility::test();
}
```

## なにが起こっているのか
通常はディレクトリをまたいで`mod`することはできない
しかし、例外的に`ディレクトリ名.rs`からは名前の一致するディレクトリのモジュールにアクセスできる

`util.rs`内で`pub mod utility`として`utilityモジュール`にアクセスする
`pub mod`とすると、読み込んだモジュールがさらに外部からアクセスできる
これを使用して、`util.rs`で読み込んだ`utility`に`main.rs`からアクセスする

つまり以下のような書き方もできる
```rust:main.rs
mod util;
use util::utility::test

fn main() {
	test();
}
```

## mod.rsてのもあるんだけど...?
`mod.rs`をディレクトリに配置せよという文献も散見される
[# Rustのライブラリ管理は「mod.rs」が大事（Rust 2015）](https://note.com/marupeke296/n/n65ac2671095e)
しかしこれは**Rust2015**の機能であり、現在は後方互換のためだけに残っているものと思われる
現在は基本的に使わなくて良さそう

# 参考文献
[モジュール - Rust By Example 日本語版](https://doc.rust-jp.rs/rust-by-example-ja/mod.html)
[[Rust] モジュールのベストプラクティス](https://zenn.dev/msakuta/articles/83f9991b2aba62)
[Rustでのモジュール分割について #Rust - Qiita](https://qiita.com/TakedaTakumi/items/7936a19979e46fc1b780)
DP-203合格体験記

DP-203を受験し幸いにも受かることができました。スコアは900点中800点でした。受験としては約一年前に1度落ち、2度目の受験となります。お勧めの勉強方法と試験内容について記載します。

# 前提
- DP-203は2度目の受験
- SynapseやAzure Data Lake Storageは業務でさわっている
- 失効済だが、AZ104とAZ-700を過去に取得したことがある
- Azure歴は4年ほど、データ分野に関しては1年半ほどかかわっている

# 今回行った勉強方法

- whizlabsのPracticeテストを3年分実施
https://www.whizlabs.com/microsoft-azure-certification-dp-203/
- 以下のDP-203のプラクティス評価を実施
https://learn.microsoft.com/ja-jp/credentials/certifications/practice-assessments-for-microsoft-certifications#availability

※因みに1度目の受験の際にDP-203用のMS Learnは一通り目を通しました
https://learn.microsoft.com/ja-jp/credentials/certifications/exams/dp-203/

# 試験内容
配分として公式で上がっているのは以下です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269528/c9bf8bcd-4783-02bc-5d1b-c5df53513299.png)
https://learn.microsoft.com/ja-jp/credentials/certifications/exams/dp-203/

リソースごとの出題傾向ですがあくまで体感ですが、ADF：25%、Synapse：20%、Storage：15%、databricks：15%、stream analytics：15%、その他10%のイメージでした。
普段よくADFやSynapse、Azure Storage、bricksを扱っている方であればstream analyticsの勉強を重点して行うのがいいかと思いました、特にstream analyticsのウィンドウ関数の問題は2問でたので絶対抑えるべきです。
またケースごとにどの製品を選ぶべきかなどの問題もよく出てきました。
アーキテクチャセンターのドキュメントのここら辺を読んでおくことで点数がとれるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269528/5f761a7c-ff25-3c36-3d59-73585c5e3885.png)
https://learn.microsoft.com/ja-jp/azure/architecture/data-guide/technology-choices/analytical-data-stores

whizlabsとプラクティスの問題が全体の10~15%ほどでました。

# 感想
何とか2度目でうかれてよかったです。
前回は過去問を一度も解かずに挑んでしまったのですが、今回過去問の大切さに気が付きました。Azureの試験は日本語が独特であったり、手順の並べ替え問題などは答えが考えようによっては何個かある問題もあるので、今後対策されるかたは、MS Learnによる勉強も大切ですが、それより過去問を解く時間を優先するべきかと思います。
また最近Azureの試験はDocsが見られるようになったので、どのような内容がどのドキュメントに書かれていたのかを検索する能力も一つ重要になりました。
Azureのアーキテクチャセンターのドキュメントをすぐに検索できるようになっておくのがいいと思います(私は試験中探せませんでした)。

# お勧めの勉強方法
最後にお勧めの勉強方法をまとめます。
- 普段業務でsynaspeやADFを触っている方；初めから過去問を解いてしまうことをお勧めします。過去問を解いていくなかで不明点がでた部分のDocsを重点的に読んで、同じ過去問を2回繰り返し知識の定着をはかります

- 普段業務であまりsynapseやADF触っていない方：MS Learnを丁寧に学習しLabなども実施の上でwhizlabsとプラクティス評価テストを実施することをお勧めします。

### Tips
whizlabsは英語のものしか現在は残念ながらないのですが、edgeの翻訳機能で日本語にすることが可能です。
またwhizlabsは回答に解説がついており、解説には根拠となるAzureのドキュメントのリンクを載せてくれているので試験対策にも向いています。
解説にのっているドキュメントのリンク自体は英語用のものなの(en-us)ですが、それを分割ウィンドウで開き2画面目も日本語に翻訳することで毎回毎回翻訳する手間が省けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269528/a4e9c12e-bdb5-b8b5-47c1-f300e3473138.png)
https://www.whizlabs.com/learn/course/microsoft-azure-certification-dp-203
※画像のはwhizlabsの無料問題(20問)のうちの1つです
Vue.jsのslotを理解しよう！

# ■ はじめに
　Vue.jsを学習中のエンジニアです👩🏻‍💻
　Vue.jsの`<slot>`について学習した際、インプットの段階では理解できていると思っていたものの、実際にアウトプットしようとすると使い方が分からなくなってしまいました。この経験を踏まえて、自分自身の理解度の確認に加え、同じように困っている方の助けになればと思い、このトピックを取り上げました！
# ■ Slotとは
　Slotは、親コンポーネントから子コンポーネントにコンテンツを挿入する仕組みです。これにより、子コンポーネントが親から受け取ったコンテンツを特定の場所に表示することができます。
　具体的な使い方は、親コンポーネント内で子コンポーネントを使用し、子コンポーネント内に**Slot**を配置します。これにより、親コンポーネントで子コンポーネントのタグ内に挿入したコンテンツが、**Slot**に渡されます。そして、子コンポーネント内で受け取ったコンテンツを特定の場所に表示します。
言葉だけでの説明だとわかりづらいと思うので、以下では実際のコードを使用して、**lot**の使い方について説明します。
# ■ Slotの使い方
例えば、親コンポーネントで子コンポーネントを使用し、その中にテキストを挿入する場合、以下のような形になります。
```ParentComponent.vue
<script setup>
import ChildComponent from './ChildComponent.vue';
</script>

<template>
  <div>
    <h1>親コンポーネント</h1>
    <ChildComponent>
      <p>子コンポーネントへのコンテンツ</p>
    </ChildComponent>
  </div>
</template>
```
```ChildComponent.vue
<template>
  <div>
    <h2>子コンポーネント</h2>
    <div>
      <slot />
    </div>
  </div>
</template>
```
それぞれのファイルをブラウザで実行すると、次のような表示になります。
```ParentComponent.vue
親コンポーネント
子コンポーネントへのコンテンツ
```
```ChildComponent.vue
子コンポーネント
子コンポーネントへのコンテンツ
```
# ■ PropsとSlotの違い
- Props(プロパティ)の特徴
    - 親コンポーネントが子コンポーネントにデータを直接指定することが可能
    - 子コンポーネントでは受け取ったデータを変更することができない
    - **HTML要素そのものを渡すことができない**
    
- Props(プロパティ)の使い方
```ParentComponent.vue
<script setup>
import ChildComponent from './ChildComponent.vue';
const parentMessage = 'Hello from parent!';
</script>

<template>
  <ChildComponent :message="parentMessage" />
</template>
 ```
 ```ChildComponent.vue
<script setup>
const props = defineProps({
  message: String
});
</script>

<template>
  <div>{{ props.message }}</div>
</template>
```
先ほどProps(プロパティ)の特徴の中で、
**HTML要素そのものを渡すことができない**と記載しましたが、実際にどういうことなのか具体例を用いて説明します。
例）
① 親コンポーネントでmessageという変数を用意します。
```ParentComponent.vue
const message = ref("<p>Hello world!</p>");
```
② 変数messageを次のようにProps経由で子コンポーネントに渡したとします。
```ParentComponent.vue
<ChildComponent v-bind:message="message" />
```
③ 子コンポーネントで次のようにマスタッシュ構文で表示させようとした場合、エスケープされるため、HTML要素とは認識されず、文字列として表示されてしまいます。
```ChildComponent.vue
<section>
 {{ props.message }}
</section>
```
```
<p>Hello world!</p>
```
- Slot特徴
    - 親コンポーネントから子コンポーネントに複数の要素を渡すことが可能
    - コンポーネントの内部構造を調整し、再利用することが可能
    - 動的なコンテンツをコンポーネントに挿入可能
    
※　Slotの使い方に関しては、■ Slotの使い方を参照してください。

# ■ Slotのオススメの使い分け
どんなときにSlotを使用するかわからないこともあると思うので、私が実際に先輩から教示いただいことを記載します。Slotを使用する場合は、以下の場合がオススメです✨
- 挿入したい内容に変更がない場合
- （挿入したい内容に変更がない）複数の要素挿入したい場合
- ディレクティブを追加で複数使用することがない場合
    - 例）複数のディレクティブ使用
    ```
        <button class="action-btn" :class="props.btnClass":disabled="isDisabled">
    ```
# ■ 最後に
　ここまで記事を読んで下さり誠にありがとうございます！
　インプットの際に理解できていると思っていても案外実務で使用するってなった場合に、あれ？どうやって使うんだっけ？思い通りの処理にならない。。みたいなことって結構あるなと思ったので、インプットしたことはQiitaの記事やコードをたくさん書いてアウトプットするべきだなと深く感じました！
Bashを使ってkey-value形式のファイル解析

#### key-valueファイルの基本形式

key-valueファイルは通常、以下のような形式でデータが格納されます。

```txt
key=value
```

この形式の各行は特定のキーとその値が=で結ばれています。

例:　MySQL設定ファイル

```key-value
[client]
host=examplehost
user=exampleuser
password=examplepassword
```

#### ファイルの読み込み

Bashでファイルを読み込む基本的な方法はcatコマンドを使用することです。しかし、ここではwhileループとreadコマンドを組み合わせて、各行を効率的に読み込みます。

```sh
while IFS= read -r line; do
  echo $line
done < "config.txt"
```

#### キーと値の抽出

読み込んだ各行からキーと値を抽出するには、cutコマンドを使用するか、またはBashの内部文字列操作機能を利用します。

```sh
declare -A config
while IFS='=' read -r key value; do
  config[$key]=$value
done < "config.txt"
```
生産性における即レスの大切さ

# はじめに
昨今「開発生産性」についての話題をよく目にします。
生産性が向上することで悪いことは無いので、様々な組織の事例が公開されて業界全体に知見が共有されていくことはとても素晴らしいことだと感じています。

話題のこちらの本
[「世界一流エンジニアの思考法」](https://www.amazon.co.jp/%E4%B8%96%E7%95%8C%E4%B8%80%E6%B5%81%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E6%80%9D%E8%80%83%E6%B3%95-%E7%89%9B%E5%B0%BE-%E5%89%9B/dp/4163917683)にもとても大切なことが書かれておりますし

こちらの記事も参考になりました。

https://qiita.com/kntr0116/items/302d5e379505089780d2


それらを踏まえて個人的に生産性向上のベースになる大切なことだと思っている **「即レスの大切さ」** について書きたいと思います。

## これまでやってきたお仕事
- ツールアプリの新規事業責任者（3年ほど）
    - 全体3名の少人数チームでスタート
    - 私（責任者+PdMの役割）、エンジニア1名、デザイナー1名
    - 最終的には30人前後の組織の事業部長
- ゲームアプリのマーケティングマネージャー（5年ほど）
    - 組織全体としてはビジネスサイド20名、エンジニア5名、デザイナー5名ほど
- 会社経営（4年ほど）
    - 組織全体としては40名弱
    - エンジニア、デザイナー、ビジネスメンバー

## 生産性における即レスの大切さ
**目次**

* [なぜ即レスが大切なのか?](#なぜ即レスが大切なのか?)
* [レスが遅いことの弊害](#レスが遅いことの弊害)
* [ピラミッド構造組織におけるレス速度の影響](#ピラミッド構造組織におけるレス速度の影響)
* [最後に](#最後)


## なぜ即レスが大切なのか?
おそらくレスが遅いよりは早い方が良いというのは皆さんも感じていることだと思います。
個人的にはほぼ全ての組織における仕事はいわゆる**キャッチボールで成り立っている**と考えています。

例えば、ある一定の時間内におけるキャッチボールの往復回数を生産性と定義するとします。
無駄なキャッチボールを増やすのではなく、依頼→開発→テスト→納品→リリースのようなステップを進めていく流れを前進させるコミュニケーションをキャッチボールと呼ぶことにします。

その場合の生産性を高めるには以下のようなアプローチがあると思います。

**1. 正確に相手にボールを投げる（受け取る）**
**2. 投げる速度を速くする**
**3. 投げ返すまでの時間を短縮する（すぐに投げ返す）**

この場合
1は正確なアウトプットをするだったり、相手に的確な情報やモノを渡すことことにあたります。
2はコミュニケーション手段の話が近いと思います。電話・メール・チャットなどのツールの話やコミュニケーションの階層やルールの話になります。
**3が今回の主題である「即レス」にあたります。**

この3つの中で、自身の意識と行動次第ですぐに改善しやすいポイントが「即レス」です。
生産性を高めていくためのベースとして大切だと考えます。


## レスが遅いことの弊害
キャッチボールを想像すると分かりやすいですが、ボールを投げたあとボールが返球されるまでは「待ち」が発生します。実際に仕事をするうえではボールは複数抱えているので待ちが発生することはそうそう無いと思いますが、状況的に**ボールが返ってこないと次の行動が取れない**という状態が発生することがあります。

例えば社内の承認であったり、レビューであったり、そのステップが完了しないと次のステップへ進めないものです。もっと日常的なものでいうと承認フローには組み込まれていなくても上司に「これ進めて良いですか？」という確認を非同期的に取ることも多いのでは無いでしょうか。こういう場合にボールが返ってこないと待ちが発生します。

そしてこの目に見えにくい**待ちの時間が積み重なっていくことで全体としての生産性も下がってく**はずです。


## ピラミッド構造組織におけるレス速度の影響
個人的にこれまでの経験の中で強く感じるのがこの観点です。
一般的な組織では以下のようなピラミッド型の組織構造になっていることが多いかと思います。

![1626914.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502865/8fa1f2d0-cf44-9c79-4928-72eb851f4b7b.png)

この場合、上の階層間で待ちが発生するとそれ以下の階層ごとに**待ち時間がねずみ算のように波及**していきます。
そのため階層が上になるほど即レスの重要性は増していくはずです。
個人的にはこれまで優秀な人ほど忙しいはずなのにレスが早いという経験を何度もしてきました。そのためレスの早さについて忙しさや時間の無さはあまり理由にならないと感じています。

## 最後に
即レスについては特別な才能やスキルではなく、心がけと習慣化で出来ることだと思います。
もちろんどうしても時間や心の余裕的に難しいときもありますが、日々1人1人が心がけていくことで目に見えない待ち時間を減らし、全体の生産性向上に結びつくのではないでしょうか。
連続する N 個の和の最大値】 連続する N 個の和の最大値 4 (paizaランク C 相当)

連続する N 個の和の最大値】 連続する N 個の和の最大値 4 (paizaランク C 相当)

https://paiza.jp/works/mondai/prefix_sum_problems/prefix_sum_problems__sum_max_boss

解答

n,k = [int(x) for x in input().split()]

a= [int(x) for x in input().split()]

s= [0]*(n+1)
m=0　
for i in range(n):
    s[i+1]=s[i]+a[i]   #累積和を求める式

for i in range((n+1)-k):
    m=max(m,s[i+k]-s[i])　#大きい方を採用

print(m)

累積和を求めてから連続するk個の和の最大値を求めました。
言語処理学会2024論文紹介/RealPersonaChat: 話者本人のペルソナと性格特性を含んだ 雑談対話コーパス

【一言で言うと】
「話者本人のペルソナ」、「性格特性」、「話者間の自由対話」を収集して構築されたRealPersonaChat(RPC)コーパスは、　既存のコーパス（JPersonaChat；JPC）よりも自然（ペルソナの情報を過剰に含まない）で、質（対話満足度）が高いことを明らかにした。

【タイトル/URL】
RealPersonaChat: 話者本人のペルソナと性格特性を含んだ雑談対話コーパス
https://www.anlp.jp/proceedings/annual_meeting/2024/pdf_dir/B10-4.pdf

RealPersonaChat
https://github.com/nu-dialogue/real-persona-chat

【まとめ】
1.RPCコーパスの構築
　　- 話者の募集→事前アンケートの実施→対話の収集→事後アンケートの実施
2.RPCコーパスの基本統計（表１）
3.RPC vs JPC
　　- 名詞、内容語のペルソナ出現率がJPCで有意に高い（JPCは過剰にペルソナの情報を含んでいる？）
　　- 60名による第三者主観評価では、RPCの対話満足度がJPCよりも有意に高かった
　　- 対話とペルソナの関連度はJPCで有意に高かった（JPCがペルソナの使用で偏った分布を持つ？）
４.性格特性スコアの相関係数
　　- 対話から性格特性が認識可能か？→　RPCでは、対話から話者の性格特性を認識することは難しく、話者本人が自覚する性格と第三者が認識できる性格に差がある

【感想】
RPCには様々なペルソナを持つ会話データがあるので、これを利用することで多種多様なキャラクターを持つ患者さんを擬似的に生成することができるかも。

【画像】
![スクリーンショット 2024-04-26 14.18.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2106750/8e1d9df6-af9d-ed9a-2826-1c17c3d7aa9f.png)
![スクリーンショット 2024-04-26 14.19.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2106750/6b5693cb-61a1-4ca6-985e-c08c267e3834.png)
Copilotによるコードレビューのすゝめ

# Copilotによるコードレビュー
ここではVS Codeの拡張機能である【Github Copilot】を使うことで、コードレビューを個々で進めていければと思って記載していきます

# ここでは記載しないこと
- Github Copilotのアカウント準備
- VS Codeの準備
- 拡張機能のインストール

# コードレビューの仕方
1. 対象のソースを開く
![スクリーンショット 2024-04-26 11.34.52_gimp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3763114/2cd6d83b-f133-97be-a040-a3a0667a63ea.png)
1. レビュー対象の範囲をエディタ上に開いておく
1. Github Copilotの拡張機能を開いて「こちらのコードのレビューをお願いします」と打ち込む
![スクリーンショット 2024-04-26 11.51.49_gimp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3763114/d8ca6bfd-09cf-763d-d49e-cbe29071952e.png)
1. Gighub Copilotから返事が来るので、内容を確認する
![スクリーンショット 2024-04-26 12.49.49_gimp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3763114/38c5144f-38cc-bf46-c5a0-eef75b81f23d.png)
1. 改善点の内容を確認して、指摘内容が必要なことであれば修正する
1. レビューの結果が詳細説明だけの場合、「こちらのソースに指摘はありますか」と打ち込むと改善点を指摘する場合もあります

## 注意点
- VS Codeの拡張機能は、開いているソースの表示されている部分しかCopilotが反応しません
- 長いソース（100行以上）の場合は、分割して確認する
- コードレビューの返信内容は、時と場合によって異なります
- 改善点の修正指摘をしてもらいたい場合は、画面の特定範囲を選択した上で「指定箇所の良い書き方を教えてください」などをCopilotに投げてもらうのもありです
![スクリーンショット 2024-04-26 13.00.50_gimp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3763114/7ac1c1a6-7453-f07c-f155-dd1175d04068.png)


# まとめ
コードレビューをしていて思うことはコチラになります。
- コードのレビューはこまめに
- 小さい機能単位の関数化をしておいて
- 難しい記述はなるべくやめて
- 他人に見やすいコードを作りましょう
AWS Launch WizardでHANAをAWS上に自動デプロイする

AWS上にHANA Databaseを新規にデプロイしたい場合、「AWS Launch Wizard」というサービスが便利なのだが、構築中にいくつかハマりポイントがあった

## AWS Launch Wizardとは
公式より引用
>AWS Launch Wizard は、Microsoft SQL Server Always On や HANA ベースの SAP システムなどサードパーティーアプリケーション用の、AWS リソースのサイズ変更、設定、デプロイをガイドします。個々の AWS リソースを手動で指定したり、プロビジョニングしたりする必要はありません。開始するには、サービスコンソールでパフォーマンス、ノード数、接続性などのアプリケーション要件を入力します。すると、Launch Wizard は、EC2 インスタンスや EBS ボリュームなど、アプリケーションをデプロイして実行するための適切な AWS リソースを特定します。Launch Wizard は、デプロイの推定コストを提供します。また、リソースを変更して、更新されたコスト評価を即座に表示することが可能です。AWS リソースを承認すると、Launch Wizard は選択されたリソースを自動的にプロビジョニングおよび設定して、完全に機能する本番稼働環境に対応したアプリケーションを作成します。

HANAだけでなく、MS-SQLなども自動でAWS上にデプロイしてくれるサービス
※SAPも自動でインストールしてくれるようだが対応しているバージョンなどの制約があったり、SAPインストール中にバグをひいたりして私は諦めたが、データベースのデプロイは割と簡単にいけた


## 注意点
* インターネット接続可能なVPC(Subnet)が必要
    * 構築時にインターネット接続可能なVPC(Subnet)を用意しないとデプロイできない
    * SAP(HANA)はプライベート環境で構築することが多いため、一度インターネット接続可能な環境で構築した後、AMIを取得しプライベート環境へ移せばOK
* HANA Databaseのメディア
    * SAP for MEから必要なHANAメディアをダウンロードする必要がある
    * サポートしているバージョン : [Supported versions for SAP deployments](https://docs.aws.amazon.com/ja_jp/launchwizard/latest/userguide/launch-wizard-sap-versions.html#launch-wizard-sap-versions-databases)
    * S3にアップロードしておく必要があるのだが、S3のバケット名が「launchwizard」から始まるパスじゃないと構築中にはじかれる（参考:[Make SAP HANA software available for AWS Launch Wizard to deploy a HANA database](https://docs.aws.amazon.com/ja_jp/launchwizard/latest/userguide/launch-wizard-sap-structure.html#launch-wizard-sap-s3)）
* OSライセンスのサブスクリプション
    * Marketpaceから必要なOSのライセンスをサブスクリプションする必要がある(参考:[SUSE Linuxの場合](https://aws.amazon.com/marketplace/seller-profile?id=d8e49cc8-b2f8-448d-8531-fc8e873121b0)）

## デプロイ
* あとは必要な項目を埋めてすすめいてくだけ!!（ここは特につまるところなし）
* 項目についてはこちらの方が詳細に書かれていました→[AWS Launch Wizard for SAPの設定項目を眺めてみた](https://qiita.com/duelist2020jp/items/aee2c319fa06c8e146ac)


## エラーが発生したら？
* Launch Wizardのログをみても大したことは書いていないため、Cloud Formationのログを見ればOK
* 内部的にはCloud Formationを利用してデプロイしているため、詳細なログが記載されている。またエラーが発生した根本原因というボタンを押せばどこでコケたのかが分かる
* 自力で解決できない場合、ログとともにAWSサポートに投げれば大体は解決できる(多分)

個人でやるとめちゃくちゃに高いので注意が必要（HANAはハイスペックマシンですからね…）
【PHP】指定した値が配列のカンマ区切りに含まれてるか検索

やりたいこと。生息地が【丘陵】のポケモンを検索したい。

ただし生息地はカンマ区切りになっている


# コード
```PHP
<?php
$query_data = [
    ['id'=> 1,'name'=>'イシツブテ','habitat'=>'渓谷,洞窟']
    ,['id'=> 2,'name'=>'イワーク','habitat'=>'砂漠,鉱山']
    ,['id'=> 3,'name'=>'ウソッキー','habitat'=>'鉱山,地中']
    ,['id'=> 4,'name'=>'ハガネール','habitat'=>'丘陵,窪地']
    ,['id'=> 5,'name'=>'サイドン','habitat'=>'渓谷,丘陵']
];


function searchValueInArray($query_data, $value) {
    $keys = [];
    foreach ($query_data as $key => $item) {
        $elements = explode(',', $item['habitat']);
        if (in_array($value, $elements)) {
            $keys[] = $key;
        }
    }
    return $keys;
}


// 検索したい値
$searchValue = "丘陵";

// 関数を呼び出す
$keys = searchValueInArray($query_data, $searchValue);

if (!empty($keys)) {
    echo "【{$searchValue}】が生息地のポケモンが見つかったよ。レコード番号は【" . implode(', ', $keys).'】です';
} else {
    echo "【{$searchValue}】が生息地のポケモンはいなかったよ";
}
```

# 結果
```javascript
【丘陵】が生息地のポケモンが見つかったよ。レコード番号は【3, 4】です

```
第一回 | 商品レビュー分析のリニューアルに伴う自動化システム構築について

# はじめに
弊社 ヴェネクト株式会社では、データに基づいたマーケティング支援を特長の1つとしています。  
そのデータに基づいた支援を体現する為に、様々な調査・分析を実施しておりますが、その中に「商品レビュー分析」というものがあります。  
「商品レビュー分析」は、単独のサービスとしても売り出しており、”商品を購入した顧客が**どのような商品評価をしている**のか、競合他社の商品と比較した際に**それぞれの差はどこにある**のか” を分析する内容となっています。  
これまでの「商品レビュー分析」は、レビューサイトやECサイトから取得した商品レビューを人の手で大量に読み込み、ポジティブ/ネガティブなどの判別をしてきましたが、この度「商品レビュー分析サービス」のリニューアルを機に、この判別作業の一部自動化を目指しました。  
詳細の内容は後述する関連記事をご参照いただきたいのですが、主に自然言語解析を使用することでレビュー文章のポジティブ/ネガティブを人によらず分類できたり、定量データとして分析できる環境を構築しましたので、合計4回の記事にて、どのような目的から何の技術を採用し、上手く構築できた点や構築に苦戦した点などを掲載していこうと思います。


# 商品レビュー分析サービスとは
VENECTサイト｜商品レビュー分析サービスページ：  
https://www.venect.jp/services/review-analytics/

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2598043/11e87cc4-7b97-d051-601e-3e87aeadfede.png" width="100%">


## 成果物イメージ
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2598043/cb4c9e85-7382-b6c6-4944-0abd58133030.png" width="100%">

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2598043/93990198-3a85-1eee-b7ac-306c2a5e6549.png" width="100%">

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2598043/1eebc069-1979-f51f-ee8c-435cd8a0fce4.png" width="100%">

## 分析結果の活用用途
* ECサイト内挿入サムネイルのクリエイティブ訴求の検討
* 検索型広告の買い付けキーワード/広告文の検討
* 次の商品開発・企画の検討
* 競合対策の検討
* 商品のポジショニングの明確化


## 構築内容について
今回の構築において、弊社が新しく取り入れた技術スタックや処理の流れについて紹介したいと思います。

## 処理の流れ
まずは商品レビュー分析における処理の流れは以下で実装しました。
1.  商品レビューで頻出するキーワードを抽出
2.  商品レビューからレビューとキーワードのポジティブ/ネガティブを分析
3.  キーワードを商品の特徴カテゴリーに分類
4.  集計

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2598043/36e7ef24-c625-18ef-1818-b2f07fb3b6e1.png" width="100%">


### 使用した技術
以下の技術を使用しています。技術的なトピックについては別記事として掲載していますが、それぞれどのような目的で使用しているかの概要を記載します。
* Python（django）
* Google Cloud Natural Language API
* ChatGPT API
* MeCab

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2598043/dfca7579-234b-cbfb-e4c3-298615709727.png" width="100%">


#### [Google Cloud Natural Language API](https://qiita.com/venect_qiita/items/83607a124cad9dcb4e8a)
このAPIを利用することで、レビューの感情やエンティティの感情を自動的に分析し、ポジティブ/ネガティブの度合いを把握することができます。

* レビューの感情（ポジティブ/ネガティブの度合い）を判断
* エンティティの感情（ポジティブ/ネガティブの度合い）を判断

#### [ChatGPT](https://qiita.com/venect_qiita/items/d53be4b15ad44be8f1db)

* 商品に対する特徴カテゴリーの提案（扇風機の場合、「風量」「サイズ」など）
* 頻出エンティティを特徴カテゴリーに分類

#### [MeCab](https://qiita.com/venect_qiita/items/5123b266478c4796db02)

* 頻出エンティティの抽出
* エンティティの原型化
* 共起ワードの抽出

## 今回の構築により出来るようになったこと
大きくは以下の2点がシステムから自動的に出力できるようになったのが影響が大きいと思います

* レビュー全体から算出される評価ポイントのカテゴライズ
* レビューおよびキーワードごとのポジティブ/ネガティブの判別（数値化）

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2598043/d16aa9d1-a1e4-e72c-ca76-65614cb7e083.png" width="100%">

# その他記事へのリンク
* 第一回 | 商品レビュー分析のリニューアルに伴う自動化システム構築について
* [第二回 | Google Natural Language API](https://qiita.com/venect_qiita/items/83607a124cad9dcb4e8a)
* [第三回 | ChatGPT](https://qiita.com/venect_qiita/items/d53be4b15ad44be8f1db)
* [第四回 | MeCab](https://qiita.com/venect_qiita/items/5123b266478c4796db02)
Salesforce REST APIをcurlで試す その2 - User.Email変更

https://qiita.com/pilot/items/baf71a0ad7ceb3a7965c の続き

以下のようなJSONファイルを作る
```json
{
  "Email" : "XXX@example.com"
}
```

以下、curlコマンド
```
curl --ssl-no-revoke --trace-ascii - -X PATCH "https://＜ドメイン＞/services/data/v60.0/sobjects/User/＜当該ユーザーレコードのId＞" -H "Authorization: Bearer ＜アクセストークン＞" -H "Content-Type: application/json" -d @＜JSONファイル名＞"
```

以下、実行結果抜粋
```
<= Recv header, 25 bytes (0x19)
0000: HTTP/1.1 204 No Content
```
nRF9160 がブートしないもしくは、CONFIG_BOOT_MAX_IMG_SECTORS が too small というメッセージが出る

NCS 2.5.2 にて、nRF9160 がブートしない もしくは、CONFIG_BOOT_MAX_IMG_SECTORS が too small というメッセージが出る症状を確認した（基板のメーカーが異なると症状が異なる）。

mcuboot.conf で CONFIG_BOOT_MAX_IMG_SECTORS の値を変更すればとりあえず起動するようにはなるが、ブート時のメッセージは消えず、不安になったので調べてみたときの備忘録。


# build_xxxx -> partitions.yml
一部の基板では、MCUBOOTのセカンダリー領域がないからアップデートできないよ、とのメッセージが出ていた。

build ディレクトリに自動生成される partitions.yml の内容を確認してみたところ、 MCUBOOT のセカンダリー領域が、外部の SPI-NOR フラッシュに割り当てられていた。

# 対策

mcuboot.conf でも、proj.conf でも改善しないので、pm_static.yml に、正常なパーティション情報の詳細を定義してみたところ、解消した。

以前も似たようなことがあり、メッセージも表示されずにブートしなかった際、同じことをしたら解消した記憶がある。

nRF Connect SDK vX.X.X Release Notes の どれかのバージョンで、正常に計算されない不具合が記されていたのはずなので、おそらくそれだと思われる。


ご参考まで。

# 以上。
【Next.js】App Routerのnext/redirectでリダイレクトできない時の対処法。

## はじめに
next.jsのサーバーアクション内でリダイレクト関数を使用していたところ、リダイレクトできない症状に遭遇しました。

## 誤ったコード
try-catch文の中で直接redirect関数を記述しても、リダイレクトは効きません。

```typescript:action.ts 
'use server'

import { FormData } from '@/src/commons/types/type'
import { PrismaClient } from '@prisma/client'
import { redirect } from 'next/navigation'

const prisma = new PrismaClient()

export async function postFormAction(data: FormData) {
	try {
		const formData: FormData = {
			// FormData から必要なプロパティを抽出する
		}

		const createdFormData = await prisma.FormData.create({
			data: formData,
		})
		redirect('/')
		
	} catch (error) {
		console.error('Error creating FormData:', error)
		throw error
	}
}


```

## 理由
公式ドキュメントに対処法の記載がありました。
try-catch文の外にredirect関数は配置する必要があるようです。
redirect関数はリダイレクトが必要なことを示すエラーをスローするため、tryの中でリダイレクト関数を実行すると、catchの処理が実行されることになります。

https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations#redirecting

## 修正したコード
以下のように、直接try文の中にリダイレクトを記述せず、外に逃がしてあげることで、正常にリダイレクトが実行できるようになりました。

```typescript:action.ts 
'use server'

import { FormData } from '@/src/commons/types/type'
import { PrismaClient } from '@prisma/client'
import { redirect } from 'next/navigation'

const prisma = new PrismaClient()

export async function postFormAction(data: FormData) {
	let redirectRequired = false // リダイレクトするかの判定フラグ
	try {
		const formData: FormData = {
			// FormData から必要なプロパティを抽出する
		}

		const createdFormData = await prisma.FormData.create({
			data: formData,
		})
		redirectRequired = true

	} catch (error) {
		console.error('Error creating FormData:', error)
		throw error
	}
	if (redirectRequired) {
		redirect('/') // redirect関数をtry catch文の外で実行する
	}
}
```

## 参考にした記事
https://bel-itigo.com/nextjs-redirect-not-working/
[flutter] Firebaseと組み合わせて開発をしたい

こんにちは！
今回はFirebaseについてとflutterとFirebaseを組み合わせた処理について紹介したいと思います。
最後まで読んでいただけたら、嬉しいです！

## Firebaseの主なサービス

### 1,リアルタイムデータベース
Firebaseはリアルタイムデータベースとして知られるRealtime Databaseを提供しており、リアルタイムでデータを同期させることができます。これはチャットアプリやリアルタイムなゲームなど、リアルタイムなデータ同期が必要なアプリに適しています。

### 2,認証サービス
Firebase Authenticationは、ユーザー認証のためのサービスで、メール/パスワード、ソーシャルログイン（Google、Facebook、Twitterなど）、電話番号認証などのさまざまな方法でユーザーを認証することができます。

### 3,クラウドストレージ 
Firebase Storageは、クラウド上にユーザーの画像、動画、アプリのファイルを保存するためのサービスです。アプリのユーザーがアップロードしたファイルを保存し、簡単に取得できます。

### 4,クラウド関数
Firebase Functionsは、サーバーレスのバックエンド機能を提供し、特定のトリガーに応じて自動的に実行されるJavaScriptコードを記述できます。これにより、バックエンドロジックを簡単に実装し、アプリの機能を拡張することができます。

### 5,アナリティクス
Firebase Analyticsは、アプリの使用状況やユーザー行動に関する詳細なデータを収集し、分析するためのツールです。これにより、アプリのパフォーマンスやユーザーエンゲージメントを追跡し、改善することができます。

### 6,クラッシュレポート
Firebase Crashlyticsは、アプリのクラッシュやエラーをリアルタイムでモニタリングし、開発者に通知するツールです。これにより、アプリの安定性を向上させるためのデバッグや修正が容易になります。

※こちらの記事でも紹介しているので、よかったらご覧ください！

https://qiita.com/yamaguchi_slj/items/7376b234c69b51fcc9b2


## flutterと組み合わせた開発
FlutterとFirebaseは、モバイルおよびWebアプリケーション開発において強力な組み合わせを形成します。FlutterはクロスプラットフォームのUIフレームワークであり、ユーザーインターフェースの構築とアプリのロジックの実装に使用されます。一方、Firebaseは、アプリのバックエンド機能やクラウドサービスを提供し、アプリの機能拡張やデータの管理に役立ちます

### 1,Firebase SDKの統合
FlutterプロジェクトでFirebaseを使用するには、まずFirebase SDKをプロジェクトに統合する必要があります。Firebase SDKには、データベース、認証、ストレージ、アナリティクスなどのさまざまな機能が含まれています。

### 2,Firebaseプラグインの利用
FirebaseとFlutterを統合するためには、Flutterコミュニティによって開発されたFirebaseプラグインを使用します。これらのプラグインは、FlutterアプリからFirebaseサービスを利用するためのAPIを提供します。

### 3,データベースの操作
FlutterアプリからFirebaseのRealtime DatabaseやFirestoreを使用してデータを読み書きすることができます。これにより、リアルタイムでデータを同期させたり、データの永続化を実現したりすることができます。

### 4,認証サービスの利用
Flutterアプリでは、Firebase Authenticationを使用してユーザーの認証や認可を行うことができます。これにより、メール/パスワード、ソーシャルログイン、電話番号認証などの認証方法を利用してユーザーを管理できます。

### 5,クラウド関数の実行
Firebase Cloud Functionsを使用すると、Flutterアプリからバックエンドの処理を実行することができます。これにより、サーバーレスのアーキテクチャを採用し、アプリの機能を拡張することができます。

### 6,クラウドストレージの活用
Flutterアプリでは、Firebase Storageを使用してクラウド上にファイルを保存することができます。画像や動画などのメディアファイルをアップロードし、ダウンロードすることができます。

#### ※参考サイト

https://firebase.google.com/docs/flutter/setup?hl=ja&platform=ios

https://zenn.dev/kazutxt/books/flutter_practice_introduction/viewer/29_chapter4_overview

https://firebase.flutter.dev/

## 終わりに
今回の記事は以上になります。
今回も最後まで読んでいただきありがとうございました！
では、また次の記事で〜！
nRF Connect SDK:Softblinkを実装してみる

# 昔も作った
以前にも似たような内容でSoftblinkっぽいものを作ったことがあります。

https://qiita.com/yoshihiro0709/items/0edfd512de8986f78416

もう3年くらい前なんですね…。そんなに長い間、このSDKと戯れているんですね(笑)。いつになったらまともにうごｋ…あ、誰か来たようだ…。

## そんなに筋は悪くないかも
改めて見てみましたがそこまで筋が悪いサンプルではなさそうです。ただ、タイマースレッド使っていてその他のスレッドへの影響もありそうなので、もう少しそれっぽく作ってみることにしました。

::: note
タイマースレッドはシステムキューに入るので、システムキューに入るその他のスレッドへ影響を及ぼします
:::

# 3年の間にずいぶんと変わった
SDKも変わりましたが、自分自身のRTOS(Zephyr)への理解度も相当上がっています。そりゃ3年も戯れて何も変わっていなかったらそれはそれで問題ですわwww

``` main.c
#include <zephyr/kernel.h>
#include <dk_buttons_and_leds.h>
#include <zephyr/device.h>
#include <zephyr/drivers/pwm.h>
#include <zephyr/logging/log.h>

LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);

#define PWM_PERIOD	1000 * 1000 * 10				// 10msec
#define RATE_MIN	-200
#define RATE_MAX	100
static int16_t rate = 1;

static const struct pwm_dt_spec led_pwm0 = PWM_DT_SPEC_GET(DT_ALIAS(pwm_led0));

static void led_pwm_work_thread(void *p1, void *p2, void *p3)
{
	int16_t dimming = 0;
	int16_t dimming_temp;

	while (true) {
		if (dimming <= 0) {
			dimming_temp = 0;
		} else if (100 <= dimming) {
			dimming_temp = 100;
		} else {
			dimming_temp = dimming;
		}
		pwm_set_dt(&led_pwm0, PWM_PERIOD, (PWM_PERIOD * dimming_temp / 100U));
		LOG_INF("PWM Percentage: %d%%", dimming);
		if ((dimming <= RATE_MIN) || (RATE_MAX <= dimming)) {
			rate = -rate;
		}
		dimming += rate;
		k_sleep(K_MSEC(10));
	}
}
K_THREAD_DEFINE(led_pwm, 512, led_pwm_work_thread, NULL, NULL, NULL, K_PRIO_PREEMPT(0), 0, 0);

int main(void)
{
	return 0;
}
```

``` prj.conf
CONFIG_PWM=y
CONFIG_LOG=y
```

以前のサンプルから比べたらずいぶんとすっきりしました。ただ、nRF SDK時代のようにAPI一つで勝手に光ってくれるようなものは未だ用意されていません。きっと今後も用意されることはないんじゃないかなと思います。

::: note
たぶんRTOSになった関係でそういうAPIは作れないんじゃないかな…
:::