OmniAICreator/Qiita-1.07M huggingface dataset:
Web Serial APIでCO2センサーの値を読み込み

新しいChrome（及びEdge）では、ブラウザが直接シリアルで会話できるということでシリアル通信のCO2センサーの値を取得してみました。
取りあえずなんとなく値をとるというだけであればトラブルはなく動きましたが安定稼働できるかはまだ不明です。

# 環境
* CentOS7 + Chrome91 + MHZ19C/USBシリアル変換済み（[これ](https://www.amazon.co.jp/dp/B091PGDMH7)） 
* Debian(いくつ？) + Chrome91 + MHZ19C/USBシリアル変換済み
* Windows10 + Chrome91 + MHZ19C/USBシリアル変換済み
* Windows10 + Edge91 + MHZ19C/USBシリアル変換済み

（全て数分程度軽く流した程度）


[MHZ19C](https://www.amazon.co.jp/dp/B08SJCWKKG)は[こんな感じ](https://qiita.com/YoshitakeKitamura/items/043e33f472c892c40925)にシリアル変換かませておけばOK。

# 動いているもの

## 実物
[こちら](https://epea.co.jp/tools/co2viewer/v0_1/v0_1_0.html)

## ポート選択
```
port = await navigator.serial.requestPort();
```

上記でPCのシリアルの選択ダイアログがでてくるのでブラウザ上で選択


## 開け閉め
```
await port.open({ baudRate: 9600 });
（略）
port.close();
```
な感じ。ブラウザ閉じたときとかきちんと解放されるのかな？ちょっと怪しいけどまだ調べられていない。（そのうち誰かがきっと教えてくれる。）

## 書き（送信）

```
        const writer = port.writable.getWriter();
        const data = new Uint8Array([255, 1, 134, 0, 0, 0, 0, 0, 121]);
        await writer.write(data);
        writer.releaseLock();
```

(なんか書いてて気づいた。全体ソースのwriter.releaseLock通らないときあるけど後でなおす)


## 受信

```
        reader = port.readable.getReader();
        const { value, done } = await reader.read();
        if (done) {
          reader.releaseLock();
        }
        document.getElementById("ppm").textContent = value[2] * 256 + value[3];
```
（readerの初期化も変なとこにいる。後で治す）

## 全体

```

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>CO2Viewer Web by Epea</title>
</head>

<body>
  <h1>CO2Viewer Web by Epea</h1>
  <button onclick="startReading()">CO2センサー読み込み開始</button>
  <div id="ppm">0</div>ppm
  <script>
    async function readOnce(port){
      try {
        const writer = port.writable.getWriter();
        const data = new Uint8Array([255, 1, 134, 0, 0, 0, 0, 0, 121]);
        await writer.write(data);
        writer.releaseLock();

        reader = port.readable.getReader();
        const { value, done } = await reader.read();
        if (done) {
          reader.releaseLock();
        }
        document.getElementById("ppm").textContent = value[2] * 256 + value[3];
      } catch (error) {
        console.log("ERRORよ");
        console.log(error);
      } finally {
        console.log("finally");
        reader.releaseLock();
      }
    }

    async function startReading() {
      var reader;
      var port;
      try {
        console.log("startReading");
        port = await navigator.serial.requestPort();
        await port.open({ baudRate: 9600 });
        while (port.readable) {
          await readOnce(port);
          await new Promise(_ => setTimeout(_, 5000));
        }
      } catch (error) {
        console.log("ERRORよ");
        console.log(error);
      } finally {
        console.log("finally");
        port.close();
      }
    }
  </script>
</body>

</html>
```

## 補足

なお、WinsenのMHZシリーズなCO2センサーは同じリードコマンドなので他のモデルでも値は上記で取得できるはず。MHZ14は電力ちゃんとしないと値は不安定になるので電源付きのUSBハブがよいかもしれない。

# 参考
[Web Serial API を最短の手順で試したくてやったこと（micro:bit を利用）](https://qiita.com/youtoy/items/a0071a6d2ef7f6930d33)
RaspberryPiでリアルタイム顔検出

#今回やること
RaspberryPiとWebカメラを使ってリアルタイム顔検出

#環境
Rasbian(RaspberryPi 4)
Python
Opencv

#処理
###カスケード分類器のインストール
```ruby:
git clone https://github.com/opencv/opencv
```

###コード
git cloneしたのと同じフォルダにコードを作成し、実行する必要があります。
(パスを変えればどこでもよい)

```ruby:
import tkinter
import cv2
import PIL.Image, PIL.ImageTk


class App:
    def __init__(self, window, window_title):
        self.window = window
        self.window.title(window_title)

        self.vcap = cv2.VideoCapture(0)
        self.width = self.vcap.get(cv2.CAP_PROP_FRAME_WIDTH)
        self.height = self.vcap.get(cv2.CAP_PROP_FRAME_HEIGHT)

        self.canvas = tkinter.Canvas(window, width=self.width, height=self.height)
        self.canvas.pack()

        self.close_btn = tkinter.Button(window, text="Close")
        self.close_btn.pack()
        self.close_btn.configure(command=self.destructor)

        self.delay = 15
        self.update()

        self.window.mainloop()

    def update(self):
        _, frame = self.vcap.read()
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

        cascade_path = "./opencv/data/haarcascades/haarcascade_frontalface_alt.xml"
        cascade = cv2.CascadeClassifier(cascade_path)
　      faces=cascade.detectMultiScale(frame, scaleFactor=1.1, minNeighbors=1, minSize=(10,10))

        for x,y,w,h in faces:
            cv2.rectangle(frame, (x,y), (x+w, y+h), (0, 0, 255), thickness=30)

        self.photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(frame))
        self.canvas.create_image(0, 0, image = self.photo, anchor = tkinter.NW)
        self.window.after(self.delay, self.update)

    def destructor(self):
        self.window.destroy()
        self.vcap.release()

App(tkinter.Tk(), "Tkinter & Camera module")
```

#参考
https://yamitomo.com/article/133
https://www.argocorp.com/UVC_camera/Sample_OpenCV_cascade.detectMultiScale.html

#注意書き
とりあえずやってみました。
めちゃくちゃ遅いです。
詳細の解説や改良、カメラモジュールでの確認は気が向いたらやっていきます。
[SpringTest] MockkでBeanをMock(Spy)化する

# はじめに
SpringBootTestでControllerの単体テストを記述する際にService層のクラスの一部の関数をMock化する例です。
[Mockkの解説ページ](https://mockk.io/)にBeanのMock化手法が載っていなかったのでやり方を調べてみました。
# バージョン等
`SpringFrameWork`: 2.2.6
`Mockk`:1.11.0

# ソースコード例
```Service.kt
@Service
class Service(
    something: Something
) {
    fun notTargetServiceFunction() : String {
        return "Not target!"
    }

    fun targetServiceFunction() : String {
        return "Not mock!"
    }
}
```
Service層のクラスは`@Service`アノテーションによりBean化され、DIコンテナに登録されます。

```Controller.kt
@RestController
class Controller (
    val service: Service
) {
    @GetMapping("/path")
    fun targetControllerFunction(): ResponseEntity<String> {
        service.targetServiceFunction().let {
            notTargetServiceFunction()
            return ResponseEntity.ok(it)
        }
    }
}
```
Controllerも`@RestController`アノテーションによりBean化されています。
（省略記法によりserviceの依存性注入も行っている)


```Test.kt
class ApplicationTests {

    @Autowired
    private lateinit var webApplicationContext: WebApplicationContext

    lateinit var controllerMockMvc: MockMvc

    @SpykBean
    private lateinit var service: Service

    @BeforeEach
    fun initController() {
        controllerMockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build()
    }
    
    @Test
    fun test() {
        every {
            cdcUserService.targetServiceFunction()
        } returns "Mock!"

        val expectedResponse = "Mock!"

        controllerMockMvc.perform(MockMvcRequestBuilders.get(PATH))
            .andExpect(content().string(expectedResponse))
    }
}
```
Mockkを使用してBean化されシングルトンとして存在するServiceのインスタンスをMock化するには`@MockkBean`or`@SpykBean`を使用します。
every文のところでMock関数の定義を行っています。
`@MockkBean`と`@SpykBean`の違いは全ての関数がMock化されるか、一部の関数だけMock化するかの違いです。
`@MockkBean`ではevery文で定義しなかった関数は何も返さない関数に置き換わりますが、
`@SpykBean`ではevery文で定義しなかった関数はそのままオリジナルの関数の定義を引き継ぎます。
Pythonでエラーが出たときに再起動させる

# はじめに
プログラムを組むにあたり、バグを出さないよう論理的にコーディングするのは当然のことだ。
とはいえ、バグがないことを断言することはできない。人間だもの。

# いろいろなエラーを起こすプログラム
こんなプログラムを書いてみた。
実行するたびにさまざまなステップでエラーで停止したり最後まで完走したりするという内容だ。

```Python:make_error.py
import random
import math
import sys

print ("="*20)
"""
後でここに追記する
"""
p = random.randint(-3, 3)
print (f"{p}です")

if p == 3:
    print (p + "の倍数だとアホになります")  
elif  p == -3:
    print (p , "だと中断します")  
    exit()
elif  p == -2:
    print (p , "だとKeyboardInterruptが発生します")  
    raise KeyboardInterrupt

print ("平方根：")
print (f"　sqrt({p}) = {math.sqrt(p)}")
print ("逆数：")
print (f"　1/{p} = {1/p}")
```

# subprocess
プログラムから他プログラムを呼び出し、またその結果（標準出力）を拾うことができる。それが`subprocess`だ。MS-DOSの時代を体験していない私には標準出力やパイプは少々難解だった、がんばって勉強した。
以下の記事がたいへん役に立った。

 - [subprocessの使い方(Python3.6)](https://qiita.com/caprest/items/0245a16825789b0263ad)
 - [subprocessについてより深く（3系，更新版）](https://qiita.com/HidKamiya/items/e192a55371a2961ca8a4)

上の`make_error.py`に以下のコードを追記しよう。追記するとこれ単品では動かなくなってしまう。それを避けるのは容易だが本題から外れるので省略している。で、できないわけじゃないからね。勘違いしないでよね。

```Python:make_error.pyに追加
args = sys.argv
e = sys.argv[1]
if e != "":
    print (f"前回のエラー：{e}")
else:
    print ("前回は正常に終了しました\n")
```

そして実行するのは`make_error.py`ではなく次の`subprocess_watch.py`だ。

```Python:subprocess_watch.py
import time
import subprocess as sp

def run_subprocess(e):
    proc = sp.Popen(["python", "make_error.py", e], stdout = sp.PIPE, stderr = sp.PIPE)
    return proc
    
proc = run_subprocess("")
while True:
    ecode = proc.poll()
    if ecode is None:  # サブプロセスが実行中
        time.sleep(2)
    else:              # サブプロセス終了
        for line in proc.stdout.readlines():
            print (line.decode(encoding="cp932"), end="")  # utf-8だと全角文字でエラーになる（Windows）

        if ecode == 0: # 正常終了
            e = ""
        else:          # 異常終了
            e = proc.stderr.readlines()[-1].decode()
        proc = run_subprocess(e)

```

これにより`make_error.py`がエラーで落ちても再起動し、かつ前回のエラーメッセージを拾うことができる。
もちろん大元の`subprocess_watch.py`が落ちてしまってはダメだけど。

```:結果（例）
====================
前回は正常に終了しました

2です
平方根：
　sqrt(2) = 1.4142135623730951
逆数：
　1/2 = 0.5
====================
前回は正常に終了しました

-1です
平方根：
====================
前回のエラー：ValueError: math domain error

-3です
-3 だと中断します
====================
前回は正常に終了しました

-2です
-2 だとKeyboardInterruptが発生します
====================
前回のエラー：KeyboardInterrupt

1です
平方根：
　sqrt(1) = 1.0
逆数：
　1/1 = 1.0
```

# まともな使い方
以上のことを[家族見守りサービスを自作する](https://qiita.com/mo256man/items/13084c865bfbf512a691)の開発中に習得した。
それにより不慮のエラーが発生しても再起動することができるようになった。
![subprpcess.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520216/2c5c136e-b0d0-a7ec-f97d-367e7a53d1ff.png)
どのようなエラーが発生したかわかるようになったのならば分析して修正しろって？ ごもっともです。

# 終わりに

今回はPythonプログラムの再起動に使っただけだが、用途はそれだけに限らない。Pythonでできないことを外に出し、その結果をもらってPythonで処理するという利用法もある。
minioを署名付きURL(pre-signed URL)で使う

# 概要

署名付きURLを発行してそれを使ってオブジェクトをアップロードする。
署名付きURLを使うことでクレデンシャルを開示しなくても利用者にminioを使ってもらえる。

# 前提

- minioは構築済み
- minioのアクセスキーやシークレットキーは知っている
-  testb という名前でバケットは作成済み
- 以下のコマンドminioのpythonSDK と requests はインストール済み  
`pip3 install minio`  
`pip3 install requests`  

# 署名付きURLを発行する

```python
from minio import Minio
import requests
import datetime

url = "minioのサーバのIPとかドメイン名とか" # e.g. 192.168.1.10:9000, minio.tmksanchi.work:9000
presign_client = Minio(
    url, access_key="minioのaccessキー", secret_key="minioのsecretキー", secure=False
)  # httpsの場合はsecure=Falseは不要。指定しないとTrue。

# 署名付きURLを発行する
presign_url = presign_client.presigned_put_object(
    "testb", "scshot.png",
    datetime.timedelta(minutes=10)
) # 引数はバケット名, アップロードするファイル名, 署名付きURLの有効期限

print("---")
print(presign_url)
print("---")
```

標準出力に署名付きURLが出力されるのでコピーしとく。

# 署名付きURLを使ってアップロードする
```python
file = {"upload_file": open("./scshot.png", "rb")}  # ここで違うファイルを指定する事もできるけど、URL発行時に指定したファイル名でアップロードされる
requests.put("署名付きURL", files=file) 
```

もし、curlでやるなら以下な感じ

```bash
curl -X PUT --upload-file ./アップロードするファイル "署名付きURL"
```

# getはどーするの？

presigned_put_object の `put`の部分を `get` にするとget用のURLが発行できる。
[参考になるコードはここ](https://github.com/minio/minio-py/blob/release/examples/presigned_get_object.py)

# 参考になるドキュメント

- [PythonSDKの公式QuickStartGuide](https://docs.min.io/docs/python-client-quickstart-guide.html)
- [署名付きURLの公式ドキュメント](https://docs.min.io/docs/upload-files-from-browser-using-pre-signed-urls.html)
【Go入門】A tour of Go 【Basics】

# A tour of Go
Go入門用の公式チュートリアル
https://tour.golang.org

ブラウザ上で実行できるのでGoインストール等は不要。
Offlineで行う方法もWelcome編に記載されている : https://go-tour-jp.appspot.com/welcome/3

この記事では各チュートリアルで個人的に理解しづらかったものや、普段使用する言語と違った部分をメモとして残します。

# Basics
## packages, variables & functions
### パッケージについて
- 外部パッケージはimportで宣言
- 外部パッケージ内で使用している変数や関数などの名前は、そのパッケージでエクスポートされている場合に使用できる。エクスポートされている名前は先頭が大文字になる。


```go:exported-names.go
package main

import (
	"fmt"
	"math"
)

func main() {
	fmt.Println(math.Pi)
}

```
math.piだと宣言されていないのでエラーになる。

### 関数について
#### 基本形
func (arg1,arg2...) (return_value) {処理}

引数や戻り値を変数宣言する際は、**型宣言は変数の後ろ**

```go:functions.go
package main

import "fmt"

func add(x int, y int) (sum int) {
	return x + y
}

func main() {
	fmt.Println(add(42, 13))
}
```

同じ型の場合はまとめて宣言可能

```golang
func add(x, y int) (sum int) {
	return x + y
}
```

複数の戻り値も可能

```golang:multiple-result.go
func swap(x, y string) (string, string) {
	return y, x
}
```
戻り値に変数名を与えると、returnの後ろに指定しなくても戻り値を暗黙で指定できる (**naked return statement**)

短いコードでは有効だが、それ以外では可読性が下がる

```golang:naked-return.go
func add(x, y int) (sum int) {
	sum = x + y
	return 
}
```
### 変数について

型宣言するJavascriptと理解するとよい
var : 変数の宣言
const : 定数の宣言 (後述)


#### ゼロ値
変数に初期値を与えずに宣言するとゼロ値が与えられる
数値型(int,floatなど): 0
bool型: false
string型: "" (空文字列( empty string ))

#### 初期値の与え方

pythonのようにまとめて代入できる

```golang:variables-with-initializers.go
package main

import "fmt"

var i, j int

func main() {
	var c, python, java = true, false, "no!"
	fmt.Println(i, j, c, python, java)
}
```
#### 暗黙的な型宣言
**関数の中では** varの代わりに **:=** を用いて型宣言せずに変数宣言ができる

```golang:short-variable-declarations.go
func main() {
	c, python, java := true, false, "no!"
	fmt.Println(c, python, java)
}
```

#### 型変換

変数vを型Tに変換する : **T(v)**

GoはC言語と異なり、**型変換は明示的に変換しないとエラーになる**

```golang:type-conversion.go
package main

import (
	"fmt"
)

func main() {
	var x, y int = 3, 4
	f := float64(x) + 0.5
	y += 1
	fmt.Println(x, y, f)
}
```
#### 定数
character, string, boolean, numericのみ
定数は暗黙的宣言 (:=) はできない

数値の定数は高精度な値であり、型が指定されない場合、状況に応じて必要な型を取る

```golang:numeric-constants.go
package main

import "fmt"

const (
	// Create a huge number by shifting a 1 bit left 100 places.
	// In other words, the binary number that is 1 followed by 100 zeroes.
	Big = 1 << 100
	// Shift it right again 99 places, so we end up with 1<<1, or 2.
	Small = Big >> 99
)

func needInt(x int) int { return x*10 + 1 }
func needFloat(x float64) float64 {
	return x * 0.1
}

func main() {
	fmt.Println(needInt(Small)) -> 0.2
	fmt.Println(needFloat(Big)) -> 1.2676506002282295e+29
}

```
SmallもBigもintかfloatか決まっていないが、それぞれ関数で要求されているデータ型にマッチするように型を取っている。
ASRock 4X4 BOX-4800U/JP に Ubuntu 21.04 をインストールする

# ASRock 4X4 BOX-4800U/JP に Ubuntu 21.04 をインストールする

## 背景

[Intel NUC (BOXNUC8I7BEH) に Ubuntu 19.04 をインストールする](https://qiita.com/m-tmatma/items/b7fc996b6781d9126b3b) で Intel NUC の Linux マシンを組みましたが、Intel NUC には LAN コネクタが 1つしかついていません。

Ryzen 搭載の LAN コネクタが 2 つ(2.5G Ethernet 1つ + Gigabit Ethernel 1つ)搭載されているモデル ([ASRock 4X4 BOX-4800U/JP](https://www.cfd.co.jp/product/minipc/4x4_box-4800u_jp/) など)を見つけました。

小型で高性能な Linux マシンでかつルータにもなれるマシンを作れるので、購入して Ubuntu 21.04 をインストールしてみました。

Ryzen ベースの小型の Linux マシンを作りたい人の参考になればと思います。

## ASRock 4X4 BOX-4800U/JP の仕様リンク

https://www.asrockind.com/ja-jp/4X4%20BOX-4800U

https://www.cfd.co.jp/product/minipc/4x4_box-4800u_jp/

## 参考

crucial が ASRock 4X4 BOX-4800U/JP に互換性のあるメモリとSSDのリストを公開しています。

https://www.crucial.jp/compatible-upgrade-for/asrock/4x4-box-4800u


## 必要なものを購入

|項目  |型番  | URL  | 購入時の価格(参考) |
|---|---|---|---|
|Ryzen7 4800U ベアボーンキット|[ASRock 4X4 BOX-4800U/JP](https://www.cfd.co.jp/product/minipc/4x4_box-4800u_jp/) |https://kakaku.com/item/K0001349271/  | 76,966 円 |
|M.2 NVMe SSD 2TB (PCI Express 4.0)|[Samsung 980 PRO MZ-V8P2T0B/IT (M.2 2280 2TB)](https://www.itgm.co.jp/product/ssd-980-pro.php) |https://kakaku.com/item/K0001327694/ | 47,980 円 |
|DDR4-3200 メモリ 16GB × 2 |[CT2K16G4SFD832A](https://www.crucial.jp/memory/ddr4/ct2k16g4sfd832a) |https://kakaku.com/item/K0001177500/  | 18,850 円 |


- `ASRock 4X4 BOX-4800U/JP`は PCI Express 4.0に対応しています。
- `ASRock 4X4 BOX-4800U/JP`は 32GB のメモリを 2つ搭載できる仕様ですが、そんなにメモリは必要ないので 16GB のメモリ 2つにしました。
- `ASRock 4X4 BOX-4800U/JP`には `Intel NUC` とは異なり、電源ケーブルが、付属しているので別途購入は不要です。
- `Ubuntu` をインストールするので Windows 10 は購入しませんでした。
- ディスプレイ用のケーブルは別途用意してください。
- インストールに使用する USB メモリも別途用意してください。

## 組み立て

1. ドライバで `ASRock 4X4 BOX-4800U/JP` のふたを開けます。
2. メモリを挿します。
3. M.2 NVMe SSD を挿します。(NVMe SSD 用の小さいプラスねじが付属しているのでそれで固定します)
4. ケースを閉じます。
5. `AC アダプタ`と`電源ケーブル`を `ASRock 4X4 BOX-4800U/JP` に挿します。

## Ubuntu 21.04 のインストール

### Ubuntu のインストール用の USB メモリの作成

この作業は別の PC で行います。

1. https://ubuntu.com/download/desktop から `Ubuntu 21.04` をダウンロードします。
2. [Fedora Media Writer](https://getfedora.org/ja/workstation/download/) をダウンロードしてインストールします。
3. `USB メモリ`を用意します (32GB の `USB メモリ`を使用しました)
4. `Fedora Media Writer` を起動して、`Custom image` を選びます。
5. ダウンロードした `Ubuntu 21.04` の `iso ファイル`のパスを指定します。
6. 正しい USB メモリが選択されているのを確認して `書き込み` ボタンを押します。
7. 書き込みに成功したら、`Fedora Media Writer` を終了して USB メモリを抜きます。

`Fedora Media Writer` は Fedora 用のツールですが、USB の起動ディスクを作成するのに便利です。

### Ubuntu 21.04 のインストール

1. 作成した `USB メモリ` を [ASRock 4X4 BOX-4800U/JP](https://www.cfd.co.jp/product/minipc/4x4_box-4800u_jp/) に挿して起動します。
2. ウィザードに従ってインストールします。
3. インストールが終わったら、メディアを抜くように促されるので抜いて ENTER キーを押します。

### インストールに使用した USB メモリの後始末

インストールに使用した USB メモリはそのままでは Windows で認識しなくなるので`Fedora Media Writer` を使って後始末します。

1. インストールに使用した USB メモリを挿して、`Fedora Media Writer` を起動します。
2. `Restore` ボタンを押します。
3. 確認画面が出るので新しい画面で `Restore` を押します。
4. Windows 上で普通のドライブとして認識するようになります。
Macでpythonを使うときに覚えておいた方がいい備忘録

### はじめに
Macでpythonを使う時に覚えておいた方がいい備忘録について記載する
Windowsは手順が変わると思われるのであくまでMacのみということで限定する

###pyenv
pythonを複数バージョンで使いたいという時に使う
具体的にはbrewから以下の手順でインストールする

brewのインストールがまだというかたは以下のサイトを参照し
TOPページにあるとても長いコマンドをコピペしてインストールしておく

https://brew.sh/index_ja

インストールが終わったら

```zsh
brew install pyenv
```

とする
この時エラーが私の環境だと出たのでユーザの環境変数のファイル(私はzshを使っていたので.zshrc)に
以下の記載を追加する

```zsh
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"
```

pyenvのインストールが終わったらまずは自分が使いたいpythonのバージョンをインストールする
以下のコマンドを実行するとインストールできるバージョンがリストアップされる

```zsh
pyenv install --list
```

今回は3.6.6をインストールしたいので以下のようにする

```zsh
pyenv install 3.6.6
```

インストールが終わったら以下のようにバージョンの切り替えができる
`pyenv global <version名>`で覚えておこう

```zsh
pyenv global 3.6.6;python3 -V
```

現在のインストール状態が知りたい場合は以下の通り

```zsh
pyenv versions
```

以下のように今使っているバージョンがコメ印で表示される

```:出力結果
* system (set by /Users/yue-pc/.pyenv/version)
  2.7.16
  3.6.6
```

また元に戻したい場合は次のコマンドを実行

```zsh
pyenv global system;python3 -V
```

因みにanacondaなんかも入れられるのでローカルに入れたanacondaは消して今後はpyenvで個人的には管理しようと思う

```zsh
pyenv install anaconda3-2021.05
pyenv global anaconda3-2021.05
pyenv versions
```

次のようにanacondaに切り替わっていればanaconda3のpythonになっている

```:実行結果
  system
  2.7.16
  3.6.6
* anaconda3-2021.05 (set by /Users/xxx-pc/.pyenv/version)
```

プロンプトもanacondaになっていることを確認できる

```
% python
Python 3.8.8 (default, Apr 13 2021, 12:59:45)
[Clang 10.0.0 ] :: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
```

condaもきちんとインストールされている

```zsh
which conda
/Users/xxx-pc/.pyenv/shims/conda
```

### virtualenv
pythonにはデフォルトで仮想環境にpythonが入れられる
色々試したい時に色々ローカルにpython環境を入れて思わぬ不具合にぶつかってハゲ散らかすことがないように何かやるときは必ず仮想環境下にpython実行環境を作っておくのがオススメであるというかマストであると思う

というわけで仮想環境を作る方法だが至って簡単
pythonコマンドでに"-m"でモジュール指定でvenvと指定し仮想環境名を指定するだけである

適当にhogehogeという環境を作る
なお作成される環境はローカルのpython環境になるため、version2系を入れたいとかいう場合は事前に`pyenv global <pythonバージョン>`とかでpython2系に切り替えておく方が良い
※作り直せなくはないが面倒なので

- 環境作成

```zsh
python -m venv hogehoge
```

-仮想環境へログイン

```zsh
#. ./hogehoge/bin/activate
source ./hogehoge/bin/activate
```

`(hogehoge) % `のように先頭に仮想環境名がついていればログインできたことになる
先頭の(.ドット)がないと何故か権限エラーになる場合があるので(.ドット)を忘れないように

- 20210622追記
その後の調べでsourceと(.ドット)コマンドは同じものらしい
確認したところ実行しようとしているactivateというスクリプトには実行権限が付与されていなかったのでエラーになったことが判明した※以下参考

```zsh
-rw-rw-r--  1 xxx-pc  staff  2423  6 21 10:53 ./conda_python_works/bin/activate.fish
-rw-rw-r--  1 xxx-pc  staff  1271  6 21 10:53 ./conda_python_works/bin/activate.csh
-rw-rw-r--  1 xxx-pc  staff  2219  6 21 10:53 ./conda_python_works/bin/activate
```

実行権限がついてなくても実行できる方法としてsourceと(.)の2つが用意されているということであった
ドットだと見落しの可能性があると思うので個人的にはsourceで統一したい

- 仮想環境からのログアウト

deactivateと入力するこれだけ

```zsh
deactivate
```

- 作成した仮想環境の削除

rmで消すだけ

```zsh
sudo rm -rf ./hogehoge
```
N+1問題の解決法(Ruby on Rails)

# N+1問題とは
1つのテーブルへのSQL発行と。N回の関連デーブルへのSQL発行が発生してしまうこと。
データ量が多い大規模サービスで顕著に低いパフォーマンスが現れてしまう。

##　対象のモデル
N+1問題を確認するモデルは,tag_categoryモデルとtagモデル。
以下の2つのモデルは1対多の関係になっている。
[![Image from Gyazo](https://i.gyazo.com/f6c2f8a42af14550a3403c8ab3d535bf.png)](https://gyazo.com/f6c2f8a42af14550a3403c8ab3d535bf)

## SQL発行のタイミング
例えば以下の処理をコンソールから入力したとする。

```ruby:Ruby
Tag.find(1)
```

このコードでは、Tagsテーブルのレコードからidが1のものを検索しTagモデルのインスタンスを生成している。

## 関連するモデルの値を生成するSQL

```ruby:Ruby
Tag.find(1).tag_category
```
このコードを実行すると。
1. idが１のレコードをTagsテーブルから取得する
2. 検索結果のレコードからtag_catory_idを取得する
3. tag_categorysテーブルから2で検索したtag_category_idのレコードを取り出す
4. 検索したレコードからtag_categoryインスタンスを生成する

## N+1問題が起こる仕組み

ループによってインスタンスを複数生成する場合にN+1問題が発生する。

```ruby:Ruby
Tag.limit(5).each do |tag|
  tag.tag_category
end

```

以下のコードを実行すると、
1. Tagテーブルから5件のレコードを取得する
2. ブロック内で書くTagインスタンスに基づくtag_categoryインスタンスを取得するループ処理を行う

よって、このコードでは5+1回SQLの発行が行われN+1問題が発生している。

# N+1問題を解消する方法

アクティブレコードで以下のメソッドを使用してSQLを発行する。
1. joins
2. left_outer_joins
3. eager_load
4. preload
5. includes
【論文紹介】Tasting spoons: Assessing how the material of a spoon affects the taste of the food

#論文紹介
論文：Tasting spoons: Assessing how the material of a spoon affects the taste of the food
著者：Betina Piqueras-Fiszman, Zoe Laughlin , Mark Miodownik, Charles Spence
https://reader.elsevier.com/reader/sd/pii/S0950329311001765?token=071E8D882B46B157CB79F2140258151A0CF456F5C5072CF2797BE639347230995E5405317F907D636159E2EFD89A98D4&originRegion=us-east-1&originCreation=20210614063648

#どんなもの
　特定の金属の味が食品の知覚に与える影響を調査した。金、銅、亜鉛、ステンレスの金属でメッキされたスプーンを用いて、甘味、酸味、苦味、塩味、プレーンのクリームを試食した。その結果、亜鉛と銅のスプーンは、やや金属的で苦い味がする。また、亜鉛と銅のスプーンは、それぞれのクリームの味を引き立てることがわかった。亜鉛と銅のスプーンの金属味は、心地よさに影響を与えないこともわかった。これらの結果から、カトラリーの素材となる金属が知覚に与える影響は、食品の組成に金属塩を加えたときと異なることがわかった。

#先行研究と比較してすごいところ
　<font color="gray">先行研究では、同じヨーグルトを食べるときに金属製のプラスチックスプーンで試食した場合とステンレス製のスプーンで試食した場合とでは、被験者の品質判断と嗜好判断が大きく異なり、ステンレス製のスプーンのほうが高い結果になった。このように、</font>先行研究では食品を食べるときに使うカトラリーは食生活に影響を与えていることがわかっている。しかし、この結果がスプーンの重さや温度などの物理的性質の違いによるものか、それとも全体的な記号論理的評価(プラスチックと金属のスプーン)によるものなのか不明だった。食事の際に使用するカトラリーに焦点を当てた論文はほとんどなかった。
　カトラリーの味が、そのカトラリーを使って味わった食べ物の味の認識に影響を与えるほど強いかどうかを報告した研究はまだない。


#技術や手法のキモ
　Laughlinらの研究で使用されたものと同じスプーンを利用。同じスプーンを4つ用意した。ステンレス製のスプーン3本に金、亜鉛、銅の電気メッキを0.01mmの厚さで施し、4本目はステンレス製のままにした。
　砂糖、レモン果汁、lemonpith、食塩を用いて味・風味の異なるクリームを4種類、プレーンのクリームを1種類用意した。

#検証方法
　目隠しした状態で、５種類のクリーム(苦味、酸味、塩味、甘味、プレーン)の苦味、甘味、塩味、金属味に対する金属の影響を調べる。これらの組み合わせに対する快楽的反応を評価する。次に、目隠ししない状態で、スプーンの見た目が食品の知覚に影響を与えるかどうかを調べる。

　苦味、塩味、甘味、金属味、快感の知覚に有意な影響を与えるかどうかを調べるために、これらの要因を独立変数として、消費者、スプーンの種類、試食品、およびそれぞれの相互作用を変動要因として、データの分散分析を行った。
　スプーンの外観が評価に影響するかを調べるために、目隠しした状態としてない状態の2つの条件で、金のスプーンとステンレスのスプーンの評価について別々のANOVAを行った。

→異なる金属でコーティングされたスプーンは実際に味が異なり、その違いは食べ物の味や心地よさの知覚に影響を与えるほど大きかった。
　金やステンレスのスプーンに比べて、銅や亜鉛のスプーンは金属味が強く、甘いサンプルの苦味が強調された。しかし、銅や亜鉛のスプーンは甘味をわずかに増強し、塩味を抑制できた。また、苦いクリームや酸味のあるクリームでは、苦味や塩味が強く感じられた。
　<font color="gray">この結果は、Keast（2003）の結果と対照的である。(彼は、亜鉛を甘味料と苦味料に添加すると、甘味と苦味がそれぞれ強く抑制されることを発見した。)</font>
　塩味のクリームでは、銅と亜鉛のスプーンによって苦味と塩味が強調され、結果的に心地よさが減少するという結果が得られた。
→亜鉛と銅のスプーンは、それぞれのクリームの味を引き立てることを示した。また、スプーンの種類は快楽的にも影響を与えた。ある金属が実際の食品に添加されたときに食品の知覚に及ぼす影響は、食器の金属が及ぼす影響とは全く異なることが明らかになった。


#議論
　クリームの刺激は単純で実験しやすいが、より複雑な食べ物(オムライスとか)に対する金属味の影響はどうなのか。(他の食べ物の特性を考慮してみたら面白そう。)
　スプーンの金属が金属感覚に影響を与えているのなら、スプーンも食べ物の全体的な風味に影響を与えているのではないか。


#気になった論文
　The use ofstandard electrode potentials to predict the taste of solid metals(過去の論文)
「2進数 ⇄ 10進数【Ruby】」を参考にWolframAlphaとSymPy Liveでやってみたい。



(オリジナルポスト)

https://qiita.com/Ub_Iwerks/items/15b16adda319325a4d2f


##WolframAlphaで
https://ja.wolframalpha.com/input/?i=2%E9%80%B2%E6%95%B0+11111111%E3%82%92+10%E9%80%B2%E6%95%B0+%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B

https://ja.wolframalpha.com/input/?i=255+%E3%82%92+2%E9%80%B2%E6%95%B0+%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B

https://ja.wolframalpha.com/input/?i=11111111_2



#SymPy Liveで
勉強中

#参考

https://qiita.com/mrrclb48z/items/2eff9d74f8e7923d5b8d
【営業向け】You do not have permission to call....とGASから言われたときの対処法

##エラー内容と対処法

GASを書いているときに、以下のようなエラーに遭遇することがありました。確かスプレッドシートからスクリプトエディタを開いてマクロを作ろうとしたときに遭遇をしました。

```
Exception: You do not have permission to call DocumentApp.create. 
Required permissions: https://www.googleapis.com/auth/documents
```

こんなエラー今まで遭遇したことなかったけどな、、、と思いましたが、もしかしたらスプレッドシートのマクロにはDocumentAppとかを呼ぶ権限が初期設定ではないのかもしれません。権限の問題でAPIを呼ぶことができないという事らしいので、とりあえずググったら公式のヘルプがありまして、ヘルプ通りにやれば大丈夫です。


https://developers.google.com/apps-script/concepts/scopes#new-editor_1

対処法としては、ヘルプの通りにはなりますが、プロジェクトの設定→【『appsscript.json』マニュフェストファイルをエディタで表示する】にチェック→appsscript.jsonファイル内に権限を付与する設定を記述、をすることでエラーを回避することができました。

以下、手順です。

###①プロジェクトの設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271600/e7c169a5-eabd-438a-6be5-b4e0758de3a4.png)

###②appsscript.jsonを表示

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271600/1b0f2a34-51cb-e1bf-1417-d99b6cb86941.png)

###③appsscript.jsonを赤字のように記述
エラー内容に応じて、どのURLを入れるかは変わりますので、エラー時に表示されるURLを入れてあげれば大丈夫です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271600/fcf0955a-3d5a-9409-c10d-fff7c8432e52.png)
vivadoのsimが重いので、サードパーティのsimを使ってみた②

<a href="https://qiita.com/kamura375/items/57f83e121536c3c0d003">前回</a>、vivadoからsimvisionを立ち上げてRTLシミュレーションを実行する方法を調査した。
課題として、毎回vivadoを立ち上げてRun Simlationするのが面倒、1階層しか波形をとってくれないという不満があった。今回はここを克服することを目標とする。

# xcelium用のシミュレーションディレクトリ
<project_path>/<project>.sim/sim_1/behav/以下に移動すると、xceliumとxsimの2つのディレクトリがあった。xsimの方はvivadoのシミュレータで今回確認するのはxceliumの方。

<project>.sim/以下は以下のようなファイル構成になっていて、RTL修正後にxcelium/以下でsetup.sh→compile.sh→elaborate.sh→simulate.shの順に実行すれば、GUIを立ち上げずともシミュレーションが実行できた。

```sh
.
└── sim_1
    └── behav
        ├── xcelium
        │   ├── cds.lib
        │   ├── compile.sh     # step2
        │   ├── elaborate.sh   # step3
        │   ├── glbl.v
        │   ├── hdl.var
        │   ├── setup.sh       # step1
        │   ├── simulate.sh    # step4
        │   ├── tb_simulate.do # depth
        │   ├── waves.shm
        │   ├── xcelium_lib
        │   └── xmsim.key
        └── xsim
```

# 波形取得階層の変更
同じくxcelium以下のtb_simulate.doを見ると、以下の通り -depth 1という記述がある。この数値を変更することでより深い階層の波形を取得することができた。

```sh
set pack_assert_off {numeric_std std_logic_arith}

database -open waves -into waves.shm -default
probe -create -shm -all -variables -depth 1 -waveform

run 1000ns
```
「APIってなんだ？JSONってなに？」を初学者にわかりやすくまとめた

Web系企業でインターンをしていました。
実務で使われている技術と初学者が作るポートフォリオでは、当然ながら別物です。
そこで今回、実務でよく使われているAPIとJSONについてまとめました。
**これからエンジニアに転職しようとする人**は絶対に知っておいたほうがいい内容です。
この記事では、詳細な解説は省略しました。
なぜなら**詳細に丁寧に解説した良質な記事**はすでに存在するからです。
それらの記事は参考文献に載せておきます。

##この記事の目的
プログラミング初学者が、API、JSONについて、どういうアプローチで考えれば理解しやすいかを目的としました。
そのため言葉足らずや、厳密には違うこともあるかもしれません。
認識間違いや、「こう考えた方が正確だよね」などありましたらご指摘いただけますと嬉しいです。

##APIとは
**API（アプリケーションプログラミングインターフェース）とは、どのアプリケーションでも共通で使える機能を提供する仕組みのことです。**
API＝関数と考えると覚えやすいです。Rubyでいうとメソッドですね。
APIを使うとは、**メソッドを呼び出すこと**と考えると理解しやすいかもしれません。
このあたりの考え方は「[WebAPIについての説明](https://qiita.com/busyoumono99/items/9b5ffd35dd521bafce47#api%E3%81%A8%E3%81%AF)」という記事が大変わかりやすく、丁寧に解説されているのですべて読むことをおすすめします。

##Web APIとは
**Web APIとは、インターネット経由で別のサーバー上にあるプログラムを呼び出し、その結果を受け取ることができる仕組みのことです。**
すでに存在する機能（プログラム）を外部から呼び出して、自分のアプリケーションで利用すると考えると理解しやすいかもしれません。
例えば、Googleマップを自分のアプリケーションで利用するなどが該当します。
一言でまとめると、**別サーバーで用意している関数（機能）をhttp通信で利用することです。**

##JSONとは
**JSON（JavaScript Object Notation）とは、データを表現する仕組みのことです。**
こちらの記事は大変わかりやすくまとめてあります。
→[非エンジニアに贈る「具体例でさらっと学ぶJSON」](https://dev.classmethod.jp/articles/concrete-example-of-json/#return-note-141781-1)

```ruby:
[{"id":1,"created_at":"2021-06-19T14:50:29.673Z","updated_at":"2021-06-19T14:50:29.673Z","name":"kazu"}]
#カンマ(,)区切りで、key: valueの関係でデータを表現しています。

example = [
 {
  "id":1,          #=>数値（number）
  "name":"kazu"    #=>文字列値（string）
  "age": null      #=>ヌル値（null）
  "children": true #=>真偽値（boolean）
 }
]
#このようにインデントをつけて表現することもできます。
#上記はvalue（値）の例です。この他に配列値（[]）やオブジェクト値（{}）を持つことができます。
```

##JSONの使い方
**連想配列（オブジェクト形式）の場合、変数名.keyでvalueを取得できる。
配列値の場合は、変数名.key[0]など、配列のindex番号を指定することでvalueを取得できる。**

```ruby:
example = [
 {
  "id":1,          #=>数値（number）
  "name":"kazu"    #=>文字列値（string）
  "age": null      #=>ヌル値（null）
  "children": true #=>真偽値（boolean）
  "array": [1, "foo", "bar", "baz"]
 }
]
example.id       #=>1
example.name     #=>"kazu"
example.array[1] #=>"foo"
```

##まとめ
* APIとは、どのアプリケーションでも共通で使える機能を提供する仕組みのこと。
* Web APIとは、インターネット経由で別のサーバー上にあるプログラムを呼び出し、その結果を受け取ることができる仕組みのこと。
* JSON（JavaScript Object Notation）とは、データを表現する仕組みのこと。

##参考文献
[WebAPIについての説明](https://qiita.com/busyoumono99/items/9b5ffd35dd521bafce47#api%E3%81%A8%E3%81%AF)
[非エンジニアに贈る「具体例でさらっと学ぶJSON」](https://dev.classmethod.jp/articles/concrete-example-of-json/#return-note-141781-1)
Kotlin Flowを使ってみた[Android, Kotlin]

#やったこと
Firebase Authenticationで作成したアカウントを、ユーザーが削除できる機能を作りました。その際削除が成功したかによってToastを表示したいと思い以下のように実装しました。

1 Repositoryでアカウントを削除
2 ViewModelの isDeleteUser : Flow<Boolean> に削除が成功したかを格納
3 Fragmentで isDeleteUser : Flow<Boolean> の値を収集してToast表示

# Repository
```kotlin:Repository.kt
//削除が成功したかどうかを受け取ってViewModelに返します
 suspend fun deleteUser(): Boolean {
        val result = deleteUserFun().getOrThrow()
        if(result) return true
        else {
            Log.e("Error", result.toString())
            return false
        }
    }

//実際のアカウント削除の処理
private suspend fun deleteUserFun(): Result<Boolean> {
        return kotlin.runCatching {
            suspendCoroutine { continuation ->
                user.delete()
                    .addOnSuccessListener {
                        continuation.resume(true)
                    }
                    .addOnFailureListener {
                        continuation.resumeWithException(it)
                    }
            }
        }
    }
```
ラムダ式を使ってViewModelに値を返すこともできるのですが、コールバック形式は美しくないのでsuspend関数で値を返していきます。
コールバックをsuspend関数でなくす方法についての参考にした記事
https://star-zero.medium.com/callback%E5%BD%A2%E5%BC%8F%E3%81%AE%E3%82%82%E3%81%AE%E3%82%92coroutines%E3%81%AB%E5%AF%BE%E5%BF%9C%E3%81%99%E3%82%8B-9384dfa6ad77

# ViewModel

```kotlin:ViewModel.kt
private val _isDeleteUser = MutableSharedFlow<Boolean>()
    val isDeleteUser: Flow<Boolean> = _isDeleteUser

    fun callDeleteUser() {
        viewModelScope.launch(Dispatchers.IO) {
            val result = Repository.repository.deleteUser()
            _isDeleteUser.emit(result)
        }
    }
```
deleteUser()はsuspend関数で、suspend関数はcoroutineボディ内か他のsuspend関数内からしか呼び出せないのでこのようにしています。resultにdeleteUser()の返り値であるBooleanが格納された後
_isDeleteUser.emit(result)
とすることでMutableSharedFlowに値を送信しています。

また↓このようにしている理由ですが、MutableSharedFlowは再代入が可能なのでFragmentから参照する値をFlowにすることで再代入されることを防いでいます。

```
private val _isDeleteUser = MutableSharedFlow<Boolean>()
val isDeleteUser: Flow<Boolean> = _isDeleteUser
```

# Fragment

```kotlin:Fragment.kt
viewLifecycleOwner.lifecycleScope.launch {
                viewModel.isDeleteUser.collect {
// itにBooleanが入ってます
                    if (it) Toast.makeText(context, "アカウントを削除しました", Toast.LENGTH_LONG).show()
                    else Toast.makeText(
                        context,
                        "アカウントを削除できませんでした。再度ログイン後削除してください",
                        Toast.LENGTH_LONG
                    ).show()
                }
            }
```
Flow.collectで値を収集し分岐してToastを表示させています。またcollectもcoroutineかsuspend関数から呼び出す必要があります。

#まとめ
emit()で値を送る
collect()で値を収集

#最後に
すごく具体的な使い方の解説になりました。Flowについての理解が深まったら凡庸的な使い方についても解説するかもしれません。助言、訂正すべき箇所などあったらどしどしコメントください！！
画面表示時のイベントの発火タイミング

#####HTMLの描画が終了した時点でイベント起動
```javascript
// パターン1
$(function(){
  alert("HTML描画終了");
});

// パターン2
$(document).ready(function(){
  alert("HTML描画終了");
});
```

#####全要素の描画が終了した時点でイベント起動(現在は非推奨)
```javascript
$(window).load(function () {
  alert("全要素描画終了");
});
```
#### 参考リンク
* [JS] https://developer.mozilla.org/ja/docs/Glossary/IIFE
GPT-Jにホーランドロップについて解説してもらいました

#概要
GPT-Jにホーランドロップについて解説してもらいました
英語をDeepLで日本語化しています。

#参照元
https://colab.research.google.com/github/kingoflolz/mesh-transformer-jax/blob/master/colab_demo.ipynb

#作成文書
```
ホーランドロップは、オランダでペットとして飼われている白鼻の小型ウサギの品種の一つである。名前の由来は、このウサギがレタスを好んで食べることからで、ほとんどの人が「レタス・ラビット」と呼ぶことができる。白い鼻、中くらいの耳、長い尻尾を持つこのウサギは、中国のウサギのような外見をしている。

ホーランドロップはとてもフレンドリーで遊び好きな性格で、コンパニオンアニマルとしても人気があります。

歴史

ホーランドロップは、1906年にロイヤルダッチラビットリーがサンタクルスとネザーランドジャイアントを交配して開発したのが始まりである。1909年、この交配によって生まれたホーランドロップは、全く新しいウサギの品種として認められました。飼育者であるヤコブとゲルトのカンプ兄弟にちなんで名付けられた。その後3年間で、約60羽のウサギを使って品種改良が行われた。1910年にオランダで初めて展示されました。

イギリスのホーランドロップは現在、国際ラビット・ブリーダーズ・アソシエーション（The International Rabbit Breeders Association）によって繁殖され、展示されています。また、オーストラリアのホーランドロップ協会は別の登録団体で、このウサギを繁殖しています。

ホーランドロップのペアを持つ女王

特徴

外観。ホーランドロップの鼻は白く、中央にわずかに赤が入っています。また、中型のウサギで、厚くて光沢のある被毛を持っています。これは耳の色でもあり、端正な外見をしています。尻尾も中くらいの大きさで、根元に色がついています。脚はダークな色合いのブラウンです。

気質。ホーランドロップスは気立てがよく、知的で遊び好きな品種です。他のウサギや犬にも友好的で、子供にもかなり好意的です。社交的で適応力があり、他のペットとの相性も良い。

食事とグルーミング レタス、レタス、ニンジン、リンゴを好みます。

寿命。うさぎは通常、初産で4～5歳、2～3年生きます。ホーランドロップはイギリスでは確立された品種ではなく、純血種として購入することができますが、ブリーダーはホーランドロップとチンチラの交配種も生産しており、人気を博しています。

起源

ホーランドロップは、中米から輸入されたサンタクルスウサギを起源としています。1906年にサンタクルス種とネザーランドジャイアント種を交配して作出されました。ホーランドロップはイギリスで開発された最初のウサギの品種の一つです。
```

#感想
文書としては成立しているが、どこが本当で嘘か良くわからない結果になりました。
Akashic Engineでマルチプレイゲームを作る際、クライアント・サーバモデルプログラミングと異なる点

[Akashic Engine](https://akashic-games.github.io/) を使うと [ゲームアツマール](https://game.nicovideo.jp/atsumaru/) や [ニコ生ゲーム](https://site.live.nicovideo.jp/recent/namagame.html) でマルチプレイゲームを公開できます。

本記事では、Akashic Engineを使ってマルチプレイゲームを初めて作る際に覚えておきたい、一般的なクライアント・サーバモデルとの違いを紹介したいと思います。

# クライアント・サーバモデルとAkashic Engineマルチプレイの違い

一般的なクライアント・サーバモデルの場合、クライアントのリクエストを元にサーバ側で処理を行い、結果をクライアントで描画すると思います。クライアント側とサーバ側で両方のコーディングが必要です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1234545/a5a8080a-cba5-7d0c-61ad-bf1162faa19e.png)

しかし、Akashic Engineマルチプレイはクライアント側のコーディングしかしません。サーバ側ではなくクライアント側で処理します。ではサーバは何をするかというと、クライアントからメッセージを受け取り、全クライアントにメッセージを発信する役割を担います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1234545/947b434d-cbed-23b7-f486-5d561431e9c8.png)

# サーバサイド固有のロジックは存在しない

Akashic Engineマルチプレイの場合、サーバはクライアントから送られたイベント([`g.game#raiseEvent`](https://akashic-games.github.io/reference/akashic-engine-v3/classes/game.html#raiseevent))を全クライアントに発信([`g.Scene#onMessage`](https://akashic-games.github.io/reference/akashic-engine-v3/classes/scene.html#onmessage))します。そのため、何かデータを加工したりデータを元に判定する処理はすべてクライアント側で実装する必要があります。

# ランダムな動きは同じシードを持つ乱数生成器で同じ状態を作り出す

プレイヤー以外にCPU、モブ、NPCがいる場合、ランダムな動きをさせる必要があると思います。一般的なクライアント・サーバモデルの場合、これらの座標やアクションはサーバ側で計算して結果をクライアントに返すことになると思いますが、Akashic Engineマルチプレイの場合は異なります。

理論的には初期状態から同じシードを使って乱数を生成し、同じ時間経過処理を回せば全く同じ状況が作り出せるはずです。拙作の例で恐縮ですが、「[出勤のお時間です！【対戦版】](https://game.nicovideo.jp/atsumaru/games/gm20447?)」では住宅付近のランダムな位置に出現した通勤客が経路探索して会社に向かいます。出現位置は[シード値を共有する乱数生成器](https://akashic-games.github.io/tutorial/v3/animation.html#random-number)を使うことで全クライアントで同じにすることができます。経路探索処理もクライアント側で実行しますが、同じロジックを使うので同じ時間経過すれば同じ経路をたどるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1234545/e8072db4-6a72-2573-2fb1-dff6c03851fb.png)

# 途中参加プレイヤはゲーム開始から早送りすることで同期する

ゲームは始まってから参加したプレイヤにどう現在の状態を伝えるかですが、一般的な場合、スナップショット情報（どのエンティティがどこにいるかなど）を送ると思います。

Akashic Engineマルチプレイの場合、初期状態から経過時間早送りすることで追いつきます。途中参加プレイヤには何tick目にどのイベントが発生したかという情報が送られます。クライアント側で高速でtickを回し、イベントを消化していけば同じ状況になるはずです。

[Akashic Engine 入門(v3 版) マルチプレイの基礎](https://akashic-games.github.io/tutorial/v3/multiplay/introduction.html)
>  同じゲームスクリプトに、同じ経過フレーム数で同じイベントを与えれば、同じ実行状態に至るはずだ 、というのが、Akashic Engine のマルチプレイの基本的なデザインです。後から参加したプレイヤーに、早送りで最新状態に追いつく動作が発生するのはこのためです。

したがって、途中参加プレイヤ向けに現在のスナップショットを通知する必要はありません。

# まとめ

Akashic Engineでマルチプレイゲームを作る際、一般的なクライアント・サーバモデルと異なる点に注意しましょう。

* サーバはクライアントからのイベントを中継します。イベントを受けたロジックはすべてクライアント側で実装しましょう
* モブなどのNPCは乱数生成器のシードを共有することで同じ状態を再現します。イベントで送る必要はありません。
* 途中参加プレイヤは早送りして追いつきます。したがってスナップショット情報は送る必要がありません。
【Excel】フィルター操作

# オートフィルターとテーブルの違いについて
　・フィルターはテーブルの機能の一つである。
　　よって(テーブル > フィルター)

# オートフィルターを使ってみよう
## オートフィルターの有無を確認する。
```vb
  sheet.AutoFilterMode
```

　・AutoFilterModeを参照する (True/False)

## オートフィルターを削除する。
```vb
  sheet.AutoFilterMode = False
```

## オートフィルターを追加する。
```vb
  ' 単一セルの場合 : 全体(A1 ~ CurrentRegion)にフィルターがかかる。
  Range("A1").AutoFilter

  ' 複数セルの場合 : その領域だけフィルターがかかる。
  Range("B3:C5").AutoFilter
```

## オートフィルターで絞り込みを行う。
### 単一列の絞り込み
```vb
  ' フィルターの「3」列目の「セルの値」が「100」となる絞り込みを掛ける。
  Range("A1").AutoFilter Field:=3, Criteria1:="100", Operator:=xlFilterValues
```
### 複数列の絞り込み
```vb
  ' AutoFilterでチェインする。
  Range("A1").AutoFilter Field:=3, Criteria1:="100", Operator:=xlFilterValues _
             .AutoFilter Field:=4, Criteria1:="ABC", Operator:=xlFilterValues
```
### OR条件の絞り込み
```vb
    ' いずれかのワードを含む
    .Range("A1").AutoFilter Field:=4, Criteria1:="*削除*", _
                            Field:=4, Criteria2:="*不要*", _
                            Operator:=XlAutoFilterOperator.xlOr
```
### And条件の絞り込み
```vb
    ' いずれのワードも含む
    .Range("A1").AutoFilter Field:=4, Criteria1:="*削除*", _
                            Field:=4, Criteria2:="*不要*", _
                            Operator:=XlAutoFilterOperator.xlAnd
```
### 一致条件の指定 (Criteria)

|記載|意味|
|:-|:-|
| ="100" | 100と一致する  | 
| ="<>100" | 100と一致しない  |
| ="" | ブランク  | 
| = *ABC*  | ABCを含む  |
| = ?BC  | 2,3文字目がBC  |

## オートフィルターで絞り込みの結果をコピーする。
```vb
  ' 結果の2行目をコピーする。
  Range("A1").AutoFilter Field:=3, Criteria1:="100", Operator:=xlFilterValues _
  .Column(2).Copy
```

| 名前 | 内容 |
|:-:|:-:|:-:|
| Field  | フィルターの列数  | 
| Criteria1  | フィルターの絞り込み条件  |
| Operator  | 何と比較して絞り込むか。(セルの値、セルの色 etc)  |

## アドバンスフィルターで重複削除
```vb
  sheetEmployee.Columns("C:F").AdvancedFilter _
  Action:=xlFilterCopy, _
  CopyToRange:=sheetDepartment.range("A1"), _
  Unique:=True
```
|記載|意味|
|:-|:-|
| Action | データの転記方法 | 
| CopyToRange | データの転記先  |
| Unique | データ重複を削除するか  | 
　・データの転記と重複削除を非常に簡潔に記載できる。
　・処理速度は早くないので、大量データには向かない。

## オートフィルターの使いどころ
  大量データのうち、該当件数が少数の場合、
　1件ずつ走査するよりも、フィルターでまとめて該当部分を抜き取ったほうが処理がはやい！

# 参考
 https://excel-ubara.com/excelvba1/EXCELVBA389.html

 https://excel-ubara.com/excelvba1/EXCELVBA390.html
Unity から Google Cloud Anchor を使うための Google Cloud Platform の設定方法

Unity から Google Cloud Platform で Google Cloud Anchor を使うたための設定手順です。
Anchor を使うためのプログラムはところどころ見かけまので、そちらを参考にしてください。

# GoogleCloudConsole の設定
## 1. ARCore Cloud Anchor API を有効にします  
![2021-05-26_12h37_29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/9776422d-a481-9c1f-a606-1146c76b4735.png)
## 2. 認証情報の作成
1. ボタン押します  
![2021-05-26_12h38_20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/a753751f-6a7d-47b3-70f3-45bab6b208e0.png)
2. 認証情報の種類の設定します  
![2021-05-26_12h38_54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/1790c83a-7cf1-da2b-8ee7-a7cb1ecebd9e.png)
3. スコープの設定は省力可なので何もしません  
![2021-05-26_12h41_24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/638085ee-00c8-cd28-3739-958acfcca1f1.png)
4. keytool で SHA-1証明書のフィンガープリントを取得します。こちらは後ほど使用します。  
   取得用のサンプルコマンドは↓  
   "tekisetsuna-path/keytool.exe" -list -v -keystore filename.keystore
5. OAuth クライアントIDを設定します  
![2021-05-26_13h00_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/ecf9c096-1d29-653e-a1e4-24b9547ebfc9.png)


# Unity の設定
1. Publish Settings の Custom Keysotore を `keytool で SHA-1証明書のフィンガープリントを取得 ` で利用したものに変更、二か所あパスワード設定します。  
![2021-05-26_15h06_29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/a4600510-632f-8c8f-0369-ee39e24fc9bf.png)
2. これだけで、後はコードをかけば Anchor を利用できます。

# おまけ
## ErrorNotAuthorized が出る場合
上記設定しても Host がうまくいかない場合（ErrorNotAuthorized）は、Unity の PlayerSettings/Player/Other Settings/Identification/Package Name の値と、GCPの認証用に作ったパッケージ名が完全に一致しているか確認してみてください。（私は com.xxxx と jp.xxxx とで間違えていて、ErrorNotAuthorized が出ていました）

![2021-05-26_14h59_16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/ea6a1d6f-5db3-392a-6bf2-50d848b2c24d.png)

![2021-05-26_14h58_57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/506075/f213c471-6a3c-3447-be68-913c84b0cc5a.png)

## ErrorHostingDatasetProcessingFailed が出る場合
GCP の内部エラーの一つです。利用端末から送っている特徴量が少なすぎて保存できないことが原因だと思われます。
一度カメラで周りを見渡してから、Host することで出なくなりますので、数回そのまま試してみてください。
（Hostを開始前から周辺情報を蓄積しているようなので、先に見回しておくのが良いみたいです。）
統計学を学ぶ

# はじめに
実業務の中で誰しもが扱うものとして`データ`があります。データといわれて誰もが思いつくのは`生データ`かと思います。`生データ`は現実で起こったものを素直に数値化しており、ある種現実そのものを表しているとは言えるかと思いますが、ただ眺めているだけでは何もわかりません（ただの数値の羅列）。

この生データから特徴を抽出し、その特徴=意味のある情報を抜き出すことでデータから何か見えてきます。この、意味のある情報を抜き出すためのツールが`統計`という手法です（という理解です）。

私個人、これまで上記したような認識はあったもののきちんと学ぶ機会がなく、業務でも何となくで使っていました。これからデータサイエンティストを目指す！というわけではありませんが、昨今のAIブームもあり基礎くらいはしっかりと理解しておいたほうが良いと思ったのでアウトプットの一環として残していきたいと思います。

# 学び方
- [ ] [完全独習　統計学入門](https://www.amazon.co.jp/%E5%AE%8C%E5%85%A8%E7%8B%AC%E7%BF%92-%E7%B5%B1%E8%A8%88%E5%AD%A6%E5%85%A5%E9%96%80-%E5%B0%8F%E5%B3%B6-%E5%AF%9B%E4%B9%8B/dp/4478820090/ref=sr_1_1?adgrpid=116233548712&dchild=1&hvadid=492491408784&hvdev=c&hvqmt=e&hvtargid=kwd-332249410022&hydadcr=13897_10914414&jp-ad-ap=0&keywords=%E5%AE%8C%E5%85%A8%E7%8B%AC%E7%BF%92%E7%B5%B1%E8%A8%88%E5%AD%A6%E5%85%A5%E9%96%80&qid=1624181768&sr=8-1)
    - まずはこれで統計学の基礎を学ぶ
    - 職場の先輩からおすすめされたので
- [ ] [【世界で37万人が受講】データサイエンティストを目指すあなたへ〜データサイエンス25時間ブートキャンプ〜](https://www.udemy.com/course/datascience365/)
    - 動画形式での受講
    - コード(python)も記載しながら学習する
- [ ] [史上最強図解　これならわかる！ベイズ統計学](https://www.natsume.co.jp/books/e/1007)
    - 一番うやむやにしているベイズ統計を学ぶ
    - かなり前に購入して積読していたので、これを機にやってみる

# まとめ
本記事では自身の決意およびメモの立ち位置で投稿しました。
上記手順に則ってしっかりと学びなおそうと思います。次回からは学習した内容をまとめていく予定です。
How to count the number of unique elements in Python, Pandas, NumPy

# Environment
|  |version  |
|---|---|
|OS      |macOS Big Sur 11.4|
|Python  |3.7.4 |
|Pandas  |1.2.4 |
|NumPy   |1.19.5|


# Python

```python
l = [1, 2, 2, 2, 3, 3, 4, 4, 4, 4, 4, 5, 5]
u = {}
for i in l:
    if i not in u:
        u[i] = 0
    u[i] += 1

print(u)
{1: 1, 2: 3, 3: 2, 4: 5, 5: 2}
```

# Pandas

```python
import pandas as pd

l = [1, 2, 2, 2, 3, 3, 4, 4, 4, 4, 4, 5, 5]
df = pd.DataFrame(l)
u = df.value_counts()

print(u)
4    5
2    3
3    2
5    2
1    1
dtype: int64
```

# NumPy

```python
import numpy as np

l = [1, 2, 2, 2, 3, 3, 4, 4, 4, 4, 4, 5, 5]
u_val, u_cnt = np.unique(l, return_counts=True)

print(u_val)
[1 2 3 4 5]

print(u_cnt)
[1 3 2 5 2]
```
空白を含む文字列を受け取る(C++)

#空白を含む文字列の受け取り方(C++)
getline(cin, 入力を受け取る変数)を使うことで解決する。

```
#include <iostream>
#include <string>
using namespace std;

int main(){
    string s;
    getline(cin, s);

    cout << s << endl;
    for(int i=0; i<5; i++){
        cout << "s[" << i << "]:" <<s[i] << endl;
    }
    return 0;
}
```
###入力
```
my name is moufu
```
###出力
```
my name is moufu
s[0]:m
s[1]:y
s[2]:
s[3]:n
s[4]:a
```
空白も1文字分になっている。
[JavaScript] HTMLを取得するメソッド三種

##はじめに
HTMLを取得する三種のJavaScriptメソッドを紹介します。
HTMLの要素を取得する方法としてはid名を指定して取得する方法と、class名を指定して取得する方法と、セレクタ名を取得する方法が存在します。
それでは一つずつ紹介していきます！よろしくお願いします。

##document.getElementById("id名")
これは引数に渡したidを持つ要素を取得することができます。

```JavaScript
//id名がhogeの要素を指定する場合
document.getElementById("hoge")
```

この場合はhogeというid名のHTMLの要素を取得することができます。

##document.getElementsByClassName("class名")
使い方はidを使って取得する方法と同じですが、このメソッドの名前のなかの**Elements**が複数形になっていることに気をつけましょう。

idとの使い分けとしては、HTMLの中で同じ名前のidは存在できないので取得する要素は一つだけになります。
しかし、classはHTMLで複数同じ名前が存在する可能性があるので、それら全ての要素を取得することができます。Elementsが複数形になっている理由も納得ですね！

```JavaScript
//class名がfugaの要素を指定する場合
document.getElementsByClassName("fuga")
```

##document.querySelectorAll("セレクタ名")
セレクタ名はCSSでスタイルを適用するために指定している要素です。CSSでスタイル適応する時はid名や、class名、はたまたタグ名を指定しますよね。つまり、先ほど紹介したメソッドを使わなくても、これで完結するのです。

id名を指定する時は、id名の直前に　**.**　をつけます。class名は　**#**　をつけます。タグ名はそのままです。

```JavaScript
//class名がfugaの要素を指定する場合
document.querySelectorAll(".fuga")

//id名がhogeの要素を指定する場合
document.querySelectorAll("#hoge")

//h1タグの要素を指定する場合
document.querySelectorAll("h1")
```

##おまけ

ちなみに、document.querySelectorAll("セレクタ名")は合致する要素を全て取得してきますが、
**document.querySelector**だと、合致する要素のうち一番はじめに見つかった要素を一つだけ取得します。

```JavaScript
//id名,class名,タグ名の指定方法は、querySelectorAllメソッドと同じ
document.querySelector("セレクタ名") 
````

##最後に
これからオリジナルアプリにこの方法でフロントを実装したいところがありまして、おさらいしてみました。
JavaScriptこれから深めていきたいと思います！！！
Unity 2020で作ったAndroidアプリからFireBaseに繋ぐ時の苦労したからまとめといた



# この記事で解決できること
Unityでアンドロイドアプリを作成していて、Google Cloud Platformに
接続する時に何故かUnity2020では送信できなくって困った。
その原因と解決策をまとめているので、一助になれば幸いっす。


# 事象
## 環境
・**MacBook Pro (13-inch, 2019, Two Thunderbolt 3 ports)**
OS：BigSur 11.2.3 
・**Unity**
version:2020.3.7f1
target Platform：Android
target SDK：22
・**FireBase**
version 6.1.1


## 問題が起こったストーリー
今まで、Unity2019（1.5f）を中心に開発をしていたが、新規アプリ開発するにあたり、Unity2020（3.7f）をPJとして採用し、開発をスタート。
アプリ開発終盤に、Google Analyticsで利用ログを簡単に分析したいとの要件に対応すべく、他PJと同じように実装した。
1. FireBaseSDKとGoogle-Service.jsonをDLしてきて
2. Importして
3. 必要な実装をして、
4. Buildして
5. 実機に乗せたら
6. **LogがFireBaseに飛ばない**

logcatしてみるとこんなエラーを吐いていた。

```
Firebase App initializing app jp.co.appname (default 1).
strlen(app_options->app_id()) && strlen(app_options->api_key())
Failed to set AppOption: ApiKey must be set.
Could not initialize Firebase App Options: ApplicationId must be set.
new_app
InitializationException:  Firebase app creation failed.
   at Firebase.FirebaseApp.CreateAndTrack (Firebase.FirebaseApp+CreateDelegate createDelegate, Firebase.FirebaseApp existingProxy) [0x000e3] in <5ef67111bf8740dfbdce3ea0f81c0968>:0
   at Firebase.FirebaseApp.Create () [0x00027] in <5ef67111bf8740dfbdce3ea0f81c0968>:0
   at Firebase.FirebaseApp.get_DefaultInstance () [0x00017] in <5ef67111bf8740dfbdce3ea0f81c0968>:0
   at Firebase.Analytics.FirebaseAnalytics..cctor () [0x00000] in <9dfcce3de97b43bcb1b4b7521e9b1f07>:0
    Rethrow as TypeInitializationException: The type initializer for 'Firebase.Analytics.FirebaseAnalytics' threw an exception.```

```
errorを読むに
・ApplicationIdがセットされていない
・故にFireBase appが初期設定ができない
とのこと。これは困った。

## 困ったので調べたこと

ひとまず、`Firebase　InitializationException unity`とかで
ggってみたが、意外と記事が出てこない（そりゃそうさ、最新のUnityのversionを使っているんだから）

調査を進めていく中で、Google-Service.jsonを元に生成したGoogle-Service.xmlが読み込まれていないことに気づく。
今度は、Build時にちゃんとXMLを読み込んでもらえるようにgradleに記載。


```gradle:mainTemplate.gradle
android {
    sourceSets {
        main {
            def unityProjectPath = $/file:///**DIR_UNITYPROJECT**/$.replace("\\", "/")
            res.srcDirs += (unityProjectPath +  '/Assets/Plugins/Android/Firebase/res/values/google-services.xml')
        }
    }
}

```

これを入れたあと、普通にBuildしたら、無事FirebaseからLogが確認できました。
流行り物に飛びつくのはやめよう。と思いましたとさ。


# 参考記事
公式のチュートリアルの中にIssueがたってました
https://github.com/firebase/quickstart-unity/issues/677
pLaTeX対応同人誌用縦書きスタイルファイル「LaTeXDojinStyle.sty」配布の件

GitHubにてpLaTeX対応同人誌用縦書きスタイルファイル「[LaTeXDojinStyle.sty](https://github.com/kuragen/LaTeXDojinStyle)」を公開しました。

### 事の発端
Wordで小説同人誌を作成するとルビ振ったらとんでもなく行間が開くとか、
そういうこまごましたところに非常に不満がありましたので、
TeXLiveを導入してそいつで作っています。

専ら小説同人誌を作っておりましたので、
1999年にトニイさんが@niftyフォーラムで発表された「B6判・文庫本(A6判)スタイルオプション」を
たまたま別の方が@niftyフォーラム亡き後[別のところで配布されていました](http://irusuka.sakura.ne.jp/archive/2008/06/tex_2.html)ので
これを使わせていただいておりました。
使い始めた時、印刷所に出すデータとしては断裁用の遊び（余白）が設定されていなかったため
どうにかこうにか遊び部分を追加して
使っておりました。

しかしB6で吉○弘文館の人物叢書みたいなのを去年作りたくなってしまって、
「どうせならスタイルファイル改造しちまわね？」となりました。
これは長年のLaTeX配布パッケージの進化に、どうも中の記述が合わなくなっている部分もあったようで、
思ったような効果が出ない、または読み込んだ別パッケージがうまく動かない、というものが見られたからです。

そして上記の「人物叢書っぽい同人誌」って要するに論文や研究書の形式を取りたいということでもあり、
美文書作成でおなじみの奥村先生が開発された、論文に必要な（普通は同人誌に要らないような）
パッケージも全込みで記述してしまっています。
※まだこれ、ダウンロードURLを含めていないので、これは書かないとと思っております。

これを全部入れ込むと、こういう同人誌が作れます。([他ページのサンプル](https://yu-gen-doh.booth.pm/items/2596907))
![LaTeX_sample.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181930/aaa86810-cefb-2041-fff3-c025666e4c2f.jpeg)

### 依存パッケージ
どうせ中身を見ていただいたら判るんですが、下記を読み込んでおります。

```tex:latexdojinstyle.sty
\usepackage{geometry}
\usepackage[dvipdfmx]{graphicx,xcolor}	% PDF用
\usepackage{pxatbegshi} % 縦組だとatbegshiでエラーが出るのを回避する
\usepackage{pxrubrica}	% from http://qiita.com/zr_tex8r/items/42466cbcbeb670a3a2dc 美しい縦書きルビを振るパッケージ
\usepackage{titlesec}	% 見出しのレイアウト変更を行うパッケージ
\usepackage{tocloft}	% 目次の体裁を変更できる
\usepackage{wallpaper} % 壁紙を作るやつ

\usepackage{lipsum}	% ダミーテキスト作成パッケージ

%脚注スタイルパッケージ
\usepackage{pxftnright}	% 縦組みpLaTeX用美しい脚注・傍注パッケージ
\usepackage{endnotesj}	% 文末脚注スタイル
\let\footnote=\endnote	% これで脚注が文末脚注になる（傍注の場合は行をコメントアウトでOK）
\usepackage{warichu}	% 割注利用

%図表・段組等を利用した変形レイアウト作成パッケージ
\usepackage{wrapfig}	% 図の回り込み用
\usepackage{picinpar}	% 文章中に枠を設けて図表を入れ込むパッケージ（非推奨のよう。picinsが推奨っぽい）
\usepackage[subrefformat=parens]{subcaption}	%図を並べて複数挿入
\usepackage{url}		% URLを直書きできる
\usepackage{multicol}	% 段組みスタイル

%フォント関係パッケージ
\usepackage[deluxe]{otf}% OTFフォント使用
\usepackage[utf8]{inputenc}% 欧文文字コードをUTF8で読む
\usepackage{type1ec}	% 欧文のリガチャ可能フォント利用時、適当なフォントサイズが用意されてない時に拡大縮小する
\usepackage{lmodern}	% 欧文フォントをLatin Modernフォントにする
\usepackage[T1]{fontenc}% フォントファイルのエンコーディングをT1エンコーディングにする（アクセント符号なんかに必要）
\usepackage{textcomp}
\usepackage{ascmac}

%表調整パッケージ
\usepackage{multirow}	%表のレイアウト調整
\usepackage{longtable}	%頁またぎの表作成
```

フォント関係は全部ONにしておく方が良いと思いますが、
あんまり表入れる人は同人作家には少ないのでは？とか、脚注が入ってる同人誌って何だよとか
全ての同人誌には不要不急のパッケージも色々組み込んであります。
要らん場合は行の先頭に%を書いてもらえればその行はコメントアウトになりますのでOFFにできます。
あと何も知らずにコンパイルしてエラーが出たら、
たぶんそいつがダウンロードしてこないといけないパッケージなので…
組み込んだ時にURL控えておけば良かった。

### 使い方
.texファイルの1行目に「\documentclass」で縦書き書籍用のtbookを指定してもらい、
2行目に\usepackageでこのスタイルを読み込んでください。

```tex:sample.tex
\documentclass[dvipdfmx,openany]{tbook}
\usepackage{latexdojinstyle}
```

ダウンロードしていただいたスタイルは、
断裁用の遊び3ミリを周囲に配した文庫本サイズがあらかじめ設定されています。
A5やB6、印刷所によって異なる遊びの寸法を設定したい場合は
37行目からサイズ設定になっていますので、こちらを変更してください。

### 今後
本を出すたびに直しながら使っている状態なので、たぶん頻繁に更新します。
なにかご要望などありましたら、ここのコメントにでも投げていただけると
いつか組み込むこともあるかも知れませんし、プルリクエスト送っていただいてもいいんですよ…?