OmniAICreator/Qiita-1.07M huggingface dataset:
データベースの種類【個人的なお勉強アウトプット】

以下4つある

- 階層型
- ネットワーク型
- リレーショナル型
- NoSQL

それぞれメリットデメリットがある


## 階層型
ひとつのノードから下に複数のノードが派生し、ツリー状に展開していく
検索時に特定のノードへのルートが限定的になるため速度が早くなる。
ただし、データの重複が多くなる

## ネットワーク型
ひとつの子ノードが複数の親ノードを持つことができる。
階層型の重複を避けられる。
データ構造が複雑になるので、データの扱いが大変になる


## リレーショナル型
列と行のテーブルで構成されているデータベース。
柔軟なデータの取り扱いが可能になる。
ただしデータが膨大になると重くなったり、スケールアップするとデータベース設計を見直さないといけない

## NoSQL
リレーショナル・データベースのSQLが使えないデータベース
いくつかタイプがある

### キーバリュー型
キーとバリューだけのシンプルなデータモデル。
リレーショナル型と違い、キーとバリューに型が定義されていないので格納する値の自由度が高い。
さらに、データを永続化するか、揮発性かの2つのタイプに分かれる。
永続化は安全に蓄積、保管することでオリジナルのデータを保持して参照、更新の処理に利用する

発揮性は停止するとデータが消える。メモリー上にデータをキャッシュして利用する。
商品マスタなどのコピーを配置して、商品データ取得のような高頻度で軽量な参照処理を担当するなどのつかいかたがある


### ワイドカラム型
ひとつのKeyに対して複数のバリューをもたせることができる

### ドキュメント型
JSONやXML，PDFなどのドキュメントを格納できるデータモデル。

### グラフ型
ノード、リレーションシップ、プロパティの3つの要素で構成されるデータモデル。
ノードは社員A,リレーションシップは社員Aと同僚、友人、家族などの関係性を示すもの、プロパティは社員Aの年齢や出身地などの属性情報

### NoSQLのメリット
データの一貫性を保証しないため、処理速度が早い。
また、サーバーの台数を増やして水平分散によるスケールアップが可能。

## 参考サイト
https://it-trend.jp/database/article/89-0066#:~:text=%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AB%E3%81%AF%E3%80%8C%E9%9A%8E%E5%B1%A4%E5%9E%8B,%E7%A8%AE%E9%A1%9E%E3%81%8C%E5%AD%98%E5%9C%A8%E3%81%97%E3%81%BE%E3%81%99%E3%80%82
https://xtech.nikkei.com/atcl/nxt/column/18/01601/073000012/
https://products.sint.co.jp/siob/blog/nosql#:~:text=NoSQL%E3%81%AE%E3%83%A1%E3%83%AA%E3%83%83%E3%83%88%E3%81%A8%E3%81%97%E3%81%A6%E3%80%81%E3%81%BE%E3%81%9A,%E3%81%AB%E3%81%8A%E3%81%84%E3%81%A6%E3%82%82%E5%84%AA%E3%82%8C%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82
Rails×Dockerを使ってアプリケーション作成時に「Error response from daemon: Ports are not available: listen tcp 0.0.0.0:3306: bind: Only one usage of each socket address (protocol/network address/port) is normally permitted.」が出た時の対策

タイトル通りですが、Rails×Dockerを使って

```
docker-compose run web rails new . --force --no-deps --database=mysql
```

を実行した際に

```
Error response from daemon: Ports are not available: listen tcp 0.0.0.0:3306:
bind: Only one usage of each socket address (protocol/network address/port) is normally permitted.
```

が起きてつまづいてしまったので備忘録としてつけておきます。

versionに関しては
```
ruby: 2.7.5
docker:20.10.12
```

# 解決策

deeplで翻訳してみる。
```
デーモンからのエラー応答。listen tcp 0.0.0.0:3306:
bind: 通常、各ソケットアドレス（プロトコル/ネットワークアドレス/ポート）は1回のみ使用可能です。
```

既にポートが使われている感じなので変更してみる。


```diff_docker:docker-compose.yml
version: '3'
services:
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: root
    ports:
-     - "3306:3306"
+     - "3307:3306"
    volumes:
      - ./tmp/db:/var/lib/mysql
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db

```

docker-compose.ymlのports部分の左側3306を3307に変更すればいけました。
ちなみに右側はコンテナをを表しており、コンテナ間の通信は3306が使われているらしいので変更はしない方がいいかも。

もしかしたら起動している際にも他のコンテナ間でポートの干渉するのかな
今はDockerを動かしている個数が少ないのでいいけど、もし干渉するならいちいち変更するのはめんどくさい感じがする。

# 結果

```
Done in 96.00s.
Webpacker successfully installed 🎉 🍰
```
無事行けて安心した。

# ちなみに
余談ですがポートの干渉していた番号3306を調べてみると
"mysql.exe"でした。

このプロセスを削除するだけでも大丈夫な気がします。
SFTPは禁止して、SSHは許可する

## sshd_config編集

以下、CentOS 7 x86_64系が前提になります。

```
# override default of no subsystems
#以下、コメントアウト
#Subsystem sftp /usr/libexec/openssh/sftp-server
```

```
#sshd再起動
systemctl restart sshd
systemctl status sshd
```

```
# 今回は、FTPクライアントソフトでSFTPできないことを確認。
# 以下、エラーメッセージ
状態:Using username "Linux User". 
状態:Connected to ”IP or Host”
エラー:FATAL ERROR: Received unexpected end-of-file from SFTP server
エラー:サーバーに接続できません
エラー:FATAL ERROR: Remote side unexpectedly closed network connection
```

```
# SSHはできることを確認。
ssh -i "Pemファイル" "Linux User"@IP or Host
```

どうやら、以下の行で管理ができる模様。
時間が出来次第、仕組みを調べてみたい。
```
Subsystem sftp /usr/libexec/openssh/sftp-server
```

## 2022/03/27追記
コメントをいただき、以下追記です。
全く頭になかった発想、考え方でした。非常に参考になります。ありがとうございます。m(_ _)m（コメント欄参照）

-----

シェルが起動出来る時点で様々な事が出来るため、SFTPだけ禁止してもほとんど意味が無い。
それでも禁止したい場合、上記設定だけだと以下のようにすればSFTP出来てしまう。

```
## subsystemではなくexecでsftp-serverを起動するという方法
sftp -s /usr/libexec/openssh/sftp-server user@hostname
```

この方法はsftpのman pageにも「sshdでsftp subsystemが設定されていない時に使える」として書かれている。

なので、sftp-serverの読み込み権/実行権も落とす方がいい(もしくは削除する)

```
chmod 0 /usr/libexec/openssh/sftp-server
```

-----

## 参考

 * https://qiita.com/li-li-qiita/items/ebd5ef13c659195017bd
 * https://serverfault.com/questions/792956/sftp-cant-access-but-ssh-working-fine-when-i-changed-ssh-port
 * https://www.ibm.com/support/pages/sftp-client-begin-session-failed-connect-sftp-server-cannot-authenticate-error-sci99714

参考にさせていただきました。ありがとうございます。
シェルスクリプトの作成と実行方法

シェルスクリプトの基本的な書き方と実行方法をメモしておく。

# シェルスクリプトとは
**シェル**で解釈・実行される一連の処理（コマンド）を記述したスクリプトのこと。
シェルスクリプトで複雑な処理や繰り返し処理などをスクリプトとして書いておくことで、効率的にLinuxやUnixの操作を効率的に行うことができる。一般的に拡張子は、``.sh``を指定する。
今回は**bash**でのシェルスクリプトの作成と実行に関して基本的な部分をメモしておく。

# 基本的な書き方
**bash**のシェルスクリプトで簡単なサンプルとして、「Hello!」を出力させるものを書くと以下となる。

```shell:hello.sh
#!/usr/bin/bash
# bashを使用したシェルスクリプトであることを宣言

echo "Hello!"
```
ファイルを新規作成する際は``vi``コマンドを使って``viエディタ``を開くことができる。
```console
$ vi hello.sh
```
今回はほんとに基本的な部分だけたが、シェルスクリプトでは変数やfor文、if文なども記述することができる。

# 実行方法
以下のコマンドで実行することができる。

```console
$ bash hello.sh
$ ./hello.sh
```

```text:実行結果
Hello!
```
もし、上記で実行した場合にファイルの実行権限がないというエラーが出た場合は、以下のコマンドで実行権限を与えることができる。
```console
$ chmod 755 hello.sh
```
Axios で ApolloServer からデータ取得する

簡単な内容だが、備忘録。

## Apollo Server とは？
GraphQL サーバーを簡単に作れる技術。
簡単なデータの読み取りと書き込みは、

```javascript: index.ts
import {ApolloServer} from "apollo-server"
import {IResolvers} from "@graphql-tools/utils"

let hello = [ {text: "Hello world!"} ]

const typeDefs = gql`
  type Hello {
    text: String
  }
  type Query {
    hellos: [Hello!]!
  }
  type Mutation {
    addHello(text: String!): Hello!
  }
`

const resolvers: IResolvers = {
  Query: { 
    hellos: () => {
      return hello
    }
  },
  Mutation: {
    addHello: (root, args) => {
      const h = {text: args.text}
      hello = [...hello, h]
      return h
    }
  }
}

const server = new ApolloServer({
  typeDefs,
  resolvers
})

server.listen().then(({url}) => {
  console.log(`Server ready at ${url}`)
})
```

みたいな感じで、スキーマとリソルバを定義することで 作れる。

## Axios でデータ取得
上のサーバーから、Axios でのデータ取得は、

```javascript: index.js
import axios from "axios"

// データ取得
const result = axios({
  url: "http://localhost:4000/graphql",
  method: "POST",
  data: {
    query: `
    query {
      hellos {
        text
      }
    }
`
  }
})

result.then((r) => {console.log(r.data.data.hellos)})
```

Axios でのデータ書き込みは、

```javascript: index.js
import axios from "axios"

const result = axios({
  url: "http://localhost:4000/graphql",
  method: "POST",
  data: {
    query: `
      mutation addHello($text: String) {
        addHello(text: $text) {
          text
        }
      }
`,
    variables: {text: "hello"}
  }
})
```

と、query と query の $text に挿入される variables を定義することで、できる。
(DigitalOceanの)Ubuntu 20.04のexim4でSPFとDKIM

# SPF
DigitalOceanのダッシュボードからTXTレコードに以下を加える。
> v=spf1 ip4:[フローティングIPではなくドロップレットのIP] ~all

# テスト用ユーザ(必須ではない)
```bash
adduser user1
```

# Exim4のインストール
```bash
apt install exim4
cp -a /var/lib/exim4/config.autogenerated /var/lib/exim4/config.autogenerated.orig
dpkg-reconfigure exim4-config
```
> General type of mail configuration:
internet site

> System mail name:
[ドメイン名]

> IP-addresses to listen on for incoming SMTP connections:
<; [0.0.0.0]:587; [0.0.0.0]:25

> Other destinations for which mail is accepted: 
[ドメイン名]

> Domains to relay mail for:
(空欄)

> Machines to relay mail for:
(空欄)

> Keep number of DNS-queries minimal (Dial-on-Demand)?
No

> Delivery method for local mail:
mbox

> Delivery method for local mail:
No

> Root and postmaster mail recipient:
[外部のメールアドレス]

# DKIM
```bash
openssl genrsa -out /etc/exim4/dkim.private 1024
chown root:Debian-exim /etc/exim4/dkim.private
chmod 640 /etc/exim4/dkim.private
openssl rsa -in /etc/exim4/dkim.private -out /etc/exim4/dkim.public -pubout -outform PEM
vi /etc/exim4/exim4.conf.localmacros
```
> DKIM_SELECTOR=[yyyymmddなどの文字列]
DKIM_PRIVATE_KEY=/etc/exim4/dkim.private
DKIM_CANON=relaxed
DKIM_DOMAIN=[ドメイン名]

DigitalOceanのダッシュボードからTXTレコードに以下を加える。
> value: v=DKIM1; k=rsa; p=[dkim.publicの内容]
hostname: [yyyymmddなどの文字列]._domainkey
```bash
service exim4 reload
```

# 外部サービスでSPFとDKIMをチェック
https://dmarcian.com/spf-survey/
https://dmarcian.com/dkim-inspector/

# メモ: 設定ファイルの確認
``` bash
diff /var/lib/exim4/config.autogenerated.orig /var/lib/exim4/config.autogenerated
```
```diff
21a22,25
> DKIM_SELECTOR=[yyyymmddなどの文字列]
> DKIM_PRIVATE_KEY=/etc/exim4/dkim.private
> DKIM_CANON=relaxed
> DKIM_DOMAIN=[ドメイン名]
34c38
< MAIN_LOCAL_INTERFACES=<; 127.0.0.1 ; ::1
---
> MAIN_LOCAL_INTERFACES=<; [0.0.0.0]:587; [0.0.0.0]:25
61c65
< DC_eximconfig_configtype=local
---
> DC_eximconfig_configtype=internet
63,64c67,68
< .ifndef DCconfig_local
< DCconfig_local=1
---
> .ifndef DCconfig_internet
> DCconfig_internet=1
```

# テスト
## rootからuser1へ
```bash
mail user1
su - user1
mail
```

## user1から外部のメールアドレスへ
```bash
mail [外部のメールアドレス]
```
外部のメールアドレスで受信を確認

## 外部のメールアドレスからuser1へ
外部のメールアドレスからuser1へメールを送信後
```bash
mail
```

## user1からGmailのメールアドレスへ
```bash
mail [Gmailのメールアドレス]
```
Gmailのメールアドレスで受信を確認
GmailでははSPF、DKIMの設定が間違っていると拒否されやすい。
また、「メッセージのソースの表示」でSPF、DKIMがPASSしているか簡単に確認することができる。
Docker プライベートリジストリからイメージをプルする時、https　でないので怒られる時の対応策 (Ubuntu, mac)

## 概要
プライベートリジストリにdocker image を保存して、
チームや個人でもイメージをシェアしている例はいくつかあると思います。

そんな際に、例えばそのホストが 

```
xxx.xxx.xxx:5000
```
だったとします。
そこから　

```
docker pull xxx.xxx.xxx:5000/test
```

を用いてイメージをプルしようとした時、

```
Error response from daemon: Get https://xxx.xxx.xxx:5000/v2/: http: server gave HTTP response to HTTPS client
```

と言われたときの対処法です。


## 対応策(mac)

Mac OS ではタスクバーの鯨アイコンから Preferences > Daemon > Advanced を選択することで可能です。）
このjson形式の設定に
{
 “insecure-registries”:[“xxx.xxx.xxx:5000”]
}
この１行を追記した後、docker をリスタートすると、プルできるようになります。


# 対応策(Ubuntu)

```
$grep ExecStart /lib/systemd/system/docker.service
```

を実行してください。

```
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
```
と表示される場合、

```
$sudo vim /lib/systemd/system/docker.service
```

を実行し、

```
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry=/xxx.xxx.xxx:5000
```

となるように、
--insecure-registy 以下を追加してください。

この後、

```
$sudo systemctl daemon-reload
$sudo service docker stop
$sudo service docker start
```

を実行し、プルをもう一度試してみてください。
V字モデルについて

# V字モデルについて
## V字モデルとは?
V字モデルは、システム開発の開始から終了までの流れを表したモデルです。ウォーターフォールが上流から下流へ流れるようなモデルに対し、V字モデルは開発から後の作業を折り返したV字型をしています。V字モデルは、ウォータフォールの進化版とも言われています。

## V字モデルの特徴
- 要件定義の内容をシステムテストで確認
- 基本設計の内容を結合テストで確認
- 詳細設計の内容を単体テストで確認
この三つが主に挙げられます。

## 各工程で行った内容をリンクしたテスト工程で検証する
要件定義では、ユーザーからの要望をヒアリングし、業務要件や機能要件、非機能要件を洗い出して要件定義として定義します。システムテストでは、要件定義で定義された要件が、開発されたシステムで満たされているかを検証します。

テスト例
- 操作後の応答時間やバッチの処理時間など性能は十分か(性能テスト)
- 想定していた負荷に耐えられるか
- 障害から決められた時間内に復旧できるか
　
基本設計では、画面やレポートなどユーザーが目に見えるインターフェースの部分の設計を行います。そのため、結合テストではこれらのインターフェースが設計された通りに実装されているかを検証します。

結合テスト例
- 複数のモジュール間で正しくデータ連携ができているか
- 入力したデータに対し、想定通りの結果が出力されるか

詳細設計では、細分化された各機能の内部ロジックを設計します。成果物である詳細設計書を元に、プログラムが開発されます。よって単体テストでは、詳細設計で設計された内部ロジック通りに開発されているかを検証します。

## V字モデルを活用するメリット
- テスト内容を明確にできる
- 作業進捗がわかりやすい
- 後工程での手戻りのリスクを軽減できる

## まとめ
V字モデルはシステム開発の基本となる進め方であり、テスト内容が明確になり進捗管理しやすくなるというメリットがあります。
bashrcでPythonのバージョンを指定する方法

# はじめに
たまに使うので備忘録として残しておきます。

# bashrcとは
bashを起動したときに読み込まれる設定ファイルです。

https://tech-up.hatenablog.com/entry/2019/04/04/225638

# 方法

```
$ python -V
Python 3.7.3
```

```
$ sudo vim ~/.bashrc
```

bashrcを開いて、以下を追記します。

```md:bashrc
alias python=python3.8
```

以下のコマンドで設定を反映させます。

```
$ source ~/.bashrc
```

反映されているかどうか確認してみます。

```
$ python -V
Python 3.8.0
```

無事変更されました。
ドットインストールでCSS グリッドレイアウト編をやってみた

# ドットインストールCSS グリッドレイアウト編です
要点だけまとめてみたので、後で振り返り用としておきます

# グリッドレイアウトとは
マス目に要素を配置していくことで、複雑なレイアウトでも簡単に組むことが出来る
※グリッド = 格子状のこと

- 比較的新しい技術
    - ブラウザの対応状況は caniuse.com で調べられる

### グリッドの格子の設定
1. 列の幅を列挙
2. 行の幅を列挙
デフォルトだと左上から➜に流れるようにマス目が設定される。

#### `fraction(1fr)`
- 指定した後の残った余白を割り当てることができる
- `2fr`, `1fr` と割り当てると余った余白を2:1で割り当てることができる

#### `gap`
- グリッド間の余白を作成
- 列方向と行方向で別々の余白を設定したい場合、縦➜横(列間➜行間)の順に記述する

#### `repeat()`
- repeat(数, 幅)
- 数の部分を親要素の幅に入る限りと言った指定にしたい場合
    - `auto-fill`
        - ブラウザの幅に合わせて数が変化する

#### 好きな場所に配置する場合
- マス目の線と線が交わるところに配置する　といった指定をする
    - この線を「グリッドライン」と呼ぶ

#### グリッドラインに名前を付ける
- `target-start target-end` -> `target` に省略出来る

#### 要素がどこから並べられるかの操作
- `grid-auto-flow`
- `dense`
    - 余った余白部分に要素を詰められる
- 直感的に操作する
    - `grid-template-areas`
        - １文字ずつ指定すると分かりやすいか(色の頭文字など)
    - (.)で配置したくない場所を指定出来る
        - 配置する領域は四角になってないといけない
        - 飛び石になっていると全てが壊れてしまう

#### 領域内でのグリッドの設定
- グリッド全体を揃えるプロパティ
    - `justify-content` (列方向の揃え)
    - `align-content` (行方向の揃え)
- グリッド内で要素を揃えるプロパティ
    - `justify-items` (列方向の揃え)
    - `align-items` (行方向の揃え)
- グリッド内の個々のマス目に対して制御するプロパティ
    - `justify-self` (列方向の揃え)
    - `align-self`(行方向の揃え)
React で ReferenceError: Cannot access 'XXX' before initialization が発生する

# 現象

コンポーネント間で相互に参照しているような関係で発生します。
このエラーは React に限りません。

例えば以下の状況で発生します。

- `ComponentA.tsx`： `ComponentB.tsx` を表示
- `ComponentB.tsx`： `ComponentA.tsx` の定数を利用

```react:ComponentA.tsx
import React, { VFC } from 'react'
import ComponentB from '~/components/ComponentB'

export const widthA = 30

const ComponentA: VFC = () => {
  return (
    <>
      <div style={{ width: widthA }}>This is ComponentA.</div>
      <ComponentB />
    </>
  )
}

export default ComponentA
```

```react:ComponentB.tsx
import React, { VFC } from 'react'
import { widthA } from '~/components/ComponentA'

const widthB = widthA + 10

const ComponentB: VFC = () => {
  return <div style={{ width: widthB }}>This is ComponentB.</div>
}

export default ComponentB
```

# エラー

アプリケーションを実行するとエラーが発生します。

```javascript
Uncaught ReferenceError: Cannot access 'widthA' before initialization
```

このエラーについて調べると、[Mozila のページ](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Errors/Cant_access_lexical_declaration_before_init) では以下のように説明されています。

> JavaScript の例外 "can't access lexical declaration `variable' before initialization" は、変数が初期化前にアクセスされたときに発生します。
> これはブロック文内で、 let または const 宣言が定義される前にアクセスされたときに発生します。

どうやら変数が初期化される前に `widｔｈA` にアクセスしてしまっているようです。

# 原因

`widthA` が初期化される前にアクセスしていることが直接的な原因です。

では、なぜ `widthA` の初期化前にアクセスしてしまっているのでしょうか？
`widhtA` は `const widthA` 文で初期化されているのではないでしょうか？

今回の根本的な原因は、**ファイルを循環参照していること** です。

- `ComponentA.tsx` ↔ `ComponentB.tsx`

なぜこのエラーが発生するかを理解するには、 **JavaScript の Module の評価順序** を知る必要があります。
Module では、ファイルに `import` 文が書かれていた場合、 **そのファイルの評価を一旦止めて `import` 先のファイルを評価します。**
（リファレンスを調べきれなかったので若干推測が入っていますが、大きくは外していないはずです。修正依頼は大歓迎です。）

今回示したコード例では、以下の順序でコードを評価します。

1. `ComponentA.tsx` を1行目から評価
1. `ComponentA.tsx` の `import ComponentB from '~/components/ComponentB'` を評価
1. `ComponentB.tsx` を1行目から評価
1. `ComponentB.tsx` の `import { widthA } from '~/components/pages/ComponentA'` を評価
1. `ComponentA.tsx` の `widthA` 変数を探しに行くが、宣言されておらずエラー
  a. この時点では `ComponentA.tsx` の評価は2で止まっている
  b. `const widthA` 文が評価されておらず、そのような変数は存在していない

そのため、**変数初期化前にアクセスエラー** が発生します。

# 解決策

解決策としては循環参照を解消します。
1つの方法として、循環参照している箇所をファイルに切り出すことが有効です。

以下の例では新しく `const.ts` ファイルに定数を定義しています。
`widthA` を `baseWidth` として抽象化しています。

- `ComponentA.tsx` ← `const.ts` の方向に依存
- `ComponentB.tsx` ← `const.ts` の方向に依存

```typescript:const.ts
export const baseWidth = 30
```

```react:ComponentA.tsx
import React, { VFC } from 'react'
import ComponentB from '~/components/ComponentB'
import { baseWidth } from '~/consts/const'

const ComponentA: VFC = () => {
  return (
    <>
      <div style={{ width: baseWdith }}>This is ComponentA.</div>
      <ComponentB />
    </>
  )
}

export default ComponentA
```

```react:ComponentB.tsx
import React, { VFC } from 'react'
import { baseWidth } from '~/consts/const'

const widthB = baseWidth + 10

const ComponentB: VFC = () => {
  return <div style={{ width: widthB }}>This is ComponentB.</div>
}

export default ComponentB
```

これで循環参照はなくなり、エラーが解決されました。

# 最後に
循環参照はかなりやっかいな問題ですが、銀の弾丸のような対処法はないと感じます。
スケーラブルなディレクトリ構成を決め、依存関係を明確にすることが設計の1つとして重要になります。
【個人開発】ドキュメントサイトをVuePressとAWS Amplifyを使って簡単構築！

# 概要
今回は個人開発したWebアプリケーションの使い方を説明するためのドキュメントサイトについてご紹介していきます。
簡単に説明すると、GithubとAWS Amplifyを連携させることでVuePressで構築したアプリケーションを自動でビルドして静的なWebサイトとして公開するような仕組みが簡単にできます。

# 利用した技術やサービス
## VuePress
[VuePress](https://vuepress.vuejs.org/)はVue.jsを使って作られており、Markdownの中でVueコンポーネントが使えるように拡張されています。
また、見やすくレスポンシブなドキュメントがMarkdownを書くだけで作成できます。

## AWS Amplify
[AWS Amplify](https://aws.amazon.com/jp/amplify/)は、モバイルアプリケーションやWebアプリケーションを安全に構築するためのプラットホームになります。
Gitベースのワークフローを備えた静的ウェブサイトと単一ページのウェブアプリケーションを、レポジトリと単純に接続するだけでホスティングできます。

# 構築方法
[Amplify を使ってみる / VuePress を使った静的サイトをホスティング](https://www.northdetail.co.jp/blog/766/)を参考にしたらできました。
大事なところですが、こちらがそのまま参考になるので割愛しています。（笑）

# 何のためのドキュメントサイト？
WEBアプリケーションを一生懸命頑張って作成して公開したのに「あれっ？」思いのほか利用されていないってことありませんか？  
理由はいくつかあるかもしれませんが、そのうちの一つに使い方がわからない、というものがあります。
開発者はもちろん仕様を理解していると思いますが、初めてそのサイトに訪れたユーザーはシステムの目的や使い方なんて分からないことを前提とする方が良いと思います。

# ドキュメントサイトに求める要件
今回私は以下の要件を定めました。

- 構築コストを抑える
    - 目安1人日程度でコンテンツ含めて用意する
- 運用コストを抑える
    - Markdownで書けるようにしたい
    - インフラ維持コストとメンテナンスコストを抑えたい
- サービスで利用しているドメインのサブドメインを使う
    - Route53でドメインを取得しているのでAWSサービスだと設定が楽。


# 実際にVuePressとAmplifyでドキュメントサイトを作ってみて

## 実際のサイト

https://docs.cloudool.com/

[Cloudool](https://cloudool.com/)というクラウド伝票・業務管理システムの使い方についてのガイドサイトになります。

## 構築
ローカル環境やGithubとAmplify連携などの構築はほぼ手順通りで1時間もかかりませんでした。

## 運用
内容はシステムの修正に合わせて都度修正していますが、Markdownや画像の差し替えで済んでいるので比較的楽です。VuePress自体はまだ使い慣れていない部分はあるのですが、普通に使う分にはドキュメントや記事も比較的多いので学習コストはかなり低いです。
また、インフラ側について自分の方でサーバーのメンテナンスは不要です。
サーバレスのいいところですね(笑)

## 費用
気になる費用面について、詳細は[公式](https://aws.amazon.com/jp/amplify/pricing/)を見てほしいのですが。私は無料枠ではないですが、今の利用状況だと見込みで考えても100円/月いかないのかなー？という感じですね。
![スクリーンショット 2022-03-14 15.07.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290840/db79498f-9581-ab90-c900-fb50a248776d.png)

# さいごに
VuePressもAWS Amplifyも初めて利用しましたが、大きなつまづきはなく構築できました。
運用もしやすいので、個人開発などでドキュメントを公開したい場合には特に便利な気がしています。
はじめてのイーサリアムとスマートコントラクト

スマートコントラクトが頭だけで考えても言語化するのが困難だったので、手を動かしてみた。

# 1, 自分のマシンにWSL（Ubuntu 20.04）上に ethereum , geth インストール

こんなん、apt-get で一発。

https://github.com/ethereum/go-ethereum

# 2, とりあえずローカルでチェーン動かす

初期化設定して、コマンド実行

https://github.com/ethereum/go-ethereum

# 3, マイニングし、送金とか試す

https://book.ethereum-jp.net/first_use/mining_ether

# 4, ”スマートコントラクト”作って”NFT”をミントしてみる

いろいろ準備必要、

デプロイ先は、Ethereum のテストネット、作ったら、１つNFTをミントとして、これまたテストネットに対応しているOpensea に

1. Metamaks インストール
1. Metamask のネットワークを、Rinkeby テストネットに変更
1. 蛇口（Faucets）から 自分の Metamask に eth 送金
    1. https://faucets.chain.link/rinkeby 使った
1. OepenZeppelin で ERC-721 で NFT用 スマコンコード作成
1. Remix でスマコンを Rinkeby テストネットへデプロイ
1. そのスマコンで、とりあえずミント
1. スマコンアドレスを Opensea のテストネットへ登録

![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75458/f99fda1d-ba50-60e5-8a38-6f7c7c33f8e9.png)

とりあえずテストネットでの勝手はわかったので、次回は自分のアートでNFT作ってみるか。

# 参考
https://zenn.dev/taijusanagi/articles/b412568ace38fd
【Github Actions】本番環境だけコンフリクトが起こる

# はじめに
某プログラミングスクールで作成した、ポートフォリオを改善しようとした際に躓いたので備忘録。
デプロイのおさらいも書いています。
スクール卒業後で、メンターに質問できずに困っている初学者に参考になれば幸いです。


また間違っているところがあればご教授お願いします。


# 環境
Ruby 2.6.3
Rails 5.2.6
本番環境 Nginx／Puma／Linux2／AWS EC2／MySQL


# エラーの状況
railsアプリをGithub ActionsでCI/CD設定し、デプロイ済み。
修正したい箇所があったので、
topicブランチで修正→developブランチにmerge&push→mainブランチにmerge&pushは問題なく成功している。

が、Github Actionsの画面で確認すると以下のエラーが生じている。

```
Run echo "$PRIVATE_KEY" > private_key && chmod 600 private_key
Warning: Permanently added '***' (ECDSA) to the list of known hosts.
error: Pulling is not possible because you have unmerged files.
hint: Fix them up in the work tree, and then use 'git add/rm <file>'
hint: as appropriate to mark resolution and make a commit.
fatal: Exiting because of an unresolved conflict.
Error: Process completed with exit code 128.
```

# 解決策
### ec2上のアプリディレクトリを削除してデプロイし直す。
(cloud9上ではコンフリクトが起きていないので、ec2上のものとコンフリクトが起きていると推測しました)
### 【手順】
1. ec2にログイン
1. アプリディレクトリを削除
1. cloneしてアプリを再度ec2へ配置
1. サーバー起動の準備
1. サーバー起動


## 【手順1】ec2にログイン
sshでログインします。
```:cloud9
$ ssh -i ~/.ssh/キーペア名.pem ec2-user@パブリック IPv4 アドレス
```
## 【手順2】アプリディレクトリを削除
```:ec2
$ rm -rvf ディレクトリ名
```

__オプション解説__
- __-r, -R__
ディレクトリも削除の対象とする
- __-v__
削除の詳細表示
- __-f, --force__
エラーメッセージを表示しない
## 【手順3】cloneしてアプリを再度ec2へ配置
ホームディレクトリにいるか確認してから配置しましょう
```:ec2
[ec2-user@ip-xx-xx-xx-xx ~]$ cd
[ec2-user@ip-xx-xx-xx-xx ~]$ git clone GitHubのリポジトリのURL
```
## 【手順4】サーバー起動の準備
cloud9から"config/master.key"と".envファイル"をEC2君に送ってあげましょう。
```:cloud9
username:~/environment/アプリケーション名 $ scp -i ~/.ssh/practice-aws.pem config/master.key ec2-user@IPアドレス:GitHubのリポジトリ名/config
username:~/environment/アプリケーション名 $ scp -i ~/.ssh/practice-aws.pem .env ec2-user@IPアドレス:GitHubのリポジトリ名/
```

次はec2でbundleやmigrationを設定してあげましょう。
```:ec2
[ec2-user@ip-xx-xx-xx-xx ~]$ cd アプリケーション名
[ec2-user@ip-xx-xx-xx-xx アプリケーション名]$ bundle install --path vendor/bundle --without test development
[ec2-user@ip-xx-xx-xx-xx アプリケーション名]$ bundle exec rails assets:precompile RAILS_ENV=production
[ec2-user@ip-xx-xx-xx-xx アプリケーション名]$ bundle exec rails db:migrate RAILS_ENV=production
```
seedにデータを書いている人はこれも↓
```
[ec2-user@ip-xx-xx-xx-xx アプリケーション名]$ bundle exec rails db:seed RAILS_ENV=production
```
## 【手順5】サーバー起動
念の為
nginxをrestartしてあげて、起動してやります。
```:ec2
[ec2-user@ip-xx-xx-xx-xx アプリケーション名]$ sudo systemctl restart nginx
[ec2-user@ip-xx-xx-xx-xx アプリケーション名]$ rails s -e production
```

___
これで再デプロイが完了できました!
以降はCI/CDで設定しているトリガー(一般的にmainにpushする)で運用できます!!!
営業職からエンジニアに転職して思うこと

# 想定読者
- エンジニアってなんか良さそうだけど実際どうなの？と思っている人
- エンジニア転職を目指して勉強している人
- 未経験からエンジニアに転職するのが不安な人

# 自己紹介
- 新卒で営業職(約3年)
- 未経験からエンジニアになり1年半ほど
- サーバーサイドや機械学習の案件に参加
- インターン生の面倒をみたり、採用活動にも携わり始めた

未経験からエンジニアに転職した中で、当初持っていたイメージと違うところ、ドンピシャ一致していたところ、色々ありました。

これからエンジニアを目指そうとしている方にとって、自分の経験が少しでもプラスになれば幸いです。
入社した会社や、参加した案件によってもかなり状況は違うとは思うので、あくまで一意見として参考にしていただければと思います。

# エンジニアの良いところ
### ①自己成長を感じやすい
自分の知識が確実に積み上がっていくというのは、間違いなく一つのモチベーションになります。
１ヶ月前までは意味がわからない呪文だと思っていたものが、自分で書けるようになっていく。
自分が成長している実感というのは、やはり嬉しいものです。

営業などの他の仕事でも、もちろんそういうタイミングもありますが、エンジニアでは、より短時間で明確に成長を感じやすいです。

### ②どこでも仕事ができる
場所を問わずに仕事ができるのは大きな魅力の一つだと思います。

弊社のエンジニアでも、子供が小さいので家で仕事をしている人や、弊社の社員でも、家族の仕事の関係でベトナムからリモート勤務をしている人もいます。

人生のステージの変化や、不測の事態が起きたとしても、基本的に仕事が継続できるであろうと考えられるのは、精神的にも余裕があります。

また、
・服装がなんでもいい
・外を出歩かないので暑さや寒さの影響を受けない
というのも、営業をやっていた頃と比べて、非常にありがたいなぁと日々感じております。
### ③仕事がたくさんある
エンジニアという職業が、需要に対して供給不足であるということも魅力の一つです。
政府の試算によると、2030年には約79万人もの人材が不足するといわれています。（[参考](https://www.meti.go.jp/policy/it_policy/jinzai/houkokusyo.pdf)）
需要よりも供給が少ないということは、自分の市場価値を高めやすく、給与などの条件面でも良くしやすいということです。

もちろん、しっかりと技術力を身につけていればという前提ではありますが、露頭に迷ってどうしようもない、、という状況にはなりづらいでしょう。

# エンジニアの大変なところ
### ①勉強しないといけない
ほとんどこれに尽きるかなと思います。

これを「苦」と感じるか、「やりがい」と感じるか。
幸いにも私は、昔から学ぶことに対して、苦にならないタイプだったので、エンジニアという職には非常に向いていたなと感じます。

業務に慣れてくれば、それほど勉強をしなくてもこなせるようにもなってきますが、
周りから評価されるような、クライアントに満足してもらえるような仕事をするためには、
**学び続けていくのは必要不可欠**です。

というのも、技術的な入れ替わりが非常に早い業界なので、最新の技術をキャッチアップしていく必要が常に出てきます。

### ②意外とコミュニケーション力が必要
エンジニアの仕事は思った以上にコミュニケーションが求められます。

仕事の時間のほとんどをコードを書いているというイメージでしたが、
実際には仕様の打ち合わせや、メンバーのスタンス合わせなど、コードを書いていない時間の方が多いくらいです。

**「クライアントの意図をしっかりと汲み取る」** ことができず、
１週間かけて書いたコードがすっかり無駄になってしまった。。
ということが起こたこともあリました。

「コミュニケーションが苦手だから、」
という理由でエンジニアになった人は苦労するかなと思います。

# エンジニアに向いている(と思う)人
### ①勉強が好きな人
これがないと、かなり苦痛だと思います。正直に言ってエンジニアになることはオススメしません。

特に未経験から転職をするとなると、
「ベースとなる知識」と「業務で必要な分野」を両方キャッチアップしなければなりません。

多少慣れてきたとしても、新しい案件に入るたびに、また新しい機能を実装するたびに、新しい技術と出会うというのが日常茶飯事です。技術の流行り廃りが早い業界なので、ここまでやればOKということがありません。

「学ぶこと」を楽しめるかどうかでエンジニアライフが180度変わってきます。

### ②論理思考力がある人
実現したいものから、仮説を立てて実行する。
結果からどこまでは合っていて、どこからが間違っていたのかを判断する。
そこから再度、仮説を立てて実行する。
このトライアンドエラーをするスピードが速い人が、成長するスピードも速く、エンジニアに向いている人だと思います。

### ③コミュニケーション力がある人
**営業職から転職をするときの、一番のストロングポイント** はここになります！

未経験から転職をすると、確かに技術力的にはかなりのビハインドになりますが、
エンジニアの人がどうにも伸ばしづらい能力である「コミュニケーション能力」があれば、
**将来的に非常に重宝される人材**になれます！

IT業界において「コミュ力がある人」は「技術力はあるけれどコミュ力がない人」よりも希少価値が高いので、
技術力が多少足りなくても、チームの中で重宝される存在になることができます。

弊社でもコミュニケーションが取りやすいという理由で、継続的に仕事をいただけたこともあります。

そういった意味で、**営業職からのエンジニア転職は個人的に凄くオススメです！**

※弊社社員の営業出身者も賛同してくれました！(「営業時代に契約書周りに慣れていたことは結構役立ってます」とのことです)

# 最後に
自分の主観ではありますが、エンジニアという職業に対して感じていることをまとめてみました。

**他業界・他職種からの転職を目指している人に、エンジニア転職の良さ**
が少しでも伝わってくれていれば幸いです。

弊社社員のほとんどは、未経験からエンジニアに転職したメンバーですが、
先輩社員と共に開発業務にアサインしながら一人前のエンジニアになっていっています！
絶賛採用中ですので、ご興味ある方は[こちら](https://www.recruit.nuco.co.jp/)より。
logrotateはどうやって動いているのか

## 環境
Ubuntu20.4

## 記事
**rsyslog**サービスが起動していれば、**/var/log**の中に**syslog**が作られているはずです。サービスの起動を確認するコマンドは**service --status-all | grep rsyslog**。このコマンドを実行して、**[ + ]  rsyslog**と表示されていれば、起動されています。

サービスに関する詳細な情報も表示させたい場合は、**systemctl status rsyslog**でも確認ができる。**syslog**が作られる場所は、デフォルトで、**ls -l /var/log/syslog**となっている。


**rsyslog**に関する情報が記載されているファイルは、基本的に、**/etc/syslog.conf**であるが、**syslog**ファイルの出力先のパスが記載されているファイルは、ここではなく、**/etc/rsyslog.d/50-default.conf**に書かれている。

中身を見てみると、***.*;auth,authpriv.none          -/var/log/syslog**の行がある。ここのパスを変更すれば、**syslog**の出力先を変更することができる。設定の左側をセレクタといい、出力するログの種類が設定できる。基本的にデフォルトのままで問題ない。

**ls -l /var/log/syslog[2-9].gz**をすると、**syslog**のバックアップローテーションが動いていることが確認できる。ローテーションを作成しているプログラムは、**rsyslog**ではなく、**logrotate**という別プログラムが動いている。**logrotate**はデーモンとして常駐して動くタイプのプログラムではなく、ワンショットで１回動いて終わるタイプ。

その設定を確認してみる。**systemctl cat logrotate.service**で**logrotate**のユニットファイルの中身を見てみると、**Type=oneshot**となっている。そして、**ExecStart=/usr/sbin/logrotate /etc/logrotate.conf**の記述がある。**logrotate.service**から、**/usr/sbin/logrotate**を動かしていることが分かる。**/etc/logrotate.conf**は引き渡すパラメータ。ユニットファイルの名前と、実際に動かすサービス名が同じ場合、**systemctl cat logrotate.service**は、拡張子を省略して、**systemctl cat logrotate**だけでもOKとなる。大抵の場合、同じになっているはず。

そして、**logrotate.service**は、**logrotate.timer**からキックされる。**systemctl cat logrotate.timer**で中身を参照してみると、**OnCalendar=daily**の記載がある。つまり、ログローテーションは毎日実行されているということだ。実際に、**ls -l /var/log/syslog[2-9].gz**で表示されるバックアップのアーカイブファイルの更新日付は、１日単位になっていることが確認できる。

そして更に、**logrotate.timer**をキックしているが、**timers.taget**で、**timers.taget**をキックしているんのが、サービスの大元である**systemd**に行き着く。
エクセルで複数行のデータを区切り文字をつけて1行にまとめる方法

## メモ
備忘録として、以下に記録。
ググってもなかなかヒットしない謎。

## 結論
```
TEXTJOIN("', '", TRUE, {範囲})
```

## 例

### エクセル

| ◢ |  A  |
| ---- | ---- |
|  1  |  りんご  |
|  2  |  トマト  |
|  3  |  バナナ  |

### 関数
```
TEXTJOIN("', '", TRUE, A1:A3)
```

### 結果
```
りんご, トマト, バナナ
```
Pythonのおすすめの環境構築の方法書く(2022/03)

# Pythonのおすすめの環境構築の方法書く

## (また)環境構築することになった流れ
花粉が辛すぎてやばいです^^;
早く治ってくれないかな〜

さて、私は新学期が始まる頃になるとパソコンやらやらを初期化したくなる病気にかかっているのですが、今回もその症状が出てしまい初期化したので、開発環境を一から作り直すことになりました。

まあ色々作ってるからローカル環境汚れるのは仕方ない。。。
最初から環境作って綺麗にしましょという感じですね。

ということで今回はPythonの環境を作っていきます。
(毎年こういう記事書くことになりそう。。。)

## おすすめのPython環境
個人的には一番おすすめは[Anaconda + 仮想環境]です。
まあ定番ですね。

特に私は幅広く興味持って作ってより最適な環境を探すみたいな方法で開発しているので仮想環境は最強です。
結構しっかり環境を分けてくて仮想環境を消せば元通りなので。。。

ということで今回はAnacondaとAnacondaの仮想環境を使って開発できるようにしていきましょう！

## Macの環境
プロセッサだったりOSだったりの情報は以下です。
### ハード情報
![環境.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512282/2ff86778-97d4-006e-9a1f-83ba6ed993f5.png)
- MacBook Pro(2018年モデル)
- Intel プロセッサ

### ソフト情報
- MacOS Monterey
- シェルはzsh
- ほぼ初期化した状態でChromeやらだけ入れた

## Anaconda インストール
まずはAnacondaが無いといけないのでダウンロードしてきます。

私は普通に[公式サイトのダウンロードページ](https://www.anaconda.com/products/individual)から最新のをダウンロードしてきますが、過去のバージョンがいいという方は[こちら](https://repo.anaconda.com/archive/)のリンクから恐らく全ての過去バージョンAnacondaをダウンロードできますのでお好きなものをダウンロードしてきてください。

pkgファイルを開いて全て次へでも問題ありません。
好みがあれば適宜変えてください。
私はそのまま次へで問題ないことを知っているので次へを押しましたが、Windowsへのインストールならpathを通すかとか聞かれたかな？

その場合、他に使っているPythonがあるなら通さずにないなら通すでいいと思います。

![conda-version.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512282/4b72d5d6-6028-a656-dc12-66ba0acbe979.png)
```zsh:zsh
anaconda --version
```
と入力してバージョンが表示されたら成功です！

## 仮想環境を作成
仮想環境の作り方なんていくらでも情報あるのですが、、、インストールもそうですね。。。

一応書いていきます！

よく使うコマンド一覧とか載っけてもいいんですけど結局それもネットにあるしね。。。
問題が発生したらコメント書いていただければお力添えできるかもです。。。

さて、仮想環境を作るには
```zsh:zsh
conda create -n TEST python=3.10
```
このコマンドを入力します。

```zsh:zsh
conda create -n ["仮想環境名"] python=["バージョン"]
```
の形式で作成できます。
結構シンプルでいいですね。

![conda-v-n.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512282/54a3581f-b90b-32c0-ed88-4ef06d559250.png)
するとこんな画面になるので``y``を押してインストールします。

数秒で完了しますので、次は仮想環境に入りましょう！

![conda-act.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512282/34d3ff77-8743-2a90-9bab-eadf42657b34.png)
このように
```zsh:zsh
conda activate ["仮想環境名"]
```
と入力すると先頭の``(base)``が``(TEST)``に変わり、仮想環境に入れたことがわかります。
(その上の入力は「これでは入れないから気をつけてねという例です。間違えてません;;」)

この環境で``pip3 install ["何か"]``をしてもbaseの環境には影響せずTESTの環境にのみ影響があります。

```zsh:zsh
conda deactivate
```
で仮想環境から抜けられるのでこれも覚えておきましょう。

ちなみに削除は
```zsh:zsh
conda remove -n ["仮想環境名"] --all
```
です！
よく忘れるのでメモしておきます。

## おわりに
基本的なことしかやっていませんがいかがでしたでしょうか。
特に問題が起きそうな部分は無いと思いますが何かあればコメントしていただければ答えられるかもしれません！

それでは
Java with MavenのGithub Actionを動かしてみる

Mavenを利用したJavaのCIをGithub Actionで試してみました。

# Mavanインストール
記事を参考にMavenをインストールする。

https://qiita.com/Junichi_M_/items/20daee936cd0c03c3115

# Javaプロジェクトを作成
mvnコマンドでJavaプロジェクトを作成する。

https://qiita.com/hide/items/6593f3f02c3f28e57f2d

今回はGithubリポジトリを`java-test`で作成したので、`-DartifactId=java-test`とした。

```
mvn archetype:generate -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false -DgroupId=com.sample -DartifactId=java-test
```

# pom.xmlの追記

デフォルトのpom.xmlだとビルドエラーが発生する。

```
Error:  Source option 5 is no longer supported. Use 6 or later.
Error:  Target option 1.5 is no longer supported. Use 1.6 or later.
```

以下をpom.xmlに追記する。

```diff:pom.xml
+  <properties>
+    <maven.compiler.source>1.6</maven.compiler.source>
+    <maven.compiler.target>1.6</maven.compiler.target>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
```

# workflow作成
今回はGithub Actionの`Java with Maven`をそのまま利用した。

```yaml:maven.yml
# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven

name: Java CI with Maven

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - name: Set up JDK 11
      uses: actions/setup-java@v2
      with:
        java-version: '11'
        distribution: 'temurin'
        cache: maven
    - name: Build with Maven
      run: mvn -B package --file pom.xml
```

# .gitignoreの追加
Githubの例をそのまま利用した。

https://github.com/github/gitignore/blob/main/Java.gitignore

# 結果
CIできました！！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502127/28258219-fe5b-1b35-1bda-133e73f0602a.png)
【SQL】データベースを修正(ALTER)したり削除(DROP)したりする

![sincerely-media-XihOO7UOvy4-unsplash.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530779/e9327cab-4023-105e-30dd-5dc771cd3d21.jpeg)Photo by Sincerely Media on Unsplash

エンジニアに志望のTERRAです。
Web制作っぽいことをやっていたのですが、SQLについては本一冊読んだり動画見たりしてなるほど？程度の知識です。今なぜかFastAPIをいじることになっているのですがDBがさっぱりわかりません。

Web開発においてデータベース（以下DB）を扱えないのはダメだということを散々聞くのでマイペースながら勉強しているところです。

## 学ぶこと
表題の通りDBの修正方法と削除方法を学びます。
実際に手を動かさないとなんもわからんということで前回に引き続き[Envader](https://envader.plus "Envader")でハンズオンしていこうと思います。

## DBの修正
ALTER DATABASEでDBの修正・変更・メンテナンスを行います。前提条件としてそのDBに対するALTER権限が必要です。
ALTER DATABASE DB名 option 変更する値 のように入力します。

```SQL
# 文字コードの変更
ALTER DATABASE DB名 CHARACTER SET 文字コード;
# DB名の変更
ALTER DATABASE DB名 RENAME TO 新DB名;
# 作成者（オーナー）の変更
ALTER DATABASE DB名 OWNER TO 新オーナー名;
```
変更はDBディレクトリの`db.opt`ファイルに格納されます。

## DBの削除
DROP DATABASEでDBの削除を行います。こちらも前提条件としてDBに対するDROP権限が必要となります。

```SQL
DROP DATABASE DB名;
```

:::note warn
このコマンドはすべてのテーブルを削除した後DBを削除します。
ユーザー権限は削除されません。
:::

存在しないDBを削除しようとするとエラーが出るので以下コマンドのほうがいいかもしれません。
```SQL
DROP DATABASE IF EXISTS DB名
```
DBが存在するときのみ削除します。

ここまでの作業は[Envaderの仮想環境内](https://envader.plus/course/2/scenario/1058/ex "データベースの修正と削除")で安全に行っています。

## まとめ
とりあえず一通り触ってみたので、ALTER DATABASEとDROP DATABASEはこれで大丈夫だと思います。
わかんなくなったらMySQLリファレンスマニュアル読んで復習しますｗ

## 参考資料
https://www.postgresql.jp/docs/9.2/sql-alterdatabase.html

https://www.dbonline.jp/mysql/database/index5.html

https://envader.plus/course

https://dev.mysql.com/doc/refman/5.6/ja/drop-database.html

### これまでのMySQLの学び
https://qiita.com/Terralien/items/a24d3b8aed0757388a7c
Map（Microsoft BingMaps API ）の基本を学ぶ。動画まとめ

### 自己紹介
ジーズアカデミー学校長 山崎と申します。
**「Microsoft BingMaps API 」** を授業用で数年前に録画してたものを公開します。
情報が少ないので少しでも役に立つのではと思います。

:::note info
クレジット登録が必要ないので学生が使うにも良いと思います
:::





## ◆動画集一覧


:::note warn
【サンプルコード】ダウンロードして動画で学んでください
https://github.com/yamazakidaisuke/bingmaps_sample
:::

 
| タイトル |  動画🔗 | 
| ---- | ---- |
| 「 BingMaps入門」始めるよ！ <br>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104530/2459080e-7527-8b2c-0127-519051462897.jpeg" width="400">  | https://youtu.be/4py0m6XLrnA | 
| 「 BingMaps API 準備編 ～KEY取得～」<br><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104530/8356ba2c-6625-2478-3610-e9ce055c5073.jpeg" width="400"> | https://youtu.be/7YyAyQ7lv4Q |
| 「 No.01（基本知識） 」<br> <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104530/5dd03672-d3cd-fb92-bc7c-a2d9de7f4af8.jpeg" width="400">| https://youtu.be/A-CmTUAi6bk | 
| 「 No.02（MAP表示の種類） 」<br><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104530/600096d9-e9e1-f8d7-5592-b3e79b4cc684.jpeg" width="400"> |  https://youtu.be/RAxB65z-ksA |
| 「 No.03（MAP表示をチェンジ） 」<br><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104530/e72cd62a-d7d3-5e3f-4d4d-6bad868fe861.jpeg" width="400">| https://youtu.be/Ybcz8R1tdbU | 
| 「 No.04（Map上のイベント取得方法） 」<br><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104530/00c13778-2f0a-bcb9-ed9c-d30de32cbb34.jpeg" width="400">| https://youtu.be/NoXdxgDUdZU |
| 「 No.05（Pushpin / PushpinText） 」<br><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104530/0c9520fb-48ed-69d1-99e0-a93cfa51f728.jpeg" width="400">| https://youtu.be/BS9SmYWvOIk |
| 「No.06（PushpinにClickイベントをつける）」<br><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104530/ccd40bea-83b5-afed-828e-ce9ddc3f2c0d.jpeg" width="400">| https://youtu.be/5Y8VcR_ZZe4 |
| 「 No.07（ Map上に吹き出し表示:infobox）」<br><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104530/eb7291be-5af9-c9d6-43cc-8620606978d6.jpeg" width="400">| https://youtu.be/AdA0lx5HGEs |
| 「 No.08（ Map & 現在地の連動表示 ）」<br><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104530/1768e014-c775-5958-3eae-6503e03ab38b.jpeg" width="400">| https://youtu.be/Kkqd0pRR0Oo |


## ◆BingMapsを簡単に使える「BmapQuery.js」
##### 👇「Webサイトで使えるMapAPI」1行でMap・ピン・テキストを表示」👇

| タイトル |  動画🔗 | 
| ---- | ---- |
| **「 基本編 」** <br><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104530/4bfb2696-d7a2-796f-0ede-96cf57526bba.jpeg" width="400">| https://youtu.be/S2fxrNSpXas |
| **「 応用編 」** <br><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104530/47555b11-4e8a-b59a-a4ba-245c96c1052d.jpeg" width="400">| https://youtu.be/XrSQWPNVeEg |




 
  
-----------

:::message
今後も講義動画増えたら、こちらを更新していきます。
ブックマークしていただければ幸いです。
:::


https://www.youtube.com/channel/UCmMFmjhf1BXB1tlLcbkVRrg
 
-----------
PHP ランダム文字列生成

ランダム文字列生成 (a~zの中で生成) 32桁 for文の数値変更すれば桁数変更できる
```php
$str = chr(mt_rand(97, 122));
        for($i = 1; $i < 32; $i++){
            $str .= chr(mt_rand(97, 122));
        }
```


ランダム文字列生成 (A~Zの中で生成)
```php
$str = chr(mt_rand(65, 90));
        for($i = 1; $i < 32; $i++){
            $str .= chr(mt_rand(65, 90));
        }
```

乱数生成
```php
rand()
rand(5,8) //5~8の間で生成
```
AWSトラブルシューティング AWS上でコンテナ起動時に「standard_init_linux.go: exec user process caused: exec format error」が発生

# 現象
* ECSでFargateを用いて自分で用意したコンテナを実行しようとしたところ、以下のエラーが発生しました。
```
standard_init_linux.go:228: exec user process caused: exec format error
```

# 原因
* 原因を調査したところ、ビルド環境とAWS Fargateでの実行環境とでCPUアーキテクチャが異なるため、でした。
* 最近、ビルド環境のマシンがM1Macになったため、ビルド環境のCPUアーキテクチャはarm、Fargate側はx86_64という状態。

# 対策
* ホストPC側でDockerビルドする際に、オプションでCPUアーキテクチャを指定する。
```
docker build --platform linux/amd64 .
```
*Dockerfile内で定義することもできそうです。
https://matsuand.github.io/docs.docker.jp.onthefly/engine/reference/builder/#from
Rstudioで日本語が文字化けするときの対処法

## 環境
OS: Windows 10 Pro (10.0.19043)
R: 4.1.2 (2021-11-01)
RStudio: 2021.09.0 Build351

## 手法
Tools→Global OptionsでCodeの「Saving」タブの中にある「Default text encoding」を**UTF-8**に変更する。
<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363491/57da81fc-a05c-f6d3-5467-18f66c6e0785.png">
※Windowsであれば変更前はShift-JISかCP932に設定されていることが多いと思います。
terminalのコマンドあれこれ

## 経緯
完全に自分の備忘録用です。知らないコマンドばかりで学ぶ日々です。

### 今いる階層のフォルダをFinderで開く
```terminal: terminal
$ open .
```

---
### terminalに表示されている内容を消す
```terminal: terminal
$ clear
```

---
### requestsのライブラリをpipのモジュールを使ってインストール
※-m はモジュールのことでpipがpythonのモジュールのことになる
```terminal: terminal
$ python3 -m pip install requests
```

---
### ディレクトリ削除

※py-test-directoryというディレクトリ(フォルダ)を削除する
```terminal: terminal
$ rm -rf py-test-directory
```

---


随時更新します
jsのmapのentryをイテレーション的な感じで処理したい

map内の要素をフィルタしたいときがあって調べました。

## 解決法

`Array.from()`でarrayを生成すると、mapの各要素(`entry`と呼ぶ)が以下のようにマッピングされるのでそれを利用する。

- key　-> entry[0]
- value　-> entry[1]

### サンプルコード

```js
const sampleMap = new Map();
sampleMap.set("id1", { name: "name1", hoge: "hoge1" });
sampleMap.set("id2", { name: "name2", hoge: "hoge2" });
sampleMap.set("id3", { name: "name3", hoge: "hoge3" });

const filteredList = Array.from(sampleMap)
  .filter((entry) => entry[1].name !== "name1")
  .map((entry) => ({
    id: entry[0],
    name: entry[1].name,
    hoge: entry[1].hoge
  }));

filteredList.forEach((e) => {
  console.log(e.id +' '+ e.name+' '+e.hoge);
});
// id2 name2 hoge2 
// id3 name3 hoge3
```
Scrum Inc.認定スクラムマスター(LSM)～Zoom開催の研修受講/合格/更新の流れ

Scrum Inc.認定スクラムマスター(LSM)をこれから受ける方の参考になればと思い、概要や流れをご紹介します。
:bow:ScrumAlliance認定スクラムマスター(CSM)との比較ではありません

# はじめに
【私の経歴と受験動機】
* 1995年にプログラミングに出会いソフトウェア開発の世界へ。
* 長年のSIer勤務を脱しプログラマを卒業後、現在は事業会社の社内SEの立場で要件定義に従事。
* 実務ではウォーターフォール開発経験しかなく、スクラムを良く知らなかった。
* 2021年3月、担当するレガシーシステムの将来的なアジャイル開発への転向に備え、役立てたいと思い取得。
* 2022年3月、失効期限が到来したため、更新。

# 認定スクラムマスター(LSM)とは
* 団体Scrum Inc.[^1]が主催するスクラム研修と認定資格。
(詳しくは:point_right:[セミナーSclumInc](https://scruminc.jp/training/):point_left:参照)
* セミナー受講資格の条件はなし（誰でも受講可）
* 2日間の研修を完了すると受験資格を得られ、オンラン受験後、認定証を与えられる
* 有効期限：1年
[^1]:Scrum IncはKDDI株式会社、株式会社永和システムマネジメントとScrum Inc.の3社の合弁会社


# 費用
* 受験費用：22万円（税抜価格20万円）/人
* 更新費用：$50(クレジットカード決済のみ)

# 申し込み
[セミナーSclumInc](https://scruminc.jp/training/)の通り、常に３ヵ月程先まで満席(キャンセル待ち)状態。(*2021年～2022年03月時点*)
:bulb:期間に余裕をもって申し込もう。

# 事前準備
* Scrum Inc.Japanセミナー事務局より、受講要項の案内メールが届く(約1週間前)
* ZoomミーティングID、スクラムガイドと用語集のテキストをダウンロードURLが記載されている
:bulb:テキストは事前に目を通そう

# 研修時間
9:00～17:00(昼休憩12:00～13:30)×2日間

# 研修内容
受講メンバーがスクラムチームを作りワークショップ形式で学ぶ
【座学】
　－ 事前配布のテキストに沿って、講師による講義を聞く
【ワークショップ】
　－ 各スクラムチームごとにブレークアウトルームに移動
　－ ワーク遂行はホワイトボードツールMiro[^miro]を利用し効率的に
　－ ワーク遂行はカメラONで活発にコミュニケーション
　－ QAはMiroに質問を記入する方式で、他のスクラムチームのMiroも閲覧可能で沢山質問できたのが良かった
　－ 受講終了時に受験要領が説明され、直ぐに受験が可能となる:clap:<br>
:bulb:デュアルモニターで1面に全員のカメラ、2面にMiroを表示すると便利
(タブレットとPCの2台で入室も可)
[^miro]:Miroは豊富なテンプレートと使い勝手の良いUIで、人気の高いオンラインホワイトボードツール

# 受験
受験期限：セミナー受講後30日以内
１．[ScrumLab](https://scrumlab.scruminc.com/login)にアカウントを作成
２．受験
　　　問題数：30問（択一選択問題、4つの選択肢のうち、正解を1つ選択）
　　　時間制限：なし
　　　合格ライン：23問/30問
　　　:exclamation:不合格の場合、1度だけ無料で再受験可、以降の再受験は$25/回
　　　:bulb:テキストを見ながらの回答OK
　　　:bulb:難易度は低い
　　　　　(講師の話では8割以上の方が1発合格、2回不合格になる方は0名に近いそう）
３．認定証の発行
:bulb:できるだけ記憶が新鮮なうちに受けよう！

# 更新
１．失効期限の1ヵ月前にメールがくる(英語）
２．[ScrumLab](https://scrumlab.scruminc.com/login)にログイン
３．「達成実績」メニューより更新の手続きに進み、クレジットカード番号を入力
４．決済完了すると、更新試験の開始
　　　問題数：12問（択一選択問題、4つの選択肢のうち、正解を1つ選択）
　　　時間制限：なし
　　　合格ライン：不明
　　　:exclamation:不合格の場合、$50/1回で再受験可
:bulb:メールを見逃さないようにしておこう！
(送信者メールアドレスのドメイン「@scruminc.com」で引っ掛けるとよい）

# 失効期限到来から失効まで
更新期限1ヵ月前のメールを無視して更新しないでおくとどうなるか追記します。// add 2023.03.28
「登録済みスクラムマスターの資格の有効期限が切れました。」というメールが送られてきます。(もちろん英語)
そのメールに続けて、下記のような記載があります。
「このメールからさらに60日間の執行猶予があり、期限内に更新すれば失効を免れることが出来る。
この60日執行猶予を過ぎてしまうと、再度資格を得るためには、高額な研修受講からのやり直しとなります。」
とのことです。

# で、結局・・・「スクラム」とは何か
顧客に価値をデリバリーするフレームワーク
1. 大きな仕事を小さく分解して、小さなチームで行う
2. 2倍の仕事を1/2の時間で行う
3. 短期間でアウトプットを顧客に届ける
:point_up:これによりアジリティの高い組織にする
:point_up:単なる開発手法の方法論ではない！
:point_up:ソフトウェア開発だけでなく、製造業を始めあらゆる業種、現場で実践可能

# 「スクラム」のメリット
* 顧客満足度(価値)の最大化
* プロセスの無駄を排除(シンプルさを最優先)
* プロセスの可視化、属人化解消
* 問題を明るみにして対処する
* メンバー個々が互いに尊重しあう
* メンバーの幸福指数を大切にする(＝スクラムでHappyに:heart_exclamation:）
・・・etc・・・

# 資格を取ってみた感想
* 私が参加したときのメンバーのスキルセットは、実務でスクラム開発を始めた方と経験がない方と半々だった。
* 初対面でもワーキングアグリーメントのおかげで心理的安全が確保され、意見発信が活発になり、オンラインコミュニケーションでも十分にチームが一体となって取り組み、2日間で親睦が深まった。
* アジャイル開発のみならず、ウォーターフォールの現場でも部分的に取り入れ可能で、業務効率改善、タスク管理可視化、属人化解消等に非常に役立つスキルが満載だった。
* スクラムの素晴らしさに雷に打たれたかのように感動、とても充実した2日間だった。

ただし、実践は簡単ではないと感じた。
資格を取ればスクラム開発ができるというわけでなく、実践によって身に着つくと感じた。
組織が初めてスクラム開発を取り入れるならば、正しい知識を身につけなければ間違いだらけのなんちゃってスクラム開発(中身の実態はウォーターフォール）になるので、メンバー全員受講必須にするべきだと思った。

# 結論
Scrum Inc.講師の方に直接質問ができる絶好の機会ですし、
アジャイル開発している人もしてない人も、かなりお勧めの研修です
無名関数（クロージャ）とは【個人的なお勉強アウトプット】

関数には名前をつける。
ただ、名前をつけるのもそれなりに面倒、その場限りで使う関数もある。
そんな時は名前をつけなくてもよい。
それが無名関数。

# わかりやすい記事
https://wa3.i-3-i.info/word15754.html
【Rspec】turbo_streamを使っているときのrequest specの書き方

# はじめに

Rails7 からはバリデーションの失敗時は `status: :unprocessable_entity` をつける必要があります。
しかし request spec で書いている時、バリデーション失敗時でにリクエストのステータスが `200` で帰ってきてしまう

## やりたい事

バリデーション失敗時のレスポンスのステータスが `422`にする

## 環境

- Rails 7.0.22
- Ruby 3.1.1
- rspec-rails 5.1.0

# request spec

Rails7 から form の送信はデフォルトで Turbo_stream を利用するようになりました。
turbo_stream 利用時はレスポンスのヘッダーに `Accept: 'text/vnd.turbo-stream.html'` が追加されるので、spec の送信時にもヘッダーを追加する必要があります。

```ruby:rails/spec/request/user.rb
require 'rails_helper'

RSpec.describe 'Registrations', type: :request do
  let(:user) { create(:user) }

  describe 'POST /users' do

    # 省略

    context 'failure' do
      it 'リクエストが失敗(nameが空)' do
        post user_registration_path, params:
        { user: {
          name: '',
          email: 'test@example.com',
          password: 'password',
          password_confirmation: 'password' } },
        xhr: true, headers: { Accept: 'text/vnd.turbo-stream.html' } #この行を追加する
      end
    end
  end
end
```

# 参考

参考をなった記事たち

[Rails 7.0 + Ruby 3.1 でゼロからアプリを作ってみたときにハマったところあれこれ](https://qiita.com/jnchito/items/5c41a7031404c313da1f#%E3%83%90%E3%83%AA%E3%83%87%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E5%A4%B1%E6%95%97%E6%99%82%E3%81%AB-status-unprocessable_entity-%E3%82%92%E4%BB%98%E3%81%91%E3%82%8B%E5%BF%85%E8%A6%81%E3%81%8C%E3%81%82%E3%82%8B)

[Rails7 で Devise を利用する方法](https://gorails.com/episodes/devise-hotwire-turbo)
[Oracle] 消したテーブルを復活させる [オラクル]

## やりたいこと
間違えて削除したテーブルを元に戻したい。復活させたい。

通常、DDL文はすぐにコミットされるため、ROLLBACKはできませんが
DROP TABLE文で消したテーブルを復活させる方法を紹介します。
DELETE文でデータを消してしまった場合は別の記事で紹介しています。


## 仕組みの話
Oracle 10g以降、「DROP TABLE」文で削除したテーブルは「ゴミばこ（RECYCLEBIN）」に入るようになりました。
ゴミばこ内に永遠に残っているわけではありませんが、ごみばこに入っているものは元に戻すことができます。

ただし管理者によりゴミばこ機能を無効にされていたり、PURGEオプション付きで削除したテーブルはゴミ箱に入らなかったりするので、注意してください。

```sql
-- もとに戻せる可能性のあるDROP TABLE文
DROP TABLE ＜テーブル名＞;
```

```sql
-- もとに戻せないDROP TABLE文
DROP TABLE ＜テーブル名＞ PURGE;
```


## 削除したテーブルを元に戻す

次のSELECT文でゴミばこ内のオブジェクトを確認できます。
ORIGINAL_NAME列が、削除されたオブジェクト名です。

```sql
-- ゴミばこ内のオブジェクトを確認する
SELECT OBJECT_NAME , ORIGINAL_NAME , DROPTIME FROM USER_RECYCLEBIN;

OBJECT_NAME                                  ORIGINAL_NAME
-------------------------------------------- --------------------------------
DROPTIME
-------------------
BIN$2cE0SI6XWeLgUwMEqMB08A==$0               TEST_TABLE
2022-03-09:12:00:37
```


ごみばこに入っているテーブルは次のSQL文でもとに戻すことができます

```sql
-- 元に戻すSQL文（テーブル名は消したテーブル名）
FLASHBACK TABLE ＜テーブル名＞ BEFORE DROP;
```
vimでスラッシュを含む文字列を置換するときは#とかをデリミタにするとよい


- `/`以外をデリミタとして使うことができる

```vim
:%s#/home/ec2-user#{{ ec2_home_directory }}#g
```

## 利用できるデリミタ
- '/'
- '#'
- '@'
- '!'
- ';'
- など


## 参考
https://kaworu.jpn.org/vim/vim%E3%81%AE%E7%BD%AE%E6%8F%9B%E3%81%AE%E3%83%87%E3%83%9F%E3%83%AA%E3%82%BF%E3%81%AF%E3%82%B9%E3%83%A9%E3%83%83%E3%82%B7%E3%83%A5%E4%BB%A5%E5%A4%96%E3%82%82%E5%88%A9%E7%94%A8%E3%81%A7%E3%81%8D%E3%82%8B
[grep・egrep]ある文字列を含まないファイルのリストを表示する。

## 文字列を含まないファイルのリストを表示する。
grepの`-L`オプションを利用して、文字列を含まないファイルのリストを表示する。
```
grep -L 文字列
```

## 文字列を含まないファイルを再帰的に探索し、そのリストを表示する。
grepの`-r`オプションを利用して、再帰的に探索する。
```
grep -rL 文字列
```


## 文字列を含まない（複数条件指定）ファイルを再帰的に探索し、そのリストを表示する。
grepの`-E`オプションを利用して、正規表現を利用して、条件を指定する。
```
grep -rEL "文字列A|文字列B"
```
また、egrepも利用が可能。
```
egrep -rL "文字列A|文字列B"
```
[Javascript][CSS]画像を別窓で開き、左右に回転できるようにする

# 概要
とある案件のおまけみたいな機能として「メインのリストとは別に画像表示専用の別窓を開き、その画像を左右回転できるようにしたい。」というシステムの作成を依頼されたため作成。
せっかく書いたわりに作った事自体を忘れそうなのでネットに忘備録も兼ねて投げます。
なお、画像保存・展開する部分（サーバー側）は今回は触れない。

# 要件

- ユーザーのモニタサイズは固定で、操作はPC限定なのでスマホの考慮は必要ない
- 画像の縦横は未定
- 画像サイズは非常に大きい場合もあるのでcanvasに表示できない
- 左右回転時に画像の一部が切れてしまってはいけない
- jQueryは使わない

# 実際のプログラム

## 別窓に開くところ
リストから下記HTMLのボタン部分をクリックしたら画像表示窓が開くという構成予定。

```html:list.html

<button type="button"
    onClick="window.open('image.html', 'image_window', 'width=600, height=600, scrollbars=0')"
>画像</button>

```

## 画像表示窓の部分

画像サイズは不定だが、とりあえず600px程度で中身が見れれば良いとのことなので、表示できれば良いものとする。

```html:image.html
<link rel="stylesheet" href="image.css">
<body>
<div id="btn-wrapper">
    <button type="button" id="left-route">↶左回転</button>
    <button type="button" id="right-route">↷右回転</button>
</div>
<div id="wrapper">
  <img id="image" src="image.jpg" alt="画像">
</div>

<script src="image.js"></script>
</body>
```

画像は不定だが、画面サイズに横幅を強制している。

```css:image.css
body {
    overflow: hidden;
    padding-top: 0;
    width: 100%;
    height: 100%;
}
#wrapper {
    text-align: center;
    width: 100%;
    height: 100%;
    overflow: hidden;
    position: relative;
}
#image {
    width: 100%;
    height: 100%;
}
```

実際にサイズや回転の動きを作成しているところ。
ウインドウサイズを計算するためにはシステムで利用しているものの大きさ等も考慮しないといけない。

```javascript:image.js
window.onload = () => {
    const image= document.getElementById("image");

    //画像の縦と横のサイズを取得して、100％指定ではなく実数値で画像サイズを規定するようにする。
    const imageH = image.clientHeight;
    const imageW = image.clientWidth;
    image.style.height = imageH + "px";
    image.style.width = imageW + "px";
    //画像の縦横大きい方の値を出す
    const imageLongSide = imageH > imageW ? imageH : imageW;

    const btnWrapper = document.getElementById("btn-wrapper");
    //ボタンは高さだけ取得する
    const btnHeight = btnWrapper.clientHeight

    //ウィンドウサイズの変更をするとき、そのままではブラウザさんが任意で使ってしまう
    // （スクロールバーやURL欄等）のサイズぶん小さくなってしまうので、事前に外側と内側のサイズを取得して差分を取る
    const systemW = window.outerWidth - window.innerWidth;
    const systemH = window.outerHeight - window.innerHeight;

    //ウィンドウサイズを変更する。縦は画像の長い方＋ボタン。横は画像の長い方。
    const windowW = imageLongSide + systemW;
    const windowH = imageLongSide + btnHeight + systemH;
    window.resizeTo(windowW, windowH);

    //このように画像を指定したとき、横長の画像のとき、基準点が欲しいところより上になってしまうので下にずらす。
    if (imageW > imageH ) {
      image.style.position = "absolute";
      image.style.top = (imageLongSide / 2 - imageH / 2) + "px";
      image.style.left = "0";
    }

    //すべてが決まった段階で、画像を左右に回す場合アニメーションが動くようにする
    image.style.transitionDuration = "0.25s";

    document.getElementById("left-route").addEventListener("click", function() {rotate(-90)});
    document.getElementById("right-route").addEventListener("click", function() {rotate(90)});
  };

  let imageD = 0; //画像角度。
  const rotate = (x) => {
    const image= document.getElementById("image");
    imageD += x;
    image.style.transform = "rotate(" + imageD + "deg)";
  }
}
```

# まとめ

モニタサイズを変更するのにより短いコードで同じような結果になるような方法があれば教えて下さい。
画像サイズを100％表記にしている関係で、画像を開いている画面で更新ボタンを押すと意図と違う行動になります。注意。
UploadedFile::fake()->image()を使うとCIでのみエラーが出る

## 問題

GitLab Runnerで`Uploadedfile::fake()->image()`を使ったユニットテストを
走らせると以下のようなエラーが出ました。
（ローカルではエラーなく通っています。）

```bash
TypeError: call_user_func(): Argument #1 ($callback) must be a valid callback, function “imagejpeg” not found or invalid function name
```

要約すると、以下の通りです。
call_user_func()の第一引数には有効なコールバック関数を渡してください。
"imagejpeg"なんて名前の関数は存在していないか有効ではありません。

この原因の詳しい説明については以下の記事をご覧ください。
Laravelのバージョンアップにて一部メソッドの挙動が変更されたことが原因だそうです。

https://qiita.com/yamotuki/items/b7832973833bcb06c157

## 解決策

解決策は、以下の通りです。
1. `libpng-dev` `libjpeg-dev` をパッケージマネージャー（apt-get, yum)でインストール
1. gdの拡張機能の設定をするときに適切なオプションを追加

**2の手順**に関しては、PHPのバージョンによってオプションが少し異なります。

### 1. libpng-dev, libjpeg-dev

```bash
RUN apt-get update && apt-get install -y libjpeg-dev libpng-dev
```

### 2. gd環境設定

#### PHP7.3 or below

```bash
RUN docker-php-ext-configure gd --with-gd --with-jpeg-dir --with-png-dir
```

#### PHP7.4 or above

```bash
RUN docker-php-ext-configure gd --enable-gd --with-jpeg
```

## 余談

この問題を発見、解決するまでに時間がかかりました。
なぜなら、この問題が起きた状態でGitLab Runner上でユニットテストを一括実行しようとすると
**PHPUnitが多重起動**しました。
その際、エラーメッセージも何も表示されず、ただPHPUnitが起動・終了を繰り返すばかりで
最後は**CIのログ容量がいっぱい**になり、**強制終了する**という挙動だったからです。
PHPUnitの多重起動でお困りの方は、まず**適当なテストメソッド１つでCIを動かしてみる**と良いかもしれません。
（テストメソッド１つだと多重起動はせずエラーがちゃんと出てくれます。）

## 参考文献

https://qiita.com/yamotuki/items/b7832973833bcb06c157

https://github.com/byCedric/Docker/issues/9