OmniAICreator/Qiita-1.07M huggingface dataset:
SwiftのKeyPathとUndoの相性はバツグン！！！

Swift5.0導入の`KeyPath`と`UndoManager`の相性がはちゃめちゃに良かった話。

# 何の話？

まあとりあえずこれを観てくれ

```swift
protocol Undoable {}

extension Undoable {
    func registerUndo<Value>(
        _ keyPath: ReferenceWritableKeyPath<Self, Value>,
        _ oldValue: Value) 
    {
        undoManager.registerUndo(withTarget: self) { _self in
            _self[keyPath: keyPath] = oldValue
        }
    }
}
```

これで Undo の実装おしまい！！！


使う側はModel層で

```swift
class Model {
    var value: Int {
        didSet { registerUndo(\.value, oldValue) }
    }
}
```

これだけで Undo も Redo も実装完了！！！


# 解説


すげえええ！！！って勢いのままここまで書きました。ごめんなさい。真面目に解説します。

`UndoManager`とは`OS X - Cocoa`由来のやり直しを可能にする仕組みです。iOSでは見ることが少なかったのですが、最近iPadアプリでの実装例が増えている気がします。

例えばNumbersのこれとか

![ipados13-ipad-pro-numbers-5-2-smart-categories-chart.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117659/8ca12f0f-e667-b3e2-1dd3-aecd685685ce.jpeg)

でもってObjective-C時代は結構実装は面倒くさかったです。

Wrapper Objectを用意したり、setter が長くなったりしてました。

これが`Swift5.0`のKeyPathによって劇的に改善されたのです。

### 何をやっているか


コードの解説をします。

まず空の `protocol` を定義します。`registerUndo`内で `Self` を使うためです。

```swift
protocol Undoable {}
```

本命の`registerUndo`を`Undoable` の `extension` として定義します。

```swift
func registerUndo<Value>(
        _ keyPath: ReferenceWritableKeyPath<Self, Value>,
        _ oldValue: Value) 
    {
        undoManager.registerUndo(withTarget: self) { _self in
            _self[keyPath: keyPath] = oldValue
        }
}
```

`Objective-C` 時代は `NSDictionary` で `oldValue` の受け渡しをすることが多かったですが、クロージャが使えるのでそのまま参照できます。

```swift
var value: Int {
	didSet { registerUndo(\.value, oldValue) }
}
```

モデル側では `didSet` で Undo を登録します。

こうすることの何が素晴らしいかというと、Undoをすると原理的に自動でRedoが登録されることです。
services.api.networks must be a listと言われた

# はじめに
「Docker/kubernetes 実践コンテナ開発入門」でDockerを学んでいる時のエラーメッセージになります。
備忘録としての意味合いで簡潔に書きます。
## 「services.api.networks must be a list」のエラー文
Stackをデプロイするためにyamlファイルを書きましたが、yamlファイルの書き方が違ったようです。
**services.api.networks**の部分はyamlファイルの入れ子構造の部分なので、それぞれで変わるかと思います。
## 修正前
```ch03-webapi.yml
version: "3"
services:
  省略
  api:
    networks:
      - ch03　　←ここを指している

networks:
  ch03:
    external: true

```
## 修正後
```ch03-webapi.yml
version: "3"
services:
  省略
  api:
    networks:
      ch03:　　←ここを指している

networks:
  ch03:
    external: true

```

## 終わりに
コロン(:)にしたことで無事解決しました。
1次元波動方程式を差分法で解く（python)

# シンプルな波動方程式
```math
 \frac{\partial^2 u}{\partial t^2} = c^2 \frac{\partial^2 u}{\partial x^2} \\
0<x<l,0<t
```
これを解きたい

# 境界条件
```math
u(0)=0,\frac{\partial u}{\partial x}\Big|_{x=l} = 0
```
左端は境界での$u$の値を指定するディリクレ境界条件で、右端は境界値の微分値を指定するノイマン境界条件

左は固定端、右は自由端という境界条件になっている。
# 初期条件

```math
u(x,0) = f(x)\\
\frac{\partial u}{\partial t}=0
```

弦の振動や縦棒の振動であれば、初速は0ということ。

# 離散式
```math
x_i = i\Delta x\\
t^n = n\Delta t\\
u_{i}^n = u(x_i,t^n)\\
(i = 1\cdots m, \Delta x = \frac{l}{m})
```
と置く。ただし$m$は空間分割数とする。

## 初期条件　境界条件

まず初期解を設定する。

```math
u_{i}^0 = f(x_i)\\
u_{i}^1 = u_{i}^0
```
時間の一階微分が0なので$u_{i}^1 = u_{i}^0$となっている。

次に境界条件を設定する。
しかし、困ったことに右端のノイマン境界条件は空間微分で表されるため、表現するためには2要素使わなければならない。そのため、右端の境界にもう一つ偽の要素を加える。つまり、

```math
u_{m+1}^n = u_{m}^n
```
とすれば、一階の空間微分が0であるという、右端のノイマン境界条件が満たされる。
そして、左端のディリクレ境界条件は、以下のように表せる。

```math
u_1^n = 0
```
いよいよ方程式そのものを離散化していく。

## 空間微分の離散化
```math
\frac{\partial^2 u}{\partial x^2}\Big|_{x=x_i}=\frac{u_{i+1}-2u_{i}+u_{i-1}}{\Delta x^2}
```
$u_{i+1}$と$u_{i-1}$を$x=x_i$でテーラー展開して求めるとこれを導けます。

## 時間発展の離散化

空間微分と同様に考えると，

```math
\frac{\partial^2 u}{\partial t^2} =\frac{u^{n+1}-2u^{n}+u^{n-1}}{\Delta t^2}
```
であるから，

```math
\begin{align}
u^{n+1}_i &= 2u^{n}_i-u^{n-1}_i + \Delta t^2 \frac{\partial^2 u}{\partial t^2}\Big|_{x=x_i}\\
&= 2u^{n}_i-u^{n-1}_i + c^2 \Delta t^2 \frac{u_{i+1}-2u_{i}+u_{i-1}}{\Delta x^2}
\end{align}
```

# コードを書こう
サンプルクソコード

```python
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from copy import deepcopy


fig, ax = plt.subplots()

c = 1.
x_left = 0.
x_right = 1.
t = 0.
# 101個の点で離散化を行うという意味
num_points = 101
dx = (x_right-x_left)/(num_points-1)
# ノイマン境界のために余分に一つ確保
x = np.linspace(x_left, x_right+dx, num_points+1)
# u = x/1000 で初期化
u = 1e-3*x
# ノイマン境界条件
u[-1] = u[-2]

u_before = deepcopy(u)
u_next = deepcopy(u)

# 一定時間ごとのuの値をここに積んでいく
u_at_t = [deepcopy(u)]


dt = 0.1 * dx/c

count = 0


while t < 0.5:
    print(np.diff(u,2))
    u_next[1:num_points] = 2.*u[1:num_points] - u_before[1:num_points] + c*c*dt*dt/(dx*dx) * np.diff(u, 2)

    # ノイマン境界条件
    u_next[-1] = u_next[-2]
    u_next[0] = 0.
    u_before = deepcopy(u)
    u = deepcopy(u_next)
    u_next = np.zeros(u.shape)
    t += dt
    count += 1
    # 16ステップに一回
    if count == 16:
        u_at_t.append(deepcopy(u))
        count = 0


def update(u, x):
    plt.clf()
    plt.xlim(x_left, x_right)
    plt.ylim(-1e-3, 1e-3)
    plt.plot(x, u)


# アニメーション表示するための関数
anim = FuncAnimation(fig, update, fargs=(
    x,), frames=u_at_t, interval=10)

plt.show()

# anim.save("foo.mp4", writer="ffmpeg",fps=10)

```
動画を保存するのは重たい作業になるので注意


続く
# 参考
動画作成のためのテクニック
https://qiita.com/msrks/items/e264872efa062c7d6955
差分式
https://qiita.com/Ushio/items/0249fd7a5363ccd914dd
背景画像を読み込む方法

#背景画像を読み込む方法

publicディレクトの下にimagesフォルダを作り、ネットでダウンロードした画像をそこに置く。

cssで背景画像を読み込ませるには

```
background-image: url('../images/minato1.jpeg');
background-size: cover;
```

と指定してあげる必要があります。

background-size: cover;は画像のサイズに応じて全画面を覆ってくれるので、背景画像として使う時に必要。
GitHub API でコミットに紐づくタグを取得する

# モチベーション

- git のコミット ID に紐づくタグの一覧を GitHub から取得したい
- GitHub API によると
  - タグからコミット ID を取得する API はある
  - コミット ID からタグを取得する API はない
- なんとかして後者を実現したい

# 手順

ここでは Bash と jq を使います。

1. リポジトリのタグ一覧を取得する API を叩く  
https://developer.github.com/v3/repos/#list-repository-tags
1. 一覧から当該コミット ID を含むタグのみを抽出

## 1. リポジトリのタグ一覧を取得する API を叩く  

```bash:bash_script
# GitHub API をコール
response=$(curl -H "Authorization: token ${GITHUB_ACCESS_TOKEN}" \
                -H "Content-Type: application/json" \
                -s -XGET https://api.github.com/repos/${OWNER}/${REPO}/tags \
          )
```

### 参考: response の例

```json:response
[
  {
    "name": "test1",
    "zipball_url": "https://github.com/octocat/Hello-World/zipball/test1",
    "tarball_url": "https://github.com/octocat/Hello-World/tarball/test1",
    "commit": {
      "sha": "c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc"
      "url": "https://api.github.com/repos/octocat/Hello-World/commits/c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc"
    },
    "node_id": "MDM6UmVmMjAxMTcwOTQ4OnRlc3Qx"
  },
  {
    "name": "test2",
    "zipball_url": "https://github.com/octocat/Hello-World/zipball/test2",
    "tarball_url": "https://github.com/octocat/Hello-World/tarball/test2",
    "commit": {
      "sha": "c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc"
      "url": "https://api.github.com/repos/octocat/Hello-World/commits/c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc"
    },
    "node_id": "MDM6UmVmMjAxMTcwOTQ4OnRlc3Q"
  },
  {
    "name": "test3",
    "zipball_url": "https://github.com/octocat/Hello-World/zipball/test3",
    "tarball_url": "https://github.com/octocat/Hello-World/tarball/test3",
    "commit": {
      "sha": "762941318ee16e59dabbacb1b4049eec22f0d303"
      "url": "https://api.github.com/repos/octocat/Hello-World/commits/762941318ee16e59dabbacb1b4049eec22f0d303"
    },
    "node_id": "MDM6UmVmMjAxMTcwOTQ4OnRlc3Qz"
  }
]
```

## 2. 一覧から当該コミット ID を含むタグのみを抽出

```bash:bash_script
# コミット ID を指定
COMMIT_SHA='c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc'

# レスポンスからコミットに紐づくタグ JSON のみを取得
tag_object=$(echo -e "$response" | jq -r ".[] | select(.commit.sha == \"$COMMIT_SHA\")")
[[ -z $tag_object ]] && echo "No tag is found. response = $response" && exit 0

# タグ名だけを抽出して JSON の配列に整形して返す
echo -e "$tag_object" | jq '. | .name' | jq -s
```

# 実行結果

```json:実行結果
[
  "test1",
  "test2"
]
```

# メモ

- 全タグを取得してしまっているのであまりエコではない。もっといい方法はないものか。
【PHP】ワイ、客先でウェブサーバーをビルトするの巻


# はじめに

この記事では
PHPの導入方法や使い方ついて
まとめた記事です。
ベストプラクティスや間違いがあれば
書き直していく予定です。
今回は導入時とそのつまづきポイントについて
とビルトインウェブサーバーについて書きます。

--------------------------------
# 想定される環境

客先常駐
Windows10 Pro 64bit 
PHP 7.2.31

--------------------------------
# それってさぁ
そうです。
イマドキはdockerもしくは
クラウドでやるのが当たり前になっています。


--------------------------------
# 便利にしたいけど、んー

便利なものがあれば使えば良いんじゃないのって
なるのが普通ですが実行に移す上で
解決すべき問題が複数あります。

--------------------------------
# 問題点

・環境を好きに扱うことは難しいこと
・技術レベルがかなりのミスマッチであること
・学習コストがかかりすぎること

--------------------------------
# 環境を好きに扱うことが難しいこと

> お客様先の環境を好きに扱うことは難しいこと

これについては正直３つの中でもっとも難しい話でした。
というのもやはり、情報セキュリティが厳しい中
お客様先にソフトウェアを導入するには
お客様との信頼関係が必要

一番難しい話でしたが
これについては地道な努力が実を結び
知らず知らずのうちに信頼されていました。

--------------------------------
# 技術レベルがかなりのミスマッチであること

新人くんなどの研修を聞くと
オンプレミス前提の内容がまぁ多いこと

なぜ、手軽なコンテナ技術を使わないのか
とても疑問ですが
それを言うと私も現場の技術選定に
dockerを選択していないので
人のこと言えないのかなと思うので
いつかは入れる！いや、今年中にはdockerを導入したい！

--------------------------------

# 学習コストがかかりすぎること

docker上でPHPをやるためには
まず、dockerでサーバをビルトしないといけない。
（PHPの学習に辿り着けない？？？）

そもそもインフラをコード化するという
**infrastructure as code(IaC)** すら
知らない状況でdockerをぶち込むのは
かなりの鬼畜、相当鬼畜

--------------------------------

# ビルトインウェブサーバーとは

話がそれましたが
ざっくりいうと  
PHP 5.4.0 から導入されたウェブサーバーの機能

ローカルホストのアドレスとポート番号を
指定すると
そのアドレス上でPHPを動かしてくれる。

ローカルホストにポート8080でサーバをビルトするコマンド例

```
$ php -S localhost:8080
```

参考サイト
[php.net](https://www.php.net/manual/ja/features.commandline.webserver.php)

--------------------------------
# どんなときに使える

・xammpが使えない環境のとき
・ちょっとだけ実行内容を確認したいとき
・PHPを教えるとき

--------------------------------
# 導入方法
[php.net](https://www.php.net/downloads) から
zipでダウンロードする

解凍して任意の場所にフォルダを置く

環境変数PATHにフォルダパスを通す

php.iniを設定する。

ちなみにここで私はPostgresSQLを使う予定なので
php.ini の 907行あたりで

```
extension=pdo_pgsql
```
を記載しました。


--------------------------------
# さて動かしてみ。。。ん？
ヨシッ！動かすぞ！！
ん？？ phpinfoで設定内容を見ると

反映していないはずのmysqlとsqliteのpdoが反映されている！！

--------------------------------
# 怪奇現象の原因
もともと、xamppをインストールしている端末でした。
xammpをアンインストールして
xammpフォルダを削除することで解決しました。


--------------------------------
# 今後の方針

Laravel入れて
自分の業務効率化の為にアプリケーションでも作ろうかしら。
そうなると
Laravelの導入方法も調べないとダメね。

--------------------------------

# おわり
--------------------------------
Ubuntuでタッチパッドをタップしてクリックをオフにしたい

# Ubuntuでタッチパッドをタップしてクリックをオフにしたい
Ubuntuをインストールしたノートパソコンを利用しているとタッチパッドに親指が触れてカーソル位置がずれてしまうことがあります。
以下のコマンドでタッチパッドをタップしたときのクリックをオフにできます。

```shell
$ gsettings set org.gnome.desktop.peripherals.touchpad tap-to-click false
```

もとに戻したい場合は以下のコマンドを実行します。

```shell
$ gsettings set org.gnome.desktop.peripherals.touchpad tap-to-click true
```
Windows 10 + nodejs + selenium-webdriver + msedgedriver で headless edge(Chromium) を試してみる

#目的
Edge(Chromium)をnodejs + selenium-webdriver + msedgedriverからキックしてみる
※非同期系の処理は、まだまだだなぁ・・・・

##SeleniumBasicのインストール
※環境変数の文字数制限により、同居(笑)
[Seleniumbasic](https://florentbr.github.io/SeleniumBasic/)の Release page より SeleniumBasic-2.0.9.0.exe をDLする
exeを実行すると、C:\Users\user_name\AppData\Local\SeleniumBasic にインストールされる
ソースコードのプロジェクトをVS2019で開くと .NET Framework 3.5 を指定しているので
Windowsの設定 -> アプリ -> オプション機能 -> Windowsのその他の機能 -> .NET Framework 3.5 が有効であることを確認する

##MSEdgeDriver
[バージョン情報](edge://settings/help)よりEdgeのバージョンを確認する
今日時点では バージョン 83.0.478.45 (公式ビルド) (64 ビット)
[WebDriver](https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/)よりバージョンに合わせてDLする
edgedriver_win64.zip を解凍後 msedgedriver.exe を SeleniumBasic フォルダに上書する

##selenium-webdriverのインストール
<pre>
> npm install -S selenium-webdriver
+ selenium-webdriver@4.0.0-alpha.7
</pre>
##@microsoft/edge-selenium-toolsのインストール
<pre>
> npm install @microsoft/edge-selenium-tools
</pre>

##サンプルコード
```js
var edge = require('selenium-webdriver/edge');

let driver;
(async () => {
  try {
        let options = new edge.Options();
        options.setEdgeChromium(true);
        options.setBinaryPath("C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe");
        options.addArguments("headless");
        options.addArguments("disable-gpu");

        driver = edge.Driver.createSession(options);
        driver.get("http://www.google.com");

        let html = await driver.getPageSource();
        console.log(html);

    }  catch(error) {
        console.error(error);
    }  finally {
        if(driver) {
            await driver.quit();
        }
    }
})();
```
#参考にしたのは以下のサイト
[selenium-webdriver](https://www.npmjs.com/package/selenium-webdriver)
[Module selenium-webdriver](https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/)
[テストオートメーションに WebDriver (Chromium) を使用する](https://docs.microsoft.com/ja-jp/microsoft-edge/webdriver-chromium?tabs=javascript)
[Promiseが分かれば簡単！async, await](https://qiita.com/valley/items/dd37deb77f06eb6c451c)
[Windows 10 + Excel2016 VBA + seleniumbasic で chromedriver / msedgedriver を使ってみる](https://qiita.com/tabizou/items/9793dc04d3d98d3b4842)
[Selenium Python(ABC順)](https://www.seleniumqref.com/api/webdriver_abc_python.html)
phpでuseした時ってメモリ使うんだっけ

# phpでuseした時ってメモリ使うんだっけ
わからんのでやってみよう。

## やってみる
### やった環境
```shell-session
$ php -v
PHP 7.4.6 (cli) (built: May 14 2020 10:38:36) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Xdebug v2.9.2, Copyright (c) 2002-2020, by Derick Rethans
    with Zend OPcache v7.4.6, Copyright (c), by Zend Technologies
```

### やってみた
```PHP:main.php
<?php

namespace main;

$usage['current'] = memory_get_usage();    
logging($usage, 'initialize usage.');

require_once('empty.php');
logging($usage, 'require empty.php.');

require_once('hoge.php');

logging($usage, 'require hoge.php.');
\hoge\getName();

use hoge as piyo;
logging($usage, 'set alias.');
piyo\getName();

function logging(array &$usages, string $tag = ''): void {
    $usages['before'] = $usages['current'];
    $usages['current'] = memory_get_usage();
    echo sprintf('usage memory %4d. %s'.PHP_EOL, ($usages['current'] - $usages['before']), $tag);
}
```
な感じで↓を読み込んでみた

```PHP:empty.php
<?php
```

```PHP:hoge.php
<?php

namespace hoge;

function getName(): string
{
    return 'hoge';
}
```

### やった結果
```shell-session
$ php main.php 
usage memory  408. initialize usage.
usage memory  224. require empty.php.
usage memory  528. require hoge.php.
usage memory    0. set alias.
```
requireしたときにメモリ消費して、useのときには消費しないと
名前空間ってむずかしい

## おまけ
* [テストコードとか突っ込んだリポジトリ](https://github.com/kotaoue/InvestigateUseMemory)
Express+Node.js+Passportでgoogle認証を作る（ログイン画面を作る）

#内容
自分のためのメモだよ
hoge hoge
初心者には敷居が高い
写真を載せる

## 1. 必要なものをインストールする

今回のプロジェクトで必要となるライブラリをインストールする。`--save`はパッケージのインストール時、package.json の dependencies に追加してくれる機能。
npm v5 以降はインストール時にデフォルトで package.json の dependencies に追加してくれるようになったので --save オプションは[不要になった。](https://qiita.com/havveFn/items/c5beda8572aa8c1e6be6)

けど、一応つけておく。

```
npm install --save passport passport-google-oauth20
```

## 2. google +の設定を行う

Oauth でアカウントを作る。

callbackのURLを
http://localhost:5000/auth/google
に変更する必要が有る。


## 3. index.jsを編集する
clientIDとclientSecretをソースコードにコピペする。

client ID: みんなに共有してもいいやつだよ。
Client Secret: プライベートなトークンでみんな共有してはダメだよ。
だから、Client Secretの方はgitにプッシュしないように、ファイルを分ける必要がある。

なので、

```
module.exports={
googleClientID: "hoge",
googleClientSecret:"foo"
};
```

を別のファイルに記述する。そして、そのファイル名を`.gitignore`の中に記述して、gitでpushされないようにする。


###Under Constructon
Raspberry Pi のNode-REDで簡単IoT入門

### Raspberry Pi のNode-REDで簡単IoT ###
Raspberry PiにNode-REDをインストールして簡単IoTを体験します。
![nodered3-01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199447/65c2a75f-6bc7-f889-9350-74dc50155df3.jpeg)
ダッシュボードで作成した画面でLEDの明るさをコントロールしてみます。
### 1.制御回路を作る
ブレッドボードを使用してLEDと抵抗をRaspberry Piのピンと接続します。LEDのアノード側に適当な抵抗を挟んでGPIO2、カソード側をGNDへと接続します。
![raspiLED.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199447/c79a4c60-fa08-6555-ebbe-ff0c5b75879f.jpeg)


Raspberry Pi のピンコネクタは、USBなどのコネクタを下にしてピン番号を見ます。
![noderedled.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199447/b6955cc9-27f3-4267-290e-ccf9a554b0ce.jpeg)
### 2. ダッシュボードの設定
Raspberry Piノードからrpi gpio outを選んで配置して、ダブルクリックしてプロパティを設定します。

![nodered3-01 (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199447/e465f8fa-5255-3de1-c5de-aae9461e561a.jpeg)
スライダの値でLEDの明るさを変えるようにしたいので、Raspberry PiのGPIO からpwm出力を利用します。
プロパティの設定で出力をpwmにして、解説に書かれているお勧めのピン(GPIO2)を選んで完成です。
![nodered3-02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199447/02391663-57ee-8a74-a50e-d4561f55c9d8.jpeg)
フローエディタに戻って、 sliderの左側の○から、pwm:3と表示されたノードの右側の○にワイヤをつないで完成です。
![nodered3-3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199447/2538353c-cfdd-6d6f-5341-ae5ae8eae942.jpeg)
### 3.動作チェック
デブロイしてページを表示したらスライダを動かすとLEDの明るさが変わります。
![led01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199447/02e6cab8-646e-26c1-88d5-b2523cf7debc.jpeg)

### 4.応用編
スライダでの制御がうまくできたら、ボタンのON/OFFでLEDがON/OFFするようにフローを追加してみましょう。
[Scratch3.0×WeDo2.0]   キーボードでレゴを遠隔操作する

この記事はレゴを遠隔操作してみたい人のための記事です。
今回はパソコンのキーボードでレゴのクルマを遠隔操作してみます。

#目次
1.曲がれるクルマをつくろう
2.パソコンとレゴをつなげよう
3.プログラムをつくろう

#1.曲がれるクルマをつくろう
![スクリーンショット 2020-06-14 14.42.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654004/008e30a0-0afa-8cdd-f4bf-88a021f2886a.png)
![スクリーンショット 2020-06-14 14.42.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654004/7acab9da-9254-45ac-c1f4-2563601206bd.png)
![スクリーンショット 2020-06-14 14.42.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654004/c880a0bb-29f9-4a53-7c72-8045b9f24bcd.png)

#2.パソコンとレゴをつなげよう
####①サインインして"つくる"を押そう！
![スクリーンショット 2020-06-14 14.49.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654004/93461f74-4279-7f20-8953-d207b038189f.png)
####②スクラッチリンクを実行しよう！
####③bluetoothを有効にしよう！
####④タイトルを入力したら、拡張機能を選ぼう！
![スクリーンショット 2020-06-14 14.50.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654004/b4a111c0-674e-98cb-172e-30f2932bb02b.png)
　　　↓
![スクリーンショット 2020-06-14 14.50.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654004/cdaa23d5-0ba7-2e0c-7b0a-42c43d507d7f.png)
####⑤"検索を開始"ボタンを押してWeDo2.0のハブのボタンを押そう！
![スクリーンショット 2020-06-14 14.50.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654004/0e483059-3508-3dea-3044-1f9616874a01.png)
![スクリーンショット 2020-06-14 14.50.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654004/0ade9f07-0d7c-b2be-9ea7-2790dccd1fc3.png)
####⑥もし下のようになったらスクラッチリンクとbluetoothを確認して"もう一度試す"を押そう！
![スクリーンショット 2020-06-14 14.50.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654004/c3ec7a5c-b217-9a06-6f01-e898c667610c.png)


#3.プログラムをつくろう
###◯上向き矢印キーを押したとき(だけ)前進するプログラム
![スクリーンショット 2020-06-14 15.24.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654004/aebce8b4-5e03-cddb-9057-932e8e8635f9.png)
###◯上向き矢印キーで前進、右向き矢印キーで右折するプログラム
![スクリーンショット 2020-06-14 15.35.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654004/d22077bc-5fd6-6a00-18bd-3ca8069f0037.png)


#最後に
読んで頂きありがとうございました！　
ぜひ色々な操作をぜひやってみてください！！

より良い記事にしていくために、
　◯こうした方がわかりやすい
　◯ここがわかりにくい
　◯ここが間違っている
　◯ここをもっと説明して欲しい
などのご意見、ご指摘お待ちしております。
何卒よろしくお願い致します。
Unityでドアを作りたい (C#でゴリゴリ)

僕はUnityのAnimationを全く使いこなせないのでC#を使います。

## 作りたいドア
 - ある程度ドアに近づいてFキーを押すとドアが開く。
 - もう一度Fキーを押すとドアが閉じる。
 - ドアから離れたらFキーを押しても何も反応しなくなる

## 1. GUIでドアを作る
Cubeをドアの形にして、ただそれを回すだけだと中心を軸に回ってしまうので、空要素の中にドアを入れて、空要素の軸をドアの端に設定して空要素を回すことでUnity特有のPivot位置変えられない問題は解決します。
![スクリーンショット 2020-06-14 15.07.39.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502570/79e7e292-ce99-5786-5498-5697c5a492bd.jpeg)

## 2. C#で回す
今回は引き戸を作ります。

```c#
using System.Collections;
using UnityEngine;

public class Door_Controller : MonoBehaviour {
    public bool isOpened = false;
    public bool isEnter = false;

    void Update () {
        if (Input.GetKeyDown (KeyCode.F)) {
            if (isEnter && !isOpened) {
                transform.Rotate (0, 90, 0);
                isOpened = true;
            } else if (isEnter && isOpened) {
                transform.Rotate (0, -90, 0);
                isOpened = false;
            }
        }
    }

    private void OnTriggerStay (Collider collider) {
        if (collider.gameObject.tag == "Player") {
            isEnter = true;
        }
    }
    private void OnTriggerExit (Collider collider) {
        if (collider.gameObject.tag == "Player") {
            isEnter = false;
        }
    }
}
```

僕が書いたコードなので難しいことは何一つありません。

## 3. コンポーネントを追加して完成...
さっきの空要素に上のコードを追加して...
![スクリーンショット 2020-06-14 15.22.21.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502570/4f870e9d-faab-0355-cb9d-470d50fe729e.jpeg)

実行すればちゃんと動くはず。
<img width="702" alt="スクリーンショット 2020-06-14 15.26.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502570/f53517db-825f-f698-3dcb-77d899364a61.png">

実行!!
<img width="714" alt="スクリーンショット 2020-06-14 11.12.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502570/97d371bb-f9ec-8717-395a-846d313b54a2.png">

#### !!!!!....??

ただY軸を回転させただけなのになぜかサイズがおかしなことに...

## 4. 空要素を一度ルートディレクトリに戻す
半日かけて原因を追及したところ、どうやら最初にドアを作る作業をネストの中で行うと、サイズが親要素比べの値なので回転するだけでバグって変なことになるらしいです。

こうなってたのを
<img width="443" alt="スクリーンショット 2020-06-14 11.11.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502570/42ade400-76e2-c84f-e531-3901325b5d2f.png">
こうすると...
<img width="454" alt="スクリーンショット 2020-06-14 15.33.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502570/a40c65aa-68f4-bd08-da9e-fdb68b9ec3d9.png">
頼む...
<img width="701" alt="スクリーンショット 2020-06-14 15.35.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502570/18b799cc-0a9a-4d95-360c-c114e1d69ef5.png">

**動いた！**

---
このネスト問題はググっても全然出て来なかったのが1番の罠だったので参考になれば幸いです。
【SQL】SUM関数でGROUP BYを用いないとエラーになる際の対処法・考え方

####状況

SQLを勉強し始めて約2週間くらいになります。
タイトルの通り、SUM関数を用いたSELECT文を作成中に、エラー（意図した値が取得できないこと）が
発生した為、自身の備忘録も含めて記載します。

####具体例

「注文」テーブルがあるとします。
このテーブルには、注文された商品の商品コードや注文番号、注文された数量などが
格納されています。

そこから、注文された数量の合計を取得したい時、,以下で取得できます。

```ruby:SQL

SELECT SUM(数量)
FROM 注文

```

FROM句で「注文」テーブルを指定し、「注文」テーブルのカラムである「数量」の合計（SUM関数で取得できる）
を抽出しようとしています。

このクエリはうまくいきます。

今度は、「注文」テーブルから「注文コード」と「数量の合計」２つのカラムの値を取得したいとします。
初めに下記の様なSELECT文を思いついたのですが、こちらだと意図した値が取得できません。

```ruby:SQL
SELECT 注文コード,SUM(数量)
FROM 注文
```

####解決策

```ruby:SQL
SELECT 注文コード,SUM(数量)
FROM 注文
GROUP BY 注文コード
```

上記の様に、GROUP BYで指定したカラム列によってグループわけして
データを抽出することで、「注文コード」と「数量の合計」を取得できます。

SUM関数を用いると、複数の行を１つの行にまとめることになるので、集計結果が１行になります。
その１行になった集計結果に、複数行ある「注文コード」を対応させることができずエラーになるようです。

####今後
今回のエラーでSQLクエリが発行された時に読み込まれる順番など、
意識していなかった大事な部分に気づけました。
引き続き学習を続けます。。。
競技プログラミング練習記 No.9【ABC147練習】

初回 -> [はじめに](https://qiita.com/easychoco/items/a9ae28aca97cfe47091f)

[ABC147](https://atcoder.jp/contests/abc147)を解きました。
3完です。
D問題は自力で解けず、解説等を見て解きました。

|問題|時間|アルゴリズム|実行時間
|:-:|:-:|:-:|:-:|
| A |  1min |-|1ms|
| B |  2min |-|1ms|
| C | 55min |bit全探索|2ms|
| D | - |xor|115ms|



## A
```c++
	int a1, a2, a3;
	cin >> a1 >> a2 >> a3;
	cout << (a1 + a2 + a3 >= 22 ? "bust" : "win"); 
```
やるだけ

## B
``` c++
	string s;
	cin >> s;
	int ans = 0;
	int s_size = s.length();
	for(int i = 0; i < s_size / 2; ++i)
	{
		if (s[i] != s[s_size - i - 1])
		{
			ans++;
		}
	}
	cout << ans;
```
回文の判定方法はいろいろありますが、
入力文字列を前と後ろから同時に見て、1文字ずつ判定しました。

## C
``` c++
using Pair = pair<int, int>;
#define X first
#define Y second

void solve()
{
	int n;
	cin >> n;
	vector< vector<Pair> > saying(n, vector<Pair>());

	int a, x, y;
	for(int i = 0; i < n; ++i)
	{
		cin >> a;
		for(int j = 0; j < a; ++j)
		{
			cin >> x >> y;
			x--;
			saying[i].emplace_back(make_pair(x, y));
		}
	}

	int ans = 0;
	int people = 1 << n; // bit 0で不親切, 1で正直者
	while(people -= 1, people >= 0)
	{
		bitset<15> mask(people);
		if ((int)mask.count() <= ans) continue;

		bool ok = true;
		for(int i = 0; i < n; ++i)
		{
			if (mask[i])
			{
				for(const auto& s : saying[i])
				{
					ok &= ((int)mask[s.X] == s.Y);
				}
				if (!ok) break;
			}
		}
		if (ok)
		{
			ans = (int)mask.count();
		}
	}
	cout << ans;
}
```
制約に `N = [1, 15]`とあったので、`O(2^N)`かなとおもったらその通りでした。
この問題は`N`人が不親切か正直者かの組み合わせが`2^N`通りあるので、すべて調べます。
bit全探索というやつですね。この部分です↓

```c++
	int people = 1 << n; // bit 0で不親切, 1で正直者
	while(people -= 1, people >= 0)
```
bitを扱うときは`std::bitset`が便利です。
`不親切な人 = 必ずうそをつく` だと思いこんでしまい、時間がかかりました。
`不親切な人 = うそかほんとかわからない` でした。反省。
思いこみって怖いです。


## D


``` c++
	int n;
	cin >> n;

	vector<ll> a(n);
	for(int i = 0; i < n; ++i)
	{
		cin >> a[i];
	}

	ll ans = 0;
	for(int i = 0; i < 60; ++i)
	{
		ll d0 = 0, d1 = 0;
		for(int j = 0; j < n; ++j)
		{
			// i 桁目が 1 か 0 か
			if((a[j] >> i) & 1) ++d1;
			else ++d0;
		}

		// i 桁目が 1 の個数
		ll n = d0 * d1 % MOD;

		// 2^i * d0 * d1
		ll tmp = ((1LL << i) % MOD) * n % MOD;

		ans = (ans + tmp) % MOD;
	}
	cout << ans << endl;
```

制約より入力値は `a = [0, 2^60]` なので、最大で2進数の60桁です。
`long long`型が64bitなので`long long`型の範囲内ですね。

「`i`桁目が`0`の数字」と「`i`桁目が`1`の数字」とでxorを計算すると、
計算後の`i`桁目は`1`になりますよね。
xorには繰上りがないので、計算前の`i`桁目だけを見て計算結果がわかります。
つまり、各桁ごとに独立して考えても大丈夫です。

今回の問題は入力値どうしでxorを計算します。
xorなので2進数で考えます。
各入力値を調べて、「`i`桁目が`0`の個数」と「`i`桁目が`1`の個数」を計算します。
これで、xorを計算後の「`i`桁目が`1`になる個数」が分かりますよね。

それを計算しているのが
`ll n = d0 * d1 % MOD;`
です。

そのあとは2進数から10進数になおして、`Σ`による足し算を計算します。
今は`i`桁目を見ていて、`i`桁目が`1`になっている数字が `d0 * d1`個あるので、
計算結果は `2^i * d0 * d1` ですね。
`ll tmp = ((1LL << i) % MOD) * n % MOD;`
の部分です。

最後に `ans`に加算して`i`桁目の計算は終わりです。
MODをとる必要がある問題は計算するたびに `% MOD` が出てくるので少し大変ですね


以上です。ありがとうございました。
「プログラミングtypescript」学習メモ1

オライリーの「プログラミングtypescript」の5.13 練習問題 4.b
練習問題がむずくて全然進まん・・

型安全なビルダーパターンの設計について。以下のようなメソッドよびだしを行う。setURL, setMethodは必須、setDataは任意で、最後にbuildメソッドを呼ぶ。

```typescript

new RequestBuilder2()
            .setData({})
            .setURL('bar')
            .setMethod('post')
            .build()
```

### 該当のソースコード

```typescript
interface BuildableRequest {
    data?: object
    method: 'get' | 'post'
    url: string
}

class RequestBuilder2 {
    data?: object
    method?: 'get' | 'post'
    url?: string

    setData(data: object): this & Pick<BuildableRequest, 'data'>{
        return Object.assign(this, {data})
    }

    setMethod(method: 'get' | 'post'): this & Pick<BuildableRequest, 'method'>{
        return Object.assign(this, {method})
    }

    setURL(url: string): this & Pick<BuildableRequest, 'url'>{
        let h = Object.assign(this, {url})
        console.log(h)
        // RequestBuilder2 { data: {}, url: 'bar' }のような出力になる
        // let h: this & { url: string; } 型
        return h
    }

    build(this: BuildableRequest){
        return this
    }
}

let b = new RequestBuilder2()
            .setData({})
            .setURL('bar')
            .setMethod('post')
            .build()
console.log(b)
```

### 学び
- Pick  
  https://www.typescriptlang.org/docs/handbook/utility-types.html#picktk  
  BuildableRequestからプロパティ'url'などを選んで型を構築する。
- Object.assign  
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/assign  
  
### よくわからない

なんで`{url}`と書いたら、`{ url: 'bar' }` になるんや、誰か詳しい人教えてンゴ・・
Salesforce Files Connect の検証

SharePoint OnlineとGoogle Driveについて、Salesforce Files Connectの検証を行いました。
API Version 48.0の運用組織で検証しています。

# 結果
|接続先|できなかったこと|
|:--|:--|:--|
|SharePoint Online|（Salesforceファイルにおいて）プレビューができない。|
|Google Drive|外部オブジェクトのカスタマイズ|

SharePoint Onlineでプレビューができません。これは、ドキュメント化はされてはいます。
問題なのは、代替に用意されているリンクをクリックした場合でもPDFはSharePoint Online側でプレビューできず、ファイルのプレビューが不可能です。SPOの仕様という気もしますがユースケースによっては致命的な問題になりえます。
Google Driveでは、普通にプレビューできます。

SIの時にはSPOは繋がるけど、問題ありといったぐらいに説明するのがよさそうです。

## SharePoint Onlineのプレビュー挙動
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53358/37c084d8-07f8-4724-3423-1be72455b8e9.png)


# 設定方法

https://help.salesforce.com/articleView?id=admin_files_connect_overview.htm&type=5 内に記載のある、`Files Connect の『設定ガイド』および『ユーザガイド』`（英語）が参考になります。

## Files Connect Setup Guide Winter’17 (“204”)

上記の設定ガイドのリンク先です。p.12にさりげなく`Support previews: Yes (only in Lightning
Experience for Google Drive)` と記載されています。
LGTM outside of Qiita

Qiita以外でLGTMな記事をメモします。

○Vue.jsとFlaskでフルスタックなWebアプリの開発環境を構築 その１〜〜環境構築〜〜
https://kittagon.hateblo.jp/entry/2018/08/27/011354

○【これだけで大丈夫】.gitignore チートシート
https://blog1.mammb.com/entry/2020/01/30/090000
Ubuntu 20.04へのCUDAインストール方法

Ubuntu 20.04 に NVIDIA の CUDA のインストール方法です。私は主に Google Cloud や Amazon EC2 の GPU インスタンスを使っているので、それ前提で書きます。ストレージは20GB程度必要です。Python からしか使わない場合は Anconda 内蔵の CUDA を使用するのがお勧めです。

Ubuntu の他のバージョンはこちらをご覧ください。

- Ubuntu 16.04 https://qiita.com/yukoba/items/3692f1cb677b2383c983
- Ubuntu 18.04 https://qiita.com/yukoba/items/4733e8602fa4acabcc35

# 前準備
```
sudo apt update
sudo apt upgrade
```

# CUDA 10や11をNVIDIAのリポジトリからインストール
Ubuntu 18.04 向けが https://developer.nvidia.com/cuda-downloads で配布されているのですが、Ubuntu 20.04 はまだ配布されていないのですが、Ubuntu 18.04 用がそのまま動きます。以下は、Installer Type で deb(network) を選択する場合の流れです。ここで apt install で cuda だと最新版がインストールされ、cuda-10-1 のようにバージョン指定も出来ます。

```
sudo apt-key adv --fetch-keys http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub

wget wget http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-repo-ubuntu1804_10.2.89-1_amd64.deb
sudo dpkg -i cuda-repo-ubuntu1804_10.2.89-1_amd64.deb
sudo apt update

sudo apt install cuda cuda-drivers
sudo reboot

rm cuda-repo-ubuntu1804_10.2.89-1_amd64.deb
```

その後、~/.bashrc の末尾にこれを追加する必要があります。

```
export PATH="/usr/local/cuda/bin:$PATH"
export LD_LIBRARY_PATH="/usr/local/cuda/lib64:$LD_LIBRARY_PATH"
```

そして一度ログオフして再度ログインしてください。

nvidia-smi で動作確認です。cuBLAS など cuDNN 以外は一通りついてきます。

# cuDNNのインストール

cuDNN は別配布ですが、こちらも Ubuntu 18.04 用がインストールできます。

```
echo "deb https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64 /" | sudo tee /etc/apt/sources.list.d/nvidia-ml.list
sudo apt update
sudo apt install libcudnn7-dev
```

# CUDA 10.1をUbuntuのリポジトリからインストール

NVIDIA のリポジトリからではなく、Ubuntu 20.04 のリポジトリからインストールする方法です。

```
sudo apt install nvidia-cuda-toolkit nvidia-driver-440
sudo reboot
```

nvidia-smi で動作確認です。cuBLAS など cuDNN 以外は一通りついてきます。

ただし、この方法は Ubuntu 20.04 である限り、ずっと CUDA 10.1 です。

# Anaconda内蔵のCUDAとcuDNNを使用する場合

Anaconda で ```conda install tensorflow-gpu``` などをすると自動的に CUDA と cuDNN がインストールされます。ただしデバイスドライバはインストールされないので ```sudo apt install nvidia-driver-440``` して ```sudo reboot``` が必要です。Python からしか使わない場合は、この方法が簡単です。NVIDIA のリポジトリは不要です。

# GNOME Display Manager を止める

NVIDIA のリポジトリからのインストールでも、Ubuntu 20.04 のリポジトリからのインストールでも、ディスプレイマネージャーの GNOME Display Manager が動いてしまいます。普通のパソコンでは動くべきですが、クラウドで動かしている場合は（大きな害はないですが）無意味です。

以下のコマンドで止まります。

```
sudo systemctl set-default multi-user
sudo reboot
```

もし復活させたい場合は、以下のコマンドで復活します。

```
sudo systemctl set-default graphical
sudo reboot
```

# 後始末
```
sudo apt autoremove
sudo apt clean
```
PysimpleGUIを用いたOpenCVのカメラ画像表示


####はじめに
PysimpleGUIのデモコードをそのままコピーペーストしても動かなかったので、修正したコードを覚えとして載せておきます。

####参考　PysimpleGUIのデモコード
[Demo program that displays a webcam using OpenCV](https://github.com/PySimpleGUI/PySimpleGUI/blob/master/DemoPrograms/Demo_OpenCV_Webcam.py)

####動作環境
Windows10　64bit
Anaconda
python 3.7
OpenCV 4.2.0 (conda-forge からインストール）

####修正したコード

```python

import PySimpleGUI as sg
import cv2
import numpy as np

"""
Demo program that displays a webcam using OpenCV
"""

def main():

    sg.theme('Black')

    # define the window layout
    layout = [
            [sg.Text('Realtime movie', size=(40, 1), justification='center', font='Helvetica 20',key='-status-')],
            [sg.Image(filename='', key='image')],
            [sg.Button('Record', size=(10, 1), font='Helvetica 14'),
             sg.Button('Stop', size=(10, 1), font='Helvetica 14'),
             sg.Button('Exit', size=(10, 1), font='Helvetica 14'), ]
            ]

    # create the window and show it without the plot
    window = sg.Window('Realtime movie',
                       layout, location=(800, 400))

    # ---===--- Event LOOP Read and display frames, operate the GUI --- #
    
    recording = False

    while True:
        event, values = window.read(timeout=20)
        if event in (None, 'Exit'):
            break

        elif event == 'Record':
            window['-status-'].update("Record")
            cap = cv2.VideoCapture(0,cv2.CAP_DSHOW) #1
            # cap = cv2.VideoCapture(0)
            recording = True

        elif event == 'Stop':
            window['-status-'].update("Stop")
            recording = False
            img = np.full((480, 640), 0)
            # this is faster, shorter and needs less includes
            imgbytes = cv2.imencode('.png', img)[1].tobytes()
            window['image'].update(data=imgbytes)
            cap.release() #2
            cv2.destroyAllWindows()

        if recording:
            ret, frame = cap.read()
            if ret is True:
                imgbytes = cv2.imencode('.png', frame)[1].tobytes() 
                window['image'].update(data=imgbytes)

    window.close()

if __name__ == '__main__':
    main()

```
####修正点#1
cap = cv2.VideoCapture(0,cv2.CAP_DSHOW) #1
[ WARN:1] global ..\modules\videoio\src\cap_msmf.cpp (674) SourceReaderCB::~SourceReaderCB terminating async callback
Direct Showの設定をするとterminating async callbackのエラーは出なくなりますが、設定スピード（フレームレート）が遅くなることがあるようです。（私もフレームレートを測ってみたら30fpsから5fpsに落ちました。）
参考：
[WARN:0 terminating async callback error in cv2](https://stackoverflow.com/questions/54904259/warn0-terminating-async-callback-error-in-cv2)
[【openCV】遅いのはCAP_DSHOWだった？【Webカメラ】](https://madeinpc.blog.fc2.com/blog-entry-1361.html)

####修正点#2
不要かもしれませんが、
cap.release()
cv2.destroyAllWindows() #2
を入れてリリースしています。

####その他の修正点
・'Record'が押されたらVideoCaptureが呼ばれるように変更。
・NoneとExitが押されたらループを抜けるように変更。
ImgBurn をコマンドラインで操作する。

# ImgBurn とは
ImgBurn は、 CD / DVD / HD DVD / Blu-ray を焼くための Windows 用ツールです。実際のメディアには焼かなくても、ISO ファイルを作って複数ファイルを一纏めにするだけでも便利です。
公式サイトは[こちら](https://www.imgburn.com/)。



# (1) コマンドライン・オプションの調べ方
## (a) ImgBurn.exe と同じフォルダーにある ReadMe.txt を参照する。こちらの方が詳しい。
## (b) コマンドラインで ImgBurn /? と実行する。
※ ImgBurn.exe は %ProgramFiles(x86)%\ImgBurn\ または %ProgramFiles%\ImgBurn\ に存在。

# (2) 留意点
## (a) 一部のコマンドライン・オプションの値は、ダブルクォーテーションで括る。
```cmd.exe:cmd.exe
・正
ImgBurn.exe /VOLUMELABEL "HOGE"

・誤
ImgBurn.exe /VOLUMELABEL HOGE
```

```PowerShell:PowerShell
・正(PowerShell の例)
Start-Process -FilePath "C:\Program Files (x86)\ImgBurn\ImgBurn.exe" -ArgumentList @("/VOLUMELABEL" "`"HOGE`"") -Wait
# 勿論、ImgBurn に渡すオプションはこれだけでは足りません。
```

## (b) エラー・スキップが出来ていない。
ファイル・パスが深すぎる(フォルダ1\フォルダー2\…\フォルダーn\foo.txt とか)際にその旨を知らせるダイアログが出て動作が止まる。
今のところ回避方法(エラー時は進行をそこで止めて終了。)は不明。


# (3) PowerShell でのサンプル
・D:\WorkSpace\ 以下に、焼きたいファイル(フォルダーを含む)がフォルダー単位で纏められている。
　※例: D:\WorkSpace\FOO\ 、D:\WorkSpace\BAR\、D:\WorkSpace\HOGE\

・D:\ISO\ に .ISO ファイルを出力する。
・.ISO ファイルのラベルは、FOO、BAR、HOGE など、D:\WorkSpace\ 直下のフォルダー名が用いられる。
・.ISO のルートには、D:\WorkSpace\FOO\ 直下にあるファイル・フォルダーが置かれる。(BAR、HOGE も同様。)

```PowerShell:PowerShell
# 自分の環境に合わせて書き換える。
$cmd = "C:\Program Files (x86)\ImgBurn\ImgBurn.exe"
$SrcRootDir = "D:\WorkSpace"
$DestRootDir = "D:\ISO"


$Dirs = @(Get-ChildItem $SrcRootDir -Directory)
foreach($Dir in $Dirs)
{
    $arguments =  @(
    "/MODE"
    "BUILD"

    "/BUILDMODE"
    "IMAGEFILE"

    "/FILESYSTEM"
    "`"ISO9660 + UDF`""

    "/UDFREVISION"
    "`"1.02`"" 

    "/ROOTFOLDER"
    "NO"

    "/NOIMAGEDETAILS"

    "/CLOSE"

    "/START"
    )

    $tmpDirs = @(Get-ChildItem $Dir.FullName -Directory).FullName
    $currentSrcDir = $tmpDirs -join "|"

    $currentDstIsoFilename = "{0}.ISO" -F $Dir.Name
    $currentDstIsoFilename = Join-Path $DestRootDir $currentDstIsoFilename
    $currentLabel = $Dir.Name

    Write-host $currentSrcDir
    write-host $currentDstIsoFilename
    write-host $currentLabel
    write-host ""

    $arguments += "/SRC"
    $arguments += ("`"{0}`"" -F $currentSrcDir)

    $arguments += "/DEST"
    $arguments += ("`"{0}`"" -F $currentDstIsoFilename)
    $arguments += "/VOLUMELABEL"
    $arguments += ("`"{0}`"" -F $currentLabel)

    Start-Process -FilePath $cmd -ArgumentList $arguments -Wait
}

```
ゼロから始めるLeetCode Day56 「1480. Running Sum of 1d Array」

# 概要

海外ではエンジニアの面接においてコーディングテストというものが行われるらしく、多くの場合、特定の関数やクラスをお題に沿って実装するという物がメインである。

どうやら多くのエンジニアはその対策としてLeetCodeなるサイトで対策を行うようだ。

早い話が本場でも行われているようなコーディングテストに耐えうるようなアルゴリズム力を鍛えるサイトであり、海外のテックカンパニーでのキャリアを積みたい方にとっては避けては通れない道である。

と、仰々しく書いてみましたが、私は今のところそういった面接を受ける予定はありません。

ただ、ITエンジニアとして人並みのアルゴリズム力くらいは持っておいた方がいいだろうということで不定期に問題を解いてその時に考えたやり方をメモ的に書いていこうかと思います。

[Leetcode](https://leetcode.com/)

Python3で解いています。

[ゼロから始めるLeetCode 目次](https://qiita.com/KueharX/items/6ee2502c3b620c795b70)

前回
[ゼロから始めるLeetCode Day55「22. Generate Parentheses」](https://qiita.com/KueharX/items/45a1e18607a0f4e8094e)

今はTop 100 Liked QuestionsのMediumを優先的に解いています。
Easyは全て解いたので気になる方は目次の方へどうぞ。

[Twitter](https://twitter.com/kueharx)やってます。

# 問題
[1480. Running Sum of 1d Array](https://leetcode.com/problems/running-sum-of-1d-array/)

難易度はEasy。
問題としては配列`nums`が与えられます。全ての数を足した数をリストで返してください、という問題です。

>Input: nums = [1,2,3,4]
Output: [1,3,6,10]
Explanation: Running sum is obtained as follows: [1, 1+2, 1+2+3, 1+2+3+4].
Example 2:

>Input: nums = [1,1,1,1,1]
Output: [1,2,3,4,5]
Explanation: Running sum is obtained as follows: [1, 1+1, 1+1+1, 1+1+1+1, 1+1+1+1+1].
Example 3:

>Input: nums = [3,1,2,10,1]
Output: [3,4,6,16,17]
 

>Constraints:

>1 <= nums.length <= 1000
-10^6 <= nums[i] <= 10^6

# 解法

いわゆる累積和の問題ですね。
この問題自体は理解しやすいのでどういったやり方で実装するのか、というところが重要であると思います。

実装についてはPythonの関数に詳しいかどうかで書き方が変わってくると思います。

例えば、[itertools.accumulate](https://docs.python.org/ja/3/library/itertools.html#itertools.accumulate)を知っているならば以下のように書けます。

```Python
class Solution:
    def runningSum(self, nums: List[int]) -> List[int]:
        return itertools.accumulate(nums)
# Runtime: 60 ms, faster than 33.33% of Python3 online submissions for Running Sum of 1d Array.
# Memory Usage: 14.1 MB, less than 33.33% of Python3 online submissions for Running Sum of 1d Array.
```

超簡潔に書けるので知っている、もしくは自由にドキュメントなどを調べられるような環境であればこちらを使えば良いでしょう。

しかし、忘れていた場合にゼロから考える場合にはどう書くのか、ということも念頭に置いておかなければなりません。

累積和についての考え方はけんちょんさんの

[累積和を何も考えずに書けるようにする！](https://qiita.com/drken/items/56a6b68edef8fc605821)

がとても読みやすくて理解がしやすいと思います。
読んでいて知ったのですが、AtCoaderなどでも累積和は応用範囲が広いんですね・・・

```Python
class Solution:
    def runningSum(self, nums: List[int]) -> List[int]:
        i = 1
        while i<len(nums):
            nums[i] += nums[i-1]
            i += 1
        return nums
# Runtime: 44 ms, faster than 33.33% of Python3 online submissions for Running Sum of 1d Array.
# Memory Usage: 13.8 MB, less than 100.00% of Python3 online submissions for Running Sum of 1d Array.
```

今回はこのように書きました。

基本的な部分なのでこれくらいなら瞬殺できるくらいにしたいですね。

今回はここまで。お疲れ様でした。
Mac <=> Windows 間の文字コード問題


# 各OSの文字コード（encoding）

Windows: **shift-jis**
Mac: **utf-8**



# 対策

### Mac で sjisのzipファイルを解凍

unar というパッケージを使う。
`unar <zip file> -e sjis`


### Mac でsjisのzipファイルを作成（圧縮）

ZIPANG というアプリを使う。
ドラッグ & ドロップするだけ。

[ZIPANG のApple Store ページ](https://apps.apple.com/jp/app/zipang-zip-archive-next-generation/id882655968?mt=12)
Dockerを使うなら抑えておくべきコマンドたち

# 背景
Dockerを導入すると、いつもとはコマンドのやり方が違うものがいくつかあるので、よく使うコマンドを紹介します！これだけ抑えておけば基本的には開発を進めていけると思います。

## 抑えるべきコマンド

#### create
構築されたサービスを参考にそのコンテナを作ります。ここで作られたコンテナはまだ起動していないです。

```
$ docker-compose create
```

#### down
docker-compose.ymlに書かれているサービスを参考にコンテナを停止し、そのコンテナとネットワークを削除します。
オプションで--rmi allをつけることでイメージも削除してくれます。

```
$ docker-compose down
```

#### build
サービスをビルドします。
サービス名を指定してビルドすることもできます。
「--no-cache」等も指定できます。

```ruby

$ sudo docker-compose build

#サービスを指定してビルド
$ sudo docker-compose build nginx
```

#### up
コンテナを作成して、起動させます。オプションで-dをつけることでバックグラウンドで実行することができます。
またオプションで--buildをつけることで起動前にイメージも構築します。
(control + cで停止できます)

```
$ docker-compose up
```

#### start
サービスを開始します。これは既にコンテナがある状態でなければ実行できません。

```
$ docker-compose start
```

#### stop
サービスを停止します。

```
$ docker-compose stop
```

#### restart
コンテナを再起動させる。

```
$ docker-compose restart
```

#### rm
停止中のコンテナを削除します。デフォルトだと[y/N]の確認があるが、-fオプションをつけることで、確認無しでコンテナを削除します。

```
$ docker-compose rm 
```

#### ps
コンテナの一覧を表示します。

```
$ docker ps
```

#### kill
コンテナを強制停止します。

```
$ docker-compose kill
```

#### help
コマンドの一覧を表示します。わからなくなったらこちらを確認してください。

```
$ docker-compose help
```

#### コントローラー作成
いつものやり方に「docker-compose run web」を前頭に置く。

```
$ docker-compose run web rails g controller posts
```

#### モデル作成
コントローラーと同様。

```
$ docker-compose run web rails g model post

$ docker-compose run web rails db:migrate
```

#### bundle install
なぜかbundle installができない！そんな時に、、

```
docker-compose build --no-cache
```

## 最後に
これだけを覚えればとりあえずはある程度は開発をスムーズに進めていけると思います。
細かい部分ではまだ足りないところはあるとは思いますが、とりあえずDocker初心者の方は上記のコマンドから使えるようにしていきましょう！！
fuego test systemをインストールする

# 目的
fuego test systemをインストールする手順を記載します。

以下を参考
>[Fuego wiki](http://fuegotest.org/wiki/FrontPage)
>[Installing_Fuego](http://fuegotest.org/wiki/Installing_Fuego)

# fuegoとは

> [http://fuegotest.org/](http://fuegotest.org/)
> fuego test system
> Fuegoは、組み込みLinuxテストに特化して設計されたテストシステムです。テスト実行の主要な方法として、ホストシステムからの組込みターゲットの自動テストをサポートしています。

# 環境

Ubuntu16.04

```
# uname -a
Linux ubuntu 4.4.0-179-generic #209-Ubuntu SMP Fri Apr 24 17:48:44 UTC 2020 x86_64 GNU/Linux
# cat /proc/version
Linux version 4.4.0-179-generic (buildd@lcy01-amd64-014) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.12) ) #209-Ubuntu SMP Fri Apr 24 17:48:44 UTC 2020
# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 9 (stretch)"
NAME="Debian GNU/Linux"
VERSION_ID="9"
VERSION="9 (stretch)"
VERSION_CODENAME=stretch
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
```

# fuego のインストール

dockerをインストール

```
sudo apt install -y git docker.io
```

fuegoダウンロード／ビルド／起動を以下ステップで行う。

```
git clone https://bitbucket.org/fuegotest/fuego.git
cd fuego
./install.sh
./start.sh
firefox http://localhost:8090/fuego
```

ブラウザからJenkinsUIへアクセスできればOK
![Screenshot from 2020-06-08 01-00-57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/344880/12f9f08a-01fd-7c23-dce1-0db443b617f0.png)

# fuego git repositoty
[https://bitbucket.org/fuegotest/fuego/src/master/](https://bitbucket.org/fuegotest/fuego/src/master/)

# その他、Tips

[Using Fuego with AGL](http://fuegotest.org/wiki/Using_Fuego_with_AGL)
[Raspberry Pi Fuego Setup](http://fuegotest.org/wiki/Raspberry_Pi_Fuego_Setup#Make_a_test_directory)
[http://fuegotest.org/wiki/Using_Fuego_with_LAVA](http://fuegotest.org/wiki/Using_Fuego_with_LAVA)

# Ubuntuでのスクリーンショットの撮り方
PrintScreen　をクリックすると画面全体を撮れるが、
Shift+PrintScreen　をクリックすると画面を選択してスクリーンショットを撮れる。

# 参考
[agl-testframework](https://wiki.automotivelinux.org/agl-testframework)
[Fuego wiki](http://fuegotest.org/wiki/FrontPage)
[Installing_Fuego](http://fuegotest.org/wiki/Installing_Fuego)
[http://fuegotest.org/](http://fuegotest.org/)
[Fuego Quickstart Guide](http://fuegotest.org/fuego/Fuego_Quickstart_Guide)
[AGL API Reference/Test Framework](https://docs.automotivelinux.org/docs/en/master/apis_services)
[https://bitbucket.org/fuegotest/fuego/src/master/](https://bitbucket.org/fuegotest/fuego/src/master/)
MAMP環境でxdebugを有効化する手順

`xdebug`とは、PHPのデバッグ機能を拡張してくれるツールです。

MAMPで`xdebug`を使えるようにする手順メモとして残しています。

## 1.php.iniを編集
php.iniを開きます。
MAMPのパスは、`MAMP/bin/php/php7.4.2/conf/php.ini`のようになっています。

```
[xdebug]
zend_extension="/Applications/MAMP/bin/php/php7.4.2/lib/php/extensions/no-debug-non-zts-20190902/xdebug.so"
xdebug.remote_enable=1
xdebug.remote_autostart=1
```

xdebugの`zend_extension=...`がコメントアウトされているので解除して、下の二行を記述します。

## 2.MAMPを再起動
MAMPのStop Serversで一旦切って、再起動します。
![Screen Shot 0032-06-14 at 14.12.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482880/a2d4ef4d-8668-8bec-a903-b57d81e34714.png)

## 3.TOOLSで確認
MAMPのOpen WebStart pageから、TOOLS→PHPINFOを確認します。
![Screen Shot 0032-06-14 at 14.13.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482880/14a295ae-0742-7510-fafe-2237a83ee119.png)

`xdebug`が表示されていればOKです。

![Screen Shot 0032-06-14 at 14.03.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482880/408b154e-39f9-610b-7ca5-7a4e53d490d4.png)
iOSエンジニアが読んだら、ためになりそうな本

# はじめに

Web系のおすすめ本は結構見つかるのですが、 `iOSエンジニア` という枠ではあまり見かけなかったので、思いつくままにリストアップしてみました。他にも良い本がたくさんあると思いますが、まずは個人的に（あるいは世間の評価が高い）おすすめのものをあげてみます。

このリストはビギナー向けではありません。すでにiOSエンジニアと呼ばれている方を対象にしています。（別に読んじゃダメといっているわけではないので悪しからず）

ざっくり`アソシエート`と`プロフェッショナル`に分類はしています。定義はあいまいです。`アソシエート`側を先に読んだ方が良いかな、程度に思ってください。

表中で `↑は同じ分野`を`←は同じくためになりそう`を示しています。

# 読んだら、ためになりそうな本

||アソシエート|プロフェショナル|
|---|---|---|
|基礎|[プログラムはなぜ動くのか](https://www.amazon.co.jp/dp/B00HRN7VK0)||
|↑|[コンピュータはなぜ動くのか](https://www.amazon.co.jp/dp/B00GSHI02Y)||
|↑|[ネットワークはなぜつながるのか](https://www.amazon.co.jp/dp/B077XSB8BS)||
|Swift/iOS|[詳解 Swift 第5版](https://www.amazon.co.jp/dp/B081GK7636)|←|
|↑|[［増補改訂第3版］Swift実践入門](https://www.amazon.co.jp/dp/B086VVQ3DJ)|←|
|↑||[SwiftUI 徹底入門](https://www.amazon.co.jp/dp/4815604061/)|
|↑|[よくわかるAuto Layout](https://www.amazon.co.jp/dp/4865940324)|←|
|OOD/OOP|[オブジェクト指向でなぜつくるのか](https://www.amazon.co.jp/dp/4822284654)||
|↑||[オブジェクト指向のこころ](https://www.amazon.co.jp/dp/4621066048)|
|UML|[かんたん UML入門](https://www.amazon.co.jp/dp/B073NX8K1L)||
|↑|[UMLモデリング入門](https://www.amazon.co.jp/dp/B00EH93MR8)|←|
|↑||[UMLモデリングの本質](https://www.amazon.co.jp/dp/4822283585)|
|設計|[iOSアプリ設計パターン入門](https://peaks.cc/books/iOS_architecture)||
|↑||[Clean Architecture](https://www.amazon.co.jp/dp/4048930656)|
|プログラミング|[リーダブルコード](https://www.amazon.co.jp/dp/4873115655)|←|
|リファクタリング||[レガシーコード改善ガイド](https://www.amazon.co.jp/dp/B01AN97W08)|
|↑||[レガシーコードからの脱却](https://www.amazon.co.jp/dp/4873118867)|
|テスト|[iOSテスト全書](https://peaks.cc/books/iOS_testing)|←|
|↑|[iOSアプリ開発自動テストの教科書](https://www.amazon.co.jp/dp/4297106299)|←|
|TDD（テスト駆動開発）|[テスト駆動開発]()|←|
|DDD（ドメイン駆動開発）|[ドメイン駆動設計入門](https://www.amazon.co.jp/dp/B082WXZVPC/)|←|
|↑||[エリック・エヴァンスのドメイン駆動設計](https://www.amazon.co.jp/dp/B00GRKD6XU)|
|デザインパターン|[Head Firstデザインパターン](https://www.amazon.co.jp/dp/4873112494)|←|
|↑|[増補改訂版 Java言語で学ぶデザインパターン入門](https://www.amazon.co.jp/dp/B00I8ATHGW)|←|
|アジャイル|[カイゼン・ジャーニー](https://www.amazon.co.jp/dp/B078HZKLMB)|←|
|↑|[SCRUM BOOT CAMP THE BOOK](https://www.amazon.co.jp/dp/B086GBXRN6)|←|
|↑|[アジャイルサムライ](https://www.amazon.co.jp/dp/4274068560)|←|
|全般||[エンジニアリング組織論への招待](https://www.amazon.co.jp/dp/B079TLW41L)|
|↑|[達人プログラマー 職人から名匠への道](https://www.amazon.co.jp/dp/B06W567M44)|←|

# よゆうがあれば、読んだら、ためになりそうな本

||アソシエート|プロフェショナル|
|---|---|---|
|GitHub|[GitHub実践入門](https://www.amazon.co.jp/dp/B07JLJSDMJ)|←|
|UNIX||[UNIXという考え方](https://www.amazon.co.jp/dp/4274064069)|
|Web|[Webを支える技術](https://www.amazon.co.jp/dp/4774142042)|←|
|デザイン|[ノンデザイナーズ・デザインブック](https://www.amazon.co.jp/dp/B01LW1BC2L)|←|
|↑||[誰のためのデザイン](https://www.amazon.co.jp/dp/4788514346)|
|全般||[Code Complete 第2版 上](https://www.amazon.co.jp/dp/489100455X)|
|↑||[CODE Complete 第2版 下](https://www.amazon.co.jp/dp/4891004568)|
[Scratch3.0拡張機能] Scratch Linkのインストール  

この記事は Scratch3.0 の拡張機能を使ってみたい人のための記事です。

#1.Scratch3.0の拡張機能とは
専用のブロックを追加して、特殊な操作ができるようにした機能のことです。

#2.Scratch Linkとは
ev3などのデバイスとスクラッチをつなげるためのソフトウェアです。

拡張機能のうち以下のものを使いたい場合に必要です。

①　**micro:bit**
②　**LEGO MINDSTORMS EV3**
③　**LEGO BOOST**
④　**LEGO Education WeDo 2.0**
⑤　**Go Direct Force & Acceleration**

#4.Scratch Linkのインストール方法
　
####①スクラッチリンクの[ダウンロードページ](https://scratch.mit.edu/ev3)にアクセスする。
　　

####②OSを選択する
自分の使っているOSを選んでください！![スクリーンショット 2020-06-14 12.51.01のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654004/0ac9889f-0b1d-0a68-e99f-964615e5d8f5.png)
####③"直接ダウンロード"を選択する(今回はこの方法にします)![スクリーンショット 2020-06-14 12.51.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654004/36664a95-5c2d-b99b-5e2e-d0c4ec203f55.png)
####④zipファイルを展開して、誘導に従いインストール

#5.Scratch Linkの使用方法
Scratch Link.app をダブルクリックするだけです。
動作しているかはツールバーを確認すれば判別できます。

#6.エラーの対処
WindowsでScratch Linkを使おうとすると、英語で
**"ポートが占有されています"**
**"スクラッチリンクはすでに起動しています"**
のようなエラーメッセージが表示されることがあります。

この場合はどちらも**再起動すれば解決**するので、再起動してみてください！

#7.参考記事リンク
◯[Scratch-wiki](https://en.scratch-wiki.info/wiki/Scratch_Link)
　






#最後に
読んでいただきありがとうございます！
より良い記事をつくっていきたいと思いますので

◯こうした方がわかりやすい
◯ここがわかりにくい
◯ここが間違っている
◯ここをもっと説明して欲しい

などの御意見、御指摘お待ちしております。
何卒よろしくお願い致します。
Visual Studio CodeでMarkdown記事書き方 

# Visual Studio CodeでMarkdown記事の書き方
今回の記事でVSCodeを利用してMarkdown記事の書き方について説明します。
手順は以下の通りです。

## １、MDファイル作成
VSCodeを開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148710/f3888016-0f22-1f44-e9f2-63ab5a3f878b.png)
ファイル -> 新規ファイルで新規ファイルを作成する
ショートカットキー：Ctrl+N　
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148710/e58907da-5d98-980c-59b2-b2d7581b96e5.png)
言語を選択ー＞`mar`と入力してMarkdownを選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148710/86d15394-51e1-4ff8-c834-c9d9f83914fc.png)

右下の「プレーンテキスト」は`Markdown`になっていれば成功
Markdownファイルの拡張子は*.md
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148710/33a6b59b-6417-9fd7-2f0a-ecf278e822cb.png)

## ２、Markdown記述方法
Markdownの記述方法については[Markdown記法 チートシート](https://qiita.com/Qiita/items/c686397e4a0f4f11683d)を参照してください。
## ３、プレビュー方法
拡張機能Markdown Preview Enhancedをインストール
ショートカットキー`Ctril + Shift + x` で拡張機能検索Windowを開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148710/e61379ad-4edb-58d4-f598-67f313deeb1e.png)
`Markdown Preview Enhanced`って入力 -> 選択 -> インストール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148710/c843e94d-5a8b-aeb2-8a52-ce18405fa437.png)

インストール完了したら`Ctrl+K -> V`の順番で操作する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148710/b2b417be-a6d4-9225-b7e9-1920b4576182.png)

プレビューできていますよね、これで完了。