OmniAICreator/Qiita-1.07M huggingface dataset:
python3 でバイナリデータをシリアル通信で送受信する (mac で)

# やること

mac と python3 で USB シリアルドライバなどを使ってシリアル(UART)通信します。

# やりかた

pyserial を pip でインストールして import serial すればできます。python3 ではできないという記事が検索で沢山みつかりますが、2020/02/29 時点では python3 でもできました。

# 環境

- MacOS 10.15.3
- python3.7.4
- pip 19.2.3

# 手順

## pyserial のインストール

```install.sh
$ pip install pyserial
```

## 受信

シリアルで 1 byte 受信して、10進数表記に変換して標準出力にコードは以下の通りです。

```serial_read.py
import serial
import struct

ser = serial.Serial(
      port = "/dev/cu.usbserial-XXXXXXXX",
      baudrate = 115200,
      #parity = serial.PARITY_NONE,
      #bytesize = serial.EIGHTBITS,
      #stopbits = serial.STOPBITS_ONE,
      #timeout = None,
      #xonxoff = 0,
      #rtscts = 0,
      )

while True:
      if ser.in_waiting > 0:
            recv_data = ser.read(1)
            print(type(recv_data))
            a = struct.unpack_from("B",recv_data ,0)
            print( a )
```

port の文字列は `ls /dev/cu.*` として、`usbserial-...` と出てくるデバイスの中から適切なものを選びます。コメントアウトされている部分は、デフォルトの設定のままなので、必要があればコメントアウトして適切なパラメータを設定します。

`ser.in_waiting` を参照することで、シリアルバッファに受信データがあるか(バッファに含まれるバイト数)を調べることができます。

受信したデータは、バイナリデータであっても文字列扱いになります。受信したデータがバイナリの場合は、上のコードのように`struct_unpack_from()` を使って数値に変換する必要があります。utf8 文字列の場合は decode する必要があります。いわゆる 7bit 文字列であれば、decode や unpack せずにそのまま文字列として扱えます。

## 送信

任意のバイト列 (buf) を送信します。

```serial_write.py
import serial
import struct

def send( buf ):
      while True:
            if ser.out_waiting == 0:
                  break
      for b in buf:
            a = struct.pack( "B", b )
            ser.write(a)
      ser.flush()

ser = serial.Serial(
      port = "/dev/cu.usbserial-XXXXXXXX",
      baudrate = 115200,
      #parity = serial.PARITY_NONE,
      #bytesize = serial.EIGHTBITS,
      #stopbits = serial.STOPBITS_ONE,
      #timeout = None,
      #xonxoff = 0,
      #rtscts = 0,
      )

x = [ 0x01, 0xFF, 0x02, 0xFE, 0x03]
send( x )
```

自力で flush しないと、ある程度の送信データがバッファされるまで送ってくれないようです。`ser.out_waiting` のチェックをしないと、たまに正常に送れないことがあるようです。

バイナリではなく、(英数の)文字列を送りたければ、下記でいけます。

```serial_str_write.py
x = b'abcdef'
ser.write( x )
```

utf8 文字列を送る場合は encode する必要があります。

# まとめ

C 言語や swift で書くよりは楽かなと思って調べてみましたが、通信する部分以外でやることが結構多くて、unpack とか encode あたりを調べるのに意外に苦労しました。
【超入門】RealVNC（無償版）でリモートデスクトップ

# １．やりたいこと
あるデバイスから別のデバイスのデスクトップを見たい！操作したい！
①まず、なるべく誰にでもわかるように手順を紹介します。
②つまずいた事を書いておきます。
③おまけ　スマホからVNCViewerが使える話。

# ２．RealVNC　バージョン
<サーバー側>　VNCServer / 6.7.1
<クライアント側>　VNCViewer / 6.20.113

# ３．手順
## （１）<サーバー側>VNCServerをインストール
###RealVNC VNCServer
https://www.realvnc.com/en/connect/download/vnc
OSを選んでDownloadボタンをクリック！
ダウンロードしたファイルを開いてインストール
<img width="1439" alt="スクリーンショット 2020-02-29 17.09.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332964/b777724e-3141-887c-69c9-abc9a8d9fbd5.png">

## （２）<クライアント側>VNCViewerをインストール
###RealVNC VNCViewer
https://www.realvnc.com/en/connect/download/viewer
OSを選んでDownloadボタンをクリック！
ダウンロードしたファイルを開いてインストール
<img width="1439" alt="スクリーンショット 2020-02-29 22.14.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332964/a0319cac-96c8-10f7-6beb-ec432512af24.png">

## （３）アカウントを作成
アカウント作成ページ
https://manage.realvnc.com/en/auth
①E-mailアドレスを入力してreCAPTCHAをチェックしてNextボタンをクリック
<img width="1440" alt="スクリーンショット 2020-02-29 22.26.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332964/e34fafcf-b4a4-7f1e-16b0-3e358c66365c.png">
②すると以下のページになるので、情報を入力してSign Upボタンをクリック
<img width="1440" alt="スクリーンショット 2020-02-29 22.25.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332964/18b9d2c1-8cba-7534-3269-6d8cc7bb60e9.png">
<img width="1440" alt="スクリーンショット 2020-02-29 22.38.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332964/d05e123a-42b5-76fe-ff13-ba379db21723.png">

##（４）VNCViewerでサインイン
①右上のSign inをクリック
<img width="900" alt="スクリーンショット 2020-02-29 22.22.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332964/5f5e8c53-b739-1838-9540-1e9d48c545d0.png">
②先程登録したアカウント情報を入力してSign inをクリック
<img width="465" alt="スクリーンショット 2020-02-29 22.21.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332964/10094f6f-fd11-b1f7-94e6-8681573ee9ec.png">
③同じアカウントに登録されているサーバーのリストが表示されます
<img width="901" alt="スクリーンショット 2020-02-29 22.58.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332964/c0cd0443-5c33-f40b-5486-b6dad9e56229.png">
④サーバーを選択して、サーバー固有のパスワードを入力します
⑤これでサーバー側の画面が表示されます！

# ４．つまずいた事
## サーバー側のデバイスの権限の設定
<mac(macOS Catalina バージョン１０．１５．３)>
最初、上の手順でmacに接続したら画面が真っ黒で、あれっ？てなりました。
権限がなかったみたいです。
【対処法】
環境設定→セキュリティとプライバシー→プライバシー（タブ）で以下の項目を設定します。
・画面収録
　vncagentに許可します。
　これで画面が表示されます。
・アクセシビリティ
　VNC Viewerとvncagentに許可します。
　これで画面操作ができるようになります。
<Windows(Windows10)>
Windowsの方は、私のPCでは設定の変更は必要なかったです。

# ５．スマホでもVNCViewerが使えるよ！
私はandroidユーザーなのですが、iOSでも使えるみたいですね。
PCからのアクセスと同じでアプリを開いてSign Inすれば、サーバーのリストが表示されるようになってます。
操作性は良くないですが、外出先から見られるので、PCっていうより、ラズパイとかと組み合わせて何かできたらおもしろい気がしますね！
ちなみにラズパイには標準でVNCが入ってます。初期設定では無効になっているので有効にしないと使えないですが。
その事も気が向いたら記事にします。

# ここまで読んでいただいてありがとうございます。
resourcesとresourceの使い方と違い

##ルーティング

```
Rails.application.routes.draw do
  [HTTPメソッド] '[URIパターン]', to: '[コントローラー名]#[アクション名]'
end
```
上記のようにHTTPメソッドを使うとアクションをひとつひとつ記述していかないといけないためコードが長くなり見にくかったりするためresourcesメソッドを使う

```
Rails.application.routes.draw do
  resources :リソース名
end
```
すると上記の記述だけですむ。resourcesメソッドは7つのアクションをまとめたものでテーブルに保存されるレコード１つの情報のことをリソースと呼ぶ
##onlyオプション
指定したアクションだけに限定することができる。例えばindexとnewだけを指定したい場合は以下のように記載

```
Rails.application.routes.draw do
  root to: 'コントローラ名#アクション名'
  resources :リソース名, only: [:index, :new]
end
```
##exceptオプション
指定したアクションを除外することができる。例えばshowだけを除外したい場合は以下のように記載

```
Rails.application.routes.draw do
  root to: 'コントローラ名#アクション名'
  resources :リソース名, except: :show
end
```
これで可読性が高くなる

##resourcesとresourceの違い
resourcesは7つのアクション名に対してのルーティングを自動で生成してくれる。記述するときは複数形

resourceはidを必要としないときに使う。例えばサイトにログインした状態だとユーザーに紐付くidは絞り込む必要なくなる。そのためindexとid付きのパスが生成されない。記述するときは単数形
ちなみにターミナルにてrake routesを実行するとindexがないのが確認できます。
PHP： ダブル・シングルクオートの違い

$test = "test";

シングルクオートは文字として認識してくれる
var_dump('シングル: $test');

ダブルクオートは変数として認識してくれる
var_dump("ダブル: $test");

JSの場合（変数として認識してくれる）
let test = "test"
console.log("ダブル:" + test);
MacにVagrant+VirutalBoxでLinux環境を構築する

# はじめに
macでCentOS7の環境をVagrant + VirtualBoxで構築する手順を記します。


# 構築手順

# 1. Vagrantのインストール
[公式サイト](https://www.vagrantup.com/downloads.html)のDownloadsからdmgをインストールします。


https://www.vagrantup.com/downloads.html
![screencapture-vagrantup-downloads-html-2020-02-29-00_01_13.png (455.7 kB)](https://img.esa.io/uploads/production/attachments/13671/2020/02/29/54828/1abd4ed2-4c21-4e67-ae5d-d53abed5aca5.png)

# 2. Virtual Boxのインストール
Vagrantには仮想化ソフトウェアは含まれないのでVirtual Boxをインストールします。
macではOS X hostsからインストールします。


https://www.virtualbox.org/wiki/Downloads

![screencapture-virtualbox-org-wiki-Downloads-2020-02-29-00_04_14.png (1.1 MB)](https://img.esa.io/uploads/production/attachments/13671/2020/02/29/54828/b40b2ed0-8e40-4ac6-8f96-739b6192ba2a.png)


# 3. boxを新規追加
VagrantとVirtual Boxのインストールが完了したら、環境の元となるboxを追加します
boxは https://www.vagrantbox.es/ でCentOS検索して出てきたCentOS7.0.0のリポジトリのURLをコピーして、以下のようにboxを追加します。
今回はCentOS7としてaddします。


```bash
# 例: $ vagrant box add {仮想マシンの名前} {boxのURL}
$ vagrant box add CentOS7 https://github.com/tommy-muehle/puppet-vagrant-boxes/releases/download/1.1.0/centos-7.0-x86_64.box
```

# 4. 仮想マシンを生成
まず適当なディレクトリを作ります。
今回はCentOS7を作ります。

```bash
$ mkdir CentOS7
```

ディレクトリが作成できたら、作成したディレクトリに移動してVagrantのinitコマンドを実行して
初期化します。

```bash
# 作成したディレクトリに移動
$ cd CentOS7
# 仮想マシンを初期化
# vagrant init {boxをaddしたときにつけた仮想マシンの名前}
$ vagrant init CentOS7
```

しばらくするとディレクトリ内にVagrantfileと言うファイルが生成されます。
ここに仮想マシンの設定を記述します。


# 5. Vagrantfileを編集する
### IPアドレスの設定

まず仮想マシンのIPアドレスを設定します。

```Vagrantfile
#config.vm.network "private_network", ip: "192.168.33.10"
#35行目付近に↑のような感じでコメントアウトされているので#を消してコメントアウトを解除してあげる
config.vm.network "private_network", ip: "192.168.33.10"
```

### macのファイルを仮想マシンと共有する
Vagrantfileの最後の行にあるendの直前にホストマシン(mac)と仮想マシンで共有できるに設定を記述します。

```Vagrantfile
config.vm.synced_folder"~/CentOS7","/vagrant",owner:'vagrant',group:'vagrant',mount_options:['dmode=777', 'fmode=777']
  ```

詳しい説明はしませんが、これはホストマシン(mac)側のCentOS7というディレクトリを
仮想マシンの`/vagrant`と言うディレクトリを共有してるいと言う意味です。

# 6. 仮想マシンを起動してアクセスする

Vagrantfileを書き終わったら下記のコマンドを実行して仮想マシンを起動させます

```bash
$ vagrant up
```

しばらくすると起動が完了するので下記のコマンドを実行して仮想マシンへログインします。

```bash
$ vagrant ssh
```
 
アクセスできたら`cat /etc/redhat-release`というコマンドを実行して下記と同じ結果がでたら成功です。

```bash 
[vagrant@localhost ~]$ cat /etc/redhat-release 
CentOS Linux release 7.7.1908 (Core)
```

仮想マシンからログアウトしたいときは
`exit`コマンドを実行してログアウトします。

# 仮想マシンの停止

`halt`で仮想マシンを停止します。

```bash
$ vagrant halt
==> default: Attempting graceful shutdown of VM...
```

ちゃんと停止できたか確認してみます。

```bash
$ vagrant status
Current machine states:                                    

default                   poweroff (virtualbox)            

The VM is powered off. To restart the VM, simply run `vagrant up`     
```

`poweroff`になっています。
ちゃんと仮想マシンが停止したようです。


# まとめ
・vagrant up
・vagrant ssh
・vagrant halt
この3つのコマンドで仮想マシンの起動、アクセス、停止をコマンドラインで操作できるようになりました。

あとは仮想マシンの中に各種パッケージをインストールして開発環境を構築していきます。
今回は環境構築についてなのでひとまず以上です。
【資格】医療情報基礎知識検定に合格した時の話を思い出して書いてみる

### はじめに

過去に合格経験のある資格の中から受験時のノウハウを雑多書きしてみます。
今回は医療情報技師の前哨戦とも言える医療情報基礎知識検定試験について紹介して見たいと思います。

### 試験の概要

>医療の情報化が進む今日、保健医療分野で業務に従事される方は、ほとんど例外なく患者情報、健康情報等を扱う情報システム（病院情報システム、電子カルテシステム、レセプト電算処理システム、健診情報システム等）を利用します。患者情報、健康情報等の取り扱いには、個人情報保護、プライバシー保護に特別の注意が必要であることは言うまでもありませんが、電子化された医療情報は紙媒体とは性質を異にするため、それを取り扱う人は、ＩＴの基本的素養を身につけ、医療情報システムの特質を理解し、医療情報倫理を踏まえ、ユーザとしてのセキュリティ対策を講じることができる知識をもっていることが求められます。
>「医療情報基礎知識検定試験」は、医療情報を扱う人々が共通にもっておくべき基礎的な知識を検定するものです。本検定試験は、合否判定を行って資格を与えるのではなく、受検者が自身の知識レベルを客観的に評価する機会を提供することを目的としています。業務として医療情報システムを使うことがある方、患者情報・健康情報等の処理に携わる方には、ぜひ受検をお勧めいたします。

>引用：[医療情報基礎知識検定試験のご案内][1]

出題形式としては四者択一形式、８０問（マークシート形式）。
合格基準は得点率７５％（８０問中６０問の正解）とぱっと見だけだと若干高く見えますが試験内容が割と簡単なので身構える必要はありません。

問題形式のイメージを掴みたい方は医療情報技師育成部会が公式に出している出題例を参照して見てください。
[出題例][2]


### 受験時の勉強方法

医療システム部署に所属していたり、応用情報技術者も所有していたことから、1,2ヶ月程度の勉強でもなんとかなりました。
ベースとなる知識を特に持っていない場合はもう1,2ヶ月前持って準備しておくことをお勧めします。


###使用したテキスト

+ [医療情報サブノート](https://www.amazon.co.jp/%E5%8C%BB%E7%99%82%E6%83%85%E5%A0%B1%E3%82%B5%E3%83%96%E3%83%8E%E3%83%BC%E3%83%88-%E6%97%A5%E6%9C%AC%E5%8C%BB%E7%99%82%E6%83%85%E5%A0%B1%E5%AD%A6%E4%BC%9A%E5%8C%BB%E7%99%82%E6%83%85%E5%A0%B1%E6%8A%80%E5%B8%AB%E8%82%B2%E6%88%90%E9%83%A8%E4%BC%9A/dp/4884123980/ref=pd_sbs_14_t_0/357-7375630-6359256?_encoding=UTF8&pd_rd_i=4884123980&pd_rd_r=c2c36b46-1fa4-491b-ac1e-cf3fcec09a13&pd_rd_w=pAVdQ&pd_rd_wg=WHlz3&pf_rd_p=ca22fd73-0f1e-4b39-9917-c84a20b3f3a8&pf_rd_r=HWC9AJ1KGH0CR206EHSQ&psc=1&refRID=HWC9AJ1KGH0CR206EHSQ)

とりあえずの一冊。
できれば最新版を購入しましょう。
医療情報学会が出版のため、試験範囲について広く浅くカバーできます。


+ [医療情報基礎用語集][3]



公式で配布している試験範囲の基礎用語とその解説をまとめた用語集。
試験範囲をバッチリカバーしており、元々ある程度知識があればこれだけでも充分なのではと言える内容。
入手に少々情報登録が必要ですが、非常に役立ちました。

### 使用した過去問


+ [医療情報技師試験対策wiki](https://iryoujyouhou.wiki.fc2.com)

有志の方々で試験問題をまとめられているWiki。
注意して頂きたいのは医療情報基礎知識検定ではなく、`医療情報技師検定`の過去問をまとめているWikiである点です。
難易度が全然異なりますが、医療情報技師も受験予定だったのと、内容自体は同じだよね！ということで僕はこのサイトを必死に解いていました。


### 一応こういう過去問集もあります。

+ [医療情報の基礎知識(改訂第2版): 第15~20回医療情報基礎知識検定試験問題付](https://www.amazon.co.jp/%E5%8C%BB%E7%99%82%E6%83%85%E5%A0%B1%E3%81%AE%E5%9F%BA%E7%A4%8E%E7%9F%A5%E8%AD%98-%E6%94%B9%E8%A8%82%E7%AC%AC2%E7%89%88-%E7%AC%AC15-20%E5%9B%9E%E5%8C%BB%E7%99%82%E6%83%85%E5%A0%B1%E5%9F%BA%E7%A4%8E%E7%9F%A5%E8%AD%98%E6%A4%9C%E5%AE%9A%E8%A9%A6%E9%A8%93%E5%95%8F%E9%A1%8C%E4%BB%98-%E6%97%A5%E6%9C%AC%E5%8C%BB%E7%99%82%E6%83%85%E5%A0%B1%E5%AD%A6%E4%BC%9A%E5%8C%BB%E7%99%82%E6%83%85%E5%A0%B1%E6%8A%80%E5%B8%AB%E8%82%B2%E6%88%90%E9%83%A8%E4%BC%9A/dp/4524249931/ref=pd_sbs_14_t_0/357-7375630-6359256?_encoding=UTF8&pd_rd_i=4524249931&pd_rd_r=601e3270-648f-4aaf-8a1f-b931e41b730c&pd_rd_w=xChhK&pd_rd_wg=INUv3&pf_rd_p=ca22fd73-0f1e-4b39-9917-c84a20b3f3a8&pf_rd_r=79X0FW8MG5A90SY07XZG&psc=1&refRID=79X0FW8MG5A90SY07XZG)

こちらの参考書であれば、テキストと過去問もついており、非常に役立つのではないでしょうか。
僕は出来るだけお金を使わずに受けようとしたので、購入しませんでしたが、おそらく効率的に勉強できるはず。。。



### 最後に

おそらく、こちらの検定試験を受ける方は将来的に医療情報技師を受ける予定もある方が多いかと思われます。
ちょっとレベルを上げて医療情報技師の試験内容で勉強しても役に立つかなと思います。
後ほど、医療情報技師についても記載します。



[1]:http://jami.jp/jadite/new/kiso/news-k.html
[2]:http://jami.jp/jadite/new/doc/pdf/140418kiso_mondai_2-1.pdf
[3]:http://jami.jp/jadite/new/kiso/kiso_yougo.html
React公式の「state とライフサイクル」のclassをhooksを使って関数に書き換えしてみた


#概要
classで書かれているcomponentDidMountとcomponentWillUnmountを useEffect を使って関数にしてみます。stateはuseStateを使って管理します。
実行される内容はタイマーで時間を動的に刻まれていくものです。

React公式
https://ja.reactjs.org/docs/state-and-lifecycle.html


公式からソースを抜粋

```typescript

class Clock extends React.Component {
    constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);
```
こちらを関数に書き換えます。


```tsx

const Clock: React.FC = () => {
  let [state, setState] = React.useState({ date: new Date() });
  const dateObj = { date: new Date() };
  let timerID: any;

  useEffect(() => {
    timerID = setInterval(() => tick(), 1000);
    return () => {
      clearInterval(timerID);
    };
  });

  function tick() {
    setState({ date: new Date() });
  }

  return (
    <div className="App">
      <h1>Hello, world!</h1>
      <h2>It is {dateObj.date.toLocaleTimeString()}</h2>
    </div>
  );
};

```

useEffectがcomponentDidMountとcomponentWillUnmountの役割を果たしています。

詳しくは「副作用フックの利用法」読むと良いです。
https://ja.reactjs.org/docs/hooks-effect.html
GitHubActionsで定期実行と手動実行をやってみる

サクっと定期実行を動かしつつ、たまに任意のタイミングでもスクリプトを動かせる環境をGitHubActionsで作れないかなと試してみた記録。

### GitHubActions以外の選択肢候補
下記は考えただけで、最後までうまく行くかまでは考えてない。

| 何で動かすか       |なんで選ばなかったか|
|:-----------------|:------------------|
| AWS EC2           |外部APIを利用する際にVPCの構築とかめんどくさいし、稼働費がネック |
| AWS Lambda |手動実行するのにコンソールにログイン必要？|

### なぜGitHubActionsを選んだか
- githubのアカウントがあれば使える
- crontabのようなscheduleが使える
- repository_dispatchトリガーによりCurlで実行できる

### 作ったもの
現在時刻を記載したテキストファイルをAWS S3にアップロードする
(ネットワークの利用、環境変数の動作とかをみたかった）

```golang

package main

import (
	"time"
	"os"
	"strings"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
)

func main() {
	currentTime := time.Now()
	creds := credentials.NewStaticCredentials(os.Getenv("MY_AWS_ACCESS_KEY_ID"), os.Getenv("MY_AWS_ACCESS_KEY_SECRET"), "")
	sess, _ := session.NewSession(&aws.Config{
		Credentials: creds,
		Region:      aws.String(os.Getenv("MY_AWS_REGION"))},
	)
	uploader := s3manager.NewUploader(sess)
	_, _ = uploader.Upload(&s3manager.UploadInput{
		Bucket:      aws.String(os.Getenv("MY_AWS_S3_BUCKET")),
		Key:         aws.String("s3-put-object.txt"),
		Body:        strings.NewReader(currentTime.Format("2006-01-02 15:04:05")),
		ContentType: aws.String("text/plain"),
	})
}
```

```yml
name: UpdateS3Object

on:
  schedule:
    - cron:  '0 1 * * *'
  repository_dispatch:
    types: [build]

jobs:
  execute:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - name: build
      run: docker-compose run golang go build s3-put-object.go
    - name: execute
      env:
        MY_AWS_ACCESS_KEY_ID: ${{ secrets.MY_AWS_ACCESS_KEY_ID }}
        MY_AWS_ACCESS_KEY_SECRET: ${{ secrets.MY_AWS_ACCESS_KEY_SECRET }}
        MY_AWS_REGION: ${{ secrets.MY_AWS_REGION }}
        MY_AWS_S3_BUCKET: ${{ secrets.MY_AWS_S3_BUCKET }}
      run: ./golang/s3-put-object
```
手動実行は

```shell
curl -X POST -H "Authorization: token #{Personal access token}" -H "Content-Type: application/json" -d '{"event_type":"build","client_payload":{}}' https://api.github.com/repos/:user/:repo/dispatches
```
             

### 感想
docker-composeも使えたのでわりとなんでもできそう
手動実行をcurlで実現したが、slack botとかと連携させることもできそう
upload-artifact, download-artifactを使ってビルドと実行を分離すればもっときれいになりそう
秘匿情報の扱いも簡単(githubを全面的に信用している)

この程度のスクリプトであれば、特になんの懸念もなくやりたいことができました。
今回のサンプルコードではAWSを使ったサンプルですが、定期実行自体にはAWSは関係なく、AWSアカウントの発行は不要です。
AWSやGCPの契約を必要とせずにgithubのアカウントだけでリモート環境に定期実行環境を構築できることはなかなか強みだなと思いました。
[小ネタ] 深いネストを避けるバッドノウハウ

# 深いネストを避けたい

↓例えば、こんな if 文のネスト（下の例のままだったら一文にできるじゃん、というのは置いて置いて）

```pascal:深いネスト例
begin
  if A then
    if B then
      if C then
        // 何か処理
end.
```
while 文と組み合わせると…

```pascal:バッドノウハウ
  while True do 
  begin
    if not A then
      Break;
    if not B then
      Break;
    if not C then
      Break;

    // 何か処理
    Break;
  end;
```

こんな風に書けます！
とはいえ、思いついたけど処理と関係ない while が入るから、もうまったくもって解りづらいよね！！

しかも、これが nil チェックにまつわるものであれば、今後予定されている nil 許容型で回避できるかもしれないですね！
【OnsenUI】背景色を変更する方法


OnsenUIでは、デフォルトの背景色に灰色が適用されており、これを変更する必要があります。

#タグのスタイルを変更する

`ons-page`タグのCSSは、`www/lib/onsenui/css/onsen-css-components.css`に記述されており、`.page__background`クラスにあたっているスタイルを書き換えることで背景色を変更できます。
コードヘルス - インタフェースを間違った使われ方をされないものにしよう

*この文書は[Code Health: Make Interfaces Hard to Misuse](https://testing.googleblog.com/2018/07/code-health-make-interfaces-hard-to.html)の翻訳です。*

自分のコードの中のエラーは常に避けるようにするのは当然だが、君のコードの呼び出し側が作り出すエラーについてはどうだろう？いいインタフェースデザインは呼び出し側が正しく動作するのを容易にし、間違ったことをするのを難しくする。**君のクラスに求められる不変性の維持という責任を呼び出し側に押し付けないようにしよう。**

このコードが引き起こしうる問題が分かるだろうか？

```c++
class Vector {
  explicit Vector(int num_slots);  // `num_slots`個のスロットを持つ空のvectorを作る

  int RemainingSlots() const;  // 現在残っているスロットの数を返す

  void AddSlots(int num_slots);  // vectorにさらに`num_slots`個、追加する

  // 新たな要素をvectorの最後に追加する。呼び出し側はこのメソッドを呼び出す前に
  // RemainingSlots()が少なくとも1を返すことを気をつけること。そうでない場合は、
  // 呼び出し側はAddSlots()を呼ばなくてはならない。
  void Insert(int value);
}
```


もし、呼び出し側が`AddSlots()`を呼び出すことを忘れると、`Insert()`が呼ばれたときに**未定義動作が起きるかもしれない。** このインタフェースは複雜さを呼び出し側に押し付け、実装の詳細をさらしている。

スロットを管理することは呼び出し側に見せるクラスの挙動としては適切ではなく、インタフェースとして外に出さないようにしよう。そうすることで、`Insert()`の際に必要となるスロットの追加に関する未定義動作を引き起こさないようにできる。

```c++
class Vector {
  explicit Vector(int num_slots);

  // 新たな要素をvectorの最後に追加する。必要に応じて、
  // 新たな値に対する保管場所として新たなスロットが割り当てられる。
  void Insert(int value);
}
```

コンパイラーによって規定される契約の方が実行時のチェックによって規定される契約よりも良い。さらに悪いのは、文書だけによって規定される契約だ。それは呼び出し側が正しいことをするかどうかにかかっている。

**インタフェースが間違って使われやすいシグナルとなる他の例を挙げる:**

- 呼び出し側に初期化関数の呼び出しを要求する（代案：ファクトリーメソッドを公開し完全に初期化されたオブジェクトを返す）

- 呼び出し側に特別なクリーンナップの実行を要求する（代案：オブジェクトがスコープから外れたら自動的にクリーンナップされるような言語固有の構成の仕方を使う）

- 必要なパラメータなしでオブジェクトを作成できる方法がコードにある（例えば、IDなしのユーザー）

- いくつかの値だけが有効なパラメータがある。特に、より適切な型を使うことができるにも関わらず。（例えば、`int timeout_in_mills`よりも`Duration timeout`の方がいい）

現実的に、常に誰でも間違いなく使えるインタフェースとできるわけではない。**特定のケースでは、静的解析やドキュメントに頼ることもある。** というのも、いくつかの要求はインタフェースとして表現することは不可能である。（例えば、コールバック関数がスレッド安全でなければならないなど）

強制しなくていいことを強制するのはやめよう。コードはガチガチにならないように。例えば、関数のパラメータの広範な検証は複雜性を増し、パフォーマンスを低下させる。
Railsコマンド集

# 概要
railsで使用するコマンドと用途のまとめ。
自分で混乱することが多いのでまとめました。
内容が増えてきたら項目ごとに記事を分けていこうと思っています。
間違いや疑問点があれば指摘していただけるとありがたいです。

・()で囲まれた部分は、名前など任意で指定する部分。
・大文字および複数形は慣習的なものを含む。

# Railsアプリの作成
```bash
rails _6.0.2_ new (アプリ名) # バージョン指定でアプリを作成
```

# コントローラー
## コントローラーの作成
```bash
rails generate controller (コントローラー名) (ビュー名)
#コントローラーとビューの作成、ビューに対応するアクションの生成
```
コントローラー名は**複数形で頭文字は大文字**
ビューは省略、複数の指定が可能
ビューは後から対応するフォルダで作成してもいい

## コントローラーの削除
```bash
rails destroy controller (コントローラー名) (ビュー名)
# コントローラーとビューの削除
```

# モデル
## モデルの作成
```bash
rails generate model (モデル名) (フィールド名:データ型) # モデルを作成
```
新規にデータベースを作成する場合に実行
モデルはデータベースのテーブルへアクセスするためのもの
マイグレーションファイルも作成される
モデル名は**単数系で頭文字は大文字**

## モデルの削除
``` bash
rails destroy (モデル名)
```

## マイグレーションファイルの作成
```bash
rails generate migration
```
データベースに変更を加える場合に実行
次のようにすることでマイグレーションが自動生成される
**rails generate migration add_password_digest_to_users　password_digest:string**
add_password_digest
=> マイグレーション名、自由に設定可能
to_users
=> usersテーブルを指定
password_digest:string
=> 追加するフィールド名:データ型

## データベースの作成、変更
```bash
rails db:migrate
```
マイグレーションファイルを元にデータベースを作成、変更

## マイグレーションの状況を確認
```bash
rails db:migrate:status
```
今までに適用されたファイル、まだ適用されていないファイルを一覧で表示してくれる

## データベースのマイグレーションを一つ戻す
```bash
rails db:rollback
```

## データベースの初期化
```bash
rails db:migrate VERSION=0 
#バージョンの番号を変えれば任意のバージョンに戻せる
```

## データベースの削除
```bash
rails db:drop
```

# データベースクライアント
## データベースクライアントの起動、終了
```bash
rails dbconsole # 起動 rails dbでもいい

sqlite> .quit #終了
```
sqlite>部分は使用しているデータベースによって異なる

## 全テーブルの確認
```bash
sqlite> .table
```

## テーブルの構造の確認
```bash
sqlite> .schema (テーブル名)
```
## テーブルの内容確認
```bash
sqlite> SELECT * FROM (テーブル名)
```

# railsコンソール 
## railsコンソールの起動
```bash
rails console # rails c でもいい
```

## エラ-メッセージの確認
```bash
user.errors.full_messages
```

# アノテーション
```ruby
# TODO:　あとから実装　（やること）
# FIXME　　　　　　　　（修繕）
# OPTIMIZE　　　　　　（最適化）
```
```ruby
> rails notes
* [1] [TODO] あとから実装
```
リセットCSSとは、種類や使い方

##リセットCSSとは
理解するために復習します
各ブラウザごとに(Google ChromeやSafariなど)固有のCSSをもっていて、自分で記述したCSSが本来とは違う表示になることです。(全体の横幅が大きくなったり、スペースが空いてしまったりなど)
##リセットCSSの種類(今回は2つのみ)
調べた中で使えそうなリセットCSSを載せておきます

```HTML5 Doctor Reset CSS 2.0
sanitize.css```

HTML5 Doctor Reset CSS 2.0は初学者向きで、全ての余白が消えたり、文字サイズは全て統一され、文字の太さはリセットされないなどの特徴がある
[HTML5 Doctor Reset CSS 2.0](http://html5doctor.com/html-5-reset-stylesheet/)

sanitize.cssはブラウザ周りの余白はリセットし、見出しなどの要素の上下の余白はリセットはしない。また文字のサイズと太さはリセットしていなく、スマホなどのモバイルに対応しているなどの特徴がある
[sanitize.css](https://csstools.github.io/sanitize.css/)

調べた中で使えそうな2つを載せました。他にも種類があり、オリジナルでも作れます(まだ私には難しいので作れないですが、、、)
##リセットCSSの使い方
自身のスタイルシートの一番上に貼り付ける
リセットCSSとメインのスタイルシートは分けて管理する必要がある
つまり```app/assets/stylesheets/```の中にreset.scssのファイルを作ればいい

参考にした記事
https://web-camp.io/magazine/archives/30817
WOL を使って Mac や Android から Arch Linux を起動する

Wake-On-LAN (WOL) は LAN 経由あるいはインターネット経由でコンピュータの電源を投入する機能です。この記事は Arch Linux をインストールしたサーバーを Macbook Pro や Android スマホから起動できるようにした記録です。

# 前提条件

WOL を利用するにはマザーボードや NIC が WOL に対応しており、かつ、BIOS から WOL を有効に設定している必要があります。この設定方法はマザーボードによって異なりますので、PCI Power up, Allow PCI wake up event, Boot from PCI/PCI-E など WOL を連想させる名前の設定項目を探してください。

# WoL の設定の確認

BIOS の設定に加えて Linux 上の設定も必要です。WOL の設定を確認するために `ethtool` をインストールしてください。

```console
# pacman -Syu ethtool
```

`ethtool` を使って WOL の設定を確認します。`Wake-on:` が `d` になっている場合は WOL が無効、`g` になっている場合は WOL が有効です。

```console
# ethtool enp2s0
Settings for enp2s0:
        ...
        Supports Wake-on: pumbg
        Wake-on: d
        ...
```

`ethtool` を使用して WOL の設定を変更できます。

```console
# ethtool -s enp2s0 wol g
# ethtool enp2s0
Settings for enp2s0:
        ...
        Supports Wake-on: pumbg
        Wake-on: g
        ...
```

# サーバーの設定

`ethtool` による WOL の設定は再起動で効果を失います。設定を永続化するには以下のいずれかの設定が必要です。

## netctl

```config:/etc/netctl/profile
ExecUpPost='/usr/bin/ethtool -s enp2s0 wol g'
```

## systemctl

```config:/etc/systemd/network/10-enp2s0.link
[Match]
MACAddress=00:00:00:00:00:00

[Link]
Name=enp2s0
WakeOnLan=magic
```

# クライアントの設定

## Mac OS X

HomeBrew を使用して `wakeonlan` をインストールします。

```console
# brew install wakeonlan
```

`wakeonlan` コマンドの引数にサーバーの MAC アドレスを指定すると、Ｌｉｍｉｔｅd Broadcast Address (255.255.255.255) に対してマジックパケットを送信します。このマジックパケットがサーバーに届くと、サーバーの電源が起動します。

```console
# wakeonlan 00:00:00:00:00:00
```

## Android

適当な Android アプリをインストールしてください。私は [Wake On Lan](https://play.google.com/store/apps/details?id=co.uk.mrwebb.wakeonlan&hl=ja) を使用しました。以下に設定値の例を示します。

| Field             | Value             |
|-------------------|-------------------|
| Broadcast Address | 192.168.0.255     |
| Host IP Address   | 192.168.0.16      |
| Port Number       | 9                 |
| Mac Address       | 00:00:00:00:00:00 |

Broadcast Address には Limited Broadcast Address (255.255.255.255) あるいは Directed Broadcast Address (e.g. 192.168.0.255) のいずれかを指定します。両者の違いについてはここでは触れません。ほとんどの環境ではどちらを指定しても正常に動作すると思います。

Host IP Address にはサーバーの IP アドレスを指定します。本来、WOL にはこの設定は不要なはずですが、アプリに依っては起動に成功したかを確認するために設定が必要な場合があります。

Port Number は WOL のマジックパケットを送信するポート番号です。通常は UDP の 7 番ポート (Echo Protocol) あるいは 9 番ポート (Discard Protocol) を使用します。

Mac Address は対象のサーバーの MAC アドレスです。


# 参考文献

* [Wake-on-LAN ArchWiki](https://wiki.archlinux.jp/index.php/Wake-on-LAN)
Gitでのログインを少しでも楽にして、ついでに複数アカウントを管理する冴えたやり方

Git始めました。初心者ですがまぁ備忘録として。
入門としてSSHでのログインや取りあえずclone,add,commit,push出来るようになると、楽をしたくなってきますよね？
僕はなりました。
あと複数アカウントを管理する必要が出来たりしますよね。
僕はなりました。
というわけで方法の備忘録的なメモです。

そもそものGitの基本的な使い方はこちらの記事が参考になります。
[【GitHub超初心者入門】この前初めてGitHubを使い始めたエンジニア見習いが書くGitHubの使い方と実践～とりあえず一緒に動かしてみようぜ！～](https://qiita.com/nnahito/items/565f8755e70c51532459)
[今日からはじめるGitHub 〜 初心者がGitをインストールして、プルリクできるようになるまでを解説(エンジニアHub)](https://employment.en-japan.com/engineerhub/entry/2017/01/31/110000)

##少しでも楽にログインする。
最初のSSH鍵の作り方や、鍵のGitへの登録なんかは主にこちらを参考にさせていただきました。
あとどこのサイトでも紹介されてるconfigファイル…Win8.1だからかは分かりませんが、作らなくても動く？configファイルの必要性の有無は理解できてないです。必要だったらごめんなさい。
[GitHubでssh接続する手順~公開鍵・秘密鍵の生成から~](https://qiita.com/shizuma/items/2b2f873a0034839e47ce)
[[Windows 10] Git BashでGitHubにSSH接続](https://qiita.com/coffee_g9/items/e1b9ab28cfa54f854308)
[GitHubにssh接続できるようにする](https://qiita.com/0ta2/items/25c27d447378b13a1ac3)

さて、これで鍵を作ってログインは出来ます。しかしログインする度に

```:command
0. スタートメニューからGit-bashを起動
1. cd 作業フォルダ　#作業するディレクトリへ移動
2. ssh-agent bash　#エージェントの起動
3. ssh-add 鍵への相対パス/鍵の名前　#使う鍵の指定
4. ssh -T git@github.com　#接続の確認
```

って打ち込むの面倒な上にそもそも覚えられないんですよね…

####Step0,1
そこでまずステップ0,1の省略手順としてbatファイルを作りました。
まずはgit-bash.exeがある場所(標準ではProgram File中のGitフォルダですかね？)に環境変数でPathを通します。
そして以下のバッチファイルを作ります。これについては作業フォルダのトップにでも置いておけばいいでしょう

```bash:openGitBash.bat
cd 作業フォルダへのパス。絶対パスでの指定です。C://～で始まるやつですね
git-bash
```

これを実行してやれば一発です。スタートメニューからGit-Bashを起動してcdで移動して…という手間が省けます。
参考資料はこちら
[Windows エクスプローラからBashのコマンドウインドウを開く](https://qiita.com/ysks/items/9dba7bda6378c34939d7)

####Step2,3,4
次にエージェントを起動して鍵を選んでパスワードを入力して接続を確認して…。コマンド覚えてられんわ！
と言うわけで本当はバッチファイル一発叩くだけで～みたいなのを目指したんですが、どうやらGit bashは対話型のインターフェースみたいで複数行のコマンドの実行はしてくれない？みたい？なので。
バッチファイルを3つ作りました。~~ごり押し~~

```:con1
ssh-agent bash
```

```:con2
ssh-add 鍵への相対パス/秘密鍵の名前
```

```:con3
ssh -T git@github.com
```

これらをやはり作業フォルダのトップに置いといてあげれば、先ほど起動したGitBashで

```bash:command
sh con1
sh con2
sh con3
```

とやってあげるだけで接続できました。また鍵を指定するcon2を複数種類用意してあげれば、実行するcon2を指定することで接続するアカウントを使い分けることができます。

###ログインする時にconfigファイルを編集する
毎回する必要はないです。
初めてGitに接続するときにやったこれ。

```bash:command
git config --global user.name "ユーザー名"
git config --global user.email "E-メールアドレス"
```

これをアカウント変更の時に再設定してあげればOKです。ここの設定が合ってないとエラーが出る~~…はず。なんかやってると変更してないのにpush出来たりしてるの意味わからん…~~


##終わりに
というわけでGitbashを立ち上げる度に求められる入力を減らすことでプログラマの腱鞘炎を少しでも防ぐ記事でした。
Gitは便利だからこそ多くのプログラマに支持されていると思うので、何とか基本的な使い方ぐらいはちゃんと身に着けたいですね。
最後までご覧いただきありがとうございました。
サードパッケージを使用したGoのアプリケーションをHerokuにデプロイする v2


以前書いた記事がGoのアップデートと共にゴミ記事と化したので別アプローチを記録
[サードパッケージを使用したGoのアプリケーションをHerokuにデプロイする](https://qiita.com/matopenKW/items/d1798a2f60bffdf719a8)

結論から言うとgovendorをやめて、go modulesを使用する

# Goでアプリケーションを作成
Goアプリケーションの作り方は前回の作り方とほぼ同じ

```:main.go
package main

import (
	"github.com/gin-gonic/gin"
)

type User struct {
	Name string
	Age  int
}

func main() {
	router := gin.Default()
	// css、js　などの静的ファイルを読み込む場合。今回は使用しない。
	// router.Static("/assets", "./assets")

	router.LoadHTMLGlob("templates/*.html")

	router.GET("/", handler)

	router.Run()
}

func handler(ctx *gin.Context) {

	user := User{"User", 20}

	ctx.HTML(200, "index.html", gin.H{
		"user": user,
	})
}
```

```:templates/index.html
<!DOCTYPE html>
<html>
    <div>
        <p>Name: {{.user.Name}} </p>
        <p>Age: {{.user.Age}} </p>
    </div>
</html>
```

# go modulesを使用してサードパッケージを追加
go modulesはGo 1.11が入っている場合は入っているそうですが、ない場合はinstallする

下記のサイトが参考になりました！
[Go言語の依存モジュール管理ツール Modules の使い方](https://blog.mmmcorp.co.jp/blog/2019/10/10/go-mod/)


```
// 初期化
$ go mod init
go: creating new go.mod: module Heroku
```
go mod initが完了するとgo.modファイルが作成されます。

```:go.mod
module Heroku

go 1.13
```
初期化が完了したら、依存ファイルのダウンロードを行います。

```
// 依存ファイルをダウンロード
$ go get -v
Heroku
```

go.modファイルが更新され、新たにgo.sumファイルが作成されます。

```:go.mod
module Heroku

go 1.13

require github.com/gin-gonic/gin v1.5.0

```

```:go.sum
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
〜〜以下、依存ファイルがたくさん〜〜〜〜〜〜〜〜

```

作成したgo modluesをpushする

```
$ git add -A .
$ git commit -m "init"
[master 81579d9] init
 2 files changed, 44 insertions(+)
 create mode 100644 go.mod
 create mode 100644 go.sum
```

Herokuのアプリを作成→デプロイ
作成手順は以前のものと変わりません。

```
$ heroku create
Creating app... done, ⬢ pure-harbor-40656
https://pure-harbor-40656.herokuapp.com/ | https://git.heroku.com/pure-harbor-40656.git
$ git push heroku master
```

でけた

## 所感
今回の対応はGoと使用しているサードパッケージのアップデートによる影響でした。（詳細は下記記事）
[govendorで依存関係のファイルが取得できないエラーについて](https://qiita.com/matopenKW/items/8004eca7a6ccc46ead89)

今回のケースから
技術者は変わっていく技術にちゃんとキャッチアップしていかなきゃ行けない。
調べる時の単語のチョイス、範囲、絞り方がとても重要だなと感じました。

後、英語はちゃんと勉強しようね

## 参考サイト
[Go言語の依存モジュール管理ツール Modules の使い方](https://blog.mmmcorp.co.jp/blog/2019/10/10/go-mod/)
[サードパッケージを使用したGoのアプリケーションをHerokuにデプロイする](https://qiita.com/matopenKW/items/d1798a2f60bffdf719a8)
Pythonでマージソートを書いてみたメモ

マージソートについて自分用にメモを書いてみました。
# マージソートとは
- 分割統治法に基づく高速なソートアルゴリズムで、大きなデータサイズに対応できる。
- 計算量はO(nlogn)
  - logn個の階層があり、各層ごとの計算量はO(n)であるため。
- ソートしても同じ値の順序が変わることのない安定なソート
- 一時的にデータを保存するメモリが必要

# コード
```python:marge_sort.py
def merge(A, left, mid, right):
    
    L = []
    for i in range(mid - left):
        L.append(A[left + i])
    L.append(1000)    # 必ずソートする数よりも大きい数にする 
    
    R = []
    for i in range(right - mid):
        R.append(A[mid + i])
    R.append(1000)    # 必ずソートする数よりも大きい数にする
    
    i = j = 0
    for k in range(left, right):
        if L[i] <= R[j]:
            A[k] = L[i]
            i += 1
        else:
            A[k] = R[j]
            j += 1
    
def merge_sort(A, left, right):
    if left+1 < right:
        mid = (left + right) // 2
        merge_sort(A, left, mid)
        merge_sort(A, mid, right)
        merge(A, left, mid, right)
    return A

print(merge_sort([3, 1, 10, 2.5, 11, 3, 21, 4, -1], 0, 9))
# [-1, 1, 2.5, 3, 3, 4, 10, 11, 21]
```

今回は1000以下の数を昇順にソートできる
1000は適当に定めたので、大きくすればもっと大きな数でもソートできる
総呼び出し回数をうまくかけなかった…


# 参考
[C言語でマージソート](https://qiita.com/omu58n/items/2aa3c751cfb10cdbbb43)
[ソートアルゴリズムと Python での実装](https://qiita.com/suecharo/items/30f5d817da4c948c3be6)
[【Unity】ソートアルゴリズム12種を可視化してみた](https://qiita.com/r-ngtm/items/f4fa55c77459f63a5228)
FILTERを使ってテーブルを加工する


前回の、[RANGE関数をさらに拡張し組込む](https://qiita.com/matumoto_onga/items/b150c14c7c58b9c88839)のQL_INIT関数を使ってテーブル評価関数を定義します。
抽出元のテーブルの２次元配列の行数と、評価で返される二次元配列の行数は一致しなければなりません。
タイトル行も残すので、一行目は必ず数字の１です。


```vb
Function EV(V)
    EV = Evaluate(CC("1*(", V, ")"))
End Function

Function EVT(V, Optional S = "")     ' evaluate Table
    On Error Resume Next
    
    S = QL_INIT(EV(V), "1")
    S(0, 1) = 1 ' タイトル行

    EVT = S
End Function

' CC は　CONCAT互換関数です。

Function CC(ParamArray AR())
    On Error Resume Next
    Dim S: S = ""
    Dim I: For I = 0 To UBound(AR)
       S = S & AR(I)
    Next I
    CC = S
End Function
```

上記関数を使用して、

(BA2) =FILTER(QL_INIT("M02N_[日付,出庫,済,依頼]"),EVT("M02N_[済]=0"))

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184069/dca83ac1-d875-eb48-a001-1e6f748a3b61.png)

当然、複数条件も可能です。

(BF2) =FILTER(QL_INIT("M02N_[日付,出庫,済,依頼]"),EVT("(M02N_[済]=0) * (M02N_[出庫]>100)"))

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184069/cbd5b058-f4cb-a802-2cf3-4c51b3e832da.png)
TypescriptでHuobotする

## 概要
なんか今更感ありますが、`hubot`です。

async/await使いたくなったとかいろいろあって、`hubot`を`typescript`でかけるようにしてみたいと思います。

あと、せっかくなので`eslint`と`prettier`を導入して、ちゃんとしたコードがかけるようにします。

## やったこと
### 1. yarn init
`package.json`を作ります

```sh
yarn init
```

### 2. yarn add typescript
`typescript`をインストール

``` sh
yarn add -D typescript
```

  
### 3. tsconfig.jsonを追加
`src`にソースを配置します。
コンパイル結果は`hubot`の標準？だと思われる`scripts`ディレクトに出力します

``` json:tsconfig.json
{
  "compilerOptions": {
    "sourceMap": true,
    "target": "es5",
    "outDir": "./scripts",
    "rootDir": "src"
  }
}
```

### 4. package.json書き換え
`package.json`に以下を追加して、`yarn build`でコンパイルできるようにします

``` json:package.json
  "scripts": {
    "build": "tsc"
  }
```

### 5. `eslint`と`prettier`を設定(linterが不要なら不要です）
エディタを設定すれば、書きながらでも怪しいコードを指摘してくれるし、保存時にprettierが動くようにすれば、コードの品質を一定程度保ってくれてありがたいです。

インストール

```sh
yarn add -D @typescript-eslint/eslint-plugin \
         @typescript-eslint/parser \
         eslint \
         eslint-config-prettier \
         eslint-plugin-prettier \
         prettier
```

`.eslintrc.js`を作成

``` javascript:.eslintrc.js
module.exports = {
  extends: ["eslint:recommended", "plugin:prettier/recommended"],
  plugins: ["@typescript-eslint", 'prettier'],
  parser: "@typescript-eslint/parser",
  parserOptions: {
    sourceType: "module",
    project: "./tsconfig.json",
  },
  env: {
    browser: true,
    node: true,
    es6: true,
  },
  rules: {
    "no-console": "warn",
    "@typescript-eslint/adjacent-overload-signatures": "warn",
    "@typescript-eslint/no-unnecessary-type-assertion": "error",
  }
}
```

`.prettierrc`を追加する

``` json:.prettierrc
{
  "singleQuote": true,
  "semi": false
}
```

### 6. hubotを導入する
ここまでで、typescriptが使えるようになっているので、いつもの調子で`hubot`を導入します。

`yo`をglobalにインストール

```sh
npm i -g yo generator-hubot
```

hubotをインストールします。
`package.json`を`overrite`するかきかれるので`n`にしましょう

```sh
yo hubot
```

`scripts`ディレクトリはコンパイル結果を出力するので`.gitignore`に登録しておきます。

```add:.gitignore
+ scripts
```

`bin/hubot`を修正して、実行前に`typescript`をコンパイルするようにします。

```sh:bin/hubot
#!/bin/sh

set -e

yarn
yarn build
export PATH="node_modules/.bin:node_modules/hubot/node_modules/.bin:$PATH"

exec node_modules/.bin/hubot --name "tsbot" "$@"
```

### 7. src/main.tsを追加

その前に`hubot`の`types`をインストールします

```sh
yarn add -D @types/hubot
```

`src/main.ts`を作成します。
これがメインのファイルになります。

``` ts:main.ts
import * as hubot from 'hubot'

module.exports = (robot: hubot.Robot<any>): void => {
  robot.respond(/hello/i, (msg: hubot.Response<hubot.Robot<any>>) => {
    msg.reply('world!')
  })
}
```

### 8. 実行します
ここまでで、実行できます。

```sh
bin/hubot

tsbot> tsbot hello
tsbot> Shell: world!

tsbot>
```

あとは、すきな機能を実装するだけです。
`async/await`も使えて、型もつかえていいかんじです！
Cookie VS Session

# 概要

似てるけど、少し違うCookieとSession
大体、データを保存するのは分かりますが、
具体的にCookieとSessionは、何ものか？何の差があるのか？を調べました。

# Cookie

Cookieは、
HTTPの一種で、ユーザーがどのようなウェブサイトを訪問する場合、
そのサイトが使用しているサーバーから、ユーザーのパソコンに保存される
小さな**履歴情報ファイル**です。

HTTPクライアントの状態情報を、クライアントのPCに保存して
必要に応じて情報を参照したり、再利用することができます。

## Cookieの特徴

- 名前、Vaule、有効期限（保存期間）、パス情報で構成
- クライアントの合計300個のクッキーを保存することができる。
- 1つのドメインごとに20個のクッキーを持つことができる
- 1つのクッキーは4KB（=4096byte）まで保存可能

## Cookieの動作

<img width="555" alt="2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/421654/a9fe075e-bcb4-898e-9636-989715aa503d.png">

1. クライアントがページを要求する。（ユーザーがWebサイトにアクセス）
2. Webサーバーは、クッキーを生成する。
3. HTTPヘッダーにクッキーを含ませて応答
4. ブラウザが終了されても、クッキーの有効期限がある場合は、クライアントで保管している（ローカルPCに保存）
5. 再びサーバーに要求した時、要求と一緒にクッキーを送信する。
6. 同じサイトの再訪問時のクライアントのPCに対応するクッキーがある場合には、リクエストページと一緒にクッキーを送信

# Session

一定時間の間のようなユーザー（ブラウザ）からの着信を一連の要求を1つの状態で見て、
その状態を一定に維持させる技術です。

ここで、一定時間は、訪問者がWebブラウザを介してWebサーバに接続した時点から、
Webブラウザを終了して、接続を終了時点です。

## Sessionの特徴

- WebサーバーにWebコンテナの状態を維持するための情報を格納する。
- Webサーバーに保存されているクッキー（=セッションクッキー）
- ブラウザを閉じるか、サーバーからのSessionを削除した場合にのみ、削除がされるので、Cookieより比較的安全がいい。
- 保存データに制限がない。
- 各クライアント固有のSession IDを付与する。
- Session IDでクライアントを区別して、各クライアントのニーズに合ったサービスを提供

## Sessionの動作

<img width="555" alt="5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/421654/635bbf9d-de85-ebf3-e328-8b29eed34333.png">

1. クライアントがページを要求する。（ユーザーがWebサイトにアクセス）
2. Webサーバは、アクセスしたクライアントのRequest-HeaderフィールドインCookieを確認して、クライアントがそのSession IDを送信したことを確認する。
3. Session IDが存在しない場合、サーバはSession IDを生成してクライアントに返す。
4. Webサーバーからクライアントへの返したSession IDをCookieを使ってサーバに保存する。
5. クライアントは再接続時には、このCookieを利用して、Session ID値をサーバーに転送

# Cookie VS Session

|        |    Cookie    |    Session    |
|:------:|:------------:|:-------------:|
|保管場所|クライアント|サーバー|
|保存形式|テキスト|Object|
|有効期限|Cookie保存時の設定| 正確な時点わからない|
|容量制限|ドメインごとに20個| 容量制限なし|
長い内包表記をなんとかする方法

## 長い内包はしんどい

Pythonでは一般に、コレクションは内包表記で生成する（と思う）。

しかし少し複雑になると、内包表記は読むのがしんどい。

```python
# Fizz Buzzリストを無理やり内包で
fb = ["Fizz Buzz" if i % 15 == 0 
      else "Fizz" if i % 3 == 0 
      else "Buzz" if i % 5 == 0 
      else i 
      for i in range(30)]
```

これなら、for文を書いた方が見やすい。

だが初期化前のオブジェクトを露出させたまま、少しずつ変更を加える書き方は、（関数型嗜好が強いと）なんとなく罪悪感がある。

```python
fb = []
for i in range(30):
    if i % 15 == 0:
        fb.append("Fizz Buzz")
    elif i % 3 == 0:
        fb.append("Fizz")
    elif i % 5 == 0:
        fb.append("Buzz")
    else:
        fb.append(i)
```

どうするか？

## ジェネレータ+コレクタ

yieldでジェネレータを定義し、それを元にコレクションを作る書き方が可能。

```python
def _fb():
    for i in range(30):
        if i % 15 == 0:
            yield "Fizz Buzz"
        elif i % 3 == 0:
            yield "Fizz"
        elif i % 5 == 0:
            yield "Buzz"
        else:
            yield i

fb = list(_fb)
```

## もっと簡潔に

↑も悪くはないが、ジェネレータを定義した後、list関数を通し、変数に代入する手順が煩雑。

また、listにするのを忘れ、イテレータを直接変数で受けてしまうとバグの温床になりうる。

yieldを使った定義がそのままリストの定義として解釈されてほしい。

デコレータを使えば実現できる。

```python
def comprehension(collector):
    def ret(func):
        return collector(func())
    return ret

# 以下を実行すると、変数「fb」にリストが代入される。
@comprehension(list)
def fb():
    for i in range(30):
        if i % 15 == 0:
            yield "Fizz Buzz"
        elif i % 3 == 0:
            yield "Fizz"
        elif i % 5 == 0:
            yield "Buzz"
        else:
            yield i
```

## 元ネタ

[funcy](https://github.com/Suor/funcy)というライブラリにあるcollectingというデコレータが第一の元ネタ。ジェネレータ関数を、リストを返す関数に変える。これを使うとFizz Buzzは以下のように書ける。

```python
from funcy import collecting

@collecting
def _fb():
    for i in range(30):
        if i % 15 == 0:
            yield "Fizz Buzz"
        elif i % 3 == 0:
            yield "Fizz"
        elif i % 5 == 0:
            yield "Buzz"
        else:
            yield i

fb = _fb()
```

でも一旦関数を定義する手間が面倒。

Racketの[for/list](https://docs.racket-lang.org/reference/for.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._for%2Flist%29%29)みたいに書ければ……と思って、デコレータで関数を返さない解法を思いついた。
非同期通信


console.logの使い方
.jsに記述し、検証のConsoleで確認

ajax
urlにはAjaxでデータを送りたいアクションのパスをrake routesなどで調べて指定

url,FormDateの取得、記述
var formData = new FormData(this);
var url = $(this).attr('action');
FormDateとセット
processData: false,
contentType: false

コントローラーにrespond_toを使用してJSON形式のリクエストに対してのレスポンスを返せるようにする
respond_to do |format|
  format.json

jbuilder
jbuilderを使用して、作成したメッセージをJSON形式で返す
json.カラム　インスタンス変数.カラム
json.カラム　インスタンス変数.カラム
Blazor(.NET CORE)でMySQLを使用する

## 環境
VisualStudio2019
.NET CORE 3.1
MySQL8.0

## 手順
### Blazorアプリの作成

![blazor-mysql1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447009/8ba70653-e502-5f6a-af80-68bfb21541a0.png)

 ![blazor-mysql2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447009/05eec3a1-bfff-1fb4-ea2b-12d884530f9d.png)


今回は認証を個別のユーザーアカウントにしておきます。
![blazor-mysql3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447009/9353a36e-228c-db3d-ac5b-80c598e43786.png)

### SQLServer用のMigrationファイルを削除します。
![blazor-mysql4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447009/529b89df-efa7-d006-9501-5a8f48b6f981.png)

### appsettings.jsonをMySQL用に書き換え

```appsettings.json
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost;user id=xxxx;password=xxxx;database=xxxx"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}
```

### NuGetパッケージの管理から「Pomelo.EntityFrameworkCore.MySql」をインストールします。

![blazor-mysql6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447009/05146983-af97-ee12-89c0-446f705b2681.png)

###「"UseSqlServer"の定義が含まれておらず...」のエラーが発生するので、UseSqlServerを「UseMySql」に変更
[変更前]
![blazor-mysql9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447009/8047ac7e-55d9-c07a-e462-b98965942636.png)

[変更後]
![blazor-mysql10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447009/fd55f9bb-7a4c-622e-f57b-4793586a2a4c.png)

### パッケージマネージャーコンソールで下記コマンドを入力

```PM
add-migration 'identity'
```

![blazor-mysql11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447009/2167b169-38e1-1203-f152-91262dba9b4d.png)

### 続けて下記コマンドを入力

```PM
Update-Database

```

### アプリを起動してユーザー登録を行う
データが登録されていれば完了

![blazor-mysql13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447009/20c04b8f-e371-afb6-cc43-2289dba7cb37.png)


### 参考記事

https://medium.com/@cptullio/net-core-3-blazor-app-and-security-with-identity-and-mysql-61b12dc7523
govendorで依存関係のファイルが取得できないエラーについて


以前、govendorを使用してHerokuにデプロイするやり方を記事にしました。
[サードパッケージを使用したGoのアプリケーションをHerokuにデプロイする](https://qiita.com/matopenKW/items/d1798a2f60bffdf719a8)

１２月くらいにまたHerokuにアプリケーションをデプロイしようとした時にエラーが起きた。
書いた記事が１ヶ月でゴミ記事と化した…


## 事象
とりまHerokuのエラーログ抜粋

```
remote: -----> Fetching any unsaved dependencies (govendor sync)
remote: -----> Running: go install -v -tags heroku . 
remote: vendor/github.com/gin-gonic/gin/binding/default_validator.go:11:2: cannot find package "github.com/go-playground/validator/v10" in any of:
remote:         /tmp/tmp.ZfAOSHHFNh/.go/src/Heroku/vendor/github.com/go-playground/validator/v10 (vendor tree)
remote:         /app/tmp/cache/go1.12.16/go/src/github.com/go-playground/validator/v10 (from $GOROOT)
remote:         /tmp/tmp.ZfAOSHHFNh/.go/src/github.com/go-playground/validator/v10 (from $GOPATH)
remote:  !     Push rejected, failed to compile Go app.
remote: 
remote:  !     Push failed
remote: Verifying deploy...
remote: 
remote: !       Push rejected to pure-harbor-40656.
remote: 
To https://git.heroku.com/pure-harbor-40656.git
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'https://git.heroku.com/pure-harbor-40656.git'
```

エラーの部分は
***cannot find package "github.com/go-playground/validator/v10" in any of:***

英語力が皆無な私でも言っている意味は分かる
***github.com/go-playground/validator/v10***
のパッケージがないのだ

なーんだ、パッケージがないのかぁ……
そんな筈はない…
govendor fetch はちゃんとできていたはず

原因を探るため vendor.json を確認したところ

```:vendor.json
{
	"comment": "",
	"ignore": "test",
	"package": [
		{

　　　　〜〜割愛〜〜〜〜 

		{
			"path": "github.com/go-playground/validator/v10",
			"revision": ""
		},

　　　　〜〜〜〜〜〜〜〜
}

```
 
revisionが空ってどういこと！？取れてないのか？？

１１月から変えた事と言えばGoのバージョンをあげた事
上記エラーについてあまり情報が転がっていなかったのでパッケージ元を調査しました。

https://github.com/go-playground/validator
<img width="1348" alt="スクリーンショット 2020-02-29 21.37.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396921/72e145f0-ed4c-42ae-4069-ad1c75fbe232.png">

Go modulesに移行したとの事

えぇ？いきなり？？
確かにGoは1.11からgo module を使用する様に促しています。
https://blog.golang.org/using-go-modules

いや、でもHerokuの公式サイトはgovendorって書いとるやん…

## issues
上記エラーは困っている人はたくさんいたらしく、issueも上がっていました。
https://github.com/go-playground/validator/issues/546

苦手な英語をとにかく翻訳（Google頼り）
ざっと流れを説明すると（かなり主観）

エンジニア「Dockerfileとかでエラー起こってるんやけどー？」
開発者様　「バージョンあげて試してみて！！」
エンジニア「validatorがgin-gonic/ginに依存してるからまだ取得できないよー」
開発者様　「go modulesでやって欲しいですー」
エンジニア「govendorでやってるんだよね…」←私と同じ
開発者様　「v10のアップデートはgopkg.inからgo modulesへのバージョン管理の切り替えで…go modulesを使用していない場合はv9を使用している場合はv10を参照する様にしています。」
開発者様　「古いバージョン管理ツールがgo modulesとの互換性がないというコミュニティの悪い状態を解決するためgo modulesを使用することをオススメします。 go moduleにコミュニティが破壊されたよー（泣」

Goのアップデートに対しての処置だったのですね。
なんにせよ、ginを使用している場合はgo modulesに切り替える必要がありそうです。

Herokuもgo modulesでデプロイは可能なので、そちらを使うのをオススメします。

## 教訓
Goは日本語の記事やドキュメントが少なくて調べるのに苦労しました。英語も超超超苦手なので勉強するいい機会になりました…
Java使ってる時はライブラリは自分でインストール→読み込み→実行だったので、何も考えずにgo getしていた事で気づくのが遅れた感じですかねぇ…
やっぱり自分で使うものはある程度使い方、影響度を理解した上で使わないと！（今更）

## 参考リンク
[Go Modules](https://qiita.com/propella/items/e49bccc88f3cc2407745)
[go-playground/validatorのGithub](https://github.com/go-playground/validator)
[例のissues](https://github.com/go-playground/validator/issues/546)
Vue.jsのインストール・プロジェクト作成

# いきなりNuxt.jsに手を出すのは厳しい！？
ある日、
自分でかっこいいWebサイトやWebアプリを作るれるようになるぞ！
Nuxt.js を使いこなせるようになるぞ！
と決意した。
そして、いろいろ調べていると、

Nuxt.jsを使いこなしたいならまず **Vue.js** を勉強しなさい。

と言っている人をたくさん見つけた。
たしかに、Nuxt.jsでとりあえずプロジェクトを作ってみたり、
コードを眺めていても、よく分からなくて混乱した。


ここは素直に **Vue.js** の勉強から始めることにした。

# 今回やること
* Vue.js をインストールし、プロジェクトを作ってサンプルを実行してみる！

# 対象
どんな人向けか？ どんな人向けじゃないか？ を簡単に。

* Vue.jsでプロジェクトを作成するまでの手順を知りたい方、おさらいしたい方。
  * Vue.jsとは？等の説明はありません。

# 環境
* Windows 10

# いろいろインストールする
すぐにでもプロジェクトを作りたいところだが、その前にいろいろインストールしなくちゃいけない。

###【Node.jsをインストールする】

* 以下のアドレスにアクセスしてNode.jsのインストーラをダウンロードする（最新版ではなくLTSのものを選択する）
https://nodejs.org/ja/

* ダウンロードしたインストーラ（～.msi）をダブルクリックする（特に理由が無ければ全部デフォルトでOK）
* インストールが完了したら、Node.jsがちゃんと動くか確認する（コマンドプロンプトとかで）

```
node --version
```

* Node.jsをインストールすると、npmも自動でインストールされているはずなので、確認する

```
npm --version
```

###【Vue CLIをインストールする】

* 以下のコマンドで「Vue CLI」と「Vue cli-service-global」をインストールする（どっちもVue.js開発に必要）

```
npm install -g @vue/cli
npm install -g @vue/cli-service-global
```

# プロジェクトを作る
準備は完了！さっそくプロジェクトを作ってみる！

* プロジェクトを作りたいディレクトリに移動する

```
cd [プロジェクトを作りたいディレクトリ]
```

* プロジェクトを作る（これも特に理由が無ければデフォルトでOK）

```
vue create [プロジェクト名]
```

これだけ！
~~あれ？記事にしてまとめる程のことじゃなくない？~~

# サンプルを実行する
ちゃんとプロジェクト作成できたかの確認も含めて、サンプルを実行してみる！

* プロジェクトの中に移動する

```
cd [プロジェクト名]
```

* サンプルを実行する

```
npm run serve
```

* 以下のようなテキストが出力されれば成功！

```
App running at:
  - Local:   http://localhost:8080/
  - Network: http://xxx.xxx.xxx.xxx:8080/
```

* `http://localhost:8080/`にアクセスして画面を確認してみる（下の画像のようなページが表示されるはず）
![npm_run_serve.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558315/bb3a4045-8c81-d56f-f21a-13725b1d4c91.png)

終わり！

# 感想

Vue.jsのプロジェクト作成はびっくりするくらい簡単だった。
もろもろのインストールもつまずくこと無くすんなり！

作ったプロジェクトの中にはなんかいろいろ入ってる。。。
よし、調べよう。
コマンドラインから日本語コメント付きコードをカラー印刷する

# 目的
- 日本語のコメントの入ったコードをコマンドラインからカラーで印刷する。
- 調べてみるとあんまりいい感じのツールはないようです。`enscript`はコードのカラー化ができますが残念なことに日本語がダメみたい。`a2ps`は日本語はパッチが当たっているようですが、カラー化ができるのかすぐ見つからず、情報も古いのでなんだか面倒だとおもちゃいました。
- `vim`のコマンド`:hardcopy`でカラーになっていい感じで印刷できますが、こちらも日本語が化けます。
- そこで目につけたのが`vim`の`:TOhtml`でhtmlにしてみるといい感じでブラウザで表示できました。これならコマンドラインから変換して印刷できそう。

# 環境
- MacOSX Darwin Kernel Version 17.7.0: MacBookPro11,1 Darwin
- wkhtmltopdf  0.12.5 (with patched qt)
- VIM - Vi IMproved 8.1 (2018 May 18, compiled Aug  3 2019 18:07:03)
- GNU bash, バージョン 5.0.11(1)-release (x86_64-apple-darwin17.7.0)
- これらのインストール情報は比較的簡単に見つかりますのでそちらでお試しください。またインストールの説明は冗長だと思いますので。

# vimをバッチで使う
- vimは好きなエディタでインターラクティブに動きますが、バッチモードでも動きます。これを使います。下記のスクリプトではvimが開いて処理しますが、待てば自動でhtmlファイルが生成されます。

```{bash}
~$ cat script_vim_TOhtml
:TOhtml
:w!
:q!
:q!
~$ vim -s script_vim_TOhtml hoge.bash
tmp$ ls
hoge.bash  print_script.bash script_vim_TOhtml
tmp$ vim -s script_vim_TOhtml hoge.bash 
tmp$ ls
hoge.bash  hoge.bash.html  print_script.bash script_vim_TOhtml 
（htmlファイルができています）
```
- 一応説明して置きますと、vimのバッチ処理で受け取った引数のファイルを`:TOhtml`でhtmlファイルに変換します。これはまだメモリ上のバッファなので、`:w!`で強制上書きします。名前のデフォルトはファイル名に.htmlを加えたものです。バッファのhtmlのファイルと元のファイルを閉じるために`:q!`を二回続けます。
- `vim -s`はスクリプトを読み込むオプションです。

# 全体のスクリプト
- これを`wkhtmltopdf`と`lpr`に渡せばいいのです。こんなスクリプトです。

```bash
$ cat print_script.bash 
#!/usr/local/bin/bash
f_target=$1
f_tmp=".tmp.$$"
f_html="$f_target".html
f_pdf="$f_target".pdf
cat << EOF > ./$f_tmp
:TOhtml
:w!
:q!
:q!

EOF
[ -f $f_tmp -a -f $f_target ] && vi -s $f_tmp $f_target || exit
[ -f $f_html ] && cat $f_html | wkhtmltopdf -  $f_pdf
lpr $f_pdf
[ $? -eq 0 ] && echo "印刷成功"
trash-put $f_tmp $f_pdf $f_html
```

各行の説明です。エラー処理を追加しました[2020-03-07]
1. 3行目の`f_tmp=".tmp.$$"`で$$はプロセスIDで念のため重なりのないファイル名としました。
2. `wkhtmltopdf` はファイルの拡張子がhtmlだと`http://`をつけたURLを読みに行くので`cat $f_html`とパイプで標準入力に渡しています。`wkhtmotopdf`の入力は`-`で標準入力になります。
3. 出力に`$f_pdf`を指定すればpdfファイルができます。これを`lpr`で出力するだけ。多分pdfを介さずにパイプでいけるでしょうが、確認用にpdfも残すためにファイルにしています。
4. 最後の行はエラーチェックして成功を表示しています。


# 結果
- こんな感じです。

```{bash}
tmp$ ls
hoge.bash  print_script.bash  script_vim_TOhtml
tmp$ ./print_script.bash hoge.bash 
Loading pages (1/6)
Counting pages (2/6)                                               
Resolving links (4/6)                                                       
Loading headers and footers (5/6)                                           
Printing pages (6/6)
Done                                                                      
印刷成功
tmp$ 
```
変換されたhtmlもpdfも残しています。これで複数あるコードも一括して印刷できるでし、どのファイルを印刷したのかもファイルを見ればわかります。

こんな短いコードですが、どなたかのお役に立てれば嬉しいです。
HTMLで画面ロード時に別の画面を表示する

## はじめに
画面ロード時に別画面を表示するというニッチなユースケースだと思いますが、記事として残しておきます。

## ①画面ロード時処理（HTML）
HTMLで画面ロード時に何か処理をしたい場合には\<body>タグに`onload`属性を記述します。

```html
<body onload="画面ロード時処理を記載">
```

## ②別の画面を表示
別サイトへ遷移するには`location.href`を利用します。

```javascript
location.href="遷移させる画面のURL"
```

## さいごに
上記①、②を組み合わせれば、画面読み込み時に別のサイトの画面を表示することができます。

```html
<body onload="location.href='遷移させる画面のURL'"></body>
```