OmniAICreator/Qiita-1.07M huggingface dataset:
個人開発のWebサービスをレンタルサーバーからGCP（Google Cloud Platform）に乗り換えた話

個人開発でWebサービスを運営しています。
長らく月額500円のレンタルサーバーでなんとかやっていましたが、下記の理由でサーバーを移行することを考えました。

・ミドルウェアなど自由にインストールできない
・スケールアップできない
・アクセスログがリアルタイムで見れない
・TLS1.0/1.1の廃止スケジュールなどレンタルサーバー側で決められる
・DKIMを設定してメールの到達率を上げたい

AWSも触ってみましたが、業務でBigQueryに慣れ親しんでいたので、Google Cloud Platformを使うことにしました。

普段はWebアプリケーションの開発がメインなので、インフラは軽く触る程度ですが勉強がてら構築してみます。

# 構成
ロードバランサ （Cloud Load Balancing) 1台
本番Web・DBサーバー (Compute Engine、CentOS) 1台
メンテ用Webサーバー (Compute Engine、CentOS) 1台
![network.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278715/0bf9f8ee-9d84-1009-b6d2-cd702458ec46.png)
ロードバランサの後ろに本番Web・DBサーバーと、メンテ用Webサーバーのインスタンスをおきます。

# ロードバランサを使う理由
あまり大きくないサイトでもロードバランサを使う理由を書きます。

### グローバルIP1つで運用できる
レンタルサーバーから移行するときのDNS設定は、AレコードをロードバランサのIPに変更するだけ済みます。

### 直IPなどの不正なリクエストを除外したい
サーバーを公開すれば、直IPなどで不正なリクエストが来るようになります。.gitディレクトリへのアクセス、脆弱性ファイルのスキャンなど、そのようなアクセスは本番Webサーバーにリクエストが来ないようにします。

### Webサーバーの複数台構成などスケールできる
DBはCloud SQLなどを使って独立させて、本番Webサーバーを複数台構成にするなどスケールアップが可能です。

### ロードバランサにSSL証明書を設定できる
ロードバランサがSSL終端となり、ロードバランサから後ろのWebサーバーはHTTPのアクセスとなります。WebサーバーでSSLを復号化するより負荷は少ないかと思っています。また、Webサーバーを複数台にしたときに証明書をロードバランサに集中することができます。

### ロードバランサの振り分けのみでメンテ中にできる
例えば本番Webサーバーのインスタンスを停止させて性能を上げたいときに、ロードバランサの振り分けをメンテ用サーバーに向ければ簡単にメンテ中にできます。

# メールサーバー
Compute Engineのインスタンスから直接メールの送信はできないので、WebAPIで使える外部のサービスを使うことにしました。

# 運用について

### SSL証明書の更新
SSL証明書はLet's Encryptを使っています。Webサーバーでcertbot certonlyコマンドで作成したものを、ロードバランサの設定画面に貼り付けます。3ヶ月に一度やる必要があるのでちょっと面倒です。

### スナップショット
定期的にインスタンスのスナップショットを取ります。スナップショットはインスタンスの稼働中でも可能です。もしもの時にスナップショットから新しくインスタンスを作成することができます。

### パッケージの自動更新
Compute EngineのCentOSのインスタンスはyum-cronによるパッケージの自動更新がデフォルトで有効化されています。なので、インストール済みのパッケージのセキュリティパッチなど自動でマイナーバージョンアップされます。

例えば、phpのパッケージの更新履歴を見てみると、直近では「5.4.16-46.1.el7_7.x86_64」に自動更新されたことがわかります。

```
$ sudo yum history package-list php
Loaded plugins: fastestmirror
ID     | Action(s)      | Package                                              
-------------------------------------------------------------------------------
   142 | Updated        | php-5.4.16-46.el7.x86_64                             
   142 | Update         |     5.4.16-46.1.el7_7.x86_64                         
    57 | Updated        | php-5.4.16-45.el7.x86_64                             
    57 | Update         |     5.4.16-46.el7.x86_64                             
    10 | Install        | php-5.4.16-45.el7.x86_64                             
history package-list
```

# まとめ
全部お守りしてくれるレンタルサーバーと違って、費用もやることも増えましたが開発の自由度が上がって提供できるサービスレベルも格段に上がりました。

色々と触ってみながら、徐々に最適な運用方法を見つけていきたいと思っています。
AIに歌わすのは大変すぎる。


#AIに歌を歌わせてみた。
最近はVocaloidやVtuber等良い声が出るAiがありますが、自作できないのか探求しています。

```SpeakingOS.cpp
static constexpr auto DO = "ド";
static constexpr auto RE = "レ";
static constexpr auto MI = "ミ";
static constexpr auto FA = "ファ";
static constexpr auto SO = "ソ";
static constexpr auto RA = "ラ";
static constexpr auto SI = "シ";
int main(void){
    return NULL;
}
```

## `TITLE`残業はなくならず
`歌詞`
残業はなくならず,国は捨てる
気持ち悪くなるだけ,悪くなってしまった
闇にいーる,疲れにやられてて,窓から見えるいつもの街灯を探した,わかってる
労働争議するわけでもなくて君と文句いうこともない
かつてと違うことは1つ,生きる勇気を失ってしまった
残業は,たまあってく おーわることなくー
かーいしゃの電気がほとんど消えてしっまった
残業はなくならず国は捨てる
たくさん過労が事実でも空しみは消えません
褒美だったと思っていた毎日も無くなっていた
知らなかった。あの地位になれば死なぬと思わなかったのに
育児とか 嫁とかのため何をすれば,いいのかわからなくなるなんてな
(いや)分かってる。もう昔の俺ではない 後ろめたい表現を俺の心が生み出した
最も大きい空しみさ
残業は 給料の証という
けれど(残業代が)実らぬならそう意味が無いサービス残業
定時で帰りたいよ 上司帰ったよ
1人ですすり泣く日々 残業に追われるだけ
誰も払わない(居酒屋の)勘定
払うどころか押し付けるから
いい加減に払いません？
このツケ返して貰いますって
(上司が怖いから)言えないよ
残業はなくならず国は捨てる
上司が謝っても,空しみは消えません
生きがいだった子がいても
ここにはいない
この会社を出なければ
会うこともできないのに
一人ですすり泣く日々残業に追われるだけ
備忘録　zabbixでのTeraStation監視

TeraStation用のテンプレートをDLしてインポート
<https://share.zabbix.com/storage-devices/buffalo/buffalo-terastation>
デフォルトのコミュニティ名はterastationなので、必要に応じて変更する
<img width="533" alt="20200213_002.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/511848/0082a184-501b-2213-b1df-69f3abb70d02.jpeg">
v-forを使ってselect optionを生成

```html
<div id="app">
  <select name="user" v-model="selected">
    <option disabled value="">選択して下さい</option>
    <option v-for="user in users" v-bind:value="user.name" v-bind:key="user.id">
      {{user.name}}
    </option>
  </select>
</div>
```

```javascript
new Vue({
  el: '#app',
  data: {
    users: [
      {id:1, name:'佐々木'},
      {id:2, name:'鈴木'},
      {id:3, name:'高木'}
    ],
    selected: ''
  }
})
```
GitHub PagesとJekyllを使ってポートフォリオページを作ろう①GitHub Pages構築編

# はじめに
なんかQiita投稿したいな〜と思いつつ何も書いてなかったので書いてます。
別に記事にするほどのことではありません。日記です。
ありふれた記事を参考にありふれた記事を書きます。
参考記事を置いておくので僕の記事分かりにくかったら読んでみてください。やっていることはほとんど同じです。
- https://qiita.com/stern327/items/1748ec6265aab88648ab


# ポートフォリオってなんぞ
**ポートフォリオ(portfolio)**とは、自分の作品集のことを言います。
いわゆるクリエイターの自己紹介ですね。
主にデザイナー界隈で使われる言葉らしいです。（知らんけど）

デザイナーやエンジニア、その他クリエイターをはじめ、
就職時やクライアントへの売り込みなどで自己アピールを行うための重要なツールとなります。
# ポートフォリオ作りたくね？
Qiitaに訪れているということはプログラミングしてるorしたいってことですよね？
でもローカルで動かしたり、ただネットに置いただけで満足ですか？
もっと自分の成果見てもらいたくないですか？
ビジネスにつなげるためにも、ポートフォリオを作りましょうよ！！！

#  めっちゃ簡単に作れるやないか〜い
**今回の方法にたどり着くまでの僕**
「WixとかJimdoでサイト作ったことはあるけど、それはもう卒業したい。
AWS EC2とwordpress使ってみようかな〜でも永続的に使うと課金必要だしな〜」

**大学の友人**
「GitHub Pages＋Jekyllの組み合わせが一番いい」

**その後いろいろ調べた僕**
「なんかAWSめんどくさそうだからGitHub Pages使ってみよ〜〜......」
「え、めっちゃ簡単！！！」
って感じです。
# GitHub  Pagesってなに？
GitおよびGitHubについては適当にググってください。
簡単に言えばソースコード公開所です。少なくとも僕はそう思ってます。
GitHubPagesはGitHubを利用してHPを公開できる機能です。

・GitHubのアカウントがあれば誰でも使えます。
・**サーバーが必要なく課金も必要ありません。**
・GitHubの練習にもなる（ソロだけど）
・**コードが公開される点は注意**

# どうやって使うべや
手順は簡単、以下の通りです。
1. GitHubのアカウントを作成
2. [自分のID].github.ioでリポジトリ作成　(IDで作るのは慣習？理由あり？)
3. ローカルにクローン作っていじる


1,2は説明するほどのことではないと思うので割愛します。

## ローカルにクローンを作っていじる
一応GitHub上でも編集はできますが、編集のしやすさやGitの練習のことを考えてローカルにクローンします。 

僕の環境はMacOSです。今回はターミナルではなく**SourceTree**というGitクライアントを利用します。
↓ここからダウンロードしてインストールしましょう。
・[SourceTree公式](https://www.sourcetreeapp.com/)

インストールできたら起動します。

↓起動したら[新規]より[URLからクローン]を選択します。
<img width="479" alt="スクリーンショット 2020-02-13 4.29.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502867/05671bfe-01c4-973c-1870-275a36c7db67.png">

↓URLのところに2で作成したリポジトリのリンクを貼り付けます。保存先は好きなところにどうぞ。(Gitフォルダ作るのがオススメ)
<img width="501" alt="スクリーンショット 2020-02-13 4.30.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502867/441ff97e-3f08-7a58-18a9-3d1bf5f4a2e9.png">

ちなみにリポジトリのリンクはGitHubのリポジトリにアクセスして画像右下のボタン押すとコピーできます。
<img width="1071" alt="スクリーンショット 2020-02-13 4.27.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502867/eb654cb5-5379-a185-669a-cab432ade572.png">
↓クローンを押し、以下のようになれば完了です。
（名前変えてますが上の画像通りにやるとyuuto1228になります）
<img width="483" alt="スクリーンショット 2020-02-13 4.34.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502867/625e23ed-9cbf-ceee-4792-f58967a7c22c.png">
※実際の編集は保存先のディレクトリで行います。

### indexファイルの生成
gitの設定でテーマを変更していない場合、リポジトリには何もファイルがない状態です。
もしテーマを使いたい場合は設定を変えてからフェッチを行なってください。
１から自分で作る場合は、`index.html`を作成しましょう。
`index.md`でも良いです。


# これで環境はできた！簡単でしょう？
環境はできたのであとはファイルをいじいじ
してリポジトリにプッシュプッシュするだけです。
僕はGit初心者なのでSourceTreeの使い方含め使いながら覚えたいと思います。
その辺の手順も追い追い備忘録として書きます。

# 次回
次回はJekyllについて書こうと思います。これは**Webサイトを構成するHTMLファイル一式を出力する**ツールだそうです。

次回→[GitHub PagesとJekyllを使ってポートフォリオページを作ろう②Jekyll構築編](https://qiita.com/H_Ny/items/e53ff2533274ec362891)
iOS / Androidでスクロール禁止にするが一部だけはスクロールできるようにする

表題の通りですが、スクロール禁止にするが一部だけはスクロールできるようにする場合の対応。

基本はhtmlに`overflow: 'hidden'`を掛けて、スクロールしたいところに`overflow: 'scroll'`を掛ければいいのですが (あまり確認していないので違うかも…)、iOSだとJavaScriptを使う必要があります。

スクロール禁止にする場合は`preventDefault()`（と、`{passive: false}`も第三引数に必要）を`touchmove`イベントの時に実行すればいいのですが、注意するポイントが2つあります。

1. スクロール禁止を解除する場合
    * `removeEventListner`を実行すればいいのですが、`addEventListner`を実行したときと同じ関数を渡さなければなりません。この時アロー関数だとaddの時とremoveの時で違うものとなりますのでアロー関数は使わないようにします。
2. 表題の通り一部だけはスクロールできるようにする場合
    * スクロールしたい場合は`preventDefault()`の代わりに`stopPropagation()`を実行すればよいです。下記のコードでは`touchmove`イベントが発生した時の要素の親に`js-can-scroll`クラスがあれば、スクロールできるように`stopPropagation()`を実行するようにしています。

```js
        // スクロールを無効化
        $('html').css({
            overflow: 'hidden'
        });
        document.addEventListener(
            'touchmove',
            scrollControll,
            {
                passive: false
            }
        );

        // スクロールを有効化
        $('html').css({
            overflow: ''
        });
        document.removeEventListener(
            'touchmove',
            scrollControll,
            {
                passive: false
            }
        );

    // add/removeEventListenerでアロー関数として定義するとイベントが削除されない
    var scrollControll = function(event) {
        if ($(event.target).closest('.js-can-scroll').length > 0) {
            event.stopPropagation();
        } else {
            event.preventDefault();
        }
    };
```


参考: [iOS でページ全体はスクロールを無効にし、個別の要素（textarea など）では有効にする方法 \- Qiita](https://qiita.com/noraworld/items/2834f2e6f064e6f6d41a)
gitignoreとvendor/bundle

今回は以下のようになってしまった際の対処法です。

### Files changed に3000とか9000とか上がってしまう
[![Screenshot from Gyazo](https://gyazo.com/6e876fa464255f4be82ab82054b60005/raw)](https://gyazo.com/6e876fa464255f4be82ab82054b60005)

### レビューしてもらったが、色々指摘されている
[![Screenshot from Gyazo](https://gyazo.com/2ac013f40552aa22c33f4169af8e567c/raw)](https://gyazo.com/2ac013f40552aa22c33f4169af8e567c)

# 1. gitignoreについて知る
## gitignoreとは

gitignoreとは以下のファイルです。
gitの管理下から除外したいファイルを書きます。

`hello`というディレクトリ中身全てを除外したい場合は

```
/hello/
とするか、
hello/
とするか
hello/*
```

[![Screenshot from Gyazo](https://gyazo.com/1acc0da74575bb7ced670285e633c835/raw)](https://gyazo.com/1acc0da74575bb7ced670285e633c835)

## gitignoreの注意点
gitignoreはgitignoreに記載後、ファイルが次に作成された時にignoreされる。

### *つまり、元からあったファイルはgitignoreに記載しても除外されない*
## 対処法

実際のファイルは残しながら、gitから削除する、削除したというコミットをする。

```
git rm --cached -r ファイル・フォルダまでのパス
```

つまり
`git rm --cached -r uploads/images/* `などのコマンドを実行する

# 2. vendor/bundleについて知る
## vendor/bundleとは
bundle installするときのオプションでよく使われる

```
bundle install --path vendor/bundle
```
bundle installで導入されるgemが全て、アプリのディレクトリの中に保存されます。
バージョンを固定したい場合や本番環境なので、ごくごく稀に使用される。

## vendor/bundleする弊害
gitignoreしていないと、gitに大量の変更が上がってしまう。
## vendor/bundleの対処法
ファイルを消して、bundle installする。
ではダメです。

.bundleフォルダにあるconfigファイルにvendor/bundleのパスが残されています。
これを削除する必要があります。


```
vi .bundle/config

BUNDLE_PATH: "vendor/bundle"の行を消す
```

レビューワーからgemがアップロードされているようですrevertしましょう！
とあったとしても、上記BUNDLE_PATHの設定が原因で、revertが本質の解決とならないので気をつけましょう。
[![Screenshot from Gyazo](https://gyazo.com/2ac013f40552aa22c33f4169af8e567c/raw)](https://gyazo.com/2ac013f40552aa22c33f4169af8e567c)

また、アプリのディレクトリだけでなく、その上の階層のディレクトリにも.bundle/configにBUNDLE_PATHの記述がないか確認しましょう！
やるべきことをまとめると、

- vendor/bundleのディレクトリを削除
- .bundle/configの修正
Python3かつvenv使用時にuWSGIをインストールする時の注意点


# はじめに
　初投稿です。Pythonでwebアプリケーションを構築する際に用いるuWSGIのインストール方法に関する記事です。

# 準備
　OSはLinux、Mac。Windowsの場合は分からないです。
　まず、Python3でvenvを建てる
`$ python3 -m venv ./venv`
アクティベート
`$ . ./venv/bin/activate`
pipのアップグレード（兼pipコマンドが通るか確認）
`(venv) $ pip install -U pip`
このまま普通にuWSGIをインストールしようとしても、おそらくエラーになるはずです。

```
(venv) $ pip install uwsgi
...(略)
No such file or directory
     #include <Python.h>
              ^~~~~~~~~~
    コンパイルを停止しました。
```


# 公式のドキュメンテーションをみる
　[Installing uWSGI — uWSGI 2.0 documentation](https://uwsgi-docs.readthedocs.io/en/latest/Install.html) を参照。これによれば、

#### Devian系統 (Ubuntu等)
```
$ sudo apt-get install build-essential
$ sudo apt-get install python-dev
```

#### RedHat系統 (CentOS, Amazon Linux AMI等)
```
$ sudo yum groupinstall "Development Tools"
$ sudo yum install python-devel
```

を打ってからpipでuWSGIをインストールするとの事。
このようにすればコンパイルが通るようになり、うまくインストールできるらしい.

　[uwsgiをEC2インスタンスにインストールしようとして失敗した話](https://qiita.com/hayatetabata/items/111987d1b2b544f6185c) 
を見ても、同じコマンドを打っていてコンパイルが通ったと報告がなされている。

　しかし、Python3のvenv環境ではこのようにコマンドを打った後でもpipでのインストールが通らない。
venvを使っていなくともPython3であれば、
`$ python3 -m pip install uwsgi` とコマンドを打ってもエラーになるはず。

# 解決策
　RedHat系統でしか確認できていないが、上のコマンドを次のように変更してやれば良いだけのことだった。

```
$ sudo yum groupinstall "Development Tools"
$ sudo yum install python3-devel
```

これでuWSGiのインストールも通るはず。

```
(venv) $ pip install uwsgi
Collecting uwsgi
  Using cached https://files.pythonhosted.org/packages/e7/1e/3dcca007f974fe4eb369bf1b8629d5e342bb3055e2001b2e5340aaefae7a/uwsgi-2.0.18.tar.gz
Installing collected packages: uwsgi
  Running setup.py install for uwsgi ... done
Successfully installed uwsgi-2.0.18
```

Ubuntu等の場合でも、次のように変更すれば多分いけるはず。

```
$ sudo apt-get install build-essential
$ sudo apt-get install python3-dev
```

[bottle+uWSGI+python3+nginxでアプリを動かす](https://wwld.jp/2015/02/24/bottle-uwsgi-nginx.html) でも同じようにコマンド打ってますね。

　これでインストールが通る理由としては、python-devやpython-develはPython3ではなくPython2に対応したものだから（多分）。python3-devやpython3-devel、はたまたpython3.6-devなんてものが出ていることからも恐らくそうなのだろう。

　venvを使わずに、`python -m pip install uwsgi` などと打ってうまくいっている例が多い（ように感じる）のは、pythonのパスがPython2のバージョンのものになっているのではないだろうか。linuxだと大体デフォルトではそうだし。
　その場合、nginxやDjango、Flask等と繋げるところまではとりあえずうまくだろうが、uWSGIを通してwebアプリを動かす時にはPython2で動いていることになるので、f文字列等のPython3特有の構文は使えなくなるし、venvを使ってないので入れるモジュール（バージョン含め）を環境ごとに分けるとかも出来なくなる。


# 補足
　venv環境を使ったwebアプリケーションをuWSGIで動かす時は、コマンドを打つ際に
`$ uwsgi ~(略)~ --venv /to/path/venv`
と追加するか、.iniファイルに

```
...(略)
venv = /path/venv
```
を追記するのを忘れずに。

# 終わりに
　以上がPython3かつvenv使用時にuWSGIをインストールする時の注意点、になります。自分含めてuWSGIのインストールでハマってしまう人が多い気がするわりに、「uwsgi python3 venv」等のキーワードで検索しても全然引っかからず、また「python3-devel」で検索しようとしても検索候補にuWSGIが出なかったりしたので、必要性があるかもしれないと思い寄稿しました。
　てかPython2もサポート終了するんだし、uWSGI公式のドキュメンテーションは普通に修正した方がいいと思う。
　何か指摘あれば遠慮なくお願いします。
torchvisionをインポートする際にundefined symbolエラーが発生する

## 問題
pytorch1.1.0でtorchvision0.3.0をインポートするとエラーが発生する．

```
ImportError: myenv/lib/python3.7/site-packages/torchvision/_C.cpython-37m-x86_64-linux-gnu.so: undefined symbol: _ZN3c107Warning4warnENS_14SourceLocationENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
```

## 解決方法
それぞれをアンインストールし，再びインストールし直す．
何が起きているかはわからないがとりあえず解決した．バージョンは自分にあったものを．
[参考](https://github.com/facebookresearch/maskrcnn-benchmark/issues/813#issuecomment-495714967)

```
$conda uninstall pytorch
$conda uninstall torchvision

$conda install pytorch==1.1.0 torchvision==0.3.0 cudatoolkit=9.0 -c pytorch
```
GASのデバッグモードで、連想配列に空欄があると、デバッガーにはその要素が表示されないメモ

<h3>連想配列にあるべきキーと要素(空欄)が確認できない？？？</h3>
GASのデバッグモードでブレークポイントを使って各変数の状態を確認するなんてことはよくあると思いますが
連想配列にセットした値が空欄('')のような場合は、プロパティエリアには表示されなかったのでメモします。

```js:test.gs
  var list = {'mango':100, 'orange':200, 'apple':'', 'pineapple':'pen'};
  var breakPoint = 1; //←ここでブレイクポイントを打つ
```
デバッグモードで実行した結果、以下のようにappleは表示されない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/543473/2f9d2f60-73d4-f66f-6c2d-f52579d88e0c.png)

他のIDEもこれが普通？大層な開発環境使ってないのでわかりませんが
これだけのことで2時間ぐらいハマりました…
Githubでこんなものがでた。There have been several failed attempts to sign in from this account or IP address. Please wait a while and try again later.

*There have been several failed attempts to sign in from this account or IP address. Please wait a while and try again later.*

Githubのauthenticationの入力に何度も失敗。

5分くらいでまた入力できるようになりました。

焦った。
【HackforPlay】公開作品のログ【作品ログ】

自分のHackforPlayの公開作品のログです。

---

#hfpfes 2020/02
たにさんがプレイしてくれた『スイッチを踏んでゴールを目指そう!!』はこちらです。
メッセージ機能をシンプルに活用してみました。

https://www.hackforplay.xyz/works/kila9KMmMqsFjAAdc6A8

---

『赤い扉を目指せ!!』
https://www.hackforplay.xyz/works/ojyzRKB1SvjDM3bFsUTK

<img width="1080" alt="hfp01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/d60076db-a327-f274-db79-c73d992f4bfb.png">

---
How to print Qiita and Zhihu document



Run the code in your browser console.
## Not print link URL
```css
@media print {
  a[href]:after {
    content: none !important;
  }
}
```
**Windows**: Ctrl+Shift+I  
**Mac**: Cmd+Opt+I

```js
/* for Qiita */

function remove_ele(selector){
  try {
    $(selector).remove();
  }catch(error) {}
}


$('body').append($('.p-items_article'))

do {
  var e=$('body>*');
  if(e.className.indexOf('p-items_article')==-1){
    e.remove();
  }else{
    e.OK = 1;
  }
} while (e.OK != 1)

remove_ele('.u-flex-center-between');
remove_ele('.ai-Container');
remove_ele('.it-Footer');
remove_ele('.it-DeprecationAlert_one');

window.print();
```

```js
/* for Jianshu */
$('body').innerHTML = $('.ouvJEz').innerHTML
$('.rEsl9f').remove();
$('._1kCBjS').remove();
$('._19DgIp').remove();
$('._13lIbp').remove();
$('.d0hShY').remove();
window.print();
```

```js
/* for Zhihu */

function remove_ele(selector){
  try {
    $(selector).remove();
  }catch(error) {}
}


$('body').append($('article.Post-Main'))

do {
  var e=$('body>*');
  if(e.className.indexOf('Post-Main')==-1){
    e.remove();
  }else{
    e.OK = 1;
  }
} while (e.OK != 1)

remove_ele('.Sticky');
remove_ele('.Post-topicsAndReviewer');
remove_ele('.Post-Author');

window.print();
```
githubなどにsshを行ったとき、configや -i でidentity_fileを指定したにもかかわらず別のものが使われてしまう場合の対処法

#結論
ssh-agentが適用されてしまっていると、それが優先度が一番高くなってしまう。

#ケース
私の場合SourceTreeで、複数のGithubアカウント（会社用と個人用）のリポジトリを両方使っているとしばしば発生します。pushやpullなどリポジトリアクセスが必要な操作をしたときにエラーになります。

```
git --no-optional-locks -c color.branch=false -c color.diff=false -c color.status=false -c diff.mnemonicprefix=false -c core.quotepath=false -c credential.helper=sourcetree push -v --tags origin refs/heads/[branch名]:refs/heads/[branch名]
Pushing to [リポジトリのパス].git
ERROR: Repository not found.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
Completed with errors, see above
```

#原因
ssh-agentのせい

SSH接続の優先度は
1. keys from the agent (ssh-agentの設定)
2. keys from the config file (ssh configの設定)

opensshの該当ソース
https://github.com/openssh/openssh-portable/blob/master/sshconnect2.c#L1622

#確認方法
-vをつけてssh

```
ssh git@github.com -v
OpenSSH_7.9p1, LibreSSL 2.7.3
debug1: Reading configuration data /etc/ssh/ssh_config
・・・
debug1: Will attempt key: ｛Key｝ RSA SHA256:{フィンガープリント} agent <= これ
debug1: Will attempt key: /Users/hogefuga/.ssh/id_rsa
debug1: Will attempt key: /Users/hogefuga/.ssh/id_dsa
debug1: Will attempt key: /Users/hogefuga/.ssh/id_ecdsa
debug1: Will attempt key: /Users/hogefuga/.ssh/id_ed25519
debug1: Will attempt key: /Users/hogefuga/.ssh/id_xmss
・・・
debug1: Exit status 1
```
Will attempt key の行の末尾に `agent` が含まれていれば、ssh-agentの設定が適用されています。ログを追っていくと{Key}のidetity_fileが最終的に使われているのがわかります。

# ssh-agent

ssh-agentについてはこちら。
https://euske.github.io/openssh-jman/ssh-agent.html

## ssh-agentの状況を確認

```
$ ssh-add -l
2048 SHA256:{フィンガープリント} {Key} (RSA)
```

やはり設定されていました、いつの間にかSourceTreeを使っているとなります

#対処法

```
ssh-add -D
```

もう一度sshすると、今度はagentの行がなくなり、configの設定が適用されるはずです。

#恒久的対処法
.ssh/configのHost設定中に `AddKeysToAgent yes` があると、この設定を使うたびにssh-agentに追加されてしまうので注意。削除しましょう。
SourceTreeによって生成されたconfg設定にこの行が存在します。

以上
Rails の設計を見直す

下記の記事がRailsの設計見直しに役立ったので、リンクをメモ

[肥大化したActiveRecordモデルをリファクタリングする7つの方法（翻訳）](https://techracho.bpsinc.jp/hachi8833/2013_11_19/14738)

[Railsで重要なパターンpart 1: Service Object（翻訳）](https://techracho.bpsinc.jp/hachi8833/2017_10_16/46482)

[3年以上かけて培ったRails開発のコツ集大成（翻訳）](https://techracho.bpsinc.jp/hachi8833/2017_11_20/48322)
DRF(Django REST Framework)でSerializerからViewの情報にアクセスしたいときもある件

この作りが良いのかどうかは別にして、SerializerからViewの情報にアクセスしたい時ってありますよね。そんな時に使える便利なMixinを社内では使いまわしています。やればやるほど、ViewとSerializerとの結合が強くなるので、 __用法・用量__ を守って使うのをオススメします。

何はともあれ、ソースコードです。

## ViewAccessSerializerMixin

```python
class ViewAccessSerializerMixin(object):

    def get_view_action(self):
        """
        Serializer から View の actionへアクセスする
        """
        context = getattr(self, 'context')
        if not context:
            warnings.warn('serializerにcontextが存在しません。不正な形でインスタンスが作られています')
            return None
        return context.get('view').action

    def get_view_kw(self, key, default=None):
        """
        Serializer から View の kwargsへアクセスする
        """
        context = getattr(self, 'context')
        if not context:
            warnings.warn('serializerにcontextが存在しません。不正な形でインスタンスが作られています')
            return default
        return context.get('view').kwargs.get(key, default)

    def get_kwargs_object(self, key, model_class):
        """
        Serializer から kwargs へアクセスし、それを id とみなして、指定されたモデルを検索する
        """
        obj = model_class.objects.get_or_none(id=int(self.get_view_kw(key, 0)))
        if obj:
            return obj
```

## View の action へアクセスする

大体は、 `validation`で使ってます。多分もっと良い条件分けはあると思います。こんな感じ。

```python
class HogeSerializer(ViewAccessSerializerMixin, serializers.ModelSerializer):

    # 色々省略

    def validate(self, attrs):
        # アクションによって検証内容を変える
        action_name = self.get_view_action()
        if action_name == "xxxx":
            pass
        else:
            pass
```

## View の kwargs へアクセスする

大体、SerializerMethodField で使ってます。

```python
class PostHistorySerializer(ViewAccessSerializerMixin, serializers.ModelSerializer):

    # 色々省略

    comments = serializers.SerializerMethodField()

    def get_comments(self, obj):
        return obj.comment.filter(user_id=self.get_view_kw("user_pk"))
```

## View の kwargs へアクセスし、それを id とみなして、指定されたモデルを検索する

↑の組み合わせに近いですが、ショートカットです。

```python
class UserSerializer(ViewAccessSerializerMixin, serializers.ModelSerializer):

    # 色々省略

    def validate(self, attrs):
        user = self.get_kwargs_object('user_pk', models.User)
        if user.is_ban():
          raise NotFound()
        pass
```

基本的には、こんな感じで使っています。便利に使ってくれると嬉しいです。
openFrameworksでAPC40 MKIIのモードを変更する

# APC40 MKIIのモードについて

APC40 MKIIには次の3つのモードがある。[参照](https://www.bome.com/support/kb/akai-apc-40-mkii-change-mode)

- Generic Mode : 完全にAPC40上で操作できるモード
- Ableton Live Mode(LED Ring Remote Controled) : LEDのつまみはAPC40で制御し、それ以外はPC上で制御
- Alternate Ableton Live Mode : 全てPC上で制御

openFrameworksでMidiコンを扱う場合は、[ofxMidi](https://github.com/danomatika/ofxMidi)というAddonを使うが、下のように単純に接続するだけではGenericモードで制御することになる。

```c++:ofApp.h
ofxMidiIn midiIn;
ofxMidiOut midiOut;
```
```c++:ofApp.cpp

midiIn.listInPorts();
midiIn.openPort("APC40 mkII 0");//マシンによって違うかも
midiIn.ignoreTypes(false, false, false);
midiIn.addListener(this);
midiIn.setVerbose(false);

midiOut.listOutPorts();
midiOut.openPort("APC40 mkII 1");//マシンによって違うかも
```
Genericモードでは、APC40 MKII上の操作で、値の上書きがされる。
例えば、Padを押した際に、oFから`sendNoteOn`でPadの色を光らせても、離した際に勝手に光が消えてしまう(`SendNoteOff`がAPC40上で発生)。また、LEDリングもつまみを回すと値が上書きされる。

APC40 MKIIの値を、コントローラーとしてPCから完全に制御したい場合は、Alternate Ableton Live Modeが良い。このモードにすれば、Midiコン操作時の処理をPCで書かない限り、値は絶対に変化しない。したがって一度`SendNoteOn`で光らせれば、oFから処理を行わない限り、押しても離しても光が消えることはない。もちろん`SendNoteOff`を送れば消せる。

# モード変更方法

APC40 MKIIのモード変更は、[SysExメッセージ](https://www.g200kg.com/jp/docs/dic/systemexclusive.html)を送ることで変更可能。先ほどのofApp.cppの後に、次のコードを追加する。7つ目の`0x42`となっている箇所の値を変えることでモードが変えられる。

- `0x40` : Generic Mode
- `0x41` : Ableton Live Mode (LED Ring Remote Controled)
- `0x42` : Alternate Ableton Live Mode

~~~c++
////akai apc40 mkii
vector<unsigned char> sysexMsg;
sysexMsg.push_back(MIDI_SYSEX);

sysexMsg.push_back(0x47);
sysexMsg.push_back(0x7F);
sysexMsg.push_back(0x29);
sysexMsg.push_back(0x60);
sysexMsg.push_back(0x00);
sysexMsg.push_back(0x04);
//---change mode
///0x40 Generic (Startup Default) Track select Radio- Channel Toggle
///0x41 Ableton Live(LED Ring Remote Controlled) Momentary All
///0x42 Alternate Ableton Live Momentary All
sysexMsg.push_back(0x42);
//---
sysexMsg.push_back(0x09);
sysexMsg.push_back(0x07);
sysexMsg.push_back(0x01);
sysexMsg.push_back(MIDI_SYSEX_END);
midiOut.sendMidiBytes(sysexMsg);
~~~

または、下のコードでも動く。

~~~c++
midiOut << StartMidi() << MIDI_SYSEX
<< 0x47 << 0x7F << 0x29 << 0x60 << 0x00 << 0x04 << 0x42
<< 0x09 << 0x07 << 0x01 
<< MIDI_SYSEX_END << FinishMidi();
~~~
M5StickCでBluetooth接続のマウスを作成する

#はじめに
M5StickCには加速度センサーが付いていて、傾きを検出できます。またボタンが２つでBluetooth接続ができるので、マウスを作成してみます。
※Arduino IDEでM5StickCの開発ができる環境は事前に作成しておく必要があります。
※「MPU6886」が搭載されているM5StickCを使用します。初期ロットは「SH200Q」とのことですが、
　恐らく「SH200I」のサンプルをベースにすれば同じことができると思います。

#準備
①以下のサイトから「Bluetooth LE Mouse library for the ESP32」をZIPでダウンロードします。
https://github.com/T-vK/ESP32-BLE-Mouse
②「スケッチ」→「ライブラリをインクルード」→「.ZIP形式のライブラリをインストール...」でダウンロードしたZIPファイルを選択する。

#
①「スケッチ例」の「M5StickC」→「Basics」→「MPU6886」のサンプルをベースにします。
②別名で保存し、「ESP32 BLE Mouse」のライブラリをインクルードします。
③元のサンプルは加速度センサーの値を取得して表示するだけなので、ここにボタンの状態を取得してマウスの入力を送信する部分を追加します。

#ソース

```C++
#include <BleConnectionStatus.h>
#include <BleMouse.h>

#include <M5StickC.h>

BleMouse bleMouse;
signed char mouse_x = 0;
signed char mouse_y = 0;
float mouse_min = 200;

float accX = 0;
float accY = 0;
float accZ = 0;

float gyroX = 0;
float gyroY = 0;
float gyroZ = 0;

float temp = 0;
void setup() {
  // put your setup code here, to run once:
  M5.begin();
  M5.Lcd.setRotation(3);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setTextSize(1);
  M5.Lcd.setCursor(40, 0);
  M5.Lcd.println("BLE Mouse");
  //M5.Lcd.setCursor(0, 15);
  //M5.Lcd.println("  X       Y       Z");
  M5.MPU6886.Init();
  bleMouse.begin();
  while(bleMouse.isConnected() == false) {
    delay(100);
  }
}

void loop() {
  // put your main code here, to run repeatedly:
  //M5.MPU6886.getGyroData(&gyroX,&gyroY,&gyroZ);
  M5.MPU6886.getAccelData(&accX,&accY,&accZ);
  //M5.MPU6886.getTempData(&temp);

  //M5.Lcd.setCursor(0, 30);
  //M5.Lcd.printf("%.2f   %.2f   %.2f      ", gyroX, gyroY,gyroZ);
  //M5.Lcd.setCursor(140, 30);
  //M5.Lcd.print("o/s");
  //M5.Lcd.setCursor(0, 45);
  //M5.Lcd.printf("%.2f   %.2f   %.2f      ",accX * 1000,accY * 1000, accZ * 1000);
  //M5.Lcd.setCursor(140, 45);
  //M5.Lcd.print("mg");
  //M5.Lcd.setCursor(0, 60);
  //M5.Lcd.printf("Temperature : %.2f C", temp);

  M5.update();
  if(M5.BtnA.isPressed()){
    if(M5.BtnB.isPressed()){
      bleMouse.press(MOUSE_LEFT | MOUSE_RIGHT);
    }else{
      bleMouse.release(MOUSE_RIGHT);
      bleMouse.press(MOUSE_LEFT);
    }
  }else{
    if(M5.BtnB.isPressed()){
      bleMouse.release(MOUSE_LEFT);
      bleMouse.press(MOUSE_RIGHT);
    }else{
      bleMouse.release(MOUSE_LEFT | MOUSE_RIGHT);
    } 
  }

  mouse_x = 0;
  mouse_y = 0;
  if(accX * 1000 > mouse_min){
    mouse_x = -1 * (accX * 1000) / mouse_min;
  }
  if(accX * 1000 < mouse_min * -1){
    mouse_x = -1 * (accX * 1000) / mouse_min;
  }
  if(accY * 1000 > mouse_min){
    mouse_y = 1 * (accY * 1000) / mouse_min;
  }
  if(accY * 1000 < mouse_min * -1){
    mouse_y = 1 * (accY * 1000) / mouse_min;
  }

  bleMouse.move(mouse_x, mouse_y);
  
  //delay(50);
}
```

#注意点
ペアリングがなかなかうまくいかないことがあります。
ペアリング後、一度M5StickCを再起動してから再接続するとうまくいくことが多いようです。

#最後に
特にマウスカーソルを動かす部分はもう少し工夫が必要と思います。
とはいえ、パワポのページを進めるリモコンとかなら十分つかえそうな気がします。
Chalice ー Python Serverless Microframework for AWS

PythonのAPIを作りたいと思って調べていたところ、Chaliceを見つけました。
今回はちょっとした備忘録記事です。

Chaliceは一言で言えば、AWSによるPythonのサーバーレスフレームワークです。
AWSからGitHubに公開されており、怪しい挙動はきっとあまりしないでしょう。
https://github.com/aws/chalice

ChaliceはデプロイするとApiGateway + lambdaを利用してサーバーレスに公開してくれます。

# 環境

- macOS Catalina 10.15.1
- python 3.6.4  
- chalice 1.12.0

# Chaliceのインストール
```
$ pip install chalice
$ chalice --version
```

# AWS IAMの設定
ApiGatewayとlambdaの操作権限を持つユーザーから操作しないとデプロイできません。
今回は簡単にポリシー「AdministratorAccess」を与えたユーザーから操作させます。
本当ならより権限を絞って最低限の開発ユーザーで..(略)

IAMユーザ作成方法は以下を参考にしてください。
[AWSアカウントでのIAMユーザの作成](https://qiita.com/kzykmyzw/items/ca0c3276dfebb401f7d8)


# ハマったポイント
app.pyと.chaliceフォルダ内にある「config.json」のapp_nameが一致している必要があります。
config.json `"app_name": "hoge-api"`
app.py `app = Chalice(app_name='hoge-api')`

一致していないとdeploy時、直接的な原因特定のしにくいエラーが吐き出されます。↓

```
❯ chalice deploy
...
(略)
...
botocore.exceptions.ConnectionClosedError: Connection was closed before we received a valid response from endpoint URL: "https://lambda.ap-northeast-1.amazonaws.com/2015-03-31/functions".
```



# 参考
[20190619 AWS Black Belt Online Seminar Dive Deep into AWS Chalice](https://www.slideshare.net/AmazonWebServicesJapan/20190619-aws-black-belt-online-seminar-dive-deep-into-aws-chalice)
[Chaliceのすゝめ AWSにWebApiをサーバーレスで構築する](https://qiita.com/tukkyr/items/b1f54b467375ba29facf)
[Chaliceのすゝめ その2 WebApiに認証を追加する](https://qiita.com/tukkyr/items/d02be9c9e4fe7d974b1c)
[How to create a thumbnail API service in 5 minutes](https://www.mschweighauser.com/create-a-thumbnail-api-service/)
Realsense D435i 延長

#機材
延長ケーブル
　UGREEN USB 延長ケーブル USB 3.0 リピーターケーブル 信号強化 高速データ転送 金メッキ アクティブ式 5M https://www.amazon.co.jp/dp/B07C2KWVG1

ACアダプター
　SwitchScience ラズパイ3Bおよび3B+に最適なACアダプター 5V/3.0A USB Micro-Bコネクタ出力 https://www.switch-science.com/catalog/2801/

#接続方法
1.ACアダプターをコンセントに入れる。
2.ACアダプターと延長ケーブルを接続する。
3.延長ケーブルとRealsenseを接続する。
4.PCと接続する。もしくはPCの電源を入れる。
※先に延長ケーブルとPCを接続すると認識しない？

#その他
- パワーが要らない時(プロジェクター投影しない時？)はACアダプター不要でも動くような気がする。
- ACアダプターの電流が少ないものを使用したときにパワーがいる設定にしたときに不安定になるような気がする。
- (不明)　ACアダプターを付けた状態だとUnityのサンプルのUI Image Sample（Depth ＆ Color）が表示されない。ACアダプターを外すと動く　なぜ？　なお、CariblationTool　は　ACアダプターがないと認識されない。
BigQueryで重複削除する方法

テーブル作成時にインデックスとしてナンバリングしておけば違う書き方もできたんですけど、
特定の行だけで重複削除する方法はこれしか見つからなったので備忘録として記載。

# 最終的なコード

``` SQL
-- 一時テーブルの作成　※1
CREATE TEMPORARY TABLE tmp AS
SELECT * FROM(
SELECT *, COUNT(column)over (PARTITION BY column ORDER BY column ROWS 3 PRECEDING) as count FROM  `table`
) where count = 1;

-- テーブルのデータ削除　※2
DELETE FROM `table` where true;

-- 一次テーブルから上記でデータ削除したテーブルへデータの追加　※3
INSERT INTO `table` select EXCEPT(count) FROM tmp;

-- 一次テーブルの削除　※4
DROP TABLE tmp;
```

# 一時テーブルの作成※1

```SQL
SELECT *, COUNT(column)over (PARTITION BY column ORDER BY column ROWS 3 PRECEDING) as count FROM  `table`
```

ここまでたどりつくのが長かった。
下記の記事を参考にしました。
[分析関数（ウインドウ関数）をわかりやすく説明してみた](https://qiita.com/tlokweng/items/fc13dc30cc1aa28231c5)


分析関数を使って重複していたらテーブルの上からいくつ重複しているかをカウントして「count」として列を作成


例えば下記のようなテーブルを作成して

```SQL
CREATE TABLE `データセット名.test_orders` (fruits string);

insert into `データセット名.test_orders` select 'Apple';
insert into `データセット名.test_orders` select 'Apple';
insert into `データセット名.test_orders` select 'Apple';
insert into `データセット名.test_orders` select 'Apple';
insert into `データセット名.test_orders` select 'banana';
insert into `データセット名.test_orders` select 'banana';
```

下記を実行すると

```SQL
SELECT *, COUNT(fruits)over (PARTITION BY fruits ORDER BY fruits ROWS 3 PRECEDING) as count FROM  `Corporate_DataBase.test_orders`
```

下記の結果がでてきます。
ROWSの後ろの数値で前のいくつ前のレコードまで比較してカウントするかの設定が可能。
今回の場合2とか3にするとcountの結果が変わるので注意。


| fruits          |     count |  
|:---------------:|:---------:|
| Apple          |     1     |  
| Apple          |     2     | 
| Apple          |     3     |  
| Apple          |     4     |   
| Banana         |     1     |  
| Banana         |     2     |

その結果からcountが1のレコードのみで一時テーブルを作成すると下記のコードになります。

```
CREATE TEMPORARY TABLE tmp AS
SELECT * FROM(
SELECT *, COUNT(column)over (PARTITION BY column ORDER BY column ROWS 3 PRECEDING) as count FROM  `table`
) WHERE count = 1;
```

# テーブルのデータ削除　※2

```SQL
DELETE FROM `table` where true;
```

一時テーブルを作成したら元のテーブルのデータを削除します。


# 一次テーブルから上記でデータ削除したテーブルへデータの追加　※3

```SQL
INSERT INTO `table` select EXCEPT(count) FROM tmp;
```

一時テーブルから元のテーブルへデータの以降。
※1で作成してしまったcountのカラム以外を
一時テーブルから※2で作成したテーブルへデータを移します。


# 一次テーブルの削除　※4

```SQL
DROP TABLE tmp;
```

一時テーブルの削除
これなくても良い気がするのですが、ないとエラーがでるので付けています。

4回もクエリ叩くの効率悪いなぁと思っているのでもっと良い方法があれば教えてほしいです。
ReactでApollo-clientを用いてGraphQLでデータ取得するClassコンポーネント

#背景

ReactにてGraphQLでデータ取得したい、かつ、クラスベースコンポーネントをTypeScriptで実装したいが、Appolo-Client公式の[サンプルコード](https://www.apollographql.com/docs/react/development-testing/static-typing/)がどうしても動かなかったのでそのメモ。あと、細かいところがどうしてもわからなかったのでどなたかコメントくれたら嬉しいなという期待を込めて。

#この記事で書かないこと

GraphQL、React、Typescript、サーバサイドの実装について

#サンプルコード
まずはサンプルコードからお見せします。サーバサイドは、`term`という検索キーワード的な文字列を受け取って`id, title, description`のリストを返すイメージです。

```typescript:Works.tsx
import React from "react";
import { graphql, ChildProps } from "react-apollo";
import gql from "graphql-tag";

const query = gql`
  query GetWorks($term: String) {
    works(term: $term) {
      id
      title
      description
    }
  }
`;

interface Work {
  id: string;
  title: string;
  description: string;
}

interface Response {
  works: Work[];
}
type Variables = {
  term: string | undefined;
};

interface InputProps extends Variables {}

type Props = ChildProps<InputProps, Response, Variables>;

const ChildWorks = graphql<InputProps, ResWorks, Variables, Props>(query, {
  options: ({ term }) => ({
    variables: { term }
  }),
  props: ({ data, ownProps }) => ({ data, ...ownProps })
});

class _Works extends React.Component<Props, {}> {
  renderWorks(): JSX.Element[] {
    if (this.props.data) {
      const { loading, works, error } = this.props.data;
      if (loading) return [<div key={0}>Loading...</div>];
      if (error) return [<div key={0}>ERROR</div>];
      if (works) {
        return works.map(work => {
          return (
            <div key={work.id}>
              <h2>{work.title}</h2>
              <p>{work.description}</p>
            </div>
          );
        });
      } else {
        return [<div key={0}>nothing</div>];
      }
    } else {
      return [<div key={0}>loading...</div>];
    }
  }

  render(): JSX.Element {
    return <div>{this.renderWorks}</div>;
  }
}

export const Works = ChildWorks(_Works);
```

あとはコンポーネントとして利用できるので、どこかで

```typescript:App.tsx
<Work term={何かstring} />
```

としてあげれば実行できます。


#説明（可能な部分）

ResponseのTypeとVariableのType、PropsのTypeを指定しています。
InputPropsが空になっていますが、Variableに含めないがPropsとして呼び出し元から値を取りたい場合にはここに追記します。今回はProps=Variablesの前提にしているので空です。

```typescript
interface Work {
  id: string;
  title: string;
  description: string;
}

interface Response {
  works: Work[];
}
type Variables = {
  term: string | undefined;
};

interface InputProps extends Variables {}

type Props = ChildProps<InputProps, Response, Variables>;
```


optionsの部分でPropsで受け取った値をVariablesにセットしています。
propsの部分はなぜこういう記述になるのかは不明、、、どこか海外のサンプルコードから引っ張ってきたはずですがましたが、参照元のURLもすでにわからず。

```typescript
const ChildWorks = graphql<InputProps, ResWorks, Variables, Props>(query, {
  options: ({ term }) => ({
    variables: { term }
  }),
  props: ({ data, ownProps }) => ({ data, ...ownProps })
});
```

GraphQLで取得したデータは`this.props.data`からアクセスできます。

```typescript
const { loading, works, error } = this.props.data;
```

定義したReactコンポーネントそのままでは利用できず、さっき定義した`ChildWorks`でラップしてあげる必要があるらしい。クエリとクラスコンポーネントを結びつけてあげるイメージかなと。

```typescript
export const Works = ChildWorks(_Works);
```

一応、上記で動作してます。

JSXの配列をreturnする際にkeyを設定しないとWarningが出るので無理やり`key={0}`で回避しているのですが、これもどうにかできないものか。。。
Python3とSeleniumとGoogle ChromeでWebページのスクリーンショットはSelenium-Screenshotが便利です

Python 3とSeleniumとGoogle ChromeでWebページのスクリーンショットを取得する方法の１つとして、Selenium標準の ```save_screenshot``` メソッドを使う方法がありますが、この方法の場合、指定されたサイズ（ウインドウサイズ）のスクリーンショットを取得することはできますが、Webページ全体のスクリーンショットを取得することはできません。
Googleで検索してみると、色々な方法がヒットしますが、最も簡単で、かつ再利用性の高い方法は、Selenium-Screenshotパッケージを使う方法です。Selenium-Screenshotパッケージを使用すると、簡単にWebページ全体のスクリーンショットや、HTML要素を指定したスクリーンショットを取得することができます。
## インストール
### 1.Python3のダウンロードとインストール
Windowsの場合は、下記URLよりインストーラーをダウンロードしてインストールする方法が簡単です。
https://www.python.jp/
LinuxやMac, FreeBSDなどでは、パッケージマネージャからインストールします。
例えば、Ubuntu 18.04LTSの場合はちょっと古いですが（実行時にDeprecatedが出るかも知れませんが）以下が参考になるでしょう。
[Ubuntu 18.04LTSとchromium-browser(Headless)とpython3でSeleniumする](https://qiita.com/tabimoba/items/4ea3404416142187e645)
Pythonのバージョン複数分けて使いたい場合は、pythonbrewのようなvirtualenvっぽい何かを利用したり、Dockerで環境を分けるのが良いでしょう。
### 2.パッケージのインストール
seleniumと、Selenium-Screenshotパッケージをインストールします。
```
pip install selenium
pip install Selenium-Screenshot
```
### 3.ChromeDriverのダウンロード
下記URLより、自分の環境（Chromeのバージョン）に合ったChromeDriverをダウンロードします。
https://chromedriver.chromium.org/downloads
なお、Windows以外でパッケージマネージャよりSeleniumをインストールした場合は、パッケージマネージャよりChromeDriverをインストール出来る場合があります。その場合は、特別な事情（パッケージマネージャよりインストールされるものが満足に動作しない、機能が足りない等）を除き、可能な限りパッケージマネージャよりインストールされるものを使用するのが良いでしょう。
## コード例
以下はWindowsで、https://www.asahi.com/ のスクリーンショットを取得する例です。
なお、ChromeDriver(chromedriver.exe)はPythonスクリプトと同じフォルダ（ディレクトリ）にあることを、ここでは想定しています。
環境に合わせて、executable_path（ChromeDriverのパス）を変更することで、Windowsに限らず他のOSでも動作します。
```
from Screenshot import Screenshot_Clipping
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
import time
options = Options()
options.add_argument('--headless')
options.add_argument('--disable-gpu')
ob=Screenshot_Clipping.Screenshot()
driver = webdriver.Chrome(executable_path=r".\chromedriver.exe", options=options)
driver.set_window_size(1280, 720)
driver.get("https://www.asahi.com/")
ob.full_Screenshot(driver, save_path=r'.', image_name='Myimage.png')
driver.close()
driver.quit()
```
上記Pythonスクリプトを実行すると、Myimage.pngというファイル名でスクリーンショット画像が出力されます。
その画像を開くと、以下のようにWebページ全体のスクリーンショットを確認することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64876/2575ee35-9857-1a18-7c17-30ca90d297a6.png)
## 参考
- [Selenium-Screenshot(PyPi)](https://pypi.org/project/Selenium-Screenshot/)
docker上のOACISからホストマシンにジョブを投げる手順

[oacis_docker](https://github.com/crest-cassia/oacis_docker)のイメージを使ってdocker上OACISを動かしつつ、dockerを起動しているホストを計算ホストとして利用する手順についてまとめる。
ここでは手元のマシンがmacであることを前提とする。
たとえば手元のマシンのjupyter notebookとかで開発しつつ、OACISの環境構築はdockerで行う場合に有用。

以後、dockerを起動しているマシンをホストマシン、docker上で起動しているコンテナを仮想マシンと呼ぶ。

# 手順

- ホストマシン上でsshdを起動する。
    - mac OSの場合、"System Preferences" -> "Sharing" -> "Remote Login" でsshdを起動できる。
- ホストマシン上でxsubをインストールする。
    - `git clone https://github.com/crest-cassia/xsub.git`
    - `echo 'export PATH="$HOME/xsub/bin:$PATH"' >> ~/.bash_profile`
    - `echo 'export XSUB_TYPE="none"' >> ~/.bash_profile`
    - 詳細は https://github.com/crest-cassia/xsub を参照。
- docker上でoacisを起動する
    - `docker run --name my_oacis -p 127.0.0.1:3000:3000 -dt oacis/oacis`
- ホストマシン上に仮想マシンの公開鍵をコピーする。
    - `docker exec -it -u oacis my_oacis bash -lc "ssh-copy-id $USER@host.docker.internal -p 22"`
        - ホストマシンにログインするためのパスワードが要求されるので入力する。
- 仮想マシン上の".ssh/config"にホストマシンにログインするための情報を記載する。
    - `docker exec -it -u oacis my_oacis bash -lc "printf \"Host internal\n HostName host.docker.internal\n User $USER\n Port 22\n\" >> ~/.ssh/config"`
- http://localhost:3000 にアクセスしてOACISのページを開き "Hosts"->"New Host" から新しいホストを登録する。
    - Name: internal として登録する。他はデフォルト値でOK。
- simulatorをOACIS上で登録する。その際に`executable_on`で`internal`にチェックを入れる。
virtual box+Linux(Ubuntu19.04)のディスクを拡張する

Virual boxでubuntu立ててdocker使ってたらubuntu(というか仮想マシン)自体のディスクが足りなくなった。
拡張めんどい。あとでまたやるときのために記録残しとく
LVMではなく物理パーティション向け

仮想マシン > 設定 > ストレージ > コントローラー: SATAのHDDの+アイコンを押して、新規ディスクの作成
VDIを選択(元々他のファイルタイプ選んでればそれを選択) > 固定サイズ(可変サイズでもいい) > パスとサイズを入力して作成 > 処理終わったらVM起動！

fdisk -lで新ディスクのブロックボリューム名確認

```
ディスク /dev/sdb: 20 GiB, 21474836480 バイト, 41943040 セクタ
Disk model: VBOX HARDDISK
単位: セクタ (1 * 512 = 512 バイト)
セクタサイズ (論理 / 物理): 512 バイト / 512 バイト
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト
```

cat /etc/fstabで現在のファイルシステムを確認
※UUID=345dde19-65a3-4580-bbd6-3cbb16f964a3 /               ext4の、ext4がほしい情報

```
root@user-VirtualBox:~# cat /etc/fstab
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
# / was on /dev/sda1 during installation
UUID=345dde19-65a3-4580-bbd6-3cbb16f964a3 /               ext4    errors=remount-ro 0       1
/swapfile                                 none            swap    sw              0       0
```

```
root@user-VirtualBox:~# parted /dev/sdb
GNU Parted 3.2
/dev/sdb を使用
GNU Parted へようこそ！ コマンド一覧を見るには 'help' と入力してください。
(parted) mklabel gpt
(parted) mkpart
パーティションの名前?  []? newdisk
ファイルシステムの種類?  [ext2]? ext4
開始? 0%
終了? 100%
(parted) p
モデル: ATA VBOX HARDDISK (scsi)
ディスク /dev/sdb: 21.5GB
セクタサイズ (論理/物理): 512B/512B
パーティションテーブル: gpt
ディスクフラグ:

番号  開始    終了    サイズ  ファイルシステム  名前     フラグ
 1    1049kB  21.5GB  21.5GB  ext4              newdisk

(parted)
```

```
root@user-VirtualBox:~# mkfs.ext4 /dev/sdb1
mke2fs 1.44.6 (5-Mar-2019)
Creating filesystem with 5242368 4k blocks and 1310720 inodes
Filesystem UUID: 8985105d-d482-41f6-85f7-82afeba1172b
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
        4096000

Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done
```

いっぱい容量食ってるdockerイメージの置き場は/var/lib/dockerのようなので、
もともとの/var/lib/dockerを一時的にリネームして、新規にdockerディレクトリをつくって、新規パーティションをそこにマウント。dfで確認。で、そっちに元々のデータもうつす。わすれずにfstab書く

```
root@user-VirtualBox:/var/lib# mv docker _docker
root@user-VirtualBox:/var/lib# mkdir docker
root@user-VirtualBox:/var/lib# mount /dev/sdb1  /var/lib/docker
root@user-VirtualBox:/var/lib# df -h
/dev/sdb1        20G   45M   19G   1% /var/lib/docker
root@user-VirtualBox:~# vi /etc/fstab
/dev/sdb1                                 /var/lib/docker ext4    defaults        0       0
```

OS再起動してマウントされてて、dockerも普通に起動すればOK！
Hello Qiita

# はじめに
今回は Qiita アカウントを作成して初めての記事投稿となるので (何を投稿するかいろいろ悩んだのですが) Hello World のような感じで Hello Qiita としてみました．
内容としては

- 自己紹介
- Qiita の記事投稿をするに至った経緯
- 今後の投稿内容について

あたりをざっくり書いていこうかなと思います．

# 自己紹介
Multi-Agent Systems (MAS) の分野の研究をしている，情報系修士学生の tomochi-bcl と言います．

MAS とは何かというと，「自律的な主体 = Agent」と捉えて複数体の Agent における協調行動について研究する分野のことです．人工社会シミュレーションと呼ばれることもあるようです．
人工知能学会にもセッションがあるので，人工知能研究の一分野に属します．
(追記) 構造計画研究所 HP の「[MASとは？](https://mas.kke.co.jp/about/)」を見ていただくと MAS についてイメージしやすいかもしれません．

「自律的な主体」ってなんやねん…って方も多いと思いますが (私自身も初めて聞いたときには頭の中がハテナになりました) ，ロボットやコンピュータプログラム，蟻や人間なんかも「自律的な主体」として捉えられるものです．自律的に意思決定を行うオブジェクトのような概念だと考えていただければと思います ( MAS についての記事はそのうち別で出そうと思っています)

また，ベンチャー企業での長期インターンを２年前くらいからしており，Web アプリのチーム開発もやっています．
後述しますが，そこで学んだことに関する記事も投稿していきたいなと考えています．

# Qiita の記事投稿をするに至った経緯
Qiita は研究でグラフを作成する際の Python コード実装の参考にしたり，インターンで技術的な調べ物をする際に参考にしたりしていたので，割と身近なものでした．当然「確実な情報」を得るためには公式ドキュメントを読むのが正確だとはわかっていますが，よくある「調べたいけどそもそもなんて検索すればいいのかわからない」という時や「正確な情報にたどり着くためのヒントが欲しい」という時に Qiita は便利なツールだと思っています．

そんな今までは「一方的な受取手」の立場として利用してきた Qiita ですが，「情報を発信する側」も経験してみたいというのが半分，自分がやっていることを整理して記事とすることで自身の理解や考えを整理したい・深めたいという思い半分という感じで Qiita アカウントを作成するに至りました．

研究でもインターンでも，私は考えを整理するのに可能な限り思考を文字として書き出したいというタイプなので後者のモチベーションが強いかもしれません．それこそ「もし口に出して呟いていたら相当うるさいだろうな」というくらいにはいつも文字に起こしています.

論文投稿以外で自分の文章を公開するのは初めての試みなので，最初のうちは「いつものメモ書き」に近い文章になってしまうかもしれませんが，徐々に「(論文ほどフォーマルではないが) 人に読んでもらえるような文章」に近づけられるように頑張りたいです．

# 今後の投稿内容について
とりあえず投稿内容について考える上でこの辺りを参考にさせていただきました．

- [良い記事を書くためのガイドライン](https://help.qiita.com/ja/articles/qiita-article-guideline)
- [Qiitaで記事を公開するときに気を付けるべきマナーについて 〜無断でネットや書籍の内容を丸写しするのはやめよう〜](https://qiita.com/jnchito/items/215c2d51599eb29adabc)
- [Qiitaでよく見る，よくない記事](https://qiita.com/sax_/items/3c4d902fff257bf5fe66)
- [Qiitaはxxxではない](https://qiita.com/tag1216/items/4323ce146933c7892e77)
- [あなたはなぜQiitaに投稿する？](https://qiita.com/I-201/items/e86a27bb217a4123e6f9)

これから投稿を始めていこうという段階なので，これら全てにしたがって投稿内容を決める…というわけではありませんが，色々模索しながらなるべく継続的に記事投稿していこうと思っています．

今後の投稿内容についてですが，現状以下のようなものを候補として考えています．

- 研究内容についての投稿
- 研究の進め方や研究に使用しているツールについての投稿
- Multi-Agent Systems についての投稿
- 論文や技術書を読んだ際のまとめ投稿
- LaTeX 関連
- Python でのグラフ作成関連の投稿
- スライドデザインについての投稿
- インターンで学んだことの投稿

これらはあくまで候補なのでこれら全てを投稿するとも限らないし，これ以外の内容も投稿するかもしれませんが，おおよそこんな感じだと思います．
特に MAS 分野の研究を行っている身なので，MAS 系の記事を多めに書いていきたいなとは思っています．

# 最後に
Hello Qiita としては少々長くなりすぎてしまったかなと思いますが，こんな感じで今後投稿していこうと思いますのでよろしくお願いします．
Node.js と Babel で ES6

なんか、いつも、Node.js で、ちょっとコード書いて試したり、勉強がてらコード書いたりするときに、 ES6なコード書きたい時どうすんだっけ？ と悩んでしまうので、ここにメモしておきます。

実際に確認した時のそれぞれのバージョンは以下になります。

```
$ node --version
v12.14.1
$ npm --version
6.13.4
$ npx --version
6.13.4
```

あと、このメモ作成時にインストールされる Babel 関連パッケージのバージョンは、以下の通り。

```
$ grep babel package.json
    "@babel/cli": "^7.8.4",
    "@babel/core": "^7.8.4",
    "@babel/node": "^7.8.4",
    "@babel/preset-env": "^7.8.4"
```


# 作業用のディレクトリを作る 

```
mkdir work
```

# npm init を実行

```
npm init -y
```

# babel 関連をインストール

```
npm install --save-dev @babel/core @babel/preset-env @babel/cli @babel/node
```

# .babelrc を追加

```
{
  "presets": ["@babel/preset-env"]
}
```

# スクリプトを実行するには

index.js を実行するには以下のようにする。

```
npx babel-node index.js
```

# 最後に自分に向かって一言

これ、シェルスクリプトにしとけば良いよね？ > 自分
fetchPolicyをcache-and-networkにした時、毎回Loadingがtrueになる

# はじめに

apollo clientを絶賛勉強中です。間違いがあったらお教えください。

# 問題
cacheを有効にする際、`fetchPolicy`を設定する場合があると思います。`fetchPolicy`のそれぞれの違いは、[Apollo Client公式doc](https://www.apollographql.com/docs/react/api/react-apollo/#optionsfetchpolicy)から確認できます。
`cache-first`はcacheをまず見にいって、cacheになければデータを取りに行くというものです。そのため一度取ってきた情報が残り続けてしまい、画面が更新されないということが起こります。`cache-and-network`はcacheをまず見に行くところは同じですが、常にNetworkから最新のデータを持ってきてcacheに保存します。
そのため、今回`cache-and-network`を使おうと思うのですが、`cache-and-network`ではnetworkからデータを取りに行く際にLoadingがtrueになってしまい、実際にアプリで使ってみるとcacheが有効になっていない場合と差がないように表示されます。
そのため、今回はcacheがある場合はLoadingを流さず、cacheにあるデータを表示し、裏で取ってきたデータに途中で切り替わるというようなものを作りたいと思います。

# 変更前
簡単な例で今回変更する部分のコードを示します。（元のコードは[前回のQiita](https://qiita.com/kobyta/items/d21d5a0b6d06bfea8b48)で載せたもの）変更前後の差分を見てもらえればと思います。

```javascript
const COMMENTS_QUERY = gql`
  {
    commentDetail(title:"初めて利用してみた"){
      id
      comment
    }
  }
`;

export default function Comments(){
  const { loading, error, data } = useQuery(COMMENTS_QUERY);

  if (loading) return <p>Loading...</p>;
  if (error) {
    return <p>Error</p>;
  }

  return (
    <div >
      <div>comment:{data.commentDetail.comment}</div>
    </div>
  );
};
```

# 変更後
networkからデータを取ってきているかつcacheがない場合のみLoadingが表示されるように変更しました。

```javascript
const COMMENTS_QUERY = gql`
  {
    commentDetail(title:"初めて利用してみた"){
      id
      comment
    }
  }
`;

export default function Comments(){
  const { loading, error, data } = useQuery(COMMENTS_QUERY);

  if (！data && loading) return <p>Loading...</p>
  if (error) {
    return <p>Error</p>;
  }

  return (
    <div >
      <div>comment:{data.commentDetail.comment}</div>
    </div>
  );
};
```

# 終わりに
実装することはできたけども、最新のデータがcacheのものと違う場合いきなり切り替わるので、それが嫌な人は結局Loadingを表示させる方がいいのかなと思いました。


# 参考文献
以下の記事を参考にさせてもらいました。ありがとうございました。
[Set network status to 3 with cache-and-network fetch policy #1217](https://github.com/apollographql/react-apollo/issues/1217)
Wordpress サイト制作で役立った記事


##参考デザイン

###イケサイ
https://www.ikesai.com/

###WebDesignClip
https://www.webdesignclip.com/tag/wordpress/

##素材

###ぱくたそ
https://www.pakutaso.com/

###大人の素材（閲覧注意）
http://www.otonanosozai.com/

###足成
http://www.ashinari.com/category.php?blogid=2&category=265&page=1

###photo AC
https://www.photo-ac.com/

###いらすとや
https://www.irasutoya.com/

##デザイン検索

###freepik
https://jp.freepik.com/

###ODAN
https://o-dan.net/ja/

##カラーパターン

###カラー配色で迷わない！シーン別配色見本32パターン
http://www.hp-stylelink.com/news/2013/07/20130708.php#list01

##フォント

###GoogleFont
https://fonts.google.com/

##hタグ
###CSSのコピペだけ！おしゃれな見出しのデザイン例まとめ68選
https://saruwakakun.com/html-css/reference/h-design

###Lightningの見出しがカスタマイズできない理由と解決策
https://wp-firststep.com/lightning_headline_css/

##スキル
###WordPressで日本語フォントを変更するのは簡単3ステップ
https://ishidakeiichi.com/googlefont

```.css
@import url(https://fonts.googleapis.com/earlyaccess/sawarabimincho.css);

.wf-sawarabimincho {
	font-family: "Sawarabi Mincho"; }

```