OmniAICreator/Qiita-1.07M huggingface dataset:
【初心者向け】インクリメンタル型の開発について

こんにちは！

私は業務系SEで3年働いた後、WEB系に転職して、半年くらい経ちました。
業務系時代はウォーターフォール開発に携わることが多くて、アジャイル開発の考え方にはまだ慣れておらず、この記事を書くに至りました。

本記事ではWEBサービスを含めたアジャイル開発に強いと言われる「インクリメンタル型開発」について、書いていきます。

本記事の対象：プログラミング初心者

## インクリメンタルって何？
インクリメンタル(incremental)を辞書で調べたところ
「ますます増加する」「徐々に増加する」などの意味があるようです。
「少しずつ増えていく」というイメージで良いのかなと思います。

## インクリメンタル開発とは？
初めに最も単純で、動作する骨組みを作成します。

そして、骨組みが決まったら、少しずつ肉付けをして完成形に近づけていきます。

一気に完成させようとするのではなく、最低限の機能から作成していくようなイメージです。

言葉だけで説明するのは難しいので、以下に具体例を示したいと思います。

## インクリメンタル開発の概念を掴むための具体例
こんなプログラムを作りたいとします。

ユーザーが商品の税抜き価格を入力すると、税込み価格を表示（アラート）する
※JavaScriptで実装

例なので、細かすぎるくらい分けて書いていきます。
あくまでイメージとして、捉えてください。

#### ステップ１ まずは税込み価格を表示するロジックを記述する
```javascript
alert(`330円`);
```
最初から動的に表示させようとせず、シンプルに固定値で表示させます。

#### ステップ２　次に税込み価格を変数に置き換えてみる
```javascript
let taxIncludedPrice = 330;
alert(`${taxIncludedPrice}円`); //330円
```
まずはalertの税込み価格を変数に置き換えました。

#### ステップ３　税込み価格を算出するロジックを追加

```javascript
let taxExcludedPrice = 300;
let taxIncludedPrice;
let tax = 1.10;

taxIncludedPrice = taxExcludedPrice * tax;
alert(`${taxIncludedPrice}円`); //330円
```
税抜き価格と税率から税込み価格を算出できるように変更しました。

#### ステップ4　税抜き価格をユーザーの入力した値に変更する
```javascript
let taxExcludedPrice = prompt('商品の税抜き価格を入力してください', 0);
let taxIncludedPrice;
let tax = 1.10;

taxIncludedPrice = taxExcludedPrice * tax;
alert(`${taxIncludedPrice}円`); //n円 nはユーザーの入力値
```
ユーザーが入力した値から税込み価格を算出し、表示するようになりました。

#### ステップ5　入力値のバリデーション処理を追加する
今のままだと、ユーザーが数値以外を入力した場合、「NaN円」とおかしな値が表示されてしまいます。
エラー時の処理を記述していきます。

```javascript
let taxExcludedPrice = prompt('商品の税抜き価格を入力してください', 0);
let taxIncludedPrice;
let tax = 1.10;

if (isNaN(taxExcludedPrice)) {
	alert('エラー：数値を入力してください'); //入力値が数値以外の時
} else {
	taxIncludedPrice = taxExcludedPrice * tax;
	alert(`${taxIncludedPrice}円`); //n円 nはユーザーの入力値
}
```
条件文を追加して、数値以外の場合はエラーメッセージが表示されるように変更しました。

**このように最初は単純な処理を記述し、少しずつ肉付けをしていくイメージです。
※実務ではもっと大きな単位で切り分けて、コーディングしていくと思います。**

### まとめ
インクリメンタル開発のイメージはなんとなく掴めたでしょうか？
名前は聞いたことないけど、既に実践している方もいらっしゃると思います。
実務ではもっともっと複雑になると思いますが、なるべくシンプルに考えていけるようにしたいですね。

### 参考文献
[インクリメンタルな開発](https://www.kushiro-ct.ac.jp/yanagawa/ex-2015/2-game/05.html)
[Code Complete 第2版](https://www.nikkeibp.co.jp/atclpubmkt/book/yy/071300043/)
一部分だけ文字の色変更　（アニメーションあり）

#タイトルの文字を部分的に変更

[![Image from Gyazo](https://i.gyazo.com/15119a1fc4e39b524d46f6d285c0c827.gif)](https://gyazo.com/15119a1fc4e39b524d46f6d285c0c827)

####アニメーションを付与しているタイトルの`おすすめ`のみ色変更


```index.html
<div class="popular__header">
  <h2 class="main-title tween-animate-title">
   おすすめ作品
  </h2>
  <p class="sub-title tween-animate-title">
   愛読歴20年の独断と偏見（TOP5）
  </p>
</div>
```


```_base.scss
.popular {
  margin-bottom: 80px !important;

  .main-title {
    .char:nth-child(1) { color: aqua; }
    .char:nth-child(2) { color: aqua; }
    .char:nth-child(3) { color: aqua; }
    .char:nth-child(4) { color: aqua; }
  }

```

nth-childを使用し、文字を指定し変更できた。

アニメーションがあるタイトルには、spanタグで`おすすめ`を囲うやり方をしてもうまくいかなかった。


```css
<h2>
<span>おすすめ</span>作品
</h2>
```
rake db:migrate で ArgumentError: Unknown validator: 'UniqunessValidator'

sinatraでの開発中、
`reke db:migrate`で
`ArgumentError: Unknown validator: 'UniqunessValidator'`が出た時の原因と対処

###解決策

uniqnessvlidator?そんなの知らないよ！的な事書いているので、
対応してるモデルに、先に書いててたバリデーションを一旦消しました!


```user.rb
class User < ActiveRecord::Base
#  validates :email, presence: true, length: {maximum: 255 },
#    format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i },
#    uniquness: { case_sensitive: false }
#  has_secure_password
end
```

これで`rake db:migrate`を実行で、そしたらマイグレートされました！


####よくよく見ると、、、

uniquenessのeが抜けてる！！！

```user.rb

    uniquness: { case_sensitive: false }

```
タイプミスには注意ですね、、、
chocolateyでnodeを入れるとnpmが管理者権限の時しか実行できない問題

# 困ったこと
<!-- 発端や概要を記載 -->
・npmコマンドが管理者権限でしか使えない！
背景として、chocolateyでnvmを入れてnode.jsやnpmをインストールした。
-[管理者としてコマンドを開いたときだけnpmが認識される](https://teratail.com/questions/190899)


<!-- 各チャプター -->
<a id="#Chapter1"></a>
# 結論
・システム環境変数のpathを編集して、nvmのpathを直接通す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/623093/a69dc7aa-a5b8-41c3-9548-2a4afaa9b143.png)


<a id="#Chapter2"></a>
# 原因
・chocolateyでnvmをインストールするとシステム環境変数の設定が以下のようになる
・%NVM_HOME%はシステム環境変数内に設定した変数NVM_HOMEを呼び出しているが、これがシステム環境変数内にあることから管理者権限でしかアクセスすることができない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/623093/014cc900-0813-b5a7-451e-6b451eb9f8ce.png)

# 解決方法
・管理者モードでpowershellを起動して下記のコマンドを実行してシステム変数が編集できるようにする

```言語名:管理者権限powershell
Start C:\Windows\system32\rundll32.exe sysdm.cpl, EditEnvironmentVariables 
```
-[たった2手で管理者権限でシステム環境変数がいじれないを対処する](https://www.lisz-works.com/entry/sys-env-admin)

 

・変数に書いてあるパスを確認後、管理者権限なしで使いたいコマンドのpathをシステム環境変数またはユーザー環境変数に直接書く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/623093/8bf06861-6c69-9da4-4aec-ced8fecce568.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/623093/84cc7fd7-0dce-ba7f-d8eb-cc1422880804.png)

さいごに、vscodeでpowershellを実行している場合は、エディタを再起動させることをお忘れなく。

<a id="#reference"></a>
# 参考文献
-[管理者としてコマンドを開いたときだけnpmが認識される](https://teratail.com/questions/190899)
-[たった2手で管理者権限でシステム環境変数がいじれないを対処する](https://www.lisz-works.com/entry/sys-env-admin)
homebrewのインストールに失敗した時

# homebrewをインストールする
```zsh
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
```

```zsh
Cloning into '/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core'...
fatal: unable to access 'https://github.com/Homebrew/homebrew-core/': LibreSSL SSL_read: SSL_ERROR_SYSCALL, errno 54
Error: Failure while executing; `git clone https://github.com/Homebrew/homebrew-core /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core` exited with 128.
Error: Failure while executing; `/usr/local/bin/brew tap homebrew/core` exited with 1.
Failed during: /usr/local/bin/brew update --force
```

...ん？

# brew doctor してみる

```zsh
$ brew doctor

==> Tapping homebrew/core
Cloning into '/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core'...
remote: Enumerating objects: 40, done.
remote: Counting objects: 100% (40/40), done.
remote: Compressing objects: 100% (27/27), done.
error: RPC failed; curl 18 transfer closed with outstanding read data remaining
fatal: the remote end hung up unexpectedly
fatal: early EOF
fatal: index-pack failed
Error: Failure while executing; `git clone https://github.com/Homebrew/homebrew-core /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core` exited with 128.
Error: Failure while executing; `/usr/local/bin/brew tap homebrew/core` exited with 1.
```

やっぱり普通にcloneに失敗してるっぽい？

# 解決
```zsh
$ git clone https://github.com/Homebrew/homebrew-core /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core --depth=1

Cloning into '/usr/local/Homebrew/Library/Taps/homebrew/homebrew-core'...
remote: Enumerating objects: 5370, done.
remote: Counting objects: 100% (5370/5370), done.
remote: Compressing objects: 100% (5151/5151), done.
remote: Total 5370 (delta 53), reused 355 (delta 10), pack-reused 0
Receiving objects: 100% (5370/5370), 4.43 MiB | 25.00 KiB/s, done.
Resolving deltas: 100% (53/53), done.
Updating files: 100% (5390/5390), done.

$ brew doctor
Your system is ready to brew.
```

OK!

---
macOS Catalina 10.15.4
git version 2.24.2 (Apple Git-127)
自分のすべてのデバイスから、Office365アカウントを強制サインアウトする

以前、管理者が対象アカウントを強制サインアウトさせるべく、[Office365ユーザーを強制サインアウトする](https://qiita.com/hisssa0102/items/99f1c4b32ca8c06b1d8e)をまとめてみました。

今回は、「自分が」サインインしているすべてのデバイスからサインアウトさせるべく、手順をまとめてみた。ファーストラインワーカーとかで共有デバイスを使っている場合などで「あれ、サインアウトしたっけな・・・」というとき、管理者に連絡するまでもなく自分でサインアウトできるようになります。




#ユーザーが自分で「すべてからサインアウトする」
ここにアクセス。
https://myaccount.microsoft.com/

それから、すべてからサインアウトをクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237698/4205fc1b-7b55-3278-ee7f-f14ddb3ac097.png)

確認を求められるので、OKをクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237698/28de8ed0-f3c1-3aad-5415-6f36bea39908.png)

おしまい！

すべてからサインアウトなので、この操作をしているブラウザからもサインアウトされます。

#簡単にアクセスするには？

URLなんて覚えられないよね・・・。

というわけで一番簡単なのは、ブラウザ右上の顔をクリックして、マイアカウント。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237698/0f643c69-a455-36c9-a618-86e1d4d3acb3.png)

自分のサインイン履歴見る方法も、以前[Office365のサインイン履歴をユーザーが自分で確認する方法](https://qiita.com/hisssa0102/items/3ed0d4e7e34f76b1db3d)にてまとめましたが、同じくマイアカウントから確認できます。

#参考資料


マイ アプリ ポータルでプロファイルとアカウントの情報を更新する - すべての場所からサインアウトする
https://docs.microsoft.com/ja-jp/azure/active-directory/user-help/my-apps-portal-end-user-update-profile#sign-out-of-everywhere
No compatible servers were found - MySQL

MySQLのインストールでこけたので備忘録。

現象：認証周りの設定ができないまま完了してしまう(使えない)。

解決策：以下画像の時にExecuteボタンを押下し、インストール完了してからNextボタン押下する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630191/82139b59-e68b-90d1-ae0a-144e7e697195.png)
kubernetesのクライアント設定(masterに別VMからアクセスする方法)

## k3sの構築
研究室でkubernetesの構築を行う機会があり, 研究室内のサーバにUbuntu VMを3つ建ててそこに
k3sosを入れて環境の構築を行いました. 
masterとworkerの構築設定は, 下記のリンクに全て書いてあるのでそちらを参照してください. 
https://github.com/rancher/k3s#quick-start---install-script

#### k3sos基本構成
- vcpu 2
- RAM 4GB
- HDD 50GB

基本構成は, 上記のようになっていますが公式でNode数に応じたCPU, Memoryのスペックがありますのでそちらを参照にしてください. 今回はmasterノード1台, workerノード2台の計3台での構築なので10台までのスペックを参照した構成になっています. 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502802/174fa2ad-0d06-3f41-4724-acf4fdac6cb1.png)


https://rancher.com/docs/k3s/latest/en/installation/installation-requirements/

## k3sのクライアント設定
k3sを構築したのですがmasterへのアクセス方法の設定のやり方が特になく, k3sの場合だと$home/.kube/configが無かったりと少し戸惑う部分があったのでやり方を書いていきたいと思います. 

#### 手順
1. クライアントとしてmasterにアクセスするVMにkubectlをインストール

公式ドキュメントを参考にkubectlのインストールを行ってください. 
https://kubernetes.io/ja/docs/tasks/tools/install-kubectl

2 クライアントにコンテキスト(.kune/config)を作成
下記のQiita記事が分かりやすかったので参考にさせていただきましたm(__)m
[kubectlコマンドの使い方(1.4)](https://qiita.com/hana_shin/items/b7a947511a89accea6d4)

```
#cdslというユーザを作成
sudo kubectl config set-credentials cdsl --username=cdsl --password=cdsl user "cdsl" set.
#クラスタの作成
kubectl config set-cluster cluster --insecure-skip-tls-verify=true --server=http://master:8080
#コンテキスト(context_cdsl)を作成し, ユーザ(cdsl)とクラスタを結びつける
kubectl config set-context context_cdsl --user=cdsl --cluster=cluster
```
.kune/config内は書き換えるので特に中身は気にしていません

3 クライアントの.kube/configの設定をmasterの設定に変更し, アクセス先のIPを指定

k3sの設定は, /etc/rancher/k3s内にありk3s.yamlの設定をクライアントの.kube/configに書き換えます. 

```.kube/config
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: ＜クラスタ認証のための鍵データ＞
    server: https://<masterのIP>:6443
  name: default
contexts:
- context:
    cluster: default
    namespace: <使用するnamespace>
    user: default
  name: default
current-context: default
kind: Config
preferences: {}
```

ここでアクセスするmasterのIPアドレスをserver部分に記述するだけで基本的なクライアントからの接続設定は終了です. ですがアクセスするnamespaceやuserなどは適宜設定を個人で行うようにしてください.
いつも困るのは、キャッチ(catch)


キャッチしてもいいけど、それをユーザに見せてもね。。

ログに落とすならいいけど
キャッチしてるってことは、　どうにか　わかりやすく　ユーザにも　噛み砕いて　教えないと
ってことでしょ？

いろいろと、キャッチのメッセージが困るのですです。
.gitattributes の設定を適用してマージ

# `.gitattributes` の設定を適用してマージ

[git に登録済みのファイルの改行コードを正規化する](https://qiita.com/m-tmatma/items/cfff9f2c60a26fde802d) という記事を書きましたが、`.gitattributes` の設定を行った後、`git add --renormalize .` した後、それを適用していないブランチに対してマージするとマージに失敗してしまいます。

以下のように `-X renormalize` を指定してマージすることにより、`.gitattributes` の設定を再適用してマージすることができます。

```
git merge -X renormalize マージするブランチ名
```

## 参考リンク

* [git に登録済みのファイルの改行コードを正規化する](https://qiita.com/m-tmatma/items/cfff9f2c60a26fde802d) 
* [git-merge - Join two or more development histories together](https://git-scm.com/docs/git-merge)
* [MERGE STRATEGIES](https://git-scm.com/docs/git-merge#_merge_strategies)
* [Ubuntu Git その227 - Recursiveマージストラテジーとは（git merge）](https://kledgeb.blogspot.com/2015/06/ubuntu-git-227-recursivegit-merge.html)
Splunkで直近の繰り上げ時間を作る

小ネタ
Slackで投稿したので忘れないうちに

```sql:move_up_time.spl
index=_internal | head 100
| stats min(_time) as start max(_time) as end
| appendpipe [ eval time=relative_time(end,"+1h@h")]
| eval _time=coalesce(time,start)
| makecontinuous _time span=1h
```

| start | end | _time | count | time |
|--:|--:|:--|--:|--:|
|   |   | 2020/07/23 20:00:00.000 |   |   |
| 1595503130.524 | 1595503142.065 | 2020/07/23 20:18:50.523 | 1 |   |
| 1595503130.524 | 1595503142.065 | 2020/07/23 21:00:00.000 | 2 | 1595505600.000000 |

`bin`や`makecontinuous`は直近の時間は作ってくれる。この場合は*count*が`null`のところ。
だけど、繰り上がった時間は作ってくれない。

`addinfo`が使えるかなと思ったけど、検索期間が**全時間**だと*info_min_time*が`0`で*info_max_time*が`+infinity`だった:sweat:

`appendpipe`は直前の結果から、引き続きクエリーを追加できるので、この場合は使い勝手がよかった。

ステータスの変化を`timechart`するときなどは使うかもしれません。
ESP32にmicropythonを入れる方法（uPyCraftを使います）

# esp32でmicropython使えるようにします（簡単！）
なんか色々なサイトでごちゃごちゃしているけど，これ使えば一瞬だった．（体験者は語る）

# まずファームウェアをダウンロード
[micropythonのホームページ](https://micropython.org/download/esp32/)から最新のファームウェアをダウンロードします．
![a9a46579f3833e263401e91a53cf2c81.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459889/eeff46f4-102c-80b3-1753-4e345adcd5b4.png)


こちらの**Firmware built with ESP-IDF v3.x, with support for BLE, LAN and PPP:**の中から選択します
- esp32-idf3-20200715-unstable-v1.12-623-gf743bd3d2.bin
    - 現時点で最新
    - unstable版なので，動作不安定の可能性あり
-  esp32-idf3-20191220-v1.12.bin
    - 現時点で安定版としての最新

今回は後者の安定板を入れます👍

# 実はESP32+micropython用のIDEがある
$$uPyCraft$$
いやこれ本当にすごくて，ファームウェアのインストールからファイル転送から実行から何から何までできちゃう優れモノなんです！本当なんです！
![religion_keiji_woman.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459889/54e643f0-7a78-b9ac-c4de-3711e0827ae7.png)


### ひとまずダウンロード
[こちらから](https://randomnerdtutorials.com/install-upycraft-ide-windows-pc-instructions/)どうぞ

### 開きます
![4b37068e4076ad04382c11776c063d1e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459889/d2d8f5ce-dc24-fa45-bd00-1c5bfec3d37a.png)

こういう画面があれば大正解です👍

### シリアルポートを確認します
![519823737bcbb011406fcaa216ba58d1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459889/6e2b8b89-8217-7422-167a-baddba7c2726.png)

Windowsになってしまうのですが，デバイスマネージャーを開きます．
そして確認するべきは・・・
![136b003375379e96c67de900b4af4582.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459889/d3a45c43-0f1e-913f-e37a-fe866ab75970.png)

こ↑こ↓！！

自分の場合はCOM5に接続されていました．
※当然COM4，COM3の場合もありますので各自で確認しましょう

### ファームウェアをインストールします
![f582018339a5006da84542bac6eba1fb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459889/b8082dae-8dce-d2e4-7a48-23ebfc853819.png)


Tools
↓
Serial
↓
COM5 (デバイスマネージャーで確認したポートに設定します)

そうすると，以下のような画面が開きます．（初回限定版）
![39c185192d05041680453ff78b997f74.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459889/248a2e43-e517-16d7-5f13-84b0f57cc0d7.png)


上記のように設定します


| 項目 | 設定 |
| -------- | -------- | 
| board     | esp32     |
| bum_addr | 0x10000 |
| erase_flash | yes |

そして重要なのは**Firmware Choose**で，まずUsersにラジオボタンを設定し
**chooose**から先ほどダウンロードしたファームウェアを選びます（ダウンロードフォルダとかから持ってきます）
中にxxxxx.binというのが設定できればOKです👍


あとはOKを押してインストールが完了するのを待ちましょう

### 成功
うまくいくと下にコマンドプロンプトが開きます👍
![8e9e638a772de9f8a799a7f72a2860a5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459889/bf45de82-39d1-7202-4f84-b576824b63a0.png)


せっかくですので何かうってみてください
```python
　>>> print("Hello esp32")
Hello esp32
```

これで設定は完了です👍👍👍👍👍
お疲れ様でした！
![message_otsukaresamadesu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459889/95db33ab-337c-f00d-3d63-57122d03cf18.png)
エネルギーハーベスティング

応用情報技術者令和元年秋期 午前問22

エネルギーハーベスティングの適用例として，適切なものはどれか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/19f84f7d-d488-a992-95ba-4cfd289d8c68.png)

まずは、ハーベスティングは、やはり収穫ですね。
収穫というのは、別の力から、収穫して、電力に転換するとのこと。
素晴らしいものですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/f1af4c48-17e0-8b18-0573-224c144b93f0.png)
Jupyter labの拡張機能(Variable inspector)がインストール済みなのに動作しない（Uninstalled core extensions）

日本語ではこのバグについて見つけられず時間がかかってしまったので一応記録しておきます。

#症状
jupyterlabの拡張機能の一つであるVariable inspectorがインストール済みにも関わらず機能しなくなった。具体的には、通常タブ内で右クリックすると"Open Variable inspector"が出てきて開くことができるのだが、その文字すら一向に出てこなくなってしまった。jupyterlabの再インストール,バージョンの変更、Variable inspectorのアンインストールなど行ってみたが全く効果なし。
環境:macOS,zsh,pip

以下を行うとjupyterlabのインストール済みの拡張機能が見られる。

```
$ jupyter labextension list
```

```
JupyterLab v2.0.1
Known labextensions:
   app dir: /Users/ユーザ名/.pyenv/versions/3.8.3/share/jupyter/lab
        @lckr/jupyterlab_variableinspector v0.5.1  enabled  OK

Uninstalled core extensions:
    @lckr/jupyterlab_variableinspector
```
インストール済みのはずなのになぜかuninstalldになってしまっている。

#僕はこれで直りました
調べてみるとどうやらbuild_config.jsonというログファイル？が悪さしてるらしい。開いてみます、

```
$ open /Users/ユーザ名/.pyenv/versions/3.8.3/share/jupyter/lab/settings/build_config.json
```


```build_config.json
{
    "uninstalled_core_extensions": [
        "@lckr/jupyterlab_variableinspector"
    ]
}
```
見つけた。

build_config.jsonファイルを削除して、もう一度

```
$ jupyter labextension list
```
実行すると、buildをお勧めされるので、指示に従ってbuildする。

```
$ jupyter lab build
```

```
$ jupyter labextension list
JupyterLab v2.0.1
Known labextensions:
   app dir: /Users/ユーザ名/.pyenv/versions/3.8.3/share/jupyter/lab
        @lckr/jupyterlab_variableinspector v0.5.1  enabled  OK
```
uninstalldは無事なくなってjupytarlab再起動後無事Variable inspector復活。
おそらくバグ。何がきっかけでこうなったのかがわからなかったから怖かったです。

#参考
以下の記事にもいろいろ書いてあります。
https://discourse.jupyter.org/t/extension-shows-up-as-both-installed-and-uninstalled-and-doesnt-work/2688/3
https://github.com/krassowski/jupyterlab-lsp/issues/203
React初心者覚書05 - 条件付きレンダー

React初心者覚書05 - 条件付きレンダー

[Reactの記事](https://ja.reactjs.org/docs/conditional-rendering.html)を参考に初心者がわからないことと、なんとなく理解したかも？のメモを書いてなんとか理解しようとしています。

### 条件付きレンダー

- Reactでは必要なふるまいをカプセル化した独立したコンポーネントを作ることができる

- （わからないこと、componentDidMount() は変わらず呼び出されていると書いてあったが、
どうやって確認したらいいんだろう？と思ったら、greeting.jsの次に書いてあった！ありがたい。codepenにソースがあるおかげでわかるけど、説明文だけだったら自分にはわからない、、

```greeting.js
function UserGreeting(props){
  return <h1>Welcome back!</h1>;
}
function GuestGreeting(props){
  return <h1>Please sign up.</h1>;
}

function Greeting(props){
  const isLoggedIn = props.isLoggedIn;
  if(isLoggedIn){
    return <UserGreeting />;
  }
  return <GuestGreeting />;
}

ReactDOM.render(
// Try changing to isLoggedIn={true}:
  <Greeging isLoggedIn = {false} />,
  document.getElementById('root')
);

```

- 下記のconstructorにある、this.handleLoginClick.bind(this);は何をしているんだろう
初期化でLoginControlのhandleLoginClickメソッドはthisをバインドしている？？
- handleLoginClickメソッドは、LoginControlの機能を引き継いでいるという理解でいいんだろうか？
- LoginControlクラスの中のrender()の動きが未だぱっと理解できない。

- この部分　Reactの形式？で関数書く時に引数にpropsを入れて、
LoginControlの中のrenderで条件分岐している？


```LoginButton(props)部分.js
function LoginButton(props) {
  return (
    <button onClick={props.onClick}>
      Login
    </button>
  );
}
```


```LoginControl.js
class LoginControl extends React.Component{
  //constructor
  constructor(props){
    super(props);//必須
    this.handleLoginClick = this.handleLoginClick.bind(this);
    this.handleLogoutClick = this.handleLogoutClick.bind(this);
    this.state = {isLoggedIn: false};//初期化時にログアウトしている
  }

  handleLoginClick(){
    this.setState({isLoggedIn: true});
  }
  handleLogoutClick(){
    this.setState({isLoggedIn: false});
  }

  render(){
    const isLoggedIn = this.state.isLoggedIn;
    let button;

    if(isLoggedIn){
      button = <LogoutButton onClick={this.handleLogoutClick} />;
    }else{
      button = <LoginButton onClick={this.handle:oginClick} />;
    }

    return(
      <div>
        <Greeting isLoggedIn = {isLoggedIn} />
        {button}
      </div>
    );
  }
}

function UserGreeting(props){
  return <h1>Welcome back!</h1>;
}

function GuestGreeting(props){
  return <h1>Please sign up.</h1>
}

function Greeting(props){
  const isLoggedIn = props.isLoggedIn;
  if(isLoggedIn){
    return <UserGreeting />;
  }
  return <GuestGreeting />;
}

function LoginButton(props){
  return(
    <button onClick={props.onClick}>
    Login
    </button>
  );
}
function LogoutButton(props){
  return(
    <button onClick={props.onClick}>
    Logout
    </button>
  );
}

ReactDOM.render(
  <LoginControl />,
  document.getElementById('root')
);

```
ESP32をWifiに接続する方法

# Wifi繋げてしまう（簡単！）
ESP32をWifiに接続する方法を以下に記します
![bowling_alley.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459889/03b6628a-a7a2-b711-6617-8832c0dec002.png)


```python
SSID_NAME = "SSID"
SSID_PASS = "PASS"

import utime
import network

def connect_wifi(ssid, passkey, timeout=10):
    wifi= network.WLAN(network.STA_IF)
    if wifi.isconnected() :
        print('already Connected.    connect skip')
        return wifi
    else :
        wifi.active(True)
        wifi.connect(ssid, passkey)
        while not wifi.isconnected() and timeout > 0:
            print('.')
            utime.sleep(1)
            timeout -= 1
    
    if wifi.isconnected():
        print('Connected')
        return wifi
    else:
        print('Connection failed!')
        return null

wifi = connect_wifi(SSID_NAME, SSID_PASS)
if not wifi :
    sys.exit(0)
```

変数**SSID_NAME**にはSSID名を，変数**SSID_PASS**にはSSIDのパスワードを入れてください

最後に`Connected`と表示されれば接続完了です

本当はパスワードなどはソースコード上に入れるべきではないのだと承知していますが，今回はWifiに接続できればいいのでご容赦ください(__)

## 起動時に自動的にWifiにつなげたい！
上記のプログラムをboot.pyに入れてあげればOK👍
Rust: sqlite3 のデータを削除 (Delete)

フォルダー構造

```text
$ tree -L 2
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
    └── debug
```

```text:Cargo.toml
[package]
name = "sqlite3_delete"
version = "0.1.0"
edition = "2018"

[dependencies]
rusqlite = "*"
```

```rs:src/main.rs
// --------------------------------------------------------------------
/*
	sqlite3_delete/src/main.rs

					Jul/23/2020
*/
// --------------------------------------------------------------------
use std::env;
use rusqlite::{params, Connection, Result};

// --------------------------------------------------------------------
fn main() -> Result<()> {
	eprintln! ("*** start ***");

	let args: Vec<_> = env::args().collect();
	let file_sqlite3 = &args[1];
	let key = &args[2];

	eprintln!("{}",file_sqlite3);
	eprintln!("{}",key);

	let conn = Connection::open(file_sqlite3).unwrap();

	let sql_str = "delete from cities where id = '".to_owned() + key + "'";

	conn.execute(&sql_str,params![],)?;

	eprintln! ("*** end ***");

	Ok(())
}

// --------------------------------------------------------------------
```

実行

```text
$ cargo run /var/tmp/sqlite3/cities.db t0716
    Finished dev [unoptimized + debuginfo] target(s) in 0.92s
     Running `target/debug/sqlite3_delete /var/tmp/sqlite3/cities.db t0716`
*** start ***
/var/tmp/sqlite3/cities.db
t0716
*** end ***
```
大量に取ったスクリーンショットの名前を変更するのがめんどうだったのでPythonで変更した

#目的
Macを使っています。スクリーンショットを20枚くらい保存しましたが、それぞれ「スクリーンショット 年月日時刻.png」という名前で保存されます。
これをまとめて「~~001.png」のようにしたかったため、Pythonで以下のプログラムを書きました。

#概要
```sh
python 本ファイル 'A' 'B' N
```
A:変換するファイル一覧。ワイルドカードを使う(例：*.png)。
B:変更後ファイル名。拡張子は継承される(出力：B001.png)。
N:連番の開始番号（整数値）。何もいれないと0から開始する。

ファイルのソートは名前順です。
Bはクオーテーションで囲わなくてもいいですが、Aはクオーテーションで囲ってください。

#ソースコード
何かあったときのために、27行目をコメントアウトしています。外してください。

```Python
import os, glob, sys, pprint
args = sys.argv

# とりあえず、Aでヒットしたファイルを出力する
dirlist = sorted(glob.glob(args[1]))
pprint.pprint(dirlist)

#Nの確認
count = 0
if len(args) >= 4:
    count = int(args[3])

#出力例の表示と「本当に変更しますか?(y/n)」
ext = dirlist[0][dirlist[0].rfind('.')+1:]
ncount = '{0:03d}'.format(count)
print('change to {}{}.{} ... ? (y/n)'.format(args[2],ncount,ext))
S = input()
if S != 'y':
    exit()

#実際にファイル名を変更
for i, name in enumerate(dirlist):
    ext = name[name.rfind('.')+1:]
    ncount = '{0:03d}'.format(count+i)
    hdir = name[0:name.rfind('/')+1]
    newname = '{}{}{}.{}'.format(hdir,args[2],ncount,ext)
    # os.rename(name, newname)
    print('change {} to {}'.format(name,newname))
```
Accept-Language の順序を真面目に処理する

## Accept-Language とは何か

HTTPには Accept-Language というリクエストヘッダがある。

 - [Accept-Language - HTTP | MDN](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Accept-Language)

私の場合、以下の値が設定されている。

```
ja,zh-CN;q=0.9,zh;q=0.8,en-US;q=0.7,en;q=0.6,zh-TW;q=0.5
```

Webサイトが複数の自然言語に対応している場合、このヘッダを見てどの言語で表示するか決める訳だが、上の例だと、

 1. 日本語(ja)
 2. 大陸中国語(zh-CN)
 3. 中国語(zh)
 4. アメリカ英語(en-US)
 5. 英語(en)
 6. 台湾中国語(zh-TW)

の順序を指定したことになる。Accept-Language ヘッダからこの順序を導くプログラムを書いてみる。

## 雑な実装

優先順位は各言語タグ(zh-CN などの部分)の後ろにある ``q=0.9`` のような**重み**で決定するのが正しいのだが、多くのブラウザではこの部分を無視しても解釈を間違えないよう言語タグをソートした状態でAccept-Languageヘッダの値としている。なので、雑な実装としては言語タグの登場順をそのまま優先順位とすればよい。

```.js
function acceptLanguage(header) {
    return header.match(/[a-z][\w-]+/g);      // 言語タグだけ取り出す
}
```

## 真面目な実装

けれどこのやり方は以下のようなヘッダには使えない。

```
 zh-TW ; q = 0.8 , en-US;q=0.9,en;q=0.90, ja,zh-CN,zh  
```

先のものと優先順位は同じなのだが、重みで並び替えが必要な上に、重みの値に同じものがあり、その場合は先に出てきたものを優先しなければならない(ですよね)。さらには許されそうな箇所には空白文字を挿入している。

このような場合でも正しく優先順位を得れるよう、真面目に実装してみた。JavaScriptの ``sort()`` は安定ではないらしいので、バケツソートを使いました。

```.js
function acceptLanguage(header) {

    let bucket ={};                                 // バケツソートの器
    header = header.replace(/^\s+/g,'').replace(/\s+$/,'');
                                                    // 前後の空白を捨てる
    for (lang of header.split(/\s*,\s*/)) {         // , で分割
        let [ key, value ] = lang.split(/\s*;\s*q\s*=\s*/);
                                                    // ;q= でキー・バリューに分割
        value = +(value || 1);                      // バリューのデフォルト値は 1
        if (isNaN(value)) continue;                 // 数値でない場合はスキップ
        if (! bucket[`${value}`]) bucket[`${value}`] = [];
        bucket[`${value}`].push(key);               // バケツに入れる
    }
    let rv = [];                                    // バケツソートして優先度を得る
    for (let q of Object.keys(bucket).sort((x,y)=>(+y)-(+x))) {
        rv = rv.concat(bucket[q]);
    }
    return rv;
}
```
Rust: sqlite3 のデータを更新 (Update)

フォルダー構造

```text
$ tree -L 2
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
    └── debug
```

```text:Cargo.toml
[package]
name = "sqlite3_update"
version = "0.1.0"
edition = "2018"

[dependencies]
rusqlite = "*"
chrono = "0.4"
```

```rs:src/main.rs
// --------------------------------------------------------------------
/*
	sqlite3_update/src/main.rs

					Jul/23/2020
*/
// --------------------------------------------------------------------
use std::env;
use rusqlite::{params, Connection, Result};
use chrono::{Local, Date};

// --------------------------------------------------------------------
fn main() -> Result<()> {
	eprintln! ("*** start ***");

	let args: Vec<_> = env::args().collect();
	let file_sqlite3 = &args[1];
	let key_in = &args[2];
	let population_in = &args[3];

	eprintln!("{}",file_sqlite3);
	eprintln!("{}",key_in);
	eprintln!("{}",population_in);

	let date_mod: Date<Local> = Local::today();
	println!("{}", date_mod);

	let conn = Connection::open(file_sqlite3).unwrap();

	let sql_str = "update cities set population = ".to_owned()
		+ population_in + &", date_mod = '".to_owned()
		+ &date_mod.to_string()
		+ &"' where id = '".to_owned() + key_in + "'";

	eprintln!("{}",sql_str);

	conn.execute(&sql_str,params![],)?;

	eprintln! ("*** end ***");

	Ok(())
}

// --------------------------------------------------------------------
```

実行

```text
$ cargo run /var/tmp/sqlite3/cities.db t0713 3512600
    Finished dev [unoptimized + debuginfo] target(s) in 1.24s
     Running `target/debug/sqlite3_update /var/tmp/sqlite3/cities.db t0713 3512600`
*** start ***
/var/tmp/sqlite3/cities.db
t0713
3512600
2020-07-23+09:00
update cities set population = 3512600, date_mod = '2020-07-23+09:00' where id = 't0713'
*** end ***
```
Rust: sqlite3 のデータを読む (Read)

フォルダー構造

```text
$ tree -L 2
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
    └── debug
```

```text:Cargo.toml
[package]
name = "sqlite3_read"
version = "0.1.0"
edition = "2018"

[dependencies]
rusqlite = "*"
```

```rs:src/main.rs
// --------------------------------------------------------------------
/*
	sqlite3_read/src/main.rs

					Jul/23/2020
*/
// --------------------------------------------------------------------
use std::env;
use rusqlite::{params, Connection, Result};

#[derive(Debug)]
struct City {
	id: String,
	name: String,
	population: i32,
	date_mod: String,
}

fn main() -> Result<()> {
	eprintln!("*** start ***");

	let args: Vec<_> = env::args().collect();

	let file_sqlite3 = &args[1];

	eprintln!("{}",file_sqlite3);

	let conn = Connection::open(file_sqlite3).unwrap();

	let mut stmt = conn.prepare("SELECT id, name, population, date_mod FROM cities")?;
	let city_iter = stmt.query_map(params![], |row| {
		Ok(City {
			id: row.get(0)?,
			name: row.get(1)?,
			population: row.get(2)?,
			date_mod: row.get(3)?,
		})
	})?;

	for city in city_iter {
		println!("{:?}", city.unwrap());
	}

	eprintln!("*** end ***");

	Ok(())
}

// --------------------------------------------------------------------
```

実行

```text
$ cargo run /var/tmp/sqlite3/cities.db
    Finished dev [unoptimized + debuginfo] target(s) in 0.50s
     Running `target/debug/sqlite3_read /var/tmp/sqlite3/cities.db`
*** start ***
/var/tmp/sqlite3/cities.db
City { id: "t0711", name: "郡山", population: 38415, date_mod: "1956-5-15" }
City { id: "t0712", name: "会津若松", population: 57926, date_mod: "1956-6-8" }
City { id: "t0713", name: "白河", population: 98123, date_mod: "1956-8-17" }
City { id: "t0714", name: "福島", population: 63259, date_mod: "1956-1-21" }
City { id: "t0715", name: "喜多方", population: 21748, date_mod: "1956-9-12" }
City { id: "t0716", name: "二本松", population: 51924, date_mod: "1956-7-5" }
City { id: "t0717", name: "いわき", population: 97125, date_mod: "1956-9-12" }
City { id: "t0718", name: "相馬", population: 63219, date_mod: "1956-3-22" }
City { id: "t0719", name: "須賀川", population: 25781, date_mod: "1956-11-30" }
*** end ***
```
Rust: sqlite3 のデータを作成 (Create)

フォルダー構造

```text
$ tree -L 2
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
    └── debug
```

```text:Cargo.toml
[package]
name = "sqlite3_create"
version = "0.1.0"
edition = "2018"

[dependencies]
rusqlite = "*"
```

```rs:src/main.rs
// --------------------------------------------------------------------
/*
	sqlite3_create/src/main.rs

					Jul/23/2020
*/
// --------------------------------------------------------------------
use std::env;
use rusqlite::{params, Connection, Result};


// --------------------------------------------------------------------
fn insert_proc(conn:&Connection,key:&'static str,name:&'static str,population: i32,date_mod:&'static str) -> Result<()> {

	conn.execute(
		"INSERT INTO cities (id,name, population,date_mod) VALUES (?1,?2,$3,$4)",
		params![key.to_string(),name.to_string(),population,date_mod.to_string()],
	)?;

	Ok(())
}

// --------------------------------------------------------------------
fn main() -> Result<()> {
	eprintln! ("*** start ***");

	let args: Vec<_> = env::args().collect();
	let file_sqlite3 = &args[1];

	eprintln!("{}",file_sqlite3);

	let conn = Connection::open(file_sqlite3).unwrap();

	conn.execute(
		"drop table cities",
		params![],
	)?;

	conn.execute(
		"CREATE TABLE cities (
			  id	VARCHAR(10) PRIMARY KEY,
			  name	TEXT NOT NULL,
			  population	INTEGER,
			  date_mod	VARCHAR(20)
			  )",
		params![],
	)?;


	let _ = insert_proc(&conn,"t0711","郡山",38415,"1956-5-15");
	let _ = insert_proc(&conn,"t0712","会津若松",57926,"1956-6-8");
	let _ = insert_proc(&conn,"t0713","白河",98123,"1956-8-17");
	let _ = insert_proc(&conn,"t0714","福島",63259,"1956-1-21");
	let _ = insert_proc(&conn,"t0715","喜多方",21748,"1956-9-12");
	let _ = insert_proc(&conn,"t0716","二本松",51924,"1956-7-5");
	let _ = insert_proc(&conn,"t0717","いわき",97125,"1956-9-12");
	let _ = insert_proc(&conn,"t0718","相馬",63219,"1956-3-22");
	let _ = insert_proc(&conn,"t0719","須賀川",25781,"1956-11-30");

	eprintln! ("*** end ***");

	Ok(())
}

// --------------------------------------------------------------------
```

実行

```text
$ cargo run /var/tmp/sqlite3/cities.db
    Finished dev [unoptimized + debuginfo] target(s) in 0.80s
     Running `target/debug/sqlite3_create /var/tmp/sqlite3/cities.db`
*** start ***
/var/tmp/sqlite3/cities.db
*** end ***
```
オフライン環境構築 npm編

[オフライン環境構築 目次へ](https://qiita.com/kannkyo/items/1e5f8362ed591ebda33d)

# はじめに

[【Yarn】パッケージをオフラインでインストールする](https://qiita.com/TakuyaHara/items/a2683c74c1827cb07583) という記事に触発されて、npmパッケージのオフラインインストール用のツール[yarn-offline](https://github.com/kannkyo/yarn-offline)を作った。

npm自体はオフラインインストールに対応していないのでyarnを使う。

# ディレクトリ構成

ツールのディレクトリ構成はこんな感じ。

```shell
yarn-offline
├── .gitignore
├── .yarnrc
├── CHANGELOG.md
├── LICENSE
├── README.md
├── offline-cache
│   └── .gitkeep
└── package.json
```

ツールのミソは[.yarnrc](https://github.com/kannkyo/yarn-offline/blob/master/.yarnrc)。プロジェクトディレクトリの`.offline-cache`フォルダにtarボールを保存するための設定をしてある。

```ini:.yarnrc
yarn-offline-mirror "./offline-cache"
yarn-offline-mirror-pruning true
```

# 使い方

## オンラインでの作業

まず、ツールをcloneする。

```shell
git clone https://github.com/kannkyo/yarn-offline
cd yarn-offline
```

次に、オンライン環境でyarnコマンドを実行する。

```shell:コマンド実行
yarn add <package_name>
# or
yarn add -D <package_name>
```

または、`package.json`に手入力で所望のパッケージを記載し、`yarn online:download`コマンドを実行する。

```json:package.json
  "devDependencies": {
    "cross-env": "^7.0.2",
  },
  "dependencies": {
    "express": "^4.17.1"
  }
```

```shell
yarn online:download
```

これで、`offline-cache`ディレクトリにtarボールが保存される。

```shell:offline-cacheディレクトリ
offline-cache/
├── .gitkeep
├── @webassemblyjs-ast-1.9.0.tgz
...
└── yeoman-generator-2.0.5.tgz
```

## オフラインでの作業

最後に、オフライン環境にyarn-offlineディレクトリを丸ごと移動して`yarn offline:install`コマンドを実行する。

```shell
yarn offline:install
```

これでOK。

## バージョン更新方法

`offline-cache`を作ってからしばらくたつと、パッケージのバージョンを上げたくなることがある。

こんな場合は`yarn online:upgrade`コマンドでバージョンアップが可能。

```shell
yarn online:upgrade
yarn online:download
```
Firebaseコンソールで通知ごとのCloudMessagingレポートを確認できるようにする

# tl;dr

- Firebase CloudMessagingのペイロードに `"analytics_label": "2020_SummerCampaign_1"` のような計測用ラベルを追加する
- FirebaseコンソールのCloudMessagingレポートから、該当ラベルでフィルターした送信数、受信数、表示回数、開かれた回数を確認できる

![cloud messaging report](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/422/5e267bce-ddf2-b801-4775-3d6fcdfa3e1b.png)


# AnalyticsLabelを追加する

Firebase CloudMessaging（以降FCMと略す）のHTTP v1 API経由でPush通知を送信する際にAnalyticsLabelを設定することで、Push通知の受信数、表示回数、開封回数を集計できるようになります。

`fcmOptions.analyticsLabel`

```example.json
{
  "name": "Hello Shiny Summer",
  "data": { },
  "notification": { },
  "android": { },
  "webpush": { },
  "apns": { },
  "fcm_options": {
    "analytics_label": "2020_SummerCampaign_1"
  },
}
```

プラットフォームによって異なるAnalyticsLabelを指定したい場合は、 `FcmOptions` の代わりにそれぞれ `AndroidFcmOptions`, `WebpushFcmOptions`, `ApnsFcmOptions` でAnalyticsLabelを指定することができます。

## 制限事項
- ラベルの命名ルール: `^[a-zA-Z0-9-_.~%]{1,50}$`
  - 半角英数字（大文字小文字）と記号 `-`, `_`, `.`, `~`, `%` が使用可能
  - 最短1文字から最長50文字まで
- 1日あたり最大100種類まで指定可能
  - 100種類目以降はレポートに集計されない

## 参考

Adding analytics labels to messages - https://firebase.google.com/docs/cloud-messaging/understand-delivery?hl=en#adding-analytics-labels-to-messages

REST Resource: projects.messages - https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages
＜Swift＞NavigationBarをコードで追加する方法

呼び出し元

```swift:TopViewController.swift
class TopViewController: UIViewController {
    private func presentTodolistEditViewController(todolistId: Int?){
        let next = TodolistEditViewController(todolistId: todolistId)
        let nextNaviVc = UINavigationController(rootViewController: next)
        self.present(nextNaviVc,animated: true, completion: nil)
    }
}
```

呼び出し先

```swift:TodolistEditViewController.swift
extension TodolistEditViewController {
    private func setupNaviBar(){
        // 画面タイトル
        if let _ = todolistId {
            self.title = "TODOリスト編集"
        } else {
            self.title = "TODOリスト新規追加"
        }
        
        // 閉じるボタン
        let closeButton = UIBarButtonItem(barButtonSystemItem: .close, target: self, action: nil)
        self.navigationItem.setLeftBarButton(closeButton, animated: true)
        let closeButtonObservable = closeButton.rx.tap.asObservable()
        closeButtonObservable.subscribe(
            onNext: { [weak self] in
                self?.dismiss(animated: true, completion: nil)
            }
        ).disposed(by: disposeBag)
        
        // 決定ボタン
        let determineButton = UIBarButtonItem(title: "決定", style: .plain, target: self, action: nil)
        self.navigationItem.setRightBarButton(determineButton, animated: true)
        let determineButtonObservable = determineButton.rx.tap.asObservable()
        determineButtonObservable.subscribe(
            onNext: { [weak self] in
                self?.dismiss(animated: true, completion: nil)
            }
        ).disposed(by: disposeBag)
    }
}
```

参考にしたサイト
https://qiita.com/mochizukikotaro/items/f053495eb130e92e13e8
https://logist3.com/swift-navi-modal/
https://qiita.com/dddisk/items/0db4ffd129081aef93d3
AWS→IT用語への変換小ネタ集

#はじめに
AWS特有のサービス・用語があってAWS初心者にはとっつきづらいため、通常のIT用語に変換します。

#用語集
<h2>EC2</h2>
・EC2 仮想サーバー
・セキュリティグループ　ファイアウォール（インスタンス単位）
・ネットワークACL　ファイアウォール（サブネット単位）
・AMI　OSやソフトウェアがインストールされたディスクイメージ
<h2>VPC</h2>
・VPC 仮想ネットワーク
・インターネットゲートウェイ 　インターネットとの接続を行う仮想ルーター
<h2>Route53</h2>
・Route53 DNSサービス

#まとめ
また良い説明があれば追記します。
なぜ、admin/profile/createに辿り着けないのか

#なぜ、admin/profile/createに辿り着けないのか

#本題
こんにちは！今回はある問題にぶつかりました。。。

Laravel にて admin/profile/create にいきたいのだが、
なぜか、アクセスすると
404 not foundと表示されます。
Routing の記述ミスなのかとか、Action のミスなのか色々考えたのですが、
とりあえずは
web.php ファイルを
見てみるのが良いとネットに書いてありましたので見に行ってみました。

```php
Route::get('/', function () {
    return view('welcome');
});

Route::group(['prefix' => 'admin'], function() {
    Route::get('news/create', 'Admin\NewsController@add')->middleware('auth');
    Route::get('admin/profile/create', 'Admin\NewsController@add');
    Route::get('admin/profile/edit', 'Admin\NewsController@edit');
});
Auth::routes();

Route::get('/home', 'HomeController@index')->name('home');
```

ふむふむ、特に変わったものはないのだけど、
わからなすぎて困惑しました。

しかし、友人に尋ねてみたら速攻で間違いが判明しました。

＜友人A
お前これさ、「admin/admin/profile/create」になってね？

＜私
？
何言ってんだ、、、あ。。
なってるわ笑

＜友人A
wwwww

＜私
wwwww

友人の言った通り「admin/admin/profile/create」なっていました。。泣
問題の部分はここです。

```php
Route::group(['prefix' => 'admin'], function() {
    Route::get('news/create', 'Admin\NewsController@add')->middleware('auth');
    Route::get('admin/profile/create', 'Admin\NewsController@add');
    Route::get('admin/profile/edit', 'Admin\NewsController@edit');
});
```

お分かりでしょうか。
groupの中の['prefix' => 'admin']と記述しているのに、

```php
Route::get('admin/profile/create', 'Admin\NewsController@add');
Route::get('admin/profile/edit', 'Admin\NewsController@edit');
```
と記述してしまっているのです。
ちなみに['prefix' => 'admin']の記述は、すべて admin から始まると言うことです。

ですので、この記述だと
adminからスタート → admin/profile/create', 'Admin\NewsController@add
なってしまうと言うことですね。

直します。笑

```php
Route::group(['prefix' => 'admin'], function() {
    Route::get('news/create', 'Admin\NewsController@add')->middleware('auth');
    Route::get('profile/create', 'Admin\NewsController@add');
    Route::get('profile/edit', 'Admin\NewsController@edit');
});
```

こう言うことですね！
解決です！！
友人Aよ！ありがとう。
皆さんも私みたいにならないように、お気をつけくださいませ！笑
Raspberrypiの温度取得メモ

#Raspberrypiの初期メモ
ここでは温度センサを利用するためにRaspberrypiを初めて使った際に使った(数少ない)コードを**自分自身のメモ代わり**に残しておく

```
$ sudo restart　//再起動
$ vcgencmd measure_temp //CPU温度の取得
temp=40.0'C 
$ vcgencmd measure_clock arm //CPUの動作電圧
frequency(48)=600117184
$ vcgencmd get_mem arm//メモリの割り当て
arm=896M
$ vcgencmd get_mem gpu//メモリ割り当て
gpu=128M
```
上記のコードはコメントアウト(//)で示した通りのことを示している。
実際にこれらのコードを**Raspberrypi3B+**で実行した際に得られた結果として図を貼っておく
![Screenshot from 2020-07-16 19-49-03 - コピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679292/d354200d-ba51-d6b2-9aa8-98c69b96d5b7.png)
初期的なコードだが、クロックダウンしやすいRaspberrypiでの温度情報の取得、確認は凡庸性が高いと思われる。
LOD表現はサブクエリ

この記事はTableauのLOD表現がわからないけど、DBのサブクエリがわかる方向けです。

まず、LODについては以下の記事が非常に分かりやすいです。

Tableau：分かりやすいLOD-FIXED編 | エクスチュア株式会社ブログ
https://ex-ture.com/blog/2017/12/04/%E5%88%86%E3%81%8B%E3%82%8A%E3%82%84%E3%81%99%E3%81%84lod-fixed%E7%B7%A8/

LOD計算を本気で理解する - Tableau Note
https://www.yarakawa.com/post/lod_calculations

上の記事の中で、「LODは中間テーブルを作成すること」とあります。LODはTableau学習者が最も躓くポイントのうちの一つか思いますが、私も最初理解できないでいました。ところが上の記事で「中間テーブルを作成すること」＝「サブクエリで集計データを作成してjoinすること」ということに気づいて一気に理解が進みました。

LODがDBのサブクエリに近いことを、TableauからDBに発行されるクエリを見ながら確認するのがこの記事の目的です。

データはTableau社から提供されているサンプルスーパーストアを使用します。

LODを使って全期間の売上合計の計算フィールドを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679299/874102d1-da7c-fb04-5c32-0a2c6d1f4bb6.png)
次に、「パフォーマンスの記録を開始」した上で、LOD計算を使ってみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679299/e03fb06b-5f41-76e8-97d7-fecf392aa318.png)
今回はこのような集計表を作成しました。

「パフォーマンスの記録を停止」し、発行されたクエリを確認すると以下のものでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679299/db21cc80-0d8d-89f6-b69a-0aac647acad6.png)
ここでt0は各年度毎の売上合計を計算するためのサブクエリ、t1が全期間売上合計を計算するためのサブクエリです。このLOD計算ではディメンションを指定していないため、CROSS JOINで結合されています。このようにLODがサブクエリでt1として計算されていることが確認できました。

次にディメンションを指定してみます。顧客区分ごとに集計するよう指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679299/18185201-01b1-0382-3796-e2f44bc12a54.png)
「パフォーマンスの記録を開始」し、LOD計算を使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679299/806b8db8-743c-eef9-0634-493b2416c4a5.png)
以下のクエリが発行されていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679299/82e9e45f-cb16-6e06-3a44-bee55f500589.png)
今回は先ほどと違い、ディメンション（＝顧客区分）を指定しているので、サブクエリの中で顧客区分を使ってGROUP BYした上で、顧客区分をキーとしてINNER JOINで紐づけています。より詳細に見たい場合、このクエリや、サブクエリをDB上で実行すると、Tableauに渡されるデータや、LODで作成されるを中間テーブルを確認できます。

このように結局のところLODは裏ではサブクエリが動いており、LODを使いたいタイミングというのはDBでサブクエリを使いたいタイミングとほぼ同じと言えるかと思います。中間のテーブルの形と、それがどのように紐づけられちるのかを意識するとLODを理解できるようになります。

これはデータソースとしてDBを使った場合ですが、エクセルなどの場合はTableauが同様の処理を行っていると理解すればいいかと思います。
TSVファイルを生成する処理を作る時の自分ルール

自分ルールを書き出しておく。

# TSVファイルについて

- 当たり前だけど、データの区切りはTAB
- 最後尾には、「ここが最後尾ですよ」のマークを付ける
    - 「__ 名前 __」の形式で、自分は「eol」を使っている
    - 目に見える文字列を入れておくと、落ち着く
        - プログラムのエラーに気づきやすい、とかあるよね？
        - 改行コードの違いへの耐性が強くなる、気がする
- 先頭にはデータの型に対応したマークをつける
    - 「__ 名前 __」は同じ
    - 同じ「__ 名前 __」があれば、同じ行の後に続く項目のデータの種類や、同じファイル内で他の種類のデータのあるなしなども同じにする
        - 同一システム内で一貫性があれば良し
- 2つ目の項目（実質1つ目）にはユニークキーに相当するものを置く

# 備考

- 「サクッとMySQLとか用意して、そこに入れたほうが早くね？」という状況もあると思う。
- 全体最適化を考えて、状況に応じて。
.NET Core 3.1、.NET 5 の開発をVSCodeで行うまでと、exeの作成方法など

## VS Code で .NET 5 のソースをビルド


* [C# - Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp)


## Ubuntu


```sh:.NETのSDK
wget -q "https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb"

dpkg -i packages-microsoft-prod.deb

add-apt-repository universe
apt update
apt install -y apt-transport-https
apt install -y dotnet-sdk-3.1
```

* [VSCode](https://code.visualstudio.com/download)をインストール

```sh:VSCode
dpkg -i "code_1.47.2-1594837870_amd64.deb"
```

* VSCodeに`c#`の拡張をインストール

![スクリーンショット_2020-07-23_18-50-14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/c8812074-d9ee-da43-f59f-67894eaf9f5e.png)


ターミナルを開く。`Ctrl + Shift + @`

```sh:
# コンソールベースの開発を指定
dotnet new console -n con1
cd con1
```

VSCodeでフォルダを開く。（間違えたところを開いた場合は、`File - Close Folder`）

![スクリーンショット_2020-07-23_18-56-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/74f34bc4-df4a-6b55-7cef-66a0c26edc68.png)

```sh:実行
dotnet run
# Hello World!
```

* [.NET Core ランタイム識別子 (RID) のカタログ | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/core/rid-catalog)

```sh:exeの作成
# ランタイムを含める場合 (66MBと巨大になる！)
dotnet publish -r win7-x86 /p:PublishSingleFile=true
dotnet publish -r win10-x64 /p:PublishSingleFile=true
# Linux向けにも作れる。(※ CentOS6のような古いものでは動かない。)
dotnet publish -r linux-x64 /p:PublishSingleFile=true

# ランタイムを含めない場合 (170KBほど。)
dotnet publish -c release -r win-x64 --self-contained true
```

## winforms

```
dotnet new winforms -n win1
cd win1
dotnet run
```

![form.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/4d53f5bc-e5b1-99ae-c6bf-46b1869b0efe.png)


## ターゲット フレームワークの指定

* [SDK スタイル プロジェクトでのターゲット フレームワーク - .NET | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/standard/frameworks)

`.NET5 SDK`では`net40`の指定は framework の一覧にない ため動かなかった。
(`.NET Core 3.1 SDK`ではいけそう)

![スクリーンショット_2020-07-24_07-42-12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/2720443e-3ce9-bc1a-9f95-8c8cf43c7305.png)

## パッケージの追加方法

```sh:ZXing.net
dotnet add package ZXing.net
# Bitmapを使う場合
dotnet add package System.Drawing.Common
```

## UPX は .NET に対応していない

* [UPX](https://github.com/upx/upx/releases/)


## 好奇心で Ghidra で読ましてみたが全くわからんかった。

* [Ghidra](https://ghidra-sre.org/)
* [OpenJDK 14](http://jdk.java.net/14/)

![スクリーンショット_2020-07-24_08-21-46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25728/3eb8b498-b630-e6f2-945e-e96cafa27b85.png)
【Mac】historyコマンドの表示件数でハマってしまった件

#MacOS

Catalina 10.15.5

#概要
Macでhistoryコマンドを使ったときのこと、

20件だけ出したいと思って以下のコマンドを実行しました

```
> history 20
```

あれ？画面一面にずらっと過去の実行コマンドが表示されてしまった！

改めてネットで調べてみるも間違いはなさそう...

どういうこと？

#結論

MacはCatalinaになってから、コマンドシェルはデフォルトでZshell(zsh)が設定されている(これは知ってた)。

このzshのhistoryコマンドでは上記のコマンドは履歴20番目から全て表示するということになるらしい

20件だけ表示したい場合は、

```
> history -20
```

ハイフンをつけると末尾から20件表示するという指示になるそうです


#参考
https://qiita.com/takc923/items/8409a76e8a660f9f329f
これからはJupter Lab！Jupter Labの導入（インストール）メモ

#0.はじめに
Pythonなどを用いたデータ分析など定番ツールとなっている｢Jupter Notebook｣ですが、2020年7月現在の状況で、開発は終了し、後継である｢JupyterLab｣への移管が正式に発表されています。Sagemakerなども対応が始まり、今後はこちらにユーザも遷移していく可能性が高いので、インストール方法をメモとして残します。

#1.｢Jupter Notebook｣との違い
｢Jupter Notebook｣と何が違うのとう話ですが、基本的にできることは変わりません。イメージとしては開発環境として今風に進化し、今までは追加でパッケージとして導入していたものが、標準でいろいろなことができるようになっています。

大きな違いとしては

* ノートブックタブで管理できるようになった。
* コンソールの実行ができるようになった。
* ｢Tab｣の押下で、標準でコード補完をしてくれるようになった。
* 標準機能から拡張（Extensions）が使えるようになった。（Chromeの拡張のようなイメージ）
* ダークモードが選べるようになった。

![スクリーンショット 2020-07-23 19.23.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600679/ede0af59-7f38-8911-6d32-16ce764512a4.png)


#2.前提
Python環境が構築されていることが前提となります。Python環境の構築は[こちら](https://qiita.com/Yanagawa_Yoshihisa/items/35e6f70a8411277282ce)のリンクを確認ください。（anacondaは使わずにシンプルに導入しております。）
OSはCatalina 10.15.5です。

#3.導入方法
導入方法は至ってシンプルです。

```:ターミナル
$ pip install install jupyterlab
```

起動

```:ターミナル
$ jupyter lab
```

#4.拡張機能導入
せっかくなので拡張機能も導入してみましょう。前提としてNodeの導入が必要なものが多いようなので、まずはそちらをインストールします。

```:ターミナル
$ brew install node
```

後はUIからの導入が可能です。（左のバーの拡張から導入できます。）

便利そうだった拡張を下記にリストします

* Variable Inspector:変数名を常に表示させることができます。 セルの右クリックするとでるリストに｢Open VVariable Inspector｣が追加されます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600679/060673f0-4c85-e676-8c54-bc323d33ab9c.png)

* Table of Contents:マークダウンのリストからのリンクが可能になります。
* jupyterlab_code_formatter:自動でコードをフォーマットしてくれます。

以上です。

#最後に
初心者にもわかるように、Pythonで機械学習を実施する際の必要な知識を簡便に記事としてまとめております。
目次は[こちら](https://qiita.com/Yanagawa_Yoshihisa/items/a3fa521d89c471b3e71f)になりますので、他の記事も参考にして頂けると幸いです。
Precompiling assets failed.

# 概要
Herokuにデプロイした際に、Precompiling assets failed.というエラーが発生したので、解消方法を記述します。

# 環境
- Ruby 2.6.5
- Rails 6.0.0
- heroku

# 原因
- webpack binstubs が無かったのが原因でした。

# 解消手順
まず下記のコマンドターミナルに打ち、エラー確認します。

```ruby

bin/rails assets:precompile
```

確認したら以下の表記がでてきました。

```ruby

webpack binstubs not found.
Have you run rails webpacker:install ?
Make sure the bin directory or binstubs are not included in .gitignore
Exiting!
```
和訳すると

```
webpack binstubsが見つかりません。
rails webpacker：installを実行しましたか？
binディレクトリまたはbinstubsが.gitignoreに含まれていないことを確認してください
終了します！
```
ということです。
2行目で`rails webpacker:install`を教えてくれています。
下記実行したら解消です！

```ruby

rails webpacker：install
```