OmniAICreator/Qiita-1.07M huggingface dataset:
RailsのjbuilderでJSONを返してみる

# なぜやるのか

Railsで作成しているポモドーロToDoアプリのToDoタスクをAjaxで実装したい。
JSとRailsをつなげる..??には、RailsのタスクをJSON形式で出力する必要があるらしい。(ちょっとまだここよくわかってない)
jbuilder を使うことで、簡単にJSON形式のデータを出力することができる。


# 手順

まずはrailsアプリの新規作成

```
rails new myapp
```

移動してデータベース作成

```
cd myapp && rails db:create
```

タスクモデルを作成

```
rails g model Task name:string is_done:boolean
```


マイグレート

```
rails db:migrate
```

コンソールでデータを入れとく

```
 rails c

> Task.new(name: "タスクのテストです。JSONで飛ばせるかな")
> task1.save
> exit #で抜ける
```

コントローラーの作成

```
rails g controller tasks index
```

vimでルーティングを以下のように編集し、コントローラとビューを繋ぐ

```config/routes.rb
  1 Rails.application.routes.draw do
  2   root 'tasks#index'

  3   # For details on the DSL available within this file, see https://guides.ru    byonrails.org/routing.html
  4 end
```

index.html.erbが既にありますが、以下コマンドでjson.jbuilderを作成&開きます

```app/views/tasks/index.json.jbuilder
  1 json.array! @tasks, :name, :id, :created_at
```


```app/controller/tasks_controller.rb
  1 class TasksController < ApplicationController
  2   def index
  3     @tasks = Task.all
  4     render :index, formats: :json, handlers: 'jbuilder'
  5   end
  6 end
```

`rails s -p 3333`でlocalhost:3000に繋ぐと...

表示させられました！

![スクリーンショット 2021-05-18 13.05.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619224/df0bb395-a716-30a5-1e37-735f26b73510.png)

curlコマンドでも見れるみたい。

````
curl localhost:3333
[{"name":"タスクのテストです。JSONで飛ばせるかな","id":1,"created_at":"2021-05-18T03:20:27.370Z"}]%
```

# 参考記事

今回の記事はほぼ以下の手順を踏襲しています。が、一部db:migrateが抜けていたり、Rails6に対応していない書き方だったりしたので、修正してQiitaにまとめてみました。

https://poteblog.com/2020/07/11/post-1735/


jbuilderの記述方法についてわかりやすい記事↓
・[【Rails】Jbuilderのメソッドについて調べてみた](https://bityl.co/6tK4)
ガントチャートを作るときの手順

## はじめに
プロジェクトによっては、WBSなどと呼ぶこともあるガントチャート
作業スケジュールを把握する上でもよく利用されるものです。

今回は、システム開発で利用するガントチャートの作成手順について解説したいと思います。
とくに、PGがリーダーになり、製造工程の管理をすることを想定して書いていきます。
また、MicrosoftProjectや、Redmineなどの、タスクに依存関係がつけられる
ツールを前提として、解説します。

##よくある失敗パターン
よくある失敗パターンは、は、
「細かく作業分解して、親子課題も作ったのに進捗確認で使えない。」
ではないでしょうか。

この原因は、せっかく依存関係を付けられるのに使っていない。
依存関係を付けてガントチャートを作るための手順を知らないためです。

## 作業手順は？

### マイルストーンスケジュールを別で書く
いきなりWBS（作業分解）して、そこに線を引く・・・ということをすると、
それが妥当なのか否か、分からなくなります。
なので、まずは、マイルストーンスケジュールを紙かエクセルで書き出しておきます。
これが、経験値から出したスケジュール ＝ 検算用のスケジュールです。

### ツールの設定
ツールでやる作業は以下の通りです。
1.作業を列挙する。
2.作業を分解する。
3.作業に工数を割り当てる。
4.作業の依存関係を付ける。

うまくいけば、これだけでガントチャートが出来上がります。
1.2.の作業が、WBS(Work Breakdown Structure)というものなので、
ガントチャート＝WBSと呼ぶ方がいるのですね。

そして、3.の作業が、工数見積もり
4.の作業が、作業計画というわけです。

理屈がわかったところでそれぞれの作業の注意点を解説します。

#### 1.作業を列挙する。
このステップは、抽象度に気を付けて書いていきます。
後から具体化しますので、各項目の抽象度が合うように書いていきます。
具体的には、「要件定義を画面単位でやったのであれば、画面を列挙する。」
という具合です。
また、この際に、共通パーツ（いわゆるベース開発）をする必要がある場合は、
この時点では、ベース開発などと入れておくとよいと思います。

その他、結合テストや総合テストなど、その他の工程がある場合には、
開発工程の下に具体的な開発作業を入れておくようにします。

#### 2.作業を分解する。
この段階では、1.で列挙した工程を分解していきます。
Redmineを使うなら、子チケットに分解していくイメージです。
分解する粒度は、1人でやった場合かつ、1日以内の単位になるまで分割することが望ましいです。

この理由は、実際に進捗確認をするときに、日単位で進捗を確認することが多いからです。
2日以上のタスクで計画してしまうと、1日の遅れをキャッチするタイミングが、
翌日に持ち越されてしまうので、管理者は、2日遅れを突然受け取ることになります。
そうならないためにも、毎日報告を受け取り、想定の進捗との差をチェックすることが大切です。

一方で、0.1人日のタスクを大量に作ると、管理の手間が多くかかるので、ある程度
0.1人日単位になりそうなタスクは、まとめてしまう事も検討しましょう。


#### 3.作業に工数を割り当てる。
2.の作業に対して、工数を割り当てます。
ここで、改めて粒度を確認し、1人日以上かかるタスクがあったら分解します。
反対に、0.1人日のタスクが続く場合には、まとめてしまいましょう。
その際に、単純に足すのではなく、まとめることで足すよりも少ない工数でできないか確認します。
これは、最小単位のタスクの中に余剰工数が入ってしまうためです。

#### 4.作業の依存関係を付ける
タスクとタスクに依存関係を付けていきます。
子課題に依存関係を付けると、親課題の線が伸びるので、これにより、
複数課題の開始日と終了日を表します。
　
依存関係を付けるときには、以下のような制約事項に気を付けながら作業をします。
4.1.作業自体の前後関係（製造 → テストなど）
4.2.担当者数の制約による並行作業量（4人であれば、4人で並行）

##### 4.1.作業自体の前後関係


##### 4.2.担当者数の制約による並行作業量



#### 最終確認

ここまでくると、全体のスケジュールが見えてくるので、
はじめに作ったマイルストーンスケジュールとの差異をチェックする。
NanoPi NEO に Armbian をインストールしようとしてつまづいた話

# はじめに
うちで細々とサーバ仕事などを担ってくれている初代RaspberryPiくんの調子が悪そうなので、そろそろ引退いただいて後釜を準備しようなどと考え始めた。

あまりたいしたことはさせない予定で Raspberry Pi 3/4 あたりだとオーバースペック。そして Raspberry Pi 1/2 あたりは入手性が悪くなってしまっている、でもサーバとして常時稼働の予定なので有線LANに接続したくて Raspberry Pi Zero はちょっと、、

みたいに思いながら他のシングルボードコンピュータを探してて、NanoPi シリーズを思い出す。スペック的には NanoPi NEO くらいで十分。そしてお安い。さらっと調べた感じだと導入もそれほど難しくなさそう。というわけで、ポチっと。

# あれ？ 起動しない？
というわけで、秋月さんで [NanoPi NEO](https://akizukidenshi.com/catalog/g/gM-12301/) を買いました。一応 [ヒートシンク](https://akizukidenshi.com/catalog/g/gP-12303/) もセットで。

[Armbian (NanoPi NEO 用)](https://www.armbian.com/nanopi-neo/) もダウンロード。
（ちなみに 2021/05/18 現在、Armbian Ver.21.05.1 で Buster と Bionic が公開されてますが、なんとなくで Buster を使うことにしました）

これを [Win32 Disk Imager](https://forest.watch.impress.co.jp/docs/review/1067836.html) でマイクロSDカードに書き込んで NanoPi NEO にセット。LANケーブルを差し込んで、micro USB ケーブルから電源供給。

これでDHCPでLANから見えるんでしょ？

と思ったらLAN上にそれらしきホストが確認できず。。
```> arp -a``` とやっても知ってるマシンしか出てこない。。
起動失敗したかな、、？
（後で分かりますが、結果的にはこの時点で起動できてました。起動はできていましたが、この時点ではLANには繋がっていなかったようです）

# さあ確認だ
何が起きてるのか確認するために、debug UART を見てみる。
下の図の UART0 に USBシリアルを接続して TeraTerm で確認

![NEO_pinout-02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449620/fba77934-2091-bd4e-7a33-39a9aafa2a5c.jpeg)

母艦パソコンからぶら下がってる NanoPi NEO君。こんな感じ。

![DSC_0209-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449620/c732034e-8c77-0145-8e4a-233d387fdbbc.jpeg)

ちなみにこのUSBシリアルモジュールはだいぶ前に [IchigoJam](https://ichigojam.net/) のファームを書き換えるために購入したもの（[この辺参考](https://fukuno.jig.jp/2608)）。数年使ってなかったけど久しぶりでも普通に動いてくれて助かった。

シリアルポートの転送速度は何となくで 115200 にしてみてビンゴ（先に調べるべきだな）。

見てみるとコンソール上には普通に Armbian の起動画面が出てる。
何が問題かと思って、目線を下に下げていくと、どうやらログインを求められてるらしいので、デフォルトの ```ユーザ: root、パスワード: 1234``` を入力。

ログインすると今度は root の新規パスワードを求められたので適当に入力。そしたら、さらに新規の一般ユーザ名とパスワードも求められたので入力。ここでようやくプロンプトが表示された。

ここまで来て確認すると、すでにIPアドレスが割り振られていて、別PCからも見えるようになっていた。

# まとめ
何となくの「いけるだろ」って感じであまり調べずに買っちゃったってこともあるんだけど、たまたまUSBシリアルモジュール持ってたからなんとかなったものの、持ってなかったらもうちょっとハマってたな、これ。

なんか他にもっと上手い方法があるのかもしれないけど、とりあえず解決して NanoPi NEO が起動したので、これでいいってことにして、ここにメモとして残しておきます。
Reactのフォームの返り値と渡す値、型バラバラ問題(数値)

# 課題
Reactでフォームを実装したい。
React Hooksでcountを管理している。
ここで、素直にinputに値を渡して、変更があればinputの返り値で価格を変更してみる。

```typescript:index.tsx
import { useState } from 'react'

const Index = () => {
    const [count, setCount] = useState(0)
    return <input 
        type='number' 
        value={count} 
        onChange={e=>setCount(e.target.value)}
    />
}
export default Index
```

今回は、初期値0から100に変更したとする
初期値は、**number型の0**
変更があると、**string型の100**となる。
これでは困る。
別の`count=500`があったとしてその合計を求めると、`'100500'`となってしまう。

# 解決法
React hooksやreduxなどデータストアの型は変えない。
→表示するときに適した型に変換する
→変更があるときは、データストアと同じ型に変換する
の2つを守れば大体解決する

```typescript:index.tsx
import { useState } from 'react'

const Index = () => {
    const [price, setPrice] = useState(0)
    return <input 
        type='number' 
        value={price==0 ? '' : String(price)} 
        onChange={e=>setPrice(Number(e.target.value))}
    />
}
export default Index


// or

import { useState } from 'react'

const Index = () => {
    const [price, setPrice] = useState(0)
    return <input 
        type='number' 
        value={isNaN(price) ? '' : String(price)} 
        onChange={e=>setPrice(e.target.valueAsNumber)}
    />
}
export default Index

```

このようにこのように型を合わせてあげれば良い。
少し余計な処理があるが、これはinputを全部消してもデータストアは0にしかならず、0が必ず最後に表示されてしまうため0を消す処理を書いている。

個人的に、NaNを用いた方が見やすいと考えている。
データを送信するときに、入力のバリデーションで`count==0`と`isNaN(count)`だと後者の方が0を許容できるのと直感的だから。
stripe apiのsubscription挙動確認ドキュメント

# このドキュメントの目的

stripe apiの挙動を調べてまとめたもの

# subscriptionの決済の流れ

- Stripe::Checkout::Session.createで決済ページと決済完了後のページを指定
- 決済ページで決済が完了するとcheckout.session.completedイベントがwebhookで飛ばされる
    - ここではsubscriptionまでが生成されている
- その後invoice.createdが飛ばされる
- 更にその後invoice.paidが飛ばされる。ここでpayment_intent_idが飛ぶ

## Stripe::Checkout::Session.create

stripeのcheckoutを使用する際にcheckoutページを作成するのに必要。これで下記を行っている。

- 決済ページのsessionを作成。ここでjsonを返し、redirectToCheckoutにわたし、決済ページに行ける
- この処理はページに飛ばすところまでなので決済の完了などは行ってない

## checkout.session.completed

https://stripe.com/docs/api/events/types#event_types-checkout.session.completed

- 決済完了のイベント
- 継続課金の場合、subscription_idが飛ぶ
- ここで支払い、invoiceまでは発生していない

### 返ってくるevent

返ってくるeventのjsonの情報が1回目と2回目で違う。subscription_idは一回目のみ発行で2回目は送られない

## invoice.created

https://stripe.com/docs/api/events/types#event_types-invoice.created

- invoiceの作成でここではpayment_intent_idは送られない

## invoice.paid

- ここでpayment_intent_idが送られる
Roomデータベースファイルのエクスポート・インポートを行う雑な方法

Roomで管理するSQLiteのデータベースをエクスポートまたはインポートしたいときに、CSVの入出力を行うのが面倒なので、データベースファイルをそのままコピーするという方法を見つけた。

ほとんど何もバリデーションを行わないため、実際にリリースするアプリには怖くて使えないが、自分用のソフトウェアには問題なく利用できる。

実際に、RoomでデータベースをコピーするためのAPIがあれば良いのだが、簡単に動くものはなさそうだ。

# エクスポート
データベースを現在の状態で外部のURIにエキスポートしたい。

## 元のデータベースファイルの取得

`ApplicationContext`があれば、

```java
File sourceFile = getApplicationContext().getDatabasePath(DATABASE_NAME);
```

でdbファイルを取得できる。このときのDATABASE_NAMEはRoomDatabase.Builderでビルドするときに使った名前。

## WALのチェックポイント

RoomではWrite-Ahead Logging ([WAL](https://sqlite.org/wal.html))というものを採用している。これは、ジャーナルファイルに全てのトランズアクションを記録し、ジャーナルファイルが一定のサイズを超えると元のデータベースファイルが更新される仕組みである。よって、エクスポートするときにデータベースファイルを最新の状態にしておく必要がある。
チェックポイントを以下の構文で作動させることで、データベースファイルの内容を手動で更新できる。

```sql
pragma wal_checkpoint(full)
```
fullの代わりに、passive、restart、truncateのオプションがある。詳しくは[ドキュメント](https://sqlite.org/c3ref/wal_checkpoint_v2.html)を参照。

Javaでは色々な書き方があるがこれだけのためにDaoを作りたくなかったので、ダイレクトに実行した。(`mDb`は`RoomDatabase`のインスタンス)

```java
SupportSQLiteDatabase db = mDb.getOpenHelper().getWritableDatabase();
try {
    Cursor c = db.query(new SimpleSQLiteQuery("pragma wal_checkpoint(full)"));
    if (c.moveToFirst() && c.getInt(0) == 1) 
        throw new RuntimeException("チェックポイントが正常に完了しませんでした。");
    db.close();
} catch (Exception e) {
    // エラー対処
}
```
参照：[https://stackoverflow.com/a/52089040/9121127](https://stackoverflow.com/a/52089040/9121127)

## データのコピー

以下のようにしてファイル間でデータを移した。Fileであれば`new FileInputStream(file)`または`new FileOutputStream(file)`、Uriであれば`getContentResolver().openInputStream(uri)`または`getContentResolver().openOutputStream(uri)`を使う。

```java
try {
    FileInputStream is = new FileInputStream(sourceFile);
    FileOutputStream os = (FileOutputStream)getContentResolver().openOutputStream(destinationUri);
    FileChannel src = is.getChannel();
    FileChannel dst = os.getChannel();

    dst.transferFrom(src, 0, src.size());

    src.close();
    dst.close();
} catch (IOException e) {
    // エラー処理
}
```

# インポート

上のステップでエキスポートしたデータベースファイルを読み込みたい。明らかに、他のファイルをそのまま読み込むと危険なので注意する必要がある。

手順はほとんど同じだが、コピーをする前に既存のインスタンスへのコネクションを閉じる必要がある。

```java
mDb.close();
File destinationFile = getApplicationContext().getDatabasePath(DATABASE_NAME);

try {
    FileOutputStream os = new FileOutputStream(destinationFile);
    FileInputStream is = (FileInputStream)getContentResolver().openInputStream(sourceUri);
    FileChannel src = is.getChannel();
    FileChannel dst = os.getChannel();

    dst.transferFrom(src, 0, src.size());

    src.close();
    dst.close();
} catch (IOException e) {
    // エラー処理
}
```

データベースを更新した後は、アクティビティをリスタートした。

```java 
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
```

## createFromAsset
RoomにcreateFromAssetやcreateFromFileというAPIがあるが、使い方がドキュメントを読んだだけでは分からなかった。
本当は公式APIの方が安全なのだが、残念ながら動かすことはできずに終わった。
Jupyter-notebook での モジュールのimport エラーの対処

#概要
Anaconda-NavigatorのJupyter-notebookでpythonを実行したときに
インストールしたはずのモジュールのimport エラー
ModuleNotFoundError: No module named 'モジュール'が発生した

#エラー内容

```Python
ModuleNotFoundError                       Traceback (most recent call last)
<ファイル> in <module>
----> 1 import モジュール名

ModuleNotFoundError: No module named 'モジュール名'
```

#対処
* インストールされているかの確認
* モジュールの場所を確認
* パスの確認

##インストールされているかの確認
"pip list"でモジュールがあるか確認 なければインストール
Jupyter-notebookであれば"!pip list"で確認

```PowerShell:PowerShell
$ pip list
```

##モジュールの場所を確認
"pip show モジュール"でどの場所に保存されているか確認

```PowerShell:PowerShell
$ pip show モジュール名
```

##パスの確認

```Python:Python
import sys
sys.path
```

パスのリストの中にモジュールが保存されている場所が入っていないことがわかりました

```Python:Python
import sys
sys.path.append(該当するパス)
```
これで解決しました

#まとめ
対処法は3ステップ
1. インストールされているかの確認
2. モジュールの場所を確認
3. パスの確認
これらのステップごとに対処すればモジュールのimportエラーは解決します
AWSサービス一覧(2021年) 気になったやつだけ インフラ編(2/2) 

##今回のフォーカス
下記ページのインフラに関わるサービスを簡単にサマリー(続き)。できれば1-2行でまとめたい。
【2021年】AWS全サービスまとめ
https://dev.classmethod.jp/articles/aws-summary-2021/#toc-196

## 4. 移行と転送
- Migration Hub
    - **`各移行ツールのアプリの移行状況をトラックできるダッシュボードサービス。`**
    - Application Discovery,Databases Migration,Server Migration, Cloud Endureなどと統合されている。
- Application Discovery Service
    - **`オンプレミスのサーバ基本情報、使用状況、設定などのデータ収集サービス。`**
- Database Migration Service
    - **`同一DB製品間での移行、別DB製品への移行サービス。`**
    - ソース：RDB,MongoDB,S3
    - ターゲット：RDB,DynamoDB,Redshift,Kinesis Data Streams,Elasticsearch Service, DocumentDB
- Server Migration Service
    - **`オンプレのVMware,Hypyer-Vの仮想マシンをAWSに移行するサービス。`**
- Snow Family
    - 簡単に言えば、暑さ、寒さや落下への耐久性ががある物理コンピュータのBOX。
    - 小さいものはティッシュケースほどの大きさから14mのものまである。
    - AWS Snowcone、AWS Snowball と AWS Snowmobile で構成される Snow ファミリーは、ほとんどのコンピューティング機能が組み込まれた多数の物理デバイスと容量ポイントを提供。https://aws.amazon.com/jp/snow/

## 5. ネットワーキングとコンテンツ配信
- VPC(Virtual Private Cloud)
    - 仮想ネットワークサービス。
    - マネージドファイアウォールサービスがリリースされた。https://dev.classmethod.jp/articles/aws-network-firewall/
- CloudFront
    - 静的および動的Webコンテンツを配信するCDNサービス。
- Route53
    - フルマネージドなDNSサーバサービス。
- API Gateway
    - **`RESTful APIを作成、デプロイできるサービス。`**
    - REST API, Websocket API, HTTP APIの３つのタイプをサポート。
- Direct Connect
    - オンプレーAWSネットワーク(VPC)を接続するプライベートサービス。
- App Mesh
    - マイクロサービスアプリ間の可視性とネットワーク制御を可能とするサービスメッシュサービス。
    - サポートしているサービス：Fargate,EC2,ECS,EKS,AWS上のK8sアプリ。
- Global Accelerator
    - **`複数のリージョンにトラフィックをルーティングすることを可能とするグローバルネットワークサービス。`**

## 6. コンテナ
- ECR(Elastic Container Registry)
    - **`フルマネージドなDockerコンテナレジストリサービス。`**
    - Dockerコンテナイメージの保存、管理、デプロイができる。
    - リポジトリはプライベート、パブリックとして作成可能
- ECS(Elastic Container Service)
    - Dockerコンテナのクラスタ管理サービス。
    - Fargate起動タイプ：サーバやクラスタの管理不要。
    - EC2起動タイプ：EC2でコンテナを実行するサーバのクラスタを管理。
- EKS(Elastic Container Service for Kubernetes)
    - フルマネージドなK8sサービス。
    - **`コントロールプレーン管理不要、複数AZ運用となるため、単一障害点がない。`**

## 7. VMware Cloud on AWS
- VNware SDDCスタックを、AWSのベアメタル上で実行できるオンデマンドのサービス。
- オンプレミスと同じ感じで、vSphere,VSAN,NSX,vCenterを利用できる。

##感想
Snow Familyに興味あり。エッジデバイスとしては、利用できそうです。
Outpostsも然りだけど、AWSがHW提供も含めやっているのは興味深い。
microstackを使ってMulti-nodeのopenstackをAWSに構築する

# 目的
microstackを使ってMulti-nodeのopenstackをAWSに構築する

# 参考
https://microstack.run/docs/multi-node

# 手順
microstackのrequirementsを確認
https://microstack.run/docs/multi-node
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76498/6059a27e-d598-82b1-a03d-6431630ed2d9.png)

# AWSでVMを作る(3つ)
- 3台構成で作ってみる
- control node x1, compute node x2用にVMを作る

## AMIの選択
ubuntu20.04を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76498/5530284c-2b3a-e712-a2c2-b91934076351.png)

## instance type
2CPU, 8G Memoryを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76498/e894513e-0508-57a8-6859-352d1f43709b.png)

## storage
100Gにする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76498/44b22fa6-8000-273b-63ce-4433272715e7.png)

# 作った3つのVM間でnetwork疎通ができるようにAWSのsecurity groupを設定する
スクショ省略

# control node作成
control nodeにするVMで実施

```bash:bash
# snapでmicrostackをinstall
$ sudo snap install microstack --devmode --beta

# microstackのcontrol nodeをinstall
$ sudo microstack init --auto --control

# compute nodeがjoinする際に使うconnection-stringを確認（後でcompute nodeをinstallする時に使う)
$ sudo microstack add-compute
Use the following connection string to add a new compute node to the cluster (valid for 20 minutes from this moment):
hKhob3N0bmFtZa0xMC4yNDYuMTE0LjEwq2ZpbmdlcnByaW50xCAdnnsr99XBP9rLu0/+McUBiXTr4TG7ScdsMZJCgzpLzKJpZNkgNzFkMTY3YjU0ZmUwNGY2ZDgyODM0MGY4MmE0ZjE5NWamc2VjcmV02SBjN1ZuTUhnV1o3bmw3aX
puMXFTd3NxNncwRjE3ZG80OQ==
```

# compute node作成
compute nodeにするVM x2で実施
<connection-string>は上の`sudo microstack add-compute`の実行結果の文字列に置き換える

```bash:bash
# snapでmicrostackをinstall
$ sudo snap install microstack --devmode --beta

# microstackのcompute nodeをinstall
$ sudo microstack init --auto --compute --join <connection-string>
```

# 状態確認

```bash:bash
# control nodeで実施。compute node x2含めて見えればOK
$ microstack.openstack hypervisor list
+----+----------------------------------------------------+-----------------+-----------------+-------+
| ID | Hypervisor Hostname                                | Hypervisor Type | Host IP         | State |
+----+----------------------------------------------------+-----------------+-----------------+-------+
|  1 | ip-xxx-xxx-xxx-xxx.ap-northeast-1.compute.internal | QEMU            | xxx.xxx.xxx.xxx | up    |
|  2 | ip-xxx-xxx-xxx-xxx.ap-northeast-1.compute.internal | QEMU            | xxx.xxx.xxx.xxx | up    |
|  3 | ip-xxx-xxx-xxx-xxx.ap-northeast-1.compute.internal | QEMU            | xxx.xxx.xxx.xxx | up    |
+----+----------------------------------------------------+-----------------+-----------------+-------+
```

# httpでhorizonにloginしてみる

horizonにloginする際のpasswordを取得

```bash:bash
$ sudo snap get microstack config.credentials.keystone-password
xxxxxxxxxx
```
# httpでcontrol nodeにアクセスする
http://[control nodeのip]

# 最後に
microstackを使うことで非常に簡単にopenstackのmulti node環境を構築できました。
Compose for Web を導入してみた感想

# はじめに

先日 Compose for Web というライブラリが発表されました。

https://blog.jetbrains.com/kotlin/2021/05/technology-preview-jetpack-compose-for-web/

Kotlinを使って、フロントエンドのReactぽい記法でWebを作ることができます。

まだプレビュー版なのでプロダクションコードに組み込むのは厳しいです。
そこでとあるプロジェクトの裏側にある開発者向けページに導入してみて使い心地を試しました。

# いままで

そのとあるプロジェクトではKotlinでサーバーを開発しているためKotlinエンジニアはたくさんいます。しかし、ページを作るにはHTMLやJavaScriptを書かないといけないので普段やっていないことをやる煩わしさがありました。また、ReactやVueJSなどのWebフレームワークは使っていなくてjQueryで作っているのでコピペでidが重複して動かなくなったりDOM操作があちこちにあって後から修正しずらいなどの課題がありました。

# 導入してみる

Compose for Web の導入は簡単で公式サンプル( https://github.com/JetBrains/compose-jb/tree/master/examples/web_landing )から build.gradle.kts などをコピーしてパスなどをちょっと合わせるだけで導入できました。

また既存のサイトにIDを指定して部分適用できるため、jQueryで書かれたページの一部分だけに導入することができました。少しずつ置き換えていけるのはとてもありがたいですね。

```kotlin
fun main() {
    renderComposable(rootElementId = "root") {
        // ...
    }
}
```

また onClick などのイベントリスナーを直接書けるので、jQueryの時のようにidをつけて対応づけるひつようがなくなりとても楽ちんになりました。

```kotlin
Button(
  onClick = {
    viewModel.showPopUp()
  }
) {
  Text("Button")
}
```

またReactやAngularJSなどの既存のWebフレームワークと違うと思ったのが表示を更新したいときです。今までのWebフレームワークではステートやスコープなどのフレームワーク独自の約束事がたくさんありました。Compose for Web ではほとんど意識することなく普段Kotlinを書いている感覚で実装できました。

```kotlin
val counter = mutableStateOf(0)

@Composable
fun MyButton() {
  Button(
    onClick = {
      counter.value += 1
    }
  ) {
    Text("Button ${counter.value}")
  }
}
```

このあたりの書き方は本家のサンプルを眺めればすぐ理解できると思います。

# 感想

開発してみた感想としては

* 導入は思ったより簡単で安心。
* ページの一部分からちょっとずつ導入できる。
* jQuery時代の悩みが解決でき進化を実感。
* サンプルを見ながら素朴に作っていけばだいたい思ったように動いてしまう。学習コストはとても低そう。

おまけですが欠点としては

* まだデベロッパープレビューなので安定感はない
* コンパイラが自動生成したJavaScriptが長くて解読できない

ちょっとしたツールや社内向けのサイトを作るには現時点ですでに十分便利そうです。

これからに期待します。
[小ネタ]2次元ガウス関数の図示

#### まえがき
[すぐに使える!業務で実践できる! PythonによるAI・機械学習・深層学習アプリのつくり方 TensorFlow2対応 (日本語) 単行本 –](https://www.amazon.co.jp/%E3%81%99%E3%81%90%E3%81%AB%E4%BD%BF%E3%81%88%E3%82%8B-%E6%A5%AD%E5%8B%99%E3%81%A7%E5%AE%9F%E8%B7%B5%E3%81%A7%E3%81%8D%E3%82%8B-Python%E3%81%AB%E3%82%88%E3%82%8BAI%E3%83%BB%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%83%BB%E6%B7%B1%E5%B1%A4%E5%AD%A6%E7%BF%92%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AE%E3%81%A4%E3%81%8F%E3%82%8A%E6%96%B9-TensorFlow2%E5%AF%BE%E5%BF%9C-%E3%82%AF%E3%82%B8%E3%83%A9%E9%A3%9B%E8%A1%8C%E6%9C%BA/dp/4802612796)の3章4項でガウシアンフィルターなるものに遭遇。全くの初見だったので色々と調べると、

- 画像は高周波と低周波に分離可能
- 高周波は変化が激しく、低周波は変化が少ない。自然の画像だと低周波の部分が多くなる
- 一般に画像処理を行う際には、前処理として平滑化を行い、高周波の部分を少なくする(エッジやノイズを低減する)
- 平滑化を行うことで画像の本質である低周波の部分をなるだけ損なうことなく、処理をしやすくする(???)
- 平滑化のために使うフィルタにはいくつか種類があり、そのうちの1つがガウシアンフィルター
- ガウシアンフィルターは一律に平滑化するのではなく、注目画素からの距離に応じて重みを変えることで、自然な平滑化が実現できる(??)

らしいです。まあとにかく輪郭検出の際にやるルーティーンのようなものとのことでした。

#### 本編
ガウシアンフィルターは、以下の式に基づいて画像の平滑化を実行します。

$$f(x, y) = \frac{1}{2\pi\sigma^2}exp\left(-\frac{x^2 + y^2}{2 \sigma^2}\right)$$

$x,y$は注目画素からの距離、$\sigma$は標準偏差であり、$\sigma$を大きくするほどぼかしがきつくなるようです。

ここでシンプルに疑問に思ったのが、「そもそもこの関数は何者なのか？」ということです。最近は4次元以上の関数やベクトル？にかち合うタイミングも多く、図示ができずなかなかに理解に苦しんでいるのですが、「これだったら3次元でいけるじゃん！」ってことで、matplotlibを使ってグラフにしてみました。

##### コード
$x,y,\sigma$から値を返すガウス関数の関数を用意し、np.arrangeで指定した空間上にメッシュグリッドとして表示しています。3次元グラフをシンプルなコードでサクサクと描けてしまうmatplotlib君は本当に優秀です。

```python:gaussian.py
import math

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np

def gaussian_func(x, y, sigma):
    exponent = - (x ** 2 + y ** 2) / (2 * pow(sigma, 2))
    denominator = 2 * math.pi * pow(sigma, 2)
    return pow(math.e, exponent) / denominator

x = np.arange(-3.0, 3.0, 0.001)
y = np.arange(-3.0, 3.0, 0.001)
X, Y = np.meshgrid(x, y)
Z = gaussian_func(X, Y, 1)

fig = plt.figure(figsize=(10, 10))
ax = Axes3D(fig)
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("f(x, y)")

ax.plot_wireframe(X, Y, Z)
plt.savefig("gaussian.jpg")
plt.show()
```

##### 出力画像
今回は$(x, y) = (0, 0)$を中心としてあるため、そこから外側に向かってなだらかに下っていく形になりました。実際はこの中心が注目画素であり、そこから距離が離れるにつれてぼかしが強く、元の情報が損なわれていくのですね。実際の計算としては画素とガウシアン関数の値の畳み込み和らしいです。

![gaussian.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278439/2a39a05b-46ff-68fa-6bbb-5af958987227.jpeg)


#### あとがき
多分2割くらいしかわかっていないと思うんですが、少なくともガウシアンフィルターが何をやっているのか朧気に掴むことはできました。

集合知に感謝。

#### 参考サイト様
 - [イメージソリューション - ガウシアンフィルタの処理アルゴリズムとその効果 -](https://imagingsolution.net/imaging/gaussian/)
 - [西住工房 -【画像処理】ガウシアンフィルタの原理・特徴・計算式 - ](https://algorithm.joho.info/image-processing/gaussian-filter/)
 - [Daily Tech Blog - Gaussian Filter を用いた画像の暈し．-](https://daily-tech.hatenablog.com/entry/2020/05/07/150401)
 - [htsuda.net - 空間フィルタリングによる平滑化とエッジ検出 -](https://htsuda.net/archives/2064)
 - [Qiita - Python 3：3次元グラフの書き方（matplotlib, pyplot, mplot3d, MPL)-](https://qiita.com/orange_u/items/8a1e285a45093857aef7)
 - [Qiita - OpenCVで画像の平滑化をしてみた -](https://qiita.com/shoku-pan/items/07ec25f1d50629fed698)
Apache2 + phpのサイトでEUC-JPのHTMLが文字化けする

## 初めに
大昔にPHPで作られたWebサイトのローカル開発環境を構築した際、文字コードの周りでちょっと詰まったので解決策を記しておく。

## TL;DR
Apacheのconfファイルに`php_value default_charset EUC-JP` を書く

## 発生した問題
EUC-JPで書かれているコンテンツ(PHP, HTML, CSS, JavaScript等)をApacheというWebサーバーを使って返すサイトのローカル開発環境を、ホスト上に立てた仮想マシン上のDockerコンテナ上に作成した。各システムの概要は以下の通り。

- ホスト：Windows10 Home 20H2
- 仮想マシン
    - 仮想化ソフトウェア：VirtualBox 6.1.16
    - Box：bento/ubuntu-20.04
- コンテナイメージ：php:7.2-apacheのベースイメージでApacheのrewriteモッドを有効化したもの

開発環境が出来上がり、いざブラウザからアクセスしてみると、ページ上の日本語がすべて文字化けしていた......

## 原因調査 & 解決
まずブラウザ上でHTMLをどの文字コードで読み込まれているかを確認すると、UTF-8で読み込まれていた。メタタグで`<meta http-equiv="Content-Type" content="text/html; charset=EUC-JP" />`を指定しているのになんでUTF-8で読み込まれているのだろうかと色々調べた結果、メタタグでの指定は気休めでしかなく、実際にはファイルの内容やレスポンスヘッダの`Content-Type`の指定を見て決められるのだそう。
ファイルの内容はEUC-JPなので(だから文字化けが発生しているわけだが)、原因は`Content-Type`の値にあると考えた。Chrome Dev ToolsからHTMLファイルのレスポンスのヘッダを見てみると、案の定`Content-Type: text/html; charset=utf-8`になっていた。

`Content-Type`を明示的に指定した覚えはないので、ApacheもしくはPHPのデフォルトの設定が効いていると思われたので、調べて出てきたものを一つずつ試した。以下、試した順に記載する。

1. Apacheのconfファイルの`AddDefaultCharset UTF-8`をコメントインする、もしくは`AddDefaultCharset off`を明示する$^{[1]}$
1. php.iniで`default_charset = ""`を指定する$^{[2]}$
1. .htaccessで`AddType "text/html;charset=UTF-8" .html`を指定する$^{[3]}$

上記の方法ではレスポンスヘッダが`Content-Type: text/html; charset=utf-8`のまま変わらなかった（ほかのケースでは上記の方法のいずれかで解決できる可能性もあると思われる）。
そして、最後に試した以下の方法で解決できた。

- Apacheのconfファイルに`php_value default_charset EUC-JP` を書く

どうやらPHPのデフォルトの設定が悪さをしていたのかな？
なんにせよ無事解決できてよかった。

## 参考リンク
- [1] [Apache 文字化け対策 AddDefaultCharset](https://centos.bungu-do.jp/archives/28)
- [2] [WEBページの文字化けはApacheの設定だけではなかった](https://scribble.washo3.com/linux/web-garbled-characters-apacheweb-garbled-character-apache.html)
- [3] [apacheを使ってみる2(apacheの文字化けの修正)](https://qiita.com/jajaja/items/944904efef85ab5717f9)
Tera Termで「Cygwinディレクトリが見つかりません」とエラーが表示されてセッションの複製ができないときの解決策

備忘録です。

# 環境
- ホストOS: Windows 10
- ゲストOS: CentOS 7 (VirtualBox) 
- Tera Term: Version 4.105

# やりたいこと
Tera TermからVirtualBox上のゲストOSにsshポートフォワーディングで接続し、セッションの複製をおこなう。

# 問題
セッションを複製しようとすると、以下のようなエラーが表示されて複製できない。
![session_duplicate_error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472944/a5fc7c7f-c14f-3f42-d3a8-f4c694d2c0bb.png)

# 解決策
ポートフォワードに用いるホストポート番号を変更する。

# 原因
ポートフォワードに用いるポート番号を20022としていたが、この番号への接続はCygwinへの接続であると判断されてしまう。他の番号に変更することで、この仕様が回避されてセッションの複製ができるようになる。

参考：https://ja.osdn.net/projects/ttssh2/ticket/35854
>今の実装では、localhost の port 20000-20039 への接続は Cygwin 接続であると判断されます。
>問題を回避するには cygterm.cfg の PORT_START, PORT_RANGE の設定を変更するか、SSH を立ち上げるポート番号を変更してください。

# おわりに
しっかりと調べたら公式サイトのチケットが出てきて解決できる問題でしたが、自分はエラーメッセージのみで調べたためチケットが見つけられず、自力では解決できませんでした。この記事がどなたかの手助けになれば幸いです。
Chrome Remote Desktopで２画面→２画面で使う方法　

#目的
オフィスのPCが2画面の場合、リモートでも2画面で使用したい。

#簡単な説明
Chrome Remote Desktopを用いて２画面→２画面で使う方法は、簡単に言えばChrome Remote Desktopのリモートアクセス機能とリモートサポート機能の2回線使ってつなげることで可能です。


#手順を追った説明
手順を追って説明します。
1.Chrome Remote Desktopのリモートアクセス機能を用いて、家（リモート先）→会社（リモート元）とつなぎます。

2.Chrome Remote Desktopでつながっている会社（リモート元）PCのChrome Remote Desktopを立ち上げます。

3.会社（リモート元）PCのChrome Remote Desktopのリモートサポートを選んで、「この画面を共有」で「+コードを生成」を押します。

4.家（リモート先）のChrome Remote Desktopを立ち上げ、リモートサポートを選んで、「別のパソコンに説毒」で先程のアクセスコードを入力し接続します。

5.会社（リモート元）PCのほうに共有許可するのメッセージが出るのでOKを押す。
※別画面の方にでていることがあるので、Chrome Remote Desktopのディスプレイ切り替えで探しましょう。

6.2つのChrome Remote Desktopで会社（リモート元）に接続しているので、Chrome Remote Desktopの設定を用いて、それぞれのディスプレイを表示しましょう。
※Chrome Remote Desktopの設定を用いたディスプレイ表示方法は、ここでは説明しません。探してください。

7.会社（リモート元）PCのChrome Remote Desktopのリモートサポートを表示しているタブを消してしまうと画面共有が終了してしまうので気をつけましょう。

以上です。

はじめに入るときが若干手順が必要ですが、Chrome Remote Desktopの使い勝手が良くなりました。
azuriteを使ってローカルでtimer triggerを起動する

# はじめに

TimerTriggerをローカルで動かそうかなと思っていたらこんなエラーがでました。

```
Missing value for AzureWebJobsStorage in local.settings.json. This is required for all triggers other than httptrigger, kafkatrigger, orchestrationTrigger, activityTrigger, entityTrigger. You can run 'func azure functionapp fetch-app-settings <functionAppName>' or specify a connection string in local.settings.json.
```

functionsがAzureにある場合はlocal.settings.jsonをfetch-app-settingsを使って取得することでAzureWebJobsStorageの情報が設定されます。

ローカルで動かしている段階では大抵Azureにリソースはないと思います。

# 解決策

[azurite](https://docs.microsoft.com/ja-jp/azure/storage/common/storage-use-azurite)をインストールします。

```shell
npm install -g azurite
```

azuriteを起動します

```shell
$ azurite --silent --location /products/azurite --debug /products/azurite/debug.log
Azurite Blob service is starting at http://127.0.0.1:10000
Azurite Blob service is successfully listening at http://127.0.0.1:10000
Azurite Queue service is starting at http://127.0.0.1:10001
Azurite Queue service is successfully listening at http://127.0.0.1:10001
Azurite Table service is starting at http://127.0.0.1:10002
Azurite Table service is successfully listening at http://127.0.0.1:10002
```

BlobService,QueueService,TableServiceがそれぞれのポートで起動します。

あとはlocal.settings.jsonでazuriteを見るように修正します

```local.settings.json
{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "AzureWebJobsStorage": "UseDevelopmentStorage=true"
  }
}
```

functionsをローカルで起動します。

```shell
$ func start

Azure Functions Core Tools
Core Tools Version:       3.0.3442 Commit hash: 6bfab24b2743f8421475d996402c398d2fe4a9e0  (64-bit)
Function Runtime Version: 3.0.15417.0


Functions:

        export: timerTrigger

For detailed output, run func with --verbose flag.
[2021-05-18T02:40:04.799Z] Worker process started and initialized.
[2021-05-18T02:40:10.063Z] Host lock lease acquired by instance ID '0000000000000000000000005FB90853'.
[2021-05-18T02:45:00.072Z] Executing 'Functions.export' (Reason='Timer fired at 2021-05-18T11:45:00.0412924+09:00', Id=ff122567-13fe-46e8-81e0-948ac19ff6e0)
[2021-05-18T02:45:00.152Z] Timer trigger function ran! 2021-05-18T02:45:00.141Z
[2021-05-18T02:45:00.190Z] Executed 'Functions.export' (Succeeded, Id=ff122567-13fe-46e8-81e0-948ac19ff6e0, Duration=141ms)
```

# 参考

- [ローカルでの Azure Storage の開発に Azurite エミュレーターを使用する](https://docs.microsoft.com/ja-jp/azure/storage/common/storage-use-azurite)
URLの直打ち変更防止

そのままURLに直接打ち込む場合に他のログイン画面等へ遷移できてしまう。そういった直打ちという問題点を防止する必要がある。

今回はその直打ちの防止方法を記録する。

https://…….amazonaws.com/blogs/2/edit

上記のように2/editとURLへ記載する場合に、別のログインユーザーなどのアカウントへ行けてしまう。
#実施方法
（１）対象のコントローラーのストロングパラメータ内にどういった処理をするのかを記載する。
（２）関連するcontrollerにbefore_actionを設定する。

#具体例
(1)対象のコントローラーのストロングパラメータ内にどういった処理をするのかを記載する。
![図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1514036/02bb66fa-48fb-dc05-b6d8-c6a50e7dc392.png)


```csharp:books_controller.rb
 def ensure_correct_user
    @book = Book.find_by(id: params[:id])
    if @book.user_id != current_user.id
    redirect_to books_path
    end
  end
```

上記のメソッドを対象のコントローラーに記載をする。その際注意点として、ストロングパラメータ内に記載する。

①def ensure_correct_user
　定義文def_endを用いてメソッドを作る

②@book = Book.find_by(id: params[:id])
　ブックのidを見つけてくる

③if @book.user_id != current_user.id
　ifを用いて現在のログインしているユーザーと作成されたデータの持ち主の照合を行う。

④redirect_to books_path
正しいユーザーじゃないとトップページにリダイレクトされる。



(2)関連するcontrollerにbefore_actionを設定する。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1514036/617f24c6-1b11-1d15-5ff8-7bb113302669.png)


```csharp:books_controller.rb
 before_action :ensure_correct_user, only: [:edit, :update]
```

※before_actionメソッドは、このコントローラが動作する前に実行されます。
今回の場合、app/controllers/books_controller.rbファイルに記述したので、最初にbefore_actionメソッドが実行されます。

上記の記載では、[:edit, :update]のみログイン状態に関わらず、アクセス可能とするためのアクションを指定しています。このcorrect_userメソッドを上記のように設定すると、URL直打ちで対象ページに遷移しようとするとき、（ここではedit,updateアクション）正しいユーザーじゃないとトップページにリダイレクトされる。

またアクションが設定されていない場合の、ログイン認証が済んでいる場合には全てのページにアクセスすることができます。

※authenticate_userメソッドは、devise側が用意しているメソッドです。
:authenticate_user!とすることによって、「ログイン認証されていなければ、ログイン画面へリダイレクトする」機能を実装できます。
AWSサービス一覧(2021年)　気になったやつだけ　インフラ編(1/2)

##今回のフォーカス
下記ページのインフラに関わるサービスを簡単にサマリー。できれば1-2行でまとめたい。
長くなりそうなので、２回に分けます。
【2021年】AWS全サービスまとめ
https://dev.classmethod.jp/articles/aws-summary-2021/#toc-196

## 1. コンピューティング
- EC2
    - IaaSの一つ。Linux,Unix,Windows,macOS(いつの間に!?)対応。
    - EBSやELBと統合。EC2の場面から設定できるという意味かなと。
- Lambda
    - サーバレスサービス。
    - アプリコードorコンテナイメージをデプロイして、**`イベント駆動でコード実行できるサービス。`**
    - 最大実行時間：15分
- Elastic Beanstalk
    - PaaS。
    - **`Java、.NET、PHP、Node.js、Python、Ruby、Go および Dockerで開発されたWebアプリやサービスを、Apache、Nginx、Passenger、IIS などでデプロイおよびスケーリングするためサービス。`**
    - 因みに、Beanstalkの読み方は「Beans talk(豆たちの話)」ではなく、「Bean(豆) Stalk(スターク：茎)」らしいです。
- Outposts
    - オンプレミスをAWSのインフラやサービスを使えるフルマネージドサービス。
    - 42Uラック、**`１U,２Uが提供。`**https://dev.classmethod.jp/articles/aws-outposts-1u-2u-form-factors-announce/
- EC2 Image Builder
    - EC2やオンプレ用のLinux/Winのイメージ(コンテナイメージ含む)作成を自動するパイプラインサービス。

## 2. ストレージ
- S3
    - オブジェクトストレージ。`**
    - **`年間で99.99%(four-nines)の可用性、99.999999999%(eleven-nines)の耐久性。`**
- S3 Glacier
    - コールドデータ用の低コスト、高耐久性のストレージサービス。
    - バックアップやアーカイブ向け。
- EFS
    - フルマネージドな**`NFSサービス`**。
    - ペタバイトクラスまで自動スケール可能。
- FSx
    - フルマネージドの**`ファイルーサーバサービス`**。FSx for WinとFSx for Lustreの２種類ある。
    - FSx for Win:Win向けのファイルサーバ。
    - FSx for Lustre:HPC/機械学習向けファイルサーバ。
- Backup
    - バックアップを集中管理および自動化するサービス。
    - EC2/EBS/EFS/FSx/RDB/DynamoDBなどに対応。

## 3. データベース
- RDS
    - フルマネージドなRDBサーバのサービス
    - 6個のDBから選択が可能。
        1. Amazon Aurora
            - **`マルチクラスター構成、Aurora Serverless(自動起動/停止、拡張)、グローバルデータベース(複数リージョンにまたがった構成)`**
        1. PostgresSQL
        1. MySQL
        1. MariaDB
        1. Oracle 
        1. MS SQL
- DynamoDB
    - フルマネージドなKey-Value型のNoSQL DB。
- ElastiCache
    - フルマネージドな**`分散インメモリDBサービス`**。
    - キャッシュエンジン：memchached, Redis
- DocumentDB
    - フルマネージドなドキュメント指向DB.
    - **`MongoDB互換あり。`**
- Keyspaces
    - フルマネージドな**`Apache Cassandra互換`**のDBサービス。
    - Cassandraクエリ言語(CQL)アプリをAWSへ移行できる。
- Timestream
    - フルマネージドな時系列DBサービス。
    - **`IoTなどから収集したタイムスタンプを持つ時系列データの保存、検索、分析が可能。`**
    - https://dev.classmethod.jp/articles/amazon-timestream-ga/

##感想
Timestream気になりますね。今回新しくGAになったらサービスとのこと。
めちゃくちゃ便利そうだけど、料金みると、高いきもするので、検証として使って、本番はオンプレで作るというのもありかなと。
wallShearStressの計算

# はじめに
OpenFOAMでの壁面せん断応力（wallShearStress）の算出方法を以下にまとめます。

# 計算方法

壁面せん断応力は、壁面境界上での応力テンソルと法線方向ベクトルとの積で求められます。

```math 
\tau = {\bf R} \cdot {\bf n}
```

ここで、

| | |
|:--- | :--- | 
| $\tau$ | wall shear stress [m$^2$/s$^2$] |
| R |  shear stress symmetric tensor (retrieved from turbulence model) |
| n | patch normal vector (into domain) |

となります。

ターミナルでOFのresultファイルがあるディレクトリに移動し、

```bash
<solver> -postProcessing -func wallShearStress
```

とすれば時間ディレクトリ以下にwallShearStressというファイルが追加されています。

functionObjectで読み出す場合は、`system/controlDict` に

```c++
wallShearStress1
{
    // Mandatory entries (unmodifiable)
    type            wallShearStress;
    libs            (fieldFunctionObjects);

    // Optional entries (runtime modifiable)
    patches         (<patch1> ... <patchN>); // (wall1 "(wall2|wall3)");

    // Optional (inherited) entries
    writePrecision  8;
    writeToFile     true;
    useUserTime     true;
    region          region0;
    enabled         true;
    log             true;
    timeStart       0;
    timeEnd         1000;
    executeControl  timeStep;
    executeInterval 1;
    writeControl    timeStep;
    writeInterval   1;
}
```
を加筆することになります。
ここでpatchesで、対象壁面を指定することができます（先の計算ではすべての面についてのwall shearが計算されます）。

あとは、paraviewなどで壁面せん断応力の分布などを表示すればよいです。

# おわりに
簡単ですが、以上になります。
Ruby on Rails と Vue.js で csv 出力したい

## 背景
backend に rails 、 front に vuejs という環境で、vuejs 側に用意してあるボタンを押すと csv ファイルがダウンロードされるという機能を作成したい。

* csv は excel で扱いたいため utf-8(bom付き) を使用する。
* csv ファイルの作成は サーバー側で行う。
* 利用ブラウザは Google Chrome を想定。

### 処理の流れ

1. vuejs側でcsvダウンロードボタンを押す
1. rails側でcsvファイルを作成する
1. vuejs側にblobでファイルを受け渡しダウンロードする

### つまづいたこと
rails側でcsvファイルを作成する際、以下のコードのように rails側で文字コードを utf-8(bom付き)に指定したファイルを作成した。
しかし、blob 経由の vuejs側でダウンロードするとただの utf-8 になっていた。

```ruby:content.csv.ruby
require 'csv'
bom = "\uFEFF"
CSV.generate(bom) do |csv|
  csv << [
    'id','名前','作成日時'
  ]
  @contents.each do |content|
    csv_column_values = [
      content.id,
      content.name,
      content.created_at
    ]
    csv << csv_column_values
  end
end
```

```js:sample.vue
<template>
  <div>
    <button @click="downloadContent()"> CSVダウンロード </button>
  <div>
</template>

・ ・ ・ 省略 ・ ・ ・

// contentコントローラーのuser_reviewアクションにpostしてcsvをblobでダウンロード
async downloadContent() {
  const response = await axios.post(`/contents/user_review.csv`, {}).catch((error) => {
    ・ ・ ・ 中略 ・ ・ ・
  });
  if(response) {
    const blob = new Blob([response.data], {type: 'text/csv'});
    this.downloadCsvBlob(blob, "Content.csv")
  }
},

// csvをダウンロードする（Chromeを想定）
downloadCsvBlob(blob, fileName) {
  const url = URL.createObjectURL(new Blob([blob], {type: 'text/csv'}));
  const linkEl = document.createElement('a');
  linkEl.href = url;
  linkEl.setAttribute('download', fileName);
  document.body.appendChild(linkEl);
  linkEl.click();
  URL.revokeObjectURL(url);
  linkEl.parentNode.removeChild(linkEl);
},
```

結論から言うと bom付きかどうかの指定は vuejs側の blob で行わなければいけなかった。

## 修正内容

rails側でcsvを作成するときはutf-8を指定する。

```content.csv.ruby
require 'csv'
# bom = "\uFEFF" を削除
CSV.generate(encoding: Encoding::UTF_8) do |csv| # 変更 UTF-8 とだけ指定する
  csv << [
    'id','名前','作成日時'
  ]
  @contents.each do |content|
    csv_column_values = [
      content.id,
      content.name,
      content.created_at
    ]
    csv << csv_column_values
  end
end
```

bom付きかどうかは vuejs側の blob で行う。

```js:sample.vue
・ ・ ・ 変更なしのため省略 ・ ・ ・

// contentコントローラーのuser_reviewアクションにpostしてcsvをblobでダウンロード
async downloadContent() {
    ・ ・ ・ 中略 ・ ・ ・
},

// csvをutf-8(bom付き)でダウンロードする（Chromeを想定）
downloadCsvBlob(blob, fileName) {
  const bom  = new Uint8Array([0xEF, 0xBB, 0xBF]); // 変更 先頭の3バイト（BOM）を変数 bom へ代入
  const url = URL.createObjectURL(new Blob([bom, blob], {type: 'text/csv'})); // 変更 データの先頭に bom を配置
  const linkEl = document.createElement('a');
  ・ ・ ・ 変更なしのため以下省略 ・ ・ ・
```

これでcsvファイルをbom付きでダウンロードできた。
PHP Laravel アクセス修飾子のルールを一旦整理する

# 目的

- PHPのアクセス修飾子をなんとなくで使用していたのでこの機会にちゃんと整理する

# 記事を書いた経緯（自分用）

- LaravelでDI（依存性の注入）をしている時になんとなくコントローラークラスの最初の方で`private $userService;`と記載してコントローラークラスのプロパティを定義していた。
- ちゃんと意味を理解できておらず「とりあえずこういうふうに記載するとDIできる」と覚えていた。
- `private`がどのような意味を示しているかを整理してみる。

# アクセス修飾子

### private

| ケース | アクセス可否 |
| --- | --- |
| 同クラス内アクセス | ○ |
| 継承先でのアクセス | ✕ |
| インスタンス化後のアクセス | ✕ |

### protected

| ケース | アクセス可否 |
| --- | --- |
| 同クラス内アクセス | ○ |
| 継承先でのアクセス | ○ |
| インスタンス化後のアクセス | ✕ |

### public

| ケース | アクセス可否 |
| --- | --- |
| 同クラス内アクセス | ○ |
| 継承先でのアクセス | ○ |
| インスタンス化後のアクセス | ○ |

- `public`だとどこからでもアクセスできるらしい。アクセス修飾子を指定しない場合自動的に`public`になる。
- 指定しないなら

# 参考文献

- [https://www.php.net/manual/ja/language.oop5.visibility.php](https://www.php.net/manual/ja/language.oop5.visibility.php)
[Kotlin]半透明の操作不可用のViewを表示する。

#はじめに
ユーザー操作を防ぐために、半透明の膜をActivity画面の最前面に作成する。


#ソース
```kotlin.kt
    var vwFilm: View? = null
    protected fun showFilm(){
        if(vwFilm == null) {
            this.vwFilm = View(this)
            vwFilm?.setBackgroundColor(Color.parseColor("#66FF00FF"))
            addContentView(vwFilm, ViewGroup.LayoutParams(base.width, base.height))
            vwFilm?.bringToFront()
            //イベントを下の要素に貫通させないために空リスナーをセット
            vwFilm?.setOnClickListener { }
        }else{
            vwFilm?.isVisible = true
        }
    }

    protected fun hideFilm(){
        //メインスレッドを明示しておく。
        GlobalScope.launch(Dispatchers.Main) {
            vwFilm?.isVisible = false
        }
    }
    
    fun exec(){
        showFilm()
        thread {
            Thread.sleep(2000)
            hideFilm()
        }
    }

```
［php初学者］型宣言とかnull系について

#phpの型宣言
phpは[7.0](https://www.php.net/manual/ja/migration70.new-features.php)以降型宣言ができるようになりました。
元々は自動で型変換をしてくれていました。(coercive)
しかし、それだと見落としがちなバグなどに気づかないまま開発している...なんてことも多々あるらしく、この新機能はとても嬉しいものであったりします。

```sample.php
<?php
string $sample = 'sample';
sample1($sample);
sample2($sample);

//デフォルト
function sample1($sample1){
  var_dump($sample1);
}
//新機能
function sample2(string $sample2){
  var_dump($sample2);
}
```
例えば、sample2の引数$sample2の型をintとかに変更するとエラーが出ると思います。

#戻り値の型指定
これに加え、関数の戻り値も指定することができました。

```sample.php
<?php
string $sample = 'sample';
sample1($sample);
sample2($sample);

//デフォルト
function sample1($sample1){
  var_dump($sample);
}
//新機能
function sample2(string $sample2): string{
  return sample2 . '&test2';
}
```

`: string`とかで指定できます。
ここをintとかに変えればエラーが出るはず...(出るよね？...)

#nullableについて
変数内にnullを含めるか含めないかの違い。
phpでは、`?`が使われます。（デフォルトのやり方でもできる`= null`）

```sample.php
<?php
string $sample = 'sample';
sample1($sample);
sample2($sample);

//デフォルト
function sample1($sample1){
  var_dump($sample);
}
//新機能
function sample2(?string $sample2): string{
  return sample2 . '&test2';
}
```

`?string $sample2`の`?`がnullableの部分になります。
phpは、[7.1](https://www.php.net/manual/ja/migration71.new-features.php)以降使えます。

#null合体演算子
簡単に言えば、`??`←これですね。

説明
null合体演算子は「??」の左辺がnullでなければ左辺を返し、nullであれば右辺を返します。

```sample.php
<?php
//1行目
$user = $who ?? 'nobody';
//2行目
$user = $who ?? $where ?? 'nobody&not here';
?>
```
上記は、phpマニュアルと似たように書きました。
1行目　`$who`がnullの場合、`'nobady'`を返す
2行目　`$who`がnullの場合、さらに`$where`がnullの場合、`'nobody&not here'`を返す
と言う意味になります。

簡単に言えば、`if($who == null)$user = 'nobady'`を短縮した形になります。
これは、[7.0](https://www.php.net/manual/ja/migration70.new-features.php)以降にでた新機能です。

#終わりに
めちゃくちゃ雑な説明になってしまい、すみません。。。
現在、少しずつphp, Laravel, AWSとかエンジニアに必要な基礎知識を吸収中です。
今は、自分の再度確認用or復習用として記事を書いています。
もう少しコアで面白い記事書けるように日々精進して参ります！
データベースの設定について

#データベース設定の変更
##database.yml
Railsアプリケーションのデータベースの設定ファイルです。
database.ymlは、configというディレクトリ内にあります。

Ruby on Railsは、このdatabase.ymlを編集することで、データベースの設定を運用環境ごとに変更できる仕組みになっています。

##運用環境
システムをどこで使用するか定められている環境を運用環境と呼びます。
運用環境を使い分けることで効率的に作業を行うことが可能です。

運用環境には3つの種類があり、以下のような使い分けをします。

```
運用環境	   通称	   概要
development  開発環境	主にアプリケーションを開発をする際に使用する環境
test	     テスト環境  アプリケーションの動作をテストする際に使用する環境
production   本番環境	アプリケーションを実際にリリースする際に使用する環境
```
なぜこのように環境が分かれているかというと、環境ごとに設定の変更が必要なケースが多く存在するためです。
たとえば、開発環境であれば「バグを探しやすいツール」などを導入した方が便利ですが、本番環境ではWebアプリケーションのパフォーマンスを上げるために、余分なツールは使わない方が適切と言えるでしょう。
Pythonista3: WikipediaのURLをWikipedia PageIDのURLに変換する

# はじめに
本コードはiOS版アプリPythonista3[^1]を用いて、クリップボードにコピーされたWikipediaのURL（テキスト形式）をWikipedia PageIDのURLに変換してクリップボードにコピーし直すというものです。
1. URLをクリップボードにコピー
1. Pythonista3を起動
1. 本コードを実行
1. Pythonista3のコンソールに変換後URLを吐き出す
という趣旨です。
# ところで
3つ目の投稿……とはいえ、1つ目の投稿と似たようなものになってしまいました。2021-05-18時点でPython歴3週間です。改善点等があればご指摘いただければ助かります。投稿のお作法さえもまだまったく分からない状態です……。
# きっかけ
詳細は[初投稿の方](https://qiita.com/ekemtt/items/5256860b6a026067f6e2 "Python: WikipediaのURLをWikipedia PageIDのURLに変換する")に記載した通りです……が、そのことを思いついた時、ちょうど電車で長距離を移動しなければならないにも関わらず、パソコンを持ち歩かなかったために、最初にPythonista3を使ってソースコードを書いたのでした。このアプリ、iOSなだけあってカーソル移動がやはり不便なので、こっちの方が大変だった記憶しかありません。おかげでリニアモーターで無理やり地中深くから地上近辺まで乗り上げたりする、丹下健三作品[^2]に出勤する人たちと本郷キャンパスに通う人たちのためだけに路線計画がされたんじゃないかと邪推してしまう電車で「の」の字の部分での乗り換えに失敗して、端から端まで旅をしてしまいました[^3]。そのため、こちらの方がコードが雑です。
# 前準備
Pythonista3は有料です。別途お買い求めください。
# ソースコード
下記のコードを作成します。

```python:wpu2wpid.py　(1)
import re
import sys
import requests
import clipboard

in_text = clipboard.get() #クリップボードを取得

#------------
#URL判定ブロック
if not 'https://' in in_text:
	sys.exit("ハイパーリンクではありません。") #クリップボードの内容をそのままで終了
	
if '?curid=' in in_text:
	sys.exit("既に変換済みです") #クリップボードの内容をそのままで終了
	
lang = in_text[8:10] #言語抜き出し

text = in_text.replace('https://', '') #URL抜き出し（行程1）
text = text.replace(lang, '') #URL抜き出し（行程2）

if not '.wikipedia.org/wiki/' in text:
	sys.exit("Wikipediaのアドレスではありません") #クリップボードの内容をそのままで終了
	
text = text.replace('.m.wikipedia.org/wiki/', '') #URL抜き出し（行程3）

#------------
#変換ブロック
def getWikiData(url, params): #getWikiDataという関数を作成
	res = requests.get(url, params = params)
	return res.json()
url = 'https://' + lang + '.wikipedia.org/w/api.php' #WikipediaのAPIを使用
params = { "action" : "query",
			"titles"  : text,
			"format"  : "json"
			} #変数paramsにWikipediaのAPIからの情報を代入
wtext = getWikiData(url, params)
print(wtext)
wpid = str(wtext['query']['pages'])
wpid = wpid[2:]
wpid = re.search(r'\d+', wpid)

idurl = 'https://' + lang + '.wikipedia.org/?curid=' + wpid.group()
clipboard.set(idurl)
sys.exit("クリップボードにコピー完了：" + idurl) #操作完了報告
```

# 終わりに
-最後の行をちょちょっと変えれば、クリップボードに書き戻すというのもアリだと思います。「ショートカット」を使用した時にどちらの方が便利なのか、まだ分かりかねている状態です。
+クリップボードに変換後のリンクがコピー、コンソールに表示されます。
# 謝辞
早速のご教示ありがとうございます。
[^1]: iOS上でPython3を実行できるアプリ。一部モジュールが使えないが、アプリ「ショートカット」にも対応しているため、かなり多様な使い道があると思います。……というか、こういうことができるようにするの、スティーヴ・ジョブズなら許さなかっただろうなあ。
[^2]: 私、実は彼の建築のファンなんですよね。ただし**外側**だけ。内部は空洞にして地下を掘って、快適な空間は別の人に設計してもらえばよかったのですよ。あの人の建築は**オブジェとして**優れているのです。偉い人にはそれがわからんのです。
[^3]: パソコンを持ち歩いたとしても同じだっただろうとか、あんたそんなに集中力あったっけ、という種類のツッコミはご勘弁ください。
PHP：Laravel Strageを利用した複数画像uploadする方法1つとFlysystem-aws-s3で複数画像をuploadする方法2つとその処理速度

## 前提
・AWSアカウントが存在していてS3バケットが作成済である。
https://qiita.com/Yorinton/items/bdf5f9bc05629c9a0df7
・laravel Strageが利用できる。
https://readouble.com/laravel/8.x/ja/filesystem.html
・Flysystem-aws-s3をインストール済みである （AWS SDK for PHP laravelでもよいかな？）
https://www.ritolab.com/entry/8
https://qiita.com/ucan-lab/items/61903ce10a186e78f15f

## laravel Strageを利用したupload方法

**upload方法その1**

```PHP
foreach (Storage::disk('public')->files('TARGET_DIR') as $fileName){
    $contents = Storage::disk('public')->get($fileName);
    Storage::disk('s3')->put('UPLOAD_TARGET_DIR' . $fileName, $contents);
};
```

45ファイルをアップロードした時の
実行時間：1.089635848999秒
メモリ使用量：5501696バイト

## Flysystem-aws-s3を利用したupload方法

**S3Clientをnewする**

```PHP
$client = new S3Client([
    'credentials' => [
        'key' => 'AWS_ACCESS_KEY',
        'secret' => 'AWS_SECRET_ACCESS_KEY',
    ],
    'region' => 'ap-northeast-1',
    'version' => 'latest',
]);
```

**upload方法その2**

```PHP
foreach (Storage::disk('public')->files('TARGET_DIR') as $fileName){
    $params = [
        'Bucket' => 'BUCKET_NAME',
        'Key' => $fileName,
        'SourceFile'   => storage_path('app/public/') . $fileName,
    ];
    $client->putObject($params);
}
```

45ファイルをアップロードした時の
実行時間：0.97133994102478秒
メモリ：1193024バイト

**upload方法その3**

```PHP
$client->uploadDirectory(storage_path('app/public/') . 'TARGET_DIR', 'BUCKET_NAME' . 'UPLOAD_TARGET_DIR');
```

45ファイルをアップロードした時の
実行時間：0.68526291847229秒
メモリ使用量：1509568バイト

## 結果

laravel Strageを利用したupload方法だと時間がかかる上、メモリもだいぶ喰らう。
Flysystem-aws-s3やAWS SDK for PHPなどを利用してファイルをアップしたほうが良さそう。
実現したいことに合わせてupload方法その2と3を使い分けたほうがいいカモ？
ROUGE-Sスコアの算出方法

ズバリROUGE_Sスコアの算出方法は以下の通り

$ROUGE-S_{single}(candidate, reference)=\frac{(1+\beta^2)R_{skip2}(candidate, reference)P_{skip2}(candidate, reference)}{R_{skip2}(candidate, reference)+\beta^2P_{skip2}(candidate, reference)}$
で求められる

$R_{skip2},P_{skip2}$は以下の通りに定義される


$R_{skip2}(candidate, reference)=\frac{\Sigma_{r_i \in reference} \Sigma_{skip-bigram \in r_i} Count(skip-bigram, candidate)}{\Sigma_{r_i \in reference} numSkipBigrams(r_i)}$

$P_{skip2}(candidate, reference)=\frac{\Sigma_{r_i \in reference} \Sigma_{skip-bigram \in r_i} Count(skip-bigram, candidate)}{\Sigma_{r_i \in candidate} numSkipBigrams(r_i)}$

$r_i$と$c_i$はともにreference文とcandidate文を表す
$Count(skip-bigram, candidate)$は、skip-bigramがcandidate文中で観測された回数を表す
$numSkipBigrams(s_i)$は、$s_i$文中のskip-bigramの数を表す

例えば、police killed the gunmanという文章があったときに、この文章に対するskip2 (skip-bigram)は (police killed, police the, police gunman, killed the, killed gunman, the gunman)
HTML, CSS, JavaScriptで掲示板システムを作ってみた【その3-要素が重なる問題】

# あらすじ
可愛い掲示板を作ってアンカーを実装したはいいものの、コメントを指差すアンカーをリンクで修飾してしまい、NotFoundエラーが出されてしまっていました。そこで、前回はアンカーをリンクではなく色付き文字だけで表現し直し、アンカーをクリックするとエラーページが表示される問題を解決しました。
<a href="http://colorful-wall.com/board/boards/">【作っている掲示板】</a>
![スクリーンショット 2021-05-18 10.24.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1467169/46e1d456-a709-600f-2ad2-a1b94b7ea22a.png)

しかしながら、新たにポップアップしたメッセージが下に隠れてしまう問題を新たに発見したので今回はそれを修正することにしました。
![スクリーンショット 2021-05-18 10.30.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1467169/b6987e73-7c63-caf7-c102-95defc15c4d8.png)
#今回のプログラミング
今回のプログラムでは再帰の深さ変数を利用し、この問題を修正しました!
重要なのはz-indexです。以前までは新しく来たものは上になるだろうという希望的視点から、z-indexを適当に1にしていました。しかし動かしてみると新しく来たものは下に隠れてしまいました。
今回ネットで調べてみるとz-indexは大きいほど上に表示されるパラメータで、このプログラムの場合は再帰の深さを表示する変数nがあるから、それを利用すればこの問題が簡単に修正できることに気がつき、すぐに1文字だけ置き換えてバグとりが終わりました。

 ```JavaScript:mihon.js
(function ($) {
            $("#comment").html($("#comment").html().replace(/&gt;&gt;(\d)/g,"<span x=id$1 class='anc text-primary id$1'>" + "&gt;&gt;$1" + "</span>"));

            func(0);
            function func(n) {
                var l = 0;

                $(".anc").on("click", function (e) {
                    if (l == 0) {//ポップは一つだけ
                        l += 1;
                        $(".container").prepend("<div class='pop" + n + "'>");

                        $(".pop" + n).css({//ポップの修飾
                            position: 'absolute',
                            border: '1px solid #ccc',
                            'background-color': 'white',
                            top: '0',
                            left: '0',
                            'z-index': n,
                            width:'50%',
                        })
                        var anc = $(this).attr("x"),//アンカーのx取得
                            res = "<table class='table'> <tr><th>番号</th><th class='mes'>メッセージ</th></tr><tr>" + $("#" + anc).html() + "</tr></table>",//id検索
                            x = e.pageX,
                            y = e.pageY;
                        $(".pop" + n)
                            .append(res)
                            .css({
                                transform: "translate3d(" + x + "px," + y + "px,0)"
                            })
                            .show();
                        $(".pop" + n).on("mouseleave", function () {//マウスが離れた時削除
                            $(this).remove();
                        })
                        $(".pop" + n).on("touchmove", function () {//画面をスワイプしたとき削除
                            $(this).remove();
                        })
                        func(n + 1);
                    }
                });
            }
        

        })(jQuery);
```

いい感じに表示できています。バグ取り成功!
![スクリーンショット 2021-05-18 10.46.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1467169/bb53819a-0852-33f2-b41a-0c5edf72dc3a.png)

# 終わりに
掲示板を公開して半月ほど経ちますが、僅かながらに書き込んでくれる方がいてやっぱり自分が作ったものが人に使われることがものづくりの喜びだなぁと思う今日この頃です。よかったら使ってみてください。

参考リンク
MDN Web Docs
Z-index
https://developer.mozilla.org/ja/docs/Web/CSS/z-index