OmniAICreator/Qiita-1.07M huggingface dataset:
JavaScript FullCalendar demo timeZone確認

JavaScript の FullCalendar の demo をもとに timeZone を確認
demo は以下より取得
https://fullcalendar.io/docs/getting-started

```html
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<link href='../packages/core/main.css' rel='stylesheet' />
<link href='../packages/daygrid/main.css' rel='stylesheet' />
<script src='../packages/core/main.js'></script>
<script src='../packages/interaction/main.js'></script>
<script src='../packages/daygrid/main.js'></script>
<script>

  document.addEventListener('DOMContentLoaded', function() {
    var calendarEl = document.getElementById('calendar');
    
    var calendar = new FullCalendar.Calendar(calendarEl, {
      plugins: [ 'interaction', 'dayGrid' ],
      defaultDate: '2019-06-12',
      editable: true,
      eventLimit: true, // allow "more" link when too many events
      <!-- timeZone: 'local', -->
      timeZone: 'UTC',
      events: [
        {
          title: 'All Day Event',
          start: '2019-06-01T23:00:00Z',
          end: '2019-06-05T15:59:59Z',
        },
        {
          title: 'Long Event',
          start: '2019-06-07',
          end: '2019-06-10'
        },
        {
          groupId: 999,
          title: 'Repeating Event',
          start: '2019-06-09T16:00:00'
        },
        {
          groupId: 999,
          title: 'Repeating Event',
          start: '2019-06-16T16:00:00'
        },
        {
          title: 'Conference',
          start: '2019-06-11',
          end: '2019-06-13'
        },
        {
          title: 'Meeting',
          start: '2019-06-12T10:30:00',
          end: '2019-06-12T12:30:00'
        },
        {
          title: 'Lunch',
          start: '2019-06-12T12:00:00'
        },
        {
          title: 'Meeting',
          start: '2019-06-12T14:30:00'
        },
        {
          title: 'Happy Hour',
          start: '2019-06-12T17:30:00'
        },
        {
          title: 'Dinner',
          start: '2019-06-12T20:00:00'
        },
        {
          title: 'Birthday Party',
          start: '2019-06-13T07:00:00'
        },
        {
          title: 'Click for Google',
          start: '2019-06-23T07:00:00Z',
          end: '2019-06-27T07:00:00Z'
        }
      ]
    });

    calendar.render();
  });

</script>
<style>

  body {
    margin: 40px 10px;
    padding: 0;
    font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
    font-size: 14px;
  }

  #calendar {
    max-width: 900px;
    margin: 0 auto;
  }

</style>
</head>
<body>

  <div id='calendar'></div>

</body>
</html>

```
pythonのdatetime

pythonのdatetimeについて何回も同じことを調べるため、備忘録としてまとめました。

※IDLE等の対話モードで検証しました。

## 必要なモジュール

    import datetime
    from pytz import timezone

## 取得
### 現在日時
    TODAY = datetime.datetime.now()    #datetime.datetime.today() も同様の結果 
    TODAY    #print(TODAY)
    →　datetime.datetime(2019, 7, 19, 15, 55, 42, 566682)

### 単体要素

    TODAY.year
    →　2019
    TODAY.month
    →　7
    TODAY.day
    →　19    
    TODAY.hour
    →　15
    TODAY.minute
    →　55
    TODAY.second
    →　42
    TODAY.microsecond
    →　566682
	
### 日付のみ

    datetime.date.today()    #TODAY.date() も同様の結果
    →　datetime.datetime(2019, 7, 19)

## 変更
### 時刻を「0時0分0秒」に変更したい
 
    TODAY.replace(hour=0, minute=0, second=0, microsecond=0)
    →　datetime.datetime(2019, 7, 19, 0, 0)

## 変換
### 日付型→文字列

    TODAY.strftime("%Y年%m月%d日-%H時%M分%S秒")
    →　'2019年07月19日-15時55分42秒'

### 文字列→日付型

    DATE_STR = "2019-07-19T15:55:42Z"
    datetime.datetime.strptime(DATE_STR, "%Y-%m-%dT%H:%M:%SZ")
    →　datetime.datetime(2019, 7, 19, 15, 55, 42)

## TimeZone
### UTC

    # UTCの現在時
    datetime.datetime.utcnow()
    →　datetime.datetime(2019, 7, 19, 7, 56, 45, 543211)

    # 取得済みJSTをUTCへ変換
    NOW = datetime.datetime.now()    # JST
    NOW
    →　datetime.datetime(2019, 7, 19, 7, 57, 02, 227882)
    NOW.astimezone(timezone('UTC'))
    →　datetime.datetime(2019, 7, 19, 7, 57, 02, 227882, tzinfo=<UTC>)

## 計算

    # 今日の日時から昨日を計算
    YESTERDAY = TODAY - datetime.timedelta(days=1)
    YESTERDAY
    →　datetime.datetime(2019, 7, 18, 15, 55, 42, 566682)

    # 30分後の計算
    TODAY + datetime.timedelta(minutes=30)
    →　datetime.datetime(2019, 7, 19, 16, 25, 42, 566682)
    # timedeltaの使える引数
    [days, seconds, microseconds, milliseconds, minutes, hours, weeks]


## 比較	
### 比較記号
### 　>　>=　<　<=　==

    TODAY > YESTERDAY
    →　True
    TODAY < YESTERDAY
    →　False

### aware VS naive

 - **aware**
 
	datetimeオブジェクトがTimeZone情報を**持つ**オブジェクト
 - **naive**
 
	datetimeオブジェクトがTimeZone情報を**持たない**オブジェクト

**→ aware同士、naive同士しか比較できない**
	
**以下はエラーとなる**

    AWARE_TIME = datetime.datetime.now().astimezone(timezone('Asia/Tokyo'))
    AWARE_TIME
    →　datetime.datetime(2019, 7, 19, 17, 57, 36, 45409, tzinfo=<DstTzInfo 'Asia/Tokyo' JST+9:00:00 STD>)

    NAIVE_TIME = datetime.datetime.now()
    NAIVE_TIME
    →　datetime.datetime(2019, 7, 19, 17, 57, 58, 622168)

    # 比較
    AWARE_TIME > NAIVE_TIME
    ----------------------------------------------------------------
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: can't compare offset-naive and offset-aware datetimes

**解決法**

    #1 naiveに統一
    AWARE_TIME.replace(tzinfo=None) > NAIVE_TIME
    →　False    #エラーがなく、ちゃんと比較結果が表示されている
    #2 awareに統一
    AWARE_TIME > NAIVE_TIME.astimezone(timezone('Asia/Tokyo'))
    →　False    #エラーがなく、ちゃんと比較結果が表示されている
Mac+VSCodeでのFlutter開発環境設定(PATH)

Mac+VScodeでFlutter開発環境作成時にPATH設定でハマったのでメモ。

開発環境設定自体は公式サイトに従い、`flutter docter`で表示されるメッセージに従っていけば特に難しいことはありません。
[Flutter公式サイト](https://flutter.dev/docs/get-started/install/macos)

今回、PATHの設定を.zshrcに記述しました。
ターミナルから確認するとちゃんとPATHが通っているのでOKかと思いましたが、結果は新規プロジェクト作成時に下記のようなエラーが表示され、プロジェクトの作成ができませんでした。

`Could not find a flutter SDK. Please ensure flutter is installed and in your PATH(you may need restart).`

.bash_profileを作成してPATHを記述したところ、無事新規プロジェクトが作成できました。
公営競技を題材にGCPを勉強する

直接的にお金が絡まないと中々やる気が出ないため、公営競技を題材にしてGCPをざっくり勉強する。
なるべくサーバレスな感じで、なるべく開発もWebベースで。
GCPの色々なサービスを使ってみることを目的にしてるので、無駄の多い構成になってしまっているかも。。

#やったこと（ざっくり）
- GKE上のAirflowでバッチ処理作成
    - GKE関連のファイル類はSourceRepositoriesで管理し、PushしたらCloudBuildでデプロイ
- Functionsでとある公営競技の過去レースのデータをダウンロードしGCSに格納する
- GCSからBigQueryに格納
- BigQueryに格納したデータを元にAI Platformでモデル作成
- Functionsでスクレイピングしたデータと上記モデルからオンライン予測し、結果をFireStoreに投入
- Functionsで予測した結果を購入

#開発環境
多分これだけしか使ってない
マシン：Chromebook（ASUS Chromebook Flip C101PA）
ツール：GCP、Cloud Shell、Google Colaboratory

#最初に構築した構成イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209773/249c2f3e-ff89-6af8-9754-ad3684a440c2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209773/62ada760-8fe0-27a0-5d59-68dec7756e52.png)


##①バッチ処理基盤
このあたりは一番しんどかったので、以下記事にて少し整理
https://qiita.com/yakamazu/items/0dbf643c5e8e0b65e520
https://qiita.com/yakamazu/items/aff066b0ae811dd61f02

##②バッチ処理
###PubSub
バッチ日付をパブリッシュする

###Cloud Functions
バッチ日付のパブリッシュをトリガーに、該当日付の結果ファイルをダウンロード、解凍、整形
ファイルをダウンロードするときは/tmpディレクトリにダウンロードするのが注意点
https://cloud.google.com/functions/docs/concepts/exec

###Stackdriver Monitoring
CloudFunctionsのエラーをFunction名を指定してアラート出すことができる
[参考URL](https://www.topgate.co.jp/gcp19-stackdriver-monitoring-notify-mail-slack)

###Cloud Storage
ダウンロードファイルと整形後のファイルをひたすら蓄積

###BigQuery
GCSのファイルをロードし、サマリテーブルの作成

##③予測モデル作成とWebスクレイピング
###AI Platform
XGBoostがAI Platformで使えるようだったので、cloudshellからモデル作成ジョブをキック
モデルはGCSに保存する
その後オンライン予測用にモデルをデプロイする
やり方は[公式ドキュメント](https://cloud.google.com/ml-engine/docs/scikit/getting-started-training?hl=ja)見たら何とかなった

ちなみに機械学習素人の個人的感覚だと、XGBoostはパラメータチューニングなしでもそれなりの精度になってる雰囲気がある。

少しハマったのは、BigQueryからPandasにデータ投入するときに、
google-cloudパッケージを使用すると「'QueryJob' object has no attribute 'to_dataframe'」が発生
　⇒setup.py 作ってpandas-gbqインストール、使用する方法で解決
　　[参考](https://cloud.google.com/ml-engine/docs/tensorflow/packaging-trainer?hl=ja#adding_standard_pypi_dependencies)


###Cloud Scheduler
cronのサービス
決まった時間にPubSubメッセージのパブリッシュができる（HTTPリクエストも送れる）

###Cloud Functions(Python)
当日の情報をスクレイピング（Beautiful Soup）で取得
取得した情報を元にAI Platformのオンライン予測を使って順位を予測
一定の期待値を超えてたらPubSubに購入情報をパブリッシュ

###Cloud Functions(Node.js)
購入情報のパブリッシュをトリガーに起動
Puppeteerというライブラリを使用してヘッドレスブラウザ操作で対象を購入する

###Firestore
当日のスクレイピングした情報や、購入情報を格納する
NoSQL（ドキュメント指向データベース）と呼ばれるもので、RDBと違って格納するデータのレイアウトが途中で変わったりしても問題なし
BigQueryへのImportもすんなりできる

##この構成はお金がかかる。。
個人でやる際に、この構成で大きくお金がかかる部分は主に以下

 - GKE
    - Airflow動かそうと思ったらそれなりスペックのインスタンスを立ち上げる必要あり
    - プリエンプティブにしても月2000円くらいはかかってしまった
 - AI Platformのオンライン予測
    - 一日に150回くらいオンライン予測すると、一日50円くらいかかる

#なるべくお金がかからない感じで再構築したイメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209773/b521b9a3-d70b-9a89-8632-13a4f1b8031a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209773/c8288b5a-4829-48cd-79e3-a8df749d0f5e.png)

##①バッチ処理基盤
GKEでのAirflowをやめて、Cloud Scheduler⇒Cloud Functionsでまとめて実行に切替
個人でやる規模ならこれで十分な気がする
GKEをやめることでさらにサーバレスな感じになった
この部分の料金は今のところかかってない

##②オンライン予測
AI Platformのオンライン予測機能を使わずに、
GCSからモデルをダウンロードして、それをImportして予測を実施
個人でやる規模ならこれで十分な気がする
この部分の料金は今のところかかってない

#感想
ChromebookとGoogleのサービスだけで結構色んなことできそう。
ネストしすぎの()を何とかしたい

@Yametaro さんのエントリでこんなのを見た。

【あるある】こんなコードは嫌だ【JavaScript】
https://qiita.com/Yametaro/items/6a7ab15e5b1764bdd383

その中の｢その4: 関数ネストし過ぎ｣が何とかならないかと思って考えてみた。

```javascript
const [val0, val1, val2] = ["a", "b", "c"];
let name="xxx";

const f0 = (val)=>val+val0;
const f1 = (val)=>val+val1;
const f2 = (val)=>val+val2;
```
これについて｢f0で処理した結果をf1で処理した結果をf2で処理した結果をコンソール出力｣というのを考えると普通こんな風になる。


```javascript
// ordinary
console.log(f2(f1(f0(name))));
```
うん、見にくい。

そこで知恵を絞ってこんな風にしてみた。

```javascript
// using custom object
const applier = (val)=>{
  const  o={
    value : val,
    apply : (unary)=>{ o.value=unary(o.value); return o; }
  };
  return o;
};
console.log(applier(name).apply(f0).apply(f1).apply(f2).value);
```
もうちょい短くしてみる。

```javascript
// using custom object 2
const applier2 = (val, o={
  value : val,
  apply : (unary)=>{ o.value=unary(o.value); return o; }
})=> o;

console.log(applier2(name).apply(f0).apply(f1).apply(f2).value);
```
と、ここまで考えたところで｢配列に突っ込んであれこれすりゃいいんじゃね？｣と気づいた。

```javascript
// using array
console.log(
  [name].map(item=>f0(item))
        .map(item=>f1(item))
        .map(item=>f2(item))
        .reduce(accumulator=>accumulator)
);
```
どっとはらい。
Pythonで凸包走査実装（2D版）

# Pythonで凸包走査実装

![convexhull2d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400162/ea4ced1b-06b4-36ab-05a9-dd7f9080e2c4.png)

## はじめに
今回は2Dの凸包走査を実装です。
凸包走査とは与えられた点群のうち一番外側の点を取り出すアルゴリズム。。。です（という認識です）
取り出された点を結ぶと鈍角ができない多角形（凸多角形）になります。
この性質がDepthセンサーで取得したポイントクラウド処理や建築設計において使えそうだなと思い実装してみました。
その忘備録として。

## グラハム走査(Graham scan)
今回使用した凸包走査アルゴリズムは実装が簡単だとされる**グラハム走査**というものを使用しています。
ちなみに、よく目にするもので以下のような凸包走査アルゴリズムがあります。

・Gift Wrapping
・Graham scan
・Quickhull
・Divide and conquer

などなど。[参考](https://en.wikipedia.org/wiki/Convex_hull_algorithms)

結構奥が深そうなアルゴリズムですが、いつもながら難しいこと抜きに実装していきます。笑

## アルゴリズムの流れ
1. x座標が最小の点pを求める。
2. p周りの点を反時計周りで角度順に並べる。
3. 凸部の頂点を削除。

がざっくりとした流れになります。
この中でテクニックが必要なのが3の凸部頂点削除です。
ここでは**符号付き面積**を求めることによって、凸部となる頂点を判断します。

符号付き面積に関しては別の機会に図示しながらまとめようと思います。

簡単に説明しますと、3点の座標値を使用して三角形の面積を計算します。
この際に絶対値を考慮しない面積がマイナスになる場合が存在してしまいます。その**面積のプラス、マイナスを見ることによって、3点の並びを知ることができる**というモノです。


## 実装
ここでは座標点をp = [x, y, z]のようなリスト構造を使用し表しています。
p_listは座標点を格納するリストです。

convex_hull関数を実行すれば、凸包を構成する座標値が返されます。
その点と点を順番につないでいけば凸包図形を描画することが可能です。

詳細は省きますが僕自身はRhinocerosという3DCADを使用して描画しました。

```python:Convexhull.py
# coding: utf-8


def signed_area(p1, p2, p3):
    '''符号付き面積を計算 '''
    
    area = (((p2[0] - p1[0]) * (p3[1] - p1[1])) - ((p3[0] - p1[0]) * (p2[1] - p1[1]))) / 2
    return area


def convex_hull(p_list):
    '''グラハムの凸包走査 '''

    p_sort = []
    for i in p_list:
        p_sort.append(i[0])

    # x座標が最小のものをリストの先頭に配置。
    min_index = p_sort.index(min(p_sort))
    min_p = p_list.pop(min_index)
    p_list.insert(0, min_p)

    # 座標最小の点と他の点との角度順にソート ソートアルゴリズムに選択の余地が有る。
    p_length = len(p_list)
    count = 0
    index = 0
    while True:
        count += 1
        index += 1

        area_sign = signed_area(p_list[0], p_list[index], p_list[index + 1])

        # 符号付き面積が負ならば点を入れ替え
        if area_sign < 0:
            p_list[index], p_list[index + 1] = p_list[index + 1], p_list[index]
            count = 0

        if count == p_length - 1:
            break

        if index == p_length - 2:
            index = 0

    # 凹部の点を削除する。
    index = -1
    count = 0
    while True:
        index += 1
        count += 1

        area_sign = signed_area(p_list[index], p_list[index + 1], p_list[index + 2])
        if area_sign < 0:
            del p_list[index + 1]
            count = 0

        if count == len(p_list):
            break

        if index >= len(p_list) - 3:
            index = -1
    return p_list



```


## おわりに
最後までお読みいただきありがとうございました。
次の機会にQuickhullで実装した3D対応の凸包走査を記事にまとめようと考えていますのでよろしくお願いいたします。
ディレクトリ名を指定してクローンする方法

- 環境
    - Windows10
    - git version 2.18.0.windows.1

参考 : [git cloneしてきたプロジェクトの名前を変えてクローンしてくる方法 - Qiita](https://qiita.com/ko_coon/items/f7a555a1f57fa49e0ff9)

# ディレクトリ名を指定しないとリポジトリ名になる
```bash
$ cd {クローンしたい場所}
$ git clone https://github.com/user/{リポジトリ名}.git
$ ls
{リポジトリ名}
```

# ディレクトリ名を指定すると指定したディレクトリ名になる
```bash
$ cd {クローンしたい場所}
$ git clone https://github.com/user/{リポジトリ名}.git {ディレクトリ名}
$ ls
{ディレクトリ名}
```
VS Code Windowsでのショートカットキー (自分メモ 随時追加)

##Windowsでのショートカットキー
・リンク先に飛ぶ → Ctrl + Click
・サイドバーを閉じる → Ctrl + B
####コメント切り替え
・コメントにする → Ctrl + /
####コマンドパレットの起動
・コマンドパレットを開く → Ctrl + Shift + P
####行の移動/複製/挿入
・行の移動 → Alt + 上下矢印
・行の複製 → Shift + Alt + 上下矢印
・次の行を挿入 → Ctrl + Enter
・前の行を挿入 → Shift + Ctrl + Enter
####マルチカーソルの設定
・クリックした箇所にカーソルを増やす → Alt + Click
####同じ単語の選択
・同じ単語を選択する → Ctrl + D
・同じ単語をいっきに選択する → Ctrl + Shift + L
####真上/真下にカーソルを追加
・カーソルを垂直方向に増やす → Ctrl + Alt + 上下矢印
####ファイル/フォルダ内検索、置換
・ファイル内での検索 → Ctrl + F
・次の検索結果に移動 → F3
・前の検索結果に移動 → Shift + F3
・ファイル内での置換 → Ctrl + H
LINE WORKS Bot でカルーセル / 画像カルーセルを使う

LINE WORKS のトーク Bot API がアップデートされ、カルーセルなどが利用できるようになりました。

早速、カルーセル / 画像カルーセルを使ったメッセージ送信を試してみます。

TITLE: メッセージ送信
URL: https://developers.worksmobile.com/jp/document/1005008?lang=ja

TITLE: メッセージ送信(Carousel)
URL: https://developers.worksmobile.com/jp/document/100500808?lang=ja

TITLE: メッセージ送信(Image Carousel)
URL: https://developers.worksmobile.com/jp/document/100500809?lang=ja

## カルーセル

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/c9274613-3b30-c6dd-711f-c70689cf9afb.png)

```
import json, requests
url = 'https://apis.worksmobile.com/r/<API ID>/message/v1/bot/<Bot No.>/message/push'
headers = {
    'Content-Type': 'application/json; charset=UTF-8',
    'consumerKey': '<Server API Consumer Key>',
    'Authorization': 'Bearer <Token>'
}
payload = {

  "accountId": "user@example",
  "content": {
    "type": "carousel",
    "columns": [{
      "thumbnailImageUrl": "https://example.com/image1.png",
      "title": "タイトル",
      "text": "サンプル テキスト",
      "actions": [
      {
        "type":"uri",
        "label":"アクション 1",
        "uri":"https://example.com"
      },
      {
        "type":"uri",
        "label":"アクション 2",
        "uri":"https://example.net"
      },
      {
        "type":"uri",
        "label":"アクション 3",
        "uri":"https://example.org"
      }
     ]
    }, {
      "thumbnailImageUrl": "http://example.com/image2.png",
      "title": "タイトル",
      "text": "サンプル テキスト",
      "actions": [
      {
        "type":"uri",
        "label":"アクション 1",
        "uri":"https://example.com"
      },
      {
        "type":"uri",
        "label":"アクション 2",
        "uri":"https://example.net"
      },
      {
        "type":"uri",
        "label":"アクション 3",
        "uri":"https://example.org"
      }
      ]
    }]
  }
}

r = requests.post(url, data=json.dumps(payload), headers=headers)
```
## 画像カルーセル

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/7889e75c-24e8-dc13-0099-55dc87e7e38a.png)

```
import json, requests
url = 'https://apis.worksmobile.com/r/<API ID>/message/v1/bot/<Bot No.>/message/push'
headers = {
    'Content-Type': 'application/json; charset=UTF-8',
    'consumerKey': '<Server API Consumer Key>',
    'Authorization': 'Bearer <Token>'
}
payload = {

  "accountId": "user@example",
  "content": {
      "type":"image_carousel",
      "columns":[  
         {  
            "imageUrl":"https://example.com/image1.png",
            "action":{  
               "type":"uri",
               "label":"ラベル サンプル",
               "uri":"https://example.com"
            }
         },
         {  
            "imageUrl":"https://example/image2.png",
            "action":{  
               "type":"uri",
               "label":"ラベル サンプル",
               "uri":"https://example.net"
            }
          }

      ]
   }
}

r = requests.post(url, data=json.dumps(payload), headers=headers)

```

活用してください !
npmパッケージに起因する脆弱性の指摘を雑に解消する


GitHubに置いているコード内で使用しているnpmパッケージの脆弱性が指摘されたので、解消してみます。

## 脆弱性の診断
脆弱性の詳細を確認します。
GitHubでは、ハイレベルの脆弱性のみが指摘されるようなのですが、auditではローレベルのものも確認できます。

```
$ npm audit
```

## パッケージのアップデートがある場合

脆弱性が指摘されているパッケージにアップデートが無いか確認します。

```
$ npm outdated
```

アップデートが出ている場合はアップデートします。

```
$ npm update (package name)
```

脆弱性が解消されたか確認します。

```
$ npm audit
```

## パッケージが使用しているパッケージに脆弱性がある場合

まず自動修正で直せるものを直します。

```
$ npm audit fix
```

自動修正できなかった、脆弱性がある「パッケージ名」と、「どのバージョンまで上げればいいか」を確認します。

```
$ npm audit
```
古いパッケージのバージョンナンバーを確認します。

```
$ npm ls (package name)
```

### package-lock.jsonの修正
package-lock.json内の記述検索してバージョンを修正して、保存します。
パッケージ名前で検索すると、問題ないバージョンの箇所もヒットしてしまうので、古いバージョンナンバーで検索してパッケージ名を確認すると楽でした。

### 「^」「~」の意味
バージョンナンバーの頭についている「^」「~」は、許容するアップデートの指定です。
出典：https://docs.npmjs.com/misc/semver
>^1.2.3 := >=1.2.3 <2.0.0
>^0.2.3 := >=0.2.3 <0.3.0
>^0.0.3 := >=0.0.3 <0.0.4

>~1.2.3 := >=1.2.3 <1.(2+1).0 := >=1.2.3 <1.3.0
>~1.2 := >=1.2.0 <1.(2+1).0 := >=1.2.0 <1.3.0 (Same as 1.2.x)
>~1 := >=1.0.0 <(1+1).0.0 := >=1.0.0 <2.0.0 (Same as 1.x)
>~0.2.3 := >=0.2.3 <0.(2+1).0 := >=0.2.3 <0.3.0
>~0.2 := >=0.2.0 <0.(2+1).0 := >=0.2.0 <0.3.0 (Same as 0.2.x)
>~0 := >=0.0.0 <(0+1).0.0 := >=0.0.0 <1.0.0 (Same as 0.x)
>~1.2.3-beta.2 := >=1.2.3-beta.2 <1.3.0 Note that prereleases in the 1.2.3

### パッケージの再インストール

package-lock.jsonの記述は修正しましたが、実際には旧バージョンのパッケージがインストールされたままなので、一度node_modulesをフォルダごと消し、再インストールします。

```
$ npm ci
```

## 確認
### 脆弱性が検出されなくなったかの確認

```
$ npm audit
```

### 動作確認
パッケージのバージョンアップに伴うコードの変更点などは確認せずに修正しているので、不具合がでるようになった可能性があるので動作確認をします。

### GitHubでの脆弱性の指摘が解消されるかの確認
最後に、GitHubにPushして脆弱性の指摘を解消される事を確認します。
Swiftライブラリ優良記事まとめ

# 全般
**・[[Swift] iOSアプリ開発で便利だったライブラリ一覧 | WatchContents](https://watchcontents.com/iosapp-useful-libraries/#SwiftyUserDefaults)**
**・[2018年これだけは知っておきたいiOSライブラリ31選 - Qiita](https://qiita.com/kohei1218/items/275fcee7406395919885#parchment)**
**・[有名ライブラリに学ぶSwift実践テクニック - Qiita](https://qiita.com/yosan/items/1a675434749cbdebbf77)**
**・[【Swift】少しの手間で出来る！iOS アプリの UX改善 Tips 教えます – PSYENCE:MEDIA](https://tech.recruit-mp.co.jp/mobile/ios-ux-tips/)**
**・[Swiftの有名画像キャッシュライブラリを比較してみた - Qiita](https://qiita.com/H_Crane/items/422811dfc18ae919f8a4)**

# SwiftyUserDefaults
**・[UserDefaultsを型安全に使用する方法（#functionを使用する方法とSwiftyUserDefaultsの紹介） - Qiita](https://qiita.com/yuukiw00w/items/a31b9ae67cf7c3f07cb0)**

# LNPopupController
**・[iOS標準のmusicアプリのようなプレイヤーを出せるLNPopupControllerの紹介 - Qiita](https://qiita.com/color_box/items/de2c197c175d6b169392)**
→日本語記事少なすぎて親切なやつこれぐらいだった

# Alamofire
**・[SwiftでiOSアプリ開発入門 通信の仕組みとAlamofireの使い方を学ぶ - WPJ](https://www.webprofessional.jp/a-crash-course-on-networking-in-ios/)**
**・[ios – Alamofire 4とSwift 3でプロキシサーバーを使う方法 - コードログ](https://codeday.me/jp/qa/20190304/307960.html)**

※随時追記
affinity designerで対称なベクターを作成する

## 何
- affinity designerで左右対称の絵を作る際に、ラスターではブラシツールのオプションで可能だが、ベクターでは見当たらなかったので方法を調査した。
- 結論としては、ラスターのような、簡単な機能としては提供されていないため、シンボル機能を工夫して行っているらしい
- 動作確認はwindows版 ver1.7で行った

## 方法
![対称2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151200/278ac6c7-fa4b-e2e8-24bb-0f4c7dc7ffa5.gif)


- この動画を見た通りなのだが（ありがとうございます）　https://www.youtube.com/watch?v=lBMVUh5bU40
- １．中心を決める
- ２．左側に四角を作りシンボル化する
- ３．シンボルを複製して中心を挟んで右側に対称に置く
- ４．右側の四角を左右反転する
- ５．これで準備完了。四角は非表示にする
- ６．動画では、左右対称以上の円形の要素への複製なども行っている

## シンボルについて
- マニュアルに、非同期化やシンボルの解除についての記載がある。これを用いて、途中まで左右対称で作ってから非対称にすることが可能。

https://affinity.help/designer/ja.lproj/index.html?page=pages/SymbolsAssets/symbols.html?title=%E3%82%B7%E3%83%B3%E3%83%9C%E3%83%AB

## その他
- 原因はわからないが、作業中にシンボルへの新規パスの追加ができなくなることがあった。その場合はシンボルのグループ化解除→グループ化をして仕切り直しをする必要があった。

## 作例
![ahiru.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151200/7b46c0b4-6ede-f269-c25c-bca739064a14.png)
LeetCode / Maximum Subarray

（[ブログ記事](https://mhiro216.hatenablog.com/entry/2019/07/18/233658)からの転載）

[https://leetcode.com/problems/search-insert-position/]

Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.

Example:
Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.

Follow up:
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.

integerのlistの中で、和が最も大きくなる部分的なlist(subarray)の和を求める問題です。
所謂Dynamic Programming（動的計画法）の分野では有名な例題のようですね。
計算量$O(n)$の方法が見つかったら、次は divide and conquer approach（日本語では分割統治法）を試してみろ、と言われていますが、現時点で何のことやら、、、という感じなので、プレーンな方法のみ示します。

#### 解答・解説

##### 解法1
listに対してloopを回して探索していきますが、入力numsに対して、subarrayの和を一時的に格納しておく変数curSumと、探索した中で最大のsubarrayの和を格納しておく変数maxSumを用意します。
curSumの計算方法が若干分かりにくいですが、初期値はcurSum = nums[0]とし、ループの中で curSum = max(num, curSum + num) とすることで、listの次の要素を足した値と、次の要素単体の値を比べ、大きい方の値でcurSumを更新します。
例えばnums = [-1,2,-1,4]であれば、(curSum, maxSum)は、(-1,-1), (2, 2), (2-1, 2), (2-1+4, 5)と変わっていきます。

```python
class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        if not nums:
            return 0

        curSum = maxSum = nums[0]
        for num in nums[1:]:
            curSum = max(num, curSum + num)
            maxSum = max(maxSum, curSum)

        return maxSum
```

##### 解法2（のreference）
divide and conquer approachですが、以下サイトが参考になりそう。
Pythonのソースコードも載っていますが、説明もなく丸写しもなんなので、ひとまずリンクを示すに留めます。

[https://www.geeksforgeeks.org/maximum-subarray-sum-using-divide-and-conquer-algorithm/]
node.js+selenium環境でjqueryを使ってスクレイピングする方法

# node.js+selenium環境でjqueryを使ってスクレイピングする方法
node.js+selenium環境でjqueryを使ってスクレイピングしたい！！そんなときはこんな風にするとうまくいきました。

1. selenium側でjqueryを使ってスクレピング
2. スクレイピングした結果のデータを配列にしてJSON形式にしてサーバに渡す。
3. サーバ側でJSONパースしてオブジェクトにする。
4. サーバー側で受け取ったJSONデータを`data.json`というファイルに保存する

```javascript
  var webdriver = require('selenium-webdriver');

  var driver = new webdriver.Builder()
    .forBrowser('chrome')
    .build();

  driver.get('http://hogehoge.com/');
  driver.executeScript("return JSON.stringify($('.entry-title').map(function(){return $(this).text().trim();}).get());").then(function (return_value) {
    let json = JSON.parse(return_value);
    for (var key in json) {
      let val = json[key];
      fs.writeFile(path.join(__dirname, "data.json"), JSON.stringify(json), function (err) {
        if (err) {
          return console.log(err);
        }
      });
    }
```
※URL「 http://hogehoge.com/ 」と、jQueryのセレクタ「 .entry-title 」部分をお好きに書き換えてください。

これでjQueryのセレクタにマッチしたデータをJSONファイルに保存することができます:smile:
seleniumのお作法を学ぶより使い慣れたjQueryを使いたい！！という人には有用な方法と思います。

エンジニアに役立つ情報をTwitterでも発信していますので宜しければTwitterの方もフォローをよろしくお願いします！
[Twitterへのリンクはコチラ](https://twitter.com/mr_t_free)
Visual Studio Code の主要ショートカットキー (mac)

**【２０１９年７月２４日更新】
申し訳ありません！一箇所盛大に間違えていました…。
「＾」　は　「control」キー　であることを知りました…。**


Visual Studio Code と仲良くなりたい！！
ということで、ショートカットを自分なりにまとめてみました。

参考にした記事はこちら→[【Mac版】 VisualStudioCode キーボードショートカット](https://qiita.com/naru0504/items/99495c4482cd158ddca8)

同じくVSCodeに苦戦してるみなさま、よければ参考にしてください。


![VScode-new.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464749/ca090ccb-895e-2be4-362f-073cce3129d6.jpeg)


「ここ違うよ！」とか「このショートカットも便利だよ」などあったらツイッターへ[DM](http://twitter.com/lala_design37)をお願いします。
わかりにくかったバグとの戦いの記録

# 現象

まあまずはソースコード。

```c++:c++17
// clang++ -std=c++17 -O3 -Wall -lpthread && ./a.out 10000

#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>

using namespace std;
using namespace std::chrono_literals;

class foo {
  thread th_;
  mutex mutex_;
  condition_variable cv_;

public:
  void notify() { cv_.notify_all(); }
  foo()
      : th_([this]() {
          unique_lock<mutex> lock(mutex_);
          if (cv_status::no_timeout == cv_.wait_for(lock, 100us)) {
            cout << "received\n";
            return;
          }
          cout << "time out\n";
        }) {}
  ~foo() { stop(); }
  void stop() {
    if (th_.joinable()) {
      th_.join();
    }
  }
};

int main(int argc, char const *argv[]) {
  for (int i = 0; i < (argc<2 ? 10 : atoi(argv[1])); ++i) {
    std::cout << i << " ";
    foo f;
    this_thread::yield();
    f.notify();
    this_thread::sleep_for(200us);
  }
}
```

こうして肝のところを切り出すとわかりやすいような気もするけど、気にせずストーリーを説明すると。
やりたいことは：

> foo というクラスのインスタンスがスレッドを持っている。
> スレッドはコンストラクタでスタートする。
> メインスレッドから `notify` されると、なんか処理をして終了する。
> 時間までに `notify` が来なかったらタイムアウトして終了する。

というもの。

それらしいテストも書いて、テストはバッチリOK。
と思ったら、千回か1万回に1回ぐらい、死ぬ。上記のコードで `argv[1]` を 1万にするとだいたい途中で死ぬ。

死に方は例えばこんな

```
4155 time out
4156 time out
4157 time out
4158 time out
libc++abi.dylib: terminating with uncaught exception of type std::__1::system_error: mutex lock failed: Invalid argument
4159 Abort trap: 6
```

感じ。
ちなみに手元ではなぜか g++-9 だと死なない。
コンパイラによって死んだり死ななかったりするので、コンパイラのバグを疑ったりもした。

# 原因

よく訓練された C++ ユーザーなら一目見てわかるかもしれないが、原因は、メンバの順序であった。

```c++:c++17
  thread th_;
  mutex mutex_;
  condition_variable cv_;
```

という順序になっているので、まず、`th_`  のコンストラクタが呼ばれる。
コンストラクタでスレッドが始まる。
スレッドが始まったところで `th_` のコンストラクタは完了なので、次に `mutex_`, `cv_` を構築する。
構築しつつ、 `th_` のスレッドは走る。
すると、 `th_` のスレッドで `unique_lock<mutex> lock(mutex_);` や `cv_.wait_for(lock, 100us)` と出会う。
出会った時点で `cv_` や `mutex_` の構築が終わっている場合が多いんだけど、稀に、`th_` のスレッドのほうが早いことがある。
そうすると、 `lock` や `wait_for` はコンストラクタによる初期化が終わっていない `cv_` や `mutex_` を参照することになり、死ぬ。

というわけだと思う。

# 対策

順序が悪いのが原因なので、順序を正しくすれば良い。
`th_` のスレッドが走り始める時点で他のメンバの初期化が終わっていれば良いので、例えば

```c++:c++17
  mutex mutex_;
  condition_variable cv_;
  thread th_;
```

という順序にしておけば問題は発生しない。

# 教訓

メンバ変数のコンストラクタが呼ばれる順序に気をつけよう。
【備忘録】HTMLでプルダウン連動させて且つテキストエリア表示したものをコピーする

# テストコードを作成したので備忘録としてあげておく。
※ただの備忘録なのでインデントは考慮していないので適宜フォーマッターなどを使用して修正してください。

```html
<html>

<head>
    <meta charset="utf-8">
    <script type="text/javascript">
        msgtxt = new Array();
        for (i = 0; i < 4; i++) {
            msgtxt[i] = new Array();
        }

        msgtxt[1][1] = "a-1が選択されているときのメッセージ";
        msgtxt[1][2] = "a-2が選択されているときのメッセージ";
        msgtxt[1][3] = "a-3が選択されているときのメッセージ";
        msgtxt[2][1] = "b-1が選択されているときのメッセージ";
        msgtxt[2][2] = "b-2が選択されているときのメッセージ";
        msgtxt[2][3] = "b-3が選択されているときのメッセージ";
        msgtxt[3][1] = "c-1が選択されているときのメッセージ";
        msgtxt[3][2] = "c-2が選択されているときのメッセージ";
        msgtxt[3][3] = "c-3が選択されているときのメッセージ";


        function selchg() {
            sltd = document.f1.s1.selectedIndex;
            if (sltd == "1") {
                document.f1.s2.options[1].text = "a-1";
                document.f1.s2.options[2].text = "a-2";
                document.f1.s2.options[3].text = "a-3";
            } else if (sltd == "2") {
                document.f1.s2.options[1].text = "b-1";
                document.f1.s2.options[2].text = "b-2";
                document.f1.s2.options[3].text = "b-3";
            } else if (sltd == "3") {
                document.f1.s2.options[1].text = "c-1";
                document.f1.s2.options[2].text = "c-2";
                document.f1.s2.options[3].text = "c-3";
            }
        }

        function txtchg() {
            x = document.f1.s1.selectedIndex;
            y = document.f1.s2.selectedIndex;
            document.f1.t1.value = msgtxt[x][y];
        }

        function setCB() {
            txt = document.f1.t1.value;
            window.clipboardData.setData("text", txt);
        }
    </script>
</head>

<body>
    グループ①
    <form name="f1">
        <select name="s1" onChange="selchg()">
<option>-
<option>a
<option>b
<option>c
</select>
        <br>
        <br>
 　　　　グループ②
        <br>
        <select name="s2" onChange="txtchg()">
<option>-
<option>a-1
<option>a-2
<option>a-3
</select>
        <br>
        <br> 
　　　　テキストエリア
        <br>
        <TEXTAREA name="t1" rows="4" cols="40"></TEXTAREA>
        <br>
        <input type="button" value="コピー" onclick="setCB()">
    </form>

</body>

</html>
```
[Microsoft] SQLから始めるSQL Serverデータベース

# これはなに？

GUIではなくSQLでSQL Serverを使い始めた時の個人的なメモです。


# 前書き

Windowsであれば、SQL Server Management Studio(SSMS)という便利なGUIがあります。
LinuxやmacOS用には、[Azure Data Studio](https://docs.microsoft.com/ja-jp/sql/azure-data-studio/download)というGUIがあります。
Azure Data Studioはまだ発展途上なので、SSMSほど機能がありません。代わりにSQLを使う必要があります。

# SQL Server の始め方

## データベース作成

```sql
CREATE DATABASE データベース名 COLLATE 比較条件
go
```

## ユーザー作成

### ログイン情報作成

まずSQL Serverへ接続するための情報を作成します。

```sql
CREATE LOGIN ログインID
WITH
  PASSWORD = 'パスワード',
  DEFAULT_DATABASE = データベース名,
  CHECK_EXPIRATION = OFF, -- 有効期限チェックしない
  CHECK_POLICY = OFF -- パスワードの複雑性要件をチェックしない
go
```

### データベースユーザー作成

データベースにログイン情報と一致するユーザーを作成します。

```sql
use 「データベース]
go
CREATE USER ログインID
go
```

### ロール割り当て

ロールを割り当てます。

```sql
use [データベース]
go
EXEC sp_addrolemember 'db_owner', 'ログインID'
go
```

## パスワード変更

```sql
ALTER LOGIN ログインID
WITH
  PASSWORD = '新パスワード'
GO
```
Cognitoユーザプール認証時のJWTトークンをjwt.toで検証してみる

## 概要

Cognito ユーザプール認証時のJWTトークンをjwt.toで検証する。

公開されているJWKから公開鍵を作ってそれで検証したいので、そういう感じでやる。
※jwt.toへJWTトークンをペーストした時点で、公開鍵が入るかもしれないけど、それはそれとして自分で公開鍵を取得する

実戦で jwt.to を使って検証することは現実的でないので、jwt.toの中で紹介されているライブラリを使用すること。

## 実践

### Cognitoの認証～JWTトークン取得まで

1. [この記事](https://qiita.com/k_hoso/items/afe9aa8183b8bf0651a1) を参照にしてとりあえずユーザプールで認証してJWTトークンを貰う。

### 公開鍵取得下準備

公開鍵へはnodeを使って変換する。
JWKを公開鍵に変換するためのライブラリを入れる。

```bash
npm install jwk-to-pem --save
```

```javascript:変換用のjavascript（後で使う）
var jwkToPem = require('jwk-to-pem')
var jwk = "/.well-known/jwks.json内のkidに対応するjwkを入れる"
pem = jwkToPem(jwk)
console.log(pem)
```

### 検証用公開鍵取得

1. https://jwt.io/ へアクセスして、Encordedの欄に JWTトークンをコピペする。
2. トークンの中の`issのURL/.well-known/jwks.json` へアクセスするとjwkを取得できる。  
※[公式のステップ２](https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html) 参照（このURLはあくまでCognitoでの決め事）
3. jwt.to のHEADER欄に出ている、`kid`と一致するJSON部分が検証用の公開鍵の元ネタになる。  
※JWTトークンの署名の検証には署名時に使用した秘密鍵の対になる公開鍵が必要
4. 下準備の "変換用のjavascript" 内の、`var jwk`に、対応するkidのJSON部分を設定する。
※↓のような感じ  

```javascript
var jwk = {
    "alg": "RS256",
    "e": "AQAB",
    "kid": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "kty": "RSA",
    "n": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyy",
    "use": "sig"
}
```

で、jsを実行すると公開鍵が表示される。

### 実際に検証する

表示された公開鍵を、https://jwt.io/ の右下の "public key or certificate ..." 部分に公開鍵をペーストする。

画面下が、`Signature Verified` になれば検証OK。
※ならない場合は、トークンのダブルクォーテーションを消してみたりすると、動くかも。。


### 参考
* [公式：Amazon Cognito JSON ウェブトークンの署名を復号して検証する方法を教えてください。](https://aws.amazon.com/jp/premiumsupport/knowledge-center/decode-verify-cognito-json-token/)
* [公式：JSON ウェブトークンの検証](https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html)
* [jwk-to-pem](https://www.npmjs.com/package/jwk-to-pem)
RubyOnRailsでWYSIWYGエディタQuillを導入する方法

# RubyOnRailsでWYSIWYGエディタQuillを導入する方法

RubyOnRailsのformとQuillを連携させるには、下記のGemを入れると良い。
[quilljs-rails](https://github.com/abhinavmathur/quilljs-rails)
インストール方法はREADME.mdの通りでOK。インストール後は、`quill_container`というclass属性を付加すれば自動的にQuillエディタとなる。

```
<%= f.text_field :title, label: 'Title', type: 'text', class: 'quill_container' %>
```

ただし、１ページ内に異なるスタイルのquillエディタを複数配置するといったことは不可能っぽい（ソースを見る限り。すべて同じスタイルになってしまう）
細かい制御をしたい場合は、railsのformを使わずにjavascript経由でCDNなどでquillをインストールしてjqueryなどでゴリゴリとデータの受け渡しの処理などを書くしかないようだ。

エンジニアに役立つ情報をTwitterでも発信していますので宜しければTwitterの方もフォローをよろしくお願いします！
[Twitterへのリンクはコチラ](https://twitter.com/mr_t_free)
MacのPCの調子が悪い時にはActivyty Monitorを見よう

## MacのPCの調子が悪い時にはActivyty Monitorを見よう
Macを使っていると、どのアプリがメモリーやバッテリーを消費しているのか知りたくなる時があります。

これをターミナルで調べることも出来ますが、MacにはActivyty Monitorというアプリが入っており、各アプリのリソース消費状況を調べることができます。

command + spaceを押してから、「Activyty Monitor」と入力することで起動することができます。

ぜひMacを使っている方はお試しください。


## 終わりに
私は現在、Web3のサービスの開発をしています。詳しくはこちらの記事をご覧下さい。
        [無料でイーサリアムが当たる、Web3時代の寄付サイトを作った話](https://note.com/kenroda/n/n814347fbdcd7)
picoCTF 2018 Ext Super Magic - Points: 250

#問題

https://2018game.picoctf.com/problems

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/616f8b6b-2245-3f43-eabb-d92bbffefaa9.png)

#解いてみた

謎のファイルシステム渡すから調べてね。的な話でしょうか。
FTK Imagerで開いてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/9454e0e7-e3e2-d98a-89b3-807076e6a26f.png)

ファイルシステムを判別できないようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/bec52d4e-c22f-79b5-c928-32485e0f2d98.png)

データも先頭あたりは0だけですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/72c39156-9503-ff87-c74d-39de0e8af521.png)

真ん中あたりを見てるとところどころにファイル名っぽいのがあるので、どうにか頑張ってマウントして画像ファイルの中身を確認するという話でしょうか。
ちなみに「pico」で検索してもヒットしませんでした。

サーバでfileコマンドを実行してみましたが、何かよくわからず。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/a38a34a3-8925-1a18-3872-7ccef047086e.png)

青い空を見上げればいつもそこに白い猫を使って解析してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/01fa2dfd-6343-cc4f-0731-aed6477644f2.png)

一番上に書いてあるGMCファイルを検索してみたんですが、どうやってみればよいのかよくわかりませんでした。

復旧天使使ってみます。個人的にかなり柔軟にやってくれるイメージ。
[データ復旧ソフトと復元サービス（NAS対応）｜復旧天使 公式](https://www.recovery-angel.jp/)

そうすると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/5ac11362-501f-b81e-a6b4-2266e710a72d.png)

という感じで画像を抽出することができました。
ローカルにコピーします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/7850d290-406f-6848-0944-207a1adb835b.png)

無料版なので小さい容量のものしかできません。
残念ながらここでは1つできなかった。

画像を見てみると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/c0829208-45f8-ba56-e82a-3887472df6ac.png)

ほぼ全部こんな感じ。
ダウンロードできなかった1ファイルを復旧天使上で見てみると

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/1e1424c0-9947-c2f4-3866-896b001e1932.png)

なんか真ん中の少し上に文字がありそうな気はするけど、読めませんよね。

ヒント見てみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/a883e164-3427-567a-fdfd-863dd5909980.png)

ん？アクセスできない。

コンペ終わりました。ということでもうアクセスできないのかと思ったら、最後に「メンテしたあとにまたアクセスできるよ」的なことが書かれていたので、待つしかないようです。

一旦この記事はここでアップしておこう。
また復旧したらこの記事を編集するか、その②みたいな感じで新規で書きます。
Python3での四捨五入、切り捨て、切り上げ。

初投稿になります。
指摘等あれば、よろしくお願いします。

#はじめに
Pythonを勉強する中で、丸め処理を行う関数が複数あり混乱したので、自分への備忘録としてまとめておきます。

#実証環境
・Python3.7.1

実行コードとその出力は次のように示します。

```python:example.py
print('出力')
#出力
```

#round関数
四捨五入に近い処理を行う関数。
基本的には四捨五入を行います。
第二引数で丸め後の桁を指定することができます。

```python:round_1.py
print(round(3.1415, 2))
#3.14

print(round(3.1415, 1))
#3.1
```
また、第二引数を指定しない場合は最も近い整数となるようです。

```python:round_2.py
print(round(1.4142))
#1

print(round(1.7320))
#2
```

##round関数の注意点
私が混乱した原因です(笑)

round関数は基本的には四捨五入を行いますが、違う挙動をする場合があります。
例えば以下の例です。

```python:round_3.py
print(round(1.5))
#2

print(round(2.5))
#2

print(round(3.5))
#4
```

2.5という数に対して、四捨五入であれば本来は3を出力しなければいけません。
しかし、ここでは2を出力しています。

この例のように、round関数は数から最も近い整数が2つ存在する場合(この場合は2と3が存在する)、結果が偶数となる方へ丸め処理を行います。

#math.floor関数
切り捨てを行う関数。
小数点以下を切り捨て、整数へと丸める処理を行うようです。

```python:floor.py
import math

print(math.floor(1.1421))
#1
print(math.floor(1.7320))
#1
print(math.floor(1.5))
#1
print(math.floor(2.5))
#2
print(math.floor(3.5))
#3
```

#math.ceil関数
切り上げを行う関数。
小数点以下を切り上げ、整数へと丸める処理を行うようです。

```python:ceil.py
import math

print(math.ceil(1.1421))
#2
print(math.ceil(1.7320))
#2
print(math.ceil(1.5))
#2
print(math.ceil(2.5))
#3
print(math.ceil(3.5))
#4
```

#あとがき
これから自分が使いそうなものをまとめてみました。

初投稿ということもあり、拙い文章になってしまいましたが、ここまで読んでいただきありがとうございます。
ご指摘等あればよろしくお願いします。
テンプレート引数は部分的に省略できる

# 前書き
テンプレート関数では明示的にテンプレート引数を指定する場合と, 関数の引数から推測できる場合があります.

非常に簡単な例ではこれ

```cpp

// A("hoge")の様にTは指定しなくてもよい
template<class T>
T A(T x) { return x; }

// B<int>() の様に明示的に指定する
template<class T>
T B(){ return T(); }

int main(){
    A(1);     // 引数から推論する
    B<int>(); // 明示的に指定
}
```

今回の本題としては以下の様にテンプレート引数が複数ある場合, 1部だけ省略することが可能かどうかで
結果だけ先に書くとデフォルト引数と同じであとに書いていれば省略可能.

```cpp

// C<5>("hoge") の様に最初のNは指定するが, Tは引数で推論可能
template<int N, class T>
T C(T x) { return x; }
​
// Tを先に書いてしまうとエラーとなる
template<class T, int N>
T D(T x) { return x; }

// Tだけ指定して, U, Sは引数で推論可能​
template<class T, class U, class S>
T E(U , S ){ return T(); }
​
// 引数の順番的にTを指定するためにはUも指定しなければならない
template< class U,class T, class S>
T F(U, S) { return T(); }
​
int main(){
    C<5>(1);   // ok
    
    D<5>(1);   // NG   Nを指定したつもりだけど実際はTを指定したと解釈される
    
    E<int>(1.0, "hoge");         // ok
    
    F<int, double>(1, "hoge");   // ok  
    F<int>(1, "hoge");           // NG  Tだけ指定したつもりだけど実際はUを指定したと解釈される
}
```

# どういうときに使うか

あまりいい例ではないですが以下の様にラムダ式と組み合わせる時に使います.

```cpp

#include <iostream>
#include <array>
using namespace std;

// intを変換するTFunc型のコンバーターと数値Nを渡すと
// 0 ~ N-1の値を変換してstd::arrayにして返す
template<int N, class TFunc>
auto Convert(TFunc&& func) -> decltype(auto)
{
    using elem_type = decltype(func(0));
    std::array<elem_type, N> ret;
    for(auto i = 0; i < N; ++i)
        ret[i] = func(i);
    
    return ret;
}


int main()
{
    // 0 ~ 4の数値を二乗した配列が返る
    // ラムダ式の型はわからないけどNだけ指定すれば後は引数から推論してくれる
    auto arr = Convert<5>( [](int i) { return i * i; }  );
    for(auto i = 0; i < 5; ++ i)
       cout << arr[i] << endl;
}
```
 

# 結論

引数から型推論したいテンプレート引数は後ろに定義する.
統計検定2級に合格しました

2019年6月16日試験
統計検定2級に合格したのでそのまとめ。

##自己紹介
情報工学科に在籍する大学3年生です。
大学1年2年と確率・統計を扱ってきたのでその理解度の到達確認を目的に受験しました。
また、将来AIとデータ分析の職種に就くとき統計の知識が役立ちそうです。

##統計検定2級とは
日本統計学会のページ
http://www.toukei-kentei.jp/
こちらによると2級は
大学基礎課程（１・２年次学部共通）で習得すべきことについて検定を行います。
(1) 現状について問題を発見し，その解決のために収集したデータをもとに、
(2) 仮説の構築と検証を行える統計力と、
(3) 新知見獲得の契機を見出すという統計的問題解決力について試験します。
とあります。

試験範囲はこちら
http://www.toukei-kentei.jp/wp-content/uploads/grade2_hani_181214.pdf
センター試験で扱うような
平均値、中央値、最頻値、分散、標準偏差、相関係数、グラフ、箱ひげ図、ヒストグラム、
等から

ベルヌーイ試行、二項分布、ポアソン分布、幾何分布、一様分布、指数分布、正規分布、
最小二乗法、標準正規分布、t分布、確率分布、推定、検定
といった大学基礎範囲まで幅広く問われます。

##勉強法
僕は試験の2か月前の4月中旬から、のんびり1日30分で週3時間ほど勉強しました。試験前の1週間は1日1時間ほど。
一度確率統計学を学んだことのある人であれば、1か月本気を出せば合格するのはそれほど難しくないと思います。


###参考書等

####改訂版 日本統計学会公式認定 統計検定2級対応 統計学基礎
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315028/11e59512-474c-acb5-28f4-e47d34f96f7e.png)
https://www.amazon.co.jp/%E6%94%B9%E8%A8%82%E7%89%88-%E6%97%A5%E6%9C%AC%E7%B5%B1%E8%A8%88%E5%AD%A6%E4%BC%9A%E5%85%AC%E5%BC%8F%E8%AA%8D%E5%AE%9A-%E7%B5%B1%E8%A8%88%E6%A4%9C%E5%AE%9A2%E7%B4%9A%E5%AF%BE%E5%BF%9C-%E7%B5%B1%E8%A8%88%E5%AD%A6%E5%9F%BA%E7%A4%8E-%E7%94%B0%E4%B8%AD%E8%B1%8A/dp/4489022271
こちらの日本統計学会の参考書は評価が高くないので敬遠しました。


代わりに以下の入門書とwebサイトと過去問集を中心に学習しました。

####統計web
![2019-07-18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315028/b5422e5f-8f97-e0ad-09ea-e09dc797f241.png)
https://bellcurve.jp/statistics/course/

こちらのサイトは非常に参考になりました。2級程度の知識を全網羅しています。
数式の説明、表、例題からていねいに解説しています。
記事で知識を学んだら、まずは演習問題で確かめるといった使い方をお勧めします。
過去問題集とこちらのサイトで、公式を確かめながら使うという方法で勉強しました。

####完全独習 統計学入門
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315028/7d153cf7-8e8c-2c90-2bc7-089b92b44aee.png)
https://www.amazon.co.jp/%E5%AE%8C%E5%85%A8%E7%8B%AC%E7%BF%92-%E7%B5%B1%E8%A8%88%E5%AD%A6%E5%85%A5%E9%96%80-%E5%B0%8F%E5%B3%B6-%E5%AF%9B%E4%B9%8B/dp/4478820090
超がつくほどの入門書でした。扱っている数式は算数程度なので、数学に触れるとにアレルギー反応を起こす人におすすめします。
数学を一切用いていない説明で、これほど簡単に説明している本は他にないと思います。
頻出のΣ記号や∫記号を、図や表で説明しているので、シンプルな理解ができます。
確率・統計の基礎的な知識を学ぶのに活躍しました。


####日本統計学会公式認定 統計検定 2級 公式問題集[2016〜2018年]
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315028/2b8137c8-5ac7-e29e-534a-7f3c27b6828c.png)
https://www.amazon.co.jp/gp/product/4788925494?ie=UTF8
2016年～2018年の全6回分の問題を収録。年度によっては試験範囲が変わったりするので、必ず最新のものを手に入れるのをお勧めします。
なにはともあれ、過去問演習が第一です。
統計検定は実際に過去問から出題される問題の割合が高いので、過去問を解きながら効率よく学習できます。
3周は解きました。

###試験当日
2019年6月16日試験
2級は午前中の試験でした。電卓持ち込み。関数電卓不可。

##感想
初歩の初歩に、正規分布の1σ区間におさまる確率は68%、2σ区間におさまる確率は95%を知った時、好奇心をくすぐられました。
t分布、カイ二乗分布まではすんなり理解できたのですが、F分布は最後まで意味が分かりませんでした。
回帰分析が出てくると、おおっ、統計やってるなという気持ちになります。

##まとめ
この世のあらゆるデータが正規分布に従うことは不思議ですね。
統計学は、ビックデータを扱うデータ分析の分野に活躍するため、イケてる学問の一つであると思います。

次の試験日は2019年11月24日です。
準一級からの壁は高そうです。試験範囲を見ましたが、専門的かつ業務的な内容ですね。
http://www.toukei-kentei.jp/wp-content/uploads/grade1semi_hani_170727.pdf
機械学習の最尤法、SVMやK-means法といったMLで使われる手法も範囲です。興味はあります。

参考にしたサイト
知識0から統計検定2級取得を目指した話
https://qiita.com/akiyoshi_sasaki/items/8e4d7895f2647e22b5f9
統計検定２級に楽に合格する方法
https://qiita.com/okoppe8/items/6caca7ab6509edf0c497
[Swift 5] XLPagerTabStripでBarのLable文字列を複数行表示する方法

iOSの標準コンポーネントには存在しない、AndroidのPagerTabStripという機能を実現するために、XLPagerTabStripという、ライブラリ（フレームワーク）を使っています。

GitHub: [XLPagerTabStrip](https://github.com/xmartlabs/XLPagerTabStrip)

今回、ページ名を表示してボタンでもあるタブ部分の文字列を2行にして表示したいと思ったのですが、改行入り文字列を指定しても改行されませんでした。

色々試したものの、最終的にたどり着いた解決方法はとても簡単なものでしたが、書き残しておきます。

## なぜ1行しか表示されないのか？

タブのラベルを指定しているコードがこちらです。
※ Button Barタイプを使用しています。

XLPagerTabStripでは、`indicatorInfo(for:)->IndicatorInfo`でタブのラベルを設定します。

```SampleViewController.swift
extension SampleViewController: IndicatorInfoProvider {
    
    func indicatorInfo(for pagerTabStripController: PagerTabStripViewController) -> IndicatorInfo {
        return IndicatorInfo(title: "1行目\n2行目")
    }
}
```

しかし、このように改行を入れても1行目までしか表示されません。

念の為以下のように指定してもダメでした。

```swift
"""
1行目
2行目
"""
```



XLPagerTabStripでも、タブ名はきっとUILabelで表現されています。



StoryboardでUILabelを配置して、Attributes InspectorのLinesを確認してみると分かりますが、

UILabelはデフォルトでは1行までしか表示されないように設定されています。

なのでこの数値を変更する必要があります。

## Cellの設定メソッドを上書きしてUILabelの行数設定を変更する

XLPagerTabStrip側で`configureCell(_:indicatorInfo)`というメソッドが使われているので、こちらをオーバーライドします。

そして、引数の`cell`が`label`を持っているので、何行まで許容するのかを指定しましょう！

labelの`numberOfLines`ですね。

```swift
// セルの再設定
override func configureCell(_ cell: ButtonBarViewCell, indicatorInfo: IndicatorInfo) {
    // ラベル設定
    cell.label.numberOfLines = 2  // 表示したい行数を指定
    cell.label.font = UIFont.systemFont(ofSize: 13)  // フォントサイズ等もここで指定可能
}
```

以上で2行までラベル文字列が表示されるようになります。

numberOfLinesに0を指定すれば行数の制限がなくなります。
（タブエリアの縦の高さが足りないと切れちゃいますが…）

以上、意外と手間取った「ラベル文字列の複数行表示対応法」でした！
今日の学習

##やったこと
・railsチュートリアル第二章を参考にしながらtask管理アプリの作成
・変数について
・ルーティングについて
##学んだこと
・アプリをターミナルでの消し方
→ ```rrm -rf アプリフォルダ```
・bundle  に exec をつけないとシステム側のgemを指定されず共通のフィールドでコマンドが実行されてしまう。

##補足
https://www.youtube.com/watch?v=vumdVlnjtQI
https://www.sejuku.net/blog/13078
Coursera Machine Learning Stanford Univ. Week4

#Week4のプログラミング課題ではまったところ

Octaveに不慣れでプログラミング課題で少し手間取ってしまいました。
とりあえず自分用のメモとして記録しておきます。

課題はmnistの手書きの数字を分別するコードを完成させること。

- 10個のRegularized logistic regressionを作る方法と
- 2つのhidden layerを持つNeural Networkでやる方法

##手間取った理由
- 課題のpdfの読み込み不足
- 課題のソースコード中にあるhintの読み込み不足
まあこれはひとえに英語力のなさによるものです。
googleさんにfmincgについて相談するとgithubに日本語訳したものをがあったので読みました。
やはり母国語で読むと見落としていた部分がすぐ見つかります。
（ちなみに私が見たものは答えそのものは暗号化？されていたのでカンニングじゃないよね？）

まあちゃんと入力データのサイズくらい確認しましょうね。

##octaveの知識不足
- pdfやソースコード中にhintにあるexampleのコードの意味を調べて時間がかかった

> %     [theta] = ...
> %         fmincg (@(t)(lrCostFunction(t, X, (y == c), lambda)), ...
> %                 initial_theta, options);

というコメント文中のfmincgの説明これだけでも3つほど知らんことが

> (@(t)(lrCostFunction(t, X, (y == c), lambda)の

   - @(t) って何
   - y==c はどうすんの
    - 少し上の行のhintに説明があります。その方法はpdfに説明があります。
   - cはどこから生えてくるの？
    - これも少し上のnoteにあります　for loop使ってもいいよって書いてあります。

- predict.m　のmaxの使い方 

> max(A, [], 2) to obtain the max for each row.

- Aの行ごとに最大の値を見つけてそのカラムの番号がpにすればいいんだけどmaxってどう使うのか知らなかったので調べるのに手間取った

- 行列計算
    - 不慣れなので右からかければいいのか、左からかければいいのか、転置はいるのとか
    - pdfにそういう時は行列のsizeを表示してみろと
    - おお先生もそうやってデバッグしていたのかとちょっと安心
    - ところでsizeってどうやって表示するの？
        - size(A)とか;なしで書くとか
        - octaveのGUI版でブレークポイントを設定してワークスペースにある変数の情報を見る
-そのほか
    - 所謂biasがΘの最初の要素なのでこれを掛けるため入力データ1をつけ加えること
    - oneVsAll.mだと下記のようにしていますこれをNeural Network版で使うpredict.mでは自分でやらないとね
    
    > % Add ones to the X data matrix
    > X = [ones(m, 1) X];

ex3_nnの結果は

> Training Set Accuracy: 97.520000

こんな感じでした
[パッチ当て]ってなんや

#「パッチを当てるとはアップデートすること」
修正プログラムのことを`パッチ`といい、修正プログラムを実行してソフトウェアの不具合を修復することを`パッチを当てる`（アップデートともいう）といいます。

https://wa3.i-3-i.info/word14131.html
https://support.biglobe.ne.jp/knowhow/knowledge/security/update.html
[Git] GitHubのPullRequestされているブランチをpecoでサッとチェックアウトする

# GitHubのPullRequestされているブランチをpecoでチェックアウトする

普段業務でGitHubを使っており、PullReqestからのレビュー、マージなどを行っています。
僕はレビューはGitHub上で差分だけ見るのではなくて、ローカルに対象ブランチをcheckoutして実際に動かしながらレビューするときが多いので、

```
git fetch
git checkout -b pr-branch-name origin/pr-branch-name
```

としてレビューを始めることが度々ありました。
・・・が、今日、ふと、こんだけ毎日レビューしてるのに、毎回これやるのめんどいよな、と思いちょっと調べてみました。

## 道具
- [hub](https://github.com/github/hub)
  GitHubが作ってるらしい、git コマンドをラップしてさらにGitHub特有の処理とかを便利にできるコマンドを追加したツールです。

- [peco](https://github.com/peco/peco)
  みんな大好きpecoです。hubのコマンドを使ってcheckout対象ブランチを選びます。

### 実装

hubのサブコマンドで `pr` というGitHubのプルリクエスト関連の内容を取得するコマンドがあり、このサブコマンドで

- list
  いろんな条件で、カレントディレクトリのプロジェクトが対応するGitHubのリポジトリのPRを取得する

- checkout
  PullRequestの番号( #11 とかの番号)をキーにローカルに対象ブランチをcheckoutする。
  すでにcheckoutしたブランチが合った場合は、git pullして最新にする

というのがあり、これらを使って `hub pr list` の結果を適当にフィルタ、加工して、pecoで、PullReqest番号を選択し `hub pr checkout` でcheckoutします。

ｚｓｈ/bashで動く関数として実装しています。 `.zshrc`, `.bashrc` 等に追加して、 sourceします。
`ghpr`というコマンドとして動くようにしています。

```sh
# pecoでいまopenされているprのブランチをチェックアウトする
function peco-checkout-github-pr() {
  local selected_buffer=$(hub pr list -s open -L 20 --format='%t :%H :%I%n' | peco --prompt 'pull requests>')
  if [ -n "$selected_buffer" ]; then
    local pr_no=$(echo $selected_buffer | awk -F":" '{print $NF}')
    hub pr checkout $pr_no
  fi
}
alias ghpr='peco-checkout-github-pr'
```

![スクリーンショット 2019-07-18 22.02.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34692/3b78e683-dbd5-ee8c-8abb-3d3a33eec8fb.png)

こんな感じのPullReqestのリストが合った場合に、
<img width="448" alt="スクリーンショット 2019-07-18 22.08.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34692/aebc5382-c873-5d69-b12a-43d3aff05516.png">
で選択すると、
<img width="449" alt="スクリーンショット 2019-07-18 22.09.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34692/78466a71-2014-276a-182a-02e5b9ab14f0.png">

と、無事チェックアウトされました。便利。
Leetcode #647: Palindromic Substrings

```swift
func countSubstrings(_ s: String) -> Int {
    var dp = Array(repeating: Array(repeating: false, count: s.count), count: s.count)
    let s = Array(s)
    for i in 0..<s.count {
        dp[i][i] = true
    }
    var count = s.count
    for i in 0..<s.count {
        for j in 0..<i {
            dp[j][i] = (s[i] == s[j]) &&  (i - j < 2 || dp[j+1][i-1])
            if dp[j][i] {
                count += 1
            }
        }
    }
    return count
}
```
Rails 削除機能の実装方法　手順

#はじめに
ここではRailsにおいて削除機能を実装するときに必要な
手順について書いておきたいと思います。

##実装手順
まずは機能の実装ということで,ルーティング、コントローラー、ビューのそれぞれに削除のための定義をしている必要がある。

今回は処理の流れ順でコーディングしていく。
ここで削除の際の処理を整理すると
①あるビューで削除ボタンが実行される
②削除ボタンに設定されているルーティングが読まれる
③ルーティングに従い、コントローラーが呼ばれ、アクションが
実行され、対象のデータが削除される。
④アクションの処理が終了したことで、ビューファイルが呼ばれる。
ここでのビューは削除完了を表示するビューとする。

###削除ボタン作成
そのためまずは削除ボタンの作成をする。
作成にはビューファイルの任意の箇所にlink_toメソッドを使っていく。
以下記述例

~~~html:index.html.erb
<%= link_to '削除', "/tweets/#{tweet.user_id}", method: :delete %>
~~~

###ルーティング
データの削除を行う場合にはHTTPメソッドのうちの１つ、 deleteメソッドを使用する。
ルーティングファイルには以下のように
deleteメソッドを使ったルーティングを定義する

以下記述例

~~~ruby:routes.rb
delete 'tweets/:id' => 'tweets#destroy'
~~~

###コントローラー
コントローラーではルーティングで定義したdestroyアクションについてに処理を定義していく。

以下記述例

~~~ruby:tweets_controller.rb
def destroy
 tweet = Tweet.find(params[:id])
  if tweet.user_id == current_user.id
   tweet.destroy #destroyメソッドを使用し対象のツイートを削除する。
  end
end
~~~

###削除完了のビューファイル作成
destroyアクションの処理後のビューファイルを作成する。

ビューファイルに削除完了を表示するためのコードを記述する。

以下記述例

~~~html:destory.html.erb
<div class="contents row">
    <div class="success">
      <h3>
        削除が完了しました。
      </h3>
      <a class="btn" href="/">投稿一覧へ戻る</a>
    </div>
</div>
~~~
コードを理解する手法

システムのリプレイスや性能改善のためのリファクタリングを行うためには、コードを理解することは必須ですよね。

そのコードを見てすぐに仕様や振る舞いが理解できると幸せですが、そうでないことのほうが多いように感じます。

そんなときのアプローチ手法の紹介。

## メモる/スケッチを描く

膨大なコード、眺めてるだけじゃ理解できないことのほうが多いです。
ロジックを上から読んで、メソッド呼び出しがあればそのメソッドのロジックを確認して、、、なんてことをすると脳内メモリはすぐパンクします。

そんな時はメモを取りましょう、絵を描きましょう。

これはエクセルやメモ帳などのシステムツールではなく、紙に書いたほうが効果があります。

上からコードを読んでいき、メソッドがあればどこか別の場所にメソッド名を書いて線で結び、また元のロジックに戻る。

そうしていくうちに、縦の流れから線が伸び、植物の根のようになります。

そこから関連を見つけ出し、グルーピングすることで理解が深まることはよくあります。

メソッドの名前も正確でなくてもよいですし、よくあるUMLを使う必要もないです。
その場限りの理解を深めるためだけに使用するものとして、描いて理解することが良いようです。

## 試行リファクタリング
変更対象のコードを変更前の状態で、ただ闇雲にリファクタリングします。

メソッドの抽出や変数の移動、あらゆる方法を利用してリファクタリングをする。
ここで行うリファクタリングは、コードをきれいにすることではなくコードを**理解すること**を目的とします。

コードに触れていることで、コードへの理解が上がるという効果を狙います。

**そしてここでリファクタリングしたコードはどこにもコミットせずに捨てちゃいましょう。**

そうすることで、リファクタリングの本来の目的を意識せず、自分が理解しやすいようにコードを改変することができる、とのことです。

このような取り組みのことを「試行リファクタリング」と呼ぶようです。

---
上記の手法は
レガシーコード改善ガイド
第16章　変更できるほど十分に私はコードを理解していません
に掲載されています。
https://www.amazon.co.jp/dp/4798116831