OmniAICreator/Qiita-1.07M huggingface dataset:
対象OSのポート(開閉状態)を外部からnmapで確認する方法

#環境
 ■ポートの開閉を確認したいOS
Amazon Linux2
 ■ポートの開閉を確認するためのOS
Ubuntu（ver 16.04.4)

#初めに
Amzon linux2にiptablesを用いてポートにフィルタリングをかけます。
その後、他OS(Ubuntu)のNmapを利用してポートのフィルタリングを確認する方法を備忘録として記載します。
今回は、25、80、111番のポートにフィルタリングをかけます。

参照サイト
https://knowledge.sakura.ad.jp/4048/
https://qiita.com/Tocyuki/items/6d90a1ec4dd8e991a1ce

#iptables、Nmapの導入
まず初めにAmazon Linux2にiptablesを導入します。
Amazon Linux2でiptablesを利用するにはiptables-servicesが必要ですのでyumを使ってインストールします。

```
yum -y install iptables-services
```

そうすると、/etc/sysconfigの配下に２つのファイルが生成されます。

```ruby:/etc/sysconfig
$ ls | grep iptables
iptables
iptables-config
```

次に、Ubuntu(ポートの開閉を確認するためのOS)にNmapを導入します。

```
sudo apt-get install -y nmap
```

#何も設定していない状態のAmazon Linux2のポート番号を確認

```
$ nmap localhost

Starting Nmap 6.40 ( http://nmap.org ) at 2021-03-29 12:47 JST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.0000030s latency).
Not shown: 995 closed ports
PORT    STATE SERVICE
22/tcp  open  ssh
25/tcp  open  smtp
80/tcp  open  http
111/tcp open  rpcbind
443/tcp open  https

Nmap done: 1 IP address (1 host up) scanned in 0.03 seconds
```
ポート番号22、25、80、111、443番がopenになっていることを確認。
25、80、111番のポートにフィルターをかけてみます。

#ポート番号にフィルターをかける

viで先ほど生成されたiptablesファイルを編集します。

```ruby:/etc/sysconfig
$ vi iptables

～略～
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
```
デフォルトでは上記のような構造になっています。
iptablesには４つのテーブルが存在し、今回はfilterテーブルに記載します。

*filterとCOMMITの間に設定を記載します。

それでは25、80、111番のポートにフィルターをかける設定をしていきます。

```ruby:/etc/sysconfig
$ vi iptables

～略～

-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j DROP　　　・・・この行を追記
-A INPUT -p tcp -m state --state NEW -m tcp --dport 25 -j DROP　　　・・・この行を追記
-A INPUT -p tcp -m state --state NEW -m tcp --dport 111 -j DROP　　 ・・・この行を追記

COMMIT
```

一番右に記載してあるDROPでポート番号にフィルターをかけて、パケットを通さない設定です。
対してACCEPTは通信可能な設定になっています。

viを保存してiptablesを再起動します。

```
/sbin/service iptables restart
```

UbuntuのNmapを利用して確認してみます。

```
$ nmap -p 80,22,111,25,443 -Pn Linux2の使用しているIPアドレス
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2021-03-29 16:02 JST
Nmap scan report for linux-practice.example.com (Linux2の使用しているIPアドレス)
Host is up (0.0013s latency).

PORT    STATE    SERVICE
22/tcp  open     ssh
25/tcp  filtered smtp
80/tcp  filtered http
111/tcp filtered rpcbind
443/tcp open     https

Nmap done: 1 IP address (1 host up) scanned in 1.25 seconds

```
これで25、80、111番にフィルターがかかっていることを確認できました。

以上になります。
ありがとうございました。
Github 初push時のエラー ~ src refspec main does not main any

githubで新しくプロジェクトを作成して、ローカルの物をpushしようとした時に遭遇するエラーの解決方法のメモです。

#手順/エラー内容

githubで新しくプロジェクトを作成すると以下の表示が見つかります。

```
…or push an existing repository from the command line
git remote add origin git@github.com:.........
git branch -M main
git push -u origin main
```
従って実行すると、以下の様なエラーになってしまいます。

###git branch -M main 時のエラー

```
$ git branch -M main
error: refname refs/heads/master not found
fatal: Branch rename failed
```

###git push -u origin main 時のエラー

```
$ git push -u origin main
error: src refspec main does not main any
error: failed to push some refs to 'https://github.com/.../.git'
```

#解決方法

###git branch -M main 時のエラー
git checkout -b でブランチを作れます。

```
git checkout -b main
``` 
これでmainブランチに行けます。

###git push -u origin main 時のエラー

git add して

```
git add .
```
コミットします。

```
git commit -m 'First Commit'
```

すると、無事にpushできる様になります。

###参考資料
[【Git】初プッシュ時にsrc refspec master does not match anyとエラーになる](https://www.mtioutput.com/entry/git-pusherror-refspec)
Html.ActionLinkを使うとhrefに「?Length=4」がついてしまう

##起こったこと
Viewで@Html.ActionLinkを使ってaタグを作成すると、hrefに「?Length=4」がついてしまう。

```C#:CSHTML
@Html.ActionLink("About", "About", "Home", new { @class = "btn btn-primary" })
```

##原因
コントローラーを直で書いているのが原因みたい。
>string routeValuesのオブジェクト「Home」を取得します。MVCはこれをパブリックプロパティを検索してルート値に変換します。stringオブジェクトの場合、唯一のパブリックプロパティはLengthであり、Lengthパラメータでルートが定義されないため、プロパティ名と値がクエリ文字列パラメータとして追加されます。

##対処
string controllerNameにべた書きせずにstring routeValuesに設定する。

```C#:CSHTML
@Html.ActionLink("About", "About", new { controller = "Home" }, new { @class = "btn btn-primary" })
```
[JavaScript] いつものタグ入力UIを、少し簡単にするTagify

# Tagify

2021年のトレンドになっているらしいのでやってみた。

https://iainfreestone.hashnode.dev/10-trending-projects-on-github-for-web-developers-12th-march-2021

## ドキュメント

### 公式
https://yaireo.github.io/tagify/
### GitHub
https://github.com/yairEO/tagify

## サンプル

<p class="codepen" data-height="500" data-theme-id="light" data-default-tab="css,result" data-user="shikumiya_hata" data-slug-hash="yLgJZze" style="height: 500px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Tagify">
  <span>See the Pen <a href="https://codepen.io/shikumiya_hata/pen/yLgJZze">
  Tagify</a> by ハタユウジ@コーポレートエンジニア (<a href="https://codepen.io/shikumiya_hata">@shikumiya_hata</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>

```html:html
<p>
  <label for='tags'>1. テキストボックス内にタグ</label>
  <input id="tags" name='tags' value='javascript, ライブラリ' autofocus>
</p>
<p>
  <label for='tagsOutside'>2. テキストボックスの外にタグ</label>
  <input id='tagsOutside' name='tags-outside' class='tagify--outside' value='javascript, ライブラリ' placeholder='タグを書くのもwhitelistから選択もできる'>
</p>
<p>
  <label for='tagCustom'>3. 見た目カスタマイズ</label>
  <input id="tagCustom" class='customLook' value='javascript, ライブラリ'><button type="button">+</button>
</p>
```

※CSSは長いので省略

```javascript:js
/* 1. テキストボックス内にタグ */
var inputInside = document.querySelector('input[name=tags]');
var tagifyInside = new Tagify(inputInside);

/* 2. テキストボックスの外にタグ */
var inputOutside = document.querySelector('input[name=tags-outside]');
var tagifyOutside = new Tagify(inputOutside, {
  whitelist: ['javascript', 'js', 'ライブラリ', 'library'], //デフォルトで選択可能なタグ候補
  dropdown: {
    position: "input",
    enabled : 0 
  }
});

/* 3. 見た目カスタマイズ */
var inputCustomLook = document.querySelector('.customLook'),
    tagify = new Tagify(inputCustomLook, {
      dropdown : {
        position: 'text',
        enabled: 1
      }
    }),
    button = inputCustomLook.nextElementSibling;

button.addEventListener("click", onAddButtonClick)

// ＋ボタン押下時
function onAddButtonClick(){
    tagify.addEmptyTag() // 新しいタグを追加
}

```

ちなみに、valueを取り出すとこんな風になってます。

```javascript:value
[
  {"value":"javascript"},
  {"value":"ライブラリ"}
]
```
いい感じのランダムの色が欲しいなぁって時にこれ。

例えば10個のいい感じのランダムの色が欲しいって時。
ガチのランダムにすると意味わからない変な色が出来上がったりしてしまうので。
っていうものをメモ程度に残しておきます。
意外と使える！

hueの部分の分母を欲しい個数にするだけです。
saturationとbrightnessに関しては自分の好みの色味にしてください。

下記コードそのまま使用した際にはこんな感じの色が出力されます。
~~似てる色があるとか言わないで~~
`#CC8B29`
`#ABCC29`
`#49CC29`
`#29CC6A`
`#29CCCC`
`#296ACC`
`#4929CC`
`#AB29CC`
`#CC298B`
`#CC2929`

```swift.swift
let colorList = 
   [
    UIColor(hue: 0/10, saturation: 0.8, brightness: 0.8, alpha: 1),
    UIColor(hue: 1/10, saturation: 0.8, brightness: 0.8, alpha: 1),
    UIColor(hue: 2/10, saturation: 0.8, brightness: 0.8, alpha: 1),
    UIColor(hue: 3/10, saturation: 0.8, brightness: 0.8, alpha: 1),
    UIColor(hue: 4/10, saturation: 0.8, brightness: 0.8, alpha: 1),
    UIColor(hue: 5/10, saturation: 0.8, brightness: 0.8, alpha: 1),
    UIColor(hue: 6/10, saturation: 0.8, brightness: 0.8, alpha: 1),
    UIColor(hue: 7/10, saturation: 0.8, brightness: 0.8, alpha: 1),
    UIColor(hue: 8/10, saturation: 0.8, brightness: 0.8, alpha: 1),
    UIColor(hue: 9/10, saturation: 0.8, brightness: 0.8, alpha: 1)
   ]
```

```java.java
    /*
    * いい感じの色のリストを指定数分作成する
    * colorCount: 色の数
    * brightness: 色味 0.0~1.0
    * */
    private int[] createRandomColorList(int colorCount, float brightness) {
        float [] f = new float[3];
        f[1] = brightness;
        f[2] = brightness;
        int[] cList = new int[colorCount];
        for (int i = 0; i < colorCount; i++) {
            f[0] = 360f * (i+1)/colorCount;
            cList[i] = Color.HSVToColor(f);
        }
        return cList;
    }

```
PyCharmショートカットキー

よく使うPyCharmのショートカットキーを整理していきます。

## 移動

### メソッドやクラスに移動

`Ctrl` + `B`

### タブ移動

`Alt` + `←` or `→`

## 検索

### ファイル内検索

`Ctrl` + `Shift` + `F`

### クラス検索

クラス名で検索する。

`Ctrl` + `N`

### ファイル検索

ファイル名で検索する。

`Ctrl` + `Shift` + `N`

## リファクタリング

### ファイルのフォーマット

PEP8に合わせてフォーマットする。

`Alt` + `Shift` + `Enter`

### 名前変更

ファイル名・変数名・メソッド名などを変更する。

`Shift` + `F6`

### import追加

`Alt` + `Enter`

### import最適化

`Ctrl` + `Alt` + `O`

## 実行

### RUN

`Shift` + `F10`

### RERUN

`Ctrl` + `F5`
プログラミング未経験新卒の1スプリントルーティーン

こんにちは！3度の飯より牛タン好きなFRです！
2020年の春からSEとして働き始めました。 
去年の夏頃にアジャイル開発専門のユニットに配属されました。その時の私の心境は正直に言うと、(え？アジャイルって何？)がずっと頭の中でぐるぐるしている状況でした。
当初は右も左も、上も下もわからない状態でしたが、約半年間アジャイル開発チームに参加したことでアジャイル開発のあれこれが分かってきました！
そこで今回は1スプリント中に私のチームが取り組んでいることについて取り上げてみました。
また、プログラミング未経験新卒がSEとしてアジャイル開発チームに入り、学んだことや気付いたことも書いてみました。
SEとして働く新社会人や、これからアジャイル開発やってみるぞ！という方の参考になれば嬉しいです。



## 用語集 

今回の記事で出てくる用語についてここでざっくり解説していきます。 



### アジャイル

開発手法の一つです。一つのプロジェクトをある一定の期間に区切り、その期間の中で開発を行い、成果物を毎回リリースします。リリースを繰り返すことで全体の完成度を上げていきます。

私たちのチームはアジャイル開発の一つである「スクラム」という手法で開発を進めています！

 

### スプリント

一つのプロジェクトを一定の期間で区切る時の区切り。私たちは2週間を1スプリントとしています。

 

### プロダクトバックログリファインメント

お客様の要望をリスト化し、優先順位が付けられているものを「プロダクトバックログ」と言います。そのプロダクトバックログをお客様と共有し、次回以降のスプリントで何をやるのかを決めていくのがプロダクトバックログリファインメントです。

 

### ポイント

プロダクトバックログの中に入っている一つ一つのアイテムが、それぞれどれくらいの作業量なのかを示すものです。

 

### レビュー

スプリント内で出来た成果物をお客様にレビューしてもらいます。また、次のスプリントのゴールもこの時間に決めます。

 

### 振り返り

スプリント内での活動を改善するために、良かった点・課題・解決策をチーム全員で共有していきます。

私たちはKPT法というやり方で振り返りを行なっています！

 

 

## 1スプリント内のルーティーン

いよいよ本題です！1スプリント内で私のチームは一体何をしているのかについてお話ししていきます！
用語集にも書いた通り、私たちの1スプリントは2週間です。この2週間の中で2つの案件を並行して行っています。 

![1スプリント.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1250958/c07515fc-41c6-0bd3-9036-ec60e54a9443.png)


### 《1週目 水曜日》プランニング

私たちの1スプリントは水曜日から始まります。スプリントの初めは必ずプランニングを行います。
今回のスプリントでやることを確定させ、その後タスクの洗い出しを行うことをプランニングと言います。

タスクの洗い出しを行うことで、今スプリントでやるタスクを細かく分解し、優先順位をつけることができます。これらを行うことでやるべき事が段々ハッキリと見えてきます。そのため、この時間中はとにかく話し合います。「この機能を追加するためには何が必要なんだろう？」であったり、「何をテスト観点に書くべきなんだろう？」などの疑問点を事細かく議論し、メンバー全員が仕様について理解することが重要です。

タスクの洗い出しが終わった後は、優先順位の高いタスク作業をどんどん行なっていきます。



### 《1週目 金曜日》プロダクトバックログリファインメント

時が少し飛び、次は金曜の午後です！毎週火曜と金曜に案件の打ち合わせがあります。(この記事では毎週金曜にある打ち合わせについてのみ記載しています。)この日はプロダクトバックログリファインメントを行います。

打ち合わせが始まる数時間前にチーム内で次回以降のスプリントでやるタスクについて話し合います。また、この時タスクにポイントが付いていない時はその場でポイントを付けていきます。

いよいよプロダクトバックログリファインメントの時間です！ここではお客様から次スプリント以降でやりたい要望を確認していきます。私のチームでは、このタイミングで現在のチームの進捗状況や仕様についての確認なども行っています。

私はこの時間、メンバーと一緒に議事録を取っています。タスクの洗い出しの時にこの議事録が役に立ちます。

打ち合わせが終わった後は再びタスクをコツコツと消化していきます。

 

### 《2週目 金曜日》レビュー

時は流れ、いよいよレビューの日です。この日はテスト作業やデプロイ作業など、レビュー前の準備でだいたい大忙しです。
もちろんチーム内の話し合いも忘れてはいけません。誰がどの機能について説明するのかや、次回のスプリントで着手する予定のタスクを決めたりします。

レビューの時間です。自分が機能説明をする時間はなかなか緊張します！自分が説明しない時はしっかりと議事録を取っていきます。

 

### 《2週目 金曜日》振り返り

無事にレビューが終わり、すっかり夕方になりました。やった！一週間終わり！...ではありません！！
スプリントの終盤には振り返りを行います。私たちのチームはだいたい2週目金曜のレビュー後にやっています。
チーム内の動きで良かったこと・見直した方がいいこと・次スプリントで試してみることをじっくりと考えていきます。振り返りを終わらせることで1スプリントが終わります。(正確には2週目の火曜にあるレビューで終わりです。)

この2週間を繰り返し、アジャイル開発を続けています。

 

 

## 気付いたこと・学んだこと

-  チーム全体の様子を見ること


振り返りでチームの全体の動きで良かった点・悪かった点を挙げるため、それまでは自分のことで精一杯だった私も常にチーム全体を見るようになりました。

 

-  タスクの洗い出しが一番大事

ここでタスクを出しきれないと、やらなきゃいけないタスクを作業中に発見することになってしまいます。(経験あり)

それをなるべく減らすためにも、この時間はとにかく話し合います。

 

-  程よいおしゃべりも大切


私たちはテレワーク期間中、一日中通話を繋いで作業を行なっています。チームメンバーと話しやすい環境で作業をしているので、休憩中はよく趣味の話や最近起きた出来事について話しています！
チーム内で打ち解けることで、話し合い時間に積極的に意見を言えるようになりました。
自分の中では心地良い作業環境だなと思っています。

 

 

## おわりに

いかがでしたか？

今回はアジャイル開発のリアルな日常をお伝えしました。!
これからもアジャイル開発のあれこれについて、より深く学んでいきたいと考えています。
flutter runでError launching application on iPhone.

#エラー

```
$ flutter run
```
すると

```
Error launching application on iPhone.
```
と表示されてしまう。
実機でのビルド自体はでき、インストールされた状態になるが、上記のエラーが表示されてしまうため、Hot reload等ができない。

#解決法

Xcodeを開き、メニューからWindow -> Devices and Simuratorsでウィンドウを開き、ビルドしたい端末を右クリック。

Unpair device

もう一度実行で解決。

（デバイスがBusyだよってのが原因ぽい。）
【MySQL】複数のカラムで重複しているデータを見つける方法

データ解析に使ったので、メモ
サブクエリ内では、countを実行するだけ。
メインクエリ内では、countが１以上のものは重複していると言えるので、以下のような形でできる。

```sql
select * from (
	select concat(column1, '-', column2) as token,
		COUNT(*) as cnt
		FROM table_name GROUP BY (token)
) as contents WHERE cnt > 1;
```

解析に使っただけだが、実際のプロダクションコードとしてで扱うには、あまりよくない気がする。
TerraformでAWS RDSのDBユーザを管理する

# はじめに

MySQLやPostgreSQLのユーザをTerraformで管理するときの備忘録としてこの記事を残します。

# 前提条件

基盤はAWS、DBはPostgreSQLでDBがいるネットワークは内部ネットワークでインターネットのアクセスがないです。TerraformはローカルPC(Mac)から実行するものとします。

# 実行方法

## Terraform

[こちら](https://registry.terraform.io/providers/cyrilgdn/postgresql/latest/docs)のPostgreSQL用のTerraform providerを使い実行します。

```bash
provider "postgresql" {
  scheme   = "awspostgres" # AWSを使う場合はこれを指定
  host     = var.db_host
  username = "postgres"
  port     = 5432
  password = var.db_password

  superuser = false
}

```

バージョンはこのように指定します。

```bash
  required_providers {
    postgresql = {
      source  = "cyrilgdn/postgresql"
      version = "1.11.2"
    }
  }
```

PostgreSQLのユーザを追加します。

```bash
resource "postgresql_role" "my_role" {
  name     = "my_role"
  login    = true
  password = var.my_role_password
}

resource "postgresql_grant" "readonly_my_role" {
  database    = "test_db"
  role        = postgresql_role.my_role.name
  schema      = "public"
  object_type = "table"
  privileges  = ["SELECT"]
}
```

## ローカル

ローカルから直接PostgreSQLを触ることはできないので、踏み台サーバを経由してSSHトンネリングすることで、アクセスします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/575547/70da608c-9875-39e6-54c3-140b0ff2fb61.png)

sshトンネリング用のコマンドを実行します。

```bash
# ssh -N -L [ローカル側で転送に使用するPort（10000〜60000）]:[DBのHostName]:[DBが解放しているPort] -i [IdentityFile（秘密鍵のパス）] -p [踏み台が解放しているPort] [踏み台のUser]@[踏み台のHostName]

ssh -N -L 5432:test_db.XXX.ap-northeast-1.rds.amazonaws.com:5432 -i ~/.ssh/bastion.pem -p 22 ec2-user@XXX

```

後述するSSL証明書エラーになるので、ホストを偽装します。
 `/etc/hosts` に `localhost 127.0.0.1 test_db.XXX.ap-northeast-1.rds.amazonaws.com` を追加してください。

これでTerraformを実行するとPostgreSQLへのユーザ追加ができます。

## Tips
### SSL証明書エラー
上記に記載されているsshトンネリングコマンドを実行し、

```bash
ssh -N -L 5432:test_db.XXX.ap-northeast-1.rds.amazonaws.com:5432 -i ~/.ssh/bastion.pem -p 22 ec2-user@XXX
```

sshトンネリングで `localhost`の `5432`ポートにアクセスするとPostgreSQLにアクセスできるようになったので、Terraformのproviderのhost名を `locahost`に指定して、Terraformを実行させます。

```bash
provider "postgresql" {
  scheme   = "awspostgres" # AWSを使う場合はこれを指定
  host     = "localhost"
  username = "postgres"
  port     = 5432
  password = var.db_password

  superuser = false
}
```

そうすると、SSL証明書の確認でホスト名が異なるとエラーが出てしまいます。

```bash
Error: error detecting capabilities: error PostgreSQL version: x509: certificate is valid for stg-knew-rds.coh5dxpjppgc.ap-northeast-1.rds.amazonaws.com, not localhost
```

### セッションマネージャーを使ったポートフォワード
セッションマネージャーを使ってポートフォワードができないかと調べたが、
結局ポートフォワードはできなかった。

cf. https://dev.classmethod.jp/articles/port-forwarding-using-aws-system-manager-sessions-manager/
gemの特定のバージョンが配信停止になった時の対処法(the author of mimemagic 0.3.5 has removed it)

## エラー文

```bash
Fetching gem metadata from https://rubygems.org/............
Your bundle is locked to mimemagic (0.3.5), but that version could not be found
in any of the sources listed in your Gemfile. If you haven't changed sources,
that means the author of mimemagic (0.3.5) has removed it. You'll need to update
your bundle to a version other than mimemagic (0.3.5) that hasn't been removed
in order to install.
```

大事な部分切り取る

```bash
that means the author of mimemagic (0.3.5) has removed it. You'll need to update
```

## 解決方法

```
bundle update mimemagic
```
Pythonで月末・月初を取得

メジャーな方法は下記２パターン
・カレンダーで最終日を取得して組み合わせる
・翌月の１日前を計算する

翌月の１日前を計算する方が個人的にしっくりくるので書いてみた

```python
from datetime import date,timedelta
#月末は「翌月初日の1日前」として計算する
year = 2021
for month in range(1,13):
  month_first_day = date(year,month,1) #月の初日
  #date関数は月の引数に13以上が入ると1~12に収めろとエラーするので対応
  if month == 12: exec_year = year + 1; next_month = 1
  else: exec_year = year; next_month = month + 1
  next_month_first_day = date(exec_year,next_month,1) #翌月の初日
  month_end_day = next_month_first_day - timedelta(days=1) #月の最終日(翌月の初日-１日)
  print(str(year)+'年'+str(month).zfill(2)+'月の月初＝'+str(month_first_day))
  print(str(year)+'年'+str(month).zfill(2)+'月の月末＝'+str(month_end_day))
```

実行結果

```bash
2021年01月の月初＝2021-01-01
2021年01月の月末＝2021-01-31
2021年02月の月初＝2021-02-01
2021年02月の月末＝2021-02-28
2021年03月の月初＝2021-03-01
2021年03月の月末＝2021-03-31
2021年04月の月初＝2021-04-01
2021年04月の月末＝2021-04-30
2021年05月の月初＝2021-05-01
2021年05月の月末＝2021-05-31
2021年06月の月初＝2021-06-01
2021年06月の月末＝2021-06-30
2021年07月の月初＝2021-07-01
2021年07月の月末＝2021-07-31
2021年08月の月初＝2021-08-01
2021年08月の月末＝2021-08-31
2021年09月の月初＝2021-09-01
2021年09月の月末＝2021-09-30
2021年10月の月初＝2021-10-01
2021年10月の月末＝2021-10-31
2021年11月の月初＝2021-11-01
2021年11月の月末＝2021-11-30
2021年12月の月初＝2021-12-01
2021年12月の月末＝2021-12-31
```
JavaのObjectはObjectかとか

# クイズとか
またもや突然クイズです。
**「Javaにおいて、全ての配列およびクラスは暗黙的にObjectクラスを継承している」**
YESかNOか

# 答えとか
これ、自分もよくこういうことを言ってしまっていますし、[日本語のJavaDoc](https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Object.html)読んでみたら
>Objectクラスは、クラス階層のルートです。すべてのクラスは、スーパー・クラスとしてObjectを持ちます。配列を含むすべてのオブジェクトは、このクラスのメソッドを実装します。

と書いてありますし。

が、**答えはNO**です。

Javaにおいて、全ての配列およびクラスは暗黙的にObjectクラスを継承しているわけではありません。
**例外がある**んです。

# 例外のクラスとか
例外となるクラスはObjectクラスです。
**ObjectクラスはObjectを継承しません**。
そりゃそーですよね。
Object extends Objectとかやったら
Objcet::newを実施→super();→Object::newを実施→super();→以下略
と、コンストラクタが無限再帰しちゃいます。
"GNU's Not Unix!"みたいになっちゃう！

# 何を継承してるのかとか
そうすると、気になるのは**Objectクラスが何を継承しているか**ですよね。
特にObject::new後。
そういうわけで、コードで確認してみました。
```java
System.out.println(new Object().getClass().getSuperclass().toString());```
>Exception in thread "main" java.lang.NullPointerException

**ぬるぽ**

# おまけとか
ついでなので[Javaの言語仕様](https://docs.oracle.com/javase/specs/jls/se16/html/jls-4.html#jls-4.3.2)を見てみましょう。
>The class Object is a superclass (§8.1.4) of all **other** classes. 
「Objectクラスは**"他の"**全てのクラスのスーパークラスである」

ちゃんと書いてあった！
pyenvでインストール時に「BUILD FAILED (OS X 10.15.7 using python-build 20180424)」が発生した場合の対処法


# 概要
macのpyenvでpythonをインストールしようとした際に、以下のエラーが発生しました。
以下の手順で動くようになったので、対処法を記載します

## エラー内容
```zsh
$ pyenv install 3.5.6
　:
　:

python-build: use openssl@1.1 from homebrew
python-build: use readline from homebrew
Downloading Python-3.5.6.tar.xz...
-> https://www.python.org/ftp/python/3.5.6/Python-3.5.6.tar.xz
Installing Python-3.5.6...
python-build: use readline from homebrew
python-build: use zlib from xcode sdk

BUILD FAILED (OS X 10.15.7 using python-build 20180424)

```

## 対処法
エラーメッセージに従い、zlibを追加して環境変数に追加することで解決しました

- brewでzlibをインストールする

```zsh
$ brew install zlib
　:
　:
######################################################################## 100.0%
==> Pouring zlib-1.2.11.catalina.bottle.tar.gz
==> Caveats
zlib is keg-only, which means it was not symlinked into /usr/local,
because macOS already provides this software and installing another version in
parallel can cause all kinds of trouble.

For compilers to find zlib you may need to set:
  export LDFLAGS="-L/usr/local/opt/zlib/lib"
  export CPPFLAGS="-I/usr/local/opt/zlib/include"

For pkg-config to find zlib you may need to set:
  export PKG_CONFIG_PATH="/usr/local/opt/zlib/lib/pkgconfig"

==> Summary
🍺  /usr/local/Cellar/zlib/1.2.11: 12 files, 376.4KB
```

- シェルの設定ファイルに加える  
※zsh以外のシェルを使用している場合、対応する設定ファイルに追記して下さい

```
$ echo 'export LDFLAGS="-L/usr/local/opt/zlib/lib"' >> ~/.zshrc
$ echo 'export CPPFLAGS="-I/usr/local/opt/zlib/include"' >> ~/.zshrc
$ echo 'export PKG_CONFIG_PATH="/usr/local/opt/zlib/lib/pkgconfig"' >> ~/.zshrc
```

- ターミナルを再起動する  
  ※　下記のようにsourceコマンドで設定ファイルを再読み込みしても可能

```
$ source ~/.zshrc
```

## 参考サイト
https://github.com/aws/aws-elastic-beanstalk-cli-setup/issues/76
ゼロからのOS自作入門をMacで勉強する方法 (Docker使用)

# ゼロからのOS自作入門をMacで読み進めたい

https://www.amazon.co.jp/%E3%82%BC%E3%83%AD%E3%81%8B%E3%82%89%E3%81%AEOS%E8%87%AA%E4%BD%9C%E5%85%A5%E9%96%80-%E5%86%85%E7%94%B0-%E5%85%AC%E5%A4%AA/dp/4839975868

本書ではLinux(Ubuntu)を開発環境に選んでおり、
WindowsのWSLを使った方法を紹介しているが、Macでの方法は記載されていなかった。

## 私の環境
* macOS Big Sur(ver. 11.2.2)
* Docker Engine v20.10.2

## Docker上で環境を作っていく

Docker上のUbuntuでビルドしたOSをQEMUで起動させることにした。

### 今回作ったDockerfile

```
$ cat works/os/Dockerfile
```
```
FROM ubuntu:18.04

MAINTAINER meruneru

ENV IMAGE_NAME=MikanOS

RUN apt-get update
RUN apt-get install -y  vim \
                        build-essential \
                        python3 \
                        git \
                        okteta \
                        tmux \
                        dosfstools

# https://github.com/uchan-nos/mikanos-build
RUN cd $HOME; \
    git clone https://github.com/uchan-nos/mikanos-build.git osbook; \
    apt install -y ansible; \
    cd $HOME/osbook/devenv; \
    ansible-playbook -K -i ansible_inventory ansible_provision.yml

CMD ["/bin/bash"]

```

### Dockerfileからイメージを作成する
```
$ docker build -t os works/os
```


### Docker内のGUIアプリをMacOS側に出力するために・・・
XQuartz(X11サーバ)を別途インストールし、XQuatzの環境設定のセキュリティタブで、
"ネットワーク・クライアントからの接続を許可"にチェックを入れておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15085/b7bd27ec-f0eb-7ce1-478d-80f42d0dacd0.png)

### Dockerイメージを起動する

以下のコマンドでOSを起動させることができる。
起動後に書籍に載っているコマンドがインストールされていれば、環境構築完了:sunny:

コマンドが長いので、私は下記ファイルをシェルスクリプトにして起動してる。



```
docker run -it --rm \
           --privileged \
           -e DISPLAY=$(hostname):0 \
           -v ~/.Xauthority:/root/.Xauthority \
           -v $HOME/works/os:/root/os/ \
           os

```
【JDBCドライバ】MySQL Connector/J 8.0ダウンロード手順

##はじめに
自身がJava学習中にDB接続の環境を整える際に悩んだので、
JDBCドライバのダウンロードから環境のセットアップまでを記載します。

##使用環境
開発環境：paizacloud
Javaバージョン：13.0.1
Apache Tomcatバージョン：9.0.41
DB：MySQL
JDBCバージョン：8.0.23

##１．JDBCのインストーラーダウンロード

https://dev.mysql.com/downloads/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573636/75f58bb3-950c-f08c-b5b5-2f2b70bc9ffa.png)
------------------------------
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573636/5d49a746-5048-6b92-f23b-0ee244462728.png)
------------------------------
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573636/a8630a36-cf9d-b0c2-15e6-2ea05265b56b.png)
------------------------------
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573636/72a2939e-a89d-5eea-18cd-629337e6f372.png)
------------------------------
##2.インストーラ起動

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573636/fa8cdf9b-f829-cfda-0764-23eeb5b10759.png)
------------------------------
##3.connect/Jをダウンロード

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573636/a53b1074-dbe6-0579-5ef9-9edde8edef0f.png)
＜ファイルダウンロード先（例）＞

```
C:\Program Files (x86)\MySQL\Connector J 8.0\mysql-connector-java-8.0.23.jar
```
##4.jarファイルを配置
ダウンロードしたドライバ（jarファイル）をWEB-INF\libに配置する。


##5.Javaには下記のように記載する。
ドライバ名がバージョンで異なるそうです。

####ドライバのバージョンが8.0系の場合

```
Class.forName("com.mysql.cj.jdbc.Driver");
```

####※ドライバのバージョンが8.0系よりも前の場合

```
Class.forName("com.mysql.jdbc.Driver");
```

##参考

https://support.asteria.com/hc/ja/articles/360019113133-JDBC%E3%83%89%E3%83%A9%E3%82%A4%E3%83%90%E3%83%BC-MySQL-Connector-J-8-0-%E3%82%92%E4%BD%BF%E3%81%86%E3%81%A8%E3%81%8D%E3%81%AE%E6%B3%A8%E6%84%8F%E7%82%B9%E3%81%AF%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%81%8B-
備忘録 - ワークブック・シートの指定・操作【VBA】

##ワークブックの指定方法

```vb
ThisWorkBook 'マクロが書かれているワークブック
ActiveWorkBook　'現在アクティブのワークブック
Workbooks("ワークブック名.xlsm")　'パスは含めず、拡張子も記載する。ワークブックを開いていないと指定できない。
```

##ワークシートの指定
```vb  
コードネーム　'コードネームの前でワークブックを指定しない
Worksheets("ワークシート名") 'タブの名前を用いる（ワークブックを指定可）
ActiveSheet '現在アクティブのワークシート
```
##現在アクティブのワークブックの名前・パスを調べる
 
```vb  
ワークブック.Name　'ファイル名を表示
ワークブック.Path  'ファイルまでのパスを表示
ワークブック.FullName　'パスとファイル名を表示
```

##ワークブックを開く

```vb 
Application.Workbooks.Open "パスとファイル名"
```

##ワークブックを閉じる
```vb 
ワークブック.Close

'保存して閉じる
ワークブック.Close SaveChanges:=True
```

##ワークブックを保存する
```vb
ワークブック.Save
```

##ワークブックを新たに追加する
Addメソッド

```vb
Dim NewBook As Workbook
Set NewBook = Workbooks.Add
```

##ワークシートを新たに追加する
Addメソッド

```vb
Dim NewSheet As Worksheet
Set NewSheet = NewSheets.Add

'名前を付ける
NewSheet.Name = "名前"
```
【エラー】自動デプロイの際のエラー【AWS】

# Aws::Sigv4::Errors::MissingCredentialsError

アプリを自動デプロイした際、下記のようなエラーが出現。
※アプリのサーバには、EC2、unicorn、Nginxを利用

```
Aws::Sigv4::Errors::MissingCredentialsError: Cannot load `Rails.config.active_storage.service`:
missing credentials, provide credentials with one of the following options:
  - :access_key_id and :secret_access_key
  - :credentials
  - :credentials_provider
```

※上記のエラー内容は下記の方法にて確認した。
 （ターミナルにて、EC2にログインし下記コマンドを入力。）

```
[ec2-user@ip-000-00-0-000 アプリ名]$ cd current
[ec2-user@ip-000-00-0-000 current]$ cd log
[ec2-user@ip-000-00-0-000 log]$ cat unicorn.stderr.log
```

# 結論
EC2の環境変数にAWSのアクセスキーが設定がされておらず、デプロイ時にActive storageが読み込まれなかった事が原因。

【EC2に環境変数の設定を行う方法】
EC2にログインした状態で下記コマンドを入力。

```
[ec2-user@ip-000-00-00-000 ~]$ sudo vim /etc/environment
```
i を入力し、入力モードに変更。

```
AWS_ACCESS_KEY_ID='Access key ID'
AWS_SECRET_ACCESS_KEY='Secret access key'
```

アクセスキーの入力が完了したら、「esc」キー　→　「:wq」の順に入力。
設定した環境変数が反映されているかを確認する為、exitコマンドにてログアウト。

```
[ec2-user@ip-172-31-23-189 ~]$ exit
```
Okta で LINE WORKS に SSO

LINE WORKS は SAML での認証連携ができます。この記事では Okta での SSO 設定手順を説明します。

# 1. Okta の設定

1.1 Okta の管理画面で、[Applications] のページで [Add Application] のボタンをクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/d363dca1-cdeb-dd34-c1d3-a66653f74ec6.png)

1.2 [Search..] で LINE WORKS を検索し、選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/a913987d-d0d6-18e5-f607-8fc64450e757.png)

1.3 [Add] ボタンをクリック。 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/384bbfdc-e4d4-eaec-4484-b325d3803f95.png)

1.4 General Settings のページで [Done] ボタンをクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/d83b5558-0a22-f547-e092-11aad097c343.png)

1.5 Sign On タブを開き、[Edit] をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/06a3d4e5-3000-1879-23a1-3013e28e1f4d.png)

1.6 Advanced Sign-on Settings の Domain name に LINE WORKS のグループ名/ドメイン名を指定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/65757aba-9857-31da-2fc3-50b6118b02d4.png)

1.7 [View Setup Instructions] をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/f58ab0eb-9547-fc66-cd4f-34b5f0e98e8a.png)

1.8 Okta 社の設定手順解説 (英語) ページが表示される。ページ下方にスクロールすると、Login URL, Logout URL や証明書のダウンロード リンクが表示される。
それぞれ、後述の LINE WORKS Developer Console での作業手順で必要なためメモやファイルのダウンロードを実施。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/04fad533-d419-68db-a802-7e6788cbb73e.png)

1.9 [Assignments] タブで [Assign] ボタンをクリックし、People または Groups に LINE WORKS の利用者を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/1ad3f90a-44c0-8bb1-9c4a-4805026d0095.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/d87aa36a-f5fe-f968-d113-d1f4d7ad7ea6.png)

# 2. LINE WORKS Developer Console の設定
2.1 LINE WORKS の Developer Console にアクセス。
[SSO] のページで [SSO Type] を設定。
SAML を選択
Web Login URL, Logout URL -> 1.8 の手順でメモした URL
Certificate File -> 1.8 の手順でダウンロードした Certificate ファイルの拡張子を .pem に変更してアップロード。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/1a3cf705-68f4-5b67-37fe-bb38b5ea3696.png)


2.2 [適用] ボタンをクリック。
なお、この操作でログイン中のユーザーはログアウトされます。
再ログインには Okta での認証が必要となります。

Developer Console のログイン中の管理者は、ログアウトされません。
このまま、LINE WORKS ユーザーの External Key の設定作業を行います。

#3. LINE WORKS 管理画面の設定
管理画面のメンバー ページでメンバーの修正をクリック。
SSO の設定により [External Key] の入力欄が表示されるようになっています。
ここに、メンバーに紐づく Okta のユーザー名を指定。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/1f94272e-afe4-2faa-140c-2f441eb8f859.png)

以上で設定は完了です。
Kubernetes の環境を作りたい [Raspberry Pi 編 2]

[2021/3/31 追記]
32 bit のイメージで作業を進めてしまったところ Docker のインストールでどんづまったので 64 bit でやり直すことにしました。

(64 bit: aarch64)
http://ftp.yz.yamagata-u.ac.jp/pub/linux/centos-altarch/7.9.2009/isos/aarch64/images/

(32 bit: armhfp(armv7l))
http://ftp.yz.yamagata-u.ac.jp/pub/linux/centos-altarch/7.9.2009/isos/armhfp/
※ 以下の記事で利用したもの。


前回

https://qiita.com/yosukei3108/items/c6f49d4d3477427124d2

<h1> Raspberry Pi のキッティング </h1>
前回イメージを書きこんだ microSD カードを使って Raspberry Pi をまずは単体で動作できる状態にしていきます。
行き当たりばったりなので、状況によってはイメージから選びなおさないといけなくなるかもしれないけどまぁヨシ。

とりあえず、複数台あってネットの情報も豊富そうな 3 B+ から行こうかな。


(届いた Raspberry Pi 達の様子。ｵﾎｰｰｰｯ!!!!!!)
![Pi34_s.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616231/551a6153-8d2a-fec6-e802-2d8481310c2d.jpeg)

パーティションのリサイズについてはこちらの記事を参考にさせていただきました。

https://qiita.com/revsystem/items/9989a18116e554c133b6

また、各ノード初回ログオン時に root のパスワードは変更するようにしています。
特に外部向けに運用する予定はないですが、習慣として。

```console
# passwd
```

ついで、とりあえず更新できるものは更新しておきます。

```console
# yum update
```
ちなみにですが、-y はよく知らない状況では使わないようにしています。
今回で言えば、yum update が初回なので gpg-key のインポートについて確認されたりしますね。じゃあ、fingerprint とか全部つぶさに確認してるかっていうと、してないんですけど。。。

<h1> ノードの設定 </h1>
やっとこの環境固有の設定に入ります。

Pi 3 B+ についてはワーカー ノードとして有線 LAN のみ利用予定のため、Wi-Fi は無効 (既定) のまま利用します。

参考にしている『入門 Kubernetes』ではマスター ノードを DHCP サーバーとしていますが、今後ワーカー ノードの電源オン/オフの順序が一意であるとは限らないので全部 static に以下のようにしてしまいます (全て /24) (何か理解が間違っているような気もする。。)。
各ノードの hosts ファイルにもこの内容を記述しておきます。

10.0.0.10 kubernetes
10.0.0.11 node-1
10.0.0.12 node-2
10.0.0.13 node-3

ネットワーク周りの設定にあたって調べてみると、ifconfig は今触ってるイメージでは使えてるけど、非推奨なんですね。。

https://i-think-it.net/centos7-ip-setting/

https://server.etutsplus.com/centos-7-network-configuration/

上記のページ等を参考にしつつ、nmcli で設定を行いました。

```console
# nmcli d
DEVICE          TYPE       STATE      CONNECTION
eth0            ethernet   connected  Wired connection 1
(略)

# nmcli c mod "Wired connection 1" ipv4.addresses 10.0.0.11/24
# nmcli c mod "Wired connection 1" ipv4.gateway 10.0.0.10
# nmcli c mod "Wired connection 1" ipv4.method manual
# nmcli c mod "Wired connection 1" ipv6.method ignore
```
(CONNECTION が普通に空白を含んでいるんですが、そういうものなんでしょうか、、、?)

ホスト名については hostnamectl コマンドを使いました。

```console
# hostnamectl set-hostname node-1
```
このへんで一度再起動しておきます。

で、設定がうまく入っているかの確認ですが、よくわからなかったので結局 /etc/sysconfig/network-scripts/ifcfg-Wired_connection_1 というファイルの中を見て確認しました。。


これを 3 台分繰り返したら、マスター ノードの設定です。

が、ちょっと休憩。

なんかよくわかんなくなってきた。
一旦マスター ノードの作業に移ろう。

ということで続く。

https://qiita.com/yosukei3108/items/f2dad9b18e66ae4024f8
RDSの自動起動と自動停止スクリプト

RDSは起動しっぱなしだとお金がかかる。

しかし、停止しても7日後に再度起動してしまう。

特に検証用とかで使用しない間が多い場合、いちいち起動したら停止するという運用はかなり面倒。

そのため、検証時以外は、起動したらすぐ停止するというスクリプトを作成して、**無駄なコスト**がかからないようにする。

そこで使用するのが、AWSのLambdaを使う。

## Lambdaとは何？

Lambdaと聞いてもわからないので調べた。

AWSの「サーバレスコンピューティングとアプリケーション」と言われる。

これまではPHPやPythonをうごかすためのwebサーバーが必要だったが、Lambdaならサーバーレスのため、サーバーを準備しなくても環境が揃っていると言うことである。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255267/1235389f-8f51-f11f-ea6b-dc23ef67432e.png)


**LambdaはJava、Node.js、C#、Pythonのプログラミング言語に対応しているので、各種「機能」（プログラム）はこの言語で開発すればOK、ということのようです。**

「S3にアップされた画像のサムネイル化」で考えると、S3に画像ファイルがアップされるのを監視するためのサーバを用意して、監視し続けるプログラムを用意して、ファイルがアップされたことを検知したら、リサイズする処理を行う必要があったのが、Lambdaならこの「リサイズする処理」だけを作ればOKということ。

今回はこのLambdaを利用し、指定された時間に関数を実行すると言うことを実装し、RDSの起動停止を自動で実施する。

## 流れ

### IAMによるロール(権限)作成

IAMページでロールの作成を実施。

「信用されたエンティティの種類を選択」については、「AWS サービス」を選択。「このロールを使用するサービスを選択」は「Lambda」を選択します。

![https://www.t3a.jp/wp-content/uploads/2019/09/rds_auto_start_stop_iam3-1024x480.jpg](https://www.t3a.jp/wp-content/uploads/2019/09/rds_auto_start_stop_iam3-1024x480.jpg)

Attach(アタッチ)する権限ポリシーは、

・CloudWatchFullAccess

・AmazonRDSFullAccess

### Lambdaの設定でStartとStopの関数を作成

Lambdaで関数を作成する。関数はStartとStopの二つ。

スクリプトは下記を登録する。

```php
import boto3

region = 'ap-northeast-1'

instance = 'RDSインスタンス名'
def lambda_handler(event, context):
    rds = boto3.client('rds', region_name=region)
    rds.start_db_instance(DBInstanceIdentifier=instance)
    print('started instance: ' + instance)
```

```php
import boto3

region = 'ap-northeast-1'

instance = 'RDSインスタンス名'
def lambda_handler(event, context):
    rds = boto3.client('rds', region_name=region)
    rds.stop_db_instance(DBInstanceIdentifier=instance)
    print('stoped instance: ' + instance)
```

また、関数起動を自動でやるため、cronで動かすようにも設定する。

cronによる起動はトリガーの追加で「CloudWatch Events」を選択する。

**〇RDS の起動時間**

```php
cron(15 23 */6 * ? *)
```

**〇RDS の停止時間**

```php
cron(45 23 0/6 * ? *)
```

### テスト

起動が大丈夫かをテストできる。

失敗したらスクリプトをチェックする。

## RDS 自動停止を実装する際の実行時間の考え方

設定に関して少し蛇足になりますが、RDS インスタンスが7日後に再起動する仕様について。

コストを下げる基本的な考え方として、AWS 側のシステムで再起動を発生させないことが良いと思います。

そのため一定時間ごとに RDS を起動して1時間以内に停止命令を送る実装をすれば良いです。

**※aws は1時間以内の起動時間は1時間の使用としてコストが計上されるため**

そこで今回は6日間隔で1時間以内の起動と停止を繰り返す設定を行っています。

つまり毎月1日、7日、13日、19日、25日、29日にスクリプトを実行します。

## 参考記事

https://www.t3a.jp/blog/infrastructure/rds-auto-start-stop/
Nest.js/TypeORMでエラー ~ Cannot use import statement outside a module

以下を使っています。
マイグレーションファイル作成時にエラーが出たので、その解決方法をメモ。

* Nest.js
* Typeorm
* postgres

#エラーまで
マイグレーションファイルを作成しようと以下のコマンドを実行したらエラーが出ました。

```
npm run build
npx typeorm migration:generate -d src/migrations -n create-item
```

#エラー内容
エラー内容は以下の通りです。

```
..........src/entities/item.entity.ts:1
import {
^^^^^^

SyntaxError: Cannot use import statement outside a module
```

#解決方法

entitiesとmigrationsの探しに行く場所を
コンパイル後のjsに変更することでエラーが解消されました。

```ormconfig.json
{
    "type": "postgres",
    "host": "localhost",
    "port": 5432,
    "username": "root",
    "password": "password",
    "database": "test_db",
    "entities": ["src/entities/**/*.ts"], 
    "migrations": ["src/migrations/**/*.ts"],
    "logging": true,
    "synchronize": false
}
```
以下の様に編集

```ormconfig.json
{
    "type": "postgres",
    "host": "localhost",
    "port": 5432,
    "username": "root",
    "password": "password",
    "database": "test_db",
    "entities": ["dist/entities/**/*.entity.js"],
    "migrations": ["dist/migrations/**/*.js"],
    "logging": true,
    "synchronize": false
}
```

無事に実行されました。

###参考資料
[Githubのnestのissuesを参考](https://github.com/nestjs/nest/issues/4283)
[NestJSで簡単なtudoリストを実装するチュートリアル](https://taroosg.io/nestjs-tutorial)
vuexのgettersでstateをフィルタリングする方法

stateにあるJSONデータ、もしくはactionsで持ってきたデータをフィルタリングする方法。
今回はそもそもバックエンド側でフィルタリングしようねという話になったので、自分の環境では使用しなかった。
でもせっかく組んだし、もったいないので共有します（あんまり使い道は無いだろうけど・・・）

```
export const getters = {
    getFilteringList: (state) => (query) => {
      // queryの形式を[{key:'',value:''}...]に変換する
      let conversion = Object.entries(query).map(([key, value]) => ({'key': key, 'value': value}))
      // 条件に合致したデータを返す関数を定義（every関数なので、全てに合致する必要がある）
      function isMatchToAllConditions(data, conditions){
        return conditions.every(c => data[c.key] == c.value)
      }
      // null以外の要素を取り出す
      const conditions = conversion.filter(q => q.value && q.key)
      // フィルターをかける
      const searched = state.data.filter(list => {
        return isMatchToAllConditions(list, conditions)
      })
      // 出力
      return searched
    }
  }
```

getFilteringListにはコンポーネント側でqueryを投げてあげる必要がある。
ShapeファイルをPostGISに投入して結合する

# 概要
大量のShapeファイルをPostGISを使って結合する手順です。DockerでPostGIS環境を作成してデータベースにShapeを格納した後、一つのShapeファイルに書き出します。

## DockerによるPostGIS環境の構築
使用するPostGISコンテナーのdocker-compose.yml

```yaml
version: '3'
services:
    db:
        image: postgis/postgis:9.6-2.5-alpine
        ports: 
         - '5431:5432'
        environment:  
            POSTGRES_USER: postgres
            POSTGRES_PASSWORD: postgres-password
        volumes: 
         - pgdata:/var/lib/postgresql/data
         - ./data:/var/tmp/data

volumes: 
    pgdata: {}
```



## Shapeファイルをデータベースに格納する。
以下のようなスクリプトを作成し、フォルダ内の.shpファイルをPostgreSQLデータベースに格納しました。引数で結合させるShapeファイルの名称を与えて、findで取得した.shpファイルを処理しています。

最初のファイルの時に、-pオプションで格納するShapeのテーブルを作成しています。

```sh
shp2pgsql -p -s 4326 -W UTF-8 ${file} base_${var} > ./sqlbase/base_${var}_create.pgsql
```

作成したSQLファイル（.pgsql）をpsqlで実行してテーブル作成、その後Shapeファイルをテーブルに格納しています。shp2pgsqlの-DオプションでCOPYコマンドで格納します。INSERTよりも高速とのこと。

```sh
shp2pgsql -a -D -s 4326 -W UTF-8 ${file} base_${var} > ./sqlbase/base_${var}_data${count}.pgsql
```


```sh
var=$1
count=0
while read -d $'\0' file; do

    echo $var $count

    if [ $count = 0 ]; then
        shp2pgsql -p -s 4326 -W UTF-8 ${file} base_${var} > ./sqlbase/base_${var}_create.pgsql
        psql -U postgres -d shape -f ./sqlbase/base_${var}_create.pgsql
    fi
    shp2pgsql -a -D -s 4326 -W UTF-8 ${file} base_${var} > ./sqlbase/base_${var}_data${count}.pgsql
    psql -U postgres -d shape -f ./sqlbase/base_${var}_data${count}.pgsql

    count=`expr $count + 1`

done < <(find Basemap -name *$var.shp -mindepth 1 -maxdepth 5 -print0)
```



## PostgreSQLからShapeを出力する



```sh
bash-5.0# pgsql2shp -u postgres -f ./basemap_join/base_xda.shp shape base_xda
Initializing...
Done (postgis major version: 2).
Output shape: PolyLine
Dumping: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```
ラズパイのSDカードが壊れた？ときの対処

# 経緯
24時間/365日で動作させていたラズパイが、気が付いたらデスクトップ背景＋マウスポインタだけになっていた（マウスポインタは動かず）ので、再起動してみました。

しかし以下のメッセージを表示して、起動しない．．．:qiitan-cry:

```test
[   11.366974] mmc0: timeout waiting for hardware interrupt.
[   21.606972] mmc0: timeout waiting for hardware interrupt.
[   31.846972] mmc0: timeout waiting for hardware interrupt.
[   31.849236] print_req_error: I/O error, dev mmcblk0, sector 64614380
[   42.086972] mmc0: timeout waiting for hardware interrupt.
[   42.089241] print_req_error: I/O error, dev mmcblk0, sector 64614381
（以下省略）
```

調べたところ、メッセージの通り、SDカードに問題がある模様です。

なお、使用しているSDカードは「SanDisk Ultra microSDXC 128GB UHS-1 CLASS10」、ラズパイは「Raspberry Pi 3 Model B+（放熱フィン追加、ケースあり）」、OSは「Raspbian GNU/Linux 10 (Buster)」です。

# 対応
## SDカードの抜き挿し
何はともあれ、SDカードの抜き差しをする。が、起動しない。
接触部分を拭いてみるが、変化なし。

## OS再インストール
ハード的に壊れてる場合は意味がないけど、とりあえずOS（Rasbian）を再インストールしてみる。
ラズパイ起動時、「Shift」キー押下でBIOSメニューが表示され、そこから再インストールができます。
（ちなみに、このGUIから、起動時の設定等も変更できますが、今回はそのあたりは変更しませんでした）

当然のことながら、OSはバージョンアップされてしまいました。
（今回は10.8になりました）

# 結果
OSを再インストールしたら、なぜか起動できるようになった！
ハードの故障ではなかったのか．．．
何だったんだ、あのエラーメッセージは？

# その後
初期化されてしまったので、いろいろ設定を復帰させ、現在は無事に運用中。

でもきっと、また同じことが起きると思うので、この記録を残しておくことにしました。
firebase-admin を用いて最も単純な Firebase Cloud Firestore のデータを取得するコードサンプル

# 動機

Firestore のデータを取得する単純な事例があまり見当たらず、本家の資料を見てもいまいちピンとこなかったので、`firebase-admin` を使った最も単純なコードを書きたくなったため。

# 実行環境と利用ツール

- [Ubuntu 20.04.2.0 LTS (Focal Fossa)](https://releases.ubuntu.com/20.04/)
- [Node.js](https://nodejs.org/en/)
    - バージョンは 14.16.0
- [Firebase Admin SDK](https://firebase.google.com/docs/admin/setup)

# Cloud Firestore 設定

まずはじめに Firebase コンソール（Web）から `books` コレクションと自動 ID を割り振ったドキュメントを作成します。

内容は極めて単純にしたかったので string 型の `title` というフィールドのみ追加します。

最後、値は `javascript` としています。

完成形の画面のスナップショットを貼っておきます。

![Firestore data m.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191117/ae71cbbb-6754-35e0-2c07-b9cb886034f7.png)

# コレクション内のドキュメントを取得する最も単純なコード

```javascript

// Ref : https://www.freecodecamp.org/news/the-firestore-tutorial-for-2020-learn-by-example/

const admin = require('firebase-admin');

const serviceAccount = require('./firestore-data-modeling-96db0-firebase-adminsdk-n3i63-0670471cc1.json');

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount)
});

const db = admin.firestore();

const booksRef = db.collection('books');

// console.log(booksRef.get());

booksRef
  .get()
  .then((snapshot) => {
    const data = snapshot.docs.map((doc) => ({
      id: doc.id,
      ...doc.data(),
    }));
    console.log(data); 
    // [ { id: 'FY7PJJTw7EsS8x2hYphv', title: 'javascript' } ]
  });

```

# 実行結果

コード中にも記載がありますが JSON オブジェクトの配列を返します。

```javascript
$ node books.js
[
  { id: 'FY7PJJTw7EsS8x2hYphv', title: 'javascript' }
]
```

# 参考資料

[The JavaScript + Firestore Tutorial for 2020: Learn by Example](https://www.freecodecamp.org/news/the-firestore-tutorial-for-2020-learn-by-example/)
「;」や「\n」のあるなしで処理が変わるんだと実感した話

##この記事で解決できるかもしれないエラー
`SyntaxError: Unexpected identifier`
JavaScriptだと珍しくないエラーのようです。[Blockly](https://developers.google.com/blockly/)を使っている時にこのエラーが出た際はこの記事が参考になるかもしれません。

## プログラムの流れ
### ブロックを作成するファイル
Blocklyを使ってLOGOのようなビジュアル言語を作成しています。
![スクリーンショット 2021-03-29 10.17.54.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549093/31872a10-8c93-90c1-6c53-21bb9e4639a4.jpeg)

ブロックの定義はこんな感じ

```javascript:turtleBlock.js
Blockly.Blocks['turtleforward'] = {
  init: function() {
    this.appendDummyInput()
        .appendField("前に")
        .appendField(new Blockly.FieldNumber(0, -10, 10), "step")
        .appendField("進む");
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(60);
 this.setTooltip("");
 this.setHelpUrl("");
  }
};
```

実行されたの動きはこんな感じ

```js:turtleBlock.js
Blockly.JavaScript['turtleforward'] = function(block) {
    var number_step = block.getFieldValue('step');
    var fowardCode = `TurtleForward(${number_step})`; 
    return fowardCode;
};
```

- 引数の数字を読み取る
- 別の場所で定義されている`TurtleForward()`を実行するために`forwardCode`を定義
- `return`で渡す

### 実行するファイル
`turtleBlock.js`から値を受け取り、実行します。

```js:turtleCommand.js
TurtleForward = (value) => {
    console.log('実行された'+value);
    var code = 'TurtleForward(turtle,'+value+')';
    ggbApplet.evalCommand(code);
}
```

## 実際の挙動
ブロックを並べて実行すると

![スクリーンショット 2021-03-29 10.55.20.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549093/e45bdd28-4159-d200-7aa8-2fff5e6eacf9.jpeg)


画像のような挙動が確認されます。
しかし、ブロックを繋げて実行すると
![スクリーンショット 2021-03-29 10.54.32.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549093/dc1effee-3a64-63e9-33d9-d1e83580520a.jpeg)

上述したエラーが出てしまいます。

##解決方法
タイトルにもありますが、ブロックの定義の際に**`;`**や**`\n`**をつけていないことが原因でした。試しにブロックによって作成されるコードを表示させてみると

```
TurtleForward(1)TurtleForward(1)
```

定義されている`TurtleForward()`を認識することができず、エラーを起こしてしまうようです。

```js:turtleBlock.js
Blockly.JavaScript['turtleforward'] = function(block) {
    var number_step = block.getFieldValue('step');
    console.log(number_step+'進む');
    var fowardCode = `TurtleForward(${number_step})\n`; //変更点
    return fowardCode;
  };
```
あるいは

```js:turtleBlock.js
Blockly.JavaScript['turtleforward'] = function(block) {
    var number_step = block.getFieldValue('step');
    console.log(number_step+'進む');
    var fowardCode = `TurtleForward(${number_step});`; //変更点
    return fowardCode;
  };
```
のように**`\n`**、**`;`**を定義された関数を文字列として扱ったものを最後に入れることでエラーを解決することができました。

;
NSX-T 3.1 :  ホストとEdge TEPの同一サブネット構成

# NSX-T 3.0 & 3.1 :  ホスト内のTEP間通信の違い

VMware NSX-T 3.1以降、ホスト内で**<font color="red">ホストとEdgeのTEPの同一サブネットの指定が可能</font>**となっています。
NSX-T 3.0での同構成については、[別記事](https://qiita.com/m-eno/items/d7f703437071449d4161)に記載しましたが、図１の様な運用上の対応が必要でした。(ホストとEdgeは、VDSを分ける必要性)
　
　　　　　　　**図１ (NSX-T 3.0まで)**
![図１.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251519/d0c07326-8196-cc54-e4b5-66144e4347ba.png)
NSX-T 3.1では**<font color="blue">同一VDSで、ホストとEdgeのTEPの同一サブネット構成が可能</font>**となっています。（図２）　　

　　　　　　　**図２ (NSX-T 3.1以降)**
![図２.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251519/d736dc3c-c8db-ed16-29c3-08b9b73c1d93.png)

# NSX-T 3.1： 同一VDS、同一ホスト/Edge TEPサブネットの実装

NSX-T 3.1で、同一ホスト、同一VDSかつ同一サブネットにてホスト TEPとEdge TEPを実装するには、以下の設定が必要となります。

* **<font color="red">NSX-TでTrunkセグメントを構成し、Edgeのネットワークインターフェイスに接続する</font>**
※Edgeのネットワークの接続先は、VDS上のTrunkポートグループは指定出来ず、NSX-Tのセグメントを選択する必要がある
![図３.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251519/bfbe4be2-9b3b-13d1-feef-7ba24b98617d.png)


* 上記の設定で、Edgeが正常に動作する（Edge-ホスト間のトンネルがUpする）
![図４.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251519/962f0313-8574-0a5f-d576-8211be9c95e2.png)
![図５.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251519/5192082d-9ecf-4771-7bfc-a1c13e24322a.png)


* 一方EdgeをVDS上のTrunkポートグループに接続すると、EdgeのトンネルがDownし、オーバーレイの通信が失敗する

![図６.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251519/bde373b1-b351-f1ae-c025-ee219f1cd585.png)


# 参考リンク
https://vmwarehosting.com.au/nsx-t-3-1-enhancement-shared-esxi-and-edge-transport-vlan-with-a-single-uplink/
JavaScriptでDropbox APIから画像を読み込む

とりあえず動いた喜びと感動とメモ帳書きとして


```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Dropbox Test</title>
    <script src="https://unpkg.com/dropbox/dist/Dropbox-sdk.min.js"></script>
</head>
<body>
<h1>Dropbox Test</h1>
<script>

    let accessToken = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    let dbx = new Dropbox.Dropbox({accessToken: accessToken});
    let dir_path = "/Photos"
    dbx.filesListFolder({path: dir_path})
        .then(function (response) {
            imageLoad(response);
        })
        .catch(function (error) {
            console.error("error " + error);
        });
    function imageLoad(json)
    {
        let n = json.result.entries.length;
        for(let i = 0;i<n;i++)
        {
            let fileData = json.result.entries[i];

            dbx.filesGetTemporaryLink({"path": fileData.path_lower})
                .then(function(response) {
                    let img = document.createElement('img');
                    img.src = response.result.link;
                    document.body.appendChild(img);
                })
                .catch(function(error) {
                    console.log("got error:");
                    console.log(error);
                });
        }
    }
</script>
</body>
</html>
```

サムネールは画像をBlobで受けとるapiがありますが、
直接画像を取るには、json内のリンクを取るしかないっぽい。


#参考
知識ゼロだけど、Dropbox APIを使用したい
https://qiita.com/Ella_Engelhardt/items/c33f08b6b427eab8b310

dropbox-sdk-jsを使ってフォルダ内アイテムの共有リンクを取得
https://kittagon.hateblo.jp/entry/2018/08/13/000916
mapとeachの違い

#map
配列の入った変数.map {|変数名| 処理内容 }


```ruby
food = ["fish", "beef", "banana","potato"]
food.map {|a| a.length}

#元の配列の変更していない
#戻り値は [4, 4, 6, 6]
```

#map!（破壊的メソッド）
配列の入った変数.map！ {|変数名| 処理内容 }


```ruby
food = ["fish", "beef", "banana","potato"]
food.map! {|a| a.length}

#元の配列の変更している
#戻り値は [4, 4, 6, 6]
```

#each(mapとの違い)

```ruby
food = ["fish", "beef", "banana","potato"]
food.each {|a| a.length}

#戻り値がもとの配列を返す
#戻り値は ["fish", "beef", "banana","potato"]
```
【Mac版】ターミナル上でグローバルIPアドレスを調べる方法

## 概要
本記事ではターミナル上でグローバルIPアドレスを調べる方法について記述する．プライベートIPアドレスの調べ方は下記の記事を参照．

[Macのターミナル上でプライベートIPアドレスを調べる方法](https://qiita.com/rimorimo/items/9ee259ffb492a073884a)

## ターミナル上でグローバルIPアドレスを調べる方法 1
`curl`コマンドを用いてWebサイトからグローバルIPアドレスを取得する.

```
curl inet-ip.info
```

下記出力が得られる.

```
XXX.XXX.XXX.XXX
```

## ターミナル上でグローバルIPアドレスを調べる方法 2
**正規表現**と`curl`コマンドを用いてWebサイトからグローバルIPアドレスを取得する.（上記に比べレスポンスに時間がかかる）

```
curl -s ifconfig.me | grep '^[21]'
```

下記出力が得られる.

```
XXX.XXX.XXX.XXX
```
Microsoft Graph APIのリフレッシュトークン取得

# リフレッシュトークンとは？
Microsoft Graph APIを使用するには、アクセストークンを取得する必要があります。ただ1度アクセストークンを取得したとしても有効期限は１時間のため、すぐに使えなくなってしまいます。ここで必要になるのがリフレッシュトークンです。リフレッシュトークンでアクセストークンを更新した際に新しいリフレッシュトークンも発行されます。その度に新しいリフレッシュトークンに乗り換えていくことによってアクセストークンを継続して取得できるようになり、APIを使い続けることが可能になります。
この記事ではリフレッシュトークンを取得する方法をできる限り簡潔に紹介します。

# 前提条件
まず大前提として、AzureポータルのAzure Active DirectoryからMicrosoft Graphのアプリ登録をする必要があります。登録を終えた後、下記4点が必要になりますのでどこかに記録しておきます。
・クライアントID
・シークレットID
・リダイレクトURL
・テナントID

# codeを取得する
リフレッシュトークンを取得するためにPOSTリクエストを送るのですが、その際に「code」というものが必要になります。codeを取得するには、以下のURLをブラウザに貼り付けます。

```
https://login.microsoftonline.com/{テナントID}/oauth2/v2.0/authorize?client_id={クライアントID}&response_type=code&redirect_uri={リダイレクトURL}&response_mode=query&scope=offline_access%20user.read%20mail.read%20calendars.readwrite&state=12345
```

そうすると、新しいページにリダイレクトされます。
その際に、新しくなったURLの「code=」の部分を確認し控えておきます。

# リフレッシュトークンの取得方法
ここでは、node.jsでのコードになります。(axiosを使用しております)

```
const redirect_uri = "リダイレクトURL"
const client_id = "クライアントID"
const Tenant = "テナントID"
const client_secret = "シークレットID"

const axios = require("axios");
const qs = require("querystring");

const token_endpoint = "https://login.microsoftonline.com/" + Tenant + "/oauth2/v2.0/token";

let code = "③にて取得したcode"

async function main() {
  let data = {
    grant_type: "authorization_code",
    client_id: client_id,
    client_secret: client_secret,
    redirect_uri: redirect_uri,
    code: code,
  };

  let opt = {
    method: "POST",
    data: qs.stringify(data),
    url: token_endpoint,
  };

  let result = await axios(opt)
  console.log(result.data)
}
main()

```

上記のコードにて、リフレッシュトークンを取得することができます。

# まとめ
リフレッシュトークンを取得できれば、実際にAPIを用いて、カレンダーやメールなどさまざまな情報の取得や更新などができるようになります。
かなりざっくりとした説明になってしまいましたが、最後まで呼んでいただきありがとうございます！
（続編に繋ぐ）
CSSとは、記述の仕方など

# CSSとは
HTMLに装飾を加えるための言語です。

# 例

##### indexファイル

<!DOCTYPE HTML>
< html>
  < head>
    < meta charset="UTF-8">
    < title>HTML学習用ウェブサイト< /title>
    < link rel="stylesheet" href="style3-3.css">
  < /head>
  < body>
    < h1>
      これは見出しです
    < /h1>
    < p>
      １つ目の段落です
    < /p>
    < p class="second-message">
      2つ目の段落です
    < /p>
    < p>
      3つ目の段落です。< b>この部分は太字になります。< /b>
    < /p>
     < a href="https://www.google.com/">クリックすると、Googleへ移動します。</a>
  < /body>
< /html>

##### cssファイル

p {
  font-size: 24px;
  color: red;
}
.second-message {
  color: orange;
  font-size: 12px;
}

- p{}は< p>〜< /p>の部分をp{}のようにすること
- .second-messageはclass = "second-message"となっているところを.second-message{}のようにすること