OmniAICreator/Qiita-1.07M huggingface dataset:
docker上のwebpackサーバにポートフォワードで接続できない場合の解決策 [Remote Development]


## 実現したいこと
dockerコンテナ上でwebpackにより起動しているReactで作ったサイトに、ホスト(mac)のプラウザからアクセスしたい。

## 問題点
dockerfileのEXPOSE項目とdevcontainer.jsonのappPort項目にnode.jsのポート3333を指定

コンテナのポートフォワードがうまくいってるかは以下のコマンドで確認済み
```bash
$ docker port $(docker ps -q)
```
> `3333/tcp -> 127.0.0.1:3333`

dockerコンテナ内部からcurlで`localhost:3333`接続確認済み
しかし、ホスト側からは
> `curl: (52) Empty reply from server`

となってしまい接続できない
> `curl: (7) Failed to connect to localhost port 3333: Connection refused`

ではないのでコンテナには届いてるっぽいん

## 解決方法
**原因:** ホスト解決がうまくできてなかった
webpack.config.jsのmodule.exportsのhostにコンテナのIPアドレスを指定

```js
...

module.exports = {
...

devServer: {
+     host: '172.17.0.2',
+     disableHostCheck: true,
      port: 3333,
      contentBase: "./dist"
    },    
...

}
...

```

コンテナのIPアドレスはコンテナ側で`cat /etc/hosts`または`hostname -i`とするか、
ホスト側で`docker inspect $(docker ps -q)`で確認できる

最後にwebpack-dev-serverを再起動する


## 参考
[dockerコンテナ上でnode.jsのサーバを起動し、ホスト端末からアクセスする - Qiita](https://qiita.com/hotdrop_77/items/a2ca316c97ba4b748d9a#6%E3%82%B5%E3%83%BC%E3%83%90%E3%81%AElisten%E8%A8%AD%E5%AE%9A%E3%82%92%E5%A4%89%E6%9B%B4)
> dockerホストが割り当てたIPアドレス

[webpack-dev-serverで起動したアプリをlocalhostではなく0.0.0.0で外部に公開する方 \| tackeyy.com](https://tackeyy.com/blog/posts/how-to-access-app-through-the-ip-with-webpack-dev-server)
- webpack.config.jsのhost項目
VSCodeでssh接続先のファイルをリモートから開く


## VSCodeリモート拡張機能の導入

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185108/fbc77a1e-5feb-20c8-cbc8-89fe69ce3fa8.png)


一番上のRemote VSCodeという拡張機能をインストールします



## sshの設定

.ssh/configにsshの設定を記述します

存在しなければ作成しましょう
ローカル側で以下のコマンドを実行
```
$ touch .ssh/config
```

中身を編集します
```
$ code .ssh/config
```

```:config
Host リモート側ホストネーム
  User リモート側ユーザー名
  HostName リモート側ホストネーム
  RemoteForward 52698 localhost:52698
```

ホストネームはリモート側で以下のコマンドで確認できます
```
$ hostname
```


## rmateのインストール
リモート側にあるファイルをローカルのVSCodeで開くためにrmateコマンドを使います

リモート側にログイン
```
$ ssh -l ユーザー名 ホストネーム
```
githubからrmateを取得
```
$ wget -O インストールしたいディレクトリ https://raw.github.com/aurora/rmate/master/rmate
```

ディレクトリのアクセス権限を変更します
ここでは全てのユーザーに実行権限を追加します

```
$ chmod a+x インストールしたディレクトリ
```

chmodコマンドの詳しい使い方はこちら↓
[パーミッションなどを設定する！chmodコマンドの詳細まとめ【Linuxコマンド集】](https://eng-entrance.com/linux-command-chmod)

## rmateにPATHを通す

設定されているパスを表示
```
$ echo $PATH
```
rmateをインストールしたディレクトリが含まれていなければ、
emacsで設定を編集
```
$ emacs .bash_profile
```

`export PATH=`で始まる行末にディレクトリを追加します
例えば`home/username/rmate`を追加したいときは
`:$HOME/username/rmate`と書きます


変更を反映させるためにsshで再ログインします

## 動作確認

何かファイルを開いてみましょう

```
$ touch test.txt
```

ローカル側でVSCodeを起動させた状態で
リモート側にsshログインしrmateコマンドを打つと、
ローカル側でファイルを開くことができます
```
$ rmate test.txt
```
補足：ローカル側でcodeコマンドを打ってファイルを開くと自動的にvscodeのウインドウにフォーカスが移動しますが、
リモート側にrmatekコマンドを打ってファイルを開いてもフォーカスは移動しません。一瞬不安になりますが、手動でvscodeの方を見てみるとちゃんと開けています

ローカル側でいつも通り編集して⌘+sで上書き保存すると、
リモート側に反映されます
LioranBoard2の初回セットアップ

## LioranBoard2配布場所

LioranBoardの公式Discordにて配布中

LioranBoard
https://obsproject.com/forum/resources/lioranboard-stream-deck-animator.862/

LioranBoardのダウンロードリンク
http://lioran.servehttp.com/share/lioranboard/download.html

![lb2_006.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402886/b870dc89-4f23-64a5-030b-54a463e5a098.png)

赤で囲んだ位置のComunityDiscordに参加する。

Discordに入ったら、一番上にあるチャンネルの「announcements」に入って、
> 2021/12/21
> Lioranboard 2 is now open for beta testing.
> ~~~

と書いてある部分のURLに入って自分の環境に合うダウンロードリンク（64bits Releaseか32bits Release）を押して圧縮ファイルをDLしてきて、任意のところに解凍する。

## LioranBoard2初期設定

![アセット 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402886/3268c12c-f8b0-0b4f-1332-2fc4db8b0c24.png)

### OBSとのリンク処理

「IPアドレス」：OBSが起動しているPCとLioranBoard2が起動しているPCが同じであれば、「127.0.0.1」で構わない。
「Protocol」：「OBSws5」も選択できるが現状フルサポートしていないらしいので、念の為「OBSws4」を選択している。
「Port」：OBSWebソケットにて設定しているPort番号と同じものを設定する。
「Password」：OBSWebソケットにて設定している場合には同じものを設定、設定していない場合は未入力にする。

![アセット 3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402886/81c5d6e3-4be6-eabd-2721-c3bcf321e7b4.png)

「AutoConnect」のチェックをつけて置く。

### Twitchとのリンク処理

画面下部にある「OpenURL」からブラウザを開いて（もしくはURLをコピペしてブラウザにて開く）専用画面にてログインを行い本画面に戻ってくる。

自分のユーザ情報が表示されていれば成功となる。

![アセット 4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402886/0435142e-a0d3-552a-fd24-f42d8fd5e863.png)

「AutooConnect」のチェックをつけて置く

ユーザーの右側にある「Edit」ボタンでチャンネルポイント報酬の管理がLB2の画面から行える。

![アセット 5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402886/576536ce-8e20-7054-c329-8be24a953ea1.png)

- 「Dupe」ボタン：対象のCP報酬を複製する（コピーするとタイトルの後半に重複防止でCOPYとデフォでついてる）。
- 「Create Reward」ボタン：CP報酬を追加する。
- 「Edit」ボタン：対象のCP報酬を編集する。

![アセット 6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402886/9710b325-985f-2064-5f89-ec3d804dfa08.png)

基本的な入力はTwitchの管理画面と同じ感じだが、アイコン画像の設定だけはTwitch側の管理画面から行う必要があるかと思われる。

### Transmitterの設定

下記のファイルをOBSのブラウザでローカルファイル指定を行うこと。

> ＜LioranBoard2の導入場所＞\lioranboard2\transmitter\transmitter.html

### Deckの作成（メイン処理の記述）

<<後日書きま～す>>
PythonでQRコードを3行で作成してみた

## 0.はじめに
pythonを用いることで3行でQRコードを作成できるようなので、検証してみました。
##ライブラリをインストール
今回利用するqrcodeライブラリをインストールします。

```
pip install qrcode
```

## QRコードの作成
QRコードを作成します。

```
import qrcode
img = qrcode.make('https://www.youtube.com/watch?v=dkWzWxrINRc') 
img.save('qrcode.png') 
```

実行することで以下のQRコードを作成することができます。

![qrcode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2465378/b43897b0-26ca-dfa2-9271-6f733d301564.png)

## 実行動画
<iframe width="560" height="315" src="https://www.youtube.com/embed/dkWzWxrINRc" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

## さいごに
簡単にQRコードの作成・検証ができますので、興味があれば作成してみてください。
オブジェクト指向とは

Vueについての本だったりYouTubeなどで「オブジェクト指向」
という単語がよく出てきていたのですが、とっつきにくく避けていました。
が、これからエンジニアとして成長するにあたって逃げてはいけないと思い
理解するべく調べてみました。

参考文献としてこちらの記事を挙げておきます。
個人的に一番わかりやすかったです。↓
https://eng-entrance.com/what-oop

#ざっくりまとめると
オブジェクト指向とは
・概念である
・同じような動作をするものを作るときに、共通する機能を持つ「オブジェクトA」を作っておけば
　これを使いまわすことができる
　→同じコードを何回も書かなくてよくなる。また、「オブジェクトA」に変更を加えるだけでその変更が「オブジェクトA」を使って作られているモノに適用される。

とのこと。要は同じ機能を再利用できることに重点を置く考え方らしい。
上記参考サイトの筆者さん曰く「雰囲気理解しておけばいい」とのことなので、
難しく考えずにとりあえず「共通の機能を持たせるための再利用可能なヤツ」くらいに認識しておきます。
AOJトライに関する知識知見の記録共有：Volume0-0058

# タスク概要

The Number of Area

https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0057
 
# コード実装例
TIPS

1. 例外処理含む評価パターンを追加

```Python
import pprint, sys, time

def core(arg, adv=True):
    n = arg
    if adv:
        ret = int(n * (n + 1) / 2 + 1)
    else:
        ret = 1 + sum(range(n + 1))
    return ret

def app(*args):
    ret = []
    for arg in args:
        s = []
        for adv in [False, True]:
            st = time.time()
            try:
                r = core(arg, adv=adv)
            except Exception as e:
                r = e
            s.append([adv, round(time.time() - st, 6), r])
        ret.append([arg, s])
    return ret

print(sys.version)
pprint.pprint(app(
    # basic examples
    1,
    3,
    # additional examples
    0,
    10000,
    # exceptional examples
    "例外入力"
))

```

# 実行結果
各種補足情報出力（入力値FB、デバッグログ等）含む

```Python
3.8.10 (default, Sep 28 2021, 16:10:42) 
[GCC 9.3.0]
[[1, [[False, 3e-06, 2], [True, 1e-06, 2]]],
 [3, [[False, 1e-06, 7], [True, 1e-06, 7]]],
 [0, [[False, 1e-06, 1], [True, 0.0, 1]]],
 [10000, [[False, 0.00013, 50005001], [True, 1e-06, 50005001]]],
 ['例外入力',
  [[False, 7e-06, TypeError('can only concatenate str (not "int") to str')],
   [True, 1e-06, TypeError('can only concatenate str (not "int") to str')]]]]
```

# 補遺
残課題（Pull Request絶賛募集中！）

1. 実行速度の改善（枝刈り、データ構造の見直し等）
【UI改善】UI  Stackを学んだから大学生がまとめる

# UI Stack とは
UIを考案する上で考慮すべき**5つの状態**のこと。

- Blank State（データがない状態）
- Error State（エラー状態）
- Loading State（ローディング状態）
- Partial State（部分達成状態）
- Ideal State（理想の状態）

# なぜ必要か

- 「手戻り」を減らすため
完成したと思った後に不足が発覚すると余計な時間（作業時間・情報共有の時間・会議時間）

- フロントエンジニアとデザイナーが認識を統一するため
エンジニアが常識的に処理しているエラー画面の表示をデザイナーも理解しているわけではありません。

# 具体的になにするのか
理想の状態しか考慮されずにUIデザインが設計された場合を想定します。
これは **UI Stack** の **Ideal State** だけが考慮されている状態です。
今考えている画面において他の4つの状態になり得るかを考えます。

例えば、記事を作成する画面では、5つすべての状態を考慮する必要があります。
・記事がそもそも作成されていないため記事一覧に何も表示されていない状態
・読み込みで何らかのエラーが生じ、記事を正しく読み込めていない状態
・記事を読み込んでいる状態
・ベースのhtmlは読み込みが完了しているが、記事の読み込みだかは完了していない状態
・記事一覧が正しく表示されている状態

UI設計を行うときに、どの画面でどの状態を考慮するかをPdMとエンジニアとデザイナーで共有する必要があります。あなたがどの立場にいたとしても、チーム全体に **UI Stack** を共有することで、あなた含む全員が得をします。

# 参考文献
- [「1枚のシート」でエンジニアとデザイナーのストレスが激減した話](https://qiita.com/sugie_m/items/8f5661ba2161cac9a0e7)
Raspberry Pi 起動時に Chromium をフルスクリーンで表示してキオスク端末っぽく使用する

ラズパイで作りたいものがあって、その前提として、ラズパイをキオスク端末っぽくセットアップしたかったのでそのためのメモ。

## 前提条件

機種: Raspberry Pi 4B （メモリ4GB）
OS: Linux raspberrypi 5.10.63-v7l+

## デスクトップ環境

デフォルトのデスクトップ環境でメモリを調べたら以下のような感じ。

```
$ free -m
               total        used        free      shared  buff/cache   available
Mem:            3839         143        3459           2         235        3569
Swap:             99           0          99
```

Openbox というデスクトップ環境のほうが省メモリであると海外のブログで読んだので変えてみたら以下のような感じ。

```
$ free -m
               total        used        free      shared  buff/cache   available
Mem:            3839          92        3538           0         207        3622
Swap:             99           0          99
```

というわけで、この記事では Openbox を使用します。

## Raspbian のイメージを作成

OS のイメージは Raspberry Pi Imager で作成した。

![](https://www.evernote.com/l/ABVOD1onxJ5Nr7ur7dXDMiHIdfKQYLo8VbYB/image.png)

当初は Raspberry Pi Lite でやろうとしたけど、あれこれ試してるうちに、ここで頑張ってもあんま意味ねーなと思えてきたので、普通に Raspberry Pi OS (32-bit) を選んだ。

SSH 及び Wifi については、Raspberry Pi Imager で、CTRL + SHIFT + X で表示される画面で、あらかじめ設定した。

## 設定

Raspberry Pi に SSH でログインしたあと、以下のようなコマンドを順番に実行した。

まず、アップデート。

```
sudo apt update
sudo apt upgrade -y
```

Scratch などの不要なパッケージを削除。

```
sudo apt purge wolfram-engine scratch nuscratch sonic-pi idle3 smartsim java-common libreoffice* -y
```

今回は、キオスク端末っぽく使用したいので、マウスカーソルを非表示にしたいので、unclutter というツールをインストール。

```
sudo apt install unclutter -y
```

掃除。

```
sudo apt clean
sudo apt autoremove -y
```

デスクトップ環境を設定するための設定ファイルを置くディレクトリをホームディレクトリ内に作成。

```
mkdir -p ~/.config/lxsession/LXDE-pi
mkdir -p ~/.config/openbox
```

デスクトップ環境を Openbox に変えるための設定。

```
echo "@openbox-session" > ~/.config/lxsession/LXDE-pi/autostart
```

Openbox の設定。

* スリープとかスクリーンセーバーとかキオスク端末では不要なのでオフにする。
* unclutter でマウスカーソルを非表示に。
* Chromium を自動的に起動。

```
cat <<EOS > ~/.config/openbox/autostart
xset -dpms &     # Disable DPMS (Energy Star) features
xset s off &     # Disable screensaver
xset s noblank & # Don't blank video device
unclutter -idle 0 &
chromium-browser --noerrdialogs --disable-infobars --kiosk https://get.webgl.org/
EOS
```

最後に再起動。

```
sudo shutdown -r now
```

## おまけ

僕は、GitHub Gist さんに上のコマンドを保存して以下のような感じで実行した。

https://gist.github.com/miya0001/3639688bbb3c464cbe1bb6f5b3e8e6e6

```
curl https://gist.github.com/xxxx | bash
```

注意:

* 上のシェルスクリプトでは、タッチディスプレイのドライバのインストールもしていますので注意。
* デフォルトのパスワードの警告が出ないようにするための処理も入っているので注意。

あと、Chromium 起動後に https://get.webgl.org/ を開くようにしているのですが、Raspberry Pi の Chromium ってデフォルトでは WebGL が使えないのですね。。。汗

## 2022/1/5 追記

Matchbox というウインドウマネージャーを使うとよさそうだったのでそちらで試してみた。

その場合は、`sudo apt install matchbox-window-manager` したあとで `~/.config/lxsession/LXDE-pi/autostart` に以下のように記述する。

```
@xset s off
@xset -dpms
@xset s noblank

@matchbox-window-manager
@chromium-browser --noerrdialogs --disable-infobars --gpu --gpu-launcher --in-process-gpu --ignore-gpu-blacklist --ignore-gpu-blocklist --kiosk https://miya0001.github.io/map/
```
UiPathでPDFファイルを見た目で比較するソリューションを作ってみた！ -差分がわかるPDFを出力

#はじめに
PDFファイルを見た目で比較するソリューションです。差分がわかる下記の様なPDFファイルも出力します。
<iframe width="560" height="315" src="https://www.youtube.com/embed/gb2zXmY1Ehw" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

そもそもの切っ掛けは、テスト自動化における帳票出力の結果を回帰テストにより、自動判定したいがために作ったソリューションです。ですので、下記の記事の続編にもなります。更に用途としてシステムのアップグレードの際の帳票出力の現新比較自動化でも使えそうです。

https://qiita.com/Jun96427231/items/cd155aa4d7ff3b238976

PDF比較ツールとしても使えそうな気がしたので、UiPathマーケットプレースにもワークフローの公開を申請中です。公開されたら、ここにダウンロード先をリンクする予定です。

#作りを解説する前に
いくつかの依存関係が存在します。下記のパッケージのインストールが必要です。尚、マーケットプレースでの提供のものが含まれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639319/cff4c2f6-73c2-a2f6-0f82-0756fc2fba25.png)

#処理概要
２つのPDFファイルを各ページ単位で画像に変換して比較します。比較した結果の差分は再度PDFファイルに変換して提供します。
ざっくり、主要な処理は下記の通りです。
①２つのPDFファイルページ数を取得します。
②ページ数分、下記③~⑤の処理を繰り返します。
③２つのPDFファイルを各ページ単位で画像ファイルに変換します。
④画像変換したファイルを比較します。
⑤比較した結果の差分画像ファイルをPDFに変換します。
⑥最後にページ単位の差分のPDFファイルを結合して一つのPDFファイルにまとめます。

#ワークフローファイル
テスト自動化でも、便利ツールでも両方使える様に下記の様なインターフェースを持つワークフローで作成しています。
***＜パラメータ＞***
in_Filename1：比較する対象のPDFファイル。フルパスで指定します。
in_Filename2：比較する対象の２つ目のPDFファイル。フルパスで指定します。
out_Unmatch：一致していた場合はFalse、不一致の場合はTrueが格納されます。
in_OutputFilename：指定したファイル名で差分確認できるPDFファイルを出力します。フルパスで指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639319/b4804456-31ef-6351-95c1-92492512e156.png)

#テスト自動化で利用する
２つのPDFファイルのうち、１つ目は期待するPDFファイルで、事前にストレージバケットに格納したPDFファイルをローカルにダウンロードしたもの。冒頭で記載した「UiPath Action CenterのFormsにPDFを埋め込む - 出力帳票を目視で合否判定」の続編と言うことですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639319/3e84cc60-7662-397a-9dc6-4b99f4ea51e5.png)


２つ目のPDFファイルは、テスト実行で、ロボット操作により帳票出力したPDFファイルとなります。テストコードでは本ワーフローを呼び出し、比較の結果を下図の様に検証アクティビティで検証します。差異がある場合は、「ドキュメントを添付」アクティビティで差分のわかるPDFファイルを実行中のテストケースにアップロードしておくと後で確認する時に便利です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639319/8e3d47a8-2a86-3b51-90fa-05f3597dbdb5.png)


#おわりに
ソリューションと書きながら、たったこれだけで実現できちゃいました（笑）
UiPathの豊富なアクティビティがあってこそ成せる技ですね。UiPath Activitiesガイドのアクティビティ数が現在、約1500で、マーケットプレースには、それ以上あります。ほしいアクティビティを探したら、だいたい見つかったりしますので、アイデアとノウハウ次第で、まだまだ色んなソリューションが作れそうです！


https://www.fsi.co.jp/blog/5942/

https://www.fsi.co.jp/blog/5963/
UiPath Action CenterのFormsにPDFを埋め込む - 出力帳票を目視で合否判定

#はじめに
本記事ではUiPath Action CenterのFormsにPDFを埋め込む方法を解説します。
ストレージバケットにPDFをアップロードしておくと簡単に実現できますので、是非お試しください。
ちなみに、私はテスト自動化で、テストロボットがシステムを操作し、出力したPDF帳票の結果が正しいか目視確認する目的で利用していますが、RPAでも申請が上がってきたPDFファイルを確認し承認する場合にも同様に使えそうです。

<iframe width="560" height="315" src="https://www.youtube.com/embed/o0Wuuefpmts" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>


#前提
Action Centerを利用するサンプルワークフローは、既に、いくつかのサイトで公開されているので、ここではPDFを埋め込む方法に焦点を当て解説します。初めての方向けにサンプルワークフローが公開されているサイトを紹介しておきます。尚、下記は2019.10でのサンプルですので、パッケージが古いです。パッケージのバージョンアップや必要に応じて修正頂く前提となります。

https://www.uipath.com/ja/blog/developer/action-center

#ストレージバケットにPDFファイルを格納する
下記は、Orchestratorの「Shard」フォルダに「テスト帳票」と言うフォルダを作成し、そこに「テスト手順書1.pdf」をアップロードした例です。私はテストロボットで自動的にアップロードしていますが、お試しの際は予め手動でアップロードして置いても良いでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639319/967c696a-8c14-6656-a697-7ff3cf30c018.png)

#フォームタスクを作成する
サンプルワークフローをお使いの場合は、作成と言うより、修正となりますので、PDFに変更する部分に絞り解説します。
下記は先の説明の通りフォルダパス「Shard」とストレージバケット名「テスト帳票」をプロパティに設定しています。フォルダやストレージバケット名は任意で決めてください。
フォームデータには、２つのパラメータを設定します。まずパラメータ名「out_Check」の値「Check」ですが、ここにはフォームで操作した結果がBoolean型で格納されます。
もう１つのパラメータ名「pdf_storage」の値「TestReport」ですが、ここにはストレージバケットに格納されているPDFファイル名「テスト手順書1.pdf」が文字列で格納されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639319/d9034369-4df1-af05-299e-dd229332f616.png)

#フォームデザイナーを編集する
フォームタスクを作成アクティビティの「フォームデザイナーを開く」を選択して、フォームデザイナーを編集します。PDFを埋め込む部分は、「HTML Content」ですね。ここの編集でコンテンツ部分を編集して埋め込みます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639319/e8713084-190e-36b4-b826-37eed36bb0e1.png)

```
<embed src={{ data.pdf_storage }} width="1500px" height="700px"></embed>
```

#おわりに
サンプルワークフローには画像埋め込みが多いですが、PDFの埋め込みも非常に簡単に実現できるので、RPAで利用の際も選択肢として持っておきたいです。
ちなみに、私がテスト自動化で利用している全体像は下記の通りです。冒頭でテストロボットがシステムを操作し、出力したPDF帳票の結果が正しいか目視確認する目的としてましたが、この作業は初回だけで、合格の場合は、このPDFファイルを回帰テストの期待するPDFファイルとして、別のストレージバケットに格納ています。回帰テストでの自動判定の仕組みについては、次回に解説したいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639319/a8c400a4-58bd-58b8-4c0e-ccabf68d3fd9.png)


テクノロジーは、RPAとテスト自動化の垣根が、どんどんなくなって行きますね。と言うか、テスト自動化では、この様なプラットフォームは一般的にはないかも（笑）テスト自動化で利便性の上がる仕組みは、これからも使い倒します！

https://www.fsi.co.jp/blog/5942/

https://www.fsi.co.jp/blog/5963/
テスト自動化は、どんなプロジェクトに向いているの！？さらっと５選してみた！

#はじめに
テスト自動化には自動化すべきテストと、すべきでないテストがありますが、その前に、どんなプロジェクトがテスト自動化に向いているのか知っておくことが、とても大切だと思ってます。そうしないと後になって、導入の目的がはっきりしない、プロジェクトの特性で効果が出にくいと言ったことも良くあります。本記事では、テスト自動化に比較的向いているプロジェクトを、さらっと５選して見ましたので、ご参考にして頂ければ思います。

#１.金銭取引に関連したシステム開発・保守プロジェクト

金銭取引に影響が出るシステムの不具合はクリティカルとなり、頻繁にマネーパスを実施する必要があります。***自動化することにより、正確にかつ、頻度を上げてテスト実行が可能となり、品質維持に効果を発揮します。***

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639319/a0f00cec-0aaa-360e-04a8-1bb3a31ec935.png)

#2.運用/保守が長く続くプロジェクト

長期のシステム運用において、テストにかかる工数の蓄積は、開発時のテスト工数を大きく上回ると言われます。これは、Windowsアップデートや、システム修正・システムのアップグレードなど幾度も行われ、何度もテストを実施する必要があるためです。つまり、***運用/保守フェーズが続くシステムは、回帰テストの機会が多く自動化に適していると言えます。***

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639319/64c34e15-e8a5-9d42-fbae-a071c1b7b74e.png)


#3.市場リリースのライフサイクルを持つプロジェクト

市場に出る製品は、出荷する台数も多く、不具合によって大きな損失に繋がります。***パッケージなどライフサイクルのあるソフトにおいては、リリースの都度変更していない機能においても、一般的に回帰テストを実施します。テストを自動化することにより、中長期的なコスト効果が期待出来ます。***

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639319/5b5b5d44-dd7e-04a5-e59a-36b66d1caa4c.png)

#4.大規模で、サブシステムや機能やデータが複雑に絡み合っているシステムの開発・保守プロジェクト

大規模で複雑に絡み合っているシステムは、少しの変更で、影響のない様に見えて、影響していることが良くあります。少しの変更で、都度、広く手動テストを実施するのは非効率です。***テストを自動化することで少しの変更でも都度、コストを掛けずに広くテストが可能となります。***

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639319/babfbbaa-d8d5-5b8b-f6c2-1de5c2a7e2c7.png)

更に、大規模システムでは複数の請負会社からモジュール受け入れて統合ビルドするチームを作ってたりします。週何度もビルド～決められた手順でスモークテストを実施し、評価チームにリリースしますが、頻度が多く、時間短縮が課題となります。***ビルドからテストまで一連の作業を自動化することで、展開までの時間短縮の課題を解決します。***

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639319/fe5b48dc-55d9-74d3-b8db-496121be23af.png)

#5.アジャイル開発をしているプロジェクト

アジャイル開発において、ソフトウエアは継続的・持続的にデリバリーされます。比較的短い開発ライフサイクルにおいて品質を保つには、新しい機能に関するテストはもちろんのこと、並行して既存ソフトのデグレを防止するため、短いサイクルの都度、回帰テストを実施することが重要になります。***テストを自動化することで、サイクルの都度、既存のソフトウェアが壊されていないかテストが可能となります。***

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639319/bdd5ed6b-3e11-c753-cff3-c030be3eaacf.png)

#おわりに
もう、お気づきだと思いますが、リグレッションテストの実施機会が多いプロジェクトほどテスト自動化に向いており、その観点のプロジェクト事例をご紹介させて頂いたとも言えます。ただ、ここにピックアップしたのは一例ですので、限定しているものではありません。少しでも、ご参考なれば幸いです。
尚、日本はグローバルと比較し、テスト自動化が遅れていると言われてますが、本５選でピックアップしたアジャイルやCI/CDの導入も少ないと言ったこともあるでしょう。ただ、国内の中にも先進的な取り組みにチャレンジし、テスト自動化で効果を出している事例も増えてきているので、日本での普及にも期待出来そうです。（下記はUiPath Test Suiteを活用した国内事例）

https://www.uipath.com/ja/solutions/case-study/ok


テスト自動化の基本や導入の価値、UiPath Test Suiteによるアプリケーションテスト自動化についてのコラムもご参考に！

https://www.fsi.co.jp/blog/5942/

https://www.fsi.co.jp/blog/5963/
pyzについて調べてみた

zipappで作られる.pyzって具体的に何やってるの？と思って調べたことをまとめておく。

## .pyzとは
Pythonとして実行できるアーカイブファイル用の拡張子。
中身はただのzipファイルだが、中に「\_\_main\_\_.py」を入れておくことでPythonファイルとして実行できる。
拡張子がPythonに紐付けされていればダブルクリックでも実行できるが、「python filename.pyz」で呼び出すこともできる
拡張子の例：.pyz, .pyw

## zipappモジュール
フォルダと開始地点になるモジュール＆関数を指定することで簡単にpyzファイルを作ってくれるモジュール。
コマンドラインからも実行でき、その場合はArgumentParserでいい感じにされてからcreate_archive関数が実行されている。

create_archiveでやっていることは指定したフォルダに「\_\_main\_\_.py」があればただフォルダをpyzにまとめるだけ。
ない場合は引数のmainで指定されたモジュールと関数を使って\_\_main\_\_.pyを作成するという処理が増える。
これによって作られる\_\_main\_\_.pyの中身は以下のようなエンコード指定とモジュールのインポート、関数の実行だけのシンプルなものになっている。
main引数は「module_name:function_name」の形式で指定し、内部で以下のような「\_\_main\_\_.py」を作成するのに使われる。
出力先はtargetで指定されたパスや名前をpathlib.Path.with_suffix(".pyz")したものになるので常にpyz形式。

```python:__main__.py
# -*- coding: utf-8 -*-
import {module_name}
{module_name}.{function_name}()
```

## pyzをzipappを使わずに作る
最終的にアーカイブの中に「\_\_main\_\_.py」があればいいだけなのでこのモジュールを使わずに自分でアーカイブファイルを作っても普通に動く。

元のzipapp.create_archiveはフォルダを指定して、ZipFileでまとめるというシンプルな実装。
必要なものをすべて一つのフォルダに一回まとめないと使えないので、常にこのフォルダの中身を一緒に入れたい……というような処理はそのままだとできない。
既存の関数をそのまま利用するのであれば作業フォルダを作ってそこにファイルを入れるような前処理をしてから呼び出せばそれっぽい動きはできる。

ただ結局やってることはZipFileを作っているだけなので、そのあたりは{アーカイブ時の名前: ファイルのパス}のような辞書を引数に取る形にすれば複数のフォルダから色々と引っ張ってきてpyzを作るという処理も作れるので、そのあたりを用途に合わせて自分だけのcreate_archiveっぽいものを作っても面白そう。

## pyz用に処理を分岐させる
この方法で実行した場合のsys.argv[0]はアーカイブファイルのパスになっている。
zipfile.is_zipfileがpyz版での処理の分岐に使えるのでpyz用スクリプトでは使えそう。

```python
# よくあるやつ
if __name__ == "__main__":
    ...

# pyzのときだけ実行させるやつ
import sys
from zipfile import is_zipfile
if is_zipfile(sys.argv[0]):
    ...
```
## pyz用のスクリプトで中身を使う
sys.argv[0]をZipFileを使って取り出せば同梱したスクリプト以外のファイルも使用できる。
ZipFile.readを使って読み取れば中間ファイルなどは不要。
### 中に入れたcsvのデータを使うサンプル
```python
import csv
import sys
from io import BytesIO, TextIOWrapper
from zipfile import ZipFile

with ZipFile(sys.argv[0]) as z:
    # readでバイナリとして読み込んでIOでいい感じにする
    stream = TextIOWrapper(BytesIO(z.read("sample.xlsx")), encoding="utf-8")
dr = csv.DictReader(stream)
for row in dr:
    print(row)
```

## その他
pyzの中のフォルダ構成はそのまま普通のワークスペースの構成と同じように解釈されるようなので、
以下のようにフォルダありの構成にしたときに「\_\_init\_\_.py」が正しく定義されていればlibraryフォルダをパッケージとして扱うことができる。

```
hoge.pyz
- __main__.py
- fuga.py
- library
-- __init__.py
-- library_module.py
```

パッケージを同梱できるので、ライブラリのインストールが必要だがそれ用に仮想環境を作るほどではないような小さいツールを作るときに役に立つかもしれない。
依存関係のあるライブラリも入れる必要があるので、入れたいライブラリが他にどのライブラリに依存しているかは都度調べる必要あり。

これできるかな？で触って調べてみただけなので細かい仕様等までは分からないものの、とりあえず何かに使えそう。

# 参考
zipappの公式ドキュメント https://docs.python.org/ja/3/library/zipapp.html
AWS データレイク ハンズオン - Lab5 -

# 背景

データ分析を AWS で自動化する方法を勉強するため、AWS データレイク ハンズオンで各サービスを実際に使ってみることにした。

https://github.com/aws-samples/amazon-s3-datalake-handson/tree/master/JP

# ハンズオンを進める

## Lab5: クラウド DWH を使用したデータ分析

主に使用するサービス:

- Kinesis Data Firehose
- S3
- Athena
- Redshift
- Redshift Spectrum
- QuickSight

https://github.com/aws-samples/amazon-s3-datalake-handson/blob/master/JP/lab5/README.md

### Section1: Redshift の環境構築

#### Step1: CloudFormationでネットワークの設定

#### Step2: Redshift の構築

Redshift を特定の VPC で使用したいが、無料トライアルでは VPC を選択できないようだ (デフォルト VPC で作成される)。

VPC の変更も検討したが、スナップショットから復元する際、無料トライアルを選択できないため、手詰まり状態。

https://aws.amazon.com/jp/premiumsupport/knowledge-center/move-redshift-cluster-vpcs/

一先ず、デフォルト VPC に Redshift を置いた状態で、ハンズオンを進めてみる。

Section2, 3 は実施済みのため、スキップする。

### Section4: Redshift への接続

#### Step1: Redshift への接続

#### Step2: Redshift にデータロード

#### Step3: Redshift Spectrum の使用

#### Step4: QuickSight の設定

QuickSight で新規 Redshift データソースを作成する際、以下のエラーが出た。

```
Amazon QuickSight がプライベートネットワーク内にあるため、データソースにアクセスできません。この問題を修正するには、ホストがパブリックにアクセスできるようにします。
```

この原因はおそらく、 QuickSight がスタンダード版であるため、 VPC へ接続できないためだと思われる。

とりあえず、QuickSight の設定は飛ばす。

### Section5: 振り返り

おおよそ設定できたが、

- Redshift: デフォルト VPC 上に置かれている (無料トライアルのため、独自 VPC には配置できず)
- QuickSight: Redshift を可視化できず (スタンダード版のため、VPC 接続できず)

上記がハンズオン通りにはいかなかった。
(ハンズオンの範囲内であれば、無料トライアルできるような環境を作って欲しい・・・。QuickLabs とかで実装してくれないかな・・・。)

また、全体の作成の流れは把握できたが、

- DB の定義
- スキーマの定義
- 外部テーブルの作成方法
- VPC やサブネットの配置
- ...

などなど、細かいところはまだふわっとしてる・・・。
ハンズオンが終わったら、「　AWS ではじめるデータレイク」で細かいところも確認しよう。

# 今後の学習方針あれこれ

## プライベートで AWS 使うの？問題

非リアルタイム・小規模なデータ分析だったら、表計算ソフトで十分かもしれない。

## データ分析で AWS を使うタイミングは・・・

リアルタイム・大規模 (GB, TB レベル) を求められる案件でないと、バリューを発揮できない気がする。

ガチガチに要件定義すれば使えないこともないが、普段使いにはかなり大きめなサービスだと思う。
【React】コンポーネントのimportとexportについて【JavaScript】

## はじめに
　本記事は、プログラミング初学者が、学習を進めていて疑問に思った点について調べた結果を備忘録も兼ねてまとめたものです。
　そのため、記事の内容に誤りが含まれている可能性があります。ご容赦ください。
　間違いを見つけた方は、お手数ですが、ご指摘いただけますと幸いです。

##コンポーネントのimportとexportについて

### Reactではコンポーネントを分ける
Reactでは、1ファイル1コンポーネントになるように記述していき、importとexportをすることでそれらを組み合わせ、最終的な形にしていきます。
理由は以下の通りです。

- 何のための部品なのか明確にするため
- 管理しやすくするため
- 再利用するため

JavaScriptのモジュールと同様です。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Modules


### importとexportの使い方
improtとexportはReactでは以下の方法で行います。

```sample.js
 // デフォルトインポート
 // 関数名とファイルの相対パスを指定する
 import Sample from "./Sample";
 
 // デフォルトエクスポート
   // アロー関数の場合(rch : VSCode補完)
   const Sample = (props) => {
     return <h1>{props.sample}</h1>
   };
   export default Sample;
   // 名前付き関数の場合(rfc : VSCode補完)
   export default function Sample(props) {
     return <h1>{props.sample}</h1>
   };



 // 名前付きインポート
 import {Sample, Example} from './index';

 // 別名エクスポート
 // デフォルトエクスポートしたファイルに別の名前をつけてエクスポートする
 // Reactではエントリポイントのファイル(index.js)に記述する
 export {default as Sample} from './Sample';
 export {default as Example} from './Example';

```

別名エクスポートは、エントリポイントのファイル(index.js)に記述します。
エントリポイントに各子コンポーネントの別名エクスポートを記述することで、親コンポーネントでインポートする際に、名前付きインポートで一文にまとめることができ、可読性を高めることができます。


## まとめ

- Reactでは、1ファイル1コンポーネントになるように記述していき、importとexportをすることでそれらを組み合わせ、最終的な形にする
- Reactでは、デフォルトインポート＆デフォルトエクスポート、名前付きインポート＆別名エクスポートが使用される
- 別名エクスポートをindex.jsに記述することで、親コンポーネントで名前付きインポートをすることができ記述量を減らすことができる
LWCの選択リストの取得(js側の自動取得)(レコードタイプによりの取得)

A. レコードタイプが存在しない場合、選択リストの自動的に取得方法
①　picklistLwc.js
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371029/15b92c8d-cc12-c715-b522-c3443b268240.png)
②　picklistLwc.html
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371029/c3612de5-92a8-3329-b46c-7ab359775d22.png)
③ picklistLwc.js-meta.xml
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371029/6b815ad8-8c27-9fff-759d-a0dac8aaf15d.png)

B. レコードタイプが存在る場合、指定したレコードタイプの選択リストの取得方法
作成中。。。
①　 レコードタイプ名が「レコードタイプ名」により、該当レコードタイプのレコードIDを取得する。　　
　　@wire(getObjectInfo, { objectApiName: Account_OBJECT})
    　　getAccountObjectInfo(result) {
        　　　if (result.data) {
            　　　　const recordTypeList = result.data.recordTypeInfos;
            　　　　this.accountRecordTypeId  = Object.keys(recordTypeList).find((recordType) => recordTypeList[recordType].name === 'レコードタイプ名');
        　　　}
    　　}
②　取得したレコードタイプのレコードID(accountRecordTypeId)によって、対応の選択リストを取得する
    　　// typeの選択リストを取得する 
    　　@wire(getPicklistValues, { recordTypeId:'$accountRecordTypeId', fieldApiName: 　　　Type_FIELD})
    　　typeOption;
Rubyで non blockingにIOする際に IO::Bufferオブジェクトを補助的に使用する

rubyの非同期タスクスケジューラー実装時に必要になったのでメモる。
See: https://ruby-doc.org/core-3.1.0/Fiber/SchedulerInterface.html 。

:warning: このbufferはプログラマーが管理するbufferであり、IOオブジェクト内のbufferではない、はず。


<details>
<summary>non blocking IOとは？</summary>

Outputの方で説明する。システムコールの結果は以下の二種類。

- カーネルバッファにスペースがあれば、バッファに書けるだけ書く。結果は書き込めたバイト数が返ってくる。
    - もし全部書き込みされていなかったら、プログラムは再度writeを試みることになる。
- カーネルバッファにスペースがなければ、システムコールの結果としてエラーが返ってくる。
    - プログラムは再度writeを試みることになる。

</details>



https://ruby-doc.org/core-3.1.0/IO/Buffer.html

- IO::Bufferに保持されるバイト数は固定。(可変長ではなく、固定長を最初に確保する)
- 今まで何バイト書き込んだか(=これから何バイト目に書き込むのか)を、offset変数によって管理する。

```
string <----> io::Buffer object <--->  IO object   <--(fd)--> kernel buffer <---> disk
     (programmerが管理)            |   (IO classが管理)    |     (OSが管理)      |

(IO objectのも内部にbufferを持っている。そのどこまでデータが入っているのかはIO objectが保持してる？)
```

## Read from IO::Buffer to string

:warning: タイトルにはnon blockingに書いているが、以下ブロッキングするread_partialの例を挙げてしまった。
non blockingにするには、read_nonblock をwriteの例と同じ様に使用する必要がある。

```rb
# 読み出したいバイト数
length = 123
# 読み出した結果を保持するbuffer。ここに書きこんでいく。
buffer = IO::Buffer.new(length)
# 読み出し元
io = ~~~

# 現在何バイトまで読み出したか (io の中でもトラッキングされているはず？)
offset = 0

while offset < length
    read_string = ''
    # 最大でbuffer.size-offset(つまりバッファの残り分)を取り出し、read_stringに上書きする。
    # 最低は決まっていない。１バイトでも読み出せるものがあればブロックせずにそれを読み出す。
    # See: https://docs.ruby-lang.org/ja/latest/method/IO/i/readpartial.html
    io.read_partial(buffer.size-offset, read_string)
    # bufferの中のoffsetバイト目以降に、read_stringを書き出す。
    offset += buffer.set_string(read_string, offset)

# Use buffer and do something here.
# 書き出し終わったIO::Bufferをうまく使う。
```

read_particalはブロックをしないわけではない。以下の条件を満たす場合のみしかブロッキングをしない、ということ。

> - IO オブジェクト内のバッファが空
> - ストリームにデータが到着していない
> - ストリームが EOF になっていない
> 
> from. https://docs.ruby-lang.org/ja/latest/method/IO/i/readpartial.html


## Write from string to IO::Buffer


```rb

# https://docs.ruby-lang.org/ja/latest/method/IO/i/write_nonblock.html

# 書き込みたいstring(my_string)を含むbufferを作成する
length = len(my_string)
write_string = IO::Buffer.new(length)
## ここでwrite_string bufferにmy_stringをかく

# 書き込み先
io = ~~~

offset = 0

while offset < length
  begin
    # バッファからioに書き込むメソッドは#write_nonblockしか見つからなかった。
    # (readの場合は、bufferへの読み出しを行うメソッドはread_nonblockとread_nonpartialがある)
    result = io.write_nonblock(buffer.get_string(offset), exception: false)
  rescue SystemCallError => e
    return -e.errno
  end

  case result
  when :wait_writable
    sleep(0.1) # 非同期プログラミングではこの間に別の処理を行う。
  else
    offset += result
  end
end
```
Zigで、B - FizzBuzz Sum問題を解いてみる

https://qiita.com/official-events/5cb794f7cb9ac194ed70

**信長之代、五年、三年は持たるべく候。明年辺は公家などに成さるべく候かと見及び申候。左候て後、高ころびに、あおのけに転ばれ候ずると見え申候。藤吉郎さりとてはの者にて候**

Advent Calendar 2022 5日目[^1]です。
私の[Advent Calendar 2022 一覧](https://docs.google.com/spreadsheets/d/1HQvFjagQLRPjOYAjDVzWp9S4b8dKixxvvaz_TtbZWto/edit#gid=1723448955)。

[^1]: @kaizen_nagoya さんの「[「@e99h2121 アドベントカレンダーではありますまいか Advent Calendar 2020」の改訂版ではありますまいか Advent Calendar 2022 １日目　Most Breakthrough Generator](https://qiita.com/kaizen_nagoya/items/49ebebee3a0377f3b59b)」から着想を得て、模倣いたしました。 

# はじめに

[Elixir](https://elixir-lang.org/)を楽しんでいますか:bangbang::bangbang::bangbang:

[AtCoder](https://atcoder.jp/home)の[B - FizzBuzz Sum](https://atcoder.jp/contests/abc162/tasks/abc162_b)を[Zig](https://ziglang.org/)で解いてみます。

[Zig](https://ziglang.org/)の`Hello, world!`的なことは下記の記事をご参照ください。

https://qiita.com/torifukukaiou/private/8dd486a2d12dd44e371e

この記事では、[Elixir](https://elixir-lang.org/)のことは取り扱っていません。

# [B - FizzBuzz Sum](https://atcoder.jp/contests/abc162/tasks/abc162_b)

> AtCoderは、オンラインで参加できるプログラミングコンテスト(競技プログラミング)のサイトです。リアルタイムのコンテストで競い合ったり、約3000問のコンテストの過去問にいつでも挑戦することが出来ます。

[AtCoder](https://atcoder.jp/home)の[B - FizzBuzz Sum](https://atcoder.jp/contests/abc162/tasks/abc162_b)問題とは次のような問題です。

例: 入力が5の場合、FizzBuzzの列は、`1,2,Fizz,4,Buzz`となり、数字だけを足し算して、7が答え

問題文は[リンク先]((https://atcoder.jp/contests/abc162/tasks/abc162_b))をご参照ください。

プログラミングの基本である

- 順次
- 分岐
- 繰り返し

が含まれている良問だとおもっています。




```zig:src/main.zig
//const builtin = @import("builtin");
const std = @import("std");
const io = std.io;
const fmt = std.fmt;

pub fn main() !void {
    const stdout = io.getStdOut().writer();
    const stdin = io.getStdIn();

    var line_buf: [20]u8 = undefined;

    const amt = try stdin.read(&line_buf);
    if (amt == line_buf.len) {
        try stdout.print("Input too long.\n", .{});
    }
    const line = std.mem.trimRight(u8, line_buf[0..amt], "\r\n");
    const n = try fmt.parseInt(u128, line, 10);

    var i: u128 = 1;
    var sum: u128 = 0;

    while (i <= n) {
        if (i % 3 == 0) {
        } else if (i % 5 == 0) {
        } else {
            sum += i;
        }

        i += 1;
    }

    try stdout.print("{d}\n", .{sum});
    return;
}
```

残念ながら、[AtCoder](https://atcoder.jp/home)では2022/01/03現在、まだ[Zig](https://ziglang.org/)を選べませんでしたので、手元で`zig build run`して自分で標準入力して結果を確かめました。

作成にあたって、以下のプログラム例を参考にしました。

https://github.com/ziglang/zig/blob/0.9.x/test/standalone/guess_number/main.zig

- 入力を受け取って整数に変換するところはもっとすっきり書けるのかもしれません
- `const n = try fmt.parseInt(u128, line, 10);`は、カンで`try`をつけています
    - `try`がないと、`i <= n`のところで、下記のエラーがでます
        - error: expected type 'u128', found 'std.fmt.ParseIntError!u128'

どうでもいい話ですが、ググるとRustの記事がよくでてきます。
Rustに似ているところがあるのでしょうか。



# Wrapping up :lgtm::lgtm::lgtm::lgtm:

Enjoy [Zig](https://ziglang.org/):bangbang::bangbang::bangbang:

2022年に流行る技術予想 ーー それは、[Zig](https://ziglang.org/)です:rocket::rocket::rocket:
【Qiita投稿】ページ内リンクの英字は小文字で


# はじめに
####「目次のページ内リンクが上手くいかない！」
初めてQiitaに投稿したときに、1番困ったことです。
自分用の備忘録として書きました。


-  そのときに書いた記事 : 「[docker daemon is not running になり、Hyper-V を無効化した](https://qiita.com/cat22roo/items/3002cd841f929f14e73c)」

# 参考
- [Qiita Markdownのページ内リンクの罠](https://qiita.com/hennin/items/7ee58dd7d7c013a23be7#%E8%8B%B1%E5%AD%97%E3%81%AE%E5%A4%A7%E6%96%87%E5%AD%97abc%E3%81%AF%E5%B0%8F%E6%96%87%E5%AD%97abc%E3%81%A7)

# 結論
###ページ内リンクの英字は、小文字で書く。

Markdownでのリンクの書き方は、次の通りです。

　**```[テキスト](リンク先アドレス)```**

これを使って、**目次をページ内リンクをさせる** ことができます。


####目次に**英字の大文字**がある場合、( )内のテキストは **小文字** で書きます。

  **```[Appleについて](appleについて)```**

うっかり大文字の```(Apple)```にしてしまうと、上手くリンクされません。


例えば、次のように目次を作ります。





```
#目次
[1.はじめに](#1-はじめに)
[2.Hoge Fugaとは](#2-hoge-fugaとは)
[3.最後に](#3-最後に)

#1. はじめに
<!--内容-->

#2. Hoge Fugaとは
<!--内容-->

#3. 最後に
<!--内容-->

```

#目次
[1.はじめに](#1-はじめに)
[2.Hoge Fugaとは](#2-hoge-fugaとは)
[3.最後に](#3-最後に)

#1. はじめに
<!--内容-->
<br>
<br>
<br>
#2. Hoge Fugaとは
<!--内容-->
<br>
<br>
<br>
#3. 最後に
<!--内容-->
<br>
<br>
<br>
これで目次がリンクされました！
サーバー証明書発行の仕組み（流れ）をざっくり理解してみましょう


流れとその図

①秘密鍵と公開鍵をサーバーから発行
②CSR（サーバー証明書くださいってRequestするためのフォーマットみたいなもの）をサーバーから発行
③CSRの中身を確認して認証局にある秘密鍵からサーバー証明書を認証局側のサーバーが発行
④サーバー証明書を送る
⑤HTTPSで接続する
⑥サーバー証明書を渡す
⑦公開鍵野情報を含んだサーバー証明書が信頼に値するものであればHTTPS通信で接続する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969819/fd1b4469-8b2a-22e9-ae18-64f66232bfa6.png)
補足
オレオレ証明書は認証局と書いてある部分が自分自身であると考えてください
（ゆえに④のサーバー証明書を送るという過程は発生しませんし認証局側の秘密鍵は①で発行した秘密鍵と一致します）
Laravel Guzzel HTTPクライアントを用いてAPI通信を行う

# はじめに
どこかの外部Webサービスのデータを取得する為に外部のサーバーにアクセスしたい！！
そんな時に使えるのがこのGuzzel HTTPクライアントです。

業務でGMOペイメントの決済と送金機能のレビューをする際に使用されていたので、ここで備忘録として残そうかと思い記載しました。
こちらは備忘録として書いている為、そんなに分かりやすく書いてなくてすみません・・・

このブログの解説は分かりやすかったです！
https://blog.capilano-fw.com/?p=6033

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [Guzzelインストール](#guzzelインストール)
2. [使い方](#使い方)
3. [具体例](#具体例)

<!-- 各チャプター -->
# Guzzelインストール

Guzzel HTTPというライブラリで、API通信を行いますので、Laravelにインストールします。
プロジェクトのディレクトリ内で以下のコマンドを入力します。



```
$ composer require guzzlehttp/guzzle
```

# 使い方
今回はpostメソッドを例に出します。
【使い方】
・```use Illuminate\Support\Facades\Http;```でHTTPファサードをuse宣言します。
・postでhttp通信する場合、```Http::post('http通信を行うURLを入力', [必要なデータがあればオブジェクトに入れる]);```を記述する
・```$response->body()```
htmlのbodyタグの中身(ブラウザの表示部分のbody)をstringで取得する。
・```$response->json()```
$response->body()の値がjson形式の場合、配列でデータを取得する。

```
// 何らかのController.phpファイル


// 下記追記 (config/app.phpファイルのaliasesに登録してあるHTTPファサードを使用)
use Illuminate\Support\Facades\Http;

public function edit()
{
    $response = Http::post('http通信のURL', 
    [
        'key' => 'value',
    ]);

    dd($response->body());

    dd($response->json());
}
```

# 具体例
決済した後にキャンセルがあった場合、銀行口座が必要になると思います。
今回の場合はGMOペイメントに登録されているユーザーの銀行口座情報を取得する例です。


```
// BankAccountController.php

// 下記追記
use Illuminate\Support\Facades\Http;

public function getBankAccount($bank_id)
{
    // GMOペイメントサービス内にある、ユーザーの銀行口座を取得する為のURLを入力
    $response = Http::post('https://〜途中省略〜AccountSearch.json'), 
　　　　　　　　　　　　　　　　//　ユーザーの銀行口座を取得する為に必要な情報を入力する
　　　　　　　　　　　　　　　　[
            // GMOのダッシュボードに表示されているショップID
            'Shop_ID' => 'test00000000',
　　　　　　　　　　　　　　　　　　　　　　　　　// GMOのダッシュボードに表示されているショップパスワード
            'Shop_Pass' => 'testpass',
　　　　　　　　　　　　　　　　　　　　　　　　　ユーザーを特定する為のID
            'Bank_ID' => $bank_id,
        ]);

       dd($response->body());

       dd($response->json());

       dd($response->json()['Bank_Name']);
}

```

```
$response->body()で取得したデータ

{
 "Bank_ID":"00000000-0000test0test",
 "Delete_Flag":"0",
 "Bank_Name":"○ ○ 銀行",
 "Bank_Code":"0001",
 "Branch_Name":"○ ○ 支店",
 "Branch_Code":"123",
 "Account_Type":"1",
 "Account_Number":"1234567",
 "Account_Name":"TEST TEST",
 "Free":"",
 "Branch_Code_Jpbank":"",
 "Account_Number_Jpbank":""
}
```

```
$response->json()で取得したデータ

array:12 [▼
  "Bank_ID" => "00000000-0000test0test"
  "Delete_Flag" => "0"
  "Bank_Name" => "○ ○ 銀行"
  "Bank_Code" => "0001"
  "Branch_Name" => "○ ○ 支店"
  "Branch_Code" => "123"
  "Account_Type" => "1"
  "Account_Number" => "1234567"
  "Account_Name" => "TEST TEST"
  "Free" => ""
  "Branch_Code_Jpbank" => ""
  "Account_Number_Jpbank" => ""
]
```

```
$response->json()['Bank_Name'])で取得したデータ

"○ ○ 銀行"
```

こんな感じで、GMOペイメントのDBからAPIを用いてデータを取得できました！
メルカリを参考にECサイトを作る

作成にあたっては、こちらの方の過去の取り組みを参考にさせていただくことにした。

https://github.com/kasugatakuya/freemarket_sample_64j

初めて取り組むので、全くもって頓珍漢なことをしているかもしれないけれど。

まずはDB側から着手することとする。
【Laravel8.x】observerでEloquentモデルのイベントをディスパッチする

# はじめに

`Eloquent`に用意されている`observer`を利用して`save`メソッドを検知して処理を追加する方法を備忘録として紹介します

https://readouble.com/laravel/8.x/ja/eloquent.html


# 解消する問題

1.ログインユーザー名を取得する
2.1と`モデルインスタンス`に属性の配列を加えた配列を結合
3.`save()`メソッドで登録する

1.2の処理を更新時にも同じ処理を記述するのはイケてないので`observer`にやってもらいます

```php
$loginUser = Auth::user()->name;

$storeData = array_merge(
    (new User())->fill($request->all())->toArray(),
    ['create_user' => $loginUser],
    ['update_user' => $loginUser],
);

$result = (new User())->fill($storeData)->save();
```

# やり方

## `observer`を生成

```bash
php artisan make:observer UserObserver --model=User
```

## `observer`に処理を定義

- 今回は`save()`が成功した後に登録者・更新者を登録したいので`saved()`メソッドを利用

`saved(User $user)`:`$user`には`save()`メソッドの結果(登録したユーザーのモデルインスタンス情報）が入ります

```php:src/laravel/app/Observers/UserObserver.php
<?php

namespace App\Observers;

class UserObserver
{
    /**
     * Handle the user "save" event.
     *
     * @param User $user
     * @return void
     */
    public function saved(User $user): void
    {
        $loginUser = Auth::user()->name;
        $saveData = [
            'create_user' => $loginUser,
            'update_user' => $loginUser
        ];

        User::query()->where('id', $user->id)->update($saveData);
    }
}
```

## `observer`を`AppServiceProvider`で読み込む

```php:src/laravel/app/Providers/AppServiceProvider.php
class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot(): void
    {
        User::observe(UserObserver::class);
    }
}
```

## `observer`に移した処理を削る

スッキリかけました

なお、今回`observer`でクエリビルダで`update`していますが`save()`メソッドを利用したい場合は`saveQuietly()`メソッドを利用してください

:::note alert
save()メソッドをobserverで実行するとイベントをディスパッチしてしまうので処理が終わりません
必ずsaveQuietly()メソッドを利用するようにしてください
:::

https://readouble.com/laravel/8.x/ja/eloquent.html

```php
$result = (new User())->fill($request->all())->save();
```

# おわりに

今回は簡単な例で`observer`について紹介しました
登録前の処理は`saving`・削除前は`deleting`等、イベントを検知することでビジネスロジックがスッキリ書ける場合もあるので使ってみるといいかもしれません。
この記事が参考になれば幸いです
【Node.js】バージョンが古くてfetchが使えんのお

# はじまり
Node.jsのための環境を以下の記事のように立ち上げました。

https://zenn.dev/kinkinbeer135ml/articles/6369ee73dd1508

そして、そのまま、fetchを使ったスクリプトが動くかどうかを試してみたのですが、
何か自分のスクリプトとは違うエラー（Unexpected Identifierみたいな）が出現しました。

そこで調べてみてこんな記事を見つけました。

https://chaika.hatenablog.com/entry/2019/01/23/083000

そこには、importを使うスクリプトの拡張子は`.mjs`でなければならないと書いてあったのですが、
fetchはメジャーなモジュールなので、流石にそんなヤバい挙動を2年も引き摺っていないだろうと思いました。
恐らく、Node.jsのバージョンを上げれば直るだろうと思い、この記事を書きました。

今回、立ち上げた環境は、ubuntuです。

# 問題のやつ
これが出てきたエラー画面です。
![20220103_01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265324/84dd0a2b-4b0b-6ee9-6ec7-96e5dc37bfef.jpeg)

「SyntaxError: Unexpected Identifier」が出てきてから色々調べましたが、上述の記事くらいしか良さげなものが見つかりませんでした。fetchモジュールのファイルの中でエラー起きるとかマジですか。。。
なので、原因というものは見つかりませんでしたが、
このときに使用していたNode.jsのバージョンが「10.19.0」であり、2020-02-05にリリースされたものでした。
2022-01-03時点で、推奨版が「16.13.1」なのでバージョンアップすれば直るのではと思いました。

https://nodejs.org/ja/download/releases/

# モジュールのバージョンアップ
モジュールをバージョンアップする処理もDockerfileに加えました。

~~~bash:Dockerfile（バージョンアップしないバージョン）
FROM ubuntu:latest
RUN apt-get update
RUN apt-get install nodejs -y
RUN apt-get install npm -y
RUN update-alternatives --install /usr/bin/node node /usr/bin/nodejs 10

ADD package.json .
ADD index.js .
CMD npm run start
~~~

~~~bash:Dockerfile（バージョンアップするバージョン）
FROM ubuntu:latest
RUN apt-get update

# for install n
RUN apt install -y curl

# install old nodejs and npm
RUN apt-get install nodejs -y
RUN apt-get install npm -y

# for version up nodejs
RUN npm install -g n
RUN n 16.13.1

# uninstall old nodejs and npm
RUN apt-get purge nodejs npm -y

# for version up npm
RUN npm install -g npm
RUN npm update -g

# to avoid "npm ERR! Tracker "idealTree" already exists"
WORKDIR /usr/app
COPY ./ /usr/app

# module etc...
RUN npm install node-fetch --save

# not need "update-alternatives" if "n" package manager
# RUN update-alternatives --install /usr/bin/node node /usr/bin/nodejs 10

# to get files from local
ADD package.json .
ADD index.mjs .
ADD README.md .
# CMD npm run start
~~~

これで仮想マシンをBuildしたら動くのかと思いきや、またエラーが出てきてしまいました。

~~~javascript:index.js
import fetch from 'node-fetch';
~~~

どうやら、`.mjs`を使わないとimportできない問題は顕在中のようです。

https://iwb.jp/nodejs-esmodule-code-import-error/

しょうがないので拡張子を変えたら、ES6で動いていたスクリプトがやっと動きました！
fetchが動きました！　時間掛かった～！

~~~javascript:index.mjs
import fetch from 'node-fetch';
~~~

fetchモジュールの方は、mjsファイルにする方ではなく、package.jsonに`"type": "module"`を追加することで、index.jsの状態でも使えるようにしてるみたいです。

# おしまい
- すんごい困ったら新しいバージョンにしてみる。
- 新しいバージョンの方がエラーメッセージも分かりやすい。
- importしたファイルは.mjsファイルにする。
UnityでImageMagickを使う（Mac/Windows対応）

NuGetのMagick.NETを使って、UnityでImageMagickを利用できるようにします。
Unityエディタでの実行およびスタンドアロンでの実行で動作します。
UnityでRenderTextureを画像出力してImageMagickで画像加工するツールの開発などに便利です。

# 環境

- 開発OS: MacOS AMD64/MacOS AppleSilicon/Windows AMD64
- 実行OS: MacOS AMD64/MacOS AppleSilicon/Windows AMD64
- Unity: 2019.4.19
- Magick.NET: 8.3.3

# Magick.NETのダウンロード

以下の2つのパッケージからDLLを拝借します。

- [magick.net.core.8.3.3](https://www.nuget.org/packages/Magick.NET.Core/8.3.3)
- [magick.net-q8-x64.8.3.3](https://www.nuget.org/packages/Magick.NET-Q8-x64/8.3.3)

それぞれ、 https://www.nuget.org/ から取得します。magick.net.coreを例に説明します。
パッケージのWebページを開いたら、右側に「Download package」リンクがあります。ここからパッケージをダウンロードしてください（下図参照）。
この.nupkgファイルはZIP形式なので、拡張子をzipに変更して解凍しておきましょう。

![NuGet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754230/1f2b054f-bf85-9bdb-d396-4eb092d701fb.png)


# Unityプロジェクトの作成

新規にUnityのプロジェクトを１つ作成してください。
既存のプロジェクトに対して作業することもできますが、トラブルシュートしづらくなるのでまずは新規でお試しすることをお勧めします。
本記事では対象のUnityプロジェクトパスをPROJECT_PATHと記載します。

# DLLを配置する

コピー元、コピー先が重要です。正確にコピーしてください。

|コピー元|コピー先|
|-- | --|
|解凍先フォルダ/magick.net-q8-x64.8.3.3/lib/netstandard20/Magick.NET-Q8-x64.dll|PROJECT_PATH/Assets/Plugins/Magick.NET-Q8-x64.dll|
|解凍先フォルダ/magick.net-q8-x64.8.3.3/runtimes/win-x64/native/Magick.Native-Q8-x64.dll|PROJECT_PATH/Magick.Native-Q8-x64.dll <br>**(注意！プロジェクト直下です)**|
|解凍先フォルダ/magick.net-q8-x64.8.3.3/runtimes/osx-x64/native/Magick.Native-Q8-x64.dll.dylib|PROJECT_PATH/Assets/Plugins/Magick.Native-Q8-x64.bundle <br>**(注意！拡張子を変更しています)**|
|解凍先フォルダ/magick.net.core.8.3.3/lib/netstandard20/Magick.NET.Core.dll|PROJECT_PATH/Assets/Plugins/Magick.NET.Core.dll|


# 動作テスト

Magick.NETを使った簡単なコードを実行し、エラーがないことを確認します。
例えば、以下のコードは100x100の赤いPNG画像を生成します。

```cs:imunity.cs
using ImageMagick;
using UnityEngine;

public class imunity : MonoBehaviour
{
    void Start()
    {
        MagickImage image = new MagickImage(MagickColors.Red, 100, 100);
        image.Write("output.png");
    }
}
```

このように相対パスで出力ファイルを記載した場合、MacOSでは.appと同じパスに、Windowsでは.exeと同じパスに出力されます。

必要に応じて、MacOSスタンドアロン、Windowsスタンドアロンについても動作を確認します。
**Windowsスタンドアロンの場合、以下2点を行わないと正しく動作しません。ご注意ください。**

- Build Settings の Architecture で x86_64 を選択
- .exe と同じパスに Magick.Native-Q8-x64.dll をコピー

# 最後に

Magick.NETはバージョンごとに解凍した際のファイル構成がかなり違うので、より新しいバージョンでトライする場合は対応するファイルがどこに配置されているのか探すところから頑張ることになります。
面倒ごとを避けたい方は上記のバージョンで合わせて作業するとトラブルが少ないと思います。
あと、iOS/Androidで動作させる方法をご存じの方いらっしゃいましたらコメ欄でお教えいただけると大変うれしいです（切実）。
【Kotlin】スコープ関数まとめ

#はじめに
最近Androidアプリを作りたくてKotlinを学習してます。基礎です。
今回はスコープ関数をまとめていきたいと思います。

#スコープ関数
この関数は変数のスコープを変更する関数で、コードを簡略化、可読性の向上ができます。
使わなくても機能を実装することは可能です。
なくても困らないけどあれば便利ってやつですね。

#with関数
同じオブジェクトに繰り返し処理を行う場合に有効です。

次のようなPersonクラスを用意します。

```Kotlin
class Person(val name: String) {
    var age: Int = 0
    fun message(): String {
        Log.d("message", "私は $name です。 $age 歳です。")
    }
}
```

with関数を使わない呼び出し側はこのようになります。

```Kotlin
val person = Person("REON")
person.age = 21
person.message() // 私は REON です。 21 歳です。
```

withを使うと少し簡単に書けます。
オブジェクト`Person("REON")`にwithのスコープ内でthisとしてアクセスでき、thisは省略できるので以下のようにスマートに書けます。

```Kotlin
with(Person("REON")) {
    age = 21
    message() // 私は REON です。 21 歳です。
}
```

#apply関数
オブジェクトを生成してそれぞれ値を設定するときに使います。
with関数と違うところは、戻り値がオブジェクトであるところです。

```Kotlin
Person("REON").apply {
    age = 22
}.message() // 私は REON です。 22 歳です。
```

戻り値がオブジェクトなので、メソッドチェーンとして記述できます。

#let関数
安全呼び出し演算子「?.」と一緒に使うことが多いです。
with関数やapply関数と違い、オブジェクトはitで参照できます。

let関数を使わない場合

```Kotlin
var name: String? = "reon"
var upperCaseName = name?.uppercase(Locale.getDefault())
var nameLength = name?.length
Log.d("message", "$upperCaseName $nameLength") // REON 4
```

let関数を使う場合

```Kotlin
var name: String? = "reon"
var output = name?.let {
    var upperCaseName = it.uppercase(Locale.getDefault())
    var nameLength = it.length
    "$upperCaseName $nameLength"
} ?: "null"
Log.d("message", output) // REON 4
```

#run関数
run関数 = let関数 + with関数です。

先ほどのlet関数は以下のようにrun関数を使って書き換えられます。
with関数のようにthisでアクセスできるようになり、thisを省略できるのでこのように簡潔に記述できます。

```Kotlin
var output = name?.run {
    "${uppercase(Locale.getDefault())} $length"
} ?: "null"
Log.d("message", output)
```

#also関数
オブジェクトへ処理を行う場合やオブジェクトへの参照が必要な場合に使用します。
オブジェクトはitで参照でき、戻り値はオブジェクトです。

```Kotlin
val arrayInt = listOf(1, 2, 3).also {
    Log.d("message", "$it") // [1, 2, 3]
}
```




#おわりに
今回はスコープ関数を紹介しました。
ちなみに僕はSwiftを書くときにこんがらがりそうなので使わない派です。
【Rails】画像アップロードにcarrierwave

## CarrierWaveとは
Rubyのアプリケーションから簡単にファイルをアップロードするためのgemです。

## 開発環境
mac
ruby: 2.6.4
rails: 5.2.6
db: mysql

## 注意事項
本記事は、ローカルで作業する前提となります。
Gem追加後は読み込みの為にサーバーの再起動をしてください。
Carrierwaveのバージョンが2.0の場合は、Rails 5.0以上・Ruby 2.2以上が必要との事なので注意して下さい。
詳しい内容は下記の公式サイトから参照してください。
[carrierwave](https://github.com/carrierwaveuploader/carrierwave)

## 導入手順
- Gemfileにcarrierwave追加後インストール

```ruby:Gemfile
   gem 'carrierwave', '~> 2.0'
```
```linux:ターミナル
   % bundle
```

- 下記のコマンドでアップローダークラスを生成します。

```linux:ターミナル
   % bundle exec rails g uploader Avatar
```

- アップロード画像の情報を保存するavatarカラムを追加

```linux:ターミナル
   % bundle exec rails g migration add_avatar_to_users avatar:string
```
```linux:ターミナル
   % bundle exec rails db:migrate
```

ストロングパラメータに`permit(:avatar)`の追加を忘れずに

- avatarカラムとアップローダークラスの紐付け

```ruby:user.rb
class User < ActiveRecord::Base
  mount_uploader :avatar, AvatarUploader
end

```
- GithubにアップロードしないようGit管理下から除外

```git:.gitignore
/public/uploads
```

以上です。
【Cmd】フォルダ階層を保ったままファイルコピー

仕事でプログラミングをする時、完全に１から作ることって案外少ないです。
多くの場合、既にあるプログラムをコピーして作っていきます。

今回は特定の名称が含まれるファイル群を、フォルダ階層を保ったままコピーする方法を紹介します。

##概要
***
C:\SENOTE
├─1.00
│  │  X1.txt
│  │  Y1.txt
│  │  Z1.txt
│  │
│  └─subfolder
│　　　　X1-1.txt
│　　　　Y1-1.txt
│　　　　Z1-1.txt
│
└─1.01
***
↑こうなってるのを
***
C:\SENOTE
├─1.00
│  │  X1.txt
│  │  Y1.txt
│  │  Z1.txt
│  │
│  └─subfolder
│　　　　X1-1.txt
│　　　　Y1-1.txt
│　　　　Z1-1.txt
│
└─1.01
<font color="Red">　│  X1.txt</font>
<font color="Red">　│</font>
<font color="Red">　└─subfolder</font>
<font color="Red">　　　　　X1-1.txt</font>
***
↑こうしたいと思います。**（「X1」が含まれるファイルのみをコピー）**

##動画で見る
YouTubeに動画もアップしているので見てみてください。

<iframe width="640" height="360" src="https://www.youtube.com/embed/hlK0Zue5K48" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

##コマンドを使ってみよう

###コマンドプロンプトを開く
まずは、キーボードの「Windows」キーを押しながら「R」キーを押します。
「ファイル名を指定して実行」が起動するので、「cmd」と入力して「OK」を押します。

###ファイルをコピーする
以下の構文（/Sはサブフォルダまでコピー対象とするためのオプション）

```
robocopy [コピー元フォルダ] [コピー先フォルダ] *[コピー対象のファイル名（一部）]* /S
```
今回は以下のコマンドになります。

```
robocopy C:\senote\1.00 C:\senote\1.01 *X1* /S
```

##ついでに1.01フォルダ内の「X1」を「A1」に変更

コピーしたファイル名のまま使うということはあまりないと思うので、ファイル名の一括変更方法についてもついでに紹介します。

以下の構文（pushdは処理対象フォルダへの移動、renがファイル名の変更）

```
pushd [変更対象フォルダ] & ren [変更前文字]* [変更後文字]*
for /d /r [変更対象フォルダ] %i in (*) do (pushd %i & ren [変更前文字]* [変更後文字]*)
```
今回は以下のコマンドになります。
１行目で1.01フォルダ直下のファイル、2行目で1.01 フォルダ 内のすべてのサブフォルダ内のファイル名を変更する処理をしています。

```
pushd C:\senote\1.01 & ren X1* A1*
for /d /r C:\senote\1.01 %i in (*) do (pushd %i & ren X1* A1*)
```

##さいごに
いかがでしたでしょうか。コピー対象のファイル数が多いとなかなか手動でやるのは大変です。
コピーするルールが決まっていれば、今回のようにコマンドプロンプトを使ってみると時短ができるかもしれません。

##元記事
私が運営する以下のblogにも同じ記事を載せています。
https://senote.tokyo/folder-hierarchy-copy