OmniAICreator/Qiita-1.07M huggingface dataset:
DockerComposeを使用してMySQL環境の作成

docker-composeを使用して簡単にMySQL環境を作成します

## 実装

`docker-compose.yml`ファイルにmysqlのコンテナを作るよう記述をします。

```yaml
version: '3'

services:
  mysql:
    image: mysql:8
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: "root"
      MYSQL_DATABASE: "db_name"
    volumes:
      - ./mysql/create_tables.sql:/docker-entrypoint-initdb.d/create_tables.sql
```

## 補足

イメージはMySQLのバージョン8を使用してます。
ポートは3306を使用し、環境はルートユーザーのパスワードとデータベースだけ準備します

> MYSQL_ROOT_PASSWORD
This variable is mandatory and specifies the password that will be set for the MySQL root superuser account. In the above example, it was set to my-secret-pw.
>
> MYSQL_DATABASE
This variable is optional and allows you to specify the name of a database to be created on image startup. If a user/password was supplied (see below) then that user will be granted superuser access (corresponding to GRANT ALL) to this database.

和訳

> MYSQL_ROOT_PASSWORD
この変数は必須で、MySQL root スーパーユーザーアカウントに設定されるパスワードを指定する。上記の例では、my-secret-pw に設定されている。
> 
> MYSQL_DATABASE
この変数はオプションで、イメージ起動時に作成されるデータベースの名前を指定できます。ユーザー／パスワードが与えられた場合（以下を参照）、そのユーザーにはこのデータベースへのスーパーユーザー権限（GRANT ALLに対応）が与えられます。

https://hub.docker.com/_/mysql

volumesに指定しているファイルはMySQL起動時に自動で実行されるダンプファイルを指定してます。
今回はuserテーブルを作成してます

```sql
USE db_name;

CREATE TABLE `user` (
    `id` BIGINT NOT NULL AUTO_INCREMENT,
    `email` VARCHAR(255) NOT NULL,
    `password` VARCHAR(255) NOT NULL,
    `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`)
);
```

## 参考

https://zenn.dev/re24_1986/articles/153cdc5db96dc0

https://zenn.dev/mstn_/articles/ad5d7c7ad7e2d6

https://qiita.com/NagaokaKenichi/items/ae037963b33a85df33f5
Pythonで数値・数値文字列・バイナリ変換

# はじめに
　Pythonの数値処理関係で下記の操作をよくすることがあるのでまとめてみた。
+ 数値文字列⇔数値変換
+ 2,10,16進数変換
+ 数値⇔バイナリ変換
+ 数値テキスト(ASCII)ファイル⇔バイナリファイル変換
+ HEX文字列エンディアン変換



## 数値→文字列
　```format()```を使用する。進数と桁数を指定して数値文字列へ変換。例の変換前の数値0x1234ABCDは16進数に統一しているが、16進数でなくても変換できる。
```Python
#数値→16進数8桁
num_string = '0x{:08X}'.format(0x1234ABCD)
print(type(num_string),num_string)

#数値→10進数10桁
num_string = '{:010d}'.format(0x1234ABCD)
print(type(num_string),num_string)

#数値→2進数32桁
num_string = '{:032b}b'.format(0x1234ABCD)
print(type(num_string),num_string)
```
出力結果
```
<class 'str'> 0x1234ABCD
<class 'str'> 0305441741
<class 'str'> 00010010001101001010101111001101b
```



## 文字列→数値
　```int()```を使用する。文字列の進数を指定して変換する。
```Python
#16進数文字列→数値
num = int('0x1234ABCD',16)
print(type(num),num)

#10進数文字列→数値
num = int('305441741',10)
print(type(num),num)

#2進数文字列→数値
num = int('00010010001101001010101111001101',2)
print(type(num),num)
```
出力結果
```
<class 'int'> 305441741
<class 'int'> 305441741
<class 'int'> 305441741
```



## 数値→バイナリ
　```to_bytes```を使用する。数値をbytearray型に変換する。桁数と、エンディアンを指定する。用途としては、数値をバイナリデータとしてファイルに保存したり、外部機器とシリアル通信のデータ送信をするときに扱う。
```Python
#数値→バイナリ4byteビックエンディアン
num = 0xABCDEF01
binary=num.to_bytes(4,'big')
print(type(binary),binary)

#数値→バイナリ4byteリトルエンディアン
num = 0xABCDEF01
binary=num.to_bytes(4,'little')
print(type(binary),binary)
```
出力結果
```
<class 'bytes'> b'\xab\xcd\xef\x01'
<class 'bytes'> b'\x01\xef\xcd\xab'
```



## バイナリ→数値文字列
　```from_bytes()```と```format()```を使用する。from_bytes()でバイナリ→数値変換された後、format()で数値を数値文字列に変換する。数値のままで処理する場合は、format()は不要。用途としては、バイナリファイルのデータを処理したり、外部機器とシリアル通信の受信データを処理するときに扱う。
```Python
#バイナリ4byteビックエンディアン→数値文字列
binary = b'\xab\xcd\xef\x01'
num_string='0x{:08X}'.format(num.from_bytes(binary,'big'))
print(type(num),num)
print(type(num_string),num_string)

#バイナリ4byteリトルエンディアン→数値文字列
binary = b'\x01\xef\xcd\xab'
num_string='0x{:08X}'.format(num.from_bytes(binary,'little'))
print(type(num),num)
print(type(num_string),num_string)
```
出力結果
```
<class 'int'> 2882400001　# 16進数の0xABCDEF01
<class 'str'> 0xABCDEF01
<class 'int'> 2882400001　# 16進数の0xABCDEF01
<class 'str'> 0xABCDEF01
```



## HEX文字列→バイナリ
　```bytes.fromhex()```を使用する。用途は、数値テキストファイルのデータ列をバイナリファイルへ変換するときなど。
```Python
#HEX文字列→バイナリ変換
hex_string='ABCDEF01ABCDEF01ABCDEF01'
binary=bytes.fromhex(hex_string)
print(type(binary),binary)
```
出力結果
```
<class 'bytes'> b'\xab\xcd\xef\x01\xab\xcd\xef\x01\xab\xcd\xef\x01'
```



## バイナリ→HEX文字列
　```hex()```を使用する。用途は、バイナリファイルの数値データ列を数値テキストファイルへ変換するときなど。
```Python
#バイナリ→HEX文字列変換
binary=b'\xab\xcd\xef\x01\xab\xcd\xef\x01\xab\xcd\xef\x01'
hex_string=binary.hex()
print(type(hex_string),hex_string)
```
出力結果
```
<class 'str'> abcdef01abcdef01abcdef01
```

## HEX文字列のエンディアン変換
 HEX文字列をBig/Little変換する。```re.sub()```で正規表現変換。

 ```Python
 import re
# HEX文字列 16bit
hex_string='1234'
hex_string=re.sub(r'(..)(..)',r'\2\1',hex_string)
print(type(hex_string),hex_string)

# HEX文字列 32bit
hex_string='ABCD1234'
hex_string=re.sub(r'(..)(..)(..)(..)',r'\4\3\2\1',hex_string)
print(type(hex_string),hex_string)
 ```
 出力結果
 ```
 <class 'str'> 3412
<class 'str'> 3412CDAB
 ```

エンディアンについてもう少し。

 https://qiita.com/tapitapi/items/b72ea9d3c18bbeb85bc8




以上
【Swift】classとstructの違いを理解していなかったので整理してみた

# はじめに
いままでclassとstructの違いをしっかり調べたことがなかったのでまとめてみました

# 違い1(初期化)
### class
`class`はイニシャライザが必須です。
ないと怒られます
```swift
class PersonClass {
    var name: String
    
    init(name: String) {
        self.name = name
    }
}
```
![スクリーンショット 2023-09-17 19.58.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/6420c90a-2d00-8244-ddf0-10759c881dc5.png)

### struct
`struct`は自動初期化されるらしく、イニシャライザはなくても怒られません。
もちろんあっても良いです
```swift
struct PersonStruct {
    var name: String
}
```

# 違い2(値型と参照型)
### class
```swift
class PersonClass {
    var name: String
    
    init(name: String) {
        self.name = name
    }
}

let personClass1 = PersonClass(name: "めぐみ")
let personClass2 = personClass1
personClass2.name = "たろう" // `personClass2`の`name`を「たろう」に変える

// そうすると、、、
print(personClass1.name) // `personClass1`の`name`も「たろう」に変わる
```

### struct
```swift
struct PersonStruct {
    var name: String
}

var personStruct1 = PersonStruct(name: "めぐみ")
var personStruct2 = personStruct1
personStruct2.name = "たろう" // `personClass2`の`name`を「たろう」に変える

// そうしても、、、
print(personStruct1.name) // `personClass1`の`name`は「めぐみ」のまま
```

# 違い3(継承)
### class
```swift
class PersonClass {
    var name: String
    
    init(name: String) {
        self.name = name
    }
    
    func introduction() {
        print("私は\(name)です")
    }
}

class StudentClass: PersonClass {
    var id: String
    
    init(name: String, id: String) {
        self.id = id
        super.init(name: name) // ここは`PersonClass`のイニシャライザ
    }
    
    override func introduction() {
        print("私は\(name)です。生徒番号は\(id)です。")
    }
}

let student = StudentClass(name: "たけし", id: "123456")
student.introduction() // 私はたけしです。生徒番号は123456です。
```

### struct
できない

# 違い3(可変性)
### class
```swift
class PersonClass {
    var name: String
    
    init(name: String) {
        self.name = name
    }
    
    func rename(newName: String) {
        self.name = newName
    }
}

var personClass = PersonClass(name: "めぐみ")
personClass.rename(newName: "たけし")
print(personClass.name) // たけし
```

### struct
自身のプロパティを変更したいときには、メソッドに`mutating`が必須
```swift
struct PersonStruct {
    var name: String
    
    mutating func rename(newName: String) {
        self.name = newName
    }
}

var personStruct = PersonStruct(name: "めぐみ")
personStruct.rename(newName: "たけし")
print(personStruct.name) // たけし
```

`mutating`ないと怒られる
![スクリーンショット 2023-09-17 20.22.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/982325a1-55a8-a6f6-959a-6768bed5dd8e.png)


# おわり
ここら辺複雑でむずいです。
理解していないと予期せぬバグを生み出しそうなのでちゃんと勉強します。。。

足りないことや間違ってることがあればコメントで教えてくれると助かります
E資格の振り返り

こんにちは、すきにーです。

E資格2023#2 に合格しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/748e248b-b219-2fd3-7123-022d52ad2652.png)
E資格の振り返りを書きたいと思います。

# E資格とは
E資格とは、日本ディープラーニング協会（JDLA）が主催しているAI系の資格です。
ディープラーニングの理論を理解し、適切な手法を選択して実装する能力や知識を有しているかを認定する試験になります。

E資格の受験資格を得るために、JDLAの認定講座を修了する必要があります。

# 認定講座
認定講座はラビットチャレンジを受講しました。

他の認定講座が10万円以上する中、ラビットチャレンジは3~8万円と比較的安く受けられるため、ラビットチャレンジを選びました。

## ラビットチャレンジの内容
① スタートテスト
② Day1 - 応用数学
③ Day2 - 機械学習
④ Day3 - 深層学習1
⑤ Day4 - 深層学習2 ＆ 認定試験
という流れで進みます。

各章で試験を受け、合格点が取れないと次へ進めない仕様でした。
テストは制限時間がないため、調べながら受けることができますが、
それでもDay3や認定試験はかなり苦戦しました。

認定試験をクリアすると、E模擬試験や公式例題、直前対策問題が公開されます。
特に公式例題は本番と同レベルの問題になるので、繰り返し解くことで実力が付きました。

# 勉強期間・参考テキスト・費用について
## 勉強期間
2022年11月　G検定合格＆ラビットチャレンジ登録
途中4か月間休止
2023年6月　 ラビットチャレンジ修了、認定証獲得
2023年8月　 E資格受験

## 参考テキスト
### 徹底攻略ディープラーニングE資格エンジニア問題集 - インプレス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/9ece0fe8-2049-3b4d-b4dd-000b4d1ed665.png)

通称「黒本」です。旧課程の範囲はこれでカバーできます。
新課程範囲はカバーしていないので、認定講座の資料・問題をやるか、自分で勉強する必要があります。


### ゼロから作るDeep Learning1 - オライリージャパン
ゼロから作るDeep Learning2 自然言語処理編
ゼロから作るDeep Learning4 強化学習編

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116479/c296ea8d-024f-9f73-7500-53ae3368375a.png)


通称「赤本」です。深層学習の基礎部分をスクラッチで解説されています。
3はフレームワーク編なので必要ないですが、勉強として読んでみてもいいと思います。


### Qiitaの記事
また、Qiitaの記事になりますが、この方のＥ資格対策の記事はおススメです。
https://qiita.com/fuki_takahashi/items/af3de95b05d7a4036d7e
現在の試験範囲が一通り網羅されており、内容も濃いです。

## 合格までにかかった費用（税込み）
ラビットチャレンジ
・入会金　　　22,000円
・月謝　　　　39,600円（3,300円/月 × 12か月分）
E資格受験料　 33,000円

合計　94,600円

# 試験本番
試験内容は守秘義務で公開できないので、概要だけ話します。
難易度はかなり高く感じました。
初見で黒本の問題レベルを解いているような感覚でした。

# 感想
試験直後は手応えがなく落ちたと思いました。
結果として合格できましたが、自分が想定しているよりも難易度が高かったです。
数式やプログラムを暗記しているだけでなく、内容までしっかり理解している必要がありましたね。
また、深層学習がAIのメインなので、深層学習に一番力を入れておくべきと感じました。

進歩が激しい分野で、シラバスも年々変わっていくため、日々新しい情報を仕入れていくことも重要だと思いました。
goでパスワードを平文ではなくハッシュ化して保存し、ログインまで行う

goでパスワードのハッシュ化と、
ハッシュ化したパスワードを使用してログイン機能作ってみたかったので、
テスト的ではありますが作ってみました。

## 実装

ハッシュ化と称号に関しては`bcrypt`を使用します。

```bash
$ go get golang.org/x/crypto/bcrypt
```

https://pkg.go.dev/golang.org/x/crypto/bcrypt

リクエストで文字列のパスワードを受け取ってハッシュ化する関数は以下のような形。
`bycrypt.GenerateFromPassword()`で文字列をハッシュ化します

```go
func encryptPassword(password string) (string, error) {
	// パスワードの文字列をハッシュ化する
	hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return "", err
	}
	return string(hash), nil
}
```

> GenerateFromPassword returns the bcrypt hash of the password at the given cost. If the cost given is less than MinCost, the cost will be set to DefaultCost, instead. Use CompareHashAndPassword, as defined in this package, to compare the returned hashed password with its cleartext version. GenerateFromPassword does not accept passwords longer than 72 bytes, which is the longest password bcrypt will operate on.

和訳

> GenerateFromPassword は、与えられたコストでパスワードの bcrypt ハッシュを返します。指定されたコストが MinCost より小さい場合は、代わりに DefaultCost が設定されます。このパッケージで定義されている CompareHashAndPassword を使用して、返されたハッシュ化されたパスワードとその平文バージョンを比較します。GenerateFromPassword は、bcrypt が操作できる最長パスワードである 72 バイトより長いパスワードを受け付けません。

リクエストで受け取ったパスワードと、
ハッシュで保存されているパスワードを比較して判定する関数は以下のような形。
`bcrypt.CompareHashAndPassword()`で比較を行います。

```go
func compareHashPassword(hashedPassword, requestPassword string) error {
	// パスワードの文字列をハッシュ化して、既に登録されているハッシュ化したパスワードと比較します
	if err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(requestPassword)); err != nil {
		return err
	}
	return nil
}
```

> CompareHashAndPassword compares a bcrypt hashed password with its possible plaintext equivalent. Returns nil on success, or an error on failure.

和訳

> CompareHashAndPassword は、bcrypt でハッシュ化されたパスワードと、それに相当する可能性のある平文とを比較します。成功した場合は nil を返し、失敗した場合はエラーを返します。

## 補足

Chat GPTに聞いてみましたが、bcryptのセキュリティ性に関しては問題なさそうな感じです

![スクリーンショット 2023-09-17 19.54.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1953754/69cdce26-3c84-ba8e-72dd-902f5a159270.png)

## 参考

https://zenn.dev/ajapa/articles/5b115f53e76f3a

https://qiita.com/yoheimuta/items/57c7119dcdb46edf35c7
【エラー対応】`prisma db seed` で .env.localを読み込む方法

# 背景
* Next.jsを導入しているプロジェクトにPrismaの`seed.ts`ファイルを作成し、`prisma db seed`を実行した時に起きたエラー


```seed.ts
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()

console.log('Prisma seed');

async function main() {
  const events = await prisma.event.findMany({})
  console.log({events})
  // ...
}

main()
  .then(async () => {
    await prisma.$disconnect()
  })
  .catch(async (e) => {
    console.error(e)
    await prisma.$disconnect()
    process.exit(1)
  })
```

```package.json
{
  // ...
  "prisma": {
    "seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
  }
}
```

```.env
# ダミーデータ
DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"
```

**エラー文**
```bash
$ npx prisma db seed

Environment variables loaded from .env
Running seed command `ts-node --compiler-options {"module":"CommonJS"} prisma/seed.ts` ...
Prisma seed
PrismaClientInitializationError: 
Invalid `prisma.event.findMany()` invocation in
/Users/xxx/git/maiamea/remake-hayaoki-girls-calendar/prisma/seed.ts:12:37

   9 console.log('Prisma seed');
  10 
  11 async function main() {
→ 12   const events = await prisma.event.findMany(
User `johndoe` was denied access on the database `mydb.public`
    at vn.handleRequestError (/Users/xxx/git/maiamea/remake-hayaoki-girls-calendar/node_modules/@prisma/client/runtime/library.js:123:7003)
    at vn.handleAndLogRequestError (/Users/xxx/git/maiamea/remake-hayaoki-girls-calendar/node_modules/@prisma/client/runtime/library.js:123:6119)
    at vn.request (/Users/xxx/git/maiamea/remake-hayaoki-girls-calendar/node_modules/@prisma/client/runtime/library.js:123:5839)
    at async l (/Users/xxx/git/maiamea/remake-hayaoki-girls-calendar/node_modules/@prisma/client/runtime/library.js:128:9763) {
  clientVersion: '5.2.0',
  errorCode: undefined
}

An error occurred while running the seed command:
Error: Command failed with exit code 1: ts-node --compiler-options {"module":"CommonJS"} prisma/seed.ts
```

# `prisma db seed` 実行時に起こること（想像）
1. Prismaが`.env`を読み込む
1. `package.json`の`prisma.seed`に書いているコマンドを実行する
1. `.env`に書いてあるDATABASE_URLをもとに、DBに接続しに行く
    * Next.jsにおいては機密情報は`.env.local`に記述するのを推奨している。しかしPrismaはデフォルトだと`.env`しか読み込まない
1. `.env`に書いてある`DATABASE_URL`はダミーデータなのでDBに接続できずエラーとなる

# 対処
* `.env.local`を読み込ませるためには以下のコマンドを実行する


```bash
# dotenv-cli をインストール
$ npm install --save-dev dotenv-cli

# .env.local を読み込んで prisma db seed を実行
$ ./node_modules/.bin/dotenv -e .env.local -- npx prisma db seed

Prisma seed
{ events: [] }

🌱  The seed command has been executed.
```

無事エラーが解消された。

# 参考サイト
* 複数の .env ファイルの使用 - https://www.prisma.io/docs/guides/development-environment/environment-variables/using-multiple-env-files
Reactの「props」と「state」: その違いと役割について

Reactを学ぶ中で、最初に出会う基本的な概念として __props__ と __state__ があります。これらはどちらもコンポーネントでデータを扱うための重要なツールですが、使い方や役割が異なります。この記事では、これらの違いと役割を初心者にもわかりやすく解説します。

# props とは
props（propertiesの略）は、Reactコンポーネントが外部から受け取るデータを指します。これは、コンポーネントが再利用可能になるためのキーとなる概念で、異なるデータをpropsとして渡すことで、同じコンポーネントを様々な場面や状況で再利用することができます。

## props の特性
- __読み取り専用__: propsは外部（主に親コンポーネント）からコンポーネントに渡される情報です。
子コンポーネントは、渡されたpropsの値を直接変更することはできません。変更が必要な場合は、親コンポーネントにその変更を伝え、親がpropsの値を変更するべきです。
例: 親から子へと「名前」として"John"が渡されたら、その子コンポーネント内で"John"を"Mike"に変更することはできません。

- __再利用性__: propsを使うことで、同じコンポーネントを異なるデータで複数回使い回すことができます。
例: 一つの「ボタン」コンポーネントに、propsとして異なるテキストや色を渡すことで、様々なボタンを作ることができます。

## 使い方
親コンポーネントから子コンポーネントにデータを渡す際に、属性としてpropsを設定します。
```typescript
// ボタンというコンポーネントを定義
function Button(props) {
    return <button style={{ backgroundColor: props.color }}>{props.text}</button>;
}

// このボタンコンポーネントを利用して、異なるテキストや色のボタンを作成
<Button text="クリックしてね" color="blue" />
<Button text="削除" color="red" />
```
この例では、Buttonという一つのコンポーネントを作成しましたが、異なるpropsを渡すことで、異なるテキストや色のボタンを表示することができます。

### 子コンポーネントでのアクセス
子コンポーネント内でpropsにアクセスするには、this.props.プロパティ名（クラスコンポーネントの場合）やprops.プロパティ名（関数コンポーネントの場合）を使用します。


# state とは
Reactの __state__ は、コンポーネント内で変化するデータを管理するための仕組みです。例えば、ユーザーの操作に応じて表示内容を変更する場合や、外部APIから取得したデータを表示する場合など、変動するデータを扱う際にstateが利用されます。

## stateの特性
- __局所的__: stateは、定義されたコンポーネント内でのみ利用可能です。他のコンポーネントから直接アクセスすることはできません。
- __不変性__ : stateは直接変更すべきではありません。変更する場合は、setStateメソッドを使用します。これにより、Reactはコンポーネントの再レンダリングが必要なタイミングを適切に判断できます。

## 使い方
```typescript
// Counterという名前のReactクラスコンポーネントを定義
class Counter extends React.Component {
  // コンポーネントが作成される際に実行されるコンストラクタメソッド
  constructor(props) {
    super(props); // 親クラスのコンストラクタを呼び出す
    // stateの初期値を設定。初めてのカウント値は0。
    this.state = { count: 0 };
  }

  // コンポーネントの表示内容を定義するrenderメソッド
  render() {
    return (
      <div>
        {/* 現在のカウント値を表示 */}
        <p>{this.state.count}</p>
        {/* ボタンをクリックすると、カウント値が1増加する */}
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          カウントアップ
        </button>
      </div>
    );
  }
}
```
このCounterコンポーネントは、カウントの値を表示し、ボタンをクリックするたびにその値を1増加させるシンプルなカウンターとして動作します。カウントの値はstateに保持されており、ボタンをクリックするとsetStateメソッドによって更新され、コンポーネントが再レンダリングされます。

# まとめ
Reactでは、コンポーネントが情報を受け取る（props）と情報を管理する（state）の2つの主要な方法があります。 __props__ は親から子へと情報を渡すためのもので、 __state__ はコンポーネントが動的に変わるデータを保持・管理するためのものです。これらの概念を理解することは、Reactの動作を理解する上で非常に重要です。
Webアプリケーションとアプリケーションサーバーの比較 / PumaやRackの話も少し

### Webアプリケーションとは
:::note
インターネットなどのネットワークから利用するアプリケーションソフトウェア。Webサーバー上で動作し、ChromeなどのWebブラウザで操作する。
:::

##### ネイティブアプリとの比較
ネイティブアプリは手元の端末にインストールして利用するアプリケーションソフトウェアのこと。Webアプリはプログラム本体がネットワーク上のWebサーバーに保管されるのに対して、ネイティブアプリは手元の端末内で保管される。


### WebブラウザからWebサーバへの接続

:::note
URLは、Webサーバなどで公開されているリソースの場所を示す値。ブラウザにURLを入力すると、そのURLは実際にはWebサーバーのアドレス識別子。
:::

```
https://example.com/book/text.html
```
##### URLの解読
||名称|役割|
|:-|:-|:-|
|https|スキーム|利用するアプリケーションを指定する.**http,https**の場合はWebサーバにアクセスする|
|example.com|ホスト名|ホスト名から**DNS**を使用して、**IPアドレス**を調べる。そして**ルーター**を利用して、そのIPアドレスまでの経路を調べる。|

Webサーバに到達すると、そのサーバの中で動いているサーバを識別するために、**ポート番号**を使用する。

##### URIとURLの違い
||意味|
|:-|:-|
|URI|WWW以外にも利用できる広義の識別子。ホームページのアドレスや、メールアドレス、電話番号など様々な枠組みに対応する。|
|URL|URIよりも狭義の識別子。しばしばインターネットの資源の場所を表す俗称として使われる。|


##### ブラウザの代表例
* Microsoft Edge
* Google Chrome
* FireFox
* Safari


### Webサーバーの役割
:::note
Webサーバーは、クライアントのWebブラウザからのリクエストに応じて、HTMLや画像などのデータを返す。
:::
||役割|
|:-|:-|
|静的なサイトの場合|指定されたファイルをWebサーバーに返す。|
|動的なサイトの場合|必要に応じて、アプリケーションサーバーやDBサーバーと連携して動作する。|

##### Webサーバーの代表例
* Apache
* Nginx
* IIS


### アプリケーションサーバーの役割
:::note
Webサーバーから受け取った情報を処理するためのもの。プログラミング言語で構築されたアプリケーションを実行して、動的なコンテンツを生成する。リクエストによってはDBにアクセスして、データの抽出・加工を行う。
:::

##### アプリケーションサーバーの代表例
* Apache Tomcat
* Puma
* Unicone



### WebサーバーとAPサーバーの比較
##### 対象タスク
||比較|
|:-|:-|
|Webサーバー|Webサイトをホストし、簡単なリクエストに応答する。|
|アプリケーションサーバー|より複雑なタスクを行う。ビジネスロジックを処理し、DBなどに接続して動的コンテンツを生成する。|

##### 使用プロトコル
||比較|
|:-|:-|
|Webサーバー|使用する主なプロトコルはHTTP。またFTPやSMTPをサポートするWebサーバーは異なる。|
|アプリケーションサーバー|Webサーバーが使用するプロトコルに加えて、他のソフトウェアコンポーネントと通信するために追加の通信プロトコルがある。|

##### コンテンツタイプ
||比較|
|:-|:-|
|Webサーバー|基本的に静的コンテンツを配信する。配信前にサーバーが変更したり処理したりする必要のないコンテンツ。画像ファイルやHTMLファイルなど。|
|アプリケーションサーバー|主に動的コンテンツを配信する。ユーザーの操作方法に基づいて変化するコンテンツ。カスタマイズされたデータ表現、パーソナライズされたUI、データベース結果、処理されたHTMLなど。|


##### マルチスレッド
||比較|
|:-|:-|
|Webサーバー|ほとんどのWebサーバーはマルチスレッドをサポートしていない。|
|アプリケーションサーバー|マルチスレッドを使用して高いスケーラビリティと効率を実現する。リクエストに外部リソースが必要な場合、アプリケーションサーバーは個別のスレッドを使用してそれらのインタラクションを処理する。複数のスレッドを一度に処理し、多数のクライアントインタラクションを並行して処理できる。|


### Rackについて
:::note
Rackを使用することで、。どのアプリケーションサーバーであってもRailsアプリケーションを動作させることができる。Rackは RailsのようなRuby製フレームワークとアプリケーションサーバーの共通言語のようなもの。
:::

Rackを使わないとWebサーバーからのリクエストをRailsに渡すことができない。RailsはRackアプリサーバーであるPumaを動かすことでWebサーバーとのやり取りを実現している。


### Pumaについて
:::note
Railsのアプリケーションサーバー。Rackアプリを実行するためのアプリケーションサーバー。
:::
Puma自体もWebサーバーなので、Webサーバー機能はあるが、あくまでおまけ程度。メイン機能ではないため、大量のアクセスには耐えることができない。（PumaのWebサーバ機能は、ローカル環境で開発するときに使用している。）


### Nginxについて
:::note
Pumaの代わりに純粋なWebサーバーとして機能する。Railsは、RackアプリケーションサーバーであるPumaとしかデフォルトで連携していないため、本番環境などではNginxなどのWebサーバーをたてる必要がある。
:::
【Android】プロファイル可能なアプリにするための設定方法

# はじめに
日常的に自身が作成しているアプリのパフォーマンスが適正な状態かどうか確認する必要があるかと思います。
その確認方法の一つとして、Android Qからアプリをプロファイル可能にするために設定が提供されています。
今回は上記に関しての設定方法を備忘録的にまとめておこうと思います。

# 設定方法
設定方法は非常に簡単です。
以下をManifestのApplication直下に記載するだけでプロファイル可能なアプリとなります。

```xml
<profileable
   android:shell="true"
   tools:targetApi="29" />
```

以上です、注意点としては当然ではありますが、プロファイル可能になるということは色々見えてしまうことになるので、本番環境で設定はしないよう気をつけましょう。

# さいごに
Droid会議お疲れ様でした！
今回も非常に刺激的な登壇ばかりでした、忘れないためにも暫くはDroid会議の内容を記事にまとめるようにしたいと思います。
【Android】Mathクラスについてpart２【Kotlin】

# はじめに
前回に引き続き、Mathクラス内で使えそうなものを記事に残します！
前回よりは使わなそうだけど、もしかしたら使うなって感じ（自分基準）

https://qiita.com/Tsubasa12/items/709cbd01b1abbfe8e209

# max()
```
max(10,-8)   // 10
```
２つの数字の最大値

# min()
```
min(10,-8)   // -8
```
２つの数字の最小値

# pow()
```
5.pow(3)   // 125
```

累乗
# PI
```
PI   // 3.141592653589793
```
円周率


# random()
```
random()  // 0.6071951836875007 
```
0以上1未満の double 型の値をランダムに生成する

```
val range = (10..20)
range.random()   // 13
```
範囲を指定することで、その範囲内でランダムに値を生成する

# 参考

https://www.choge-blog.com/programming/kotlingetpi/

https://hiyoko-programming.com/1507/
RMD

資料 ダウンロードサイト

https://www.myactuator.com/dowload

プロトコル資料

https://www.myactuator.com/_files/ugd/cab28a_9d344907863b4033ada6d9318d511b6e.docx?dn=RMD-X%20Servo%20Motor%20Control%20Protocol%20V3.6.docx

電圧

x4:24v
x6 ~ :24 ~ 48v

https://www.switch-science.com/products/9059
draw.ioで色々な表を描いてみる (実践編)

# やること
具体的に表を使った帳票の図を作成してみます。

# 請求書
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116331/279af95e-252f-57c8-6f8b-49367b93f4e2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116331/7fb5f1cf-c967-1b60-2f5c-52fa5e8bcec8.png)

[コード](https://gist.github.com/project-flower/57bc85065bc0258a02bf0bfd07fae812#file-invoice_001-drawio)

# 請求書(2)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116331/862b9b79-c411-617f-a2a8-6be1bab12207.png)
列の枠を無くして少しモダンに
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116331/90c49870-33ef-9da3-0a71-fb102f563310.png)

[コード](https://gist.github.com/project-flower/57bc85065bc0258a02bf0bfd07fae812#file-invoice_002-drawio)

# Windows タスク マネージャー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116331/ceaf2cd7-addf-b8f1-dc65-16a8f38230e6.png)
Windowsのタスク マネージャーのUIを作成してみました。

[コード](https://gist.github.com/project-flower/57bc85065bc0258a02bf0bfd07fae812#file-windows_task_manager_001-drawio)
AWSサポートに問い合わせる前に確認するべきこと

AWSを利用していると、AWSに関する障害や予期せぬ動作などで、どうしてもサポートに問い合わせて解決したいことがしばしばあります。
今回はそんな中で、どのようにAWSサポートに問い合わせるべきかを記述します。


## この記事の対象者
- AWSサポートへどのような質問をすればよいかお悩み中の方。
- AWSサポートへ問い合わせる内容/受け付けない内容は何か知りたい方。


## AWS サポート への問い合わせ方
実は問い合わせ方についてはAWS側で明記しています。
以下のリンク「**[技術的なお問い合わせに関するガイドライン](https://aws.amazon.com/jp/premiumsupport/tech-support-guidelines/)**」 にAWSへの問い合わせに関する注意事項などが記載されております。
サポートへ問い合わせる前に一度読んでから実施した方が、やり取り少なく円滑に解決できる確率が高くなるため、一度読んでいただければと思います。

https://aws.amazon.com/jp/premiumsupport/tech-support-guidelines/


## 質問文の書き方

「**[技術的なお問い合わせに関するガイドライン](https://aws.amazon.com/jp/premiumsupport/tech-support-guidelines/)**」から、必要な文章としては以下の内容が含まれていれば概ね問い合わせ内容としては宜しいかと思われます。
以下の内容が網羅されていれば、完璧に近い問い合わせができる。。かも？


1. 発生時刻、アカウント情報 ... 「[状況を正確に共有する](https://aws.amazon.com/jp/premiumsupport/tech-support-guidelines/)」を参考に。
    - アカウント情報(アカウントID,リージョン)は記述する
    - 発生時刻の記述(タイムゾーンの記述やアカウント情報など忘れずに。)

2. 対象サービス(EC2やRDSなどのインスタンスIDなどの情報。)
    - 障害発生したインスタンスIDなどのリソースID情報を連携する。

3. 発生事象について 「**[経緯を共有する](https://aws.amazon.com/jp/premiumsupport/tech-support-guidelines/)**」を参考に。
    - エラー発生までのを時系列を記述。
    - エラー文言は正確に記述する。キャプチャなどがあれば添付する。

4. 原因調査について ... AWSに問い合わせる前に最低限自分たちで調査してみること。
    - エラーログがあればその内容を記述する。
    - 原因調査に使用したURLがあったら記述する。
    - キャプチャやログを圧縮して、AWSサポートに添付して送信することができる。
    - 最低限、エラー発生時に必要なログは調査して添付する。
        - 例えばOSの場合、/var/log/messagesの内容や該当するサービスのログは最低限添付するように。
        - 「追加で取得するログがありましたらご教授のほどお願いいたします」と記載した方が後々の調査が進む。

5. 復旧内容について
    - 復旧の際に検索した記事や、手順などがあれば連携する。
    - 復旧で実施した手順やログを連携する。
    - 復旧の結果についても同様に記述する。
        - 成功/失敗したのか。
    - ファイル数が多い場合、圧縮して添付する。

6. 問い合わせの目的 ... 問い合わせの目的(AWSサポートに求めるもの)を明確にする。
    - AWSサポートへ何を求めているのかゴールを記述する。
        - 例えば、「原因を突き止めたい」と「原因を突き止め、復旧の手順を連携して欲しい」は明確に異なるため、問い合わせで求めることは正確に.


## 困った質問内容
こちらはアンチパターンの質問になります。

「[ご案内が難しいご質問](https://aws.amazon.com/jp/premiumsupport/tech-support-guidelines/)」を参考にすればどのような質問がNGかがわかるため、できる/できない内容については、事前に把握しておいた方がAWSと円滑に応答ができるでしょう。

#### AWS アカウント ID を超えたお問い合わせ
問い合わせ対象外のアカウントIDについては基本的には問い合わせは実施しないように。
どうしても他アカウントの値を含めるのなら、クロスアカウントでの利用や、Organizationsを利用している等の背景は含めないと伝わらないかと。

#### 障害の原因についてのお問い合わせ
「EC2インスタンス上が停止した。何故だ!!」的な質問にはお答えできない。。
インスタンスは壊れるものと想定して、早急に復旧するシナリオを事前に作成しておく。
また、復旧を試みたが正常起動しなかった場合は、復旧で実行した手順や、調査内容(ログ、キャプチャ、参考にしたURL)を添えて問い合わせた方が良い。
また、OSレイヤー以上のアプリの問い合わせになるとAWS側も対応できない可能性もあるため、問い合わせはAWSに関係する内容で問い合わせた方がよい。


#### 性能指標についてのお問い合わせ
「思ったよりパフォーマンスが出ないんだけど」についてもお答えできません。。あくまで事前に検証や本番を想定した負荷試験などでパフォーマンスを測定して、アーキテクチャを顧客自身が検討いただく必要があるかと。


#### メンテナンスの過去の実績や頻度についてのお問い合わせ
→ 「今度DBバージョンをあげるんだけど過去の実績ない？」などの質問に関しては受け付けていません。
あくまでも、検証用DBを作成してAWS提供の移行ツールなどで検証してみて、その上で移行ツールを検討すればよいかと。。

#### AWS 内部の仕組みについてのお問い合わせ
これも言わずもがなかと。。責任境界外のアーキテクチャについて知ってどうなるのかと。。。


#### コンプライアンス関連のお問い合わせ
そもそも担当部署が異なる。。
https://pages.awscloud.com/compliance-contact-us.html?Languages=Japanese

#### AWS 基盤の不具合改修のご案内
個別対応はしてないため、不具合の解消有無については別途ケースを発行する。


### まとめ
「**[技術的なお問い合わせに関するガイドライン](https://aws.amazon.com/jp/premiumsupport/tech-support-guidelines/)**」を事前に把握していれば、やり取りを少なく、円滑に解決までのやり取りを実施することができるため、ぜひ一度目を通していただければと思います。
VScodeの便利な一括リプレイス機能（備忘録）

# 初めに
開発中に複数のファイルにまたがって使用している、テンプレートから引っ張って来たコードの一部を変更したり、いろいろなところで使っている変数名を変更したいとき一つ一つ直すのは非常にめんどくさい。そんなときVSCodeのリプレイス機能を使えば簡単に解決できます。

# やり方
1. まず初めに以下のようにhome.htmlとindex.htmlがあります。違いはpタグ内のメッセージだけです。

    home.html
        ![スクリーンショット 2023-09-17 105342.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3514631/fac933e1-9351-c7f0-7d57-0452dd84eb97.png)
    index.html
    ![スクリーンショット 2023-09-17 105307.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3514631/93a53461-049e-fd3f-44de-25bdfabedcff.png)
2. 次に左のメニューバーの虫眼鏡をクリック、もしくは(Ctrl+Shift+f)でショートカットを使用します。
    ![スクリーンショット 2023-09-17 105657.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3514631/64f5ddee-0a0b-4d51-b903-68ec17b30762.png)
3. 以下のような入力欄が出てくるので上部に変更したいワード、下部に変更後のワードを入力します。今回はpタグのクラス名をmessageからwelcome-messageに変更します。
    ![スクリーンショット 2023-09-17 111230.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3514631/89ff1b24-3864-0a90-020c-985109fd0038.png)
4. Replaceボタンを押すと以下のようなメッセージが出ます。Replaceを押すと指定したワードが変更されます。
    ![スクリーンショット 2023-09-17 111556.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3514631/cc3d4cc8-90f4-4efd-6034-b16441c036d2.png)
    ![スクリーンショット 2023-09-17 112105.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3514631/252abf00-6ef1-6ed7-fc51-794e954cd150.png)

# まとめ
このReplace機能を使えば一括でプロジェクト内の変数やクラス名を変更することができます。しかし変更したいワードが含まれているもの全てが選択されるのでその点は注意が必要です。便利な機能なので工夫して使いましょう:grinning:
Djangoでメールを送信する

### 参考にさせていただいたHP

[djangoでメールを送信する](https://houdoukyokucho.com/2020/05/31/post-1143/)

[Gmailのアプリパスワードの生成](https://www.gocca.work/python-mailerror/)

[Djangoのメール周りメモ](https://nwpct1.hatenablog.com/entry/django-email)
競プロ超初心者が解く、回分最大長さの取得

# 概要
競技プログラミングの超初心者が、初心者向けの問題を解きます。
問題を回答するにあたって、使用する言語はPythonです。
問題を解いていている時の思考と、最適なアルゴリズムを調べて記事にしています。

# 回答した問題
文字列の中から回分となる箇所を探し出して、回分となる最大文字列を出力する問題です。
[トヨタ自動車プログラミングコンテスト2023#5(AtCoder Beginner Contest 320) B - Kibgest Palindrome](https://atcoder.jp/contests/abc320/tasks/abc320_b)

## 自力の回答

## 提出コード
二重ループで文字列の左側開始位置と、終了位置を調整して部分的な文字列を網羅的に取得しています。文字列と逆の文字列を比較して、同等の文字列であれば現在の最大値を更新します。
```python
s = input()
s_len = len(s)
max_len = 0

for i in range(s_len):
    for j in range(i+1, s_len+1):
        s_mid = s[i:j]
        if s_mid == s_mid[::-1]:
            max_len = max(max_len, len(s_mid))

print(max_len)
```

## 最適解

### 回答の問題点を確認
BingAIにコードを評価してもらいました。
```
競技プログラミングの回答で、次のプログラムを提出して合格しました。
提出したコードを評価して、問題点を箇条書きで出力してください。

---
{code}
---
```

二重ループだと、文字数が長い場合はプログラムの実行時間が長くなってしまうと指摘されました。他にも指摘された点はありましたが、適切ではなかったので省略しました。
```BingAI
コードの効率性が低いです。二重ループで全ての部分文字列を調べると、時間計算量がO(n^2)になります。
動的計画法やマンチェスター法などを使うと、時間計算量をO(n)に減らすことができます。
```

### 最適化されたコード
最適なアルゴリズムに書き換えたプログラムをBingAIに出力してもらい、確認していきます。Manacherというアルゴリズムを使用しているらしく、理屈は分かりませんが正しい答えが出力されました。
```python
def manacher(s: str):
    # 文字間に#を挿入して奇数長にする
    t = "#" + "#".join(s) + "#"
    n = len(t)
    # 各位置での最長回文半径
    p = [0] * n
    # 現在注目している中心位置
    c = 0
    # 現在注目している中心位置からの最右端
    r = 0
    # 最長回文の長さ
    max_len = 0
    for i in range(n):
        # iがrより左にある場合は、対称位置の値を利用できる
        if i < r:
            p[i] = min(p[2 * c - i], r - i)
        # iがrより右にある場合は、1から始める
        else:
            p[i] = 1
        # 中心をiとして回文を拡張する
        while i - p[i] >= 0 and i + p[i] < n and t[i - p[i]] == t[i + p[i]]:
            p[i] += 1
        # 最右端と中心位置を更新する
        if i + p[i] > r:
            r = i + p[i]
            c = i
        # 最長回文の長さを更新する
        max_len = max(max_len, p[i] - 1)
    return max_len

s = input()
print(manacher(s))
```

# さいごに
今の実力では、アルゴリズムについて学習する段階ではないため記事はここで終了します。
行き詰まった時に、アルゴリズムに関する記事を書いていこうかなと。
Kubernetesを統合して、Railsアプリケーションをデプロイするチュートリアル

# Docker Desktop for MacにKubernetesを統合して、Railsアプリケーションをデプロイするチュートリアル

Docker Desktop for Macを使用して、ローカルのKubernetes環境にRailsアプリケーションをデプロイする方法を紹介します。

## 目次

1. [環境の準備](#1-環境の準備)
2. [Railsアプリケーションの作成](#2-railsアプリケーションの作成)
3. [Docker化](#3-docker化)
4. [イメージのビルド](#4-イメージのビルド)
5. [Kubernetesのデプロイメントとサービスの作成](#5-kubernetesのデプロイメントとサービスの作成)
6. [アクセス](#6-アクセス)
7. [トラブルシューティング](#7-トラブルシューティング)

---

## 1. 環境の準備

1. Docker Desktop for Macを[公式サイト](https://www.docker.com/products/docker-desktop)からダウンロードしてインストールします。
2. Dockerの設定からKubernetesを有効化します。
3. `kubectl` コマンドが動作することを確認します。

```bash
kubectl version
```

---

## 2. Railsアプリケーションの作成

新しいRailsアプリケーションを作成します (既存のアプリケーションを使用しても構いません):

```bash
rails new my-rails-app
cd my-rails-app
```

---

## 3. Docker化

1. アプリケーションのルートに`Dockerfile`を作成します:

```Dockerfile
FROM ruby:2.7.2

RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
WORKDIR /my-rails-app

COPY Gemfile Gemfile.lock ./
RUN gem install bundler && bundle install

COPY . ./

CMD ["rails", "server", "-b", "0.0.0.0"]
```

2. 同じくアプリケーションのルートに`docker-compose.yml`を作成します:

```yml
version: '3'
services:
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/my-rails-app
    ports:
      - "3000:3000"
```

---

## 4. イメージのビルド

Docker Composeを使用してアプリケーションのDockerイメージをビルドします。

```bash
docker-compose build
```

---

## 5. Kubernetesのデプロイメントとサービスの作成

1. アプリケーションのルートに`k8s-deployment.yml`ファイルを作成し、以下の内容を追加します:

```yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-rails-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-rails-app
  template:
    metadata:
      labels:
        app: my-rails-app
    spec:
      containers:
      - name: my-rails-app
        image: my-rails-app:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 3000
```

2. アプリケーションのルートに`k8s-service.yml`ファイルを作成し、以下の内容を追加します:

```yml
apiVersion: v1
kind: Service
metadata:
  name: my-rails-app
spec:
  selector:
    app: my-rails-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 3000
  type: LoadBalancer
```

3. 作成したマニフェストを用いてKubernetesにアプリケーションをデプロイします:

```bash
kubectl apply -f k8s-deployment.yml
kubectl apply -f k8s-service.yml
```

---

## 6. アクセス

Docker Desktop for

 MacのKubernetesはローカル開発用に設計されています。LoadBalancerタイプのサービスを使用する場合、ブラウザから`http://localhost`に直接アクセスすることでRailsアプリケーションを表示できます。

## 7. トラブルシューティング

### 7.1. PodのImagePullBackOffエラーの解決

**問題**: 
Podのステータスが`ImagePullBackOff`となり、KubernetesがDockerイメージをプルする際に問題が発生していました。

**解決策**:
1. `kubectl describe pod <POD_NAME>`コマンドを使用してPodの詳細なログを調査します。
2. ログには、イメージ`my-rails-app:latest`のプルに失敗したことが示されています。
3. これはローカルのDockerイメージであり、Kubernetesがそのイメージを見つけることができなかった原因です。
4. `docker images`を使用して、ローカルで利用可能なDockerイメージをリストアップします。
5. イメージ名のミスマッチを確認します。実際のイメージ名は`my-rails-app-web`であるため、`k8s-deployment.yml`のイメージ名を適切に修正する必要があります。
6. 更新された`k8s-deployment.yml`を再適用して、Podが正常に起動することを確認します。

この方法で、`ImagePullBackOff`エラーを解決しました。同様の問題が発生した場合、ローカルのDockerイメージ名とKubernetesのDeployment設定のイメージ名が一致していることを確認してください。

---

これで、Docker Desktop for MacのローカルKubernetes環境上にRailsアプリケーションをデプロイする手順が完了しました。
【Swift】指定した時間で閉じるアラートの後に処理を実行する

## 概要
アラートを表示した後指定した時間で閉じ、さらにその後処理を実行する方法です。
今回は閉じるボタンをつけていないですが、必要に応じてaddActionを使ってボタンを追加します。

## コード
### 1. アラートを表示するメソッドを作成する
```Swift
func showAutoDismissAlert(title: String, message: String, completion: (() -> Void)?) {
    let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
    present(alert, animated: true)
        
    DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
        alert.dismiss(animated: true) {
            // アラートが閉じられた後にコードを実行
            completion?()
        }
    }
}
```
`DispatchQueue.main.asyncAfter`を用いて2秒後に閉じるように設定しています。`2.0`を変更すると、任意に閉じるまでの時間を指定することができます。
`completion`を引数に指定することで、`showAutoDismissAlert`を呼び出す際にクロージャでアラートが閉じた後に実行したいコードを渡すことができます。

### 2.作成したメソッドを呼び出す
```Swift
showAutoDismissAlert(title: "ありがとうございました", message: "2秒後に閉じます") {
    // アラートが閉じた後に実行するコード
    // 画面遷移など
    hogehoge()
}
```
`showAutoDismissAlert`にアラート表示内容の`title`,`message`を渡し、クロージャ内で処理を記述します。

**処理を行わない場合**
```Swift
showAutoDismissAlert(title: "ご利用いただきありがとうございました。", message: "ログイン画面に移動します", completion: nil)
```
`completion`に`nil`を渡すことで処理を行わずに閉じることもできます。

## おわりに
このような自動で消えるダイアログは、例えば削除などの処理を終えた時に活躍します。
例えば画面遷移する場合、これからどの画面に移動するのかをアラートで明示し、アラートが消えた後に画面遷移するとユーザー体験が向上すると感じます。
実装してみて、ちょっとリッチなアプリになった気がします。

お読みいただき、ありがとうございました。
Yahooニュースの削除された記事を表示するブックマークレット作った

追記：2025年現在、使用できなくなっております

これをブックマークに登録してください。
```javascript
javascript:(function(){var a=document.location.href.replace("news.yahoo.co.jp","yahoo-archive.activetk.jp");document.location.href=a})();
```

例えばこんな感じ
![スクリーンショット 2023-09-17 17.34.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256853/b5ed050d-ec40-28a1-94d2-e3e4e2356ddc.png)

## 使い方
削除されたYahooの記事を見つけたら、このブックマークレットを呼び出します。

例えばこの記事は削除されてますね。

https://news.yahoo.co.jp/articles/75a277d0dd15cee8f1d687007fc70cdcb99045b1

![スクリーンショット 2023-09-17 17.41.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256853/7d7d4048-e259-d62c-48ff-9778a486ea48.png)

こんな感じで見れるようになります。

https://yahoo-archive.activetk.jp/articles/75a277d0dd15cee8f1d687007fc70cdcb99045b1

![スクリーンショット 2023-09-17 17.42.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256853/b0d8f16e-9ebc-97eb-a027-1ffbac9832a1.png)

## 背景・解説

やってることは、`news.yahoo.co.jp`を `yahoo-archive.activetk.jp`にreplaceしてるだけ。

アーカイブを保存する中身の実装は、ActivTKさんです。これを見て、ブックマークレットにしたら便利そうだなと思って作りました。

https://twitter.com/ActiveTK5929/status/1701917875609715025?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1701917875609715025%7Ctwgr%5Ef2ffd04463209c0d1e4da5cc082cbb322eb90443%7Ctwcon%5Es1_c10&ref_url=https%3A%2F%2Fpublish.twitter.com%2F%3Fquery%3Dhttps3A2F2Ftwitter.com2FActiveTK59292Fstatus2F1701917875609715025widget%3DTweet

## 参考にした記事
https://qiita.com/kanaxx/items/63debe502aacd73c3cb8

## コード圧縮
https://closure-compiler.appspot.com/home
AlmaLinux9にDockerとDocker Composeを導入する

# 元記事
[AlmaLinuxにDockerとdocker-composeを導入する](https://qiita.com/Nats72/items/660798a9146baf68e376)

# Dockerインストール
```
# dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# dnf -y install docker-ce docker-ce-cli containerd.io
```

## Docker起動＆起動設定
```
# systemctl start docker
# systemctl enable docker
```

## バージョン確認
バージョンを確認できればOK！
```
# docker --version
Docker version 24.0.6, build ed223bc
```

# Docker Composeインストール
最新バージョンは https://github.com/docker/compose/tags で調べた方が良いかも。
2023年9月17日時点では、 `v2.21.0` でした。

```
# curl -L "https://github.com/docker/compose/releases/download/v2.21.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
```

## 実行権限付与
```
# chmod +x /usr/local/bin/docker-compose
```
## 確認
最近はv2の「docker compose」を使います。

バージョンを確認できればOK！
```
# docker compose version
Docker Compose version v2.21.0
```
【Android】ZxingとML Kit を検証してみた

# はじめに
こんにちは。
今回はQrコード読み取りでライブラリの比較<b>（個人的主観）</b>をしたのでそのことについてです。
実装の解説などはないので興味がなければ、ブラウザバックでお願いします！
まず、Android開発で考えなければならないのがライブラリ選定です。それはQRコードを読み取りに関わらずです。セキュリティ、性能面、サポート期限などなど。。。色々あると思います。
今回注目したのが性能面です。実際に実装を行い、動かしてみてもし新しく導入するなら自分なら。。と言うことを記事にしてみました。
# 注意事項
注意事項です。
比較は今回実装したもので判定しています。
なので、実装方法を変えることにより性能が上がることも十分あります。また先ほどもお伝えしましたが、完全に個人的な意見になりますので　、間違っている可能性もあります。確認したOSはAndroid11です。また、どちらのライブラリも素晴らしかったと言うことはお知らせしておきます。
# 比較結果
比較することは以下になります。
* 読み取り
  * 読み取りの距離
  * 距離が近い場合しっかり読み取れているか
  * 読み取りの正確さ 
* 実装のしやすさ

|  | Zxing | Ml Kit |
|:------------|:-----------|:------------|
|読み取りの距離|60cmくらい離れると<br>少し読み取りが悪くなる　| 60cm離れても<br>読み取りが悪くならない|
| 距離が近い場合しっかり読み取れているか|基本的にはも読み取れてはいるが<br>フレームによっては読み取れていないことがちょいちょいある|しっかり読み取れてフレームによって読み取れないことはあるがほぼない|
| 読み取りの正確さ　|動作確認時で間違ったURLを読み込んでいることはなかった|動作確認時で間違ったURLを読み込んでいることはなかった|
|実装のしやすさ |日本語での情報も存在するしできないことはない|日本語での情報も存在するしできないことはない|

上記のような感じですね。
個人的にはMl Kitの方が読み取りはいいなと感じました。
実装についてはどちらもめちゃくちゃめんどくさくて実装しずらいという感じではありませんでした。
なので新規で導入するのであればMl Kitかなと感じています。

# 最後に
いかがでしたでしょうか？
本来の検証であればフレームレートが。。！とかスレッドがとか。。！気にすることはあると思うし数字で出さなければならないと思いますが、そこは私の勉強不足ですみません。。こう言うのも測定できるといいなどあればご教示いただきたいです。
ちなみに以下が検証したアプリになります。公開しているので、実装が間違っているなどあればぜひ合わせてご教示いただきたいです。あと実際に自分で触って検証していただければと思います。
最後までご覧いただきありがとうございました。

https://github.com/kazu09/QrCodeSample
WindowsのタスクマネージャでGPUを常時監視

このところ生成AIというかLLMにハマっているけれども、自作PCだとハードウェア資源の利用状況が気になってしまう。そして日曜エンジニアだとWindowsを使いながらWSL2を起動し、タスクマネージャでCPU、GPU、メモリ、ディスク、ネットワークの利用状況を一覧表示してくれるタスクマネージャから離れられない。

さらにWindows 3.1やWindows 95を知っている世代としては、システムが少しくらい不安定になっても全く気にならないので、レジストリを書き換えてNVIDIA Telsa P40をタスクマネージャで監視できるようにしてしまった。ただしご存じの通りレジストリ内容というのはWindows任せなので、油断していると書き換えられてしまう。そこで小細工により、Windows起動時にレジストリを毎回書き換えて常時監視できるようにしてみた。

ちなみにネットではNVIDIAのGPUをタスクマネージャで監視することが出来ないという悲鳴を散見するけれども、タスクマネージャーではWDDMモードで動作しているGPUしか認識することが出来ない。GPUが正常に設定されて動作しているかはnvidia-smiコマンド、そしてCUDAも含めて動作確認したければPyTorchをインストール後に下記コマンドを実行すると良いだろう。無事に動作していれば"True"を、動作していなければ"False"をリターン表示してくれる。

```
python3 -c "import torch; print(torch.__version__, torch.cuda.is_available())"
```

さて前置きが長くなってしまったけれども、具体的にどうやって書き換えているかを紹介する。

# 採用案：タスク・スケジューラ

「パンが食べれないなら、お菓子を食べれば良いじゃない」ではないけれども、残念ながら「レジストリを毎回書き換えたければスタートアップにバッチファイルを登録すれば良いじゃない」というアプローチは通用しない。それが今回の記事の発端だったりする。

実際に下記内容を書き込んだバッチファイルをスタートアップに登録してみたら、レジストリのキーを上書きすることは叶わず、妙てけりんなキーを新規登録する結果に終わってしまった。

```
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\0001” /v EnableMsHybrid /t “REG_DWORD” /d “1” /f
```

日曜エンジニアには分からないけれども、どうもスタートアップに登録されたプログラムが実行されるタイミングでは、レジストリキーの読み込みも完了しないのかもしれない。ログイン後に普通にクリックしてみたら、特に問題なくレジストリ内容を上書きしてくれた。

ちなみに上記はEnableMsHybridというDWORD(32bit)キーを新規作成するか、または既に存在するEnableMsHybridキーに対して1を書き込む処理である。"/f"というのは試してみると分かるけれども、バッチ処理の際に「本当にやっちゃいますか？」と尋ねる処理を省略するためのフラグである。

で、GPT3.5様にお伺いしてみて採用したのが、タスク・スケジューラにバッチファイルを登録する方法だ。なおWindows 11ではWindows 10と異なり、管理系ツールは "Windowsツール" にまとめられている。

![hentai1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3558027/f23a641f-0130-1e37-5fe8-c59d522c07bc.jpeg)

この中にタスク・スケジューラが含まれているので、まずはそれをダブルクリックして起動する。それから「操作」-->「基本タスクの作成」と進み、バッチファイル(当方の場合はwddm-tcc.bat)を「ログイン時に実行」で登録する。

あとはレジストリエディタをregeditコマンドなどで起動し、内容確認すればオッケーだ。

# 不採用案：ファイル名を指定して実行

Windows利用時に必ず実施する操作といえば、電源オン操作と電源オフ操作である。電源オフ操作に着目すると、「電源オフ操作をバッチ処理でやることにして、その際にレジストリ書き換えとシャットダウンを実施する」という方法もある。

```
shutdown /r /t 0
```

バッチファイルに上記を書き加えて、「スタートアップ」-->「ファイル名を指定して実行」やショートカットキー登録すれば良い。

そういえば弊社の場合は22時を過ぎると深夜残業ということで大騒ぎになるので、タスク・スケジューラに「21時57分になったら強制シャットダウンのバッチファイルを実行」と登録している人も存在する。ガラスの靴を残したシンデレラのように、仕事をやり残したことになるけれども、ともかく問題を起こさないという点では悪くないかもしれない。
(ちなみに当方は設定していない)

# まとめ

以上の通りで、タスクスケジューラを活用することによって毎回起動時or終了時にレジストリの内容を書き換えることが可能となる。

なお妙な意地を張らずに、素直にnvidia-smiコマンドを定期的に実行するのも悪くはない。コンソールを立ち上げるのが面倒であれば、バッチファイルにpauseコマンドとexitコマンドを加えるといった方法もある。

それとUbuntuの場合はwatchコマンドが使えるので、定期的(例えば0.5秒単位)にnvidia-smiコマンドを実行するということが可能である。

```
watch -n 0.5 nvidia-smi
```

ただし... やっぱり基本リソースの稼働状態を一覧表させるのはタスク・マネージャで「パフォーマンス」を選択するのが便利だし、GPU設定内容を表示するGPU-Zツールも存在する。vBIOSを書き換えるnvflash64もWindows環境が必要となるし、そもそも今はWSL2でCUDAが利用可能になっている。

昔はLinux (Ubuntu) 環境一択だったけれども、今はWindows環境も便利になったものだと感動する。がっつり動かす場合はUbuntuだけれども、個人的にはWindowsユーザとして終わるかもしれない。

それでは今回は、この辺で。
firebase functionsをローカル環境でデバッグする。


# 目的
* firebase functionsをローカル環境でデバッグする。
* 最小の動作する例

# 環境
friebase 11.24.1

クライアント側

```
import { getFunctions, httpsCallable, connectFunctionsEmulator } from "firebase/functions";
const app = initializeApp({{環境のキーとか}}); //0)
const functions = getFunctions(app);


  getTestCall = () => {
    return new Promise(async (resolve) => {
      const functions = getFunctions(app, 'us-central1')　//<- 1) エミュレータはこの処理を追加(リージョン指定必須)
      connectFunctionsEmulator(functions, "localhost", 5001); //<- エミュレータはこの処理を追加
      const addMessage = httpsCallable(functions, 'addMessage'); //<-関数名

      addMessage({ test: "test" })
        .then((result) => {
          console.log(result)
          console.log(result.data.message)

        })
        .catch((error) => {
          console.log("checkStripeUserById コール失敗");
          console.log(error);
        });

    })

  }
```

functions側
onCallする場合のサンプル

```
const functions = require('firebase-functions');

exports.addMessage = functions.https.onCall((data, context) => {
    functions.logger.log(" 呼び出し=============", data);
    console.log("test " + data)
    return { message: "test" };
})
```


起動
```
{{firebase init等は済み}}

firebase emulators:start --only functions 
2)
```

### ポイント
- '0) 実行環境 
    - クライアントは接続プロジェクトをAPIキーで指定。サーバはローカルで受け止める、1)でプログラム上で明記。
* '1) クライアントコード修正。ローカルのlocalhostに繋ぐようにここで指示する
* '3) http://127.0.0.1:4000/functions のようなものが払い出される。ここでログや、エンドポイントの一覧が確認可能になる
Docker Hubからコンテナイメージを取得してECRに登録するまでの手順をシェルスクリプトで自動化する


Dockerfileからイメージを作成してECRリポジトリへプッシュするまでをシェルスクリプトで自動化したいと思います。

## ECRリポジトリの作成

AWS CLIを使用して作成していきます。

```
aws ecr create-repository --repository-name my-ecr-repo --region ap-northeast-1
```

![Screenshot 2023-09-17 at 16.12.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626370/db661a6b-9a90-5e14-87e8-3157fb36a603.png)

作成が確認できました。

次にDocker Hubからコンテナイメージを取得してECRに登録するまでの手順をシェルスクリプトを作成していきたいのですが、1つずつ整理していきます。

### Dockerfile
以下のDockerfileを使用します。
```
FROM ubuntu:latest

# Install dependencies
RUN apt-get update && \
 apt-get -y install apache2

# Install apache and write hello world message
RUN echo 'Hello World!' > /var/www/html/index.html

# Configure apache
RUN echo '. /etc/apache2/envvars' > /root/run_apache.sh && \
 echo 'mkdir -p /var/run/apache2' >> /root/run_apache.sh && \
 echo 'mkdir -p /var/lock/apache2' >> /root/run_apache.sh && \ 
 echo '/usr/sbin/apache2 -D FOREGROUND' >> /root/run_apache.sh && \ 
 chmod 755 /root/run_apache.sh

EXPOSE 80

CMD /root/run_apache.sh
```

### Dockerfileからイメージを作成するコマンド
Dockerfileが存在するディレクトリ内で実行
```
docker build -t my-ecr-repo .
```

### ECRへのログインコマンド

```
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin [AccountID].dkr.ecr.ap-northeast-1.amazonaws.com
```

### DockerイメージをECR用にタグ付け
```
docker tag my-ecr-repo:latest [AccountID].dkr.ecr.ap-northeast-1.amazonaws.com/my-ecr-repo:latest
```

ECRリポジトリへプッシュ
```
docker push 445605964569.dkr.ecr.ap-northeast-1.amazonaws.com/my-ecr-repo:latest
```


これらを元にシェルスクリプトを書いていきます。

```
push-ecr.sh

#!/bin/bash

# 変数
DOCKER_IMAGE_NAME="my-ecr-repo" # Dockerイメージ名
AWS_ACCOUNT_ID="[AcountID]"     # AWSアカウントID
AWS_REGION="ap-northeast-1"     # AWSリージョン
ECR_REPOSITORY="my-ecr-repo"    # ECRリポジトリ名

# Dockerfileからイメージを作成
docker build -t $DOCKER_IMAGE_NAME .

# ECRにログイン
aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com

#イメージをECR用にタグ付け
docker tag $DOCKER_IMAGE_NAME:latest $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_REPOSITORY:latest

# イメージをECRにプッシュ
docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_REPOSITORY:latest

echo "コンテナイメージをECRに登録しました。"
```

こちら実行したところ、、、

![Screenshot 2023-09-17 at 17.01.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626370/f97e4706-bf4a-bf84-a906-65faf30dfddf.png)

無事ECRへのプッシュが確認できました。

今回はこの辺で。
Androidアプリ「はやメモ」をリリースしました【個人開発】

## はじめに

個人開発したAndroidアプリ「はやメモ」をリリースしました！

Androidアプリのリリースは今回で2回目です！

この記事では、アプリの紹介やアプリを開発している中で感じたこと、今後の課題だと思うことをまとめていきます。

## 目次
1. リリースしたアプリ「はやメモ」について
2. 制作した経緯
3. 使用した言語・データベース
4. 制作していて感じたこと
5. 今後の課題
6. おわりに

## リリースしたアプリ「はやメモ」について
#### リリースしたアプリ

* <a href='https://play.google.com/store/apps/details?id=com.ruriboshi.hayamemo'>はやメモ:シンプルなメモ帳、ノート、メモアプリ</a>

#### アプリの概要

シンプルなメモ帳アプリです。アプリを起動してすぐに新規メモが開くので、ささっとメモしたいときに便利です。すぐにメモしてすぐに保存できるように保存ボタンを画面右上に配置するなど、使いやすさも考えて制作しました。

<p>
<img width="30%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2354509/2dbc45b1-01a8-080b-9968-21a0bdb33a7b.png">

<img width="30%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2354509/00ab8d6c-e271-3b5a-b0f6-e8606d6aa908.png">

<img width="30%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2354509/8af4f6f3-11e9-55f1-1f69-456ead0bd9ac.png">



</p>


## 制作した経緯

前回リリースしたアプリ<a href='https://play.google.com/store/apps/details?id=com.ruriboshi.clask_app'>Clask</a>のリリース作業に手こずっていたときに、気分転換をするために制作しました（笑）メモアプリを作ろうと思った理由は、今までに勉強してきた知識で作れそうだったからです。

## 使用した言語・データベース

* Kotlin
前回リリースしたアプリと同様にKotlinで開発しました。

* Realm
Realmはデータを端末に保存することに適しているのでメモアプリに向いているし、今までにも使ったことがあって慣れているので選びました。

## 制作していて感じたこと

#### アプリの使いやすさも考えて開発できた
初めてのアプリ開発ではシステムのほうに苦労していて使いやすさについてあまり考えられなかったのですが、今回のアプリは今までに勉強してきた知識で開発したのでシステムの制作に余裕があり、前回のアプリを開発したときよりもアプリの使いやすさに気を配りながら開発できました。

#### リリース準備に慣れた
初めてアプリをリリースしたときはリリース準備にかなり苦労しましたが、一度経験したことで手順が分かり、今回は苦労せずにリリース準備をすることができました。

## 今後の課題

#### アプリのダウンロード数を増やすこと
前回リリースしたアプリも今回リリースしたアプリもダウンロード数が全く増えていません。個人開発でダウンロード数を増やすことはかなり難しいことで大きな課題だと感じました。これを解決するために、今後はSNSでの宣伝やASO対策、事前のマーケット調査にも力を入れようと考えています。

# おわりに
2回目のリリースは全体的に手際よく進めることができて自分でも成長を感じました。今後はアプリ開発の勉強だけでなく、アプリのダウンロード数を増やすためにASO対策やマーケティングの勉強もしてより良いアプリを作りたいです。

↓もし興味があればアプリをダウンロードしていただけると嬉しいです。

 <a href='https://play.google.com/store/apps/details?id=com.ruriboshi.hayamemo'>はやメモ:シンプルなメモ帳、ノート、メモアプリ</a>

最後までお読みいただきありがとうございました。
ESLintとPrettierを共存させる方法

## 前提
開発プロセスを効率化するためには、コードの整形ツールであるPrettierと、コードの品質を保つためのリンターツールであるESLintの共存が有効です。これらのツールは異なる役割を担っています。具体的には、ESLintはコードの品質を保つために、Prettierはコードの整形を行うために使用されます。以下の設定方法を用いることで、ファイルを保存する際にどちらのツールも効果的に利用できます。

## ESLintとは？
ESLintは、コードの品質を保つための静的解析ツールです。コードに潜む問題点やバグを早期に見つけ出し、統一されたコードスタイルを維持することができます。これにより、コードの読みやすさと保守性が向上します。

## Prettierとは？
Prettierは、コードの整形ツールです。コードを一貫したスタイルでフォーマットし、読みやすく整理されたコードベースを維持することができます。これは、チームでのコラボレーションをスムーズにし、コードの品質を向上させます。

## 設定方法
- ESLintはNext.jsの推奨設定とします。
- "next/core-web-vitals"はNext.jsの基本的なESLint設定を拡張し、
より厳密なCore Web Vitalsに関連する追加のルールを提供します。
- "prettier"を追加することによってESLintとPrettierを共存させます。
これにより、ESLintがPrettierのフォーマットルールを尊重します。

    ```.eslintrc.json
    {
      "extends": ["next", "next/core-web-vitals", "prettier"]
    }
    ```

- Prettierはシングルクォートを使用し、セミコロンを省略するスタイルを適用します。
    ```.prettierrc
    {
      "singleQuote": true,
      "semi": false
    }
    ```

- ESLintとPrettierの拡張機能を推奨します。
    ```.vscode/extensions.json
    {
      "recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"]
    }
    ```

- 保存時にESLintとPrettierを自動的に実行するように設定します。
- "editor.defaultFormatter"は、デフォルトのフォーマッターとしてPrettierを指定します。
- "editor.codeActionsOnSave"は、保存時にESLintの修正を自動的に適用します。

    ```.vscode/settings.json
    {
      "editor.defaultFormatter": "esbenp.prettier-vscode",
      "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true
      },
      "editor.formatOnSave": true
    }
    ```

自らの備忘録のために投稿してますが、なにかお役に立てましたら幸いです！:clap:
また、なにか間違ってましたらご指摘いただけますと幸いです！:pray:
Google Cloud Marketplaceに出品/提供するのは難しい

1億円稼がないと出品できない

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/35713b52-0f6a-e9b7-d4da-be3b094b4c64.png)


https://ops.jig-saw.com/tech-cate/google-cloud-marketplace

https://cloud.google.com/marketplace/docs/partners/get-started?hl=ja#requirements
PLATEAUのモデルを出力する

# やりたいこと
- PLATEAU SDKで取り込んだプロジェクトからAssetを~~FBX~~ OBJ形式で出力する
- ~~出力したFBXを取り込んだプロジェクトを作成し、ZapWorks SDK経由でマーカー上にオブジェクトを表示するWebARを作る~~
　→ こちらは別記事で実施

# 環境
OS: Windows 11
Unity Version: 2021.3 LTS

# PLATEAU SDKでのモデルExport
- エクスポートの手順は[公式ドキュメント](https://project-plateau.github.io/PLATEAU-SDK-for-Unity/manual/ExportCityModels.html)に記載の通り
- モデル取り込み済みのプロジェクトをUnityで開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/069e42bb-ddca-d061-878c-f3a8f71a273a.png)
- UnityプロジェクトメニューのPLATEAU > PLATEAU SDKを開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/08e410ff-9c8c-b46e-cf51-a06401f9749e.png)
- PLATEAU SDKのサブウィンドウでエクスポートを選択する
- 選択オブジェクトでモデルを選択、出力形式をFBXとする
- Optionとして、~~FBXフォーマットはBinary~~、テクスチャをチェック、座標変換をLocalとする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/e7245df2-0d28-499f-cfe6-0ed5e10a2fe0.png)
- 出力フォルダを選択して エクスポート ボタンを押下する
(特に出力完了などのダイアログなどはなく、フォルダを確認すると出力が完了している)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573632/ab110bf2-4351-9574-8310-bb7918d3fac8.png)
Docker(コンテナ)の備忘録

Docker(コンテナ)を学習するとまず最初にvmwareのような仮想サーバとの違いが書かれている。
そこには「コンテナ型の場合はホストOSを共有するので、軽量・・・」のような事が記述がある。
そしていざ実践講座みたいなところを受けてみると、こんな状況があった。
ホストのサーバーはubuntuでcentOSのコンテナを作成する。
ホストOSの共有とは？
調べてみるとホストOSの共有→Linuxカーネルを共有と言うことらしい。
Linuxなどを元から知っている人てきにはホストOSを共有で伝わるらしいが、、
なので、ホストOS:ubuntu コンテナ：centOSが可能らしい。
ただ、ホスト名OS:ubuntu コンテナ:windowsは通常無理らしい
↑virtualboxなどを利用して、なんとかできるみたいな記事は見つけたがそれをコンテナでして意味があるのかはよくわからない
Docker(コンテナ)をちゃんと理解しようとすると、Linuxをある程度知らないといけないみたいです。