OmniAICreator/Qiita-1.07M huggingface dataset:
データの型の確認方法

#Rでデータの型を確認する方法
データ分析にある程度なれてくると、データの型にぶつかることが多いと思います。
そこで「R データ型」などでググると下記のようなサイトで、`character`や`integer`を知るかと思います。
[統計解析フリーソフト R の備忘録頁 25. データ型とデータ構造](http://cse.naro.affrc.go.jp/takezawa/r-tips/r/25.html)

こういったサイトさんは間違いなく便利ですし、僕もこれで`factor`やら`numeric`やらへの変換方法を学びました。（ホントありがとうございます！）

で、本題です。複数列まとめて型を確認する方法、
それが下記です！

```
> sapply(table, class)
          ID        Weeks        Brand purchase_flg 
    "factor"    "integer"  "character"    "numeric" 
```

これだけです！
これで`sapply`で一発です！



一応、一列毎の型の変換方法や、「numericか否かの確認方法」を下記にしるします。


```
#僕がよく使う下記のtable （知らないよ！という方は過去の記事を見てね！）
> table
   ID Weeks Brand purchase_flg
1   A     1   ABC            1
2   A     2   ABC            1
3   A     3   DEF            0
4   A     4   ABC            1
5   B     1   DEF            0
6   B     2   DEF            0
7   B     3   DEF            0
8   B     4   ABC            1
9   C     1   ABC            1
10  C     2   GHI            0
11  C     3   ABC            1
12  C     4   GHI            0
13  D     1   GHI            0
14  D     2   GHI            0
15  D     3   ABC            1
16  D     4   DEF            0

#ID列がcharacterか否か確認します
> is.character(table$ID)
[1] TRUE
#TRUEということで、characterと確認できました。

#次にこれをfactorに変換します
> table$ID <- as.factor(table$ID)
> is.factor(table$ID)
[1] TRUE
> is.character(table$ID)
[1] FALSE
#この通り、factorになり、characterはfalseとなりました。ちゃんと変換されたことがわかります

#またclass関数で下記のように型を確認できます。
> class(table$ID)
[1] "factor"
```


次回は「複数列まとめて型変更する方法」をまとめます！
RailsでMongoDB使ってみようと思ったらLinuxが32bitだったのでハマった話

# あらすじ
RailsでMongoDB（Mongoid）使うぞ！

apt-getでmongodbってやると超古いのが入るから、リポジトリを追加してmongodb-orgとかいうやつを入れればいいっぽい（記事によっては書いてあるpublic keyが古いの注意）
（うちの環境はLinux Mint 17 32bitなので、ubuntu14.04用の手順）
https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/

不穏な空気を[ arch=amd64 ]から感じつつ、そこは消してやってみる

```
>sudo apt-get install -y mongodb-org
E: パッケージ mongodb-org が見つかりません
```

やっぱりだよ！

# 判明した問題点
32bit linuxはもはやサポートされていない

# 無理やり解決する
以下を参考に古いバージョンをインストールする。32bitサポートの最新は3.2.22っぽかったのでそれを使った。
あと、なんかうまく起動しなかったのでfork: falseにかえた（もはや調べる気力がなかった）
https://dzone.com/articles/installing-mongodb-on-32-bit-ubuntu-1510

# お断り
手元でちょっと遊ぶ用なのでやってみただけで、あんまりよろしくないのは明らか
【初心者向け】勉強会やもくもく会に参加して知り合いを増やしてプログラミングライフをもっと楽しもう

# はじめに

プログラミングの勉強を独学で開始し半年ほどを経過してから、今度は少しずつ勉強会、もくもく会に参加するようになり3ヶ月程度が経ちました。

会への参加を重ねることで徐々に知り合いの方も増え、プログラミングライフの充実を感じてきています。

そこで、本記事では、会にまだ参加していなかった頃、会に参加したての頃の気持ちや記憶を忘れないうちに、勉強会・もくもく会の参加までの道のりや会での過ごし方を初心者目線で書き残します。

# 本記事の対象者

書籍や動画、オンライン学習サイトなどでプログラミング勉強を開始したものの、勉強会やもくもく会にはまだ参加したことの無い人

# twitterアカウントを用意しよう

この後に紹介するconnpassでのアカウント登録や、勉強会の他の参加者との事前、事後の交流にも便利なので、twitterアカウントを用意することをおすすめします。

# 勉強会、もくもく会の探し方と参加方法

[connpass](https://connpass.com/dashboard/)には数多くの勉強会、もくもく会が登録されています。

アカウント登録後、「このイベントを申し込む」ボタンで申し込めます。

後は、当日会場に向かうだけです。

受付ではconnpassの受付票をスマホで見せ、必要に応じて参加費を支払ってください。

# どのような会が良いか

## おすすめ1 初心者歓迎の会

イベントの説明文に初心者歓迎、駆け出しエンジニア歓迎といった記載があるものがおすすめです。

こういった会は主催者側も当然初心者の参加を想定していますし、参加者に占める初心者の割合も多くなるので、参加にあたって心理的ハードルは低いかと思います。

## おすすめ2 ある程度参加人数の多い会

少人数の会に参加するのは最初は勇気がいるかもしれません。

参加者50名以上など規模の大きい会もあるので、そうしたものを探してみましょう。

## おすすめ3 参加費が無料から1000円程度の勉強会

勉強会の中には参加費として数千円以上を求めるものもありますが、無料や1000円程度のものも数多くあります。この1000円も懇親会の飲食費だったりして、勉強会本体としては実質的に無料です。

最初に参加する会は特別な理由が無い限り、こうした低額の参加費で済む会が良いかと思います。

なお、こうした低額の費用で会に参加できるのも、主催者や設営をされる方、会場を提供する企業の厚意があってのことなので、感謝の気持ちは忘れないようにしたいですね。

# 行きたい勉強会が見つかったが参加枠がいっぱいになってしまっていたら

connpassでは、例えば「先着順 67人/65人」といったように、参加枠に対して、申込者が溢れてしまっている場合があります。

こうした状況でも、前日などや当日に、仕事の都合や体調不良でやむなくキャンセルする人が出て、繰り上がって参加可能な場合があります。

参加枠がいっぱいでも魅力的な勉強会であれば、参加申込だけはして補欠登録しておいても良いと思います。

(キャンセルが出て補欠から繰り上がると、connpassから登録したメールアドレスに通知が来ます)

# 名刺の用意は？

会で知り合った方、打ち解けた方と挨拶の延長線上の行為として、名刺交換を行う場面はよく見かけます。

本名や勤務先の企業名、企業のメールアドレスを知られることに抵抗や問題が特に無いのであれば、勤務先の名刺をそのまま使えば良いかと思います。
ただ、これだけではSNSを通じた交流には繋がりにくいかと思います（その企業の名刺に、個人のSNSアカウントも併記されてない限り）。

私の場合は、twitterアカウントの他にブログと簡単なWebサイトを持っており話のネタにもなるので、それらURLを記載した個人の名刺を別に用意して、そちらを中心に名刺交換しています。

iOS、Androidでは手軽に名刺を作れるアプリもあります。

[すぐ名刺](http://iki-p.jp/app/)

とは言ったものの、わざわざ個人の名刺まで用意しなくても、「twitterやってますか？良かったらフォローさせてもらえませんか」の一言とともに、twitterアプリの機能でQRコードを表示、カメラでスキャンして、フォローし合うのもお手軽で良いと思います。

# 参加者と交流しよう

もくもく会であれば、自己紹介タイムや休憩時間があると思いますし、もくもく会・勉強会では会終了後に懇親会が用意されている場合があるかと思いますので、そうした時間を活用して参加者と交流しましょう。

# 立食形式の懇親会が始まったが誰と話せば良いかわからない時は

登壇された方に対しては、その登壇テーマをネタに話しかけやすいのですが、一方で登壇者は人気者でなかなか話し掛けるタイミングが掴みづらいかもしれません。

あたりを見回して自分と同じように一人でいる人がいれば、恥ずかしがらずに話しかけてみましょう。目が合ったら、話しかけるチャンスです。

大丈夫、懇親会なのだから話しかけられて嫌な人は基本いないはずです。

どうしても自分から話しかけられない人は、話しかけやすそうな雰囲気を出しながら飲み食いしながら待ちましょう。

きっと誰かが声を掛けてくれるはずです（私は、この方法でも結構声を掛けてもらったことがあります）。

# 会が終わった後は

参加した勉強会・もくもく会の様子や感じたことをブログやtwitterでレポートすると、自身の振り返りにもなりますし、それを読んだ人と新たな交流が生まれるきっかけになります。

# 最後に

最初は緊張もしますが、勉強会・もくもく会で知り合いが増えていくことは世界が広がり、プログラミングの勉強がより楽しいものとなっていきます。

この記事が勉強会・もくもく会に未参加の方の参考になれば幸いです。
【Laravel】フォームリクエストFormRequestでバリデーション前に入力値(Request)を整える

`ValidatesWhenResolvedTrait.php`の`prepareForValidation()`をオーバーライドすると、バリデーション実行前にリクエストに対して任意の処理を行い、データを整形できます:relaxed:

```php:/app/Http/Requests/MyFormRequest.php

    protected function prepareForValidation(): void
    {
        // ここで任意の処理を行う
        // 今回は、comment配列から、空の配列要素を取り除く処理を行う例
        if ($this->has('comment')) {
            $this->merge([
                'comment' => $this->trimEmptyElements(
                    $this->input('comment')
                )
            ]);
        }
    }

```
バリデーション前に入力値に任意の処理を行いたいことって結構ありますよね:blush:
以下オーバーライド元の処理を参考に掲載しておきます:dizzy:


### 参考

- https://laravel.com/api/5.6/Illuminate/Validation/ValidatesWhenResolvedTrait.html
- https://github.com/laravel/framework/blob/5.6/src/Illuminate/Validation/ValidatesWhenResolvedTrait.php#L10-L38
RxJSの各Subjectの挙動の違いを試せるデモを作った

## 一言で説明
Angular歴半年あるかないかの私がRxJSのsubjectと触れ合えるデモページを作成しての感想と反省、抱負を述べます。初心者の方におすすめの本や役に立ったサイトも併せて紹介します。

## Hello,Subjects!
RxJSには四種類のSubjectがありますが、きちんと使いこなせているでしょうか？
検索すればいくらでも説明やわかりやすいマーブルダイアグラムが出てきます。でも、勉強したての時に一気に読んだって覚えられないし、そんなにまだRxJSを使ったコード書いてもいないとピンと来なかったりします。ということで、それぞれのSubjectの違いをビジュアル的に理解するためのデモサイトを作ってみました。

：[Hello,Subjects](https://master.d1t0005mradh7l.amplifyapp.com/)

まだまだ追加したい内容や直したいところはたくさんありますが、抱え込んで全てを消化するまで待っているとどんどん時間が経ってしまうと思ったので一度区切りをつけて公開することにしました。そこまで複雑な機構のあるものではありませんが、ぜひsubjectと触れ合いに来ていただければと思います。ちなみにもしRxJS初心者の方がいれば、[前回の記事](https://qiita.com/rena_m/items/25b0db2bfe77344612b5)では具体的にRxJSのsubjectの取り扱い方をまとめたのでよければそちらもどうぞ:snowflake:

## 反省 (アニメーション編)
「かわいくて、わかりやすくて、役に立つ」が作れるエンジニアを目指しているので、今回も色々可愛い要素を取り入れたつもりです。結構ガーリーなかわいさに寄った印象ですね。知識としては多少知っていたものの、これまでほとんど実際に手を動かしてアニメーションを使ったことがなかったので、そこそこ苦戦しました。

アニメーションをもっと思い思いにかけるようになると一段上のクオリティを目指せるのではないかと感じるので[100DaysCss](https://100dayscss.com/)とかを地道に続けてアニメーションに強くなりたいです。今回はちょうどforwardsでアニメーションを2つ繋げることに挫折したので、目下スムーズにアニメーションを繋げることができる、を目標にしたいと思います。

以前Youtubeで見た講演で、「認知的負荷を減らすためのアニメーション」について知りました。ただ可愛さを出すためだけでなく、こうして役に立つアニメーションの利用もマスターしたいです。

## 反省 (制作時間)
本当は昨年末には一旦目処をつけたいと思っていたのですが、だんだん実装したい内容が増えたり、単純に忙しかったりで長引いてしまいました。個人開発だと人を巻き込む納期が存在しないので、あれもこれもとつい進めてしまい、**満足するまで着地できなくなりがち**で良くないですね。次回以降この反省はきちんと生かしていきたいです。

途中でIssueによる管理をはじめてから、ラベルをつけたりするときに「これは今すぐやらなくても最低限の動きは担保できるな」とか「これはbugだからenhancementのものより優先してやらないとな」などの整理がしやすくなったのでよかったです。個人開発だとしても、頭の中に構想をまとめておくのではなく、アウトプットして整理した方が捗ると感じました。ということで、**Issue管理おすすめ**です。

## 感想(AWS Amplify)
デプロイにはAWS Amplifyを使いました。以前cliを使ってデプロイしたことがあったのですが、今回はコンソールのGUIから行いました。個人的にはcliよりこっちの方がスムーズでした。cliも驚くほどスムーズではありますが、一度作成した後の管理はコンソールの方が楽な印象です。私はcliの時は東京リージョンで作成したのですが、**2019年2月現在コンソール経由ではアジアを選択できない**ので、デプロイしたアプリ一覧などで確認することができません。最初はそれを知らなくてあれ！？ない！！と焦ってしまいました。

それから、cliの時は実行した後に**手元に色々なaws関連のファイルが増え、正直どれをpushしていいものなのかと結構不安になりました。**(アカウント名っぽいものが入っていたりしたので)普通に乗っかって進めたときに自動デプロイのような設定にも出会いませんでしたし、初心者の方であればコンソール経由の方が安心できるのではないかと感じました。

## 感想 (Sass)
これを作っている最中で、[Sassの教科書](http://book.scss.jp/)という本を読みました。これが結構わかりやすくて、サクサク読めておすすめです。これを読んでから自分のスタイルを見たら修正したいことだらけで大変でしたが、sassの機能を積極的に使うようになったおかげで連動して変わって欲しい部分を一気に変更できたり、後から見てわかりやすい計算式で値を記述しておくことができたりしてとても捗りました。まだ**sass,lessを使ったことがない！という方やそこまで変数や関数を積極的に使ったことがないという方には全力でオススメ**します。

## 次回への抱負
今回はほぼウェブサイトのような内容になったので、あまり複雑なロジックを書くことがありませんでした。次回はもう少し外部とのやり取りや綿密なロジックを必要とするものを作ってみたいです。今の所は編み図エディタが作りたいなあと思っています。編み図と聞いて「知ってる、便利だよね！」と思う方はよかったら一緒に作りましょう。
以上です。最後まで目を通していただきありがとうございます:dog2:
MNISTのデータ構造をNuｍPyを使って理解する

### MINSTのデータセットの中身を知る
modelにどんなデータを渡しているのか理解するためにデータの中をみてます  

[目的]
チュートリアルやサンプルなどで書かれている処理の内容を理解するにはデータの構造がどうなっているのか知る必要ある。
そのために、numpyの基本的な配列操作の扱い方を覚えること、そしてデータがどのようになっているかを知ることでデータの渡し方を理解できるようになりたい。
 

```
from keras.datasets import mnist
# データ取得
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()

# train_imagesの配列を見る
print("配列の軸数：" + str(train_images.ndim))
>>> 配列の軸数：3

# テンソルの形状
print("テンソルの形状：" + str(train_images.shape))
>>> テンソルの形状：(60000, 28, 28)

# データタイプ
print("テンソルのデータ型：" + str(train_images.dtype))
>>> テンソルのデータ型：uint8
# uint8 は 8bit 整数型
```

### 次に訓練データの画像をプロットしてみる
```
# 28px * 28pxの画像を表示してみる 
digit = train_images[4]

# 28 * 28の配列のデータをプロット
import matplotlib.pyplot as plt
plt.imshow(digit, cmap=plt.cm.binary)
plt.show()
```
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3230323539312f62303232636237612d653432332d333963342d653931302d3462613166316364633463662e706e67.png](https://qiita-image-store.s3.amazonaws.com/0/294552/78045f69-e0ae-03c9-fef1-b9e759b4ded6.png)

### 配列操作でよく使われるやつ
```
# NumPyでのテンソルの操作
# train_images 60000の 10 - 1000までを取り出す※２次,３次軸は暗黙的に全て取得
my_slice = train_images[10:100]
my_slice.shape
>>> (90, 28, 28)

# train_images 60000の 10 - 1000までを取り出す※２次,３次軸は明示的に全て取得
my_slice = train_images[10:100, :, :]
my_slice.shape
>>> (90, 28, 28)
# 結果は同じ

# train_images 60000の 10 - 1000までを取り出す※２次,３次軸は0-28(全て）までを取得
my_slice = train_images[10:100, 0:28, 0:28]
my_slice.shape
>>> (90, 28, 28)
# これも結果は同じ

# １次元目全て、　２次元、３次元目は14-全て
my_slice = train_images[:, 14:, 14:]
my_slice.shape
>>> (60000, 14, 14)

# １次元目全て、　２次元、３次元目は7 から(28-7)までを取得
my_slice = train_images[:, 7:-7, 7:-7]
my_slice.shape
>>> (60000, 14, 14)
```

### 振り返り
MNISTで使われているデータの形が理解できた
1. MNISTでは学習データを3次元テンソルから2次元テンソルへ変換している
(60000, 28, 28) → (60000, (28 * 28)) 
※MNISTで利用するmodelはベクトルデータを扱うモデルを利用している
※現時点でKeras、Tensorflowのライブラリの中身を見てないので詳しいことはわかっていません

2. MNISTのラベルデータ（分類データ）は keras.utils.to_categorical()を使ってデータを成形している
※MNISTで利用するmodelはラベルデータをone-hotで渡す仕様らしい
※ほかのデータを受け取るmodelもあるらしい

```
from keras.utils import to_categorical
train_labels = to_categorical(train_labels, 10)
test_labels = to_categorical(test_labels, 10)
# one-hotエンコーディングしてくれる関数
```

### まとめ
MNISTの機械学習の流れの理解に役立った。
レイヤー層の扱いもいろいろルール（お作法）が存在するらしいのでその辺は改めて学びたい。
Ruby+ Selenium Webdriverでスクレイピング

参考: 

- https://morizyun.github.io/web/selenium-cheat-sheet.html
- https://qiita.com/yulily@github/items/c3edbe25e84280c17776


## 準備
### gemをインストール

```ruby:Gemfile
gem "selenium-webdriver" #アクセス用
gem "pry-byebug" #デバッグ用
```


```bash
$ bundle install
```



## ミニマムに実行してみる



### 必要なgemをrequire

```ruby:
require "selenium-webdriver"
require 'pry'
```



### Chrome用ドライバオブジェクト取得

```ruby
driver = Selenium::WebDriver.for :chrome
```



### URLにアクセス

```ruby
driver.navigate.to "https://www.google.co.jp/"
```



### name= "q"要素を取得

検索formインプット部分

```ruby
inputElement = driver.find_element(:name, 'q')
```





### 取得要素に検索ワードを設定

formに値が指定される

```ruby
inputElement.send_keys "パンケーキ"
```



### ボタンを探してきて、サーチする

buttonは2つあるので、"Google検索"の方を選択。(もう一方のボタンは"btnI")

```ruby
submitElement = driver.find_element(:name, 'btnK')
submitElement.click

# inputElement.submit これだけでも良い
```



### ドライバは終わったら必ず閉じる

```ruby
driver.quit
```



## 入門



このサイトから”ペッシェドーロ東戸塚”を取ってくる<https://r.gnavi.co.jp/city/kanagawa/cwtav2440000/pancake/rs/>

“パンケーキ”の検索結果は、div.r > aの10件のリンク

find_elementメソッドは最初にヒットしたエレメントを取得

(全件ならfind_elements)

```ruby
search = driver.find_element(:css, "div.r>a")
search.click
```



店名は a.result-cassette__box-title に入っている

```ruby
content = driver.find_element(:css, "a.result-cassette__box-title")
puts content.text
```



最終的なコード


```ruby:sele.rb
require "selenium-webdriver"
require 'pry'
# Chrome用のドライバを指定
driver = Selenium::WebDriver.for :chrome

# Google検索にアクセス

driver.navigate.to "https://www.google.co.jp/"
# name属性にqが設定されている要素を取得
inputElement = driver.find_element(:name, 'q')
#
# # 取得した要素にパンケーキを設定
inputElement.send_keys "パンケーキ"

# ボタンを探してきて、サーチする（ボタンは2つあるので）
# submitElement = driver.find_element(:name, 'btnK')
# submitElement.click

inputElement.submit #これだけでも良い

#検索結果の最初の一件を取得
search = driver.find_element(:css, "div.r a")
search.click

#店名を取得
content = driver.find_element(:css, "a.result-cassette__box-title")
puts content.text

#閉じる
driver.quit
```



### 結果



```bash
$ ruby sele.rb 
> ペッシェドーロ 東戸塚
```



できた！！！
アニメをタイトル毎に自動振替し、フォルダに格納する

# 前置き
下書きがいっぱいになっているので、とりあえず投稿
過去にやったことで、内容の信憑性はちょっと、あれかも。
でも、消すのももったいないので、投稿。

# 本題
chinachuで録画してから、WindowsにDLし、mp4にエンコードしている。
しかし、ファイルが多くなってきたので、整理したくなった。

##これでやること
1. 指定フォルダ内のmp4を全て抽出 **←batファイル**
2. ファイル名の空白より前のテキスト抽出 **←ここからjava**
3. ２で抽出したテキストと同じフォルダがあるか検索
4. 同じフォルダが無ければ作成
5. 該当フォルダにファイルを移動

##コード
###animeSelection.bat


```animeSelection.bat
@echo off

# 該当フォルダ内のmp4をmp4FileName.txtに格納する
dir C:¥Users¥izumi¥Videos¥アニメ¥*.mp4 /a-d /b > mp4FileName.txt

# mp4FileName.txtを1行づつ取り出し、javaに渡す
for /f %%a in (mp4FileName.txt) do ( ^
  java animeSelection.animeBatch %%a
  timeout 3
)
```

###animeSelection.java
```animeSelection.java
package animeSelection;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class animeBatch {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String filename = args[0]; //引数を格納
		String title = null;
		System.out.println(filename);
		
		int i = filename.indexOf("　"); //全角空白の位置取得
		if(i == 0){
			System.out.println("該当の文字は見つかりません。");
		} else {
			System.out.println("終了位置は" + i + "です。");
			
			title = filename.substring(0, i); //空白より前を切り取り
			System.out.println(title);
		}
		
		
		File dir = new File("c://Users/izumi/Videos/アニメ");
		File[] list = dir.listFiles();
		System.out.println(list.length);
		
		int ll = list.length;
		
		//フォルダ内のファイルを確認
		for (int j = 0; j < ll; j++){
			if(list[j].isFile()){
				//System.out.println("[F] " + fn.getName());
			} else if(list[j].isDirectory()){
				//System.out.println("[D] " + fn.getName());
				String dname = list[j].getName();
				System.out.println("dname: " + dname);
				System.out.println("title: " + title);
				if(dname.equals(title)){
					System.out.println(title + "がありました。");
					moveDir(title, dir, filename); //フォルダがあればmoveDirでファイルを格納
					break;
				}
			}
			if(j == ll-1){
				makeDir(title, dir);
				moveDir(title, dir, filename);
			}
		}
	}


	private static void makeDir(String title, File dir) {
		// フォルダを生成
		File newdir = new File(dir + "/" + title);
		if(newdir.mkdir()){
			System.out.println("oooooフォルダ作成成功ooooo");
		} else {
			System.out.println("xxxxxフォルダ作成失敗xxxxx");
		}
	}

	private static void moveDir(String title, File dir, String filename) {
		// ファイルを該当のフォルダに格納
		System.out.println("ファイルを移動するよ。");
		try{
			Path sourcePath =Paths.get(dir + "/" + filename);
			Path tergetPath = Paths.get(dir + "/" + title + "/" + filename);
			System.out.println(sourcePath + "を" + tergetPath + "に移動します。");
			Files.move(sourcePath, tergetPath);
			System.out.println("移動成功");
		} catch (IOException e) {
			e.printStackTrace();
			System.out.println("移動失敗");
		}
	}

}
```
Marp でページ番号の大きさを変える

ファイルの最初に以下を記述する。

```
<style>
.slide_page {font-weight:bold;transform:scale(2);margin:12px;}
</style>
```

`.slide_page` がページ番号のスタイルなので、そのサイズやマージンを変更している。`font-size` を直接変えてもダメだった(おそらく Marp 側で上書きしている)ので、`transform` を使って無理やり。ちなみにページ番号以外にも、[このディレクトリ](https://github.com/yhatt/marp/tree/master/sass/themes)で設定されているクラスのスタイルをいじれば色々悪さできる。

これで質問する人もページを確認しやすくてハッピー。

<table>
<th>Before</th><th>After</th>
<tr>
<td><img src="https://qiita-image-store.s3.amazonaws.com/0/117994/b5ccee9a-7968-0901-0343-6e9b8160159e.png"></td>
<td><img src="https://qiita-image-store.s3.amazonaws.com/0/117994/fc8a65d1-9a50-4bc2-85f3-1279bbae7c65.png"></td>
</tr>
</table>

Marp は作者の方が正式版を作っている間、永遠に古い版が放置されているので、古い版で自分の作りたいスライドを作るために黒魔術が発達していて趣がある。
リストをボタンクリックでクリップボードにコピーしたい。

# Introduction
ボタン一つでリストに書いている情報をクリップボードにコピーして、メモ帳とかにペーストしたくなった話。

`textarea`の入力値を`execCommand("Copy")`するとよいらしいのですが、今回は`<ul>`のリストとして表示しているitemをコピーしたかったのでちょっと工夫。

# コピー対象

```html:sample.html
<ul id="copy_target">
  <li>item1</li>
  <li>item2</li>
  <li>item3</li>
</ul>

<button type="button" id="copy_button">Copy</button>

<div id="copy_area"></div>
```

こんな感じのHTMLをイメージしてます。`copy_button`をクリックするとクリップボードにコピーされて、メモ帳とかにペーストすると

```text
item1
item2
item3
```

となることをめざします！
`<div id="copy_area"></div>`は今のところ何も表示されていませんが、隠し味です。

# いきなり答え合わせ

```coffeescript:sample.coffee
$("#copy_button").click ->
  list = $("#copy_target li")
  $("#copy_area").append('<textarea id="copy_textarea"></textarea>')
  target = $("#copy_textarea")
  list.each ->
    target.append($(@).text() + '\n')
  target.select()
  document.execCommand("Copy")
  target.remove()
  alert("ブレスト結果をコピーしました！")
```

coffeescriptで書いてます。それぞれ何をしているのか説明します！

# コードの中身
```coffeescript
$("#copy_button").click ->
```
まず、ボタンクリックをトリガーにしてます。

```coffeescript
list = $("copy_target li")
```
ここで、`<ul id="copy_target"></ul>`内の`<li>`要素たちを`list`に入れてます。

```coffeescript
$("#copy_area").append('<textarea id="copy_textarea"><textarea>')
target = $("#copy_textarea")
```
`<div id="copy_area">`内に一時的に`textarea`を作りました。その要素をtargetに入れてます。

```coffeescript
list.each ->
  target.append($(@).text() + '\n')
```

`list`の中には3つの`<li>`要素が入っているので`each`を使って一つずつ取り出してあげます。
そして、`append($(@).text()`でその要素ごとの文字列を先ほど作った`textarea`の中に入力していきます。`'\n'`を入れることで`<textarea>`内で改行してあげてます。

```coffeescript
target.select()
document.execCommand("Copy")
```
ここまでくれば普通のtextareaのコピーとやり方は一緒です。`select()`で`textarea`に入力している文字列を全選択し、`document.execCommand("Copy")`でクリップボードにコピーします。

```coffeescript
target.remove()
```
このままだとさっきまでなかったはずの`textarea`が残ったままになってしまうので削除しちゃいます。

```coffeescript
alert("ブレスト結果をコピーしました！")
```
これはあってもなくても、他のやり方でもよいと思いますが、ユーザーにコピーしたことを伝えるためにダイアログを出して完了です。

# Conclusion
最初は「textareaならできるけど、リストは無理かー」みたいに簡単に諦めちゃうところだったのですが、`append()`を使うことでなんだってできることを知りました。今回は`<ul>`を使いましたが、この方法ならなんだっていけますね。

# Reference
- [クリップボードとのやりとり - Mozilla | MDN](https://developer.mozilla.org/ja/docs/Mozilla/Add-ons/WebExtensions/Interact_with_the_clipboard)
- [Coffeescript + jQueryでeachする時 - Ich habe hunger](http://sugi511.hatenablog.com/entry/2016/09/30/Coffeescript_%2B_jQuery%E3%81%A7each%E3%81%99%E3%82%8B%E6%99%82)
- [HTMLでテキストエリア(textarea)の改行をする方法とは【メンターが回答】 | TechAcademyマガジン](https://techacademy.jp/magazine/18396)
ハイブリッドアプリ開発するときはDate型に気をつけよう

## はじめに
ハイブリッドアプリを開発していて、Web上から動作確認してるときは普通に表示されているのに、実機で動かしたら全く表示されてない？！という現象が発生しました。その備忘録です。

## 現象

今回、投稿した記事の日時が現在時刻と比較してどれくらい経つかを計算して変換する実装をしていました。
投稿記事に「n分前」とか、「n時間前」とか出したかったんですね。
でも実機で見ると何も表示されなくなってる・・・ん・・・？ デバッグしてもNaN・・・・？ InvalidDate・・・？

## 原因

計算前の日時フォーマットが「yyyy-mm-dd hh: mm:ss」になっていました。
ブラウザ差異であるあるな話題ですが、以外と盲点。ハイフンだと動かないらしいです。

## 解決策

ハイフン → スラッシュにすることで解決。

```
let beforeDate = '2019-02-02 10:00:00';
let date = value.replace(/-/g, '/');
let resultDate = new Date(date);  /** 2019/02/02 10:00:00 にしておくことで無事に意図した挙動へ! */
・・・
```

Date型には気をつけましょう！！！！！
eglot を clone した solargraph に接続する

Emacs で LSP を使ってるときにちょっと Language Server 側にパッチを当てたかった。
その際、git clone した Language Server ([solargraph](https://github.com/castwide/solargraph)) に [eglot](https://github.com/joaotavora/eglot) を繋げるのに少し躓いたので自分用メモ。  

## 接続手順

### 1. solargraph の起動

以下をターミナルで実行

```sh
$ git clone git@github.com:castwide/solargraph.git
$ cd solargraph
$ bundle exec solargraph socket --port "YOUR_PORT"
```

これで solargraph がローカルで立ち上がる。
確認はターミナルで `top` コマンド等を実行すればOK。

(See: [solargraph/using the solargraph executable](https://github.com/castwide/solargraph#using-the-solargraph-executable))

### 2. eglot の起動

以下を Emacs で実行
（`univarsal-argument` は、後に続くコマンドに argument を追加できるコマンド）

```el
M-x univarsal-argument RET
M-x eglot RET
```

minibuffer 上で接続するプログラムを聞かれるので `localhost:"YOUR_PORT"` と入力
これで eglot が solargraph に接続しにいく。

(See: [eglot/conncting to a server](https://github.com/joaotavora/eglot#connecting-to-a-server))

## 動作確認

<img width="800" alt="Screen Shot 2019-02-02 at 18.18.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/144707/419ecdc9-6f32-db97-a9ce-731493a10bb9.png">

Mode Line 上に `eglot` の文字列が現れれば接続成功！
おつかれさまでした。
ORM論

#広義のORM論

@suke_masa さんのスライド、
https://www.slideshare.net/masatoshitada7/java-or-jsug
に触発されて、
もしも自分がアーキテクチャーの決定に全責任を持つとした場合、かつ、与件としてRDBMSとJavaを使うとした場合に、ORMに何を選定するか？現時点の解を出しておきたい。

開発者のスキルレベルにもよるが、そこそこのレベル（標準的という意味）だと仮定した場合に、現時点での優先順位は以下になるかな…
１．MyBatis
２．Doma
だいぶ離れて、JPA・・・
自前のDAOは無いな。

##◆まずMyBatisのメリットは「現実的なアプローチを採っていること」
どれか一つドキュメントを読むならこれを読んで欲しい。
http://www.mybatis.org/mybatis-3/ja/sqlmap-xml.html
この中にも、
「MyBatis は「データベースは必ずしも希望通りに定義されている訳ではない」という思想に基づいて設計されています。 すべてのデータベースが完全な第三正規形あるいは BCNF なら最高ですが、実際はそうではありません。 また、たったひとつで全てのアプリケーションに適合できるようなデータベースを作ることができたら素晴らしいですが、これも現実とは異なります。」という記述があります。

デメリットは、定義がXMLに寄せてあるので、「このご時世にXML地獄なのか？」という印象を持たれること。
ただし、XMLによるマッピング定義の学習コストはさほど高くないと思う。黒魔術になるくらいならちゃんと書こうよ。という姿勢もある意味潔いかな。
SQLの知識は当たり前だが相当に求められる。（というよりもSQLの知識を活かしやすい）

##◆Domaも魅力的である・・・
SQLファイルを一発書いたら、それをDomaからもRDBMSのプロンプトからも実行できる2-Way-SQLはやはり圧倒的な安心感がある。ピンチになったらヒント句書いておけばなんとかなるしｗ

SQLの知識を素直に活かせるという意味ではDomaはMyBatisと通じるものがある。ただし、Domaは元々はDomainを定義することに重きを置いており、現実世界の実用性から見るといくつかの機能不足がある。
MyBatisと比べた場合に、Association（関連するエンティティ）の紐づけ管理を、アプリ側の責務に寄せているのが個人的には残念。ただし、これは得られた結果をいい感じにDomainオブジェクトに詰め直す処理をJavaで書けば済む話なので、MyBatisのマッピング方言に慣れるか？Javaでマッピングを書くかは、最終的には好みの問題な気もする。

##◆JPAは厄介だｗ
JPA自体も厄介だが、さらに話をややこしくするのが中途半端にJPAやHibernateを使ったことがある輩がプロジェクトで変な動きをし出すと収拾がつかなくなる。
しかしながら、”由緒正しい標準である”という紛れもない事実は大きいので、ハマりどころと、それを避けるには結局どうすれば良いのか？というのは知っておいた方が良い。

ひとことで言うと、永続性コンテキストと関連やFetch戦略のオプションが複雑過ぎてコントロールしきれないということだと思う。すごい優秀なメンバーばかりで新規にテーブル設計もできるならJPAは最適解かもしれないが、そのような状況があまりないという現実を見据えるとやはり仕様がToo Muchだと思う。

皮肉なことに過去のプロジェクトではHibernateを使っていたが、なんとか乗り切るために、Hibernateの良さを殺す使い方をしていた。
まずは、Daoは永続性コンテキストから切り離した状態でEntityを返すことにしていた。従って、LazyLoadは使えない。
突き詰めると、Databaseは色々な形でデータを取り出したいというニーズに対応したものなので、ORMで隠蔽化する際にはある程度手間を掛けてマッピングせざるを得ないというのが現実である。
ところがJPAはこれをある意味真っ向から勝負してメタ定義一発でSQLを自動生成するというアプローチで解決を試みている。しかし現実にはメタ定義でモデルの関係性を定義しきれるものではなく、
JPQL、NativeQuery、Criteria、そして、JavaEE7では永続性コンテキストにアサインされないコンストラクタ式をサポートするという多様なアプローチで凌ごうとしている。
（実はアプリが単純であれば、JPQLでなんとかなるので、SpringJPAを使うとほぼノンコーディングでCRUD出来る。実際、チュートリアルレベルでは私もJPAは愛用しているｗ。しかし、現実の開発業務はそんなに簡単ではないので、様々な選択肢の中からチョイスすることになる。）

関連（OneToOneとかOneToMany）については、明らかにライフサイクルをともにするものに限りつけることを許可する。それ以外は、JPQLで明示的にFetchしてねという方針になっていく。
そうすると結局はSQL書いたほうが良いのでは？という話になる。
Qiitaで炎上したSQLオジサンの主張もあながち間違っていないwww

ちなみに、JPAでもNativeSQLがあるから良いじゃんという意見もあるが、あれはEntityにマッピングする場合には、永続性コンテキストを使うことには違いないので、永続性コンテキスト固有の厄介さとは無縁になれない。
更に言うと、永続性コンテキストを実質無効化して、NativeSQLを使うならばJPAにする意味がほとんど無い…

尚、JPAについてはこの辺の記事が非常に役立ちます。
http://enterprisegeeks.hatenablog.com/entry/2015/02/16/080922


##◆まとめ◆

結局、JPAに一番文字数を割いてしまった…。
永続性コンテキストを否定することを前提としたが、永続性コンテキストに載った状態で、ドメインロジック書くとJavaオブジェクトのミューテーターを呼べばよしなにJPAが面倒みてくれるのは非常に魅力的ではある。
ただし、世の中がイミュータブルに流れる中では、ミュータブルなオブジェクトを管理することに重きを置いていたJPAは時代遅れ（成熟する前に時代が変わってしまった）なのかもしれない。

案外JPAが好きだったのか、オレ？
Polycom SoundPoint IP 331との戦は今も続いている

戦始め
---

IP電話機Snom300が故障したので、替わりに中古のPolycom SoundPoint IP 331を購入しました。ヤフオクで1,000円程で落札できました。
管理者パスワードが初期化されてなくても使えるようになるだろう、と安易に思い購入したのですが、現在も思いの外苦戦しています。

<img src="https://qiita-image-store.s3.amazonaws.com/0/63318/284cb1f0-0b46-9537-2e13-91c5dd16caca.jpeg">

戦利品
---

前所有者が設定した管理者パスワードを出荷時設定値**456**に戻し、ファームウェアを最新版に更新することです。

戦術
---

:one:

- [Polycom SoundPoint IP電話機 出荷時設定への戻し方](https://qiita.com/TKY_JP1_CNT/items/d38d694e6582d967e346)の通りに実行します。
- この手順で【いったん】**456**にできましたが、その後最後までシステムが立ち上がると管理者パスワードが元に戻ってしまいます。
- 何度やっても元に戻ってしまうので、私は何かの不具合かと思い:two:の手順に進みましたが、多分**456**になった直後に出荷時設定すればそれでよかったのではと後で思いました。設定メニューをよく確認していなかったので、出荷時設定の項目を見逃していました。本当にそれでよいかは今となっては確認のしようがないですが。
- いずれにしろファームウェアを最新版に更新する必要があるので:two:に進みます。

:two:

- 仕方がないのでファームウェアを更新することにしました。多分これならすべて出荷時設定されるはずだと思ったので。
- また:one:を済ませ、すぐの起動途中で電源を再投入し、**Welcome ? secs until boot**のメッセージが表示されたら、すかさず**Setup**を押します。
- そうすると管理者パスワードを聞いてくるので**456**を入力します。
- その後[spitfire - Polycom IP 331 Firmware Upgrade](https://www.spitfire.co.uk/wp-content/uploads/2015/09/Polycom-IP-331-Firmware-Upgrade.pdf)に沿ってブート・サーバ等を設定・保存するとすぐに更新処理が始まります。**Upgrade to firmware version 4.0.8.1608**の手順で大丈夫です。
- 3.2.3.1734から4.0.8.1608にバージョン・アップしましたが、その後4.0.8.1608が最新版でないことに気づきました。
- [WEBCONTENT/directory.html](http://voipt2.polycom.com/WEBCONTENT/directory.html)を一つずつ確認しました。4.1.1.0731が最新版のようです。**Server Address: 140.242.64.35/411**にして最新版に更新します。

参考

- [Welcome to the Polycom VoIP Phone Provisioning Server](http://voipt2.polycom.com/)

後はWebインターフェースでSIP設定しようと思ったのですがこのありさまです。何も表示されません。

<img src="https://qiita-image-store.s3.amazonaws.com/0/63318/4fa72a47-279a-c96d-d050-0d72023ec70f.png">

うーん、いったいどうすればいいのでしょうか。^^;

~~戦が続く...~~
---

戦が終わる
---

ブラウザを Microsoft Edge に変えたら、Webインターフェースが使えるようになりました。
（情報提供者：@sitdownfire さん。ありがとうございます。）
Apple Swiftの高品質なチュートリアルを翻訳しています。

レイウェンダーリッチの高品質なSwiftチュートリアルを翻訳しています。
（３年前にも行なったのですが、挫折していました・・・）

URL:
https://www.doumeishi.me/raywenderlich.com/

Swift4.1で作る３マッチゲームの翻訳です。
このチュートリアルで作るゲームは、そのまま販売できちゃうんじゃね？
というぐらいレベルが高いです。
全部で３パートあり、パート１が翻訳完了済みです。
Swiftの勉強会とかに使ってもらえたら最高に嬉しいです。
是非みてやってください。

サイトの元はココ：
https://www.raywenderlich.com/
【最新サービス試用①】Gitの学習や検索に便利な「Git Command Explorer」を試用。

- 日々輩出される素晴らしき最新サービスを素早く試して、不鮮明な先見性を堂々と誇示する記事第一弾。
- 数多くの技術者達が、しっかりと技術学習に励んでいる中、[時間跳躍ごっこ](https://qiita.com/t_o_d/items/f5fbe4b1daec25f6e9bb)や[サービス調査](https://qiita.com/t_o_d/items/01301bc6c079e63d4020)に続いてまたもや新しい趣味に奔走する、泥沼ぶり。
- 今回は、そのような私の表面的な学習宣伝になるサービスを試用していくことにしよう。

## 試用サービス名
### 「[Git Command Explorer](https://gitexplorer.com/)」

## 概要
- Gitのコマンドを用途別に簡単に検索できるツール。
- コマンドのみならず、その説明も一緒に読むことができる。
- ワンクリックで、簡単にコピー可能。

## 手順
### 1. [こちらのURL](https://gitexplorer.com/)にアクセス
![image.png](https://qiita-image-store.s3.amazonaws.com/0/336499/56c2b5e2-3276-5446-f218-c1611eac8263.png)
### 2. 学びたい、もしくは調べたい操作を一つ目のプルダウンにて選択。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/336499/161512fb-c2eb-acd0-8d08-df9a27558636.png)
※例では、「delete/remove」の削除系コマンドを選択。
### 3. 一つ目で選択した操作の詳細を、２つ目のプルダウンで選択。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/336499/9b407665-1ec4-91ce-138c-a2741618805c.png)
※例では、「files from index」の管理対象からのファイル除外コマンドを選択。
### 4. 選択操作のコマンドと、その操作の説明が表示される。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/336499/4651105d-fc15-a45c-5dc4-3e7c1d5808f1.png)
### 5. 完了。
※その他、基本操作から便利操作等、様々なコマンドが簡単に検索できる。

## まとめ
- 今回はGit学習サービスということで、お気に入りに登録しておけば、簡単な操作から複雑なオプション指定を素早く検索することができると実感。
- 試用後、「暗記と検索からの逃避」が急速に脳内を駆け巡った私は、早期に「技術者適性判断」を受けて、烙印を押してもらったほうが良いのではと、不相応の即時紛失型自問自答をしてみる。
- これからもよどみなく続く、賢人の方々が開発した素晴らしきサービス達の、ふんだん試用を決断した私は、引き続き夢見心地調査へ戻る。

## 参考
- https://www.lifehacker.jp/2019/01/gitexplorer.html  
→今回の手順の参考にしました。大変お世話になりました。
python で テキストから複数個のハッシュタグを正規表現で抽出して、結果を配列で得る

python で テキストから複数個のハッシュタグを正規表現で抽出して、結果を配列で得る

# Example

```py
import re

match = re.findall(r'(#[^\s]+)', 'I like #cat and #dog both.')

# ['#cat', '#dog']
```

# One liner

```
>>> import re; match = re.findall(r'(#[^\s]+)', 'I like #cat and #dog both.'); match
['#cat', '#dog']
```

# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/550








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
git push (Ruby on Railsチュートリアル5章の5.5で発生)

#はじめに

Ruby on Railsチュートリアル5章の最後のgit push実施時に発生したエラーとそれを解決するときに行った方法をまとめました。

#エラーログ

```terminal
ec2-user:~/environment/sample_app (master) $ git push
Username for 'https://github.com': xxx@example.com
Password for 'https://xxx@example.com@github.com': 
To https://github.com/xxx/xxx.git
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'https://github.com/xxx/xxx.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
```

#実施したこと

###①git status

```terminal
ec2-user:~/environment/sample_app (master) $ git status
On branch master
Your branch and 'origin/master' have diverged,
and have 1 and 2 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)
```

####'origin/master = originという名前のレポジトリのmasterブランチ'
origin/masterからリモートとローカルでコミット差分があった際に発生する場合にこういった状態になるみたいです。

###②git pull

```terminal
Already up-to-date!
Merge made by the 'recursive' strategy.
```

とりあえず'recursive' strategyでマージされたみたいです。

###③git fetch

ログ出力無し

###④git merge origin/master

```terminal
Already up-to-date!
```

特に問題なさそうです。

###⑤git push

```terminal
Username for 'https://github.com': xxx@example.com
Password for 'https://xxx@example.com@github.com': 
Counting objects: 42, done.
Compressing objects: 100% (40/40), done.
Writing objects: 100% (42/42), 155.97 KiB | 13.00 MiB/s, done.
Total 42 (delta 15), reused 0 (delta 0)
remote: Resolving deltas: 100% (15/15), completed with 14 local objects.
remote: This repository moved. Please use the new location:
remote:   https://github.com/xxx/xxx.git
To https://github.com/xxx/xxx.git
   xxx..xxx  master -> master
```

無事pushできました。


##参考資料
◆エラーログ出力前(git pushする前)のgit log

```terminal

commit xxx..xxx (HEAD -> master, filling-in-layout）
Author: xxx <xxx@example.com>
Date:   Sat Feb 2 07:59:59 2019 +0000

    Finish layout and routes

commit xxx..xxx
Author: xxx <xxx@example.com>
Date:   Mon Jan 28 12:55:15 2019 +0000

    Add a full_title helper
```

◆手順④実施後のgit log

```terminal

commit xxx..xxx (HEAD -> master）
Merge: xxx xxx
Author: xxx <xxx@example.com>
Date:   Sat Feb 2 08:07:23 2019 +0000

    Merge branch 'master' of https://github.com/xxx/xxx

commit xxx..xxx (filling-in-layout)
Author: xxx <xxx@example.com>
Date:   Sat Feb 2 07:59:59 2019 +0000

    Finish layout and routes

commit xxx (origin/master)
Merge: xxx xxx
Author: xxx <xxx@example.com>
Date:   Sat Feb 2 06:54:40 2019 +0000

    Merge branch 'master' of https://github.com/xxx/xxx

commit xxx
Author: xxx <xxx@example.com>
Date:   Mon Jan 28 12:55:15 2019 +0000

    Add a full_title helper

```

##参考サイト
[gitで「Your branch and 'origin/***' have diverged」と言われたときの対処](https://qiita.com/hnw/items/5ac4416c72dd567b263f)
[【GIT】git pushしたら、error: failed to push some refs toとでたときの原因と対処法](https://chat-rate.com/it/2583/)
【WSL環境】sshを作成してgithubにアクセスするまでの道のり


WSLを導入後、ホームディレクトリーはWindows側に設定しました。
以下のリンクを参照
https://qiita.com/funafuna/items/c3bb78a546cf2605205d
<br>
今回はwslでgithubにアクセスできるよう設定していこうと思います。


##SSHを作る
SSHの作り方はGithubにも載っていました。
https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/

実際の手順はこちらから参照
https://qiita.com/shizuma/items/2b2f873a0034839e47ce
     
    cd ~/.ssh
    ssh-keygen

すると公開鍵（id_rsa.pub）と秘密鍵（id_rsa）が作成されます。



##作成したSSH(公開鍵)をgithubに設定

作成した公開鍵(id_rsa.pub)のコピー方法は以下を参照しました。
https://help.github.com/articles/adding-a-new-ssh-key-to-your-github-account/


clipコマンドがうまく動作しなかったため

    cat ~/.ssh/id_rsa.pub

で中身をコピーして、
GitHubに貼付け設定。
<br>
GitHubアクセスできるか確認

    ssh -T git@github.com
<br>
エラー

    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    @         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Permissions 0777とパーミッションがオープンすぎるらしく
パーミッションを変更。

    chmod 600 ~/.ssh/id_rsa

どの番号もダメでした。

##こちらの２つ目の方法を参照してみる
https://qiita.com/angel_katayoku/items/9d95241af81dc4466ee1

WSLのホームディレクトリをlinux側に変更して、.sshを作成

/home/ユーザー名/.ssh

再び公開鍵をGitHubに設定し、GitHubに接続できたか確認してみる

    ssh -T git@github.com

GitHubへのアクセスが成功しました。
<br>
しかし、ホームディレクトリをWindowsに変えると.sshが読みこんでいないようで、エラー。。

.bashrcの設定が必要なようで(環境変数的な？)
そこでまた以下ページを参照します
https://qiita.com/angel_katayoku/items/9d95241af81dc4466ee1
<br>
Windows側のホームディレクトリにファイルを作成


    touch ~/.bashrc

.bashrcに記述

    #SSH
    eval `ssh-agent` > /dev/null
    ssh-add /home/ユーザ名/.ssh/id_rsa >& /dev/null


.bashrcを読み込むが、githubにアクセスできない
 
    source ~/.bashrc
<br>


##先程のURL先の３つ目の方法を試す
https://qiita.com/angel_katayoku/items/9d95241af81dc4466ee1

    ln -s /home/ユーザ名/.ssh ~/


成功した！！


##まとめ
- sshの置き場所はフォルダーの手前側で保存しないとエラーが発生する(奥だとアクセスされやすいため)
- ln -sなどでシンボリックリンクを使ってアクセスするとエラーも起きず、GitHubにアクセス可能でした。
A1表記と26進数

# A1表記 (A1 notation)
表計算ソフトでは、行番号を通常の10進数、列番号を`A`から始まる大文字のアルファベットを組み合わせた文字列により表します。
この方法では一番左上のセルが `A1` という風に表されるため、この表記方法はA1表記と呼ばれています。

# 列番号は26種類の記号を使うから26進数じゃないの？
大文字のアルファベットは26種類なので、実質26進数なんじゃないの？という感じがしますが、一般的なn進数とは違った性質を持ちます。

なんとなく触っていると、思わぬ落とし穴にはまるかもしれません。
簡単にですが違いについて考えてみました。

## 10進数、26進数、A1表記の列番号の比較
* 0-9の記号を使った10進数
* A-Zの記号を使った26進数
* A1表記の列番号

この三つを比較してみましょう。

| 10進数 | 26進数 | A1表記 |
|:-:|:-:|:-:|
| 0000 | AAAA | ---- |
| 0001 | AAAB | ---A |
| 0002 | AAAC | ---B |
| ... | ... | ... |
| 0025 | AAAZ | ---Y |
| 0026 | AABA | ---Z |
| 0027 | AABB | --AA |
| 0028 | AABC | --AB |
| ... | ... | ... |

一般的なn進数ではゼロに対応する記号があります。10進数だと"0", 26進では"A"です。

一方で、A1表記の列番号では、ゼロに対応する記号がありません。上の表では代わりに"-"を使ってそれを表現しています。もし"-"を"A"に置き換えた場合、二桁に繰り上がったときに2桁目が"A"で始まるため、扱いに困ってしまいます。

26進数では、（ゼロの場合を除いて）最上位の桁が"A"になることはないため、そういった問題は起こりません。

したがって、A1表記の列番号では桁数の情報を暗黙的に持っており、それが本質的な意味を持っているのでしょう。そして、その情報の分、26進数より同じ桁数でも表現の能力も高くなります。

## A1表記の列番号から10進数への変換

```math
\begin{equation}
f(d) = 
\begin{cases}
    0, & d = \mbox{'A'} \\
    1, & d = \mbox{'B'} \\
    2, & d = \mbox{'C'} \\
    ... \\
    25, & z = \mbox{'Z'} \\
\end{cases}
\end{equation}
```

このように関数$f$を定義すると、26進数の10進数への変換は

```math
\Sigma_{i=0}^{D_{max}}{f(D[i])*26^i}
```

と表せます。ただし、$D$は26進数の数で、$D[i]$は右からi番目の桁の文字を表し、$D{max}$は$D$の最大桁の番号を表すものとします。まあ、これは一般的な基数変換の計算ですね。

A1表記の列番号から10進数への変換は、各桁がゼロ始まりではなく1始まりなので、$f$の値に+1することで、

```math
\Sigma_{i=0}^{D_{max}}{(f(D[i])+1)*26^i}
```

と表せます。

※26進数の場合は、最大桁の番号は必ずしも必要なわけではなく、これ以上大きなものはないという値（32bit整数における31のような値）が前もってわかっていれば、それでも構いません。

N文字で表される場合、表現できる数に$\Sigma_{i=0}^{N-1}{26^i}$だけ違いがあることがわかりました。

## 実装例 (Java)
26進数及びA1形式の列番号から、10進数への変換をJavaで実装してみます。

```java

public class Main {
    public static int f(char d) {
        return d - 'A';
    }

    public static int fromBase26Num(String base26Num) {
        int base10Num = 0;
        for (int i = 0; i < base26Num.length(); i++) {
            base10Num += (f(base26Num.charAt(base26Num.length() - 1 - i))) * Math.pow(26, i);
        }
        return base10Num;
    }

    public static int fromA1ColNum(String a1ColNum) {
        int base10Num = 0;
        for (int i = 0; i < a1ColNum.length(); i++) {
            base10Num += (f(a1ColNum.charAt(a1ColNum.length() - 1 - i)) + 1) * Math.pow(26, i);
        }
        return base10Num;
    }

    public static void main(String[] args) {
        System.out.println("【0が表示される】");
        System.out.println(fromBase26Num("AAAA"));

        System.out.println("【1が表示される】");
        System.out.println(fromBase26Num("AAAB"));
        System.out.println(fromA1ColNum("A"));

        System.out.println("【27が表示される】");
        System.out.println(fromBase26Num("AABB"));
        System.out.println(fromA1ColNum("AA"));
    }
}
```

実行結果

```
【0が表示される】
0
【1が表示される】
1
1
【27が表示される】
27
27
```

OK

# まとめ
* A1形式の列番号は一般的な26進数ではない
 * N桁だと、26進数より$\Sigma_{i=0}^{N-1}{26^i}$だけ表現できる数が多い
* 実装するときは気を付けましょう！

ここでは書かなかったですが、10進数からA1形式の列番号に変換するのはもっと面倒です。
https://github.com/ttk1/A1Util
需要があるかわかりませんが、ここに実装したものを置いています。（変数名・関数名がイケてないのはご容赦を！）

# 追記
> 10進数からA1形式の列番号に変換するのはもっと面倒です。

と書きましたが、@saka1029さんからのコメントの通り、思ったより面倒ではなかったです。
redux-thunkを使ってJSONPlaceholderと非同期通信してみた

#概要
題名の通りで、目標としてはJSONPlaceholderで提供されている100個のポストのタイトルを並べてみたいと思います。
#JSONPlaceholderとは
JASONPlaceholderはダミーデータを提供してくれているAPIです。

詳細　https://jsonplaceholder.typicode.com/
#redux-thunkとは
redux-thunkはreduxのmiddlewareの一種でreduxを使って非同期通信する際に有名なライブラリです。

詳細　https://github.com/reduxjs/redux-thunk

#コードを書いていく
必要なライブラリをインストールしましょう。

```terminal
npm install --save redux react-redux redux-thunk axios
```
axiosは通信を行うのに使います。以下で紹介しています。

参考　https://qiita.com/ssnyarii/items/d9758d6ab573b9b53c4b

まずはsrc/index.jsから

```javascript:src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';

import App from './components/App';
import reducers from './reducers';

const store = createStore(reducers, applyMiddleware(thunk));

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.querySelector('#root')
);
```
createStoreの第二引数にapplyMiddlewareでthunkを取り込んでいます。

次にsrc/reducers/index.js

```javascript:src/reducers/index.js
import { combineReducers } from 'redux';

export default combineReducers({
  dummy: () => 'dummy'
});
```
エラーが出るためとりあえずダミーにします。

次に、大事なsrc/actions/index.js

```javascript:src/actions/index.js
import axios from 'axios';

export const fetchPosts = () => {
  return async (dispatch) => {
    const response = await axios.get("https://jsonplaceholder.typicode.com/posts");

    dispatch({
      type: 'FETCH_POSTS',
      payload: response.data
    });
  };
};
```
redux-thunkはactionに関数を与えることができ、ここではJSONPlaceholderからデータを取得してdispatchしています。単にasync/awaitで通信を行うとエラーが出ます。

src/reducers/index.jsも作りましょう。

```javascript:src/reducers/index.js
import { combineReducers } from 'redux';

const postsReducer = (state = [], action) => {
  switch (action.type) {
    case 'FETCH_POSTS':
      return action.payload;
    default: 
      return state;
  }
};

export default combineReducers({
  posts: postsReducer
});
```
stateを配列で管理しています。

最後にsrc/components/App.jsで表示しましょう。

```javascript:src/components/App.js
import React, { Component } from 'react';
import { fetchPosts } from '../actions';
import { connect } from 'react-redux';

class App extends Component {
  componentDidMount() {
    this.props.fetchPosts();
  }

  render() {
    const title = this.props.posts.map((post, i) => {
      return <div key={i}>{post.title}</div>
    });

    return (
      <div>
        {title}
      </div>
    );
  }
}

const mapStateToProps = (state) => {
  return {
    posts: state.posts
  };
};

export default connect(mapStateToProps, { fetchPosts })(App);
```

ページを表示した時にデータを読み込みたいのでcomponentDidMount()でアクションを起こしています。
あとはmapで回して表示といった流れです。

#まとめ
今回はredux-thunkを使ってみました。reduxは難しいところが多いですが頑張って学んでいきます。
ビッグデータ向けプラットフォームに入門する

(2019/03追記: 記事が長くなったので一部分割しました。)

# はじめに
今日大規模データ処理には非常に多くの種類のプラットフォームが用いられています。

しかしその間口の広さから、これらのデータ処理基盤を勉強しようとする際、
どこから手を付けたらいいのかわからない、各基盤を解説した記事を読んでも知らない単語だらけ、
結局各基盤の違いがどこにあるか分からない、といったことが起こりがちです(私は起こりました)。

そこでこの記事では、データ処理基盤の全体感を把握することの第一歩として、
代表的な基盤であるDWH, Hadoop, NoSQLについて、特徴を比較しつつ解説していきます。

- この記事でわかること
    - 各基盤のなんとなくのアーキテクチャ・思想
    - それらに由来する特徴と使われる目的の違い
- この記事でわからないこと
    - 各基盤の具体的な使い方

# そもそもなぜ大規模データ処理基盤を使うのか
なぜ普通のRDBでない、大規模データ用の処理基盤が使われるようになったのでしょうか。
それは「**3V(Volume, Velocity, Variety)についての要請が高まったから**」ということに集約できます。

処理対象となるデータ量(Volume)の爆発的な増加とそれを高速に処理すること(Velocity)への要求が高まっていることはもはや言うまでもありません。
しかしRDBは単体のハードで動く必要があるため(詳細はNoSQLの節で後述します)、
ペタバイト級のデータを保持することは難しくコストにも見合いません。
また、データを格納できたとしても、Disk I/Oに膨大な時間がかかることとなり、
VolumeおよびVelocityに関する要件を満たすことが非常に難しいと言えます。

さらに、従来のように扱う対象となるデータの多様性(Variety)も増加していると言えます。
従来のようなスキーマが厳密に定義されたデータだけでなく、
RestfulなAPIから取得したJSONデータ、アクセスログなども扱う必要があります。
これらのデータもスキーマを定義し、RDBに格納することは可能ではあるものの、
定義自体が面倒であったり、仕様の変更に柔軟に対応できないという問題があります。

そのため、3Vの要件に対応できる大規模データ処理用の基盤が広く採用されているというわけです。

# 代表的なデータ処理基盤
一口に大規模データ処理基盤といっても、各プラットフォームにはそのアーキテクチャに由来する特性があります。
そのため用途に応じて複数のプラットフォームを使い分ける・組み合わせるのが一般的です。
一方で各基盤は互いに自分の苦手分野を補完するよう進化しているため、これらの特性は被る部分があり、
それぞれの特性がわかりにくい原因となっています。

しかし**基本的にはどのプラットフォームも分散処理を行うことを前提としたアーキテクチャ**と言えます。

これにより

- Disk I/Oを並列的に行うことで処理時間を短縮できる
- 高スケーラビリティで、容量を柔軟に変更することが可能

という特徴があります。

以下の子記事で歴史期的に登場した順にData WareHouse, Hadoop, NoSQLデータベースについて解説します。

## Data WareHouse(DWH)
[ビッグデータ向けプラットフォームに入門する - DWH](https://qiita.com/mito_110/items/fa224895d1e583bbffee)

## Hadoop
[ビッグデータ向けプラットフォームに入門する - Hadoop](https://qiita.com/mito_110/items/b83a2e38cef505b306d6)

## NoSQL
[ビッグデータ向けプラットフォームに入門する - NoSQL](https://qiita.com/mito_110/items/d76a92f6b78e62451a21)

## (RDB)
順番通り読んでいただいた方ならわかるかと思いますが、このような新しいデータ処理用のプラットフォームが出てきたからといって、**RDBがオワコンになったわけでは決してありません**。

トランザクション処理を確実に行うためにはRDBは不可欠です。
さらに(ある程度のデータ規模までは)非常に小さなレイテンシでデータにアクセスすることができ、
しかも非常に長い間使われているプロダクトのためチューニングのための知見が多く溜まっています。
間違いなく今後もRDBは生き残り続けるでしょう。

またここまで紹介した基盤の総括にもなりますが、https://www.slideshare.net/recruitcojp/rdbnosqlnosql にあるの各基盤の位置づけの図は非常にわかりやすいです。
[このスライドの作者である方の著書](https://www.amazon.co.jp/RDB%E6%8A%80%E8%A1%93%E8%80%85%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AENoSQL%E3%82%AC%E3%82%A4%E3%83%89-%E6%B2%B3%E6%9D%91%E5%BA%B7%E7%88%BE-ebook/dp/B07143JTD9)もわかりやすいのでよかったら読んでみてください。

# あとがき
大規模データの処理基盤としてDWH, Hadoop, NoSQLについての概要と特徴について見てきました。

思ったより長くなってしまいましたが、オブジェクトストレージや検索エンジンなどまだまだ触れていないプラットフォームもたくさんありますし、大規模データ処理を扱うのであれば、ログ収集、バッチ・ストリーム処理、ETLなどデータの収集やパイプラインについての知識も必要となるかと思います。
また元気が出ればここらへんの内容についても追加で記事を書きたいと思います。

記事の内容について誤り・補足等のコメントがあればぜひお願いいたします。
Laravelのルーティング

## 記事を書いた経緯

業務で初めてLaravelを利用し、いろいろと戸惑ったので備忘録用に。
基礎的すぎる内容ですが、コントローラを介してビューを表示させるというところまで書いていきます。

## Laravelのルーティング
###　①web.phpの記述

まずは`routes/web.php`に、『ここにアクセスしたら、このコントローラのこのファンクションに飛ぶ』という記述を追加します。

```ruby:web.php
Route::get('/user', 'UserController@index');
```
上の例では、「http://ルートディレクトリ/user」にアクセスした場合に、「UserController」の「index」の処理が行われるという内容になります。
他にも色々と書き方の種類がありますが、ここでは簡素なものをピックアップしました。

[公式リファレンス](https://readouble.com/laravel/5.6/ja/routing.html)に色々とあります。


###　②コントローラの作成

Laravelではコマンドを打つことによってコントローラファイルを作成する事ができます。
コマンドプロンプトでルートディレクトリまで移動したあと、以下のコマンドを打ちます。

```ruby:コマンドプロンプト
php artisan make:controller UserContoroller
```
上記で、`app/Http/Contorollers`にUserContorollerファイルが作成されます。
ここでは「users」ビューを返す記述をしておきます。

```ruby:UserContoroller
<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    public function index () 
    {
        return view('users');
    }

}
```

###　③ビューの作成

ビューは`resources/view`直下に、手動で作成します。
先程コントローラで記述した内容に沿って、ファイル名は『`users.blade.php`』とします。
bladeとは、Laravel特有のテンプレートエンジンです。

[公式リファレンス](https://readouble.com/laravel/5.5/ja/blade.html)にbladeについての詳細の記載があります。


ブラウザを開き、「http://ルートディレクトリ/user」にアクセスし、ビューが表示されれば成功です。
ここまでで『コントローラを介してビューを表示する』事ができました。


## モデルについて
Laravelには、デフォルトではモデルディレクトリが用意されていません。
なので自由なところにモデルディレクトリを作成する事ができます。
今回はコントローラと同じ`app/Http`に「UserModel」を作成します。

以下のコマンドを打ちます。


```ruby:コマンドプロンプト
php artisan make:model Models/UserModel
```
ズボラな機械学習エンジニアはとりあえずcomet.mlを使え

# TL; DR

- comet.mlという機械学習の実験データを保存できるサービスがある
- 1〜２分程度で学習過程のダッシュボードが作成できる
- 勝手にネットワークのグラフやログ出力を記録してくれる
- 過去にやった実験を忘れても再現できるようになる

実験ごとのログ取りが面倒な人はこいつでサクッとログ取りましょうって話。

# comet.mlとは
機械学習のgithubを目指している、機械学習実験を保存するサービスです。
https://comet.ml

comet.ml上では実験ごとに学習曲線やデータの入出力の可視化をしたり、
使用したハイパーパラメータとその値を、更には学習コードを記録することができます。

使い方は公式ドキュメントに投げます。Quickstartから順に読んで、例に従って書いていけばサクッと導入できます。
https://www.comet.ml/docs/

# なぜ便利か
とりあえず列挙しますが、それでも雰囲気すらわからないと思うで、これを読みながら、公式の概要説明動画を見ることをお勧めします（以下）
https://www.youtube.com/watch?v=xaybRkapeNE

#### comet_ml apiを通すだけでグラフとログを保存してくれる
tensorboardでグラフ構造を可視化すると場合によっては手間がかかりましたので、
何も意図して記述しなくてもグラフを出力してくれるのは嬉しかったです。

特にpytorchだと仕様がわからなくて断念したので嬉しいです。
ただしテキストベースでの出力になるので注意しましょう。

また、プログラムのログ出力もcometml上で見れるようになっているので、
ロギング機構を作る手間も省けました。いちいちsshを使ってCLIで見に行く必要もなくなりましたし。

#### ダッシュボードをカスタマイズできる
（2/3追記）学習曲線のグラフのグルーピングもできます。`Charts`の画面で下図の `Add Chart` を選択->まとめたい指標（例えばtrainとvalidationのaccuracy）を選択すると同じグラフに学習曲線をまとめられます。

![スクリーンショット 2019-02-03 13.18.07.png](https://qiita-image-store.s3.amazonaws.com/0/62541/e774fbde-43d4-f4f8-941b-9f4867b8edb1.png)

まとめた学習曲線はこんな感じ

![スクリーンショット 2019-02-03 13.22.02.png](https://qiita-image-store.s3.amazonaws.com/0/62541/1239e14b-7247-7476-a422-853b41273439.png)


#### 学習を再現できる
個人でkaggleに参加する場合などで、ズボラな人はいちいちgitにコードやハイパーパラメータを記録しないかと思います。そういう人に必ずあるのが、**過去の学習を再現できなくて後悔すること**かと思っています。

comet.mlならAPIをコードに挟むだけで、学習する度に学習過程を自動で保存してくれますので、ズボラな人でも過去の学習を再現できるようになります。コードを書くだけなので、わざわざ実験ごとにgitでブランチを分けるとかタグ付けするとかする必要がありません。

# お勧めする人
#### 個人で機械学習をやっている人
個人でやると、いちいちログ機構やダッシュボードを作っている余裕がないし、わざわざ他人に作ってもらう理由がないので重宝します。cometmlなら直近10件までの実験を無料で記録できます。実験記録がある程度publicになってもいい内容でしたらお勧めです。

#### ダッシュボードのサーバーを作るのが面倒な人
私がこれに該当しました。

GCP上で計算を回していたので、tensorboardサーバーを立てて、nginxでbasic認証を6006ポートに通そうとしましたが、面倒でやりませんでした。

cometmlのAPIを使って、cometmlにエポック毎のロスなどを記述すれば勝手にダッシュボードを作ってくれるのは便利でしたね。

#### fluentdなどロギング機構を作成するのが面倒な人
上と似たような動機です。インフラエンジニアじゃなかったらだるくないですか？

個人で機械学習をやる場合で、例えばstdoutとstderrの生の出力でも抵抗がない人は、勝手にプログラムの吐いたstdoutとstderrを記録してくれます。

#### 上記に関する知識がない人
機械学習からエンジニアになった人はインフラ側に関する知識が全然ない人が多いかと思います。kaggleなど個人で機械学習を行なっている人にも便利なものではないでしょうか。

# おすすめしない人
#### （無料版の場合は）仕事でデータを扱っている
無料版は全てのダッシュボードがパブリックになるので、仕事で使っている場合は注意しましょう

#### 学習曲線が見づらいと思う人
~~例えばtensorboardみたいに、訓練データのロストバリデーションデータのロスを、
一つのグラフにまとめてくれる機能はありません。確認できなかったので多分ないと思っています。~~

（2/3追記）嘘つきました。先述の通り一つのグラフにまとめる機能があります。

#### ネットワークのアウトプットが見づらい
上の動機に似ていますが、まだtensorboardに劣る点はあるかと思います。

ネットワークのグラフの出力がテキストベースなので、イメージで掴みにくいと思います。
ただし各層ごとのハイパーパラメータをしっかり出力してくれましたので、酷くて意味がないということはないかと思います。

# 注意点
勝手にコードを晒しますので、**クレデンシャルをコードに直書きとかは絶対にやめましょう。**大変なことになりますので、ズボラな人はご注意を。

# 最後に
まだ使い始めてまもないのでちょくちょく修正加えようと思っています。
UnityのSplash Screenでロゴ画像の縦横比がおかしくなる場合の対処

#TL;DR

Unity 5.5からゲーム起動時のロゴ表示シーンがPlayer Settingsで簡単にできるようになりましたが、透過画像の余白が大きいと縦横比が狂うのでSprite ModeのMesh TypeをFull Rectにしましょう。

# スプラッシュスクリーンの縦横比が変

元画像（画像は適当です）

![tekitou.png](https://qiita-image-store.s3.amazonaws.com/0/19010/f5958d60-7fc5-42d7-f2c2-29da034d66d4.png)

Unity Editorに入れてTexture TypeをSpriteにして、PlayerSettingsのとこでゲーム起動時ロゴに設定

![失敗.jpg](https://qiita-image-store.s3.amazonaws.com/0/19010/11737f39-5cc2-54d3-b1bd-79c32f61566f.jpeg)

なんでや！

理由は元画像をSplite Meshとして描画する際、透過部分をUnityがいい感じに裏で切り抜いているからです。（画像自体は1024x512なのですが）
というわけで画像の設定を変更します。Sprite ModeのMesh TypeがデフォルトではTightになっているので、Full Rectにしましょう。

![SetFullRect.jpg](https://qiita-image-store.s3.amazonaws.com/0/19010/6e05224b-1930-16a5-41de-1937d01e5394.jpeg)

![seikou.jpg](https://qiita-image-store.s3.amazonaws.com/0/19010/b033e19f-03d8-6392-b81a-acde4ad91fa7.jpeg)

なおりました。
っていうかスプラッシュスクリーン機能は余白の大きさも指定できるようになってほしさがあります。
（横画面にすると極大ロゴになったりする）
pythonちょい嵌り-NamedTemporaryFile-

# はじめに
pythonで一時的にファイルをつくり、CSVファイル書き出し
それをHTTPレスポンスでZIPした状態で返すコードを書いている最中で
**UnsupportedOperation: not readable**が出て困っていました。
という訳で、ちょい嵌りしたポイントをご紹介します。

# pythonで一時ファイルを作成する
「[11.6. tempfile — 一時ファイルやディレクトリの作成](https://docs.python.jp/3.6/library/tempfile.html)」のサンプルを参考にすれば一時ファイルはすぐに作れます。
しかもcloseすると勝手に消してくれる優れもの(^^♪

```python
import tempfile
fp = tempfile.TemporaryFile()
fp.write(b'Hello world!')
fp.seek(0)
fp.read()
fp.close()
```

こいつは優れものだなぁ～と思い次の様に流用しました。

# CSVファイルを一時ファイルに作成しZIPでレスポンスを返す(失敗)

contentに辞書型でデータ列が入っていると仮定してみてください。
するとCSV出力するのはこんな感じになると思います。

```python
import csv
import tempfile

fp = tempfile.NamedTemporaryFile(mode='w', newline='', encoding='shift_jis')
fname = fp.name
header=[]
for key in content:
    header.append(key)
writer = csv.DictWriter(fp, fieldnames=header)
writer.writeheader()
writer.writerows(content)
```

出来上がったCSVファイルをZIP圧縮してHTTPレスポンスに返すには…
このファイルをPythonのマニュアルの例通りseek(0)してread()すれば値が取れるかなと思っていたのですが…

```python
import os
import io
import csv
import tempfile
import zipfile
from django.http import HttpResponse

fp = tempfile.NamedTemporaryFile(mode='w', newline='', encoding='shift_jis', delete=False)
fname = fp.name
header=[]
for key in content:
    header.append(key)
writer = csv.DictWriter(fp, fieldnames=header)
writer.writeheader()
writer.writerows(content)

fp.seek(0)

zip_io = io.BytesIO()
 with zipfile.ZipFile(zip_io, mode='w', compression=zipfile.ZIP_DEFLATED) as backup_zip:
    backup_zip.writestr('CSVファイル.csv', fp.read())
response = HttpResponse(zip_io.getvalue(), content_type='application/x-zip-compressed')
response['Content-Disposition'] = 'attachment; filename=%s' % 'your_zipfilename' + ".zip"
response['Content-Length'] = zip_io.tell()
fp.close()
return response
```

こんな感じかなと実行してみると…
`fp.read()`の段階で**UnsupportedOperation: not readable**の例外が発生
色々ネットを徘徊しましたが、どうやら`'w'`モードで開いた状態で`read()`は出来ないらしいことが判明

どうする俺(笑)


# CSVファイルを一時ファイルに作成しZIPでレスポンスを返す(成功)

結局一時ファイルを自動的に消してくれる`close()`の恩恵を無視し(`delete=False`)
一時ファイルに書き込み`close()`し、読み取りモードで開いて読み込みHTTPレスポンスへ流し、最後に消すって流れになってしまいました。

```python
import os
import io
import csv
import tempfile
import zipfile
from django.http import HttpResponse

fp = tempfile.NamedTemporaryFile(mode='w', newline='', encoding='shift_jis', delete=False)
fname = fp.name
header=[]
for key in content:
    header.append(key)
writer = csv.DictWriter(fp, fieldnames=header)
writer.writeheader()
writer.writerows(content)
fp.close()

fp = open(fname, 'r')
fp.seek(0)    # これはいらないかもね

zip_io = io.BytesIO()
 with zipfile.ZipFile(zip_io, mode='w', compression=zipfile.ZIP_DEFLATED) as backup_zip:
    backup_zip.writestr('CSVファイル.csv', fp.read())
response = HttpResponse(zip_io.getvalue(), content_type='application/x-zip-compressed')
response['Content-Disposition'] = 'attachment; filename=%s' % 'your_zipfilename' + ".zip"
response['Content-Length'] = zip_io.tell()
fp.close()
os.unlink(fname)
return response
```

# 本当は
一時ファイルすら作りたくなくって、直接ZIP化できればよいんですけどね。