OmniAICreator/Qiita-1.07M huggingface dataset:
Java length（）とlengthメソッド

#はじめに
学習用のメモになります。

#length（）とlengthメソッド
[詳しくはこちら](https://flytech.work/blog/11725/)

##1.length()
length()メソッドは`文字列の長さ`を取得するメソッドとなります。

length()の構文は下記となります。

```Main.java
String.length()
```
length()メソッドは、文字列の長さを返します。
つまり半角、全角関係なく文字列の文字数を返してくれます。

##2.length
lengthは、`配列型の長さ(要素の数)`を格納するフィールドというデータを格納する変数というものになります。
配列型の長さを格納するものと思っていれば大丈夫です。

lengthの構文は下記となります。

```Main.java
int length = 配列変数名.length
```
lengthは、配列に適用できる最後の変数です。
長さ変数を使用して、配列のサイズを取得できます。
CSS postion absolute / relative

##positionプロパティ
`positon` = `要素を配置する基準を指定するプロパティ`
基準の場所を区別する為に、`absolute(絶対位置)`と`relative(相対位置)`がある。

##absolute(絶対位置)
`移動するときの基準がウィンドウ、もしくは親要素になる。`
absoluteで指定した場合、`他の要素を無視して左上（top:0、left:0の位置）が基準になる。`

```
.クラス名 or #id名 {
    position: absolute;     
}
```

##relative(相対位置)
`移動するときの基準が元々いた位置(positionを記述する前に配置されていた場所)になる。`
親要素にrelativeを指定することで、親要素の位置を基準に子要素を移動させることもできます。

```
.クラス名 or #id名 {
    position: relative;     
}
```

参考元はこちら
こちらのサイトにて画像でわかりやすく説明されていますので是非ご覧ください。
（https://uxmilk.jp/63409）
Rubocop 静的コード解析ツール



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666271/6eca3c6c-54cf-ada0-75a8-be6982c0240e.png)

#Rubocopとは
[Rubocop](https://github.com/rubocop-hq/rubocop)とはRubyコードが
「コーディング規約どおりに書かれているか」をチェックする静的コード解析ツール(Gem)です。
解析するコマンドを実行することによって「コードの長さ、無駄なスペース、インデント,メソッド名の変更...」
などのチェックを行ってくれます。
あくまでもRubocopの指摘はアドバイスなので厳しすぎるチェックは設定で変更が可能です。

##所感
Webエンジニア１年生ということでまだまだ綺麗なコードを書くことが出来ず、
インデントのずれや半角スペースなど残したままPRを出してしまうことがあります。
以下でも述べますが、Rubocopを導入することで綺麗なコードにすることが出来ます。
綺麗というか、どのファイルもコーディング規約に従い統一されたコードになるので自分以外でも目の通しやすいコードになるはずです。
先輩エンジニアにコードを見てもらう前に一度試してはどうでしょうか！


##導入してよかった点
* エンジニア初学者からすると”綺麗なコード”というものを実感できる

* PR提出前に修正コマンドを実行することにより開発途中の乱れたコードの修正してくれる

* PRを提出した際にレビューコストを少なくできる 

* コードが統一されるので"別のファイルでは記述が違う"ということを避けられる


##インストール

```
#Gemfileに追加してください
#開発環境のみで利用します

group :development do
  gem 'rubocop', require: false
  gem 'rubocop-performance', require: false
  gem 'rubocop-rails', require: false
  gem 'rubocop-rspec'
end
```


##使用したコマンド

```

$ bundle exec rubocop

 # プロジェクトの中のrubyファイルを全てチェックしターミナルに出力する

$ bundle exec rubocop --auto-correct 

 # 自動修正

$ bundle exec rubocop --auto-gen-config 

 # 規約違反の一覧が表示される.rubocop.todo.ymlが生成される
 # .rubocop_todo.ymlに警告を一旦退避
 #　警告内容が.rubocop_todo.ymlに記述される

```


## 修正の流れ

1.

```
$ bundle exec rubocop --auto-correct 
```
まずは自動で修正してくれる箇所を上記コマンドで修正する

2.

```
$ bundle exec rubocop
```
自動修正が終了次第、上記コマンドを実行し警告されるファイルをターミナルに出力する
出力されたファイルの修正が終了次第、次の作業に取り掛かる(PR提出するなど)

3.　１、２を繰り返すことで自分のコーディング規約にそったコードが保たれる
　　コーディング規約は.rubocop.ymlファイルに記述する
  　　RuboCopの挙動は.rubocop.ymlで設定する

##.rubocop_todo.yml ファイル

開発途中からRubocopを導入すると大量の違反ファイルが指摘されます。
なので一旦既存のコードは無視するため、このファイルが存在します。
回避しているだけで違反している内容なので”.rubocop_todo.yml”ファイルを削除しても違反が指摘されないこと目指しましょう。

```
$ bundle exec rubocop --auto-gen-config 
```
上記コマンドで”.rubocop_todo.yml”ファイルが作成されます。




###例).rubocop.yml
✳︎以下ファイルは見やすいように短縮してあります

```
inherit_from: .rubocop_todo.yml


require:
  - rubocop-rails
  - rubocop-rspec
  - rubocop-performance

Rails:
  Enabled: true

Rails/ActiveRecordCallbacksOrder: 
  Enabled: true

Rails/AfterCommitOverride: 
  Enabled: true

Rails/FindById: 
  Enabled: true


# 環境の種類
Rails/UnknownEnv:
  Environments:
    - production
    - staging
    - development
    - test

Rails/NotNullColumn:
  Enabled: false

AllCops:
  TargetRubyVersion: 2.6.3
  DisplayCopNames: true
  Exclude:
    - 'db/schema.rb'
    - 'vendor/**/*'
    - 'bin/**/*'

# クラスの行数
Metrics/ClassLength:
  Max: 100

# モジュールの行数
Metrics/ModuleLength:
  Max: 100

# ブロックの行数
Metrics/BlockLength:
  Exclude:
    - 'spec/**/*'

# メソッドの行数
Metrics/MethodLength:
  Max: 25

# メソッドの複雑度
Metrics/AbcSize:
  Max: 25
```
Windowsの隠し機能？GodModeについて


この記事は、IIT AdventCalendar 10日目の記事です。
初めての投稿なので、自分の知っている小技を紹介します。

##GodModeとは
GodModeとは、~~神に授けられた~~Windowsにある隠し機能のことです。
通常はコントロールパネルの各項目にある各種設定を、一つのフォルダ上に一覧表示できる隠し機能のことです。
Windows 10 以前のバージョンにも搭載されていた機能ですが、Windows 10 のデフォルト設定では表示されないため、特殊な操作をして表示させる必要があります。

##作成方法
まずは、デスクトップ上で右クリック→新規作成→ショートカット　でショートカットを作成します。
![スクリーンショット 2020-12-01 114409.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869435/f67c1737-cbec-168c-8ef1-2a24ff1e3b6f.png)
![スクリーンショット 2020-12-01 114508.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869435/a9fa128d-d7f3-63aa-1ca1-7f40376cbb44.png)

画面のとおりに進めます。
![スクリーンショット 2020-12-01 130939.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869435/6c99c8fd-7645-0f56-8cad-234f5a5f00a1.png)
「項目の場所を入力してください：」のところに、次のコマンドを入力します。

**```explorer.exe shell:::{ED7BA470-8E54-465E-825C-99712043E01C}```**
「次へ」を押します。
![スクリーンショット 2020-12-01 131054.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869435/ef6fb751-5480-159e-c5f1-f2654492ef58.png)

次に名前をつけることができます。
~~「神に授けられた設定」という名前に設定しましょう。~~　好きな名前に設定してください。

「完了」を押すと、ショートカットが作成されました！
![スクリーンショット 2020-12-01 131118.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869435/f72529e4-09c4-d478-94d5-5df953df2978.png)




##実際に見てみる
![スクリーンショット 2020-12-01 131247.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869435/abb3c394-f0d1-f1e8-7ac5-6ffabbe55707.png)

このように、一覧でズラッと項目が表示されました。

試しに、「ファイアウォールの状態の確認」を開いてみます。
![スクリーンショット 2020-12-01 132129.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869435/e49e64c3-acae-55f2-d2b4-0b48d4ba43c1.png)

すると、しっかりとコントロールパネルの設定項目へ行くことができました。
![スクリーンショット 2020-12-01 132153.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869435/c5bbd9e5-f396-1b0b-b294-b68d5366c9d2.png)

設定項目が一覧で表示されるので便利ですね！



 
##【おまけ】ショートカットのアイコンを変更する方法

これはすでに知っている方も多いと思いますが、おまけとして紹介します。

変更したいショートカットを右クリック→プロパティを選択
![スクリーンショット 2020-12-01 132938.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869435/7dc62353-b82b-369d-caa8-301ba8c15626.png)

すると、~~「神に授けられた設定」の~~プロパティ画面が開きました。

上の項目で「ショートカット」を選択します。すると、中央のやや下に「アイコンの変更」という項目がありますね。

![スクリーンショット 2020-12-02 133856.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869435/43329c76-d243-4a4e-d856-cac646407d55.png)

アイコンの変更のダイアログが出てきました。
すでにアイコンの画像がいくつか表示されていますが、数が少ないですね。
そこで、Windowsで使用されているアイコンをもっと表示させてみましょう。





Windows 10の様々なアイコンは「.DLLファイル」に格納されています。.DLLファイルはWindows10の以下のフォルダーに格納されています。これには２つの「.DLL」ファイルがあります。2つのどちらかお好みの.DLLファイルをコピペし、アイコンを選びましょう。
**```%SystemRoot%\System32\imageres.dll```**
**```%systemRoot%\system32\shell32.dll```**

![スクリーンショット 2020-12-02 134509.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869435/0522037d-9b6e-3c20-3c77-4cc5aebf491e.png)

たくさん表示されましたね。
では好きな画像を選択して、OKを押します！

![スクリーンショット 2020-12-02 134619.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869435/7037159a-44f2-82b2-8b41-b46aad2378a6.png)
適用されました！

この方法で簡単にショートカットのアイコンを変更することができます！
みなさんもチャレンジしてみてください！
PC-98 QuickCでグラフィック描画してみた

#環境
- QuickC 2.0
- Neko Project Ⅱ x64

#ソース

```lineart.c
#include <conio.h>
/*#include <machine.h>*/
#include <math.h>

void init();
int point(int x, int y);
void pset(int x, int y, int c);
void line(int x0, int y0, int x1, int y1);
void transform(int x, int y, float c, float s, int* px, int* py);

long gvram[] = { 0xa8000000, 0xb0000000, 0xb8000000, 0xe0000000 };

int main()
{
	float rad, c, s;
	int x0, y0, x1, y1;
	int i, t;

	init();
	for (t = 0; t < 360; t += 45) {
		rad = 3.14159f * t / 180;
		c = cos(rad);
		s = sin(rad);
		for (i = -100; i <= 100; i += 2) {
			transform(i, -100, c, s, &x0, &y0);
			transform(-100, -i, c, s, &x1, &y1);
			line(x0, y0, x1, y1);
		}
	}
	return 0;
}

void init()
{
	short far* lp;
	int i, j;

	outp(0x6a, 0x01);	/* 16 color */
	outp(0xa2, 0x4b);	/* G-GDC CSRFORM */
	outp(0xa0, 0x00);	/* line scale */
	outp(0x68, 0x08);	/* 400 line */
	outp(0xa2, 0x0d);	/* G-GDC START */

	for (i = 0; i < 16; i++) {
		j = i << 1;
		if (j > 15) j = 15;
		outp(0xa8, i);	/* palette# */
		outp(0xaa, i);	/* G */
		outp(0xac, i);	/* R */
		outp(0xae, j);	/* B */
	}

	outp(0x7c, 0x80);	/* GRCG=ON TDW(Tile Direct Write) */
	for (i = 0; i < 4; i++) {
		outp(0x7e, 0x00);	/* GRCG tile */
	}
	lp = (short far*)0xa8000000;
	for (i = 0; i < 40 * 400; i++) {
		*lp = 0;
		lp++;
	}
	outp(0x7c, 0x00);	/* GRCG=OFF */
}

int point(int x, int y)
{
	long offset = 80 * y + (x >> 3);
	char mask1 = 0x80 >> (x & 7);
	char far* lp;
	int c = 0;
	int i;

	for (i = 3; i >= 0; i--) {
		c <<= 1;
		lp = (char far*)(gvram[i] + offset);
		if (*lp & mask1) {
			c |= 1;
		}
	}
	return c;
}

void pset(int x, int y, int c)
{
	long offset = 80 * y + (x >> 3);
	char mask1 = 0x80 >> (x & 7);
	char mask0 = ~mask1;
	char far* lp;
	int i;

	for (i = 0; i < 4; i++) {
		lp = (char far*)(gvram[i] + offset);
		if (c & 1) {
			*lp |= mask1;
		} else {
			*lp &= mask0;
		}
		c >>= 1;
	}
}

void line(int x0, int y0, int x1, int y1)
{
	int dx, dy, sx, sy, err, e2, c;

	dx = x1 - x0;
	if (dx < 0) dx = -dx;
	dy = y1 - y0;
	if (dy < 0) dy = -dy;
	sx = (x0 < x1) ? 1 : -1;
	sy = (y0 < y1) ? 1 : -1;
	err = dx - dy;
	for (;;) {
		c = point(x0, y0) + 1;
		if (c > 15) c = 15;
		pset(x0, y0, c);
		if (x0 == x1 && y0 == y1) break;
		e2 = err << 1;
		if (e2 > -dy) {
			err -= dy;
			x0 += sx;
		}
		if (e2 < dx) {
			err += dx;
			y0 += sy;
		}
	}
}

void transform(int x, int y, float c, float s, int* px, int* py)
{
	*px = 320.5f + x * c - y * s;
	*py = 200.5f + x * s + y * c;
}
```

#コンパイル&リンク
##QuickC
`qcl /c lineart.c`
`link lineart;`

##LSI C-86試食版

```c
/*#include <conio.h>*/
#include <machine.h>
```

`lcc lineart.c -lmathlib`

![lineart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257554/db95352d-4b58-3313-5f95-505ff22e212d.png)
docker-composeでnginxを立てる際に環境変数を使う方法

docker-composeでnginxを立てる際に、confファイルに環境変数を使う方法について解説します。nginxのversionが1.19より前と後でやり方が異なるので注意してください。

## nginx:1.19以降
[1.19以降では公式にサポートされている方法を使うことができます。](https://hub.docker.com/_/nginx)
以下のようなdocker-compose.ymlを例に用います。

```yml:docker-compose.yml
version: "3"
services:
  nginx_service:
    container_name: nginx
    image: nginx:1.19-alpine
    volumes:
      - ./templates:/etc/nginx/templates
    environment:
      - PORT=8080
    ports:
      - 3000:8080
```

デフォルトではコンテナ内の`/etc/nginx/templates/*.template`が読み込まれ、環境変数をセットした結果が、`/etc/nginx/conf.d`に吐き出されます。

例えば、`default.conf.template`を以下のように用意します。

```:templates/default.conf.template
server {
  server_name         localhost;
  listen              ${PORT};
}
```

`docker-compose up --build`を実行すると、上記ファイルがコンテナ内の`/etc/nginx/templates`にマウントされます。

コンテナ内の`/etc/nginx/conf.d`を確認すると、以下のように環境変数がセットされたファイルが出力されていることが確認できます。

```:/etc/nginx/conf.d/default.conf
server {
  server_name         localhost;
  listen              8080;
}
```

## nginx:1.19以前

1.19以前ではenvsubstコマンドを使用して、自前で環境変数をセットする必要があります。
以下のようなdocker-compose.ymlを例に用います。上記との違いは、commandでinit.shを実行していることです。

```yml
version: "3"
services:
  nginx_service:
    container_name: nginx_1.19_earlier
    image: nginx:1.18-alpine
    volumes:
      - ./nginx:/etc/nginx/conf.d
    environment:
      - PORT=8080
    ports:
      - 3000:8080
    command: sh /etc/nginx/conf.d/init.sh
```

`default.conf.template`を以下のようにします。これは上記と変わりません。

```:templates/default.conf.template
server {
  server_name         localhost;
  listen              ${PORT};
}
```

`init.sh`を以下のようにします。
envsubstコマンドで`default.conf.template`に環境変数をセットして、結果を`default.conf`に出力します。nginxを立ち上げるコマンドも忘れずに記載します。

```sh:templates/init.sh
#!/bin/sh

envsubst '$$PORT' < \
  /etc/nginx/conf.d/default.conf.template > \
  /etc/nginx/conf.d/default.conf

nginx -g 'daemon off;'
```

`docker-compose up --build`を実行すると、コンテナ内の`/etc/nginx/conf.d`で環境変数がセットされたファイルを確認できます。

```conf:/etc/nginx/conf.d/default.conf
server {
  server_name         localhost;
  listen              8080;
}

```

説明に使用したファイルは以下のレポジトリを参照してください。
https://github.com/happyfukumoto/nginx_on_dockercompose
非管理者で実行した際に管理者として再実行するPowerShellスクリプト

この記事はPowerShell Advent Calendar 2020 の 2 日目です。

PowerShellスクリプトを管理者で実行させようとした際、右クリックからは直接出来ず、
一度PowerShellのターミナルを管理者で実行させてフォルダを移動して…としないといけなくて少し(結構)面倒だと思います。
右クリック→PowerShellで実行をした際に、非管理者の場合に管理者として立ち上げなおすことが出来れば楽なのでは？
ということで書いてみました。

# 経緯
定期的にPowerShellスクリプトを実行する必要があるけど、そのスクリプトは管理者権限じゃないと動かないのであった。
ターミナルを管理者で起動させてフォルダを移動してスクリプトを実行…は面倒なのでスクリプト自体に仕込んでしまうことにした。

# やりたいこと
- PowerShellスクリプト(.ps1)を右クリック→PowerShellで実行だけで管理者として実行させたい
- UACは出てもよい
- ファイルを複数に分けない
    - 別途バッチ(.bat)を用意し、これを右クリック→管理者として実行すればOK…みたいなのはナシ
- ある程度汎用性とか使い回しが出来るとなお良い

# 環境
PSVersion 5.1 での動作を確認しています。
コードの内容から、PSVersion 3.0 以降であれば動作します。[^1]
[^1]: $PSCommandPathがPSVersion 3.0以降を要求するため…ではあるのですが、MSサポート範囲内に含まれるOSであれば既に3.0以降な気がします。

# コードの実装
スクリプトファイルの先頭付近に以下のコードを記載します。

```PowerShell
if(!(([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator"))){
    Start-Process -FilePath "powershell.exe" -ArgumentList "-File $PSCommandPath" -verb runas;
    ### 非管理者で実行させたい内容があればこのあたりに記述 ###
    exit;
}
### 以降、管理者で実行させたい内容を記述 ###
```

# コードの説明
`if(!(([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")))`
自分自身が管理者(Administrator)権限を保有しているか確認します。
__!__で反転させているので、保有していない場合がTrueとなり、以下のコマンドに続きます。


`Start-Process -FilePath "powershell.exe" -ArgumentList "-File $PSCommandPath" -verb runas;`
管理者権限を保有していない場合、上記のコマンドを実行して管理者として自分自身を実行させます。
1つ目の引数`-ArgumentList "-File $PSCommandPath"`で自分自身のスクリプト名(フルパス)を引数として渡し、
2つ目の引数`-verb runas`で管理者として実行となります。


`exit;`
非管理者権限で実行したスクリプトは不要なので、そのまま終了させます。
(非管理者権限で実行させたい内容がある場合、何か書いてもいいと思います。)

# 終わりに
## 感想1
もっと楽な方法がありそうな気がする…。

## 感想2
そもそも定期的に管理者として実行させないといけないスクリプトがあるならさっさとタスクスケジューラーに放り込みましょう(戒め)
PowerAutomateで会議招集を送る

Office365を使用しており、PowerAutomateもライセンス的に使用できるため、
PowerAutomateで会議招集を送るフローを作成しました。

# 予定を作成するコネクタ
「イベントの作成」で自分の予定表に予定を作成することができます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895455/6edb5c83-cc91-51e2-cdfd-bc0976009b58.png)


# 予定の詳細を入力する
初期表示は以下のような感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895455/4f29b9cc-1900-6d8f-2a2f-63ae0f5f6a8c.png)

[詳細オプションを表示する]のリンクを押すと入力項目が増え、
会議招集を送るための項目が増えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/895455/d999cfd0-500a-c1e2-8ac8-fa30437b9624.png)

あとはもろもろ入力します。

|  項目名  |  内容  |
| ---- | ---- |
|  予定表ID  |  自分の予定表を選択する  |
| 件名 | 会議の件名を入れる |
|  開始時刻<br>終了時刻  |  yyyy-mm-ddThh:MM:ss　形式で指定する。<br>文字列ならOKなので、concatで結合した値を指定することもできる。  |
|  タイムゾーン | 日本だったら (UTC+09:00) Osaka, Sapporo, Tokyo を選ぶ |
|  必須出席者<br>任意出席者 | 出席者のメールアドレスを入力|
|  リソース出席者 | 会議室などのメールアドレスを入力|
|  本文 | 会議招集の本文 |
| 場所 | 自由入力で記載できる。<br>メールアドレスをもってない場所を指定するときに使用 |
| 重要度 | low - 低<br>normal - 標準<br>high - 高|
|終日イベントですか?|はい - 終日<br>いいえ - 終日ではない|
|繰り返し | none - なし<br>daily - 毎日<br>weekly - 毎週<br>monthly - 毎月<br>yearly - 毎年 |
|繰り返しの終了日 |yyyy-mm-dd形式で指定する。|
|発生回数 |予定を繰り返す回数を入れる。 |
|アラーム |アラートがあがる時間を指定。単位は分。 |
| リマインダーをオンにする | アラームを指定するときは「はい」を選ぶ|
| 表示方法 | free - 空き時間<br>tentative - 仮の予定<br>busy - 予定あり<br>oof - 外出中<br>workingElsewhere - 他の場所で作業中<br>unknown - 非公開|
| 応答の要求 | 承諾、辞退時に応答を希望するばあいは「はい」を選ぶ|

# Teams会議にしたい
Outlookの「イベントの作成」のコネクタではなく、
Teamsの「Teams会議の作成」コネクタを使用する

# きになってること
- 表示方法について、「予定あり」と「非公開」の両立ができるのか
CentOS8.2にgitインストール

```
# git --version
-bash: git: コマンドが見つかりません
```

#### 方法１：dnfでインストール
```
# dnf -y install git
...
# git --version
git version 2.18.4

# which git
/usr/bin/git
```


#### 方法２：ソースから最新版をインストール
```
# dnf -y install wget make

# cd /usr/local/src
# wget https://www.kernel.org/pub/software/scm/git/git-2.29.2.tar.gz
# tar zxf git-2.29.2.tar.gz

# cd git-2.29.2
# make prefix=/usr/local all
# ↓makeすると出るエラーにそれぞれ対応

make: curl-config: コマンドが見つかりませんでした
# dnf -y install curl-devel

/bin/sh: cc: コマンドが見つかりません
# dnf -y install gcc

git-compat-util.h:301:10: 致命的エラー: openssl/ssl.h: No such file or directory
 #include <openssl/ssl.h>
# dnf install openssl-devel

http-push.c:22:10: 致命的エラー: expat.h: No such file or directory
 #include <expat.h>
# dnf -y install expat-devel


# make prefix=/usr/local all
# make prefix=/usr/local install

# git --version
git version 2.29.2

# which git
/usr/local/bin/git
```

備忘録です。
最適な中華基板屋をチョイスする？

#こんにちは、2020秋ロボアドベントカレンダー１日目　
こんにちは
やましょうです。

#中華基板の発注先について
今日はIotの第１歩、基板のデータ作成後、いったいどこの基板屋にすればよいのか？を
書いてみたいと思います。

条件として**日本のメーカーはあえて記載しません。**
基本やましょう個人的なチョイスになります。
中華の基板メーカーとして代表的な４社の利点、欠点を*やましょう*がまとめた感じになります。
やましょうは実装はかならず国内で行うので基板作成だけで記載してます。


**メーカーは下記の４社**

##1.Fusion PCB
Seeed社の基板作成ブランドです。
Hpは日本語でわかりやすいです。個人的にはお安いときに使用しています。
事務所は深圳のit系のビルがそろった地域にありますね。
長所：入稿時にファイルビュアーで確認できて便利です。
発注時にホームページも日本語で分かりやすいですね。
グループ企業日本法人のSeeedもありますし、
make等で割引券兼リフロー時に使用するカードがもらえることがあります。
5cmx5cmの低価格を出していてとても驚いた記憶があります。
低価格のパイオニア的存在です。
感想：基板の進捗状況は発送連絡までわかりません。
発注番号が印刷されてしまいます。

##2.Elecrow
深圳の空港に近い？エリアにあります。
発送連絡がくるとすでに届いている場合があります。
長所：ともかく安い＆PCBの色による価格差ない（特殊カラーは別）
何枚余分にはいっているか？
期待させてくれるところが大好きです。
10枚発注で16枚きたとかよくある話です。
10cmx10cmの基板内で、同一基板を何枚取っても追加料金を私は取られていないので、分割する基板はとてもおすすめ。
そして最近は**とても出来が良い**です。
発注番号は印刷されません。
感想：基板の進捗状況は発送連絡までわかりません。
問題の対応能力はピカイチで、スタッフさんはとても良い人で信頼できます。
ただしすべて英語でのやり取りですが、GOOGLE先生の翻訳でもほぼ通じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31412/0f3c794d-57a0-6605-5298-482974726861.png)
10枚取れても追加料金なし！！

##3.Pcb gogo/Pcb way
運営会社は同じJDB  Technology Co., Ltd.です。空港からかなり遠い地域＆恵州に工場がある様です。
長所：日本語によるサポートがされます。サイズが大きいPCBでも結構安価です。OSCで発送もできます。（私が要望したのよ。）
感想：かなり基板は**荒い**です。傷がついていても、動けばOKって感じでサポートされます。
発注番号は消して要求をしないと印刷されます(wayは選択だったと思う）
どのくらい荒いかと言うと
こんな感じで本来はレジストの部分が剥げていて、ハンダメッキされてもokなんだそうです。
**こっちは売り物になりませんが。。。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31412/8394b917-860e-16fd-7f3e-c327af6cc6bc.png)
こんな傷もOKなんだそうです。
ちなみにこの写真を公開することはPCB GOGOさんには許可をもらっています。（太っ腹）


##4.JLC PCB
4社の中で最も微細なPCBが作れる会社です。発送を急ぐ場合はDHLのみなので、その点が難点です。
長所：PCB自体は安い。ですがカラーによって価格日程が変動します。おすすめ点は、**ステンシルが激安**になっています。
発注番号消去や、いろいろオプションで選べます。
感想：頼むと、グッズを送ってきます。
早期発送サービスはないです。基板自体は荒い場合があります。ただしすべて英語でのやり取りですが、GOOGLE先生の翻訳でもほぼ通じます。
この荒いとは、シルクが印刷されていなかったり、レジストがされすぎていたりが過去にありました。

#フローチャートにするとこうなる。
![SnapCrab_NoName_2020-12-1_22-19-22_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31412/c04059b5-5baa-7643-0344-166114d80b40.png)


ということで、やましょうの個人的な独断と偏見で中華PCBの発注先チョイスフローを書いてみました。。
canvasの文字がぼやける・にじむ 他【HTML5】

ハマったのでメモ。

# fillTextで書いた文字がにじむ

結論から言うと、[ここに書いてあること](https://developer.mozilla.org/ja/docs/Web/API/Window/devicePixelRatio)をやればいい。windowsなのでRatinaディスプレイ云々は関係ないと思い込みスルーしていたのだが、windowsの設定で「全体を大きくする」を使用していたことをすっかり忘れていた。

以下、ついでにハマったことメモ。

# fillTextの高さがおかしい

高さの基準がデフォルトでalphabeticになっているため、CSS感覚で指定すると何か上にずれる。[textBaselineをtopに指定すれば](https://developer.mozilla.org/ja/docs/Web/API/CanvasRenderingContext2D/textBaseline)解決する。


# canvasの画像をリサイズする
上の方法でcanvasの内部解像度を大きくすると、画像にした時に環境によって画像サイズが変わってしまう。jsで新しくサイズ固定のcanvasを作成し、そこに元canvasをdrawImageするのが手っ取り早い。
Progate jQuery 中級編　復習

昨日詰まってた部分が多かったけど、スルッと出来るようになっていて気持ちよかったですね。
この場で留まらず、どんどんステップアップしていきたいところ。。
thisが使えるようになれると、こんなことが自動的に行われるようになるんだ〜って感じられたところが昨日より成長しているなって思いました。
VSCodeでPrettierが使えない問題を解決する３手順

# VSCodeでPrettierが使えない問題

たまに上書き保存時にPrettierが使えない問題が発生するけど、対処方法がぱっと出てこないやつ。
特に３つ目。
そしてFormatOnSaveとDefaultFormatterを同時に説明してる記事が上の方に出てこなくてつらい

## Prettier拡張を入れる

1. `Cmd + P`でクイックオープンウィンドウを開く
2. `ext install esbenp.prettier-vscode`を入力, Enterを押下しインストールする。

## Format On Saveが有効にする

1. `Cmd + Shift + P`でコマンドパレットを開く
2. `Preferences: Open Settings (UI)`を入力し設定パネルを開く
3. `format on save`を検索し、`Editor: Format On Save`にチェックを入れる。


## Editor: Default Formatterをprettierにする

1. `Cmd + Shift + P`でコマンドパレットを開く
2. `Preferences: Open Settings (UI)`を入力し設定パネルを開く
3. `default formatter`を検索し、`Editor: Default Formatter`の値を`esbenp.prettier-vscode`に設
動的型付け言語での GraphQL Client

GraphQL API を利用する client のコードを書くとき、静的型付け言語においては codegen のアプローチが非常に有効です。なぜなら、すでに存在する GraphQL Schema から型を実質無料で手に入れることができるからです。

一方で、JavaScript や Ruby のような動的型付け言語が GraphQL API の client になるときはどうでしょうか? その場合でも codegen でクラスを生成してレスポンスをマッピングするアプローチは、一定の効用はあるかもしれません (クラスになってることでIDEのサポートとかが多少得られるかも、試してない) が、少なくとも静的型付け言語ほどの恩恵は望めません。

動的型付け言語の場合は、むしろその特性を生かすため、 codegen の煩雑さ (実質無料と書いておきながらですがw) を捨て、手軽さを重視したいところです。JavaScript であればふつうのobject, Ruby であれば OpenStruct を使うのが良いのではないでしょうか。あとは、その型であることをプログラマーが十分信じられればよいわけです。そこが静的型付け言語との考え方の違いです。

以下は、Ruby において GraphQL API を呼び出すコードです(雰囲気だけ)。

```rb
class FooRepository
  FOO_QUERY = <<~EOS
query foo($id: ID!) {
  foo(id: $id) {
    bar {
      baz
    }
  }
}
  EOS

  def self.find(id)
    res = Faraday.post('.../graphql', { query: FOO_QUERY, variables: { id: id } })

    # このへんでエラーハンドリングとかする

    # OpenStructにマッピングする
    # 正確には再帰的にやる必要がある
    foo = OpenStruct.new(JSON.parse(res.body)['data'])

    # 振る舞いをmixinすることもできる
    foo.extend(SomeModule)

    foo
  end
end
```

以上のコードでは、メソッドのコードのすぐ上に GraphQL の query が配置されており、このメソッドからどんな型のオブジェクトが返ってくるかが分かりやすくなっています。動的型付け言語の場合は、この程度のゆるふわさで、プログラマーがどんな型で返ってくるかを信じられればそれで十分だと思います。

余談ですが、OpenStruct は存在しないキーにアクセスするとnilが返りますが、このときnilを返さずエラーをraiseする OpenStruct::Strict が提案されています ( https://github.com/ruby/ruby/pull/3594 ) 。GraphQL client としてはこちらの挙動のほうが使いやすいので、モンキーパッチ的に導入してもよいと思います。

---

昨今ではWebフロントエンド向けにはTypeScript全盛になり、SwiftやKotlinも合わせてクライアントサイドは静的型付け全盛の時代ですが、サーバーサイドでは Ruby (on Rails) などまだまだ動的型付け言語も健在です。そのため、 Server to Server での GraphQL API リクエストをする時は、動的型付け言語から行うこともあり得ます。その際は静的型付け言語でのプラクティスを無理に適用せず、動的型付け言語の良さを生かす形で実装するのがおすすめです。
Laravel Excelの結合セルに罫線を引きたい

laravelにspreadsheetをインストール
/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader

Html.php
を開いて
  if (isset($attributeArray['rowspan'], $attributeArray['colspan'])) {
 }
の最後に以下を追加する

```php
$sheet->getStyle($range)->getBorders()->getTop()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN);
							$sheet->getStyle($range)->getBorders()->getBottom()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN);
							$sheet->getStyle($range)->getBorders()->getRight()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN);

$sheet->getStyle($range)->getBorders()->getLeft()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN);
```
以下のようにする

```php


if (isset($attributeArray['rowspan'], $attributeArray['colspan'])) {

                            //create merging rowspan and colspan
                            $columnTo = $column;
                            for ($i = 0; $i < $attributeArray['colspan'] - 1; ++$i) {
                                ++$columnTo;
                            }
                            $range = $column . $row . ':' . $columnTo . ($row + $attributeArray['rowspan'] - 1);
                            foreach (Coordinate::extractAllCellReferencesInRange($range) as $value) {
                                $this->rowspan[$value] = true;
                            }
                            $sheet->mergeCells($range);
                            $column = $columnTo;
							$sheet->getStyle($range)->getBorders()->getTop()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN);
							$sheet->getStyle($range)->getBorders()->getBottom()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN);
							$sheet->getStyle($range)->getBorders()->getRight()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN);
							
                        }


```
ServiceNow - onChangeチェックの落とし穴

#概要
ServiceNowではフィールドに入力された内容をonChangeスクリプトでチェックすることができる。しかし、それには落とし穴がある。不正な値が入力されていてもフォームを申請することができる。
間違えた内容の申請を防止するにはonSubmitのスクリプトでも同じチェックをすることもできるが、正規表現を定義した方が簡単にできる。

##onChangeチェックの例
次のスクリプトはフィールド「phone_number」の形式をチェックしている。正しくない場合はメッセージを表示する。

```
function onChange(control, oldValue, newValue, isLoading) {
    if (isLoading || newValue == '') {
        return;
    }
    try {
        var phone = newValue.replace(/\s/g, '');
        phone = phone.substring(0, 10);
        phone = phone.substr(0, 4) + ' ' + phone.substr(4, 3) + ' ' + phone.substr(7, 3);

        //var reg = new RegExp("^0[45][0-9]{2} [0-9]{3} [0-9]{3}$");
		var reg = /^0[45][0-9]{2} [0-9]{3} [0-9]{3}$/;
        if (reg.test(phone)) {
            if (newValue != phone) {
                g_form.setValue('phone_number', phone);
            }
        } else {
            g_form.setValue('phone_number', '');
            g_form.showFieldMsg('phone_number', 'Phone number should start with 0 and be 10 digits', "error");
        }

    } catch (e) {
        alert(e.message);
    }
}
```

実行例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/bf821d67-660b-752d-116a-8df482285957.png)

しかし「Order Now」ボタンを押下すると間違えた内容で注文されてしまう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/fb7c861d-9a65-6045-7836-83a546de2d46.png)

##正規表現
###正規表現の定義
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/cc8a2397-4bcb-e262-4c67-cbb160340ebd.png)

###フィールドでの指定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/b3632668-18ea-1fc1-7e2a-d786d11f29eb.png)

###実行
フィールドを入力した後にエラーメッセージが表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/194a2b4f-30e7-8ce7-6bed-e4a0a7888f94.png)

「Order Now」ボタンを押下するとフォームにエラーメッセージが表示されて申請はされない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/3c23e4c6-fd68-df29-f341-db9dee8cc4ca.png)

以上
E-sports大会運営をサポートする

#サービスの概要
自分はE-sports大会運営を補助するBotのサービスを公開しました。

E-sportsの大会の運営に携わったことのある人はわかるかもしれませんが、人数が多い大会であればあるほど結果の集計は地獄のような作業になります。

**基本的な大会の集計作業の流れ**
> 試合が終わり次第スプレッドシートに結果を手入力
↓
全員分記録したことを目視で確認
↓
デザイン担当にデータを渡し集計画像を作成し配信側に渡す

また、自分の経験上その作業が遅くなればなるほど配信の同接が減るとともにコメント欄荒れてきます

そこで、自分が開発したサービスはゲーム上の通話や大会の際に使われるDiscord.Inc社が開発した**Discord**とGoogle社の**Spread sheet**を連携させ、
早さと正確性が求められる**集計作業**から**集計画像の作成**までを自動化するサービスです。

***

**このサービスを利用するには**
①大会の概要やゲームの種類をweb上で入力してもらう

②提供したゲームの種類に合ったSpreadシートのテンプレートをコピーして、サービスアカウントを追加します。

③discordのBotをサーバーに追加する

**discordBotのコマンドリスト**

>**:point <チーム番号> \<kill数> <順位>**
>>**チーム番号**のスプレッドシートにチームのポイントを記録

>**:img**
>>集計したポイントのランキングから順位画像を作成

>**:send**
>>Botの指示に従いオプションを指定し、指定したコンテンツを指定したカテゴリのチャンネルに一斉に送信する。

以上が主要なコマンドとなっており、サブコマンドとしてdiscord上でPythonコードが実行できるもの、アラームや大会中に各VCに入り音声による連絡を行うものを実装しています。

#使用した言語、仕組み
各オプションを指定するためのwebサイトのバックエンドの開発にはJavaScript
discordのBot,Spreadシートの操作にはPython、
データベースには学生の自分サーバーでデータベースを使うのためのお金がないのでスプレッドシートを代用として使い、2週間で制作しました。

***

**スプレッドシートをデータベースとして利用するにはいくつか利点**があり、
どこからでもアクセスできること。
綺麗にまとまって見やすくデータ操作がしやすいこと
などが挙げられます


今回Botを作るために色んなモジュールに頼りました。
**Pythonはライブラリが豊富**で適切なモジュールを用いることで簡単に機能を実装できます。

>spreadsheet操作 → `gspread`
discord botの実装 → `discord.py`
imgの生産 → `PIL`


#開発にあたって
今回自分はE-sports大会の運営を務めて
空いている時間はパソコンの前に張り付き作業をする日々を経験したことをきっかけに開発に至りました、

まず、自分が苦労した作業を紙に書き出し、その中からプログラミング技術で解決できそうな作業を選びました。
プログラミングで解決できなさそうな問題に関しては諦めるのではなく、作業工程を分割して考え、ここだけなら！という部分の実装にも取り組みました。

公開直後は自分だけで行ったテストの繰り返しでは直面しなかったエラーが出て苦労しましたが、現在は安定しており大規模な大会との契約も頂けました。

##サービスを初めて公開して学んだこと
###まずは紙に書き出す！(開発プロセス設計の重要性)
自分はこれを後悔する以前に興味本位で自分の推しがライブ配信を始めるタイミングで通知を送るBotを計画していましたが、
ところどころで予測できなかった問題に直面し挫折しました。
今回は一つ一つの設計計画を丁寧に取り掛かり、データベースに用いるものも複数検討し、汚いながら紙にまとめて計画しました。
![421FCD4F-FE4F-4B8F-A158-B6F0D7227DFC.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600026/ba63d189-752d-2b64-9eae-68440772ac72.jpeg)
紙にまとめることで自分の頭の中で整理できなかったものを可視化することができ、新しいアイディアに繋がりました。
開発プロセスの設計はビルで例えると基礎部分にあたります。
当然基礎がしっかりしていなければ、不安定で脆いビル(サービス)となり失敗に繋がりかねないです。

###そのサービスはどのような価値を生み出すのかを考える
今回自分はそのサービスが実現するとどのような人の役に立ち、
どのような影響をもたらすのかを考えてから設計に取り掛かり、

設計の際はサービスのターゲットとなる人の立場や目線を合わせ操作性を意識したサービスを目指し、リアクション操作などを多く使わさせていただきました。

###

#今後の予定
契約数も増えており、特に問題なく運用できているため契約で得られたお金を使ってデータベースを使えるプランに変更し、それに対応したコードに修正をしようと考えています。

また、それと並行して今後はE-sports界隈に留まらず今回のサービス開発を通し、学べたことを活かして社会的ニーズに適したBotの開発に取り組み、高校に進学するタイミングで公開したいと考えています
セッションとCookie



<h1>セッションとCookie</h1>
今回はRailsでログイン機能を作るときに学んだセッションとCookieについて書いていこうと思います。


<h2>セッション</h2>
WebアプリケーションではブラウザからサーバへHTTPリクエストを送り、HTTPレスポンスを受け取って表示する。
このHTTPリクエストを繰り返し行うことで順番に操作を行っていく。
しかし、HTTPはステートレス(*1)なプロトコルなので、
そのままでは、同じユーザーから送られた1つ目のリクエストから2つ目のリクエストに情報を引き継ぐことができない。
(例えば、ユーザー登録情報画面に個人情報を記載して登録ボタンを押したが必須のところの書き忘れがあると
初めから記入し直さなくてはいけないなど。)
そのため、Webアプリケーションではサーバー側にセッションと言う仕組みを用意して、
1つのブラウザから連続して送られている一連のリクエストの間で、「状態」を共有できるようにしている。
Railsでは、コントローラからsessionと言うメソッドを呼び出すことで、セッションにアクセスできる。
sessionはハッシュのように扱うことができる。
セッションをデータを入れるには、任意のキーを指定して値を格納します。

```ruby:
session[:user_id] = @user.id
```
値を取り出すには次のように参照する。

```ruby:
@user_id = session[:user_id]
```

<h2>Cookie</h2>
セッションに似た仕組みとしてCookieがある。
セッションはアプリケーションサーバー側で独自に実現される仕組みであるのに対して
CookieはブラウザとWebサーバの間でやり取りされる、より汎用的な仕組み。
Cookie情報は、キーと値のペアの集合。


*1 ステートレスとは？
https://qiita.com/wind-up-bird/items/b210e294ecb147d67e2b
【NeosVR】LogiXで湯婆婆を実装してみる【基礎練習】

はじめに
---
この記事は「[NeosVR Advent Calendar 2020](https://adventar.org/calendars/5277)」の10日目です！
昨日は、Hamadoriさんの「[1時間でバーチャル自室を作ってみた](https://twitter.com/Hamadori_vrq/status/1336334557595881479?s=20)」でしたω

---
僕(https://twitter.com/TewiEwi_no96) がNeosVRで人にモノづくり教える時に説明する内容を記します。
NeosVRが好きになるキッカケになってもらえると嬉しいです。
必要知識
---
・ロジックスチップの使い方(https://neosvrjp.memo.wiki/d/LogiX)
LogiX
---
ノードブラウザを開いて以下のようにつないでみましょう！
Variables -> Strage -> String
Input -> String
Flow -> BooleanLatch
Flow -> If
Assets -> Write
String -> StringLength
String -> Substring
String -> Format
Math -> Random -> RandomInt
![2020-12-01 09.59.08.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556177/916c634b-e657-b0a3-f326-305d0a1cccc4.jpeg)
解説
---
Pulseを押すと「契約書だよそこに名前を書きな」といわれ、
「荻野千尋」と仮に入力し、もう一度Pulseを押すと、
[フン。{0}というのかい。贅沢な名だねぇ。
今からお前の名前は{1}だ。いいかい、{1}だよ。分かったら返事をするんだ、{1}!!]
というフォーマットに{0}には「荻野千尋」、{1}にはランダムな一文字が入力されます。

ネタで作ってみましたω
DisplayのところをUIなどで綺麗に整えてあげると、本格的なアイテムになると思います！
お疲れ様でしたω
FUNBOXで支援してもらえると記事を書く励みになります。
---
https://frick.fanbox.cc

終わりに
---
明日は、@piacere_exさんの
[NeosVR＋Elixirで気軽にVR WebSocketプログラミング（VR |> AR投影アプリの裏側）](https://qiita.com/piacerex/items/4d8b23d99434d5a841ca)です！
ユーザーインタビューで聞こえた「チームの声」

# はじめに :slight_smile:
ディップ株式会社でサービスの企画・改善を行っている@yoshinokatsuhiro0530です。

普段、計測ツールを使った定量的な分析を軸に課題発見をしていましたが
定性的なデータからも課題発見をしようとなり、組織でユーザーインタビューを行いました。

今回は、組織でユーザーインタビューを行って分析した流れと、ぶつかった壁について書きます。
そこで**最も聞けたのが「チームの声」**でした。

# こんな人に読んで欲しい :raising_hand_tone1:
- ユーザーインタビューを始めたばかりの方
- Webサービスの企画をしている方
- 組織に一体感がないと感じている方

# 先にまとめ :eyes:

- とりあえず、実行してみることで壁が見えてきた
- インタビューのまとめは4ステップで行った
    - カード化
    - グループ化
    - 図解化
    - 文章化
- チームの目指すべき方向性のすり合わせに役立った。

# インタビューの実践 
## STEP1：個人ごとにインタビュー
とにかくユーザーインタビューを実践しました。
運用が開始すれば、自然と壁が見えてくるのでとりあえず行動！

まずは個人ごとでユーザーの課題発見を発見していました。
（初めのうちはこれでうまく回っていました）

### 壁1：徐々にやり方に疑問が発生
インタビューを個人でやっていたため
もちろん、やり方も人それぞれでした。

インタビューをする人が増えることで
こういった疑問がチーム内で徐々に発生してきました。

:girl_tone1:｛総じてユーザーは何に困ってる？
:boy_tone1:｛課題の共通認識できてる？
:girl_tone1:｛インタビューって何のため？
:boy_tone1:｛全員が目的理解している？


次にこの疑問を解決していきます。

## STEP2：チームみんなで目線を合わせるために

### STEP2-1：インタビューしたデータのまとめ方

以下のような流れでインタビューをまとめました。

1. ユーザーインタビューから得た声を付箋にアウトプット
2. アウトプットした内容を似たもの同士でグループ化
3. 気持ちの変化を図解化

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/868782/fbc8faee-fd99-b7cc-b471-8015ad1ff0d4.png)

### STEP2-2：図解化したものを最後に文章化

図解化して見えてきたユーザーストーリーを文章化します。
言葉にすることで、図解化では見れなかった矛盾点や新たな疑問、課題などが見えてきました。

うまく文章に出来ない場合は
グループ化がおかしいか、なにか情報が抜け落ちている可能性があります。

### STEP2-3：目線を揃えて再インタビュー

この文書化したことで、抜け漏れが発見できました。

抜け漏れを意識して、再度インタビューを行ったことで
チーム全体で同じ粒度でインタビューできるようになりました。

### STEP2-4：ペルソナとカスタマージャーニーの作成

それぞれが集めたデータの粒度を揃えました。
ここからユーザーの共通課題を見つけ、ペルソナとカスタマージャーニーを作成をします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/868782/cf093d7d-981e-e389-2e7e-0ade933b21b6.png)


### 壁2：データの2次加工についての疑問

次にこのような疑問が出てきました。

:girl_tone1:｛データの二次加工で生データがから抜け漏れ発生するけどいいの？<br>　　生データあるのに結局推測が混じるのはいいの？
:boy_tone1:｛そもそもカスタマージャーニーって？<br>　　課題が改善された状態の「理想のシナリオ」？<br>　　実際の行動や感情を反映？
:girl_tone1:｛ところで、理想的な体験って？

施策ひとつひとつに対しては、各々が「こう使ってほしい」という理想を描けてはいました。
しかし、チームで見たときに、理想の体験の共通認識が持てていないということが分かりました。

もともとは、課題発見をしようと始めたインタビューですが
最終的には進むべき方向性の目線合わせとして役立ちました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/868782/464b136a-22af-2310-3a5c-565dc4a97b49.png)

## STEP3：救いたい人を見つける

インタビュー内容を元に、お話を聞いたユーザを思い返しながら
「こういった人の役に立ってほしい」と目指すべきところを話しました。

まとめた結果、現在と将来の2軸とう形でテーマを可視化することにつながりました。
（申し遅れましたが、私たちは求人情報サービスを企画しています。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/868782/0dc2c8ab-bccc-7eee-d1e4-a7a2251e98cd.png)


# まとめ

- とりあえず、実行してみることで壁が見えてきた
- インタビューのまとめは4ステップで行った
    - カード化
    - グループ化
    - 図解化
    - 文章化
- チームの目指すべき方向性のすり合わせに役立った。
object-fitで画像をうまく調整する

# はじめに
現在、質問アプリケーションの開発を個人で行っています。
こちらにまとめているのでよろしければ是非見てください。
[【未経験・独学】Laravelでアプリケーションの開発からAWSを用いたデプロイまで](https://qiita.com/sasao3/items/5311d442699dba198bb0)

新しく画像を非同期で保存し、プレビューに表示させる機能を実装するにあたって
`object-fit`という簡単に画像を指定したサイズに調整してくれるcssプロパティを使用したので学習メモとして残します。

# object-fitとは？
> CSSのobject-fitプロパティは、置換要素、例えばimgタグやvideoタグなどの中身を、コンテナーにどのようにはめ込むかを設定します。
参考:[object-fit MDN web docs](https://developer.mozilla.org/ja/docs/Web/CSS/object-fit)

※***置換要素とは、コンテンツが現在の文書のスタイルに影響されない要素のこと***。一般的な置換要素は、iframeタグ・videoタグ・embedタグ・imgタグなど。
参考：[置換要素 MDN web docs](https://developer.mozilla.org/ja/docs/Web/CSS/Replaced_element)

object-fitで画像を指定のサイズに切り取ったり、縦横比を維持しながらリサイズしたりと様々な設定ができる。


# プロパティ一覧 object-fit: ◯◯;
### ・fill
初期値。要素に合わせるため縦横比は維持されない（画像が伸びたり縮んだりしてしまう）。

###・contain
画像の縦横比は維持されつつ、指定の画像領域に収まるよう大きさが調整される。

###・cover
要素に余白がでないようにしつつ、縦横比は維持し要素からはみ出ている部分はトリミングする。

###・none
画像のリサイズはされず、画像オリジナルのサイズのまま表示される。

###・scall-down
要素より画像が大きい場合は、「contain」を、小さい場合は「none」を指定する。
つまり画像が大きい場合は縦横比を維持しつつ、要素内に収まるよう調整され、小さい場合は画像オリジナルのサイズで表示される。


## 参考サイト
こちらのサイトに、object-fitのそれぞれの使用イメージが記載されていてとてもわかりやすいです。
[object-fit CODE KITCHEN](https://code-kitchen.dev/css/object-fit/)

# まとめ
今回は、object-fitというCSSプロパティについてまとめました。
CSSについては、まだまだ便利なものが沢山あるので使いながらどんなものがあるか知っていきたいと思います。
【YouTube Data API】BGMを教えてくれる神コメントを探す

[MYJLab Advent Calendar 2020](https://qiita.com/advent-calendar/2020/myjlab)  6日目の記事です

# 背景
YouTubeを視聴していると、動画内で流れているBGMをどうしても知りたくなる時があります。そんな時にコメント蘭を覗くと、BGMを教えてくれる神コメントがあったりなかったり。


<img width="400" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638354/431724dc-5062-913b-2c3c-9e321720884e.png">

コメントを全部見るのは大変なので、神コメント探しを自動化したい。


# 準備
## 実行環境
Python 3.7.9

## YouTube Data API

コメントの取得にはYouTube Data APIの[CommentThreadsリソース](https://developers.google.com/youtube/v3/docs/commentThreads)を使います。APIの利用には、APIキーが必要です。APIキーの取得については[こちら](https://developers.google.com/youtube/v3/getting-started)。



# 実装
## コメントにBGMの情報があるかどうかの判定
コメントに「BGM」「曲」「音楽」のいずれかの単語が含まれていれば、そのコメントもしくはコメントへの返信にBGMの情報があるものとして扱います。

```python
def has_bgm_info(comment):
    if re.search(r'[Bb][Gg][Mm]', comment) != None:
        return True

    if '曲' in comment:
        return True
    
    if '音楽' in comment:
        return True

    return False
```

## コード全体
標準入力から動画URLを受け取り、BGMの情報を含むと思われるコメント及びコメントへの返信を標準出力へ出力します。

```python:find_bgm.py
import requests
import re

def get_comment(video_id, page_token = ''):
    request_url = 'https://www.googleapis.com/youtube/v3/commentThreads'
    param = {
        'key': 'your api key',
        'videoId': video_id,
        'part': 'replies, snippet',
        'maxResults': '100',
    }

    if page_token:
        param['pageToken'] = page_token

    req = requests.get(request_url, params=param)
    return req.json()


def has_bgm_info(comment):
    if re.search(r'[Bb][Gg][Mm]', comment) != None:
        return True

    if '曲' in comment:
        return True
    
    if '音楽' in comment:
        return True

    return False


video_id = ''
while True:
    print('urlを入力：', end='')
    url = input()
    url_pattern = r'https://www.youtube.com/watch\?v=[0-9A-Za-z-_]{11}'
    if re.match(url_pattern, url) != None:
        video_id = re.search(r'[0-9A-Za-z-_]{11}', url).group()
        break
    print('urlが間違っています')

page_token = ''
while True:
    req = get_comment(video_id, page_token)

    for comment_thread in req['items']:
        comment = comment_thread['snippet']['topLevelComment']['snippet']['textOriginal']

        if has_bgm_info(comment) and 'replies' in comment_thread and 'comments' in comment_thread['replies']:
            print('') # 見やすくするために改行を入れる
            print(comment)

            for replies_thread in comment_thread['replies']['comments'][::-1]: # replyを時系列順に並べるため逆順で取り出す
                reply_comment = '┣━' + replies_thread['snippet']['textOriginal']
                print(reply_comment)

    if 'nextPageToken' in req:
        page_token = req['nextPageToken']
    else:
        break
```

# 結果
作成したpythonファイルを実行して、標準入力に動画URLを入力します。

```sh
$ python find_bgm.py
urlを入力：https://www.youtube.com/watch?v=wMS0-1IEYuU

後ろで流れてるBGMわかる方いますか？
┣━becoさんの「深海に生きる」ですよ〜
┣━@i y ありがとうございます…！
┣━いえいえ！
```
できた！

# 参考
- [YouTube Data API のドキュメント](https://developers.google.com/youtube/v3/docs/)
SQLAlchemyで実行されるSQLの生クエリを取得したい

## SQLAlchemyのquery実行時に出力されるログ
```
INFO 2020-12-01 00:00:00 SELECT table.col1, table.col2
FROM table
WHERE table.pk1 = %(primary_1)s AS anon_1 [in 略/sqlalchemy/engine/base.py:1151]
INFO 2020-12-01 00:00:00 {'primary_1': 'value'} [in 略/sqlalchemy/engine/base.py:1154]
```

この出力って凄く見づらいんですよね。
どうにかならんものかなぁと思って調べてみたんです。

### 地道に頑張るパターン
```python
class Session(object):
    def __exit__(self, exc_type, exc_value, traceback):
        # 略
        for st in self._profiler.statements_with_parameters:
            query = st[0] % st[1]
            logger.info("[SQL] %s" % query)
```

SQLAlchemyの発行する見づらいSQLをそのまま当て込んで使うパターンですね。
これだと文字列が””とかで囲われないので型が分かりにくい問題点があります。

### 正しいパターン
```python
def find_by_pk():
    query = session.query(table).filter(table.pk1 = "value")
    logger.info(query.statement.compile(dialect=mysql.dialect(),
                               compile_kwargs={"literal_binds": True}))
```

```
INFO 2020-12-01 00:00:00 SELECT table.col1, table.col2
FROM table
WHERE table.pk1 = 'value' AS anon_1 [in loggerが呼ばれた場所]
```
どうやらsession.queryに発行されたSQLが保持されているようで、それを使うことできれいに出力することができました。
ただ、検証したバージョン(1.2.0)はバグが含まれているようで、'value'の部分にdatetime型が入るとエラーになります。
チケットが発行されていたので最新版では修正されているとは思います。(未確認)

### 参考
[SQLAlchemyが生成するクエリを確認する](https://techblog.recochoku.jp/2423)
[NotImplementedError: Don't know how to literal-quote value date time.datetime](https://github.com/bbelyeu/Flask-SQLAlchemy-Caching/issues/2)
[String compiler can now literal compile date time objects](https://github.com/sqlalchemy/sqlalchemy/commit/fea89ef47080a581d79aafc1dc649bf21e165793)
[Linux Gnome]ubuntu でキーボードの設定がもどってキーッってなっているあなたへ🥺

## はじめに

`Advent Calendar 12/8の記事になります`

私はハンズラボ株式会社にて、トータルオプティマイゼーショングループのマネジャーをやっております。
普段はあまり開発をやっていませんが、プログラミング大好きです！

寒い季節になりましたね〜。　サンタさんは今年は何をプレゼントしてくれるのでしょう🥺
最近最愛の娘がサンタの正体を気づいており、時の早さを痛感しております。


自称PC好きで2台の自作PC(Windows10,Ubuntu)を持ち、2台のノートPC(Windows10,MacbookPro(会社支給))と
iPad, ラズパイ(3B)を保有しています。(何台もってるんや・・・)


## 本題です

リモートワークが進み、会社PCではMac Book Pro 、個人PCではubuntu(20.04)を使用していますが

**どちらも同じキーボード使いたいし（私はメカニカルキーボードを利用）、webカメラ、マイクとかを使うPCのたびに
切り替えるのってすごくめんどくさいですよね！！！！**

ちなみにHTML端子も交換器を使っています

## USBの切替時にキーボード(Mozc)の設定もどりませんか？

**私はusb切替機をつかっているんですが、
USBの端子を指すたびに、ubuntu側のMozcのキーボード設定が戻るんです。**

`通常の設定(Macに合わせてCAPS LOCKを左Controlに変えているひとは多いのでは？)`

![スクリーンショット 2020-11-24 09-16-09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344266/ac0bd87f-a31f-a09a-7cc9-17211e10a69f.png)


USBを差し替えると、tmuxのkeyバインドとかでctrlをつかうので
**CapsLockが初期設定に戻るのが超絶に不便なのです！**

![スクリーンショット 2020-11-24 09-17-08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344266/225b5c73-c398-3015-c28b-347afdbca56e.png)

## 打開策 厳選３種


いろいろ調べた結果、いろいろの打開策を考えました。

### １．ログアウト
ぐぐるとまず出てくるのがこれ、はじめはこれでやっていましたが切り替えるたびにログアウトは正直めんどくさい。
ブラウザとかアプリが一度落ちてしまうし。。。


### ２．alt + F2  → r

gnome shellをリスタートさせる方法。
これで解決しますが、２アクションは嫌だ。（いや、我慢できる人はこれでOK）
あと、alt + F2 って忘れる。。。
これをコマンドにしたのが下になります！

### ３．カスタムファンクションを作る

そこで考えついたのは案３！現在はこれ一択です。

ubuntu → システム設定　→ キーボード
でショートカット（自分の場合はF11）に下の実行権限のついたshellをフルパスで記載します。


![スクリーンショット 2020-11-24 09-28-39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344266/f2213ca4-6472-97e5-f984-49f2bd9bcb10.png)



```bash

$ cat gnome_refresh.sh
#!/bin/bash

killall -3 gnome-shell & > /dev/null 2>&1

exit 0
$
```

key設定がおかしくなぁ、、、と思ったら、F11で終わり、解決！！！
わすれないし、ブラウザとかも落ちずに戻ります。
困ったら真似してみてください。
(ちなみにF12はとかはよく使うので、あまりつかわないF11にしています。)


それでは良いLinuxライフを！
npm installとexpo installの違いって何？

## 結論

expo installは、

「使用中のExpo SDKのバージョンと互換性のある依存関係のバージョンをインストールする」

点が異なります。

## 挙動の違い

npm installもexpo installも実際のインストールはnpmやyarnを呼び出します。

### expo installでインストールする場合

```
expo install expo-secure-store
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33823/1cf47d23-0aa5-12ff-fbfd-fc97bac4c07c.png)

yarnを使ってSDK39と互換性のあるネイティブモジュールをインストールと書いてありますね。
以下のようにバージョンをしてくれています。

```
expo-secure-store@~9.2.0
```

### npm installでインストールする場合

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33823/6af796e0-c23c-dbba-deaf-3774ba6fe56a.png)

npm installでも結果的に同じ9.2.0がインストールされました。ただバージョンの指定はされていないですね。

## おわりに

expo installを使うとexpoのSDKと互換性のあるバージョンのnpmをインストールしてくれるので、Expoで紹介されている公式コンポーネントは全てexpo installでインストールしましょう。

npm installだとライブラリによっては、バージョンの差異でexpoが動かなくなることがあるので注意してください。
devise_parameter_sanitizerメソッドについて

## devise_parameter_sanitizerとは？
　**devise（Gem）のUserモデルに関わる「ログイン」「新規登録」などのリクエストからパラメーターを取得できるようになるメソッド。**
　また、新しく追加したカラムをdeviseに定義されているストロングパラメーターに含めたい場合は、**permitメソッド**を用いることで含めることができる。
　さらに、deviseに関するストロングパラメーターを記述する際は、**application_controller.rb**に記述する。（deviseの処理を行うコントローラーはGem内に記述されており編集できないため。）
## 使用方法
####①　privateにdeviseに関するストロングパラメーターの記述する。
```ruby:application_controller.rb
private

def configure_permitted_parameters
  devise_parameter_sanitizer.permit(:deviseの処理名, keys: [:許可するキー])
end
```

　第一引数の処理名には、それぞれサインイン時やサインアップ時、アカウント情報更新時の処理を記述する。

|deviseの処理名   |役割                      |
|:--             |:--                      |
|:sign_in        |ログインの処理を行う時        |
|:sign_up        |新規登録の処理を行う時       |
|:account_update |アカウント情報更新の処理を行う時|

例）新規登録時に名前（name）を許可する記述

```ruby:application_controller.rb
private

def configure_permitted_parameters
  devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
end
```
####②　before_actionを用いてメソッドを呼び出す。
```ruby:application_controller.rb
before_action :configure_permitted_parameters, if: :devise_controller?

private

def configure_permitted_parameters
  devise_parameter_sanitizer.permit(:deviseの処理名, keys: [:許可するキー])
end
```

「if:」
　before_actionのオプションの一つで、値にメソッド名を指定することで、その戻り値がtrueであるときのみ処理を実行するように設定できる。
　今回の場合は、「：devise_controller?」というdeviseのヘルパーメソッド名を指定して、deviseに関するコントローラーの処理であればその時だけ実行されるように設定している。
新 shiftr のクラウドMQTTブローカーとNoodl 2.1を連携したみたメモ

[Noodlアドベントカレンダー2020](https://qiita.com/advent-calendar/2020/noodl)の１日目！🍜

NoodlでIoTなものを作りたいときに外部MQTTブローカーとしてよく使う shiftr が、最近新しいサーバーに移行するとのアナウンスを出していたようです。

旧 shiftr：https://legacy.shiftr.io
新 shiftr：https://www.shiftr.io

この記事は、新 shiftr のクラウドMQTTブローカーとNoodl バージョン2.1を連携したみたメモです。新 shiftr には[デスクトップ版](https://www.shiftr.io/desktop)と[クラウド版](https://www.shiftr.io/cloud)があります。今回はクラウド版とNoodlを連携するお話です。

ちなみに、デスクトップ版については @youtoy さんが「[MQTTブローカー shiftr.io の新バージョンをチェックしてみる！ 〜デスクトップアプリ編〜](https://qiita.com/youtoy/items/8cbc9e6fa1cd46ca2c3c)」を書かれていますので、そちらをチェックしてみてください。

#バージョン
Noodl 2.1.0 Build 30

#旧 shiftr から新 shiftr への移行

新 shiftr の[ドキュメント](https://www.shiftr.io/docs/platform/migration)を読むと、旧 shiftr のサーバーが停止する時期がまだ発表されていないようです。また、旧 shiftr での登録は2020年12月17日までのようですね。
![スクリーンショット 2020-11-30 1.33.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526082/35605c31-d297-0dce-0c51-68c8ff3f7720.png)

##移行してみた

旧 shiftr から 新 shiftr への移行についてドキュメントに書かれています。
>Migrating projects from the legacy shiftr.io platform to the new shiftr.io Cloud is simple. For each namespace on the legacy shiftr.io platform, you essentially deploy a new instance in shiftr.io Cloud, recreate the tokens, and reconfigure your devices and applications.

旧 shiftr の Namespace が、新 shiftr の Instance に相当するようです。

▼ざっくり手順
１．Group を作成
２．Instance を作成
３．無料プランの Basic を選択（有料プランもあります）
４．トークンを発行

無料の Basic プランなのですが、使ってみるとちょっと一癖あるようで... クラウドMQTTブローカーを動かせる時間が、１日当たり最大６時間のようです。以下が Basic プランの注意書きの引用です。
>Free instances are only allowed to run 6 hours a day. They will automatically sleep and recharge if not used.

使った感じから判断すると、Budget がクラウドMQTTブローカー使用の残り時間っぽい...？
この Budget が、ソシャゲのライフや石のように、時間が経つと回復するような感じになっているようです... おそらく。（Budget に関する説明を見つけられなかったので、予想ですが）

![スクリーンショット 2020-12-01 0.19.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526082/6e780b9b-d12e-d3ee-fb0e-11166ff5e627.png)

#Noodl 2.1 と shiftr Cloud の連携
Noodlでプロジェクトを開いたら、画像左側の①のアイコンからライブラリを表示します。「MQTT Module」にマウスオーバーすると出てくる ADD ボタンを押して、追加してください。
※ Noodlバージョン2.1からは、このモジュールを読み込まないとMQTTが使えません。
![スクリーンショット 2020-12-01 0.49.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526082/99c0ab1f-6ef8-d56b-4fa5-2be11289972f.png)

モジュールを読み込むと、以前のバージョンと同様に「Send Message」と「Receive Message」のノードが使えるようになります。また、画面左側の歯車アイコンからMQTTのブローカーURLを設定できるようになります。

![スクリーンショット 2020-11-30 13.38.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526082/09259ccb-7529-899b-edec-0af63d5679ed.png)

Broker URL のスキーム名 を `mqtt` に設定すると、動きませんでした。`mqtts` や `wss` にしたら動いたので、使う時は要注意ですね！

※ 旧 shiftr の Broker URL を Noodl 2.1 で設定する時は `mqtt` で動くのですが、新 shiftr を Noodl 2.1 で利用する時は `mqtts` や `wss` にしないといけないようです。

#まとめ
新しい shiftr のクラウド版を使ってみましたが、サービスやUIの変更がありました。

ただ、大まかな仕組みは変わっていないので、あまり苦戦することなくNoodlとの連携ができました（むしろNoodlでのMQTT設定に少し焦りました...）

無事、連携できてよかったです！b
AWS障害時のNature Remo リモート APIの状況


# Nature Remoサーバ障害
先日、AWSのus-east-1リージョンの障害に伴い、Nature Remoを利用できない事象が発生しました。

参考リンク
[【11/26 11:12更新】システム障害のお詫びと復旧のお知らせ](https://nature.global/jp/notice/2020/11/26/1126-1110)
[【11/26 10:15更新】11月25日からシステムの障害が発生しております](https://nature.global/jp/notice/2020/11/25/1125)

Remoが赤点滅になり、リモコン操作ができない状況になりましたが、Wifiルータ障害等とは状況が異なる動作をしておりました。サーバ障害時にAPIを動作させた場合どのような状況になっていたのか、またサーバ障害を早期に確認する方法があったのか、定期的に実行しているAPIの状況から振り返ってみます。

# 通常時のNature RemoのAPI利用状況
Nature Remo (初代) と Nature Remo mini を利用しています。
リモコンとして利用するだけでなく、センサーデータを1時間に1回の頻度で取得し、スプレッドシートに保管をしています。

センサーデータを 1時間に1回の頻度で取得する方法は、こちらの記事を参考にしています。
[リビングの環境監視ダッシュボードを６０分で作る方法（Nature Remo Cloud APIとGoogleサービス連携）](https://qiita.com/t-chi/items/01b9a9b98fbccef880c3)

AWSの障害の前後での、このスプレッドシートへの記載状況から当時の状況を振り返ります。

## AWSの障害発生中はセンサーデータを取得できていない
AWSの障害発生の前後の時間帯は、スプレッドシートへの書き込み失敗しています。
Remo自体の障害や、Wifiルータの障害であれば、APIは利用できるが、センサーの情報が古い情報のまま更新されていないという状況になります。
今回のようにサーバー側が原因でNature Remoが使えないという場合、書き込みができないということで状況の切り分けが可能と思われます。
サーバの障害が発生している可能性があることをメール等で通知すれば、原因の切り分け、把握がしやすくなりますし、慌てずに済みそうです。

## 障害前後の時間帯のセンサーデータの取得状況
スプレッドシートへの書き込みができていても、センサーのデータを更新できているもの、データを更新できていないものなどがあり、正しい情報を取得できない状態になっているものもありました。
温度や湿度等の具体的な数値は割愛しますが、時刻だけまとめると以下のようになっていました。

参考) スプレッドシートへの書き込み時刻と、センサーから取得した情報の更新時刻  (JSTに修正してあります)

|スプレッドシート 書き込み時刻|Remo温度 取得時刻|Remo湿度 取得時刻|Remo照度 取得時刻|Remo人感 取得時刻|mini温度 取得時刻|
|:-:|:-:|:-:|:-:|:-:|:-:|
|11/25 20:53|11/25 19:13|11/25 20:04|11/25 9:10|11/25 20:53|11/25 15:28|
|11/25 21:53|11/25 19:13|11/25 20:04|11/25 9:10|11/25 21:47|11/25 15:28|
|11/26 4:53|11/25 19:13|11/25 20:04|11/25 9:10|11/25 22:56|11/25 21:57|
|11/26 6:53|11/25 19:13|11/25 20:04|11/26 5:40|11/25 22:56|11/25 21:57|
|11/26 7:53|11/26 7:33|11/26 7:20|11/26 5:40|11/26 7:45|11/25 21:57|
|11/26 8:53|11/26 8:19|11/26 8:35|11/26 5:40|11/26 8:51|11/25 21:57|
|11/26 9:53|11/26 8:19|11/26 9:34|11/26 5:40|11/26 9:53|11/25 21:57|
|11/26 10:53|11/26 10:51|11/26 10:33|11/26 5:40|11/26 10:53|11/25 21:57|
|11/26 11:53|11/26 10:51|11/26 10:33|11/26 5:40|11/26 11:42|11/25 21:57|
|11/26 12:53|11/26 12:27|11/26 12:50|11/26 5:40|11/26 12:54|11/25 21:57|

状況を確認すると

* 障害発生時間帯は、スプレッドシートへの書き込みが失敗している。4:53は書き込み成功 5:53は書き込み失敗となっているのは中途半端に回復したためか？
* 障害の発生前から、温度、湿度、照度の情報が更新できていなかった。しかし、人感センサーの時刻は更新されている。
* 照度の値は、障害回復後も正しく取得できていない。(上表には値は記載していませんが、朝5:40から夜まで、ずっと 124 という値で一定でした。通常時は、明るい場合は240以上、暗い場合は10未満の値であることが多く、124という数字が続くことは無いため、ここからも障害の可能性を検知できるかもしれません)
* Nature Remo miniのデータ更新が復旧していない。(miniは、AWSのトラブルのあと赤点滅から自動復旧しなかったためと考えられます。)

余談ですが、Nature Remo miniの復旧にあたっては、電源ON/OFFでは回復せず、以下の手順を実施することで、復活させることができました。
[ソフトバンク光BBユニットをお使いの方へ](https://nature.global/jp/faq/softbankbb)

## 考えられるサーバ障害検知方法
今回のようなサーバー側の障害を検知する方法として、結果から考えてみると以下のような方法が考えられます

* APIの実行に失敗し、スプレッドシートへの書き込みができなかったことをメール等通知する
* 照度センサーが 124 等の値で連続している

前者の方法であれば、比較的短期間に確認ができます。ただし通知方法にAWSのサービスを前提とした方式(AWS SNS等)としてしまうと、AWS障害時に通知ができない場合があるので、他の方法で通知するのが適切だと思います。
後者の方法は、障害が判明するまでに時間が掛かってしまうため、早期に障害を検知するという目的には適していません。
CPUを食いまくるウイルススキャンソフトに制裁を


直ぐ解決したい人向け

```sh
brew install cpulimit 
sudo cpulimit -p {PID} -l {CPU Power(%)}
```


# 怒りのポエム

アンチウイルスソフトって仕事をすると付き物です。ウイルススキャン自体が悪いわけではありません。ウイルススキャンにパワーを使いすぎて、動作を重くしたり熱を籠もらせてPC自体に悪影響を勝手にするのが良くない。

俺「お前、スキャンばっかりしてるけど成果は？」
Sym「スキャンの結果、ウイルスゼロだったので、満点です！（CPU使用率200％超え）」

結果として俺の成果はゼロ。そして怒りは満点だ


俺「いいかい、アンチウイルスくん。君は１番である必要はないのだ。」
Sym「ウイルスがあったら困るから働く！」
俺「・・・一番じゃなきゃダメですか？」
Sym「一番働く！」

働くのは良い。しかし、お前が一番じゃ俺の成果はゼロだ。

俺「２位じゃダメ？」
Sym「ウィィィィィィイイイイィイイィイ...」
俺「スキャン始めやがった・・。」

聞く耳を持たないことよくありますよね。そして、こいつらは強制終了してもすぐ復活します。一番働くゾンビなんて社畜。
そしてこういうやつらって、管理者権限で制限されていて、スキャンの日程変更などのコントロールは直ぐ側にいる俺を差し置いて上の命令ばかり聞いている。許さねぇ・・・。



# ならば制限だ

```sh
brew install cpulimit 
# sudo cpulimit -p {PID} -l {CPU Power(%)}
sudo cpulimit -p 749900 -l 20
```

ActivityMonitorなどでCPUパワーが使われているPIDを調べます。
CPU使用率を減らします。20％くらいでしょうか。

これで晴れて働き者のSymくんを制限出来ました。
めでたしめでたし。