OmniAICreator/Qiita-1.07M huggingface dataset:
ある項目が同じレコードを一つのレコードとしてまとめる

# したいこと
MySQL5.6にて、以下のようなレコードを、

```
mysql> SELECT * FROM sample;
+------+--------+--------+
| id   | code01 | code02 |
+------+--------+--------+
|    1 | 101    | 11     |
|    1 | 102    | 12     |
|    2 | 201    | 21     |
|    2 | 202    | 22     |
+------+--------+--------+
4 rows in set (0.00 sec)
```

このような形にしたい

```
+------++------------+-----------------+
| id   | marge_code1 | marge_code2     |
+------+------------+------------------+
|    1 | 10111      | 10212            |
|    2 | 20121      | 20222            |
+------+------------+------------------+
```

# 第１ステップ
まずは、CONCAT関数を使用して、「code01」と「code02」を連結。
カラム「concat_code」として表示する。

```
mysql> SELECT
    ->   id,
    ->   CONCAT(code01, code02) AS concat_code
    -> FROM
    ->   sample;
+------+-------------+
| id   | concat_code |
+------+-------------+
|    1 | 10111       |
|    1 | 10212       |
|    2 | 20121       |
|    2 | 20222       |
+------+-------------+
4 rows in set (0.00 sec)
```

# 第２ステップ
次にGROUP_CONCAT関数を使用して、「concat_code」をカンマ区切りで連結。
カラム「group_concat_code」として表示する。
さらに「id」でグルーピングし、「id」ごとに「group_concat_code」を集約。

```
mysql> SELECT
    ->   A.id,
    ->   GROUP_CONCAT(concat_code) AS group_concat_code
    -> FROM (
    ->   SELECT
    ->     id,
    ->     CONCAT(code01, code02) AS concat_code
    ->   FROM
    ->     sample
    -> ) AS A
    -> GROUP BY A.id;
+------+-------------------+
| id   | group_concat_code |
+------+-------------------+
|    1 | 10212,10111       |
|    2 | 20121,20222       |
+------+-------------------+
2 rows in set (0.00 sec)
```

# 最終ステップ
あとはカンマ区切りの「group_concat_code」を別フィールド「marge_code1」「marge_code2」として分ける

```
mysql> SELECT
    ->   X.id,
    ->   SUBSTRING_INDEX(X.group_concat_code, ',', 1) AS marge_code1,
    ->   SUBSTRING(X.group_concat_code, INSTR(X.group_concat_code, ',') + 1) AS marge_code2
    -> FROM (
    ->   SELECT
    ->     A.id,
    ->     GROUP_CONCAT(concat_code) AS group_concat_code
    ->   FROM (
    ->     SELECT
    ->       id,
    ->       CONCAT(code01, code02) AS concat_code
    ->     FROM
    ->       test.sample
    ->   ) AS A
    ->   GROUP BY A.id
    -> ) X;
+------+------------+------------------+
| id   | marge_code1| marge_code2      |
+------+------------+------------------+
|    1 | 10111      | 10212            |
|    2 | 20121      | 20222            |
+------+------------+------------------+
2 rows in set (0.01 sec)
```

# まとめ
この方法がベストなのかは不明だが、とりあえずやりたい事は実現できた。。。
Docker上で動かしているPrometheusをnginxをつかってサブディレクトリで動かす

# 概要

PrometheusとはGo製のプル型の監視ツールである。複数の雑多なサービスをまとめているサーバ上でPrometheusをサブディレクトリで動かしたい、つまり、 https://exsample.com/prometheus/ という風にアクセスしたいということがあった。また、環境を汚したくないのでDocker上で動かしたい。しかし、よい日本語情報がなかったのでまとめておく。

# Prometheusをサブディレクトリで動かす

キーになる設定が"--web.external-url"と"--web.route-prefix"である。"--web.external-url"では"外側のURL"、つまりnginx側に設定するURLを設定する。"--web.route-prefix"にはprometheus側のprefixを設定設定する。
例えば下記のようにdocker-compose.ymlに設定する。

```
version: '2'
services:
  prometheus:
    image: prom/prometheus
    container_name: prometheus
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - ./data:/prometheus/data
    ports:
      - 3002:9090
    command: >
      --config.file=/etc/prometheus/prometheus.yml
      --storage.tsdb.path=/prometheus/data
      --web.console.libraries=/etc/prometheus/console_libraries
      --web.console.templates=/etc/prometheus/consoles
      --web.external-url http://localhost:9090/prometheus/
      --web.route-prefix=/
```

nginx側の設定は exsample.com/prometheus/ でアクセスしたい場合たとえば下記のように設定する。

```
    server_name  exsample.com;
    # 中略
    location /prometheus/ {
            proxy_pass http://localhost:3002/;
        }
```

これで "https://exsample.com/prometheus/" にきたアクセスを "http://localhost:3002/" に飛ばすということが正常に行えるようになる。

## 参考

- [Reliable Insights -External URLs and path prefixes-](https://www.robustperception.io/external-urls-and-path-prefixes)
【WEBエンジニアとASVS 肆（V3）】

[前回](https://qiita.com/scn7188/items/f87aa1b9a13dbb176bf7)の続きからです。

今回の記事を書くにあたっての経緯などです。
[ASVSとは](https://qiita.com/scn7188/items/e108b812efb869a2747d)
本記事で紹介している内容（各No）は自分で作った資料のNoをもとにしています。

##V3：セッション管理に関する検証要件
ウェブアプリケーションではほぼ必需品とも呼べる機能です。
だからこそちゃんとした使用方法を分かっておきたい。

###No.1 セッションマネージャーを独自実装していない，または独自実装のセッションマネージャーはあらゆる一般的セッション管理攻撃に耐えられる
セッションを独自実装することは珍しいかと思います。
素直にフレームワークの機構を使いましょう。

###No.2 ユーザがログアウトするとセッションが無効になる
ログアウト処理に以下の処理を加える

```php:
// セッション変数を全て解除する
$_SESSION = array();

// セッションを切断するにはセッションクッキーも削除する。
// Note: セッション情報だけでなくセッションを破壊する。
if (isset($_COOKIE[session_name()])) {
    // 有効期限に意図的に切れさすことによりクッキーを削除できる。
    setcookie(session_name(), '', time()-42000, '/');
}

// 最終的に、セッションを破壊する
session_destroy();
```

###No.3 一定期間非アクティブ状態が続くとセッションがタイムアウトする
無操作状態でセッションがタイムアウトしないとセッションの乗っ取り・重要情報の盗難に遭う危険性が高まります。

セッションのタイムアウトを設定する方法は以下を参照（PHPの場合）
php.iniで以下を設定

```php:
//有効期限の秒数を設定する
session.gc_maxlifetime = 18000//5時間の場合
```

ただし上記設定はアプリケーション全体の設定となるため、
個別で設定したい場合はプログラム上で以下を行う。


```php:
//セッションの保存場所を変更
ini_set( 'session.save_path', 'ディレクトリ(フルパス)' );
//有効期限を設定（5時間）
ini_set( 'session.gc_maxlifetime', 18000);
```

セッションの保存先を変更する理由は
> 注意: 異なる値を session.gc_maxlifetime に指定している 別々のスクリプトがセッションデータの保存場所を共有している場合、 一番小さい設定値に達した時点でデータが消去されます。このような場合には、 お互いに session.save_path を使用します。

[参考](http://php.net/manual/ja/session.configuration.php#ini.session.gc-maxlifetime)

###No.4 管理者が設定可能な上限時間を超えると，ユーザのアクティビティに関係なくセッションがタイムアウトになる(絶対タイムアウト機能)
レベル2の項目です。
管理画面では特に重要情報を扱うことが多いので、
操作状態関係なくセッションのタイムアウトを行うことが望ましいです。
ユーザビリティは多少は悪くなりますが、リスクを考えれば当然ともいえる対策だと思います。
また、望ましい時間は「30分～1時間」（個人的に）
操作毎に有効期限を延長させないようにしてください。

###No.5 認証を必要とするすべてのページに，見やすくて分かりやすいログアウト機能がある
No.3~4の設定しておけば時間経過でログアウトされますが、
自発的にログアウトできないとユーザー側に不信感を与えてしまいます。
共通的なヘッダーやフッター、サイドメニューに設置するのがベストです。

###No.6 セッションIDがURLやエラーメッセージ，ログを通じて漏洩しない．またセッションクッキーによるURL書換えをサポートしない
セッションIDは画面やログに表示するものではありません。
セッションハイジャックの危険性が高まります。
PHPでデフォルトの設定でセッションIDをクッキーにする設定となっていますが、
以下の設定項目が該当の項目となります。

```php:
//URLにセッションIDを付加しない(デフォルト：0)。
session.use_trans_sid = 0
 
//セッションIDの保存にcookieを使用する(デフォルト：1)。
session.use_cookies = 1
 
//セッションIDの保存にcookieのみを使用することを指定(デフォルト：1)。
session.use_only_cookies = 1

//HTMLの自動書き換え機能（デフォルト：a=href,area=href,frame=src,input=src,form=）
url_rewriter.tags = ''
```

HTMLの自動書き換え機能はブラウザの設定によりクッキーが無効となっている場合の代替機能ですが、
HTML上にセッションIDが表示されるため無効としています。
詳しくは[output_add_rewrite_var()](http://php.net/manual/ja/function.output-add-rewrite-var.php)を参照

###No.7 認証と再認証の成功時に必ず新たなセッションとセッションIDが生成される
ログイン時にセッションIDの再生成を行う。

```php:
session_regenerate_id(true);
```

ただ、一つ注意点があります。
「session_regenerate_id」ですが、短い間隔で連続で呼ばれると「セッションが切れる」事象が発生します。
原因は諸説ありますが、セッションIDの再生成中に再度生成処理が加わることにより、
うまくセッション情報が引き渡されないのが原因だとか。

なので、以下の点に気を付けて実装を行うこと。
・JavaScriptなどで連続クリックの対応
・リダイレクトが入る処理はリダイレクト後に再生成を行う


V3の後半は次回とします！
  ▼▽▼▽▼▽▼▽▼▽▼▽▼▽▼▽▼▽▼▽▼▽
  [ASVS 3.0.1まとめ - Google スプレッドシート](https://docs.google.com/spreadsheets/d/1wGC9sF2gZoHnGKJt2mIJrb_Cr0bqETl9r07s_YQFWK8/edit?usp=sharing)
  ▲△▲△▲△▲△▲△▲△▲△▲△▲△▲△▲△
【初心者】中心極限定理

#中心極限定理は「標本の平均値の分布」に注目したもの！
混乱しやすいが重要な点は、中心極限定理とは、標本の個々のデータについてのものではなく、**たくさんの標本データのそれぞれの「標本平均」をかき集めた「標本平均の分布」**についてのものであるということ！
そこからさらに、**「「標本平均の分布」の平均、分散(標準偏差)」**について考える。

<img width="683" alt="IMG_0691.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/331975/4f09e0a3-a2c4-4282-531e-6206e1ab9d6e.jpeg">

中心極限定理とは以下のようなことである。


**(1)「「標本平均$\bar{x}$の分布」の平均」は「母集団の平均(μ)」と一致する
(2)「「標本平均$\bar{x}$の分布」の分散」=　$\frac{σ^2}{n}$（σ：母集団の標準偏差）
(3) 母集団がどのような分布でも、サンプル数ｎが大きくなるにつれ「標本平均$\bar{x}$の分布」は正規分布に近づく**

あるデータの分布を知りたいとき、「平均」と、それを中心にどれだけずれがあるかの「標準偏差」が分かれば、分布の特徴がつかめる。
（１）より標本平均**$\bar{x}$**の分布の平均がわかる。
（２）より、標本平均**$\bar{x}$**の分布の標準偏差はわからなくても、母集団の標準偏差(σ)が分かっていれば、**$\frac{σ^2}{n}$**で代用できることがわかる。分母に標本数ｎがあるので、標本が大きくなるほど分散が小さくなり、母集団の分布に近づいていくことがわかる。
<img width="614" alt="IMG_0692.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/331975/10a76693-f625-8879-8d94-aeb29d79e407.jpeg">
無能プログラマはプログラマを続けてはいけないのか。

#なぜ有能SEは無能プログラマをいじめるのか。

まず詳細設計書を新たに起こしたり修正をする際のケースでよくあるいじめをご紹介します。
設計書を起こす、修正する場合、ミーティングなどでざっくりした資料を渡されたり、ざっくりした内容を口頭で伝えられて、その情報をもとに設計書を修正するわけですから、
当然SEと同等の業務知識が無ければ、そこに指し示してある言葉の意味すらわからないと思います。
指し示す情報でわからない部分が少ない場合、その場で「この箇所はこういう認識ですが、よろしいですか。」等すぐ確認できますが、そもそも業務知識がついてなく、言ってることの大半が何を言ってるのかさっぱりわからない場合、多くのプログラマは
「とりあえずやってみます。わからなかったら都度聞くので教えてください。」
とその場をしのぐと思います。
無能プログラマはそこで３つの作戦を考えます。
###①とりあえずここで言いたいのはこうだろうと断定して、設計書を提出する。
やっつけ仕事というやつですね。もちろん頓珍漢な内容だと跳ね返されます。
ただ中には天使のようなSEも居ます。その人は何行目がどう間違ってたか、どう修正してほしいか、具体的に答えを書いてくれます。
もちろんそうじゃないSEもいます。大半のSEは、答えを教えてくれず、「なぜこう思ったのか」問答してきます。その質問に答えたとしても、こういう質問をしてくる場合はたいていプログラマが間違った認識を持っているのを正すためです。次の問答が始まります。「じゃあこういうデータはありえるの？」「あり得ると思いますがないのですか？」「なぜないと思うのですか？」
のように問答が続きます。このようなやり取りを1ヶ月ほど繰り返すと大抵のプログラマは壊れて辞めてしまいます。嫌いなプログラマが他社の人間の場合、こういうグレーないじめで退場させるのはもはやSIerの常套句ではないでしょうか。私は過去に３回これで辞めています。
なぜ有能SEがこのようなことをするかというと、プログラマに自身と同等の知識を身につけてほしくてあえて厳しくしている人もいれば、相手が困っている姿を見るのが報酬となっていじめている場合もあります。どちらにせよ心理的負荷が高ければやめて次に行くのが懸命でしょう。どうせお荷物になるなら次の現場でもお荷物になってあげましょう。
###②調べて都度聞く作戦に出る
一番誠意がある仕事の対応ですね。できないなりにやろうとする努力がSEに伝わると思います。
人間というのは勘定と感情の生き物です。情抜きには語れません。ただし注意点が必要です。
中にはあなたの仕事ぶりを責めて、あなたを良いように使おうとするSEが出てきます。
「お前が仕事遅いせいでリリースまで間に合わない。どうやって遅れ取り戻すつもりだ？」
こんなこと言われたら残業や休日出勤しろと言わんばかりですよね。
多くのSEは賢いので、ギリギリパワハラにならないラインを責めてきます。
もしその現場で長くやりたいなら適応すべきでしょうが、そうじゃないなら次の現場に逃げてしまいましょう。
###③業務知識がわからないから設計は無理！と投げ出す
これも１つの手です。ただこういう姿勢が続くとやる気がないと感じられて契約を切られてしまう恐れがあります。自社にもクレームが来て自宅待機が増えれば当然解雇もありえます。
しかし安心してください。我が国には失業保険や生活保護という立派なセーフティネットがあります。
生活に困窮したら迷わず申請しましょう。おわり
CentOS 7 で MariaDB 10.4 をビルド

CentOS 7 上でソースコードから MariaDB Server 10.4 をビルドする手順をまとめます。

# 依存パッケージのインストール

以下のドキュメントに記載されている，

https://mariadb.com/kb/en/library/source-building-mariadb-on-centos/#installing-build-dependencies

RPM パッケージをインストールします。

```
yum -y install git curl \
      gcc \
      gcc-c++ \
      bison \
      libxml2-devel \
      libevent-devel \
      ncurses-devel \
      rpm-build \
      cmake
```

# GitHub レポジトリの 10.4 ブランチから clone 

ソースを GitHub レポジトリから clone し，

```
git clone --branch 10.4 https://github.com/MariaDB/server.git
```

以下の公式 Knowledge Base に書かれている，

https://mariadb.com/kb/en/library/Build_Environment_Setup_for_Linux/

以下のコマンドを実行します。

```
yum -y install yum-utils
yum-builddep -y mariadb-server
```

# MariaDB Server 10.4 をビルド

ビルド用のディレクトリを作成し，cmake します。

```
mkdir build-10.4
cd build-10.4
cmake ../server
```

4CPUコアを利用可能な場合，-j オプションでコア数を指定しますと並列コンパイルできます。

```
make -j4
```

debug フラグをたててビルドした場合，--versionオプション実行時の出力，file コマンドを実行した際の出力は以下のようになります。

```
# file sql/mysqld
sql/mysqld: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), 
 dynamically linked (uses shared libs), for GNU/Linux 2.6.32, 
 BuildID[sha1]=bce0b6f1a652954191233da97b0a43ebb9731cc9, not stripped
# ./sql/mysqld --version
sql/mysqld  Ver 10.4.2-MariaDB-debug for Linux on x86_64 (Source distribution)
```
C++ Builder XE4, 10.2 Tokyo > Bug? > TStreamMemory > WriteCopmponent() > TShape->Brush->Color = clWhiteの時だけ、色情報をコピーできない > clWhiteがデフォルトColorであるため

```txt:動作環境
C++ Builder XE4
Rad Studio 10.2 Tokyo
```

### 前回

- [C++ Builder XE4 > TControl > プロパティのコピー > Shape1からShape2へプロパティをコピーする](https://qiita.com/7of9/items/ddc84da9762234773bff)


### 不可解な動作

上記の実装を使っていたが、不可解な動作となる

- コピー元のTShapeがBrush->Color = clWhiteの時、色情報がコピーできない

### 実装

```Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
	// Shape1は白に、他は任意の色
	Shape1->Brush->Color = clWhite;
	Shape2->Brush->Color = clAqua;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	copyProperties((TControl *)Shape1, (TControl *)Shape2);

	// 重なっているため
	Shape2->Left = Shape1->Left + 150;
}

void __fastcall TForm1::copyProperties(TControl *srcCtrl, TControl *dstCtrl)
{
	// 元の名前を保持
	String orgName_src = srcCtrl->Name;
	String orgName_dst = dstCtrl->Name;

	// プロパティコピー
	TMemoryStream *strm = new TMemoryStream;
	Shape1->Name = L"";  // to avoid source collision
	try {
		strm->WriteComponent(srcCtrl);
		strm->Position = 0;
		strm->ReadComponent(dstCtrl);
	}
	__finally
	{
		delete strm;
	}

	srcCtrl->Name = orgName_src;
	dstCtrl->Name = orgName_dst;
}
```

### 動作例

ソフト起動直後
![2018-12-26_19h35_33.png](https://qiita-image-store.s3.amazonaws.com/0/32870/4710a381-4e64-cf59-941e-3eeb709775ca.png)

Button1押下後
![2018-12-26_19h35_48.png](https://qiita-image-store.s3.amazonaws.com/0/32870/ecf688b8-9900-601b-798b-102d8e9acf63.png)

サイズに関するプロパティはコピーできたが、Brush->Color(=clWhite)はコピーできていない。

IDEのバグのようだ。

Shape1のBrush->ColorがclWhite以外の時はColorもコピーされる。

### 対処

以下のように、Colorをコピーしなおす処理が必要だろう。

```cpp
	copyProperties((TControl *)Shape1, (TControl *)Shape2);
	Shape2->Brush->Color = Shape1->Brush->Color;
```


10.2 Tokyoでも同じ実装を確認したところ、再現した。



### StackOverflow

StackOverflowにて質問をしている。

- [C++ Builder XE4, 10.2 Tokyo > TStreamWriter > clWhite cannot be copied](https://stackoverflow.com/questions/53931205/c-builder-xe4-10-2-tokyo-tstreamwriter-clwhite-cannot-be-copied)

~~回答が付いたらここにも記載する予定。~~

2018-12-28 
回答をいただいた。

https://stackoverflow.com/questions/53931205/c-builder-xe4-10-2-tokyo-tstreamwriter-clwhite-cannot-be-copied/53952403#53952403

clWhiteがdefaultカラーであるための挙動であるとのこと。
RTTIによるコピー方法のコード例も合わせて教えていただいた。

I appreciate it, Remy Lebeau.
WINでDDを叩きたかっただけなのにorz

#はじめに
USBフラッシュにubuntuをインストールしたほうが絶対幸せになれるよ。あとDD for winとか...

#DD for Win
USB接続にすればHDDやSSDもWindows10で認識します。
ただ、一度ファイルを作り、そのあとに書き込みをする方法なので、HDD容量が数Tibのものを行う際には保存先のHDDを用意しなくてはならないのが欠点です。

#だったら仮想環境をつくればいいじゃない！
となるとVmware worksstation Playerですよね。
色々と試した結果、USBフラッシュは認識するものの、外付けHDDは全く認識しなかったのでVirtual Boxにしました。

#Virtual Boxをインストールしたら
VirtualBox 6.0.0 Oracle VM VirtualBox Extension Packを公式サイトからダウンロードしましょう
https://www.virtualbox.org/wiki/Downloads
警告が出ますが公式のやつなので問題ないです。

#インストールとubuntuのインストール
が終わったことを前提に話を進めます。

外付けHDDをubuntu側で認識させるためUSBの項目を画像の通りにします。
なお、USB3.0を選択する場合カーネルのバージョンによっては認識しませんのでご注意ください。今回使用するubuntuは18.04です。![無題2.png](https://qiita-image-store.s3.amazonaws.com/0/293379/bac28de4-10e2-70dd-5638-aed0cef6bdab.png)

#DDを叩く！
が、速度が頑張っても5Mib/sしか出ない...遅い!!!!!!!!!!!!!!!!!!
環境はX250です。
#USBフラッシュから起動したら
40Mib/sでました...やっぱり素直のこっち使うべきですね。。
同じ環境でこうも違うとは...

#結論
素直にUSBフラッシュにインストールしたubuntuからやりましょう()
【GrowthPush】【Android】FCM対応したのにPush通知が受信できない

## はじめに
いよいよGCMの終了も近くなり、GCMを使ったPush通知アプリを開発している皆さまは対応に追われている頃でしょう。
各種ライブラリもFCM移行の対応が必要になってきます。
GrowthPushを使ったAndroidアプリを担当しており、FCM移行で詰まった箇所があったので備忘録として残しておきます。

## GrowthPushのFCM対応
Android版の公式ドキュメントは以下になります。
https://faq.growthbeat.com/article/226-gcmtofcm
基本的には書いてある通りにやっていけば大丈夫！
と思っていましたが、そんなことはありませんでした。

## Push通知が受信できない
私がハマったのは以下の２点です

### ①新規作成したFirebaseプロジェクトのサーバキーをGrowthbeatの管理画面で登録したら、まだFCM対応していないアプリでPush通知が受信できなくなった

GrowthPushはアプリ側がFCM対応をしておらず、サーバ側がFCM対応済み、といった状況でもPush通知を受信することができます。
もしサーバキーの更新後にPush通知が来なかったら、**管理画面で登録したサーバキーと、アプリで設定しているSenderIDの紐付けを疑ってください。**

アプリ側のFCM対応によって、デバイストークン登録メソッドである
```GrowthPush.getInstance().requestRegistrationId(String senderId)```
の引数が消え、ここでのSenderIdは不要になります。
代わりにアプリにインポートしたgoogle-services.jsonにproject_numberとして同一の数値が記載されているのです。

**FCM対応前に使用していた上記メソッドでSenderIdと、FCM対応後にgoogle-services.jsonに記載されているproject_numberは同一のものでなければなりません。**

つまり、google-services.jsonに記載されているproject_numberが以前使用していたSenderIdと違う値だった場合、GrowthPushの管理画面で登録したサーバキーとSenderIdが紐づいておらず、Push通知が受信できない、ということになります。

SenderIdの数値がFCM対応前と対応後で変わってしまう、などという状況があるのでしょうか。
####ありました。

GCMをGoogleCloudPlatformのプロジェクトで利用しており、Firebaseプロジェクトがまだ存在しない場合、Firebaseプロジェクトを新規作成する必要があります。
Firebaseプロジェクトを新規作成する際、それまでGCMを利用していたGoogleCloudPlatformの既存プロジェクトを引き継ぐことができるのですが、それをしなかった場合
**つまり、Firebaseプロジェクトを完全新規で作成した場合はSenderID（FirebaseConsole内では送信者ID）も新規で発行され、当然ですがGCMで利用していたプロジェクトとは全く紐づいていない状況になります。**

実際にこの状況になっており、FCM対応をしていないアプリでPush受信ができなくなる、という事象にはまっておりました。

#### ※GCMをすでに利用しており、FCM対応でFirebaseプロジェクトを新規作成する場合は必ず既存プロジェクトを引き継ぎましょう

### ②デバイストークンが登録されず、Push通知が受信できない

こっちが本題になります。こちらはアプリ側にFCM対応を行なった後の話です。

**公式ドキュメント通りに対応したはずなのにデバイストークンが登録できてない！**

ってことが実際にあり悩みました。

そんな時にググりまくってたどり着いたのが以下の答えです。

```apply plugin: 'com.google.gms.google-services'```

これをapp/build.gradleの一番下に追加してあげてください。
私の場合はこれで全て解消されました。
公式ドキュメントには書いてなかったので、これ、相当悩みました。

以上対応で無事にFCM対応前アプリ/対応後アプリの両方でGrowthPushによるPush通知が受信できるようになりました。

めでたしめでたし
TouchDesigner 映像音響処理概論 2018 各回の内容リスト


## 背景
TouchDesignerを習得していく中で、常に開いている[@satoruhiag](https://qiita.com/satoruhiga)さんの講義情報。あまりにも参照しすぎて、作業中に必要になった情報は第＊回だな、と脳内インデックス化が進んできたので書いてみました。

**もちろん、基本的には一次情報である下記のサイトをご参照ください**

http://station.backspace.tokyo/satoruhiga/TDWS_2018/


## 映像音響処理概論 2018 各回の内容リスト

- [第二十回 2018.12.11](http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/day20/) : window制御・UI
- [第十九回 2018.11.27](http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/day19/) : Arduino・Firmata・ESP8266
- [第十八回 2018.11.21](http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/day18/) : GLSL MATについて
- [第十七回 2018.11.14](http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/day17/) : GLSL TOPについて
- [第十六回 2018.10.23](http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/day16/) : パーティクル + ジオメトリインスタンス 2
- [第十五回 2018.10.15](http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/day15/) : パーティクル + ジオメトリインスタンス
- [第十四回 2018.10.10](http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/day14/) : DAT, op参照, table, python
- [第十三回 2018.10.02](http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/day13/) : Timelineについて
- [夏休み 2018.07.20](http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/summer-holiday/) : VJ作例のソース
- [第十二回 2018.07.11](http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/day12/) : VJ作例の紹介
- [第十一回 2018.07.03](http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/day11/) : ブレンドモード・ノイズ・displacement_shader・Locked to Timeline・Animation COMP
- [第十回 2018.06.27](http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/day10/) : ジオメトリインスタンス・GLSL MAT
- [第九回 2018.06.19](http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/day9/) : OSC
- [第八回 2018.06.13](http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/day8/) : オペレータータイプの変換
- [第七回 2018.06.06](http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/day7/) : よく使うSOP紹介
- [第六回 2018.05.30](http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/day6/) : SOPのレンダリング・カメラ・ライト・マテリアル・render
- [第五回 2018.05.23](http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/day5/) : SOP基礎・Geometry Viewer・プリミティブ
- [第四回 2018.05.16](http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/day4/) : DAT基礎・python・op参照
- [第三回 2018.05.09](http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/day3/) : パラメータのリンク・リファレンス・TOP基礎・音の解析
- [第二回 2018.04.25](http://station.backspace.tokyo/satoruhiga/TDWS_2018/post/day2/) : CHOP基礎


**もちろん、基本的には一次情報である下記のサイトをご参照ください**
http://station.backspace.tokyo/satoruhiga/TDWS_2018/
SPSS Modeler 18.2のJSONノード

SPSS Modeler18.2でJSONのファイルの読み書きができるようになったので試してみました。

JSON ソース・ノード
https://www.ibm.com/support/knowledgecenter/ja/SS3RA7_18.2.0/modeler_mainhelp_client_ddita/clementine/jsonimportnode.html

JSON エクスポート・ノード
https://www.ibm.com/support/knowledgecenter/ja/SS3RA7_18.2.0/modeler_mainhelp_client_ddita/clementine/jsonexportnode.html

#1 サンプルデータ
以下のようなデータでテストしました。

```
[
    {
      "_id": "53ea1d4734e8189d0385473b",
      "年齢": 26,
      "名前": "山田太郎",
      "likes": [
        "cats",
        "sleeping"
      ],
      "friends": [
        {
          "id": 0,
          "name": "Lane Castaneda"
        },
        {
          "id": 1,
          "name": "Cline Mccoy"
        }
      ]
    },
    {
      "_id": "53ea19146bc5d2192ef92733",
      "名前": "鈴木次郎",
      "isActive": false,
      "weight": 61.345,
      "likes": [
        "dogs",
        "jogging",
        "music"
      ],
      "friends": [
        {
          "id": 0,
          "name": "Claire Phelps"
        }  
      ]
    }
  ]

```
狙いは以下です。

* 日本語の値が読めるか
* 日本語の列名が読めるか
* キー値がそろっていない場合にどうなるか（年齢というキー値は山田さんにしかありません）
* ネストしたデータがどうなるか（マニュアルにあるようにネストしていると読めないということですが、どうなるかも含めてテストしました。）

#2 インポート

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223763/25f620a5-bb12-df69-755e-d4bfa8e49912.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223763/3d5147b1-adac-f3b7-3bb5-623098b8d1c1.png)

結果

* 日本語の値が読めた
* 日本語の列名が読めた
* 列項目がそろっていない場合には列が存在しないレコード分は$null$となった
* ネストしたデータは文字列ではいった
* ファイルのエンコードをUTF-8にしないと「データ モデルを取得できません: json ファイルを解析できませんでした。詳細: Invalid octet in UTF-8 sequence when decoding 'string'。」のエラーになった

#3 エクスポート

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223763/547b341e-3411-c62e-164d-b3eb9a228d09.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/223763/d25154a9-46c9-aac5-a5c2-e7145cf94ab1.png)


結果

* 日本語の値はUnicodeエスケープシーケンスで出力された
* 日本語の列名もUnicodeエスケープシーケンスで出力された
* $null$の値もキー値が出力された
* ネストしたデータはダブルクォートで囲まれ文字列としてはいった
* オブジェクトの区切りなどでも改行は入らなかった。
JavaScriptで画面遷移してハッシュ値を取得する方法

#やりたいこと

aタグを使用せずに、クリックした際に特定の値をひもづけた状態で画面遷移し、その値を取得したい。

#結論

以下の方法で、画面遷移、値の受け渡しが実現可能。

##1. 値をひもづけて画面遷移

```js
const input = 'sample value'
location.assign(`/output.html#${input}`)
```

##2. 値の取得

```js
const output = decodeURI(location.hash.substring(1))
```

#やったこと

ボタンをクリックした際に、``input.html``から``output.html``へ画面遷移し、``input.html``内のinputタグに入力した値を遷移先の``output.html``で表示する。


##htmlを用意
それぞれのファイルはこんな感じ

```html:input.html

<body>
    <h1>input.html</h1>
    <input type=text id="input">
    <button id="link">to output page</button>
    
    <script src="input.js"></script>
</body>
```
*aタグを使用せずにclickイベントで画面遷移させたいのでbuttonタグを用意

```html:output.html
<body>
    <h1>output.html</h1>
    <h2>Output >>> <span id="output"></span></h2>

    <script src="output.js"></script>
</body>
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/329068/3b07bcd3-5a05-c507-358a-ab538c0e5c6e.png)


Output >>>　の部分にinputタグで入力した値を出力できたらOK

##JavaScript実装

###input.js

input.htmlで読み込む用のinput.jsを作成。

やることは、
  1. buttonのクリックイベントで
  2. inputの値を取得して
  3. 値を渡して画面遷移


```js:input.js

document.querySelector('#link').addEventListener('click', (e) => { // 1. buttonのクリックイベントで
    const input = document.querySelector('#input').value           //2. inputの値を取得して
    location.assign(`/output.html#${input}`)                         //3. 値を渡して画面遷移
})
```

####画面遷移

今回の肝でもある画面遷移は、

```js
location.assign(/* 遷移先 */)  
```
とすれば実現できる。

[MDNのドキュメント](https://developer.mozilla.org/ja/docs/Web/API/Location)によると、

>Location インターフェイスは、関連付けられたオブジェクトの場所 (URL) を表します。 Location に対して変更が行われると、関連するオブジェクトに反映されます。 Document インターフェイスおよび Window インターフェイスにはこのような関連付けられた Location があり、それぞれ Document.location および Window.location でアクセスできます。

とのことで、urlに関連した操作が可能。


####値の受け渡し

今回はハッシュ値を利用することで値の受け渡しを行いたいので、遷移先のパスに``#受け渡す値``を付け足す。下の場合、変数``input``の値を受け渡している。

```js
location.assign(`/output.html#${input}`)  
```


###output.js

output.htmlで読み込むようのoutput.jsを作成。

やることは
1.ハッシュ値を取得
2.デコードして、
3.spanタグに表示


```js:output.js
const hashValue = location.hash.substring(1)            //1.ハッシュ値を取得
const output = decodeURI(hashValue)                     //2.デコードして、
document.querySelector('#output').textContent = output  //3.spanタグに表示
```

####ハッシュ値の取得

urlに付随するハッシュ値は、``location.hash``で取得することができる。しかし、``location.hash``の値は#も含まれてしまうので#を取り除く必要がある。subtring(1)で先頭を取り除いた状態でハッシュ値を取得する


```js 
// 「http://127.0.0.1:8080/output.html#hash-value」　の時、
console.log(location.hash) 
// #hash-value
console.log(location.hash.substring(1)) 
// hash-value
```

####デコード

urlのハッシュ値では、空白や日本語などはエンコードされるので、値を取得したら表示する前にデコードする。

```js
// 「http://127.0.0.1:8080/output.html#こんにち」 の時

const hashValue = location.hash.substring(1)

console.log(hashValue)
//%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF
console.log(decodeURI(hashValue))
//こんにちは
```

デコードは、

```js
decodeURI(encodedURI)
```

で実現可能。

#完成

これで完成。

inputタグに値を入力しボタンを押すと、画面遷移して入力内容が出力される。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/329068/9506f6e1-0a0d-dc13-d988-3475e7a6df75.png)

#まとめ

urlを操作したいなら``location``インターフェイスを使えばOK
GitHubのWebでコンフリクトを直す方法

#環境
Windows10
#コンフリクトの状態
コンフリクトを起こすとPull requestsの各ブランチの画面に以下のような表示が出る
<img width="500" alt="キャプチャ.JPG" src="https://qiita-image-store.s3.amazonaws.com/0/329556/03c2eed9-c934-5bad-b4c2-c2db7568ba4a.jpeg">

# 解決法
GitHubのWeb上で直します。
1.コンフリクト表示画面右上の[Resolve conflicts]を押す.
2. `<<<<<<<`と`>>>>>>>`で囲まれたコンフリクト部分を手動で修正する．
3.修正画面右上の[Mark as resoved]を押す.
4.[Commit changes]を押す.
![fd64b010-c06b-11e6-9dd3-a827e299c5bf.gif](https://qiita-image-store.s3.amazonaws.com/0/329556/0468b5e8-5996-9344-7c3e-5bf4652ba057.gif)
参考：https://blog.github.com/2016-12-12-resolve-simple-merge-conflicts-on-github/
Conversationに表示されているcommit一覧に`Merge branch 'master' into [コンフリクトしていたブランチ名]`が表示されてたらOKです。
#こんな時は
GitHubのWebではコンフリクトが解決しているけど、コマンドプロンプト上では治っていない。
Conversationに表示されているcommit一覧に`Merge branch 'master' into [コンフリクトしていたブランチ名]　Verified　[コミットID]`があるのでコマンドプロンプト上で`git reset --hard　[コミットID]`を入力してコンフリクトを直したところに移動します。
※このときエディタを起動していたら全部閉じておく(管理者権限で移動できないエラーが発生することがあるので)

一応`git log`と`git status`で状態を確認して作業に戻ります。
ビカビカ光るウォッカと叩くと光る焼酎を5分で作る


用意すると治安を悪くすることができる光る酒です。光る他に、飲めるという特徴があります。クリスマス会用に適当に作ってみたら、簡単にできてパーティー感でてよかった。元ネタはギャル電。

#もの

##カラフルに光るキンミヤ 25°

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">光るキンミヤは色が変わるようにしてみた、光るだけですが <a href="https://t.co/qGwYmhI7Fv">pic.twitter.com/qGwYmhI7Fv</a></p>&mdash; むらさきMFTaipei c23 (@interestor) <a href="https://twitter.com/interestor/status/1076512995277041666?ref_src=twsrc%5Etfw">2018年12月22日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


##叩くと光るウヰルキンソン・ウオッカ 40°   

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">５分でできる光るウォッカ、明日のクリスマス会用のおもちゃ <a href="https://t.co/5OnuxCwdzI">pic.twitter.com/5OnuxCwdzI</a></p>&mdash; むらさきMFTaipei c23 (@interestor) <a href="https://twitter.com/interestor/status/1076500731690024960?ref_src=twsrc%5Etfw">2018年12月22日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


#作成

##叩くと光る酒を作る（所要時間5分）

押すと光るだけですが、音楽に合わせて叩いてカスタネットみたいに使うと楽しい（バカなので）。

### 用意するもの
- 中身の入った酒瓶
    - 透明・透明に近い液体が入っていないと光がうまく散乱しないよ
- littlebits
  - 電源
　 - 電池の場合は電池、microUSBの場合はモバイルバッテリーをつないだもの
  - ボタン
  - ワイヤー
  - LED

###組み立て
- 1.littlebitsを下記のようにつなぐ
    - 電源→ワイヤー→ボタン→LED
    - 磁石が付いてるから向きは間違えようがない
- 2. 1を酒瓶にマスキングテープでぐるぐる貼って止める
    - LEDが中身に向くようにね！
    - 底につけるのが一番きれいに光るが、そこは酒瓶の形と相談で 　
- 3.テスト
    - ボタンを押したら光るはず


##色んな色に光る酒を作る（所要時間5分）

いろんな色に光る。素敵な照明ですね。

### 用意するもの
- 中身の入った酒瓶
- Arduino
- Neopixel
- ジャンパピン3本
- （ブレッドボード）
- パソコン
- モバイルバッテリー

###組み立て
- 1. ArduinoとNeopixelをジャンパピンでつなぐ
    - 5Vと5V
    - GNDとGND 
    - 2(DIGITAL)とDO
- 2. 下のコードを書き込む　
- 3. Arduinoの電源をモバイルバッテリーから取る
- 4. 作ったやつを酒瓶にマスキングテープでぐるぐる貼って止める

####コード
Lチカ的にランダムに色が変わりながらピカピカする。光り方とか変えるともっとかっこよくなる。

``` blink.ino

//ライブラリをインクルード
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>// Arduinoの省電力化
#endif

#define PIN            2   //Arduinoで使うピン
#define NUMPIXELS      1   //LEDの数。

//ライブラリのセットアップ
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

void setup() {
     pixels.begin(); // ライブラリ使用開始
}

//全て光らせる
void loop() {
     //i番目のLEDのRGBを指定
     for(int i=0;i<=15;i++){
       int R=random(255);
       int G=random(255);
       int B=random(255);
       pixels.setPixelColor(i,pixels.Color(R,G,B));      
     }
      pixels.show();
      delay(500);



//全て消す(pixels.clear();がうまく使えないので)
     for(int i=0;i<=15;i++){
       pixels.setPixelColor(i,pixels.Color(0,0,0));      
     }
    pixels.show();

      delay(10);

}
```
Bitnami Redmine 3.4 から 4.0 へデータを移行してみました

引き続き[Bitnami版のRedmine](https://bitnami.com/stack/redmine)の話題。
4.0.0にバージョンアップする際の、データの移行手順や注意点をまとめてみました。
なお、作業はLinux（Ubuntu）で行っています。

## 移行手順

### Bitnami Redmine 4.0.0-0 のインストール

まずはダウンロードした`bitnami-redmine-4.0.0-0-linux-x64-installer.run`を実行してインストールしましょう。
インストール先は`/opt/redmine-4.0.0-0`とします。

### データベースのバックアップ

インストールが完了したら、すぐにデータベースをバックアップしておきましょう。失敗した時にインストール直後の状態に戻すためです。
「パスワード」の部分はインストール時に指定したパスワードで。

```
/opt/redmine-4.0.0-0/mysql/bin/mysqldump --single-transaction -u root -pパスワード bitnami_redmine > /home/me/bitnami_redmine_4_default.dump
```

### 旧Redmineのデータベースをダンプ

移行データをダンプして保存します。その際、`-t`オプションを付け、`DROP TABLE`や`CREATE TABLE`を行わないようにします。ファイル名は`bitnami_redmine.dump`とします。

```
/opt/redmine-3.4.x-x/mysql/bin/mysqldump --single-transaction -u root -pパスワード -t bitnami_redmine > /home/me/bitnami_redmine.dump
```

### 初期データの削除

Bitnami Redmineをインストールすると、トラッカーやステータスなどの初期データが自動作成されるのですが、インポート時にIDが重複してしまうので、一旦すべて削除します。
下記の8テーブルを空っぽにするSQLを作成します。

```truncate.sql
TRUNCATE TABLE `email_addresses`;
TRUNCATE TABLE `enumerations`;
TRUNCATE TABLE `issue_statuses`;
TRUNCATE TABLE `roles`;
TRUNCATE TABLE `schema_migrations`;
TRUNCATE TABLE `trackers`;
TRUNCATE TABLE `users`;
TRUNCATE TABLE `workflows`;
```

で、4.0側のBitnami ConsoleでこのSQLを実行します。

```
mysql -u root -pパスワード bitnami_redmine < /home/me/truncate.sql
```

### データ移行

お待ちかね、旧Redmineのデータをインポート……と言いたいところですが、このままだと不都合が出ます。
4.0では、多数の日付型フィールドで型が`datetime`から`timestamp`に変更されており、かつ`timestamp`型は日付が**UTC**として保存されるため、結果的にすべての時刻が**9時間ずれます**。
詳しくはこちらの記事を。参考になりました。

[MySQLのDATETIME型とTIMESTAMP型のタイムゾーン的な違いの話+O/Rマッパーのタイムゾーンの挙動の話](https://qiita.com/ryokkkke/items/a007d5edd4d8e7484c56)

で、どうすりゃいいかというと、先ほどダンプした移行データの頭の方に下記の一文を追記します。

```
SET SESSION TIME_ZONE = '+09:00';
```

これで、JSTの時刻をUTCに変換してインポートしてくれます。もちろん、RedmineではJSTで表示されますよ。
では、今度こそインポート。ちなみに`-f`オプションを付けると、途中でエラーが発生しても処理を継続します。

```
mysql -u root -pパスワード -f bitnami_redmine < /home/me/bitnami_redmine.dump
```

なお、移行データの中に、プラグインが作成したテーブルのデータがある場合、「そのテーブルが存在しないよ」というエラーメッセージが出ます。
先にプラグインをインストールしてテーブルを作成しておくか、プラグイン用のデータは別途移行するか、その辺はお好みで。

## 注意点

以上でデータ移行は完了ですが、気付いた点がいくつか。

* 私の環境では、なぜか「ウェルカムメッセージ」が移行できませんでした。しょうがないので旧環境からコピペします。

他にも見つかったら追記します。
Excel から Redmine へごにょごにょ

この記事は [Okinawa.rb Advent Calendar 2018](https://qiita.com/advent-calendar/2018/okinawarb) の21日目の記事です。

最近は Laravel づくしで、Rails が恋しい今日この頃、みなさんいかがお過ごしでしょうか？
去年までフリーのプログラマやってましたが、息切れしてリーマン落ちした私です。


# Excel から Redmine へ一括チケット登録

ruby から .xlsx 読んで Redmine へ REST 使って登録します。

多分他にも便利なの色々ありそうですが、、あえて書かせてもらいます。
なぜなら他にネタもないのでっ！

ということで...

__確認したバージョン__

> redmine: 3.4.3
> ruby: 2.4.4
> Excel: .xlsx が使えるバージョン


__事前準備__

+ Redmine の REST API を有効化しといてください

+ REST 利用するユーザーのAPIアクセスキーを控えておく

ソース公開しますので、よしなにやってください。
多分動くはず。（エラー処理とかほとんどやってませんが...）
https://github.com/tokanao/xlsx2redmine


__補足__

+ 一応新規作成時にチケットid取得して、xlsx 更新しているので、更新にも対応しています

+ 実行前に xls ファイル閉じてください

+ issue シートは start_date, due_date 入れると、行の対応する日付に稼働時間（8.0）が入るので簡易 WBS としても使えます

+ tracker_id, assigned_to, status_id などの id は自分で一覧取得で確認してください
 
__参考__
https://{your Redmine domain}/projects.xml?key={REST API Key}
https://{your Redmine domain}/trackers.xml?key={REST API Key}
https://{your Redmine domain}/issues.xml?key={REST API Key}
https://{your Redmine domain}/issue_statuses.xml?key={REST API Key}


## 解説

もう解説とかも手抜きです。
手を抜くことは大切です。人生休み休み歩んでいきましょう。

+ メイン処理です、シート読みながら対応するテーブルを投げてます。なので、シート名は Redmine のテーブル名と一致させる必要があります
https://github.com/tokanao/xlsx2redmine/blob/master/run.rb#L220-L230

+ 関連チケット情報とカスタム項目の情報収集
https://github.com/tokanao/xlsx2redmine/blob/master/run.rb#L33

+ 送信用 xml 作成
https://github.com/tokanao/xlsx2redmine/blob/master/run.rb#L81

+ Redmine へリクエスト送信
https://github.com/tokanao/xlsx2redmine/blob/master/run.rb#L125

## そしていきなりまとめ

え？VBAから直接やれよって？
...だってその当時 ruby 使いたかったんだもんっ！（←ココかわいい感じで）
webpackで、React/JSXをビルドする際、es2015でエラー

## 環境 :fallen_leaf: 
仮想環境のOS：Ubuntu
webpack 4.19.1


## エラー内容 :fallen_leaf: 

```
ERROR in ./src/main.js
Module build failed (from ./node_modules/babel-loader/lib/index.js):
Error: Plugin/Preset files are not allowed to export objects, only functions. In /home/vagrant/React_study/React入門/Reactのツールで自動ビルド/hello/node_modules/babel-preset-es2015/lib/index.js
    at createDescriptor (/home/vagrant/React_study/React入門/Reactのツールで自動ビルド/hello/node_modules/@babel/core/lib/config/config-descriptors.js:178:11)

```

## エラーが出てしまうファイル:cry: 
エラーが出るwebpack設定ファイルです

```
module.exports = {
  entry: './src/main.js',
  output: {
    filename: './src/out/bundle.js'
  },
  module: {
    rules: [
      {
        test: /.js$/,
        loader: 'babel-loader',
        options: {
          presets:['es2015', 'react']
        }
      }
    ]
  }
};
```

test:ではjsファイルを指定。optionsでは、babel-loaderのオプションとしてes2015とreactを指定しReact/JSX変換を行う。

しかし、エラーが出てしまう。es2015古いんかなぁ、、、


## 解決方法 :smile: :
調べてみると、足りないパッケージをインストールする必要があるようだ。

```
npm i @babel/preset-env
```
インストールが始まった。
そして、上の方に書いたwebpackの設定ファイルを修正した。
['es2015','react']から、['@babel/env', '@babel/react']に修正した

```
module.exports = {
  entry: './src/main.js',
  output: {
    filename: './src/out/bundle.js'
  },
  module: {
    rules: [
      {
        test: /.js$/,
        loader: 'babel-loader',
        options: {
          presets:['@babel/env', '@babel/react'] //['es2015','react']から変更
        }
      }
    ]
  }
};

```

## 結果 :smile: :
無事に、一つのファイルとして生成されたファイルが生成された
DDのディスククローンと進捗と



#PVインストール方法
```$ sudo apt install pv
(ubuntuの場合)
$ sudo yum install pv
(centOSの場合) 
```

#クローンをするときのコマンド
```DD_command
sudo dd if=/dev/sdb bs=4k | pv -s 1024m -p -t -e -r -a -b | sudo dd of=dev/sdc bs=4k conv=noerror,sync

```

ifのソースディスクとofの書き込み先ディスク、はそれぞれの環境で変更してください。
1024mについては、書き込みする量になりますので、これも適当な値に変更してください。あくまで例として1Gibにしただけです。

実行時の状態
![Screenshot from 2018-12-26 18-29-22.png](https://qiita-image-store.s3.amazonaws.com/0/293379/75fee85f-b385-9617-76e6-6d7573666235.png)
キャプチャー画像で申し訳ありませんが、一番下の行になります。
左から、書き込みをした容量、経過時間、現在の書き込み速度、平均書き込み速度、-sで指定したサイズの進捗(プログレスバー) 割合　推定残り時間です。

#参考にさせていただいた記事
[進捗どうですか? - 時間のかかる処理の進捗を確認](https://qiita.com/_sobataro/items/07f39be531a6dd70a6c7)
https://wonderwall.hatenablog.com/entry/2017/08/03/072500
dockerでjupyter notebookが動く環境を付け加える作業

# 目的
dockerで時々する作業を文字起こししてみる。
めぼしいImageをpullしてきたあと、どうやっていじろうかなと考えているときはこんな流れで作業します。

# 実行するコマンド
### コンテナ作成
```
docker run -it --name MYCONTAINER -p 8001:8000 -v /Users:/home IMAGE bash
```

- 作成するコンテナを「MYCONTAINER」と命名。
- コンテナの8000番ポートをローカルの8001番ポートにポートフォーワード
- コンテナの/homeとローカルの/Usersを共有
- 「IMAGE」という名前のイメージをベースにする
- bashを実行。

### コンテナから抜けたあと再度起動し、bashで入る
```
docker start MYCONTAINER
docker exec -it MYCONTAINER bash
```

### コンテナからjupyter notebookを実行する
```
(自分の使いたいpythonバージョンをセットアップしてから）
pip install jupyter
jupyter notebook --port 8000 --ip=0.0.0.0 --allow-root
```
- OSError: [Errno 99] Cannot assign requested address
- こんなエラーが出てきたので、--ipと--allow-rootをつけた

あとは、表示されたアドレスとトークンを、ローカルでブラウザにコピペする
API Gateway で Cookie（リクエスト＆レスポンス）ver.201812

宮崎在住エンジニアのジョウ(@JotarO_Oyanagi) です。

API Gateway のエンドポイントで　Cookie をやり取りする時どう設定するの？
という問題に小一時間消費したので、方法を共有します。

# リクエストで Cookie を使う

エンドポイントにトークンとして Cookie を使うケースなどの設定です。

1. 作成されたメソッドの **メソッドリクエスト** 、こちらの **HTTP リクエストヘッダー** に `Cookie` を設定します。
![スクリーンショット 2018-12-26 18.07.45.png](https://qiita-image-store.s3.amazonaws.com/0/217369/a1a86a3f-6450-275a-80cb-dbb97801ebc3.png)

2. 続いて **統合リクエスト** の **HTTP ヘッダー** に `Cookie` 、その *マッピング元* に 
 `method.request.header.Cookie` を設定します。
![スクリーンショット 2018-12-26 18.10.08.png](https://qiita-image-store.s3.amazonaws.com/0/217369/ab9574ec-11a3-b934-9f28-9eb420a5b903.png)

以上です。

# レスポンスで Cookie を返す

認証用 API で Cookie を返すケースなどの設定です。

1. 作成されたメソッドの **メソッドレスポンス** 、こちらの **200 のレスポンスヘッダー** に `Set-Cookie` を設定します。
![スクリーンショット 2018-12-26 18.12.22.png](https://qiita-image-store.s3.amazonaws.com/0/217369/dde13485-a840-dffc-ba35-9b4322881725.png)

2. 続いて **統合レスポンス** の 200 の **ヘッダーのマッピング** に `Set-Cookie` 、その *マッピングの値* に `integration.response.header.Set-Cookie` を設定します。
![スクリーンショット 2018-12-26 18.12.51.png](https://qiita-image-store.s3.amazonaws.com/0/217369/60fa3aa3-2c08-cae9-1fc7-23494b0f1ea6.png)

以上です。

# 終わりに

今更ながらにネットワークの勉強が足りないことを実感した小一時間でした。
NGUIのPanelにSpineをクリップしてみた

アプリで、NGUIを使っていて、困った話です。以外に、悩んだのでメモも兼ねて投稿します。

### 当時の状況
アプリのUIには、NGUIを使っていました。
また、演出には、Spineが使われており、UnityのRuntimeで再生させています。
2Dの演出やエフェクトにはSpineが使われているところが多く、NGUIのインスタンスにAddComponentして再生している箇所もあります。

### 起きた問題
NGUIでViewを重ねた時に、後ろで再生されているSpineのエフェクトが、前面にあるViewに隠れず表示されてしまっていました。具体的には、UIScrollViewに、UIGridでアイテムを並べてあって、そのアイテムの子供にSpineのComponentがあり、再生された時にNGUIのクリップが効かず、スクロールで本来隠れて見えない範囲のSpineの演出が表示されてしまっている状況でした。

### 原因
NGUIは、子供のオブジェクトをクリップして、描画を行っていますが、SpineのRuntimeでは行っていません。その為、Spineにクリップする処理を足します。

### 行った対応
今回は、シェーダーにクリップ領域を渡して、フラグメントシェーダーでクリップしています。

### 実際に書いたコード
UIPanelには、localCorners と worldCorners というメンバを持っています。
下の画像は、dumpしてみたログになります。画像から、どんな情報が入っているかは、想像が付くかと思います。
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/153021/660507ca-6493-435a-c401-35d8219163b8.png)


今回は、Panelの頂点座標が、world座標系に変換されている worldCorners をそのまま使用する事ができました。
シェーダーに要素を渡しているコードです。

```
// MeshRendererは、MaterialにSetVectorする
meshRenderer = gameObject.GetComponent<MeshRenderer>();
// UIPanel は、GetComponentInParentしなくても、クリップする領域のpanelのインスタンスであれば、OK
worldCorners = gameObject.GetComponentInParent<UIPanel>().worldCorners;
mat = meshRenderer.material;

// _ClipArea
// x : UIPanel のxのworld座標系の左上のx座標
// y : UIPanel のyのworld座標系の左上のy座標
// z : UIPanel のxのworld座標系の右下のx座標
// w : UIPanel のyのworld座標系の右下のy座標
mat.SetVector("_ClipArea", new Vector4(worldCorners[0].x, worldCorners[0].y, worldCorners[2].x, worldCorners[2].y));
```

今回は、Skeleton-Fog.shaderを修正しています。

頂点シェーダーの内容です。
worldPosには、World座標に変換したvertexを入れています。2DのUV座標系になっている為、必要なのは、xとyの値になります。

```
Skeleton-Fog.shader
------------------------------------------------
struct v2f {
    float4 vertex : SV_POSITION;
    float4 color : COLOR;
    float2 texcoord : TEXCOORD0;
    float2 worldPos : TEXCOORD1;
};

v2f vert(appdata_t v)
{
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.color = v.color;
    o.texcoord = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
    // クリップ領域をWorld座標に変換
    o.worldPos = mul(unity_ObjectToWorld, v.vertex).xy;
    return o;
}
```
フラグメントシェーダーの内容です。
worldPosには、World座標に変換されたvertexが入っています。
また、_ClipAreaには、クリップ領域の情報が入っているはずなので、以下のような情報をセットしてありますので、xの座標の判定は、xとzでチェックし、yの座標の判定は、yとwでチェックしています。


```
Skeleton-Fog.shader
------------------------------------------------
fixed4 frag(v2f i) : COLOR
{
    float inArea = (step(_ClipArea.x, i.worldPos.x) *
                    step(i.worldPos.x, _ClipArea.z) *
                    step(_ClipArea.y, i.worldPos.y) *
                    step(i.worldPos.y, _ClipArea.w));
    // クリップ領域に入っていなければ、inAreaが 0.0 になる為、色が出ない。
    return inArea * i.color * tex2D(_MainTex, i.texcoord);
}
```

以上となります。
AmazonLinux+Route53でLetsEncryptのDNS-01認証する

## DNS-01とは
LetsEncryptから発行されるワンタイムトークンをDNSのTXTレコードに設定する認証方式。
IP制限などでHTTP-01での認証ができない場合に有効。

## Route53を使ったDNS-01を行う環境が入ったDockerイメージ
Certbotの`dns_route53`プラグインでRoute53を使ったDNS-01認証ができるが、CertbotはAmazonLinuxに対応していないのでDockerを使う。

- DockerHub: https://hub.docker.com/r/certbot/dns-route53/
- certbot-dns-route53のドキュメント: https://certbot-dns-route53.readthedocs.io/en/stable/

## 手順

### 1. Route53のレコードを編集するIAMポリシーを作成

```
{
    "Version": "2012-10-17",
    "Id": "certbot-dns-route53 sample policy",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "route53:ListHostedZones",
                "route53:GetChange"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect" : "Allow",
            "Action" : [
                "route53:ChangeResourceRecordSets"
            ],
            "Resource" : [
                "arn:aws:route53:::hostedzone/YOURHOSTEDZONEID"
            ]
        }
    ]
}
```

- `YOURHOSTEDZONEID` は ドメインの Hosted Zone ID をコピー

[![Image from Gyazo](https://i.gyazo.com/3666bd08760538b5a83484f0ad981901.png)](https://gyazo.com/3666bd08760538b5a83484f0ad981901)
### 2. 作成したポリシーを証明書を作成するEC2のロールにセット
省略

### 3. 証明書を作成するEC2で以下を実行

```bash
# 事前にDockerをインストールしておく
yum install docker
service docker start
chkconfig docker on
```

```bash
docker run  -v "/etc/letsencrypt:/etc/letsencrypt" certbot/dns-route53 certonly -n --agree-tos --email [LetsEncryptアカウントメールアドレス] --dns-route53 -d [ドメイン名]
```

- `/etc/letsencrypt/live/[ドメイン名]` ディレクトリに秘密鍵(privkey1.pem)と証明書(cert1.pem)がインストールされる
バウンススクロールを制御する方法

#バウンススクロールを打ち消したい

アプリ風のウェブサイトを作る際にバウンススクロールの制御で手間取ったのでメモ

##採用した方法
position:fixedを使ってバウンススクロールしていないように見せかける方法を採用。

##問題点
実際にバウンススクロールを起こすと数秒間フリーズし要素に触れなくなるというiOSのバグにぶつかった。
フリーズ中に更にスクロールを行うと追加で数秒間フリーズされる。

##解決方法
スクロール位置を検知し上下にスクロールが行われたらスクロール位置を0に矯正するjsと追加。

```
$(window).on('touchmove', (e) => {
  let moveY = $(window).scrollTop();
  if(moveY !== 0){
    $(window).scrollTop(0);
  }
});
```

###まとめ
これでひとまず動いたので一旦これで。
プログラマの本での勉強がコスパ最悪な件を解決したい。 @yumainaura  #アウトプット #書籍 #kindle #比較  @yumainaura

# 記事を書いたきっかけ

Rubyist3年目にして初心者向けの本を読みたいと思っているが、躊躇している。

[サンプルコードでわかる！Ruby 2.6の主な新機能と変更点 - Qiita](https://qiita.com/jnchito/items/ce11cb7fccdf4b66af24)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/5d29646b-7004-c55f-2a36-6cb70b56b194.png)

これも読み直したい

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/352e309d-9378-586a-1977-bf843fb4bc12.png)


# 書籍の良さ

- 内容が精選されており、出版社の編集が入っており、コンテンツは本のほうが優れている
- 以上。

# 紙の本を読んで学習するのは意外と難しい

- プログラミングとの親和性の低さ、相性の悪さという根本的な問題がある
- そもそも「紙のページを開いたまま、PCも開いてプログラミングする」という行為が難易度高すぎ
- いろいろと試行錯誤しても、根本的な親和性の低さは解消しづらそう

# Kindle、電子書籍での学習は？

- せっかく電子書籍なのに「コピペ回数制限」「コピペしたら変なスペースが入る」という地球絶滅レベルの仕様のせいで、UIは最悪
- こういった著作権的な問題のせいで、アウトプット学習には全く使えないと言って過言じゃない状況
- ページめくりも遅いし、紙の本のUIの爆速さもなく、非常に残念な感じ

# じゃあどうすれば良いの？考えてみる

- なんとか「書籍のコンテンツの良さ」と「Webのアウトプット学習の相性の良さ」を組み合わせたい
- せっかくコンテンツが優れていても「アウトプットしながら勉強」じゃないと学習効率がガタ落ちする、リーディングだけの勉強のコスパの悪さがやばい

# 回答例 - 音声アウトプット

- 本を読みながら自分の発見、トークを録音or動画撮影して、Youtubeなどにアウトプットする
- 紙の本を目で読むことと、自分の声で喋ること、視覚と聴覚はバッティングしないので素晴らしい

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/11e9a024-cb13-a02f-b6d8-bbbe1389ce63.png)

# 他の回答例

- 読書会を開く、本の内容を人とわきあいあいと雑談するなどして「楽しい音声アウトプット」の道を探す
- KindleからせめてHTMLに落とし込める何らかのツール類を探す(AmazonWebでKindleのハイライトから無制限コピペできるやつが前あったたのだが、既に対策されてしまった様子)
- 著作権という時代遅れのシステムが世界から絶滅するのを待つ









<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
GMail APIでメール送信（Java）

# はじめに
Javaで [GMail API](https://developers.google.com/gmail/api/guides/?hl=ja) を叩いてメール送信するところを軽く試してみましたのでまとめます。

なお本例ではメールアカウント所有者に成り代わってメール送信するため、
送信前に [OAuth認証](https://developers.google.com/identity/protocols/OAuth2?hl=ja) でアカウント所有者から許可を得る必要があります。

※ アカウント所有者に認証させる代わりにサービスアカウントを使用するパターンは [こちら](https://qiita.com/tnagao3000/items/3d210582bc7f1ca218cc) で。

# 概要

### 必要なもの

- GCPプロジェクト
- Gmailアカウント
- [サンプルソース](https://github.com/tnagao3000/sending-mail-using-gmail-api)

### 環境の作成手順

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26808/e1520d52-649b-f288-c451-6b3a5a4f6117.png)

### サンプルソースの処理フロー

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26808/1e8b1fb9-2579-5099-b9c1-b6dc480b20c4.png)

# 何はともあれ動かしてみたい
そんな感じで試してみます。

### 実行環境を作成する

##### (a-1) GCPにプロジェクト作成
[GCP](https://cloud.google.com/) で適当にプロジェクトを用意します。

##### (a-2) APIを有効にする

該当プロジェクトで **APIとサービス** で **Gmail API** を探して有効にします。
次の通り。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/26808/e1170fd7-b369-ca2d-5b8a-1cf8e5b69908.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26808/1f20fb41-a91b-a412-8070-e43f1d70156f.png)

##### (a-3) ソース準備
[GitHubから取得](https://github.com/tnagao3000/sending-mail-using-gmail-api) して [送信先メアド](https://github.com/tnagao3000/sending-mail-using-gmail-api/blob/bd372df8848bb857c8d128eea39c3a9b59731f9b/src/main/java/com/example/SendingMailUsingGmailApi.java#L60) を適当に修正してください。
送信元メアドは認証画面で許可した人のものが使われます。

なお公式ガイドは次の場所にあり、今回のサンプルはほぼこちらから（以下略）

- [認証まわり](https://developers.google.com/gmail/api/quickstart/java)
- [メール送信まわり](https://developers.google.com/gmail/api/guides/sending)

##### (a-4) プロジェクトのOAuth2.0クライアントID取得
まず適当にOAuth同意画面を作ります。
名前だけあればいいようです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/26808/9e4accca-fd2a-d622-64e9-bf5fc6b865bb.png)
次にOAuthクライアントIDを作成してjsonファイルでダウンロードします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/26808/784b6e07-3252-f81a-2f91-f2d563e6a1b5.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26808/bdc5c675-b339-6373-d731-12d05e6877b0.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26808/268a4666-e957-989d-3af7-81878bb42da9.png)

以上です。
あとはIDEを使うなりjarにするなりで実行できます。

### 実行してみると・・

初回実行時には次のような認証画面が表示されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26808/ad256723-df9d-d5f7-7df8-240c41a7fd64.png)

上記画面で許可をクリックするとメールが送信されます。

このとき合わせてローカルにアクセストークンとリフレッシュ
トークンの保存も行われます。

再実行時は上記トークンが使用されるため認証画面は出ません。

# 注意点など

### OAuth認証で許可された操作について
本例では [メール送信のスコープのみ](https://github.com/tnagao3000/sending-mail-using-gmail-api/blob/bd372df8848bb857c8d128eea39c3a9b59731f9b/src/main/java/com/example/SendingMailUsingGmailApi.java#L36) をリクエストしています。
他の操作も行いたい場合は [適切なスコープ](https://developers.google.com/gmail/api/auth/scopes) をリクエストする必要があります。

### リフレッシュトークンの期限切れ

今回は軽く試すだけなので気にしていませんが、本番ではアカウント所有者による 
[いくつかの操作](https://developers.google.com/identity/protocols/OAuth2?hl=ja#expiration) によってトークンが期限切れになる点も考慮する必要があります。


以上です。
Python×seleniumでChromeの画面サイズを最大化するmaximize_window()

#はじめに

PythonでChromeを操作する際、デフォルトだと画面サイズが小さいです。
一行加えてあげることで、簡単に画面サイズを最大化できます。

#環境

- MacOS High Sierra 10.13.4
- Python 3.7.1
- chromedriver 2.45


#準備
- chromedriverを[こちら](http://chromedriver.chromium.org/downloads)からダウンロード
- Pythonファイルと**chromedriver**は、同じフォルダ内に置きます。

#Pythonスクリプト

```python:test.py
def start_chrome():
    #chromedriverのPATHを指定
    driver_path = ".\chromedriver"

    #Windowsは以下
    #driver_path = r".\chromedriver.exe"
    
    driver = webdriver.Chrome(executable_path=driver_path)
    driver.maximize_window()

    return driver

start_chrome()
```

#実行
それぞれの環境でPythonファイルを実行してください。

（例）
**Mac** ターミナル or ATOMのターミナルから実行。
**Windows** IDLE or コマンドスクリプトから実行。

#結果

Chromeが起動し、画面が最大化されればOKです。

#参考

Seleniumクイックリファレンス
[【Python】maximize_window・・・ウィンドウを最大化する](http://www.seleniumqref.com/api/python/window_set/Python_maximize_window.html)

#著者のプログラミングスキル

今の時代、独学でもプログラミングはできる！ということをモットーにしてます。

- 10年のブランクを経て、2018年9月からPython独学スタート。
- Pythonを使った個人開発（スクレイピング・クロール系）がメイン。
- PHP, GAS, Amazon MWSAPI, Webフレームワーク、サーバー周りも勉強中。
- C言語での業務経験3年。（ただし2008年頃と大昔w）
C++hristmasってどう発音するかStackOverflowで聞いたときの反応

# きっかけ

<blockquote class="twitter-tweet" data-lang="ja"><p lang="en" dir="ltr">I wish you a merry C++hristmas!</p>&mdash; Meeting C++ (@meetingcpp) <a href="https://twitter.com/meetingcpp/status/1077526290574598144?ref_src=twsrc%5Etfw">2018年12月25日</a></blockquote>

こんなツイートがあった。いや、C++hristmasってどう発音するのさ・・・。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">まって、どう発音したらいいんだ <a href="https://t.co/i3IkKM6CLx">https://t.co/i3IkKM6CLx</a></p>&mdash; yumetodo-鳥の氷河から逃げる (@yumetodo) <a href="https://twitter.com/yumetodo/status/1077744819139563520?ref_src=twsrc%5Etfw">December 26, 2018</a></blockquote> 

# StackOverflowで聞いてみた。

>Mis-directed Christmas spirit.

訳: 誤ったクリスマスの精神

>Ah **** no, don't sully the best time of the year with that C++ crap. 

訳: おいっ、C++とかいうゴミでこの一年で最高の時間を汚すんじゃねぇ！

>Could it beeeee SATAN?

訳: そそそそれって悪魔より恐ろしいのっ？

>SATAN plus plus

訳: 悪魔++

>Oh no! That is where SATAN resides!!!

訳: なんてこった、ここが悪魔のいるところだったのねっ!!!

皆さんノリノリである。

~~のりのり過ぎて~~規約違反で質問はめでたく削除されました。

![c++ - How should I pronounce C++hristmas - Stack Overflow 2018-12-26.png](https://qiita-image-store.s3.amazonaws.com/0/94177/bc4ad711-4589-584e-1ddd-925f8b8d19ad.png)

https://stackoverflow.com/questions/53927662/how-should-i-pronounce-christmas
(アクセスできない)

# 肝心の発音

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">I wish you a merry Cplusplushristmas! <a href="https://t.co/roATvXkDHF">https://t.co/roATvXkDHF</a></p>&mdash; Destiny Gaia (@destiny_gaia) <a href="https://twitter.com/destiny_gaia/status/1077794355958575104?ref_src=twsrc%5Etfw">December 26, 2018</a></blockquote>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">しーぷらすぷらしゅりすます（早口で3回）</p>&mdash; 白山風露@kazatsuyu@qiitadon.com (@kazatsuyu) <a href="https://twitter.com/kazatsuyu/status/1077794414875992070?ref_src=twsrc%5Etfw">December 26, 2018</a></blockquote>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">しーぷらすぷらすしゅりすます</p>&mdash; Destiny Gaia (@destiny_gaia) <a href="https://twitter.com/destiny_gaia/status/1077794700021526528?ref_src=twsrc%5Etfw">December 26, 2018</a></blockquote>

StackOverflowでは

>[Bernard](https://stackoverflow.com/users/61/bernard)
>See Plus Plus Wristmas

>[Ruks](https://stackoverflow.com/users/8423261/ruks)
>*/ˈsiːˌplʌsˈplʌs rɪsməs/* (See plus plus rismas)...

という意見が寄せられました。

# 15歳

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">I unearthed a 15year-old C++hristmas message :3<a href="https://t.co/ee8rRtxxdq">https://t.co/ee8rRtxxdq</a></p>&mdash; 黒翼猫|ω･)｡o(や、やばた2000) (@BlackWingCat) <a href="https://twitter.com/BlackWingCat/status/1077806615351287808?ref_src=twsrc%5Etfw">December 26, 2018</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

[UserFriendly Strip Comments](http://ars.userfriendly.org/cartoons/read.cgi?id=20031212&tid=972606)