OmniAICreator/Qiita-1.07M huggingface dataset:
SourceTreeを使った差分抽出、最終版【macOS】

受託案件をやっていると
**「差分で納品ファイルください」**
と言われることが多いと思いますが、
その時の納品ファイルを一発で作る方法。

私は、GitクライアントソフトにSourceTreeを使っているので、
以下のICSさんの記事を元に納品ファイルを作っています。

https://ics.media/entry/4475/

**今回の記事は、上記の記事の設定を少しカスタマイズしたものになります。**

いつも上記の方法で差分データを作成してから
さらに**２つの工程**を手動で行ったのち
クライアントにデータを納品していました。

(1). SourceTreeの「カスタムアクション」で差分のzipファイルを作る → **[スクリプト]**
(2). zipのデータからhtdocsのデータだけを抜き出す → **[手動]**
(3). (2)のデータを日付のフォルダに格納して、zipにする → **[手動]**

これは、イケていないのでなんとか自動化して、
そのまま納品ファイルを送りたいものです。。

## (a).差分データからhtdocsのデータだけを抜き出す

これがgitで管理している、
私のプロジェクトのルートのファイル群です。

```
webpack.config.js
tasks
src
README.md
path.config.js
package.json
package-lock.json
node_modules
htdocs // 納品するのはこいつだけ
.prettierrc
.node-version
.gitignore
.git
.eslintrc
.editorconfig
```
実際にクライアントに納品するのって、htdocs以下だけなんですよね。
でも、差分には当然それ以外の開発データが含まれてしまいます。
なので、
**htdocsだけをzipに入れて、それ以外のファイルは含めない**必要があります。

## (b).日付のフォルダに格納して、zipにする

納品って、大抵１度ではなく、多い時は、同じ日に何回もする場合があります（これが地獄）。
ですが、毎回「archive.zip」という名前だと、
送られた方はバージョンに混乱してしまい、間違ったデータをサーバーに上げてしまうことも考えられます。

なので、私は
「data_20200401.zip」
「data_20200401-2.zip」
のようにわかりやすいようにリネームして送っていました。
これも正直辛いです。。

## (a)(b)の処理も自動化する

というわけで、シェルスクリプトに改良を加えてみました。

```export_diff_zip.sh
#!/bin/sh

# ファイル名を指定
FILE_NAME=`date '+data_%y%m%d_%H%M%S.zip'`

# 古→新の順番じゃないとファイル削除の場合などにエラーになる [例] $1 HEAD, $1 $2

if [ "$2" = "" ]; then
	# コミットハッシュが１つの場合
	git archive master:htdocs --format=zip -o $FILE_NAME --prefix=htdocs/ `git diff --name-only --relative=htdocs --diff-filter=AMCR $1 HEAD`
else
	# コミットハッシュが2つの場合
	git archive master:htdocs --format=zip -o $FILE_NAME --prefix=htdocs/ `git diff --name-only --relative=htdocs --diff-filter=AMCR $1 $2`
fi

```
まず、スクリプトの

```sh
master:htdocs
```
と

```sh

--relative=htdocs
```
のところで、対象ディレクトリを指定しています。
このままだと、zip内にhtdocsは含まれないので

```sh

--prefix=htdocs/
```
を指定しています。
あとは、日付です。

```sh

# ファイル名を指定
FILE_NAME=`date '+data_%y%m%d_%H%M%S.zip'`
```
ここで、タイムスタンプをそのままファイル名に反映しています。

この設定でカスタムアクションを走らせると、、

**data_yymmdd_hhmmss.zip　→　data_200506_215510.zip**

のように、タイムスタンプのzipが作成され、
解凍すると、htdocsからファイルが展開されます。

終わりです。

# 参考記事
https://qiita.com/hironaito/items/9b5135698ea1a497a3c0
https://qiita.com/nyamogera/items/04f5b8c6a7ab6c860f29
https://qiita.com/usamik26/items/9a2d14aea30cb01a60c6
form_with url指定(ネストしてるとき)

初投稿です。よろしくお願いします。

スクールでECサイトのチーム開発をしているときに出た不明点の備忘録です。

# ネストしてるときのform_with url指定
form_withのurlオプションでidを2つ指定すると正常に値が渡されて動くようです。
今回はorderとorder_itemが1対多の関係になっています。
また、admin_order_order_item_pathはorder_itemをupdateする際の名前付きルートです。

```orders_controller.rb
def show
    @order = Order.find(params[:id])
    @order_items = OrderItem.all.includes(:item)
    @order_item = OrderItem.find(params[:id])
end
```

```order/show.html.erb

<% @order_items.each do |order_item| %>

<%= form_with(model:[order_item], url: admin_order_order_item_path(order_id: @order.id, id: order_item.id)) do |f| %>
        <%= f.select :production_status, [["着手不可","着手不可"],["製作待ち","製作待ち"],["製作中","製作中"],["製作完了","製作完了"]] %>
        </td>
        <td><%= f.submit "更新" %></td>
        <% end %>
```

↑ブラウザに表示されるurlがorder/:order_id/order_item/:id のようになるため、
url: admin_order_order_item_path(order_id: @order.id, id: order_item.id)というふうに前から順番にidを指定する必要があります。

```order_items_controller.rb
class Admin::OrderItemsController < ApplicationController
  def update
    
    order_item = OrderItem.find(params[:id])
    order_item.update(order_item_params)
    redirect_to admin_order_path(order_item.order_id)
  end

  private
  def order_item_params
    params.require(:order_item).permit(:production_status)
  end
end
```

form_withがeach文の中の@order_itemsでorder_itemのidを持ってきているので、そのidをorder_item = OrderItem.find(params[:id])の(params[:id])に入れてOrderItemモデル内を検索し、該当レコードをupdateして完了。


##余談
ちなみに、メンターさんに教えてもらう前までは、以下のように記述して、なぜか思った通りに動いてはいるもののターミナルに出ているパラメータの数値がなんかおかしい・・・という状態になっていました。

(例えばorder_id:1の中にあるorder_item_id:5を更新したい場合)

```orders_controller.rb
def show
    @order = Order.find(params[:id])
    @order_items = OrderItem.all.includes(:item)
    @order_item = OrderItem.find(params[:id])
end
```

```order/show.html.erb

<% @order_items.each do |order_item| %>

<%= form_with(model:[order_item], url: admin_order_order_item_path(order_item.id)) do |f| %>
        <%= f.select :production_status, [["着手不可","着手不可"],["製作待ち","製作待ち"],["製作中","製作中"],["製作完了","製作完了"]] %>
        </td>
        <td><%= f.submit "更新" %></td>
        <% end %>
```

admin_order_order_item_path(order_item.id)の部分では、
order_item_idの(5)が入っていますが、本来であれば、順序的にはorder_idが入らないといけないので、それが次の
.find(params[:order_id])の部分に入ります。(当初.find(params[:id]としていましたが、idが見つからないというエラーが出てしまったため、いろいろ試して苦し紛れで[:order_id)としたら動いてしまいました。)


```order_items_controller.rb
class Admin::OrderItemsController < ApplicationController
  def update
    
    order_item = OrderItem.find(params[:order_id])
    order_item.update(order_item_params)
    redirect_to admin_order_path(order_item.order_id)
  end

  private
  def order_item_params
    params.require(:order_item).permit(:production_status)
  end
end
```
order_item = OrderItem.find(params[:order_id])の[:order_id]に(5)が入り、OrderItemモデルの中の5番目のレコードを探して order_itemに入れてupdateしています。
これでこれで思惑通り5番目のレコードが更新されました。が、

ターミナルを見ると、

```ターミナル.
Parameters: {(略}, "commit"=>"更新", "order_id"=>"5", "id"=>"1"}
```
となっていて、
(あれ、"order_id"=>"1", "(order_item_)id"=>"5"が正しいよな・・・　なんで・・・？)
と思って調べても出てこず、メンターさんに教えていただき10分で解決しました。

#まとめ
調べるまでもなく基本事項だったのかもしれませんが、勉強になりました。
点と線分との最短距離(sympyの行列)

# 参考

https://qiita.com/Kyome/items/3fad4253c62bedb620c7

https://qiita.com/kkdd/items/b3c5e06798e59fe2768e

~~# 参考 点と線分の距離を求める~~
~~https://qiita.com/boiledorange73/items/bcd4e150e7caa0210ee6~~

# 参考 wikipedia

点と直線の距離＞直線が通る2点によって定義された直線

https://ja.wikipedia.org/wiki/%E7%82%B9%E3%81%A8%E7%9B%B4%E7%B7%9A%E3%81%AE%E8%B7%9D%E9%9B%A2#直線が通る2点によって定義された直線

間違っていたら、すいません。
もっと短くなる気がします。

```
# 点と線分との最短距離(sympyの行列)
from sympy import *
var('x0 y0 x1 y1 x2 y2 c s tx ty d sx sy')
d=sqrt((x1-x2)**2+(y1-y2)**2)
v=solve([c*0-s*0+tx-x1,s*0+c*0+ty-y1,c*d-s*0+tx-x2,s*d+c*0+ty-y2],[c,s,tx,ty])
A=Matrix([
      [v[c],-v[s],v[tx]],
      [v[s], v[c],v[ty]],
      [0   ,    0,    1]
   ])
B=Matrix([
       [x0],
       [y0],
       [ 1]
])
AinvB=A.inv()*B
sy=AinvB[1].subs([(c**2 + s**2,1)])
print(sy)
#結果省略
```
# 左右の判定にも使えます。
具体的に数値を入力してみました。行列の座標変換です。

(参考)

https://qiita.com/hotoku/items/e768c7afac172521dcf6

【補足】(2020/12/16)

```python
# 点と線分との最短距離(sympyの行列)
from sympy import *
var('x0 y0 x1 y1 x2 y2 c s tx ty d sx sy')

# x0 = 0.3
# y0 = 1.4
# x1 = 0.0
# y1 = 0.0
# x2 = 1.5
# y2 = 1.5

d=sqrt((x1-x2)**2+(y1-y2)**2)
v=solve([c*0-s*0+tx-x1,s*0+c*0+ty-y1,c*d-s*0+tx-x2,s*d+c*0+ty-y2],[c,s,tx,ty])
A=Matrix([
[v[c],-v[s],v[tx]],
[v[s], v[c],v[ty]],
[0   ,    0,    1]
])
B=Matrix([
[x0],
[y0],
[ 1]
])
AinvB=A.inv()*B
sy=AinvB[1].subs([(c**2 + s**2,1)])

sy=sy.subs({x0:0.3, y0: 1.4, x1: 0.0, y1: 0.0, x2: 1.5, y2: 1.5})
print(sy)

#最初から変数 に代入 0.777817459305201
#後　からsubsで代入 0.777817459305202
#cadで大体あっていました。
#syがプラスなので、ｐは、ｑｒの左側です。
```

# 左右は３次元にも使えそうですね。
Z座標を無視して、XY平面に投影するだけ。


# (空間上で)3次元で、点と線分との最短距離もできそうですね。
どこかにあれば、助かります。製作中。
行列の座標変換です。クォータニオン (Quaternion) を使えば何とかなりそうです。
?Z軸回転して、Y軸回転して、qrをX軸上にするだけのような気がします。


# 参考

https://qiita.com/takenakadx/items/ca137088d3f897bc8b45
StateパターンとStrategyパターンの違い

#StateパターンとStrategyパターンの違い#

##はじめに
私の書く記事はざっくりをモットーとしています
自分はまず結論とか要点をパッと知って深堀したいからです
軽く知りたい人はおすすめです:smiley:


#Strategyパターンとは#
ざっくりといいますと、抽象インターフェースを利用して、実装部分を交換できるようにするパターンです
UMLはこちら
画像はWikiさんから
![500px-StrategyPatternClassDiagram.svg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515149/7369226b-f7c5-965c-26f9-07679846aa5e.png)

##Stateパターンとは
これは覚えておかないといけない、絶対というレベルでしょうｗ
そのオブジェクトが持つ複数の状態をクラス化するパターンです

プレイヤーの立っているとき、走っているとき、攻撃の時とか一つにしないで分けましょうって考えです。
UMLはこちら
画像はWikiさんから
![450px-State_Design_Pattern_UML_Class_Diagram.svg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/515149/46cc5c30-2caf-b7e7-a877-9d6c47ef4965.png)


##UMLは同じ

やっていることがまあ同じなのでこのような形になります。

##本題　StateパターンとStrategyパターンの違いとは
これがデザインパターンというものですね。ここを【どっちでもいいや】とやってしまいますと、良いプログラマーにはなれないと思います。

デザインパターンは考え方です。
StrategyパターンはAIの設計などに使い、Stateパターンは状態変化に使います。
あくまで考え方で、プログラムを作る際、この本質を理解して作ればベストです。
【AzureAD】ユーザーの作成について


**・ユーザーの作成**
**・ライセンス付与について**

について記載します。
クリックする項目は[　］で囲っています
検証用のAzureADを使用しています。

#ユーザーの作成

AzureADのユーザー作成は簡単です

AzureADのユーザ画面から**[+新しいユーザ］**をクリックします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480057/6da18d4c-c684-60de-fb1b-28e1ba91481e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480057/eadbd0c8-5c8b-f644-a2f2-3da879d64a97.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480057/02c3442d-f704-2ac4-15d0-566b74a99060.png)

ここでは**ユーザーの作成**を選択します
**パスワード**は自動生成でも自分でも作成ができます
**グループ**はセキュリティグループを作成していたら割り当てることができます。
**役割**はライセンスを持っていれば割り当てられます。
**利用場所**ここが重要なんですが、いまは未記入にしておきます。
**[作成］**をクリックすればユーザーが作成されます。

#ライセンス付与について

次に作成したユーザーにライセンスを割りあててみます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480057/7cf0c4c3-c179-f229-97c3-4f154049052b.png)

ここでは以下のように割り当ててみましたが、割り当てが失敗してしまいました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480057/f351aeb5-abd2-8f08-011d-07288f9f2c1a.png)

ここでユーザーの編集画面から**利用場所**に[Japan]追加してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480057/368475d4-9f88-1f0d-2edb-54433c645c23.png)

そうすると無事割り当てることができました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480057/ba55263d-fe64-3e33-af09-5b85f65e8dfb.png)

場所を設定しておかないと、ライセンスがあたらないとは。。。

ちょっとはまったので備忘録として残しておきます。
docker を ubuntu 18.04 にインストールしようとしたら怒られた

```
# sudo apt install docker.io
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
インストールすることができないパッケージがありました。おそらく、あり得
ない状況を要求したか、(不安定版ディストリビューションを使用しているの
であれば) 必要なパッケージがまだ作成されていなかったり Incoming から移
動されていないことが考えられます。
以下の情報がこの問題を解決するために役立つかもしれません:

以下のパッケージには満たせない依存関係があります:
 docker.io : 依存: containerd (>= 1.2.6-0ubuntu1~)
E: 問題を解決することができません。壊れた変更禁止パッケージがあります。

```

こうやって怒られたので

```
sudo apt-get remove containerd.io
sudo apt install containerd
```

これで無事
```
sudo apt install docker.io
```
が通った。その後dockerコマンドを利用しようとしたら

```
# systemctl start docker
Failed to start docker.service: Unit docker.service is masked.
```

こうやって怒られたので、

```
# systemctl unmask docker.service
Removed /etc/systemd/system/docker.service.

# systemctl unmask docker.socket

# systemctl start docker.service
```

この３つを実行したら無事dockerが使えるようになりました。
golangの:=の使い方

※自分用にメモを残しています

# Go言語における`:=`と`=`の使い分け
## `=`を利用をする場合
### 明示的な定義
下記のように`var [変数名] [型]`と明示的に変数に型を定義したい場合に利用

```
var n int
n = 5
```

## `:=`を利用する場合
### 暗黙的な定義
下記のように、`[変数名] = [値]`と型を指定せずとも
型推論が行われる。型の指定が必要ない
※但し、ローカル変数のみ使用可

```
n := 5
```

## 補足
### ローカル変数とパッケージ変数
Goの変数は定義される場所によって種類が分かれる。
任意の関数で定義される変数を`ローカル変数`、
関数の外で定義される変数をパッケージ変数という。
PythonでABC036のA~Cを解く

### はじめに
おひさしぶりです。茶色になったので、少しさぼってました。
今日はABC036と解きます。

### A問題
[問題](https://atcoder.jp/contests/abc036/tasks/abc036_a)

**考えたこと**
ceilで切り上げて割り算する。

```python
import math
a, b = map(int,input().split())

print(math.ceil(b/a))
```

### B問題
[問題](https://atcoder.jp/contests/abc036/tasks/abc036_b)

**考えたこと**
forで縦と横を入れかえるだけ。

```python
n = int(input())
s = [list(input()) for _ in range(n)]

d = []
for i in range(n):
    c = []
    for j in range(n):
        c.append(s[j][i])
    c = c[::-1]
    d.append(c)

ans = ''
for i in range(n):
    s = ''.join(d[i])
    print(s)
```

### C問題
[問題](https://atcoder.jp/contests/abc036/tasks/abc036_c)

**考えたこと**
解説ACです。dictを使えば簡単にできました。知らなかった。$a$の重複要素をsetで消してsortして、順にdictにつっこみます。

```python
n = int(input())
a = [int(input()) for _ in range(n)]
s = sorted(list(set(a))) #set
dic = {}

for i, e in enumerate(s): #enumerateを使うことで、最小の数にできる。
    dic[e] = i
for i in a:
    print(dic[i])
```

### まとめ
データ構造に疎いので、勉強します。めざせ緑! ではまだ、おやすみなさい。
5 月 LeetCode 挑戰, W1D6, Majority Element (Hash Table/Hash Map), in Swift

演算法與資料結構： `Hash Table`

- 挑戰頁面 - [Majority Element](https://leetcode.com/explore/challenge/card/may-leetcoding-challenge/534/week-1-may-1st-may-7th/3321/)
- 原題目頁面 - [169. Majority Element](https://leetcode.com/problems/majority-element/)

## 想法

第一直覺是想到是用 hash table 解。而這一題有另外一個解法，會另外開一篇來記錄。

### 步驟

- 依序走訪紀錄出現次數
- 當出現次數超過個數的一半時就回傳

## 程式碼

``` swift
class Solution {
    func majorityElement(_ nums: [Int]) -> Int {
        var hashTable = [Int: Int]()
        let halfSize = nums.count / 2

        for number in nums {
            let count = (hashTable[number] ?? 0) + 1
            if count > halfSize {
                // 超過就提前回傳
                return number
            }
            hashTable[number] = count
        }

        return -1
    }
}
```

### 複雜度分析

n 為傳入陣列的長度

- 時間複雜度： O(n) - 走訪過一次
- 空間複雜度： O(n) - hash table 用掉的份

### 執行結果

不是那麼漂亮 XD

``` text
Runtime: 148 ms (beats 75.09%)
Memory Usage: 21.4 MB
```
ASP.NET Core: ブラウザから照明をON/OFF


# 1. やりたいこと
リモコンを使わず、ブラウザから照明をON/OFFしたい。
将来的には、照明を消し忘れて寝てしまった場合に、自動的に消してくれるシステムをつくりたい。

# 2. 準備するもの
* Arduino UNO
* 赤外線LED
* 抵抗（1kΩを使用）
* 赤外線リモコン受信モジュール（PL-IRM2121-A538を使用）
* ブレッドボード/ジャンパー線
* LEDシーリングライト（NEC HLDZ06209を使用）
* リモコン（NEC RE0206を使用）

# 3. 作業内容
## 参考にしたサイト
Arduinoで赤外線リモコンの値を読み取り、送信する方法
http://asukiaaa.blogspot.com/2018/05/arduino.html
⇒丁寧にまとめられていて、わかりやすかったです。

## 作業概要
* 電子回路（受信/送信）を作成する。
赤外線リモコン受信モジュール（PL-IRM2121-A538）は、正面左から[OUT GND 5V]の順に並ぶ。OUTをArduinoの[3]につなぐ。
赤外線LEDは、長いほうが[＋]。短いほうが[-]。[+]をAruduinoの[11]につなぐ。
* Arduinoにプログラム（受信）を書き込む。
* 実機リモコンを使って、送信信号のデータを取得する。
* 取得したデータをもとに、Arduinoのプログラム（送信）を作成する。
* Arduinoにプログラム（送信）を書き込む。
* ASP.NET Coreでプログラムを作成する。
* ブラウザから照明をON/OFFしてみる。
誰からも頼まれていないのにコードを書く機会を作り続ける秘訣

2020年のゴールデンウィークを、黙々とコードを書いて過ごした。仕事でコードを書く必要性が皆無な職種だが、それでもコードを書き続けることで仕事での重大な局面を何度も切り抜けてきたし、色々と得してるんじゃないかと思ってる。

ふと、現場での経験に恵まれず、才能を発揮できていないプログラマがいたら、この「誰からも頼まれていないのにコードを書く機会を作り続ける秘訣」は役に立つんじゃないかと思ったので、ちょっと書いてみようと思う。

#1.自分が使うものを作る

10年ぐらい前にプログラムのコンテストに出てトイレを探すサービスを作ったことがあった。当時に一緒になったメンバーが街でトイレを探す機会が多いからと考えたサービスだ。このサービスを作ったことで、賞もいただけたし、手を出さなかったけど、アプリへの広告掲載などの話もあった。ただ、機能追加を続けるのは２年が限界だった。どうも自分にはトイレを探す才能が備わっていて、自分でアプリを使ってトイレを探すことがなかったのだ。

アプリを書くキッカケとして、誰かのニーズを汲むことは否定しない。ただ、コードを書き続けたいのであれば、自分自身のニーズと向き合うことが重要だ。世界中で何万人が困っている問題に目を向けたがる人もいるが、その何万人に自分が含まれていないアプリに、どれだけ時間をかけられるのだろう。

#2.作る前に市場調査をしない

自分が使いたいものを思いついたとする。そうしたら、その瞬間からインターネットで検索するのをやめ、プロトタイプを作り始める。検索すれば便利なソリューションに出会えるかもしれない。でも便利なソリューションに出会っても、コードを書くモチベーションを保ち続けられるだろうか。

報酬のために働いているのであれば、じっくりと競合を研究し、クオリティを高めるべきだ。ただ、報酬とは関係なく「自分のためにコードを書く」ということを優先させるのであれば、貴重なモチベーションを無駄にしてはいけない。

#3.まずExcelで作ってみる

あまり世間で見かけることがないアドバイスかもしれないが、もし自分自身のニーズを満たせるサービスを思いついたら、ワイヤフレーム（画面のモック）を考えるより先に、Excelなどの表計算ソフトで入力データと出力データをシミュレーションしたほうがよい。APIなどで何か役に立つ情報が得られるとして、そこから自分が欲しい情報に加工できるか。もしくは手入力するとして、現実的なインプットで意味のあるアウトプットが得られるか。ここを見誤ったままデータベースを作ってしまうと取り返しがつかない。

簡単に入手できるデータでは容易に価値のあるアウトプットを提供できないことが露骨にわかってしまうので、何も作れなくなるというジレンマに陥る可能性もある。でも、ここをクリアできないと継続できるサービスになりえない。というか、いきなりワイヤフレームを書かせるメンターって、どれだけ騙された回数が少ないんだろうかと。

#4.宣言とか公開とかしない

SNSなどで「連休中に、こういうサービスを作る」みたいな宣言を見かけることがあるが、これも逆効果だ。せっかくコードを書く気になったのに「このアプリで十分じゃね」という親切で迷惑なツイートを見てしまうかもしれない。また、逆に期待されてしまっても、自分の中でイマイチだと思っても方向転換しにくくなり、イマイチなものを作るために貴重なモチベーションが浪費する。

制作過程をツイートで残すのもやめたほうがいい。もし誰かに応援してもらいながら作りたいなら、何を作って、どんな問題を解決するのかは我慢して、技術要素だけ喋ればいいと思う。

#5.テーマにお金を使う

経験豊富でないので的はずれなことを書いてしまうかもしれないが、一般的にフロントエンドと呼ばれる領域は学習コストが高いと言われている。料理に例えると、調味料の微妙な加減を見極めるようなものだ。しかも、その調味料のトレンドが２〜３年で入れ替わる。

個人でサービスを開発・運営してる人と情報交換しても話題になることが少ないが、Bootstrapなどメジャーなフレームワークは有料のテーマがあって、高品質なデザインを買うことができる。もちろん無料でクオリティの高いテーマもあるが、どこかの誰かが使ってる可能性が高い。

#6.別の言語に置き換えてみる

基本的に、個人開発なのだからアーキテクチャも自由に選べる。かつて集まったメンバーの共通言語（例えばRuby）でサービスを作ったが、あまりにメンバーが役に立たないから自分が使いやすいPythonで書き直し、さらにFacebookのSDKを使いたくなってPHPで書き直したことがあるが、こんな感じで自分の興味の赴くままに過去のリソースを捨てられるのは個人サービスの醍醐味だ。

アイデアに出会う頻度と、技術に出会う頻度は人それぞれだ。もしアイデアに出会えなくて、でも技術を試したくてしょうがなかったら過去に自分が書いたものを別の言語で書き直せばいい。自分は最近では、Pythonで書いたものをRustに置き換えているが、適当なチュートリアルより達成したときの満足度が高い。

#7.コンテストは締切にはなるが・・・

自分はMaker FaireやMashup Awardなどの締切をひとつのターゲットとして設定していた時期があった。他の参加者の作ったものをじっくりと見て刺激を得られるし、勝ち残れば参加者同士の交流を深める場にもなる。あえて言うなら、コンテストが求める領域と自分がやりたい領域が重なることは稀なので、そこにこだわるのではなく、割り切った付き合いがいいと思う。
Rubyでハッシュ探索法を書いてみたMinitestでテストしてみた

##はしめに
今回はこちらの本でアルゴリズムの勉強をしているので学んだハッシュ探索法をRubyで書いて見ました。
[アルゴリズムをはじめよう](https://www.amazon.co.jp/%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E3%82%92%E3%80%81%E3%81%AF%E3%81%98%E3%82%81%E3%82%88%E3%81%86-%E4%BC%8A%E8%97%A4-%E9%9D%99%E9%A6%99-ebook/dp/B01CZDTINE/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1IFTF2EOG9SW2&dchild=1&keywords=%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E3%82%92%E3%81%AF%E3%81%98%E3%82%81%E3%82%88%E3%81%86&qid=1588756149&sprefix=%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%2Caps%2C320&sr=8-1)

##ハッシュ探索法とは
データを探す探索アルゴリズムの一つ。予めデータを違う配列を作成して格納。格納した配列からデータを探索する方法。

##実装
与えられた配列をデータ格納用の配列に格納するメゾットとデータ格納用の配列から目的の値を探し出すメゾットの二つを作成します。

```ruby
#与えられた配列をデータ格納用の配列へ格納
def hash_storage(arrayd)
    #データ格納用の配列を元の２倍の要素を初期値０で作成
    arrayh =Array.new(arrayd.count*2,0)
    #ハッシュ計算用
    x = arrayh.count
    #繰り返し数を初期化
    i = 0
    #元の配列の要素数繰り返す
    while i < arrayd.count
        #ハッシュの計算
        k = arrayd[i] % x
        #格納先の配列にすでにデータがある場合（０じゃない場合）
        until arrayh[k] == 0
            k = (k+1) % x 
        end 
        #要素を格納
        arrayh[k] = arrayd[i]
        i += 1
    end
    arrayh
end

#データ格納用の配列から値を探索する。
def hash_search(arrayh,target)
    #ハッシュ値計算用
    x = arrayh.count
    #ハッシュ値の計算
    k = target % x
    
    #0以外の値が格納されている場合処理を繰り返す。
    until arrayh[k] == 0
        if arrayh[k] == target
            return "格納場所は#{k+1}番目の要素です"
        else 
            k = (k+1) % x
        end
    end
    "#{target}は存在しません。"
end
```

テストはこちら

```ruby
require 'minitest/autorun'

class HashTest < Minitest::Test
  def test_hash
    arrayd = [11,13,17,19,23,29,31]
    assert_equal  [0,29,0,17,31,19,0,0,0,23,0,11,0,13], hash_storage(arrayd)
  end

  def test_hash_search
    arrayd = [11,13,17,19,23,29,31]
    arrayh = hash_storage(arrayd)
    assert_equal "格納場所は5番目の要素です" , hash_search(arrayh,31)
    assert_equal "12は存在しません。" , hash_search(arrayh,12)
  end
end
```

以上です。間違いやアドバイス等あればコメントいただけると幸いです。
ありがとうございました。
shellとかコマンドとかをサービス化(デーモン化)するやつ

# shellとかコマンドとかをサービス化するやつ

これも忘れがちだからメモ
この記事は必要に応じて調べながら修正していく。

## やり方
`sudo`して`/etc/systemd/system/`にサービス名.serviceを作る。
各セクションの説明は[systemd サービスユニット覚書](https://qiita.com/ch7821/items/369090459769c603bb6b)のほうが詳しく載ってる。

### Unit
サービスの説明

| 項目 |説明|
|----|---|
|Description|説明|
|After|前提サービス※|
|Before|このサービスより前に起動するべきサービス|

※ディレクトリのマウントを待つことも可能。`/home/min06s/hoge`を待つなら`home-min06s-hoge.mount`と書く

### Servise
サービス自体の設定

| 項目 |説明|
|----|---|
|ExecStart|実行コマンド|
|Restart|Restartオプション|
|Type|サービスタイプ|

### Install
サービスのenable/disableに対するオプション

|オプション|説明|
|---|---|
|WantedBy|enable時にこのUnitの.wantsディレクトリにリンクを作成する|
|RequiredBy|enable時にこのUnitの.requiredディレクトリにリンクを作成する|
|Also|enable/disable時に同時にenable/disableするUnit|
|Alias|enable時にこのUnitの別名を用意|

参考：http://enakai00.hatenablog.com/entry/20130917/1379374797

### 例
とりあえず適当に使いたいときは`ExecStart`らへんをちゃんとしておけばok

```bash
[Unit]
Description = example
After=network-online.target
ConditionPathExists=/home/user/script

[Service]
ExecStart=/home/user/script/ping.sh
Restart=no
Type=simple

[Install]
WantedBy=multi-user.target
```

### Restartについて
結構細かい設定が可能。

|オプション|説明|
|---|---|
|no|プロセスが終了してもプロセスを再起動しません。|
|on-success|プロセスが正常終了したときにプロセスを再起動します。ただし正常終了とは終了コードが 0 のときや SIGHUP, SIGINT, SIGTERM, SIGPIPE のシグナルで終了した場合のことです。|
|on-failure|プロセスが異常終了したときにプロセスを再起動します。ただし異常終了とは終了コードが 0 以外のときやコアダンプなどの上記4つ以外のシグナルで終了した場合などのことです。|
|on-abnormal|on-failure と似ていますが、終了コードによるプロセスの再起動はしません。|
|on-abort|プロセスが上記4つ以外のシグナルで終了したときにプロセスを再起動します。|
|on-watchdog|watchdogがタイムアウトしたときにプロセスを再起動します。|

参考：[systemctlでプロセス自動再起動](https://tex2e.github.io/blog/linux/systemd-restart-config)

## 有効化

```bash
$ sudo nano /etc/systemd/system/ping.service
$ sudo chown root:root /etc/systemd/system/ping.service
$ sudo chmod 644 /etc/systemd/system/ping.service
$ sudo systemctl daemon-reload
$ sudo systemctl enable ping.service
$ sudo systemctl start ping.service
```
Ruby と Perl と Java と Python で解く AtCoder ARC 086 C ハッシュのソート

# はじめに
*[AtCoder Problems](https://kenkoooo.com/atcoder/#/)* の Recommendation を利用して、過去の問題を解いています。
AtCoder さん、AtCoder Problems さん、ありがとうございます。
# 今回のお題
*[AtCoder Regular Contest 086 C - Not so Diverse](https://atcoder.jp/contests/arc086/tasks/arc086_a)*
<font color="brown">Difficulty: 431</font>

今回のテーマ、ハッシュのソート
# Ruby
重複したリストと言えば、ハッシュですよね。

```ruby.rb
n, k = gets.split.map(&:to_i)
a = gets.split.map(&:to_i)
h = Hash.new(0)
a.each do |x|
  h[x] += 1
end
puts n - h.values.sort.reverse[0, k].inject(:+)
```
```before.rb
h.sort_by{|key, v| -v}.each do |key, v|
```
```after.rb
puts n - h.values.sort.reverse[0, k].inject(:+)
```
~~*Ruby* にはハッシュの破壊的ソートは準備されていないのですが、そういう用途が少ないものと思われます。~~
**追記**
元のコードはハッシュをソートするものでしたが、コメントにてvalues側を配列として取り出しソートしてスライスして合計するアイデアをいただきました。
# Python
```python.py
from collections import defaultdict

n, k = map(int, input().split())
a = list(map(int, input().split()))
h = defaultdict(int)
for x in a:
    h[x] += 1
ans = 0
i = 0
for key, v in sorted(h.items(), key=lambda x: -x[1]):
    i += 1
    if i > k:
        ans += v
print(ans)
```
```sort.py
for key, v in sorted(h.items(), key=lambda x: -x[1]):
```
*Python*の場合、ハッシュではなく辞書型と呼ばれます。
また、`defaultdict`ではなく`Counter`を使用されているプレイヤーが多いです。
# Perl
```perl.pl
chomp (my ($n, $k) = split / /, <STDIN>);
chomp (my @a = split / /, <STDIN>);
my %h;
$h{$_}++ for @a;
my ($c, $ans) = (0, 0);
for my $v (sort {$b <=> $a} values %h) {
  $c++;
  $ans += $v if $c > $k;
}
print "$ans\n";
```
```sort.pl
for my $v (sort {$b <=> $a} values %h) {
```
*Perl* のソートはシンプルです。
# Java
```java.java
import java.util.*;
import java.util.stream.Collectors;

class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = Integer.parseInt(sc.next());
        int k = Integer.parseInt(sc.next());
        HashMap<Integer, Integer> h = new HashMap<>();
        for (int i = 0; i < n; i++) {
            int a = Integer.parseInt(sc.next());
            h.merge(a, 1, Integer::sum);
        }
        sc.close();
        List<Integer> s = new ArrayList<>(h.values());
        Collections.sort(s);
        int ans = 0;
        for (int i = s.size() - k - 1; i >= 0; i--) {
            ans += s.get(i);
        }
        System.out.println(ans);
    }
}
```
```sort.java
        List<Integer> s = new ArrayList<>(h.values());
        Collections.sort(s);
```
*Java* の場合、リストに変換してソートしています。
**追記**
コメントよりコードを修正しました。

||Ruby|Python|Perl|Java|
|:--:|:--:|:--:|:--:|:--:|
|コード長|156 Byte|286 Byte|226 Byte|723 Byte|
|実行時間|187 ms|261 ms|214 ms|620 ms|
|メモリ|32880 KB|39352 KB|46668 KB|70772 KB|
# まとめ
+ ARC 086 C を解いた
+ Ruby に詳しくなった
+ Python に詳しくなった
+ Perl に詳しくなった
+ Java に詳しくなった

参照したサイト
*[Python sortのまとめ (リスト、辞書型、Series、DataFrame)](https://qiita.com/shizuma/items/40f1fe4702608db40ac3)*
Azure IoT Hub Explorerのインストール

# IoT Hub Explorerのインストール
Azure IoT Hubへデバイス登録するためのシミュレーター


```bash
$ npm -g install iothub-explorer
npm WARN deprecated iothub-explorer@1.2.2: iothub-explorer will be retired on November 31st, 2018 and has been replaced by the Azure CLI IoT Extension: https://aka.ms/iotcli
npm WARN deprecated azure-event-hubs@0.0.8: This package has been deprecated. Please use @azure/event-hubs instead
npm WARN deprecated crypto@0.0.3: This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in.
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
/Users/k.tsumura/.nodebrew/node/v14.1.0/bin/iothub-explorer -> /Users/k.tsumura/.nodebrew/node/v14.1.0/lib/node_modules/iothub-explorer/iothub-explorer.js
+ iothub-explorer@1.2.2
added 213 packages from 188 contributors in 20.009s
```

# Expireされてた
2018年から移行されていた

```bash
--------
DEPRECATION NOTICE: iothub-explorer will be retired on November 31st, 2018
It has been replaced by the Azure CLI IoT Extension (https://aka.ms/iotcli).
--------
```

# gitからinstall
gitのRead meを参考にやってみた
https://github.com/Azure/azure-iot-explorer

## 手順
gitのページの抜粋（２０２０年５月）

>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/627617/6386eebb-3e24-8f9b-3940-37bed7e3b58b.png)

4を実行するとブラウザで以下のページを開いてくれる（http://127.0.0.1:3000/）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/627617/f9fa4528-09fa-f112-ac79-662bd71ac701.png)

# 使ってみる
Connectしてみると以下の画面へ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/627617/2fb7558a-aac0-059a-d497-e40a8ab40f19.png)

## Deviceの追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/627617/31141a96-e697-8bf9-b3ec-9124e0e0def5.png)

## Deviceが追加されていることをこのツールとAzure portalで確認

ツール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/627617/bf5dcb54-ebd7-17ab-2dfc-416e5f5bfe54.png)

Azure portal
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/627617/7258e699-c5b0-4eb8-e4ad-b420b18bf2a8.png)


# 詰まったところ

package.jsonが見つからないと言われた。
Cloneしたディレクトリへ移動し忘れ

```bash
$ npm install
npm WARN saveError ENOENT: no such file or directory, open '/Users/k.tsumura/Desktop/test/package.json'
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN enoent ENOENT: no such file or directory, open '/Users/k.tsumura/Desktop/test/package.json'
npm WARN test No description
npm WARN test No repository field.
npm WARN test No README data
npm WARN test No license field.

up to date in 0.668s
found 0 vulnerabilities
```
Next.jsプロジェクトをつくってFirebase(FunctionsとHosting)へデプロイする方法

#概要

皆さんこんにちは。

Next.jsのプロジェクトをFirebaseのFunctionsとHostingへデプロイしてSSR(サーバーサイドレンダリング)を実現したいと思います。

【前提】
・Firebaseのプロジェクトは用意されている。
・npmコマンドを使えるようにインストールしておく。

#環境

・macOS Catalina
・Next: 9.3.4
・Firebase: 8.2.0

#参考

Next公式Github
https://github.com/zeit/next.js/tree/canary/examples/with-firebase-hosting
(ここのREADME.md通りに進めればできます。)

#方法

##①Nextプロジェクトの初期化(準備)

ローカル環境において、プロジェクトを置きたいディレクトリで下記のコマンドを実行。
[作成されるディレクトリ名]には好きな名前を入れてください。

```
npm init next-app --example with-firebase-hosting [作成されるディレクトリ名]
# or
yarn create next-app --example with-firebase-hosting [作成されるディレクトリ名]
```

##②Firebaseプロジェクトの設定
作成されたディレクトリに「.firebaserc」ファイルがあるのでそれを開き、デプロイするFirebaseのプロジェクト名を記述しましょう。

```:.firebaserc
{
  "projects": {
    "default": "juno-project"
  }
}

```

##③各種パッケージのインストール

ターミナルで、プロジェクトルートへ移動(cd)して下記のコマンドでパッケージをインストールしましょう。
(package.jsonに記載されたパッケージがインストールされます。)

```
npm install
# or
yarn
```

これでプロジェクト自体の導入は完了です。

##④作成されたNextプロジェクトをローカルで確認
導入したサイトをローカルでみてみましょう。
下記のコマンドを入力し、[ ready ]になったら、[localhost:3000](http://localhost:3000)へ。

```
npm run dev
# or
yarn dev
```

<img width="250" alt="スクリーンショット 2020-05-06 21.36.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360790/e8e01b16-c074-6e3d-3914-09e71ec5a3b1.png">

##⑤Firebaseへデプロイ
あとはこれをFirebaseへデプロイするのみです。

```
npm run deploy
```

これで自動的に設定したFirebaseのプロジェクトのFunctionsとHostingへデプロイしてくれます。

Deploy complete!が表示されたらサイトを確認してみましょう。
先ほどローカルで確認したサイトと同じものが確認できます。

Nextプロジェクトはpublicやsrcディレクトリ以下をいじって制作してください。
以上になります。

#あとがき

最近、過去に制作したWebサイトをレンタルサーバーからFirebase Hostingに移行させました。
レンタルサーバーだと毎月サーバー料金もかかるため無料で運用する方法を考えていました。
そこで、訪問数も少ないためFirebaseの無料枠を使って運用することにしました。移行してからかかる料金は元々設定していたドメイン料くらいです(Firebaseはカスタムドメインも無料で設定できます)。
(移行するにあたって、サイトは動的(PHP)から静的(JS)にしました)
そこから今回はさらに、そのサイトをNext.jsプロジェクトにしてみました。

Next.js慣れないな(*´-`)
フィボナッチ数列でDPの勉強をしてみました

時間ができたので100周遅れでAtCoderに入門するため、動的計画法（以下DP）に取り組みはじめました。

# TL;DR
[プログラミングコンテストにおける動的計画法](https://www.slideshare.net/iwiwi/ss-3578511)のフィボナッチ数列の部分をPythonで実装しただけです。

# DP
同じ探索を2度しないようにすること
一度計算したら結果を保存して使い回す

# フィボナッチ数列
> 「フィボナッチ数列」とは，「前の２つの数を加えると次の数になる」という数列です。
ただし，１番目と２番目の数は両方とも１です。

> - 第0～21項の値は次の通り：

> ```math
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, …
```

> - フィボナッチ数列（フィボナッチすうれつ、（英: Fibonacci sequence） (Fn) は、次の漸化式で定義される：

> ```math
F0 = 0\\
F1 = 1\\
F_{n+2} = F_n + F_{n+1}\,(n ≥ 0)\\
```

> [Studyplus](https://www.studyplus.jp/445)
[Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0)

# 処理時間計測
処理時間を計測する際、頻繁に使用している推し関数があるので紹介します！
kaggleマスターのアライさんが紹介していたtimer関数をシンプルにしました
（これを知れただけでもkaggleやっててよかった...）


```
import time
from contextlib import contextmanager


@contextmanager
def timer():
    t0 = time.time()
    msg = "start"
    print(msg)
    yield
    msg = f"done in {time.time() - t0:.2f} s"
    print(msg)
```

> [Kaggleコード遺産](https://qiita.com/kaggle_master-arai-san/items/d59b2fb7142ec7e270a5#timer)

# 本題
## 普通にフィボナッチ数を計算する
```
def fib(n: int):
    if n == 0:
        return 0
    if n == 1:
        return 1
    return fib(n - 1) + fib(n - 2)
```

## メモ探索（再帰関数のメモ化）
```
def fib_memo(n: int):
    global done
    global memo
    if n == 0: return 0
    if n == 1: return 1

    if done[n]:
        return memo[n]

    done[n] = True
    memo[n] = fib_memo(n - 1) + fib_memo(n - 2)
    return memo[n]
```

## 動的計画法（漸化式＋ループ）
```
def fib_loop(n: int):
    global memo
    memo[0] = 0
    memo[1] = 1

    for i in range(2, n+1):
        memo[i] = memo[i - 1] + memo[i - 2]
    return memo[n]
```

## 実行
```
if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("method", help="Select to solve with which fibonacci method")
    parser.add_argument("max_num", help="Set max number")
    args = parser.parse_args()

    n = int(args.max_num)
    done = [False] * (n + 1)
    memo = [0] * (n + 1)
    with timer():
        print(eval(args.method)(n))
```

## コマンド
```
python fibonacci.py fib_memo 1000
```

# 処理速度
上記の3つでは動的計画法が最も早く、次にメモ探索、最も遅いのは普通にフィボナッチ数を計算する場合でした。
  
[プログラミングコンテストにおける動的計画法](https://www.slideshare.net/iwiwi/ss-3578511)に記載があるように計算量が指数時間かかるか擬多項式時間かかるかの違いのようです。

```
動的計画法 < メモ探索 <<<<<<<<<<<<<<<<<< 普通にフィボナッチ数
```
- n = 30000の場合  
  - 動的計画法： 0.04 s
  - メモ探索：   0.06 s
  - 普通にフィボナッチ：　終わらない(n=100でもめっちゃ時間かかる）

[詳細はGithubを参照くださいませ](https://github.com/yoshinori77/atcoder/blob/master/dp_practise/fibonacci.py)
【swift】xcode11 クイズアプリ

<blockquote class="twitter-tweet"><p lang="und" dir="ltr"><a href="https://twitter.com/hashtag/xcode?src=hash&amp;ref_src=twsrc%5Etfw">#xcode</a> <a href="https://twitter.com/hashtag/swift?src=hash&amp;ref_src=twsrc%5Etfw">#swift</a> <a href="https://t.co/DekEyTMxoC">pic.twitter.com/DekEyTMxoC</a></p>&mdash; aa2302 (@aa23021) <a href="https://twitter.com/aa23021/status/1258013923770417152?ref_src=twsrc%5Etfw">May 6, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<a href="https://kininin.blogspot.com/2019/07/iosswift.html">参考記事</a>


<img width="1440" alt="meinnsutori-to.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/627010/ca203f9f-7883-a7bd-fdd0-8cba9ac4fd42.png">
コードは参考記事丸パクリなのでメインストリートだけお載せします。

【学んだ点】
・csvの作り方
・タイマーの設置の仕方
・UIイメージの設置の仕方

【雑談】
元々クイズ番組が好きで、MAC買ったらクイズアプリが作りたい！との気持ちだけで、何も勉強せずMAC買ってまもない時に参考記事の通りにコードを書いてみたもののmainstoryboardやビューコントローラーの繋げ方など何もわからずエラーばかり出てしまい一度は諦めてしまったコード。
それが地道に基礎を固めてもう一度挑戦してみたらエラー出ることなく無事アプリが完成した時には自分の成長を感じました。笑
MacでDockerを使ってUbuntu上にLaTex環境を構築する

# はじめに
今回はMac環境でLaTex環境を構築しました。
一度、Macに直接環境を構築したものの、研究室で使っているUbuntu環境と同じ実行結果にならなかったため、Dockerで環境構築をして、全く同じ環境を構築しました。

# ディレクトリ構成
用意するディレクトリは、今回`LaTex-app`としました。
treeコマンドで出力するとディレクトリ構成はこんな感じ。
devのディレクトリにコンパイルしたいtexファイルを置いておきます。

```
LaTex-app
├── Dockerfile
├── README.md
├── dev/
└── docker-compose.yml
```

# Dockerfile
私の研究室ではUbuntu20.04を使っていましたので、同じものをイメージに使いました。
Latexのインストールは以下の記事を参考にしました。
[Ubuntu 18.04 LTS に LaTeX をインストール](https://qiita.com/BitPositive/items/6b13e2038d628c33be8e)

``` Dockerfile:Dockerfile
# imageの選択
FROM ubuntu:20.04 
# インストール時にダイアログ・ボックスを開こうとして、エラーがあっても停止しないようにする。
# 参考:http://docs.docker.jp/v1.11/engine/faq.html#dockerfile-debian-frontend-noninteractive
ENV DEBIAN_FRONTEND noninteractive
# デフォルトのシェルをbashに設定
SHELL ["/bin/bash", "-c"]
# 各種必要なファイルをインストール
RUN apt-get update && apt-get install -y\
    texlive-lang-cjk xdvik-ja evince\
    texlive-fonts-recommended texlive-fonts-extra
RUN apt-get -y upgrade
```

# docker-compose.yml
docker-compose.ymlは見ての通りですね。

``` yml:docker-compose.yml
version: '3'
services:
  ubuntu20.04:
    restart: always
    build: .
    container_name: ubuntu20.04
    working_dir: '/root/dev/'
    tty: true
    volumes: 
    - ./dev:/root/dev/
```


# docker-composeの使い方
(あらかじめ、`$ cd LaTex-app`で`LaTex-app`に移動しておく)

### コンテナ起動
(初めての起動には-bオプションをつけるとなおよし)

```
$ docker-compose up -d
```
### コンテナに入る
```
$ docker-compose exec ubuntu20.04　bash
```

### コンテナから出る
コンテナ内で実行する。

```
$ exit
```

### コンテナ削除
```
$ docker-compose down --rmi all
```  


# LaTeXの使い方

### ドキュメント化

（参考文献がある場合は2回くりかえす）

```
$ platex hoge.tex
```
### dviファイルをpdfに変換(PCで見る用)
```
$ dvipdfmx hoge.dvi
```
### dviファイルをpsファイルに変換（印刷用、きれいに印刷できる）
```
$　dvips hoge.dvi
```

# まとめ
docker-composeでUbuntu環境を立ち上げて、LaTex環境を構築しました。
起動時間が結構かかってました。
毎回、LaTex環境を立ち上げるのはあまり向いてないってことなのか。
ですが、確実に環境を合わせられることが結構便利ではある。
最適なやり方があるのであれば知りたいです。
Power Automate - Excel - 行を追加する

今回は「行を追加する」アクションを見ていきたいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512887/b777a806-93f2-a111-8fc6-af02fb070db6.png)

このアクションは指定したテーブルの**末尾**に、１行追加する、というものです。

行の中の値は任意に設定することができます。

詳しい使い方を見ていきましょう。

## 使い方
テーブルの選び方までは、[以前](https://qiita.com/kenny55/items/3cc102f898ae584db9bc) に説明した方法と同じですのでそちらを参考してください。


今回は、以下のテーブルに行を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512887/8a9ebe3b-70c7-e0ed-4d8f-1138ae9f33d7.png)

ここでは、以下の値の行を追加するとします。
  社員番号 = 10
  氏名 = 森
  データ = 30

それぞれの列の値には以下のように記入します（ってそのまんまですね）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512887/da9769dc-dee0-12e2-a506-876dbf234ff3.png)

で、これを実行すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512887/5aa0f0c5-ed65-169d-f2f2-bfecb27e7bf7.png)

ポコッと行が追加されました！

## 注意事項
冒頭にも書きましたが、行を追加する位置はテーブルの**末尾固定**です。
末尾以外に追加するユースケースには使えません。。
そして、末尾以外に行を追加するアクションは5/6時点でなさそうです。。

なので、現在のExcelアクショングループの使い方は、

 * テーブルの末尾にレコードを追加していく蓄積タイプ
 * 既存のテーブルの値を書き換える最新状態記録タイプ

のような感じになります。 

## まとめ
以上、「行を追加する」アクションの説明でした。
かんたんなのでほぼ説明不要ですね！笑

日々のデータを蓄積させていくようなケースでは、
頻出のアクションではないでしょうか？
ぜひご自分で試してみてください。
#Python基礎（スコープ）

#1.スコープ
Pythonのスコープについてのメモ

同じ名前の変数valをグローバル変数とローカル変数として作って動きを確認

```
val = 100        # グローバル変数
def showVal():
    val = 1      # ローカル変数
    print("local val : ",val)
    
showVal()
print("global val : ",val)
```
```:実行結果
local val :  1
global val :  100
```
---
関数内でグローバル変数に値を代入

```
val = 100        # グローバル変数
def showVal():
    global val      # 変数がグローバルである事を明記
    val = 1 
    print("local val : ",val)
    
showVal()
print("global val : ",val)
```
```:実行結果
local val :  1
global val :  1
```
Dockerでgit commit時に静的解析をする

### はじめに
静的解析ツールを使って、コーディング規約に沿ってコーディングされているかを解析できます。
そして、その解析をコミット時に行い、規約違反していたらコミットできない`pre-commit`というGemがあります。
今回は、その設定でつまづいたのでここに残しておきます。

参考にしたのはこちらの記事です。
[rubocop + pre-commitで規約違反のコードをコミットできないようにする](https://ohmyenter.com/rubocop-with-pre-commit/)


### Gemの導入

今回、`rubocop-airbnb`という規約が決まっているgemを導入してみました。

`rubocop-airbnb`の使い方は[こちら](https://qiita.com/tmyn470/items/751511335b44aef2ecad)を参考にしてください。

```
group :development do
 gem 'pre-commit'
 gem 'rubocop-airbnb'
end
```

gemをインストールします。

```zsh
$ docker-compose build
```

ここで、dockerの場合は下記の設定が必要になります。

```zsh
$ git config pre-commit.ruby "docker-compose run --rm web bundle exec ruby"

# 以下の設定だとpre-commitが動いてくれない
$ git config pre-commit.ruby "bundle exec ruby"
```

また、参考にした記事のコマンドで、`bundle`から始まるものは基本的にこのように使う必要があるみたいです。

```zsh
$ docker-compose run --rm web bundle exec #以下のコマンド
```

### まとめ
Dockerを使う場合は、設定なども含めて`dockerコマンド`をつける必要があるため、注意が必要ですね！
5 月 LeetCode 挑戰, W1D5, First Unique Character in a String, in Swift

演算法與資料結構： `Hash Map`

- 挑戰頁面 - [First Unique Character in a String](https://leetcode.com/explore/challenge/card/may-leetcoding-challenge/534/week-1-may-1st-may-7th/3320/)
- 原題目頁面 - [387. First Unique Character in a String](https://leetcode.com/problems/first-unique-character-in-a-string/)

## 說明

資料結構來看還滿直覺可以想到 hash table ，這部分就不多說明了。

走兩次 (2-pass) 解法

- 第一次的走訪計算出現的次數
- 第二次的走訪尋找 hash table 中計數為 1 的字母。如果有找到第一個就直接回傳 index 。

## 程式碼

``` swift
class Solution {
    func firstUniqChar(_ s: String) -> Int {
        var hashTable = [Character: Int]()

        for character in s {
            hashTable[character] = (hashTable[character] ?? 0) + 1
        }

        var index = 0
        for character in s {
            if hashTable[character] == 1 { return index }
            index += 1
        }

        return -1
    }
}
```

### 複雜度分析

n 為字串 s 的長度。

- 時間複雜度： O(n)
  - 第一次和第二次的走訪為 O(n) + O(n) = O(2n) ，簡化係數後為 O(n) 。
- 空間複雜度： O(n) or O(1)
  - O(n) - 如果每一個字元都不一樣的話 hash table 的大小將會是 n
  - O(1) - 由題目可以知道 hash table 的大小最大是 26 ，或許可以視為常數

如果有什麼錯誤和討論歡迎留言！
DroidcamをArchLinux上で使う

AURから`droidcam`をインストールすれば良いのですが、以下のようなエラーが出ます。

```
Device not found (/dev/video[0-9]). Did you install it?
```

カーネルモジュールが必要なようです。

```bash
yay -S v4l2loopback-dc-dkms
sudo modprobe v4l2loopback_dc
```

解像度は以下の方法でFullHDに変更できます

```bash
# 解像度の設定
WIDTH=1920
HEIGHT=1080
# ドライバをアンロードする
sudo rmmod v4l2loopback_dc
# 設定する
sudo insmod /usr/lib/modules/$(uname -r)/extramodules/v4l2loopback-dc.ko.xz width=${WIDTH} height=${HEIGHT}
# 設定をバップアップ
sudo cp /etc/modprobe.d/droidcam.conf /etc/modprobe.d/droidcam.conf.org
# 設定ファイルを書き換える
sudo nano /etc/modprobe.d/v4l2loopback-dc.conf
```
macOS から SoftEther サーバを操作する

[Amazon EC2 \+ SoftEther でリモートアクセス VPN サーバを作る \- Qiita](https://qiita.com/hoto17296/items/9b6fea9468ca92c431ed)
で作った SoftEther サーバを手元の MacBook から操作してみたい。

macOS の GUI アプリもあるらしいが、 `vpncmd` が使えれば特に問題はなかったので CUI でやることにした。

## `vpncmd` をビルド
ビルドする以外のやり方は見当たらなかったのでビルドした。
Command Line Tools は既にインストール済み。

バージョンは最新のやつとかにしたらいいと思う。
[Releases · SoftEtherVPN/SoftEtherVPN](https://github.com/SoftEtherVPN/SoftEtherVPN/releases)

``` console
$ wget https://github.com/SoftEtherVPN/SoftEtherVPN/releases/download/5.01.9674/softether-vpn-src-5.01.9674.tar.gz
$ tar xzf softether-vpn-src-5.01.9674.tar.gz
$ cd SoftEtherVPN-5.01.9674
```

``` console
$ ./configure
$ make -C tmp
```

成功すれば `build/` 以下に `vpncmd` などのコマンドが生成されている。

## 言語設定を変更する
クライアントのデフォルト言語は日本語になっているが、英語にしたい場合はこうする。

``` console
$ echo 'en' > build/lang.config
```

## 接続する
SoftEther サーバのホスト名を指定して `vpncmd` コマンドを実行する。

``` console
$ build/vpncmd {hostname}
```

デフォルトでは 443 ポートを利用するので、SoftEther サーバが Amazon EC2 で動いている場合は Security Group をよしなに設定しておく必要がある。

`vpncmd` の詳しい使い方については `--help` などを参照。
C++の並列ソート

https://qiita.com/dc1394/items/d2b8de600a304664cdb5 を読んで、 `__gnu_parallel::sort` が無いなと思って記事を書くことにした。

# 整列の仕方

整列アルゴリズムにはいろいろあるけど、ライブラリ提供者が普通これが速いんじゃないの、と思うものが、不安定ソートとしては `std::sort` という形で、安定ソートとしては `std::stable_sort` という形で提供されている。

でもそれは並列計算ができない場合の話。
並列計算ができる場合は、それを活かせばもっと速くなる。かもしれない。そして、今どきのコンピュータはだいたい並列計算できるようなハードウェアになっている。

並列計算を使った整列を実現する方法はいくつかあるんだけど、手軽なのは、 [gcc 4.6.0 のころから存在していたらしい]( https://gcc.gnu.org/onlinedocs/gcc-4.6.0/libstdc++/manual/manual/bk01pt03ch18s03.html#parallel_mode.using.parallel_mode ) `__gnu_parallel::sort` 。というか、これしか知らなかった。

で。
この記事を書こうと調べていたら、C++17 で並列計算が標準でサポートされるようになったことを知った。

```c++:c++17
std::sort(first, last, comp);
```

などを、 `#include <execution>` とした上で、

```c++:c++17
std::sort(std::execution::par, first, last, comp);
```

などとすると並列計算になるらしい。すばらしい。 `par` の部分は下表の通り4通り。

|ポリシー|マルチスレッド|ベクトル化|C++|
|:--:|:--:|:--:|:--:|
|`seq`|禁止|禁止|C++17以降|
|`par`|**許可**|禁止|C++17以降|
|`par_unseq`|**許可**|**許可**|C++17以降|
|`unseq`|禁止|**許可**|C++20以降|

上記以外も処理系の気持ち次第で増えるかもしれないらしい。

処理時間を短くしたいならとりあえず `par_unseq` を指定しておけばいいかなという感じ。

とはいえ。手元の環境ではただ単に上記のように書けばいいわけではなく

```shell
$ brew install tbb
```

を実行しておく必要がある。リンクするライブラリとかも設定が必要。
TBB は、 Intel Threading Building Blocks のことらしい。

# 実行結果

安定ソート、不安定ソートのそれぞれについて。
以下の5つの方法で、4種類のデータを整列した。データの件数は $2^{10}$〜$2^{20}$ とした。

## 整列方法

|名前|実装(xxx は、`sort` か `stable_sort`)|
|:--|:--|
|gnu_parallel| `__gnu_parallel::xxx(b, e)` 
|std| `std::xxx(b, e)` 
|std(par)| `std::xxx(略::par, b, e)` 
|std(par_unseq)| `std::xxx(略::par_unseq, b, e)` 
|std(unseq)| `std::xxx(略::unseq, b, e)` 

※ `unseq` は C++20 以降のハズなんだけど、 `-std=c++17` でも使えた。

## データ

|名前|意味|
|:--|:--|
|random_uint32| $2^{32}$種類の値を持つ、ランダムな `std::uint32_t`|
|few_uint32<8>| 8種類の値しか取れない、ランダムな `std::uint32_t`|
|random_string<1024>| すべての文字がランダムな英小文字の `std::string` 。長さは 1024文字。|
|few_strings<8, 1024>|8種類の値しか取れない、ランダムな `std::string` 。長さは 1024文字。|

整列済みとかほぼ整列済みとか逆順とかいろいろ試そうかとも思ったけど、控えめにしてみた。

# 結果

軸にラベル付け忘れた。
縦軸はミリ秒。整列1回に要する時間。
横軸はデータの件数。

マシンは MacBook Pro (Retina, 15-inch, Mid 2015)。クアッドコアIntel Core i7。

コンパイラは `g++-9 (Homebrew GCC 9.3.0) 9.3.0`。
コンパイルオプションは `-march=native -O2` にした。

## 不安定ソート

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6854/a9d3834a-7889-701c-8433-d402bc4e2fc9.png)

意外と gnu_parallel がふるわない。
`uint32_t` で件数が多いと gnu_parallel がやや速い。
それ以外では gnu_parallel は意外に遅い。特に、 `uint32_t` で件数が少ないと顕著。

std(par) と std(par_unseq) が速い。同じかなとも思う。
std(unseq) は std と同じかな。

件数が少ないと並列計算のメリットは少ない。特に gnu_parallel はかえって遅い。

## 安定ソート

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6854/9b2f2019-3aba-f797-3f4e-8ab439c3fcf6.png)

不安定ソートと傾向は同じ。

# まとめ

* 試した範囲では `std::execution::par` と `std::execution::par_unseq` を使ったものが速い。
* 件数が少ないと並列計算のメリットは少ない。
* g++-10 で試したほうが良かった？

# 補足

ソースコードなどを https://github.com/nabetani/parallelsort においている。
5/6の進捗～Cの配列など～

#multiple_total
引数aの倍数のうち，引数b以下のものの合計値を算出するメソッド

```Python
def multiple_total(a, b):
	if	a>0	and	b>=0:
		i=0
		total=0        
		while a*i <= b:
			total += a*i
			i += 1
	else:
		total = 0
	return total
```

#FizzBuzz
ある整数nが与えられた時条件の文字列を返すメソッド

```Python
def fizzbuzz(n):
    if n % 3 == 0 and n % 5 == 0:
	    return 'FizzBuzz'
    elif n % 3 == 0:
        return 'Fizz'
    elif n % 5 == 0:
	    return 'Buzz'
    else:
	    return str(n)#nだけにしない
```
#Cの配列1
公舎の入居・退去の情報を読み込み、各部屋の入居者数を出力するプログラム

```C
#include <stdio.h>

int main()
{
    int a[100][100];
    int i,j,input;
    int n,m,b[100],sum=0;
    scanf("%d %d",&n,&m);
  
    for(i=0;i<n;i++){
        for(j=0;j<m;j++){
            scanf("%d",&a[i][j]);
        }
    }
  
    for(i=0;i<m;i++){
        scanf("%d",&b[i]);
    }
    for(i=0;i<n;i++){
        sum=0;
        for(j=0;j<m;j++){
            sum+=a[i][j]*b[j];
        }
        printf("%d\n",sum);
    }
    return 0;
}
```
#Cの配列2
n 枚のカードを入力として、足りないカードを出力するプログラム

```C
#include<stdio.h>
 
int main()
{
  int t[4][14];
  int n, i,j,c;
  char m, d;
  for(i=0; i < 4; i++){
    for(j=0; j < 14; j++){
      t[i][j]=0;
    }
  }
 scanf("%d", &c);
  for(i = 0; i < c; i++){
    scanf("%c %d", &m, &n);
    if(m == 'S'){
      t[0][n] = 1;
    }
    else if(m == 'H'){
      t[1][n] = 1;
    }
    else if(m == 'C'){
      t[2][n] = 1;
    }
    else if(m == 'D'){
      t[3][n] = 1;
    }
  }
  for(j=1; j < 14; j++){
    if(t[0][j] != 1){
      printf("S %d\n", j);
    }
  }
 
 for(j=1; j < 14; j++){
    if(t[1][j] != 1){
      printf("H %d\n", j);
    }
  }
 
 for(j=1; j < 14; j++){
    if(t[2][j] != 1){
      printf("C %d\n", j);
    }
  }
 
 for(j=1; j < 14; j++){
    if(t[3][j] != 1){
      printf("D %d\n", j);
    }
  }
 return 0;
}
```

#次回 Pythonのクラス
・`__init__(self)`は，クラスが実際に使われるとき自動で呼ばれる初期化関数（コンストラクタとは`__init__`という名前の部分）
・引数に`self`をもっていてクラスの実体そのもの表す
IntelliJにIdeaVimを入れてキーバインドを設定したらShiftが使えなくなった話

#キーバインド設定時に起きた問題
業務で**IntelliJ**を使うことになりました．
普段はVimを使っているので，とりあえずVimライクな操作ができるように，**IdeaVim**というプラグインを入れてみました．
このプラグインを入れると，**.vimrc**と同じように，**.ideavimrc**に設定を記述できるらしい．

しかし以下のようなキーバインド設定を記述したところ，HとLを打てなくなった（打っても何も入力されない状態になった）．

```
nnoremap <S-h> 0
nnoremap <S-l> $
```

定番のやつですね．これが使えなくなるのは非常につらい．というか，Shiftを含むキーバインドを設定できないのはつらすぎる．

#解決方法
以下のように書き換えたらうまくいった．めちゃくちゃ単純だった．

```
nnoremap H 0
nnoremap L $
```

.vimrcにおいても，上記のように記述して正しく動作することが確認できた．今後は，Shiftを含むキーバインドを記述する際に，\<S-h>のような表記を用いないことを固く誓うのであった．
Simulink APIを使ってJMAABガイドラインに準拠したモデリングを行う


#はじめに#
複数人でSimulinkモデルを設計する場合、何かしらのルールを導入しないと、人によってモデルの書き方が異なる場合があり、結合した際に統一感の無いモデルに仕上がってしまいます。
単に見た目が悪くなるだけでなく、場合によってはモデルに振る舞いに影響する場合もあります。
その様な場合は、モデルの検証をやり直ししたり設計効率にも悪影響を及ぼします。
その様な悪影響を抑えるために、様々な「モデリングガイドライン」が存在します。

#モデリングガイドライン#
その中でも認知度が高いと思われる[*JMAAB*](http://jmaab.mathworks.jp/)のモデリングガイドラインは日本国内の自動車OEMやサプライヤの方が知恵を出し合って作成されており、日本語で読めるガイドラインとなっています。

今回はこのガイドラインのルールID [*jc_0008*](https://jp.mathworks.com/help/simulink/mdl_gd/maab/jc_0008definitionofsignalnames.html) と [*jc_0009*](https://jp.mathworks.com/help/simulink/mdl_gd/maab/jc_0009signalnamepropagation.html)を遵守するためにSimulink APIを使ったユーティリティを作成したので、紹介しようと思います。このルールは各々、次のように解釈出来ます。
1. 信号源となるブロックに信号名を付与し、接続される出力ポートはその信号名と同一とする。
2. モデル階層を跨ぐ場合は伝播信号を有効にすること。

#コードとサンプルモデル#
コードと動作確認用のSimulinkモデルはMathWorksの[***File Exchange***](https://jp.mathworks.com/matlabcentral/fileexchange/75017-setinheritedportname-simulink-utility)経由でGitHubからダウンロード出来るようにしました。
[*操作動画*](https://github.com/stozaki-mathworks/SetInheritedPortName-Simulink-Utility/blob/master/DetaileOoperation.gif)も併せて公開しました。(動画は2オペレーションですが、実際は1オペレーションで操作出来ます。)

#本プログラムの目的#
この2つのルールは、Simulinkは信号フローの伝播によって、その信号の属性を接続先のブロックに継承させます。それによって、信号フローとしてモデルの可読性が向上し、Simulinkのセマンティックにより信号属性が正しく継承させることが狙いです。
また、複数人で設計している場合においては、サブシステム同士の接続ミスを無くすことにも繋ががります。
しかし、いざ設定を施そうとすると、
**1. 信号線を1つ1つ選択してチェックを有効にしていく必要があります。非常に面倒臭い!!**
**2. Simulink APIで一括設定をしようとすると、設定を有効にする箇所と無効にする箇所の区別をプログラム的に判定することが容易ではない!!**

そこで、**マウスで選択したブロックに接続する信号線のみを対象に伝播信号の設定やポート名のを有効に**出来れば、モデリングをしながらサクサクと設定を有効に切り替えられるのではないか？と考え、プログラム作成を行いました。(いわゆるコンテキストメニューのカスタマイズです。)

#プログラム上のポイント#
プログラム的には複雑ではないので、興味のある方はダウンロードなりクローン作成して、中身を見てください。
ポイントは、マウスで選択したブロックが設定対象となるようなAPI記述です。
find_systemの第4引数、第5引数でSelectedというプロパティ値をonにすることがポイントです。

```matlab
find_system(gcs,'SearchDepth', 1,'Selected', 'on');
```
railsのspina cmsにwebpを導入する。

railsのspina cmsはtrix editorを使っています。
画像などはリサイズとかしてくれません。
そこでこの記事ではリサイズと圧縮(webp)を使う方法を書きます。
webpが使える環境構築は適当に調べてください。

まずは実際のコードはこんな感じです。

```ruby:app/model/spina/text.rb
module Spina
  class Text < ApplicationRecord
    extend Mobility
    translates :content, fallbacks: true
    has_many :page_parts, as: :page_partable
    has_many :layout_parts, as: :layout_partable
    has_many :structure_parts, as: :structure_partable
    before_save :webpify

    def webpify
      doc = Nokogiri::HTML.parse(self.content)
      doc.xpath('//figure').each do |node|
        img_url = node.at_xpath('.//img')[:src]
        if img_url.include?('blobs/')
          blob_signed = img_url.split('blobs/')[1].split('/')[0]
          blob = ActiveStorage::Blob.find_signed(blob_signed)
          webp_url = blob.representation(define: 'webp:lossless=false', convert: 'webp', resize_to_limit: [ 800, 600 ]).processed.url
          resized_url = blob.representation(quality: 55, resize_to_limit: [ 800, 600 ]).processed.url
          inner_html = ApplicationController.render(
            template: 'active_storage/blobs/_spina_blob',
            layout: false,
            locals: { blob: blob }
          )
          node.attributes['data-trix-attachment'].value = ApplicationController.render json: JSON.generate({ content: inner_html })
          node.inner_html = inner_html
        end
      end
      self.content = doc.to_html
    end

    def webpify!
      webpify
      self.save!
    end
  end
end
```
それと

```html:active_storage/blobs/_spina_blob.html.erb
<% if blob.representable? %>
  <picture>
    <source type="image/webp" srcset="<%= blob.representation(define: 'webp:lossless=false', convert: 'webp', resize_to_limit: [ 800, 600 ]).processed.url %>">
    <img src="<%= blob.representation(quality: 55, resize_to_limit: [ 800, 600 ]).processed.url %>">
  </picture>
<% end %>

<figcaption class="attachment__caption">
  <% if caption = blob.try(:caption) %>
    <%= caption %>
  <% end %>
</figcaption>
```

これ。
やっていることは、
1. trixが生成してくるimgタグをnokogiriで見つけ出して、
2. imgのsrcのurlからblobをdbから引っ張り出してきて、
3. そのblobからvariantを作成してurlを作り、
4. それを基にしてwebpとかのhtmlタグを作り、Spina::Textに再度保存する。

これをbefore_saveで実行したり、`webpify!`などでconsoleとかで既に作っちゃったコンテンツにあとからwebpを導入したりできます。