OmniAICreator/Qiita-1.07M huggingface dataset:
Reduxの導入 - 簡単なサンプル -

# Reduxのインストール
~~~bash
npm install --save redux
~~~

# Reduxの実装
~~~public/index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>sample count app.</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>
~~~

~~~src/index.js
// 各種クラス、関数が利用できるようにインポート
import React from 'react';
import { render } from 'react-dom';
import { createStore } from 'redux';

// No.9「No.7」で使用しているActionCreatorを定義
const actionCreator = (count) => ({
    type: ACTION_COUNT_UP,
    payload: {
        count
    }
});

// No.7「No.6」で使用している関数のコンポーネントを定義
function CountApp({ store }) {
    const { count } = store.getState();
    return (
        <div>
            // No.8 以下のbuttonを押下すると、spanタグの中の{count}がインクリメントされるように、イベントの登録をしています。
            <span>{count}</span>
            <button value={ACTION_COUNT_UP} onClick={() => store.dispatch(actionCreator(count))}>Count Up.</button>
        </div>
    );
}

// No.4「No.3」の関数のstateの初期値を定義
const initialState = {
    count: 0
};

// No.5「No.3」で使用しているActionのtypeを定義
const ACTION_COUNT_UP = 'COUNT_UP';

// No.3「No.2」に渡すreducer（stateの更新処理）を定義
function reducer(state = initialState, action) {
    switch (action.type) {
        case ACTION_COUNT_UP:
            return {
                count: ++action.payload.count
            };
        default:
            return state;
    }
}

// No.2「No.1」に渡すstoreを作成
const store = createStore(reducer);

// No.10「No.8」のbuttonが押下されて、「3.」のreducerが実行された際、
//    renderCountApp()が実行されるようにリスナーの登録を行っています。
store.subscribe(() => renderCountApp(store));

// No.6「No.1」で実行している関数を定義
function renderCountApp(store) {
    render(
        <CountApp store={store} />,
        document.getElementById('root')
    );
}

// No.1 全体の表示処理
renderCountApp(store);
~~~
※Reactを使っているので、Reactをインストール前提のソースコードです。
　参考：[Reactの開発環境構築～Hello,World!](https://qiita.com/k-murayama/items/014e3745290208b92af1)
  
* ソースコード  
    [GitHub](https://github.com/kazuyuki-murayama/redux-01-initial)
* react-reduxの導入  
[参考](https://qiita.com/k-murayama/items/e271276ff2a22e1fec3c)
なぜ再起動した○○サーバーは〇〇サーバーのままでいられるのか

#前提
サーバー構築などやったことが初心者向け
UNIX系OSに明るくない初心者向け

#疑問
とある〇〇サーバーが再起動された。再起動されるとその〇〇サーバーとして働いているデーモンプロセスは途切れてしまいそうである。
しかし、〇〇サーバーは再起動後も〇〇サーバーであり続けることができる。
これはなぜだろうか？

#そもそもOSが起動するまで
そもそもどのようにOSは起動するのか。下記のような流れで起動しているらしい。
1. 電源が入る
2. BIOS(Basic Input Output System)というハードウェアを管理するプログラムが動く（このプログラムはもちろんROM上にある）
3. 管理されているハードウェアのうち、ブートデバイスに決められている場所から、ブートローダーというものが起動する（UNIX系OSではGRUBという）
4. GRUBからLinuxカーネルが読み込まれる
5. initプロセスというプロセス界のアダムが起動する

この5番に秘密があった。

#OSの動作モード
また、OSには電源の状態がONとOFFの二種類ではなく、ランレベルと呼ばれる動作モードが存在する。
以下はランレベルとその状態の一例。OSによって微妙に異なる。
0. システムの停止
1. シングルユーザーモード
2. 未使用
3. マルチユーザーモード(コンソールログイン)
4. 未使用
5. マルチユーザーモード(グラフィカルログイン)
6. システムの再起動

#起動スクリプト
このランレベルごとに/etc/rc.d/rcX.dディレクトリが存在する。(Xに0から6までのランレベル)
ディレクトリの配下にはK(Kill)から始まるスクリプトとS(Start)から始まるスクリプトがあり、起動時にはS始まりのスクリプトがファイル名に書かれている数字の順番に実行されていくことになる。
この中にあるスクリプトの一つが、〇〇サーバーとして働いているデーモンプロセスを起動させるスクリプトのはずである。
これらはシンボリックリンクであり、その実態は/etc/rc.d/init.dディレクトリに存在している。

このような設定によりOSが起動すると同時にデーモンも起動することが可能となっている。

なおランレベルのデフォルトは/etc/inittabで設定されている。
また、serviceコマンドで/etc/rc.d/init.dディレクトリにあるスクリプトを使うことにより、手動でデーモンプロセスの起動や停止を行うこともできる。

#余談
initはもう古い。今ではsystemdという仕組みを使うらしい。
initでは起動プロセスを順番にひとつずつ起動していく必要があるが、systemdでは並列処理をさせることも可能になっており、効率化が進んでいる。
言葉の定義やディレクトリの構造は違うが、やりたいことは同じであるようだ。
CloudflareでError502を解消する方法

##ホームページにアクセスできない問題を解消せよ。
まずは、現在の環境だが、000webhostを使っていて、これは日本で言ったら、xserverのようなポジションで、ワードプレスを簡単にインストールができて、ひとつのアカウントで、２つまで、独立サイトを作ることができる。
独自ドメインは有料だが、freenomという無料の独自ドメインレンタルをしているところがあるから、３ヶ月とかまずは借りればいいのだ。
この借りて行くと、あとで、延長できると思う。
この独自ドメインを利用すると、今度は、広告が自動挿入される問題が起こるが、それは、広告を消す　non displayのcssを使えば解消される。
ディスクは、1GB利用できて、すでに、ワードプレスとか、データーベースが入っている関係上、ほんの少し、利用されている。
92%以上は、残っている。ので、テキストベースで、記事を書いていくなら十分な量になっていくはずで、ある。
##そもそもブログに何を書くの？
ブログに書く内容だが、ここで、プロダクトローンチを使って、行く。オプトインによって、顧客リストを確保して、その後、無料のプレゼントということで、独自ブログに案内する。基本的には、記事や、動画などは全部埋め込みにすることによって、本当に使用するデーター容量は少なくてすむはず。
最近はよくインスタグラムも使っているので、インスタ埋め込みでも結構雰囲気出るかなって思う。さらにその特化型インスタにも遊びに行ってくれるかもしれないからね。

では本題に入ろう。まずは、エラーが発生している文字として、Host errorと書いているので、そこを確認しよう。

まずはpoint domainを選択して、freenomでどのようなドメイン名に設定したのか確認しよう。

この作業は、すでにドメインの登録の中で終わっていたようなので、
改めて、listwebsiteからselect domain to websiteがあるので、ここで、自分が、設定したいウェブサイト選ぶ


いったんどちらもサブドメインの流れを作っていきましょう。
cloudflareの設定方法をわすてしまったので、もう一度調べて見ようと思います。


>how to set dns subdomain in cloudflare

とかで十分でしょうね。

[ここが](https://support.cloudflare.com/hc/en-us/articles/200168756-How-do-I-add-a-subdomain-to-my-site-)わかりやすいですね。やっぱり問題を一番早く解決してくれるはオフィシャルサイトですね。
単純に次の順番で入力すればいいことがわかりました。

例だと、domain名が　example.co
subdomainとして、test.example.comとしたい場合。

| Name       |       Domain name |  
|:--|--:|
|test|example.com|

##今度の課題
httpsを含めて入力しないと、暗号通信モードにならないので、
短縮リンクを使っても自動的にこのモードにするように設定したい。
あとは、広告を消す方法　これはすでに調査済み
[Swift4] APIKitのリクエスト実行をシンプルに書く

# ビフォー&アフター

## ビフォー
```before.swift
let request = HogeRequest() // 自身で定義したリクエストの生成

Session.send(request) { result in
    switch result {
    case .success(let response):
        dump(response)
        // 色々やる
    case .failure(let err):
        print(err)
        // 色々やる
    }
}
```

個人的に感じていた問題点

- コールバックの処理が長くなってくると、全体の見通しが悪くなる
- 似たような処理を各所に何回も書く ← `Session.Send`や`Indicatorの表示`や`セッションのタイムアウト時の処理`など

## アフター
**コールバックの処理を[クロージャー](https://docs.swift.org/swift-book/LanguageGuide/Closures.html)で渡して**呼び出せるようにした。
ざっくりこんな感じ↓

```after.swift
let request = HogeRequest()
    
let prepare = {() -> Void in print("Indicatorの表示とかとか")}
let success = {(response:HogeResponse, _:HogeRequest) -> Void in 
    print("test")
    dump(response)
}
let error = {(err: SessionTaskError) -> Void in print(err)}
    
doRequest(request: request, prepare: prepare, success: success, error: error)
```

```swift
// doRequestの定義
func doRequest<T>(
    request: T,
    prepare: ()-> Void = prepare_default,
    success: @escaping (T.Response, _: T)-> Void = success_default,
    error: @escaping (SessionTaskError)-> Void = error_default) where T:Request {
    
        prepare()
        Session.send(request) { result in
            switch result {
                case .success(let response):
                    success(response, request)
                case .failure(let err):
                    error(err)
            }
        }
}

// 各クロージャーのデフォルト処理
func prepare_default(){}
func success_default<T: Request>(response: T.Response, _: T){ dump(response) }
func error_default(err: SessionTaskError){ print(err) }
```

# おわりに
もっと良い方法ありそう...アドバイス等あれば是非コメントください:pray:
プログラミング講座まとめ資料①

##はじめに
この資料は第1回プログラミング講座～第3回プログラミング講座を、まとめて復習するために作成しました。内容的には基本の基本です。

##プログラムとは？
残念ながらコンピューターは自動では動いてくれません。人間が命令を与えてあげる必要があります。そのために使うのがプログラムです。最終的にはCPUが理解できる形（機械語）に変換されます。しかしそれでは人間が理解し難いので、人間が理解しやすいプログラムであったりと多くの種類があります。（高級言語）

##アルゴリズム
アルゴリズムは問題を解決するための手段や方法のことです。プログラムを書く上で必要になってきます。アルゴリズムを改良することでプログラムの実行速度が速くなったり、処理が軽くなったりします。

##変数
例）

```cpp
int num;
int count;
float ans;
bool isNameEmpty;
double aaaiiiuuu;
```
変数はデータを格納する入れ物の役割をします。変数には2種類の要素があります。「**データ型**」と「**変数名**」です。
「データ型」はどんなデータを入れるのかを決めます。例えば「int」はintegerの略で整数型です。データ型によって格納できる値に限りがあるので、適切に型を選択する必要があります。他にも多くの型が存在します（データ型）。
「変数名」は入れ物の名前です。変数名は一部の単語（予約語）を除いて自由に決めることが出来ますが、理解しやすい名前が推奨されてます（命名規則）。

##代入演算子
例）

```cpp
num = 1;
count = 0;
ans = 1.2f;
isNameEmpty = true;
2.5 = aaaiiiuuu;    //エラー
```
入れ物を用意したら中にデータを格納する必要があります。そこで使うのが代入演算子です。「=」ですが数学のイコールの意味とは全く違います。意味は**右辺を左辺に代入**です。データ型にあったデータを格納する必要があります。型が違うとデータ型が変換されたり（型変換）、エラーが出る場合もあります。

##算術演算
例）

```cpp
num = num + 1;    //numに1足したものをnumに格納する
count++;          //count = count + 1と等価
ans = ans - 3.2f;
aaaiiiuuu / 4;    //計算のみで代入はしない
```

プログラムでも算術演算ができます。代表的なものは

|  意味 |   　構文　   |
|:-----------|:------------:|
| 加算|+|
| 減算|-|
| 乗算|*|
| 除算|/|
| 剰余|%|


です。`整数 + 少数`の計算を行った計算結果は少数になります（暗黙的型変換）。

例）

```cpp
int hoge = 1, foo = 1;
double banana = 1.2;
hoge = banana + foo;    //int型の値に変換されて格納される
banana = banana + foo;  //double型の値に変換されて格納される
```

○　整数型 = 整数型 * 整数型
○　実数型 = 実数型 + 整数型
×　整数型 = 実数型 + 整数型

なお「×」と書きましたが、あえてそのような処理をする場合もあります。計算時は**データ型**と**型変換**を意識する必要があります。これは実際にコードを書いて結果がどうなるのか確かめるのが一番理解が深まると思います。

##if文
if文は条件分岐文です。条件式が`true（真）`の時、`false（偽）`の時など条件を指定します。条件には後述の比較演算子などを使用します。
例）

```cpp
if(/*条件式*/){
    //条件式が真の時実行
} else {
    //条件式が偽の時実行
    //elseは省略可能
}
```

具体例）

```cpp
int ans = 38;
if(ans >= 60){
    //合格
} else {
    //不合格
}
```
とあったらこの場合不合格になります。


```cpp:よくあるミス
int count = 0;
if(count = 10){
    //countが10の時実行したい処理
}
```
とい言うようなプログラムを書いたとします。しかしこのプログラムは想定した動作をしません。それは条件式が「==」ではなく「=」になっているからです。どのような動作になってしまうのかは試してみるといいと思います。


##比較演算子
|  意味 |   　構文　   |
|:-----------|:------------:|
|小なり|a < b|
|小なりイコール|a <= b|
|大なり| a > b|
|大なりイコール|a >= b|
|非等価|a != b|
|等価|a == b|
主にこれらを使用します。等価は「==」なので間違えないように。



##論理演算子
|  意味 |   　構文　   |
|:-----------|:------------:|
|論理積（かつ）|&&|
|論理和（また）|｜｜|
複数の条件を指定したい場合などに使用します。これらを上手くしようすると複雑なif文もきれいに書くことができるかもしれません。言語によってはある条件を満たした時、評価がスキップされるのを利用することもあります（短絡評価）

##for文
for文は繰り返し文です。

```cpp
for(/*初期化式*/;/*条件式*/;/*変数可変式*/){
    //処理
}
```
条件式が真の間実行されます。

具体例）

```cpp
for(int i = 0;i < 10;i++){
    //処理
}
```
これはiの値が0,1,2,3,4,5,6,7,8,9と増えて行きます。`i++`は`i = i + 1`と同じ意味です。仮に5ずつ増加したい場合は`i = i + 5`もしくは`i += 5`と書きます。
C++の場合は初期化式の中で変数宣言をすることが出来ますが、授業などでC言語などを使ってる場合は、エラーが出ることがあるので注意して下さい。（ビルドしたい場合は`-std=c99,C11`などで検索してみてください）

```cpp:無限ループ
for(;;;){
    //処理
}
```
と書くと無限ループになります。他にもいろいろなfor文の使い方、応用があるので気になる人は調べて見て下さい。
Homebrewとbundleの違い

<h2 id="Rubyの開発者を目指し基礎を学んでいる:relaxed:">Rubyの開発者を目指し基礎を学んでいる:relaxed:初心者の私が知識をまとめてみました。</h2>
梅雨ですね

今日の天気 : :cloud::umbrella2:
<h2><strong>目的:</strong><h2>

<ul>
<li>自己理解</li>
<li>情報共有</li>
<li>情報整理:sweat:</li>
</ul>


<h2>
<span id="code---コードの挿入" class="fragment"></span><i class="fa fa-link"></i>What:thinking:</a>
</h2>

<p><strong>Homebrewとbundleの違いとは</strong></p>

<h2>
<span id="code---コードの挿入" class="fragment"></span><i class="fa fa-link"></i>Why:thinking:</a>
</h2>

<p><strong>r</strong>ailsではよく"bundel install"での"bundle"やgem、brewといったコマンドを使うと思います。最初は混乱してしまいます。ので、こういったものは早めに:imp:まとめるのが吉ですね。</p>


<h2>
<span id="code---コードの挿入" class="fragment"></span><i class="fa fa-link"></i>各違いについて</a>
</h2>

<p>Homebrew、通称"brew"はMacにソフトウェアをインストールしたい。といった時に使います。</p>
ちなみにhome brew  how to あたりで画像を調べると見事に🍺の作り方が出てきます。

```bash:bash
brew install google-chrome

// または

　brew cask install google-chrome
```

<p>試しにchromeをインストールして見た例ですが、"cask"をつけるのが標準？なのかな。拡張らしいので。</p>
<p>基本的にはwebサイトからよしなにchromeをインストールしているのでこういったコマンドをMac,もしくはLinux(もしくはWinなんとかさん)で実行することはないと思います。おそらくですがAppStoreでインストールできるものはbrewでインストールできるのでは？と予想しています。</p>
裏ではこういったものが走っているんだな。と理解するとかなり中身のシステムに好奇心が持てますね。</p>

<p>bundleを見て見ましょう</p>
```bash:bash
bundle install rails

// gemfileにインストールしたいgem(例えばrails)を追記した後

bundle install
```
<p>といった感じで、rubyのgem（ライブラリ）をインストールしたいよ、て時に使います。</p>



<h2>
<span id="code---コードの挿入" class="fragment"></span><i class="fa fa-link"></i>まとめ:smirk_cat:</a>
</h2>
<p><strong>ま</strong>とめますと、</p>

<ul>
<li>brewはとにかく"Mac"に何かしらインストールしたいよ。といった時に使う。</li>
<li>bundleはRubyに関するライブラリやパッケージ(gem)をインストールしたいよ。といった時に使う。</li>
</ul>
<p>といった使い分けでしょうか。あ、brewはXcodeのインストールが必要ですのでお忘れなく。</p>
<p>基本bundleはよく使うと思います。brewとかいつ使ったの？といった具合で使いませんが、Macに何かしらの環境を構築したいときに重宝する（はず）です。:hugging:</p>
Angular CLI v10でPWAを作ってみよう！

:tada: 2020/06/29 Angular CLI v10 に対応しました :tada:

2018年のng-japanでも PWA（Progressive Web App[^1]） が取り上げられましたね！
対応ブラウザも増えてきて、PWAは最近かなり注目されていると思います。

Angular CLIを使えば比較的簡単にPWAを作成できます。早速やってみましょう！

[^1]: Webアプリにネイティブアプリ並のUXを提供するもの。Googleが提唱している。

<img width="1024" alt="Angular CLI" src="https://qiita-image-store.s3.amazonaws.com/0/106886/03b12b44-140d-09e2-0c1a-723adb9dd073.png">

※ 本記事は「[Angular CLI 1.6 で PWA を作ってみよう！](https://qiita.com/puku0x/items/16f3e134dc6a425601fd)」を加筆修正したものです
※ 記事中のソース及びコマンドはAngular CLI v10系を対象としています。
※ 最終的な成果物はこちら→ https://github.com/puku0x/angular-pwa-sample

## Angular CLIのインストール

最新のAngular CLIはNode.js v10以降のみ対応しています。

https://nodejs.org

Node.jsのバージョンがv10よりも古い、または未インストールの場合は上記のページにアクセスしてインストールしてください（nvmやnodebrew等のツールを利用してもOK）。

Node.jsをインストール後、下記コマンドでAngular CLIをインストールしてください。

```shell
$ npm i -g @angular/cli
```

新しいプロジェクトを作成します。

```shell
$ ng new my-app --routing --style=scss
```

プロジェクトができたら、次のステップに向けて作業ディレクトリに移動しましょう。

```shell
$ cd my-app
```

## Service Workerを組み込む

下記のコマンドを実行してService Workerを組み込みましょう。

```shell
ng add @angular/pwa
```

プロジェクトが複数ある場合は、下記のように指定します。

```shell
ng add @angular/pwa --project=my-app
```

`@angular/pwa`を追加すると、Service Worker以外にも`manifest.webmanifest`やアイコン等、PWAとして機能させるのに必要ファイル一式が作成されます。

## App Shellを組み込む（任意）

[App Shell](https://developers.google.com/web/fundamentals/architecture/app-shell)はUIが機能するために必要な最小限のHTML/CSS/JavaScriptです。アプリ読み込み中に表示するプレースホルダーとして利用することで、アプリが起動するまでの体感スピードを上げることができます。

下記のコマンドを実行するとApp Shellが生成されます。

```shell
$ ng g app-shell --client-project=my-app
```

パスはデフォルトで`/shell`となりますが、`--route`オプションで変更可能です。

```shell:パスを変更する場合
$ ng g app-shell --client-project=my-app --route=my-path 
```

## アプリのビルド

`ng run`でビルドします。

```shell
$ ng run my-app:app-shell --configuration=production
```

## ブラウザで表示

作成したアプリを確認してみましょう。

```
$ npx node-static ./dist/my-app/browser --spa --port=9000
```

サーバ起動後、ブラウザで`localhost:9000`を開くと表示されます。

## 比較

表示速度がどれだけ改善されたか見てみましょう（[ここ](https://angular-pwa-38ba5.firebaseapp.com)からプレビューできます）。Chromeの開発者ツール等で回線速度をFast 3G等に設定すると比較しやすくなると思います。

PWA化前は↓こんな感じです。 [[ソース](https://github.com/puku0x/angular-pwa-sample/tree/old)]

<img width="983" alt="PWA化前" src="https://qiita-image-store.s3.amazonaws.com/0/106886/d9c568a5-9a06-f168-2c14-a8f1fa993468.png">

ツールバーが表示される（First Paint）まで約2000msといったところでしょうか。

App Shellを組み込むと、

<img width="983" alt="PWA化後" src="https://qiita-image-store.s3.amazonaws.com/0/106886/9f500397-05fb-16c0-c7e4-b9ff4a0fe4c0.png">

約1500msに短縮されます。

さらに、Service Workerが登録されキャッシュが有効になると、

<img width="983" alt="PWA化後（Service Workerキャッシュ有効）" src="https://qiita-image-store.s3.amazonaws.com/0/106886/44bf6e24-fcd2-34ac-2512-58080b38a8c2.png">

アイコンが表示される（First Meaningful Paint）まで含めて約500msになります。

かなり高速化できましたね :raised_hands:

## おわりに

最新のAngular CLIではPWAの実装が非常に簡単になりました。

`@angular/service-worker`については今回はキャッシュ用途のみでしたが、アプリの更新監視やプッシュ通知などもあるので今後活用していきたいところです。

皆さんもこれを期にAngularでPWAを作ってみましょう！

## 参考
https://angular.io/guide/service-worker-getting-started
https://angular.io/guide/app-shell
https://github.com/puku0x/angular-pwa-sample
入れ子になった配下のコントロールをすべて列挙する(機能強化版)

[入れ子になった配下のコントロールをすべて列挙する](https://qiita.com/albireo/items/49b7f999f4b1b431150f)をさらに改良して使いやすくしました。

<dl>
<dt>列挙するコントロールの型を指定</dt>
<dd>列挙後のキャストが不要になる上に、不要なコントロールを列挙しないことによる高速化が期待できます。</dd>
<dt>抽出条件を指定できるようにする</dt>
<dd>列挙後にさらに条件を追加して対象コントロールを絞り込むことも多いだろうから、列挙メソッド側の機能として持った方がいいかなと。</dd>
</dl>

```csharp
IEnumerable<T> GetAllControls<T>(Control ctrl, Func<T, bool> predicate = null)
  where T : Control
{
  if (predicate == null) predicate = _ => true;
  IEnumerable<T> list = ctrl.Controls.OfType<T>().Where(predicate);
  return list.Concat(ctrl.Controls.Cast<Control>().SelectMany(child => GetAllControls<T>(child, predicate)));
}
```

```csharp:使い方
//名前が"ID"で終わるテキストボックスをdisableに
foreach(var txtbox in GetAllControls<TextBox>(form, c => c.Name.EndsWith("ID")))
{
  txtbox.Enabled = false;
}

//名前が"panel"で始まるコンテナ直下のテキストボックスを非表示に
foreach(var txtbox in GetAllControls<TextBox>(form, c => c.Parent?.Name.StartWith("panel") ?? false))
{
  txtbox.Visible = false;
}
```

#WPF版(論理ツリー)
```csharp
IEnumerable<T> GetAllControls_WPF<T>(FrameworkElement element, Func<T, bool> predicate = null)
  where T : FrameworkElement
{
  if (predicate == null) predicate = _ => true;
  var childrenList = LogicalTreeHelper.GetChildren(element).OfType(FrameworkElement);
  IEnumerable<T> list = childrenList.OfType(T).Where(predicate);
  return list.Concat(childrenList.SelectMany(child => GetAllControls_WPF<T>(child, predicate)));
}
```

最近WPFいじってないのでビジュアルツリーでの列挙とか使い方はなし

####修正(6/19)
predicateを省略した場合の対応が抜けていたので修正しました。
XMLHttpRequestでJSONをPOST

#はじめに
JSONのデータをサーバーに送って処理するのにXMLHttpRequestでPOSTしてサーブレットで受け取ります。

#XMLHttpRequestでPOST
ブラウザの右クリックメニューで post json した時にデータをPOSTします。

* POSTする文字列は POST.stringify(object or array) する。
* POSTするときのヘッダーは xhr.setRequestHeader("Content-Type", "application/json")
* xhr.send(string) で送信

```javascript:background.js
browser.contextMenus.create({
    id: "name",
    title: "get name",
    contexts: ["selection"]
});

browser.contextMenus.create({
	id: "postJson",
	title: "post json",
	contexts: ["all"]
});

name = "blue";
browser.contextMenus.onShown.addListener(info => {
	getting = browser.storage.local.get("name", function (value) {
	    name = value.name;
	    console.log("getting " + name);
	});
});

browser.contextMenus.onClicked.addListener((info, tab) => {
    if (info.menuItemId === "name" ){
        console.log(name);
    } else if (info.menuItemId === "select text") {
    	let persons = [];
    	let person1 = new Object();
    	person1.name = "Satoh Taro";
    	person1.id = "123";
    	person1.mail = "taro@sample.com";
    	persons.push(person1);
    	let person2 = new Object();
    	person2.name = "Suzuki Hana";
    	person2.id = "124";
    	person2.mail = "hana@sample.com";
    	persons.push(person2);
    	let json = JSON.stringify(persons);
        console.log(json);
        var url = "http://localhost:9080/sampleWeb/TestServlet";
        console.log("start doPost");
        doPost(url, json);
        console.log("end doPost");
    }
});

function doPost(url, data) {
   console.log(url);
   var xhr = new XMLHttpRequest();
   xhr.open("POST", url);
   xhr.setRequestHeader("Content-Type", "application/json");
   xhr.onload = () => {
     console.log(xhr.status);
     console.log("success!");
   };
   xhr.onerror = () => {
     console.log(xhr.status);
     console.log("error!");
   };
   xhr.send(data);
}
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/262366/a73cc1ab-5d74-1769-d9e0-917a41538482.png)


このコードだけでうまくいくと思ったのですが、 xhr.statusの戻り値が 0 になってて動いてない、TCPモニターもとってみたのですがサーバーまでリクエストが来ていないような状況でした。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/262366/0a3c4d71-5092-c4fe-4e92-666646bda413.png)

しばらく試行錯誤して "permissions" に "http://*/*" が必要だったことがわかりました。

```json:manifest.json
{
	"manifest_version": 2,
	"name": "Sample Tool",
	"description": "Sample Tool for Firefox",
	"version": "1.0",
	"homepage_url": "https://sample.com",
	"icons": {
		"48": "icons/sample.png"
	},
	"applications": {
		"gecko": {
			"id": "sample@sample.com",
			"strict_min_version": "42.0", 
			"update_url":"https://sample.com/"
		}
	},
	"background": {
		"scripts": [
			"background.js"
		]
	},
	"options_ui": {
    	"page": "options.html"
    },
	"permissions": [
		"contextMenus",
		"storage",
		"http://*/*"
	],
	"content_scripts": [
		{
			"matches": [
				"https://qiita.com/keniooi/*"
			],
			"js": [
				"sample.js"
			]
		}
	]
}

```

200が戻ってくるようになりました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/262366/296df043-6b08-784f-9903-c5d36ee3bc1a.png)


#参考
[menus.ContextType](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/menus/ContextType)
Ubuntu Serverのcloud-imageでユーザーとパスワード設定をしてみる。

#概要
https://cloud-images.ubuntu.com/bionic/current/ を使おうとしたのに、ログインできなかった。なぜか。設定が必要だったからだ。

#環境
Ubuntu 18.04

#実践
まず、イメージをダウンロードする。

```shell:ダウンロード
wget https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-arm64.img
```

ツールのシェルスクリプトと、必要な道具を入れる。

```shell
wget https://raw.githubusercontent.com/Crazykev/backdoor-image/master/backdoor-image.sh 
chmod +x backdoor-image.sh 
#同じ階層に
wget https://raw.githubusercontent.com/Crazykev/backdoor-image/master/mount-callback-umount
chmod +x mount-callback-umount
#いらないかも
sudo apt-get install -y cloud-image-utils
```
パスワードの設定。

```shell:パスワード
sudo ./backdoor-image.sh --user ユーザ名 --password パスワード --password-auth bionic-server-cloudimg-arm64.img
```

これでできた。

#まとめ
あっさり解決できた。ところがまとまった記事がないので、迷われた方も多いと思う。
それから、このイメージの活用方法は書けたら書きたい。

#参考
https://blog.richliu.com/2017/08/31/2165/change-ubuntu-cloud-image-password
https://askubuntu.com/questions/499316/how-to-create-a-backdoor-add-a-login-to-ephemeral-images
https://bugs.launchpad.net/ubuntu/+source/cloud-utils/+bug/1741300
WSL の初期化方法

# ストアを使って
ウィンドウズメニューから初期化したい WSL を右クリックしてアンインストール。
Microsoft Store から今アンインストールした WSL を検索して、再インストール。

他より少しだけ時間がかかるものの、分かりやすい。
他より少しだけ時間がかかるとはいえど、インストール容量は小さいのでそんなにかからない。

# 設定から
`Ctrl + I` で設定を開き、
設定 -> アプリ -> distro(ie `ubuntu`) -> 詳細オプション -> リセット

![詳細オプション.png](https://qiita-image-store.s3.amazonaws.com/0/100313/3d0cec86-ddf0-b865-028d-ba1230f88d2f.png)

![リセット.png](https://qiita-image-store.s3.amazonaws.com/0/100313/1439a68a-56b4-caf0-c15b-684db5156d76.png)

GUI からの初期化としては一番妥当な気がするが、ちょっと遠い。

# wslconfig.exe を使う
[win + x] -> [i]
で PowerShell を開く。管理者ではなくて良いです。

```
PS> wslconfig /u ubuntu
```

CLI 使える人ならこれ。
Django-Celery-Redisのherokuへのデプロイがうまくできたときのメモ

#転載元ブログ情報

自分のブログからの転載です
http://k-mawa.hateblo.jp/entry/2018/06/18/235203

#コメント

Django+Celeryで非同期処理ができるようにしたDjangoプロジェクトのherokuデプロイです。公式ドキュメントだけだと（たぶん）エラーになり・・・試行錯誤の末についにできたので、その時のメモがもしかしたら他の人の役に立つかもしれないと思い投稿します。

#手順1 Procfileに追加→Redis動かすワーカー起動を指示

↓Procfile↓

```
web: gunicorn [プロジェクト名].wsgi:application -b 0.0.0.0:$PORT
worker: celery worker -A [プロジェクト名].celery -l INFO
#↑この行が追加された
#ローカルで必要だった、
#$celery -A [プロジェクト名] worker -l infoをherokuが勝手にやってくれるイメージです
```

#手順2 heroku localで動くか動作確認
```
$redis-server 
#コマンドうつ場所はどこでもOK。heroku localでredis起動は同じく必要
(仮想環境,herokuのgitコマンドを打つ場所にて僕はやってます)$heroku local
```
ここまではローカル対応のsettings.pyで動かしました。これでデプロイ下準備は完了。

ローカルで動かない時用にチェックポイントを自分なりにまとめました。もうちょっとローカル開発部分を詳しく書いています。
http://k-mawa.hateblo.jp/entry/2018/06/18/211445

#手順3 heroku-redisアドオンを追加

```
$heroku addons:create heroku-redis:hobby-dev
```
公式ドキュメントより。なおhobby-devは無料
https://elements.heroku.com/addons/heroku-redis


#手順4　アドオンが追加されたか確認

```
$ heroku redis:info
=== redis-xxxx-123456 (REDIS_URL) #仮の名前に変更してます
Plan:               Hobby Dev
Status:             available
Created:            2018-06-15 13:19 UTC
Version:            3.2.11
Timeout:            300
Maxmemory:          noeviction
Maintenance:        not required
Maintenance window: Thursdays 17:30 to 21:30 UTC
Persistence:        None
HA Status:          Unavailable
```
これはwebのherokuコンソールでも確認可能です。

#手順5 Django用のheroku-redis接続パッケージをインストール

django-redis-cacheというモジュールが必要。公式ページに記載されてました。

```
pip install django-redis-cache

pip freeze > requirements.txt
```

#手順6 settings.pyのCelery設定をデプロイ先のheroku-redisに接続されるようにする
```
#settings.pyローカルで動いた参考例(引用です)

BROKER_URL = 'redis://localhost'
CELERY_RESULT_BACKEND = 'redis'
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_ACCEPT_CONTENT = ['json']
```
引用元
https://qiita.com/seizans/items/a40952248ef2004f1d62

↓こう変える

```
#↓ここから追記↓

import os

CACHES = {
    "default": {
         "BACKEND": "redis_cache.RedisCache",
         "LOCATION": os.environ.get('REDIS_URL'),
    }
}

BROKER_URL = os.environ.get("REDIS_URL")
CELERY_RESULT_BACKEND = os.environ.get("REDIS_URL")

#↑ここまでが変更点↑

#BROKER_URL = 'redis://localhost' #localのときだけ
#CELERY_RESULT_BACKEND = 'redis' #localのときだけ
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_ACCEPT_CONTENT = ['json']
```
REDIS_URLという環境変数はheroku:redisを導入しときに勝手に設定されるようだ。

#手順7　いつものようにherokuにデプロイ

```
$git add.
$git commit -m "celery"
$git push heroku master
```

#手順8 logをとってうまく行ってるかチェック
 
```
$heroku logs -t
```

# 参考資料
公式ドキュメント"Connecting in Django"の箇所
[https://devcenter.heroku.com/articles/heroku-redis#connecting-in-python:embed:cite]

自分の完成形とちょっと違うけど、参考になりました
[https://github.com/celery/django-celery/issues/455:embed:cite]
シグモイド関数を調べる（仮）




　Pythonでシグモイド関数
$$ f(x) = \frac{1}{1+\exp (-x)} $$
について調べます。

　はじめにNumPyで実装しプロットしてみます。


```python
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

x = np.linspace(-5.0, 5.0, 100)
y = sigmoid(x)
plt.plot(x,y)
plt.show()
```
![output_3_0.png](https://qiita-image-store.s3.amazonaws.com/0/190127/a2096717-6a4b-f1ea-2d68-1fcbd277a980.png)

0から1の間で単調に増加する形状になります。

# SymPyでシグモイド関数を調べる

　関数の形を理解するためには微分をする必要があります。SymPyを使うと解析解を求めつつ簡単にグラフ化できます。


```python
%matplotlib inline
import matplotlib.pyplot as plt
import sympy as sym
sym.init_printing()
```

Jupyter notebookで数式を表示させるために、`sym.init_printing()`を実行します。シグモイド関数をプロット後、１次導関数、２次導関数を求めます。


```python
x, y, dy, ddy = sym.symbols('x y dy ddy')
y = 1 / (1 + sym.exp(-x))

sym.plotting.plot(y, (x, -5, 5))
```

![output_9_0.png](https://qiita-image-store.s3.amazonaws.com/0/190127/67ebff20-a942-c960-0a82-6d2c11e27623.png)


##1次導関数

```python
dy = sym.diff(y, x, 1)
dy
```




$$\frac{e^{- x}}{\left(1 + e^{- x}\right)^{2}}$$




```python
sym.plotting.plot(dy, (x, -5, 5))
```

![output_11_0.png](https://qiita-image-store.s3.amazonaws.com/0/190127/2c5e039e-369e-15a7-87f4-080e1183b1db.png)


##2次導関数

```python
ddy = sym.diff(y, x, 2)
ddy
```




$$\frac{e^{- x}}{\left(1 + e^{- x}\right)^{2}} \left(-1 + \frac{2 e^{- x}}{1 + e^{- x}}\right)$$




```python
sym.plotting.plot(ddy, (x, -5, 5))
```

![output_13_0.png](https://qiita-image-store.s3.amazonaws.com/0/190127/35c72646-edd5-dc34-051c-e3782dfd806d.png)
RTX830を自宅に導入してちょっとハマった話

# やりたいこと
PINGをデフォルトゲートウェイに飛ばして、Echo Replyをフィルタしないようにしたい。

# 経緯
これをどうにかしたかった。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/30037/149a8608-9fc9-0477-e54a-05d90fc89dd2.png)

keep aliveをpingでやってるので、フィルタが邪魔して「経路死んだ」って勘違いしてるRTX830ちゃんかわいい。（かわいくない）

# NW構成

PR-500KIのLANインタフェースは192.168.1.1
RTX830のWANインタフェースはDHCP固定割り当てで192.168.1.10
ルーティングは静的ルートをPR-500KI側に設定して、RTX830側にあるPCからはインターネットにつながるようになっている。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/30037/e4ca7069-2c5a-883b-fb8c-1542b5cc0a2c.png)



# 原因の特定（いろいろすっ飛ばし　眠いので許して）

```syslog notice on```
でSyslogを有効にして、パケットフィルタで何がドロップされているかを確認

``` log
2018/06/18 23:49:10: LAN2 Rejected at IN(101100) filter: ICMP 192.168.1.1 > 192.168.1.10 : echo reply
2018/06/18 23:50:11: LAN2 Rejected at IN(101100) filter: UDP 192.168.1.1:5060 > 192.168.100.3:5060
```

SIPもついでにポート開けておく

# ルールの追加
```
ip filter 101100 pass * 192.168.1.0/24 * * *
ip filter 101101 pass * * udp * 5060
```

で、こんな感じに設定する

```
ip lan2 secure filter in 101100 101101 既存ルール(おすすめ設定で入った奴ら)
```
最後に
```syslog notice off```
して、ログを出さないようにしておく。（気持ちの問題）

ステータスランプが消えた。
我が家のNW環境は平和を取り戻した。

次書くときは、たぶんWANが死んだときにサブ回線に経路切り替えするネタ。
ConfigurationManager.AppSettingsでキーがなかったらExceptionを発生させるクラスを書いてみた。

COnfigurationManager.AppSettingsって指定したキーがなくてもnullが返答されるだけどエラーにはならんのです。

そのあと、そのConfigurationを使用した処理がエラーになるかも知れないし、意図してそう動いて欲しい時もあるんだけど、逆にエラーにしたい場面もあったりします。

そういうのを簡単に切り替えられるクラスってどんな感じかなぁって考えて書いてみました。

```csharp

    public static class ConfigurationManagerRequired
    {
        static ConfigurationManagerRequired()
        {
            AppSettings = new AppSettingsRequired();
        }

        public static AppSettingsRequired AppSettings { get; }

        public class AppSettingsRequired
        {
            public string this[string keyName]
            {
                get
                {
                    if (ConfigurationManager.AppSettings.AllKeys.Contains(keyName))
                    {
                        var value = ConfigurationManager.AppSettings[keyName];
                        if (string.IsNullOrEmpty(value))
                        {
                            throw new Exception($"AppSettings key {keyName} is empty");
                        }

                        return value;
                    }
                    else
                    {
                        throw new Exception($"AppSettings key {keyName} is not found");
                    }
                }
            }
        }
    }

```

普通は

```csharp


var value = ConfigurationManager.AppSettings["key"];

```

と取得できるのですが、キーを必須にしたい場合には

```csharp

var value = ConfigurationManagerRequired.AppSettings["key"];

```

と書くと、キーが設定されていなかった場合にはExceptionが発生するようになります。
Azure VM復元 可用性セット組み込めない

Azure BackupからVMを復元すると可用性セットに組み込まれない。
サポートから提供されるPowershellもしくは自作のPowershell等で可用性セットに組み込む必要がある。

##Powershellで可用性セットに組み込むとIAMが外れる。理由は仮想マシンを再作成しているから。
【Pythonチュートリアル】制御構造ツール  4.7.5 lambda(ラムダ)式

Pythonチュートリアルより抜粋
python3.6

```py
>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
>>> pairs.sort(key=lambda pair: pair[1])
>>> pairs
[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]
```

-----

`(key=lambda pair: pair[1])`
↑()の処理をした結果、なぜ[`(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]`
この並びになるかわかりません。検索しましたが解決せず記事を投稿しました。

また、【良い記事をかくには】を確認していますが、問題があれば教えてください。
よろしくお願いいたします。
Cloud Functions for Firebase でdeploy成功してるのに実際の動作は置き換わっていなかった

## 何が起きた？

Cloud Functions for Firebase を触りながら勉強していた。動作を変えてみようと思ってコードを編集し、以下のコマンドで再びdeployした。

```sh
firebase deploy --only functions

```

以下のような出力 (一部省略) が得られたので「やったーDeployできた〜」と思った。

```sh
✔  functions: Finished running predeploy script.
i  functions: ensuring necessary APIs are enabled...
✔  functions: all necessary APIs are enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (50.52 KB) for uploading
✔  functions: functions folder uploaded successfully
i  functions: updating function {MyFunctionName}...
✔  functions[createCheckEvent]: Successful update operation.

```

動作確認してみたら「あれ？さっきと何も変わってない！(T_T)」

その後 `firebase logout` `firebase login` とかいろいろ試して再度deployするも、やはり成功するが動作は変わらない。


## 原因

以下のように違う階層のファイルをimportしていたのが原因だった。

```sh
import Hoge from "../../client/src/Hoge"

```

importしていたのは interface 定義なのだが、とりあえずimportをやめて `index.ts` に定義をコピペしたら動いた。

ただし、これは絶対に正しい対処方法ではないと思う。ひとまず直接的な原因はわかったのでここまで。

## おわりに
初めてのQiita投稿。へっぽこですが、未来の自分と願わくば誰かの助けになればいいな、と思いながらちまちま投稿していくことにします。
WSL でユーザーを作らずに root で作業する

# ユーザーを root だけにする
Microsoft ストア からインストールした後、初回起動時に

```
Installing, this may take a few minutes...
Please create a default UNIX user account. The username does not need to match your Windows username.
For more information visit: https://aka.ms/wslusers
Enter new UNIX username:
```

と新規ユーザーの名前を入力することを求められる。ここで、 `root` と入力すると

```
Enter new UNIX username: root
adduser: The user `root' already exists.
Enter new UNIX username:
```

と先に進めないが、ここで `Ctrl + C` を押すとウィンドウが閉じる。
もう一度、スタートメニューから起動すると `root` ユーザーとしてログインされた状態で起動する。

# 通常のインストール
通常、ここでユーザー名を入力するとパスワードの入力を求められ、2度同じパスワードをタイプするとインストールが完了する。

```
Installing, this may take a few minutes...
Installation successful!
Please create a default UNIX user account. The username does not need to match your Windows username.
For more information visit: https://aka.ms/wslusers
Enter new UNIX username: username
New password:
Retype new password:
passwd: password updated successfully
Use same password for root user?
Type "y" to approve, any other key to reject: y
Default UNIX user set to: username
username@HOSTNAME:~>
```
Prisma使ってHello World GraphQLサーバ

# GraphQLサーバ界の新星Prisma　と勝手に思っている

颯爽と現れ、偉いスピードでgithub stargazersが増え続けています。
ちょっと異種だけど、postgraphileと比較したら、上昇率の違いが歴然です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/96277/65b9b93f-a941-20a3-e8cd-8b1aaca1ca1e.png)

# TL;DR

```shell
# Prismaのインストール
$ npm install -g prisma

# Prisma projectの作成
$ prisma init <project name>
$ cd <project name>

# Databaseを起動
$ docker-compose up -d

# スキーマ定義に従ってデータベースを作成しGraphQLサーバを起動
prisma deploy
```

# 各自の環境によってちょっと変更するところ

生成されたディレクトリの中の設定ファイル`prisma.yml`のエンドポイントの設定を自分のdocker環境に合わせる。
最初は`localhost`になっているが、私の場合にはvirtualbox上のdockerを使っているので、IPアドレスがちょっと違うので、ここを変更します。

- 変更前

```yaml
endpoint: http://localhost:4466
```

- 変更後

```yaml

endpoint: http://192.168.99.100:4466
```

# 実行結果
```shell

$ prisma deploy
Creating stage default for service default ✔
Deploying service `default` to stage `default` to server `default` 646ms

Changes:

  User (Type)
  + Created type `User`
  + Created field `id` of type `GraphQLID!`
  + Created field `name` of type `String!`
  + Created field `updatedAt` of type `DateTime!`
  + Created field `createdAt` of type `DateTime!`

Applying changes 1.2s
```

# 出てくる画面

![image.png](https://qiita-image-store.s3.amazonaws.com/0/96277/201d8117-75bb-f1f0-6e3e-4beda62c8209.png)

GraphiQLだとスキーマ表示がドリルダウンするといちいち上書きされた記憶があるのですが、
Prisma Playgroundだと右に右にどんどんペインが増えていきますね。これいい。

### 参考

https://qiita.com/yoshi_ksk/items/6d51703f648533bdbfc8
消えない環境変数を設定する

# 環境変数がよく消える

＼＼＼SLACK用に環境変数を設定するぞ！！！／／／

```bash
export SLACK_API_TOKEN=xoxb-HOGEHOGE123456789
```
`bundle exec ruby bot.rb` ...よし、上手く動いた！！！
ターミナルを落として寝るか！！！

# ２日後のワイ将
```bash
undefined local variable or method `event' for main:Object (NameError)
```
なんやコレ...。
`export` コマンドを打っても、環境変数が`SLACK_API_TOKEN`が出てこない...。

# 原因と解決策

`~/.bashrc`、もしくは`~/.bash_profile`を開き、環境変数を追加しましょう。vimで開くとそのまま編集できるので良いと思います。私の場合は、こんなふうになっていました。

```bash:~/.bash_profile
export PATH=/usr/local/bin:$PATH
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
export PATH="$HOME/.rbenv/bin:$PATH"
export PATH=$HOME/.nodebrew/current/bin:$PATH
eval "$(rbenv init -)"
``` 

上記に`export SLACK_API_TOKEN=xoxb-HOGEHOGE123456789`を追加し、ターミナルを開き直すことで、いつでも環境変数`SLACK_API_TOKEN`を参照することができるようになりました。

環境変数はログアウト時に消えるそうなので、毎回読み込みを行う`~/.bashrc`、または`~/.bash_profile`に書いておくことで環境変数を保持することができそうです。
> 変数はターミナルからログアウトもしくはexitするまで保持

# 余談
実は環境変数を定義するshellを誤って`SLACK_API_TOKEN`とgithubにpushしてしまい、以下のようなメールがSlackから飛んできました。よく見つけたなと、逆に驚きです...。

> Your authentication tokens were found in a public code repository alongside a custom integration or bot that you (or someone with access to your token) wrote and published publicly on GitHub or a similar code-sharing site.
> あなたの認証トークンは、あなた（またはあなたのトークンへのアクセス権を持つ人）が書いたとGitHubのまたは同様のコード共有サイトに公に発表されたカスタム統合やボットと一緒に公共のコードリポジトリで発見されました。

これでそのような過ちを犯すこともなく、安心してbotが作成できるようになりますね。

## 参考
- [LINUX 修験道 - 環境変数って何なのさ？](https://linuxshugendo.wordpress.com/2013/12/26/環境変数って何なのさ？/)
- [今さら聞けない！環境変数とシェル変数の違いと定義方法](https://qiita.com/pink/items/73e712345cfabaef31e8)
React(v16.4.1)のコンポーネントライフサイクルチートシート

:writing_hand: **[The Component Lifecycle](https://reactjs.org/docs/react-component.html#the-component-lifecycle)**

<img width="949" alt="342.png" src="https://qiita-image-store.s3.amazonaws.com/0/259253/14c4951e-01ee-a7f0-761b-bb97776d8ad0.png">
[this lifecycle diagram](http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/)
AndroidスマホでNode.jsをマルチスレッド処理させてみた

ポケットの中に夢が拡がる.. .

と言う訳で、今回は[Termux](https://termux.com)を使って、AndroidにNode.js環境を構築してみます。


# 導入
## 1. アプリのインストール
[Termux - Google Play](https://play.google.com/store/apps/details?id=com.termux)
Android向けLinux実行環境。
よくあるターミナルエミュレータアプリより高機能で、感覚的にはUbuntuターミナルに近い。

[DroidEdit - Google Play](https://play.google.com/store/apps/details?id=com.aor.droidedit)
高機能テキストエディタ。
各言語のシンタックスハイライトやインデントに対応しているので便利。

## 2. Node.jsのインストール
Termuxを起動して、作業を進めます。

```shell
apt update
apt upgrade
```
`apt`が使えます。
Temux専用のパッケージリポジトリに繋がっている模様。

```shell
apt install coreutils
apt install nodejs
```
インストールはコレだけ。
Node.js以外にも、各種スクリプト言語エンジンの最新版バイナリが揃っているようです。

## 3. 動作確認
```shell
node -v
npm -v
```
Stable版がインストールされていると思います。


# 動かしてみる
Expressを使った簡易Webサーバーを書いてみます。
折角マルチコアSoCなので、`cluster`モジュールを使ったマルチスレッド処理も試す事にしました。

```shell
npm inatall -g express
```

<details>
<summary>JavaScript</summary>
<div>

```javascript:main.js
const cluster = require("cluster");
const fs = require("fs");

const express = require("/data/data/com.termux/files/usr/lib/node_modules/express");

const cpus = require("os").cpus().length;
const app = express();

const port = 8001;

if(cluster.isMaster){

  console.log("node.js test app");
  console.log("Listen: " + port);

  for(let i = 0; i < cpus; i++){
    cluster.fork();
  }

  cluster.on("fork", (worker)=>{
    console.log("Starting Worker ID: " + worker.id);
  });

  cluster.on("exit", (worker, code, signal)=>{
    console.log("Worker " + worker.id + " is died");
  });
}

else if(cluster.isWorker){

  app.get("/", (req, res)=>{
    console.log("Request from: " + req.connection.remoteAddress);

    res.setHeader("Content-Type", "text/html");
    res.send(fs.readFileSync("./index.html"));

    console.log("Processing Worker ID: " + cluster.worker.id);
  });

  app.listen(port);
}
```
</div></details>
<details>
<summary>HTML</summary>
<div>

```html:index.html
<!DOCTYPE html>
<html>
  <head>
    <title>Node.js on Android!</title>

    <style>
      body {
        margin: 0;
        padding: 0;
        width: 100%;        
      }
    </style>

    <script>
      document.getElementById("bar").click = ()=>{
        const text = document.getElementById("foo").value;
        alert(text);
      }
    </script>
  </head>

  <body>
    <input type="text" id="foo"></input>

    <button id="bar">
      Click Here
    </button>
  </body>
</html>
```
</div></details>

```shell
node main.js
```
![Screenshot_20180618-203334.png](https://qiita-image-store.s3.amazonaws.com/0/253070/38fc3a7f-9399-a952-4b8d-78b5962cf1f1.png)

Chromeで`localhost:8001`に接続すると、無事にページが表示されました。
ターミナルではWorkerが6個走ってるのが確認できます。
3回ほどページリロードしましたが、Requestが毎回別のWorkerに割り当てられている事も確認できました。

今回使用したスマートフォンはSM-G930Fで、Exynos8890は8コアですが、恐らくkernelの電力コントロール絡みで、使用可能コアは6個と判断されるようです。

# まとめ
動いたからと言って、今すぐ世界が変わる訳では無いですが...
今までPCでしか出来なかった事が、だんだん掌の上で出来るようになっていくの、とてもワクワクしますね。

活用案ゆるぼ、と言う事で締めたいと思います。
それではまた。
TensorFlowを勉強してみた

#【TensorFlowとは】
###■参考リンク
[オープンソースのAI・人工知能／TensorFlowとは](https://www.ossnews.jp/oss_info/TensorFlow)

---

###■概要
Googleが開発した機械学習のOSSのこと。多次元データ構造を流れるように処理し、Deeplearningを行う。</br>
Core部分はC++で実装されていて、**Pythonのインターフェース**が用意されている。</br>
利用方法例としては、画像に写っているものを認識して文章化するアルゴリズム、各種数値計算、自然言語処理などの応用分野がある。

---
#
###■特徴
TensorFlowの特徴としては、データフローグラフによる柔軟性、ローレベルオペレータも手書きできる汎用性、高いパフォーマンス、スケーラビリティ、研究レベルから実productまで扱える効率性がある。
</br>

---
#
####具体的に・・・
* データフローグラフ
<br>TensorFlowの処理は、データフローグラフの「構築」＋「実行」の2フェーズで行われる。
* Deep Flexibility（深い柔軟性）<br>
柔軟にNeuralNetworkを構築することができる。C++で低位レベル処理を書くことも可能。
* True Portability（真の携帯性）<br>
CPU用/GPU用でコードを分ける必要がない。移植性も優れている。
* 簡易/柔軟な記述方式<br>
シンプルかつわかりやすいコーディング記述でできます。**自動微分の機能が内蔵されており、計算処理と目的関数を定義するだけで学習できる。**
* WebIF「TensorBoard」<br>
WebIFで学習状況確認、NeuralNetworkの可視化ができる。

---
#
###■利用用途
利用用途として以下が上げられる。
* 顔認識
* 音声認識
* 画像検索
* 画像認識から文章化するアルゴリズム
* 各所数値計算
* 自然言語処理
* 検索最適化
* メール自動返信
* 自動運転
<brなど>

---
#
###■Download
####[Downloadリンク](https://www.tensorflow.org/install/)

---
#【TensorFlowのインストール】
###MacOSにインストールしてみた
* Homebrewのインストール（済みのためコマンド省略）<br>
　　　↓
* pyenv-virtualenvのインストール（済みのためコマンド省略）<br>
　　　↓
* Python 3.5.2をインストール（済みのため・・・）<br>
　　　↓
* Python 3.5.2のTesorFlow用の環境作成<br>

```console:console
$ pyenv virtualenv 3.5.2 TensorFlow
$ pyenv rehash
```

---

* 作成した環境へ切り替え<br>

```console:console
$ pyenv global TensorFlow
```

（確認・・・）

```console:console
$ python -V
```

　　　↓
* pipのインストール（済みのため・・・）<br>
　　　↓
* TensorFlowのインストール<br>

```console:console
$ pip install --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.9.0-py3-none-any.whl

```

　　　↓
* Pycharmのインストール<br>
[リンク](https://www.jetbrains.com/pycharm/download/)からインストール

---

#【TensorFlow】でPythonを書く
Python勉強で躓いたところ

Pythonの導入からサンプル勉強までで躓いたところ

□アジェンダ
　１　導入
　２　Anaconda失敗
　３　Pythonもくもく会
　４　個人勉強


□１．導入
　▽Pythonインストールについて
　　バージョン：Python3.6
　　パッケージ：anaconda
　　その他入れたApp：PythonLauncher,IDLE
　▽手順
　　以下リンク等を参考にインストール（基本はhomebrew）
　　<a href="https://qiita.com/crankcube@github/items/15f06b32ec56736fc43a">『MacOSとHomebrewとpyenvで快適python環境を』</a>
　　<a href="http://develtips.com/python/191">『【超初心者向け】MacにPython 3をインストールする方法+アンインストール方法』</a>
□２．Anaconda失敗
　▽まず初めに・・・
　　Anacondaは不要！
　　後に環境を好き勝手いじるために仮想環境を用いるのだが、anacondaを入れるとPATHが書き換わるので、毎度切り替える（やり方は色々ある）必要がでてきてかなり面倒。
　　しかも、特にAnaconda環境で開発する予定がなければAnacondaの恩恵を受けることができないので尚更不要かと。
　▽Anaconda不要話やpyevn不要説について
　　<a herf="https://qiita.com/shibukawa/items/0daab479a2fd2cb8a0e7">『pyenvが必要かどうかフローチャート』</a>
　　<a herf="https://qiita.com/t2y/items/dd6d7f9c70ac2b8a79da">『Anaconda は Environment Isolation Tool (環境分離ツール) ではない』</a>
□３．Pythonもくもく会
　▽ Python入門者向けハンズオン #6

　▽ハンズオン概要
　　○Python言語入門
    * Pythonについて(スクリプトの書き方/型/制御構文/fizzbuzzやってみる)
    * 標準モジュールについて (re, os, sysなどの紹介)
    * サードパーティパッケージ (pipの使い方)
　　○スクレイピング
    * スクレイピング (requestsの使い方/BeautifulSoup4の使い方/サイトをスクレイピングする)
　▽Python Q&Aについて
　　<a herf="https://teratail.com/questions/search?q=python&conditions=and">terarails</a>というtech系yahoo!知恵袋的なＱ＆Ａサイトがある。
　　※運用団体
　　　teratails（テラテイルズ）
　▽内容色々
　【Pythonの概要】
    ▼テキスト
        https://github.com/pynyumon/pynyumon/blob/master/1_python_basics.md
    ▼内容（メモ）
        仮想環境（venv）
            開発プロダクト別に開発環境を作成するのに最適な機能
            $ python3 -m venv （仮想環境名）
                ※anacondaのpythonをインストールしている場合は
                https://teratail.com/questions/87368?sip=n0070000_019&uid=79904
    ▼備考（anaconda環境と通常python環境を分ける）
           http://d.hatena.ne.jp/isobe1978/20140310/1394437846


□４．個人勉強
【Oracle】SQL集

### ディレクトリオブジェクトの作成

```sql
CREATE DIRECTORY ディレクトリオブジェクト名 AS 'ディレクトリ名'
```

### エクスポート

```sql
expdp USER_NAME/PASSWORD@SERVICE_NAME DIRECTORY=DIRECTORY_NAME DUMPFILE=DIRECTORY_NAME:FILE_NAME.dmp
LOGFILE=DIRECTORY_NAME:LOGFILE_NAME.log
```   

- オプション 
COMPRESSION=[ALL | DATA_ONLY | METADATA_ONLY | NONE]
  - ALL
  - DATA_ONLY
  - METADATA_ONLY
  - NONE

- DataPumpジョブの進捗状況を確認する

```sql
select * from user_datapump_jobs
```

### インポート

```sql
impdp USER_NAME/PASSWORD@SERVICE_NAME directory=DIRECTORY_NAME dumpfile=DIRECTORY_NAME:FILE_NAME.dmp
logfile=DIRECTORY_NAME:LOGFILE_NAME.log
```

- オプション
 - logfile
     - 未指定の場合、import.log がディレクトリオブジェクトのパスに出力される。
 - query
     - 条件を指定してインポートする
     - QUERY=TABLE_NAME:\"WHERE 条件"\
 - table_exists_action
     - TRUNCATE
     - REPLACE
     - APPEND
 - content
     - METADATA_ONLY
     - ALL
     - DATA_ONLY
 - execlude
     - 特定のオブジェクトだけを除外可能。
     - emp テーブルのみ除外： 「 exclude=TABLE:\”LIKE \’EMP%\’\” 」
     - インデックスのみ除外： 「 exclude=INDEX 」
 - include オプション
     - 特定オブジェクトだけをインポート可能。
     - インデックスのみインポート：「 include=INDEX 」

### impdpの停止方法
  - 処理実行中にCtrl + C
  - その後 Import > となるので
    - ジョブの停止：stop_job
    - ジョブの再開：start_job
    - ジョブの状態確認：status
    - ジョブの完全停止：kill_job
Reactで追加ノード無しで複数要素をreturnする

:writing_hand: **[Fragments](https://reactjs.org/docs/fragments.html)**

```jsx:普通にやるとトップレベルは1つしか返せないので変なノードができがち
import React, { Component } from "react";

const Tabledata = props => {
  return (
    <div>
      <td>{props.col1}</td>
      <td>{props.col2}</td>
    </div>
  );
};

class Table extends Component {
  render() {
    return (
      <table>
        <tbody>
          <tr>
            <Tabledata col1="silence suzuka" col2="special week" />
          </tr>
        </tbody>
      </table>
    );
  }
}

export default Table;
```

<img width="500" alt="ss.png" src="https://qiita-image-store.s3.amazonaws.com/0/259253/d08577b5-740a-7562-b506-7cee27847962.png">

```jsx:そんな時はReact.Fragmentを使う
const Tabledata = props => {
  return (
    <React.Fragment>
      <td>{props.col1}</td>
      <td>{props.col2}</td>
    </React.Fragment>
  );
};
```

<img width="500" alt="2.png" src="https://qiita-image-store.s3.amazonaws.com/0/259253/c1a72002-d280-82f6-e81c-75c71fcb175a.png">

```jsx:一応ショートハンドもある、けど現状だとその他ツールが追いついていないのでReact.Fragment使っとけばよさそう
const Tabledata = props => {
  return (
    <>
      <td>{props.col1}</td>
      <td>{props.col2}</td>
    </>
  );
};
```

```jsx:因みにarrayみたいな渡し方でもいけるそう
const Tabledata = props => {
  return [<td>{props.col1}</td>, <td>{props.col2}</td>];
};
```
[GAS]音声入力で雑に食費を計算したい。

#やったこと
やったことはiPhoneからGoogle Assistant+IFTTT+GAS+GoogleSphreadSheetを用いて、
今日の昼飯、夕飯で使ったお金を音声で入力し、スプレッドシートに記録するだけ。
もし入力するのに失敗してもその日のうちだったら上書き出来ます。

#ソースコード
これがコードワニ🐊

```GASのソース.
var sphreadSheetId = "スプレッドシートのID";
var sheetName ="シート名";

function doPost(e) {
  
  // スプレッドシートファイルを開く
  var sphreadSheet = SpreadsheetApp.openById(sphreadSheetId);
  
  // シートを取得する
  var sheet = sphreadSheet.getSheetByName(sheetName);
  
  // 今日の日にちを取得する
  var dateData = new Date();
  var dateCompSourceString = Utilities.formatDate(dateData,"JST","yyyy/MM/dd");

  // 検索範囲を設定する（データの入力された最終行を取得したいものである・・・）
  var searchRange = 100;

　// 検索範囲文繰り返す  
  for(var i = 2; i < searchRange; i++)
  {
    // セルの日付をYYYY/MM/DDの文字列で取得する
    var dateCompDestString = Utilities.formatDate(sheet.getRange(i,1).getValue(),"JST","yyyy/MM/dd");
  
    // 日付を比較する
    if(dateCompSourceString == dateCompDestString)
    {
      // 日付が合っていれば、現在のセルの右隣の昼飯列に数値を入れる
      sheet.getRange(i,2).setValue(e.postData.getDataAsString());
    }
  }
  
}

```

スプレッドシートはこんなやつ

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/211061/f51672b6-1ca6-e5a9-07f7-c12ed0fd4c1a.png)

IFTTTの設定はこんなやつ

```IFTTT.
+this:Google Assistant(Say a Phrase with a number)
What do you want to say?:昼飯 #
Language:Japanese

+that:webhooks(Make a web request)
URL:GASのURL
Method:POST
Content Type (optional):text/plain
Body (optional):{{NumberField}}
```

#所感
・Google Assistantの設定なのか入力時に頭に「OK Google」が必要。なので、「OK Google 昼飯 500」のように音声入力するワニ🐊
・日にちの比較に手間取りましたワニ。このあたりの記事を参考にさせてもらいましたワニ🐊
https://jjnurburg.com/newdate/
https://macprimary.white-doll.net/?p=289
・夜飯は昼飯の右隣ワニ。GASファイルは分けましたワニ。Webhookの設定で分岐できそうな気がするワニ🐊
【jQuery3.3.1】壊れた画像を"noimage.jpg"に差し換える Level①インラインでonerrorを使う

#誰に向けて
- 壊れた画像のあつかいがわからない人
- イベントハンドラのことがわからない人
- JavaScriptの実行順序について、あまり理解していない人

#経緯
「壊れた画像をno imageに差し換える」

単純に見える作業ですが、
めちゃくちゃハマりました。

けもの道を作る気持ちで、連載します。

#サンプルのHTML

```html:broken_image.html
<html>

<head>
    <style type="text/css">
        div {
            width: 150px;
            height: 150px;
            border: 1px solid;
        }

        img {
            max-width: 100%;
            max-height: 100%;
        }
    </style>
</head>

<body>
    <!--存在しない画像-->
    <div>
        <img src="http://google.com/hogehoge.jpg" />
    </div>
    <div>
        <img src="http://google.com/fugafuga.jpg" />
    </div>
    <!--存在する画像-->
    <div>
        <img src="https://3.bp.blogspot.com/-rNmXJXzt8DQ/VsPnSNB6MzI/AAAAAAAA4Dw/GOIgFy4n2ls/s180-c/music_sakkyoku_piano_man.png"
        />
    </div>
    <div>
        <img src="https://2.bp.blogspot.com/-lAIFjv3ejHg/WEztKOlwR-I/AAAAAAABAUU/d9sJUl9xolIAaodsAHmZQFVj_7wkqpSmQCLcB/s400/ai_music.png"
        />
    </div>

</body>

</html>
```

|表示結果|
|---|
|![image.png](https://qiita-image-store.s3.amazonaws.com/0/228301/e5bfcdb3-1375-d2c3-940f-1dc5da571c3e.png)
|

上の2枚の画像が壊れているので、
直したいですね。

試行錯誤スタートです！！

#Level①インラインでonerrorを使う

```html:broken_image_onerror.html
<html>

<head>
    <style type="text/css">
        div {
            width: 150px;
            height: 150px;
            border: 1px solid;
        }

        img {
            max-width: 100%;
            max-height: 100%;
        }
    </style>
</head>

<body>
    <!--存在しない画像-->
    <div>
        <img src="http://google.com/hogehoge.jpg" onerror="this.src='https://placehold.jp/150x150.png?text=NoImage'"
        />
    </div>
    <div>
        <img src="http://google.com/fugafuga.jpg" onerror=" this.src='https://placehold.jp/150x150.png?text=NoImage'"
        />
    </div>
    <!--存在する画像-->
    <div>
        <img src="https://3.bp.blogspot.com/-rNmXJXzt8DQ/VsPnSNB6MzI/AAAAAAAA4Dw/GOIgFy4n2ls/s180-c/music_sakkyoku_piano_man.png "
        />
    </div>
    <div>
        <img src="https://2.bp.blogspot.com/-lAIFjv3ejHg/WEztKOlwR-I/AAAAAAABAUU/d9sJUl9xolIAaodsAHmZQFVj_7wkqpSmQCLcB/s400/ai_music.png "
        />
    </div>

</body>

</html>
```

|表示結果|
|---|
|![image.png](https://qiita-image-store.s3.amazonaws.com/0/228301/491fba4d-8f7a-4ade-3bcc-e4dd35538a7d.png)
|

壊れた画像がnoimageに変わりました。
これで、最低限対応できそうです。

#この方法の問題
壊れた画像に決め打ちで`onerror`を指定していくのは、
現実的ではありません。

じゃあすべての`<img>`タグに`onerror`を指定するかというと、
それも気が遠くなる話です。

そもそも、HTMLにインラインでscriptを記述するのは非推奨としている現場が多いです。
理由は、大きくわけて以下の2点です。

##①外部Scriptが予期せぬ動きをする原因になる
`<img>`タグをつかんでなにか操作する外部のScriptを読み込んでいる場合、
タグ内のScriptが悪さをすることがあります。

いつどこでどの要素にどんな操作が行われているのか追うのが困難になるので、
なるべく避けたほうが無難です。

##②変更を加えづらい
ソース内にべったりコードを書いてしまうと、
変更を加えるときに困難です。

「noimageの画像を変えたい」
と思ったときに、他のページのHTMLも全て書き換えることになります。

それはちょっと。。。ですよね。

#次回
Level② 「onerror」を使う
です。

2018/06/19追記
書きました！
https://qiita.com/konkipiano/items/4ddf3bdc74cef138b22e
Windows10でcdコマンドの一部が使えなくなった？

一般にディレクトリ移動で使われるコマンドは2通り挙げられる．

例：Eドライブへ移動する際のcdコマンド
(1)

```
>cd e:
```

(2)

```
>cd /d e:
```

Windows10 Version 10.0.17134.112のコマンドプロンプトでは，(1)が使えなかった．(2)しか受け付けない．

※(1)を使うと"E:\"と表示は返ってくるが，カレントディレクトリが変化しない．念の為pwdコマンドで確認しても変化なし．

以前から使えなかったのか，最近使えなくなったのか…どちらにせよディレクトリ移動だけで時間を取られた．
Cordova の Camera プラグインで画像を取得したが向きがおかしい

# iOS が画像の exif をいい感じに解釈してくれる話

[cordova-plugin-camera](https://github.com/apache/cordova-plugin-camera) でカメラで画像を撮ろうとしたところ、iOS でだけ変な向きに画像が回転してしまいました。。。

しかも Canvas に描画して`rotate()`しても反映されない始末。

調べてみたところ、画像の exif を Safari が解釈したりしなかったりするので、
画像が回転するとか。

参考: [iPhoneからアップロードしたJPEG写真が横向きになる問題(EXIF, Orientation)
](https://qiita.com/RichardImaokaJP/items/385beb77eb39243e50a6)

# RTFM

`navigator.camera.getPicture()`の第３引数に次のオプションを指定してやります。

```javascript
navigator.camera.getPicture(
    function success(img){},
    function error(){},
    {
        correctOrientation: true
    }
);
```

これで画像が回転しなくなります。exif を設定しなおしているのか、削除しているのかはチェックしていません。

# 教訓

**Canvas でゴリゴリ回す前にマニュアル読もうね！**