OmniAICreator/Qiita-1.07M huggingface dataset:
Jenkinsのスレーブのストレージ容量を監視する


#Jenkinsのスレーブのストレージ容量を監視する

Jenkinsには各情報等を取得等できるapiが用意されています。
http://[your-jenkins-path]/[jenkin_function]/api/[xml,json]
なのでそれを利用すれば簡易的にも監視機能を作ることができます。

例えばこんなスクリプトをJenkinsに組み込んで適宜Slackに投げたりすれば
スレーブのストレージがパンクしておじさんが息をしていないの！！ということを未然に防ぐことができます。

もっとちゃんとしたツールを利用するのも手ですが, 簡単にであればこういうスクリプトでもいいですし。
またJenkins特有の何か(例えばジョブが今どうなっているか)などについてはこういう方法がおそらくいいと思います。

```powershell
$req = Invoke-WebRequest -Uri http://[your-jenkins-path]/computer/api/xml

$xml = [xml]($req.Content)

$computerSet = $xml.computerSet.computer

$temporarySizeList = @{}
$sizeList = @{}

foreach ( $computer in $computerSet )
{
    $name = $computer.displayName
    $arch = $computer.monitorData["hudson.node_monitors.ArchitectureMonitor"].InnerText
    
    $isLinux = "$arch" -like "*Linux*"
    Write-Host "$arch"
    
    $tempSize = $computer.monitorData["hudson.node_monitors.TemporarySpaceMonitor"].size
    $gByte = $tempSize / 1024.0 / 1024 / 1024
    $temporarySizeList[$name] = $gByte
    Write-Host "$name : $gByte" 
    
    #閾値（各自調整したりしてください）
    $threshold = if($isLinux){5}else{50}
    if($gByte -lt $threshold)
    {
        #閾値超えていた場合
    }


    $size = $computer.monitorData["hudson.node_monitors.DiskSpaceMonitor"].size
    $gByte = $size / 1024.0 / 1024 / 1024
    $sizeList[$name] = $gByte
    
    Write-Host "$name(temp) : $gByte"

    #閾値
    $threshold = if($isLinux){5}else{100}
    if($gByte -lt $threshold)
    {
        #閾値超えていた場合
    }
    Write-Host "-------------------------------------"
    
}


@([pscustomobject]$sizeList) | ConvertTo-Csv | Select-Object -Skip 1 | Out-File size.csv -encoding ascii
@([pscustomobject]$temporarySizeList) | ConvertTo-Csv | Select-Object -Skip 1 | Out-File temporary.csv -encoding ascii
```
Mock使用メモ

https://qiita.com/5at00001040/items/83bd7ea85d0f545ae7c3

https://keis-software.com/2015/05/04/powermockitoを使ってみるテスト/

https://qiita.com/morinco/items/a41cc7685be75a2f6e08

https://futurismo.biz/archives/6815

http://javatechnology.net/java/mock-thenreturn-number/


等を参考にMockを使用しようとしているが
一番↑の
targetField.set(null, 1000); 
が読み取れず……

TargetClass
Field
ってjavaの標準クラスなのかな？？？

あと　　　　　　　↓が本当にあっているのかな？
targetField.set(null, 1000); 
しかないんだろ？？？
サルでも分かるHMM作成ツールHTKの入手

こんにちは，卒業論文や就活で崖っぷちのKiatです．

今回は音声認識に関する論文を書くためにHMM(Hidden Markov Model,隠れマルコフモデル)について学習したことをメモとして記録していこうと思います．

#HTKって何だ？
この記事の題名にあるHTK（【H】idden Markov Model 【T】ool【k】it）とはイギリスのケンブリッジ大学が無償で公開しているHMMに関するツールのことです．（最近だとMicrosoft Hololensが有名だからそっちと間違いそうだけど，Hololens Toolkitのことじゃないよ笑）音声の収録，認識結果の評価などHMMを用いた音声認識に関する一連の動作をC言語で作られたソフトウェアで行うことができます．
今回はその入手方法の一連の流れをメモします．

まず専用のホームページ
http://htk.eng.cam.ac.uk/
に移動します．
下のような英語サイトに飛びます．
![HTK Speech Recognition Toolkit - Google Chrome 2019_06_24 15_44_48 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306370/4f99416b-d404-1f75-e820-ef7c3c2f50ed.png)

#ユーザー登録，ダウンロード
サイトページのGetting　Start，Registarをクリックします．
![HTK Speech Recognition Toolkit - Google Chrome 2019_06_24 15_44_48 (2)_LI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306370/37bfabc4-adcb-b4f7-93d0-f2b366fa188b.jpeg)
すると，下の登録画面に飛ぶので，ハンドルネーム(_OK)，自分の名前，Eメールアドレス，団体名（学校名，企業名），住所を記入します．
![HTK Speech Recognition Toolkit - Google Chrome 2019_06_24 16_42_04 (3)_LI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306370/1f63cfcf-eff8-0af4-4d32-9be3ebc0f188.jpeg)
下にスクロールして使用許諾の確認を求められるので，Yesを押します．
![HTK Speech Recognition Toolkit - Google Chrome 2019_06_24 15_44_03 (2)_LI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306370/ff3cf083-d408-cd00-4e46-061ad7272e9e.jpeg)
下のが出てきたら登録完了ではないです．(_の文字入れちゃったのでやり直し)
![HTK Speech Recognition Toolkit - Google Chrome 2019_06_24 15_44_33 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306370/e6816c01-7f41-3029-499a-31be935b52e5.png)

うまくいくとこの画面になります．
![HTK Speech Recognition Toolkit - Google Chrome 2019_06_25 13_15_41 (2)_LI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306370/a55e8ecf-f8f5-ce97-8e23-2ac359263f2c.jpeg)

これでユーザー登録は完了です．

そして指定したアドレスにメールが届いています．
そこにパスワードが記載されているので，そのパスワードを使ってダウンロードします．

※メール等送られてこなかった場合は，もう一回ページを確認しましょう．


#参考文献
・イラストで学ぶ音声認識～荒木雅弘～
・フリーソフトでつくる音声認識システム(パターン認識・機械学習の初歩から対話システムまで)～荒木雅弘～
Makefileのファイル依存関係をGraphvizで可視化してくれるものを作った

Makefileのファイルの関係を絵に書いて理解しようとしていたのですが、手作業じゃ無理〜となったので自動化を試みました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404817/83411032-0fd0-5282-45b3-d4c805b5cc2f.png)

`LANG=C make -p`によって出力されたMakefileのデータ構造をJSON形式へ変換してから、DOT形式で出力しています。
オリジナルのファイルがグレー、生成されるファイル(ターゲット)は白で表されています。

こちらの記事: [Makefileの依存関係の可視化](https://qiita.com/kshramt/items/dace8875d9686475f6cd) を元にソースコードを改変させていただきました。

# ソースコード

こちら→ https://github.com/souring001/makefile-visualizer

# 環境

GNU Make (3.81)
Python (3.5.2)
Graphviz (2.40.1)

# 実行
Makefileと関連するファイルをソースコードがあるフォルダに入れて以下を実行してください。

```python
LANG=C make -p | python3 make_p_to_json.py | python3 json_to_dot.py | dot -Tpdf >| workflow.pdf
```

# License

GPL version 3.
初心者のためのアルゴリズム〜バブルソート編〜

アルゴリズムで最初に習うであろうバブルソートについて、簡単に言葉で説明していきます。
また、Pythonでコードを書いて実行してみました。

# バブルソートとは
バブルソートとは、隣り合う二つの数値を比較していき、大小関係に応じて交換を行って整列していくアルゴリズムです。

# 手順
リストを昇順に整列されるための手順です。

>
1. 先頭の数値aと、それと隣り合う数値bを比較する。
2. a>bであった場合、aとbの数値を入れ替える。a<bであった場合、入れ替えずそのまま。
3. この作業をリストの終端まで繰り返す。
4. 終端の数値はリスト内の最大値となっているので、この数値をソート済みにする。
5. 手順1~4を繰り返す。
6. 全ての数値がソート済みとなれば完了。


手順を見れば明らかですが、実行時間がかかるアルゴリズムのひとつです。
しかし、単純明快なアルゴリズムかつ並列処理との相性がいいので、割と使用されることもあるようです。

# コード
言葉だけで説明されてもなかなか分かりづらいと思うので、自分の理解を深めるためにも実際にコードを書いてみました。

```BubbleSort.py
import random

def bubbleSort(lst):
    for i in range(len(lst)):
        #比較作業を最後まで繰り返し、最大値をソート済みとします。（手順３,4,5）
        for j in reversed(range(i+1,len(lst))):
            #数値aとbを比較します。(手順１)
            if lst[j-1] > lst[j]:
                #数値a>bの場合、aとbの値を入れ替えます。(手順２)
                lst[j-1],lst[j] = lst[j],lst[j-1]
    return lst

if __name__ == "__main__":
    #20個の数値をランダムに配列する
    lst = list(range(20))
    lst_ran = random.sample(lst,len(lst))

    print("リスト整列前：")
    print(lst_ran)

    #ここでバブルソート実行
    algo = bubbleSort(lst_ran)
    print("リスト整列後：")
    print(algo)
```

ランダムに0から19の配列を作成し、バブルソートで整列させました。
こちらを実行すると、このようになりました。

リスト整列前：
[11, 8, 19, 10, 9, 12, 4, 15, 2, 6, 17, 5, 14, 7, 0, 3, 13, 16, 18, 1]
リスト整列後：
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

しっかりと整列されていますね。


# まとめ
今回は、アルゴリズムのバブルソートを説明しました。
アルゴリズムにはまだまだたくさんの方法があるので、また次の機会にコード付きで紹介していきたいと思っています。
docker-composeでentrypointを指定するとDockerfileのCMDが無視されるよというお話

タイトルの通りなんですけども、ちょっとハマったので書き残しておこうかなと思いました。
ってか、ドキュメントにガッツリ書いてあるんですけどね。読めよって話ですよね。。

https://docs.docker.com/compose/compose-file/#entrypoint

> Note: Setting entrypoint both overrides any default entrypoint set on the service’s image with the ENTRYPOINT Dockerfile instruction, and clears out any default command on the image - meaning that if there’s a CMD instruction in the Dockerfile, it is ignored.

google翻訳さん

> 注：entrypointを設定すると、ENTRYPOINT Dockerfile命令を使用してサービスのイメージに設定されているデフォルトのエントリポイントが上書きされ、イメージのデフォルトコマンドが消去されます。DockerfileにCMD命令がある場合は無視されます。

## ハマったケース

DBの起動を待ってからWebサーバーを起動しようと思って [dockerize](https://github.com/jwilder/dockerize) を使ってたのですけども、このdockerizeのコマンドを `docker-compose.yml の entrypoint` に書いてた訳です。
コンテナに直截入って叩けば起動するし、docker-compose.ymlのcommandに書いても起動するし、なんなんだよーって思って調べたら公式の注意書きに書いてありました。。

## まとめ

何か壁にぶち当たったら、まずは公式ドキュメント読みましょう。。
シンプルな再帰下降のサンプル（３）変数と代入

変数と代入
===

a-zの変数と、代入=に対応。それから式の区切りを ',' にしました。

まず a=a という式について考えてみましょう。
左側のaは参照、右側は値です。

代入処理をするなら、代入したい変数にアクセスするための情報が必要です。この情報を持っているのが一般に lvalue（left-value）といわれているものです。

右側のaは値でも参照でもいいのですが、

``` a=3+a*2 ```

のような場合、式の途中のa*2を計算する時に欲しいのはaの値です。そして値を使ってしまったら変数にアクセスする情報は必要ありません。ですから = の右側に変数名が出てきた場合は、変数名から変数の持っている値に変換します。

パースの最中はどっちかわからないので、とりあえずスタックには変数にアクセスするための情報（この場合配列var[]のインデックス）を保存します。
今回はpop()を変更して値に変換するようにしました。変数にアクセスする情報が欲しい時は ref_pop() を使います。

代入もオペレータと同じように expr=expr の形をしているはずなので、add()やmul()と同じく = の右と左をそれぞれ処理しています。
let()の中が add()→while(1)add() ではなく add()→let() なのは a=b=0 のような式に対応するためです。
+ や * は左から順に処理をしていけばよかったのですが、= は右から順に処理をしなくてはいけません。つまり演算子の表によくある「結合規則が左←右」ということです。ですから、右側を先に処理するために再帰になっています。

結合規則が左←右というのは、 a=b=0 のような場合 a=(b=0) のように右を先に評価するという意味です。
逆に結合規則が左→右なら 例えば a-b-1 のような場合ですが (a-b)-1 の順で評価します。

演算子の優先順位が関数の呼び出し関係で処理されているのは最初に解説しました。結合規則もどこかにデータを持っているのではなく、 ***結合規則は呼び出す関数が1つ下なのか自分自身なのかで表現*** します。

今までもそうでしたが、今回も最適化とエラー処理はしていません。

```t3.c
/*
再帰下降サンプル
cc -o t3 t3.c
*/

#include <stdio.h>

char* text="b=a=5,a=a+(3+4)*5,b*7" ;
char* ptr ;
char token ;

int var[26]={0} ;	//	変数 a-z

//	計算結果を積むスタック
int stack[32] ;
int sp=0 ;
int t_stack[32] ;


int promote(int ref){
	return var[ref] ;
}

void push(int value, int tag){
	stack[sp]=value ;
	t_stack[sp]=tag ;
	sp++ ;
}

int pop(void){
	sp-- ;
	if(t_stack[sp]==1){
		//	スタックトップを数値に変換
		return(promote(stack[sp])) ;
	}
	return(stack[sp]) ;
}

int ref_pop(void){
	sp-- ;
	return(stack[sp]) ;
}


void get_token(void){
	while(*ptr==' ' || *ptr=='\t') ptr++ ;

	token=*ptr ;

	if(*ptr!=0){
		ptr++ ;
	}
}



void expr(void);

void factor(void){
	get_token() ;
	if(token>='0' && token<='9'){
		push(token-'0', 0) ;
		printf("number(%d)\n", token-'0') ;
		get_token() ;
	}
	else if(token>='a' && token<='z'){
		push(token-'a', 1) ;
		printf("var(%c)\n", token) ;
		get_token() ;
	}
	else if(token=='('){
		expr() ;
		get_token() ;
	}
	else if(token==','){
		token=0 ;
	}
}

//	掛け算
void mul(void){
	factor() ;
	while(1){
		if(token=='*'){
			factor() ;
			printf("mul\n") ;
			push(pop() * pop(), 0) ;
		}
		else if(token=='/'){
			factor() ;
			printf("div\n") ;
			int top=pop() ;
			push(pop() / top, 0) ;
		}
		else{
			break ;
		}
	}
}

//	足し算と引き算
void add(void){
	mul() ;
	while(1){
		if(token=='+'){
			mul() ;
			printf("plus\n") ;
			push(pop() + pop(), 0) ;
		}
		else if(token=='-'){
			mul() ;
			printf("minus\n") ;
			int top=pop() ;
			push(pop() - top, 0) ;
		}
		else{
			break ;
		}
	}
}

//	代入
void let(void){
	add() ;
	if(token=='='){
		int top, ref ;
		let() ;
		top=pop() ;
		ref=ref_pop() ;
		var[ref]=top ;

		printf("let(%c)=(%d)\n", ref+'a', top) ;
		push(top, 0) ;
	}
}

//	式の評価
void expr(void){
	let() ;
}

int main(void){
	ptr=text ;
	while(*ptr!=0){
		expr() ;
		printf("answer=%d\n", pop()) ;
	}

	return 0 ;
}
```

---
代入は、このパーサは 式 としています。式なので値を返します。
これを代入文（Assignment statement）としている言語もあります。
ここから先は各言語の定義が強く出てくるところなので、このパーサはこれで一段落とします。
Raspbian 2019-06-20 Release-note 翻訳

(追記: 7/13にRaspbian Buster 2019-07-10がリリースされています)
https://qiita.com/utaani/items/2d4e641eba3d2e46d9f3

http://downloads.raspberrypi.org/raspbian/release_notes.txt

Debian Busterベースに変更
Raspberry Pi 4 ハードウェアサポート
FKMS OpenGL デスクトップグラフィックスドライバとxcompmgrウインドウマネージャ。(Raspberry Pi 4使用の時)
FKMSドライバを使うスクリーン設定アプリを追加
Raspberry Pi設定アプリにRaspberry Pi 4 ビデオ出力オプションを追加
GTK と OpenboxPiX でflat UI テーマを使うように
デフォルトでタスクバーにCPUアクティビティゲージプラグインが表示されないように
CPU温度ゲージプラグインが追加（デフォルトでは表示されません）
USBイジェクタとBluetoothタスクバーが、使えない時には非表示に
Chromium web browser Version 74.0.3729.157を導入
Flash player Version 32.0.0.207を導入
IDLE Python IDE削除
Busterと互換性がない間、一時的にWolfram Mathematica を削除。
Recommended Softwareからパッケージサイズ表示を削除
Appearance Settingsを2画面設定時に独立してできるように変更
Oracle Java 7 / 8 は OpenJDK 11に置き換え
いくつかの細かいバグ修正
オンボード5GHz Wifiはrfkillでデフォルトでブロックされる。
以下の設定でブロックが外れる：
　設定ウィザードで国選択する
　ネットワーク設定アプレットかRaspberry Pi 設定ツールでWiFi国設定する
　raspi-configでWiFi国設定する
  wpa_supplicant.confをbootパーティションで設定する
　'rfkill unblock wifi'を実行する
Bootパーティションのサイズが256Mに
Linux kernel 4.19.50
Raspberry Pi ファームウェア 88ca9081f5e51cdedd16d5dbc85ed12a25123201
Gitでのcommitエラーメモ

# Gitでcommitエラーに遭遇
WindowsでGitを用いてコミットしようとした際にエラーに遭遇。

**実行文**

```
>git commit -m 'first commit'
```

**エラー文**

```
error: pathspec 'commit'' did not match any file(s) known to git
```
add時に存在したファイルが、commit時に無くなっていたときに出るエラー
# 環境
- Windows10
- Git for Windows

```>git version git version 2.19.1.windows.1
```

# 解決方法
Gitでは、commitメッセージはシングルクオーテーションではなくダブルクオーテーションを用いて書く。

**x**　```>git commit -m 'first commit' ```
**o**　```>git commit -m "first commit" ```
３日目　フロント基礎の基礎 ~utilityでの打ち消し・上書きについて等~

#フロント業務でつまずいたポイント
　・FLOCSSにおけるutilityの上書き、打ち消しのしすぎ　←今日のメイン
　・Ceckboxのチェック部分の位置を変えたい
　・フォームのtextareaのrowsのレスポンシブ対応の仕方

一個ずつまとめていきます。

##FLOCSSにおけるutilityの上書きのしすぎ
現在FLOCSSやBEMでのCSS設計の練習をしているのですが、スマホ版で付けていたutilityをレスポンシブ対応する際、PC版で上書きしなければいけない、という場面に陥ってしまいました。:robot:
もっと複雑な指定でしたが、簡略化した形で説明します。

###ケースその①　スマホ版とPC版がまるっと変わる。
スマホでもPCでも３箇所同じ指定内容。ただし値が
**スマホ ≠ PC**の場合。

```HTML
<!-- HTML -->
<p class="box01 u-large-text"></p>
<p class="box02 u-large-text"></p>
<p class="box03 u-large-text"></p>
<!-- わかりやすくまとめているが、実際はバラバラの場所に書かれた三つ -->
```

```CSS
<!-- CSS -->
.u-large-text {
   font-size: 18px;   
}

@media all and (min-width:769px){
   .u-large-text {
      font-size: 35px;
   }
}
```
この場合はマルッと上書きなので、使って良い。
便利な書き方だと思いました。

###ケースその②　スマホ版≠PC版　かつPC版の一部が異なる
ちょっとややこしい。

```HTML
<!-- HTML -->
<div class="box01 u-back"></div>
<div class="box02 u-back"></div>  <!-- ここののPC版だけ背景を付けたくない -->
```

```CSS
/*CSS*/
.u-back {
   background: #000;       /*こちらがスマホ版*/
}

@media all and (min-width:769px){
   .u-back: pink;      /*PC版の指定*/

   .box02.u-back {     /*無理やり詳細度をあげて指定*/
      background: none;
   }
}
```

これは保守的にもあまり良くないしわかりづらい、、ということで、次の改善策をとりました。

**解決策①：特殊部分だけutilityを別個にする**

```HTML
<!-- HTML -->
<div class="box01 u-back"></div>
<div class="box02 u-back-spOnly"></div>
```

```CSS
/*CSS*/
.u-back {
   background: #000;
}
.u-back-spOnly {
   background: #000;   /*スマホ版では色を付けて、、*/
}

@media all and (min-width:769px){
   .u-back-spOnly {
      background: none   /*分けたので、他のu-backに影響を与えない。無理な指定も不要。*/
   }
}
```
こうすることで、無理な打ち消しをしないで済みます。

**解決策②：そもそもユーティリティを付けず特殊部分の指定をエレメントにつける**
無理やりutilityをつける必要は何もありませんでした。

```HTML
<!-- HTML -->
<div class="box01 u-back"></div>
<div class="box02"></div>
```

```CSS
/*CSS*/
.box {
   height: 100px;
   width: 100px;
   background: #000;
}

@media all and (min-width:769px){
   .box {
      background: pink;   /*そもそもね*/
}
```


##checboxのチェック部分の位置を変えたい。
かなり簡単に解決しました。

```HTML
<!--HTML-->
<label for="agree" class="contact-agree">
   <input type="checkbox" id="agree" value="check">プライバシーポリシーに同意する
</label>
```

```CSS
/*CSS*/
#agree {
   margin-right: 30px;
}
```
直接インプットに指定しちゃっていいみたいです。

##フォームのtextareaのrowsのレスポンシブ対応の仕方##
スマホ版ではちょっと短め、PC版ではちょっと長めにするために、
それぞれ二つtextareaを準備して、スマホ版では片っぽ、PC版ではもう片っぽ、、と指定していました。
↓今までのコード例です。

```HTML
<!-- HTML -->
<textarea class="smartPhone" id="mainContact" name="mainContact" rows="5" cols="40"></textarea>
<textarea class="pc" id="mainContact" name="mainContact" rows="30" cols="40"></textarea>
/rowをいじっただけ*/
```

```CSS
/*CSS*/
.pc {
   display: none;     /*スマホ版ではこちらを隠す*/
}

@media all and (min-width:769px){
   .smartPhone {
      display: none;    /*pc版ではこちらを隠す*/
   }
}
```
もっとスマートなやり方がありました。
なんとrowsの属性値に関係なく、heightをいじれば普通に伸びるみたいです。盲点！

```HTML
<!-- HTML -->
<textarea class="area" id="mainContact" name="mainContact" rows="5" cols="40"></textarea>
/一個でOK*/
```

```CSS
/*CSS*/

@media all and (min-width:769px){
   .area {
      height: 600px;  /*高さ分行が打てます*/
   }
}
```

今日は以上です！
webpack4に乗り換えたら、IE11が動かなくなった話

# 去年、webpack4が出ましたね

https://github.com/webpack/webpack/releases/tag/v4.0.0

新しいもの好きな僕は、まんまとwebpack４に乗り換えました

# 僕のフロントの開発環境

- webpack4でjsのみをバンドル
- scssやejs等はgulpでコンパイル
- 画像等もgulpで最適化
- ライブラリは主にjQueryを使用

それぞれのバージョンは下記

``` json
"webpack": "^4.20.2",
"webpack-cli": "^3.1.1",
"gulp": "^3.9.1",
"babel-core": "^6.26.0",

```
jQuery v3.3.1

## あれIE動かねぇ

オワタ＼(^^)／

# やったこと

まずpolyfillを追加

``` js
require('babel-polyfill');
```

→変わらず構文エラー

productionモードでコンパイル


``` shell
npx webpack --production
```
→変わらず構文エラー


オワタ＼(^^)／


#原因

原因は、多分jQueryの関数の中でes6を書いたことっぽいです。

例１）
ページロード時にメインのクラスを読み込む

```js
import UIController from './UI/Controller.es6';
$(window).on('load',e=>{
 new UIController();
})
```

例２）
あるクラスの要素に繰り返し処理をする

```js
$('.hoge').each((i,e)=>{
 $(e).text(i);
})
```


これらがうまくコンパイルされてねぇ。。。。


# 対策

僕がとった対策は下記です。

- webpack4で一旦productionモードでコンパイル
- gulpのgulp-babelでさらに、コンパイルされたjsコードをさらにコンパイル

→動いた！！

gulpの設定

```js

const gulp = require('gulp');
const babel = require('gulp-babel');
var config = require('../config').js;
const uglify = require('gulp-uglify');
var saveLicense = require('uglify-save-license');
gulp.task('babel', () =>{
  return  gulp.src(config.src)
        .pipe(babel({
            presets: ['@babel/env']
        }))
        .pipe(uglify({output: {comments: saveLicense}}))
        .pipe(gulp.dest(config.dest))
});
```

package.json

```json
"scripts": {
 "release": "npm-run-all -s release:*",
 "release:webpack":"webpack --production",
 "release:gulp":"gulp babel"
}
```

同じように詰まってる人の解決になれば幸いです＾＾
Chromeデベロッパーツール（検証モード）

HTML/CSSの概要をある程度覚えてきて、
サイトの模写をしてみようとしたとき、フォントのサイズやカラー空白欄の広さなど
見た目で分からないときはChromeデベロッパーツールを使う。

確認したいところで右クリック→検証
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420053/f8632494-41fd-782c-6eb2-dbe35cd3de20.png)


ショートカットキーでは、【Ctrl+Shift+I（MacではCommand + Option + I）】もしくは【F12】キーで起動できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420053/c4b92e98-600b-52e8-86c2-637c79214c09.png)


その場でいじって変化を確認できたりもする。
エクセルでJAVAアプリを超簡単生成！「ワンダーロボ」Gridに関する処理

###ステップ1.Gridに検索結果を設定する方法
###ステップ2.Grid改ページ前後の処理
###ステップ3.Grid行に入力不可、可能処理方法

---
###ステップ1.Gridに検索結果を設定する方法
最初に、Gridに検索結果を設定する方法を説明します。例として、「商品入庫」画面で説明します。
<img width="1128" alt="99.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184885/742c4bfd-6e08-f5aa-0f35-5026e7ce7ee1.png">
「検索」ボタンを押すと、以下のデータ操作が処理されグリッドに設定されます。
#####※「1.データ操作1：テーブル「在庫」によるフィールド「注文書NO、注文書明細NO、工事管理番号、在庫NO、仕入先、商品名称、出入庫時間、数量、単価、出入庫状態、代金金額、出荷NO、商品型番、在庫数量、商品NO」を取得、条件はフィールド「注文書NO」が画面項目「注文書No」,フィールド「商品名称」が画面項目「部品名」,フィールド「在庫NO」が画面項目「在庫NO」,フィールド「工事管理番号」が画面項目「社内工事番号」。」

<img width="1128" alt="97.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184885/023c9071-0c4a-bdff-e354-c2f5b0b0986a.png">

#####・設計書ファイルをインポートして確認
SaaSForceの開発環境にログインし、設計書ファイルをインポートします。そして、利用画面で反映されているか確認します。

**ユーザー利用画面表示例↓**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184885/a55b9dfb-5fca-392b-5da0-124aa2130f0d.png)


---
###ステップ2.Grid改ページ前後処理の指定方法
次に、Grid改ページ前後処理の設定方法を説明します。Grid改ページ設定は、グリッド設定に記載します。下の図は、「商品入庫画面」のグリッド設定です。
Grid改ページ後処理は、グリッド行のページが次ページになった場合、処理されます。改ページ後設定で状態が2の場合は、「入庫」を非表示、1の場合は「入庫」ボタンにキャンセルを設定します。

<img width="1128" alt="103.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184885/51a05ee9-e6f5-f303-8307-fde768ae5df1.png">

**ユーザー利用画面表示例↓**
<img width="793" alt="109.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184885/e819de75-4fca-8868-f5dc-9ccdc14ab6d8.png">

---
###ステップ3.Grid行に入力可能、不可処理方法
最後に、Grid行に入力不可、可能を設定する方法を説明します。例として、「部品管理画面」を使って説明します。
※図1
<img width="1128" alt="114.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184885/f166236c-7e0d-69ac-0a2c-7d0141e0cc64.png">
条件によって、Grid「B16」の行を入力可能または入力不可にします。
※図2
<img width="1128" alt="110.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184885/8f0e4747-994a-14df-02ca-baf5d274ce9b.png">
※図3
<img width="1128" alt="111.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184885/55e89068-3ac7-79ef-5cf7-e0fdd00a5ab9.png">

**ユーザー利用画面表示例↓**
「確定」ボタンをクリックすると、該当行が入力不可になります。「取消」ボタンをクリックすると、該当行がまた入力可能になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184885/26ff2c66-915a-cd6f-411a-d9a23a6dbc3e.png)
Mac Shortcut Key

Macを仕事で使うようになるため、ショートカットキーをまとめてみることにした。
個人の都合で、ControlとOption、Commandそれぞれのキーにわけてまとめた。

# Command Key ⌘
(親指で操作)
## Basic
|Short cut|Operation|
|:-------:|:-------:|
|⌘ + c|コピー|
|⌘ + v|貼り付け|
|⌘ + x|切り取り|
|⌘ + z|戻る|
|⌘ + a|全て選択|
|⌘ + f|検索|

## Application
|Short cut|Operation|
|:-------:|:-------:|
|⌘ + n|新しいフォルダを開く|
|⌘ + o|ファイルを開く|
|⌘ + q|アプリを終了する|
|⌘ + w|ウィンドウを終了する|

## Finder
|Short cut|Operation|
|:-------:|:-------:|
|⌘ + ⇧ + n|新しいフォルダを作成|
|⌘ + d|ファイルを複製|
|⌘ + i|ファイルの詳細|
|⌘ + delete|ファイルの削除|
|⌘ + ⇧ + delete|ゴミ箱の中を空にする|
|⌘ + Space|Spotlight|

## Screenshot
|Short cut|Operation|
|:-------:|:-------:|
|⌘ + ⇧ + 3|全画面|
|⌘ + ⇧ + 4|選択範囲|
|⌘ + ⇧ + 4 + Space|ウィンドウ単位|

### Application
|Short cut|Operation|
|:-------:|:-------:|
|⌘ + q|アプリケーションを閉じる|
|⌘ + ⌥ + esc|アプリケーションの強制終了|
|⌘ + h|ウィンドウを隠す|
|⌘ + w|ウィンドウを閉じる|
|⌘ + ⌥ + w|ウィンドウを閉じる|

### Browser
|Short cut|Operation|
|:-------:|:-------:|
|⌘ + i|アドレスバー|
|⌘ + r|表示ページのリロード|
|⌘ + n|新規ウィンドウでタブを開く|
|⌘ + ⇧ + t|閉じたタブを再度開く|
|⌘ + ←|１つ前のページに戻る|
|⌘ + ↑|ページ一番上に移動|
|⌘ + ↓|ページ一番下に移動|
|⌘ + [|進む|
|⌘ + ]|戻る|
|Space|下スクロール|
|⇧ + Space|上スクロール|

### Terminal
|Short cut|Operation|
|:-------:|:-------:|
|⌘ + d|横分割|
|⌘ + ⇧ + d|縦分割|
|⌘ + [|時計回り移動|
|⌘ + ]|反時計回り移動|

# Control Key ⌃
### Text
|Short cut|Operation|
|:-------:|:-------:|
|⌃ + d|右側の文字削除|
|⌃ + k|右側の文字行削除|
|⌃ + a|行先頭にカーソル移動|

### Application
|Short cut|Operation|
|:-------:|:-------:|
|⌃ + ↓|ウィンドウの切り替え|

### Terminal
|Short cut|Operation|
|:-------:|:-------:|
|⌃ + u|行コマンド全削除|
|⌃ + i|Clearコマンドと同じ効果|
|⌃ + r|履歴search|

# Option Key ⌥
(小指で操作)
### Text
|Short cut|Operation|
|:-------:|:-------:|
|⌥ + ↑|行頭に移動|
|⌥ + ↓|行末に移動|
|⌥ + ←|カーソルを一単語分戻す|
|⌥ + →|カーソルを一単語分おくる|

# Emacs Command
メモ帳やTerminal等、Emacsコマンドを使用できる場合のショートカットキー
多用するものだけ記載

|Short cut|Operation|
|:-------:|:-------:|
|⌃ + f|右|
|⌃ + b|左|
|⌃ + p|上|
|⌃ + n|下|
|⌃ + e|行末|
|⌃ + a|行頭|
|⌃ + h|削除|
|⌃ + d|後ろ削除|
|⌃ + k|後ろ全削除|
何もしていないのにRails serverがすっっっごい重い

# 結論

```
bundle exec rails log:clear
```
# 事象
Railsのプロジェクトで特にプログラム自体に対する変更の有無に関わらず、
保存した状態でページをリロードしたりAPI叩いたりするとやたら時間がかかるようになってしまいました。
それこそ体感10秒くらい。

これじゃあお仕事になんないよとRails serverのログを見つめているとあることに気づきます。

```
↳ vendor/bundle/ruby/2.5.0/gems/activerecord-5.2.0/lib/active_record/log_subscriber.rb:98

（ここでログの流れが数秒間止まる）
Started GET 〜
```

もしやと思いdevelopment.logを確認してみると、いつの間にやら800MB超の大ボリュームに。
冒頭のコマンドを実行したところ止まることもなく快適な開発環境が戻ってきました。
Tableau Ideas for Mapping

#Tableau Mapに関する機能拡張や改善要望アイデアのまとめ
よいアイデアはぜひVote-Up下さいね！随時追加更新します
キーワード"map"でのアイデア検索結果は[こちら](https://community.tableau.com/search.jspa?q=map&place=%2Fplaces%2F1029&depth=ALL&type=idea)から

## Active
- [Independent map layers](https://community.tableau.com/ideas/6418) 
- [Dashboard - Zoom all maps showing](https://community.tableau.com/ideas/6270)
- [Map - Zoom Level Selector - Needed](https://community.tableau.com/ideas/10008)
- [Ability to support zoom level of above 16 with Tiled Map Service (WMS)](https://community.tableau.com/ideas/9329)
- [Maps - Layer multiple WMS or Internal WMS & Tableau maps](https://community.tableau.com/ideas/1294)
- [Default map center and zoom](https://community.tableau.com/ideas/6568)
- [Ability to filter for one distinct location on a map](https://community.tableau.com/ideas/2822)
- [Union Multiple Spatial Files](https://community.tableau.com/ideas/7260)

## Released 
- [Map Layers in Edit Mode on Tableau Server](https://community.tableau.com/ideas/9123) (in v2019.4)
- [Population Density Mapping](https://community.tableau.com/ideas/7878) (in v2018.3)
- [Enable dual axis with custom and generated latitude/longitude] (https://community.tableau.com/ideas/6354) (in v2018.1)
- [Add a Map Scale](https://community.tableau.com/ideas/1719) (in v10.2)

## 参考: 新規アイデアのポスト方法
- [Tableau であんなこと出来たらいいな – Ideas サイトから生まれる新機能](https://www.tableau.com/ja-jp/about/blog/2018/7/your-ideas-to-new-tableau-features-91966)
【Swift】TabbarItem と NavigationItem の名前を連動させる

`TabbarItem`と`NavigationItem`それぞれの名前を連動させたいと思って調べたら簡単にできるみたいです。

`NavigationController`の下に`TabbarItem`があります。
なので`NavigationController?.NavigationItem.Title`を変更するとタブの名称も連動して変わるようです。

連動して変えたくない場合は`TabbarItem.title`を直接変えるとそれぞれ設定できます。
Laravel-Mix4でもIEとか古いブラウザになるべく楽に対応したい

# 背景

- Laravel-Mix4でBabelの設定に躓いた
- 設定ファイルもなるべく書かずに楽をしたい

## 結論

`webpack.mix.js`でbabelメソッドを使う

## コード

```js
// webpack.mix.js
let mix = require('laravel-mix');

mix
  .js('resources/js/*.js', 'assets/js/app.js')
  .babel('assets/js/app.js', 'assets/js/app.js');
```

ただしコンパイルが重いので`mix.inProduction()`を使用して本番環境のコンパイルのみBabelを噛ませるようにすれば、開発もスムーズになりそう。

## 参考

[Laravel公式ドキュメント](https://laravel.com/docs/5.5/mix)
[Convert ES6 to ES2015 using babel and laravel-mix](https://stackoverflow.com/questions/52352701/convert-es6-to-es2015-using-babel-and-laravel-mix)
1分でセッション、メール認証ありのユーザー付きサーバーを立てる

# 冗談と思ったっか？
本当です。
今回は[phauxth](https://github.com/riverrun/phauxth)という、ElixirのPhoenixをベースにしたライブラリーを紹介しようと思います。
紹介と言っても簡単にサーバーを立てる以外何もしないですが。

**それにコード一行も書きません。**
それほど強いです。

## 事前準備
Elixir, Erlang, Phoenixをインストールすること。
自分のバージョンを参考にしていただければと。
erlang 21.3
elixir 1.7.4
phoenix 1.4.6

# スタート
**今回の戦いは1分しかないので急ごう。**
まず前述のライブラリーのインストーラーをインストールする。
直接インストールする方法もあるが、Erlangのバージョンが異なるせいでうまくいかない可能性があるので、自分でビルドしてからarchiveにインストールするのがオススメ。

```bash
git clone git@github.com:riverrun/phauxth_installer.git
```

ビルドとインストール。

```bash
cd phauxth_installer/phauxth_new
MIX_ENV=prod mix build
cd ../archives
mix archive.install phauxth_new-2.2.0.ez
```

新しいPhoenixのプロジェクトを作る。

```
mix phx.new phauxth_qitta
cd phauxth_qitta
mix ecto.setup
```

最後、ユーザーを作ろう。

```
mix phauxth.new --confirm
```

# は？終わり？
DependenciesをGetしてサーバーを立ててみよう。

```bash
mix deps.get
iex -S mix phx.server
```

で http://localhost:4000 を開いたら。
<img width="805" alt="スクリーンショット 2019-06-24 15.46.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443144/f3dc56cc-fd93-563d-617f-d9be6fde24e3.png">

new userをクリック、サインアップ。
<img width="805" alt="スクリーンショット 2019-06-24 15.47.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443144/3d776036-61e1-702c-b933-5e8eddfd67a1.png">

サーバーのコマンドラインを開いたらこのようなメッセージがあるはず、サンプルドメインをlocalhost:4000に変えてアクセスしたらメール認証完了。

```bash
%Bamboo.Email{assigns: %{}, attachments: [], bcc: [], cc: [], from: {nil, "admin@example.com"}, headers: %{}, html_body: nil, private: %{}, subject: "Confirm your account", text_body: "Confirm your email here http://www.example.com/confirm?key=SFMyNTY.g3QAAAACZAAEZGF0YXQAAAABbQAAAAVlbWFpbG0AAAAQdGVzdGFjY0B0ZXN0LmNvbWQABnNpZ25lZG4GAPtLPohrAQ.nVfZdoPOn7i1TtTJrgbqdDQzUEhx45Jor8ddYb9C8dw", to: [nil: "testacc@test.com"]}
```

<img width="805" alt="スクリーンショット 2019-06-24 15.51.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443144/b710d106-8437-a57f-8f60-e9fa1a19786a.png">

ログインしてみる。

<img width="805" alt="スクリーンショット 2019-06-24 15.51.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/443144/e18d234f-247d-a034-7d53-02f0dae42f37.png">

# 終わりに
メール認証に、Phauxthは[Bamboo](https://github.com/thoughtbot/bamboo)というライブラリーを取り入れています。
最初はローカル用のアダプターをしてるので、簡単に置き換えればそのまま認証機能を利用できます。
自分はAWS SES用のアダプターに変えてみたら30分もかかりませんでした。

一応Authenticationについて、Elixirでは[guardian](https://github.com/ueberauth/guardian)というライブラリーが一番有名らしいが、自分はまだ使ったことないので、比較もできません。
もし両方を使った方がいらっしゃればぜひご意見を聞きたいです。
Raspberry Pi 4 発表

# この記事は？
説明するまでもなく、タイトルのとおりですｗ

# Raspberry Pi 4
![Buy a Raspberry Pi 4 Model B – Raspberry Pi 2019-6-24 15-37-28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169018/aa6ff06f-7fff-17cb-d198-3628bd947a2c.png)
https://www.raspberrypi.org/products/raspberry-pi-4-model-b/
発表 & 販売開始されたようです。
正式名称は Raspberry Pi 4 Model B 。
なお、日本での販売はまだです。技適が取れるまで数ヶ月かかるでしょうから、もうしばらく待ちましょう。

## 4B と、3B / 3B+ との違いを確認してみる
違いをざっくりまとめてみます。

| | 3B       | 3B+ | 4B    |
|:-------|:-----------------|:------------------|:------------------|
| CPU    | BCM2837(Cortex-A53) 4コア 1.2GHz | BCM2837B0(Cortex-A53) 4コア 1.4GHz | BCM2711(Cortex-**A72**) 4コア **1.5GHz** |
| メモリ | 1GB LPDDR2 | 1GB LPDDR2 | 1GB/**2GB/4GB** **LPDDR4** |
| 有線LAN | 100Mbps | 1G(実効300M)bps | **1Gbps** |
| 無線LAN | 2.4GHz | 2.4/5GHz | 2.4/5GHz |
| bluetooth| 4.0? | 4.2 | **5.0** |
| USB | USB2.0 x 4 | USB2.0 x 4 | USB2.0 x 2 / **USB3.0 x 2** |
| HDMI | フルサイズHDMI x 1 | フルサイズHDMI x 1 | **micro HDMI x 2** |
| 電源 | 5V 2.5A microUSB | 5V 2.5A microUSB | **5V 3.0A USB-C** |

## 個人的な感想
- メモリ4GBはすげー嬉しい。
- 電源が USB-C になったのは嬉しいけど、相変わらず大容量の電源を要求するのはつらい。
- CPUが速くなったのはどうでも良いけど、A53 から A72 になって省電力化しているはず。
  - でも電源はデカイのを要求するのね。
- HDMI 2つ付ける必要あったのだろうか？
  - ラズパイ4ではガッツリ画像処理をやることができるようになるのか？
  - 個人的にはHDMIよりコンソールのポートが欲しい。
- さすがに発熱量が心配
  - [ヒートシンク](https://shop.pimoroni.com/products/raspberry-pi-4-heatsink) デカすぎね？

## OSも同時にメジャーバージョンアップ
Raspberry Pi用OSである Raspbian も、4B の発表と同時にメジャーバージョンアップされています。
詳細は（ざっくりですが）別記事にしております。
→ [Raspbian Buster リリース](https://qiita.com/nara256/items/ef03c163d6e77b147800)

# とりあえずポチッとな
イギリスの [PIMORONI](https://shop.pimoroni.com/) から1個注文しておきましたｗ
経験上、1週間程度で届くはず。
技適の関係で無線は使えないけど、とりあえず使い勝手は分かるでしょう。
AWS KMSで暗号化されたS3オブジェクトの期限付きURL(PreSignedURL)を、Nodejsで発行する

こういう状態のオブジェクトを想定。
<img width="894" alt="スクリーンショット 2019-06-24 15.52.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23936/920bbd30-ebe3-bb9d-3cbb-15b4fd9d8d43.png">

## 一般的な書き方

```typescript
import { S3 } from 'aws-sdk'

const client = new S3()

client.getSignedUrl('getObject', {
  Bucket: 'BUCKET_NAME',
  Key: 'OBJECT_KEY',
  Expires: 60 * 60 * 24 * 2
}, (e, r) => {
  console.log(e)
  console.log(r)
})
```

## 結果
URLは発行されるのですが、暗号化されているオブジェクトは、HTTP403が返ってきます。
<img width="973" alt="スクリーンショット 2019-06-24 15.57.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23936/dda1e39e-2fbe-9191-2bcd-f0128823fd30.png">

## 対応
クラスを初期化する際にsignatureVersionを渡してやりましょう。

```typescript
import { S3 } from 'aws-sdk'

const client = new S3({
  signatureVersion: 's3v4'
})

client.getSignedUrl('getObject', {
  Bucket: 'BUCKET_NAME',
  Key: 'OBJECT_KEY',
  Expires: 60 * 60 * 24 * 2
}, (e, r) => {
  console.log(e)
  console.log(r)
})
```
並列処理学習３－データ競合を防ぐには

グローバルインタプリタロック（GIL）を知っているプログラマは、Pythonデータ構造を操作するプログラムについても、GILが適用されると勘違いしてしまう場合がある。
それは間違いで、GILはプログラムを保護しているわけでは無く、あくまでもプロセス毎に制御をしているだけ。

# 勘違いから起こる問題
一つのデータ構造に対して、複数のプロセスから操作を行うような処理を書いてしまうと、スレッドの切り替えが行われ、データの不整合が発生してしまい、プログラムが壊れてしまう。

# 問題の原因
Pythonインタプリタは、スレッドの実行の公平性を担保する仕組みがあり、それぞれが等しいプロセス時間を得られるようになっている。
そのため、実行中のスレッドを一時的にサスペンドして、次の処理を行うようになっている。
一見、サスペンドが起こらないような処理に見えても、発生する場合がある。

# 対策
上記のようなデータ競合を発生させないためのモジュールがある。
それが、threading.Lock。
threading.Lockを使用すると、複数プロセスからのアクセスを保護するデータの定義ができる。

プログラム内のスレッド間データ競合が発生しないようにするのは、プログラマに責任なので注意が必要。
GASで１行おきに行を挿入するスクリプト

```{js}
function insert() {
  var objSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var objSheet = objSpreadsheet.getActiveSheet();

  var i=10 // 10行目から始める
  for(i; i>0; i--){
  objSheet.insertRowAfter(i);
  }
};
```
【PHP】cron で動かす際は「ユーザー」と「ワークディレクトリ」を意識しよう

PHP を cron で動かす際に、「相対パス」を使うとなぜか上手く動かない！ 初心者あるあるだと思います。

簡単な解決法と、「そもそもなぜ動かないの？」という説明です。

--------------------------------------------------------------------------------

## 簡単な解決法

プログラムの先頭あたりに以下の 1 行を書くと、相対パスでも動くようになります。

```php
chdir(__DIR__);

//-- PHP5.3以下の環境も考慮する必要がある場合は↓をchdir()の「前」に追加します
// if (!defined('__DIR__')) {
//     define('__DIR__', dirname(__FILE__));
// }
```

もちろん、相対パスではなく、絶対パスを使っても良いです。

```php
file_get_contents('./example.txt');
```

　**↓ ↓ ↓**

```php
file_get_contents(__DIR__ . '/example.txt');
```

--------------------------------------------------------------------------------

### 補足

- [\_\_DIR\_\_](https://www.php.net/manual/ja/language.constants.predefined.php)
    - PHP ファイルがあるディレクトリ（絶対パス）

- [chdir()](https://www.php.net/manual/ja/function.chdir.php)
    - ワークディレクトリ（カレントディレクトリ）を変更する

- [ワークディレクトリ](https://www.google.co.jp/search?q=%E3%82%AB%E3%83%AC%E3%83%B3%E3%83%88%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E3%81%A8%E3%81%AF&ie=utf-8&newwindow=1)
    - PHP を動かす場所（ディレクトリ）

--------------------------------------------------------------------------------

## 調べ方

[getcwd()](https://www.php.net/manual/ja/function.getcwd.php) を使って…

```php
//-- パーミッションに注意
file_put_contents(__FILE__ . '.test.txt', getcwd());
exit;
```

1. cron から動かした場合
2. ウェブブラウザからアクセスして動かした場合

で、結果を見比べてみると良いと思います。

--------------------------------------------------------------------------------

## なぜ相対パスだと動かないのか

上記を試せば分かる通り、cron から実行すると、「ワークディレクトリが、cron を実行するユーザーのホームディレクトリになるから」です。

- [ホームディレクトリ](https://www.google.co.jp/search?q=%E3%83%9B%E3%83%BC%E3%83%A0%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E3%81%A8%E3%81%AF&ie=utf-8&newwindow=1)
    - ユーザーのデフォルトのワークディレクトリ

「相対パス」というのは、読んで字の如く、○○を『基準』として『相対的に』ファイルのパスを表現する方法です。

ですので、そもそも基準となる○○が、自分が想定している場所と異なる（PHP ファイルのある場所ではない）のであれば、動かないのは当然ですよね。

`chdir(__DIR__)` は、「ワークディレクトリを、PHP ファイルのあるディレクトリへ変更する」という意味になりますので、cron からでも、PHP ファイルを『基準』にした、相対的なパスの指定が可能となるわけです。

--------------------------------------------------------------------------------

PHP に限った話ではなく…

1. どのユーザーで実行されているのか？
2. ユーザーのホームディレクトリはどこなのか？
3. ワークディレクトリはどこなのか？

…といった事を意識しておくと、色んな事に応用が効くと思います。
SAS ViyaのCASLibを管理する

CASとはSAS Cloud Analytic Servicesの略で、CASLibはCASにアクセスするための一連の技術を指します。テーブル、アクセス制御、データを管理するためのメモリを提供します。

今回のCASLibの作成および削除の方法をPythonのコードで紹介します。

## Viyaに接続する

まず SAS Viyaへ接続します。

```py
from swat import *

cashost='localhost'
casport=5570
useremail='dev@sas.com'
userpassword='password'
casauth='~/.authinfo'
conn = CAS(cashost, casport, useremail, userpassword, caslib="casuser")
```

## CASLibの作成

以下のコードで `/research/data` に `research` という名前のCASLibを作成します。なお、デモ環境では作成できないので注意してください。

```py
conn.addcaslib(path='/research/data', 
               caslib='research', 
               description='Research Data',  
               subdirs=False, 
               session=False, 
               activeonadd=False)
```

## CASLibの確認

`caslibinfo` で既存のCASLibが一覧されます。

```py
conn.caslibinfo()
```

| Name | Type | Description | Path | Definition | Subdirs | Local | Active | Personal | Hidden | Transient |
|------|------|-------------|------|------------|---------|-------|--------|----------|--------|-----------|
| 0 | CASUSER(dev@sas.com) | PATH | Personal File System Caslib | /home/dev/casuser/ |  | 1.0 | 0.0 | 0.0 | 1.0 | 0.0 | 1.0 |
| 1 | Formats | PATH | Stores user defined formats. | /opt/sas/viya/config/data/cas/default/formats/ |  | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 2 | ModelPerformanceData | PATH | Library for Model Management performance objects. | /opt/sas/viya/config/data/cas/default/modelMon... |  | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 3 | Models | PATH | Stores models created by Visual Analytics for ... | /opt/sas/viya/config/data/cas/default/models/ |  | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 4 | Public | PATH | Shared and writeable caslib, accessible to all... | /opt/sas/viya/config/data/cas/default/public/ |  | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 5 | QASMartStore | PATH | Stores quality analytic suite mart tables. | /opt/sas/viya/config/data/cas/default/qasMartS... |  | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 6 | Samples | PATH | Stores sample data, supplied by SAS. | /opt/sas/viya/config/data/cas/default/samples/ |  | 0.0 | 0.0 | 1.0 | 0.0 |


## CASLibの切り替え

アクティブなCASLibの切り替えは `setsessopt` を使います。

```py
conn.setsessopt(caslib='Samples')
```

## CASLibの削除

CASLibの削除は `dropcaslib` を使います。

```py
conn.dropcaslib('research')
```

## まとめ

CASLibを分けることで分析対象のプロジェクトを区別したり、個人や開発環境などの区分けができます。ぜひ使い方を覚えておいてください。
フリーランス開発者が「初めてでやり方が分からないクライアント」から受託した場合のiOS証明書

# 前提
- フリーランスの開発者が、iOSの開発案件を受託しました。開発者はApple IDを取得済みです。
- クライアントは、既にApple Developer Programに参加済みのiOSアプリの配給元であり、Developer Consoleが使用できます。ただし、初めてでやり方が良く分かりません。
- 双方とも、Macが使用可能です。
- コンソールの使用方法についての情報は巷に溢れているし、UIが繁く変わるので、この記事では扱いません。

# 手順

### 概念図
![iOS 証明書.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365845/e5788682-db72-9cae-de7d-6487be18a410.png)

### 配給元と開発者の証明
1. 開発者側作業
    1. Macで、キーチェーンアクセスを開きます。
    1. 開発者のApple IDと名前で証明書要求ファイル(.certSigningRequest)を作り、自身のApple IDとともにクライアントに渡します。
1. クライアント側作業
    1. Macで、キーチェーンアクセスを開きます。
    1. クライアントのApple IDと名前で証明書要求ファイル(.certSigningRequest)を作ります。
    1. 作った証明書要求ファイルを使い、Developer Consoleで、iOS Distribution証明書を作ります。
    1. 作ったiOS Distribution証明書ファイル(.cer)をダウンロードして、キーチェーンアクセスに登録します。
    1. 登録した証明書から個人情報交換ファイル(.p12)を書き出します。
    1. 開発者から受け取った証明書要求ファイルを使い、Developer Consoleで、iOS Development証明書を作り、証明書ファイル(.cer)をダウンロードします。
        2. (開発者に証明書へのアクセス権があれば、自身で作ることができます。)
    1. 開発者から得たApple IDをApp Store Connectに登録して開発者としてのロールを与えます。
    1. 書き出した個人情報交換ファイル(.p12)と、ダウンロードしたiOS Development証明書(.cer)ファイルを開発者に渡します。
1. 開発者側作業
    1. クライアントから受け取った二つのファイルをキーチェーンアクセスに登録します。

### アプリの証明
1. 開発者側作業
    1. クライアントにテストデバイスのUDIDを伝えます。
1. クライアント側作業
    1. Developer Consoleで、アプリを登録します。
    2. 続けて、クライアントが使用するテストデバイスのUDIDと、開発者から得たUDIDを登録します。
    3. 最後に、テストに使うデバイスを指定して、アプリのProvisioning Profileを生成します。(開発者にプロファイルへのアクセス権があれば、作ったファイルを手渡す必要はありません。)
1. 開発者側作業
    1. Xcodeでアーカイブを実行する際に、適切に指定します。

#### XcodeのOrganizerでうまくいかない場合
- Signingを自動にせず手動を試してみましょう。
    - エラーしているプロビジョニングプロファイルに対して、改めて Download Profile… してみましょう。
- Xcode > Preference > Accounts を確認しましょう。
- Xcode > Product + Option > Clean Build Folder... を試してみましょう。
- Macを再起動してみましょう。(まれによくある)
- Apple側の不具合を疑ってみましょう。サポートに問い合わせを出せます。
    - 何をやってもダメなので問い合わせたら「サーバの不具合でした」ということがありました。
- 諦めて寝ましょう。
    - Appleからの返答は時間がかかります。しかし、不具合なら翌日には直っているかも知れません。

### 更新作業
- 各証明書には有効期限があり、年次更新が必要です。
    - iOS Distribution 証明書の更新
        - 実際には更新ではなく新規作成で、初回と同じ手順で作業します。
        - 期限切れの証明書は破棄します。

#### あとがき
- アプリ開発者が自分で配給する場合の情報は豊富ですが、委託側と受託側に作業を分離して双方を網羅した情報が乏しかったので記事にしてみました。
- 想定が妙に具体的ですが、特定の企業や個人とは関係ありません。(ありませんてばありません!)
【Vim】コンマ1秒でも起動を速くする為のタイマー機能

# 前置き
私の重装系vimは、プラグインは40個、vimrcは300行超えのカスタマイズを施してます。
当然、素のvimと比べると明らかに起動が遅い。
プラグインはマネージャに搭載された遅延ロードを使うことで起動の短縮を図ってます。
用意されてる分では足りなかったので、自分で色々試して更に遅延ロードをかけてます。
(参照：https://qiita.com/M4s0n/items/d251a90e4a71d67444dd)

第3世代のエディタが勢力を伸ばす昨今。
盲目にvimを愛する私は、さらなる高みを目指してvimの起動時間を短縮するべく
タイマー機能を活用し、起動を爆速にしました。

## 環境
vim8

# 下調べ
先ず、起動時のボトルネックを探りました。

```vim
Plug 'mattn/benchvimrc-vim'
```

上記プラグインを使用すると幾つかボトルネックを発見しました。

```vim
python3 from powerline.vim import setup as powerline_setup
python3 powerline_setup()
python3 del powerline_setup

set undodir=~/.vim/undo
set undofile
```

大きく分けて2つ

* vimのステータスラインに使用しているPowerline
* ファイルを閉じても、以前のundoが使えるようにする設定

# 遅延ろぉぉぉぉおおど
みんな大好き遅延ロード。
vim8から搭載されたタイマー機能を使って、vim起動後にボトルネックだった設定を非同期で読み込ませる。

```vim
function! s:lazy_load(timer)
    python3 from powerline.vim import setup as powerline_setup
    python3 powerline_setup()
    python3 del powerline_setup
    echo 'Powerline Loaded'

    set undodir=~/.vim/undo
    set undofile
endfunction

" vim起動後、100ミリ秒後にcallされる
call timer_start(100, function("s:lazy_load"))
```

関数に遅延ロードしたいものを突っ込むだけの荒業。
後は、時間を設定してタイマーをコールするだけであら不思議。
起動が爆速になりました。

# まとめ
全部が全部遅延ロード出来るわけではないですが、
遅延して問題ないものはタイマー機能を使ってロードすると、
ちょっぴり幸せになれます。

# 参考
* vimrcのベンチマークを計るプラグイン

https://github.com/mattn/benchvimrc-vim
SAS Viyaに取り込む際のデータ形式を指定する

SAS ViyaはAIプラットフォームです。その元になるデータソースとして、CSVやExcel、HTMLなどを指定できますが、さらに独自のクラス（Pythonのコード）から取り込むこともできます。今回はその手順と、データ型の指定法を紹介します。

## Viyaに接続する

まず SAS Viyaへ接続します。

```py
from swat import *

cashost='localhost'
casport=5570
useremail='dev@sas.com'
userpassword='password'
casauth='~/.authinfo'
conn = CAS(cashost, casport, useremail, userpassword, caslib="casuser")
```

さらにデータハンドリングを行うライブラリを読み込みます。

```python
from swat.cas import datamsghandlers as dmh
```

## クラス（データハンドラー）を用意する

クラスのデータハンドラーを定義します。この時、transformersを使ってデータ型を指定できます。今回は日付（birthdate）について、CASの日付型への変換を指定します。

```py
class MyDMH(dmh.CASDataMsgHandler):

    def __init__(self):
        self.data = [
            ('Alfred',  'M', 14, 69,   112.5, '1987-03-01'),
            ('Alice',   'F', 13, 56.5, 84,    '1988-06-12'),
            ('Barbara', 'F', 13, 65.3, 98,    '1988-12-13'),
            ('Carol',   'F', 14, 62.8, 102.5, '1987-04-17'),
            ('Henry',   'M', 14, 63.5, 102.5, '1987-01-30'),           
        ] 

        vars = [
            dict(name='name', label='Name', type='varchar'),
            dict(name='sex', label='Sex', type='varchar'),
            dict(name='age', label='Age', type='int32'),
            dict(name='height', label='Height', type='double'),
            dict(name='weight', label='Weight', type='double'),
            dict(name='birthdate', label='Birth Date',
                 type='date', format='DATE', formattedlength=12),
        ]

        transformers = {
            'birthdate': dmh.str2cas_date,
        }

        super(MyDMH, self).__init__(vars, transformers=transformers)

    def getrow(self, row):
        try:
            return self.data[row]
        except IndexError:
            return
```

## クラスのインスタンスを作成する

作成したクラスのインスタンスを作成します。

```python
mydmh = MyDMH()
```

## インスタンスを取り込む

作成したインスタンスをSAS Viyaに取り込みます。

```python
conn.addtable(table='myclass', caslib='casuser', replace=True, **mydmh.args.addtable)
```

## データを確認する

取り込んだデータを確認します。

```python
conn.columninfo(table=dict(name='myclass', caslib='casuser'))
```

**§ ColumnInfo**

| Column | Label | ID | Type | RawLength | FormattedLength | Format | NFL | NFD |
|--------|-------|----|------|-----------|-----------------|--------|-----|------|
| 0 | name | Name | 1 | varchar | 7 | 7 |  | 0 | 0 |
| 1 | sex | Sex | 2 | varchar | 1 | 1 |  | 0 | 0 |
| 2 | age | Age | 3 | int32 | 4 | 12 |  | 0 | 0 |
| 3 | height | Height | 4 | double | 8 | 12 |  | 0 | 0 |
| 4 | weight | Weight | 5 | double | 8 | 12 |  | 0 | 0 |
| 5 | birthdate | Birth Date | 6 | date | 4 | 12 | DATE | 0 | 0 |

```py
conn.fetch(table=dict(name='myclass', caslib='casuser'), sastypes=False)
```

**§ Fetch**

| name | sex | age | height | weight | birthdate |
|------|------|------|------|------|------|
| 0 | Alfred | M | 14 | 69.0 | 112.5 | 1987-03-01 |
| 1 | Alice | F | 13 | 56.5 | 84.0 | 1988-06-12 |
| 2 | Barbara | F | 13 | 65.3 | 98.0 | 1988-12-13 |
| 3 | Carol | F | 14 | 62.8 | 102.5 | 1987-04-17 |
| 4 | Henry | M | 14 | 63.5 | 102.5 | 1987-01-30 |

## まとめ

データ型を指定することで絞り込みや並び替えが正しく行えるようになります。今回のテクニックを覚えておくことで、データ分析がしやすくなるでしょう。
Tableau Mapに必要なインターネットアクセス要件

#Tableauにおけるバックグランドマップ参照に必要な要件

インターネット アクセス要件
https://help.tableau.com/current/desktopdeploy/ja-jp/desktop_deploy_proxy.htm
https://help.tableau.com/v2019.1/desktopdeploy/ja-jp/desktop_deploy_proxy.htm (v2019.1: Mapbox以前)

インターネットとの通信
https://help.tableau.com/current/server/ja-jp/plan_network.htm
https://help.tableau.com/v2019.1/server/ja-jp/plan_network.htm (v2019.1: Mapbox以前)

> ※ Tableau 2019.2以降にバージョンアップした後の接続トラブルが増えています：mapsconfig.tableau.com, api.mapbox.com

#タイル画像の表示確認
マイアミとハバナ (青い水) マップにアクセスすることで接続をテストできます
https://onlinehelp.tableau.com/current/desktopdeploy/ja-jp/desktop_deploy_proxy.htm#%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%8D%E3%83%83%E3%83%88-%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%AE%E3%83%86%E3%82%B9%E3%83%88
https://maps.tableausoftware.com/tile/d/mode=named%7Cfrom=tableau1_2_base/mode=named%7Cfrom=tableau1_2_admin0_borders/mode=named%7Cfrom=tableau1_2_place_labels/ol/6/17/27.png?apikey=ttab56540ba691a909b0f7d2af0f6fe7
[Python]浮動小数点数(float)の表現誤差を直すメソッド

こんな風に、floatだと微妙に値がずれる事があります。

```python
print(0.3)
# => 0.3

print(0.1 * 3)
# => 0.30000000000000004 
```

そこで、表現誤差を取り除くメソッドを作ってみました。
（小数点以下15桁になるように四捨五入しています。）

```python
from decimal import Decimal, ROUND_HALF_UP

def remove_representation_error_in_float(x):
    x = Decimal(str(x)).quantize(Decimal('0.000000000000001'), rounding=ROUND_HALF_UP)
    x = float(str(x))
    return x
```

参考：[Pythonで小数・整数を四捨五入するroundとDecimal.quantize | note.nkmk.me](https://note.nkmk.me/python-round-decimal-quantize/)
SAS ViyaにSQLite3からデータを取り込む

SAS ViyaはAIプラットフォームです。その元になるデータソースとして、CSVやExcel、HTMLなどを指定できますが、さらにSQLite3をそのまま取り込むこともできます。今回はその手順を紹介します。

## Viyaに接続する

まず SAS Viyaへ接続します。

```py
from swat import *

cashost='localhost'
casport=5570
useremail='dev@sas.com'
userpassword='password'
casauth='~/.authinfo'
conn = CAS(cashost, casport, useremail, userpassword, caslib="casuser")
```

## SQLite3を準備する

SQLite3のデータベースを用意します。これはCSVから読み込む形で作ります。まずはライブラリのインポートから。

```py
import csv
import sqlite3
```

次にテーブルを作ります。

```python
sqlc = sqlite3.connect('iris.db')
cur = sqlc.cursor()
cur.execute('''CREATE TABLE iris (
                 sepal_length REAL,
                 sepal_width REAL,
                 petal_length REAL,
                 petal_width REAL,
                 species CHAR(10));
            ''')
```

そしてCSVファイルの内容をSQLite3のデータベースに取り込みます。データは[pandas/iris.csv](https://github.com/pandas-dev/pandas/blob/master/pandas/tests/data/iris.csv)を使います。この処理はSAS ViyaではなくPythonのSQLite3ライブラリの機能です。

```python
with open('iris.csv', 'r') as iris:
  data = csv.DictReader(iris)
  rows = [ (x['SepalLength'],
             x['SepalWidth'],
             x['PetalLength'],
             x['PetalWidth'],
             x['Name']) for x in data]
cur.executemany('''INSERT INTO iris (sepal_length, 
                                     sepal_width,
                                     petal_length,
                                     petal_width,
                                     species)
              VALUES (?, ?, ?, ?, ?);''', rows)
sqlc.commit()
```

## SQLite3を取り込み

いよいよデータベースを取り込みます。ライブラリを読み込みます。

```py
from swat.cas import datamsghandlers as dmh
dbdmh = dmh.DBAPI(sqlite3, cur, nrecs=10)
```

取り込みます。

```py
conn.addtable(table='iris_db', caslib='casuser',  **dbdmh.args.addtable)
```

## データを確認する

ちゃんと取り込めたかデータを確認します。

```py
conn.columninfo(table=dict(name='iris_db', caslib='casuser'))
```

| Column | ID | Type | RawLength | FormattedLength | NFL | NFD |
|--------|----|------|-----------|-----------------|-----|-----|
| 0 | sepal_length | 1 | double | 8 | 12 | 0 | 0 |
| 1 | sepal_width | 2 | double | 8 | 12 | 0 | 0 |
| 2 | petal_length | 3 | double | 8 | 12 | 0 | 0 |
| 3 | petal_width | 4 | double | 8 | 12 | 0 | 0 |
| 4 | species | 5 | varchar | 10 | 10 | 0 | 0 |

```py
conn.fetch(table=dict(name='iris_db', caslib='casuser'), to=5)
```

| sepal_length | sepal_width | petal_length | petal_width | species |
|--------------|--------------|--------------|--------------|--------------|
| 0 | 5.1 | 3.5 | 1.4 | 0.2 | setosa
| 1 | 4.9 | 3.0 | 1.4 | 0.2 | setosa
| 2 | 4.7 | 3.2 | 1.3 | 0.2 | setosa
| 3 | 4.6 | 3.1 | 1.5 | 0.2 | setosa
| 4 | 5.0 | 3.6 | 1.4 | 0.2 | setosa

## まとめ

データベースがそのままデータソースとして使えて、さらにSAS Viyaの強力なデータ管理機能が使えるようになります。ぜひお試しください。
【GAS】Googleフォームで回答が来た時Slackに通知を送るようにしてみた

## はじめに
GAS初心者の方はチュートリアル記事を作りましたので、良かったら読んでみてください。
[GASで「Hello,World!」を出力するまでをまとめてみた。](https://qiita.com/ta9star/items/fae274689334f8836a80)

##目的
* スプレッドシートが更新されるたびにSlackに通知がくるようにしていたが、新規入力時に項目セルごとに直書きしていたため、通知がうるさくなってしまった。<br>そこで、新規入力用のフォームを作成し、回答をスプレッドシートにまとめて、フォーム側で通知処理をするようにしたかった。
* Qiitaになんか投稿してみたかった。

##実装
通知を送りたいチャンネルのWebHook URLを取得します。
手順は下記記事を参照にしました。
[SlackのWebhook URL取得手順](https://qiita.com/vmmhypervisor/items/18c99624a84df8b31008)

対象のGoogleフォームを開き、その他→スクリプトエディタからGASを書いていきます。

```javascript
FormApp.getActiveForm();

function myFunction(e) {
var webhook = "Webhook URL";
  
  var body = "Googleフォームの「" + e.source.getTitle()　+ "」に回答が送信されました。\n\n";
  var itemResponses = e.response.getItemResponses();
  body += "```";
  itemResponses.forEach(function(itemResponse){
    body += '【' + itemResponse.getItem().getTitle() + '】\n'
    body += itemResponse.getResponse() + '\n'
  });
  body += "```";
  
  var message = body;
  
  var jsonData =
 {
    "username" : "insertAlert", // ボットの名前
    "text" : message       //実際に送る内容
 };
 var payload = JSON.stringify(jsonData);
 var options =
 {
   "method" : "post",
   "contentType" : "application/json",
   "payload" : payload
 };
 
 //　リクエストを飛ばすメソッド
 UrlFetchApp.fetch(webhook, options);
}
```

次に、スクリプトエディタの編集→現在のプロジェクトのトリガーから、下記のトリガーを作成します。
![スクリーンショット 2019-06-23 19.19.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247753/f708ece6-6cd0-52a6-9825-c926f71d5822.png)

以上です。

##結果
フォームから回答を送信すると、
![スクリーンショット 2019-06-23 19.44.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247753/75a22a50-98a0-1ace-8165-f6eaa0b9137c.png)
以下の形式でSlackの該当チャンネルに通知が来るようになりました。
![スクリーンショット 2019-06-23 19.46.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/247753/ad2d1085-fcb1-0d67-6e7e-1e2deb14381a.png)



##終わりに

実装に関しては特に詰まることもなく、先駆者もたくさんいて容易にできました。
Qiitaは初投稿でしたが、インターン先でRedmineを使っていたこともありマークダウン記法に慣れていたため書きやすかったです。
今後もアウトプットを続けていけるよう頑張ります。
スペースを含む(creative cloud fileなど)ディレクトリのパスを扱う方法(terminal)

# 問題
スペースを含む(creative cloud filesなど)ディレクトリに`cd`などでアクセスしたいのにこうなった
Finderでディレクトリを選択して`option+command+c`をやるとパスをコピーしてくれるのですが工夫が必要

```
$ cd /Users/ユーザー名/Creative Cloud Files/work/hoge
-bash: cd: /Users/ユーザー名/Creative: No such file or directory
```

# 解決策
スペースを含むディレクトリを`""`で囲むだけ

```
$ cd /Users/ユーザー名/"Creative Cloud Files"/work/hoge
hoge ユーザー名$
```
ちゃんと`hoge`を参照してます

# 参考文献
・[ターミナルで空白文字(半角スペース)を含むディレクトリやファイルを扱う方法](https://qiita.com/fantm21/items/aab0b2e55b2ffb4681c4)
・[Macでファイルフルパスを簡単にコピーする方法](https://do-zan.com/mac-copy-path/)