OmniAICreator/Qiita-1.07M huggingface dataset:
【Swift】サロンでRxSwiftとMVVMを教えてもらったのでまとめる

#はじめに
随時更新予定
今回は、オンラインサロンでRxSwiftを教えてもらっているので、その中で自分の学びになったことを簡潔にまとめてみたいと思います。

#学んだこと
・どれがBLなのかを考える
・Result型で値を返すことができる

```swift
enum CalculateError: Error {
    case numberToDivideIsZero
}
func calculate(num1: Double, num2: Double) -> Result<Double, CalculateError> {
    if num2.isZero {
        return .failure(.numberToDivideIsZero)
    }
    return .success(num1 / num2)
}

let num1 = 10.0
let num2 = 0.0
switch calculate(num1: num1, num2: num2) {
    case .success(let result):
        print(result)
    case .failure(let error):
        print(error)
}
```
・メインスレッドで実行したいものには、Driverを使う（イベントをながすものはRelay）
・Driverをbindするときは、drive(onNext:)を使う
・Relayはaccept()でイベント通知する

```swift
relay.accept("text")
```
・Alertなどはイベントとして、enumを用意する

```swift
enum Event {
    case showAlert(String)
}
```
・BehaviorとPublishの使い分け
Behavior: 現在地を表したい場合に使う（subscribeした時点で現在地を取得できるため）
例: ラベルへの表示
Publish: イベントを表したい場合に使う（subscribeした時点で最後の値が流れてこないから）
例: アラートの表示要求
UIに表示したいストリームの源流をPublishで表した場合、subscribeした後に新たにEventが流れてこないとUI表示が更新されない。
アラート表示要求に使いたいストリームの源流をBehaviorで表した場合、subscribeした時点より前に流したEventが流れてしまうので余分にアラート表示がなされてしまうことになる。
・MVVMにおけるViewは状態を持たない。
・MVVMにおけるViewModelはViewを描画するための状態の保持と、Viewから受け取った入力を適切な形に変換してModelに伝達する役目を持つ。すなわちViewとModelの間の情報の伝達と、Viewのための状態保持のみを役割とする要素である。
・viewDidLoadにも処理を書かない(ViewModelにやらせる)

```swift
override func viewDidLoad() {
    super.viewDidLoad()

    viewModel.viewDidLoad()
    setupBindings()   

}
```
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・
・



#おわりに
おわりです。
AWS Cloud9でLaravel環境を構築その弐

前回、Cloud9でLaravel環境を構築した。
[AWS Cloud9でLaravel環境を構築その壱](https://qiita.com/_bobtabo_/items/9fc5a4d35ec1b5bfeaf4)
だけど、MySQLに外部接続できなかったので、設定する。

# マシンスペック
* Mac mini 2018
* macOS Catalina（10.15.x）
* Intel Core-i7 3.2GHz 6コア
* メモリ 32GB
* SSD 512GB

# Laravel環境
* Nginx 最新版
* PHP（PHP-FPM） 7.2.x
* MySQL 5.7
* Composer 最新版
* Laravel 5.6

# やること
* Cloud9のEC2インスタンスのMySQLに外部接続する

# 前提
[AWS Cloud9でLaravel環境を構築その壱](https://qiita.com/_bobtabo_/items/9fc5a4d35ec1b5bfeaf4)は構築済み。

# EC2インスタンスのMySQLに外部接続する

Cloud9環境を作成すると、セットでEC2インスタンスも作成される。

### EC2の設定

EC2を開く。
![スクリーンショット 2021-05-16 1.09.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111551/37ff966f-35a6-d42f-402d-cb8880578959.png)

インスタンスIDを選択する。
![スクリーンショット 2021-05-16 1.12.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111551/baa2fb03-83d6-4788-33e1-2136b8444f9d.png)

セキュリティグループを開く。
![スクリーンショット 2021-05-16 1.14.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111551/59b7a4b7-fe39-7b04-b8c0-866d41cdcb4b.png)

インバウンドルールを編集する。
![スクリーンショット 2021-05-16 1.16.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111551/969c7b53-6d8f-3919-a8f0-cce0b04974e4.png)

ルールを追加して保存する。
![スクリーンショット 2021-05-16 1.18.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111551/83267fba-6993-89df-eab5-9522678bba43.png)

※参考
[ec2のmySqlに外部サーバから接続する方法](https://screenof.blue/archives/73)
[AWS EC2のデータベースに外部からODBC経由で接続するための設定](https://a1-style.net/aws/ec2-mysql-redmine-odbc/)

### rootで外部接続を許可

```console
$ mysql -u root -p
Enter password: cloud9#CLOUD9

mysql> select user, host from mysql.user;
+---------------+-----------+
| user          | host      |
+---------------+-----------+
| fuga          | %         |
| fuga          | localhost |
| mysql.session | localhost |
| mysql.sys     | localhost |
| root          | localhost |
+---------------+-----------+
5 rows in set (0.00 sec)
```

当然ながらrootは中からしかアクセスできないが、外部から接続可能にする。

```console
mysql> GRANT ALL PRIVILEGES ON *.* TO root@'%' IDENTIFIED BY 'cloud9#CLOUD9';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> select user, host from mysql.user;
+---------------+-----------+
| user          | host      |
+---------------+-----------+
| fuga          | %         |
| root          | %         |
| fuga          | localhost |
| mysql.session | localhost |
| mysql.sys     | localhost |
| root          | localhost |
+---------------+-----------+
6 rows in set (0.00 sec)

mysql> quit
```

※参考
[外部のホストから接続できるようにする方法](https://www.wakuwakubank.com/posts/322-mysql-access-host/)

### DBクライアントから接続する

パブリック IPv4 DNSをコピーする。
![スクリーンショット 2021-05-16 1.35.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111551/4c3806df-65b7-d820-407d-8bd65393d7b9.png)

下記の接続情報で、お好きなDBクライアントで接続する。

| ホスト | ユーザー | パスワード |
|:-----------|------------:|:------------:|
| パブリック IPv4 DNS| root | cloud9#CLOUD9 |

※参考
[Sequel AceでMySQLに接続する(Sequel Proの後継)](https://qiita.com/ucan-lab/items/b1304eee2157dbef7774)
[DBクライアントツールはDBeaverをおすすめしたい](https://tech-blog.s-y[]oshiki.com/entry/233)
Amazon EC2上にFreeBSD13を立てAmazon EBSをマウントする

#前提
AWSコンソールまでは行き着ける環境
手元のマシンからSSHでEC2に接続できる環境

#操作
##インスタンスの起動
仮想マシンの新規作成、ってことですね。

###ステップ 1: Amazon マシンイメージ (AMI)
検索枠に「FreeBSD」と入れると「AWS Marketplace で 12 件の結果 件」と出てきますのでリンクをクリックします。いくつか出てきますので今回は「FreeBSD13」を選択します。
次に料金などについて情報が表示されますので、さらっと「Continue」をクリック。

###ステップ 2: インスタンスタイプの選択
今回は無料枠の「t2.micro」タイプでいきます。「無料利用枠の対象」と表示されているのを確認してください。
で、「確認と作成」ではなく「次のステップ：インスタンスの詳細設定」をクリックします。

###ステップ 3: インスタンスの詳細の設定
何もせず、「津美のステップ：ストレージの追加」をクリック。

###ステップ 4: ストレージの追加
「新しいボリュームの追加」をクリック。
サイズとボリュームタイプを入力します。
サイズは、無料枠は合計30GiB迄です。
ボリュームタイプは、汎用SSD(gp2)とマグネティック(standard)のみ無料枠で使えます。
で、「確認と作成」をクリックします。

###ステップ 7: インスタンス作成の確認
無料枠を超す設定がされているとここでメッセージが出てきますので、「戻る」で確認してください。
で、「起動」をクリックすると

###SSHアクセスキーの作成
TeraTermなんかでログインするのに必要な .pem キーの作成とダウンロードを行います。
方法はググってみてください。
で、キーをダウンロードすれば、インスタンスの作成と起動がなされます。


##ログイン
初期ユーザーは ec2-user です。
TeraTermなんかの使い方はググってください。

##EBSデバイスのマウント
###デバイス名の確認
dmesg でも ls /dev でもいいので、「xbd1」というデバイスがあることを確認してください。

###パーティションの作成と初期化
ここはいつものハードディスク増設手順です。

```
# gpart create -s GPT xbd1
# gpart add -t freebsd-ufs xbd1
# newfs -U /dev/xbd1p1
# mount /dev/xbd1p1 /mnt
```

```:df
# df -h
Filesystem         Size    Used   Avail Capacity  Mounted on
/dev/gpt/rootfs    9.6G    3.6G    5.2G    41%    /
devfs              1.0K    1.0K      0B   100%    /dev
/dev/gpt/efiesp     32M    878K     31M     3%    /boot/efi
/dev/xbd1p1        992M    8.0K    912M     0%    /mnt
```

あとは /etc/fstab に記述するなど、どうぞ。

#まとめ
キモは、
・FreeBSDの初期ユーザーは「ec2-user」
・EBSデバイス名は「xbd*」
・クラウドストレージといっても、OSからはただのハードディスクに見える
ABC201

#はじめに
こんばんは

京都に住んでいる修士2年の大学院生です．
明日というか今日は朝からバイトなので心が憂鬱ですが、頑張ってこの記事を書きます．本日は土曜日ということで朝から勉強しようと思いつつ、のんびりしていたら夕方になっていました．とりあえずABC201には出場しようと思い、だらけきった体をたたき起こしパソコンに向かいました．

今回はこんな感じでRatingは上がてくれました．よかったです．しかし、一向にD問題以降は安定して解けないですね．このままでは緑まで上がるのに時間がかかりそう……

![スクリーンショット (124).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465908/747fd8c3-e7a0-7554-60d9-c363504e28ea.png)

以下ABC201のリンクです．[https://atcoder.jp/contests/abc201]
#全体の感想
A、B、C問題はそこまで難しくありませんでした．しかし、BC問題で雑なコードを書いてしまい、時間をロスしてしまいました．

D問題は（列＋行）について、偶数の場合は高橋君、奇数の場合は青木君が動かすというのは分かって、動かすたびに最適解を求める関数でも書くのかなと思っていたら時間切れになりました．多分時間がいくらあってもできなかったとは思いますが……

#各問題の感想
###A問題
これはそのまま解きました．
等差数列かどうかを判別せよだったのでソートして確認だけしました．

```python
a=list(map(int,input().split()))
a.sort()
if abs(a[0]-a[1])==abs(a[1]-a[2]) :
    print("Yes")
else :
    print("No")
```
###B問題
これはリスト内の2つ目の要素である高さでソートしました．
本番は思いついた方法で実装してしまったため、汚いコードになってしまいました．


```python
n=int(input())
ans=[]
for i in range(n) :
    s=list(input().split())
    s[1]=int(s[1])
    a=s[0];b=s[1]
    s[0]=b;s[1]=a
    ans.append(s)
ans.sort()
print(ans[-2][1])
```
入力のところで以下のように書けばよかったですね．文字と数字を並べて書くのは久しぶりでしたので忘れてました．

```python
for i in range(n) :
    s,t=input().split()
    ans.append([int(t),s])
```

もし[山の名前、山の高さ]の順番のままで山の高さをソートしたければ下のようにすればよかったですね．

「***itemgetterを用いて2重リスト内の要素を並び替える***」のは忘れないようにします……なんか忘れてしまうんですよね．だから太文字にしてます．

```python
from operator import itemgetter
for i in range(n) :
    s,t=input().split()
    ans.append([s,int(t)])
ans.sort(key=itemgetter(1),reverse=False)
```

自分のために補足で、wh=[[8,8][2,2][5,3][2,1][4,2]]のリストについて、***第１キーの昇順をメインに第２キーは降順にする***には以下のコードになる

```python
from operator import itemgetter
wh.sort(key=itemgetter(1),reverse=True)
wh.sort(key=itemgetter(0),reverse=False)
```

###C問題
これはなんか数学のような問題でしたね……

まずは、４つの数字の並び方について、１種類は１通り、２種類は１４通り、３種類は３６通り、４種類は２４通りと調べました．

後は、〇の書いているインデックスの数字はすべて使った上で、まだ残りの枠があればハテナから選んで使うという方針で解きました．

つまり、（〇の種類）＝n、（？から選んだ種類）＝r、（？の全種類）＝cとすると

  ***ans=（n＋c 種類の並べ方） × （nCr （?からの選び方））***

でハテナの選ぶ種類をfor文でまわしてansの和をとれば求まると思いました．
for文は5-nでまわせば問題なかったです．ただ、5-nがcを超えないかだけは気を付けました．


```python
import itertools
s=list(input())
known=[]
unknown=[]
for i in range(10) :
    if s[i]=="o" :
        known.append(i)
    elif s[i]=="?" :
        unknown.append(i)
    else :
        continue
if len(known)>=5 or len(known)+len(unknown)==0 :
    print(0)
    exit()

def ncr(i) :
    return len(list(itertools.combinations(unknown,i)))

def comb(i) :
    if i==1 :
        return 1
    elif i==2 :
        return 14
    elif i==3 :
        return 36
    elif i==4 :
        return 24
    else :
        return 0

ans=0;n=len(known)
for i in range(5-n) :
    if i>len(unknown) :
        break
    ans+=comb(i+n)*ncr(i)
print(ans)
```

###D問題
答えを読むとそのコマからどの動きが最大の点数になるかを調べて動かし続けるといったものでした．
全体の感想でも言ったように、コマを動かす人は
高橋君＝（行数＋列数）が偶数の場合
青木君＝（行数＋列数）が奇数の場合
というのは自分でも分かりましたがそこからがダメでしたね．

今日は夜遅いのでまた解けたらここは更新しますね

###E,F問題
問題文すら読んでいない……

#最後に
そろそろD問題しっかり解けるようになりたいです！！（本当に）
ただD問題の難しさが水色くらいの時になると流石に厳しい……
茶色か緑色くらいでないと自分にはまだまだ厳しい感じではある

atcoder Problem の方で精進するしかないか、後はアルゴリズム勉強会の方のスライド問題を進めていかないとだめですね

それではまた
IME自動ONにできるのはIEだけ

IEコンポーネントやActiveXは新Edgeが育つまでは
OS上から完全に消し去ることはなさそうと思いました。

## IME制御の動作確認

![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/e70f3112-3d7b-0b0c-1441-b8bc787a29fa.png)

```html:sample.html
<meta charset=utf-8>

<h3>ime-mode (IE専用)</h3>

<li> 日本語入力ON <input style="ime-mode: active" /> </li>
<li> 日本語入力OFF <input style="ime-mode: disabled" /> </li>

<h3>inputmode</h3>

一時期あったが廃止された

<li> 日本語入力ON <input inputmode="kana" /> </li>
<li> 日本語入力OFF <input inputmode="none" /> </li>


<h3>input type</h3>

特定の入力に入ったら日本語入力OFF。
自動ONにする方法はない

<li> 日本語入力OFF <input type="email" /> </li>
```

## 懸念点

* 旧Edgeでサポートされていたが、バージョンアップでなんと効かなくなった。

https://answers.microsoft.com/ja-jp/windows/forum/windows_10-ime/edge%E3%81%A7ime/b33895d1-d9d5-4925-a124-c289f8246a95

* 新Edgeの独自機能追加によりIME制御対応になるかもしれませんがそれは将来の話。

https://mamewaza.com/support/blog/controling-input-method.html


## メモ: datalist

IE11にも対応していた。

![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/9dd011a4-a9bf-65d0-1aaa-5dee9fcc173a.png)


```html
<input type="text" name="name" list="options" />
<datalist id="options">
	<option value="東京都"></option>
	<option value="神奈川県"></option>
	<option value="千葉県"></option>
</datalist>　
```
【Swift】MVPを簡単にまとめてみる

#はじめに
今回は、MVPアーキテクチャについて簡単にまとめていきたいと思います。

#MVPとは
特徴
・Model, View, Presenterにより分割されるGUIアーキテクチャ
・データ同期する方法に、PassiveViewとSupervisingControllerの二つがある

#フロー同期とオブザーバー同期
まず、PassiveViewとSupervisingControllerを理解する前に、フロー同期とオブザーバー同期の説明をします。

##フロー同期
上位モジュールのデータを下位モジュールに適宜セットして同期する同期方法
つまり、手続き的な同期方法。

メリット
・画面遷移間でデータの受け渡しなどでデータフローを追いやすい
→上位モジュール（遷移先）が下位モジュール（遷移元）の参照を持つことができるため、有効

デメリット
・共通したデータを参照しているすべての箇所の参照を持っておかなければいけなくなるので、参照の管理が煩雑になりやすい。

##オブザーバー同期
下位モジュール（監視元）が上位モジュール（監視先）からObserverパターンを使い送られてくるイベントを受け取ってデータを同期させる同期方法。
つまり、宣言的な同期方法である。

メリット
・共通した監視先を持つ複数の箇所でデータ同期をしやすい
・上位モジュールが下位モジュールの参照をもつ必要がなく、かつコンポーネント間の距離に関係なくデータ同期ができる。（互いに疎結合）

デメリット
・データ変更のたびに同期処理が実行されるため、いつデータ同期が行われるのかが追いづらい。


#Model
MVC, MVVMなどもModelと同じ。

#View
View+ViewController

#Presenter
ViewとModelの仲介役
プレゼンテーションロジックを担う
1Viewにつき、1Presenter作成することが多い
PresenterからはViewをweak参照することが多い


#PassiveView
Presenter→Viewでフロー同期を使う

```swift:MVPのフロー同期例
myNameLabel.text = "REON"
tableView.reloadData()
```

Viewはすべてのユーザー入力イベントをPresenterに渡す。Presenterは入力に応じてプレゼンテーションロジックを処理して、Viewに対して手続き的な描画処理を出す。
ViewはPresenterの指示によってのみ描画処理を行い、Viewを基準とした描画処理は行わない。

![ScreenShot 2021-05-15 22.37.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/f12e773f-5311-a219-f065-907d63209373.png)


#SupervisingController
フロー同期とオブザーバー同期の両方を使う
Presenter→View間をフロー同期
Model→View間をオブザーバー同期する
監視元であるViewが監視先であるModelからNotificationCenterなどで送られるイベントを受け取って描画処理を行うことが例として挙げられる。
Viewは簡単なプレゼンテーションロジックを持つ。
Presenterは複雑なプレゼンテーションロジックを持つ。
ModelはPresenterによって呼び出され、Viewに対して描画に必要なデータをイベント通知によって受け渡しする。

![ScreenShot 2021-05-15 22.45.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/2dcf1523-13a9-5e6e-b9d6-767250dcb106.png)

SupervisingControllerはModel→View間にオブザーバーパターン同期を用いることで、処理を簡潔にかける。


#おわりに
MVPはPassiveViewかSupervisingControllerのどちらを使うのかがミソですね。
LaravelにReactとTypeScriptを導入する

## 前提
Laravelでプロジェクトを作成していて、nodeはインストール済みの想定で進めていきます。

## TypeScriptをインストールする
webpack.mix.js（webpackのラッパーライブラリ）を下記のように編集する

```
mix.ts('resources/ts/index.tsx', 'public/js')
    .sass('resources/sass/app.scss', 'public/css');
```

先ほどの編集内容を反映させる

```
npm install
```

プロジェクト内にnode_modulesディレクトリが作成されていればOK。
一旦下記コマンドでビルドする。

```
npm run prod
```


package.jsonにwebpack.mix.jsで編集した内容の不足分が記載される（typescriptとsass）

## Reactをインストールする

```
npm i -D react react-dom @types/react @types/react-dom
npm install
```

package.jsonに追記されているか確認する。

## React用のTypeScriptの設定ファイルを作成する

```
tsc --init --jsx react
```

すると...
tsconfig.jsonが作成される。


## 動作確認
①webpack.mix.jsに記載した下記を作成する。
■resources/ts/index.tsx

```
import React from 'react'
import ReactDOM from 'react-dom'

const App = () => {
  return (
    <h1>Laravel SPA</h1>
  )
}

ReactDOM.render(
    <App />,
    document.getElementById('app')
)
```

■resources/sass/app.scss
→resources/css/app.cssをリネームする

②下記コマンドでビルドする

```
npm run prod
```

③resources/views/welcome.blade.phpをresources/views/index.blade.phpへリネームする
下記のように書き直す

```
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Laravel</title>
        <link rel="stylesheet" href="{{ mix('/css/app.css') }}">
    </head>
    <body>
        <div id="app"></div>
    </body>
    <script src="{{ mix('/js/index.js') }}"></script>
</html>
```

④web.phpでrouteをwelcomeからindexへ変更する

⑤キャッシュ対策でファイルパスにパラメーターを付与する
webpack.mix.jsに下記を追記する

```
if (mix.inProduction()) {
    mix.version()
}
```

⑥ビルトインサーバーを起動してlocalhost:8000へアクセスする

```
php artisan serve
```

編集した内容が表示されていることを確認できました！
Termuxでpkg(apt)が使えない問題を解決する(2021年5月)

初投稿です。Android端末にTermuxを入れて遊んでいるのですが，最近`pkg update`や`pkg install`を実行すると`403 Forbidden`とエラーが表示され，パッケージのアップデートやインストールができなくなっていることに気づきました。調べてみたところ解決できたので記事にしてみることにしました。

# 問題
Termuxで`pkg update`を実行すると下記のようにエラーが発生する。

```bash
$ pkg update
Checking availability of current mirror: ok
Hit:1 https://grimler.se/termux-packages-24 stable InRelease
Ign:2 https://dl.bintray.com/grimler/game-packages-24 games InRelease
Ign:3 https://dl.bintray.com/grimler/science-packages-24 science InRelease
Err:4 https://dl.bintray.com/grimler/game-packages-24 games Release
  403  Forbidden
Err:5 https://dl.bintray.com/grimler/science-packages-24 science Release
  403  Forbidden
Reading package lists... Done
E: The repository 'https://dl.bintray.com/grimler/game-packages-24 games Release' does not have a Release file.
N: Metadata integrity can't be verified, repository is disabled now.
N: Possible cause: repository is under maintenance or down (wrong sources.list URL?).
E: The repository 'https://dl.bintray.com/grimler/science-packages-24 science Release' does not have a Release file.
N: Metadata integrity can't be verified, repository is disabled now.
N: Possible cause: repository is under maintenance or down (wrong sources.list URL?).
```

なお，`pkg install ○○`などでも同様でした。

# 原因
色々と調べていると，以下の記事を発見しました。

https://github.com/termux/termux-packages/issues/6726

どうやら，5月1日から今までのリポジトリが使えなくなってしまったのが原因のようです。

# 解決方法
上記のサイトに書かれているとおりです。

①`termux-change-repo`を実行する。
②`Main repository`，`Game repository`，`Science repository`をすべて選択する。
③`Mirrors by Grimler`を選択する。

これで`pkg`が使えるようになりました。

# 補足
これについて調べているときに知ったのですが，Google Playで配布されているTermuxは技術的背景の問題で2020年9月29日を最後に更新されていないようです（詳細は以下のサイトに書かれています）。

https://wiki.termux.com/wiki/Termux_Google_Play

どうやら，以下のF-Droidというサイトで配布されているのが最新版のようです。

https://f-droid.org/packages/com.termux/

この記事を執筆した時点での最新版は0.112で，2021年4月26日に更新されたものでした。
最新版をインストールしてみたところ，`pkg`コマンドは最初から問題なく動いたので，上記の問題が発生するのはGoogle Playで配布されている古いバージョンのみのようです。
EC2って何ぞや？？

EC2ってよくわからないので、勉強したことを書いてみた。

## EC2とは
EC2とはAmazon Elastic Computing CloudというAWSのサービスの1種。
ちなみにElasticとは、「伸縮自在な」という意味で、需要に応じて必要な分だけ使えるということ。

## EC2の特徴

### 必要な時に必要な数だけ稼働できる
EC2は、インスタンスという仮想サーバーのようなものを起動させて使用することができる。
オンプレミス環境では事前に需要を予測して必要な分のサーバーをずっと稼働させることになるが、需要が少ない時は使わないサーバーを稼働させ続けることになり、無駄なコストがかかってしまう。
しかし、EC2インスタンスは、稼働数が需要に応じて柔軟に変化するため、サーバーの過不足が少なくなる。

### インスタンスタイプが変更可能
EC2インスタンスには、インスタンスタイプというものがあり、メモリの最適化、高速コンピューティングといった利用目的や、必要なスペックに合わせて設定する。
インスタンスタイプは,'t2.micro'のように（ファミリー）（世代）.（性能）の形式で表記する。
ファミリーが利用目的、世代がバージョン、性能がスペックを表す。
インスタンスタイプによってコストが異なるため、自分が求めるスペックに合わせたインスタンスタイプを選択するべき。
ここで重要なのは、事前に予算や必要なスペックを計算しておく必要はなく、稼働後もパフォーマンスをモニタリングしながら適切なインスタンスタイプを柔軟に変更できることである。

### 使用に時間がかからない
オンプレミスの場合、サーバーの調達に時間がかかり、すぐに使用できるわけではない。
しかし、EC2インスタンスの場合、サーバーの調達が不要で、数分の手作業で稼働できてしまう。

### 世界中のリージョンで使用できる
世界中のリージョンで使用できるので、東京にいながらも地球の裏のサンパウロ（ブラジル）でインスタンスをデプロイすることもできる。

### AMIから同じインスタンスを起動できる
EC2インスタンスは、AMI（Amazon Machine Image, EC2インスタンスのテンプレート）から起動する。
1つのAMIからEC2インスタンスをいくつでも起動でき、同じ種類のインスタンスを複製することができる。

### セキュリティグループでトラフィック制御ができる
EC2インスタンスへのアクセスは、セキュリティグループで許可しているものだけできる。

## EC2の料金体系
EC2の料金は次の3種類に対して課金される。

- EC2の起動
- データ転送
- ストレージ

上で述べたとおり、オンプレミス環境の場合、稼働させているサーバーの分だけ常に課金される。
それに対してEC2インスタンスは、必要に合わせて必要な分だけ稼働し、稼働した分だけ課金される（従量課金）。

EC2の料金プランは、主に以下の4種類が挙げられる。
### オンデマンドインスタンス
稼働したインスタンスの数と時間の分だけ課金されるオプション。
使わない分のインスタンスを停止させると、停止させている間の料金は課金されない。
### リザーブドインスタンス
インスタンスを使用する量があらかじめわかっている場合、1年や3年という期間で契約することで料金の割引が受けられるオプション。
### スポットインスタンス
他のユーザーがインスタンスを使っていない期間は料金が安くなり、使っている期間は料金が高くなるといった具合に、料金が市場価格のように変動するオプション。
インスタンスを使用するユーザーが増えてきてキャパシティが減ってくると、AWSによって強制的にインスタンスの使用を止められてしまう。
そのため、途中で中断してはいけないインスタンスには向かないオプションである。
### Dedicated Hosts
EC2を使用するホストを占有するオプション。
インスタンスに対してではなく、ホストに対して課金される。


参考文献：AWS認定資格試験テキスト・AWS認定クラウドプラクティショナー
VSCode設定メモ

# VSCodeの設定メモ
端末変わったとき用の自分向けメモです。
ショートカットと、単語区切りの設定だけとりあえず。

## ショートカット設定
```json
[
    {
        "key": "ctrl+tab",
        "command": "workbench.action.nextEditor" 
    },
    {
        "key": "ctrl+shift+tab",
        "command": "workbench.action.previousEditor"
    },
    {
        "key": "ctrl+left",
        "command": "cursorWordPartLeft"
    },
    {
        "key": "ctrl+shift+left",
        "command": "cursorWordPartLeftSelect"
    },
    {
        "key": "ctrl+right",
        "command": "cursorWordPartRight"
    },
    {
        "key": "ctrl+shift+right",
        "command": "cursorWordPartRightSelect"
    },
    {
        "key": "ctrl+shift+alt+w",
        "command": "workbench.action.closeWindow"
    },
    {
        "key": "ctrl+shift+w",
        "command": "-workbench.action.closeWindow"
    },
    {
        "key": "ctrl+w",
        "command": "workbench.action.closeActiveEditor"
    },
    {
        "key": "ctrl+shift+c",
        "command": "editor.action.commentLine"
    },
    {
        "key": "ctrl+oem_2",
        "command": "-editor.action.commentLine",
        "when": "editorTextFocus && !editorReadonly"
    },
    {
        "key": "ctrl+shift+d",
        "command": "editor.action.deleteLines",
        "when": "textInputFocus && !editorReadonly"
    },
    {
        "key": "ctrl+shift+k",
        "command": "-editor.action.deleteLines",
        "when": "textInputFocus && !editorReadonly"
    }
]
```

## その他設定
### 単語区切り
ctrl + ←, → での移動範囲設定
日本語や全角文字を入れておいたほうがいろいろ便利
```
"editor.wordSeparators": "/\\()\"':,.;<>~!@#$%^&*|+=[]{}`?-、。「」【】『』（）！？　てにをはがのともへでや"
```
簡単にコインを掘る方法

# 環境
- ubuntu 18.04

# MinerGate
## PPAのリポジトリにNVIDIAがドライバを公開しているので、このリポジトリを追加します。
`$ sudo add-apt-repository ppa:graphics-drivers/ppa`
`$ sudo apt update`
## 推奨ドライバチェック
### ドライバインストールの前に、本当に今入れようとしているドライバが推奨ドライバなのか確認します。
`$ sudo apt install ubuntu-drivers-common`
`$ ubuntu-drivers devices`
`$ sudo apt install nvidia-driver-460`
## 再起動
`$ sudo reboot`
## 確認
`$ nvidia-smi`

# VNC接続
## パッケージのアップデート
`$ sudo apt-get update`
`$ sudo apt-get -y upgrade`

## GUI環境のインストール
`$ sudo apt-get install -y lxde`

## VNCサーバのセットアップ
`$ sudo apt-get install -y vnc4server`
`$ mkdir ~/.vnc`
`$ ln -s /etc/X11/Xsession ~/.vnc/xstartup`
`$ vncserver`
`$ sudo vi /etc/init.d`

``` /etc/init.d
su -l ubuntu -c "vncserver"
```

## ローカルマシンから接続
``` 
open vnc://xx.xx.xx.xx:5901
```
M5StackでWinSTAR社OLEDモジュールを使うには

M5Stackには液晶画面があるのですが、小さいので少し離れたところから見る装置等には不向きです。
現在熱帯魚水槽のpH常時測定器を作成しているので、たまたま手元にあったWinSTAR社OLEDディスプレイを
使用することにしました。（I2C変換を使ってI2C制御ですが。）
本来は8bitパラレル入力のHD44780互換なので、<font color="BLUE">liquidCrystal_I2C.h</font>で簡単に利用できる．．．はず
なのですが、WinSTAR社OLEDモジュールのコントローラーが__WS0010__が曲者でイニシャライズが特殊です。
初回起動時（パワーオンリセット時）は正常に動いている感じですが、m5stackをリセットした際などにinitしても上手くいきませんでした。

半日程ネットを徘徊して調べたんですが、旧式なモジュールなので情報も少なく．．．
ロシア人の記事が一軒見つかり、その記事によると、おかしくなったら(0x00)を4回送れとのこと。



```C++:LiquidCrystal_I2C.cpp
 //put the LCD into 4 bit mode
 // this is according to the hitachi HD44780 datasheet
 // figure 24, pg 46
	
 // we start in 8bit mode, try to set 4 bit mode
 //write4bits(0x03 << 4);
 //delayMicroseconds(4500); // wait min 4.1ms
   
 // second try
 //write4bits(0x03 << 4);
 //delayMicroseconds(4500); // wait min 4.1ms
   
 // third go!
 //write4bits(0x03 << 4); 
 //delayMicroseconds(150);
	write4bits(0x00);
	delayMicroseconds(100);
	write4bits(0x00);
	delayMicroseconds(100);
	write4bits(0x00);
	delayMicroseconds(100);
	write4bits(0x00);
	delayMicroseconds(100);
	write4bits(0x00); 
	delayMicroseconds(150);
```
と、こんな感じで正常にイニシャライズ出来たようです。
あまり需要のなさそうな情報ですが、半日かかったんでまとめておきます。
Github プライベートリポジトリを途中から公開リポジトリに変更する

# 目的

- プライベートリポジトリを公開リポジトリに変更する方法をまとめる

# 方法

1. 当該のリポジトリを開く。
1. `Settings`をクリックする

    ![miriwo0104_tasks.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/d4c3b49d-5956-7003-3221-570f355a3c1b.png)

1. サイドバーにて`Options`を選択する。

    ![Options.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/1e7d31d5-4ba2-060d-ae1f-da02d9972543.png)

1. ページ最下部までスクロールする。
1. `Change repository visibility`の`Change visibility`をクリックする。

    ![Options.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/6dac64dd-c184-b208-e56a-807cc70c5a6b.png)

1. `Make public`をラジオボタンで選択する。下部のテキストボックスに当該のリポジトリ名を入力して`I understand, change repository visibility.`をクリックする。

    ![Options.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/bc24546b-fbb5-cc85-5056-314618aa93dc.png)

1. プライベートリポジトリを公開リポジトリに変更することができた。
Atomic Kotlinの誤記載：NumberTypes/Task4.kt

[intelliJIdeaのプラグイン（Edu Tools）](https://www.jetbrains.com/help/education/install-edutools-plugin.html)で[Atomic Kotlin](https://stepik.org/lesson/171437/step/1?unit=146116)というコースで学ぶ中で、明らかにコース作成者側のミスと思われるものを見かけたので、他の学習者のために残す。
この記事はエクササイズ：NumberTypes/Task4.ktについて。
目次は[こちら](https://qiita.com/Amairo/items/c80a7d04e26c7eb92ab2)

NumberTypes/Task4.kt
## 課題内容
![NumberTypes_Task4.kt.01..jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1501375/563d5958-3f15-8ac8-3ddf-56fb3381a2c7.jpeg)
５行目の`TODO()`を編集して、7行目の`fun main(){}`を実行してすること。
初めから、`fun main()`にはargumentとして`(1,30,0)`が入力されている。

## 問題点
`TODO()`に正解例のコードを入力しても、右サイドバーにある正解（Expected）の数字（3600000000000000）にはならない。
`fun main()`にデフォルトで入力されているargumentを、`(1000000000,0,0)`に入力し直さないといけない。
![NumberTypes_Task4.kt.02..jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1501375/3e2ce31f-3768-5251-e708-f5eec9642530.jpeg)

一度【Check】をして右サイドバーに間違いへのメッセージを表示させない限り、10億時間のミリ秒変換をするというのは分からない。

##解決策
![NumberTypes_Task4.kt.03..jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1501375/f65fca10-1b9f-eee2-6678-dcaa1c9f287d.jpeg)
上述の通り。
`fun main()`にデフォルトで入力されているargumentを、`(1000000000,0,0)`に入力し直す。
CircleCIでテストを自動実行する

## 前提
今回は前回の記事にCircleCIを組み込んでいきます。
[DockerでLEMP環境を構築する](https://qiita.com/yu_ku/items/494c3ca16e9bb7c8924c)



## テストを作成する

```
# Laravelプロジェクト内でテスト用の.envファイルを作成する
cp .env.example .env.testing

# APP_KEYを作成する
php artisan key:generate --env=testing
```

.env.testingへ下記を記載する

```
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel-test
DB_USERNAME=root
DB_PASSWORD=
```

## テストコードを作成する

```
php artisan make:test HogeTest
```

下記などを参考にPHPUnitでテストを記述する
https://qiita.com/tsuuuuu_san/items/46246168dc36ad2369cc
https://qiita.com/nakano-shingo/items/9446568a2f9e903922d4

## 作成したテストをCircleCI上で実行できるように設定情報を追記する
config/database.phpの'connections'に下記を追記する

```
'circle_testing' => [
        'driver' => 'mysql',
        'host' => '127.0.0.1',
        'port' => '3306',
        'database' => 'circle_test',
        'username' => 'root',
        'password' => '',
        'charset' => 'utf8mb4',
        'collation' => 'utf8mb4_unicode_ci',
        'prefix' => '',
        'prefix_indexes' => true,
        'strict' => true,
        'engine' => null,
    ],
```

## CircleCIへログインする
アカウントがない場合GitHub連携で簡単に作成できます。
Projectsへ遷移するとGitHubのリポジトリが表示されるので設定したいプロジェクトのSet UP Projectボタンを押下する（開発言語など問われるので適宜選択する）

## CircleCIの設定ファイルを作成する
【ルートディレクトリ】へ移動して.circleci/config.ymlを作成する

```
mkdir .circleci && touch .circleci/config.yml
```

.circleci/config.ymlに下記のように設定を記載する

```
version: 2 # 設定ファイルのバージョン
jobs: # 実行させたいジョブの定義
  build: # ジョブ名を定義する
    docker: # ジョブを実行するマシンを定義
      # CircleCIのイメージを使用
      - image: circleci/php:7.3.0-node-browsers
      - image: circleci/mysql:5.7
    environment:
      - DB_CONNECTION: circle_testing
    working_directory: ~/CI-test
    steps: # マシンに対しての命令手順
      - checkout # コードをレポジトリからチェックアウト
      - run: # コマンドを実行
          name: Update apt-get
          command: sudo apt-get update
      - run:
          name: Docker php extensions install
          command: sudo docker-php-ext-install pdo_mysql
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "src/composer.json" }}
            - v1-dependencies-
      - run:
          name: Install PHP libraries
          working_directory: src
          command: composer install -n --prefer-dist
      - save_cache:
          paths:
            - ./vendor
          key: v1-dependencies-{{ checksum "src/composer.json" }}
      - run:
          name: Run PHPUnit
          working_directory: src
          command: vendor/bin/phpunit

# 定義したジョブを実行するタイミングを定義できる
# 未定義だとGitプッシュがトリガーになり実行される
workflows:
  version: 2
  builid_workflow: # ワークフロー名を定義する
    jobs: # どのJOBを実行するか
      - build
```

## テストを自動で実行する
GitHubにコミット/プッシュする。
CircleCIのセットアップ画面へアクセスしてStart buildingをクリックするとビルド画面へ遷移する。

すると...
無事テストが走り、テスト結果が表示されました！
次回からはGitHubにコミット/プッシュしたタイミングで自動でテストが走るようになります（.circleci/config.ymlのworkflowsでタイミングは変更できます。）
m1 macにscipyとscikit-learnが入った件(安定するかは不明)

brewを最新化してpyenvでpython 3.9.1にしたら、scipyとscikit-learnが入ったのでメモ
(3.9.5はなぜかダメ)

brew updateして、openblasやらlapackが入っていることが前提
これで入った

```terminal
% pip install --upgrade pip
% OPENBLAS="$(brew --prefix openblas)" pip install scipy
% OPENBLAS="$(brew --prefix openblas)" pip install scikit-learn
```

一生懸命ビルドするので結構時間が掛かる。
【React】Childrenの要素で表示するものがない時、親のコンポーネントを非表示にする


Children props として渡した子コンポーネントが何も表示しない場合に、親のコンポーネントを表示しないようにするにはどう書けるのかをまとめました。
Accordion の要素や ul/li タグの表示の切り替え など、いくつかのユースケースが考えられます

## コード

- `App` で `ParentComponent` を呼び出して、`Children Props` として `ChildComponent` を記載しています。
- `ChildComponent` には描画するかどうかを Props で渡しています。

```tsx:App.tsx
import ParentComponent from "./ParentComponent";
import ChildComponent from "./ChildComponent";

const App = () => {
  return (
    <div className="App">
      <ParentComponent>
        <ChildComponent
          componentRenderable={false}
          text={"child component1"}
        ></ChildComponent>
        <ChildComponent
          componentRenderable={false}
          text={"child component2"}
        ></ChildComponent>
        <ChildComponent
          componentRenderable={false}
          text={"child component3"}
        ></ChildComponent>
      </ParentComponent>
    </div>
  );
};

export default App;
```

```tsx:ParentComponent.tsx
import * as React from "react";
import ReactDOMServer from "react-dom/server";

interface Props {
  children: React.ReactElement[];
}

const ParentComponent = (props: Props) => {
  const renderableChildren = props.children.filter(
    (child: React.ReactElement) =>
      ReactDOMServer.renderToString(child) !== ""
  );
  if (renderableChildren.length === 0) return null;

  return (
    <div>
      <p>Parent Component</p>
      <ul>{props.children}</ul>
    </div>
  );
};

export default ParentComponent;
```

```tsx:ChildComponent.tsx
interface Props {
  componentRenderable: boolean;
  text: string;
}

const ChildComponent = (props: Props) => {
  if (!props.componentRenderable) return null;

  return <li>{props.text}</li>;
};

export default ChildComponent;
```

## 解説

下記は最初書いて、うまく動作しなかったものです。

```tsx:(うまく動かなかったもの)ParentComponent.tsx
import * as React from "react";

const ParentComponent = (props: Props) => {
  if (props.children.length === 0) return null;

  return (
    <div>
      <p>Parent Component</p>
      <ul>{props.children}</ul>
    </div>
  );};
```

`ChildComponent` で描画を制限していますが、component 自体は children として渡ってしまいます。
なのでここでは、**渡ってきた子コンポーネントが描画するのかどうか**で親コンポーネントの描画を制限する必要があります。

今回は、[ReactDOMServer.renderToString](https://ja.reactjs.org/docs/react-dom-server.html#rendertostring) という関数を使用しました。

こちらの関数は、React Element を初期状態の HTML へと変換し、String で返します。
描画しない場合は空文字列が返るため、それを利用して、子コンポーネントが描画されるかどうかを判定することができます。

## 終わりに

codesandbox に今回のソース上げてます。

https://codesandbox.io/s/stupefied-water-0fjl6?file=/src/App.tsx

動作の確認もできるので、気になる方は見てみてください。
dockerでbinding.pry

##Dockerでbinding.pryするには設定が必要だった。
アタッチということをしなければいけないらしい

Gemfileに下記を記載


```ruby:Gemfile
group :development do
  gem 'pry-byebug'
end
```

docker-compose.ymlファイルに下記の2つを設定する
`stdin_open: true
tty: true`

```ruby:docker-compose.yml
back:
    build: back/
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    stdin_open: true #追記
    tty: true  #追記
    env_file:
      - ./back/environments/db.env
    # 以下省略

```



##Gemfileを変更したので、buildしなおす

Dockerfileがある場合
今回の場合
Dockerfileの中に下記のような記述があり、再度読み込みをしなければいけない
bundle installやbundle updateコマンドは使用しないでもbuildし直すことで構築される。

```
CMD ["bundle", "exec", "rails", "s", "puma", "-b", "0.0.0.0", "-p", "3000", "-e", "development"]
```

```
$ docker-compose build
```


###検証場所にbinding.pryを記述


```
$ docker-compose up
```

別のターミナルで
###アタッチ

```
$ docker attach <コンテナNAME or ID>
```

$ docker ps
でNAME、IDは確認できます


###検証すると...

```
    13:     else
    14:      binding.pry
 => 15:       User = User.find_by(name: '山田')
// 省略
> 
```

止まった！

###デバッグから出る

```
$ exit
```

###アタッチから出る

```
control + P -> control + Q
```

**Control + D or C　だとコンテナが停止してしまうので上記で安全にデタッチしましょう!!**
##番外
デバッグ終えてフォルダをみると
コマンドのログが書かれたファイルが生成されています。
gitignoreに記載しておきます。

```ruby:gitignore
/.ash_history
/.local/*
```

***
アタッチってそもそも何？

https://qiita.com/RyoMa_0923/items/9b5d2c4a97205692a560

https://logicoffee.hatenablog.com/entry/2018/06/26/195502
Java初心者のつまづき（1）クラス型変数の代入の罠

#Java初心者のつまづき（1）クラス型変数の代入
##この記事を書こうと思ったきっかけ
アウトプットの練習もかねて、Javaを勉強した際につまづいた「クラス型変数の代入」について、まとめておきたいと思います。

##クラス型変数を代入するときの注意点
クラス型の変数を同じクラス型の別の変数に代入した場合、
代入されるのは__"変数"そのものの値ではなく、"オブジェクト"の参照値__になります。

以下のBookクラスでは本オブジェクトを生成し、setBookで本の名前とページ数をセットしています。showBookが呼ばれると本の名前とページ数を画面上に表示します。


```java:Book.java
public class Book {
	// 本の名前
	private String name;
	// ページ数
	private int page;
	
	public Book() {
		name = "名称なし";
		page = 0;
	}
	/**
	* 本の名前とページ数を設定する
	* @param name
	* @param page
	*/
	public void setBook(String name,int page) {
		this.name = name;
		this.page = page;
		
	}
	
	/**
	* 本の情報をsysoutして表示させる
	*/
	
	public void showBook() {
		System.out.println("本の名前:"+name);
		System.out.println("ページ数:"+page+"ページ");
		
	}
}
```
これをinfoクラスのmainメソッドで呼んでみます。infoクラスでは
①小説　300ページ
②辞典　1000ページ　の二冊の本の情報を登録します。

```java:info.java
public class info {
	
	public static void main(String[] args) {
		// コンパイルテスト
		// System.out.println("Hello!");
		
		// 本オブジェクトをnewして生成
		Book book1 = new Book();
		
		// 作ったbook1に小説の情報をセット
		book1.setBook("小説",300);
		
		// book1の値をnewせずに代入
		Book book2 = book1;

		// book2に辞典の情報をセット
		book2.setBook("辞典",1000);
		
		book1.showBook();
		book2.showBook();
		
	}
}
```

newしたBookオブジェクトbook1に「小説」とページ数300を登録します。
登録には先ほど作ったBookクラスのセッター(setBook)を呼び出します。
その後book2に「辞典」とページ数を__newせずに__代入してみましょう。

それぞれの結果をshowBookで表示させてあげると、

```java:実行結果
本の名前:辞典
ページ数:1000ページ
本の名前:辞典
ページ数:1000ページ
```

はい。両方とも「辞典」になってしまいました。
これはStringクラスのようなクラス型変数では__値のそのもの__ではなく、
値が格納された__メモリの場所__を変数に渡しているためです。
そのため、新しくBookクラスのオブジェクトbook2をインスタンス化
つまりnewしてあげてから代入しましょう。

```java:info2.java
public class info2 {
	
	public static void main(String[] args) {
		// コンパイルテスト
		// System.out.println("Hello!");
		
		// 本オブジェクトをnewして生成
		Book book1 = new Book();
		
		// 作ったbook1に小説の情報をセット
		book1.setBook("小説",300);
		
		// Bookクラスのオブジェクト、book2をインスタンス化 ←　こう直す
		Book book2 = new Book();

		// book2に辞典の情報をセット
		book2.setBook("辞典",1000);
		
		book1.showBook();
		book2.showBook();
		
	}
}

```

これを実行すると、、、

```java:実行結果2
本の名前:小説
ページ数:300ページ
本の名前:辞典
ページ数:1000ページ
```

意図する実行結果になりました！
ハンドルネームを作成するプログラム[ruby]

今回は表題のコーディングテストをrubyで解きます。そこまで難しい問題ではなかったのですが、採点後に復習をした結果、7行で作成した回答を1行に集約できた喜びから、ここに記しておこうと思います。

復讐の際には、以下の記事を参考にさせて頂きました。（参考になりました、ありがとうございました！）

https://qiita.com/shibukk/items/7dded3e74b0f7dbfb633

## 問題

```:問題文
ハンドルネームを作成するプログラムを設計する
その際のハンドルネームは、名前の文字列から母音を取り除いて子音のみを連結して生成します。

ただし、ここで母音とは "a", "e", "i", "o", "u" の
5つのアルファベットの小文字( "a", "e", "i", "o", "u" )を指し、
子音とはそれ以外のアルファベットを意味します。
```

```
入力例1
	Torvalds
出力例1
	Trvlds

入力例2
	PAIZA
出力例2
	PZ
```

## 初期の回答

```ruby
input_line = gets.chomp.split("")
boin = ["a", "i", "u", "e", "o"]
array = []
boin.each do |bo|
    array.push(bo) if input_line.include?(bo)
end
puts (input_line - array).join("")
```

これに関して、「selectをうまく使えればもっとスタイリッシュにかけそう」と考えた。

## 復習で覚えたselectとreject

復習する上で、結果的にはselectメソッドではなく、rejectメソッドが最適でした。以下の具体例は、参考記事の引用です。

```ruby:select(find_all)メソッド
# 2で割り切れるものを抽出する
[1, 2, 3, 4, 5, 6].select { |n| n % 2 == 0 }
# => [2, 4, 6]
```

```ruby:rejectメソッド
# 2で割り切れるものじゃないものを抽出する
[1, 2, 3, 4, 5, 6].reject { |n| n % 2 == 0 }
# => [1, 3, 5]
```

## 改善後の回答

```ruby
puts gets.chomp.split("").reject { |i| ["a", "i", "u", "e", "o"].include?(i) }.join("")
```

1行になった！！(๑˃̵ᴗ˂̵)
まぁわかりやすさで言うと、どうなのかな、って思うところだけど、とりあえず嬉しかった！

以上です！最後まで読んで頂きありがとうございました。
Ruby Gemの削除方法

# gemfileでインストールしたgemを削除する方法

学習中に、gemを削除したいと思い、調べたところ、[この記事](https://qiita.com/sys_cat/items/16d55e7cd8a3f177863a)のとおり実行したら、うまくいったので、メモで残します。

**私が行った流れ**

1、下記のコマンドを実行

```
$ bundle exec gem uninstall （gemの名前を記載）
```

2、Gemfileから該当するGemの部分を削除する

3、Gemfile.lockから削除
　bundle installでGemfile.lockの中身を更新する
EC2の一覧を必要な情報だけ絞ってS3へ日次保管

### 実装の方法

LambdaのPython(boto3)を使います。
1日1回実行するトリガーとして、EventBridgeを使います。

### 実装できると何がうれしいのか

**1点目**
EC2のdescribe_instances APIは、取得結果が冗長なデータ構造となっていて、Javascriptなどで取り込んだ時にやや扱いにくいです。
特に、`Reservations[*].Instances[*]` の階層の深さと、タグの構造が `[{'Key': 'タグキー名' }, {'Value': 'タグの値}]`　となっている点が冗長でしょうか。
階層を単純な1次元配列(Pythonのリスト)とし、欲しい情報だけに絞ることで、プログラムから扱いやすくなります。

**2点目**
AWSのAPI/CLIでは、**”現時点の”**EC2の一覧を取得できますが、**”x月x日時点の”**EC2の一覧を取得したいとなった場合に、急に困ることになります。
1日1回Lambdaを実行して蓄積しておくことで、簡単に調べられるようになります。


### IAMロールの作成

IAMロールを作成します。
最低でも、以下の4つのポリシー(IAMポリシー or インラインポリシー)を含んだIAMロールを作成しましょう。

- EC2 の DescribeInstances
- S3 の PutObject
- S3 の GetObject
- S3 の ListBucket

### S3バケットの作成

S3バケットを作成します。
特にデフォルト設定で構いません。


### Lambdaの概要

- EC2の一覧取得のAPI(describe_instances)を実行してEC２の情報を取得します。
- 深いデータ構造となっているのをシンプルな構造(1次元配列のインスタンス一覧)にします。
- APIの結果から必要な属性情報だけを切り出します。今回は、インスタンスID、タグ、サブネットID、インスタンスタイプ、の4つが必要情報の例としています。
- タグのデータ構造を `[{"Key":"Name", "Value":"Server1"}, ..]` から `{"Name":"Server1", ..}` とシンプルにします。
- S3へ日付つきファイル名(キー名)と日付無しファイル名(キー名)の2つを保管します。
- 日付つきは ec2lite_YYYYMMDD.json、日付無しは ec2lite.json の名前とします。

### Lambdaの作成

Lambdaを作成します。
言語は Python で、3.8 にします。
EC2の数が多い場合は、デフォルト設定値の 3秒 では間に合わない可能性があります。その場合は 10秒 などに増やしましょう。
lambda_function.py を以下のコードに置き換えます。
`'your_bucket_name'`は自身のバケット名にします。

```python:lambda_function.py
import json
import boto3
from datetime import datetime, time, timedelta, timezone

ec2 = boto3.client('ec2')
s3 = boto3.resource('s3')
# ↓↓ 正しいバケット名に書き換えてください ↓↓
s3_bucket = 'your_bucket_name'

# APIのデータにはJsonに存在しない日付型を含むため文字列に変換する
def datetime_json_parse(dict):
	return dict.isoformat() if isinstance(dict, (datetime, date)) else dict

def lambda_handler(event, context):
	ec2_lite_json = []
	# ファイル名(オブジェクトキー名)1
	s3_obj_path1 = 'ec2lite.json'
	# ファイル名(オブジェクトキー名)2  +9時間で日本時間に
	s3_obj_path2 = datetime.now(timezone(timedelta(hours=9))).strftime('ec2lite_%Y%m%d.json')

	try:
		ret_instances = ec2.describe_instances()
	except Exception:
		return { 'result': 'ng' }
		
	for rsv in ret_instances.get('Reservations'):
		for inst in rsv['Instances']:

			tags_new = {}
			# シンプルなタグの構造に変換
			# "or []" はタグのないEC2でNoneType Errorとなる対策
			for tag in inst.get('Tags') or []:
				tags_new[ tag['Key'] ] = tag['Value']

			# 必要な情報に絞ったデータを生成
			# SubnetIdのみTerminated中のEC2でKey Errorとなるためget()
			ec2_lite_json.append(
				{
				'InstanceId' : inst['InstanceId'],
				'InstanceType' : inst['InstanceType'],
				'Tags' : tags_new,
				'SubnetId' : inst.get('SubnetId')
				}
			)

	# キー1はputして保管、キー2はキー1からコピーして保管
	s3.Object(s3_bucket, s3_obj_path1).put(
		Body = json.dumps(ec2_lite_json, ensure_ascii=False, default=datetime_json_parse)
	)
	s3.Object(s3_bucket, s3_obj_path2).copy_from(CopySource={'Bucket': s3_bucket, 'Key': s3_obj_path1})
	
	return { 'result': 'ok' }
```


### EventBridgeの作成

EventBridgeを作成します。
マネージメントコンソールで操作する場合、Lambdaのコンソール上のままでトリガーの追加ボタンを押してEventBridgeを選択しても新規のルール作成ができます。
cron式で `rate(1 day)` とすると日次で実行ができます。

### もっとうれしいこと

サーバー運用していると、EC2インスタンスを終了（削除）したのは何月何日かをさかのぼって知りたい場合がありますが、消えてしまったEC2に対してAWSでは簡単に調べることができません。

このLambdaの実装が前提として、もう1つ別のLambdaを作成し、そのLambdaで生成したJsonを見るだけで簡単にEC2削除日を調べることができる、という展開も可能になります。
（別の記事で記載予定です）
組み込みLinuxコンピュータにシリアルコンソールからファイルを送信する

組み込みLinuxコンピュータを入手したが、Wifi機能が無かった。
我が家のネットワークは無線化されているので、有線LANは無い。
どのようにすれば、開発環境であるホストコンピュータとターゲット機との間でファイルの送受信を行えるか？

# 環境

ホスト
- MacBook Air (M1, 2020)
- macOS Big Sur 11.3.1
- zsh
- シリアルターミナルソフト： screen

ターゲット
- Armadillo-IoT ゲートウェイ A6 C1モデル(AG6110-C01D0)
- Debian GNU/Linux 10 (buster)

# 方針

シリアルで使用できるファイル転送プロトコルであるZmodemを使用し、シリアルコンソールを経由してファイル転送する

# 準備

ホストとターゲットの双方にlrzszをインストールする

ホスト(Mac)側

```
% brew install lrzsz
```

ターゲット(Armadillo)側[^1]

```
$ sudo apt-get install lrzsz
```

[^1]: apt-getでインストールするのに、ネットワークに繋ぐ必要がある。どうしてもネットワークが用意できない場合は、SDカード経由でlrzszのバイナリをコピーするしかない。。

# ホストからターゲットへの接続

ホスト(Mac)のターミナルで

zmodemで送信する際のモードを指定しておく

```
% echo 'zmodem catch' >> ~/.screenrc
```

screenでターゲットのシリアルコンソールに入る

```
% screen /dev/tty.[シリアルポート名] 115200
```


# ホストからターゲットにファイルを送る

screen内で Ctrl-aを押した後、: を押して、コマンド実行モードに入る

```
:exec !! sz [送信したいファイル名]
```

# ターゲットからホストにファイルを送る

screen内(ターゲットのコンソール)で

```
$ sz [送信したいファイル名]
```

ホスト側でrzが実行され、ファイルが転送される

```
$ sz [送信したいファイル名]
rz
:!!! rz -vv -b -E
```

# 参考にしたサイト

https://gist.github.com/Sulter/d2ce41ca2dc5f59738d80c728f6b669e

# 感想

ターゲット側にrzコマンドが必要なことに気づくのに時間がかかった。
【jQuery】jQueryでカウントダウンタイマーを作成せよ。具体的な要件は以下に示す。

１・カウントは03:00からスタートする
２・スタートボタンを押すと1秒ずつカウントが進む
３・カウントが00:00になったら「Time UP!」と表示する
４・ストップボタンを押すとカウントが止まる
５・リセットボタンを押すとカウントが03:00に戻り、カウントが止まる
６・スタートを二度押しても1秒ずつカウントが進むこと。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954863/23a52cca-23ac-4e6c-e985-0f2f8ab06696.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954863/b785cc14-d0da-6860-f502-539730f17afc.png)



```javascript
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>jqueryでカウントダウンタイマー</title>
    <script src="jquery-3.6.0.min.js"></script>
    <script>
//001----------jqueryの開始------------------------------------------------------
$(function(){

//002-----------↓何分のタイマーにするか入力------------------------------------------
  var minutes = 0.1;
//003---------------------------------------------------------------------------
  var dafa_time = (minutes * 60);
  var time = dafa_time;
  var interval;
  var min;
  var sec;

  calc();

  $('#start').on("click",function(){
    $('#start').prop('disabled',true);
    interval = setInterval(startTimer,1000);
  });

  $('#stop').on("click",function stopTimer() {
    clearInterval(interval);
    $('#start').prop('disabled',false);
  });

  $('#reset').on("click",function() {
    clearInterval(interval);
    $('#start').prop('disabled',false);
    $('#timer').html("TIME UP!!").css("color","black");
    resetTimer();
  });


  function startTimer() {
    time --;
    if (time === 0 ) {
      $('#timer').html("TIME UP!!").css("color","red");
      clearInterval(interval);
    } else {
      calc();
    }
    
  }


  function resetTimer() {
    time = dafa_time;
    calc();
  }


  function calc() {
    min = Math.floor( time / 60 );
    sec = time % 60;
    min = ('00' + min).slice(-2);
    sec = ('00' + sec).slice(-2);
    $('#timer').html(min + ":" + sec);
   }

});



</script>
<!-----タイマーを表示--------------------------------------------->
<div id ="timer"></div>
<!-------------------------------------------------------------->
<!-----スタートボタンを表示----------------------------------------->
<button id="start">スタート</button>
<!-----ストップボタンを表示----------------------------------------->
<button id="stop">ストップ</button>
<!-----リセットボタンを表示----------------------------------------->
<button id="reset">リセット</button>
<!-------------------------------------------------------------->




```
L4 L7ロードバランサーの違いを30秒で


## L7ロードバランサ
HTTP/HTTPSなどのアプリケーション層（urlなど）をみて負荷分散できる。
ロードバランサがapplicationサーバーと通信を行う。
applicationサーバーから見た送信元ipは、ロードバランサのものになる。

AWSではALB - Application Load Balancer などで使用される。

## L4ロードバランサ
HTTP/HTTPSなどのアプリケーション層をみて負荷分散できない。
ロードバランサが送信先のipをapplicationサーバーに書き換える。
applicationサーバーから見た送信元ipは、クライアントのものになる。

AWSでは、NLB - Network Load Balancer　などで使用される。
【Python×Tkinter】パス指定ではなくGUIでファイルを選択する方法

#はじめに
普段Pythonで何かファイルを操作するとき、ディレクトリを移動したりパスを指定してファイルを読み込むことが多いと思います。しかし自分が作ったプログラムを他人（非プログラマー）が使うとなったら、人によっては自分でコードを書き換えてパスを変えるとか難しいですよね。また自分で使うにしても、読み込むファイルが毎日変わるものであればいちいちコードを書き換えるのは面倒ですよね。

そんな方のために今回はGUIからファイルを選択できるようにする方法を解説します。


#準備
```python
import tkinter
import tkinter.filedialog
import tkinter.messagebox
import os
```
Tkinterというライブラリを使っていきます。読み方は「ティーキンター」です。
PythonのGUI系ライブラリの中ではかなり有名で、よく使われているものだと思います。
ちなみにTkinterだけインポートしてもファイルダイアログとメッセージボックスは使えないので、この２つもtkinter単体とは別にインポートします。あとエクスプローラーを利用するため、ディレクトリ移動できるようにosもimportします。


#ファイルをインポート


```python
root = tkinter.Tk()
root.withdraw()
```
rootはTkinterにおけるいわゆるウィンドウを作る働きをします。最初のroot = tkinter.TK()でまさにウィンドウを生成しています。しかしその際に空の小さなウィンドウも出てきてしまいます。この小さいウィンドウは使わないので、root.withdraw()で非表示にします。

```python
root.attributes('-topmost', True)
root.lift()
root.focus_force()
```

またこれは好みによりますが、ウィンドウが他のアプリやブラウザのページに隠れてしまうのが嫌という方は、root.attributes('-topmost', True)とroot.lift()を使いましょう。ウィンドウが常に最前面に来ます。またその際にroot.focus_force()も書いてあげると、ウィンドウにフォーカルが当たります。

```python
fTyp = [("","*")]
iDir = os.path.abspath(os.path.dirname(__file__))
tkinter.messagebox.showinfo('Qiita','ファイルを選択下ください')
file = tkinter.filedialog.askopenfilename(filetypes = fTyp,initialdir = iDir)

# Show file name
tkinter.messagebox.showinfo('Qiita',file)
```

fTyp = [("","*")]はアスタリスクを指定することで全種類のファイルを選択できるようにしていますが、もし特定の拡張子のファイルだけ取得したいときはアスタリスクのところにtxtやxlsxなど取得したい拡張子を入れてください。

iDir = os.path.abspath(os.path.dirname(__file__))は、実行中のファイルのパスを取得します。そしてここで取得したパスをもとに、エクスプローラーで選択したファイルのパスが
file = tkinter.filedialog.askopenfilename(filetypes = fTyp,initialdir = iDir)で取得されます。


２つあるmessageboxは、任意のメッセージを２つ目の引数で指定できます。ちなみに１つ目の引数に入力したものはウィンドウのタイトルになるので、アプリの名前などにしておくとよいでしょう。

実行結果は下記のようになります。
ファイル選択ダイアログメッセージ
![ファイル選択してください.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646654/4aeb3311-f780-66a1-1bde-093d68031461.png)

ファイル選択
![ファイルダイアログ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646654/624dd685-17d4-5ae2-59d7-9929abfa80a6.png)

選択後ダイアログ。ここでは選択したファイルのフルパスを表示
![後メッセージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646654/9489d02d-68ac-855b-4d7e-d5934dd79569.png)

コード全体としては下記のようになります。

```python
# Select file
root = tkinter.Tk()
root.withdraw()
root.attributes('-topmost', True)
root.lift()
root.focus_force()
fTyp = [("","*")]
iDir = os.path.abspath(os.path.dirname(__file__))
tkinter.messagebox.showinfo('Qiita','ファイルを選択下ください')
file = tkinter.filedialog.askopenfilename(filetypes = fTyp,initialdir = iDir)

# Show file name
tkinter.messagebox.showinfo('Qiita',file)
```

#参考にした記事
今回は下記の記事を参考にサンプルコードを書いてみました。
ちなみにウィンドウを最前面に持ってくるコードとメッセージボックス以外は、この記事のサンプルコードを引用させていただいております。


『Python：処理ファイルをGUIから選択する方法』https://qiita.com/666mikoto/items/1b64aa91dcd45ad91540
Atomic Kotlin（intelliJのKotlin学習コース） の誤記載集

Kotlinを学習中。
[intelliJIdeaのプラグイン（Edu Tools）](https://www.jetbrains.com/help/education/install-edutools-plugin.html)で[Atomic Kotlin](https://stepik.org/lesson/171437/step/1?unit=146116)というコースで学ぶ中で、明らかにコース作成者側のミスと思われるものを見かけたので、他の学習者のために残す。


---
2021/05/20
開発者に問い合わせたところ、コースの内容へのfeedbackの提出方法を教えてくれた。
[このページ](https://www.atomickotlin.com/exercises/)にあるように、
[This Prefilled Form](https://youtrack.jetbrains.com/newIssue?project=EDC&summary=AtomicKotlin%3A%20%3C%3C%20atom%20%2B%20exercise%20%3E%3E&description=%3C%3C%20Describe%20the%20problem%20here%20%3E%3E&c=Subsystem%20Kotlin&c=Assignee%20svtk&_ga=2.117104640.74073500.1621517347-463013052.1621077164)から提出できる。
アカウントを作成し、過去に提出されたfeadbackとintelliJのコースのコンテンツを比較したところ、全ては見ていないが、いくつかは修正されていた。
よって、今後はこの投稿記事に書くのではなく、開発者側にフィードバックを送ることにした。
既に書いた下記の誤記載は、そのうち修正されることになる。
（わざわざこの記事を読んで下さりありがとうございました。）

---




この記事は目次専用。
下記リンクから詳細に飛びます。
コース内で誤記載を発見し次第、随時upします。

目次（誤記載を発見したもののみ書いています。）
<details>
<summary>Programming Basics</summary>
- [Functions/Task1.kt](https://qiita.com/Amairo/items/51b7f9b2fa93b8aac080)
- [Functions/Task2.kt]()
- [NumberTypes/Task3.kt]()
- [NumberTypes/Task4.kt](https://qiita.com/Amairo/items/b46873f5e9ca8c615590)
</details>
psd一日改訂版

#使い方
``$ python psd_1day.py 2001/200109_N.MWDH_Uhp01.s``
#コード
```psd_1week.py
import obspy
from obspy import read
from matplotlib import pylab as plt
import numpy as np
from mpl_toolkits.axes_grid1 import make_axes_locatable
import sys
import matplotlib.ticker as tick


#コマンドラインから引数
file = sys.argv[1]

#サンプリング周波数
samplerate = 100

#sacファイル読み込み
sac1 = read(file, debug_headers=True)#読み込みたいファイルをここに入力
#振幅データ（縦軸）
y = sac1[0].data

#データの頭の時刻
starttime = (sac1[0].stats.starttime)
#観測点名
station = (sac1[0].stats.station)
#グラフタイトル用
title = str(starttime) +'  ' + str(station)

#時間（横軸）．
time = np.arange(0, len(y))/samplerate

#グラフとグラフの隙間
plt.subplots_adjust(hspace=0.1)

#波形
ax1=plt.subplot(2,1,1)
plt.title(title)
plt.plot(time, y, color='black', linestyle='solid', linewidth = 0.3)
plt.tick_params(labelbottom=False)
plt.xlim(0, 86400)
plt.ylim(-2e-06, 2e-06)
plt.ylabel("Ground velocity [m/s]")

#スペクトログラム
ax2=plt.subplot(2,1,2, sharex=ax1)
plt.specgram(y, Fs=samplerate,scale='dB', vmin = -200, vmax = -150, cmap = 'jet',NFFT = 1024, noverlap = 512)
plt.xticks(np.arange(0, 86400, step=3600))
plt.tick_params(labelbottom=False)
#plt.gca().xaxis.set_minor_locator(tick.MultipleLocator(3600))
plt.gca().yaxis.set_minor_locator(tick.MultipleLocator(2))
plt.ylabel("Frequency [Hz]")
plt.xlabel("Time [hour]")
plt.xlim(0, 86400)
#カラーバー
ax=plt.colorbar(orientation='horizontal', aspect=10, shrink=0.2)
ax.set_label('Intensity [dB]')

plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1101426/168de0fb-85b8-982f-9229-e78146348b20.png)
HerokuのMailgunでエラーが出た時の解決方法「 Net::SMTPUnknownError (could not get 3xx (421: 421 Domain xxx」

## 問題

[Railsチュートリアル第11章の本番環境でのメール送信](https://railstutorial.jp/chapters/account_activation?version=6.0#sec-activation_email_in_production)を進めていて、本番環境でサインアップ後にエラーに見舞われました。

まず、Herokuのlogを確認します。

```
$ heroku logs
```

下記のエラーが出ていました。

`[1fdfdc3a-013efafafafafaafafaa2] Net::SMTPUnknownError (could not get 3xx (421: 421 Domain sandbox74837842728438274278.mailgun.org is not allowed to send: Sandbox subdomains are for test purposes only. Please add your own domain or add the address to authorized recipients in Account Settings.`

要約すると「このドメインはメール送信を許可していません。」です。

## 解決策

解決策は、特定のメールアドレスの送信を許可することです。Mailgunを使用しているため、Mailgunのサイトにアクセスします。

HerokuアドオンでMailgunが追加できれいれば、ターミナルで以下のコマンドを入力するとサイトにアクセスできます。Cloud9の場合はブラウザが立ち上がらないので、ターミナルに出力されたURLをコピーしてブラウザに貼り付けます。

```
$ heroku addons:open mailgun
```

サイトにアクセスしたら、サイドバーの「Sending」→「Domains」選択し、以下の画像の赤枠の部分をクリックします。

![スクリーンショット 2021-05-15 22.29.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264073/b419e0c2-2a38-d6b4-728f-e51f1612a2d2.png)

右側にあるテキストボックスに認証したいメールアドレス（実際に使用できるメールアドレス）を入力し、「Save Recipient」ボタンをクリックします。

![スクリーンショット 2021-05-15 22.26.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264073/7c9d135a-9267-24f0-506a-251f655c1b9d.png)

数分後に入力したメールアドレスに認証用メールが届きます。認証メールから「I Agree」ボタンをクリックし、送信先のメールアドレスとして認証してください。

![スクリーンショット 2021-05-15 22.35.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264073/f4efb21a-3c76-8c36-1475-cdff0c87c11f.png)

あとは、このメールアドレスを使用して、Herokuの本番環境でサインアップを行えば成功するはずです。

## 参考

https://github.com/openmediavault/openmediavault/issues/832