OmniAICreator/Qiita-1.07M huggingface dataset:
PHPで変数の型によって条件分岐させる方法

PHPでは、変数の型に応じて条件分岐することができます。以下にいくつかの方法を示します。

## is_*関数を使用する
PHPには、変数の型を判定するための「is_*」系の関数が用意されています。例えば、「is_int」関数は整数型かどうかを判定するために使用されます。

```php
$value = 42;

if (is_int($value)) {
    echo "Value is an integer.";
} else {
    echo "Value is not an integer.";
}
```

## gettype関数を使用する
「gettype」関数は、変数の型を文字列として取得することができます。この文字列を使用して、条件分岐することができます。

```php
$value = 42;

switch (gettype($value)) {
    case "integer":
        echo "Value is an integer.";
        break;
    case "double":
        echo "Value is a double.";
        break;
    default:
        echo "Value is not an integer or double.";
        break;
}
```
このように、PHPには変数の型に応じて条件分岐するための複数の方法があります。使用する方法は、プログラムの要件に応じて適宜選択することができます。
az vm resizeで複数のVMをまとめて実行する方法

# はじめに
意外と便利なやり方だけど手順が見つけるのに苦労したのでメモ残す

# コマンド
あらかじめリソースIDを準備しておくことがコツ。
az vm wait で--upatedで待つのもポイント。

```
$vm1_id="/subscriptions/2a7080ea-1981-457b-aac9-902be7c5f00d/resourceGroups/pro-nabehiro-001/providers/Microsoft.Compute/virtualMachines/nbfr151v"
$vm2_id="/subscriptions/2a7080ea-1981-457b-aac9-902be7c5f00d/resourceGroups/pro-nabehiro-001/providers/Microsoft.Compute/virtualMachines/nbfr152v"

az vm resize --resource-group pro-nabehiro-001 --name nbfr152v --size Standard_B1ls --no-wait
az vm resize --resource-group pro-nabehiro-001 --name nbfr151v --size Standard_B1ls --no-wait
az vm wait -g pro-nabehiro-001 --updated --ids $vm1_id $vm2_id
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416263/98da0c5d-6412-e6fa-57df-3b26c02c9e2c.png)
UnityのCinemachine dollytrackでトラックに沿ってカメラを動かす2023

# はじめに
cinemachineは、カメラを切り替えたりフォローするのに便利なパッケージです。cinemachineの機能の一つにdolly trackと呼ばれる、トラックに沿ってドリーすることが可能な機能があります。
単純に動かそうとするだけでも少しハマったので簡単な使い方手順のメモです。
調べて出てきた記事と少し使い方が変わっている部分があるようなので、ご参考になればと思います。

検証環境
- Unity 2022.2.5
- Cinemachine 2.9.5


# 準備
cinemachineをPackage Manegerからインポートします。
本記事では、単純なMain Cameraとcubeが配置されたようなシーンをもとに説明します。
HDRPのシーンを作成して、cubeを置いただけです。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595566/a2e774d9-a103-509d-904a-46a52c793492.png)

## Dolly camera with trackを追加
Hierarchyウインドウ上で右クリックし、Cinemachine > Dolly Cmaera with Trackを選択します。
すると、自動的にシーンの中にCinemachine Brain、Virtural Camera、そしてトラックが追加されます。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595566/1554f29c-4963-37ee-fd98-40043afbd60b.png)

## トラックを配置
お好みでトラックを配置します。
トラックにWayPointを追加し、経路を設定します。
下記の記事が参考になりました。

https://light11.hatenadiary.com/entry/2019/07/16/210124

とりあえず、円形上に配置してみました。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595566/fc3b3c5c-a3dd-fc94-eb13-86d51e121ede.png)


## Virtual Cameraを設定
Virtual CameraにアタッチされているCinemachineVirtualCameraの中から、トラックに沿ってカメラを動かしていくための設定をしていきます。

まず、今回は常にCubeに注目させたいのでLook AtにCubeを指定します。
CinemachineVirtualCamera>BodyをTransposerに変更します。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595566/1ab31c59-2198-68cc-b0ab-3d357ecd193d.png)


## トラックを動かすスクリプトをアタッチする
CinemachineVirtualCameraにAdd Componentから、スクリプト"Cinemachine Dolly Cart"をアタッチします。
PathにはDolly Trackを、Speedにはカメラを動かしたいスピードの数字を入力します。

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595566/3783009f-be09-52dd-0274-e9fbcef4329a.png)

以上の手順で、私の環境では動きました。
間違いなどありましたらご指摘ください。
ChatGPTがえぐいっていう話

# ChatGPTって？
OpenAIが提供しているチャットでやりとりする形のサービスです．
こいつがすごい．その辺の人間よりよっぽど賢いです．

自分はAIが人間にとって代わるなんてまだまだ先派だったんですが，ChatGPT見ると…アレ？？って感じです💦

研究等自分で触っているAIではデータが少なく，できることが限られているというのも1つあるんですよね．
ChatGPTはえぐい量のデータを学習させているので，えぐいことができています．

いやぁ…えぐいよ…？

Googleアカウントとかで誰でも無料で使えます．Wow
[ChatGPT: Optimizing Language Models for Dialogue](https://openai.com/blog/chatgpt/)


# やばすぎる記事たち
TwitterでもChatGPTの記事ばかり流れてきます．
大学入試等の試験も軒並み合格ラインを出しているらしいです．（難関大ですよ
…俺より優秀じゃんね(´;ω;｀)

- [米医師試験で合格ライン](https://news.yahoo.co.jp/articles/46346ffb8919781adffe155ca2d9093eec1a769b)
- [センター試の英語を受けたら何点取れるの？](https://data-analytics.fun/2023/01/29/openai-chatgpt/#toc24)
- [AIツールのChatGPT、米名門大の試験を次々通過](https://www.cnn.co.jp/tech/35199213.html)

中学や高校では，課題にChatGPTを使うの禁止令が出たりもあるらしいですよ？
でもChatGPTはあくまでAIなので，絶対に正解を出すとは限らないので，”嘘を嘘と見抜けるひとでないとChatGPTを使うのは難しいでしょうね”ってやつです．

%--------------------------------%
嘘は嘘であると
　見抜けぬ人でないと
　ChatGPTを使うのは難しい
　　　　＿＿_＿
　　　／へへ　 ＼
　　／／⌒⌒＼　 ＼
　 / /　　　　ヽ　 ヽ
　｜｜ヽ　／⌒ |　　|
　 ﾚY-･／　-･- ヽ　 |
　　| /　　　　 Ｖ) |
　　|(＿つ　 ･　 丿ノ
　　|＜三三＞)　/ /
　　ヽ　ﾞﾞ　　／ﾚｿ
　　　＼从ww／　｜
　　　　/)￣　　∧
　　　／ﾚヽ　 ／ |＼
　　 ｜|　|　｜⌒ |｜
%--------------------------------%


# 使ってみた
こいつはコードも書いてくれます．
すげぇっすわ
![Input.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3120757/fb0daa6c-7998-c9c4-45b0-500986b23446.png)
![Output.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3120757/d1d7750c-9f01-f4a9-b755-ec0a2cc03c47.png)



ただ，3年前？くらいのデータで学習しているので情報が古かったりするらしいっすよ．
その辺はちゃんと使い分けようね🥰
GASでGoogleDriveの特定のフォルダのサブフォルダ、ファイルを全て取得する（再帰でスッキリ）

# 前書き
Googleドライブで、特定のフォルダ以下にあるサブフォルダ、ファイルをまとめて取得できたら便利だなーと思ってまとめました。
既存の記事もいくつかあったのですが、結構パワープレイなコードが多く、理解が大変な感じだったので、再帰を使用してスッキリ書くことに挑戦します。

# とりあえずコード
```JavaScript
function main(){
  const folderId = "xxxxxxxxxxxxxxxxxxxx";

  const targetFolder = DriveApp.getFolderById(folderId);
  const subFolders = getAllSubfolders(folderId);
  const folders = [targetFolder].concat(subFolders);
  const files = getAllFiles(folders);

  for(folder of folders){
    const name = folder.getName();
    try{
      //フォルダごとに実行したい処理をここに記載
      console.log(`${name}：成功時のメッセージ`);
    } catch(e){
      console.log(`${name}：失敗時のメッセージ\nエラー内容：${e.message}`);
    }
  }

  for(file of files){
    const name = file.getName();
    try{
      //ファイルごとに実行したい処理をここに記載
      console.log(`${name}：成功時のメッセージ`);
    } catch(e){
      console.log(`${name}：失敗時のメッセージ\nエラー内容：${e.message}`);
    }
  }
}

function getAllSubfolders(folderId, retArray=[]){
  const targetFolder = DriveApp.getFolderById(folderId);
  const folders = targetFolder.getFolders();

  while(folders.hasNext()){
    const folder = folders.next();
    const id = folder.getId();
    retArray.push(folder)
    getAllSubfolders(id, retArray);
  }

  return retArray;
}

//引数にはフォルダイテレータの配列を用いる
function getAllFiles(folders){
  let allFiles = [];

  for(folder of folders){
    const files = folder.getFiles();
    while(files.hasNext()){
      allFiles.push(files.next());
    }
  }

  return allFiles;
}
```

# 解説
ポイントはこの関数です。直下のフォルダ一覧を取得し、そのそれぞれのフォルダに対して、関数を再帰的に呼び出しています。
```JavaScript
function getAllSubfolders(folderId, retArray=[]){
  const targetFolder = DriveApp.getFolderById(folderId);
  const folders = targetFolder.getFolders();

  while(folders.hasNext()){
    const folder = folders.next();
    const id = folder.getId();
    retArray.push(folder)
    getAllSubfolders(id, retArray);
  }

  return retArray;
}
```

# 使用例
指定したフォルダ、およびそのサブフォルダ、ファイルの権限を一括でプライベート（共有されている人のみアクセス可能）に変更します。
```JavaScript
function setPrivate(){
  const folderId = "xxxxxxxxxxxxxxxxxxxx";

  const targetFolder = DriveApp.getFolderById(folderId);
  const subFolders = getAllSubfolders(folderId);
  const folders = [targetFolder].concat(subFolders);
  const files = getAllFiles(folders);

  const access = DriveApp.Access.PRIVATE;
  const permission = DriveApp.Permission.NONE;

  for(folder of folders){
    const name = folder.getName();
    try{
      folder.setSharing(access, permission);
      console.log(`${name}：フォルダの権限設定に成功しました`);
    } catch(e){
      console.log(`${name}：フォルダの権限設定に失敗しました\nエラー内容：${e.message}`);
    }
  }

  for(file of files){
    const name = file.getName();
    try{
      file.setSharing(access, permission);
      console.log(`${name}：ファイルの権限設定に成功しました`);
    } catch(e){
      console.log(`${name}：ファイルの権限設定に失敗しました\nエラー内容：${e.message}`);
    }
  }
}
```
laravelでページネーションが動かなかった

 　　  
いつものようにDocker立ち上げて、
laravel作って、
ページネーションを追加

```
public function index()
    {
        return view('user.index', [
            'users' => DB::table('users')->paginate(15)
        ]);
    }
```

　　　
　　　

しかし、
ページネーションは表示されるけど、２ページ目、３ページ目のボタンを押しても
１ページ目から変化しない！
　　　
　　


色々調べた結果、Dockerで立ち上げたnginxの設定が間違えてた。
ページネーションはurlパラメータを使うので、その設定が間違えてたみたい。

nginxの設定ファイルのlocationに設定を入れて、治りました。

```
location / {    
    try_files $uri $uri/ /index.php?$query_string;
}
```
PHPのarray_map関数の使い方

## 概要
`array_map` 関数は、配列のすべての要素に一定の処理を行い、新しい配列を生成するために使用されます。次のような形式で使用できます。
```php
array_map(callable $callback, array $array1 [, array $array2, ...]);
```
* callback: 配列のすべての要素に適用される関数またはコールバック。
* array1, array2, ...: 処理対象の配列。

この関数は、指定された配列のすべての要素に、$callback 関数またはコールバックを適用して、新しい配列を返します。配列の要素数が異なる場合、最も小さい配列の要素数に合わせて、他の配列の要素は無視されます。

## 使用例
### 通常の関数
次の例では、数値配列内のすべての数値を2倍する関数を使用して、array_map 関数を使用する方法を示します。

```php
<?php

$numbers = [1, 2, 3, 4, 5];

$doubled = array_map(function ($number) {
    return $number * 2;
}, $numbers);

print_r($doubled);

// Output: Array ( [0] => 2 [1] => 4 [2] => 6 [3] => 8 [4] => 10 )
```
このように、array_map 関数を使用することで、配列内のすべての要素に対して同じ操作を行うことができます。
### アロー関数
アロー関数を使用して、array_map 関数を使用することもできます。次の例を見てください。
```php
<?php

$numbers = [1, 2, 3, 4, 5];

$doubled = array_map(fn($number) => $number * 2, $numbers);

print_r($doubled);

// Output: Array ( [0] => 2 [1] => 4 [2] => 6 [3] => 8 [4] => 10 )

```

### もう少し複雑な使用例
次に、`array_map` 関数を用いて、フィールド名の配列から、SQLのテーブル定義に変換する処理を書いてみます。
次のように、array_map 関数を使用して、フィールド名の配列から SQL のテーブル定義に変換する処理を書くことができます。

```php
<?php

$fields = [
    'id' => 'INT',
    'name' => 'VARCHAR(255)',
    'email' => 'VARCHAR(255)',
    'created_at' => 'TIMESTAMP',
];

$sql = "CREATE TABLE table_name (\n" . implode(",\n", array_map(function ($field, $type) {
    return "  `$field` $type";
}, array_keys($fields), $fields)) . "\n);";

echo $sql;

/* Output:
CREATE TABLE table_name (
  `id` INT,
  `name` VARCHAR(255),
  `email` VARCHAR(255),
  `created_at` TIMESTAMP
);
*/
```
このように、array_map 関数を使用することで、フィールド名とデータ型を組み合わせた新しい配列を生成することができます。次に、生成された配列を implode 関数を使用して連結し、SQL のテーブル定義文字列を生成することができます。
proconio::fastoutを使用しようとすると、「proc macro `fastout` not expanded」が出るようになった

正しい解決法かわかりませんが、
`rust-analyzer.diagnostics.disabled`に`unresolved-proc-macro`を追加して無視しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561891/6ab160b8-be9f-644f-3b65-642aa51639a2.png)

Rust-Analyzerのアップデートで発生するようになったような気がしますが、
とりあえず使えるようになったのでこれで凌ごうと思います。。
React userefの用途について

# React userefの用途を、具体的に書いて下さい。

React userefは、Reactコンポーネント内に複数の参照を保持するために使用されます。 例えば、コンポーネント内にフォームを持つ場合、userefを使用してフォーム要素への参照を保持することができます。 また、userefを使用すると、コンポーネント内で定義されている定数や関数への参照を保持することもできます。

# 参照を保持するとは、具体的にどういうことですか？　分かり易く説明してください。

参照を保持するとは、コンポーネント内で定義されている定数や関数などをプログラム内で一度だけ参照するために、参照を一時的に保存しておくことです。 これにより、ある処理を繰り返し実行したり、ある処理の中で参照を取得して処理を行ったりすることができます。

# 参照とはポインタのことですか？　ＩＤ番号ですか？　中身は何ですか？

参照とは、プログラム内のオブジェクトへの参照を指します。 具体的な内容としては、オブジェクトのID番号、またはオブジェクトのメモリ上のアドレスなどです。 中身は、オブジェクトのプロパティやメソッドなどです。

# 事例のコードを書いて下さい。
```
React.useRef(null);

const myRef = React.useRef(null);

// フォーム要素への参照を保持
const handleSubmit = () => {
  const formElement = myRef.current;
  // フォームのデータを取得し処理を行う
  const formData = new FormData(formElement);
  // 以降、フォームデータを扱う処理を行う
};

return (
  <form ref={myRef} onSubmit={handleSubmit}>
    ...
  </form>
);
```
# 動作を説明してください

上記のコードでは、ReactのuseRefを使用してフォーム要素への参照を保持し、フォーム要素を参照してフォームデータを取得しています。 フォームのsubmitイベントが発火すると、handleSubmit関数が実行され、myRefで保持している参照を使用してフォーム要素を取得します。 取得したフォーム要素を使用して、FormDataオブジェクトを作成してフォームデータを取得し、以降の処理を行います。

# currentとは、何ですか？

currentとは、ReactのuseRef関数で参照オブジェクトを取得するためのプロパティです。 currentプロパティは、参照オブジェクトの内容（値）を取得するために使用します。

# 他にuserefのプロパティはありますか？

ReactのuseRef関数では、currentプロパティ以外にも、その他のプロパティがあります。 例えば、callbackプロパティを使用すると、参照オブジェクトの内容が変更されたときにコールバック関数を実行できます。 また、dependenciesプロパティを使用すると、参照オブジェクトの内容が変更されるときに、依存関係を確認できます。

# <form ref　という書き方は、他のHTML、コンポーネント要素でも、共通ですか？　refって、W3Cに規定されているのですか?

<form ref>　という書き方は、他のHTML要素やコンポーネント要素では利用できません。 refはReact独自の機能であり、W3Cでは規定されていません。

# userefとusestateの違いは何ですか？

useRefとuseStateの違いは、参照を保持するか状態を保持するかです。 useRefは、参照を保持するための特別な関数であり、useStateは、コンポーネントの状態を保持するための特別な関数です。 また、useRefは、参照を保持するためだけに使用するのに対し、useStateは、コンポーネントの状態を更新するためにも使用する必要があります。

# 参照と状態の違いを、コンピュータ知識のない小学生や高齢者にもわかるように教えてください。

参照と状態の違いを説明するには、家族間での会話を例にして説明することができます。 例えば、お母さんが友達家に会いに行くときに、お母さんの住所を友達家に伝えるときです。 このとき、友達家にはお母さんの住所を伝えるだけでなく、お母さんの住所を参照するための住所の番号なども伝える必要があります。 この住所の番号が参照です。 一方、お母さんの住所は、お母さんの住所が変わるときにも、お母さんの住所を友達家に伝える必要があります。 この時、お母さんの住所が変わることを状態と呼びます。

# タラちゃんと、サザエさんで説明してください

サザエさんがタラちゃんに住所を教えようとした時、サザエさんはタラちゃんに住所を伝えるだけでなく、住所を参照するための番号も伝える必要があります。 この番号が参照です。 一方、サザエさんの住所が変わった場合は、タラちゃんにサザエさんの新しい住所を伝える必要があります。 これが状態です。

# 住所を参照するための番号とは、つまり郵便番号ですか？　住民登記票の登録コードですか？

住所を参照するための番号とは、郵便番号や住民登記票の登録コードなどです。 ただし、参照として使用する番号は、上記のもの以外にも様々な形式があります。

# どんなものが、他にあるというのですか？具体的に説明してください。

参照として使用する番号としては、IPアドレス、メールアドレス、URLなどがあります。 IPアドレスは、コンピュータなどのネットワーク上のデバイスを識別するための番号です。 メールアドレスは、メールを受信するためのアドレスです。 URLは、特定のウェブページを指定するものです。

# サザエさんの住所が変わった場合とは、住所の地名が変わることを指しますか（つまり郵便番号が同じだが、地名が変更された場合。市が町になったとかですか）。もしくはサザエさんが引っ越しをしたという事ですか？（つまり引っ越ししたから、郵便番号自体がそもそも変わってしまった）

サザエさんの住所が変わった場合とは、サザエさんが引っ越しをした場合を指します。 つまり、サザエさんが引っ越しをしたことにより、郵便番号自体が変わってしまったという意味です。

# 何となくわかりました。

では、サザエさんからタラちゃんに状態を伝えるためには、何を伝えれば良いですか？

サザエさんからタラちゃんに状態を伝えるためには、サザエさんの新しい住所を伝える必要があります。 また、サザエさんが住所を変更した日時も伝える必要があります。

# 複雑すぎて、負担になります。

その悩みを解決するために、ReactのuseRef関数を使用すると便利です。 ReactのuseRef関数を使用すると、サザエさんの住所を参照するための番号を取得し、サザエさんの住所が変更された時には、サザエさんの新しい住所を取得することができます。 これにより、サザエさんの住所が変更されたかどうかをタラちゃんに伝える必要がなくなります。
【Python】なるべく短くベジェ曲線

# ベジェ曲線の定義
制御点$P_0,...,P_{N-1}$が与えられたとき，
```math
P(t)=\sum_{i=0}^{N-1}P_i\left(\begin{array}{c}n\\ i\\ \end{array}\right)t^i(1-t)^{n-i}\\
\mathrm{where} \quad t \in [0, 1]
```
簡単そう．

# 書く
```python
import numpy as np

def Bezier(p, t):
    *_, n = p.shape
    J = np.vectorize(lambda i, t: (n/np.r_[1:i+1]-1).prod() * t**i * (1-t)**(n-1-i), signature='(),(m)->(m)')
    return p @ J(np.r_[:n], t)
```
書いた．

# 使ってみる
```python
import matplotlib.pyplot as plt

n = 4 # 3次ベジェ曲線
t = np.linspace(0, 1, 1000)
p = np.random.randn(2, n).cumsum(0) # 制御点
plt.scatter(*p) # 制御点をプロット
plt.plot(*Bezier(p, t)) # ベジェ曲線をプロット
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501281/2914331c-dda0-473e-1f2d-f8d2858f804a.png)

良さそう．

```python
import matplotlib.pyplot as plt
fig, ax = plt.subplots(subplot_kw={'projection': '3d'})

n = 4 # 3次ベジェ曲線
t = np.linspace(0, 1, 1000)
p = np.random.randn(3, n).cumsum(0) # 制御点
ax.scatter(*p) # 制御点をプロット
ax.plot(*Bezier(p, t)) # ベジェ曲線をプロット
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501281/ec6c1919-2952-cd65-5db6-69a5e9c0edda.png)

次元上げても使えそう．

```python
import matplotlib.pyplot as plt

n = 4 # 3次ベジェ曲線
num = 10 # 本数
t = np.linspace(0, 1, 1000)
p = np.random.randn(num, 2, n).cumsum(1) # 制御点
plt.scatter(*p.transpose(1, 2, 0)) # 制御点をプロット
plt.plot(*Bezier(p, t).transpose(1, 2, 0)) # ベジェ曲線をプロット
plt.show()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501281/77efdf1f-ebb0-a2df-2436-c68a71d46803.png)

複数本同時でも．
[軽量化] マルチステージビルドによるrails環境のdocker化


## rails環境のdocker化

rails環境のdocker化についてまとめます。
dockerの軽量化のためにマルチステージビルドで環境を構築します。

### 各種バージョン
- rails 6.0.6.1
- ruby 3.0.2
- node 15.0.1
- postgresql 14.6-alpine


### Dockerfileの作成
リポジトリに `dockerfile` を作成。`apt-get install` を使用せずに下記のようにマルチステージビルドでnodeをインストールすることで、dockerの軽量化およびbuildの時間短縮が期待できます。

``` docker
FROM node:15.0.1
FROM ruby:3.0.2

COPY --from=node /opt/yarn-* /opt/yarn
COPY --from=node /usr/local/bin/node /usr/local/bin/
COPY --from=node /usr/local/lib/node_modules/ /usr/local/lib/node_modules/
RUN ln -fs /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
  && ln -fs /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npx \
  && ln -fs /opt/yarn/bin/yarn /usr/local/bin/yarn \
  && ln -fs /opt/yarn/bin/yarnpkg /usr/local/bin/yarnpkg
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev

RUN mkdir /repogitory_name
WORKDIR /repogitory_name
ADD Gemfile /repogitory_name/Gemfile
ADD Gemfile.lock /repogitory_name/Gemfile.lock
RUN bundle install
ADD package.json yarn.lock /repogitory_name/
RUN yarn install
ADD . /repogitory_name
``` 


### docker-compose.ymlの作成

```yaml
version: '3'
services:
  db:
    image: postgres:14.6-alpine
    environment:
      - POSTGRES_PASSWORD=password
  web:
    image: repogitory_name:latest
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/repogitory_name
    ports:
      - "3000:3000"
    depends_on:
      - db
```

### database.ymlの編集

``` yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password: password
  pool: 5

development:
  <<: *default
  database: myproject_development

test:
  <<: *default
  database: myproject_test
```

### 起動方法

```
$ docker-compose build
```

```
$ docker-compose run web rake db:create db:migrate
```

```
$ docker-compose up
```

上記コマンドを実行後、localhost:3000 にアクセスできれば成功です🎉
エラー対処:References to interface static methods are allowed only at source level 1.8 or above Java(1610613404)

エラー対処の備忘録です。

MavenプロジェクトでJavaのコードを書き始めた時に、次のようなエラーが出ました。

```
References to interface static methods are allowed only at source level 1.8 or above Java(1610613404)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3123353/25f0f899-4c6c-bf31-54b1-d85a9673af93.png)

### 原因

原因は`maven-compiler-plugin`の設定でソースのjavaバージョンを指定していなかったためでした。(デフォルトでは1.7でした[^1])
[^1]:https://maven.apache.org/plugins/maven-compiler-plugin/

javaでインターフェースにstaticメソッドを定義できるようになったのはバージョン1.8からなので、そのメソッドを使うためにはコンパイラにもそのバージョン以上を使うことを指定しないとだめということですね。

### 修正内容

pom.xmlに追加していた`maven-compiler-plugin`に、以下のように1.8以上のjavaのバージョンを指定するとエラーがなくなりました。

```xml:pom.xml
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
          <configuration>
            <source>17</source>
            <target>17</target>
          </configuration>
        </plugin>
```

(参考　https://maven.apache.org/plugins/maven-compiler-plugin/examples/set-compiler-source-and-target.html ）
Node.jsでタイムゾーンを指定する

# Javascriptのタイムゾーン
最近ではクラウド環境を利用することも多くなり、ローカルはJSTでクラウドはUTCの設定になっていることなどがよくあると思います。
この影響でローカルではうまく動いていたのにデプロイすると日付がちがーう！！！なんてことも・・・
ということで今回はサーバー側にNode.jsを利用していた場合にはタイムゾーンを固定することができるようだったので備忘として残そうと思います。

# タイムゾーンの指定
日付を扱うためのnpmライブラリには[Moment.js](https://www.npmjs.com/package/moment)や[date-fns](https://www.npmjs.com/package/date-fns)、[cdate](https://www.npmjs.com/package/cdate)、[luxon](https://www.npmjs.com/package/luxon)など様々なものがあるようです。
正直どれもよくわかってないのですが、、、今回のタイムゾーンを固定するという目的からするとライブラリは使用せずに環境変数`TZ`を指定すれば良さそうです。

## Windows対応
Windowsには対応してないよ、みたいな情報ばかりですがしっかり[対応](https://nodejs.org/es/blog/release/v16.2.0/)されているのでご安心ください！

# 設定方法
```.env
TZ=UTC
# TZ=Asia/Tokyo
```
たったこれだけです！

## 動作確認
UTCとJST(Asia/Tokyo)での動作差分を見てみます。
```typescript
// UTC
console.log(process.env.TZ);
console.log(new Date().getTimezoneOffset());
// -> UTC
// -> 0

// JST
console.log(process.env.TZ);
console.log(new Date().getTimezoneOffset());
// -> Asia/Tokyo
// -> -540
```
しっかり反映されていますね。

## Jest
ついでにJestでも反映されるか確認してみました。
検証用のテストコードはこちら。
```date.utils.ts
export class DateUtils {
  static getTimezoneOffset() {
    return new Date().getTimezoneOffset();
  }
}
```

```date.utils.spec.ts
import { DateUtils } from './date.utils';

describe('DateUtils', () => {
  it('getTimezoneOffset', () => {
    console.log(process.env.TZ);
    expect(DateUtils.getTimezoneOffset()).toBe(0);
  });
});

```

実行結果
```bash
# UTC
npm run test
# > cognito_authentication@0.0.1 test
# > jest
# 
#   console.log
#     UTC
# 
#       at Object.<anonymous> (utils/date.utils.spec.ts:5:13)
# 
#  PASS  src/utils/date.utils.spec.ts
#   DateUtils
#     ✓ getTimezoneOffset (11 ms)
# 
# Test Suites: 1 passed, 1 total
# Tests:       1 passed, 1 total
# Snapshots:   0 total
# Time:        0.819 s, estimated 1 s
# Ran all test suites.

# JST
npm run test
# > cognito_authentication@0.0.1 test
# > jest
# 
#   console.log
#     Asia/Tokyo
# 
#       at Object.<anonymous> (utils/date.utils.spec.ts:5:13)
# 
#  FAIL  src/utils/date.utils.spec.ts
#   DateUtils
#     ✕ getTimezoneOffset (13 ms)
# 
#   ● DateUtils › getTimezoneOffset
# 
#     expect(received).toBe(expected) // Object.is equality
# 
#     Expected: 0
#     Received: -540
# 
#       4 |   it('getTimezoneOffset', () => {
#       5 |     console.log(process.env.TZ);
#     > 6 |     expect(DateUtils.getTimezoneOffset()).toBe(0);
#         |                                           ^
#       7 |   });
#       8 | });
#       9 |
# 
#       at Object.<anonymous> (utils/date.utils.spec.ts:6:43)
# 
# Test Suites: 1 failed, 1 total
# Tests:       1 failed, 1 total
# Snapshots:   0 total
# Time:        0.873 s, estimated 1 s
# Ran all test suites.
```
バッチリですね！

# 終わりに
ということでNode.jsでのタイムゾーンの指定方法でした。
ドキュメント読めや！ってのはごもっともなですが、それでもやっぱりもっと早く知りたかった・・・・
Chatgptで typescript typeorm の entity 定義を作成する

# Chatgptで typeormの entity 定義を作成する
この動画をみて、entity 定義も作ってくれるのでは！？っと思ったので試してみました。
https://www.youtube.com/watch?v=42hN7SnJVp4&t=204s

### 簡単なテーブル構成を書いてもらう
twitter のようなアプリのDB設計をしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/709188/eabccb26-e9f9-642c-a082-4071b439808e.png)

### カラムも書き出してもらう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/709188/a2aa8463-be58-f6a6-8a21-a21a2e553ba3.png)

### typescript にて entity 作成をお願い
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/709188/cd6778bb-f601-6ae6-132d-f92c177752fe.png)

### 以下Chatgptさんの成果物
```
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, JoinColumn, OneToMany } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  user_id: number;

  @Column()
  username: string;

  @Column()
  password_hash: string;

  @Column()
  profile_image: string;

  @Column()
  created_at: Date;

  @OneToMany(type => Tweet, tweet => tweet.user)
  tweets: Tweet[];

  @OneToMany(type => Follower, follower => follower.user)
  followers: Follower[];

  @OneToMany(type => Follower, follower => follower.follower)
  following: Follower[];

  @OneToMany(type => Like, like => like.user)
  likes: Like[];

  @OneToMany(type => Retweet, retweet => retweet.user)
  retweets: Retweet[];
}

@Entity()
export class Tweet {
  @PrimaryGeneratedColumn()
  tweet_id: number;

  @Column()
  text: string;

  @Column()
  created_at: Date;

  @ManyToOne(type => User, user => user.tweets)
  user: User;

  @OneToMany(type => Like, like => like.tweet)
  likes: Like[];

  @OneToMany(type => Retweet, retweet => retweet.tweet)
  retweets: Retweet[];
}

@Entity()
export class Follower {
  @PrimaryGeneratedColumn()
  id: number;

  @ManyToOne(type => User, user => user.followers)
  user: User;

  @ManyToOne(type => User, user => user.following)
  follower: User;
}

@Entity()
export class Like {
  @PrimaryGeneratedColumn()
  id: number;

  @ManyToOne(type => Tweet, tweet => tweet.likes)
  tweet: Tweet;

  @ManyToOne(type => User, user => user.likes)
  user: User;
}

@Entity()
export class Retweet {
  @PrimaryGeneratedColumn()
  id: number;

  @ManyToOne(type => Tweet, tweet => tweet.retweets)
  tweet: Tweet;

  @ManyToOne(type => User, user => user.retweets)
  user: User;
}
```

## まとめ
やばい
NLBのNW要件を検証してみる

# やりたいこと

ふとしたきっかけで、AWSのドキュメントで気になる部分があり、CDKの練習を含んで検証してみようと思いました。
その部分とは、NLB(Network LoadBalancer)の[ホワイトペーパー](https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/network/network-load-balancers.html)のこの部分です。

> 要件
> * インターネット向けロードバランサーの場合、指定するサブネットには最低 8 個の利用可能な IP アドレスが必要です。内部ロードバランサーの場合は、 AWS がサブネットからプライベート IPv4 アドレスを選択する場合にのみ必要です。
> 
> * 制約のあるアベイラビリティーゾーンにあるサブネットを指定することはできません。エラーメッセージは、「'network' タイプを使用したロードバランサーは az_name でサポートされていません」です。制約されていない別のアベイラビリティーゾーンにあるサブネットを指定し、クロスゾーン負荷分散を使用して、制約されているアベイラビリティーゾーンのターゲットにトラフィックを分散することはできます。
> 
> * ローカルゾーンでサブネットを指定することはできません。

普段はIPを固定して設計しているので、最低8個という要件をあまり気にしていませんでしたが、記載があるならそうなのか？？？

ということで、検証してみようと思います。


# 結論

結論からいうと、ホワイトペーパーにある通りでした！（当たり前ですね笑）
* IPを指定する場合は、1つでも空きがあればOK
* AWSにお任せする場合はNG


# 前提

Network周りのリソースとSubnetのIPを埋めるためのEC2インスタンスはCDKで定義しようと思います。
基本的なソースはこちら

https://github.com/nnydtmg/aws-nlb-ip-requirements-check.git


VPC・3PrivateSubnet・EC2 10台を構築します。
/28のサブネットを作成しているので、5台ずつaz-a,az-cに構築しています。
空いているIPは6つなので、要件としてはNGのはずです。


# NLBの構築

## NGになる方

IPv4 settingsの部分で、`Assigned from CIDR 10.1.0.0/28`を選択します。
（ターゲットグループなどは事前に作成しています。）

![01_nlb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679884/e9514e59-53c4-3939-43ca-d51a9ae8d866.png)
![02_nlb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679884/9939eaad-0c8b-7c74-00e7-6190f156ddca.png)

`Not enough IP space available in subnet-******.ELB requires at least 8 free IP addresses in each subnet.`というエラーが出てます。
ホワイトペーパーの通りAWSがIPを定義する場合はダメなようです。


## OKになる方

IPv4 settingsの部分で、`Enter IP from CIDR 10.1.0.0/28`を選択します。
空いているIPを適当に入力してデプロイしてみます。

![03_nlb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679884/38eab33a-25c1-6655-39f3-cc92c4da9983.png)
![04_nlb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679884/4496a061-263d-a416-5cdb-3f7448955c59.png)

`Successfully created load balancer`と出てデプロイ出来ました。
ホワイトペーパーの通り自身でIPを指定する場合はOKなようです。


# 最後に

普段よく使うサービスでもしっかりとドキュメントを読むと、意外と理解できてない部分がありますね。
こういう部分を簡単に検証できるのもパブリッククラウドの利点ですね！

CDKのコードを綺麗にかけるようになりたいです。。

以上です、お読みいただきありがとうございます！！
Ruby オプションを作れるoptparseの使い方（簡単に）

# はじめに
ターミナルで`ls -a`や`ruby -v`などオプションを指定するとそれに対応する実行がされるが、rubyで自身でオプションが作れないかと思ったところこの`optparse`の存在を知った。

# バージョン
ruby 3.1.3

# optparseとは
- rubyにデフォルトで搭載されている標準ライブラリの１つ。
- コマンドラインのオプション操作を取り扱う時に使われる。

# optparseを使ってみる
今回はオプションで指定した数字の**5の倍数**を出力することを目標とします。

まずは完成品のコードになります。
```ruby:optparse.rb
require 'optparse'

opt = OptionParser.new
opt.on('-n') {|v| v}
opt.parse(ARGV)
select_number = ARGV[1].to_i
p select_number * 5
```
ターミナルでは`-n`オプションを指定し、引数に６を入れる想定とします。
```:terminal
$ ruby optparse.rb -n 6
```
```
$ 30
```

5の倍数なので`30`になれば正解です。

```optparse.rb
opt.on('-n') {|v| v}
```
まずここで`-n`オプションを設定しています。
```ruby:optparse.rb
opt.parse(ARGV) # ["-n", "6"]
```
指定したオプションを**文字列**で配列として受け取ることができます。
```optparse.rb
select_number = ARGV[1].to_i
```
数字が入っているのは配列の１番目なのでこれを受け取り、`to_i`でint型に変換します。
```optparse.rb
p select_number * 5
```
これで`30`と出力されます。

# おわりに
今回は簡単な使い方でしたがもっと難しい使い方もあると思います。
ぜひ使ってみてください〜

# 参考
[library optparse (Ruby 3.1 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/latest/library/optparse.html)
Vue備忘録 with Flask

```html
{% block content %}
<div class="mb-3" id="msg">{{ message }}</div>

<!-- Vie.js container -->
<div id="app" class="m-5">
  <mycomp />
</div>

<!-- mycomp's template -->
{% raw %}
<script type="text/x-template" id="mycomp-template">
  <p class="alert alert-primary h5">
    Hello! This is My-Component!
  </p>
</script>
{% endraw %}

<!-- Vue.js script -->
<script>
// mycomp object
Vue.component('mycomp',{
  template: 'mycomp-template',
});  

// start vue
new Vue({
  el: '#app'
});
</script>
{% endblock %}
```

# 今回の課題
突然ソースを出してみましたが、今回はこちらを倒していきます。

## Vueオブジェクト
Vueコンポーネントを作成する際に、
__mycomp__ というコンポーネント名を付ける。
これによって __\<mycomp />__ という記述でコンポーネントを呼びだせる。

__template__ の箇所でどのテンプレートに処理を付加させるかを決定している。
今回の処理は__mycomp-template__ をidとして指定している箇所に
Vueが適用される。

最後に、(最初でもいいと思うが)どこのタグ内にVueを適用するかを
__new Vue__ を用いて宣言する。

これでVueが使える状態になったのではないか。

## テンプレート部
Vueの処理を受ける見た目を作成する。
scriptタグである必要はあるのだろうか...?
rawもここを囲むのか...?

色々思う所はあるが、先に進んでみよう。

## 表示部
見事 __\<mycomp />__ で見た目ができた。

# Vue.jsは4つの部分で構成されている
・Vue.jsコンテナ
・コンポーネントのテンプレート
・コンポーネントのスクリプト
・Vue.jsオブジェクト作成

プログラムの中心は「コンポーネントのテンプレート」「コンポーネントのスクリプト」となる。

と、Vueオブジェクトの作成方法は2種類あるみたいだね。
今後どういう違いがあるのかを明確にできればいいかな。

# プロパティ
作成したテンプレートに動的な値を入れられるようにする。
例えば前回の例で、
__\<mycomp />__ というテンプレートを作成した。

ここに、class、idのように、内部的な値を渡したい。
それを可能にするのがプロパティである。
https://qiita.com/raisack8/items/49f21906dbc7576000e9


# 早速コード
```html
<!-- Vue.js container -->
<div id="app">
  <mycomp name="Hanako" 
    msg="This is my first message. hum..." />
</div>

<!-- mycomp's template -->
{% raw %}
<script type="text/x-template" id="mycomp-template">
  <div>
    <p>
      Hi! I'm {{ name }}
    </p>
    <p>
      {{ msg }}
    </p>
  </div>
</script>
{% endraw %}

<!-- Vue.js script -->
<script>
//mycomp object
Vue.component('mycomp',{
  template: '#mycomp-template',
  props:['name', 'msg']
})
//....
</script>
```

テンプレートの中で変数を使っている。。

<INS>テンプレートを作成している中で、変数を扱いたくなったら、一旦{{}}で変数名を囲み、Vueスクリプトの中に __props__ を使って変数を配列で宣言させる</INS>
ここでは"name"、"msg"を変数として使えるよってこと


### 参考書籍
https://www.amazon.co.jp/Python%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AF-Flask%E3%81%A7%E5%AD%A6%E3%81%B6Web%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E3%81%97%E3%81%8F%E3%81%BF%E3%81%A8%E3%81%A4%E3%81%8F%E3%82%8A%E6%96%B9-%E6%8E%8C%E7%94%B0%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4802612249
Django初学者のざっくり理解

# RenderとRedirect
　Djangoの勉強をしていて、`Render`と`Redirect`がこんがらがったので整理のためにまとめます。

# Render
## Renderの記述
　まずはRenderの記述から見ていきます。
```python:Render
def hoge_view(request):
    object_list = Model.objects.all()
    return render(request, 'hoge/hoge.html', {'object_list' : object_list})
```
　まず、renderはviewの中で使われています。引数は前から順に、`リクエスト`、`テンプレート`、`データ`です。前2つは、[前回記事](https://qiita.com/devagar/items/919cdf77b7dccd852f2f)を参照してください。
　今回の記述において、データは`モデル`の情報を使っています。モデルのすべてのオブジェクトを取得して、キーと値の組み合わせで利用しています。

## Renderの動作イメージ
　Renderの動作を理解した範囲で、説明します。Renderはデータを受け取って、テンプレートに適用して表示するという処理をしています。抽象的な説明をすると、「データを持ってきて、表示だけ新しくする」感じです。今あるページの上から、新しいページを上書きするというイメージです。

# Redirect
## Redirectの記述
　こちらでもまず、Redirectの記述を見ていきます。
```python:Redirectの記述
def hoge_view(request):
    return redirect('hoge')
```
　こちらもViewの中での記述です。引数になっている`'hoge'`ですが、表記が違うだけでテンプレートです。遷移先のテンプレートを指定しています。

## Redirectの動作イメージ
　こちらも分かっている範囲で説明します。Redirectは他のページに遷移するという処理をしています。「そもそも違うページ」という感じです。

# まとめ
　Renderは「自分の見た目を変える」、Redirectは「違う人になる」という感じでした。ざっくり理解ですので、気になった人は適宜調べてください。
スプレッドシート 列指定数字⇔アルファベット(英字)を変換する数式

# 数字 から アルファベット(英字) 変換
```
=SUBSTITUTE(ADDRESS(1,数字,4),1,"")

// 例)列数6の場合
=SUBSTITUTE(ADDRESS(1,6,4),1,"")
> F
```


## セルの値を使って指定

|  | A            | B |
|:-|:-------------|:--|
|1 |列数           |7 |
|2 |列アルファベット|=SUBSTITUTE(ADDRESS(1,B1,4),1,"") |

↓

|  | A            | B |
|:-|:-------------|:--|
|1 |列数           |7 |
|2 |列アルファベット|G|


# アルファベット(英字) から 数字 変換

```
=COLUMN(INDIRECT("アルファベット"&"1"))

// 例)列アルファベットがBの場合
=COLUMN(INDIRECT("B"&"1"))
> 2
```


## セルの値を使って指定
|  | A            | B                        |
|:-|:-------------|:-------------------------|
|1 |列アルファベット|C                         |
|2 |列数           |=COLUMN(INDIRECT(B1&"1")) |

↓

|  | A            | B |
|:-|:-------------|:--|
|1 |列アルファベット|C |
|2 |列数           |3 |
PHPで名前空間内でPDOを使う方法

PHPで名前空間内でPDOを使うには、次のように記述します。

```php
namespace YourNameSpace {
    use PDO;
    // ...

    $pdo = new PDO(...);
    // ...
}
```
このように、名前空間内でuse構文を使用してPDOクラスをインポートし、その後にPDOオブジェクトを生成することができます。

注意：PDO拡張モジュールがPHPにインストールされていることが前提となります。また、接続文字列（. . .の部分）は適切なものに置き換えてください。
【GAS】任意のフォルダにスプレッドシートを作成する

# GASでスプレッドシートを作成する際、フォルダを指定できない(※2023/02/10 時点)


GASでスプレッドシートを作成するメソッド
```
SpreadsheetApp.create("テストファイル名");
```
上記の処理では**マイドライブ**にスプレッドシートが生成されるだけで、フォルダの指定はできません。
https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app#createname

任意のフォルダに作成したい場合は
**①マイドライブにスプレッドシートを生成**
**②指定のフォルダに移動**
という手順が必要になります。
そこで、1行で任意のフォルダにスプレッドシートが作成できるよう関数を作成しました。
(フォルダを指定するだけでなく、 初期シート名も変更できるようにしています。)

関数は以下になります。

# 任意のフォルダにスプレッドシートを作成する関数
```javascript:
function createSpreadsheet(fileName, {sheetName=null, folderId=null}) {
  // 新規スプレッドシートをマイドライブに生成
  const ss = SpreadsheetApp.create(fileName);

  // シート名指定がある場合、シート名を書き換える
  if (sheetName) {
    ss.getSheets()[0].setName(sheetName);
  }

  // フォルダ指定がある場合、フォルダ移動
  if (folderId){
    // スプレッドシートをファイルオブジェクトとして開く
    const file = DriveApp.getFileById(ss.getId());

    // フォルダオブジェクト取得
    const folder =DriveApp.getFolderById(folderId);

    // フォルダ移動
    file.moveTo(folder);
  }

  return ss;
}
```

## 解説
引数を以下のようにしています
+ **fileName**(必須): スプレッドシート名
+ **sheetName**(任意): シート名
+ **folderId**(任意): フォルダID

※フォルダIDはGoogleDriveのフォルダのURL
```https://drive.google.com/drive/u/0/folders/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX```
の"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"の部分

sheetName, folderId を任意指定しているため
シート名の指定が
**有り：指定のシート名で書き換え
なし：初期(シート1)のまま**

フォルダID指定が
**有り：指定のフォルダにスプレッドシートを移動
なし：マイドライブのまま**
という動作になります。

# 使い方
```javascript:
// 指定のフォルダに作成、シート名変更
const ss = createSpreadsheet("ファイル名", {sheetName: "シート変更", folderId: "XXXXXXXXXXXXXXXX"});

// 指定のフォルダに作成、シート名変更せず
const ss = createSpreadsheet("ファイル名", {folderId: "XXXXXXXXXXXXXXXX"});

// マイドライブに作成、シート名変更
const ss = createSpreadsheet("ファイル名", {sheetName: "シート変更"});

// マイドライブに作成、シート名変更せず SpreadsheetApp.create("ファイル名")で作るべきだとは思うけど
const ss = createSpreadsheet("ファイル名", {});
```

# 参考
https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet-app?hl=ja
Vue基本操作備忘録

(個人の意見・感想も含まれているので、必ずしも正しい情報ではないので、予めご了承ください。
　また、間違った点がありましたら指摘していただきまけますと幸いです。)

エディターにはCodePenなるものを使ってみる。
書いたコードがリアルタイムで画面に表示される。
勉強として使うには非常にいいツールなのでは。
[CodePen](https://codepen.io/pen/)

当記事はFlaskと一緒に使うことを前提として進めています。

# はじめに
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1573902/f3418721-0ac7-0851-7a5d-df283ba02686.png)
チュートリアルの一番初めです。
自分なりにどのように作用し合っているのか確認してみましょう。

…と思ったけど、公式ドキュメントはちょっと重かった、、、

# 書籍を参考に
Vueの基本的な考え方としては、

>「Vue」というオブジェクトを作成し、
HTMLの特定のタグに割り当て、
>表示を組み込む。

## Vueオブジェクトの作成する処理
Vueオブジェクトを作成するとき、作成に必要な情報をオブジェクトにまとめたものを引数に指定する。
```js
new Vue({
    el:'#app',
    data: {
        vue_msg: 'This is Vue.js!'
    }
});
```

__el__ では組み込みたいタグを指定している。
上の例でいうと、__idがapp__ の中身に適用している
```html
<div id="app">
...
</div>
```
このVueが適用される範囲を<INS>__コンテナ__</INS>と呼ぶ
__vue_msg__ はコンテナ内では変数として利用できる。
```html
<h2> {{ vue_msg }} </h2>
```

## Flaskのjinjaと区別する
jinjaテンプレートと区別するために、
コンテナの前後を __{% raw %} ～ {% endraw %}__
で区切るらしい。

# コンポーネント
ここの理解が一番大変そう。
書籍を参考にしてみたけど一旦公式ドキュメント参考に
```html　test.html
<div id="components-demo">
  <button-counter></button-counter>
</div>
```

```js test.js
// Create a Vue application
const app = Vue.createApp({})

// Define a new global component called button-counter
app.component('button-counter', {
  data() {
    return {
      count: 0
    }
  },
  template: `
    <button v-on:click="count++">
      You clicked me {{ count }} times.
    </button>`
})

app.mount('#components-demo')
```
すると下記添付のように、
クリックするとカウントが増えていくボタンが生成される。
詳しく見てみよう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1573902/0ea73eef-2ac9-cd17-efa0-69d59b26bf2e.png)

<INS>①定数「__app__」を宣言。</INS>
__Vue.createApp__ 関数を発動。
<INS>②appに __component__ を付けて、「button-counter」(第一引数)という部品を作る。</INS>

コンボーネントとは、「表示」「データ」「処理」を一体化したものだという。
色々便利な部品と考えていいかもしれない。

<INS>③data()によって変数を宣言。(count)</INS>
countを返してくれる？ってこと？

<INS>④テンプレートを宣言する(宣言であっているのかな？)</INS>
この中にはHTML形式で、作りたいタグを作る。
バッククオーテーションで囲うのかな？

<INS>(⑤ ディレクティブ「v-on:click」</INS>
クリックすると変数のcountをインクリメントしていく。)

<INS>⑥完成したら、app定数をid=vomponents-demo にマウントさせる。</INS>

うーん、、、、むずい。

# HTMLに組み込む場合

先程は別々のファイルで実行していたが、HTMLに埋め込む。

### コンポーネントのテンプレート
```html
<script type="text/x-template" id="テンプレートのID">
    ......表示内容......
</script>
```
 type="text/x-template"を記載すればscriptタグ内にHTMLタグを記述できるらしい。

### コンポーネントのオブジェクト
```js
Vue.component( コンポーネント名 ,{
    template: テンプレートの指定
});
```

### コンポーネントの利用
```html
<コンポーネント名 />
```

これを記載すれば、その箇所に先程作成したコンポーネントを埋め込める。

続きは次回へ

#### 参考書籍
https://www.amazon.co.jp/Python%E3%83%95%E3%83%AC%E3%83%BC%E3%83%A0%E3%83%AF%E3%83%BC%E3%82%AF-Flask%E3%81%A7%E5%AD%A6%E3%81%B6Web%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E3%81%97%E3%81%8F%E3%81%BF%E3%81%A8%E3%81%A4%E3%81%8F%E3%82%8A%E6%96%B9-%E6%8E%8C%E7%94%B0%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4802612249
AWS 全リージョンのリソースを検索してみた

# はじめに

AWS を利用しているときに、どのリージョンに何のリソースを作成したか確認したくなるときがあります。普段使わないリージョンで動作検証などを行った時に、削除忘れなどがあります。そういったときに簡単に全リージョンの全リソースを対象に検索できます。

今回の記事ではその方法を簡単に紹介します。クラスメソッドさんの記事を参考にさせていただきました。

https://dev.classmethod.jp/articles/tag-editor-seach-allregion/



# Tag Editor で全リソースを検索

Tag Editor の画面を開きます。

![image-20230210201040079.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/ef8483ab-c3ec-ca41-76a7-c69c035b8ff9.png)



Tag Editor の機能を選択します。

![image-20230210201202394.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/c54c8b49-f92e-8e9f-4016-b950f527ace8.png)



All regions を選択します。

![image-20230210201227914.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/8c37c085-f32e-b01a-1865-999e9a858703.png)



Resource types の選択肢がぐるぐる回って、約 10 秒ほど読み込みが走ります。All supported resource types を選択して、Search resources を押します。

![image-20230210201359223.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/67843d3c-5726-46d6-fc16-69b5511c7832.png)



このような形でリソースが検索されます。全リージョンを検索しきるには時間が掛かるので、のんびり待ちます。

![image-20230210202003586.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/c03c85b4-8fbd-254d-3706-e61dc039e38e.png)



全リージョンの検索が終わると、csv でダウンロードが出来る用になっています。ダウンロードしておくと、後から見返すときに便利です。

![image-20230210202251564.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/3791af1e-317c-0a50-43f3-cee4049e4e09.png)



# Cost Explorer で見る

お金が発生しているリソースについては、Cost Explorer も同様に全リージョンのリソース状況を確認できます。無料枠などでお金が発生していないものはひっかかりません。料金を気にして全リージョンを確認したい時は、Cost Explorer も良い選択肢でしょう。

最近 Cost Explorer の画面が変わっています。右側の Dimension から Region を選択します。

![image-20230210203759366.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/33059325-a2d8-ac23-8853-ed5cc583a86f.png)



すると、リージョン毎に発生している料金の全体感がわかります。

![image-20230210204106987.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/9a2df305-c1f7-c1e2-180e-526afd4d43d5.png)



全リージョンの全体感を把握したあとに、特定のリージョンでどういったサービスが使われているかを確認したい場合は、以下の操作を行うとリージョン内での詳細を確認できます。

- Region でフィルターを掛ける
- Dimension を Service に変更する

![image-20230210204316128.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/b1a94120-1bd7-64e2-183b-e38e0b770843.png)



# 参考 URL

https://dev.classmethod.jp/articles/tag-editor-seach-allregion/
【Swift】重複しない綺麗な数列を作る

# はじめに
https://qiita.com/SNQ-2001/items/025de03a9f070c740610

保存機能を作成している際に、重複しないファイル名を付けるために書いたコードを記録しておきます。
もっといい方法があれば、コメントください！！

# やりかた
```swift
let timeInterval = Int(Date.now.timeIntervalSince1970 * 1_000_000)
print(timeInterval.description) // 1676029701621150
```
![スクリーンショット 2023-02-10 20.48.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/9c869945-612d-fdc6-5fd7-489d6a1b39b5.png)

# おわり
これ重複しないよな。。。？
databricksのhiveメタストアに保存されたテーブルの過去バージョンにアクセスする方法

databricksの標準ファイルフォーマットであるdeltaにはtime travelなる機能があり、この機能を使うと過去のバージョンのデータにアクセスできる。このdelta形式は実はhiveメタストアにも使われているので、hiveメタストアに保存されたテーブルにもtime travelは使える。しかし、やや面倒な方法をとる必要があるため、備忘録的に書いておく。なおtime travel機能については下記を参考のこと。
https://www.databricks.com/jp/blog/2019/02/04/introducing-delta-time-travel-for-large-scale-data-lakes.html

## hiveメタストア上のテーブルのフォーマットを確認してみる
とりあえず下準備としてsklearn.datasetsのbreast_cancerを使って、hiveメタストアにデータを保存してみる。
```python
import pandas as pd
from sklearn import datasets

breast_cancer_data = datasets.load_breast_cancer()
breast_cancer_df =  pd.DataFrame(
    breast_cancer_data.data,
    columns = breast_cancer_data.feature_names
  )
breast_cancer_df.columns = [col.replace(' ', '_') for col in breast_cancer_df.columns]
cols = list(breast_cancer_df.columns)
# spark DataFrameに変換
breast_cancer_df['target'] = breast_cancer_data.target
breast_cancer_sdf = spark.createDataFrame(breast_cancer_df)

# hiveメタストアにテーブルを保存
breast_cancer_sdf.write.saveAsTable('default.breast_cancer')
```
ここでdefaultデータベースに保存されたテーブルbreast_cancerのデータフォーマットを確認してみよう。
```python
display(spark.sql('DESCRIBE DETAIL default.breast_cancer'))
```
実行結果は以下のとおり。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158676/7feeafb1-f97f-b5bc-59a8-148aa6bf58c6.png)
format列の値がdeltaになっていることが分かる。さてdeltaのtime travelで過去バージョンにアクセスするには、hiveメタストアに保存されたテーブルのファイルパスが必要になる。ファイルパスはこの結果のlocation列の値になる。

## 実際にtime travelしてみる
ではbreast_cancerからtarget列を削除してhiveメタストア上のテーブルを上書き保存してみる。
```python
breast_cancer_sdf = breast_cancer_sdf.drop('target')
# hiveメタストアに上書き保存
(breast_cancer_sdf
    .write
    .mode('overwrite')
    .option('overwriteSchema','true')
    .saveAsTable('default.breast_cancer')
)
```
ついでにバージョン履歴も確認しておく
```python
display(spark.sql('DESCRIBE HISTORY default.breast_cancer'))
```
結果は以下のとおり。hiveメタストアもバージョン管理されていることがわかる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158676/f6b0ebe6-d698-7830-5422-9bf999bba8a1.png)

繰り返しになるがtime travelにはデータのファイルパスが必要になるため、DESCRIBE DETAILで取得する。
```python
location = (spark
  .sql('DESCRIBE DETAIL default.breast_cancer')
  .select('location')
  .collect()[0][0]
)
# version 0のテーブルを読み込む
df_v0 = spark.read.format('delta').option('versionAsOf',0).load(location)
```
結果は以下のとおり、target列が存在しているので、列を削除前のバージョンを復元できていることがわかる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158676/2aee112b-de81-32ae-ead5-71ca56cac08b.png)

一応バージョン1の結果も載せてみる。当然だがtarget列は存在しない。
```python
df_v1 = spark.read.format('delta').option('versionAsOf',1).load(location)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158676/1eea13c4-239e-32d8-d506-6eef88efed0e.png)

なお[time travelで遡れる期間はデフォルトで30日](https://docs.databricks.com/delta/history.html#configure-data-retention-for-time-travel)なので、それ以上長い期間のバージョンを保持する場合は別途設定が必要な点に注意が必要。
Ruby if, elseを使ったプログラムの作成

# if, elseを使ってプログラムを作成します

条件は以下の通りです。
- 条件1:第一引数にオウムが鳴く場合はtrueを指定し、鳴かないfalseを指定する
- 条件2:第二引数には時間を指定する（ただし、「分」は考えないものとする）
- 条件3:20時から翌朝7時までの間にオウムが鳴いた場合は「NG」と出力する（20時と7時は含まれない）
- 条件4:上記以外の場合は「OK」と出力する

```ruby
def parrot_trouble(talking, hour)
  if talking && (hour < 7 || hour > 20)
    puts "NG"
  else
    puts "OK"
  end
end

# 呼び出し例
parrot_trouble(true, 6)
```

```ruby
NG
# ターミナル出力
```

## 解説
オウムが鳴いている時間帯が20時〜7時 → NG
上記以外の場合にはOKを出力されるように記述を考えていきます。

- 第一引数"talking"について

オウムが鳴いているか・鳴いていないかの真偽判定を行うため、第一引数にtrueが入っているときに真と判断されます。

- 第二引数"hour"について

ここでは、「20時から翌朝7時までの間」か「それ以外」かという点を判断します。
SearchBar付きのTableViewでセルタップ時に画面遷移させる時の注意点

SearchBar付きのTableViewでセルをタップ時画面遷移させる時、
検索モードだと画面遷移されず詰まったので解決策を共有します。

### ■セルタップで画面遷移する実装
```swift
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let viewController = SelectViewController()
    let navigationViewController = UINavigationController.init(rootViewController: viewController)
    navigationViewController.modalTransitionStyle = .crossDissolve
    navigationViewController.modalPresentationStyle = .fullScreen
    self.present(navigationViewController, animated: true)
}
```

:::note warn
これだと普通にセルをタップした時は画面遷移するが
検索モードに入った状態でセルをタップしても画面遷移しなかった。
:::

### ■解決方法
検索モードに入った時は、searchController.isActive = falseにする。

```swift
    if searchController.isActive {
        searchController.isActive = false
        self.present(navigationViewController, animated: true)
    } else {
        self.present(navigationViewController, animated: true)
    }
```
### ■全体のコード
```swift
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let viewController = SelectViewController()
    let navigationViewController = UINavigationController.init(rootViewController: viewController)
    navigationViewController.modalTransitionStyle = .crossDissolve
    navigationViewController.modalPresentationStyle = .fullScreen
    if searchController.isActive {
        searchController.isActive = false
        self.present(navigationViewController, animated: true)
    } else {
        self.present(navigationViewController, animated: true)
    }
}
```
dynamodb-localのdockerイメージにマニフェストがなくてGitLabのCIが失敗した

## 結論から先に
Dockerイメージを1.20.0以下に固定する
*amazon/dynamodb-local:1.20.0*

```docker-composer.yml
version: "3"
services:
    dynamodb:
      image: amazon/dynamodb-local:1.20.0
    ...
```


## 現象
gitlab-runnerのログ（抜粋）

```bash
$ docker-compose -f docker-compose-ci.yml up -d
Creating network "orpheanalyticsserverapi_default" with the default driver
Pulling db (mysql:5.7)...
5.7: Pulling from library/mysql
Digest: sha256:8cf035b14977b26f4a47d98e85949a7dd35e641f88fc24aa4b466b36beecf9d6
Status: Downloaded newer image for mysql:5.7
Pulling dockerize (jwilder/dockerize:0.6.1)...
0.6.1: Pulling from jwilder/dockerize
Digest: sha256:5712c481002a606fffa99a44526fbff2cd1c7f94ca34489f7b0d6bbaeeff4aa4
Status: Downloaded newer image for jwilder/dockerize:0.6.1
Pulling dynamodb (amazon/dynamodb-local:latest)...
latest: Pulling from amazon/dynamodb-local
mediaType in manifest should be 'application/vnd.docker.distribution.manifest.v2+json' not 'application/vnd.oci.image.manifest.v1+json'
Cleaning up project directory and file based variables
00:00
ERROR: Job failed: exit code 1
```

## 原因
mediaTypeがマニフェストに必要だが見つからない

### docker manifestとは
- イメージに関するレイヤー、サイズ、ダイジェスト値に加えて、イメージがビルド対象とした OS やアーキテクチャーなどの情報

https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/commandline/manifest/

## 解決するまでのステップ
- GitLabのCIのログを見ると `latest: Pulling from amazon/dynamodb-local` で止まっているので、dynamodb-localのイメージが怪しいと判断した。
- マニフェストがどうなっているか確認
    - マニフェストがそもそも見つからない
    ```
    $ docker manifest inspect --insecure amazon/dynamodb-local:latest
    no such manifest: docker.io/amazon/dynamodb-local:latest
    ```
- ひとつ前のバージョンを確認
    - マニフェストが表示された。mediaTypeもある。
     ```
    $ docker manifest inspect --insecure amazon/dynamodb-local:1.20.0
    {
       "schemaVersion": 2,
       "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
       "manifests": [
          {
             "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
             "size": 1160,
             "digest": "sha256:ba8d8489ab2d68434b53cd3f2d13a6d05db8b3a295572957104a2e4851812e21",
             "platform": {
                "architecture": "arm64",
                "os": "linux"
             }
          },
          {
             "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
             "size": 1160,
             "digest": "sha256:aed85599f5000979c28c8b2fea7d685a0f2c60810df819973b1fb8e8dc5d7206",
             "platform": {
                "architecture": "amd64",
                "os": "linux"
             }
          }
       ]
    }
    ```

※ docker manifest inspectが権限エラーになる場合は、**docker login**が必要です。

latest(1.20.1)になぜmanifestが存在しないのかは不明。
Azure SQL Databaseにログインユーザーを追加してユーザーデータベースにアクセスする方法

# はじめに
Azure SQL Databaseを初めて初めてデプロイする際に管理者ログインユーザーとパスワードを指定して構築する必要があります。

管理者ログインユーザーとは別で追加したログインユーザーを使用してSSMS経由でデータベースにアクセスしようとしたところ、以下のようなエラーが発生しログインができませんでした。


>ADDITIONAL INFORMATION:
>The server principal 'ログインユーザー名' is not able to access the database 'master' under the current security context.
Cannot open user default database. Login failed.
Login failed for user 'ログインユーザー名'. (Microsoft SQL Server、エラー: 916)

このメッセージからdefault databaseをユーザーデータベースに変更する必要があると思いましたが、Azure SQL Databaseではログインに対してDefault databaseが変更できない仕様のようです。（Default databaseは必ずmasterデータベース）

そのため追加したログインユーザーでSQL Server Management Studio (SSMS) や sqlcmdから接続する際にはデータベース名を指定する必要があります。


# 手順

## SSMSからデータベースを指定して接続する

①	サーバー名、認証情報を入力した後、SSMSの認証画面の右下にある"Options >>"を開く
②	Connect to database 欄にログイン先のデータベースを指定
③	Connectを押下し、接続

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1293404/a8fc0f9f-7805-36c2-154d-6e3d351953ea.png)






## sqlcmdからデータベースを指定して接続する
①	接続元のマシンからコマンドプロンプトや PowerShell を開く。
②	以下の接続コマンドで対象のデータベースに接続（-d <データベース名>にてデータベースを指定）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1293404/d5ac7736-873b-a4c4-a815-96a150276d1a.png)

接続コマンド例
sqlcmd -S <SQL Server名> -U <ログイン名> -P <パスワード> -d <データベース名>



# おわりに

参考情報：[追加のログインと管理アクセス許可を持つユーザーを作成する](https://learn.microsoft.com/ja-jp/azure/azure-sql/database/logins-create-manage?view=azuresql#create-additional-logins-and-users-having-administrative-permissions)
参考情報：[CREATE LOGIN (Transact-SQL)](https://learn.microsoft.com/ja-jp/sql/t-sql/statements/create-login-transact-sql?view=azuresqldb-current&preserve-view=true)