OmniAICreator/Qiita-1.07M huggingface dataset:
定期的にLet's Encrypt証明書を更新してSlackでアナウンス

## Let's Encrypt
公開サイトでは常時SSL(AOSSL)の対応が必須になってきていまして、
[Let's Encrypt](https://letsencrypt.org/)は証明書発行が無料で簡単で最近数年間、人気を呼んでいます。
また、[2018年1月からワイルドカード証明書の発行を開始](https://letsencrypt.jp/blog/2017-07-06.html) しています。
Let's Encryptの証明書有効期間は基本3ヶ月で、
certbotという簡単な証明書発行クライアントを利用します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/108364/049ba191-aa9d-067c-b732-0fddcf5e47c5.png)

## 定期的にLet's Encrypt証明書を更新
有効期間が短いので、自分はcron設定で定期的に更新されるようにしておきました。

```
0 4 1 1,3,5,7,9,11 * root /usr/bin/systemctl stop httpd.service && /usr/bin/certbot renew --force-renew --quiet --post-hook "/usr/bin/systemctl start httpd.service"
```

## 定期的にLet's Encrypt証明書を更新してSlackでアナウンス
その状況をSlackにアナウンスするために以下のようにShellScriptでカスタマイズしました。

### ShellScript

```ssl_certificate_renew.sh
#!/bin/bash

# WebHookのURL
WEBHOOK_URL='https://hooks.slack.com/services/***************************'

# メッセージを一時保存する場所
MESSAGEFILE=$(mktemp -t ssl-certificate-notice-XXXX)

# 送信先のチャンネル
CHANNEL=${CHANNEL:-'#lee_test'}

# 終了時に削除
trap "rm ${MESSAGEFILE}" 0


send_notice_to_slack_renew_start () {
    # 見出し
    hd=${HEAD:-"start to ssl certificate renew.\n"}

    # json形式に整形
    payload="payload={
        \"channel\": \"${CHANNEL}\",
        \"text\": \"${hd}\"
    }"

    curl -s -S -X POST --data-urlencode "${payload}" ${WEBHOOK_URL} > /dev/null
}

send_notice_to_slack_renew_success () {
    # 見出し
    hd=${HEAD:-"ssl certificate renew success.\n"}
    # 絵文字
    emoji=${EMOJI:-':carlton:'}

    # json形式に整形
    payload="payload={
        \"channel\": \"${CHANNEL}\",
        \"icon_emoji\": \"${emoji}\",
        \"text\": \"${hd}\"
    }"

    curl -s -S -X POST --data-urlencode "${payload}" ${WEBHOOK_URL} > /dev/null
}

send_notice_to_slack_renew_fail () {
    # 改行処理
    cat ${MESSAGEFILE} | tr '\n' '\\' | sed 's/\\/\\n/g' > ${MESSAGEFILE}

    # 絵文字
    emoji=${EMOJI:-':aaw_yeah:'}
    # 見出し
    hd=${HEAD:-"<!here>ssl certificate renew fail.\n"}
    # メッセージをシンタックスハイライト付きで取得
    msg='```'`cat ${MESSAGEFILE}`'```'

    # json形式に整形
    payload="payload={
        \"channel\": \"${CHANNEL}\",
        \"icon_emoji\": \"${emoji}\",
        \"text\": \"${hd}${msg}\"
    }"

    curl -s -S -X POST --data-urlencode "${payload}" ${WEBHOOK_URL} > /dev/null
}

send_notice_to_slack_renew_start

/usr/bin/systemctl stop httpd.service
/usr/bin/certbot renew --force-renew --quiet 2> ${MESSAGEFILE}
RENEW_RESULT=$?
/usr/bin/systemctl start httpd.service

if [ ${RENEW_RESULT} -eq 0 ]; then
  send_notice_to_slack_renew_success
else
  send_notice_to_slack_renew_fail
fi
```

そして、ShellScriptを定期的に呼び出します。

### cron

```
0 4 1 1,3,5,7,9,11 * root /bin/sh /run/ssl_certificate_renew.sh
```

### 結果
#### 証明書更新成功
![image.png](https://qiita-image-store.s3.amazonaws.com/0/108364/18c7c1c5-10d3-5a31-d340-13bb29c7d040.png)

#### 証明書更新失敗
![image.png](https://qiita-image-store.s3.amazonaws.com/0/108364/052b8997-6ee0-fd13-aabb-f49c48e20eff.png)

ありがとうございます。
5/18のトークンエコノミーイベント反省

#URL

[ブロックチェーンによる小さな経済圏が作る未来とその事例](https://tokeneconomy.connpass.com/event/85402/)

##やったこと
・１ヶ月前に募集をTwitterで行なった。
→Twitterで行うと、学生からの募集が結構きた。ただ、１ヶ月の管理は難しかった。

・募集枠の母体数を徐々に上げていった。
→なんのクレームもなく、できた

・質問をTwiiterで募集した
→あまり馴染みがなかったので、来なかった。50人程度のイベントでは、意味がないのかもしれない

・大人で1000円いただいた。
→それでも20人ほど集まった。

・Twitter枠を導入した。
→透明性が担保された。ただ、目的がはっきりしていなかったので、何もなく終わった。もっと募集するべきだった。

・




##反省
・インタラクティブ性がなかった？
・応募の時期が早すぎた


##改善
・応募の時期は30~50人規模なら、10~14日前にする
・司会でもっと盛り上げたらよかった
ソース内で各linterの設定をスイッチする


# sass-lint

sass-lintの場合、ソース内からルールを変更することはできず、ルールの拒否か復活かしかできない。  
また各ルール内のオプションだけをスイッチすることもできない。

## 全てのルールを拒否

```scss:
// sass-lint:disable-all
```

`sass-lint:disable-all`はスペースを挟まずに記述しないと作動しない。  
拒否されたルールを途中から復活させたい場合、

```scss:
// sass-lint:enable-all
```

と記述する。


## 単数ないし複数のルールを拒否

```scss:
// sass-lint:disable class-name-format
// sass-lint:disable class-name-format, variable-name-format, nesting-depth
```

`sass-lint:disable`はスペースを挟まずに記述しないと作動しない。  
ルール名はカンマ`,`区切りで複数記述できる。

また、ソース頭に書かずに途中で書くとその場所から拒否する。  
拒否されたルールを復活させるには

```scss:
// sass-lint:enable class-name-format, variable-name-format, nesting-depth
```

のように`sass-lint:enable`を使う。

## ブロック内のルールを拒否

```scss:
body {
  section {
    // sass-lint:disable-block no-color-literals
    color: #F0F0F0;
  }
}
```

`sass-lint:disable-block`はスペースを挟まずに記述しないと作動しない。  
ブロック内で拒否したルールをさらに復活させることはできない

## １行のみルールを拒否

```scss:
body {
  section {
    color: #F0F0F0; // sass-lint:disable-line no-color-literals
  }
}
```

# stylint

ルールごとの変更や拒否はできず、ルール全ての拒否か復活のみができる

## 全てのルールを拒否

```stylus:
// @stylint off
.button_block .btn-default {
  background-color: green;
  color: white;
}
// @stylint on
```

`@stylint off`で全ルール拒否、`@stylint on`でルールを復活できる。

## １行のみルールを拒否

```stylus:
:root
  font-size 14px // @stylint ignore
```

この方法は`sortOrder`などの複数行に渡るエラー検査は拒否できない。



# eslint

eslintの場合、ルール内オプションを含め、ほぼ全てのルールをソース内で変更できる。

## 全てのルールを拒否

```javascript:
/* eslint-disable */
```

拒否されたルールを途中から復活させたい場合、

```javascript:
/* eslint-enable */
```

と記述する。

## 単数ないし複数のルールを変更

```javascript:
/* eslint no-var: 0 */

/* eslint no-var: 0, no-unused-vars: 2 */

/*
  eslint
    no-var: 0,
    no-unused-vars: 2,
    indent: [2, 2, { SwitchCase: 1 }]
*/

/*
  eslint {
    "no-var": 0,
    "no-unused-vars": 2,
    "indent": [2, 2, { "SwitchCase": 1 }]
  }
*/


```

上記全てのルールが正常に処理される。  
`0`ないし`"off"`でルール拒否、`1`ないし`"warn"`で警告処理、`2`ないし`"error"`でエラー処理となる。

## １行のみルール拒否

```javascript:
alert('foo'); // eslint-disable-line no-alert

// eslint-disable-next-line no-alert
alert('foo');
```

ブロック単位のルール変更などはできない。
ブランチのいろいろ

#ブランチのいろいろ

　前回は[リポジトリを共有しよう](https://qiita.com/n_hirai/items/dd98a29a4b070dd65026)でリポジトリについて、説明してきました。  

　今回は[エンジニアの必須であるgitとは何か](https://qiita.com/n_hirai/items/de895134194400110fd2)でも述べた**ブランチ**について説明します。  


##ブランチのルール
　まずはブランチの運用ルールについてです。gitでは自由にブランチを作ることができますが、あらかじめルールを設けておくことが重要です。  

* **統合ブランチ** リリース版がいつでも作成可能なようにしておくためのブランチ  
	* 安定した状態を保っておく
	* 通常masterブランチを統合ブランチとしてる

* **トピックブランチ** 機能追加やバグ修正といったあり課題に関する作業を行うためのブランチ  
	* 複数の課題を作業する場合はその数だけ作成される
	* 作業が完了したら統合ブランチに取り込む

##チェックアウト
　チェックアウトとは作業するブランチを切り替える操作のことです。

* **HEAD**  
 	* 現在使用しているブランチの戦闘を表す名前のこと
	* デフォルトではmasterブランチ

* **stash**
	* ファイルの変更内容を一時的に記録しておく領域のこと
	*  移動先のブランチで同じファイルに変更がある場合チェックアウトに失敗してしまうため

##マージ
　マージとは統合ブランチに統合するために、複数の履歴の流れを合流することです。また、トピックブランチより統合ブランチより進んでしまっている場合でも、マージコミットが作成されそのあとに統合ブランチに移動してくれます。  

* **rebase**
　マージとほぼ同じであるが、トピックブランチの履歴が統合ブランチの後ろに付け替えられるため履歴が1本化されます。
　

##まとめ
　このようにブランチの運用は2つの種類に分けて行うことで、分かりやすく並行してバグの修正することが出来ます。また作業履歴を残すことで、問題が発生した場合に原因となる変更箇所を修正することができます。
　

##参考文献
[サルでもわかるgit入門](https://backlog.com/ja/git-tutorial/)
ロリポップでLaravelのプロジェクトを公開

ロリポップでDBを作成しておく

ロリポップにssh接続
$ cd 
$ git clone myProject
$cd web
$ ln -s /home/users/1/ユーザー名/myProject/public/ myProject
$ chmod -R 777 ~/myProject/public/
$ cd myProject
$ /usr/local/php7.1/bin/php ~/web/composer.phar install
$ vi .env
DB_HOST=ホスト名
DB_DATABASE=作成したDB名
DB_USERNAME=作成したDBのユーザー名
DB_PASSWORD=作成したDBのパスワード

$ /usr/local/php7.1/bin/php artisan key:generate
$ /usr/local/php7.1/bin/php artisan migrate:refresh --seed


独自ドメイン取得後
ロリポップ側
php設定でバージョンを7系に
Microsoft Azureでログを参照する

# はじめに

Azureで動いているサービスでシステムログを追跡する際に、Microsoft Azureでのログ参照方法の知識が必要だったので、共有します。

# 手順

## Microsoft Azureにログイン

https://portal.azure.com/

## 当該システムの設定を参照する

「Webアプリ」「App Service」と表示されている項目を選択し、「開発ツール」-「高度なツール」をクリック。
サービスによっては直リンクもあります。

## ログディレクトリを参照する

ページ上「Debug Console」から、CMDまたはPowerShellをクリックして表示される画面で、Azure上のディレクトリをたどることができます。
使い方は下記URLを参照してください。
http://www.atmarkit.co.jp/ait/articles/1707/27/news024_3.html

## ログディレクトリの場所

アプリケーションの状態に依存します。
初期状態を`D:\home`とすると、`D:\home\site\wwwroot`以下がリポジトリのルートディレクトリです。
IntelliJ に乗り換えた際、プロパティーファイルのエンコードで大量差分が出てしまった

Eclipseから、IntelliJ IDEAに乗り換えた時に
プロパティーファイルを編集時、大量の差分が出てしまった。

プロパティーファイルがエンコードされると、英数文字が大文字か、小文字かで大量な差分が出てしまうことで、困った

残念ながら、メニューからは設定でき無そうでしたが、
プロパティーファイルを編集することで回避できるみたいだ

idea.propertiesファイルに以下の行を追加すればよい。
ヘルプ→カスタム・プロパティーの編集で、編集できるみたい

`idea.native2ascii.lowercase=true`
2018年5月頃に行うASP.NET Core2をCentOS7に入れてHelloWorld!

# 初めに
難しいことは考えずに、この世界へようこそを出す。

日本語訳で、(マイクロソフトにしては)ユーザーフレンドリーになってるドキュメント。
[Linux における .NET Core の前提条件](https://docs.microsoft.com/ja-jp/dotnet/core/linux-prerequisites?tabs=netcore2x)

## 前提
- CentOS7
- ASP.NET Core2
- 空のプロジェクトを実行して「Hello World!」をだす。

## 注意事項
- コンソールアプリでの「Hello World!」だよ。
- Webじゃないよ。でもコンソールからWebに変えるのは超絶簡単だよ。
- Webで「Hello World!」したい場合は`dotnet new console`を`dotnet new web`に変えるだけだよ。
- クリーンなCentOS7を用意する為、私はVagrantとVirtualbox使いました。

# 垂れ流すコマンド
```shell
sudo yum update -y
sudo yum install -y libunwind libicu

sudo rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm
sudo yum install -y dotnet-sdk-2.1.105

mkdir /hogehoge
cd /hogehoge

dotnet new console
dotnet run
```



# 何が起きたか
## 依存パッケージのDL
```shell
sudo yum update -y
sudo yum install -y libunwind libicu

```
yumの更新。
依存パケのDL。

## ASP.NET Core2のDL
```shell
sudo rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm
sudo yum install -y dotnet-sdk-2.1.105
```
rpmが訪問する場所にマイクロソフトを追加。
そしてDL。
ちなみに`dotnet-sdk-2.1.105`の部分はわりかし変わる。
最新追い続ける方は適宜チェック&変えてね。
[Install .NET Core SDK 2.1.105 on Linux CentOS / Oracle](https://www.microsoft.com/net/download/linux-package-manager/centos/sdk-2.1.105)

## プロジェクトフォルダの作成、立ち合い
```shell
mkdir /hogehoge
cd /hogehoge
```
ASP.NET Coew2の「空のプロジェクト」を入れる場所の確保。

## 「空のプロジェクト」作成、実行
```shell
dotnet new console
dotnet run
```
ASP.NET Coew2のコンソールアプリの「空のプロジェクト」を作成。
カレントディレクトリにあるdotnetプロジェクトを実行する。
結果は以下の通り。

```shell
>Hello World!
```
# おわりに
**全部公式ドキュメントに書いてあるね……**
CSVの読み出し


#最初

小さな更新

大した記事じゃないんですけど、CSVの読み出し処理に何日も悩まされたので、
備忘録として書いときます

#コード

``` csharp

using System.Collections.Generic;

namespace Utility {
	using DataCSVLineReader = Dictionary<string, string>;
	using DataCSVLineReaders = List<Dictionary<string, string>>;

	/*
		
		CSVからデータを抜き出すクラスです
		
		＊このクラスはタプルを使用しているため、
		System.ValueTuple.dllを参照しないとコンパイルできません＊

	*/
	public sealed class DataCSV {
		const char csvPunction = ',';

		const int keyIndex = 0;
		const int valueStartIndex = 1;
		
		const int keyNameFirstCharIndex = 0;
		/*
			キータグ用文字
			最初にこの文字を付けた列のデータ全てが連想配列に登録される対象
			
			抽出されるデータ対象は、
			一番上の列から１つ下の列、
			もしくは一番左の列から１つ右の列から最後の列までです

			（ただし、空白だけの列は無視されます）
		*/
		const char keyNameFirstChar = '@';

		string[][] CSV { get; }

		public DataCSV(string[][] csv) {
			CSV = csv;
		}

		int LengthY => CSV.Length;
		int LengthX => CSV[0].Length;

		//一番上のデータを連想配列で抜き出します (横列CSV用)
		public DataCSVLineReader DataHorizonFirst => GetLineDataHorizon();
		//一番左のデータを連想配列で抜き出します (縦列CSV用)
		public DataCSVLineReader DataVerticalFirst => GetLineDataVertical();

		//指定した列のデータを連想配列で抜き出します (横列CSV用)
		public DataCSVLineReader GetLineDataHorizon(int readLineIndex = 0) {
			return GetAllLineDataHorizon()[readLineIndex];
		}
		//指定した列のデータを連想配列で抜き出します (縦列CSV用)
		public DataCSVLineReader GetLineDataVertical(int readLineIndex = 0) {
			return GetAllLineDataVertical()[readLineIndex];
		}

		DataCSVLineReaders GetAllLineData(int valueLength, int dataLineLength, Func<int, int, (string Key, string Value)> func) {
			var list = new DataCSVLineReaders();

			for (var i = valueStartIndex; i < valueLength; i++) {
				var datas = new DataCSVLineReader();

				for (var n = 0; n < dataLineLength; n++) {
					DatasDictAddKeyAndValue(datas, func(i, n));
				}
				if (!IsDatasDictValuesNullOrWhiteSpace(datas)) list.Add(datas);
			}

			return list;
		}
		//データを全て連想配列抜き出します (横列CSV用)
		public DataCSVLineReaders GetAllLineDataHorizon() {
			return GetAllLineData(LengthY, LengthX, (y, x) => {
				var key = CSV[keyIndex][x];
				var value = CSV[y][x];

				return (key, value);
			});
		}
		//データを全て連想配列で抜き出します (横列CSV用)
		public DataCSVLineReaders GetAllLineDataVertical() {
			return GetAllLineData(LengthX, LengthY, (x, y) => {
				var key = CSV[y][keyIndex];
				var value = CSV[y][x];

				return (key, value);
			});
		}

		void DatasDictAddKeyAndValue(DataCSVLineReader datas, (string Key, string Value) args) {
			DatasDictAddKeyAndValue(datas, args.Key, args.Value);
		}
		void DatasDictAddKeyAndValue(DataCSVLineReader datas, string key, string value) {
			if (!IsAddKeyName(key)) return;

			datas.Add(key, value);
		}

		/*
			キーを連想配列に登録するかどうか

			この例では、キー名の最初が@で始まるものはtrueで返します
		*/
		bool IsAddKeyName(string key) {
			if (string.IsNullOrWhiteSpace(key)) return false;
			if (key[keyNameFirstCharIndex] == keyNameFirstChar) return true;

			return false;
		}
		//連想配列のValuesの値が全て空白であればtrueを返します
		bool IsDatasDictValuesNullOrWhiteSpace(DataCSVLineReader datas)
			=> datas.Values.All(i => string.IsNullOrWhiteSpace(i));
	}
}


```

#処理の流れ（縦並びcsvの場合）

・処理１
連想配列を格納するリスト配列を作成

・処理２
string型の二次元配列を参照し、
横列の読み出したい文字列を全て連想配列に格納する

・処理３
連想配列内の文字列が全て空白なら、リスト配列に追加しない

・処理４
処理２と処理３を縦列の数だけ実行
開発標準を考えるヒント

・設計書を統一すると不便が多い。どこかの業務・機能に合わせて設計書を作ると、他の業務・機能には合わないものとなる。同じ画面でも、入力項目が少ないものと多いものでは適切な設計書は異なる。アップロード・ダウンロードがある画面と、そうでない画面では最適な設計書は異なる。DB参照しかない画面と、DB更新もある画面では、最適な設計書は異なる。DBしか扱わない画面と、ファイルも扱う画面では最適な設計書は異なる。その業務・機能の特性や採用するアーキテクチャによって設計書のフォーマットは分けた方がよい。表紙、ヘッダー、余白、フォント等の統一であれば問題は少ない。

・採用するアーキテクチャをもとにプログラムが作成できることを確認できた上で、設計書フォーマットは考えるべき。フレームワークが吸収してくれる要素（エラー処理等）は設計の必要がない。余計な設計をすることでフレームワークとの整合性が取れなくなってしまう。またフレームワークを利用するために必要な検討要素が漏れてしまうと実装ができない。そのためフレームワーク、アーキテクチャ等を考慮・検証した上で設計書フォーマットは考える。

・開発標準は、体制、スケジュール、技術者スキルなどを考慮した上で検討しなければならない。工程、アクティビティ、タスクを定義し、その順番、依存関係、ボリュームなども定義する。またそれぞれのタスクに登場するロール、組織なども定義する。設計書はタスクの成果物であり、設計書を作ることが（本来の）タスクではない。

・設計書は順番に作成するものではなく、作成後、他の設計書の影響を受け、修正されるものである。シリアルに成果物が作成されるわけではなく、相互に補完しながら成長するものである。「〇〇設計書がないから△△設計書が作れません」という言い訳には、相互に補完することを説明する。

・設計書フォーマットはステークホルダーによって、求める観点が異なる。業務・機能によって最適な設計書フォーマットが異なる。それ以外にも、設計者にとっての最適（量が少ない）、実装者にとっても最適（プログラムに落としやすい）、レビューアにとっての最適（読みやすい）は相反するので全員が満足することは難しい。そのため設計書フォーマットを推進する人は、影響力を行使できる人がのぞましい。設計経験があるという程度では、設計書フォーマットを普及させるのは難しい。
[C#] Serialize and Deserialize a class instance (Xml)

There are a lot of ways to serialize and deserialize a class instance.
Here show a simple way with `System.Xml.Serialization`.


# Class Description

```csharp
public class Item {
    public int    Id   { get; set; }
    public string Name { get; set; }

    [XmlIgnore]
    public bool Active { get; set; }
}

public class ItemGroup {
    public List<Item> ItemList { get; set; }
}
```

# Serialize/Deserialize Implementation

```csharp
using System.Xml;
using System.Xml.Serialization;

public class SerializeTest {
    public static string Serialize (ItemGroup group)
    {
        string xml = "";

        XmlSerializer serializer = new XmlSerializer (group.GetType ());
        using (var sw = new StringWriter()) {
            serializer.Serialize (sw, group);
            xml = sw.ToString ();
        }

        return xml;
    }

    public static ItemGroup Deserialize (string xml)
    {
        ItemGroup group = null;
        XmlSerializer serializer = new XmlSerializer (typeof (ItemGroup));
        using (var sr = new StringReader (xml)) {
            group = (ItemGroup)serializer.Deserialize (sr);
        }
        return group;
    }
}
```

# Xml Result 

After serialize a class, we will get something like this.

```xml
<?xml version="1.0" encoding="utf-16"?>
<ItemGroup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ItemList>
    <Item>
      <Id>1</Id>
      <Name>Book</Name>
    </Item>
    <Item>
      <Id>2</Id>
      <Name>Pen</Name>
    </Item>
  </ItemList>
</ItemGroup>
```

# Other

1. As described in [C# refernece](https://docs.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlserializer.serialize?view=netframework-4.7.2#System_Xml_Serialization_XmlSerializer_Serialize_System_Xml_XmlWriter_System_Object_), This method just serialize

- public fields
- read/write properties

into xml.
2. Field with `[XmlIgnore]` attribute would be ignored.
Windows Subsystem for LinuxのUbuntu 18.04を使ったLaravel Homesteadの構築手順

# 概要
会社ではMac、自宅ではWindowsのような環境の場合、自宅でも慣れ親しんだBashを使って開発環境を整えたい場合や、WindowsにPHPやComposerを入れるのがめんどくさい、あまり汚したくないというなどという理由で、Windows Subsystem for Linuxを使ってPHPが動作する環境及びLaravel Homesteadが動作する環境を構築する手順を以下にまとめる。

なお、Homesteadはプロジェクトごとにインストールすることを前提とする。

プロジェクトごとにインストール - Laravel Homestead 5.6 Laravel
https://readouble.com/laravel/5.6/ja/homestead.html#per-project-installation

# VirtualBoxのインストール

Oracle VM VirtualBox - Downloads | Oracle Technology Network | Oracle
http://www.oracle.com/technetwork/server-storage/virtualbox/downloads/index.html?ssSourceSiteId=otnjp

# Windows Subsystem for LinuxのUbuntu 18.04のインストール

Microsoft Storeからインストールする

Ubuntu 18.04 を入手 - Microsoft Store ja-JP
https://www.microsoft.com/ja-jp/p/ubuntu-1804/9n9tngvndl3q

# Ubuntu 18.04を起動する

スタートメニューからUbuntu 18.04を起動することで、シェルが起動される。
初回起動時ユーザー作成が必要となるので、ユーザー名の入力、パスワードを入力する。

パスワードは以後、`apt`を利用する際に`sudo`を実行した時に聞かれるので覚えておくこと。

# 必要なパッケージのインストールする

* php-cli
* php-mbstring
* php-mysql
* php-xml
* php-zip
* composer

```
$ sudo apt update
$ sudo apt install php-cli php-mbstring php-mysql php-xml php-zip composer
```

# ソース格納ディレクトリの準備とシンボリックリンクの作成

Windows Subsystem for Linuxでは、Ubuntu内からWindowsのファイルシステムにアクセスする場合/mnt配下にあるドライブレターごとのディレクトリ配下を参照することになる。

毎回ディレクトリを移動するのが面倒なため、Ubuntuのホームディレクトリ配下に、Windowsのホームディレクトリ配下に作成したディレクトリのシンボリックリンクを作成する。以下を実行し`src`というディレクトリでプロジェクトを管理できるようにする。

```
$ mkdir /mnt/c/Users/<Windowsのユーザー名>/src
$ ln -s /mnt/c/Users/<Windowsのユーザー名>/src ~/src
```

# Vagrantのインストール

VagrantはWindowsとWindows Subsystem for Linuxの両方にインストールする必要がある。

## Windowsへのインストール

Download - Vagrant by HashiCorp
https://www.vagrantup.com/downloads.html

## Windows Subsystem for Linuxへのインストール
```
$ wget https://releases.hashicorp.com/vagrant/2.1.1/vagrant_2.1.1_x86_64.deb
$ sudo apt install ./vagrant_2.1.1_x86_64.deb
$ rm vagrant_2.1.1_x86_64.deb
```

# Vagrantの設定

Vagrant and Windows Subsystem for Linux - Vagrant by HashiCorp
https://www.vagrantup.com/docs/other/wsl.html

```
$ echo 'export VAGRANT_WSL_ENABLE_WINDOWS_ACCESS="1"' >> ~/.bashrc
$ source ~/.bashrc
```

必要に応じて、秘密鍵と公開鍵を生成しておく。Vagrantを起動する際に必要だが、他に利用用途が無い場合にはパスワードを設定しなくても良いかも。

```
$ ssh-keygen -t rsa -b 4096
```

ここまで設定すれば、後の手順はLinuxやMacで行う手順とほぼ同じとなる。

# Laravelコマンドのインストール

```
$ composer global require laravel/installer
$ echo 'export PATH="$PATH:$HOME/.config/composer/vendor/bin"' >> ~/.bashrc
$ source ~/.bashrc
```

# プロジェクトの作成とHomesteadの追加

```
$ cd ~/src
$ laravel new blog
$ cd blog
$ composer require laravel/homestead --dev
$ php vendor/bin/homestead make
```

# Homesteadの起動
Homesteadを初めて利用する場合、必要なBoxイメージをダウンロードするため時間がかかる。

```
$ vagrant up
```

`vagrant ssh`を実行した際、vagrantのユーザーのパスワードを聞かれた場合にはパスワードとして`vagrant`を入力する。
Mediator Pattern

# Mediator Pattern
全く関わりのないオブジェクト同士を疎結合させる

# Reference
- [tutorialspoint:Mediator](https://www.tutorialspoint.com/design_pattern/mediator_pattern.htm)
- [journaldev:Mediator](https://www.journaldev.com/1730/mediator-design-pattern-java)
- [geeksforgeeks:Mediator](https://www.geeksforgeeks.org/mediator-design-pattern/)
- [iluwatar:Mediator](https://github.com/iluwatar/java-design-patterns/tree/master/mediator)
openstack 基礎

## はじめに

完全に個人用のメモです
間違っているところがあったら教えてください。

## 頻出コマンド一覧

https://qiita.com/drafts/abe43049208538aaa889

## クラウドコントローラ

各コンピュートノード（後述）を制御するサーバー

## コンピュートノード

VMインスタンスを管理する（建てる）サーバー

## フローティングIP

NATの外側のIP
AWSでいうところのEIP（外部IP）

## br-int, br-tun

internalスイッチとトンネルスイッチ

どちらもコンピュートノード上にある。

コンピュートノード上にインスタンスを建てるとbr-intに繋がり、br-tunというトンネルスイッチでカプセル化される。おかげで、別のコンピュートノード上に建てられたインスタンスとグローバルの世界を気にせずにあたかも同じネットワークにいるかのように通信することができる。

![9F259619-8498-430A-928B-85FA5B7B6B0F.jpeg](https://qiita-image-store.s3.amazonaws.com/0/132486/4facdc36-133a-f6aa-3156-efe585d6caf8.jpeg)


## Availability Zone

一つの括りのサーバ群

習慣的には一つのデータセンタと同義
LaravelのクエリビルダでgroupByを使った件数(count)の集計

[参考ドキュメント] (https://readouble.com/laravel/5.5/ja/queries.html)

件数を出すだけの集計ならこれでいいのだが

```php
$users = DB::table('users')->count();
```
　
groupbyしたグループIDごとの件数集計結果を取りたい場合は生クエリを書くしかないようだ。（ドキュメントにのってんだもん）

```php
$users = DB::table('users')
    ->select(DB::raw('count(*) as user_count, status'))
    ->groupBy('status')
    ->get();
```

実行したわけじゃないから確信ないけど、多分statusごとのユーザ数がみれる。

ユーザーテーブル

|status  |status数|
|---|---|
|未登録| １００|
|登録済み| １０|
|購入済み| ５|


とかって感じに出る。
　

---
エラーサーチという、働くエンジニアのためのメモ帳サービスを運営しています!

自分用の情報をパパッとメモ書きしたり、役立つ情報は整理して他の人にもシェアしたり！
[エラーサーチ] (https://error-search.com/)

[Twitterはこちら] (https://twitter.com/error_search)

---
IFTTTからスプレッドシート書き出し時の日付タイムスタンプのフォーマット修正

サービス間連携で便利なIFTTTですが、Webhookなどのログを記録する際にスプレッドシートへタイムスタンプを残す際の日時フォーマットが汎用的なものではなく、スプレッドシート側で日時として認識できずにその後のグラフ化などに支障があるため、汎用的に使える日時書式に書き換える方法を編み出したのでその知見を残しておきたいと思います。

## 課題
IFTTTのイベント発生タイムスタンプ書式 `{{OccurredAt}}` で書き出される日時
`May 20, 2018 at 03:30PM`
がスプレッドシートで日付として認識できない(DATEVALU関数で取り扱えない)

## 解決方法
出力の" at "を境に日付部分と時間部分に別けた上で、日付を`GOOGLETRANSLATE`関数に食わせて日本語に変換
`May 20, 2018`　→　`2018年5月20日`
これでめでたくスプレッドシートが日時として認識し、`DATEVALUE`関数に食わせる事ができました。

### 数式と出力例
数式 | 出力例
---- | ----
{{OccurredAt}}  |  May 20, 2018 at 03:30PM
=GOOGLETRANSLATE(left("{{OccurredAt}}",find(" at ","{{OccurredAt}}")),"en","ja") |  2018年5月20日 ※1
=RIGHT("{{OccurredAt}}",len("{{OccurredAt}}")- find(" at ","{{OccurredAt}}")-3)  |  03:30PM ※1
=DATEVALUE(GOOGLETRANSLATE(left("{{OccurredAt}}",find(" at ","{{OccurredAt}}")),"en","ja"))+TIMEVALUE(RIGHT("{{OccurredAt}}",len("{{OccurredAt}}")- find(" at ","{{OccurredAt}}")-3)) | 2018/05/20 15:30:00 ※2
※1　GOOGLETRANSLATEにかけただけだと書式の変更はかけられない。
※2　DATEVALUE、TIMEVALUE関数に食わせる事でシリアル値となり、書式設定が可能になります。

### 具体的なIFTTT上での設定数式
![IFTTT日時書式.png](https://qiita-image-store.s3.amazonaws.com/0/85622/4e09788d-9c96-37d6-2040-9c04783e1efd.png)
### 出力例
{{OccurredAt}} | {{EventName}} | {{Value1}} | 日付 | 時間 | 日時
--- | --- | --- | --- | --- | ---
May 20, 2018 at 03:30PM | Temp_push | 24.82 | 2018年5月20日 | 03:30PM | 2018/05/20 15:30:00

 {{EventName}}と{{Value1}} はWebhookでPOSTしているイベント名とJSONで送っているvalue情報です。

##背景
マイコンボードのArduinoから測定した温度をIFTTTのWebhookを通してスプレッドシートにロギングしていく仕組みを作っていました。
センサーであるArduino自体には時間情報を持っていないため、データを受け取った処理側で時間情報を書き込む必要がありました。

![温度センサーロギングシステム.png](https://qiita-image-store.s3.amazonaws.com/0/85622/93255fcd-ceeb-c8a0-3db8-bfdcede57e63.png)


同じ課題を解決しているGithubの英語ユーザーによる[IFTTTDate.md](https://gist.github.com/oscarmorrison/bf14dab89854238d4cca)がありましたが、これではなぜか月の英語表記を日時解釈することがスプレッドシートの日本語環境ではできないため、苦肉の策として翻訳関数であるGOOGLETRANSLATEをかますことで解決できた。という裏技的な解決方法ではあります。
成功したときちょっと笑ってしまった。

##注意点
翻訳関数という曖昧な仕組みを利用しているため利用はご自身の判断でお願いします。
ログに数式が入りまくっているという気持ち悪さはありますがリアルタイムでの可用性重視でこの形となっています。
適宜数式を取り除く処理をすれば良いかな。

p.s.初めてQiita投稿しました。
Kivyのtextureでの画像表示の注意点

Kivyで、textureを使って画像表示した際に、
なんか表示がうまく行かず、調べたら「これはひどい[^1]」となったので、
[^1]: ただの自分の無知
今後のためにメモ

# textureでの画像表示
textureでの画像表示は、sourceを使わず、textureを使う。
(textureで表示しようとしているので当たり前)

## 最初のソース(問題あり)
Pillow使ったので、こんな感じ。(参考->[ここ](https://qiita.com/dario_okazaki/items/fc8ae0525f2e8036cde7)[^2])
[^2]: 何回もリンクすみません！ほんとお世話になります。
Pillowデータをtextureにした時の大事な点は、上下反転させる必要がある点みたい。
(ソースは、ほぼ[前記事と一緒](https://qiita.com/taashi/items/e68c527bba13854eb555))

```ImageApp.py
from kivy.app import App
from kivy.properties import StringProperty, ObjectProperty
from kivy.uix.widget import Widget
from kivy.graphics.texture import Texture

from PIL import Image


class ImageWidget(Widget):
    image_texture = ObjectProperty(None)
    image_src = StringProperty('')

    def __init__(self, **kwargs):
        super(ImageWidget, self).__init__(**kwargs)
        filename = './image.png'
        self.image_src = filename
        self.image_texture = image_to_texture(filename)
        pass


class ImageApp(App):
    def __init__(self, **kwargs):
        super(ImageApp, self).__init__(**kwargs)
        self.title = 'Image Slide'

    def build(self):
        return ImageWidget()


def image_to_texture(filepath):
    img = Image.open(filepath)
    texture = Texture.create(size=img.size)
    texture.blit_buffer(img.tobytes())
    texture.flip_vertical()
    return texture


if __name__ == '__main__':
    app = ImageApp()
    app.run()
```

```image.kv
#:kivy 1.10

<ImageWidget>:
    canvas.before:
        Color:
            rgb: 1,1,1
        Rectangle:
            pos: self.pos
            size: self.size

    BoxLayout:
        size: root.size
        orientation: 'vertical'

        Label:
            text: root.image_src
            color: 0, 0, 0, 1
            font_size: 20
            size_hint_y: 0.1

        Image:
            size_hint_y: 0.9
            allow_stretch: True
            texture: root.image_texture
```

で、表示されると思っていた！
が、いざ表示してみると、何か表示されるけど、表示したい画像がなんかずれて表示されてる感じだった。

## 修正版ソース
表示された画像からして、画像データのformatの認識ミスっぽく見えたので、調べたところ、

||format|
|:--|:--|
|Pillowで読み込んだ画像|RGBA|
|Texture.create()で作ったtexture|RGBA|

あれ？あってんじゃん。。。
と思って、[KivyのドキュメントのTextureのところ](https://kivy.org/docs/api-kivy.graphics.texture.html#kivy.graphics.texture.Texture)を見たら、

create()のParametersには、
>colorfmt: str, defaults to ‘rgba’

blit_buffer()のParametersには、
>colorfmt: str, defaults to ‘rgb’

と書いてあるのを見つけた。

やられた。これか。ということで、修正したソースが以下。

```ImageApp_fix.py
  ~ 以上、上記ImageApp.py差分無しのため省略 ~

def image_to_texture(filepath):
    img = Image.open(filepath)
    texture = Texture.create(size=img.size)
    texture.blit_buffer(img.tobytes(), colorfmt='rgba')
    texture.flip_vertical()
    return texture

  ~ 以下、上記ImageApp.py差分無しのため省略 ~
```

これで、無事、ちゃんとした画像が表示されました。
修正版ソースでは、`colorfmt='rgba'`として固定してしまっていますが、
本来は、`img.mode`で取得した値に対して、colorfmtを変更する処理を書いたほうがよさそうです。

にしても、
(同じモジュール内の同じようなパラメータの)デフォルト値が違うのはわかりずらい...
まぁ、textureを作成する元データとしては、RGBが多いからってことなのかもしれないが...

## まとめ
- textureは、Texture.create()で作成する。
- デフォルトのTexture.create()で出来たtextureは、RGBA。
- textureにデータを渡すには、Texture.blit_buffer()を使用する。
- デフォルトのTexture.blit_buffer()が期待するformatは、RGB。
- Texture.blit_buffer()に渡すデータに合わせてcolorfmtを指定しましょう。
Markdownで複数行のコードを書くときは下に１行空けたほうが良いと思う

Qiitaは大丈夫なんですけどね。


# １行空けない場合

```
Type error: Argument 1 passed to App\Http\Controllers\PostController::test() must be an instance of App\User, string given, called in /home/vagrant/code/Laravel/app/Http/Controllers/PostController.php on line 92
```

## 見づらい
![スクリーンショット 2018-05-24 11.06.43.jpg](https://qiita-image-store.s3.amazonaws.com/0/214031/231d1f27-7af9-369e-51ff-08d608d0f6aa.jpeg)



# １行空ける場合

```
Type error: Argument 1 passed to App\Http\Controllers\PostController::test() must be an instance of App\User, string given, called in /home/vagrant/code/Laravel/app/Http/Controllers/PostController.php on line 92

```

## 見やすい

![スクリーンショット 2018-05-24 11.08.05.jpg](https://qiita-image-store.s3.amazonaws.com/0/214031/eee4bd17-7f42-2517-e83a-7ae4909f0cea.jpeg)



# そんだけ
まあスタイルで回避するのが賢い方法なんだろうとは思いつつも。
ShellScript note #bash #zsh

## コマンドの返り値を変数に代入する方法

```shell
branch=$(git symbolic-ref --short HEAD)

if [ ${branch} = 'master' ]; then
  echo 'master'
elif [ ${branch} = 'develop' ]; then
  echo 'develop'
else
  echo 'other branch'
fi
```
ヒント: http://sweng.web.fc2.com/ja/program/bash/bash-store-command-result.html
[Other] One way to get IP location


### Configuration
Append this line to your `~/.bashrc` file.

```sh
iplocation() { curl ipinfo.io/$1; echo; }
```


### Usage

```
iplocation 172.217.161.227
```

will print something like this

```json
{
  "ip": "172.217.161.227",
  "hostname": "kix06s05-in-f3.1e100.net",
  "city": "Mountain View",
  "region": "California",
  "country": "US",
  "loc": "37.4192,-122.0570",
  "postal": "94043",
  "org": "AS15169 Google LLC"
}
```

*The [ipinfo.io](https://ipinfo.io) has times limitation for free usage.*
Laravelでランダムな文字列を生成する

![str_random.png](https://qiita-image-store.s3.amazonaws.com/0/7565/a7c7f15a-afb5-5ab6-9b1c-8c5baa7c18c8.png)

`str_random` ヘルパ関数を使います。第一引数に文字長を指定します。引数を省略した際のデフォルト文字長は16文字になります。

```php
$randomString = str_random(30);
```

## 参考リンク

* [Laravel Helpers](https://laravel.com/docs/5.6/helpers#method-str-random)

## 付録

内部実装は下記のようになっています。

```php
    public static function random($length = 16)
    {
        $string = '';

        while (($len = strlen($string)) < $length) {
            $size = $length - $len;

            $bytes = random_bytes($size);

            $string .= substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $size);
        }

        return $string;
    }
```

`random_bytes`関数はPHP7であれば内蔵の関数が使われますが、PHP5系ではこの関数が存在しないため、[paragonie/random_compat](https://github.com/paragonie/random_compat) パッケージがPolyfillとして使われます。
Docker for Windows で Redmine構築

### 1. Docker for Windows をインストール

---

Docker初心者ですが、Docker for Windows上にRedmineを構築しました。<br>
構築環境です。

| OS | x86-x64 | Memory |
| :--------: | :--------: | :--------: |
| Microsoft Windows 10 Pro | x64 | 4GB |


---

[Docker Store](<https://store.docker.com/editions/community/docker-ce-desktop-windows>) から”Docker CE for Windows (stable)”をインストールします。


![](https://i.imgur.com/izE8PdT.png)

---

### 2. Docker for Windowsを起動

---

自動起動設定にしていない場合、スタートメニューから、"Docker for Windows" を起動します。
![](https://i.imgur.com/uDlOpE8.png)

---

私の環境では、メモリ確保できずにDocker起動失敗したアラートが表示されました…。
![](https://i.imgur.com/TjeoLtv.png)

---

Settings...を開き、AdvancedタブのMemoryで "1024MB" に設定変更。起動しました。
![](https://i.imgur.com/dyOUDek.png)

---

### 2. ファイル永続化の設定

---

Settings...のShared Drivesタブで、共有したいドライブレターにチェックを付けます。
![](https://i.imgur.com/vn47t1u.png)

---

### 3. stack.ymlを作成

---

Docker Hubの "[OFFICIAL REPOSITORY(Redmine)](https://hub.docker.com/_/redmine/)" を参考にしました。
docker-composeでやりたかったのですが、サンプルに倣いました…。

---

```
services:
  # redmine
  # http://localhost:8080
  redmine:
    image: redmine
    restart: always
    ports:
      - 8080:3000
    environment:
      REDMINE_DB_MYSQL: db
      REDMINE_DB_PASSWORD: password
      REDMINE_PORT: 8080
    depends_on:
      - db
    links:
      - db:mysql
    volumes:
      - ../redmine/files:/usr/src/redmine/files
      - ../redmine/plugins:/usr/src/redmine/plugins

  # mysql
  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: redmine
    volumes:
      - ../mysql:/var/lib/mysql
```

---

### 4. コンテナを作成・実行

---

* コマンドプロンプトを起動し、"stack.yml"の格納先フォルダに移動します。
<br>

* "docker stack deploy -c stack.yml redmine"を実行します。<br> (もしくは、docker-compose -f stack.yml up)
![](https://i.imgur.com/XujJvOv.png)
<br>

---

* "docker ps"でコンテナの起動状況を確認します。<br>STATUSが"Up"になっていればOKです。
![](https://i.imgur.com/vo8emTy.png)


---

### 5. ブラウザでRedmineの起動確認

---

ブラウザで <http://localhost:8080> を開き、Redmineが表示されることを確認します。
![](https://i.imgur.com/zoXnMCS.png)

---

### 補足

---

* Redmineは、 "[sameersbn/redmine](<https://hub.docker.com/r/sameersbn/redmine/>)" のほうがよく使われているようです。<br>私は、「個人使用」と「Dockerに慣れる」という２点でOFFICIALを選択しました。

* Docker for Windowsのインストールで参考にさせていただいた記事です。
<https://qiita.com/furu8ma/items/c94df50bc23eb795c459>
すべての開いているターミナルのCWDを取得  - macos

癖で普段から沢山ターミナルを開いています。しかし、イベントでの発表とか、[ちょっとした都合](https://www.twitch.tv/nobolycloud)で自分の端末を映像配信・録音に使うなどのため、できるだけ負担を減らす目的で全部閉じることがあります。

で、閉じる前何やってたっけ。。があるのでダンプしておくことにしよう。

lsofでcwdつき出力して、あとは良くあるフィルタのワンライナーで実施。

```bash
$ for x in $(pidof bash); do lsof -a -d cwd -p $x ; done |  grep bash | awk '{print $9}' | sort | uniq
/Users/sawanoboly
/Users/sawanoboly/develop/src/git.example.com/kafka-docker
/Users/sawanoboly/develop/src/git.example.com/zookeeper-docker/stack
/Users/sawanoboly/develop/src/git.example.com/sawanoboly/kafka-miscs
/Users/sawanoboly/develop/src/git.example.com/sawanoboly/kafka-miscs/landloop
/Users/sawanoboly/develop/src/github.com/confluentinc/cp-docker-images
/Users/sawanoboly/develop/src/github.com/getshifter/base
/Users/sawanoboly/sandbox/kafka-leaning/fluentd
/Users/sawanoboly/sandbox/spot/opencv
/Users/sawanoboly/sandbox/spot/opencv/face_recognition/examples
/Users/sawanoboly/sandbox/spinnaker
```

脳内コンテキスト復旧の手助けになるよう。
超初心者が学ぶLinuxコマンド

## 自己紹介
2018卒未経験プログラマー
Linuxって何？黒い画面かっこいいっていうレベル

## 趣旨
現段階で使っている覚えたLinuxコマンドをメモ
覚えるたびにアップデート
初心者の方でも最初に必要なコマンドが把握しやすいかと思います。

##2018/5/24現在

ディレクトリ→フォルダという認識で操作中

`cd ディレクトリ/ファイル名` 今いるディレクトリから一個下のディレクトリまたはファイルに移動する
`cd ~` ホームディレクトリに移動する 
`mkdir ディレクトリ名`　ディレクトリを作成 
`ls` 下の階層にあるものをリスト表示
`ls -l`　縦でリスト表示
`pwd` 自分が今どの階層にいるかを表示 

学んだコマンドはもっとありますが使うのはとりあえずこんな感じ

ちなみによく使うショートカットキーは

`タブキー`　予測変換してくれてすごく便利
`↑ ↓`　　履歴を出してくれてすごく便利
`Ctrl + a`　カーソルを先頭に移動してくれてすごくラク

使うようになるたびに更新していきます！
Microsoft Graph を使ってみよう : 目次

先日 de:code 2018 で Microsoft Graph について話してきました。
折角なのでブログでもしばらく Microsoft Graph について書いていきます。

# 目次

- はじめに
 - [Microsoft Graph : 概要](https://qiita.com/kenakamu/items/22705c20a674793a3b21)
 - [Graph エクスプローラー](https://qiita.com/kenakamu/items/17905fe66345b8e3754b)

- 認証について
    - [Azure AD における認証概要](https://qiita.com/kenakamu/items/3ea0a8d149eb44a9b08b)
    - Azure AD v1 エンドポイント
        - [Azure AD v1 エンドポイントのユーザー委任を ADAL で行う](https://qiita.com/kenakamu/items/8805e44043077f969123)
        - [Azure AD v1 エンドポイントでデバイスのプロファイル認証を ADAL で行う](https://qiita.com/kenakamu/items/76ffbe6a6bd976edd2fc)
        - [Azure AD v1 エンドポイントのアプリケーション認証を ADAL で行う](https://qiita.com/kenakamu/items/1e4557dfcedeebe78e88)
        - [Azure AD v1 エンドポイントでの認証を Web アプリケーション (MVC) と ADAL で行う](https://qiita.com/kenakamu/items/7e670d5e1275e84bdd7c)
        - [Azure AD v1 エンドポイントでの認証を Web API と ADAL で行う](https://qiita.com/kenakamu/items/842d668e8178e176da52)
    - Azure AD v2 エンドポイント
        - [Azure AD v2 エンドポイントのユーザー委任を MSAL で行う](https://qiita.com/kenakamu/items/81c3dff2bbdc5562418e)
        - [Azure AD v2 エンドポイントのアプリケーション認証を MSAL で行う](https://qiita.com/kenakamu/items/81d8db61a9c5a352f959)
        - [Azure AD v2 エンドポイントでの認証を Web アプリケーション (MVC) と MSAL で行う](https://qiita.com/kenakamu/items/74d9613c7726fbdfc3eb)
        - [Azure AD v2 エンドポイントでの代理認証フローを Web API と MSAL で行う](https://qiita.com/kenakamu/items/1051a867af33860b6167)

- API 共通の使い方
    - [基本的な操作](https://qiita.com/kenakamu/items/52e16d1fde3232fdd9cb)
    - [データの変更履歴取得](https://qiita.com/kenakamu/items/63a8d5d136223ad1939a)
    - [変更通知 (Webhook)](https://qiita.com/kenakamu/items/e7dfd7a93ea6a3c631bf)
    - [拡張](https://qiita.com/kenakamu/items/c83f1e1982c0028b417b)
   
- Microsoft Graph リソース
    - [ユーザーとグループリソース](https://qiita.com/kenakamu/items/16848e33f31b0aaca872)
    - [メール、予定表、連絡先リソース](https://qiita.com/kenakamu/items/dd448b830a696a2b2132)
    - [ドライブとファイルリソース (OneDrive/SharePoint)](https://qiita.com/kenakamu/items/2a56d20f5eb74f0665d1)
    - [サイト、リスト、リストアイテムリソース (SharePoint )](https://qiita.com/kenakamu/items/61ff83a2b381bc3e9cdb)
    - [ノート リソース (OneNote) ](https://qiita.com/kenakamu/items/bec18034e78b369d2f6f)
    - [ブックやグラフリソース (Excel)](https://qiita.com/kenakamu/items/e073a99e3b6a93fada6b)    
    - [チームワークリソース (Teams)](https://qiita.com/kenakamu/items/28f13414893c19d77d85)
    - [レポートリソース](https://qiita.com/kenakamu/items/05a1d22e1dbe42836e50)
   
- インテリジェント機能
    - [人物と洞察リソース](https://qiita.com/kenakamu/items/d4af9aa91fb02deb2220)
    
- クロスデバイス体験
   - [クロスデバイス エクスペリエンス (プロジェクト Rome)](https://qiita.com/kenakamu/items/a6a70d175ed9b01c365a)
   
- Microsoft 他サービスとの連携
    - [PowerApps の Office テンプレート](https://qiita.com/kenakamu/items/01caf2082bbce7ab7900)
    - [Microsoft Flow トリガーとアクション](https://qiita.com/kenakamu/items/d0905363c9d2109cefc1)
    - [Azure ファンクション バインディング](https://qiita.com/kenakamu/items/23d6e35aec2704620cd1)
    
# ご意見・要望について
こんな情報が欲しい、ここが分からないなどあれば、コメントお願いします。
RubyでTCP/HTTPサーバを立てる

当投稿は主に以下のブログの翻訳です。
[Building a 30 line HTTP server in Ruby](https://blog.appsignal.com/2016/11/23/ruby-magic-building-a-30-line-http-server-in-ruby.html)

ブログにて詳細な説明をしています。
[RubyでHTTPサーバを立てる①（ブログ）](https://be-kan.hatenablog.jp/entry/2018/05/24/012445)

[追記]
この記事の続きを書きました。
合わせてご覧ください。
[RubyでHTTPサーバを立てる②（ブログ）](https://be-kan.hatenablog.jp/entry/2018/05/24/210834)
[RubyでHTTPサーバを立て、その上でRailsを動かす(Qiita)](https://qiita.com/be-kan/items/3867d4c317fc054d41bf)

ソースコードは[GitHub](https://github.com/be-kan/http_server_in_ruby)にアップしています。


以下、ソースコードのみ貼り付けます。

```ruby:tcp_server.rb
require 'socket'
server = TCPServer.new(5678)

while session = server.accept
  session.puts "hello time is #{Time.now}"
  session.close
end
```

```ruby:tcp_client.rb
require 'socket'
server = TCPSocket.new 'localhost', 5678

while line = server.gets
  puts line
end

server.close
```

```ruby:http_server.rb
require 'socket'
require 'rack'
require 'rack/lobster'

app = Rack::Lobster.new
server = TCPServer.new 5678

while session = server.accept
  request = session.gets
  puts request

  method, full_path = request.split(' ')
  path, query = full_path.split('?')

  status, headers, body = app.call({
    'REQUEST_METHOD' => method,
    'PATH_INFO' => path,
    'QUERY_STRING' => query
  })

  session.print "HTTP/1.1 #{status}\r\n"

  headers.each do |key, value|
    session.print "#{key}: #{value}\r\n"
  end

  session.print "\r\n"

  body.each do |part|
    session.print part
  end
  
  session.close
end
```

`http_server.rb` を起動してブラウザで見ると、以下のような見た目のはずです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/196673/614cd2e3-f44a-cb06-a2f7-038707c64d88.png)
リポジトリを共有しよう

#リポジトリを共有しよう

前回[エンジニアの必須であるgitとは何か](https://qiita.com/n_hirai/items/de895134194400110fd2)でリポジトリについて説明をしました。  
今回はリポジトリについて詳しく説明していきます。  

##ワークツリーとインデックス
　ワークツリーとはユーザーが実際に作業しているディレクトリのことです。  
インデックスというのは、リポジトリとワークツリーの間にありコミットする準備をするための場所のことです。インデックスがあることにより、ワークツリーに必要なファイルだけコミットすることができます。

![white.png](https://qiita-image-store.s3.amazonaws.com/0/259195/3e747de8-5317-8c46-83e1-02f28a8e69a2.png)


##クローンとプル
　前回プッシュについて説明しましたが、アップロードをするだけではなく他の人と共有することができます。  

　クローンというのは、リモートリポジトリを複製する操作のことです。誰かが変更を行ったリモートリポジトリがあれば、それをまるごと複製して作業することができます。また、クローンしたローカルリポジトリは変更履歴も複製されています。  

　プルというのは、リモートリポジトリからローカルリポジトリを更新する操作のことです。他の人がプッシュした変更内容を取り込むことが出来ます。
　
##まとめ
　リポジトリの共有は自分がアップロードするだけではなく、他の人のファイルも簡単に共有できるので、とても便利なものです。  
　また、インデックスがあることで不必要なファイルと必要なファイルの管理もできるので共有する上での混乱も防げますね。
　
##参考文献
[サルでもわかるgit入門](https://backlog.com/ja/git-tutorial/)
gulp実行時エラーの解決法

node.jsのバージョンをあげたことにより、gulpを走らせるとエラーになることが度々あった。

1、node_modulesを削除して「npm install」し直す。
↑その後gulpで動きはするが、PC再起動後などに再びエラーが発生することがあるので、2の方法も試す。

2、「npm rebuild node-sass」してsassをビルドし直す。(例としてnode-sassを出したが、つまりverが古そうなパッケージをrebuild)
openstack 頻出コマンド一覧

## はじめに

完全に個人用のメモです。
間違っているところがあったら教えてください。

## user

### list

一覧

## network

### list

一覧

### create NETWORK_NAME

ネットワークの作成

## subnet

### create

作成

## image

### list

一覧

### show IMAGE

詳細

### delete IMAGE

削除

### set IMAGE

更新

## flavor(?)

CPU・メモリ・ディスク

## server 

### create --nic net-id=NETWORK_NAME,v4-fixed-ip=IP_ADDRESS

dhcpじゃなくてstaticで振りたいとき

## key

秘密鍵

## security

### group

セキュリティグループ

## router

### create ROUTER_NAME

ルータ作成

## その他

### ・neutron

openstackのコンポーネントの一つであるneutronを直接叩くコマンド

**[subnet-list]**

サブネット一覧
（最新バージョンではopenstack subnetコマンドでも可能）

**[router-create]**

ルータを作成する

### ・ovs-vsctl

バーチャルスイッチを制御するコマンド

**[show]**

詳細

### ip netns exec NETWORK_ID ip a

NETWORK_ID：VSwitchでネットワークを切り分けた時の各ネットワークの識別子
NETWORK_IDの中でip aを実行
リスト内包表記内でsuper()の引数は省略できない

# リスト内包表現で、引数なしのsuper()を使うとTypeErrorになる

```test1.py 
>>> class A:
...     def f(self):
...         return None
...
>>> class B(A):
...     def g(self):
...         return [super().f() for i in range(1)]
...
>>> B().g()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in g
  File "<stdin>", line 3, in <listcomp>
TypeError: super(type, obj): obj must be an instance or 
subtype of type
```

# ジェネレータ式でも同じ
```test2.py 
>>> class A:
...     def f(self):
...         return None
...
>>> class B(A):
...     def g(self):
...         return (super().f() for i in range(1))
...
>>> B().g()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in g
  File "<stdin>", line 3, in <listcomp>
TypeError: super(type, obj): obj must be an instance or 
subtype of type
```
また、python2では、引数なしで`super()`は使用できないので、そもそもこの問題は発生しない。
# 原因
おそらく原因は、リスト内包表記内(または、ジェネレータ式)では、関数内と別スコープになっているからと推測できる。

```test3.py
>>> class A:
...     def f(self):
...         return None
...
>>> class B(A):
...     def func_scope(self):
...         return locals()
...     def comprehension_scope(self):
...         return [locals() for i in range(1)]
...
>>> B().func_scope()
{'self': <__main__.B object at 0x6ffffc60550>}
>>> B().comprehension_scope()
[{'i': 0, '.0': <range_iterator object at 0x6ffffcd2870>}]
```
蛇足だが、リスト内包表記内のスコープでは'.0'でiteratorにアクセスできるようだ。
(Pythonの仕様か、CPythonがこう実装しているだけなのかは不明)

# 対策
引数で対象のクラス、オブジェクトを指定すれば、関数スコープ以外でも使用可能なので、問題なくに使用できる。

```test4.py
>>> class A:
...     def f(self):
...         return None
...
>>> class B(A):
...     def g(self):
...         return [super(self.__class__, self).f() for i in range(1)]
...
>>> B().g()
[None]
```
パクリかどうかのチェックリスト

納品物が、具体的にパクリかどうか認定する、もしくは世間一般的に「せめてID名とかは変えろよ」というモラルのしきい値が具体的に知りたいです。

数行の短いコードは変数名やオブジェクト名くらいは変える
オープンなものはライセンスと照会する

くらいはわかるのですが、オープンになっていないものとか、どうすればいいのか。

厳密にいうと、アルゴリズムの特許チェックとかあるのでしょうけど、こういう検品スキルってどこかに体系化、もしくはそれを専門にやっているところってあっても良さそうなものですけど、どうなのでしょうか。
【初心者向け】Linuxについての簡単なまとめメモ

# 前書き
Linuxについて勉強したことを簡単にメモ。
概要・簡単なLinuxの歴史・広義のLinux、狭義のLinux・Linuxディストリビューションとは・実際のコマンド
などをメモしています。
今後追記していく予定です。


補足、修正あったらぜひお待ちしております。

# Linuxとは
リーナス・トーバルズがUNIXというOSを真似て、一から作ったOSのこと。
大きな特徴は、「**オープンソースであること**」。利用するのもカスタムするのも無料で自由。
だから、サーバー用のOSにはLinuxが使われてることが多い。
またいわゆる組み込み機器である身近な電子機器にも搭載されることが多い。その場合、サーバーで使われるLinuxとは区別して「**組み込みLinux**」と呼ぶ。

補足：オープンソースではあるが、Linuxをベースにした商業用のOSもある。

# 簡単なOSの歴史
元々は「**Multics**」という今のOSと同じような動きを想定したOSが開発された。
しかし、昔のPCのスペックでは足りなかったため、単一の処理だけをするためのOSとして、「**UNIX**」が開発された。その後さまざまOSが登場していくが、UNIXをベースにしたものがほとんど。
そんな中、UNIXみたいな動きをするOSを目指し、中身を一から作りあげた天才が現れた。それが「**リーナス・トーバルズ**」。リーナスが作ったUNIXだからLinux。
外面を真似しようとしただけで中身は全く違うものだから、著作権には引っかからなくて、全部無料で公開できた。

# 広義のLinux, 狭義のLinux
####**広義のLinux**
OS全体のこと。Linuxとして動くもの全てを合わせた言い方。または、Linuxを利用できるようにまとめ上げた配布形態のこと。
別の言い方をすると、「**Linuxディストリビューション**」ともいう
例 ） ubuntu、CentOS、Debian、Fedora 等

####**狭義のLinux**
「**Linuxカーネル**」のこと
ハードウェアとソフトウェアの中立ちをしてくれる、OSとして動く大元の部分。

# 実際のコマンド操作（ターミナル）
###ターミナル操作についてのメモ
操作する時のイメージは、**階層の移動**（イメージというかその通りなんですが）。
自身が今いる階層を「**.**」で表すことができ、一個上は「**..**」。
常に自分がどの階層のどのフォルダにいるのかを把握しないと操作できない。

GUIの方が直感的でわかりやすく、誰でも操作できるという強みがあるが、ターミナルのコマンドでの操作の方が膨大な処理を行うのがたやすい。
それぞれのコマンドに -（ハイフン） + なんか　でオプションの機能をつけることができる。

###よく使う代表的なコマンド

## **ls**
listの略。現在自分がいる階層のデータを表示する。-a コマンドをつけると、隠れているファイルもすべて表示。
オプション -l
もっとたくさん見れる。
ailias ll = ls -l
ってしておくと使いやすい（bashではもともとそういう設定になっている。）

## **pwd**
print working directoryの略。現在位置を表示するコマンド。一番親の階層から、自分がいる階層までのパス（流れ・繋がり）を表示する。

## **cd**
change directoryの略 ディレクトリの移動に使う。基本的にディレクトリは縦に繋がっている場所への移動しかできないので、行きたいディレクトリの親ディレクトリに行ってから、再度行きたいディレクトリに向かう。みたいな動きになる。 . は階層を表しているので cd . は動かず、cd .. で一階層上に行ける。

## **mkdir**
make directoryの略 新しくディレクトリを作るコマンド。mkdr ディレクトリ名

## **mv**
：moveの略。 名前の変更またはファイルの移動に使う。

## **rm**
removeの略。削除用のコマンド。mvと間違えて打つと悲しいことになる。ディレクトリを消すときは -rコマンド を追加

## **cat**
catenateの略。ファイルの中身を閲覧する。

## **du**
disk used
ディスク容量を調べるために用いるコマンド
オプションで単位指定できる。
-b：バイト表示
-k：キロバイト表示
-m：
-g
-h可変
システム全体を見たい場合はスーパーユーザーで行う

## **df**
disk free
ファイルシステム（パーティション）ごとの空いているディスク容量を確認するコマンド。



## **cp**
copy

ファイルをコピーするコマンド。

## **grep**
global regular expression print

ファイルや標準入力から正規表現でマッチする行を抜き出すコマンド。
ファイル内に記述している内容から検索したいときに用いる。
ファイルの中身検索用
### **git grep**
gitで管理しているリポジトリの範囲内限定で使うことができるgrep
検索範囲が狭まっているため、圧倒的に早い。

## **find**
ディレクトリの中身検索用。
AWS Direct Connect GW 設定してみたよ


DirectConnect の記事は結構あるんですがGWまで含めた記事ってのが少ないようなので
設定した手順を共有します。DCGWとっても便利ですので是非！

# Gatewayの作成
なにはともあれまずはDCGW作成します。ASNを間違えないように。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223740/2e60e8b2-c3dd-1ad2-5e7e-73c4333f957b.png)


available になった事を確認
![image.png](https://qiita-image-store.s3.amazonaws.com/0/223740/b52387d1-5e5c-d0e0-49b3-91b3ec483cda.png)


自動的に他のリージョンにもDCGWのコピーが作成されます(以下はバージニアの例)ので各リージョンのVPCはこっちに繋ぎましょう。自分はFrankfurtのリージョンを使うのでそっちを利用

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223740/63c32d89-d902-48a0-67eb-da1bf3528acb.png)

# VIF(仮想インターフェース) の接続

ベンダが事前に用意してくれているVIF の存在を確認し、Standby側を承認します

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223740/1d2c8fdc-8b8f-0d7e-3841-4021f12ebd04.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/223740/59242ab2-5e7d-fe3a-703e-6ba5b39ee903.png)



DCGWを接続先として指定(ここをミスると結構面倒らしいので慎重に..)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223740/e2b347f2-0848-9ae9-2a9e-90e320d7712b.png)

Pending->down state になるので 10分程待ちます

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223740/f18da2e6-cc20-737a-e16d-e302b6c81c2f.png)

Available になりました

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223740/40129663-0442-f4bd-386a-d28b3c4b06f5.png)


#各リージョンのVPCをDCGWに接続

DCGWに繋ぐ各リージョンに仮想プライベートGWを作って

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223740/a8ed69aa-4c49-7fbe-001f-1926b64a2e27.png)

VPCのルートテーブルを上で作ったVPGW に0.0.0.0/0のルーティング先として追加

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223740/7a3b1df9-071d-c583-57ea-7d6503c9df1c.png)

できあがった仮想プライベートGW をDCGWに

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223740/687eac78-ec92-bca1-50eb-9181d37d4996.png)

関連付けます

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223740/257716ed-9482-6145-b676-3c94ea1c6e32.png)

ちょっと待ち時間ができるので...

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223740/6d56815e-170f-3bd1-b8df-04a8093dab1a.png)

同じ要領でFrankfurt の PrivateGWを関連づけておきます

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223740/7d71c256-0cf9-72cc-4cdc-212e12019cb1.png)

#Active 側 VIF の接続

ひととおり設定終わったので、Active 側の VIFをアタッチ

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223740/b0706aa9-4e89-773c-ac05-4709cf86fab9.png)

設定としてはここまでで終了です。

#動作確認

各リージョンでテスト用のEC2を立てて社内からpingで疎通確認。
ssh接続できてよしよしと思ったころには

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223740/1277dfd9-52ea-f711-c2d6-d33265947acb.png)

VIFアクティブ側もavailable になってました。めでたしめでたし。

#追記:転送速度について

FrankfurtにEC2立てて社内LAN(物理的には南東北の某市内)から圧縮データを数回SFTPしてみました。結果は以下の通り

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223740/b540cd95-4681-c7b1-4175-ae0e12d05c6b.png)

DirectConnectは100Mbpsベストエフォート契約にしていますが
上り下り共に40Mbps前後ってのはかなりいい感じじゃないでしょうかね！
親ViewのサイズいっぱいにAutoLayoutを設定するUIViewのextension

addSubViewをしたけど、iPhoneの画面サイズによって正しく表示されないことがあると思います。
これを解決すべく、AutoLayoutを簡単に設定できるextensionを書いたので、メモです。

# コード

``` AutoLayout.swift
import UIKit

extension UIView {
    
    /// Viewいっぱいにオートレイアウト
    func autoLayout(to toView: UIView) {
        self.translatesAutoresizingMaskIntoConstraints = false

        self.topAnchor.constraint(equalTo: toView.topAnchor).isActive = true
        self.bottomAnchor.constraint(equalTo: toView.bottomAnchor).isActive = true
        self.leftAnchor.constraint(equalTo: toView.leftAnchor).isActive = true
        self.rightAnchor.constraint(equalTo: toView.rightAnchor).isActive = true
    }
}
```

# 使い方

``` 
let view = UIView()
self.addSubview(view)
view.autoLayout(to: self)
```
Qiitaの様なサービス作成中 はてなブログインポート 連載(4)

## 基本情報

* [次に作りたいQiita、dev.toの様なサービスについて](http://alphabrend.hatenablog.com/entry/2018/05/07/090803) で書いたサービスを開発中です。
* [前回の記事](https://qiita.com/dala00/items/93f96dfbf63e71765562)

## はじめに

冒頭の記事にも書いているように、僕自身はサービスが公開できる状態になったらはてなブログからそのサービスに引っ越そうと思っています。また、引っ越す予定のない方も、カノニカルタグに対応しているので自分のブログに記事を掲載したまま、このサービスにも同じ記事を投稿できるようになっています。（SEO的にも問題なし）

ただ、手動でやるならやっぱり手間で微妙ですので、インポート機能は必須かなと思っており、とりあえず自分が持っていて且つAPIが提供されているはてなブログについては自動で取り込む機能を実装しました。

## 導入

はてなのAPIは色々と導入方法があるのですが、今回はOAuthを利用したログイン＆インポートを行います。

LaravelのSocialiteで既に認証機能を実装してるので、下記を参考にしてSocialiteにはてなのドライバを追加することでログイン＆トークンを取得できるようにしました。むちゃくちゃ簡単にできました。

[Laravel Socialite の独自ドライバを実装する](https://localdisk.hatenablog.com/entry/2015/12/03/142656)

## 記事の取得

事前準備はできたので実際に記事を取得していきます。上記で紹介した記事に書かれているHatenaServerというクラスに下記のような取得処理を実装しました。

```php
    public function getBlogEntries($token, $tokenSecret, $id, $blogId, $page = null)
    {
        $tokenCredentials = new TokenCredentials();
        $tokenCredentials->setIdentifier($token);
        $tokenCredentials->setSecret($tokenSecret);

        $url = "https://blog.hatena.ne.jp/{$id}/{$blogId}/atom/entry";
        if ($page) {
            $url .= "?page={$page}";
        }
        $client = $this->createHttpClient();
        $headers = $this->getHeaders($tokenCredentials, 'GET', $url);

        try {
            $response = $client->get($url, [
                'headers' => $headers,
            ]);
        } catch (BadResponseException $e) {
            $response = $e->getResponse();
            $body = $response->getBody();
            $statusCode = $response->getStatusCode();
            throw new \Exception(
                "Received error [$body] with status code [$statusCode] when retrieving token credentials."
            );
        }

        $xml = simplexml_load_string((string) $response->getBody());
        $json = json_encode($xml);
        return json_decode($json, true);
    }
```

最後の３行がすごいですよね。下記で紹介されていました。（ただしあとで見てみたところ、一部消えてしまうパターンがあるようです）

[simplexml_load_file(simplexml_load_string) を配列に変換する](https://qiita.com/ka_to/items/54fe4d5bb655841f85d8)

これで記事はもう取れてしまうので、あとはLaravelにコマンドを追加し、実際のサーバーでは延々とcronで回していけば自動的に最新の記事をインポートしていくことができます。

上記のメソッドを参考にちょこっと変更してPUTとかすれば記事を更新したりする機能を作ることもできます。
（まあでもはてなブログのAPIはあまりサービスに組み込むことはないと思うのでBASIC認証でちゃちゃっと実装することの方が多いかもしれませんね）

## 次回

多分サーバーへのデプロイ＆αバージョン公開