OmniAICreator/Qiita-1.07M huggingface dataset:
DeepLearningを用いた株価予測（データ加工編）

#DeepLearningを用いた株価予測（データ加工編）

[前回の続き](https://qiita.com/hiro0219/items/533ad4c7d1830384c4e6)

前回の回で株価のデータを取得したので，そのデータを分析用に加工していく．
どのように分析していくかによって加工の仕方が変わっていくため，ここらで分析方法について考えていく．

私自身株をやっているが，基本的に日中仕事をしているため，株は中期・長期目線でやっている．
その為，翌日の予測をしたいとかそんなレベルの分析よりかは1か月後に上昇しているかなどの分析を行いたい．
とりあえず，過去2か月分のデータを元にその1月先の株価が上昇しているかの2値分類が出来たらいいかなと思い，それを軸にデータを加工していくことにする．

###データ確認
落としてきたCSVデータを早速確認

    4004 東証1部 昭和電工(株)（化学）,,,,,
    日付,始値,高値,安値,終値,出来高,終値調整値
    "2015-01-05","148","151","147","149","8516000","1490"
    "2015-01-06","147","148","142","143","23008000","1430"
    "2015-01-07","141","145","141","144","9663000","1440"
    ....(下に続く)
　

分かった情報は以下の要素
・ヘッダー行は2行目から
・文字コードがSJIS
・カラムは"日付","始値","高値","安値","終値","出来高","終値調整値"
・日付以外の項目はcsvによってばらつきが大きい(見るまでもなく分かることだが)
・1日1行のデータ

機械学習をするうえで，"始値","高値","安値","終値","出来高","終値調整値"の要素に関してはデータによって大幅な偏りがないよう加工する必要がありそうだ．

###データ加工
　過去2か月分のデータを元にその1月先の株価が上昇しているかの2値分類をするのであれば，とりあえず教師データ（2か月分），正解データ（その先の1か月後）の3か月分のデータがあれば十分である．そこで1か月分のデータが20行（1か月の平日日数）あると仮定し，csvデータを60行ごとに分割してデータの嵩増しを行う。
　またcsvごとのデータのばらつきに関してはcsvごとにカラムの最大値を取得し，その値で割る［0-1］の正規化を行うことにする．（上手くいかなかったら，正規化の方法を再度検討する余地あり）

```python
import os
import pandas as pd
import shutil

PATH = "chart_data/"
BK_PATH = "chart_data_bk/"
CUT_DATA = 60
OUTPUT_PATH = "shapeInfo/totalData/"

def shape_data_set():
	csv_list = os.listdir(PATH)
	for csv in csv_list:	
		#カラム行は2行目から
		csv_src = pd.read_csv(PATH + csv, skiprows=1, encoding="shift-jis")
		#CSVのデータを約3か月ごとに分割
		i = 0
		while True:
			csv_src_tmp = csv_src[CUT_DATA * i: CUT_DATA * (i + 1)]
			if len(csv_src_tmp) < CUT_DATA:
				break
			#日付以外のカラムは0-1区間で正規化
			csv_src_tmp["始値"] = csv_src_tmp["始値"] / csv_src_tmp["始値"].max()
			csv_src_tmp["高値"] = csv_src_tmp["高値"] / csv_src_tmp["高値"].max()
			csv_src_tmp["安値"] = csv_src_tmp["安値"] / csv_src_tmp["安値"].max()
			csv_src_tmp["終値"] = csv_src_tmp["終値"] / csv_src_tmp["終値"].max()
			csv_src_tmp["出来高"] = csv_src_tmp["出来高"] / csv_src_tmp["出来高"].max()
			csv_src_tmp["終値調整値"] = csv_src_tmp["終値調整値"] / csv_src_tmp["終値調整値"].max()
			csv_name = csv.split('.')[0] + "_" +str(i) + ".csv"
			csv_src_tmp.to_csv(OUTPUT_PATH + csv_name, encoding='shift-jis')
			i += 1
		#加工した加工前のデータは別フォルダに
		shutil.move(PATH + csv, BK_PATH)	
		
def main():
	shape_data_set()


if __name__ == '__main__':
	main()

```

加工前のデータは再度使用することがあるかもしれないので，置いておきたい．
ただ，追加でデータを取得することもあると思うので，データ加工をすでに行っているかの区別はしたい．
ということで，加工したデータは別フォルダに移動することにした．

次回はこの加工したデータをどのように使用していくか検討しようと思う．
【勉強用】Apacheとかnginxとかunicornとかpassengerとか（おまけにリバプロ）

#勉強用
自己学習の為にQiitaに残していきたい


##Webアプリケーションの流れ

###静的なサービス
- Webブラウザのリクエストに対して、Webサーバが結果を返す
    - webブラウザ ⇄ Webサーバ

###動的なサービス
- Webブラウザのリクエストに対して、Webサーバがアプリケーションサーバにリクエストを送り、返ってきた結果をwebブラウザに返す
    - Webブラウザ ⇄ webサーバ ⇄ アプリケーションサーバ ⇄ アプリケーション
- Webブラウザのリクエストに対して、webサーバがモジュールを通してプログラムを実行し、返ってきた結果をWebサーバに返す
    - Webブラウザ ⇄ Webサーバ（モジュール） ⇄ アプリケーション


##Webサーバ
例）Apache、nginx

##アプリケーションサーバ
Webサーバから受け取ったリクエストを元に、Rubyなどを実行し、Webサーバに結果を返す
例）unicorn、Puma

※passengerは？
Apacheやnginxのようなwebサーバに組み込んで使えるモジュール。
Railsアプリケーションを動かすためにアプリケーションサーバを用意する必要がない。

##からのプロキシとリバプロ
###プロキシ（webブラウザのパシリ）
１．Webブラウザ→「俺の代わりにこのページ貰ってきておくれ」→プロキシサーバ
２．プロキシサーバ→「このページおくれ」→Webサーバ
３．プロキシサーバ←「ほれ、そのページだよ」←Webサーバ
４．Webブラウザ←「ほれ、貰ってきたページだよ」←プロキシサーバ

###リバースプロキシ（webサーバのパシリ）
１．Webブラウザ→「このページおくれ」→リバースプロキシサーバ
２．リバースプロキシサーバ→「このページをくれってきたよ」→Webサーバ
３．リバースプロキシサーバ←「じゃあ、このページ返してあげて」←Webサーバ
４．Webブラウザ←「ほれ、そのページだよ」←リバースプロキシサーバ

###リバプロを使うメリット
身元を隠せる
負荷分散ができる

##参考
ピヨ太くんでおなじみの
https://wa3.i-3-i.info/word1755.html
SQLのクエリが重すぎた話

#概要
大量のレコードを扱うテーブルを表示するときに、クエリの発行の仕方が悪くてクエリの量がとんでもなく多くなってしまったので、そのときの解決方法を書いておきます。

#本題
![d4b2e4b5c79fe9b78a580e4fe6822a65.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638271/80940606-aa2b-8ccd-ed93-221112aa012c.png)
上記のようなテーブルをデータベースから取得して表示する場合、
A~Eそれぞれに02などの値が紐づくのであれば、
行ごとに値をとってこようとするとA~E,F,G,...と増えていくにつれて発行するクエリはそれだけ増えていきます。
そこで、`group_by`などを使い、aa,bb,cc,dd,ee,ffの列ごとにクエリを発行するようにすれば、
レコード自体が増えても影響は少なくできます。

#まとめ
こういった問題はn+1問題とも呼ばれているようですが、自分は知りませんでした。
駆け出しのうちはそもそも知らないことが多いので、実装方法はときどき人に聞いた方がよさそうです。
refileのattachment_image_tagで画像がうまく表示されない場合に



##この記事について
画像を表示させるためにrefileのattachment_image_tagで画像が表示されない時があって、いろいろ調べて試行錯誤した結果安定して？表示されるようになったので投稿


##問題のエラー
<img width="206" alt="スクリーンショット 2020-08-05 18.35.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653956/127bef38-faf6-40d4-f02c-63e110599147.png">

白い雲と青い空、そして可愛らしい山を描いた画像で癒されそうだが、こいつは精神を破壊させてくる悪魔の画像。
この悪魔が表示されていた時のコードは以下の通り

```ruby:qiita.rb
<%= attachment_image_tag [_idを除いたカラム名], :image, :fill, 横幅数値, 縦幅数値, format: '識別子（jpegなど）' %>
```


##**僕の場合**の解決法
attachment_image_tagの`fill`の書き方を変更した。

```ruby:qiita.rb
# 変更前
<%= attachment_image_tag [_idを除いたカラム名], :image, :fill, 横幅数値, 縦幅数値, format: '識別子(jpegなど)' %>  



# 変更後  
<%= attachment_image_tag [_idを除いたカラム名], :image, size: "横幅数値x縦幅数値", format: '(jpegなど)' %>

```

どうやら`fill`が悪さをしていて、画像の大きさを指定するために`size`を使用してみると忌々しい悪魔の画像が表示されないようになった。


https://github.com/refile/refile

公式を見てみも`size: "横幅数値x縦幅数値"`で書いてる様子はなく、これでなぜ上手くいってるのかが良く分かっていない。
多分根本的な解決にはなっていないから、判明次第編集しまっす。
ユーザー情報をセッションに格納する方法

#ユーザー情報をセッションに格納する方法

phpを使用したポートフォリオ作成時にログイン画面を実装しました。
ログイン後、ユーザー情報に紐づいた処理を行うため、ユーザー情報をセッションに格納しました。ログイン → ログアウトまでの中で、セッションに格納に必要な記述をカンタンにまとめました。

##そもそもセッションとは
こちらのサイトの言葉がわかりやすいので引用します。Cookieとの違いも記載しており、わかりやすいです。

>セッションとは、コンピュータのサーバー側に一時的にデータを保存する仕組みのことです。
[PHPでセッションを使う方法【初心者向け】](https://techacademy.jp/magazine/4970)


##手順
1. ログインするときにユーザー情報を格納する
2. ログイン成功後、セッションからユーザー情報取得
3. ログアウトしてセッションを削除

ものすごく簡単に書きました。

### 1. ログインするときにユーザー情報を格納する

記載したコードはこちらです。今回私はユーザーIDのみを格納しました。
※まだローカル環境で開発中なので画面遷移はlocationです。

ログイン成功後の画面に遷移する前にセッションに値を格納しました。

```php:

//セッションにユーザーID $user_id を格納
session_start();
$_SESSION['user_id'] = $user_id;

//ログイン成功後の画面に遷移
header("Location: ./index.php");
```

### 2. ログイン成功後、セッションからユーザー情報取得
ログイン後遷移したファイルにユーザーIDを取得するコードを記載。

```php:
//セッションからユーザーID取得
session_start();
$user_id = $_SESSION["user_id"];
```
セッションからユーザーIDを取得、 `$user_id` という変数に格納しました。
こちらの値を元に、画面上にデータを表示させたりします。

### 3. ログアウトできるようにする
ログアウト つまり 格納したセッションを削除します。

ログイン後の画面上に「ログアウト」ボタンを設置し、ログイン画面に遷移するようにしました。その際にセッションを削除します。

・ログイン後の「ログアウト」ボタン　※ボタン押すとログイン画面に移動

```php:
  <form action="../users/index.php" method="post">
      <input type="hidden" name="action" id="action" value="destroy"/>
      <input type="submit" value="ログアウト" />
  </form>
```

・ログイン画面の処理

```php:
//ログアウト セッションの値を削除
if ($_POST["action"] == "destroy") {
    unset($_SESSION["user_id"] );
}
```

###まとめ
こちらに記載した内容以外にも、ログイン失敗したときなども考慮が必要ですが、いったんログイン成功パターンの流れを記載しました。セッションでの記述は思った以上にシンプルでスムーズに記載できたので、今後も活用していきたいと思います。
Xplenty中級編 Part5： DB周りの設定（Source編）

今回はよく使うDatabaseコンポーネント（ソース）について紹介します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65461/88666e90-b1a6-d2be-5763-e70da4c70fb7.png)
##Table/Queryの選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65461/aa597e48-348b-b04b-aa89-b99b37544a9e.png)

**Tableを選択した場合**：1つのテーブルを変換なしでシンプルに取り込みたい場合に使用します。
**Queryを選択した場合**：SQLクエリを自身で書き、取り込みと同時に結合処理やデータ変換をSQLで行いたい場合に使用します。

#Tableを選択した場合の各オプションについて

**Souce shema**：ソースのスキーマ名を設定します。
**Souce table/view**：ソースのテーブルもしくはViewの名前を設定します。
**Where clause**：SQLのWhere句を設定します。（Whereは不要です。Where以降を入力ください。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65461/d1275bf2-2000-d732-b362-4e04e98dd91f.png)

###クエリ並列化オプション
データをクエリの並列実行で取得することで取り込み処理部分の高速化が期待できます。
クエリを並列化するには、クエリを分割するキーと並列接続の最大数を設定します。クエリを並列化する場合、最初に列の最小値と最大値を取得し、データを範囲に分割するためのwhere句を使用し、複数の接続からクエリを実行します。例：pk> = 1 AND pk <1000、pk> = 1001 AND pk <2000。

**Split query by key column**：クエリの分割に使用するプライマリキーを指定します。

**Max parallel connections**：クエリを並列実行するための接続数を設定します。クラスターの処理パワー（ノード数）に対して「Node数x5」の値を目安に設定ください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65461/525b87db-4c1a-c0bf-3e2c-4c08f8e35df0.png)


###データ取得方法の指定
**Noneを選択した場合**：データベースからデータが読み取られ、変換がすぐに適用されます。
**Copyを選択した場合**：データを処理する前に、データベースソースから中間ストレージにデータをコピーします。これにより、データベースコネクションを開いている時間を短縮することが出来ますが、通常ジョブ全体の時間はNoneのほうが短くなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65461/19708513-83c5-b4ed-007e-2cb8a774c928.png)



#Databaseコンポーネント（Destination）の設定はこちら
送信先（Destination）がDBの場合、「[Xplenty中級編 Part4： DB周りの設定（Destination編）](https://qiita.com/Azabu10ban/items/bb920de09b8eb3487b58)」を参考ください。
IonicのLoadingControllerをObservableで扱う

## 前置き
RxJSを勉強してある程度使えるようになり、
async/awaitは全部ぶっ潰したくなる病になってしまったが、
ionicのコンポーネントは公式で紹介されている書き方がほとんどasync/await。

page.tsの中のapi取得処理はObservableで書いており、
ObservableとPromiseの混在が気持ち悪かったので
Loading処理をObservableで使えるようにしてみた。

[ion-loading公式ドキュメント](https://ionicframework.com/jp/docs/api/loading)

## loadingのserviceを作成する

```loader.service.ts
import { Injectable } from "@angular/core";
import { LoadingController } from "@ionic/angular";
import { Observable, from } from "rxjs";
import { flatMap, finalize } from "rxjs/operators";

@Injectable({
    providedIn: "root"
})
export class LoaderService {
    private loader = null;

    constructor(public loadingController: LoadingController) {}

    loading(obs$: Observable<any>): Observable<any> {
        return from(this.openLoader()).pipe(
            // ローディングを表示した後、引数で渡したobservable処理を開始
            flatMap(() => obs$),
            // 引数で渡したobservable処理が終わったらローディング表示が消える
            finalize(() => this.closeLoader())
        );
    }

    private async openLoader(): Promise<void> {
        if (this.loader == null) {
            this.loader = await this.loadingController.create({});
        }

        await this.loader.present();
    }

    private async closeLoader(): Promise<void> {
        if (this.loader == null) return null;

        await this.loader.dismiss();
        this.loader = null;
    }
}

```

## 各ページでのローディング記述

```hoge.page.ts
fetchData(param) {
    // API取得処理を定義して変数に格納
    const obs$ = this.search(param).pipe(
        tap(data => this.data = data)
    );

    // 定義したObservable処理をloadingServiceに渡してsubscribe
    this.loaderService.loading(obs$).subscribe();
}
```
Goolge Cloud Buildでエラーが出たときの対処

# request contains an invalid argument.エラーが発生

## デプロイしていたらエラーが発生

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533120/cf93f866-551e-1e01-87b0-4c998b387633.png)


## 原因はcloudbuild.yamlだった

```yaml:cloudbuild.yaml
  - name: gcr.io/cloud-builders/gcloud
    id: Deploy
    args: ['beta', 'app', 'deploy', '--no-cache', 'app.yaml']

  - name: gcr.io/cloud-builders/gcloud
    id: Deploy
    args: ['beta', 'app', 'deploy', '--no-cache', 'queue.yaml']
```

idがかぶっていたのでエラーになっていた。
それならそうと言ってくれれば楽なのに。
解決するのに時間をすごい使ってしまいった。
GoogleColaboratoryでゼロから作るDeep Learningのサンプルコードを実行した際のメモ

<h1>はじめに</h1>
O'REILYから出版された**「ゼロから作るDeep Learning -Pythonで学ぶディープラーニングの理論と実装」**をGoogleColaboratory環境でサンプルコードを実行する際にメモした内容となります。

- 書籍のサンプルデータをGitHubより入手
- データのマウント方法について（マイドライブにデータをアップロードするだけでは、利用できないので接続方法の紹介）
- 画像の表示について（サンプルコード記述してもGoogleColaboratoryでは画像が表示されなかった為、代替え方法の紹介）


<h2>第３章　ニューラルネットワーク</h2>
3.6.1　**MNISTデータセット**
3.7.1　**ニューラルネットワークの推論処理**

上記の内容を実行した際のメモとなります。
(*P72〜P75*)



<h2>データの取得</h2>
**GitHubよりデータを取得します。**（ダウンロード）
https://github.com/oreilly-japan/deep-learning-from-scratch
フォルダ名  = **deep-learning-from-scratch-master**



<h2>データのアップロードとマウントについて</h2>
1. マイドライブ**Googleドライブ**内にフォルダをアップロードします。
2. 新規でGoogle Colaboratoryを作成します。
3. ドライブをマウントします。（ノートブックでデータを使用できる状態にする）<br>


   - アイコンをクリックすることで処理が始まります。<br>
<img width=350  alt="mount_1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527869/5a967490-739b-a188-876f-2056b203179a.png">
   - Googleドライブに接続<br>
   <img width=500 alt="接続.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527869/ff06e506-3dd2-0526-e327-717e591f4f4d.png">
   - driveが表示されたら接続完了<br>
<img width=350 alt="mount_2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527869/a46ca6e1-380d-ae42-3b9f-1ada479f4030.png">

<h2>ディレクトリを移動する</h2>
最初のコードを入力する前に、カレントディレクトリを変更する必要があります。
<img width=700 alt="cd.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527869/2e72ef4c-3926-f237-177e-2469e2e49380.png">

<h2>load_mnist 関数のインポート</h2>
<img width=700 alt="load_minst関数インポート.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527869/ec22d2bc-1622-6713-6e48-15536a35f5a7.png">

<h2>mnist_show.pyを実行</h2>
- ６行目までのコードを省略することも可能です。（load_mnistのインポートの際に実行済み）
- １枚目の訓練画像の数字　＝　**5**
- １次元配列の個数　＝　**784,**
- １次元配列より元の形状に再変形　＝　**28, 28**
- 本来、表示されるはずの訓練画像が表示されません。　＝ **imgに格納はされているが表示されない。**
<img width="700" alt="mnist_show.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527869/f30a44c3-ee0f-1cf5-6682-b52520850e18.png">


<h2>画像の表示</h2>
- 本当に **5** であるか確認する為、別の表示方法を試みました。
- matplotlibをインポートし画像の表示を実行。
- １枚目の訓練画像を表示することに成功しました。<br>
<img width="300" alt="5img.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527869/ad354443-5726-f0fc-725b-a2c0f35457e7.png">

<h2>neuralnet_mnist.pyを実行</h2>
- 正解した認識精度　＝　**0.9352(93.52%)で分類する。**
<img width="600” alt="neuralnet_mnist.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527869/8af02705-d7a5-6929-a956-8e00eec27eea.png">

<h2>最後に</h2>
ただサンプルコードをGoogleColaboratoryで実行するだけですが、結構な時間を費やしてしまいました。
同じような内容で悩んでいる方に、少しでも役立てていただけるよう初めて投稿しました。
Centos7環境のProxy設定まとめ

centos7でプロキシ（認証あり）を利用する場合のメモです。

#profile
```
vi /etc/profile

最終行に追加
#プロキシ設定
PROXY="http://<user>:<pass>@<proxy_host>:<proxy_port>" # proxyサーバのドメインとポートを指定
export http_proxy=$PROXY
export HTTP_PROXY=$PROXY
export https_proxy=$PROXY
export HTTPS_PROXY=$PROXY
```

#yum

```
vi /etc/yum.conf

最終行に追加
#プロキシ設定
proxy=http://<user>:<pass>@<proxy_host>:<proxy_port>
```

#rpm
```
rpm --httpproxy <user>:<pass>@<proxy_host> --httpport <proxy_port>
```
#docker
```
vi /etc/default/docker
export http_proxy=http://<user>:<pass>@<proxy_host>:<proxy_port>
```

#参考サイト
https://qiita.com/KuwaK/items/a33c625d1472b0ab2e16
https://qiita.com/Ki4mTaria/items/d10f3d562d02a0a4ded4
[Laravel]Composerエラー　「Do not run Composer as root/super user!〜」

Composerを使ってライブラリを使ってインストールをしたとことろ以下のエラーが出ました。

```
Do not run Composer as root/super user! See https://getcomposer.org/root for details
```

composerを使ったインストールをrootユーザーでしようとしたため、エラーが出たみたいです。
なぜrootユーザーでインストールは好ましくないかについては以下を参照してください。
https://getcomposer.org/doc/faqs/how-to-install-untrusted-packages-safely.md

root以外のユーザーを作成します。Linuxのコマンドの`useradd`でアカウントを設定します。

```
// rootユーザーになる
$ sudo su -

// ユーザーを追加
$ useradd -m 名前

//　追加したユーザーに移動
$ su 名前

名前$ composer コマンド
```

これでroot以外のユーザーになったため、composerでインストールができるようになりました
DevOpsにおけるサービスの可視化

今回はサービスの可視化について書いてみます。
ただし、システムのツールによる可視化ではなく、メンバーの作業に関する可視化です。
ツールは全ての事がわかってから使えばよく、最初からツール化を考えると間違った方向に進んだ場合修正が難しくなります。
面倒でも最初はコミュニケーションも兼ねて手作業で物事を進めましょう。

##DevOpsにおける基本を無視する##
最初から不穏なことを言っていますが、DevOpsにおいて
- 障害等の犯人捜しはしない
- なぜ起こったのかを詳しく検証し、次回以降修正する
と言うのがあります。
しかし、縦割りの業務形態では皆が責任を回避しようとし、詳しく調査をおこなわないため、また似たような問題を発生させます。

縦割りの業務形態では責任範囲がはっきりしているわけですから、犯人(責任の所在)探しは重要です。
しかし、ただ単に~が悪いでは、全く意味がありません。
当然のことながら問題が何故発生したのか、いつ発生したのか、どのような状況で発生したのか等詳細に原因追及を行う必要があります(別の部署に責任を被せようとする人もいますから)

DepOpsでは、割と性善説に則っており、問題はみんなで解決しよう、経験はみんなで分かち合い業務を向上させていこうと言う形ですが、縦割り業務には通用しません。

このためにもサービスの可視化は非常に重要な項目となります。

###メンバーの作業量、作業内容の可視化###
縦割り業務の最大の問題は、「**隣の部署で何をしているかわからない**」という事です。
この問題を解決するため各メンバーの
- 1日の作業時間
- 作業内容の比率
を出す必要があります。
非常に面倒な作業ですが、自動化し、手作業が減る事で報告する内容も回数も減るわけですから義務とします。
作業時間が多く、トラブル対応ばかりならそのメンバーの作業に何か問題があることがわかります。
また、作業時間は少ないのにトラブルの原因となることが多い場合は、何か対策が抜けているという事になります。

このようにして全メンバーの作業を可視化することで、トラブル発生時の作業内容や作業時間も把握しやすくなり、原因の特定の容易さにもつながります。
一番大きいのは、「この部署こんなに大変なのか」と言った実態を他の部署が気付けることでしょう。

###トラブル発生時の作業手順の可視化###
何か障害が発生した場合、1分でも1秒でも早く復旧したくてむやみに手を動かしてしまう場合があります。
これで素早く復旧することもありますが、当然原因の解析や今後の改善には役に立たないので、多少時間がかかっても、各メンバーが行う作業手順を可視化する必要があります。

ここではプロジェクトマネージャーの手腕が大きくかかわってきますが、各メンバーから提出された作業手順を確認し、どの順序で原因究明をするのか、対策を行うのかを決めなければいけません。
これも最初は非常に大変ですが、サービス運用やトラブル対応が改善されるにつれて、定収される作業手順も正確になり、少なくなっていきます。

対応手順では
- 目的
- 作業時間
- 作業手順
- 想定される結果
を記述します。
目的と想定される結果は重要で、これがないと他のメンバーには作業内容が何のために行われるのか不明になってしまいます。
これらはアジャイル開発のタスクシートと同様にホワイトボードに貼り付けて管理すると便利でしょう。

また、よくある事ですが、対応を行った際新たに問題を発生させてしまった、作業に間違いがある事に気づいたという場合もあります。
既に他のメンバーも対応作業を始めてしまっている場合もあるので、この際にも新しく対応手順を作成し、プロジェクトマネージャーの指示を仰ぐ必要があります。
これもアジャイル開発で作業タスクに誤りを見つけた場合にその場で直すのではなく、アーキテクトに報告するのと同じ手法になります。

この方法の問題はサービス初期には非常に時間がかかる事です。
そのためにも、サービスリリース前に想定されるトラブルシナリオなどを作成し、あらかじめ対応シートを作成しテストしておくことで、リリース初期の対応の遅れをある程度カバーできると思います。

##まとめ##
今回は非常に手作業の多い内容となりましたが、最初は手作業でやりましょう。
最初からツールを導入するのは全くお勧めできません。
これはメンバー間のコミュニケーションにも関わってきますので、時代に逆行するようですが、紙とホワイトボードで作業を進めていくことが、その後の効率化にも生きてきます。
【時短テク】再生速度を指定できない動画を倍速で見るためのワンライナー

## ブラウザのデベロッパーツールでこれを実行すれば動画が倍速で再生される

```js
document.getElementsByTagName('video')[0].playbackRate = 2
```

### 注釈

* 倍速だと早すぎる場合は、最後の `= 2` を1.5に変えると1.5倍速にできます。1にすれば元に戻ります。
* 動画（videoタグ）がページ内に一つだけの場合に使えます。　※複数ある場合は `[0]` を指定したい動画にあわせればOK！

## Have a nice time!

現在、多くのセミナーやカンファレンスなどのイベントが、Webinar形式＆動画公開になっています。動画のインターフェースによっては、再生速度を指定できない場合も多いのですが、そんなときにこのワンライナーを使うことで、いろんなセッションを効率よく視聴することができ、さらに捗ってます！
Vuetify Sparklinesに垂直ラベル、基準線がない件

Vuetifyで用意されている線グラフのコンポーネント**Spark lines**
https://vuetifyjs.com/ja/components/sparklines/



見た目も綺麗でぜひ利用したいと思い
プレイグラウンドで色々いじってみて気づいたのが、

各データポイントの下にラベルを表示するのは
**show-labels**を**true**にすることでできるが
####垂直ラベルを表示する機能がついていない




ということ。




スパークラインのVuetifyのスタンスとしては
あまり細かくデータを見せる気は無いようで、
https://vuetifyjs.com/ja/components/sparklines/#%E3%81%A1%E3%82%87%E3%81%A3%E3%81%A8%E4%BC%91%E6%86%A9

>簡潔な情報を得るために、完全なチャートはやり過ぎかもしれません。グラデーションをいれたトレンドラインを使用すると、あまり多くの情報を表示することなく、ユーザーに十分な詳細を提供できます。

色のグラデで基準線を表現してるんですね。

基準線と垂直ラベルの
切実なリクエストはあるようですが、改めて対応予定を否定していました。
https://github.com/vuetifyjs/vuetify/issues/6173


あくまでSparklinesは動向をなんとなく見せるような感じで
例えばInstagramのアクティビティのような…
![E0725ADD-B697-4DB5-BF72-D9BE8EA60BD4.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/619638/d7c8cc38-c09e-4063-ffc5-5931b180db2c.jpeg)
（基準線がない／垂直ラベルがなく水平方向のラベルのみ）
この程度の情報量だけで簡潔に伝える場合に使うものと考えた方が良さそうです。

結果、今回はより詳細な情報として線グラフの情報を出したいため、
Chartjsなどを使用することにしました。
https://www.chartjs.org/

参考になれば幸いです。
【備忘録】PythonのOpenCVにC++のcopyTo, Cloneはない

###気をつけよう
copyToの代わり

```python:copyTo.py
src1[ 0 : src2.shape[0], 0 : src2.shape[1]] = src2

```
Cloneの代わり

```py:clone
src2 = src1.copy()
```
【Java】電卓プログラムの作成１

#目的
Javaの学習を独学で初めておよそ１ヶ月が経ち、Javaを使用してGUIアプリケーションを作成したいと思い、電卓アプリを作成してみる。今回は、まず電卓アプリの見た目を作成していく。

#参考
▼webサイト
・[Let'sプログラミング-Swingを使ってみよう](https://www.javadrive.jp/tutorial/)
・[Javaで始めるプログラミング-Chapter12電卓を作ってみる](http://msyk.net/keio/JavaBook/eclipse-indigo/ch12.html)
・[クラスBorderLayout](https://docs.oracle.com/javase/jp/8/docs/api/java/awt/BorderLayout.html)

#使用環境
OS：Mac
言語：JavaSE1.8
Eclipse

#成果物
プログラム作成時に参考にさせて頂いたWebサイト
[Javaで始めるプログラミング](http://msyk.net/keio/JavaBook/eclipse-indigo/ch12.html)

###作成したプログラム
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686562/8116deec-5847-d695-1422-3a76fedf1e91.png)
1〜8行目：必要なライブラリ等をインポート

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686562/e583e51e-f690-b8b6-4e28-0034b4cc0830.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686562/748e214f-ae0a-2f4a-1ee6-ecafb2393e55.png)
１８〜２１行目：フレームの生成（フレームのタイトルをつけたり、フレームの大きさを決めるなど）

22〜25行目：テキストボックスの生成

２７〜５１行目：テンキーの生成。
４×４のグリッドに数値等のボタンを配置。

###実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686562/ae46b661-a28f-dba6-db2c-77bb614e77fd.png)
次回は数字ボタン等のボタンの処理を作成する。
lwc关联笔记(5)生命周期


在刷新页面的时候，也就是lwc控件开始加载到完毕的时候，有以下的生命周期。
只要一个控件重新加载了，请记住，这里指的是refresh，refresh页面或者refresh component。都会触发该加载流程。

refreshApex的方法只是重新刷新了后台，这个时候不会调用构造器。






![33ccf031-de9d-41cb-9e59-18725345c125.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491095/ad98cbde-02ab-295a-d43a-5733a9d850b5.png)

上图是lwc的生命流程。
对此我们进行实验检测。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491095/4c242e94-b5b7-0521-f888-fe289399edd8.png)

由此得知，这是没有问题的。


我们稍加说明一下：

1.父控件的constructor，这很明显，第一步要执行父的构造函数
2.由于此时子插件还没开始加载，所以会先执行wire等一系列操作
3.如果apex返回来了结果，那么callback接收
4.这时开始加载子控件，执行子控件的构造函数
5.子控件如果有后台操作，那么会在这个时候执行，由子的callback来接收
6子控件已经完全加载完毕，state可以进行更新了，所以执行rerender，刷新子控件时加载reredenercallback
7各个部位的子控件加载完毕，这个时候父控件的state也已经可以更新了，执行父控件的rerender，同时执行父控件的reredenrcallback
システム全体稼働率（直列、並列組み合わせ）

平成31年春期 午前問題13

稼働率の等しい装置を直列や並列に組み合わせたとき，システム全体の稼働率の高い順に並べたものはどれか。ここで，個々の装置の稼働率は0より大きく1未満である。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/d0de4c01-c386-741f-45d3-73889de1eb1e.png)

１、直列
R　×　R

２、並列
１－（１－R)　×　（１－R)


上記の列を使って、計算すると、高い順にソートすると、A>C>Bですね。
A:
並列ので、１－（１－R)　×　（１－R)
仮に、Rは0.8の場合、０．９６ですね。

B：
0.8 * 0.96 < 0.8

C:
1 - (1-0.64) ×　(1-0.64) = 1- 0.36*0.36 = 0.8704
Python + Seleniumで「Message: session not created」が発生した場合

PythonでSeleniumを動かしている時に「Message: session not created」が発生して、気づいたら数時間エラー解決に掛かっていました。
このエラーをググると大体「Chromeのバージョン」と「Chrome-driverのバージョン」違いで発生するという情報が出てきますが、今回自分が経験したパターンは異なっていたので、備忘録として残しておきたいと思います。

```bash
[root@v111-111-111-11 html]# python3 run.py
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/selenium/webdriver/chrome/webdriver.py", line 81, in __init__
    desired_capabilities=desired_capabilities)
  File "/usr/local/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py", line 157, in __init__
    self.start_session(capabilities, browser_profile)
  File "/usr/local/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py", line 252, in start_session
    response = self.execute(Command.NEW_SESSION, parameters)
  File "/usr/local/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute
    self.error_handler.check_response(response)
  File "/usr/local/lib/python3.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.SessionNotCreatedException: Message: session not created
from disconnected: Unable to receive message from renderer
  (Session info: headless chrome=80.0.3987.122)
```
#エラー原因
バージョンも両方一致しているし、バージョン変更していないし、以前まで動いていたから、何かChromeのプロセスが大量に溜まってたりしないかなと思って、実行しているサーバ上でChromeのプロセスを確認しました。

```shell
[root@v111-111-111-11 html]# pgrep -l chrome
10436 chrome
10444 chrome
[以下略]
```
ずらっとChromeのプロセスが50個くらい大量に残っていました。恐らくwebdriverの処理が終了した後にChromeのプロセスを終了できておらず、溜まってしまったのかと思います。

#解決方法
```shell
[root@v111-111-111-11 html]# pkill chrome
```
Chromeのプロセスを終了させ、再度スクリプトを実行したところ、問題なく動きました。
「Chromeのバージョン」と「Chrome-driverのバージョン」が一致しているにも関わらず、上記エラーが発生する場合は参考にしてみてください。
Lightning プラットフォーム API の基礎 ⇒ Salesforce Lightning プラットフォーム API の概要

１．Salesforce で開発する場合の API ファーストアプローチにより、お客様は何ができますか?
２．REST API が最適なのは、次のうちどの使用事例ですか?
３．SOAP API が最適なのは、次のうちどの使用事例ですか?
４．Bulk API が最適なのは、次のうちどの使用事例ですか?
５．ストリーミング API が最適なのは、次のうちどの使用事例ですか?
６．合計 API 制限の計算に関与する、すべての要因は何ですか?
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634241/e1c4ad4c-9e7e-4a3f-8112-a57179a267c8.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634241/fd349451-ae18-3ef4-70fd-4211ed68cea3.png)
[GAS][JS] 配列Aにあって配列Bにない値を取り出したい

配列Aには存在していて、配列Bに存在しないものを取り出したい。という事がありました。

ケースとしては **すでに記録されているデータがあって(existData)、新たにもらったデータ(newData) のうち、existData にあるものは無視して新しいものだけを取り出したい** というものでした。

教えてもらったコードが下記。きっと後でも使うのでメモ。

下記の例では `[4,5]` を取り出したい。

```js:javascript/GAS
function pickupNewData(){
  const newData   = [3,4,5];
  const existData = [1,2,3];

  const filtered = newData.filter( newVal => {
    const hasValue = existData.some( existVal => existVal === newVal );
    return !hasValue;
  });
  console.log(filtered); // => [ 4, 5 ]
}
```

私、Javascriptで配列を扱う関数(mapとかfilterとかsomeとかreduceとか)を扱うのが苦手なんです。なのでこのコードも、filterの中でsomeがいて、パッとみて「どゆことだ？」って思ってしまうのです。ゆっくり考えたらわかるのにね。

もっといい方法がありそう？ 
**(追記) コメント欄に @xtetsuji さんからアドバイスもらいましたので是非そちらも見てみてください！**

ちなみに

```js
return hasValue; // !を取る
```

にすると「どちらの配列にも存在するもの」である `[3]` が取得できます。 


# 追記: 高階関数

その後、filter とか map みたいのを「高階関数」というんだと知りました。高階関数についてはこの動画がめちゃめちゃわかりかすかったので紹介します。英語苦手な私でも字幕付きで理解できました。

https://www.youtube.com/watch?v=BMUiFMZr7vk
tensorflow-gpuが動いたCUDA, cuDNNのバージョンのメモ

PyPIに置かれているtensorflow-gpuビルドが対応している
CUDA, cuDNNバージョンをメモするだけの記事です。

新しいバージョンで動作を確認したらこの記事に追記していきます。

## 対応CUDA, cuDNN一覧

このページは個人が自分用メモとして作っていますので
tensorflow公式に記載がない場合のみ参考までにご覧ください。

tensorflow公式
https://www.tensorflow.org/install/source#tested_build_configurations

#### Windwows10

| tensorflow  | CUDA   | cuDNN    | 備考                 |
|:------------|-------:|:--------:|---------------------:|
| 2.3.0       | 10.1   | 7.6      | 手元環境で動作を確認   |
| 2.2.0       | 10.1   | 7.6      | 手元環境で動作を確認   |
| 2.1.0       | 10.1   | 7.6      | Release Noteに記載あり |
| 2.0.0       | 10.0   | 7.4      | 公式サイトに記載あり   |

#### Ubuntu 18.04

| tensorflow  | CUDA   | cuDNN    | 備考                  |
|:------------|-------:|:--------:|----------------------:|
| 2.3.0       | 10.1   |          |                       |
| 2.2.0       | 10.1   | 7.6      | 手元環境で動作を確認   |
| 2.1.0       | 10.1   | 7.6      | Release Noteに記載あり |
| 2.0.0       | 10.0   | 7.4      | 公式サイトに記載あり  |


## バージョンについて

pip installでインストールされるtensorflow-gpuビルドは特定のバージョンのCUDAを参照するようになっているので、バージョンが違うCUDAを入れると動きません。

どのバージョンのtensorflow-gpuがどのバージョンのCUDAを使うようにビルドされているかは古いバージョンについては<a href="https://www.tensorflow.org/install/source#tested_build_configurations">こちら</a>に一覧されているので問題ないんですが、2020年8月現在tensorflow 2.3.0までリリースされているのに一覧表には2.1.0までしか載ってません。
https://www.tensorflow.org/install/source#tested_build_configurations

じゃあRelease Notesに載ってるかというとtensorflow 2.1.0には対応CUDAバージョンが書かれているのにtensorflow 2.2以降のRelease Notesには載ってません。
https://github.com/tensorflow/tensorflow/releases

これだと困るので新しいバージョンがちゃんと動いたらそのときのバージョンをメモしておこうというのがこの記事です。新しいバージョンについても新しい記事を書くんじゃなくてここに追記していきます。

## 自分で確認する方法

CUDAが入っていないかバージョンが適切でない場合、importした際に以下のようにエラーメッセージが出ます。その際に表示されるdllのファイル名でバージョンが分かります。以下ではcudart64_101.dllを読もうとしているのでおそらくCUDA10.1が必要なんだろうという感じです。

```python:python
>>> import tensorflow as tf

2020-08-05 00:33:55.037723: W tensorflow/stream_executor/platform/default/dso_loader.cc:59] Could not load dynamic library 'cudart64_101.dll'; dlerror: cudart64_101.dll not found
2020-08-05 00:33:55.037919: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.
```

## 確認に使っている手元環境

Windows10
Anaconda3
Ryzen7-1700X
GTX-1080Ti

Ubuntu18.04
Anaconda3
core i9-9900K
TitanV
LaravelでToDoアプリを作ったときの備忘録

定期的にQiitaで記事を投稿（アウトプット）することが大事かなと思い、間違い等もあると思うが、書いていく。

下の記事を参考にToDoアプリを作る際の備忘録を残していく。
下の備忘録は、全てこちらの記事に載っているのでそちらを参考にする。
[HyperTextCandy　LaravelによるToDoアプリ作成記事](https://www.hypertextcandy.com/laravel-tutorial-introduction)

## 環境
- Windows10
- Xampp
- MySQL
- PHP7
- Laravel7
- VsCode使用

## 準備
`$ laravel new ToDo`で新しくToDoプロジェクトができあがった。かんたん。
`$ php artisan serve`でロケットが出ることを確認。オッケーちゃんとできてる。

## 色々
- コントローラ作成
- マイグレーション作成
- モデルクラスの作成
- シーダーの作成
    - `$ php artisan make:seeder FoldersTableSeeder`でシーダーを作成
    - シーダーの中にテストデータを記述する。参考文献を参照。ただし、`Carbon::now()`はLaravel7では最初からパッケージ化されているので`now()`でいける。
    - `$ php artisan db:seed --class=FoldersTableSeeder`でテストデータをテーブルに入れる。「successfully」がでればオッケー。
- タスクを選択しているかしていないか
    - viewのaタグに三項演算子を用いてactiveを付与する。`{{ $current_folder_id === $folder->id ? 'active' : '' }}`
- tinkerの利用
    - `$ php artisan tinker`すると、コマンドラインからアプリの機能を見ることができる。例えば`>>> $folder = \App\Folder::find(1);`すると、Folderテーブルからid=1を拾ってきて表示してくれる。

### アクセサ
これまでの学習ではよくわかっていなくてスルー気味だったので、ここで確認。
モデルクラス内で、get[HogeHoge]Attributeを定義すると、[モデル名]->[hoge_hoge]でアクセスできるとのこと。

viewで条件分岐してたけど、modelのなかに組み込むというのもありだよね。

### FormRequestクラスの作成
フォーム入力時には、バリデーションが必要ですよね。ちゃんと学びましょう。
`$ php artisan make:request CreateFolder`
`app/Http/Requests` フォルダに `CreateFolder.php`が作られる。
このCreateFolderにバリデーションルールを記述する。
その後、
Controllerでメソッドの引数で渡すRequestをCreateFolderクラスに変更する。FormRequestクラスは、Requestクラスと互換性あり。
つまり、
`public function index(Request $request)`の部分を、`public function index(CreateFolder $request)`とすることで、FormRequestクラスである、「CreateFolder」を使ってバリデーションしたあとにフォームを$requestで受け付けることができる。

### バリデーション違反のときのメッセージ
バリデーション違反の場合のメッセージは、`resources/lang/en/vallidation.php`の中に、連想配列で記述されている。
それを日本語にするには、jaディレクトリを作って、上のファイルをそのままコピーして、該当する部分を変えていく。楽したいなら、誰かが作ってくださったものを利用するのが良いかも。

共通のバリデーションメッセージはここにあるが、別個に作る場合は、FormRequestクラスの中に、messages()メソッドを作ってreturnしてやるといい。

### 編集画面のTips
oldメソッドの第一引数に、inputのname属性を指定、第二引数にはデフォルト値を指定する。そうすると、編集画面時には、もうすでに入力値があればそれを出力してくれる。
SNMPでプリンタの総印刷ページ数を取得

#はじめに
aloha !
さて、今回はプリンタの総印刷枚数を、SNMP（Simple Network Management Protocol）プロトコルで取得してみます。
どれだけ酷使しているのかみたい時に使えるかも。そろそろ故障するんじゃないかとか。

#環境
・EPSONプリンタ（EP-881ANを使いました）
・docker image（ubuntu）

※私の場合は、Jetson Nanoにdockerを入れて使ってます。

#手順
##snmpwalkを導入します。

```
# apt install snmp
```

##プリンタのIPアドレスを調べます。
nmapコマンドを使って、プリンタのIPアドレスを調べます。

```
# nmap -sS -p631 [NETWORK]/[SUBNET MASK] -open
```

詳しくは、<a href="https://qiita.com/ko-p/items/6819e06acf30bc238379">こちらの記事</a>を見てください。

##snmpwalkコマンドを使います。

総印刷ページ数を示すSNMPのプロパティはこれの様です。
``1.3.6.1.2.1.43.10.2.1.4.1```

```
# snmpwalk -v1 -c public [PRINTER_IP_ADDR] 1.3.6.1.2.1.43.10.2.1.4.1
```

##結果

```
SNMPv2-SMI::mib-2.43.10.2.1.4.1.1 = Counter32: 1287
```

#まとめ
SNMPを使って、プリンタの総印刷ページ数が1,287枚だったということがわかりました。
このプリンタは、まだまだ働いてくれそうです。

Mahalo
AIX の lspath chpath コマンド備忘

このページは、lspath, chpath コマンドの備忘録です。

# lspath コマンドとは

lspath コマンドは、AIX の MPIO (Multi path I/O) デバイスのパス情報を表示するコマンドです。

[lspath コマンド](https://www.ibm.com/support/knowledgecenter/ja/ssw_aix_72/l_commands/lspath.html)を見ても分からないところもあるので、メモに残します。

lspath コマンドには大きく２種類の使い方があります。
２種類に分かれる理由は、コマンドが参照する ODM の違いによるものと思われます。


### マルチパスに関連するODM -1- (CuPath)
ODM CuPath には、以下の値が格納されています。

| 属性名           |       意味        |   　値(例)         |
|:-----------------|:------------------|:------------------:|
| name             |            パス名 |     　hdisk0       |
| parent           |        親デバイス |       fscsi0       |
| connection       |  ww_name,lun_id   | XXXXXXXXXXXXXXXb,Y000000000000|
| path_id          |          パス番号 |          0         |
| path_status      |    パスの利用可否 |       Available    |


以下のコマンドで出力可能
` # lspath -l hdisk0 -F "name  parent path_id connection path_status status" 
hdisk0  fscsi0 0 XXXXXXXXXXXXXXXb,Y000000000000 Available Enabled 
hdisk0  fscsi0 1 XXXXXXXXXXXXXXXa,Y000000000000 Available Enabled
hdisk0  fscsi1 2 XXXXXXXXXXXXXXXa,Y000000000000 Available Enabled
hdisk0  fscsi1 3 XXXXXXXXXXXXXXXb,Y000000000000 Available Enabled`

-F オプションを使用して、表示できる属性は、CuPath ODM に書かれている情報のみ
chpath では、変更できない項目


### マルチパスに関連する ODM -2- (CuPathAt)
ODM CuPathAt には、以下の値が格納されています。

| 属性名           |       意味        |   　値(例)         |
|:-----------------|:------------------|:------------------:|
| name             |       disk名      |       hdisk0       |
| path_id          |       パス番号    |          0         |
| node_name        |       ノード名    |  0xXXXXXXXXXXXXXXXb|
| scsi_id          |       SCSI ID     |       0x30100      |
| priority※       |       優先順位    |         1...255    |

※ priorityは、default の 1 が設定されている場合、ODM のエントリーは存在せず、PdPathAt の default 値が使用される。これらの属性のうち、**priority** 属性のみがchpath コマンドで変更可能。

以下のコマンドで出力可能
オプションの条件は、
1. -l disk名 + -i パス番号
2. -l disk名 + -w connection情報
のいずれかのオプションが必要である。

`# lspath -l hdisk0 -w XXXXXXXXXXXXXXXb,Y000000000000 -E`
scsi_id   0x30100            SCSI ID      False
node_name 0xXXXXXXXXX200a4cb FC Node Name False
priority  1                  Priority     **True**

`# lspath -l hdisk0 -i 0 -A -E`
scsi_id   0x30100            SCSI ID      False
node_name 0xXXXXXXXXX200a4cb FC Node Name False
priority  1                  Priority     **True**

**True** となっているものだけが、後で説明する chpath コマンドにて変更可能。


# chpath コマンドとは
chpath コマンドは、「パスの操作状況をマルチパス入出力 (MPIO) 可能デバイスに変更するか、またはパスに関連付けられている属性を MPIO 可能デバイスに変更」するコマンドである。

変更対象は、
1. パスの属性値
2. パスの操作状況
の２つである。

## パスの属性値の変更方法
1.のパスの属性値は、lspath で紹介した CuPathAt 上の属性である。
変更可能な属性値は、実質 priority のみである。
priority を変更することで複数あるパスに対して、優先順位をつけることが出来る。

実行例

`# chpath -l hdisk0 -w XXXXXXXXXXXXXXXb,Y000000000000 -a priority=5`
path Changed

`# chpath -l hdisk0 -i 0 -a priority=5`
path Changed

## パスの操作状況の変更
2.のパスのステータスは、
  - enabled から disable 
  - disable から enable
に変更可能。


実行例

`# chpath -l hdisk0 -s enable -i 0 `
paths Changed

`# chpath -l hdisk0 -s disable -w XXXXXXXXXXXXXXXb,Y000000000000`
paths Changed
Google Functions: Node.jsで重要度付きのロギング

前回、[Google Functions: console.infoやconsole.errorなどとログビューアの「重大度」の関係性](https://qiita.com/suin/items/d5d5d7199b62eed63bde)という記事を投稿しました。そこでは`console.error`や`console.info`などのConsole APIでは、GCP上のログの重要度(severity)は、`DEFAULT`か`ERROR`の二択になるということを説明しました。

GCP上の重要度はこの2つしか無いわけではなく、以下の9つのレベルがあります。

<img width="858" alt="LogEntry_ _ _Cloud_Logging_ _ _Google_Cloud.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/889/a147734a-ef20-5118-0bbc-01f301c7e3fa.png">

この投稿では、Google Cloudのロギングクライアントライブラリを使って、Cloud Functionsでも重要度を指定したロギングをする方法を説明します。

## この投稿で学ぶこと

* Google Cloud Function & Node.jsで@google-cloud/loggingを使って重要度をつけたログを記録する方法
* そして、その面倒くささ。
* `console.log`と@google-cloud/loggingで記録されるログ内容の違い。

## ロギングクライアントライブラリをインストールする

まず必要となるロギングクライアントライブラリをインストールします。

```
yarn add @google-cloud/logging
```

## ライブラリをCloud Functionsに組み込む

次にこのロギングライブラリをCloud Functionsの実装に組み込みます。

下のコードが組み込んだものです。`console.log`を使ってロギングするのと打って変わって、いろいろな下準備が必要なのと、ログを記録するごとにログエントリーオブジェクトを作る必要があるのが分かります。ちょっとめんどくさそうですね。


```index.js
const { Logging } = require('@google-cloud/logging')

exports.loggingWithClient = async (req, res) => {
  // クライアントを作る
  const logging = new Logging()

  // ログ出力先を決めてロガーを作る
  const log = logging.log('my-name')

  // ログエントリーを作る
  const entry = log.entry(
    {
      resource: { type: 'global' },
      severity: 'INFO', // 重要度「INFO」を指定
    },
    'ログをクライアントで書き込むテスト',
  )

  // ログを書き込む
  await log.write(entry)
  res.send('OK')
}
```

ひとまずこれをデプロイして、

```bash
gcloud functions deploy loggingWithClient --runtime=nodejs12 --trigger-http
```

呼び出してみます:

```bash
curl https://asia-northeast1-${PROJECT}.cloudfunctions.net/loggingWithClient
```

どのようにログが記録されたか、ログビューアを開いてみます。`console.log`で記録したログは、自動的にどの関数のものか関連付けされるため、管理コンソールの「Cloud Functions」から当該関数の「ログを表示」から行く導線が使えましたが、上のコードで記録したログは関数に紐づけてロギングしていないので、「ロギング」の「ログビューア」から探しに行きます:

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/889/173543ca-d582-15ab-d4c8-1253bc066bdf.png)

この導線からだと、プロジェクトの全ログが出るので、たくさんログがある場合は「直近の3分」などで絞り込むと見つけやすいです。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/889/fc095b0c-242d-20f8-b13d-2945d60a7f03.png)

このように、`console.info`などではできなかった重要度「INFO」でロギングされているのが確認できます:

<img width="805" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/889/aa02df3f-d87e-a596-2a47-60e5f7ca4a73.png">

今回試したサンプルコードでは、ログエントリーのメタデータを色々省いたため、かなり質素な内容になっています:

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/889/553bbf6c-8257-8d51-0842-2fb25b26a212.png)

下は普通に`console.log`しただけのログエントリーですが、それと比べると情報の少なさが分かります:

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/889/8fd35497-1e1e-2307-6cd3-67f3e0bac301.png)

## まとめ

この投稿を通じて、次のことが分かったと思います。

* Google Cloud Function & Node.jsで@google-cloud/loggingを使って重要度をつけたログを記録する方法
* そして、その面倒くささ。
* `console.log`と@google-cloud/loggingで記録されるログ内容の違い。

@google-cloud/loggingはかなり低レベルなロギングができる一方、使い勝手が良くなく、どの関数で実行されたかなどは自動的に記録されないので、次回はもっと利便性の高い方法について投稿したいと思います。
Vagrantでawait_response_stateエラーが発生し、共有フォルダの同期がとれない

# Vagrantでawait_response_stateエラーが発生し、共有フォルダの同期がとれない

vagrant up/reloadしたらネットワーク関係のエラーが発生し、
VMは立ち上がりますが共有フォルダが空ディレクトリになり、利用できなくなりました。

```powershell
==> default: Configuring and enabling network interfaces...
C:/HashiCorp/Vagrant/embedded/gems/2.1.2/gems/net-scp-1.2.1/lib/net/scp.rb:398:in `await_response_state': Agent pid 1839 (RuntimeError)

# snip...
```

Vagrantfile内容

```ruby:Vagrantfile
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  
  config.vm.define "ubuntu" do |node|
    node.vm.box = "bento/ubuntu-18.04"
    node.vm.hostname = "ubuntu"
    node.vm.network "public_network", ip: "192.168.0.3", netmask: "255.255.255.0", bridge: "en1: Wi-Fi (AirPort)"
    node.vm.synced_folder "../html", "/var/www/html", :mount_options => [ "dmode=777", "fmode=777" ]
    node.vm.provider "virtualbox" do |vb|
      vb.memory = "1024"
    end
  end
end
```

## 動作環境

- Windows 10 Home(Host OS)
- vagrant == 2.1.2
- Ubuntu18.04(Guest OS)

## 原因について

**VMにSSHしたときに標準出力がある場合**は`await_response_state`エラーが発生します。

```bash
Last login: Wed Aug  5 07:48:04 2020 from 192.168.1.1
Agent pid 3480
vagrant@ubuntu:~$
```

私の場合、上記の出力のように`~/.bashrc`に`ssh-agent`の設定をしていたため、
ログイン時に`Agent pid`が出力されるため、エラーとなってしまいました。

```bash:~/.bashrc
eval `ssh-agent`
```

## 対応策

`~/.bashrc`を`ssh-agent`設定の出力を捨てることで、vagrant upでエラーがでなくなりました。
(ここでは、標準出力と標準エラー出力を出さないように設定)

```bash:~/.bashrc
eval `ssh-agent` > /dev/null 2&>1
```

## Reference

[Vagrantでawait_response_stateエラー](https://blog.freedom-man.com/vagrant-await_response_state)
[vagrant up/reload で「scp.rb:nnn:in `await_response_state' ... (RuntimeError)」エラー](http://les-r-pan.hatenablog.jp/entry/2017/09/04/105455)
C言語でグローバル変数は必ず初期化されるか

グローバル変数[^external]のxが以下のように定義されていた場合に0に初期化されるのでしょうか？

[^external]: 外部変数

```
int x;

int main(void)
{
    /* 略 */
}
```

# 規格によると「0に初期化される」

「JIS X 3010:2003 プログラム言語Ｃ(2003).」 のp.95に以下の記載があります。

![スクリーンショット 2020-08-05 10.32.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113168/bcf33d66-9588-8018-3868-fa8670e5a48c.png)

「b) そのオブジェクトの型が算術型の場合，(正又は符号無しの)0 に初期化する。」とあります。これによるとグローバル変数xは初期値0をもつようになります。実際、多くの汎用計算機ではプログラムを実行するたびにリロードされるので、グローバル変数xは初期値0をもつようになります。

# 組込みシステムでは

組込みシステムでは、グローバル変数の初期化には注意が必要です。通常、グローバル変数が割り当てられるメモリはプログラムがロードされるときに初期化されます[^bss]。プログラムがロードされないとグローバル変数は必ずしも「意図した」初期値をもちません。[1, 9.3.5節, pp.255-256]によると、多くの組込みシステムでは、実行ごとにプログラムはリロードされません。

> But in many embedded systems, the program is not necessarily reloaded for each run.

したがって、グローバル変数xは必ずしも初期値0をもつと仮定できません。

[^bss]: 一般にbssセクションに割り当てられるメモリはこのような初期化が行われます。

ではどうするのが良い実践なのでしょうか？ main関数がある場合は、main関数の本体において宣言のならびの直後にグローバル変数の初期値を代入する文を記述するのがより安全でしょう。

```
int x;

int main(void)
{
    x = 0;
    /* 略 */
}
```


# 参考文献

[1] Edward A. Lee and Sanjit A. Seshia, Introduction to Embedded Systems, A Cyber-Physical Systems Approach, Second Edition, MIT Press, ISBN 978-0-262-53381-2, 2017. https://ptolemy.berkeley.edu/books/leeseshia/
あなたも知らない間に三項演算子を使っている？！

### プログラマーじゃなくても無意識に使っている人多そう

使っているプログラミング言語によって事情は違えど、「わかりにくい」「読みづらい」などの理由で「三項演算子」を嫌っているプログラマーって数多くいると思う。

例えば「ここのif分岐を三項演算子に書き換えてみよう」とか、そんな煩わしいコト、
「考えた事なーい！」って人も多いのではないだろうか？

そもそも「自分は使わないから書式すら覚えてない」なんて人、
Excelでセルに関数を埋め込むとき、

```
=IF(C3>=80, "合格", "不合格")
```

ここに出てくる2つの「,」の1つ目を「?」、2つ目を「:」で置き換えてみよう。
なんだ、コレのことだったのか！

```sample.js
const score = 95;
console.log(score >= 80 ? "合格" : "不合格");
```

もし間違いとかあったらご指摘いただければ幸いです。
MAMPでLaravelのルートの設定をどこにするか

Laravelのルートを最初はLaravelで作成したアプリ名のディレクトリにしていました。一番上のディレクトリ。

そこに設定していると、LaravelmのRouteでURLを設定してもNOT FOUNDになってパニック。

実は`public`にドキュメントルートを設定しないといけないよう。

`Desktop/blog/public`という感じ。

`The requested URL /blog/1 was not found on this server.`
のようなエラーが出てきたら確認してみよう！
【UFT】ユーティリティまとめ　～TestArgs編～

テスト自動化ツールである、UFT(Unified Functional Testing)

今回は TestArgs Objectについて、
公式リファレンスを参考にしながら使い方などをまとめたいと思います。

※公式リファレンスは英語のみです。日本語記事がないので、作成をしてみました。

# TestArgsオブジェクト

アクションに設定したパラメータ名を指定して、
入力・出力パラメータの値を取得・設定することができます。

```VB:TestArgs
'構文
TestArgs(parameter名)

'例文
print TestArgs("Test")

```

## パラメータの設定方法
1.UFTを起動する
2.任意のアクションを開く
3.パラメータを追加したいアクションをクリック
4.メニューバーにある[ 表示 ] > [ プロパティ ]を選択
5.UI上にプロパティ画面が表示されるので、ペンのようなマークのアイコンを選択
6.[ 追加 ]を押下し、入力パラメータを作成
7.パラメータ名と設定値を設定する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288745/d82acdd1-bcf3-7ab5-17f3-aa8f0634fb3c.png)

※１アクションに対して入力パラメータは10まで設定が可能

### コード例

入力パラメータに[Browser]を作成し、下記から使用するブラウザ名称をパラメータ値に入力する
・IE
・Edge
・Chrome
・Firefox


```VB:入力パラメータで起動するWebブラウザを選択する

Select Case TestArgs("Browser")
	Case "IE"
	    Set ie = CreateObject("InternetExplorer.Application")
    	ie.Navigate "http://www.google.co.jp/"
    	ie.Visible = True
		wait 5 '表示されるまで待機.待機方法は変更してください。
    	
	Case "Edge"
		CreateObject("Shell.Application").ShellExecute "microsoft-edge:http://www.google.co.jp/"
		wait 5 '表示されるまで待機.待機方法は変更してください。
		
	Case "Chrome"
		Set objCR = CreateObject("WSCript.shell")
		objCR.run ("""C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"" http://www.google.co.jp/")
		wait 5 '表示されるまで待機.待機方法は変更してください。
		
	Case "FireFox"
		Set objCR = CreateObject("WSCript.shell")
		objCR.run ("""C:\Program Files (x86)\Mozilla Firefox\firefox.exe"" http://www.google.co.jp/")
		wait 5 '表示されるまで待機.待機方法は変更してください。
End Select

```



*********************** 
今回は"TestArgs"についてだけ紹介させていただきました。
この他にもパラメータを制御するメソッドやオブジェクトはあります。

それらについては別の記事にまとめさせていただきます。

# 参考・参照
・UFT One Object Model Reference（公式ページ）
https://admhelp.microfocus.com/uft/en/15.0-15.0.1/UFT_Help/Subsystems/OMRHelp/Content/OV_Supp_Util/Utility_ReservedObj.htm?tocpath=Object%20Model%20Reference%20for%20GUI%20Testing%7CUtility%20Objects%7C_____0
【Python】ワンライナーFFT（高速フーリエ変換）などという狂気

使うNumpy関数+定数

```python
from numpy import tile, interp, linspace, exp, r_, pi
```

#DFT（遅い）

```python
def dft(x):return exp(-2j * pi * r_[:len(x)] / len(x))**r_[[r_[:len(x)]]].T @ x
```


#FFT（2の累乗要素限定）

```python
def fft(x):return tile(fft(x[::2]), 2) + (r_[[[1],[-1]]] * (exp(-2j * pi * r_[:len(x) // 2] / len(x)) * fft(x[1::2]))).ravel() if len(x) > 1 else x
```

#FFT（要素数制限なし、長い）

```python
def fft(x):return interp(linspace(0, 1 << (len(f'{len(x) - 1:b}')), len(x)), r_[:1 << (len(f'{len(x) - 1:b}'))], fft(r_[x, [0] * ((1 << (len(f'{len(x) - 1:b}'))) - len(x))])) if ('1' in f'{len(x):b}' [1:]) else tile(fft(x[::2]), 2) + (r_[[[1], [-1]]] * (exp(-2j * pi * r_[:len(x) // 2] / len(x)) * fft(x[1::2]))).ravel() if len(x) > 1 else x
```

#動作確認

```python
from numpy import sin, fft, random
import matplotlib.pyplot as plt
```
###変換する波形
周波数、振幅がランダムな5つの$sin$波の合成、$2048(=2^{11})$要素

```python
n = 1 << 11
x = linspace(0, 2 * pi, n)
y = 0

for w in n / 2 * random.rand(5):
    y += random.rand() * sin(w * x)

plt.plot(x, y, lw = .3)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501281/eb119712-c6d3-3f2d-d342-61533a7bfc1c.png)

### Numpy.fft.fft

```python
%timeit fft.fft(y)
plt.plot(abs(fft.fft(y))**2)
```
9.01 µs ± 42.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501281/93128673-893e-2aa6-d5d2-1890fe254c10.png)

### DFT
```python
%timeit dft(y)
plt.plot(abs(dft(y))**2)
```
568 ms ± 899 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501281/d532cc93-eede-ce79-8a7e-323c650d02e0.png)

### FFT(2の累乗要素限定のほう)
```python
%timeit fft(y)
plt.plot(abs(fft(y))**2)
```
51.2 ms ± 76.9 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501281/73755664-e8e1-ba4c-d139-d8b4f33f4a41.png)

### FFT（長いほう）
```python
%timeit fft(y)
plt.plot(abs(fft(y))**2)
```
54.1 ms ± 159 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501281/95b7126c-20df-689c-305c-c45bf1a8d422.png)

#まとめ
NumpyのFFT早すぎィ！
出力は一致してますが、FFTではただのDFTの約10倍高速化出来ていることが確認できます。
始点と終点をクリックして画像を黒塗りにする方法

http://pic2change.qcweb.jp/
というサイトをデプロイしたのですが閉めてしまうので記念に記事を書いておきます。
仕組みは簡単。画像をJSで読み込み矩形の目隠しをする、サイトです。
どうせJSなのでコードを見ようとすれば見えるので共有しておきます。

<img width="894" alt="スクリーンショット 2020-08-05 16.29.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54774/073a6311-41d0-fe8f-9dfa-5b50b4489964.png">





```javascript
document.getElementById('file').addEventListener('change', function (e){
var file = e.target.files[0];
// ファイルのブラウザ上でのURLを取得する
var blobUrl = window.URL.createObjectURL(file);
var img = new Image();
var flg = true;
var flg2 = false;
var first_x = null;
var first_y = null;
var last_x = null;
var last_y = null;
var base1 = null;
var data = null;
img.src = blobUrl;
var w =null;
var h = null;

var canvas = document.getElementById('screen_image');
if (canvas && canvas.getContext) {
  var ctx = canvas.getContext('2d');
  img.onload = function () {
    w = img.width;
    h = img.height;
    canvas.width = w;
    canvas.height = h;
    ctx.drawImage(img, 0, 0);
    canvas.addEventListener("click", first_click, false);
    canvas.addEventListener("click", fill_rect, false);

  };
//始点と終点の情報を取得、メソッドを分割しても良かった気がする
  var first_click = function (e) {
    var rect = e.target.getBoundingClientRect();
    if (flg) {
      first_x = e.clientX - rect.left;
      first_y = e.clientY - rect.top;
      flg = false;
    } else {
      last_x = e.clientX - rect.left;
      last_y = e.clientY - rect.top;
      flg = true;
      flg2 = true;
    }
  };
  document.getElementById("btn1").addEventListener("click", function(){
    var link = document.getElementById('download');
    link.href = canvas.toDataURL();
    link.download = 'download.png';
    link.click();
  });
//黒塗りする
  var fill_rect = function () {
    if (flg2 === true) {
      if (first_x > last_x) {
        [first_x, last_x] = [last_x, first_x];
      }
      if (first_y > last_y) {
        [first_y, last_y] = [last_y, first_y];
      }
      ctx.fillStyle = "rgb(0, 0, 0)";
      ctx.fillRect(first_x, first_y, last_x - first_x, last_y - first_y);
      flg2 = false;
      data = canvas.toDataURL('image/png');
      document.getElementById('screen_image').value = data;
    }
  };
}
```
CircleCIのOrbのバージョンの違いによる設定パラメータの有無について調べたときの小メモ

# 背景

Orbの知識ではなく、つまづいた時にソースやアップデートの情報をどう調べたかという初心者の記録です。

こちらのドキュメント([Language Guide: Ruby - CircleCI](https://circleci.com/docs/2.0/language-ruby/))を参考に手元でCircleCIを動かして勉強していた際、下記のような簡単な設定で実行したところ、エラーログが吐かれました。

~~~yml:./circleci/config.yml(修正前)
version: 2.1
orbs:
  ruby: circleci/ruby@1.1.0 
  node: circleci/node@3.0.1 # 参考にしたサンプルではバージョンが"@2"

jobs:
  build:
    docker:
      - image: cimg/ruby:2.5-node
    steps:
      - checkout
      - ruby/install-deps
      - node/install-packages: 
          pkg-manager: yarn
          cache-key: "yarn.lock" # 後述 ： これでエラーが出る

workflows:
  version: 2
  build_and_test:
    jobs:
      - build

~~~

~~~:ログ
#!/bin/sh -eo pipefail
# Error calling workflow: 'build_and_test'
# Error calling job: 'build'
# Error calling command: 'node/install-packages'
# Unexpected argument(s): cache-key
# 
# -------
# Warning: This configuration was auto-generated to show you the message above.
# Don't rerun this job. Rerunning will have no effect.
false

Exited with code exit status 1
CircleCI received exit code 1
~~~

``cache-key``は知らないよということなので、``circleci/node@3.0.1``かそれ以前においてパラメータが廃止されていることを確認してみることにしました。

## 調べた流れ

Orbのコマンドについては、GitHubリポジトリの``./src/commands``にそれぞれを定義したYAMLファイルが置かれています。

今回の場合は``install-packages``コマンドが対象なので、該当するのは以下のページです。
https://github.com/CircleCI-Public/node-orb/blob/master/src/commands/install-packages.yml

[このファイルのCommit履歴](https://github.com/CircleCI-Public/node-orb/commits/master/src/commands/install-packages.yml)(本投稿記述時で5つだけ)を新しいものから遡れば、``cache-key``が廃止された際の更新が見られるだろうと思ったのですが、最新のものがまさにそれでした。

[Advanced conditionals \[semver:major\] (#38) · CircleCI-Public/node-orb@c0c6a55](https://github.com/CircleCI-Public/node-orb/commit/c0c6a551f81038991e03e01c8ca2a8e5e7baa535#diff-9632dce4bb08d040a1f12f4ec6a7c0b5)
コメントで
> cache-key parameter removed. Now decided automatically.

など、設定の自動化に伴い必要がなくなったパラメータ``cache-key``が削除された旨が説明されています。
([定義が削除されている箇所](https://github.com/CircleCI-Public/node-orb/commit/c0c6a551f81038991e03e01c8ca2a8e5e7baa535#diff-9632dce4bb08d040a1f12f4ec6a7c0b5L27))

また、上記の変更では``<< parameters.pkg-manager >>``が``npm``か``yarn``であるかによって条件分岐が設けられ、``save_cache``のキーの一部``<<parameters.cache-key>>``が、それぞれ``package-lock.json``あるいは``yarn.lock``に置き換わっています。
説明にある「自動的に決定される」の該当部分を確認することもできました。


## 設定ファイルの修正

前項より、``pkg-manager``が``npm``か``yarn``によってキャッシュが自動で設定されることが分かったので、冒頭の設定ファイルを修正してみます。

~~~yml:./circleci/config.yml(修正後)
version: 2.1
orbs:
  ruby: circleci/ruby@1.1.0 
  node: circleci/node@3.0.1 # 参考にしたサンプルではバージョンが"@2"

jobs:
  build:
    docker:
      - image: cimg/ruby:2.5-node
    steps:
      - checkout
      - ruby/install-deps
      - node/install-packages: 
          pkg-manager: yarn
          # cache-key: "yarn.lock" <--この記述を削除

workflows:
  version: 2
  build_and_test:
    jobs:
      - build

~~~

変更をpushして実行すると、ビルドエラーは起きませんでした。

# あとがき

些細な調べ事についてでしたが、パッケージやライブラリを利用する時など、参考にするチュートリアルなどの記述と異なるバージョンのものを使用したい時などに、設定パラメータの定義が変更されていて振り回されるような場面は今後遭遇しやすいのではないかと考えたので、記録に残してみました。
トレジャーデータでDownloadしたCSVをExcelで文字化けせずに開く方法


トレジャーデータで抽出したデータをCSVダウンロードしてExcelで開くと日本語の文字化けがしてしまいます。
これを簡単に防ぐ方法のメモ。

## 手順

・データをSELECTしてDownloadボタンを押す

| ![TD→Download→Excelで文字化けしない方法①.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242038/b8bb27ef-478b-c1cb-e9e0-f18181315dd6.png)
|:--|

・Encodingで初期値が**UTF-8**になっているのを、**SJIS**に変更する

| ![TD→Download→Excelで文字化けしない方法②.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242038/a3bed8a4-228a-0da6-6943-d5de2604e592.png)
|:--|


これでダウンロードしたCSVをExcelで開いても文字化けしません。

この方法を知るまでは、トレジャーデーター上でデータをコピーし、値貼り付けして文字化け回避するなどで対処してたのですが、その苦労から解放されました。
Railsでの複数カラムの追加・削除とまとめて行う方法

自分用です！

複数のカラム追加していきます。

まずはマイグレーションファイルを作ります。


```ruby:ターミナル
rails g migration add_columns_to_users
```


複数のカラムを追加する際、特定のカラムを意識するわけでもない場合は「add_columns」などとしておけばいいでしょう。

```
class AddColumnsToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :last_name, :string
    add_column :users, :first_name, :string
  end
end
```

rails db:migrateをすれば追加される。