OmniAICreator/Qiita-1.07M huggingface dataset:
マルチプロセス

```py
import logging
import multiprocessing
import time

logging.basicConfig(level=logging.DEBUG, format='%(processName)s: %(message)s')


def worker1(i):
    logging.debug('start')
    logging.debug(i)
    time.sleep(5)
    logging.debug('end')


def worker2(i):
    logging.debug('start')
    logging.debug(i)
    logging.debug('end')



if __name__ == '__main__':
    i = 10
    t1 = multiprocessing.Process(target=worker1, args=(i,))
    t1.daemon = True
    t2 = multiprocessing.Process(name = 'renamed worker2', target=worker2, args=(i,))
    t1.start()
    t2.start()
    t2.join()
    t1.join() #これがないとworker2が終了した時点でプログラムが終了してしまう
```

```txt
Process-1: start
Process-1: 10
renamed worker2: start
renamed worker2: 10
renamed worker2: end
Process-1: end
```
Python Django CSS 反映

#前提
css反映のさせかたが曖昧だったので記述します。

【環境】
os
python3.7.3
Django3.0.5

アプリケーション名：sns

【ファイル構成】
sns
| - snsproject
| | - setting.py
| | - urls.py
| - snsapp
| | - urls.py
| | - views.py
| - templates
| | - sns
| | | - index.html
| - static
| | - css
| | | - style.css
|manage.py


#本題
早速実装していきます。

```settings.py
・・・
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'sns', #追記
]
・・・
TEMPLATES = [
    {
        'DIRS': [
            os.path.join(BASE_DIR, 'templates'), #追記
        ],
            ],
        },
    },
]
・・・

STATIC_URL = '/static/'

STATICFILES_DIRS = (
    [
        os.path.join(BASE_DIR, "static"), #追記
    ]
)
```

続いてtemplates/index.htmlを編集していきます。

```index.html
{% load static %} 
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> 
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>sns</title>
    <link href="{% static 'css/stylesheet.css' %}" rel="stylesheet">
  </head>
  <body>
  </body>
</html>
```

これでCSSが反映されるようになりました。
HTMLタグと内容


例えばタグは文字とは違います。文字の中にタグがある。これは普通のプログラミングでは考えられない出来事です。混在している中で、判別が必要。つまりタグは判別するブラウザや読み取りのアプリケーション次第でした。

完璧なマークアップができているサイトは少ないものです。大手のサイトでも検査にかけると100％ではない。不完全でした。<a href="https://premium-catfood.com/purina-cat-review-sefety/" >猫ピュリナワンの評判口コミ</a>のようなサイトは失格。

大手のサイトが対応できない。一般のブロガーやサイト運営者に対応できるでしょうか。<a href="https://note.com/yuki_blog" >NOTE</a>
elm-uiでごちゃごちゃレイアウトしてみました

elm-uiという、cssに詳しくなくてもレイアウト面をうまいことやってくれるライブラリを見つけたので、勉強してみました。

作成したものはこちらです。
[github](https://github.com/GoldentTuft/layout-study1)
[demo](https://goldenttuft.github.io/layout-study1/)

# 困ったところ
### ボーダーライン
リンクにマウスカーソルが乗ったときボーダーラインをつけようとしたのですが、レイアウトに影響を与えるスタイルは適用できないそうです。
elm-uiではレイアウトに影響を与えるものはAttribute型、レイアウトに影響を与えないものはDecoration型として分けられ、mouseOver関数に当てられるのはDecoration型だけということです。
DiscordでGadaさんに教えていただきました。
ありがとうございます。

解決策としてはhtmlAttributeかCSSになるみたいです。

*コメントではinFrontを使う方法も教えていただきました。*
*ありがとうございます。*


### スクロールバー
これはあっさりあきらめてしまったのですが、columnにscrollbarY指定してスクロールバーを付けてみようとしたのですが、なぜか付きません。

### スタイルが効かないことがある
フォントの色を変えようと、cssに書いたのですが色が変わらなかったりします。
ボーダーラインがelm-uiからだめならとcssに書いても効かなかったりします。
次第に諦めがちで、インラインstyleで指定するか、cssに書くか、elm-uiの関数を利用するか、どれかで効けばいいやとなりました。

# モーダル
海外のどこかで見かけたものを改造して、そのまま貼り付けてしまいますが。

```elm
modalStyle : Float -> List (Element.Attribute msg)
modalStyle alpha =
    [ Background.color <| rgba 0.0 0.0 0.0 alpha
    , htmlAttribute <| Html.Attributes.style "position" "fixed"
    , htmlAttribute <| Html.Attributes.style "z-index" "1000"
    , htmlAttribute <| Html.Attributes.style "top" "0"
    , htmlAttribute <| Html.Attributes.style "left" "0"
    , htmlAttribute <| Html.Attributes.style "width" "100%"
    , htmlAttribute <| Html.Attributes.style "height" "100%"
    , style "cursor" "default"
    ]
```
こんなのをスタイルに指定してしまえば良さそうです。

# フォーカスを利用したドロップダウンメニューの実装
モーダルとbelowを利用すればドロップダウンメニューを簡単に作れそうだと思ったのですが、それを先にしてしまうとフォーカスを利用したものは面倒で作らなくなってしまいそうなので、意味は余りなさそうですがチャレンジしてみました。

demoのdrop1がフォーカスを利用したもので、drop2がモーダルを利用したものです。

想像はしていましたが、苦労して完成させ、結果どれだけ意味があるのかわかりませんでした。
この方式の利点はなんなんでしょう?

drop1だと、メニューを開き外で右クリックや、ブラウザの検索バーにフォーカスが移るとメニューが消えます。
しかしスクロールバーをクリックしても消えませんし、そのままhoverの上にマウスカーソルを持っていくとそっちも開くのが面倒です。

# シンプルなドロップダウンメニューの実装
透明な要素をサイズを最大にして表示させ、その上にメニューを表示するものです。

```elm
dropDown2 : Element Msg
dropDown2 =
    column []
        [ el (modalStyle 0 ++ [ Events.onClick CloseDropDown2 ]) <| none
        , column
            [ class "dropDown"
            , style "z-index" "2000"
            , paddingXY 0 10
            ]
            [ simpleDropDownItem "item1"
            , simpleDropDownItem "itemitemitem2"
            , simpleDropDownItem "item3"
            ]
        ]
```

Qiitaなどたぶんこの方式だと思います。

このシンプルな方法で問題ないどころか、こっちのほうがいいんじゃないかと思いました。

# まとめ
勉強と探索のため、ごちゃごちゃとやってみて苦労した部分もありますが、シンプルに素早く作るのならelm-uiはかなり便利そうです。
まだ全然使いこなしてはいないと思うので、さらに真価を感じるシーンなどあるのだと思います。

レイアウトライブラリは他にも[elm-neat-layout](https://arowm.github.io/elm-neat-layout/slide/
)というものがあるらしいです。
(キーボードのカーソルでスライドです)
結局css使うなら、、、と気になるライブラリです。
Windows 10 で i3 window manager を使う

- 2020-05-30 更新:[WSL2対応版](https://qiita.com/taoy/items/0938b6097f56962b6fa9)を書きました。(この記事を読んでる前提ですので先にこちらを読んでから)

普段 Debian GNU/Linux Desktop 環境で使っている i3 window manager を Windows 10 でも使いたい。Windows Terminal も悪くないんだけど、やっぱり使い慣れている xfce4-terminal や Thunar が使いたい。そのためだけに VirtualBox 入れるのも良いのだけど、それはそれで独立環境になっちゃうので、Windows 10 そのものとシームレスに使いたい。

## 必要なもの
- Windows 10
- WSL (私の場合は Debian)
- VcXsrv

## セットアップ
### Windows 10
1. WSL を有効にする
2. Debian を入れる
    1. Microsoft Store から WSL 用 Debian を入れる
    2. /etc/apt/sources.list を編集する(任意): 私は Sid を使っちゃう
    
### VcXsrv
1. [VcXsrvのサイト](https://sourceforge.net/projects/vcxsrv/)から、ダウンロードする
2. ダウンロードしたインストーラからインストールする

### WSL上での作業
```
$ sudo apt install i3 j4-dmenu-desktop xfce4-terminal thunar dunst i3pystatus uim-mozc uim-gtk3
```
その他、入れておきたいパッケージは適宜入れる

### i3 設定
WSL のユーザホームディレクトリに .config/i3 ディレクトリを作って、そこに i3 設定ファイル config を作る。
キモは、i3 の終了方法。以下のように書く。

```
# Exit i3 and VcxSrv Together (Thanks for https://gist.github.com/marfillaster/85a3da3a19902236655db1232fa9d8df)
bindsym $mod+Shift+e exec "taskkill.exe /IM vcxsrv.exe /T"
```
i3 を終了する際に、Windows の taskkill コマンドで vcxsrv も終了させる

### WSL 起動時に i3 を動かす shellscript を書く
```
#!/bin/bash
# .scripts/wm
export DISPLAY=:0
source ~/.bashrc
cd
i3
```
これを ~/.scripts/wm として保存する。

### VcXsrv を起動して、WSL を実行する vbscript を書く
```
Set shell = CreateObject("WScript.Shell" ) |
shell.Run """C:\Program Files\VcXsrv\vcxsrv.exe"" :0 -fullscreen -wgl", 0, false |
shell.Run "debian -c "" ~/.scripts/wm""", 0, false |
```
これを i3wm.vbs とか名前を付けて保存する。

## 起動
Windows 10 で、i3wm.vbs をダブルクリックすると VcXsrv が起動して、X Client として i3 wm が動作する

- 各種設定ファイルやスクリプト類は [こちら](https://gist.github.com/taoy/8b44beef41f833280e0edc96c8e3306a)
プログラマ脳を鍛える数学パズルQ06(改造版)コラッツの予想

#問題概要
10000以下の偶数のうち、以下の操作を繰り返して自分自身に戻る数を見つける。

- 初回は3を掛けて1を足す
- 2回目以降は
    - 偶数の場合、nを2で割る
    - 奇数の場合、nに3を掛けて1を足す

# Code
```python
loopnums = []
for num in list(range(2, 10000, 2)):
    n = num * 3 + 1
    while True:
        if n % 2 == 0:
            n = n / 2
        else:
            n = n * 3 + 1
        if n == 1:
            break
        elif n == num:
            loopnums.append(num)
            break

print(loopnums)
print(len(loopnums))
Proxy 配下の Windows 10 で、WSL や Hyper-V 環境が proxy をちゃんと使うように設定する

## 前提
- 企業内ネットワーク環境で、Proxy 経由でないとインターネットへ出られない
- Proxy そのものの設定は変更できない
- 話を簡単にするために、全プロトコル同一 Proxy
- Proxy にユーザ認証は無い

## やりたいこと
- WSL のディストリビューションが普通にインターネットから更新出来るようにしたい
- VSCode のリモート WSL が普通に動くようにしたい
- VSCode のリモート SSH で Hyper-V 上の環境が普通に動くようにしたい

## 設定
### WSL
#### apt.conf 設定

プロキシサーバが立っていてそのままネットに出られない場合、apt.conf を作らないと apt-get 等でソフトウェアのインストールや更新が行えない

- /etc/apt.conf

```conf
Acquire::http::proxy "http:<fqdn>:<port>";
````

- [参考リンク](https://github.com/Microsoft/WSL/issues/1570)

#### wget
VSCode の Remote WSL で拡張機能を入れる際に内部的に wget を使っているので、``` .wgetrc ``` を書く。

- ~/.wgetrc

```
use_proxy=on
http_proxy=http://<fqdn>:<port>
https_proxy=http://<fqdn>:<port>
HTTP_PROXY=http://<fqdn>:<port>
HTTPS_PROXY=http://<fqdn>:<port>
```

#### bash

bashrc にも書いておく。

- ~/.bashrc

```
export http_proxy=http://<fqdn>:<port>
export https_proxy=$http_proxy
ALL_PROXY=$http_proxy
```

### Hyper-V 仮想マシン

基本的に、上記 WSL と同様。

参考情報: https://gist.github.com/taoy/eaf225e4459af23f8cc1be59937407da

### Docker Desktop

設定パネルに proxy 項目があるのでそこで設定。
【Day59】積み上げ日記

##予定
■Udemy（有料教材）
－セクション13-14

##完了
■Udemy（有料教材）
−セクション１３、１４（途中）

##学習時間
６h

##学習ポイント
■sender = UIButton（オブジェクト）のこと

■MVCモデル
・Model：機能をまとめたもの
・View：外見をまとめたもの
・Controller：
①Viewに見せるための処理をまとめたもの
②ViewからModelに、ModelからViewへの処理をまとめたもの

■プロパティとメソッドの違い　
・プロパティ：
var name = “Conan”
・メソッド：
func greet( ) {
	print ( “ I am \(変数)” )
}

■initの記述は、funcなしでOK！
秘伝のエクセル！　どこ変えたんだ！？を調べてみる

むか～しむかしから伝わる秘伝のエクセルがあります
相当古くから部署の担当者たちが作り伝え続けてきた秘伝のエクセル
それぞれの時代の担当者たちが独自に拡張を重ねてきてすでに全体像が分からなくなっている
二度と同じものは作れないんじゃないかって感じの秘伝のエクセル

そう、どこかの老舗の秘伝のタレのような...そんなエクセル

そんな秘伝のエクセルをWEB化して欲しいと言われて
いろいろ担当者たちに話を聞き、一部分のみを条件を限定してWEB化した

数年前の話だが、いまだに更新依頼が来る

「この辺をこういう風に変えたんでWEB側も同じようにお願い」
って軽く言われるけど、毎回調べるとそれ以外の計算式もいろいろ変わってたりする

しかも端数処理が変わったりしてるんだけど、担当者たちは気付いていないのか気にしていないのか..
数バージョン前に先祖返りしてる個所もよく見つかる
おそらく担当内での最新版の管理とかもされてなくて
担当者たちがそれぞれ手元のエクセルを最新版と思って修正してたりするんでしょう...

秘伝のタレを持って行った弟子たちがそれぞれ本家を名乗ってるような...そんな感じ


毎回、変更点を調べるために書いてるVBAをとりあえずココに書き留めておく
どこかで同じようなことしている人達のためにも

これを張り付けて実行すれば、計算式をテキストファイル化してくれるので
差分比較ツールなどで変更点をあぶり出せます（WinMargeとか）


```vb
Sub a()
    Dim s As Worksheet      '// WorkSheet  - シート
    Dim r As Long           '// Row        - 行
    Dim c As Long           '// Column     - 列
    Dim fn As Long          '// FileNumber - ファイル番号
    Dim f As String         '// FileName   - 出力ファイル名
    
    '// 出力ファイル準備
    fn = FreeFile
    f = ActiveWorkbook.Path & "\" & ActiveWorkbook.Name & "_diff.txt"
    
    '// 出力ファイル生成 - エクセルファイル名も出力
    Open f For Output As fn
    Print #fn, ActiveWorkbook.Path & "\" & ActiveWorkbook.Name
    
    '// 全シート対象
    For Each s In ActiveWorkbook.Worksheets
        DoEvents
        
        '// シート名出力
        Print #fn, ""
        Print #fn, String(100, "=")
        Print #fn, "【 " & s.Name & " 】"
        Print #fn, String(100, "-")
        Debug.Print s.Name
    
        '// 全セル対象（行列）
        For c = 1 To s.Range("A1").SpecialCells(xlCellTypeLastCell).Column
        For r = 1 To s.Range("A1").SpecialCells(xlCellTypeLastCell).Row
            
            '// セルの位置（A1等）と内容（計算式の場合は計算式）を出力
            Print #fn, s.Cells(r, c).Address(False, False) & ": " & s.Cells(r, c).Formula
        
        Next r
        Next c
    Next s

    '// 出力終了
    Print #fn, String(100, "=")
    Close #fn
    MsgBox ("セル内容出力が完了しました" & vbCrLf & f)
    
End Sub
```

セルの位置と内容をこんな感じで出してくれます
> A1: =roundup(xxxxxxxxxx)



行列が大きく変わったりしてる場合は「セルの位置」の出力を
計算式の後ろに出すようにするなど、すると良いのではないでしょうか

ちなみにこのVBAでは色付けの変更やら罫線が変わったとかはわかりません
計算式が変わったことが分かればよい、、そんな限定用途でご使用くださいです


以上
秘伝のタレも良いけれど、WEB化したかったら業務そのものの改革が必要だよね
Dcoker でMinecraft Serverを建てる

# 背景
DockerでMinecraftサーバを構築してみました。

[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/roarh21o6rw/0.jpg)](http://www.youtube.com/watch?v=roarh21o6rw)

## 参考

https://hub.docker.com/r/itzg/minecraft-server/

# コマンド

```shell
docker run -d -p 25565:25565 -e EULA=TRUE -e FORCE_REDOWNLOAD=true --name mc --restart=always -v /Users/{user}/mc:/data  itzg/minecraft-server
```

## コマンド解説

```shell
docker         # docker
run            # docker-hub からpullしてコンテナを生成し、コンテナを開始する
-p 25565:25565 # portをコンテナの25565から実行PCの25565に転送する
-e EULA=TRUE   # 環境変数、利用許諾に同意する場合はTRUE。FALSEだと起動しない
-e FORCE_REDOWNLOAD=true  # 最新バージョンをダウンロードする場合はtrue
--name mc                 # コンテナ名
--restart=always          # 終了してしまった場合に自動的に再起動する
-v /Users/{user}/mc:/data # 実行PCの/Users/{user}/mcをコンテナ内の/dataにマウントする
#※自分の好きなフォルダに変更してください。
itzg/minecraft-server     # docker-hub からpullするイメージ名
```
AWS認定 Alexaスキルビルダー - 専門知識に合格したので、実践した勉強方法を共有します

#はじめに
[AWS認定 Alexaスキルビルダー - 専門知識](https://aws.amazon.com/jp/certification/certified-alexa-skill-builder-specialty/)にスコア815点で合格しました。勉強期間は約1ヶ月でした。

[<img width = 200 src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266372/1fe86f69-1935-8395-cfe5-b2ed088525eb.png">](https://www.youracclaim.com/badges/88efef4f-4673-4a71-b6fa-e1a7138c0385/public_url)


私が実践した勉強方法を共有しますので、これから受験する方の参考になれば幸いです。

#私とAWSとAlexa
AWS歴は約4年です。
**Alexaを業務で扱ったことはありません。**[Alexa道場](https://developer.amazon.com/ja-JP/alexa/alexa-skills-kit/webinars)の動画を見ながら、サンプルアプリを作ったことがある程度です。

こんな感じの人が以下の勉強方法で約1ヶ月勉強したら合格できたと思ってください。

#実践した勉強方法
私が実践した勉強方法を共有します。基本的に上から順番に実施していきました。

##先駆者の方々のまとめ記事を見る
既に受験された方々のまとめ記事を見て、出題範囲のAWSサービスや問われる知識分野を把握しました。
私は以下の記事を参考にさせて頂きました。

- [AWS認定Alexaスキルビルダーになりました](https://note.com/iga_lab/n/n168b140eb814)
- [AWS 認定 Alexaスキルビルダーの日本語版が公開されたのでスキルビルダーになった話](https://qiita.com/ikegam1/items/accf98a9d007e4a27619)

## AWSトレーニングルーム(eラーニング)を受講する
[AWS認定 Alexaスキルビルダー - 専門知識のトレーニングルーム](https://www.aws.training/Details/eLearning?id=45890)を受講しました。
講義内でサンプル問題を解くことができるので、満点を取るまで繰り返し解きました。

## サンプル問題を解く
[サンプル問題](https://d1.awsstatic.com/training-and-certification/docs-alexa-skill-builder-specialty/AWS%20Certified%20Alexa%20Skill%20Builder%20-%20Specialty_Sample%20Questions_JPN.pdf)を解きました。満点取るまで繰り返し解きました。

## 公式の模擬試験を受験する
公式の模擬試験を受験しました。正答率は65%(20問中13問正解)でした。
終わった後も繰り返し解けるように、問題文と選択肢の画面を試験時間中にスクショしておきました。
公式の模擬試験は各問の回答が分かりません。なので、公式ドキュメントや機械学習系の記事を調べて、自分で答えを見つける必要があります。
本当に合っている答えかは分かりませんが、満点が取れるまで繰り返し解きました。

## 非公式の問題集を解く
Amazonで以下の非公式の問題集の試し読み部分だけを解きました。Alexaスキルビルダーはけっこう簡単と言われているので、購入するまではしなくていいかなと思って購入しませんでした。

- [AWS Certified Alexa Skill Builder Specialty Practice Tests 2020: AXS-C01 AWS Certified Alexa Skill Builder Specialty Exam Dumps. 100% pass guarantee in first attempt (English Edition)](https://www.amazon.co.jp/Certified-Alexa-Builder-Specialty-Practice-ebook/dp/B083NKVWVR/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=aws+certified+alexa&qid=1587451719&sr=8-1)



#感想
先駆者の方々の受験記を読むとけっこう簡単みたいなことが書かれている記事が多くありましたが、実際に受けてみるとそんなことありませんでした。普通に問題の難易度は高かったです。けっこう細かいAlexaの仕様を問う問題が多く、自信を持って解答できたものは少なかったですが、合格できて良かったです。
今回の勉強を通して、VUI開発の流れをなんとなく理解できる程度にはなれたと思います。今のところ業務で扱う予定はありませんが、今後何かで使える日がくれば良いなと思います。
プログラマ脳を鍛える数学パズルQ05いまだに現金払い？

#問題概要
1000円を500円玉、100円玉、50円玉、10円玉の組み合わせに両替する。ただし硬貨の枚数の合計は15枚以下。

#Code
何も考えずに解く

```python
#Q05いまだに現金払い？

combinations = [] #組み合わせのリスト
for c500 in range(3):
    for c100 in range(11):
        for c50 in range(16):
            for c10 in range(16):
                if c500 + c100 + c50 + c10 <= 15:
                    if c500 * 500 + c100 * 100 + c50 * 50 + c10 *10 == 1000:
                        combinations.append((c500, c100, c50, c10))
                
print(combinations)
print(len(combinations))
```

#Codeその2
なるべくfor文の繰り返しを減らして書く

```python
import itertools
import numpy as np

combinations = []
for c in list(itertools.product(list(range(16)), repeat=4)):
    m = np.array(list(c)) * np.array([500, 100, 50, 10])
    if np.sum(c) <= 15 and np.sum(m) == 1000:
        combinations.append(c)
        
print(combinations)
print(len(combinations))
```

コードが短くなったが、べつに処理速度が速くなったようは思えないし、可読性も低くなったので参考程度で。。。

言いたいことは、配列回りの処理をするときには、

- itertools
- numpy

あたりを漁ると、実装が楽になるツールが見つかる、ということ。

以下、今回使ったツールの補足。

##itertools.product
配列の直積を求める。repeatオプションを使うと、自分自身との直積を求めることができる。itertoolsオブジェクトを返すが、listにキャストできる。以下使用例。

```python
import itertools

x = ['a', 'b']
y = ['c', 'd']
z = list(range(3)) #[0, 1, 2]

print(list(itertools.product(x, y))) 
#[('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd')]

print(list(itertools.product(x, repeat=2)))
#[('a', 'a'), ('a', 'b'), ('b', 'a'), ('b', 'b')]

print(list(itertools.product(z, repeat=2)))
#[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
```

##numpyでのリストの四則演算
通常のリストでは、+記号はリストの連結を表す。それ以外の演算記号はエラー。
numpyでは、リストを演算記号でつなぐと、同じ位置にある要素を演算した結果のリストを返す。

```python
import numpy as np

x = [1, 3, 5]
y = [2, 4, 6]

print(x + y) #[1, 3, 5, 2, 4, 6]
print(x - y) #error
print(x * y) #error
print(x / y) #error

print(np.array(x) + np.array(y)) # [ 3  7 11]
print(np.array(x) - np.array(y)) # [-1 -1 -1]
print(np.array(x) * np.array(y)) # [ 2 12 30]
print(np.array(x) / np.array(y)) # [0.5 0.75 0.83333333]
```
SLが見たい

# 急にSLが見たくなる
ターミナルで作業中にSLが見たくなることありますよね！そ言う言うときはslコマンドをインストールだ。

```
$ sudo apt install sl
```

そしておもむろにslエンター

```
$ sl

```

コピペできないので結果はご自身で確かめてください。

```
$ while true; do sl -e ; done
```
なんかは延々SLが見られます。-e　をつけないとCtrl-Cが効きません。-a とか -l とか -F  とかあります。
Zoom で使用するデータセンターを設定する手順

## 背景

下記の記事のように利用サーバを選べるようになりました。

* [Zoom、有料プランなら利用サーバーを選べるように](https://www.gizmodo.jp/2020/04/zoom-pro-server-selection.html)

参考までに自分が行った設定手順をメモしておきます。

＊上記記事の通り、2020/04/22 現在有料プランアカウントでのみ設定可能でした。
＊無料アカウントでは設定項目 自体が表示されませんでした。

## 手順

https://zoom.us/ を開きます。

画面右上の [サインイン] ボタンでログインします。

![2020-04-22_05h03_55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14284/1f4cbadf-6c96-9eba-a7f7-c0d27d3495fa.png)

アカウント画面が開きますので、画面左側のメニューより、 [Settings > In Meeting(Advanced)] を選択します。

![2020-04-22_05h06_29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14284/24a86102-e3ce-ab8f-213a-dbf3150e4ba4.png)

"In Meeting(Advanced)" セクション末尾あたりに [Select data center regions for meetings/webinars hosted by your account] という項目があります。チェックを入れると使用するデータセンターをチェックボックスで選択できます。

![2020-04-22_05h10_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14284/5d139750-3f2a-6b82-cdf2-a95280e218a5.png)
初心者によるプログラミング学習ログ 296日目

#100日チャレンジの296日目
twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。
100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
296日目は、
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">おはようございます<br>296日目　2h<br>・xdデザインカンプからのサイト模写<br>・ハンバーガーメニュー作成<a href="https://twitter.com/hashtag/%E6%97%A9%E8%B5%B7%E3%81%8D%E3%83%81%E3%83%A3%E3%83%AC%E3%83%B3%E3%82%B8?src=hash&amp;ref_src=twsrc%5Etfw">#早起きチャレンジ</a><a href="https://twitter.com/hashtag/%E9%A7%86%E3%81%91%E5%87%BA%E3%81%97%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%A8%E7%B9%8B%E3%81%8C%E3%82%8A%E3%81%9F%E3%81%84?src=hash&amp;ref_src=twsrc%5Etfw">#駆け出しエンジニアと繋がりたい</a><a href="https://twitter.com/hashtag/100DaysOfCode?src=hash&amp;ref_src=twsrc%5Etfw">#100DaysOfCode</a></p>&mdash; ぱぺまぺ@webエンジニアを目指したい社畜 (@yudapinokio) <a href="https://twitter.com/yudapinokio/status/1252691525693108226?ref_src=twsrc%5Etfw">April 21, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
【Truffle】デプロイ時の "run out of gas" への対処法

##コンパイルの最適化でデプロイ量を減らす

**Truffle(v5.1.21)** 環境でコントラクトをデプロイしようとしたら、ガス不足エラーがでました。**truffle-config.js** でガスの値をブロック上限まで上げても失敗します。

```js:truffle-config.js(リミット上限でもダメ)
module.exports = {
  networks: {
    rinkeby: {
      host: "localhost",
      port: 8545,
      network_id: 4,
      gas: 10000000,		// リミット上限
      gasPrice: 20000000000	// 20 gwei
    }
  }
}
```

頭を抱えていたのですが、コンパイルの最適化を有効にして全コンパイルをしたら、なんとかデプロイできました。

```js:truffle-config.js(最適化をオンにしたら通った)
module.exports = {
  networks: {
    rinkeby: {
      host: "localhost",
      port: 8545,
      network_id: 4,
      gas: 10000000,		// リミット上限
      gasPrice: 20000000000	// 20 gwei
    }
  },

  // 最適化を有効にする
  compilers: {
    solc: {
      settings: {
        optimizer: {
          enabled: true,
          runs: 200
        }
      }
    }
  }
}
```

コントラクトがデカくなりすぎているのがそもそもの原因なので、本来なら **Solidity** コードの分割を検討しないといけないのかもしれませんが、「あと関数１つだから」という時には最適化で逃げるのもありかもしれません。

##おまけ

気になったので最適化無し／有りで、デプロイ時のガス使用量がどれぐらい減るかを比べてみました。

・ 最適化前（ぎりぎりデプロイできた時の使用量）
   > gas used:            5548561 (0x54aa11)
   > gas price:           20 gwei

・最適化後
   > gas used:            3817618 (0x3a4092)
   > gas price:           20 gwei

最適化で３割強減っていました。
やったー。
Flutter製のiOSアップロードに失敗する｜Error ITMS-90717

## 発生した問題

FlutterでiOSビルドして、App Store Connectにアップロードする時にエラーが発生しました。
どうも、App Storeのアイコンには透過を含めないでほしいとのことでした。

```
iTunes Store Operation Failed
Error ITMS-90717: "Invalid App Store Icon. The App Store Icon in the asset catalog in 'Runner.app' can't be transparent nor contain an alpha channel."
```

## 環境

- macOS Catalina 10.15.1
- Xcode 11.4
- Flutter 1.17.0


## 結論

アイコン画像を透過のないものに変更したのち、[flutter_launcher_icons](https://pub.dev/packages/flutter_launcher_icons)でアイコン画像を更新する。

```
$ flutter pub get
$ flutter pub run flutter_launcher_icons:main
```

## TIPS

iOSは透過なしの画像を設定すれば、以下のように自動で角丸の画像を生成してくれます。

![icon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36927/b733c660-1fa9-d92f-758b-17584a371776.png)

しかし、Androidは自分で角丸の画像を設定しないと正方形の画像がストアやランチャーアイコンに指定されます。加えて、Androidの場合は、星型やハート型など任意の形のアイコンを指定することが可能です。

そのような場合は、 `pubspec.yaml` でiOSとAndroidのそれぞれでアイコン画像を指定してあげればOKです。

```pubspec.yaml
flutter_icons:
  android: true
  image_path: "assets/icon/icon.png"
  ios: true
  image_path_ios: "assets/icon/ios-icon.png"
```
pipでCould not fetch URL 443が出た時の対処法

# venvでpipを使ってパッケージをインストールしようとするとエラーが出た！

Could not fetch URL https://pypi.org/simple/certifi/: There was a problem confirming the ssl certificate: HTTPSConnectionPool(host='pypi.org', port=443): Max retries exceeded with url: /simple/certifi/ (Caused by SSLError("Can't connect to HTTPS URL because the SSL module is not available.",)) - skipping


どうやらSSLErrorが原因の様子。

ググってみた結果以下の二つが出てきました。


[pip install でSSL関連のエラーが出たらこれを読め！！！](https://qiita.com/kj455/items/9c50b5457631850b3bc)
[pipが動作しないエラーの解決](https://qiita.com/agajo/items/73d6f14855da703972e0)


これらを参考にしましたが上手くいかず・・・

その後venvを作り直してみるとすんなり上手くいきました。


なぜこんなことに陥ったのかを考え直してみると、この直前に作ったvenvは

```
$ virtualenv 名前
```

で作ってしまっていました。
なんでこんなことを・・・

改めてググり直した結果

```
$ python3 -m venv 名前
```

で作り直したら上手くいきました。

ハマっている方は是非一度作り直してみることをお勧めします。
[Heroku][Rails]ログ出力方法

### はじめに
Railsでログを追加する場合、主にloggerを使用するかと思いますが、そのままではHerokuでログが残りません。
利用は以下2点。
・Herokuは標準出力されたものをログとして保存している
・Railsのloggerはデフォルトではファイル出力

loggerで追加したログをHerokuでも残るように設定する方法を記載します。

### 対応方法
結論から記載すると、Heroku側にRAILS_LOG_TO_STDOUTという環境変数を設定することで対応します。

#### 対応手順
1.メニューの「Dashboard」
2.設定したいアプリケーション選択
3.「Settings」タブ
4.「Reveal Config Vars」ボタンをクリック
5.「Config Vars」にそれぞれ以下を入力
　KEY：RAILS_LOG_TO_STDOUT
　VALUE：任意の値　※"true"で確認済み
6.「Add」ボタンをクリック
7.アプリケーションを再起動

#### Railsの設定ファイルについて
RailsではどこでRAILS_LOG_TO_STDOUTを参照しているかを紹介しておきます。

```Ruby:config/environments/production.rb
Rails.application.configure do
  (略)
  if ENV["RAILS_LOG_TO_STDOUT"].present?
    logger           = ActiveSupport::Logger.new(STDOUT)
    logger.formatter = config.log_formatter
    config.logger    = ActiveSupport::TaggedLogging.new(logger)
  end
  (略)
end
```

### 注意点
この対応を行うと、ログの量が大幅に増えるためログが流れてしまわないように注意してください。
Herokuはログを保存しておく量が少ないため、アドオンを入れるなどの対策をしない場合、せっかく追加したログが流れてしまって取得できない、という事態になりかねません。
多言語でも自然言語処理〜その１中国語jiebaR〜

##Rで中国語の形態素解析・自然言語処理
Mecabなどを用いて日本語の処理は行ったことがあったのですが
今回、中国語メディアの分析をすることになったので軽く解説。
案外、Rで外国語自然言語関連の記事は少ないんだなと...(みんなPythonでやるんでしょうけど)
今後韓国語やその他言語の処理を行うことも多くなると思うので
社内外向けにシリーズ化していきたい。

##とりあえず名詞抽出からワードクラウド生成まで
```R:chinese_analysis.rb

#パッケージインストール
install.packages("jiebaR")
library("jiebaR")
library("wordcloud2")

#workerで指定するといろいろできるらしいとりあえず、名詞だけ抽出しましょう
cc = worker("tag")
mixseg = worker()
#サンプル
res = cc["杨家的这种爱国精神由衷地佩服，并暗暗下定决心，我一定好好学习，
         长大后也要做像杨业一样的人，爱自己的祖国，为了祖国的发展、强大付出自己的全部，
         甚至是自己的生命也在所不惜。 之后我们去了万岁山大宋武侠城，一路走走停停来到了水浒街，
         看到了许多水浒情景剧，有“拳打镇关西”、“杨志卖刀”、“怒杀西门庆”、还有吞火表演之类的危险表演，
         看的我满身冷汗，真为她们捏一把汗呀！还好每次都是有惊无险，这真是“台上一分钟，台下十年功”呀 ！
         这就像是我们的学习，我们得到的每一分成功都和我们平时的付出紧密相连。在以后的成长道路上，
         我会时刻谨记一份耕耘，一份收获这个道理，在学习上踏踏实实地用好每一分，每一秒，绝不偷奸耍滑，
         拖拖拉拉，大家一起看我以后的表现吧！ 最后我们实景体验了压轴大戏真人版的“三打祝家庄”表演，
         只这一个演出参演人员有一百多人，他们个个骑着战马，手持兵器，在沙场上奋勇杀敌。
         最先出场的是祝家庄‘一丈青’扈三娘，梁山好汉王英策马迎战，几个回合后，王英被扈三娘活捉回去。
         梁山好汉秦明立即前来帮忙，祝家庄的祝龙策马迎战，两人打了十几个回合，祝龙不敌策马跑回了阵营，
         祝龙的师傅栾廷玉冲出阵营和秦明厮杀在一起......看着马在沙场奔跑，听着“嘚嘚嘚”的马蹄声，
         我仿佛身临其境，最后随着梁山好汉的胜利表演结束！ 夜幕降临、华灯初上，
         我们去品尝了开封著名小吃灌汤包，这才恋恋不舍的回家了。 六五班 于晗晨"]

#名詞抽出の関数作成
get_noun = function(x){
  stopifnot(inherits(x,"character"))
  index = names(res) %in% c("n","nr","nr1","nr2","nrj","nrf","ns","nsf","nt","nz","nl","ng")
  x[index]
}

#名詞のみ抽出
res<-get_adjective(res)
seg <- segment(res, mixseg)
seg2<-sort(table(seg), decreasing = T)[1:50]

#wordcloud準備
wordcloud_noun<-data.frame(seg2)
colnames(wordcloud_noun) <- c("word","freq")

#wordcloud描写
wordcloud2(wwordcloud_noun,size=1,minSize=0)
```
##アウトプット
![chinese.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182397/54a04850-f5ca-22ef-9398-d3bfc99c5172.png)

とりあえずここまでできればあとはMecabなどの処理と変わらないのでいろいろ遊んでみる予定。


##参考文献
**Package ‘jiebaR’**
https://cran.r-project.org/web/packages/jiebaR/jiebaR.pdf
**Quick Start Guide - jiebaR**
https://cran.r-project.org/web/packages/jiebaR/vignettes/Quick_Start_Guide
**上手jiebaR**
https://www.cnblogs.com/hyacinth-yuan/p/8243476.html
Gmailの新着をLINEに通知する


##〇問題と解決法
大学から配給されているメールアドレス(ラボメールと呼称します)をスマートフォンに登録して確認していますが、プッシュ通知にもかかわらずラボメールの**受信時刻から2時間以上も後になってスマートフォンに通知がきます**。しかし、ラボメールをGmailへの自動転送に設定してGmailへ迂回すると、なぜかラグなく受け取ることができます。なので、今までその自動転送設定で過ごしてきましたが、
Gmailの受信を見る
=>Gmailのメールを開いて既読にする
=>ラボメールを開く
=>ラボメールで返信する
と**かなり手間**なうえ、**Gmailの受信ボックスに重複したメールが溜まっていく**良くない状態だったため、メール環境を整えることにしました。
今回は**Gmailのメール設定**と**Google Apps Scriptを用いたLINEへの通知の設定**をしました。
事後でこの記事を書いていますが、劇的に便利になったかというと正直そうでもないです。

##〇参考にしたサイト
参考、というよりほとんどそこから拝借した形になります。
[「【2020年版・iPhone向け】Gmailに届いた特定のラベルのメールをLINEに通知する方法｜IFTTTではなくGASをつかいます。」](https://philosophie-eisen.com/gmail-to-line)
[「Gmailの新着通知をLINEで受け取る by Google App Script」](https://note.com/yuut6/n/nb3528b53ddfa)


##〇やったこと

Gmail側の設定は

- ラボメールからGmailへの転送設定
- 転送されてきたメールのみをラベル付けしてアーカイブにいれる

です。

続いて、Google Apps Scriptを用いたLINEへの通知の設定ですが、1つ目の参考サイトをほとんどそのままやっただけです。なので、大半のことは割愛します。
Google Apps Scriptのコードのところは自分なりに色々いじってみました。
変更点は

- 取得間隔:3秒へ変更(2つ目の参考サイトに倣って) 
- 検索条件指定をto:で指定(ここが重要だった)
- getMonthのずれ修正
- メールの本文を50字だけ表示
- 細かな誤字修正

です。


```javascript:コード　修正版
var lineToken = "********************"; //LINE notify token
var get_interval = 1; //1分前からの新着メールを取得


function send_line(Me){
 var payload = {'message' :   Me};
 var options ={
   "method"  : "post",
   "payload" : payload,
   "headers" : {"Authorization" : "Bearer "+ lineToken}  
 };
 UrlFetchApp.fetch("https://notify-api.line.me/api/notify", options);
}


function fetchContactMail() {

 //取得間隔
 var now_time= Math.floor(new Date().getTime() / 1000) ;//現在時刻を変換
 var time_term = now_time - (60 * get_interval + 3); //秒
 
 //検索条件指定(未読で転送元のメールアドレス宛てのメール)
  var strTerms =  ('is:unread to:(転送元のメールアドレス)');
 
 //取得
 var myThreads = GmailApp.search(strTerms);
 var myMsgs = GmailApp.getMessagesForThreads(myThreads);
 var valMsgs = [];
 for(var i = 0; i < myMsgs.length;i++){
   valMsgs[i] = " " + (myMsgs[i].slice(-1)[0].getDate().getMonth()+1) + "/" + myMsgs[i].slice(-1)[0].getDate().getDate()
    + " " + myMsgs[i].slice(-1)[0].getDate().getHours() + ":" + myMsgs[i].slice(-1)[0].getDate().getMinutes()
    + "\n[From]" + myMsgs[i].slice(-1)[0].getFrom()
    + "\n\n[Subject]" + myMsgs[i].slice(-1)[0].getSubject()
    + "\n\n\n[Message]"+ myMsgs[i].slice(-1)[0].getPlainBody().slice(0,50);
    myMsgs[i][0].markRead(); //メッセージを既読にする
 }
 

 return valMsgs;
}

function main() {
 new_Me = fetchContactMail()
 if(new_Me.length > 0){
   for(var i = new_Me.length-1; i >= 0; i--){
     send_line(new_Me[i])
   }
 }
}
```


これで、うまくいきました。しかし納得がいかないのが、受信時刻の分が1桁だと"14:06"が"14:6"になることです。getMinute()がよくわからなかったので断念。
ValueError: The field admin.LogEntry.user was declared with a lazy reference to 'accounts.user', but app 'accounts' isn't installed.

#makemigarionsしようとしたらなんかエラー出た

ValueError: The field admin.LogEntry.user was declared with a lazy reference to 'accounts.user', but app 'accounts' isn't installed.

なんじゃこれ？
そもそもaccountsというアプリは作っていないし、AUTH_USER_MODELにもそんな表記はしていない。
`settings.py`を見てうんうん悩みましたが、結果分からなかったのでググりました。


# ググった結果

まずヒットしたのはStackOverFlow。

[ValueError: The field admin.LogEntry.user was declared with a lazy reference](https://stackoverflow.com/questions/50324561/valueerror-the-field-admin-logentry-user-was-declared-with-a-lazy-reference)

回答に選ばれていたのは全部のmigrationsファイル消してもう一回やったら上手くいくよ！

最初のmakemigrationsでつまずいているのでこれは違う。

次のは一旦AUTH_USER_MODELを消して新しいテーブル作って、それでまたAUTH_USER_TABLE追加してください,
とのこと。

そもそもAUTH_USER_TABLEを表記していないのでこれも違う。

それぞれ色々試した結果、Redditに気になる回答が

[Getting Errors When Running "Makemigrations"](https://www.reddit.com/r/django/comments/5ifvj3/getting_errors_when_running_makemigrations/)

`私はvirtualenv作り直したら上手くいったよ`

なるほど。ということで試したら見事に上手くいきました。


困っている方がいたら是非試してみてください！
flask-loginでWebアプリの認証を実装できた

# 概要
flaskを使用したWebアプリを作成しています。
以下の参考にさせて頂いたサイトのREADMEコピペほぼで実装できました。
本記事のコードはpassword照合のロジックを書く必要があります。

## 参考にさせて頂いたサイト
https://github.com/maxcountryman/flask-login

flask-loginの公式ドキュメント
https://flask-login.readthedocs.io/en/latest/
## 

## flask-loginの説明
>Flask-Loginは、Flaskのユーザーセッション管理を提供します。ログイン、ログアウト、長期間のユーザーセッションの記憶といった一般的なタスクを処理します。

## 実装

```bash
$ pip install flask flask-login
```

```python
import flask
import flask_login


login_manager = flask_login.LoginManager()
login_manager.init_app(app)

app = flask.Flask(__name__)
app.secret_key = 'super secret string'  # Change this!

# Our mock database.
users = {'foo@bar.tld': {'password': 'secret'}}

class User(flask_login.UserMixin):
    pass


@login_manager.user_loader
def user_loader(email):
    if email not in users:
        return

    user = User()
    user.id = email
    return user


@login_manager.request_loader
def request_loader(request):
    email = request.form.get('email')
    if email not in users:
        return

    user = User()
    user.id = email

    # DO NOT ever store passwords in plaintext and always compare password
    # hashes using constant-time comparison!
    user.is_authenticated = request.form['password'] == users[email]['password']

    return user

@app.route('/login', methods=['GET', 'POST'])
def login():
    if flask.request.method == 'GET':
        return '''
               <form action='login' method='POST'>
                <input type='text' name='email' id='email' placeholder='email'/>
                <input type='password' name='password' id='password' placeholder='password'/>
                <input type='submit' name='submit'/>
               </form>
               '''

    email = flask.request.form['email']
    if flask.request.form['password'] == users[email]['password']:
        user = User()
        user.id = email
        flask_login.login_user(user)
        return flask.redirect(flask.url_for('protected'))

    return 'Bad login'


@app.route('/protected')
@flask_login.login_required
def protected():
    return 'Logged in as: ' + flask_login.current_user.id

@app.route('/logout')
def logout():
    flask_login.logout_user()
    return 'Logged out'

@login_manager.unauthorized_handler
def unauthorized_handler():
    return 'Unauthorized'

if __name__ == '__main__':
    app.run(host="0.0.0.0",port=8000,debug=True)
```

## テスト
以下を元に実装してみるとよいかもしれません。
https://github.com/maxcountryman/flask-login/blob/master/test_login.py
Node.jsでBルートから消費電力を取得する

# 必要なもの
* BルートのIDとパスワード
* Wi-SUNの通信デバイス
* プログラムを実行するPCなど

## BルートのIDとパスワード
契約している電力会社に申請します。
僕の場合は東電エリアなので以下のURLから申請を行いました。

2週間ほどで書面にいてBルートに接続するためのIDが送られてきます。
パスワードはメールにて送付されますので、IDと併せて大切に保管しましょう。

## Wi-SUNの通信デバイス
僕はテセラテクノロジーのRL7023（8,000円 [税抜]）を購入しました。
USBタイプのものは他にもいくつか製品がありますが1万円を超えるものばかりなので、この製品が最も安価だと思います。

https://www.tessera.co.jp/rl7023stick-d_ips.html

## プログラムを実行するPCなど
通信デバイスがUSBドングルタイプなのでPCでもMacでも何でも良いですが、僕は手元にRaspberry Pi 3Bが余っていたのでこれを使いました。

OSはRaspbianです。
Node.jsを入れたり、npmでモジュール追加したりするのでインターネットに繋がるくらいにはセットアップしておきます。

---

# 開発

## Node.js
apt-getするとv10が入ったので、最新安定版のv12を使うためにnodenvを使うことにします。
nodenvからv12.16.2をインストールしました。

## RL7023をRaspberry Piにセット
普通に挿しただけで使えるようになります。
シリアルポートを確認するには以下のようなコマンドで確認してみましょう。

```bash
pi@raspberrypi3:~ $ ls -l /dev/serial/by-id/usb-FTDI_FT230X_Basic_UART_DJ00RTB4-if00-port0
lrwxrwxrwx 1 root root 13  4月 21 17:17 /dev/serial/by-id/usb-FTDI_FT230X_Basic_UART_DJ00RTB4-if00-port0 -> ../../ttyUSB0
```
この場合は`/dev/ttyUSB0`を使います。

## Node.jsでシリアルポートに接続
[serialport](https://www.npmjs.com/package/serialport)というモジュールを使います。

```javascript
import SerialPort from 'serialport'

const port = new SerialPort('/dev/ttyUSB0', {
    baudRate: 115200,
});
```

そして

```javascript

port.once('open', async () => {
    // Bルート認証パスワード設定
    port.write(Buffer.from('SKSETPWD C <Bルートのパスワード>\r\n'))

    // Bルート認証ID設定
    port.write(Buffer.from('SKSETRBID <BルートのID>\r\n'))
}       
```
というようにシリアルポートにメッセージを送って応答を受け取っていくのが基本になります。

## 積算電力量計測値履歴1
当日から99日前までの任意の1日の積算電力量を30分区切りで取得できます。
積算電力量なので、過去から未来にかけて増えていくものですが、例えばとある日の0時0分～0時30分時点の積算電力量を次の区切りである0時30分～1時00分の積算電力量から減算すれば、0時0分～0時30分の間で消費した電力がわかります。

こうして見える化できれば、電気代の高い昼間に沢山電気を使っていることがわかるので、洗濯機や掃除機の使用は昼間ではなく朝夕に変えようかな、といった具体的な行動に移すキッカケになると思います。

特に今は緊急事態宣言が発布されているので、在宅勤務をしている人も多いのではないでしょうか。
となると必然的に日中はPCをつけっぱなしになったりするわけで、平時よりも電気代は高くなっているはずですよね。

作ったソースコードは以下のリポジトリに置いてあります。
https://github.com/chaki1019/broute-js

## 今後
データを取得することができたので、今後は貯めて可視化することを狙っていきます。
貯める場所についてはまだ決めていませんが、クラウドのマネージドサービスを使いたいなあと思ってはいます。

最有力なのはAmazon DynamoDBかな。

---

# 参考

ここにある公式なドキュメントが参考になります。
https://echonet.jp/spec_v112_lite/

今回Bルートをやろうと思った背景などは別途ブログに書いています。
もし良かったら見てやってくださいませ。

https://campstylist.com/2020/04/21/broute1/
PowerShellのPause方法についての備忘録

PowerShellにはDOSコマンドの`PAUSE`にあたるコマンドレットがないため
自分で実装する必要があります


`$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")`で実現はできるのですが
この場合PowerShell ISE上から実行した場合、エラーが発生するので注意が必要です

```pause.ps1
    if ($psISE)
    {
        Add-Type -AssemblyName System.Windows.Forms
        [System.Windows.Forms.MessageBox]::Show("")
    }
    else
    {
        $x = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
    }
```

参考
---
[Stack Overflow - Press any key to continue [duplicate]](https://stackoverflow.com/questions/20886243/press-any-key-to-continue)
JSONをCSVに簡単に変換する方法

# JSONをCSVにpythonで変換する

## JSONファイル

キーの中に、jsonの配列がある形にします(jsonlではない）。
以下ではdataというキーの値にjsonの配列が入る形としている。
配列になってない場合は、配列になるように修正する。あとで加工しやすくするため。

```:target.json
{"data":[{"code":"001","address":{"Pref":"TOKYO","postalCode":"1230021"}},
{"code":"002","address":{"Pref":"FUKUOKA","postalCode":"8140004"}}]}
```



## スクリプト

```python:pandas.py
# coding:utf-8
  
#Pandasをインポート
import pandas as pd
import json
from pandas.io.json import json_normalize

#変換したいJSONファイルを読み込む
df = pd.read_json('target.json')
print(df)

# read_jsonした結果だとネストしたjsonを展開できないのでnormalizeで展開させる
df_json = json_normalize(df['data'])
df_json.to_csv("out.csv", encoding='utf-8')
```

## 実行
```terminal:terminal
python pandas.py
```

## 出力されるCSV
```csv:out.csv
,address.Pref,address.postalCode,code
0,TOKYO,1230021,001
1,FUKUOKA,8140004,002
```

ネストしていないシンプルなJSONであれば、json_normalizeも不要なはず。
ネストが含まれている場合は、上記で解決できると思います。
gitのセキュリティー問題のため、macのgitのバージョンupdate

最近
***Xcode 11.4.1 より前のバージョンでcredential helperの脆弱性によりgitの認証情報が漏えいする可能性があります。***
という情報を見つけた。
参照）https://at-virtual.net/securecoding/%E3%80%90poc%E3%81%82%E3%82%8A%E3%80%91cve-2020-5260-xcodemac%E7%89%88%E3%81%ABgit%E3%81%AE%E8%AA%8D%E8%A8%BC%E6%83%85%E5%A0%B1%E3%82%92%E5%8F%96%E5%BE%97%E3%81%95%E3%82%8C%E3%82%8B%E8%84%86/

自分はすでにXcodeを最新バージョンにアップデートしているが、結局gitのセキュリティーの問題なので、gitのバージョンも上げる必要がある。
それで自分のgitのバージョンを調べて見た。

```Bash 
➜  /Volumes git --version
git version 2.24.2 (Apple Git-127)
```

現在（2020/04/22）時点でgitの最新バージョンは*2.26.2*。
バージョンが古いのでgitのアップデートをしたい。

## macでgitの種類
結論から言うと、mac環境でgitを使うためには、3つの方法があって、それぞれupdate方法が異なる。
1. xcodeに含まれているgitと使う　→　updateできない。公式ホームページからファイルをダウンロードして再度インストールするしかない。
2. 公式ホームページからファイルをダウンロードしてインストールする　→　updateできない。公式ホームページからファイルをダウンロードして再度インストールするしかない。
3. Homebrewでinstallしたgitを使う　→　brew update && brew upgrade コマンドを叩いてupdate

自分の現在gitがどちらから来ているのかがわからないならターミナルで`which git`コマンドを叩いて確認できる。

```Bash
➜  /Volumes which git
/usr/bin/git
```

自分は`1. xcodeに含まれているgit`なので`/usr/bin/git`のディレクトリーが出ている。
Homebrewでinstallしている場合は`/usr/local/bin/git`のディレクトリーが出る。
このgitをupdateするためHomebrewからgitをinstallすることにした。

## Homebrewでgitをinstall

```Bash
➜  /Volumes brew update && brew install git
```
ターミナルで上記のコマンドを叩く
そうしてもう1回`which git`を叩くと

```Bash
➜  /Volumes which git
/usr/bin/git
```

あれ？まだxcodeのgitのまま
Homebrewでinstallしたgitにする適用されていない。

## Homebrewでinstallしたgitの適用方法
### 1. Homebrewのリンクを貼り直す
Homebrewでインストールされたパッケージはその実体が /usr/local/Cellar に、そのリンクが /usr/local/binにそれぞれ保存されている。
そのリンクを貼り直して、ターミナルを再起動するとmacはHomebrewでinstallしたgitに認識する。

```Bash
➜  ~ brew unlink git && brew link git
Unlinking /usr/local/Cellar/git/2.26.2... 206 symlinks removed
Linking /usr/local/Cellar/git/2.26.2... 206 symlinks created
```

を叩いて、ターミナルを再起動した後、`which git`を叩いて確認する。

```Bash
➜  ~ which git
/usr/local/bin/git
```

Homebrewのgitのディレクトリーが出ている。成功。

### 2. 環境変数を指定する
bashの環境設定ファイルにHomebrewのgitのPATHを登録する。
mac osのcatalinaの場合、デフォルトシェルがzshになっているので、ホームディレクトリから設定ファイル`.zshrc`を探す。ない場合には作る。
catalina以前のバージョンの場合、bashシェルのなので`.bash_profile`にする。

`.zshrc`に下記のPATHを登録して、ターミナルを再起動する。

```Bash
export PATH="/usr/local/git/bin:$PATH"
```

再起動した後、`which git`を叩いて確認する。

```Bash
➜  ~ which git
/usr/local/bin/git
```

成功。

## gitのバージョン確認

```Bash
➜  ~ git --version
git version 2.26.2
```
【Bash】getopts が関数内で動かないときはトップレベルの $@ を関数内に持ち込めばいい

# 問題の説明

Bash で実行したスクリプトで、関数内で `getopts` を実行したが思ったように動かない。
これが起きるのは、例えば、スクリプトの引数を解釈する部分を関数に切り出したい場合:

```bash:動かない.sh
parse() {
  while getopts "abc" OPT
  do
    処理...
  done
}

parse
```

これは思ったように動かない。

# 原因

`getopts` はデフォルトで `$@` もしくは `$1, $2, ...` に相当するものを引数リストとみなして解析する。
これは関数内では **関数の引数** であって、**スクリプトの引数ではない** ので、期待通りに動かないのであった。

# 解決方法

- 【方法1】`getopts` は第3引数以降に引数リストを指定することができて、その場合は指定した引数リストが解析される。なので、スクリプトのトップレベルで、スクリプトの引数を変数に入れ、それを getopts で指定すればよい:
  
  ```bash:方法1.sh
  parse() {
    while getopts "abc" OPT argv; do
      処理...
    done
  }

  argv=$@  # 配列変数 argv にスクリプト引数のリストを代入
  parse
  ```
  
  ただし変数スコープ的に気に入らない人もいると思う。その場合は次の方法をとる。

- 【方法2】トップレベルの `$@` を関数の引数として渡す。この場合、関数に独自の引数を設定することはできないと思う:
  
  ```bash:方法2.sh
  parse() {
    while getopts "abc" OPT; do
      処理...
    done
  }

  parse $@
  ```

# さいごに

シェルあまり詳しくないので、間違いや改善点がありましたら教えて下さい。
oracle db を使う時の備忘録

## 概要
いつもはmysqlを使うが、色々なデータベースに触れる機会があり苦しめられたので、
備忘録として役に立ったことを書いていく。随時更新していく。


## 記録

### GUIを使う。(SQL developer)

https://www.postgresql.org/ftp/pgadmin/pgadmin4/v4.19/macos/

### RDS にアクセスするとき

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_ConnectToOracleInstance.html

ここをしっかり見るのが大事だが、特に
[SID]に```ORCL```と書くのに注意！

また、database 名が　```ORCL```となることにも注意！！


### コマンドラインからアクセス
https://yohei-a.hatenablog.jp/entry/20170918/1505738926
ここなどを参考にする。
basicとsqlplusの２つのzipをダウンロードした後、フォルダに格納してPATHを通す。

```
mkdir -p /opt/oracle &&\
cd /opt/oracle &&\
wget https://download.oracle.com/otn_software/linux/instantclient/19600/instantclient-basic-linux.x64-19.6.0.0.0dbru.zip&&\
sudo apt-get install unzip &&\
unzip instantclient-basic-linux.x64-19.6.0.0.0dbru.zip &&\
sudo apt-get install libaio1 &&\
sudo sh -c "echo ./instantclient_19_6 > /etc/ld.so.conf.d/oracle-instantclient.conf" &&\
sudo ldconfig && export LD_LIBRARY_PATH=/opt/oracle/instantclient_19_6:$LD_LIBRARY_PATH
```



さらに、http://tazakazushi.net/sqlplus_ora_12162.html
ここにあるように念のため
```export ORACLE_HOME=admin``` 及び```export　ORACLE_SID=ORCL```　を設定。

そして、接続してみる。

```bash

sqlplus ‘user_name@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=dns_name)(PORT=port))(CONNECT_DATA=(SID=database_name)))’  
```
このとき、```dns_name```, ```port```, ```database_name```を適宜設定すること。


### sqlplusのよく使うコマンドたち
#### show tables

```sql
SELECT TABLE_NAME FROM USER_TABLES;
```

#### 各カラムのデフォルト値を取得する

```sql
Select TABLE_NAME, COLUMN_NAME, DATA_DEFAULT from DBA_TAB_COLUMNS where TABLE_NAME = '<table_name>';
```

#### 各カラムのコメントを取得する

```sql
SELECT COLUMN_NAME,COMMENTS FROM USER_COL_COMMENTS WHERE  TABLE_NAME = '<table_name>'
```


### sqlalchemy を噛ませて接続しようとする時

```
Cannot locate a 64-bit Oracle Client library: "libclntsh.so: cannot open shared object file: No such file or directory". See https://oracle.github.io/odpi/doc/installation.html#linux for help
```

と出たら、上のリンクに飛び、コマンドをフォローする。
それで、ODPI-Cをインストールすれば良い。


```
cx_Oracle.DatabaseError: ORA-12505: TNS:listener does not currently know of SID given in connect descriptor
```
Pythonのライブラリについて調べたらegg.info について少し理解した。

## 概要
自作したpythonライブラリをコードごとシェアしてわざわざビルドのための環境を作ってもらうのが申し訳なくなり、
もっと簡単な方法がないものかと考えて調べたところ、egg.infoについての理解が少し深まった。

## 

pythonのライブラリは```pip install```などでインストールしたり、
ソースコードから```python setup.py install```したりなどするが、

https://qiita.com/chatrate/items/eb4b05cd1a6652529fd9
ここにあるように、それらはpython環境の```site-packages```に格納されていた。
場所は、上のリンクにあるように

```bash
python -c "import site; print (site.getsitepackages())"
```
でわかる。

この際、シナリオとしてもし自分で作ったライブラリなどがあり、
依存関係がちょっとややこしいとする。そのときソースコードを誰かに渡してビルド環境を構築してもらいライブラリを試してもらうのが申し訳ない時がある。

そのときは、ここにあるライブラリのフォルダをコピーしてそれをそのまま渡せばそのままビルドなどをすっ飛ばして使えるのだが、少し気をつけなければならないことがあった。

## 気をつけること
実際自作ライブラリなどをつくって、コンパイルした後、site-packagesをみると

```　
*****-0.0.0-py3.6-linux-x86_64.egg　
```


みたいなフォルダがある。これをコピーして他の環境のsite-packagesにいれて、

```
python 
>>> import ****
```

みたいにしてもダメである。

この時は、このフォルダをコピーした後、site-packagesの中に入って、

```
easy_install *****-0.0.0-py3.6-linux-x86_64.egg　
```

としなければならない。
この際、このライブラリが参照するべきsoファイルなどがある時は、それらもあらかじめコピーして
あるべき場所(/usr/local/lib/)などの場所に格納を前もってしておき、
上のコマンドを走らせる必要がある。

ただし、site-packagesの中身が、

```
******16.dist-info
```

みたいな時は、コピーするだけで import できるので楽。

終わり。
【備忘録】「docker-compose exec 〜」で 「cd」 使いたい。

#  ■何が起きたんだ。
先日僕はこんな記事を上げました。
[【Mac】Laradock と PhpStorm を使って、Laravel + PHPUnit + Xdebug の簡単開発環境構築](https://qiita.com/Tatsuyaaaa/items/9b156e0330eb24819b84)

そうです。僕はこの記事の通りの環境を構築するために奮闘していたんですね。

今回Laradockで環境を立ち上げた後、Laravelをcomposerでインストールしました。
その時使ったコマンドがこちら↓

```bash
# docker-compose exec {コンテナ名} {実行コマンド}
# workspaceコンテナに、「composer create-project --prefer-dist laravel/laravel=6.* laravel-test」　のコマンドを実行する
$ docker-compose exec workspace composer create-project --prefer-dist laravel/laravel=6.* laravel-test
```

このように、`docker-compose exec`コマンドを華麗に使いこなし、優雅にローカル環境からコンテナ目掛けてコマンドを打っていました。

> 僕「よし、本当にLaravelが正しくインストールされたかを見てやろう」

そんな上から目線状態でこのコマンドを叩きました。

```bash
# 「php artisan --version」　はLaravelのバージョンを確認できます。
$ docker-compose exec workspace php artisan --version
```

するとこんなエラーが。

```bash
Could not open input file: artisan
```


> 僕「おー、そうだそうだ。`artisan`コマンドはLaravelプロジェクト内で実行するから、`laravel-test`ディレクトリに移動しなきゃだな。」

と思いましたが、ここで手が止まりました。

> 僕「あれ、そもそも2回の命令を同時に投げたい時どうすれば良いんだ。。。」

# ■ググってみたら最強にジャストミートな記事を発見。

> 検索ワード：「`docker-compose` `exec` `cd`」

.
..
...

![スクリーンショット 2020-04-22 0.17.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425581/23937ca1-b326-842d-a519-325069f64250.png)

> 僕「これこれぇ！！！！！！！！！！」

最強な良記事を発見しました。

どうやら実行するときは、2つポイントがあるみたいです。

- 「コンテナ名」と「実行コマンド」の間に`bash -c`を入れる。
- 実行コマンドは、`"実行コマンド1 && 実行コマンド2"` と、`&&`でコマンドで区切り、かつ `"`で囲む。

こちらに気をつけて、コマンドを作ってみると。

```bash
$ docker-compose exec workspace bash -c "cd laravel-test && php artisan --version"
```

実際に打ってみます。
結果がこちら。

```
Laravel Framework 6.18.8
```

.
..
...

### **やったぜ！！！！！！！**

# ■参考文献
[naughtLdyのメモ帳 - docker exec で cd する方法](https://naughtldy.hatenablog.jp/entry/2017/10/25/160000)
GatsbyでScssファイルを作成して読み込む方法

GatsbyでSCSSを書いたり、Bootstrap4のような外部ファイルを読み込む方法。

## GatsbyでSCSSを読み込むには

### Gatsbyの設定
まずは必要なモジュールをインストール。

```
npm install --save node-sass gatsby-plugin-sass
```

次に`gatsby-config.js`の`plugin`設定を追加。この設定を行うとコンパイルできるようになる。

プラグイン設定で圧縮形式などオプション設定も可能。
https://www.gatsbyjs.org/packages/gatsby-plugin-sass/

```js
module.exports = {
  ...
  plugins: [
    {
      resolve: `gatsby-plugin-sass`,
      options: {
        outputStyle: 'compressed', // nested, expanded, compact, compressed,
      },
    },
  ],
}
```

### SCSSを書く
ファイルの設置場所は`src`以下に置く、例えばこんな感じ。

```
src
  - styles
    - theme.scss
    - global
      - header.scss
      - footer.scss
    - components
      - card.scss
```

コンポーネント用スタイルなどはメインのファイルからインポートする。

```scss
// src/styles/theme.scss
@import 'global/header';
@import 'global/footer';
@import 'components/card';
```

### GatsbyでSCSSファイルを読み込み
ファイルを読み込む方法はいくつかある。

まず１つは`gatsby-browser.js`からグローバルスタイルとして読み込む方法。

```js
// gatsby-browser.js
import "./src/styles/theme.scss"
```

２つ目はレイアウトコンポーネントで読み込む方法。

```jsx
// src/components/layout.js
import React from "react"

import "../styles/theme.scss"

const Layout = ({ location, title, children }) => {

  return (
    <div className="wrapper">
      <main id="contents">{children}</main>
    </div>
  )
}

export default Layout
```

scss以外にもBootstrap4のような外部ファイルを同様にして読み込むことができる。
opensslのバージョンを下げる時に苦しめられた。

## 概要
openssl のバージョンを1.1.1から1.0.2に落とそうとした時にはまり、
1.0.2を用いてライブラリの関数の一部を構築しようとした時にはまったので備忘録。

## 出たエラー
```bash

bn.hh:47:9: note: suggested alternative: 'BN_print'
         BN_init(&b);
         ^~~~~~~
         BN_print
```
このようなエラーはopensslのバージョンの違いからくる。
参考 https://github.com/vertcoin-project/vertcoin-core/issues/43
この場合このライブラリは1.0系を使っている。
このため、1.0系へとダウングレードしてみて走るかどうかを検証したかった。

したがって以下のコマンドを実行。

```bash
wget http://www.openssl.org/source/openssl-1.0.2a.tar.gz
tar -xvzf openssl-1.0.2a.tar.gz
cd openssl-1.0.2a
./config --prefix=/usr/
make
sudo make install
```


これで

```bash
openssl version
```

をすると1.0.2系に落とせていることがわかったものの、ライブラリをビルドする時に

```bash
/usr/bin/ld: /usr/lib/libcrypto.a(cryptlib.o): relocation R_X86_64_PC32 against symbol `stderr@@GLIBC_2.2.5' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
error: command 'g++' failed with exit status 1
```

このようなエラーに散々悩まされたが、
openssl 1.0.2系のビルドの際に、

```bash
make clean
export CFLAGS=-fPIC
./config shared --prefix=/usr
```
とすることで解決した。



終わり。
公開ディレクトリ指定方法 Python 簡易HTTPサーバー 

PythonにはWEB開発用の簡易HTTPサーバー機能が備わっています。
便利なのですが、公開したいディレクトリ直下に公開用スクリプトを置く必要がある（と思い込んでました）ため不便であり、公開ディレクトリを指定する方法を調べただけです。

# 結論
(Python3.7以上対応)
以下__DIRECTORYにスクリプトからの相対パスを__入れればOK。

参考1 より引用

```python:server.py
import http.server
import socketserver

PORT = 8000
DIRECTORY = "web"

class Handler(http.server.SimpleHTTPRequestHandler):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, directory=DIRECTORY, **kwargs)


with socketserver.TCPServer(("", PORT), Handler) as httpd:
    print("serving at port", PORT)
    httpd.serve_forever()
```

## 参考1
[StackOverflow "How to run a http server which serves a specific path?"](https://stackoverflow.com/questions/39801718/how-to-run-a-http-server-which-serves-a-specific-path)
私が知りたいことそのまま書いていた。

#コードの意味
公開ディレクトリを特に指定しない場合は、以下のようなコードでよい。自動的にスクリプトの存在するディレクトリが公開ディレクトリとなる。
TCPServer()にハンドラを引数として渡すことで、TCPServer()の中でSimpleHTTPRequestHandlerのコンストラクタに適切な引数を入れている。だからこの__Handlerは関数ポインタ__のようなイメージ。（つまり、それが"ハンドラ"か。）

```python:ディレクトリ指定しない.py

Handler = http.server.SimpleHTTPRequestHandler
with socketserver.TCPServer(("", PORT), Handler) as httpd:
    print("serving at port", PORT)
    httpd.serve_forever()
```

で、上の結論のコードにおいて何をやっているかというとTCPServer()の中でSimpleHTTPRequestHandlerのコンストラクタを呼ぶという大枠は変えないで(以下のコードで言うところの*argsと**kwargs),
引数 directory に"任意の指定ディレクトリ"を渡すように__コンストラクタを上書き__している。

```python:難しかったところだけ調べた.py

#SimpleHTTPRequestHandlerの初期化関数を再定義
class Handler(http.server.SimpleHTTPRequestHandler):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, directory=DIRECTORY, **kwargs)

#ほんとはこれがやりたいのだけど、引数足りないエラーになる。
#引数はTCPServer()の内部で適当に入れているから、ここでは入れられない＆わからない。
Handler = http.server.SimpleHTTPRequestHandler(directory="web")

#これもだめ。当然だがargsってなんだよって言われる。
Handler = http.server.SimpleHTTPRequestHandler(*args,directory="web",**kwargs)
```

## 参考2
[python仕様書より http.server](https://docs.python.org/ja/3.7/library/http.server.html?highlight=http)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26413/4f327c44-f288-f5b7-b54c-27715b375ed3.png)

そう！やりたいのは以下のdirectoryに引数を入れたいだけなんだよ！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26413/c2ff66d8-51a1-178f-e9c1-a1789ddfbc4a.png)

## 参考3
[pythonで継承とsuper()を使って派生クラスをinitしてみよう](https://qiita.com/Anaakikutsushit/items/c67d4edb0c01a97f3130)
コンストラクタ上書きの部分がわからなくてお世話になりました。
[Pythonの可変長引数（*args, **kwargs）の使い方](https://note.nkmk.me/python-args-kwargs-usage/)
*argsのアスタリスクの意味が分からなくてお世話になりました。
Javaの変数使用方法に関して

## Javaの変数に関してのまとめ
Javaの変数に関して学習したことを、アウトプットします。
参考書籍：[スッキリわかるJava入門](https://www.amazon.co.jp/dp/B07ZQWKL2Q/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)

## 代表的な9種のデータ型 

| 分類 | 型名 | 格納するデータ | 使用頻度|
|:-----------|------------:|:------------:|:------------:|
| 整数       | byte       | とても小さな整数| △|
|     | short      | 小さな整数       |△|
|        | int        | 普通の整数 |     ◎   |
|          | long         | 大きな整数  |△   |
| 少数       | float       | 少し曖昧でも良い少数     | △ |
|     | double    | 普通の少数     | ○ |
| 真偽値     | boolean      | trueかfalse |   ○    |
| 文字       | char       | 一つの文字    |    △ |
| 文字列        | String         | 文字の並び     |  ◎  |



## 補足

 整数は、基本的に”int型”を使っていれば問題ない。 
 少数は、基本的に"double型"を使っていれば問題ない。 
 文字は、引用符で囲む。（'家'） 
 文字列は、二重引用符で囲む。（"家で踊ろう"） 


## 変数宣言の方法 

```java
 int = age;  //変数宣言 
 age = 22;  //ageに「22」を代入 
 // 又は 
 int age = 22;  //変数宣言と代入を一行で行う 

 System.out.println(age);  //出力
```