OmniAICreator/Qiita-1.07M huggingface dataset:
初めてkotlinを触る - クラス基礎(1)

# 目次
* 目的
* クラスのコンストラクタ
* 引数取る
* 気になること

----

# 目的

* javaと違うことを紹介
* 気になることを紹介
* kotlinの使うことを進める

----

## コンストラクタ
* プライマリコンストラクタ(一つ)

```kotlin
class Weather(state: String) {  //プライマリコンストラクタ
}
```

* セカンダリコンストラクタ(複数)

```kotlin
class Weather(state: String) {
    constructor(state: String, temperature: Int) : this(state){ //セカンダリコンストラクタ
    }
}
```

----

## コンストラクタ - コンストラクタの引数

```kotlin
class Weather(val state: String) {    
    init {
        println(state)
    }
}

fun main() {
    Weather("cloudy") // cloudy
}
```

----

## コンストラクタ - 引数取る

```kotlin
class Weather(state: String) {
    val newState = state
    
    init {
        println(newState)
    }
}

fun main() {
    Weather("cloudy") // cloudy
}
```

* プライマリコンストラクタは、どんなコードも含めない
* 初期化コードは、initキーワードが付いている初期化ブロック内に書く




----

## 気になること1

### 初期化とセカンダリコンストラクタの順番？

----

```kotlin
class Weather(val state: String) {    
    init {
        println(state)
    }
    
    constructor(state: String, temperature: Int) : this(state){
        println("secondy constructor: " + state)
        println("temperature: " + temperature)
    }
}

fun main() {
    Weather("cloudy") // cloudy
    Weather("sunny", 30) 
    // sunny
    // secondy constructor: sunny
    // temperature: 30
}
```

* 初期化ブロックはプライマリーコンストラクタ、セカンダリーコンストラクタどちらを実行した場合でも実行される
* セカンダリーコンストラクタを実行した場合は、初期化ブロックが実行された後にセカンダリーコンストラクタの処理が実行される


----

## 気になること2

### セカンダリコンストラクタの引数にvalやvarを使えないので、初期化は？

```
constructor(var state: String, level : String) : this(state){
// エラー： var on a second constructor paramter is not allowed
```

----

```kotlin

class Weather(val state: String) {
    private lateinit var newLevel : String
    
    init {
        println(state)
    }
    
    constructor(state: String, level : String) : this(state){
        println("secondy constructor: " + state)
        println("temperature: " + level)
        newLevel = level
    }
    
    fun getTemp() : String {
        println(newLevel)
        return newLevel
    }
}

fun main() {
    Weather("cloudy") // cloudy
    Weather("sunny", "A").getTemp()
    // sunny
    // secondy constructor: sunny
    // temperature: A
    // A
}
```
USB Redirector – a powerful solution for remoting USB Devices

Sharing USB device allows to others automatically access that external device on the same network. This is the best one that helps you mimic all client content and create an exact virtual copy of a shared USB device. The device appears to be directly connected to other computers on the same network. This article will help you organize and distribute your USB storage via a [USB Redirector]( https://www.net-usb.com/usb-redirector/) - a great solution for removing USB devices.

##USB Redirector Client 

A USB redirector is a convenient software for remotely using USB shared devices via LAN, WLAN, or the Internet as if they were connected directly to your computer.

To use this software, install USB Redirector on the main computer. This computer will act as a USB server.

![share on server.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447311/518b22ba-282f-b032-977f-c8ed044147ff.png)


##Over the network, remotely use shared USB

Please note that when sharing a USB device, USB remote clients will be available for personal use. To make the device available locally again, unshare it. When you are finished, install the USB Redirector on a computer that you need to use USB devices remotely. USB client, it will be yours. 

Now they have a direct connection from a USB client to a USB server or a USB client from a USB server.
![device.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447311/28882c7b-57c7-130c-0376-543062135802.jpeg)


Select the desired device from the list of USB on-screen accessories and click the "Connect" button, which you have needed.
![connect device.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447311/09d326fb-4f79-39be-c790-57c9db0269cc.png)

You can now work on an external USB device. The unique feature of USB activation is that the application runs as a background and so you do not need to keep the app open all the time.



When you have designed all the important alternatives, you can securely close it. Moreover, you can add certain USB devices to the ‘Exclusion List’ as an extra measure of precaution, against virus infections. 

You can [download USB Redirector](https://www.net-usb.com/downloads/) for Windows from its home page. It is free when connecting from a Windows computer.
StaticPress S3のスクリプトをAWS SDK for PHP3に対応させて書く

急ですが、EC2上に構築しているWordPressの記事をHTMLに変換してS3のバケットに送るということをやりたくなりました。
StaticPressとStaticPress S3を試したのですが、ファイルをS3に送るところだけ別でいろいろとしたいなぁ、と考えました。
（この記事に載せるには「いろいろ」は大人の事情でかけません…。なので、バージョン上げた部分だけ書きます）

ファイルをS3に送信するスクリプトは「StaticPress S3」のドキュメントにて公開されていました。
http://ja.staticpress.net/2013/06/11/69/
現在は2019年なので、内容が古いです。
AWS SDK for PHPのバージョンが2の時の内容ですね。

現在はAWS SDK for PHPはバージョン3になってます。
https://aws.amazon.com/jp/sdk-for-php/
なので、このスクリプトを3を使って書き直してみました。
PHP7.3
AWS SDK for PHPはpharで落としてきて読み込んでいます。

```
<?php
require_once('aws.phar');
use Aws\S3\S3Client;  
use Aws\Exception\AwsException;
use Aws\Credentials\Credentials;

$key = 'Your Access Key';
$secret = 'Your Secret Key';
$region = 'ap-northeast-1';	
$bucket = 'bucket_name';
$dir = '/var/www/html/fugafuga/';

/**
 * 指定されたディレクトリのファイル一覧を取得
 */
function get_dir_file_list($dir)
{
	$check_dirs = [$dir];
	$file_paths = [];
	$file_name = [];

	while( $check_dirs ) 
	{
		$dir_path = $check_dirs[0] ;

		if( is_dir ( $dir_path ) && $handle = opendir ( $dir_path ) ) 
		{
			while( ( $file = readdir ( $handle ) ) !== false ) 
			{
				if( in_array ( $file, [ ".", ".." ] ) !== false ) 
				{
					continue;
				} 

				$path = rtrim ( $dir_path, "/" ) . "/" . $file ;

				if ( filetype ( $path ) === "dir" ) 
				{
					$check_dirs[] = $path ;
				} 
				else 
				{
					$file_name[] = $path;
				}
			}
		}
		array_shift( $check_dirs ) ;
	}

	return $file_name;
}

/**
 * ここから実際の処理
 */
try 
{
	$credentials = new Credentials($key, $secret);
	// Create a S3Client
	$s3Client = new S3Client([
		'region' => $region,
		'version' => 'latest',
		'credentials' => $credentials,
	]);

    $files = get_dir_file_list($dir);
    $info = new Finfo(FILEINFO_MIME_TYPE);
    foreach ($files as $filename) 
    {
    	$filetype = $info->file($filename);
    	$filebody = fopen($filename, 'r');
        if ( $filetype == 'text/plain') 
        {
    		if (preg_match('/\.css$/i', $filename)) 
    		{
                $filetype = 'text/css';
    		} 
    		else if(preg_match('/\.js$/i', $filename)) 
    		{
                $filetype = 'application/x-javascript';
    		} 
    		else if(preg_match('/\.html?$/i', $filename)) 
    		{
                $filetype = 'text/html';
    		}
    		else if(preg_match('/\.xml$/i', $filename)) 
    		{
                $filetype = 'application/xml';
    		}
    	}

		echo $filetype . ':' . str_replace($dir, '', $filename) . "\n";

		$response = $s3Client->putObject([
			'Bucket' => $bucket,
			'Key' => str_replace($dir, '', $filename),
			'Body' => $filebody,
            'ContentType' => $filetype,
//			'StorageClass' => 'STANDARD',
// 			'ACL' => 'public-read',
		]);

    }
} catch(S3Exception $e) {
	echo $e->getMessage();
}
```

ディレクトリ下のファイルを取得する関数を書き直しました。
拡張子である程度しぼって取得するほうがよかったかもなぁ、とも思います。ContentTypeも決めているので…。

コメントにしてあるStorageClassとACLは必須パラメータではないです。

APIドキュメントはこちらを。
https://docs.aws.amazon.com/aws-sdk-php/v3/api/index.html
初めてkotlinを触る - クラス基礎(2)

## 目次
* ゲッターとセッター
    * 宣言
    * カスタムとバッキングフィールド

* 継承
    * プライマリコンストラクタ
    * セカンダリコンストラクタ
    * メンバのオーバーライド
    * プロパティのオーバーライド

----

# ゲッターとセッター


----

## 宣言

```kotlin
var <propertyName>: <PropertyType> [= <property_initializer>]
  [<getter>]
  [<setter>]
```
* 完全な構文
* イニシャライザ、ゲッターとセッターは必須ではない

----

## 宣言 - デフォルトでゲッターとセッター

```kotlin
class Car(p: Int) {
    var init: Int
    init {
        init = p
    }
}

fun main() {
    var car = Car(4)
    println(car.init) // 4
    car.init = 2
    println(car.init) // 2
}
```

----

## 宣言 - 読み取り専用

```kotlin

class Car(p: Int) {
    val init = 1
}


fun main() {
    var car = Car(4)
    println(car.init)
    car.init = 2 // error: can not be reassigned
}
```

* varの代わりにval(バルキーワード) 
* セッターが使えない




----

## カスタムとバッキングフィールド

```kotlin
class Ben(q: Int) {
    var init = 1
      set(value) {
          field = value + 10
      }
}

fun main() {
    var ben = Ben(4)
    ben.init = 2
    println(ben.init) // 12
}
```

* カスタムでゲッターとセッターを実装できる
* Kotlinは自動バッキングフィールドを提供する



----

# 継承

----

## openアノテーション
* クラスの open アノテーションは、Javaの final と反対
* openをつけているクラスは、その他のクラスがこのクラスから継承することができる
* デフォルトでは、Kotlinのすべてのクラスはfinalである

----

## プライマリコンストラクタ

```kotlin
open class Base(p: Int)
class Car(p: Int) : Base(p)
```

* javaと違いは、明示的にベースクラスをプライマリコンストラクタの引数を使用して初期化する
* openをつけないと、エラーが発生
    * ![スクリーンショット 2019-08-20 20.13.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13451/cbcc631e-3b62-0490-6e40-f8cfbb5278d1.png)

----

## セカンダリコンストラクタ

```kotlin

open class Base(p: Int) {
    constructor(p: Int, q: String): this(p){}
}
class Car: Base {
    constructor(p: Int): super(p){}
    constructor(p: Int, q: String): super(p, q){}
}

fun main() {
    var car1 = Car(4)
	var car2 = Car(4,"a") 
}
```

* セカンダリコンストラクタで継承する時に、superを使って初期化できる


----

## メンバーのオーバーライド

```kotlin

open class Base(p: Int) {
    open fun v(){}
    fun w(){}
}
class Car(p: Int) : Base(p) {
    override fun v(){}
}
```

* ファイナルクラス（例えば、 open アノテーションを持たないクラス）の中では、openメンバは禁止されている
* openメンバーを指定してサブクラス内でオーバライドできる
* override としてマークされているメンバは、それ自身がopen



----

## プロパティのオーバライド


```kotlin
open class Base {
    open val x: Int = 1
}

class Car : Base {
    override val x: Int = 2
    constructor(){}
}

fun main() {
    var base = Base()
    println(base.x) // 1
    var car = Car()
    println(car.x) //2
}
```
突然AppDelegateでsignal SIGBRT(& terminating with uncaught exception of type NSException & First throw call stack)[Swift][実機]

# 概要
今まで実行できてたプロジェクトが再起動とかした途端
`AppDelegate`で`signal SIGBRT`と

```
*** First throw call stack:
...
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
```
が出てしまってクラッシュになってしまった
ググって出てきた
・xcodeを再起動
・Build FolderをClean
・Derived Dataを削除
をすべてやったもののうまくいかず
#### 参考
**・[IBDesignableのRending Errorで困り果てたので状況別の解決策[Swift] - Qiita](https://qiita.com/jbnkk40/items/1e875b21fa9616b7c3aa)**

# 対策
思いつきで実機で**インストールされてたプロジェクトのアプリを消してもう一度やってみた**ところ実行できた

# 原因
詳細はわからんのですが
再起動してから実行したプロジェクトはバージョンがそれまでと変わっており
・実機側ではそれまでとは別で新しくアプリがインストールされていた
・xcodeのバグでうまくいかなかった状態のものが実機側に残っている
・**#概要**でやった対策が実機のアプリ側で反映されず、ただ起動し直した感じになってしまった？

というようなことが原因かなと考えました
もしわかる方いればご意見ください
Zoho Mail ではフィルターに Deluge カスタム関数を指定できる

(初出: 2019-07-11 "Zoho Mail supports custom functions to filter emails" を改題)

[Filter – Custom DRE Functions](https://www.zoho.com/mail/help/custom-functions.html)

そう、 Zoho Mail はマイナーだが強力なのだ。Web ベースのメールホスティングサービスでフィルターにカスタム関数を設定できるものは他に寡聞にして知らない。メールを適当に編集して ClickSend で SMS へ飛ばすカスタム関数は、次のように書ける。

```c
// 到着したメールを取得
msg = zoho.mail.getMessage(mail_messageId);
body = msg.get("CONTENT");
subject = msg.get("SUBJECT");
from = msg.get("FROM");
// 適当に編集
subject = subject.replaceAll(...,...);
subject = subject.left(mailSubject.length().min(21));
body = body.replaceFirst(...,...);
body = body.left(mailContent.length().min(60));
// ClickSend 経由で SMS 送信
sendmail
[
	from: zoho.loginuserid
	to: "81**********@sms.clicksend.com"
	subject: "auth~USERNAME~UUIDUUID-UUID-UUID-UUID-UUIDUUIDUUID~" + subject + "~CALLERID"
	message: body
]
```

カスタム関数は Zoho Creator の機能を流用しているのだろうから、契約によっても利用の可否が異なるのかもしれない。私の契約は Zoho Workplace である。
Slackのチャンネル名が最大80文字に拡張された

### 今までの問題点
コミュニケーションツールとして便利な[Slack](https://slack.com/intl/ja-jp/)
障害対応などで、とりあえず気軽に使い捨て前提でチャンネルを作ることがあると思います。
しかし、今までは最大21文字しか使うことができませんでした。

これにより、日付つきでチャンネルを作成したいといったときに
例えば`日付+サービス名+状況` などを記載するとあっという間に21字に達することがあります。

```
% echo 20190822-service-warning | wc -m
      25
```

この名前でも21文字を超えてしまいます。

### Get specific with longer channel names
2019年8月21日の[slackのブログ](https://slackhq.com/)の記事より。

[In case you missed it: New tools for announcements, search, calls and more \| The Official Slack Blog](https://slackhq.com/new-slack-features-search-calls-channels?utm_medium=in-prod&utm_source=in-prod&utm_campaign=cd_in-prod_in-prod_all__all_cr-whatsnew_ym-201908)

```
If Game of Thrones can have more than 21 characters, then so can our channels. We’re extending the maximum length of channel names—from 21 to a whopping 80 characters
```

今までこの文字数制限で困ったことがあたっと人もいると思いますが、
思う存分長いチャンネル名を作ることができますね。
実際に試したところ入力が可能でした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20303/d18f4d7e-d765-1ad0-3e72-7975fc06a919.png)

25文字入力しましたが残り56文字まで打てる状態ですね。

Slack APIを用いて自動的にチャンネル名をつけるときにこの制限をあまり気にしなくなったのはうれしい改善だと思います。
PhpStormでCRLF/LF/CRを切り替える

##改行コード 「CRLF」「LF」「CR」の違い。

###CR（Carriage Return　キャリッジリターン）
カーソルを左端の位置に戻すこと

###LF（Line Feed　ラインフィード）
カーソルを新しい行に移動すること

##CRLF 
CRとLFを組み合わせたもの。左端にカーソルを戻して改行する。

##  PhpStormでのCRLF/LF/CR切替方法
PhpStorm右下のCRLFをクリックで切替可能

![CRLF.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109300/77295888-8574-a1cc-3c7c-0a1d1fb301db.gif)

## 備忘録
PhpStorm上でシェルスクリプトを書くとき、CRLFだと改行が入りシェルが実行されないので、LFに変えてから書きましょう。

## 参考URL
備忘録：改行コード「LF」と「CR」と「CRLF」の違い
https://marusunrise2.blogspot.com/2014/06/lfcrcrlf.html
github apiでブランチの作成と削除を行う

バッチ処理の途中にブランチを作成したり削除したりしたくなった時はAPIでできます。

## 準備

githubのpersonal access tokenが必要です。（作成方法は割愛）

## ブランチ削除

削除は簡単です。

```
curl -s -X DELETE -u [user]:[token] https://api.github.com/repos/[owner]/[repo]/git/refs/heads/[branch]
```

例えば `nysalor/foo_proj` の `feature/bar` を削除するなら

```
curl -s -X DELETE -u [user]:[token] https://api.github.com/repos/nysalor/foo_proj/git/refs/heads/feature/bar
```

## ブランチ作成

作成はちょっと複雑で二段階になります。

### SHA取得

まず作成元のブランチのSHAを得ます。（この例ではmasterから作成します）

```
curl -s -u [user]:[token] https://api.github.com/repos/[owner]/[repo]/git/refs/heads/master
```

jsonでオブジェクトの情報が返るのでSHAを切り出します。

```
{
  "ref": "refs/heads/master",
  "node_id": "xxxx==",
  "url": "https://api.github.com/repos/[owner]/[repo]/git/refs/heads/master",
  "object": {
    "sha": "xxxx",
    "type": "commit",
    "url": "https://api.github.com/repos/[owner]/[repo]/git/commits/xxxx"
  }
}
```

なお、`jq`を使えば一発でSHAを切り出せます。

```
SHA=$(curl -s -u [user]:[token] https://api.github.com/repos/[owner]/[repo]/git/refs/heads/master | jq -r .object.sha)
```

### ブランチ作成

SHAからブランチを作成します。

```
curl -s -X POST -u [user]:[token] -H "Content-Type: application/json" -d '{"ref": "refs/heads/[branch]", "sha": "'[上記で得たSHA]'"}'  https://api.github.com/repos/[owner]/[repo]/git/refs
```

例えばS `nysalor/foo_proj` のmasterから `feature/bar` を作成するなら

```
SHA=$(curl -s -u [user]:[token] https://api.github.com/repos/nysalor/foo_proj/git/refs/heads/master | jq -r .object.sha)
curl -s -X POST -u [user]:[token] -H "Content-Type: application/json" -d '{"ref": "refs/heads/feature/bar", "sha": "'$SHA'"}'  https://api.github.com/repos/nysalor/foo_proj/git/refs
```
indexの配列を用いてpython辞書型やpandas.Dataframeから値を取得する

# はじめに

やりたいことはタイトルの通り．
indexの配列があり，辞書やテーブルを参照して同じサイズのvalue配列を獲得したい．

# やりかたはいろいろ

同様の課題がstackoverflowに存在した．そのうち，[stackoverflowの回答](https://stackoverflow.com/a/34452268)で，リスト内包以外にもoperator，map関数などが比較されている．
indexの配列を直接代入するような短いコードでできそうかなと思ったが，そういった簡単な方法は見つからなかった．まあ回答の方法でスピードや可読性は十分ではある．

本記事では，リスト内包を用いた方法を中心にまとめる．

# 辞書型

indexの配列は2次元とした．
Jupyter notebookにて，%timeitで時間計測を行った．

```py:
import numpy as np

# 1-1000までのindexがランダムに入った1000 x 1000の配列
inds = np.random.randint(1,1001, (1000,1000))
# indexからvalueを得るための辞書
test_dict = { x: np.random.rand() for x in range(1,1001) }

# 手法1：一度numpyを平らにして一重リスト内包
%timeit np.array([test_dict[_] for _ in inds.flatten() ]).reshape(1000,1000)
# 手法2：numpy配列のまま二重リスト内包
%timeit np.array([test_dict[_] for __ in inds for _ in __]).reshape(1000,1000)
# 手法3：numpy配列をリストに変換してから二重リスト内包
%timeit np.array([test_dict[_] for __ in inds.tolist() for _ in __]).reshape(1000,1000)
'''結果：
514 ms ± 92.4 ms per loop (手法1)
468 ms ± 51   ms per loop (手法2)
229 ms ± 19.1 ms per loop (手法3)
'''
```

いずれのやり方もリスト内包で1次元の出力を得てから，reshapeしてもとの配列と同じ形にしている．`tolist()`を用いてリストに変換してからのほうが2倍以上速度が向上した（同様の事例は調べるといろいろ出てくる）．

# pandas

pandasでは，値を取得するためにいくつかのメソッドのが存在する．
こちらもstackoverflowなどで速度について議論がなされており，[この回答](https://stackoverflow.com/a/37761363)ではメソッドごとの速度比較を行っている．
早い順に，`iat`>`at`>`iloc`>`loc`となっているよう．

本記事でも，このうちいくつかの比較を行ってみた．

```py:
import pandas as pd

# 1-1000までのindexがランダムに入った1000 x 1000の配列
inds = np.random.randint(1,1001, (1000,1000))
# indexからvalueを得るためのpandasテーブル
test_df = pd.DataFrame({ 'INDEX': range(1,1001), 'VALUE': np.random.rand(1000) }).set_index(['INDEX'])

# 手法1：locを使用する
%timeit np.array([test_df.loc[_,'VALUE'] for __ in inds for _ in __]).reshape(1000,1000)
# 手法2：atを使用する
%timeit np.array([test_df.at[_,'VALUE'] for __ in inds for _ in __]).reshape(1000,1000)
# 手法3：iatを使用する
ind_dict = { _:i  for i,_ in enumerate(test_df.index) }
%timeit np.array([test_df.iat[ind_dict[_],0] for __ in inds for _ in __]).reshape(1000,1000)
'''結果：
13.1 s ± 211 ms per loop (手法1)
9.95 s ± 604 ms per loop (手法2)
12.3 s ± 290 ms per loop (手法3)
'''
```

うーん，辞書と比べてしまうとちょっと遅い．．．
この例では`at`を用いる方法が最も早かった．`iat`を用いるために，行番号とindexの値とを結びつけるという強引なことをやってみたが，大幅な速度改善とまでは至らなかった．

# おわりに

辞書型のほうが相当早いので，pandasテーブルを所得後，辞書型に変換して処理を行うのがよさそう．

```py:
new_dict = test_df['VALUE'].to_dict()
```

これ以上は並列計算とかCythonとかに譲るしかないかもしれない．
Vuetifyのv-text-fieldからメソッドへidを送る方法

最近Vue+Vuexはじめました。

いきなり本題ですが、下記のようにv-text-fieldの変更を@changeからメソッドに引き渡し、
idと変更内容を受け取ろうとしてみました。こんな感じで。

```vue
          <v-text-field
            id="text1"
            label="テキスト"
            @change="updateField($event)"
          ></v-text-field>
```

```vue
  methods: {
      updateField(e){
        console.log(e.target.id,e.target.value)
      },
}
```

が、、動かないな？？？なんでかな？？
とりあえずinputは動くからinputで受けるか、、、
inputの戻り値はstringで入力した内容だけなので、第2に手動でidを指定してと、、、

```vue
          <v-text-field
            id="text1"
            label="テキスト"
            @input="updateField($event,'text1')"
          ></v-text-field>
```

```vue
  methods: {
      updateField(e,_id){
        console.log(e,_id)
      },
}
```

結果
```
[変更内容] undefined
```

なんでや！！！

こうしてみたら・・・？

```vue
          <v-text-field
            id="text1"
            label="テキスト"
            @input="updateField([$event,'text1'])"
          ></v-text-field>
```

```vue
  methods: {
      updateField(e){
        console.log(e)
      },
}
```

結果
```
(2) ["[変更内容]", "text1"] 
```

ヤレバデキルジャン☺️ 

しかしなぜ@changeが効かないのか・・・。
あんまりこのやり方もスマートではないので解決策が欲しいところ。

ちなみに、

```vue
updateField({id:'text1',value:$event})
```

とオブジェクトでこんなふうにも渡せます。こっちのが一般的か。
Linux + Ubuntu + Django + Apache

#Linux종류
##ubuntu
- 데비안계열
- 설치간단
- 초심자용

##CentOS
- 유료 리눅스인 레드햇을 상표권만 제거
- 안정적이고 레드햇의 기술을 무료로 사용할 수 있다.

#ubuntu + Django + Apache2 + mod_Wsgi 설치
##1. ubuntu
- LTS(Long Term Service) : 지원기간 5년, 다른버전은 6～9개월마다 업그레드 권장
- [Desktop 버전 다운](https://ubuntu.com/download/desktop)
- iso 파일을 DVD로 구워 설치 > 윈도우 기본 기능으로 컨버팅

##2. django
- 파이썬으로 만들어진 무료 오픈소스 웹 애플리케이션 프레임워크

- Linux에 기본탑제

```python:qiita.rb
# 버전확인
$ python3 --version
Python 3.6.1

# 버전선택설치
$ sudo apt install python3.6
```
- 에디터 설치
    - [Atom](https://atom.io/)

- 장고설치하기
    - 1. 가상환경(Virtual environment)

```python:qiita.rb
# home 디렉토리 아래 작업폴더생성
$ mkdir djangogirls
$ cd djangogirls

# myenv 라는 이름의 가상환경 만들기
$ python3 -m venv myvenv

# 가상환경 실행
$ source myvenv/bin/activate
```
##2.1. ダウンロード
Strapi + Heroku でヘッドレス CMS 環境を 5 分で構築する

Node.js ベースのオープンソースヘッドレス CMS「[Strapi](https://strapi.io/)」を、Heroku にサクっと構築する方法です。
REST だけでなく GraphQL API も作成してくます。

**下書き状態で放置したままだったので公開しましたが、
GraphQL を使えるヘッドレス CMS を使いたい場合は、[Graph CMS](https://graphcms.com/) がオススメです！**

## 1. アプリの作成

Heroku の [Strapi アプリ作成ページ](https://dashboard.heroku.com/new?button-url=https%3A%2F%2Fblog.strapi.io%2Fdeploying-a-strapi-api-on-heroku%2F&template=https%3A%2F%2Fgithub.com%2Fstrapi%2Fstrapi-heroku-app) から、Strapi アプリを作成します。[App name] に適当な名前を入力し、[Deploy App] ボタンをクリックします。

なお、データベースには Strapi が推奨する MongoDB が使用されます。 
（最新版では sqlite がデフォルトになったようですが）
<img width="707" alt="スクリーンショット 2019-02-24 17.43.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/37412/985c6703-c030-ebdb-6f76-841e51015028.png">


## 2. 完成

ほどなくして環境が構築されます。:sunglasses:
アドミン画面 (/admin) にアクセスし、管理者を作成します。
<img width="461" alt="スクリーンショット 2019-02-24 18.25.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/37412/477beecb-487b-3fac-3440-a1348ae57f39.png">

## Enjoy!

拍子抜けするくらい簡単にヘッドレス CMS 環境が構築できてしまいました。
Strapi については、後述の参考を参照ください。

#### ロールと権限

メニューの「ロールと権限」から、登録した Post を API から取得できるようにしておきましょう。
これで　`/posts/` ですべての記事が取得できるはずです。
<img width="875" alt="スクリーンショット 2019-02-24 18.52.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/37412/49c2fbdf-b615-25a0-948b-1eebda929e46.png">

#### GraphQL API

Strapi の GraphQL プラグインがインストールされているため、GraphQL API も使えます。



## 参考

- [Deploying a Strapi API on Heroku](https://blog.strapi.io/deploying-a-strapi-api-on-heroku/)
- [Quick start | Strapi Documentation](https://strapi.io/documentation/3.x.x/getting-started/quick-start.html)
- [Headless CMSと静的サイトジェネレータ「Gatsby」を使ったサイトの構築](https://qiita.com/prograti/items/6497621015481487d7fb)
[Bookmarklet] ページ上のチェックボックスを全部ONにする

1ページ内のチェックボックスの数が多いと全部ONにするのが大変。
ということで、ページ内のすべてのチェックボックスをONにするBookmarkletを作りました。

## 対応している要素・タイプ
```
- input
    - checkbox
```

## 使い方

1. ブラウザを起動する(Chromeのみ動作確認済み)
2. ブックマークマネージャーを起動する
3. 新しいブックマークを作成で以下を入力し保存する  
・ ブックマーク名: 任意のもの  
・ URL: 下記のコード
4. 使いたいWebページを開き、Step.3のブックマークをクリックする

## ソースコード
```js

javascript:
(function(){
    var elements = document.querySelectorAll('input');
    for(var i = 0; i < elements.length; i++){
        if( elements[i].type == 'checkbox' ){
            elements[i].checked = true;
        }
    }
}())
```
※ 全部OFFにしたい場合は、
`elements[i].checked = true;`を`elements[i].checked = false;`とすればできます。  


## 参考
[\<input type="checkbox"\>－HTML5タグリファレンス](http://www.htmq.com/html5/input_type_checkbox.shtml)
Jinja (Flask/SQLAlchemy) で日付をフォーマットする

#Jinjaでstrftime()が使える

Flask/SQLAlchemy 使ってる方、jinja で困ってませんか？

>括弧の進化ってのがあります。

>インデントで省略するのが Python 式「粋」な現代風の書き方であるとすると、括弧()[]{}が古風な書き方ですね。

>そうすると閉じ括弧で endfor など書くのは時代への逆行（反逆の精神）ですね。

本体で Python の関数を書いてもいいんですが、テンプレートでも関数が呼べます。

>伝統＋悪習だけで使い続けているだけの旧式なプログラム言語の使用を正当化するなよ。

>世界のプログラマは別の方向へ向かっている。

>「連盟よさらば」ってのは、つまり世界の味方ではないってこと

日付を出したい場合、フォーマットなら strftime() が使えます。

```Jinja
{% if blog.date_posted %}
    {{ blog.date_posted.strftime('%b %d, %Y') }}
{% endif %}
```

わざわざ文字列を作って渡す必要はありません。

上記のコードであれば出力結果は`Aug 20,2019`（米国式）です。

（マルチポストです。）
[Jinja (Flask/SQLAlchemy) で日付をフォーマットする]("https://easaiwindows.blogspot.com/2019/08/jinja-flasksqlalchemy.html" "Jinja (Flask/SQLAlchemy) で日付をフォーマットする")
グループポリシーのリンク全解除

`Default Domain Policy` と `Default Domain Controllers Policy` 以外のポリシーを全OUから取り払います。

```
Get-ADOrganizationalUnit -Filter 'Name -like "*"'| %{Get-GPInheritance -target $_} | %{$_.gpolinks}   | ?{$_.DisplayName -notmatch "Default Domain Policy|Default Domain Controllers Policy"} | %{Remove-GPLink -Guid $_.gpoid -Target $_.target}
```
Docker Network メモ

クソメモです。
ある程度情報そろったらきれいにします。。。


## 参考
https://tech.uzabase.com/entry/2017/08/07/172411
https://tech.uzabase.com/entry/2017/08/23/175813
https://docs.docker.com/network/overlay/
https://docs.docker.com/network/network-tutorial-overlay/

# Docker マルチホストネットワーク

## 1. Docker Swarm mode (swarm service network?)

[メモ]
古いバージョンのSwarmだとこの機能を使用するため、分散KVS(etcd,consul,zookeper)が必要であったが、新しめのバージョンではDockerに機能が組み込まれているため、不要になった
　-> いつのバージョンから??

SwarmにてOverlay Networkを利用することでコンテナのマルチホスト間通信を実現する


### Breakdown

#### overlay Networkにて使用されるポート

* TCP 2377 -> クラスタ管理通信
* TCP/UDP 7946 -> ノード間通信
* UDP 4789 -> overlay Network通信

#### セキュリティ
管理用通信はすべてAESにより暗号化されている

overlay network作成時に"--opt encrypted"オプションを付与してあげることでアプリケーション通信(overlay Network通信?)もIPSECにより暗号化される。(Dockerノード間でIPSECトンネリング)
IPSECも結局AESアルゴリズムにより暗号化されている
　-> ネットワークパフォーマンスに影響する可能性があるため、テストはマスト

おまけ: encryptedしているoverlay networkはwindowsに対応していない

docker swarmを初期構築およびworkerとしてswarmに追加した際に以下のネットワークが作成される

- ingress 
    - swarmの管理用トラフィックの送受信用
    - swarm serviceを構築時、ネットワークを選択しない場合はデフォルトでこれに接続される
- docker_gwbridge
    - Swarmに関係する個々のdockerデーモン同士が通信する際に利用する
    - ingressをdockerホストのIFに接続する
    - これによりswarm manager/worker間の通信が可能?

overlay networkはserviceにて要求されたタイミングで自動で作成される
-> managerだけで定義すればOK


#### Control traffic と Data trafficを分割
swarmに登録する際に --advertise-addrおよび--datapath-addrを分ける


## 2. Overalay Network　構築ツールを使う

flannel -> もともとk8sにてマルチホストネットワークを実現する機能だった

# 3. 手動で構築

分散KVSとdocker network create -d overlay コマンドを使って構築する

# Tutorial


```text:manager
# docker network create --driver=overlay --attachable test-net
wpwhkxk5ovxfheq0z37fi6t0p
```

```text:manager
# docker run -it --name alpine1 --network test-net alpine
```

```text:worker1
# docker network ls
managerで作成したnetworkは表示されない

# docker run -dit --name alpine2 --network test-net alpine

# docker network ls
managerで作成したnetworkが表示される
```

```text:manager
# ping alpine2
PING alpine2 (10.0.3.10): 56 data bytes
64 bytes from 10.0.3.10: seq=0 ttl=64 time=0.679 ms
64 bytes from 10.0.3.10: seq=1 ttl=64 time=0.408 ms
```
スキーマバージョンをPowershellで取得

## Powershellで実行
```
Get-ADObject (Get-ADRootDSE).schemaNamingContext -Property objectVersion | Select-Object -Property objectVersion
```
## バージョン対応表

| OS                     | スキーマ バージョン |
|------------------------|---------------------|
| Windows 2000 Server    | 13                  |
| Windows Server 2003    | 30                  |
| Windows Server 2003 R2 | 31                  |
| Windows Server 2008    | 44                  |
| Windows Server 2008 R2 | 47                  |
| Windows Server 2012    | 56                  |
| Windows Server 2012 R2 | 69                  |
| Windows Server 2016    | 87                  |
| Windows Server 2019    | 88                  |
各種クラウド FaaS (Function as a Service) 実行環境 (プログラミング言語とバージョン) まとめ (2019年8月22日現在)

## 概要
- AWS Lambda, Microsoft Azure Functions, Google Cloud Functions, Cloud Functions for Firebase, IBM Cloud Functions について実行環境 (プログラミング言語とバージョン) の情報をまとめる

## AWS Lambda (Amazon Web Services: AWS)
- [AWS Lambda ランタイム \- AWS Lambda](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-runtimes.html)
- 使用可能な言語とバージョン(2019年8月22日現在): Node.js 10.15, Node.js 8.10, Python 3.6, Python 3.7, Python 2.7, Ruby 2.5, Java 8, Go 1.x, .NET Core 2.1 (C#, PowerShell Core 6.0), .NET Core 1.0 (C#)

## Microsoft Azure Functions (Microsoft Azure)
- [Azure Functions でサポートされている言語 \| Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/azure-functions/supported-languages)
- Azure Functions ランタイム 2.x で使用可能な言語とバージョン(2019年8月22日現在): .NET Core 2.2 (C#), Node.js 8, Node.js 10, .NET Core 2.2 (F#), Java 8, PowerShell Core 6, Python 3.6, TypeScript

## Google Cloud Functions (Google Cloud Platform: GCP)
- [Cloud Functions Execution Environment  \|  Cloud Functions Documentation  \|  Google Cloud](https://cloud.google.com/functions/docs/concepts/exec?hl=ja)
- 使用可能な言語とバージョン(非推奨ランタイムは含まず。2019年8月22日現在): Node.js 8.15.0, Node.js 10.15.3, Python 3.7.1, Go 1.11.6

## Cloud Functions for Firebase (Firebase)
- [関数のデプロイとランタイム オプションを管理する  \|  Firebase](https://firebase.google.com/docs/functions/manage-functions)
- 使用可能な言語とバージョン(2019年8月22日現在): Node.js 8, Node.js 10

## IBM Cloud Functions (IBM Cloud)
- [ランタイム](https://cloud.ibm.com/docs/openwhisk?topic=cloud-functions-runtimes)
- 使用可能な言語とバージョン(非推奨ランタイムは含まず。2019年8月22日現在): Node.js 8.15.0, Node.js 10.15.0, Python 2.7.15, Python 3.6.8, Python 3.7.2, Swift 4.2, PHP 7.3, Go 1.11, Java 8, Ruby 2.5, .NET Core 2.2
TypeScriptの型推論と文字列固定値

# TypeScriptの型推論と文字列固定値
ちょっと引っかかったので備忘も兼ねて。

## 起こった事象
文字列固定値を持つ型に別に作ったオブジェクトを代入しようとしたら型が合わないと怒られました。
具体的には以下のような感じです。(実際にはもっとプロパティや階層構造がありましたが関連するところだけ簡略化。)

``` typescript
interface Fuga {
 key:'FUGA'
}
let f:Fuga = { //当然これはOK
  key:'FUGA'
};
let f1 = {
  key:'FUGA'
};
let f2:Fuga = f1;//型が合わないと怒られる
```

判別共用体のタグを含むオブジェクトを作ろうとして引っかかりました。


## 原因
f1に代入した時点で、f1の型が'{key:string}'と推論されてしまうため。
f2に代入するタイミングでは、コンパイラは実際の値ではなく``string型のkeyというpropertyを持つオブジェクト``という推論されたf1の型を基に確認するので、Fuga型と合わないと判断する。

よくよく考えれば当たり前なんですが。

## 対応策

### 代入前に型推論に頼らない

``` typescript
let f1:Fuga = {
  key:'FUGA'
};
let f2:Fuga = f1;//FugaをFugaに入れるので当然問題ない
```

### 推論して欲しくない項目に型注釈をつける
``` typescript
let f1 = {
  key:'FUGA' as 'FUGA' // as 'FUGA'によりkeyの型は'FUGA'として扱われる　
};
let f2:Fuga = f1;//f1.keyの型がstringではなく'FUGA'なのでOK
```

## まとめ
* 型推論に任せる場合でもどのように推論されるか想定することは必要
* 特定の項目だけ推論させたくない場合は型注釈を使う
JobSchedulerでのジョブ監視機能－１　　概要説明編

# JobSchedulerについて
JobSchedulerは、オープンソースのジョブ管理ツールです。
ドイツの企業「Software-und Organisations-Service GmbH (SOS社)」が開発を行なっています。
Linux/Windows版はGPLのもと、無償で使用することができます。

ジョブ定義は全てXML形式のテキストファイルであり、ジョブの中で、Java, Perl, JavaScript, VBScript, Powershell, javax.scriptの内部APIを使ったロジックを記述可能です。
外部APIによりRESTまたはコマンドラインからジョブの実行制御、実行状況の取得が可能です。 

JobSchedulerの詳細は以下をご確認ください。
SOS社：https://www.sos-berlin.com/
ナレッジ：https://kb.sos-berlin.com/display/PKB/Product+Knowledge+Base+Home
OSSラボ：https://www.ossl.co.jp/

# Monitoring Interfaceについて
Monitoring Interfaceは、ジョブ、ジョブチェーン、オーダ等を監視し、Nagios、Zabbixなどの監視システムにエラー通知等を行います。
この機能は、V.1.8以降で使用できますが、本記事ではV.1.12.xでの機能を説明します。

# 仕組み
1. JobSchedulerより実行されるジョブ、ジョブチェーンのタスク、オーダ実行履歴は、Historyテーブルに記録されます。
2. Historyテーブルのログ情報を監視対象のジョブ、ジョブチェーンでフィルタリングし、分析を行います。
3. ジョブ実行が正常に終了したか、もしくはエラーや警告で終了したかを分析します。
4. このジョブの情報をHistoryテーブルとは別のNotificationsテーブルに書き込み、監視システムへ通知を行います。


# 使用する利点
・Monitoring Interfaceの実装：
　既存のジョブ、ジョブチェーン等を編集する必要はなく、SystemMonitorNotification_\<MonitorSystem\>.xmlに通知を行うジョブ、ジョブチェーンの設定を行います。

・監視機能：
　アーキテクチャ全体がJobScheduler側にあるため、ジョブ監視の通知の送信先の監視システムに依存しません。

・ワークロードに依存しない：
　ジョブ監視設定を行っても 他のジョブ、ジョブチェーンのパフォーマンス等の影響はありません。

・明確に定義された情報フロー：
　監視対象のジョブ、ジョブチェーンから詳細なログ情報を、監視システムへ送信することができます。
　また、エラーは定期的に監視システムに送信されます。

# 提供機能

・Job Chain and Order Monitoring
　ジョブチェーンをトリガーするオーダーによってジョブチェーンを監視できます。

・History Notifications
　ジョブのエラー通知を監視できるだけでなく、ジョブの成功通知も監視できます。
　実行されてたジョブがどのような結果、どのようなステータスで終了したかなど具体的に履歴として残るため、ジョブの実行結果に応じた通知設定を行うことができます。

・Performance measurement (Timer)
　ジョブ・ジョブチェーンの遅延監視を行います。
　ジョブチェーンの完了時に事前に定義された時間以上かかる場合、監視システムに警告アラートを送信できます。

・Acknowledgment
　「Acknowledge」操作を行える監視システムの場合、監視システムよりResetNotificationsを行う外部スクリプトを実行することができます。
　この外部スクリプトを実行することにより、JobSchedulerはResetNotificationsのジョブを実行します。
　ResetNotificationsのジョブを実行することにより、 JobSchedulerはすでに発生したジョブのエラーや警告等の通知を再度監視システムへの送信を行わなくします。

# 監視システムへの送信メッセージ内容
監視システムへ送信するメッセージは監視ジョブのパラメータを設定できます。
例えば監視システムがZabbixの場合は、zabbix_senderを使用してメッセージを送信します。

以下によく使用するパラメータの内容を記載します。
パラメータは以下に記載している他に多くあります。以下のパラメータは一部を抜粋して記載しましたので、他のパラメータの詳細は以下のナレッジを参照ください。
https://kb.sos-berlin.com/pages/viewpage.action?pageId=2523518

・よく使用するパラメータ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66557/5cb8f6f9-a445-333e-624a-77a96b703a5f.png)


# 監視システムへのエラー通知設定

次回の記事「JobSchedulerでのジョブ監視機能－２　Zabbixへのジョブエラー通知設定編」で実際に監視システムへの通知設定方法についてを記載します。
監視システムはZabbixを使用し、通知はジョブにエラーが発生した際にZabbixにzabbix_senderを使用してエラーを通知するものとします。
JobScheduler Monitoring Interfaceの設定、Zabbixの設定や、通知する内容は次回の記事で詳しく記載します。
DartでカオナビAPIを使ってデータ取得

カオナビのAPIでデータ取得する際、DartでのAPI通信に初挑戦した。

## pubspec

pubspec.yaml には http を追加する必要がある。

```yaml:pubspec.yaml
dependencies:
  http: ^0.12.0
```

追加したらターミナルでpub getを実行する。

```
$ pub get
```

## コード

`consumer_key` と `consumer_secret` はカオナビ管理者から取得しておき、値を置き換えよう。

```dart:main.dart
import 'package:http/http.dart';
import 'dart:convert';
import 'dart:async';

void main() async {
  String token = await getToken();
  String users = await getUser(token);
  print(jsonDecode(users)['data']);
}

Future <String> getToken() async {
  String url = 'https://api.kaonavi.jp/api/v1.0/get_token';
  var data = {
    'consumer_key': 'xxx',
    'consumer_secret': 'xxx'
  };
  // POST request
  Response response = await post(url, body: data);
  int statusCode = response.statusCode;
  print(statusCode);

  String body = response.body;
  print(body);

  String accessToken = jsonDecode(body)['data']['access_token'];
  print(accessToken);
  return accessToken;
}

Future <String> getUser(String accessToken) async {
  String url = 'https://api.kaonavi.jp/api/v1.0/user';
  var header = {
    'X-KAONAVI-TOKEN': accessToken
  };

  Response response = await post(url, headers: header);
  return response.body;
}
```


#### 処理の流れ
- アクセストークンを取得
- トークンをもとにユーザーを取得

#### コード実行
ターミナルからmain.dartを実行する。

```
$ dart main.dart
```

処理が正常にいけば、カオナビのユーザー情報のjsonがログ表示される。

## 感想
追加ライブラリをpubspecで管理するやり方を覚えられた。
DartのAPI通信は初めて実装したが、思ったよりコード量が少なかった。
async/await は使いやすいが、もうちょっと実装に慣れる必要がある。

Dartいいね
Pythonでソートアルゴリズムの再発明をしてみる: マージソート

# 概要
* Pythonでソートアルゴリズムを再発明してみるだけ
* 今回はマージソートについて
* 参考サイトのサンプルコードをできるだけ見ずに実装する
* とりあえず昇順ソートのみの対応とする

# マージソートの概要
* どのような条件でもわりと安定して速い
* 安定ソート

## 基本的な手順
1. リストを半分に分割する（要素の大きさに関係なく、単純に分割する）
2. 手順1について、要素数が全て1つになるまで繰り返す
3. ソート済みのリスト同士をマージする。先頭要素を比較し、小さい方から順に別のリストに詰めていく（※要素数が1のリストも「ソート済み」とみなせる）
4. 手順3を繰り返し、分割したリストが全てマージされたらソート完了

# ソース
```python
import random

def merge_sort(lst):
    # 再帰の終了条件
    if len(lst) == 0 or len(lst) == 1:
        return lst

    # 分割
    # 今の実装だと要素数が奇数の場合は余りの要素が後ろに入るが、どちらでもよいはず
    length = len(lst)
    firstHalf = lst[0:length // 2]
    latterHalf = lst[length // 2:length]
    
    # 再帰呼び出し。戻り値はソートされた状態になっている
    firstHalf = merge_sort(firstHalf)
    latterHalf = merge_sort(latterHalf)

    # マージ処理。それぞれの先頭要素を見て小さいほうからresultに詰めていけば全体がソートされたリストになる
    result = []
    while True:
        a = firstHalf[0]
        b = latterHalf[0]
        
        # 小さいほうをresultに追加し、元のリストからは削除
        # ここが逆なら降順ソートになる
        if a < b:
            result.append(a)
            firstHalf.pop(0)
        else:
            result.append(b)
            latterHalf.pop(0)

        # 両方とも空なら完了
        if len(firstHalf) == 0 and len(latterHalf) == 0:
            break
        
        # 片方だけ空なら、空じゃないほうをresultの後ろに足す
        if len(firstHalf) == 0:
            result +=  latterHalf
            break

        if len(latterHalf) == 0:
            result +=  firstHalf
            break

    return result


lst = list(range(10))
random.shuffle(lst)

print("ソート前: " + str(lst))

lst = merge_sort(lst)

print("ソート後: " + str(lst))

```

# 参考サイト
* https://ja.wikipedia.org/wiki/マージソート
rbenvでRubyのバージョンアップを行う

# rbenvとは

rbenvとは、複数のRubyのバージョンをOSの中で共存させて、必要に応じてRubyの環境を切り替えられるツールです。自分の環境にrbenvが入っていなかったら、git cloneでGitHubからインストールします。apt ではインストールできないようです。

公式サイト　https://github.com/rbenv/rbenv

# rbenvのバージョンを上げる

rbenvコマンド自体のバージョンが古いと、最新のRubyがインストールできない事があります。（正確にはruby-buildのバージョンが影響している）その場合は、rbenvコマンド自体のバージョンを上げないといけない事になります。

現状のrbenvのバージョンでインストール可能なRubyのバージョンの一覧が表示されます。一覧の中に、インストールしたいバージョンが含まれていなければ、rbenvコマンドのバージョンを上げる事になります。
`rbenv install -l`

rbenvのバージョンアップの前に、現状のrbenvのバージョンを確認しておきましょう。
`rbenv -v`

rbenvのバージョンを上げるには、先ず、rbenvが入っているディレクトリに移動します。自分の環境(Ubuntu)では、/usr/local/rbenvでした。
`cd /usr/local/rbenv`
`git pull`

確かに、バージョンが上った事を確認します。
`rbenv -v`

rbenvだけでなく、ruby-buildもバージョンアップしないといけない事になります。
`cd /usr/local/rbenv/plugins/ruby-build`
`git pull`

これで、最新のRubyのバージョンが表示される筈です。
`rbenb install -l`

# 最新のRubyのバージョンをインストールする

現状インストールされているRubyのバージョン一覧を表示します。*がついているバージョンが、現状、有効になっているRubyのバージョンという事になります。systemが表示されれば、OSにプレインストールされていたrubyのバージョンがsystemに該当します。
`rbenv versions`

systemが実際に何のバージョンであるかを調べたい場合は、適当なディレクトリに移動した後、これで確認できます。
`rbenv local system`
`cat .ruby-version`

.ruby-versionファイルは、確認のために、一時的に作成しただけなので、確認が終わったら削除しておいて下さい。
`rbenv local --unset`

.ruby-versionが本当に削除された事を確認しておく。一番したに表示されていなければOK。
`ls -latr`

今回は、2.3.0のバージョンのRubyをインストールします。（この間が多少長いので、しばし、休憩 :smiley:）
`rbenv install -v 2.3.0`

インストールしたRubyが表示される事を確認します。
`rbenv versions`

# グローバル環境で、Rubyのバージョンを変更する

蛇足ではあるが、グローバル環境のバージョンを確認する方法は４つあります。
`cat /usr/local/rbenv/version`　--- たぶん、使わないと思われる
`rbenv versions`  --- 他バージョンも表示してくれるので便利
`rbenv version`  --- グローバル環境１つだけを表示
`ruby -v`  --- ローカル環境を指定していない事が条件ではある

グローバル環境を2.3.0に変更します。バージョンをきっちりと入力しなくても、Tabキーで補完入力ができます。
`rbenv global 2.3.0`

グローバル環境が確かに変更された事を確認します。
`rbenv versions`

***この時点で自作したRubyのプログラムを流しても、グロバール環境にインストールしたgemを使っている場合、最新バージョンの環境ではgemが未だインストールされていないため、エラーになります。なので、最新バージョンの環境で、グローバル環境に必要なgemを１個つづインストールする必要があります。***

元の環境に戻したい場合は、元のバージョンを指定すれば戻ります。p247とかのパッチレベルまでしっかりと指定しないといけません。
`rbenv global  2.0.0p247`

旧バージョンでグローバル環境にインストールしていたgemの一覧を保存しておきます。
`gem list > gem_list_2.0.0.txt`

もう一度、グローバル環境を最新バージョンに変更します。
`rbenv global 2.3.0`

旧バージョンのgemのlistを基に、必要なgemをインストールします。バージョン指定が必要な場合は、指定します。
`gem install gem名 -v 0.0.0`

自作したRubyのプログラムを動かしてみて、動作に問題がなければ、旧バージョンのRubyは削除しておきます。インストールにはあれだけ長い時間がかかった割りには、削除は一瞬だったりする。
`rbenv uninstall 2.0.0p247`

旧バージョンのRubyが削除された事を確認します。
`rbenv versions`

# Rubyの開発環境を最新にしてみよう（補足）

現在の開発環境のRubyのバージョンを確認する。

```
rbenv versions
* 2.5.1 (set by /home/vagrant/.rbenv/version)
```

現在のRubyの最新バージョンを確認する。現時点では、2.6.3が最新なので、このバージョンをインストールする事にする。

```
rbenv install -l
```

2.6.3のバージョンをインストールする。結構時間がかかります。

```
rbenv install -v 2.6.3
```

2.6.3がインストールされた事を確認する。

```
rbenv versions
* 2.5.1 (set by /home/vagrant/.rbenv/version)
  2.6.3
```

グローバル環境を、2.5.1→2.6.3に変更します。

```
rbenv global 2.6.3
```

グローバル環境が2.6.3になった事を確認する。

```
rbenv versions
  2.5.1
* 2.6.3 (set by /home/vagrant/.rbenv/version)
```

Rubyのバージョンを確認して、確かに変わった。

```
ruby -v
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-linux]
````

C'est fini　:sweat_smile:

# 補足

rbenvのインストール方法と、rbenvを使ったRubyのインストール方法については、TechPitに学習教材があります。

https://www.techpit.jp/courses/190
PHPのローカル環境開発


VirtualBoxをまずはダウンロードする。
https://www.virtualbox.org/

MacならMac用をWinならWinをクリックして少し待つ

時間がかかるので時間のある時にしよう！

おそらくMacなら左上にある箱が開いたようなやつをダブルクリックして待つ

続けるを押していき、インストールが終われば終了。

ゴミ箱へ捨てるをクリック。





次にVirtualBoxを扱いやすくするためのvagrantをダウンロードする。
https://www.vagrantup.com/

だいたいは一緒

ダウンロードボタンを押して、MacならMacをWinならWinをクリック。

インストールする。



次はターミナルでの操作にうつります

command + スペース　　で検索して　ターミナルと検索
【駆逐してやる...】JavaScriptでExcelブックを配列化【1ファイル残らず！】

久々の業務で役立つ(かも？)シリーズです。

「受け取ったデータが`.xlsx`だった...」
「社内システムが`.xlsx`しか吐き出してくれない...」
「~~`.xlsx`をこねくり回すと全身に拒絶反応が...~~」

そのような絶望とも今日でおさらば！


# js-xlsx
- [SheetJS/js-xlsx - GitHub](https://github.com/SheetJS/js-xlsx)
- [SheetJS/xlsx - npm](https://www.npmjs.com/package/xlsx)
- [SheetJS/xlsx - jsDelivr](https://www.jsdelivr.com/package/npm/xlsx)

`.xlsx`以外にも`.xls`や`.ods`など、大抵の表計算ファイルをJavaScriptから扱えます。

もちろんShift-JISにも対応しており、なんとNode/Browserどちらでも使えます。

まさに救世主！


# 導入
```html:Browser
<script src="https://cdn.jsdelivr.net/npm/xlsx@latest/dist/xlsx.full.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xlsx@latest/dist/cpexcel.js"></script>
```
グローバル領域に`XLSX`オブジェクトが展開されます。
`cpexcel.js`は追加の文字コードセットで、これが無いとShift-JISを認識できません。

```js:Node
const XLSX = require("xlsx");
```
こちらは単純明快。
文字コードセットは全て内包されているので問題ありません。


# コード
```js:JavaScript
function parseSheet(blob){
    return new Promise((res, rej)=>{
        const fr = new FileReader();
        fr.addEventListener("load", () => res(fr.result));
        fr.addEventListener("error", () => rej(fr.error));
        fr.readAsArrayBuffer(blob);
    }).then((bin)=>{
        const book = XLSX.read(bin, {
            type: "array",
            codepage: 932
        });

        const sheets = book.SheetNames.map((name)=>{
            const sheet = XLSX.utils.sheet_to_csv(book.Sheets[name], {
                FS: "\u001F"
            }).split("\n").map((row)=>{
                return row.split("\u001F").map((field)=>{
                    if(/^$/.test(field)){
                        return null;
                    }
                    else if(/^true$/i.test(field)){
                        return true;
                    }
                    else if(/^false$/i.test(field)){
                        return false;
                    }
                    else if(/^((|-)((\d{1,3},){0,}\d{3}|\d+)|0(X|x)[0-9a-fA-F]+|0(B|b)[0-1]+)$/.test(field)){
                        const s = field.replace(/,/g, "");
                        const n = Number(s);
                        return Number.isSafeInteger(n) ? n : BigInt(s);
                    }
                    else{
                        return String(field);
                    }
                });
            });

            return {
                [name]: sheet
            };
        });

        return Object.assign(...sheets);
    });
}
```
各シートを一旦CSVにしてから、各フィールドの型判定を行い二次元配列化しています。

空白セルは`null`となります。
`Number`は、桁区切りでカンマが入っていたり16進や2進の表記でも問題ありません。
値が巨大な場合は`BigInt`となります。
それ以外の文字列は`String`です。


出力されるオブジェクトは、下記のようなデータ構造です。

```js:DataStructure
{
    "シート名": [/*行番号*/][/*列番号*/],
    ...
}
```

# 使う
```js:HowToUse.js
const file; // 任意の表計算ファイル

const parsed = parseSheet(file);

console.log(parsed["シート1"][0][0]); // シート1のA1セルに相当
```
行/列の番号が`0`スタートなところさえ気を付ければ、特に難しい操作はありません。

これで正規表現での総当りも、条件付きSUMも、フォームへの自動入力も思いのまま！

# おわりに
Excelのない朝は
今よりずっと素晴らしくて
すべての歯車が噛み合った
きっとそんな世界だ
Ubuntu18.04のDockに好きなアプリのアイコンをお気に入り登録する方法

# はじめに
　「Ubuntu16.04からUbuntu18.04にバージョンアップさせるぞ！」と私のPCの空き領域に入れるまでは良かったのですが、GUIが若干変わっておりいくつか戸惑った点がありました。
　今回は、Ubuntu16.04から仕様が変わったものの一つである、Dockに好きなアプリのアイコンをお気に入り登録する方法を備忘録的な形で紹介します。

# Dockとは
![Screenshot from 2019-08-22 09-06-17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253991/72572032-afba-b2e5-97f8-2c0255b56acf.png)
こいつのことです。

# 問題点
　Ubuntu16.04までは、アプリを立ち上げてDockに表示されるアイコンを右クリックして登録を押せば、特に問題なくDockにピン止めされる仕様でした。しかし、Ubuntu18.04からその右クリックからのピン止めが一部のアプリでしかできなくなっています。

# 方法
　ここではpycharmを例にアイコンをDockにお気に入り登録する流れを説明します。
## ~/.local/share/applicationsに移動
　まず、`~/.local/share/applications`ディレクトリに移動してください。移動は端末でもよいですが、ファイルで`ctrl+H`を押下することで隠しファイルが表示できるので、GUIで移動しても大丈夫です。
　移動した`applications`ディレクトリには.desktopと呼ばれる、アイコンの情報と実行に関する情報が記述されたファイルが置かれています。
　![Screenshot from 2019-08-22 17-08-47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253991/54fef38b-916d-8b31-0072-49b67984d93b.png)
　なお、.desktopファイルは、マウスでダブルクリックしても実行するプログラムがデフォルトでは紐づけされていないため、geditなどのテキストエディタにドラックして開く必要があります。

## .desktopファイルを作成
　次に追加したいアプリケーションの.desktopファイルを`applications`ディレクトリに作成します。例えば、私の環境ではpycharmは`/opt/pycharm/pycharm-2019.2`の中に入っているため、.desktopファイルは以下のような内容になります。

```
[Desktop Entry]
Version=1.0
Type=Application
Name=Pytharm
Icon=/opt/pycharm/pycharm-2019.2/bin/pycharm.svg
Exec="/opt/pycharm/pycharm-2019.2/bin/pycharm.sh" %f
Comment=A cross-platform IDE for python
Categories=Development;IDE;
Terminal=false
StartupWMClass=jetbrains-pycharm
```
*jetbrains-pycharm.desktop*

　このようなファイルを作成し、`applications`ディレクトリに保存すれば、自動的にアクティビティの中にアイコンが出現します。
　ちなみに、`Name`などは自分で任意に変えても大丈夫ですが、`Icon`、`Exec`はパスなどに間違いがあるとアクティビティにアイコンが出現しません。逆に出現しないとなればどこかが間違っている可能性が高いので、再度geditなどのエディタで開き、修正してください。

## Dockにお気に入り登録
　アクティビティにアイコンが出現したら、あとはこっちのもんです。右クリックしてお気に入りに登録すればめでたくアイコンがDockに表示されるようになります。
![Screenshot from 2019-08-22 17-24-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253991/09d29d02-5785-48c6-b3ee-cd884d117da4.png)

# おまけ
　.desktopの`Icon`などのパスを変えれば、emacsのアイコンでvimが立ち上がるというような使い方もできるのでぜひ（）
クロスリージョンレプリケーションをしているRDSに更新を適用するときの注意点

# 結論
RDSの保留中の更新を適用するとき、CRRのクラスターがある場合は先にそちらに更新を適用する必要がある。
(更新のタイプにはos-upgrade/system-update/db-upgradeの3種類がある。今回はsystem-updateなのでそれ以外も必須かは未検証。)

# 環境
ap-northeast-1にAuroraクラスターがあり、そのCRRクラスターがus-west-2にある。

```text:describe-db-clusters
"Engine": "aurora",
"EngineVersion": "5.6.10a",
```

どちらもAurora 1.16で保留中の更新に`Aurora 1.17.8 release`がある。

# やろうとしたこと
保留中のメンテナンスに `Aurora 1.17.8 release` が来ていたので、
下記のコマンドでap-northeast-1側のクラスターに更新を適用しようとした。

```bash
$ aws rds apply-pending-maintenance-action \
--resource-identifier "arn:aws:rds:ap-northeast-1:xxxxxxxxxxxx:cluster:hogehogecluster" \
--apply-action system-update \
--opt-in-type immediate
```


# 発生したエラー

```text:error
Unable to upgrade DB cluster hogehogecluster because related Aurora cross region Replica hogehogecluster-crr is not yet patched. 
Upgrade the Aurora cross region Replica and try again.
```

```text:Google翻訳
関連するAuroraクロスリージョンレプリカhogehogecluster-crrにはまだパッチが適用されていないため、DBクラスターhogehogeclusterをアップグレードできません。
Auroraクロスリージョンレプリカをアップグレードして、再試行してください。
```

# おわりに
たしかにupdateによる互換性とかのことを考えれば当たり前なんですが、すっかりCRRがあることを忘れていましたね。
これのせいでメンテ時間中に作業が終わらず…。
Railsのcheck_boxで親切に0を送ってくれているのは誰なのか

## Railsのcheck_boxは未チェック状態だと"0"を送ってくれる
デフォルト時の挙動です
paramsを見てもわかるとおり、0が送られてきます
時と場合によって`true/false`にしてみたりとか、いろいろあると思いますが、普通は0が送られます

## でも別にcheckboxのvalueが0/1で変化するわけではないんです
ある日、「checkboxのvalueが0か1で判定したいのに、チェックしてもチェック外してもvalueが1で変わらないんです :cry: 」と相談を受けました
まあその判定の善し悪しは置いておいて

HTMLのcheckboxってチェックしてないとそもそも送信されないですよね
Railsのparamsはチェック時に1未チェック時に0が送られてくるので、チェックのオンオフでvalueが0/1で変わると、その子は混乱しちゃったんですね
**まあ相談されてしばらくは僕も混乱してましたが**

## じゃあいったい誰が"0"を送ってる…？
checkboxはチェックされていたら"1"を送り、チェックされていなかったらそもそもなにも送らない
では、Railsにおいて親切に"0"を送っているのは誰なんでしょうか？

サンプルのフォームをscaffoldしてみて確認しました
![SampleRailsApp_-_Vivaldi.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7912/c95b55ce-eef8-faf8-bdd3-9c9a2bead1d3.png)

なるほど！君か！
**Railsはデフォルトでhiddenなvalueを作ってくれている**んですね
チェックされた場合、checkboxの方が後なので上書きされて"1"になると…なるほど

でも注意しないといけないのは、これがあくまでcheck_boxの話でcheck_box_tagはまた微妙に挙動が異なるということなんですが…それはまた別のお話(˘ω˘)

## 意外と詰まりやすいcheckbox
未チェック時は送信されないとか、true/falseにしたいときとか、check_box_tagを使ったときとか…なにかと詰まりやすいのがcheckboxだなあと思っています
でもこの辺の、実際に生成されているHTMLがなんなのか把握できると、詰まることも減るんじゃないかな〜と思いました
謎のvalue"0"を作る職人の存在がわかってスッキリしました
AzureVMにApp ServiceからVNet統合でアクセスする

タイトル通りの検証をしたので、備忘録として、、、


#【経緯】
SQL Server を Azure VM 上に展開して、そこのDBデータに対して App Service 上のアプリケーションからアクセスを試みる。

方法としては、今までオンプレミスのDBにアクセスする際に使用していたハイブリッドコネクション（ハイブリッド接続）による接続しか考えて居なかったが、よくよく考えてみると今回のパターンでは VM も Azure 上に存在する訳だし、わざわざハイブリッドコネクションをしないでも Azure VNet 内で完結するんじゃね？？？ってなった。

 ~~SQL Database を使え~~
やむにやまれぬ事情（レガシーに捕らわれている）がありまして、、、

#【結果】
もちろん可能だった。

方法としても Azure で用意されている機能でほぼほぼ事足りた。

# 【前提】
VNet 統合が完了した時点で、オンプレミス上のSQL Server と同様に扱うことができたので、統合完了後の確認作業等の記載はありません。

#【方法】
### 1. 接続先 Azure VM の作成
まず Azure VM をたてます。

後々SQL Server をインストールするのも面倒なので、Marketplace 上の SQL Server 20○○ on Windows Server○○ を使ったほうが楽です。

VNet 等もまとめて作ってくれるので楽ちん。

パブリックIPはあってもなくてもどっちでもいいです。(リモデできるのであれば)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185688/2a896931-5888-1c82-8333-909e6d371410.png)



SQL 認証はここで設定しておくと楽です。

適当に設定して作成します。

### 2. 接続確認用のウェブアプリケーションを作成
適当な App Service を作成します。

ただし App Service Plan に関しては Standard 以上を選択しましょう。

それ以外は適当に設定してください。

### 3. App Service を VNet 統合する
App Service のブレードから ネットワーク → VNet 統合の「構成するにはここをクリック」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185688/1864162f-a883-a016-d170-4b0021179dfe.png)


VNet 統合には Gateway を使用する方法と、使用しない方法（2019/08/21現在プレビュー）があります。

今回は Gateway を使用しない方法で接続します。（Gateway は高いし作成に時間がかかるので。。。）

適切な設定を入力してOKをクリック！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185688/f8a0f57e-04e7-17cc-5233-499b7b455c3f.png)

これで設定は完了です。

#【まとめ】
以上の作業を持って、VNet 統合が完了しました。
以降は、オンプレミスのSQL Serverにアクセスするのと同様に扱うことが出来ました。

Azure の機能はかなりの数がありますが、ひとつずつでも触っていって知見を深め、情報共有できれば、と思います。

# 参考

[アプリを Azure 仮想ネットワークに統合する - Azure App Service](https://docs.microsoft.com/ja-jp/azure/app-service/web-sites-integrate-with-vnet)


[Azure Web Apps と VNET 統合 - Japan Azure PaaS Support Blog](https://blogs.msdn.microsoft.com/jpcie/?p=455)
Vuetifyによる子コンポーネントと親コンポーネント間の双方向データ受け渡しの話

# 本記事について

下記問題に当たった人向けにv-modelと$emitを使った解決方法を記載してます。

- Vuetifyを使った子コンポーネントと親コンポーネント間のデータ受け渡しで困った方
- 双方向データ受け渡しを実装したけど、「Vue warn]: Avoid mutating a prop directly since ~」って出ちゃった人

# 問題
例えば、`<v-navigation-drawer>`をの開閉Toggleを親コンポーネント内で作成したく下記のような実装をしたとする。

- 子コンポーネント

```AppNavigationDrawer.vue
<template>
  <v-navigation-drawer
    v-model="drawer"
    absolute
    temporary
  >
  </v-navigation-drawer>
</template>
<script>
  export default {
    props: {
      drawer: {
        type: Boolean,
        default: false
      }
    }
  }
</script>
```

- 親コンポーネント

```AppHeader.vue
<template>
  <v-app-bar>
    <v-app-bar-nav-icon
      @click.stop="drawer = !drawer"
    />
  </v-app-bar>
 <navigation-drawer
   v-model="drawer"
 />
</template>
<script>
import NavigationDrawer from '@/components/AppNavigationDrawer'

export default {
  components: {
    AppNavigationDrawer
  },
  data () {
    return {
      drawer: false
    }
  }
}
</script>
```

結果、子コンポーネント側のdrawerが変化するような操作、例えばNavigationの外側をクリックをすると下記のようなエラーが出る。
![スクリーンショット 2019-08-22 16.34.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242893/494e3cf1-a9ea-38e1-bb35-6c5ce323b66d.png)
propsを直接変更するんじゃねぇ！っていうアラートですね。

# 解決方法
直接変更がダメならemitを使えばいいじゃない。つまり、[この辺](https://jp.vuejs.org/v2/guide/components.html#%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%A7-v-model-%E3%82%92%E4%BD%BF%E3%81%86)の話をVuetify Componentに応用すれば良いだけ。

- 子コンポーネント

```AppNavigationDrawer.vue
<template>
  <v-navigation-drawer
    :value="value"
    absolute
    temporary
    @input="$emit('input', $event)"
  >
  </v-navigation-drawer>
</template>
<script>
  export default {
    props: {
      value: {
        type: Boolean,
        default: false
      }
    }
  }
</script>
```

- 親コンポーネント

```AppHeader.vue
<template>
  <v-app-bar>
    <v-app-bar-nav-icon
      @click.stop="drawer = !drawer"
    />
  </v-app-bar>
 <navigation-drawer
   v-model="drawer"
 />
</template>
<script>
import NavigationDrawer from '@/components/AppNavigationDrawer'

export default {
  components: {
    AppNavigationDrawer
  },
  data () {
    return {
      drawer: false
    }
  }
}
</script>
```
親からのprops valueを`<v-navigation-drawer></v-navigation-drawer>`の開閉状態であるvalueにbindする。
子の変化は自身のinput event契機で、親のinputイベントを$emitすることで親コンポーネントへ変化を伝播する。

# 他
eventとvalueが定義されているVuetifty Componentであれば何でも応用できそうです。