OmniAICreator/Qiita-1.07M huggingface dataset:
web初心者がNetlify-cli使って静的サイトをデプロイしてみた


# TOC

- [netlifyとは](#Netlifyとは)
- [netlifyに登録する](#netlifyに登録する)
- [netlify-cli](#netlify-cli)
  - [netlify-cliをインストールする](#netlify-cliをインストールする)
  - [netlify-cliでログイン](#netlify-cliでログイン)
  - [プロジェクトをdraftとしてデプロイ](#プロジェクトをdraftとしてデプロイ)
  - [プロジェクトを本番用にデプロイ](#プロジェクトを本番用にデプロイ)

# Netlifyとは


| One workflow.
| From local development
| to global deployment.
| Netlify is everything you need to build fast, modern websites: continuous deployment, serverless functions, and so much more.
|
| -- netlify.com

[Netlify](https://www.netlify.com)とは、 *手軽に静的なサイトをデプロイできるサービス*です

- カスタムドメイン追加
- Let's Encryptを使用したHTTPS対応
- 自動デプロイ
- Github/Bitbucket/Gitlab等からのデプロイ
- *無料から使用可能*
- *公式のCLIツールが存在*


web系疎いけど、神か。

CLIツールがあるので、CLIに住んでいる私のような人にもおすすめです。

# netlifyに登録する

- Github
- Gitlab
- Bitbucket
- Email

のいづれかで登録できます。
自分はGithubで登録しましたがワンクリックなので楽です。

# netlify-cli

Netlifyには公式のツールとして[netlify/cli](https://github.com/netlify/cli)があり、これを使ってサイト登録・デプロイ等を行うことができます。

## netlify-cliをインストール

npmでインストールします

```bash
$ npm i netlify-cli -g
```

複数人での開発の場合は、`package.json`に記載した方が良いらしいです。
(該当しないので試していないですが)


## netlify-cliでログイン

```bash
$ netlify login
```

ブラウザが開き、連携の確認画面が出ます。
許可すればOAuthトークンを取得し、ログインに成功します。

## プロジェクトを登録

```bash
$ netlify init
```

デプロイしたいディレクトリで実行すると、プロンプト形式で必要事項を入力してNetlifyに登録できます。

```
<X_X>:cj-bc.github.io$ netlify  init
Logging into your Netlify account...
Opening https://app.netlify.com/authorize...

You are now logged into your Netlify account!

Run netlify status for account details

To see all available commands run: netlify help

? What would you like to do? +  Create & configure a new site
Choose a site name or leave blank for a random name. You can update later.
? Site name (optional): Cj-bc
? Team: Cj-bc's team

Site Created

Admin URL: ...
URL:       https://Cj-bc.netlify.com
Site ID:   ...
? Your GitHub username: Cj-bc
? Your GitHub password:
```

最後にGithubのユーザー名とパスワードを聞かれていますが、無視しても一応大丈夫でした。なんだったんだ...
(Githubのレポジトリとの連携ができていなかったので、おそらくそれな気がする)


## プロジェクトをdraftとしてデプロイ

```
$ netlify deploy
```

最低限だと、これだけでデプロイされます。
但しあくまでもDraftとしてデプロイがされるため、本番のURLとは異なったURLにデプロイされます。

(但しあまり挙動を理解していません、とりあえず`deploy path`にある`index.html`が表示されるようになりました。)

```
<X_X>:cj-bc.github.io$ netlify deploy
Please provide a deploy path relative to:
/Users/Cj-bc/.ghq/github.com/Cj-bc/cj-bc.github.io
? deploy path /Users/Cj-bc/.ghq/github.com/Cj-bc/cj-bc.github.io
Deploy path: /Users/Cj-bc/.ghq/github.com/Cj-bc/cj-bc.github.io
Deploying to draft URL...
✔ Finished hashing 44 files
✔ CDN requesting 31 files
✔ Finished uploading 31 assets
✔ Draft deploy is live!

Logs:           https://app.netlify.com/sites/cj-bc-homepage/deploys/...
Live Draft URL: https://nnnnnnnnnnnnnnnnnnnnnnnn--cj-bc-homepage.netlify.com

If everything looks good on your draft URL, take it live with the --prod flag.
netlify deploy --prod

```


`Live Draft URL`にアクセスすると、実際にデプロイされたページを見ることができます。


## プロジェクトを本番用にデプロイ

```
$ netlify deploy --prod
```

`--prod`オプションを追加することで、本番用として事前に登録したURLにデプロイされます。
再帰的にリンクを辿って画像スクレイピング

beautiful soupを使って、urlから画像のスクレイピングをしてみた。
収集元は[乃木坂まとめ](http://nogizaka46matomenoma.blog.jp/)(http://nogizaka46matomenoma.blog.jp/)

beutiful soupは結構わかりにくいところなどもあったが、一応できた。

ただ、再帰的にやると同じ画像が多くなる。これを解決する方法あったら誰か教えてください。


```python

from urllib.request import urlopen
from bs4 import BeautifulSoup
import requests


def get_link (url):
    html = urlopen(url)
    soup = BeautifulSoup(html, 'lxml')
    link_list = []
    for i in soup.find_all('a'):
        link = i.get('href')
        if type(link) is str:
            if 'http' in link:
    # javascriptの何か？が混ざっている。よくわからないからtype＝strとif ~ in で絞る。
                link_list.append(link)
    return link_list


def link_to_img(url):
    html = urlopen(url)
    soup = BeautifulSoup(html, 'lxml')
    img_list = []
    for i in soup.find_all('img'):
        link = i.get('src')
        img_list.append(link)
    return img_list


url = "http://nogizaka46matomenoma.blog.jp/"

img_name_list = []
for img in img_list:
    try:
        re = requests.get(img)
        if len(img.split('/')[-1]) > 20:
            img_name = img.split('/')[-1][-20:]
        else :
            img_name = img.split('/')[-1]
            with open('./' + img.split('/')[-1], 'wb') as f: # img_listフォルダに格納
                f.write(re.content)
            img_name_list.append(img_name)
    except:
        pass
    

big_pic_list = []
for i in range(len(img_name_list)):
    try:
        pic = Image.open(img_name_list[i])
        if pic.size[0] > 400 and pic.size[1] > 400:
            big_pic_list.append(pic)
    # 　高さ、幅それぞれ500以上のものだけをリストにする。
    except:
        pass
```


![nanamin2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275145/efd5fb52-2bf3-10a6-8c09-203177dac24a.png)


100枚くらい集まった。
【WordPress】猿にでもできる脆弱性チェック

- [WordPress\(ワードプレス\)脆弱性診断 セキュリティースキャナ \| ワードプレスドクター](https://wp-doctor.jp/blog/wordpress%E3%83%AF%E3%83%BC%E3%83%89%E3%83%97%E3%83%AC%E3%82%B9%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E3%83%BC%E3%82%B9%E3%82%AD%E3%83%A3%E3%83%8A%E3%83%BC/)
    - 日本語
    - URLを入力するだけ
    - プラグイン不要

[WPScan](https://www.google.co.jp/search?q=WPScan&ie=utf-8&newwindow=1&tbs=qdr%3Ay2)とかよく分からないという人でも、流石にこれならできる筈。[^1]

[^1]: データベースの更新頻度がかなり低いようですし、オススメのサービスとは言い難いですが、やらないよりは遥かにマシかと…。残念ながら、情報商材などに騙されて、訳も分からず WordPress を運用している人に、小難しい話をしても無駄だと思います。

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

## 迷惑です

WordPress は、非常に攻撃対象になりやすい CMS ですので、**セキュリティ意識の低い人は、今すぐ使うのを止めてサイトを閉鎖して欲しい**なと思います。

Qiita をご覧になるような方は大丈夫だと思いますが、もし身の回りに「WordPress のセキュリティ？何それ美味いの？」という人がいたら、自分が被害に遭うだけではなく、他人にまで迷惑をかける事も多々あるという事を、よ～く教えてあげてください。

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

### 経緯

1. 息抜きに Web サーバのエラーログを何となく眺める

2. 相変わらず WordPress への攻撃を試みるリクエストがたくさんあるなぁ…

3. あれ？この攻撃元の IP は…たぶん○○の VPS だ… うちもお世話になってるところなのに、けしからんなぁ… 誰がやってるんだ…

4. あぁこれ、WordPress が改ざんされて踏み台にされてるよ… WordPress のバージョン丸見え… って 4.4.1！(驚愕)

5. 同じサーバーで運営してる別のドメインも改ざんされてるよ… こっちは 4.5.3 …(呆れ)

6. 知識があまり無い人・セキュリティ意識の低い人でも、簡単に使えるサービスはないかと探してみる（今ココ）

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

### 同様の攻撃が急増中

私が管理しているサーバーだけかもしれませんが、ここ最近、上記と同様の攻撃が急増しています。以下はホンの一例ですが…

- https://cleantalk.org/blacklists/45.77.227.19
- https://cleantalk.org/blacklists/54.39.28.145
- https://cleantalk.org/blacklists/188.226.133.180

改ざん被害を受けた WordPress を経由して…

- `wp-admin/admin-ajax.php?Action=EWD_UFAQ_UpdateOptions`
- `wp-admin/admin-ajax.php?action=update_zb_fbc_code`

…のような、脆弱性のあるプラグインかテーマファイルを狙っているっぽいリクエストが送られてきます。

以下のような資料にもある通り、`admin-ajax.php` はその性質上、攻撃対象になりやすいファイルですので、ご注意ください。

- https://www.ffri.jp/assets/files/monthly_research/MR201504_Web_defacing_Attacks_targeting_WordPress_JPN.pdf
rails モデルについて

##modelの作成

```
$ rails g model モデル名
```

上記をを実行するとマイグレーションファイルが作成される。　　
これを使うことでSQL文を書かずして、railsからmysqlなどのデータベースを操作することができる。作成するだけでは操作できない。　　
##マイグレーションファイルの実行

```
$ rails db:migrate
```
このコマンドでデータベースにモデル名のテーブルが作成される。
railsのルールとして一度実行されたファイルに変更をしてはならない。　　
データベースに変更を加えたい場合、rails db:migrate:resetでもう一度作り直すかカラムを追加する方法がある。

##カラムの追加

```
$ rails g migration Addカラム名Toテーブル名
```
テーブル名はモデル名の小文字複数形だが、上記ではキャメルケース記法なので大文字になる。
rails aborted! I18n::MissingTranslationData: translation missing: en.faker.name.first_name

##rails aborted!I18n::MissingTranslationData: translation missing: en.faker.name.first_name

`bundle exec rails db:reset`しようとしたら、上記のエラーがでた

##解決方法
下記をコピペ＊日本語での設定とかそこらへん

```locale.rb
require 'i18n'
I18n.locale # => :en
I18n.locale = :ja
I18n.locale # => :ja
require 'faker'
Faker::Config.locale # => :ja
Faker::Internet.email # => ".@.com"

```

で

```
$ bundle exec rails db:reset
```
【Python3.6】電話番号の正規表現を書いてみた

# 実装

Pythonで書いてみました。
「()」付きや「-」付きの場合も対応しました。

```

import re

pattern = r'''(
    (\d{3,4}|\(\d{3,4}\))
    (-)?
    (\d{4})
    (-)?
    (\d{4})
)'''
phone_regex = re.compile(pattern, re.VERBOSE)
text = "(090)12345678"
match = phone_regex.search(text)
if match is not None:
    print("電話番号です")
else:
    print("電話番号じゃありません")

```
FIDOとは何なのか？

# 最近FIDOが熱いらしい
社内のセキュリティをどうするか考えていたところ、
最近FIDOによるパスワードレス認証が盛り上がっているということを知りました。
[FIDO Alliance](https://fidoalliance.org)の公式ページを見ると、
Google、Amazon、FaceBook辺りの企業が最上位のBoard Level Membersになっており、
[Wikipedia](https://ja.wikipedia.org/wiki/FIDO_(認証技術)#cite_note-富士通-2)の`業界標準になるとみられている`という記述もかなり信頼性が高そうです。

## FIDOとは？
FIDOはクライアントサイドに秘密鍵を保存し、その利用に生体認証や物理トークンを要求する認証方式です。
この2段構えによって、従来の認証方式に比べて手軽かつ堅牢な認証を行うことができます。

### 他の認証方式との比較
上記の説明だけではわかりにくいので、
実際に従来の認証方式とその欠点を見ながらFIDOの長所を見ていこうと思います。

#### パスワード認証
最も普及している認証方式ですが、以下のような問題があります。

##### パスワードが短いと総当たり攻撃や辞書攻撃で簡単に突破されてしまう
[総当たり攻撃](https://ja.wikipedia.org/wiki/総当たり攻撃)に関してはサーバー側の実装である程度対策が可能ですが、
あまりに脆弱なパスワードを使っている場合、[辞書攻撃](https://ja.wikipedia.org/wiki/辞書攻撃)で少ない回数で突破される可能性があります。

また、これらを防ぐためにパスワードポリシを厳しくすると、今度は利用者側が忘れる問題が頻発するようになります。

##### パスワードの使いまわしによって、連鎖的に侵入される可能性がある
パスワードが保存されているサーバーがクラッキングを受けると、
同じメールアドレス、ユーザー名とパスワードを流用しているサービスに連鎖的に侵入されてしまいます。

普通はこれを防ぐためにパスワードを平文で保存せずハッシュ関数をかけるなどして復元できない状態で保存するものですが、
[FaceBookがやらかしていた](https://jp.techcrunch.com/2019/03/22/2019-03-21-facebook-plaintext-passwords/)記事が最近出ていましたし、
世間のシステムが皆しっかり守っていてくれると期待するのは依然として楽観的過ぎるようです。

##### フィッシングや中間者攻撃によって情報を奪われる可能性がある
サービス提供者側がどれだけ注意して守っていても、
ユーザー側がフィッシングに引っかかるなどして、パスワードとID自体を知られてしまうと、
正面から突破されてしまいます。

#### 多要素認証
これらの問題に対応するために、多要素認証が考案されました。
通常のID/パスワードの他にワンタイムパスワードなど別の要素を要求する方式です。

パスワードやIDだけでは認証が完了しないため、
前述の総当たり/辞書攻撃やパスワード使いまわしによる侵入を防ぐことができます。

##### フィッシング対策は不十分
とはいえ、フィッシングによって通常のパスワード/IDに加えてワンタイムパスワードまで盗み取られた場合は侵入されてしまいます。
ワンタイムパスワードの有効時間が短いとは言え、人が入力する都合上数十秒はあります。
これだけあれば、悪意ある侵入者にとっては十分です。
認証に必要な情報を、有効期限付きとはいえ流用可能な形で送信している限り
フィッシングによる侵入は防ぐことができません。

##### デバイスごと奪われても厳しい
PCやスマートフォンと言ったデバイス自体が盗難にあった場合などには
多要素すべてを握られてしまうことになるので、防御が不十分になります。

#### FIDO
多要素認証の欠点を、公開鍵暗号方式と生体認証や物理トークンによって解消したものがFIDOです。

##### 公開鍵暗号方式
FIDOでは秘密鍵をクライアント側に置いた公開鍵暗号方式が前提となっています。
サーバー側がクライアント側に対し、ランダムな文字列を送り、
クライアント側が秘密鍵によってそれに署名することで認証を行います。
秘密鍵で署名した情報を奪っても、元となる秘密鍵は復元できないため、
フィッシングによって情報を偽装サーバーに送らせても、
その情報を用いて真正サーバーにアクセスすることはできません。

##### 生体認証や物理デバイスによる秘密鍵の保護
FIDOに利用する秘密鍵は、生体認証(UAF規格)や物理デバイス(U2F規格)によって保護されます。
特に生体認証の場合はデバイスごと盗まれた場合でも侵入されることはないため、非常に安全性が高いです。
(このため、パスワードとの二段階認証も求められておらず、パスワードレス認証が可能です)


## まとめ
* FIDOは従来の認証方式の弱点を補ったもの。
* UAF規格の場合はパスワードレス認証が出来る

jsから利用するAPIのWebAuthnもありますし、今後触る機会は増えそうですね。
【PHP】Google検索結果URLをサクっと生成する

## コード

```php
$queryAry = [
    'q' => 'サンプル',     // 検索ワード
    'ie' => 'utf-8',       // 検索ワードの文字コード(念の為指定)
    'newwindow' => '1',    // 検索結果へ飛ぶ際に新しいウインドウを開く
    'tbs' => 'qdr:y2',     // 期間指定(とりあえず2年)
];

//-- 指定しないパラメータは削除
$queryAry = array_filter($queryAry, 'strlen');

//-- 生成したURLを出力
echo 'https://www.google.co.jp/search?', http_build_query($queryAry, '', '&');
```

### 実行結果

- https://www.google.co.jp/search?q=%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB&ie=utf-8&newwindow=1&tbs=qdr%3Ay2

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

Qiita 等に Google の検索結果 URL を載せる際、少しでも面倒だなと思ったら、数十秒でスッキリ＆サクッと書けるのが、PHP の良いところですね。

※今回のようなコードは、ウェブブラウザから実行結果を見るのではなく、CLI 版の PHP から実行結果を見る事を想定しています。

- [PHP マニュアル：コマンドラインの使用法](https://php.net/manual/ja/features.commandline.php)
- [PHP・Ruby・Perl等のスクリプト言語をサクっと書いてサクっと実行\(EmEditor編\)](https://qiita.com/fallout/items/0d4f221e176d6521091f)
[terraform] AWSのクレデンシャル情報を思った通りに変更できない場合の対処法

terraformでAWSインフラを構築する際は、```aws configure```でAccess KeyとSecret Access Keyを設定し使用しますが、それだとエラーになる場合があるので、その場合の対処法を備忘録がてら記載します。

解決法が記載されたページ：
https://github.com/hashicorp/terraform/issues/18801

つまり、ホストの環境変数にAccess KeyとSecret Access Keyが設定されている場合、terraformではそちらを使用してしまいます。

```
$ printencv
AWS_ACCESS_KEY_ID=oooooooo
AWS_SECRET_ACCESS_KEY=xxxxxxxxxx
```

上記のように環境変数が設定されている場合は、terraform側でどんなに頑張ってもawsのクレデンシャル情報を変更できないので、注意してください。

この場合は、
・環境変数に設定されたキーを変更する
・環境変数のキーを削除してterraform側のクレデンシャル情報を使用する
のいずれかで対処してください。
Visual Studioの謎のDockerfile

```
FROM mcr.microsoft.com/dotnet/core/runtime:2.2-stretch-slim AS base
WORKDIR /app


FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS build
WORKDIR /src
COPY ["hoge-server/hoge-server.csproj", "hoge-server/"]
RUN dotnet restore "hoge-server/hoge-server.csproj"
COPY . .
WORKDIR "/src/hoge-server"
RUN dotnet build "hoge-server.csproj" -c Release -o /app

FROM build AS publish
RUN dotnet publish "hoge-server.csproj" -c Release -o /app

FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "hoge-server.dll"]
```

　こんなファイルなんですけど、これを普通にたたくとバグるんですよね。
  
```
Step 7/17 : COPY ["hoge-server/hoge-server.csproj", "hoge-server/"]
ERROR: Service 'hoge-server' failed to build: COPY failed: stat /var/lib/docker/tmp/docker-builder655807069/hoge-server/hoge-server.csproj: no such file or directory
```
  
  
あたりまえだけどファイルの指定位置がおかしい。Dockerfileがhoge-serverディレクトリの中にあるのに、hoge-serverディレクトリの中を見に行くみたいなことになってるんですよね。一旦上のディレクトリにDockerfileを持ち上げてるような動きをしてる。で、ためしにもちあげて実行すると普通にうごくんですよね。

なので同じDockerfileを二つ置いて運用しています。いやーなんでこんな仕様になってるのか教えてくれ～
Intel(R) Dynamic Power Performance Management の「手動アンインストール作業」

# 概要
Let's note CF-NX1 をP2VしたVM(Windows 7)のWindows 10へのアップグレード時に必要となった Intel(R) Dynamic Power Performance Management 手動アンインストール作業について

# 本文
ある Windows 7 が動いているVMをWindows 10へアップグレードしようとした際、下記のようにIntel(R) Dynamic Power Performance Managementのアンインストールを求められた。
![msg1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354637/2e86c217-9681-859b-9857-436118d06812.png)
>「Intel(R) Dynamic Power Performance Management」このアプリは Windows 10と互換性がないため、今すくアンインストールしてください。」

調べたところ、どうやら以前 Let's note CF-NX1 をP2VしたVMだったみたいです。

対処方法をいろいろ調べましたが、下記の状況でした。

- コントロールパネルに "Intel(R) Dynamic Power Performance Management" は存在しない
- コントロールパネルに "Intel(R) Dynamic Power Platform and Thermal Framework" は存在しない
- フォルダ "C:\util\" "C:\util2\" "C:\util3\" は存在しない
- ファイル "DppmCleaner.bat" "LPOSetting.js" "DptfInvalidPolicyRemover.exe" は存在しない
- パナソニックのサイトから etm_6071084.exe をダウンロードしてもインストールできない

さて、困った・・・

数日後、P2V 前と思われる Let's note を発見！
いろいろ試したところ、"Intel(R) Dynamic Power Performance Management"がある状況で、"Intel(R) Dynamic Power Platform and Thermal Framework"(etm_6071084.exe)をインストールした時のセットアップ進行状況で、削除を行っている作業がわかった。
![msg2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354637/a9d8234e-0b67-d07d-5a42-ff0f42843042.png)

これより、以下の作業を行った。

## Intel(R) Dynamic Power Performance Management 手動アンインストール作業
管理者として実行したコマンドプロンプトで

- サービス EtmService 削除
    - sc.exe stop EtmService
 - sc.exe delete EtmService
- ファイル削除
 - del C:\windows\system32\drivers\EtmDevDram.sys
 - del C:\windows\system32\drivers\EtmDevFan.sys
 - del C:\windows\system32\drivers\EtmDevGen.sys
 - del C:\windows\system32\drivers\EtmDevPch.sys
 - del C:\windows\system32\drivers\EtmDevProc.sys
 - del C:\windows\system32\drivers\EtmDrvMgr.sys
 - del C:\windows\SysWow64\EtmService.exe
- レジストリキー削除
 - regedit でキー「HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\IIF2Installer」を削除

上記作業後、再度Windows10のsetupを行ったところ、Intel(R) Dynamic Power Performance Managementのアンインストールは求められず、Windows10にアップグレードインストールに進めました。
![msg3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354637/32164e29-77d4-3e4e-0bd3-2df84b40322f.png)
【PHP】FizzBuzz問題を解いてみた。【具体的解説付き】

・動作環境　PHP7

プログラミングの世界で最低限の実力を持っているかどうかを測る指標のような存在であるFizzBuzz問題を解いてみました。
以下に解くまでの過程と考え方も併せて解説致します。

なお**「最低1回forとif文でコードを記述した事のある人向け」の解説**となっています。
どうしてFizzBuzzがそのソースコードで成立するのか理解する助けになればと思います。

#PHPにおけるFizzBuzz問題の答え

```PHP:fileName.php
<?php

echo "FizzBuzz問題";
echo PHP_EOL;

for($i = 1; $i <=100; $i++){
	if($i % 15 === 0){
		echo "FizzBuzz";
		echo PHP_EOL;
	}elseif($i % 5 === 0){
		echo "Buzz";
		echo PHP_EOL;
	}elseif($i % 3 === 0){
		echo "Fizz";
		echo PHP_EOL;
	}else{
		echo $i;
		echo PHP_EOL;
	}
}

?>
```

以下解説。

##その1 : For文

```PHP:fileName.php
<?php
for($i = 1 ; $i <= 30 ; $i++){
  「条件式」
}
?>
```

Forはループを作り出すのに用います。
なお上記のforに続く()の中身を訳しますと、

１、「$i = 1」最初は$iに1を入れる。そしてまずはそれを出力。
２、「$i <= 30」以降の繰り返し処理で$iの中身が30を超えない限り出力を繰り返す。
３、「$i++」なお1回繰り返す毎に1を足していく。

という処理内容です。
なので上記の場合1~30までの数字が出力されます。

forは「n番目まで続く連続した数列を作る」とか、「n回同じ処理を必要とする」場合に用いられる訳です。

#その2 : if文

一番上の答えの中でif文は以下の部分にある事が解ります。

```
for($i = 1; $i <=100; $i++){
　「この部分がif文」
}
```

ここからはその部分の解説をします。

```PHP:filename.php

	if($i % 15 === 0){
		echo "FizzBuzz";
		echo PHP_EOL;
	}elseif($i % 5 === 0){
		echo "Buzz";
		echo PHP_EOL;
	}elseif($i % 3 === 0){
		echo "Fizz";
		echo PHP_EOL;
	}else{
		echo $i;
		echo PHP_EOL;
	}
```

なおそもそもの挙動としてif文は以下のように、順番に処理をしている事になります。


１、(今回の場合)最初のfor文で出てきた数字を受け取る。
２、if文の中身のソースコードを上から順番に処理し、該当部分が出たらその処理内容を出力する。
３、出力処理がされたらそこで計算は一旦終了。1に戻りfor文の記述に従い、次の数字を受け取る。

つまり今回のソースコードの場合は、「1をifで処理し、2をifで処理し、3をetc…」　という処理をしていた事になります。

##ifでの処理の順番

次に処理の順番です。
結論から言うと、

１、if文で15の倍数を検知して”FizzBuzz”を出力。
２、3の倍数を検知して"Fizz"を出力。
３、5の倍数を検知して"Buzz"を出力。
４、上記に該当しなかった場合そのまま数字を出力。

この順番で処理します。


また、FizzBuzz問題を解く際は、「集合」を気にしてみるのが良いと感じました。
高校数学Aでやったあの集合です。

四角形の中に〇が2つ描かれていて、その丸同士が重なっている図を1度は見た事があると思います。

その**図の丸が重なった部分から処理し、次に丸単体を処理し、最後に丸に該当しない数字を順番に書き出せばよいのです。**
そうすれば重なった部分を重複処理する事を避ける事ができます。

###図で集合を解説
![FizzBuzz.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413468/ce6650b9-cf55-dae6-aa03-467fc98a382e.jpeg)

上記の図は、
・forの四角い枠が全ての数字。
・3nの円が3の倍数。
・5nの円が5の倍数。
・そして3と5が重なる部分が15の倍数
という事になります。

今回はこの図を使って解説します。

###計算部の考え方

ところでFizzBuzz問題は3の倍数や5の倍数や15の倍数の時に表現をFizzやらBuzzにすり変えよという問題です。
**この場合、複数条件が重なった部分を出力し、次に単体で条件に重なるものを順番に出力して、最後にどの条件にも合致していない数字を出力すればよいのです。**

従って、
１、計算部の重なっている部分の15n(3の倍数かつ5の倍数である15nの部分)をまず出力
２、3nの部分を出力
３、5nの部分を出力
４、3倍でも5倍でもない数字を出力
※2と3は重なり合った部分ではないので順番が逆でもOK!

という順番に処理を行えば、FizzBuzzが完成するという訳です。

![FizzBuzz.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/413468/ce6650b9-cf55-dae6-aa03-467fc98a382e.jpeg)

###if文の仕様

「え？15の倍数を処理できても、それらは3の倍数とか5の倍数でもあるのだから"FizzBuzzFizz"みたいな出力にならないか？」
と考えたかもしれませんが、ご安心を。

**if文は、1度処理に成功したら以降の処理をしないという仕様です。**

処理時に数字が15の倍数であると解ればFizzBuzzを出力して、以降にある3の倍数・5の倍数の処理層にはそもそも計算が行かないのです。
それを考慮しながら下記のif文をもう一度ご覧ください。

```PHP:filename.php

	if($i % 15 === 0){
		echo "FizzBuzz";
		echo PHP_EOL;
	}elseif($i % 5 === 0){
		echo "Buzz";
		echo PHP_EOL;
	}elseif($i % 3 === 0){
		echo "Fizz";
		echo PHP_EOL;
	}else{
		echo $i;
		echo PHP_EOL;
	}
```

if文は、例えるのなら”フィルター”に近いです。

・最初が15の倍数というフィルターで該当したらそこで処理。
・次が、3と5の倍数というフィルターで該当したらそこで処理。
・そして最後の"}else{"以降で、どのフィルターにも当てはまらない数字を処理。

となります。

最後までフィルター(15の倍数/5の倍数/3の倍数)にかからなかった数字が最後の処理層に届く訳です。


間違い等ありましたらお気軽にコメント欄へお申し付けください。
Phpstormのプロジェクトでnode.jsを導入してglupでcssとjsを結合して圧縮

毎回プロジェクト作るたびに同じことやってるので、備忘録的に書いとく。

とりあえず、scssやjs圧縮のために導入することがほとんどなので、そこだけにしか言及しないZE。

<a href="https://pleiades.io/help/phpstorm/using-gulp-task-runner.html" target="_blank">Gulp - 公式ヘルプ | PhpStorm</a>

## プロジェクトにnode.js導入

Alt+f12でコンソールを出し、「npm init」で設定ファイルをつくっておく。npmコマンドのたびにワーニングが入るので、避けられる。

エンター連打！

~~~
npm init
~~~

## Gulp導入

引き続きコマンド。

~~~
npm install gulp --save-dev
~~~

プロジェクトに導入するのでsave-dev。

## 必要なのを導入。

私用テンプレ。

~~~
npm install gulp-sass gulp-clean-css gulp-rename gulp-sourcemaps gulp-watch gulp-plumber gulp-babel @babel/core @babel/preset-env gulp-uglify gulp-concat gulp-minify-css --save-dev
~~~
sass, minify, rename, sourcemaps, watch,plumber, babel, uglify, concat を入れてる。

### gulpfile.jsをつくって記述していく。

あとはもうgulpfile.jsをつくって記述していく。

これまた私用テンプレ。

~~~js
//設定

//基本フォルダ
var base_path = "publics/common/";

//スクリプト対象フォルダ
var js_files = [
	'accessory'
];


var gulp = require('gulp');
var sass = require('gulp-sass');
var minifyCss = require('gulp-minify-css');
var rename = require('gulp-rename');
var sourcemaps = require("gulp-sourcemaps");
var watch = require('gulp-watch');
var plumber = require('gulp-plumber');


gulp.task("sass", done => {
	gulp.src(base_path + "scss/*.scss")
		.pipe(plumber())
		.pipe(sourcemaps.init()) //sassの前に.init()する
		.pipe(sass())
		.pipe(gulp.dest(base_path + '/css'))
		.pipe(rename({extname: '.min.css'})) // ファイル名を変える
		.pipe(minifyCss({advanced: false})) // minifyする
		.pipe(sourcemaps.write('./'))
		.pipe(gulp.dest(base_path + '/css'));
	done()
});

var babel = require('gulp-babel'),
	uglify = require('gulp-uglify'),
	concat = require('gulp-concat');

gulp.task('js', function (done) {
	js_files.forEach(function (js_file) {
		gulp.src(base_path + "concat_js/" + js_file + '/*.js')
			.pipe(plumber())
			.pipe(sourcemaps.init()) //sassの前に.init()する
			.pipe(concat(js_file + '.js'))
			.pipe(babel({
				"presets": ["@babel/preset-env"]
			}))
			.pipe(gulp.dest(base_path + 'js/'))
			.pipe(uglify())
			.pipe(rename({extname: '.min.js'}))
			.pipe(sourcemaps.write('./'))
			.pipe(gulp.dest(base_path + 'js/'));
	});
	done();
});


gulp.task('watch', function () {
	gulp.watch(base_path + "scss/*.scss", gulp.parallel('sass'));
	gulp.watch(base_path + "concat_js/*/*.js", gulp.parallel('js'));
});

~~~

base_path で設定したディレクトリのscssを生成、jsはディレクトリごとに小分けして、それを結合する。復数のjsに分けて生成したい場合にディレクトリ指定で同じことをforEachで回していくスタイル。
ニーモニックから秘密鍵を取得してみた

みなさん、MetaMaskはお使いでしょうか？
すごい便利なのですがニーモニックでのインポートが出来ないんですよね。
とある Ethereum のアカウントを移行しようと思ったときに少し困ったのでメモです。

# 実装
早速ですが以下のライブラリを使用しました。
https://github.com/justinchou/ethereum-mnemonic-privatekey-utils

まずはクローンしてきて、必要なライブラリをインストールしていきます。

```sh
$ git clone https://github.com/justinchou/ethereum-mnemonic-privatekey-utils.git
$ cd /ethereum-mnemonic-privatekey-utils
$ npm install
```

続いてコードを書いていきます。
と言いたいところですが、すでにサンプルがあるのでそれを利用しましょう。
サンプルファイルの名前は demo.js になります。

```demo.js
const pkutils = require('./index');
  
pkutils.debug = false;

const mnemonic = 'this is your mnemonic words do not show this words other people';
const password = 'this is a totally long password';

console.log('mnemonic               : %s', mnemonic);
console.log('password               : %s', password);

const privateKeyGen = pkutils.getPrivateKeyFromMnemonic(mnemonic);
console.log('pkey from mnemonic     : 0x%s', privateKeyGen);

const keystore = pkutils.getKeystoreFromPrivateKey(privateKeyGen, password);
console.log('\nkey store              : %j\n', keystore);

const privateKeyParsed = pkutils.getPrivateKeyFromKeystore(keystore, password);
console.log('pkey from keystore     : 0x%s', privateKeyParsed);

const account = keystore.address;
console.log('account address        : 0x%s', account);
```

`mnemonic`にはご自分のニーモニックを入力してください。
試しにこのスクリプトを実行すると以下のような出力になると思います。

```sh
$ node demo.js
mnemonic               : this is your mnemonic words do not show this words other people
password               : this is a totally long password
pkey from mnemonic     : 0x1a50c342ee19eeed0d29dad2f9d37ff06690b7e6fd764e23de94296ec02074fc

key store              : {"address":"d0c53d7d802fbcf5a8162b0ebf1e6aca66202e33","crypto":{"cipher":"aes-128-ctr","ciphertext":"ece9cb20184c907916e61c66b8070569bec61f0c92ed9f33eda9303066906b52","cipherparams":{"iv":"fe93ca7db03671a77849fb5926727bed"},"mac":"be432d8e2b21ce619b97dee0073281c8ffd1e451e661b4e3f61fbad1f3316a3d","kdf":"pbkdf2","kdfparams":{"c":262144,"dklen":32,"prf":"hmac-sha256","salt":"65b7e9eabeb6db63ed4193b4e863d2ce1e826f66ac8394c198f570a5c26be9af"}},"id":"38812fce-3ff8-4a84-b135-fe2b120785ef","version":3}

pkey from keystore     : 0x1a50c342ee19eeed0d29dad2f9d37ff06690b7e6fd764e23de94296ec02074fc
account address        : 0xd0c53d7d802fbcf5a8162b0ebf1e6aca66202e33
```

この中の pkey from mnemonic が秘密鍵となりますので、後はMetaMaskに突っ込むだけですね！
Swift UI を使って簡単なSNS風（見た目だけ）を作りました。

# SwiftUI を用いSNS風（見た目）を作ってみました

- 現状のswiftUIの導入方法については[こちらをご覧ください。](https://qiita.com/ankuma0617/items/be708d817bc924800050)
- できたもの
- サンプルコード
    - 縦スクロール
    - 画像のハメかた
    - 横スクロール


<br>

## 感想

今までより簡単にコードが書けるので学習コストもそんなにかからないと思いました！
flutter を勉強しようと思っているのですがどちらから勉強すればいいか迷っています。。。

##　できたもの
　
<img width="1260" alt="sns風" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310283/b76017e4-d9eb-168d-e652-06cf9ad8881e.png">

## サンプルコード

### 縦スクロール
まずはTableViewのような縦にスクロールできるものを作っていきます。

~~~ContentView.swift
import SwiftUI

struct ContentView: View {
    

    var body: some View {
        NavigationView{
            List{
               Text("Row_1")
               Text("Row_2")
            }
        }.navigationBarTitle(Text("Groups").color(.green))
    }
}
~~~
こんな感じになるはずです（なぜかNavigationBarが表示されません。）
<img width="1088" alt="スクリーンショット 2019-06-07 18.52.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310283/488c0353-c765-8f89-0978-c61be05f6432.png">

また以下のように書くと
文字がいじれます。

~~~ContentView.swift
struct ContentView: View {
    

    var body: some View {
        NavigationView{
            List{
                Text("Row_1")
                    .font(.headline)
                    .color(.red)
                Text("Row_2")
                    .font(.footnote)
            }
        }.navigationBarTitle(Text("Groups").color(.green))
    }
}
~~~
文字のフォントと色を変えてみました。
<img width="1061" alt="スクリーンショット 2019-06-07 18.56.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310283/95568a05-dd82-6c3d-a407-4f9d00f6dfd2.png">

## 画像のハメかた

長くなりそうなので別の記事に書こうと思います。
それは突然やって来た

# "Github Desktop"なるもの
- インストなりして動かしていたら元を忘れてしまったが、（多分自分のRSSリーダーだと思うが）[Github Desktop v2](https://github.blog/2019-06-05-github-desktop-expands-to-support-stashing-and-rebasing/)がリリースされたとの事
- 記事見て[オフィシャルサイト](https://desktop.github.com/)からDLしてインスト
- Github上の自分のリポジトリからクローンしてリモートリポジトリを作成
- すごく原始的だけどGCEからコピペでファイルをローカルに保存
- ローカルからローカルリポジトリへコミット
- ローカルリポジトリからリモートリポジトリへプッシュ
- 出来た！

# 何がよくて何がいけなかったのは、今は追いかけない方がいいと思う
- リモートリポジトリへプッシュ出来た事に変わりはない。ではなぜSource treeはダメでGithub desktopなら平気なのかは分からない。でもプッシュ出来たので一先ずはよしとしよう。目的達成出来たからね:grinning:

# 今日の気持ち
- ここで改めて言う必要はないと思うけど、大切な事だから忘れないように書いておく
- 今の会社は辞める。気持ちは完全に固まった
- 自分はコンピュータエンジニアでいる、居続ける。そこだけはブレない
Vue-CLI3でjQueryを使う

最近「jQueryいらない」みたいな風潮ですが、
「bodyにclass追加したい」と思ったら、jQueryを使うのが速い。
使い分け大事

```terminal
$ npm install --save-dev jquery
```

Vue-CLI-uiを使うとさらに簡単です。
![スクリーンショット 2019-06-07 18.44.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216132/f16b422a-29d9-4a37-bbcc-88d17ef52535.png)

App.vueに読み込む

```App.vue
<template>
  <div id="app">
    <router-view />
  </div>
</template>
<script>
import $ from 'jquery' // ← 読み込む
export default {
  //（省略）
}
if(navigator.userAgent.indexOf('Android')>0){
  $("body").addClass("Android"); // ← 書ける
};
</script>
```

![スクリーンショット 2019-06-07 18.51.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216132/5f56803f-761b-aab1-d265-1036f83d3a6e.png)

コレでAndroid用のCSSが書ける。

【追記】
あれ、ココに書いてDOMの操作できるっけ ？？
mounted(){}の中に書いたほうが良いと思う。

```App.vue
<script>
import $ from 'jquery' // ← 読み込む
export default {
  //（省略）
  mounted(){
    if(navigator.userAgent.indexOf('Android')>0){
      $("body").addClass("Android"); // ← 書ける
    };
  },
}
</script>
```
Saving microphone audio recorded in PowerApps into SharePoint library

# Overview
Saving microphone audio recorded in PowerApps into SharePoint library has been discussed long time, but AFAIK there is no “low-coding” solution for this challenge.

Today, we have ability to convert images and audios to base64 string by using JSON function in PowerApps. (See [here](https://docs.microsoft.com/en-us/powerapps/maker/canvas-apps/functions/function-json
))

and here I summarized simple & low-coding solution for saving audio from Microphone to SharePoint Library using JSON and Flow.

NOTE: This approach only works well in PC browser, not mobile device.

# PowerApps

First I assumed that there added 1 Microphone control, TextInput, and Button in my app.
![audio1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/3bed81eb-f44d-4da5-a4fc-fef4954a1cf8.png)


TextInput is just used as file name, and button triggers Flow described later.

For Microphone control, set below function in OnStop property:

```
Set(tmpJson,JSON(MicrophoneAudio1.Audio,IncludeBinaryData));
Set(strB64Audio, Mid(tmpJson,25,Len(tmpJson)-25);
```

where IncludeBinaryData is key to convert Microphone audio into base64 string.
The remaining part Mid(...)  is extracting base64-ed content from generated string.

![audio2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/7ba3afeb-55c0-fb38-04af-744d7af4e150.png)


# Flow
Saving base64ed audio into SharePoint library is very simple and straightforward.
 1.  Initialize string variable using "Ask in PowerApps" with name "b64Audio"
 2.  Add Create file action of SharePoint connector with 
   - Filename : Ask in PowerApps
   - Filecontent : base64ToBinary(variables('b64Audio'))
  * Other parameters are your site and some document library which you want to store file.
![audio3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/86c9030e-34ce-6dbb-b7b5-87997f42cae5.png)

Save flow with name "SaveAudio"
Ref: http://johnliu.net/blog/2017/7/building-non-json-webservices-with-flow

# Back to PowerApps
We can now store microphone audio to SharePoint library.
Last, execute flow "SaveAudio" by select button:

```
 OnSelect : SaveAudio.Run(strB64Audio,TextInput1.Text)
```

# Check result
This provides you easy & low-coding solution to save microphone audio to SharePoint list.
You can apply this method for meeting note with recording or some fun apps :-)

Have fun!!
![audio5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202779/bf5c98a2-2581-542d-e376-7b0551f6f13b.png)
Chrome Remote DesktopでUbuntuにいつでもどこでもリモートアクセス

今回の私の要求：**「家からも研究室の自分のPCにアクセスしたい」**

一応：*リモートアクセスという行為の性質上、悪意をもった第三者に遠隔操作されてしまう可能性もあったり(Googleが提供しているサービスだからまず大丈夫だろうけど)、遠隔操作されてる側の端末自体は自由に操作できるのでオフィスにいる人に操作されてしまったり、下に書くようにログインした状態で帰ることになるのでセキュリティ的にもまずいです。この記事に書いてあることは自己責任で行ってください。*

# Chrome Remote Desktopのセットアップ
もちろん、Google Chromeが必要。
https://remotedesktop.google.com/home にアクセスして、**リモートアクセスの設定**をする。
![Screenshot from 2019-06-07 18-24-50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225983/c74439f2-641b-5620-1298-1c88ccc3cc91.png)

# Ubuntuのセットアップ
※GNOMEを使っているので、Unityだと設定項目が多少異なるかもしれません
Ubuntuからログアウトされると、**Remote Desktopからはログインすることができない**ので詰む。なのでAutomatic Screen Lockはオフにする。遠隔操作したい時は、帰る際にログアウトせずに放置して帰る。
![Screenshot from 2019-06-07 18-26-30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225983/93cf2826-debd-5a3d-7b95-19d2be1aaeca.png)
スクリーンは消えても大丈夫なので、こちらのBlank Screenの設定はしていてもOK。
![Screenshot from 2019-06-07 18-30-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225983/53c23e9b-7151-f7fa-865e-5b3e4600c023.png)

# 情報を保護する
ログインしたまま放置して帰るので、セキュリティ的によくない。というかいろいろまずい。オフィス内の治安が良かったとしても、そのままにして帰るのはあまりに無防備なので、ちょっとは防衛策を貼っておく。

私の場合、見られて困る情報はすべてブラウザ上に保存されているものだったので、ブラウザだけ保護する方法を探した。
[Chrome Lock](https://chrome.google.com/webstore/detail/set-password-for-your-bro/cjmjgijhapgicbhmniemjkjeaedanank?hl=en)などの拡張機能を用いれば、起動時にパスワードが必要なのである程度保護できる。放置する前はかならずChromeを閉じておけばよい。（Firefox用の同様の拡張機能を探したけどなかったです...）

# リモートアクセスする！
これで、リモートアクセスできるようになったはずです。
**どこからでも(旅行先でも)いつでも(深夜でも)研究ができるね！**
兵法ができるAI開発

#兵法ができるAI開発
## 記事の目的
こんにちは！今ちょうど深層学習（ディープラーニング）や強化学習の勉強をしていてAI同士を協力させると面白くないかな？と思ってこのプロジェクトを始めました。
## このシリーズを通して学べる事
LSTM
強化学習
興味を用いた強化学習
アクタークリティック
簡単なゲームの作り方
Unity
Ml Agents
## 動機

ちょうど「キングダム」という漫画
![61FXHv0I7rL._SX260_.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/414567/6864a8ad-a5ec-aa51-a44a-a7e1b77e8448.jpeg)
を読んで兵法や戦場における人というものの面白さに触れられてこのような思想戦を行えるゲームがしてみたかったからです。もちろん将棋やチェスみたいな簡略化したゲームはありますが戦場における以下の点を無視しているような気がしました（両方苦手ですがw）。
#### 1. 指揮系統がない
普通の戦場では命令系統があり、上からの命令と目の前の状況から次にする行動を決めると思います。しかし普通のゲームでは単純に命令を与えたらその場所に動き、駒に作戦などがありません。よって駒が自分で考えて上からの命令を参考するようにしました。
#### 2. ランダムではない
ここで言っているのは一つの駒がもう一方の駒を攻撃したときに結果が決まっているということです。例えば飛車を歩の場所までもっていったら歩が取れるということが将棋では決まっています。しかし、正直それって正確には大してあっていないと思います。例えば四方向から誰かを囲めば確かに倒す確率は上げられるかもしれませんが逆にやられてしまう可能性が皆無というわけではないと思います。なので、そういったこと確率なども含んでみました。
#### 3. 見える範囲
戦場において一番重要だと思うことは相手に自分の戦略が明らかにならないことです。ここで一番それができる確実な方法は相手に自分が見えないことです。よってそれを可能にするために各AIに個人個人見える範囲を設定しました。
#### 4.動きが変
チェスや将棋にはマスがあり、双方順番に駒を進めます。しかし、実際には３６０度のどの方向にも動くことはできるはずでしかも両方毎秒毎秒動きます。順番などはありません。なのでそれも含めてみました。

## 手順
#### 1.上の４条件を満たすゲームを考えてみる。
#### 2. AIで学習できるようにする。
#### 3. 結果報告
#### 4+2n 改善したこと
#### 5+2n 結果報告
でき次第リンクをつけておきますがここではとりあえず1を先に説明します。
とりあえず、最初の１だけここでとりあげます。
# 1.ゲームのルール
前提に置いておきますが、このゲームは上の四つの条件を満たす最低限度のゲームを考えてみたのですが結構複雑になってしまったのでそのことはすみません。
すべてのプレイヤーは丸です。
<img width="95" alt="circle.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/414567/9e9b8c8a-ef20-0813-0761-02f39bf5cab2.png">
この丸は動くことができ、攻撃範囲と攻撃する角度を指定すれば敵の丸を攻撃できます。Unityで作ったら下のようになりました。（学習したモデルはのっけてないです）
![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/414567/b7d1fbd7-c9a3-4337-cdcd-740a2fbb77a6.gif)
このゲームにはHPとかはなく、生きていると死んでいるという二つの状態しかありません。だから攻撃範囲（二つの黒い棒の間）に入ったら死ぬか相手を殺すかの２パターンしかありません。ここで第二条件の「ランダム」をいれてみました。
具体的にはすべての兵に正規分布からてきとうに「力」というパラメターを付けます。物理にならって力を$f$となずけましょう！
ここで一対一の勝負の場合もし兵１と兵２が戦う場合、兵１が勝つ確率,$p_1$を
$$p_1 = \dfrac{f_1}{f_1+f_2}$$
と定義しました。しかし、１対４とかの場合ではどうでしょう？こういう試合を４回するだけでしたら１対１の戦いを４回繰り広げるだけとなり、兵法においてとても大切な「戦術の分断」と「多数で少数を攻撃する」ことじたいを否定してしまいます。

なので、先ほど言った攻撃範囲というものも作ってみました。
攻撃範囲とは攻撃を始める角度と攻撃を終了する角度の二つによって定義しました。敵の中心が攻撃範囲に入ったら攻撃したことになります。攻撃範囲が小さければ小さいほど力$f$が大きくなり、攻撃範囲が大きいほど$f$が小さくなります。よって攻撃範囲を広くすればするほど勝ちにくくなります。
では、学習したら兵たちは全員小さい攻撃範囲になるはずというかもしれませんが攻撃範囲以外の場所からの攻撃を考えてみました。その場合は力を$\dfrac{1}{4}$くらいにするように設定しました。これがUnityの上のGifで一人で全員倒せた理由です。攻撃範囲の外から攻撃してたからです。
これによって、大勢いる際は必ず攻撃範囲を広げないといけなく、多勢の方は攻撃範囲を狭くできて勝ちやすくなるようにしました。
Gifに出ていた数も気になると思います。これは階級です。1は一番下っ端で2がその一個上3はそれのさらに上っという感じで無限に付けられます。つけ方も結構簡単で５人同じ階級の兵がいたら一番優秀な一人（一番力があるもの）は必ず一個上の階級になる。というのを繰り返すと全員に階級がつけられました。
では、階級が上の人の存在意義というのは何でしょう？これは少し将棋とか少ししたりキングダムを読んで感じたものですが「次の状態を予測する」ことでついでに言うと「より広い視野」を持つことだと個人的に思いました。なので学習の際では指令として、上からの指令と今見える盤上をもとに次に起こると予想した兵の位置や状態などを送ることにしました。結構屁理屈かもしれませんが個人的には結構な理屈です。ここでどれくらいもっと見えるかは
$$r_{base}2^{rank-1}$$
ということにしました。つまり部下の２倍の景色が見れるようにしました。Unityで見せるとしたらこんな感じです。
![ezgif.com-video-to-gif (2).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/414567/1997e3f7-df29-fb5a-ec80-af1f2eb8875d.gif)

人間で遊ぶ場合はどうやって次の状態っというのを送るかは思いつきませんでしたので、上のように自由に階級を行き来できるようにするつもりです！
Android StudioのTerminalでfishを使うときにfzfが効かないときの対処

## 環境

- macOS Mojave(10.14.5)
- Android Studio 3.4.1
- fish 3.0.2

## 現象

Android Studioやfish,fzfなどの設定を済ませ、control-rで履歴を表示しようとすると

```
fish: Unknown command fzf                                                                                                                                        Fri Jun  7 18:35:09 2019
- (line 1): 
begin; fzf --read0 -q (commandline) 
       ^
from sourcing file -
        called on line 61 of file /usr/local/Cellar/fish/3.0.2/share/fish/functions/eval.fish

in function 'eval'
        called on standard input

in function 'fzf-history-widget'
        called on standard input
```

とfzfが見つからないエラーが出てしまいました。

## 対処

Android Studio側で持っているfish_variablesを使っているのが原因
シンボリックリンクで置き換えて対処します。

```
cd /Applications/Android\ Studio.app/Contents/plugins/terminal/fish
mv fish_variables fish_variables.bak
ln -s ~/.config/fish/fish_variables
```
apt で "files list file for package 'XXXX' is missing final newline" が起きた場合の対処方法

# はじめに

Debian で運用しているシステムで、apt-get upgrade 等を使ってパッケージをアップグレードしようとした時、次のようなエラーが出て失敗することがあります。('XXXX' にはパッケージ名が入ります。どのパッケージが入るかは場合によります。)

```console
dpkg: unrecoverable fatal error, aborting:
 files list file for package 'XXXX' is missing final newline
E: Sub-process /usr/bin/dpkg returned an error code (2)
```

# 原因

```/var/lib/dpkg/info/``` に各種パッケージの情報が格納されています。そのうち XXXX(パッケージ名)に関するファイルがなんらかの事情で壊れていると、前節のようなエラーが発生します。

# 対処方法

そもそも、これらのファイルが壊れること自体が問題なのですが、この記事ではその問題は置いといて、とりあえずシステムを復旧して再度 apt が正常に動くようにします。

## XXXX に関するファイルを削除(移動)

```console
shell# cd /var/lib/dpkg/info
shell# mkdir /var/lib/dpkg/info/old
shell# mv XXXX.* /var/lib/dpkg/info/old
```

## パッケージを再インストール

```console
shell# apt-get install --reinstall XXXX
```

連鎖的に他のパッケージが同様にエラーが発生する場合がありますが、ひとつひとつ根気よく復旧します。
Vue2（Vue-CLI3）Vuexでリロードに耐える

# vuex-persistedstateをインストール
コレをインストールします。
https://www.npmjs.com/package/vuex-persistedstate

```terminal
$ npm install --save-dev vuex-persistedstate
```

# store.jsに読み込んで使う
store.jsの末尾に追加する

```store.js
import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from "vuex-persistedstate" //←読み込む
Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    test:[],
  },
  getters:{
  },
  mutations: {
    updateStoreTest: function(state, payload){
      var self = this;
      self.state.test = payload;
    },
  },
  actions: {
    updateTest: function(dispatch, val ){
      var self = this;
      self.commit('updateStoreTest',val )
    },
  },
  plugins: [createPersistedState({storage: window.sessionStorage})] // ← ココ！
});
```
これでブラウザをリロードしても消えなくなります。


# 消し方
Local Strageは、キャッシュよりも強く残ってしまうので、
データの消し方がわからなくなると困るので、追記します。

■chromeの場合
＞その他のツール
　＞デベロッパーツール
　　＞Application
　　　＞Local Strage
　　　　＞（あなたのドメイン）
　　　　　＞vuex　を×ボタンで消す
【Unity】上下にゆらゆら動くアイテムボックスをつくる

<dr>
Unityでゲーム開発をしているときの
あーこういうの欲しいな！を叶える、
知っていれば確実にゲームに彩りを加えられるメソッドを紹介します。
<dr>

##PingPong関数
この記事で紹介するのは
ゲーム内によくある、上下にゆらゆら動いているアイテムボックスなどに使える
PingPong関数です。
<dr>
<dr>

```
Mathf.PingPong(時間, 上下差)
```

<dr>
この関数では その名の通り、
0と「上下差」で指定した数値の間を、ピンポン球のように行ったり来たりする値を取得できます。
<dr>
<dr>

```
Mathf.PingPong(time.deltaTime, 10);
```
このようにすれば、0~10の値が返ってきます。
<dr>
<dr>

##アイテムボックスを動かす

上下に移動するアイテムボックスはy軸方向に動いているので
PingPong関数をy座標に使います。

<dr>
<dr>
まず、次のように書いてみます。
<dr>

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class itemBoxScript : MonoBehaviour { 

    public float nowPosi;

    void Start () {
        nowPosi = this.transform.position.y;
    }

    void Update () {
        transform.position = new Vector3(transform.position.x, nowPosi + Mathf.PingPong(Time.time, 0.3f), transform.position.z);
	}

}
```

<dr>
再生開始と同時に最初のアイテムボックスのy座標(_nowPosi_)を取得しておきます。
でないと、Mathf.PingPongだけでは
<dr>
__（y座標） = 0 + （上下させたい値）__
<dr>
になってしまうので、
オブジェクトをシーンビューでどのようにおこうとも
開始と同時にy=0の周辺で上下するようになってしまいます。

<dr>
<dr>
次に
取得したy座標にMathf.PingPongで上下させたい値を足します。

x座標、z座標には最初の座標をそのまま反映させましょう。
<dr>
<dr>
<dr>
するとこんな感じ。

![pingpongそのまま.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401981/930bc84d-d7ef-c413-0ec9-3ab1e8095459.gif)


なんだか上下の動きが激しい気がするので
Mathf.PingPongのところを
<dr>
<dr>

```
Mathf.PingPong(Time.time/3, 0.3f)
```
<dr>
このように変えてみると

![pingpong:3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401981/c37048b7-b9e8-7b05-84ab-d9f81bac51a2.gif)

ゆっくりになりました。

##まとめ
+ 再生開始時の座標を取得する
+ Mathf.PingPongはゆらゆら移動してほしい向きの座標に足す

<dr>
上下に動くアイテムボックスが完成しました！
<dr>
<dr>
<dr>
##参考
[Unityスクリプトリファレンス]
(https://docs.unity3d.com/ja/2018.2/ScriptReference/Mathf.PingPong.html)
iOS13でpresentViewControllerでの遷移はひとくせあり


#**iOS13でpresentViewControllerでの遷移はひとくせあり**

iOS13のベータ版が公開されたので、早速実機にインストールして、
開発中のアプリをXCode11ベータ版でビルドして動作確認してみました。

そこで、画面遷移の仕様が変わっていました。
具体的にはpresentViewController（セグエも同様でしょう）を使用したモーダルタイプの遷移後に、
**前の画面が下に存在することが分かる**ようなレイヤーチラ見せ方式になっています。
※ナビゲーションのpushの遷移は従来と同様でした。

####**連絡先**アプリの例

|iOS13|iOS12|
|:----------:|:----------:|
|<img width="100%" alt="iOS13.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51578/0c1fafa2-9cea-17c6-e9fc-5f674d93e590.png">|<img width="100%" alt="iOS12.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51578/adf69c48-63a5-1f10-5040-5ebd10e3011f.png">|

これにより、iOS13ではキャンセルボタンを押さずとも
**下方向にスワイプ**すると、今の**ビューを終了して前の画面に戻ることが可能**になりました。

iOS12でも同様の仕様の部分はありました。
例えばミュージックアプリの以下画面など

<img width="375" alt="iOS12_Music.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51578/ec1f289f-3440-b40e-7299-adfc3d38da6c.png">

下スワイプで前の画面に戻れる点では、すごく便利になりますね。
その反面、presentViewControllerで遷移後、
**戻ることを想定しない構成**で作られていたアプリは、
2019年秋以降のアップデート時には**修正が必要**になりそうです。

その他にも、仕様の変更点があるようでしたのでそれは別途で。。。
・セグメントなどパーツの見た目の変更
・ダークモードによる背景色・テキストカラーへの影響など
TableViewのCell入れ替えでViewが透過されてしまったあなたへ

# まくら

iOSアプリといえばUITableViewでございます。たぶん。
今回はそんなUITableViewの小ネタをひとつ。

UITableViewは割と簡単な設定でセルの入れ替えを実現させてくれます。

``` swift 
extension TableWorkViewController: UITableViewDataSource {
    // ...省略...

    // 移動可能
    func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
        return true
    }
    
    // 移動実行
    func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
        print("source: \(sourceIndexPath)")
        print("dest: \(destinationIndexPath)")
    }
}
```

こんな感じで設定してやって、どこかで

``` swift
self.tableView.isEditing = true
```
してやると、
![SS06071401.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106197/5993ccbe-a529-e939-7f34-8add9ce2b9d1.png)

こんな感じで入れ替えアイコンが表示されるようになります。
基本的なものでいいのならこれだけ。簡単。

では実際に入れ替えてみましょう。

![SS002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106197/2b1efc2c-768c-bed7-6343-03da5bf16f27.png)

お気づきだろうか？

セルの上に`UIView`を乗せているのですが、見えなくなっていますね。
どうやら入れ替えの時はセルの上に乗っている`UIView`は透明にされてしまっているようです。

何やらちょっと気持ち悪いので、対策を考えてみましょう。

# ほんだい

という訳で本題。

自分も地味にハマってしまったのですが、ナイスな力技で解決している方がいたので、マネさせて頂きました。

参考: 
https://medium.com/@vhart/tableview-cell-reordering-keep-the-color-4c03623d2399

最高！この力技感！

元ネタの方を見て頂けばわかる通り、移動の時に`UIView`の`backgroundColor`に透明がセットされてしまうので、強制的に色を保持してやろうという訳です。

そんなわけで作ったものがこちら

``` swift 
/// セルの入れ替え時に色をのキープしておくためのView
class TableWorkColorKeepView: UIView {

    /// キープ用のbackgroundColor
    @IBInspectable var keepBackgroundColor: UIColor = .clear {
        didSet {
            self.backgroundColor = self.keepBackgroundColor
        }
    }
    
    /// 背景色
    override var backgroundColor: UIColor? {
        set {
            // キープしている色と異なればリターン
            guard newValue == keepBackgroundColor else {
                return
            }
            super.backgroundColor = newValue
        }
        get {
            return super.backgroundColor
        }
    }
}
```

これを使うと、

![Simulator Screen Shot - iPhone Xʀ - 2019-06-07 at 18.19.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106197/519e2aab-4508-3eb3-9c2a-2a25f06d68f7.png)

こうなります。

キープ用の色を用意して、背景色が変更される時にその色と異なったら無視してやっているだけですね。
背景色をセットしたい場合は`keepBackgroundColor`の方に設定してやる感じです。
（Storyboardで初期値設定したかったので`@IBInspectable`してやっています）

##しまいに
力技なので用法用量にご注意を。
もっとスマートなやり方あれば教えてつかあさい。
CodeigniterにSkeletonを導入する時の覚書。

Codeigniterのナイスなサードパーティー、Skeletonを導入する時の覚書自分用。

<a href="https://github.com/bkader/skeleton" target="_blank">bkader/skeleton</a>

## Codeigniterの導入
index.phpだけpublicへ、他は奥に突っ込む。

## Mysql
Skeletonのfull.sqlをインポートする。

![47db1d01410725c08a5bb0bd5211786b[1].png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22850/2b59766d-4a51-1627-ac48-330bf0ba3ef8.png)

できてることを確認。

## Skeleton上書き
各ディレクトリをSheletonで上書き。

contentディレクトリはpublicに出す。

index.phpも書き換わっている項目があるので、wikiで見ながら自分で編集するか、上書きする。

## index.php編集

$skeleton_pathにskeletonディレクトリまでのパスを指定。

~~~php
$skeleton_path = '/home/hogehoge/skeleton';
~~~

$application_folder も同様

~~~php
$application_folder = '/home/hogehoge/application';
~~~

publicを外に出しているので、そこまでのパスも一応設定しておくといいかもしれない。

~~~php
define('PUBPATH', '/home/hogehoge/public_html/');
~~~

## sess_save_pathの設定
config.phpのsess_save_pathが未設定だと、私の環境だとエラーが出るので設定しておく。

~~~php
$config['sess_save_path']          = realpath(APPPATH . '/./session/');
~~~
基礎知識の補填　Python (内包表記）

# 内包表記（コンプリヘンション）について

今回は、内包表記について。

元々、Progate２週程度の理解しかなく現場でのソースがほとんどこの内包表記という書き方で
書かれていて、もう「for文の前についてる変数…なにこれ？？」みたいな感じだった。

勉強しなんとなく理解できたので、簡単にまとめていきたいと思う。

## 内容表記とは
for文でリストを作成していく際、短く簡潔な方法で書くこと。
他にもディクショナリやset型も扱うことができる。

### 通常の記述方法
例：
下記のdata変数へ１～５までの数値をリストとして代入し、

```python

data = [1, 2, 3, 4, 5]
```
配列の中身を３倍にする処理をfor文で回しながらnewData変数へ再度、入れ込んでいく

```python
newData = []
for d in data:
  newData.append(d * 3)

#[3, 6, 9, 12, 15]
```

### 内容表記での記述

上記３行で表してた処理を１行で簡潔に記述すると以下のようになる。

```python
newData = [d * 3 for d in data]

# [3, 6, 9, 12, 15]
```

### if文を使った条件式
入れ子構造にして、if文で条件をつける場合も可能。

```python
for d in data:
   if  d % 2 ==0:
      newData.append(d)
      #[2, 4]
```
上記の記述を内包表記で記述すると、以下のようになる。

```python
newData = [d for d in data if d % 2 == 0]
#[2, 4]
```
Vue-CLI3で環境変数.env.localを使う

dockerで手元にapiサーバー立ててる人もいれば、外部apiサーバーを見に行く場合もあったり、
書き換えて間違えてコミットしちゃったりして混乱する。そういう時に便利な.envファイル。

まず.envは.gitignoreに書く。

```..gitignore
# local env files
.env.local
```

Vue-CLI3のプロジェクト直下に「.env.local」を置く

```..env.local
VUE_APP_ENV=localhost
```

```store.js
getQuery: function(){
      var self = this;
      if(process.env.VUE_APP_ENV=='localhost'){
        self.commit('updateAPI', 'http://127.0.0.1:8001/api/v1/hoge?query') //docker
      }else if(process.env.VUE_APP_ENV=='dev'){
        self.commit('updateAPI', 'https://api.devserver.com/api/v1/hoge?query') //外部
      }
},
```

これでlocalサーバー立てても、ソースに影響ないです。
Ruby on Railsを開発する時にいれておきたいAtomのパッケージ


## ファイル検索・移動系

###[Rails Transporter](https://atom.io/packages/rails-transporter)

Controller/Model/View間の移動をコマンド一つできる。

RubyMineにもそんな機能があったからAtomにもないかなと思って探したら発見。
ControllerからViewを探すのは結構めんどくさいからかなり重宝している。

###[atom-fuzzy-grep](https://atom.io/packages/atom-fuzzy-grep)

高速簡易グレップ。

Atomの標準でプロジェクト内全体の検索はできるが、このfuzzy-grepはより早く検索したい時におすすめ。


###[advanced-open-file](https://atom.io/packages/advanced-open-file)

現在いるファイルから別のファイルを検索したい時に使える。

RailsだとViewでpartialの中身を確認したくて、別のファイルに移動する時に使える。
Viewって似たようなファイル名が多いから、grepしても検索結果が多くて判別できないため、これを使っている。

###[goto-definition](https://atom.io/packages/goto-definition)

関数定義場所のファイルにジャンプする。

私は`atom-fuzzy-grep`でも十分かなと思うが、直接関数に飛んでくれるのでたまに使う。


## Git系

###[git-blame](https://atom.io/packages/git-blame)

行毎に最終変更者が確認できる。

その名の通り、誰かのせいしたい時に使う。（笑）


###[git-time-machine](https://atom.io/packages/git-time-machine)

ファイルの過去の変更履歴を時系列で確認できる。

git-blameでは追えない犯人を追う時に使う。


## その他

###[platformio-ide-terminal](https://atom.io/packages/platformio-ide-terminal)

Atom上にターミナルを開く。

初回起動の場所をプロジェクトのrootパス等に設定できるため、gitのコマンド等使いたい時に使用。
ちょっと重い。。



（更新中。。）
cloud9→ローカルに移したら写真投稿ができなくなった

#はじめに
SNS風の写真投稿アプリを久々にローカルで確認してみたところ、肝心の写真投稿がバリデーションに引っかかり、投稿はもちろん、テストなども通らなくなってしまっていました。

#原因
結果を言ってしまうと、`Minimagick`を使うのに必要な`ImageMagick`を、ローカルでインストールしていませんでした。

cloud9時代に`ImageMagick`をインストールした自体あまり覚えていなかったので、気付くのが遅れてしまいました。


```
$ brew install imagemagick
```
これで今まで通り、問題なく写真投稿できるようになりました！

#参考
[Rails gem MiniMagick を利用して画像ファイルをリサイズする](https://qiita.com/ryo-ichikawa/items/6fbb66b8ecfdd0f1f9c4)
[RubyでImageMagick使うにはMiniMagickの方がよい](http://thr3a.hatenablog.com/entry/20180117/1516174199)
PHP foreachで回した配列を更新する

#PHP foreachで回した配列を更新する

基礎の基礎という感じですが、初投稿も兼ねてforeachで回した配列の要素を更新する方法についてメモします。

###例）数値型を持つ配列$arrayの各要素をforeachで取り出し、各要素に+1する

以下はNGケースです。

```
$array = [1, 2, 3];

foreach($array as $value){
    $value += 1;
}

print_r($array);

/* 実行結果　→　各要素に+1されない
Array
(
[0] => 1
[1] => 2
[2] => 3
)
*/
```

上記のコードでは配列を更新できません。foreachの仕様として、**配列要素のコピーがforeach内の変数に格納される**ため、更新ができないのです。

foreachの変数を利用して配列要素を更新するためには、参照渡しをする必要があります。
手順は以下2点です。
・更新したいforeach変数の頭に&を付与　**（参照渡し）**
・更新処理の後にunset(変数名)を記述　**（参照渡しの解除）**

以下はOKケースです。

```
$array = [1, 2, 3];

foreach($array as &$value){       //（参照渡し）
    $value += 1;
}
unset($value);                   //（参照渡しの解除）

print_r($array);

/* 実行結果
Array
(
[0] => 2
[1] => 3
[2] => 4
)
*/
```

#まとめ
foreach変数に参照渡しをすることで、配列要素とforeach変数がリンクするので、配列要素の更新が可能になります。
この点は少し注意が必要ですが、foreachを抜けた後も参照渡しをした変数には配列の最後の要素が入ったままなので、unset()で参照渡しの解除をしています。
resize_to_limit(fit)　投稿されたメッセージをビューに表示させる際に、messageとimageが異常に大きい

#今回の問題

chat-space/app/views/messages/_message.html.hamlに

```
.main-content__chat--contents
  .chat-message
    .chat-message--name
      = message.user.name
    .chat-message--time
      = message.created_at.strftime("%Y/%m/%d %H:%M")
    .chat-message--comment
    - if message.content.present?
      %p.lower-message__content
        = message.content
    = image_tag message.image.url, class: 'lower-message__image' if message.image.present?

```

と記述し、ビューを表示させると、

<img width="921" alt="スクリーンショット 2019-06-07 12.32.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432050/84224dbb-b87c-3a1d-2bc1-a0e12d87f94a.png">

imageも大きいが、messageもimageと同じ大きさで表示されてしまう。

#やりたいゴール

ちょうどいい大きさで、messageのみの時は、それ相応の大きさにする

<img width="865" alt="スクリーンショット 2019-06-07 12.34.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432050/5a010e6c-1812-8714-6ad9-84461935fc9a.png">
#原因

app/assets/stylesheets/_groups.scssに高さを指定してしまっていた。

```  
&__chat--contents{
    background-color: #fafafa;
    height: 500px;
    padding: 10px 20px;
    overflow: scroll; 
```  
heightをコメントアウトするとmessageのみの表示がちょうどいい大きさに変化した。

<img width="1189" alt="スクリーンショット 2019-06-07 12.54.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432050/b7e88307-14ff-0967-bd75-227d1575fba5.png">


しかし画像が馬鹿でかすぎる

#process resize_to_limit: [XXX, XXX]

resize_to_fitは縦横比を維持したまま、width, heightをXXXpxにリサイズしてくれる

app/uploaders/image_uploader.rbに

``` 
  process resize_to_limit: [200, 200]
```  
を記述する

#結果

<img width="699" alt="スクリーンショット 2019-06-07 17.36.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432050/9f8683e4-1971-a7c4-44c1-39982bf4bc69.png">

ちょうどいい感じに表示されるようになりました！