OmniAICreator/Qiita-1.07M huggingface dataset:
Cognos Analytics の監査機能の拡張版の紹介

#はじめに
最近、学んでも直ぐ忘れてしまうので、学んだ事は未来の自分のためにも、日本語で投稿しておきます。

元ネタはこちらの記事ですが、Cognos Analyticsの監査機能の拡張版がある、という事を知っておいて頂ければと思います。

**IBM Cognos c11AuditExtension**
https://developer.ibm.com/tutorials/ibm-cognos-11-audit-extension/

#拡張監査機能で見れるもの
**ユーザーアカウント周り**
通常の監査ログでは、ユーザー名くらいしか監査ログDBに書き込まれませんが、これを使うとユーザーアカウントの、プロパティーの詳細情報、自分のポータルに何を設定しているかの情報、アカウントが作成され修正された日付、マイフォルダに何のコンテンツがあるか、というのが監査情報として取得できるようです。

**コンテンツ周り**
レポートとかフォルダーとかの、コンテントストア上のコンテンツの詳細な情報を監査情報として取得できます。
コンテンツの名前、パス、付与されている権限、作成および修正日、レポート内容が全て含まれるXML情報、クエリーの情報、レポートが保存されている場合は何のパラメーターを指定して保存されたか、保存レポートのバージョンに関する情報、などが監査情報として取得できるようです。

**役割や機能の権限周り**
例えば、「レポート作成」などの機能に対して、この機能が使用可能な役割やグループを登録して、機能に対する権限管理を行うと思いますが、この拡張監査では、どのユーザーアカウントがこの機能を利用したか、という監査情報の取得が可能なようです。

#拡張監査の使い方
上記の3つのタイプの拡張監査機能は、以下の方法によりON/OFFができるようです。
・WEBの管理画面
・URLで指令
・WEBサービスで指令

監査情報は、データベースに書き込まれるとのこと。

#使用可能環境
Cognos Analytics 11で使える。
カスタム認証を使用してる環境は注意。普通のユーザーID・パスワードを入力して認証させているだけの環境や、トラステッドサインオンを使っている環境であれば問題ないが、もっと別のクレデンシャル情報(SAMLとかもですかね)を使用しているカスタム認証の場合使えないので注意、だそうです。
書き込み先DBは、Db2、SQL Server、Oracleで、バージョン指定あり。

#セットアップ方法
拡張監査モジュールのインストール(解凍)がCognos Analyticsノードに対して必要で、セットアップ時に必要なテーブルは勝手に作成され、監査機能追加する対象ノードを指定するためのプロンプトが表示されるので、そこに対象ノードの情報を入力するようです。
セットアップは、概ね以下のステップで行います。
本当にやる時は、先の英語の記事を読んでください。詳細手順が書かれています。
・拡張監査モジュールをCognos Analyticsサーバー上で解凍し配置
・設定ファイルを環境に応じてカスタマイズ
・JDBCドライバーをdriversフォルダに置く
・WARファイルを作成
・WARファイルをCognos AnalyticsのWebSphere Liberty Profileにデプロイ
・WEBの画面からアクセスして、各種設定を行う
→この各種設定のところで、監査情報を書き込むDBの指定を行います。DBは、新しいDBでも良いし、既存の監査DBでも良いが、Content Storeを指定するんじゃないぞ、とのこと。
DBの準備方法も詳細に記載されていますが、既存の監査DBを使用するのが自然で楽なように思いますね。
※既存の監査DBを使用する場合、既存のテーブルに情報が書き込まれるのではなく、拡張監査用に新規にテーブルが作られるようです。

後は、監査ログパッケージのモデルをFramework Managerで開いて、拡張監査用のテーブルを取り込んで、モデリングして、パッケージ発行して、レポートで見る、という感じですね。

#モジュール入手
わかりにくいですが、英語の記事の右のメニューのRESOURCEのところで、「AuditExtension.zip」の文字をクリックすると、こちらのBoxのリンクに飛んで、ダウンロードできます。
https://ibm.ent.box.com/v/auditExt


以上です。
もし使った方がいらっしゃったら、是非フィードバック頂けるとうれしいです！

#メモ
Cognos Analytics 11.1.7/11.2.1で、以下の変更をしないと動作しなかったという情報がありましたので、メモ代わりに置いておきます。

```html
modify the build.bat file for the new jre location
from
  ..\..\jre\bin\java -classpath "../../bin/ant.jar;../../bin/ant-launcher.jar" org.apache.tools.ant.Main %*
to
  ..\..\ibm-jre\jre\bin\java -classpath "../../bin/ant.jar;../../bin/ant-launcher.jar" org.apache.tools.ant.Main %*
```
ステートフルなアプリのDocker化(ステートレス)についてチェックすべき部分

## 背景
ステートフルなアプリケーションをコンテナ化する場合、
コンテナライフサイクル上環境を破棄するため、
状態を中に持たないように改修しなくてはならない。

その際のチェックポイントまとメモ。

## チェックポイント
* セッション
    * クライアントのセッション情報を自サーバに保持せず、外出しする。  
    例) Spring Sessionを使用して Redis や RDBMSに保存する

* 設定まわり
    * アプリケーションやミドルウェアの制御を環境変数から読み込むようにする。  
        → k8sの場合はConfigMapへ
    * 認証情報は平文ではなくセキュアに環境変数に設定する  
        → k8sの場合はSecretへ

* ログ
    * ファイルにログを出力しているところ、ログローテートを削除し、標準出力に出すようにする。

* 永続化データ
    * サーバ内部にファイルを作成している場合、永続ストレージに保存するようにする。  
        → k8sの場合はPersistentVolumeへ

## さいごに
ツッコミ大歓迎です
Github の jupyter notebookをGoogle Colaboratoryで開く ブックマークレット

Github の jupyter notebook のファイルの、URLを変えるだけで Google Colaboratoryで開けると言うことらしいので、URLを置換してColabで開くブックマークレットを作った。  

## ブックマークレット（登録用）

※このコードをブックマークのURL欄に貼り付けてください。

```js
javascript:location.href=location.href.replace('https://github.com', 'https://colab.research.google.com/github');
```

## 使用例

以下のページで実行すると  
https://github.com/tensorflow/docs/blob/r2.0/site/ja/tutorials/quickstart/beginner.ipynb  
  
URLが置換されて Colabで開く  
  
https://colab.research.google.com/github/tensorflow/docs/blob/r2.0/site/ja/tutorials/quickstart/beginner.ipynb  


そのまま動くjupyterファイルばかりとは限らないけど、ちょっと試してみたい時とかに使えるかな。  

## 参考

[えるしってるか ColaboratoryではGithub上のjupyter notebookがひらける \| せかいらぼ](https://sekailab.com/wp/2018/05/24/colaboratory-github-jupyter-notebook/)
dmgファイルをマウントする


マウントという表現が正しいのかわかりませんが個人的にわかりやすかったので。
教えて~~偉い人()~~

参考(ってかこれ見れば良い): http://stupiddog.jp/note/archives/410

# マウント

```
$ hdiutil attach <dmg file>
```

# アンマウント

```
$ hdiutil detach
```
three.jsでふわふわでピカピカなパーティクルを作ってみました！

# はじめに
初めての three.js でパーティクルを作ったので、Qiita で初めての記事を投稿してみます。
three.js を学び始めたのはここ１カ月くらいな超ド級の初心者です。


# 経緯
上記で書いた通り超ド級初心者の私ですが、学び始めて約1カ月が経ったところで、
いままで学んだことのアウトプットとして、自分が大好きなパーティクルを作成しました。

パーティクル自体は専門学生時代に卒業制作の作品で、パーティクルを作るのに特化したとあるライブラリを利用しつつ作った経験があり、モワモワしててフワフワで、時にはシャッキシャキで、とにかく視覚を楽しませてくれるところが大好きです。


# 成果物
私は英語がまったくもって出来ないので（致命的）、ググって出てきた「fluff（ふわふわ）」と「glitter（ピカピカ）」の単語を合わせて「fluffs-glitters」という名前をこのパーティクルに授けました。

**fluffs-glitters**
<p data-height="265" data-theme-id="0" data-slug-hash="dQxxGg" data-default-tab="js,result" data-user="UtmHnn" data-pen-title="fluffs-glitters" class="codepen">See the Pen <a href="https://codepen.io/UtmHnn/pen/dQxxGg/">fluffs-glitters</a> by Hinano Utsumi (<a href="https://codepen.io/UtmHnn">@UtmHnn</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## パーティクルのデータ構造

- mesh (three.js のメッシュ)
- xDirection (メッシュの横軸方向の制御プロパティ)
- yDirection (メッシュの縦軸方向の制御プロパティ)
- xMoveSpeed (メッシュの横軸方向への速度制御プロパティ)
- yMoveSpeed (メッシュの縦軸方向への速度制御プロパティ)
- lifeCount (メッシュが画面に表示される寿命)

`mesh`を 500 個生成して、画面中央から上下左右の外枠方向に向かって放射状に拡散します。
メッシュの大きさとスピードはランダムな値で排出され、`opacity`の値は、画面中央から離れるにつれて低い値になります。

## パーティクルの挙動

```js
function updateCircles () {
  for (let i = 0; i < circles.length; i++) {
    circles[i].mesh.material.opacity -= circles[i].lifeCount

    if (circles[i].mesh.material.opacity <= 0) {
      circles[i].mesh.position.x = -0.5 + Math.random() * 1
      circles[i].mesh.position.y = -0.5 + Math.random() * 1
      circles[i].mesh.material.opacity = 1.0
    }

    circles[i].mesh.position.x += circles[i].xMoveSpeed * (circles[i].xDirection ? 1 : -1)
    circles[i].mesh.position.y += circles[i].yMoveSpeed * (circles[i].yDirection ? 1 : -1)
  }
}
```

描画フレームごとにメッシュを透過していき、`opacity`の値が 0 になったら、メッシュの座標を初期値にし、`opacity`を 1 に戻します。このようにメッシュの再利用を行うことで、必要最低限の数の描画で済ませています。


## パーティクルの加算合成
```js

opacity: 0.7,
blending: THREE.AdditiveBlending
```
メッシュに`opacity`と`blending`を設定して、透過させ加算合成を行うことで、光っぽさを出しています。

![image_02.png](https://qiita-image-store.s3.amazonaws.com/0/323928/7956d60e-3d50-8b7d-d8d0-e52eacde9e91.png)

# 感想
当初の自分は、というか今の自分も、JavaScript の基礎も学びつつ three.js を学習している最中なので、特別キレイなコードを書いたり、機能的な構造になっているプログラムを作ることは、まだとても難しいです。

自分が頭の中でイメージした表現と差分の無いアウトプットが出来るようになることを目指してこれからも学習したことをアウトプットしながら、力をつけていきたいです。
iPhone/safariでinput type=numberでマイナスの数値を入力する方法

#0. 今回お話しすること
+ 数値（正負両方）しか入力しないフィールドを作り、キーボードの初期選択を数値キーボードにしたかったよ
+ input type=telだとキーボードにマイナス記号がなかったのでinput type=numberにしたよ
+ focus時に数値キーボードが初期表示されるようになったけど、iPhone/safariだとマイナス記号が入れられなくなったよ
+ どれだけ検索しても解決策が見つからなかったけれど、妙案（苦肉の策）を思いついたよ

#1. どうやったか
まずは肝となる部分のソースを記載します。
※実はこのままの記述だと、android/chromeでは不都合があります。（後述）

``` html:HTML
<input type="number" id="target" />
```
``` javascript:Javascript
$("#target").focus(function(){
	$(this).prop("type", "text");
});
$("#target").blur(function(){
	$(this).prop("type", "number");
});
```

#2. どんな考え方なのか
```input type="text"``` だと、focus時に英字キーボード（数字が表示されていないキーボード）が表示されてしまいます。数値しか入力しないようなフィールドの場合、ユーザがキーボードを切り替えるひと手間はなくしてあげたいですよね。なので、focus時には```input type="number"``` であってほしいわけです。

ですが、文字を入力し始めたときに```input type="number"``` だと、はじめにマイナス記号を入力した時点で入力規則にひっかかるのか強制削除されてしまいます。なので入力をし始めた時には自由な```input type="text"``` であってほしいわけです。

・・・なら、focus時にtype変えちゃえばよくない？

という解決法です。

#3. この記述の不都合
iPhone/safariではこの記述で問題なく動くのですが、android/chromeだとfocusしてもキーボードが表示されなくなってしまいます。focusイベント内でtypeを変えるのが気に入らないのでしょう。なので実際に使うときには


``` javascript
$("#target").focus(function(){
	if(navigator.userAgent.indexOf('Android') == -1){
		$(this).prop("type", "text");
	}
});
```

のような形でAndroidを省くか、逆にiPhone, iPadのみ動作するようなif文で囲ってあげましょう。
[メモ] saml2awsでのログインを楽にしたい

## 背景
saml2awsを導入された。

```
Identity Providers: Google Apps
```

saml2awsの導入の話はこちら: https://qiita.com/tarumzu/items/7a20f8b414815de02b8e

毎回ログインは面倒くさいので、楽にしたい！

## トークンの有効期間
デフォルトは`1 hour`で、流石に短すぎて、面倒くさい。最大の`12 hour`まで伸ばした。

```text:~/.saml2aws
[idp_my_google]
app_id               =
url                  = url 
username             = username
provider             = GoogleApps
mfa                  = Auto
skip_verify          = false
timeout              = 0
aws_urn              = urn:amazon:webservices
aws_session_duration = 43200
aws_profile          = my_saml
subdomain            =
```

aws_session_durationの値を**43200**(12 hour)に修正した。

## AWS Profile
AWS Profileの指定も面倒くさいので、いつも使うProfileを環境変数として保存しました。

```text:~/.bashrc
export AWS_REGION=ap-northeast-1
export AWS_PROFILE=my_saml
export AWS_DEFAULT_REGION=ap-northeast-1
export AWS_DEFAULT_PROFILE=my_saml
```

複数のprofileを使う場合は、指定する必要があります。

## ユーザー名とパスワード
ユーザーとパスワードもパラメーターで渡したい

```shell:~/aws-auth
saml2aws login -a idp_my_google --username=username --password='password'
```

それで、エンターキーを押すと携帯に届くGoogle App承認通知の`yes`ボタンを押すだけで認証が完了です。

## ロール
同じGoogleアカウントで複数のAWSアカウントを持っている場合はロールの選択が必要です。それもパラメーターで渡せます！

まず、ロールが分からない時に`list-roles`で調べましょう。

```shell
$ saml2aws -a idp_my_google list-roles
Using IDP Account idp_my_google to access GoogleApps xxxxx
To use saved password just hit enter.
? Username user_name
? Password

Open the Google App, and tap 'Yes' on the prompt to sign in

Account: account_1 (xxxx)
arn:aws:iam::xxxx:role/Developer

Account: account_2 (xxxx)
arn:aws:iam::xxxx:role/Administrator
```

account_2を使いたい場合は、`aws-auth`スクリプトを修正します。

```shell
saml2aws login -a idp_my_google --username=username --password='password' --role='arn:aws:iam::xxxx:role/Administrator'
```

## エンターキーも押したくない （ from @osd ）

```shell
saml2aws login -a idp_my_google --username=username --password='password' --role='arn:aws:iam::xxxx:role/Administrator' --skip-prompt
```

それで携帯での`yes`ボタンを押すだけで認証完了。

## 参照
- https://aws.amazon.com/jp/blogs/security/enable-federated-api-access-to-your-aws-resources-for-up-to-12-hours-using-iam-roles/
- https://github.com/Versent/saml2aws
【Swiftでデザインパターン】TemplateMethod

# 定義
> Template Method パターン（テンプレート・メソッド・パターン）とは、GoF(Gang of Four; 4人のギャングたち)によって定義されたデザインパターンの1つである。「振る舞いに関するパターン」に属する。Template Method パターンの目的は、ある処理のおおまかなアルゴリズムをあらかじめ決めておいて、そのアルゴリズムの具体的な設計をサブクラスに任せることである。そのため、システムのフレームワークを構築するための手段としてよく活用される。

[wikipedia](https://ja.wikipedia.org/wiki/Template_Method_パターン)から定義をお借りしました。

処理の大枠を共通化しつつ、肝心なところの処理をサブクラスやプロトコルの適合者に任せるためのパターンです。

Swiftでの実装パターンを２つ考えてみました。

# クラスを使ったパターン(非推奨)
かけることはかけますが、javaのように `abstract class` が言語仕様的に定義できないので、fatalErrorを使うしかないです。RxSwiftなどでも見られるパターンですが、できる限り使いたくありません。

```swift:class.swift
import Foundation

// ClassでTemplateMethodを実現
// Swiftでは抽象クラスがないのでクラスで表現
class ClassFileProcessor {
    
    func readFile(fileName: String) throws {
        if !fileName.isEmpty {
            doProcessLine(line: fileName)
        } else {
            throw NSError(domain: "ClassFileProcessorError", code: 200, userInfo: nil)
        }
    }
    
    func doProcessLine(line: String) {
        fatalError()
    }
    
}

class ClassSimpleFileProcessor: ClassFileProcessor {
    
    override func doProcessLine(line: String) {
        print(line)
    }
    
}

let processor: ClassFileProcessor = ClassSimpleFileProcessor()
try! processor.readFile(fileName: "Super expensive.")
// Super expensive.
```

# プロトコル拡張を使ったパターン
対してこっちはSwiftyにかけます。

```swift:protocol.swift
// プロトコルでTemplateMethodを実現
protocol FileProcessor {
    
    func doProcessLine(line: String)
}

extension FileProcessor {
    
    func readFile(fileName: String) throws {
        if !fileName.isEmpty {
            doProcessLine(line: fileName)
        } else {
            throw NSError(domain: "ProtocolFileProcessorError", code: 200, userInfo: nil)
        }
    }
}

struct SimpleFileProcessor: FileProcessor {
    
    func doProcessLine(line: String) {
        print(line)
    }
    
}

let protocolProcessor: FileProcessor = SimpleFileProcessor()
try! protocolProcessor.readFile(fileName: "Super cheap.")

```
キーエンスコン

C

```
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
#include<map>
#include<math.h>
#include<queue>
#include<deque>
#include<stack>
#include<cstdio>
#include<utility>
#include<set>
#include<list>
#include<cmath>
#include<stdio.h>
#include<string.h>
#include<cstdio>
#include<iomanip>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
using piii = pair<pii, pii>;
const int INF = 1e9 + 7;
int main() {
	int N; cin >> N;
	vector<ll>A(N), B(N);
	for (int i = 0; i < N; ++i)cin >> A[i];
	for (int i = 0; i < N; ++i)cin >> B[i];
	vector<ll>plus;
	ll sum = 0;
	int num = 0;
	for (int i = 0; i < N; ++i) {
		ll dif = A[i] - B[i];
		if (dif < 0)sum -= dif, num++;
		else plus.push_back(dif);
	}
	if (num == 0)cout << 0 << endl;
	else {
		int res = num;
		sort(plus.begin(), plus.end(), greater<ll>());
		ll p = 0;
		for (int i = 0; i < plus.size(); ++i) {
			p += plus[i];
			++res;
			if (p >= sum)break;
		}
		if (p >= sum)cout << res << endl;
		else cout << -1 << endl;
	}
	return 0;
}
```
Vue.jsでつくったSPAをGitHub Pagesで公開する

# SPA作った！けど…
Herokuにデプロイしたらエラーが出て解決策もよくわからなかった。
調べてみるとGitHub PagesでもSPA公開できるみたいだからそっちでやってみようということになりました。
ちょっと詰まったことがあったのでメモとして残しておきます。
間違い等ありましたら教えていただけると幸いです。

# 環境
Vue CLI v3.3.0
yarn v1.13.0

# vue.config.jsの編集
デフォルトでvue.config.jsはないのでプロジェクトディレクトリ直下に作成します。
参考にしたサイト：https://cli.vuejs.org/config/#global-cli-config

```vue.config.js
module.exports = {
  publicPath: "./",
  assetsDir: "",
  outputDir: "dist"
}
```

# デプロイ
gh-pagesというツールを使ってデプロイします。

```
$ yarn add gh-pages --dev
```

インストール後、package.jsonを書き換えます。

```package.json
{
  //省略
  "scripts": {
    "deploy": "gh-pages -d dist" // 追加
  }
  //省略
}
```
その後`yarn build`して`yarn deploy`をする。

# GitHubで公開設定
リモートリポジトリの設定画面に行き、画像のように`gh-pages branch`を選択する。
![{1ADFBB95-AC29-44F0-8683-CA96D85970B8}.png.jpg](https://qiita-image-store.s3.amazonaws.com/0/271796/ff5baba5-a14e-5791-a6fe-643e8af18004.jpeg)
これで反映に時間がかかりますが(私の場合)ちゃんと公開することができました。
AWSでウェブアプリケーション環境構築：⓪概要

# はじめに
これはシリーズ記事の中の1つです。

[AWSでウェブアプリケーション環境構築：⓪概要](https://qiita.com/minato-naka/items/ddb5f5301f9f590cdcbf)
**↑↑↑現在の記事↑↑↑**
[AWSでウェブアプリケーション環境構築：①EC2インスタンスにwebサーバを構築](https://qiita.com/minato-naka/items/c21e4d53db7a720f8fdd)
[AWSでウェブアプリケーション環境構築：②RDSでDBを作成し、Laravelサンプルアプリを動かす最小構成を構築](https://qiita.com/minato-naka/items/03f9dbd09eb3919a501f)
[AWSでウェブアプリケーション環境構築：③ロードバランサーを作成し、webサーバを冗長化する](https://qiita.com/minato-naka/items/396e2a25ec9a94840a67)
[AWSでウェブアプリケーション環境構築：④ElastiCacheのRedisを作成し、セッション共有可能にする](https://qiita.com/minato-naka/items/76cd5f660d987d34f7be)
[AWSでウェブアプリケーション環境構築：⑤webサーバをプライベートサブネットに配置し、メンテナンス用踏み台サーバを構築](https://qiita.com/minato-naka/items/406c2f247c0d29a93665)
[AWSでウェブアプリケーション環境構築：⑥Route53を利用して独自ドメインでアクセス可能にする](https://qiita.com/minato-naka/items/6f29694c1540f04dedb2)
[AWSでウェブアプリケーション環境構築：⑦ACMを利用してHTTPS通信可能にする](https://qiita.com/minato-naka/items/1a4f03e85857b8f61c4f)
[AWSでウェブアプリケーション環境構築：⑧サーバ負荷に応じてwebサーバがオートスケーリングする仕組みを構築](https://qiita.com/minato-naka/items/c0fab5d9fbb1cce68ac9)


# 概要
ウェブアプリケーションが実際に動作する環境を
AWS上に構築します。

AWSを利用したインフラ環境構築の学習が目的であり、
その環境で動作するアプリケーションの実装は目的としていません。


# 構築する環境
![aws完成図.png](https://qiita-image-store.s3.amazonaws.com/0/297693/137d739d-7641-d28b-6c15-cfe0719a1abe.png)
上記の環境を構築し、
Laravel公式サンプルアプリケーションをのせて
実際にアプリが動く状態にします。
https://github.com/laravel/quickstart-intermediate

このサンプルアプリは、
アカウント登録機能、ログイン機能、タスクの登録削除機能をもった
シンプルなタスク管理アプリです。

# 全体の流れ
上記の環境を最短距離で構築せず、
下記のような流れで
最低限の環境を構築し動作確認しながら段階的に進めます。

1. EC2インスタンスにwebサーバを構築
![1.png](https://qiita-image-store.s3.amazonaws.com/0/297693/b9f28155-01f6-e5a0-ec81-07fcfd59e1b0.png)

2. RDSでDBを作成し、Laravelサンプルアプリを動かす最小構成を構築
![2.png](https://qiita-image-store.s3.amazonaws.com/0/297693/b3bf713a-1db6-fe9e-5426-89f7f152c529.png)

3. ロードバランサを作成し、webサーバを冗長化する
![3.png](https://qiita-image-store.s3.amazonaws.com/0/297693/db8a530f-de1a-1278-e692-46fa7e3d5b58.png)

4. ElastiCacheのRedisを作成し、セッション共有可能にする
![4.png](https://qiita-image-store.s3.amazonaws.com/0/297693/be97487d-d2fa-0c9b-ca4a-bb49c9294905.png)

5. webサーバをプライベートサブネットに配置し、メンテナンス用踏み台サーバを構築
![5.png](https://qiita-image-store.s3.amazonaws.com/0/297693/84326896-440b-1cf0-4ffc-81c1fd8b3205.png)

6. 独自ドメインでアクセス可能にする
![6.png](https://qiita-image-store.s3.amazonaws.com/0/297693/dd3ea3b4-964b-667f-710f-e7b04199a593.png)

7. httpsで通信可能にする
![7.png](https://qiita-image-store.s3.amazonaws.com/0/297693/f6a90842-c059-e5a1-dddb-63bfdf863a7f.png)

8. webサーバがオートスケーリングするようにする
![8.png](https://qiita-image-store.s3.amazonaws.com/0/297693/5f82e885-a98e-a5dc-9080-e530f533352b.png)

# 利用するサービス
- VPC
- EC2
- RDS
- ALB
- ElastiCache
- Route53

# 次回
[AWSでウェブアプリケーション環境構築：①EC2インスタンスにwebサーバを構築](https://qiita.com/minato-naka/items/c21e4d53db7a720f8fdd)
PostgreSQLで曜日名をcase文使わずに1文で抽出する方法


## case文の場合

```sql
SELECT
  case EXTRACT(DOW FROM CAST('2019/01/24' AS DATE))
    when 0 then '日'
    when 1 then '月'
    when 2 then '火'
    when 3 then '水'
    when 4 then '木' 
    when 5 then '金' 
    when 6 then '土'
  end 
```

## case文を使わない方法
arrayを使うと1文で書けます(※arrayの添字が1から始まるので要注意)

```sql
SELECT
  (array['日','月','火','水','木','金','土'])[EXTRACT(DOW FROM CAST('2019/01/24' AS DATE)) + 1]
```
Salesforce 開発者向け初心者編

##Salesforce　勉強用のメモ

インサイドセールスの業務でSalesforceにはとてもお世話になった。
顧客管理用のリストを作成する際や、チームで数値を可視化するためにグラフやダッシュボードをカスタマイズする際にプログラミングの知識は全く必要なく、簡単に作成できる。
ただ、私は実際にSalesforceの開発経験は無く開発側の視点でもっと深く学んでみたいと思いこの記事を作成した。

**Salesforceとは、クラウド上で顧客管理・営業管理などができる世界シェアNo.1の営業支援・CRMツール。**

Salesforce開発環境は、ほとんどがブラウザベースで整う。やはり日本語での情報収集は限られており、英語で調べた方が情報量は膨大になるし、とても詳細な解説。

年に3回のメジャリリースが行われ、多くの新機能が追加され、WEB・UI開発はHTML・CSSで可能。
Lightning　Componentにより、高度なUIを作成する場合にはApexとJSのスキルが必須。　

開発者向けの学習ツールで一番は「TRAILHEAD」が最も良い教材となるだろう。
日本語で十分に学ぶことができる。
https://trailhead.salesforce.com/ja/home


#Apex 開発者ガイド
https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_dev_guide.htm
 
#salesforce　Lightningとは？
プラットフォームサービスの総称。Lightning以前はClassicと呼ぶ。
 Lightning Web Componentsについて。
 https://developer.salesforce.com/blogs/2018/12/introducing-lightning-web-components.html
　　
#Herokuについて
https://devcenter.heroku.com/
  

#Pardotとは？
https://help.salesforce.com/articleView?d=70130000000iERn&DCMP=Google-JP&ef_id=EAIaIQobChMIy462ivyF4AIVkwcqCh3-RQhxEAAYASAAEgKOzPD_BwE:G:s&gclid=EAIaIQobChMIy462ivyF4AIVkwcqCh3-RQhxEAAYASAAEgKOzPD_BwE&id=bundle_pardot_parent.htm&s_kwcid=AL!4724!3!307661448865!b!!g!!&type=5
Salesforceと一体型のマーケティングツール。顧客のWebアクセス分析、メールシナリオ設定、Salesforce連携などができる。
 メールのトラッキング機能を活用し、インサイドセールスでは顧客の要望に合わせたセールスアプローチで営業活動の最大化に繋がる。
 
#Youtubeで学べる！
・Salesforce Developers（開発者向けの公式のチャンネル）
 https://www.youtube.com/watch?v=DGy-j2xHMsc&t=3886s
   
・Salesforce Developers Japan
（日本の公式チャンネル。海外と比べ、チャンネル登録者数が４００人規模と少なめ、唯一日本語で分かりやすい解説をしてくれている。）
   https://www.youtube.com/user/salesforcedevjp/videos

・Salesforce Hulk　　
（開発者向けのスキルやApexなどの言語を分かりやすく紹介している。）
https://www.youtube.com/channel/UCTzF0VQiCXsZ_41fjVuX7UA/videos
  
  ・edureka!
（Salesforceに関するQ&Aを分かりやすく解説している。他の動画はエンジニア向けに様々な言語や技術の解説をしている。）
  https://www.youtube.com/watch?v=tQsiH7odkOQ
Angularの「?.」でつまづいた

# 事象
AngularのTemplate Syntaxである「`?.`」（Safe Navigation Operator）で思わぬ障害を作りこんでしまいました。
Angularのテンプレートにて

```html
<span *ngIf="obj.getData()?.indexOf(':') >= 0">
  テスト
</span>
```

というコードを書きました。
コードの目的は、`getData()`がnullでない場合、`:`が文字列中に含まれるなら[^1]「テスト」という文字列を出力し、その他の場合は、何も表示しないようにすることです。
`getData()`は戻り値として、文字列を返します。ただし、nullを含むことがあります。
そこで、AngularのSafe Navigation Operator（getData()の直後の「`?.`」）を用いて、

- `getData()`がnullでないなら以降の式を実行
- nullなら実行しない（`ngIf`全体でfalse）

となるようコーディングしたつもりでした。
しかし、`getData()`の戻りがnullの場合でも、「テスト」が表示されてしまいました。

# 原因
Safe Navigation Operatorの仕様を勘違いしていたことです。
Safe Navigation Operatorはnull（またはundefined）の場合その後の式を評価しないのではなく、続くプロパティにアクセスしないことです[^2]。
よって、`getData()`がnullである場合、上記のコードは以下のように評価されます。

```html
<span *ngIf="obj.getData() >= 0">
  テスト
</span>
```

JavaScriptにおいて、`>=`で比較する際に、0とnullは同じものとして評価されます。
よって上記の式の結果は`true`となり、「テスト」の文字列が表示されてしまいました。

# 解消法
事前にnullの判定を入れました。

```html
<ng-container *ngIf="obj.getData()">
  <span *ngIf="obj.getData().indexOf(':') >= 0">
    テスト
  </span>
</ng-container>
```



[^1]: そもそも「文字列中に含まれるかどうか」なら`String.prototype.includes()`を使いたいところなのですが、IE11対応がシステム要件に含まれるため、使えませんでした。
[^2]: [Angualrのドキュメント](https://angular.io/guide/template-syntax#safe-navigation-operator)には「The expression bails out when it hits the first null value. 」とあります。
新規テンプレートを使ったアプリ作成時のAndroidManifest.xmlでApp Indexingがされていない警告を消す

# 結論

* AndroidManifest.xmlに以下を追加する。

```AndroidManifest.xml
    <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme"
            tools:ignore="GoogleAppIndexingWarning"> <!-- この一行を追加 -->
```

## 補足

* アプリの作成時にいつも忘れるからメモ程度に書いた。

* App IndexingはGoogleの検索結果からアプリに直接飛んだり、SEOに強くなるための仕組みなので、モックレベルのアプリ作成時には警告を無視して良さそう。

* https://www.seohacks.net/basic/terms/appindexing/
gitのpush周りで問題が起きた時の対処

# pullできない
古いシステムの乗っている本番サーバーには本番の環境に合わせてファイルが弄られているものがあったりして、コードの更新などをする際にすんなりpullできないことがある。
具体的にはこんなエラー表記が出る。

```
Your local changes to the following files would be overwritten by merge
```

この時に使ったコマンドは基本的な開発をする上でのaddやcommitとは違うので、今まで触ることがなかったので、覚書として書くことにしました。

#どうやったか
本番のサーバーで変更のあったファイルをstashを使って一時退避。変更した部分が消えたところで、リモートリポジトリから更新したソースコードをpullしてくる。
今度はstash popを使って退避したファイルを元に戻す。
stash popを使えば、退避させたファイルが自動的にマージされる。
でソースコードの本番反映は完了。

# 対処に使うgitコマンド
## ファイル退避コマンド
変更ファイルを一時的に記憶領域へと退避させる。今回は、本番サーバーで変更のあったファイル群をこれを使って逃すことにした。このコマンドはファイルが変更されていない限り使用できないという使用条件がある。

```
$ git stash save ファイル名
```

## 退避ファイル復活コマンド
stashで退避させたファイルを再度ワークスペースへと引き戻す。この際に自動的にマージが行われる。

```
$ git stash pop
```

## 新規ファイル退避コマンド
先ほどファイル変更されていないとstashは使えないと書いたが、中には新規で作られたものもあるかもしれない。そんな時は、-uオプション(多分untrackの意味だと思います)を使えば新規作成されたファイルも退避可能です。

```
$ git stash -u 
```
#コミットを見るコマンド
コミットIDや、コミットメッセージ、コミッター、コミットした日付などが見られる。オプションを使って見たいコミットを絞り込むことができる。
個人的によく使うオプションは、

- --all
- -n 表示数
- --author='ユーザー名'
 
```
$ git log
```

特定のコミットの日付やユーザーの他にコードの差分も確認できる。

```
$ git show コミットID
```
#指定コミットまでバックするコマンド
本番いじっているファイルで問題が生じたりした時にカムバックしたい時は
コミットのログを見れるコマンドを使って、コミットIDを調べた後に、このコマンドを使用することで、そのコミットIDの場所までバックすることができる。
pushする前の対抗手段としてのresetコマンドは以前の記事で詳しく書いたので、ここでは、pushした後の対処方法としてcheckoutを使います。

resetコマンドに関してはこちらです。
[機能だけで覚える基本的なGitコマンド　〜ほぼほぼ作業順〜　
](https://qiita.com/Nedward/items/12b6b86a39795aa5201b)

checkoutコマンドはブランチ切り替えに使ったコマンドですが、バックする際にも利用可能です。
指定したコミットIDにまで状態を戻します。その際に、指定したコミットID以降のコミットはpushされていな限り、破棄されますので戻せなくなります。
ただ、git logには以前のコミットIDが残っているので、どこにでも切り戻しが可能。切り戻した段階では、コミットID指定した場所が、ステージングに上がった状態まで戻っています。
ただし、切り戻されるのはあくまでローカルリポジトリでの話なので、pushしない限り、切り戻した状態はリモートには反映されません。

```
$ git checkout コミットID -- ファイル名
```

# [加筆：パニクった経験]rejectされたからstashしたら・・・
stashを行い、git pullを行なった後に、pushを行なったら、自分のいじっていないファイルがごっそりpushされていて焦った。

コミットメッセージは以下の通り。

```
Merge branch 'master' of github.com:gaiax/hogehogeapp
```

弄ってもいないファイルしかpushされていなかったので、これはやらかしたかと思ったんですが、pullを行なった際に、さっきrejectされていたpushが裏側で自動的にpushされ、再度pushを行なった時に裏側で行われたpushでgitにあったファイルの進んでいた分を上書きしてしまっているので、再プッシュによって、その差分を埋めてくれたことになっているようです。
順番が前後していますが、mergeはうまく最新のものになっているようです。

が、pushがリジェクトされたら、その時点でpushをgit resetで取り下げてから、stash=>pull=>stash pop=>pushの手順が心臓には良さそうです。
homebrewで普通のformulaとcask用formulaを同じレポジトリで管理する


  - `cask`用formulaを`Casks`ディレクトリ以下に仕舞う

参考: https://github.com/Homebrew/homebrew-cask/blob/master/USAGE.md

> You can add Casks to your existing (or new) Taps: just create a directory named Casks inside your Tap, put your Cask files there, and everything will just work.)
>
> ---
> すでにある(もしくは新しく作る)Tapにcaskを追加することができます: `Casks`ディレクトリを作成し、Caskファイルをそこに入れてください。これで万事解決です。
Codilityテスト：昇順が最も長く続く部分を調べる問題

とあるスイスのIT企業のバイトの入社試験で，「Codility」というOnlineテストを受けさせられた．自分にとってははじめての存在だったので念のためシェア．

事前に調べるとこういう感じの問題みたい．ちょっと頭を使うことを覚悟する．
http://tjnet555.hatenablog.com/entry/2016/09/03/191251

アルゴリズムの知識で計算量を減らさないと得点が低くなるらしい．
デモで $O(n^2)$ の式を書いたら，Correctnessは100%だったが，Efficiencyみたいなのが25%だった．
なるほどなと思い本番へ．


自分の場合は，

* 試験時間は45分
* タスクは1問
* Pythonで受けろと会社から指定．

問題文は英語で，20行ぐらい．最初の5分ぐらいで何が言いたいのか理解できた．

問題はこんな感じ
ーーーーーーーーーーーーーーー
[2, 2, 2, 2, 1, 2, -1, 2, 1, 3]といったようなリストがあった時に，昇順になっている部分で最も長い部分を探し，その部分の始まりのインデックスを返す関数solution(A)を作成する．
上の例だと，4か6か8のどれかを返せばいい．

[30, 20, 10]だと，0か1か2 (ひとつの数字は長さ1の昇順の部分と考える)
配列の長さNは1<=N<=150,000，
Aに含まれる整数Kの範囲は，-(2^31)<=K<=(2^31)
ーーーーーーーーーーーーーーー

書いたコードを下に示した．
$O(n)$で計算量は，色々工夫はできるけど，オーダーはこれ以上減らせなくないですか...?
大学生バイトだから，初歩的な問題にしてくれたみたいです．


```Python
def solution(A):
    max = 0
    begin = 0
    target = 1
    length = 1
    max_length = 1
    list_length = len(A)
    while target < list_length:
        if (A[target - 1] < A[target]):
            length = length + 1
        else:
            if length > max_length:
                max = begin
                max_length = length
            begin = target
            length = 1
        target = target + 1
    if length > max_length:
        max = begin
        max_length = length
        return max

```
世界一簡単なgitの移行・コピー

# この投稿で出来ること
- gitのブランチ・コミットのコピー

# 出来ないこと
- PRのコピー
- issueのコピー

# その他
- 元ブランチには影響ありません

# 実践
- 移行先のリポジトリを作成しておく `iOS-App` など
- localに適当なディレクトリを作ってコピーの元をclone

```
$ git clone --mirror (移行元)https://github.com/hoge.git
```
- localに `hoge.git`が出来ているのでその中に移動

```
$ cd hoge.git
```
- 移行先にpushする

```
$ git push --mirror (移行先)https://github.com/iOS-App.git
```

done
Jenkins 起動時にジョブをまとめて作成・更新する

[Jenkinsの構築それ全部自動でできるよ](https://qiita.com/fuku2014/items/995cf34afd126a627c22)

上記の記事にあった、 Jenkins 起動時にジョブをインポートしている Groovy を参考に

- ジョブ定義をディレクトリから読み込む
- ジョブ定義のファイル名をジョブ名とし(拡張子は除く)
    - 既に存在するジョブは更新
    - 存在しない場合はジョブ作成

というのを書いてみたのでメモ

```groovy
import jenkins.model.*
import javax.xml.transform.stream.StreamSource

def instance  = Jenkins.getInstance()
def jobNames = instance.getItems()

File dir = new File("ジョブ定義ファイルを置いてあるディレクトリ")
File[] files = dir.listFiles();

for (int i = 0; i < files.length; i++) {
  File file = files[i]
  String fileName = file.getName()
  String jobName = fileName.substring(0, fileName.lastIndexOf('.'))

  if (jobNames.any { it.fullName == jobName } ){
    println "update job ${jobName}"
    InputStream is = new FileInputStream(file);
    instance.getItem(jobName).updateByXml(new StreamSource(is));
    continue
  }

  println "create job ${jobName}"
  def configXml = file.text
  def xmlStream = new ByteArrayInputStream( configXml.getBytes() )
  instance.createProjectFromXML(jobName, xmlStream)
}
```
abc 116

C

```
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
#include<map>
#include<math.h>
#include<queue>
#include<deque>
#include<stack>
#include<cstdio>
#include<utility>
#include<set>
#include<list>
#include<cmath>
#include<stdio.h>
#include<string.h>
#include<cstdio>
#include<iomanip>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
using piii = pair<pii, pii>;
const int INF = 1e9 + 7;
int main() {
	int N;
	int h[110];
	cin >> N;
	for (int i = 0; i < N; ++i) {
		cin >> h[i];
	}
	int l,k;
	int ans = 0;
	for (int i = 0; i < N; ++i) {
		while (h[i] > 0) {
			int j;
			for (j = i + 1; j < N; ++j) {
				if (h[j] == 0) {
					break;
				}
			}
			for (int k = i; k < j; ++k) {
				h[k]--;
			}
			++ans;
		}
	}
	cout << ans << endl;
	return 0;
}
```

D
p種類のネタを選んだ時の美味しさの基礎点の最大値をf(p)と定義する。またg(p)=f(p)+p*pで定義する。g(p)の最大値を求めればよいことがわかる。まず寿司を美味しさで降順にソートする。ここから貪欲に(おいしさが大きい順に)K個寿司を選びその集合をSとする。Sのネタの種類数がxの時Sの美味しさ基礎点の和がf(x)となります。明らかにf(I)<f(x)なのでg(I)<g(x)となりI<xの場合は考えなくてもよいことがわかる。次にf(a)とそれを構成する寿司の集合の一つSaがわかっている場合にf(a+1)とそれを構成する寿司の集合の一つSa+1はSaに以下の操作を加えることで構成することができる。
集合Saから取り除いてもネタの種類数が減らない寿司の中で最もおいしさの小さいものを取り除く。集合Saに含まれない寿司の中で集合Saにないネタを持つ最も美味しさの大きいものをSaに加える。
この操作を繰り返すことによりf(I)を再帰的に求めることができる。

```
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
#include<map>
#include<math.h>
#include<queue>
#include<deque>
#include<stack>
#include<cstdio>
#include<utility>
#include<set>
#include<list>
#include<cmath>
#include<stdio.h>
#include<string.h>
#include<cstdio>
#include<iomanip>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
using piii = pair<pii, pii>;
const int INF = 1e9 + 7;
int main() {
	int N, K;
	cin >> N >> K;
	priority_queue<ll>kind[N];
	for (int i = 0; i < N; ++i) {
		int t;
		ll d;
		cin >> t >> d;
		kind[t - 1].push(d);
	}
	priority_queue<ll>best, remain;
	//best:各種類で一番おいしいやつを集めたもの
	//remain:bestの余り
	for (int i = 0; i < N; ++i) {
		if (!kind[i].empty()) {
			best.push(kind[i].top());
			kind[i].pop();
			while (!kind[i].empty()){
				remain.push(kind[i].top());
				kind[i].pop();
			}
		}
	}
	vector<ll>bsum = { 0 };
	//bestの累積和(bsum[i]=bestの先頭からi個の総和)
	while (!best.empty()) {
		bsum.push_back(bsum.back() + best.top());
		best.pop();
	}
	vector<ll>rsum = { 0 };
	//remainの累積和
	while (!remain.empty()) {
		rsum.push_back(rsum.back() + remain.top());
		remain.pop();
	}
	ll ans = 0;
	for (ll x = 1; x <= K; ++x) {
		//種類が多すぎるケース
		if (x >= bsum.size())break;
		//種類が少なすぎて余り物が足りないケース
		if (K - x >= rsum.size())continue;
		//bestからx個、remainからK-x個貪欲に選ぶ
		ans = max(ans, bsum[x] + rsum[K - x] + x * x);
	}
	cout << ans << endl;
	return 0;
}
```
JavaScript/Node.jsで現在のディレクトリ名のみを取得する

# 概要

グローバル変数__dirnameとpathモジュールを使用することで実現することができる。

## __dirname

[Modules | Node.js v11.7.0 Documentation](https://nodejs.org/docs/latest/api/modules.html#modules_dirname)

Node.js標準でグローバル変数で用意されている。絶対パスでディレクトリ名までを取得できる。

### sample

```javascript
console.log(__dirname);

// /Users/ユーザ名/~略/src/components/Modals/HogeModal
```

## path

[Path | Node.js v11.7.0 Documentation](https://nodejs.org/api/path.html)
パス関係の便利なメソッドが用意されている。

Node.js標準で用意されているモジュールのため、package.jsonになくても問題はない。

path.basename(__dirname)でディレクトリ名のみを取得することができる。

## コード

```javascript
import path from 'path';

console.log(path.basename(__dirname));
// HogeModal
```

# 感想

正規表現を使わなくても大丈夫でした。
Fake Stake攻撃完全に理解した！


#Bitcoinで新しいブロックをダウンロードする仕組み

Bitcoinのノードは、基本的には最も長いチェーンのデータを保存しています。2019年1月24日現在、およそ558000ブロックほどが繋がっていますが、例えばいま僕の手元にある最新のブロックが558010だとすると、基本的には、その558010番目のブロックの次に繋がる558011番目のブロックが他のノードから送られてくるのを待っている状態です。しかし、ノードの中には、他のノードとの接続が悪くてまだ558009番目までしか手元になく、他の人がすでにマイニングしている558010番目のブロックの存在に気づかないまま、558010番目のブロックのマイニングに勤しんでいる場合もあります。そこで偶然その人が558010番目のブロックのマイニングに成功すると、その情報は他のノードに伝搬されて、僕の手元にも、二つ目の異なる558010番目のブロックが送られてくることになります。

ブロックが送られてくる、という表現をしましたが、実はこれは正確ではありません。いわゆる「ブロック」はそれぞれブロックヘッダーとブロックの中身に分解できます。ブロックヘッダーとは、前のブロックのヘッダーのハッシュ値や、そのブロックの中身の送金情報のサマリやナンスと呼ばれるものなど、合計80バイトの情報で構成されるもので、そのヘッダー自体をハッシュ化すると最初にたくさん0が並ぶようになっています。ブロックの中身には最大で1Mバイトの送金情報が詰められています。僕は他のノードから二つ目の558010番目のブロックがあることを伝えられた時、ブロックヘッダーだけまずは受け取ります。ブロックヘッダーを見れば、前の558009番目のブロックの次に繋げる気持ちで送られてきたことと、それをハッシュ化して0がたくさん並んでいることを確認することができ、ブロックの中身に本当は存在しちゃいけないものが混ざっている可能性は否定できないものの、0がたくさん並ぶようなものは相当頑張らないと作れないわけで、とりあえず将来的に最長のチェーンになるかもしれない候補生としてブロックの中身もダウンロードしてきます。ブロックの中身まで含めると1Mバイトになりますが、ブロックヘッダーだけだと80バイトだけなので、およそ1万分の1のデータをちょろっと見るだけで、めっちゃ頑張って作られたものであることが確認できます。実際に正しいブロックであるためには、ブロック内の送金が二重支払いされていないかの確認なども必要ですが、その確認をしようと思ったら、究極的には558010ブロックすべてを見なきゃいけないので、候補生の段階で絞り込まれているというのはすごく便利ですね。


#UTXO型PoSで新しいブロックをダウンロードする仕組みとその脆弱性

そもそもUTXO型PoSがどういう仕組みかをまずは説明する必要があります。やりたいこととしては、コインを持っている数量に比例してマイニングに成功する確率が変わるけど、マシンリソースはほとんど必要のない仕組みを作ることです。そこで、マイニングに成功する条件を次のように定義します。

hash(前のブロックの情報で変更できない情報+自分の持ってるUTXOのTXID+16秒単位でしか変更できないtimestamp)<=定数k*そのUTXOにあるコイン数量n/全コイン数量N

普通の人の気持ちとしては、ブロック更新されるたびに自分のUTXOとその時のタイムスタンプを並べてhash関数通して、ワンチャン成功すればブロードキャスト、だめなら16秒後にもう一回、新しいブロックが来たら今度はそれをベースに、と続けていきます。この情報はcoinstake transactionという名前で、ブロックの中に乗っかることになります。


ちなみに、UTXOをたとえば１０個に分解すれば１０倍チャンスですが、一つ当たりの成功確率が1/10になってしまいます。数学的に厳密にいうと、UTXO一つにまとめた場合には自分がブロックを見つける確率はn/Nで、無限に細かく分割すると、1-exp(-n/N)の確率になり、n/N>1-exp(-n/N)が恒等的に成立するので、まとめ上げたほうがお得になり、ユーザーがUTXOを自発的にまとめあげてくれる副次効果もあったりします。

さて、この仕組みのブロックチェーンで、新しく送られてきたブロックが正しいことを確認するためには、coinstake transactionが正しいことの検証と、ブロックの中身に二重支払いのものがないかなどを検証することが必要になりますが、では、coinstake transactionはどのように正しいことを検証すればいいか、が問題になります。検証するポイントは、

①確かに上の不等式を満たしていることの証明
②そのTXをほんとにその人が所有していることを証明する署名
③そのTXがほんとにまだ使われていないこと(UTXOであること)の証明

となりますが、①と②は一瞬の計算です。しかし、③をやろうとすると、究極的には少なくともそのTX以降のブロックはすべて検証する必要が発生します。一応の注意書きとしては、Bitcoin含めUTXO型のブロックチェーンにおいては、毎回0ブロック目から確認するのは無駄なので、直近のブロック時点でのUTXOを手元に保存しておく運用なのですが、いま考えているシチュエーションは、最終的に正しいブロックとなる候補生がたくさんあるケースで、そうするとどの時点のUTXOの情報を使えばいいのか、という問題が発生することになり、やはりブロックをさかのぼって検証するほかありません。その背景から、③の検証はせずに、①と②の検証だけパスできたら、他のブロックの中身の情報をダウンロードしてくることになります。

そこで今回の攻撃手法が考案されました。すなわち、UTXOである必要はないのだから、自分が署名できる使用済みTXをたくさん用意して②をパスできるものをたくさん用意し、それらを使って①をパスできるものをたくさん作って、それにテキトーに作った最大サイズのブロックをくっつけて送り付ければ、ノードはそれらを全部ダウンロードすることになって、disk逼迫するやんけ！というワザです。

自分が署名できるTXをたくさん用意するのは簡単で、どこかの取引所からそこそこな数量のコインを買ってきて、自分の所有するウォレット間で送金しまくって、そこそこな量たまったら、取引所に送って売ればよいのです。ブロックチェーン上の送金手数料と、取引所の売買手数料をいくぶんか支払うだけで攻撃が可能というわけです。

この攻撃が使えるUTXO型PoSコインでショートできる市場があるものはなさそうであるゆえ、得られるメリットは特になさそうですが、暇を持て余した悪戯っ子クラッカーがお小遣い程度の出費でできてしまうので問題ですね。




参考：
https://blog.qtum.org/qtums-proof-of-stake-consensus-at-a-high-level-ea53e051ac66
https://medium.com/@dsl_uiuc/fake-stake-attacks-on-chain-based-proof-of-stake-cryptocurrencies-b8b05723f806
ctl系コマンドについてまとめてみた

#はじめに
Kubernetesを勉強し始めて気づいたことがある。
コマンド名がhogectlといったctlがつく命名ルールのものが多いこと多いこと。

そこで一度どういったものがあるかリストしてみた。

#ctl系

| コマンド | 用途 |備考 |
|:-----------|------------|:------------|
| kubectl | kubernetesのコマンド | [リンク](https://kubernetes.io/docs/reference/kubectl/overview/) |
| etcdctl | etcdのコマンド | [リンク](https://github.com/etcd-io/etcd/tree/master/etcdctl) |
| calicoctl | calicoのコマンド | [リンク](https://github.com/projectcalico/calicoctl) |
| istioctl | istioのコマンド | [リンク](https://istio.io/docs/reference/commands/istioctl/) |
| eksctl | Amazon EKSのコマンド | [リンク](https://aws.amazon.com/jp/blogs/opensource/eksctl-eks-cluster-one-command/) |
| mcmctl | IBM Cloud Private MCMのコマンド | [リンク](https://www.ibm.com/support/knowledgecenter/en/SSBS6K_3.1.0/mcm/manage_cluster/cli_commands.html) |
| cloudctl | IBM Cloudのコマンド | [リンク](https://www.ibm.com/support/knowledgecenter/en/SSBS6K_3.1.0/manage_cluster/cli_commands.html) |
| crictl | CRI-Oのコマンド | [リンク](https://github.com/kubernetes-sigs/cri-tools/blob/master/docs/crictl.md)　|


順不同です。



#さいごに
まとめてみると、そこまで多くはなかった。。
他にもあると思いますが、一旦ここまで。
（気づいたら追加します）
ActiveRecord::StatementInvalid: PG::DuplicateAlias: ....

一覧表示時にソートしようとしたらエラーが出た

# エラーを掘り下げる
```
ActiveRecord::StatementInvalid: PG::DuplicateAlias: ERROR:  table name "*******" specified more than once
```

### 読む
ふむふむ、なるほど
`PG::DuplicateAlias`ってことはDB(PostgreSQL)側の問題ですね

### ググる
`specified more than once`でググって見ると
[UPDATE文の失敗。](https://kin29.info/update%E6%96%87%E3%81%AE%E5%A4%B1%E6%95%97%E3%80%82/)
[【PostgreSQL】specified more than once](http://blog.jojo.jp/?eid=1263060)

エイリアスがどうのこうの

### SQLから何がダメなのか探る
`to_sql`メソッドでデバッグする

```sql:(一部省略)
SELECT
    (省略)
FROM
    "table_a"
    INNER JOIN "table_b" ON "table_b"."id" = "table_a"."table_b_id"
    INNER JOIN "table_c" ON "table_c"."id" = "table_b"."table_c_id"
    LEFT OUTER JOIN "table_d" ON "table_d"."id" = "table_c"."table_d_id"
    LEFT OUTER JOIN "table_d" ON "table_d"."id" = "table_c"."table_d_id"
WHERE
    (省略)
ORDER BY
    "table_d"."name" ASC
```
なるほど
2回同じ結合がされてるのにエイリアスがないではないか

ちなみに各テーブルの関係性は
`table_a : table_b : table_c : table_d = N : 1 : 1 : 1`

### rails側の悪いところを探す
問題の実装部分(実際はもっとごちゃごちゃしてるけどわかりやすく整理)

```ruby:ソートに関する処理
records =
  TableA
    .eager_load(table_b: { table_c: :table_d })
    .merge(TableD.order(:name))
```
```ruby:絞り込みに関する処理
records.merge(
  TableC
    .left_joins(:table_d)
    .merge(TableD.where(省略))
)
```

# 修正
## 修正案1 ソートと絞り込みを一つにまとめる
`TableD.where(省略)`を`TableD.order(:name)`にくっつけて
`Table.where(省略).order(:name)`にする

残念ながら弊社のシステムの仕組みではソートと絞り込みで処理が別れていて
しかもソートする時としない時で`eager_load`があったりなかったりするので不採用

## 修正案2 `left_joins`するかどうかの条件分岐をする
ソートするかどうかで`left_joins`するしないかを決める

なんてね、論外論外
書いてみただけ

## 修正案3 SQL書いて自分で結合のエイリアスを書く
たぶんやろうと思えばいけるよね
やったことないから知らんけど

でもこれもできるとしても無駄な手間がかかる上にダサいコードになりそうで不採用

## 修正案4 別名でアソシエーションを定義する
ってことだと思う(英語自信ない...)
https://github.com/rails/rails/pull/33066#issuecomment-395945311
PR上で上がってた
試してないけどなんとかなりそう
でもめんどくさそうだからこれもないかな

## 修正案5 railsのバージョンを上げるか下げるか
実はこれrailsのバグで`5.2.0`でだけ起こるので
`5.2.1.rc1`以上にするか`5.1`に下げれば治るはず

下記PRで修正されてた(5.2.0リリース後だった)
https://github.com/rails/rails/pull/33066

`5.2.2`ではエラーにならないことを確認できた
(`$ bundle update rails`ってやったら5.2.2まで上がっちゃって
バージョン指定してアップデートする方法ってないのかな？)

マイナーアップデートだからそこまでやばくはないだろうけど
バージョン変えるのってそんなホイホイやりたくないので一旦見送り

## 修正案6 絞り込み部分の`left_joins`を`preload`にする
`left_joins`はSQL上でjoinするけど
`preload`は別のSQLを流してrailsがいい感じにキャッシュしてくれるやつだから
`left outer join`が2回流れなくなる

一番楽な解決法だけど気持ちパフォーマンスが悪い気がする
けど挙げた中で一番簡単かつ後々への影響も小さいかなと


# 結論
修正案5のrailsのバージョン変更か
修正案6の`left_joins`を`preload`にする

が妥当かな〜〜
特定ディレクトリ配下のファイルのみ(またはディレクトリのみ)を取得（Node.js v10.10以降版)

Node.js で特定ディレクトリ配下のファイルのみ(またはディレクトリのみ)を取得するには、以前は特定ディレクトリ配下のリストを取得して、1つずつ `fs.stat` でファイルか否か判定する必要がありました。
しかし、Node.js v10.10.0 で新たに追加されたオプションによってちょっとだけ簡単に書けるようになりました。 

# TL;DR

`fs.readdir` または `fs.readdirSync` のオプションで `withFileTypes: true` を指定する。

---

以下のサンプルは、特定ディレクトリ配下のファイルのみを取得するコードですが、ディレクトリのみを取得する場合も同様で `stat.isDirectory()` や `dirent.isDirectory()` とするだけです。
また、コードの読みやすさのために同期版API( `fs.readdirSync` など)を使用していますが、非同期版APIでも同じです。

# Node.js v10.10 より前の書き方

```node.js
const fs = require("fs");

const isFile = path => {
  const stat = fs.statSync(path);
  return stat.isFile();
}

const dirPath = "path/to/target";

// "path/to/target" 直下のファイルやディレクトリ名全てが文字列の配列で返ってくる
const allNames = fs.readdirSync(dirPath);

const fileNames = allNames.filter(name => isFile(`${dirPath}/${name}`))  
```

# Node.js v10.10 以降でのちょっと簡単な書き方

```node.js
const fs = require("fs");

const dirPath = "path/to/target";

// "path/to/target" 直下のファイルやディレクトリ全てがDirentオブジェクトの配列で返ってくる
const allDirents = fs.readdirSync(dirPath, { withFileTypes: true });

const fileNames = allDirents.filter(dirent => dirent.isFile()).map(({ name }) => name);
```

* `withFileTypes` のデフォルト値は false のため、何も指定しない場合は従来と同じ挙動となります。
* `withFileTypes: true` を指定すると、戻り値の型がDirentオブジェクトの配列に変わります。

# 参考

- [fs.readdir のドキュメント](https://nodejs.org/api/fs.html#fs_fs_readdir_path_options_callback)
- [fs.Dirent のドキュメント](https://nodejs.org/api/fs.html#fs_class_fs_dirent)
aviutlをmacに入れてみた【ざっくり】

###ざっくり実践したことのみ
１easywineをダウンロードする
https://github.com/mattintosh4/compact-wine/releases/tag/20180815
２Macでダウンロードのセキリュティ設定を、app store以外からも可能にする。
３easywineの起動確認、OOがインストールされていませんと出たので、
通知内のurlを踏んでインストール
４無事起動

５aviutlをダウンロード
http://spring-fragrance.mints.ne.jp/aviutl/
６easywimeで開くを選択するも、起動せず
７一度終了し、特段深い理由もなくaviutlの拡張機能をダウンロード。
８再度立ち上げると成功
以前windowsでaviutlをダウンロードした際に体験した、ダウンロード後のこまごまとした設定をする手間を想像しちょっとげんなりする。
９明日やろうと思ってaviutl初心者ページを開いたままパソコンをスリープ
CSSの色のネーミングで迷うのをやめよう！色のネーミングサイト紹介

##cssのネーミングの問題
cssで色を当てるためのクラスをつける時、次のようなクラスを定義する事があります。

```css
.text-red {
   color: red
} 
```

しかし、少し濃い赤、濃い赤など赤っぽい色を複数使いたい場合にネーミングに迷う事があります。

###色のネーミングサイト

そんな時には、以下のサイトで色のコードから色の名前を教えてもらうと非常に便利です。

http://chir.ag/projects/name-that-color/#F4FAF7


###使い方
色のコード(#370B8E)などを入力するだけです。
色を名前にして教えてくれます。(#370B8E =>Blue Gem, など)

###効果
1.似た色のネーミングがバッティングしない
2.ネーミングで迷う時間がなくなる
3.色の知識がたまり色彩センスが向上する


###終わりに

結構便利です。以上です。
boto3からaccess_key, secret_keyを取得する

# boto3からprofileを指定してIDとパスワードを取得する

```python
def get_credentials():
    import boto3
    session = boto3.session.Session(profile_name='default')
    credentials = session.get_credentials()
    return {'ID': credentials.access_key, 'PW': credentials.secret_key}
```

## 参考

https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html

> ```
# Do not hard code credentials
client = boto3.client(
    's3',
    # Hard coded strings as credentials, not recommended.
    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',
    aws_secret_access_key='ABCDEF+c2L7yXeGvUyrPgYsDnWRRC1AYEXAMPLE'
)
```

> Hard coded strings as credentials, not recommended.
> Hard coded strings as credentials, not recommended.
> Hard coded strings as credentials, not recommended.

間違っても、コード内にAKIAI~と書かないようにしましょう。
GitHubにソースをアップロードして大変な事になります。(経験談)

## 余談

https://qiita.com/hatobeam75/items/f9430f016a8366b63cf0

私はCognitoからID, PWを取得する前の確認用に使っていました。
Sessionでは無くID/PWを要求するタイプのAPIを用いる場合は間違ってもハードコードしないようにしてください。
GitHubにソースをアップロードして大変な事になります。(2回目)
【Vue.js】imgタグのsrc要素は指定の仕方によって読み込み方が違う

vue.jsのimgタグはsrcの指定の方法によって実は参照するファイルが異なるっぽい。
imgタグを並べて表示する場合この挙動を知らないとハマりそうなので、どのような挙動になっているのか調べたのでまとめました。
対象はVue CLI 3で生成したプロジェクトです。

##例1: 普通にimgタグを並べる場合
例えば画像を並べて表示する場合、一番単純な実装はimgタグを並べるだけで良いです。
画像は`src/assets/`以下に置いてます。
シンプル。

```vuejs:home.vue
<template>
  <ul>
    <li><img src="@/assets/img1.png"/></li>
    <li><img src="@/assets/img2.png"/></li>
    <li><img src="@/assets/img3.png"/></li>
  </ul>
</template>
```

# 例2:v-forでimgタグを並べる場合 (失敗)
ただ画像数が少なければいいですが、数を増やしたり要素が複雑化した場合はv-forで生成したほうがよいです。
増えても画像のパスだけ追加すれば良くなるので保守性があがります。

```vuejs:home2.vue
<template>
 <ul>
    <li v-for="icon in icons" :key="icon">
      <img :src="icon"/>
    </li>
 </ul>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component
export default class Home extends Vue {
  icons = [
    '@/assets/img1.png',
    '@/assets/img2.png',
    '@/assets/img3.png',
  ]
}
</script>
```
一見これでもうまく動きそうなのですが、ビルドは通るがブラウザ上で見ると画像が404になってしまいます。
なんで...？

# 解説
なぜうまくいかないかというとsrc要素を静的に指定する場合と、v-bindで動的に指定する場合では参照方法が異なるからです。
例1では静的にsrc要素を指定していますが、その場合は内部でWebpackのfile-loaderで画像をモジュールとして読み込んでいます。
例2ではv-bindで動的に指定していますが、その場合はそのままのパスとして扱われます。

以下のURLに詳細が書かれています。
[HTML and Static Assets | Vue CLI 3 ](https://cli.vuejs.org/guide/html-and-static-assets.html#relative-path-imports)

#解決策1:publicフォルダの画像を参照する
モジュールとして解決できないなら、単純に静的ファイルとしてURLを指定すれば良い。
画像を`src/assets`フォルダから`public/img`フォルダに移動させて、パスを絶対パスに書き換えます。(相対パスでも可。)
publicフォルダはビルド時に出力先のフォルダにコピーされるので、そのパスを書いとけばいい。

```vuejs:home2.vue
<template>
 <ul>
    <li v-for="icon in icons" :key="icon">
      <img :src="icon"/>
    </li>
 </ul>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component
export default class Home extends Vue {
  icons = [
    '/img/img1.png',
    '/img/img2.png',
    '/img/img3.png',
  ]
}
</script>
```
#解決策2:require()を使いモジュールとして解決する
解決策1でも動作しますが、publicフォルダを使用するよりモジュールとして読み込んだほうが以下のような利点があります。


- ファイルが見つからないと404エラーでなくコンパイルエラーになる
- 画像ファイル名にコンテンツハッシュ(例:`img1.3020e851.png`)がつくため、ファイルを変更したときにブラウザキャッシュのせいで古い画像を表示してしまうという問題が発生しない

なので、できるだけモジュールとして画像を扱いたい。
その場合はプログラム上でreuqire()を呼び出せばよいです。
画像ファイルは`src/assets`フォルダに置きます。

```vuejs:home2.vue
<template>
 <ul>
    <li v-for="icon in icons" :key="icon">
      <img :src="icon"/>
    </li>
 </ul>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component
export default class Home extends Vue {
  icons = [
    require('@/assets/img1.png'),
    require('@/assets/img2.png'),
    require('@/assets/img3.png'),
  ]
}
</script>
```
require()でなくてimport文でも動作しますが単純に記述量が増えるためrequire()を使用しています。
これで画像をモジュールとして扱い、v-forで画像を並べることができました。

#まとめ
imgのsrcをv-bindで指定する場合は、静的ファイルとして扱うか、reuqire()を使用してモジュールとして解決する。
【メモ】メディアクエリに合わせてjavascriptに何らかの処理を行わせる【暫定】

脱JQueryシリーズ。

javascriptだけでロード時やリサイズ時にメディアクエリに合わせて処理を変えたい。というか変えなきゃいけない場面に出くわしたわけです。
毎度のこと、JQueryの偉大さを痛感させられます・・・。

```javascript
function fireForEachSize(){
  if(window.matchMedia('(min-width: 1025px)').matches){
    console.log('PC用の処理書いてね！')
  }else if(window.matchMedia('(min-width: 600px)').matches){
    console.log('タブレット用の処理書いてね！')
  }else{
    console.log('モバイル用の処理書いてね！')
  }
}
window.addEventListener('load', fireForEachSize);
window.addEventListener('resize', fireForEachSize);
```
内容はどうなかは別としてとりあえず動く・・・。
何か良案お持ちのかたは是非おねがいします！！！
UnityのProfilerWindowの情報をスクリプトで取得する


#概要
Unityのスクリプト上からProfilerウィンドウの中のデータを取得する機能の紹介。

サンプルは下記リポジトリ。
https://github.com/KTA552/UnityProfilerCapture

作成環境
Unity 2018.1.4f1

#目的
処理負荷の計測を行う際、UnityのProfilerを使用するが、負荷が高いところを探すのにツリーをいちいち展開していく必要があるため、それが結構手間で面倒くさかった。
重い処理が特定出来ている場合は、Profilerの名前検索などでフィルター出来るが、既に名前が特定出来ている場合に限られてしまう。
そのため、Profilerで計測されている中身を全部精査してSelfTimeや全体の割合を関数単位で見られるように出来ると楽になるので作成しました。

なお、既に負荷を計測したいものがわかっているなら普通にUnityのProfiler.Recorderを使用するのが楽だと思います。
Unity - Scripting API: Recorder 
 https://docs.unity3d.com/ScriptReference/Profiling.Recorder.html

#やること

- Profilerが保持しているProfilerPropertyのルートを取得する
- 取得したProfilerPropertyの中から必要なデータを取得。
- ProfilerPropertyの子供がいなくなるまで繰り返し行う。

上記２点。
その後データを加工したりソートしたり出力したりはご自由に。

実際に機能しているUnityのツールのコードは下記リポジトリのコード。
UnityProfilerCapture/ProfilerCapture.cs 
https://github.com/KTA552/UnityProfilerCapture/blob/master/Assets/%20Debug/ProfilerCapture.cs

#サンプルコード
### ProfilerPropertyの取得
ProfilerのRoot情報を取得します。
SetRootのフレーム指定で-1しているのは、ProfilerWindowに表示されているCurrentFrameと1つずれたフレームの情報が取れてしまうためです。
第２引数は取得するProfilerPropertyのソート順を指定します。TotalTimeやSelfPercentなど指定出来ます。
第３引数はProfilerWindowから取得するカテゴリを指定します。
Timelineとか指定すればProfilerのTimelineの情報が取得出来ると思います。それはやったことないので知りません。

```CSharp
// ProfilerのRoot情報を取得
var property = new ProfilerProperty();

property.SetRoot(_captureIndex - 1, ProfilerColumn.SelfTime, ProfilerViewType.Hierarchy);
```

###ProfilerPropertyから情報を取得
property.NextをすることでcurrentのPropertyのヒエラルキーの次の階層へ移動します。
Nextの引数は自身の子供も含めて次の階層へ向かうかのオプションです。

サンプルの中では、Rootから丸ごと情報を取得しているため結構大量のPropertyが取得できてしまうため、
SelfTimeで適当な負荷以上のものだけデータを取得するようにしています。

```CSharp
// ネストする子供がいなくなるまで回す
while (property.Next(true))
{
    var value = property.GetColumnAsSingle(ProfilerColumn.SelfTime);

    // 根こそぎ取れるので適当なしきい値で切る
    if (value > 0.01)
    {
        _logText += String.Format("{0}, {1}, {2}. \n",
                        property.GetColumn(ProfilerColumn.FunctionName),
                        property.GetColumn(ProfilerColumn.SelfTime),
                        property.GetColumn(ProfilerColumn.SelfPercent));

    }
}
```

#参考

UnityCsReference/ProfilerWindow.cs
https://github.com/Unity-Technologies/UnityCsReference/blob/57f723ec72ca50427e5d17cad0ec123be2372f67/Modules/ProfilerEditor/ProfilerWindow/ProfilerWindow.cs

ProfilerProperty.Next, UnityEditorInternal C# (CSharp) Method Code Examples - HotExamples
https://csharp.hotexamples.com/examples/UnityEditorInternal/ProfilerProperty/Next/php-profilerproperty-next-method-examples.html

第6章 EditorGUI (EdirotGUILayout) - エディター拡張入門 
https://anchan828.github.io/editor-manual/web/part1-editorgui
Laravelの認証を別テーブル(モデル)に変更してカスタマイズする

Laravelの認証は通常`users`テーブルで行います。ユーザーの種類が複数ある場合は、それぞれのユーザーで別々のテーブルをつかって認証させたいことがあると思います。
通常ユーザーと管理ユーザー、生徒と教師、みたいな関係です。
今回は、管理ユーザーは`admin_users`テーブルで認証させる例を使います。

## 認証テーブルを作成

```sql:admin_users
CREATE TABLE `admin_users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `remember_token` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
```

## モデルを作成

```
php artisan make:model Eloquent/AdminUser
```

```php:Eloquent/AdminUser.php
<?php

namespace App\Eloquent;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class AdminUser extends Authenticatable
{
  protected $fillable = [
    'email', 'password',
  ];
}
```

## 自作の認証テーブル、認証モデルを使うようにする

```php:config/auth.php
'defaults' => [
  'guard' => 'web',
  'passwords' => 'admin_users',
],
'guards' => [
  'web' => [
    'driver' => 'session',
    'provider' => 'admin_users',
  ],
...
],
'providers' => [
  'admin_users' => [
    'driver' => 'eloquent',
    'model' => App\Eloquent\AdminUser::class,
  ],
],
```

## RegisterControllerでのValidationを変更

```diff:RegisterController.php
protected function validator(array $data)
{
  ...

  return Validator::make($data, [
-    'email' => ['required', 'string', 'email', 'max:255', 'unique:creators'],
+    'email' => ['required', 'string', 'email', 'max:255', 'unique:admin_users'],
    ...
}
```
localhostでのERR_SSL_PROTOCOL_ERRORを解消する

Visual Studioから、ASP.NET Webアプリを起動すると、Chromeで、ERR_SSL_PROTOCOL_ERRORとなることがあります。
この状態の解消方法が以下URLにありました。

- SSL Connection Error When Debugging via Localhost in Google Chrome
  - https://www.codeproject.com/Articles/1010667/SSL-Connection-Error-When-Debugging-via-Localhost

手順は以下の通りです。

1. 以下にアクセスする。
   chrome://net-internals/#hsts 

2. Query domainにlocalhostを入力し、dynamic_sts_domainにlocalhostがあることを確認する。
   ![image.png](https://qiita-image-store.s3.amazonaws.com/0/44912/7b6979ba-c660-f5af-c3e2-9419b935067a.png)
  ![image.png](https://qiita-image-store.s3.amazonaws.com/0/44912/aeb88e80-ae2a-6341-c1b4-f72ea13bc943.png)

3. localhostをdeleteする。
  ![image.png](https://qiita-image-store.s3.amazonaws.com/0/44912/69e62d74-1a59-a6f3-5f7f-7e82dce68a3f.png)

4. 再度Query domainを確認し、なくなっていることを確認する。
  ![image.png](https://qiita-image-store.s3.amazonaws.com/0/44912/afb61441-1a75-2102-87af-c191d66aafc1.png)


おしまい。