OmniAICreator/Qiita-1.07M huggingface dataset:
EC-CUBEのSymfony開発ブランチでカスタマイズディレクトリを使って既存フォームに新規項目を追加してみる

# 概要

EC-CUBEのSymfony開発ブランチではEC-CUBE3.0系にはなかったカスタマイズディレクトリによるカスタマイズ方法が導入されています。
本記事ではカスタマイズ例として既存フォームへ新規項目を追加するまでの流れを示します。

ソースコードは以下でも確認いただけます。
https://github.com/okazy/ec-cube/tree/demo

# 新規画面追加

新規会員登録画面へ趣味のフォームを追加します。

詳しい内容は[公式ドキュメント](http://doc3n.ec-cube.net/customize_entity)を参照してください。

## Step1: `/app/Customize/Entity` 配下に `CustomerTrait` トレイトを作成します。

```php:/app/Customize/Entity/CustomerTrait.php
<?php

namespace Customize\Entity;

trait CustomerTrait
{

}
```

## Step2: `@EntityExtension` アノテーションを追加して拡張するエンティティを指定します。

```php:/app/Customize/Entity/CustomerTrait.php
<?php

namespace Customize\Entity;

use Eccube\Annotation\EntityExtension;

/**
 * @EntityExtension("Eccube\Entity\Customer")
 */
trait CustomerTrait
{

}
```

## Step3: `$hobby` 変数を追加します。

```php:/app/Customize/Entity/CustomerTrait.php
<?php

namespace Customize\Entity;

use Eccube\Annotation\EntityExtension;

/**
 * @EntityExtension("Eccube\Entity\Customer")
 */
trait CustomerTrait
{
    public $hobby;
}
```

## Step4: `@ORM\Column` アノテーションでデータベースの設定を追加します。

```php:/app/Customize/Entity/CustomerTrait.php
<?php

namespace Customize\Entity;

use Eccube\Annotation\EntityExtension;
use Doctrine\ORM\Mapping as ORM;

/**
 * @EntityExtension("Eccube\Entity\Customer")
 */
trait CustomerTrait
{
    /**
     * @ORM\Column(type="string", nullable=true)
     */
    public $hobby;
}
```

## Step4: コマンドラインからプロキシファイルを作成します。

`/app/proxy/entity` ディレクトリに `Customer.php` が作成されます。

```shell
bin/console eccube:generate:proxies
```

## Step5: コマンドラインからDBのスキーマを変更します。

`dtb_customer` テーブルに `hobby` カラムが追加されます。

### 実行されるSQLの確認。

```shell
bin/console doctrine:schema:update --dump-sql
```

### 問題がなければ実行

```shell
bin/console doctrine:schema:update --dump-sql --force
```

## Step6: `@FormAppend` アノテーションでフォームの設定を追加します。

```php:/app/Customize/Entity/CustomerTrait.php
<?php

namespace Customize\Entity;

use Doctrine\ORM\Mapping as ORM;
use Eccube\Annotation\EntityExtension;
use Eccube\Annotation\FormAppend;

/**
 * @EntityExtension("Eccube\Entity\Customer")
 */
trait CustomerTrait
{
    /**
     * @ORM\Column(type="string", nullable=true)
     * @FormAppend(
     *     auto_render=true,
     *     form_theme="Form/hobby.twig"
     * )
     */
    public $hobby;
}
```

## Step7: `/app/template` 配下にテンプレートファイルを追加します。

```twig:/app/template/default/Form/hobby.twig
{%- extends 'Form/form_div_layout.twig' -%}

{%- block _entry_hobby_row -%}
    <dl>
        <dt>
            {{ form_label(form, '趣味', {'label_attr': {'class': 'ec-label'}}) }}
        </dt>
        <dd>
            {# 確認画面での表示 #}
            {% if type is defined and type == 'hidden' %}
                {{ form.vars.data }}
                {{ form_widget(form, {type: 'hidden'}) }}
            {% else %}
                {# 入力画面での表示 #}
                <div class="ec-select{{ has_errors(form) ? ' error' }}">
                    {{ form_widget(form) }}
                    {{ form_errors(form) }}
                </div>
            {% endif %}
        </dd>
    </dl>
{%- endblock _entry_hobby_row -%}
```

画面を更新して趣味が登録できたら成功です！
railsのエラーについて

エラー表示で現れるエラー文について
下記のように５つに分けられる。

①NoMethodError[問題箇所のコントローラー]#アクション
**メソッドが定義されていなかったり、
リクエストで指定されたコントローラーにそのアクションが無い場合に起こるエラー**

メソッドを使用するインスタンスのクラスに定義されていないメソッドを使用するとエラーに

エラーメッセージのなかで「`[メソッド名]' for nil::nilclass」と表示されると
メソッドを使用しているインスタンスがnilになっています。そのインスタンスを生成している箇所を要チェック


②Pending migration error
**実行していないマイグレーションファイルがあると起こるエラー**
マイグレーション忘れが原因

実行し忘れているマイグレーションファイルがないかチェック

③Routing Error
**リクエストしたルーティングが設定されていないと起きるエラー**

ルーティングの確認と間違ったルーティングをリクエストしていないか確かめるべき。


routes.rbで設定しているルーティングの記述をきちんと確認？
routes.rbを開き、リクエストするルーティングの記述が正しいかどうかチェック

エラー文が出ている画面のurLをみてチェック、
現在、送られているパスを確認することができます。

```
localhost:3000/check これがリクエストとして送られている
```

よくある間違いは、routes.rbの中で「:id」を指定されているルーティングで、
viewファイル側のリクエスト箇所でも同じように'tweets/:id'としてしまうことです。

この場合は必ずビュー側で式展開を行うこと

routes.rbに書いてあるHTTPメソッドと、
ルーティングをリクエストする箇所で指定しているHTTPメソッドが合っているか確認


④syntax error　　　
**Rubyの文法エラー**

構文に必要な「end」がなかったり、
""(クォーテーション)や「,」(カンマ)忘れが主な原因

メソッドの中でif文やeach文を利用してエラーが出たら必ずendの数が正しいかどうかを確認

""(クォーテーションや「,」(カンマ)忘れをよくよくチェック

⑤Template is missing
**指定されたviewファイルが無い場合などに起きるエラー**

リクエストを受け取るアクションに対応したviewファイルがあるかを確認(erbファイルを確認)
aliasで自分だけのコマンドを作っちゃおう！！

#はじめに 
開発環境はUbuntu
エディタはemacs
文章が乱雑な可能性あり

当記事はaliasと呼称されるコマンド作成法を紹介することを目的としています。
#そもそもaliasとは何だ？
**端的に言うと"alias"とはコマンドの一覧表みたいなもの**

端末に打つコマンドの一部を載せているコマンド集がaliasと呼ばれるものなんです。
それでは実際にどんなコマンドがあるのかをご紹介しましょう！！

1.```$ls --color=auto``` 
2.```$ls -alF```
3.```$ls -CF```

等々、様々なものがあります・・・

って`ls`ばっかりじゃないか！！
と、思いますよね？

でも、実際に上記のオプションはそれぞれきっとそれなりに使用頻度があるものなのです。
ですが、いつも使うのにいちいちオプションを付けたりするのは面倒くさいなぁ・・・

**そんなときこそ**aliasの使い所さんなのです！！
つまり長いコマンドや複雑なシェルスクリプトを短いコマンドとして登録したものがaliasなのです！！
以上がaliasの簡単な説明です。

「いやいや、aliasの説明はそれじゃ不十分じゃよ・・・」
「aliasのファイルに書かれてるのはそれ以外にも・・・」

**黙らっしゃい！！**

この記事はaliasなるものを用いて**コマンドを作る**事を目的にしているのです！！
そのプロセスの具体的説明などは最初から眼中になどないのです！！
もし知りたいのならば他の記事を参考にするのです！！
なぜなら私ですら理解していないのですから！！(大方、シェルスクリプトで編まれた起動時の動きとかだと思っています)

#aliasを見てみよう！！
上記で説明したとおりにaliasはコマンド集の一覧表みたいなものです。
では、それに新しくコマンドを追加するには**書き足せば**いいのです。

まずは好きなエディタでホームディレクトリの次のファイルを開きます。
```$emacs .bashrc```
＊この際にroot権限はいりません
私はvimよりもemacsの方が大大大好きなのでこうしましたが、皆さんがどうしてもと言うならvimでもcatでもメモ帳だろうが大丈夫です。

すると沢山の文字の羅列が出てきますので、78行目を見て下さい。
```alias ls='ls --color=auto'```
以上のようにあります。

この文で「```ls```というコマンドは```ls --color=auto```という物だよ♪」という意味になります。

＊基本的に```'登録したいコマンド'```とalias記述後のスペース以外にはスペースは挙動がおかしくなるので入れてはいけません


#aliasでコマンドを作ろう！！

ここからは実際に私が作って使っているコマンドの例を紹介して皆さんにコマンド作成の手本として見せます。
＊書き込む場所は先述の78行目の下で大丈夫です。場所によって書き込んでいい場所と駄目な場所があるのでちゅういしましょう。

- 直結sshコマンド 

このコマンドはいつもsshする対象の公共サーバーがあるのですが直打ちするのが面倒くさいけど他の方法が思いつかなかったから作ったコマンドです。

```alias myssh='sudo ssh ここは対象サーバーを書いた'```



- いつでもroot権限なemacsさん

これはemacsで開くときにroot権限が必要なファイルの時に使ってます(あんまりないけど)

```alias SPemacs='emacs C-xC-v /sudo::/etc/passwd'```



- 可愛いだけで意味はないparuコマンド

私が個人的に好んでいる"ぱる"と連呼するキャラを模して作ったコマンドです。

```alias paru='while true ;do echo -n "ぱる"　;sleep 0.1 ;done'```



- 自作の目覚ましアラートさん

私がC言語で自作した目覚まし時計を起動させるコマンドです。
まぁこれは実行ファイルを実行させているだけなんですけどねｗｗ

```alias araisan='./対象の実行ファイル'```

・・・以上がaliasを用いてコマンドを作るやり方とその例でした。

#書き込めたら？

さて、aliasに自分が作りたいコマンドも書いたし・・・
**いざ、実行！！！**
と思っても実行できません？

実はaliasの書かれている.bashrcなるファイルは端末の起動時に読み込まれるのです！！

なので書き終えたら端末を１回、閉じましょう。
```$exit```
(なんで、わざわざ```$exit```で閉じるか？愚問じゃな、こっちの方が**格好いい**からだ！！)

そして再び、端末を開いて書き込んだコマンドを打ってみよう！！
もし出来てなかったら書き込んだコマンドに不備があると思われるのでよく見直してみよう！！

・・・以上で当記事を終了いたします！！

起立！
気をつけ！！
礼ッ！！！
ありがとうございました！！！！
GithubのWikiで画像の表示をする場合

### プロダクトの製品マニュアルをwikiでまとめることになった
GithubのWiki、README.mdで画像を表示させたいのに、
表示出来ずに困った。画像の保存先に迷った。

### Wikiリポジトリを作成、imagesフォルダを作成する方法がいいのでは
GithubのWikiリポジトリクローンしてきて、
imagesフォルダを作成して、表示させたい画像を入れる。
コミット＆プッシュ！

### 画像を表示させるには(直下にimagesフォルダを作成)
`![Alt Text](images/hogehoge.png)`

プレビューでも表示させたい場合は、絶対パスを入力すればいい。
`![Alt Text](https://github.com/ユーザー/リポジトリ/wiki/images/hogehoge.png）`
おすすめリンク

# はじめに
ここでは、Qiita以外のページで良質な記事のリンクをまとめます。不定期更新

# リンク
* [ぼくにもわかるデザインパターン](https://www.ulsystems.co.jp/topics/028)
    * 具体例が丁寧にまとめられていて非常に読みやすい。

* [コマンドの構文](http://publib.boulder.ibm.com/tividd/td/framework/SC32-0806-01/ja_JA/HTML/ref14.htm)
    * コマンドラインの構文
最大値を求める


Swiftは、命令型プログラミングと関数型プログラミングをサポートしているマルチパラダイムプログラミング言語です。

そこで、「最大値を求める」という関数を通して、命令型プログラミングと関数型プログラミングのアプローチの違いを紹介いたします。

# 命令型プログラミングと関数型プログラミングの違い
[関数型プログラミングの基礎 JavaScriptを使って学ぶ (amazon)](https://www.amazon.co.jp/%E9%96%A2%E6%95%B0%E5%9E%8B%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%81%AE%E5%9F%BA%E7%A4%8E-JavaScript%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E5%AD%A6%E3%81%B6-%E7%AB%8B%E5%B7%9D%E5%AF%9F%E7%90%86/dp/4865940596)」から

* 土台となっている数学モデルが異なる
	* 命令型プログラミング = チューリング・マシン
	* 関数型プログラミング = ラムダ計算
* それぞれにおける計算の意味が異なる
	* 命令型プログラミング = 命令(状態の変更）を実行すること
	* 関数型プログラミング = 関数を呼び出して値を得ること


# 命令型プログラミングによる最大値の導出

最大値を格納する変数を用意し、forループ文で各要素を比較していく。

```imprerative_maximum.swift
func maximum<T>(_ arr: [T]) -> T where T: Comparable {
    guard arr.isEmpty == false else { fatalError() }
    var maximum = arr[0]
    for i in arr {
        maximum = maximum > i ? maximum : i
    }
    return maximum;
}
```

# 関数型プログラミングによる最大値の導出

最大値を返すmax関数を再帰で呼び出していく。

```functional_maximum.swift
func maximum<T>(_ arr: [T]) -> T where T: Comparable {
    switch arr.count {
    case 0:
        fatalError()
    case 1:
        return arr[0]
    default: 
        return max(arr[0], maximum(Array(arr.dropFirst())))
    }
}
```

# 参考書籍
[関数型プログラミングの基礎 JavaScriptを使って学ぶ](https://www.amazon.co.jp/%E9%96%A2%E6%95%B0%E5%9E%8B%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%81%AE%E5%9F%BA%E7%A4%8E-JavaScript%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E5%AD%A6%E3%81%B6-%E7%AB%8B%E5%B7%9D%E5%AF%9F%E7%90%86/dp/4865940596) Amazon

[すごいHaskellたのしく学ぼう!](https://www.amazon.co.jp/%E3%81%99%E3%81%94%E3%81%84Haskell%E3%81%9F%E3%81%AE%E3%81%97%E3%81%8F%E5%AD%A6%E3%81%BC%E3%81%86-Miran-Lipova%C4%8Da/dp/4274068854) Amazon

# 関連Qiita
[命令型プログラミングと関数型プログラミングによる単方向リスト](https://qiita.com/ysn551/items/c62be92937b86a91ccfd)
bashスクリプトで実行されたコマンドを表示する


デバッグしやすくするために、`set -x`を先頭に書いておくことで実行されたコマンドを都度表示することができます。

```bash
#!/bin/bash
set -x
date
```

```bash:実行結果
+ date
Fri Mar 23 02:30:35 UTC 2018
```
このように `+` につづいて `date` コマンドを実行したことがわかります。
開発中に便利 :star2:
中国製Arduino互換機でLチカをしてみよう

この記事の目的
--

この記事では、中国で売られている[Arduio UNO R3](https://store.arduino.cc/usa/arduino-uno-rev3)の互換機(またはArduino UNO R3偽物)にLEDをつけ、LEDを点滅させる(Lチカ)をすることをゴールとします。

免責
--

この記事について書かれているとおりにして発生した如何なる事象についても、筆者および関係者は一切の責任を負いません。

中国製Arduino互換機について
--

Arduinoはオープンなハードウェアです。
基板データが公開されているされているため、設備があれば誰でも互換機を作ることができる[^1]ため、Arduinoの互換機が作られています。
[^1]: "Arduino"という名称は商標登録されているため、互換機は"Arduino"を名乗ることはできませんが。しかし、"Arduino"を名乗っている偽物を見ることもあります。
Arduino UNO R3の正規品は3,000円くらいしますが、中国だと互換機は数百円くらいで買えたりします。

![中国の深圳の電気街である华强北で購入したArduino UNO R3互換機](https://qiita-image-store.s3.amazonaws.com/0/67657/b587aef2-957d-b3ca-8c88-a0d246e92cba.jpeg "中国の深圳の電気街である华强北で購入したArduino UNO R3互換機")

![右が互換機、左が本物のArduino UNO R3](https://qiita-image-store.s3.amazonaws.com/0/67657/fcb56311-a7b9-a8af-bff4-5faa1da9efce.jpeg "右が互換機、左が本物のArduino UNO R3")


Arduino UNO R3と中国製互換機の違い
--

いろんなところで互換機が作られているため一概に違いを述べることはできませんが、USB-Serialのチップが違うことが多いです。
Arduino UNO R3はUSB-SerialのチップにATmega8u2が使われていますが、中国製の互換機では中国WCH社製のCH340というチップが使われていることが多いようです。
互換機を使う前にCH340のドライバをインストールする必要があります。
ドライバをインストールすればあとはArduino UNO R3と全く同じように使えます。

CH340のドライバのインストール
--

### Windows

http://www.wch.cn/download/CH341SER_EXE.html のサイトを開き、Windowsのドライバがあるのでダウンロードしインストールしてください。

### Mac

http://www.wch.cn/download/CH341SER_MAC_ZIP.html のサイトを開き、Macのドライバがあるのでダウンロードしインストールしてください。

「公式のドライバをインストールすると互換機を接続時にクラッシュする」として、他のサイトから公開されたドライバをインストールするように促しているサイトもあります[^2]。
[^2]: 以前は署名された公式のドライバが公開されていなかった名残のようです。
が、現時点で上記で公開されている公式ドライバでHigh Sierraで問題なく動作しています。

Arduino IDEのインストール
--

[Arduinoのサイト](https://www.arduino.cc/)からArduino IDEをダウンロードしてインストールしてください。
サイト上部のメニューから `Software` → `Downloads` を選択するとダウンロードページに遷移します。
記事執筆時点での最新版は `1.8.5` です。

LEDをつなげる
---

写真の通りにLEDをつなげます。
LEDの足の長い方(LEDの+)を13番に刺し、LEDの足の短い方(LEDの-)をGNDに刺します。

![IMG_20180323_003254-2.jpg](https://qiita-image-store.s3.amazonaws.com/0/67657/37680416-1c01-25d9-a417-ac800c4f69ff.jpeg)

逆に刺すとLEDが光りませんが壊れることはまずないので、もし光らない場合はLEDの足を逆にして刺してみてください。

プログラムを書き込みLチカしてみる
---

Arduino互換機とPCをUSBで接続し、Arduinoのアプリを立ち上げます。
メニューの[Tools] → [Port]から `/dev/cu.wchusbserial142220` を選びます。
また、[Tools] → [Board]から `Arduino/Genuino UNO` を選びます。

下記のコードをエディタ部に入力し、 [Sketch] → [Upload]を選択します。
するとLEDが1秒おきに点滅します。

```c
const int led = 13; // LEDの接続を13番ポートにする

void setup() {
  pinMode(led, OUTPUT); // 13番ポートを出力にする
}

void loop() {
  digitalWrite(led, HIGH); // LEDを光らせる
  delay(1000);             // 1秒待つ
  digitalWrite(led, LOW);  // LEDを消す
  delay(1000);             // 1秒待つ
}
```
drawable xml内でattrsを参照するとクラッシュするバージョンについての話

# 概要

shapeなどのdrawable xml内でattrs(`?`で参照する変数)に参照するとランタイムでクラッシュします。
これはAndroid 4.4まで存在していたバグで、5.0で修正されたと思われていたのですが…

思ってたよりひどかった。


# 検証コード

attrs参照でクラッシュする記述は2種類あります。

## パターンA

shapeで`?selectableItemBackground`を使う。
(`?`参照なら何でも構いません)

```drawable/shape_pattern_a.xml
<layer-list>
   <!-- ここ -->
   <item android:drawable="?selectableItemBackground" />

   <item>
       <shape android:shape="rectangle">
           <solid android:color="@android:color/black" />
           <corners android:radius="2dp" />
           <padding
               android:bottom="4dp"
               android:left="8dp"
               android:right="8dp"
               android:top="4dp" />
       </shape>
   </item>

</layer-list>
```

## パターンB

attrsを直接使うのではなく、間接参照します。

```drawable/shape_pattern_a.xml
<layer-list>
   <!-- ここ -->
   <item android:drawable="@drawable/mySelectableBackground" />

   <item>
       <shape android:shape="rectangle">
           <solid android:color="@android:color/black" />
           <corners android:radius="2dp" />
           <padding
               android:bottom="4dp"
               android:left="8dp"
               android:right="8dp"
               android:top="4dp" />
       </shape>
   </item>

</layer-list>
```


```values/drawables.xml
<resources>
    <drawable name="mySelectableBackground">?selectableItemBackground</drawable>
</resources>
```

# 結果

| バージョン | パターンA | パターンB |
|:--:|:--:|:--:|
| **4.4以下** | クラッシュ | クラッシュ |
| **5.x** | OK | クラッシュ |
| **6.0以上** | OK | OK |


# まとめ

4.4以下に人権はない。
正規表現で日本の住所を解析する

#背景
ネット上に乗せられてある日本の住所のフォーマットが普段は決まっています。郵便番号から都道府県市区町までの流れて表示しているはず。そして正規表現の郵便番号とか県名とかを抽出することによって、Google Geocodingするなど仕様はよくあります。

#正規表現
ここで気をつけないといけないのは県名とか市名とかを抽出するためには貪欲モードを使うわけにはいかないです。
(.\*県)ではなくて(.\*?県)です
そうしないと、例えば"愛知県名古屋市県民分館"を解析の結果は"愛知県"ではなく、"愛知県名古屋市県"まで取り出してしまいます。

#ソースコード

```

String matchString = "〒066-0012\n" +
        "北海道千歳市美々　新千歳空港国内線ターミナルビル２Ｆ";

Matcher matcher = Pattern.compile("\\s*〒(\\d{3}-\\d{4})[\\s　]*(.*?都)?(.*?道)?(.*?府)?(.*?県)?(.*?市)?(.*?区)?").matcher(matchString);

while (matcher.find()){
    System.out.println("住所:" + matcher.group(0));
    System.out.println();
    System.out.println("郵便番号:" + matcher.group(1));
    System.out.println();
    System.out.println("都名:" + matcher.group(2));
    System.out.println();
    System.out.println("道名:" + matcher.group(3));
    System.out.println();
    System.out.println("府名:" + matcher.group(4));
    System.out.println();
    System.out.println("県名:" + matcher.group(5));
    System.out.println();
    System.out.println("市名:" + matcher.group(6));
    System.out.println();
    System.out.println("区名" + matcher.group(7));
}
      
```


#結果

```
住所:〒066-0012
北海道千歳市

郵便番号:066-0012

都名:null

道名:北海道

府名:null

県名:null

市名:千歳市

区名null

```

簡単な内容ですが、よく使われると思って、投稿しました。
Vue.js の data に Map 型変数を使うとリアクティブにならない

Map 型はいいぞ。ES6 からサポートされた本物の連想配列だ。と、みなさんが賞賛していたので積極的に使っていたのですが Vue.js の data に使っていると何やら挙動がおかしいのです。変更しても再描画されない。リアクティブになってくれてないようなのです。

そこで検証してみたのがこちらです。

<p data-height="254" data-theme-id="0" data-slug-hash="QmvaBv" data-default-tab="html,result" data-user="akicho8" data-embed-version="2" data-pen-title="Vue.js Map Class Reactive Test" class="codepen">See the Pen <a href="https://codepen.io/akicho8/pen/QmvaBv/">Vue.js Map Class Reactive Test</a> by Akira Ikeda (<a href="https://codepen.io/akicho8">@akicho8</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

1. 似非連想配列を普通に更新 (Vue.js を始めた人がはまるやつ)
2. **似非連想配列を Vue.set を使って更新**
3. Map 型を普通に更新
4. Map 型を Vue.set を使って更新

これの2番目だけが成功します。悲しいことに 3, 4 の Map 型は無反応です。

リアクティブの探求 — Vue.js
https://jp.vuejs.org/v2/guide/reactivity.html

によると、

> プレーンな JavaScript オブジェクトを (略) getter/setter に変換します。

とあってどこまでがプレーンなのかよくわからなかったのですが Map 型は含まれていないということです。
ご注意ください。
EC-CUBEのSymfony開発ブランチでカスタマイズディレクトリを使って新規画面を追加してみる

# 概要

EC-CUBEのSymfony開発ブランチではEC-CUBE3.0系にはなかったカスタマイズディレクトリによるカスタマイズ方法が導入されています。
本記事ではカスタマイズ例として新規画面追加までの流れを示します。

ソースコードは以下でも確認いただけます。
https://github.com/okazy/ec-cube/tree/demo

# 新規画面追加

`/demo` のURLで新規画面を追加します。

詳しい内容は[公式ドキュメント](http://doc3n.ec-cube.net/customize_controller)を参照してください。

## Step1: `/app/Customize/Controller` 配下に `DemoController` クラスを作成します。

```php:/app/Customize/Controller/DemoController.php
<?php
namespace Customize\Controller;

class DemoController
{

}
```

## Step2: `demo()` ファンクションを追加します。

```php:/app/Customize/Controller/DemoController.php
<?php

namespace Customize\Controller;

class DemoController
{
    public function demo()
    {

    }
}
```

## Step3: `@Route` アノテーションでルーティングの設定をします。

```php:/app/Customize/Controller/DemoController.php
<?php

namespace Customize\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

class DemoController
{
    /**
     * @Route("/demo", name="demo")
     */
    public function demo()
    {

    }
}
```

## Step4: 戻り値でResponseクラスを返します。

この時点で画面が表示できるようになりますので確認して見てください。

```php:/app/Customize/Controller/DemoController.php
<?php

namespace Customize\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;

class DemoController
{
    /**
     * @Route("/demo", name="demo")
     */
    public function demo()
    {
        return new Response("Hello Demo!");
    }
}
```

## Step5: `@Template` アノテーションでテンプレートファイルを指定します。

```php:/app/Customize/Controller/DemoController.php
<?php

namespace Customize\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\HttpFoundation\Response;

class DemoController
{
    /**
     * @Route("/demo", name="demo")
     * @Template("demo.twig")
     */
    public function demo()
    {
        return new Response("Hello Demo!");
    }
}
```

## Step6: 戻り値でテンプレートへ変数をわたします。

```php:/app/Customize/Controller/DemoController.php
<?php

namespace Customize\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

class DemoController
{
    /**
     * @Route("/demo", name="demo")
     * @Template("demo.twig")
     */
    public function demo()
    {
        return [ "name" => "Demo" ];
    }
}
```

## Step7: `/app/template` 配下にテンプレートファイルを追加します。

```twig:/app/template/default/demo.twig
<h1>Hello {{ name }} !!</h1>
```

画面を更新して見てh1タグで `Hello Demo !!` と表示されて入れば成功です！
css 忘れやすいポイント

cssにおいて忘れやすいポイントを３つ明記

１、ヘッダーの固定
```
position:fixed;
width:100%; この２行が必須

padding: ヘッダーの高さ分も忘れずに
```

2、コンテンツへの入力が多くなった場合に高さがテキスト分増加し
　　　　万が一、テキストが減っても高さを残す方法

```
min-height: ;最低限の高さを明記できる

```

３、テキスト関係の表記方法

text-alignプロパティは、
ブロック要素の中に入っているインライン要素やテキストを中央寄せにする

背景色を維持したまま幅を取りたい時にはpaddingプロパティを使う。

class="contents"の要素を中央寄せにします。

ブロック要素に対しては、横幅を指定した上で、
左右のmarginの値をautoにすると中央寄せにすることができます。
上下のmarginは要らないため、0にする

上下が0、左右がautoの場合

margin: 0 auto;
[python2][python3]printが文でなくて式になると何がうれしいか？【雑考】

今はpythonを使っているのでいいんだけど、いずれ古巣に戻るつもりなので、そこからまたpythonに戻ってきたら確実に忘れてるだろうな、と思うことを備忘録にしています。

# printが式でなくて文になると何がうれしいか？
<a href="http://d.hatena.ne.jp/hekyou/20111224/p1">探せばこのように、小難しい話とかはいっぱいある</a>んですが、**実感として自分に降りてきてない**ので自分どうなんよ？という話にフォーカスします。
**正確性のある、かつ体系的な情報を求めている方にとっては有益な情報は提供できていない**[^1]かもしれません…
[^1]: 【有益な情報が提供できない理由】アーキテクチャーの話も理解しようとしたのですが、私の中でうまく理解しきれていません…

## 大前提
以下のように書くとpython2系でも式っぽくなります。

``` user_print.py
lambda message:print message

# 上記は以下と同義
import six
def message(message):
  if six.PY2:
    print message
  elif six.PY3:
    print message
```

なので、python2でもprintを式っぽく書くこと自体は可能です。
厳密に言うと上記サイトの通り、上記のようなオレオレ関数は小回りは利かないのでpython3のprint式とは違うのですが…
私が使ってきた範囲ではあんまり関係ないので、本記事では同じものとして扱います。

## 実践
高階関数を使うのが分かりやすいと思います。

``` practice.py
from user_print import user_print

str_list = [
  'test1',
  'test2',
  ]

list(map(print, str_list))  # python3
list(map(lambda string:print(string), str_list))  # python3

list(map(message, str_list))  # python2
list(map(lambda string:message(string), str_list))  # python2

# forで書く
for string in str_list:
  message(string)  # if six.PY3: print(string)

```

別にfor文に何か思うところがあるわけではないんですが、たとえば上記のようにする場合。
mapとかで引数が一つのケースでlambda式を書くメリットはほとんどないと思ってますが、帰ってきた時に忘れてそうなので書いておきます。

### 脱線メモ
以下のようなケースではlambda式を使う必要があります。

``` class.py
class user_print(object):
  def __init__(self, string):
    self.string = string
  def main(self):
    print(self.string)

list(map(lambda string:user_print(string).main(), str_list))
```
list(map(user_print, str_list))
とか
list(map(user_print.main(), str_list))
は期待する結果を得られませんが、エラーにもなりません（？）

## 要望、というか希望
上記でも書いてますが、printとmessageは同じものなので深く考えなくていい[^2]んですが、message関数のようにバージョンに対応出来た方が比較的親切かな、と思うシーンが多かったです。
本来はpy2とpy3のパーサがあればいいんでしょうが[^3]、探すより作ったほうが楽だったのでそうしてます。
個人の環境でgitサーバーなりを立ててライブラリをまとめたプロジェクトを置いておくだけでも相当捗ります。

[^2]: 【printとユーザー関数messageが同じ】大事な事なので何度も言いますが、本記事のような使い方に限定しています。
[^3]: 【py2-py3のパーサ】例えば今回でいうところのprint文・式をいい感じにするものとかはありそうな気はしますよね。configparserとConfigparserみたいなのとか、socketのsettimeoutとか、探せば色々見つかります。

# 念のために
- python2.7.12
- python3.6.4

で検証しています。

# 読了後いいね！をお願いします。
どれだけの方に読んでもらっているか知りたいので、お手数をおかけしますがご協力いただけると嬉しいです。
Azure ノウハウ

# ストレージアカウント
https://docs.microsoft.com/ja-jp/azure/storage/common/storage-create-storage-account


# 単語
BLOB（Binary Large OBject）・・・データベース管理システム(DBMS)においてバイナリデータを格納する場合のデータ型である。画像や音声、その他のマルチメディアオブジェクトがBLOBとして格納される。時には実行形式が格納されることもある。
【LINE bot】可愛くするために

# はじめに

- Line bot勉強会の資料です。
- botは機械的に判断されがち
- スタンプや、絵文字を入れるだけでふんわりする

---
## LINE bot勉強会の流れ
|流れ|step1|step2|step3|
|:--:|:--:|:--:|:--:|
|機能|[おみくじbot](https://qiita.com/4geru/items/438a2dfcaf9eea4bdbb5)|[カウントbot](https://qiita.com/4geru/items/ef59098cec4708a6b7a3)|[最寄駅検索bot](https://qiita.com/4geru/items/30fa69c65e9fcdd12108)|
|学ぶこと|LINE botの作り方|DB・リッチニュー|ボタンアクション・URIスキーマ・外部API|

その他TIPS

- <strong>[可愛くするために](https://qiita.com/4geru/items/398a38c89cf01bb8f151)</strong>
 - スタンプの使い方
 - 絵文字の使い方

---
# 今回学ぶこと
- スタンプを送る
- 絵文字を使う

---
# スタンプの送り方
[ドキュメント](https://developers.line.me/ja/docs/messaging-api/reference/#anchor-e6e9bb7daca9d620ad548d23e157ecab6d396573)

```ruby:example
{
  "type": "sticker",
  "packageId": "1",
  "stickerId": "1"
}
```

---
## スタンプの情報

- スタンプの情報はdevelopersにpackageIdとstickyIdの一覧があります。
- packageId=STKPKGID, stickyId=STKIDで対応しています。

[スタンプ一覧](https://developers.line.me/media/messaging-api/sticker_list.pdf)

---
## スタンプの利用例
- 自分の場合は乱数を用いて喜怒哀楽をスタンプを通じて送信するようにしています。
- reply_messageは第二引数を配列にすることにより、複数のメッセージを返すことができます。
- 配列の中からランダムで、スタンプを返す関数を作成し、メッセージを送ります。

```ruby:app.rb
client.reply_message(event['replyToken'], [happySticky, message])
```

```ruby:app.rb
def happySticky
  [    
    { "type": "sticker", "packageId": "1", "stickerId": "4" },
    { "type": "sticker", "packageId": "1", "stickerId": "5" },
    { "type": "sticker", "packageId": "1", "stickerId": "13" },
  ].shuffle.first
end
```

---
# 絵文字の利用例
- 絵文字は:book: :pencil: :thumbsup: などイメージを沸かせるのに効果的です。
- [Unicode](http://www.unicode.org/emoji/charts/full-emoji-list.html)と[LINE独自](https://developers.line.me/media/messaging-api/emoji-list.pdf)の絵文字を使うことができます。
- UnicodeはiPhoneとAndroidで見え方が違うので少し注意が必要です。
- rubyの文字列の中で、Unicodeを使う場合には`\u{xxxxx}`と表記すると利用できます。

---
# まとめ
- 絵文字・スタンプを入れることによって、優しい感じのbotができる。
- スタンプをランダムに表示させることによりAIっぽさが出る。
- 絵文字を入れることにより絵だけでなくイメージが湧く。

---
## 参考文献

- [LINE BOT作りに使えるスタンプ参照表](https://qiita.com/fuji_syan/items/63caa2515871aff65e35)
- [rubyでunicode, UTF8を扱うためのTips](https://qiita.com/kasei-san/items/fb9a6c8bdfafb2449b36)
Hyperledger-fabric  ノウハウ

# ストレージアカウント
https://docs.microsoft.com/ja-jp/azure/storage/common/storage-create-storage-account

# 参考HP
Fabric公式ドキュメント
https://hyperledger-fabric.readthedocs.io/en/release/
Architecture Explained
http://hyperledger-fabric.readthedocs.io/en/release/arch-deep-dive.html#architecture-explained
Endorsement policyについて
https://qiita.com/kozw4x_2e/items/25f6c58b40a6a325e211
Howto make big request body


```shell

$ dd if=/dev/zero of=zero bs=1024k count=128
128+0 records in
128+0 records out
134217728 bytes transferred in 0.199715 secs (672045843 bytes/sec)
$ curl -v -H "Expect:" -XPOST localhost:9200/ --data-binary @zero

```

Refer: https://github.com/elastic/elasticsearch/issues/2902#issuecomment-267572324
VMware Workstation 12 Player のゲスト OS 内で FreeBSD 10.3 に xorg をインスコさせて日本語入力と Firefox を動作させる手順書 ibus-mozc版

VMware Workstation 12 Player のゲスト OS 内で FreeBSD 10.3 に xorg をインスコさせて日本語入力と Firefox を動作させる手順書。

xorg で利用する windowmanager は MATE(マテ) を利用しログインは slim を使って簡素な x window システムを構築しデバック環境を整えるのがお題目(笑)

日本語として ibus-mozc を用いるが他の物を使うなら ibus-mozc 関連のインスコは無視してもよい。

VMware は既に環境が整っていることを前提に、肝心な個所のみ記述していくので詳細は割愛している。必要であれば各自で調べるなりして欲しい。

OS の入手先 url
ftp://ftp.jp.freebsd.org/pub/FreeBSD/releases/amd64/amd64/ISO-IMAGES/10.3/FreeBSD-10.3-RELEASE-amd64-disc1.iso

以下を wheel グループユーザでインスコする。

```text
# pkg install \
	xorg \
	mate \
	slim \
	open-vm-tools \
	xf86-input-vmmouse \
	xf86-video-vmware \
	firefox-i18n \
	ja-font-std \
	ja-ibus-mozc
```

次に以下のファイルを新規作成する。

```text:~/.xinitrc
export XIM=ibus
export GTK_IM_MODULE=ibus
export QT_IM_MODULE=xim
export XMODIFIERS=@im=ibus
export XIM_PROGRAM="ibus-daemon"
export XIM_ARGS="--daemonize --xim"
/usr/local/bin/mozc start
ibus-daemon -r --daemonize --xim
```

```text:/usr/local/etc/X11/xorg.conf.d/keyboard.conf
Section "InputClass"
	Identifier	"system-keyboard"
	MatchIsKeyboard	"on"
	Option		"XkbLayout" "jp"
	Option		"XkbModel" "pc106"
	Option		"XkbOptions" "terminate:ctrl_alt_bksp"
EndSection
```

```text:/usr/local/etc/X11/xorg.conf.d/system.conf
Section "ServerFlags"
	Option		"DontZap" "false"
EndSection
```

```text:/usr/local/etc/X11/xorg.conf.d/vmmouse.conf
Section "InputClass"
	Identifier	"Mouse Defaults"
	Driver		"vmmouse"
	MatchIsPointer	"on"
EndSection
```

デスクトップ環境に ibus-mozc 関連のアイコン表示するために、環境ファイルをコピーする。

```text
# mkdir ~/.config/autostart/
# cp -a /usr/local/share/applications/ibus-setup.desktop ~/.config/autostart/
```

IBus の設定
「詳細」→「キーボードレイアウト」→「システムのキーボードレイアウト」を使用するにチェック
ここまでで、firefox の日本語入力は可能となる。
VMware Workstation 12 Player のゲスト OS 内で FreeBSD 10.3 に xorg をインスコさせて日本語入力と Firefox を動作させる手順書 fcitx-mozc版

VMware Workstation 12 Player のゲスト OS 内で FreeBSD 10.3 に xorg をインスコさせて日本語入力と Firefox を動作させる手順書。

xorg で利用する windowmanager は MATE(マテ) を利用しログインは slim を使って簡素な x window システムを構築しデバック環境を整えるのがお題目(笑)

日本語として fcitx を用いて M$ 系の IME からの移行もスムーズに出来る事を意図しているので、他の物を使うなら fcitx 関連のインスコは無視してもよい。

VMware は既に環境が整っていることを前提に、肝心な個所のみ記述していくので詳細は割愛している。必要であれば各自で調べるなりして欲しい。

OS の入手先 url
ftp://ftp.jp.freebsd.org/pub/FreeBSD/releases/amd64/amd64/ISO-IMAGES/10.3/FreeBSD-10.3-RELEASE-amd64-disc1.iso

以下を wheel グループユーザでインスコする。

```text
# pkg install \
	xorg \
	mate \
	slim \
	open-vm-tools \
	xf86-input-vmmouse \
	xf86-video-vmware \
	firefox-i18n \
	ja-font-std \
	ja-fcitx-mozc \
	zh-fcitx-configtool
```

次に以下のファイルを新規作成する。

```text:~/.xinitrc
export GTK_IM_MODULE=fcitx
export QT_IM_MODULE=xim
export XMODIFIERS=@im=fcitx
/usr/local/bin/mozc start
fcitx -r -d
```

```text:/usr/local/etc/X11/xorg.conf.d/keyboard.conf
Section "InputClass"
	Identifier	"system-keyboard"
	MatchIsKeyboard	"on"
	Option		"XkbLayout" "jp"
	Option		"XkbModel" "pc106"
	Option		"XkbOptions" "terminate:ctrl_alt_bksp"
EndSection
```

```text:/usr/local/etc/X11/xorg.conf.d/system.conf
Section "ServerFlags"
	Option		"DontZap" "false"
EndSection
```

```text:/usr/local/etc/X11/xorg.conf.d/vmmouse.conf
Section "InputClass"
	Identifier	"Mouse Defaults"
	Driver		"vmmouse"
	MatchIsPointer	"on"
EndSection
```

デスクトップ環境に fcitx 関連のアイコン表示するために、環境ファイルをコピーする。

```text
# mkdir ~/.config/autostart/
# cp -a /usr/local/share/applications/fcitx.desktop ~/.config/autostart/
```

ここまでで、firefox の日本語入力は可能となる。
DjangoのデータベースアクセスでIM002または08001エラーが出る

# エラー内容
InterfaceError 
'IM002', '[IM002] [Microsoft][ODBC Driver Manager] データ ソース名および指定された既定のドライバーが見つかりません。 (0) (SQLDriverConnect)'
# 発生状況
Python Djangoでpyodbcを使って、Microsoft SQL Serverに接続している。
開発環境ではアクセスできるが、実行環境のIISへデプロイしたところエラーが出た。
![pyodbc3.PNG](https://qiita-image-store.s3.amazonaws.com/0/241999/0081821c-b16e-1c62-5fe8-af2edafdd758.png)

# 環境
### 開発環境
-Windows10 64bit
-Visual Studio Community 2017 ver.15.4.1
-Python ver.3.6.1
-Anaconda ver.4.4.0
-Django ver.1.11.11
-django-pyodbc ver.1.1.3
### 実行環境
-Windows7 32bit
-IIS Version 7.5.7600.16385
-Django ver.2.0.3
-django-pyodbc ver.1.1.3

## 解決方法とソース
接続文字列を修正することで、解決した。
開発環境で正常に動いていた接続文字列はこちら。

```db_access.py
connectionString = 'DRIVER={ODBC Driver 13 for SQL Server}; 
SERVER='+'localhost'+'; DATABASE='+'database'+';
UID='+'sa'+'; PWD='+'password'
```

実行環境の方は、こう書き換えたら正常に動いた。

```db_access.py
connectionString = 'DRIVER={SQL Server};
SERVER='+'localhost'+'; DATABASE='+'database'+';
UID='+'sa'+'; PWD='+'password'
```

なお開発環境の接続文字列を上記のように変えると、また異なるエラーが出た。
>OperationalError
>'08001', '[08001] [Microsoft][ODBC SQL Server Driver][DBNETLIB]SQL Server が存在しないか、アクセスが拒否されました。 (17) (SQLDriverConnect); [08001] [Microsoft][ODBC SQL Server Driver][DBNETLIB]ConnectionOpen (Connect()). (5)'

![pyodbc2.PNG](https://qiita-image-store.s3.amazonaws.com/0/241999/f82c48d8-7c3f-b97a-1978-58a83b94743e.png)

環境によってDjangoのバージョンが一致しないことが原因の模様。
PHP DBUnit で getDataSet() が動作しなかった件

# 環境（今回の原因は環境関係ないですが）
　FuelPHP 1.8
  PHP 5.6
  PHPUnit 5.5.7
  DBUnit 2.0.3

# 動かなかったソース
```php:controller.php
class TestCase_Controller extends \PHPUnit_Extensions_Database_TestCase
{
    protected function getConnection()
    {
        //～～～割愛～～～
    }

    protected function getDataSet()
    {
      //実際に読み込む内容は各テストクラスに記載している
    }

    protected function setup()
    {
        //～～～いろいろ 処理（割愛）～～～
    }
```

# 原因
「setup()」の中で「parent::setUp()」を実行していなかった

# 修正後ソース
```php:controller.php
class TestCase_Controller extends \PHPUnit_Extensions_Database_TestCase
{
    protected function getConnection()
    {
        //～～～割愛～～～
    }

    protected function getDataSet()
    {
      //実際に読み込む内容は各テストクラスに記載している
    }

    protected function setup()
    {
        parent::setUp();

        //～～～いろいろ 処理（割愛）～～～
    }
```

気づいてしまえば、そりゃそうだよね、、、というミスでした。orz
assertInstanceOfが使えない！？どーすれば・・・

# 概要

PHPもPHPUnitもバージョンが古くてassertInstanceOfがそもそも使えない。
テストどーするよ・・・？となった時のためのTips。


# そもそもassertInstanceOf使って何したいんだっけ？

返ってくる値がそもそもちゃんと正しいクラスオブジェクトかどうかを確かめたかった。
今回の私の場合でいうと、以下のようなメソッドのテストを書きたかった。
ただそれだけ・・・。

```php:sample.php
<?php

class SampleClass
{
    protected function sampleMehthod ($args) {
        switch($args) {
            case '1':
                ~ => なんかクラスオブジェクトが返ってくるよ？例えば　case1objectとか
            case '2':
                ~
            ・・・
    }
}
```

そもそもこれが綺麗じゃないとかそれはおいておくとして・・・
書かねばいかんのだ。

# assertInstanceOf を assertEqualsで置き換えてみる

これが本質的なアプローチではないかも。
もちろん古いのでReflectionを使ったprotectedのアプローチは使えません・・・
そのため、dummyObjectをかませつつ、sampleMethodを呼んだ上で、assertEqualsを使う。
結局以下のような感じに。


```php:testsample.php
require_once 'sample.php'

class dummyClass extend SampleClass
{
    ~値をセットしたりとかのメソッドを書いておく~
}

class test
{
    public function testSampleMehthod {
        $dummy = new dummyClass();
        $sample_object = $dummy->sampleMethod($args);

        $this->assertEquals(
            get_class(--期待する該当クラスのオブジェクト--),
            get_class($sample_object)
        );
    }
}
```

何か他に良い施策をお持ちの方。教えていただけると嬉しいです。

# 他の方法として(追記)

@ysKuga さんに教えていただいた方法。
assertEqualsではなく、assertTrue(場合によってはassertFalse)とinstanceofを使って判定を行う。testsample.phpの「$this->assertEquals」を以下のように置き換えて使用する。PHP5から使用可能。それより前のバージョンは・・・。

```php:testsample2.php
・・・
       $this->assertTrue($sample_object instanceof SampleClass) 
・・・
```
TradingViewのPine Scriptを効率的にデバッグする

Pine Scriptにはコンソール出力のような仕組みがないため、複雑なスクリプトのデバッグが少し面倒です。

ここでは実際にPine Scriptを書いていてデバッグの役に立った機能についてまとめます。

# 特定の条件を満たしているポイントを可視化する
`plotchar`を使うと、特定の条件を満たしているキャンドル上に印を表示することができます。

```
longSignal = ...
plotchar(longSignal, location=location.belowbar, text="Longエントリー")
```

`bgcolor`を使うとチャート上の任意の範囲で背景色を変更することができます。条件にマッチした範囲をまとめて可視化したい時などに有用です。

```
//@version=3
study("My Script", overlay=true)

// ローソク足の頭が前の頭より上に出ている場合、背景を青に
bgcolor(max(open, close) >= max(open[1], close[1]) ? blue : na)
```

![3CF65C3E-B823-4220-9330-67E24BCEF045.png](https://qiita-image-store.s3.amazonaws.com/0/7325/0ad226ba-3177-fb2e-c37f-0fb65938d2e4.png)



# 数値の可視化
`plotchar` は手軽にチャートへ印をつけられますが、表示する文字列には定数しか使えないため、各ローソク足での計算結果を確認のために表示するといった事はできません。

ローソク足で計算した数値を可視化したい場合は`plot`でグラフを描画します。
例としてローソク足の胴の長さ・上下のヒゲの長さを表示するインジケータを用意します。

```
//@version=3
study("My Script")

plot(abs(high - max(open ,close)), title='上ヒゲの高さ', color=green, linewidth=1)
plot(abs(high - low), title='胴の高さ', color=black, linewidth=1)
plot(abs(low - min(open ,close)), title='下ヒゲの高さ', color=red, linewidth=1)
```

チャートにこのインジケータを追加します。線グラフでぱっと見数値が見えづらいですが、マウスオーバーしたローソク足における数値がインジケータ名の横に表示されるので、これを見ればデバッグがやりやすくなります。

![candle-debug.gif](https://qiita-image-store.s3.amazonaws.com/0/7325/56c2ac5d-5cd8-c123-2195-3f110b7c575c.gif)


# まとめ
Pine Scriptのデバッグを効率的に行う方法についてまとめました。現状ではplot系の関数を頑張って活用するしか方法がありませんが、Pine Script v4以降でコンソール出力機能が追加される事を期待しています。
Webフォントによるちらつきをなくす方法（ネット低速環境も考慮）

# 2022/07/26追記
Loading画面を使用したい場合は[こちら！！](https://qiita.com/hirossyi73/items/731b829673affaed1e98)
# はじめに
AdobeやGoogleが用意しているWebフォント、本当に便利ですよね。
スタイリッシュなフォントを、CSSやJavascriptの数行を追加するのみで使用できる優れものです。
ですが欠点として、Webフォントを読み込みブラウザに反映させるのに若干ラグがあるために、文字幅の変更が発生することから、
**サイトが一瞬ちらついて表示されているように見えます。**
これには「Flash Of Unstyled Text (FOUT)」という名前も付いているようです。
具体例：https://helpx.adobe.com/jp/typekit/using/font-events.html
このちらつきをなんとかする方法ですが、[すごく参考になるサイト](https://blog.aroundit.net/webfont-fout/)があって、
Webフォントの読み込み完了後、htmlタグに.wf-activeというclassが挿入されることから、
以下のようなcssを紹介されております。
```css
html {
  visibility: hidden;
}
html.wf-active {
  visibility: visible;
}
```
通常のhtmlタグにはvisibility: hidden;のスタイルを追加しておいて、
Webフォントの読み込みが完了したら付加されるクラスwf-activeによって、visibility: visible;が反映させるという流れ。
非常に分かりやすくて活用しやすいのですが、一点欠点があって、
それは**低速環境だと画面がいつまでも表示されないこと。**
電車の中のスマホ、帯域制限・・・色んな理由がありますが、いつまでも真っ白な画面となるサイトを作るのは考えものです。
その現象の改善方法を記載します。
# 方針
(1)基本的には、Webフォントの読み込みが完了したら画面表示を行う
(2)ただし低速環境を考慮して、**一定時間経過したら強制的に画面表示を行うようにする**（Webフォント読み込み完了かは問わない）
# コード
以下のcssとjavascriptを追加してください。
## css
```css
html {
  visibility: hidden;
}
html.wf-active, html.loading-delay {
  visibility: visible;
}
```
## javascript
**※headタグ閉じの直前に記載すること**
```javascript
setTimeout(function () {
    document.getElementsByTagName("html")[0].classList.add("loading-delay");
}, 3000);
```
解説すると、読み込み開始3秒後にhtmlタグに"loading-delay"クラスを追加します。
cssによって、Webフォント読み込み完了後に付加されるwf-activeクラス、もしくは3秒後に付加されるloading-delayクラスによって、htmlはvisibleになるという流れです。
例の場合は3秒後に強制表示を行っています。時間を前後させたい場合は、javascript3行目の「3000」を変更するといいです。
ニューラルネットを使って任意の分布からサンプリングする

##はじめに
[前回の記事](./544ecdded914289c85c8)で紹介した密度推定の手法を応用して、データのサンプリングを行ってみます。
$F(x)=P(X\leq x)$を学習させたモデルをもとに、この逆関数$G(y)$を同様のニューラルネットで学習させます。
$[0, 1]$の一様分布から得られた$y$に対して、$F(G(y))$がyに近づくようにオートエンコーダ的な学習を行えばいいわけです。損失関数にはベルヌーイ分布を仮定した負の対数尤度([chainer.functions.bernoulli_nll()](https://docs.chainer.org/en/stable/reference/generated/chainer.functions.bernoulli_nll.html))を使います。
学習後、サンプリングを行うには$[0, 1]$の一様分布から得られた$y$で$G(y)$を計算させれば良いです。

###一次元混合ガウス分布
オレンジ色の実線が学習済みの$P(X)$で、青の棒グラフが今回のサンプリング結果です。
$P(x)=0$ 付近と、$P(x)=1$ 付近ではうまくサンプルが得られていないようです。
![mixed_gaussian_1d_sampled.png](https://qiita-image-store.s3.amazonaws.com/0/152511/262c1ae1-1ecb-65be-2f25-bf012b37d227.png)

###二次元混合ガウス分布
左から順に、元データ、$P(X)$の学習結果、今回の手法によるサンプリング結果です。
$P(X)$の学習結果に影があらわれていますが、Min-Max Poolingが悪さをしているようです。このプーリングは不要なのかもしれません（要調査）。
![mixed_gaussian_2d_sampled.png](https://qiita-image-store.s3.amazonaws.com/0/152511/45a7db86-afd0-5fee-d3fb-dcfbfe636c7f.png)

###二次元切断(?)ガウス分布
![half_gaussian_2d_sampled.png](https://qiita-image-store.s3.amazonaws.com/0/152511/2936e475-c937-5871-b67a-a66b15c056fd.png)
$P(X)$のヒートマップ上ではうまく行っていないように見えましたが、今回の結果を見ると意外と形は取れているようです。
ネットワークブリッジ動作不良の対応(VMWare)

# 現象
VMWare Workstationを起動したら、「デバイス VMnet0 のネットワーク ブリッジが動作していません」のメッセージが表示され、仮想マシンがネットワークにつながらなくなった。

#環境
ホストOS：Windows 10 (Ver. 1709)
ゲストOS：Windows Server 2008
VMWare ：VMWare Workstation 12.5.9

# 原因
Windows 10 (Creators Update)の適用？

# 対策
1. VMWare Workstationを修復セットアップする。
2. ホストOSのネットワークアダプタの「VMware Bridge Protocol」をONにする。
このとき、ブリッジさせるアダプタのみ適用することに注意。複数のアダプタの「VMware Bridge Protocol」がONになっていると、期待したアダプタを使用されない場合もあるようです。

# 参考
https://www.teradas.net/archives/12033/
https://pig-log.com/vmware-player-vmnet0/
イベント発動時に、とあるキーを押す方法

きっかけは、event.initEventを使うと、エラーが出てしまったから。（調べたら、非推奨だし、対応していない？）

流れとしては、「イベント登録　→　キーが押される動作の設定　→ $(document).triggerで登録したイベントを発動」でした。勘違いしていたけど、keyCodeを入れると、そのイベント発動時に押したことになるらしい。<br>
JavaScriptで直で書こうとすると、なかなか出来なかったので、Jqueryの力を借りた。<br>以下のコードで、イベント呼び出し時に設定したキーが押されたことになる。

```javascript:
// 変数Key_eventをイベント登録する、keyupなのでキーが押されて上がった際に発動
  var key_event = $.Event('keyup'); 

// イベント発動時に「Fキーを押す」の登録
  key_event.keyCode = 70;
  key_event.which = 70; 

// イベントの発動
  $(document).trigger (key_event); 
```

$.Event('keyup').keyCode は、押されたボタンのキーコードを取得するもので、これをFのキーコードにすると、
イベント発動時にFキーを押したことになる。

$.Event('keyup').which というのは、キーボードまたはマウスでのイベント用で、押されたボタンに紐付けられた
キーコードを取得する。
http://js.studio-kingdom.com/jquery/events/event_which

あれ、which と keyCode は同じ意味なのかなと思って調べたら、開くブラウザで動きが違うらしい・・・。
Whichは、FireFox用。
https://stackoverflow.com/questions/4471582/keycode-vs-which
__proto__を取得したい

# 巷でよく見かける__（アンダーバーダングル）でprototype拾ってるあれ
##非正規な表現なのでちゃんと拾いたい

~~~javascript
    class Test {
        say (any) {
            console.log(any);
        }
    }

    new Test().__proto__ === new Test().constructor.prototype; //true
    new Test().__proto__ === Object.getPrototypeOf(new Test()); //true
~~~

参考までにどうぞ。
create-react-appで作成したアプリでCSSのローカルスコープを使う

## はじめに

弊社で運営しているWebサービスのスマートフォン用サイトでは、Reactを使ってフロントエンドを開発しています。

現在、Reactのコンポーネントの中で、CSSファイルをロードする方法と、style属性を直接書く方法とが混在していたため、両者の良いところを活かせる方法がないか探していました。


## create-react-appとは

Reactでアプリを開発するには、reactjsだけでなくwebpackなどのモジュールバンドラや、Babelなどのトランスパイラといった他のライブラリを合わせて使うことがよくあります。
create-react-appは、そういったよく使うライブラリを含めて1発でインストールしてくれる優れものです。


## CSSのスコープはグローバルになる

Reactではコンポーネントという単位でUIを部品ごとに作成し、コンポーネントを組み合わせてアプリを開発しますが、以下のようにスタイルシートを書くと、スタイルはコンポーネントとは関係なくグローバルに定義されてしまいます。

```css
/* style.css */
.hoge {
  color: red;
}
```

```js
// hoge.js
import React from 'react';
import Foga from './fuga.js';
import from './style.css';

class Hoge extends React.Component {
  render() {
    return (
      <div>
        <div class="hoge">
          これは赤色の文字になる
        </div>
        <Fuga />
      </div>
    );
  }
}
```

```js
// fuga.js
import React from 'react';

class Fuga extends React.Component {
  render() {
    return (
      <div class="hoge">
        これも赤色の文字になってしまう
      </div>
    );
  }
}
```

## CSSのスコープをコンポーネントに閉じ込めたい

以下のような感じで実装できます。

```css
/* style.css */
:local .hoge {
  color: red;
}
```

```js
// hoge.js
import React from 'react';
import Foga from './fuga.js';
import style from './style.css';

class Hoge extends React.Component {
  render() {
    return (
      <div>
        <div class={style.hoge}>
          これは赤色の文字になる
        </div>
        <Fuga />
      </div>
    );
  }
}
```

```js
// fuga.js
import React from 'react';

class Fuga extends React.Component {
  render() {
    return (
      <div class="hoge">
        これは赤色の文字にならない
      </div>
    );
  }
}
```

従来CSSのグローバルスコープの問題は、class属性の命名規則などで回避していました。
アプリケーションの規模が大きくなってくると、規則を維持することが大変になってきたり、規則自体が破綻してしまうこともあるのですが、Reactを使う場合はコンポーネント毎にスコープを絞れるので便利です。
javascript でオブジェクトをメソッドや継承まで含めてコピー

# javascript でオブジェクトをメソッドや継承まで含めてコピーしたい
##Object.assign({}, target)という書き方が巷に溢れてる
から、きちんとしたコピー方法を書きたい

~~~javascript
    Object.copy = function (o) {
        return Object.assign(Object.create(o.constructor.prototype), o);
    };
~~~

きちんとしたオブジェクトのコピーがしたいなら、スニペットとして活用してほしいです。
Python ノウハウ

# Macで動かす時
何もしなくてもsierra以降であれば、インストールされている。
$ python --version
Python 2.7.10

が、3にしたいので、以下を実行。
$ brew install python3
OKだったら下記になる
$ python3 -V
Python 3.6.5

# サンプルコード
・たぶんこれが一番わかりやすい。フレームワーク使ってないから。
https://coreblog.org/ats/stuff/minpy_web/


# これやる
https://qiita.com/summer4an/items/db0124eee8103c1d3b85


# LevelDB
https://qiita.com/tomotaka_ito/items/60c65dd5261fdfc6e71a


# 単語
・pip（"Pip Installs Packages" または "Pip Installs Python"）はPythonで書かれたパッケージソフトウェアをインストール・管理するためのパッケージ管理システムである。
pipはPython 2.7.9以降、Python 3.4以降からデフォルトで付属するようになった[2]。


#　　あとで見る
・初心者向け・Pythonの練習問題をたくさん解ける学習サイト7選
https://paiza.hatenablog.com/entry/2017/06/02/%E5%88%9D%E5%BF%83%E8%80%85%E5%90%91%E3%81%91%E3%83%BBPython%E3%81%AE%E7%B7%B4%E7%BF%92%E5%95%8F%E9%A1%8C%E3%82%92%E3%81%9F%E3%81%8F%E3%81%95%E3%82%93%E8%A7%A3%E3%81%91%E3%82%8B%E5%AD%A6%E7%BF%92%E3%82%B5
PhpStorm で Indexing がループして止まらないときの対処法

たまにですが PhpStorm で Indexing がループしてピコピコめんどくさい状態になる時があります。

アプリケーションを再起動しても、起動したら同じ状態が続くときは、以下のように [File] - [Invalidate Caches / Restart...] をメニューから実行してキャッシュを消去したら解決しました。

![](https://www.evernote.com/l/ABXDdO6lXQ1NsLmolSdYwOOpwh9_g82RaUoB/image.png)
グローバルIPアドレスを調べる（IPv4/IPv6）

# はじめに
自宅にIPv6が来るようになったので以前作ったグローバルIPアドレス取得ツール[gip](https://github.com/dalance/gip)をIPv6対応にしてみました。
その際に調査したIPアドレス取得サービスの一覧もまとめておきます。

# ツールの紹介

- リポジトリ: https://github.com/dalance/gip 
- 紹介記事: [グローバルIP取得ツールを作ってみた](https://qiita.com/dalance/items/8835ce9bb453b9cd8fe5)

最新版を[こちら](https://github.com/dalance/gip/releases)からダウンロードして以下のように使えます。

```console
$ gip -4
xxx.xxx.xxx.xxx
$ gip -6
xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
```

# IPアドレス取得サービス

実際にはもう少し見つけましたが、応答の遅いものや
IPv4/IPv6を明示的に指定できないものは外しています。

| Site         | URL                                  | Type | Format |
|:-------------|:-------------------------------------|:-----|:-------|
| [inet-ip.info](http://inet-ip.info) | http://inet-ip.info/ip               | v4   | plane  |
| [httpbin.org](https://httpbin.org)  | http://httpbin.org/ip                | v4   | json   |
| [ipify.org](https://www.ipify.org)  | http://api.ipify.org                 | v4   | plane  |
| [ipv6-test](http://ipv6-test.com)   | http://v4.ipv6-test.com/api/myip.php | v4   | plane  |
| [ipv6-test](http://ipv6-test.com)   | http://v6.ipv6-test.com/api/myip.php | v6   | plane  |
| [ident.me](http://api.ident.me)     | http://v4.ident.me                   | v4   | plane  |
| [ident.me](http://api.ident.me)     | http://v6.ident.me                   | v6   | plane  |
V8における円周率の実装

JSのMath.PIの真の値を調べた。

V8のGitHubミラーで、「math pi」などで検索し、それっぽいコードを拾ってきた。
https://github.com/v8/v8/blob/master/src/bootstrapper.cc#L2649

```c++:src/bootstrapper.cc
double const kPI = 3.1415926535897932;
// (中略)
InstallConstant(isolate, math, "PI", factory->NewNumber(kPI));
```
というように定義されていた。というわけで真の値は`3.1415926535897932`である。

確かにChrome DevToolのConsoleで`Math.PI * (10**16)`と打つと、`31415926535897932`となるが、`Math.PI * (10**17)`と打つと`314159265358979300`になるので、狂い始めるのは確実にこの頃である。

ちなみにSpiderMonkeyも調べたのだが、`M_PI`で実装されていたので、おそらく環境依存である。ビルドバッチを調べるのが面倒くさいのでやめた。
よく考えたら、なぜV8は`M_PI`じゃないのかとは思った。
あと`M_PI`の界隈はとても闇が深いことがわかった。なんか`math.h`や`cmath`には直接定義してはいけないらしく……
[C言語(標準)にM_PIは無い](http://qnighy.hatenablog.com/entry/2015/05/22/225558)

もうC++のコードは読みたくない。以上。
WEB APIのCSRF対策の例（ステートレスで）

# 対策例
* Token APIを作成する
* Token APIは、JWT（Json Web Token）で電子署名したJSONを返す。
    * JSON項目の例
      * userId:
      * expireDate: 24時間後など
* 更新APIを呼ぶ前（更新画面表示時など）に、Token API を呼んでJWTを取得する
* 更新APIをリクエストする際は、AutorizationヘッダにJWTを追加する（クッキーを使用すると対策にならないので注意）

# 参考
* [このWeb APIってCSRF対策出来てますか？って質問にこたえよう - Qiita](https://qiita.com/maruloop/items/e14d02299bd136f4b1fc)
* [JWT（JSON Web Token）でCSRF脆弱性を回避できるワケを調べてみた話 - Qiita](https://qiita.com/mejileben/items/ae7b346f0fc4a59101b5)
* [トークンを利用した認証・認可 API を実装するとき Authorization: Bearer ヘッダを使っていいのか調べた - Qiita](https://qiita.com/uasi/items/cfb60588daa18c2ec6f5)
10分で作れるBrainf*ck派生言語:シロ組さん専用のプログラミング言語「siro」を作ってみた

Brainf*ckの概要は[こちら](http://www.kmonos.net/alang/etc/brainfuck.php)参考にするとわかりやすいです。

#概要
- Rubyライブラリ[r-fxxk](https://github.com/masarakki/r-fxxk)を利用してBrainf*ck派生言語「Siro」を実装した
- 電脳少女YouTuberシロちゃんのチャンネル登録数40万人おめでとう

##Siro言語仕様

- シロちゃんの名言を命令にする。
- 命令以外の文字は無視する。

~~~
いーねっ！ ポインタを１進める
おほほい   ポインタの指す要素の値を１増やす
ｷｭｰｲ       ポインタを１戻す
ぱいーん   ポインタの指す要素の値を１減らす
白組さん   ポインタの指す要素の値が 0 だったら対応する次の "救済" までジャンプ
救済       対応する前の "白組さん" までジャンプ
なんて日だ！ ポインタの指す要素の値を外に出力
ズンドコズンドコ♪ 外から値を入力して、 ポインタの指す場所へ入れる
~~~
##r-fxxkで実装
最初は1から書こうと思っていたのですが、便利なライブラリを見つけたので、とても簡単に実装できました。
r-fxxkではBrainf*ckの各命令を設定するだけでインタプリタが実装できます。インタプリタであるsiro.rbのコードです。サンプルコードの命令部分を置き換えるだけです。

~~~
Encoding.default_external = "UTF-8"
require 'r-fxxk'

class Siro < Brainfuck
  nxt "いーねっ！"
  inc "おほほい"
  prv "ｷｭｰｲ"
  dec "ぱいーん"
  opn "白組さん"
  cls "救済"
  put "なんて日だ！"
  get "ズンドコズンドコ♪"
end

puts Siro.new.fuck(ARGF.read)
~~~

こちらがsiro言語でHelloWorldを表示するコードHelloWorld.siroです

~~~
いーねっ！おほほいおほほいおほほいおほほいおほほいおほほいおほほいおほほいおほほい白組さんｷｭｰｲおほほいおほほいおほほいおほほいおほほいおほほいおほほいおほほいいーねっ！ぱいーん救済ｷｭｰｲなんて日だ！いーねっ！おほほいおほほいおほほいおほほいおほほいおほほいおほほい白組さんｷｭｰｲおほほいおほほいおほほいおほほいいーねっ！ぱいーん救済ｷｭｰｲおほほいなんて日だ！おほほいおほほいおほほいおほほいおほほいおほほいおほほいなんて日だ！なんて日だ！おほほいおほほいおほほいなんて日だ！白組さんぱいーん救済いーねっ！おほほいおほほいおほほいおほほいおほほいおほほいおほほいおほほい白組さんｷｭｰｲおほほいおほほいおほほいおほほいいーねっ！ぱいーん救済ｷｭｰｲなんて日だ！いーねっ！おほほいおほほいおほほいおほほいおほほいおほほいおほほいおほほいおほほいおほほいおほほい白組さんｷｭｰｲおほほいおほほいおほほいおほほいおほほいいーねっ！ぱいーん救済ｷｭｰｲなんて日だ！いーねっ！おほほいおほほいおほほいおほほいおほほいおほほいおほほいおほほい白組さんｷｭｰｲおほほいおほほいおほほいいーねっ！ぱいーん救済ｷｭｰｲなんて日だ！おほほいおほほいおほほいなんて日だ！ぱいーんぱいーんぱいーんぱいーんぱいーんぱいーんなんて日だ！ぱいーんぱいーんぱいーんぱいーんぱいーんぱいーんぱいーんぱいーんなんて日だ！白組さんぱいーん救済いーねっ！おほほいおほほいおほほいおほほいおほほいおほほいおほほいおほほい白組さんｷｭｰｲおほほいおほほいおほほいおほほいいーねっ！ぱいーん救済ｷｭｰｲおほほいなんて日だ！白組さんぱいーん救済おほほいおほほいおほほいおほほいおほほいおほほいおほほいおほほいおほほいおほほいなんて日だ！
~~~

##実行してみる
~~~
>siro.rb HelloWorld.siro
Hello World!
~~~

ライブラリをインストールしてから10分程度で、Brainf*ck派生言語を実装することができました。派生言語作りたい放題ですね。

#ほかにも見つけたBrainf*ckライブラリ
[orenono](https://qiita.com/tbpgr/items/9d68fdb0d0e7bbccdd2c)
r-fxxkと同じくgemです

[php-fxxk](https://qiita.com/ryo511/items/54a503208e5ba13303e5)
phpで実装できます

#後記
- 今回は、シロちゃんチャンネル登録数40万人記念として作りたかったので、実装速度を優先しましたが、いつかちゃんと全部実装してみたいです。
- C言語をBrainF*ckに変換→siro言語化するツールを作ったら面白いかも。
Laravelアプリにアクセスしてきたユーザーのアクセス日時を記録する（全ページ共通の前処理）

# なにがしたい？

表題の通り、アクセスしてきたユーザーごとに「最終アクセス日時」というのを記録したい、という案件です。そう、「最終ログイン日時」とは違います。ログインした状態（クッキーにセッションが保存されている期間での再訪も含む）でトップページにアクセスしただけで記録したいんです。

できあがったものは、特にログイン日時の記録に限らず「すべてのページで共通の前処理」をすることを想定しています。

サンプルコードは Laravel 5.2 です。最新のものはちょっと異なるかもしれません。

# 結論

## 新しいミドルウェアの登場

専用のミドルウェアを追加しちゃいましょう。場所は```Authentificate```というミドルウェアがあるところでOK。内容もほとんどそれと同じです。

```php:/app/Http/Middleware/LoginCounter.php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Auth;
use Carbon\Carbon;

class LoginCounter
{
    public function handle($request, Closure $next, $guard = null)
    {
        if (Auth::guard($guard)->guest()) {
          // ログインしていないユーザーがアクセスしてきたときの処理

        } else {
          // ログインしているユーザーがアクセスしてきたときの処理
          $user     = Auth::user();
          $now      = Carbon::now();
          $prevtime = Carbon::parse( $user->last_logged_in_at );

          // 前回アクセスしてきたときから５分以上経過していたらタイムスタンプを更新
          if( $prevtime->diffInMinutes( $now, false ) >= 5 ){
            $user->last_logged_in_at = $now;
            $user->login_count++;
            $user->save();
          }
        }
        return $next($request);
    }
}
```

新しく作ったミドルウェアをねじ込みます。

```php:/Http/Karnel.php
<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    /* ... */

    /**
     * アプリケーションのルートミドルウェアグループ
     *
     * @var array
     */
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \App\Http\Middleware\LoginCounter::class, // <-- 追加
        ],

    /* ... */
```

## パフォーマンス 30ms程度

全ページで毎回やるので、毎回記録していたらリソースがもったいないので5分間隔にしています。その記録時以外で一番重いのは ```Auth:user()``` で、自分のローカル環境で30msくらい。それがない場合（未ログインユーザーの場合）は全体で5msくらいと、許容範囲かと思います。Carbonが重いのかも。

# 解説

## 代案と選ばなかった理由

他には、コントローラーに書く、ComposerServiceProviderに書く、AuthやUserモデルに書くといった方法も検討しました。

### コントローラ

新しく基底クラスを作るのが大変そうだったのと、そもそもその目的のためにミドルウェアがあるんじゃないかなぁと。

### ComposerServiceProvider

「全VIEWに共通の変数を用意する」という目的っぽかったので今回は避けました。

### AuthやUserに書く

それなりに筋が通っている気はしますが、ちょっと書くのが大変になりそうな予感。モデルはどちらかというとビジネスロジック＝内部処理を書くべきところで、今回はどちらかというと「ページ表示時のユーザー操作に対するリアクション」に近いのでコントローラ側に書くのがスマートじゃないかと思いました。

# 感想

実は結構どうしたものかと悩んでいたのですが、しばらく塩漬けにしていたら、すっと答えが降りてきました。もっといいやり方があったらコメントいただけると幸いです。

こうしてしまうと、逆に、「最終ログイン日時」を記録しようとするほうが、どこでやるのか探すのがめんどくさいような気がしてきました。