OmniAICreator/Qiita-1.07M huggingface dataset:
【Node.js】Pinata-SDKでファイルをIPFSへPINする

ここを見ながらやりました。

https://github.com/PinataCloud/Pinata-SDK

ファイルをアップロードするようなことを、IPFSではピンというらしいですね。
（違ったらごめんなさい）


## 私の環境
- macOS　Ventura
- Node.js: v20.9.0 
- 開発環境： VSCode

## 準備
### PINATA
https://www.pinata.cloud/

APIキーを取得して、どこかに控えておく


### 環境変数の設定
ルートディレクトリで
Pinata のSDKと
環境変数設定のライブラリ dotenv をインストールする。

```
npm install --save @pinata/sdk
npm install --save dotenv
```

ルートディレクトリに .envファイルを作成し、
さっき控えたAPIキーなどを環境変数を設定する。

```.env
PINATA_API_KEY = "PINATAのAPIキー"
PINATA_API_SECRET = "PINATAのAPIシークレットキー" 
```

### APIがとおるか、以下のコードで確認

```index.js
const PINATA_API_KEY = process.env.PINATA_API_KEY;
const PINATA_API_SECRET = process.env.PINATA_API_SECRET;

const pinataSDK = require('@pinata/sdk');
const pinata = new pinataSDK(PINATA_API_KEY, PINATA_API_SECRET);

pinata.testAuthentication().then((result) => {
    //handle successful authentication here
    console.log(result);
}).catch((err) => {
    //handle error here
    console.log(err);
});

```

コンソールログに以下のメッセージが出たらOK
```
{ authenticated: true }
```

こんなエラーが出る場合は、
```
Error [ERR_SOCKET_CONNECTION_TIMEOUT]: Socket connection timeout
```

Node.jsのバージョンを V20.9.0 にアップデートしたら解決しました。　

ちなみに、僕のバージョン管理ツールは NVM なのでここをみながらやりました。

https://qiita.com/monaka33/items/2b7262b4dc91a8d1f658


## ファイルをIPFSにピンする

ここを見ながらやりました。

https://github.com/PinataCloud/Pinata-SDK#pinFileToIPFS-anchor

ファイルを用意する。
<IMG SRC="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291592/f5c2960c-7ac0-9413-b877-d78ef9386775.png" width=60%>

この写真を以下の index.js と同じディレクトリに pic.png というファイル名で保存する。


```index.js
require('dotenv').config();
const PINATA_API_KEY = process.env.PINATA_API_KEY;
const PINATA_API_SECRET = process.env.PINATA_API_SECRET;

const pinataSDK = require('@pinata/sdk');
const pinata = new pinataSDK(PINATA_API_KEY, PINATA_API_SECRET);

const fs = require('fs');
const readableStreamForFile = fs.createReadStream('./pic.png');
const options = {
    pinataMetadata: {
        //nameは必須
        name: 'Cats',
        //keyvaluesは必須ではない
        keyvalues: {　　　　
            customKey: 'customValue',
            customKey2: 'customValue2'
        }
    },
    pinataOptions: {
        cidVersion: 0
    }
};
pinata.pinFileToIPFS(readableStreamForFile, options).then((result) => {
    //handle results here
    console.log(result);
}).catch((err) => {
    //handle error here
    console.log(err);
});
```

これを実行すると、
```
{
  IpfsHash: 'QmWZF4Vbm8nqfkvVngnYWhgyLc8XYp7kN4RWZa1VfMuDxc',
  PinSize: 74809,
  Timestamp: '2023-11-16T14:42:17.257Z'
}
```

IPFSに保存されました。

このアドレスで確認できます。
```
https://gateway.pinata.cloud/ipfs/<IpfsHash>
```

つまり、本件ではこちらのアドレスに猫の写真がピンされました。
https://gateway.pinata.cloud/ipfs/QmWZF4Vbm8nqfkvVngnYWhgyLc8XYp7kN4RWZa1VfMuDxc

以上です。
[備忘録]Python環境について

# Pythonの環境について
当方Pythonぺーぺー何もわかっておらんの民です．

色々あってPythonを触ることになったのですが，Anacondaさん，どうにもよくわからんということで色々と調べた結果**pyenv+venv環境**が良いらしいということで実際に構築したので備忘録なり．

## pyenvってなんだ
まず[pyenv](https://github.com/pyenv/pyenv)ってなんだ．

> Simple Python Version Management: pyenv

ということで**Pythonのバージョン管理システム**らしいです．Pythonくんは良くバージョンがどうちゃらこうちゃらと問題が起こるってのをよく聞くので，Pythonのバージョン管理ができたら良さそう．

### インストールとか
まずはGitHubからcloneする．
```bash:install
git clone https://github.com/pyenv/pyenv.git ~/.pyenv
```
次にパスとかの設定．
```bash:path setting
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
```
この変は基本的にpyenvのGitHubのまんまなので不具合が起こっても私ぺーぺーにはわかりやせん．

### pyenvの使い方
pyenvはpythonのバージョン管理システム．その使い方は

* 好きなバージョンのpythonをダウンロード
```bash:install any python version
pyenv install "version" #versionには好きなPythonのバージョン
pyenv install --list #インストール可能なバージョンの確認
```
* 好きなディレクトリ使用するPythonのバージョンを指定
```bash:select local version
pyenv local "version"
```
これでlocalコマンドを叩いたディレクトリでpython -Vとかでバージョンを確認すると好きなバージョンになってるはずです．

<details><summary>私の場合(具体例)</summary>

私の場合はpyenvを使用するディレクトリを作成して，更にその中でバージョンごとにディレクトリを分けて使用しています．
```bash:create parent directory
mkdir /home/pyenv
cd /home/pyenv
```
でpyenv環境を使用するディレクトリ(/pyenv)を作成してそこをカレントディレクトリとします．
その中で例えばPython3.7の最新のものを使用するとするときは，
```bash:create version directory
mkdir py37
cd py37
```
でPython3.7の最新バージョンを使用するディレクトリに移動．
```bash:choose Python version using current directory
pyenv local 3.7
```
これだけで使用するPythonバージョンごとにディレクトリを変えれば良いように設定できました．ちゃんと設定できてるかどうかは
```bash:check Python version current directory
pyenv local #python --verionでも可
```
</details>

## venvってなんだ
まず[venv](https://docs.python.org/3/library/venv.html)ってなんだ．

>The venv module supports creating lightweight “virtual environments”

仮想環境を作るのを手伝ってくれるやつらしいです．

### インストールとか
apt使ってインストールしろとかそういうのはないです．もともとPythonに入ってたはず(入れたの昔なので覚えてない…たしかもともとあったはず)．

### venvの使い方
まずは仮想環境を作ります．
仮想環境を作っとくとpipとかで色々モジュールとかパッケージとかインストールするのを，プロジェクトごとに分けられます．なのでごちゃごちゃいろんなものが干渉することもないし，一個よくわからなくなったからと行ってPCのPython環境まるごと整理みたいなことはしなくて良くなります．

まあ良くて，とりあえず作り方．
```bash:create virtual environment
python -m venv "venv name" #venv nameのところは作成する仮想環境の名前
```
これだけで仮想環境作れます．そんで
```bash:activate virtual environment
source "venv name"/bin/activate
```
これでOK．うまく立ち上がってたら，
```
("venv name")$ 
```
みたいになってるはず．各環境内でpip installとかして好きなように使えますわ．

## pyenvとvenvの合わせ技．
pyenvでディレクトリごとに行って，venvでその小ディレクトリに仮想環境を作るとバージョンごとの仮想環境を構築できるのでオヌヌメです．

私の場合，
* pyenv
    * py35
        * venv name0
    * py36
        * venv name1
        * venv name2
    * py37
        * venv name3

みたいな感じの構造を作って管理しています．こんなに色々バージョン使うほどPythonやってないけど…

### 参考になれば👍でした．どうも．
【TypeScript】型の条件分岐

以下のように記述すると`id`と`name`は`isLoading`が`true`の場合には任意に`false`の場合には必須になります。

```ts
type Sample<T extends boolean> = T extends true
  ? {
      isLoading: T
      id?: string
      name?: string
    }
  : {
      isLoading: T
      id: string
      name: string
    }


// 以下のように使用
Sample<boolean>
```

`Sample<boolean>`のように引数に`boolean`を設定した場合には`Sample<true | false>`とした場合と同様になります。
結果として以下のような型になります。

```ts
type SampleBoolean = Sample<boolean>

type SampleBoolean =
  | {
      isLoading: true
      id?: string
      name?: string
    }
  | {
      isLoading: false
      id: string
      name: string
    }
```

https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types

そのため、`id`と`name`は`isLoading`が`true`の場合には任意に、`false`の場合には必須ということになります。

また、`Sample`の引数に`boolean`ではなく`true`、`false`というより具体的な型を指定すると以下のようになります。

```ts
type SampleTrue = Sample<true>

type SampleTrue = 
  {
    isLoading: true
    id?: string
    name?: string
  }


type SampleFalse = Sample<false>

type SampleFalse = 
  {
    isLoading: false
    id: string
    name: string
  }
```
CloudFormationでForEach関数を使う

## 背景
- 直近terraformばかり使っていたがCloudFormationを使う機会に恵まれた
- 同じようなリソースの繰り返し記述を前にチェックの大変さを想像し悲しくなる
- ForEach関数でレビューの負荷を下げることができれば嬉しい
- 何番煎じかわからないがこの記事が誰かの役に立つと嬉しい

## 練習
- VPC2個とそのVPCに紐づくSubnetを2個作る

## サンプルコード

```yaml
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::LanguageExtensions
Mappings:
  VpcM:
    Vpc01:
      Cidr: 10.0.1.0/24
      Name: test-vpc-01
    Vpc02:
      Cidr: 10.0.2.0/24
      Name: test-vpc-02
  SubnetVpc01M:
    Vpc01Prv01:
      Cidr: 10.0.1.0/28
      Az: ap-northeast-1a
      Name: Vpc01Prv01
    Vpc01Prv02:
      Cidr: 10.0.1.16/28
      Az: ap-northeast-1c
      Name: Vpc01Prv02
  SubnetVpc02M:
    Vpc02Prv01:
      Cidr: 10.0.2.0/28
      Az: ap-northeast-1a
      Name: Vpc02Prv01
    Vpc02Prv02:
      Cidr: "10.0.2.16/28"
      Az: "ap-northeast-1c"
      Name: Vpc02Prv02

Resources:
# vpc
  'Fn::ForEach::VPC':
    - VpcName
    - [Vpc01, Vpc02]
    - '${VpcName}':
        Type: 'AWS::EC2::VPC'
        Properties: 
          CidrBlock: !FindInMap [VpcM, !Ref VpcName, Cidr]
          EnableDnsHostnames: true
          EnableDnsSupport: true
          Tags:
            - Key:  Name
              Value: !FindInMap [VpcM, !Ref VpcName, Name]

# vpc01 subnet
  'Fn::ForEach::SubnetVpc1':
    - SubnetName
    - [Vpc01Prv01, Vpc01Prv02]
    - '${SubnetName}':
        Type: 'AWS::EC2::Subnet'
        Properties:
          AvailabilityZone: !FindInMap [SubnetVpc01M, !Ref SubnetName, Az]
          # 修正したいポイント(後述)
          VpcId: !Ref Vpc01
          CidrBlock: !FindInMap [SubnetVpc01M, !Ref SubnetName, Cidr]
          Tags:
            - Key: Name
              Value: !FindInMap [SubnetVpc01M, !Ref SubnetName, Name]
  
# vpc02 subnet
  'Fn::ForEach::SubnetVpc2':
    - SubnetName
    - [Vpc02Prv01, Vpc02Prv02]
    - '${SubnetName}':
        Type: 'AWS::EC2::Subnet'
        Properties:
          AvailabilityZone: !FindInMap [SubnetVpc02M, !Ref SubnetName, Az]
          # 修正したいポイント(後述)
          VpcId: !Ref Vpc02
          CidrBlock: !FindInMap [SubnetVpc02M, !Ref SubnetName, Cidr]
          Tags:
            - Key: Name
              Value: !FindInMap [SubnetVpc02M, !Ref SubnetName, Name]



```

## ハマったところ
- 以下エラーによく遭遇。色々確認したが、私の場合100%インデントのミス

```
Transform AWS::LanguageExtensions failed with: Duplicate key 'Type' when merging keys to parent object in Fn::ForEach. Rollback requested by user.
```

## クリアできなかったところ
- 以下を見る限り[AWS::LanguageExtensions]を使っていれば、Ref関数内でFindMap関数を使用できそうなのだけれども、参照方法がわからず、結果サブネットリソースのVpcIDの参照をハードコードしてしまった（うまくいけばもう少し圧縮できたと思う）

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html#ref-supported-functions
【行によって長さが違う二次元配列の表示】すべての行の長さと値が不定な 2 次元配列の出力 Python3編

今日の最終問題
https://paiza.jp/works/mondai/stdout_primer/stdout_primer__variable_array_boss
たとえば、こんなふうに入力が与えられるとすると

10 4
1 2 3 4 5 6 7 8 9 10
2 6 1 1

最初の行は全部の数と、行数
2行目は全部の数
3行めは何番目まで出力するかを示している
つまり、3行目は　2文字まで、6文字まで、1文字まで、1文字まで、というのを表している。
出力は
1 2
3 4 5 6 7 8
9
10
となる。

---
さて、解いてみたが、最後の最後、一方のループを止めず、一方のループをリセットする方法が見つからずギブアップ。
参考までに私が書いたやつ。

```py
tmp = input().split()
N = int(tmp[0])
M = int(tmp[1])

values = input().split()
A =[0] * N
for i in range(N):
    A[i] = int(values[i])
    
nums = input().split()
B = [0] * M
for j in range(M):
    B[j] = int(nums[j])

for k in range(1,N+1):
    
    for l in B:
        if k == l:
            print(k)
        else:
            print(k,end=" ")
        k = k + 1

```

10 4
1 2 3 4 5 6 7 8 9 10
2 6 1 1

で正解はどうするかというと、
途中までは合っていたらしいが、
一方のループを止めないところをどうするか。

まず、A配列は1〜10。B配列は何文字目までを止めるかを配列に入れている。

で、まず、Bループを回して
i、つまり上の場合だと、まず2が出てくる。
そこまでをforループで range関数に引数iにして、jで回す。
そうすると1~3まで出力できる。そこで、i-1になるときに改行すればOK
このとき、iは使えないので別の変数、下の場合headを使う。これをつかうことで、
iとは関係なく、Aループのheadを保存することができる。
その次は3文字目から6文字目までだが、headがこのとき開始indexを保存しているので
引き続き出力が可能になる。


```py
head = 0
for i in B:
    for j in range(i):
        if j == i - 1:
            print(A[head])
        else:
            print(A[head], end=" ")

        head += 1
```

聞いてみればなるほど、と思った。
もはやそれしか感想が思いつかないが。
私の中では、どうやってスキップしようかとか考えてたので、
他の変数に保存することが思いつかなかったなぁと反省。
勉強になりましたー。
Vue3におけるpropsの値の監視(watch)

# 前提知識

vueやref、watchについて知識ある人は[本文まで](#本文)読み飛ばしてください。

## リアクティビティとは

Vueのリアクティビティシステムは、データの変更を検知し、それに応じてUIを自動更新します。
これにより、データとUIの一貫性が保たれ、開発者はデータの管理に集中できます。

## refとは

Vue 3で導入された`ref`は、値をリアクティブにするための関数です。
これにより、値の変更がVueシステムによって追跡され、関連するUIが更新されます。

## ウォッチャーとは

ウォッチャーは、データや状態の変更を監視し、変更があった際にカスタムの副作用やロジックを実行する機能です。

## watchとは

`watch`はVueにおいてウォッチャーを作成するVueのAPIです。
これにより、指定したデータソースの変更を監視し、変更があった際にコールバック関数を実行します。

## サンプルコード

```vue
<script setup lang="ts">
import { ref, watch } from 'vue';

// refを使ってリアクティブなカウンターを作成
const count = ref(0);

// watchを使ってcountの変更を監視
watch(count, (newValue, oldValue) => {
  // カウンターが変更されたときにコンソールにログを出力
  console.log(`カウントが ${oldValue} から ${newValue} に変更されました。`);
});

// カウンターを増加させる関数
const increment = () => {
  count.value++;
};
</script>

<template>
  <div>
    <p>カウント: {{ count }}</p>
    <button @click="increment">増加</button>
  </div>
</template>
```

この例では、countはrefを使用して作成されたリアクティブな値です。
count.valueの値が変わると、Vueのリアクティビティシステムがこれを検知し、関連するUI部分を自動的に更新します。
また、watchはcountの変更を監視し、変更があるたびにコールバック関数を実行して、変更をコンソールにログ出力します。
これにより、Vueのリアクティビティシステムの動作原理を理解するのに役立ちます。

https://ja.vuejs.org/guide/extras/reactivity-in-depth.html

# 本文

vue3において親要素から渡したpropsの値を下記のようにwatchしようとしたら、値の変更が検知されなかった。

```vue
<script setup lang="ts">
watch(props.selectedSiteJsUrls, (newUrls, oldUrls) => {
    // ここには配列が変更されたときに実行するコードを書きます。
    console.log('新しいURLリスト:', newUrls);
    console.log('古いURLリスト:', oldUrls);
});
</script>
```

下記のようにアロー関数で渡し、`deep:true`をつけると、値の変更が検知され、consoleが呼ばれるようになる

```ts
<script setup lang="ts">
watch(() => props.selectedSiteJsUrls, (newUrls, oldUrls) => {
    console.log('新しいURLリスト:', newUrls);
    console.log('古いURLリスト:', oldUrls);
}, { deep: true });
</script>
```

## chatgpt先生による解説

Vue 3のリアクティブシステムにおいて、アロー関数を使用してプロパティをラップする理由は
Vueが内部的にリアクティブな依存関係を追跡する方法に関連しています。
直接的にpropsのプロパティをwatchに渡す場合（例：watch(props.selectedSiteJsUrls, callback)）と
アロー関数を使用する場合（例：watch(() => props.selectedSiteJsUrls, callback)）の違いを理解することが重要です。

### アロー関数の使用

* リアクティブな依存関係の設定： Vueのリアクティブシステムは、アロー関数内でアクセスされるプロパティを「依存関係」として認識し、これらのプロパティが変更されたときに関連するリアクティブな効果（この場合はwatchコールバック）をトリガーします。
* 値の変更の追跡： アロー関数内でプロパティにアクセスすることにより、Vueはそのプロパティの値が変更された場合にのみ、watchコールバックを実行するように設定します。これにより、プロパティの値そのものの変更をより正確に追跡できます。
* より細かい制御： アロー関数を使用することで、プロパティの特定の部分（例えば、オブジェクトの特定のキー）だけを監視するように設定することが可能になります。これは、より細かく監視の範囲を制御するのに役立ちます。

### 直接propsを渡す場合

* リファレンスの変更のみの追跡： 直接propsのプロパティをwatchに渡すと、Vueはそのプロパティのリファレンス（参照）が変更された場合にのみ反応します。つまり、配列やオブジェクトの中身が変わっても、そのリファレンスが同じであれば、変更は検知されません。
* 深い監視（deepオプション）の必要性： リファレンス型のデータ（例：オブジェクトや配列）の内容が変更された場合にこれを検知するためには、deepオプションを設定する必要があります。
結論
* アロー関数を使用してプロパティをラップすることにより、Vueはそのプロパティの現在の値の変更を追跡し、変更があった場合にのみリアクティブな効果（watchコールバック）をトリガーします。これにより、より正確に、かつ細かくプロパティの変更を検知することができます。

### deep:trueに関して

Vue 3において、アロー関数を使用してwatchを設定する場合、deep: trueオプションの必要性は、監視対象のデータの種類に依存します。具体的には：

* プリミティブ値（文字列、数値、ブーリアンなど）：これらの値に対しては、deep: trueは必要ありません。プリミティブ値の変更は、Vueのリアクティブシステムによって自動的に検知されます。

* オブジェクトや配列：これらのリファレンス型のデータに対してwatchを使う場合、deep: trueオプションが重要になることがあります。deep: trueを設定すると、Vueはオブジェクトや配列の内部の変更（プロパティの追加/削除や配列の要素の変更など）も検知します。

例えば、props.selectedSiteJsUrlsが配列である場合、この配列内の要素が変更されたときにそれを検知したいなら、deep: trueオプションが必要です。
rex0220 計算式プラグインの使い方をGPTsに学習させてみる（その７）誤った計算式の訂正学習

[rex0220 計算式プラグインの使い方をGPTsに学習させてみる（その６）](https://qiita.com/rex0220/items/196b0eab24179c928e69)の続きです。
誤った計算式の訂正学習を試してみます。

# 概要

「前月の10日を算出する例は？」の問いに、学習前は誤った計算式を応答
※前月ではなく、当月の10日を計算した

質問と答えをそのまま学習させて試してみた。

- 学習前：DATE_FORMAT(DATE_ADD(DATE_STARTOF(日付項目, "month"), 9, "day"), "YYYY-MM-DD")
![2023-11-16_22h23_26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/124b0e67-df9a-a19a-0950-604f4a10928a.png)

- 学習後：DATE_ADD("TODAY", -1, "month", "YYYY-MM-10")
![2023-11-16_22h23_51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/8f988c25-e544-968f-1e0e-6bf18b9ff79f.png)

# 学習内容

下記をDATE_ADD関数の説明に追加。
誤った応答がある場合は、質問と答えをそのまま記述したほうがいいと思われる。

>前月の10日を算出する例；書式の日にちに"10"を指定
　DATE_ADD(日付, -1, "month", "YYYY-MM-10") 


```.function1.txt
・DATE_ADD関数について
DATE_ADD：日付加算

DATE_ADD(項目|"TODAY", num, type [,format])
  "TODAY": 当日日時
  num: 数値
  type:"year", "month", "week", "day", "hour", "minute", "second"
  format: ["YYYY-MM-DD"]

ex:
DATE_ADD(日付, 1, "month")
DATE_ADD(日付, -1, "month", "YYYY-MM-01") ※前月1日
DATE_ADD(日付, -1, "month", "YYYY-MM-10") ※前月10日
DATE_ENDOF(DATE_ADD(日付,1,"month"), "month") ※来月末日

前月の10日を算出する例；書式の日にちに"10"を指定
　DATE_ADD(日付, -1, "month", "YYYY-MM-10") 

```

# ２か月前の１０日を計算
「日付項目の２か月前の１０日を計算」
>DATE_FORMAT(DATE_ADD(日付項目, -2, "month"), "YYYY-MM-10")

間違ってはいないが、DATE_ADD(日付項目, -2, "month", "YYYY-MM-10") と応答してほしいところ。
応用は、難しいらしい。

![2023-11-16_22h38_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/d659cbc4-4d17-46a0-8ef8-d3b896db74eb.png)

# 学習内容２

2ヶ月前の10日の例を追加

>前月の10日を算出する例；書式の日にちに"10"を指定
　DATE_ADD(日付, -1, "month", "YYYY-MM-10") 
2ヶ月前の10日を算出する例；書式の日にちに"10"を指定
　DATE_ADD(日付, -2, "month", "YYYY-MM-10") 

# ２か月前の１０日を計算（その２）

こんどは、問題なく「DATE_ADD(日付, -2, "month", "YYYY-MM-10")」
ただ説明に誤りがあり、「DATE_FORMAT 関数を使って」とあるが使っておらず、オプションの書式を指定している。

![2023-11-16_22h46_37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/fbf77529-296d-28ff-94aa-346d27ea6d0c.png)

# 学習内容３

2ヶ月前の10日の例を訂正。
「DATE_ADDのformatオプションで日付書式に"10"を指定」とオプションを明確に記述

>前月の10日を算出する例: DATE_ADDのformatオプションで日付書式に"10"を指定
　DATE_ADD(日付, -1, "month", "YYYY-MM-10") 
2ヶ月前の10日を算出する例: DATE_ADDのformatオプションで日付書式に"10"を指定
　DATE_ADD(日付, -2, "month", "YYYY-MM-10") 

# ２か月前の１０日を計算（その３）

こんどは、説明も問題なく応答された。

![2023-11-16_23h07_39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/3539f163-4eb1-58de-7967-694394069d25.png)

# ４か月前の１５日を計算

「日付項目の４か月前の１５日を計算」では、応用が利き、
「DATE_ADD(日付, -4, "month", "YYYY-MM-15")」が応答された。

![2023-11-16_23h09_19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/a6db41fb-d9e6-83df-93f9-1c47c9b376a5.png)


# まとめ

誤った計算式の訂正や、効率的な計算式の学習には、いくつか計算例のパターンを学習させる必要がある。
また、説明文も誤解の生じないように明確に記述する必要がある。
いろいろ問合せと応答を確認しつつ、説明をブラッシュアップすることの繰り返しですね。
現在いるセルのURLを叩いてレスポンスを右側に格納する[GAS/Google Apps Script]書いた

## はじめに

いい感じのスクリプト書いたので忘れないように投稿しておく。


## イメージ


![スクリーンショット 2023-11-16 22.21.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112929/4f428b4c-89fe-b9b9-d9a3-27ad54d356dd.png)


## コード

fetchするURLは `https://httpbin.org/get`

gasのコードはこんな感じ

```javascript
function fetchApi() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getActiveSheet();
  const cell = sheet.getCurrentCell();
  const [col, row, url] = [cell.getColumn(), cell.getRow(), cell.getValue()];

  const res = UrlFetchApp.fetch(url);
  const result = res.getContentText();
  const code = res.getResponseCode();

  sheet.getRange(row, col + 1, 1, 1).setValue(`CODE: ${code}, RESULT: ${result}`);
}


```

* 今いるセルのURLを取ってくる
* Fetchする
* 右隣に結果を書き込む


## 設定

### Apps Script

![スクリーンショット 2023-11-16 22.22.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112929/606db9ae-b1f5-106a-d9e9-cfa03fed73be.png)

### 図形描画
![スクリーンショット 2023-11-16 22.22.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112929/7a1e904d-1d14-c436-7222-d265342aa6da.png)

### 図形へのスクリプト割当

fetchApi　を設定

![スクリーンショット 2023-11-16 22.23.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112929/a402951f-a54a-9f08-f037-50833f45cf11.png)


### 認証関連もろもろ

自分が作ったスクリプトなのにかなり権限しつこく聞かれる。
基本的に他人が作ったスクリプトに権限渡さない。Googleの認証とかこのあと入る

![スクリーンショット 2023-11-16 22.07.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112929/ad7d3c4b-98c7-f01e-fe0e-168e129032a7.png)


## 終わりに

今回は具体的にはJamstackでお世話になりやすい https://microcms.io/ さんのブログ取得APIを使って、microcms側でブログを書いて、定期的にスプレッドシートにコンテンツを出力、それをコピペしてhtmlに埋め込む、みたいなことやってて必要になったので作りました。

その場合、以下のような書き方に一部変更されますが、概ね簡単な作業でできたので満足です。

```js
  const options = {
    'method' : 'get',
    'headers': {
      "X-MICROCMS-API-KEY": "あなたのAPIキー"
    }
  };
  const res = UrlFetchApp.fetch(url, options);
  const content = JSON.parse(res.getContentText()).content
```
ファイルコピーアクティビティが機能しなかった話について

# 1.はじめに
クラシックアクティビティからモダンアクティビティに変更しようとしている中で表題の件が起こりました。
これを解決するのに3か月かかり、ふと案が思い浮かんでそれで解決できました。

# 2.前提

:::note info
ざっくりですが、使用しているアクティビティは下記のスクショの通りです。
Excel操作して、DドライブにあるファイルをSharePointにアップロードする手順です。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327229/dc790ca4-4550-2031-d0c4-23b590a56086.png)

:::note alert
この流れだとOrchestratorからのトリガー実行だと正常終了するものの、SharePointにアップロードできていない事象が発生しました。
:::

# 3.試したこと
### (1)待機アクティビティを追加

:::note info
下記のスクショの通りで、待機5秒を追加しました。
:::
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327229/0c15d837-9cbc-83aa-472d-9b2d64f1108f.png)

追加した理由は、重いファイルだったので、保存に時間がかかったのでは？と思いました。
そんなことはあるのか？と半信半疑というよりも疑しかなかったですが、、、。

:::note alert
結果は同じでした。
:::

### (2)ファイルコピー⇒ファイルを移動アクティビティに変更

:::note info
下記のスクショの通りです。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327229/1b932856-c11f-5a4d-5172-6d78bb93569d.png)

:::note alert
結果は同じでした。
:::

### (3)Excelプロセススコープ内の一番最後に名前を付けてExcelファイルを保存アクティビティを追加

:::note info
下記の通りで、最後に名前を付けてExcelファイルを保存を追加。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327229/540c54f2-7911-1f79-0c5b-3fc9a7b94a83.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3327229/1337c146-450d-062b-1473-481d69f34f9f.png)

今までの開発ルール、お作法に乗っ取らないが、モダンを使用していくにはこういう実験も必要かと思いしたところ、、、。

:::note info
これが正解でファイルをSharePointに格納できました！！
:::

# 4.さいごに
モダン化するあたって、今までの常識で通用しないことがわかりました。
**そういうときにはモダンのみで解決できないか？と調べてみることが大事だと思いました！！**
開発ルールもこれから見直さないといけないです。
AIで人の仕事はなくなるのか？

結論から言うと、無くなりません。むしろ増えます。

えー！ふざけんなよー！と思ったそこのあなた。なんでもネガティブに捉えないでください。
むしろ今までなんでこんな無駄なことしないといけないんだよーって思ってた単純作業や無駄な仕事が無くなります。
最高にハッピーです。むしろ今までだって人類はやりたくない重労働をテクノロジーに置き換えてきました。今日からお前は電車にも自動車にも乗らずに馬に乗れ！とか明日から手で畑を耕せ！とか、洗濯も手でやってねとか言われても無理ですよね？

マジでOpenAI社凄すぎ。ChatGPT-4も凄いがDALL-E3もヤバい。ほんと、自分もITコンサルだからほとんど仕事なくなるからヤバいんだけどｗそれよりも知的好奇心の方が勝ってしまう。もうこれがシンギュラリティなんだけど、別に混乱なんか起きなくて、これと似たような事が実はインターネットの登場だったと思っている。

インターネットの登場により、ソフトウェア開発は根本的に変わった。まぁ、以下の文章はHups の共同創設者でアジャイルの専門家である Henrik Knibergの記事の和訳に過ぎないんだけど、首がもげるほど同意したので、日本の非エンジニアの人にもわかりやすい表現に直して自分の言葉で解説してみようかと思い書いてたら長くなったのでブログにもしましたｗ（最初はFBにだけPostしようと思ってた。）

ソース記事が見たい方はこちらからどうぞ
https://hups.com/blog/are-developers-needed-in-the-age-of-ai

インターネット登場前までは、技術的な問題を解決するためには、その特定の分野で何年もの専門知識を積む必要があったんだけど、今ではGoogle、YouTube、Redditで調べれば大抵のやり方やソースコードが動画で丁寧に説明されてる。しかもご丁寧にサンプルコードスニペットなんかも置いてあったり、ダウンロードできる無料のオープンソースコードライブラリや、それを備えた各種フレームワークまで用意されている。

その時もITエンジニアの生産性は10倍位上がったと思う。ちょっとググればすぐに、専門家レベルの知識、コード例、役に立つビデオなどを瞬時に無限に見つけられる。つまり、現在のエンジニアにとって最も重要なスキルの 1 つは、情報を検索し、既存のツールやフレームワークを見つけてレゴブロックの用に上手く組み合わて、それらが全体像にどのように適合して実際のビジネス課題を解決できるかを理解する能力だと思います。

すべての基本的な問題（パスワード認証とか、ファイル解析など）はすでにほぼ解決されており、車輪を再発明する必要がないというのはよくIT業界で言われていますが、開発は実際にコードを入力するというよりも、2000年ごろからはアジャイル開発という概念が入ってきて、コミュニケーションと統合に重点を置くようになっていきました。

インターネットが普及し始めた 90 年代初頭に遡ると、エンジニアのほとんどが余剰人員になるだろうと推測したかもしれません。このようなツールによって開発者の生産性が 10 倍向上するのであれば、必要な開発者は少なくて済みますよね？チーム全体ではなく、1 人だけでしょうか？そうすると、多くの人が職を失うことになりますよね？

そんな訳で実際どうなったかのエビデンスを調べてみたら、まったく逆のことが起こったことがわかりました。ソフトウェア業界は爆発的な成長を遂げています。2022 年の時点で、世界には約 2,800 万人のソフトウェア開発者がおり、一貫して増加しています。

ソース
https://www.statista.com/statistics/627312/worldwide-developer-population/

「当社の開発者の生産性は 10 倍なので、90% を解雇できます!」とも言えますが、「当社の開発者の生産性は 10 倍なので、同じ人数で 10 倍の製品や機能を作成することができます!」と言うことができます。そして、実際に各開発者の効率が向上するにつれて、より多くの企業がソフトウェアを構築することが経済的合理性があると判断し、ソフトウェア開発者の需要が世界中で増加していきました。

ただ、人が減らせるから省力化に進むって業態や産業もあると思う。斜陽産業や衰退産業の「新聞・テレビ・ラジオ」などのマスメディアは完全に終わりだろう。テレビの情報よりChatGPTの情報の方がよっぽど信頼できるしｗｗｗ

実際、自動運転が実用化したらワキガ臭い80歳のタクシー運転手とかいらなくなるしね。乗りたくないでしょう？そんな高齢者が運転する車。だけど、生産性が10倍になっても人は働くのをやめない。過去のインターネットやプログラミングが出てきてからもそうだった。

ちなみに、もう既に知能や知識では人間ではChatGPTに敵わない。だけど、それで仕事が減るってのは全然違くて、また新しい仕事が出てくるんだよ。むしろ、１番ローテクな法曹関係なんかは一気に変わる可能性がある。まぁ、日本では団塊の世代の既得権益ジジイどもが妨害工作をしてまた世界に置いてけぼりにされるんだろうけど。。。

システム開発においては今までは大規模なシステムに莫大なお金を掛けてたけど、一人のエンジニアが出来ることの幅が二次関数的な曲線を描いて増えていくので、そのうち自然言語でこんなシステムつくってってAIにお願いしたらAIがテストからデプロイからビルドまでぜーんぶ自動化してくれる未来が待っていると思う。（4000億円以上かけてもいまだにバグだらけでたまにATMからお金を引き出せなくなる某銀行のサグラダファミリア問題もサクッと解決するかもねｗ）

まぁ、動画は見て損はないと思うし、英語が苦手でも自動翻訳字幕機能付けたらほぼ完璧に理解できるし、ほんとテクノロジーの恩恵を受けまくってるね、我々人類は。いやー、本当に面白い時代に生まれて良かった。

https://www.youtube.com/live/U9mJuUkhUzk?si=R3T7-KfRJOUWwHkU
terraform init で「Error: failed to get shared config profile」

# 概要

環境：MacOS
以下の様にAWSのssoプロファイルを使ってs3バックエンドを定義

```hcl
terraform {
  backend "s3" {
    bucket = "sample-bucket"
    key = "terraform.tfstate"
    region = "ap-northeast-1"
    profile = "sso-my-profile"
  }
}
```

この状態でterraform initすると以下のエラーになった。

```bash
Initializing the backend...
╷
│ Error: failed to get shared config profile, sso-my-profile
```

# 原因と解決策

いつぞや環境変数に設定していた`AWS_CONFIG_FILE`が原因だった。

```bash: ~/.zshrc
export AWS_CONFIG_FILE="~/.aws/config"
```

~~デフォルトパスなのでそもそも指定する必要はないのだが...~~
このパスの「~」がうまく認識されておらず、configファイルをうまく参照できていなかったらしい。
該当の環境変数を消したら無事terraform initが通った。
【クロスプラットフォーム開発入門】Flutterとはなにか

# はじめに
最近の業務でクロスプラットフォーム開発のフレームワークの一つであるFlutterに触れるようになってきたので、自分が学んだことを整理するためにもここにまとめていこうと思います。

# クロスプラットフォーム開発
まず、クロスプラットフォームとはAndroidやiOS、WindowsやMac OSなど異なる環境でも一つの開発言語をもとに同じ仕様のアプリケーションを動かすことを可能にするフレームワークのことを指します。
本来はAndroidではJavaやKotlin、iOSではObjective-CやSwiftといった言語を使用して、それぞれのIDE（Android StudioやXcode）で開発を進めていく必要があります。
そのため、両方のプラットフォームに対応したアプリを開発する場合はソースコードがプラットフォーム間で別れてしまい、開発工数がかかってしまったり、メンテナンスのコストがかかってしまったりします。
クロスプラットフォーム開発ではプラットフォーム間で共通の言語を使用するため、前述したコストを抑えることが期待できます。
クロスプラットフォーム開発のフレームワークにはReact NativeやXamarinなどいくつか存在しますが、この記事ではFlutterに焦点をあてていきます。

:::note info
**要点**
クロスプラットフォーム開発とは異なるプラットフォーム間で同じアプリケーションの開発を可能にするフレームワークのこと。
:::

# Flutterとは
Flutterは2018年にGoogleからリリースされた、**モバイルアプリ開発向けのクロスプラットフォーム開発フレームワーク**です。モバイルアプリ向けと書いたように、最大の特徴は「**AndroidとiOSのアプリを同時に開発することができる**」です。
その他の代表的な特徴としては**ホットリロード機能**が搭載されていることも挙げられます。これは、プログラムを変更した際に、**即座にUIへと反映する**ことができる機能です。
従来のアプリ開発ではプログラムに変更を加えて確認する際に、その都度ビルドを行う必要があるために時間がかかってしまいましたが、Flutterではその必要がなく、**効率的に開発を進めることが可能**になります。
Flutterの開発言語には**Dart**を使用します。これは元々JavaScriptの代替言語として2011年に登場した言語であり、JavaScriptやJavaと似ている文法となっているので、これらの経験がある方にとっては理解がしやすいことが特徴です。また、OS固有の実装が必要な場合（Push通知など）は各OSの開発言語で実装を行うこともできます。

:::note info
**要点**
Flutterはモバイルアプリ開発向けのクロスプラットフォーム開発フレームワークのこと。
開発言語はDartを使用する。
ホットリロード機能によって効率的に開発することができる。
:::

## メリット

* AndroidとiOSで同じ仕様のアプリを同時に開発することができるため、開発コストが削減される。
* 基本的に共通言語を使用するため、仕様変更や運用保守のコストが削減される。
* ホットリロード機能が搭載されているため、開発効率が良い。

## デメリット

* Dart言語を使用するため、学習コストがかかる場合がある。
* 比較的新しめの技術であるため、従来通りの開発と比べると情報が少ない。
* 各OS固有の不具合などが発生するとその原因を見つけにくい。

# まとめ
Flutterの特徴とメリット・デメリットについて簡単にまとめてみました。徐々に普及してきているようで、日本語で書かれた情報も増えてきているので、モバイルアプリ開発に興味のある方は調べてみると良いと思います。私もまだまだ勉強を始めたばかりなので、これから始める方は一緒に頑張っていきましょう！

# 参考
https://qiita.com/nskydiving/items/c13c949cc17c6f980a67

https://www.offshore-kaihatsu.com/contents/general/cross-platform/

https://genee.jp/contents/tech0005/

https://spice-factory.co.jp/smartphone-app/application-engineer-talk-about-flutter/
【メモ】Goの環境設定

MacOSの場合

1. Goのダウンロードページにアクセス https://go.dev/dl/
2. 自分のPCのOSに応じ、選んでダウンロード
3. インストール
4. ターミナルで`ls /usr/local/go/bin`で`go`が表示されるかを確認
5. 右記を実行 `echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.zshrc`
6. 右記を実行 `source ~/.zshrc`で変更内容を適用
7. `go version`でバージョンが表示されたら成功
【直前㊙️テク】TOEICあるあるを網羅！〜変な常識を知って、点数を稼ぐ！

以下のやり方で`TOEIC 800`行きました。

直前にささっと読んで、点数を稼ぐ助けとなれば💪
網羅してます。

## TOEICあるある（変な常識）
- 基本的に平和な世界
- コピー機が故障する
- 仕事中にランチの誘い
- 通販の配送トラブル
- 商品の故障、破損対応
- 政治や宗教に関しては出題されない
- 複雑な人間関係・過度に深刻な事態が出題されることはない
- 韓国人は「Kim(金)」

以下には例も載せてます。

- ツアーに参加したら、帰りはお土産物コーナーに立ち寄る
> Please be sure to visit our gift shop at the end of this tour.
- ラジオの交通情報では渋滞に関する話題が定番
> Route 10 will be congested because of road construction.
- イベントを企画すれば大盛況
> The conference room accommodates only 70 people.
- 病院の予約は医者の都合でキャンセルされる
> I apologize for the inconvenience this has caused you.
- ランチは誘っても断られてしまう
> The report needs to be completed by noon.
- 会社の倒産やリストラの話は皆無
> The sales of our shampoo have increased sharply over the year.
- コピー機が壊れていて誰も修理できない
> The copy-machine doesn’t seem to be working.
- パート１（写真描写問題）の机上は散らかっている
> The artwork is hanging on the wall.
- イベントのチケットが取れても行けなくなることが多い
> Do you happen to know someone who are interested in this game.
- 飛行機は遅れる
> The flight was delayed due to bad weather.

# 一緒に頑張りましょう💖
【SwiftUI】動画を再生する

# はじめに
SwiftUIで動画を再生するサンプルを記事にしときます。

# サンプルアプリ
![Simulator Screen Recording - iPhone 15 - 2023-11-16 at 21.38.46.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/ac3111c7-93e3-bd7c-d306-65e1adbaccff.gif)

# 実装
### インターネット上にある動画を再生する
```swift
import SwiftUI
import AVKit

struct ContentView: View {
    let url: URL = URL(string: "https://taishin-miyamoto.com/sample.mp4")!

    var player: AVPlayer? {
        .init(url: url)
    }

    var body: some View {
        VideoPlayer(player: player)
    }
}
```

### ローカルに用意した動画を再生する
![スクリーンショット 2023-11-16 21.29.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/dbb364ee-4552-2656-735f-8ad13caabb6a.png)
```swift
import SwiftUI
import AVKit

struct ContentView: View {
    let url: URL = Bundle.main.url(forResource: "sample", withExtension: "mp4")!

    var player: AVPlayer {
        .init(url: url)
    }

    var body: some View {
        VideoPlayer(player: player)
    }
}
```

# おわり
UIKitをラップして使わないといけない記憶があったのですが、めっちゃ簡単に使えました
Gitのコミットを既存のSSH鍵(1password SSH Agent)で署名する 

GitHubがSSH鍵によるコミット署名の検証をサポートした
↓
1passwordのSSH Agentが便利！これであなたもVerified
↓
PCを変えた
↓
署名の設定の方法忘れてUnverifiedユーザになっちゃった！

---

- 1passwordで該当の鍵に対し「コミットの署名を設定する」

![スクリーンショット 2023-11-16 21.23.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178486/bb59113b-911b-72e4-6bbb-9ae4ae8b55ad.png)

- 自動的に編集してもらう
 
![スクリーンショット 2023-11-16 21.27.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178486/5072ce6b-5476-d6a0-cf44-03c2076dabe2.png)

- ForkのGlobal User Informationを自分の情報にする

![スクリーンショット 2023-11-16 21.36.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178486/55dc0722-3c23-cb13-4226-d0c99c4e59fe.png)

---

最後のを忘れてたせいでしばらくUnverifiedユーザーだった　すみません
ReactでのuseState②

## はじめに
ReactでのuseState②の備忘録です💁
初心者です😅
間違えてる部分多々あると思います。
もし見つけた場合、ツッコミいただけると助かります🙇


## 内容
Reactでのお問い合わせフォームを作成。いただいたお問い合わせを自身のメールに通知して内容を確認できるためにはサーバーの概念とHTTPリクエストの概念を学んだ。

```jsx:Contact.js
const Contact = () => {
    const [user, setUser] = useState({
        name:"",
        Email:"",
        Comment:"",
    });

    const handleUser = (e) => {
        setUser((prev) => ({...prev, [e.target.name]: e.target.value}));
    };
```

:::note warn
注意点
* (e)はeventを省略して記載してる。
:::

:::note info
押さえておくべき点🧠
* user : 初期化された箱。この中に3つのname属性の小さな箱がある（name,Email,Comment）
* setUser : 更新を定義する変数
* prev : 直前の状態のものを指す（user）更新される前のuser（ここではなにも入力されてない）の状態
* ...prev : userオブジェクトを新しく作成（更新されてるものが反映されてる）
*  (e) : eventの略。関数が呼び出された時にアクションがあった時に動作する。
* [e.target.name]はuserにあるname属性を取得する（’name''Email''Comment’）
* e.target.valueはuserにある[e.target.name]で得た属性の値を取得する。
:::
【メモ】SAMのLambdaの記述

# 前提
Runtimeはpythonを指定。
今回使用したキー情報のみを記述。


## 記述例

```yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
    # S3 Buckets
    BucketName:
        Type: AWS::S3::Bucket
        
    # Lambda Functions
    FunctionName:
        Type: AWS::Serverless::Function # Serverless::FunctionがLambdaのこと
        Properties:
            Handler: app.handler #ここはファイル名.メソッド名で記述する。pythonの場合、app.pyのhandler関数を呼び出すということになる
            Runtime: python3.11 
            CodeUri: ./test/ # 実行ファイルがあるパス
    Policies:
        # S3へのアップロードが必要であれば「S3CrudPolicy」のような記述をする。
    Environment:
        Variables:
            # 環境変数をセットする場合、ここに記述する。その際に「!Ref [インんスタンス名]」のように変数を格納できる。
```

## 所感
- 他にもmemory等の設定も記述できるため、コンソールで行うのと同じように様々な設定ができることが便利。
- pythonの場合、requirements.txtが実行スクリプトファイルと同じ階層にありそ子にライブラリを追加することで簡単にLambdaの実行環境が作れるように感じた。Layer追加やECRを使用したコンテナLambdaのよリも楽に設定できる。
    - ライブラリの容量が少ない場合に適しており、ライブラリの容量が大きい場合やライブラリの使用にあたり様々なモジュールがimportされる場合はLayer・コンテナLambdaを使用した方が良い印象。

## 参考
https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/sam-specification-template-anatomy-globals.html
自作アプリのシェア画像は画像でも動画でもなく、GIFでやるのが良いのではないかという仮説

自作アプリをシェアするなら、画像でも動画でもなく、GIFが最適なんじゃあないか、そう考えた私は、アマゾンの奥地へと進むのだった。

# 理由1.　容量の小ささ 💼
GIFは動画よりもサイズが小さく、通学や通勤中の通信容量心配なし！いつでもどこでも手軽にシェアできます。

# 理由2. ミュート対応 🎶
通学や通勤中、音を出してアプリの説明を聞く機会は限られているかもしれません。そんなときはミュートならGIFで十分楽しめます！

# 理由3. 目を惹くリッチな表現 🌟
画像よりもリッチで、視覚的に訴える力があります。使い勝手も抜群で、ユーザーの興味を引きつけること間違いなし！

# 理由4. iOSでも安心のシェア 📱
iOSユーザーの場合、GIFをシェアしても、「画像をシェア」というメッセージになり、容量を気にせずシェアする可能性。

自分が人柱になってやってみます。
ゲーミングCSSを作ってQiitaを光らせてみた

# 概要

ゲーミングPC、ゲーミングマウス、ゲーミングキーボード、ゲーミングチェアーなど、色々ありますが、なぜか光っています。

なので、WEB画面も光らせてみようと、`gaming-css`というプラグイン作成しnpmに公開しました。

# セットアップ方法

下記のコマンドでインストールできます。

```bash
$ npm install gaming-css
```

詳細な使い方についてはREADMEを確認して頂ければと思います。

https://github.com/ishi720/gaming-css

# CSSを適用

## Qiitaのプロフィール画面を装飾しました！

### Before

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473097/c2a7dca2-6b89-7836-ea05-22dd00c3d1d0.png)

### After

![Animation4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473097/fd6efbee-2e1d-de3c-ae5b-27d444d71976.gif)

とっても綺麗になりましたね！（Qiita運営さん！ゲーミングテーマはいかがでしょうか？）

ちなみに、CSSを適用するのに１時間くらいかかりました。


# 仕組み

仕組みは、簡単です。下記のように、線・文字・背景・画像などに対してアニメーションのスタイルを用意して適用しているだけです。

```css
/*背景色*/
.gaming-background-color {
  animation: gaming-background-color 5s linear infinite
}
@keyframes gaming-background-color {
  0% { background-color: Magenta; }
  33% { background-color: yellow; }
  66% { background-color: Cyan; }
  100% { background-color: Magenta; }
}
```

```css
/*画像の色*/
.gaming-filter {
  animation: gaming-filter 5s linear infinite;
}
@keyframes gaming-filter {
  0% { filter: hue-rotate(0deg); }
  33% { filter: hue-rotate(120deg); }
  66% { filter: hue-rotate(240deg); }
  100% { filter: hue-rotate(360deg); }
}
```

# おまけ

npmにパッケージ公開する時のメモです。

```bash
# 認証
$ npm adduser

# 自分が誰かを確認
$ npm whoami

# 登録
$ npm publish

# 削除
$ npm unpublish {パッケージ名}@{バージョン} --force
```


# おわりに

今回は、自作したnpmのパッケージの`gaming-css`の紹介をしました。

皆さんも、WEB画面を光らせてみてはどうでしょうか。

ここまで、読んでいただきありがとうございました。
tight-binding

$$ \left(\begin{array}{ccccc}
V_1 & -t_{12} & -t_{13} & -t_{14} & -t_{15} \\\ 
-t_{21} & V_2 & -t_{23} & -t_{24} & -t_{25} \\\ 
-t_{31} & -t_{32} & V_3 & -t_{34} & -t_{35} \\\ 
-t_{41} & -t_{42} & -t_{43} & V_4  & -t_{45} \\\ 
-t_{51} & -t_{52} & -t_{53} & -t_{54} & V_5   \\\
\end{array}\right ) $$
絵文字トラブル解消！Coreserver×Wordpressで楽しく絵文字入力🎉

自分は、CoreserverでWordpressを運用しています。

ある日、絵文字を使おうとするとセーブできないトラブルに悩まされました。解決法はシンプルで、Wordpressのデータベースの一部をアップグレードするだけです。詳しくは以下。

# 解決策
`utf8mb3`から `utf8mb4`へアップグレード 👌

結論から言うと、Wordpress関連のデータベースの文字コードをutf8mb3からutf8mb4に変更すれば、絵文字の利用ができるようになります。手順は簡単ですが、注意点がいくつかありますので、確認を怠らないようにしましょう

# 参考記事
対処法は、以下のリンク先の記事を参考にしてみてください。以下の記事を読む上で、ただし、注意が必要です。

文章で書いてある部分を読み逃さないように！特に、`チェックボックスにチェックをつける操作`については、忘れているとなんの解決にもならないのでお気をつけて。

https://mb923.net/2022/06/13/【メモ】coreserver-v1-wordpressで絵文字（特殊文字）使用する/

これで絵文字トラブルから解放！！Wordpressで楽しく表現しよう！！ 🚀
ILI9341で遊ぶ(洗濯ばさみの表示


目的
カラー液晶のテスト


![o_cop791.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/0487c15b-0de8-2e9c-d49e-c5db0722b988.jpeg)



https://javl.github.io/image2cpp/



```c++



//ili9341_sentakubasami1_071

//インクルド
#include <SPI.h>
#include "sentakubasami2.h"

//定義
//GPIO
//GPIOの設定1　開始
//GPIO
#define TFT_RST   A1
#define TFT_RS    3
#define TFT_CS    4
#define GPIO_RESET(s)  digitalWrite(TFT_RST,s)
#define GPIO_RS(s)     digitalWrite(TFT_RS,s)
#define GPIO_CS(s)     digitalWrite(TFT_CS,s)


void GPIO_8BIT(int s)
{
  SPI.transfer(s);
} //GPIO_D0_D7


//ライト

void LCD_Write_CMD(int a)
{
  GPIO_CS(0);//CS=0; 12
  GPIO_RS(0); //A0=0; 9
  GPIO_8BIT(a);//P1=a; data SPI SPI
  GPIO_CS(1);//CS=1; 12
} //LCD_Write_CMD

void LCD_Write_Data(int a)
{
  GPIO_CS(0);//CS=0; 12
  GPIO_RS(1); //A0=1; 9
  GPIO_8BIT(a);//P1=a; data SPI SPI
  GPIO_CS(1);//CS=1; 12
} //LCD_Write_Data


//画面の書き込み
void P_display(void)
{
  //画面の書き込み開始
  LCD_Write_CMD(0x2C); //memory write
  //delay(1);

  unsigned int jjk=0;
  unsigned char vg=0;
  unsigned char hp[8]={0x80,0x40,0x20,0x10,  0x08,0x04,0x02,0x01};
  for (int i = 0; i < 320; i++) {
    for (int j = 0; j < (240/8); j++) {

      //vg=pgm_read_byte_near(databytes + jjk);
      vg=databytes[jjk];
      for(int k=0;k < 8;k++){

        if ( ( vg & hp[k]) == 0 ) {
        //if ( 0 == 1 ){
          LCD_Write_Data(0x00);
          LCD_Write_Data(0x00);
          LCD_Write_Data(0x00);
        } else { //        12345678
          LCD_Write_Data(0b11111111);
          LCD_Write_Data(0b11111111);
          LCD_Write_Data(0b11111111);
        }//enf if

      }//k
      jjk++;

    } //j
  }//i

} //P_display


//液晶の初期化処理
void TXDT144TF_ST7735S_Init(void)
{

  GPIO_RESET(1);//LCD_RESET=1;
  delay(1); //Delay 1ms

  GPIO_RESET(0);//LCD_RESET=0;
  delay(1); //Delay 1ms

  GPIO_RESET(1);//LCD_RESET=1;
  delay(120); //Delay 120ms

  LCD_Write_CMD(0x01);//SOFTWARE RESET
  delay(50);

  LCD_Write_CMD(0x01);//SOFTWARE RESET
  delay(50);

  LCD_Write_CMD(0x11);//SLEEP OUT
  delay(200);

  LCD_Write_CMD(0x29);//display on
  delay(100);

} //TXDT144TF_ST7735S_Init


//初期化
void setup() {

  //ポートのモード設定　アウトプットモード
  pinMode(TFT_CS, OUTPUT);
  pinMode(TFT_RST, OUTPUT);
  pinMode(TFT_RS, OUTPUT);

  //ポートの初期化
  GPIO_CS(1);//CS=1
  GPIO_RESET(1);//RESET=1
  GPIO_RS(0);//RS=0


  // SPIの初期化
  SPI.beginTransaction( SPISettings( 4000000, MSBFIRST, SPI_MODE0) );
  //SPI.beginTransaction( SPISettings( 2000000, MSBFIRST, SPI_MODE0) );
  //SPI.beginTransaction( SPISettings( 1000000, MSBFIRST, SPI_MODE0) );
  SPI.begin(); // 11 12 13


  delay(500); //0.5秒待つ

  //液晶の初期化処理
  TXDT144TF_ST7735S_Init();

  P_display();

} //setup


//メインループ
void loop() {
} //loop



```

sentakubasami240x320.h

https://qiita.com/caa45040/items/a4199dd52cb4e84ae226
【CSS Tips】gridを使ってwidth: 100%だけど中のコンテンツ幅を制限するUIを作る

## これは何

Webで、UIを実装するときに、「外側は常に幅いっぱいに広げたいけど中のコンテンツ幅は〇〇px以下にしたい」ということがあります。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577501/7ab82fe3-bce2-02a4-0803-32341b27da86.png)

今まで自分はこうしたUIを余分に一つ内側に`div`を作り、その`div`に`max-width`を指定して実装していました。

こんな感じのコードです。

```html
<section class="section_list">
  <section class="section">
    <div class="section_inner">...</div>
  </section>
  <section class="section">
    <div class="section_inner">...</div>
  </section>
  <section class="section">
    <div class="section_inner">...</div>
  </section>
</section>
```

```css
.section{
  width: 100%;
}

.section_inner {
  width: 100%;
  max-width: 320px;
  margin: auto;
}
```

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="XWOepNJ" data-user="kabechiyo" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/kabechiyo/pen/XWOepNJ">
  ヘッダー</a> by kabechiyo_shunkaaizawa (<a href="https://codepen.io/kabechiyo">@kabechiyo</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

冗長すぎるというほどでは無いですが、なるべく意味のないDOMは減らしたい派なので、`grid`を使ってこのinnerのdivを減らしたい..と思い、`grid`を使えばいい感じになるのでは？と試してみました。

### `grid`を使って、innerの`div`を減らす

こんな感じのコードです。
`grid-template-columns: minmax(auto, 280px)`を指定することで、コンテンツの最大幅を指定してます。

```html
<section class="section_list">
  <section class="section">...</section>
  <section class="section">...</section>
  <section class="section">...</section>
</section>
```

```css
.section{
  display: grid;
  grid-template-columns: minmax(auto, 280px);
  justify-content: center;
}
```

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="qBgPRxr" data-user="kabechiyo" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/kabechiyo/pen/qBgPRxr">
  ヘッダー＿grid</a> by kabechiyo_shunkaaizawa (<a href="https://codepen.io/kabechiyo">@kabechiyo</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

divもスタイル指定も減らせてスッキリしました！
Laravelの`storage:link`のシンボリックリンクがうまくできなかった話


ご覧いただき，ありがとうございます。
Laravelの`storage:link`を張ったのに画像が表示されない問題でつまずいたので，その解決方法を共有します。
いつも通り，シンボリックリンクを張ったのですが，画像が表示されませんでした。
答えは単純です。
`storage`ディレクトリの権限が`777`になっていなかったのです。
ということで，以下のコマンドを実行して権限を変更しましょう。

```bash
chmod -R 777 storage/app/public
```

権限設定は難しいですね。
AWS S3 パブリックアクセス設定について検証してみた

# はじめに
AWS S3のパブリックアクセス設定をオンにした場合の挙動が知りたいため、個人アカウントにて
検証したため記事にしました。


# 検証手順

公開設定しているS3バケット
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/23aa3c0e-07e7-22b4-693f-27bdb98275c5.png)


サービス >> S3 >> このアカウントのブロックパブリックアクセス設定をクリックする。

パブリックアクセスをすべてブロックにチェックを入れて[変更の保存]をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/47b3b146-c2e1-594f-5be8-2b08a312fb9e.png)


公開設定されていたS3バケットが認証ユーザーのみアクセスに変更されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/d42af2d7-1069-4599-114f-21db5c31ead5.png)


## 試しにバケットを公開設定しようとすると
バケット自体のパブリックアクセスブロックをオフにする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/50973e32-9e08-bc13-9c25-609b30fe1b89.png)

公開設定するバケットポリシーを設定して「変更の保存」したところ、エラー画面になりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/1d7b6ad2-6b01-b97b-be56-3ad04f43f0c1.png)

# まとめ
S3の「このアカウントのブロックパブリックアクセス設定」を有効にすると、アカウントにある公開設定のバケットが「このアカウントの認証ユーザーのみ」に変更されることが分かりました。
またバケットを公開設定しようとするとエラー画面が出て設定出来ないことが分かりました。
【AWS】IAMを用いたセキュリティ設定

# 【AWS】IAMを用いたセキュリティ設定

Amazon Web Services（AWS）は、クラウドコンピューティングサービスを提供するプラットフォームです。このプラットフォーム上で、セキュリティとアクセス管理は非常に重要な要素です。AWSのIAM（Identity and Access Management）サービスを通じて、ユーザーの認証と権限付与を効果的に行うことができます。ここでは、AWSとIAMの概要から始め、IAMユーザー、IAMポリシー、IAMユーザーとルートユーザーの違い、IAMグループ、そしてIAMロールについて初心者にも分かりやすく解説します。

## AWSの概要

### クラウドコンピューティングサービス

AWSは、Amazon.comが提供する世界最大級のクラウドコンピューティングサービスです。様々なオンラインサービスやアプリケーションのバックエンドとして機能し、ストレージ、コンピューティング、データベース、ネットワーキングなど多岐にわたるサービスを提供しています。

## IAMの概要

### アイデンティティとアクセス管理

IAMは、AWSリソースへのアクセスを安全に管理するためのサービスです。IAMを使用すると、ユーザー、グループ、ロール、ポリシーを定義して、誰がどのAWSリソースにアクセスできるかを細かく制御できます。

## IAMユーザー

### 個々のアイデンティティ

IAMユーザーは、AWSリソースへのアクセスを必要とする個人やサービスに割り当てられるアイデンティティです。それぞれのユーザーには一意の認証情報があり、必要な権限を付与することができます。

## IAMユーザーとルートユーザーの違い

### 最高権限者と通常ユーザー

ルートユーザーは、AWSアカウントを作成した際に自動的に作成される最高権限者です。これに対して、IAMユーザーはアカウント内で作成される通常のユーザーで、必要な権限のみを付与することができます。

## IAMグループ

### ユーザーの集合

IAMグループは、複数のIAMユーザーを一つのグループにまとめるための機能です。共通のポリシーをグループに適用することで、ユーザーごとに個別にポリシーを設定する手間を省けます。

## IAMユーザーとIAMロールの違い

### 一時的な権限付与

IAMロールは、一時的な権限を持つアイデンティティであり、特定のシナリオやAWSサービスで使用されます。ロールは、一時的に他のユーザーやサービスに特定の権限を付与するために使われ、使い終わったらその権限を削除できます。
AWSの他サービスへ付与されることが多いです。

## IAMポリシー

### アクセス権限の規則

IAMポリシーは、JSON形式で書かれたドキュメントで、特定のアクションとリソースに対するアクセス許可または拒否の規則を定義します。これらのポリシーをIAMユーザー、グループ、またはロールに割り当てることで、セキュリティを強化しながら柔軟なアクセス管理が行えます。

## まとめ

AWSのIAMサービスは、クラウドリソースのセキュリティとアクセス管理において極めて重要な役割を果たします。IAMユーザー、ポリシー、グループ、ロールを適切に設定し管理することで、AWSリソースへの安全なアクセスを確保しつつ、必要な柔軟性を保持することができます。IAMを効果的に使用することで、企業のクラウドセキュリティを強化し、AWS環境をより効率的に管理できるようになります。
LLMを読み込む際にメモリを節約する対策「量子化」について

サイズが大きなLLM（70b、130b）を使いたい時に、大量なメモリが必要です。70bの場合は少なくとも80GB以上のメモリが必要です。（130bの場合は150GB）
例えば、A100（40GB）で計算しても、2,3台以上組み合わせて使う必要があります。
そこまでのリソースがない時には量子化という手法をよく使われてます。
今日は量子化について簡単に紹介したいと思います。

## ①量子化前の前提作業：シャーディング（Sharding）
ShardingはほとんどのLLMがやっていることです。
Hugging Faceでモデルをダウンロードすると、モデルファイル（.bin）が一つのファイルではなく、少なくとも十数個のファイルで構成されていることは気づけると思います。
一つのファイルをわざと数十個に分ける理由は、異なるstepでモデルの重みを分けて、メモリを節約できるからです。Shardingはacceleratorライブラリを使ってやります。

## ②モデルを読み込む際に量子化
LLMは、非常に多くの重みとニューロンで構成されています。
これらの重みやニューロンなどはすべて32ビットの浮動小数点数（float32）です。
この浮動小数点数のビット数を減らすと(32bit→4bit)、当然モデルのサイズが小さくなり、メモリ使用量も減少します。もちろん、ある程度の精度も落ちます。 なので、単純に4ビットに変換するのではなく、精度をできるだけ落とさないように4ビットに変換する必要があります。
それで、NF4という少し特別な4ビットの形式が提出されました。

NF4について私もよくわからないですが、簡単的に言うと、モデルの重みを平均的に分割して、4ビットでも32ビットの重みを表現できるようにする仕組みみたいです。
あとモデルが推理する時には、自動的に4ビットから32ビットへ戻る機能もあります。そうすると、精度もそこまで落ちないようにできます。量子化はbitsandbytesライブラリを使ってやります。

## ③量子化されたモデルを直接使う
毎回モデルを読み込む際に量子化するとかなり時間かかりますので、量子化されたモデルをそのままダウンロードして使った方がより便利です。
量子化されたモデルには主にGPTQ、GGUF、AWQの3種類があります。

1.GPTQはGPU向けに特化されたアルゴリズムです。

2.GGUFはCPU向けです。（処理速度は結構遅いですが、GPUがないか、または性能が低いGPUの場合は活用できます。）

3.AWQは先月新しく公開された、GPTQよりも高性能な量子化アルゴリズムです。
特徴としては、量子化する時に重みの重要性を判断する機能があって、重要ではないと判断された重みはスキップ（削除）して、重要な重みだけ量子化することができました。でも実際使ってみた時にはGPTQとあまり違いは感じてなかったです。


AWQ: 

https://github.com/mit-han-lab/llm-awq
[Roblox] StarterPlayerScripts から StarterGui を制御する方法 🚀

Roblox Studioを使っているエンジニアの皆さん、StarterPlayerScripts内のlocalScriptからStarterGuiの挙動を制御したいことはありませんか？そんな時のためのテクニックを紹介します！

（呼び出す側のStarterPlayerScripts > localScript)
```lua
local player = game.Players.LocalPlayer
local GuiFrame = player.PlayerGui:WaitForChild("ScreenGui"):WaitForChild("ScreenGui_Frame")

-- 行いたい処理
GuiFrame.Visible = false
```

注意点は2つ。

- GuiScreenは`StarterPlayerScripts`からではなく、
`player.PlayerGui`から呼び出すこと。
- 初期化時に呼び出したい場合は、`:WaitForChild()`を利用して呼び出しましょう。

これであなたもStarterPlayerScriptsとStarterGuiを巧みに操れるようになります！🎮✨

おしまい
next.jsとsupabaseでRow Level Securityを使用して権限による抽出をおこなってみた

あなたが提供した情報に基づいて、SupabaseでのRow-Level Security (RLS) ポリシーを設定するプロセスを検討しましょう。まず、`public.posts` テーブルの作成に関しては問題ありません。次に、提案されたRLSポリシーに関して検討します。

参考資料
https://qiita.com/kaho_eng/items/6f9ac01d77ab198881f4

詳しい！
https://www.docswell.com/s/hmatsu47/5RMEWZ-2022-05-30-232653#p31

https://supabase.com/docs/guides/auth/row-level-security#using-functions

### ポリシーの設定

1. **管理者アクセス**:
   このポリシーは、「管理者」（`profiles.introduce` が `admin` の場合）であれば、全ての投稿を取得できるように設定します。

   ```sql
   create policy "管理者アクセス" on public.posts for select using (
     (SELECT profiles.introduce
      FROM profiles
      WHERE profiles.id = auth.uid()) = 'admin'
   );
   ```

   このポリシーは、`profiles` テーブルの `introduce` カラムをチェックして、その値が `admin` であるかどうかを確認します。その条件が真の場合、そのユーザーは `posts` テーブルの全レコードにアクセスできます。

2. **ユーザー別アクセス**:
   こちらのポリシーは、ユーザーが自分の投稿のみにアクセスできるように設定します。

   ```sql
   create policy "ユーザー別アクセス" on public.posts for select using (
     auth.uid() = user_id
   );
   ```

   このポリシーでは、`auth.uid()`（ログインしたユーザーのID）が `posts` テーブルの `user_id` と一致する場合にのみ、その行へのアクセスを許可します。

### 注意点

- **ポリシーの適用順序**: 複数のポリシーが適用される場合、いずれかのポリシーが `true` を返せば、その行へのアクセスが許可されます。そのため、セキュリティポリシーを慎重に設計する必要があります。

- **テストと検証**: ポリシーを実装した後は、異なるユーザーのロールでのアクセスが期待通りに機能するかをテストすることが重要です。

- **プロファイルテーブルとの関連付け**: この設定は `profiles` テーブルが存在し、適切に設定されていることを前提としています。`profiles` テーブルにはユーザーIDと `introduce` カラムが必要です。

以上のポリシー設定は、あなたが記述した要件に基づいていますが、実際のアプリケーションのセキュリティニーズに応じて調整する必要があるかもしれません。常にセキュリティのベストプラクティスに従い、慎重にポリシーを設計してください。
Pythonで「文字列の先頭および末尾から指定した文字をすべて取り除く(strip)」の動作を確認してみた

# 概要

Pythonで「文字列の先頭および末尾から指定した文字をすべて取り除く(strip)」の動作を確認してみました。以下のページを参考にしました。

https://www.javadrive.jp/python/string/index19.html

# 実装

以下のファイルを作成しました。
```sample.py
print("  Hello ".strip())
print(" My First Diary ".strip())
print("")
print("...Hello...".strip("."))
print("www.example.com".strip("wcmo."))
print("")
print("...Hello...".rstrip("."))
print("")
print("...Hello...".lstrip("."))
```

以下のコマンドを実行しました。
```
$ python3 sample.py 
Hello
My First Diary

Hello
example

...Hello

Hello...
```

# まとめ

何かの役に立てばと。
【Day 4】Web環境構築 - Next.jsの起動まで

## はじめに

![スライド5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/5cfcbefd-4940-a2f3-0993-236f90fe78fb.png)

---

**2023年アドベントカレンダー4日目**です。

https://qiita.com/advent-calendar/2023/life-sync-app

昨日は画面デザインを作るストーリーを消費しました。

今回は「開発者はWebの開発を進めることができる」を消費していこうと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/13e79272-8479-39f1-e857-a04f2bfcc4b1.png)


## Next.jsの環境構築

### NodeJSのインストール

記事を書いている現在のLTSを調べたところ、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/7f01f141-117e-4df1-b476-95bde82aef75.png)

という状態だったので、`20.9.0`をインストールすることにします。

:::note warn
asdfでのインストール手順を書いていきますが、
インストール方法はおまかせします。
:::

#### asdfのインストール

```bash
git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.13.1
```

:::note warn
gitがinstallされていない場合はインストールしてください。
:::

https://git-scm.com/book/ja/v2/%E4%BD%BF%E3%81%84%E5%A7%8B%E3%82%81%E3%82%8B-Git%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB

#### nodejsのインストール

1. asdf pluginの追加

    ```bash
    asdf plugin add nodejs https://github.com/asdf-vm/asdf-nodejs.git
    ```

2. asdfでnodejsのインストール

    ```bash
    asdf install nodejs 20.9.0
    ```
3. Nodejs 20.9.0のセット

    ```bash
    asdf global nodejs 20.9.0
    ```

4. Nodejsのバージョン確認
    
    ```bash
    node -v
    v20.0.9
    ```
    :ok: Nodejsがインストールできました

### CreateNextApp

[day 1]()で作成したディレクトリ構成にしていきます。

```bash
npx create-next-app web
✔ Would you like to use TypeScript? …       Yes
✔ Would you like to use ESLint? …           Yes
✔ Would you like to use Tailwind CSS? …     Yes
✔ Would you like to use `src/` directory? … Yes
✔ Would you like to use App Router? (recommended) … Yes
✔ Would you like to customize the default import alias (@/*)? … No
```

エイリアスをカスタマイズするかどうかの設定のみ`No`にして、他は`Yes`にしました。

```
├── web
│   ├── README.md
│   ├── app/
│   ├── next-env.d.ts
│   ├── next.config.js
│   ├── node_modules/
│   ├── package-lock.json
│   ├── package.json
│   ├── postcss.config.js
│   ├── public/
│   ├── tailwind.config.ts
│   └── tsconfig.json
```

こうなったはずです。

### 起動

```bash
cd web/
npm run dev
```
[localhost:3000](http://localhost:3000)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985550/39184611-b322-0c8c-b13c-d394a2a489ff.png)

起動しました :ok:

次はE2Eテストが回せるようにしていきます。