OmniAICreator/Qiita-1.07M huggingface dataset:
[Rails6]ActionTextの入力フォームが伸びて困る

# はじめに
就活のポートフォリオサイトとして[Asobi](http://www.asobi-app.com/)というWebサイトを作成しました。(QiitaにAsobiに関しての記事を書いています。[就活用ポートフォリオとしてWebサービス「Asobi」を作りました。](https://qiita.com/sasakura_870/items/1eb666c80c4ceb815dd8))
このサイトの中でRails6から新しく導入された`ActionText`を使っているのですが、入力フォームが行数に応じて伸びてしまいます。

今回はそんなActionTextの入力フォームをいい感じにするためにやったことをご紹介します。

# 実行環境
+ Ruby 2.6.5
+ Rails 6.0.2

# ActionTextとは
Rails6から実装されたリッチテキストコンテンツと編集機能を導入する機能です。

ActionTextのインストールと導入したいモデルとカラムの用意を行い、少しコードを書くだけでブログのようなリッチテキストエディタが導入できます。

![actiontext_test.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449905/9caab6e2-0820-24b1-8ea2-60f8495e16e3.gif)

Ajaxを利用した画像のアップロードも実装されており、アップロードされた画像は`ActiveStorage`を利用して保存されます。

![actiontext_pic.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449905/10b4f849-3242-4622-cd32-3c1320f7833f.gif)

今回ActionTextの導入に関しては割愛させていただきます。
導入に関しては下記の記事が参考になるかと思います。

[Rails6新機能 ActionText使用方法](https://qiita.com/tomokiyao/items/3c22ca9cb916d5c99ca4)
[Rails 6 と Action text を使ってみる - もふもふ技術部](https://tech.mof-mof.co.jp/blog/rails6-actiontext.html)

# 伸びて困る
ActionTextで生成されるリッチテキストエディタの入力フォームは、行数に応じて高さが伸びるようになっています。

**デフォルトの挙動**

![actiontext_default.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449905/bc27e861-b649-e2b4-76e8-158ad7109230.gif)

これをQiitaやはてなブログのような、はみ出た部分をスクロールバーで表示するように実装します。

**こんな風な挙動にしたい**

![actiontext_custom.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449905/617faae6-010f-dac2-76db-ed83124d4bdb.gif)

# 実装
`Rails`側でこれを実装する方法を見つけられなかったため、`CSS`で実装します。

## Trixについて
実装の前に、ActionTextに含まれる`Trix`について説明します。
`Trix`とはリッチテキストエディタを実装するJavascriptのライブラリです。(ちなみに開発元はRuby on Railsと同じBasecampです)
[Trixのドキュメント](https://github.com/basecamp/trix)を見てみると、

> Place an empty \<trix-editor\>\</trix-editor\> tag on the page. Trix will automatically insert a separate \<trix-toolbar\> before the editor.
> Like an HTML \<textarea\>, \<trix-editor\> accepts autofocus and placeholder attributes. Unlike a \<textarea\>, \<trix-editor> automatically expands vertically to fit its contents.

とのことで、ページのTrixのエディタを入れたい場所に`trix-editor`タグを書き込むことで使えるようになります。

ActionTextの場合、`erb`ファイルに

```erb
<%= form.rich_text_area :body %>
```

と記述することで`trix-editor`タグが生成されます。
そしてリッチテキストエリアへの入力は`trix-editor`タグの子要素にDOMとなって反映されていきます。

![actiontext_dom.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449905/d0291f7a-c941-a95a-d4c5-6745fbfd27a4.gif)

なので、入力フォームのスタイルは`親要素であるtrix-editor`タグのCSSを記述することで調整できそうです。

## CSSの記述
入力フォームの高さを固定するために`min-height`と`max-height`を、そして入力フォームからはみ出した部分は`overflow-y: auto;`を設定することでスクロールバーで表示できるようにします。

以下のCSSを記述します。(`actiontext.scss`が`/app/assets`か`/app/javascript`に生成されていると思うので、そこに追記することをオススメします)

```css
trix-editor {
  min-height: 20em;
  max-height: 20em;
  overflow-y: auto;
}
```

以上で目指す挙動の入力フォームになっていると思います。

# まとめ
ActionTextは新しい機能のため中々情報が出てきません。もしかしたらActionTextの設定ファイルか何かでうまいことやれるかもしれないです。

何か直すべき点、間違った記述があればコメント等で指摘していただければと思います。

# 参考文献
[Trix](https://trix-editor.org/)
https://railsguides.jp/action_text_overview.html
原点回帰：HighCharts

#はじめに
私の記憶が確かならば、とあるお客様からforce.com上に「散布図表示してくれ」と言われ、現CTOが選んできたのが[Highcharts JS](https://www.highcharts.com/)でした。
Salesforceの標準レポートでは、動的な散布図を表示できなかったり、データ点数200個までといった制限があったりしたので、こいつが選ばれたのだと思います。
infomotionが出てくる前、私の中でグラフといえばHighchartsになっていました。サンプルのグラフを眺めているだけで面白いですね。
敬意を込めて、今回は、そんなHighchartsをInfotypeにしてしまいましょう。

#完成
はい、完成です。enebularのDiscoverの[こちら](https://enebular.com/discover/infotype/56738907-7a2c-44f5-9d71-a939f6234c51)からインポートしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266424/33fcd93c-3ce8-a745-0c37-99d599a206cd.png)



#工夫した点
- 縦軸と横軸に表示するデータを入れ替えられるようにした
- 縦軸と横軸のそれぞれ軸の範囲を指定できるようにした
- Tooltipに2軸に収まらない他のデータの中身を表示できるようにした

#注意
あくまでデモのためにつくっています。使う時は、目的に応じて、Highchartsの[ライセンス](https://shop.highsoft.com/)に従ってください。
不正プログラム書き込み疑いにより中学生が補導されてしまったJavaScriptに思いを馳せ子供向けビジュアルプログラミング言語Scratchで似たやつを作ってみた


[クソアプリ2 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/kuso-app2)の22日目の記事です。

今年の3月、こんな事件があったことを皆さん覚えていますでしょうか

## [「何回閉じても無駄ですよ～」ブラクラURLを掲示板に貼っただけで補導、「やり過ぎ」と物議｜ITMedia](https://www.itmedia.co.jp/news/articles/1903/05/news080.html)


個人的にはえっちな漫画の広告とかの方がやめて欲しい気持ちなんすよねー

そんな今年の事件に思いを馳せながら、子供のたくさんいるScratchの世界で似たアプリをつくってみました

https://scratch.mit.edu/projects/291759210/

<img width="962" alt="スクリーンショット 2019-12-18 20.57.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86930/c693baae-b415-afe2-ac48-4cff2ce6860e.png">

緑色の旗を押すとゲームスタートです


![Dec-18-2019 20-59-34.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86930/3cba0913-1f52-dd0a-df48-36695bfb24d2.gif)

いいかんじにできた

素材はFigmaで秒で作成
コードは20minくらいかなーで作成

まっじ簡単なんですよScratch

# 手順説明します
### クラスを用意する
クラスはこれだけ。
window, ok, 文字, おまけの猫(スプライト1という名前)
<img width="321" alt="スクリーンショット 2019-12-18 21.01.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86930/7e2c2260-9fb3-e534-b29d-53291f765ddf.png">

### windowのコード
<img width="545" alt="スクリーンショット 2019-12-18 21.03.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86930/92c76525-a357-f004-9ef2-877dbd0afd0b.png">
右にある「旗が押された時」ブロックがScratchゲームスタートのトリガーです。

iという謎の変数が出ています。
今windowの表示されている場所に対して、次の描画位置をどの程度ずらして表示するか決めている数字です。
今回は8ずらしています(Scratchの世界ではpxではなく、座標です。多分)

「クローンされた時」というトリガーもありますが、クローンとは**インスタンス生成**のことです。
OKボタンが押された時にwindowのクローンを作成するコードを書いています。
<img width="457" alt="スクリーンショット 2019-12-18 21.07.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86930/1ade4396-d4a9-c019-964b-2fd47acb3ccd.png">

ちなみに文字もクローンしています
<img width="585" alt="スクリーンショット 2019-12-18 21.01.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86930/6c00d2fb-c54e-e982-8114-e24cf28dc970.png">

# remixしてくれた
Scratchにはremixという文化があります。
これがScratchという文化を大きく成長させてる理由です。
今Scratchで公開されている全てのゲームを誰もが自分用にカスタマイズして公開することが可能です。
ということで私の作ったブラクラゲームをカスタマイズして公開している人がいたのでみてみましょう

https://scratch.mit.edu/projects/315218524/

![Dec-18-2019 21-16-15.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86930/3bf6cbbd-8180-71e9-7022-7b71e2520caa.gif)
なにこれ普通に怖いんだけど？(remixありがと)

### 30minでクソアプリみのあるScratchのゲームができる

だいたい30minくらいで作れるんで楽しいんですよね
こういうくだらない遊びを一緒にしてくれる小学生にScratchをレクチャーするスクールをやっていますので、もし興味あればTwitterのDMなどお待ちしています〜

ぐっどくそあぷり〜
vimrc設定方法について　


#動作環境
Windows10,64bit
Oracle VirtualBox 6.0.14
CentOS-7x86_64-DVD-1908 linux redhat64bit

#vimrcのパスを調べる
まず、vimrcがどこにあるのか探してみる。ターミナルに

```
$vim --version
```
と入力するといろいろずらずらと表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455763/d4162790-3cdb-acdd-d6df-06b053c04fa0.png)
この中でvimのパスは下図の部分に書かれている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455763/8a3f1d58-d108-8b39-eef7-4ebf450334c9.png)
基本的に編集するのは一番上のシステムの部分で問題ないと思うが、システムの部分のvimrcは読み込み専用ファイルになっており、通常のユーザーでは編集することができない。私の場合はsudoコマンドを使うことで編集が可能となった。vimrcのパスについては各自で変えてください。

```
$sudo vim /etc/vimrc
```
**管理者権限のない方に向けて**
管理者権限のない方でもユーザごとにvimrcの設定ができる。大学のサーバにアクセスするような方はユーザとして登録されているので先ほどの**ユーザ**の部分をパスに指定して新規にvimrcを作ることができる。私の環境では以下のコマンドを使うことで編集可能であった。~は/home/userを表します。

```
$vim ~/.vimrc
```
#vimrcのカスタマイズ
vimrcのカスタマイズについてはいろんな方がわかりやすく解説してくださっているのでそちらを参考にしていただいた方がいいと思います。
https://qiita.com/marrontan619/items/541a1374e1ac672977e6
そんなにこだわりのない方は以下の設定をコピペしておけば問題ないでしょう。

```
set title↲
set ambiwidth=double↲
set tabstop=4↲
set expandtab↲
set shiftwidth=4↲
set smartindent↲
set list↲
set listchars=tab:»-,trail:-,eol:,extends:»,precedes:«,nbsp:%↲
set nrformats-=octal↲
set hidden↲
set history=50↲
set virtualedit=block↲
set whichwrap=b,s,[,],<,>↲
set backspace=indent,eol,start↲
set wildmenu↲
```

**このままコピペすると文末に？が表示されることがあるので消さないとエラーになる可能性があります。**

#insertモードでのカーソル操作
insertモードでわざわざノーマルモードに戻らずにカーソルを動かしたいという時があると思います。
その際はvimrcに以下のキーマップを追加することをお勧めします。私はUnix配列のキーボードであるHHKB Professional JPを使っているのでemacsのカーソル操作と同じもの割り当てておきました。

```↲
imap <C-p> <Up>↲
imap <C-n> <Down>↲
imap <C-b> <Left>↲
imap <C-f> <Right>↲
```
#カラースキームの変更について
https://qiita.com/sff1019/items/3f73856b78d7fa2731c7
この方が非常にわかりやすくまとめてくださっているのでこちらを参照してください。
私は新たにテーマをダウンロードするのが面倒だったのでデフォルトで入っているdarkblueを使っています。vimrcに以下のように追加することで設定できます。

```
syntax enable↲
colorscheme darkblue↲
```
Z-index使用するときのフローチャート（英語）

<img width="1043" alt="スクリーンショット 2019-12-18 21.13.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161691/c926e67f-66c2-80d8-9054-3140ba55704e.png">

all credits on App Brewery
https://www.appbrewery.co/p/web-development-course-resources
CakePHPのドキュメント翻訳は英語学習とフレームワークのキャッチアップにつながる

この記事は、[PHP Advent Calendar 2019](https://qiita.com/advent-calendar/2019/php)の18日目の記事です。

# TL;DR

- CakePHPなどフレームワークの多くには、コミュニティでメンテされている日本語翻訳ドキュメントが存在する
- ドキュメントの変更を追って自ら翻訳対応していくことで、英語力とフレームワーク自身の理解が進む

# CakePHP Book

つい最近、メジャーバージョンアップ（**4**）がリリースされたことで話題（！？）のCakePHPには、開発者向けのドキュメントとしてCakePHP Bookというものが公開されています。

https://book.cakephp.org/4/en/index.html

CakePHPを触ったことがある方なら一度は訪れたことがあるサイトかと思います。CakePHPはOSSですので、もちろんこのサイト自体も、GitHubに公開されています。

https://github.com/cakephp/docs

こちらのサイトは、様々な言語で翻訳されており、特に日本語ドキュメントのメンテナンスも盛んに行われています。

筆者自身も昨年からちらほらと翻訳やもとの英語ドキュメントを修正したりしています。

<img width="831" alt="Screen Shot 2019-12-18 at 20.48.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84126/7ae89a0d-4f24-cc10-1cbe-c25a579b93d0.png">

https://github.com/cakephp/docs/pulls?q=is%3Apr+author%3Ahgsgtk+is%3Aclosed

山があるのは、マイナーバージョンアップ時の移行ガイドを翻訳した際のものです。

3.7 Migration Guide: https://github.com/cakephp/docs/pull/5950
3.8 Migration Guide: https://github.com/cakephp/docs/pull/6128
3.9 Migration Guide: https://github.com/cakephp/docs/pull/6228

CakePHP Bookの翻訳を継続してやってみると色々メリットがあったので紹介して、あわゆくば、読んでいただいた方々をこちらの沼に誘えればと思います。

# ドキュメント翻訳のメリット

## 仕様の変化をおえる

これは、特に移行ガイドを翻訳する際の気づきですが、ただ流し読みするのではなく、一文づつ翻訳していくため、どのような変更が行われたのかを知ることに繋がります。また、どう訳していいかわからない場面において、一度その機能の仕様自体を調べるので、普段業務で触れない部分についての理解を深めることが出来ます。

さらに、継続してバージョンアップの移行ガイドをやっていくと、ちょっとした傾向みたいな部分も見えてきます。とくにCakePHP3.6以降は、CakePHP4に向けた非推奨機能の追加が多かったのですが、なんとなくの情報として得るのと、実体験としてドキュメントメンテナンスを通じて知るのでは大きな違いがあります。

## 対応する技術的な英語文を知れる

シンプルですが、英語文を訳して読んでいく際に、普段、日本語で見聞きする技術的単語や文章がどういうふうに表現されるのかを知る切っ掛けに繋がります。「英語がなければなるべく翻訳されたやつがいい」という方でも、強制的に英語に立ち向かう土俵に立つので、強制的な英語学習となります。

## コミュニティのコアな方々と触れ合える

ドキュメントをメンテナンスするような方は、そのフレームワークにおいて、非常に熱量の高い方々が多いです。そのような方々とGitHub上で触れ合えることは刺激になります。また、そこでやっておくとリアルであった際にすでにGitHub上でコミュニケーションを取っているので話の種に繋がります。コミュ力がなくても事前に知ってもらえるのはメリットですね。

# ドキュメントを翻訳したいぞと思ったら

「[CakePHP Cookbook を直す方法(表示確認してからプルリクエストを出すまで)](https://devblog.thebase.in/entry/2018/02/13/163843)」という記事にて、 @tenkoma さんが環境構築の仕方から丁寧に解説してくださっています（さすが丁寧のてんこまさん！）。CakePHP Bookは、PHPコミュニティで広く知られている上に、修正ポイントが多く、コントリビュートチャンスは非常に多くなっています。ぜひ、チャレンジしてみてください！
【Rails】使用するレイアウトファイルを切り替える

デフォルトでは全てのviewファイルが`application.html.erb`をレイアウトとして利用するようになっています。
コントローラーやアクションごとに、使用するレイアウトを指定する方法を調べました。

##レイアウトファイル側から指定
レイアウトファイルの名前を`views/layouts/hoges.html.erb`にすることで、`hoges_controller`内の全てのアクションに適用されます。

##コントローラー側から指定
コントローラーの内上部に`layout '<layoutファイル名の冒頭>'`と書き込むことで、そのコントローラー内のアクションで利用するレイアウトファイルを指定することができます。

```rb:hoges_controller.rb
class HogesController < ApplicationController
  layout 'another'

  def index
  end
.
.
```
（レイアウトファイル名が`another.html.erb`の場合）

##アクションごとに指定
アクション内に`render layout: '<'layoutファイル名の冒頭'>`と書き込むことで、そのアクションで利用するレイアウトファイルを指定することができます。

```rb:hoges_controller.rb
class HogesController < ApplicationController
  layout 'another'

  def index
    render layout: 'another'
  end
.
.
```
（レイアウトファイル名が`another.html.erb`の場合）

##参考
[コントローラやアクション毎に使用するレイアウトを切り替える](https://www.javadrive.jp/rails/template/index3.html)
.xsession-errorsのF86AudioLowerVolume failed! を黙らせる。

xfceの謎のエラーを止める方法になります。

```terminal:xfce4-volumed1196エラー
** (xfce4-volumed:1196): WARNING **: 20:46:51.720: Binding 'XF86AudioLowerVolume' failed!
```

```terminal:解決コマンド
amixer -D pulse set Master Playback Switch toggle
```
Django REST framework [第1章〜第3章] をやってみた

[こちら](https://www.django-rest-framework.org/tutorial/1-serialization/)のチュートリアル(1-3章)をやった個人的記録。(要約ではなくメモ)

# Tutorial 1: Serialization

* 必要なのは`urls.py`, `api.py`, `views.py`, `models.py`, `serializer.py`
* Serialization APIはDjango's Forms APIに似ている
* SerializerクラスはModelSerializerを継承することで簡単に書ける

**Modelの属性に含まれない要素をSerializeの際に含めることは可能**、例えば

`Model`において

 * Snippet ModelはUser属性をもつ (Snippet -> Userのbelongs toは指定されている)
 * User ModelはSnippet属性をもたない。(User -> Snippetのhas manyは指定されていない)


この時、`ModelSerializer`において

* SnippetSerializerはuser属性を`serializers.ReadOnlyField(source='user')`で
* UserはUserSerializerをsnippetを`serializers.PrimaryKeyRelatedField()`で引っ張ってくる。


![58551.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534442/4b3c1194-e8b8-670a-b7c8-8840354e320b.jpeg)

# Tutorial 2: Requests and Responses
この章では`function based view(@api_viewデコレータ)`の実装。

* `return Response(data)`を使えば`content negotiation`(determine the correct content type to return to the client)が簡単に実現できる。 
* APIendpointに拡張子をつける方法

snippets/views.py

```
def snippet_list(request, format=None):
```
snippets/urls.py

```
urlpatterns = format_suffix_patterns(urlpatterns)
```

* クライアントからのformatの指定は`HTTP request bodyのAccept:xxx/yyy`か`endpointの拡張子`で行う。

```
# Request JSON
http http://127.0.0.1:8000/snippets/Accept:application/json 
# Request HTML
http http://127.0.0.1:8000/snippets/ Accept:text/html         
```
```
# JSON suffix
http http://127.0.0.1:8000/snippets.json
# Browsable API suffix
http http://127.0.0.1:8000/snippets.api
```
(要確認)`html = api`っぽい

# Tutorial 3: Class based views
この章では`Class-based Views(APIViewを継承)`で実装していく。3段階にかけてどんどん楽に実装する方法を学んだ。



1. `APIView`を継承
    * この時点ではrequest method一つにつき一つのmethodを用意する。

2. `generics.GenericAPIView`と`mixins.XxxxModelMixin`を継承.
    * Xxxx = { ListModelMixin, Create, Retrieve, Update, Destroy}
3. `generics.ListCreateAPIView` を継承。

結果、ここまでシンプルになった。

```
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework import generics


class SnippetList(generics.ListCreateAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer


class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
```
初心者によるプログラミング学習ログ 187日目

# 100日チャレンジの187日目

twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。

100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。

187日目は

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">おはようございます<br>187日目<br><br>webサイトコーディング課題<br>udemyでvue.jsをさらっと復習<br><br>いちおう形にはなったので、メンターさんに提出してみました。<a href="https://twitter.com/hashtag/100DaysOfCode?src=hash&amp;ref_src=twsrc%5Etfw">#100DaysOfCode</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%E3%81%A4%E3%81%AA%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/%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></p>&mdash; ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) <a href="https://twitter.com/yudapinokio/status/1207029541610217472?ref_src=twsrc%5Etfw">December 17, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
pyenv installがエラーで進まないときの対処法

# はじめに
pyenvでpythonのバージョンを変えようと思い別バージョンをインストールした矢先エラーが置きたので対処した手順をメモ
環境: MacOS Mojave バージョン 10.14.6

# 起こったエラー
`$pyenv install 3.6.4`

```

python-build: use openssl from homebrew
python-build: use readline from homebrew
Downloading Python-3.6.4.tar.xz...
-> https://www.python.org/ftp/python/3.6.4/Python-3.6.4.tar.xz
Installing Python-3.6.4...
python-build: use readline from homebrew

BUILD FAILED (OS X 10.14.6 using python-build 20160602)

Inspect or clean up the working tree at /var/folders/_4/hss19f1x2b12ys793gz8lsd00000gn/T/python-build.20191218170128.37056
Results logged to /var/folders/_4/hss19f1x2b12ys793gz8lsd00000gn/T/python-build.20191218170128.37056.log

Last 10 log lines:
  File "/private/var/folders/_4/hss19f1x2b12ys793gz8lsd00000gn/T/python-build.20191218170128.37056/Python-3.6.4/Lib/ensurepip/__main__.py", line 5, in <module>
    sys.exit(ensurepip._main())
  File "/private/var/folders/_4/hss19f1x2b12ys793gz8lsd00000gn/T/python-build.20191218170128.37056/Python-3.6.4/Lib/ensurepip/__init__.py", line 204, in _main
    default_pip=args.default_pip,
  File "/private/var/folders/_4/hss19f1x2b12ys793gz8lsd00000gn/T/python-build.20191218170128.37056/Python-3.6.4/Lib/ensurepip/__init__.py", line 117, in _bootstrap
    return _run_pip(args + [p[0] for p in _PROJECTS], additional_paths)
  File "/private/var/folders/_4/hss19f1x2b12ys793gz8lsd00000gn/T/python-build.20191218170128.37056/Python-3.6.4/Lib/ensurepip/__init__.py", line 27, in _run_pip
    import pip
zipimport.ZipImportError: can't decompress data; zlib not available
make: *** [install] Error 1
```

# やったこと
`$ brew install zlib`
`$ brew install sqlite`
`$ export LDFLAGS="${LDFLAGS} -L/usr/local/opt/zlib/lib"`
`$ export CPPFLAGS="${CPPFLAGS} -I/usr/local/opt/zlib/include"`
`$ export LDFLAGS="${LDFLAGS} -L/usr/local/opt/sqlite/lib"`
`$ export CPPFLAGS="${CPPFLAGS} -I/usr/local/opt/sqlite/include"`
`$ export PKG_CONFIG_PATH="${PKG_CONFIG_PATH} /usr/local/opt/zlib/lib/pkgconfig"`
`$ export PKG_CONFIG_PATH="${PKG_CONFIG_PATH} /usr/local/opt/sqlite/lib/pkgconfig"`

# 結果
```shell

$ python --version
Python 2.7.13 :: Anaconda custom (x86_64)

$ pyenv install 3.6.4

$ pyenv global 3.6.4

$ python --version
Python 3.6.4
```
Assembly Definitionの関係性を可視化するEditor拡張

# はじめに

Unityのプロジェクトで使用されているAssembly Definitionの依存元/依存先を可視化するEditor拡張を開発しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274974/f779f699-daa3-3c08-2393-b99ce997290c.png)

* [naninunenoy/AsmdefGraph](https://github.com/naninunenoy/AsmdefGraph)

開発するまでの経緯などを記事にまとめさせてもらいました。

# Assembly Definition

Unityの機能にディレクトリ単位でアセンブリを分割できるAssembly Definitionがあります。
使い方や利点などの解説はこちらの記事が詳しいです。

 * [Unity Assembly Definition 完全に理解した](https://qiita.com/toRisouP/items/d206af3029c7d80326ed)

関心の分離やビルド時間の短縮に効果があり、開発効率を上げるために使いこなしたい機能の１つです。

## 数が増えがち

[こちらの記事](https://qiita.com/naninunenoy/items/07bc2088877318771565)ではClean Architectureの原則に基づいてAssembly Definitionを設定する試みを行いました。
この時、 **11個の** `.asmdef` ファイルが作られることになりました。

1プロジェクトに数個くらいであれば特にAssembly Definitionの関係性を気にする事なく使えると思いますが、真面目に `.asmdef` を切っていくと数が増えて管理が大変になり、意図しない参照の定義が入ってしまい最悪破綻する可能性も出てきます。(聞く話によると、3桁の `.asmdef` が存在する規模のプロジェクトもあるらいしいです)

Assembly Definitionの依存関係を可視化できることができると、管理の助けになると思い上記のEditor拡張を開発しました。

# AsmdefGraph

https://github.com/naninunenoy/AsmdefGraph

## できること

プロジェクト内のAssembly Definitionの関係を取得し、 `GraphView` のノードエディタベースで表示します。
**あくまで表示するだけで、 `.asmdef` の編集/追加/削除には対応していません。**

また、全てのノードを同じ初期位置に生成するため、見やすいように人間が移動させたり、デフォルトで入ってるプロジェクトに関係ないノードを削除するなどして、自力で見やすくしてもらう必要があります。 😅

## やったこと

### CompilationPipeline

最初はプロジェクトのルートディレクトリから `GetFiles("*.asmdef", SearchOption.AllDirectories)` みたいに取得して、Jsonを読み込んでましたが、専用のAPIがあることを知り、そっちに切り替えました。

 * [CompilationPipeline](https://docs.unity3d.com/ja/2018.1/ScriptReference/Compilation.CompilationPipeline.html)

`CompilationPipeline.GetAssemblies()` でプロジェクトに関係する `.asmdef` の情報を `Assembly` クラスの一覧として取得できます。その中に、`assemblyReferences` のフィールドがあるので、参照している `.asmdef` のフルパスが取得できます。
これによって `.asmdef` の関係を網羅したマップを作成できます。

### GraphView
作成したマップをもとに可視化する訳ですが、`UnityEditor.Experimental.GraphView` を用いました。

* [GraphView完全理解した(2019年末版)](https://qiita.com/ma_sh/items/7627a6151e849f5a0ede)

こちらの記事のおかげで完成させることができました。🙏

* `EditorWindow` の中に `GraphView` がある
* `GraphView` に `Node` が属する(`AddElement()`する)
* `Node` にはinとoutの `Port` がある
* `Port` は `Edge` で繋がる

という関係性になっています。
`Edge` は `contentContainer.Add()` してやらないと表示されないということを知るまで結構かかりました。。

## やりたいこと

とりあえず見るだけなら今の機能でもできますが、特定の `.asmdef` の関係性にフォーカスする機能は欲しいかなと思っています。ノードを選んでそれに関係するノードとエッジをハイライトする(もしくは無関係なノードを見えなくする)イメージです。

## やらないこと

`.asmdef` のパスがわかるので、Jsonファイルとして処理すれば編集できなくもないですが、プロジェクトをぶっ壊しそうなのでやるつもりはありません。😅
`CompilationPipeline` のAPIも `get` しか公開されていませんでした。

# おわりに

Assembly Definition手軽で強力な機能なので、ぜひ試してみてください。
あとAPIとかEditor拡張用のクラスとか知らなかった便利な機能がUnityには色々あるんだなと思いました。🙏
ちょっとバグチェックしてほしいんだよね、と言われた時に何をするか

ちょっと社内の開発チームから、開発中のサービスを触ってみてくれと言われ、そしてそこにフォームがあったときにどんなことをすればよいのか、ざっとリストしてみた。ちなみに海外では社内の動作確認会をバグバッシュと呼んでいる。

- 連打してみる
    - とにかく連打すればよい。もし二重にデータができたら、喜びのポーズをしてもらってかまわない。

- 空欄のまま submit 
    - フォームがあったらとりあえず「送信ボタン」相当のボタンを何も記載せずに押してみよう。
        - エラー的な文言も何も表示されなかったらそれは問題である。
    - なお、よくトレーニングされた開発者が作成したフォームはなにか記載するまで「送信ボタン」が薄いグレーで表示されていたりする。
        - このようなフォームを見つけたら開発者を褒めてあげると開発者は内心とても嬉しいと思ってくれるだろう。

- フォーム表示後に、フォームの送信が通る条件 ( validation という) を別タブなどで変更する
    - 必須ではないフォームがあったら別画面でそれを必須に設定したりする。
    - 非必須のフォームを表示して、別タブで必須化する、設問項目を増やすなど。
    - 最近 Javascript で画面を構成する SPA が主流となってきたため、画面を構成した時に予期せぬ事態がとくにあとから発生した時、どれくらい耐久性のある防御的な実装をしているか問われてくる。
        - ある人は昔 Windows でよく見た「予期せぬエラーがおきました」という恐怖のエラー体験を思い出すかもしれない。

- 嫌な文字注入
    - 全角スペースだけ、半角スペースだけ、あるいは iPhone の絵文字を注入してなにかまずいことが起きないか。ユーザーは絵文字が大好きだが、開発者は大嫌いなことが多い。
    - 連続した記号、例えば --------- をいれてあげるとなにかレイアウト崩れが起きるかもしれない。

- POST 後にバックキーやリロードを組み合わせて意図しない動作か破壊検証
    - ユーザーは戻るボタンが大好きだ。
    - せっかちなユーザーは 0.5 秒でも待たされると、Mac なら Command + R、ウインドウズなら F5 を反射的に押下しているだろう。

- 一定時間放置して、1日くらいしてから送信する
    - 締め切り期限を過ぎた状態でフォームが表示されていて送信されたとき、締切を過ぎても受け付けてくれたら運営にとっては問題、それともユーザーにとってはラッキーなのか。

- 別タブでフォームを開いて、ダブル投稿して不都合がないか
    - 一人一回しか投票できない投票フォームを、複数画面同時に開いて複数回投稿できるとしたら・・ラッキー、いや、きっとまずいはずだ。

- フォームを表示したまま、ログインユーザーを切り替えて、フォームを表示した人と今ログインしている人が不一致の状態で投稿できるか検証する
    - 「俺、俺だよ俺」。そうオレオレ詐欺は Web サービスにも存在するのだ。

- 設定できないはずの値にパラメタを書き換えて POST 後のサーバサイドでの妥当性チェックをしているか破壊検証する (上級者向け)
    - 6桁の数字で入力してください、とかいてあったら、とりあえず Inspector を起動して、他の内容を注入してみる。

- hidden 値を意図しない値に書き換えて破壊する (上級者向け)
    - 見えないフォームで送信する内容を書き換えた時に意図しない動作をしないかどうか・・・! 

- とりま XSS / SQL 注入 (上級者向け)
    - もうここまで読まれた方は、詳しくは調べてほしい。


これらをサクッとやってあげて、問題があれば 5W1H をまとめて開発チームにフィードバックしてあげると一目置かれるはずだ。
とりあえずやってみるアジャイル"風"開発

![無題のプレゼンテーション (11).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87716/310c5f25-6e03-f5cf-c5b8-1b3b7d192520.png)

---

![無題のプレゼンテーション.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87716/9c44c3e1-9b48-b6ad-1456-e51a271c1c45.png)

---

![無題のプレゼンテーション (13).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87716/d23aed59-7376-6cf6-290b-12c1bb62dc39.png)

---

![無題のプレゼンテーション (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87716/ebd4b04a-9e95-3380-c7e6-0cee7cea0f22.png)

---

![無題のプレゼンテーション (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87716/53811bb6-3722-72a3-c250-c0a294255fae.png)

---

![無題のプレゼンテーション (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87716/edab0829-eb18-a5e9-5b01-b3f1126f6b55.png)

---

![無題のプレゼンテーション (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87716/9208a8da-b4f7-70e1-229b-317c19270b38.png)

---

![無題のプレゼンテーション (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87716/7907fcd5-b48d-9933-4207-96402b20b0a0.png)

---

![無題のプレゼンテーション (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87716/952dbfb4-0c5b-2fe3-58fa-a1b250f78d57.png)

---

![無題のプレゼンテーション (8).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87716/c5183fed-e75a-8db0-5e59-61121f76d1a6.png)

---

![無題のプレゼンテーション (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87716/92c5d4c0-a303-e3b3-b716-5efe2fa136e5.png)

---

![無題のプレゼンテーション (14).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87716/f33376a0-2868-0166-b7ab-5b56056933e8.png)

---

![無題のプレゼンテーション (15).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87716/7cbc3fa6-80fd-04ff-163f-d1937b338bc3.png)

---

![無題のプレゼンテーション (12).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/87716/7d3ffa8c-40b0-a59f-d83f-40b9e3197e2a.png)
ハッカソン系イベントを教えてくれるSlack bot v0.1作ってみた

# はじめに
connpassのAPIを使ってハッカソン関連のイベントを教えてくれるbotです
わざわざ調べなくても旬な情報がでてきます！


# 手順
### **Slackの準備**
**ボットのアプリをインストールする**
Slackのワークスペースにボットのアプリ(中身のない箱のようなもの)をインストールする。

ここをクリック。
![スクリーンショット 2018-01-29 13.25.35.png](https://qiita-image-store.s3.amazonaws.com/0/143517/0022686c-3347-86b1-6f75-16249303ca83.png)

"hubot"と検索し、インストールをクリック。
![Slack_-_テスト用.png](https://qiita-image-store.s3.amazonaws.com/0/143517/a1417dd9-935f-604c-e50c-ab013ed03fc9.png)

インストールをクリック。
![Hubot___Slack_App_ディレクトリ.png](https://qiita-image-store.s3.amazonaws.com/0/143517/349960d2-1aa9-1206-1661-a9f6990c66e5.png)

botのユーザー名を入力してHubotインテグレーションの追加をクリック。
![Hubot___テスト用_Slack.png](https://qiita-image-store.s3.amazonaws.com/0/143517/6c48c3ad-1870-e55b-c1f6-c81345cf5e33.png)

APIトークンなるものが発行されるのでメモしておく。
![Hubot___Slack_App_ディレクトリ 2.png](https://qiita-image-store.s3.amazonaws.com/0/143517/b7db07bd-463f-d3f3-88b6-c26e93796162.png)

Slackに戻ってみると、中身のない箱のようなボットが作成されていることが確認できますね。
![Slack_-_テスト用 2.png](https://qiita-image-store.s3.amazonaws.com/0/143517/ed3fe194-b2f3-7460-0ad1-094084eb9ae2.png)

### Google Apps Scriptの準備
各種伏せ字部分を埋めてください

```code.js
function myFunction() {
  var connpassApiOptions = {
    'method': 'get',
    'contentType': 'application/json'
  };
  
  var connpassApiResponse = UrlFetchApp.fetch('https://connpass.com/api/v1/event/?keyword_or=%E3%83%8F%E3%83%83%E3%82%AB%E3%82%BD%E3%83%B3&keyword_or=hackathon&count=30', connpassApiOptions);
  
  Utilities.sleep(2000)
  var content = JSON.parse(connpassApiResponse.getContentText("UTF-8"))
  
  var title = content.events[0].title
  var url = content.events[0].event_url
  var startTime = content.events[0].started_at
  var discription = content.events[0].description
  
  var text = " *最新のハッカソン情報をお届けします!!😆* " + "\n\n"
  
// ハッカソン関連のワードが含まれているかの判別
  content.events.map(function(value,index){
                                 if(Boolean(value.title.match(/ハッカソン/)) || Boolean(value.title.match(/アイデアソン/))  || Boolean(value.title.match(/thon/))){
    text = text + "- " + value.title + "(" + value.event_url +  ")\n\n"
  }
})
  
// hubotのtoken
  var slack_token = ★★★★★★★★★★★★;
 
  var slackApp = SlackApp.create(slack_token);
  // 対象チャンネル名
  var channelId = "#★★★★★★";
  // 投稿するメッセージ
  var message = text;
  
  var options = {
    'username': "★★★★★★", // botのSlack表示名
    'icon_url': "★★★★★★" // botのアイコン画像URL
  }
  
  slackApp.postMessage(channelId, message, options);
}

```

### 実行！
※実運用中なので画像と名前は伏せます
![スクリーンショット 2019-12-18 20.25.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143517/38507311-edab-1e01-6880-0195be16370d.png)

# おわりに
Google Apps Scriptの時計マークボタン(トリガー)を設定すると週に1回自動で教えてくれたりします♪
AWS環境構築（用語編）~EC2~

# AWSの基本サービスEC2
今回はEC2についてまとめてみた。
詳細は[公式ウェブサイト](https://aws.amazon.com/jp/ec2/)に譲ります。

EC2とElastic Compute Cloudの略で一言で説明するなら、Amazonが提供する仮想サーバーである。
自分たちでサービスを構築する場合、まずサーバーを購入し、設置して環境を設定する必要があります。もちろん、サーバーを置く場所を適当にするわけにもいかないですし、24時間稼働する必要があります。また、その時は十分だと思っていたスペックも不足することも十分にありえます。このあたりの煩わしさをAmazonさんにお任せしてやってもらうということです。

まずEC2を使用する上で頻繁に登場する単語がインスタンスという単語です。初めてその単語を聞いた時は全くなんなのか理解できませんでした。
インスタンスとは一言でいうならばOS付きの仮想サーバーです。このインスタンスを起動させるにあたり、OSの種類、インスタンスタイプを選択します。インスタンスタイプとは要はスペックです。めちゃくちゃ種類があって完璧には把握していませんが、Qiitaなどでよく見かけるt2 microというものは無料です。もちろん、それぞれの用途によって変更すべき部分です。
（[インスタンスタイプ一覧](https://aws.amazon.com/jp/ec2/instance-types/）)）

以下にEC2作成で登場する単語についてまとめます。

####AMI（[公式サイト](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/AMIs.html)）
Amazon Machine Imageの略。インスタンスを使用する時に必要となる。インスタンス起動に必要な情報が用意されている。
####IOPS
Input Output per seconds の略。1秒間に何回データを出し入れできるか
####パブリックアクセス
ユーザーがアクセスできるかどうか

##その他の関連記事
[AWS環境構築（用語編）~VPC~](https://qiita.com/ryuryu52868475/items/ce93d746991742a516a0)
[AWS環境構築（実装編）~VPC~](https://qiita.com/ryuryu52868475/items/e9600c1050051f407cf2)
複数の Mac で Google 日本語入力のユーザー辞書を共有する方法

Google 日本語入力のインストールや初期設定の方法については「 [Mac に Google 日本語入力を導入して設定する手順](https://qiita.com/normalsalt/items/017031713f6577e488aa) 」に書いておきましたが、

複数の PC 間で Google 日本語入力の『 ユーザー辞書 』を共有し、同期させて使うには、ちょっとした工夫が必要です。

まぁ、結論から言ってしまえば、**ユーザー辞書のデータが保存されているディレクトリを、Dropbox などのオンラインストレージを用いて共有するだけ** なんですけどね。

Mac の場合、そのディレクトリとは、次の場所にある `JapaneseInput` です。

```
% ls ~/Library/Application\ Support/Google
Chrome/ JapaneseInput/ RLZ/
```

厳密には「 ユーザー辞書のデータが保存されているディレクトリ 」というか、その他の Google 日本語入力に関するデータファイルも一緒に置かれているディレクトリのようですが、

これを、**Dropbox に移動させ、元の場所にはシンボリックリンクを作成しておく** ことで、ディレクトリの実体は移動されていても、構成としては何も変わっていないように見せかけます。

具体的には、以下のようなコマンドになるのではないでしょうか。

```
% mv ~/Library/Application\ Support/Google/JapaneseInput ~/Dropbox
% ls ~/Library/Application\ Support/Google
Chrome/ RLZ/
% ln -s ~/Dropbox/JapaneseInput ~/Library/Application\ Support/Google
% ls ~/Library/Application\ Support/Google
Chrome/ JapaneseInput@ RLZ/
```

これで、ユーザー辞書を共有する準備は完了です。

次に、Dropbox でディレクトリを共有済みの、別の Mac でも、同じようにシンボリックリンクを作成して、共有されているデータを使用するように変更しましょう。

```
% mv ~/Library/Application\ Support/Google/JapaneseInput ~/Library/Application\ Support/Google/JapaneseInput.bak
% ln -s ~/Dropbox/JapaneseInput ~/Library/Application\ Support/Google
% ls ~/Library/Application\ Support/Google
Chrome/ JapaneseInput@ JapaneseInput.bak/ RLZ/
```

こちらに元からあった `JapaneseInput` ディレクトリは、別に削除しても良かったのですが、一応、名前を変えて残しておきました。

後で、もし Windows でも同じユーザー辞書を共有するようなことがあれば、また追記します。
テスターがJSTQBのテスト勉強をして思ったこと

# はじめに
　　
会社からJSTQBで資格をとれ、といわれて初めてテストについて勉強しました。
今までは過去のテスト仕様書を参考にシステムの仕様書見てケース作ってテストして、の繰り返しで、本来テストとはどうあるべきなのかとか何のためにこのテストが必要なのか、というのは正直考えたことありませんでした。

そんな状態から、Foundation Levelとテストアナリストを無事取得しまして、いろいろと思うところが、、、というかまずはいろんな人にテストについて知ってほしいな、と思いました（知らないで10数年過ごしてた自分ってかなり残念だなあとの反省もあり）

そんなわけで、テスト勉強していて意外に思った、というか想定外だったことを中心に書いてみたいと思います。

# なぜテストが必要なのか

ソフトウェアが期待通りに動作しないと、何らかの不都合をユーザに与えることになり、作った側にもいろいろ悪いことが起こったりします。

- 経済的な損失
修正・再テストにかかるコストやユーザの業務停止による損害補償、機会損失への補償

- 時間的損失
修正作業による開発担当者の時間圧迫（他の製品の開発コストやスケジュールに影響を及ぼす）
マネジメント的な調整が必要になる

- 信用の失墜
製品競争力の低下、会社そのもののイメージの低下、傷害や死亡事故

こんなことになると会社として立ち行かなくなるので、ソフトウェア開発においては、期待通りに動作するものを納品するのが第一目標なわけです。
スタート地点はここです。テストの価値は決して画面キャプチャの数やカバレッジではないのです。



#「期待通りに動作する」の「期待」って具体的にどんなこと？

普通はここで品質の話をするんだと思いますが（実際、JSTQBでもあたりまえ品質と魅力的品質の話とかFRUEMPとか出てきます）実際にはそれ以前のところで引っかかる方が多いよな、と思っています。
どういうことかというと、いわゆる開発あるあるネタ。
お客様に「カレー作って」と言われてカレーだけ作ったらご飯と福神漬けがついてないって怒られたとか、実はシチューが食べたかったっていわれたとか、、、、ありますよね。

原因の大半はコミュニケーション不足と言われたりしますが、実際のところ、欲しいなと思っているものを現実的なシステム仕様に変換するのって、思っている以上に難しいのだと思います。
それは、ユーザが求めているものが具体的な何かであるのに対して、システムで作るのはそのもとになる理論（ルール）だからです。
例えば月末に請求書出して、という要求があったとします。この要求の背景には多くのルールがあります。締めは末日なのか20日なのかとか、年末はどうするのか、末日が休日だったらとか。システムはルールを求めます。こうした見えないルールの存在に気づくことも、テスターに期待されるかのようにシラバスには書かれています。

困るのはこうした「ルール」の存在自体を発注者自身が理解してない時です。請け負った方も気づいていない、細かなルールはシステムが形になっていくにしたがって明らかになったりもします。（いわゆる「やってみなければわからない。」）


# テスター像
従来のウォーターフォール型の開発工程では、要求とか要件とかは、かなり上流にあるものです。そうした場合、テスターは実装と同時か実装中にプロジェクトに参加することが多く、要件定義などの初期からかかわることはまれです。
ウォーターフォール式の開発の場合は特に、要件定義がしっかりできていないと後で大変なことになります。なのでJSTQBでは、要件定義に対するテスト、それが本当に顧客の要件を満たしているのか確認すること（レビュー）がちゃんと場所を占めています。
要求を要件に落とし込めているかをテストするためにも、テスターは開発の初期からプロジェクトにかかわるべきだといわれていますし、また、そうしたテスターの能力としては単にテストケースを実行するだけではなく、その案件に関する知識や経験（一般常識や法令も含めて）が必要とされています。
平たく言えばECサイトのテスト担当なら、そのサイトに支払いや配送に関する機能またはそうした機能との連携がなかったら変だな？と思えないとだめだよねってことなのです。

一般に「テストを実行する人＝テスター」という認識だと思っていましたが、それとはちょっと違うな、という印象をうけました。

# どこまでテストするのか
もう一つ、有名な「テストの七原則」というのがあるのですが、その中に「全数テストは不可能」というものがあります。　

例えば電卓機能を製品に持たせるとして、１＋１、１＋２、１＋３、と電卓で計算できるケースをすべて実行するのは不可能だよね、という話です。

ではそうした場合にどこまでテストするのか、というのが問題になるわけです。一般的な手法の話としては、境界値分析とか直交表とかペアワイズ法とか、あるいはC1カバレッジだとかいろいろあるのですが、そもそもどこまでやるべきなのか、どこまでやればいいのか、というのはまた別の話になります。

それはリスクとコスト、納期から決まります。決まる、というより決める、といったほうが正しいかも。

微に入り細に入りテストできるならしたほうが不具合は減るでしょう。でも現実問題として全数テストは不可能です。ならば、エラーが出たときに影響が大きいもの、またはエラーが出やすいものを中心にテストして、それらの範囲はコストと時間で決めましょう。というのがJSTQBのシラバス（多分アドバンストの方）に書かれていました。
完璧は無理。じゃあ次善の策としてどこまでやっとく？というのを決める（少なくとも決めるための材料を提供する）のもテスターの仕事のうちなのです。


# 終わりに

個人的な印象、感想を中心に書いてきましたが、テスターの試験だと思っていたので範囲の広さにちょっとびっくりでした。テスト手法とか、バグレポートの書き方とか、そういうものだけじゃなくて、むしろ開発方法や出荷に関わるようなネタも入っていて、自分のテストに対する見方が変わったかなと思います。
テスターだけでなく、プログラマやプロジェクトリーダーにも役に立つことがいろいろ書かれているので、ぜひ勉強してみてください！といいたいところなんですが、JSTQBのシラバスは日本語訳がちょっと。。。なので黒本から入るのがおすすめです。
<input type="file">をカスタマイズ

`<input type="file">`を頑張ってカスタマイズしました。

<p class="codepen" data-height="265" data-theme-id="default" data-default-tab="html,result" data-user="d0ne1s" data-slug-hash="OJPWgqP" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="form_file">
  <span>See the Pen <a href="https://codepen.io/d0ne1s/pen/OJPWgqP">
  form_file</a> by d0ne1s (<a href="https://codepen.io/d0ne1s">@d0ne1s</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

##ポイント
- `<input type="file">`のデザインは変更できないので、`display: none`で非表示にしています。
- 代わりに`label`と`label:after`で、ボタンと「選択されていません」の文字列を表現しています。
- ファイルが選択された時、`label:after`を非表示にし、代わりに`<span>ファイル名</span>`を表示するようなjqueryを書きました。
- 同一ページ内に複数あっても動くようになってるはずです。（その場合、各input要素の`id`と、labelの`for`は適宜変更する必要があります。）

##2020/04/27追記
jqueryを使わずに書けました。

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="html,result" data-user="d0ne1s" data-slug-hash="eYpvzLm" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="eYpvzLm">
  <span>See the Pen <a href="https://codepen.io/d0ne1s/pen/eYpvzLm">
  eYpvzLm</a> by d0ne1s (<a href="https://codepen.io/d0ne1s">@d0ne1s</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>


##その他
- こういうテンプレートを増やして、いい感じのデザインをパパッと作れるようになりたいです。
- 今回の書き方だとjqueryに依存しているので、時間がある時に生のJavascriptでもかいてみようと思います。

##参考
[input=”file”要素のデザインをフルカスタマイズする](https://designsupply-web.com/knowledgeside/2747/)
rails 部分テンプレート健忘禄


#rails ~render 健忘禄~ 

共通部分のレイアウトをまとめて一つのファイルにしてそれを使い回す際に用いられる

`code`
```index.html.erb
<render "パス" >
```
↑で記述したところに"_ファイル名.html.erb"のレイアウトが表示される。

- パスの部分は部分テンプレートのファイル名がインスタンス変数の単数形
- 部分テンプレートのファイル内で使う変数名が同一であること
この条件を満たしていれば

`code`
```index.html.erb
<render "@インスタンス変数名" >
```

と記述することができる。
Idea(Android Studio)のプラグインインストール

# はじめに

ネットに接続できないローカル環境で製造するときにIdea(Android studio)にプラグインをインストールする方法をいつも調べてインストールしていたので、自分用の記事にすることにした。

# 環境

AndroidStudio:3.5.2

# 方法

まず、AndroidStudioを起動して
File→Settings
をクリックする。
<img width="686" alt="画像1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540218/fc8b6f50-0af0-717c-4ff3-fdb1306dca06.png">

表示された設定画面の
Plugin→歯車のマーク→Install Plugin from Disk
をクリックする。
<img width="758" alt="画像2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540218/4806b93c-59d9-ace7-871c-394ecc85c58a.png">

プラグインを選択するダイアログが表示されるのでプラグインを選択して
OKをクリックすれば、あとは勝手にインストールしてくれる。

# おわりに

これでまたAndroidStudioにプラグインをインストールするときにいちいち調べる必要がなくなる。
Android 4.4のサポートはもうやめるべきなのだ


<blockquote class="twitter-tweet"><p lang="und" dir="ltr">23</p>&mdash; minSdkVersion (@minSdkVersion) <a href="https://twitter.com/minSdkVersion/status/1204145130673975311?ref_src=twsrc%5Etfw">December 9, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

minSdkVersionをつぶやくだけの謎なTwitterアカウントが23(Android 6)とツイートしていたのがまだ記憶に新しい。

世の中のminSdkが5.0以上がもう大多数になってきたかなと思っているが、4.4ユーザが数％まだいるからという理由でまだサポートを強いられている現場だってまだ存在している。
まぁ、5.0以上でしか使えないAPIやWebView周りの挙動があったのだとしても切り分けして
ソースコードを無駄に条件分岐でややこしくしたり、最悪4.4以下ユーザはごめんねすればいい話なのかと呑気に思っていた。
しかしとあるニュースを見てちょっと考え直した。

## RetrofitライブラリがAndroid 5+の対応になった
https://github.com/square/retrofit/blob/master/CHANGELOG.md#version-270-2019-12-09

この変更についての詳しい情報は以下
https://cashapp.github.io/2019-02-05/okhttp-3-13-requires-android-5

要するにAndroid4.4はTLS1.2を標準サポートしていない。

そして下記の箇所に一番驚いた
> On October 15 our colleagues at Google, Mozilla, Microsoft, and Apple announced that their browsers will require TLSv1.2 or better starting in early 2020.

つまり主要ブラウザはTLS1.0,TLS1.1のサポートを終了する。
即ち、世の中のスタンダードはTLS1.2に移行し、TLS1.1はもうセキュアじゃないという判断だ。


> If you really need TLSv1.2 on Android 4.x, that’s possible! Ankush Gupta has written a thorough guide that explains how to get Google Play Services to do it. Even if you follow this process you should still use OkHttp 3.12.x with Android 4.x devices.

Android 4.xでもTLS1.2を行う方法はあるとのこと。
しかしすでに大多数のアプリがAndroid 4.4のサポートをすでに終了している。
とある1アプリだけAndroid 4.4のサポートを続けられたとしても、それ以外のサポートの終了したアプリでは
TLS1.1の通信を行う。これでは意味がない。

なので**Android 4.4のサポートを終了し、よりセキュアな通信ができるAndroidへ移行を促す**べきなのだ。


---
参考
https://github.com/AndroidDagashi/AndroidDagashi/issues/1168
【#PowerApps】コンポーネントの新機能

# 概要

2019/12/18 にコンポーネントに機能が追加されたのでそのご紹介

# Power Apps のコンポーネントとは

Power Apps の部品をスクリーンやアプリ間で使いまわすための仕組みです。
詳しくはこちらの記事をご覧ください。
[#PowerApps の Componentsについて紹介](https://qiita.com/h-nagao/items/daf143225f28acb7990f)

# 新機能

## コンポーネントにギャラリーが配置可能になりました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183354/bdd33c64-3b5c-d925-4391-a20721f07c9e.png)

これによって今まで共通化できなかった部品をコンポーネント化(共通化)できるようになりました。

## テーブルとレコードを入出力プロパティとして受け取れるようになりました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183354/83d7de42-126b-b8eb-7478-41762949c26d.png)

テーブルやレコードの変換機能をコンポーネント化することができるようになりましたねー

## コネクターが利用可能になりました

コンポーネントの中から各コネクタを直接利用することが可能になりました！
Office 365 コネクターを追加し、

```
Office365ユーザー.MyProfile().DisplayName
```

といったことがコンポーネントでも可能となりました。



# まとめ

ギャラリーとコネクターが利用できるようになっていままで、ヘッダーやサイドメニューといった簡単なものしかコンポーネント化は難しかったのですが、今回のアップデートによってほとんどすべての機能やビジュアルがコンポーネント化することができるようになりました。

# 参考


- https://powerapps.microsoft.com/en-us/blog/canvas-components-get-support-for-connectors/
Firestoreリアルタイムリスナーで通知ドットを実装してみたよ

リアルタイムリスナーってすごい機能なのにあまり使い道を見出せず単一リクエストばかりしていたのですが、ちょっと使えそうな余地のある部分を発見したので試してみました。

## 通知ドット
SNSやお知らせなどのタブ上にあるアレです。不定期更新な機能でも見て欲しい時に見てもらうための導線になるのでよいものです。
未読がないか毎回フェッチするよりも、リアルタイムアップデートしたほうが面白いのでリアルタイムにデータを同期して通知ドットを表示させてみようと思います🐞

## 仕様
- お知らせ一覧へ遷移するタブをもつアプリ
- お知らせに未読があればお知らせタブ上に通知ドットを表示してあげる
- お知らせのソートは常に最新順

## 実装方法

### 未読判定
未読かどうかの判定は取得された最新１件のドキュメントIDと既読とみなされたローカルに保存されているドキュメントIDで判断するシンプルなものです。

```swift
public struct UnreadState {
    private(set) var latestLocalId: String?
    private(set) var latestRemoteId: String?

    public var hasUnread: Bool {
        guard let local = latestLocalId,
            let remote = latestRemoteId else {
            return false
        }
        return local != remote
    }

    // ...
}
```

### お知らせのコレクションをつくる
`notifications/{notificationId}`

### Firestoreリアルタイムリスナーでデータを監視
お知らせコレクションの最新１件をリッスンする

```swift
Firestore.firestore()
    .collection("notifications")
    .order(by: "createdAt", descending: true)
    .limit(to: 1)
    .addSnapshotListener({ (snapshot, _) in
        // 最新１件目のドキュメントID
        let latestRemoteId = snapshot?.documents.first?.documentID
    })
}
```

### ローカルの未読は とりあえず UserDefaults
お知らせ一覧へ遷移した時に最新の１件のドキュメントIDを既読とみなして保存する。

```swift
// お知らせ一覧を取得してきた想定
let notificationId = notifications.first?.id
userDefaults.set(notificationId, forKey: .lastReadNotificationId)
```
お知らせ一覧へ遷移時に単一リクエストで取得した最新１件を保存する。
> このようにフラットに保存してしまうと複数アカウントの未読を管理できないですがここでは知らなかったことにする。

### Viewの更新
```swift
// 通知ドットView
let notificationDot: DotView = .init()

// state is Observable<UnreadState>
state
    .map { $0.hasUnread }
    .distinctUntilChanged()
    .bind(to: Binder(self) { me, hasUnread in
        me.notificationDot.isHidden = !hasUnread
    })
    .disposed(by: disposeBag)
```
RxSwiftを利用していますがなんらかの方法でViewに変更を伝えます。
 
### 通知ドットView

仕上げに通知ドットViewにはいい感じの出現アニメーションを実装してあげます。

```swift
class DotView: UIView {

    init() {
        super.init(frame: .init(x: 0, y: 0, width: 5, height: 5))
        backgroundColor = SPColor.badge
        layer.cornerRadius = bounds.midX
        isHidden = true
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override var isHidden: Bool {
        didSet {
            guard oldValue != self.isHidden else {
                return
            }
            if !self.isHidden {
                appearAnimation()
            }
        }
    }

    private func appearAnimation() {
        self.transform = CGAffineTransform(scaleX: 0, y: 0)
        UIView.animate(
            withDuration: 0.6,
            delay: 0,
            options: .curveEaseInOut,
            animations: { self.transform = CGAffineTransform.identity }
        )
    }
}
```

`isHidden`プロパティをオーバーライドして出現時に拡大アニメーションを追加しました。

![dotview.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203147/53bd8afc-fbc0-901e-a1da-cda9a4927728.gif)

ドーパミンが分泌されます😇

## おわりに
このまま実運用だと並び順の変更や未読数カウントなどによって破綻する未来が見えますが、わりと最小限実装で事足りるケースも少なくないかと思います。この機能を応用して更新フラグに利用したりもできそうです。
PHPでお問い合わせフォームを作る

# PHPでお問い合わせフォームを作ってみよう
最近、新人君たちにプログラミングを教える機会が多くなってきました。
教えていく中で「自分の教え方って大丈夫なんだろうか？」と最近不安になっている次第。
という事で簡単なお問い合わせフォームを作る事で、人への教え方を再考するために「お問い合わせフォーム」を題材にちょっとずつ難しい事を実装していきます。
そして、最終的には実戦で使えるようなフォームを作れるようになります。

# フォームの全体の流れ
1. 入力画面
2. 確認画面
3. 完了画面

てな感じで

じゃあ、もうちょっと細かくみてみましょう

### 入力画面
うん、これがないと始まらないですね。
今回はお決まりの以下の入力項目にしてみます
項目１　お名前
項目２　メールアドレス
項目３　お問い合わせ内容

お、お、ぉぅ　最低限の設定やね。。今後拡張していく予定なので我慢してください。。。

### 確認画面
そう、ここで入力した内容を表示して「送っていいですか？」って確認させます。

### 完了画面
要するに「ありがとうございました」ページです
ここでメール送信とかデータベースに接続とかいろいろあるけど、とりあえずはメール送信しときましょう


## 細かいとこ
とりあえずPHPで動く事を目標にするのでCSS等は後回しにします


# 入力画面
取り敢えず最低限のこのhtmlで

```html:index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>phpでフォーム送信</title>
</head>
<body>
<form action="./confirm.php" method="post">
    <div id="contents">
        <div id="name">
          お名前　<input type="text" name="name">
        </div>
        <div id="mail">
          メールアドレス　<input type="text" name="mail">
        </div>
        <div id="toiawase">
          お問い合わせ内容　<textarea name="toiawase"></textarea>
        </div>
        </br>
        </br>
        <input type="submit" value="確認">
    </div>
</form>
</body>
</html>
```
味気の無い画面ですね。
name="name"　のテキストボックスが名前を入れるところです
name="mail"　がメールアドレス、テキストエリアに問い合わせ内容ですね
そして formタグで 確認ボタンを押した後のリクエスト先が指定されています
`action=./confirm.php"`　です。この記述で、ボタンを押したらconfirm.phpにリクエストを投げます。
そして `method="post` の記述でリクエスト時はPOSTでデータを投げる、と指定しています。


# 確認画面
入力画面で確認ボタンをクリックすると form タグの指定通り confirm.php にリクエストが投げられます。

```php:confirm.php
<?php

	$name = $_POST['name'];
	$mail = $_POST['mail'];
	$toiawase = $_POST['toiawase'];

echo "
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<title>Insert title here</title>
</head>
<body>
お名前：$name
</br>
メールアドレス：$mail
</br>
お問い合わせ内容
</br>
$toiawase
</br>
</br>
<form action='complete.php' method='post'>
<input type='hidden' name='name' value='$name'>
<input type='hidden' name='mail' value='$mail'>
<input type='hidden' name='toiawase' value='$toiawase'>
<input type='button' onclick='history.back()' value='戻る''>
<input type='submit' value='確認'>
</form>
</body>
</html>";
```

はい、必要最低限の記述です。
`index.html` で入力された内容が表示されると思います。
ここ（confirm.php）で、本当はやっておかなきゃいけない事、やっておいた方が良い事、やらない方が良い事を書いておきます

**やっておかなきゃいけない事**
postで投げられたデータのチェック(nullチェック、文字数チェック、その他もろもろチェック)

**やっておいた方が良い事**
セッションへの値保存、テンプレートの使用

**やらない方が良い事**
hidden タグの使用

これらのやり方、対応方法は後々の記事で書いていきます。
ここまでで データの入力、データの送信、データの受信、データの表示まで出来ました。
この画面で確認がOKであれば 次へボタン をクリックして完了画面に移ります

# 確認画面

```php:complete.php
<?php

$name = $_POST['name'];
$mail = $_POST['mail'];

$toiawase = $_POST['toiawase'];

$mailTO = $mail;
$mailHeader = "From: from@from.com";

$mailSubject = "お問い合わせありがとうございます";
$mailBody = $name . "様 お問い合わせありがとうございます";
$mailBody .= "¥n";
$mailBody .= "ご返信まで～～～～";

mail($mailTO, $mailSubject, $mailBody, $mailHeader);

echo "
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<title>Insert title here</title>
</head>
<body>
お問い合わせありがとうございます。
</body>
</html>
";
```
はい、これでデータ（名前、メールアドレス、問い合わせ内容）を入力し、データを送信
confirm.php で受け取ったデータの表示、データの送信
complete.php でデータ受け取り、メール送信、完了画面の表示
ここまで出来ました。


# 最後に
今回書いた内容は本当に必要最低限の流れですが、次回からこのフォームに肉付けしていこうと思います。
vscodeでhtml.erb用のスニペットを登録

vscodeには拡張子ごとにスニペット(定型文)を登録する機能がありますが、`erb`用のスニペットを作っても`html.erb`で利用することができませんでした。

不具合でしょうか?

代わりにグローバルスニペットを作成して対応したので、設定方法と記述内容を書いていきます。

##グローバルスニペットを作成
1. `CODE>基本設定>ユーザースニペット`をクリック

2. 「新しいグローバルスニペットファイル」をクリック

3. 任意のファイル名を入力（私は`html.erb`と入力しました）

4. 以下のようにファイルを編集

```json:html.erb.code-snippets
{
	"embedded Ruby": {
		"prefix": "erb",
		"body": [
			"<% $1 %>"
		]
	},
	"print embedded Ruby": {
		"prefix": "prb",
		"body": [
			"<%= $1 %>"
		]
	},
	"link_to": {
		"prefix": "lt",
		"body": [
			"<%= link_to $1, $2 %>"
		]
	},
	"link_to group": {
		"prefix": "lg",
		"body": [
			"<%= link_to($1) do %>",
			"<% end %>"
		]
	},
	"image_tag": {
		"prefix": "it",
		"body": [
			"<%= image_tag '$1' %>"
		]
	},
	"form_for": {
		"prefix": "ff",
		"body": [
			"<%= form_for @$1 do |f| %>",
			"  <%= f.label :name %>",
			"  <%= f.text_field :name, class:'form__txt'%>",
			"<% end %>"
		]
	},
	"end": {
		"prefix": "end",
		"body": [
			"<% end %>"
		]
	}
}
```

##構文解説
以下で一かたまりです。

```json
"embedded Ruby": {
  "prefix": "erb",
  "body": [
    "<% $1 %>"
  ]
}
```
`"embedded Ruby"`：タイトル。識別用。
`"prefix": "erb"`：erbと入力してTABキーをクリックした時に、スニペットが展開されるように設定しています。
`"body":`：この下に、展開するスニペットの内容を登録します。
`"<% $1 %>"`：展開されるスニペットです。展開時`$1`の部分にカーソルが合った状態になります。

あとは好きな数だけ、json形式でスニペットを登録することができます。

##参考
[VSCodeにコードスニペットを登録して効率的にコーディング！](https://haniwaman.com/vscode-snipet/)
pyenv でcan't decompress data; zlib not availableが出る場合

メモ

環境： Mac OSX 10.15.1（19B88）

pyenvで新しいpythonバージョンをインストールしようとすると、以下のエラーが出ることがある。

```terminal:terminal

$ pyenv install python3.6.2

python-build: definition not found: python3.6.2

See all available versions with `pyenv install --list'.

If the version you need is missing, try upgrading pyenv:

  
$ pyenv install 3.6.2

python-build: use openssl from homebrew
python-build: use readline from homebrew
Downloading Python-3.6.2.tar.xz...
-> https://www.python.org/ftp/python/3.6.2/Python-3.6.2.tar.xz
Installing Python-3.6.2...
python-build: use readline from homebrew

BUILD FAILED (OS X 10.15.1 using python-build 1.2.8)

Inspect or clean up the working tree at /var/folders/3k/g2s6z15s20q8bzy_5btxg29r0000gn/T/python-build.20191218194948.78102
Results logged to /var/folders/3k/g2s6z15s20q8bzy_5btxg29r0000gn/T/python-build.20191218194948.78102.log

Last 10 log lines:
  File "/private/var/folders/3k/g2s6z15s20q8bzy_5btxg29r0000gn/T/python-build.20191218194948.78102/Python-3.6.2/Lib/ensurepip/__main__.py", line 4, in <module>
    ensurepip._main()
  File "/private/var/folders/3k/g2s6z15s20q8bzy_5btxg29r0000gn/T/python-build.20191218194948.78102/Python-3.6.2/Lib/ensurepip/__init__.py", line 189, in _main
    default_pip=args.default_pip,
  File "/private/var/folders/3k/g2s6z15s20q8bzy_5btxg29r0000gn/T/python-build.20191218194948.78102/Python-3.6.2/Lib/ensurepip/__init__.py", line 102, in bootstrap
    _run_pip(args + [p[0] for p in _PROJECTS], additional_paths)
  File "/private/var/folders/3k/g2s6z15s20q8bzy_5btxg29r0000gn/T/python-build.20191218194948.78102/Python-3.6.2/Lib/ensurepip/__init__.py", line 27, in _run_pip
    import pip
zipimport.ZipImportError: can't decompress data; zlib not available
make: *** [install] Error 1
```

と表示が出る場合は、以下で回避できる。

```terminal

CFLAGS="-I$(xcrun --show-sdk-path)/usr/include" pyenv install 3.6.2

```
Hover.cssをReact上で使って、要素をブルンブルン動かしたい！

## はじめに
タイトル通り、Reactで生成した要素にホバーアクションを実装してブルンブルン動かしたくなったのでやってみました。

## 開発環境
VsCode
npm 6.12.1

## セットアップ
###Hover.cssのインストール
何パターンか方法があるらしいですが、今回はGithubからソースファイルを引っ張ってきてローカルに保存する方法でやってきます。

https://github.com/IanLunn/Hover
上記サイトのcssフォルダ配下にある`hover-min.css`をダウンロードして、ローカルの適当なフォルダに配置します。

###hover-min.cssを上位のスタイルファイルでインポート
プロジェクトの上位のスタイルファイルで、保存した`hover-min.css`をimportします。

```
@import url("hover-min.css");
```

###classをつける
これでHover.cssを使える状態になったので、ブルンブルンさせたい要素に対してクラスをつけてあげます。

```
    <div className="hvr-grow">
```

## 動作確認
サーバを起動して確認してみましょう。
![screen.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502798/73d17605-0c6b-da1e-c862-678affc72e88.gif)

## 終わりに
楽ちんですね。