OmniAICreator/Qiita-1.07M huggingface dataset:
macOSで.exeを開こう

# はじめに
この記事に辿り着いたということは、少なくともあなたはMacでWindows向けのアプリケーションを開く何らかの方法を探しているのだろう。細かいことは置いておいて結論を述べると、macOSで.exeファイルを開く方法は3通りある。

　
<b>・ Wineと呼ばれるアプリケーションを利用して無理やり開く方法</b>

<b>・ VirtualBoxなどを利用してWindows仮想環境を構築する方法</b>

<b>・ BootCampを利用してWindows環境を構築する方法</b>

　

## 1-1. Wineを利用する
Wineを利用して.exeを開く方法が最も簡単で有名だと思われる。Wineは、macOS上で.exeをダブルクリックするだけで、あたかもMac向けに作られたアプリであるかのように.exeを動作させることができるソフトである。

### Wineを使うことのメリット
・アプリの起動が簡単
・ストレージをあまり占有しない
・軽いため、低スペMacでも動作可
・Macの再起動が必要ない

### Wineを使うことのデメリット
・開けない.exeファイルが存在する
・UIやフォントが汚い

## 1-2. Wineの導入

### 前提ソフトのインストール
Wineの動作に必要な前提ソフトである[XQuartz](https://www.xquartz.org/)をインストールしておこう。

### Wine本体をインストール
WineといってもWineやWineBottler、PlayOnMacなど種類は様々である。ここでは各Wineの紹介は省く。各自でお好みのものを導入するとよい。



## 2-1. 仮想環境を利用する
VirtualBoxは、macOS上にWindowsの仮想環境を構築できるソフトだ。
ただし、この手段を選んだ場合には、Mac上でOSを同時に2つ動かすことで高負荷がかかり、Intel Mac(特にノート)ではほとんど使い物にならない。
以上の理由からIntel MacにおけるWindows仮想環境の構築はお勧めできない。
あなたが使用しているMacがIntelプロセッサを搭載しているなら特別な事情がない限り、後述するBootCampを使ったデュアルブート環境の構築をお奨めする。

### 仮想環境を使うことのメリット</b>
・Mac上でWindowsを動かすことができる
・再起動が必要ない

### 仮想環境を使うことのデメリット</b>
・macOS上でWindowsを起動するためCPUやメモリに負荷がかかり、Mac自体の動作を遅くする


## 2-2. VirtualBoxの導入
仮想環境を構築するためのMac向けソフトは多数存在するが、今回はVirtualBoxを導入する場合の手順を解説する。
<font size=4, color=red>【！】Apple Silicon搭載Macを使っている場合はVirtualBoxの代わりにParallelsを利用しよう。執筆時点ではVirtualBoxはApple Siliconに対応していない。


### VirtualBoxのダウンロード
以下のサイトよりダウンロードを行う。もちろん、各自で用意したソフトを利用しても構わない。


[VirtualBoxのダウンロード](https://www.virtualbox.org)

### Windowsディスクイメージのダウンロード</b>
Windows環境を構築するには、仮想環境構築ソフト以外にWindowsのディスクイメージファイルが必要だ。
下記リンクのページではWindows10のディスクイメージファイルが手に入る。


[Windows10.isoのダウンロード](https://www.microsoft.com/ja-jp/software-download/windows10ISO)


### VirtualBoxをインストール</b>
インストール後、起動し、「新規」をクリック。
この後、メモリーやストレージなどの割り当て設定を行う。
![スクリーンショット 2020-12-30 12.53.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374371/cd52a3f8-c80f-d35c-2ff7-074eaf25b643.png)


### 起動設定
OSの起動設定で、手順2でダウンロードした.iso形式のファイルを指定

### Windowsのセットアップ
必要に応じてプロダクトキーの購入が必要となる。

## 3-1. BootCampを利用する
<font size=4, color=red>【！】Apple Silicon搭載MacではBootCampはサポート対象外となる。これらのMacでWindows環境を構築したい場合は、前述の仮想環境を構築する方法をお勧めする。

Wineでもアプリを開くことができず、Macのスペックが低い場合でも、ストレージにある程度の空き容量があれば「BootCamp」を使用してWindows環境を構築することができる。
BootCampを利用した場合、WindowsとmacOSは一度にどちらかしか起動せず、OSをの多重起動を防ぐことができるため、仮想環境を構築する方法よりも軽く快適にWindowsを利用することができる。
仮想環境との主な違いは「Macにかかる負荷」と「再起動が必要かどうか」の2つ。

◆ BootCampでは、Windows11をサポートしていない。

◆ 2020/01/26現在、macOS10.15.2 Catalinaに付属するBootCampでは、Windows8.1もしくはWindows10のみのサポートとなり、これ以前のisoファイルを使用することはできない。

◆ もしWindows7をBootCampで使いたい場合は、macOS10.13(HighSierra)以前を搭載したMacを用意しよう。

[BootCampの導入方法についての記事はこちら](https://qiita.com/Nether_2046/items/b8a38dcaa4e5af7ad3a3)


# 追記情報
|更新日|更新内容|
|---|---|
|2023/01/12 |記事を一部修正
|2022/04/08 |記事を一部修正
|2021/06/25 |記事を一部修正
|2021/04/04 |WineにおけるmacOS Big Surに関する記述を訂正
|2020/12/30 |記事を一部修正
|2020/1/26 |記事を一部修正
|2020/1/25 |BootCampについての記述を追記
DokuWiki で ImgPaste Plugin が Windows で動かない

# DokuWiki って PHP か
自分はWindowsなのでIISで動くでしょ、と思いながら調べたら、ちゃんとDokuWikiのヘルプにIISで動かす場合が書いてあった。

[IIS と Dokuwiki](https://www.dokuwiki.org/ja:install:iis)

# よし、いざ動かすぞ
画像をそのままコピーしたいから ImgPaste プラグインを入れておくぞ。

[ImgPaste プラグインはこちら](https://www.dokuwiki.org/plugin:imgpaste)

とまぁここまではよかった。

# ImgPaste が謎のエラーで動かない！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/136398/00c5e5e1-52e8-dd20-ae7d-e2111da55126.png)

# なんで？
探しても特に引っかからなかった（探し方が悪かったかも）ので、自分で検証した結果、
ImgPaste のオプションに保存するファイル名を決めるオプションがあった。
「plugin»imgpaste»filename」というオプション。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/136398/e360db47-d2a8-724f-d146-d8cfaf51f616.png)

入っているのは `@NS@:pasted:%Y%m%d-%H%M%S` という値。

これは `@NS@` とか `@` で囲まれたところは置き換え文字列なんだけど、そうじゃないところに `:`（コロン）が入ってる。

Linuxではそれでいいんだけど、Windowsではファイル名やパスに `:` はNGなんだよなぁ。

しかも、DokuWikiの仕様で、名前空間の区切り文字に `:` が使われてるから、必然的に `@NS@` （名前空間に置き換わるもの）が使えない。

なので、それらを消して、 `%Y%m%d_%H%M%S` に変更。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/136398/f97ddd73-e058-6a50-f163-3d404b3503f6.png)
↑こんな感じ。
（`-` が `_` になっているのは好みです）

**動いた！**

# まとめ
Linuxに入れる前提のソフトウェアなんかはWindowsだと気をつけようね。
ラズパイでProcessingするときは、OpenGL (Fake KMS)で。

最近、Processingをもう一度試しています。
ラズパイで気がついたことがあるので、簡単にメモ。

折しも、からあげさん(https://qiita.com/karaage0703) もProcessing熱、再燃、ということで、からあげブログ(https://karaage.hatenadiary.jp/entry/2019/03/04/073000) 経由で色々と情報を仕入れさせてもらっています。感謝。

本題、からあげブログで知ったKeijiro Takahashiさんの作品、sketches2016を再生していて、すごい！　でも、ラズパイはやっぱり遅いなぁ、ラズパイクラス（教室）で使うには厳しいかな？とちょっと残念でした。

ところが、別のラズパイで動かしてみると、意外とイケてる。はて、と思って調べて見たら、遅いものはOpenGLの設定がLegacyになってました。OpenLG (Fake KMS)だと、MacBook 13inch 2017と同等とは言いませんが、使えるレベル。

sketches2016/cube5のムービーを撮ってGIFアニメにしてみました。（このGIFアニメは4倍速です。これぐらい速いと表現の幅も広がるな。。）上がMacBook 13inch 2017、左がラズパイでOpenGL Fake KMS、右がラズパイOpenGL Legacyです。Lagacyの3倍速くらい？
![cube5-mov.gif](https://qiita-image-store.s3.amazonaws.com/0/5412/c4574650-ed7b-c727-323b-bd56372400ad.gif)


ちなみにOpenGL (Full KMS)にすると、RealVNCが使えなくなるのと、マイクラも具合が良くないので使っていません。

Processing、よくわかっていないのですが、tif画像をキャッシュして、順番に表示している感じ。それでもOpenGLが効くんですね。インターラクティブな作品だとキャッシュできないと思いますが。

あと、お気に入りは、アプリに同梱のサンプル、Demos/Graphics/Yellowtailです。
Yellowtail(https://vimeo.com/661922)


以下、raspi-configコマンドによる、OpenGLの設定画面です。

```
$ sudo raspi-config
```

![iTerm2ScreenSnapz002.png](https://qiita-image-store.s3.amazonaws.com/0/5412/6a46b6f9-0d77-f077-0ed5-ad919b458c3d.png)
![iTerm2ScreenSnapz003.png](https://qiita-image-store.s3.amazonaws.com/0/5412/2b227c16-18d3-37b2-2d7a-693dd8380e09.png)
![iTerm2ScreenSnapz004.png](https://qiita-image-store.s3.amazonaws.com/0/5412/ddd5c51a-ac3b-a59c-95f6-f918d661b7f5.png)


Keijiro Takahashiさんの作品
https://github.com/keijiro/sketches2016
EgretEngineでログを出力する

# 課題
HTML5ゲームの開発のすそ野を広げるために、EgretEngineでいわゆるランゲームをお試しで開発しています。

数秒に一回プチフリーズするので原因を突き止めたいという状況です。

サンプルURL:
https://liberapp.net/applications/643acd30-4074-11e9-bb24-e194797f46d1

各処理のパフォーマンスを測定してログ表示する方法をまとめます

# 結論
こちらのGitHubのCommitをご覧ください
https://github.com/liberapp-inc/h5g-qiita-jump-and-run/commit/cbc881e5db243fa84247dbb922cafd964517718e

# 測定方法

以下のように`performance.now()`を使いましょう

```ts
    const start = performance.now();
:
// 処理
:
    const cost = performance.now() - start;
```

MDNによると マイクロ秒までの精度を持った浮動小数点形式でミリ秒を取得できます。

> performance.now() メソッドは、ミリ秒単位で計測された DOMHighResTimeStamp を返します。
> performance.now() が返すタイムスタンプは、1ミリ秒の分解能に制限されません。その代わりに、マイクロ秒までの精度を持った浮動小数点の値で表します。

https://developer.mozilla.org/ja/docs/Web/API/Performance/now

# ログの出力方法

## ロギング方法

egret.log関数(メソッド)でログを出力することができます

> ### Log () method
> #### `public log( message:any,...optionalParams:any[] ):void` 
>
> - Language version: all
> - Runtime version: Web, Runtime
>
> Output a log message to the console.
>
> #### parameter
> - Message:any — information to output to the console
> - ...optionalParams: any[] —
http://developer.egret.com/cn/apidoc/index/name/egret.globalFunction



## ログ表示方法

ログを以下のように画面にリアルタイムに表示することができます。

<img width="375" alt="IMG_1961.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/302078/0c4bfb47-f1b9-f254-8446-de4286243b64.png">

そのためには`index.html`を以下のように`data-show-log`を`true`にしてください。

```diff:index.html
    <div
      style="margin: auto;width: 100%;height: 100%;"
      class="egret-player"
      data-entry-class="Main"
      data-orientation="portrait"
      data-scale-mode="fixedWidth"
      data-frame-rate="60"
      data-content-width="640"
      data-content-height="1136"
      data-show-paint-rect="false"
      data-multi-fingered="2"
      data-show-fps="true"
-      data-show-log="false"
+      data-show-log="true"      
      data-show-fps-style="x:0,y:0,size:12,textColor:0xffffff,bgAlpha:0.5"
    ></div>
```
「EclipseでJavaアプリを書いて、Libertyコンテナで、Kubernetesで公開するまでの話し (その1)」をやってみた際のメモ

ちょっとレガシーなものをコンテナ化するためにどうしようかなと思い、以下のサイトを参考にやってみたら、いくつか躓いたのでメモ。

https://qiita.com/MahoTakara/items/1f2d160aeb129eec50ce#kuberntes%E3%81%A7%E3%81%AE%E5%8B%95%E4%BD%9C%E3%83%86%E3%82%B9%E3%83%88

（本当にメモ書きレベルなので投稿で申し訳ない。勉強になったので。編集依頼出せよとか言わないの！）


# 注意事項
Dockerはじめての人がミスりがちなこと

- 対象PCがVPN使った状態で使うと、minikube startのときエラーとなって起動できない。自分のCisco AnyconnectでVPN接続中にStartコマンド使ったらエラーで起動できなかった。
- EclipseでLibert動かした後や、Docker CEでテストした後、適宜、Libertyを落としておかないと、止めたはずなのにサイトが動いているとか、修正したのに反映されないという事象で原因解析に苦労する。これだから素人は・・・（自虐ネタ）。なお、Dockerを止めるのはdocker stopコマンドだ。

# プログラムの一部改善
プログラムのうち、ViewSessionObject.javaは、param1が入っていないとぬるぽになるようなので、Try-catchでヌルポ回避するコードを書いてみた。
雑なのはさーせん。

```java:ViewSessionObject.java
        response.setContentType("text/plain; charset=UTF-8"); 
        PrintWriter out = response.getWriter(); 
        InetAddress ia = InetAddress.getLocalHost();
        out.println("Host Name = " + ia.getHostName());
        out.println("IPaddr    = " + ia.getHostAddress());
        try {
	        HttpSession session = request.getSession();
	        SessionObject so = (SessionObject)session.getAttribute("param1");
	        out.println("param1    = " + so.getParam1());
        }catch(Exception e) {
        	out.println("param1    = " + "null data");
        }
        //response.getWriter().append("Served at: ").append(request.getContextPath());

```

にしても、Docker内のLibertyがすべてのロードが終わったか判別する方法がわからん。

テストするとき、みんなどうしているんだろう。。
なんとなく待つとかいう残念なことではないと信じているが。。
WordPressでタグで判別して表示を変更する方法

外観 > テーマエディター > 変更したいphpファイル

`<?php if( has_tag('QOL') ) : ?>
<body style="background-image:none">
<?php else: ?>
<body>
<?php endif; ?>`

タグ：QOLの場合、バックグラウンドイメージを消す。
リストの空の要素を駆逐する

更新履歴: 間違いを修正しました。@shiracamusさん、ありがとうございます。

# Introduction

あるデータを読み込むと、以下のようなリストが返されました。

```python
>>> list_example = ['a', '', '', 'b', 'c', '']
```

この空の要素`''`をサクッと取り除くためにはどうすればよいでしょうか。

# removeメソッド

## removeメソッド

試しに`remove`メソッドを使って、空の要素を取り除いてみます。

```python
>>> list_example.remove('')
>>> list_example
['a', '', 'b', 'c', '']
```

'a'の隣の空の要素が一つ削除されていることがわかります。このように、**removeメソッドはリストの先頭から検索して最初に発見した該当要素を削除**します。

空の要素がn個あった場合に、それらを全部駆逐したければ、removeメソッドをn回繰り返せばよい、ということになります。

## removeメソッドの戻り値は何か

```python
>>> list_example = ['a', '', '', 'b', 'c', '']
>>> type(list_example.remove(''))
<class 'NoneType'>
```

余談ですが、実はremoveメソッドの処理が成功した場合は**`None`を返します(つまり何も返しません)**。となるとこのメソッドの戻り値を頼りに、forやwhileでTrueの場合には削除を続ける(Falseで削除を終了する)なんて操作はできなさそうですね。

また、removeメソッドは該当する要素が見つからない時には以下のような例外を返します。

```python
>>> list_example.remove('')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: list.remove(x): x not in list
```

# whileループで空の要素を駆逐する

以下のように、whileループの中のif文の条件式に要素を指定することで、空の要素を取り除くことができます。

```python
>>> count = 0
>>> list_example2 = []
>>> while count < len(list_example):
...     if list_example[count] != '':
...         list_example2.append(list_example[count])
...     count += 1
... 
>>> list_example2
['a', 'b', 'c']
```

# forループで空の要素を駆逐する

また上述のスクリプトはforループで書くことも可能です。

```python
>>> list_example3 = []
>>> for a in list_example:
...     if a != '':
...         list_example3.append(a)
... 
>>> list_example3
['a', 'b', 'c']
```

# 内包表記で空の要素を駆逐する

上2つのようにwhile文, for文を使う方法もありますが、スクリプトが長くなってしまいます。そんな時には、Pythonでおなじみの内包表記が便利です。

```python
>>> list_example4 = [a for a in list_example if a != '']
>>> list_example4
['a', 'b', 'c']
```

# filter関数とlambda(無名関数)で空の要素を駆逐する

```python
>>> list_example5 = filter(lambda a: a != '', list_example)
>>> list_example5
<filter object at 0x1102e64e0>
>>> list(list_example5)
['a', 'b', 'c']
```

Python3系では、`filter関数`は`filterオブジェクト`を返します。リストとして取得したい場合には`list関数`を使いましょう。

参考Link:
https://teratail.com/questions/92477
https://it-engineer-lab.com/archives/124
mac の初期設定やアプリインストールメモ

新しい mac をゼロから設定したのでメモ
一部を除き，基本的に無料のアプリケーションばかりです．

# 必須

- OSアップデート
    - まずしましょう

# アカウント登録系

- Apple ID 登録
    - mac 使うならほぼ必須でしょう
- Google アカウント登録
    - gmail や google カレンダーなどでお世話になってます

# mac OS 向けおすすめアプリ

- [Google chrome](https://www.google.com/intl/ja_ALL/chrome/)
    - 言わずとしれたブラウザ．デフォルトのブラウザにしてます．
    - [google 翻訳の拡張機能](https://chrome.google.com/webstore/detail/google-translate/aapbdbdomjkkjkaonfhkkikfgjllcleb?hl=ja)が便利なことに最近気がつく
    - 公式サイトからダウンロード
    
- [1password](https://1password.com/jp/)
    - パスワード管理アプリ．iCloud 経由で別端末とも同期可．
    - App Store からダウンロード
    
- [Google 日本語入力](https://www.google.co.jp/ime/)
    - google 製の IME. ことえりより使いやすいです．
    - 公式サイトからダウンロード
    
- [Coteditor](https://coteditor.com/)
    - テキストエディタ. 日本製なので文字コードなどで困ることはなさそう．
    - App Store からダウンロード
    
- [BetterTouchTool](https://folivora.ai/)
    - トラックパッドの機能を拡張するアプリ．トラックパッド使う人はぜひ．
    - ディスプレイに合わせたウィンドウのリサイズもできるようになります．
    - 有料
    - 公式サイトからダウンロード

# チャットアプリ
   
- [Slack](https://slack.com/intl/ja/signin)
    - チャンネルっていう概念があるのが SKype との大きな違いか．
    - 過去のメッセージ検索などが容易
    - App Store からダウンロード
    
- [LINE](https://line.me/ja/)
    - 説明不要
    - App Store からダウンロード

# ターミナル作業向けアプリ
## パッケージ管理

- [homebrew](https://brew.sh/index_ja)
    - パッケージ管理ソフトウェア． yum みたいなものです．
    - ターミナルから ruby ワンライナーで一発インストール

## プログラミング関連

- Xcode command line tools
    - mac でプログラミングがしたいなら必須
    - apple developer なんちゃらに登録がいるかも（忘れました）
    - GUI アプリの Xcode からでも OK
    - ターミナルで `gcc` とか打ったらダイアログが出て，OK を押したらインストールされます．
           
- ctags
    - ソースコード内の単語を拾って索引を作るソフトウェア．vim などののサジェスト機能が強くなる．
    - homebrew でインストール可
    
## その他

- [mactex](http://tug.org/mactex/)
    - ダウンロードは本家ではなく，ミラーサイトからしたほうが早いです
    - 日本語フォントの設定などがやや面倒
    - 参考にしたサイト: http://doratex.hatenablog.jp/entry/20180501/1525144736
    - 公式サイトからダウンロード
    
- [tmux](https://github.com/tmux/tmux)
    - 1画面で複数の仮想端末を扱えるソフトウェア．screen みたいなものです．
    - 日本語表示がおかしくなるときは `-u` オプションを追加
    - homebrew でインストール可
    
- Microsoft Office 製品
    - ライセンスを持っているならばインストールしておくべし
    
以上
Cloudflareのhttp/3実装 quiche サンプルサーバを試す

Cloudflareのhttp/3実装が目についたので、とりあえずサンプルサーバを動かしてみました

## HTTP/3について
IETFでHTTP/3の標準化が進められています。

現在はdraft-19が出ているところです。
https://tools.ietf.org/html/draft-ietf-quic-http-19

QUIC及びHTTP/3について別途まとめましたので、参考にして頂ければ
- [QUICの話 (QUICプロトコルの簡単なまとめ)](https://asnokaze.hatenablog.com/entry/2018/10/31/020215)
- [HTTP over QUICと、その名称について (HTTP3について)](https://asnokaze.hatenablog.com/entry/2018/11/06/025016)

## 各社QUIC, HTTP/3実装状況
簡単に他の実装状況にも触れます。
IETF QUIC, HTTP/3 は標準化を進めるとともに各社が実装を持ち寄って相互接続性テストを行っています。

今は「[11th Implementation Draft](https://github.com/quicwg/base-drafts/wiki/11th-Implementation-Draft)」での接続テストを行っています。下の図は実装同士で接続テストをし、動作確認がとれたものが書かれている表になります。3と書かれているのがHTTP/3の実装が行われているものになります。
![5842298-1c9f2754ca60076ba766aca52996441d71fb8c35.png](https://qiita-image-store.s3.amazonaws.com/0/32425/afd413d2-fb35-564d-0d87-0d9ca17a7604.png)

- [QUIC Interop Matrix](https://docs.google.com/spreadsheets/d/1D0tW89vOoaScs3IY9RGC0UesWGAwE6xyLk0l4JtvTVg/edit#gid=1965785440)
- [QUIC Implementations](https://github.com/quicwg/base-drafts/wiki/Implementations)

## Cloudflare quiche
[quiche](https://github.com/cloudflare/quiche)はCloudflareのQUIC, HTTP/3のRUST実装です。ちなみに現在は、draft 18の実装になっています。
([Googleも同名の実装を持っていて紛らわしい](https://quiche.googlesource.com/quiche/))

先日、HTTP/3実装がmasterにマージされたのでexampleのサーバ・クライアントを試しに動かしてみました

### Build
READMEに書いてあるとおり

```shell
# 準備
$ apt-get install cmake
$ curl https://sh.rustup.rs -sSf | sh # 適宜PATH通してcargo使えるように

$ git clone https://github.com/cloudflare/quiche.git
$ cd ./quiche
quiche$ git submodule update --init
quiche$ cargo build --examples
```

## 動作確認
### server
デフォルトでポート4433でリッスンします。証明書や鍵はexamplesに含まれているため指定は不要です

```shell
quiche$ quiche$ mkdir ./examples/root
quiche$ echo 'It works!!' > ./examples/root/index.html

quiche$ target/debug/examples/http3-server
```

### client
```shell
quiche$ target/debug/examples/http3-client https://localhost:4433/index.html
It works!!
```

### wireahark
Clientがデフォルトの `version=babababa` で接続しにいったあとVersion Negotiationパケットが返ってきて改めて`draft-18`で接続しに行ってる様子や、Handshakeパケットのあとにショートヘッダパケットが送受信されている様子が見えます。
![quiche.png](https://qiita-image-store.s3.amazonaws.com/0/32425/b00fbbc4-01fb-af94-e088-b316c39c15c9.png)
Firebase 向け Google アナリティクス の初期設定・分析運用

前提として、[Google アナリティクス から Firebase 向け Google アナリティクス の移行（Firebaseイベントの設計）](https://qiita.com/ryosayo/items/c06f421126b1a82251e3)の実践編となります。

## 導入
1.以下ページで「プロジェクトを追加」をクリック
https://console.firebase.google.com/


2.プロジェクト名、ロケーションを以下のように入力し、チェック項目はすべてチェックしてプロジェクトを作成
![画像](https://s3-ap-northeast-1.amazonaws.com/yrowqiita/fb01.png)

3.プラットフォーム毎に商用／開発用のアプリを作成し、iOS用のplistとAndroid用のjosnファイルを取得
※実際にアプリに埋め込み疎通を行うことで設定完了となります。
※設定に必要な情報
iOS バンドル ID
App Store ID
Android パッケージ名
・iOSのスクリーンショット（主要のみ）
![画像](https://s3-ap-northeast-1.amazonaws.com/yrowqiita/fb02.png)

・Androidのスクリーンショット（主要のみ）
![画像](https://s3-ap-northeast-1.amazonaws.com/yrowqiita/fb03.png)

※Androidの広告IDについて、"不要な広告IDの利用" によりStoreからRejectされる場合があります。
Firebase 向け Google アナリティクスを利用するには、広告IDの利用は必須となるためStore上にプライバシーポリシーのリンクを必ず用意するようにしてください。

## 運用
### アプリ新規インストール数の確認
1.左メニューの「アナリティクス」から「Events」を選択する。
![画像](https://s3-ap-northeast-1.amazonaws.com/yrowqiita/fb04.png)

2.画面上部の「フィルタを追加」から対象のアプリを指定する。

3.画面右上の日付の範囲を変更する。

4.「first_open」の件数がインストール数となる。

※その他、共通で自動的に収集されるイベント
https://support.google.com/analytics/answer/6317485?hl=ja&ref_topic=6317484

### カスタム（任意）パラメータを利用したイベントの確認
1.左メニューの「アナリティクス」から「Events」を選択する。

2.対象のイベントの右側の編集アイコンをクリックし「パラメータ レポートを編集」を選択する。

3.対象のパラメータを追加して、保存をクリックする。（基本的に文字列を送ってるのでテキストを指定）
![画像](https://s3-ap-northeast-1.amazonaws.com/yrowqiita/fb08.png)
※保存してからデータが反映されるまでに24時間かかる

4.対象のイベント詳細で、追加したパラメータ毎の数値が表示される。
![画像](https://s3-ap-northeast-1.amazonaws.com/yrowqiita/fb09.png)

### SelectContentを利用したContentType、CotentItemの確認
1.左メニューの「アナリティクス」から「Events」を選択する。

2.「select_content」をクリックする。
![画像](https://s3-ap-northeast-1.amazonaws.com/yrowqiita/fb05.png)

3.ページ内のコンテンツパネル（select_contentのみ利用可能）にcontent_type毎の数値が確認できる
![画像](https://s3-ap-northeast-1.amazonaws.com/yrowqiita/fb06.png)

4.content_type内の明細をクリックすると、所属のアイテムの数値が確認できる
![画像](https://s3-ap-northeast-1.amazonaws.com/yrowqiita/fb07.png)

### イベント名を利用した数値の確認
1.左メニューの「アナリティクス」から「Events」を選択する。

2.一覧上部の検索枠にフィルタする文字列を指定する。
![画像](https://s3-ap-northeast-1.amazonaws.com/yrowqiita/fb10.png)
EmacsでWSLを使っている/いないを判断する

WSLを使っている時に行いたい処理がある時はどうしようか。
`system-type`の値は`gnu/linux`。これはWindowsサブシステムではないLinuxと同じなので、プラス何かの情報がほしいです。

## 外部コマンドを使う

`uname -r`や`uname -v`にはWSL固有らしい文字列が含まれているので、それを参考にします。

```shell-session
$ uname -r
4.4.0-17763-Microsoft
$ uname -v
#379-Microsoft Wed Mar 06 19:16:00 PST 2019
```

unameの出力に`Microsoft`が含まれていればWSLだとすると、こんな感じか。

```emacs-lisp
(when (and (eq system-type 'gnu/linux)
           (string-match-p "Microsoft" (shell-command-to-string "uname -v")))
  (do-something))
```

この先ずっとカーネルバージョンに`Microsoft`が含まれているとは限らないのが悩ましいところです。数カ月先、数年先に落とし穴が待ってそう……

## 環境変数を探す

Windows 10はビルド17063以降`WSLENV`という環境変数を提供しています。[^1]
`WSLENV`はWindowsとWSLの間でファイルパスのようなシステム固有のデータを橋渡しする役目がある環境変数だそうで。これがあればWSLの環境下にあると言えそうです。

```emacs-lisp
(when (and (eq system-type 'gnu/linux)
           (getenv "WSLENV"))
  (do-something))
```

外部コマンドを使う場合と同様、`WSLENV`がずっと使える保証がないところは泣き所です。
とはいえ、カーネルバージョンの文言よりは後方互換性を期待できるので、使うとしたらこちらかなーと考えています。

[^1]: [Windows Command Line Tools For Developers | Share Environment Vars between WSL and Windows](https://devblogs.microsoft.com/commandline/share-environment-vars-between-wsl-and-windows/)
agora.io Chromeで画面（アプリケーション）共有

#agora.ioのWebRTC SDKで画面（アプリケーション）共有を実装

[Githubに公開しています](https://github.com/fu-jimoto/AgoraIO-WebRTC-ScreenShare-v3)

##開発環境
Chrome 85.0.4183.83
AgoraVideoSDK for Web 3.1.2

##使用するAPI
```javascript
createStream(spec: StreamSpec): Stream
```
[公式ドキュメント](https://docs.agora.io/en/Video/screensharing_web?platform=Web)

##実装内容

CreateStreamのscreenをtrueするだけです。

```javascript
rtc.localStream = AgoraRTC.createStream({
 streamID: rtc.params.uid,
 audio: true,
 video: true,
 screen: true,　←ここ
 screenAudio: true
})

```

##画面
（APPID、Channelを入力してJoinをクリック）
・画面共有のダイアログ表示時
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/93fb799b-2185-deb9-1c64-45074c3e9af6.png)

・画面共有時
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/4e89510e-1556-62e4-291e-b06bbbb4006a.png)

##補足
・Web SDK v3.0以降、Windows Chrome74以降より音声共有もできます。詳細は[こちら](https://docs.agora.io/en/Video/screensharing_web?platform=Web#a-name--screenaudioashare-audio)
・Web SDK v2.6またはChrome 72以下の場合は[プラグイン](https://docs.agora.io/en/Video/chrome_screensharing_plugin)が必要です。

##関連リンク
・[画面共有のドキュメントはありますか？](https://docs.agora.io/en/Video/screensharing_web?platform=Web)
・[画面共有のサンプルはありますか？](https://github.com/AgoraIO/Advanced-Video/tree/master/Web/Agora-Screen-Sharing-Web-Webpack)
・[画面共有で、ブラウザ(Chrome)標準の中止ボタンを押した場合、そのイベントをリッスンする方法はありますか？](https://vcube-support.zendesk.com/hc/ja/articles/900001228386)


#最後に
[**agora.ioに関するお問い合わせはこちらから**](https://jp.vcube.com/lp/agora?utm_campaign=Agora&utm_source=Qiita&arc_id=aa7328a2f250a6da13ec)
[<img width="912" alt="スクリーンショット 0001-08-15 13.41.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300377/5d815376-9b89-08fa-9434-6fa7e8e67bcf.png">](https://jp.vcube.com/lp/agora?utm_campaign=Agora&utm_source=Qiita&arc_id=aa7328a2f250a6da13ec)
【備忘録】PHPStormでとりあえずこれだけ覚えておこうコマンド

## 前提：Macを使っています。

## 全検索
`Shift`を２回
class、functionに限らず、とりあえず全部検索すれば大丈夫

## 宣言（定義）へジャンプ
`command + ↓`

## ジャンプ元に戻る
`command + option + ←`

## 現在見ているタブを消す
`command + W`

## 最近見たファイルを表示
`command + E`

## 他にも便利なものがあったら教えてください。
【swift】jsonファイルをclassで作成する

# 概要
サーバーと通信してJsonデータを取得してアプリに表示する事はよくあると思われるのですが、サーバーとアプリを同時に開発しているとサーバー側の開発が遅れていてJsonデータを取得出来ないことはよくあります。
そういった場合は、API仕様書等でサンプルのJsonを作ってもらってそのJsonデータを使ってアプリを開発していきます。
よく使う方法としては、.jsonファイルをアプリにインポートして`String(contentsOfFile: path)`でファイルを取得して、`JSONSerialization`でDictionaryに変換します。

```swift:ViewController.swift
let path = Bundle.main.path(forResource: "TestJson", ofType: "json")
let content = try? String(contentsOfFile: path!, encoding: .utf8)
if let _content = content {
    let json = try? JSONSerialization.jsonObject(with: _content.data(using: .utf8)!, options: []) as! [String: Any]
}
```
これで全く問題ないのですが、今回はJsonデータをクラスで管理して、応用してデータを利用しやすい方法を紹介したいと思います。

# 実装方法
```swift:JsonFactory.swift
import UIKit

protocol JsonString {
    func jsonString() -> String
}

class JsonFactory: NSObject {
    class func getJson(_ content: JsonString) -> [String: Any]? {
        let json = try? JSONSerialization.jsonObject(with: content.jsonString().data(using: .utf8)!, options: []) as! [String: Any]
        guard let _json = json else { return [:] }
        
        return _json
    }
}
```

```swift:TestJson.swift
class TestJson: JsonString {
    func jsonString() -> String {
        return """
        {
        "test1":"あああ",
        "test2":"いいい",
        "test3":"ううう",
        "test4":"えええ"
        }
        """
    }
}
```

```swift:ViewController.swift
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        let aa = JsonFactory.getJson(TestJson())
        print(aa)
    }
```

# まとめ
この方法を使うと様々な応用が出来るようになります。

- JsonFactoryに本番とstubデータの切り替えフラグを立てて切り替えしやすく出来る
- baseJsonを作って継承することで同じJsonデータのいろんなパターンをテストしやすく出来る
Android4.4でtouchendが効かないときの対処法



Android4.4でtouchendが効かないときは、
**touchcancel**を追加すれば良い。


```js
$(document).on("touchend touchcancel", function (e) {
					doSomething();
				});
```



[参考資料](https://stackoverflow.com/questions/19088117/touchend-not-firing-after-touchmove)
PowerShell 2でスクレイピング

# 環境

Windows7 + PowerShell 2

# やりたいこと

ツールを導入できない環境でスクレイピングしたい。でも自前でhtmlパーサは書きたくない。
なお、Invoke-WebRequestはPowerShell 3からなので使用できない。

# 方法

COMオブジェクトのhtmlfileにIHTMLDocument2_writeで書き込めばDOM経由でHTMLの内容にアクセスできる。
書き込むHTMLはWebClientのDownloadStringで取得する。

```powershell
# アクセス先
$url = "http://google.com"

# WebClientを準備
$wc = New-Object System.Net.WebClient
$wc.Encoding = [System.Text.Encoding]::GetEncoding("UTF-8")

# htmlfileオブジェクトを準備
$content = $wc.DownloadString($url)
$htmlfile = New-Object -com "htmlfile"
$htmlfile.IHTMLDocument2_write($content)

# htmlfileオブジェクトを操作して必要な要素を見つけだす。
# 今回は google 検索ボタン を参照している。
# htmlfileのDOM操作は独特でgetElementByIdがうまく使えない。
# getElementsByTagNameは有効なのでそれを手掛かりに探す。
# querySelector なんて便利なものは存在しない。
$htmlfile.getElementsByTagName("form")[0].getElementsByTagName("input")[6].value
```
GKEでスナップショットからMongoDBをリストアするときの備忘録

# スナップショットでMongoDBをバックアップするときの大まかな流れ
* 定期的に`mongodump`
* スナップショットスケジュールの作成
* 対象ディスクを作ったスケジュールにアタッチ
    * [Attaching a snapshot schedule to a disk](https://cloud.google.com/compute/docs/disks/scheduled-snapshots#attach_snapshot_schedule)

※ もしかしたら、別記事立てるかもです。

# 本編(スナップショットからmongoリストア)
## リストア作業用のVMインスタンス追加
以下に従ってVMインスタンス追加。
[ブートディスク以外のディスク スナップショットの復元
](https://cloud.google.com/compute/docs/disks/restore-and-delete-snapshots?authuser=3&hl=ja#restorenonboot)
スナップショットは追加ディスクで追加。
## リモートアクセス
SSHとかブラウザウィンドウからとか、いくつか選択肢あり。それほど重い作業ではないので、ブラウザウィンドウがお手軽。
## 追加ディスクのマウント
```shell
working_dir=/mnt/disks/[name]
mkdir -p ${working_dir}
mount -o defaults /dev/disk/by-id/google-${additional_disk_name} ${working_dir}
```

## リストア(ずぼら版)
```shell
docker run --rm -v ${working_dir}/${path_to_dump}:/backup mongo bash -c "mongorestore /backup --host=${host} --port=${port} -u ${user} -p ${pw} --authenticationDatabase admin"
```
権限でおこられたら`sudo`付きで。
ちゃんとするなら、コンテナ立てて中でやった方がいいかもです。

#### 参考ページ
[Google Cloudで追加ディスクのマウントを行う](http://tug-uca.hatenablog.com/entry/2017/06/22/151621)
WinActor VBAマクロ非同期実行

###問題
WinActorでマクロ実行するとマクロでダイアログが出ても自動操作できない。

###オフィシャル対処(WinActor　FAQ　（よくある質問）2018.11.8 第5.1版より)
1.実行ボタンを画像マッチングしてクリック
2.キーボードエミュレーションAlt+L+P+Mでマクロ一覧実行後実行
3.マクロ書き換え

###想定理由
ライブラリのマクロ実行は同期処理であるため、マクロ終了まで操作が出来ない。

###希望
マクロで何か問い合わせがあった際に自動でYesなりなんなりしてほしい。
マクロをいっそ書き換えようか迷ったが、メリットが失われてしまうのを懸念
→　基幹システムの既存の処理を変えずに実行できる
それに今後もありそうなので簡単な回避策が欲しい。

###対処方法
同期実行を非同期に切り替えてみる。

```VBScript:書換前
xlsApp.Run "'" + filePath + "'!" + !マクロ名!
```

```VBScript:書換後
xlsApp.OnTime Now + TimeValue("00:00:00"), "'" + filePath + "'!" + !マクロ名!
```

###懸念
非同期なのでマクロ実行終了を待つ必要がある。
フォーラムはFAQで自己発信系のこういったノウハウためる感じが無い。
自己紹介

プロフィール
・理系の大学に通う男の人（2019年4月から3年生）
・プログラミング開始時期：2019年2月19日
・始めた言語：python
・プログラミングの経験：KAIMU

Like
・読書（家で）
・ゲーム（家で）
・映画（家で）
・家でスポーツ観戦（家で）

Dislike
・人混み
・混雑しているところ
・満員電車
・プルーン

勉強したいこと
・プログラミング、機械学習、ディープラーニング、VR、AR、MR、光、音、電気回路、電子回路etc...

【重要】プログラミングを始めた理由（わけ）
・最近よく耳にするdiversity（多様性）という言葉の意味を自分なりに考えてみました。いま、僕たちが目指している"多様性のある世界"って何だろうと考えると、個人がありのまま暮らす世界なのかなとはじめは思いました。「みんな違ってみんな良いのだから、みんな平等だよ」という風な世界です。僕もこの世界には大賛成で最終的にはこういう世界になってほしいと思います。でもこれはあくまで最終ゴールであって、まだこの段階を目指すのは危険だと思います（以下、このような世界を真のdiversityとします）。ここでいう"みんな違う"といっているのは、いわゆる外見、性格のような個性だと思います。しかし、今はなんらかの先天的、後天的要因でほかの人と比べて不自由を感じる人がたくさんいます。そういった不自由を無視して多様性を尊重しようというのは、結果として多数派の人たちの多様性しか尊重してないよね、という風になるのではないかと思われます。では、不自由を感じている人たちを個性の違いというレベルまでもっていくにはどうすればいいかと考えたときに科学の力で解決するというのが僕の結論になりました。特に、人間が感覚として使用している光、音で問題を抱えている人たちの問題を解決すれば真のdiversityに少しは近づけるのではないかと考えました。そうなると自分が勉強するべきものとしてプログラミングが適当だと思いました。

現状
・プログラミングを勉強し始めてから丁度１か月経ちました。（大学の春休みを使ってプログラミングの学校などには通わずに独学でやってます。）やっぱりプログラミングに対して常識みたいなものが備わっていないと感じます。なにが備わっていないのかもわからない、嗚呼逆ソクラテス状態（2019年3月20日）。
セレクタまとめてみた

#セレクタとは
cssで要素を特定するための目印。

#セレクタまとめ
##タグ
##クラス
###何回も登場。共通の特徴。緑が好きとか、黒の服を来ているとか。
##id
###一回だけ登場。そいつの個性。名前とか、今持っているペンとか。
##スペース
###要素の「内側」。
##>
###要素の「子要素」。
##+
###要素の「次に来る」。
##~
###要素の「兄弟関係にある」。
##擬似要素
###hover/visited/first-child/nth-child/only-of-type/first-line/first-letter/before/after
Google アナリティクス から Firebase 向け Google アナリティクス の移行（Firebaseイベントの設計）

##TL;DR
2019 年 10 月以降、Google アナリティクス開発者サービス SDK は順次サービスを終了となります。
これにより アプリ分析を行う場合はFirebase SDK に移行する必要がありますが、Googleアナリティクス（以降GA）からFirebase向けGoogleアナリティクス（以降FA）の移行についてイベントに対する考え方が大きく変わっております。

実際のアプリへの導入、分析については以下を参照してください。
[Firebase 向け Google アナリティクス の初期設定・分析運用](https://qiita.com/ryosayo/items/3af80cbf04e0bb7f1a93)

##GAとFAの比較

GAでは1つのイベントを カテゴリ / アクション / ラベル のように階層化していましたが、FAでは1つのイベントに対して、階層は1つで、パラメータ（属性）を付与する考え方となります。

例）あるアプリで、言語設定を日本語にして 一覧A から 商品1 を選んだイベントの場合
◯ GA
一覧A / 商品1 / 日本語

◯ FA （パラメータの名前は任意）
・パターン1
商品1 (パラメータ1 = 一覧A, パラメータ3 = 日本語 )

・パターン2
一覧A (パラメータ2 = 商品1, パラメータ3 = 日本語 )

##FAのイベント設計
パターン1の場合でイベントを作成した場合、FAのダッシュボードで一覧Aの商品を羅列して確認することができません。
パターン2の場合は一覧Aの商品を確認することができますが、ConversionsやFunnelsといった達成率を計測する機能はイベントのみ登録可能（属性はだめ）なので商品1を指定することができなくなります。

パラメータは1プロジェクトにつき50個までという制限があります。
※同じパラメータでも3つのイベントで利用していたら3個消費
※GUI上で見れないだけでBigQueryとの連携を行うのであれば可能

またFAが標準で用意しているイベントと推奨イベントがあります。
https://support.google.com/analytics/topic/6317484?hl=ja

上記イベントでアプリの初回起動やバージョンアップなどは自動で採取されます。
その他にも上記に記載しているイベントを利用することで、将来のFirebase側のバージョンアップ時にダッシュボードの新しい集計閲覧など恩恵を受けれるようです。

また推奨イベントの中にSelectContentというイベントがあり、CotentItemとContentTypeを利用することで階層を実現することが可能で、Firebase上のGUIで専用の分析エリアが設けられています。

ただし現状はCotentItemなどもConversionsやFunnelsには設定できないようです。

各種制限値は以下となります。

| 項目| 制限内容|
|:-----------|:-----------|
| イベントの種類       | 500個まで |
| 属性の種類       | 50個まで |
| イベント名・属性名     | 半角英数40文字まで |
| 属性の値       | 100文字まで（同一属性名の型は揃える） |


## 結論
現状のイベント登録方式は以下3つから選択と考えております。
1) カスタム（任意）パラメータを利用してイベントを登録する。
2) SelectContentを利用してContentType、CotentItemで親子関係を作る。
3) パラメータは利用せず、"一覧1"・"一覧1_商品1"・"一覧1_商品1_日本語"など
イベント名にカテゴリ名を含める。（ダッシュボードのフィルタ機能で確認する）

ConversionsやFunnelsを利用する場合は、3)しか方法がない状況となりますが
各カテゴリごとの集計値は自前で計算するまたは専用のイベントを発行する必要があります。
ただしBigQuery連携を行うのであれば以下の形式で全データを抽出できます。

```Javascript
{
  "event_date": "20190315",
  "event_timestamp": "1552625635701322",
  "event_name": "SampleEvent1",
  "event_params": [
      {
          "key": "firebase_event_origin",
          "value": {
              "string_value": "app"
          }
      },
      {
          "key": "firebase_screen_id",
          "value": {
              "int_value": "-5828902028743042063"
          }
      }
    ],

    ...

    "platform": "IOS"
}
```


なので、基本的には BigQuery との連携を推奨する考え方なのかもしれません。
1)、2)については、親／子の集計値をそれぞれ確認できますが、最大50個の制限とConversionsやFunnelsを利用できない状況となります。

またGAとFAを共存することは問題ないようです。（多少なり余計なトラフィックは増えますが）
https://developers-jp.googleblog.com/2017/03/how-do-i-add-firebase-analytics-to-app.html

GAの画面上でFAのデータを表示することは以下手順で可能です。

1. アプリのプロパティに移動
2. [プロパティ] メニューの [新しいプロパティを作成] を選択
3. [モバイルアプリ] をクリック
4. Firebase アプリを選択
5. [アプリを接続] をクリック

※公式ヘルプ関連
https://firebase.google.com/docs/analytics/?hl=ja
https://support.google.com/analytics/answer/6317479
https://support.google.com/firebase/answer/7397304?hl=ja
https://support.google.com/analytics/answer/7663853?hl=ja
https://support.google.com/analytics/topic/6317484?hl=ja
[iOS][FCM] "application:didFailToRegisterForRemoteNotificationsWithError: Appの有効な“aps-environment”エンタイトルメント文字列が見つかりません" というエラーでPUSH通知が届かない

[公式ガイド](https://firebase.google.com/docs/cloud-messaging/ios/client?hl=ja) に従って、
* Firebaseプロジェクトの設定（Firebase Console）
* SDKと初期化処理を追加(Xcode)
* AppID, APNs用キー, プロビジョニングプロファイルの作成 (Apple Developer > Certificates, Identifiers & Profiles)
を行って [テスト送信](https://firebase.google.com/docs/cloud-messaging/ios/first-message?hl=ja) をしてみるが、通知が届かかった。

エラーログを見ると

```
[Firebase/Messaging][I-FCM012002] Error in application:didFailToRegisterForRemoteNotificationsWithError: Appの有効な“aps-environment”エンタイトルメント文字列が見つかりません
```

というエラーが出ている。
どうやら下記の設定が不足していたようだ。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/52847/06248380-a54d-d3e1-4cec-3ee2d52821fd.png)

↑ONに変えると、無事通知が届くようになった。

参考:
https://develop.hateblo.jp/entry/ios-firebase-cloud-messaging
マジか！？Σ(･ω･ﾉ)ﾉ！Pleiadesの環境構築でつまづいたこと

# Pleiadesとは？

10年以上プログラムを組んでいて、Javaの開発をしていた人には定番の統合開発環境（IDE）であるEclipse。
Eclipseの日本語環境を作るための日本語化パッケージプラグインがPleiades。

今ではEclipse＋PleiadesのセットになったAll in Oneでも提供している。
ダウンロードして展開するだけで使えるのでJavaが必要になった時よく使う。
今回の記事はそんな時に発生した事象。

# Pleiades All in OneをダウンロードしてJavaソースを読み込んだところ、ビルドできない！

いつもと同じようにサイトからzipファイルをダウンロードして、ローカルに展開。
昔からzipの解凍には頓着ないので、Windowsの展開を使っていた。

いつも通りの操作をポチポチ進めて、いよいよビルドかーそうしたところ、エラー？？
ソース触ってないのに・・・。

`/workspace/.metadata/.log` を見るとクラスが無い？？しかもeclipseの？？？？

```
java.lang.NoClassDefFoundError: org/eclipse/jface/text/source/OverviewRuler$WidgetInfos
```

# たどり着いた結論

zipの解凍の時に壊れたらしい。

ええええΣ(･ω･ﾉ)ﾉ！

クラスファイルが無いのだから、何故か消えた？　→　解凍に失敗？
7-Zipで解凍してみよう　→　成功。

あとでPleiadesのサイトを見たら解凍に関する注意書きが。
http://mergedoc.osdn.jp/pleiades.html?v=3#zip-notice

Windowsの展開する場合でも`C:\`みたいな最短のパスを指定する！？

要するに、展開された後のパスの文字列長の問題らしい。
最近気にすることなかったからな。。全然考えてなかった。
しかし、ファイルパスが深すぎるってのはどうなのよ。。

# 最後に
いつも使っていたから、サイトの説明すら見ないようになっていたところにつまづいたもんだから、イラっとして愚痴を書きました(＠_＠;)


##### 雑記
PyCharmの日本語化にもPleiadesを使うのだけど、過去に最新のPyCharmにPleiadesを入れたら動かなくなったことがある。
あの時はPleiadesの対応するバージョンに、最新のPyCharmが入ってなかったからだと理解していた。（構成を見る限り関係なさそうに見えたけど）
これ以降、PyCharmは英語のまま使っている。

しかし、今回の件でもしかして解凍ミスってた！？という疑惑が生まれた。
でも英語のまま使う。

##### 雑記2
今回Eclipseを落として使ったけど、最近はInteliJがメジャーみたいなことよく見る。
私はこれまでEclipseばっかりだったので、使い慣れたEclipseを使ったけど・・・・立ち上がりが遅すぎる。。
まぁUltimateで使うってのが良くないのかもしれないけど、立ち上がりに体感5分はキツイな。。（多分5分も経ってない）
InteliJに乗り換えようかな・・・。
EclipseはVSCodeみたいに何でもかんでもてんこ盛りができる利点はあるんだよなー。
Javaが私のメインではなくなって久しいけど、こんなだったっけ？　いや、逆に昔から立ち上がりの遅さが変わってないって感じだ・・・。
Eclipseはいつも、その時期の最新スペックのPCを求めている印象。
push表示で遷移後レイアウトが上にずれる


タイトルの通りpush表示で遷移した後にscrollviewを使ったレイアウトが
上にずれる理由がわからず悩んでいたので同じ境遇の方がいれば参考になれば幸いです

##結論　isTranslucent = trueになっていた
viewでnavigationより下か上かの設定のコードが仕組まれてました。
上記が理由で今回遷移後にその作用が残っており、viewが少し上に表示されていた。
下記が挙動の詳細です。

###navigationBarの上から開始

```
   navigationController?.navigationBar.isTranslucent = true
```

###navigationBarよりも下から開始

```
navigationController?.navigationBar.isTranslucent = false
```

##少し深掘り

下記を参考にして少し深掘りしてみる
[UINavigationControllerと座標ズレの小ネタ](https://qiita.com/Yaruki00/items/1ca29e9f26578f33c80e)
[apple公式 isTranslucentの説明](https://developer.apple.com/documentation/uikit/uinavigationbar/1624928-istranslucent)

isTranslucent = true　にすると
`ViewControllerのビューの描画範囲は、ナビゲーションバーで隠れる部分を含めて画面全体になります`

と書かれているので、scrollviewをautoPinEdgesToSuperviewEdgesでsuperviewと同じ大きさ取ってくるようにしてたから動いたのかな？

edgesForExtendedLayoutも怪しい...
[iOS11 + Xcode9.0でedgesForExtendedLayoutの値を空にしていると、UITableViewのドリルダウンでアニメーションが崩れる](https://qiita.com/kazuhiro4949/items/db2cbcd5bc06c3e0009e)

深く解明していないのでもう少し調べてみます。
もしくは知見のある方教えて欲しいです🙇‍♂️
Nuxt.jsでGoogle Fontsを使う

nuxt.jsで作ったサイトに[Google Fonts](https://fonts.google.com/)を使いたかった。
URL指定で個別に読み込む方法もあるが、今回は[nuxt-webfontloader](https://github.com/Developmint/nuxt-webfontloader)を使った。

# 環境

Mojave 10.14.3（18D109）
node.js v10.11.0
yarn 1.10.1

# 手順

##1. nuxt.jsでプロジェクト作成

```sh
$ yarn create nuxt-app プロジェクト名
```

##2. [nuxt-webfontloader](https://github.com/Developmint/nuxt-webfontloader)をインストール

```sh
$ yarn add nuxt-webfontloader
```

##3. nuxt.config.jsを編集

```javascript:nuxt.config.js
module.exports = {
// 省略
modules: [['nuxt-webfontloader']],
webfontloader: {
  google: {
    families: ['Josefin+Sans']
  }
},
// 省略
}
```

##4. 導入したフォントを使ってみる
```vue:pages/index.vue
<template lang="pug">
  section
    h1 ABCDEFGHIJKLMNOPQRSTUVWXYZ
    h1 abcdefghijklmnopqrstuvwxyz
    h1 1234567890
</template>

<style lang="scss" scoped>
h1 {
  font-family: 'Josefin Sans', sans-serif;
}
</style>
```

```sh
$ yarn dev
```
localhost:3000にアクセス。
![スクリーンショット 2019-03-20 11.10.40.png](https://qiita-image-store.s3.amazonaws.com/0/131949/4b3f0d8b-685a-d322-d39b-4a9f7a343907.png)
CloudFrontのアクセスログを使って特定IPからの不正リクエストをAWS WAFでブロックする - 設定変更編

# はじめに
[CloudFrontのアクセスログを使って特定IPからの不正リクエストをAWS WAFでブロックする - 初期設定編](https://qiita.com/kooohei/items/08899b58658d9fed712c)を設定しました。
ですが、「違うログバケットのログをチェックしたい」「チェックするエラーコードを変更したい」といったことがあると思います。
その変更方法についていくつかまとめてみました。

# 変更リスト
・[参照するログバケットの変更](https://qiita.com/kooohei/items/1821bae6600e1244c1c1#%E5%8F%82%E7%85%A7%E3%81%99%E3%82%8B%E3%83%AD%E3%82%B0%E3%83%90%E3%82%B1%E3%83%83%E3%83%88%E3%81%AE%E5%A4%89%E6%9B%B4)
・[チェックするリクエスト回数の変更](https://qiita.com/kooohei/items/1821bae6600e1244c1c1#%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%81%99%E3%82%8B%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E5%9B%9E%E6%95%B0%E3%81%AE%E5%A4%89%E6%9B%B4)
・[IPをブロックしている期間の変更](https://qiita.com/kooohei/items/1821bae6600e1244c1c1#ip%E3%82%92%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E6%9C%9F%E9%96%93%E3%81%AE%E5%A4%89%E6%9B%B4)
・[チェックするエラーコードの変更](https://qiita.com/kooohei/items/1821bae6600e1244c1c1#%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%81%99%E3%82%8B%E3%82%A8%E3%83%A9%E3%83%BC%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E5%A4%89%E6%9B%B4)

# 参照するログバケットの変更
CloudFrontを導入済みの場合、すでにログ出力を行なっているバケットを利用できた方が便利かと思います。
参照するログバケットの変更は、S3イベントで行います。

## S3イベントの設定
変更先S3バケットのプロパティからS3イベントを選択し、「通知の追加」をクリックして設定を行います。
![スクリーンショット 2019-03-18 14.33.10.png](https://qiita-image-store.s3.amazonaws.com/0/82090/38699695-b9a8-9467-3455-698c35560926.png)

- **名前：** イベント名を入力します。入力しない場合はランダム文字列が付与されます。
- **イベント：** 「すべてのオブジェクト作成イベント」にチェックをします。
- **プレフィックス：** 複数のログを1つのバケットに集約している場合は、出力される場所を記載します。
- **サフィックス：** CloudFrontのログが出力されるファイル形式「gz」を入力します。
- **送信先：** 「Lambda関数」を選択します。
- **Lambda：** CloudFormationで作成されたLambdaを選択します。


## ブロックリストの変更
WAFでブロックされるIPリストはデフォルトではスタック作成時に入力する変数(CloudFrontAccessLogBucket)のバケットに *current_outstanding_requesters.json* というファイル名で出力されます。
参照ログバケットを変更した際は、ここも変更した方が良いです。

```python:変更前
OUTPUT_BUCKET = None
OUTPUT_FILE_NAME = 'current_outstanding_requesters.json'
```

```python:変更後
OUTPUT_BUCKET = <ログバケット名>
OUTPUT_FILE_NAME = '<CloudFront名>_current_outstanding_requesters.json'
```

# チェックするリクエスト回数の変更
デフォルトの設定は１分間に50回です。
回数の変更を行うには、CloudFrontのスタックの更新で `RequestThreshold` のパラメータを変更します。
<img width="1012" alt="スクリーンショット 2019-03-18 15.41.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/82090/81326f8a-0c57-987f-8767-0d3dc477409d.png">
または、Lambda関数内の変数を修正することでも変更ができます。
以下は回数を「50(デフォルト)→100」へ変更した例です。

```python:変更例
REQUEST_PER_MINUTE_LIMIT = 100
```

# IPをブロックしている期間の変更
デフォルトの設定は14400sec(4時間)です。
これもリクエスト回数と同様、CloudFormationのスタック更新で変更できます。
スタックの更新から`WAFBlockPeriod` のパラメータを変更してあげます。
<img width="1012" alt="スクリーンショット 2019-03-18 15.41.19のコピー.png" src="https://qiita-image-store.s3.amazonaws.com/0/82090/1459383a-8103-2e11-0fdc-fc673f1c60fb.png">
または、Lambda関数内の変数を修正することでも変更ができます。
以下は期間を「4時間(デフォルト)→1時間」へ変更した例です。

```python:変更例
BLACKLIST_BLOCK_PERIOD = 3600
```

# チェックするエラーコードの変更
検知対象とするエラーコードの変更も行えます。
デフォルトでは「400, 403, 404, 405」の4つが設定されていますが、ここでの例では「401」だけチェックするように変更します。

```python:変更例
BLOCK_ERROR_CODES = ['401']
```

# おわりに
ドキュメントには設定変更については記載がなかったので色々見てみました。
他にも変更できる部分はありますが、とりあえずここら辺が変更できればとても使いやすくなるかなと思います。
TypeScriptの文字リテラル

TypeScriptの文字リテラルは下記の3つの方法でくくる

1. シングルクォート (')
2. ダブルクォート   (")
3. バッククォート   (`)

3のバッククォートの場合、テンプレート文字列として次のことが可能です

- 文字列に変数を埋め込める
- 複数行の文字列を改行コードなしに埋め込むことができる

例↓

```sample.ts

let x: string = '埋め込み文字列'
let msg = `ここからスタート
           埋め込み文字列 → ${x}
           ここまで`
```
`${x}` の部分が文字列に埋め込まれている変数


シングルクォートで書く場合↓

```sample.ts

let x: string = '埋め込み文字列'
let msg = 'ここからスタート\n 埋め込み文字列  → ' + x + '\n ここまで'
```
Typescript で配列をシャッフルする

 Typescript で配列をシャッフルしたかったので [Fisher–Yates shuffle](https://en.m.wikipedia.org/wiki/Fisher–Yates_shuffle) を実装した話。

調べても ts 版がなかったのでメモ的な。

実装と言っても関数を書いただけ…（簡単だからわざわざ記事とか無いのかも）

```tsx:shuffle.ts
export default function shuffle<T>(array: T[]) {
  const out = Array.from(array);
  for (let i = out.length - 1; i > 0; i--) {
    const r = Math.floor(Math.random() * (i + 1));
    const tmp = out[i];
    out[i] = out[r];
    out[r] = tmp;
  }
  return out;
}
```

swap の部分は es6 だと 1 行で書ける
[ネタ]Qiitaの通知カウント欄をいじって遊んでみる

## 前フリ
こんにちは。
みなさまは Qiita を開いた際に赤い通知の表示があるとなんかわくわくしませんか？**僕はします。**

こんなのです。

|通知なし|
|---|
|![スクリーンショット 2019-03-18 15.05.16.png](https://qiita-image-store.s3.amazonaws.com/0/70638/c6a5e03b-a6e7-c74f-1a08-190415445342.png)|

|<font color="red">なんかきた！</font>|
|---|
|![スクリーンショット 2019-03-18 15.04.05.png](https://qiita-image-store.s3.amazonaws.com/0/70638/169a7a1d-5734-fab9-eb4d-3614986943e0.png)|

通知が赤くなるとテンション上がりますね。消すのがもったいなくなります(**だいたいがまんできなくてすぐ見ますが**)


## 本題
HTMLを少し調べてみたら、クラス属性の付け外しだけで切り替えられそうだったので、スクリプトで簡単に再現できるようにしてみました。

### スクリプトの作成

[以前に使用](https://qiita.com/tommy_aka_jps/items/ef706414bc26fefb9cbd) した UserScript と Tampermonkey の出番です。
カウントアップ用とリセット用のボタンを作成し通知欄の横に並べる、というスクリプトを作成します。

```js:UserScript
// ==UserScript==
// @name         qiita-notification-count-changer
// @namespace    None
// @version      0.2
// @description  通知カウント欄の表示を変える
// @author       tommy_aka_jps
// @match        https://qiita.com/*
// ==/UserScript==

(() => {
  //通知カウント表示エレメント
  const notifyElem = document.querySelector(".st-Header_notifications");

  const main = () => {
    //カウントアップ用ボタン
    const countUpButton = createButton();
    countUpButton.textContent = "+";
    countUpButton.addEventListener("click", countUp);

    //リセット用ボタン
    const resetButton = createButton();
    resetButton.textContent = "C";
    resetButton.addEventListener("click", reset);

    //作ったボタンを設置
    const targetWrapper = notifyElem.parentNode;
    targetWrapper.insertBefore(resetButton, notifyElem);
    targetWrapper.insertBefore(countUpButton, notifyElem);
    targetWrapper.style.display = "flex";
  }

  const createButton = () => {
    const button = document.createElement("button");

    //margin, padding 調整用クラスを流用
    button.classList.add("px-2", "mr-2");

    //スタイル定義
    button.style.display = "flex";
    button.style.alignItems = "center";
    button.style.justifyContent = "center";
    button.style.width = "32px";
    button.style.height = "32px";
    button.style.backgroundColor = "#3f9200";
    button.style.color = "#fff";
    button.style.borderRadius = "4px";
    button.style.fontSize = "1.2rem";
    button.style.position = "relative";
    button.style.cursor = "pointer";

    return button;
  }

  const countUp = () => {
    notifyElem.classList.add("st-Header_notifications-active");
    notifyElem.innerText = parseInt(notifyElem.innerText, 10) + 1;
  }

  const reset = () => {
    notifyElem.classList.remove("st-Header_notifications-active");
    notifyElem.innerText = 0;
  }

  main();
})();
```

### 完成
- <kbd>＋</kbd> を押すとカウントが増えます。
- <kbd>Ｃ</kbd> を押すとクリアされます。

![opbbb.gif](https://qiita-image-store.s3.amazonaws.com/0/70638/c74e5c4b-4cca-979c-f6e2-745a920a1ac2.gif)




気持ちええっすね。**一瞬だけバズった気分になれます。(錯覚)**
バカですね＼(^o^)／

## さいごに
箸にも棒にもかからない薄い記事ですが、最後までお読みいただきありがとうございました。
所詮はリロードでリセットされてしまう紛い物なので、本物の赤い通知欄を見るためにがんばっていい記事を書こうとおもいました。まる。

## 蛇足
ちなみに Advent Calendar の時期だったら、いろんなカレンダーを購読設定しておくと毎日たくさん赤い通知が見れますｗ
初めて開発リーダをした時に策定した開発ルールや実施したこと

半年ほど前に初めて開発リーダを担当した際に、

- 時間に余裕がない
- メンバー間の実力のばらつきがある

というつらい状況をなんとか乗り切るために
`コミュニケーションコストを省くことに重きを置いた`開発ルールを
あらかじめ決めておいたら案外上手くいったのでその時のメモを

# ブランチ運用
途中参加やgitやgithubを使った開発に慣れていないメンバーへのインプットの手間を削減するため

また、複雑なブランチ運用故に起こる不慣れなメンバーのミスを回避して
フォローに時間を取られないようにするため

- どの作業はどのブランチから切るか
- 切るブランチの命名規則
- 元となるブランチの意味

# PRの書き方
レビュイー側の負担を大きくして
ボトルネックになりがちなレビュアーの負担を減らすため

慣れてる人にとっては当たり前でも
不慣れな人にとっては当たり前にできない基本的なことも書いて
コミュニケーションコストカットするため

- チケットのリンクを貼る
- 処理の流れの概要を書く
- 特に見てもらいたい箇所を書く
- 複雑な部分の解説や意図をソース上やPR上でコメントする
- 途中で仕様変更があったりした場合は議論された最終的な結論を書く
- 実装の際に参照したドキュメント(設計書など)を書く
- フロントの実装の場合は一緒にスクショを添える



# テストコードの書き方や参考記事のリンク
テストコードは経験値の差が大きく影響するので知見を共有して
可読性の高いコードを書かせるため
(テストコードのレビューは時間がかかるから。。。)

- 行数が膨れ上がりやすいのでディレクトリ切って`describe`(対象)単位でファイル分割する
- 最低限抑えてほしい異常系の観点
- 可読性やメンテナンス性を上げる
  - letを使ってすっきりしたコードにする
  - スタブやモックを使ってメソッドのテストを疎結合にする
  - など

# 全体的な作業の進め方
全体的なタスクの状況や実装状況を把握するために

- チケットのステータスをこまめに更新する
  - 未着手/進行中/レビュー中/完了のステータスをすぐに反映する
- ブランチ切ったらすぐに[wip]つけたPRを作る
- こまめにpushする

# 質問の仕方
コミュニケーションコストを下げるために

- 質問の意味がわかるように前後のコンテキストを一緒に
- ログに残す意味も兼ねてissueやPR上でやり取りを
- 急がない場合はメンションつけてissueやPRに書いてslackでも投げて待ってる間に別の作業をする
- 動作は問題ないけどコードが気に入らない、とかは一旦完成させてPR上で相談する
- 質問は極力まとめる
  - １つ気になる点があったら他にもないか一通り見てからまとめる
- 不明瞭な部分はそのまま進めず確認する(手戻りがないように

# 便利なもの集
作業効率を上げるために

- コマンドラインのタブ補完を使う
- ショートカットを活用
- オススメのエディタのプラグインなど
Herokuで定期的にrakeタスクを実行したい場合は、Heroku Schedulerを使おう

定期的にrake タスクを実行したい時、
サーバーに入れるならcronに登録すれば良いと思うのですが、
Herokuでは[Heroku Scheduler](https://devcenter.heroku.com/articles/scheduler#dyno-hour-costs)を使う必要があったのでやり方をメモします。

*Heroku Schedulerの実行はベストエフォートのようなので、本番環境で使うには[custom clock process](https://devcenter.heroku.com/articles/scheduled-jobs-custom-clock-processes#custom-clock-processes)という方法が推奨されているようです。

1.プロジェクトフォルダーで`heroku addons:create scheduler:standard`を実行
スケジューラーアドオンが登録されます。

```console
➜  highlights_delivery git:(master) ✗ heroku addons:create scheduler:standard
Creating scheduler:standard on ⬢ hightdeliverer... free
To manage scheduled jobs run:
heroku addons:open scheduler

Created scheduler-asymmetrical-91648
Use heroku addons:docs scheduler to view documentation
➜  highlights_delivery git:(master) ✗ 

```

2.`lib/tasks/scheduler.rake`ファイルを作ります。
このファイルに記述されたtaskがHeroku Schedulerの実行対象です。

```ruby
desc "This task is called by the Heroku scheduler add-on"
task :update_feed => :environment do
  puts "Updating feed..."
  NewsFeed.update
  puts "done."
end

task :send_reminders => :environment do
  User.send_reminders
end
```

3.コンソールで`heroku run rake update_feed`　でタスクのテストができます。今回自分はvagrant使っていて、herokuコマンドはvagrant側にはインストールしておらず実行できない環境だったので飛ばしました

4.`heroku addons:open schedulerk`を実行するとブラウザーでタスクの登録画面が開くので設定します。NEXTDUE（次の実行時間）はUTCなので気をつけてください。
<img width="799" alt="スクリーンショット 2019-03-10 16.14.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/162167/7edd9fbf-2190-425e-8a69-b63eae263f2c.png">


以上で設定終了です。

スケジュールはHerokuのOverviewから確認できます。
<img width="612" alt="スクリーンショット 2019-03-10 16.33.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/162167/8e41c09d-9c71-9cae-58e8-b4f9acfd798f.png">

本番の実行ログが見たいときには、Herokuのログから
schedulerのIDを調べて、 コンソールで`heroku logs --ps scheduler.id`コマンドでschedulerの実行ログだけ表示可能です。

Heroku ViewLogs

``` 
2019-03-10T07:51:03.733908+00:00 app[scheduler.5299]: /app/bin/bundle:3:in `load'
2019-03-10T07:51:03.733910+00:00 app[scheduler.5299]: /app/bin/bundle:3:in `<main>'
2019-03-10T07:51:03.733911+00:00 app[scheduler.5299]: Tasks: TOP => on_a_daily_basis
2019-03-10T07:51:03.733913+00:00 app[scheduler.5299]: (See full trace by running task with --trace)
```

➜  app git:(master) heroku logs --ps scheduler.5299

```
2019-03-10T07:51:03.727169+00:00 app[scheduler.5299]: ICAgIDxwPjU4PC9wPg0KICAgIDxwPi0tLS0tLS0tLS0tLS0tLS0tLS0tLS08
2019-03-10T07:51:03.727170+00:00 app[scheduler.5299]: L3A+DQogICAgPHA+5pel5pys5LyB5qWt44Gr44Gv44CM5L2Z6KOV44GM5qyy
2019-03-10T07:51:03.727172+00:00 app[scheduler.5299]: 44GX44GE44Gq44KT44Gm55SY44GI44Gg44CN44CM44GM44KT44Gw44KM44Gw
2019-03-10T07:51:03.727176+00:00 app[scheduler.5299]: 5L2Z6KOV44KC5L2c44KM44KL44CN44Go44GE44Gj44Gf57K+56We6Ku

```
CocoaPodsを導入したプロジェクトでUITestが必ず失敗する時

UITestを一個だけ実行して失敗を確認した後、システムの出力を見てみてみるとこのような表示があった。
`Library not loaded: @rpath/Alamofire.framework/Alamofire`

割と昔から皆遭遇してる問題のようす
https://github.com/CocoaPods/CocoaPods/issues/5250
https://github.com/CocoaPods/CocoaPods/issues/7558

# 自分の場合の解決策
上記のissueの解決法を参考に対処しました。

本質的な解決法ではないかもしれませんが、以下のようにUITestのターゲット関数スコープを外側へ移したら解決しました。

```shell:from.sh
target 'App' do
    use_frameworks!

    pods 'Firebase'

    target 'AppUITests' do
        pods 'Testingpod'
    end
end
```

```shell:to.sh
target 'App' do
    use_frameworks!

    pods 'Firebase'
end

target 'AppUITests' do
    pods 'Testingpod'
end
```
10日目(2)：Git

プログラムのソースコードなどの変更履歴を記録・追跡するための分散型バージョン管理システム


#Gitコマンドの流れ
![一般的な計算.jpg](https://qiita-image-store.s3.amazonaws.com/0/294402/5ba01d37-0263-601b-aa5b-c53cb0a7587c.jpeg)


##Gitを使う為の準備
```
git init
```

#共同開発の流れ
1. コード変更
2. 共有準備
3. 共有

#コマンド
##共有する準備
###共有したいファイルを選択
```
# git add ファイル名
git add indext.html
```

###コミット
選択したファイルを記録する

```
# git commit -m "適当なメッセージ"
git commit -m "Create index.html"
```

##共有
###リモートを登録
リモートとは、Git共有ファイルの置き場所
また、originはリモート名のこと

```
git remote add origin URL名
```

### **push** リモートにファイルアップロード
```
git putsh origin mastaer
```

### **pull** リモート上のファイルをDL
```
git pull origin master
```

###変更ファイルを把握
追加分を緑色、変更分を赤色で表示

```
# 変更ファイル名を表示
git status

#変更コードを表示
git diff
```

###履歴を見る
```
# コミット履歴を見る
git log

# コミット履歴と変更内容を見る
git log -p
```
laravel で web.php, api.php をぼちぼち卒業してみませんか？ sebastiaanluca/laravel-router のススメ

タイトルのとおりなのですが、 https://github.com/sebastiaanluca/laravel-router が良いのでオススメしたい。

## 導入したらどうなるか

Class で Routing 書けるようになります！

```php
<?php
declare(strict_types=1);

namespace App\Http\Routers;

use App\Http\Controllers\IndexController;
use SebastiaanLuca\Router\Routers\Router;

/**
 * Class IndexRouter
 * @package App\Http\Routers
 */
final class IndexRouter extends Router
{
    /**
     * @return void
     */
    public function map(): void
    {
        $this->router->group([
            'middleware' => ['web'],
            'prefix' => '/',
        ], function () {
            $this->router->get('', IndexController::class)->name('index');
        });
    }
}

```

こんな感じです。

この例では `/` へのアクセスを `App\Http\Controllers\IndexController::__invoke` で受ける例です。

※ 僕は、 single action controller を多用するのが好きなのでこのような使い方を良くします。

もし、  `App\Http\Controllers\IndexController` に `index()` method, `create()` method を用意する場合は、以下のように書けます。

```php
// ..snip..
        $this->router->group([
            'middleware' => ['web'],
            'prefix' => '/',
        ], function () {
            $this->router->get('', IndexController::class.'@index')->name('index');
            $this->router->get('create', IndexController::class.'@create')->name('create');
        });
// ..snip..
```

どうでしょう？

もし、この時点で"あ、良さそう"と思ったら、迷わず https://github.com/sebastiaanluca/laravel-router を導入しても損は無いかと思います。

## 何が嬉しいの？

### まず、 web.php や　api.php にべた書きするのに比べて、 Class になったので **UnitTest が格段に楽に** 書けます。

安心感！大切ですよね。(dusk とかでリクエスト通ればええやん…って話もあるけど、単体で Test Green なの、やっぱりいいよねって。)

### web.php, api.php の肥大化が防げます。

長くなるよね。 diff とか面倒な時も出てくるし…

もちろん、単一の Class で全ての Routing を網羅している状態だと同じことが起きますが、せっかく Class で切り出せるようになったなら、その恩恵を受けて Class 分割してみるのも良さそうでしょ？って。

## もうちょっと嬉しいポイントありそうな気がするけど…いつか覚えてって気が向いたら書いてみる！ :cactus: