OmniAICreator/Qiita-1.07M huggingface dataset:
Kali LinuxとCentOS7２台の仮想サーバ構築からpingを各方向に通すまで

ハッカーの学校という本を買ったので、KaliLinuxを使って本の内容を実践するための環境づくりを自分なりにまとめておきます。

本記事ですが、OSのインストールについては触れておらず、
OSインストールからブリッジ設定を行ってPing疎通が取れるところまでをまとめています。



**１．構築環境**

VirtualBox 5.2.12

KaliLinux 2018.2
ホスト名　：kali.localcom
IPアドレス：192.168.11.18

CentOS 7×2台
ホスト名　：mouse.localcom
IPアドレス：192.168.11.19

ホスト名　：rat.localcom
IPアドレス：192.168.11.21


ちなみにホストはWin10です。

**２．OSのインストール**

詳しいOSのインストール方法は今回端折ってます。
(記事にまとめるつもりがなかったから何も残してなかった。。。)

Kali Linuxはちょっとバージョン違うけど以下を参考にさせていただきました。
https://www.websec-room.com/2014/01/07/1485

CentOSはストレートに。。。。


**３．ネットワーク設定**

*1.設定したいVMを選択して『設定』を押下。*

![virtualbox_main.png](https://qiita-image-store.s3.amazonaws.com/0/272948/596764ce-e5c0-02f3-038c-c248a73db959.png)


*2.ネットワークを選択し、『割り当て』をブリッジアダブターに設定してOKを押下。*


![virtualbox_nw_conf.png](https://qiita-image-store.s3.amazonaws.com/0/272948/dbb9354b-f138-5cab-3ce4-06b316f430d0.png)


*3.全VMに同じ設定をしたら、それぞれ起動する。*

↓起動するとこんな感じ
![virtualbox_servers.png](https://qiita-image-store.s3.amazonaws.com/0/272948/71898df6-3635-7587-982c-19e3b33a9b7f.png)


*4.ホストネームの設定(Ping通すだけなら必ず必要ではない)*

```sh:/etc/hostname
# 任意のホストネームを設定する。
vi /etc/hostname
```
ホストネームはhostnameコマンドでも設定できるが、
VMを再起動すると/etc/hostnameを参照してホストネームを設定しているため、
変更内容が反映されないので恒久対応で/etc/hostnameを編集しています。


*5.IPアドレスを確認する。*

```sh:cmd
#実行するとなんかいっぱい出てくるので、enp0s3のinetを見ればそれぞれのIPアドレスがわかります。

ip addr

```

*6.Pingを送信してみる。*

```sh:cmd
ping -c 4 <inet>
```
これでパケットが損失してなければ疎通確認はOK!


**４．最後に**

初めて記事を投稿するので、基本的なルールとか守れてない可能性もあるので
気づいたこと等ありましたらご指摘ください。

また、これからも記事投稿を続けていきますので、
気が向いたらご指導いただければと思います。

次回は今回作成したCentOSにvsftpdをインストールし、FTPサーバを構築してみます。

以上です～
Powershellのダウンロード処理でプロキシサーバーエラーが起きる件の対処

## 事象
Githubのリポジトリをクローンしたり、VagrantのBoxをダウンロードしたり、
Poweshellでファイルをダウンロードする処理がことごとくエラー。

## 原因（推測）
「HTTPS_PROXY」という環境変数が定義されていたために、プロキシ経由でダウンロードが行われていた。
「HTTPS_PROXY」の値が https://proxy.server.com:8080 というでたらめな値だったために、ダウンロードに失敗していた。

## 対処
環境変数「HTTPS_PROXY」を削除する。
【3分でわかる】Amazon Connectは何がすごいのか？

# Amazon Connectって何？
[Amazon Connect](https://aws.amazon.com/jp/connect/)はAWSのサービスの1つで、クラウド上でコールセンターシステムを提供するものです。

# そもそもコールセンターに必要なものって？
仕事柄、コールセンターの構築案件とかを結構やってきたのですが必要なシステム（コンポーネント）は一般的に以下のようなものがあります。

- **PBX**
    - いわゆる電話の根幹の機能。SIPサーバと呼んだりもする。
- **CTI**
    - オペレータのスキルに応じた呼の振り分けとか。CRMの顧客情報と連携させたりとか。 
- **IVR**
    - 「○○の方は1を押してください」とか自動アナウンスするやつ。人をイライラさせる。
- **リアルタイムレポート**
    - 入電状況とかオペレータの空き状況を把握する
- **ヒストリカルレポート**
    - 過去の入電状況を把握する。KPIとかに使われるので非常に重要
- **通話録音**
    - クレームのときの証拠になったり、オペレータの評価に使ったり
- **音声認識**
    - 最近はビッグデータとなって分析とかに使われがち

ざっと挙げてこれくらい。最近だと問い合わせ手段は電話だけじゃなく、チャットなんかも登場してますね。
電話だと1対1ですが、チャットだとオペレータは同時に3人くらい相手にできるので効率がよいそうです。

# Amazon Connectは何がすごいの？
話がそれました。
いままでこれだけのシステムを作ろうと思ったら半年とか長ければ1年とかかかりますし、お金も何千万・何億とかかってたわけです。
このビジネスモデルをAmazonはブッ壊そうとしてます。

- **コールセンターに必要な大半のシステムを、画面ポチポチで簡単に作れる**
    - 特にIVRなどのコールフローはGUI上のフロチャートで直感的に操作が可能
- **初期費用なし。通話時間に応じた課金体系**
    - 日本だとフリーダイヤルは＄0.2114/分（約23.7円/分、通話料含む）、通常ダイヤルインは＄0.0056/分（約0.63円/分、通話料は電話かけてきた人が別途負担）　※＄1＝112円計算
    - 従来は1席いくらのライセンス体系で、使ってなくてもお金を払うのが一般的だった
- **ピークに合わせたシステム拡張の考慮不要**
    - クラウドなので必要なときに必要なぶんだけリソースを使う思想
    - Amazonプライムデーの問い合わせ対応で培った技術が活かされているらしい

# 日本におけるAmazon Connectの課題
じゃあAmazon Connectは爆発的に普及するのかというとそうではありません。
というのも、日本で利用するにはまだまだ課題も多いです。

- **既存の電話番号の移行ができない**
    - 新規にコールセンターをつくるならまだしも、既存コールセンターの電話番号を変えるのは結構な障壁
    - ~~電話番号はAmazonが用意した050番号（ダイヤルイン）、0800番号（フリーダイヤル）のみ~~
        - 0120は知ってても、0800がフリーダイヤルとはほとんどの人が知らない
        - 電話番号を変えないためボイスワープするという案はありかも

    **→　(2018/12/11追記)：フリーダイヤル0120が2018年11月に使えるようになりました。**

- **音声品質がよくない**
    - ~~現状は東京リージョンがなく、シドニーリージョンを使うことになる~~
    - 実際に通話してみたところ、音声の遅延(1秒程度)やプチプチ途切れたりということが結構ある

    **→　(2018/12/11追記)：東京リージョンが2018年11月に開設されました。**

- **~~音声認識が日本語対応していない~~**
    - [Amazon Lex](https://aws.amazon.com/jp/lex/)や[Amazon Transcribe](https://aws.amazon.com/jp/transcribe/)の日本語対応に期待

    **→　(2020/9/4追記)：Amazon Transcribeは2019年11月に日本語対応しました。**
    **→　(2021/4/2追記)：Amazon Lexは2021年4月に[日本語対応](https://aws.amazon.com/jp/about-aws/whats-new/2021/04/amazon-lex-launches-support-japanese/)しました。**

- **(2021/12/22追記)：日本の電話番号を取得するのにサポートケースの起票および書類提出が必要。また個人利用は不可**
    - 以前はAmazon Connectの画面から簡単に電話番号の取得ができたのですが、2020年に規制がかかって変更になったようです

https://dev.classmethod.jp/articles/tsnote-support-amazon-connect-003/

https://qiita.com/kei75/items/a0bbf966e466efc235a1


# おわりに
ハンズオンの前置きを書くつもりがだいぶ長くなってしまい、結局コラムみたいになってしまいました。
別途ハンズオンを書こうとおもいます。
IBM Notes 9がうんともすんとも言わないときの対処法(Mac)

#背景
IBM Notes 9を普段使用していたのに急に起動ができなくなってしまった。
起動してもログインパスワードを打った直後に落ちてしまう。
エラーメッセージも特に無い。どうしたものかと困っていたところに以下のページを発見。
http://www-01.ibm.com/support/docview.wss?uid=swg22012665

どうやらMacにインストールされているJavaのバージョンにNotesが対応してないようである。
とても心当たりがあるので、JavaをアンインストールしてNotesが対応しているJDKのバージョンに戻す作業を試みる。

#対処手順

###1. javaのアンインストール

```
$ sudo rm -fr /Library/Internet\ Plug-Ins/JavaAppletPlugin.plugin
$ sudo rm -fr /Library/PreferencePanes/JavaControlPanel.prefPane
$ sudo rm -fr ~/Library/Application\ Support/Oracle/Java
```

###2. Java1.8_151のJDKをインストール
以下URLからJava1.8_151のJDKをインストールする(要Oracleアカウント)
http://www.oracle.com/technetwork/java/javase/downloads/java-archive-javase8-2177648.html

###3. jdkのバージョン変更
~/.bash_profileに以下2行を追記
```
export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/A/Commands/java_home -v “1.8.0_151”
PATH=$JAVA_HOME/bin:$PATH
```

###4. 以下を実行
```
$ source ~/.bash_profile
$ java -version
```

Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
が表示されれば、JDKの切り替えは終了。
Notesが起動することを祈る(私はこの手順で解決しました)

#まとめ
MacのNotesユーザーでJavaのアップデートをした人が結構ハマったそうです。
いろいろな解決策がありましたが、これが一番シンプルで早いと感じたのでメモとして残しておきました。
aptってなんだ？

##aptとは？？
「apt」ってなんだよ、私の第一声だ。「apto」なら知っている、スペイン語のテストに通過したときに使われる目にしたら嬉しいヤツだ。
そこで困ったときのマニュアル頼み。

``` 
$ man apt 
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/267695/b63f289a-c736-21ae-2c49-ba41f817e0ce.png)

aptはパッケージマネージャ。macでいうHomebrewらしい。

##使ってみる
大まかな操作は[APT - Wikipedia](https://ja.wikipedia.org/wiki/APT)を見ながらできたが、```list```を使うとインストール可能なすべてのパッケージが出てきて動揺したのでメモ。

- インストール済みのパッケージを表示する

```
$ apt list --installed
```

-アップグレードできるパッケージを表示する

```
$ apt list --upgradable
```
多要素認証が有効なアカウントでConnect-MsolService ができない

PowerShellでOffice365に接続する方法は、以下の通りなのですが

Office 365 PowerShell への接続 | Microsoft Docs
https://docs.microsoft.com/ja-jp/office365/enterprise/powershell/connect-to-office-365-powershell

この通りにやってもConnect-MsolService 実行時に出てくる認証画面が以前のまま(IDとパスワードを入れさせるタイプ)で、多要素認証が有効なアカウントだとサインインできない、ということがありました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/146444/b6c46987-e6c1-8d5f-8f2b-a85514952e69.png)



必要な準備(前提条件)としてはこちらが詳しいですが、これらを満たしてもまだできないという始末。

Azure Active Directory の PowerShell モジュール – Japan Azure Identity Support Blog
https://blogs.technet.microsoft.com/jpazureid/2017/12/04/aad-powershell/

ちなみにこんなエラーが出ます。

-----------------------------
Connect-MsolService : 種類 'Microsoft.Online.Administration.Automation.MicrosoftOnlineException' の例外がスローされました。
発生場所 行:1 文字:1
+ Connect-MsolService
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [Connect-MsolService], MicrosoftOnlineException
+ FullyQualifiedErrorId : 0x800434D4,Microsoft.Online.Administration.Automation.ConnectMsolService

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

オチは、過去にインストールしていた Windows Azure Active Directory Module for Windows PowerShell (Windows PowerShell 用 Windows Azure Active Directory モジュール)が残っていて、Install-Module -Name MSOnline で最新のモジュールを読み込んでいても古い方が使われていた、ということのようで・・・
![image.png](https://qiita-image-store.s3.amazonaws.com/0/146444/b6cd62e5-cbce-a294-f488-a54df743fd7b.png)

こいつをアンインストールしたら、無事に認証画面がブラウザベース(ADAL仕様)の方に変わり、サインインできるようになりましたとさ。めでたしめでたし。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/146444/5f5daab2-85e3-a577-e36e-7ea7d480fdc0.png)
API23未満でButtonにsetDrawableTintを使う


# Code(Kotlin)

```app/build.gradle
android {
    ....
    dataBinding {
        enabled = true
    }
}
```

```BindingAdapter.kt
import android.databinding.BindingAdapter
import android.graphics.PorterDuff
import android.widget.Button

@BindingAdapter("app:drawableTintCompat")
fun Button.setDrawableTintCompat(color: Int) {
    val drawables = compoundDrawablesRelative
    for (drawable in drawables) {
        drawable?.setColorFilter(color, PorterDuff.Mode.SRC_ATOP)
    }
}
```

# Layout

```xml
    <Button
        ...
        app:drawableTintCompat="@{@color/colorPrimary}"
    />
```

# 参考
- [google: データバインディングライブラリ](https://developer.android.com/topic/libraries/data-binding/?hl=ja)
- [qiita: API23未満でTextViewのDrawableにTintをかける](https://qiita.com/konifar/items/f963414cca6937aabc09)
- [qiita: Kotlin + DataBindingでカスタムセッターを作る](https://qiita.com/umetsu/items/157a52eb4dc1c697685b)
- [sof: Android Button Drawable Tint](https://stackoverflow.com/a/44650149/4791194)
MSX マンデルブロー

```mandel.c
/*
z88dk / WebMSX
zcc +msx -lndos -lm -create-app -bnmandel mandel.c
*/

#define SIZE 100

int gttrig(char num)
{
#asm
	ld	a, l		; num
	call	$00d8		; GTTRIG
	ld	l, a
	ld	h, 0
#endasm
}

void nwrvrm(int addr, char data)
{
#asm
	ld	ix, 0
	add	ix, sp
	ld	a, (ix+2)	; data
	ld	l, (ix+4)	; addr
	ld	h, (ix+5)
	call	$0177		; NWRVRM
#endasm
}

void chgmdp(char mode)
{
#asm
	ld	a, l		; mode
	ld	ix, $01b5	; CHGMDP
	call	$015f		; EXTROM
#endasm
}

void main()
{
	chgmdp(8);

	float zoom = 4;
	float cu = 0;
	float cv = 0;

	for (int y = 0; y < SIZE; y++) {
		int addr = y * 256;
		float pv = cv - zoom * (y / (float)SIZE - 0.5);
		for (int x = 0; x < SIZE; x++) {
			float pu = cu + zoom * (x / (float)SIZE - 0.5);
			float u = 0;
			float v = 0;
			int c = 0;
			int i;
			for (i = 0; i < 10; i++) {
				float uu = u * u;
				float vv = v * v;
				if (uu + vv > 4) {
					c = (i & 7) << 5;
					break;
				}
				v = 2 * u * v + pv;
				u = uu - vv + pu;
			}
			nwrvrm(addr++, c);
		}
	}
	while (! gttrig(0)) ;
}
```

![WMSX Screen (1).png](https://qiita-image-store.s3.amazonaws.com/0/257554/32fba714-6d81-e04d-a614-c46aff5b2d11.png)
slimでjQueryを複数行書く

## 概要
erbをslim化するにあたって少々詰まったのでメモ

## コード
```Slim
| $("#hogehoge_#{@hoge.id}").html("
= escape_javascript(render partial: 'hogehoge/fuga_form', locals: { hoge: @hoge } )
| ");

| $("#hoge_with_fuga_#{@hoge.id}").remove();
```

## 解説
rubyコードを `=`で書いて純粋なjQueryはパイプを使用しました。
思ったよりハマったのは、erbのときはけつに `;` がなくても通ったが、
slimの場合は、2行に渡す場合は必ず最後に `;` をつけないとSyntax errorで怒られた。
Mac に Ubuntu 16.04 LTSをデュアルブート環境で構築する方法（作成中）


ゆるく浅く、PC環境設定手順をサクサクっとやります。
備忘録です。

参考動画
[YouTube "How to get Ubuntu 16.04 (Linux) on Mac OS X (Dual Boot)"](https://www.youtube.com/watch?v=IQIaDO9nR6Y)


必要なもの（ハード）
**・USBメモリ(4G程度)**
必要なもの（ソフト）
**・Ubuntu16.04 LST （isoイメージ）**[日本語版Link](https://www.ubuntulinux.jp/News/ubuntu1604-ja-remix)
**・Bootable Drive Maker**　[Link](https://gregoryconrad.github.io/)
**・rEFInd**　[Link](https://sourceforge.net/projects/refind/)
rEFIndはうまくダウンロードできない可能性あり。ブラウザ変えるなり何度かチャレンジしてみてください。

#Ubuntu 16.04 LTS のダウンロード

Ubuntu16.04 LTS* の日本語設定版の.isoイメージファイルをダウンロードします。
AI界隈では、16.04がデファクトスタンダードとなってるぽい。

好きなものをチョイスしてください。
機能が足りなければ、あとでなんぼでも追加できるよLinuxならね。

*LTS(Long Term Support: 長期サポート版)は2年間隔でリリースされ、サポート期間はリリースから5年。安定して使用したいユーザに最適。 

<details><summary>[Ubuntu16.04 日本語版](https://www.ubuntulinux.jp/News/ubuntu1604-ja-remix)</summary>
![JapaneseUbuntu.png](https://qiita-image-store.s3.amazonaws.com/0/272931/dd4797ce-5135-89d3-7c02-5d8f70fbe29d.png)
(2018.07.18時点)
</details>

#Bootable Drive Makerのダウンロード
<img width="151" alt="スクリーンショット 2018-07-18 22.41.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/272931/1bb24be4-4639-19ca-00c8-fe26fdb507d2.png">
Dualbootに必要なドライブ設定ソフトをインストールしてください。



<details><summary>[ダウンロードLink](https://gregoryconrad.github.io/)</summary>
<img width="500" alt="スクリーンショット 2018-07-18 22.37.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/272931/a2b17654-e227-93eb-1ca4-99eb05966851.png">
<img width="500" alt="スクリーンショット 2018-07-18 22.37.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/272931/4076f770-2d2c-c6a8-108a-1dffe97ddf5f.png">

##Bootable Drive Maker設定


#rEFIndのダウンロード
rEFIndはうまくダウンロードできない可能性あり。ブラウザ変えるなり何度かチャレンジしてみてください。
<details><summary>[Link](https://sourceforge.net/projects/refind/)</summary>
<img width="600" alt="スクリーンショット 2018-07-18 23.03.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/272931/91e1faee-b577-ac02-417e-eabe0a19cdd7.png">


#rEFInd 不具合
##~Ubuntuアップデートしたら、DualBootできなくなっちゃうヤツ。
DualBootの成功にほっと一息いれて、
るんるんでUbuntuの様々アップデート作業したら
DualBootできなくなってしまっていました。
**[R+Command]で再起動かけて、rEFIndの再インストールする必要があるみたい**
Ubuntuのアップデートの際には注意ですね。


# rEFIndの再インストール
MACのOSの更新とともにrEFIndが立ち上がらなくなってしまった。
そこで、再インストールを行う。

①　[R+Command]でリカバリーモードで再起動かける

②　起動後> ユーティリティー> ターミナル

③　<username>以下 rEFIndのダウンロード先を指定し、インストール実行

```ruby:terminal
$ /Volumes/Macintosh\ HD/Users/<username>/Downloads/refind-bin-0.11.3/refind-install
```

④　インストールしますか？（Y/N）に'Y'で答える。
⑤　“Installation has completed successfully.” で再インストールの成功。
機械学習知識ゼロの囲碁キチが3か月で囲碁AIを作った話　～概要編～

Qiitaはすごい人が多くて見る専でしたが、囲碁分野なら書けることがあるんじゃないかと思い、初めて投稿します。よろしくお願いします！

プロフィールはユーザーページに書いてあるので割愛。

※囲碁AIを作る方法については次回の導入編から解説するので「早く囲碁AIを作り始めたいんじゃ～！」という人は飛ばしてOKです。
## **前置き**
当記事は、「Python？TensorFlow？なんやねんそれ！でも囲碁AIは作ってみたい！」という機械学習について無知だった囲碁キチの僕が、自分の棋譜データ5360局分を学習させ、出来上がったAIをネット碁で動かすことに成功するまでの3か月間で得た知見をまとめたものです。

えっ？機械学習素人が3か月で囲碁AIなんて作れるわけがない？

...バレてしまっては仕方がないですね。**実はPythonもTensorFlowもほとんど分かりません**。

では何故、囲碁AIを作ることができたのか？答えは簡単です。
棋譜さえあれば自分だけの囲碁AIが作れそうなプロジェクトがTwitterのタイムラインに流れてきたからですよ。これはやるっきゃない！（囲碁キチ的発想）

前置きが長くなってしまいました（すみません）

それでは、囲碁が分からない人向けに囲碁とは何なのかを少し説明したいと思います。
## **囲碁って難しそう**
2016年3月、囲碁の世界タイトル獲得数18回、「韓国棋界の魔王」と評されている李世乭（イ・セドル）とデミス・ハサビス氏率いるDeepmind社のAlphaGoによる五番勝負が行われたことは覚えているでしょうか。

その対局は、全世界2億人が見守る中、AlphaGoが4-1で勝利して全世界を震撼させました。

> 
囲碁は創造的、戦略的思考を必要とする複雑なボードゲームであり、長い間、囲碁は、チェスのようなその他のゲームと比較して人間に勝つのがコンピュータにとってはるかに困難であると考えられていた。これは、他のボードゲームよりも可能な局面の数がはるかに大きい（約2×10172通り）ため、力まかせ探索といった伝統的なAI手法にとって極めて困難なためであった。**wikipediaより引用**

これだけを見ると「**囲碁って難しそうだなぁ～**」「**ハードルが高すぎてやろうとは思えない**」という声が聞こえてきそうですね。
でも実際、囲碁をやったことが無い人の大半が難しそうと感じているようです（経験談）

その原因として挙げられるのが「**素人が見ても何をしてるのか分からないしどっちが勝ってるのかも分からない**」という点。
でも囲碁AIなら、与えた棋譜の着手情報を元に学習して、ルールを教えなくても強くなります！

**自分で囲碁を打つのはもちろん楽しいですが、囲碁AIという自分の化身を作って戦わせるのも1つの楽しみ方ではないでしょうか。**
## **次回**
[機械学習知識ゼロの囲碁キチが3か月で囲碁AIを作った話　～導入編～](https://qiita.com/intenseG/items/34b452cbab04817cdaef)
階層が異なるファイルをフラットにして連番を振り直す

# 概要

以下のような感じのディレクトリ構成で配置されたファイルを

~~~
.
|-- 1
|   |-- 001.txt
|   |-- 002.txt
|   `-- 003.txt
`-- 2
    |-- 001.txt
    |-- 002.txt
    `-- 003.txt
~~~

こうしたい。

~~~
.
|-- 001.txt (元1/001.txt)
|-- 002.txt (元1/002.txt)
|-- 003.txt (元1/003.txt)
|-- 004.txt (元2/001.txt)
|-- 005.txt (元2/002.txt)
`-- 006.txt (元2/003.txt)
~~~

# Bashワンライナー

~~~bash
a=0; find ./ -type f | sort | while read i; do a=`expr $a + 1`; mv "$i" `printf "%03d" $a`.${i##*.}; done
~~~

特定のファイルだけリネームするには、`find`の引数に条件を加える。
例: `find ./ -type f -iname "*.txt"`

連番の0パディングの桁数は`printf`の引数を変更する。
例: 4桁にする場合 `printf "%04d" $a`

空になったディレクトリを削除する場合は追加で下記のワンライナーを実行。

~~~bash
find ./ -type d -empty | xargs rmdir
~~~
WildFlyのホットデプロイ機能を使う

# はじめに
WildFlyのホットデプロイ機能が便利すぎて涙が出てきたため、自分への備忘録として残します。

# ホットデプロイって
ホットデプロイとは、WebアプリケーションやWebサービス（に加えた変更）を運用環境に適用する際、システムの一時停止と再起動を伴わずに適用することである。[ここから抜粋](https://www.weblio.jp/content/%E3%83%9B%E3%83%83%E3%83%88%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4)

すごくザックリいうと・・・
ソースコードの修正→サーバーの再起動→反映の確認
という面倒な手順をせずに済むようになる。

# 今回試した環境
WildFly10
Eclipse Oxygen （画面ショットで使われているEclipseのバージョンです。設定自体には関係ないです）

# 設定方法

### 現在の状態を確認する
EclipseからWildFlyを起動後、サーバーのウィンドウ（ビュー）から
WildFly10.x＞サーバー詳細＞Subsystems＞deployment-scanner＞scanner＞default　と開いていき
default内の**auto-deploy-exploded**属性を確認する。
trueの時はホットデプロイ機能が有効、falseの時は無効になっている。
画像は有効に設定済みのためtrueになっている。![ホットデプロイ1.png](https://qiita-image-store.s3.amazonaws.com/0/205038/844a36de-307e-eabb-f3bb-e1566c0a7f55.png)

### 「auto-deploy-exploded」をtrueにする
現在のauto-deploy-explodedの状態を確認した後、サーバーを停止させる。
設定の変更をするためにはstandalone.xmlを編集する必要がある。

wildfly-10.0.0.Final\standalone\configuration\standalone.xml を開く。
「deployment-scanner」タグを探す。

以下「deployment-scanner」タグ部分を抜粋

```xml:standalone.xml
 <deployment-scanner path="deployments" relative-to="jboss.server.base.dir" scan-interval="5000" auto-deploy-exploded="true" runtime-failure-causes-rollback="${jboss.deployment.scanner.rollback.on.failure:false}"/>
```

「auto-deploy-exploded」について何も書かれていない状態だとfalseになるため、上記のように「auto-deploy-exploded="true"」を追記し保存する。

### 設定の反映を確認する
standalone.xmlの編集が終わったあと、再度Eclipseからサーバーを起動させ「auto-deploy-exploded」属性がtrueになっていることを確認出来たら、設定は完了！
あとはその便利さを体感してください。
easingを計算でやってみる

CSSアニメーションでも各種JSのライブラリでも、easingはとても簡単にできるようになりましたが、
それらを使わずにJavaScriptで値を計算してやるのも面白いです。
昔ActionAcriptでやっていたことの復習です。

練習がてらやってみます。
今回はまず基本的な徐々に減速するやつ

```javascript:javascript
const fps = 1000/30 //calを実行するインターバル1秒間に30回
const dx = 200 //目標値
const speed = 0.3
let _tmp = 0 //現在値
function cal()
{
  _tmp += (dx - _tmp) * speed
  console.log(_tmp)
}
const int = setInterval(cal, fps)

```
目的地（値）と現在値との距離を少しずつ加算していく感じ。
距離がつまってくると加算される値も小さくなるので減速する
というイメージです。

大筋はこんなところいいですが、
目標値に至ったところでsetIntervalをクリアしないといけません。
が、tmpをトレースしても
加算される値が小さくなるので現在値tmpが99.999999...のまま100にはなりません。

なので加算される値がある程度小さくなったら処理を停止し、現在値に目標値を代入します。

```javascript
let _sa = 200
function cal()
{
  if(_sa >= 0.03 )
    _sa = (dx - _tmp) * speed
    _tmp += _sa
    console.log(_tmp)
  }
}
else
{
  clearInterval(int)
}
```
こんな感じです。
https://jsfiddle.net/urtyo64x/4/


もうひとつMath.sinを使った減速と加速の繰り返し。
sinについてはこのgifを見るとすごく理解しやすかったです。
https://twitter.com/InfinityLoopGIF/status/997448838737776641



```javascript:javascript

function cal()
{	
  
  if(ang < 360 )
  {
  
    ang += 3 //角度を3度づつ増やしていく
    _tmp = Math.sin(ang * (Math.PI / 180)) 

    obj.style.left = (100 * _tmp) +'px'

  }
  else
  {
    //角度をリセット
    ang = 0
  }
}
const int = setInterval(cal, fps)
```
うまく振り子のようになっています。
https://jsfiddle.net/pryvn4tx/6/


今日はここまで。
[Python] tkinterでメニューバー作り。

pyQt5 をつかってますが、
最近 Tkinterに戻し、学びながらつかってます。

# Import

```python:menu.py
import tkinter as tk
from tkinter import ttk
from tkinter import Menu
```

#Window 

```python:mune.py
win = tk.Tk()   
# Add a title       
win.title("Python GUI Tanosii")  

# Modify adding a Label
a_label = ttk.Label(win, text="Hello Qiita")
a_label.grid(column=0, row=0)

```

#Menu作り。
```python:menu.py

menu_bar = Menu(win)
win.config(menu = menu_bar)

file_menu = Menu(menu_bar, tearoff=0)
file_menu.add_command(label='New')
file_menu.add_separator()
file_menu.add_command(label='Exit')
menu_bar.add_cascade(label='Files', menu=file_menu)

```

#みせて

```python:menu.py
win.mainloop()
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/137182/c6ad2963-3256-12bd-1e06-95aff95899c8.png)
MySQL についてまとめた 

# MySQL とは
世界でもっとも利用されている **データベース管理システム**(DBMS : DataBase Manegement System)

 - オープンソースソフトウェア(OSS : Open Source Software) のため基本的に無料
 - 拡張性と柔軟性が高い
  - 小さなアプリケーションから巨大なアプリケーションまですべてに対応可能
  - Mac, Windows, Linuxなど複数のOSで利用可能
 - **ストレージエンジン** をテーブルごとに選択できる

# MySQL 実行の流れ
クライアントからSQL文が投げられた場合、MySQLではおおまかに以下のような流れで処理されます。

<img width="810" alt="SQL実行の流れ2.png" src="https://qiita-image-store.s3.amazonaws.com/0/175122/0ff92c37-2260-b902-9ddc-8bc70c90a984.png">

## オプティマイザ とは

- SQL文を最適化してくれる、MySQLの 脳 のようなもの
- 各テーブルのレコード数、列数と列のサイズやインデックス情報などの **統計情報** を元にどのようにテーブルにアクセスするか（フルスキャンするのか、インデックスをつかうのか、など）がかかれた **実行計画** を作成する

※ 実際のDBの情報 = 統計情報 ではないため、DBの情報が更新されたら統計情報も更新が必要
  （更新しないと古い情報をもとに実行計画がつくられてしまい、SQLのパフォーマンスが落ちる）

## ストレージエンジン とは
- 実際にデータベースにデータの読み書きを行っている
- 様々な種類があり、テーブルごとに選択できる
- デフォルトでは MySQL5.6までは **MyISAM**, MySQL5.7以降は **InnoDB** が選択されている（デフォルトストレージエンジン を設定することもできる）
- テーブルを作成するときに選択する

```SQL
CREATE TABLE sample_table(id int) ENGINE = InnoDB;
```
### MyIsam と InnoDB

#### MyIsam 特徴
- メリット
 - 参照系処理が高速
- デメリット  
 - トランザクションが使えないので、リカバリが面倒 
 - テーブルロックをかけるので、複数のクライアントからの同時更新でロックが発生する 

#### InnoDB 特徴
- メリット
 - トランザクションが使えるので、リカバリが楽。  
 - 行ロックを行うので更新/参照の競合が限定的になる。  
- デメリット
 - 参照処理がMyISAMに比べて遅い。 
 - データサイズがMyISAMに比べて大きくなるのでその分ディスク容量が必要。  


### MyISAM や InnoDB のほかにも以下のような種類がある

|ストレージエンジン    |特徴　　　　　　　　　　　　　
|:-----------------|:-------------------------------------------------------------------------------------------|
|MyISAM　　　　　　　|データファイルとインデックスファイルの2ファイルで保存される。トランザクション、行レベルのロックをサポートしていない。|
|InnoDB　　　　　　　|トランザクション、行レベルに対応したエンジン。MyISAMよりは速度が劣る。|
|Memory　　　　　　　|メモリにデータを格納するエンジン。再起動などで、データが失われる。|
|Merge　　　　　　　 |複数のMyISAMを統合したエンジン。|
|Federated　　　　　|ローカルにデータを保存せず、リモートを参照するエンジン。|

# おまけ
MySQLの処理を料理にたとえてみました！

<img width="529" alt="MySQLの流れ（料理）.png" src="https://qiita-image-store.s3.amazonaws.com/0/175122/2dda25a3-83d7-457b-f634-607f2cf23627.png">

# 参考
・[実行計画？？統計情報？？って人へ](https://qiita.com/NagaokaKenichi/items/5b6eb9887f88046a594d)
・[MySQLの「InnoDB」と「MyISAM」についての易しめな違い](http://shindolog.hatenablog.com/entry/2015/04/01/185703)

# わたくしごと
DBA目指して勉強中...

1. **MySQL について**　 ◀ これ
2. [MySQL のインストール](https://qiita.com/at_1016/items/66e5ec0c2bf7e9a19ea0)
3. [my.cnf について](https://qiita.com/at_1016/items/874788e375938837a027)
Go言語でファイルの変更日時を取得する。

# はじめに
ファイルの一覧を標準出力するときに、ファイルの変更日時を見てfilterしたいときがあって調べました。

# ファイルに関する日時

`stat`コマンドでファイルを確認すると、以下の3つの日時を保持しています。Birthという項目もあるのですが`-`になっています。カーネルが`xstat()`を提供しているかに依存するそうです。なので、私の環境では見れないみたいです。

- Access: 2018-07-16 14:39:26.824920847 +0900
- Modify: 2018-07-17 09:47:15.038632561 +0900
- Change: 2018-07-18 21:07:34.324530860 +0900

---
### Access
Accessは最後に利用した日時です。
以下で更新されます。

- エディタで開く

---
### Modify
Modifyは最後に修正した日時です。
以下で更新されます。

- エディタで書き込み
- リダイレクトによる書き込み

---
### Change
Changeは最後に変更した日時です。
以下で更新されます。

- エディタで書き込み
- リダイレクトによる書き込み
- ファイル名の変更(ファイルの移動)

## Goでファイルの日時を取得する
ファイルの情報は`type FileInfo interface`で、下記の値を取得できます。

|メソッド名|概要|
|----------|----|
|Name()|ファイル名|
|Size()|ファイルサイズ|
|Mode()|読み込み、書き込み、実行|
|ModTime()|修正日時|
|IsDir()|ディレクトリかどうか|
|Sys()|基礎情報|

見て分かるとおり、Modifyしか取得できません。
AccessとChangeを取得するには、Sys()から取らなければなりません。
まず、Sys()がinterfaceなので`syscall.Stat_t`にキャストします。
そして、LinuxならAtime,CtimeというTimespec構造体から値を取り出します。
MacOSならAtimespec,Ctimespecらしいです。手元にMacOSがないため検証はしていません。
Nano()でナノ秒で値が返ってきます。

```go
if internalStat, ok := fileInfo.Sys().(*syscall.Stat_t); ok {
  fmt.Printf("Access: %v\n", internalStat.Atim.Nano())
  fmt.Printf("Change: %v\n", internalStat.Ctim.Nano())
}
```
Go API Server 環境構築


# 概要

開発の際に Go 言語の API Server をローカル開発環境で立ち上げる事があったので、備忘録です。

## そもそも Go 言語とは

Google が開発しているマルチプラットフォームなプログラミング言語です。
大抵のことはできるそうです。(docker も Go 言語で作られている)
詳しくは[公式サイト](https://golang.org/)を確認してください。

## API Server とは

API = Apprication Programming Interface の略。
どのアプリーケーションでも共通で使える機能を提供する仕組みのことです。
API Server = http 等の Web 技術を用いて構築されたもので、API より意味合いは限定的になります。
また、データ通信は JSON で行うので、プログラミング言語に縛られません。

# 環境構築

## 前提

- 開発環境は mac
- Homebrew が入っていること
- GitHub にリポジトリがあること

# Homebrew が入っていない場合

下記をターミナルで実行して下さい。
詳しくは[こちら](https://brew.sh/index_ja)で確認して下さい。

```sh:terminal
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```

# Go 言語のインストール

Go 言語をインストールしていきます。
下記をターミナルで実行して下さい。

```sh:terminal
brew install golang
# Goのバージョン確認
go version
```

# 以下を~/.bashrc に書き込む

お好みのエディターを使って `~/.bashrc`を開き、下記の内容を追記して下さい。

```sh:.bashrc
export GOPATH=$HOME/go
export GOBIN=$GOPATH/bin
export PATH=$GOBIN:/usr/local/go/bin:${PATH}
```

上記では Go 言語の PATH を設定しています。

- デフォルトの\$GOPATH は \$HOME/go になっていますが、明示しています。
- \$GOPATH/bin を \$GOBIN として設定しておきます。
- go get したツールは\$GOBIN に入るため、PATH を通しています。

また、デフォルトでは`~/.bashrc`は常時読み込みではないので、同様に`~./bash_profile`に下記を追記して下さい。

```sh:terminal
if [ -f ~/.bashrc ] ; then
. ~/.bashrc
fi
```

ここまでの内容を追記し終えたら、一度ターミナルを再起動しましょう。

# 補助ツールのインストール

Go API Server を立てる際に便利な補助ツールです。

## dep の導入

依存パッケージ管理ツールです。
下記でインストールして下さい。

```sh:terminal
brew install dep
```

`dep version` でバージョンを確認して、 v0.4.1 以上を使うようにしてください。

## ghq の導入

GitHub のリポジトリを手軽にクローンできます。

```sh:terminal
brew install ghq
# ghqのディレクトリ設定
git config --global ghq.root $GOPATH/src
```

実際に使用する場合は下記のようにして、GitHub リポジトリをクローンして下さい。

```
# リポジトリをクローン
ghq get <リポジトリのURL>
```

## nodemon

ファイルの変更があれば、自動で再起動をかけてくれる便利なツールです。
このツールは Node.js という JavaScript の環境からインストールして下さい。

```sh:terminal
npm i -g nodemon
```

もし Node.js が入っていなければ、これまでと同じように brew でインストールして下さい。

```sh:terminal
brew install node
```

## make

mac であればデフォルトで入っているはずです。
念のために`which make`で確認して下さい。
もし上手くいかなければ、[こちら](http://yucatio.hatenablog.com/entry/2016/05/16/230513)が参考になります。

# まとめ

以上で、Go API Server の環境構築が完了しました。
この記事では API Server を立ち上げることはしませんが、
実際に API Server を立ち上げるところまで書いていきたいと思います。
Back Propagationを数式ベースで考えてみる

# どういう風に使うのか

1. とりあえず、一回forward propagationでoutputを出してから、cost調べてみる。それからback propagationを使って、$\delta$を求める。
2. その$\delta$を用いて、$w$を更新する。($\triangle w_{ij} = -\eta\delta_jo_i$)

# Back Propagationの骨格

```math
\frac{\partial E}{\partial w_{ij}} = \frac{\partial E}{\partial o_j} 
\frac{\partial o_j}{\partial net_j}
\frac{\partial net_j}{\partial w_{ij}}
= \delta_jo_i
```
言ってしまえば、どれだけcost function$E$とweight$w$の相関があるかがを求めて、相関が大きければ大きいほど$w$を小さくするようにしている。
Swift：CGPathをNSBezierPathに変換する

#背景
NSBezierPathをCGPathに一旦変更して利用した後、再びNSBezierPathに戻したい場合があったため、方法を探りました。

##ソースコード（2018/7/11 Swift4対応版）
```swift:
import Cocoa

extension CGPath {
    
    public var nsBezierPath: NSBezierPath {
        let path = NSBezierPath()
        self.applyWithBlock { (element) in
            switch element.pointee.type {
            case CGPathElementType.moveToPoint:
                path.move(to: NSPoint(x: element.pointee.points[0].x, y: element.pointee.points[0].y))
            case CGPathElementType.addLineToPoint:
                path.line(to: NSPoint(x: element.pointee.points[0].x, y: element.pointee.points[0].y))
            case CGPathElementType.addCurveToPoint:
                path.curve(to: NSPoint(x: element.pointee.points[2].x, y: element.pointee.points[2].y),
                           controlPoint1: NSPoint(x: element.pointee.points[0].x, y: element.pointee.points[0].y),
                           controlPoint2: NSPoint(x: element.pointee.points[1].x, y: element.pointee.points[1].y))
            case CGPathElementType.addQuadCurveToPoint:
                path.curve(to: NSPoint(x: element.pointee.points[1].x, y: element.pointee.points[1].y),
                           controlPoint1: NSPoint(x: element.pointee.points[0].x, y: element.pointee.points[0].y),
                           controlPoint2: NSPoint(x: element.pointee.points[0].x, y: element.pointee.points[0].y))
            case CGPathElementType.closeSubpath:
                path.close()
            }
        }
        return path
    }
    
}
```

#使い方
上のソースコードを`PathExtension.swift`など適当な名前をつけてプロジェクトファイルに突っ込めば準備OK！
あとは`　CGPath`のパス生成後に`path.nsBezierPath`とすればNSBezierPathが取得できる。
Macの$PATHの設定箇所は「/etc/paths」にある

:star: タイトルの通りですが、調べたことを以下に綴ります :star:

## 環境
macOS High Sierra (v10.13)
macOS Mojave (v10.14.1)

## 発端
`~/.bash_profile`が存在しなくても、$PATHが設定されていた。

```
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
```

## 調査
```
L1  $ cat /etc/profile
L2  if [ -x /usr/libexec/path_helper ]; then
L3  	eval `/usr/libexec/path_helper -s`
L4  fi
L5  
L6  if [ "${BASH-no}" != "no" ]; then
L7  	[ -r /etc/bashrc ] && . /etc/bashrc
L8  fi
```

L3の`/usr/libexec/path_helper -s`を見てみる

```
$ man path_helper
The path_helper utility reads the contents of the files in the directories /etc/paths.d and /etc/manpaths.d and appends their contents to
```
##### >> Google翻訳
path_helperユーティリティは、ディレクトリ/etc/paths.dおよび/etc/manpaths.dにあるファイルの内容を読み込み、その内容を次の場所に追加します。

## 結果
`/etc/paths.d`配下には何もないが、`/etc/paths`に$PATHの設定があった！

```
$ cat /etc/paths
/usr/local/bin
/usr/bin
/bin
/usr/sbin
/sbin
```

## 参考になりました。
[PATH設定がどこにあるか分からないときに見るべきファイル](https://qiita.com/gm_kou/items/24dec9f0e51b9343651b)
PC-98x1でテキスト画面をスクロールする

PC-98x1で，テキスト画面をスクロールするアセンブリ言語ソース
PC-9821Cxで作成・確認しました。

```
code	segment
	assume ds:code, cs:code

	org 100h

start:
	mov	dx,00h
	jmp	looop

MES	db	'done.$'

looop:
	mov	ah,0eh
	int	18h
	cmp	dx,(2 * 80 * 25)
	jz	fin
	add	dx,160
	jmp	looop
fin:
	mov	ah,0eh
	mov	dx,00h
	int	18h
	mov	ah,09h
	mov	dx,offset MES
	int	21h
	mov	ax,4c00h
	int	21h
	ends
end	start
```
PC-98x1のXMS情報をアセンブラで取得する

# PC-98x1でのXMS情報をアセンブラで取得する

## xms.asm はじめのバージョン
``` 
code	segment
        assume cs:code, ds:code
        org 100h
	
cr	equ	0dh
lf	equ	0ah

start:	jmp is_xms

m_nai	db	'XMSドライバは存在しません。',cr,lf,'$'
m_aru	db	'XMSドライバが存在します。',cr,lf,'$'
m_a20ok	db	'A20は有効になっています。',cr,lf,'$'
m_a20ng	db	'A20は無効です。',cr,lf,'$'
m_a20	db	'A20を有効化します。',cr,lf,'$'
m_a20n	db	'A20を有効化できませんでした。',cr,lf,'$'
m_hmaok	db	'HMAが存在します。',cr,lf,'$'
m_hmang	db	'HMAは存在しません。',cr,lf,'$'

is_xms:
	mov	ax, 4300h	; mov ah=43h,mov al=00hでも同じ
	int	2fh
	
    cmp	al,80h
	jz	xms_aru
	mov	dx,offset m_nai
	jmp	disp

xms_aru:
	mov	dx,offset m_aru

disp:	mov	ah,09h
	int	21h
	
is_hma:
	mov	ah,00h
	int	2fh
	
    cmp	dx,01h
	jz	hma_aru
	mov	dx,offset m_hmang
	jmp	hma

hma_aru:
	mov	dx,offset m_hmaok

hma:
	mov	ah,09h
	int	21h

is_a20:
	mov	ah, 07h
	int	2fh

    cmp	ax, 01h
	jz	a20_aru
                             ;Ａ２０無効の場合
	mov	dx, offset m_a20ng   ;無効の表示
	mov	ah,09h
	int	21h

    mov	dx, offset m_a20
	mov	ah,09h
	int	21h

    mov	ah,05h               ;A20を有効化
	int	2fh

    cmp	ax,01h               ;有効化できたら
	jz	a20_aru              ;a20_aruにジャンプ
	mov	dx, offset m_a20n
	jmp	disp_a20

a20_aru:
	mov	dx, offset m_a20ok
	jmp	disp_a20

disp_a20:
	mov	ah, 09h
	int	21h

mov	ah,4ch
int	21h

code	ends
end start
```
PC-9821Cx（i486)で作りました。

## xms.asm 次のバージョン
で，作り直し。
（どこが変わったか分かりづらくてすいません。

```
code	segment
	assume cs:code, ds:code
	org 100h
	
cr	equ	0dh
lf	equ	0ah

start:	jmp is_xms

m_nai	db	'XMSドライバは存在しません。',cr,lf,'$'
m_aru	db	'XMSドライバが存在します。',cr,lf,'$'
m_a20ok	db	'A20は有効です。',cr,lf,'$'
m_a20ng	db	'A20は無効です。',cr,lf,'$'
m_a20	db	'A20を有効化します。',cr,lf,'$'
m_a20activeok	db	'A20を有効化しました。',cr,lf,'$'
m_a20activeng	db	'A20を有効化できませんでした。',cr,lf,'$'
m_hmaok	db	'HMAに16byte要求し成功しました。',cr,lf,'$'
m_hmang	db	'HMAに16byte要求し失敗しました。',cr,lf,'$'

is_xms:
	mov	ax, 4300h	; mov ah=43h,mov al=00hでも同じ
	int	2fh
	
	cmp	al,80h
	jz	xms_aru
	mov	dx,offset m_nai
	jmp	disp

xms_aru:
	mov	dx,offset m_aru
	jmp	disp

disp:	mov	ah,09h
	int	21h
	jmp	is_hma
	
is_hma:
	mov	ah,01h
	mov	dx, 010h      ; HMAに16byte要求
	int	2fh
	
	cmp	ax,01h        ;割り当て成功したら
	jz	hma_aru
	mov	dx,offset m_hmang
	jmp	disp_hma
hma_aru:
	mov	dx,offset m_hmaok
disp_hma:
	mov	ah,09h
	int	21h

is_a20:
	mov	ah, 07h
	int	2fh
	
	test	ax, 01h
	jz	a20_aru
	                             ;Ａ２０無効の場合
	mov	dx, offset m_a20ng   ;無効の表示
	mov	ah,09h
	int	21h
	
	mov	dx, offset m_a20
	mov	ah,09h
	int	21h
	
	mov	ah,05h               ;A20を有効化
	int	2fh
	
	test	ax,01h               ;有効化できたら
	jz	a20_activeok         ;a20_activeokにジャンプ
	mov	dx, offset m_a20activeng
	jmp	disp_a20

a20_activeok:
	mov	dx, offset m_a20ok
	jmp	disp_a20
	
a20_aru:
	mov	dx, offset m_a20ok
	jmp	disp_a20
	
disp_a20:
	mov	ah, 09h
	int	21h

	mov	ax,4c00h
	int	21h

		
code	ends
	end start
```

## 結果
次のようになりました。

```
XMSドライバが存在します。
HMAに16byte要求し失敗しました。
A20は有効です。
```
ちなみに，vmapの結果は次の通りです。
（HMAのところだけ）

    VMAP Version 2.01  Copyright (C) 1989-91 by c.mos
    ----- XMS ver2.00 -----
    HMA used: 57 KB by DOS
Railsでファイルが選択されたらボタンを有効化する

## 経緯
独学サイトでファイルをアップロードする際にfile_fieldにファイルを選択していない状態でアップロードボタンを押すとエラーになりました。
そもそも、ファイルが選択されてない状態であればボタンを押せなくればいいのでは、と思考。

## 環境
Ruby 2.3.0
Rails 5.0.4

## 施策
##### 1). views/hogehoge/_formにJavaScriptを効かせる施策をする。

```erb:views/hogehoge/_form.html.erb
<%= form_for(hogehoge) do |f| %>
  <div>
    <%= f.label :file %>
    <%= f.file_field :file, id: 'elmFile', onchange: 'selectFile()' %>
  </div>

  <div>
    <%= f.submit 'アップロード', id: 'btnUPload', disabled: true %>
  </div>
<% end %>
```

##### 2). assets/javascripts/hogehoge.jsでファイルが選択されたらボタンを有効になるように記述

```javascript:assets/javascripts/hogehoge.js
function selectFile() {
    if (document.getElementById("elmFile").value === ""){
        document.getElementById("btnUpload").disabled = true;
    }
    else {
        document.getElementById("btnUpload").disabled = false;
    }
}
```

### 参考サイト
[input type="file"でファイルが選択されたらアップロードボタンを有効化する](input type="file"でファイルが選択されたらアップロードボタンを有効化する)
悲報 minikubeのメモリ割り当てのdefault値は2GB

以下のようにdefaultでは2GBしか割り当てられていません。
どれだけメモリを積んだマシンでもdefaultでは2GBしか使われません。

```bash
$ minikube start -h
( : 略 )
      --memory int                      Amount of RAM allocated to the minikube VM in MB (default 2048)
( : 略 )
```

メモリ不足が原因でエラーメッセージなど出力せずにコンテナが落ちることがあります。
コンテナが落ちる原因が不明の場合はメモリ不足も被疑対象に入ります。

以下のようにして変更できます。
変更後はいったん`minikube delete`が必要なようですので、余裕をもって設定しておいたほうが良さそうです。

```bash
$ # 20GBを設定する
$ minikube config set memory 20480
These changes will take effect upon a minikube delete and then a minikube start
$ # 設定の確認
$ minikube config view
- memory: 20480
$ # 泣く泣くクラスタを削除してから
$ minikube delete
Deleting local Kubernetes cluster...
Machine deleted.
$ # 新たな気持ちでクラスタを開始する、もろもろ再構築しましょう。
$ minikube start
```

[SpinnnakerやKayentaをminikube上にデプロイした](https://qiita.com/loftkun/items/2fd1d598d04084495e2c)際はこの方法で20GBを割り当てることでデプロイできるようになりました。

なお、[minikubeのCPUコア割り当てのdefault値は2コア](https://qiita.com/loftkun/items/41ecde082778254de79a)という悲報もありますのでご注意下さい。
第22話 ラマヌジャンの式

この記事は[仮面ライダービルドの数式](https://qiita.com/izmktr/items/e26a624e79bce3edccc9)の第22話です。

```math
\frac{2143}{π^4} \simeq 22
```

ラマヌジャンが発見した式で、以下の式が残されています。

```math
\sqrt[4]{\frac{2143}{22}}\simeq π
```

なぜこんな式を考えたかというと、以下の式を考えることで、
円周率に非常に近い値を作図で表現しようとしたから、のようです。

```math
\frac{2143}{22}=9^2+\frac{19^2}{22}
```
作図の方法は複雑なので割愛します。
なお、コンパスと定規で表現できるのは平方根が限度なので、
四乗根が表せませんから、比例中項の2つの値を示しています。

比例中項とは、以下の式が成り立つ時、xはaとbの比例中項である、と表します。

```math
a:x=x:b
```

なお、$\pi^4$はこんな値です。

```math
\pi^4=97.409091034\cdots
```
よくみると、090910という部分が見えますね。
ここを090909という循環小数とみなすとこうなります。

```math
\pi^4\simeq97.409090909\cdots=97.4\dot0\dot9=97.4+\frac{9}{99}\times0.1=\frac{2143}{22}
```
[Rails]Reference型の持つカラムをKeyにしてあいまい検索をしたかった

# 背景
Reference型の持つカラムをKeyにして、LIKEによるあいまい検索をしようとしたところ、全然一筋縄でいかなかった。

## Model
UserモデルとItemモデルを以下のように設計した

```
User
├─ t.integer   :user_id
└─ t.string    :user_name

Item
├─ t.integer   :item_id
└─ t.reference :user
```

## 欲しかったもの
例えば、検索バーに「田中」と入力した時に
「田中」を含むuser_nameのuserを:userとして持っているItemの一覧を、Item.allから抽出したかった

が、これが簡単ではなく

```rb
@item = Item.where("user.user_name LIKE ?", "%#{query}%")
```
とかで上手くいかないかな〜と試してみても全然ダメだった。Rails初心者の実力では、似たような探し方を複数試しても全く上手くいかず…
「rails reference where」などで検索をかけても全然解決法が見つからないので、自力で解決することにした。

# 解決まで
投げられたクエリでUserからあいまい検索する方法はコレ

```rb
User.where("user_name LIKE ?", "%#{query}%")
```

また、もし検索結果の中に含まれるuser_idのリストが手に入れば、そのuser_idの:userを持っているItemオブジェクトはコレで抽出できる

```rb
Item.where(:user_id => [user_idのリスト])
```

そして、あいまい検索した結果のidをリスト型で整形する事はplunkメソッドで可能

```rb
User.where("user_name LIKE ?", "%#{query}%").plunk(:id)
```

# 正解
以上の結果から、queryの文字列を含む名前のuserを、Reference型の:userとして持っている、Itemの一覧を抽出する方法は以下の通りになる。

```rb
Item.where(:user_id => User.where("user_name LIKE ?", "%#{query}%").pluck(:id))
```

解決して良かった〜〜〜
コルーチンがなぜか止まらなかった

## 起こったこと

コルーチンの中でwhile使って、WaitForSecondsで数秒ごとにループさせていたのですが、任意のタイミングでそのコルーチンから抜け出したくなって、**StopCoroutine**を使って別のコルーチンを呼び出したら、中断したはずのコルーチンの中の処理が数回勝手に呼び出されるという問題が発生しました。。。

### 目次

1. 原因
2. 対策

## 1. 原因(僕の場合)

### 1-1.連続で処理命令してしまって処理が溜まってしまった可能性
コルーチンの中にwhile文を入れてWaitForSeconds使ってループさせていた。
とあるモデルのアニメーションが終わるまで、6秒ほどかかる。(Unity側でアニメーションの速度を遅くしたから)しかし、WaitForSecondsで止めていた秒数は3秒。
となると、アニメーションは6秒ごとに再生されているが、アニメーション再生命令は3秒ごとにしてしまっていたので、処理が溜まってしまって、後から処理されてしまったのではないだろうか。。。



### 1-2. そもそもStopCoroutineって本当に止まっているのか
アニメーションの命令が溜まってしまってもStopCoroutineしたら強制的に中断されるのかと思ったらそうではなかった。
だとしたら、Unity側のバグなのかなぁ、、、

## 修正したこと
やはり原因1-1の部分が怪しいって思って、while文を使うのをやめて、アニメーションイベントを使ってアニメーションの最後のタイミングでまたStartCoroutine使うことでループさせるようにしたら、勝手に再生されることはなくなった。

また、StopCoroutineしても止まらなかった場合、StopCoroutineした後に、何の機能も持たせない仮のコルーチンを呼び出したら無事に前のコルーチンが終了できた。

```c#:I_am_hentai.cs
	IEnumerator HogeHoge(){
		var wait = new WaitForSeconds (5);

		yield return wait;
	}
```


## 感想
while文使ってWaitForSecondsを長くしたら処理がたまるはずがないが、長くしても勝手に処理されてしまう。。。
whileをやめたループの仕方をすれば完全にバグがなくなったので、コルーチンのなかにwhileを使うこと自体がバグの原因になってしまうのだろうか。。。ここだけは謎です。
処理が溜まって後からそれがどんどん実行されるっていうのが初めてで気づくまでに時間がかかってしまいましたが、それに気づけてよかった。。。笑
カーネル法を詳しくみてみる

# カーネル法の定義
データを高次元の特徴空間に写像する。

# 線型から非線形へ

linear regressionと同じように、線形から非線形へ拡張できる。

```math
\\ f(x) = \sum_{k = 1} ^ d w_i \phi_i(x)

```

パーセプトロン法(ざっくり言えばカーネル法の線型バージョン）とは、

```math

w ^ \ast = armgin \sum_{k = 1} ^ n l_P(w;y_i,x_i)

\\ where  \ l_p(w;y_i,x_i) = max(0, -y_iw^tx_i)
```
これを、確率的降下勾配法を使って解を求める。

さらにreformulationして見てると、

```math

R( \alpha)= min_{\alpha_{1:n}} \sum_{i = 1}^nmax \{ 0, - \sum_{j = 1}^n\alpha_jy_iy_jx_i^Tx_j \}
```

ここから線型から非線形に拡張していく。

```math
x \mapsto \phi(x)
\\ x^Tx \mapsto \phi(x)^T\phi(x) =:k(x,x')
```

この$ x^Tx$の計算コストが高いので、ここでカーネルが出てくる。

# カーネルの種類

## Linear kernel
```math
k(x, x^T)= x^Tx
```

## Polynominal kernel
```math
k(x, x^T) = (x^Tx + 1)^T
```

##RBF
```math
k(x, x^T) = exp(-||x - x||_2^2 / \ h^2)
```
[OF] QR コードリーダー

#はじめに
openframeworksでQRコードを読み込もうとすると、既存のaddonですとofxZxingが一番有名です。
ですがそのofxZxingも最後にプッシュされたのが5年前となり動かない環境の方が多いようです（実際僕も動きませんでした）
そこで、今のところ自分の環境のみですが最新のZxingを使って現在のバージョンに合わせたQR読み込みaddonを作ってみました。

動作確認した環境は以下の通りです。
windows10
Visual Studio 2017
openframeworks 0.9.8

時間を見つけて他の環境での動作チェックをしようと思います。


#作ってみました
こちらのaddonはC++のQRコードリーダーライブラリである**[zxing-cpp](https://github.com/glassechidna/zxing-cpp "zxing-cpp")**のwrapperです。

###**[ofxZxing](https://github.com/Iwanaka/ofxZxing "ofxZxing")**

###参考にさせていただいた既存のofxZxing制作者様
Kyle McDonaldさん作、ofxZxingを参考に今のzxingのバージョンで動くように制作しました
**[Kyle McDonaldさんのofxZxing](https://github.com/kylemcdonald "ofxZxing")**

#終わりに
Pull Request大歓迎です！というより人の作ったものを勝手に参考にして同じ名前で公開しちゃったんですけど問題なかっただろうか...どこかに怒られたりしないかちょっと不安(笑)

ではまた次回に。読んでいただきありがとうございました。
よかったら使ってみてください。
【sequelize】よく使うWhere条件

sequelizeを使用して、Where句に条件を書こうとするときに調べることが多いので、よく使うものをまとめます。

##環境
DB：MySQL
sequelizeのバージョン：4.38.0
node.jsのバージョン：7.10.0

以下、コードについてはそのままコピペでは動きません(モデル定義等必要です)。
あくまでWhere句部分を参考にしてもらえればと思います。
一番下に早見表もあります。


##where id= 2
```javascript
models.Book.findAll({
  where: {
    id : 2
  }
}).then(function(books){
  console.log(books);
});
```

##where id != 2
```javascript
models.Book.findAll({
  where: {
    id : {
      $ne: 2
    }
  }
}).then(function(books){
  console.log(books);
});
```


##where id = 2 AND price = 500
```javascript
models.Book.findAll({
  where: {
    id : 2,
    price: 500
  }
}).then(function(books){
  console.log(books);
});
```

##where id = 2 OR price = 500
```javascript
models.Book.findAll({
  where: {
    $or: [
      {id: 2}, 
      {price: 500}
    ]
  }
}).then(function(books){
  console.log(books);
});
```

一つのカラムで複数の値を調べたい場合は以下でも可。

```javascript
models.Book.findAll({
  where: {
    price : {
      $or : [500, 0]
    }
  }
}).then(function(books){
  console.log(books);
});
```

##where price > 500
```javascript
models.Book.findAll({
  where: {
    price : {
      $gt: 500
    }
  }
}).then(function(books){
  console.log(books);
});
```

##where price >= 500
```javascript
models.Book.findAll({
  where: {
    price : {
      $gte: 500
    }
  }
}).then(function(books){
  console.log(books);
});
```

##where price < 500
```javascript
models.Book.findAll({
  where: {
    price : {
      $lt: 500
    }
  }
}).then(function(books){
  console.log(books);
});
```

##where price <= 500
```javascript
models.Book.findAll({
  where: {
    price : {
      $lte: 500
    }
  }
}).then(function(books){
  console.log(books);
});
```

##where price BETWEEN 500 AND 1000
```javascript
models.Book.findAll({
  where: {
    price : {
      $between: [500, 1000]
    }
  }
}).then(function(books){
  console.log(books);
});
```

##where price NOT BETWEEN 500 AND 1000
```javascript
models.Book.findAll({
  where: {
    price : {
      $notBetween: [500, 1000]
    }
  }
}).then(function(books){
  console.log(books);
});
```

##where id IN (1,5)
```javascript
models.Book.findAll({
  where: {
    id : {
      $in: [1, 5]
    }
  }
}).then(function(books){
  console.log(books);
});
```


##where id NOT IN (1,5)
```javascript
models.Book.findAll({
  where: {
    id : {
      $notIn: [1, 5]
    }
  }
}).then(function(books){
  console.log(books);
});
```

##where title LIKE '%巻'
```javascript
models.Book.findAll({
  where: {
    title : {
      $like: '%巻'
    }
  }
}).then(function(books){
  console.log(books);
});
```

##where title NOT LIKE '%巻'
```javascript
models.Book.findAll({
  where: {
    title : {
      $notLike: '%巻'
    }
  }
}).then(function(books){
  console.log(books);
});
```






##where price IS NULL
```javascript
models.Book.findAll({
  where: {
    price : null
  }
}).then(function(books){
  console.log(books);
});
```

##where price IS NOT NULL
```javascript
models.Book.findAll({
  where: {
    price : {
      $ne: null
    }
  }
}).then(function(books){
  console.log(books);
});
```


###参考
http://docs.sequelizejs.com/
RDS for Oracle の DataPump

## RDS for Oracle 同士の DataPump
エクスポートしたら DBLink を張って、Dump を送り込み、インポートするだけの作業です。
この記事は、訳あって 12c -> 11g への移行した際のメモになります。

## 手順
### エクスポート
RDS for Oracle の `DATA_PUMP_DIR` は変更出来ない。

```sql:
SELECT directory_name, directory_path FROM dba_directories WHERE directory_name='DATA_PUMP_DIR';

DIRECTORY_NAME
--------------------------------------------------------------------------------
DIRECTORY_PATH
--------------------------------------------------------------------------------
DATA_PUMP_DIR
/rdsdbdata/datapump
```

DBMS_DATAPUMP でエクスポートを実行する。
ダウングレードしないのであれば、version の指定はいらない。

```sql:
DECLARE
hdnl NUMBER;
BEGIN
hdnl := DBMS_DATAPUMP.open( operation => 'EXPORT', job_mode => 'SCHEMA', job_name => null, version => '11.2.0');
DBMS_DATAPUMP.ADD_FILE( handle => hdnl, filename => '<<hoge.dmp>>', directory => 'DATA_PUMP_DIR', filetype => dbms_datapump.ku$_file_type_dump_file);
DBMS_DATAPUMP.add_file( handle => hdnl, filename => '<<exp_hoge.log>>', directory => 'DATA_PUMP_DIR', filetype => dbms_datapump.ku$_file_type_log_file);
DBMS_DATAPUMP.METADATA_FILTER(hdnl,'SCHEMA_EXPR','IN (''<<SCHEMA_NAME>>'')');
DBMS_DATAPUMP.start_job(hdnl);
END;
/
```

出力したファイルを確認する。

```sql:
SELECT * FROM TABLE(RDSADMIN.RDS_FILE_UTIL.LISTDIR('DATA_PUMP_DIR')) ORDER BY MTIME;
```

ログを確認する。

```sql:
SELECT TEXT FROM TABLE(RDSADMIN.RDS_FILE_UTIL.READ_TEXT_FILE('DATA_PUMP_DIR','<<exp_hoge.log>>'));
```

### 転送
まずは DBLink を作成する。

```sql:
CREATE DATABASE LINK <<DB_LINK_NAME>> CONNECT TO <<USER_NAME>> IDENTIFIED BY <<USER_PASSWORD>> USING '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=<<host>>)(PORT=<<port>>))(CONNECT_DATA=(SID=<<identifier>>)))';
```

そしてダンプファイルを送りこむ。

```sql:
BEGIN
DBMS_FILE_TRANSFER.PUT_FILE(
source_directory_object => 'DATA_PUMP_DIR',
source_file_name => '<<hoge.dmp>>',
destination_directory_object => 'DATA_PUMP_DIR',
destination_file_name => '<<from_hoge.dmp>>',
destination_database => '<<DB_LINK_NAME>>'
);
END;
/
```

### インポート
ファイルが転送されている事を確認する。

```sql:
SELECT * FROM TABLE(RDSADMIN.RDS_FILE_UTIL.LISTDIR('DATA_PUMP_DIR')) ORDER BY MTIME;
```

確認出来たら、DBMS_DATAPUMP を使い、インポートを実行する。

```sql:
DECLARE
hdnl NUMBER;
BEGIN
hdnl := DBMS_DATAPUMP.open( operation => 'IMPORT', job_mode => 'SCHEMA', job_name => null);
DBMS_DATAPUMP.ADD_FILE( handle => hdnl, filename => '<<from_hoge.dmp>>', directory => 'DATA_PUMP_DIR', filetype => dbms_datapump.ku$_file_type_dump_file);
DBMS_DATAPUMP.add_file( handle => hdnl, filename => '<<imp_hoge.log>>', directory => 'DATA_PUMP_DIR', filetype => dbms_datapump.ku$_file_type_log_file);
DBMS_DATAPUMP.METADATA_FILTER(hdnl,'SCHEMA_EXPR','IN (''<<SCHEMA_NAME>>'')');
DBMS_DATAPUMP.start_job(hdnl);
END;
/
```

ログを確認する。

```sql:
SELECT TEXT FROM TABLE(RDSADMIN.RDS_FILE_UTIL.READ_TEXT_FILE('DATA_PUMP_DIR','<<imp_hoge.log>>'));
```

不要になったファイルは消しましょう。

```sql:
BEGIN
utl_file.fremove('DATA_PUMP_DIR', '<<hoge.dmp>>');
utl_file.fremove('DATA_PUMP_DIR', '<<exp_hoge.log>>');
END;
/
```

DBLink も不要なら消しましょう。

```sql:
DROP DATABASE LINK <<DB_LINK_NAME>>;
```

以上です。

## 仲間募集中
[弊社](https://www.nittsu-infosys.com/)ではエンジニアを募集中です。インフラからアプリ、ユーザサポートまで幅広く業務を行ってます。
https://www.nittsu-infosys.com/recruit/2019/index.html
fwrite 直後に fread しても読み込めないことがある(と思ったらそんなことはなかった)

# 準備
まずは binary ファイルを用意

```c
int main(void)
{
    FILE *f = fopen("./in.dat", "wb");
    char hoge[10] = "abcdefghi\0";
    fwrite(hoge, sizeof(char), 10, f);
    fclose(f);
}
```

binary モードで vim で開くと、
(`vim -b in.dat` => `:%!xxd`)

```vim
00000000: 6162 6364 6566 6768 6900                 abcdefghi.
```

# 本題

in.dat から読み込み、その内容を out.dat に出力する。
その後、out.dat を fread して、それを末尾に fwrite で追加しようとする。

そのとき、うまく書き込めない。

## パターン１: 何も考えないで書く

```c
#include <stdio.h>

int main(void)
{
    char buff[10] = {0};
    char buff2[10] = {0};

    FILE *in = fopen("./in.dat", "rb");
    FILE *out = fopen("./out.dat", "wb");

    fread(buff, 1, 10, in);
    fwrite(buff, 1, 10, out);

    fseek(out, 0, SEEK_SET);
    fread(buff2, 1, 10, out);

    fseek(out, 10, SEEK_SET);
    fwrite(buff2, 1, 10, out);

    fclose(in);
    fclose(out);
}
```

これをやると、うまくいかない

```vim
00000000: 6162 6364 6566 6768 6900 0000 0000 0000  abcdefghi.......
00000010: 0000 0000                                ....
```

# パターン2: fflush() する

バッファに残っているからでは？と思ったので fflush() してみる

```c
#include <stdio.h>

int main(void)
{
    char buff[10] = {0};
    char buff2[10] = {0};

    FILE *in = fopen("./in.dat", "rb");
    FILE *out = fopen("./out.dat", "wb");

    fread(buff, 1, 10, in);
    fwrite(buff, 1, 10, out);

    // ここで fflush
    fflush(out);

    fseek(out, 0, SEEK_SET);
    fread(buff2, 1, 10, out);

    fseek(out, 10, SEEK_SET);
    fwrite(buff2, 1, 10, out);

    fclose(in);
    fclose(out);
}
```

これもうまくいかない


```vim
00000000: 6162 6364 6566 6768 6900 0000 0000 0000  abcdefghi.......
00000010: 0000 0000                                ....
```

## パターン3: setbuf() を使う

setbuf() を追加し、第二引数で NULL を指定することで、バッファリングをしないようにする。
(fflush でできているはずだが、念の為)

```c
#include <stdio.h>

int main(void)
{
    char buff[10] = {0};
    char buff2[10] = {0};

    FILE *in = fopen("./in.dat", "rb");
    FILE *out = fopen("./out.dat", "wb");

    // そもそもバッファリングしない
    setbuf(out, NULL);

    fread(buff, 1, 10, in);
    fwrite(buff, 1, 10, out);
    // ここで fflush
    fflush(out);

    fseek(out, 0, SEEK_SET);
    fread(buff2, 1, 10, out);

    fseek(out, 10, SEEK_SET);
    fwrite(buff2, 1, 10, out);

    fclose(in);
    fclose(out);

```

これもうまくいかない


```vim
00000000: 6162 6364 6566 6768 6900 0000 0000 0000  abcdefghi.......
00000010: 0000 0000                                ....
```

# 結論
よくわからないが fflush() とかしてもうまくいかないことがあるのだろうか。。。謎。。。

https://stackoverflow.com/questions/19062239/fclose-function-in-c-why-fread-works-but-not-fwrite-if-you-call-fclose-for
↑をみると、以下のようなコメントがある。

```
(Actually, I think there are some cases where data may not physically arrive
in the file even after fclose() or fflush().)
```
これは一体どういうケースなのだろうか・・・

# 追記
と思ったが、↓で解決した(コメントいただいた)。

```c
    FILE *out = fopen("./out.dat", "wb+");
```

fread するには `+` をつけないといけないという初歩的なミス。。。
こういうときは fread が NULL を返すもんだと勘違いしていたのも気づけなかった原因だった。。
1つのstreamから複数回読み込みを行う

# はじめに
GolangでのCLIツール作成の練習として[画像をリサイズしてくれるツール](https://github.com/mafuyuk/imageresize)を作っていた際に、1つのstreamから複数回読み込みを行う必要がでてきたのでその備忘録

# なぜ複数回の読み込みが必要？
* 画像の形式に関しては利用者側は意識しなくても良いように`image.Decode()`で取得できる`format`を使い処理を条件分岐してました。（この処理で１つの読み込みが必要

```golang
img, format, _ := image.Decode(in)
  
switch format {
  case "png":
```

* `png`と`jpeg`に関しては`image.Decode`で取得できる`Image`インスタンスをそれ移行の処理で使えばいいだけなのですが、`gif`は`gif.DecodeAll()`という別の関数を呼び出す必要があるらしく、こちらの引数が`io.Reader`でした(２つ目


# どうしたのか
```golang
buf := bytes.NewBuffer(nil)
gifDecodeTarget := bytes.NewBuffer(nil)

w := io.MultiWriter(buf, gifDecodeTarget)
io.Copy(w, in)

img, format, err := image.Decode(buf)

switch format {
case "gif":
  gifimg, err := gif.DecodeAll(gifDecodeTarget)
```

`io.MultiWriter`を使うことで複数のoutに対して書き込みができるので、`io.Copy`を利用してinを複数のout(両方とも`Buffer`)に書き込み、`bytes.Buffer`はRead関数を持ってるため`io.Reader`を満たしているので、読み込みが必要な場面で利用していきました

# その他指摘いただいた方法
## Seekを使うパターン
Seekerが実装されている`os.File`などで受け取ること前提になってしまいますが、Seekを使うパターン

```golang
img, format, err := image.Decode(in)

switch format {
case "gif":
  in.Seek(0, 0) // インデックスを先頭に戻す
  gifimg, err := gif.DecodeAll(in)
```

## io.TeeReaderを使うパターン
こちらだと`io.Reader`のまま行けそうです

```golang
buf := bytes.NewBuffer(nil)
r := io.TeeReader(in, buf)
img, format, err := image.Decode(r) // このタイミングでbufに書き込みが走る

switch format {
case "gif":
  gifimg, err := gif.DecodeAll(buf)
```