OmniAICreator/Qiita-1.07M huggingface dataset:
多分間違えてるColaboratoryの使い方(Kotlinを試す)

# はじめに

多分間違えてるColaboratoryの使い方シリーズ第４弾

今回は会社の後輩に聞かれたので、Kotlinを試してみたいと思います。

過去の記事

- [多分間違えてるColaboratoryの使い方(Go入門)](https://qiita.com/kei0425/items/19bebc966dcf50e5af2e)
- [多分間違えてるColaboratoryの使い方(now入門)](https://qiita.com/kei0425/items/e82b1796f8a7a0dbd445)
- [多分間違えてるColaboratoryの使い方(最新nodejsを利用する)](https://qiita.com/drafts/852b2f23384eaea6873a/)

# Kotlinとは

Java仮想マシンで動作するいわゆるJVM言語。
Javaの資産を利用可能。
主にJavaのいけてない部分を改良したもの。

詳しくはこのへんをみてください。

- [Android開発を受注したからKotlinをガッツリ使ってみたら最高だった](https://qiita.com/omochimetaru/items/98e015b0b694dd97f323)

# 環境設定

## Colaboratoryの準備

[Google Colaboratory](https://colab.research.google.com/)をクリックします。

初めての場合は、Colaboratory へようこそというノートが開かれるので、左上メニューの「ファイル」の「Python 3 の新しいノートブック」を選択して新しいノートを開いてください。

## Javaのインストール

Javaはaptでインストールできます。
せっかくなので最新版の11をインストールします。

```:入力セル
!apt install openjdk-11-jdk
!java --version
!javac --version
```

## Kotlinのインストール

公式ではSDKMANを使えとありますが、Colaboratoryではシェルツールが利用できません。
（私が知らないだけかもしれませんが）
なので、SDKMANは利用せず、直接ぶち込みます。

```:入力セル
!curl -OL https://github.com/JetBrains/kotlin/releases/download/v1.3.21/kotlin-compiler-1.3.21.zip
!unzip kotlin-compiler-1.3.21.zip
!cp -r kotlinc/* /usr/local
```
※バージョンがあがって、アーカイブの場所が変わっていたため修正しました。

# 動作確認

やっぱり、動作確認は、Hello Worldですね。

```:入力セル
%%writefile hello.kt 
fun main(args: Array<String>) {
    println("Hello, World!")
}
```

```:入力セル
!kotlinc hello.kt -include-runtime -d hello.jar
!java -jar hello.jar
```
```:出力セル
Hello, World!
```

# おわりに

KotlinはAndroid用なのかなって思っていましたが、Javaとそのまま置き換えられるので、何でもできそうですね。
ちゃんと勉強しようと思いました。

というわけで、WebFramework編(Spring)もやるかもしれません。
Yubikeyを使ってAWS Consoleにログインする際の設定してみた

AWS ConsoleにやっとU2Fが来たぞー！さぁセットアップだ！とぬか喜びしているシステム管理者の戯言です。
IAMユーザやRootアカウントにYubikeyをセットアップしてみました。

多分YubikeyなどのU2F対応デバイスに詳しい人は早速試してるんじゃなかろうかと思うので、後追いになりますが、同様の記事となりますので、既に知ってるよ！って方は読み飛ばしていただければと思います。

# どうなったか

セットアップは超簡単でUSBにYubikeyを差し込み金属部分をタップするだけで終わります。

ぼく「よーし、別の人もセットアップできるかな？」(ポチ

![4. MFA-Resetting.png](https://qiita-image-store.s3.amazonaws.com/0/13837/28490e54-6013-b55d-33f9-2da84c5ae1af.png)

あqwsでfrgthy樹医kぉp；＠：「

***あのーAWSさん？***

## 何が問題なのか

複数登録する機能(アプリ、ハード、U2Fの複数登録機能)ぐらい実装しようぜ！
デバイス無くしたらどうすんじゃいって話があるのでマジイケてない。
さっさと改善しろください。

電話問い合わせしたら解除してくれるのかもしれませんが、不都合な部分があるんですよね

というのも弊社ってぼく一人がシステム管理してるわけじゃないんですよ。
なので管理者の人数分のU2F対応デバイスを購入しています。（お試し部分も含め）

1つのIAMユーザ(恐らくRootアカウントも含め)につき、1つのU2Fってなると結局遠隔地にいるメンバがログインする際はハードのMFA使って番号伝える方式になるやーんって感じです。
ほとんどRootアカウントでログインすることがないとはいえ、必要になるケースがないわけじゃないんですよね。
例えばプラン変更とか一部の制限解除依頼とか。

とりあえずせっかくなのでセットアップ方法を以下に記載します。

## セットアップ方法

セットアップのおおまかな流れを記載します。

1. IAMユーザの画面を開きます。
2. U2Fを設定したい人のアカウントを開きます。
3. 認証情報タブをおもむろにクリックします。
4. 既にMFAを設定している場合は削除します。
5. USBにU2Fデバイスを差し込んでおきます。
6. U2Fセキュリティキーを選択し続行ボタンを押します。
![1. MFA-Select.png](https://qiita-image-store.s3.amazonaws.com/0/13837/5435373a-1b82-b79c-d542-6ce27325bc1f.png)
7. セットアップ画面が出るので金属部分をタップします
![2. MFA-Setup.png](https://qiita-image-store.s3.amazonaws.com/0/13837/92335d3a-8767-4f90-5252-a9878c86d139.png)
8. 画面が切り替わり閉じるボタンを押せば終了
![3. MFA-Complete.png](https://qiita-image-store.s3.amazonaws.com/0/13837/6f27c142-f32a-a1d1-20e9-fcd98db6a43a.png)

# まあもともと1つしか認証しない設定なんだからそうなるよね

でも、複数登録させろください。マジでお願いします。
（っていう要望を今度出してみることにしますー）

あ、ちなみに最近FirefoxもU2Fに対応してますのでChromeしか使えないよってサービスは少なくなっています。
ex. Google(G Suite含む)はChromeでなければ登録できない仕様。

ただ一度認証さえしてしまえば、ChromeじゃなくてもFirefoxでも認証してくれます。
ただしMac標準のメールアプリからGoogle(G Suite含む)を追加しようとした際は、Mac標準のアカウント設定がU2Fに対応してないため別の認証方式を利用することになります。

もっと世間にU2F対応デバイスが広まーれ！
　　　*ﾟﾟ･*+。
　　 ｜　　　ﾟ*｡
　　｡∩∧∧　　*
　 + (･ω･`) *+ﾟ
　 *｡ヽ　　つ*ﾟ*
　　ﾞ･+｡*･ﾟ⊃　+ﾟ
　　 ☆ ∪　 ｡*ﾟ
　　　ﾞ･+｡*･ﾟ

むしろ、どの案件でもWebサービスをローンチする際に、U2F対応のサービスにすると大喜びだと思いますよ。
React Reduxを簡単に利用してみる


Reduxを人に説明する簡単なコンテンツ作らなきゃと思っていたところ大変良い記事を発見したので、それを参考に自分の目的にあった形にアレンジさせていただきました。

thunkを利用したAPIリクエストやコンポーネント間での共有についての[続編](https://qiita.com/zaburo/private/1557d5a1ea80d304687b)も書きました。

## 参考サイト

シンプルなReduxサンプルが無く困っていまいたが、大変参考になりました。ありがとうございます。

* https://qiita.com/loverails/items/8c46767413a3c8d15f00

## 準備

参考サイトさんではreact nativeを利用されていますが、普通のcreate-react-appでやってみます。

```bash
create-react-app redux_test
cd redux_test

npm install --save redux react-redux
```

## 実装

直下にmyRedux.jsファイルを作成し、以下の記述をします。
変数の依存関係がわかりやすいようにあえて変数名を場所により変えております。

```js:myRedux.js
import {combineReducers, createStore } from 'redux';


//actions

export const editName = _name => ({
    type: "EDIT_NAME",
    name: _name
});

export const deleteName = () => ({
    type: "DELETE_NAME",
    name: ''
});

//reducers

//reducerの_userと命名
export const _user = (state = {}, action) => {
    switch (action.type){
        case 'EDIT_NAME':
            return action.name;
        case 'DELETE_NAME':
            return action.name;
        default:
            return state;
    }
}

//keyを指定して別名(user)で参照可能にしました（keyを指定しないと_userとなる） 。
export const reducers = combineReducers({
    user: _user,
});


//store

//値は以下の構造となる。
const initialState = {
    user: {
        name: 'foo'
    }
};

export const store = createStore(reducers,initialState);

```

App.jsはそのまま上書きして利用します。

```js:App.js
import React, { Component } from 'react';
import { connect } from 'react-redux'
import { editName, deleteName } from './myRredux'


class App extends Component {
  render() {
    return (
      <div className="App">
        {/* USER.name等で参照可 */}
        <h3>{this.props.USER.name}</h3>
        <button onClick={() => this.props.editName({name: 'my name is hoge.'})}>Add</button>
        <button onClick={() => this.props.deleteName()}>Del</button>
      </div>
    );
  }
}

//combineで付けたkey名でマッピング（props.USERにマップ）
const mapStateToProps = state => ({
  USER: state.user
});

//dispatchはそのまま
//props.addName()にマップ
const mapDispatchToProps = {
  editName,deleteName
}

//バインドさえれたAppが返る
export default connect(mapStateToProps,mapDispatchToProps)(App);
// export default App;

```

index.jsは\<Provider></Provider>を追加するだけ。

```js:index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';


import { Provider } from 'react-redux'
import { store } from './redux'

ReactDOM.render(
    <Provider store={store}>
        <App/>
    </Provider>,
    document.getElementById('root')
);
```

動作確認。

```bash
npm start
```
laravel5でProviderが呼ばれない場合の対処法

laravel5で、新たにProviderを設定したのに、Providerで呼び出し先のメソッドがないなどのエラーになった場合の対処法です。

## 環境
・centos6.8
・php7.0
・laravel5.1


## 原因
新たに`config/app.php`に追加したProviderが呼ばれない場合は、プロバイダーの呼び出しのキャッシュが更新されていない。

## 対処法
`php artisan clear-compiled`
でキャッシュをクリアしてください。

それでも解決しない場合は、以下を試してください。
1. `php artisan clear-compiled`で`bootstrap/cache/services.json`を削除
2. `php artisan config:cache`で`bootstrap/cache/config.php`を作り直す

2を行うと`bootstrap/cache/services.json`も作成されています。
config.phpを作り直したことで、追加したProviderもservices.jsonに登録されました。

<br>
以下を参考にさせて頂きました。
https://blog.ytake.jp.net/entry/2015/12/17/224038
特定データベースの全権限を持つユーザの作成（RDS for MySQL 5.6）

ちょっとひっかかかったのでメモ.

# 最初に完成形

username, databasename, passwordの部分を書き直して利用します。

```sql
# username,password,databasenameを置き換える
# ユーザ作成
CREATE USER 'username'@'%' IDENTIFIED BY 'password' ;

# 権限付与
GRANT
    SELECT,
    INSERT,
    UPDATE,
    DELETE,
    CREATE,
    DROP,
    REFERENCES,
    INDEX,
    ALTER,
    CREATE TEMPORARY TABLES,
    LOCK TABLES,
    EXECUTE,
    CREATE VIEW,
    SHOW VIEW,
    CREATE ROUTINE,
    ALTER ROUTINE,
    TRIGGER
ON  `databasename`.* 
TO 'username'@'%'
;

# [OPTION]SQL実行前に実行されるスクリプトを設定(パラメタグループのinit_commandで指定)している場合はそのスクリプトの実行権限(EXECUTE)を付与
# 以下では古いRDS用に設定してい「UTCを日本時間にする」スクリプトの実行権限を付与
GRANT EXECUTE ON PROCEDURE `mysql`.`adjust_time_zone` TO 'username'@'%';

# ユーザ一覧を表示
SELECT user, host FROM mysql.user;
```
# ひっかかったところ

２つあって、１つは権限付与時の**Incorrect usage of DB GRANT and GLOBAL PRIVILEGES**エラー。
もう１つはSQL実行時の**Access Denied (init_command)**エラー。

## 権限エラーの原因と対処

公式サイトに記載されている権限一覧表の「コンテキスト列」の値が「サーバ管理」となっている権限はデータベース単位では付与できません。例えば ALL, SHOW DATABASESなどです。

[MySQL :: MySQL 5.6 リファレンスマニュアル :: 6.2.1 MySQL で提供される権限](https://dev.mysql.com/doc/refman/5.6/ja/privileges-provided.html)

RDSのマスタユーザの権限を元に作成しようとしたので余計な権限が付与されていた。というオチでした。汗

[RDS MySQL でマスターユーザー権限を持つユーザーの新規登録](https://aws.amazon.com/jp/premiumsupport/knowledge-center/duplicate-master-user-mysql/)

## SQL実行時エラー（init_command）

古いRDSではデータベースサーバの時刻がUTCとなっていて恒久的な設定変更ができませんでした。
このためパラメタグループのinit_commandに時刻調整用スクリプトを設定するというハックが必要でした。

このスクリプトの実行権限が付与されていなかったのが原因でした。

```
GRANT EXECUTE ON PROCEDURE `mysql`.`adjust_time_zone` TO 'username'@'%';
```
Pythonista on iPADで乗り物の揺れの違いを見るのをもう少し簡単にする

# はじめに
Matlab iOS も便利に使えるのがわかったのだが、Phtynistaを使えばその出来上りをHome Screenに置き、さらに手軽に可視化できそうだ。Pythonはほとんど使ったことがないが、Pythonista のExampleプログラムを基軸にネット情報を頼ってなんとかツールらしきものを作ってみた。
## Example program
Phtyonista 3 をiPAD にインストール。いろいろ触ってみて、Open, This iPad, Examples, Plottingの中の Motion plot.py を少しだけ変えれば、とりあえず形になりそうだ。
#必要 modules
**motion :**  Pythonista 3 独特のmoduleらしい。iOS のセンサのデータを所得できる。凄い❣️詳しくは、[作者ページ](http://omz-software.com/pythonista/docs/ios/) の**motion**から。他にも、**location**のデータにもアクセスできる。 
**matplotlib.pyplot :** プロット専用。
**time :** 定期的にデータを獲得するため。
**numpy :** 数値計算用。
# motion module
詳しくは、上記のページから。ざっと、acceleration, gravity, attitude, magnetic field を取得。Matlab のそれと似ているが同じではない。今回は、motion.get_user_acceleration()を使う。オリジナルはmotion.get_gravity()を使用。
## 全コード
めんどくさいので、全コードを貼り付ける。オリジナルをほぼそのままところもあるので、**問題があるなら、教えてください！**もちろん、**根本的な考え方やコードの間違いなどの指摘も大歓迎です！**

やってる（と思っている）ことは、
1. 時間とデータをストックするための名前（例えば、Shinkansen20181017とか）を入力させて
2. その２秒後にデータを取り始め「名前.npy」でデータをセーブ
3. 生のデータと、フーリエ変換したデータをプロットして「名前.png」でセーブ
今回もデータ取得は100Hzに設定しておいた。プロットが少し見にくくなるので、Y軸のラベルはコメントアウト。
これを、Add to Home Screen でホームスクリーンにおくと、いつでも好きなときにデータを取り始めることができる。

```py:TransportSickness.py

import motion
import matplotlib.pyplot as plt
from time import sleep
import numpy as np
def main():
	duration = input('enter duration: ')
	duration = int(duration)
	name = input('enter data name: ')
	motion.start_updates()
	sleep(2)
	print('Capturing motion data...')
	num_samples = duration * 100
	data = []
	for i in range(num_samples):
		sleep(0.01)
		a = motion.get_user_acceleration()
		data.append(a)
	motion.stop_updates()
	np.save(eval('name'),data)
	print('Capture finished, plotting...')
	ft = np.fft.fftn(data)
	p2=np.absolute(ft/num_samples)
	p1=p2[np.arange(0,int(num_samples/2)+1),]
	p1[1:] = 2*p1[1:]
	f=100*np.arange(0,int(num_samples/2)+1)/num_samples
	sample_number = [x*0.01 for x in range(num_samples)]
	plt.subplot(131)
	for i, color, label in zip(range(3), 'rgb', 'XYZ'):
		plt.plot(sample_number,[a[i] for a in data], color, label = label, lw=2)
	plt.grid(True)
	plt.xlabel('Sec')
	#plt.ylabel('Acceleration')
	plt.subplot(132)
	for i, color, label in zip(range(3), 'rgb', 'XYZ'):
		plt.plot(f,p1[:,i], color, label = label, lw=2)
	plt.grid(True)
	plt.xlabel('Hz')
	#plt.ylabel('Spectrum')
	plt.gca().set_xlim([0, 20.0])
	plt.subplot(133)
	for i, color, label in zip(range(3), 'rgb', 'XYZ'):
		plt.plot(f,p1[:,i], color, label = label, lw=2)
	plt.grid(True)
	plt.xlabel('Hz')
	#plt.ylabel('Spectrum')
	plt.gca().set_xlim([0, 2.0])
	plt.legend()
	plt.show()
	plt.savefig(eval('name'))	
if __name__ == '__main__':
	main()

```

# 考察というより感想
1. センサーのデータに簡単にアクセスできるというのは、かなり嬉しい。
2. Matlab を少しだけ齧った身としては一番役に立ったのは[Numpy for Matlab Users](http://mathesaurus.sourceforge.net/matlab-numpy.html)。
3. プロットの見た目は、Matlabのそれに似ている。
4. トグルでデータ取得のオンオフできるともっと使いやすいかも。
5. Phtonistaはlocation,phtos,reminderなどにもアクセスすることができるみたいなので、いろいろ遊べるようになりたい。
オブジェクト指向の基本的な用語

オブジェクト指向第２弾。
今回はオブジェクト指向に欠かせない基本的な用語を、覚書から抜粋して紹介していきます。
自分もわかるように書いていきますので、お付き合いください。

#オブジェクト指向に必要な用語
以下の用語は、オブジェクト指向の中で必要になるものです。
これを覚えておけば、とりあえずオブジェクト指向の話題にはついていけるはずです。
自分がそうですから。

#オブジェクト(object)
- これが大本、一番重要な用語と捉えています。

前の記事に書きましたが、オブジェクトとは「物」という意味の言葉です。
プログラムの世界ではデータと処理の集まりを意味しています。
簡単に言えば、**「人間」**というオブジェクトの中には、
**「名前」**や**「性別」**といった**個人情報(データ)**があり、
何かが**「出来る」**といった**行動力(処理)**を持っていると考えられるわけです。

#クラス(class)

- クラスとはオブジェクトを作るもの事。
オブジェクトは情報の塊という事は先に説明した通り。
つまり、情報をまとめる為の最初の**データ(プロパティ)**や**操作(メソッド)**を行う為に必要なものと考えて構わないでしょう。

ここでは人間に例えられないので、みんなよく使うスマホで例えてみます。
**スマホ(オブジェクト)**を組み立てる時に必要なものは何になるかと考えてみます。

つまり、設計書です。こう考えると、クラスとは設計書になるわけです。
この設計書の中に、データやこういう操作ですという指示が入っている訳です。

また新しい単語が出てきたので、この後説明します。
~~オブジェクト指向はこれが面倒くさいのです、専門用語ばかりなので。~~

#プロパティ(property)
- オブジェクトの中にあるデータの事です。
プロパティは属性って意味になります。

さっきの例えだと、スマホにはいろいろな情報が付随してますよね？
**「Android」**か**「iphone」**で迷ったりしますよね。**「カラー」**はどれがいいとか。
今言ったスマホ商品の**「情報」**の事を**プロパティ(属性)**といいます。

#メソッド(method)
- オブジェクトが内にある処理の事です。
メソッドとは、操作といった意味の言葉です。

スマホで言えば、**「電話をかける」「メールをする」「ネットを見る」**といった動作に繋がるものですね。
このスマホの**「動作」**の事を**メソッド(操作)**といいます。

#オブジェクトをまとめると
- オブジェクト内部にはクラス、プロパティ、メソッドが入っていることになります。

クラス、プロパティ、メソッドの関係は大まかに書くとこうなります。

> class　クラス名{
　プロパティの宣言
　　メソッド名{ 
　　　　実際の処理内容
　　　　　　　}
　　　}

- **実際には言語によって少し変わるときもあるので、調べてから書き始めましょう。**

#インスタンス(instance)
- 最後に、インスタンスは覚えておきましょう。
**オブジェクトが実際に処理を実行したもの**に当たります。

インスタンスとは、「実体」という意味になります。
オブジェクトが何かを作る事を**インスタンス化**と言いますので、これも覚えたほうがいいかもしれません。

実際にはこう書きます。

> class　クラス名 参照する変数 = new クラス名(　);

**これも言語によりますので、実際に自分が触れる時はどうなるのか調べてみてください。**

#最後に
これ以外にももう少しあるのですが、あまりいっぺんに書くと専門書と同じで眠く読みづらくなるので、この辺で終わります。

あくまでも、読みやすい覚書と思って接していただけると幸いです。

#追記
ご指摘ありがとうございます。
今後もう少し改善するようにいたします。
CentOS7に mysql-community-server をインストールし、LAN内の別マシンからアクセス可能にする。

MySQL と競合しそうなMariaDBを削除しておく

```
$ sudo yum remove mariadb-libs
$ sudo rm -rf /var/lib/mysql
```

CentOS 7 に MySQL 公式の yum リポジトリを追加

```
$ sudo rpm -ivh http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm
```

MySQL のインストール

```
$ sudo yum install mysql-community-server mysql-community-client
```

サービスの起動

```
$ sudo systemctl start mysqld
```

初回起動時に自動設定されたパスワードを確認

```
$ sudo cat /var/log/mysqld.log | grep password
2018-10-17T02:30:35.176475Z 1 [Note] A temporary password is generated for root@localhost: password
```

mysql_secure_installationを実行

```
$ mysql_secure_installation
Change the password for root ? ((Press y|Y for Yes, any other key for No) :
#=> Yをプレスし、任意のパスワードに変更

Remove anonymous users? (Press y|Y for Yes, any other key for No) : 
#=> Yをプレスし、匿名ユーザを削除

Disallow root login remotely? (Press y|Y for Yes, any other key for No) :
#=> Yをプレスし、rootをローカルに限定

Remove test database and access to it? (Press y|Y for Yes, any other key for No) : 
#=> Yをプレスし、テストデータベースを削除

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : 
#=> Yをプレスし、権限テーブルをリロード
```


設定ファイルの編集

```
$ sudo vi /etc/my.cnf
```

[mysqld] セクションに以下を追記

```
# ソケット通信だけでなく、LAN内の別マシンから接続させたい
port = 3306
bind-address = 0.0.0.0

# パスワードの有効期限切れを防ぐ
default_password_lifetime = 0
# パスワードのバリデーションを切る
validate_password_policy=LOW
validate_password_length=4
```


サービスを再起動

```
$ sudo systemctl restart mysqld
```

リモートアクセスを許可するユーザを作成

```
$ mysql -u root -p

mysql> CREATE USER 'username'@'192.168.%' IDENTIFIED BY 'password';
mysql> GRANT ALL PRIVILEGES ON *.* TO  'username'@'192.168.%';
mysql> FLUSH PRIVILEGES;
```

CentOS7からファイアウォールが「iptables」から「firewalld」に変更されている。mysqlのポートを開放し、サービスを再起動。

```
$ sudo firewall-cmd --add-service=mysql --zone=public --permanent
$ sudo systemctl restart firewalld
```

別のマシンより接続テスト。繋がった。

```
$ mysql -h $MYSQL_SERVER_ADRESS -u username -p
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 6
Server version: 5.7.23 MySQL Community Server (GPL)

Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]> 
```

###参考にした記事

https://qiita.com/Thort/items/637b32b6c850a62af8de
https://qiita.com/haminiku/items/56fcb578d86abcd0b571
Raspberry Pi の アップデート

まとめておく

# パッケージの更新
```sh

$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get dist-upgrade
```
# ファームウェアの更新
```sh
$ sudo rpi-update
$ sudo reboot
```

- rpi-updateのインストール（rpi-updateが無い場合）

```sh
sudo apt-get install rpi-update
```
C++ Builder XE4 > TTabControl > フォームデザイナ: Tabの追加手順

```txt:動作環境
C++ Builder XE4
```

TTabControlでTabを追加する手順の情報が見つかりにくい。
IDEを触っていて見つけたので共有しておく。

下記はTTabControlをフォームに追加した直後。
![2018-10-17_11h46_07.png](https://qiita-image-store.s3.amazonaws.com/0/32870/91635c6a-a087-8ab3-625c-e8bada20545a.png)

下記のようにTabsの`[...]`をクリックすると、「文字列リストの設定」が表示される。そこにタブの表記名リストを記載する。
![2018-10-17_11h46_53.png](https://qiita-image-store.s3.amazonaws.com/0/32870/34928b28-cdae-ea38-7eca-41995f2b0c22.png)

下記のようになる。
![2018-10-17_11h48_38.png](https://qiita-image-store.s3.amazonaws.com/0/32870/fc450bae-1ce8-80f1-2d9c-88b58ac743f6.png)


### 関連

- [TPageControlタグ、XE4タグ、by 7of9 @ Qiita](https://qiita.com/search?utf8=%E2%9C%93&sort=created&q=user%3A7of9+tag%3ATPagecontrol+XE4)
React Routerでprops.matchが取得できなかった

# 状況
React Routerを使い、pathの:id部分を取り出したかった。

[React Router v4で任意のid情報を送る方法](https://qiita.com/gcyagyu/items/834041c5bd5b45691d32)

上記記事を見たらprops.matchに入っているとのことで簡単だ！と思ってpropsにmatchがあるか確認したらなかった…。

# 原因
componentを利用していないのが原因だった。routerでpropsを渡したかったので、renderを使っていた。

[react-router v4にてchild componentにpropsを渡す方法](https://qiita.com/park-jh/items/7486a0d1dcc5f32c69ec)

# コード

``` javascript
<Route
	exact path = '/'
	render = {() => 
		<SampleComponent 
			data = { data }
		/>}
/>
```

propsを渡したかったので上記の書き方をしていた。

``` javascript
<Route
	exact path = '/'
	component = { SampleComponent }
/>
```

componentにしたらきちんとprops.matchが渡るようになった！
渡したかったpropsはreact-reduxでなんとかしました。（もともとreactで実装してからreact-reduxを入れる、みたいな学習をしていただけなので…）

# 感想

react-redux化した後にpropsを渡す処理が必要じゃなくなったのでrenderである必要がなくなりcomponentに書き直しましたが、そのおかげで気づくことができました。
書くコードにきちんと責任を持って、意味を理解することが重要だなと改めて感じました。。コードに疑問を持つの、大事ですね。
オーディエンスターゲティングについて

![image.png](https://qiita-image-store.s3.amazonaws.com/0/257568/19729221-05f3-fb01-3311-f77b89616b2c.png)


DSP/RTBオーディエンスターゲティング入門を読んだまとめ。
DSP/RTBだけといわず広告システムについて体系的に記されていたので小分け。
オーディエンスターゲティングについて。

## 総論
「枠」から「人」への大きなパラダイムシフトを理解する

## オーディエンスターゲティングとは
- オーディエンスという抽象度のグループから、どのグループをターゲットにするか選択すること。

## 従来ターゲティングとの違い
- ターゲティング対象の抽象度が高いこと
- 従来
  - 単一データ(IPアドレス、GPSデータ、クッキーIDのみ。等)に対して近しいまたは同じデータのユーザーが対象
- オーディエンスターゲティング
  - 単一データを掛け合わせて「人」が判断できる抽象名の付いた概念のグループが対象

## オーディエンスターゲティングに含まれるデータ
- デモグラフィックデータ・興味データ
- 検索データ
- リアルの購買データ

## 大別したオーディエンスデータ
- 内部データ
  - 自社(広告主)が持っている情報 
- 外部データ
  - 自社がもっていない(売買されている)情報

->外部データは一般的に**認知**のフェーズで活用されるもの
　内部データは一般的に**欲求・獲得**のフェーズで活用されるもの

## オーディエンスデータ活用の手法
- **オーディエンス拡張**
  - **CVを獲得したユーザーデータ**と、同じ**ような**ユーザーを探すもの。

->システムだけが機械的に判断できる情報 

例)一戸建てを検討しているユーザーデータ -> マンションを調べているユーザー(同じような買切物件を考えているユーザー) 

- **Look-Alikeターゲティング**
  - CVを獲得したユーザーデータ(内部オーディエンス)が、**外部オーディエンスのどこに所属していたか**を探すもの

->システムと**人間も**判断できる情報

例)
一戸建て資料請求(CV)のユーザーデータ
　　　↓
一戸建て資料請求ユーザーが含まれる外部オーディエンス(多い順)
1. 不動産オーディエンス
2. 一戸建てオーディエンス
3. マンションオーディエンス
4. 妊娠・出産オーディエンス
5. ペットオーディエンス
　　　↓
一戸建てを検討しているユーザーはペットオーディエンスにも存在
　　　↓
マンションより一戸建てが良いことを訴求するクリエイティブを作成したいと考えた場合、ペットオーディエンスに含まれるようなユーザーに対してはペットが一戸建てではストレスなく飼える事を訴求ポイントにした方が、効果が高い
　　　↓
ターゲットへの特定度が高いので、メッセージ性の強いクリエイティブが作成できる

Look-Alikeターゲティングは、**関連がある外部オーディエンスデータの名称**が分かるため、オーディエンス拡張が直接的に関連性が強い人を出すのに比べて、今まで**知り得なかった顧客像がわかる**。つまりマーケターが介在する余地を多くすることができる。

## 書籍情報
横山 隆治, 菅原 健一, 楳田 良輝　DSP/RTBオーディエンスターゲティング入門
https://amzn.to/2xUJEQ5

## 雑感
この辺りの表現はサービスや視点によってニュアンスが微妙に違ったりするので、手法名そのまま先に覚えるより、仕組み自体を把握しておくのが意味ありそう
オーディエンス拡張はターゲティング拡張とも呼んだりする(指すものは同じ)
Facebookなどでは「[類似オーディエンス](https://www.facebook.com/business/help/164749007013531)」というのがそれに近そう
tag入力をtagitを使い実装してみた

#tag入力とは
Qiitaの記事を書いたことある方ならご存知だと思いますが、
以下の写真のように、入力したワードがタグ形式に表示され、設定したワードに関しては、
自動補完する候補を出してくれます。
(Lと打つと、Linux,laravel,lambda,ect...と出てきています)
<img width="503" alt="スクリーンショット 2018-10-13 16.17.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/243062/c41ffadd-884d-b598-6176-c3e184ebb71e.png">

#tag入力プラグイン
今回は、JQueryのプラグインの[tag-it]([title](http://...))を使いました。

調べてみるとtag入力のプラグインだけでも何種類かあって、それぞれメリット・デメリットがあるそうです。
http://d.hatena.ne.jp/a_kimura/20120712/1342097317

#使い方
前提として、こんなディレクトリ構造です。

```
- tagitSample
    - sample.html
    - js
        - tag-it.min.js
    - css
        - query.tagit.css
```

手順をザザっと書くとこんな感じです。

①htmlファイルのheadに以下を入れる

- js
    - jquery.min.js
    - jquery-ui.min.js
    - tag-it.min.js

- css
    - jquery-ui.css
    - jquery.tagit.css 

②htmlファイルのbodyにtag入力するエリアを作成する

③JQueryのイベントを設定する。

```html:sample.html
<!DOCTYPE html>
<html lang="ja">
  <head>
//　①htmlファイルのheadに以下を入れる
    <script src="https://code.jquery.com/jquery-1.9.1.js"></script>
    <link rel="stylesheet" type="text/css" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1/themes/flick/jquery-ui.css">
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/jquery-ui.min.js"></script>
    <link rel="stylesheet" type="text/css" href="css/jquery.tagit.css">
    <script type="text/javascript" src="js/tag-it.min.js"></script>

//③JQueryのイベントを設定する。
    <script type="text/javascript">
        $(document).ready(
            function(){
                $("#myTags").tagit({
                    singleField: true,
                  //自動補完するワードを設定
                    availableTags: ['php', 'ruby', 'react', 'reactNative', 'laravel']
                });
            }); 
     </script>
  </head>

<body>
　<h1>tag-it sample</h1>

//②htmlファイルのbodyにtag入力するエリアを作成する
　　<div class="search-area-colum form-contents">
    　<ul id="myTags" value="tags" name ="tags"></ul>
　　</div>
</body>
```
#####上記のコードを動かすと.....
<img width="454" alt="スクリーンショット 2018-10-13 17.13.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/243062/f3cc71ff-a36a-9d0b-894c-12be7fec3c10.png">

殺風景ですが、ちゃんと自動補完機能も動いて、タグ入力ができていますね！
簡単簡単！！

```js
$("#myTags").tagit({
    singleField: true,
    //自動補完するワードを設定
    availableTags: ['php', 'ruby', 'react', 'reactNative', 'laravel']
 });
```
↑で自動補完設定した[ruby', 'react', 'reactNative']が自動補完されています。
配列であれば、availableTags:　に渡すことができるので、データベースから取ってきた値を渡してあげることもできます。私も実際の開発では、データベースにあるマスターデータから、自動保管するワード持ってきています。

##補足
jqueryのバージョンが3.2.1だと動かないので、
3.2.1を使いたい場合は、

```html
<script src="https://code.jquery.com/jquery-migrate-3.0.0.min.js"></script>
```
を追加してください。
slurm に関する情報

# 概要

slurm に関する情報を集めている。

# まとめ

いくつか調べてみた。

## GridEngine との対応関係

すでに、 GridEngine 系の経験があるならば

- [SGE to SLURM conversion | Stanford Research Computing Center](https://srcc.stanford.edu/sge-slurm-conversion) 

## Galaxy で使うなら

- [Galaxyでジョブを分散実行するには（実践編） - Qiita](https://qiita.com/nasunom/items/ca1e29e6e6df6baeef73) 


## スパコンセンタ

- [某スパコンのキュー情報確認方法 - Qiita](https://qiita.com/satonasu/items/b6efc3d1e1d8055a897e) 


## 101

- [Slurm 101: Basic Slurm Usage for Linux Clusters](http://www.brightcomputing.com/blog/bid/174099/slurm-101-basic-slurm-usage-for-linux-clusters?utm_content=59699158&utm_medium=social&utm_source=twitter)
firebase deployのプロジェクトが途中で変わったときの対応方法

## はじめに
Firebaseを使って開発をしている皆々様。個人開発をしていてFirebaseのdeploy先を変えたいな〜
別のプロジェクトにdeployしよう！ってなったときに
結構躓いたので備忘録として書いておきます。

### TR;DL
開発途中で**デプロイ先**を変えたくなったら

```
firebase use --add
```

## firebase CLI
前提としてfirebase CLIを使用してdeploy作業をしています。

- firebase CLIの更新方法

```
npm i -g firebase-tools
```

## 基本的なfirebase deploy方法
めちゃくちゃ簡単です。

**login**して**init**して**deploy**する

```
firebase login
```
> 再認証したい場合は**--reauth**

```
firebase init
```

```
firebase deploy
```
[本家](https://firebase.google.com/docs/hosting/deploying?hl=ja)

## デプロイ先を変えるには

1回目にデプロイ先を変えるには

```
firebase use --add
```
でプロジェクト先を変える必要があります。ちなみに別のアカウントだったら再ログインが必要。

ちなみに認証情報だけ変えてdeployしても`Authorization failed.`になってしまうので注意です。自分はこれで地味に時間を潰したので参考になればと思います。
git branch 削除のコマンド

#ローカルブランチ
```zsh:一覧表示
$ git branch
master
foo
bar
```

```zsh:HEADにマージしたブランチの削除
$ git branch --delete foo
```
たまにマージしていないと警告が出される

```zsh:マージのエラー分
error: The branch 'foo' is not fully merged.
If you are sure you want to delete it, run 'git branch -D foo'.
```
とくにマージする必要もなく、削除するだけなら`git branch -D foo`のコマンドで削除できる

#リモートブランチ
```zsh:一覧表示
$ git branch --remote
origin/master
origin/foo
origin/bar
```

```zsh:リモートのHEADにマージしたブランチの削除
$ git push --delete origin foo
```

リモートでマジーしていないと警告が出るところをまだ見たことがないので、現象が確認できたら追記。
アレクサスキルのヘルプと終了のサンプル発話をまとめた

## 動機
チュートリアルやアレクサ道場の使い方を色々みて、いざ作ってみたときにサンプル発話を書き込むのが面倒だったので、同じところでぐだる人がいないようにまとめてみました。
スキルによっては独自のサンプル発話を作る必要があると思うので、その部分は追加してください。
私はアレクサスキルでゲームを作っていたので、「降参」みたいな発話で終了しています。豆知識スキルのような場合は必要ないので、削除してください。
下のコードをAlexaSkill KitのJsonエディターの中にあるAMAZON.CancelIntentのサンプルの部分にコピーしてください。
似たようなインテントにストップインテントがありますが、あちらは中断するときに使用されるみたいです。

キャンセルインテントとストップインテントの処理の違いについては以下を参照してください
https://developer.amazon.com/ja/docs/custom-skills/standard-built-in-intents.html#about-canceling-and-stopping
# AMAZON.CancelIntent
```AMAZON.CancelIntent.json
"samples": [
  "降参",
  "降参する",
  "降参するよ",
  "降参した",
  "降参だ",
  "降参だよ",
  "降参だね",
  "降参です",
  "降参ですね",
  "降参ですよ",
  "降参します",
  "負けた",
  "負けだ",
  "負けです",
  "負けですね",
  "負けですよ",
  "負けました",
  "諦める",
  "諦めた",
  "諦めます",
  "もういい",
  "もういいよ",
  "もういいです",
  "やめ",
  "やめる",
  "やめます",
  "やめだ",
  "やめです",
  "やめてください",
  "もうやめ",
  "もうやめて",
  "もうやめる",
  "もうやめます",
  "もう",
  "ダメだ",
  "ダメだよ",
  "ダメです",
  "もうダメだ",
  "もうダメだよ",
  "もうダメです",
  "終わり",
  "終わります",
  "終わりです",
  "終わって",
  "終わってください",
  "ギブアップ",
  "ギブアップします",
  "ギブアップです",
  "終了",
  "終了します",
  "終了です",
  "中止"
]
```
# HelpIntent
こちらはヘルプインテントにコピー&ペーストしてください

```AMAZON.HelpIntent.json
"samples": [
  "ヘルプ",
  "ヘルプして",
  "ヘルプしてください",
  "ヘルプです",
  "ヘルプが欲しい",
  "ヘルプが欲しいです",
  "わからない",
  "わからないです",
  "わかりません",
  "やり方",
  "やり方がわからない",
  "どうやってやるの",
  "どうやってやればいい",
  "どうするの",
  "どうすればいいの",
  "どうしたらいいの",
  "使い方を教えて",
  "使い方を教えてください",
  "使いかたがわからない",
  "使い方がわからないです",
  "使い方を教えて",
  "方法がわからない",
  "方法がわからないです",
  "方法を教えて",
]
```

###参考URL
スキル終了の発話を参考にしました。
https://qiita.com/t_ryusuke/items/dae852d552e2389c5ed5
GitHubのレビューでコード提案をする便利機能を試してみた

# GitHubのレビューでコード提案をする便利機能を試してみた

## New! Suggest specific code changes that the pull request author can immediately commit. You will be attributed in the commit.

今日PRをレビューしていると以下のメッセージが出たので新機能を使ってみた記事です。内容は薄いです。

![Screenshot from 2018-10-17 11-00-47.png](https://qiita-image-store.s3.amazonaws.com/0/112929/c484a526-81f6-778a-1f3b-394cc14ebff1.png)


![Screenshot from 2018-10-17 11-17-03.png](https://qiita-image-store.s3.amazonaws.com/0/112929/b9473416-3fbd-21ac-018b-b0b1afc9fd6a.png)

PRの作成者がその変更を受け入れる `Apply suggestion` とコミットメッセージが聞かれるので `Commit changes` でコミットしましょう。

![Screenshot from 2018-10-17 11-19-12.png](https://qiita-image-store.s3.amazonaws.com/0/112929/42f6224d-b730-b591-e040-38eb8755413d.png)

コミットされておしまい。
UiPathでブラウザ上の要素が認識できないときにすること

#はじめに
UiPathはPC上での様々な操作を自動化するRPAツールの一つです。
UiPath（に限らずですが）ではブラウザに表示されたウェブページ上の操作を自動化することもできます。
ウェブページ内のテキストボックスに文字列を入力したり、ボタンを押したり、任意の部分のデータを取得したりできます。

さて、そのような自動化プロセスを作成して使っていると、まれに以下のようなメッセージが出て自動化プロセスの実行が終了することがあります。
![clipboard_20181017103613.png](https://qiita-image-store.s3.amazonaws.com/0/245438/0db72224-33ef-6456-fecf-7fc68aa2ccce.png)

「メッセージ:このセレクターに対するUI要素が見つかりません」にあるとおり「UI要素がみつからない」ことが原因のようです。
なぜこのようなことになるのかはひとまず置いておいて、その解決方法を紹介します。
ブラウザはChromeで説明していますが、ほかのブラウザでも同じです。

#解決方法１
ブラウザに対する各要素（ボタンやテキストボックスなど）の選択をやり直してください。
このとき、各要素を指定できない場合は解決方法2を読んでください。

#解決方法2
UiPathの拡張機能の削除、再インストールを行い、解決方法1を行ってください。
ただし、再インストールはUiPath Studioからインストールしてください。

##UiPathのブラウザ拡張機能を削除
まずはブラウザにインストールしているUiPath拡張機能を削除します。
ブラウザ上の拡張機能のアイコンで右クリックして表示されるコンテキストメニューから「Chromeから削除」を選択して拡張機能をアンインストールします。
ここで、コンテキストメニューの一番上の項目「UiPath Web Automation」を選択すると、UiPathのChrome拡張機能のウェブストアのページが表示されます。
![clipboard_20181017105030.png](https://qiita-image-store.s3.amazonaws.com/0/245438/1dd8aa1b-0d14-ee20-eecc-4de8c7cef49d.png)
「Chromeから削除します」ボタンがあるので、ここから拡張機能を削除することもできます。
削除すると、以下のように表示され、ここからインストールしなおすこともできますが、UiPath Studioからインストールしましょう。
![clipboard_20181017105857.png](https://qiita-image-store.s3.amazonaws.com/0/245438/50c4fec3-634d-3001-17dd-8ae9b02161c6.png)


##UiPathのブラウザ拡張機能をインストール
UiPath Studioからブラウザの拡張機能をインストールすには、まず左上の「スタート」をクリックします。
![clipboard_20181017111123.png](https://qiita-image-store.s3.amazonaws.com/0/245438/27f6afa1-f407-3373-0317-b0b195eac7f7.png)

すると以下のようなメニューページが表示され、左側のペインから「ツール」を選択すると、拡張機能のインストールを行うボタンが表示されます。お使いのブラウザの拡張機能を選択し、指示に従ってインストールしてください。
![clipboard_20181017101109.png](https://qiita-image-store.s3.amazonaws.com/0/245438/296c4f10-4849-a735-9c47-1781d2ce8d80.png)

インストール時にはブラウザのすべてのプロセスが動いていないことを確認してください。
ウィンドウを閉じていても、タスクマネージャーで見てみるとプロセスが動いている場合があり、それだとインストールすることができません。
[link] C++ Builder XE4 > difference > TPageControlとTTabControl > TTabControl: 同じコンポーネントを複数タブで持つ

```txt:動作環境
C++ Builder XE4
```

TPageControlとTTabControlの違いは何か?

以下はLazarusの情報ではあるが
http://forum.lazarus.freepascal.org/index.php?topic=18853.0

> Blaazen
« Reply #3 on: November 10, 2012, 11:41:04 pm »
Simply, TPageControl contains other components on each tab.
TTabControl has the same components on each tab.

残りの詳細についてはリンク先を参照のこと。


TTabControlについては２つ目のタブの追加方法がXE4で見つからない (2018-10-17)。
Windows版VirtualBoxで64bit版Windowsが使えないときの確認事項

#症状
WindowsにインストールしたVirtualBoxで，64bit版Windowsが選べない。（OSの選択肢に64bit版Windowsが表示されない）

#実証環境
- Windows10 64bit版
- VirtualBox (Version 5.2.20)

#確認事項
1. Hyper-V
2. BIOS
3. Windows Defender

## Hyper-Vの確認
###原因
Hyper-VとVirtualBoxは，Intel製CPUの機能である`Intel virtualization technology`の機能の"奪い合い"が発生してしまい，Hyper-Vが優先されてしまうため共存することが出来ない。
###解決策
以下の手順でHyper-Vを削除(無効化)する。
1. Windows ボタンを右クリックし、`アプリと機能`を選択する。
2. `Windowsの機能の有効化または無効化`を選択する。
3. `Hyper-V`のチェックボックスからチェックを外した上でPCを再起動する。

もしくは，**管理者権限**で開いたコマンドプロンプト or PowerShellで以下のコマンドを実行する。
`bcdedit /set hypervisorlaunchtype off`

##BIOSの確認
###原因
Intel Virtualization Technologyが使えない設定になっている。
###解決策
BIOSの設定の中にある`Intel Virtualization Technology`の設定項目がONになっているか確認する。
(機種によって設定方法に差があるため操作方法は割愛)

##Windows Defenderの確認
###原因
Windows Defenderの機能にある「コア分離」が有効になっている。
###解決策
以下の手順でコア分離を無効化する。
1. Windows Defender セキュリティセンターを開く。
2. `デバイスセキュリティ`→`コア分離の詳細`をクリック。
3. `メモリ整合性`をOFFにし，PCを再起動する。
PythonでPDFフォームにデータを埋める

PDFフォームにデータを挿入したい。
以下の環境で試してきた。

- Java
    - iText
- PowerShell
    - iTextSharp

Pythonでできないかを探していた。
やっと見つけた。

[How to Populate Fillable PDF's with Python](https://bostata.com/post/how_to_populate_fillable_pdfs_with_python/)

英語読めてPythonお得意なら上記のサイトを見てやるといいよ。

## 環境
僕の環境は下記の通り
多分、LinuxやmacOSの方が快適に動くと思う。

- Windows10 Pro x64
- Python 3.5.5 
- pdfrw

pdfrwはPythonのLibrary
下記のようにpipを使ってインストールしておくといいでしょう。

```
# pdfrwをインストールしておく
C:\> python -m pip install pdfrw

```

## サンプルコード

コードに書くとこんな感じです。

```python:fillform.py
#! /usr/bin/python

import os
import pdfrw

INVOICE_TEMPLATE_PATH = 'pdfform.pdf'
INVOICE_OUTPUT_PATH = 'fillform.pdf'

ANNOT_KEY = '/Annots'
ANNOT_FIELD_KEY = '/T'
ANNOT_VAL_KEY='/V'
ANNOT_RECT_KEY = '/Rect'
SUBTYPE_KEY = '/Subtype'
WIDGET_SUBTYPE_kEY='/Widget'

def write_fillable_pdf(input_pdf_path,output_pdf_path,data_dict):
    template_pdf=pdfrw.PdfReader(input_pdf_path)
    annotations=template_pdf.pages[0][ANNOT_KEY]
    for annotation in annotations:
        if annotation[SUBTYPE_KEY]==WIDGET_SUBTYPE_kEY:
            key=annotation[ANNOT_FIELD_KEY][1:-1]
            if key in data_dict.keys():
                annotation.update(
                    pdfrw.PdfDict(V='{}'.format(data_dict[key]))
                )

    pdfrw.PdfWriter().write(output_pdf_path,template_pdf)


data_dict={
    'name':'齋藤さん',
    'gender':'男'
}

if __name__ == '__main__':
    write_fillable_pdf(INVOICE_TEMPLATE_PATH,INVOICE_OUTPUT_PATH,data_dict)

```

GitHubに上げておきました。
https://github.com/arachan/pdffillformpy

## 問題

僕の作ったPDFでは問題はない。
[invoice_template](https://bostata.com/download/post/fillable_pdf/invoice_template.pdf)の方はTextBoxNameが邪魔してFormに挿入したデータが見えない。
印刷してもTextBoxの名前だけが印刷されてしまう。
PDFの仕様とpdfrwの問題なのだとは思うが、きっちり調査できてない。

## Reference 
[How to Populate Fillable PDF's with Python](https://bostata.com/post/how_to_populate_fillable_pdfs_with_python/)
GKE+Container-Optimized OS+NFS環境で、共有ストレージに置いたスクリプトを実行すると hang する

#環境

- GKE クラスタ
- ノードイメージは **COS**（Container-Optimized OS）
- Pod では 別途用意した NFS 共有ストレージをマウント（NFS バージョンは任意）

#検証

Apache+Perl 実行環境 と NFS をマウントするよう設定した Pod にログインして検証

```bash
[root@<Pod Name> /]# df -h
･･･
10.1.0.6:/       40G   48M   38G   1% /var/www/cgi-bin
･･･

[root@<Pod Name> /]# ls -l /var/www/cgi-bin
total 8
-rwx---r-x 1 root root 247 Oct 16 17:02 index.cgi
-rwxr-xr-x 1 root root  33 Oct 16 17:51 test.sh

[root@<Pod Name> /]# /var/www/cgi-bin/test.sh
（hang）

[root@<Pod Name> /]# curl http://localhost/cgi-bin/index.cgi
（hang & Timeout）
```

#対策

公式にある[ノードイメージのページ](https://cloud.google.com/kubernetes-engine/docs/node-images?hl=ja)に、次のように書かれていた。

> Ubuntu
>
> Ubuntu ノードイメージは、Kubernetes Engine のノードイメージ要件に照らして検証されています。ノードで **NFS**、glusterfs、Sysdig、または Debian パッケージをサポートする必要がある場合は、Ubuntu ノードイメージを使用してください。サポートが終了した container-vm ノードイメージは Ubuntu イメージに置き換えられます。

#再検証

ノードイメージを **Ubuntu** に変更すると再現しなくなった。

```bash
[root@<Pod Name> /]# df -h
･･･
10.1.0.6:/       40G   48M   38G   1% /var/www/cgi-bin
･･･

[root@<Pod Name> /]# ls -l /var/www/cgi-bin
total 8
-rwx---r-x 1 root root 247 Oct 16 17:02 index.cgi
-rwxr-xr-x 1 root root  33 Oct 16 17:51 test.sh

[root@<Pod Name> /]# /var/www/cgi-bin/test.sh
Hello World!

[root@<Pod Name> /]# curl http://localhost/cgi-bin/index.cgi
<html>
<body>
<div style="width: 100%; font-size: 40px; font-weight: bold; text-align: center;">
CGI Test Page
</div>
</body>
</html>
```

#参考情報
https://github.com/kubernetes/examples/issues/249
https://cloud.google.com/kubernetes-engine/docs/node-images?hl=ja#ubuntu
Javaの金額計算で学んだこと

##前置き
プロジェクトで使っているのはJava8です。

##事の発端
Javaで金額計算が絡むコーディングをしていて、画面に表示される値が
>299.999999999999988897769753748434595763683319091796875000

のように微妙にずれる事象に遭遇しました。
恥ずかしながら、ちゃんと(?)金額を計算するようなロジックを初めて書いたので、
なぜそうなるのかといった理由も調べながら進めました。

##犯人探し
金額に対してパーセンテージを掛けるような処理の前段で

```java
// どこかのｍodelから取得したパーセンテージと金額
double d = 0.3;
BigDecimal bd = new BigDecimal("1000");
// 計算
BigDecimal bd2 = bd.multiply(new BigDecimal(d));
System.out.println(bd2); // 299.999999999999988897769753748434595763683319091796875000
```

doubleの引数をコンストラクタに渡してBigDecimalインスタンスを生成していたんですね。
DBからごにょごにょ取得した結果、いろいろあってServiveクラスで使用しているmodelのフィールドがdouble型で定義されていました。

##なんでずれるの？
コード上は10進数で定義していますが、内部では2進数で扱っているため、
2進数で循環小数になるような値（例えばdoubleの0.3）は計算をすると丸めが発生、つまり誤差が発生します。
>![スクリーンショット 2018-10-16 18.37.13.png](https://qiita-image-store.s3.amazonaws.com/0/262530/b2267433-b9ce-ebe2-6ce7-449c4b12104e.png)
byリファレンス

#こういうのもだめ
```java
double d = 3.3 / 1.1 // 3になってほしいけど2.9999999999999996
```

##ここでBigDecimalさんの使い方を再確認（汗）
とりあえずリファレンスを読んでみました。
https://docs.oracle.com/javase/jp/8/docs/api/java/math/BigDecimal.html

　- add
　- subtract
　- multiply
　- divide
　などのメソッドを用いて四則演算します。
RoundingModeで四捨五入/切り捨て/切り上げの指定をします。
今回のロジックはそこまで複雑じゃなかったのでややこしいメソッドは使わなかったです。

##だめなのと良いの
```java
// 毎回インスタンス生成、効率が悪い
BigDecimal b1 = new BigDecimal(10); //だめ
//　キャッシュを使うvalueOf()
BigDecimal b2 = BigDecimal.valueOf(10); // 良い

//　∵2進数で循環小数になるものは誤差が発生する
BigDecimal b3 = new BigDecimal(0.3); //　だめ
// 文字列から生成する
BigDecimal b4 = new BigDecimal("0.3"); //　良い
//　doubleの値をBiｇDecimalに変換したいとき
BigDecimal b5 = BigDecimal.valueOf(0.3); //　（なるべくならこの変換が発生する実装にはしたくないけど）
```

 - BigDecimal#ROUND_xxxx系はJava9以降でDeprecatedです。RoundingModeを使いましょう（今のプロジェクトではJava8を使っていますが、バージョンアップを見据えてそのあたりも意識しようと思います）。


##参考URL
http://javazuki.com/articles/bigdecimal-usage.html#_roundingmode
https://qiita.com/TKR/items/52635175654b9b818b89

##2019/11/12 自分用メモ
####大小比較(compareTo())が毎回わからなくなる件

```java
BigDecimal three = BigDecimal.valueOf(3);
BigDecimal five = BigDecimal.valueOf(5);

int hoge  = three.compareTo(five); // -1 
int piyo = three.compareTo(three); // 0
int fuga = five.compareTo(three); // 1

```
Nuxt.jsでnpm run dev した時にポートの競合を回避する

表題通りです。
Nuxt.jsを使い始めたのですが、よーしnpm run devして動かしてみるぞ！って思った時にこんなことがあったので備忘録として。
そして、誰かの役に立てばいいなあ。

#問題発生
https://blog.frevo-works.co.jp/entry/2018/09/27/154355
を参考にNuxt.jsの環境を整えて、
```npm run dev```
を実行！

```shell
Error: listen EADDRINUSE 127.0.0.1:3000at Server.setupListenHandle [as _listen2] (net.js:1345:14)
    at listenInCluster (net.js:1386:12)
    at GetAddrInfoReqWrap.doListen [as callback] (net.js:1501:7)
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:72:10)
Emitted error event at:
    at emitErrorNT (net.js:1365:8)
    at process._tickCallback (internal/process/next_tick.js:114:19)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! client@1.0.0 dev: nuxt
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the client@1.0.0 dev script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
```
よくわからないエラーが出てrunできません。
あと一息なのに…

#解決策①使われているportのプロセスを停止して奪う
これはNuxt.jsがデフォルトで使用するport3000番が他のアプリケーションで使われているから起こるみたいです。
そこでポートが使われていないかチェックしてみます。

```
sudo lsof -i:3000
```

```
COMMAND   PID  USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
node    38708 ◼︎◼︎◼︎◼︎   14u  IPv4 ◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎◼︎      0t0  TCP localhost:hbci (LISTEN)
```
と返ってきました。
PID38708が使用していることがわかります。

なので、

```
kill 38708
```
を実行し

```
npm run dev
```

をもう一度実行すると今度は立ち上がります。

#解決策②Nuxt.jsのデフォルト使用ポートを変更する
package.jsonを開きます。

```package.json(変更前)
  "scripts": {
    "dev": "nuxt ",
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate",
    "lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
    "precommit": "npm run lint"
  },
```

```package.json(変更後)
  "scripts": {
    "dev": "nuxt --port [使いたいポート番号]",
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate",
    "lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
    "precommit": "npm run lint"
  },
```
に変更しnpm run devを実行。

#できた！

```

 INFO  Building project

✔ success Builder initialized
✔ success Nuxt files generated

Compiling


 READY  Listening on http://localhost:3332
```
async/awaitでPromiseの待ち合わせを行う

もう語り尽くされた感もあるのですが、async/awaitで複数のPromiseを待ち合わせる場合のやり方についてです。

Chrome 69のDevToolsのコンソールで動作確認を行いました。

#### 3行で

* `Promise.all()` を使う方法があるよね
* awaitの配列を作る方法もあるみたいなんだ
* おもしろいね（小並感）

## Promise.all()をawaitする

筆者がよくやるのは、`Promise.all()`をawaitする方法です。

```js:Promise.all()をawaitする方式
async function hoge() {
    const start = Date.now(); // 時間計測用

    // sleep的なやつ
    const p11 = new Promise(resolve => setTimeout(resolve, 1000));
    const p12 = new Promise(resolve => setTimeout(resolve, 2000));
    const p13 = new Promise(resolve => setTimeout(resolve, 3000));

    // 結果を待ち合わせる
    const [r11, r12, r13] = await Promise.all([p11, p12, p13]);
    
    // 経過時間を表示
    console.log("time", Date.now() - start);
}
hoge();

=> time 3005
```

逐次に実行されたら6秒かかる処理ですが、並行で実行されてくれたようで、3秒で終わっています。

p11〜p13の結果が出揃った時点で結果が出るので、待ち合わせをしたい場合には、これでよさそうです。

## awaitの配列を作る

さて、こんな話を同僚の @kaminchu にしてみたところ、

> 
>     const [r11, r12, r13] =[await p11, await p12, await p13];
> でいけるかも・・・？

というコメントをいただきまして、「流石にそれは逐次で実行されるやろー」と思いながら試してみました。

```js:awaitの配列を作る方式
async function fuga() {
    const start = Date.now(); // 時間計測用

    // sleep的なやつ
    const p21 = new Promise(resolve => setTimeout(resolve, 1000));
    const p22 = new Promise(resolve => setTimeout(resolve, 2000));
    const p23 = new Promise(resolve => setTimeout(resolve, 3000));

    // 結果を待ち合わせる
    const [r21, r22, r23] = [await p21, await p22, await p23];

    // 経過時間を表示
    console.log("time", Date.now() - start);
}
fuga();

=> time 3003
```

並行処理になってる……！！！！

動いちゃった以上は疑いようがないですが、評価順が謎です。もともとそういう仕様なんでしょうけれども、意外でした。疑ってごめんよ……

## 両者の違い

記述量だったり見た目の違いというのはあるのですが、挙動としてはあまり違いがないので、好きな方を使えばよさそう、というのが正直なところです。

### 追記

と思っていましたが、`Promise.all()`と`[await p1, await p2...]`は全然違う挙動でした。`new Promise()`の式と`[await p1, await p2...]`を組み合わせると近い挙動にはなりますが、`[await p1, await p2...]`という記法自体が`Promise.all()`と同じ機能を持っているわけではありません。

コメント欄でご指摘いただきましたが、awaitを配列にするやり方は、

```js
const p21 = new Promise(resolve => setTimeout(resolve, 1000));
const p22 = new Promise(resolve => setTimeout(resolve, 2000));
const p23 = new Promise(resolve => setTimeout(resolve, 3000));
```

の時点で並行処理が始まっているので、これだと

```js
const p21 = new Promise(resolve => setTimeout(resolve, 1000));
const p22 = new Promise(resolve => setTimeout(resolve, 2000));
const p23 = new Promise(resolve => setTimeout(resolve, 3000));

const r21 = await p21;
const r22 = await p22;
const r23 = await p23;
```

とあまり変わりません。

筆者は `Promise.all()` を使う感じになりそうです。

## まとめ

async/awaitは奥が深いですね（小並感）
xmlDocument.Evaluate()におけるSnapshotとIteratorの動作の違い（Javascript）

DOM木でXPATHを評価する際、JavaScriptでは

```javascript:evaluateメソッドを使う
result = document.evaluate(XPATH, 対象ノード, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); 
```

のよう記述します。
第三引数をSNAPSHOTやITERATORにすると、複数の結果を取得できます。

```javascript:イテレータを使う
var node = result.iterateNext();
while (node) {
    hoge(node);
    node = iterator.iterateNext();
}	
```


今回、上記hoge(node)の部分で以下のように別のDOM木（document2）にnodeをコピーする処理を以下のように書きました。

```javascript:
    document2.firstChild.appendChild(node);
```

するとiterateNext()で例外（invalidstate）が発生。
この方法だと、元のDOM木から当該nodeがコピーではなく移動されます。当然元のDOM木は1つnodeを失います。

問題はなぜ例外が出るのか。
[こちら](https://developer.mozilla.org/ja/docs/Introduction_to_using_XPath_in_JavaScript#document.evaluate)によると
「反復処理中に文書が変異した (文書ツリーが改変された) 場合、反復処理は無効化され、XPathResult の invalidIteratorState プロパティが true に設定され、NS_ERROR_DOM_INVALID_STATE_ERR 例外が投げられます。」
とあります。

上記のように元のDOM木が変更される可能性がある場合は、イテレータではなくスナップショットを使うのがお作法のようです。

```javascript:スナップショットを使う
var nss= document.evaluate(XPATH, 対象ノード, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );
for ( var i=0 ; i < nss.snapshotLength; i++ )
{
    document2.firstChild.appendChild(nss.snapshotItem(i)); 
}
```



この記事の本筋とは外れますが、元のDOM木の内容を保持したままnodeをコピーしたい場合はcloneNode()を使用します。元のDOM木を再利用する必要がある場合はこのような方法で対応する必要があります。

```javascript:元のDOM木を保持
while (node) {
    document2.firstChild.appendChild(node.cloneNode(true));
    node = iterator.iterateNext();
}	
```
logrotateで日付を付与して独自フォーマットのファイル名を設定


```/etc/logrotate.d/hoge
/var/log/hoge/hoge_error.log {
    daily
    rotate 30
    dateext
    missingok
    notifempty
    sharedscripts
    delaycompress
    postrotate
        mv /var/log/hoge/hoge_error.log-`date '+%Y%m%d'` /var/log/hoge/hoge_error_`date -d '1 days ago' '+%y%m%d'`.log
    endscript
}
```
nginx と dehydrated の組み合わせで ACME クライアントを用いたお手軽 ssl 対応 web サーバの構築 IPv6専用

FreeBSD 11.2-RELEASE が前提ですが、執筆時点では 10.4-RELEASE や 12-current でも適応可能です。
また本記事は FreeBSD 経験者を対象に書いているので、事細かい配慮はされていません。

#下準備
OS は最新のパッチが当たっていることと、ports skeleton もなるべく最新のものに同期していること。
__IPv6 でインターネット接続__されていること。

#アプリケーションの導入
ports から以下のパッケージをインスコする。

* www/nginx
* security/dehydrated

#ACME クライアント取得用アカウント作成
以下のコマンドを実行して ACME アカウントを発行します。

```text:
# dehydrated --register --accept-terms --ipv6 --domain %%HOSTNAME%% --ocsp --challenge http-01
```
:warning:%%HOSTNAME%% の箇所は今後使用予定の web サーバアドレスで、実際にインターネット網からアクセス出来るアドレスである事。
これが出来てないとこの先には進めないので注意。
:warning:また、%%HOSTNAME%% は___全て半角小文字___である事に注意。
:warning:日本語ドメインで利用する場合は__自動変換__しないので、予め [IDN](https://www.nic.ad.jp/ja/dom/idn.html) で Punycode 化したドメイン名を指定する事。
#ACME クライアントの認証用に用いる特定ディレクトリの設定
nginx の設定で server 節内に以下の alias を追記します。

```text:nginx.conf
        location ^~ /.well-known/acme-challenge/ {
            alias /usr/local/www/dehydrated/;
        }
```
#証明書発行作業

```text:
# dehydrated --cron --ipv6 --domain %%HOSTNAME%% --ocsp --challenge http-01
```
問題が無ければ以下のディレクトリに証明書と個人鍵などが作成されているはずです。

```text:
/usr/local/etc/dehydrated/certs/%%HOSTNAME%%/
```
作成されるファイル名 (実際は静的リンク)

+ cert.csr
+ cert.pem
+ chain.pem
+ fullchain.pem
+ privkey.pem

#nginx に作成された証明書を書き入れて ssl の準備
先ほど server 節内に追記した箇所とは別に、新しく server 節を書き足します。

```text:nginx.conf
    server {
        listen [::]:443 ssl http2;
        ssl_certificate /usr/local/etc/dehydrated/certs/%%HOSTNAME%%/fullchain.pem;
        ssl_certificate_key /usr/local/etc/dehydrated/certs/%%HOSTNAME%%/privkey.pem;
        ssl_trusted_certificate /usr/local/etc/dehydrated/certs/%%HOSTNAME%%/cert.pem;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_protocols tlsv1.1 tlsv1.2 tlsv1.3;
        ssl_prefer_server_ciphers on;
        ssl_stapling on;
        ssl_stapling_verify on;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;
        add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";
        resolver [2001:4860:4860::8844] [2001:4860:4860::8888] valid=60s ipv6=on;
        resolver_timeout 5s;
    }
```
#nginx の再起動

```text:
# service nginx reload
```
#証明書の有効期限を自動更新
毎週定期的に更新 script を実行させる設定をする。

```text:/etc/periodic.conf.local
weekly_dehydrated_enable="YES"
weekly_dehydrated_flags="--ipv6 --domain %%HOSTNAME%%"
```
証明書の自動更新後、nginx にも伝えてあげないと古い証明書を握ったままなので、デプロイスルクリプトを作成して、nginx の config をリロードさせる。

```text:/usr/local/etc/dehydrated/deploy.sh
#!/bin/sh
/usr/local/sbin/nginx -s reload
```
当然、シェルスクリプトなので、実行権限も与えておくことを忘れないように。

```shell
chmod +x /usr/local/etc/dehydrated/deploy.sh
```
先ほど編集した periodic.conf.local にもこのデプロイスクリプトを指定させておく。

```text:/etc/periodic.conf.local
weekly_dehydrated_deployscript="/usr/local/etc/dehydrated/deploy.sh"
```
おしまい🙌
GitLabのデフォルトブランチの設定とプロテクト

たまにやろうとするといつも迷子になるのでメモに残しておきます。

# デフォルトブランチを設定する

* プロジェクトを選択
* Settings - Repository を選択
* Default Branch で設定

# ブランチをプロテクトする

* プロジェクトを選択
* Settings - Repository を選択
* Protected Branches で設定  
   マージ／プッシュできる権限をそれぞれ選択する(No oneは誰にも許可しない状態）
VirtualBox環境下でのCentOS7ディスク拡張[2018-10]　

*VirtualBoxの最近のバージョンでのVMディスクの拡張方法（2018年10月）*

### 環境：
VirtualBox 5.2.18
CentOS 7.5
※デフォルト最小構成でインストール

### 手順：
#### まずは仮想基盤上での拡張
[*GUIからできるようになっている!!*]

- 対象VM停止

- VirtualBox画面右上のグローバルツール→
ハードディスク→
対象VMのディスク→
プロパティ→
サイズ変更（拡張）→
適用

- 対象VM起動

#### 次にfdiskによるパーティションの拡張


```
# fdisk /dev/sda

コマンド (m でヘルプ): p
Disk /dev/sda: 32.2 GB, 32212254720 bytes, 62914560 sectors

デバイス ブート      始点        終点     ブロック   Id  システム
/dev/sda1   *        2048     2099199     1048576   83  Linux
/dev/sda2         2099200    33554431    15727616   8e  Linux LVM

コマンド (m でヘルプ): d
パーティション番号 (1,2, default 2): 2
Partition 2 is deleted

コマンド (m でヘルプ): n
Partition type:
   p   primary (1 primary, 0 extended, 3 free)
   e   extended

Select (default p): p
パーティション番号 (2-4, default 2):
最初 sector (2099200-62914559, 初期値 2099200):
初期値 2099200 を使います
Last sector, +sectors or +size{K,M,G} (2099200-62914559, 初期値 62914559):
初期値 62914559 を使います
Partition 2 of type Linux and of size 29 GiB is set

コマンド (m でヘルプ): w
パーティションテーブルは変更されました！

ioctl() を呼び出してパーティションテーブルを再読込みします。

WARNING: Re-reading the partition table failed with error 16: デバイスもしくはリソースがビジー状態です.
The kernel still uses the old table. The new table will be used at
the next reboot or after you run partprobe(8) or kpartx(8)
ディスクを同期しています

# reboot
```

#### 最後にLVM拡張

```
# pvresize /dev/sda2
# lvextend -l +100%FREE /dev/centos/root
# xfs_growfs /dev/centos/root
```
以上です。
Unity 覚え書き：マテリアルを削除する

適用したマテリアルを削除してデフォルトの状態に戻したいとき、Inspectorに表示されているマテリアルを削除しようとしても、削除のメニューがなく出来ません。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/234600/32f15208-9af7-b4c8-ee98-d0c46f07429a.png)

#マテリアルの削除手順
##１．Inspectorの「Mesh Renderer」にある「Materials」のElement0を見つける
（マテリアルをクリックしてDeleteキー）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/234600/a8144b6e-2ce5-04d8-7d26-3133984e7c32.png)
##２．右の小さな丸をクリックし、Default-Materialを選択。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/234600/1cf86d09-aead-b7d8-9045-cc7520ceac07.png)

なお、Element0に表示されていたマテリアルをクリック→削除（Deleteキー）すると、デフォルトのマテリアルが自動で適用されるわけではないようで、ピンクの物体になりました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/234600/f3bef37c-f701-b353-dc38-66f85ac57829.png)
開発環境を整える。solidity

### セットアップする

Browser Solidityを使用する

- ネットワークにブラウザでアクセス
- Browser Solidityでネットワークにアクセス


```
geth --networkid 10 --nodiscover --maxpeers 0 --datadir ./ --rpc -rpccorsdomain "*"
---rpc
```

http://localhost:8545
にアクセス


（GethをHTTP-RPCモードで起動するため）


-rpccorsdomainでアクセスを指定。*なので全ドメインを許可


### Browser Solidityのインストールをする
https://github.com/ethereum/browser-solidity/archive/gh-pages.zip


index.htmlを開く



右上のRunボタンを押して
「Environment」→Web3 Providerを選択する。



URLの入力でhttp://localhost:8545
とする。



Gethで立ち上げたローカルプライベートネットに接続完了。



Browser Solidityのプラスアイコンをクリック。


### ファイル作成

HelloWorld.sol

ここに引数で指定した根を出力するプログラムを作成。


```
pragma solidity ^0.4.8;

contract HelloWorld {
    string public greeting;

    function HelloWorld(string _greeting) public {
        greeting = _greeting;
    }

    function setGreeting(string _greeting) public {
        greeting = _greeting;
    }

    function talk() public constant returns (string) {
        return greeting;
    }
}
```

保存。



Browser Solidity上で"Hello World!!"とし、Createボタンを押す。


未処理のトランザクション
デプロイ


→未処理のトランザクションをブロックに取り込む。
→マイニング（実行）


console
```> miner.start()```


talkボタンを押すと、
中央にメッセージが出る。

"Hello World!!"のとこには

```
[call] from:0x870767f7aebcb0670f474769a9d63819b3490b41, to:HelloWorld.talk(), data:a9731...31769, return:
Details
Debug
{
    "0": "string: Hello World!!!"
}
```

続いてsetGreetingの部分に
"Good Morning"とうつ。


変更したらトランザクションの処理が必要。
```> miner.start()```


未処理かどうかを確認。

```
> eth.pendingTransactions
> []
```



ここでtalkボタンを押すと変更してる
「Hello World」→「Good Morning」


```
[call] from:0x870767f7aebcb0670f474769a9d63819b3490b41, to:HelloWorld.talk(), data:a9731...31769, return:
Details
Debug
{
    "0": "string: Good Morning"
}
```