OmniAICreator/Qiita-1.07M huggingface dataset:
Nextcloud でフォルダのアクセス制限をする

しばらく投稿をサボっていましたが、Nextcloudを触っていたらこれいけるなと思いましたので、投稿します。

#はじめに
Nextcloudはオンラインストレージを構築できるオープンソースソフトウェアです。オンラインストレージなので、どこからでもファイルにアクセスしたり、他のユーザーやグループでファイル共有をしたりと利便性が良いものです。しかし、機密情報や個人情報など、外部からはアクセスさせたくないファイルもあるかと思います。今回は、Nextcloud内のフォルダのアクセス制限方法について、ご紹介したいと思います。

#対象フォルダ
今回は、社内用（アクセス制限）というフォルダを作成しました。
![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308127/76a40836-dda0-93c2-4db9-c9026fbc7790.png)

#タグの作成
設定から管理者メニューのタグ管理を開き、新しいタグを作成します。今回はわかりやすく「外部アクセス禁止」というタグを作成し、制限付き（タグが付いていることは一般ユーザからも確認できるが、タグを外したりすることはできない）に設定します。
![002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308127/1ecd708d-f69b-54d9-8c86-8e31da1f40d8.png)

#対象フォルダにタグ付け
ファイル操作画面に戻り、対象フォルダに先ほど作成したタグを割り当てます。
![003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308127/f46260f4-f356-ca59-e6e6-246b2d945050.png)

#ファイルアクセス制限
今度は、設定から管理者メニューのファイルアクセス制限を開き、設定を行います。今回は以下のように設定しました。
・リクエストリモートアドレスはxxx.xxx.xxx.xxx/32（会社のグローバルIP）以外
・ファイルシステムタグが「外部アクセス禁止」
![004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308127/206ed04a-c48f-a410-16ee-e555af52f5c1.png)

#確認（会社内から）
会社内のPCからアクセスすると、今まで通りフォルダが表示されています。
![005.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308127/c04c755b-e9f5-912f-fa33-867d4f8cea1b.png)
フォルダ配下も表示されています。
![006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308127/28ce5183-76ae-8474-2909-22f033c8205f.png)

#確認（会社外のスマホから）
同じ階層にアクセスしましたが、アクセス制限をしたフォルダ自体が表示されません。
![007.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308127/7963c094-a075-abb2-66cb-725e7b8d3d07.png)

#まとめ
タグ機能とファイルアクセス制限機能を組み合わせることにより、今回のようなフォルダアクセス制限みたいな細かい設定ができますね。よりセキュアに運用をしたい方は是非活用いただければと思います。

この記事は、[スタイルズ社のNextcloudサイト](https://nextcloud.stylez.co.jp/nextcloudblog)にも公開しております。
Javaユーザーがよく見るイベントサイトは？ connpassとDoorkeeperで収集したデータをRevealで可視化してみた。

# はじめに

## Revealとは
[Reveal  ダッシュボードをアプリケーションに組み込み](https://www.revealbi.io/jp)
> Reveal Embeddedは、アプリケーションに組み込み可能なデータ可視化SDKです。シンプルな価格体系、組み込みの容易さでアプリケーションの価値を最大限向上することができます。


## この記事では

JavaユーザはーTECH系イベントに参加するとき、どんなイベントサイトを参照しているのか？
有名なTECHイベントサイトの"connpass"と"Doorkeeper"のJavaコミュニティの数値取得し、Revealでダッシュボードを作ってみました。
(2019年12月の情報に基づいた記事です)


# 対象サイトを選定
## 有名なIT系イベントサイトをリストアップ
まずは、私も利用経験のあるイベントサイトをリストアップ。

- connpass
- Doorkeeper
- ATND
- TECH PLAY

## 最終的に2つ(connpass と Doorkeeper)に絞り込み
それぞれのサイトでJavaの情報を収集し、
そこそこのボリュームが得られたconnpassとDoorkeeperを対象にデータを収集することにしました。

- connpass
　カテゴリ「Java」から結果を取得。9コミュニティがヒットしたのでこれらを分析対象に決定。
https://connpass.com/category/Java/

- Doorkeeper
　トピック「Java」から結果を取得。49コミュニティもヒットしたのでこれらを分析対象に決定。
https://www.doorkeeper.jp/topics/java

- ATND
https://atnd.org/events/search?q%5Battendee_gteq%5D=1&q%5Btitle_or_description_or_place_or_address_cont%5D=Java
 -> 2019/12/18時点でイベント数が3件という結果だったので今回は除外。

- TECH PLAY
　-> TECH PLAYの、横断検索を行う性質から、connpassとDoorkeeperも対象になるため、今回は除外しました。


# データの収集対象
## connpass
connpass はカテゴリ「Java」のグループに所属しているメンバー数の合計を取得。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48623/def449b6-75e4-9185-f27a-3eecbdc11eb9.png)

## Doorkeeper
Doorkeeper はトピック「Java」のコミュニティ所属しているメンバー数の合計を取得(※)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48623/bcf33fa0-8377-9975-db90-c4f2caa70878.png)

※ Doorkeeperはトピックのフォロワー数を知ることも出来ますが、connpassとなるべく近い集計手順を実施するために、コミュニティに所属しているメンバー数の合計としています。

## 収集結果
泥臭く収集した結果は、下記のExcelにまとめています。（疲れた...）
https://github.com/furugen/Reveal-Samples/raw/master/1218-RevealApp/CommunityData-Doorkeeper-connpass.xlsx

シンプルに３カラムを設けました。

 - サイト　... connpass / Doorkeeper
 - コミュニティ名 ... コミュニティの名称
 - コミュニティメンバー数 ... 参加メンバー数
 - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48623/b3883d5c-7da5-2dad-3460-965d7e3e1d05.png)


# Reveal でダッシュボード作成
## 出来たもの
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48623/adeb652e-0c25-a8f4-ee18-44eb632d8080.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48623/e2c123b3-d318-40bd-c5c2-8d5d8bfaff12.png)

## ダッシュボードの作り方

別途動画とって公開します！(近日公開予定)

# まとめ

**Javaユーザーがテックイベントを探す場合は、Doorkeeperは必須！**

Doorkeeperが圧倒的にJavaユーザ多し！　その差、約8倍以上でした。
メンバー数上位コミュニティで１位の日本Javaユーザーグループ、２位の日本Springユーザ会がJavaコミュニティを引っ張っている結果でしょう。
※余談ですが昔所属していたJava Kueche(沖縄)が上位コミュニティにランクインしているのが嬉しい。

最近テックイベントはconnpassで探すことが多かったのすが、久々にJavaイベントを探そうとした際に、「あれ？Javaのイベントが少ない…？」と感じたのが調査のきっかけでした。
イベントサイトによっては、それぞれ特色があるので利用する方も気を付けないといけませんね。

本記事はJavaでしたが、.NET系(たぶんconnpassが強いはず)や、他の言語も機会があれば可視化していこうと思います。

次回もまたRevealの記事を執筆予定ですので、興味があればまたご覧ください！
これからの強化学習_1

# **これからの強化学習**  　　


理系大学院修士1年のはりまです。
自分の学習内容をメモ程度にまとめていきます。見辛いのは申し訳ありません。
分からないところは教えていただきたいです。



### **Chap.0 Introduction**

   - 強化学習とは、経験をもとに試行錯誤しながら最適な行動を獲得するための理論的枠組み

   - ex)自転車

   - アルゴリズムの出力によって、収集されるデータそのものが変化（探索と利用のトレードオフ）

   - 十分なデータを持っておらず、データの収集にコストがかかる世界において、データをどのように収集するか（←→ビッグデータ）  　　
  　　

---

### **Chap.1 強化学習の基礎的理論**  　　

   - 強化学習の基礎的概念を、最新の見方をもとに簡潔に整理  　　
   
---

#### **1.1 強化学習とは**  　　


   - **強化学習問題**・・・対象について不完全な知識しかなく、また、対象へのはたらきかけによって観測出来ることが変わってくる場合に、最適なはたらきかけ方の系列を発見するような問題

   - 行動する主体を**エージェント**、はたらきかけられる対象を**環境**、働きかけを**行動**、それによって変化する環境の要素を**状態**

   - 未知の環境で発生することを統一的に比較する指標を**報酬**（経済学では**利得**、制御工学では**損失**または**コスト**）

   - **置かれた環境の中で、行動の選択を通して得られる報酬の総和を最大化**

   - エージェントの行動決定の**方策**を観測の結果を入力として、行動を出力とする関数で表す
   
   - **即時報酬**と**遅延報酬**を合わせ、得られる長期的な報酬（**収益**）を最大化することが必要
   
   - エージェントの現在の状態、使う方策などを固定した場合の条件付き期待値として**価値**を計算
   
   - ほとんどの場合、エージェントが環境に関して事前の知識をもっていない、あるいは知識が不完全であると仮定
   


   - **探索と利用のトレードオフ**・・・これまでの学習結果を**利用**しようとすると、**探索**が減ってしまい、損失機会が増える。一方探索を増やせば最良の行動とは異なる行動を取るため、得られる報酬が減る（最適解は得られた情報の量と偏りによって動的に変化）
   
   - **多腕バンディット問題**・・・スロットマシンの腕が$K$本、払い戻される額を$R$、腕$i$を引いた場合当たりが出る確率を$p_i$とする（プレイヤーは事前に確率値を知ることができない）
   


   - **greedyアルゴリズム**・・・これまでの結果から期待値が最大の腕を選択する
   
     - まだn回選んだことがない腕がある場合、その腕を選ぶ。
     - それ以外の場合、すべての腕に対して、これまでの報酬の平均を計算する。
     - $\mu_i$が最大の腕を選ぶ
     
     
```math
\mu_i=\frac{これまで腕iから得られた報酬の和}{これまで腕iをプレイした回数}
```


   - 本来は最適でない腕$i'$が、たまたま試行のときに多く当たったため、腕$i'$の払戻率$p_{i'}$が最適な腕$i$の払戻率$p_i$より大きいと誤認
   
      - 誤った最適解に基づき腕$i'$を引き続けると腕$i'$の結果がより多く集まり、$p_{i'}$の推定誤差は試行を増やすほど減少し、いつかは誤りを訂正可能
   
   - 本来は最適である腕$i$が、たまたま試行のときにあまり当たらなかったため、腕$i$の払戻率$p_i$が最適でない腕$i'$の払戻率$p_{i'}$より小さいと誤認
   
      - 誤った最適解に基づき腕$i'$を引き続けても、本来最適な腕$i$の情報は集まらないため、試行を繰り返しても推定誤差は減少せず、誤りを訂正不可能  　　
      



  
   - **$\epsilon$-greedyアルゴリズム**・・・確率$\epsilon$でランダムな腕を選ぶ（$0 \leq \epsilon \leq 1$）
   
      - まだ選んだことがない腕がある場合、その腕から一つ選ぶ
      - 確率$\epsilon$で、すべての腕からランダムに一つ選ぶ
      - 確率$1-\epsilon$で、これまでの報酬の平均$\mu_i$が最大の腕を選ぶ
    
      - $\epsilon$はランダムよりも効率の良い探索方法がありそう
   


   - **不確かなときは楽観的に**・・・期待値に不確実性があるときには、その不確実性の範囲の中で、大きい期待値を仮定すべき
   
      - 1) 現在の知識と整合性のあるような「想定しうる環境」という集合を考える
      - 2) その集合から「最も都合の良い」環境を選び出す
      - 3) その最も都合の良い環境における最適解を次の行動とする


   - 学習初期は探索に重点が置かれ、後期になると利用に重点が置かれる
   
   - **楽観的初期値法**・・・学習前に各腕から報酬の最大値を$K$回観測していたという形で、各腕の価値の楽観的な期待値を見積もる
   
      - 報酬の上界$r_\sup$とする
      - 学習中に観測した結果に加え、各腕から$r_\sup$の報酬が$K$回観測されていたと考えて、各腕の報酬の期待値を計算する
      - $\mu'_i$が最大の腕を選ぶ
      
```math
\mu'_i = \frac{これまで腕iから得られた報酬の和+Kr_{\sup}}{これまで腕iをプレイした回数+K}
```

   - **UCBアルゴリズム**・・・信頼区間の確率を少しずつ1に近づけることで、すべての選択肢に対して必要な探索が行われ、また探索のコストも最適解を間違えるリスクも少なく出来る
   
      - $R$：払戻額の最大値と最小値の差
      - まだ選んだことのない腕があれば、そのうち一つを選ぶ
      - 各々の腕$i$から得られる報酬の期待値を計算する
      - 各々の腕$i$から得られる報酬の信頼区間の半幅を計算する
      - $x_i= \mu_i + U_i$が最大の腕$i$を選ぶ
      
```math
\mu_i=\frac{これまで腕iから得られた報酬の和}{これまで腕iを選んだ回数}\\
```

```math
U_i=R \sqrt{\frac{2 \ln (これまでの総プレイ回数)}{これまで腕iをプレイした回数}}
```


  

   - $K=4$の場合のシュミレーションを行う。
   
      - 払戻額はそれぞれ0.2,0.3,0.4,0.5
      - 10,000時間ステップの学習を10,000回繰り返す



   - 様々な未知の環境において、自ら情報収集してロバストに良い行動を獲得する
   
   - 問題によって適切なアルゴリズムは違ってくる（アルゴリズムの選択が重要）


---
jq で日付の連番を生成

日付で partition を切りたい時とか自動生成したいじゃないですか。

```js:a.jq
env.UPPER_BOUND_DATE | strptime("%Y-%m-%d") | mktime as $e2
| [ range(env.RANGE_DAYS|tonumber) ]
| map(
  $e2 - . * 24 * 3600 | strftime("%Y-%m-%d")
)
```

```bash
$ date +"%Y-%m-%d %H:%M:%S"
2019-12-18 15:38:58

$ export UPPER_BOUND_DATE=$(date -d '1 day ago' +%Y-%m-%d)
$ export RANGE_DAYS=30

$ jq -n -f a.jq
[
  "2019-12-17",
  "2019-12-16",
  "2019-12-15",
  "2019-12-14",
  "2019-12-13",
  "2019-12-12",
  "2019-12-11",
  "2019-12-10",
  "2019-12-09",
  "2019-12-08",
  "2019-12-07",
  "2019-12-06",
  "2019-12-05",
  "2019-12-04",
  "2019-12-03",
  "2019-12-02",
  "2019-12-01",
  "2019-11-30",
  "2019-11-29",
  "2019-11-28",
  "2019-11-27",
  "2019-11-26",
  "2019-11-25",
  "2019-11-24",
  "2019-11-23",
  "2019-11-22",
  "2019-11-21",
  "2019-11-20",
  "2019-11-19",
  "2019-11-18"
]
```
Rustで始めるゲーム開発

Rustを使ったゲーム開発について紹介したいと思います。言語の特徴、ゲームエンジンの選択肢、実際の作品について書いていきます。

## 1. Rustの特徴
コンパイラが非常に優秀で、メモリや変数の管理がうまくできてないとめちゃくちゃコンパイルエラーを吐き出してくれます。以下に個人的に好きなところを列挙しました。
### 1.1 メモリ管理が安心
Rustでは変数に寿命と所有権が存在しています。

変数の寿命はスコープの外に出たら使えなくなるという性質です。他の言語でもスタック領域ならその性質は存在するのすが、Rustの場合ヒープ領域に作った変数でもスコープから出ると削除してくれます。このおかげでメモリリークしなくてよさそうです。

```rust:変数の寿命
fn hoge() {
    let a: i32 = 23; // スタック領域の変数
    let b = String::from("hoge"); // ヒープ領域の変数
    println!("{}, {}", a, b);
}
// aもbもメモリから削除されます。
```

所有権は変数を別の変数に代入したり、関数の引数として渡したりするときに登場する概念です。これによって効率的で安全なメモリ管理ができます。

```rust:所有権の譲渡
fn aaa(hoge: Vec<i32>) {
    println!("{:?}", hoge);
}

fn main() {
   let hoge: Vec<i32> = vec![1, 2, 3];
   aaa(hoge); // ここで所有権がaaaにムーブ
   // aaa(hoge)をもう一度実行したらコンパイルエラーがでます。
   // 無駄なメモリが削除されるので効率がいいです。
}
```

上の例ではVectorをそのまま渡しているのですが普通はそんなことをせずに参照を渡します。そのときに所有権を貸し出すということをします。今回は言及しませんが、書き換える目的で変数を借りるmutable borrowに関して危険なプログラムを書くとコンパイラがエラーを吐き出します。安心ですね。

```rust:所有権の貸し出し
/// 変数を借りている
fn aaa(hoge: &Vec<i32>) {
    println!("{:?}", hoge);
}

fn main() {
   let hoge: Vec<i32> = vec![1, 2, 3];
   aaa(&hoge); // hogeを貸し出し、終わったあと戻ってくる
   aaa(&hoge); // hogeが戻ってきたのでエラーは出ません
}
```

### 1.2 型チェックが結構厳しい
これは読んで字の如く、i32型にu32型の変数を代入しようとするとエラーを吐き出すみたいな話です。自動でキャストするみたいなことをしないので、その辺自分は雑になりやすいのでうれしいです。他にもRustには変数に書き換え可能かどうかの設定をする必要があって、let mutで宣言した変数にletで宣言した変数を代入するとエラーになります。

### 1.3 Cargoが便利
Rustのパッケージ管理マネージャなのですが、パッケージ管理だけでなくプロジェクトの作成や実行などなんでもやってくれます。これは完全に感覚なのですがとても快適で最高です。

### 1.4 Rustに関する結論
ゲームはバグが大量に発生しがちなので、Rustみたいなバグを産みにくい言語はゲーム開発にかなり適しているような気がします。

## 2. ゲームエンジンの種類
Rustのゲームエンジンで流行っているのは[Amethyst](https://amethyst.rs/)、[Piston](https://github.com/PistonDevelopers/piston)、[ggez](https://github.com/ggez/ggez)などですね。
自分が個人的に使っているのはAmethystです。
### 2.1 Amethyst
Amethystのチュートリアル的なものは以前に書いたので興味ある方は[こちら](https://qiita.com/takeryo_dayo/items/30431ef95bf7c38642a7)をどうぞ。
Amethystは3Dも2Dも作ることができるエンジンで、ECS(EntityComponentSystem)という設計をとっています。

### 2.2 Piston, ggez
Pistonも3Dゲームをつくれますが最近あまり開発が活発でない印象です。
ggezは2Dゲーム開発に強みがあるそうです。（あまり詳しくなくてすいません）

## 3. 実際の作品
毎月、Rustで開発されたゲームの紹介をしているサイトがあるので以下にリンクを貼っておきます。
https://rust-gamedev.github.io/

自分も現在ゲーム開発をしていて、Twitterにて不定期で進捗をアップしていますのでよければチェックしてみてください。 
https://twitter.com/takeryo_eeic

## まとめ
Rustを使ったゲーム開発の紹介は以上になります。ありがとうございました。
EBSの高速初期化ツールを公開します

EBS 初期化を高速化するツールを作ってみましたので公開します。**fio** でやる場合より3倍ぐらい速く動作します。

## EBS 初期化とは？

EBS は AWS の標準的な仮想ストレージです。EBS の魅力のひとつにスナップショット機能がありますが、構造上、スナップショットの利用開始直後はパフォーマンスがかなり悪くなります。これはスナップショットの実体が S3 にあり、アクセスがあったブロックから順次ダウンロードされるためです。この構造のため EBS スナップショットからボリュームを作成するとすぐに完了しますが、一度目のアクセスは非常に重いという特性があります。

この問題を回避するためには、一度 **dd** 等を利用して全ブロックを読み込んでしまえばオーケーです。これを「EBS の初期化」と言います。ただし **dd** では遅いため、ベンチマークツールの **fio** を利用して初期化する方法が公式ページで紹介されています。

 * [Amazon EBS ボリュームの初期化](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ebs-initialize.html)

## 初期化の無駄をなくすには？

EBS 初期化は全データを読み込まなくてはならたいため、大きなスナップショットだと数時間かかります。しかし、S3 のチャンクサイズはどうやら 512KiB のようであり、1ブロック中の一部でも読み込めばそのブロックの初期化は完了します。この性質を利用すると、数バイトだけ読み込んで 512KiB シークする事を繰り返し、高速に初期化が可能です。これを応用したワンライナーが、stak overflow にポストされていました。

 * https://stackoverflow.com/questions/46284897/optimize-big-ebs-volumes-initialization-warm-up/46777006#46777006

状況にも依存するのですが、**fio** で初期化するより高速に動作する場合も多いです。

## さらに速くするためには？

上記のワンライナーはとても優秀でお世話になったのですが、読み込み毎に **dd** を起動したり、`/dev/null` に出力したりしている等、シェルスクリプトであるが故の無駄が多いのも事実です。そこでこのアルゴリズムを C言語で実装したのが今回のツールです。システムコールは [io_submit(2)](https://linuxjm.osdn.jp/html/LDP_man-pages/man2/io_submit.2.html) を利用しており、シングルスレッドで高速に IO を同時発行できるようになりました。

## ソースファイルとライセンス

github に置きました。MIT ライセンスです。

 * https://github.com/matsumoto-sp/ebsinit

## ダウンロードとインストール

RPM パッケージを用意しましたので、以下のコマンドでダウンロード・インストールができます。

```
rpm -ivh https://github.com/matsumoto-sp/ebsinit/releases/download/1.0.3/ebsinit-1.0.3-Linux.rpm
```

## 利用方法

コマンドラインに初期化したいデバイスを指定するだけです。以下のように利用します。

```
ebsinit /dev/nvme2n1
```

その他、以下の通りいくつかのオプションがあります。

オプション | 機能
---|---
-s, --silent  | 進捗表示を行わない
-l, --syslog  | syslog に進捗を出力する
-h, --help    | ヘルプメッセージを表示する
-v, --version | バージョン番号の表示

## ベンチマーク

400GiB中、67% 程度を利用している gp2 のボリュームでテストをした所、以下のような結果になりました。

初期化方法 | 時間
----|----
fio | 147m
上記のワンライナー | 156m
ebsinit | 41m

## ストライピングとの併用でさらに高速化

LVM 等を利用してストライピングを行うとそれぞれのデバイスを同時に処理できますので、さらに速くなります。120GiB の gp2 のボリュームを8台つなげてストライピングした 950GiB のドライブ（使用率50%程度）は、わずか7分で初期化が終了しました。

なお、ストライピングドライブに適用する場合には、`/dev/mapper/` 以下のボリュームグループではなく、個々のボリュームそれぞれで実行して下さい。そうしないとストライプサイズの関係で特定のボリュームに偏って読み込みされてしまう場合があり、結果として初期化が正しく行えません。 **ebsinit** は複数のボリュームを同時に初期化する機能は今はありませんので、ボリュームの数だけ同時起動して下さい。


## FSR もお忘れなく！

最後になりましたが、先日公開された AWS の新機能 [Fast Snapshot Restore (FSR)](https://aws.amazon.com/jp/blogs/news/new-amazon-ebs-fast-snapshot-restore-fsr/) は、EBS スナップショットの初期化を不要にする魅力的な機能です。料金が結構掛かる事や初めて利用する時に時間がかかる等の問題がありますが、EBS 初期化の新しい方法だと思います。EBS 初期化で困っている人は、是非 FSR も検討してみて下さい。
Linux初心者がWindowsタブレットにLinuxを入れた話

Qiita初投稿です。拙い文章ですがお付き合いいただけると助かります。

## Windowsタブレットは動作が重い(主語がでかい)

2018年の10月頃に購入したASUSのTransbook R106HA(といっても中身はT102HAらしいのですが)というWindowsタブレットを使っているのですが、メモリ4GBだとやはりWindows10には厳しく動作が重い状況でした。Windowsを使うなら普段から使っているラップトップのノートPCでいいやと思って、2019年の6月ほどまで放置してました。

## 再利用しようと思ったきっかけ

その普段から使っているノートPCのバッテリーが消耗して、講義が3限分連続だと一度充電を挟まないと途中で切れてしまう状況に陥ってしまいました。そこでさきほど挙げたタブレットをどうにか改良して使えないかと思った結果、Linuxを入れようと思い立ったのでした、まる。

## Linux化にするにあたって

という前振りをして、Linuxを入れたいと思います。一応スペック紹介を。

|ASUS|Transbook T102HA(R106HA)|
|:-:|:-:|
|CPU|Intel Atom x5-Z8350
|ストレージ|eMMC:64GB|
|RAM|4GB|

あと地味にキーボードドック着けても1kgいかないの良い。
そして入れるディストリビューションですが、今回はXubuntu 18.04 LTS版を選択しています。理由はCPUの負担が比較的少ないため。

導入の手順に関しては[こちら](https://relativelayout.hatenablog.com/entry/2018/07/14/181459)を参考に。

インストール完了までは順調に進みました。

## トラブルの発生

使ってみるといくつかトラブルが生じたため、備忘録のついでに書いておきます。

- 画面関係のトラブル

　さきほど参考にした記事のとおり、このタブレットはデフォルトだと本体を縦にした状態がデフォルトになってしまいます。

　画面を右に90度回転すると本体を横にした際の正常な向きになるため、ターミナル上で`xrandr -o right`もしくは画面設定から向きを右向きに設定してあげます。しかし、タッチしたときの座標は移動しないため、同じくタッチパネルのキャリブレーションを行う必要があります。

`xinuput list`を打つと、マウスやキーボードなどの入力デバイスの一覧が出力されます。そこで、タッチパネルの名前を取得します。
そして、コマンド`xinput set-prop 'dev-name' 'Coordinate Transformation Matrix' 0 1 0 -1 0 1 0 0 1`を入力するとキャリブレーションが行われます。('dev-name'はidでも代用可能ですが、強制終了などをした際に変わってしまうのでオススメしません)

入力デバイス名の取得や原理はこちらを[参考](https://sh4869.hatenablog.com/entry/2015/11/01/013350)にしました。
[ここ](https://en.wikipedia.org/wiki/Transformation_matrix#Affine_transformations)よりCoordinate Transformation Matrixは

```math
\begin{matrix}
\cos\theta & \sin\theta & 0 \\
-\sin\theta & \cos\theta & 0 \\
0 & 0 & 1
\end{matrix}
```

となっています。それぞれ0度(通常)、90度(タッチ座標をを右に補正する場合)は、

```math
\theta = 0 \\
\begin{matrix}
1 & 0 & 0 \\
0 & 1 & 0 \\
0 & 0 & 1 
\end{matrix} \\
\theta = 90 \\
\begin{matrix}
0 & 1 & 0 \\
-1 & 0 & 0 \\
0 & 0 & 1 \\
\end{matrix}
```

になります。覚えていても結局0度か90度のときしか使わないとは思いますが…

私は`~/.profile`に記述しました。多分別の場所に記述したほうがよさげだと思います。(ログイン画面上で適応されない)

- Bluetoothが勝手に起動する

何故かインストール直後は起動時にデフォルトでBluetoothがonになってしまう状態でした。
最初はプロファイルかコンフィグかどちらかに入っていると思い、~~linux bluetooth 自動接続という頭の悪いキーワードで~~検索したところ、[ここ](https://qiita.com/nyakuo/items/98bc140163f77b808d65)の記事にたどり着きました。

```
[policy]
AutoEnable == true
```
と変更を加えて再起動します。しかし失敗。割と焦っていろいろ見てみた結果、自動開始アプリケーションの中にBlueman Bluetooth Managerが入っていたのが原因で、それを切ってあげれば自動でonにならないようにできました。

## 整備が終わって

あらかた使っていく上で不便と感じる原因は解決できました。今後の課題としてはせっかくのタブレットPCであるため、画面回転を検出して自動で画面の向きを切り替えができるようにしたいなと思っています。あと余談で、Xubuntuを入れる前はLinux Mint MATEを入れていたのですが、バッテリーの持ちがすごく悪い(1時間程度しか持たない)という理由でXubuntuに変更しています。ディストロの違いをこのような形で体感ができたのは素直に良い経験になりました。~~というか画面の輝度が変更できないLinux Mintさん側にも問題がある~~

### 追記(2020/1/28)
後日談ができました→https://qiita.com/Requin/items/cde193aaf4b9ff5dae78
LIKE  や NOT LIKE　はNULL まで判定してしてしまう話。

例えば

favorite_table

|    name|    food        |
|:-------:|:-------------:|
|  tanaka |  野菜ラーメン  |
|  satou  |   ちゃんぽん  |
| ikeda   |      みそラーメン|
| numata  |     やさい      |
|  inoue  |              |


ラーメン以外のnameを取得したい時に

```sql
SELECT *
FROM favorite
WHERE food NOT LIKE 'ラーメン';
```

みたいにしてしまうと
inoueさんが出てこなくなってしまう。

今の所

```sql
WHERE food IS NULL OR food NOT LIKE 
```
ってやるとうまくいくみたいだけどもっといい書き方ないかな。
xinetdのサービスのport番号を知る方法

とあるサービスのport番号がわからなくて、xinetdで起動してることは知ってたので /etc/xinetd を見てもportぽいものがなにもない。

# xinetd の service という項目を見る
xinetdのconfは service 名で書くこともできるとのこと。

試しに time というサービスの例。


```sh
# cat /etc/xinetd.d/time-stream
service time               <--------------- ここでport番号が実は定義されている
{
   ...
```

# port番号は `/etc/services` に書いてある
port番号は */etc/services* でわかる

```sh
# cat /etc/services  | grep time | head -5
daytime         13/tcp
daytime         13/udp
time            37/tcp          timserver              <---------- あった！
time            37/udp          timserver              <---------- あった！
utime           519/tcp         unixtime
```




いつも `/etc/services` を忘れてしまう


## おまけ listenしてるポートを知る方法 `netstat -nltpa`
```sh
# netstat -nltpa
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
...
tcp6       0      0 :::21                  :::*                    LISTEN      3247/xinetd       <------- このポートはxinetdだなーがわかる
tcp6       0      0 :::873                 :::*                    LISTEN      3247/xinetd
```


# おわりに
*この記事のコマンド結果はすべて捏造したので信用しないでね
★新卒で学んだ知識を活かし、大学用で使っていたMacをエンジニア用に環境構築してみた

## はじめに
[2019新卒 エンジニア Advent Calendar 2019](https://qiita.com/advent-calendar/2019/2019-graduates) 20日目の記事です。
### 自己紹介
どうも、新卒入社した会社でエンジニアに転生したkitaです！

現在は<b>HTML, CSS, jQuery</b>を使った、フロントエンド中心の業務をやっております。
プライベートで勉強しているのは Ruby on Rails, Swift, Reactです。
Gitに草を生やすことが趣味でコードを書いています（笑）

### なぜやるのか
自宅から会社まで、<b>約1時間半</b>かかるんですよね...笑

<b>防音物件</b>ということもあって、遠くに住んででも一人暮らししたかったんですw

帰ってからやれることも少なく、どうにかして時間を有効化したいと思い、大学生の時に使っていたMacをリセットして、プログラミング用に環境構築しようと決めました。

## ステップ1：不要なデータ削除
まず要らないデータが多かったです。

大学の時に書いていたレポートだったり授業資料だったりを一掃しました。
使っていないアプリケーションも全部削除しました。

さて、ストレージを見てみると、「その他」という謎のデータがww
ググって色々記事を漁ってみると、iTunesのArtworkのキャッシュが30GBくらいを占めていましたw



探し方：このMacについて → ストレージ → 管理 →　不要なファイルを削除　→　ファイルブラウザ　→　ミュージック　→　iTunes → Album Artwork

ゴミ箱に入った容量が多く、全て削除するのに1時間くらいかかりましたw

<b>結構きれいになりました！</b>
![storage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504081/cfee995f-7cb8-f449-cf81-35ef2a657e05.png)


## ステップ2：Gitインストール
![icon_git.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504081/38657338-207b-3882-baca-64687ad4a95c.png)

Gitは元から入っていたみたいなのですが、バージョンが低かったのでアップデートしました。
[こちらの記事](https://qiita.com/takm-reason/items/1c368d14a76cf1ccedde)を参考に、Homebrewを使ってGitインストールして、パスを指定し直しました。

Gitをインストールできれば、色々なプロジェクトをGit管理して草を生やせます（完全に自己満）
GitHubにファイルをアップロードした話は[こちらの記事 - 【GitHub】ローカル環境にあるフォルダをリモートリポジトリにアップロードする際に詰まった話](https://qiita.com/kitagawa_shouri/items/e463a5ed188c77bac967) にて。

## ステップ3：rbenvのインストール
![rbenv.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504081/d68d8668-b012-f343-7fb3-735445c1c624.png)

Rubyを触ってみたいということもあって、rbenvでバージョン管理しようと思いました。

インストール方法は、[こちらの1.rbenvのインストール](https://qiita.com/Alex_mht_code/items/d2db2eba17830e36a5f1#1rbenv%E3%81%AEinstall)を参照しました。

## ステップ4：OS 10.10Yosemiteから10.15Catarinaへ
![catalina.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504081/b4a564cc-4bc5-b071-3ee5-7dbba9d89e22.jpeg)

僕のMacBookAirは、

```
MacBook Air(11-inch, Mid 2013)
プロセッサ 1.3GHz デュアルコアintel Corei5
メモリ 4GB 1600 MHz DDR3
```

というなかなか低スペックなPCです。

古くても問題ないかなと思っていたのですが、そりゃ大間違いで。

<b>Xcodeのサポート対象が10.14以上</b>だったんですよね。Swiftを使ってアプリ開発してみたいな〜と思っていたのですが、Xcodeが使えないと困るので、大幅なアップデートをしました。

ちなみにアプリ開発をしたいなと思った理由は以下から。
[【記事】初心者が1日で恋愛ゲームアプリを開発してみた](https://liginc.co.jp/247506)
めっちゃ面白そうですw

## ステップ5：MAMPのインストール
![MAMP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504081/b6dc026e-ff9c-58bf-e25b-a5f826b1311a.png)

MAMPのApacheを使って、ローカル環境でもサイトをブラウザで表示できるようにしたいと思い、MAMP導入を決めました。（社内でも使っているので便利です）

httpd-vhosts.confにドキュメントルートを設置し、hostsにもサーバーネームを入れたのですが、なぜかドキュメントルートが正しい場所にならず、結局MAMPのWebServerにあるドキュメントルートを直接設定しました。


## 終わり
とまぁこんな感じで、深夜に勢いで環境構築しましたww
これから新しいことを学ぶたびにGitHubにリポジトリを作りプッシュして、草が生えていることに達成感を感じるのでしょうかw
まぁはじめはこんな感じで、プログラミングを楽しめばいいんじゃないでしょうかね！
どんどんやっていきます！
ppa:jonathonf/python-3.6  が非公開になった

## ppa:jonathonf/python-3.6  が非公開になった

ubuntu16.04などでpython3.6を入れるときに
*ppa:jonathonf/python-3.6*
のppaを使っていたんですが、非公開になってしまってちょっと困ったのでメモ

変更前

```
sudo add-apt-repository ppa:jonathonf/python-3.6
sudo apt update
sudo apt install python3.6
```

apt update時のログ

```
W: The repository 'http://ppa.launchpad.net/jonathonf/python-3.6/ubuntu xenial Release' does not have a Release file.
N: Data from such a repository can't be authenticated and is therefore potentially dangerous to use.
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: Failed to fetch http://ppa.launchpad.net/jonathonf/python-3.6/ubuntu/dists/xenial/main/binary-amd64/Packages  403  Forbidden [IP: 91.189.95.83 80]
E: Some index files failed to download. They have been ignored, or old ones used instead.

```


ppaを以下に変更
*ppa:deadsnakes/ppa*

変更後

```
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt update
sudo apt install python3.6
```

こっちだと入れられる
Pythonのドキュメントコメント(Docstrings)の書き方

# Pythonドキュメントコメント

Pythonのドキュメントコメント(Docstrings)の書き方です。
どうも、派閥？流派？があるようです。

1. [NumPyスタイル](https://numpydoc.readthedocs.io/en/latest/)
2. [Googleスタイル](https://github.com/google/styleguide/blob/gh-pages/pyguide.md#38-comments-and-docstrings)

## Short Summary：簡単な1行説明。名前とか

``` NumPyスタイル.py
def add(a, b):
   """The sum of two numbers.

   """
```

``` Googleスタイル.py
def add(a, b):
   """The sum of two numbers.

   """
```

## Extended Summary: 複数行の詳細な概要

``` NumPyスタイル.py
def add(a, b):
   """The sum of two numbers.

   (Extended Summary)
   """
```

``` Googleスタイル.py
def add(a, b):
   """The sum of two numbers.

   (Extended Summary)
   """
```

## Parameters: 関数の引数

``` NumPyスタイル.py
"""
Parameters
----------
x : type
    Description of parameter `x`.
y
    Description of parameter `y` (with type not specified)
"""
```

``` Googleスタイル.py
"""
Args:
  x (type): Description of parameter `x`.
  y: Description of parameter `y` (with type not specified)
"""
```

## Returns: 関数の返り値

``` NumPyスタイル.py
"""
Returns
-------
int
    Description of anonymous integer return value.
"""
```

``` NumPyスタイル.py
"""
Returns
-------
err_code : int
    Non-zero value indicates error code, or zero on success.
err_msg : str or None
    Human readable error message, or None on success.
"""
```

``` Googleスタイル.py
"""
Returns:
  int: Description of anonymous integer return value.
"""
```

## Raises: 例外

``` NumPyスタイル.py
"""
Raises
------
LinAlgException
    If the matrix is not numerically invertible.
"""
```

``` Googleスタイル.py
"""
Raises:
  LinAlgException: If the matrix is not numerically invertible.
"""
```

## See Also: 関連項目

``` NumPyスタイル.py
"""
See Also
--------
average : Weighted average
"""
```

``` Googleスタイル.py
# なし
```

## Notes: 備考。追加の説明。LaTeXも使える。

``` NumPyスタイル.py
"""
Notes
----------
The FFT is a fast implementation of the discrete Fourier transform:
.. math:: X(e^{j\omega } ) = x(n)e^{ - j\omega n}
"""
```

``` Googleスタイル.py
"""
Note:
  The FFT is a fast implementation of the discrete Fourier transform:
  .. math:: X(e^{j\omega } ) = x(n)e^{ - j\omega n}
"""
```

## Examples: 使用例

``` NumPyスタイル.py
"""
Examples
----------
>>> np.add(1, 2)
3
"""
```

``` Googleスタイル.py
"""
Example:
  >>> np.add(1, 2)
  3
"""
```

## Attributes: クラスの属性

``` NumPyスタイル.py
"""
Attributes
----------
x : float
    The X coordinate.
y : float
    The Y coordinate.
"""
```

``` Googleスタイル.py
"""
Attributes:
  x (float): The X coordinate.
  y (float): The Y coordinate.
"""
```

## Methods: クラスのメソッド

``` NumPyスタイル.py
"""
Methods
-------
colorspace(c='rgb')
    Represent the photo in the given colorspace.
gamma(n=1.0)
    Change the photo's gamma exposure.
"""
```

``` Googleスタイル.py
# なし
```
flexboxを使用した横スクロール可能なレイアウト

#概要

cssのflexboxを使用しつつ、横スクロールが可能なレイアウトのサンプルです。flexの設定ですこし手間取ったので記録しておきます。要件は以下の通り。

- 横幅を縮めると横スクロールになる
- 横幅を広げると中身の数で均等に分かれる
- 中身の文字列が多い時は、改行せずに横幅が広がる

#サンプル

<p class="codepen" data-height="265" data-theme-id="default" data-default-tab="css,result" data-user="y___k" data-slug-hash="jOEyMdK" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="scroll-x flexbox ">
  <span>See the Pen <a href="https://codepen.io/y___k/pen/jOEyMdK">
  scroll-x flexbox </a> by T_Y (<a href="https://codepen.io/y___k">@y___k</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

flexboxの外側で`overflow-x: auto`して、中身にflex設定をするだけです。
flexは、flex-grow, flex-shrink, flex-basis の一括指定プロパティです。（[MDN](https://developer.mozilla.org/ja/docs/Web/CSS/flex)）

```flex.scss
.item {
  flex: 1 0 200px;
  // flex-grow: 1; … 横幅を広げた時にいっぱいまで広がるように設定
  // flex-shrink: 0; … 横幅が調整されて縮まらないように設定
  // flex-basis: 200px … 基本の幅を指定

  white-space: nowrap;
  // 改行しないように
}
```

#備考
IE、Edgeは未確認です。確認後に追記します。
【Swift】Partial application of 'mutating' method is not allowedってなんだ

structを使っていたら、

> Partial application of 'mutating' method is not allowed

というエラーに遭遇しました。
僕の場合、原因は別件だったんですが、日本語情報があまりないエラーメッセージだったので、記事にしてみます。

# 僕のエラーの原因
僕の場合、
 
```swift
protocol aDelegate {
    var aView: ViewClass
}

struct AStruct {
    
    private weak var delegate: aDelegate?

    private mutating func aFuncation() {
        switch aView.aVariable { //この行で"Partial application of 'mutating' method is not allowed"
        case .any
            //any
        default:
            //any
        }
    }
}
```

という書き方をしたらこのエラーが出ました。

```swift:誤
switch aView.aVariable
```

ここを

```swift:正
switch delegate?.aView.aVariable
```

とすればOKでした。

それで終わりなんですが、ついでなんでエラーメッセージの意味も調べてみました。

# Partial application of 'mutating' method is not allowedってなんだ
## Partial application
Partial applicationは、日本語にすると部分適用と訳される技術用語です。
関数型プログラミングっぽい用語で、日本語記事見ると、だいたいカリー化と一緒に紹介されている用語です。
複数の引数を持った関数に対して、普通は全変数に値を渡して、戻り値を得ます。
たとえば、f(a,b,c) = a + b + c という関数があったら、f(1,1,1) = 1 + 1 + 1 = 3 ですね？ 
これを部分適用だと、

f(a,b,c) = f(a, 1, 1) = f(a) + 2 = f(1) + 2 = 3
ただしf(a) = a, f(b, c) = b + c

みたいな計算ができます。
命令形言語使ってると、「何が嬉しいんだ……？」という気になりますが、
関数型言語だと[関数が汎用的なので、利便性のために汎用性を減らしたいときがある](https://ja.javascript.info/currying-partials)みたいです。

## Partial application of 'mutating' method is not allowedの例
[Partial application of 'mutating' method is not allowed](https://stackoverflow.com/questions/37488316/partial-application-of-mutating-method-is-not-allowed)

エラーメッセージでググったら一番上に出てくるのがこちらの記事。

```swift:例
struct MyStruct {
    var count = 0

    mutating func add(amount: Int) {
        count += amount
    }
}

var myStruct = MyStruct()

[1, 2, 3, 4].forEach(myStruct.add)
// Partial application of 'mutating' method is not allowed
```

想定している結果としては、1+2+3+4でcount=10となるのを想定していると思われます。
そもそもforEachの中にカッコ省略してメソッド書いて動くのか……？とかはあるんですが、とりあえず"Partial application of 'mutating' method is not allowed"でエラー。
記事の中でも動くコードの例は出てますが、下記でも動きます。

```swift:動く例
var count = 0
[1, 2, 3, 4].forEach({ amount in count += amount })
print(count) //10
```

なぜこれがエラーになるかというと、内部的には

myStruct.add(1)
↓
myStruct.add(2)
↓
myStruct.add(3)
↓
myStruct.add(4)
↓
myStruct.add(1,2,3,4)　※この関数の場合ここでは何もせず

という順番で処理する必要があり、これが部分適用になる訳ですね。

# Swiftで部分適用？
[Swiftで部分適用（カリー化）](http://www.tokoro.me/posts/swift-partial-application/)にある、

```swift
func addTwoNumbers(a: Int)(b: Int) -> Int {
  return a + b
}

let add1 = addTwoNumbers(1)
add1(b: 2) //< 3
```
という書き方がその昔Swiftオフィシャルでできたらしいのですが、Swiftいくつからなのかは不明ですが、[廃止されました。](https://io-enjoy.info/%E9%83%A8%E5%88%86%E9%81%A9%E7%94%A8%E3%81%A8%E3%82%AB%E3%83%AA%E3%83%BC%E5%8C%96%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6/)
GitHubのイベントをトリガーにしてAzure Functionsにある関数を実行する


Microsoft Learning で1通り学習したので流れを思い出しながらメモする。
サーバーレスアプリケーションの作成：https://docs.microsoft.com/ja-jp/learn/paths/create-serverless-applications/

## 目標

GitHubのイベントをトリガーにしてAzure Functionsと通信する。  
→ GitHubのWikiが更新されたら、Azure Functionsにある関数を実行する。

## 前提

- Azure Functions作成したことがある。
- JavaScript書いたことがある。
- GitHubアカウントを持っている。

最低これがあれば、この記事を読み進めて目標を達成できるだろう。  

### GitHubアカウント作り方

GitHub：https://github.com/

サイトにとんでメールアドレス等必要事項を入力して進めればアカウント作成できるのでここでは詳しく書かない。  
プランはFreeにしよう。

## 環境を構築

### 関数アプリを作る

1. Azureポータル開く：https://portal.azure.com/#home
2. リソースの追加をクリック。
3. 「Function App」で検索 → 作成
4. 必要事項を入力して確認および作成（入力項目の説明は割愛） → デプロイされるまで待つ。この間にGitHubでレポジトリを作っちゃおう。
5. Azure側構築完了。

### GitHubでレポジトリを作成する

1. GitHubにサインイン
2. [Create a new Repository] or [New]をクリック
3. Repository Name を入力。（わかりやすいように「LearnWebhookTest」にでもしとこう）
4. Public　ot Privateを選ぼう。(料金プランFreeの場合、PrivateにするとWikiが無効になるので注意。)
5. [Create Repository]をクリック → Repositoryが作成される
6. [Wiki]タブをクリック → [New Page]をクリック → [Save Page]
7. 準備完了。

## 関数アプリに関数を追加する  

Azure

1. 作成した関数アプリに移動。
2. 関数名の横の「+」をクリック。
3. [JavaScript用の～] → [ポータル内] → [webhook + API] → [作成]
4. ファイルindex.jsを開き以下のコードに変更する（if~else~の部分を以下に置き換える）

    ``` javascript
    if (req.body.pages[0].title){
        context.res = {
            body: "Page is " + req.body.pages[0].title + ", Action is " + req.body.pages[0].action + ", Event Type is " + req.headers['x-github-event']
        };
    }
    else {
        context.res = {
            status: 400,
            body: ("Invalid payload for Wiki event")
        }
    }
    ```

5. [Ctrl + S]で保存を忘れずに
6. 関数アプリを選択して[関数のURLを取得する]を選択して出てきたURLをコピーしておく。

## GitHubにWebhookを追加する

GitHub

1. [Settings]タブ → [Webhook] → [Add Webhook] で追加する
    - Payload URL：さっきコピーした関数のURLを入力する。
    - Content type：データフォーマットの設定。今回はapplication/jsonを戦tなく
    - Secret：Webhookペイロードをセキュリティ保護できる。今回は未入力で大丈夫。
    - Which events would you like to trigger this webhook?：トリガーどれにするかを選択。一番下のLet me select individual events選択 → Wikiのみチェックしとく
    - Activeにはチェックをいれる。

2. Add webhookで追加

## Wikiを編集する

準備は完了したのでWikiを更新してみる。

1. さっき作ったWikiをEdit
2. 適当にテキスト追加して保存
3. 関数呼び出しが行われている

## 動きを確認する

GitHub

1. [Settings]タブ → [Webhook] → [Edit] → 一番下の[Recent Deliveies] で省略記号「…」をクリック。
2. [Response]タブをクリック。下記のように応答が返っていたら成功だ。

    ``` text
    Page is Home, Action is edited, Event Type is gollum
    ```
create database は何単位？

# SQL Server で・・・

むかし、「Visual Basic」＋「SQL Server」で、
とある工場の生産管理のシステムを作ってまして、
１システムの中に、複数のデータベースが作られていました。

>
>・共通ＤＢ（作業員のマスタとか）
>・製品ＤＢ（製品の状態管理とか）
>・資材ＤＢ
>・購買ＤＢ
>・    ：
>

最初に設計した人は、**何となく業務単位で分けた**のでしょう。
でも これが仇となってしまいました。
上記の複数のＤＢに接続するので、ＤＢコネクション数が膨れ上がるのです。

たとえば、工場内の端末が１００台あり、
１台につき「共通ＤＢ」と「製品ＤＢ」に接続すると、
単純計算で２００のコネクションが張られます。

工場立ち上げ時に、全端末の電源を入れたところ、
あっさり SQL Server のコネクション上限に達してしまい、
やむなく上限を引き上げたりしました。

いま考えれば、すべてをひとつのＤＢにすればよかったです。

# MySQL で・・・

最近も、私が（途中から）担当するシステムに、Ａ業務とＢ業務の２業務があり、
MySQL(MariaDB) 上、やはり２つのＤＢに分かれていました。
これも最初の設計者が 何となくで分けたのでしょう。

そのせいで（場合によっては）わざわざ２つのＤＢに接続しなければなりません。
（あぁ めんどくさい。）

これも ひとつのＤＢにすればよかったです。

# 複数ＤＢどう使う？

そもそも どんなときに、１サーバ内に複数のＤＢを張るのでしょう？

思いつくのは、**共用のレンタルサーバ**で、
お互いに無関係のユーザのために、独立したＤＢを準備するという使い方でしょう。

また あるとすれば、テストサーバで、
**開発者ごとにデータベースを準備する**、なども考えられます。

あと詳しくないのですが、ＤＭＰ（データマネジメントプラットフォーム）だと
利用するユーザやツールも変わってくるので、ＤＢを分けたりするのでしょうか？
（それ以前に、物理サーバが別かもしれませんが。）

# 最後に

`create database` は基本、１システムにつき１データベース！

何かしら関連があれば、ひとつのＤＢにまとめる。
何となくでＤＢを分けたら、後でめんどうになる（場合があります）

# 参考

[RDBMS毎の概念の違い](https://qiita.com/wakayama-y/items/9a437f76a7f9247fec5e)
webpackを使ってobjectFitをIEに対応させる

webpackでobjectFitImagesを使えるようにするのははじめてだったので手順を残す。

最低限必要なのはライブラリだけ。
https://github.com/fregante/object-fit-images

## object-fit-imagesをインストールする

```bash
yarn add object-fit-images
```

## 読み込ませるためのjsを書く
```objectFitImages.js
/*
 * This file is use object-fit-images
 * IEをobjectFitに対応させるためのライブラリ
 * https://www.npmjs.com/package/object-fit-images
 *
*/
import objectFitImages from 'object-fit-images'

objectFitImages()

```

後はapp.tsなりにimportすればおｋ。

## IEにも対応する
全てのCSSにfont-familiyを書いていくのは手間なので、postCssを使う。
https://github.com/ronik-design/postcss-object-fit-images

```bash
yarn add -D postcss-object-fit-images
```

postcss.configに追記

```js
const objectFitImages = require('postcss-object-fit-images')
const autoprefixer = require('autoprefixer')

module.exports = {
  plugins: [
    autoprefixer,
    objectFitImages,
  ],
}
```

終わり。
で、最近のIPv6普及率は？

# はじめに

この記事は [IPv6 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/ipv6) の 19日目の記事として投稿しています。

# IPv6普及率って？
IPv6なんて流行ってないねーって話ばっかり聞きますが、実際どうなんでしょう？普及率上がってるといわれても、全然実感ないよ！って人がほとんどだと思いますが、そもそも IPv6普及率ってなんやねん

ということで、日本でのIPv6普及率について、公開情報からどれだけわかるかなーということで少し調べてみました。ちなみに、個人的にIPv6に結構関わってるので、下記の内容にバイアスが掛かってるであろうことはお伝えしておきます。

## アクセス網ベース
いわゆる一般ユーザがお家で使ってたり、携帯で使ってたりするネットワークが、どれだけいままでの IPv4に加えて、IPv6 にも対応したか。企業ネットワークも含まれたり。これを調べると、コンテンツを消費する側の対応状況が見えてくるかと思います。

IPv6普及・高度化推進協議会の

[アクセス網におけるIPv6の普及状況調査](http://v6pc.jp/jp/spread/ipv6spread_03.phtml)

を見ると、2019年9月現在で

- フレッツ光ネクストのIPv6普及率 68.2% 
- KDDI AUひかり 100% (2014年12月〜）
- CTCコミュファ光 100% (2019年9月〜）

これだけ見ると、もうほぼほぼ普及してるじゃん！とか思っちゃいますが、データにはCATVさんを含む ISP だとか、携帯キャリア、公衆Wi-Fi、企業ネットワークなどの対応状況についてのデータは含まれていません。じゃぁ実際どれぐらい普及してるんだろう？と考えると、なかなか直接的なデータがありません。困った時の Google先生！ということで、多分みんな Google は使ってるよね？とか考えると、Googleが公開しているデータが指標として使えそうです。かれらのウェブサイトにアクセスしたユーザが、IPv6でもアクセスできたユーザであったかどうか、その割合についてのデータを公開してくれています。

- [Google IPv6](https://www.google.com/intl/ja/ipv6/statistics.html)

ということで、グラフから読み取るに、2019年12月現在では、アクティブなユーザの25%〜30%は、IPv6でアクセス可能なネットワークにいると考えていいのかな？

また、

- [情報通信白書令和元年版](https://www.soumu.go.jp/johotsusintokei/whitepaper/ja/r01/html/nd111120.html)

を見る限り、インターネット利用端末の種類は、2010年以降、携帯の方が多いようなので、モバイルキャリアさんの頑張りによって、今後アクセス網でのIPv6普及率も、さらに伸びたり、伸び悩んだりするのかもしれません。

## FQDN ベース

これを調べることで、コンテンツを提供する側での、IPv6対応の度合いが見えてくるかと思います。

Alexa と呼ば得れるさまざまなWebサイトのアクセス数ランキングを提供しているサイトがありますが、そのデータをベースに日本でのウェブサイトでのIPv6対応について解析したデータが公開されています。

[IPv6 Deployment Status](https://www.vyncke.org/ipv6status/detailed.php?country=jp)

これによると2019年12月17日現在でAAAA(IPv6アドレス）がついている Webサイトが 16%、メールサーバが 25%、DNSサーバ が 68% だそうです。

んー肌感覚的にはもっと少ないイメージでしたが、アクセス数が多い上位サイトを対象としているとはいえ、結構 IPv6 アドレスついてますね？

なお、もっと広範囲に日本のサイトに AAAA(IPv6アドレス）がついているかを調べた鍋島さんの調査によると

- [IPv6 Survey 2019](https://www.slideshare.net/MasaakiNabeshima/ipv6-survey-2019)
  - [IPv6サーベイ補足](https://www.kosho.org/blog/net/ipv6/ipv6-survey-2019/)

2019年11月19日現在では

- FQDNベース：2.98%
- ドメインベース：1.88%

とのことです。これぐらい低いと、みなさんの肌感覚的な IPv6の普及率と近いでしょうか？

## トラフィックベース

CDN屋さんで有名な Akamai さんが、ご自身のCDNで見えているトラフィックでの IPv6 の割合を公開しています(厳密には、セッションベースなので、Googleさんのデータと同じく、トラフィックベースではないですが）

[インターネットの現状 - IPv6 の普及状況の可視化](https://www.akamai.com/jp/ja/resources/our-thinking/state-of-the-internet-report/state-of-the-internet-ipv6-adoption-visualization.jsp#countries)

を見ると、日本は 2019年12月18日現在では 34% ぐらいですかね？前に上げた Googleさんのデータとも併せて考えると、コンテンツを消費する側の IPv6普及率は3割を越えつつあるといってもよさそうです。

あと、まだ公開されていないデータに言及するのもどうかと思いますが、[Internet Week 2019](https://www.nic.ad.jp/iw2019/)で話された内容によると、IPoE 事業者さんで観測したデータでは、IPv4とIPv6のトラフィックの割合がほぼイコールにまでなってきたそうです。単純に考えれば、コンテンツを消費するユーザ側がIPv6に対応したら、トラフィックの5割がIPv6のトラフィックで占めるようになるってことですね。
……この IPv6 のトラフィック、だれが流してるの？というと、FQDNベースのIPv6対応の寂しさから考えるに、Google, Facebook, CDN屋さんのようです。動画ベースのサービスを持っているから、というのもあるのでしょうけど、なかなか強いですね……

## 我が家でのIPv6普及率
我が家には、妻と私、子供２人がいます。ネットワークは、IPoE で IPv6に対応しています。子どもたちは暇さえあれば、AppleTVや iPadで別々にYoutubeを見ているので、トラフィックベースでは IPv4 を越えて、圧倒的に IPv6 が多くなっています。ということで、現時点では妻と私はIPv4サイトの利用が、子供たちはIPv6サイトの利用が支配的といった感じです(いや、だからどうしたって話ですが）

# まとめ
普及してないと言われるほど、利用が進んでいないわけじゃないし、普及してるよ！と言えるほど浸透もしてないといった感じでしょうか。
人の立ち位置によって、普及率の捉え方、置かれている状況が違うので、よくわからんというお話でした＜おいっ
LINEで送られてきた写真をS3に保存したい

#何に使うのか
AWSのLambdaなどを用いて画像加工する時やAWS.rekognitionのリソースとして使う時に
役に立てばと思います。
今回、LINE Developperの設定などは飛ばします。

類似の検索をするとSDKを使用している方が多いですが、今回は使わずにいきたいと思います。

##使用技術
- LINE Messaging API
- Python 3.7
- AWS S3
- AWS Lambda

##プログラム
メイン関数一部

```python:lambda_function.py
import requests
import os
import json
import boto3
from io import BytesIO
#Headerの生成
HEADER = {
    'Content-type':
    'application/json',
    'Authorization':
    'Bearer ' +'チャンネルアクセストークン'
}
#main
def lambda_handler(event, context):
    #Json Load
    body = json.loads(event['body'])
    for event in body['events']:
        payload = {'replyToken': event['replyToken'], 'messages': []}
        # ImageMessageが来た時
        if event['message']['type'] == 'image':
#HEADERとmessages(pyload)を付加してpost
     if len(payload['messages']) > 0:
            response = requests.post(
            'https://api.line.me/v2/bot/message/reply',
            headers=HEADER,
            data=json.dumps(payload))
```
ImageMessageがきた時に画像を保存したいので、

```python:lambda_function.py
# ImageMessageが来た時
if event['message']['type'] == 'image':
```
このIF文の中で処理を書いていきたいと思います。

```python:lambda_function.py
MessageId = event['message']['id']  # メッセージID
ImageFile = requests.get('https://api-data.line.me/v2/bot/message/
'+ MessageId +'/content',headers=HEADER) #Imagecontent取得

Image_bin = BytesIO(ImageFile.content)
Image = Image_bin.getvalue()  # 画像取得
```
[コンテンツを取得する](https://developers.line.biz/ja/reference/messaging-api/#get-content)←に詳しい事が書いてあるので気になる方は読んでみてください。

```python:lambda_function.py
S3 = boto3.client('s3') 
FileName = MessageId + '.jpeg'  # メッセージID+jpegをファイル名
# s３へのput処理
S3.put_object(Bucket='バケット名',
             Body=Image, # 写真
             Key=FileName)  # ファイル名
```

##最後に
ここまでの処理を書いてLINEから画像送信してS３に保存されてれば大丈夫だと思います。
処理していく中で画像が毎回保存されて残っているのが気持ち悪い人は下記のコードを書けば
解決します。

```python:lambda_function.py
S3.delete_object(Bucket="バケット名", Key=FileName)  # 送信画像削除
```
AWS SESを国内のDNSで運用するためには

AWSのSESを運用する際ドツボにハマるわけですが、なぜかというと

nameがappendされるからです。という記事で、txtだけって書いてあったんですが、
どうやら、cnameとかもごそっとだめです。
そのため、ネームサーバ毎引越ししていた時期もありました。

しかし、ようやく仕掛けがわかりました。

日本のドメイン管理サーバは

[【Amazon SES ✕ ムームードメイン】Domainのstatusがpending verificationから一向にverifiedにならない](https://qiita.com/mr-myself/items/878fd11aab53bc9185af
)

にある通り、
__nameで勝手に折り返す__という仕様があります。

つまり、AWSからは

```
 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx._domainkey.example.com.example.jp	canonical name = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.dkim.amazonses.com.
```

などのように見えるわけです。
そのため、SESが自動で払い出すレコードに記載されているものを使うと、onamae.comやムームードメインでは動きません。ですから、払い出されたものから.xxx.com等の利用ドメインを削除して記載する必要があります。
そして、

```
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx._domainkey.example.com	canonical name = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.dkim.amazonses.com.
```

このようにAWSから見える必要があります。
国内のDNSの独自仕様も困ったものなので、今後はGoogleドメインや、それこそRoute53（っていっても、こいつも癖が相当ひどい）などのグローバル仕様を使っていった方が良いのかもしれない。
/usr/bin/[ とは何者か

# 答え

testのこと。

# 経緯

/usr/bin/[ というファイルがあり、最初は何者か分からずteratailで質問しかけたのでメモに残す。
shファイルでそこそこ見かけるし、気づかなかった自分の醜態を晒す意味も込めて

```
# /usr/bin# pwd
/usr/bin
# ll \[
-rwxr-xr-x 1 root root 51384  1月 18  2018 '['*
```

容量やハッシュで調べてもよく分からず、試しに実行しても閉じ括弧ねーぞと怒られて終わり。

```
# md5sum /usr/bin/\[ 
9e0d13be90862937242d7fbfe2e05504  /usr/bin/[
# sha1sum /usr/bin/\[ 
0cd62334966e14bf21c8782b74917c00728116db  /usr/bin/[
# sha256sum /usr/bin/\[ 
d1ffbde61ddab63a1aded06d8847a5050b483623c0b798388c78f9d47422d98d  /usr/bin/[
```
```
# ./[
./[: missing `]'
```
でも検索したら普通に答えがありました。
https://superuser.com/questions/334549/what-is-usr-bin-and-how-do-i-use-it

# 確認

```
# [ -e /etc/hosts ];echo $?
0
# [ -e /etc/hostsssss ];echo $?
1
```

# 環境

```
# cat /etc/os-release | grep VERSION
VERSION="18.04.3 LTS (Bionic Beaver)"
VERSION_ID="18.04"
VERSION_CODENAME=bionic
# uname -r
4.15.0-70-generic
```

# まとめ

ダブルクォートでくくっても[が省略された検索結果を出してくんのやめろ。
強化学習３８　OpenAI Atari Ramバージョンの特徴

中学生から大学生のAI初学者が対象です。

Atariのenvでどれを選択すればいいのだろうか？
それぞれの違いは、こちらに詳しく書かれています。
https://qiita.com/keisuke-nakata/items/141fc53f419b102d942c

これを見る限り、以下の順番でやってみると良さそうです。
１　Breakout-ramNoFrameskip-v4
２　BreakoutNoFrameskip-v4
３　それ以外。
それ以外が何のためにあるのか分かりませんが。

chokozainerRLは、chainerRLのexampleをコピーして、魔改造しています。
そのため、train_dqn_aleは、NoFrameskip限定の、
chainerrl.wrappers.atari_wrappers.make_atariを使います。

この強化学習シリーズもOpenAIのAtariを始めていますが、率直に大変です。
まず、画像処理を伴わないRamバージョンでの学習を試みていますが、10000　episodesくらいではダメですね。Ramバージョンで学習させている報告が少ないので、画像バージョンを基本に考えていきます。

画像ヴァージョンで、いろいろと紹介されている方法では、
4回分のstepを１つにまとめるようなwrapperを使っています。

例えば、ChainerRLでatariのゲームをDQNで解いてみよう
https://chainer-colab-notebook.readthedocs.io/ja/latest/notebook/hands_on/chainerrl/atari_sample.html

こちらのale.ALEは、default設定で4回になっています。

breakoutはラケットで跳ね返したボールが、壁に当たるまでにかなりのstepがかかるので、gamma=0.99でも、Q判定が難しくなります。なので、4回に1回にすれば、学習効率が上がりそうです。

chainerrl/wrappers/atari_wrappers
のMaxAndSkipEnvは、Ramバージョンでは使えないので、
下のように魔改造します。

```python
class MaxAndSkipEnvRam(gym.Wrapper):
    def __init__(self, env, skip=4):
        """Return only every `skip`-th frame"""
        gym.Wrapper.__init__(self, env)
        # most recent raw observations (for max pooling across time steps)
        self._obs = None
        self._skip = skip

    def step(self, action):
        """Repeat action, sum reward, and max over last observations."""
        total_reward = 0.0
        done = None
        for i in range(self._skip):
            self.obs, reward, done, info = self.env.step(action)
            total_reward += reward
            if done or info.get('needs_reset', False):
                break
        return self.obs, total_reward, done, info

    def reset(self, **kwargs):
        return self.env.reset(**kwargs)
```

それでも学習は単純なDQNでは難航しそうなので、Ramバージョンはオススメできません。
Spine・・というかSortingOrderがあるものに対して、パーティクルを回り込ませる

本記事は，サムザップ [Advent Calendar 2019 #2](https://qiita.com/advent-calendar/2019/sumzap2) の12/24の記事です
#はじめに

みなさま、はじめまして
サムザップの中山です。

今年は、Unite Tokyo 2019にて[Addressable Assets System](https://learning.unity3d.jp/3298/)について
お話させていただく機会がありました。
此度のアドベントカレンダーでもその話の続きを・・・と思いましたが
今回は、本業であるインゲーム開発に関わる話をしようと思います。

#2Dゲームの表示順について

SortingLayerとSortingOrderを組み合わせて、階層構造で表示順を決めていくのが一般的です。
ある意味web制作的でシンプルなので、大抵の場合問題なく開発を進められると思います。
しかし、表示されるオブジェクトの順番が整数で決まるので、中途半端なかぶりを許してくれません。
2Dで取り扱われる想定のオブジェクトには、"RenderType = Transparent"、"ZWrite = off"が記述されたシェーダーが刺さっています
これはSpineの基本的なシェーダーでもそうですし、Unityのビルトインシェーダーでも同じです。
半透明かつZwriteを無視することで、いわゆる2D表現を行っています。

#パーティクルとの組み合わせ

とはいえ、ゲーム上で扱うには表示順が曖昧であったほうがいいときもあります。
エフェクトに使うパーティクルと組み合わせるときが代表的な例です。
Spineのオブジェクトとパーティクルを重ねたらどうなるでしょうか？
Spineのサンプルデータで見てみます。

SortingOrderとSortingLayerが同じだった場合
最終的な表示順は、Z軸でどちらが前かで決まります。
パーティクルの場合エミッターが基準となります。
つまりエミッターがSpineより少しでもカメラに近ければ
そこから発生されるすべてのパーティクルがSpineオブジェクトよりも表示順が強くなります。
![spine1_1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547916/16e22e98-10ba-b932-c73c-59dc99ad3a14.gif)



生み出されたパーティクルがそれぞれ個別の表示順を獲得するには、ZWriteをOnにするのが手っ取り早いです。
しかし、その際に意図しない見た目になることが多いと思います。
Spineなどの２Dオブジェクトはたいていポリゴンの形と画像の形は一致していません。
ポリゴンの余白の部分があるのですが、通常は透明になっているので目には見えません。
ZWriteをOnにすると、パーティクルよりも先に余白の部分がレンダリングされてしまう事があるのです。
![spine2_1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547916/3bf8ca4e-1c13-d29e-46f3-b94f28347773.gif)
↑足の部分で後ろに回り込んだパーティクルがレンダリングされていない


透明と不透明がはっきりしているデザインの場合、これを回避するのは比較的容易です。
シェーダーにカットオフ用のレンジスライダーを作り、その値に応じてフラグメントシェーダーでクリップを行えば
不要な部分がレンダリングされないので、意図した見た目に近くなります。
![spine3_1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547916/5b43fff2-589a-4995-0c56-467781fe137d.gif)

参考までにこんな感じで追加してみました。
`_Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1`
//中略
`clip(texcol.a - _Cutoff);`

# その他
ZWriteを追加したことによって、Z軸から表示順を決めることができるようになりました。
しかし、同時にSortingLayerとSortingOrderも生きている状態です。
Z軸での判定が効くのは、ZWriteをOnにしたオブジェクトに対してOffの状態のオブジェクトのSortingLayerが<strong>同等か高いとき</strong>です。
そうでない場合はSortingLayerとSortingOrderに準じた表示順になります。

# まとめ
お手軽ですが、なかなか反動のあるやり方でもあるので
使えない場面も、まぁあるかなと思いますが
一つの手段として覚えておくといいかもしれません。

明日は[@shirahama_manabuさん](https://qiita.com/shirahama_manabu)の記事です
それでは、良いお年を〜
クリップボードを活用したい

この記事は[Wanoグループ Advent Calendar 2019 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/wano-group)の18日目です。

この時期になるとアドベントカレンダーだったり、年末の振り返りだったりで文章に画像を含めて投稿したい事が増えてきます。

ひと昔前のコミュニケーションツールは文字ベースでせいぜい絵文字を含める程度でしたが、昨今は何かにつけて画像も添付したいというパターンが多いと思われます。

## クリップボードにコピーしたい
いちいち画像を保存 → ドラッグ＆ドロップでアップロードなんてやってられません。
刹那的な思いつきを投稿するのにPCのリソースを食うのは我慢ならん！という方の為に色んなクリップボードの活用方法を紹介したいと思います。
※Windows環境でのものになります。

### Webの画像をクリップボードにコピー
基本は画像上で右クリックでメニューが出ますので「画像をコピー」するのみ。
backgroundで指定されているような場合は「背景画像のみを表示」等して画像そのものを表示してから右クリックすればOK

#### Chrome
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152319/17c3e3f8-11f7-b0b5-f730-96ba85100b6e.png)

#### FireFox
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152319/a024f487-03e1-789d-9d85-54ee83daad82.png)

### 画面の特定領域をクリップボードにコピー
Windows10であればこれがおすすめです。 `Ctrl` + `Winキー` + `S` で画面に黒色のオーバーレイがかかり、範囲選択でコピーが可能です。
フリーハンドでの切り取りにも対応していますし、ウィンドウ単位での切り取りも可能
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152319/716df8ff-8645-992d-53a0-138b6282a138.png)

### ウィンドウ全体をクリップボードにコピー
`ALT` + `PrtSc`でウィンドウ全体がコピーされます。
これは昔から有名ですね。

## クリップボードから貼り付けたい

### Qiita
単純にショートカットでペーストするのみです。サイズが大きすぎると「equest Entity Too Large」となるのでもう少し小さな画像を取得しましょう。
成功すると`![image.png](対象のURL)`という形で本文に挿入されるのでプレビューで確認しましょう。

### Slack
ショートカットでペースト。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152319/ddc7699e-3d92-6733-d8f8-cc16b1ce3551.png)
こういう画面になるのでコメントも入力可能です。

### WordPress
旧エディタ（TinyMCE）ですとプラグインを使用しないと対応していません…Wordpressで記事投稿が面倒なのがこれなんですよね…

新エディタ（Gutenberg）ですと通常の段落でペーストすると勝手にメディアにアップロードしてくれて挿入可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152319/ceaee614-e1f6-6cbe-b1f8-08bce4ee35cd.png)

## なんでこんな事を
個人的に、書き物をしなければならない場合にあたって一番面倒なのが

**画面をキャプチャしまくって分かりやすく書かなければならない**

という強迫観念的なものがありました。ブラウザに表示されているコンテンツをコピーするだけでもいちいちプラグインやアドオンを入れたり、フォトショに一度貼り付けて加工したり…
この面倒のせいでかなりモチベーションが下がることが多かったんですよね。

クリップボードから**画像も普通の文章と同じようにコピペできる仕組みが搭載されたサービスが多くなってきた**昨今であればこのあたりのハードルが下がりやすくなってるのかな、と。

画像を使うのが面倒って思っている方がいれば意外と簡単にクリップボードを活用すれば画像さくさく貼れますよって事を伝えたかったという感じです。
[python]DataFrameを用いて任意の変数や配列をまとめてラベル付してcsvに保存[pandas]

変数をまとめてラクに保存したいなーって思ったのでそういうプログラムを作りました。
2次元配列も応用すれば保存できます。

…書いてから気づいたけど追記のやり方の方が良さそうかも
[忙しい方は追記へジャンプ](#追記) 
[単純に全変数を保存したい場合はdillを用いたやり方で](#dillを用いたやり方) 

追記の方法だと、型の関係か使おうとしたデータではエラーになりました。
DataFrameを使う方法だとエラーにならなかったので、
一度DataFrameを挟むのも無意味ではないのかも。

```python
import pandas as pd
```
まずpandasをimportします

```python

# --- テスト用に変数を定義 ---
a ,b,c,d = 1,2,3,4
xx = [3,6,8]
yy = [5,8,2]
zz = [8,2,8]
```
この関数、配列を保存します

```python
# --- 変数をまとめてdataframeにしてcsv保存 ---
def getName(obj):
    return  [k for k, v in globals().items() if id(obj) == id(v)][0] # 変数名をstrでreturn
```
この関数を使うことで変数名をstrとして取得します
ほぼ[こちらの記事](https://xnoiz.blogspot.com/2010/01/python.html)のコピペです
内容はこちらを参照ください

```python
df = pd.DataFrame()

datas1 = [xx,yy,zz] # 変数名をヘッダーにしながら、1次元配列をまとめてdataframe化
for data in datas1:
    df = pd.concat([df, pd.DataFrame({getName(data):data})],axis=1) # {}集合を使ってdataframeをconcatで追加
```
`{名前:値}`を元にDataFrameを作成してconcatで`df`にどんどん追加保存していきます
axis = 1を入れることで横に追加となります

```python    
datas2 = [a,b,c,d]# 変数名をヘッダーにしながら、変数をまとめてdataframe化
for data in datas2:
    df =  pd.concat([df, pd.DataFrame({getName(data):[data]})],axis=1)# {}集合を使ってdataframeをconcatで追加
```
先ほどと同様の事を行います
`{名前:値}`の`値`は配列である必要があるので`値`を`[data]`としています

```python
df.to_csv('test.csv')
print(df)
del df
```
保存して表示します。
`df`はいろいろなとこで使いがちなので削除も一応しておきます。

以下の表にちゃんと表示、保存出来ていることが分かります

```python
   xx  yy  zz    a    b    c    d
0   3   5   8  1.0  2.0  3.0  4.0
1   6   8   2  NaN  NaN  NaN  NaN
2   8   2   8  NaN  NaN  NaN  NaN
```

ソースコード

```python
import pandas as pd

# --- テスト用に変数を定義 ---
a ,b,c,d = 1,2,3,4
xx = [3,6,8]
yy = [5,8,2]
zz = [8,2,8]

# --- 変数をまとめてdataframeにしてcsv保存 ---
def getName(obj):
    return  [k for k, v in globals().items() if id(obj) == id(v)][0] # 変数名をstrでreturn

df = pd.DataFrame()

datas1 = [xx,yy,zz] # 変数名をヘッダーにしながら、1次元配列をまとめてdataframe化
for data in datas1:
    df = pd.concat([df, pd.DataFrame({getName(data):data})],axis=1) # {}集合を使ってdataframeをconcatで追加
    
datas2 = [a,b,c,d]# 変数名をヘッダーにしながら、変数をまとめてdataframe化
for data in datas2:
    df =  pd.concat([df, pd.DataFrame({getName(data):[data]})],axis=1)# {}集合を使ってdataframeをconcatで追加
df.to_csv('test.csv')
print(df)
del df
```
# 追記
直接csvに書き込む

```python
# --- テスト用に変数を定義 ---
a ,b,c,d = 1,2,3,4
xx = [3,6,8]
yy = [5,8,2]
zz = [8,2,8]
```

```python
import csv
# --- 変数を選んでcsv保存 ---
def getName(obj):
    return  [k for k, v in globals().items() if id(obj) == id(v)][0] # 変数名をstrでreturn

with open('test2.csv','a', newline="") as f:
    datas = [xx,yy,zz,]
    writer = csv.writer(f)
    for data in datas:
        writer.writerow([getName(data)]+data)
    datas = [a,b,c,d]
    for data in datas:
        writer.writerow([getName(data)]+[data])
```
場合分けは単一の変数をlist型に変換するため

出力　`test2.csv`

```python
xx,3,6,8
yy,5,8,2
zz,8,2,8
a,1
b,2
c,3
d,4
```

# dillを用いたやり方

保存

```python

import dill
dill.dump_session('session.pkl')
```

読み込み

```python
import dill
dill.load_session('session.pkl')
```
ですべての変数がそのまま使えます。
LaTeXでhyperrefを使うと全体的に右にずれる


# はじめに

LaTeXでは，[hyperref](https://texwiki.texjp.org/?hyperref#he2b8021)というパッケージがあります．

このパッケージは，文書内のURLや参考文献にハイパーリンクを用意し，PDFを読みやすくしてくれます．
これがあると，いちいちページの節や，参考文献の番号を見返さなくて良くなります．

# 問題点

自分はjsreportというスタイルを利用していたのですが
どうやらhyperrefを利用すると，文書全体ごと右にずれてしまうようです．
おそらく，日本語環境特有のものなのかもしれません．

# 改善策

TeXwikiの[hyperref](https://texwiki.texjp.org/?hyperref#he2b8021)を参照します．

どうやらPXjahyperパッケージを利用するか

```tex
\usepackage[dvipdfmx,setpagesize=false]{hyperref}
```

のようにsetpagesize=falseというオプションを設定すれば良いようです．

LaTeXを初めて触っていますが，色々と環境構築が必要だったり，エラーが出て大変です＞＜