OmniAICreator/Qiita-1.07M huggingface dataset:
kaminariのページネーション機能でundefined method `page' for #<Array:~>とエラーになった時の対処法

kaminariを使ったページネーション機能は、かなり簡単に実装できるのが良いですよね。
そんなkaminariですが、Arrayオブジェクトに対しては通常の実装だと、

```
undefined method `page' for #<Array:~>
```
とエラーが出てしまいますので、対処法をまとめます。

# kaminari実装前

商品(Product)オブジェクトをお気に入り数順で、ランキングするメソッドです。

```ruby:
class RankingsController < ApplicationController
  def like
    @ranking_counts = Like.ranking
    @products = Product.find(@ranking_counts.keys)
  end
end
```

# エラー対処前

通常のKaminariの利用だと、このように実装します。が、これだとエラーになります。

```ruby:
class RankingsController < ApplicationController
  def like
    @ranking_counts = Like.ranking
    @products = Product.find(@ranking_counts.keys).page(params[:page]).per(10)
  end
end

```

# エラー対処後

`@products`を引数に、`Kaminari.paginate_array`を追記することで、実装ができました。

```ruby:
class RankingsController < ApplicationController
  def like
    @ranking_counts = Like.ranking
    @products = Product.find(@ranking_counts.keys)
    @products = Kaminari.paginate_array(@products).page(params[:page]).per(10)
  end
end

```
`find`や`where`メソッドを利用するとArrayオブジェクトが生成されるので、上記のような対処が必要です。

# 参考
・[kaminariでundefined method `page' for # Array:0x000xxxxxxと出た](https://haayaaa.hatenablog.com/entry/2019/03/11/215042)
【学び】Laravelのsshログイン時にcodeディレクトリが表示されないとき・・・(´・ω・`)

#問題点
https://qiita.com/7968/items/97dd634608f37892b18a#%E7%AC%AC6%E7%AB%A0-%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83%E3%81%AE%E6%A7%8B%E7%AF%89
上記記事を実行していたときのことだった。

laravelの環境構築をしようと意気込んで、つまづいた（僕的には）最大の難所。
Homestead.yamlの設定などを終え、いざvagrant upし、ssh接続してみると
肝心のcodeディレクトリが出てこない・・・

これではcomposerさんを使ってインストールできないではないか！！！

僕のバラ色あふれるlaravel生活にレッドサインだったので、死ぬ気で解決しました。




##解決法
気づけば結構しょぼいミスで原因はHomestead.yamlの設定だった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402399/ed559cc1-08f1-d1f9-2c09-821bc33dae08.png)

これがつまづいていたときの僕だ。

これを下記に書き換えた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402399/e893cc70-4d5e-4222-dda2-02deda65d7a9.png)


下記二点の対応を行った。



###①ディレクトリの名前を変える

僕のパソコンはCドライブとDドライブの二台構成だ。
CドライブはSSDで~~ゲームを主に入れているため~~大容量入りきらないため、いつもDドライブで行っている。

そのDドライブにappフォルダを作成し、その直下にてHomesteadをインストールして行っていた。

ので、appフォルダの名前をcodeに書き換えてやった。~~ざまあみろ~~





###②Homestead.yamlの設定にて、D:\appをD:\codeに変更

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402399/e893cc70-4d5e-4222-dda2-02deda65d7a9.png)


同じ画像の使いまわしだが、mapの指定をD:\codeに変えた。




あとは、vagrantをrelodadして仕上げだ。


ssh接続してlsコマンドをたたくと・・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402399/50682b44-13a2-bd96-d45f-4a955e87c37e.png)

###あああいるではないかあああああああああああああああああああああああああ



こうして僕のlaravel生活は守られたのであった。



##補足
今回の件を経て、公式ドキュメントをちゃんとみるようになったのだが、
どうやらappというものがだめだったらしい（名前などに使用してはいけない）

と僕は思っている。

（もし解決策がまちがってたら教えてクダサイ）
GORMでINSERT時に構造体の特定のフィールドを無視する方法

# 概要
GolangのORマッパーとしてGORMがあります。
GORMを利用するときは、構造体を引数に渡してDBから値を取得します。
構造体は基本的にテーブルのカラムにあわせて定義すると思いますが、JOINなどをしたときには、構造体にフィールドを追加することがあります。
しかし、フィールドを追加したがために、INSERTのときにそんなカラムはないよ！！となったりします。
そういうとき、特定のフィールドを無視して欲しいですよね！という解決策を書いていきます。

# 今回の元の構造体
```golang:entities/user.go
package entities

type User struct {
  ID   uint   `gorm:"primary_key"`
  Name string `gorm:"not null"`
}
```

```golang:entities/user.go
package entities

type Article struct {
  ID       uint   `gorm:"primary_key"`
  UserID   string `gorm:"not null"`
  Title    string `gorm:"not null"`
  Content  string `gorm:"not null"`
}
```

# 課題
今回、「Userに紐づく記事の数を取得したい。」というものがあった。
具体的には、Userの構造体に`記事の数`のフィールド(**`ArticleAmount`**フィールド)を追加して、データを取得したい。
そこで以下のように追加すると、DBからSELECTは取得できるが、UserデータをGORMでINSERTするときに、そんなカラムはないよ...!!と言われてしまう。

*※新たに構造体を定義すればよいじゃん！といえばその通りだが、そのために新たな構造体を作るのもなんだかなぁという気持ちになっている。*

```golang:entities/user.go
package entities

type User struct {
  ID            uint   `gorm:"primary_key"`
  Name          string `gorm:"not null"`
  ArticleAmount string
}
```

では、どうしよう...?

# 解決策
案外簡単で、``` `gorm:"-"` ```を追加するだけで良い。
ドキュメントには[こちら](http://doc.gorm.io/models.html#model-definition)に示してある。

```golang:entities/user.go
package entities

type User struct {
  ID            uint   `gorm:"primary_key"`
  Name          string `gorm:"not null"`
  ArticleAmount string `gorm:"-"`
}
```
dashで疑似配列

dashにはbash等とは異なり配列がない。

制御コードを区切り文字にするとブランク含みの文字列も配列要素にできる。これだと構造を再帰的にできないけどどうせbash もできないし、制御文字を変えれば数次元配列くらいまでは再現できる。
([制御文字を使用しないパターン](https://qiita.com/opiliones/items/45102406a95d3e030454))

### 配列を作成する

```
$ array 1 "1 2" 3
11 23
$ y="`splt "1,1 2,3," ,`"
$ echo "$y"
11 23
```
制御コードが見えないのですべての要素が詰まって見える。

### 要素を取り出す
```
$ idx "`array 1 "1 2" 3`" 1
1 2
```
コマンド置換はコードがうるさい上にフォークが発生して遅いので戻り値用のグローバル変数に代入したほうがいいかもしれない。

### 部分配列
```
$range "`array 1 "1 2" 3`" 0 2
11 2
```

### forループ
```
$ for_array i in `splt "1,1 2,3," ,`; do_array
>   echo "$i"
> done_array
1
1 2
3

$
```

### コード
```
_SI=$(printf '\017')
eval "FS=\"\${FS:-$_SI}\""

_ORG_F_OPT=+f

alias for_array='set -f; _OFS=$IFS; IFS='$FS'; for'
alias do_array='do IFS=$_OFS; set '"$_ORG_F_OPT"';'
alias done_array='_OFS=$IFS; done; IFS=$_OFS; set '"$_ORG_F_OPT"';'


if ! type return_val >/dev/null 2>&1; then
  alias return_val='echo'
fi

array() {
  set -f
  set -- "$@"
  local IFS="$FS"
  return_val "$*$IFS"
  set $_ORG_F_OPT
}

range() {
  local IFS="$FS" i=$2 n=$3 t=
  set -f
  set -- $1
  shift $i
  while [ "$n" -ge 1 ]; do
    t="$t$1$FS"
    n=$((n-1))
    shift
  done
  return_val "$t"
  set $_ORG_F_OPT
}

idx() {
  local IFS="$FS" i=$2 n=1
  set -f
  set -- $1
  shift $i
  return_val "$1"
  set $_ORG_F_OPT
}

splt() {
  local IFS="$2"
  set -f
  set -- $1$IFS
  IFS="$FS"
  return_val "$*$IFS"
  set $_ORG_F_OPT
}
```
【勉強会メモ】Search Engineering Tech Talk 2019 Spring

# はじめに
先日 [検索技術勉強会](https://search-tech.connpass.com/) に参加しました。
その際個人的に印象に残った点をまとめます。

# イベント概要
[Search Engineering Tech Talk 2019 Spring](https://search-tech.connpass.com/event/126506/)

> 検索技術勉強会の目的は、「検索」/「検索システム」にまつわる技術や手法に関して共有できる場を提供することです。
検索エンジンごとの勉強会などもありますが、検索エンジンには関係なく、 「検索」というシステム、サービスを作る上で共通の解決すべき課題があります。
これらの課題をみんながどのように解決しているのかといった知識を共有できる場になればと思っています。

# 発表
## [「安心な移動」のための POI(Point-of-Interest; 地点) 検索](https://www.slideshare.net/NavitimeJapan/poi-141851184) / 株式会社ナビタイムジャパン [小式澤 篤さん](https://twitter.com/lastarrow21)
- POIとは、特定の場所、地点、スポット、目的地
- ナビタイムさんのような経路探索サービスでは、POI検索（目的地検索）がキモとなる
 - ユーザの求めるPOI検索ができないと、経路探索のサービスを提供できない
     - 結果としてユーザが満足できない（目的地にたどり着けない）
- 普通の検索だと、「適合率」や「再現率」が重要だが
 - 経路探索の場合、それだけでは思うような検索ができない
     - 重要なのは「有名度」と「距離」
     - POIによって「有名度」を優先するか「距離」を優先するかを決めていく
         - 有名度
             - "ディズニー" で検索すると誰もが知ってる "ディズニーランド" を上位にヒットさせたい
         - 距離
             - コンビニなどのチェーン店の場合、"セブンイレブン" で検索した場合は、ユーザから近い場所にあるのをヒットさせたい
     - 「有名」あるいは「距離」の判断方法
         - 有名かどうかはログを調査
             - 多くのユーザが目的地と指定したものを「有名」と判断
         - チェーン店はPOI属性としてカテゴリを用意しておく
             - カテゴリは社外からのデータ提供者から付与される、もしくは手動で付与

## [社内ドキュメント検索システム構築のノウハウ](https://www.slideshare.net/shinsuke/ss-141757479) / [Shinsuke Sugayaさん](https://twitter.com/shinsuke_sugaya)
- [Fess](https://fess.codelibs.org/ja/index.html)とはオープンソース全文検索システム
   - 内部でElasticsearchを内包している
- 企業内検索の課題
  - クロールデータの大規模化
     - クラスタ構成にして分散検索で対応
     - あるいは更新されたファイルだけクロール（差分クロール）
  - ロール
     - ログインユーザ情報により文書の参照権限あり・なしを制御
  - SSO
     - ActiveDirectoryや認証サーバによるリダイレクト
  - 業務システムとの連携
     - JDBCドライバでDBにアクセス
  - 扱うファイルの多様化
     - [POI](https://pdfbox.apache.org/) や [Tika](https://tika.apache.org/) などを使用してテキスト化


## [料理動画アプリ「クラシル」の検索について](https://speakerdeck.com/sakura818uuu/liao-li-dong-hua-ahuri-kurasiru-falsejian-suo-nituite) / [sakuraさん](https://twitter.com/818uuu)
- 大変なこと
  - 辞書シノニムのメンテ
     - とにかく毎日メンテ
         - 結果、辞書にどんな単語が登録されているかを暗記するまでに（すごい・・）
     - 表記違いが多い
         - とりむねにく、鳥胸肉、鶏胸肉、鶏胸・・・
     - どこまでが類義語かを判断するのが難しい
         - えんどうまめ？さやえんどう？きぬさや？・・・
  - 検索しても結果がない
     - 一つずつ地道につぶしていった（結果1000個以上削減）
  - 検索した結果がおかしい
     - これも一つずつ地道につぶしていった
- 時期や検索する端末によって検索クエリが変わってくる
  - 例えばAndroidだと節約系レシピの検索が多い（笑）

# おわりに
- 一言で検索と言っても、提供するサービスや扱う情報によって、工夫するポイントが色々ある
- やはり辞書メンテはどこも苦労していそう
- Fessが面白そうなので触ってみる
PowerShellでバイト計算

#言いたいこと
KBやMBなどのデータ量の単位を利用した計算が可能
（PowerShell 5.1で確認したところKB～PBまで）

```
PS v:\test> 1KB
1024
PS v:\test> 1KB*0.5
512
PS v:\test> 1MB
1048576
PS v:\test> 1MB*2
2097152
PS v:\test> 1PB
1125899906842624
PS v:\test> 1EB
1EB : 用語 '1EB' は、コマンドレット、関数、スクリプト ファイル、または操作可能なプログラムの名前として認識されません。
名前が正しく記述されていることを確認し、パスが含まれている場合はそのパスが正しいことを確認してから、再試行してください
。
発生場所 行:1 文字:1
+ 1EB
+ ~~~
    + CategoryInfo          : ObjectNotFound: (1EB:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
```

#ダミーファイル作成
接頭辞付の数値の直接指定はエラーになる

```
PS v:\test> fsutil file createnew test1mb.txt 1MB
使用法 : fsutil file createNew <ファイル名> <長さ>
   例 : fsutil file createNew C:\testfile.txt 1000
PS v:\test>
```
一度変数に代入してから作成　⇒　成功

```
PS v:\test> $size = 1MB
PS v:\test> fsutil file createnew test1mb.txt $size
ファイル v:\test\test1mb.txt が作成されました
PS v:\test>
```
サイズ確認(1024*1024=1048576)　⇒　OK

```
PS v:\test> Get-ChildItem


    ディレクトリ: v:\test


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2019/04/24     21:47        1048576 test1mb.txt


PS v:\test>
```
ワンライナーだと↓のように。
要素数1（値:1048576）の連番のオブジェクト（追って説明）を処理している。


```
PS v:\test> 1MB | % {fsutil file createnew test1mb.txt $_ }
ファイル v:\test\test1mb.txt が作成されました
PS v:\test> dir


    ディレクトリ: v:\test


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2019/04/24     22:27        1048576 test1mb.txt


PS v:\test>
```


#連番

PowerShellではこんな感じ↓で連番を簡単に作成可能だが、


```
PS v:\test> 1..10
1
2
3
4
5
6
7
8
9
10
PS v:\test>
```
接頭辞付の数値の直接指定でもOK

```
PS v:\test> 1..1KB
1
2
3
4
5
(中略)
1022
1023
1024
PS v:\test>
```
パイプでつないで利用OK

```
PS v:\test> 1..1KB | % {New-Item ("test$_.txt")}


    ディレクトリ: v:\test


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2019/04/24     22:40              0 test1.txt
-a----       2019/04/24     22:40              0 test2.txt
-a----       2019/04/24     22:40              0 test3.txt
-a----       2019/04/24     22:40              0 test4.txt
-a----       2019/04/24     22:40              0 test5.txt
(中略)
-a----       2019/04/24     22:40              0 test1020.txt
-a----       2019/04/24     22:40              0 test1021.txt
-a----       2019/04/24     22:40              0 test1022.txt
-a----       2019/04/24     22:40              0 test1023.txt
-a----       2019/04/24     22:40              0 test1024.txt


PS v:\test>
```
Redash のクエリを export するツールを書いた

## 動機

Azure で動かしていた Redash を [redash.io](https://redash.io/) に乗せ変えることになり、クエリをエクスポートできるツールを探していた。

https://gist.github.com/arikfr/598590356c4da18be976

[公式からリンクされてる](https://redash.io/help/user-guide/integrations-and-api/api/)上のツールを使おうとしたんだけど、自前のRedashサーバのバージョンが古かったのや自分の環境のPythonのバージョンが古かったりでうまく動かなかった。あと最終実行時間とかでフィルタリングしたかったので Ruby で似たようなツールを書いてみた。

[oieioi/redash_exporter](https://github.com/oieioi/redash_exporter)

## 使い方

シェルからはこんな感じで使う。

```bash
$ gem install redash_exporter

# 実行ディレクトリにsqlをエクスポート
$ redash_exporter --redash-url="http://your.redash.server.example" --api-key="your API key"

# 出力先のディレクトリを指定する場合は
$ redash_exporter --redash-url="http://your.redash.server.example" --api-key="your API key" --dest=redash-sqls
```

Ruby でいじくる時はこんな感じ。

```ruby
require 'redash_exporter'

queries = RedashExporter::Queries.new('http://your.redash.server.example', 'your API key')

# 全クエリを取得
queries.fetch

# フィルタリング
queries.reject! { |q| q[:created_at].to_time > 3.months.ago }

# SQLを出力
puts queries.first.to_s

# ファイルエクスポート
queries.first.export

# 全部エクスポート
queries.export_all

```

API は変更になる可能性あり。

バグとかあったらissue/パッチください。
Agilent MicroArray(1色法)解析備忘録１

なんかAgilentの解析に苦労したので書きます
# 使うソフト
RStudio使います。
データのあるディレクトリを作業ディレクトリに設定しておいてください。
タブにあるSession > Set Working Directory > Choose Directoryから設定できます。

# 下準備
データを扱う前には下準備が必要です。
読み込んで処理する対象ファイルを示してあげる必要があります。

↓こんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383410/007c1508-4c9c-84bb-77d3-c5cd05cf640e.png)

|列名     |       内容 |
|:-----------------|------------------:|
|SlideNumber       |アレイデータの通し番号|
|Name         |各アレイデータの通称。わかりやすい名前で。|
|FileName|アレイデータの入ったファイルの名前|
|Target|アレイデータの群分け。3群以上でも可|

Excelとかで作ってTargets.txtとしてタブ区切りで保存しましょう。
(作業ディレクトリにおいてね)

# パッケージのインスコ
データの読み込みとか正規化に使うLimmaパッケージをBiocManagerからインストールします。

```R
if (!requireNamespace("BiocManager", quietly = TRUE))
    install.packages("BiocManager")

BiocManager::install("limma")
```

インストールしたLimmaパッケージを読み込みます。

```R
library(limma)
```

# データの読み込み
生のtxtファイル使います。

↓Excelで開くとこんな感じのやつ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383410/be7c837d-1ab2-3d20-9cf4-fdcc425804d2.png)

さっき作ったターゲットを指定するファイルを使ってデータを読み込みます。

```R
targets <- readTargets("Targets.txt", row.names="Name")
RG <- read.maimages(targets, source="agilent",
green.only=TRUE,other.columns="gIsWellAboveBG")
```
# データの正規化
バックグラウンドの補正と正規化をします。

```R
boxplot(RG$E,ylim=c(0,300))
RGcor <- backgroundCorrect(RG, method="normexp")
boxplot(RGcor$E,ylim=c(0,300))
RGnorm <- normalizeBetweenArrays(RGcor, method="quantile")
```

※正規化
　マイクロアレイではアレイデータごとに全体的なシグナル強度に差が出てしまう。
　それだとアレイ間の比較が出来ないので、シグナル強度を合わせようっていう処理。
　色んなメソッドの理解にはこのスライドが役立った。
　https://www.slideshare.net/antiplastics/normalization-of-microarray


バックグラウンド補正のmethod="normexp"と正規化のmethod="quantile"から見るにRMA法に相当する処理をしてるっぽい。

# 遺伝子のフィルタリング
シグナル強度がバックグラウンドを下回るプローブ、Gene Symbol(Gapdhみたいな遺伝子の通称)がないプローブは除く。

```R
Control <- RGnorm$genes$ControlType==1L
NoSymbol <- is.na(RGnorm$genes$GeneName)
IsExpr <- rowSums(RGnorm$other$gIsWellAboveBG > 0) >= 1
RGfilt <- RGnorm[!Control & !NoSymbol & IsExpr, ]
```

# 各アレイデータを群に割り当てる
最初に使ったTargets.txtのTarget列を使って、各アレイデータを群に振り分けます。

```R
lev <- c("WT","KO")
f <- factor(targets$Target,levels=lev)
design <- model.matrix(~0+f)
colnames(design) <- lev
fit <- lmFit(RGfilt,design)
```
1行目は設定した群に応じて書き換えてください。

# 解析・プロット

```R
contrast.matrix <- makeContrasts(KO-WT,levels=design)
fit2 <- contrasts.fit(fit, contrast.matrix)
plotMD(fit2)
```

1行目の「KO-WT」のところがキモです。

このステップまでに各群のシグナルがlog2変換されていますので、その差によってアレイ間の比較を行います。その引き算をここでやっているわけです。
多群の場合には「(A-B)-(C-D)」などとすることもできます。

実験デザインによって書き換えて使ってください。

出てくる散布図は横軸が発現量の平均、縦軸が発現変化量になってます。
特定の遺伝子をプロットするのはまた今度書きます。

### 補足
各群が2つ以上のデータを含んでいる場合は
```fit2 <- eBayes(fit2)```
とすることでベイズ統計的にp値などを求められるようです。

# おわり
おわりです。
バイオインフォ的なことに触れるのは初めてだったので間違いがあるかもしれません。
間違いとかこうした方がいいよとかあったら、教えていただけると非常に非常にありがたいです。
今後少しずつパスウェイ解析なども書こうかと思います。
データ収集とデータ分析の自動化。仮説（28）

変わりゆく機械学習と変わらない機械学習
神 嶌 敏 弘 〈産業技術総合研究所 mail@kamishima.net〉
https://www.jps.or.jp/books/gakkaishi/2019/01/74-01seriesAIphys2.pdf

# ノーフリーランチ定理

# 醜いアヒルの子の定理

# データロボット　
https://www.datarobot.com 

数十の機械学習の方式を競わせる方式は、ノーフリーランチ定理に対応する努力の側面がある。

データ収集とデータ分析の自動化は、醜いアヒルの子の定理の影響を小さくする努力の側面がある。

２年前のデータロボット社の行事では、メディア非公開で従来の制御方式との比較で効果があったことなどは記録にないため紹介できないのは残念。

# 参考資料(reference)
AI（機械学習）の適用限界を示唆する２つの数学定理【初心者向け】
https://qiita.com/zaq9/items/5e347f7e138ae05f9ef2

# 文書履歴 (document history)
ver. 0.01 初稿 20190424
ver. 0.02 表題追記 20190425

### 最後までおよみいただきありがとうございました。

いいね　💚、フォローをお願いします。

#### Thank you very much for reading to the last sentence.

Please press the like icon 💚　and follow me for your happy life.
プロデルでネ申Excel作成を自動化したい #0

##いきさつ
　このところRPAがブームになっているようですが、ITの時流から大きく取り残されたうちの職場にもそんな空気が作用したのか、昨年ぐらいから業務自動化の相談が舞い込んできています。どのくらい取り残されているかといえば、Wordで表入りの書類を作るのが煩雑だからExcelを使うとか、横罫線入りの手書き用紙から様式を変えずPC入力に移行したいからExcelを使うとかいうレベルです（一太郎がメジャーで残っててくれたらなぁ・・・）。とはいえ、電卓とワープロ専用機が仕事の道具という昔のやり方を踏襲していては、増える一方の仕事量は到底こなせるものではありません。
　これまで[日本語プログラミング言語「プロデル」](https://rdr.utopiat.net/)の力を借りながら、手弁当で業務自動化アプリをボチボチ作ってきました。敢えてマイナーな言語にしたのは、こんな職場環境でも日本語であれば開発を分担したいと言ってくれるスタッフが現れるかも・・・という淡い期待があってのことです（実際興味を示す人は何人もいます）。
##今回の依頼
 ある部署が毎月発行しているカレンダー形式の時間割表のようなものがあり、全入所部門はこの表を基に日々の業務の段取りを組み立てています。Excelファイルなのですが、氏名や時間、その他備考など細かく記載されていて、情報量はかなり多いです。発行部署のスタッフは、或る意味で職人的スキルを持っており、累計で10時間程度かけて作成しています。受け取った部署は該当する利用者氏名を蛍光ペンでマーキングしていきます。2、3度誤りチェックをしているので多くて2時間程度でしょうか。これらを通常の介護業務の合間を見て、あるいは夜勤帯の寝静まった時に一気呵成に行っています。
　昨年あたりから、うちもご多分に漏れず人手不足が**さらに**顕在化してきたうえに、利用者の異動やインフル感染などで時間割の組直しが頻繁に発生するようになり、さすがにもう無理・・・という声がちらほら上がるようになりました。ニーズとしてまとめると次の2点です。
1.セルにちまちまと文字列を入力していた作業の負担を軽くしたい。
2.マーキングの作業をなくしてほしい。
1.については、当日のサービスの内容と参加した利用者を記録する日報アプリを作成し、その部署で稼働させています。リストに表示された利用者名や業務内容を選んで入力するので迅速にできます。データはMDBファイルに記録するので、罫線抜きの一覧表で出力するぐらいなら標準のOffice連携機能で簡単に実装できそうに思えます。
2.については、部署ごとに所属する利用者だけが入っている時間割を出力するようにすれば解決です。
と思ったのですが、時間割表のフォーマットは結合セルや、フォント、色の指定を多数入れて、美しさにこだわって作られてきました。フォーマットは変えずに、ステークホルダーのコンセンサスから逸脱しないようにすすめたい。となると、連係機能では難しいので、白紙のフォーマットファイルをアプリから直接編集するのがよさそうです。
##.xlsxファイルの構造##
　早速xlsxファイルの構造を調べて見ました。正体は複数のXMLファイルをまとめたZIPファイルだったと知り、今更驚きました。
http://mitsutakauomi.com/?p=362
それなら、XML機能でセルの文字列を編集できそうです（初めて使う機能ですが）。セルの位置を指定して編集するのはかなり煩雑な作業になりそうなので、ひな型とするファイルの目的のセルに「@サービス名1-1」、「@参加者1-2」などの文字列を入れておいて、取得した要素の内容により分岐させ書き換えと。
##セル内の文字列の読み出し##
ひとまず、Excelで適当なカレンダーをつくって試してみます。
![コメント 2019-04-24 214031.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349242/252881fa-46fd-53b4-e245-a5b85ee3f8c7.png)
このxlsxファイル内のsharedStrings.xmlの内容は次のようになっています。

```xml:sharedStrings.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="8" uniqueCount="8"><si><t>月</t></si><si><t>火</t></si><si><t>水</t></si><si><t>木</t></si><si><t>金</t></si><si><t>土</t></si><si><t>日</t></si><si><t>2020年1月</t><rPh sb="4" eb="5"><t>ネン</t></rPh><rPh sb="6" eb="7"><t>ガツ</t></rPh><phoneticPr fontId="5"/></si></sst>
```

プロデルの例を参考に以下のコードを実行させてみました。

```xml取得.rdr
XMLを使う
データは、「［プログラムの位置］カレンダー\xl\sharedStrings.xml」からXMLとして読み込んだもの
一覧は、データから「sst\si」を取得したもの
一覧を要素へそれぞれ繰り返す
　　［要素の「t」の内容を表示する
繰り返し終わり
```
結果はエラー。要素の「t」の中身が無だそうです。「si」の内容の表示はできるのになぜ？？
プロデルの実行例で出力したXMLと見比べつつ調べてみると、原因は名前空間でした。
https://www.atmarkit.co.jp/fxml/ddd/ddd001/ddd001-namespaces1.html
名前が違うフルネームに変換されるためか、すんなり参照できないようです。上のXMLからxlmns属性を削除すると上記のコードで問題なく動きます。とは言え、それがxlsx内でどのように作用するのか分かりません。
　そこで、次のように変えてみました。

```xml取得その2.rdr
文字xmlは、「［プログラムの位置］カレンダー\xl\sharedStrings.xml」をXMLとして開いたもの
文字セル一覧は、文字xmlから「sst\si」を取得したもの
文字セル一覧を箱へそれぞれ繰り返す
	臨時一覧は、箱の要素一覧
	臨時一覧を器へそれぞれ繰り返す
		もし器の名前が「t」ならば
			器の内容を報告する
		もし終わり
	繰り返し終わり
繰り返し終わり
```
結果は、
>月
>火
>水
>木
>金
>土
>日
>2020年1月

うまく行きました。これで文字列の書き換えはすぐにできそうです。ただ、再圧縮したzipファイルをExcelがすんなり読み込めるかがヤマになりそうな気がします。
[〜続く〜](https://qiita.com/shukvaal/items/f246aca1745059d0a9da)
画像データをnumpyに変化しよう

このメモは画像データをnumpyに変換するScriptを書きます。
まずは必要なライブラリーをインストールしますね！

```
pip install pillow
```
# Folder構成
Folderの中にclsA,clsB,clsC３つのFolderがありまして、中に200枚つつの.jpg写真があります。
絵からみるとこんな感じかな：

```
|-clsA
| |-photo1.jpg..etc
|-clsB
| |-photo1.jpg..etc
|-clsC
| |-photo1.jpg..ec

```

#流れ
1. 各Folderの名前を配列として初期化します。
2. 画像用のTemp配列とLabel用のTemp配列を作成します。
3. For loopでFolderの中にLoopし、Patternが同じFileを探します。
4. もう１個もFor loop始まり、Pillowライブラリーを使ってImageを処理します。
5. 処理から出てきたデータをTemp配列に入れます。
6. 最後はnumpy配列に変換します。

…って感じかな？

##各Folderの名前を配列として初期化
```
from PIL import Image
import os,glob
import numpy as np

classes=['clsA','clsB','clsC']
num_classes=len(classes)

#resize the image to 50px
image_size=50

```

##画像用のTemp配列とLabel用のTemp配列を作成

```
#image data
X=[]

#label data
Y=[]
```

## For loopでFolderの中にLoopし、Patternが同じFileを探し

```
for index,clss in enumerate(classes):
	photos_dir='./'+clss
	#get the same pattern of files
	#in this case is .jpg files
	files=glob.glob(photos_dir+'/*.jpg')
```


##Pillowライブラリーを使ってImageを処理

```
	for i,file in enumerate(files):
		#in this apps, only have 200 pictures
		if i >=200:
			break

		image=Image.open(file)
		image=image.convert('RGB')
		image=image.resize((image_size,image_size))
		data=np.asarray(image)

		#0=clsA
		#1=clsB
		#2=clsC
		X.append(data)
		Y.append(index)

```
##numpy配列に変換
```
#change to numpy array
X=np.array(X)
Y=np.array(Y)
```

# Scriptの全体

```
from PIL import Image
import os,glob
import numpy as np
from sklearn.model_selection import cross_validate

#the name of your classes but also the path name
classes=['clsA','clsB','clsC']
num_classes=len(classes)

#resize the image to 50px
image_size=50

#load the images

#image data
X=[]

#label data
Y=[]

for index,clss in enumerate(classes):
	photos_dir='./'+clss
	#get the same pattern of files
	#in this case is .jpg files
	files=glob.glob(photos_dir+'/*.jpg')
	for i,file in enumerate(files):
		#in this apps, only have 200 pictures
		if i >=200:
			break

		image=Image.open(file)
		image=image.convert('RGB')
		image=image.resize((image_size,image_size))
		data=np.asarray(image)

		X.append(data)
		Y.append(index)

#change to numpy array
X=np.array(X)
Y=np.array(Y)
```

##実行してみよう

Xの長さは600になり、つまり200x3になります。

```
len(X)
```

Yの100番、200番、300番にもそれぞれ0,1,2がちゃんと配られるとわかってます。

```
Y[100]
Y[200]
Y[400]
```
バンディットアルゴリズム - トンプソンサンプリングの実装

## 概要

今回のコードは[Github](https://github.com/RINDO/thompson_sampling)にあげています。

## ひとことだけ

バンディットアルゴリズムの概要、トンプソンサンプリングの説明、確率系のお話(ベータ分布etc)は他に素晴らしい記事がたくさんあるのでそちらにゆずるとして、自分が感じたトンプソンサンプリングのイメージを文字で紹介して終了とします（笑）。

トンプソンサンプリングの良いところとしては、これまで探求してきた各アームに対して成功回数・失敗回数を記憶しておくことによってアームの選択に反映することができるという点があります。
回数がどのように影響してくるか、ということに関してはベータ分布やベイズ推定のような数学（確率）の知識が必要になってきます。
下のベータ分布のシミュレーションで書いているように、成功・失敗の回数によってグラフの形状が変化してきます。
グラフを捉える際のイメージとしては、 `グラフとX軸で囲まれた領域では、その事象が一様に起こり得る` という感じで捉えると入ってきやすいと思います。
言い換えると、囲まれた領域から点を選ぶことができて、その点のXの値 = 事象が起こる確率という風に捉えることができます。
トンプソンサンプリングでは、そのような処理を各アームに対して行なっており、各アームからランダムに選んだ `確率` の中で最大のアームを次に引くようになっています。
成功回数が多ければ高い確率の部分の面積が大きくなり、失敗回数が多ければ低い確率の部分の面積が大きくなる、というイメージです。
つまり、成功した回数が多ければ多いほど選択されやすくなる (= これまでの経験を活かした選択ができるようになる)ということです。

## ベータ分布のシミュレーション

ベータ分布のシミュレーションは[こちら](https://keisan.casio.com/exec/system/1180573226)をやってみるといい。

### a: 1, b: 1

成功: 0回 / 失敗: 0回のグラフ。どの確率(X軸)も一様に起こりうる、と言う風に見るらしい。

<img width="263" alt="スクリーンショット 2019-04-24 21.59.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29844/c143256d-b3ce-1555-4980-6274edf3600b.png">


### a: 5, b: 2

成功: 4回 / 失敗: 1回のグラフ。グラフの右側の面積が大きい。X軸とグラフで囲まれた部分から事象が起こり得ると見るとわかりやすい。

<img width="261" alt="スクリーンショット 2019-04-24 22.00.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29844/b010c3d5-1e04-c9fd-4439-c3f91fc5e014.png">


### a: 2, b: 5

成功: 1回 / 失敗: 4回のグラフ。さっきの逆。

<img width="262" alt="スクリーンショット 2019-04-24 22.00.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29844/9c67ce5e-6fb8-c04a-012e-3c2e0488ad7a.png">

## 参考資料

* [バンディットアルゴリズム入門と実践](https://www.slideshare.net/greenmidori83/ss-28443892)
* [15分でわかる(範囲の)ベイズ統計学](https://www.slideshare.net/matsukenbook/15-59154892)
* [確率変数、確率分布、確率密度関数とは](http://arduinopid.web.fc2.com/P18.html)
* [コインで理解するベータ分布](http://r-tips.hatenablog.com/entry/beta-distribution)

## さいごに

数学的な詳しいことはあまりわからなかったので、追記していただける方いたらリクエスト送ってください！！ (イメージ重視の説明が望ましいです)
私家版SOLID原則ひとことまとめ

自分用にSOLID原則を一言づつでまとめる。

- S：クラスを変更する理由がいくつもあるとバグりやすい。でも変更可能性がないうちから心配しすぎるな
- O：ストラテジーパターンとかで影響範囲を閉じるとバグりにくい
- L：子クラスは親クラスと置換可能にしとくと良い
- I：インターフェースにあるメソッドはすべての実現クラスで実装されるべき。そうならない場合インターフェースを分ける
- D：上位のレイヤは下位レイヤのインターフェースに依存するようにしとくと良い

## 参考
https://postd.cc/solid-principles-every-developer-should-know/
【Angularアプリ開発】Angularアプリの開発環境を構築します

本稿では、Angularアプリ開発を巡って、プロジェクトの稼働環境や必要になる技術ポイントなどを解説してみたいと思います。

#前提
最近、Node.jsを利用しハイブリッドようなプロジェクトを動かしているユースケースが多くなってそうです。今回、AngularアプリにもNode.jsから稼働したいと思っておりますので、まず、プロジェクトを作る前に、Node.jsのインストールを行いましょう。

#Node.jsインストール
Node.jsのインストールの順番として、Node.jsのバージョン管理ツールとしているnpmをインストールすることが必要です。やり方は以下の通り。

```sh
# nodebrewをインストル
$ brew install nodebrew
# Node.jsとnpmのインストール
$ nodebrew install-binary latest
$ mkdir -p ~/.nodebrew/src
$ nodebrew install-binary latest
# 以下が表示
  Fetching: https://nodejs.org/dist/v11.12.0/node-v11.12.0-darwin-x64.tar.gz
######################################################################## 100.0%
Installed successfully
```
上記のコマンドで最新版がインストールされます。
Node.jsを有効にします。

```sh
# バージョンの一覧を確認
$ nodebrew list
# バージョンの一覧が表示
  v11.12.0
  current: none
# current: noneとなっているため、必要なバージョンを有効化する。
  nodebrew use v11.12.0
# バージョンの一覧を再確認
$ nodebrew list
# 以下が表示
  v11.12.0
  current: v11.12.0
```
nodebrewが使いやすいように環境パスを通します。
インストルした結果を確認します。

```sh
$ echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bash_profile
$ source ~/.bash_profile
# node.jsがインストル済かどうかを確認
  node -v
# 以下が表示
  v11.12.0
# npmがインストル済かどうかを確認
$ npm -v
# 以下が表示
  6.7.0
```
上記ような各バージョーンが表示されたらNode.jsのインストールが終わりします。

#AngularCLIインストール
以下コマンドでAngulerCLIをインストールします。

```sh
$ npm install -g @angular/cli
# 以下の内容が表示されたら、インストールがOK
  + @angular/cli@7.3.8
  added 363 packages from 197 contributors in 22.591s
```
Angularのバージョンを確認しましょう。
![スクリーンショット 2019-04-24 21.31.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229009/40d7dfa3-4ae7-d9b8-cac3-2185aa9c580a.png)

#VSCodeに連携
VSCodeに、Anguler拡張機能をインストールします。
🌾Angular Essentials
Angular Essentials拡張機能は、Angularの開発がしやすくなります。

**インストール方法**
VSCodeの拡張機能→Angular Essentials→インストール

**Angular Essentialsに含まれる拡張機能**

- Angular v4 Snippets
- Angular Language Service
- Editor Config
- tslint
- Chrome Debugger
- Bracket Pair Colorizer
- Path Intellisense
- Angular Inline
- Angular Material Theme
- 
🌾Auto Import
Auto Import拡張機能は、TypescriptとTSXで動作する拡張機能で、WebStormのように、インポート文を自動で追加され、より高速に開発ができます。

**インストール方法**
VSCodeの拡張機能→Auto Import→インストール

#Angulerアプリ作成
VSCodeのターミナルからAngulerアプリを作ります。

```sh
$ ng new coolesson
```
サーバを起動します。

```console
$ cd coolesson
$ ng serve 
# 以下が表示されます
  ** Angular Live Development Server is listening on localhost:4200, open your browser on 
  http://localhost:4200/ **
  Date: 2019-04-24T13:12:14.814Z
  Hash: a27f36c54306bf454f91
  Time: 9382ms
  chunk {es2015-polyfills} es2015-polyfills.js, es2015-polyfills.js.map (es2015-polyfills) 284 kB [initial] 
  [rendered]
  chunk {main} main.js, main.js.map (main) 11.5 kB [initial] [rendered]
  chunk {polyfills} polyfills.js, polyfills.js.map (polyfills) 236 kB [initial] [rendered]
  chunk {runtime} runtime.js, runtime.js.map (runtime) 6.08 kB [entry] [rendered]
  chunk {styles} styles.js, styles.js.map (styles) 16.3 kB [initial] [rendered]
  chunk {vendor} vendor.js, vendor.js.map (vendor) 3.77 MB [initial] [rendered]
```
任意ブラウザーで、URL欄にlocalhost:4200を打つと、以下の画面が表示されるはずです。
![スクリーンショット 2019-04-24 22.15.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229009/757f13b9-8850-ef22-4dfb-bb9aed54e539.png)
Live Programming環境のORCΛを試してみる②PILOTと連携して演奏する

ORCΛに入門してみようの続編です。今回はいよいよ実際に音を出してみたいとおもいます。

なにを使って音を出すかには色々な選択肢がありますが、大きく分けると以下の３つになるとおもいます。
・ORCΛ→（MIDI信号）→MIDI音源を鳴らす・・・既にMIDI環境がある人はこれが一番手っ取り早いと思います
・ORCΛ→（OSC信号）→OSCを受け取るシステムで演奏する・・・これにも色々ありますが、特にSonic piであれば簡単に連携できます。→sonic piとの連携についてはこちらに日本語記事が出てました！（2019/06/01追記）
[ライブコーディングツール「ORCΛ」と「SonicPi」の連携（備忘録、初心者向け）](https://qiita.com/donbeumai/items/a22198cef709b019e0be)
・ORCΛと連携しているシンセのPILOTを使う

現時点で音を鳴らす環境が何もない人でも、PILOTを導入すれば手軽にORCΛで演奏することができます。
今回は折角なので、PILOTを導入するところからやってみます。

##下準備

まずは[ここ](https://github.com/hundredrabbits/pilot)からPILOTをインストールします。
PILOTとORCΛをそれぞれ起動します。これだけで、連携するための設定などは特に必要ありません！

##リズムパターンを作る

ではORCΛで以下のような単純なキックの4つ打ちから作ってみます。
｜ * _ _ _  ｜ * _ _ _  ｜ * _ _ _  ｜ * _ * _  ｜

4回目だけちょっとバリエーションをつけているイメージが伝わるでしょうか。
これを実装する方法は色々考えられますが（答えがひとつではない所がORCΛのパズル的な面白みですね）
今回は以下のようにしてみます。


![drum.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250171/f3f8c771-5641-25ca-777e-ecf9541fd7c7.jpeg)

右下の「;C1C」という部分がPILOTをコントロールするための情報で、それ以外の部分はbangのパターンを生成するためのオペレータです。（オペレータの扱いについては[前回](https://qiita.com/rucochanman/items/98a4ea988ae99e04b333)の記事を参照）
具体的には、「;」にbangが当たる毎に「C1C」というコマンドをPILOTに送信することで、PILOT側で音を出しています。
PILOTに送るコマンドは、
・チャンネル番号（0～Fのチャンネルごとに異なる音色がアサインされている/ここで音の種類が選べる）
・オクターブ
・ノート番号
・音量
・音の長さ
の順番になっています。
今回の例（C1C）の場合は、チャンネルはCを選択、低い音にするためオクターブは１を指定（数字が上がればオクターブが上がる）、音程はC（ド）（ちなみに半音は小文字で表現）、音量と音の長さは指定していないためデフォルト、という命令を送っていることになります。

続いて、パーカスというか、上モノ的な用を作っていきます。
これはランダムなパターンで音が鳴るようにしてみます。

![perc.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250171/3857a60e-ca3d-8dce-7df6-7bbb20259bf1.jpeg)

bangのタイミングと、PILOTへのコマンドの音量をランダム（R）で決定しているのがわかるでしょうか。

##Eを発射する

最後にリードメロディ的な部分を作っていきますが、ヴィジュアル表現に優れたORCΛのインターフェースを生かすべく、動的な要素を使ってみます。ORCΛには各東西南北の方向に移動していくオペレータ（EWSN）があるので、この中から東に移動していくEを使って、ランダムなアルペジエーター？的な機能を作ってみます。

![lead.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250171/b0feb926-22db-cf6c-cd1d-6002cf6b484a.jpeg)

発射されたEが各コマンドに当たったときに音が出ているのが分かるでしょうか。

以下は自分の環境で実際に動かしてみた映像です。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">チュートリアル向けデモ <a href="https://t.co/U8VGtmcbKc">pic.twitter.com/U8VGtmcbKc</a></p>&mdash; г ∪ ⊂ о (@rucochanman) <a href="https://twitter.com/rucochanman/status/1121036388122550274?ref_src=twsrc%5Etfw">2019年4月24日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


以上で一通り演奏っぽいことを試すことができました。
これを書いている間にも、ORCΛはすごいスピードでアップデートを進めているので、また便利なtips的なものがまとめられたら記事にしたいとおもいます。
最新ログを逐次表示するコマンド

# 概要
処理が終了するたびにログファイルを生成するサービスを監視していました。通常はtailコマンドでログファイルをリアルタイム表示しますが、処理が終了するたびにログファイルが生成されるため上手く行きません。そこで、リアルタイムでばなく逐次表示させることで解決しました。

# 目的
watchコマンドで最新ログファイルを逐次表示するコマンドを組み立てます。

# 作業
```
$ watch -n <secs> tail -n <lines> '$(ls -r | head -n 1)'
```

# 最後

以外とシンプルなコマンド群で実現可能です。
AWS Glacier での破産は「過去の話」ではなかった件（90日以前削除課金）

**(2019/04/26) いただいたコメントに基づいて、わかりずらい表現を修正・補足しました。**

AWS Glacier は、大容量データのアーカイブ先として大変重宝します。

2016年11月以前までは「ピーク復元レート」の考え方に基づき、短時間でのデータ取り出しにより高額請求されるリスクがありましたが、改訂後は大幅な値下げとなり、使いやすくなりました。詳細は、以下のサイトが大変わかりやすいです。

[Amazon Glacierで高額料金請求は「過去の話」になりました]
(https://digital-chiebukuro.com/aws/amazon-glacier-kaizen/)

## 「過去の話」ではなかった件

ある日のこと、Glacier の利用料がたった一日で、月額の 1/3 を占めることになりました。
あわてて明細をみると「Glacier：最小期間追加料金」の文字が。

そう、課金の前日、Glacier 上の不要なファイルを一括削除したのでした。
3ヶ月経過する前の、若いファイルも、なにもかも。

あわてて調べた結果、以下の Q&A が見つかりました。

[Q: 3 か月経過前にデータを削除した場合は、どのように請求されるのですか?]
(https://aws.amazon.com/jp/glacier/faqs/#How_am_I_charged_for_deleting_data_that_is_less_than_3_months_old)

> Amazon S3　Glacier は、データを月単位や年単位で、あるいはそれ以上の長期にわたって保持するという用途のために設計されています。Amazon S3　Glacier からデータを無料で削除できるのは、削除されるアーカイブが 3 か月以上保管されていた場合です。アップロードされてから 3 か月未満でアーカイブを削除する場合は、早期削除料金をいただきます。米国東部 (バージニア北部) リージョンでは、3 か月未満で削除された場合の早期削除料金は 0.012 USD/GB を按分計算したものとなります。そのため 1 GB のデータをアップロードの 1 か月後に削除すると、早期削除料金の 0.008 USD が課金されます。1 GB のデータを 2 か月後に削除した場合は、早期削除料金は 0.004 USD となります。

## 「90日以前削除課金」という罠

Glacier は長期保管ニーズに応えるもの。そのため「最低保存期間=90日間」と定められています。
**それより前に削除すると、「最低保存期間までの残日数」分の保管料金がその時点で課金されてしまいます。**

今回の場合、とあるシステムのフルバックアップデータを日次で保管していました。
データサイズがほぼ同一のファイルが 90 日分。これらを一気に削除しました。課金額は以下の計算式で表現されます。

```math
 \sum_{d=1}^{90} m_{d} * \frac{(90 - d)}{90} * 0.012_{USD} \sim m * 0.012 * 90 / 2 = 0.54 m _{USD}
```
* m: 対象データのサイズ(GB)
* d: Glacier に保管してからの経過日数
* 0.012 USD : バージニア北部リージョンでの早期削除課金係数（保存初日の場合）

データサイズが 1TB とすると、1ドル 110 円換算で、約 60,000 円となります。

## 早期削除しても90日保管しても総額は変わらないのでは？

コメントで指摘いただいたとおり、90日放置しても総額は変わりません。一方、
　**「早期削除に伴い、本来 3 か月分割支払いのところ、ひと月にまとめて請求されてしまう」**
という弊害が生じます。お仕事などで月額の予算上限がある方はご注意ください。

## まとめ：Glacier は「取り出し行為」で課金されるという思い込み

削除する行為で課金されるとは夢にも思いませんでした。

リアルに破産するほどの額ではなかったのが不幸中の幸いですが
お仕事で確保していた予算を大幅に超えてしまい、偉い人への説明に難儀しました。

Glacier を利用する際は、張り切ってお掃除しないよう、ご注意ください。
Tensorboard（Graph）覚書

<!---
# Tensorflowとは
--->

TFのwrapperであるkerasを使い、Fashion-MNISTを分類する、MLP（中間層が1層）を構築した。TFのグラフを理解するため、Tensorboardを活用した。

今回、Tensorboardを使って、うまくできなかったところは、tf.Placeholderやtf.Variableをわかりやすく表示すること。やり方が分かったら、アップデートすることにする。

## Tensorboardを使って可視化した、TFグラフ
![20190424-113909.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253276/40d5cd0c-4b56-eaed-2b89-d79b03094e8f.png)

###`flatten`: 入力値を1次元化(flatten)する
全結合層（Dense layer）に流し込むために、1次元にする必要がある。
(nbatch, 28, 28)→(nbatch, 784)

`flatten_input`を`flatten`のノードに入力する。
![20190424-_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253276/7d11a8ad-5145-38f3-180e-db2bf74023a0.png)

`flatten`のボックスをクリックすると、右側に`flatten`ノードの詳細情報を見ることが出来る。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253276/25517202-f0de-4acb-f062-1e4201b6742e.png)

- `Subgraph: 4 nodes`: `flatten`ノードをクリックしていくと、ノード内のグラフ（４つのノードからなる）を見ることができる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253276/30806512-d0ae-5d5b-4f39-53f79fb031fe.png)

- `Inputs (1)`: インプットは`flatten_input`のみ。
- `Outputs (2)`: `dense`ノード（ロスを計算するため）と`training`ノード（中の`Adam`ノードに渡される。自動微分で必要であるためか？）

###`dense`→`dropout`→`dense1`：全結合層（+Relu活性化）→ドロップアウト→出力層（+Softmax活性化）
このアーキテクチャーは、入力層が１つ、中間層（ドロップアウト有）が１つ、出力層が１つ、のMLP。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253276/433328dd-61e3-33ae-337a-14834a56c567.png)

`dense`layer

- `Matmul`ノード：`flatten`ノードのアウトプットと、`kernel`ノードのアウトプット（重みW）を掛ける。
- `BiasAdd`ノード：`Matmul`ノードのアウトプットと、`bias`ノードのアウトプット（バイアスb）を足す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253276/3687d28f-cb60-98fe-079a-a76004b97747.png)

`dropout`layer

- `cond`ノード：たぶん、ドロップアウトするかどうかの条件（conditionを適用するノード）
- `keras_learning_phase`ノード：ドロップアウトするMLPのノードを決めるための乱数をアウトプットしているはず。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253276/6960a9f5-e21f-4bac-ad7f-e7d25833e4fc.png)

`loss`ノード
詳しくはわからないが、cross entropyを計算しているはず。出力は`training`ノードに入力しており、`Adam`Optimiserを使って、訓練が行われる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253276/75d934a8-898f-2a4f-7ff0-26eaf9036b4a.png)
JavaScript  ランダム　整数　覚書

###0~1未満のランダム値
```js
Math.random() 
```

###小数点以下切り捨て
```js
Math.floor
```

##ランダムな整数値
```js
// 0,1,2 のランダムな整数値
Math.floor(Math.random() * 3)

// 0.....n　のランダムな整数値
Math.floor(Math.random()*(n + 1))

// min.....max　のランダムな整数値
min + Math.floor(Math.random()*(max + 1 - min ))
```
csvをTreasureDataに取り込んでエクセルの代わりに使う。

普段の業務で、csvを処理する事が多い。

色々なシステムから出力されるcsvは、文字コードがShift-JISだったり、UTF8だったり、UTF8のBOM付きだったり、文字コードがバラバラで、excelで文字化けせずに開けるCSVファイルと文字化けするCSVがある。

なので、excelで開くために、テキストエディタで文字コードを変更したりする。

面倒で、numbersで開いたりもする。

エンジニアといっても、excelを使いこなす事ができる訳でもなく、フィルターくらいしか使っていない。

集計も、excelの関数を覚えていないので、本当に面倒。

そのフィルターや集計結果も疑心暗鬼。

今まで、csvを使って複雑な処理をするときは、データベースにインポートしたり、nodejs、java, phpなどプログラミングツールを使ってプログラミングで処理をしていた。


treasuredataを導入してからは、s3にcsvをアップ、Embulkでcsvのインポート処理の設定を吐き出して、treasuredataにcsvインポートでデータベースのテーブルを作って、SQLでフィルターや集計をしている。

treasuredataが、schemaレスのDBなので、ほぼ何も考えず、いい感じデータベースにcsvのデータを流し込めるところがいい。

面倒なインポート設定は、Embulkが勝手に作ってくれる。s3にアップしたcsvを参照するseedファイルを作って、Embulkでインポート設定ファイルを作って、treasuredataのworkflow に食わせる。文字コードもいい感じで処理してくれる。

Embulkは、一行コマンド。

あとは、treasuredataのworkflow を実行して、csvをデータベースに流し込んで、作成されたデータベースに、SQLを実行する。

SQLの結果は、csvでダウンロードする事も出来るので、excelのフィルター的な使い方にいい。

treasuredataのSQLは、数行のテストデータでも、数万行の本番データでも同じくらいのスピードで処理してくれるのでいい。

常に本番データを使って色々試せる。

あと、treasuredataで作業すると、SQLなどが残るという事。excelで色んな関数使って、何やってるかわからなくなることがなくなる。

SQLなので、自分が書いたフィルターや集計処理の結果も安心感がある。

シェアも出来てレビューも出来る。
わからなくなったら、treasuredataに質問できる。

これは、
treasuredataのイレギュラーな使い方。
でも本当に便利。
PHPでクエリパラメータから配列を受け取る物語

#クエリパラメータで配列を渡してぇ（唐突
ある時、理由は忘れちまったが俺はそう思ったんだ。
思い立ったが吉日、すぐに旅に出たんた。

##単純に配列書いちまえば良いんじゃねぇか？

```
http:www.sakdor.net?var=[1,2,3]
```

varという変数は配列、そう書いちまえば良い。
俺はそう思ってたから旅支度は簡単にしていて
日帰りのつもりだったんだ。
でも甘かった、この旅は短くは無い。
PHPで`$_GET`を`var_dump`してみると…

```PHP
array(1) { ["var"]=> string(7) "[1,2,3]" }
```

と表示される。
そう、`var`は`[1,2,3]`という文字列が入った、ただの変数だ。

##じゃぁ逆転の発想をしてしまえ
最初に訪れた街を出て一ヶ月はたっただろうか
悩み続けた先に、ある1つの閃きが生まれた。
「$varという配列に代入したら良いのではないか？」
ということだ。

```
http:www.sakdor.net?var[0]=1&var[1]=2&var[2]=3
```

結果はこうなった

```PHP
array(1) { ["var"]=> array(3) { [0]=> string(1) "1" [1]=> string(1) "2" [2]=> string(1) "3" } }
```

無事にvarという配列が出来上がっている！！

##研究を重ねた末に
奇跡の大発明で満足しなかった俺は
更に旅を続けて、研究に研究を重ねた。
すると新しい発見がみつかった。

- 連想配列もクエリパラメータから受け取れる

```
http://www.sakdor.net/test/?var[a]=1&var[b]=2&var[c]=3
```

こういう感じにURLを書くことで

```PHP
array(1) { ["var"]=> array(3) { ["a"]=> string(1) "1" ["b"]=> string(1) "2" ["c"]=> string(1) "3" } }
```

連想配列を受け取ることが出来るのを発見した。
ちなみに`?var["a"]=1`とURLを書くと出力は`array(1) { ["var"]=> array(1) { [""a""]=> string(1) "1" } }`となってしまう。

- keyが無くても代入出来る。

```
http://www.sakdor.net/test/?var[]=1&var[]=2&var[]=3
```

こういう感じにURLを書くことで

```PHP
array(1) { ["var"]=> array(3) { [0]=> string(1) "1" [1]=> string(1) "2" [2]=> string(1) "3" } }
```

URLの左から右の順で配列に格納される。

##引き算されたスマートなものへ
旅を終え、自宅へ帰った。
研究が世に認められ、俺は富と名声を得た。
だが、なんだろうか、この虚しさは。
全てを知り尽くしたからだろうか。
次に私は何を求めれば良い？

答えはすぐに見つかった。
追い求め足し算するのはやめにしたんだ。

```
https://www.sakdor.net/test/?var=1,2,3
```

そうコレでよかったんだ。
「これでは1,2,3という文字列じゃないか」って？

```php
$array=explode(",",$_GET[var]);
```

こうすれば良いのさ。
そうしたら

```php
array(3) { [0]=> string(1) "1" [1]=> string(1) "2" [2]=> string(1) "3" }
```

出来上がりだ。

何も仰々しくURLを書かなくたって良い。
ありのままの姿で良いんだ。

#編集後記
入社18日目
俺は一体何を書いているんだ？？？
初心者にわかりやすいレスポンシブデザインとメディアクエリ

##概要
　アルバイトの業務として、久しぶりにCSSを書いていて、その中でレスポンシブデザインにするためにメディアクエリを書いていて、改めてサイトをレスポンシブにすることは重要で、メディアクエリって便利だな〜と思いましたので、まとめていこうと思います。

##レスポンシブデザインとは
**レスポンシブデザイン**とは、
>
閲覧者の画面サイズまたはウェブブラウザに応じてデスクトップウェブページが閲覧できることを目指したウェブデザインの手法

　つまりは、どんな大きさの画面でも見やすく、使いやすいWebサイトにするために必要なもので、一つのHTMLに対してデバイス毎にCSSを変更してやるということです。


　極端な例で言うと以下のように、CSSを分けることによって、スマホでは赤色の文字で、タブレットでは青色の文字で、パソコンでは緑色の文字で表示することが可能になるのです。![responsive.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395817/1b60130a-4f5b-f7d7-890a-fc07ff86efd8.png)

##メディアクエリとは
　レスポンシブデザインにするには、様々なやり方があります。その中の一つの方法がメディアクエリです。
　メディアクエリの細かな構文は[MDN web docs](https://developer.mozilla.org/ja/docs/Web/CSS/Media_Queries/Using_media_queries)と言う有名なサイトに任せて、ここでは実際に簡単なレスポンシブデザインを作成したいと思います。

###デモ
　以下はhtmlとcssだけの非常に優しいサンプルコードです。
<img width="519" alt="スクリーンショット 2019-04-24 21.10.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395817/8e3de68d-3dab-10f1-9cca-068fd6feab47.png">
<img width="683" alt="スクリーンショット 2019-04-24 21.12.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395817/fadc60e6-cd3b-0069-e1ce-b163fc49217b.png">

###結果
　以下は以上のコードを実行した結果になります。
　画面の幅が**0~479px**の時は**赤色**で表示され、画面の幅が**479px~767px**の時は**青色**で表示され、画面の幅が**767px以上**の時は**緑色**で表示されます。
<img width="1023" alt="スクリーンショット 2019-04-24 21.01.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395817/9dc7fb90-7f1b-7f73-40bf-2931c2fd5029.png">
<img width="1106" alt="スクリーンショット 2019-04-24 21.01.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395817/b36be20f-f30d-9c7b-05c1-c346cec72696.png">
<img width="1140" alt="スクリーンショット 2019-04-24 21.01.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395817/a86494af-9815-2556-eec7-e7a77f0c8c68.png">

##終わり
　今回はレスポンシブデザインとは何？レベル人向けの記事となりましたが、サイトをレスポンシブにしてUI/UXを高めることは非常に重要なことです。
　また、メディアクエリについては詳しくは説明しませんでしたが、こちらのMDNのサイト[MDN web docs](https://developer.mozilla.org/ja/docs/Web/CSS/Media_Queries/Using_media_queries)に詳しく構文や関連情報が載っているの見てみてください。
　次回はもう少しメディアクエリを使った難易度の高いことに挑戦して記事を書いてみたいと思います。

##参考
　https://developer.mozilla.org/ja/docs/Learn
　https://digitalidentity.co.jp/blog/creative/responsive-web-design.html
今年の言語はRust その３６

# 今年の言語はRust その３６

Rustを学びます

Rustの日本語ドキュメント 2nd Edition
https://doc.rust-jp.rs/book/second-edition/

オリジナル(英語)
https://doc.rust-lang.org/book/


## 実行環境

```sh
$ cargo -V
cargo 1.33.0 (f099fe94b 2019-02-12)

$ rustup -V
rustup 1.17.0 (069c88ed6 2019-03-05)

$ rustc --version
rustc 1.33.0 (2aa4c46cf 2019-02-28)

$  cat /proc/version
Linux version 4.14.97-74.72.amzn1.x86_64 (mockbuild@gobi-build-64002) 
(gcc version 7.2.1 20170915 (Red Hat 7.2.1-2) (GCC)) 
#1 SMP Tue Feb 5 20:59:30 UTC 2019

$ uname -a
Linux ip-10-100-0-8 4.14.97-74.72.amzn1.x86_64 
#1 SMP Tue Feb 5 20:59:30 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

$ cat /etc/\*release
NAME="Amazon Linux AMI"
VERSION="2018.03"
ID="amzn"
ID_LIKE="rhel fedora"
VERSION_ID="2018.03"
PRETTY_NAME="Amazon Linux AMI 2018.03"
ANSI_COLOR="0;33"
CPE_NAME="cpe:/o:amazon:linux:2018.03:ga"
HOME_URL="http://aws.amazon.com/amazon-linux-ami/"
Amazon Linux AMI release 2018.03

```

## 13. 関数型言語の機能: イテレータとクロージャ

### 13.2 一連の要素をイテレータで処理する

```rust
let v1 = vec![1, 2, 3];

let v1_iter = v1.iter();

for val in v1_iter {
    // {}でした
    println!("Got: {}", val);
}
```


#### Iteratorトレイトとnextメソッド


```rust
pub trait Iterator {
    type Item;
    
    fn next(&mut self) -> Option<Self::Item>;
}
```



```rust
#[test]
fn iterator_demostration() {
    
    let v1 = vec![1, 2, 3];
    
    let mut v1_iter = v1.iter();
    
    assert_eq!(v1_iter.next(), Some(&1));
    assert_eq!(v1_iter.next(), Some(&2));
    assert_eq!(v1_iter.next(), Some(&3));
    assert_eq!(v1_iter.next(), None);
}

```

#### イテレータを消費するメソッド

```rust
#[test]
fn iterator_sum() {
  let v1 = vec![1, 2, 3];

  let v1_iter = v1.iter();

  let total: i32 = v1_iter.sum();

  assert_eq!(total, 6);
}

```

#### ほかのイテレータを生成するメソッド

```rust
let v1: Vec<i32> = vec![1, 2, 3];

v1.iter().map(|x| x + 1);

```

```rust
fn main() {
    
    let v1: Vec<i32> = vec![1, 2, 3];

    let v2: Vec<_> = v1.iter().map(|x| x + 1). collect();
    
    assert_eq!(v2, vec![2, 3, 4]);

}
```

眠たすぎる
ちょっと手抜き



イエス！
Luaコードを評価するVSCode Extensionを作りました

# 開発したVSCode Extensionの紹介
選択中のコードをLuaコードとして評価した値に置き換えます。
![eval.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275289/6cc9edd1-76bc-4b1b-517c-725690a9880b.gif)

### DLページ
https://marketplace.visualstudio.com/items?itemName=Y0KUDA.lua-eval

### リポジトリ
https://github.com/Y0KUDA/vscode-lua_eval


# コード解説
Luaの評価にはfengariを使っています。JavaScriptで実装されたLuaVMです。
https://fengari.io/

```typescript
import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {

	// Luaを評価するために必要なモジュールをロード
	const lua = require('fengari/src/lua.js');
	const lauxlib = require('fengari/src/lauxlib.js');
	const lualib = require('fengari/src/lualib.js');
	const { to_luastring } = require("fengari/src/fengaricore.js");

	// 文字列をLuaコードとして評価し、評価した値を文字列で返す関数
	// fengari のテストコードを見て適当に作ったので、仕組みはよくわかっていない・・・
	function eval_as_lua_code(code: string): string {
		let L = lauxlib.luaL_newstate();
		lualib.luaL_openlibs(L);
		lauxlib.luaL_loadstring(L, to_luastring(code));
		lua.lua_call(L, 0, -1);
		return lua.lua_tojsstring(L, -1);
	}

	//　コマンド lua_eval.replace を定義
	let disposable = vscode.commands.registerCommand('lua_eval.replace', () => {
		// 現在アクティブなエディタを取得
		const editor = vscode.window.activeTextEditor;
		if (editor !== undefined) {
			// エディタ上の選択領域を取得する
			const selections = editor.selections;
			// エディタを編集するためにコールバックを渡す
			editor.edit(builder => {
				// 全ての選択領域を順番に処理していく
				for (const selection of selections) {
					// 選択領域のテキストを取得する
					var text = editor.document.getText(selection);
					// 選択領域のテキストを、Luaコードとして評価したものと置き換える
					builder.replace(selection, eval_as_lua_code(text));
				}
			});
		}
	});

	context.subscriptions.push(disposable);
}

export function deactivate() { }

```

似たようなExtensionを開発するときに参考にしていただければ幸いです。
第1,第3,第5月曜日の午前中・・・的なスケジュールをGoogle カレンダーに登録する

第1、第3、第5の月曜日の9時～12時といったスケジュールが多いのだが、Googleカレンダーで繰り返し予定として登録するのは無理だ。1年分登録するとなると25回も繰り返す羽目になるし、このような予定が数種類あるので途方もない作業量になる。面倒なことはPythonにさせてみよう・・・・ということで書いてみた。
GoogleカレンダーAPIにアクセスするのは面倒なので、GoogleカレンダーにインポートできるCSVファイルを作るのを目標とする。

```
import pandas as pd
import datetime


def generate_appoints(start, end, weekday, odd, start_time, end_time, offset_days = 0):
    """
    start, endの間で条件に合うdatetime.datetimeのタプルを返す。
    
    start, end: datetime.date
    weekday: int datetime.date.weekday()の戻り値で曜日を指定
    odd: bool 奇数週ならTrue
    start_time, end_time: datetime.time()
    offset_days: int 指定日の前日なら1
    """
    dates = [start + datetime.timedelta(days = x) for x in range(0, (end - start).days)]
    wdays = list(filter(lambda x: x.weekday() == weekday, dates))
    wdays_select = list(filter(lambda x: ((x.day-1) // 7 + 1) % 2 == odd, wdays))
    # 偶数、ないし奇数週の日付を抽出する　x.day から1を引かないとxx月7日の判定がおかしくなる

    start_dt = [datetime.datetime.combine(x - datetime.timedelta(days = offset_days), 
                                      start_time) for x in wdays_select]
    end_dt = [datetime.datetime.combine(x, end_time) for x in wdays_select]

    return (start_dt, end_dt)
```

`generate_appoints()`は条件に合う`datetime.datetime`のタプルを返してくれる。これを`pd.DataFrame`に整形する。

```
def generate_pd(subject, tp):
    """
    開始日、終了日のタプルを受け取りpd.DataFrameを作る
    """
    df = pd.DataFrame({"Subject": subject,
                             "Start Date": [x.date() for x in tp[0]],
                             "Start Time": [x.time() for x in tp[0]], 
                             "End Date": [x.date() for x in tp[1]],
                             "End Time": [x.time() for x in tp[1]]})
    return df
```

試しに第1，3，5月曜日のhoge1と第2、第4金曜のhoge2の予定表を作ってみる。

```
if __name__ == "__main__":
    start = datetime.date(2019, 6, 3)
    end = datetime.date(2020, 3, 31)
    hoge1 = generate_appoints(start, end, 1, True, datetime.time(18, 0), datetime.time(19, 0), 1)
    hoge2 = generate_appoints(start, end, 4, False, datetime.time(9, 0), datetime.time(15, 30))
    hoge1_df = generate_pd("hoge1", hoge1)
    hoge2_df = generate_pd("hoge2", hoge2)
    final = hoge1_df.append(hoge2_df)
    final.to_csv("2019_appointments.csv", encoding = 'utf_8_sig', index = False)
```

出力されたCSVをGoogleカレンダーにインポートすると狙った通りに予定が登録されている。ただ、祝日や代休のことは考慮されていない。手動で消すのは大した手間でないのでまあいいだろう。
kaggle 音コンペに挑戦

 [Freesound Audio Tagging 2019](https://www.kaggle.com/c/freesound-audio-tagging-2019)
挑戦していますが、データ読み込みが何をやっているのかわからないので色々と調べて見ました。

このkernelを参考にしています。
https://www.kaggle.com/maxwell110/beginner-s-guide-to-audio-data-2

```
import wave
wav = wave.open(fname)
print("Sampling (frame) rate = ", wav.getframerate())
print("Total samples (frames) = ", wav.getnframes())
print("Duration = ", wav.getnframes()/wav.getframerate())
```

ここにある  wave.getframerate()は何をやっているのだろう。。
リファレンスには
Wave_read.getframerate()
　　　　サンプリングレートを返します。
とあります。

サンプリング・レートとは...
アナログ信号をデジタルで表現する場合に、アナログの電圧をチェックする1秒あたりのサンプル数。この数値が大きいほど、アナログ信号をより正確に表現できる。CDには44.1kHzのサンプリング・レートが採用されており、この場合、毎秒44,100回のアナログ信号をチェックしている。

つまり音波のサンプリング間隔らしい。
青い点の間隔がサンプリングレート。
![alt](https://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Pcm.svg/500px-Pcm.svg.png)
これが音の特徴になるのは驚きですね。
jsで未定義の変数を含むテンプレート文字列を定義する


ES6には、テンプレート文字列（Template literal）という便利な構文があります。

> Template literal は組み込み式を扱うことができる文字列リテラルです。

（[テンプレート文字列 - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/template_strings)より）

テンプレート文字列は`${}`を用いて文字列中に変数（というか式）を挿入することができます。

```javascript
const a = 456;
const b = `123${a}789`;

console.log(b); // -> 123456789
```

当たり前なのですが、上の場合、aが前もって定義されてない場合、エラーを起こします。
でも「テンプレート」ってそうじゃないじゃん。
後から定義できてこそのテンプレートじゃん。

....という人たちのための書き方があります。
手っ取り書くと以下になります。

```javascript
// 未定義テンプレート文字列関数
const tmpl = raws => (...subs) => String.raw(raws, ...subs);

// テンプレートを定義
const gt = tmpl`12${0}56${0}`;

console.log(gt());       // -> 1256
console.log(gt(34));     // -> 123456
console.log(gt(34, 78)); // -> 12345678
```

最初にタグ関数を処理するための関数（tmpl）を定義しておき、これを使ってテンプレート（gt）を作ります。
あとは関数として呼び出して引数に入れたいものを入れるだけです。
引数を指定せず呼んだ場合は、その部分は無視されます。

これを使えば、

```javascript
const gt = tmpl`
  <dl>
    <dt>${0}</dt>
    <dd>${0}円</dd>
  </dl>
`;
```

みたいなHTMLのテンプレートを前もって定義しておいて、後から変数を指定して使いまわしたり、ということができるようになります。
ただ、変数部分がいっぱいある時は、それを順番に入れていかなくてはならないのが不便ですが....。