OmniAICreator/Qiita-1.07M huggingface dataset:
R初心者がでMLB Statcastを分析してみる

Rを使ってMLBのデータを解析してみようと思う。ちなみにRは全く使ったことのない初心者。
なので、自分のメモを兼ねて基本的なこともメモしていくと思う

# インストールするパッケージ
パッケージの前に
googleでrtoolsと検索し、インストールする。

以下のパッケージをインストールしておいた。何かと便利らしい。
ggplot2　描写ツール
tidyverse
dplyr
devtools
インストール方法は、以下のサイトを参照
https://qiita.com/drafts/18e3df8b173227f263e5/edit

# Statcastデータをダウンロードする為のパッケージ
有名なのは
baseballer
statcastr
等がある。今回はpontsuyu氏が作成したパッケージを使用
https://github.com/pontsuyu/statcastr
このパッケージはRstudioのインストールからは検出できないので、コードを打ってインストールする必要がある

githubのコードからインストールするときは以下のように入力するだけ

```R:install.R
devtools::install_github("pontsuyu/statcastr")
```

# 簡単に動かしてヒストグラムを作成
例として、トラウトの打球を6段階に分けたヒストグラムを作成する。
まずはstatcastrを使って、2020年のMLBのデータを引っ張ってくる。
最後は、csv形式にして保存する。

```R:data.R
devtools::install_github("pontsuyu/statcastr") #statcastrをインストール
library("statcastr") #パッケージをアクティブにするライブラリ関数
data <- scrape_statcast("2020-07-23", "2020-09-28") #2020年シーズンのデータをすべて入力
write.csv(data, "C:/Users/ファイルの保存場所/data.csv", row.names=F)
```
rows.namesは行の見出しを付けるかの設定。T(True)にすると見出しがついてしまう。
https://a-habakiri.hateblo.jp/entry/2016/12/12/222806
また、csvに含まれている情報が何を示しているかは以下URLを確認
https://baseballsavant.mlb.com/csv-docs

```R:Trout.R
#トラウトの打球…を作成
trout<-filter(data,batter==545361) #トラウトのデータを抽出
fig_trout = ggplot(trout, aes(x=launch_speed_angle)) + geom_histogram()
#fig_trout
#aesでx軸に何を描くかを示す
#geom_histogram():描画を行うことを示す
```
![Rplot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307295/fbed4ca4-920b-cd9c-5ea8-aad8562dff29.png)

とりあえずのメモということで
コピぺで使える簡易的なスロットマシーン実装

#コピぺで使える簡易的なスロットマシーン実装

![51dfdc85977ada043ac57c858b1ee611.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/725167/651b305e-bdf4-0234-2e97-5a033c0a5abe.png)

```java:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>スロットマシーン 1</title>
<style>
input {
	width:40px;
	font-size:30px;
	text-align:center;
}
button {
	width:50px;
}
.x1 {
	padding:10px 0;
}
.x1 div {
	float:left;
	width:60px;
	text-align:center;
}
</style>
<script>
window.onload = function() {
	var a = document.getElementById('a');
	var b1 = document.getElementById('b1');
	var b2 = document.getElementById('b2');
	var b3 = document.getElementById('b3');
	var c1 = document.getElementById('c1');
	var c2 = document.getElementById('c2');
	var c3 = document.getElementById('c3');
	var t1 = null;
	var t2 = null;
	var t3 = null;

	function start() {
		if (t1) {
			clearInterval(t1);
		}
		if (t2) {
			clearInterval(t2);
		}
		if (t3) {
			clearInterval(t3);
		}
		c1.value = Math.floor(Math.random() * 10);
		c2.value = Math.floor(Math.random() * 10);
		c3.value = Math.floor(Math.random() * 10);
		t1 = setInterval(function () {
			c1.value = (+c1.value + 1) % 10;
		}, 200);
		t2 = setInterval(function () {
			c2.value = (+c2.value + 1) % 10;
		}, 200);
		t3 = setInterval(function () {
			c3.value = (+c3.value + 1) % 10;
		}, 200);
	}

	function stop1() {
		if (t1) {
			clearInterval(t1);
			t1 = null;
		}
		check();
	}

	function stop2() {
		if (t2) {
			clearInterval(t2);
			t2 = null;
		}
		check();
	}

	function stop3() {
		if (t3) {
			clearInterval(t3);
			t3 = null;
		}
		check();
	}

	function check() {
		if (!t1 && !t2 && !t3) {
			if (c1.value == c2.value && c1.value == c3.value) {
				alert('あたり！');
			} else {
				alert('はずれ！');
			}
		}
	}

	a.addEventListener('click', start);
	b1.addEventListener('click', stop1);
	b2.addEventListener('click', stop2);
	b3.addEventListener('click', stop3);

	start();
}
</script>
</head>
<body>
	<button type="button" id="a">start</button>
	<div class="x1">
		<div>
			<input type="text" id="c1">
			<button type="button" id="b1">stop</button>
		</div>
		<div>
			<input type="text" id="c2">
			<button type="button" id="b2">stop</button>
		</div>
		<div>
			<input type="text" id="c3">
			<button type="button" id="b3">stop</button>
		</div>
	</div>
</body>
</html>
```
#現場からは以上です！
[Rails] form_with の２種類の書き方

この記事ではmacOS Catalina10.15.6にインストールしたRuby 2.6.5を使っています。

# form_withとは
- 情報を送信するためのヘルパーメソッドです。
- 入力に必要なHTMLを表示してくれます。
- form_withには２つの書き方があります。
- １つ目は、__入力された情報をデータベースに保存する場合__、２つ目は__入力された情報をデータベースに保存しない場合__です。

# データベースに保存する時
- `model: `に続けて__モデルクラスのインスタンス__を記述します。
- `f.text_field`でテキストボックスを作成します。


```ruby
<%= form_with model: @book, local: true do |f| %>  
    <%= f.text_field :keyword, placeholder: "keyword", class: "search-input"%>
    <%= f.submit "search", class: "search-btn" %>
<% end %>
```



# データベースに保存しない時
- `url:`に続けて__情報送信先のパス__を記述します。

```ruby
<%= form_with url: search_path, local: true do |f| %>
   <%= f.text_field :keyword, placeholder: "keyword", class: "search-input"%>
   <%= f.submit "search", class: "search-btn" %>
<% end %>
```
# ルーティングでネストしている場合
- 例えばpostコントローラーにcommentコントローラーのルーティングがネストしているとしましょう。
- その場合、コードはこんな感じになります。
- __モデルクラスのインスタンスを親クラスと子クラスの順で２つ__記述すれば良いのですね。

```ruby
<%= form_with model: [@post, @comment] do |f| %>
  <%= f.text_field :comment%>
  <%= f.submit %>
<% end %>
```

# 参考
https://pikawaka.com/rails/form_with
https://qiita.com/hmmrjn/items/24f3b8eade206ace17e2
ビジネス統計スペシャリスト（エクセル分析ベーシック ）

2020年10月25日にビジネス統計スペシャリスト（エクセル分析ベーシック ）を受けました。
合格したので記事を書いておきます。
少しでも次受ける方の参考になれば幸いです。

## 受験理由
■１ データ分析の仕事で案外エクセルを使うことを知ったため
■２ ビジネス統計スペシャリスト（エクセル分析スペシャリスト）を受ける前に取っておきたかったので

## 感想
■１ データ分析の仕事をしたことがあり、統計検定3級とMOS Excel 2016を取得していれば、1週間ぐらい勉強すれば受かると思います（私はこの試験の前日にMOS Excel 2016のエキスパートを取得したので、その勉強も役に立ったかもしれません）。
■２ 模擬試験よりも本番の方が難しい気がしました。
■３ [アオテンストア](https://aoten.jp/)で模擬試験と動画を購入できるので、それをやっておけば受かると思います。
	
## 学習教材
■１ Excelで学ぶビジネスデータ分析の基礎（初版第5刷）（株式会社オデッセイコミュニケーションズ）
・・・実はこれはほとんど使っていません。アオテンストアで動画を購入したら、この本の内容を動画で解説していたので、読まなくてもよいかなと思い、ほとんど読みませんでした。
■２ 動画で理解！ビジネスデータ分析の基礎 全3編セット 
・・・この動画を購入するのなら、１の本はいらないかもしれません。紙媒体でも勉強したい人は購入すればよいです。
■３ ビジネス統計スペシャリスト エクセル分析ベーシック 模擬テスト 
・・・模擬テストは3回分あります。

## 学習方法
■１ 動画と模擬テスト実施
・・・動画を一回視聴して（全3編を全て視聴）、そのあと模擬テスト1を解きました。模擬テストで理解していない点に関しては再度その部分の動画を見ました。その後、模擬テスト2を解きました。わからない点に関しては、また動画を見て復習しました。繰り返しのようですが、模擬テスト3を解き、不明な点は動画を視聴しました。最後は試験当日に模擬テスト（模擬テスト1~3）を一気に解きました。

## 試験
■１ 模擬テストの1問目は簡単な問題から始まるのですが、本番の試験は1問目が難しめの問題でしたので、そこでリズムを崩されると時間内に解き終わらないかもしれません。簡単な問題と難しめの問題が交互にでる感じですので、難しめの問題は飛ばして、簡単な問題を解いていった方がよいです。自分は最初の問題にリズムを狂わされたため、残り30秒ぐらいで最後の問題を解き終えました。

## 反省点
■１ 模擬テストでは最初の問題の難易度が低かったので、本番もそうだと思い込んでいたら、最初の問題でリズムを崩された点。

## 試験前にやっておいてよかったこと等
■１ 試験直前まで模擬テストを解いて、時間内に解く感覚を磨いておいた点。試験時間内に全部解けたのは（ギリギリで解き終わったのですが）、最後まで時間内に解く練習をしていたからだと思います。
意外と簡単にできた。パスワードを入力させずにユーザー情報を更新する方法

## 概要
今回の記事は表題の通り「パスワードを入力させずにユーザー情報を更新する方法」です。
Railsでとあるアプリケーションを作成中に、どうにかしてパスワードを入力させずにユーザー情報を更新できないものかと考えました。
updateメソッドではパスワードの入力を必須としているようです。
で、よく考えてみたらSNSやECサイトなどの多くのWEBアプリケーションは、ユーザー名やプロフィールなどをパスワードを入力せずとも更新可能です。
updateメソッドをオーバーライドとかしなくても、意外と簡単に出来るのでは...と思い調べてみました。

## 実際にやったこと
update_without_passwordという、そのまんまな名前をしているメソッドがありました。 
これを用いて今回は下記のように実装しました。
単純にパラメータに含まれるパスワードが空かどうかで、使用するメソッドを振り分けています。

```
# パラメータに含まれるパスワードが空の場合、
if params[:password].blank?
  # パスワードなしでユーザー情報を更新
  @user.update_without_password(user_params)

# パラメータにパスワードが含まれていた場合
else
  @user.update(user_params)
```


## 注意点
モデルに以下のような記載があると、update_without_passwordメソッドをつかった際にエラーになります。
パスワードの入力を必須にする、という意味のバリデーションですね！

app/models/user.rb

```
validates :password, presence: true
```
onオプションでバリデーションをかけるアクションを指定しましょう。
以下のようにすれば、ユーザーを作成する際のみバリデーションがかかります。

```
validates :password, presence: true, on: :create
```
Django APIドキュメントにSwaggerの設定をする

#APIドキュメント
APIがたくさん増えてどんなAPIがあるかわからない!!
的なことが起きたのでDjangoでAPIドキュメントの設定をしていきます😃

そこで今回は、`Swagger`を導入していきたいと思います😃


#設定方法

###インストール

```bash:terminal
pip install drf_yasg
```
`drf_yasg`は、`djangorestframework`のバージョンによっては、エラーが発生するようなので注意です😭😭😭
私がそれ⇦ 
(djangorestframeworkのバージョンが3.12だと出るかも😭)
その場合は、drf_yasg2をインストール

```bash:terminal

pip install drf_yasg2
```

###settingのINSTALLED_APPSに追加

drf_yasgの方はdrf_yasg2を適時読み変えてください。

```python:setting.py
INSTALLED_APPS = [
    ...
    'rest_framework',
    'django_filters',
    'drf_yasg2', # <- or drf_yasg

]
```

###プロジェクトのurls.pyに追加

```python:urls.py
from drf_yasg2 import openapi # <- or from drf_yasg
from drf_yasg2.views import get_schema_view # <- or from drf_yasg

schema_view = get_schema_view(
    openapi.Info(
        title="Snippets API",
        default_version='v1',
    ),
    public=True,
    permission_classes=(permissions.AllowAny,),
)

urlpatterns += [
    re_path('^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),
    path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
    path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
]

```
#完成

ブラウザでアクセスすると
http://localhost:8000/redoc/
や
http://localhost:8000/swagger/

こんな感じで確認することができます😃😃😃😃😃😃
![スクリーンショット 2020-10-25 23.53.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563930/ec955447-d43b-b276-9eab-793268d1f758.png)


[公式サイトはこちらです!!](https://github.com/axnsan12/drf-yasg)

以上!!
お疲れ様です☺️☺️☺️☺️☺️
【C#】int型を1バイト区切りの16進/2進数文字列へ変換する拡張メソッド

#0. はじめに
.NET標準の`Convert.ToString( int value, int toBase )`は
10進数から2, 8, 16進数に変換した文字列を返してくれますが、
個人的に文字列の形式がイマイチな気がするのでピカイチにする拡張メソッドを作りました。
何らかの参考になればと:hotsprings:

#1. こーしたい
例えば下のように`Convert.ToString()`を使って数値を16進数、2進数に変換すると、

```cs:sample.cs
int n = 9999999;
Convert.ToString( n, 16 );
Convert.ToString( n, 2 );
```

出力は以下になります。

```
98967f
100110001001011001111111
```

**この出力形式のイヤなところ**:poop:
・バイトの区切り位置が分からん
・オール0のバイトは文字列に変換してくれない
・パッと見何バイトか分からん
・16進数の場合は小文字なのがなんかイヤ

**こうあってほちかった:cry:**

```
00 98 96 7F
00000000 10011000 10010110 01111111
```
#2. こーしました
ということで、DIY（てめーでやれ）の精神にのっとり以下の拡張メソッドを作りますた。

```cs:Int32Extensions.cs
using System;
using System.Linq;

namespace MyLibrary.Extensions
{
    /// <summary>
    /// Int32 拡張メソッドクラス
    /// </summary>
    public static class Int32Extensions
    {
        /// <summary>
        /// 2進数表記の文字列に変換します。
        /// </summary>
        /// <param name="value">変換対象の値</param>
        /// <returns>16進数表記の文字列（形式：11111111 ... 11111111）</returns>
        public static string ToBin( this int value ) => value.ToAnyBase( 2, "11111111".Length );

        /// <summary>
        /// 16進数表記の文字列に変換します。
        /// </summary>
        /// <param name="value">変換対象の値</param>
        /// <returns>16進数表記の文字列（形式：FF FF FF FF）</returns>
        public static string ToHex( this int value ) => value.ToAnyBase( 16, "FF".Length );

        /// <summary>
        /// 8進数表記の文字列に変換します。
        /// </summary>
        /// <param name="value"></param>
        /// <returns>8進数表記の文字列（形式：037 777 777 777）</returns>
        public static string ToOct( this int value ) => value.ToAnyBase( 8, "777".Length );

        /// <summary>
        /// 10進数の値を、4桁区切りの基数表記の文字列に変換します。
        /// </summary>
        /// <param name="value">変換対象の値</param>
        /// <param name="toBase">変換対象の基数</param>
        /// <param name="length">変換対象の基数における、1バイトを表現可能な桁数(例: 16進数 = "FF" = 2 )</param>
        /// <returns></returns>
        private static string ToAnyBase( this int value, int toBase, int length )
        {
            var strs = Convert.ToString( value, toBase ).ToUpper()
                              .PadLeft( length * sizeof( int ), '0' )
                              .Select( ch => ch.ToString() );

            return string.Join( string.Empty, strs.Select( ( s, i ) =>
                                  ( i + 1 ) % length == 0 ? s + " " : s ) ).TrimEnd();
        }
    }
}
```

中核処理`ToAnyBase()`を`ToHex()`、`ToBin()`から呼び出して変換を行っています。
ちょこっと変更すれば`short`や`long`にも対応できそうです。
以下のように呼び出して使います。

```cs:sample.cs
int n = 9999999;
n.ToHex();
n.ToBin();
```

すると、冒頭にお見せした個人的ピカイチな文字列を返してくれます！**やったぜ。**:sunglasses:

```
00 98 96 7F
00000000 10011000 10010110 01111111
```

#3. 他の n 進数にも変換したい
実は`ToAnyBase()`内で使用している`Convert.ToString()`の仕様で
2、8、10、16進数にしか対応できません。。。。
なので（実用的かどうかは別として）、5進数や7進数に変換したい場合は
別途処理をﾓﾆﾓﾆ書く必要があります。ｺﾞﾒﾝﾅｻｲ (´ω`/ )

**Convert.ToString()を笑うものはConv(ryに泣く**

#4.おわりに
今回はちょっとした小ネタを投下させていただきました。
現在アイディア募集中なので、
他にもこんな拡張メソッドが欲しい！いや作れ！などなど
コメントお待ちしておりまーす:postbox:
サクッとPython + OpenCVで顔検出した時のメモ

#目次
[1.仮想環境の準備](#仮想環境の準備)
[2.openCVのインストール](#openCVのインストール)
[3.顔検出のプログラム準備](#顔検出のプログラム準備)
[4.分類器のファイルを取得](#分類器のファイルを取得)
[5.実行](#実行)
[6.ソースコード](#ソースコード)

# 仮想環境の準備
opencvEnvの環境をvenvで作成

```
$ python3 -m venv opencvEnv

# activate　しておく
$ source opencvEnv/bin/activate

(opencvEnv)$  ...
```


# openCVのインストール
pipでopenCVをイントール  

```
(opencvEnv)$ pip install opencv-python

Collecting opencv-python
  Downloading https://files.pythonhosted.org/packages/e2/a9/cd3912ca0576ea6588095dce55e54c5f0efeb3d63fb88f16f4c06c0fac8d/opencv_python-4.1.2.30-cp36-cp36m-macosx_10_9_x86_64.whl (45.2MB)
    100% |████████████████████████████████| 45.2MB 721kB/s
Collecting numpy>=1.11.3 (from opencv-python)
  Using cached https://files.pythonhosted.org/packages/22/99/36e3408ae2cb8b72260de4e538196d17736d7fb82a1086cb2c21ee156ddc/numpy-1.17.4-cp36-cp36m-macosx_10_9_x86_64.whl
Installing collected packages: numpy, opencv-python
Successfully installed numpy-1.17.4 opencv-python-4.1.2.30
import cv2
```

# 顔検出のプログラム準備
face_detect.pyを作成する   

```python:face_detect.py
import cv2

if __name__ == '__main__':
    # 定数定義
    ESC_KEY = 27     # Escキー
    INTERVAL= 33     # 待ち時間
    FRAME_RATE = 30  # fps

    ORG_WINDOW_NAME = "org"
    GAUSSIAN_WINDOW_NAME = "gaussian"

    DEVICE_ID = 0

    # 分類器の指定
    cascade_file = "../xml/haarcascade_frontalface_alt2.xml"
    cascade = cv2.CascadeClassifier(cascade_file)

    # カメラ映像取得
    cap = cv2.VideoCapture(DEVICE_ID)

    # 初期フレームの読込
    end_flag, c_frame = cap.read()
    height, width, channels = c_frame.shape

    # ウィンドウの準備
    cv2.namedWindow(ORG_WINDOW_NAME)
    cv2.namedWindow(GAUSSIAN_WINDOW_NAME)

    # 変換処理ループ
    while end_flag == True:

        # 画像の取得と顔の検出
        img = c_frame
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        face_list = cascade.detectMultiScale(img_gray, minSize=(100, 100))

        # 検出した顔に印を付ける
        for (x, y, w, h) in face_list:
            color = (0, 0, 225)
            pen_w = 3
            cv2.rectangle(img_gray, (x, y), (x+w, y+h), color, thickness = pen_w)

        # フレーム表示
        cv2.imshow(ORG_WINDOW_NAME, c_frame)
        cv2.imshow(GAUSSIAN_WINDOW_NAME, img_gray)

        # Escキーで終了
        key = cv2.waitKey(INTERVAL)
        if key == ESC_KEY:
            break

        # 次のフレーム読み込み
        end_flag, c_frame = cap.read()

    # 終了処理
    cv2.destroyAllWindows()
    cap.release()
```

# 分類器のファイルを取得  
顔検出に使用する`haarcascade_frontalface_alt2.xml`を以下のサイトから取得し、<b>任意の場所</b>にファイルをダウンロードする。  

https://ja.osdn.net/projects/sfnet_magicvisionport/downloads/mvp/cascades/haarcascade_frontalface_alt2.xml/

# 実行
face_ detect.pyを実行する。ターミナルからカメラのアクセス許可を求めらるので許可する。

```
(opencvEnv)$ python face_ detect.py
```

カメラで取得できる映像から顔検出することができる。カメラは[Esc]で強制終了できる。  


# ソースコード
今回のソースコードは以下のリポジトリの`face_detect.py`から転載。  

https://github.com/kawakeee/openCV_practice/blob/master/detection/face_detect.py

## 参考記事  
[Webカメラを使ってリアルタイムに顔検出してみる](https://qiita.com/mix_dvd/items/98feedc8c98bc7790b30)


個人ブログもやっています。[長野エンジニアライフ](https://kawakeee.hatenablog.com/)
【個人的備忘録】GASでGoogle Spread Sheet の値を読み取ってLINE Botに送った話

#やったこと
・LINE Bot宛に特定のメッセージを送ることで，Google Drive 上のSpread Sheetのセルの値を読み取り，それをメッセージとして返すという流れをGoogle Apps Scriptで実現した．
#使い方
① Google DriveでGASのスクリプトファイルを作成する．
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483686/84407ff6-29d3-bab9-78de-4df5bae51d3f.png)
②以下のスクリプトをコピペ．LINE Messaging APIのアクセストークンとスプレッドシートのURLを入力する．

```javascript

// LINE Messaging APIのアクセストークン 
var ACCESS_TOKEN = 'hogehoge' 
  
// ユーザがメッセージ送信したときに動く関数
function doPost(e){
    var replyToken = JSON.parse(e.postData.contents).events[0].replyToken; 
    var userMessage = JSON.parse(e.postData.contents).events[0].message.text; 
    var url = 'https://api.line.me/v2/bot/message/reply'; 
    var headers = { 
      'Content-Type': 'application/json; charset=UTF-8' ,
      'Authorization': 'Bearer ' +ACCESS_TOKEN 
    };

    //　Google Spread Sheetを開き，読み込む
    var sheet = SpreadsheetApp.openByUrl("https://hugahuga");
    var val = sheet.getRange("A1").getValue();
  
    var reply = null;

    if(userMessage === 'A1の値を教えて！'){
     reply = "A1の値は" + val + "です．";
    }else{
     reply='A1の値を教えて！と言うことでA1の値を返します．';
    }

     //送信内容
    var payload = JSON.stringify({
      'replyToken': replyToken ,
      'messages': [{   
         'type': 'text' ,
         'text': reply
        }] 
      } ) 
    
    var options = { 
      'headers' : headers ,
      'method' : 'post' ,
      'payload' : payload }; 

    // メッセージを応答 
    UrlFetchApp.fetch(url ,options)
}
```
③　公開→ウェブアプリケーションとして導入と進んで，
Project version：New
Execute the app as：Me
Who has access to the app：Anyone
と設定して「更新」を選択．Webアプリとしてデプロイされる．

④表示されるURLをWebhookURLとしてLINE Messaging APIに登録する．

上のスクリプトでは，セルのA1の値を読み取っている．
LINEで「A1の値を教えて！」と送信すると，A1の値が返ってくる．

以上．
コンソールから任意のテキストを LINE に通知できる自作コマンドを用意する

# はじめに
データ分析や機械学習などで長時間の処理をコンソール上で実行する際、処理の途中経過や終了を LINE で通知してもらえたら便利ですよね。というわけで、引数で指定したテキストを LINE で通知してくれるコマンドを自作して使ってみています。

# やったこと
[LINE Notify](https://notify-bot.line.me/ja/) の [通知 API](https://notify-bot.line.me/doc/ja/) を `curl` で叩くシェルスクリプトに実行権限を付けてコマンド化しました。

## LINE Notify を設定する
作業は以下のとおりです。

- LINE で通知先としたいグループを作る。
- 作ったグループに "LINE Notify" を招待する（メンバーとして加える）。
- [Line Notify のマイページ](https://notify-bot.line.me/my/) でアクセストークンを発行する。
    - このとき、通知の送信先には、作っておいたグループを指定します。
    - 発行されたアクセストークンはシェルスクリプトで使います。
    - アクセストークンは重要なセキュリティ情報です。自分以外には知られないよう管理しましょう。

## シェルスクリプトを用意する
引数（テキスト）を LINE Notify の 通知 API を使って通知するシェルスクリプト（ファイル名を例えば `line_notify` としておきます）は、以下のような感じになります。

```bash:line_notify
#!/bin/bash

API_URL=https://notify-api.line.me/api/notify
API_TOKEN=<発行したトークン>

if [ $# -ne 1 ]; then
  exit 1
fi

curl -X POST -H "Authorization: Bearer $API_TOKEN" -F "message=$1" $API_URL
echo
```

## コマンド化する
作ったシェルスクリプト `line_notify` に実行権限を付与します。もちろん、あらかじめパスを通しておいた場所に置いても使いやすいと思います。

```
$ chmod 700 line_notify
```

# 使い方
通知したいテキストを引数にして、`line_notify` を実行してみましょう。

```
$ line_notify '処理が完了しました！'
```

コンソールに以下が表示されれば成功で、LINE にテキストが通知されます。

```
{"status":200,"message":"ok"}
```

![Screenshot_20201025-223719.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/336603/6a499eab-44c6-e7f0-3188-1578e1ca70fb.png)

# おわりに
時間がかかる処理の途中や最後に `line_notify` を入れて LINE へ通知を送るようにしておけば、安心して PC の前を離れることができる、かもしれません。

# 参考
- [コマンドラインから LINE にメッセージを送れる LINE Notify - LINE ENGINEERING](https://engineering.linecorp.com/ja/blog/using-line-notify-to-send-messages-to-line-from-the-command-line/)
- [bashシェルスクリプトでLINE通知関数を作成した - 塵積ぶろぐ](https://chiritsumo-life.com/20200821/line-notify-bash/)
- [コンソール上の処理終了通知をslackに投稿する - Qiita](https://qiita.com/iganari/items/b78644cff91f0b6a53cd)
AWS lambdaでPOST+JSONをテストイベント、Webアプリからのイベントに対応する

###やりたい事
lambdaにPost+JSONが来た時に、bodyからデータを取り出し変数に格納したいが、
テストイベントとWebアプリからのイベントで別のコードに分けていたので、同じにしたい

###テストイベント用のコード
まずテストイベントでは以下のようなJsonを使っていた

```
{
  "body": {"name":"test","score":0}
}
```

受け取りの処理は以下のように取得できる

```
exports.handler = async (event, context) => {
    let bodyMessage = event.body;
    
    let name = bodyMessage.name;
    let score = bodyMessage.score;
}
```

しかし、Webアプリケーション側でbodyにJSONを付与した場合はJSON.Parseをしないとデータが取得できず、nameとscoreの変数に格納される値は空欄となってしまっていた

##Webアプリ用のコード

Jsonの形式は同じなので省略
以下のように取得する

```
exports.handler = async (event, context) => {
    let bodyMessage = JSON.parse(event.body);
    
    let name = bodyMessage.name;
    let score = bodyMessage.score;
}
```

JSON.parseをする事でJSONに変換し、変数に値を格納していた。
先ほど作ったテストイベントを使うと以下のようにエラーが起こる

```
ERROR	Invoke Error 	{"errorType":"SyntaxError","errorMessage":"Unexpected token o in JSON at position 1","stack":["SyntaxError: Unexpected token o in JSON at position 1","    at JSON.parse (<anonymous>)","    at Runtime.exports.handler (/var/task/index.js:10:28)","    at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)"]}
END RequestId: 554eb535-495a-423c-9c7f-47419d0e8dae
```

##解決策

以下のコードで分岐させる事で解決したが、コードがテスト専用のコードになっているため、良くない。

```
let bodyMessage = event.body;

//Webアプリケーションからの場合、parseをしないとundefineになる
if(bodyMessage.name===undefined){
    bodyMessage = JSON.parse(event.body);
}
```

一旦はこの状態で利用しているが、より良い方法が見つかれば追記する。
MOS Excel 2016 expert

2020年10月24日にMOS Excel 2016 expertを受けました。
合格したので記事を書いておきます。
少しでも次受ける方の参考になれば幸いです。

## 受験理由
■１ これまで我流でやってきたので正式な方法を学ぶため
■２ 仕事の効率化のため
■３ ビジネス統計スペシャリスト（エクセル分析スペシャリスト）を受ける前に取っておきたかったので

## 感想
■１ MOS Excel 2016を取得しており、エクセルを仕事で使っている人であれば、1週間（毎日２～３時間程度）ほど勉強すれば受かると思います。私は、試験当日に猛烈に詰め込みましたが。
■２ 模擬試験と言い回しが異なっているので、本番の試験の方が難しく感じました。
■３ 今回紹介している試験対策の本にはCD-ROMがついており（※学習教材の箇所を参照してください）、動画での解答があるので、試験対策の本を買って勉強するだけでもよいかもしれません。
	
## 学習教材
■１ Microsoft Office Specialist Microsoft Excel 2016 Expert 対策テキスト&問題集 (よくわかるマスター)（第2版第6刷）（富士通エフ・オー・エム株式会社 (FOM出版), 2020, FOM出版）
・・・仕事でエクセルを使っているのであれば、基本的にはこれだけやれば問題ないです。エクセル使ったことある人なら、この教材のCD-ROMをインストールして模擬試験を全て理解して解けるようになれば受かると思います。私は本を読んでいませんが、気になる場合は、本を読んでもよいかもしれません。模擬試験は正解と認識されにくいのですが、動画での解答を確認して、自分の行った操作と同じであればOKです。また、キューブ関数はわからなくても受かるので、理解できない場合は、捨てても問題ないです。

## 学習方法
■１ 上記の学習用教材の模擬試験5回分を解き（2周しました）、不正解の箇所に関しては、動画で解答を見て勉強しました。
・・・時間がなかったので、1週間だけ勉強しました。月曜～金曜の仕事終わりに模擬試験5回分を解き（1週目）、試験当日（土曜日）に模擬試験5回分一気に解きました（2週目）。

## 試験
■１ 言い回しが模擬試験と違うので、「模擬試験のあれのことかな？」と予想しながら解きましたので、問題の意味を理解して解答しているか不安な状態で解き進めました。また、ブックの上書き保存してはいけないと、いくつかのタスクに書いてあったのですが、これに関しては正直意味がわからなかったです。そのタスクに行く前に一回上書き保存したので、ヤバいかもと思いながら、解き進めましたが問題なかったようでした。

## 反省点
■１ 運よく受かったからよかったですが、勉強する時間が足りていなかったので、解答に自信がなく落ちたかもと思いました。時間があるのであれば、模擬試験は3～4周くらいした方がよいです。

## 試験前にやっておいてよかったこと等
■１ 試験当日に模擬試験5回分解いて、操作方法をチェックしていなければ落ちていたと思います。試験当日に試験直前まで模擬試験を解きまくるのは有効です。使用する関数が意外と多いため、短期記憶でもよいので、覚えていないと時間内に終わらないかもしれませんので。
Spree:: Taxonのカラムを解説

solidus使っていると初心者にとっては「。。。ん？」みたいな状態ですよね。
この記事を読まれていると言うことは少し全体像が掴めて、「Spree::Taxon」にはどう言ったカラムが存在するんだ？」と言うところなのかなと思います。:point_up:
そこで今回は「Spree::Taxon」内のカラムについて簡潔に紹介と説明をしていきます。

##Solidusのバージョン
solidus 2.0.9

##カラムの紹介と説明

Spree::Taxonのid=1をのぞいてみましょう。
![スクリーンショット 2020-10-25 19.05.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696807/0f895d7f-b2cd-da04-0c4a-a2e3871c0fc8.png)

それではここにあるカラムについて説明します。

###id
id。

###parent_id
![スクリーンショット 2020-10-25 22.37.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696807/d1ee0e93-e6d5-c971-0d5f-f430671085e8.png)
例えばこのような入れ子構造になっていた場合、以下のtaxonのparent_idをそれぞれ示します。
Category　▶︎　parent_id:nil
Clothing,Shoes　▶︎　parent_id:1
T-shirts,Shirts,Socks ▶︎　parent_id:2
Boots,Sandals,Sneakers ▶︎　parent_id:3
つまり、その商品が所属する一つ上のtaxonのid。

###position
画像リスト中のImageの配置場所を設定する。
例として，「２」の値では，「１」の値の後で表示される。

###name
分類（taxon）名。

###permalink
その商品のtaxon内でのurl。

###taxonomy_id
![スクリーンショット 2020-10-25 22.41.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696807/aa0ace2b-dda1-b544-1de8-36228e87829a.png)
所属するtaxonomyのid。
Clothing,Shoesを含めそれ以下　▶︎　taxonomy_id:1(Category)
NIKE,Ferrari,GUUCI　▶︎　taxonomy_id:2(Brands)

###lft
商品の階層構造の中にある位置。
awesome_nested_set-Gem参照。

###rgt
商品の階層構造の中にある位置。
awesome_nested_set-Gem参照。

###icon_file_name
調査中。

###icon_content_type
調査中。

###icon_file_size
調査中。

###icon_updated_at
調査中。

###description
分類（taxon）紹介文。

###create_at
分類（taxon）が作られた時間。

###update_at
分類（taxon）が更新された時間。

###meta_title
HTMLのタグ。空の場合はnameが使用される。

###meta_description
SEO用で、サーチエンジン向けの説明。

###meta_keywords
SEO用で、サーチエンジン向けのキーワード。

###depth
そのtaxonの所属するディレクトリの深さ。
例えば
Category,Brands　▶︎　depth:０>
Clothing,Shoes,NIKE,Ferrari,GUCCI　▶︎　depth:1>


<関連情報>
Spree::Productのカラムを解説
https://qiita.com/roooll12/items/92b370741a53c8dd268c

Spree::Taxonomyのカラムを解説
https://qiita.com/roooll12/items/8b788e01309f0593934b

駆け出しsolidus開発者にとってSpree::Taxonモデルを理解する糧になれば幸いです！
JavaScript で collect と scan

JavaScript には filter, map, reduce などの配列を扱う便利な関数がいくつかありますが，他のモダンな言語にはあるけど JavaScript にはない関数というのもあります。今回はその中で `collect` と `scan` という関数を自作してみます。

## collect

map と flat を合わせたようなものです。
各要素に対して指定された関数を適用し，結果を連結したリストを返します。

参考：https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-listmodule.html#collect

**（2020/10/26 追記）**
コメントいただきました。普通に同じ意味の `flatMap` というのがありますね。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap
ランタイムが古くて使えないなどの理由がない限りは必要ないですね。
※ また，その場合でも「大きな配列の場合は避けるべきである」と上記リンクで警告されてます。

#### ソースコード

``` js
const collect = (list, fn) => (
  list && list.map(fn).reduce((acc, x) => acc.concat(x), [])
);

Array.prototype.collect = function(fn) {
  return collect(this, fn);
}
```

#### 実行例

``` js
[3, 4, 5].collect(x => [...new Array(x).keys()].map(x => x + 1))
// > [1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5]
```

任意の数を受け取ると１からその数までの配列を生成する関数を適用しています。
適用する関数では 3 なら [1, 2, 3] が，4 なら [1, 2, 3, 4] が返りますが，collect はそれらを展開した結果を返します。


## scan

fold (reduce) に似ていますが，最終的な結果だけでなく，途中経過の結果の配列を返します。

参考：https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-listmodule.html#scan

#### ソースコード

``` js
const scan = (list, fn, initialValue) => (
  list && list.reduce(
    ([acc, scanAcc], cur, idx, src) => {
      const ret = fn(acc, cur, idx, src);
      scanAcc.push(ret);
      return [ret, scanAcc];
    },
    [initialValue, []]
  )[1]
);

Array.prototype.scan = function(fn, initialValue) {
  return scan(this, fn, initialValue);
}
```

#### 実行例

``` js
[1, 2, 3, 4, 5].scan((a, x) => a + x, 0)
// > [1, 3, 6, 10, 15]
```

アキュムレーター `a` に各要素 `x` を加算する関数と初期値 `0` を指定します。

```
 0 + 1 =  1
 1 + 2 =  3
 3 + 3 =  6
 6 + 4 = 10
10 + 5 = 15
```

このような順に計算されていきます。fold (reduce) では，最終結果 15 が返却されますが，scan の場合は途中結果も含めて各要素に適用した結果が配列として返却されます。
kotlinxをインポートする 

#環境

windows10
Android Studio 4.1
JRE: 1.8.0_242-release-1644-b01 amd64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o


#kotlinxがインポートされていない場合
バージョンアップの激しい言語の参考書あるあるだが、サンプルコード通りに入力しても動かないんじゃ~~BOKE~~
ってことで、ググってもよく分からなかったので記述。

```
import kotlinx.android.synthetic.main.activity_main.*
```

以下のファイルに「id 'kotlin-android-extensions'」を追加する.

```app\build.gradle
plugins {
    id 'com.android.application'
    id 'kotlin-android'
    //以下１行追加
    id 'kotlin-android-extensions'
}

（省略）
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547467/0fb75592-8e7d-0ac6-69e5-0f161fa1aea1.png)



プラグインダウンロードしますか？（みたいな）メッセージでるのでOKを押す。もしくは、「提案を適用」
（しばらく掛かる）その後、上のタブで「Sync　Now」を押す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547467/32c60b3b-b48e-2659-96e1-bd89d6c56142.png)



kotlinx　インポートすることで、画面で作成したボタンのid「morningBtn」が見えるようになる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547467/3dcbcd39-ede5-26f6-3b2c-a78378c072eb.png)

左上プルダウンメニューで、プロジェクトとandroidを切替
app>src>main>java>(プロジェクト名)>MainActivity.kt

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547467/f1be2643-8bf5-1ad1-408a-8cf8d20c9024.png)

以上
【JavaScript】仮引数の括弧{}の挙動を理解した

#概要
ES2015の{}←コイツの記法で惑わされたので自分の理解の範囲でまとめる。
CやJavaは嗜んでいた私。JavaScriptを勉強し始めて現れた`{ hoge }`の表記。{}ってナニ？
で、調べた。{}を利用すると基本的にふたつ挙動がある。

# 分割代入
{}で囲うとそのプロパティの値を代入できる

```js
const { a } = { a: 1, b: 2 } //a=1
const { a, b } = { a: 1, b: 2 } //a=1, b=2
```
なお分割代入は配列でも使える。
[分割代入 - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)

# プロパティ名の省略
変数やメソッドをオブジェクトに入れると、プロパティを省略できる。
プロパティ名はその変数名,メソッド名。

```js
  const a = 1
  const b = {a} //b = { a: 1 }
  //const b = { a: a }と同じ

  const c = x => {
    console.log({x})
  }
  c(a) //{ x: 1 }
  c(b) //{ x: { a: 1 } }
```

# 仮引数で{}を使うと分割代入
分割代入もプロパティ名省略も理解したぞーと思ったらここがややこしい。

```js
  const a = 1
  //プロパティ名省略
  const b = { a }


  //仮引数の{}は分割代入
  const c = ({ a }) => {
    console.log(a) //1

    //プロパティ名省略
    console.log({ a }) //{ a: 1 }
  }
```

プロパティ名省略の部分が分割代入のに見えたり見えなかったりでつまずいたのでした。
EC2でJupyterLabやJupyter Notebookを使う

データ分析ではJupyterLabやJupyterNotebookを使うことも多いかと思います。

ちょっとした処理ならローカルで動作させてもいいですが、重い計算を回すときはローカルではなくクラウド上の計算機を使いたい場合も多いと思います。

今回はAWS EC2上でJupyterLabを動かす方法についてメモしていきます（Jupyter Notebookも同じ手順で起動できます）。

# EC2インスタンスを起動してssh接続する

AWSコンソールにログインしてインスタンスを起動します。OSはpythonが入っているubuntuが良いかと思います。

![image-20201025213638286.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201348/e5bedb1a-f295-e174-0f7e-59abf3df684d.png)

自分のIPからの接続しか許可しないようにセキュリティグループを設定します。

![image-20201025214549882.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201348/16a4b386-c4c4-0630-eac4-ccbe364f72f1.png)

インスタンス概要の「パブリックIPv4アドレス」に書かれているIPに対してssh接続してサーバーにログインします。



# JupyterLabをインストールする

OSをubuntuにしている場合、pythonはすでに入っています。

```sh
$ python3 --version
Python 3.8.2
```



pipとライブラリ類を入れていきます。

```sh
sudo apt update
sudo apt install -y python3-pip
```



[公式ドキュメント](https://jupyter.org/install)を参考に、現バージョンで推奨されるインストール方法に従ってインストールしていきます。

```sh
pip3 install jupyterlab
```



PATHにないところにインストールされたようなWARNINGが出ていたので、PATHに追加しておきます。

```
WARNING: The scripts jupyter, jupyter-migrate and jupyter-troubleshoot are installed in '/home/ubuntu/.local/bin' which is not on PATH.
```

```sh
export PATH="$HOME/.local/bin:$PATH"
```



# JupyterLabを起動する

起動時には、jupyter-server側ではすべてのipを許可するように指定して起動します。

```sh
jupyter-lab --ip='0.0.0.0'
```

ローカルPCからブラウザで`http://<EC2インスタンスのパブリックIPv4>:8888`のアドレスに接続するとtokenの入力画面が出てきて、入力すればログインできます。


![image-20201025221235818.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201348/d61fd6e8-2e8e-8fe7-e194-e79eb5c68234.png)

あるいは`http://<EC2インスタンスのパブリックIPv4>:8888/?token=<token>`のようにリクエストパラメータにtokenを含めると直接ログインできます。

ログインするといつものJupyterLabの画面になり、分析を開始できます。

![image-20201025221400207.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201348/ad673c04-96a6-8b13-68d6-41a2ed87f55f.png)


昔ながらのjupyter notebookも同様にipを指定して起動して使うことができます。

```sh
jupyter notebook --ip='0.0.0.0'
```



# TIPS：パスワードでログインしたい場合

tokenの入力が面倒な場合はパスワードを設定できます。

```sh
$ jupyter notebook password
Enter password:  ****
Verify password: ****
```

の1コマンドで設定できます（参考：[Running a notebook server — Jupyter Notebook 6.1.4 documentation](https://jupyter-notebook.readthedocs.io/en/stable/public_server.html)）。


![image-20201025221725711.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201348/165f890f-c520-e5ff-55ac-0ee2bc827a0a.png)
未経験エンジニアが転職を目指す上で意識するべき3つのこと

こんにちは！NAMIです！


寒い時期が続いて家を出るのが億劫な時期になりましたが、



未経験エンジニアで転職を目指して日々頑張っている皆さん、、、、勉強されていますか？


そして毎日勉強するのは当たり前として、Progateを何回も周回して満足されていませんか？

レベルアップして嬉しいのはわかります（それはめっちゃわかります:sweat:）

ですが、それだけでは意味がありません:no_good:

次の段階である「output」中心の学習に切り替えましょうね!(ちなみに私は今ここの段階:triumph:)



さて、ここまではエンジニアを目指す人、現役エンジニアが発信されている内容と同じものであり、ご存知の方も多いと思います:relieved:


ここからは私の個人的な意見ですので、合わないと思った人は時間を無駄にしてしまうので読まずにご自身の勉強を進めてくださいね:wink:




私は未経験エンジニアが転職を目指す上で意識するべき3つのことがあると考えています。

内容は以下の３つです。

1. 「プログラミング」だけを武器にして勝負を挑むのは分が悪すぎること
2. 「大多数の中の一人」にならないこと
3. 「転職後に何がしたいか」を考えること


ここから１つずつ説明しますね:smiley:



1. 「プログラミング」だけを武器にして転職活動へ勝負を挑むのは分が悪すぎること



これも大多数の現場に出ているエンジニアの方が仰っていますが、間違いないと思います。

私たちが転職活動をする際にライバルになるのは、未経験エンジニアだけではありません。

エンジニア経験者、それもベテランエンジニアなど多彩な人材がライバルとなります。

独学やスクールでいくらプログラミングを学んだとしても、現場経験のあるエンジニアにスキルでは勝てません。


では、企業様側からプログラミングの能力だけを未経験者と経験者を比較して見たとしましょう⬇️

・未経験エンジニア(30歳/独学：３ヶ月、スクール：３ヶ月/学んだ言語：HTML,CSS,JavaScript,Ruby)
・2年目エンジニア(30歳/SES：2年【Java中心に業務実施】/学んだ言語：HTML,CSS,JavaScript,Ruby)

これだけの情報を比べて採用担当者はどちらが欲しいと思いますか？

この情報だけならば、2年目エンジニアの方です。

なぜなら、「エンジニアとしての社会人経験がある」という圧倒的なポテンシャルの差が存在しているためです。

現場の人は企画、設計、アプリ開発、テスト実装、AWSを用いたインフラ構築などを経験してきています。

この時点で現場経験もない未経験エンジニアが「プログラミング能力だけで戦う」のは無理があるのがわかります。

なので、企業様側が求める「最低限の」プログラミングができるように意識して、日々の勉強を行いましょう:wink:



2. 「大多数の一人」にならないこと



ここで質問です。


「ダイヤモンドと石をもらえるとしたらどちらが欲しいですか？」


もちろん、「ダイヤモンド」ですよね？


では、それはなぜですか？

答えは「石よりもダイヤモンドの方が市場価値が高いから」です。

この例えから、私が何を伝えたいのかというと、

「エンジニア転職でプログラミングを勉強することは【スタートライン】に立つための準備でしかない」ということです。

私たちのような未経験エンジニアはプログラミングを勉強して成果物を出して、初めて「石」になれます。

やっと「石」になれた人がプログラミング技術をどんなにアピールしたところで、

「石をさらに磨いているよー、すごいでしょ？」

ということになります。

企業様側からすれば、「で？」で終わります。

なぜなら、大多数の人がプログラミングを勉強してくることは「大前提」だからです。

企業様側から「欲しい！」と思われる人材になるためには「ダイヤモンド」にならないといけません。

では、「ダイヤモンド」になるためにはどうしたらいいか？

それは、他人にはない「あなただけが持つ価値」を見つけるしかないです。

つまり、最低限のプログラミング能力＋企業様側にとっての圧倒的な付加価値

というプログラミング以外のアピールポイントが必要ということを頭の片隅に置いておきましょう:wink:



3. 「転職後に何をしたいか」を考える



これも個人的な意見ですが、SNSを散見していると以下のような内容が見受けられます。

・Progateで基礎固め
・Java silver試験の勉強中
・〇〇スクールで勉強中
　　　　　　　　　　　　　　　　　　　　などなど

素晴らしいですね:smiley:

こうやって日々の積み重ねをoutputすることはいいことではあると思います。

では、個人的に聞きたいのですが、「プログラミングを勉強して何を成し遂げたいのですか？」

お金を稼げると聞いたから？ITブームだから？今後一生使えるスキルとして身につくから？

それでも構いません。それは自分にも多少なりともあるのは間違いありません。

しかし、それで大きな障壁にぶつかったときに乗り越えられますか？

SNSで上記のような発言をしている人たちの過去の投稿を見ても、「エンジニアになって成し遂げたいこと」が書いてない人がほとんどです。

その時点でより具体的な長期目標を持つ人と大きな差がつくと自分は考えています。

なぜなら、目標がある人は「迷わない」からです。

そして「迷わない」人は思考が一貫しているため、転職先の企業選択の１つの大きな指標として活かせます。

なので、まだ「目標がない人」はプログラミングの勉強を続けながら考えておきましょうね:sunglasses:




今回、「未経験エンジニアが転職を目指す上で意識するべき3つのこと」というテーマで書かせていただきました。

その内容として以下の３つを取り上げました。

1. 「プログラミング」だけを武器にして勝負を挑むのは分が悪すぎること
2. 「大多数の中の一人」にならないこと
3. 「転職後に何がしたいか」を考えること


また、それぞれの対策として以下に簡単にまとめておきます。

1.　企業様側が求める「最低限の」プログラミング能力を意識して勉強しよう
2.　プログラミング以外の付加価値を見つけよう
3.　エンジニアになって成し遂げたいことを見つけよう


エンジニア転職活動を始めて１ヶ月、まだまだ技術も知識も未熟な自分ですが、

今回の内容が未経験エンジニアの皆様の今後の活動の参考になれば幸いです。

最後まで読んでいただきありがとうございました:relieved:
[memo]ActivityResultContractでActivity間通信を行う

#準備
```build.gradle(app)
    implementation("androidx.activity:activity-ktx:1.2.0-alpha06")
    implementation("androidx.fragment:fragment-ktx:1.3.0-alpha06")
```

#結果を受けとるActivity or Fragment側
```xxx.kt
    private val launcher: ActivityResultLauncher<Intent> = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) {
        if (it.resultCode == Activity.RESULT_OK) {
            doSomething()
        }
    }
```
※公式ドキュメントではprepareCallとあるが、ライブラリバージョンアップ時にregisterForActivityResult()にメソッド名が変更されている
#画面遷移時
```xxx.kt
val intent = Intent(this, yyy::class.java)
launcher.launch(intent)
```
#結果を送るActivity or Fragment側
```yyy.kt
    // fragmentから呼び出す場合はrequireActivity or getActivityでActivityのインスタンスを取得する
    setResult(Activity.RESULT_OK)
```
値を渡したい場合は第二引数にIntentを渡す

#Intentを作らなくても型安全に値を渡すことも可能
[ActivityResultContractを使ったActivity間のデータ受け渡し](https://medium.com/@star_zero/activityresultcontract%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9Factivity%E9%96%93%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E5%8F%97%E3%81%91%E6%B8%A1%E3%81%97-17052bfafde0)
民間企業の次期ネットワーク構想に向けて　第3話

#コロナで見えたセキュリティ問題から次期ネットワーク構想へ
テレワークで問題となるのはセキュリティと通信速度です。
※ここでいうテレワークとは，在宅勤務を指します。
セキュリティに関しては，各企業ごとにポリシーやガイドラインが策定されていると思います。
テレワークの多くは，自宅や公衆回線から社内ネットワークへVPN接続する方式だと思います。
中には，フルクラウドでテレワークでもインターネット接続だけで運用できる企業もあるかと思いますが，本記事では割愛します。
例にもれずウチもVPN接続利用をしています。
VPN接続をした上でPCを使用する場合は，社内ネットワーク経由でインターネットへ出るのでセキュリティはポリシー通りとなり，セキュリティレベルは保たれます。
(ちなみにFortiClientでローカルブレイクアウト利用はしていません)
問題はVPN接続をしないでインターネットなどを利用してしまった場合です。
悪意あるサイトへの接続は「URLフィルタリング」で制御しており，会社が許可したサイトにしか接続できません。
ですが，VPN接続をしないまま使用した場合，社内ネットワーク経由とならず，好きなサイトへ接続する事が出来てしまいます。
この問題を防ぐために，テレワークのガイドラインで「VPN接続を行ってからインターネットを使用する事」としています。
運用でカバーする方法は，必ず「漏れ」が発生します。
システム屋として，「運用でカバー」という言葉は「暫定対策」もしくは「逃げ」です。
運用ではなくシステムで対策する方法がなければ，見た目(正常な運用をした場合を前提)のセキュリティレベルは担保しても，根本的なセキュリティレベルをシステム的に担保したことにはなりません。
#セキュリティ製品のクラウド移行
セキュリティレベルをシステム的に担保するために検討し始めたことは，
①クラウド型FW，クラウド型プロキシ
②クラウド型WAF
③EDR＋NGAV
です。
①クラウド型FW，クラウド型プロキシ
　→社内外問わず全てのインターネット通信をクラウドにあるFW，プロキシを通すことによって同じセキュリティレベルにすることが出来る
②クラウド型WAF
　→IPS/IDSの置換候補＆公開サーバの脆弱性対策を一挙に解決するため
③EDR＋NGAV
　→混在するセキュリティ対策ソフトを整理し，マルウェア対策，ウィルス対策を統合管理できるようにする
③は＋αですが，この際，導入しているセキュリティ製品の整理も含めて見直しをすることにしました。

(次回：第4話)
　ネットワーク構成の大幅な更改
S3からバケット指定でファイルダウンロード、削除するpythonのクライアントアプリ 

## 概要

特定のバケットからファイルをすべて取得したいときにコンソールからだと面倒だったので、
バケットを指定することでファイルを一括で取得できるツールを作ってみました。
(たぶん既にありそうですが・・・)
取得だけでなく削除処理もつけてみました。
(こちらを使用して何か起こっても自己責任でお願いします。)

## 使用ライブラリ


* boto3を使っています。
* exeに固めるため PyInstaller を使用しています。


### ツールの説明

ソース自体は[こちら](https://github.com/dmikita-sss/pythonGui/tree/master/s3)で公開しています。
ツールを起動すると以下のようになります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/657697/6f4f89c0-7aa2-9469-e073-727903d5bc75.png)

* こちらはtkinterを使用して作成しています。
* バケット名はプロパティに設定しているので適宜設定できます。
* 処理内容はファイル取得か削除かを選択できます。
* フォルダ指定はファイル取得するときにどこに格納するかを選択します。
* プロパティファイルにaccess keyとsecret access keyを設定する形になっていますが、 aws configure でアカウントの設定していればこちらの設定は不要です

* ソースのS3に関する部分は以下になります。

```python
        if aws_access_key_id =='':
            s3 = boto3.resource('s3')
            s3client=boto3.client('s3')
        else:
            s3 = boto3.resource('s3',
                                                aws_access_key_id=aws_access_key_id,
                                                aws_secret_access_key=aws_secret_access_key_id)
            s3client=boto3.client('s3', 
                                                aws_access_key_id=aws_access_key_id,
                                                aws_secret_access_key=aws_secret_access_key_id)

        bucketName=self.inputFileName.get()
        resultFolder=self.outputFolder.get()
        dataBaseDir=os.path.join(resultFolder,bucketName)

        executeType=EXECUTE_LIST.index(self.combo.get())


        s3bucket=s3.Bucket(bucketName)
        objs = s3bucket.meta.client.list_objects_v2(Bucket=s3bucket.name)

        for o in objs.get('Contents'):
            key = o.get('Key')
            s3Paths=os.path.splitext(key)
            if len(s3Paths[1]) !=0:
                keys=key.split('/')
                filename=keys[len(keys)-1]
                if executeType==0:
                    outputDataDir=key.split(filename)[0]
                    outputDataDir=os.path.join(dataBaseDir,outputDataDir)
                    os.makedirs(outputDataDir,exist_ok=True)
                    outputDataFile=os.path.join(outputDataDir,filename)
                    s3bucket.download_file(key,outputDataFile)
                else:
                    s3client.delete_object(Bucket=s3bucket.name, Key=key)
```
* ツールの方から入力されたバケット名、処理内容をもとに度の処理を動かすかを判定しています。
* 対象のバケットの中は 

```python
objs = s3bucket.meta.client.list_objects_v2(Bucket=s3bucket.name)
```
の部分で取得できるのであとはfor文で処理をしています。
引数に`Prefix`を追加することで特定のフォルダ、ファイルのみを指定することも可能です。

* ソースを実行しても確認ができますが、クライアントアプリとして使う場合は以下のコマンドでexeを作成します。 ソースのファイル名を `pythonGui.py` とした場合以下のようになります。
    * pyinstaller pythonGui.py --onefile
GitHub Pages で React-TypeScriptで作成したアプリをデプロイする

Qiita 投稿4回目です。今回は**GitHub Pages**に関する記事です。

> 当記事は作成したアプリ(React TypeScript)をGitHub Pages で公開する内容です。

# GitHub Pgaeについて
GitHub PageとはGitHubにより自身のレポジトリのプロジェクトを静的ホスティングを行えるサービスです。

GitHub Pagesでホスティングを行えるのは HTML CSS JavaScriptのみです。サーバーサイドのホスティングを行うことはできません。

また、GitHub Pagesを利用する場合はGitHubアカウントの取得とホスティングを行いたいWebアプリかWebサイトのリポジトリが必要になります。

GitHub　Pagesには利用規約があります。使用制限や禁止要項などが存在します。ホスティングをしたいプロジェクトが利用規約に反していないかを確認してGitHub Pagesを利用しましょう。

利用規約はこちらから（https://docs.github.com/ja/free-pro-team@latest/github/working-with-github-pages/about-github-pages）

# GitHub Pagesを利用した理由
私がなぜ GitHub Pagesを利用したかというとGitHub Pagesが容易に利用できそうだったからです。

私は今まで、Netlifyやfirebaseでフロントのホスティングを行なっていましたが、GitHub Pagesに関する記事を見たときに簡単そうだったので、GitHub Pagesを利用しました。

プロジェクトをGitHubからホスティングできるというのはとても魅力的だと思います。皆様ぜひホスティングにお悩みの際はGitHub Pagesを利用してみてはいかがですか？

# 他のホスティングサービスについて
フロントのホスティングサービスはGitHub Pages意外にも多々あります。

有名なサービスとしてNetlifyやfirebaseなどが存在します。

ホスティングサービスによるプロジェクトの速度のちがいについては正直よくわかりません。

どのサービスも黄本無料で利用することができます。ただし場合によっては有料プランになることもあるそうです。（今まで無料だったので、どうしたら有料になるかは不明。誰か分かる方教えてください）

基本無料ってとてもいいですよね。私のような学習でデプロイを行うにはとてもありがたいです。

# GitHub Pagesのセットアップ

それでは本題のGitHub Pagesの利用方法について解説します。

今回はReactで作成したアプリをGitHub Pagesに公開する方法なので、VueやAngularといった他の人気javaScriptフレームワークの場合異なるかもしれないのでその場合はご了承ください。

デプロイしたいプロジェクトはないがGitHub Pagesを利用してみたい人は **[create react app]** で作成された初期のアプリなどで試してみてください。

リポジトリを作成していない人はリポジトリの作成を行い、リポジトリにソースコードを push してください。

まず

``` bash
yarn add gh-pages @types/gh-pages
```

でGitHub Pagesに関するライブラリをインストールしましょう。

これでめちゃくちゃ簡単にGitHub Pagesにデプロイを行うことができます。

次にインストールをしたgh-pagesを用いて簡単でデプロイができるように設定を行います。

```json 
//...
"homepage": "https://[自身のGitHubのアカウント名].github.io/[デプロイしたいリポジトリの名前]/"

"scripts": {
  //...
  "deploy": "yarn build && gh-pages -d build"
}
```

package.jsonに上記の内容を追加します。

これでGitHub Pagesのセットアップは完了です。

ちょー簡単ですね。

# 作成したReact製アプリをGitHub Pagesにデプロイする

ではGitHub Pagesに作成したプロジェクトをデプロイしましょう。
先ほど追加したpackage.jsonのscriptsを実行します。

``` shell
yarn deploy
```

ではGitHubのリポジトリの**setting**を確認しましょう。

<img src="https://user-images.githubusercontent.com/51228144/97108645-46d2c380-1712-11eb-94cb-bc5f6bc084c5.png" title="GitHub Pages">


これで公開されています！

### しかし ...

URLにアクセスしても何も表示されない！

解決策

``` HTML
<base href="<GitHub Pagesの公開URL>">
```

上記を**public/index.html**の**head**に追加することで表示することができました！

以上がReactアプリをGitHub Pagesにデプロイする方法です。

## 参考サイト
[GitHub Pagesについて](https://docs.github.com/ja/free-pro-team@latest/github/working-with-github-pages/about-github-pages)

[ReactアプリをGitHub Pages(Project Pages)で公開する](https://qiita.com/EisKern/items/15dcf7864fa49df8f247)

[GitHub PagesにReactアプリをデプロイする方法](https://qiita.com/yuitnnn/items/11375ea29ec023d19fdf)
R-日次データの結合

#日次データ

#ライブラリ読みこみ
    library(readr)
    library(data.table)
    library(dplyr)

#データの繰り返し読み込み
   
    list<-read_csv("time.csv")
    master_table<-data.table()
    for( time in list) {
        #データピックアップ
    　  table<-read_csv(paste0(list,".csv"))
        pick<-table[table$id==021,]
        #テーブル作成
        pick_table<-data.table(table(pick_table$id))
        #列名づけ
        colnames(pick_table)<-c("id",as.character(pick[1,"time"]))
        write.csv(pick_table,paste0(list,".csv"),row.names = FALSE)
     }

# データ紐づけ
    time<-list[1]
    master_data<-read_csv(paste0(time,".csv"))
    colnames(master_table)<-c("id","sample")

    for( time in list ) {
        master_table<-full_join(master_table,pick_table,by="id")
    }
    dplyr::select(master_table, -sample)
    master_table[is.na(master_table)]<-0
【Unity】Fungusでゲーム制作(8) 制限時間付きの選択肢・QTEを作る

Fungusの基本的な使い方に関しては[第1回](https://qiita.com/Kirikabu_ueda/items/bfc6e086d408b1cba34b)の記事で解説しておりますので、まだの方はそちらからお読み下さい。

[前回](https://qiita.com/Kirikabu_ueda/items/5eb99f155191fe157f61)は会話ウィンドウや選択肢のUIを作り変えてみました。
今回は制限時間付きの選択肢やQTE（一定時間内にキーを入力しなくてはならないイベント）といったリアルタイム性のあるイベントを実装していきたいと思います。
# 制限時間付きの選択肢を作る
**Menu Timerコマンド**を使うことで選択肢に時間制限を設けることができます。一連のMenuコマンドのどこかに紛れ込ませておけば機能します。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63319/0d18457f-f397-5d21-2f58-9162c01187ac.png)
**Duration欄**は制限時間の秒数を、**Target Block欄**には時間切れになった際に飛ぶブロックを指定します。
プレイして確認してみましょう。以下のように選択肢の下に残り時間ゲージが表示され、空になると時間切れ用のブロックに飛びます。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63319/9464555c-bf93-3cea-73d3-7cea3ac04cb0.png)
# QTEを作る
今回は一定時間内に指定されたキーを1回入力することで展開が分岐する、という単純なQTEを作ってみたいと思います。

先にQTE用のUIを作っておきます。Unity全体のメニューから**「GameObject」→「UI」→「Text」**を選択するとテキストのUIを生成できます。それを選択してInspectorビューに移り、**Rect Transformコンポーネント**で位置を、**Textコンポーネント**でフォントの種類やサイズを調整してください。
押すキーを示すテキストと、残り時間を示すテキストの2つを作っておきます。
またこのまま表示すると見えにくいので、半透明の背景もつけておきます。**「GameObject」→「UI」→「Panel」**と選択してパネルを作り、やはり大きさを調節し、先ほどのテキスト2つをその下に入れます。
だいたい下図のようになるのではないかと思います。ゲーム開始直後から表示されていては困るので、パネルを非アクティブ化して隠しておいてください。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63319/031f1177-2611-f8c1-3eef-5b7135689296.png)
さて中身の実装に移りたいと思います。まず、今回作るQTEがどのような仕組みで動くのかを考えてみましょう。QTEは**「制限時間以内に、画面に表示されたキーを入力させるイベント」**です。これを分解するような形で必要なパーツを考えてみると、以下のようになります。

* 時間制限の仕組み
    * 残り時間を保持する変数
    * 残り時間変数を継続的に減らす仕組み
    * 残り時間変数が0になった時に時間切れ用の処理に飛ぶ仕組み
* キーの入力を常に受け付け、入力が成功したら成功用の処理に飛ぶ仕組み
* 入力すベきキー（と残り時間）を画面に表示する仕組み

1つずつ考えていってみましょう。残り時間を保持する変数は普通に作ってSet Variablesで値を入れればよいですね。変数を継続的に減らすにはループが使えます（Loop RangeでもWhileでもOK）。ただし**普通にループするだけだと一瞬で残り時間が0になってしまうので、短いウェイトを入れます。**そして残り時間が0になったらループを抜けて、時間切れ用の処理に飛べばよいでしょう。
キーの入力受け付けもループの中で行います。これは**GetKeyコマンド**を使います。
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63319/b9368a73-f27a-7e5c-4a38-2eeb2dfacd5f.png)
**Key Code欄**で受け付けたいキーの種類を選択します。種類が多いのですが見ればだいたい分かるかと思います。今回は↑キー（Up Arrow）を指定してみます。**Key Query Type欄**は今回は**Down**に指定してください。初期値のStateのままだと指定されたキーを押しっぱなしにしてQTEに突入したときにもクリア扱いになってしまいます。**Out Value欄**は受け付けた結果を入れるInteger型の変数を指定します。受け付けた場合は1が入ります。

最後に入力すべきキーと残り時間の表示ですが、これはSet Activeコマンドで先ほどのテキストを乗せたパネルをアクティブにし、Set Textコマンドで中身を書き換えればOKですね。ループの外側で入力すべきキーを、内側で残り時間を書き換えます。

方針がまとまったので、実際に組んでみましょう。下図のようになるかと思います。
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63319/8d4dcb02-df50-7530-7bd5-397dc19bd589.png)
起動してQTEが機能しているのを確かめてみましょう。
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63319/0577cd9e-9acc-5f97-aeba-0caebc9bf6ad.png)
今回は制限時間付きの選択肢や、QTEといったリアルタイム性のあるイベントの作り方について取り扱いました。
次回はセリフや指示を並べたテキストから会話イベントを展開してくれるConversationコマンドについて解説する予定です。
「令和の現場力」まとめ

#はじめに
昨今、有名な企業による不祥事を目にすることが多くなってきた。モノづくりの日本！と言われた時代は、どこにいったのか？現場は今、過去の活気ある姿勢は失われ、日々膨大な業務をこなすのに必死で疲弊し壊れ始めている。本書は、そんな現場で働く社員が働くことの楽しさを思い出し、仕事のやりがいを見出すための新しい業務改革のノウハウが詰まった本である。

#コンセプトはYTR
Y = 役に立つ
T = 楽しく
R = 楽に

#生産性は会社よがり
無駄をなくせ！もっと効率的に！と生産性と売上げ向上を追い求めるばかりで人間らしく働くことができず長くは続かない。
人間中心の業革が、人々の眠るの創造性を覚醒させモチベショーンUPに繋がり生産性を上げる。
ここで大切なことは、業務のこなし方(How)ではなく”なぜするのか？(Why)”を伝えることである。

#業務改革は、イベントではなく”常体”に
よし！専門家に頼って、はやりのIOTやAIに頼って一気に業務効率化に！
こんな表面的なデジタル化は生産性を下げ、社員を疲弊させる原因になる。

#創造性と生産性を同時に
変化の少ない一昔まえまでは、会社が決めたことに全社一丸となって突き進むため、効率性が最も重要であった。しかし変化の激しい今日の社会では、効率性だけ、創造性だけの片方を追い求めるだけでは生きのこれない。
そもそも生産性と創造性は相反するものではなく、同時に追い求めることでより相乗効果が生まれるのである。

#戦略よりも実行力が大切
インターネットに情報や答えはある。また、お手頃な値段のサブスクリプションの到来により、誰でも世界最高峰の知にふれるこができる。
暗記を中心にした情報の処理能力よりも、得た情報をどう組み合わせるかの情報の編集能力が大切になる。

#最後はやっぱり人
どれだけすごいものができても、それを使ってくれる人がいないと何も価値がない。プロダクトは賢く使ってくれて初めて価値が生みだす。つまり、**テクノロジーが社会が変えるのではなく、人が社会を変える**のである。

#終わりに
本書は業務改革を、これまでにない新たな視座と、新たな発想でアプローチするための成功のメソッドに溢れた本であった。また本書には、4社の企業による業務改革がインタビュー形式にかかれており、真似してみよう！と思えるほど非常に実践的なものであった。
みなさんもぜひ！

##書籍情報
令和の現場力 デジタル×AI時代の「業革3.0」
出版社 : 日本経済新聞出版 (2019/5/25)
遠藤 功  (著) 山本 孝昭 (著)
【エディタ拡張】ProjectWindowのフォルダ開閉状態をリセットするエディタ拡張

# 概要
開きまくっていたプロジェクトウィンドウ上のフォルダ開閉状態をいったんリセットしたい場合に有効なエディタ拡張です。

# 使い方
![ProjectCollapse.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148284/3908788f-e5dd-115e-20fb-a8b31a26c852.gif)

- `Window/ProjectBrowserHelper`で開きます。
- `Collapse All`

※TwoColumnレイアウトだと動作が完全ではなく、全部閉じるではなく、
現在のフォルダ以下のものだけが閉じられる挙動になっております。

# 環境
- Unity2019.4.13f1～

# コード
[Gist](https://gist.github.com/t-macnaga/387080ad0f157903efd741b93c35acda)にもアップしました。

```ProjectBrowserHelperWindow.cs
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

public class ProjectBrowserHelperWindow : EditorWindow
{
    [MenuItem("Window/ProjectBrowserHelper")]
    static void Init()
    {
        GetWindow<ProjectBrowserHelperWindow>();
    }

    void OnEnable()
    {
        var collapseAllButton = new Button(() => OnClickCollapseAll());
        collapseAllButton.text = "Collapse All";
        rootVisualElement.Add(collapseAllButton);
    }

    void OnClickCollapseAll()
    {
        Selection.activeObject = null;
        var window =
        Resources.FindObjectsOfTypeAll<EditorWindow>().FirstOrDefault(x => x.GetType().Name == "ProjectBrowser");
        if (window == null) { return; }

        new InternalProjectBrowser(window).ClearExpandedIDs();
        window.Repaint();
    }

    /// <summary>
    /// UnityEditor.ProjectBrowserのリフレクション
    /// </summary>
    class InternalProjectBrowser
    {
        SerializedObject so;

        SerializedProperty AssetTreeExpandedIDsProperty => so.FindProperty("m_AssetTreeState.m_ExpandedIDs");
        SerializedProperty FolderTreeExpandedIDsProperty => so.FindProperty("m_FolderTreeState.m_ExpandedIDs");

        public InternalProjectBrowser(EditorWindow ProjectWindow)
        {
            so = new SerializedObject(ProjectWindow);
        }

        public void ClearExpandedIDs()
        {
            so.Update();
            AssetTreeExpandedIDsProperty.ClearArray();
            FolderTreeExpandedIDsProperty.ClearArray();
            AssetTreeExpandedIDsProperty.arraySize = 0;
            FolderTreeExpandedIDsProperty.arraySize = 0;
            so.ApplyModifiedProperties();
            Reload();
        }

        void Reload()
        {
            var methodInfo = so.targetObject.GetType().GetMethod("ResetViews", BindingFlags.Instance | BindingFlags.NonPublic);
            methodInfo.Invoke(so.targetObject, new object[0]);
        }
    }
}
```

# まとめ
フォルダの開閉状態を一気に閉じたい場合、便利かと思います。
JavaScriptテスティングフレームワークのJestとは

#プログラミング勉強日記
2020年10月25日
Babel、Typescript、Node、React、Angularなどで使えるテストの存在を知ったのでまとめる。


#Jestとは
　FaceBook社がOSSとして開発しているJavaScriptのユニットテストのためのツール。公式のドキュメントは[こちらで](https://jestjs.io/)、[日本語のドキュメント](https://jestjs.io/ja/)もある。
　特別な設定をすることなく、他のライブラリを追加することなく、<b>誰でもすぐにユニットテストを書ける</b>のが特徴。

#特徴
　公式ドキュメントにあるようにJestの特徴は以下のようになる。

- zero config
- snapshots
- isolated
- great api
- fast and safe
- code coverage
- easy mocking
- great exceptions


##zero config
　上でも述べているが、JestはJavaScriptプロジェクトにおいて細かい設定が不要なので、すぐにユニットテストを書くことができる。

##snapshots
　テストと一緒にインラインに埋め込んだ状態で表示できるスナップショット機能で大きなオブジェクトを容易に追跡できるテストを作成できる。

##isolated(独立的)
　パフォーマンスを最大化するために、別々のプロセスで実行してテストを並列化する。

##great api
　`it`から`expect`まで、Jestにはすべてのツールキットが1つにまとまっている。ドキュメント化されてメンテナンスもできている。

##fast and safe
　テストが一意なグローバル状態であり、Jestは安全にテストを並列実行することができる。また、開発効率を上げるために前に失敗したテストから実行して、テストファイルの所要時間に基づいて再整理する。

##code coverage
　フラグの`--coverage`を指定することで、追加の設定なしでコードガバレッジを生成する。Jestは最後のテストのファイルを含むプロジェクト全体からコードガバレッジ情報を収集できる。


##easy mocking
　Jestはテストにおけるインポートに独自のリゾルバを使用することで、テストコード外のオブジェクトを簡単にモックできる。豊富なモック機能APIでモックされたインポートを利用して、読みやすいテスト構文で関数呼び出しをできる。

##great exceptions
　テストが失敗したときの理由をわかりやすく表示する。


#参考文献
[第1回 環境の準備とテストの実行](https://app.codegrid.net/entry/2018-jest-1)
[公式ドキュメント](https://jestjs.io/)