OmniAICreator/Qiita-1.07M huggingface dataset:
Vue で Chrome の新しいタブを VS CODE っぽい WISYWIG Markdown Editor にする拡張機能をつくりました

フロントエンド開発が趣味のUIデザイナーです。
VS CODE と Chrome と Vue が好きなので、自然とできたやつを紹介させてください。

# つくったもの
[![Tabulasa](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50195/10d2cb5d-2025-9a6a-a760-6e2e6bff5176.png)](https://psephopaiktes.github.io/tabulasa/)
https://psephopaiktes.github.io/tabulasa/
新しいタブをシンプルなMarkdownエディタにするだけのChrome拡張です。

### こだわりポイント
- デザイン ([サイト](https://psephopaiktes.github.io/tabulasa/)みて:pray:)
- ローカルホストに自動保存してくれてるので安心
- Markdownで入力すればリアルタイムにWISYWIGで表示してくれる
- :emoji:やチェックボックスなどGFMも対応
- VS CODE のキーバインディングがかなり使える
- Gistに投稿したりHTMLで保存したり地味に便利な機能

### 用途
- EvernoteやNotionなどを開くまえに、とにかくいったんメモしたいとき
- MTG中に議事録をとるとき
- PRやSlack投稿前の下書き

たまに、ブラウザで `data:text/html, <html contenteditable>` を開いて[メモ帳代わりにしている人](https://blog.56doc.net/Entry/508/)がいますが、そういう人に特におすすめしたいです。てかChromeとVS CODE使ってる人は全員さわってみてほしいです。



# 技術的な知見
いろいろ試してみた知見をメモ程度に共有しときます！

### EditorはCodeMirror
ブラウザ上で動くエディターのライブラリはいくつかあるのですが、今回は[CodeMirror](https://codemirror.net/)という歴史ある定番のヤツを採用しました。だいぶレガシーになりかけているのですが、PCだけで使うならとても良く動きますしかんたんでした。スマホでも使おうとすると厳しいらしく、[リニューアル版](https://github.com/codemirror/codemirror.next)が開発中だったりします。

ほんとはMicrosoft公式の[Monaco](https://microsoft.github.io/monaco-editor/)を使いたかったのですが、機能過多すぎるのと、デザインの自由度が全然無くてありがちになっちゃいそうでやめました。

### Dark Mode 対応はやっぱりCSS変数が便利
他でも書いたのですが、WebでもOSのLight/Darkモードに応じてデザインを出し分けられるようになりましたね。以下の記事で書いた方法で色を変数管理しながら対応させました。

> [Webのダークモード対応をSCSS変数で管理する方法を考える - Qiita](https://qiita.com/psephopaikes/items/d1d8f19b8a77d3ee3810)

今回ちゃんとダーク/ライト両方のデザインに対応させたのですが、これは最初にしっかり変数化して作らないと大変ですね。既存のページをあとから対応させると絶対抜けが出るだろうしやりたくないなあと思いました。

### SVG画像の個人的にベストプラクティス
ReactやTypeScriptでSVGの画像やアイコンを扱う場合、どうやって扱っているでしょうか？

A. publicフォルダに.svg画像ファイルを直接`<img>`タグで普通に使う
B. Component(jsファイル)にして適宜importして使う
その他 ( HTML部分に直接<svg..を書く、objectタグなど

A,Bのメリデメは以下のような感じでしょうか

 |メリット:+1:|デメリット:thumbsdown:
:--|:--|:--
A|わかりやすい<br>更新が楽|SVGの数だけリクエストが増えるので遅くなる<br>CSSでSVGをいじれない
B|インラインになるのでリクエストが減る<br>CSSで見た目を変えられる<br>StoryBookなどで管理できる|いちいち@importするのが面倒<br>更新がだるい

今回は折衷案として[vue-svg-inline-loader](https://github.com/oliverfindl/vue-svg-inline-loader#readme)を使用しました。簡単に言うと`<img svg-inline src="@/assets/icon/about.svg" />`と書くとビルド時にインラインに変換してくれるパッケージです。

個人的には↑の両方良い所どりなので、しばらくこれを使っていこうかなと思います。(PUGには非対応...)


### その他の雑感想
- pugで書くとコード量めっちゃ減るけど、@include使えないしLinterも効かないのはつらみ
- TypeScriptいちおう使ったけどぜんぜんわからん
- 個人開発だとデザインファイルもドキュメントもタスクチケットも全部GitHubにまとめるのが便利ですね



# これからの予定
> [Issues · psephopaiktes/tabulasa](https://github.com/psephopaiktes/tabulasa/issues)

- こまかいUXのブラッシュアップ
- Vue3で作り直す
- (需要ありそうなら)VimとかAtomのキーバインディングに対応

ただしばらくは[TRPG用のアプリ](https://twitter.com/psephopaiktes/status/1217409051769765888)を作る予定なので、こっちの更新は遅くなるかもです :bow:
ActiveRecord::NoDatabaseError: Unknown database 'アプリ名_development'　解決策

#RMVC設定中にrails db:migrate出来ない

localhost:3000 に'アイウエオ'と表示させたい為
rails new後にターミナルとVSCodeでRMVC設定を行う。
rails db:migrate　コマンドを打ち込んだ後に以下のエラーが発生。

・ActiveRecord::NoDatabaseError: Unknown database 'アプリ名_development'
・Mysql2::Error: Unknown database 'アプリ名_development'

databaseがないですよというエラーでした。

databaseがないのなら作ればいいのではと思い、ターミナルで以下のコマンドを打ち込む。

```
rails db:create
```

Created database 'アプリ名_development'
Created database 'アプリ名_test'　　　　　

上記の様に表示されればdatabaseが出来たはずなので改めて

```
rails db:migrate
```

これで無事migrateできました。


#参考記事（重要）
rake or rails コマンドでdbを扱うときのメモ
https://qiita.com/pugiemonn/items/e237b73025d8db8545bf
Gitの履歴から名前とメールアドレスを一括変更 (git-filter-repo)

タイトルのシチュエーションにおける方法としてgit-filter-branchを使う方法がよく紹介されていますが、git-filter-branchを使用すると[git-filter-repo](https://github.com/newren/git-filter-repo)を代わりに使用するよう警告が出るようになりました。
そこでgit-filter-repoを使う方法を紹介しようと思います。

## 前提

* git >= 2.22.0, [一部の機能](https://github.com/newren/git-filter-repo#upstream-improvements)は git >= 2.24.0
* python3 >= 3.5

参照: https://github.com/newren/git-filter-repo#prerequisites


## インストール

git-filter-branchはGitに組み込まれた機能ではないので、インストールが必要です。

pipからインストールする場合:

```sh
$ pip3 install git-filter-repo
```

パッケージマネージャからインストールする場合:

```sh
$ PACKAGE_TOOL install git-filter-repo
```

対応しているパッケージマネージャのリスト: https://github.com/newren/git-filter-repo/blob/master/INSTALL.md#installation-via-package-manager

## コマンド

まずメールアドレスをマッピングするためのテキストファイルを以下のような形式で作成します。

```
new_name <new@email.com> <old@email.com>
```

そしてリポジトリのディレクトリで以下のコマンドを実行します。

```sh
git filter-repo --mailmap mailmap
```

`mailmap`は上で作成したテキストファイルのパスに置き換えてください。
多くの場合では強制的に修正するために`-f`をつける必要があるかと思います。

```sh
git filter-repo -f --mailmap mailmap
```

参考: https://stackoverflow.com/questions/58263216/how-to-change-commit-author-for-multiple-commits-using-filter-branch
WordpressのWP Mail SMTPで証明書エラーの回避方法

# 概要
php5.3からphp7.4にバージョンアップしたところ、WordpressプラグインのWP Mail SMTPで以下のエラーが発生したので、その対処についてのメモ。

```stream_socket_enable_crypto(): Peer certificate CN=`*.example.com’ did not match```

# エラー原因
原因はphp5.6からOpenSSLがバージョンアップし、ピア証明書が必須になったため。証明書がないとエラーが発生する。

> 暗号化されたすべてのクライアントストリームで、ピア検証がデフォルトで有効になりました。 デフォルトでは、OpenSSL のデフォルト CA > バンドルを使ってピア証明書を検証します。 たいていの場合は、正しい SSL 証明書を持つサーバーと通信するならこれを変更する必要> はありません。 OpenSSL が、よく知られた CA バンドルを使うように設定されているからです。

# 対処方法
対処方法としては、証明書を用意するか、php.iniの変更か、PHPMailerの`SMTP Options`で設定するかのいずれか。
WP Mail SMTPの場合、functions.phpに以下のコードで追加する。

```functions.php

// WP Mail SMTPでメール送信元が効かなかったので設定。（証明書エラーとは関係ない）
add_filter( 'wp_mail_from', function() {
	return 'info@gmail.com'; // 送信元メールアドレス
} );

// これ以降が証明書エラーのための設定。
function my_wp_mail_smtp_custom_options ( $phpmailer ) {
	if ( isset( $phpmailer->SMTPAuth ) ) {
		if ( $phpmailer->SMTPAuth == true ) {
			$phpmailer->SMTPOptions = array('ssl' => 
array(
 'verify_peer' => false,
 'verify_peer_name' => false,
 'allow_self_signed' => true));
		}
	}
	return $phpmailer;
}
add_filter("wp_mail_smtp_custom_options", "my_wp_mail_smtp_custom_options");
```

各オプションの説明は以下の通り。

| オプション | 説明 | 初期値 |
|:--|:---|:-:|
| verify_peer       | SSLサーバー証明書の検証を要求するか否か   |TRUE |
| verify_peer_name  | ピア名の検証を要求するか否か             |TRUE |
| allow_self_signed | 自己証明の証明書を許可するか否か         |FALSE|

tetsuro.tayama@gmail.com
Truncated Distributionからのサンプリング

確率分布を$x \in[a,b]$に制限してサンプリングを行う方法のメモ。
例えば [tf.random.truncated_normal](https://www.tensorflow.org/api_docs/python/tf/random/truncated_normal)みたいなやつを使いたい時、他のフレームワークには実装が無かったりして困る。

元にする分布の確率密度関数を$f$その累積分布関数を $F$ とするとこれを $[a,b]$ で切断した分布の密度関数$g$は

$$
g(x) = \frac{f(x)}{F(b)-F(a)} \quad (a \leq x \leq b)
$$

となる。したがってこれの累積分布関数 $a \leq x \leq b$ で

$$
G(x) = \frac{F(x)-F(a)}{F(b)-F(a)}
$$

となる。よってこれの逆関数は $0 \leq x \leq 1$ で

$$
G^{-1}(x) = F^{-1}\left((F(b)-F(a))x+F(a)\right)
$$

となる。よって [逆関数法](http://nineties.github.io/math-seminar/14.html#/20) を用いて $[0,1]$ での一様乱数を $U$ とすると

$$
F^{-1}\left((F(b)-F(a))U+F(a)\right)
$$

と変換すれば求める分布が得られる。

## Truncated Normal Distribution
標準正規分布の場合で計算してみる。$\mathcal{N}(0,1)$の累積分布関数は

$$
F(x) = \frac{1}{2}\left[1 + \mathrm{erf}\left(\frac{x}{\sqrt{2}}\right)\right]
$$

と書くことが出来るので、この逆関数を求めると
$$
F^{-1}(x) = \sqrt{2}\mathrm{erf}^{-1}(2x-1)
$$

となる。PyTorchでの実装例は以下。

```python
from math import sqrt
import torch

def truncated_normal(shape, a, b):
    U = torch.distributions.uniform.Uniform(0, 1)
    u = U.sample(shape)

    Fa = 0.5 * (1 + torch.erf(a/sqrt(2)))
    Fb = 0.5 * (1 + torch.erf(b/sqrt(2)))
    return sqrt(2)*torch.erfinv(2 *((Fb - Fa) * u + Fa) - 1)
```

実験

```python
import numpy as np
from scipy.stats import norm
import matplotlib.pyplot as plt

N = 10000
a = -1.
b = 2.

samples = truncated_normal((N,), torch.Tensor([a]), torch.Tensor([b]))
plt.hist(samples, bins=100, density=True)

x = np.linspace(-3, 3)
plt.plot(x, norm.pdf(x)/(norm.cdf(b)-norm.cdf(a)))
plt.savefig('truncated_norm.png')
```

良さそう。

![4A58E631-93DC-48BB-B305-16018EFE649D.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83682/38d701e3-e7f3-0fa7-49cd-5561b6e60c39.png)
WKWebViewでローカルリソースにAjaxアクセスする場合について

Monacaで利用しているCordovaでは、ローカルリソースにアクセスする場合、`file://スキーム`が使用されます。

WKWebViewでは、セキュリティーの制約により、ローカルリソースに対して「file://スキーム」を使用してAjaxアクセスすることができません。この問題に対応するために、Monacaから `Custom Schemeプラグイン` がリリースされました。

# 注意点
- このCustom Schemeプラグインは、`iOS 11以降` から利用することができます。
  そのため、 以下のように config.xml にiOSの `Deployment Target` を指定する必要があります。

  ```xml:config.xml
  <platform name="ios">
    <preference name="deployment-target" value="11" />
  </platform>
  ```

- Custom Schemeプラグインの動作を確認する場合は、デバッグビルドで確認する必要があります。WkWebView が `有効` になっているカスタムビルドデバッガーでは、デバッガー内で設定が行われているため `Custom Schemeプラグイン` が `無効` の状態でもローカルリソースにAjaxアクセスすることができます。


# Custom Schemeプラグインの利用方法

Custom Schemeプラグインを利用する場合は、Monacaプロジェクトの

設定 > Cordovaプラグインの管理 > 利用可能なプラグイン > Custom Scheme

を `有効` にします。その他の設定は、必要ありません。


## Custom Schemeプラグインの動作確認

今回は、ローカルリソースとしてJSONファイルにAjaxアクセスして動作確認を行ってみたいと思います。

Monacaプロジェクトの `www` フォルダーに検証用のJSONファイルを作成します。検証用データは、以下を使用します。ファイル名は `test.json` にしています。

```json:test.json
{
  "name": "Monaca", 
  "age": 1000
}
```

検証コードは、以下になります。
今回、Ajaxアクセスには `Fetch API` を使用しています。

```html
<script>
  function test01() {
    fetch("test.json")
      .then(function(response) {
        alert("response.status: " + response.status);
        alert("response.ok: " + response.ok);

        if (response.ok) {
          response.json().then(function(json) {
            alert(JSON.stringify(json));
          })
        }
      })
      .catch(function(error) {
        alert("error: " + error);
      });
  }
</script>

<body>
  <input type="button" value="Fetch APIテスト" onclick="test01()" />
</body>
```

MonacaプロジェクトのiOSアプリ設定画面から WkWebView を `有効` にして、Custom Schemeプラグインを `無効` にしている場合は、以下のようなエラーが出力されます。

```
TypeError: Cross origin requests are only supported for HTTP.
```

iOSアプリ設定画面から WkWebView を `有効` にして、Custom Schemeプラグインも `有効` にしている場合は、正常に test.json にアクセスされ、以下の内容が出力されます。

```
response.status: 200
response.ok: true

{"name":"Monaca","age":1000}
```

# おわりに

WKWebViewを使用してローカルリソースにAjaxアクセスする必要がある場合は、Custom Schemeプラグインを `有効` にしてご利用ください。
Answer Set Programming

Answer Set Programming がなんか使えそうと思ったので勉強中。
例題を通じて理解を深めようと思っている

#Answer Set Programming(ASP)とは
組み合わせの問題を解決するためのツール。
https://potassco.org/

#例題
[例題０ 組み合わせ](https://qiita.com/Ganesha/items/9e6f7481a8409cf90ecc)
[例題１ コイン問題（制約充足問題）](https://qiita.com/Ganesha/items/68cbc856662085830f2a)
[例題２ コイン問題２](https://qiita.com/Ganesha/items/89e1fc2c6778974587f5)

以下予定
~~[部分和問題]()~~
~~[魔法陣]()~~
~~[グラフ彩色問題]()~~
~~[数独]()~~
~~[ビンパッキング問題]()~~
~~[ナップサック問題]()~~
~~[クイーン問題]()~~
~~[制約最適化問題]()~~
~~[ハノイの塔]()~~
~~[巡回セールスマン問題]()~~
~~[ブロックワールド問題]()~~

# 参考
https://potassco.org/
https://qiita.com/yutaro-t/items/3a361aef5f9610ae4b8e
[Coprisによる制約プログラミング入門](http://bach.istc.kobe-u.ac.jp/copris/docs/intro-ja.html)
Rails-APIでsorceryを使ったらundefined local variable or method `form_authenticity_token'と怒られた

## 概要

Rails-APIにて認証用のgem sorceryを使ってloginメソッドを叩いた時に

```
undefined local variable or method `form_authenticity_token'
```
と怒られたので解決策を書きます。

## 環境
ruby 2.6.5
Rails 6.0.2.1
sorcery (0.14.0)

## 結論
ログイン処理を行うコントローラーに下記を追加すればOK

```ruby:sessions_controller.rb
private

def form_authenticity_token; end
```

## 原因
[こちらの記事](https://github.com/NoamB/sorcery/issues/724)によると、ユーザーがログインする際にCSRFトークンがリセットされるのですが、それを行うform_authenticity_tokenメソッドがRails-APIに存在しないかららしいです。

このメソッドがないと動作が保証されないので、とりあえず自前で空メソッドを用意してくれ、とのことでした。

見た目はブサイクになりますが仕方なくこれで対応して無事に動きました。
作図に便利！！「diagrams.net」

# 概要
Home Page：<a href="https://www.diagrams.net">https://www.diagrams.net</a>

Home Pageより（DeepL翻訳）
> 誰とでも、どこでもダイアグラム。
diagrams.netは、オープンソース、オンライン、デスクトップ、コンテナで展開可能なダイアグラム・ソフトウェアです。

仕事関連（システム開発）ドキュメントに、システム構成図／ソフトウェアスタック図等を効率良く、再利用出来るツールを探した結果、
「diagrams.net」に辿り着きました。
Office系(Word／Power Point／Excel)アプリでの作成はストレスでした。

# 起動
Home Pageの「Start」でブラウザ上にツールが起動します。

![alt](http://www.cloudsquare.jp/kumonosu/wordpress/wp-content/uploads/2020/04/diagrams_net_01.png)

起動後「新規ファイルを作成する」or「既存のファイルを開く」を選択。
右下の言語で各言語に変更出来ます。変更後は再更新で反映です。

![alt](http://www.cloudsquare.jp/kumonosu/wordpress/wp-content/uploads/2020/04/diagrams_net_02.png)

「既存のファイルを開く」は保存したデータファイルを開きます。
「Change storage」で保存先を変更出来ます。
・Google Drive
・One Drive
・デバイス（ローカルドライブ）
・DropBox
・GitHub
・GitLab

![alt](http://www.cloudsquare.jp/kumonosu/wordpress/wp-content/uploads/2020/04/diagrams_net_03.png)

# 画面
画面は標準的な作りのため、特に困らず使用出来ると思います。

![alt](http://www.cloudsquare.jp/kumonosu/wordpress/wp-content/uploads/2020/04/diagrams_net_04.png)

分かりづらいのですが左下に「＋その他の図形...」があります。
使用する図形を追加出来ます。
Google Cloud Platform図形、ネットワーク図形等々。
必要なものを追加すれば大抵は事足りると思います。
足りない場合、オリジナル図形はメニューバーの「＋」－「イメージ」から追加出来ます。

![alt](http://www.cloudsquare.jp/kumonosu/wordpress/wp-content/uploads/2020/04/diagrams_net_05.png)

# iPad
ブラウザで起動するアプリのため、iPadでも使用可能です。
最近話題のMagic Trackpad 2やマウスとキーボードを用意すればPCと変わりなく。

# デスクトップアプリ版
macOS／Windows／Linux／Chrome OS版があります。
macOSでインストール、起動しました。
ブラウザ版と変わりません。オフラインで使えます。

![alt](http://www.cloudsquare.jp/kumonosu/wordpress/wp-content/uploads/2020/04/diagrams_net_06.png)
Amazon Cognito Identity Providerのエラーレスポンス

[Amazon Cognito Identity Provider](https://docs.aws.amazon.com/ja_jp/cognito-user-identity-pools/latest/APIReference/Welcome.html)では異なるエラー内容でも同じエラーコードが発行されるものがある。
エラー内容ごとにエラーハンドリングを行う必要がある場合は、エラーメッセージを確認することで区別が可能である。
ここでは一部の実際に確認したものを掲載する。

# AliasExistsException

- `{'Message': 'Already found an entry for the provided username.', 'Code': 'AliasExistsException'}`

# CodeMismatchException

- `{'Message': 'Invalid session provided', 'Code': 'CodeMismatchException'}`

# ExpiredCodeException

- `{'Message': 'Invalid code provided, please request a code again.', 'Code': 'ExpiredCodeException'}`

# GroupExistsException

- `{'Message': 'A group with the name already exists.', 'Code': 'GroupExistsException'}`

# InvalidParameterException

- `{'Message': 'Attributes did not conform to the schema: {attributes}: Attribute does not exist in the schema.\n', 'Code': 'InvalidParameterException'}`
- `{'Message': 'Invalid email address format.', 'Code': 'InvalidParameterException'}`
- `{'Message': "1 validation error detected: Value 'string' at 'userPoolId' failed to satisfy constraint: Member must satisfy regular expression pattern: [\\w-]+_[0-9a-zA-Z]+", 'Code': 'InvalidParameterException'}`

# InvalidPasswordException

- `{'Message': 'Password did not conform with password policy: Password not long enough', 'Code': 'InvalidPasswordException'}`
- `{'Message': 'Password did not conform with password policy: Password must have uppercase characters', 'Code': 'InvalidPasswordException'}`
- `{'Message': 'Password did not conform with password policy: Password must have numeric characters', 'Code': 'InvalidPasswordException'}`
- `{'Message': 'Password did not conform with password policy: Password must have lowercase characters', 'Code': 'InvalidPasswordException'}`

# LimitExceededException
- `{'Attempt limit exceeded, please try after some time.', 'Code': LimitExceededException'}`

# NotAuthorizedException

- `{'Message': 'Incorrect username or password.', 'Code': 'NotAuthorizedException'}`
- `{'Message': 'Invalid Access Token', 'Code': 'NotAuthorizedException'}`
- `{'Message': 'Invalid Refresh Token', 'Code': 'NotAuthorizedException'}`

# ResourceNotFoundException

- `{'Message': 'Group not found.', 'Code': 'ResourceNotFoundException'}`

# UsernameExistsException

- `{'Message': 'User account already exists', 'Code': 'UsernameExistsException'}`
- `{'Message': 'An account with the email already exists.', 'Code': 'UsernameExistsException'}`

# UserNotFoundException

- `{'Message': 'User does not exist.', 'Code': 'UserNotFoundException'}`
初心者によるプログラミング学習ログ 280日目

#100日チャレンジの280日目
twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。
100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
280日目は、
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">おはようございます<br>280日目　2.5h<br>・xdデザインカンプからのサイト模写<br>・メンターさんからの修正をやる<br>・ヘッダーの上部とフッターの下部の謎隙間解決に手間取る<a href="https://twitter.com/hashtag/%E6%97%A9%E8%B5%B7%E3%81%8D%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash&amp;ref_src=twsrc%5Etfw">#早起きチャレンジ</a><a href="https://twitter.com/hashtag/%E9%A7%86%E3%81%91%E5%87%BA%E3%81%97%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%A8%E7%B9%8B%E3%81%8C%E3%82%8A%E3%81%9F%E3%81%84?src=hash&amp;ref_src=twsrc%5Etfw">#駆け出しエンジニアと繋がりたい</a><a href="https://twitter.com/hashtag/100DaysOfCode?src=hash&amp;ref_src=twsrc%5Etfw">#100DaysOfCode</a></p>&mdash; ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) <a href="https://twitter.com/yudapinokio/status/1246171661843357696?ref_src=twsrc%5Etfw">April 3, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
PHP基本集(2)~フォーム作成~

###【formタグ】　
```php
<form action="(urlを入力する)" method="（postもしくはgetを入力する）"> 
//urlには階層を意識したファイル名でも可能
//methodのgetは送信される値がURLに表示され、postの場合はURLに表示されない
</form>
```

###【inputタグ】
<img width="338" alt="スクリーンショット 2020-04-04 3.51.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/ecaed9d0-0ebc-00d8-98da-a30878063918.png">

```php
<form action="(urlを入力する)" method="（postもしくはgetを入力する）"> 
  Emailを入力してください
  <input type="text" name="email">  //name属性は入力された値の取得に使用され、データを受け取る時のキーとして使用する
</form>
```

**入力値を受け取りたい場合**
formタグに入力して送信したデータ内容を受け取る場合は、「**$_POST**」を使用する。
$_POST」は連想配列となっており、**キーが「name属性の値」**と**値が「入力値」**となる。

```php
<?php
  $_POST['email'];  //['']には取得したいタグのname属性の値を入力する
?>
```

###【textareaタグ】
<img width="494" alt="スクリーンショット 2020-04-04 3.54.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/96a3dc32-3eb4-0995-0869-4b879186c0a1.png">

```php
<form action="(urlを入力する)" method="（postもしくはgetを入力する）"> 
  内容
  <textarea name="content"></textarea> //改行を含む文章のためのテキストボックス
</form>
```

**入力値を受け取りたい場合**
選択したoptionタグのデータ内容を受け取る場合

```php
<?php
  $_POST['content'];  //['']には取得したいタグのname属性の値を入力する
?>
```

###【送信ボタン】
<img width="148" alt="スクリーンショット 2020-04-04 3.57.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/3dfb536c-54ff-ef54-38ca-04ae8bffdc9b.png">

```php
<form action="(urlを入力する)" method="（postもしくはgetを入力する）"> 
  <input type="submit" value="送信">  //typeを「submit」とし、表示させる文字を「value」に記述する  
</form>
```

###【selectタグ・optionタグ】
<img width="367" alt="スクリーンショット 2020-04-04 4.07.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/c2718c66-3796-3064-6382-e7cecbe948a3.png">

```php
<form action="(urlを入力する)" method="（postもしくはgetを入力する）"> 
  <select name="fruits">  //selectタグの中に選択肢となるoptionタグを記載する
    <option value="apple">りんご</option>  //選択したoptionタグのvalue属性が送られる
    <option value="banana">ばなな</option>
    <option value="orange">おれんじ</option>
  </select>
</form>
```
**入力値を受け取りたい場合**
選択したoptionタグのデータ内容を受け取る場合

```php
<?php
  $_POST['fruits'];  //['']には取得したいタグのname属性の値を入力する
?>
```

###【繰り返し処理と変数展開を用いて多数のoptionタグを作る】

<img width="375" alt="スクリーンショット 2020-04-04 4.16.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/159b8855-e686-ce86-982e-aa3772cf5bcd.png">


```php
<?php
  for($i = 1; $i =<3; $i++) {
    echo "<option value='{$i}'>{$i}</option>"
  }
?>
```

###【配列要素を繰り返し表示させる】

<img width="216" alt="スクリーンショット 2020-04-04 4.22.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/29be4a66-d166-04aa-b644-676af66ecdb6.png">

```php
<?php 
  $types = ['お問い合わせ', 'ご意見・ご要望', '採用に関するお問い合わせ', '取材・メディア関連のお問い合わせ', '料金に関するお問い合わせ', 'その他'];
?>

  <select name="category">
    <option value="noSelect">選択してください</option>
    <?php
      foreach($types as $value) { //配列$typesに入れられた要素を$valueという名前で変数化
        echo "<option value='{$value}'>{$value}</option>";
      }
    ?>
 </select>
```

今回はここまで:santa:
【React Native + Expo】 iOSシミュレータを複数起動する

# 前提
- React Native 0.61.4
- Expo 3.17.11

# 背景
RN開発をしていると、プルリクで複数デバイスでの見栄えのキャプチャを添付することがよくある。
Vanilla React Nativeであれば、複数のシミュレータを
`react-native run ios --simulator simulator-name`から起動すればよい。

しかし、ExpoはExpoのクライアントアプリが必要かつ、expoコマンドで起動するので、
シミュレータを指定する方法が不明だったので、調べる必要があった。

基本的には[こちらの参考記事](https://stackoverflow.com/questions/53924934/can-i-run-my-expo-app-on-multiple-ios-simulators-at-once)にしたがって進めればいいのだが、手元ではExpoがインストールされない問題にぶち当たったので、その解決方法を記す。

# 方法

## 結論
上記参考記事を要約すると、xcrunコマンドを駆使してforループでシミュレータ起動&Expoインストールをすればよいということだ。
そして、僕が手元でうまくいかなかったExpoのインストールは、初回のみ対象のシミュレータを個別で `expo start` で起動してインストールする。
（Expoは自動で最後に開いていたシミュレータを起動する）

以下はその具体的な手順。

## 記事の方法
念のため、まずは参考記事の方法から。
（繰り返しだが、これでうまく行けばいいが、手元ではうまくいかなかった）

- iOS simulatorのIDを取得する

```bash

xcrun simctl list
```

- 一覧から、目的のシミュレータのIDを変数 `simulators` に格納

```bash

declare -a simulators=("YOUR-SIMULATOR-ID1" "YOUR-SIMULATOR-ID2" "YOUR-SIMULATOR-ID3")
```

- Expoのバージョン確認

```bash
expo --version
```

- installするExpoのバージョンを前述のバージョンに変更し、以下のコードを実行する

```bash

for i in "${simulators[@]}"
do
    xcrun instruments -w $i
    xcrun simctl install $i ~/.expo/ios-simulator-app-cache/Exponent-3.17.11.app # バージョンによって"3.17.11"の部分を変更する
    xcrun simctl openurl $i exp://127.0.0.1:19000      
done
```

だが、何度やってもシミュレータが立ち上がるまでで、Expoがインストールされない。

## Expoをシミュレータに個別でインストールする

様子を個別にみるため、forループを外してやってみたところ、以下のエラーが起きていた。

```bash

xcrun simctl openurl YOUR-SIMULATOR-ID exp://127.0.0.1:19000
An error was encountered processing the command (domain=NSOSStatusErrorDomain, code=-10814):
The operation couldn’t be completed. (OSStatus error -10814.)
```

要するにインストールできませんでしたよと。

色々調べていたが、途中で面倒になったので、Expoの自動インストールに任せることにした。

Expoは最後に起動したシミュレータを起動するようなので、対象のシミュレータを一度起動し、最後に閉じる。
方法は何でもいいが、

例えば、以下の記事や、
https://stackoverflow.com/questions/47709953/expo-change-default-ios-simulator

あるいは、以下のコマンドでも出来る

```bash

xcrun instruments -w YOUR-SIMULATOR-ID #シミュレータの起動
```

Expoが未インストールのシミュレータを最後に閉じるのを確認した上で、もう一度、

```bash

expo start
```

これでExpoが入って、アプリが立ち上がるはず。

一度Expoを入れてしまえば、今後は以下のコマンドで３つとも立ち上がる。

```bash

declare -a simulators=("YOUR-SIMULATOR-ID1" "YOUR-SIMULATOR-ID2" "YOUR-SIMULATOR-ID3")
for i in "${simulators[@]}"
do
    xcrun instruments -w $i
    xcrun simctl openurl $i exp://127.0.0.1:19000      
done

```

# 編集後記
もっとスマートな方法があるはずだが、30分ほどエラーと戦って面倒くさくなってやめました。
もし見つけた方は教えてくださると幸いです。
PyTorch Tacotron(ForwardTacotron)を TorchScript に変換し libtorch で C++ で動かす

## 背景

libtorch で Tacotron を動かし, モバイルで on device で neural text-to-speech したい.

tensorflow 版はこちら

Tacotron(Neural text-to-speech) の推論を C++ で動かす(2019 年 6 月 8 日時点 78% くらい C++).
https://qiita.com/syoyo/items/8cf844e277952f4d8c6b

今回は ForwardTacotron https://github.com/as-ideas/ForwardTacotron を変換します.

## 問題点

一応動きはするのですが, 結果の音声がちょっとおかしいです.
プロダクション利用の場合は, 現状は Tacotron 系は TensorFlow 版(libtensorflow_inference)を使うのがよいでしょう.
(vocoder として libtorch での WaveGlow などを使うとした場合, libtorch と libtensorflow_inference を混在してのビルドができるのは確認しています)

## 環境

* pytorch(libtorch) v1.4.0
  * ちなみに, 最新 `master`(v1.5.0 相当)だと, よりエラーメッセージなどが詳細になりデバッグしやすくなっています. 

## 流れ

tensorflow 版とだいたい同じです.

- Sequence(int64 配列)は C++ 側で用意する
- Network(`forward`)部分を TorchScript へと変換する
  - Python コードに型を与える
  - mel スペクトログラムを作るところまで
  
Mel から Wav を作る部分(e.g. WaveRNN, WaveGlow など)は別途です. 

型付けは 

PyTorch model を libtorch で C++ 実行するための, Python スクリプトへの型付けメモ
https://qiita.com/syoyo/items/ee398a4648c1bb5fe533

を参照ください

間違った型を付けてしまうと問題があるかもしれません. 素の Python + typing module だと, Python で実行するぶんには型チェックとエラーを出してくれないようなので, mypy あたりと組み合わせるといいかもしれません.

ForwardTacotron を fork して, `torchscript` branch に, モデルを TorchScript 変換できるようにしたものをアップロードしました.

https://github.com/syoyo/ForwardTacotron/tree/torchscript


## 結果を保存する

結果の MEL データは [80, N] の 2D tensor です(80 = n_mel). 

`torch::save(x, "file.pt")` でファイルに保存できます.

https://github.com/pytorch/pytorch/issues/19025

ただ, `torch::save` だと, NPZ 形式でいろいろメタ情報がついてそのままでは python 側でうまく再読み込みできません.(Python で `torch.load` すると, `No module names '__torch__'` エラー) 

適当に numpy ascii(`np.loadtxt` で読める形式)などにして保存しましょう.
また, `std::stringsteam` でメモリ(バイナリストリーム)に保存することもできます!

https://github.com/pytorch/pytorch/issues/19025


あとはこの mel データを griffin-lim, WaveRNN, WaveGlow などの vocoder で変換すれば WAV ができます! 

## 動きはするが...

PyTorch Tacotron を C++(モバイル)で動かすのは, 1 年以上(2 年未満)想いを馳せていたことでしたので, libtorch + TorchScript により実現したことに感動ひとしおです.

しかし, 生成される音声はちょっとへんです.
(両方とも, WaveRNN で mel -> wav 生成しています)

pytorch リファレンス
https://clyp.it/qj0x20re

libtorch 実行
https://clyp.it/5chrtz3a

(最初が切れている + 不明瞭)

libtorch のほうは生成するたびに音声の長さが変わる(抑揚などが変わる)ので, DurationPredictor あたりの振る舞いがどうもおかしいです(また, たまに実行が失敗したりもする). 並列処理だったり, 精度だったり, 乱数の初期化や生成(Dropout まわり?)で Python と振る舞いが異なるものがあるのかもしれません.

状況は v1.4.0 でも `master`(v1.5.0 相当)でも同じでした.

DurationPredictor あたりを libtorch(C++) で書き直しするといいかも?

動作は Ryzen9 3950X で確認しました. libtorch 実行は少なくとも pytorch での実行より早いでした(モデルデータのロードなど込みでも).


## TODO

* [ ] libtorch 実行の結果がおかしい原因をつきとめる
* [ ] Trace 形式(`torch.jit.trace`)に変換できないか試す
  * [ ] 現状 duration predictor が毎回異なる長さの tensor を返すため trace 形式への変換が失敗するが, この辺りうまく固定長にすればいけるかも.
* [ ] Vocoder 部分(WaveRNN, WaveGlow, SqueezeWave, and so on)も libtorch で動かす.
* [ ] **優秀な text-to-speech 若人さまが, libtorch により人類史上最速で優秀な C++ neural text to speech 若人さまへと昇華なされるスキームを確立する旅に出たい**
【JavaScript】月初・月末取得や日数0付けや日付比較

## 概要

JavaScriptのDateオブジェクトを使用している中で、よく忘れてしまう事を備忘録として残します。

## 月初の取得

```js
 function getFirstDate (date) {
   return new Date(date.getFullYear(), date.getMonth(), 1);
 }
 var date = getFirstDate(new Date());
 console.log(date); // Wed Apr 01 2020 00:00:00 GMT+0900 (日本標準時)
```

## 月末の取得

```js
 function getLastDate (date) {
   return new Date(date.getFullYear(), date.getMonth() + 1, 0);
 }
 var date = getLastDate(new Date());
 console.log(date); // Thu Apr 30 2020 00:00:00 GMT+0900 (日本標準時)
```

## 日付や月の前に0を付ける

```js
 var today = new Date();
 var date = ("0"+today.getDate()).slice(-2);
 var month = ("0"+ (today.getMonth()+1)).slice(-2); 
 console.log(`${today.getFullYear()}-${month}-${date}`) // 2020-04-04  
```

## 日付の比較

```js
 var date1 = new Date();
 var date2 = new Date("2020-03-01");
 console.log(date1.getTime() > date2.getTime()) // true
```
rolling rankを行うpythonライブラリを作りました

## rollingrank

rollingrankという、rolling window内での順位を計算するpythonライブラリを作ったので紹介です。kaggleで使ってください。バグ報告はgithubのissueでお願いします。

リポジトリ
https://github.com/contribu/rollingrank

## 背景

1. kaggleなどで時系列予測の問題を解きたい。
2. rolling window内での順位を特徴量としたい。
3. それを行うpythonライブラリが見つからなかった。
4. pandasでの実装は見つかったが遅かった( https://github.com/pandas-dev/pandas/issues/9481 )

私が解いていた問題では、
rolling window内での順位を特徴量とすることが汎化性能を出す鍵になりました。
時期によって分布が偏らないことがポイントと見ています。

有用そうな一方で(自分の事例しか知らないので一般に有用かどうかは知らない)、
kaggle界隈ではあまり見かけません。

その理由はかんたんに使えないことが原因かもしれません。
このライブラリを使うとかんたんにrolling rankを使えるので、とりあえず今解いている問題で使ってみては？

## インストール

```bash
pip install rollingrank
```

## 使い方

```python
import numpy as np
import rollingrank

# numpy arrayを入力すると同じ長さのnumpy arrayが返ります。
x = np.array([0.1, 0.2, 0.3, 0.25, 0.1, 0.2, 0.3])
y = rollingrank.rollingrank(x, window=3)
print(y)
# [nan nan  2.  1.  0.  1.  2.]

# pctを使うと、[0, 1]で返ります
y = rollingrank.rollingrank(x, window=3, pct=True)
print(y)
# [nan nan 1.  0.5 0.  0.5 1. ]

```

## 順位のカスタマイズ

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.rank.html

に定義してあるmethodのうち、average, min, max, firstをmethodオプションで渡して使えます。

## 注意

計算量が、O(n * log(w))のものを作りたかったのですが、
実装してからよく見ると O(n * w)になっていました。
平衡木を工夫すれば O(n * log(w))にできるはずです。
だれかお願いします。

以下のようなものを改造すれば良さそう。
https://github.com/mpaland/avl_array

## 個人メモ

pipライブラリの作り方: https://blog.amedama.jp/entry/packaging-python

rolling rank: https://github.com/pandas-dev/pandas/issues/9481

C++との連携はpybind11が便利でした。
Vue.jsのthis変数を可変的、動的に変更する

Vue.jsの`this`変数を可変的に変更したいときがあったけども、ぐぐっても出てこなかったのでメモ。

`.`を付けずに、`[]`を使用して表現する。
javascriptでObjectを扱うのと同じですね。

```javascript:vue.js
data() {
  return {
    isCheck: false
  }
},
methods: {
  CheckFunc: arg => {
    // 正解例
    // this.isCheckと同義
    this[arg] = true;
    
    // NG例
    this.[arg] = true;
  }
}

```

実は公式リファレンスにサラッと書いてある。
https://jp.vuejs.org/v2/cookbook/adding-instance-properties.html
Rail enumで2択のデータを保存する方法(integer型)

##　概要

こんにちは。
個人アプリの作成過程でラジオボタンで２択のデータを保存する機能を実装したので、残しておきます。
今回はMaterializeを使用しています。

こんな感じです。

[![Screenshot from Gyazo](https://gyazo.com/9ecdcbf7665f401c1b9f10b051611cae/raw)](https://gyazo.com/9ecdcbf7665f401c1b9f10b051611cae)

### 手順
* integer型でカラムを作成
* モデルにenumを記述
* view側に記述

## integer型でカラムを作成

ポートフォリオでカフェを投稿するアプリを作成したので今回は

**wifi**カラムをinteger型で作成します。

```ruby:add_columnn.rb
  def change
    add_column :shops, :wifi, :integer
  end
```
##モデルにenumを記述

```ruby:shop.rb
  enum wifi: { yes: 1, no: 2 }
```

コンソールでは

```
pry(main)> @shop.wifi = 1
=> 1
pry(main)> @shop.wifi
=> "yes"
```

このようにenumに設定したvalueが出力されます。


## viewに記述

form_forでラジオボタンからデータを送ります。

```html
<%= form_for(@shop) do |f| %>
  <%= f.radio_button :wifi, :yes %> # チェックすると1が入る
  <%= f.radio_button :wifi, :no %> # チェックすると2が入る
<% end %>
```

私はmateriarizeで実装したのでこんな感じになりました。

```html:例
<%= form_for(@shop) do |f| %>
  <div class="col s12 radio_col">
    <label>
      <span class="list">Wifi</span>
      <i class="material-icons small">wifi</i>
      <%= f.radio_button :wifi, :yes, class: "with-gap"%>
      <span>有</span>
    </label>
    <label>
      <%= f.radio_button :wifi, :no, class: "with-gap"%>
      <span>無</span>
    </label>
  </div>
<% end %>
```

表示は

```html
<% @shop.wifi %>
valueが1なら
"yes"
valueが2なら
"no"
と表示される
```

if文では

```html
<% if shop.wifi == "yes" %>
```
と書く
== 1ではfalseになってしまいました。

また,enum時点で文字列でも設定できるみたいです！

次回はJqueryで選択解除する方法をあげたいとおもいます！
Elasticsearchの認証ユーザーを構築前に事前登録する

# 概要

ElasticsearchはX-packセキュリティを有効にすることで、**無料の範囲内で**Basic認証を設定可能です。
設定方法は[Elasticのブログ](https://www.elastic.co/jp/blog/getting-started-with-security)などに詳しくまとまっていますが、クラスター構築後にユーザー登録で手作業が発生してしまいます。
ESをDocker imageやTerraformなどを使って自動構築できる作りにしてあると、なんとか手作業を避けたいです。

この記事ではESの起動時に各ノードにBasic認証が設定された状態で起動する方法を紹介します。
対象のバーションはElasticsearch7で、Docker imageで構築することを前提としています。


## Elasticsearch

```yaml:elasticsearch.yml
xpack.security.enabled: true
```

の一行を追加して X-packセキュリティを有効にします。 
これだけでBasic認証が有効になります。 この設定のESを起動して、`curl -I http://<ES_NODE>:9200` などでアクセスを試みると、`HTTP/1.1 401 Unauthorized` が返されることがわかります。
ESはビルトインユーザとして4ユーザー(`elastic` 、`kibana`、`logstash_system`、`beats_system`）が事前に登録されています。

これらのユーザーのパスワードは

```sh
$ sudo bin/elasticsearch-setup-passwords interactive
```


を実行することでインタラクティブに設定可能なので、これをDockerfileに記述して起動前に実行することで、各ユーザーのパスワードを事前に設定しておくことができます。
`elastic` のパスワードについては、以下のコマンドを使うことで、Dockerfileから直接実行することができます。

```Dockerfile:Dockerfile
RUN echo <YOUR_PASSWORD> | bin/elasticsearch-keystore add "bootstrap.password" -xf
```

 `<YOUR_PASSWORD> `には設定したいパスワードを記載します。
パスワードは秘匿情報のため、Github等でバージョン管理している場合は、CIから渡す作りにするといいでしょう。

```sh

$ sed -i "s/<YOUR_PASSWORD>/${YOUR_PASSWORD}/g" Dockerfile
```


以上の設定で、 `elastic` ユーザのパスワードが設定された状態で起動されます。構築されたESに対して

```
$ curl -u elastic:<YOUR_PASSWORD> <ES_NODE>:9200/_cluster/state
```

のように認証付きでリクエストすると、検索やindexingが可能なことがわかります。


## Kibana

kibanaからBasic認証を有効にしたESクラスターに対してアクセスすると、以下のように認証情報の入力を求められます。

<img width="40%" alt="kibana" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81805/6b29e2ad-da7a-6aaf-7407-41e33d91a9a8.png">

これを突破するには、 kibana.yml にESに登録した認証情報を追加します。

```yml:kibana.yml
x-packxpack.monitoring.enabled: true
elasticsearch.username: elastic
elasticelasticsearch.password: <YOUR_PASSWORD>
```

## Kibana Monitoring


Basic認証を有効にしたESクラスターに対して、Kibanaモニタリングを使う場合は、別途 elasticsearch.ymlにモニタリング用の認証情報を追加する必要があります。

```yml:elasticsearch.yml
xpack.monitoring.exporters.my_remote.auth.username: elastic
xpack.monitoring.exporters.my_remote.auth.password: <YOUR_PASSWORD>
```

これを設定することで、Kibanaモニタリングを使うことができます。

<img width="70%" alt="kibana" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81805/7c0d6274-1492-a8df-c015-b164683a2a77.png">

元記事: https://medium.com/@hinatades/basic%E8%AA%8D%E8%A8%BC%E4%BB%98%E3%81%8Delasticsearch%E3%82%92%E8%87%AA%E5%8B%95%E6%A7%8B%E7%AF%89%E3%81%99%E3%82%8B-27aa22a4754
Rustの特徴的なところ(構文編)

Rustを勉強中ですが、押さえておいた方が良いなという構文をまとめました。
Ownershipは別立てでまとめようと思ってます。

# 変数のmutable/immutable

並行プログラミングを安全・簡単に記述するための"nudge"の１つ
筆者私見: ある処理ブロックの中で変数が変わらないことを保証する役目

```rust
let x = 5;
x = 6; // できない！！
```

```rust
let mut x = 5;
x = 6; // できる！！
```

ただしimmutableでも下記のようなreassignはできる

```rust
let x = 5;
let x = 6; // できる！！
```

またimmutableでも型が違う値は代入できない

```rust
let mut x = 5;
x = "5"; // できない!!
```

しかし、reassignでは違う型を代入できる（新しい宣言なので当たり前か）

```rust
let x = 5;
let x = "6"; // できる！！
```


# データ型

Rustは静的型付け言語
そのためコンパイラに教えるためのtype annotationが必要

```rust
let guess: u32 = "42".parse().expect("Not a number!"); // 非負整数であることをannotationする必要がある
```

これはResult型でも一緒

```rust
let res: Result<u32, ParseIntError> = "-42".parse();    
match res {
    Ok(n) => println!("{}", n),
    Err(err) => println!("Error: {:?}", err),
}
```

データ型は以下の二種類に分かれる
- Scalar
- Compound

Scalarは整数型などの、単一値で
Compoundはtuple, arrayの複数値をもつ型

# Function

基本的に他の言語とほとんど同じ
ただし返り値にreturnがいらない。(あっても良い)

```rust
fn ret_test() -> i32 {
    let x = 5;
    x
}
```

また、Statementには返り値の概念はないが、Expressionには返り値の概念がある。
下記もExpressionの１つ

```rust
let y = {
    let x = 5;
    x
};
// y => 5
```

関連して、`if`もExpressionなので以下のような書き方ができる

```rust
let number = if condition {
    5
} else {
    6
};
// condition = true なら number => 5
```

# Control flow

loop構文がある。
breakした値を返り値とできる。

```rust
let mut index = 0;
let result = loop {
    println!("loop!");
    index += 1;
    if index == 5 {
        break index;
    }
};
```

ちなみにwhileやforでは常に空のtupleが返却される。

```rust
let result2 = while index < 10 {
     println!("the value is: {}", index);
     index += 1;
};
println!("result2 {:?}", result2); // => result2 ()
#PowerApps と タイムゾーンのおはなし

今回は、Power Apps とデータソースのタイムゾーンについて、です。

# 検証アプリの概要
文章で説明するのはとても大変なので、簡単なアプリで説明します。

## データソース
UTC（協定世界時）の SharePoint Online（以降、SPO）環境と、UTC+9:00（日本時間)のSPO、2つの環境を準備しました。

・UTC
![図5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/def91b94-ac3f-9503-8c6a-25c729d14c8e.png)
・日本時間
![図6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/b01d858a-5b55-2a45-e486-80df91e3ab1c.png)

利用するデータソースは、どちらも上記サイトにカスタムリストを新規追加して、更新日時をビューで表示するようにしただけなので割愛。なお、SPOのリストは新規登録時にも、必ず登録日時で“更新日時”の列もあわせて値が登録されます。

## アプリ
Power Apps で前述2つのSPOリストへ接続。

まず、1つ目のScreenにギャラリーを設置して、UTC、日本時間、各々の[タイトル]と[更新日時]を表示するように設定。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/fedc69b7-1b4c-2429-0037-49eda4f8fefe.png)
続いて、2つ目のScreenを追加し、Formコントロールでタイムゾーン＝UTCのリストをNow()関数（システム時間）でListのタイトルへ新規追加するようにします。これで、準備したデータソースのListへタイトルが登録され、あわせて更新時間も設定されるようになりました。
![図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/2f3419e7-31ae-dcdc-236e-f6902a57f7d2.png)
上記の2つ目のScreenを複製して、3つ目のScreenは日本時間のリストを処理するようにすれば完成です。

なお、Power Apps 自体の環境設定は［UTC+9:00（日本時間）］にしてあります。

# 動作イメージ
<blockquote class="twitter-tweet"><p lang="en" dir="ltr"><a href="https://twitter.com/hashtag/PowerApps?src=hash&amp;ref_src=twsrc%5Etfw">#PowerApps</a> SPO LIst. TimeZone... <a href="https://t.co/WzF5CoOr0o">pic.twitter.com/WzF5CoOr0o</a></p>&mdash; やま (Yama) (@yamad365) <a href="https://twitter.com/yamad365/status/1246088374017871874?ref_src=twsrc%5Etfw">April 3, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 現象の説明
ギャラリーコントロール、上段がListのタイトル、下段が更新日時です。各SPOサイトのListを更新した直後の結果です。
![図3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/edf76681-09ef-dc9f-9623-05d723b055bd.png)
更新日時、どちらも同じ値ですね。

では、データが格納されているListを確認してみましょう。上段が日本時間、下段がUTCです。
![図4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/c03fdb77-d70a-7058-098a-a8c6a6aee3e6.png)
UTC側は9時間ズレているコトが確認できます。
タイトル列が同じ値なのは、テキスト型なので Power Apps から文字列で格納されているからですね。更新日時の列は日付型なので、日時の概念が発生しています。そして、SPOはサイトのタイムゾーンによって自動的に時間が調整されているのです。

前イメージでは、更新日時は同じ値でした。しかし、データソース側ではタイムゾーンによって異なる。

つまり ***『SPOをデータソースとして利用する場合、日時を扱うフィールドはタイムゾーンに注意すべき』*** ということです。

# 厳密には・・・
基本的に、クラウドソリューションは日時の概念は全てUTCで管理されている、と考えて差し支えありません。SPOも、CDSも、Azure の SQL Databaseも、です。（殆ど裏側一緒やんけ、っていうツッコミは無しでｗ）
ちなみに、AWSも基本的にはUTCで管理されているはずです。（AWSは数年触ってないので最近どうなのか知らんですが汗）
内部的な値はUTCで管理されていて、利用するソリューションのタイムゾーンがよしなに日時を調整してくれているのです。

# まとめ
- クラウドの日時は基本的にUTCで管理されていると考えましょう
- 利用するデータソースとタイムゾーンで自動的に日時が変換されるコトがあります
- Power Apps 側のタイムゾーン(地域)にも影響される場合があります

日本だけで利用するアプリなら全てのタイムゾーンを日本時間（UTC+9）にしてしまえば問題は発生しないでしょう。例えば、複数の国をまたいで利用するようなアプリを考える場合は注意が必要なポイントです。データソースの値を他のソリューション（例えば、Power BI や Power Automateなど）で再利用する場合も注意が必要になります。

また、作ったアプリで「登録できたけど、日時の情報が意図した値じゃない！」みたいな場合は、データソース側のタイムゾーンが間違っているコトが多いです。タイムゾーン、けっこう奥が深いですね。

それでは、皆さま、素晴らしい Power Platform Life を！
win32.cs

using System;
using System.Runtime.InteropServices;

namespace Win32
{	 
	public struct RECT 
	{
		public int Left;
		public int Top;
		public int Right;
		public int Bottom;
	}
	public struct POINT 
	{
		public int x;
		public int y;
	}
	public struct SIZE 
	{
		public int cx;
		public int cy;
	}
	public struct FILETIME 
	{
		public int dwLowDateTime;
		public int dwHighDateTime;
	}
	public struct SYSTEMTIME 
	{
		public short wYear;
		public short wMonth;
		public short wDayOfWeek;
		public short wDay;
		public short wHour;
		public short wMinute;
		public short wSecond;
		public short wMilliseconds;
	}
}
Intellij IDEAでScala3(Dotty)を試してみる

[Scala 3 support in IntelliJ Scala plugin](https://blog.jetbrains.com/scala/2020/03/17/scala-3-support-in-intellij-scala-plugin/)
ということらしいので、試してみました。

# 環境

Windows10
Intellij IDEA Ultimate

# IDEA EAPインストール
先のURLに書いてある通り。
[Toolbox App](https://www.jetbrains.com/toolbox-app/?_ga=2.142451698.1988012757.1585584038-186643976.1557157657)をインストールして起動し、ToolboxからIntellij IDEA Ultimate EAPをインストールしました。
インストール先は

```
C:\Users\xxx\AppData\Local\JetBrains\Toolbox\apps\IDEA-U\ch-0\201.6668.13
```

となっていました。
自分はIDEA UltimateをToolboxなしでインストールしていたのでわかりませんが、通常版のIDEAとは別の場所にインストールされるという認識でいいのでしょうか。

# IDEA起動

通常版の設定を引き継ぐため、起動すると最後に開いていたプロジェクトが自動的に開きます（設定による？）
ここでScalaプロジェクトを開いていた場合、通常版/EAP/Nightlyのどのプラグインを使用するかダイアログが表示されます。
自分はうっかり閉じてしまったんですが、ちゃんと設定画面が用意されていたので問題ありませんでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144437/ee5e9eda-07dd-5294-9b5e-4bbab28cd342.png)

# Dottyプロジェクト新規作成

おもむろに新規プロジェクトを作成しようとすると、そこには燦然と輝く"Dotty(experimental)"の文字が。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144437/47b8d645-5917-6ad4-279e-7f655301de01.png)

選択すると、Hello Worldおよびテストが実装されているシンプルなプロジェクトになっています。
そのまま実行することでHello Worldできます。めでたしめでたし。

…本当にDottyで実行されているのか怪しいので、Union Type等Dottyで新規に追加された機能を試しましたが、一応問題ないようです。
他の機能をいくつか試したところ、プラグイン側の対応が追いついておらずIDE側で構文エラーが出るけどコンパイルは通る、サジェストが働かない、などの事象がちらほら見られましたが、試しに使ってみるレベルではそこまで困る事はありませんでした。

本当はDottyの新機能をすべて試してみたかったのですが、正直半分くらいはどういう機能なのかドキュメントを見てもよく分からないという状態です・・・
解説してくださる方をお待ちしています！
Fix Collectd permission problem

When collectd has permission problem. e.g. hddtemp plugin
`*** plugin: *** failed: Permission denied`
Do below,

```
audit2allow -a
audit2allow -a -M collectd_t
semodule -i collectd_t.pp
```

In case of permission problem of openvpn plogin,

```
setenforce 0
```


reference:
https://stackoverflow.com/questions/34787016/collectd-permission-denied-to-connect-to-remote-host
【Laravel】Herokuでのデプロイ

Herokuを利用して、Laravelのアプリのデプロイを行います。その一連の手順をメモします。
DBにはMySQLを利用したいので、その設定も行います。

###前提
・laravelアプリが作成済み
・Herokuアカウント取得済み
・Heroku CLI導入済み
・DBにはMySQLを利用します。

###Procfileの作成
まずはLaravel側の設定を行います。

ProcfileというHerokuの設定ファイルを作成。サーバーにApacheを使うこと、public/をドキュメントルートとすることを宣言するために使います。アプリフォルダの直下に作成してください。

```Procfile:Procfile
web: vendor/bin/heroku-php-apache2 public/
```

###DBの文字数の設定
Herokuではvarchar型の文字数はデフォルトの255では大きすぎるため191に設定します。
app\Providers\AppServiceProvider.phpのboot()に設定します。

```php:AppServiceProvider.app
use Illuminate\Support\Facades\Schema;

public function boot()
{
    Schema::defaultStringLength(191);
}
```

###アプリをhttpsに対応させる
本番環境の場合にhttpsを強制します。こちらもapp\Providers\AppServiceProvider.phpのboot()に設定します。

```php:AppServiceProvider.app
public function boot()
{
    if (\App::environment('production')) {
      \URL::forceScheme('https');
  }
}    
```
Laravel側の設定は以上です。ほかにもあるとは思いますが、これらをしておけば少なくともデプロイには成功すると思います。

###Herokuへのログイン

```
$ Heroku login
```

###Herokuアプリの作成、デプロイ
Herokuアプリを作成します。

```
$ heroku create myapp –buildpack heroku/php
```
デプロイはGitを利用したHerokuアプリへのプッシュによって行います。
なのでまずHerokuアプリをリモートとして登録します。myappのところは先ほど作成したHerokuアプリを指定します。

```
$ heroku git:remote -a myapp
```
このHerokuリモートにプッシュしてデプロイします。変更点のコミットを忘れずにしましょう。

```
$ git add . 
$ git commit -m 'Add Procfile, varcher length, force https'
$ git push heroku master
```

###DBとしてMySQLを利用
HerokuはデフォルトのDBがPostgreSQLであるため、MySQLを使うためにはアドオン「ClearDB」を利用して設定を変更します。
ClearDBは利用自体は無料ですが、クレジットカードの登録が必要となります。Herokuのサイトから行うことができます。

クレカの登録をしたら、下記コマンドでClearDBのインストールをします。

```
$ heroku addons:add cleardb
```

###環境変数の設定
アプリの環境変数は.envなどに定義しますが、それらはデプロイされません。したがって環境変数はHerokuアプリに定義する必要があります。

下記コマンドで設定ができます。

```
$ heroku config:set キー=値
```
###DBの環境設定
まずは自分のClearDBのURLを確認します。

```
$ heroku config:get CLEARDB_DATABASE_URL 
mysql://[ユーザー名]:[パスワード]@[ホスト名]/[データベース名]?reconnect=true
```
各キー、値を登録します

```
$ heroku config:set DB_DATABASE=[データベース名]
$ heroku config:set DB_HOST=[ホスト名]
$ heroku config:set DB_USERNAME=[ユーザー名]
$ heroku config:set DB_PASSWORD=[パスワード]
```
###その他の環境設定
```
$ heroku config:set APP_KEY=$(php artisan key:generate --show)
$ heroku config:set APP NAME=myapp
$ heroku config:set APP_ENV=heroku
```
このほかにもメールやapi等の各種環境変数もここで設定します。

###マイグレーションの実行
```
$ heroku run php artisan migrate

$ heroku open
```
マイグレーションを実行し、成功したらサイトにアクセスしてみましょう。

下のようなエラーが出た場合、MySQLのvarchar型の文字数を変更がうまくいっていません。

```
Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes
```
"jupyter notebook 環境構築～起動" as Code

<!-- TOC -->

- [1. Overview](#1-overview)
- [2. jupyter notebook インストール](#2-jupyter-notebook-インストール)
- [3. （任意）jupyter notebook を Dark Thema に](#3-任意jupyter-notebook-を-dark-thema-に)
- [4. （任意）jupyter notebook に Slideshow 出力拡張 を](#4-任意jupyter-notebook-に-slideshow-出力拡張-を)
- [5. （任意）jupyter notebook 起動時の初期フォルダ変更](#5-任意jupyter-notebook-起動時の初期フォルダ変更)
- [6. jupyter notebook 起動](#6-jupyter-notebook-起動)

<!-- /TOC -->

# 1. Overview

パクリ集ですが、、、jupyter 環境構築をCodeで行った備忘録です。
`（任意）`の項を省略すれば [jupyter notebook 起動](#6-jupyter-notebook-起動)まで瞬殺かと。

参考にさせていただいた
@u1and0さん、@ishizakiiiiさん、@mitamaさん
ありがとうございます。

# 2. jupyter notebook インストール

Windows 10 Home に Chocolatey をインストールするところから。  
jupyter notebook は anaconda に同梱されている。  

**anaconda3 インストール**

> 
```Command
> @powershell -NoProfile -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin
> choco install -y --execution-timeout=1000000 anaconda3
```

> 参考
> @u1and0 さん
> 2行でpythonインストール@Windows
> https://qiita.com/u1and0/items/d63546c0d64eceab6b41

# 3. （任意）jupyter notebook を Dark Thema に

Darkが落ち着くので。（消費電力的にもきっと）

**Dark Thema 適用**

> 
```Command
> pip install jupyterthemes
> jt -t onedork -fs 95 -altp -tfs 11 -nfs 115 -cellw 88% -T
```

> 参考
> @ishizakiiii さん
> Jupyter Notebookをより便利に使うために、色々まとめ
> https://qiita.com/ishizakiiii/items/b98bbf8997f039f40058

# 4. （任意）jupyter notebook に Slideshow 出力拡張 を

人に資料として見せることを見据えて Slideshow 出力拡張 を行う。

**Slideshow 出力拡張**

> 
```Command
> pip install RISE
> jupyter-nbextension install rise --py --sys-prefix
> jupyter-nbextension enable rise --py --sys-prefix
```

> 参考
> @ishizakiiii さん
> Jupyter Notebookをより便利に使うために、色々まとめ
> https://qiita.com/ishizakiiii/items/b98bbf8997f039f40058

# 5. （任意）jupyter notebook 起動時の初期フォルダ変更

Windows 10 Home の自分の環境だと `C:\Windows\System32` が初期フォルダになっていた。
読み込み待ちが長く、 jupyter notebook 起動にやたら時間かかった。
初期フォルダを変更する必要があった。

**configファイル生成**

> 
```Command
> jupyter notebook --generate-config
```

**configファイル編集**

`C:\Users\{user}\.jupyter\jupyter_notebook_config.py`を編集。

例)

```Python
c.NotebookApp.notebook_dir = 'C:\\Works\\Projects\\jupyter'
```

> 参考
> @mitama さん
> Jupyter Notebookの初期ディレクトリを変更する
> https://qiita.com/mitama/items/a8129e50afcc462e02d6

# 6. jupyter notebook 起動

```Command
> jupyter notebook
```

以上
javascriptの代入の基礎（深いコピー、浅いコピー）

# 1. `string`, `number`, `boolean`の代入
配列やオブジェクト以外を代入する場合、**値が代入**される。

```js
let ori_num = 10;
let new_num = ori_num; // 変数の場合数字を代入
ori_num = 20;

console.log(ori_num, new_num); //output => 20, 10
```

# 2. 配列`array`の代入
配列を代入する場合、代入される配列は**元の配列を参照**する。
そのため、元の配列(`ori_arr`)の値が変更されると、代入される配列(`new_arr`)の値も変更されてしまう。

```js
const ori_arr = ['aaa', 'bbb'];
const new_arr = ori_arr; // 元の配列を参照
ori_arr[1] = 'ccc'; // 元の配列の値が変わると…

// 新しく作成した配列も変わる!
console.log(ori_arr,new_arr); // output => ["aaa","ccc"], ["aaa","ccc"]
```
この対策として以下の4つの方法がある。

## 対策1：`slice`でコピー

```js
const ori_arr =['aaa', 'bbb'];
const new_arr = ori_arr.slice();
ori_arr[1] = 'ccc'; //元の配列の値を変えても...

// 新しく作成した配列には反映されない！
console.log(ori_arr, new_arr); // output => ["aaa","ccc"] ["aaa","bbb"]
```

## 対策2: 新しい配列作成＋`concat`
```js
const ori_arr =['aaa', 'bbb'];
const new_arr = [].concat(ori_arr);
ori_arr[1] = 'ccc'; //元の配列の値を変えても...

// 新しく作成した配列には反映されない！
console.log(ori_arr, new_arr); //["aaa","ccc"] ["aaa","bbb"]
```

## 対策3: ES6 spread
```js
const ori_arr =['aaa', 'bbb'];
const new_arr = [...a];
ori_arr[1] = 'ccc'; //元の配列の値を変えても...

// 新しく作成した配列には反映されない！
console.log(ori_arr, new_arr); //["aaa","ccc"] ["aaa","bbb"]
```

## 対策4: `Array#from`

```js
const ori_arr =['aaa', 'bbb'];
const new_arr = Array.from(ori_arr);
ori_arr[1] = 'ccc'; //元の配列の値を変えても...

// 新しく作成した配列には反映されない！
console.log(ori_arr, new_arr); // output => ["aaa","ccc"] ["aaa","bbb"]
```

# 3. `Object`の代入
オブジェクトを代入する場合、代入されるオブジェクトは**元のオブジェクトを参照**する。
そのため、元のオブジェクト(`ori_obj`)の値が変更されると、代入されるオブジェクト(`new_obj`)の値も変更されてしまう。

```js
const ori_obj = {
    a:"aaa"
}
const new_obj = ori_obj; //元のオブジェクトに代入
ori_obj.a = "bbb"; //元のオブジェクトの値を変えると...

// 新しく作成したオブジェクトも変更される！
console.log(ori_obj, new_obj); // output => {a:"bbb"}, {a:"bbb"}
```
そのための対策方法は下記の通り。

## ~~対策？~~：`assign`を使用（浅いコピー）
`Object#assign`は浅いコピー(shallow copy)のため、
オブジェクトの中のオブジェクトの値（下記の例だと`shallow.b.c`）は元のオブジェクト`obj`に依存してしまう。

```js
const obj = {
    a : 'aaa',
    b: {
        c: 'ccc'
    }
}
//浅いコピー (shallow copy)
const shallow = Object.assign({}, obj);
obj.a = 'change';  // オブジェクトを変更
obj.b.c ='change'; // オブジェクトの中のオブジェクトを変更

console.log(obj, shallow);
// output
// obj     = {a:"change",b:{c:"change"}}
// shallow = {a:"aaa",   b:{c:"change"}} オブジェクトの中のオブジェクトは変更される
```
そこで、以下のような実装でこの問題を解決する。

## 対策：`JSON.parse(JSON.stringify(obj))`を使用（深いコピー）
`JSON#parse`は`string`を`JSON`に変換し、
`JSON#stringify`は`JSON`を`string`に変換する。

```js
const obj = {
    a : 'aaa',
    b: {
        c: 'ccc'
    }
}
//深いコピー (deep copy)
const deep = JSON.parse(JSON.stringify(obj));
obj.a   ='change';
obj.b.c ='change';

console.log(obj, deep);
// output
// obj     = {a:"change",b:{c:"change"}}
// shallow = {a:"aaa",   b:{c:"ccc"   }} 
```

### `JSON.parse(JSON.stringify(obj))`が深いコピーになる理由
```js
// JSON.stringify(obj)が
JSON.parse("{aaa:bbb,{ccc:ddd}}");
// のようにいったん文字列に置き換えているから
```
複数投稿した画像を1枚のみ表示する方法

carrierwaveを使って画像を複数投稿できる機能を実装したのですが、
投稿を一覧で表示する際には一枚のみ表示させたいと思いました。


###前提条件
・railsのバージョンは6.2.0
・インスタンス変数は@gym
・事前にindex.html.erb内のrenderメソッドによって、@gymをasオプションを使ってgymに変換してます。




```_gym.html.erb
<div class="container">
  <div class="row">
    <div class="col-md-4">
      <div class="gymbox">
        <div class="gymtitle">
          <%= link_to (gym.name), gym_path(gym) %>
        </div>
        <div class="delete">
          <% if current_user?(gym.user) %>
          <%= link_to "削除", gym, method: :delete,
          data: { confirm: "削除しますか？" } %>
          <% end %>
        </div>
        <div class="gympicture">
          <%= image_tag gym.picture.first.url  %> →この部分です。

        </div>
      </div>
    </div>
  </div>
</div>
```



firstを使って、一枚目を指定してあげると良いです。

```
<%= image_tag gym.picture.first.url  %>
```
時間を持て余す小３がママのプログラムを手伝った話

##きっかけ
Webデザインをしている嫁が、ビデオ通話でマイクボリュームのデザインをしていて、サンプルを動作こみで社内レビューに出そうとしてました。
こんなデザインです。
■■■■□□□
1秒毎にこうなったり、
■□□□□□□
こうなったり。
■■■■■□□

プログラマーであればJavascriptですぐに実装できますが、Webデザイナーである嫁は何から手をつけていいかわからず。当然プログラマー出身SEの僕にどうしたらいいか聞いてきます。

えーっと正直めんどくさいw
そもそもいきなり構文を書くよりロジックというものを分かってもらわないと今後の為になりません！
ということで、コロナの影響で休校中の暇な小３の息子にサンプルを作らせましたw

##利用させたツール
DeNAさんが提供している「[プログラミングゼミ](https://programmingzemi.com/)」です。
![00.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43851/c5896c40-c5d4-3404-af9e-298a1392a609.jpeg)

実際にコードを書かずに、ブロックの組み立て（フローチャート）でアプリケーションを作るというものです。
視覚的にロジックが分かるので息子の作り上げたロジックをまずは嫁に理解してもらおうという作戦です。

##僕の要求

- 1が押されたらランプが1個光る
- 2が押されたらランプが2個光る
- 3が押されたらランプが3個光る
- 4が押されたらランプが4個光る
- 5が押されたらランプが5個光る


これを指示しました。
結果、基本デザインは以下のようになりました。
![Screenshot_20200403-234740.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43851/27a0ea82-95d4-2b9b-4fc9-b89e9eb88ad2.png)

ランプ＝電球を僕はイメージしてましたが、息子の中では魔法のランプと受け取ったようです。

##実装部分
まずは呼び出し部分です。ボタンにこのロジックが付与されています。
![Screenshot_20200404-000232.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43851/a1936d8b-4715-d694-87e7-aa0e7f0f92dd.png)
ボタンをタッチされたら何かしらのデータを送っています。

次に受け取り部分です。
![Screenshot_20200403-234730.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43851/339795c5-b517-87f5-3837-032c5a7f8e8c.png)
それぞれのランプは値を受け取ったあとにお化け？を呼び出すようになっています。（＝光る）

まあ、実際に引数の数字にあまり意味はありませんが、そこは見なかった事に。

この呼び出しと受け取りが５セット存在しているプログラムになりました。

##完成品
GIFアニメーションにしてみました。実際にクリックしている様子は見えませんが、３、４、２をクリックしています。
![ezgif-4-cf3fc2e32d84.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43851/c0ccceaf-0e8a-e174-81de-0def07dec452.gif)

作成依頼をして３０分くらいでつくりあげました。
とうぜん他にもいろいろなロジックがあるんですが、これはこれですごくよくできていると思います。

##結局のところ。。。
嫁が実装したプログラムはfor文使ってました。
（for文の中に余分なコードももあってやっぱりよく理解できてなさそうでした）
途中まではできてましたが、結局うまく動かない部分があり、仕上げは僕が。。。