OmniAICreator/Qiita-1.07M huggingface dataset:
gRPC-webを使ってJSONとgRPCどっちが速いのか検証してみた

## 概要

- タイトルは本当はREST API vs gRPCが正しい
    - REST APIでサーバー/クライアント通信する時にjsonでやり取りすることが多いと思うのでこのタイトルにした
- あまり情報がない中公式のexampleを参考にし、gRPC-webも取り入れて[動くプロジェクト](https://github.com/jigengineer/json-vs-protocol-buffers)を作った
- 比較方法は同じデータをクライアントからサーバーに任意の回数「シリアライズ->リクエスト->レスポンス」の時間を比較
    - シリアライズされたデータで速度検証してもあまり意味がないと判断したため

*作ったリポジトリ -> https://github.com/jigengineer/json-vs-protocol-buffers*

## 結果

比較は、それぞれ1000回試行するのにかかった時間を計測。

|n|JSON|gRPC|
|---|---|---|
|1|3.614 sec|4.247 sec.|
|2|3.586 sec.|4.637 sec.|
|3|3.608 sec.|4.57 sec.|
|4|3.656 sec.|4.836 sec.|
|5|4.316 sec.|4.278 sec.|
|6|3.55 sec.|4.387 sec.|
|7|3.483 sec.|4.303 sec.|
|8|3.567 sec.|4.468 sec.|
|9|3.603 sec.|4.481 sec.|
|10|3.575 sec.|4.402 sec.|
|ave.|3.656 sec.|4.461 sec.|

圧倒的にJSONの方が高速である。

## あとがき

この比較だと、シリアライズにかかる時間が大きいのか、ネットワークロードが重いのかがまだわからないことと、gRPC自体も複雑で、いろんな通信方式があるようなので、gRPCの方が遅いという結論づけはできません。

明確なのは、「シリアライズ+リクエストしてレスポンスをもらう」一連の流れを連続して複数回行う場合、JSONの方が速かったということです。

ちなみにもう少し言うと、gRPCについてそこまで詳しくないので、公式リポジトリのexampleを参考にして動く状態に持ってきたので、パフォーマンスを最適化したりとかはしていないですし、どのような状況でパフォーマンスが最高になるのかもよく知りません。

一応[比較に用いたプログラムはこちらに置いてある](https://github.com/jigengineer/json-vs-protocol-buffers)ので、参考にしてみてください。
#udemyメモ　studentクラス

Attributes, getters, setters - Text directions, references and code
Section 2, Lecture 50

```.rb
class Student
  attr_accessor :first_name, :last_name, :email, :username, :password
#ゲッターとセッターをメタプロでやってる（動的プロキシ？ゴーストメソッド？違いがよくわかってない）
  def initialize(firstname, lastname, username, email, password)
#Studentクラスのオブジェクトを新しく作るときに初期化して、ついでにインスタンス変数をセット
    @first_name = firstname
    @last_name = lastname
    @username = username
    @email = email
    @password = password
  end
 
  def to_s
#to_sメソッドをオーバーライドしている
    "First name: #{@first_name}, Last name: #{@last_name}, Username: #{@username},
                  email address: #{@email}"
  end
 
end
 
mashrur = Student.new("Mashrur", "Hossain", "mashrur1", "mashrur@example.com",
                      "password1")
john = Student.new("John", "Doe", "john1", "john1@example.com",
                      "password2")
puts mashrur
puts john
mashrur.last_name = john.last_name
puts "Mashrur is altered"
puts mashrur
#putsメソッドはto_sが自動的に呼び出す。わざわざto_sオブジェクトに渡さなくてもいい。
```

```bash
$  ruby student.rb
puts mashrur => First name: Mashrur, Last name: Hossain, Username: mashrur1,
                  email address: mashrur@example.com
puts John => First name: John, Last name: Doe, Username: john1,
                  email address: john1@example.com
puts "Mashrur is altered" => Mashrur is altered
puts mashrur => First name: Mashrur, Last name: Doe, Username: mashrur1,
                  email address: mashrur@example.com
```
jupyter notebookで実行できない！

jupyterで遊ぼうとインストールしていざ立ち上げると、うんともすんとも言わなくて困ったので同じような状況の方がいればと思い、走り書きます

# 解決法

tornadoというWebフレームワークのバージョン6で、なにやらおかしなことが起きてるようでしたので、5.1.1にダウングレードします

```shell
pip uninstall tornado
pip install tornado==5.1.1
```

# 状況

こういう記事では序盤に能書きをたれていると腹が立つかなと思い、いつも後ろに詳細を書いています

## 環境

- macOS 10.14.3
- pyenv
    - Python 3.7.1

## 解説？

振り返ると何ということはない、エラーを見ていなかったから苦労したんですよね
困ったらまずエラーを読んでエラーメッセージでググるのは基本です(?)

```shell
RuntimeWarning: coroutine 'WebSocketHandler.get' was never awaited
```
というエラーが見えたので、とりあえずググってみると[stackoverflow](https://stackoverflow.com/questions/54963043/jupyter-notebook-no-connection-to-server-because-websocket-connection-fails)が出てきました

そもそもWebSocketの接続にエラーがあったせいでkernelとの接続に失敗していたようです
そりゃ実行できないワケです

# 教訓

jupyterが動かなかったら

- 左上のインジケータでkernelとの接続状況を確認すること
- ターミナルに戻ってエラーメッセージをがんばって読むこと

心を折る前に初心にかえることですね
こんなことで数時間悩みました

…ようやく動くようになったので遊んできます…
郵便番号検索プログラム #udemyメモ

Dial book solution code:

```rb
dial_book = {
  "newyork" => "212",
  "newbrunswick" => "732",
  "edison" => "908",
  "plainsboro" => "609",
  "sanfrancisco" => "301",
  "miami" => "305",
  "paloalto" => "650",
  "evanston" => "847",
  "orlando" => "407",
  "lancaster" => "717"
}
 
def get_city_names(somehash)
  somehash.keys
end
 
def get_area_code(somehash, key)
  somehash[key]
end
 
loop do
  puts "Do you want to lookup an area code based on a city name?(Y/N)"
  answer = gets.chomp.downcase
  break if answer != "y"
  puts "Which city do you want the area code for?"
  puts get_city_names(dial_book)
  puts "Enter your selection"
  prompt = gets.chomp
  if dial_book.include?(prompt)
    puts "The area code for #{prompt} is #{get_area_code(dial_book, prompt)}"
  else
    puts "You entered a city name not in the dictionary"
  end
end
```
Visual Basic エディタのバグ、検索ダイアログの文字化け修正手順

# つまらないことはVBAに
と思ったら、VisualBasicエディタの検索ダイアログが拗ねました。
ピンポイントで、検索ダイアログにのみ文字化けが発生します。

![kensaku.jpg](https://qiita-image-store.s3.amazonaws.com/0/309183/03b07ee9-2575-b522-2c5d-016f44e2e009.jpeg)

初めて遭遇した時は、IMEがおかしくなったのかと学習情報や入力履歴を消去しました。
直りませんでしたが。

# 修正方法
[https://support.microsoft.com/ja-jp/help/416637](https://support.microsoft.com/ja-jp/help/416637)
公式サイトより。

それぞれ下記のレジストリを登録し、Excelを再起動することで修正されます。
`Excel 2010`
キー名 : HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Excel\Options
名前：QFE_17407
種類：DWORD
データ: 1

`Excel 2013`
キー名 : HKEY_CURRENT_USER\Software\Microsoft\Office\15.0\Excel\Options
名前：QFE_17407
種類：DWORD
データ: 1

# おわりに
このバグの歴史は古く、Office2003のころから発生しており、検索するとOffice2016でも
発生しているみたいです。2019でも発生するんでしょうか。

長い付き合いのバグですが、新たに誰かの記憶の片隅に引っかかればいいなと。
Oracleのプライマリーキー(主キー制約)を追加/変更する

#1．主キー制約を追加する
##手順
1.主キー制約を追加する

```
-- 主キー制約を追加する
ALTER TABLE [テーブル名] ADD CONSTRAINT [主キー制約名] PRIMARY KEY [列];
```

#2．主キー制約を変更する
##手順
1.主キー制約を削除する
2.インデックスを削除する(場合による)
3.主キー制約を追加する

※主キー制約を追加すると自動的に「PK_[テーブル名]」という名前の(ユニーク)インデックスが作成されるため、主キー制約名を同名にしている場合、手順2を行わないと手順3で同名のオブジェクトがある旨のエラーが発生する。

```
-- プライマリーキーを削除する
ALTER TABLE [テーブル名] DROP CONSTRAINT [主キー制約名];
```
```
-- インデックスを削除する
DROP INDEX [インデックス];
```
```
-- 主キー制約を追加する
ALTER TABLE [テーブル名] ADD CONSTRAINT [主キー制約名] PRIMARY KEY [列];
```
【PowerShell】再帰的にファイルを検索し！それらを一箇所にコピーして！一気にファイル名を変える！

# 利用シーン
- 複数のディレクトリに散らばっているファイルを一箇所にまとめたい
- まとめてファイル名を変更したい(変更したいファイル名が決まっている)

# 自分が試した環境
- Windows10
- PowerShell 5.1


# 書いたコード
記事最下部の「コード」から、一部を抜粋

## ▼再帰的に取得した情報が、ファイルかディレクトリかを判定する

```PowerShell:testpath.ps1
$files = Get-ChildItem -Recurse -Name

# 取得した情報を一つ一つ処理する
foreach($file in $files) {
    if( Test-Path $file -PathType Leaf ) {
        Write-Host($file + 'はファイルです。')
    }
}
```

[Test-Path - Microsoft Docs](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/test-path?view=powershell-6)


## ▼ファイル名に「txt」という文字があるかどうかを判定(拡張子判定のつもり)

```PowerShell:splitpath.ps1
# ファイル名だけを抽出する('.\dir\file.txt'みたいなときに'file.txt'を抽出する)
$tailFileName = Split-Path $file -Leaf
if( $tailFileName.Contains('txt') ) {
    Write-Host($tailFileName + 'にはtxtという文字が含まれています')
}
```

[Split-Path - Microsoft Docs](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/split-path?view=powershell-6)


## ▼外部ファイルを一行ずつ読み込む

```PowerShell:get-content.ps1
Get-Content '.\nameList.txt' -as[string[]]
```


# コード

```PowerShell:meetupAndChangeFIlesAll.ps1
# いろんなところに散らばるファイルを一つのディレクトリに集める
$files = Get-ChildItem -Recurse -Name

foreach($file in $files) {
    if( Test-Path $file -PathType Leaf ) {
        $tailFileName = Split-Path $file -Leaf
        if( $tailFileName.Contains('txt') ) {
            Copy-Item $file '.\target_dir'
        }
    }
}

# 外部ファイルから読み取った文字列(一行に一単語)を使って指定ディレクトリ内のファイル名を変更
$nameList = (Get-Content '.\in.txt') -as[string[]]
$targetDir = Get-ChildItem '.\target_dir'
$concatDir = '.\target_dir\'

$i = 0

foreach($f in $targetDir) {
    Write-Host ('新しいファイル名は ' + $nameList[$i])
    Write-Host ('現在のファイル名は ' + ${concatDir} + ${f})

    Rename-Item ${concatDir}${f} -NewName $nameList[$i]
    $i++
}

Get-ChildItem '.\target_dir'
```

https://gist.github.com/itsumoonazicode/b344af179c96055b2d7cb5311c01d92f
ヌンチャクをマウスにしてみよう（ヌンチャク型コントローラ・ミーツ・Digispark）

# はじめに

先日、某ゲーム機のヌンチャク型コントローラをリサイクルショップでお安く見つけました。
そこで今回は、Digisparkというマイコンボードを使用して、そのコントローラをUSBマウスとして使える※ようにしてみた、というお話です。

※：標準的なHIDクラスに準拠したデバイスとして扱う（＝PCに接続して自動的に使用できる状態になる）ということを指します


# やったこと
			
## ハードウェアの準備
            
まずはヌンチャク型コントローラのケーブルを切断して4本の線を取り出します。
　赤色：VCC
　白色：GND
　黄色：SCL
　緑色：SDA
となっています。（下の写真参照）
　![ヌンチャクコントローラの線.jpg](https://qiita-image-store.s3.amazonaws.com/0/155449/ee715535-6c77-6c2d-93c6-f6d9fa482d07.jpeg)

そしてDigisparkと以下のように結線します。（下図参照）
　赤色：VCC→5V
　白色：GND→GND
　黄色：SCL→P2
　緑色：SDA→P0
![Digispark&Nunchuck.png](https://qiita-image-store.s3.amazonaws.com/0/155449/a3dc0b09-8e8b-f320-4f42-e8268a5434d4.png)

VCCは3V推奨のようですが、5Vでも動作します。

## ソフトウェアの準備
			
Arduinoを使用しました。
具体的なDigisparkの環境構築方法は、以下のWeb記事を参考にしました。

URL：
 https://homemadegarbage.com/digispark-1 

### ソースコード

ソースコードは[「こちら」](https://github.com/bigw00d/DigistumpNunchuk/blob/master/src/DigistumpNunchuk/DigistumpNunchuk.ino)に置きました。

ヌンチャク型コントローラとのI2C通信にはWire.hを使用しました。
そして、マウス動作にはDigispark専用のDigiMouse.hを使用しました。

コントローラのマウスへの割り当ては以下の通りです。
　スティック：カーソル移動
　Zボタン：右クリック
　Cボタン：左クリック

注意事項としては、起動時にスティック位置の基準を決定する（その時の位置を基準とする）処理を行うため、それが終わるまではスティックを放しておく必要があります。
（LEDとかでそのタイミングがわかるようにすれば良いかもしれません）	
			
			
# 終わりに

いかがでしたでしょうか。

ヌンチャク型コントローラはリサイクルショップで購入しやすいですし、Digisparkも1個400円くらいで購入できます。そして、Web上に多くの情報があり、さらにArduinoで100行くらいのコードで実現できるため、非常に取り組みやすい内容でした。（調査に多少の時間は要しましたが）

同コントローラを使用した今後の展開としては、内蔵されている加速度センサ※をマウスカーソルの移動に使用しても良さそうです。

[※参考記事](https://www65.atwiki.jp/dolphin-tas/pages/13.html)
→ヌンチャクから受信するデータの構成がわかります（「ヌンチャク」の項目参照）

そして、ヌンチャク型コントローラのみならず、同メーカーの他のコントローラも情報がたくさんあるため、それらを使ってみても面白そうなことができそうでした。（SFCのコントローラはSPIっぽいです）

最後に、実は自分で作らなくても以下のような部品を購入することで同じようなことができますので、参考までにリンクを張っておきます。

[リンク①：ゲームパッドコンバータ](https://www.amazon.co.jp/%E3%82%A8%E3%83%AC%E3%82%B3%E3%83%A0-%E3%82%B2%E3%83%BC%E3%83%A0%E3%83%91%E3%83%83%E3%83%89%E3%82%B3%E3%83%B3%E3%83%90%E3%83%BC%E3%82%BF-%E3%82%AF%E3%83%A9%E3%82%B7%E3%83%83%E3%82%AF%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%A9%E5%AF%BE%E5%BF%9C-JC-W01UWH%E3%80%90%E3%83%89%E3%83%A9%E3%82%B4%E3%83%B3%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88X-%E5%8B%95%E4%BD%9C%E7%A2%BA%E8%AA%8D%E6%B8%88%E3%80%91/dp/B009PDK6EI)
[リンク②：ヌンチャクアダプタ基板](https://www.amazon.co.jp/WiiChuck%E3%82%A2%E3%83%80%E3%83%97%E3%82%BFArduino%E4%BA%92%E6%8F%9B-WiiChuck%E3%82%A2%E3%83%80%E3%83%97%E3%82%BF%E3%81%AF%E5%B0%8F%E3%81%95%E3%81%AAPCB-designed-Nintendo-Nunchuck%E3%81%AE%E3%82%B3%E3%83%8D%E3%82%AF%E3%82%BF%E3%81%AB%E6%8C%BF%E5%85%A5%E3%81%95%E3%82%8C%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%82%92%E6%8F%90%E4%BE%9B%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AB%E3%81%99%E3%81%B9%E3%81%A64%E3%83%AF%E3%82%A4%E3%83%A4%E3%81%AE%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88/dp/B01DDWNBDY)


			
見ていただいてありがとうございました。
тнайк чoμ_〆(・ω・｡)			
			
# 参考記事
　
HomeMadeGarbage(小型マイコン Digispark の設定方法)
https://homemadegarbage.com/digispark-1

猫にコ・ン・バ・ン・ワ(Wiiヌンチャクの動作確認しました)
http://nuneno.cocolog-nifty.com/blog/2015/05/wii-088b.html

しぐれぎゃらりー(ヌンチャク型マウス)
http://mashigure.blog.jp/archives/21385105.html
【WPF】RelativeSource(バインディング)の使い方メモ

# RelativeSource

あるコントロールが、親のコントロールのプロパティを使いたいときに使う。
＝ElementNameで名前を指定せずに、自分から相対的にバインド相手を指定する。

テンプレートとかで、親と同じ背景色やフォント色にしたい、というときによく使うっぽい。
(「AncestorLevel」を使って、自分からみて何番目にヒットしたAncestorTypeのものをつかう、という指定もできる)

``` a.xaml
<Canvas Margin="5" Grid.Column="0">
    <TextBlock Text="あいうえお"/>
    <!-- 上位のCanvasと同じ大きさにする -->
    <Border Width="{Binding ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType=Canvas}}"
            Height="{Binding ActualHeight, RelativeSource={RelativeSource FindAncestor, AncestorType=Canvas}}"
            Background="#330000FF" BorderBrush="Red" BorderThickness="1">
        <InkCanvas Width="{Binding ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType=Canvas}}"
            Height="{Binding ActualHeight, RelativeSource={RelativeSource FindAncestor, AncestorType=Canvas}}"
               Background="Transparent"/>
    </Border>
</Canvas>
```

ここで使っている「FindAncestor=祖先を探す」以外に、下記のようなものがある。

・Self
自分の別のプロパティを見る。
下の例では、幅と高さを同じにして、正方形にする、ということをしている。

``` a.xaml
<Border Width="{Binding ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType=Canvas}}"
        Height="{Binding ActualWidth, RelativeSource={RelativeSource Self}" />
```

・TemplateParent 
ControlTemplate、DataTemplateで、テンプレートを使う側のプロパティを取るために使う？
(試してない)

## コード

https://github.com/tera1707/WPF-/tree/master/016_RelativeSource

## 参考
http://gushwell.ldblog.jp/archives/52328636.html
http://posaune.hatenablog.com/entry/20100114/1263426229
JavaFXアプリをJava8/11両方で動くjarファイルに固める

## 結論

- 各プラットフォーム向け OpenJFX 11 ライブラリをすべて含む fat jar を生成する．

## JavaFX (Java 11から非同梱)

JavaFXは，JVM上で動作するクロスプラットフォームなGUIライブラリです．が，Java 11からライブラリが同梱されなくなり，かわりに[OpenJFX](https://openjfx.io/)として外部ライブラリ化されました．

ここで悩ましいのは「どのJavaバージョンに対応するか？」です．Java 11に対応したいものの，Java 8を簡単に切り捨てるわけにはいきません（[個人ユーザへのOracleの無償アップデート提供は2020年末まで続く](https://www.oracle.com/technetwork/jp/java/eol-135779-ja.html)）．

## Java8/11 両方で動かす fat jar

この悩みを解決するのが fat jar で，端的に言えば OpenJFX 11 ライブラリを jar ファイルにすべて含めてしまいます．

詳細は [Getting Started with JavaFX 11 > Runtime images > Non-Modular project](https://openjfx.io/openjfx-docs/#modular) に記載がありますが， Gradle だと（通常のjarタスクの設定に加えて）下記のような指定を追加します．

```gradle:build.gradle
compileOnly "org.openjfx:javafx-graphics:$javafx.version:win"
compileOnly "org.openjfx:javafx-graphics:$javafx.version:linux"
compileOnly "org.openjfx:javafx-graphics:$javafx.version:mac"
```

そしてJDK11でビルドすると， Java8/11 両方で動く fat jar が出来上がります．
ji32k7au4a83

I read good stuff.

　[Why 'ji32k7au4a83' Is a Remarkably Common Password - Gizmodo](https://gizmodo.com/why-ji32k7au4a83-is-a-remarkably-common-password-1833045282)

So, I'll give it a try.

```sh:bpmf
#! /bin/sh -

echo 'ㄨㄛˇㄉㄜ˙ㄇㄧˋㄇㄚˇ' | sed 'y/ㄅㄉˇˋㄓˊ˙ㄚㄞㄢㄦㄆㄊㄍㄐㄔㄗㄧㄛㄟㄣㄇㄋㄎㄑㄕㄘㄨㄜㄠㄤㄈㄌㄏㄒㄖㄙㄩㄝㄡㄥ/1234567890\-qwertyuiopasdfghjkl:zxcvbnm,.\//'
```

Open a terminal, change to the directory where I installed this script, and run the following command[^1].

```
$ ./bpmf
ji32k7au4a83
```

I guess it's enough.

[^1]: "bpmf (bopomofo)" means "注音符號".
データ前処理ツールの調査

AIモデルの学習にはデータが必要です。

例えば、時系列データを学習に用いるモデルを作る場合、多量の時系列データを用意しますが、得てして一部に欠損があったり、標準化する必要があったりと前処理と呼ばれる加工が必要になります。

また、データの可視化のためグラフにすることも多々あります。

そうした時に、少量をサンプルとして抽出し、エクセル使って加工したり、PythonのPandasを使ったりしていたのですが、元データと加工後データの紐付けをフォルダ構成でなんとかしたりとか、何かと本筋とは別のところで気を使う日々を過ごしていました。

ちょっとそういう状態はどうにかならないかなということで、世にあるツールを探してみたところ、２つ気になるツールがあったのでメモです。
※後日、使ってみた感想を追記していきます。

1. [OpenRefine](http://openrefine.org/download.html)
    * スタンドアローンのオープンソースのデスクトップアプリケーション
    * 参考
        * [【まとめ】OpenRefineの使い方をまとめていく](https://qiita.com/keita69sawada/items/5f47d1a8ff078e67ee3f)
2. [Orange](https://orange.biolab.si/download/)
    * オープンソースのデータ視覚化、機械学習、データマイニング用ツールキット
    * 参考
        * [非プログラマのための機械学習ツールOrangeのご紹介](https://qiita.com/junkonakajima/items/9fbf65ec88b1245ee6d1)
Pythonで親階層のモジュールをimportする

python 3.7でのみ動作検証しました。

以下のような構成があったとします。


```

sample/
├── sample1.py
├── main
│   ├── main1.py
│   └── src1
│       ├── main2.py
│       └── src2
│           ├── main3.py
│           └── main4.py
└── sub
    └── sub1.py
```

main4.pyから

- main3.py
- main2.py
- main1.py
- sample1.py
- sub1.py

を呼び出したいときのメモです。

Pythonでimportを記述した場合、ライブラリを探すディレクトリが決まっています。しかしそこには、実行ファイルを含むディレクトリとそのサブディレクトリ群しか含まれません。

実行ファイル親階層にあるファイルをimportする場合、探索範囲に指定ディレクトリを追加する必要があります（パスが通っている状態にする）。



なお、 `main4.py` 以外のファイルでは、以下の内容で実装されてるとします。

```py
def hello():
    print(os.path.basename(__file__)) # 該当のファイル名を出力
```

## とりあえず動く

```py:main4.py
import main3

import sys
sys.path.append('../')
import main2

sys.path.append('../../')
import main1

sys.path.append('../../../')
import sample1

sys.path.append('../../../sub')
import sub1

main3.hello()
main2.hello()
main1.hello()
sample1.hello()
sub1.hello()
```

## 参考

https://note.nkmk.me/python-import-module-search-path/

https://tex2e.github.io/blog/python/import-files
Excelからコピペしてcsvにする簡易ツール


## 要点
Excelのセルをコピーしたテキストはtsvなので、これをReplaceで置換してcsvに保存するチャレンジ。

### 経緯
作業効率化のために、Excelからcsvを吐き出したいものの、
昨今はセキュリティの都合上現場は外のネットワークに繋がらず、VBAのソースもコピペできないことも多いです。
さて困ったけど、どうやってcsvファイルを作ろうかと考えたとき、Excelからセルをコピーしたときの特徴を利用すればよいと分かりました。

Excelからコピーしたセルは、テキスト上ではtsvで持っているので、区切り文字を``\t``から``,``に置換すればよいのです。

### 完成品の外観

適当にテキストボックスを配置し
（※AcceptsEnter, AcceptsTabをオン(true)にしてください）
![CSV_00.PNG](https://qiita-image-store.s3.amazonaws.com/0/114324/220accb1-ee4c-34f7-8b60-3e2df2a03768.png)

セルをコピーして
![CSV_01.PNG](https://qiita-image-store.s3.amazonaws.com/0/114324/ed782e85-d80f-20dd-5ef2-c5576b301936.png)

ペッと貼り付けるとファイルパスが出るので開くと
![CSV_02.PNG](https://qiita-image-store.s3.amazonaws.com/0/114324/537ecde7-cfd4-2446-dcef-4244fad4834b.png)

一瞬でcsvファイルの出来上がり！
![CSV_03.PNG](https://qiita-image-store.s3.amazonaws.com/0/114324/0bed7bbc-2311-32c1-f63b-636335c1c4ed.png)


## 通常版とワンライナー版

### 通常版

```C#:CopyTsvToCsv_Normal.cs
string[] sepArr = new string[] { "\r\n" }; // Split用
string toCsv = content.Replace("\t", ","); // tsv→csvへ
string[] lines = toCsv.Split(sepArr, StringSplitOptions.RemoveEmptyEntries); // 行を分割
File.WriteAllLines(fi.FullName, lines); // 上の行を削除してFile.WriteAllText(fi.FullName, toCsv)でもOK
```

### ワンライナー

```C#:CopyTsvToCsv_One-Liner.cs
File.WriteAllLines(fi.FullName, content.Replace("\t", ",").Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries));
```

### 応用プラン
- ファイルパス、ディレクトリパスから変換できるようにしてもOK
    - 後日書きます

### ソース
以下、上記のまとめです。

```C#:CopyTsvToCsv.cs

        private void TxbInputTsv_TextChanged(object sender, TextChangedEventArgs e)
        {
            DateTime dtNow = DateTime.Now;
            string fileName = string.Format("out_{0}.csv", dtNow.ToString("yyyyMMddHHmmss"));
            FileInfo fi = new FileInfo(Path.Combine(di.FullName, fileName));

            if (fi.Exists) return;

            OutPutCsv(fi, ((TextBox)sender).Text);
        }

        private void OutPutCsv(FileInfo fi, string content)
        {

            if (string.IsNullOrEmpty(content.Trim())) return;

            try
            {
                // ワンライナー版
                // File.WriteAllLines(fi.FullName, content.Replace("\t", ",").Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries));
                                
                string[] sepArr = new string[] { "\r\n" };
                string toCsv = content.Replace("\t", ",");
                string[] lines = toCsv.Split(sepArr, StringSplitOptions.RemoveEmptyEntries);
                File.WriteAllLines(fi.FullName, lines);
                
                TxbInputTsv.Text = string.Format("Save: {0}", fi.FullName);
                Thread.Sleep(5000);
                TxbInputTsv.Text = "";
            }
            catch(Exception ex)
            {
                TxbInputTsv.Text = ex.ToString();
            }
        }
```
Railsでページ遷移後にJavaScriptが実行されない問題の解消法

Railsでページ遷移後にJavaScriptが実行されない問題について解説します。
## Railsでページ遷移後にJavaScriptが実行されない問題の解消法

以下の行を削除します。

```javascript:application.js
//= require turbolinks
```

turbolinksは初心者にとっては余計な悩みを増やすだけですので、削除するのが良いでしょう。
## 終わりに
私は現在、Web3のサービスの開発をしています。詳しくはこちらの記事をご覧下さい。
        [無料でイーサリアムが当たる、Web3時代の寄付サイトを作った話](https://note.com/kenroda/n/n814347fbdcd7)
お手軽Laravel環境構築(Virtualbox-Vagrant)(CentOS7+php7.2+mysql+apache)#2

仮想環境に管理者でログインする

```:コマンド
[vagrant@localhost ~]$ su -
```

## ◆phpのインストール

```:コマンド
yum install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
yum install yum-utils
yum-config-manager --enable remi-php72
yum -y install --enablerepo=remi,remi-php72 php-mysqlnd
```

php7.2をインストールするためにremi(yumのライブラリ)をいれた。
2つめのコマンドはyum-utilsをいれている(パッケージrpmのみダウンロードできる)
3つ目のコマンドでphp72をインストールすることを許可している。

## ◆apacheのインストール

```:コマンド
[root@localhost ~]# yum -y install httpd
[root@localhost ~]# systemctl enable httpd.service 自動起動設定
[root@localhost ~]# systemctl start httpd.service 起動
```

## ◆MySqlのインストール

```:コマンド
[root@localhost ~]# yum remove mariadb-libs 競合解決
[root@localhost ~]# yum localinstall http://dev.mysql.com/get/mysql57-community-release-el7-7.noarch.rpm
[root@localhost ~]# yum install mysql-community-server
[root@localhost ~]# systemctl enable mysqld.service 自動起動設定
[root@localhost ~]# systemctl start mysqld.service 起動
```

https://enomotodev.hatenablog.com/entry/2016/09/01/225200
初期設定はこれ参考

## ◆Composerインストール

```:コマンド
[root@localhost ~]# curl -sS https://getcomposer.org/installer | php
[root@localhost ~]# mv composer.phar /usr/local/bin/composer
```

これでcomposerコマンドが実行可能

## ◆vagrantFileを変更する
・config.vm.network "private_network", ip: "192.168.33.10"の#削除
・config.vm.synced_folder "ローカルディレクトリ", "/home/vagrant/○○"

この時/home/vagrant/としてしまうと、同期するときにかぎのファイルを上書きする可能性があり、
sshログインできなくなるので、ディレクトリを作ってそこと同期する

変更した設定を反映するためvagrantの再起動

```:コマンド
[root@localhost ~]# vagrant reload
```

## ◆laravelインストール

```:コマンド
[root@localhost ~]# yum install --enablerepo=remi-php72 php-mbstring php-xml php-pdo
[root@localhost ~]# yum install -y git ssh
[root@localhost ~]# composer create-project --prefer-dist laravel/laravel sample
[root@localhost www]$ sudo chown apache:apache -R sample/storage
[root@localhost www]$ sudo chown apache:apache -R sample/bootstrap/cache
[vagrant@localhost sample]$ php artisan serve --host 0.0.0.0
```

上で有効化した
vagrantFileのip 「192.168.33.10」
で接続完了
TOEIC285学生のためのSQL

# SQLとは

私は恥ずかしながら25歳になるまでSQLという言葉の存在すら知らなかった。

>SQLは関係データベース管理システム (RDBMS) で、データの操作や定義を行うためのデータベース言語である

RDBMS....RedDragonBattleModeSystem（レッドドラゴンバトルモードシステム）....いや違う

>Relational DataBase Management System（リレーショナルデータベースマネジメントシステム）

【Relational】リレーショナル・・・関係のある
【DataBase】データベース・・・記録の集合体
【Management】マネジメント・・・制御、管理
【System】システム・・・組織、機関

つまり、SQLは
データベースに対して「消えろ！」と言ったらデータが消えて
データベースに対して「増えろ！」と言ったらデータがコピーされる命令が出来る、らしい。

**ところで　RDBMS　は「Relational DataBase Management System」**
**なら　SQL　は？　「SQLは略語じゃないそうです」**

RDBMSのあるところにSQLあり、データを取り扱うにはSQLをマスターしたほうが良さそうです。
VBAしかまともに書いたことのない人間がPython3を学ぶ上で忘れそうなことを記録する日記

これは、以下のほぼほぼIT知識のない人間が、調子に乗ってPython3を学ぶ上での備忘録である。
※話はどうでも良いところで長いタイプです。
　Qiitaをお使いの諸兄にとっては、中身はないに等しいです。

#経緯というか経歴というか、私の知識レベル
十数年前にプログラマを目指してC言語とアセンブラを必死に勉強したものの、アセンブラのメモリ値選択理由がないと言われて心が折れて以来、さーっぱりプログラミングから離れ、つい3年ほど前に業務効率化に興味をもってExcelをメインに仕事を始めてVBAも書くようになった程度の人間が、アラサーも過ぎて正しく調子に乗ってPython3を学ぶ上での備忘録です。
（上の説明を長くしました）
（正直心折れた理由も正しく説明できないくらい時が経ちました。記憶から薄れる用語）

ここ3年でiパスなら取った。情セキュも取った。
基本情報技術者？　勉強……止まってる。
フレームワークって考え方のことでしょ？
半年以上前に、本の通りにPython書いてBJ作ったけど、GitHubってなんなの。
Djangoってなんなの。

こんなやつですが、調子に乗ってpaizaのpython3入門編を1から真面目に（時に聞き流しながら）演習問題を解いて、とりあえず1週間ほどでpaizaのBランクは取得しました。
入門編は実はまだ最後まで走り切っておりません。
入門編6までで止まっています。（スキルチェックを優先してしまった）

#まず最初につまずいたこと、標準入力
標準入力ってなんなん。ということ。
何せVBAは標準入力に値する言葉がありませんというか、私の知識の中にありません。
読み込ませたい内容は、セルに書いてあるかテキストファイルとして読み込むものです。
おかげで、最初のスキルチェックが一切わからず、聞かれるたびに無力感を感じ、paizaから逃げておりました。

結論としては、

```
str = input()　　　#strは任意の変数
```
って書いた行数だけ変数に入力値を読み込む。
だったのですが、もう本当にVBAにその概念がなさ過ぎて、それならそう一言で言ってくれよ……と思いました。
Forで回すに至っては、下記に置き換えてやっと、なるほどね。という気分です。

```
str = Cells( i, 1 )
```

#で、今回メモしたかったこと、
時間も無くなってきたのでやっと本題です。
今回メモしたかったのは、重複するワードが存在する配列において、その配列において各ワードの初出順に、重複回数を返す、というちょっと詳しく説明しようとすると何かに抵触しそうな内容です。
いやでも、これ使うことあると思うのよ。

どうやろうかと調べるに当り、下記のサイトさんなどに目を通しました。
https://note.nkmk.me/python-list-unique-duplicate/
https://www.lifewithpython.com/2013/11/python-remove-duplicates-from-lists.html
https://pg-chain.com/python-list-set

なるほどsetなるものがあるねー。あー、sotedとか学んだな。
と書いてみたのですが、内容に知らないことが含まれていたので、深く理解することを避けたまま書いたため、思い通りの結果は得られませんでした。
ソートされた並び順でなら吐き出せたんですけどね。初出順にするのに混乱したので即座に諦めました。
ので、阿呆とは承知で自分が理解できる手順で、自分がもっている知識のみを使って書くことにしました。

実際に書いたコード抜粋は規約に反しそうなので、便利だったもののみを記します。
結局やりたいことを調べた結果、任意のワードがリスト内で何回重複しているかがわかるコードがありました。

```.py
list.count(str)
#listとstrは任意の変数
```
なにこれ超便利。
じゃああとはー、重複のあるリストをもとに重複のないリストを用意してー、それをもとに重複のあるリストで数を数えればー……完璧じゃん！

なんでしょう、非常に見慣れたコードのくせして使い方が一切慣れないので、すぐにそらでは書けなさそうなのでここに残します。
っていうかその一行のためだけにこれだけの恥を書いたのだからもう覚えてほしいです。

#おわり
これより、Pythonの勉強どころじゃなくならない限り、少しずつ学んだことをここにまとめ残していきたいと思います。
頑張ります。
MacでExcelのシートをcsv（UTF-8形式）で保存して、awk,joinコマンドとかする際の留意点

# Intro
MacのExcelでcsv形式で保存したファイルに対してawkやjoinで良きに図ろうとするとぐちゃぐちゃな表示になった経験はありませんか？
ニッチすぎて需要があるかものすごく疑問ですが、MacのOffice 365の2019/03/05時点最新版Excelでシートをcsv（UTF-8）形式で保存した場合に、そのファイルに対してawk,joinコマンドを使いたいあなた（？）に向けて留意点を書きます。

# 留意点
MacのExcelでcsvを保存すると、

- 文字コードはUTF-8ですが、BOM（バイトオーダーマーク）が付きます
- 改行コードがLFではなく、CRLFになってCRが余計に付きます

改行コードCRLFがMacだとキッツイ。
Windowsじゃないのです。

# 検証
Excelで
1 2
2 3
3 4
4 5
5 5
をcsv形式でsheet1.csvという名前で保存。

```
$ cat sheet1.csv
1,2
2,3
3,4
4,5
5,5
```
一見何の変哲も無い。

```
$ awk '{print $1,$2}' sheet1.csv
1 2
2 3
3 4
4 5
5 5
```
これは大丈夫。

```
$ awk '{print $2,$1}' sheet1.csv
 1
 2
 3
 4
5 5
```
これがNGです。

まず先に怪しそうなCRLFをLFに変換して再度awk

```
$ nkf --overwrite -Lu sheet1.csv
$ awk '{print $2,$1}' sheet1.csv
2 1
3 2
4 3
5 4
5 5
```
OKです。

CRLFが余計であって、BOMは関係なさそうですね。


# 対処
BOMも気になる方は、BOMなしUTF-8かつ改行コードをLFにして上書き保存しちゃいましょうか。

```
$ nkf -w -Lu --overwrite [csvファイル名]
```

この記事にたどり着いた人でnkfコマンドを知らない人はいない気がするので、この解説とインストールは省きます。
Jupter Notebook 実行時のTime out エラー

# Jupyter Notebook インストール後のエラー
Webスクレイピングを行うツールとして勧められたのですが、インストール後に謎の事象に悩まされました。結論として解決できず、従来手法や別の対処法にて行うことにしましたが(恥ずかし)、原因を調査した経緯事象をまとめておきたいと思います。

**操作環境**
　　   - OS: Windows10Home 64bit
 　　  - CPU: IntelCorei5-8250U 1.60GHz
  　　 - RAM: 8.00GB
  　　 - Python 3.7.2
  　　 - jupyter==1.0.0
  　　 - notebook==5.7.4

**事象**
　1. Jupyter Notebookで実行時にConnecting to kanel の状態
![図1.png](https://qiita-image-store.s3.amazonaws.com/0/177907/848938f3-e5b2-ff2b-98d2-eaa346469a8c.png)

　2. 一定時間経過後、Connection failed のメッセージウィンドウが表示される。
![図2.png](https://qiita-image-store.s3.amazonaws.com/0/177907/68c9bae1-f0fa-044b-d53c-24537378bb5d.png)

　3. Runningで状態確認すると、タスクは実行されてる？
![図3.png](https://qiita-image-store.s3.amazonaws.com/0/177907/768f7b73-a639-4564-f649-cbaf863e2b2a.png)

　4. WebSocket が kernels に接続失敗している。
　   ※セキュリテイの程度が分からずマスキングしてますが...解決に必要？
![図5.png](https://qiita-image-store.s3.amazonaws.com/0/177907/8572c612-e428-7f28-6ba5-a89fb5dce0d2.png)

**状況**
ググりもがくこと1時間...色々事象を探してもなかなか該当はなく...OSを再インストール？それだけは避けたい思いで解決を目指しましたが、2019.3.5時点で解決しておりません。

# 躓いた先に浮かぶのは ... プランBでいこうかな
Webスクレイピングの手法自体は、沢山あるので現時点でJupyterNotebookには拘らず、別の手法で継続しようと考えました。(プランAを放棄)
プランBは従来のやり方に加え、**Google Colaboratory**を利用するのもよいかと考えています。分析業務をどっぷり行う方であればご存知かと思いますが、環境構築に煩わされることなく最適解な気がしています...
GatsbyとNetlifyを用いて爆速でブログの公開

# 概要
今回は、Reactベースの静的サイトジェネレータのGatsbyと、サイトを公開するためのNetlifyを利用して、爆速でWebアプリケーションをデプロイする方法について書きます。
※ブログはテンプレートのままでデプロイしています。

# プロジェクトの作成
Gatsbyはテンプレートを選んでプロジェクトを作成することができます。
今回は[Netlifyのテンプレート](https://www.gatsbyjs.org/starters/netlify-templates/gatsby-starter-netlify-cms/)があるため、そちらを利用していきます。
それ以外のテンプレートは[こちら](https://www.gatsbyjs.org/starters?v=2)から探すことができます。

```bash
# GatsbyのCLIのインストール
npm install -g gatsby-cli

# プロジェクトの作成
# gatsby new [プロジェクト名] [GatsbyのテンプレートのGitHubのurl]
gatsby new ferretdayo.blog.io https://github.com/netlify-templates/gatsby-starter-netlify-cms
```

# Netlifyへのデプロイ
以下のURLにアクセスしてNetlifyにデプロイするための準備をしましょう。
https://app.netlify.com/start/deploy?repository=https://github.com/AustinGreen/gatsby-starter-netlify-cms&stack=cms
アクセスするとこちらの画面が表示されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/116983/657d650b-5363-0851-7981-9415397ebf15.png)


ここのページでやってくれることは、以下の２つです。
1. GitHubとNetlifyの連携
2. GitHub上にNetlifyにデプロイしてくれるレポジトリも作成


ここにレポジトリ名を記入すると、GitHubにレポジトリが作成されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/116983/90729839-3742-14b5-59cf-2fe29bd5415e.png)

その後ダッシュボードが表示され、`Getting started`の通り進めていきましょう。

## 1. Your site is deployed
作成したレポジトリに対してpushしましょう。

```bash
cd [作成したGatsbyのプロジェクト名]
git init
git remote add origin [対象のレポジトリのURL]
git push origin master
```

## 2. Custom domain is set
ドメインを持っていない場合は、やらなくてもいいです。
わたしは、お名前.comでドメインを取得している場合で書いているため、お名前.comではない方はご注意ください。

1.まずはじめに、こちらから所有しているドメインを打ち込みましょう！
https://app.netlify.com/account/dns/setup
![image.png](https://qiita-image-store.s3.amazonaws.com/0/116983/1cd6d3bf-4914-45a4-0227-c1f060e7398a.png)

2.次のDNSレコードの設定は放置します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/116983/aacbfccb-336f-0806-a8ab-0cc28885bc25.png)

3.お名前.com側のネームサーバを設定します。
Netlifyから以下の４つをネームサーバ変更してくださいと言われるため、お名前.comのネームサーバを変更します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/116983/fb6331c6-0ef9-5bb3-3a5d-07efb84d580f.png)

このように、お名前.comの`ネームサーバの変更`から設定します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/116983/9f911875-e05c-b010-c620-6e95cae2a866.png)

4.Netlify側でDNSレコードを作成します。
`Settings > Domain Management`からDNSの設定ページを開きます。
`Check DNS configuration`をクリックするとモーダルが出るので、`Create DNS Records`を押してDNSレコードを生成しましょう。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/116983/9ab726d4-18e4-2ddf-8666-08351342508b.png)

生成後は以下のようにDNSレコードが増えていると思います。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/116983/9df2cb20-5263-9a19-c61a-849301b67cf8.png)

これで設定は終わりです。

## 3. Secure your site with HTTPS
ボタン押せばLet's EncriptでHTTPSの設定をしてくれます。めちゃ簡単ですね。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/116983/f606605f-0450-9679-9ff0-0f95e4079eba.png)

# デプロイしたアプリを確認
設定したドメインにアクセスすると、無事デプロイされていると思います。 
![image.png](https://qiita-image-store.s3.amazonaws.com/0/116983/301df055-1a5a-7931-1820-9aa99ba979a2.png)
ワイ「いうても型なんて面倒くさいだけやろ？」

**※登場人物等は全てフィクションです。**

# 再就職したワイ

社長「やめ太郎くん」

ワイ「はい」

社長「今うちで開発中の**ブラウザゲーム**があるんやけど」
社長「そのゲームの中に登場する**ジュースの自動販売機**をプログラミングしてくれへんか」

ワイ「ええで」

社長「言語は**TypeScript**や」

ワイ「・・・ええで（**震え声**）」

# タイプスクリプト is 何

ワイ「なんや**TypeScript**て」
ワイ「**JavaScript**の打ち間違いか？」
ワイ「きっとそうやな」
ワイ「誰かが**タイプミス**で仕様書に**TypeScript**って打ち込んでもうたんや」
ワイ「いわば**タイポスクリプト**や」

ハリー先輩「**ちゃうで**」

ハリー先輩「知らん言葉が出てきたからって**変な妄想**で自己解決したらアカンで」
ハリー先輩「なにが**タイポスクリプト**や」
ハリー先輩「**TypeScript**は静的型付けが出来る**AltJS**や」 

ワイ「ほえー、静的な**型**のあるJavaScriptでっか」

# 型があるメリット

ワイ「型があるとなんか嬉しいんでっか？」

ハリー先輩「けっこう嬉しいで」
ハリー先輩「例えば、引数として**数値しか認めない**関数とかを作れるんや」
ハリー先輩「あと**返り値の型も指定できる**で」

ハリー先輩「つまり関数や変数の**使い方に関するルール**を自分で決められるんや」
ハリー先輩「この関数は**数値を受け取って文字列を返さなあきまへんよ**」
ハリー先輩「みたいなルールや」
ハリー先輩「そんで、**その通りに実装**せえへんと**JSに変換してくれへん**ねん」

ハリー先輩「その関数が**受け取るべき引数**や**返すべき値**の**型**・・・」
ハリー先輩「それが**コード上に明記される**ことになるから、可読性も**爆上がり**や」
ハリー先輩「あとからプロジェクトに参加したメンバーも助かるやろ」

ワイ「ワイみたいな**ザコーダー**が関数の使い方を間違えて**ウンコード**を生産してしまうのを防いでくれるわけでんな」

ハリー先輩「せや」

# さらに

ハリー先輩「**自作の型**みたいなもん[^1]も定義できるで」

ワイ「型を自作・・・」
ワイ「そもそも型を作りたいとか**思ったことない**ですわ」
ワイ「型が作れると何が嬉しいんでっか」

ハリー先輩「**めっちゃ嬉しいで**」
ハリー先輩「例えばやな」
ハリー先輩「**ジュースの自販機**の例やと・・・」

```typescript
type Coin = 10 | 50 | 100 | 500;
```

ハリー先輩「こうや」

ハリー先輩「コインいうのは**10円玉、50円玉、100円玉、500円玉の事ですよ**」
ハリー先輩「っちゅう意味や」
ハリー先輩「ジュースの自販機には**1円玉や5円玉は入れられへん**からな」

ハリー先輩「そんで次はこうや」

```typescript
type Bill = 1000;
```

ハリー先輩「これは」
ハリー先輩「**紙幣（Bill）いうのは千円札の事ですよ**、いうことや。」
ハリー先輩「ジュースの自販機には**二千円札、五千円札、一万円札は入らへん**からな」

ハリー先輩「さらにこうや」

```typescript
type Money = Coin | Bill;
```

ハリー先輩「**お金いうのは、硬貨と紙幣のことですよ**、と」

ハリー先輩「こうやって、**硬貨として受け取るべき値**、**紙幣として受け取るべき値**・・・」
ハリー先輩「そして**自販機に投入されるお金としてあるべき値**」
ハリー先輩「そんなんを自分で定義できるんや」

ハリー先輩「そうすることで、**Money型の引数しか受け取らへん関数**とかも作ることが出来るわけや」
ハリー先輩「↓こんな感じや」

```typescript
// 引数 money には Money型の値しか渡せない
function insertMoney (money: Money) { 
    /* ・・・・ */
}

insertMoney(5); // 5円玉はエラー！
```

ハリー先輩「変数や関数の**あるべき使い方**を**自分で定義**して」
ハリー先輩「**その通りに実装**せんと前に進めへん」
ハリー先輩「これだけでちょっとした**テスト駆動開発**みたいになるやん？」

ワイ「ほんまや・・・」

ハリー先輩「場合にもよるけど」
ハリー先輩「仕様として求められとる要件を」
ハリー先輩「**割とそのまんまの感じ**でコードにできたりするから」
ハリー先輩「**訳が分からなくなりにくい**っちゅうのもメリットやな」

```typescript
type Coin = 10 | 50 | 100 | 500;
type Bill = 1000;
type Money = Coin | Bill;
```

ワイ「たしかに↑これとか**一目瞭然**ですわ・・・」

ハリー先輩「TypeScriptを[**ブラウザ上で気軽に試せるサイト**](https://www.typescriptlang.org/play/)もあるから、まずは触ってみいや」

ワイ「さっそくやってみますわ！」

# Let's TypeScript

ワイ「ポチポチポチ・・・っと」
ワイ「なんや、おかしいな」
ワイ「ハリー先輩」
ワイ「このブラウザ上のエディタ、なんかオカシイでっせ」
ワイ「エラーばっかり吐きよる」

ハリー先輩「いや、ちゃうな」
ハリー先輩「ここ、**money**のスペルが**moony**になっとるで」
ハリー先輩「**ムーニー**て」
ハリー先輩「**紙オムツ**やないかい」

ワイ「いや、**パンツタイプ**もありまっせ」

ハリー先輩「**どうでもええわ**」
ハリー先輩「お前が一番**タイポスクリプト**しとるやないかい」

**〜おしまい〜**


# オススメ記事
[**TypeScriptの型演習**](https://qiita.com/uhyo/items/e4f54ef3b87afdd65546)
[**TypeScriptの型演習（解答・解説編）**](https://qiita.com/uhyo/items/0e7821ce494024c98da5)

[^1]: 正しくは[**型エイリアス**](http://js.studio-kingdom.com/typescript/handbook/advanced_types#type_aliases)ですね。
pythonメモ　噛み砕いて覚えるos.pathの一部

特定のファイルを他のディレクトリから参照したい場合に衝突した
pathの取得の分かった部分だけ　(最初いがいprint()は割愛しています

```python:main.py
import os

print(__file__)
# これで実行中の.pyの絶対パスが分かる

os.path.abspath('test.txt')
# 実行中の.pyと同じディレクトリならばこれでパスを調べれる

os.path.dirname(__file__)
# これで実行している.pyが存在するディレクトリのパスがわかる

os.path.dirname(os.path.dirname(__file__))
# どうやら上位のディレクトリにどんどんいけそうだ

dir_path = os.path.dirname(os.path.dirname(__file__))
new_path = os.path.join(dir_path, 'hello.txt')
# これでパスを繋げることができるのでディレクトリを探したりもできそうだ
```


```text:結果.py
C:\User\mpec\python\main.py

C:\User\mpec\python\test.txt

C:\User\mpec\python

C:\User\mpec

C:\User\mpec\hello.txt
```


##まとめ
pathlibの方が良いみたいだな。。。
 - [Python3.4以降ならos.pathはさっさと捨ててpathlibを使うべき](https://qiita.com/tag1216/items/29bf3b9c3c4b563ff0fe)


また、お気づきの点がありましたら遠慮なくご指摘お願いいたします。
TIPS: Windows10 Update 1809 上に RAID 5 環境を構築する

## これまでの経緯

ふだんはバッテリーでバックアップされた環境（というか ThinkPad 上）で作業しているせいか、これまであまり意識してこなかったのだが、これから隠居生活を始めるにあたって、自宅の仕事場の安全を確保するために UPS でバックアップされた RAID 5 環境を構築することを唐突に思いついた。

## RAID 5 を構築する

思いついたらやってみないと落ち着かない性分。RAID 5 のエンクロージャーとしてどんな選択肢があるのかを調べていて目に留まったのがこの [Highpoint RocketStor 6114V](https://www.amazon.co.jp/Highpoint-4%E3%83%99%E3%82%A4RAID5%E3%82%B9%E3%83%88%E3%83%AC%E3%83%BC%E3%82%B8%E3%82%A8%E3%83%B3%E3%82%AF%E3%83%AD%E3%83%BC%E3%82%B8%E3%83%A3%E3%83%BC-USB3-1Gen2-RocketStor-6114V/dp/B071X9XY16/ref=pd_ybh_a_8?_encoding=UTF8&psc=1&refRID=AZC39A51E6Q943MWMFDA) という製品。
![81Y16YH7wfL._SL1500_.jpg](https://qiita-image-store.s3.amazonaws.com/0/372272/ecca9629-5121-db4d-305f-381c01653b9b.jpeg)
今日時点で USB 3.1 Gen2 接続の RAID 5 エンクロージャーにはあまり選択肢がなかったこともあるが、製品レビューの中に「WINDOWS 10を最新にアップしたら使えなくなった」などとあったのもこの製品に魅力を感じた点の一つ。さっそく取り寄せてみると、案の定 Windows10 Update 1809 との組み合わせだと一筋縄ではいかないようだ。具体的にはこのエンクロージャーに RAW HDD を組み込み USB に接続してみると：

1. 個別の RAW HDD が Windows から中途半端に認識されてしまう（接続・切断を繰り返す）
2. RocketStor RAID Manager からこれらの RAW HDD に接続できない

どうやら Windows10 Update 1809 がこれらの RAW HDD を直接握ってしまっているようだ。このままでは RAID を構築することができないので、Device Manager で様子をうかがってみると、どうやら「UAS マス・ストレージデバイス記憶域コントローラー」というのが悪さをしているらしい（試しにこのコントローラーを Disable にしてみると個別の RAW HDD が Windows10 に握られてしまうこともなくなるが、同時にこれらの RAW HDD が RAID Manager からも見えなくなってしまうので、このコントローラーを単純に Disable すれよい、というようなものでもないらしい）。
![device manager.png](https://qiita-image-store.s3.amazonaws.com/0/372272/78487bbf-5f33-5195-4aca-0c174475ead5.png)
そんなわけで何か方法がないか、試行錯誤をしていて気が付いたのが、マシンを Reboot してからこれらの RAW HDD が Windows に「握られてしまう」までに少し時間があるという点。ならばそれまでの間に RocketStor RAID Manager を手早く立ち上げて Create Array してしまえばよいのではないか。というわけで、その通りやってみた結果がこちら。
![RS6114V.PNG](https://qiita-image-store.s3.amazonaws.com/0/372272/358609e4-671a-1d74-6038-8378f3fecee8.png)
すんなりとセットアップが通り、これまでのところ運用にも支障は出ていない。

## UPS を組み込む

ボクがまだ若かったころのシステムでは、これは実地に見たことはないのだが、無停電電源として巨大なフライホイールが稼働していたらしい。電源がある間はモーターでこのフライホイールをぶん回しておき、電源が落ちるとこのフライホイールが発電機を回すことによって束の間の猶予時間を稼ぐという仕組み。当時、作業中のコンソールに「The system is going down in 5 minutes.」などというメッセージが表示されるのを何度か目撃した記憶があるが、おそらくそのタイミングで電源の切り替えが起きていたのだろうと推察する。

今回チョイスした UPS は [CyberPower 750VA/525W CP750SWLTJP](https://www.amazon.co.jp/gp/product/B004L2JJAU/ref=ppx_yo_dt_b_asin_title_o06_s00?ie=UTF8&psc=1) という製品。選択肢はいろいろとあったのだが、この製品にはフロントパネルに状況インジケーターがあるのが良さげだったので。
![41Y1Opc849L.jpg](https://qiita-image-store.s3.amazonaws.com/0/372272/ebc758de-3ad9-09bf-852f-37c88d370e90.jpeg)
この UPS には PC 側から電源の残り時間をモニターする機能が用意されていて、あらかじめ閾値をセットしておくと UPS の電源が落ちてしまう前に PC 側から Shutdown をかけることができるようになっている。以前の UPS にはこんな気の利いた機能はなかったような気がするのは気のせいか。
![UPS.png](https://qiita-image-store.s3.amazonaws.com/0/372272/1ba4c7fb-1a74-dd09-cf70-d7094292ded3.png)

## まとめ

いつになっても新しい環境というのは気分がよろしい。
次回はデモ機として入手した [ThinkPad 13](https://www.lenovo.com/jp/ja/notebooks/thinkpad/ThinkPad-13-Windows-2nd-Gen/p/22TP2TX133E) の改造について書いておこう。
再帰の最大回数を確認する/設定する

再帰の最大回数を確認したい場合は`sys.getrecursionlimit`、設定したい場合は`sys.setrecursionlimit`をそれぞれ利用します。なお2つのメソッドのドキュメントはそれぞれ次の通りです。

- `sys.getrecursionlimit`: https://docs.python.org/ja/3/library/sys.html#sys.getrecursionlimit
- `sys.setrecursionlimit`: https://docs.python.org/ja/3/library/sys.html#sys.setrecursionlimit

実際的なアプリケーション開発において、再帰が必要になることは少ないと思いますが、たとえば競技プログラミングでは再帰関数を実装する機会が多々あります。そのような場合に`sys.setrecursionlimit`を覚えておくと、とても便利です。というのは、再帰の最大回数を増やしてやるだけで、ACするケースが意外にあるからです(個人的な体感)。逆に言うと、再帰の回数がデフォルト値だと少なすぎ、そのせいでRuntime Error (RE; Stack Over Flow)になっているケースが少なからず存在するということです。

では簡単に実験してみましょう。なおPythonのバージョンは`3.7.2`になります。

`fib`は再帰を用いてフィボナッチ数列を求める関数です。`sys.setrecursionlimit`により再帰の最大回数を変えることで、`fib`がStack Over Flowになったり、正しく数値を求めることができたりする様子が確認できます。

```python
>>> import sys
>>> fib = lambda n: 1 if n < 2 else fib(n - 1) + fib(n - 2)
>>>
>>>
>>> sys.setrecursionlimit(10)
>>> sys.getrecursionlimit()
10
>>> fib(20)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
  File "<stdin>", line 1, in <lambda>
  File "<stdin>", line 1, in <lambda>
  [Previous line repeated 6 more times]
RecursionError: maximum recursion depth exceeded in comparison
>>>
>>>
>>> sys.setrecursionlimit(100)
>>> sys.getrecursionlimit()
100
>>> fib(20)
10946
```
2日目　ruby基礎,rails_scaffold(スキャフォールド)

##文字コードの設定
ソースコードの文字コードをUS-ASCIIに設定する時は以下の３つのどの書きかたでも合ってる。
` # coding: us-ascii `
` # encoding: us-ascii `
`# CODING: US-ASCII`

##変数と定数
rubyの場合、変数を定義する時は、小文字、定数を定義する時は、最初の文字が、大文字。以下に例を示す。
`komozi=1`
`Oomozi=3.14`

##例外処理（begin rescue ensure）
beginの処理がエラーだった場合に、rescueの処理が実行される。ensureには、beginの処理がエラーでも、エラーじゃなくても処理される。

##三項演算子
以下の２つの実行結果は同じである。

```
x = 10
y = x < 10 ? "A" : "B"

puts y
```

```
x = 10
y = nil
if x < 10
  y = "A"
else
  y = "B"
end
puts y
```
##引数（*a）
以下のようにコードを書くと、実行結果が配列として出てくる。

```
def foo(*a)
  p a
end

foo(1,2,3)
```
##繰り返し
繰り返しはeach,step,uptoメソットがある。
以下は例文。
・each

```
money = 1000
(1..10).each do
  (1..10).each do
    money = money + 1
  end
end

puts money
```
・step

```
money = 1000
rate = 1.1
(2001..2010).step(2) do |i|
  money = money * rate
end
puts money.to_i
```

 ・upto

```
money = 1000
rate = 1.1
2001.upto(2004) do
  money = money * rate
end
puts money.to_i
```

##scaffold(スキャフォールド)
ruby on rails でアプリケションを作る際の便利ツール。本来、railsでは、モデル、コントローラー、ビュー、ルーティングを作る必要があるが、scaffoldを使えば、これらの作業をまとめて行って、簡単にアプリケーションの雛形を作ってくれる。

##今日の授業の感想
今日はRubyの基礎を午前に行い、午後はscaffoldを用いて、フォームを作成した。午前は問題に出されたコードが、どのような処理を行うのかを学び、色んな発見があって理解が深まった。しかし、午後の授業に追いついて行けなかった。railsの環境構築も行ったが、〜をして、次に〜をしてくださいと言われても、どこで実行すればいいのかもわからず、（macでとか、mysql、railsとか）、専門用語も多いので、それが何の意味を指していて、なんでそれを実行する意味があるのかもわからず、自分の非力さを感じた。現在何をしているのかが全く分からなかった。事前課題はprogateで指定されたことを一通り行ったが、それだけではついていけなかった。授業の復習を行い、少しずつ理解を深めて行きたい。
D3のコードをES5からES6に書き直す場合はthisの扱いに注意

# はじめに
ES5書かれていたd3のコードをES6に書き直した際に、文法的には間違っていないのにエラーが発生したのでメモ。

# 問題
`selectAll()`で取得した要素を`each()`でループ処理する際に、各要素を適切に取得できていなかった。

## エラー箇所
修正後

```js
d3.selectAll('.hoge')
  .each(d => {
    const fuga = d3.select(this); // DOM内にhogeクラスはあるのに変数fugaがundefinedてしまう
    fuga.append('piyo')
    ...
  })
```

修正前

```js
d3.selectAll('.hoge')
  .each(function(d) {
    const fuga = d3.select(this); // DOM内にhogeクラスはあるのに変数fugaがundefinedてしまう
    fuga.append('piyo')
    ...
  })
```

## エラー内容

```console
d3 select this createElementNS' of undefined"
```
`select()`で要素が適切に取得できていないため、DOM操作に失敗していた。

# 原因
**アロー関数内の`this`はスコープが従来と異なるため**

詳細は以下の記事に詳しく書いてありました。
[アロー関数はthisの値を語彙的に束縛する”らしい]  (https://qiita.com/mejileben/items/69e5facdb60781927929#%E3%82%A2%E3%83%AD%E3%83%BC%E9%96%A2%E6%95%B0%E3%81%AFthis%E3%81%AE%E5%80%A4%E3%82%92%E8%AA%9E%E5%BD%99%E7%9A%84%E3%81%AB%E6%9D%9F%E7%B8%9B%E3%81%99%E3%82%8B%E3%82%89%E3%81%97%E3%81%84) @ Qiita

# 対策

1. 従来のES5の文法で`function`を定義
2. d3で用意されている引数を利用

2のやりかた

```js
d3.selectAll('.hoge')
  .each((d, i, nodes) => {
    const fuga = d3.select(nodes[i]);
    fuga.append('piyo')
    ...
  })
```

# おわりに
`ES5の関数定義 = ES6のアロー関数定義` とひとくくりに考えていたためハマってしまった。よくよく考えると、文と式の違いだからスコープが違うのは当たり前か。
AWS CloudWatchメトリクスマス計算による数式関数を使用した可視性向上

#CloudWatchでメトリクス数値を四則演算する


![image.png](https://qiita-image-store.s3.amazonaws.com/0/276897/ad2a9048-ed27-18bb-15b0-08b574c82bbb.png)
###サーバー1のCPU使用率　と　サーバー2のCPU使用率

これらの平均が80%を超えた時、Auto Scalingが発動する…
よくある設計だ。


![pic2.jpg](https://qiita-image-store.s3.amazonaws.com/0/276897/ab919e51-ef1f-681a-79a0-6cad277cd12e.jpeg)

CPU使用率のメトリクスを2つ選択した後、

[グラフ化したメトリクス]タブで
[+数学式の追加]を押下しよう。

すると、ラベルが [式1] となったメトリクスが現れる。


![pic3.jpg](https://qiita-image-store.s3.amazonaws.com/0/276897/97fda1f4-152f-8c1b-6fe0-2167b6bda5c4.jpeg)
詳細欄に四則演算を書いてみよう。

```
(m1 + m2) /2
```

（サーバー1のCPU使用率 + サーバー2のCPU使用率）/ 2

　※m1やm2はメトリクスの[Id]のラベルの名前に紐づく

完成。

#まとめ

アイディア次第によっては色々な数式を試せる。

↓冗長化サーバーのCPU使用率平均。AutoScalingの発動目安になる

```
(CPUUtilization + CPUUtilization) /2
```


↓500エラー（リクエストに対するサーバー側のエラー）発生率

```
100 * HTTPCode_Target_5xx_Count ÷ Request_Count
```
↓RDSの読み込み使用率

```
100 * ConsumedReadCapacityUnits ÷ ProvisionedReadCapacityUnits
```


参考
https://aws.amazon.com/jp/blogs/mt/amazon-cloudwatch-metric-math-simplifies-near-real-time-monitoring-of-your-amazon-efs-file-systems-and-more/
英語OKな方ならこちらも参照して頂きたい。

ありがとうございました。
少しでもお役にたちましたら「いいね」をよろしくお願いします。
【SwiftChaining】 バインディング処理を確定する関数

[SwiftChaining](https://github.com/objective-audio/SwiftChaining)の解説記事その5です。

[SwiftChaining](https://github.com/objective-audio/SwiftChaining)とは何か？というのは、こちらの[最初の記事](https://qiita.com/yasos/items/4d8dd0d1aa63605dc63b)を参考にしてください。

[前回の記事](https://qiita.com/yasos/items/ff4486908684038bdc5c)では、監視対象のオブジェクトの`chain()`を呼んだ後に繋げて書く「処理を構築する関数」の解説をしました。

今回は、「バインディング処理を構築した後に確定させて監視を開始する関数」について少し詳しく解説しようと思います。

今まで何度も出てきたものになるのですが、`end`と`sync`についてです。

# バインディング処理を確定する関数

## end

`end`は、`chain()`の後に繋げて書いて構築したバインディング処理を確定し、監視を開始します。

```swift
let notifier = Notifier<Int>()

let chain1 = notifier.chain()

// ここではまだ監視は始まらず処理が追加できる
let chain2 = chain1.do { _ in }

// endを呼んで処理が確定し監視が始まる
let observer = chain2.end()

// endの後に処理を追加しようとするとfatalErrorになる
// chain2.do { _ in }

observer.invalidate()

// invalidateされたので監視は止まる
```

`end`は返り値に`Observer`のインスタンスを返し、それ以降はもう処理をつなげることはできません。処理を追加しようとしても`fatalError`になります。

なお、`end`を呼んだ時点では何もイベントは起きず、その後監視対象のオブジェクトからイベントが発生したら`chain()`以降で書いた処理が実行されます。バインディングという意味では、監視を開始したタイミングで値を知りたくなるのですが、その場合は次で紹介する`sync`を呼ぶことになります。

## sync

`sync`は、`chain()`の後に繋げて書いて構築したバインディング処理を確定し、1度イベントを送信させた上で監視を開始します。

```swift
let sender = ValueHolder(1)
let receiver = ValueHolder(0)

let observer = sender.chain()
    .sendTo(receiver)
    .sync()

// syncが呼ばれたことによってreceiverは1になっている
print(receiver.value)

sender.value = 2

// 変更を監視しreceiverは2になっている
print(receiver.value)
```

監視対象のオブジェクトが常に値を返すことのできる場合に使うことができ、`sync`を呼ぶと内部的に`end`を呼びつつ、監視対象のオブジェクトから一度イベントを送らせる事が出来ます。

`end`だと変更があったら送られるだけですが、`sync`で監視し始めにも送ることによって繋げた値を同期させられるという感じです。

なお、監視対象のオブジェクトからはいくつも`chain()`を呼んで複数の場所から監視ができ、普通に対象の値が変更された時のイベントはその全部に対して送られますが、`sync`を呼んだ時のイベントはそのひとつだけに送られます。

ちなみに、ここで出てきた「常に値を返すことのできる」オブジェクトというのは何かと言うと、今までの記事で紹介したものの中では…

* ValueHolder
* KVOAdapter

というクラスのオブジェクトになります。

逆に「値を返す事ができない」クラスは…

* Notifier
* NotificationAdapter
* UIControlAdapter

などです。後者のような値を持っていなくて返すことができないオブジェクトからのみ処理が繋がっている場合は`end`でしか終わらせることができません。

`merge`などで値を返せるオブジェクトと返せないオブジェクトの処理を混ぜた場合には`sync`を呼ぶことはできますが、無い袖は振れないので値を返せるオブジェクトからのみイベントが送信されます。

なお、「値を返せる」「値を返せない」の違いは何かと言うと、`SwiftChaining`的には適合しているプロトコルに[`Fetchable`](https://qiita.com/yasos/items/bacc276397606bc7dca1#fetchable)が含まれているかということなのですが、これは[次の記事](https://qiita.com/yasos/items/bacc276397606bc7dca1)で解説します。
Python seleniumでわからないことを解決する記事

#概要
Seleniumを使用していてわからなかったところを、誰かの役に立てばよいということから書きます。
WebScraypingは著作権違法などに気を付けて行ってください（詳しくは@nezuqさんが書かれた<a href="https://qiita.com/nezuq/items/3cc9772118ad112c18dc">記事</a>を参考にしてください。）

#Selenium API リファレンス
http://www.seleniumqref.com/

#Seleniumの良記事紹介
<a href="https://qiita.com/memakura/items/20a02161fa7e18d8a693">すばらしい記事</a>にて導入の仕方と、簡単なチュートリアルが書かれています。勘が良い方はこれだけをみてわかると思いますが、具体的にどうすればよいかわからないことがあったので、補完する意味合いの記事です。

#スクレイピング画像保存
requestsを使ってください。Bit単位でファイルに保存してます。

```python
import requests
src = driver.find_element_by_id("A").get_attribute("src")
imagename = src.split("/")[-1]
with open("img/"+imagename, "wb") as f:
    re = requests.get(src)
    f.write(re.content)
```

#Tableの詳細一覧を個別に取得したい
for分を使ってループ処理します。下コードは場所を特定したかったのでenumerateを使ってindexも取得しています。

```python
scroll = driver.find_element_by_id("A")
table = scroll.find_element_by_tag_name("table")
thead = table.find_element_by_tag_name("thead").find_element_by_tag_name("tr").find_elements_by_tag_name("th")
for i, th in enumerate(thead):
    explain += "<th>"+ th.text+ "</th>"
tbody = table.find_element_by_tag_name("tbody").find_element_by_tag_name("tr").find_elements_by_tag_name("th")
for i, th in enumerate(tbody):
    explain += "<th>"+ th.text+ "</th>"
```

#あるID以下のHTMLだけほしい
innerHTMLをgetする

```python
kore = driver.find_element_by_id("kore")
element_html = kore.get_attribute("innerHTML")
```

#ID_Aの下のtagBの中のtagCの中のhrefがほしい
Xpathを使って素直に書くこともできますが、こういう書き方もあるよとご参考になれば

```python
href = driver.find_element_by_id("A").find_element_by_tag_name("B").find_element_by_tag_name("C").get_attribute("href")
```

#指定されたIDがあるかチェックしたい
find_elements_by_idでlistで取得して、サイズを確認して個別処理を走らせる

```python
if(len(driver.find_elements_by_id("A")) > 0):
    a = hogehoge(driver)
```

#ソースをごそっと抽出したい
driverからBeautifulSoupを使います。

```python
from bs4 import BeautifulSoup
page_source = driver.page_source
soup = BeautifulSoup(page_source, 'html.parser')
ab3 = soup.find(id="AB3")
```

#iframeの中を取得したい
<a href=https://qiita.com/motoki1990/items/a59a09c5966ce52128be>素晴らしい記事がありました</a>
スクロールしないとダメなケースがありますので、そのケースの場合は
# javascriptを実行してページの最下部へ移動
```python
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
```
##javascriptで行う場合
```python
javascript_ret=driver.execute_script("return data.contentDocument.body.innerHTML;")
soup=BeautifulSoup(javascript_ret,"html.parser")
#処理
```
##seleniumで頑張る場合
```python
dd=driver.find_element_by_id("detailFrame")
driver.switch_to_frame(dd)
```

## selectboxの中を操作したい

参考になるリンクがあったので、こちらをご参照ください
https://yuki.world/selenium-select/
自宅の検証環境にNginxによるForward Porxyを構築する

自宅環境にNginxによるForward Porxyを導入した際の手順とかをまとめてみます。
実は自宅外の勉強会等で検証用MacBookProを持ち出し、現地で作業する際に非セキュアなフリーWiFiや、提供されたWiFiでは自宅のIPアドレスセグメントに接続する形式では不都合が生じるからです。
ということで、MacBookPro内に検証LANをホストオンリーネットワークとして構築し、検証LAN内にForward Proxyを置き、検証LANからは必ずForward Proxyを経由する方式にします。

# ソフトウェア
- CentOS Linux release 7.6.1810 (Core) 
- Nginx 1.14.2

# 構築手順

構築した際の手順は下記の通りです。

## Nginxのリポジトリを追加
Nginxのリポジトリを追加します。
CentOSとRHELではURLパスが異なるので注意しましょう。
詳しくはNginx(公式)のInstallを読んでください。

```
$ sudo vi /etc/yum.repos.d/nginx.repo
```

```nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1
```

## Nginxをインストール
```
$ sudo yum install nginx
````

## Forward Proxyの設定ファイルを作成
作成するファイルと内容は下記の通りです。
ファイル名は何でも良いですが、機能ごとに分けて管理します。

```
$ sudo vi /etc/nginx/conf.d/forward-proxy.conf
```

```forward-proxy.conf
server {
    # Proxy Server port
    listen 3128;

    # DNS server
    resolver         8.8.8.8;
    resolver_timeout 5s;

    location / {
        proxy_pass $scheme://$http_host$request_uri;
    }
}
```

## 設定ファイルのチェック
```
$ sudo /usr/sbin/nginx -t
```

## Nginxの起動と自動起動の設定
```
$ sudo systemctl start nginx
$ sudo systemctl enable nginx
```

## Proxyのテスト
yumの通信が正しく行えるか確認してみます。
まずは他のサーバのyum.confにproxyの設定を入れます。

```
$ sudo vi /etc/yum.conf
```

```yum.conf
proxy=http://プロキシサーバのIP:3128
```

`yum update`コマンドでうまく通過するか確認する。

```
$ sudo yum update
```

成功です！

## ちょっとハマったところ

### 1. Nginxが起動しない

forward-proxy.confを作成し、Nginxをstartさせた際、何故か起動に失敗しました。

```
nginx: [emerg] bind() to 0.0.0.0:3128 failed (13: Permission denied)
```
と表示されていて、ピンときて`/var/log/audit/audit.log`を見るとSE Linuxで弾かれてました。とりあえずはSE Linuxを無効化して対応です。

### 2. Forward Proxyが通過できない

Forward ProxyのサーバでFirewalldが動いていて接続ができない状態でした。
忘れずに止めるか許可する設定を入れましょう。私は止めました。

```
$ sudo systemctl stop firewalld
$ sudo systemctl disable firewalld
```
# 参考サイト

[SIOS TECH.LAB "Nginxを使ってみよう"](https://tech-lab.sios.jp/archives/10767)
[Nginx(公式) Install](https://www.nginx.com/resources/wiki/start/topics/tutorials/install/)
homebrew チートシート

# ダウンロードキャッシュを全て削除する

```shell-session
$ brew cleanup -s
```

# インストール先を確認する

```sh
brew ls パッケージ名
```


# 任意の場所にインストールする

https://github.com/Homebrew/brew/blob/master/docs/Installation.md#untar-anywhere

bundlerとかnpmみたいにプロジェクト固有のbrewツリーを用意できるかも。

```sh
mkdir homebrew
curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C homebrew
```

**formulaのインストール**

```sh
./homebrew/bin/brew install ffmpeg
```


# Linuxでbrewをセットアップする

https://docs.brew.sh/Homebrew-on-Linux の`Install`に書いてある手順だと、sudoが有効だと勝手に`/home/linuxbrew/.linuxbrew/`にインストールされてしまうという謎仕様なので（一応スクリプトを見てみたがインストール先を変えられるオプションは無いっぽかった）、[`Alternative Installation`](https://docs.brew.sh/Homebrew-on-Linux#alternative-installation)に書いてある手順でインストールします。

```sh
git clone https://github.com/Homebrew/brew ~/.linuxbrew/Homebrew
mkdir ~/.linuxbrew/bin
ln -s ../Homebrew/bin/brew ~/.linuxbrew/bin
eval $(~/.linuxbrew/bin/brew shellenv)    # <= インストール終了後、この行を ~/.bashrc に追加する
```
WSL(Ubuntu) セットアップメモ

# ホームディレクトリの変更
- こちらの記事を参考
    - https://qiita.com/funafuna/items/c3bb78a546cf2605205d

- 以下のように、/mnt/cでCドライブにマウントできる

```
$ ls -la /mnt/c
```

- Cドライブ直下にlinux_home作ってそこをホームディレクトリにする場合
- etc/passwdファイルを以下のように変更

```
$ sudo vim /etc/passwd
root:x:0:0:root:/mnt/c/linux_home:/bin/bash
```
- 再起動して反映される

# ビーブ音を消す
- こちらの記事を参考
    - https://linuxfan.info/bow-stop-beep

```
$ echo "set bell-style none" >> ~/.inputrc
```

- vim使用時の警告音を消す

```
$ echo "set visualbell t_vb=" >> ~/.vimrc
```

- どちらも再起動後に反映される