OmniAICreator/Qiita-1.07M huggingface dataset:
WeChat ミニプログラム 技術選定

# 目的
日本であまりWeChatミニプログラムについての情報が少なく、作成の技術選定の際に調べました。
あくまで個人開発レベルでの調査と総評なので正しいとは限りませんし、前提によって結論は変わると思いますが、ある程度参考になればと思います。

# WeChatMini プログラムとは
「WeChat」は中国名で微信（ウェイシン）と呼ばれる、中国最大のSNSプラットフォーム。
中国の利用率が90%以上。社会インフラになっている。

ミニプログラム自体は以下のメリットがあり、スタートアップ企業などで注目されている。
・WeChatの決済・会員機能のAPIが容易に利用可能
・アプリでの利用の際に発生する手数料がAppleなどと比べるとかからない。
（Apple: 決済時に30%、WeChat: 現金化の際に0.1%ほど）

# 作成方法
作成には、WeChat開発者ツールが必須。
https://developers.weixin.qq.com/miniprogram/en/dev/devtools/devtools.html

開発言語は、JavaScriptにテンプレートエンジンを追加した独自のPLFを用意している。
JS , WXML(WeiXinxML) , WXSS(WeiXinCSS)

※その他、開発者登録・アプリ登録などは略。

# 選定対象
今回は、WeChatの提供している独自のPLF（JS,WXML,WXSS)をそのまま利用して開発するか、
それとも、上記をReactでラップした、Remaxを使って開発するのかを検討した。
Remax: https://github.com/remaxjs

# 前提条件
- 機能要件
  - 会員機能あり
  - 課金機能あり
  - 大容量の動画のアップロード・閲覧機能あり
  - CrossPLFへの要件はなし
  - デザインなどは強い要望なし

- その他条件
    - 初期開発以降は、メンテナンス体制はなく、ある程度放置予定。

# 比較
以下の２つを比較
Native: JS , WXML(WeiXinxML) , WXSS(WeiXinCSS)
Remax: https://github.com/remaxjs

細かい比較
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237101/31265518-9062-59dd-cf5a-ea2cba1fce5c.png)

総評
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237101/160bbad3-0564-7b8d-9aaa-14d29843af64.png)
WeChatAPIへのアクセス、WeChatのアップデート時のメンテナンス、ライブラリ不具合などを考慮すると、現段階ではWeChatのNativeでの作成のほうが良さそう。
terraform apply が実行できない

terraform 初心者です。

##結論
terraform apply は main.tf と同じディレクトリではないと、実行できない。

```
Test1
└── Test2
     ├── main.tf
     └── terraform.tfstate
```

```
$ cd Test1
$ ls
terraform_test

# main.tf より上の階層（Test1）で terraform apply を打つと…
$ terraform apply
Error: No configuration files

Apply requires configuration to be present. Applying without a configuration
would mark everything for destruction, which is normally not what is desired.
If you would like to destroy everything, run 'terraform destroy' instead.
```
うまくいきません。
そこで、階層を変えます。


```
~ master*
$ cd Test2
$ ls
main.tf           terraform.tfstate

# main.tf と同じ階層（Test2）で terraform apply を打つと…
$ terraform apply   
aws_instance.example: Refreshing state... [id=i-0dde93a30067c72a1]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # aws_instance.example will be updated in-place
  ~ resource "aws_instance" "example" {
        id                           = "i-0dde93a30067c72a1"
      ~ tags                         = {
          + "Name" = “Hello”
        }
        # (26 unchanged attributes hidden)




        # (4 unchanged blocks hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_instance.example: Modifying... [id=i-0dde93a30067c72a1]
aws_instance.example: Modifications complete after 1s [id=i-0dde93a30067c72a1]

Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
```
無事に実行されました。
ちなみに、上述のコードは、EC2インスタンスのタグをHelloにしようとしています。
お疲れ様でした。
Node.jsのMongodbをPromiseで行ったチートシート（？）

#初めに
Node.jsでMongodbを操作したいという際にもうちょっと簡単で楽にならないかなと考えて作ったのが今回のプログラムです。楽is神。

#前提
・Node.jsのインストールを済ませていること
・Mongodbのインストールを済ませていること
・npmのインストールを済ませていること
・mongodbのNode.jsのAPIをインストールしていること
###環境
・さくらVPSのCentos7
・node.js v15.11.0
・npm 7.6.2
・mongodb v4.4.4
#Mongodb
わかりやすいようにMongodbを操作する用のディレクトリをとりあえず作っておきましょう。

```
$mkdir database
$cd database
```
###接続部分
まずはMongodbとの接続についてのファイルを作成します。

```
$vim mongo_connect.js
```

```node.js
//mongo_connect.js
const MongoClient = require('mongodb').MongoClient
function open(){
  let url = 'mongodb://ユーザー名:パスワード@localhost:27017';
  const connectOptions = {
    useNewUrlParser: true,
    useUnifiedTopology: true,
  }
  return new Promise((resolve,reject)=>{
    MongoClient.connect(url,connectOptions,(err,db)=>{
      if(err) reject(err);
      else resolve(db);
    });
  });
}

function close(db){
  if(db)db.close();
}

let db = {
  open:open,
  close:close
}

module.exports=db;
```
urlについてですがユーザーを作成していた場合は以上のとおりになります。ユーザー名とパスワードを設定したとおりに入れてくださいね。
認証を設定したいという方は

[こちら](https://qiita.com/SUNAsan/items/392b9fb981b6a2d67b86)の記事の最後の方に書いてあるので、是非参考にしてくださいな。
またMongodbをwebサイトのデータベースとしてでもなんでも、本格的に運用したいという方は27017からポートの変更をしておいたほうがいいです。今回はテストも兼ねていたのでデフォルトのポートのままです。

###クエリ部分
Mongodbにおいてもクエリと呼んでいいのかどうかはわかりませんがとにかくクエリです。

```
$vim insertOne.js
```

```node.js
//insertOne.js
const zenodb = require('./mongo_connect.js');

function insertOne(object,col){
  let database = null;
  zenodb.open()
  .then((db)=>{
    database = db;
    const dbName = db.db("自分の使うデータベース名を入力してね！");
    return dbName.collection(col);
  })
  .then((collection)=>{
    return collection.insertOne(object);
  })
  .catch((err)=>{
    console.error(err)
  })
  .finally(()=>{
    zenodb.close(database);
  })
}

module.exports=insertOne;
```

insertOne({データ名,データ},コレクション名)とすることで実行できるメソッドを用意しました。requireしている接続ファイルがzenodbですが、参考にさせていただいたQ&Aの回答者の人がそう書いていたのでそう書かせてもらいました。意味は・・・調べてみたんですがよくわからなかったっす。
念の為、参考にさせていただいたQ&Aのサイトを載せておきます。
>https://stackoverflow.com/questions/37911838/how-to-use-mongodb-with-promises-in-node-js

###集合部分
今回はinsertOneだけでしたが、他にも作れば当然便利になるでしょう。しかしそうしたらrequireするのがめんどくせぇ！とかなりそうなので、集合部分を予め作っておきましょう。

```
$vim methods.js
```

```node.js
const insertOne = require("./insertOne.js");

let methods = {
  insertOne:insertOne,
}

module.exports=methods;
```

let methodsの場所にクエリをたくさん追加できるようになれば便利ですね。
最後に一応今回作ったプログラムを試しておきましょう。
使用するのは先程作ったmethodsファイル。

```node.js
const insertOne = require("./insertOne.js");

let methods = {
  insertOne:insertOne,
}

methods.insertOne({name:"tekitou"},"users");

module.exports=methods;
```

```
node methods.js
```
これでmongodbシェルにログインしてみて、対象のデータベースのコレクションの中にデータが入っていればOKです。
以上！
なにか質問があれば書いてください！わからないかもしれませんけどねw
HSP3.6β5 HGIMG4 でドミノ倒し

HSP3.6β5 HGIMG4 では gpbox モデルを gppbind で剛体化する際、その前に指定した setscale の設定が、gpbox の剛体の形状に反映されるようになりました。
このおかけで直方体剛体が作成できるようになりドミノ倒しが実現できるようになりました。

サンプルコードは以下のようになります。

```hs
#include "hgimg4.as"
#define GRAVY (-9.8 * 3.0)
	gpreset
	setcls CLSMODE_SOLID, 0x000000
	setpos GPOBJ_CAMERA, 30,40,110
	gplookat GPOBJ_CAMERA, 0,2,0
	gosub *make
	repeat
		redraw 0
		gpdraw
		redraw 1
		await 1000/60
	loop

*make
	num = 10
	dist = 6
	offset_y = 10.0
	offset_x = -2.2
// 床1段目
	fric = 1.0
	pong = 0.01
	col = 0x606060
	size = double(dist * num) * 0.5, 1.0, 4.0
	ps = size.0, 0.0 + offset_y, 0.0
	id = _box(size, ps, col, 0, fric, pong)
// 床2段目
	ps = - double(dist * num) * 0.5 + offset_x, 0.0, 0.0
	id = _box(size, ps, col, 0, fric, pong)

	mass = 10.0
	size = 1.0, 4.0, 2.0
	fric = 0.2
	pong = 0.5
// キックピース
	col = 0xff0000
	ps = double(dist * (num - 1)) - 2.0, 2.0 + offset_y, 0.0
	gpbox id, 2.0, col
	setpos id, ps.0, ps.1, ps.2
	setscale id, size.0, size.1, size.2
	setang id, 0, 0, M_PI * 0.1
	gppbind id, mass, fric
	gppset id, GPPSET_FRICTION, fric, pong

	flup = 2
	mass = 2.0
	repeat num-2, 1 // 1グループ目
		r = (rnd(5 - flup) + flup) * 51
		g = (rnd(5 - flup) + flup) * 51
		b = (rnd(5 - flup) + flup) * 51
		col = (r << 16) | (g << 8) | b
		ps = double(dist * cnt), 2.0 + offset_y, 0.0
		id = _box(size, ps, col, mass, fric, pong)
	loop
	repeat num-1, 1 // 2グループ目
		r = (rnd(5 - flup) + flup) * 51
		g = (rnd(5 - flup) + flup) * 51
		b = (rnd(5 - flup) + flup) * 51
		col = (r << 16) | (g << 8) | b
		ps = offset_x - double(dist * cnt), 4.0, 0.0
		id = _box(size, ps, col, mass, fric, pong)
	loop
	return

// 直方体剛体を作成する
#defcfunc _box array _size, array _pos, int _col, double _mass, double _fric, double _pong, local _id
	gpbox _id, 2, _col
	setpos _id, _pos.0, _pos.1, _pos.2
	setscale _id, _size.0, _size.1, _size.2
	gppbind _id, _mass, _fric
	gppset _id, GPPSET_FRICTION, _fric, _pong
	gppset _id, GPPSET_DAMPING, 0.0, 0.0
	gppset _id, GPPSET_GRAVITY, 0.0, GRAVY, 0.0
	return _id
```

|実行結果1|
|:---:|
|![qdomi1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213145/6972585d-a724-ec80-fae2-a8343db0866c.png)|
|右の赤いドミノから倒れていきます|

|実行結果2|
|:---:|
|![qdomi2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213145/d9e445bf-6dfd-499c-6b9c-ff1f785bd08b.png)|
|パタパタパタパタ、、、|

デフォルトの重力値だと少し動きがもっさりしている気がするので値を大きくしています。
AWS CLIで(InvalidAccessKeyId)のエラーで詰まってた話

##悩まされたエラー文
An error occurred (InvalidAccessKeyId) when calling the ListBuckets operation: The AWS Access Key Id you provided does not exist in our records.

##経緯
- AWS CLIをインストールし`aws configure`で初期設定をしました。

```
AWS Access Key ID [None]: ＊＊＊＊＊＊
AWS Secret Access Key [None]: ＊＊＊＊＊＊
Default region name [None]: ap-notheast-1
Default output format [None]: json
```

- `aws s3 ls`でアクセスできるか確認したところ、アクセスできなかったため修正方法を確認（リージョン名の綴りを間違えてましたap-notheast-1ではなくap-northeast-1）このリージョン間違いが悪夢の始まり

https://soypocket.com/it/aws-cli-configure-reset/


- 上記サイトを参考に`rm -r .aws`を実行


- 再度IAMでアクセスキーを作成しコピペ、リージョン名もコピペ


- 全部あってるはずなのにアクセスキーが無いというエラーが出る（２、3時間公式のドキュメント見たりバージョン違いかと思ってインストールし直したり…`rm -r .aws`とアクセスキー作成１０回ほどやりました…笑）


- `aws configure list`で登録されてる内容確認

```
% aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************3JQ7              env    
secret_key     ****************vnOS              env    
    region           ap-northeast-1      config-file    ~/.aws/config
```

access_keyとsecret_keyが直前に設定したものと違うことに気づく
Locationも公式のドキュメントで見たものと違うようでどこに保存されてるかわからない…
どなたかわかる方いらっしゃいましたらコメントお願いします。

##今回のエラー解決?
- 初期設定の`aws configure`を`aws configure --profile ユーザー名`で作成

```
% aws configure --profile ユーザー名
AWS Access Key ID [None]: ＊＊＊＊＊＊
AWS Secret Access Key [None]: ＊＊＊＊＊＊
Default region name [None]: ap-northeast-1
Default output format [None]: json
```

- `aws --profile ユーザー名 s3 ls`でアクセスできた！

```
% aws --profile ユーザー名 s3 ls
2021-03-21 13:26:25 ＊＊＊＊＊＊
2021-03-21 13:24:15 ＊＊＊＊＊＊
2021-03-21 13:31:26 ＊＊＊＊＊＊
2021-03-20 14:31:04 ＊＊＊＊＊＊
```

##解決に至った参考資料

https://qiita.com/suuungwoo/items/66f39ac1d12c7a800d98

##補足

```
% aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ****************3JQ7              env    
secret_key     ****************vnOS              env    
    region                <not set>             None    None
```

```
 % aws configure list --profile ユーザー名
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                   ユーザー名           manual    --profile
access_key     ****************FAFS shared-credentials-file    
secret_key     ****************Zf7u shared-credentials-file    
    region           ap-northeast-1      config-file    ~/.aws/config
```

解決後確認してみたらこのようになってました。後々解決できればと思ってます。
デザインパターンの学習を始める前にクラス図を読めるようになろう

デザインパターンを学習していると説明にクラス図が用いられることが多いですよね。
みなさんはクラス図を見て、概要を理解してからコードを読んでいますか？
クラス図の読み方を理解しておくと概要の把握と理解が捗るので、デザインパターンを始める前にクラス図を読めるようにしておくことをお勧めしています。
実際に自分もそうすることでデザインパターンを理解するまでのコストを抑えられたように感じました。

この記事では、クラス図を読む時に必要最低限の情報をまとめています。
よろしければ、参考になさってください。

## 図の読み方
![スクリーンショット 2021-03-21 13.42.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94596/0e6d199e-71f5-0462-3fae-5f7d141bb028.png)
![スクリーンショット 2021-03-21 13.56.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94596/98d089bf-0a25-da8f-660e-c7d1b4ba6ecf.png)

## 図からソースコードを想像してみる
上で確認した読み方を参考に下のクラス図はどのようなソースコードになるか想像してみましょう。
サンプルコードはPHPで書いています。

### クラス図
![スクリーンショット 2021-03-21 16.11.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94596/ad299cb2-6d44-734d-5931-d0c199def18f.png)


### ソースコード
``` ClassA.php
<?php
declare(strict_types=1);

abstract class ClassA
{
    private $attribute1;

    public abstract function operation1();

    public function operation2()
    {
        return true;
    }
}
```
``` ClassB.php
<?php
declare(strict_types=1);

class ClassB extends ClassA
{

    public function operation1()
    {
        // TODO: Implement operation1() method.
    }
}
```
``` InterfaceC.php
<?php
declare(strict_types=1);

interface InterfaceC
{
    public function operation3(ClassA $param);
}
```
``` ClassD.php
<?php
declare(strict_types=1);

class ClassD implements InterfaceC
{

    public function operation3(ClassA $param): int
    {
        // TODO: Implement operation3() method.
        $return_value = 0;

        return $return_value;
    }

    public static function operation4()
    {
        return new ClassE();
    }
}
```

いかがでしたでしょうか？
クラス図の読み方をマスターして、デザインパターン学習の役に立てたら幸いです。
【Rails6】多対多のアソシエーションを利用したグループ参加機能の実装

※2022年から技術系の記事は[個人ブログ](https://yamaday0u.net/category/programmer/)に投稿しております。ぜひこちらもご覧ください→[yamaday0u Blog](https://yamaday0u.net/category/programmer/)

多対多のアソシエーションを利用してグループ参加機能を実装する方法を紹介します。
**目次**

- 前提条件
- グループ参加機能の仕様
- 動作確認
- 実装手順１：モデルの作成
- 実装手順2：コントローラーの作成
- 実装手順3：ルーティングの設定
- 実装手順4：ビューの作成

## 前提条件
Rails 6.0.3.5

## グループ参加機能の仕様
承認制ではなく、グループに参加するボタンをクリックすると、データベースにユーザーIDとグループIDに組み合わせが保存されて参加できる簡単なものになります。

## 動作確認
- 「Join this group」をクリック
- Are you sure to join this group?」というメッセージが出る
- OKをクリックするとグループのトップページに移動する
- 「Notice: joined the group!!」のフラッシュメッセージが出る。

これでグループへの参加が完了です。
[![Image from Gyazo](https://i.gyazo.com/54e832f0f22737b2d4312fff83b4d23e.gif)](https://gyazo.com/54e832f0f22737b2d4312fff83b4d23e)
それでは説明していきます。
グループ参加機能の実装に関係する記述以外は省略しているのでご承知おきください。

## 実装手順１：モデルの作成
用意するモデル（テーブル）はuser, group, user_groupの３つです。

```app/models/user.rb
class User < ApplicationRecord
  has_many :user_groups
  has_many :groups, through: :user_groups
end
```

```app/models/group.rb
class Group < ApplicationRecord
  has_many :user_groups
  has_many :users, through: :user_groups
end
```

```app/models/user_group.rb
class UserGroup < ApplicationRecord
  belongs_to :user
  belongs_to :group

  validates :user_id, uniqueness: { scope: :group_id }
end
```

## 実装手順2：コントローラーの作成
`groups_controller`と`user_groups_controller`を以下のように記述します。グループ参加機能の実装には、`users_controller`への記述は特にありません。

```app/controllers/groups_controller.rb
class GroupsController < ApplicationController
  def show
    @group = Group.find(params[:id])
    # UserGroupテーブルからログインユーザーと、詳細を表示しているグループの組み合わせを探します。
    # 組み合わせがなければnilを返します。
    @userGroup = UserGroup.find_by(user_id: current_user.id, group_id: params[:id])
  end
```

```app/controllers/user_groups_controller.rb
class UserGroupsController < ApplicationController
  def create
    @userGroup = UserGroup.new(user_id: current_user.id, group_id: params[:group_id])
    if @userGroup.save
      # グループ参加後のリダイレクト先を指定
      redirect_to XXXX_path(@userGroup.group_id), notice: 'joined the group!!'
    end
  end
end
```

## 実装手順3：ルーティングの設定
`user_groups_controller.rb`で`params[:group_id]`をを使用するアクションを定義しているため、`user_groupsコントローラー`を`groupsコントローラー`にネストさせます。

```config/routes.rb
Rails.application.routes.draw do
  resources :groups, only: :show do
    resources :user_groups, only: :create
  end
end
```

## 実装手順4：ビューの作成
ボタンの部分の記述だけ掲載します。
条件分岐で`@userGroup`に値が入っていれば、グループに参加しているのでグループメンバーしか見られない情報を表示し、値が入っていなければで「Join the group」ボタンを表示します。

```erb:app/views/groups/show.html.erb
<% if @userGroup.present? %>
  <div class="form-group">
    <div class="schedule-item">
      <div class="schedule-item-header text-left">
        <p class="bold">Task</p>
      </div>
      <div class="schedule-item-body text-left">
        <p><%= @group.task %></p>
      </div>
    </div>
  </div>
<% else %>
  <div class="actions">
    <%# user_groupsコントローラーのcreateアクションを実行するリンク %>
    <%= link_to 'Join this group',  group_user_groups_path(@group.id), method: :post, data: { confirm: 'Are you sure to join this group?'}, class:"sign-up-btn" %>
  </div>
<% end %>
```
これでグループ参加機能の実装完了です。
【Rails】古いデータベースが影響してエラーが出た話

#概要#
以前作成したRailsアプリを削除して、再び同じ名前で同様のアプリ作成しました。
そして`rails db:migrate`実行後、`ActiveRecord::PendingMigrationError`が発生した。

結論から言うと、過去アプリのデータベースが残っており
作成したアプリ上の`db/migrateディレクトリ内`のファイルをコマンド`db:migrate`にて反映させようとした際、ファイルのバージョンが異なるためエラーが発生しました。
![2021-03-17 13.20.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521366/42534d6e-3d90-3ae9-3cd8-fc36bded45f1.png)
#開発環境#
・データベース：PostgreSQL
・railsのバージョン：6.1.3
・PC：macbook pro

#エラー発生から解決までの流れ#
1. 元々あったrailsアプリを削除する。(rails db:create,rails db migrate実行済み)
2. 元々あったrailsアプリと同じ名前のrailsアプリを再び作成する。(rails db:create実行済み)
3. `rails db:migrate`を実行後、`rails s`にてサーバを立ち上げてブラウザを見ると、`ActiveRecord::PendingMigrationError`が発生する。
4. `rails db:version`を実行すると、terminal上のファイルとアプリmigrationファイル(db/migrate)のバージョンが異なる。
5. `rails db:reset`を実行して`rails db:migrate`を行うと、問題なくアプリケーションを実行できる。<br>また、`rails db:version`にてファイルを確認すると、terminal上とrailsアプリのmigrationファイルが一致していることが確認できた。
6. `rails db:migrate`を行ってアプリを起動してみると、問題なく動作した。
![スクリーンショット 2021-03-17 12.22.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/521366/e40af3f2-aeb4-162d-9cca-0e98cf79d2ff.png)


#エラーが発生した原因#
原因は私の理解不足によるもので、アプリファイルを削除すると一緒にデータベースも消すことができると思っていたためです。<br>(アプリファイルとデータベースは、同一の場所にあると思っていた）
実際は、下記ディレクトリにデータベースが保存されています。
また、データベース削除とversion確認コマンドは、下記になります。

PostgreSQL：… /usr/local/var/postgres 内
MySQL：… /usr/local/var/mysql 内

データベース削除：`rails db:reset`　<font color="Red">(データベース内の情報は消えるので注意！)</font>
データベースversion確認：`rails db:version`


#最後に#
正直なところ、データベースについてまだまだわかっていない点がたくさんあります。
もし間違っている点等がある場合、ご指摘頂けると大変ありがたいです。
最後まで読んで頂きありがとうございました。
Yoctoでdocker0を作成しない

# 背景
yocto(rocko)でdockerを有効にすると docker0 が作成される。今回は使用しないので、削除したい。

# 手順
`/etc/docker/daemon.json` で bridge を none に設定する。

```
root@qemuarm64:~# cat /etc/docker/daemon.json
{
  "iptables": false,
  "bridge": "none"
}
```
Dockerのphp:XX-apacheでpdo_mysqlを使用したい時は

よくあるPHPのLAMP環境をDockerで再現しようとした時

- Dockerfile

```
FROM php:7.2-apache
WORKDIR /var/www/html/
RUN echo "<?php" > index.php && echo "phpinfo();" >> index.php
```

でDocker起動

```
docker build -t phptest .
docker run -it -d --name phptest2021 -p 80:80 phptest:latest
```



localhostでphpinfoを見てみると
![スクリーンショット 2021-03-21 16.07.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1224758/f7b960e0-3201-05d4-6e95-02da42efe9ea.png)

ああ、sqliteしかないのか・・

MySQLやMariaDBを使用したいので、
https://www.php.net/manual/ja/ref.pdo-mysql.php
これが使いたいんですよね・・

そんな時は

```
docker-php-ext-install
```
を使う。

- Dockerfile　書き直す。

```
FROM php:7.2-apache
RUN docker-php-ext-install pdo_mysql && docker-php-ext-enable pdo_mysql
WORKDIR /var/www/html/
RUN echo "<?php" > index.php && echo "phpinfo();" >> index.php
```
でもう一度Docker起動

```
docker build -t phptest .
docker run -it -d --name phptest2021 -p 80:80 phptest:latest
```
localhostでphpinfoを見てみると
![スクリーンショット 2021-03-21 16.10.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1224758/ea67d99e-9db2-bfe7-bb6c-a901551418ce.png)

PDOが使用で切ることを確認。



- おまけ

```
docker-php-ext-install
```
このコマンドを知らなかったときは
https://pentan.info/php/pdo_mysql_install.html
直接上記をやろうとして時間を浪費しました。
他にも

```
docker-php-ext-install mysqli mbstring gd iconv
```

色々インストールできます。
Kubernetesの概要を学習したときのまとめ

#はじめに

Dockerについて、書籍と動画を用いて学習を進めてきて一通り終わりました。
Kubernetesは今の自分に必要ないと思うので、目を背けようかと思いましたが、概要くらいは知っておくべきと考えてざっと書籍に目を通してみました。

この記事は、学習した内容を整理する意図でまとめたものです。

#要件

Dockerについてそれなりに理解がないと何を言っているかわからないと思います。
わかっててもよくわからないかもしれません。
なんなら、僕以外わからないかもしれません。

#Kubernetesとは
複数台のサーバにまたがって、Dockerなどのコンテナを動かすためのプラットフォームでオーケストレーションツールと呼ばれる。

元々はGoogleが開発し、現在はOSS化されている。

Kubernetesは、マスターノードとワーカーノードで構成され、マスターノードはコントロールプレーンと呼ばれるシステムがインストールされ、そこに含まれるコンポーネントを連携させてクラスタを管理する。

Kubernetesは、自律的なシステムであり、Dockerのように管理者が直接コンテナ等のオブジェクトを削除することはキホンない。
管理者がkube-apiserverに対して、kubectlというコマンドで指示を出し、etcdというDBにdesired stateという”望ましい状態”を登録する事で、Kubernetesがその状態になるよう調整を行うようになっている。

#Kubernetesオブジェクト

Kubernetesを理解するうえで重要なKubernetesオブジェクトについてまとめる。

##Podオブジェクト

Kubernetesの **最小実行単位** で、1つ以上のコンテナ、いくつかのボリューム（ストレージ）を含む。
ワーカーノードで実行され、分割される事はない。
PodにはprivateIPアドレスが割当られ、含まれるコンテナ間の通信が可能である。（同じポート番号は使えない）
当然ながらPod内に含めたボリュームはコンテナが破棄されたタイミングで消えてしまうので、NFS等で外部保存するのが望ましい。


##Serviceオブジェクト

Serviceは同一構成のPodを配下に束ねる概念である。同じ構成のPodはReplicaと言う。
Serviceはワーカーノードを跨いで構成が可能で、これはワーカーノードの持つ kube-proxy によって実現する。

Service作成時にはClusterIPというIPアドレスが割り当てられ、これは明示的にServiceが削除されない限り固定値である。
KubernetesにはCoreDNS（kune-dns）が動作しており、Serviceの名称とClusterIPは名前解決が可能である。

ClusterIPを設定しない場合、Serviceの名前をDNS検索したときに各PodのprivateIPが全て一覧で返され、これらを使って通信することをヘッドドレスサービスという。
プロキシによるパフォーマンス低下を防ぐなどの目的で設定される。
ヘッドドレスサービスの設定は、オブジェクト単位で作成されるマニフェストという設定ファイルにYAML形式で記述する。

尚、Podに割り当てられるIPをアドレスやClusterIPは、クラスター内のみで有効なアドレスなので、外部に公開はできません。
グローバルIPとこれらのIPを変換する仕組みが必要。


###セレクター

Serviceの配下にあるPodを指定する仕組みである。
PodやServiceなどのすべてのKubernetesオブジェクトには任意のラベルを付けることが出来る。
ラベルはキーと値のペアであり、例えば本番用に ”Honban!:app” 、開発用に ”kaihatu!：app” とラベリングしてグルーピングして処理することができる。


##IPアドレスの運用について

PodのIPアドレスは動的なので、Podだけでは外部との通信が難しい。
Podの前段にはServiceが必要で、その前段にはロードバランサーかIngressが必要になる。

###ロードバランサーとNodePort
ワーカーノードの持つIPアドレスを使う方法。
ワーカーノードのポート番号とServiceのポート番号をマッピングして通信する。

この場合、ワーカーノード単位でServiceが分断される為、DNSラウンドロビンでノードを振り分けたり、前段にロードバランサーを設置する等が必要になる。
Serviceオブジェクトに対して LoadBalancer オプションを構成すると、前段にグローバルIPを設定したロードバランサーを構成できる。

ただし、これはKubernetesで規定したものではなく、AWSならELBが使われるように各クラウドベンダーで異なる。


##Ingressオブジェクト
HTTP/HTTPS専用のリバースプロキシであり、Serviceの前段に設置することで通信を振り分けます。

リバースプロキシは、社内の端末等の代理でインターネットにアクセスするプロキシの逆で、インターネットからの通信を中継する仕組みである。
負荷分散や、URLのパスごとにサーバを振り分けたりすることが可能になる。

ロードバランサーと同様にIngressコントローラに何が利用できるのかはシステム構成で異なる。


##Deploymentオブジェクト・ReplicaSetオブジェクト

ReplicaSetオブジェクトは同じ構成のPodの数を管理・制御する。
Podが停止した場合は必要数だけ増やしたりする。

DeploymentオブジェクトはReplicaSetを管理する。
Replicaの数や、コンテナイメージの情報が記述され、設定やバージョンの更新が入るとPodを削除し作成し直してくれる。
この際、設定やデータも全て削除される。

更新によりデータを失いたくないときは、StatefulSetオブジェクトが使用します。
StatefulSetでは、更新前のIPアドレスやボリュームを引き継がれる。


##Jobオブジェクト・CronJobオブジェクト

Podがバッチ処理用途の場合など、処理が終わり次第不要になるケースにおいてはKobオブジェクトを使用します。
CronJobオブジェクトはLinuxにおけるCronと同様に指定日時にPodを実行するオブジェクトです。


##DeamonSetオジェクト

ワーカーノードを専有してバックグラウンドで常に動くPodを実行したいときに使用する。
例えばログの処理やモニタリングをするPodなどが該当する。


#ネームスペース

Kubernetesクラスターを区切る概念である。
Kubernetesでは当然複数のシステムが稼働することがあり、NWや名前の重複も起こり得る。
それを避けるために環境ごとにネームスペースを分断することができる。


#おしまい

書籍にはminikubeを使った動作確認もありましたが、僕は一旦やめておきました。
こういう学習はどこまでやるかの線引がとても大事で、そこが制御出来ないと自分が達成したい事からドンドン遠のいてしまうので...。
残りは必要になったら、もしくは、達成した後にしたいと思います。
Ubuntu Serverのインストール

Ubuntu Serverのインストールの手順について

①OSのインストール用のソフトウェア、Raspberry Pi Imagerを公式サイトのダウンロードページ[https://www.raspberrypi.org/software/](https://www.raspberrypi.org/software/)からダウンロードしてインストールする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593111/dede7b1c-90f8-81a8-3a69-fa185d3f55d9.png)
下にスクロールするとリンクが表示されるのでクリックするとダウンロードが始まる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593111/3c6189a3-0377-6655-596e-296cf265bebf.png)
※ラズパイの標準インストールソフトウェア、Noobsにてインストール可能なOSは10種類（Raspbian Full、LibreELEC_RPi2、Raspbian Lite、Raspbian、OSMC_Pi2、Screenly OSE、RISC OS、Windows10 Iot Core、Lakka_RPi2、TLXOSである）
※今回のUbuntu ServerはNoobsでインストールできない（SDカードにイメージを用意して起動するだけではインストールできない）ため、別ソフトウェアで予めOSをインストールしないといけない。

②公式サイトのダウンロードページ[（https://jp.ubuntu.com/download）](https://jp.ubuntu.com/download)の「Ubuntu Server for ARM」リンクからイメージをダウンロードする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593111/9be6ad23-b156-c6db-f921-cfefef3652af.png)
下にスクロールするとリンクが表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593111/9b7e9e3c-8b7e-fe7d-49dd-36a7afbfce97.png)
拡大Ver
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593111/50359823-9b41-2f55-0eb3-8eb749e0abe0.png)
リンクをクリックすると別のページに飛ばされるのでその先のリンクをクリックしてイメージをダウンロードする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593111/740e618d-d836-24e6-7014-aec822eec274.png)
※ここのリンク先のDownload Ubuntu 20.04.2 LTSとDownload Ubuntu 20.10の違いはセキュリティサポートが長いかどうかであり、基本的にLTSと付いている方を選ぶ方が良い。[参考1](https://www.sejuku.net/blog/83842)、[参考2](https://linuc.org/study/knowledge/453/)


③先ほどダウンロードしたRaspberry Pi Imagerをインストールする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593111/18b3b751-e130-ef14-3a7b-83ae132926cf.png)
もし下記の画面が表示された場合は詳細情報をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593111/75d77df6-cbb2-5ad3-5cc7-eb6d152bb0e9.png)
詳細設定をクリックすると実行ボタンが表示されるのでクリックする。
※「WindowsによってPCが保護されました」画面で詳細設定を押しても実行ボタンが表示されない場合はWindowsの設定もしくはWindows Defenderの設定など変更する必要がある、が今回は表示されたため方法は割愛する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593111/7c32758d-f05d-9282-b00f-4d3b7670b592.png)
実行ボタンを押したら下記メッセージが表示されたので何かを間違えたらしい（訳：インストーラーの完全性チェックに失敗しました。一般的な原因は、ダウンロードが不完全であったり、メディアが破損していることです。詳細は以下のサイトをご覧ください。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593111/5bd71e1d-1389-b119-7678-6e65ba77604e.png)

休憩中
mixhostにcomposerをインストールする




引用元　https://noter.fugo.ml/2019-05-02-mixhost%E3%81%ABcomposer%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B

手順

sshでログインし、以下のコマンドを実行する

curl -sS https://getcomposer.org/installer | php

下記コマンドを実行し、composerのバージョンなどが表示されて入れば正常にインストールされている。

php composer.phar
【Blender 2.9】  ウェイトペイント 基本設定 【自分用メモ】

# 動作環境
本記事の動作環境は以下の通りです。

 
| 項目             |               環境 |
|:-----------------|:------------------|
| OS               |         Windows 10 | 
| Blender          |               2.9 |

# ウェイト0を黒で表示する

ウェイト0を黒で表示することでウェイト0の確認を簡単にする。
ウェイトペイントモードで以下の設定をする。


- Viewport Overlays > Zero Weights を Activeにする

![001_settings.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/682933/a8204265-5d08-7a35-012d-4eee174ee6ed.jpeg)

# 左右対称に編集する

左右対称に編集するために以下の設定をする。

- アクティブツールとワークスペースの設定 > 対象 > ミラー の X を有効にする

補足：アクティブツールとワークスペースの設定はNキーでツールタブから同様の設定をしてもいい

![002_settings.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/682933/eb5e3726-3504-8e81-cf6c-abc70a3e60e5.jpeg)



# 頂点ウェイトの合計を1にする

各ボーンの頂点ウェイトの合計を1にするために以下の設定をする。

- アクティブツールとワークスペースの設定 > オプション > Auto Normalize を有効にする 

補足：アクティブツールとワークスペースの設定はNキーでツールタブから同様の設定をしてもいい

![002_settings.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/682933/bccf47b1-ed3b-e3d8-f8e5-ab2b4e215cb7.jpeg)


# 余分なウェイトを消す

以下の方法で余分なウェイトを消すことができる

- パターン①：ウェイトを0にする
- パターン②：アクティブツールとワークスペースの設定 > ブラシ設定 > ブレンド を差分にして消す

補足：アクティブツールとワークスペースの設定はNキーでツールタブから同様の設定をしてもいい

![003_settings.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/682933/402c11c7-3aee-89a3-d0ac-46d7354a81c1.jpeg)


# ウェイトの減衰方法の変更方法

ステップ的にウェイト塗りをしたい場合などに以下の方法でウェイトを塗った中心部分からのウェイト減衰度合いを変更することができる。

- アクティブツールとワークスペースの設定 > ブラシ設定 > 減衰 で任意の減衰設定に変更可能

補足：アクティブツールとワークスペースの設定はNキーでツールタブから同様の設定をしてもいい

![003_settings.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/682933/6360b409-fbcb-1bd9-a461-a186874ca96e.jpeg)


# 選択した頂点(面)部分だけウェイトペイントをする

狙った部分以外にウェイトペイントしたくない場合に、以下を行うことで、選択した頂点(面)部分だけウェイトペイントする

- 手順①：オブジェクトを選択して編集モードにする
- 手順②：ウェイトペイントしたい部分だけ選択する
- 手順③：ウェイトペイントモードにする
- 手順④：ペイントマスクを有効にする

![004_mask.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/682933/a1536f6d-e645-4ddc-6d2e-38e0660daa84.jpeg)

![005_mask.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/682933/fc072710-2c13-4c95-7485-a954c7b837ff.jpeg)

# 一気にウェイトペイントする

とりあえず一気にウェイトペイントしたいときは以下の方法で一気に塗れる

- 手順①：オブジェクトを選択して編集モードにする
- 手順②：aキーで頂点を全選択する
- 手順③：ボーン → オブジェクトで選択して、ウェイトペイントモードにする
- 手順④：頂点で選択を有効にする
- 手順⑤：ブラシのウェイトを任意の値に設定する
- 手順⑥：Shift + k キーで一気にウェイトを塗る

![006_ikki.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/682933/1be530f2-926e-d2ce-d633-3ff4a1890b8c.jpeg)

![007_ikki.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/682933/51a5b6ed-3a62-93b7-8424-1849da861d62.jpeg)

# 参考

以下の動画・サイトを参考にしました。

- [髪の毛のウェイト方法](https://www.youtube.com/watch?v=1EuyiH_uuqc)
- [キャラのウェイト方法](https://www.youtube.com/watch?v=HQ67uB_n4cQ)
- [一気にウェイトを塗る方法](https://katumi-umikaze.tumblr.com/post/120520926902/blender)
VLC for Android：楽曲管理画面の解析

# はじめに

VLC for Androidの楽曲管理画面を解析する。ゴールは登場するクラスの洗い出しと関連性のざっくりとした把握。

# 各種リンク

[アプリ](https://play.google.com/store/apps/details?id=org.videolan.vlc&hl=ja&gl=US)
[GitHub](https://github.com/videolan/vlc-android)
[公式サイト](https://www.videolan.org/index.ja.html)


# 楽曲管理画面のスクリーンショット

WIP

# 楽曲管理画面のオブジェクト図

こんな感じ。赤いオブジェクト図は楽曲管理部分
ざっくりいうとリポジトリクラスの状態を監視して、各モデルクラスのインスタンスを取り出してUIに反映している。

![Class Diagram0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39706/83175a3a-f2c3-dd9b-f08f-01b5a68c2f0b.png)

# 楽曲管理画面を構成する主なクラス

## UI部分

- AudioBrowserFragment：楽曲管理を表現するフラグメント
- AudioPagerAdapter：ジャンル、楽曲、アルバム、アーティスト用画面を切り替えるViewPager用のアダプター
- AudioBrowserAdapter：ビューページャが管理するRecyclerViewに紐づくアダプター。ジャンル、楽曲、アルバム、アーティスト用の４つある。
- AudioBrowserViewModel:〜Providerクラスのインスタンスを管理するViewModel
- ArtistsProvider:MediaLibraryを監視してArtistを供給する。
- AlbumsProvider:MediaLibraryを監視してAlbumを供給する。
- TracksProvider:MediaLibraryを監視してTrackを供給する。
- GenresProvider:MediaLibraryを監視してGenreを供給する。

## モデル部分

- MediaWrapper：音楽ファイルを表現する。
- Album:アルバムを表す。
- Arist:アーティストを表す。
- Genre:ジャンル
- MediaLibrary:上記４つのインスタンスを供給する。所謂リポジトリクラス。シングルトン。
Ubuntu カスタムリポジトリ セットアップ手順

# 背景
Ubuntu 18.04のcmakeのバージョンが古いので、最新版のパッケージを利用するためにカスタムリポジトリを作成する。

# 環境
- Ubuntu 18.04.5

```
$ cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.5 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.5 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic
```

# セットアップ手順
## 事前準備
```
$ sudo apt -y install dpkg-dev
```

## リポジトリ用ディレクトリ作成
```
$ sudo mkdir /home/customdpkgs
$ cd /home/customdpkgs
```

## パッケージ配置
```
$ sudo cmake_3.19.7_amd64.deb /home/customdpkgs/
```

## パッケージのスキャン
```
$ sudo dpkg-scanpackages . | gzip > Packages.gz
```

## ソースリスト作成
```
$ sudo vi /etc/apt/sources.list.d/customdpkgs.list
$ cat /etc/apt/sources.list.d/customdpkgs.list
deb [trusted=yes] file:///home/customdpkgs ./
```

## アップデート
```
$ sudo apt -y update
$ sudo apt -y install cmake
$ cmake --version
cmake version 3.19.7
```

# 参考文献

以下の文献の dpkg-scanpackages コマンドでは成功した。
https://wiki.debian.org/DebianRepository/Setup#dpkg-scanpackages_and_dpkg-scansources

以下の文献の dpkg-scanpackages コマンドでは `apt update` で失敗した。
https://www.percona.com/blog/2020/01/02/how-to-create-your-own-repositories-for-packages/

エラーメッセージは以下の通り。

```
Reading package lists... Error!
E: Read error - read (21: Is a directory)
E: The package lists or status file could not be parsed or opened.
```
Mac・Windowsで.mp4や.movを.gifに変換する

[FFmpeg](https://www.ffmpeg.org/)という動画と音声を記録・変換・再生するためのフリーソフト使用して簡単にできます。
FFmpegはMac・Windows共に使えるソフトなのでWindowsでも可能です。

brewを使ってインストールします。

```install.console
brew install ffmpeg
```

変換したい場合

```templete.console
ffmpeg 入力オプション -i 入力ファイル名 出力オプション 出力ファイル名
```

#### 例
入力ファイル: test.mp4
出力ファイル： test.gif

```ex.console
ffmpeg -i test.mp4 -r 24 test.gif
```

これで完了です！
プログラミングの初歩(1)


※この記事は、プログラミング未経験の方向けの記事です。
すでにプログラムを組まれているかたは退屈な内容かもしれません。




みなさん、こんにちわ

私はSE歴5年の、ごくごく一般的なサラリーマンです。
仕事を始めてからＩＴ系の勉強を始めましたし、IT業界に入ってからすぐにプログラミングができるようになった、いわゆる才能があるわけでもありません。

それでも今、多少プログラミングのことがわかりましたし、それで仕事もいただけています。
この知識が誰かの役に立つと思って、この記事を書くことにしました。




まず、これからプログラミングを勉強しよう、もしくはIT業界で仕事をしようと思っている人が悩みそうなことを考えてみました。

・ITってパソコンに詳しくないとできなさそう
・プログラムって理系の頭いい人にしかできなさそう
・パソコンのタイピング早くならなきゃいけない
・そもそもパソコンの操作が苦手
・首肩が凝りそう
・目が疲れそう　　　...etc


すいません、ほとんどが自分が思っていたことですｗ
で、またすいませんが目や首肩は疲れますｗｗ
ここは逃れようがないですね。。(´-ω-`)


ですが、それ以外についての答えとしては、

「ITってパソコンに詳しくないとできなさそう」
　⇒最低限、電源を入れて、インターネットのブラウザー(Internet ExplorerとかChromeとか)が使えれば、あとは追々覚えていくでもOK
　ブラウザーの使い方がわからないやパソコンを使ったことがない方は、まずはパソコン教室などに行くことをお勧めします。
　（おそらくこの記事が見れる人はそれなりに使える方だと思います）

「プログラムって理系の頭いい人にしかできなさそう」
　⇒プログラムに理系の要素ってほとんどありません。むしろ、プログラムは文字の記入するんで文系に近い面もあるとも言えます。
　処理としては合っていても、「なぜそう書いた・・・」みたいなプログラムもあったりします。。。

「パソコンのタイピング速いならなきゃいけない」
　⇒仕事の効率を上げる、という面で言えば速いほうがいいです。ですが、そのほうがいい、くらいのレベルです。
　　正直早くタイピングできても、よくタイピングをミスします。

「そもそもパソコンの操作が苦手」
　⇒使っていないだけで様々な機能がありますからね。。私も知らない機能があったりします。。
　　ただ、インターネットで調べることができれば、困ったときに調べればOKなことがほとんどです。








と、回答するとこのようになります。
偉そうに書いていますが、私もまだまだ勉強することが多いですし、新しい技術が日々出てきているので勉強しなくてもよくなることはないでしょう。
ただ、仕事をやりながら技術や知識をつければいいと個人的には思っています。
すべてを知ることはできないので、自分のやりたいこと、仕事に合った知識をやりながらつけていくということですね。これは別の業界でもいえることかもしれませんが。

この回答で、少しはIT・プログラミングに触れるハードルは下がっていればうれしいです。

私個人の経験をおおまかに語ると、
ほとんど何も知らない状態でIT企業に入り
未経験からでもできる仕事をやりながら少しづつ勉強して
本格的なSEの仕事ができるようになった。
という流れです。

これがおよそ５年ほどかかっています。

この５年が早いのか遅いのかは人それぞれの意見だとは思いますが、
５年で未経験・知識0からでもSEの仕事がそれなりにできるようになる、
と言えるのかなと思っています。



じゃあ次に出てくる疑問はおそらく

「じゃあプログラミングしたいけど、何すればいいの」

だと思います。

それについては、次回から説明できればと思います。



この記事に関して、ご意見や相談があればぜひぜひコメントをお寄せください。


では次に続きます。
Apache LDAP StudioのLDAP result code 49 invalidCredentialsエラーの対処法

#コネクション作成時にエラー発生
[@IT](https://www.atmarkit.co.jp/ait/articles/0710/03/news122_2.html)のサイトのような感じで、Apache LDAP StudioのLDAPサーバへの接続を作成をしようとした所、「The authentication failed [LDAP result code 49 invalidCredentials]」エラーが発生した。
![スクリーンショット 2021-03-21 15.50.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449478/2d24c96e-a2c5-b7da-7cc1-c3db440074ce.png)

#対処法
[環境構築：LDAPサーバ](http://hatman62.hatenablog.com/entry/2016/06/08/230701)のサイトに紹介されている[LDAPの構築　その１（インストール、初期設定）]
(http://christina04.blog.fc2.com/blog-entry-178.html)を参照。

Invalid Credentials(無効な資格情報)エラーは認証パラメータ情報の間違えで発生するエラーのため、`slapcat`コマンドで設定値を確認することができる。

`slapcat`で`dn:`以降の情報を認証パラメータのBindDn or userに入力。
![スクリーンショット 2021-03-21 16.00.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449478/b94e9678-b69e-a62c-7d73-c7c9e7ded864.png)
そうするとエラーは解消され、認証が成功する。
![スクリーンショット 2021-03-21 16.02.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449478/d90b8633-de4c-6fb1-458d-98c2529ebc23.png)
fetch API で POST したらエラー

Nest.jsで作ったAPIをReactからfetchしようとした時にエラーが出たので、その解決方法をメモします。

エラーの原因の結論は、データがうまく渡せていなかったからです。空で渡っていました。

##エラー内容
実行したのは大体こんな感じです

```App.tsx
async function addTodo() {
        const body = JSON.stringify({todo:todo,limit:limit})
        await fetch('http://localhost:3000/item',{
            method: 'POST',
            mode: 'cors',
            body: body,
        })
        .then(() =>{
            // 省略
        })
    }
```
POSTでfetchしたらエラーが出ました。

```
POST http://localhost:3000/item 400 (Bad Request)
```

##原因
エラー内容をしっかりと見ていってわかったこと。

* データが渡せていない(サーバー側で確認したら、空の配列になっていた)
* サーバー側で「not null」のバリデーションを付けているため、空のデータに対してエラー

##解決方法

ヘッダーにContent-Typeを指定して、Jsonであることを伝える事で解決

```App.tsx
async function addTodo() {
        const body = JSON.stringify({todo:todo,limit:limit})
        await fetch('http://localhost:3000/item',{
            method: 'POST',
            mode: 'cors',
            body: body,
             // =====↓追加====
            headers:{'Content-Type': 'application/json'}
             // =====↑追加====
        })
        .then(() =>{
            // 省略
        })
    }
```

これで、データをサーバー側で受け取ることができました。
無事、エラーがなくなりました。

##参考文献
[Fetch の使用](https://developer.mozilla.org/ja/docs/Web/API/Fetch_API/Using_Fetch)
未経験からエンジニア転職する際に準備しておきたかったこと

#はじめに
・以下の記事を発見して読ませていただいたところ共感できることが多く、エンジニア転職してから苦労したことを元に、入社前に準備しておけばよかったと思うことを書いてみます。
https://qiita.com/hnak0210/items/713839c3589599a95222

#簡単な経歴
・20代後半です。現在は未経験からバックエンドエンジニアに転職して3ヶ月ほど。
・前職でシステム企画の仕事をしていましたが、実装の部分の知りたいと思いエンジニアに転職しました。
・システム関連の経験があったのでとりあえず転職活動始めました。全て落ちたらポートフォリオ作成しようと思っていたら内定いただけたので結局作っておらず、全般的に実力が足りていないです。

#この記事で書くこと
バックエンドエンジニアとして仕事をする上で必須の知識、入社前に知っておきたかったことを重要度順に書いています。
※知ってて当たり前と思われるものも載せています。
※私の経験に基づくものなので全ての人に当てはまるわけではないです。

# 重要度【高】
たぶんどの現場でも重要です。絶対に知っておきたい範囲。
### 1. 現場で利用されるプログラミング言語の理解
現場で利用されているプログラミング言語の基本的な文法やFWについての理解は必須です。
現職ではpythonで開発を行っているのですが、同じ時期に入社された未経験の方はrubyの経験しかなかったようでだいぶ苦戦していました。
経験を積んでいる方であれば言語の違いは程度の差はあれど吸収できそうですが、実務未経験の場合は入社前に最低限の知識をつけておきたいです。

### 2. Git（Github・Gitlab）
1人で開発や学習しているときはあまり意識していなかったのですがGitの知識も必須です。
ステージング、コミット、ブランチ作成から、コンフリクト時の対応方法、`git reset`の使い方、リモートブランチへ影響辺りは絶対に知っておきましょう。（リモートのmasterブランチを破壊することは絶対にないように）
Gitを理解していないととても非効率なことをしてしまったり、なによりもパニックになってしまうので絶対に理解しておきたいです。

### 3. LINUX
高度なコマンドやオプション都度調べればよいのですが`cp`・`mv`・`ls`を始めとする基本操作は知っておきたいです。
できるだけ薄い入門書を一冊読みながら、実際に手を動かせると良いと思います。

### 4. サーバーの基本
基本的というと範囲が難しいですが、公開鍵および秘密鍵の生成・SSH接続・踏み台サーバーの利用・DNS・ポート番号・configファイルの設定辺りをなんとなく分かっていれば良いと思います。

# 重要度【中】
### 1. DB操作の基礎
「DML」の操作は知っている方が多いと思いますが、バックエンドエンジニアでは「DDL」や「DCL」の操作も必要になってくるので概要は知っておきたいです。

|区分  |正式名称  |主な操作  |
|---|---|---|
|DDL  |Data Manipulation Language  |SELECT, INSERT, UPDATE, DELETEなど  |
|DML  |Data Definition Language  |CREATE, DROP, ALTERなど  |
|DCL  |Data Control Language  |GRANT, REVOKE, COMMITなど  |


### 2. AWS
AWSが全く使われていない現場というのはほとんどないと思うので、以下の本の範囲を1周しておくと全然違うと思います。Linux同様に実際に手を動かせるならそれが良いです。

「Amazon Web Services 基礎からのネットワーク&サーバー構築 改訂3版」
www.amazon.co.jp/dp/4296105442

### 3. クライアントツール
ツールは人によって使っているものが異なっているため、教えてもらいづらいので自身で合うものを見つけるのが良いです。開発効率は高めていきましょう。

・ターミナルソフト
「iTerms2」は使いやすいです。

・GitのGUIアプリケーション
「Sourcetree」や「GitKraken」などいくつかあるので好きなものを1つ選びましょう。CUIでGit操作をしなくて良いのでかなり楽になります。

・エディタ
「Visual Studio Code」や「Atom」など好きなものを選びます。職場にエディタの宗教戦争があったら指示に従うと事を荒立てません。

・その他
ブラウザに「Google Chrome」を利用するなら「JSON Viewer」や「Wappalyzer」は入れておくと便利です。

# 重要度【低】

### 1. フロントエンドの基礎
バックエンド開発とはいってもフロントとのやり取りが生じるのでシア低減のHTML・CSS・JavaScriptの知識はあったほうが何かとやりやすいです。

### 2. 社内ツールの把握
社内で利用するツールなので先立って知る必要もないのですが、gmail・backlog・slack・JIRA・confluence辺りは結構メジャーだと思うのでもし社内ツールが事前に分かるなら触ってみると戸惑わないです。

### 3. Docker
最初は作成側でなくても良いと思うのですが、配布されたDockerを利用できるぐらいにはなっておくと良いです。

#最後に
これまで紹介したことを知らなかったとしても、もし転職できたのであれば早く環境に飛び込むのが一番良いのかもしれません。
結局実務で利用することになったら嫌でも学習せざるを得ないのでその方が身につくと思います。
ただ、基本的前提が無い中で現場に入ると同僚に迷惑をかけてしまったり、予想以上の負担になってしまうこともあります。また自身のメンタルもキツイです。
これらのことから、できれば入社前に知っておけばと思ったことを書いてみました。
1人でも参考になる方がいましたら幸いです。
デブキャン成果記録(2021.03.20)

3/20に参加したデブキャンの成果記録です。

## 1. 個人開発ツール
#### カレンダーぺージを追加
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697384/673a38ef-d610-d0da-710b-4fd98b67477e.png" width="60%">

まだまだ殺風景ですが、今後カレンダーに機能を追加していきます。
・予定を追加、管理できる
・アンケート結果を確認できる
・発表スライドを確認できる

## 2. オブジェクト指向プログラミングについて
社内輪読会で議論中の「オブジェクト指向」について、個人開発ツールと絡めて理解を深めていきたく改めて読み直ししました。

輪読会の記事はこちらから
https://qiita.com/michida/items/b3615d018fb88409f730
https://qiita.com/fumiya-uehara/items/2a0e521b725ef0a48e19

##### 以下の状態を目指してアウトプットしていきます。
- 「なんとなく分かった！」な感覚が多いので、自分の言葉で説明できるようになりたい。
- 分かった気になっても良いが、自分の中でしっくりくる言葉を持っている状態になりたい。

（もし解釈が違ったらご指摘頂けるとうれしいです🙇🏻‍♀️）

## ポリモーフィズム(多態性)とは
- 異なるクラスでも、「このクラスはこのインタフェースを持ちます！」といった記述をすることで、同じものとして扱うことができる
- ポリモーフィズムはインタフェースを使って実現すると良い

### ポリモーフィズムを使うと何が良いのか
- 呼び出す側は「処理がどこで何をしようがどんなところから値を取ってこようが」そんなことを意識せずに、思い通りの型・データを受け取れる
- インタフェースを挿入することでソースコードの制御の流れに関わらず、依存関係の方向を逆転することができる

### インタフェースとは
- クラスに実装する処理の約束事（シグネチャ：メソッド名、戻り値の型、引数の型）を宣言することで、「どんなデータを返す」を約束する
- インタフェースには処理の中身は実装しない




# まとめ
せっかくポリモーフィズムについて学んでるから使ってみよう！と使ってみたものの、
**開発規模や開発人数によって取り入れるべきか否かを判断する必要がある**ことを伺い、
今回の個人開発ツールの規模では不要と判断しました。

実際実装しているときも、恩恵を感じられず「ポリモーフィズムのメリットとは」と迷走してたので
先輩方に相談してよかった。。理解が深まりました。(たぶん)
【Swift】キーボードに合わせてViewをアニメーションさせる

キーボードに合わせてUITextFieldやUIViewをアニメーションさせたい時に、`animate(withDuration:animations:completion:)`でアニメーションさせようと思ったら上手く動かなかったので調べてみました。
`UIResponder`を使うと上手くいったので、困っている人は参考にしてみて下さい！

[サンプルコード(GitHub)](https://github.com/asa08/Keybord-animation)

こんな感じのが作れます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305854/09014928-b5f9-09de-1c9a-8e91396bb5d1.gif" width=40%>


## キーボードの表示・非表示を検知する
```swift
override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
    NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}

// Keybordが表示
@objc dynamic func keyboardWillShow(_ notification: NSNotification){

}

// Keybordが非表示
@objc dynamic func keyboardWillHide(_ notification: NSNotification){

}
```

## キーボードのアニメーションを抽出・アニーメーションを実行
```swift
@objc dynamic func keyboardWillShow(_ notification: NSNotification){
    // キーボードのdurationを抽出 *1
    let durationKey = UIResponder.keyboardAnimationDurationUserInfoKey
    let duration = notification.userInfo![durationKey] as! Double
    
    // キーボードのframeを抽出する *2
    let frameKey = UIResponder.keyboardFrameEndUserInfoKey
    let keyboardFrameValue = notification.userInfo![frameKey] as! NSValue
    
    // アニメーション曲線を抽出する *3
    let curveKey = UIResponder.keyboardAnimationCurveUserInfoKey
    let curveValue = notification.userInfo![curveKey] as! Int
    let curve = UIView.AnimationCurve(rawValue: curveValue)!
 
    let animator = UIViewPropertyAnimator(duration: duration, curve: curve) {
        // ここにアニメーション化したいレイアウト変更を記述する
        animations?(keyboardFrameValue.cgRectValue)
        self.view?.layoutIfNeeded()
    }
        
    animator.startAnimation()
}
```
*1 [キーボードのduration](https://developer.apple.com/documentation/uikit/uiresponder/1621600-keyboardanimationdurationuserinf)
*2 [キーボードのframe](https://developer.apple.com/documentation/uikit/uiresponder/1621578-keyboardframeenduserinfokey)
*3 [アニメーション曲線](https://developer.apple.com/documentation/uikit/uiresponder/1621613-keyboardanimationcurveuserinfoke)

### レイアウト設定時の注意
textFieldなどをキーボードの上にくっつけて表示したい場合はレイアウトの設定を`Safe Area`に合わせると`Safe Area`分の空白はキーボードとViewの間にできてしまうので注意です。
こんな感じで`Super View`に合わせましょう！
![スクリーンショット 2021-03-21 15.32.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305854/bea1840d-5858-db62-4388-17c33b47fb86.png)


これをUIViewControlleなどで`extension`して共通で使えるようにするのがおすすめです。
怪文書で自己紹介に対して返信する

　ゼミの自己紹介で`Pythonやってます！`と言っていた人が居たので、怪文書コードで返信しようとした。
　以下コード

```Python3
a = [[875079.8095873848], [-2882947.5355600277], [4056234.642952851], [-3283373.044987327], [1728271.5227123285], [-631498.0970303839], [166468.3240147154], [-32394.07511043425], [4710.754802641195], [-513.6959614565977], [41.7881579194053], [-2.496902614930717], [0.10632426026426153], [-0.0030523592139228553], [5.292142586414675e-05], [-4.184215771782444e-07]]
print(*['%s'%chr(round(sum(a[j][0] * i ** j for j in range(len(a))))) for i in range(1,len(a)+1)], sep='')
```
　実行すると

```
Nice to see you.
```

　と表示される。

## 日本語で喋りましょう

　print文内は以下のように書き換えられる。

```Python3

for i in range(1,len(a)+1):
    letter_code = 0
    for j in range(len(a)):
        letter_code += a[j][0] * i ** j
    print(chr(round(letter_code)), end='')
```

　Pythonでは`chr(num)`で、numに対応したASCIIコードの文字に変換できる。つまり、一文字づつASCIIコードを計算し、それを表示している。
　計算式は`len(sentence)`次の方程式になるが、それもPythonでよしなに計算できる。ただし16次までしか計算できないっぽいので、送れる文字数の最大数は16文字になる。
　コード内変数`a`を求めるコードは以下。

```Python3
import numpy as np

sentence = 'Nice to see you.'

targetList = [ord(i) for i in sentence]
length = len(targetList)
a = [[i**j for j in range(length)] for i in range(1,length+1)]

a = np.matrix(a)
y = np.matrix([[i] for i in targetList])

ans = np.linalg.solve(a,y).tolist()
print(ans)
```

## 感想
　行列で計算したものをそのままリストにしてたけど、普通に考えて2次元リストは1次元リストに変換してからやればよかった。
　１次元リストに変換するならこうなる

```Python
import numpy as np

sentence = 'Nice to see you.'

targetList = [ord(i) for i in sentence]
print(len(targetList))
length = len(targetList)
a = [[i**j for j in range(length)] for i in range(1,length+1)]

a = np.matrix(a)
y = np.matrix([[i] for i in targetList])

ans = np.linalg.solve(a,y).tolist()
print([i[0] for i in ans])
```

```python

a = [875079.8095873848, -2882947.5355600277, 4056234.642952851, -3283373.044987327, 1728271.5227123285, -631498.0970303839, 166468.3240147154, -32394.07511043425, 4710.754802641195, -513.6959614565977, 41.7881579194053, -2.496902614930717, 0.10632426026426153, -0.0030523592139228553, 5.292142586414675e-05, -4.184215771782444e-07]
print(*['%s'%chr(round(sum(a[j] * i ** j for j in range(len(a))))) for i in range(1,len(a)+1)], sep='')

#わかりやすいほう
for i in range(1,len(a)+1):
    letter_code = 0
    for j in range(len(a)):
        letter_code += a[j] * i ** j
    print(chr(round(letter_code)), end='')

```
初心者がAidemyにてPythonを学んでみた

#【はじめに】
私は基盤系SEです。
日々業務の過程でプログラミングに興味を持ち、今後のスキルアップを目標としAidemyにてPythonを学びました。その経緯と結末をまとめます。
プログラミングに興味を持っているが、オンライン学習が高くて迷っているという方はぜひ参考にしてください。

#【経緯】
Pythonは独学にて勉強をしていましたが、限界を感じていました。
ネットを参照しても何を言ってるかよくわかりませんでした（笑）
その時たまたまAidemyを見つけましたが、とにかく受講料が高い！！
ですが、教育訓練給付金制度を知り、「この機会しかない！」と思い即決で申し込みました。

#【学習の振り返り】(3ヵ月コース)
・1ヶ月目 
なにもできませんでした（笑）
他のことが忙しく、環境を構築したぐらいでした。
・2ヶ月目 
月末になってから本格的に勉強しました。
内容は基礎～様々なモジュールの使用方法です。(Numpy等)
・3ヶ月目
ここからはモジュールの使用方法～ディープラーニングを使用したAIまで一気に勉強しました。
・振り返って
少し触っていた他にVBA等他の言語でプログラミング自体は触っていたので、最初のほうは苦ではなかったです。ただ、応用を用いた課題と直面した時、アルゴリズムは思い浮かぶけどコードがきちんと書けない場面が多々ありました。(おそらく期限的に焦っていたのもあります)
そんな時にエラーの意味、改善点等をわかりやすく・かつ詳細に説明していただき、理解することに繋がりました。
何とか一通り期間内に理解して終了することが出来ました。

#【成果物】
以下は住宅価格データセットを用いた価格予測のためのプログラムです。
よろしければ参考にしてください。

(必要モジュールをインポート)
import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Activation, Dense, Dropout, Input, BatchNormalization
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.datasets import load_boston
import matplotlib.pyplot as plt
%matplotlib inline

(データセットの読み込み)
boston=load_boston()
X = boston.data
Y = boston.target

(テストデータとトレーニングデータに分割)
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.25, random_state=42)
model = Sequential()

(ディープラーニングによるモデルの構築)
model.add(Dense(256, input_dim=13))
model.add(Activation("sigmoid"))
model.add(Dense(128))
model.add(Activation("sigmoid"))
model.add(Dropout(rate=0.5))
model.add(Dense(1))
model.compile(loss='mse', optimizer='adam')
​
​(モデルによるテストデータの学習)
history = model.fit(X_train, y_train, epochs=64 , batch_size=32 , verbose=1, validation_data=(X_test, y_test) )

(予測値を算出)
y_pred = model.predict(X_test)

(二乗誤差を使用した性能評価)
mse= mean_squared_error(y_test, y_pred)
print("REG RMSE : %.2f" % (mse** 0.5))


#【まとめ】
結論としてとても有意義でした。
反省点としては、時期を見誤って時間に追われた学習だったため、サービスを十分に活用できなかったと思います。
ただ、一人では苦戦していたものがこんな短時間で理解できるようになるとは思いませんでした。
もしオンライン学習に迷っている方がいる方はぜひ一度お試しください。
【SAA試験対策】EC2 インスタンスタイプについてまとめてみた

#概要
SAAの模擬試験対策の自分用のメモ
EC2のインスタンスタイプが覚えれないのでまとめてみました

#ネーミングポリシーについて

インスタンスタイプの表記は以下の通り


```
[ファミリー][世代](追加機能).[サイズ]
```

t2.microの場合
　t：ファミリー
　2：世代
　micron：サイズ
となる

・**世代**・・新しい方が高性能でコストパフォーマンスも高いため、極力最新世代のインスタンス利用が推奨されている
・**サイズ**・・以下のネーミング順で大きくなる。サイズが1段大きくなるにつれ、vCPU、メモリのサイズが倍もしくはインスタンスサイズ名の係数に応じて倍増、価格もそれに比例して増加する

```
nano→ micro→ small→ medium→ large→ xlarge→ 2xlarge→ 4xlarge・‥
```

#インスタンスファミリー
汎用、コンピューティング最適化、メモリ最適化、ストレージ最適化、高速コンピューティングの5つのカテゴリに分類されるため、処理するワークロードに合わせて選択する

|カテゴリ| 特徴| ユースケース|ファミリー
|:-----------:|:-----------:|:------------:|:------------:|:------------:|:------------:|
|汎用 |CPU・メモリ・ネットワークのバランスが取れている|開発環境、Web、マイクロサービス|T,M,A,Mac|
|コンピューティング最適化| 計算パフォーマンスが高い | 高性能Webサーバ・バッチ処理、科学モデリング、機械学習、広告配信、ゲーム|C |
|メモリ最適化| メモリ量が多くて高速処理が可能|ハイパフォーマンスDB、インメモリDB、ビックデータ処理|R,X,z|
|ストレージ最適化| ストレージアクセスが速い（＝I/Oパフォーマンスが高い）|分散ファイルシステム、NoSQLデータベース、Apache Kafkaなどのログ分析|I,D,H|
|高速コンピューティング|GPU(スーパーCPU)が搭載|機械学習、深層学習|P,G,F,Inf

##汎用
|ファミリー|覚え方|特徴|
|:-----------:|:-----------:|:------------:|
|T|**T**urbo（ターボ）|CPUクレジットを蓄積し、必要な時だけバーストさせる機能をもつ|
|M|**M**iddle（バランスが良い中間）|さまざまな場面で利用可能。全インスタンスファミリーの中で基準となる
|A|**A**rm|通常より最大45%コスト削減できるArmプロセッサをもつ
|Mac|**M**ac（そのまんま）|Apple Mac mini をもつ

##コンピューティング最適化
|ファミリー|覚え方|特徴|
|:-----------:|:-----------:|:------------:|
|C|**C**ompute|計算パフォーマンスが高い|


##メモリ最適化
|ファミリー|覚え方|特徴|
|:-----------:|:-----------:|:------------:|
|R|**R**AM(Random Access Memory)|メモリ最適化
|X|**メ**モリのメ＝X（無理やり）|EC2インスタンスの中でメモリあたりの価格が最も低い
|z|周波数H **z** |高速な最大 4.0 GHz の持続的な全コア周波数を提供

##ストレージ最適化
|ファミリー|覚え方|特徴|
|:-----------:|:-----------:|:------------:|
|I|**I**/O|低レイテンシー、極めて高いランダム I/O パフォーマンスのSSDをもつ
|D|H **D**D|最大48TBのHDDをもち、高ディスクスループットを実現する
|H|**H**igh disk throughput|最大16TBのHDDをもち、高ディスクスループットとバランスの取れたCPU・メモリをもつ

##高速コンピューティング
|ファミリー|覚え方|特徴|
|:-----------:|:-----------:|:------------:|
|P|G **P**U|	汎用 GPU 搭載
|G|**G**raphic|	グラフィックスなどの画像描写に最適化
|F|**F**PGA|FPGAカスタマイズ可能
|Inf|**Inf**erence（推論）|機械学習の推論に最適化

GPU（Graphics Processing Unit）・・グラフィックス処理や画像処理に適した内部構造を持つプロセッサ
FPGA（Field Programmable Gate Array）・・ デバイス内の電子制御機能の大部分を変更できる半導体 IC 

#参考
詳細は公式サイトをご確認ください

[Amazon EC2 インスタンスタイプ](https://aws.amazon.com/jp/ec2/instance-types/)
[Amazon EC2インスタンスタイプの選び方ガイド](https://pages.awscloud.com/rs/112-TZM-766/images/C2-07.pdf)
pymysql.err.OperationalError: (1193, "Unknown system variable 'tx_isolation'")

## sqlalchemy 利用時にMySQLに接続できなくなった場合

- sqlalchemyの再インストール

```
% pip uninstall sqlalchemy 
% pip install sqlalchemy 
```

MySQLのバージョンを5.x系から8.x系にあげた場合などに起こるようです。