OmniAICreator/Qiita-1.07M huggingface dataset:
【コマンド】unameでシステムの情報(OS, プロセッサ, ハードウェア)を表示する

#uname
```shell:
$ uname -a
Darwin TKPro.local 18.5.0 Darwin Kernel Version 18.5.0: 
Mon Mar 11 20:40:32 PDT 2019; root:xnu-4903.251.3~3/RELEASE_X86_64 x86_64
```

#オプション
|名前|内容|
|---|---|
|-a|（おすすめ）全ての情報表示|
|-m|ハードウェア名|
|-n|ホスト名|
|-p|プロセッサーの型|
|-r|カーネルのリリース日|
|-s|カーネル名|
|-v|カーネルバージョン|

#Happy Hacking :sunglasses: !
ROCm-Pytorch-Dockerの環境構築


docker,ROCm環境はすでに構築済みと仮定します

この前に書いたやつと内容はそれほど変わりません

#環境構築


##ホストマシン側での下準備

```
cd ~
mkdir data
cd ./data
git clone https://github.com/pytorch/pytorch.git
cd pytorch
git submodule update --init --recursive
```

##docker imageの用意とDocker run

```
sudo docker pull rocm/pytorch:rocm2.7_ubuntu16.04_py3.6_pytorch
sudo docker run --name pytroch_rocm -it -v /home/???/data/:/data --privileged --rm --device=/dev/kfd --device=/dev/dri --group-add video rocm/pytorch:rocm2.7_ubuntu16.04_py3.6_pytorch 
```


???にはユーザーの名前を入れてください、絶対パスで設定しています


##Dockerコンテナ内での下準備

ココらへんは頻繁に開発環境を用意するようならdockerfileにまとめていい気がしてますね

```
apt update
apt install git
apt install nano (vimでもいい）
```

##Dockerコンテナ内でのpytorch build
buildを一々しないと駄目な仕様なので事前に時間のあるときにハイパワーPCでやったほうがいいです。


一応環境変数に```export PYTORCH_ROCM_ARCH=gfx900```を追加しておきました
RadeonⅦならgfx906、RX400や500だったらgfx803でいいと思います

```
cd /data/pytorch
./.jenkins/pytorch/build.sh 

```
Vuetifyを日本語化する

昨日までVuetify v1.5でしたが今日はv2.0のお話です。
DataTableの読込中メッセージはloading-textプロパティで変更できるものの、
どうやったらNot foundとかを変えるのか...ということで公式読んでやってみました。

公式ドキュメントだと拡張子をつけないまま読み込む＆.tsファイルしか対応していませんでしたが、
調べたらES5にも対応していたので今回はその方法で行います。

```es5
import Vue from 'vue'
import Vuetify from 'vuetify'
//ES5の言語ファイルをimport
import ja from 'vuetify/es5/locale/ja.js'

//Typescriptはこっち
//import ja from 'vuetify/src/locale/ja.ts'

Vue.use(Vuetify)

//localeでjaを指定したらcurrentでもja指定する
const app = new Vue({
    vuetify: new Vuetify({
      lang: {
        locales: { ja },
        current: 'ja',
      },
    }),
}).$mount('#app')
```

これでDataTableのメッセージなどが切り替わります。

localesを複数読み込めば動的にも変えられるようです。
今回は特にそういった要件が無かったので対応していません。
【Google Cloud】Natural Language APIやってみた【AI】

#序文、環境

記事の粒度がちょいと浅いので今後お勉強かな…

APIキーの取り方は後で書きます。
googleMAPなどほかのAPIのキーがあればおそらく流用可能。

curl入れる感じでやります。
(json書けない・・・)

実施環境は
CentOS: 7.4
PHP: 7.1.32
Curl: 7.29.0


# 感情分析API

### ポジティブ代表 升田 幸三名人（将棋）
「何より大事なのは、人生を楽しむこと。幸せを感じること、それだけです。」

<pre>
curl -X POST -H "Content-Type: application/json" -d '{  "document": {    "type": "PLAIN_TEXT" ,  "content": "何より大事なのは、人生を楽しむこと。幸せを感じること、それだけです。"  }}' "https://language.googleapis.com/v1/documents:analyzeSentiment?key=[YOUR_API_KEY]" 
</pre>

### ネガティブ代表 ウィリアム・シェイクスピア
「友情は多くは見せかけであり、恋は多くの愚かさにすぎない。」

<pre>
curl -X POST -H "Content-Type: application/json" -d '{  "document": {    "type": "PLAIN_TEXT" ,  "content": "友情は多くは見せかけであり、恋は多くの愚かさにすぎない。"  }}' "https://language.googleapis.com/v1/documents:analyzeSentiment?key=[YOUR_API_KEY]" 
</pre>


## 返り値(長さの都合上ポジティブのみ)

<pre>
{
  "documentSentiment": {
    "magnitude": 1.4,
    "score": 0.7
  },
  "language": "ja",
  "sentences": [
    {
      "text": {
        "content": "何より大事なのは、人生を楽しむこと。",
        "beginOffset": -1
      },
      "sentiment": {
        "magnitude": 0.6,
        "score": 0.6
      }
    },
    {
      "text": {
        "content": "幸せを感じること、それだけです。",
        "beginOffset": -1
      },
      "sentiment": {
        "magnitude": 0.8,
        "score": 0.8
      }
    }
  ]
}
</pre>

### googleより

score=ネガティブ->ポジティブ
magnitude=感情的でない->感情的である

|感情|サンプル値|
|:-----------------|------------------:|:------------------:|
|明らかにポジティブ|"score": 0.8、"magnitude": 3.0|
|明らかにネガティブ|"score": -0.6、"magnitude": 4.0|
|ニュートラル|"score": 0.1、"magnitude": 0.0|
|混合|"score": 0.0、"magnitude": 4.0|

### Natural Language APIの金額

Natural Language APIにはリクエストごとに課金される。
5000req/month　以下なら無料で利用可能。

料金詳細は以下：
https://cloud.google.com/natural-language/pricing?hl=ja
airdropの速度を上げろう

airdropでMac間ファイルをコピーする時、速度が遅い場合、下記のコマンドを叩くと、改善するかもしれません

```
ln -s /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport /usr/local/bin/airport
sudo airport -z
```

Mac間Peer-To-Peerコネクションを作れるようにネットワークの接続を閉じます。P2Pコネクションができると、速度は10Mbpsまで上がれます。
プロパティをまとめて指定するmixin

やりたいこと
-
[marginの上下・左右だけを一行で指定するMixin - Qiita](https://qiita.com/milkmeta/items/06cf72eb4f080aabd9a0#)
↑この話と似た話です。

`セレクタ { プロパティ : 値 ; }`
複数プロパティで同一値を指定したい時が時々あります。
そのためのmixin。

mixin
-
```scss:sameValues.scss
@mixin sameValues($props,$value){
  @each $prop in $props {
    #{$prop} : $value;
  }
}
```

使い方
-
```scss:正方形が描きたいな.scss
.square {
  $size: width height;
  @include sameValues($size, 200px);
}
/* 出力
.square {
  width: 200px;
  height: 200px;
}
*/
```
```scss:ブロックを中央に寄せたいな.scss
.center-box {
  margin: {
    @include sameValues(left right, auto);
  }
}
/* 出力
.center-box {
  margin-left: auto;
  margin-right: auto;
}
*/
```
書き出しエラー
-
```scss:第１引数は配列.scss
@include sameValues(left, right, 10px);
// ↓こうしましょう
@include sameValues(left right, 10px);
// ↓またはこう
$array: left, right;// ここで「,」区切りはOK。スペース区切りでもOK。
@include sameValues($array, 10px);
```
mixin名の命名で悩む
`sameValues`→複数出力する
`sameValue`→値は1つ
複数形のsをつけるかどうか悩む。
【Python】Enumを使わない静的データ管理

## 背景
簡易なプログラムを書く際、わざわざデータベースを立てたり設定ファイルから定数を取得するのも面倒な時は、データをプログラムにハードコーディングしてしまう場合もしばしばあります。


Enumを使うとスマートに書きやすいと前回 [【Python】Enumで静的データ管理](https://qiita.com/azumagoro/items/bafed453e12b7a5d4b2f) 書きました。

しかし、**Enumはメンバーの命名が必要なため、命名コストが重たいときは向いてません**。そこで命名をしないで済む方法を調べ、実装してみました。

結論としては、namedtupleをclass内listに格納して管理します。
listの要素に辞書型を使ってもいいですが、変数へのアクセスがnamedtupleの方が書きやすいのでnamedtupleを使用します。

ちなみに、わざわざclass内にlistを設けるのは、変数のスコープを狭めたいからです。

## 環境
Python3.6.8

3.7以上からはdataclassesなるものがあるので、使えるならそちらの方がスマートに書けるかもしれません（全然触ってないため分かりませんが）。


```.py
from collections import namedtuple

class MonsterData:

    Monster = namedtuple('Monster', ['id', 'en', 'ja'])

    members = [
        Monster(0, 'None', '無し'),
        Monster(1, 'Slime', 'スライム'),
        Monster(2, 'Killer Ant', 'キラーアント'),
        Monster(3, 'Goblin', 'ゴブリン'),
        Monster(4, 'Lizardman', 'リザードマン'),
        Monster(5, 'Ogre', 'オーガ'),
        Monster(6, 'Dragon', 'ドラゴン'),
    ]

    @classmethod
    def get_by_id(cls, id):
        for c in cls.members:
            if id == c.id:
                return c
        # default
        return cls.members[0]

    @classmethod
    def get_by_ja(cls, ja):
        for c in cls.members:
            if ja == c.ja:
                return c
        # default
        return cls.members[0]



if __name__ == "__main__":

    print(MonsterData.get_by_id(1).ja)
    print(MonsterData.get_by_id(1).en)
    print('=====')
    print(MonsterData.get_by_ja('ゴブリン').id)
    print(MonsterData.get_by_ja('ゴブリン').en)

```

```
スライム
Slime
=====
3
Goblin
```

変数の命名コストを省けました。
mysql5.5でbinlog_formatによってはslave重複エラーが出た


mysql5.5でbinlog_format＝mixedでslaveがDuplicateで止まるエラーが出たので備忘録を。

まあ、MyISAMからInnoDBにしたいのでパラメータどうすればいいのか聞かれたので色々オススメしたなかの一つに、バイナリログのサイズ削れるしディスク圧迫抑えられそうだしいいかなーということでbinlog_formatをrowからmixedに変えたのがあったんですが、スレーブがどうあっても開始できなくて開始直後にエラーで止まった。
その時に出たエラーが以下。

```
[ERROR] Slave SQL: Error 'Cannot add or update a child row: a foreign key constraint fails
[ERROR] Slave SQL for channel '': Error 'Duplicate entry '' for key 'PRIMARY'' on query.
```
検索したら以下のバグがヒットして再現手順にInnoDB＋SBRと書いてありました。
https://bugs.mysql.com/bug.php?id=41754

SBRじゃないけどmixedだと似た動きするときもある。
以下スライドによると整合性重視ならrowがいい（ただしPrimaryキーないとログの量が多くなって詰むようだ）
https://www.slideshare.net/yoku0825/mysql-86831302

まとめるとbinlog_format＝rowに戻したらslave開始できました。

ついでに言うと、
5.5までだと、perconaサーバはクラッシュセーフなパラメータがあるようです。
https://www.percona.com/blog/2013/07/15/crash-resistant-replication-how-to-avoid-mysql-replication-errors/

5.6以降であれば以下のパラメータでクラッシュセーフreplicationできるような話を聞いた[記憶](https://qiita.com/smallpalace/items/e9fd924078b663d7616b)が。

master-info-repository=TABLE
relay-log-info-repository=TABLE
relay_log_recovery=ON

最初はDuplicate entryならskipでもいいのではという話でしたが、開始位置が間違ってたわけでもなくスキップしてもまた止まってたし、
Skipした場合トランザクションのかかわりのあるものがまとめてスキップされかねないとの情報もありました。
https://yakst.com/ja/posts/14

以上
AlfrescoのshareページにGoogleアナリティクスタグを埋め込む

# 概要
内容は表題の通りですが、ネットにあまり情報が無かったので備忘録も兼ねて。
「どのサイト、ファイルがよく閲覧されているのか」などを
見慣れたGoogleアナリティクスのダッシュボードで集計できるので、きっと何かに役立ちます。

# 環境
 - Alfresco Community (Version 6.2.0)
 - docker-compose（[Alfresco/acs-community-deployment](https://github.com/Alfresco/acs-community-deployment/blob/master/docker-compose/docker-compose.yml)）

# 手順

 footerのhtml.ftlファイルにGoogleアナリティクスのトラッキングタグを記述し、shareを再起動してください。
 （dokcer-compose.ymlで当該ディレクトリの永続化設定もしてください。）


```html:/usr/local/tomcat/webapps/share/WEB-INF/classes/alfresco/site-webscripts/org/alfresco/components/footer.footer.get.html.ftl
<@markup id="css" >
   <#-- CSS Dependencies -->
   <@link href="${url.context}/res/modules/about-share.css" group="footer"/>
   <@link href="${url.context}/res/components/footer/footer.css" group="footer"/>
</@>

<@markup id="js">
   <@script src="${url.context}/res/modules/about-share.js" group="footer"/>
</@>

<@markup id="widgets">
   <@createWidgets/>
</@>

<@markup id="html">
   <@uniqueIdDiv>
      <#assign fc=config.scoped["Edition"]["footer"]>
      <div class="footer ${fc.getChildValue("css-class")!"footer-com"}">
         <span class="copyright">
            <a href="#" onclick="Alfresco.module.getAboutShareInstance().show(); return false;"><img src="${url.context}/res/components/images/${fc.getChildValue("logo")!"alfresco-logo.svg"}" alt="${fc.getChildValue("alt-text")!"Alfresco Community"}" border="0"/></a>
            <#if licenseHolder != "" && licenseHolder != "UNKNOWN">
               <span class="licenseHolder">${msg("label.licensedTo")} ${licenseHolder}</span><br>
            </#if>
            <span>${msg(fc.getChildValue("label")!"label.copyright")}</span>
         </span>
      </div>
   </@>
   
<!-- ↓↓↓ここにタグを埋め込む↓↓↓ -->
   <script async src="https://www.googletagmanager.com/gtag/js?id=UA-XXXXXXXXX-X"></script>
   <script>
       window.dataLayer = window.dataLayer || [];
       function gtag(){dataLayer.push(arguments);}
       gtag('js', new Date());
       gtag('config', 'UA-XXXXXXXXX-X');
   </script>
<!-- ↑↑↑ここまで↑↑↑ -->

</@>
```
Goのポインタ変数

## ポインタ変数とは
メモリのアドレスを値として持つ変数のこと。

```go
var intVal int      // int型の変数
var intPointer *int // intのポインタ変数

intVal = 5
intPointer = &intVal // intPointerはintValのアドレスを指し示す

fmt.Println(&intVal)     // 0x0000011
fmt.Println(intPointer)  // 0x0000011
fmt.Println(&intPointer) // 0x0000145
```

メモリは1Byte単位でアドレスがつけられて, そのアドレスで区別される。
上のコードの場合, `intVal`はメモリを確保して`5`という値を直接格納する。
(下の図は64-bit環境基準でintは8bytesのため, アドレス8個分になっている)
`intPointer`はメモリを確保して`intValのアドレス`を値として格納する。

<img width="474" alt="pointer.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306025/96dd984f-4259-3a65-0724-01e42077aec2.png">

## ポインタの扱い

### ポインタ変数の定義
指し示す変数の型に合わせて`*`をつけて定義

```go
var intPointer *int
var boolPointer *bool
var stringPointer *string
```

### ポインタに参照先を設定する
`nil`状態のポインタの参照先に値をセットする場合, panicになる
(指してるところがないので, どこに値を入れればいいかわからない状態)

```go
// int型のポインタ変数
var intPointer *int
*intPointer = 5 // panic: runtime error: invalid memory address or nil pointer dereference
```

#### 変数のアドレスを代入する
一般的には変数のアドレスを代入して使う

```go
var intPointer *int
intVal := 5

intPointer = &intVal

fmt.Println(intPointer)  // 0x0000011
fmt.Println(&intVal)     // 0x0000011
```

#### newでポインタに値をセット
変数を定義せず`new`を利用して無名変数を代入することができる。

```go
var intPointer *int
intPointer = new(int) // ゼロ値のint型がメモリに確保され, それを指し示すようになる
*intPointer = 5       // 指しているメモリアドレスに5をセットする

fmt.Println(*intPointer) // 5
fmt.Println(intPointer)  // 0xc000014080
```

### 参照先の値を変更
ポインタ変数名に`*`をつけると指し示す変数の扱いになる。

```go
intVal := 5
intPointer := &intVal

fmt.Println(intVal)      // 5
fmt.Println(*intPointer) // 5

*intPointer = 10 // intVal = 10 するのと同じ

fmt.Println(intVal)      // 10
fmt.Println(*intPointer) // 10
```


## ポインタ変数のサイズ
ポインタはメモリアドレスであるため, ポインタのサイズは指し示すデータのサイズではなく,
アドレスを指定できるメモリの最大量に基づいて決まる。
32-bitシステムでは4bytes(32bits), 64-bitシステムでは 8bytes(64bits)になる。

よって, 下記のように指し示すデータ型は異なってもポインタ変数のサイズは64-bitシステムでは全て8になる

```go
type User struct {
	name  string
	birth time.Time
}

func main() {
	var intPointer *int
	var userPointer *User
	var boolPointer *bool

	fmt.Println(unsafe.Sizeof(intPointer))  // 8
	fmt.Println(unsafe.Sizeof(userPointer)) // 8
	fmt.Println(unsafe.Sizeof(boolPointer)) // 8
}
```

## まとめ
スライスや構造体にはポインタがよく使われるのでGoで開発するにはポインタの理解は必要だ。
ポインタは何が値で何がアドレスか分かりにくくなるときがあるが, `*`と`&`の書き方と意味をちゃんと理解しておけば, ポインタ演算がないGoでは案外難しくないかもしれない。
【DataPipeline】AWSアカウント跨ぎで、DynamoDBエクスポートデータのインポートでハマった話し

# やったこと
## AWSアカウント「A」でやったこと
1. DataPipelineで、DynamoDBからデータをエクスポート、S3に保存
2. S3に保存されたデータをローカルにダウンロード

## AWSアカウント「B」でやったこと
1. ローカルにダウンロードしたデータをS3にアップロード
2. DataPipelineで、S3からデータをインポートし、DynamoDBにインポート
3. DataPipelineがFAIL

# 結論
エクスポートしてできたファイルの「manifest」を手動で編集して使用する必要あり

# なぜ？
DataPipelineのS3＜＞DynamoDBのインポート/エクスポートは、同一バケットを想定してるっぽい。（元にそういった記事しか見つからなかった）
が、今回のようにAWSアカウントを跨ぐということは、バケット名は絶対に異なる。（バケット名はグローバルでユニークなので）
後々ようやく気づいたのだが、エクスポートしてできたファイルの中の１つ「manifest」には以下のような記述があった。

```json:manifest
{"name":"DynamoDB-export","version":3,
"entries": [
{"url":"s3://[AWSアカウントAのバケット名]/2019-08-25-09-06-35/4622bd21-0a13-4d5a-b96f-f2897e39ef17","mandatory":true}
]}
```

AWSアカウント「B」で、DataPipelineを使用してインポートする際に、このファイルも参照していて、このファイルに書かれているバケットに対してインポートするファイルを探しているようだった。
AWSアカウント「B」でインポートする場合は、manifestにかかれているバケット名を修正しなければならない。
そして、S3へアップロードする際も、ディレクトリ名、インポートするファイル名は合わせないといけない。
もちろん、DynamoDBのスキーマ構造もである。

気づけばなんてことないんだけど、DataPipelineではあたかもワンストップでできるような見た目になっており、気付くまでだいぶ時間がかかった。

教訓：エクスポートされたデータをちゃんと確認しましょう
Skill hacks1週目を終えて

迫さんのskillhacksを参考にプログラミングを勉強中です。
主に忘備録的な感じになりますが、よろしくお願いします。
現在は動画を参考にメモアプリを作成してみました。

![スクリーンショット 2019-05-26 17.40.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488766/0a5948b6-e705-6dab-c5ff-086b68b6d2e8.png)

メモの新規作成、メモ一覧の削除編集、カテゴリー別にソート等
とてもシンプルなwebアプリですが、MVCモデルの思想、基礎的なプログラム
を網羅しており、大変勉強になりました。

経験者からすると物足りないかもですが、
私のようなweb系初心者にとっては最初の一歩として非常に助かります。
Cookieとセッションについてメモ

自分用メモ。基本のこと。

# Cookie
- ユーザーがサイトにアクセスした時に発行されるファイル
- Webサーバー(訪問したサイト)が発行し、ユーザーに送信する
- 内容はセッションID(後述)
- アクセスするたびにWebサーバーに送信する

## Cookieの種類
#### セッションCookie
- 有効期限がない
- ユーザーのPCのメモリに保存される
- メモリに保存されるため、ブラウザを閉じると破棄される

#### 持続Cookie（または持続的・永続的Cookie）
- 有効期限がある
- ユーザーのPCのディスクに保存される（MacのChromeの場合`/Users/ユーザー名/Library/Application Support/Google/Chrome/Default`に保存される。）
- 有効期限が来るまでは、ブラウザを閉じても破棄されない

参考：[クッキーとは？ セッションと永続の違いは何ですか。](https://www.cisco.com/c/ja_jp/support/docs/security/web-security-appliance/117925-technote-csc-00.html)

# セッション
- ユーザーがサイトにアクセスし、サイトを離れる(ブラウザを閉じる)までの一連の行動のこと
- 例『サイトにアクセス→ページ移動→カートに商品を入れる→サイトを離れる』これで１セッション
- サイトにアクセスした状態で放置するなど、ある程度時間が経過すると別セッションとしてカウントされる
- 例『サイトにアクセス→ページ移動→(1時間放置)→カートに商品を入れる→サイトを離れる』サイトにアクセス→ページ移動まで１セッション。カートに商品を入れる→サイトを離れるまで１セッション。

参考：[セッション とは 意味/解説/説明 【session】](https://webtan.impress.co.jp/g/%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3)

## セッション情報
- Webサーバーにファイルとして保存されるセッション内容のこと
- 例：ログイン情報、カートに入れた商品等

## セッションID
- ユーザーを識別するための情報
- ユーザーが最初にサイトにアクセスした際、Webサーバーが発行する
- 発行したセッションIDはCookieに持たせて、ユーザーに送信する
- Webサーバー自身もセッションIDを保持する
- 一定時間アクセスがない・またはユーザーがログアウトすると破棄される

#### セッションIDの利用
ユーザーが再度サイトにアクセスする際、セッションIDをもつCookieをWebサーバーに送信する。
Webサーバーは送られてきたセッションIDを自身も持っているか確認する。
持っていればそれを元にセッション情報を取り出しユーザーに送信する。
持っていなければ発行し、Cookieに持たせてユーザーに送信する。

参考：[セッションの仕組みについて](http://blog.pionet.co.jp/experience/archives/1252), [ログアウト機能の目的と実現方法](https://blog.tokumaru.org/2013/02/purpose-and-implementation-of-the-logout-function.html)

# おまけ：キャッシュ
閲覧したサイトの情報をブラウザに保存する機能。
次回アクセスした時に早く表示できる。
Azure Blockchain Serviceを試してみる3（エクスプローラ導入編）

# まえおき
[前回の記事](https://qiita.com/hayago/items/ba4ca93bcd5d99735b9e)では、Azure Blockchain Serviceで構築したチェーンに対して、ERC20のトークンコントラクトをデプロイしました。今回の記事では簡単にではありますが、チェーンの運用に向けてメトリックの紹介と、ブロックチェーンエクスプローラの導入を行います。

# メトリック
Azureのポータル上にはノードの状態を監視するための、様々なメトリックが存在します。
<img width="600" alt="スクリーンショット 2019-09-03 11.57.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16354/a3ca00d2-6b84-d9fa-95ff-818c9e3976fd.png">
指定出来るメトリックとして、ブロック数等のチェーンの状態に関するメトリック群、リクエスト数等の通信コネクションに関するメトリック群、CPU使用率等のパフォーマンスに関するメトリック群が存在します。
これらのメトリックを適切に利用して、チェーンが正常に動作しているか監視する必要があります。

# エクスプローラの導入
前述のメトリックで確認出来ることは、チェーンのごく僅かな情報や、ノードのインスタンスとしての情報に限られます。ブロックの詳細の情報、トランザクション情報、デプロイされたコントラクト等は、ブロックチェーンのエクスプローラを利用して確認が可能です。
Azure Blockchain Service Explorerという簡易的なエクスプローラがMarketplace上にありますので、今回はそれを導入してみます。
<img width="600" alt="スクリーンショット 2019-09-03 12.37.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16354/34103693-a051-15fe-063a-f5a9ff1619ce.png">

作成ボタンをクリックし、必要情報を入力するとデプロイが行われます。
デプロイが完了したら、ポータルから仮想マシンが立ち上がっていることが確認できます。
<img width="600" alt="スクリーンショット 2019-09-03 14.10.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16354/1a261e1e-394d-c9dd-b0e4-bf27f5bfb4b7.png">

画面に表示されているDNS名にブラウザからアクセスすると、エクスプローラを閲覧出来ます。

**なお注意点として、デプロイを終えた状態ではアクセス制御がかかっておらず誰からでもエクスプローラを閲覧出来てしまう、かつ通信がHTTP通信になっているため、実際に運用する場合はセキュリティ面の見直しが必要です。**

### エクスプローラにアクセス
かなりシンプルなUIではありますが、ブロック情報やトランザクション情報、トークンの送金履歴などの基本的な情報の閲覧・検索が可能です。
<img width="600" alt="スクリーンショット 2019-09-03 14.02.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16354/8fe96a06-0d22-885d-30a2-020229b8763e.png">

以下は[前回の記事](https://qiita.com/hayago/items/ba4ca93bcd5d99735b9e)でデプロイしたALISのトークンコントラクトの情報です。
<img width="600" alt="スクリーンショット 2019-09-03 15.20.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16354/de505a30-a4e6-03ed-f198-76d9d842a9e7.png">

# おわりに
ブロックチェーンの状態をJSON RPCやweb3.js経由で確認するのはかなり面倒ですが、メトリックやエクスプローラを使って効率よく確認しましょう。以上、簡単にですがメトリックの紹介とエクスプローラの導入に関してでした。
[次回の記事](https://qiita.com/hayago/items/c1785a785d891f56f192)ではAzure Blockchain Serviceのコンソーシアムの管理を行います。:wave:
解消法→Excessive stack depth comparing types 'MongoRepository<Entity>' and 'Repository<Entity>'.

本稿ではtypeormのコンパイルで発生する「Excessive stack depth comparing types 'MongoRepository<Entity>' and 'Repository<Entity>'.」というエラーの解消法について伝える。

なお、この問題は発見されてから日が浅いため、より良い解消法が見つかる可能性がある。

## 僕の環境での発生状況

* typeorm 0.2.18
* typescript 3.6.2 (3.5.3では再現せず)

## 解消法1: typescript@3.5.3にダウングレードする

僕の環境では、typescript@3.5.3ではこの問題が発生しておらず、また、GitHubのissueでも3.5.3にダウングレードしたら解決したという報告が寄せられていることから効果があると考えられる。

## 解消法2: "skipLibCheck: true"をセットする

暫定措置として、tsconfig.jsonの`compilerOptions`に`"skipLibCheck": true`をセットするとエラーを抑制できる。これはすべての*.d.tsファイルの型チェックをスキップするというもの。

```tsconfig.json
{
  "compilerOptions": {
    // skipLibCheck is a temporary solution for https://github.com/typeorm/typeorm/issues/3194
    "skipLibCheck": true
  }
}
```

## 関連

* [TS2321: Excessive stack depth comparing types 'MongoRepository<Entity>' and 'Repository<Entity>' · Issue #3194 · typeorm/typeorm](https://github.com/typeorm/typeorm/issues/3194)
SQL テーブルを作成する為のcreate文について

PostgreSQLの場合

【データベースのテーブルについて】
テーブルとはデータベースに格納されている表のことをいいます。
リレーショナルデータベース管理システム(略してRDBMS)はデータを表形式で保存します。

表は行(レコード)と列(カラム)で構成されています。
エクセルの表をイメージしていただければ分かりやすいでしょう。

表の列(カラム)にタイトルをつけ、行(レコード)ごとにデータを格納していきます
</font>
【テーブルを作成するSQL文】
表を作るSQLは次のように書きます

```sql

create table テーブル名
(
    カラム名 データ型 制約
)
```

実際にサンプルコードを書いてみると

```sql

create table GoldenTable     --1行目
(                            --2行目
    column1 int not null,    --3行目
    column2 char,            --4行目
    column3 varchar(10)      --5行目
)                            --6行目
```

のようになります。

<b>1行目はテーブルを作成するcreate文の書き出しです</b>
上記ではGoldenTableをテーブル名にしました。

次に、()で囲んだところに列に関することを書いていきます。
<b>3行目から5行目が列に関することです</b>

3行目についての内容は次の通りです
column1が列名で
intがデータ型で
not nullが制約です

データ型とはデータの種類のことをいい、整数型や文字型などがあります
整数型にはint型やlong型などがあり
文字型にはchar型やvarchar型などがあります
さらに詳しくはググってみてください

not null制約があると該当のカラムはnullを許容しないということになります

列名 データ型 制約 の間は半角スペースを入れて書きます。
WPXクラウドでAll-in-One WP Migration のエクスポートファイルのダウンロードが失敗する。

WPXクラウドでAll-in-One WP Migrationを使ってエクスポートするときに、出来上がったファイルをダンロードしようとすると壊れたファイルがダウンロードされる。
中身は500エラーのHTML
これを治す。


FTPやWPのプラグインで
`/wp-content/ai1wm-backups/.htaccess`
の中身を

``` apache-config:.htaccess
AddType application/octet-stream .wpress
```

のみにする。


* コントロールパネルから設定できる.htaccessをいじっていない前提
* コントロールパネルでのFTPの設定によっては `/wp-content/ai1wm-backups/.htaccess`は`/ai1wm-backups/.htaccess` に見えるかも
* もしかしたらXserverでも使えるかもしれないね。
AWS サポートセンター利用時の履歴が出てこない場合

# 事象
AWSサポートセンターで過去の履歴を確認するため、Case history で確認しようとしたが、履歴が出てこない。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211196/c5d77620-ec3d-5c58-15ff-c7f4973b3543.png)

# 対応
画面右側 「View cases created in :」の部分を「English」から「 日本語」に変更する。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211196/ddb6db7c-9589-5853-e66a-1207ca7204d1.png)

# 原因
テストケース作成時のデフォルトが、「日本語」となっているが、履歴ページのデフォルトが「English」となっているため。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211196/f1be32b5-e469-b083-fbcd-b86f8a6f8efa.png)
エラー[14:30	Gradle sync failed: java.lang.NullPointerException (26 s 253 ms)](ReactNative, android)

# エラー

Android Studioを立ち上げた際に、下記のようなエラーが発生

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291139/1186623b-063a-0f23-d00a-0952ffe4c032.png)


```
14:30	Gradle sync failed: java.lang.NullPointerException (26 s 253 ms)
```

# 解決策
`Build -> Clean Project`を実行。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/291139/f352e990-2c91-5d8c-4887-a74ca8fdc483.png)

# 参考
[Gradle sync failed after upgrade to Android Studio 3.0 Beta 1](https://stackoverflow.com/a/45648280)
Blenderで3Dオブジェクトをインポートした時に真っ黒になった場合の対処法

単純な話です。
また付ければいいだけです。

Blenderのバージョンは2.79です。



最初のキューブがいらないので消しましょう
３Dオブジェクトの縁がオレンジになってたら選択中です。
今のうちです。
「Delete」ボタンを押しましょう。![スクリーンショット 2019-09-03 14.53.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376429/8ebf97f8-53dc-58a0-665d-9add3ff0b8a6.png)
※オレンジ色になってなかったら対象の３Dオブジェクトを「右クリック」してあげましょう

対象の３Dデータをインポートします。
![スクリーンショット 2019-09-03 14.43.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376429/92cf20bc-b283-d4b3-76a9-69be22e9ca6b.png)

見事に真っ黒ですね。この状態でお困りなはずです
![スクリーンショット 2019-09-03 14.57.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376429/24d57101-3736-a969-88a4-3ab03de87f30.png)

対象のオブジェクトを右クリックして選択しましょう。
選択すると右側のタブの中に球体のマークのタブがあるのでクリックするとこの画面になるはずです
マテリアルタブです。
画像を見た方が早いです。

![スクリーンショット 2019-09-03 15.00.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376429/3a58fe53-2392-b5d5-eecd-2d524b61f27b.png)

オレンジで囲った部分が今のところ操作するところです。
「＋」「－」ボタンがあるので「－」ボタンで消しましょう
マテリアルがなくなるので真っ黒じゃなくなるはずです。

「＋」ボタンを押してマテリアルを追加しましょう
次に「New」をクリックします
![スクリーンショット 2019-09-03 15.13.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376429/62a0ea4d-ab88-fd57-6040-eb95ff1d35fb.png)


新しいマテリアルが追加されました
![スクリーンショット 2019-09-03 15.14.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376429/9a013e7e-4722-40a5-4ba9-af429f4cc6ac.png)

テクスチャを開きます
「New」を押しましょう
![スクリーンショット 2019-09-03 15.18.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376429/69bdc3d8-a2f2-25df-2918-01a74c28719d.png)
「Open」を押して本来張り付いてたテクスチャを選択しましょう（ＵＶ展開されてるはずです）
![スクリーンショット 2019-09-03 15.19.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376429/90d19221-3b6d-7978-c39a-831f350a4092.png)

このような画面になってるはずです
![スクリーンショット 2019-09-03 15.22.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376429/96fa419e-8c1e-ea03-a997-303774b5f154.png)
マテリアルタブに戻りましょう
そうするとマテリアルにテクスチャが張り付いてます！すごい！
![スクリーンショット 2019-09-03 15.25.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376429/8f8a4f54-019d-358e-fc17-ea0dc2a9d4d2.png)

これでもう完成ですが、まだメタリックカナヅチ君（３Ｄモデルの名前）状態なのは見え方を変えていないからです。
見え方を変えましょう
今はソリッドですが、これをマテリアルにします。
![スクリーンショット 2019-09-03 15.28.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376429/eab89629-8b99-4488-f1f8-8f67c06721aa.png)

これで表示されるはずです
![スクリーンショット 2019-09-03 15.29.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376429/403479a6-c8d5-e8f8-6243-8e3c4c6889c7.png)

暗いのでライトを追加しましょう
マウスカーソルを３Ｄモデルが置いてある場所で「Shift＋A」を押します
後は画像のように選択してください

![スクリーンショット 2019-09-03 15.32.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376429/f5451544-7449-3796-0274-973e2d012865.png)


![スクリーンショット 2019-09-03 15.34.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376429/df568b8f-a8f0-5ac3-94e4-c3af9c7f94dc.png)


まじかる解決です
Ubuntu 16.04にTerraformをインストールする

# Terraformとは

Terraformはインフラの構築・変更、バージョン管理を安全かつ効率的に行うためのインフラストラクチャ定義ツールです。

HashiCorp社のOSSでTerraformを使うことで以下のことが実現できるとあります。

- インフラのコード化
- コードベースで管理することにより、インフラのバージョン管理が可能
- コード化することでシェアしたり、再利用しやすくなる

[公式ドキュメント](https://www.terraform.io/)にはユースケース等も含めていろいろ詳しく書かれています。

今回は公式サイトの手順に従って以下の環境にTerraformをインストールしたので、手順を紹介します。

# 環境
Ubuntu 16.04.6 LTS
Terraform v0.12.7

# Terraformのインストール

公式サイトに[インストール手順](https://learn.hashicorp.com/terraform/getting-started/install.html)が動画で紹介されているのでこちらに従ってインストールを進めていきます。

## インストール手順
公式サイトの[ダウンロードページ](https://www.terraform.io/downloads.html)からインストールするOSに合わせたダウンロードURLをコピーして、wgetでダウンロードします。

```
$ wget https://releases.hashicorp.com/terraform/0.12.7/terraform_0.12.7_linux_amd64.zip
```

ダウンロードしたzipファイルを解凍します

```
$ unzip terraform_0.12.7_linux_amd64.zip
```

作業ディレクトリに解凍したフォルダを移動

```
$ mkdir downloads
$ mv terraform downloads
```

`~/.profile`を編集して、末尾にPATHを追加する。

```~/.profile
export PATH="$PATH:~/downloads"
```

設定したPATHを有効にする

```
$ source ~/.profile
```

以下のコマンドを実行してバージョンが表示されればインストールは完了

```
$ terraform --version
````

公式サイトの動画の手順通りに実行したら簡単にインストールできました。

# tfenvのインストール

合わせてTerraformのバージョンマネージャのtfenvをインストールします。このツールを利用することで、Terraformのバージョンを簡単に切り替えることができます。

githubの[リポジトリ](https://github.com/tfutils/tfenv)にインストール手順が載っているので、こちらに従ってインストールを進めます。

## インストール手順

ソースコードをクローンする

```
$ git clone https://github.com/tfutils/tfenv.git ~/.tfenv
```

`~/.profile`のPATHに`~/.tfenv/bin`を追加する。

```~/.profile
export PATH="$PATH:＄HOME/.tfenv/bin"
```

設定したPATHを有効にする

```
$ source ~/.profile
```

以下のコマンドを実行してバージョンが表示されればインストールは完了

```
$ tfenv --version
````

これでUbuntuでTerraformを使う環境が整いました。
とあるCSSのインデックス

##loading
・[読み込み時間チェック](https://www.thinkwithgoogle.com/intl/ja-jp/feature/testmysite/)
・[コピペで簡単！シンプルなローディング画面](https://myscreate.com/loading-view/)
・[loaders.css](https://connoratherton.com/loaders)
・[pace](https://github.hubspot.com/pace/docs/welcome/)
・[Single Element CSS Spinners](https://projects.lukehaas.me/css-loaders/)
・[spinkit](https://tobiasahlin.com/spinkit/)
Macで crontab -e すると Permision denied と言われて保存できない問題

# 問題
macOSで `crontab -e` で設定編集しようとすると終了時に Permision denied と言われて設定できない。

# 解決策
「設定＞セキュリティとプライバシー＞プライバシー＞フルディスクアクセス」 にターミナルアプリ(iTerm2とかAlacritty)を追加すれば解決します。

# 注意点
~~フルディスクアクセスの許可を与えたターミナルソフトを使っていても、tmux の中からだとやっぱり駄目なので、その場合は一度 detouch して tmux から出てから `crontab -e` する必要があります。~~

1. 先にtmuxで作業してる
2. ターミナルに許可を追加して再起動 ≒`tmux detouch`
3. 許可済みのターミナル上で `tmux atouch`
4. `crontab -e` が失敗するまま！？

↑こういうアホな手順で失敗してただけだったと後で気づいた…。フルディスクアクセスの許可が無いターミナルから起動したtmuxは権限を持ってないままだから、その頃から生きたままの tmux のプロセスにアタッチしたら、権限付きのターミナル上から操作してようがそりゃ失敗するわ。
VS Code の quickFix をカスタマイズする

# quickFixを使った自動インポートの挙動を変更する
VSCodeでTypescriptを書く際、インポートすべきファイルが見つからない場合、
quickFixを使って自動インポートすることがある。

Nest.jsを使う場合、インポートするファイルは相対パスで指定しなければいけないが、
VSCodeの自動インポートは絶対パスで指定する挙動になっている。

以下の設定をsetting.jsonに追記し、自動インポート時に相対パスになるよう指定する。

```
"typescript.preferences.importModuleSpecifier": "relative",
```

戻す場合は以下

```
"typescript.preferences.importModuleSpecifier": "non-relative",
```

# ショートカット
ちなみにカーソルのあたっている部分を素早くquickFixしたい場合は以下コマンドを使うと良い。（Mac）

```
Command + .
```
TableViewCell のIndexPathと値抽出

###はじめに
TableViewCellが複数だと、どのCellのどのボタンが押されたのか判断が付かない

→CellのIndexPathが取得できれば可能

```tableviewcell.swift

 // セルに値をセットする
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell  {
        // tableCell の ID で UITableViewCell のインスタンスを生成
        let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath)
        
// ボタンにタグを設定し、どのセルのボタンか判断する
        let button = cell.viewWithTag(1) as! UIButton 
        button.addTarget(self, action: #selector(buttonPush(_:)), for: .touchUpInside)
        button.tag = indexPath.row //タグを設定

        print(indexPath.section) //分けない限り0固定

        return cell
       }

```

```buttonPush.swift
@IBAction func buttonPush(_ sender: UIButton) {
     //Int型からIndexPath型にキャスト
     let indexPath = IndexPath(row: sender.tag, section: 0)
        //indexPathでセルを指定可能
        let cell = self.checkSheetTableView.cellForRow(at: indexPath)

        // 作成したセルのタグ(4)のviewから値を取り出す
        let countView = cell?.viewWithTag(4) as! CountView 
        print(countView.count) //Cell内のcountの値取得
      }

```
Homebrewのインストールで「/usr/local/Homebrew/.git: Permission denied Failed during: git init -q sudo: /private/etc/sudoers.d is owned by uid 501, should be 0」のエラー対応


###/usr/local/Homebrew/.git: Permission denied 
###Failed during: git init -q sudo: /private/etc/sudoers.d is owned by uid 501, should be 0


以下のコマンドを実行してhomebrewのインストールを試みる。

```
sudo chown -R `whoami` /usr/local
```
```
brew --version
```
インストール出来ました。
supervisorで管理しているqueueがローカル以外でうまく動かなかった時の対処法【Laravel】

# 起きたこと

ローカルでは正しくコード反映後の内容で動いていた、バックグラウンドメール送信処理がテスト及び本番か環境で謎のエラーが出まくる

```
[2019-09-03 13:22:49] develop.ERROR: Call to a member function insert() on null {"exception":"[object] (Symfony\\Co
mponent\\Debug\\Exception\\FatalThrowableError(code: 0): Call to a member function insert() on null at /usr/share/n
ginx/working-dir/app/Jobs/SendMail.php:80)
```

そもそも80行目なんてないし、insertも見当たらない

```
[2019-09-03 11:20:38] production.ERROR: /usr/share/nginx/working-dir/app/Jobs/SendMail.php92 send_mai
l_error: Invalid view.
```

もちろん92行目なんてないしviewも呼んでない

# 原因

定かではないが、failedメソッドを自分で作成→そのなかの処理変更がうまく反映されていなかったぽい。

# 対処法

```
$ sudo systemctl restart supervisord
```

これだけで最新の内容になる。

superovisorがコード反映後の内容で動いていた、バックグラウンドメール送信処理がテスト及び本番か環境で謎のエラーが出まくる

```
[2019-09-03 13:22:49] develop.ERROR: Call to a member function insert() on null {"exception":"[object] (Symfony\\Co
mponent\\Debug\\Exception\\FatalThrowableError(code: 0): Call to a member function insert() on null at /usr/share/n
ginx/working-dir/app/Jobs/SendMail.php:80)
```

そもそも80行目なんてないし、insertも見当たらない

```
[2019-09-03 11:20:38] production.ERROR: /usr/share/nginx/working-dir/app/Jobs/SendMail.php92 send_mai
l_error: Invalid view.
```

もちろん92行目なんてないしviewも呼んでない

# 原因

定かではないが、failedメソッドを自分で作成→そのなかの処理変更がうまく反映されていなかったぽい。

# 対処法

```
$ sudo systemctl restart supervisord
```

これで正しく動くようになる。

superovisorがLaravelのファイルの一部分をキャッシュとして保持してしまうのか。。。？
何か不備、指摘、なぜこうなるのかわかる方がいたらコメントいただけますと幸いです。
Imlib2をMacで使うときに遭遇したエラーと対処

### imlib2を使いたい
ImageMagcikの代わりとして一時期はやった。

- 参考
  - [本当はもっと速いImlib2: Imlib2でもImageMagickと同じ仕組みでサムネイル画像生成を速くする方法](http://blog.livedoor.jp/techblog/archives/65467928.html)
  - [Imlib2でImageMagickより3倍高速かつ美しいサムネイル画像の生成 - 昼メシ物語](https://blog.mirakui.com/entry/20100724/imlib2)

今回は環境はLinuxじゃなくてMacで。rubyで使いたい。

### bundle installしたい
`Imlib2-Ruby 0.5.2` を使いたいとき。gemfileは以下。

```
gem 'Imlib2-Ruby', git: 'https://github.com/pepabo/imlib2-ruby.git'
```

本家にない。
http://pablotron.org/files/gems/imlib2-ruby-0.5.2.gem

`Imlib2` を使いたいと思ったときにforkしているこちらのgithubから参照する形をとっている。

#### imlib2がないとエラー
`bundle install` をしていたときに下記エラーでつまずいた。

```
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.
```

imlib2が必要ということだと判断。

環境はMac。ruby2.5.3(rbenv）
実行時の詳細なエラーは下記。

```
Using Imlib2-Ruby 0.5.2 from https://github.com/pepabo/imlib2-ruby.git (at master@47c04bc)
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /Users/hoge/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/bundler/gems/imlib2-ruby-47c04bce88f1
/Users/hoge/.rbenv/versions/2.5.3/bin/ruby -r ./siteconf20190903-6773-1sradmq.rb extconf.rb
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

Provided configuration options:
        --with-opt-dir
        --without-opt-dir
        --with-opt-include
        --without-opt-include=${opt-dir}/include
        --with-opt-lib
        --without-opt-lib=${opt-dir}/lib
        --with-make-prog
        --without-make-prog
        --srcdir=.
        --curdir
        --ruby=/Users/hoge/.rbenv/versions/2.5.3/bin/$(RUBY_BASE_NAME)
        --with-imlib2-config
        --without-imlib2-config
extconf.rb:5:in ``': No such file or directory - imlib2-config (Errno::ENOENT)
        from extconf.rb:5:in `<main>'

extconf failed, exit code 1

Gem files will remain installed in /Users/hoge/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/bundler/gems/imlib2-ruby-47c04bce88f1 for inspection.
Results logged to
/Users/hoge/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/bundler/gems/extensions/x86_64-darwin-18/2.5.0-static/imlib2-ruby-47c04bce88f1/gem_make.out

An error occurred while installing Imlib2-Ruby (0.5.2), and Bundler cannot continue.


In Gemfile:
  Imlib2-Ruby
```


#### Imlib2を使うとこができる環境
imlib2が必要ということだと判断。
その上で下記操作が必要だった。

```
brew cask install xquartz
brew install imlib2
```

homebrewで管理していたのでimlib2をいれたかった。
imlib2-develはなく、imlib2も xquartzを必要としていた。

これで解決。
Rubyでcurry

なんかよくわからないのですが、ある日突然カリー化に興味を持ってしまいました🍛

### カリー化とは
_カリー化 (currying, カリー化された=curried) とは、複数の引数をとる関数を、引数が「もとの関数の最初の引数」で戻り値が「もとの関数の残りの引数を取り結果を返す関数」であるような関数にすること（あるいはその関数のこと）である。_
[カリー化 - Wikipedia](https://ja.wikipedia.org/wiki/カリー化)より

引数が複数個あるのメソッドを「1引数のメソッドを返すメソッド」に変換してくれます。

```
def magic_spice(a, b, c)
  a + b + c
end

> magic_spice(1, 2, 3)
=> 6
> magic_spice(1, 2)
ArgumentError: wrong number of arguments (given 2, expected 3)

```
引数が３つのメソッドに対して、引数を2つしか渡さないとこうなるのは当たり前ですよね。

ではこのメソッドをカリー化してみます。
Rubyでカリー化する場合は Method#curry を使います。

### [instance method Method#curry](https://docs.ruby-lang.org/ja/latest/method/Method/i/curry.html)
_十分な数の引数が与 えられると、元の Proc に引数を渡し て実行し、結果を返します。引数 の個数が足りないときは、部分適用したカリー化 Proc を返します。_

```
# まずはprocに。
proc_magic_spice = self.method(:magic_spice).curry
=> #<Proc:0x00007fb642009ad8 (lambda)>

proc1 = proc_magic_spice.call(1)
=> #<Proc:0x00007fb645083858 (lambda)>

proc2 = proc1.call(2)
=> #<Proc:0x00007fb64300f090 (lambda)>

# ここでmagic_spiceメソッドの3つめの引数を渡すと…
proc2.call(3)
=> 6

```

わーい！できたー😄

ただ、Rubyでカリー化して嬉しい時ってどんな時だろう・・・
簡単なTodoアプリ作ってみた-勉強のメモ

簡単(すぎる)Todoアプリの作成過程をまとめて。

#目的
簡単なTodoアプリを作る

#コード

```HTML:HTML
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="style.css">
    <script src="script.js"></script>
    <link href="https://fonts.googleapis.com/css?family=M+PLUS+Rounded+1c&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css">
    <title>Todo App</title>
</head>
<body>

    <section>

        <h1>Todo List</h1>

        <div class="todo_add">
            <div id="add_btn"><i class="fas fa-plus"></i></div>
            <input type="text" id="input_add" placeholder="追加する">
        </div>

        <ul id="list_todo"></ul>

    </section>
    
</body>
</html>
```

```CSS:CSS
body{
    font-family: 'M PLUS Rounded 1c', sans-serif;
}

h1{
    text-align: center;
    border-bottom: 3px solid #38b1f7;
    color: #38b1f7;
    font-size: 40px;
    letter-spacing: 10px;
    padding-bottom: 25px;
    
}

.todo_add{
    display: flex;
    margin-left: 500px;
}

#add_btn{
    background-color: #38b1f7;
    border-radius: 40px;
    width: 40px;
    height: 40px;
    color: #ffffff;
    font-size: 20px;
    text-align: center;
    line-height: 40px;
   margin-right: 20px;

}

#input_add{
    border-radius: 10px;
    border: 1px solid #6b635a;
    width: 240px;

}

.todo_li{
    
    font-size: 20px;
    padding: 10px 0;

}
```


```JavaScript:JavaScript

const add = document.getElementById('add_btn');

    add.addEventListener("click", function() {

      const li = document.createElement('li');

      document.getElementById('list_todo').appendChild(li);

      li.classList.add('todo_li');

      li.textContent = `${input_add.value}`;

    })

```

#コードの解説

```HTML
<ul id="list_todo"></ul>

```

```JavaScript:JavaScript
const li = document.createElement('li');

document.getElementById('list_todo').appendChild(li);
```
`list_todo`に`document.createElement`で`li`を生成する。

```JavaScript:JavaScript
li.classList.add('todo_li');
```
`classList`で生成した`li`にクラスを追加する。


```JavaScript:JavaScript
li.textContent = `${input_add.value}`;
```

`textContent`で`value`で入力された文字を`todo_li`に表示する。


#感想
(あまりにも物足りなさすぎるので削除機能とかタスクをジャンルごとに分ける機能とかつけたい…)
[M5StickC]  USBモードへの切替方法（How to switch to USB mode）※2021.08.25 Update

**※2021.08.25 ファームウェア v1.5.x 以降の切替方法追記**

ようやく [M5StickC](https://www.switch-science.com/catalog/5517/) を入手することが出来たので、[M5Flow](http://flow.m5stack.com/) というクラウドサービスを利用してイジってみました。（この辺りは[**クイックスタート**](https://docs.m5stack.com/#/ja/quick_start/m5stickc/m5stickc_quick_start)に従いました。）
 
あれやこれや遊んでいる内に「これってローカル環境で開発できない？」という疑問に駆られ、色々と調べてみたところ、**USBモード**に切り替えることで、ローカルPC（UIFlow-Desktop-IDE、VSCode等）からアクセスできることが解りました。（デフォルトでは**Cloudモード**になっていました）

この**USBモード**への切替方法が詳細に書かれているドキュメントが見当たらないっぽいので、以下に書き残しておきます。

# USBモードの切替方法（How to switch to USB mode）
## 本体のボタン位置と名称（Buttons location and name）

![m5stickc_button.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94476/b671e312-453a-fd88-e2de-a3a7bb3652e2.jpeg)


## 切替手順（Switching procedure）UIFlow <= v1.4.x


1. [M5Burner](https://mag.switch-science.com/2018/08/30/m5burner_try/) を使って最新バージョンのUIFlowファームウェアを書き込み（Flash the latest stable version of UIFlow firmware using M5Burner.）<br />※執筆時点の最新バージョンは v1.3.2（The latest version at the time of posting is v1.3.2）

2. **パワースイッチ**を6秒以上長押しして電源OFF（Press and hold the power switch for more than 6 seconds to turn off the power.）

3. **ボタンA**を押しながら**パワースイッチ**を押して電源ON（While pressing button A, press the power switch to turn on the power.）

4. **パワースイッチ**、**ボタンA**を離す（Release the power switch and button A.）

5. **ボタンB** を2回押す（Press button B twice.）<br />![m5stickc_usb_1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94476/b99148ad-c216-6dc2-f1b6-0f93a39dc2e1.jpeg)

6. **ボタンA** を押す（Press button A.）<br />![m5stickc_usb_2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94476/9ddaec80-1a46-ad88-f365-2f1a54f85fc2.jpeg)

7. **ボタンB** を押して`USB Mode` を選択し、**ボタンA** を押す（Press button B to select **USB Mode** and press button A.）<br />![m5stickc_usb_3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94476/7c676551-2622-32d4-7c8a-bdefa84b0de8.jpeg)

8. `APIKEY` が表示されればUSBモードへの変更完了（APIKEY is displayed and the change to USB mode is completed.）<br />![m5stickc_usb_4.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94476/6db4297f-9ba3-eb5d-2d83-4af230e96ac6.jpeg)

## 切替手順（Switching procedure）UIFlow >= v1.5.x

1. **パワーボタン**を押してデバイスを再起動する（Press the power button to restart the device）
2. UIFlow ロゴが表示されている間に**ボタンB**を1回押す（Press Button B once while the UIFlow logo is displayed）<br />![m5stickc_usb_mode_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94476/298ebae4-3abd-af60-4bd5-9301a092f373.png)
3. USBモードが選択されるので少し待つ（USB mode will be selected, so wait for a while）<br />![m5stickc_usb_mode_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94476/9a76235e-5f21-b71e-e57e-306aa121f852.png)
4. USBモードに切り替わる（Switch to USB mode）<br />![m5stickc_usb_mode_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94476/e427750b-96de-9d00-9b71-9d480df90f06.png)
【C#】正規表現で抽出した結果に対してLinqを使う

正規表現を使って条件に一致する文字を抽出して
その結果を処理したい時にそのままだとLinqが使えなかったのでメモ。

任意の文字列から16進数として有効な文字を2文字ずつ取得したい場合のサンプル。

```C#:16進文字列を抽出
// 抽出結果を格納したい
var result = new List<string>();

// 16進数文字列を2文字ずつ取得
var matches = Regex.Matches("0123abcdXyx", "[0-9a-fA-F]{2}");

// MatchCollectionクラスはIEnumerableでIEnumerable<T>じゃないので
// そのままだとLinqが使えないのでIEnumerable<Match>にキャストしてから使う。
result.AddRange(matches.Cast<Match>().Select(m => m.Value));

// 結果は『01』『23』『ab』『cd』

```
A5:SQL Mk-2 よく使うショートカットキー 


コメントアウト <b>Ctrl + K</b>

アンコメント <b>Ctrl + Shift + K</b>

全選択 <b>Ctrl + A</b>

コードの整形 <b>Ctrl + Q</b>

よく使うものを随時更新していきます
JestがJasmine2互換な理由

[Jestのリポジトリ](https://github.com/facebook/jest/tree/c588c18595000d68c98bf8c72d003ff8b3674124/packages/jest-jasmine2)を見ていて `jest-jasmine2` というパッケージが含まれていて気になったので調べてみました. 

`jest-jasmine2`はJasmine2と互換があるパッケージでJestへの移行がスムーズになります.

どうやら、以下の背景でJasmin2互換が残っている様です.

1. Facebookのいくつかのプロジェクトでは`Jasmine1`でテストが書かれていた.
2. `Jasmine1`から`Jasmine2`に書き直した.
3. 同じ時期か書き直した後にFacebookのの人ではなく外部の人(今はAWSの人っぽい)から[Optional jasmine 2 support #330](https://github.com/facebook/jest/pull/330)のPRを受け取って取り込んだ.

テストのフレームワークを置き換えるとなると、既存のテストを維持しながらの移行なので一見大変そうですが、こうしてみるとシームレスな移行ができてた感じす.
もし自分が担当するプロジェクトのフレームワークのリプレースが必要になったら一つの手段として、真似たいと思う.

### 元記事

- [Jasmine and Test Assertion Improvements : Jest 11.0 Jest](https://jestjs.io/blog/2016/04/12/jest-11.html#jasmine-and-test-assertion-improvements)
学習コンテンツ

# 背景
新卒のころの学習リソースは、書籍かネット上でしかなく、今のように、Qiitaやブログでの配信による情報がごく僅かでしかなかった。
今では、Udemyさんなどの学習環境だったり、外部勉強会やブログの情報、SNSが盛んになり、多くの方々の知見やノウハウが情報として出てくるようになった。

参考になる情報や学習コンテンツを整理していく。

# 有料コンテンツ（一部無料もあり)
## Udemy
https://www.udemy.com/ja/

- 自己啓発や、プログラミング、ITインフラetc さまざまな学習コンテンツを配信させている。
- たまにセールで90% off になる期間があり、学習したいときに学習できる

## schoo
https://schoo.jp/

- 月額会費制(プレミアム会員)、無料（オンタイム無料で動画視聴可能）
- 学びたい情報があれば、該当する時間に視聴することは可能
- 過去の動画を観たい場合は、プレミアム会員になる必要があり。

# 無料コンテンツ
## Progate (オンラインプログラミング学習サービス)
https://prog-8.com/

# 各コミュニティ、勉強会イベント
## JAWS-UG
https://jaws-ug.jp/

- 各拠点での支部や、専門支部に分かれている。
- 年に数回大きなイベントを開催させている。

## エンジニアの登壇を応援する会
https://portal.engineers-lt.info/

- その名もエンジニアの登壇を応援するコミュニティ
- slack でコミュニケーションを取ったり、時折、イベントで日本酒LTがあるとかないとか。
- 登壇を応援している会なので、初心者大歓迎とのこと。

## connpass
https://connpass.com/

- 各勉強会のイベントなどの募集が行われている

## Doorkeeper
https://www.doorkeeper.jp/

- 各勉強会のイベントなどの募集が行われている
社内勉強会 機械学習入門（7.アヤメを分類してみよう）

今日のテーマは、「アヤメを分類する機械学習プログラム」です。（これも有名な題材ですね。）

# 題材
アヤメを分類するプログラムです。
アヤメの品種を分類するのに関係しているデータがGitHubに公開されているので、このデータ（csvファイル）をダウンロードして使いましょう。

[アヤメデータのCSVデータ](https://raw.githubusercontent.com/pandas-dev/pandas/master/pandas/tests/data/iris.csv)
↑をクリックし、ブラウザに表示されたCSVデータを「右クリック」して保存してください。
ファイル名は、<b>「iris.csv」とし、C:\ml-introの直下に保存</b> してください。

# データを見てみよう

ヤマメの分類に関係する特徴が数値化されていますね。
![2019-09-03_13h02_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101846/bfdc773b-32d4-9965-503d-d726555c07ef.png)

<b>＜アヤメデータの内容＞</b>

|カラム名 | 説明 |
|:--|:--|
|SepalLength| がく片の長さ |
|SepalWidth| がく片の幅 |
|PetalLength| 花びらの長さ|
|PetalWidth| 花びらの幅 |
|Name | アヤメの品種名|

分類に関係する <b>特徴</b> は、「がく片の長さ」「がく片の幅」「花びらの長さ」「花びらの幅」の４つありますね。
「アヤメの品種名」は、<b>正解ラベル</b>です。

アヤメの品種としては、「Iris-Setosa」「Iris-Versicolor」「Iris-Virginica」の３つに分類されるそうです。
![2019-09-03_13h17_41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101846/ecbb5b8f-ec3a-5a09-0312-6110ce9db500.png)
（画像は、https://www.datacamp.com/community/tutorials/machine-learning-in-r より引用）

では、未知のデータに対し、３つのうちのどれかに分類する機械学習プログラムを書いていきましょう。

# ゴールまでのステップ

1. 「iris.csv」を読み込む。
2. 読み込んだアヤメのCSVデータには、正解ラベルが付いているので分離する。
3. 全データのうち70%を訓練用データに、30%を判定用データに分ける。
4. 訓練用データを使って学習させる。
5. 判定用データ（未知のデータという想定）を与え、正しく分類できたか？を評価する。

学習に使うアルゴリズムは、サポートベクターマシンを使います。
アルゴリズムの選定については、↓の情報がわかりやすと思いました。
[参考情報]https://engineers.weddingpark.co.jp/?p=872

# ここからが本題！　機械学習プログラムを書いてみよう

先に「Pandas」という Pythonでデータ分析を効率的に行うためのライブラリ をインストールしましょう。
（データの読み込みや統計量の表示、グラフ化などが楽にできる。）
```$ pip install pandas```

必要なライブラリをインポート

```python
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
```

【Step1】アヤメデータの読み込み

```python
# 【Step1】アヤメデータの読み込み
iris_data = pd.read_csv("iris.csv", encoding="utf-8")
```

【Step2】読み込んだアヤメデータには、正解ラベルが付いているので分離する

```python
# 【Step2】読み込んだアヤメデータには、正解ラベルが付いているので分離する
y = iris_data.loc[:,"Name"]
x = iris_data.loc[:,["SepalLength","SepalWidth","PetalLength","PetalWidth"]]
```

【Step3】全データのうち70%を訓練用データに、30%を判定用データに分ける。

```python
# 【Step3】全データのうち70%を訓練用データに、30%を判定用データに分ける。
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.3, train_size = 0.7, shuffle = True)
```

【Step4】学習する（アルゴリズムは、サポートベクターマシン（クラス分類）の１つであるSVCを使う。）

```python
# 【Step4】学習する（アルゴリズムは、サポートベクターマシン（クラス分類）の１つであるSVCを使う。）
clf = SVC()
clf.fit(x_train, y_train)
```

【Step5】評価する

```python
# 【Step5】評価する
y_pred = clf.predict(x_test)
print("正解率 = " , accuracy_score(y_test, y_pred))
```
![2019-09-03_14h06_44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101846/6ed629ca-decb-3654-c7df-55afaede8a66.png)

正解率＝約96%！　まあまあでしょうか、、、

# まとめ

今回も、前回に引き続き、「機械学習の雰囲気」を感じてもらいました。
徐々に <b>機械学習プログラムの流れ</b> がつかめてきたのではないでしょうか？
次回は、気象データをもとにした”予測”にチャレンジしてみたいと思います。
情報処理試験でのセキュリティ問題(DNSキャッシュポイズニング編)

## 情報処理試験でのセキュリティ問題

### ターゲット
経験の浅いエンジニアおよび、情報処理試験に挑戦しようとしている方、ITに関してプログラミング以外も知識を増やしたい方。

### まえがき
情報処理試験でのセキュリティ問題は午後の必須化を始め、重点の置かれ方が変わってきています。結構前からっちゃ前からなんですけど。
そのため、情報処理に出てくる午前問題のセキュリティについてをまとめていきます。どれも重要なんで、紹介の順番は順不同です。

なんで情報処理試験についての記事を書くかというのは私の別記事参照です。
[「ただのプログラマ」で終わらないためには](https://qiita.com/sorabin/items/3cae75d4428a96ccbbd3)

私の知識も完璧ではありません。学習者や私のためにもなりますので、間違いがあればご指摘ください。攻撃的なコメントはお控えください。泣きます。

### DNSキャッシュポイズニング攻撃
平成３０年の春秋両方に出題されていた（気がする）頻出の問題です。名前もよく耳にしますね。
DNSとはなにか？については厳密にはセキュリティ問題とは異なるため、別にします。

さて、本題です。**DNSキャッシュポイズニング攻撃**は、その名の通り、**DNSキャッシュサーバに毒で冒しまっせ**って攻撃です。
DNSサーバにも、毎回問い合わせする時間を短縮させるためにDNSキャッシュサーバがあります。そのキャッシュサーバにももちろんDNS情報があるわけですが、この攻撃はDNSキャッシュサーバに偽のDNS情報をキャッシュとして登録させることで、利用者を偽のWebサイトに誘導する攻撃です。

基本情報ではない知識ですが、DNSの名前解決はその性質によって**再帰的な問合せ**と**反復(非再帰的)問合せ**に区別されます。
名前は「なんじゃそりゃ」って思いますが、どんな問い合わせをしているか、という内容はいたって簡単です。

#### 再帰的問合せ
クライアントPCから名前解決要求を受けたDNSキャッシュサーバが他のDNSサーバに代理で問合せを行い、最終的な結果を返す必要のある問合せのこと

このクライアントPCをResolver(**リゾルバ**)と言います。

キャッシュサーバは、この問い合わせ内容を自身にキャッシュとして残しておき、次回以降の問い合わせに素早い対応をすることが可能になります。
このキャッシュが毒に侵されてしまいます。

#### 反復(非再帰的)問合せ
DNSキャッシュサーバが、名前を解決できるまで繰り返し他のDNSサーバに行う問合せのこと

#### 攻撃内容

１回目

```
リゾルバ「なんちゃら.comのIPアドレス教えて！」
DNSキャッシュサーバ「ほいきた。DNSサーバーに聞いてくるわ」
各種DNSサーバ「a.b.c.d だよ」
DNSキャッシュサーバ「a.b.c.dだってさ！(次回用に自分に書き込んどこ)」
```

２回目(正常)

```
リゾルバ「なんちゃら.comのIPアドレス教えて！」
DNSキャッシュサーバ「おっ、待ってました、前と同じだね！a.b.c.dだよ！」(1回目より早い応答が可能)
```

３回目(DNSキャッシュポイズニングに攻撃された状態)

```
悪いやつ「IP変えてやろ」

リゾルバ「なんちゃら.comのIPアドレス教えて！」
DNSキャッシュサーバ「おっ、待ってました、前と同じだね！o.p.q.rだよ！」(書き換えられたIPを返却してしまう)

リゾルバ「変なページじゃんか！！！」
```

という具合です。

この攻撃の具体的な動きを以下に記します。

```
悪いリゾルバ(攻撃者)「なあなあ、俺にもなんちゃら.comのIPアドレス教えて」( 偽の再帰的問合せ )
DNSキャッシュサーバ「ほいきた。DNSサーバーに聞いてくるわ」
各種DNSサーバ「a.b.c.d だy
悪いリゾルバ(攻撃者)「いやいや o.p.q.r だよ＾＾こっちがただしいよ＾＾」
DNSキャッシュサーバ「o.p.q.rだってさ！(次回用に自分に書き込んどこ)」

```
とまあこんな具合にキャッシュサーバに偽の情報を書き込ませて、正しい情報を破棄させます。

#### 対策

キャッシュサーバへの再帰的問合せの役割は、内部ネットワークから外部ネットワークに接続する際の名前解決です。原則として外部からの再帰的な問合せに応じる必要はないんですよね。会社の出入り口のようなもので、内部の方のリクエストにのみ応じていればいいんです。
DNSキャッシュポイズニングは、外部からの（見ず知らずの人からの）問い合わせに応えてしまっていることがことの発端なので、**リクエストを受け付けるホストを、内部ネットワークだけに限定すること**が対策になります。

また、DNSキャッシュサーバは、DNSサーバからの**ポート番号、IPアドレス、トランザクションID**が自分の知っている情報と一致して初めて「DNSの情報だな、よし、キャッシュに登録しよう」と認めます。則ち、DNSキャッシュポイズニングが成立するためには**ポート番号、トランザクションID**など、必要な情報が推測しやすいようなものになっていると、正しい応答だ、と誤認させる原因にもなります。

###最後に

会話形式にしたのが若干滑ってしまった感は否めません。若干後悔しています。

本記事のような内容は、プログラムとは直接関係ないけどいいのかな、って不安になったので運営に問い合わせたところ、「技術者の役に立てばいいですよ（要約）」という返答が来たので引き続きまとめていきたいです。

交流などはぜひTwitterからどうぞです～！

ご意見ご感想、コメントでもなんでもお待ちしております。

### 改訂履歴
(2019/09/03) 作成 DNSキャッシュポイズニング攻撃について
PowerShellでRSSフィードを取得

新しい言語を覚える際は、自分が他の言語で書いたツールを移植してみることから始めることにしている。

そんなわけで、[前にPythonで書いたRSSリーダ（マルチコア対応）](https://qiita.com/usop4/items/599aabd53f8a89251749)を書き換えてみた。本当はマルチコアで動かしたかったが、MacOSで動くPowerShellではworkflowが実装されてないので、とりあえずシングルスレッドで動かす。

```powershell
#!/usr/local/bin/pwsh 
$regex = Read-Host "keyword"

$urls =@(
    'https://gizmodo.com/rss',
    'https://www.cnet.com/rss/all/',
    'https://techcrunch.com/feed/'
)

foreach ( $url in $urls ){
    $f = [XML](Invoke-WebRequest $url)
    foreach( $item in $f.rss.channel.item ) {
        if ($item.description -match $regex ){
            Write-Host $item.title
            Write-Host $item.link
            Write-Host ""
        }
    }
}
```

お気付きの通り、かなりシンプル。特にXMLが信じられないほど楽だ。
全文検索的な曖昧な検索をサーバー無し、javascriptだけで実行する方法

![Fuse_js_-_JavaScript_fuzzy-search_library.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16757/43ae3020-a9bc-4186-36a0-ca9593eafd85.png)

# Fuse.js
https://fusejs.io/
これを使う。
Live Demoが用意されているのでオプションの調整もすぐ分かる。

Examplesを見るとより分かりやすい。
![Fuse_js_-_JavaScript_fuzzy-search_library-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16757/b63d4fe5-7393-7947-6e7e-e38aaaebf4a5.png)