OmniAICreator/Qiita-1.07M huggingface dataset:
カードの中にアコーディオンを表示したい

# カードの中にアコーディオンを表示したい
そのまんまですがカードの中にアコーディオンを作って表示するようにしてみました。

```
<html>
<head>
<meta content-type="UTF-8">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", () => {
	document.querySelectorAll('div.accordion-hover a').forEach(e => {
		e.addEventListener('mouseover', (e) => {
			if(e.srcElement.getAttribute('aria-expanded') === 'false') {
				e.srcElement.click();
			}
		});
	});
});
</script>
</style>
</head>
<body>
<div class="container-fluid">
	<h2>カードの中にアコーディオンを設定したい</h2>
	<div class="card">
		<div class="card-header"><h6>カードの見出し</h6></div>
		<div class="card-body p-0">
			<div class="accordion accordion-hover" id="accordion" role="tablist" aria-multiselectable="true">
				<div role="tab" id="list1">
					<a href="#list1items" class="d-block" data-toggle="collapse" role="button" aria-expanded="false" aria-controls="list1items">リスト1</a>
					<div id="list1items" class="collapse" role="tabpanel" aria-labelledby="list1" data-parent="#accordion">
						<div class="row no-gutters">
							<div class="col"></div>
							<div class="col"><a href="javascript:alert('1');">リスト1のアイテム1</a></div>
							<div class="col"><a href="javascript:alert('2');">リスト1のアイテム2</a></div>
						</div>
					</div>
				</div>
				<div role="tab" id="list2">
					<a href="#list2items" class="d-block" data-toggle="collapse" role="button" aria-expanded="false" aria-controls="list2items">リスト2</a>
					<div id="list2items" class="collapse" role="tabpanel" aria-labelledby="list2" data-parent="#accordion">
						<div>リスト2のアイテム</div>
						<div>リスト2のアイテム2</div>
					</div>
				</div>
				<div role="tab" id="list3">
					<a href="#list3items" class="d-block" data-toggle="collapse" role="button" aria-expanded="false" aria-controls="list3items">リスト3</a>
					<div id="list3items" class="collapse" role="tabpanel" aria-labelledby="list3" data-parent="#accordion">
						<div>リスト3のアイテム</div>
						<div>リスト3のアイテム2</div>
					</div>
				</div>
			</div>
		</div>
	</div>
<div>
</body>
</html>
```

これだけです。。
これから学ぶWEBサイト制作フロントエンド

## はじめに
後輩への資料を想定してさくっと書いて見たのでペタっとしておきますね。

転職してWEB業界に入ってから1年ちょっと。仕事を通してこのあたりの技術を使いました、という紹介です。初心者向けに、どんなものどの程度勉強すれば良いかという案内になります。

[前に似たような記事](https://qiita.com/nanarya/items/661ec10ff262c84424a6)を書いたんですが、これだと色々と列挙しただけだったので、もう少しピンポイントにどのあたりが役にたったかとかを軽くまとめていければと思います。

また、作業環境によっては使用する技術も変わってくると思うので、もしすでに環境があれば（先輩などがいれば）、デファクトスタンダードを学ぶより、まずはその環境に慣れることを優先した方が良いと思います。

あと、WEBサイトの制作と、WEBアプリケーションの制作で結構毛色が変わると思うので注意です。

## HTML
HTMLはまずはある程度 `HTML5` のタグに慣れましょう。

### pug
あとは `Pug` を覚えておくといいんじゃないかと思います。

```html:index.html
<div class='hoge'>
  hello
  <span>world</span>
</div>
```
これが

```pug:index.pug
.hoge hello
  span world
```

こんな感じになります。
実際の開発ではこうやって省略できたりするメタ言語と呼ばれるものを使用することが多いです。
とりあえず基本的な記法がわかればOKです。
ほかにもmixinやblockなど、色々な機能があるので、余裕ができてきたら調べてみましょう。

## CSS
CSSもまずはCSS3の基本的な書き方を押さえましょう。
ある程度できるようになったら以下のようなところから勉強してみてください。

### CSSメタ言語
こちらは `SCSS` がデファクトスタンダードになるかと思います。

```css:style.css
.box {
  background-color: blue;
}

.box-yellow {
  background-color: yellow;
}

.box .inner {
  padding: 10px;
}
```

これが

```scss:style.scss
.box {
  background-color: blue;

  &-yellow {
    background-color: yellow;
  }

  .inner {
    padding: 10px;
  }
}
```

こんな感じで入れ子に（ネスト）できたりできます。こういった機能によってコードを整理しやすくなります。
覚えたら便利になりますが、ひとまず素のCSSも書けるので、焦らなくても大丈夫です。
そのほかにも色々な機能があるので、こちらも基本的な記法を覚えたらmixinなどを調べてみるのも良いですね。
ちなみにSCSSと書きましたが、「SASS」と呼ばれることもあります。
これは、もともとSASSという言語があって、ただそれが使いづらいとのことで紆余曲折あってSCSSという記法も使えるようにした、という経緯があるからです。なので呼ぶときは「サス」と呼ばれることもありますが、大抵はこちらのSCSS記法を指すんじゃないかと思います。（ちなみに正式名称は「サース」らしいです）
ちなみに個人的には `Stylus` の方が好きです。

### CSS設計手法
このあたりは規模なんかによっても変わってくるのでなんともですが、ひとまず `FLOCSS` （と一緒に `MindBEMding` ）を覚えておくと、他の手法なんかも理解しやすくなってくると思います。
設計というと大仰に聞こえますが、CSSのデータのフォルダ分けや命名のことです。ちなみに、SCSSなどのメタ言語と一緒に使うことが多いと思うので、まずはSCSSの基本的な記法などから先に覚えた方が良いと思います。

## JS
これについてはフレームワークやAltJSの勉強も良いですが、ひとまず `ES2015` と `jQuery` をちゃんと使えるようにしておいた方が汎用性は高いかな、という気がします。
特にES2015の書き方はわかるようになっていないと混乱しやすいところもあるので早めに覚えられるといいでしょう。
フレームワークやAltJSは、プロジェクトで使う場合にはそれに合わせたものを勉強するというくらいで大丈夫だと思います。使うものが環境によって大きく変わるので、周りの人に聞いてみてください。
また、周辺技術として `webpack`, `babel` などはよく使う技術なので合わせて調べておきましょう。

## その他
### Git
`Git` というバージョン管理システムです。今現在、デファクトスタンダードになっている技術なので基本的な使い方は必修と思っていいと思います。
コマンドを覚えても良いですが、初心者には `Sourcetree` などのソフトを使った方が優しいと思います。
ある程度わかるようになったら合わせて `ブランチモデル` などを勉強しておくと役に立つと思います。
また、合わせて `GitHub` や `GitLab` などのホスティングサービスも使えるようになっておくと良いと思います。 `Issue` や `Pull Request` の使い方を覚えましょう。

### MarkDown
簡単な記法でHTMLのようなマークアップがかけるというものです。

```markdown
## その他
### Git
`Git` というバージョン管理システムです。...
```

こんな感じで書いて行きます。
簡単に書ける分、出来上がるのは簡素なものですが、GitHubなどで使えたり、Qiitaの記事もこれで書かれていたりと、何かとお世話になります。

### 開発環境関係
`Homebrew`, `nodenv(anyenv)`, `Node.js`, `npm`, `Webpack`, `Gulp` あたりの単語をサクッと検索してそれぞれの役割を覚えておくといいと思います。
このあたりは1から環境を作るのは少し大変なので、まずは周りの人を真似して同じ環境を作りましょう。
最初は「魔法の呪文で起動できる」で構わないです。まずは使えるようになりましょう。

## まとめ
学ぶことは色々ありますが、焦らず急がず順番に覚えていけば大丈夫です。

まずはマークアップの基本として `HTML5` と `CSS3` を押さえましょう。
それができたら、既存の開発環境に慣れながら `Git` の使い方を覚えていく感じが良いと思います。
ある程度わかるようになってきたら、 `Pug` や `SCSS` を勉強してみましょう。効率がグッと上がると思います。
ここまでできればある程度仕事ができるようになっていると思います。
あとは `Pug` や `SCSS` を深く掘り下げていくなり、 `CSS設計` や `開発環境関係` の技術を勉強してみるなり、気になったところのスキルアップを目指しましょう。

と、これから勉強していく人向けとしてはこんな感じでしょうか。
ご意見ご感想をコメントよりお待ちしてます。
[EC-CUBE4]ワンライナー/必要なPHP拡張ライブラリのインストール

# 環境

- Ubuntu 18.04 / Amazon Linux2
- PHP 7.2  ★当初7.3として記載していましたがComposerコマンドがエラーになるので7.2に変更しました
- ECCUBE 4.0.2
- MySQL 5.6

# 背景

ECCUBE4公式の[システム要件](http://doc4.ec-cube.net/quickstart_requirement)には必要となるPHPライブラリの一覧記載されていますが、「どうやってインストールするの？」という細かい部分は記載されていません。
![](https://i.gyazo.com/8538ba521e050e9b686cfca1ec88af2c.png)

後述した表に記載したようにインストールする際に必要とするパッケージ名はライブラリ名と違うこともありますし、PHPバージョンが必要だったり・不要だったり一貫性がありません。さらに上記の一覧には「標準インストールすれば有効になっている（＝追加インストール不要）」ものも含まれています。

全部を揃えるまで、~~イラッとしました~~面倒でした。こういう機械的な作業はさっとコピペで終わらせたいという人が多いと思うので控えておきました。ご利用ください。

# 結論

結論から書くと以下を実行すればOKです。

## PHP本体(7.2)
### Ubuntu 18.04の場合
```
sudo apt install software-properties-common
sudo add-apt-repository ppa:ondrej/php
sudo apt update
sudo apt install php7.2
```

### Amazon Linux 2の場合
```
amazon-linux-extras install php7.2
```


## 拡張モジュール
### Ubuntu 18.04の場合
```
sudo apt install php7.2-mysql php7.2-common php7.2-mbstring php7.2-json php7.2-xml php7.2-zip php7.2-curl php7.2-intl php-apcu php7.2-opcache php7.2-sqlite
```

### Amazon Linux 2の場合
```
yum install php-mysql php-common php-mbstring php-json php-xml php-zip php-cURL php-intl php-apcu php-opcache php-sqlite
```

#### SQLiteの拡張モジュール(php7.2-sqlite php-sqlite)を含めている理由
[ECCUBEのコマンドラインインストール時](http://doc4.ec-cube.net/quickstart_install#%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%83%A9%E3%82%A4%E3%83%B3%E3%81%A7%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)に自動的にSQLiteが利用されるためです。インストールしていないとデータベース作成処理で以下の実行エラーが発生します。

```
Script bin/console doctrine:database:create handling the installer-scripts event returned with error code 1
```

## 有効になっているPHPモジュールの確認

```bash
$ php -m
```

# 付録

## ライブラリ名と（インストール時に利用する）パッケージ名

| 拡張名 | 必須or推奨 | パッケージ名 |
|:--|:--|:--|
| mysqli | 必須 | php7.2-mysql |
| pdo_mysql | 必須 | php7.2-mysql |
| pdo | 必須 | php7.2-common |
| phar | 必須 | php7.2-common |
| mbstring | 必須 | php7.2-mbstring |
| zlib | 必須 | デフォルトで有効<br>自身でコンパイルする場合`--with-zlib`を指定 |
| ctype | 必須 | php7.2-common |
| session | 必須 | デフォルトで有効 |
| JSON | 必須 | php7.2-json |
| xml | 必須 | php7.2-xml |
| libxml | 必須 | デフォルトで有効 |
| OpenSSL | 必須 | デフォルトで有効<br>自身でコンパイルする場合`--with-openssl`を指定 |
| zip | 必須 | php7.2-zip |
| cURL | 必須 | php7.2-curl |
| fileinfo | 必須 | php7.2-common |
| intl | 必須 | php7.2-intl |
| hash | 推奨 | デフォルトで有効 |
| APCu | 推奨 | php-apcu |
| ZendOPcache | 推奨 | php7.2-opcache |


## 各ライブラリ名(php extensions)の詳細やインストール手順

上記の表でオプション指定して 自身でPHPをコンパイルする時のオプション指定について記載していますが、こういった情報は、[PHP公式マニュアル](https://www.php.net/docs.php)の画面右上のボックスにライブラリ名を入力すると`Extensions`という見出しの中にリンクが表示されるので、そこをクリックするともろもろ確認できます。

![](https://i.gyazo.com/9eb951c613c5c9895cf5236a1841060f.png)

![](https://i.gyazo.com/0b4239152c4561d6e160d60a8512bee6.png)
Mysql_常用SQL

system関係
--
文字コード確認：
SHOW VARIABLES LIKE 'character_set%';

limit
--
SELECT *
  FROM sales
 ORDER BY sale_date DESC
 LIMIT 0,10

更新するデータをNULL値にする
--
UPDATE t_jisseki 
SET
  `State` = 1
, `StartActTm` = NULL
, `EndActTm` = NULL
WHERE
  `BushoCd` = 10 
  AND `ShainNo` = 1234 

全角スラーを半角に一括置換
--
(特殊マークのため、前に円マークを付ける)
UPDATE t_bunsyo 
SET
  FileNm = REPLACE (FileNm, '\＼', '\\') 

groupby時、空白ある場合、空白を最大値'99999999'で取得する
--
SELECT
  orderno
  , MAX(IF (EndDt = '', '99999999', EndDt)) 
FROM  t_order 
GROUP BY  orderno
iOS-Chartsの注意点

#環境
Xcode 10.2.1, Swift5
[danielgindi/Charts: Beautiful charts for iOS/tvOS/OSX\! The Apple side of the crossplatform MPAndroidChart\.](https://github.com/danielgindi/Charts)
version 3.3.0

インストール方法は、
[ios\-chartsに関する記事 \- Qiita](https://qiita.com/tags/ios-charts)
の他の記事読めば出てくるので割愛。

#個人的に躓いた点
IAxisValueFormatterのdelegateをViewControllerにすると、deinitされなくなるので、
IAxisValueFormatterを継承した子クラスを作成する

##解放されるケース

```swift:CombinedChartViewController.swift
chartView.xAxis.valueFormatter = XAxisValueFormatter()

class XAxisValueFormatter: IAxisValueFormatter {
    let months = ["Jan", "Feb", "Mar",
                  "Apr", "May", "Jun",
                  "Jul", "Aug", "Sep",
                  "Oct", "Nov", "Dec"]
    
    // X軸のラベルを設定する
    func stringForValue(_ value: Double, axis: AxisBase?) -> String {
        return months[Int(value) % months.count]
    }
}
```

##解放されなくなるケース（DemoのCombinedChartViewController）

```swift:CombinedChartViewController.swift
extension CombinedChartViewController: IAxisValueFormatter {
    func stringForValue(_ value: Double, axis: AxisBase?) -> String {
        return months[Int(value) % months.count]
    }
}
```

##なぜVCだと解放（リーク）されないのか
・パット見delegate protocolのように定義されているかつ、
Demoや他の記事でも、チャートを表示するViewControllerのextensionでIAxisValueFormatterを実装しているが、
実はライブラリ内で弱参照でなく強参照している為、解放されなくなる。
・Issueとして上がってるが、それなりの修正が必要なようで保留になっている。
[Should valueFormatter property use weak modifier? · Issue \#1873 · danielgindi/Charts](https://github.com/danielgindi/Charts/issues/1873)
・強参照しているのが原因なので、
viewWillDisapperでchartView.xAxis.valueFormatter = nilにしても解放される。
Log4Net自身のデバッグログを出力する方法

下記URLのHow do I enable log4net internal debugging?を参照していただくとトレースログにlog4net自身のデバッグログを出力する方法が説明されています。
Apache log4net Frequently Asked Questions
http://logging.apache.org/log4net/release/faq.html

以下をアプリケーションコンフィグファイル(hogehoge.exe.config)に記載します。

```
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <appSettings>
        <add key="log4net.Internal.Debug" value="true"/>
    </appSettings>
</configuration>
```
Laravel5.3からController __construct からAuth::user()アクセスできないですが、裏ワザある

```php

class PointCardSwapController extends Controller
{
 
    protected $name;

    public function __construct()
    {

        $this->middleware(function ($request, $next) {
            $this->name = \Auth::user()->name;
            echo $this->name;
            return $next($request);
        });

    }

}
```

参考
https://github.com/laravel/docs/blob/5.3/upgrade.md#session-in-the-constructor
Oracle_常用SQL

row_number()
--
①
select * from
(
select
row_number() OVER(ORDER BY SEQ) as row_number
,ID
,SEQ
,NOTE_TEXT
from
 Table) A
where row_number>=1488987

②rownumはoracle default 並べ順の行番号、Orderしていません
select
rownum
,ID
,SEQ_NO
,TEXT
from
Table
where rownum<10


like
--
select * from A
where TEXT like '%޼%'
ロジスティック回帰を使ったモデルトレーニング-Breast Cancer Wisconsin (Diagnostic) Data Set-

#やりたいこと
ロジスティック回帰モデルのトレーニングを体験してみる。

###ロジスティック回帰（Logistic Regression）
重回帰モデルは目的変数が何かのサイズを予測するなどの数値であるのに対して、ロジスティック回帰ではどのカテゴリに属するかを扱う。つまり、あるカテゴリに属する確率を算出する。例えば、がんの良悪性判別など。（このようなデータをカテゴリ変数という。）

####重回帰との違い
分類タスクの学習に交差エントロピー誤差関数などを用いる。この誤差が最小になるように学習を行う。

#環境
Python 3.6.8
scikit-learn 0.21.x

#コード
```
'''
Created on 2019/05/14

@author: tatsunidas
'''

#ロジスティック回帰のモデルインポート
from sklearn.linear_model import LogisticRegression

#オッズ算出用
import numpy as np

#訓練データとテストデータを分けるファンクション
from sklearn.model_selection import train_test_split

#データの読み込み
from sklearn.datasets import load_breast_cancer
dataset = load_breast_cancer()
#データの詳細
# print(dataset.DESCR)

#目的変数(y)と説明変数(X)を設定
X = dataset.data
y = dataset.target#[0 = 'malignant' 1 = 'benign']

#訓練データとテストデータに分ける
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.5,random_state=0)

#重回帰の初期化
model = LogisticRegression()
#学習
model.fit(X_train, y_train)

#正解率を表示
print('精度[train] %.3f ' %model.score(X_train, y_train))
print('精度[test] %.3f ' %model.score(X_test, y_test))

#各変数の係数を見てみる
# print(model.coef_)

#オッズ比
# print(np.exp(model.coef_))

#標準化（standardization, 平均が0、分散が1となるようにデータを変換すること）を取り入れて比較する
#標準化のためのクラスをインポート
from sklearn.preprocessing import StandardScaler
#標準化の実施
ss = StandardScaler()
ss.fit(X_train)
X_train_std = ss.transform(X_train)
X_test_std = ss.transform(X_test)

#ロジスティック回帰クラスの初期化と学習
model_ss = LogisticRegression()
model_ss = model_ss.fit(X_train_std,y_train)
#正解率を表示
print('精度(標準化あり)[train] %.3f ' %model_ss.score(X_train_std, y_train))
print('精度（標準化あり）[test] %.3f ' %model_ss.score(X_test_std, y_test))
```
#結果
/home/tatsunidas/.conda/envs/py36/lib/python3.6/site-packages/sklearn/linear_model/logistic.py:433: FutureWarning: Default solver will be changed to 'lbfgs' in 0.22. Specify a solver to silence this warning.
  FutureWarning)
精度[train] 0.968 
精度[test] 0.958 
/home/tatsunidas/.conda/envs/py36/lib/python3.6/site-packages/sklearn/linear_model/logistic.py:433: FutureWarning: Default solver will be changed to 'lbfgs' in 0.22. Specify a solver to silence this warning.
  FutureWarning)
精度(標準化あり)[train] 0.989 
精度（標準化あり）[test] 0.979 

※将来の修正に関するsklearnの注意が出ているが、これは無視する。

#参考図書
* 東京大学のデータサイエンティスト育成講座
JavaScriptでJSONが不正かどうか判定する関数

JSONを文字列からパースするための関数として`JSON.parse()`が存在するが、不正な文字列を与えた時には`SystaxError`をthrowすることを利用して下記のような関数を実装できる。

```javascript
isValidJson(value) {
  try {
    JSON.parse(value)
  } catch (e) {
    return false
  }
  return true
}
```
【WordPress】自作テーマ, cssの読み込み

wordpressのテーマ開発において、
テーマのcssファイルを読む方法。

## その1
bloginfo関数を使う。bloginfo()はwordpress管理画面で設定してある、いろいろ（タイトルとかキャッチフレーズ、urlとか）を取れる関数。

```php
bloginfo('stylesheet_url');
```
[公式リファレンス](https://wpdocs.osdn.jp/%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%82%BF%E3%82%B0/bloginfo)

### 使用例
```php
<link rel="stylesheet" href=<?php bloginfo('stylesheet_url'); ?>>
```


## その2（公式推奨
css取る専用の関数を使う。公式推奨。

```php
get_stylesheet_uri();
```
[公式リファレンス](https://wpdocs.osdn.jp/%E9%96%A2%E6%95%B0%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9/get_stylesheet_uri)

### 使用例
```php
<link rel="stylesheet" href=<?php echo get_stylesheet_uri(); ?>>
```

get関数は値をreturnしてくるので、echoを書くのを忘れずに。


どちらも、現在適用されているテーマのcssファイルを自動的に出力してくれる記述。
（※テーマファイルでは、ルートにcssを置いておかないといけない。これはそのルートまでのパスを通すもの。cssファイルをassetsフォルダを作ってその下に置く、などはできない。）
Magic Leap MagicScript Landscape Application. Casting

**Prepare**
Magic Leap One
https://www.magicleap.com/magic-leap-one

mlsdk v.0.20.0
https://creator.magicleap.com/downloads/lumin-sdk/overview

magic-script-cli v2.0.1
https://www.npmjs.com/package/magic-script-cli

magic-script-polyfills v2.1.1
https://www.npmjs.com/package/magic-script-polyfills

Casting(Please read if you do not know.)
https://creator.magicleap.com/learn/guides/design-casting

**Create Project**

```
magic-script init my-cast org.magicscript.cast "Cast"
cd my-cast
```

**Code**
Change manifest.xml

```xml
<manifest xmlns:ml="magicleap"
          ml:package="org.magicscript.cast"
          ml:version_name="0.0.1"
          ml:version_code="1">
  <application ml:visible_name="Cast"
               ml:application_type="untrusted"
               ml:sdk_version="1.0">
    <component ml:name=".universe"
               ml:visible_name="Cast"
               ml:binary_name="bin/index.js"
               ml:type="Universe">
      <mode ml:shareable="true"/>
      <icon ml:model_folder=""
            ml:portal_folder=""/>
    </component>
    <uses-privilege ml:name="MagicScript"/>
    <uses-privilege ml:name="CopresenceAccess"/>
    <uses-privilege ml:name="PwCastingMap"/>
  </application>
</manifest>
```


**Build**

```
magic-script build -i
```

**Run**

```
magic-script run --port=10000
```

**Reference**
https://creator.magicleap.com/learn/guides/sdk-lrt-casting-overview
https://creator.magicleap.com/learn/tutorials/hello-other-cube-casting

magicscript
https://www.magicscript.org/

Thanks!
ラズパイでマジックミラー、準備その1

ラズパイで[こちらのMagicMirror2プロジェクト](https://magicmirror.builders/)を前からフォローしてまして、ついに暇つぶしに自作してみようと思っています。

実現したい機能としては、

## ハード面

* 4Kモニターで高精細な画像・文字表示
* できるだけ普通の鏡に近い薄さ

## ソフト面（最小限）

* Google Assistantの音声対応
* 天気表示
* 日程表示

## 心配点

4Kモニター中の安い方を検討しています。パネルを取り出す必要があるので、モニターをどこまで分解できるのがまだ不明です。

* [LG 24UD58](https://pasotan.com/monitors/7kgg) - 3万円台のIPS
* [JAPANNEXT IPS2702UHDR](https://pasotan.com/monitors/bwqz) - 4万円弱IPS, HDR対応


手元にあるRP3Bの4Kでのリフレッシュレートは15Hzのようで、マジックミラーは主に情報の表示なので、特に問題ないかと思っています。
本当にダメだったら、RPの4K完全対応な競合製品（出費が増えるのが）にすれば解決できそうです。

あとはどこまで日本語化できるかのところがちょっと心配ですね。

経験のある方々、ぜひアドバイスしてください。
【SpringBoot】producesを設定したエンドポイントでHttpMediaTypeNotAcceptableExceptionになった場合の対処

# 原因
`produces = "text/csv"`が設定されているのにJSONを返そうとしたことが原因でした。

# 状況
状況は以下の通りです。

## 実現したかったもの
- csvを返す（`produces = "text/csv"`を設定）エンドポイントを立てる
- 集計エラー時はステータス400で、JSONにエラー内容を詰めて返す

実際には以下のようなアノテーションを付与していました。

```java
@PostMapping(value = "[エンドポイント]", produces = "text/csv")
```

## 起きたこと
- エラー時にステータスが406になる
    - エラー内容も空になる
- サーバーサイドでは`HttpMediaTypeNotAcceptableException`が発生する

# 対策
`produces`の指定を無くせばOKでした。

```java
@PostMapping(value = "[エンドポイント]")
```

[`produces`を指定しない場合場合はよしなに扱われる](http://blog.64p.org/entry/2016/09/27/213704)ようなので、問題が出なければ指定しなくてもよいと思われます。

## 補足
動的かつ明示的に指定する必要がある場合、`HttpServletResponse`を用いてレスポンスを直接書き込む方法が考えられます。
その場合は以下のようにして書けます。

```java
@PostMapping(value = "/api/csv")
public void csv(HttpServletResponse response) {
    String csv = // CSV取得処理;

    response.setHeader(
            "Content-Disposition",
            "attachment;filename=\"" + /* ファイル名 */ + "\""
    );
    response.setCharacterEncoding("Shift-JIS");
    response.setContentType("text/csv");

    try (Writer writer = response.getWriter()) {
        writer.write(csv);
    } catch (IOException e) {
        // エラー処理
    }
}
```

# 感想
エラー処理は`ExceptionHandler`を用いて共通化していましたが、コントローラーで設定した`produces`がそこまで貫通してくると思わず原因特定に時間がかかってしまいました。
`HttpMediaTypeNotAcceptableException`とは書いてあったんですが……。

# 参考にさせていただいた記事
- [@RequestMapping の produces を指定するとどうなるか \- tokuhirom's blog](http://blog.64p.org/entry/2016/09/27/213704)
- [Springで直接Responseデータを書き込むには \- Qiita](https://qiita.com/d-yosh/items/ad26f2806e9e91ce0b2b)
CentOSのhttpdが起動しません

昨日5/13までＯＳ(CentOS7)起動時にhttpdは自動的に立ち上がっていましたが
本日5/14は立ち上がりません。
![20190514-Q1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416420/2b5d3841-5b49-41cb-7f46-7e1d7af172ae.jpeg)

設定などを変更した事実はありません。
使用環境(場所)は異なります。
自分でも調査しますが、なにかキーワードなどに
気づく方がいましたら教えていただければと思います。
Linux初心者ですが、よろしくお願いいたします。

→その後OS再起動を２回目（May 14 15:40) にて不具合は復旧してしまいました。
　本日5/14に施した処理はプロセス再起動、OS再起動です。

→その後、やはりhttpdはダウンしていました。
![20190514-Q2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416420/79e2f62c-63b4-14d8-dbd1-5d2650458cd0.jpeg)

　本日5/14に施した処理はプロセス再起動、OS再起動です。
アドバイスいただけましたら、よろしくお願いします。
XAMP/MAMPでのLaravel注意点　文字数やマイグレーション

# MAMP環境でマイグレーションができなかった

会社のWindowsPCのXAMPPでLaravel開発をしている時は特につまづく事無くスムーズに事が運んでいました。
しかし、自宅のMacPCで開発となると全くマイグレーションが成功せず、開発ができなくなってしまいました！
Macの場合はXAMPPでなくMAMPを使うため、環境が違うせいで設定の仕方が変わるのです。

やっと解決方法がわかったので、ここに記録します。

#１、バージョンの低いLaravel

Laravelのバージョンが低いとマイグレーションで失敗する可能性があります。

デフォルトのマイグレーションファイルはDBに反映されるのに、自作したマイグレーションファイルが反映されないパターンの時は、バージョンが低い事が原因だったりします。

```
Laravelはデータベース中への「絵文字」保存をサポートするため、
デフォルトでutf8mb4文字セットを使っています。
バージョン5.7.7より古いMySQLや、バージョン10.2.2より古いMariaDBを使用している場合、
マイグレーションにより生成されるデフォルトのインデックス用文字列長を
明示的に設定する必要があります。
AppServiceProvider中で
Schema::defaultStringLengthを呼び出してください。
```

### 解決策

##### １、AppServiceProviderに追記する

app\Providers\AppServiceProvider.phpのuseのところに

```
use Illuminate\Support\Facades\Schema;
```
を追記します。さらにboot関数の中に

```
Schema::defaultStringLength(191);
```
を追記します。

これでマイグレーションが通るようになります。

##### ２、そもそもバージョンの高いLaravelを入れる

Laravelをインストールする際にバージョンを簡単に指定してしまえば解決します。
古いLaravelだとFORM::が使えなかったりしますしね！
5.7以上をインストールするのであれば

```
composer create-project --prefer-dist laravel/laravel 名前 "5.7.*"
```

このようにインストールします。

# 2、MAMPは少し面倒

MAMPでマイグレーションをする場合には、config/database.phpに追記をしないといけません。

```
'mysql' => [
            'driver' => 'mysql',
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            // 追記 ↓
            'unix_socket'   => '/Applications/MAMP/tmp/mysql/mysql.sock',
        ],
```

そして.envファイルの設定は

```
DB_CONNECTION=mysql
DB_HOST=localhost
DB_PORT=3306
DB_DATABASE=データベース名
DB_USERNAME=root
DB_PASSWORD=root
```

XAMPPだと127.0.0.1だったりパスワード無しだったりするので、少しややこしいですね。

自分はこれらを修正した事でマイグレーションが通るようになりました。
複数のサーバへのsshコマンドを非同期で実行する

特定のサーバについて

1. ファイルのバックアップ作成
2. ローカルの圧縮ファイルをアップロード
3. 圧縮ファイルをサーバ上で展開してなにかする

などのように、一連のコマンドを複数台のサーバで一気に実行したかったので、以下のようなコマンドで実行していました。  

```sh
for i in $(seq 1 10);
  do ssh server${i} 'tar ...';
    scp ./archive.tar.gz server${i}:/home/user/;
    ssh server${i} 'tar ...; some commands ...';
done
```

ただ、この方法では同期処理なのでサーバ台数が増えれば増えるほど時間がかかってしまいます。
以下は、sleepコマンドを3台のサーバ上で実行する例です。 3秒の sleep * 3台 ということで9秒かかっています。

```sh
time for i in $(seq 1 3);
  do ssh vagrant-local-ubuntu16-20190401 "echo ${i}; sleep 3; echo ${i}";
done

1
1
2
2
3
3

real    0m9.955s
user    0m0.045s
sys     0m0.185s
```

サーバ1台に対して実行する処理が1～3まであるとした場合、この順序さえ崩れなければ、サーバ A に対する処理とサーバ B に対する処理が同時に実行されても何ら問題はありません。
なので、サーバごとの処理を非同期で実行することで時間短縮を図ります。

```sh
time for i in $(seq 1 3);
  do ssh vagrant-local-ubuntu16-20190401 "echo ${i}; sleep 3; echo ${i}" & ;
done
-bash: 予期しないトークン `;' 周辺に構文エラーがあります
```

どうやら for で繰り返し実行するコマンドをバックグラウンドで実行する場合は done の前に「;」を含ませてはいけないようです。

```sh
time for i in $(seq 1 3);
  do ssh vagrant-local-ubuntu16-20190401 "echo ${i}; sleep 3; echo ${i}" & 
done
```

「;」を除いて再実行すると問題なく動きました。
約3秒後に3台分のコマンドが完了しました。

```
time for i in $(seq 1 3);
  do ssh vagrant-local-ubuntu16-20190401 "echo ${i}; sleep 3; echo ${i}" &
done
[1] 17172
[2] 9824
[3] 11896

real    0m0.077s
user    0m0.000s
sys     0m0.031s

2
1
3
2
1
3

[1]   終了                  ssh vagrant-local-ubuntu16-20190401 "echo ${i}; sleep 3; echo ${i}"
[2]-  終了                  ssh vagrant-local-ubuntu16-20190401 "echo ${i}; sleep 3; echo ${i}"
[3]+  終了                  ssh vagrant-local-ubuntu16-20190401 "echo ${i}; sleep 3; echo ${i}"
```

この部分は同期処理したいけど、この部分は非同期で良い。
など細かい制御が必要な場合は wait を組み合わせることで実現できそうです。
参考 : https://qiita.com/inosy22/items/341cfc589494b8211844
指定された値の倍数となるように切り上げる

# Excel関数で言うところのCEILING

以下はセルA1の値以上となる最小の５の倍数を返す式（にほんごむずかしい）。セルA1の値が 23 であれば 25 が返ってきます[^Excel]。

```
=CEILING(A1,5)
```

「セイリング」って読むなよ「シーリング」だぞ。天井に取り付ける照明器具を「シーリングライト」って言うでしょ。

# そもそもこれ何て呼ぶの？

「天井」（てんじょう）[^Wikipedia]だそうです。 $\lceil x \rceil$ と表現します。
反意語は「床」（ゆか）で、 $\lfloor x \rfloor$ と表現します。

# もう少しシンプルに書けないものかな

Excelのように一発で書く手段は無さそう。というより、Excelが特殊なパターン？

```python:python
for i in range(4, 8):
     print(i, '->', -(-i // 5) * 5)
# 4 -> 5
# 5 -> 5
# 6 -> 10
# 7 -> 10
```

[^Excel]: [指定の値の倍数になるように切り上げる(CEILING) - 数値関数 - Excel関数入門](https://www.officepro.jp/excelfunc/num/index7.html)
[^Wikipedia]: [床関数と天井関数 - Wikipedia](https://ja.wikipedia.org/wiki/%E5%BA%8A%E9%96%A2%E6%95%B0%E3%81%A8%E5%A4%A9%E4%BA%95%E9%96%A2%E6%95%B0)
ログイン機能の仕組みを解説

#はじめに
 Railsでは、簡単にログイン・ログアウト機能を実装できるgem '**devise**'があります。
 初めてRailsでアプリケーションを作成するときによく使っていましたが、どのような仕組みで成り立っているのか分からなかったので、自分でログイン機能を実装しました。その中で、重要な部分だと感じたSessionとCookieについて紹介します。

##そもそもログイン・ログアウトとは
 簡単に言うと、Webアプリ・サイトにユーザーが誰なのか把握してもらうことです。
 把握してもらうと、ユーザー（自分）を特定してもらい認証してもらえます。
 この過程を得ることで、自身のアカウントでWebアプリやサイトを閲覧することができ、例えばGoogle社の提供するGmailであれば、自身のメールアドレス宛て届いたメールを閲覧・返信することができます。

##ログインの仕組み
 ログイン機能の前提には、**Session**と**Cookie**の仕組みを把握しておく必要があります。

**Session**とは、１つのブラウザから連続して送られる一連のリクエストの間で状態を共有できるようにする仕組みです。
 一般的に、ユーザーがブラウザにリクエストを送ると、レスポンスが返ってきます。HTTPリクエストの場合、状態を保持しないプロトコル（通信する上での決まり）なので、ユーザーから送られた１つ目のリクエストを２つ目のリクエストに引き継ぐことはできません。
 そのため、Webアプリケーション側で**Session**と言う仕組みを用意して、一連のリクエストの間でログイン状態を共有するようになっています。

 一方、**Cookie**はSessionと似たような仕組みですが、ブラウザとWebサーバーの間で行われる仕組みです。
具体的には、Webサーバーからブラウザhttpレスポンスが返ってくるときに、レスポンスを一緒に**Cookie**の情報を返します。
**Cookie**情報は、キーとペアの集合体で、ブラウザは**Cookie**の情報をサーバーのドメイン等に紐づけて保存されます。そして、ユーザーが同じドメインに対して、httpリクエストを送るときに**Cookie**情報を添えて送ることで以前にどのような**Cookie**情報を受け取ったブラウザからリクエストが送られてきているかを判断します。
具体的な例をあげると、PCからGmailやTwitterにアクセスすると、ログインの過程を得ることなく自分のアカウントにログインできていることがあります。これは、**Cookie**情報を添えてリクエストが行われているためです。
ログイン自体は、**Session**を使って実装することになりますが、その**Session**の仕組みの一部を**Cookie**が担っている形になっています。

以上の**Session**と**Cookie**の機能を基に、ログイン機能が実装されています。

##まとめ
ログインの基本的な仕組みを担う**Session**と**Cookie**について紹介しました。
本当に基本的な知識ですが、重要なものだと思いますので参考にしてください。
SAP 訓練目次


###初級　ABAP開発訓練

[第一弾　ABAPー入門:runner_tone3:]
(https://qiita.com/luyu1567/items/03583bb450a65a7dcc1a)
[第二弾　ABAPー言語:runner_tone3:](https://qiita.com/luyu1567/items/3bc5c0db61e5543b4b38)
[第三弾　ABAPー訓練「REPORT」「Dynpro」:runner_tone3:](https://qiita.com/luyu1567/items/df2c17dc02300757d646)
[第四弾　ABAPー訓練「ALV／クエリ」「Dynpro」:runner_tone3:](https://qiita.com/luyu1567/items/99c366529daae823ea29)
[第五弾　ABAPー訓練「Dynpro」:runner_tone3:](https://qiita.com/luyu1567/items/11abae036e5f3cb70d4b)
[第六弾　ABAPー訓練「汎用等」:runner_tone3:](https://qiita.com/luyu1567/items/82044e7cfa23f08cf7e3)
[第七弾　ABAPー訓練「帳票」:runner_tone3:](https://qiita.com/luyu1567/items/d724ca99a263d0ae2442)
[第八弾　ABAPー訓練「拡張」:runner_tone3:](https://qiita.com/luyu1567/items/81e8ed4545ca0a61cdcf)

###入門　コンサルタント[SD]
[(SD)第一弾 SAPー訓練「概要」:runner_tone3:](https://qiita.com/luyu1567/items/d09fd7827ebdcf5dc0dc)
[(SD)第二弾 SAPー訓練「見積伝票」:runner_tone3:]()
[(SD)第三弾 SAPー訓練「受注伝票」:runner_tone3:]()
[(SD)第四弾 SAPー訓練「出荷・出庫伝票」:runner_tone3:]()
[(SD)第五弾 SAPー訓練「請求伝票」:runner_tone3:]()
[(SD)第六弾 SAPー訓練「受注伝票一覧１」:runner_tone3:](https://qiita.com/luyu1567/items/e858554ef7a9c50c2a8b)
[(SD)第七弾 SAPー訓練「受注伝票一覧２」:runner_tone3:]()
[(SD)第八弾 SAPー訓練「受注伝票一覧３」:runner_tone3:]()

[公式サイト](https://help.sap.com/doc/saphelp_erp2005/6.0/ja-JP/80/ea89395eb58c4f9d0c3e837cf0909d/frameset.htm)
CircleCIのためのdocker image作り

# 流れ
3ステップで簡単だった。
1. Dockerfileを作成する
2. docker imageを作成する
3. docker imageをアップロードする

# Dockerfileの作成
[dockerhub](https://hub.docker.com/) からベースとするdocker imageを選ぶ。
（今回は[centos:latest](https://hub.docker.com/_/centos)を使用）
`docker run -it centos:latest sh` コマンドでcontainer内に入る。
コンテナ内でDockerfileに記載したいコマンドを１つずつ実行し、問題なければDockerfileに記載する。
今回はvueをbuildしてs3に上げるためのimageが欲しいのでこんな感じ。

```dockerfile
FROM centos:latest

# install basics
RUN yum install -y git

# install awscli
RUN yum install -y https://centos7.iuscommunity.org/ius-release.rpm
RUN yum install -y python36u python36u-pip python36u-devel
RUN pip3.6 install --upgrade pip
RUN pip3.6 install awscli

# install nodejs
RUN curl -sL https://rpm.nodesource.com/setup_10.x | bash -
RUN yum install -y gcc-c++ make
RUN yum install -y nodejs

# install vue-cli
RUN npm install -g vue-cli
````

# docker imageの作成
`docker build -t <user_name>/<image_name> .`
※user_nameはdockerhubのユーザ名、image_nameは任意
上記コマンドでdocker imageを作成する。
`docker images` で作成したimageが見つかればOK。

# docker imageのアップロード
`docker login` でdockerhubへログインし、
`docker push <user_name>/<image_name>:<tag>`でイメージをｐushする。

successしたらdockerhubにimageが上がるので、circleciのconfigファイルで使用することができる。
Magic Leap MagicScript Landscape Application. UiPortalIcon

**Prepare**
Magic Leap One
https://www.magicleap.com/magic-leap-one

mlsdk v.0.20.0
https://creator.magicleap.com/downloads/lumin-sdk/overview

magic-script-cli v2.0.1
https://www.npmjs.com/package/magic-script-cli

magic-script-polyfills v2.1.1
https://www.npmjs.com/package/magic-script-polyfills

glb file
https://poly.google.com/view/esWz3QtmDCX

background image
https://imgur.com/a/WbR5Eoy

**Create Project**

```
magic-script init my-icon org.magicscript.icon "Portal Icon"
cd my-icon
mkdir res
```
Put glb file and background image in res folder.

**Code**
Change app.package

```
DATAS = "digest.sha512.signed" : "." \
        "bin/" : "bin/" \
        "res/" : "res/"
OPTIONS = package/minApiLevel/2
```
Change app.js

```javascript
import { LandscapeApp, ui } from 'lumin';
const {
    UiLinearLayout
  , UiPortalIcon
  , UiImage
  , LabelDisplayMode
  , UiText
  , EclipseLabelType
  , Alignment} = ui;

export class App extends LandscapeApp {
  
  onAppStart () {
    let count = 0;
    const prism = this.requestNewPrism([0.5, 0.5, 0.5]);
    const layout = UiLinearLayout.Create(prism);
    layout.setAlignment(Alignment.CENTER_CENTER);

    const text = UiText.CreateEclipseLabel(prism, "", 
                                            EclipseLabelType.kT7);
    text.setAlignment(Alignment.CENTER_CENTER);
    
    const model = 
      prism.createModelNode(
        prism.createModelResourceId("res/ar-poop-vroom.glb", 0.05)
    );
    const bg = UiImage.Create(prism, "res/yellow_gradient.png"
                                            , 1.0, 1.0);
    // This component can not be added directly to Prism.
    const icon = UiPortalIcon.Create(prism, "Pile of Poo");
    icon.setIconModel(model);
    icon.setBackgroundModel(bg);
    icon.setTextSize(0.015);
    icon.setHoverScale(2.0);
    icon.setLabelDisplayMode(LabelDisplayMode.kHover);
    icon.onActivateSub(function(uiEventData)
      {
        text.setText("Click Icon " + count++);
      }
    );
    layout.addItem(icon, [0.03, 0.03, 0.03, 0.03]);
    layout.addItem(text, [0.03, 0.03, 0.03, 0.03]);
    prism.getRootNode().addChild(layout);
  }
}


```

**Build**

```
magic-script build -i
```

**Run**

```
magic-script run --port=10000
```

**Reference**
UiPortalIcon (MagicScript API)
https://docs.magicscript.org/lumin.ui.UiPortalIcon.html

magicscript
https://www.magicscript.org/

Thanks!
Firebase×Bigqueryでクラシックリテンションを集計する

# 動作環境
FirebaseとBigQueryを統合し、FirebaseAnalyticsのデータをBigQueryにインポートしている環境です。

# やりたいこと
初回起動(first_open)の日を起点に、2日目起動率、3日目起動率、7日目起動率（クラシックリテンション）を初回起動日別に取得し、ダッシュボード化したい。
リテンションの定義は<a href = "https://tech-magazine.opt.ne.jp/entry/2018/07/19/120000">アプリのリテンションをSQLで出して可視化する</a>を参考にしました。

# 考え方
WITH句の中のstartで初回起動日とuser_pseudo_idの一覧を作成。
usedateで初回起動に限らない起動日とuser_pseudo_idの一覧を作成。
その後、起動日と初回起動日の差分を出すことで何日後に起動したかを導き出し、合計ユーザー数を出して初回起動数との比較でリテンションを計算しています。


# クエリ
``` sql
WITH start AS 
(SELECT 
  user_pseudo_id,
  EXTRACT(DATE FROM TIMESTAMP_MICROS(event_timestamp) AT TIME ZONE "Asia/Tokyo") AS start_date
FROM
  `hogehoge.analytics_xxxxxxxx.events_*` ---BigQueryの集計対象となるテーブル名
WHERE
  _TABLE_SUFFIX BETWEEN FORMAT_DATE("%Y%m%d", DATE_SUB(CURRENT_DATE('Asia/Tokyo'), INTERVAL 14 DAY)) AND FORMAT_DATE("%Y%m%d", DATE_SUB(CURRENT_DATE('Asia/Tokyo'), INTERVAL 1 DAY))
  AND event_name = "first_open"
  AND EXTRACT(DATE FROM TIMESTAMP_MICROS(event_timestamp) AT TIME ZONE "Asia/Tokyo")  BETWEEN DATE_SUB(CURRENT_DATE('Asia/Tokyo'), INTERVAL 14 DAY) AND DATE_SUB(CURRENT_DATE('Asia/Tokyo'), INTERVAL 1 DAY)
GROUP BY
  user_pseudo_id,
  start_date
),
usedate AS 
(SELECT 
  user_pseudo_id,
  EXTRACT(DATE FROM TIMESTAMP_MICROS(event_timestamp) AT TIME ZONE "Asia/Tokyo") AS use_date
FROM
  `hogehoge.analytics_xxxxxxxx.events_*` ---BigQueryの集計対象となるテーブル名
WHERE
  _TABLE_SUFFIX BETWEEN FORMAT_DATE("%Y%m%d", DATE_SUB(CURRENT_DATE('Asia/Tokyo'), INTERVAL 14 DAY)) AND FORMAT_DATE("%Y%m%d", DATE_SUB(CURRENT_DATE('Asia/Tokyo'), INTERVAL 1 DAY))
GROUP BY
  user_pseudo_id,
  use_date
),
retention AS(
SELECT
  start.user_pseudo_id,
  start.start_date,
  IFNULL(DATE_DIFF(usedate.use_date, start.start_date,  day), 0) AS retention_day
FROM
  start
  INNER JOIN usedate ON start.user_pseudo_id = usedate.user_pseudo_id AND usedate.use_date >= start.start_date
GROUP BY
  start.user_pseudo_id,
  start.start_date,
  retention_day),
retention_sum AS(
SELECT
  retention.start_date,
  retention.retention_day,
  count(retention.user_pseudo_id) AS uu
FROM
  retention
GROUP BY
  retention.start_date,
  retention.retention_day)
SELECT
  start_date,
  SUM(CASE WHEN retention_day = 0 THEN uu ELSE NULL END) AS startuu,
  SUM(CASE WHEN retention_day = 1 THEN uu ELSE NULL END) / SUM(CASE WHEN retention_day = 0 THEN uu ELSE NULL END) AS oneday,
  SUM(CASE WHEN retention_day = 2 THEN uu ELSE NULL END) / SUM(CASE WHEN retention_day = 0 THEN uu ELSE NULL END) AS twoday,
  SUM(CASE WHEN retention_day = 3 THEN uu ELSE NULL END) / SUM(CASE WHEN retention_day = 0 THEN uu ELSE NULL END) AS threeday,
  SUM(CASE WHEN retention_day = 7 THEN uu ELSE NULL END) / SUM(CASE WHEN retention_day = 0 THEN uu ELSE NULL END) AS sevenday
FROM
  retention_sum
GROUP BY
  start_date
ORDER BY
  start_date ASC
```

# アウトプット
ダッシュボードツールのRe:dashを使うとこんな形で可視化することができます。
<img width="460" alt="スクリーンショット 2019-05-13 16.59.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215653/b91c54e4-d29f-8b4a-e446-4fdc0a0660ea.png">
【ことはじめ】自然言語処理機能の作成

# ことはじめ
自然言語処理を実施しようと思う。
そのために、必要な機能をリスト化している。

# 基本的な方針
使用言語はpythonで、スタンダードなやり方をまず学習する。
その後で、自身がやりたい箇所についてカスタムするための方法を学習する。

# 自身への課題

- ドキュメントは1次情報に当たる。
- 単純なライブラリユーザーにはならない。

# 疑問
クローラーで必要なデータを検索するロジックをどうするか？
解析したデータから意味を解釈するためのデータベースをどうやって作っているのか？

# 調査対象
[Python による「スクレイピング & 自然言語処理」入門](https://github.com/Salinger/found_it_project_06_crwl/blob/master/slide/crawler_nlp_20170324.pdf)

# 調査結果
- クローラーに必要な機能
    - クロールリストの制御機能
        - クロースするURLを保持する
        - クローリングのタイミングを制御する
    - クローリング機能
        - URLからhtmlドキュメントを取得する
- 前処理に必要な機能
    - 取得したデータの加工機能
        - htmlドキュメントから、htmlタグを取り除いて必要なデータを取得する機能
        - 取得したデータをプログラムで扱いやすい構造に変更する機能
        - 前処理しやすいように、所定の形式に加工する機能（csv, データフレーム, など)
    - 前処理機能
        - 前処理をほどこす
        - 前処理済みのデータを保存する
- 自然言語処理に必要な機能
    - 調査中
        - MeCabを使った頻度分析を予定
saveできない。Validation failed: # must existの解決方法

#はじめに
Rails5でサービスを開発していく中で```save```してもテーブルにデータが入らないという問題が。

#解決方法
```belongs_to``` に、```optional: true``` をつけてあげることで、関連先の値を検知しないようにさせる。(Rails5から仕様変更になった。)

```follow.rb
class Follow < ApplicationRecord
  belongs_to :user, optional: true
end
```

これでデータがちゃんと入るようになります。

###補足
save,createなどでデータが入らない場合はsave!でエラー内容を確認すべし

#参考
（個人メモ）Rails5で関連を定義した時はbelongs_toに気をつける
https://qiita.com/junara/items/ca6f65d2f2a27f185f0e
Validation failed: ◯◯ must existのエラー[Rspec]
https://qiita.com/aoitrain/items/90a1781160485bb95abe
ー初心者でもわかるー　テストの概念と実施方法

## テストの概念
### テストとは?
「プログラムが意図した動作をしているか」を確かめることをテストと言います。

Railsでは[rspec-rails]というGemを使ってテストをすることができます。

### テストコードのメリット
- 仕様漏れを減らせる

　テストをする際には、どのメソッドがなぜ作られどのように動作するかを列挙します。
　すると、仕様の確認を頻繁に行うことになり、結果的に仕様漏れが少なくなりやすいです。

- リファクタリング、機能追加がしやすい

　リファクタリングとは、コードをより綺麗な形に整えることです。
　一度テストを通過したコードは、その機能を維持することを意識するだけで安全に実装ができます。

## テストの実施方法
### gemをインストールする
 - gemfileにgem 'rspec-rails'を追記
 - ターミナルでbundle installを実施

### RSpecの設定を行う
 - ターミナルでrails g rspec:installを実行する
 - 設定ファイルやテストを保存するフォルダが生成される
 - .rspecに--format documentationを追記（他のオプションもあるが、わかりやすい）

### 実際にテストをする
```
describe "test" do
  it "1 + 1は2になること" do
    expect(1 + 1).to eq 2
  end
end
```
上が実際のテストコードです。ポイントが３つあります。

**1.describe**
　```describe "テストの説明" do ~ end```
　""の中にテストの説明を書き、do ~ endの間に実際の処理のまとまりを書きます。

**2.it**
　 ```it　"処理の説明"```
　　itの記載で、テストの処理のまとまりであることを表しています
　""の中に処理のまとまりの内容を記入できます

**3.エクスペクテーション**
  　```expect(X).to eq Y```
  　Xの処理がYと等しい（＝eq）である時にテストが成功する処理です
　　.rspecに--format documentationを追記してあるので、使えます
小学生でも作れる2軸2足歩行ロボット筐体(サーボ代込み2500円)

#■以前類似の投稿をしました。
https://qiita.com/Google_Homer/items/bf269828fbdf3ce83a8e

#■今回は上記の進化系で、より簡単で安く作れるようにしたものです
使用する部品は、TAMIYAのユニバーサルプレートとサーボと結束バンドのみです。ネジはサーボ付属のもののみ使用します。
歩行プログラムははobnizで作ったのですが、情報量が多くなるのでここでの掲載は省略します。汎用的な筐体なので、Arduinoやmicro:bitなど他のCPUボードでも使えます。

#■まずは動作映像から
<blockquote class="twitter-tweet"><p lang="und" dir="ltr"><a href="https://t.co/lHGRJC1EQ7">pic.twitter.com/lHGRJC1EQ7</a></p>&mdash; Google Homer (@google_homer_) <a href="https://twitter.com/google_homer_/status/1125017512100294657?ref_src=twsrc%5Etfw">May 5, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
#■組み立て手順
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234533/917dbf03-9d36-683b-eab3-f85d4b944ff4.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234533/3b11e428-6937-130e-189d-d1c9cd4eab1c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234533/99fe92ad-fb11-2537-4a27-02385169860a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234533/2c22afe3-3a50-dca6-c6e3-477a11b9e164.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234533/f6614b91-dbf0-9921-0e82-ccffc4d04dac.png)

#■まとめ
いかがだったでしょうか。たぶん世界で最も簡単に作れる2軸の2足歩行ロボットだと思います。足し首や足板は、何となくそれっぽいものであれば他の材料で代替できると思いますので、各自で工夫してより簡単なものにトライしてみて下さい。

以上
小規模SPAのバックエンドについて、調べてみたことのまとめ。


# 目的

- 少人数(max2人)で小規模SPAを開発するにあたり、工数を最小限に抑えるためのアーキテクチャを模索したい
- 2019年5月時点
- 以前はRails API + PostgreSQLを使っていたけど、serverlessしたい

# DB+API周りについての候補

## Firebase

結局FirebaseのFireStoreがすごいよねって感じ。
他のAWS上のシステムと連携したいので、ちょっと使うのが厳しい感じもする。

## Amplify

SPAがAmplifyに集約されていると思いきや、Cognito, AppSyncなどそれぞれの処理とAmplifyの動きを２重に把握する必要があって辛い。

## AppSync + DynamoDB

DynamoDBを良きに計らってくれるかと思ってたけど、結局DynamoDBに引っ張られる。
DynamoDBは検索にIndex必須だったり、何かと面倒くさそう(好みの問題)

## AppSync + Lambda(js) + MongoDB(DocumentDB)

DynamoDBよりMongoDBでしょ、Tokyo解禁されたし、集計関数使えるし、経験あるし。
ただ、工数を最小限に抑えるアプローチからは遠ざかってる気もする。
と思ったけど、DocumentDBってt3インスタンス無いのか。。

## ServerlessFramework(ApiGateway + Lambda + ts) + MongoDB
だったら、RestAPIで良くね？
ServerlessFrameworkで解決出来るし

## ServerlessFramework(ApiGateway + Lambda + ruby) + PostgreSQL
だったらActiveRecordをそのまま持って行ってしまえば(ry)
libcudnnのインストールで1 DECLINE 2 ACCEPTを表示せずインストールする

libcudnnをインストールするとき、ライセンスへの同意でユーザー入力を待つ部分があります。ここがy/nではなく1/2の入力であるため-yオプションで自動ACCPETすることができません。自動構築では不便なのでここをスキップしたいです。

このときは`DEBIAN_FRONTEND=noninteractive sudo apt install -y libcudnn7-dev`でインストールしましょう。

https://devtalk.nvidia.com/default/topic/518430/cuda-programming-and-performance/non-interactive-installation-of-nvidia-software/post/4833578/#4833578
Unity2017でエクスポートしandroidStudioでビルドすると「Could not find org.codehaus.groovy:groovy-all:2.4.〜」

諸々広告SDKの最新版を入れる関係で、androidの直ビルドせず、エクスポートしてから
AndroidStudio上でビルドして、下記エラーになった。

```
Could not find org.codehaus.groovy:groovy-all:2.4.15.
Searched in the following locations:
  - file:/Users/hoge/Library/Android/sdk/extras/m2repository/org/codehaus/groovy/groovy-all/2.4.15/groovy-all-2.4.15.pom
  - file:/Users/hoge/Library/Android/sdk/extras/m2repository/org/codehaus/groovy/groovy-all/2.4.15/groovy-all-2.4.15.jar
  - file:/Users/hoge/Library/Android/sdk/extras/google/m2repository/org/codehaus/groovy/groovy-all/2.4.15/groovy-all-2.4.15.pom
  - file:/Users/hoge/Library/Android/sdk/extras/google/m2repository/org/codehaus/groovy/groovy-all/2.4.15/groovy-all-2.4.15.jar
  - file:/Users/hoge/Library/Android/sdk/extras/android/m2repository/org/codehaus/groovy/groovy-all/2.4.15/groovy-all-2.4.15.pom
  - file:/Users/hoge/Library/Android/sdk/extras/android/m2repository/org/codehaus/groovy/groovy-all/2.4.15/groovy-all-2.4.15.jar
  - https://dl.google.com/dl/android/maven2/org/codehaus/groovy/groovy-all/2.4.15/groovy-all-2.4.15.pom
  - https://dl.google.com/dl/android/maven2/org/codehaus/groovy/groovy-all/2.4.15/groovy-all-2.4.15.jar
  - file:/Users/hoge/Desktop/CookiePuzzle/libs/groovy-all-2.4.15.jar
  - file:/Users/hoge/Desktop/CookiePuzzle/libs/groovy-all.jar
Required by:
    project : > com.android.tools.lint:lint-gradle:26.3.1
```

groovy:groovyや、lint-gradleなどを疑ったが、
下記で解決

```app.build.gradle
//〜〜
allprojects {
    repositories {
       jcenter() //ここ※順番注意
       flatDir {
           dirs 'libs'
           }
       google()
    }
}
//〜〜
```

> 環境
* Unity2017.4.10f1
* Admob： Google Mobile Ads Unity Plugin v3.15.1 （最新版）
* AppLovin： GoogleMobileAdsAppLovinMediation-4.0.0.zip （最新版）
React.js 開発準備

# React.jsの開発準備まで
環境
MacOS Mojave 10.14.5


## React.js導入方法

1. CDN利用
1. `npm install`
1. `create-react-app`

`create-react-app`はライブラリ、ビルドツール(`webpack/Babel`)、開発サーバまで用意されている。今回は3を使用する。

## Node.jsインストール

Macでのインストール方法は下記参照
[Homebrew + nodebrewでNode.jsをインストール](https://qiita.com/abeeeee/items/f65f4517575e50b48e6e)

## yarnインストール

npmでも良いが、yarnを入れておく(via homebrew)

```
$ brew install yarn
```

## create-react-appインストール

```
$ yarn add create-react-app
```

## アプリ作成

1. プロジェクト用ディレクトリを作成
2. 作成したディレクトリへ移動
3. コマンド実行

```
$ mkdir {project_dir}
$ cd {project_dir}
$ npx create-react-app {your_app_name}
```

## 開発サーバー起動

1. 作成したアプリディレクトリへ移動
2. `yarn start`実行

```
$ cd {your_app_name}
$ yarn start
```

## localhost:3000へアクセス

下記のような画面が表示される。

<img width="868" alt="スクリーンショット 2019-05-14 12.16.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92407/f78b0fc6-a742-843b-8e19-9a26b75d8678.png">

## 補足

開発サーバーの停止は`Ctrl + C`
続・Azure Blob Storage の HTBB (High-Throughput Block Blob) が何も考えずに使っても結構速い件。

# 概要
昨日、[Azure Blob Storage の HTBB (High-Throughput Block Blob) が何も考えずに使っても結構速い件。](https://qiita.com/tokawa-ms/items/8b2f85171a236eb36fa7) という記事を書きましたが、その後ちょっと条件を変えたらもっと速くなるのでは…？と実験してみたら案の定さらに 4 倍以上のスループットが出ました！というまとめ。

# 背景
昨日の実験では、とりあえず RAM Disk を確保しても十分位のメモリ…ってことで、Standard D4s v3 (4 vcpu 数、16 GB メモリ) を選んでいました。
でもそれだと、VM がホストされているサーバーのネットワークインターフェイスを他の VM とシェアする形になっているはずなので、その部分がボトルネックになってるのでは…と思った次第。

# 実験条件
今回は、DSv3 シリーズで一番いいのを頼む、ってことで、Standard D64s v3 (64 vcpu 数、256 GB メモリ) にしてみました。あとの実験条件は一緒なので割愛。

そして結果！

```
tokawa@<VMNAME>:~/azcopy_linux_amd64_10.1.1$ ./azcopy cp "/mnt/ramdisk/" "https://<STORAGEACCOUNT>.blob.core.windows.net/<CONTAINER>?<SAS>" --recursive=true
INFO: Scanning...

Job b7fdd9b2-5b05-1f4d-59a0-82b693eea438 has started
Log file is located at: /home/tokawa/.azcopy/b7fdd9b2-5b05-1f4d-59a0-82b693eea438.log

0 Done, 0 Failed, 1 Pending, 0 Skipped, 1 Total, 2-sec Throughput (Mb/s): 18643.0 Done, 0 Failed, 1 Pending, 0 Skipped, 1 Total, 2-sec Throughput (Mb/s): 1832.1718


Job b7fdd9b2-5b05-1f4d-59a0-82b693eea438 summary
Elapsed Time (Minutes): 0.1003
Total Number Of Transfers: 1
Number of Transfers Completed: 1
Number of Transfers Failed: 0
Number of Transfers Skipped: 0
TotalBytesTransferred: 5368709120
Final Job Status: Completed
```

**コマンド打ってから完了するまで、目に見えてわかるくらいだいぶ速くなった！！！**

とりあえず計算。
5368709120 [Bytes] / 0.1003 [Minutes] = 53,526,511,665 [Bytes/Min]
一分間に 53 GB くらい送れそうな感じですね。

53,526,511,665 [Bytes/Min] / 60 = 892,108,527.75 [Bytes/Sec]
なんと秒間 900 MBytes くらい！bit per second になおすと、7200 Mbps ってとこ。

8K ビデオでもビットレートは 200 - 300 MBit/Sec くらいが標準だと思うので、全然余裕ですね！

もはや大容量データを扱う案件も、VM - Storage 間でガンガンデータやり取りする感じの実装でいいのでは…と思ったりします。

# まとめ
Azure Blob Storage のスループットは、もはや書き込み元のスループットやネットワークの帯域幅が大きなキャップになってくるポイントだなぁ、と昨日からの 2 つの実験で感じました。
何も考えず、適当に使ってもそこそこ速いですが、書き込み元側で詰まってる状況であれば、単一の Blob に複数 VM から分割して書き込むとか、アプリのアーキテクチャを考えれば、もっともっと超速書き込みが実現できるのではないでしょうか！？

それではまた！
Selenium + Python + Docker + Jupyter で快適にフロントエンドテストを作る

# あらすじ
フロントエンドテストをするのに Selenium を使うことになった。

- 画面で実際にどんな動作しているか見ながら出ないとわからない！
- 一行ずつコード書きながらあっているのかかくにんしたい！
- Image を大きくしたくない
    - Docker ということもあり極力分散

とのことでいろいろ方法を探しました。

# VNC で画面を見ながら行う

## コンテナ準備
ノードが接続する Selenium Grid Hub の立ち上げ。

```
docker run -d -p 4444:4444 --name selenium-hub selenium/hub
```
テストを実行できるノードの起動します
※ポートがかぶらないようにしておきます。

```
# Chrome
docker run -d -p 5900:5900 --name sel-node_c --link selenium-hub:hub -v /dev/shm:/dev/shm selenium/node-chrome-debug
# Firefox
docker run -d -p 5901:5900 --name sel_node_f --link selenium-hub:hub -v /dev/shm:/dev/shm selenium/node-firefox-debug
```
## VNC 準備
立ち上がったら、VNCで画面が表示されることを確認します。
今回は [VNC® Viewer for Google Chrome™](https://chrome.google.com/webstore/detail/vnc%C2%AE-viewer-for-google-ch/iabmpiboiopbgfabjmgeedhcmjenhbla) を使いました

接続先は
Chrome: ```<VM の IP>:5900```
Firefox: ```<VM の IP>:5901```
パスワードはデフォルトで secret になっています。

## Python から操作できるか確認
Python はもともとのサービスコンテナに入っていたので

```.py
# python3.6
>>> from selenium import webdriver
>>> from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
>>> web_driver = webdriver.Remote(
... command_executor='http://<VM の IP>:4444/wd/hub',
... desired_capabilities=DesiredCapabilities.CHROME) # Chrome
    or
... desired_capabilities=DesiredCapabilities.FIREFOX) # Firefox


>>> # サービスの画面を取得
... web_driver.get("http://<サービスの IP>")
>>> # TOP のリンクを取得
... link = web_driver.find_element_by_link_text('TOP')
>>> # TOP のリンクを押す
... link.click()
>>> # 接続終了
... web_driver.quit()
```

# 動いたけどどうやってテストコードを書いていこうか。。。
## 1行ずつ動かせる Jupyter があるではないか！
ということで、Jupyterで書いてみると簡単！

ローディング時間を目で確認しながらブラウザをあたかも操作しているように実行できます。
Jupyter で操作を模倣したコードを作成し、そのまままとめてテストスクリプトに
流し込んだらあっという間にできました。

# 問題点
- ~~web_driver.close() した後に再度接続しようとしてもつながらない~~
    - ~~別のブラウザを指定すれば動く（Chrome -> Firefox）~~
    - ~~（暫定的な改善策）selenium-hub のリスタート~~

=>（2019/05/15 追記）
```web_driver.close() ``` ではなく、```web_driver.quit() ``` を使うことで解決

- プロキシ下で行う際、外部サイトを表示する場所があるとエラーになる

# まとめ
毎回同じ操作しなくて便利！
これで操作し忘れもなくなる！

# 参考
https://qiita.com/reflet/items/89ff50c991168adb3a9b
https://github.com/SeleniumHQ/docker-selenium/tree/master/NodeChromeDebug
flexbox ざっくりとしたまとめ

以前からFlexboxにはお世話になっていたのですがまとめられていなかったので備忘録として。
CSSで要素を横並びにしたいときは習った教材などの通りに`float: left`して擬似要素を作って...みたいな事をしてましたがFlexboxに出会ってからは色々とカスタマイズできるのでずっと使っています笑

#flexコンテナー（親要素）とflexアイテム（子要素）
flexboxは親要素であるコンテナーと子要素のアイテムにプロパティを指定してCSS見た目を変えていきます。

```html
  <div class="container">  <!-- flex-container(親要素) -->
    <div class="box box-1">1</div>  <!-- flex-item(子要素) -->
    <div class="box box-2">2</div>
    <div class="box box-3">3</div>
    <div class="box box-4">4</div>
    <div class="box box-5">5</div>
 </div>
```

```css
.container {
  width: 300px;
  height: 300px;
  color: #fff;
  background: #eee;
  display: flex;
}
.box {
  height: 80px;
  width: 80px;
}
.box-1 { background: tomato; }
.box-2 { background: slategray; }
.box-3 { background: pink; }
.box-4 { background: skyblue; }
.box-5 { background: limegreen; }
```

[![Image from Gyazo](https://i.gyazo.com/2f871aa6e0913d1d60d78a3469127c31.png)](https://gyazo.com/2f871aa6e0913d1d60d78a3469127c31)

上の例でいう**flexコンテナー（親要素）**は背景色がグレーの要素になります。
**flexアイテム（子要素）**はそれぞれ色(赤、青、緑とか)のついている要素になります。

**flex-containerの作り方は`display: flex`と指定するだけです。**
これだけで要素は横並びになります。
flex-containerを作成すると**flex-direction(rowかcolumn)**が指定できるようになります。
**flex-directionは選択していなくてもデフォルトrow（行）になっているので横並びになっているわけです。**

```css
.container {
  width: 300px;
  height: 300px;
  color: #fff;
  background: #eee;
  display: flex;   /* flex-direction: row  記述しなくてもデフォルトになっている。 */
}
```

ではflex-directionをcolumn(列）にしてみます。

```css
.container {
  width: 300px;
  height: 300px;
  color: #fff;
  background: #eee;
  display: flex; 
  flex-direction: column;
```
[![Image from Gyazo](https://i.gyazo.com/a969d6126a5f7cdee7deaf1f56141b83.png)](https://gyazo.com/a969d6126a5f7cdee7deaf1f56141b83)

すごく便利です。
他にも並べる順番を逆にする`row-reverse/column-reverse`も指定できます。

- ###flex-containerにつけるプロパティ
  - **flex-direction(初期値はrow) -子要素の並ぶ向き**
  - **flex-wrap(初期値はnowrap) -子要素の折り返し**
  - **justify-content(初期値はflex-start) -水平方向の揃え**
  - **align-items(初期値はstrech) -垂直方向の揃え**
  - **align-content(初期値はstrech) -複数行にしたときの揃え**



- ###flex-itemにつけるプロパティ
  - **order - 順序の指定**
  - **flex-grow -子要素の伸びる率**
  - **flex-shrink -子要素の縮む率**
  - **flex-basis - 子要素のベースとなる幅の指定**
  - **align-self -子要素の垂直方向の揃え**



https://flexboxfroggy.com/#ja
こちらのサイトはflexboxxの練習に適してるのではないかと思います！
documentation > フォルダのtree構造作成 > yone098@githubさんの手法 + アルファ

```txt:動作環境
Windows 10 Pro (64bit) バージョン 1809 (October 2018 Update)
秀丸エディタ Version 8.79
SmartGit 18.2.3
Git for Windows (git version 2.19.1.windows.1)
```

### tree構造の取得

- [tree コマンドが無い環境で tree コマンドを実現](https://qiita.com/yone098@github/items/bba8a42de6b06e40983b) by @yone098@github さん

情報感謝です。

実行例

```
$ find . | sort | sed '1d;s/^\.//;s/\/\([^/]*\)$/|--\1/;s/\/[^/|]*/|  /g'
|--dirA
|  |--dirA-1
|  |--dirA-2
|--dirB
|  |--dirB-1
|  |--dirB-2
|  |  |--You've_got_it.txt
|  |--dirB-3
|--dirC
```

### tree構造の編集

置換元: `|  ` (3文字)
置換先* `   ` (3文字)

秀丸エディタを使いました。

結果

```
|--dirA
   |--dirA-1
   |--dirA-2
|--dirB
   |--dirB-1
   |--dirB-2
      |--You've_got_it.txt
   |--dirB-3
|--dirC
```

自分はこちらのほうが好みです。

さらに置換をすると、よりきれいになるかもしれませんが。
(過剰かもしれません）

- 例: `|--`を`┗--`へ

```
┗--dirA
   ┗--dirA-1
   ┗--dirA-2
┗--dirB
   ┗--dirB-1
   ┗--dirB-2
      ┗--You've_got_it.txt
   ┗--dirB-3
┗--dirC
```