OmniAICreator/Qiita-1.07M huggingface dataset:
active hashを使う場合のバリデーション

active hashを使ってプルダウンを実装する場合、プルダウンの一番上を

```
---
```
みたいにすると思う。

例えば、

```
class Genre < ActiveHash::Base
  self.data = [
    { id: 0, genre_id: '--' },
    { id: 1, genre_id: '悩み' },
    { id: 2, genre_id: 'エラー' },
    { id: 3, genre_id: '技術内容' },
    { id: 4, genre_id: '恋愛' },
    { id: 5, genre_id: '人間関係' },
    { id: 6, genre_id: 'キャリア' },
    { id: 7, genre_id: '家庭' },
    { id: 8, genre_id: '体調' },
    { id: 9, genre_id: '自己実現' },
    { id: 10, genre_id: 'その他' }
  ]
 
   include ActiveHash::Associations
   has_many :articles
 
  end
```

このようなコードの場合、id=0のデータは、テーブルに保存したくないはず。
そのようなバリデーションを設定するには、

```
with_options numericality: { other_than: 0 } do
    validates :genre_id
  end
```
このように、thanの指定を、保存したくないidを指定することで、テーブルに保存ができないようにバリデーションをしてくれる。

参考にして頂ければ、幸いである。
【初心者向け】CIツール構築に必要なYAMLの読み方

## この記事の内容
急に職場でCIツールを扱うことになりました。実はYAMLもまともに読めなかったので、CIツールの設定に必要だったことをまとめました。

なお、ソースは全て[こちらのサイト](https://magazine.rubyist.net/articles/0009/0009-YAML.html)です。しっかり勉強したい方はこちらを読んでくださいね！

- [プログラマーのための YAML 入門 (初級編)](https://magazine.rubyist.net/articles/0009/0009-YAML.html)

追記：公式サイトが、まさにCircleCIを読み解くためのYAMLの文法を紹介してくれていました！これだけ読めばとりあえず大丈夫そうですね！

- [YAML の記述](https://circleci.com/docs/ja/2.0/writing-yaml/)

## 文法
### 配列
YAMLでは`-`で配列を表現します。

```YAML
- "あああ"
- "いいい"
- "ううう"
#=> ["あああ", "いいい", "ううう"]
```
なお、シングルクォーテーションで囲んだ文字列は、ただのテキスト。
ダブルクォーテーションで囲んだ文字列は、エスケープシーケンスなども使うことができるようです。

- 詳細：[YAML フォーマット](https://symfony.com/legacy/doc/reference/1_4/ja/02-yaml)

### ハッシュ
YAMLでは`:`でハッシュを表現します。

```YAML
A: "あああ"
B: "いいい"
C: "ううう"
#=> {"A"=>"あああ", "B"=>"いいい", "C"=>"ううう"}
```

### ネスト
半角スペースのインデントでネストを表します。

```YAML
- "あああ"
-
 - "いいい"
 - 
  - "ううう"
#=> ["あああ", ["いいい", ["ううう"]]]

A: "あああ"
B:
  C: "ううう"
#=> {"A"=> "あああ", "B"=> {"C"=> "ううう"}}
```

### パイプ
稀にパイプ`|`がコードの中に出てくることがあります。

```YAML
command: |
  echo 'Hello World!'
  echo 'This is the delivery pipeline'
```
このパイプは、複数行のシェルコマンドが後に続いていることを示しているそうです。

- 参考：[設定ファイルの概要#学習ポイント](https://circleci.com/docs/ja/2.0/config-intro/#%E5%AD%A6%E7%BF%92%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88)

## その他
設定ファイルをざっと見直しましたが、今のところこれ以上複雑な文法は出てこない（出てきても稀）ので、一旦ここまでにしようと思います。

配列とハッシュとネストができれば概ね大丈夫なのね！すごい！！
他の文法も出てきたら追記していきます。

なお、CircleCIの構築自体も別途記事にしていますので、完成し次第リリースしたいです。
シルエット カメオ 4 Plus で15インチの用紙を使えない問題について

#カッティングプロッターを購入しました

カッティングシートをきれいに切り出したかったので、色々調べてみたところ、グラフテックを進められましたがプロ向けで高価なものでしたのでコンスーマー向けのシルエット カメオ 4 Plus を購入することにしました。カメオ 4 は3種類あって、カメオ 4 が12インチまでの用紙をサポートしており、Plus が15インチ、Pro が24インチまでとなっています。24インチというと621ミリもあるのでそこまででかいのいらないなぁ、15インチでいいかなぁ、となって Plus を購入しました。

#アプリもダウンロードできて便利！

シルエット カメオ シリーズは Silhouette Studio という専用のデザインソフトウェアを使っていろいろな設定やデザインも作れてしまう便利アプリです。もちろん Adobe Illustrator などからデータをインポートすることなども可能です。同じようなデザインを複数カットしたい場合などもレイアウトを作成するのが簡単でとても助かっています。

#15インチの用紙が使えない！？

シルエットカメオ 4 Plus の売りは、15インチの用紙をサポートしていることで、クラフト系のサプライを販売している[ユーロポートさん](https://europort.jp)でも15インチに合わせて380ミリ幅で販売してくれていたりします。ところが！Silhouette studio で15インチを用紙に設定して、カッティングシートをセットした状態にしても以下のエラー画面が出てきてカッティングすることができません。

![スクリーンショット 2021-04-19 21.47.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39350/2fde5986-d16d-77fd-db79-33fb6d782e01.png)

かなり時間をかけて検索したりしてどうしてこのエラーが発生するのか調べてみたのですが回答は得られず。何度か電話をかけてサポートにつながり、やっと理由がわかりました。Silhouette Studio の仕様上15インチを用紙として選択すると印刷できないそうなのです。「カッティング用台紙」で15インチの台紙を選ぶ際はカッティングできるそうです。では、具体的に何ミリまで印刷できるのでしょうか？と聞いてみたところ、この記事を書いている2021年4月19日時点では371ミリ幅が最大だそうです。

このような情報がなんで検索で引っかからないのだろうかと思いつつもこの記事が同じ悩みを抱えている方の助けになればと思います。なお、これはソフトウェア上の制約なようなので、Silhouette Studio (4.4.463ss)がアップグレードされたら変わるかもしれませんね。
Vagrantが立ち上がらなくなったのを解決

##概要
久々にVirtualBoxを立ち上げようとしたら立ち上がらなくなっていたので解決方法のメモ

##vagrant upでエラー

```
$ vagrant up
No usable default provider could be found for your system.

Vagrant relies on interactions with 3rd party systems, known as
"providers", to provide Vagrant with resources to run development
environments. Examples are VirtualBox, VMware, Hyper-V.

The easiest solution to this message is to install VirtualBox, which
is available for free on all major platforms.

If you believe you already have a provider available, make sure it
is properly installed and configured. You can see more details about
why a particular provider isn't working by forcing usage with
`vagrant up --provider=PROVIDER`, which should give you a more specific
error message for that particular provider.
```

#原因
以下によるとvagrantとvirtualboxのバージョンの組み合わせが悪いとエラーとなっている様子

[vagrantとvirtualboxのバージョンの組み合わせの確認](https://qiita.com/lunar_sword3/items/682fdd39c57a2319b83f)

#解決法
Vagrant(ver2.2.15)、virtualbox(ver5.2.34)へバージョンの調整で解決した（2021_04_19時点）
※virtualbox(5.2.34)は以下からダウンロード
[Download_Old_Builds_5_2 – Oracle VM VirtualBox](https://www.virtualbox.org/wiki/Download_Old_Builds_5_2)
Python 少ない点に対する近似曲線 2

# 続き

この記事は前回の記事の続きです。

https://qiita.com/quryu/items/886a7bf723ed7cdb1c6e

今回は2つのランダム点間の分割に加えて、近似曲線も分割してみます。

# 例） ランダム点が30個の場合

- ランダム点30個、次数30

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/03fbc35d-dfb6-b955-9bdf-b614c3a089ce.png)

極大ランダム点で極小となっていたり、その逆になったりしています。曲線の右側もおかしな極値を取っています。

- ランダム点30個、次数60

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/57d5660d-8c0a-14fc-3a0d-0d79ec4ed9f8.png)

次数を倍にしてみました。曲線の右側のおかしな挙動は改善されましたが、それでもグラフ中央付近は改善が見られません。

# 近似曲線の分割

近似曲線を分割するため、中間ランダム点を格納したndarrayを分割します。

```sample6.py
import matplotlib.pyplot as plt
import random
import numpy as np
import math

SIZE = 30
SEED = 2
DEGREE = 30
SPLIT_DISTANCE = 0.1 # 2点のランダム点の距離を0.1の長さに分割する
SPLIT_ARRAY = 3 # 中間ランダム点の分割数

def plot_split(x_val1, x_val2, y_val1, y_val2, x_medium_points, y_medium_points):
    """
    各ランダム点の中間点を生成するメソッド
    (x_val1, y_val1), (x_val2, y_val2): 2点のランダム点
    x_medium_points: 中間点のx座標をすべて格納する配列
    y_medium_points: 中間点のy座標をすべて格納する配列
    """
    # 2点のランダム点の距離を計算
    distance = math.sqrt(math.pow(x_val2 - x_val1, 2) + math.pow(y_val2 - y_val1, 2))
    # 必要な中間点の数を計算
    spl_num = math.floor(distance / SPLIT_DISTANCE)
    # 2点のランダム点を分割する. (x, y)が中間点の座標
    x_ = np.linspace(x_val1 ,x_val2, spl_num)
    y_ = np.linspace(y_val1 ,y_val2, spl_num)
    # 中間点を追加する
    x_medium_points = np.append(x_medium_points, x_)
    y_medium_points = np.append(y_medium_points, y_)
    return x_medium_points, y_medium_points


def plot_split_curve(x_medium_points, y_medium_points, DEGREE, n):
    """
    分割した中間ランダム点を描画するメソッド
    """
    coeff = np.polyfit(x_medium_points, y_medium_points, DEGREE)
    y_polyfit = np.poly1d(coeff)(x_medium_points)

    plt.plot(x_medium_points, y_medium_points, marker='o')
    if n == 0:
        plt.plot(x_medium_points, y_polyfit, label='approximate curve', color='red')
    else:
        plt.plot(x_medium_points, y_polyfit, color='red')


def plot_curve():
    """
    近似曲線を描画するメソッド
    """
    np.random.seed(seed=SEED)
    plt.figure(figsize=(8.0, 6.0))

    x = np.array(range(SIZE))
    y = np.random.rand(SIZE)
    x_medium_points = np.empty(0) # すべての中間点のx座標を格納するndarray
    y_medium_points = np.empty(0) # すべての中間点のy座標を格納するndarray
    # すべてのランダム点間を分割するループ
    for i in range(SIZE - 1):
        x_medium_points, y_medium_points = plot_split(
            x[i], x[i + 1], y[i], y[i + 1], x_medium_points, y_medium_points
        )
    # ndarrayの分割
    for n, x_split_array, y_split_array in zip(
        range(SPLIT_ARRAY),
        np.array_split(x_medium_points, SPLIT_ARRAY),
        np.array_split(y_medium_points, SPLIT_ARRAY)
    ):
        plot_split_curve(x_split_array, y_split_array, DEGREE, n)
    plt.legend()
    plt.show()

plot_curve()
```

- ランダム点30個、次数30、中間ランダム点の分割数3

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/e5879745-3009-1e02-c175-9ba453e2206e.png)


- ランダム点30個、次数30、中間ランダム点の分割数6

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/affac599-3e08-9c55-9e16-6d0de1ccb1b1.png)

# 参考記事

https://www.python.ambitious-engineer.com/archives/1843
VBA .csv保存

```
Sub csv保存()
    
        Application.DisplayAlerts = False  '上書き保存する際に、警告メッセージを無視します。
        
        ActiveSheet.Copy '現在のアクティブシートを新規ブックに保存します。
        
        ActiveWorkbook.SaveAs Filename:="C:\Users\user\Documents\text.csv", FileFormat:=xlCSV, Local:=True 'CSVファイルに保存します。
        
        Application.DisplayAlerts = True    '警告メッセージの無視を解除します。
        
        ActiveWorkbook.Close SaveChanges:=False

End Sub
初投稿_「Active Directory」について

目次
・Active Directoryとは
・Active Directoryの仕組み
・専門用語
参考
https://www.sbbit.jp/article/cont1/37798
■Active Directoryとは
Active Directory（アクティブディレクトリ）とはWindows Serverに備わっている機能で、認証管理システムのこと。
「ディレクトリ」=データの場所や関係性を表す一覧表。
※データの関係性や場所を分かりやすくするための「ディレクトリ」であって、データそのものではない。
■Active Directoryの仕組み
Active Directoryでは「ドメイン」にリソースの関係性を表す領域が作成されます。
「ドメイン」は大きなファイルのようなもので、「ドメイン」の中に、
・ユーザー
・プリンタ
・PC
・共有データ
・部署
・プロジェクトチーム
といったリソースに関する情報を格納する。
利用者は「ドメインコントローラー」にユーザー名とパスワード等を入力し認証を受けることで、
チケットを配布してもらいチケットで自分と関わりのあるリソースに自由にアクセスすることができるようになる。![Active-Directory-Figure.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120895/b301a120-ef30-090a-f1e2-a95e9ab7f3b1.jpeg)

■専門用語
「ドメインツリー」=全く違うドメインと信頼関係を結べる。(会社の合併・吸収に柔軟に対応できる)
「フォレスト」=1つ以上のドメインツリーで構成された最大の単位
「シングルサインオン」=1度のログインでさまざまなリソースにアクセスできるようになる仕組み。
ex.
「ドメインツリーの関係」GmailアカウントでGoogle Driveを使える。
「フォレストの関係」GmailアカウントでGoogle以外のサービスにもログインできる。

「フェデレーション」=認証連携。一度認証を通れば、その認証情報を使って、許可されているすべてのサービスを使えるようにする仕組み。フォレストはWindows Server内でActive Directoryを使った信頼関係を指すのに対して、外部のクラウドサービスやウェブサービスにおいてシングルサインオンができる関係性がフェデレーション。
【Python tips】htmlタグの削除の方法

##1.はじめに
今回はテキストデータからHTMLタグを削除する方法を紹介します。
htmlタグは文章の意味を学習させる際にノイズとなるデータです。
なので、削除してあげることが重要になります。

##2.環境
- MacOS Catalina10.15.5
- Miniconda
- Python3.7.5

##3.例題

```はまってしまう!楽しい!!	ついついやってしまいます。<br />簡単なものから難しいものまで<br />子供と一緒に楽しく遊べて考えながら<br />出来るので面白いです。
```

Amazon Reviewのデータセットから<br />タグが付いている文章を抽出しました。

ここから<br />タグを抜き出しましょう。

##4.方法

###4.1.beautiful Soupのインストール
まずはPythonライブラリであるbeautiful soupをMiniconda環境にインストールします。

```
>conda install beautiful Soup
```

###4.2.変数htmlに文字列を代入

```
>>>html = ""はまってしまう!楽しい!!	ついついやってしまいます。<br />簡単なものから難しいものまで<br />子供と一緒に楽しく遊べて考えながら<br />出来るので面白いです。""
```

###4.3.HTMLタグを除去する関数を定義
```
from bs4 import BeautifulSoup

def clean_html(html, strip=False):
      soup = BeautifulSoup(html, 'html.parser')
　　　 text = soup.get_text(strip=strip)
      return text
```

###4.4.出力する
```
clean_html(html)
```

他にも正規表現を使った方法などもあるので追々紹介できたらと思います！
【VBA】セルへの値代入と削除


# ◆セルへの値の代入

```vb:rangeSample.xlsm
Sub rangeSample()

    'セルへの値の代入
    Worksheets("Sheet1").Range("A1").Value = "A1"
    
    'Worksheets を省略するとアクティブなシートが対象となり動作する
    Range("A2").Value = "A2"
    
    ' 複数セルの への代入
    Range("A3", "B4").Value = "A3 - B4"
    Range("A5:B6").Value = "A5 - B6"

     '行や列全体への代入
    Range("7:7").Value = "Row 7"
    Range("C:C").Value = "Column C"
      
End Sub
```

```vb:cellsSample.xlsm
Sub cellsSample()

    'Cells を用いると行・列を数値で指定できる
    Worksheets("Sheet1").Cells(1, 5).Value = "(1, 5)"
    Cells(2, 5).Value = "(2, 5)"
    
End Sub
```

# ◆相対位置のセルに値を代入
```vb:offsetSample.xlsm
Sub offsetSample()

   'Offset を用いると相対位置に値を入力できる
    Range("A1").Offset(1, 1).Value = "A1 + (1, 1)"
    Cells(3, 3).Offset(1, 1).Value = "(3, 3) + (1, 1)"

End Sub
```

# ◆セルの値の削除
```vb:clearSample.xlsm
Sub clearSample()

    Range("A1:C3") = 1

    'Clear で値を削除できる
    Range("A1").Clear
    Cells(2, 2).Clear

End Sub
```
なお、Cells.Clearをすれば、全セルの値を削除する。
シェルスクリプト＋ロックファイルで二重実行防止

# はじめに

cronで定期的にコマンドやシェルスクリプトを実行する場合、

* そのコマンドやシェルスクリプトが応答を返さない
* 処理が遅く次の定期実行タイミングまでに終わらない

という事象が発生する可能性があり、そうなった場合はcronで次に予定されている実行を防止する必要があります。

この防止がない場合、cronは予定されている間隔で無条件(前回の実行状態を加味せず)にコマンドやシェルスクリプトを実行していきますので、その分プロセスが残っていき、最後にはメモリ不足が発生しサーバーの応答がなくなるなどの問題に繋がる場合があります。

今回はシェルスクリプト＋ロックファイルでその防止(二重実行防止)を実現するやり方を紹介します。

また、今回の二重実行防止策は、

* 定期実行の後処理でいろいろなことをしたい方！
* 引き継いだサーバー＋定期処理で再起動時にロックファイルが残ってしまう事象に遭遇している方！

そんな方々のお役にも立てられるかもしれません。

では本題です！

# シェルスクリプト例

```Bash:my-script.sh
#!/bin/bash

LOCKFILE="/var/run/my-script.lock"
if [ -f $LOCKFILE ]; then
  echo "Already execute script."
  exit 9
fi
trap "{
  rm $LOCKFILE;
}" EXIT
touch $LOCKFILE

#ここにやりたいことを書く
```

簡単ですね。
touchコマンドで特定の位置(/var/run)にロックファイル(my-script.lock)を生成し、次の実行でそのロックファイルが存在している==前に実行したシェルスクリプトが実行中と判断し中断する、というものです。

以降で、もう少し詳しく見ていきましょう。(trapはなに？？？ということも含めて)

```Bash
LOCKFILE="/var/run/my-script.lock"
```

ロックファイルのパスを変数に格納します。
/var/runにはプロセスIDを記載した.pidファイルが格納されますが、今回は/var/runに作成するようにしました。ここは任意のフォルダやファイル名で問題ありません。

ただし書き込み権限があるフォルダにする必要がありますので、その点だけ注意してください。

```Bash
if [ -f $LOCKFILE ]; then
```

ロックファイルの存在をチェックしています。
-fは"ファイルが存在するか"になります。
-eで"パスが存在するか"になりますが、そちらでも問題ありません。

```Bash
  echo "Already execute script."
  exit 9
```

ロックファイルが存在していれば、エラーを出して終了しています。上記の場合の終了コードは9になりますが何番でもかまいません。(0でも可)

スクリプトの呼び元で終了コードを判定する場合に適切な終了コードを指定してください。

```Bash
trap "{
   rm $LOCKFILE;
}" EXIT
```

これがこの記事の肝になります。(私的に)

一見、

```Bash
\#ここにやりたいことを書く

rm $LOCKFILE;
```

とスクリプトの最後でも問題ないように思います。
しかしながら "#ここにやりたいことを書く"で書いたことが応答を返さないなど正常に終了しないケースもあり、Ctrl+C で中断したりプロセスをkillしたりしますが、その場合はロックファイルが削除されません。(実行中にサーバーを再起動した場合も同じですね)

trapを利用することで、Ctrl+Cでの中断やプロセスkillのシグナルを受信(トラップ)することができ、任意の処理(ここではrm)を行うことができます。シグナルについてはここでは省きます。


```Bash
touch $LOCKFILE
```

touchはタイムスタンプを変更するコマンドですが、存在しないファイルを指定した場合は空(ファイルサイズが0)のファイルを作成します。今回の二重実行防止ではファイルが空であれ存在しているかどうか、が判断できればよいので、ロックファイル生成の目的でtouchを利用しています。

# その他の後処理

今回、

```Bash
trap "{
   rm $LOCKFILE;
}" EXIT
```

ではrmでのロックファイルを削除するだけになっていますが、それ以外の後処理も記載することが可能です。

以下はあくまでも例ですが、

* その他不要プロセスのkill
* その他残骸ファイルの削除
* LED消灯
* メール通知
* 某所への投稿

などなど。

※何がどこまでできるかは私自身も把握しておりません。例ということでご理解ください。

# その他の二重実行防止

今回のシェルスクリプト(touch、trap、rm)を利用したやり方以外にも、

* 各言語のシグナル処理を利用する。
* ps、grepを利用する。

などがあります。

各言語にはシグナル処理があり、そちらでシグナルを受信し任意の処理を実行することも可能です。
ただ引き継いだソースにシグナル処理がなく、手っ取り早く対応したいなんて時は今回のやり方で対応してみては如何でしょう。

またps、grepを利用する方法については以下の記事で書きました。あわせてご確認ください！

ps、grepを利用して二重実行防止 - Qiita
https://qiita.com/SECUAL_masa/items/f402546bca49c4943e7e

他にこんなやり方があるよ！って方はぜひコメントいただけると幸いです。
【AWS】仮想化を理解する

#プログラミング勉強日記
2021年4月19日

#クラウドと仮想化
　クラウドは、仮想化技術によって成り立ってるサービスのこと。仮想化は、サーバー、CPU、メモリといった物理的なインフラの構成を抽象化して、物理的な制限にとらわれることなくソフトウェア的に統合・分割できるようにする技術のこと。

　図のようにサーバーの中に複数のサーバーを仮想化して作ることでインフラとしては物理的な1つのサーバーだが、それを分けることができる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/4d15226e-7cee-833f-8525-5caefa944a66.png)

#仮想化の仕組み
　物理的なインフラに仮想化ソフトウェアを設定して、実質的な機能をユーザごとに切り分けて提供できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/2e79f993-4c52-64e4-6ba5-4d5dc74983b0.png)

　①物理的なサーバーを仮想化したい。(容量が大きすぎて1つのシステムではもったいないときなど)
　②1つの物理的なサーバーを仮想化するためには、サーバーの中に仮想化ソフトウェアをインストールしてセットアップする必要がある。仮想化ソフトウェアでは、VMware型とハイパーバイザー型の2タイプがよく使われる。
　③個々のユーザはそれぞれが単体のサーバーのように利用できる。具体的には、別のOSを使用することができる。

#仮想化の対象
　サーバー・ストレージ・ネットワーク・デスクトップを仮想化することができる。

　サーバーの仮想化は、1代の物理的なサーバー上に複数のOSを動作させる技術。ストレージの仮想化は複数のストレージを仮想的に統合して1つの大きなストレージプールを構成する技術。ネットワークの仮想化は、新しい仮想ネットワークの構築や制御をソフトウェアによって動的に行う技術。デスクトップの仮想化は、サーバー上においたPC環境のデスクトップ画面を遠隔地にある接続端末に転送する技術。
　デスクトップの仮想化は主に、セキュリティを高めるために使われる。PCにすべての情報が入っているとPCを紛失したときにセキュリティのリスクが高い。そのため、PCにはセットアップされていなくてインターネットに接続できるようにする共有するだけの機能を使って、仮想化デスクトップとして遠隔地の端末にデスクトップをデータセンターから映し出すといった中央管理されたデスクトップの提供ができる。AWSではAWS WorkSpacesといったサービスで仮想化デスクトップを提供している。

#仮想化のメリット
　仮想化を利用することで、インフラ利用の効率性や柔軟性が向上する。

- サーバースペースの削減
- データセンターの費用の削減
- セキュリティの向上
- 効率的にサーバーを利用できる
- 構成変更やメンテナンス対応の柔軟性
[PHP] 3桁ごとに数値にカンマを挿入する

#概要
金額を表示するために3桁ごとにカンマで区切りたい場合、
PHPだと関数一つで簡単に実現することができます。

例）1000000　→　1,000,000

#方法
* number_format()を使う

```.php
<?php
	$num = 1000000;

	$result = number_format($num);

    print_r($result);
?>

//結果：1,000,000
```

文字列でも可能です。

```.php
<?php
	$str = '1000000';

	$result = number_format($str);

    print_r($result);
?>

//結果：1,000,000
```
【OpenAPI】swagger × prismでモックサーバーを構築

## 概要

前回swaggerでAPIドキュメントを作成したので今回は作成したドキュメントをモックサーバーとして活用する方法をまとめました。
前回の記事は以下のリンクから遷移できます。

https://qiita.com/d-yamagishi522/items/c2626171781dbc8eba00

## docker-compose.ymlについて

前回との差分の解説を書いていきます。

```docker-compose.yml
prism:
  image: stoplight/prism:3
  volumes:
    - ./swagger.yml:/swagger.yml
  # prismは4010で立ち上がるのでとりあえず3000を指定
  ports:
    - "3000:4010"
  # -h でホストを指定してからモックサーバーとして使用するファイルを指定
  command: mock -h 0.0.0.0 /swagger.yml
  # swagger.ymlが作成されてから起動
  depends_on:
    - "swagger-merger"
```

```swagger.yml
/user:
 get:
  ~ 省略 ~
  responses:
    '200':
       description: ユーザーデータ
       content:
         application/json:
           schema:
             properties:
               id:
                 example: 61798c29-d0e3-472f-91dd-db912e602249
                 type: string
               name:
                 example: ユーザー名
                 type: string
             type: object
```

ターミナルで以下を実行

```
$ curl http://localhost:3000/user
```

exampleで指定した内容が返ってきます

```
{"id":"61798c29-d0e3-472f-91dd-db912e602249","name":"ユーザー名"}
```

## まとめ

開発初期にAPIのドキュメント作成とモックサーバーの構築を行うことでフロントエンドとバックエンドを並行して開発を進められるのでかなり便利だと感じています。

https://github.com/d-yamagishi522/sample-openapi
chrome拡張modHeaderを使ってreferer偽装した話

メモ的な感じで書いていきます。

## modHeaderとは
リクエストヘッダを編集出来て便利。
ここではreferer偽装して諸々を解決した。

## そもそものやりたかったこと
localhostからとあるドメインにアクセスしたときにエラー(クロスドメイン)になるので、そうならないようにしたかった

※refererとは[ここに書いているのがわかりやすかった](https://wa3.i-3-i.info/word129.html)

## サーバーにも設定してもらった
リファラ設定とアクセス先を提示してもらって、フロント側がそれを対応する感じ。

ここでは例として
リソースアクセスドメイン(バイナリアクセス用)　⇒　resource.jp
リファラドメイン　⇒　referer.co.jp
とする。

resource.jpをlocalhostからアクセスできるようにするため、リファラ偽装をしてresource.jpにアクセスできるようにするということ。

## modHeaderの設定
modHeaderを追加するとこういう画面が出るので
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431968/0d0e47c6-471f-7ae6-a53c-49b42114075f.png)
リクエストヘッダーに指定されたrefererにリファラドメインを入力。

これを入力するだけだと全サイトにアクセスするときにrefererが有効になってしまうので、
filterをかけて制限をする。
filterのURL Patternに正規表現を入れると
ヘッダーの変更は、指定された正規表現に一致するすべてのURLで有効になります。
例ではresource.jpにアクセスした時だけ有効にするみたいなfilterをかけるとうまくいくみたいです。
(最初アクセス元のlocalhostを入れるんだと思ってたけど違って、アクセスしたいURL？だったぽい)

ちなみにresource.jpの場合、URL Patternはhttps:\/\/resource.jpでいける

これでクロスドメインを起こさずアクセスすることができるようになる。

## おまけ
リクエストヘッダーとレスポンスヘッダーは書き換え可能。便利。
ユーザーエージェントも書き換えできるんじゃないかな？
また便利なことあったら追記するつもり

## 参考というか本家

* [公式サイト](https://bewisse.com/modheader/)
* [chrome Web Store](https://chrome.google.com/webstore/detail/modheader/idgpnmonknjnojddfkpgkljpfnnfcklj?hl=ja)
LeetCode日本語修行6日目- [27- 指定要素の削除]

## Remove Element
#####参考：https://leetcode.com/problems/remove-element/
###問題の内容:
配列numsの中に、valとイコールのvalueをその場で削除し、新しい長さを返します。
余分なスペースを使わない。順序は変更可能です。新しい長さの先に気にしない。
###例:
例1:
Input: nums = [3,2,2,3], val = 3
Output: 2, nums = [2,2]
Explanation: Your function should return length = 2, with the first two elements of nums being 2.
It doesn't matter what you leave beyond the returned length. For example if you return 2 with nums = [2,2,3,3] or nums = [2,2,0,0], your answer will be accepted.

例2:
Input: nums = [0,1,2,2,3,0,4,2], val = 2
Output: 5, nums = [0,1,4,0,3]
###ヒント:
0 <= nums.length <= 100
0 <= nums[i] <= 50
0 <= val <= 100

---
二重ポインタを使います、

```Kotlin
class Solution {
    fun removeElement(nums: IntArray, `val`: Int): Int {
        var start = 0
        var end = nums.size - 1

        while(start <= end){
            if(nums[start] == `val`){
                nums[start] = nums[end]
                end--
            } else {
                start++
            }
        }

        return start
    }
}
```
ubuntuのzshでbashのようにコマンドの提案を行う

ubuntuのbashで存在しないコマンドを実行した場合、

```bash
$ ruby

コマンド 'ruby' が見つかりません。次の方法でインストールできます:

sudo snap install ruby  # version 3.0.0, or
sudo apt  install ruby  # version 1:2.7+1

他のバージョンについては 'snap info ruby' を確認してください。

```
のようになる。だがzshでは

```zsh
$ ruby
zsh: command not found: ruby
```
だけしかメッセージが表示されないため、いつも`ubuntu {パッケージ名} インストール`でggっている。
# コマンドが見つからないときの挙動
調べてみるとコマンドが見つからないときには関数`command_not_found_handle`が実行されるようだ。関数の定義は`declare`で調べられるらしい。実行してみると

```bash
$ declare -f command_not_found_handle
command_not_found_handle ()
{ 
    if [ -x /usr/lib/command-not-found ]; then
        /usr/lib/command-not-found -- "$1";
        return $?;
    else
        if [ -x /usr/share/command-not-found/command-not-found ]; then
            /usr/share/command-not-found/command-not-found -- "$1";
            return $?;
        else
            printf "%s: command not found\n" "$1" 1>&2;
            return 127;
        fi;
    fi
}
```
となる。つまり、`/usr/lib/command-not-found`があればそれを、`/usr/share/command-not-found/command-not-found`があればそれを、両者ともなければ単純なメッセージを表示するという内容である。つまり、これを`~/.zshrc`にコピペすれば、

```zsh
$ ruby

コマンド 'ruby' が見つかりません。次の方法でインストールできます:

sudo snap install ruby  # version 3.0.0, or
sudo apt  install ruby  # version 1:2.7+1

他のバージョンについては 'snap info ruby' を確認してください。

```
成功！！
# `/usr/lib/command-not-found`
筆者の環境では、`/usr/lib/command-not-found`が実行されるようである。これのhelpを表示してみると、

```bash
Usage: command-not-found [オプション] <コマンド名>

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -d DATA_DIR, --data-dir=DATA_DIR
                        データフィールドの検索に次のパスを使う
  --ignore-installed, --ignore-installed
                        ローカルのバイナリーを無視して、利用可能なパッケージを表示する
  --no-failure-msg      '<コマンド名>: コマンドが見つかりません' を出力しない
```
と、表示される。また、ggってみると、環境変数COMMAND_NOT_FOUND_INSTALL_PROMPTをyに設定すると、インストールできる項目が一つしかない場合に、インストールするか聞いてくれます。
![Screenshot_20210419_210057.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643208/9a213470-a7b3-fe99-eb93-13827e8f0ba0.png)

# 参考
https://gihyo.jp/admin/serial/01/ubuntu-recipe/0516
Djangoでよく使うコマンド操作一覧

#Djangoでよく使うコマンド操作一覧

##概要
WEBアプリケーションを作るときにDjangoを使うのですが、よく使うコマンドをよく忘れてしまうのでまとめてみました!!


###プロジェクト作成

```python
django-admin startproject プロジェクト名
```

###アプリケーションの作成

```python
python3 manage.py startapp アプリ名
```

###サーバーの起動

```python
python3 manage.py runserver
```

###マイグレーションファイルを作成

```python
python3 manage.py makemigrations モデルのあるアプリ名
```

###マイグレーションファイルをデータベースに適用
```python
python3 manage.py migrate
```
HTTP/1.1、HTTP/2の特徴

# HTTP/1.1
HTTPは、長年に渡り機能追加と改良が重ねられてきた。現在はHTTP/1.1が最も普及している。
## HTTPキープアライブ
HTTP/1.0以前ではWebブラウザからHTTPリクエストを送信するたびにコネクションを確立し、WebサーバーがHTTPレスポンスを渡した段階でコネクションを閉じるという方法が用いられていた。
この方法では、Webページに画像データが埋め込まれていた場合、画像取得のために再度コネクションを確立する必要があるため、無駄な通信が発生していた。
HTTP/1.1以降では、コネクションを継続して利用する方式となり、この機能を**キープアライブ**と呼ぶ。
## HTTPパイプライン
通常はHTTPレスポンスを受け取るまでは、次のHTTPリクエストを送ることはできない。
しかし、HTTP/1.1では、HTTPレスポンスを待つことなく複数のHTTPリクエストを送信することができる**HTTPパイプライン**と呼ばれる機能がサポートされている。
これにより、複数のHTTPリクエストを短時間で処理できる。
![HTTPバージョン (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/999125/07dfbad9-0645-5210-492e-279ec1afc90e.jpeg)

# HTTP2
飛躍するデータ量の増加に対応するため2015年に公開されたのがHTTP/2である。
## ストリームによる多重化
HTTPパイプラインは「HTTPリクエストの順番通りにHTTPリクエストを帰さなかればならない」という制約があるため、複数のHTTPリクエストが送信されても、ある１つのHTTPレスポンスの処理に時間がかかる場合、それ以降のHTTPレスポンスはその処理を待つ必要があった。
この問題解決のため、HTTP/2では１つのコネクション上に「**ストリーム**」と呼ばれる仮想的な通信経路を複数形成し、それぞれのストリーム内での独立したやりとりを可能にしている。HTTPレスポンスの待ち状態が発生するということがなくなり、より高速で効率よくデータのやりとりが可能になった。
![HTTP2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/999125/8f94193c-2d01-b7a4-ed52-f3204f2caaec.jpeg)
![HTTP2.2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/999125/10317f20-d85f-047e-5d1b-46696ad32d17.jpeg)

## バイナリ形式の利用
HTTP/1.1以前ではHTTPリクエストやHTTPレスポンスのやりとりをテキスト形式のフォーマットで行ってきた。HTTP/2では、バイナリ形式（コンピュータが扱うためのデータ形式）のフォーマットとなったため、変換処理時間やWebブラウザやWebサバーの負担を軽くできる。
## ヘッダー圧縮
HTTPでのやりとりのヘッダー情報において、HTTPレスポンスはWebブラウザの種類など、HTTPリクエストはWebサーバーの除法などが重複する部分が多い。
HTTP/2では重複データの転送を避けるため、HPACKと呼ばれる圧縮方式を利用し、変更があった部分のみを転送している。
## サーバープッシュ
HTTP/2では、HTTPリクエスト内容をもとにWebサーバーが必要なファイルを判断し、事前にWebブラウザへ送信することができる。
例えば、HTMLファイル内に画像が埋め込まれていた場合、Webサーバーは画像に対するHTTPリクエストを受け取らなくても、事前に画像データを転送する。

# 参考
[イラスト図解式 この一冊で全部わかるWeb技術の基本](https://www.amazon.co.jp/gp/product/B06XNMMC9S/ref=ppx_yo_dt_b_d_asin_title_o05?ie=UTF8&psc=1)
cloud9のrails周りの環境構築メモ

## Yarn
Rails6をインストールするのに必要

```bash
$ npm install -g yarn
```

https://qiita.com/kutarou197/items/7a6be9a46739599cd378

## Ruby
デフォルトのバージョンだと、Herokuにデプロイできなかったりする。新しめのバージョンにアップデート。
cloud9ではデフォルトで、rbenvではなくrvmを使ってRubyのバージョンが管理されている。
アンストしてrbenvを入れ直してもいいけど、ここでは最小手数で行きたいのでrvmを使う。

```bash
$ echo rvm_autoupdate_flag=2 >> ~/.rvmrc # rvmが常に最新バージョンになるよう設定
$ rvm -v
$ rvm get latest # rvmのバージョンを最新版に更新
$ rvm -v
$ rvm list # インストール済みのRubyバージョンを一覧表示
=* ruby-2.6.3 [ x86_64 ]
$ rvm list known # インストール可能なRubyバージョンを一覧表示
$ rvm install 3.0.0
````

## Rails
```bash
$ gem install rails -v 6.1.3.1
$ rails -v
```

## ImageMagick
```bash
$ sudo yum -y install libpng-devel libjpeg-devel libtiff-devel gcc
$ cd
$ git clone https://github.com/ImageMagick/ImageMagick.git ImageMagick-7.0.11
$ cd ImageMagick-7.0.11
$ ./configure
$ make
$ sudo make install
```

## Heroku CLI
```bash
$ curl -OL https://cli-assets.heroku.com/heroku-linux-x64.tar.gz
$ tar zxf heroku-linux-x64.tar.gz && rm -f heroku-linux-x64.tar.gz
$ sudo mv heroku /usr/local
$ echo 'PATH=/usr/local/heroku/bin:$PATH' >> $HOME/.bash_profile
$ source $HOME/.bash_profile > /dev/null
$ heroku -v
$ heroku login --interactive
```

https://qiita.com/queq1890/items/1def659860416e2d90ff
sketchupでruby その6

#概要

sketchupでrubyやってみた。
material使ってみた。

#写真

![colorbox.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/c6384f9a-cc3a-a099-d4fd-8542d9bc107a.png)


#サンプルコード

```
def colorbox
    model = Sketchup.active_model
    entities = model.active_entities
    Sketchup.set_status_text "Please wait a little."
    for x in 0..8 do
       for y in 0..8 do
          for z in 0..8 do
             group = entities.add_group
             entitie = group.entities
             pts = []
             pts[0] = [x * 10 + 5, y * 10 + 5, z * 10 + 5]
             pts[1] = [x * 10 + 10, y * 10 + 5, z * 10 + 5]
             pts[2] = [x * 10 + 10, y * 10 + 10, z * 10 + 5]
             pts[3] = [x * 10 + 5, y * 10 + 10, z * 10 + 5]
             base = entitie.add_face pts
             base.pushpull 5
             materials = model.materials
             m = materials.add "ohi" + String(x) + String(y) + String(z)
             m.color = Sketchup::Color.new(x * 32 , y * 32 , z * 32)
             m.alpha = 0.7
             entitie.each { |e|
                case e
                when Sketchup::Face
                   e.material = "ohi" + String(x) + String(y) + String(z)
                end
             }
          end
       end
    end
end



```

以上。
"xcodeが予期しない理由で終了しました" が表示された時の解決方法

<br>
ある日突然"xcodeが予期しない理由で終了しました" と表示されXcodeの開発途中プロジェクトが
開かなくなってしまいました。

その時の解決法を備忘録として記載しておきたいと思います。

まずはエラーメッセージで検索し、先人が残してくれた記事を読みDerivedDataを削除してみたが
結果は変わらずでした。

## 解決法
**project.xcworkspace**を削除し、再度起動したら解決しました。

削除方法は、ターミナルを開き起動しないプロジェクトフォルダまで移動します。
EX)  Users/ユーザー名/Desktop/アプリ名/アプリ名.xcodeproj

その後、アプリ名.xcodeproj内にある**project.xcworkspace**を削除すれば完了です。

結局クラッシュした原因は分からずでしたが、とりあえず解決してよかったです。

また同じ事象が発生した時はログを見て少し解析してみようかなと思います。
【Python】すべてのシートの印刷設定を行う。

pythonを使用してExcelファイルの操作を勉強しています。
本日の気づき(復習)は、印刷設定に関してです。
pythonでExcelを操作するため、openpyxlというパッケージを使用しています。

何気に、印刷設定を行うのって苦痛ではないですか？
ヘッダーだったり、フッターだったり・・・。

# 印刷を行う属性一覧

調べてみると、印刷の設定を行う属性が沢山ありました。
主要と思われる所を以下にまとめています。

- print_area：印刷範囲
- print_title_cols：常に印刷する列
- print_title_rows：常に印刷する行
- oddHeader.center.text：ヘッダー中央部
- oddFooter.center.text：フッター中央部
- page_setup.orientation：印刷の向き（横：ORIENTATION_PORTRAIT）（縦：ORIENTATION_LANDSCAPE）
- page_setup.fitToWidth：ページ数に合わせて印刷する設定(横)１ページなら、「1」自動なら、「0」
- page_setup.fitToHeight：ページ数に合わせて印刷する設定(縦)１ページなら、「1」自動なら、「0」
- sheet_properties.pageSetUpPr.fitToPage：fitToWidth属性、fitToHeight属性を有効にする
- page_setup.paperSize：用紙サイズ

たぶん、これぐらいだと思います。

# 最終的なコード

```python
from openpyxl import load_workbook

print_area = 'A1:D50'
print_title_rows = '1:5'
header_text = '&F'
footer_text = '&P / &Nページ'

wb = load_workbook('サンプル.xlsx')

for ws in wb.worksheets:
    # プリントエリアを設定
    ws.print_area = print_area
    # 常に印刷する行を指定
    ws.print_title_rows = print_title_rows
    # ヘッダーを指定
    ws.oddHeader.center.text = header_text
    # フッターを設定
    ws.oddFooter.center.text = footer_text

    wps = ws.page_setup
    # 印刷の向きを設定
    wps.orientation = ws.ORIENTATION_LANDSCAPE
    # 横を１ページ
    wps.fitToWidth = 1
    # 縦を自動
    wps.fitToHeight = 0
    # fitTo属性を有効にする
    ws.sheet_properties.pageSetUpPr.fitToPage = True
    # 用紙サイズを設定
    wps.paperSize = ws.PAPERSIZE_A4

wb.save('サンプル_印刷設定.xlsx')
```

気を付けたポイントは

worksheets属性で全シートを取得して繰り返し処理をする。

ヘッダー、フッターには
ブック名を表す'&F'、ページ番号を表す'&P'、総ページ数を表す'&N'
を、それぞれ設定した。

page_setup.fitToWidth属性、page_setup.fitToHeight属性を使用した場合は
sheet_properties.pageSetUpPr.fitToPage属性を「True」にしないと有効にならない。

と言うところでしょうか。

比較的簡単に、前ページ変更できるのでお勧めです。
【Swift】Cartographyを使ってコードだけで簡単に画像を実装

Swiftの超便利ライブラリ「Cartography」を使ってコードだけで画像を実装する方法をご紹介します。

感覚としてはCSSみたいに実装できます。

podで導入する際はPodfileに

```
pod 'Cartography'
```
を書いて
初めてPodをインストールするプロジェクトなら

```
pod install
```
Pod installしてあるプロジェクトなら

```
pod update
```
を実行。

実装するSwiftのコードは以下の通り。

```swift
import UIKit
import Cartography

(中略)

let Image : UIImage = UIImage(named:"sample")!
let imageView = UIImageView(image:Image)
self.view.addSubview(imageView)
constrain(imageView) { image in
    image.width  == 50
    image.height == 50
    image.centerX == image.superview!.centerX
    image.centerY == image.superview!.centerY
}
```

コードの順番（特にaddsubview）とか間違えるとエラーになるのでご注意ください。

補足
・superviewとは親要素のこと（今回はself.viewのこと）
・centerXとは中心のX軸の値
・centerYとは中心のY軸の値

## Swiftのお役立ち情報

https://wagtechblog.com/programing/swift-iphone-application-school

https://wagtechblog.com/programing/swift-textbook.html
AWS CLI 多要素認証を設定しなければならなくなったとき

# 初めに

国のガイドラインなどで、多要素認証が義務付けられることは多いです。AWS CLIを使ってデータを扱う際にも多要素認証が必要になることがあります。そんなとき、AWSのドキュメントにちょうど解決方法が記載されていましたので紹介します。

https://aws.amazon.com/jp/premiumsupport/knowledge-center/authenticate-mfa-cli/

# 手順

## 1. 仮想MFAデバイスのインストール

こちらからインストールします。

https://winauth.github.io/winauth/download.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/6abaa3a4-e266-34f3-ee7c-ca95ee7d9ec5.png)

## 2. MFAデバイスを割り当てる

IAMからユーザーを選択し、赤枠で囲った「管理」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/107c6341-750c-ab7d-f202-1e5b70bd30b3.png)

## 3. 一時認証情報の取得

デフォルトのまま続行をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/c13f565e-9441-b19d-71e7-1d2d061c5634.png)

シークレットキーの表示をクリックし、シークレットキーをコピーします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/17553c31-57b7-56de-0675-5285ac819c9c.png)

WinAuth.exeを起動し、Addをクリックします。Authenticatorを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/2f407e71-eaa6-fe1c-ec49-0fae7af75697.png)

シークレットキーを1. Enter the Secret Code ... のテキスト部分に貼り付けます（緑枠で囲った部分）。その後、3. Click the Verify button ... の箇所にある「Verify Authenticator」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/15238ab5-01e6-1b1a-4a5f-478dc3835220.png)

次に、4. Verify the followinf code ... の場所に一定間隔で6桁の数字が表示されるので、2回連続でその数字を記録します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/534cbe99-a000-7f93-947d-68f24d5e28e2.png)

それらの数字をMFAコード1, 2に入力します。その後、MFAの割り当てをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/e2f4db51-ceb5-f327-7008-2bf2585fb1b0.png)

## 4. profileに一時認証情報を追加する

以下の更新マークを押すと、**- - - - - -** の部分に6桁の数字が表示されるのでメモしておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/c4eb5b9b-1497-9a49-c030-7c8a55ec76cb.png)


コマンドラインで以下を入力します。（もちろんcliを操作できるロールまたは認証情報が別途必要です）

`--serial-number`には、ARNを渡します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/114cca95-b8bb-6d5c-6f38-f32cd672f002.png)


`--token-code`には、先ほどの6桁の数字を渡します。

```
$ aws sts get-session-token --serial-number arn:aws:iam::012345678912:mfa/user_name --token-code 012345
```

アクセスキーID、シークレットキーアクセスキー、セッショントークンが返ってきます。

```
{
    "Credentials": {
        "AccessKeyId": "ASIA...",
        "SecretAccessKey": "Edr...",
        "SessionToken": "IQo...",
        "Expiration": "2021-04-19T22:42:00+00:00"
    }
}
```

これらを`.aws/credentials`に登録します。（もし永続的なIAM 認証情報である[default]があれば、[default]を消去して次のステップに進むと一時認証が機能していることがわかります）

```
[mfa]
aws_access_key_id = ASIA...
aws_secret_access_key = Edr...
aws_session_token = IQo...
```

profile名を与えてcliを操作します。

```
$ aws s3 ls --profile mfa
```

# 参考記事

https://aws.amazon.com/jp/premiumsupport/knowledge-center/authenticate-mfa-cli/

https://www.ooooouchi.info/entry/2020/05/26/080000
【VBA】VBAでのHello world

VBAでのHello Worldとコメントの書き方。

```vb:helloWorld.xlsm
Sub helloWorld()
    'コメントはシングルコーテーション で記述
    MsgBox ("Hello World")
End Sub
Sub helloWorld2()
    'アンダーバーを使うと複数行に渡る文を書ける
    MsgBox _
    ("Hello World 2")
End Sub
```
機械が言うと角が立たない

# 背景
「マスクして」と直接言うと角が立つ
「マスクしてって、AIが言っています」といえばそうでもないのでは

# 何をする？
- マスクしていない人を見つける
- マスクをしばらくしていない人に「マスクしぃやぁ」とリコメンドする

# 実現のために必要なもの
1. 顔の部分を認識する
2. 顔にマスクがあるかどうかを認識する
3. マスク無しの人が以前と同じ人かどうかを認識する
3. 一定時間マスクなしの人がいる場合、発声する

# どうやって作ろう
1. 1-3はモデルを作る必要があるだろう
1. 4は1−3ができればルールベースで普通に開発できるだろう
というよみのもと、1を更に考える
* 顔の部分を認識するー＞クラウドビジョンでfaceannotationとして囲まれた部分でよいのでは？
* マスクがあるかどうかを認識するー＞APIで返してくれるものは見つからなかった、、
* 同じ人かどうか確認するー＞Azureの顔検証でできるのでは？

マスク有無の判定は手元で作るしかないかも、、と思ったら[lobe](https://lobe.ai/)というアプリをMSが出していた

![トヨタ_2019-02-18-2021-03-29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328600/b1f479a9-fe7a-8dbc-fa6d-de916cf994aa.png)


```python:マスクなし画像の判定
Predicted: {'predictions': [{'label': 'UnMask', 'confidence': 0.9900614023208618}, {'label': 'Mask', 'confidence': 0.0099386190995574}]}
```

![mask_トヨタ_2019-02-18-2021-03-29.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328600/ff46849e-c010-162c-e884-8eeac5597dd7.jpeg)

```python:マスクあり画像の判定
Predicted: {'predictions': [{'label': 'Mask', 'confidence': 0.9465017318725586}, {'label': 'UnMask', 'confidence': 0.0534982867538929}]}
```

# ノーコードのAIモデル構築
とりあえず動かし始めるには十分
環境整えてデータそろえて自前で学習するか事前学習を持ってくるか検証して考えて、、、
という重厚なフローをイメージしたのに、今回のこの程度であればもう道具はそろっていた

# やったこと

自分のマスク付けた画像とつけてない画像をそれぞれ20件そこら投入して学習する
当然上記で判定した人物とは全く別物、かつ、背景も雑多
![20210419_lobe_metrics.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328600/283acdcc-e099-99cc-f0b4-d31e01231e94.png)

好きな感じにエクスポートする
今回はTensorFlowを選択。出てくるサンプルコードはv1系を使用する（それはそれで面倒なことが起きそうではある、、）

![20210419_lobe_export.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328600/faac1722-18e1-1a4a-0494-e6e556650850.png)

フォルダにあるReadmeにある通りに実行するだけで上記のような結果が得られる。
あとは周辺アプリを開発するだけ
- test-imageフォルダは自分で作成して判定対象の画像を配置した
- tf-venvはreadmeに従って操作すると作成される仮想環境フォルダ

![20210419_sample_code.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328600/c86efd90-a6ae-c3be-48b4-5b868473fec9.png)

# 精度が必要なのか？

連携する部分と物理ガジェットは人がするが、もはやAI開発ではなく普通の開発に見える。精度が7-8割で目的を達成できるのであれば注力すべきは物理ガジェットや可愛い声になるのかもしれない。
それはそれとして作れるところまで作ってみよう
【Swift】コードだけでUIScrollViewの定義

UIScrollViewの定義を解説する記事の殆どがstoryboardでの実装ばかりだったので、コードでの実装をメモとして残しておきます。


```swift
let scrollView = UIScrollView()
scrollView.frame = self.view.frame
scrollView.contentSize = CGSize(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
self.view.addSubview(scrollView)
```

たった４行だけ。

個人的にはstoryboardよりも実装しやすいのでこちらの方法を選択しています。

＊UIScrollViewのwidthやheightは状況に応じてカスタマイズしてください。


## Swiftのお役立ち情報

https://wagtechblog.com/programing/swift-iphone-application-school

https://wagtechblog.com/programing/swift-textbook.html
2セットのデータ全体の分散

# はじめに

2014年6月の統計検定2級の問4で出題された2セットのデータ全体の分散

```math
s_z^2 = \frac{1}{2n - 1}\left\{(n-1)(s_x^2 + s_y^2) + \frac{n}{2}(\bar{x} - \bar{y})^2\right\}
```
を導出します。

# 2セットのデータ全体の分散の導出

同一の条件において、
1セット目データ{$x_1, ..., x_n$}の平均が$\bar{x}$、分散が$s_x^2$であり、
2セット目データ{$y_1, ..., y_n$}の平均が$\bar{y}$、分散が$s_y^2$となるデータが得られたとする。

全体の平均を$\bar{z} = (\bar{x} + \bar{y}) / 2$であることを用いると、全体の分散$s_z^2$は以下のように表される。

```math
\begin{align}
s_z^2 &= \frac{1}{2n - 1}\left\{\sum_{i=1}^n(x_i - \bar{z})^2 + \sum_{i=1}^n(y_i - \bar{z})^2)\right\}\\
&= \frac{1}{2n - 1}\left\{\sum_{i=1}^n\left((x_i - \bar{x}) + \frac{\bar{x} - \bar{y}}{2}\right)^2 + \sum_{i=1}^n\left((y_i - \bar{y}) + \frac{\bar{y} - \bar{x}}{2}\right)^2\right\}\\
&= \frac{1}{2n - 1}\left\{\sum_{i=1}^n(x_i - \bar{x})^2 + \sum_{i=1}^n(y_i - \bar{y})^2 + \frac{\bar{x} - \bar{y}}{2}\sum_{i=1}^n(x_i - \bar{x}) + \frac{\bar{y} - \bar{x}}{2}\sum_{i=1}^n(y_i - \bar{y}) + n\left(\frac{\bar{x} - \bar{y}}{2}\right)^2 + n\left(\frac{\bar{y} - \bar{x}}{2}\right)^2\right\} \\
&= \frac{1}{2n - 1}\left\{(n-1)s_x^2 + (n-1)s_y^2 + 0 + 0 + 2n\left(\frac{\bar{x} - \bar{y}}{2}\right)^2\right\} \\
&= \frac{1}{2n - 1}\left\{(n-1)(s_x^2 + s_y^2) + \frac{n}{2}(\bar{x} - \bar{y})^2\right\}
\end{align}
```


# どのような問題が実際に出題されたか

ざっくりとした問題の内容は、
「1セット10回のゲームを5人で2セット実施したとき、2セットを通して得点が安定していたのは誰か」
である。

|人|セット|平均|標準偏差|
|-|-|-|-|
|A|1|4.1|2.02|
|A|2|4.8|1.23|
|B|1|3.8|2.86|
|B|2|4.1|1.37|
|C|1|8.7|0.95|
|C|2|8.7|0.95|
|D|1|7.2|1.14|
|D|2|6.8|1.23|
|E|1|5.1|0.74|
|E|2|8.7|1.16|


# 問題の解答

1セット目と2セット目で「平均の差が小さい」ことと「標準偏差が小さい」ことに注目すると、
得点が最も安定しているのは、CさんとEさんに絞られる。

したがって、CさんとEさんのデータ全体の分散$s_C^2$と$s_E^2$を求めて比較する。

Cさんのデータ全体の分散は以下になる。

```math
\begin{align}
s_C^2 &= \frac{1}{2\times10 - 1}\left\{(10 - 1)(0.95^2 + 0.95^2) + \frac{10}{2}(8.7 - 8.7)^2\right\} \\
&= \frac{18}{19}0.95^2 \\
&\approx 0.855
\end{align}
```

同様にして、Eさんのデータ全体の分散は以下になる。

```math
\begin{align}
s_E^2 &= \frac{1}{19}\left\{9(0.74^2 + 1.16^2) + 5\times0.42^2\right\} \\
&\approx 0.980
\end{align}
```

したがって、$s_E^2 < s_E^2$より、
2セットを通して得点が最も安定しているのはCさんになる。

# 参考にしたもの

[統計検定2級 公式問題集](https://www.amazon.co.jp/%E6%97%A5%E6%9C%AC%E7%B5%B1%E8%A8%88%E5%AD%A6%E4%BC%9A%E5%85%AC%E5%BC%8F%E8%AA%8D%E5%AE%9A-%E7%B5%B1%E8%A8%88%E6%A4%9C%E5%AE%9A-2%E7%B4%9A-%E5%85%AC%E5%BC%8F%E5%95%8F%E9%A1%8C%E9%9B%86-2013%E3%80%9C2015%E5%B9%B4/dp/4788925281)
GitHubのOverviewを楽しくしよう

# はじめに
みなさん、GitHub使っていますか？
さて、そんなGitHubですが、Overviewをカスタマイズできるんです。

# やってみよう
実はもうやってしまっていて画像での解説ができませんが許してください。

## リポジトリ作る
アカウント名と同じ名前のリポジトリを作ってください。
私の場合はrisuneyなので、risuneyというリポジトリを作りました。ちなみに、READMEだけが必要なのでリモートブランチだけでいいでしょう。

## README

`README.md`を作成してcommitします。

# 完成

https://github.com/risuney

![できました](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1053860/17d94252-4714-324d-4cf2-7bc00dc90891.png)

完成しました。README作るだけです。簡単です。
Interlisp-D を起動するまで / Ubuntu20.04 on WSL2


https://g000001.cddddr.org/3806872251

私も動かすところまで試してみました。
現時点ではビルドの必要がなく、展開してすぐ起動できるようになっていたのでまとめてみます。

## 私の環境
Ubuntu20.04 on WSL2 上でX11 が起動するようにしてあります。

## maiko のセットアップ
※ナイトリービルドです。

```
wget https://github.com/Interlisp/medley/releases/download/nightly-210401/maiko-nightly-210401-linux.x86_64.tgz
tar xvfz maiko-nightly-210401-linux.x86_64.tgz
```
maiko フォルダができます。
## medley のセットアップ
※ナイトリービルドです。

```
wget https://github.com/Interlisp/medley/releases/download/nightly-210401/medley-nightly-210401.tgz
tar xvfz medley-nightly-210401.tgz
```
medley フォルダができます。
## 起動
```
medley/run-medley
```

起動しました！
![Desktop Screenshot 2021.04.19 - 20.07.35.53 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265413/8b1fea58-c02c-0502-0b86-aebd9af3f5a5.png)
【Swift】ホームボタンのあるiPhoneと無いiPhoneでレイアウトの処理を分ける

Swiftのレイアウトで厄介なのが

「iPhone6やiPhone8などのホームボタンがあるiPhone」
と
「iPhoneXSやiPhone11などのホームボタンが無いiPhone」

とでレイアウトがずれてしまう問題。

このホームボタンのあるiPhoneと無いiPhoneでレイアウトの処理を分けるコードを書いたのでメモとして残しておきます。

```swift
    if UIScreen.main.nativeBounds.height > 2208 || UIScreen.main.nativeBounds.height == 1792{
        //ホームボタンがあるiPhoneでの処理
    }
    else{
        //ホームボタンが無いiPhoneでの処理
    }
```
要は画面の縦幅から振り分けています。

縦幅の詳細はこちらの記事を参考にしました。

https://qiita.com/tomohisaota/items/f8857d01f328e34fb551

最初は2208をラインに振り分けていたのですが、iPhone11とiPhoneXRだけ縦幅のpxが2208より大幅に少ない1792でしたのでそれも考慮。

＊iPadについては考慮していません。
よく使用するコマンドまとめ

#はじめに
よく使うコマンドをまとめてみました。
他にも便利なコマンドがありましたら、その都度更新していきます。


##Git
###ファイル変更確認
```
git status
```
###ステージング
```
git add .

git add ファイル名 
```
.で全てステージングする
ファイル名で変更ファイルのみステージングする
###コミット

```
git commit -m "メッセージ"
```
###プッシュ

```
git push origin -u ブランチ名
```
-uを使用することで次回から　git pushでpush可能
###リモートリポジトリに新しいブランチを作成してpush
追記2021/5/20

```
git push origin 新しいブランチ名
```


###マージ
```
git merge 変更したブランチ名
```
###リモートの変更を取り込む(fetch)
```
git fetch
```
リモートの内容がローカルより進んでいる場合に使用する。
fetchすると、ローカル状のorigin/masterに変更が保存されるため、反映するにはセットでgit merge masterの作業が必要である。
###リモートの変更を一回で取り込む(pull)
```
git pull origin master
```
fetchとmergeを一括で行う方法。
###リモートの変更を取り込んでpushする
```
git pull origin develop
```
pullをpushを一回で行う方法。
###ブランチを作成し、移動
```
git checkout -b ブランチ名
```
###ブランチ削除
```
git branch -d ブランチ名
git branch -D ブランチ名
```
変更があった場合でも削除したい時は「-D」

###masterブランチ以外一括削除
```
git branch | grep -v master | xargs git branch -D
```
>https://qiita.com/takat0-h0rikosh1/items/766e207ba1c799ed1375

###特定のコミットまで戻る
```
git reset --hard ハッシュ値
```
>https://qiita.com/Yorinton/items/e0e969d961b17a359e19

### 直前のコミットの状態に戻す
追記2021/5/20

```
git checkout .
```

###直前のコミットメッセージを変更
追記2021/4/20

```
git commit --amend -m"コミットメッセージ"
3
```
###変更を一時的に退避したい時
追記2021/4/24

```
git stash
```
###stashした内容を削除する
追記2021/4/24

```
git stash drop
```
###コミットログ確認
追記2021/4/20

```
git log 
git log --oneline
```
onelineでコミットメッセージのみ表示

###変更内容を確認
追記2021/4/24

```
git diff
git diff ファイル名
```
ファイル名を指定することでそのファイルの変更内容のみ確認できる。
##Rails
###ルーティング確認
```
rails routes
```
###GemfileとGemfile.lockの差分をインストール

```
bundle install
```
###Gemfileを全てインストール
```
bundle update
```
gemfile.lockの情報関係なく１からgemfileをインストールする。

##Rails Console
###DBに保存しないでconsoleを使用する時
```
rails c -s
→rails console sandboxの略
```
###テーブルのカラムを確認する時
```
モデル名.column_names
```
機械学習における「モデル」を画像1枚で説明したかった


# 機械学習における「モデル」を画像1枚で説明してみる

![model.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/116386/d4054d2c-d224-8570-ef6a-b18321cbed7f.png)
sketchupでruby その5

# 概要

sketchupでrubyやってみた。
followme使ってみた。

# 写真

![sphere.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/852bbbfa-5f8b-308d-5f85-21d72f4f6f87.png)


# サンプルコード

```
def sphere
   model = Sketchup.active_model
   entities = model.active_entities
   x = 0
   y = 0
   z = 0
   r = 30
   n = 24
   circleBase1 = entities.add_circle(Geom::Point3d.new(x, y, z), Z_AXIS, r, n)
   circleBase2 = entities.add_circle(Geom::Point3d.new(x, y, z), X_AXIS, r, n)
   base = entities.add_face(circleBase1)
   status = base.followme(circleBase2)
end

```

以上。
sketchupでruby その4

# 概要

sketchupでrubyやってみた。
pushpull使ってみた。

# 写真

![cube.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/dc83fb37-5724-67aa-ef3a-c9e8e142ab69.png)


# サンプルコード

```
def cube
   cube = Sketchup.active_model.definitions.add("Cube");
   unit = 10
   p = Array.new;
   p[0] = ORIGIN;
   p[1] = [unit, 0, 0];
   p[2] = [unit, unit, 0];
   p[3] = [0, unit, 0];
   face = cube.entities.add_face(p);
   face.reverse! if face.normal.z < 0;
   face.pushpull(unit);
   trans = Geom::Transformation.new([5, 5, 5]);
   Sketchup.active_model.active_entities.add_instance(cube, trans);
end


```

以上。
継承

# 継承
継承とは、あるクラスを元に新たなクラスを作ることをいいます。
「`class 新しいクラス名(元となるクラス名)`」と記述することで他のクラスを継承して、新しいクラスを定義することができます。この時、新しいクラスを`子クラス`、元となるクラスを`親クラス`と呼ばれます。
継承により、親クラスのインスタンスメソッドをそのまま子クラスでも使うことができます。
しかし、子クラスで定義したメソッドは親クラスでは使えないので注意が必要です。

```py:script.py
from fruit import Fruit

fruit1 = Fruit('りんご', 200)

print(fruit1.info())
```
```py:fruit_price.py
class FruitPrice:
    def __init__(self, name, price):
        self.name = name
        self.price = price
   
    def info(self):
        return self.name + 'は' + str(self.price) + '円です'
```
```py:fruit.py
from fruit_price import FruitPrice

class Fruit(FruitPrice):
    pass
```
```text:出力結果
りんごは200円です
```
上記のように、継承させることで親クラスのインスタンスメソッドである`info`メソッドを子クラスで使うことができました。
まず、`script.py`で`Fruit`クラスを呼び出すことで、`fruit.py`内の`Fruit`クラスを呼び出します。この時、`Fruit`クラス(子クラス)は`fruit_price`内の`FruitPrice`クラス(親クラス)を継承させているため、
親クラス内の`info`メソッドを使うことができるので、`Fruit`の引数である`'りんご'`と`200`を用いて出力結果を得ることができました。
nvmを使用してNode.jsのバージョンを変更する方法

#初めに
今回は、CentOSに導入したNode.jsのバージョンをnvmで変更します。
nvmとは、Node.jsのバージョンマネージャーです。

私の環境のNode.jsはバージョン12.21.0ですが、バージョン14.16.1に変更したいと思います。


```
# node -v
v12.21.0
```

手順は、nvm公式のGitHubを参考にしました。
↓
https://github.com/nvm-sh/nvm

では、始めます。

#環境
■OS
CentOS 8

#nvmのインストール

curlコマンドを使用してインストールスクリプトを実行します。
curlコマンドは、データの転送やダウンロードができるコマンドです。

```
# curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.2/install.sh | bash

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 13527  100 13527    0     0  40621      0 --:--:-- --:--:-- --:--:-- 40621
=> Downloading nvm as script to '/root/.nvm'

=> Appending nvm source string to /root/.bashrc
=> Appending bash_completion source string to /root/.bashrc
=> You currently have modules installed globally with `npm`. These will no
=> longer be linked to the active version of Node when you install a new node
=> with `nvm`; and they may (depending on how you construct your `$PATH`)
=> override the binaries of modules installed with `nvm`:

/usr/local/lib
└── n@7.1.0
=> If you wish to uninstall them at a later point (or re-install them under your
=> `nvm` Nodes), you can remove them from the system Node as follows:

     $ nvm use system
     $ npm uninstall -g a_module

=> Close and reopen your terminal to start using nvm or run the following to use it now:

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
```
インストールスクリプトを実行後、「~/.bashrc」に設定が入っていることを確認します。

```
# vi ~/.bashrc

〜略〜
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion
```
設定が入っていることを確認しました。
sourceコマンドで、「~/.bashrc」を実行します。

```
# source ~/.bashrc
```

#Node.jsバージョンの切替

インストール可能なNode.jsを表示します。

```
# nvm list-remote

～略～
v14.16.1   (Latest LTS: Fermium)
        v15.0.0
        v15.0.1
        v15.1.0
        v15.2.0
        v15.2.1
        v15.3.0
        v15.4.0
        v15.5.0
        v15.5.1
        v15.6.0
        v15.7.0
        v15.8.0
        v15.9.0
       v15.10.0
       v15.11.0
       v15.12.0
       v15.13.0
       v15.14.0
```

それでは、インストールを行います。

```
# nvm install 14.16.1 
Downloading and installing node v14.16.1...
Downloading https://nodejs.org/dist/v14.16.1/node-v14.16.1-linux-x64.tar.xz...
################################################################################################## 100.0%
Computing checksum with sha256sum
Checksums matched!
Now using node v14.16.1 (npm v6.14.12)
Creating default alias: default -> 14.16.1 (-> v14.16.1)
```
インストールが成功し、デフォルトがバージョン14.16.1になっていることを確認できました。

最後にNode.jsのバージョンを確認します。

```
# node -v
v14.16.1
```

以上になります。
ありがとうございました。
バッチファイルでゼロ埋めする（桁数可変）

Y子です。
今回は、ゼロ埋めの方法を考えます。

<details><summary>【ゼロ埋め（`zero padding`）とは】</summary>ゼロを使って数字の桁数を合わせることを言います。
たとえば「`1`」「`20`」「`1000`」を、「`0001`」「`0020`」「`1000`」と書いて桁数を合わせます。
そうすることで、見栄えが揃うほか、ソートしやすくもなります。</details>

# 概要・用途
対象文字列の頭にゼロを結合して、意図する桁数の文字列にします。
たとえば、分割したファイルのファイル名末尾に付加する用途を想定します。
_【[確認環境：Windows 10 Home (Bld. 19042.928)](https://qiita.com/koiwaiwaiko/items/ef2d457ae1e1a7c8b698 "Windows10のバージョンを確認・表記する")】_

# コード
## (1) シンプルな例
対象の数字を引数から取得する例です。
対象の数字の左側に、「`0000`」のようなゼロだけの文字列を結合し、その後右側から必要な長さを切り出します。

ゼロ埋め後の桁数は、ハードコードで「4桁」としました。
違う桁数にしたい場合は、この2か所を変えてください。

* 「`zeros`」に入れるゼロの個数
* 最後の処理の「`%number:~-4%`」の数字を変えてください。

※ゼロの個数は、本当は`n-1`個でいいんですが、同じ数の方が見やすい気がしますし、多い分には問題にならないので、このようにしました。

```bat:zeropad1.bat
@echo off

rem 引数がない場合は終了する
if "%~1"=="" (echo 引数がありません & pause & exit /b)

rem 対象の数字
set number=%1
rem ゼロ埋め用文字列(4桁)
set zeros=0000

rem ゼロ埋め用文字列と引数を結合
set number=%zeros%%number%

rem 既定の桁数に削り(右から4桁)、出力
echo %number:~-4%
```

実行してみます。

```:実行結果
> zeropad1.bat 1
0001
> zeropad1.bat 123
0123
> zeropad1.bat 12345
2345
```

「4桁」固定で文字列を切り出しているので、「`12345`」のように5桁以上の数字を与えると __答えが変わってしまいます__ 。
用途や環境によって、あらかじめ適切な桁数を設定する必要があります。

## (2) 欲張り仕様
以下のような仕様を追加してみます。

* 桁数は可変とし、引数で与える
* 対象文字列の桁数以下で削らない

昨日の「[バッチファイルで文字列長を取得する](https://qiita.com/koiwaiwaiko/items/bb3629937ce5642d2e2b)」サブルーチンを使って、桁数を判定します。

```bat:zeropad2.bat
@echo off

rem 引数がない場合は終了する
if "%~2"=="" (echo 引数がありません & pause & exit /b)

rem 遅延環境変数の展開を有効にする
setlocal enabledelayedexpansion

rem 対象の数字、ゼロ埋め後の桁数、ゼロ埋め用文字列(初期化)
set number=%1
set keta=%2
set zeros=

rem 指定の桁数が対象の数字以下の場合はゼロ埋め不要 → 最後に飛ぶ
set strlen=0
call :get_strlen %number%
if %keta% leq %strlen% (goto :result)

rem ループをketa回まわして、必要な長さのゼロを作る
for /l %%a in (1,1,%keta%) do set zeros=!zeros!0

rem ゼロ埋め用文字列と引数を結合
set number=%zeros%%number%

rem 右からketa桁を切り出して、出力
call set number=%%number:~-%keta%%%

:result
echo %number%
exit /b

rem ====サブルーチン====
rem 文字列長を取得する
:get_strlen
  set str_in=%~1
  
  :label_top
  rem 長さ加算
  set /a strlen+=1
  rem 1文字減らす
  set str_in=%str_in:~1%
  rem 文字列がなくなったら終了
  if not "%str_in%"=="" (goto :label_top)
exit /b
```

1行の`for`文でゼロの桁数を調整したり、`call`を使って変数の中で変数を展開してみたり、かなりオシャレになりました。
※後者は __「[2回解釈させる](https://qiita.com/plcherrim/items/c7c477cacf8c97792e17#%EF%BC%94%E3%81%8A%E3%81%BE%E3%81%91%E5%A4%89%E6%95%B0%E3%82%922%E9%87%8D%E3%81%AB%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%82%80%E3%81%9D%E3%81%AE%E4%BB%96%E3%81%AE%E6%96%B9%E6%B3%952016529%E8%BF%BD%E8%A8%98 "バッチファイル界の魔境『遅延環境変数』に挑む（おまけもあるよ）")」__ というワザみたいです。勉強になりました。

では実行してみます。

```:実行結果
> zeropad2.bat 1 4
0001
> zeropad2.bat 123 4
0123
> zeropad2.bat 12345 4
12345
> zeropad2.bat 12345 20
00000000000000012345
```

長い数字を与えても削りすぎませんし、大きい桁数も正しく出力できました。いいですね。

# おわりに
(2)で高機能なバッチを作りましたが、ゼロ埋め処理を単独で使うことは少ない気がしますので、コンパクトな(1)の桁数を調整して使った方が、使いやすいコードになりそうですね、実は。
まあでも！道具が増えて、達成感と自己肯定感が爆上がりですよ！
自己肯定感が大事ってしょこたんも言ってますし！

ではでは！