OmniAICreator/Qiita-1.07M huggingface dataset:
【初心者向け】SQLに関する基礎知識

# はじめに

アプリ開発には欠かせないSQLの知識について。
初心者の私の備忘録として、また同じように初心者の方にとって少しでも参考になれば嬉しく思います。

# SQL（シークェル）とは

データベース言語の一つで、データベースの定義や操作を行うことができます。
SQLはISO（国際標準化機構）で規格が標準化されているので、一度学習すればほかのデータベースでも同じように操作可能です。

# SQL 基礎知識

SQLは、大きく3種類の言語で構成されています。
全て命令文で、動詞と目的語を組み合わせて作られています。

## 1. DDL（データ定義言語：Data Definition Language）

DDL は、データベース自体やテーブルに関する命令をするときに使う言語です。
例えば、新しいデータベースの定義、テーブルの結合、テーブルの削除

CREATE：新しいデータベースやテーブルなどのオブジェクトを定義する
- JOIN：テーブル同士を結合する
- DROP：定義したオブジェクトを削除する
- ALTER：定義したオブジェクトの内容を変更する
- TRUNCATE：データをすべて削除する

## 2. DML（データ操作言語：Data Manipulation Language）

DML は、データそのものに関する命令をするときに使う言語です。
例えば、データの削除、データの検索、データの更新などのことです。

- SELECT：データを検索する
- INSERT：データを挿入する
- DELETE：データを削除する
- UPDATE：データを更新する

## 3. DCL（データ制御言語：Data Control Language）

DCL は、データへのアクセス権限に関する命令をするときに使う言語です。
例えば、ユーザー権限の付与、ユーザー権限の削除、トランザクションの開始合図など

- GRANT：ユーザー権限を付与する
- REVOKE：ユーザー権限を削除する
- BEGIN：トランザクションを開始する
- COMMIT：トランザクションを確定する
- ROLLBACK：トランザクションを取り消す

# 基本的な使い方

### SELECT文の場合

SELECT文はデータベースからデータを取得する命令のことで、データベースに登録されている情報を抽出して閲覧・表示できます。
使い方は基本的に以下のように使用します。
```sql
SELECT 列名 FROM テーブル名 WHERE 条件;
```
実際に下の表を例にデータの取得の流れを確認します。

***

### pokemonテーブル
| name | level | owner |
| :------ | :----: | ----: |
| ピカチュウ | 20 | サトシ |
| トゲピー | 15 | カスミ |
| イワーク | 40 | タケシ |

- SELECT name FROM ;

実行結果
+----------+
| name     |
+----------+
| ピカチュウ |
| トゲピー |
| イワーク |
+----------+
3 rows in set (0.00 sec)
Blockchain Bridgeとは？🌉

![blockchain-bridge.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987391/1d0781cf-47f0-8d28-1dd8-5aa68990f3cf.png)

# Blockchain Bridgeを一言で
Blockchain Bridgeは任意の2つのBlockchainでインタラクションする時にその橋渡し役となるプロトコル。

# どんな時に必要なの？
例えばあなたがBitcoinを持っていたとして、それをEthereum上にあるDeFiで使いたいとします。Blockchain Bridgeがない場合は、Bitcoinを売ってEthereumを購入しなければいけません。しかし、Blockchain Bridgeを用いることによってBitcoinを売却せずにそれを行うことができます。

# なぜ必要なの？
様々なBlockchainネットワークが発展する中で大きな問題の1つとしてあるのは、それぞれのBlockchainネットワーク同士が連携を取れないことです。なぜなら各ブロックチェーンには、独自のルール、トークン、プロトコル、およびスマートコントラクトがあるからです。これらのそれぞれ独立したBlockchainネットワーク同士を繋げる役割を果たします。

# どういう仕組み？
Blockchain Bridgeの最も一般的な使用例としてトークン転送があります。例えばBitcoinをEthereumネットワークに転送したいとします。方法の1つとして考えられるのはBitcoinを売却してEthを購入することです。しかし、取引手数料が発生したり価格変動にさらされたりと良くない点があります。
Blockchain Bridgeを使用することでこの問題を解決することができます。BitcoinをEthereum WalletにBridgeすると、Blockchain Bridge ContractがBitcoinをロックしEthereumと互換性のあるERC20である同量のラップされたWBTC(Wrapped Bitcoin)を作成します。転送したいBitcoinの量はスマートコントラクトでロックされ、宛先のBlockchainネットワークで同等のトークンが発行または作成されます。それは、それが表す資産の価値に固定されており、通常はいつでも償還 (アンラップ) できます。

# 最後に
![Frame 9 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/87f2a488-c5cd-549d-f07f-01b44a1317b8.png)
<b>Veroo</b>は、Blockchain技術を活用した「想いの巡るグルメSNSアプリ」です。食に対する熱量、例えばラーメンがめちゃくちゃ好きで年間400杯食べているとか、変態的に具材にこだわった中華料理を作っているなどのような、今まで直接お金にはならなかった食に対する情熱や熱量、その裏側にある想いがトークンを使うことで巡る世界。自分のラーメンに費やす熱量がコミュニティに承認される。自分がほんとにいいと思って作った食べ物がコミュニティで広まる。Verooは単なるSNSアプリではなく、クリエイターたちの想いが紡がれるソーシャルグルメアプリです。

##### Homepage: https://veroo.xyz/
##### Discord URL：https://t.co/VoT0gpsflA
C++で複数の型を同時に扱う

自らを責める地獄のアドカレ一日目です。

https://qiita.com/advent-calendar/2022/shiro

## はじめに
C++で複数の型を一つのポインタで同時に扱いたいと思ったことはありませんか？私はありました。
設計を変えて型それぞれに別のポインタを割り当てたほうがいいとは思いますが、どうしても複数の型を一つの変数で扱いたいときのための備忘録のようなものです。

## 方法
- std::anyを使用する
- unionを使用する

## std::anyを使用する
### std::any
std::anyとは様々な型の値を動的に保持できる標準ライブラリのクラスです。
一般的なユースケースではこちらで十分です。

https://cpprefjp.github.io/reference/any/any.html

### 具体例
```c++
std::any value;
value = int(5);
try {
    int i = std::any_cast<int>(value);
    printf("%d\n", i);
} catch (std::bad_any_cast& error) {
    // キャストできなかった際のエラー
}
```

## Unionを使用する
### Union
unionは複数の型をstructのように扱う方法です。
structとは違い、すべての変数は同じメモリで管理され、メモリのbyteを共有しています。
### std::anyと比べる
std::anyと違い、内部の変数の寿命を完全に制御することができ、また参照の扱いもstd::anyと比べ複雑ではありません。
しかし、std::anyを使用した方が安全な場合も多いと思います。
unionを使用するのは高度な制御を要求された場合のみにした方が良いかと思います。

### Unionでint型とchar型を同時に扱う例
```c++
union int_char{
  int i;
  char c;
};
```
これで、intとcharを同時に扱うint_char型を定義できました。
このあとは、普段通りにint_char型を使うことができます。扱いとしては、int型とchar型を合わせたようなもので、int_char+intのような演算をすることもできます。

### int_char型の操作

:::note warn
コメントでご指摘いただいたようにintとcharのunionでintの値を操作しcharの値を表示するような方法はあまり推奨されません。int型のbyteの並びは環境依存です。あくまで、intを操作したらcharも変わっていることを表現するためのコードです。
:::

```c++
int_char x;
x.i = 0;

x.c = 'c';
printf("%c %d\n", x.c, x.i);  // c 99

x.i++;
printf("%c %d\n", x.c, x.i);  // d 100
```

このように、int型としてもchar型としても扱えます。99からint型の値をインクリメントすると、char型の値はintと同じ値を参照しているので、100のcharに対応する'd'が出力されます。
このコードで`x.i = 0;`を入れているのは、char型が1byteに対して、int型が4byteなので、int型に合わせ変数xのために、4byte確保されますが、このまま`x.c = 'c';`を代入すると、1byte目以外のbyteは初期化されない状態なので、int型に0を入れることで、4byte分初期化しています。
この、最大サイズの型にあわせて初期化をしなければならないのが、Unionの落とし穴かと思います。

### 具体例

実体をstd::byteでもつValueクラスのサンプル
あくまでサンプルです。int型,double型等の数値型以外からの代入は想定していませんし、安全性もあまり考慮していません。
```c++
class Value {
  size_t size;
  byte* data;
public:
  // メンバ変数dataにT型から代入する
  template <class T>
  void set(T val) {
    union {
      T val;
      byte b[sizeof(T)];
    } union_byte;
    cout << sizeof(T) << endl;
    union_byte.val = val;
    data = union_byte.b;
    size = sizeof(union_byte);
  }
};
```

## まとめ
- c++で一つの変数で複数の型を扱うためには基本的にstd::anyを使うとよい。
- より複雑な管理を行いたいときはunionを使う。
- unionを扱うときは一番大きなサイズの型で初期化を行う。
クロージャーのキャプチャを簡単にまとめてみた＃1

## はじめに
「クロージャ内」では「スコープ外」の変数や定数の値を参照し保持する機能がある。という一部の機能に関しての記事である。

## 詳細
1. 「クロージャー内」では「スコープ外」の変数や定数の値を参照し保持する機能がある。
2. （ちなみに）キャプチャするのは値のことではなく、スコープ外にあるキャプチャされた変数や定数自身をキャプチャする
```swift:Swift
let greeting: (String) -> String

//doは新しくスコープを作る機能がある。
do {
    //doスコープの中の定数symbol。そのため、本来、doスコープ外では値を参照できないはず。
    let symbol = "!"

    //定数greeting（クロージャーの型定義）はグローバル定数なためどこからでもアクセス可能
    greeting = { user in
        //ここに注目
        //greeting内でsymbolを「キャプチャ」
        return "Hello, \(user)\(symbol)"
    }
}

//インスタンス化
//greetingクロージャーの引数userの文字列を定義する
greeting("山田") // "Hello, 山田!" <- キャプチャしたsymbolの値もしっかり出力されている

//symbol出力
//クロージャーにキャプチャされていないdoスコープ内にあった普通の定数
print(symbol) // Cannot find 'symbol' in scope <- symbolはスコープ内で見つけることができないエラー
```

## おわりに
スコープ外の変数や定数でもクロージャ内でキャプチャすれば値を参照し保持する。
記事についてご指摘がある方はぜひコメント欄にてご指摘いただけると幸いです。

## 参考記事
[[増補改訂第3版]Swift実践入門 ── 直感的な文法と安全性を兼ね備えた言語 (WEB+DB PRESS plusシリーズ)　](https://www.amazon.co.jp/%E5%A2%97%E8%A3%9C%E6%94%B9%E8%A8%82%E7%AC%AC3%E7%89%88-Swift%E5%AE%9F%E8%B7%B5%E5%85%A5%E9%96%80-%E7%9B%B4%E6%84%9F%E7%9A%84%E3%81%AA%E6%96%87%E6%B3%95%E3%81%A8%E5%AE%89%E5%85%A8%E6%80%A7%E3%82%92%E5%85%BC%E3%81%AD%E5%82%99%E3%81%88%E3%81%9F%E8%A8%80%E8%AA%9E-PRESS-plus%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA/dp/4297112132)
↑引用元
石川 洋資 (著), 西山 勇世 (著)
発行者：片岡 巌
出版社：技術評論社
印刷/製本：日経印刷株式会社

## 開発環境
- Xcode-13.4.1
- Swift version 5.7
iOS UIScene.willEnterForegroundNotificationやUIScene.didEnterBackgroundNotificationはアプリスイッチャーに行った・から戻った　時は呼ばれない

A. アプリをアプリスイッチャーに移しただけで端末のホーム画面まで行ってない時は、UIScene.didEnterBackgroundNotificationが呼ばれずUIScene.willDeactivateNotificationのみ呼ばれる。またアプリスイッチャーからアプリを前面に戻した時は、UIScene.willEnterForegroundNotificationが呼ばれずUIScene.didActivateNotificationのみ呼ばれる

-> そのため、UIScene.willEnterForegroundNotificationやUIScene.didEnterBackgroundNotificationを購読しているだけでは、うまく通知を受け取れないことに注意。
        
B. アプリをバックグラウンドまで戻し端末のホームまで戻ると、UIScene.didEnterBackgroundNotificationとUIScene.willDeactivateNotificationが両方呼ばれる。アプリを端末のホーム画面から全面に戻した時は、UIScene.willEnterForegroundNotificationとUIScene.didActivateNotificationが両方呼ばれる。

参考:[iOS 13 起動時／終了時メモ](https://qiita.com/katafuchix/items/17b7c6baf1004c41bf88)
[Detect iOS app entering background](https://stackoverflow.com/questions/34744783/detect-ios-app-entering-background)
テスト業界未経験からテストリーダーを経て学んだこと💪





AIQVE ONE Advent Calendar8日目🌟を担当する@mutayshです！
最近は寒さも増して年末やな～🎍と感じるところです。
今年は、みなさんどんな2022年でしたか？少しずつ振り返るのもいいかもしれませんね。

"振り返る"といえば、みなさん初めてした経験、初めて教えて貰ったことその時の感情などを覚えていますか？
今日の記事は、『テスト業界未経験からテストリーダーを経て学んだこと💪』をお送りします！

私のことを少しお話します。
# 未経験からテスト業界へ🏃‍♀️

2021年2月に未経験でテスト業界に飛び込みました。
まず、テスト業界の存在を知らない普通のゲーム好きで右も左も分からずに入社しました。
大体の方はテスターから始まりリーダー又は、設計・自動化のチームなど成長していくのですが・・・

私の場合は、少し変わっています。
修行です:lifter_tone3:修行期間が私にはありました。
自動化や設計など幅広くお話ができるリーダーになることを目的とし福岡に修行に出たんですね。
関西から出たことない人間が九州にいきなり出るんですよ。序章ー修行開始-って笑


# 修行から感じたこと💭
修業期間中は、自動化と設計の研修を受けさせてもらいひたすら自動化を組む！
自動化の課題をもらっては作成する日々をこなしていました。
また関西に帰ってからも、案件取得のためのお仕事や資料など管理業務のことを教えてもらうのですが・・・
**1年目はリーダーとしてアサインする案件に上手くあたれなかった**んです。(タイミングがあるので仕方ない)
さぁ！いざって時に学んだことがすぐに実践・発揮できなかったんですね。**下積みだけしてる状態**


その日々の中で、**教えられてきたことが何に活かせるのか今何をしているのか分からない(点が線になっていない状態)**
ずっとモヤモヤした日々を送った1年になるんですね。この経験やテストリーダーを経て学んだことをこの記事でお伝えしたいことがあります💡



:::note info

**:writing_hand_tone2:学んだことに無駄はない**
**:sunny:ベターではなくベストな選択を**
**:tools:失敗を恐れるな！結局はリカバリー(問題解決能力）**
:::


# 学んだことに無駄はない-何故？を追い続ける-

2年目にアサインした案件では、はじめてリーダー業務を行いました。
リーダーをした際に、管理業務・自動化・設計と教えてもらった内容に関して**点で認識していたことが線で繋がった**んですね！なんのためにやるのか、何故この工程がいるのか？教えてもらうだけではピンと来なかったことが実践を経て初めて実感しました。

現在勉強をしていてこれがなにに活きるのかピンとこないっていう人もいると思います。
ですが積み重ねることで必ず活かせる時が来るので、それまで学ぶ物事に関して
**「何故」「どうして？」という疑問と理由を常に追い続けて**ほしい。
考えることで答え合わせができるタイミングが必ずきます。

# ベターではなくベストな選択を

1年目の修行の最中
この方法この考えはベストなのか？という疑問がありました。
例えば自動化
**💭このスクリプトってベストなのか**
**💭ベターなスクリプトは組めたとしてもベストなスクリプトなのかどうか**
(見やすさやシンプルさ綺麗なスクリプトなのかどうか)

これは、案件でも生活でも何にでも活かせる考えだと思います。
物事の選択に対して、ベストな選択を積み重ねる事で1ヶ月後～1年後には今より成長した自分に会えると思います。
また考える機会が増えることで物事の選択肢の幅が増えていきます💡

私はゲームをしてる時に考えていること
勝つためにベストな戦略？バランスは？攻める？守る？
今の自分の実力は？武器と自分の相性は？実力を上げるためには基礎練習etc..
そんな考えを仕事や生活に落とし込んで考えています！
何事にも楽しんで今自分ができるベストな選択をしていって欲しいです。


# 失敗を恐れるな結局はリカバリー(問題解決能力)
これは、1年目2年目でも付き纏っていました。
**「失敗したらどうしよー・・・:sob:」**
これはいまだに、私を悩ませてるものでもありますが笑
やったことないこと初めてのことに対して、誰でも失敗を恐れてしまうと思います。
ここで伝えたいことは、**失敗していい**ということ**失敗したことない人間はいない**ということです。
テスト業務など特にですが、予定を組んで予定通りになんていかないものなので
その際に**大切なことはリカバリー**上手く復旧出来たらいいだけの話です。

**失敗したらどうしよう➡何かあった時に先読みしてリカバリー案を考えておこう！**　
不安な気持ちに対して、リカバリー案を考えよう！というプラスの考えになれば極論恐れることはないと思います。
今、不安な気持ちが多いと感じている人が少しでも気が楽になってくれればと思います！（ここでもベストな選択を）


# おわりに
私が『テスト業界未経験からテストリーダーを経て学んだこと💪』になります。
ざっくりと拙い文章でしたが・・・
少しでも読んでくれた人のモチベーションや何かの気づきになるきっかけになってくれればと思います。
読んでいただきありがとうございました。
寒さに気を付けてお過ごしください⛄以上、@mutayshでした！
【AWS】インスタンスプロファイルと紐付いているEC2インスタンスをスムーズに確認する方法とは？

## はじめに
AWSCLIを用いて、インスタンスプロファイルと紐付いているEC2インスタンスをスムーズに確認する方法について書きます。
どのEC2インスタンスにどのインスタンスプロファイルが紐付いているのかをすぐに確認したい場合に使える方法になります。

## 環境
- 今回使用するAWSCLIのバージョン情報

```
% aws --version
aws-cli/2.7.31 Python/3.10.6 Darwin/21.4.0 source/x86_64 prompt/off
%
```

## 作業手順

### 1.対象のインスタンスプロファイルを確認する。

- 以下のコマンドを用いて確認する。
    - `インスタンスプロファイルのarn` と `Role名` を抽出することが可能。

```zsh:コマンド
aws iam list-instance-profiles | jq -r '.InstanceProfiles[] | [.Arn, .Roles[].RoleName] | @csv' | tee tmpRole.csv | cat
```

```zsh:実行例
% aws iam list-instance-profiles | jq -r '.InstanceProfiles[] | [.Arn, .Roles[].RoleName] | @csv' | tee tmpRole.csv | cat
arn:aws:iam::<AWSアカウントID>:instance-profile/<Role名>,"Role名"
arn:aws:iam::<AWSアカウントID>:instance-profile/<Role名>,"Role名"
arn:aws:iam::<AWSアカウントID>:instance-profile/<Role名>,"Role名"
%
```

※インスタンスプロファイルに設定している許可ポリシー等の詳細情報を確認したい場合は、AWS Console にて以下を確認。

```
IAMダッシュボード -> ロール -> 対象のロール
```

### 2.IAMロールと紐付いているEC2インスタンスを確認する。
以下のコマンドを実行します。

```zsh:コマンド
aws ec2 describe-instances --region ap-northeast-1 | jq -r '.Reservations[].Instances[] | [.IamInstanceProfile.Arn, .InstanceId, (.Tags[]?|select(.Key=="Name").Value)] | @csv' | tee tmpEC2.csv | cat
```

- こちらのコマンドにて、インスタンスプロファイルに紐付いているEC2インスタンスの一覧を表示させることが可能。
    - `インスタンスプロファイルのarn`、`EC2インスタンスのID`、`EC2インスタンス名` を抽出することが可能。
    - EC2インスタンス名は、Nameのタグ付けをしている場合のみ抽出することが可能。

```
% aws ec2 describe-instances --region ap-northeast-1 | jq -r '.Reservations[].Instances[] | [.IamInstanceProfile.Arn, .InstanceId, (.Tags[]?|select(.Key=="Name").Value)] | @csv' | tee tmpEC2.csv | cat
"arn:aws:iam::107500286332:instance-profile/<Role名>","<EC2インスタンスのID>","<EC2インスタンス名>"
```

## 参考
https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html

https://docs.aws.amazon.com/cli/latest/reference/iam/list-instance-profiles.html

https://dev.classmethod.jp/articles/export-list-ec2-iamrole/
ion-searchbarでcloseボタンのアクションをユーザフレンドリーにする方法

Ionic Frameworkを使っていると、 `ion-searchbar` を利用する場面も多いでしょう。多くのリストから絞り込む用途に使われることがほとんどなのですが、実際ユーザとして使っているとひとつの問題があります。それは、closeボタンを押下しても、 `ion-searchbar` にフォーカスされたままの状態になることです。

![49f09cc0f0d654254dcda801df5f32aa.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100460/b32ff1ba-d2cf-be8c-1bac-2e22a7d9ad41.gif)

closeボタンを押下しても、カーソルが残っていることがわかるかと思います。これは外部キーボードを利用している時は問題になりませんが、モバイルデバイスでオンスクリーンキーボードを利用してる時は問題になります。

__closeボタンを押下してもオンスクリーンキーボードは立ち上がったままです。__

もちろんこれにはシナリオが2つあります。

- 入力内容をすべて消去して、別のキーワードを入力したい
- 入力内容をすべて消去して、すべてのリストを表示したい

前者だとキーボードが立ち上がったままなのは問題ありませんが（Twitterの絞り込み検索のような場合）、在庫管理などで一時的に絞り込むシナリオを描いていた場合は、そのシナリオに沿うとユーザは

1. closeボタンを押下したあと
2. どこか別のエリアをタップしてフォーカスを外してキーボードを非表示にする

というプロセスを踏むことになります。これは手間ですよね。

なので、後者のシナリオの場合はこのように実装しましょう。

```html
<ion-toolbar>
  <ion-searchbar
    (ionClear)="searchbarBlur()"
  >
</ion-toolbar>
```

```typescript
public async searchbarBlur() {
  setTimeout(() => (document.activeElement as HTMLElement).blur(), 100);
}
```

`document.activeElement` は、DOM内で現在フォーカスを持っている要素を返します。

https://developer.mozilla.org/ja/docs/Web/API/Document/activeElement

またsetTimeoutをいれているのは、closeボタンをタップすることにより `ion-searchbar` もタップしたことになり、ミリセカンド秒後にフォーカスがあたるので、必ずフォーカスが当たったあとにフォーカスを外すためです。

これで、closeボタンをタップしたらフォーカスが必ず外れて、キーボードが非表示になるようになりました。簡単ですね。

それではまた。
zipを使った中間テーブルへのレコード追加

コードそのままはやばそうだからテーブル名とかは変えてる。
```ruby:controller
def create
    answer = Answer.new(answer_params)
    dates = answer.dates
    sc_answers_params.zip(dates) do |status, date|
      answer.sc_answers.build(date_id: date.id, status:)
    end
    if answer.save
      render json: [answer, answer.sc_answers]
    else
      render json: answer.errors
    end
  end
```
createメソッドで親テーブルに値を追加すると同時に子テーブルにも値を追加してる。
buildメソッドで作ってるけどnewメソッドでもいける。ただ、子テーブルに関連レコードを作るときは慣習的にbuildメソッドを使用するらしい。
【Laravel9】リクエストパラメータをちょびちょびキャストする時代は終わり

## 概要
Laravel9から一部パラメータをキャストして取得できるようになりました

```php:bool
$archived = $request->boolean('archived');
```

```php:date
$birthday = $request->date('birthday');

//日付フォーマットも可能
$elapsed = $request->date('elapsed', '!H:i', 'Europe/Madrid');
```

### Laravel9.32で更にキャストできる種類が増えました ← New
> まだドキュメントには記載されてません

```php:integer
$request->integer('some_int_value');
```


```php:float
$request->float('some_float_value');
```


### 参考

https://readouble.com/laravel/9.x/ja/requests.html

boolとdateはドキュメントに記載されてます。

PHP8ならではの、その他Laravel9から色々追加したみたいなので覗いてみてください。
> enumとか

![スクリーンショット 2022-11-28 18.24.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282328/c57742d6-684e-ffe4-bd4f-c7ea39e478c7.png)
インターン中、不採用になった書き方集

不採用になった書き方を追記していきます。

## ruby
### 複数テーブルの値を一気に引っ張ってくる
```ruby:不採用
status_count = Event.joins(possible_dates: :schedule_answers).select("events.*, possible_dates.*, schedule_answers.*").where(id: @set_event.id).group(:status).size
```
```ruby:採用
render json: @set_event.adjust_show_json
```
別記事で紹介してる小技のやつを使って、メソッドをモデルに実装した。
不採用になったやつは可読性も低いし、めっちゃメソッド使ってるから処理速度的にもきついかも（わからんけど）。
VS CodeでiOSアプリを開発する方法

# はじめに
XcodeでiOSアプリを開発していると、重くて困ることがあります。文字選択に時間がかかったり、スクロールしただけなのに待たされたり。これではまともに開発できません。そこで、VS CodeでiOSアプリを開発できないかと思って調べていたところ、Xcodebuild Toolsという拡張機能を見つけました。

# Xcodebuild Tools
Xcodebuild Toolsは、VS CodeからiOSアプリをビルドできるようにする拡張機能です。
https://marketplace.visualstudio.com/items?itemName=sterin.xcodebuild-tools

# 手順1： Xcodebuild Toolsをインストール
VS Codeで「Xcodebuild Tools」を追加します。

# 手順2： ios-simをインストール
```
npm install --global ios-sim
```


https://www.npmjs.com/package/ios-sim


# 手順3： プロジェクトをVS Codeで開く　
Xcodeで作成したプロジェクトをVS Codeで開きます。

# 手順4： JSONファイルを追加

```json:.vscode/xcodebuild-tools.json
{
    "variables": {
        "SDK_VERSION": "16.1"
    },
    "sdk": "iphonesimulator${SDK_VERSION}",
    "workspace": "ワークスペースのパス",
    "scheme": "スキームの名前",
    "debugConfigurations": [
        {
            "name": "Simulator",
            "cwd": "${buildPath}",
            "program": "ios-sim",
            "args": [
                "launch", "アプリ名.app/",
                "--devicetypeid",  "com.apple.CoreSimulator.SimDeviceType.iPhone-14, ${SDK_VERSION}"
            ]
        }        
    ]
}
```

# 手順5： 実行🎉
一度ウィンドウを閉じ、再び開くとウィンドウ下部に実行ボタンが現れるのでクリックします。しばらくするとシミュレーターが起動し、あなたのアプリが表示されます🎉

# 注意点　
シンタックスハイライトやコード補完を利用するには、別途拡張機能が必要です。
↓これがおすすめ
https://marketplace.visualstudio.com/items?itemName=sswg.swift-lang


# 参考記事
https://marketplace.visualstudio.com/items?itemName=sterin.xcodebuild-tools

https://www.npmjs.com/package/ios-sim

https://marketplace.visualstudio.com/items?itemName=sswg.swift-lang

---

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

🐦 [Twitter: @shota_appdev](https://twitter.com/shota_appdev)

📱 [個人アプリ: Symbols Explorer](https://apps.apple.com/jp/app/symbols-explorer/id1612933742)
railsでjson出力するときの小技

railsで処理を書いているとき、renderを使用してjsonで処理結果だったりDBのデータを返すことがあると思います。
そんなときに習った小技をメモしておきます。
## 書き方
処理はcontrollerのindexメソッドとかに書くと思います。
でも小技としてはmodelに処理を書きます。
```ruby:event.rb
def adjust_json
    {
      event: {
        id: self.id,
        user_id: self.user_id,
        category_id: self.category_id,
        name: self.name,
        description: self.description,
        is_public: self.is_public,
      },
      dates:
        self.dates.map do |date|
          {
            id: date.id,
            at: date.proposed_at
          }
        end
    }
end
```
```ruby:events_controller.rb
def index
    render json: event.adjust_json
end
```
ファットコントローラーとかの概念的にもコントローラーに書く処理は少なくするってのがいいらしい。
今回書いた処理は親テーブルと子テーブルの関係の関係があってそのデータも引っ張ってくる。子テーブルから複数レコードの値を引っ張ってくるのはmapメソッドを使って引っ張ってくる。


## 参考URL
https://engineer-first.net/fat-controller-workarounds
PythonでOpenImageIO(OIIO)を使ってlinearな色空間をsRGBに変換する

# 自己紹介
株式会社digitalbigmoのパイプラインエンジニアの小池@plinecomです。

# これは何？
OpenEXRを単純にJPEGにすると暗くなってしまうことがある。大体の場合、OpenEXRがLinearでJPEGがsRGBを要求するからだ。その辺をいい感じにしてくれる関数がOpenImageIOにあるので、使い方を記録する。


# とりあえず、コード
```python:main.py
import OpenImageIO as oiio
import glob

if __name__ == '__main__':

    for path in glob.glob('/foo/bar/*.exr'):
        print(path)
        jpg_path = path.replace('.exr', '.jpg')

        #Read File
        buf = oiio.ImageBuf(path)

        #Convert ColorSpace
        dst = oiio.ImageBufAlgo.colorconvert(buf, "linear", "sRGB")

        #Write File
        dst.write(jpg_path)
```

# 必要なPython外部モジュール
* OpenImageIO
* NumPy

Dockerfileも用意した。
```Dockerfile:Dockerfile
FROM rockylinux:8
RUN dnf install -y which python3 epel-release
RUN dnf config-manager --set-enabled powertools
RUN dnf install -y python3-openimageio python3-numpy
```
```terminal:terminal
docker pull plinecom/py_oiio
```

# コードの説明

## 色空間の変換方法の指示
```python:
        #Convert ColorSpace
        dst = oiio.ImageBufAlgo.colorconvert(buf, "linear", "sRGB")
```
とても単純にlinearをsRGBに変換している。

# 宣伝
株式会社digitalbigmoでは美肌プラグインの販売や映像VFXの制作業務を行なっています。ご興味のある方は、webページを見にきてください。一緒にお仕事しましょう。

https://digitalbigmo.com

# 参考文献
[OpenImageIO本家（英語）](https://sites.google.com/site/openimageio/home)
[OpenImageIO本家リファレンス（英語）](https://openimageio.readthedocs.io/en/latest/imagebufalgo.html#color-space-conversion)
実体験：アウトプットは大事は、本当か？？

![24315561_s.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23130/9a41cd99-24d3-7f1b-7261-24bd9e5de963.jpeg)
CTO歴２０年以上、エンジニアとしても３０年やってるとインプットする事が少なくなってきます。いや、実際はインプットする事が少なく感じてきます。

# インプットが少なく感じる理由
喜怒哀楽が無くなったのが理由。　若い頃は、知らない事だらけなので色んな事が新鮮で、関心したり難しく感じたりします。難しい問題に直面すると少し恐怖を感じたり、不安になったりしますが、それが解決すると喜びを感じます。時にミスをすると自分に怒りがこみ上げたり、悲しみ暮れるときもあります。
こういう時ってインプットしてるなぁと感じます。新しい事がなくなってくるとインプットがなくなると感じる一番の理由です。
旅行に行く時、行く時は知らない道で分からない事ばかりなので、長く感じますが、帰り道は、結構短く感じる。
あの現状、**ジャネーの法則**というみたいです。

# ジャネーの法則
人は経験したことがないことをやっているときは、それが強く意識に残り時間が長く感じます。反対に、慣れてしまうと時間の長さが気にならなくなり、あっという間に時が過ぎたように感じます。

# ２０２２年１１月からは沢山記事書いてます。
現在、エンジニア顧問等をやってますが、今後の人生、エンジニアを育てたいと思うようになりました。
その手始めとして、記事を沢山書いていこうと思いました。先ずは年内に１００記事を目標にしてます。
昔、IMJに居た頃はブログを書いてましたが、最近、アウトプットをしてませんでした。**ジャネーの法則**の通り、新しい事が無く、書くネタが思いつかなかったからです。
かなりハードルが高いと思いますが、やった事のない事にチャレンジしてみて何かが見えるかと思って始めてます。

# アウトプットは大事は本当だと思う
年内に記事１００なので月に５０記事を書く必要があります。このためにはインプットが必要です。決めたからには、がむしゃらにインプットするしかありません。
これを機会にKindle Unlimitedの読み放題に登録しました。このサービスは過去に何度か登録した事はあるのですが、月に１００冊とか本が読めます。今月も１００冊くらい読みました。
真剣に読んでるわけではなく、流し読みです。基本、本の内容も新鮮味を感じる事がなかったのですが、今回の読み方は、キーワードを見つけて、そこからネットで調べて知識を深めていく。そんな感じでドンドンと勉強のスパイラルに回してます。そして、勉強した内容と自分の知識がくっつくと良い感じのアウトプットが出来上がります。
更に本からは、考え方も学んでます。一つの物事の説明でも人によって言葉が違います。これは色んな人と会話してるのと一緒で非常に参考になります。

# 最後に
アウトプットに向かうためには色んなインプット、勉強が必要となります。
あらためて無理やりでもアウトプットしていくのは大事だと感じました。
今後も続けていきますので、フォロー、イイね、シェアお願いします。
下記、説明会もご参加下さい。
[エンジニア年収アップ講習(転職サポート付き！)　無料説開会　12月6日　19時開催](https://cto-can-be.hp.peraichi.com/)
pythonanywhere.comで自作アプリ公開

PythonとFlaskで作ったウェブアプリをレンタルサーバーで公開しようとしましたが、エラーの対処が難しくpythonanywhere.comで公開することにしました。

エラーが出たのは、コアサーバーです。
V1プランですが、サポートに確認したところpipは、利用者に権限が無いと言われました。
また、Flaskもnotebookも使えないと言われてしまいました。
ネットでコアサーバーでPythonで作ったアプリを公開する記事をみかけましたが、挑戦される方は、注意が必要です。

Pythonでアプリを作る手順はたくさん公開されていますが、デブロイしたり、アプロを公開したりする手順の記事が少ないように思えたので書きました。

こちらの記事を参考にしました。

https://qiita.com/dem_kk/items/92c16ebbe3bfba669025

デブロイするファイルをまとめたZipファイルを解凍するときは、予めアプリのフォルダを作っておいてから解凍すると良いです。


下記のコマンドで、仮想環境に入ることができました。
```bash 
. app/bin/activate
```
.の後にスペースが、必要でした。

```bash 
~/.virtualenvs
```
のディレクトリの中で、起動しました。
実は、思うように仮想環境に入れなかったので、ディレクトリを移動していたのです。

仮想環境から抜けるときは、
```bash
deactivate
```
で終了できます。

## pythonanywhere_com_wsgi.pyの書き方
私は、Pythonのプログラムをapp.pyとして、HTMLのページやプログラムの処理を行う形で作りました。
そのため下記のように入力すると、左側に黄色の三角のマークが付いてしまいます。

project_home = '/home/***/uma/'の部分で、umaの後ろに/を付けてください。
私は、この/が無いために、数時間悩みました。

![スクリーンショット 2022-11-28 174607.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20977/7f012ee6-b42c-b962-1120-ba950c3bd64d.png)


 
```py
# add your project directory to the sys.path
project_home = '/home/***/uma/'
if project_home not in sys.path:
    sys.path = [project_home] + sys.path

# import flask app but need to call it "application" for WSGI to work
from app import app as application # noqa
```

この注意マーク？が出ていても、ウェブサイトの公開ができました。
レスポンシブで、表示できます。

https://masaru21.pythonanywhere.com/

今回のプログラムの制作にあたり、下記のページの作者の方が作られた漢字の画数のファイルを使用しました。

https://qiita.com/kuroge/items/cc6c8167d7b9f06a1aef#comment-fa64c9c4930de0b6d7c6

この出会いに、感謝しています。
ありがとうございます。
Cypress でキー入力(type) の Delay を無くす

# 概要

Cypress におけるキーボード入力用の API である `type` は、デフォルトで1文字入力ごとに 10ms の待機が発生し、長文を入力する場合にテストが遅くなってしまうことがあるので、これを解消する。

# バージョン

- `cypress`: 11.0.0

# コマンドごとに Delay を設定する

`type` メソッドのオプションを設定すればOK

```javascript
cy.get('input').type('Hello, World', { delay: 0 })
```

# テスト全体でのデフォルト値を変更する

`cypress/support` あたりの設定ファイルに記述すればOK

```javascript
Cypress.Keyboard.defaults({
  keystrokeDelay: 0
})
```

# 参考

https://stackoverflow.com/questions/68190643/how-to-type-a-very-long-string-for-testing-an-input-box-in-cypress
Salesforceでフローを作成しよう～キャンペーンメンバー作成時にリード項目更新

Salesforceでフローを作成しましょう

今回はキャンペーンメンバー作成時に最新のキャンペーンメンバーのリード項目に更新するフローです

リードは参考までに姓項目を更新します

フローは以下のようになります

![フロー01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/7d047693-26a1-683b-b937-9eb33bbae54c.png)

![フロー02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/37d9cb3e-6a24-f66c-a34d-0ad6d655a8f7.png)

![フロー03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/10acce95-1f22-1207-22de-d80914a914d7.png)
ExpoでstagingビルドをTestFlightする時にはアプリアイコンを変えるとわかりやすい

# やりたいこと
- Expoで開発中、staging向きのビルドをApp Store Connectにアップロードし、TestFlightをつかった確認をよくする
- しかし、どのビルドがstaging向きで、どれが本番向きかがパッ見とで区別がつかない
- 区別がつかないと、うっかりミスをいつかやってしまうかもしれない
    - 間違ってstaging向きのビルドを公開してしまうとか
    - stagigだと思って操作してたら本番だったりとか
- そこで、App Store Connect上でぱっと見でstagingビルドなのか本番ビルドなのか区別がつくようにしたい
- 今回はstagingと本番でアプリアイコンを変えるというアプローチを紹介する

![スクリーンショット 2022-11-28 17.14.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268579/1febeee5-f90f-b7f1-f5d7-5e771d8e8178.png)
↑何もしないとどれがstagingビルドかこれだけだとわからない・・・

![スクリーンショット 2022-11-28 17.23.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268579/826b466b-6dec-c029-82a0-4a203b87a583.png)
↑アイコンがグレーのものがstagngビルド。こうすれば一目瞭然

# app.config.tsで環境に合わせてアプリアイコンを設定する
Expoでアプリの諸々の設定が書かれた[app.jsonはapp.config.tsから動的に設定することができる。](https://docs.expo.dev/workflow/configuration/)(jsで書いてる場合はapp.config.js)

[build numberを動的に変更したりもできる](https://qiita.com/0ba/items/22fb052e1c3737295b2a)

環境ごとにアイコンを変えるためにはこのようにする。
process.env.APP_ENVでビルドの環境ごとにiconのパスを変えている。
androidの場合はadaptiveIconを書きかえる必要があるので注意


```app.config.ts
export default ({ config }: ConfigContext): ExpoConfig => {
    // 通常のアプリアイコンのパス
    let icon = "./assets/icon.png"
    let adaptiveIcon = "./assets/adaptive-icon.png"
    switch (process.env.APP_ENV) {
        case "staging":
            // staging用のアイコンのパス
            icon = "./assets/icon-stag.png"
            adaptiveIcon = "./assets/adaptive-icon-stag.png"
            break;
        case "production":
            break;
        default:
            break;
    }
    return {
        ...config,
        name: config.name ?? "",
        slug: config.slug ?? "",
        // 上書きする
        icon: icon,
        android: {
            ...config.android,
            // 上書きする
            adaptiveIcon: {
                ...config.android.adaptiveIcon,
                foregroundImage: adaptiveIcon,
            },
        },
    }
};
```

あとはpackage.jsonのビルドスクリプトをこんな感じに書き換えて
```package.json

"scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web",
    "eject": "expo eject",
    "build:ios:stag": "eas build --profile staging --platform ios --auto-submit-with-profile=staging",
}
```

`build:ios:stag`を実行すればよい。
`--profile staging`オプションをつけることで、process.env.APP_ENVが`staging`となる。
`--auto-submit-with-profile=staging`をつけることで、そのままApp Store Connectにビルドをアップロードしてくれる。



# まとめ
環境ごとにアプリアイコンを変えればうっかりミスを防止できてよい！

もちろんインストールした時にもアイコンで環境の区別がつくのでわかりやすい。
![IMG_0022.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/268579/208a19b9-5f4b-d6c5-f908-02f3cc2d408f.png)

ちなみにこのアイコンのアプリは↓で紹介してます。
[【個人開発】「後で」返事ができる文通チャットアプリ「レイター」を作った話：技術編](https://qiita.com/0ba/items/2dc7eb1e7f16289ae739)


Twitterもやってるので、よければフォローお願いします。
→https://twitter.com/ObataGenta
【Rails】引数は必要な分だけ渡すかまるごと渡すか【リファクタリング】

## 環境
Rails 6.1.3.1
ruby 2.7.1
mysql Ver 8.0.26

## 前提

(1)User -> (多)Attendance


## before
```create_or_update_time!```はざっくり言うと
・idがなかったら新規登録
・idと時間の指定があったら特定して更新
・idはあるが時間が指定がなかったら削除
を行うメソッド。

この場合、```create_or_update_time!```メソッドに引数を必要な分3つのみ(```parameter[:punch_in]```と```parameter[:date]```と```parameter[:type]```)渡している。
引数が3つというのが少し多い気もするが、必要な分の引数を渡す方法で一見良いような気がする。

```ruby
parameter = {
    id: employee.id,
    punch_in: { id: 1, value: '11:30' },
    type: 'home',
    date: '2022/10/01'
    month: '2022-10',
}

create_or_update_time!(parameter[:punch_in], parameter[:date], parameter[:type])

# models/user.rb
def create_or_update_time!(parameter, date, type)
    time = parameter[:value]
    attendance = attendances.build(type: type, date: date) if parameter[:id].blank?
    attendance = attendances.find(parameter[:id]) if parameter[:id].present?
    attendance.update!(punched_at: "#{attendance.date} #{time}".in_time_zone) if time.present?
    attendance.destroy! if time.blank?
end
```



## after

```create_or_update_time!```に引数```parameter```をまるごと渡した。
理由は、
**before**の第1引数```parameter```が入れ子になっており一段階取り出す必要があるが、第2引数```date```と第3引数```type```は```parameter```の値をそのまま使っているため。
3つある引数のうち、1つはもう一段階取り出すのが感覚的に気持ち悪い感じがするのと、使う側が分かりづらい。

引数は必要な分だけ最小限渡すほうがいいと思っていたが、上記の場合は引数のオブジェクトをまるごと渡す方がわかりやすくていい。

```ruby
parameter = {
    id: employee.id,
    punch_in: { id: 1, value: '11:30' },
    type: 'home',
    date: '2022/10/01'
    month: '2022-10',
}

create_or_update_time!(parameter)

# models/user.rb
def create_or_update_time!(parameter)
    time = parameter[:value]
    attendance = attendances.build(type: parameter[:type], date: parameter[:date]) if parameter[:id].blank?
    attendance = attendances.find(parameter[:id]) if parameter[:id].present?
    attendance.update!(punched_at: "#{attendance.date} #{time}".in_time_zone) if time.present?
    attendance.destroy! if time.blank?
end
```
CSSテクニックまとめ（初級～中級編）


# CSSテクニック

今回はCSSの初心者～中級くらいの小ワザを少しですがまとめてみました。
どれもよくWebサイトでみかけるテクニックなので、好きな時に使えるようにしておきたいものです。
備忘録として残していきたいと思います。

## グラデーション

グラデーションは「linear-gradient」というものを使います。
（）内には、変化させたい「方向」、2種類以上の「色」を指定します。
- to right：左から右に色が変化する
- to bottom：上から下に色が変化する
- to right bottom：左上から右下に色が変化する
- 30deg：30度の角度で色が変化する
- radial-gradient：中心から外側に向かって円形のグラデーションを表現する

## 要素を透明にする

「opacity」というものを使います。
値は「1」が不透明で「0.5」が半透明、「0」が透明になります。
[![Image from Gyazo](https://i.gyazo.com/7cd5f292e93b229d76f2df7e2b339350.png)](https://gyazo.com/7cd5f292e93b229d76f2df7e2b339350)

## 要素を好きな場所に配置する

「position」プロパティを使用します。
よく使うポジション指定方法は主に3種類あります。（ポジションの初期値はstatic）
### 「relative」
配置ができる範囲を設定する値。主に親要素に指定し、子要素に「absolute」を指定することで親要素の中を自由に動かすことができます。
この「relative」「absolute」は基本セットで使用します。
### 「absolute」
配置する場所を設定する値。親要素の範囲内で自由に動くことができる。
### 「fixed」
画面に固定しして配置する値。
スクロールしてもついてくるアレです。

## ホバーアニメーション

滑らかに変化させる「transition」プロパティと「セレクタ名：hover」を使います。

変化させたい部分にマウスカーソルを乗せた（ホバー）ときにリストの背景色や文字色など、スタイルを変更できます。
※スマホの場合はタッチしたとき
- transition: all .8s・・・「all」は背景や文字色すべてを対象にし、「.8s」は0.8秒かけて変化させるという意味
- セレクタ名:hover ・・・ホバーした時のスタイル設定

# 最後に
簡易的なものにはなりますが、今回は以上となります。
学習はやはり、インプットだけではなく、実際に手を動かしてコードをとにかく書いていくのが一番身になります。
「こういうのが作りたい」というようなアイデアをネットサーフィンで見つけて、どんどん自己流のサイトを作ってみましょう。

## 学習参考サイト

https://ninjacode.work/


https://koga.ninjacode.site/?ni=q_3
MkDocsで作成した静的サイトをGitHub Actionsを使ってGitHub Pagesに自動でデプロイする

# やったこと
- あらかじめリポジトリは GitHub にあげておく
  - [作業リポジトリ](https://github.com/cleantted/cleantted_github_action_test)
- MkDocs をローカルで使えるようにする
- GitHub Actions が実行できる環境を作る
- GitHub Actions の設定ファイルを追加する
- GitHub Pages の設定を変更する

## MkDocs をローカルで使えるようにする

- MkDocs を pip でインストールして、Hello World する
  - 確認は`http://127.0.0.1:8000/` にアクセスすればできる
```bash
pip install mkdocs
mkdocs new cleantted_action_test
mkdocs serve
```

- 静的コンテンツの作成は以下でできる
```bash
mkdocs build
```

## GitHub Actions が実行できる環境を作る

### Python のライブラリをインストールできる準備をする

- `requirements.txt` を用意する
  - [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/) を使用するので、 `mkdocs-material` も追記する
```requirements.txt
mkdocs
mkdocs-material
```
### GitHub Actions で Pages のデプロイ用の SSH 鍵を用意する

- デプロイ用の SSH 鍵を作成する
```bash
ssh-keygen -t ed25519 -C "$(git config user.email)" -f gh-pages -N ""
```

- ユーザーの SSH keys に公開鍵を登録する
  - ユーザーの「Setting」→「SSH and GPG keys」→ 「New SSH key」
  - 公開鍵を登録する

- リポジトリに SSH 秘密鍵を登録する
  - リポジトリの「Setting」→「Secrets」の「Actions」→「New repository secret」
  - 「Name」を `ACTIONS_DEPLOY_KEY` にして秘密鍵を登録する

## GitHub Actions の設定ファイルを追加する
- `./.github/workflows/` 配下に設定のymlファイルを追加する（名前は任意）
  - master に push されたらデプロイするように設定
```yaml
name: Deploy MkDocs

on:
  push:
    branch:
      - master

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout the repository
        uses: actions/checkout@v3
     
      - name: Install MkDocs
        run: python3 -m pip install -r requirements.txt     
      - name: Deploy HTML files
        run: mkdocs build --verbose --clean --strict
     
      - name: mkdocs deploy
        uses: peaceiris/actions-gh-pages@v3
        with:
          deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
          publish_dir: ./site
```

## GitHub Pages の設定を変更する

- リポジトリのから、Pages ターゲットブランチを `gh-pages` に変更する
  - 「設定」→「Pages」→「Build and deployment」→ 「gh-pages/(root)」を選択して「Save」
  - 補足: `gh-pages` のブランチは Actions を一度実行するとできる

![Pasted image 20221125203943.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190546/c3ff21d0-1170-d6c7-0dac-a71264e01b50.png)

# 参考文献
- [mkdocs+GitHub ActionsでMarkdownベースのドキュメントを作成/公開する](https://taxintt.hatenablog.com/entry/2020/06/07/225215)
- [MkDocs](https://www.mkdocs.org/)
- [GitHub Pages Action](https://github.com/peaceiris/actions-gh-pages)
- [Creating a personal access token](https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token)
- [Encrypted secrets](https://docs.github.com/ja/actions/security-guides/encrypted-secrets)
- [SSH認証に最強の「Ed25519鍵」を使おう](https://linuxfan.info/ssh-ed25519)
- [ゼロから学ぶ Python](https://github.com/rinatz/python-book)
Surface Go 3を2台連続で壊した話

# この記事を書く経緯
　ほぼ全く同じ症状で2台のSurfaceを壊したため。

# ここに来てくれた人へ
　症状が出るようになった経緯をコメントして頂けると嬉しいです。共通点を見つけたい。完全放電なんて無駄だよね。

# 注意事項
　この記事の中での「Surface」は、「Surface Go 3」のことを指します。

# 壊したSurfaceの状態(外観)
　電源を入れると一瞬Windowsロゴが出てくるが、その後、UEFIが起動するタイミングで画面が映らなくなる。
　しばらくするとType Coverのバックライトが光り、Windowsの起動音がする。
　USB Type-CポートにHDMIの変換コネクタを繋ぐと外部モニターに出力できるため、内部でWindowsは動いている。
　タッチ入力とSurfaceペンによる入力は動作していない。
　1台目は画面が映らなくなった日の昼頃にタッチが効かなくなり、夕方に画面が映らなくなった。
　2台目は昼頃にタッチが効かなくなり、その時点でデバイスマネージャーにエラー表示(I2C HID デバイスとNxpNfcClientDriver)、その日の夜に画面が映らなくなった。

　つまり、本体の液晶、Windows共に生きているが、Windowsと液晶の間にある何かの動作がおかしい。→起動時の画面が映らなくなるタイミングも考えるとUEFIの不具合…？

# 壊したSurfaceの状態(内面)
　デバイスマネージャーを見てみると、1台目は
* I2C HID デバイス
* NxpNfcClientDriver　
にエラーが出ていて(エラーコード10、デバイスが開始できません)、モニターが「非汎用PnPモニター」として認識されていた。(正常なSurfaceは「汎用PnPモニター」として認識される)

　2台目は
* I2C HID デバイス
にだけエラーが出ていた。NxpNfcClientDriverにもエラーが出ていた時期があったが、画面が表示されている頃に回復ドライブから再インストールを行うと直った。モニターは汎用PnPモニターとして認識。

# 壊した2台に共通すること
* Windows11 21H2
* bitlockerオフ
* Windowsが起動しているところから、回復→ローカルからWindowsを再インストールしている

# ポイントだと考えているところ
* 「ローカル」から再インストール
　回復ドライブから再インストールを繰り返している友人のSurfaceには症状が現れない、再インストールをしていないSurfaceにも問題はない。
　1台目は再インストール後約1ヶ月で画面が映らなくなった。
　2台目は再インストール後5日で画面が映らなくなった。
　再インストールするだけでは症状は現れず、その後の何かの更新によって不具合が起こる…？

* 「Surface UEFI」は書き換えができない
　Windows Updateから他のアップデートと共にダウンロード&インストールされるが、その後手動で書き換えができない。MicrosoftのWebサイト上で公開されているのは「ドライバ」であって、UEFIではない。

# 2022/11/28時点の予想
　Surfaceをローカルから再インストールすると、「Surface UEFI」に何かしらの不具合が起こり、その後のアップデートによってOS側とハードウェア側の間の連携が取れなくなるのではないか。

# まとめ
　全く確証は無いけれど、とりあえず予想として書いてみました。1台目は購入後約8ヶ月で、2台目は交換(1台目と)後約10日で発生したので、何かしらの不具合を抱えているんじゃないかなぁと思っています。コメントお待ちしております。
MFC から SVG クラスのテキスト呼び出しコードサンプル

## MFC から SVG クラスのテキスト呼び出しコードサンプル
MFC(GDI+) の座標系がグラフ座標系の場合、文字を描くと上下反転した状態で表示されます。
一時的に描画領域を上下反転してテキストを描いて元に戻します。

MFC(GDI+) の場合以下のようになります。
```cpp
	Matrix matrix;
	pGraphics->GetTransform(&matrix);
	pGraphics->ScaleTransform(1, -1);
	FontFamily  fontFamily(L"Times New Roman");
	Gdiplus::Font  font(&fontFamily, 24, FontStyleRegular, UnitPixel);
	PointF      pointF(30.0f, 10.0f);
	SolidBrush  solidBrush(Color(255, 0, 0, 255));

	pGraphics->DrawString(L"Hello", -1, &font, pointF, &solidBrush);

	pGraphics->SetTransform(&matrix);
```
SVG 出力ではテキストを上下反転させる必要はありません。
位置調整のため、MFC で縦幅だけ取得します。
これでも多少ずれると思います。
計算式を編集してある程度調整することもできますが、フォントにより差分が発生してしまいますので完全に対応するのは難しいです。

SvgImage に書き出すと以下のようになります。
```cpp
	FontFamily  fontFamily(L"Times New Roman");
	Gdiplus::Font  font(&fontFamily, 24, FontStyleRegular, UnitPixel);
	PointF      pointF(30.0f, 10.0f);
    Gdiplus::RectF boundingBox(0, 0, 0, 0);
	pGraphSrc->MeasureString(L"Hello", -1, &font, pointF, &boundingBox);
    CPoint pn = CPoint(30.0f, 10.0f + boundingBox.Width / 2);
    COLORREF crColor = Color(255, 0, 0, 255);
	pSvgImage->AddText(pn, L"Hello", 24, L"Times New Roman", crColor, 0, 0);  
```

## テキストがずれないMFC から SVG クラス呼び出しコードサンプル
MFC と SVG で出力される場所がずれない方法がパスによるテキスト出力になります。
パスにベクタ画像として文字列の書き出しを行うことで各頂点の座標を固定します。
この方法であれば SVG が対応していないフォントの描画も可能になります。
ただし、フォントの利用規約で「ベクタ形式で出力したデータの配布を禁止」されていることもあります。
安易に使える方法ではありませんが SVG でテキストを表示する際の利便性が高いためサンプルコードを紹介します。

先述の通り、テキストが上下反転するため Gdiplus::GraphicsPath オブジェクトの座標系を書き込み先の座標系に合わせるため Gdiplus::Matrix で変換します。
座標系はグラフ座標系で統一されますので MFC と SVG でパスを作成するところまで同じコードになります

MFC(GDI+) の場合以下のようになります。
```cpp
    Gdiplus::Matrix matrix;
    matrix.Scale(1.0, -1.0);
	FontFamily  fontFamily(L"Times New Roman");
	Gdiplus::Font  font(&fontFamily, 24, FontStyleRegular, UnitPixel);
	PointF      pointF(30.0f, 10.0f);
	SolidBrush  solidBrush(Color(255, 0, 0, 255));
    Gdiplus::GraphicsPath path;
    path.AddString(L"Hello", -1, &fFontFamily, 0, font.GetSize(),
                   pointF, Gdiplus::StringFormat::GenericDefault());

    path.Transform(&matrix);
	SolidBrush solidBrush(Color(255, 0, 0, 255));
	pGraphics->FillPath(&solidBrush, &path);
```
SvgImage に書き出すと以下のようになります。
```cpp
    Gdiplus::Matrix matrix;
    matrix.Scale(1.0, -1.0);
	FontFamily  fontFamily(L"Times New Roman");
	Gdiplus::Font  font(&fontFamily, 24, FontStyleRegular, UnitPixel);
	PointF      pointF(30.0f, 10.0f);
	SolidBrush  solidBrush(Color(255, 0, 0, 255));
    Gdiplus::GraphicsPath path;
    path.AddString(L"Hello", -1, &fFontFamily, 0, font.GetSize(),
                   pointF, Gdiplus::StringFormat::GenericDefault());

    path.Transform(&matrix);
    Gdiplus::PathData pathData;
    path.GetPathData(&pathData);
    pImage->AddPathData(&pathData);
    pImage->AddAttrFill(RGB(0, 0, 255), FALSE);
```
Azure PortalからWindows Admin CenterでVMに接続する

# はじめに
Azure PortalからWindows Admin CneterでVMに接続できるようなので試してみました。
Microsoftのドキュメントを参考に設定しました。

https://learn.microsoft.com/ja-jp/windows-server/manage/windows-admin-center/azure/manage-vm

# 前提条件
* VMに`Windows Admin Center Administrator Login`ロールが付与されていること
* 送信インターネット アクセス、または WindowsAdminCenter および AzureActiveDirectory のサービス タグへの HTTPS トラフィックを許可する送信ポートの規則が許可されていること
* パブリック IP アドレスを使用して VM に接続する場合の受信ポートの規則が許可されていること

# インストール
ネットワーク規則を確認し、必要に応じて追加します。
送信規則は制限なしなのでそのまま。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604991/584f40a4-6e96-f657-b730-3096e428fe7e.png" width=100%>

作業端末からアクセスしたいのでパブリックIPで許可しています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604991/a240750a-bd5f-e99f-6dbd-248067f50143.png" width=100%>

対象VMの`Windows Admin Center(プレビュー)`を選択し、インストールを選択します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604991/c9954fe9-3ba7-3df2-f86e-b86d0f74790a.png" width=90%>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604991/ce2ee55d-a04d-b0fa-664b-514127603bca.png" width=50%>

インストール完了です。
と思ったのですがVMにロールを付与するのを忘れていたため`接続`が選択できません。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604991/c5dfab5c-82c7-10d4-72b7-5522e0ef7e6b.png" width=80%>

`Windows Admin Center Administrator Login`ロールを割り当てます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604991/fd769684-0e55-4440-84f8-0a95e0403eb6.png" width=80%>


# 接続
Windows Admin CenterでVMに接続します。
`接続`を選択します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604991/5a114edd-cd1c-6e18-ae6c-ab90306f3b82.png" width=90%>

読込みに少し時間掛かりました。（初回だけ？）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604991/d3e06f7e-b986-e526-23b5-3745a386c8d6.png" width=80%>

接続できました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604991/0c0a33e7-a589-e536-77a3-e50ff8abb1ee.png" witdh=100%>


試しに更新プログラムを適用してみます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604991/27ec3d18-6971-78ac-f81e-5b5bb52e0846.png" width=100%>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604991/d59f4a34-643b-5d06-8b05-764c4139f24b.png" width=100%>

1つ適用後新たに更新プログラムが増えたのでこちらも適用してみます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604991/08abf34a-ff94-a44e-602b-01a1d2734d6d.png" width=100%>

全て適用できました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604991/ebd815b0-8909-3935-9c11-a1106758cdb3.png" width=70%>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604991/2488bda6-3c9e-1b31-24ff-2a5a2a8dcede.png" width=100%>

ファイルやユーザ情報も見てみます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604991/82d0a1f2-0073-bf63-9567-ea0ab20e6c70.png" width=100%>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/604991/ee3fe3c3-0022-4ece-4425-40286fa54cdb.png" width=100%>


# おわりに
設定がとても簡単でした。
VMにリモートデスクトップ等でアクセスせずにOSの情報が見れたり設定出来るのはとても便利ですね。
運用でうまく使っていけたら良いなと思っています。
AWS CloudFrontについてmemo

## はじめに
アプリケーションのパフォーマンス改善の一つとして
cloudFrontを導入しようとしている。

そのために個人的に調べたことをメモするための記事です

## 参考

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/Introduction.html

## AWS CloudFrontとはなんぞや
静的、動的コンテンツを迅速かつ安全に配信できるコンテンツデリバリネットワーク(CDN)サービス

### CDN とはなんぞや
コンテンツをスピーディーに配信できるようにしたネットワーク。
コンテンツの大容量化が進んでネットワーク負荷が高くなりwebページ表示に時間がかかる、コンテンツダウンロードに時間がかかるという問題を解決する。

##### 仕組みとしては?
世界中にあるエージサーバーから各ユーザーの地理的に近い場所(エッジ)にあるサーバーから配信される。
各サーバーには静的コンテンツがキャッシュされている。

### DNSの設定
通常DNSでAレコードで行き先を設定するが
CDNを利用する場合、
CNAMEレコードを設定することでエッジサーバーにアクセスが向くようにできる

### エッジロケーション
AWSのエッジロケーションとは、AWSのリージョンデータセンターとは別の、コンテンツ配信を行うデータセンターのこと。
ユーザーからのアクセスをエッジロケーションに流すことで
エッジサーバーでコンテンツをキャッシュし、配信の高速化・オリジンサーバーへの負荷軽減を行うことができる

### オリジンサーバー
コンテンツが格納されているサーバーのこと。
EC2だけでなく、S3やELBなどをオリジンサーバーとして使用することができる

### TTL(Time To Live)
キャッシュを保持する期間(秒)の設定。
指定したキャッシュ保持期間(TTL)が経過するまで、エッジロケーションからファイルを提供する。有効期限が切れるとCDNはオリジンサーバーにリクエスを流し、そのデータをまたキャッシュする。
- 短く設定
    - 動的コンテンツを供給することができる
- 長く設定
    - ユーザー側のパフォーマンスは向上する。
    - コンテンツがエッジキャッシュから直接返される可能性が高くなるため。

### ディストリビューション
ドメインごとに割り当てられるCloudFrontの設定のこと。
【Python】インポートするパッケージのパスを通す

importを記述しても対象のパッケージが認識されない場合に、対象パッケージのimport文の前にパス指定を追加する。

```sample.py
import sys
sys.path.append( r"<パッケージのパス>" )
import <対象のパッケージ>
```
FSx for WinでHDDを利用する時はIOPSに注意

# はじめに
[FSx for Windows File Server](https://aws.amazon.com/jp/fsx/windows/)は簡単にCIFSファイルサーバを立てられる便利なファイルサーバマネージドサービスです。HDDを利用すると価格もリーズナブルで、実はHDD/SingleAZの場合Standard S3よりも安く利用できます。一方、HDDはIOPSの制限値が厳しめなので注意が必要です。今回は、機能とIOPSにフォーカスして説明していきたいと思います。

# HDD利用時の価格とIOPS
**ポイント**
スループット予約によりインスタンスとしての最大性能が決まるが、HDDを使う場合は、その前に限界が来る

**説明**
FSx for Winodws File Serverの課金は、スループット予約料、容量利用料とデータ転送料で構成されています。データ転送は他のAWSサービス同様、同一AZ内の通信は課金されません。バリエーションとして、シングルAZ or マルチAZ、SSD or HDDの4パターンに対し、必要なスループットを予約する形となります。（スループット予約による性能値は[FSx for Windows Fileserverパフォーマンス](https://docs.aws.amazon.com/ja_jp/fsx/latest/WindowsGuide/performance.html)を確認してください。）

容量課金の性能
|タイプ|メディア|料金(月額)|スループット(MB/秒)|IOPS|
|:--|:--|:--|:--|:--|
|シングルAZ|SSD|0.156USD/GB|750MB/TiB|3,000/TiB|
|マルチAZ|SSD|0.276USD/GB|同上|同上|
|シングルAZ|HDD|0.016USD/GB|12ベースライン;80バースト/TiB(ファイルシステムあたり最大1GB/秒)|12ベースライン;80バースト/TiB|
|マルチAZ|HDD|0.03USD/GB|同上|同上|

※東京リージョン 2022/11/28時点の情報
※HDDの場合は一定時間バースト値まで利用できますが、バーストクレジットを使い切るとベースラインの速度まで落ちます。バーストクレジットの使用状況は2022/10/12のアップデートで確認できるようになりました。

つまり、2TiBのHDD構成の場合、スループット予約を256Mbpsしても、通常24IOPS(24MB/秒)、最大160IOPS(160MB/秒)しか出ないことになります。

参考)
[FSx for Windows Fileserver利用料](https://aws.amazon.com/jp/fsx/windows/pricing/?nc=sn&loc=3)
[FSx for Windows Fileserverパフォーマンス](https://docs.aws.amazon.com/ja_jp/fsx/latest/WindowsGuide/performance.html)
[FSx for Windows Fileserver 新メトリック情報(2022/10/12更新)](https://aws.amazon.com/jp/blogs/storage/optimizing-amazon-fsx-for-windows-file-server-performance-with-new-metrics/)
[利用料計算ツール](https://calculator.aws/)

# HDD利用時の注意点
上記のように、HDD使用時はインスタンスの性能限界の前にHDDの性能限界を迎えます。特に、IOPSの限界は重複排除が止まってしまったりボリュームシャドーコピーのデータ消失と言った問題を引き起こします。

ボリュームシャドーコピーはWinodws OSの機能で実現されており、変更差分をCopy on Writeで記録していきます。ボリュームシャドーコピーは一瞬でも書き込みが間に合わないと**全ての履歴を失います**。

特に、重複排除スケジュール実行時にIOPS消費が激しくなるので注意が必要です。
（重複排除とボリュームシャドーコピーを同時に利用する時はSSDをお勧めします）

HDD利用でこれらのサービスを利用する時は、新たに見えるようになった、FileServerDiskIOPSUtilization、FileServerDiskIOPSBalanceを監視しておくことをお勧めします。

参考)
[ボリューム シャドウ コピー サービス](https://learn.microsoft.com/ja-jp/windows-server/storage/file-server/volume-shadow-copy-service)
[シャドーコピーの使用](https://docs.aws.amazon.com/ja_jp/fsx/latest/WindowsGuide/shadow-copies-fsxW.html)

# まとめ
HDDはIOPS設定が低いので重複排除やボリュームシャドーコピーのようにIOPSを多く消費するサービスを利用する時はIOPSに注意する。これらのサービスを利用する時はSSD利用を推奨。
表示する行数を指定してselect結果を取得する

統合監査表（UNIFIED_AUDIT_TRAIL）

■最も新しいレコードを10レコード表示する
select EVENT_TIMESTAMP from UNIFIED_AUDIT_TRAIL group by EVENT_TIMESTAMP order by 1 desc fetch first 10 rows only;

■最も古いレコードを10レコード表示する
select EVENT_TIMESTAMP from UNIFIED_AUDIT_TRAIL group by EVENT_TIMESTAMP order by 1 fetch first 10 rows only;
PHPUnit TypeErrorが発生することを確認するテストを書く

# 概要

- テストコードにてTypeErrorが発生することを確認する方法をまとめる。

# 方法

- 下記の様に記載し`expectException()`を用いて確認する。

    ```FooTest.php
    public function test_TypeErrorが出る()
    {    
        $this->expectException(\TypeError::class);
    
        // 確認したいメソッドやエンドポイントの呼び出し
    }
    ```

- ちなみに新しいPHPだと`expectError()`が使えるらしい。

# 参考文献

https://stackoverflow.com/questions/34350734/make-phpunit-catch-php7-typeerror

https://github.com/KEINOS/Practice_PHPUnit-test-of-TypeHint/blob/master/tests/FunctionSayHelloToTest.php

https://phpunit.de/manual/6.5/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.exceptions

https://phpunit.readthedocs.io/ja/latest/writing-tests-for-phpunit.html
360度写真のブラウザでの表示（A-Frame）

THETAや、Insta360、GoproMax等色々な360度カメラが普及しましたが、
数年前に、画像をWebに公開する際の技術選定をした結果を記録しておきます。
（新しいネタではありません。ご了承ください。）

## <360写真が表示できるライブラリ>
- [A-Frame](https://aframe.io/)
- [Google VR View](https://developers.google.com/vr/develop/web/vrview-web)
- [Pannellum](https://pannellum.org/)
- [Babylon.js](https://doc.babylonjs.com/)

その中でも、A-Frameを選定しました。
A-Frameをおすすめする理由は、
- ライブラリで組み込めるので、外部依存しない。
- オープンソースなのでランニングコストかからない。
- HTMLベースで書ける（動きはJSで作るが・・・。）
- **一つのソースで、PCブラウザ、スマホ、スマホVR、VRゴーグルすべてに対応する**。
- ３D空間を作るイメージなので、３Dオブジェクトも扱える＝VRやARにも使える。
（３D空間で、床がなく、空に360度写真を貼り付けたイメージ。死角のないプラネタリウムのイメージ。）

## 一枚の360度写真を表示する例
```
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>360° Image</title>
	<meta name="description" content="360° Image - A-Frame">
	<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
</head>
<body>
	<a-scene>
		<a-sky src="360度写真へのPath.jpg" rotation="0 -90 0"></a-sky>
	</a-scene>
</body>
</html>
```
（360度写真へのPath.jpgはご自身のファイルに合わせてください。）
これだけで360写真表示できます。（A-Frameはnpmでもインストール可能。)
表示されている写真は、平面に見えますが、マウスのドラッグで視線方向を360度自由に変更できます。
お使いの端末が、
- スマホであれば、ドラッグ以外にも端末を傾けること(ジャイロセンサー)で、視線方向を変更できます。
    - 画面右下のVRボタンを押すと2眼VRモードになり、[ハコスコ](https://hacosco.com/vr-goggle/)等の簡易VRゴーグルで見ることもできます。
- Quest等のVRゴーグルであれば、ブラウザでこのWebページを開き、右下のVRボタンを押すと、VRゴーグルの歩行（頭の方向）で視線方向を変えることができます。


ソースコードを簡単に解説
`<a-scene>`でA-Frameの空間を定義
この内
`<a-sky>`今回は360度写真なので、空に360度写真を貼り付けます。

rotationは、X,Y,Z軸の初期回転です。
カメラ機種によって、正面方向が変わるので、Y軸を90度回したりして初期位置（正面）を調整します。
どんな角度で撮影しても、基本的にカメラ側で天頂補正（ジャイロ）が効いているので、
`<a-sky>`に関しては、Y軸角度の調整のみで大丈夫です。
３D空間なので、本当はカメラ位置、ライト位置等ありますが、360度写真なら自身が中心なので、デフォルトでも大丈夫です。

クラウドサービスを使うこと無く、簡単に360度写真を表示できるサイトを自作できました。


## おまけ

360度写真に慣れる「360度写真の中に文字を埋め込めないのか？」となります。
簡単にできます。
sceneの中に`<a-text>`タグを入れるだけです。

```
<a-text font="kelsonsans" value="Hello 360" width="6" position="-2.5 2 -1.5"
rotation="0 15 0"></a-text>
```

ただ、３D空間なので、テキストを置く位置、距離、角度は重要です。
- 位置はposition(XYZ)で指定、前方1.５ｍ左方向2.5m高さ２ｍなら(-2.5,2,-1.5)
    - Z軸（奥行き方向）　プラスは後ろ方向。マイナスは前方向。
    - X軸（横方向）プラスは右方向。マイナスは左方向。
    - Y軸（縦方向）プラスは上方向。マイナスは下方向。
- 距離は、カメラから０距離(位置が、0,0,0)では見えないです。
- 角度rotationは、文字やPNGの場合、視線と水平だとペラペラで見えません。
    （これはカメラ設定後、Look-at-me機能もあります。）

- テキストは、現状英語フォントしか対応していないので、日本語を出すにはフォントを持参する必要があります。
- ブラウザの平面で見ているうちは距離に違和感がないのですが、VRで左右視差（立体感）が有ると距離感が全然違って、調整に時間かかかることもあります。


360度写真を表示することができたので、
Web地図上にマーカーリンク等を作成し、iframe等で３６０度写真を表示すれば、GoogleStreetViewっぽい物を自作することも可能です。
terraformのfor_eachでリソース作る作らない判定をする



やるたびに忘れてしまうので、メモする

## for_each
- 本来、リソースをループ処理をするために使うが、それを利用して「0回ループ」するということをするとリソースを作らないということができる
- `count`でもできるが、リソース名がインクリメントされるため、途中のリソースが削除されると、いっきにずれてしまい、クセがある
    - ただ、単純に作る作らないの判定をさせるということであれば、countのほうがぱっと見わかりやすいかも
- for_eachは、map型のみ受け付ける


## サンプル
```hcl
resource "local_file" "ecs" {
  for_each = lookup(local.params, "ecs", "") != "" ? { for i in local.params.ecs.services : i.name => i } : {}
  content  = lookup(each.value, "name")
  filename = lookup(each.value, "name")
}


locals {
  params = {
    ecs = {
      services = [
        {
          name   = "front"
          cpu    = 512
          memory = 1024
        },
        {
          name   = "app"
          cpu    = 512
          memory = 1024
        },
      ]
    }
  }
}

```

- `lookup(local.params, "ecs", "") != "" ?`
    - `local.params.ecs`のリソースがあれば、`{ for i in local.params.ecs.services : i.name => i }`が実行される
    - なければ、{}が実行。つまり0ループになり、リソースが作成されない
- `{ for ~~~}`で、暗黙的にmap型になっているので、for_eachに渡せる


## 注意
- 上記の場合はもともとlist型のものをforでループさせていたが、list型でないものは、明示的に`[]`などでlist型にしてあげる必要がある
    - （そりゃそうなんだけど、はまったのでメモ）

```hcl
resource "local_file" "rds" {
  for_each = { for i in [local.params.rds] : i.engine => i }
  content  = lookup(each.value, "engine")
  filename = lookup(each.value, "engine")
}

locals {
  params = {
    rds = {
      engine         = "mysql"
      engine_version = "5.7.38"
    }
  }
}
```