OmniAICreator/Qiita-1.07M huggingface dataset:
NeovimでJSDocを使う

# NeovimでJSDocを使う
JSやGASでコードを書いていく時に、コメントはどのように書いているだろうか。
手軽に分かりやすく、コードを共有した人が確認しやすいものはないかと調べた結果、JSDocというものを知った。
**[jsdoc.vim](https://github.com/heavenshell/vim-jsdoc)**を参考にインストールを行った。

## 環境

- macOS Mojave ver.10.14.5
- [Neovim](https://github.com/neovim/neovim)
- [vim-plug](https://github.com/junegunn/vim-plug)（vimプラグインマネージャー）

## インストールの仕方と使い方

```vim:~/.config/nvim/init.vim
" jsdoc
Plug 'heavenshell/vim-jsdoc'
nnoremap j :JsDoc <Enter>
```

上記を`~/.config/nvim/init.vim`に記入した。
>nnoremap j :JsDoc <Enter>
>

の部分は、マッピングをさせている。
通常は`:JsDoc`+`<Enter>`で実行されるので、これを`j`に置き換えた。

これでビジュアルモード時にobjectやfunction上で`j`を押すだけでJSDocが作成される。

以下はJSDocに関しての簡単なまとめである。詳しくは参考文献のリンクを参照にしてほしい。
 
## コメントの構文に関して

 コメントは適切であるかを確かめる必要がある。

```js
/** 
 * JSDocコメントはスラッシュと2つのアスタリスクから始めます。 
 * インラインタグは {@code this} のように波括弧で囲みます。 
 * @desc ブロックタグは必ず行の先頭から開始します。 
 */
```

>[Google JavaScript スタイルガイド - 日本語訳](https://www38.atwiki.jp/aias-jsstyleguide2/pages/14.html)より

## JSDocのインデント
ブロックタグ内での改行が必要な場合はスペース４つ分のインデントが必要。

```js
/** 
 * 長いparam/returnアノテーションの説明文の折り返し方を示します。 
 * @param {string} foo これは1行でおさめるには長すぎるパラメータの 
 *     説明文です。 
 * @return {number} この戻り値の説明文は長すぎて、とても1行の中には 
 *     入りきりません。 
 */
project.MyClass.prototype.method = function(foo) { 
  return 5; 
};
```
>[Google JavaScript スタイルガイド - 日本語訳](https://www38.atwiki.jp/aias-jsstyleguide2/pages/14.html)より

## ファイルへのコメント

`@author`で作成者に関する情報を添付する。

```js
/**
* @fileoverview ファイルの説明を行う。
* 依存関係についての情報
* @author aaa@bbb.com
*/
```

## classへのコメント

```js
/** 
 * Humanクラス 
 * @param {number} height ヒトの身長
 * @param {number} weight ヒトの体重
 * @constructor 
 */
class Human{
  constructor(height, weight){
  this.height = height;
  this.weight = weight;
  }
}
```

## メソッド・関数へのコメント

```js
/** 
 * 日付を処理し、休みの日かどうかでtrueかfaleを返します。 
 * @param {date} date 日付
 * @return {boolean}  
 */
function isSunday(date){
  //...
}
```

## 参考文献
[Google JavaScript スタイルガイド - 日本語訳](https://www38.atwiki.jp/aias-jsstyleguide2/pages/14.html)
[Jsdoc cheatsheet](https://devhints.io/jsdoc)
docker-composeを使ってVue.jsのプロジェクトを作成して、Dockerで動かしてみた

`docker-compose`を使って`Vue.js`のプロジェクトを作成して、Dockerで動かしてみました。

## プロジェクトを作成するディレクトリを作成する
```:directory
/hoge_directory
```

## プロジェクトを作成するための`docker-compose.yml`を作成する
```:directory
/hoge_directory
    |_ docker-compose.yml
```

```:docker-compose.yml
version: '3'
services:
  node:
    image: node:12.7.0-alpine
    volumes:
      - .:/vuejs
```

今回はコンテナ内で作成した`Vue.js`プロジェクトを、ホストに同期させて作るので、
ホスト側の`hoge_directory`とコンテナ内の`/vuejs`をマウントする

```
    volumes:
      - .:/vuejs
```

## `docker-compose`でサービスを起動して、コンテナ内に入る

```:sh
$ docker-compose run node sh
```

## マウントされている`/vuejs`に移動する

```:sh
/ # cd vuejs/
```

## `Vue CLI`をインストールする

今回は`Vue CLI`を使用して、プロジェクトを作成するので、`Vue CLI`をインストールする

```:sh
/vuejs # yarn global add @vue/cli
```

## `Vue.js`のプロジェクトを作成する

```:sh
/vuejs # vue create .
```

上記のコマンドを実行すると、対話式でプロジェクトの設定をしていく

```:YESを選択
?  Your connection to the default yarn registry seems to be slow.
   Use https://registry.npm.taobao.org for faster installation? (Y/n) Y
```

```:YESを選択
? Generate project in current directory? (Y/n) Y
```

```:defaultを選択
? Please pick a preset: (Use arrow keys)
❯ default (babel, eslint) 
  Manually select features
```

```:Yarnを選択
? Pick the package manager to use when installing dependencies: (Use arrow keys)
❯ Use Yarn 
  Use NPM 
```

コンテナ内と、ホスト側に、プロジェクトが作成される

```:コンテナ
/vuejs
    |_ node_modules
    |_ public
    |_ src
    |_ .gitignore
    |_ babel.config.js
    |_ docker-compose.yml
    |_ package.json
    |_ README.md
    |_ yarn.lock
```

```:ホスト
/hoge_directory
    |_ node_modules
    |_ public
    |_ src
    |_ .gitignore
    |_ babel.config.js
    |_ docker-compose.yml
    |_ package.json
    |_ README.md
    |_ yarn.lock
```

### プロジェクトの作成完了！！！

## `docker`で`Vue.js`を動かす

Dockerfileを作成する

```:directory
/hoge_directory
    |_ node_modules
    |_ public
    |_ src
    |_ .gitignore
    |_ babel.config.js
    |_ docker-compose.yml
    |_ package.json
    |_ README.md
    |_ yarn.lock
    |_ Dockerfile <- 作成
```

```:Dockerfile
FROM node:12.7.0-alpine

WORKDIR /myapp

COPY package.json ./
COPY yarn.lock ./

RUN yarn install
```

## `docker-compose.yml`を修正する

```:docker-compose.yml
version: '3'
services:
  view:
    build: .
    command: yarn run serve
    volumes:
      - .:/myapp
      - /myapp/node_modules
    ports:
      - "8000:8080"
```

`Vue.js`プロジェクトをマウントした場合に、
コンテナ側の`node_modules`が上書きされて、削除される場合があるので、
マウントされないようにする

```
volumes:
      - ./vuejs:/myapp
      - /myapp/node_modules <- マウントで上書きされなくなる
```

(プロジェクトが作成される時に作成される`.gitignore`では、
`node_modules`はデフォルトで無視されているので、Gitで共有していると、
コンテナが立ち上がらなくなる)


## サービスを起動して、コンテナを立ち上げる

```:sh
$ docker-compose up -d
```

## アクセスする

```:URL
http://localhost:8000/
```

<img width="1393" alt="スクリーンショット 2019-07-28 13.19.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272551/296c7735-589c-2e1a-c32a-4c218670a076.png">

### 終わり

マウントした時に、`node_modules`が上書きされて、削除されるのは、
なかなかハマりました...

https://github.com/tubutubumustard/vuejs_docker
Pythonの集合型setの基本

# はじめに
Pythonのsetについて最近学習したので基本をまとめる。

# set型とは
set型もシーケンスと似たデータ型で、リストのように複数の要素を保存できる。
（シーケンスとは、複数の要素を持つデータ型のこと。（例：リスト・タプルなど)）
ではリストと何が違うのか。

setはリストと違い、**中の要素が重複されない**ように管理される。
既にsetの中に存在する値を登録しようと思っても、新しい要素が追加されない。
また、インデックスを使って値を取り出すこともできない。

つまり、set型とは**重複しない要素のグループを集合として扱うためのデータ型**。
set型を使うことで複数の集合の集合演算ができる。
要素を集合として扱うため、setに**要素の順番はない**。

# setの定義
setは要素に数値や文字列を追加できる。
setの定義は、**{}**を使用する。

ここで、集合numberに１〜６の整数を要素として定義してみる。

```Python:例
number = {1,2,3,4,5,6}
print(number)

{1, 2, 3, 4, 5, 6} #結果
```

ただし、リストや辞書は変更できてしまうため、setの要素にはできない。

```Python:例
list_num = [1,2,3]
set_num = {list_num,4,5,6}

TypeError: unhashable type: 'list' #結果
```

同様の理由からsetを別のsetの要素にすることもできない。

```Python:例
A_num = {1,2,3}
B_num = {A_num,4,5,6}

TypeError: unhashable type: 'set' #結果
```

ちなみに、重複した値を要素に指定して結果をみてみる。

```Python：例
number = {1,2,3,4,5,6,6}
pirnt(number)

{1, 2, 3, 4, 5, 6} #結果

```


# setの和集合
複数の集合の和集合を考える。
<img width="277" alt="スクリーンショット 2019-07-28 17.22.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429159/7fa2b45e-b9c0-2895-29ae-d59eec4c112c.png">

setの和集合を得る場合、**|演算子**を使用する。
和集合→+演算子を使いそうなところだが、
和集合の場合は重複した要素は足されないため論理和（OR）に近いため、この演算子を用いる。

実際に和集合を計算してみる。

```Python:例
prime = {2,3,5,7,11,13}
number = {1,2,3,4,5}
prime_number = prime | number
print(prime_num)

{1, 2, 3, 4, 5, 7, 11, 13} #結果
```

# setの差集合
複数の集合の差集合を考える。
2つの集合A,Bを与えた時、集合Aから集合Bの要素を取り除く。
<img width="277" alt="スクリーンショット 2019-07-28 17.37.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429159/f365ccb4-01dc-74f0-e68a-a05bd7383ee5.png">

setの差集合を得る場合、**-演算子**を使用する。
実際に差集合を計算してみる。

```Python:例
number = {1,2,3,4,5,6}
even = {2,4,6,8,10}
odd_number = number - even
print(odd_number)

{1,3,5} #結果
```

# setの交わり
複数の集合の交わりを考える。
<img width="277" alt="スクリーンショット 2019-07-28 18.52.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429159/6940bb03-2555-02da-6df4-2a2e66af7f11.png">
setの交わりを得る場合、**&演算子**を使用する。
実際に交わりを計算してみる。

```Python:例
number = {1,2,3,4,5,6}
even = {2,4,6,8,10}
even_number = number & even
print(even_number)

{2, 4, 6} #結果
```

# setの対象差
複数の集合の対象差を考える。
2つの集合の対象差をとると、両方のsetに共通して含まれている要素だけを取り除いた要素の集合を得ることができる。
<img width="277" alt="スクリーンショット 2019-07-28 19.39.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429159/31482f4a-731c-e475-1345-3afba69efb9c.png">
setの対象差を得る場合、**^演算子**を使用する。
実際に対象差を計算してみる。

```Python:例
dice = {1,2,3,4,5,6}
even = {2,4,6,8,10}
not_even_dice = dice ^ even
print(not_even_dice)

{1, 3, 5, 8, 10} #結果
```

# リストからsetへの変換
組み込み関数**set()**を使うとリストをsetに変換することができる。
以下の結果から、setは「重複しない要素の集合」であること、「要素の順番はない」ということも確認できる。

```Python:例
list_alpha = ["A","B","C","D","E","E"]
set_alpha = set(list_alpha)
print(set_alpha)

{'E', 'C', 'A', 'D', 'B'} #結果
```



以上です。
RailsへのBootstrap導入方法

# RailsへのBootstrap導入方法 備忘録

### 1. Gemfile
Gemfileに以下4点を追加する

```
gem "sass-rails", "~>5.0"
gem "bootstrap-sass", "~>3.3.6"
gem "jquery-rails"
gem "jquery-ui-rails"
```

<img width="644" alt="スクリーンショット 2019-07-28 17.18.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442023/ba009dd1-5a63-4c18-f03e-424f36f26644.png">
---------------------------------------

### 2. bundle update
ターミナルにて bundle update を実行

---------------------------------------
### 3. csccファイル変更

ファイル名変更
/app/assets/stylesheets/application.**css** から
/app/assets/stylesheets/application.**scss** へ

末に以下2点を追加

```
@import "bootstrap-sprockets";
@import "bootstrap";
```

<img width="890" alt="スクリーンショット 2019-07-28 17.39.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442023/469f0904-76c8-6495-c423-6b091d7f4467.png">
---------------------------------------
### 4. jsファイル変更

/app/assets/javascripts/application.js

以下2点を追加（図では13、18行目）

```
//= require jquery
//= require bootstrap-sprockets
```

<img width="834" alt="スクリーンショット 2019-07-28 17.48.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442023/55f1d442-6691-ac51-f70d-5d99c339a1fc.png">
---------------------------------------

### 実際に使ってみる
https://getbootstrap.com/
今回はGemfileにてversion3系を指定したので、v3.3.7 を選択

<img width="1351" alt="スクリーンショット 2019-07-28 19.02.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442023/11cf42f1-99ce-e8f5-a31a-cbc9f870d89d.png">

使いたいデザインを探して…

<img width="1440" alt="スクリーンショット 2019-07-28 19.22.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442023/a086625e-8486-0a3e-15de-7e1d09e13aa3.png">

htmlにclassを適用する

<img width="888" alt="スクリーンショット 2019-07-28 19.19.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442023/c0e10d21-3350-59e7-f608-4b7ea569d1c3.png">

<img width="1440" alt="スクリーンショット 2019-07-28 19.24.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442023/0d3e5731-8a87-c6d1-bde5-18abca5ee624.png">

無事にデザインが反映されました
仮想環境構築：Vagrant/ VirtualBox/ Linux

macOSにVagrantとVirtualBoxを使用した仮想環境を構築し、その中にLinuxをインストールする方法の覚え書きです。
# 流れ
- Vagrant ダウンロード・インストール
- VirtualBox ダウンロード・インストール
- Linux インストール 
- Linux を使う

# Vagrant ダウンロード・インストール
https://www.vagrantup.com/downloads.html
# VirtualBox ダウンロード・インストール
https://www.virtualbox.org/wiki/Downloads
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292215/d4eafa53-1d7b-cfa6-659e-c00a1d76bd37.png)

*セキュリティ環境設定でブロックされたら許可してから再度インストール。*

# Linux インストール
## Linux仮想環境をインストールするためのディレクトリを作成
```
mkdir -p ~/vagrant/ubuntu64_16
cd ~/vagrant/ubuntu64_16
```
## Vagrantを実行してLinuxを仮想環境にインストール
```
vagrant box add ubuntu/xenial64
```
上記のダウンロード元は「Vagrant Cloud」という以下のサイト
末尾にURLをつけなければ最新版がダウンロードされる
https://app.vagrantup.com/ubuntu/boxes/xenial64

## Vagrantを実行して仮想マシンの設定ファイルを作成
```
vagrant init ubuntu/xenial64
```

# Linuxを使う
## Vagrantを実行して仮想マシン上のLinuxを起動
```
vagrant up
```
## SSH接続
```
$ vagrant ssh
Welcome to Ubuntu 16.04.6 LTS (GNU/Linux 4.4.0-154-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

0 packages can be updated.
0 updates are security updates.

New release '18.04.2 LTS' available.
Run 'do-release-upgrade' to upgrade to it.


vagrant@ubuntu-xenial:~$ 
```
## SSH接続切断
```
exit
```
## Vagrantを実行して仮想マシン終了
```
vagrant halt
```
HTML で 画面端 に 変な 余白 が 出来てしまった時の 対処法

# 目的
- HTMLファイル作成でプレビューを見たら画面端に謎の余白ができてしまって困った時の対処法をまとめる

# この記事のターゲット
- HTMLやBootstrapの勉強中にプレビューの画面端に謎の余白がheaderからfooterまで入ってしまい困っている方。
- 余白の原因やスペルミスを探しても見つからず泣きたくなっている方
- どんなに頑張っても余白が消えずにHTMLやBootstrapやCSSが嫌になりそうな方

# 押さえるポイント
- コードをじっくり眺めてもミスの発見は至難の業
Google Chromeの検証画面やソースコードの差分を視覚的に表示してくれるアプリを使おう！
- 書いたコードを疑う→設定を疑うの順に悪さしてるところを探す。
- 要素の飛び出しが原因のかも。  
設定が不十分かスペルミスで要素のwidthの設定がおかしくなってしまっている事が多い。
- Google Chromeの検証を用いて余白の原因になっている要素(飛び出してしまっている要素)を探す。

# 具体的な原因の探し方
1. Google Chromeで該当のHTMLファイルを表示する。
1. ブラウザ上に表示されたHTMLファイルの任意の場所で右クリック → 検証をクリックする。
**画像**
1. 検証画面にて下記画像のアイコンをクリックしてマウスポインタで余白部分に飛び出している要素を探索する。
1. 余白部分に飛び出している要素を発見できたらその親要素は余白部分に飛び出していないか確認する。
1. 親要素が余白に飛び出していなかったら、その親要素の要素(タグ)名、クラス名にスペルミスがないか確認する。
1. CSSで要素(タグ)名、クラス名を指定するときにスペルミスをしていないか確認する。
※教材があり、それを元にコーディングしたのに余白が出てしまうときはスペルミスによって設定が反映されないことによる表示の崩れがよくある。

# 筆者が実際に体験した余白の問題
- [Drew Ryan](https://www.youtube.com/user/DrewOnCue)さんの動画の[Responsive Bootstrap Website Start To Finish with Bootstrap 4, HTML5 & CSS3](https://www.youtube.com/watch?v=9cKsq14Kfsw&feature=youtu.be)を見ながら動画の見よう見まねでコードを書いていた時にheaderからfooterまで画面右端に余白ができてしまった。
※画像の赤矢印部分に余白ができていることがわかる。
※青枠はブラウザの表示幅
![余白_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/597509b4-4668-417e-1227-ff2d4c3322d0.png)
![余白_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/187f3405-bcf0-d6d3-0c9c-d642029050af.png)



- 検証モードで原因を探る
Google Chromeの検証モードを起動(Ctrl + Shift + i)し原因を探した。  
赤矢印部分をクリックしてカーソルモード？にして余白部分に飛び出ている要素を探した。
![余白_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/ec2cc7bd-671a-dfe9-0f8b-537f179eb715.png)

- 原因箇所の特定完了
ブラウザ表示幅より飛び出しているcol要素を発見した。
※赤矢印部分がcolクラスのdiv要素が飛び出しているところ
※青枠は正常な表示幅
![余白_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/9100830f-2ba0-cc0c-643f-f510a6294c49.png)

- 親要素は飛び出しているかのチェック
飛び出しているcolクラスのdivの親要素であるrowクラスのdivが飛び出しているかを確認した。
rowクラスのdivも飛び出していることを確認した。
※赤矢印部分のrowクラスのdiv要素が飛び出しているところ
※青枠は正常な表示幅
![余白_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/50e0508a-837b-37e1-e2b6-33494c5bfd3a.png)

- さらに次の親要素は飛び出しているかのチェック
飛び出しているrowクラスのdivの親要素であるcontainerクラスのdivが飛び出しているかを確認した。
containerクラスのdiv要素は飛び出していないことが分かった。
※青枠は正常な表示幅
![余白_7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/3818dd51-e0b6-811a-7726-d331f14c918f.png)

- 飛び出していない親要素をチェック
containerクラスのdiv要素のクラス名や要素名、記載方法に誤りがないか確認した。
containerのスペルがおかしい。(画像右上の赤枠部分)
これだとグリッドシステムの表示がおかしくなる。
![余白_8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/399aac8d-d5b5-165f-4e85-6a726c3724ab.png)

containerのスペルを直したところ、余白はなくなり正常に表示された。

# まとめ
- HTMLでコーディングしたときにできる謎の余白の問題個所の解決方法について記載した。
- HTMLの謎の余白については多くのWebサイトで解決方法が記載されているが、設定を見直す方法がよく記載されている。
- 自分で完全に位置から作成したWebサイトなら設定がおかしい可能性があるが、初心者でコピーコーディングを行ってサンプルとデザインが一致しないのは十中八九スペルミスかだと思われる。(少なくとも自分は今まで詰まったところはすべてスペルミスだった)
- やっとの思いで完成させたWebサイトのデザインの最終仕上げで躓くのはほんとにメンタル的にも来るので、一日空けて再確認をするとミスに気が付きやすい。
【Kotlin】ActivityのLaunchModeについて

#記事を移動しました。
https://zenn.dev/dd_sho/articles/2dcee31a829bed
今後は上記の記事で更新します。（2021/10/03）

Androidアプリ開発でActivityの`launchMode`の設定が結構重要だと感じたので調べたことをまとめます。
特にBack Stackで挙動が大きく変わるので画面遷移の設計とかにもろに影響する内容だと思います。

`launchMode`の設定には２通りあって

- Manifestファイルの`<activity>`タグの属性として設定する方法
- Intentのfragで設定する方法

です。画面遷移毎に挙動を変える場合は２つ目の方法が必要ですが、常に同じ挙動なのであれば１つ目の方法で良いと思います。

# Manifestファイルの`<activity>`タグの属性として設定する方法
`<activity>`タグで設定できる`launchMode`は４種類です。
下記のように設定します。
```ruby:qiita.rb
puts 'code with syntax'
```

```kotlin:Manifest.xml
<activity 
          // 省略

          android:launchMode="standard"

          // 省略
</activity>
```
### standard
- デフォルト値
- Activityのインスタンスがタスク上に生成される
- Back Stackの一番上に追加される
- 複数の異なるタスク上にインスタンスを生成することができるし、同じタスク上に複数のインスタンスを生成することもできる

### singleTop
- Back Stackの一番上にActivityのインスタンスがある場合は新しくインスタンスを生成せずに、既にあるインスタンスを`onNewIntent()`で呼ぶ。
- Activityのインスタンスが存在してもBack Stackの一番上でなければ新しいインスタンスを生成する
![singleTop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139470/69b5161a-22d2-8963-877f-3dd58e42c744.png)
![standard.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139470/b63f030a-f972-6928-ba55-eb2b17044f3c.png)

### singleTask
- 新しいBack StackのrootとしてActivityのインスタンスを生成する
- ただし別のBack Stackの上にActivityのインスタンスが存在する場合は、既にあるインスタンスを`onNewIntent()`で呼び新しいBack Stackのrootにする
- Activityのインスタンスは常に１つ  
![singleTask.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139470/1ca67a6e-8272-1f58-c9cd-a41c214d3faa.png)
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139470/42bd29d5-b56e-ccaf-4d9f-a1cb187ed8d9.png)

 
> Note: Although the activity starts in a new task, the Back button still returns the user to the previous activity.

### singleInstance
- singleTaskとほぼ同じ

#### 注意点
> Note: The behaviors that you specify for your activity with the launchMode attribute can be overridden by flags included with the intent that start your activity, 

Intentのfragで上書きされます。

# Intentのfragで設定する方法
Intentのfragで設定できる値は３種類です。
### FLAG_ACTIVITY_NEW_TASK
- `launchMode`の`singleTask`と同じ

### FLAG_ACTIVITY_SINGLE_TOP
- `launchMode`の`singleTop`と同じ

### FLAG_ACTIVITY_CLEAR_TOP
- `launchMode`に該当するものはない
- 既にActivityのインスタンスが存在する場合、Back Stack上でこのActivityの上にあるインスタンスが全てdestoryされた状態で`onNewIntent()`メソッドで既存のインスタンスが呼ばれる
- `FLAG_ACTIVITY_CLEAR_TOP`と`FLAG_ACTIVITY_NEW_TASK`は一緒に使われることが多い
    - 新しいタスクでインスタンスを生成した時にBack Stackをclearできるから
  
今回の記事は以上です。
Unity Editor上でMRTKv2のハンドインタラクションを検証する方法

# はじめに
Unity Editor上で、MRTKv2のハンドインタラクションを検証する方法が __(調査不足で)__ 公式ドキュメントに見当たらなかったので、キーボードを一つずつ叩き、調査を行いました。その結果をまとめたので、Qiitaで共有したいと思います。

# 結論
ホロラボのデコシさん ([@Ash_Yin](https://twitter.com/Ash_Yin)) にURLを教えてもらい、公式ドキュメントがあることが判明！教えていただき、ありがとうございます！

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">どぞ<a href="https://t.co/3rEIbkNBP7">https://t.co/3rEIbkNBP7</a></p>&mdash; Decoc (@Ash_Yin) <a href="https://twitter.com/Ash_Yin/status/1155389005287968769?ref_src=twsrc%5Etfw">July 28, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

[Input Simulation Service](https://microsoft.github.io/MixedRealityToolkit-Unity/Documentation/InputSimulation/InputSimulationService.html?q=simulation) (公式ドキュメント)

# なぜ調査を行ったのか？
HoloLens 2 から、両手を各関節25点、表裏を認識することが可能で、手のひらをひっくり返すジェスチャーを行うと、メニューを表示することができます。

> <img src="https://img.esa.io/uploads/production/attachments/3505/2019/07/28/10862/88595043-9431-42bd-a1e0-1d1857ff57c6.gif" width="450">
>
> [Hand Constrained Solver (useful for Hand UI)](https://github.com/microsoft/MixedRealityToolkit-Unity/pull/4532) より引用。

ただ実機がない現状でこれを試すことはできないので、Unity Editor上、もしくは、HoloLens 2 Emulator で確認したいというのが調査のきっかけ。

# 調査結果

Unity Editor上でも手を自由自在に操作でき、Hand Menu を表示することができました。

<img src="https://img.esa.io/uploads/production/attachments/3505/2019/07/28/10862/c8b677dc-13f0-4449-b7cf-f4dc8fd9aef1.gif" width="450">

# 基本的な操作方法
A41枚にまとめたので参考までに。

<img src="https://img.esa.io/uploads/production/attachments/3505/2019/07/28/10862/63126ef7-296d-4676-8fde-430df5c8ff5f.png" width="750">

# MRTKv2 プロファイルで定義されている
シミュレーション方法は、__MRTK Profile [Input] > [Input Data Providers] > [Input Simulation Service]__ で設定・管理されている。

<img src="https://img.esa.io/uploads/production/attachments/3505/2019/07/28/10862/fae58e28-1c72-41d5-8038-416dd7fd4170.png" width="450">

デフォルトでは、 __「DefaultMixedRealityInputSimulationProfile」__ が使用されている。
※ 個別に変更を加えたい場合は、プロファイルをCloneして修正すると良い。

> <img src="https://img.esa.io/uploads/production/attachments/3505/2019/07/28/10862/f952071b-5f21-4d62-af55-25b52489a2f6.png" width="450">
>
> <img src="https://img.esa.io/uploads/production/attachments/3505/2019/07/28/10862/e95dbe25-bf52-461a-82d0-dbee0db92236.png" width="450">


# おわりに
細かい操作方法については、[公式ドキュメント](https://microsoft.github.io/MixedRealityToolkit-Unity/Documentation/InputSimulation/InputSimulationService.html?q=simulation)を確認してください。(※ちなみに、MRTKv2を少し触る程度であれば、プロファイルをクローンして変更する必要はないと思います。)MRTKv2導入時に少しでもお役に立てれば幸いです。最後までお読みいただき、ありがとうございました。
【Windows】モニタなしでラズパイ3をセットアップするだけ

<h2>わざわざモニターやキーボード使うのめんどくさくないですか？</h2>
今までNOOBS使っていたのでモニタやキーボードが必要でしたがめんどくさくなったので自分の備忘録としてでもモニタなしでセットアップした話を書いておきます。多くの記事がMacだったのでWindowsでも。

###SDカードのフォーマット
詳しい話は割愛。SDカードフォーマッタを使うのが一番安心です。
フォーマットオプションは上書きフォーマットで。

フォーマットしている間にラズベリーパイ財団のHPにいってOSを落とします。
###OSのダウンロード
https://www.raspberrypi.org/downloads/raspbian/
から落とします。
中の人は案外GUIも使うので「Raspbian Buster with desktop and recommended software」を使用しました。
5G光回線じゃないとダウンロードに失敗するかもしれません。その場合は国内ミラーサイトから落とすといいと思います。

Etcherも落としてきます。
####Etcherのダウンロード
https://www.balena.io/etcher/

④②で落としたZIPファイルを解凍します。
###OSの展開
「（リリース日）raspbian-buster-full」というISOファイルが現れます。

Etcherを開き、ISOイメージを指定、フォーマットが完了したSDカードを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/471662/6330c7eb-ff83-8395-8f22-047177996b6f.png)
####OSの書き込み
「Flash！」をクリックします。
待ちます。

完了したらSDカードを一度抜き、数秒置いてもう一度差し込みます。
###SSHの有効化
bootを開き、何もないところで右クリック→新規作成を。テキストドキュメントを作ります。ssh.txtというものを作ってください。
上の表示タブ→ファイル名拡張子で拡張子を表示します。
F2で名前を変更します。<strong>.txtを削除し「ssh」という拡張子なしのファイル</strong>を作成します。
警告が出るけど無視で結構です。
これでSDカード側の準備は完了。SDカードを抜きます。

ラズパイに差します。この時、<strong>無線LANは設定されていないので有線LANを接続し</strong>電源を投入してください。無線LANを設定する方法もあるらしいけどめんどくさいから割愛。

Advanced IP Scannerを落としてきて開きます。これ、固定IPにしている場合は不要ですが中の人みたいにめんどくさくて固定していない人は非常に便利なツールです。ワンクリックでIPアドレスを調べることができます。

Tera TermとかSSHコンソールを開いて、先ほど調べたIPアドレスを入力。piユーザー+初期パスワードでログインします。

⑩接続完了。初期設定まで行きます。

⑪パスワードの変更から。
###パスワードの変更

```
sudo raspi-config
```

1のパスワードなんちゃらを選択→OKで新しいパスワードを入力します。
あとは同じような手順でWi-fiの設定もします。
I2Cとか使うのであればついでに有効にしちゃいます。
英語設定でもそんなに影響ないので日本語にするかは個人の好みで。日本語化はGUIでやったほうが楽な気がします。

以下はGUIをVNCで使えるようにセットアップする手順です。GUI使わないなら飛ばして大丈夫です。
###VNCでの接続

```
sudo raspi-config
```

でインターフェースなんちゃら→VNC
で有効化します。
お約束を行います。

```
sudo apt-get update
sudo apt-get upgrade
```
OK

```
sudo apt-get install xrdp
```
xrdpをインストールしました。

スタートメニュー→Windowsアクセサリ→リモートデスクトップ
を開いて、ラズパイのIPアドレスを入力、資格情報を入力すると接続できます。
WSL 初期手続き

## 「Windows の設定」変更
スタートメニュー > 設定 を選択
アプリ > アプリと機能 の中の関連設定 プログラムと機能 を選択
Windows の機能の有効化または無効化 を選択
Windows Subsystem for Linux にチェックを入れる
再起動
## 不要？開発者モードの変更
【コラム】開発者モードが不要になったWSL
https://www.buildinsider.net/enterprise/wsl/01
スタートメニュー > 更新とセキュリティ > 開発者向け
再起動
## 不要？ PowerShell ウィンドウでのコマンド実行
管理者モードで PowerShell を立ち上げ、次を実行
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
再起動
## Ubuntu のインストール
スタート > Microsoft Store
Ubuntu で検索
インストール
## Ubuntu の起動+更新
インストールで少し待つ
ユーザ名の設定 atai
パスワードの設定 watasi
sudo apt update
sudo apt upgrade
注意: パッケージの名前 amd64 -> 64bit for amd and intel, x86 -> 32bit for amd and intel
## Ubuntu の開発環境のインストール
sudo apt install build-essential
https://www.yokoweb.net/2018/03/02/windows10-wsl-gcc-install/
## X サーバ VcXsrv の Windows へのインストール
https://sourceforge.net/projects/vcxsrv/
vcxsrv-64.1.20.5.1.installer.exe をダウンロード
Windows 10 の管理者権限で C:Program Files\VcXsrv （デフォルト）にインストール
https://www.atmarkit.co.jp/ait/articles/1812/06/news040.html

VcXsrv を起動
デフォルトのまま選択
configuration を保存して完了
Windows Defender ファイアウォールでブロックされているという警告が出る プライベートネットワークの通信を許可だけに変更（パブリックネットワークは許可しない）

## Ubuntu に X server の設定を追加する
$HOME/.profile に DISPLAY=:0.0 を追加
必要があれば source ~/.profile で読み込みなおす
X window のアプリケーションを起動して確かめる

## WSL のコンソールの高機能版 wsltty を使う（やってない）
https://www.atmarkit.co.jp/ait/articles/1812/13/news031.html

## ウィンドウマネージャ xfce4 を起動する
Ubuntu のターミナルから次を実行
startxfce4
全画面が xfce4 になる
ウィンドウマネージャを閉じてターミナルに戻るには xfce4 の Log Out を選択する
## Ubuntu の作業ディレクトリを Windows 側に設定
Windows のユーザ名を wu1 とかく
Ubuntu 
cd /mnt/c/Users/wu1/Desktop
sudo mkdir UbuntuHome
~/.bashrc の末尾に次の1行を追加
cd /mnt/c/Users/wu1/Desktop/UbuntuHome
ターミナルを立ち上げたときのディレクトリが UbuntuHome になる（ホームディレクトリではない）
 my-web-site.iobb.net/~yuki/2018-03/soft-tool/wsl-ubuntu/
【Unity】コンポーネントのアタッチ時にデフォルト値を自動で設定する

# 環境
- Unity 2019.1.12f1 (Unity 5系 のような古いバージョンでも大丈夫です)


# デフォルト値の設定について
コンポーネントのデフォルト値を設定する際、私はインスペクタを開いて手動で設定していました。この操作、割と面倒ですしヒューマンエラーを起こします。
![イラスト57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246559/9a0056fa-6998-00dc-09ac-4472c925854e.png)

手間を減らせないかと探したところ、`Reset()` という関数が MonoBehaviour クラスには存在しているようです。

# Reset() について
[・**リファレンス**](https://docs.unity3d.com/ja/current/ScriptReference/MonoBehaviour.Reset.html)
([古いバージョン (Unity 5.0) のリファレンス](https://docs.unity3d.com/500/Documentation/ScriptReference/MonoBehaviour.Reset.html)にも存在しています。)

> Reset はインスペクターのコンテキストメニューにある Reset ボタンやコンポーネントを初めて追加するときに呼び出されます。 この関数はエディターモードのみで呼び出されます。Reset はインスペクターでデフォルト値を設定するときにもっともよく使用されます。

`Reset()`は、コンポーネントをアタッチするときに呼ばれる関数です。この関数内でデフォルト値を設定する処理を書けば、アタッチ時にデフォルト値が自動で設定されるわけです。

# 使い方
アタッチするコンポーネントに `Reset()` を定義します。関数内でデフォルト値を設定します。

```HogeComponent.cs
using UnityEngine;
using UnityEngine.UI;

public class HogeComponent : MonoBehaviour
{
    [SerializeField] private Image image;
    [SerializeField] private Text text;

    void Reset()
    {
        if(!text){ text = GetComponentInChildren<Text>(); }
        text.text = "Hoge";
        if(!image){ image = GetComponentInChildren<Image>(); }
        image.color = Color.red;
    }
}
```

後はこのコンポーネントをアタッチするだけです。
↓gifです
![s2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246559/5deb4ebe-0588-1b05-6cd5-2b892facd9e8.gif)

上のように、アタッチした瞬間に参照をつけることが出来ました。
また、参照先のコンポーネントのパラメータの変更もできます。


なお、コンポーネントのアタッチ後に、そのコンポーネントの `Reset()` を定義しても、アタッチ済みのコンポーネントのデフォルト値は設定されません。
アタッチ済みのコンポーネントのデフォルト値を設定する場合は、右クリックメニューから`Reset`を選択することで、`Reset()`が実行されます。
↓gifです
![s3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246559/3eb825a0-d4f0-c56a-9096-c72f53bc94f6.gif)
SkeletalMeshのLODバイアスを強制する

# この検証のゴール
以下のようなことをしたいので、実装可能なのかを検証します

- ゲーム内の特定の場面では設定に関わらず、常にLOD1を使う
- デバッグ機能として、LODモデルをプレビューできるようにする

# 環境
- UE4.22
- Windows 10

LODを作る際に以下のアセットを利用しています
https://www.unrealengine.com/marketplace/ja/slug/ue4-mannequin-mobile
（マネキン欲しさにスターターパックを入れるのは何となくいやだったので）

# LODの設定
基本的な設定手順についてはUE4のドキュメントを参考にしています
https://api.unrealengine.com/JPN/Engine/Content/Types/StaticMeshes/HowTo/LODs/index.html
https://api.unrealengine.com/JPN/Engine/Content/Types/SkeletalMeshes/PerPlatformLOD/index.html


今回は一定のサイズ以下になると、マテリアルを変えて色が変わるようにしています
![lod-screensize-preview.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66889/91e94696-bcd6-fe63-6112-61802082ef10.gif)

SkeletalMeshを開き、「アセット詳細」の「Material Slots」で色変え用のマテリアルをセットして
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66889/ca7b7c3e-3cee-73a7-f0af-2fc7053fdcdc.png)

LOD1で使用するマテリアルを指定することで動画のような動作をさせることが可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66889/0c484d46-047f-a708-a3fa-fd134f645430.png)

変化する距離については、LODSettings側でScreenSizeを設定すれば準備完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66889/525eba2a-31cc-79c9-b6e1-151699269161.png)

# 切り替え処理実装
とりあえず、レベル内にLODの設定を済ませたSkeletalMeshを雑に配置します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66889/2f87d0e1-818f-7fc5-10ec-731845d7d5d7.png)

続いてレベルブループリントで以下のノードを作成します
SkinnedMeshごとに、どのLODを適用させるかを設定します
keybordの'1'でLOD1を、keybordの'2'でLOD2を設定します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66889/b9f61857-df58-f82b-04f2-534f0baecdfd.png)
SetForcedLODについては以下を参照
https://api.unrealengine.com/INT/BlueprintAPI/Components/SkinnedMesh/SetForcedLOD/index.html

# 結果
あとはゲームを開始してキーボードを押せば切り替えを確認できます
![lod-manual-near-preview.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66889/cf791350-513f-d6fd-49d8-17766faf7f66.gif)

ちなみに一度SetForcedLODを行ったMeshについては、そのレベル内では常に設定したLODが適用されます。
LOD1を設定した後、どれだけカメラが離れて小さく映ろうがLOD1のままです。
![lod-manual-far-preview.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66889/dcc6d1f0-1d51-da60-3e38-6de835129ba8.gif)

SetForcedLevelのInNewForcedLODに0を渡すか、
レベルを読み込みなおすと状態がリセットされます。

LODがいくつ存在するかを返してくれるノードもあるので、
BPを少し修正すれば3Dモデルのビューワーなどを作成するときに利用できそうですね
https://docs.unrealengine.com/en-US/BlueprintAPI/Components/SkinnedMesh/GetNumLODs/index.html
環境変数で失敗: Git pullできない(fatal: Not a git repository)

コマンドプロンプトで`git pull`しようとすると`fatal: Not a git repository: 'C:\Program Files\Git\bin'`というエラーが出てしまい、何が何だかわからない事態に陥った。`git-cmd`では動くから`git`自体は問題なさそうなのに、なんでこんなことが起きるのかと思っていたら、「[Gitディレクトリ外からgitコマンドを実行する](https://qiita.com/paty-fakename/items/d592806b6a4d5d2a4b55)」を読んでようやく理解できた。気付きにくい残念な失敗だったので残しておく。

#原因: 意図せず意味のある環境変数"GIT_DIR"を定義していた
Node.jsを実行するコマンドプロンプトを開く際、`PATH`や`PYTHON`などの環境変数を設定したかったので、以下のようなバッチファイルを作っていた。その中で、GitのバイナリへのPATHのつもりで環境変数`GIT_DIR`を定義していた。この環境変数は一時的な用途のつもりだったのだが、悪さをしてしまった。

```:setting.bat
set NPM_DIR=E:\node\9_5_0\npm_global
set NODE_DIR=E:\node\9_5_0
set GIT_DIR=C:\Program Files\Git\bin ←これが良くなかった
set PYTHON=E:\Python\2_7\python.exe
set PYTHON_DIR=E:\Python\2_7
set PATH=%NODE_DIR%;%NPM_DIR%;%GIT_DIR%;%PYTHON_DIR%;%PATH%

cd /d %~dp0
cmd /K npm config set prefix %NPM_DIR%
```
> 環境変数設定画面を開く手間、環境変数が増え過ぎ防止、複数バージョンをインストールすることなどを考慮し、起動用のプロンプトを作っていた。それがこんな悪さをするなんて…

「[Gitディレクトリ外からgitコマンドを実行する](https://qiita.com/paty-fakename/items/d592806b6a4d5d2a4b55)」によると、`GIT_DIR`はgit pull などを実行する際の`.git`の場所を指定するための環境変数ということだった。一時的な環境変数のつもりが、実は意味があって`.git`フォルダを指定してしまったことで、「リポジトリじゃない！」と怒られてしまうのだった。(しかもこの環境変数は、`-C`オプションより強いため、無効化しないといけなかった)

# 対処: GIT_DIRの定義を削除(改名)した
環境変数`GIT_DIR`さえ定義しなければよいので、以下のようにして解決…しょぼい。

```:setting.bat
set NPM_DIR=E:\node\9_5_0\npm_global
set NODE_DIR=E:\node\9_5_0
set GIT_PATH=C:\Program Files\Git\bin
set PYTHON=E:\Python\2_7\python.exe
set PYTHON_DIR=E:\Python\2_7
set PATH=%NODE_DIR%;%NPM_DIR%;%GIT_PATH%;%PYTHON_DIR%;%PATH%

cd /d %~dp0
cmd /K npm config set prefix %NPM_DIR%
```
>もっと別な名前があるかもしれないが、とりあえず動いたのでこれで良し…

# 気を付けること
一時的な用途のつもりで作った環境変数でも、誰かにとって意味があるかもしれない。意図せず何かの設定をいじってしまい、不可解なトラブルを起こす可能性がある。環境変数を作るときは、`MY_abc`とか`TMP_xyz`のような、まず被らない名前を付けるべきだったと思う。
Sprockets::FileNotFoundを解決する。

# エラー出現動作
gemを追加後localhost:3000を更新

# エラー内容
Sprockets::FileNotFound

# 原因
gemを追加する以前にRailsサーバーを立ち上げている。

# 解決
Ctrl + CでRailsサーバーを切り、`rails s`で再起動する。
DockerのみでつくるRailsプロジェクト

## 概要
Railsプロジェクトを作成する際にDocker環境があるのにわざわざローカル環境にRubyを入れて…は効率が悪すぎるので、Rubyコンテナを使用してRailsプロジェクトを作成しました。
忘備録に手順をまとめたので同じようにRailsプロジェクトを作成したい方の助けになればいいと思います。

## 環境
- macOS Mojave 10.14
- Docker version 18.09.2, build 6247962

## rubyコンテナの取得
DockerHubよりRubyイメージを取得

```bash
$ docker pull ruby:2.6.3
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ruby 2.6.3 f1c13927d193 13 days ago 870MB
```

## Gemfileの生成
Rubyイメージからコンテナを作成し、Gemfileを生成する。

```bash
// コンテナの起動
$ docker run --rm -v `pwd`:/myapp -w /myapp -it ruby:2.6.3 bash
// オプション
--rm: 実行後のコンテナを削除
-v:   共有ディレクトリの設定
-w:   ワーキングディレクトリの設定
-it:  コンテナをフォアグラウンドで実行

// Gemfileの生成
root@a1eeb5367697:/myapp# bundle init
Writing new Gemfile to /myapp/Gemfile
```

## Gemfileの編集
Gemfileを編集し、Railsをインストールするように変更する。

```diff:Gemfile
- # gem "rails"
+ gem "rails"
```

## Dockerfile、docker-compose.ymlの作成
コンテナを作成するDockerfileとdocker-compose.ymlを作成する。
各ファイルは下記のようにディレクトリを作成し、配置する。
### ディレクトリ構成

```
├ docker-compose.yml
└ docker
  ├ mysql
  │  ├ volumes ← DB永続化用ディレクトリ
  │  └ password.env
  └ rails
     └ Dockerfile
```

### ファイル内容
```Dockerfile:Dockerfile
FROM ruby:2.6.3
ENV LANG C.UTF-8

RUN set -x && \
    : "前提パッケージのインストール" && \
    apt-get update -qq && \
    apt-get install -y \
        build-essential \
        mysql-client \
        nodejs

RUN set -x && \
    : "パッケージのインストール" && \
    gem install bundler

WORKDIR /tmp
ADD Gemfile Gemfile
ADD Gemfile.lock Gemfile.lock
RUN bundle install

ENV APP_HOME /myapp
RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME
ADD . $APP_HOME
```

```yml:docker-compose.yml
version: '3'
services:
  db:
    image: mysql:5.7.26
    ports:
      - "3306:3306"
    volumes:
      - ./docker/mysql/volumes:/var/lib/mysql
    env_file: ./docker/mysql/password.env
  web:
    build:
      context: .
      dockerfile: ./docker/rails/Dockerfile
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    ports:
      - "3000:3000"
    volumes:
      - .:/myapp
    environment:
      RAILS_ENV: development
    env_file: ./docker/mysql/password.env
    depends_on:
      - db
```

DBのパスワードを設定

```text:password.env
MYSQL_ROOT_PASSWORD=password
```

## Railsプロジェクトの生成
Dockerfile、docker-compose.ymlで定義したコンテナのビルドを行い、コンテナにログインする。

```bash
// コンテナビルド
$ docker-compose build

// コンテナにログイン
$ docker-compose up -d
$ docker-compose exec web bash
// オプション
-d: バックグラウンド実行

// railsプロジェクトの生成
root@477e08f00455:/var/www/CleanManager# rails new . -d mysql -BT
// オプション
-d: DBをmysqlに設定
-B: bundle installを省略
-T: テストファイルの作成を省略

// パッケージのインストール
root@477e08f00455:/var/www/CleanManager# bundle install
```

## railsアプリの起動
コンテナの再起動を行う。
docker-compose.ymlにビルドインサーバを起動するコマンドを記述しているため、別途起動するコマンドを実行する必要はない。
再起動後、ブラウザで http://localhost:3000 にアクセスし起動していることを確認する。

```bash
root@477e08f00455:/var/www/CleanManager# exit
$ docker-compose down
$ docker-compose up -d
```

## まとめ
Docker初心者だったので、よくわからないことがありましたが、なんとか作成することができました。
DBをMySQLからPostgreSQLに変更したかったのですが、PostgreSQLコンテナが起動直後に落ちてしまったのでMySQLで妥協しました。
今後も原因を探して判明しだい、再度記事にしたいと思います。
間違い等ありましたら、コメントから修正お願いします。
IS NULL と NOT EXISTS どっち使う？

最近、現場でIS NULL を書いて、え？と言われたので。

# IS NULL と NOT EXISTS は、同じデータを抽出できる
## 前提
こんなテーブルがあったとします。
*がついているカラムが、PKとします。

T1_TBL

ID *|VAL
|---|---
ID1|VAL1
ID2|VAL2
ID3|VAL3

T2_TBL

NUM *|VAL|ID
|---|---|---
1|VAL1|ID1
2|VAL2|ID2

## 抽出したい結果
T1_TBLに有るけど、T2_TBLに無い T1_TBLのレコードを取得したい。
こんな結果。

ID|VAL
|---|---
ID3|VAL3

## IS NULL の場合
```
SELECT 
 *
FROM T1_TBL a
LEFT OUTER JOIN T2_TBL b
on a.ID = b.ID
WHERE b.NUM IS NULL
```
こう書くと、内部では以下のように疑似テーブルができます。

T1_TBL.ID *|T1_TBL.VAL|T2_TBL.NUM * |T2_TBL.VAL|T2_TBL.ID|
|---|---|---|---|---|
ID1|VAL1|1|VAL1|ID1
ID2|VAL2|2|VAL2|ID2
ID3|VAL3|NULL|NULL|NULL

で、WHERE句で、T2_TBL.NUM(PK)なので、本来NULLにならないけど、
NUM IS NULL条件を加えることで、NULLではない不要な行を省けます。

PK以外で、IS NULLを行うと、NULLのデータも抽出されてしまうので、
必ず、PKを指定します。

T1_TBL.ID *|T1_TBL.VAL|T2_TBL.NUM * |T2_TBL.VAL|T2_TBL.ID|
|---|---|---|---|---|
ID3|VAL3|NULL|NULL|NULL

## NOT EXISTSの場合
```
SELECT 
 *
FROM T1_TBL a
WHERE NOT EXISTS(SELECT * 
                 FROM T2_TBL b
                 WHERE a.ID = b.ID
                 )
```
ですね。

結果は、IS NULL と一緒です。

# 結論
分かり易さ？からすると、NOT EXISTS かな？と思います。
ただ、個人的な好みは、IS NULLです（笑）

あとは、パフォーマンスとの相談ですね。
2回目以降、MAMPでCakePHP環境を作成する方法

どうも、フロントエンドのくらげです。
最近cakePHPに苦しめられることが多くなってきたので、よし久しぶりに勉強するかと思ったのですが、すっかり環境の作り方を忘れてしまっていて時間を取られたので、自分用メモがわりに作り方を置いておきます。
## 作り方
プロジェクト作成にはcomposerを使います。諸々のインストールや設定は１回目に終わっていると…
```composer create-project --prefer-dist cakephp/app tutorial-blog[プロジェクト名]```
これだけ。

## ちなみに
composerはPHPのパッケージ管理システムらしい。npmみたいなものなのかなと思っている。

`composer create-project`
はフレームワークの新規プロジェクトを作成するときのコマンド

`cakephp/app`の部分を`laravel/laravel`などにするとララベルの環境が作れる（前設定必要かも）。

`tutorial-blog`は今回作成するプロジェクト（フォルダ）名

てな感じである。
上記コマンドを叩くと`Set Folder Permissions ?`ってきかれるんだけどデフォルトがyesらしいのでyesにしてる。


こんな感じでとりあえずの環境はすぐ作れます。

## あとはMAMPの設定
MAMPを立ち上げて、左上メニューの、MAMP > reference > Web Server の画面へ。
画面内のDocument Root右のSelectのボタンを押して、先ほど作成したプロジェクト（フォルダ）をファインダーから選択。

## サーバーを立ち上げて完成
ここまでできたら、MAMP内のStart Serverボタンを押して、ブラウザ上に開かれたMAMPのページへ。
ページ内メニューからMY WEBSITEに飛んで赤いCakePHPの画面が開かれれば成功！！！やったね。


ちなみに、
この後DBの設定をするためにconfig/app.phpの`Datasources`を設定するが、MAMPデフォの`username`と`password`はどちらも`'root'`です。
【Python】ルーターやスイッチでshow ip int bを定期的にcsv出力する

#はじめに
**netmiko**はネットワーク機器にSSH接続するためのPythonモジュールです。

netmikoのコマンド実行結果は非構造化データです。
**TextFSM**と**ntc-templates**を利用して、構造化データに変換できるのでcsvにきれいに保存できます。ntc-templatesは様々なネットワーク機器のshowコマンド解析結果を構造化データに変換するためのテンプレート集です。

##ntc-templatesのダウンロード

- [ここ](https://github.com/networktocode/ntc-templates)からzipをダウンロードします
- ホームディレクトリ（Windowsならユーザーのディレクトリ）に展開します
- フォルダ名をntc-templates-masterから**ntc-templates**に変更

Netmikoが自動で~/ntc-templates/templates/indexを参照してくれます。



##コード

netmikoなどのpip installはお忘れなく！

```
$ pip install netmiko
$ pip install schedule
```

以下ソースです。

```python:ssib.py
import netmiko
import pprint
import time
import schedule
import csv

def SIIB():
  device = {'device_type': 'cisco_ios',
            'host': 'Cisco1',
            'ip': 'ネットワーク機器のIP',
            'username': '入力',
            'password': '入力',
            'secret':   'cisco'}

  print('Connecting...')
  conn = netmiko.ConnectHandler(**device)

  print('Enable...')
  conn.enable()

  print('Execute command...')
  # コマンド実行(TextFSMを有効にしてパース)
  result = conn.send_command('show ip interface brief', use_textfsm=True)

  print('SIIB done')
  header = result[0].keys()

  print('SIIB write')
  # DictWriterを使用してCSV形式で出力
  with open('保存ファイル名', 'w', newline='') as f:
    writer = csv.DictWriter(f, fieldnames=header, lineterminator='\n')
    writer.writeheader()        # ヘッダ出力
    writer.writerows(result)   # 結果出力
  
  print('Disconnecting...')
  conn.disconnect()

#以下はscheduleモジュールを使った定期実行部分。
#Ctrl Cで止められます

#一分毎に実行
schedule.every(1).minutes.do(SIIB)

while True:
  schedule.run_pending()
  time.sleep(1)



```


#作っていて困ったこと


- scheduleがちょっと特徴あるなと思いました

#まとめ
netmikoは各ベンダーのコマンドをそのまま使えて便利ですね。
反面、各ベンダー毎にコードを書く手間が出てきそうです。
同じpythonモジュールのnapalmは異なるベンダー機器に対して共通のコマンドを使えるようです。便利そう。
[JavaScript]undifinedをStringオブジェクトの引数に入れたら文字列undifinedに変換されてしまった話

undifinedをStringオブジェクトの引数に入れたら文字列undifinedに変換され、意図しない処理が入ってしまってびっくりしたので、投稿。
JavaScript初心者なので、間違い指摘はコメントください。

結論としては、「undifinedかどうか判断してから文字列変換しよう」です。
　undifinedかどうか判断は、typeof a === "undefined"で比較などで対応しよう。
　(undefinedは、typeof演算子をかけると文字列"undefined"に変換されるため)

実際、どのようにundifinedが文字列に変換されるか見てみましょう。

```javascript
let a;
console.log(a + ":" + typeof a); // undefined:undefined

let b = String(a);
console.log(b + ":" + typeof b); // 'undefined:string'

let c = a.toString(); // Uncaught TypeError: Cannot read property 'toString' of undefined
// console.log(c + ":" + typeof c); 

let d = a + "";
console.log(d + ":" + typeof d); // 'undefined:string'

let e = a.valueOf(); // Uncaught TypeError: Cannot read property 'valueOf' of undefined
// console.log(e + ":" + typeof e); 
```

toStringやvalueOfは例外が生じます。
Stringやobj+""は文字列"undefined"に変換されます。

私の場合、Stringオブジェクトで変換していたため例外が生じず、気づくのが遅れてしまいました。

ただし、Stringオブジェクトは、「toStringでプリミティブ値が返されなければvalueOfを呼び、その値を文字列に変換する」というプロセスとなっているため、文字列変換において安定して使えるようです。
toStringやvalueOf、obj+""では、必ず文字列変換されるという保証がないとのことです。
詳しくは、下記のリンク先を読もう。(現在、勉強中・・・)

[obj+""≠obj.toString()≠String(obj)っていう話 - Qiita](https://qiita.com/alucky0707/items/8d80ca107555489710ea)  より
>toStringはJavaのように文字列の連結に暗黙的に使用されるメソッドではない。
obj+""はまずobj.valueOf()を呼び、obj.toString()を呼ばないことがある（がしかし、実は一つだけ例外がある）。
String(obj)は間違いなく obj.toString() を呼ぶ。


[valueOfとtoStringメソッドの水深43cmぐらいの深さの話 - 三等兵](https://sandai.hatenadiary.org/entry/20100916/p1)  
>オブジェクトを文字列に変換するならtoStringで、数値ならvalueOfという傾向がある。（valueOfの場合正確には基本型に変換すると表現するのが正しい）
toStringのみでオブジェクトを変換するときはvalueOfに一切触れずに行う。逆にvalueOfのみで変換するときは、文字列のときはtoStringを通じて変換する。ただし、toStringが使えないようならそのままvalueOfで返す。
Power Queryで順列出力

順列が何通りかを求めるのではなく、実際にその全通りを発生させるという試みです。
いわゆるクロス結合処理をした後、絞り込むという工程で作っています。
手元のPC（メモリ4GB、Celeron）だと、要素9個から9個を選択する順列で、プレビューが返るのに1分半くらいかかりました。こんなもんでしょうかね:thinking:

###コード
下記のコードを空のクエリに貼り付けて、「fx_順列」という名前をつけてください。

```pq:fx_順列
(InputList as list, NumberOfTimesToSelect as number)=>

if not List.Contains({1..List.Count(InputList)},NumberOfTimesToSelect) then
    "Error:NumberOfTimesToSelectは、1からInputListの要素数までの整数で入力してください。"

else
    let
        Source = Table.FromColumns({InputList}),
        クロス結合 =List.Last(List.Generate(()=>[id=0,tbl =Source],
                                           each [id]<NumberOfTimesToSelect,//―――「NumberOfTimesToSelect-1」だけ列追加するため。
                                           each [id=[id]+1,
                                                 Name="Column"&Number.ToText(id+1),
                                                 Added =Table.AddColumn([tbl],Name,each InputList),
                                                 tbl=Table.ExpandListColumn(Added,Name)],
                                           each [tbl]
                             )
                    ),
        整理 = Table.SelectRows( クロス結合, each List.Union({InputList,Record.ToList(_)})=InputList ),
        重複削除 =Table.Distinct(整理)
    in
        重複削除
```

###実行例1：引数に重複がない場合
赤、青、緑、黄、白の5個の順列、組合せを出してみましょう。
関数を下記のコードを空のクエリに打ち込みます。

```
fx_順列({"赤","青","緑","黄","白"},5)
```
↓実行結果。ちゃんと5の階乗で120行になってますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370992/4083b623-cfd9-be6b-e24c-b7cfbcfb92a4.png)


###実行例2：引数に同じものがある場合
試しに、赤、青、緑、白、白から5個の順列、組合せを出してみましょう。

```
fx_順列({"赤","青","緑","白","白"},5)
```
↓実行結果。重複がある分、減ってます。（この場合は2の階乗だけ重複があるので、それで割ることになる）
※要素に重複があるケースの公式など覚えてないので、興味のある方は調べてみてください。他のケースでも、たぶん結果は合ってます。:sweat_smile:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370992/3e546862-b297-2411-e1bc-a370c7a2cba2.png)


###解説
####「クロス結合」の箇所
列追加で引数に入れたリストを入れて、展開する、の単なる繰り返しです。
個数が決まっているなら、カスタム列追加で当該リストを入れて、展開するという手作業でもいいわけです。

####「整理」の箇所
Table.SelectRowsの第2引数(condition)は、テーブルの行の値(Record型)を引数にした関数の形で書きます。Record型そのままではList.Union関数に渡せないので、Record.ToList関数でリストに変換しています。

List.Union関数は、その行の値がInputListの要素だけで成立しているかを判定するのに用いました。
List.Union関数の挙動は下記の通り。

```
List.Union({{1,1,1,2,2},{2,1,1}})
//第1引数の範囲に収まるので、 {1,1,1,2,2}が返る。

List.Union({{1,2,2,2},{2,1,1}})
//第1引数には1が1個しかないので、 {1,2,2,2,1}とおしりに追加される。
```

>その他参考
[Record.ToList関数：Microsoft Docs](https://docs.microsoft.com/en-us/powerquery-m/record-tolist)
[Table.Distinct(List.Distinct)の使用例 | qiita](https://qiita.com/tanuki_phoenix/items/215a2cd331b34533242d)
Cannot find module '@rails/webpacker' を解決する

# 対象者
Rails5 + webpack のプロジェクトを作成したが、以下エラーが出現する方

# エラー
```terminal
$ bin/webpack-dev-server
The CLI moved into a separate package: webpack-cli.
Please install 'webpack-cli' in addition to webpack itself to use the CLI.
-> When using npm: npm install webpack-cli -D
-> When using yarn: yarn add webpack-cli -D
module.js:557
    throw err;
    ^

Error: Cannot find module '@rails/webpacker'
    at Function.Module._resolveFilename (module.js:555:15)
    at Function.Module._load (module.js:482:25)
    at Module.require (module.js:604:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (.../appname/node_modules/webpack-dev-server/bin/webpack-dev-server.js:64:1)
    at Module._compile (module.js:660:30)
    at Object.Module._extensions..js (module.js:671:10)
    at Module.load (module.js:573:32)
    at tryModuleLoad (module.js:513:12)
    at Function.Module._load (module.js:505:3)
```

# 原因
@rails/webpackerがインストールされていない。

(私の場合、yarnがインストールいなかった為、`rails new app --webpack=vue`実行後にrails/webpackerがインストール出来ない旨のエラーが出力されていた。)

# 解決
yarnをインストールし、Railsプロジェクトを再作成する。

# 手順
### 1. yarnをインストール
```terminal
# インストール
$ brew install yarn

# インストール出来たか確認
$ yarn -v
1.17.3
```

### 2. Rails + webpackプロジェクトを新規作成
```terminal
$ rails new app --webpack=vue
$ cd app
$ rails g scaffold pages
$ rails db:migrate
```
### 3. ファイルを編集

2.のコマンド実行により作成された以下２つのファイル
index.html.erb, routes.rb
を下記のように置き換える。

```ruby:app/views/pages/index.html.erb
<%= javascript_pack_tag "hello_vue" %>

```

```ruby:config/routes.rb
Rails.application.routes.draw do
  root "pages#index"
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

```

### 4. Railsサーバーを起動
```terminal
$ rails server
```

### 5. ローカルホストを確認

http://localhost:3000/ にアクセス

以下のように表示されたら成功。
<img width="998" alt="スクリーンショット 2019-07-28 18.14.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153140/a8518fed-eec1-73b6-8325-d0feb64e9058.png">


以上。

# 参考
https://github.com/rails/webpacker/issues/1295
【firestore】 Cloud Functions for FirebaseからFire Storeへデータ追加する~位置情報(GeoPoint)編~


今開発中のアプリの中でfirestoreにGeoPoint型のデータを追加する処理を書く機会があったので、忘備録も兼ねて記載。

# Cloud FunctionsでFire StoreにGeoPoint型のデータ追加を行う

 GeoPointクラスに関するFirebase公式ドキュメントは[こちら](https://firebase.google.com/docs/reference/android/com/google/firebase/firestore/GeoPoint?hl=en)
(日本語のリファレンスはまだないみたいですね...)


## サンプルコード
今回はサンプルコードとして梅田駅の位置情報をfirestoreに追加するファンクションを書いてみます。

```javascript:index.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
var fireStore = admin.firestore();

  exports.insertHotelRoom = functions.region('asia-northeast1').https.onRequest((request, response) => {
    var dataRef = fireStore.collection('Stations');
    var data ={
        Address:'大阪府大阪市北区梅田1-1-1',
        Area:'梅田',
        Location:  new admin.firestore.GeoPoint(34.421740, 135.295420),
        Name: 'UMEDA STATION'
    }
    // Add a new document with a generated id.
    dataRef.add({
        data
    }).then(ref => {
        console.log('Added document with ID: ', ref.id);
    }).catch(err =>{
        response.send('ERROR HAPPENED.'+err)
    });
  })

```

簡単ですが、以上になります。
シンプルにnew admin.firestore.GeoPoint(緯度,経度)でGeoPointの設定ができるみたいですね。
参考になれば幸いです。

## 参考にした記事
本記事を書くにあたって(というよりもCloud FunctionsからFire Storeを参照する処理について)以下の記事を参考にさせていただきました。

- [cloud functionsでfirestoreを使う](https://qiita.com/kaba/items/35a82b470354b9db29ba)
Vue.jsでポートフォリオサイトを作ってみた

# はじめに
まだ大した内容ができてないですが、最低限のページを作成したので、公開します。
見た目や内容は今後調整していきます。
GitHub Pagesで公開しました。

[ポートフォリオ](https://minuro.github.io/portfolio/)
GitHub: https://github.com/minuro/portfolio

# 環境構築
以下の記事で書いた内容で環境を構築しました。
[Vue.jsの環境構築](https://qiita.com/minuro/items/a7defcb9dbe4ac06856b)

# Vuetify
今回はVuetifyを導入しました。
これは、Vue.js用のマテリアルデザインのフレームワークです。
vueプロジェクトのディレクトリに移動後、以下のコマンドで導入できます。
色々聞かれますが、とくにこだわらなければエンターで大丈夫です。

```
vue add vuetify
```

# 基本的な作り方
簡単に作り方を記載しておきます。
※以下のソースはある程度省略しています。

## ルートの作成
`src/router.js`にページを記載します。
例えば以下のように記載します。

```js:src/router.js
import Vue from 'vue'
import Router from 'vue-router'
import Top from './views/Top.vue' //importを追加
import About from './views/About.vue' //importを追加

Vue.use(Router)

export default new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [ //routesを追加
    {
      path: '/',      //url
      name: 'top',    //ページ名
      component: Top  //コンポーネント指定
    },
    {
      path: '/about',
      name: 'about',
      component: About
    }
 ]
})
```
ルートパスで、`views/Top.vue`にアクセスでき、`ルート/about`のパスで、`views/About.vue`にアクセスできます。

## 表示の作成
`src/App.vue`にあるように、`router-view`を記載した箇所に、先ほどルートで指定したコンポーネントの内容が表示されます。

また、ルートを切り変える際は、`router-link`で記載したリンクから遷移できます。
nameのところには、ルートで指定した名前を記載します。

```vuejs
<router-link :to="{ name: 'about' }">
```

## コンポーネントの作成
`template`タグの中に内容を記載します。
`v-`となっているタグはVuetifyのタグで、詳しくはドキュメントに書かれています。
[Grid system — Vuetify.js](https://vuetifyjs.com/ja/components/grids)

`text-xs-center`や`justify-center`は内容を中央寄せにし、
`row`は要素を横方向に並べ、`wrap`は横方向に入らない際に改行を行います。
`xs12`などは横幅の指定になります。

```vuejs
<template>
  <v-container text-xs-center>
    <v-layout row wrap justify-center>
      <v-flex xs12>
        <h1>About</h1>
      </v-flex>
    </v-layout>
  </v-container>
</template>
```

# GitHub Pages
## ビルド
ファイル作成後は、`npm run build`コマンドを実行することで、プロジェクトがビルドされます。
これにより、ビルドファイルがデフォルトだと`dist`ディレクトリに作成されます。
しかし、GitHub Pagesで公開するためには、`docs`ディレクトリを作成する必要があります。
そのため、以下のように設定を修正します。

まず、プロジェクト直下に、`vue.config.js`というファイルを作成します。
その中に、以下の内容を記載します。

```js:vue.config.js
module.exports = {
    publicPath: process.env.NODE_ENV === 'production'
      ? '/"プロジェクト名"/' //ここは各自のプロジェクト名を入力します。
      : '/',
    outputDir: 'docs',
  }
```
これは、本番環境時は`/"プロジェクト名"/`というパスでファイルにアクセスし、ビルドファイルの出力先ディレクトリを`docs`にするというような内容です。

上記の設定を完了したら、`npm run build`を実行します。

## GitHub Pagesの設定
ビルドを実行して作成された、`docs`ディレクトリをmasterブランチにプッシュします。

GiuHubにて、該当のリポジトリのSetting欄の真ん中ほどにGitHub Pagesという欄があるため、以下のように、Source欄で`master branch/docs folder`を選択します。
<img width="750" alt="githubpages.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311225/0362414d-80ef-1e41-56db-197c8ce1183b.png">

反映されると、`https://"ユーザー名".github.io/"リポジトリ名"/`のURLでアクセスできるようになります。
XAMPPを使ったローカル開発[バージョン : OS X XAMPP-VM(PHP 7.2.10)]


PHP開発の簡単な利用方法についての記述。

XAMPPのインストール方法については、Google検索すると簡単にまとめられている。


◯バージョンは、Mac OS X XAMPP-VM (PHP 7.2.10)です。
2018年10月現在の最新バージョンです。
<img width="1141" alt="スクリーンショット 2018-10-07 14.33.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/299106/34cc0ccd-fdcb-758d-c34d-2c27caca8704.png">

◯PHP記述に使うテキストエディターは、Sublime Textです。
【参考サイト：https://php-archive.net/php/php-texteditor-mac/ 】

<img width="122" alt="スクリーンショット 2018-10-08 11.01.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/299106/f0e970c2-2eaf-e330-27c3-b66404afb3e4.png">


◯利用方法

① General タブ
「 Start 」ボタンをクリック
（開発言語の細かい操作は、Servicesにて可能）
<img width="552" alt="スクリーンショット 2018-10-08 11.11.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/299106/afc8f803-35df-84fb-7f1e-291a6815102c.png">


「 Start 」ボタン押すとこんな感じ↓
<img width="540" alt="スクリーンショット 2018-10-08 11.15.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/299106/bfe01673-3535-12ef-e288-dda67f7ddf16.png">




② Network タブ
使用ローカルホスト（localhost）を選択し、Enableをクリック
今回は、localhost:8080 -> 80(Over SSH)を使用
<img width="537" alt="スクリーンショット 2018-10-08 11.18.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/299106/b1c1091e-490e-e6c1-978d-104a0a2e5b74.png">


実際やってみるとこんな感じ↓
<img width="536" alt="スクリーンショット 2018-10-08 11.23.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/299106/98467c11-2bb5-984e-63ac-eb28e64a9277.png">



③ Volumes タブ
Mountをクリック
<img width="541" alt="スクリーンショット 2018-10-08 11.27.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/299106/1e2c291c-546b-9929-46ee-e11699a0ed4f.png">

デスクトップにXAMPPのディレクトリが表示される
<img width="117" alt="スクリーンショット 2018-10-08 11.00.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/299106/10127cb3-12d4-633d-7e6d-648fd763f970.png">


ディレクトリを開き、[htdocs]内にprojectフォルダを作成。

<img width="594" alt="スクリーンショット 2018-10-08 11.51.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/299106/868e92f8-3e24-9288-285b-6d27bc6d03b6.png">




④ PHPの記述
Sublime Textを開き、適当に記述する
<img width="666" alt="スクリーンショット 2018-10-08 11.41.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/299106/05ad7091-9055-c3ef-a902-9c2f20fd2fb7.png">


test.phpなど適当に名前をつけて、projectフォルダに保存。


④ WEBブラウザにて表示
Google Chromeにて
localhost:8080/project/test.php
上記URLをブラウザで検索。
<img width="1122" alt="スクリーンショット 2018-10-08 11.53.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/299106/2c0f6ad3-72ff-a82e-d0fa-3ad02c3f4964.png">



ブラウザでの表示完了！


バージョンアップがかなり多いので、初心者には苦戦する内容ですが、
チャレンジしてみると案外シンプルでした！

【参考にしたサイトURL : https://blanche-toile.com/web/mac-xampp 】