OmniAICreator/Qiita-1.07M huggingface dataset:
各種 Linux の chroot による開発環境の分離まとめ

# chroot による開発環境の分離まとめ

OpenCV によるクロスプラットフォーム開発において Linux の開発環境を chroot で本体から切り分けたかったので。

※ とはいえ一番簡単なのは Docker だと思う。

※ FreeBSD なら jail。

※ macOS には chroot 有り。brew の jailkit や brew 自身と併用で色々出来そう。

※ Windows なら UNIX Like な開発環境は Cygwin にせよ MSYS2 にせよ WSL1 や WSL2 にせよある程度分離されている気がしないでもないので割愛。

## chroot について
https://wiki.archlinux.jp/index.php/Chroot

## Debian/Ubuntu
pbuilder を使用する
https://www.debian.org/doc/manuals/maint-guide/build.ja.html
https://wiki.ubuntu.com/PbuilderHowto

<details><summary>参考とした文献</summary><div>

https://hnakamur.github.io/blog/2017/09/02/add-repositories-to-pbuilder-chroot-images/

</div></details>

## Fedora/RHEL/CentOS
mock を使用する
https://github.com/rpm-software-management/mock/wiki

<details><summary>参考とした文献</summary><div>

https://hnakamur.github.io/blog/2015/12/16/how_to_debug_errors_in_rpm_build_using_mock/
https://hnakamur.github.io/blog/2015/12/18/add_third_party_to_build_on_mock_and_copr/
http://manpages.ubuntu.com/manpages/bionic/man1/mock.1.html
https://blog.packagecloud.io/eng/2015/05/11/building-rpm-packages-with-mock/

</div></details>

## Slackware/Zenwalk/SalixOS
インストールCD から対象ディレクトリに展開・導入する
https://docs.slackware.com/howtos:general_admin:setting_up_a_slackware_chroot

あとは通常手順で chroot

## Arch
pacstrap コマンドを用いる
https://wiki.archlinux.jp/index.php/インストールガイド#ベースシステムのインストール

```sh:例
pacstrap /var/tmp/chroot base base-devel
```

あとは通常手順で chroot

## Manjaro
extra/manjaro-tools-base に含まれる basestrap コマンドを用いる
https://wiki.manjaro.org/index.php?title=Manjaro-tools

```sh:例
basestrap /var/tmp/chroot base base-devel
```

あとは通常手順で chroot

## Gentoo
stage3 イメージを対象ディレクトリに展開する
https://wiki.gentoo.org/wiki/Handbook:AMD64/Installation/Stage/ja

あとは通常手順で chroot

## Sabayon
Sabayon_Linux_＜年＞.＜月＞_amd64_tarball.tar.gz を対象ディレクトリに展開する

```sh:例
mkdir /var/tmp/chroot
cd /var/tmp/chroot
curl -LO http://＜ミラーのSabayonのディレクトリ＞/stable/Sabayon_Linux_＜年＞.＜月＞_amd64_tarball.tar.gz
#以下は理研のミラーの場合
#curl -LO http://ftp.riken.jp/Linux/sabayon/stable/Sabayon_Linux_19.03_amd64_tarball.tar.gz
tar xpvf Sabayon_Linux_＜年＞.＜月＞_amd64_tarball.tar.gz --xattrs-include='*.*' --numeric-owner # アーカイブの展開
```

あとは通常手順で chroot
herokuデプロイ　背景画像表示させる

##記事投稿の理由
初めてherokuでデプロイした際に画像が表示されなくて苦しんだので
復習兼ねて記事書かせていただきます。
環境によって違う場合もある。参考程度にみてくださると幸いです。

###今回のテーマと環境
rails 5.0.7.2

herokuでデプロイはできていて
画像のみが表示されないと仮定します。

### 変更箇所

assetファイルは事前にコンパイルしておきます。
しかしassetファイルが見つから無い場合にtrueにしておくとサーバー側でコンパイルしてくれるそうです。
ただし、コンパイルによりサーバー側の負荷も上がるのでここは環境によって変わると思います。

今回私の場合はconfig.assets.compile = falseのところをtrueに変更して対応しました。

```production.rb
# Do not fallback to assets pipeline if a precompiled asset is missed.
  config.assets.compile = true
```

config.assets.css_compressor = :sassのコメントアウトを外して
私の場合scssファイルで色付けなど行なっていたため
config.assets.css_compressor = :scssに変更

```production.rb
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier
config.assets.css_compressor = :scss
```


背景画の設定しているところを
background-image: url("china.jpg");から下記に変更

```index.scss
.contact{
  background-image: image-url("china.jpg");
```

asset_pathの追加
＜img src="freemarket.png" alt="制作事例１" width=500px height=280px＞を下記に変更


```index.html.erb
<li class="portfolio">
        <a href="http://18.177.66.99/" class="portfolio-image">
          <img src="<%= asset_path "freemarket.png" %>" alt="制作事例１" width=500px height=280px >
        </a>
      </li>
```

あとherokuにファイル送付する前に開発環境のコンソールにて下記忘れないように。。

```
$ rake assets:precompile RAILS_ENV=production
```

###最後に
僕はこのような方法でデプロイした際にうまく画像が表示されるようになりました。
環境によっても違うと思いますが参考になれば・・・・

##参考にさしていただいたサイト
[Rails4 asset pipeline関連設定まとめ](https://qiita.com/tomomomo1217/items/fa8dfa094cc4c0e4e350)
[Rails4ではbackground:url("assets/hoge.png")の書き方は動かない話](https://qiita.com/wadako111/items/03bc00d914e62243a511)
[Rails初学者がつまずきやすい「アセットパイプライン」](https://www.transnet.ne.jp/2016/02/28/rails%E5%88%9D%E5%AD%A6%E8%80%85%E3%81%8C%E3%81%A4%E3%81%BE%E3%81%9A%E3%81%8Dcolnr%E3%80%8C%E3%82%A2%E3%82%BB%E3%83%83%E3%83%88%E3%83%91%E3%82%A4%E3%83%97%E3%83%A9%E3%82%A4%E3%83%B3/)
[HerokuにRubyのデータをデプロイ後、画像が見れない
](https://ja.stackoverflow.com/questions/26659/heroku%E3%81%ABruby%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E5%BE%8C-%E7%94%BB%E5%83%8F%E3%81%8C%E8%A6%8B%E3%82%8C%E3%81%AA%E3%81%84%E7%8A%B6%E6%85%8B%E3%81%A7%E3%81%99)
Oculus Link 時に FMOD failed to initialize the output device エラーが出たときの対応方法

Oculus Link しようとした時に、`FMOD failed to initialize the output device` エラーが出たときの対応方法です。このエラーが出ると、AVPro ではファイルがありませんというエラーが出るようになり、知らないと迷走するなと思いました。（実際迷走した）

# 前提
* Windows10
* Unity 2019.2.02f
* Oculus Integration 12.0
* AVPro
* 元々開発中のプロジェクトで、本エラーが発生する前は Unity Editor で正常に動作していた
    * ビルドして、adb install すれば、Oculus Questでも正常に動作していた

# 再現手順
1. Oculusの管理アプリケーションをインストール
2. Unity から Editor 実行

# エラー
Unity Edtior から実行すると、

```
FMOD failed to initialize the output device.: "Error initializing output device. " (60)
```

とエラーが発生した後に、AVPro からも以下エラーが発生した。

```
[AVProVideo] Error: Loading failed.  File not found, codec not supported, video resolution too high or insufficient system resources.
UnityEngine.Debug:LogError(Object)
RenderHeads.Media.AVProVideo.MediaPlayer:UpdateErrors() (at Assets/AVProVideo/Scripts/Components/MediaPlayer.cs:1783)
RenderHeads.Media.AVProVideo.MediaPlayer:Update() (at Assets/AVProVideo/Scripts/Components/MediaPlayer.cs:1107)
```

# 解決方法
Oculus の管理アプリケーションをインストールすると、音声の箇所が下記の通り、 `ヘッドホン（Oculus Virtual Audio Device）`となるようです。この設定値を変更するだけで解消されます。
![2019-12-23_14h34_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/580171ff-d0ef-d5a7-22b7-ffb2efe89aef.png)
iOSアプリのバージョンアップをApple Storeへ提出するメモ

iOSアプリのバージョンアップを Apple Store へ提出するときいつも悩みます。今回は個人メモをまとめて記事にしてみました。

## 審査提出までの手順

<table boder="0">
<tr>
<td width='50%'><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253995/8892c7c5-2d19-b1fc-24b9-87f98ca25d18.png">
<td>Generic iOS Device を選択

<tr>
<td><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253995/b34dee2f-052e-cfa4-073b-1737714b8c70.png">
<td>実行ボタンの右側のプロジェクト
<br>EditSchema
<br>Release に変更

<tr>
<td><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253995/ecb51285-475e-2427-725e-5d5cdc6d5c76.png">
<td>Product → Archive
<br>Distribute APP（青いボタン）
<br>App Store Connect
<br>Upload

<tr>
<td><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253995/fdb6b2d8-d3c6-6d2b-6bc8-334663bc2c57.png">
<td>include bitcode for ios content
<br>Strip Swift symbols
<br>Upload your app's symbols ...
<br>３つともチェック
<br>＊クラッシュログをAPPに送るなど

<tr>
<td><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253995/25932fed-7e87-97e0-2c67-38c0e385a1d1.png">
<td>Automatically manage signing を選択
<br>Upload （5分ほど待ちます）

<tr>
<td><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253995/7e95953a-55a0-c554-4ddd-ae1fa0e3a1b9.png">
<td>Apple Developer へサインイン
<br>(＋)バージョンまたはプラットフォーム
<br>＊6桁の数字でエラーの場合、英字入力
<br>＊AppleStoreは12/23〜27はお休みです

<tr>
<td><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253995/2f0b5db8-2d6c-363b-adde-770bc698b762.png">
<td>アプリの更新情報を記入

<tr>
<td><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253995/a29cdebc-6f44-1757-89c8-d23b5354f4f1.png">
<td>ビルド(＋)ボタンで追加します
<br>＊ビルドが表示されない場合、30分ほど待ちます

<tr>
<td><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253995/6eb754e4-aae2-2810-5bf7-27322b69c6a2.png">
<td>審査へ提出
<br>できない場合、completed processing というメールが来るまで30分ほど待ちます

<tr>
<td><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253995/b479a56c-640d-096b-6d57-177e48940e12.png">
<td>輸出のコンプアライアンスと広告ID
<br>送信
<br>状態が審査待ちになります
</table>

# ポイント
- ブラウザから Apple Developer へのサインインで、6桁の数字でエラーになる場合は、キーボードを英字入力にしてください。
- 12/23〜27 は Apple Store も Xmas 休暇です（みんなも休もう）
- 私のアプリは顔を検出して黒塗りにする機能があるのですが、顔データに関するプライバシーポリシーが必要なのだそうです。
- 今回の戦い  
12/21 審査提出  
12/24 リジェクト（顔データに関するプライバシーポリシーがない）  
12/29 再提出  
12/30 リジェクト（プライバシーポリシーが不十分）  
01/04 再提出  
01/04 Ready for Sale（やたー！）

# まとめ
これまで審査でバイナリのリジェクトは一回もなく、すべてメタデータの再提出です。プライバシーポリシーは英語のみで出しているので難しいです。最近は YouTube にアップロードしてもいろいろ聞かれますよね。個人情報の取り扱いなど、プログラマーも知っておくべきでしょう。今回はとても勉強になりました。
form_withでデフォルトのデータ送信先を変更する[Rails]

ポートフォリオアプリを作っています。
作品の一覧と各作品の詳細は誰でも見られるようにしようと思いますが、作品の投稿と編集は管理者だけができるようにしたいと思います。

管理者ユーザーの作成は、過去の自分のこちらの記事を読んで実装できたのですが、

[【初心者向け】管理者ユーザーと管理者用controllerの追加方法[Ruby, Rails]][1]
[1]:https://qiita.com/tanutanu/items/7ce8826615f1af605164

その後、管理者ユーザーの投稿機能をつけ、submitボタンを押したときに、以下のようなエラーが出ました。

[![Image from Gyazo](https://i.gyazo.com/e987d1db32f9084329e6e98e980551c6.png)](https://gyazo.com/e987d1db32f9084329e6e98e980551c6)

何、`/works`に**POST**メソッドでつながるルーティングがないそうです。
確かに、`rake routes`で確認してみると、管理者ユーザーが画像を投稿するときのルーティングは`admin_works_path`で、URLも `/admin/works`です。

```
      works GET    /works(.:format)  works#index                                                                    
       work GET    /works/:id(.:format)  works#show                                                                   
admin_works GET    /admin/works(.:format)  admin/works#index                                                                  
            POST   /admin/works(.:format)  admin/works#create                                                                  
```
ところが、form_withの記述を見直してみても、以下の通り。

```ruby
= form_with model: @work, local: true do |f|
 # 中略
 =f.submit
```
そうでした、form_withは投稿先のメソッドに応じて、よしなにURLを変更してくれるのでした。ちなみに、これで`POST(create)`にも`PATCH(edit)`にも対応してくれます。わー、便利。

ですが、今回はこちらのデフォルトのURLを変更しなければいけません。
form_withのAPIドキュメントを翻訳してくれた方がいたので、こちらの記事を参照しました。

[Rails 5.1〜: ‘form_with’ APIドキュメント完全翻訳][2]
[2]:https://techracho.bpsinc.jp/hachi8833/2017_05_01/39502

こちらの記事によると、「ルーティングをadmin_post_urlのように名前空間化する場合は以下のようにします。」とのこと。

```erb
<%= form_with(model: [ :admin, @post ]) do |form| %>
  ...
<% end %>
```
こちらを参考に、hamlに合わせて、以下のように記述を変更しました。
第二引数にurlを追記しています。

```ruby
= form_with model: [ :admin, @work ], local: true do |f|
```

・・・そしたら、、、動いた！！
以上、簡単ですが、form_withのデフォルトの送信先を変更する方法でした＾＾
風水プログラミング

今日は趣向を変えて風水のプログラミングをしてみます。

風水？オカルト？
「そんなの風水師が適当なこと言ってるんじゃないの？」
と思う人もいるかもしれません。

いいえ、そんなことはありません。
風水、九星気学、四柱推命は計算のアルゴリズムがしっかりと確立していて、入力が同じならば出力は同じになるという特徴を持っています。

成立した経緯はわかりませんが、昔の中国の人がたくさんの運命を見てきて統計的な法則を見つけたけどわかりにくいから陰陽五行にあてはめてみたとかそういう類じゃないかと思います。

例えば、風水ならば、竣工年と建物の向きが決まれば、結果は一意に定まります。
四柱推命も誕生の年月日と時間で結果は一意に決まります。

**入力が決まれば出力も一意に決まる** っていいですね。

そのアルゴリズムはちゃんとした本を読めば書いてあります。陰陽五行の話とかいろいろ出てくるのですが、結局のところは、

 - 足し算や引き算をする
 - テーブルを引く
 - 割り算して余りを求める
 - if文で分類して、パターンを減らす

ということを繰り返しています。　

ロジカルで、まさにプログラミングにぴったりですね！

作ったプログラムの一部を示しましょう。
まずは基本のチャートを描くためのもの。

```php
	$a = array();
	$a[0] = $basenum + 8;
	$a[1] = $basenum + 4;
	$a[2] = $basenum + 6;
	$a[3] = $basenum + 7;
	$a[4] = $basenum + 0;
	$a[5] = $basenum + 2;
	$a[6] = $basenum + 3;
	$a[7] = $basenum + 5;
	$a[8] = $basenum + 1;
	$text = "";
	for($i = 0; $i < 9;$i++ )
	{
		$text .= strval(($a[$i] - 1) % 9 + 1);
		if($i != 8) $text .= ",";
	}
```
こういうチャートを描くためのものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542455/62ff322c-fbd9-0e7e-db50-a1e6833bfd47.png)

次は、運星から山星・水星を求めるプログラム。ちょっと複雑になってくるので変数名がaとかだと破綻します。

```php
	$運星 = array(); // 
	$運星["東南"] = 剰余($era + 8); // 
	$運星["南"  ] = 剰余($era + 4); // 
	$運星["南西"] = 剰余($era + 6); // 
	$運星["東"  ] = 剰余($era + 7); // 
	$運星["中央"] = 剰余($era + 0); // 
	$運星["西"]   = 剰余($era + 2); // 
	$運星["北東"] = 剰余($era + 3); // 
	$運星["北"]   = 剰余($era + 5); // 
	$運星["北西"] = 剰余($era + 1); // 

	switch($向) {
		case "N1": case "N2": case "N3":
			$中央水星 = $運星["北"];
			$中央山星 = $運星["南"];
			break;
		case "NE1": case "NE2": case "NE3":
			$中央水星 = $運星["北東"];
			$中央山星 = $運星["南西"];
			break;
		case "E1": case "E2": case "E3":
			$中央水星 = $運星["西"];
			$中央山星 = $運星["東"];
			break;
		case "SE1": case "SE2": case "SE3":
			$中央水星 = $運星["東南"];
・・・（中略）・・・
		case "NW1": case "NW2": case "NW3":
			$中央水星 = $運星["北西"];
			$中央山星 = $運星["東南"];
			break;
	}

	$山星 = array();
	if(  (preg_match("/[23]/",$向) && !($中央山星 % 2))    // 偶数で区分2か3
	  || (preg_match("/[1]/",$向)  &&  ($中央山星 % 2))) { // 奇数で区分1
	  $山星順行 = true;
	}
	else {
	  $山星順行 = false;
	}
	
	$水星 = array();
	if(  (preg_match("/[23]/",$向) && !($中央水星 % 2))    // 偶数で区分2か3
	  || (preg_match("/[1]/",$向)  &&  ($中央水星 % 2))) { // 奇数で区分1
	  $水星順行 = true;
・・・（中略）・・・
	if($中央山星 == 5) { // 5は特別扱い
		if(  (preg_match("/[23]/",$向) && !($era % 2))    // 偶数で区分2か3
		  || (preg_match("/[1]/",$向)  &&  ($era % 2))) { // 奇数で区分1
		  $山星順行 = true;
		}
		else {
		  $山星順行 = false;
		}
	}

```

怪しげな変数名が並んでいます。

PHPは変数名に普通に漢字が使えるし、連想配列が使えるのでわかりやすく書けました。
もし、英数字しか使えないとどうやって英語に訳せばよいかわからなくて困っていたことでしょう。
　
こういう計算を延々とやっていくと、下の図のようなチャートが作られます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542455/4684660c-5957-2a96-3c6c-bfeaafe1274b.png)

こうして年飛星まで入ったチャートをPNGファイルで出力するPHPのプログラムが出来ました。

この数字を求めるところまでは機械的にできるのですが、数字を解釈するところに風水師の経験や勘といったものが必要になります。もちろん、私にはできません。

ある程度の一般的な解釈まではプログラムでもできるかもしれませんが、最終的には人間がいるのでしょう。
MySQLで採番機能（シーケンス）を実装する方法を整理する

## 概要

今更ですが、MySQLで採番機能（シーケンス）が必要になったので、実装方法について自分用に整理してみました。

## 環境

MySQL 8.0.18

## 実装方法

### 方法１．LAST_INSERT_ID(expr) を使う

公式ドキュメントで紹介されている方法です。
[MySQL :: MySQL 8.0 Reference Manual :: 12.15 Information Functions](https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#idm45240483382624)

１. 採番用のテーブルを用意し、ID=0のレコードをINSERTしておく

```sql
CREATE TABLE sequence (id INT NOT NULL) ENGINE=InnoDB;
INSERT INTO sequence VALUES (0);
```

２. `LAST_INSERT_ID`を使用し、連番を取得する

```sql
UPDATE sequence SET id=LAST_INSERT_ID(id+1);
SELECT LAST_INSERT_ID();
```

注意点として、

1. rollbackすると、同一のIDが再度発行される
2. UPDATEで排他ロックがかかる（分離レベル：`REPEATABLE-READ`で検証）

が挙げられます。

### 方法２．AUTO_INCREMENTを使う

「[MySQL で採番テーブル](https://qiita.com/NAKANO_Akihito/items/44db44375a464c72606a)」で紹介されている方法です。

１．採番用のテーブルを用意する

```sql
CREATE TABLE seq_ai (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
) engine = InnoDB;
```

２．新規レコードをINSERTし、`LAST_INSERT_ID`で連番を取得する

```SQL
INSERT INTO seq_ai VALUES (NULL);
SELECT LAST_INSERT_ID();
```

３．採番テーブルにたまるレコードを削除する

```SQL
DELETE FROM seq_ai WHERE id < :id; -- 2で取得した最新のレコードを残して削除
```

方法１の注意点1（rollback時の挙動）については、こちらの方法ではrollbackしても同じIDは発行されません（AUTO_INCREMENTのカウンタはrollbackしても戻らない）。

一方で、こちらの方法だと３のDELETE時に排他ロックが発生します（分離レベル：`REPEATABLE-READ`で検証）。

## 方法３．方法１＋ストレージエンジンをMyISAMにする

方法１の注意点はどちらもトランザクションに起因する問題だったので、採番用テーブルのみストレージエンジンをMyISAMにします。

```sql
CREATE TABLE sequence (id INT NOT NULL) ENGINE=MyISAM;
INSERT INTO sequence VALUES (0);
```

シーケンスの取得方法は方法１と同じです。

```sql
UPDATE sequence SET id=LAST_INSERT_ID(id+1);
SELECT LAST_INSERT_ID();
```

ストレージエンジンをMyISAMにすることで、

- rollbackしても同じIDが発行されない
- 排他ロックがかからない

という状態を実現できます。

## 参考URL

- [MySQL で採番テーブル](https://qiita.com/NAKANO_Akihito/items/44db44375a464c72606a)
- [MySQL で シーケンス 機能実現](https://qiita.com/jlake/items/b92cf5281216825abe58)
- [ID生成方法についてあれこれ](https://qiita.com/j5ik2o/items/1799887fec241c10af39#_reference-c849f9b40250294aad1e)
冬休みのmy宿題として、自宅サーバーを建ててみて感じたこと

##はじめに
いやぁ、冬ですね。寒いですね。
皆さん、年明けいかがおすごしでしょうか？

どこか旅行に行かれてますか？それとも、美味しい物食べて寝正月ですか？
いいですね。

かくいう私は、冬休みの期間を活用して、３ヶ月ほど前からやりたかった自宅サーバーの開設にチャレンジしてみました。
言ってみれば、鯖正月って感じですかねw

セキュリティとか使い勝手は酷いものですが、一応データベースサーバーを作ることができました。
この記事では、サーバー構築してみた経験をポイントに分けて振り返ってみたいと思います。


##作った物のザックリ概要
- PC本体: SONYのVAIO,CPUはintel celeron
- OS: Ubuntu18.04.3 LTS
- その他: Apache2、MySQL5 etc.

試しに、「サーバー建ててみる」という目的で始めたので、昔使っていたノートパソコンを使ってサーバーにしていきました。

##ディストリビューション選定はデスクトップ版のほうがいい！
今回はUbuntuディストリビューションを使っていったんですが、
Ubuntuにはサーバー版とデスクトップ版との２つエディションがあります。

最初は、「サーバー建てるためだから」と、その名前の通りサーバー版を安易に選んでいました。
CLIで環境設定を行うんですが、ここで困ったのがWi-fiの接続です。

めちゃめちゃ基本ですし、ファイルを編集して行うはずなんですが、
何度設定しようとしてもできませんでした、、

###デスクトップ版だと環境設定が楽！
そこで、一度入れたサーバー版のOSを削除してGUIを使うことができるデスクトップ版をインストールしました。

すると、なんということでしょう！
初期設定でwi-fiの設定もできますし、日本語の設定をすれば、環境設定後も楽々作業できます。
初心者には断然、デスクトップ版がオススメです。


##IPやDHCPなどのネットワーク周りの知識がついた(たぶん)
これは、もともとの目的だったんですが、基本的なネットワーク周りの知識をサーバーを建てていく過程で触れることができます。

僕は、始める前は固定IPアドレスの必要性など、簡単なところも理解できていなかったのですが、今では説明できますし、なぜDDNSなどのサービスがあるのかも理解できたかなと思っています。
本でネットワーク周りの知識はあるけど、イマイチピンときていないって方はサーバー開設で理解を深めるというのもいいのではないでしょうか？

##セキュリティに関する知識がついた（きっと）
今回の成果物ではセキュリティ周りはダメダメだと思っているので、もっと丁寧に設定しないといけないなと反省しているのですが、それでもファイアーウォールの設定やsshの設定、sslなどに触れることはできました。

聞いたことあるけど良くわからんというセキュリティ関連の分野に爪先だけでも入ることができたかなと思っています。


##サーバーも人が作ってるんだという実感が湧く(重要)

僕にとってはこれが結構デカイです。

正直、「自宅サーバー建ててみたら？」と勧められるまで、サーバーはAmazonやGoogleと言った大企業から賜る神の御業や贈物かなにかだと思ってましたww
(けっこうガチで)

でも、実際はそんなことはなく、サーバーも人の手で作られていますし、人が作れる物は大抵自分でも作れます。（そんなことない時もありますがw）

さらに、誰でも作れるように世界中の自分よりも頭も能力も優れている人たちがネット上に情報を発信してくれています。それらを使えば、広大で理解できないように思われるインターネット技術の端っこに触れることは誰にだってできるんだと改めて感じました。

小さいですが、こうゆう成功体験ができると、また作ってみたいという気持ちも湧いてきますし、この感覚は重要だと自画自賛してますw

本当に自信なかったですが、サーバー建ててみて良かったです！
皆さんも、チャレンジしてみてください！
for文 range

0から9まで出力させたい場合

```python:めんどくさい
num_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

for num in num_list:
    print(num)
```
だとめんどくさい。。。

```py:range
for num in range(10):
    print(num)
```
の方がいい。


2から9まで出力させたい場合は、

```py:2から9まで
for num in range(2, 10):
    print(num)
```

2から9までで3差で出力させたい場合は、

```py:2から9までで3差
for num in range(2, 10, 3):
    print(num)
```

```:2から9までで3差の実行結果
2
5
8
```

Helloを10回出力させたい場合

```py:Hello10
for i in range(10):
    print('Hello')
```

iも一緒に出力させる場合は

```py:Hello10_index
for i in range(10):
    print(i, 'Hello')
```

```:Hello10_indexの実行結果
0 Hello
1 Hello
2 Hello
3 Hello
4 Hello
5 Hello
6 Hello
7 Hello
8 Hello
9 Hello
```

逆に変数iを後々使わない場合は、
_に入れる。

```py:Hello10回
for _ in rage(10):
    print('Hello')
```
Homebrewのエラー

### Python update時、venvをリセットする時でたエラー
 
```
$ brew cleanup
```
で下記のWarningがありました。
`Warning: Skipping python: most recent version 3.7.6_1 not installed`

----
アップデートします。

```
$ brew upgrade
```
で下記のエラー...
```Traceback (most recent call last):
	4: from /usr/local/Homebrew/Library/Homebrew/brew.rb:23:in `<main>'
	3: from /usr/local/Homebrew/Library/Homebrew/brew.rb:23:in `require_relative'
	2: from /usr/local/Homebrew/Library/Homebrew/global.rb:13:in `<top (required)>'
	1: from /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require': cannot load such file -- active_support/core_ext/object/blank (LoadError)```

---
```
$ brew update-reset
```
で[ブランチのリセットとアップデート](https://stackoverflow.com/a/54913258/8762296)
```==> Fetching /usr/local/Homebrew...
==> Resetting /usr/local/Homebrew...
Branch 'master' set up to track remote branch 'master' from 'origin'.
Reset branch 'master'
```

```
brew upgrade
```
で問題なくアップデートしましたが、Warningもありました。
```Warning: Building python from source:
  The bottle needs the Apple Command Line Tools to be installed.
  You can install them, if desired, with:
    xcode-select --install```

----
```
$ xcode-select --install
```
でまだ下記のエラー...
`xcode-select: note: install requested for command line developer tools`

- [command line developer toolsをインストール](https://qiita.com/mym/items/8bc079b7d0f5f55c49dc)

以上で全部解決。
Ruby on Rails にdeviseを使ってログイン機能を導入する

書きつくされているRuby on Railsにdeviseを導入する記事ですが、ひとそれぞれ目的が微妙に違うのか躓いてしまいます。

そこで僕の無知から来るミスも含めて共有し、同じ過ちを皆様に犯さないでいただけるのなら記事を書いたかいがあります。
また、よりよい方法があると思いますが、ご参考にしていただければと思います。

それではいきましょう！

## 環境
・macOS
・Ruby 2.7.0
・Ruby on Rails 6.0.2

## もくじ
１．Railsのプロジェクトを作成する
２．簡単な画面遷移を作る
３．ログイン機能を実装する（ここでdeviseが登場）

## １．Railsのプロジェクトを作成する
まずはアプリを開発するディレクトリを作成する。

```
$ mkdir app_name
$ cd app_name 
```

その後のプロジェクトの作成方法は以下を参照してください。
https://qiita.com/tom-ohiro/items/0030999b838bfe05006d



## ２．簡単な画面遷移を作る（トップページの作成）
この工程があったために勝手に混乱することに。
まずはユーザーコントローラを作って、トップページを作成。
以下のコマンドでusers_controller.rbなどのファイル、ディレクトリが作成される。

```
$ rails g controller users
```

```app/controllers/users_controller.rb
    def index
    end
```

ルートを設定する。

```config/routes.rb
get  '/'  => 'users#index'

```

表示ページを作成する。inde.html.erbは新規ファイルを自分で作成する。

```app/view/users/index.html.erb
Hello world! とプログラマっぽく書く
```

以下を実行してサーバーを起動する。

```コンソール
$ rails s
```

http://localhost:3000/
にアクセスするとトップページが表示される。

## ３．deviseを用いてログイン機能を実装する
ここからが本番。
コマンドの順番を間違えると初学者には非常に厄介に感じられるので、よく注意して進んでください。

１．Gemfileに以下を記入

```
gem 'devise'
```

２．以下のコマンドをターミナルで実行
順番を間違えないようにゆっくりやりましょう。

```
$ bundle install
```

以下のような画面が表示される。
<img width="244" alt="スクリーンショット 2020-01-04 22.18.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246652/0b8a8365-2800-d883-1648-f0b00bac0176.png">

僕は以下のコマンドを忘れていて非常に困った。。。皆様ご注意ください。

```
$ rails g devise:install
```

うまくいくとこんな感じの画面が表示される。
<img width="304" alt="スクリーンショット 2020-01-04 22.21.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246652/e4f5b122-b1e4-ffab-df50-5265ee9d6d31.png">

こちらの設定は１，２だけ別途やっておけば大丈夫。
１．はメールを送るときの設定の話。以下の記述を追記してください。
まぁ書いてあるとおりにやるだけなんですが、英語で表示されているだけでうわってなってしまいますよね。
これからこんな画面の連続なので、頑張って読みに行くようにしてみましょう。
読んで見ればこんなこと解説するまでもねーじゃねえかって思うようなことなんです。
でも、はじめのとっつきにくさは半端ないので少しでもハードルが下がればと思い解説させていただきました。

```config/environments/development.rb
   config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
```

２．はトップページの表示の話。
以下の記述は上の方で書いた内容と同じことなので、以下の内容を上書きしていただければ大丈夫です。

```config/routes.rb
  root to: "home#index"
```

次に以下のコマンドをターミナルで実行します。
これでログイン画面や新規登録画面などを用意してくれます。

```
$ rails g devise:views
```

続いてUserモデルの作成です。
migrationファイルなどが作成されます。
初めての場合は特にmigrationファイルの編集なしで連続して以下のコマンドを入力しても大丈夫でしょう。
あとから保存内容を変えることもできますし、今のうちに編集していただいてももちろん大丈夫です。

```
$ rails g devise User
$ rake db:migrate
```

続いて以下の画面。
僕はここで非常に困ってしまいました。
すでにusers_controllersを作ってしまっているので、名前がかぶってしまうのではないか？
ということでコントローラを消すという作業をしてしまいました。
deviceでよく使うusers_controllerと混同してしまいますが、実行しても問題ありません。今後は先を見越して先にdeviceの導入からしたほうがいいでしょう。

```
$ rails g devise:controllers users
```

以下の記述はログインする前にページにアクセスしようとすると、ログイン画面に遷移させるというものです。

```app/controllers/application_controller.rb
  before_action :authenticate_user!
```

これでdeviceの導入は完了です。
トップページにアクセスしようとするとログイン画面に遷移すると思います。

## おわりに
deviceはとっても便利な機能である一方でわけわからなくても使えてしまうgemでもあります。
便利さと引き換えに使いこなしまでのレベルになるにはもう何段階かレベルアップする必要がありますが、まずは使える技を少しずつ増やして自信をつけることが大切だと思います。
共に頑張っていきましょう。
もし、この方法でうまくいかないとか、このやり方はおかしい。このやり方の方が適当ではないかと言う場合はコメントいただけると大変うれしく思います。
最後までお読みいただきありがとうございました。
svmでtfidfとword2vecを比較してみたゾ！

#　はじめに

前回の記事の続きです。
https://qiita.com/teri/items/bc4e04316a1b14ae8365

# 前回の概要と考察

前回は、tfidf、svmを用いて、分類器を作りましたが、学習データにある単語を含めた文章については、期待通りの分類をしてくれました。しかし、学習データにない単語を含めた文章の分類は、期待通りには分類してくれませんでした。

この事象について、考えたのですが、tfidfの言語モデルは、分類器に用いる学習データと同じのデータを使う必要があるので、学習データの量が少ないと、ベクトル化に影響する単語が少なくなるんだと思うんですよ。(結局、データ量って大事なんですよね。。。)

# tfidfとword2vecを比較をしてみたい

前回は、tfidfを使いましたが、今回はword2vecを使った分類器を作って、結果を比較したいと思います。
word2vecはtfidfと違って、分類器の学習データと同じのデータを使う必要がないので、事前に大量のデータを学習させたword2vecの言語モデルを用いれば、色んな単語に対応させることができると考えられます。（word2vecの学習済みモデルは、インターネット上にけっこうあります。公開してくださっている方々には感謝しかありませんな。。。）

難しく書いていますが、まとめると。。。
word2vecを使うことで、tfidfより、汎用的な分類器が出来ると思うんです！！！


#比較結果
* tfidfでの結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239022/ec052c5a-328f-598e-5fba-5e8c4967684a.png)

* word2vecでの結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239022/0219e9c0-ef24-409e-4fb5-f590d3f9b8c5.png)


比較すると、下の2文の結果が違いますね。
word2vecのほうが、期待通りに分類されています。
word2vecってすげえ！


#最後に
今回の比較でword2vecってすごいんだなって改めて実感しました。
ただ勘違いしてほしくないのは、tfidfよりword2vecが全面的に良いというわけではないことです。
tfidfはword2vecよりもメモリ量が少ないですし、単語の重要度という観点でベクトル化ができます。
それぞれのメリットがあるので、何をやりたいかで、どの手法を選定するかが重要なんだと、思います。

僕も、これから、どんどん自然言語処理の知識を身に付けていって、
「ここは、○○な手法を使うと精度あがるよ」なんてことを簡単に言えるような、かっちょいいエンジニアになっていきたいですね～('◇')
【Vuex】Rails(devise_token_auth)+Vue.jsのSPAでサインアウトするサンプルコード

## はじめに
Rails + Vue.jsのSPAで**devise_token_auth**を使ってサインアウトするサンプルコードを残します。

リクエストヘッダ情報の保存に**Vuex**を活用しました。

## 環境
```yaml
OS: macOS Catalina 10.15.1
Ruby: 2.6.5
Rails: 6.0.2.1
Vue: 2.6.10
vuex: 3.1.2
axios: 0.19.0
```

## 考え方

[devise_token_authの公式ドキュメント](https://github.com/lynndylanhurley/devise_token_auth/tree/master/docs/usage)の、**sign_out**のくだりにはこう書かれています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/483292/19f999f1-82a7-ab6d-fda7-038821e9c22a.png)


> Use this route to end the user's current session. This route will invalidate the user's authentication token. You must pass in uid, client, and access-token in the request headers.

リクエストヘッダに`uid`, `client`, `access-token`を含めて、DELETEリクエストを投げる必要があります。

この**ヘッダ情報を保管するため**にVuexを使用します。

## コード

```javascript:store.js
import 'babel-polyfill'
import Vue from 'vue'
import Vuex from 'vuex'

import axios from 'axios'

Vue.use(Vuex)

const store = new Vuex.Store({

  state: {
//ヘッダの入れ物を用意。
    headers: null,
  },

  mutations: {

//サインイン時のレスポンスヘッダから情報を抜き出して保存しておく。
    signIn(state, payload) {
      state.headers = {
        "access-token": payload["access-token"],
        "client": payload["client"],
        "uid": payload["uid"],
      };
    },

//サインアウトしたらヘッダを空にしておく。
    signOut(state) {
      state.headers = null;
    },
  },

  actions: {
//paramsはemailなどのユーザー情報が入っていると思って下さい。
//（paramsへの情報の入れ方は今回割愛。）
    signIn(context, params) {
      axios
        .post('/api/v1/auth/sign_in', params)
        .then(function (response) {
//ここでレスポンスヘッダを受け取る。
          context.commit('signIn', response.headers);
      })
    },
    signOut(context) {
      axios
//ここでヘッダ情報を呼び出してDELETEリクエストに含める
        .delete('/api/v1/auth/sign_out', { headers: context.state.headers })
        .then(function () {
          context.commit('signOut');
      })
    },
  },
})

export default store
```

※本来は`currentUser`のような`state`も用意してすべきかと思いますが、話を超シンプルにするためにカットしています。

## 呼び出し方

Webpackのエントリーポイントとなるファイルで先程の`store.js`を読み込みます。

```javascript:main.js
import Vue from 'vue'
import App from '../App.vue' 
import store from './store.js' //こちら

document.addEventListener('DOMContentLoaded', () => {
  const app = new Vue({
    store, //こちら
    render: h => h(App)
  }).$mount()
  document.body.appendChild(app.$el)
})
```
↓
`store.js`を読み込めば任意の単一ファイルコンポーネント内にて、以下のようにして`signOut`を呼び出せます。

```vue:Anything.vue
<template>
  <div>
    <button @click="signOut">ログアウト</button>
  </div>
</template>

<script>

  export default {
    methods: {
      signOut() {
        this.$store.dispatch('signOut')
      }
    }
  }
</script>
```
※例では超シンプルに、サインアウトに必要な箇所のみ抜き出しています。

## おわりに
最後まで読んで頂きありがとうございました:bow_tone1:

どなたかの参考になれば幸いです:relaxed:

## 参考にさせて頂いたサイト（いつもありがとうございます）
- [Vuex 入門 | Vuex](https://vuex.vuejs.org/ja/guide/)
- [devise_token_auth/docs/usage at master · lynndylanhurley/devise_token_auth · GitHub](https://github.com/lynndylanhurley/devise_token_auth/tree/master/docs/usage)
フラクタル図形を描く(木)

# はじめに

「木」というのは、プログラマにとって、少なくとも「データ構造」としてはなじみ深いものです。

![Tree_struct.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101445/48487b67-7849-11a2-fa2c-1d5264dec57d.png)

木構造を構成する要素は以下の４つです：
- 節点(node)
- 枝(branch)
- 葉(leaf)
- 根(root)

このうち、葉と根は節点の特殊なものです。

この「データ構造としての木」を扱う処理は、今回の「図形としての木」の処理と同様の「再帰呼び出し」となっています。

# プログラムで木を描く

フラクタル図形としての木（ここでは二分木）を描くには、タートルグラフィクスで以下のようにします。

```c++
#include <stdio.h>
#include <math.h>
void pd();
void pu();
void rt(float th);
void lt(float th);
void fd(float len);
void bk(float len);

void tree(float len, float rr, float lr, float th, int n) {
   if(n > 0) {
      fd(len);
      lt(th);
      tree(len*lr, rr, lr, th, n-1);
      rt(th*2.0);
      tree(len*rr, rr, lr, th, n-1);
      lt(th);
      bk(len);
   }
}

int main()
{
   pd();
   tree(10.0, 0.7, 0.7, 30.0, 10);
}
```

※タートルグラフィクスについては[別記事(フラクタル図形を描く(道具編)](https://qiita.com/fujim2/items/a4a3e3b8c1824c09fd02)参照の事。


木の形を制御できるように以下の引数(len,lr,rr,th,n)をパラメータとしています：

|  パラメータ  |   意味  |
| ----------- | ---------- | 
|  len        | 枝の基本長さ |
|  lr         |  左の枝の縮み率 |
|  rr         |  右の枝の縮み率 |
|  th         | 枝の開き角度 |
|  n          | 再帰呼び出しの深さ |

## 以下、パラメータを変化させたものです。

|  パラメータ  |   結果  |
| ----------- | ---------- | 
|  (10.0, 0.7, 0.7, 30.0 )   | ![draw_tree_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101445/68985144-a77c-6e02-0102-9054044a7b4b.png)
|  (10.0, 0.7, 0.7, 10.0 ) | ![draw_tree_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101445/99fe18b8-1c74-7d18-5492-cd48a1a0ba40.png) 
|  (10.0, 0.7, 0.7, 45.0 ) |![draw_tree_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101445/b31bfff8-9319-9d9c-1d22-6cffa9c3e145.png)|
|  (10.0, 0.5, 0.8,  30.0 ) | ![draw_tree_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101445/5eae2ce3-7318-2370-3403-891a3572a56f.png)
 |

# 発展

ここまで、二分木の描画のためのコードと例を紹介しましたが、パラメータや描画の構造に手を加える事で、されに複雑で本物らしい木を描く事も可能です。例えば以下のようなバリエーションがあると思います：
- 枝の分岐を二本以上にする
- 枝の縮み率に乱数を含める
- 枝の太さをパラメータに入れる
- 末端で葉(leaf)を描く

等々、いろいろと試してみると面白いと思います。

今回は以上です。
SparkでS3やAzureBlobにファイル名をつけて保存

# 動機

Sparkではデータをストレージに保存する際にファイル名をつけて保存することはできない。Sparkではディレクトリ名までしか指定できない。Sparkではビッグデータを扱う前提なので、１つ１つのファイル名には感知しない方針なのだろう。だが、ちょっとしたファイルを名前をつけてストレージに保存したいことがあるときもある。かもしれない。

# やり方

## 下準備

### core-site.xmlの編集

ストレージのIDを `${HADOOP_HOME}/etc/hadoop/core-site.xml`に以下を追加する。

#### S3

```xml

<property>
  <name>fs.s3a.access.key</name>
  <value>YOUR ACCESS KEY</value>
</property>
<property>
  <name>fs.s3a.secret.key</name>
  <value>YOUR SECRET KEY</value>
</property>
```

#### Azure Blob 

アクセスキーを使う場合

```xml

<property>
  <name>fs.azure.account.key.youraccount.blob.core.windows.net</name>
  <value>YOUR ACCESS KEY</value>
</property>
```

Managed Identityを使う場合

```xml

<property>
  <name>fs.azure.account.auth.type</name>
  <value>OAuth</value>
  <description>
  Use OAuth authentication
  </description>
</property>
<property>
  <name>fs.azure.account.oauth.provider.type</name>
  <value>org.apache.hadoop.fs.azurebfs.oauth2.MsiTokenProvider</value>
  <description>
  Use MSI for issuing OAuth tokens
  </description>
</property>
```

###環境変数の設定

```
HADOOP_OPTIONAL_TOOLS=hadoop-aws,hadoop-azure
```


## pysparkからストレージにアクセス

```python

from pyspark.sql import SparkSession
spark = SparkSession.builder.appName("test").getOrCreate()
sc = spark.sparkContext
FileSystem = sc._gateway.jvm.org.apache.hadoop.fs.FileSystem
URI = sc._gateway.jvm.java.net.URI
Path = sc._gateway.jvm.org.apache.hadoop.fs.Path
# S3の場合
s3addr ='s3a://' + 'YOUR_S3_BUCKET_NAME'
s3fs = FileSystem.get(URI(s3addr), sc._jsc.hadoopConfiguration())
s3fs.copyToLocalFile(Path("S3a://YOUR_S3_BUCKET_NAME/YOUR/S3/File"), Path("/YOUR/local/File"))
# blobの場合
blobaddr = 'wasbs://' + 'YOUR_CONTAINER_NAME' + '@' + 'YOUR_ACCOUNT_NAME' + '.blob.core.windows.net'
blobfs = FileSystem.get(URI(blobaddr), sc._jsc.hadoopConfiguration())
blobfs.copyToLocalFile(Path("wasbs://YOUR_CONTAINER_NAME@YOUR_ACCOUNT_NAME.blob.core.windows.net/YOUR/blob/File"), Path("/YOUR/local/File"))
```

# 参考文献
hdfsでblob操作
https://hadoop.apache.org/docs/current/hadoop-azure/index.html

S3の操作
https://hadoop.apache.org/docs/current/hadoop-aws/tools/hadoop-aws/index.html

参考にしたblogの記事
http://hatunina.hatenablog.com/entry/2018/08/06/200915

上記のpythonの中の`FileSystem`内の関数
https://hadoop.apache.org/docs/r3.2.1/api/org/apache/hadoop/fs/FileSystem.html
複数の MIDI ファイルを MP3 ファイルに一括変換する Shell Script

お正月ドラマを観ながら、昔作った MIDI ファイルを MP3 にして整理するためにシェルスクリプトを作りました。
![midmp3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5542/f2f8ca74-e335-bd76-4a58-fac22546c025.gif)
MIDI ファイルは 2020 年現在、デフォルトで QuickLook できないので、MP3 の方が取り回しが楽ですね。

# ツールのインストール

[Homebrew](https://brew.sh/index_ja) を使えるようにしておき、 [Fluid Synth](https://formulae.brew.sh/formula/fluid-synth) と [ffmpeg](https://formulae.brew.sh/formula/ffmpeg) をインストールします。

```sh
$ brew install fluid-synth
$ brew install ffmpeg
```

# Sound Font を入れる

[S. Christian Collins--Pianist, Composer, Virtual Instrument Designer](http://www.schristiancollins.com/generaluser.php) から、**「GeneralUser GS 1.471」** をダウンロードして伸長し、好きなディレクトリに配置します。

Sound Font は超絶平たくいうと MIDI 音源の種類の一つです。
質の良い Sound Font を使うと音が良くなります。
上のやつはライセンス的にも良さげなのでこれを使います。

`$HOME/Music/SoundFonts/GeneralUser GS 1.471/GeneralUser GS v1.471.sf2` に配置しました。

# 一括変換シェルスクリプトを作る

次の `create_mp3_from_midi.sh` ファイルを適当なディレクトリに配置して、実行権限を与えます。

`$HOME/Music/create_mp3_from_midi.sh` に配置しました。

「今見ているディレクトリ」にある `.mid` `.MID` 拡張子のファイルを一括で `.mp3` に変換するスクリプトです。

```sh:create_mp3_from_midi.sh
#!/bin/sh
soundfont="$HOME/Music/SoundFonts/GeneralUser GS 1.471/GeneralUser GS v1.471.sf2"
echo "🎹 SoundFont の場所は $soundfont ！"

for file in `\find . -maxdepth 1 -type f`; do
  filename=${file%.*}
  fileext=${file##*.}
  if [ $fileext = "mid" ] || [ $fileext = "MID" ]; then
    echo "🎹 ${file}"
    fluidsynth -F "${filename}".wav -i "$soundfont" $file 
    ffmpeg -i ${filename}.wav -f mp3 -b:a 192k ${filename}.mp3
    rm ${filename}.wav
    echo "🎹 ===== > ${filename}.mp3"
  fi
done

echo "🎹 おしまい!"
```

Sound Font を配置したパスを変えた場合は、`soundfont` 変数に指定してください。

実行権限を与えます。

```zsh
$ chmod 755 create_mp3_from_midi.sh
```


# スクリプトをどこからでも実行できるようにする

`midimp3` コマンドを作って、どこでも実行できるようにエイリアスを作ります。

```sh
$ echo 'alias midimp3="~/Music/create_mp3_from_midi.sh"' >> ~/.bash_profile
$ source ~/.bash_profile
```

# 実行！

midi ファイルがあるディレクトリに Terminal で移動して、`midimp3` コマンドを実行します。

```sh
$ midimp3
```

![midmp3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5542/f2f8ca74-e335-bd76-4a58-fac22546c025.gif)
できた！

# 参考

[MacでMIDIファイルを再生&WAV出力する - Qiita](https://qiita.com/yktakaha4/items/009306108b9c9fe06a37)
AWS CloudWatch Logsで例外のログを取得する

現在勤めている企業ではDjangoで開発したアプリケーションをDocker Composeを利用して運用しています。

Dockerのログは以下のコマンドで確認することができます。

```
# appコンテナのログエントリーを表示し続ける（-fオプションでtail）
$ docker-compose logs -f app

# appコンテナの直近の500件のログエントリーを表示する
$ docker-compose logs --tail=500 app
```

しかし、運用していると、様々なトラブルがあって、トラブルの都度コンテナを実行しているサーバーにログインして、コンテナのログを確認するのが面倒臭い。

また、コンテナを破棄すると、今までのログも破棄してしまうため、運用環境では外部のログ保存ソフトウェアにログを送って保存します。Docker Composeではlog driverを利用することで、fluentdやAWS、GCPにログの送信・保存を行うことができます。

現在アプリケーションはAWSで運用しているので、以下の1〜3を行い、AWS CloudWatch Logsにログを送ることにします。

```
1. EC2インスタンスにIAMロールを設定
2. CloudWatch Logsでロググループを作成
3. docker-compose.ymlを修正
```

## 1. EC2インスタンスにIAMロールを設定
コンテナを実行しているEC2インスタンスに以下のIAMロールを作成し設定する。

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}
```
 
参考：
[Amazon CloudWatch Logs ロギング・ドライバ](http://docs.docker.jp/engine/admin/logging/awslogs.html)

## 2. CloudWatch Logsでロググループを作成
AWSのコンソールでCloudWatchにアクセスし、ログ-->ロググループで「アクション」ボタンを押下します。そして、表示したダイアログにロググループ名を入力し、「ロググループの作成」ボタンを押下し作成します。

![aws-cloudwatch-logs-action.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76958/bdbfe617-8eca-30d2-e2dd-29a4bd8d3e61.png)


## 3. docker-compose.ymlを修正
以下の設定をdocker-compose.ymlに追記します。


```docker-compose.yml
version: '3'
services:
  app:
    ・・・（中略）・・・
    logging:
      driver: "awslogs"
      options:
        awslogs-region: "us-east-2" # オハイオリージョン
        awslogs-group: "/sample-app/dev/"
        awslogs-create-group: "true" # グループがない場合は作成
        awslogs-stream: "web"
```

以下のようにCloudWatch logsに保存できるようになりました。

![aws-cloudwatch-logs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76958/4f048af8-2b3f-e31d-e3ed-7c3795bda697.png)


ログをCloudWatch logsに保存できるようになったのは良いですが、例外が発生した場合、ログが以下のように1行ずつ分割してしまい非常に見づらくなってしまいました。例外が発生したスタックトレースも1行ずつ分割しないで1行で保存するようにします。

![aws-cloudwatch-logs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76958/b8854993-ce27-c55a-9b87-6627c84fbb45.png)

docker-compose.ymlに「awslogs-multiline-pattern」を追加します。またログを構造化してCloudWatch上で検索しやすくするために、django-structlogというモジュールをインストールします。django-structlogについては参考をご参照下さい。


```docker-compose.yml
version: '3'
services:
  app:
    ・・・（中略）・・・
    logging:
      driver: "awslogs"
      options:
        awslogs-region: "us-east-2" # オハイオリージョン
        awslogs-group: "/sample-app/dev/"
        awslogs-create-group: "true" # グループがない場合は作成
        awslogs-stream: "web"
        awslogs-multiline-pattern: '^{"request_id":'
```

以下のように例外も1行のログとしてCloudWatch Logsに保存できるようになりました。

![aws-cloudwatch-logs-after-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76958/7f37f97f-aba9-dcd9-88f0-6d9fce111461.png)

![aws-cloudwatch-logs-after-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76958/686acdbf-e700-e165-bdda-716df312f159.png)

参考：
[Djangoでロギング(logging)を行う方法](https://sinyblog.com/django/logging-001/#django-structlog)
Docker コンテナ内で立ち上げた godoc にホスト側からアクセスできなかった

## この記事について

Go言語の勉強用の環境として立ち上げた Docker コンテナ内で godoc サーバを立ち上げたが、ホストOS側のブラウザからアクセスできなかったので調べてみたメモ。

**環境**

* Windows10 Pro Insider Preview (バージョン: 2004, OSビルド: 19536.1000)
* WSL2 / Ubuntu-18.04 ( [.wslconfig で localhost フォワーディング設定済み](https://qiita.com/snaka/items/a8eee4cfc8f7d733e6ab) )
* Docker
    * 2.1.7.0(41536)
    * Engine 19.03.5

**用意した Dockerfile**

```Dockerfile:Dockerfile
FROM golang:latest

RUN mkdir /go/src/app
WORKDIR /go/src/app
RUN go get golang.org/x/tools/cmd/godoc
EXPOSE 6060/tcp
```

**実行したコマンド1**（godocがインストールされたコンテナのビルドと、そのコンテナでのgodocサーバの起動）

```terminal
$ docker build -t hoge .
$ docker run --rm -p 6060:6060 hoge godoc
```

**実行したコマンド2**（ホストからgodocサーバにアクセス）

```terminal
$ curl http://localhost:6060
curl: (52) Empty reply from server
```

上記のようにサーバから正常な応答が返ってこない。

**上記のURLにアクセスした場合の期待する応答**は、以下のようなリダイレクトのレスポンス。

```terminal
$ curl -v http://localhost:6060
* Rebuilt URL to: http://localhost:6060/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 6060 (#0)
> GET / HTTP/1.1
> Host: localhost:6060
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 302 Found
< Content-Type: text/html; charset=utf-8
< Location: /pkg/
< Date: Sat, 04 Jan 2020 12:58:12 GMT
< Content-Length: 28
<
<a href="/pkg/">Found</a>.

* Connection #0 to host localhost left intact
```

## 対処

godoc サーバを起動するコマンドを以下のように変更

```terminal
$ docker run --rm -p 127.0.0.1:6060:6060 hoge godoc -http 0.0.0.0:6060
```

* godoc の起動オプション `-http 0.0.0.0:6060` を付与し、コンテナのすべてのネットワークインターフェースからの接続を受け付けるようにする。
* docker run でコンテナ起動時に `-p 172.0.0.1:6060:6060` のようにホスト側のネットワークインターフェースをローカル・ループバック・アドレスに限定する。
    * 別に `-p 6060:6060` でもホストからアクセス可能だが、ホストと同じネットワークに存在する別の端末からもアクセス可能になってしまう。（[参考](https://qiita.com/amuyikam/items/01a8c16e3ddbcc734a46#%E6%B3%A8%E6%84%8F)）
    * それでも構わない、あるいは、むしろ別端末アクセスさせたいというケースでは `172.0.0.1:` の部分は省略しても構わない。  

上記のようにサーバを起動したあと、ホスト側のブラウザから `http://localhost:6060` にアクセスすると、無事 GoDoc のページが表示できた。

[![Image from Gyazo](https://i.gyazo.com/742a1b8bd95bcd793d30ec1bd459353f.png)](https://gyazo.com/742a1b8bd95bcd793d30ec1bd459353f)

## 参考

以下の記事がより詳しい

* [docker上のアプリにlocalhostでアクセスしたらERR_EMPTY_RESPONSEが出る](https://qiita.com/amuyikam/items/01a8c16e3ddbcc734a46)
「文言」でレンダリング-邪道ですが漢文に挑戦　前編

## はじめに

[ハート(畫心)の出力とレンダリング](https://qiita.com/libru1/items/97f521f4d661b20115e1)に成功し、その美しさにソース以外も出力したくなります。そうです、「漢文」です。観賞したいのです

ソース出力機能を邪道な使い方してすいません
でも、「漢文」を観賞したい方いらっしゃるのではないかと思い公開させていただきます。少しでも参考になればと思います

[後編](https://qiita.com/libru1/items/36e7a1897bf1bc5b4b5c)も併せてご覧ください

## 実行
流石に拡張子.wyはまずいかと思い、.txtに春暁を保存してみました

```sh
$ cat examples/春暁.txt
春暁 孟浩然
春眠不覚暁
処処聞啼鳥
夜来風雨声
花落知多少

$ wenyan examples/春暁.txt -r --title 春暁
/xxxxxxxx/examples/春暁.svg
```

<img width="406" alt="Screen Shot 2020-01-04 at 4.47.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334227/ebfc78bf-45e9-ffe5-6a19-b7f077504f54.png">

おおっ!タイトル部分と共にレンダリングされました

しかし、改行していません
やはりソースじゃないからでしょうか。拡張子を変え、行末に句点を打ってみます

```sh
$ cat examples/春暁.wy
春暁 孟浩然.
春眠不覚暁。
処処聞啼鳥。
夜来風雨声。
花落知多少。
$ wenyan examples/春暁.wy -r --title 春暁
/xxxxxxx/examples/春暁.svg
```
<img width="406" alt="Screen Shot 2020-01-04 at 4.56.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/334227/c54e30b9-2fff-7eae-4eb4-ff13fb4a137c.png">

句点が赤丸で入りましたが、改行しません
しかし、今までのレンダリング見直してみるとソースは改行されていません
スペースも無視され詰まってしまします。そんな仕様はないのかもしれません

ちょっと物足りませんが、レンダリング成功という事ですかね:sweat_smile:

## おわりに

象牙色のような黄ばんだ紙に写し取られる縦書きのその文字は、本当に見ていてドキドキします。
deno v0.28.1の変更点

## 概要

https://github.com/denoland/deno/releases/tag/v0.28.1

denoのv0.28.1がリリースされたため、変更点をまとめます。

## `req.body`が関数から`Reader`に変更された(std/http)

https://github.com/denoland/deno/pull/3575

`req.body`を`Deno.readAll`等の`Reader`を受け取る関数の引数として渡すことができるようになりました。

それに伴い、`req.bodyStream()`メソッドが削除されています。

#### 変更による影響

v0.28.0ではリクエストボディをデコードする際は下記のように処理が行われていましたが、

```typescript:v0.28.0
import { serve } from "https://deno.land/std@v0.28.0/http/server.ts";
const server = serve({ port: 8000 });
for await (const req of server) {
  const body = await req.body();
  console.info(new TextDecoder("utf-8").decode(body));
  ...
}
```

v0.28.1では下記のように変更する必要があります。

```typescript:v0.28.1
import { serve } from "https://deno.land/std@v0.28.1/http/server.ts";
const server = serve({ port: 8000 });
for await (const req of server) {
  const body = await Deno.readAll(req.body);
  console.info(new TextDecoder("utf-8").decode(body));
  ...
}
```

## `req.contentLength`が追加された(std/http)

https://github.com/denoland/deno/pull/3575

`Content-Length`ヘッダの値を`number`型の値として返却します。

```typescript
import { serve } from "https://deno.land/std@v0.28.1/http/server.ts";

const server = serve({ port: 8000 });
for await (const req of s) {
  console.info(req.contentLength);
  ...
}
```

## OpenSSLへの動的リンクに関する問題の修正

https://github.com/denoland/deno/pull/3586

[v0.28.0](https://qiita.com/uki00a/items/879a65f52c2a09bf1295)のリリース時に、[reqwest](https://github.com/seanmonstar/reqwest)というライブラリがv0.10.0にアップグレードされました。

- [v0.9.22からv0.10.0-alpha.2へアップグレード](https://github.com/denoland/deno/pull/3418)
- [v0.10.0-alpha.2からv0.10.0へアップグレード](https://github.com/denoland/deno/pull/3567)

その間にreqwestライブラリにOpenSSLへの依存が追加されました。(Linux環境のみ)

その関係で、一部Linux環境でdenoのビルドに失敗する問題が発生していたため、修正が実施されたようです。
firestore+nuxtでチャットを作る（読み込み回数少ないver）

# やりたいこと

* 以前下記の記事でチャット機能についてまとめたがこのやり方だと、messageごとにuserを読み込むので凄まじく読み込み回数が多くなる（ただし、user情報が変更されたらmessageのiconも変更される。）
    * https://qiita.com/you8/items/60d7d384bb470cb6c85f
* user_iconの変更を許容してmessageにuser_iconを入れてmessageの読み込みだけですむようにして読み込み回数を減らしたい（firebaseを節約したい）

# 全体図



* login時にuser情報をfirestoreとstoreに保存
* storeのphotoURLをmessage送信時にfirestoreに送る
* messageからphotoURLを取得

# 実装！！！

## firestoreとstoreに保存

```javascript:default.vue
  created() {
    firebase.auth().onAuthStateChanged(user => {
      var user = firebase.auth().currentUser
      var name, photoUrl, uid
      if (user != null) {
        uid = user.uid
        name = user.displayName
        photoUrl = user.photoURL
        var db = firebase.firestore()
        db.collection('user').doc(uid).set({
          name: name,
          photoUrl: photoUrl,
          uid: uid,
          created: firebase.firestore.FieldValue.serverTimestamp()
        })
        .then(function (docRef) {
          console.log("")
        })
        .catch(function (error) {
          console.log("")
        })
      }
      if (user) {
        user.isLogin = true
        this.$store.commit('login', user)
      } else {
        this.$store.commit('logout', user)
      }
    })
  },
  methods: {
    googleLogout: function () {
      firebase.auth().signOut().then(() => {
        window.location.href = '/'
      })
    },
    googleLogin: function () {
      firebase.auth().signInWithRedirect(new firebase.auth.TwitterAuthProvider())
    }
  }
}
```
```javascript:store/index.js
mutations: {
      login (state, user) {
        state.uid = user.uid
        state.name = user.displayName
        state.isLogin = user.isLogin
        state.photoURL = user.photoURL
      },
      logout (state) {
        state.user = null
      }
    }
```


## message送信

```javascript
methods: {
    send_message: function () {
      var db = firebase.firestore()
      db.collection('room').doc(this.room_id).collection('message').doc().set({
        user_id: this.$store.state.uid,
        user_photoUrl: this.$store.state.photoURL,
        message_content: this.message_content
      })
      .then(function (docRef) {
        console.log("")
      })
      .catch(function (error) {
        console.log("")
      })
    }
```

messageの中にphotoURLをいれちゃう

## messageの表示

```javascript
db.collection('room').doc(this.room_id).collection('message').onSnapshot(querySnapshot => {
      querySnapshot.docChanges().forEach(doc => {
        this.messages.push({
          ...doc.doc.data(),
          id: doc.doc.id
        })
      })
    })
```

* ...doc.doc.data()でスプレッド構文使ってdocの中を展開している
* これをmessagesで展開していってmessage.contentでテキストを表示
* foreachでmessagesにpushで配列を追加していってる
Pythonによる AI・機械学習について学んだ内容(2)

#はじめに
この本を使って勉強しています
[Pythonによる AI・機械学習・深層学習アプリのつくり方](https://www.socym.co.jp/book/1164)

#1-4　Google Colaboratory
Google が提供している Colaboratory を使うとインストール不要で機械学習の開発を始めることができます。必要なのは、HTML5に対応したWebブラウザだけです！

## Colaboratory を使うメリット
Python 環境をインストール不要、最初からよく使うライブラリの一式がインストール済み。
サーバのOS は、Ubuntu(Linux)なのでUbuntuで動作するツールやライブラリであれば自由にインストールして使用可能。
仕組みは、Colaboratoryのサーバで計算が行われ、結果だけがWebブラウザに返されて表示される。


##Google Colaboratory を開く
https://colab.research.google.com/


##GPUをアサイン
メニュー ランタイム > ランタイムのタイプを変更 で、 ノートブックの設定 を開く
ハードウェア・アクセラレータに GPU を選択し 保存 する

## どんなサーバーなの？

次のコマンドを実行するとわかるよ

- !cat /proc/cpuinfo
- !cat /proc/meminfo
- !cat /etc/issue
- !df -h
- !free -h
- !cat /proc/cpuinfo
- !nvcc -v
- !nvidia-smi

```
Sat Jan  4 12:04:20 2020       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.44       Driver Version: 418.67       CUDA Version: 10.1     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla T4            Off  | 00000000:00:04.0 Off |                    0 |
| N/A   37C    P8     9W /  70W |      0MiB / 15079MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+
```

Tesla T4だって！:grinning:
AI専用サーバーを構築しようと思ったけどやめました。:blush:

##制約
- 最大利用時間は１２時間
- 最大利用時間を超えると全部初期化されて消えてしまう

##Google Drive をマウントするといい
Colaboratory の左にある > からドライブをマウントをクリックすると Google Drive を
/content/drive/My Drive/　以下にマウントすることができる。
必要なファイルは、Google Drive にアップロードすればすぐにみられる。
12時間を超えてもちゃんとファイルは保存されてる。

ディレクトリの移動は、cd で行える。
ちなみに ls ll などのコマンドも使える。

##ちょっとグラフを描いてみる

```Python
import numpy as np
import matplotlib.pyplot as plt

x = np.arange(0, 10, 0.1)
y = np.sin(x)
plt.plot(x, y)
plt.show()
```
![コメント 2020-01-04 212935.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561197/0ff1cb35-b038-d371-c41a-ed23ef1e61b8.png)
e-ラーニングについて

小売業の辛いところですが
ようやく年末年始が終わって、崩した体調も回復したので
投稿を再回します。

# e-ラーニングとは
平たくいうとインターネットを使った学習です。

プログラミング学習では
paiza,progateやμdemyが有名で

昨今では社員研修でも注目を浴びています。

# e-ラーニングのメリット

基本時間、場所を選ばす大幅なコストの削減やペースの調整ができます。
もっと詳しく書くと以下の3点が挙げられます。

## 受講者を集める必要がない

現代人は何かと仕事の都合で集まるのが難しいです。
e-ラーニングなら時間と場所を選ばないので都合がとても良いです。

## コスト低減

イニシャルコスト(導入費用)はかかりますが
会場の手配や資料の印刷など様々な費用がなくなるので
コストが限りなく抑えられます。

## 受講者情報の管理

そもそもPC上でやるのでダイレクトに情報を登録
そのまま管理を行えるので、手間隙が抑えられます。

# e-ラーニングのデメリット

忘れてはいけないのはデメリットもあるということ

## モチベーションの持続困難

時間、場所を選ばないのがかえって、継続や受講を疎かにしてしまうことがあるので
SNSなどの繋がりでモチベーションをあげていくのが重要です。

## 実技には向かない

形式的に実技を行い難いので、実技の受講には向きません

方法としてwebカメラを使った受講や,VRなどの使用が挙げられます。

## ネットワーク環境必須

前提としてネットワーク環境がないと受講できないこと

CD,DVDにデータを入れるなり、環境があるところで一旦ダウンロードするなど方法があります。


# e-ラーニングの企業

推定でも72件以上ありますが

2019年3月31日を推定して
営業利益TOP5を紹介すると

1位ジャストシステム:75億9915万(連結)
2位ＥｄｕＬａｂ:9億3782万(連結)
3位レアジョブ:1億7818万(連結)
4位チエル:7770万(連結)
5位すららネット:6837万(単独)

などあります。
JavaScriptのmap()メソッドについて

# はじめに
現在、JavaScript、jQueryを使って簡単な検索予測機能をつくっています。
その際、新しい配列の要素を作るために.map()メソッドを使用したのですが、引っかかった部分がありましたので、記事にしてみました。

# 疑問点
複数のワードに対して検索予測をかけるために
ここでは、inputタグにて入力された値を配列に入れ、正規表現に変換することまでを目的にしています。

```Javascript
//HTMLの<input>タグで下記のようにid="keyword"が与えられている状態
//<input type='text' id="keyword" class="form-control">

//配列inputsの要素に対して、入力された文字を先頭として始まる文字列を表現する
//ために"^"を付け足すための関数
  function editElement(element) {
      let result = "^" + element;
      return result;
    }
  
  //①入力された文字列をval()で受け取る。
  let input = $("#keyword").val();
  //②split("")で配列としてinputsに納める。
  let inputs = input.split(" ")
  //③inputsの要素に対して正規表現を加えるために、コールバック関数editElementを
  //呼び出す。
  let newInputs = inputs.map(editElement); //←ここで疑問点
  //④.join("|")でRegexpで使える形に変換し変数regに代入する
  let reg = new RegExp(newInputs.join("|"));
```

.map()によってeditElementが呼び出された際、実引数として何も指定されていないのに仮引数に(element)が使われ、配列の要素の値が変換されています。本来なら実引数として、配列の各要素を指定しななければいけないのではないかと疑問が湧いたので.map()について調べてみました。

#調べた結果

まずリファレンスにある、.map()メソッドの構文を見てみると

```Javascript
array.map(function(currentValue, index, arr), thisValue)
```
となっています。
.map()の引数として使われるコールバック関数はcurrentValue(required), index(option), arr(option)という三つの引数をとり、currentValueの部分には配列の要素の値が渡されます。その値がコールバック関数で引数として使用されます。

これを踏まえて、元のコードに戻って確認してみると
inputs.map(editElement)で呼び出された
function editElement(element)には引数として、配列inpusの各要素の値が渡されていることがわかります。

要するに、.map()メソッドは「与えられた関数を配列のすべての要素に対して呼び出し、その結果からなる新しい配列を生成する」ためのメソッドなので、こちらから引数を指定しなくても、自動で配列の各要素をコールバック関数に渡してくれるようです。