OmniAICreator/Qiita-1.07M huggingface dataset:
【備忘録】python開発環境構築してみた

T先輩で会社で教わった通りにまずはインストールしてみる

# まずはGit
　複数人でやるわけではないので不要？入れてみる。
　Git bashも。
　https://git-scm.com/

# 次にpython(anaconda3)
 インストール先は全ユーザー
　Pathを設定をyes
　とのこと。
　https://www.anaconda.com/distribution/

# 開発用IDE　Visual Studio Code
 anaconda3のインストール時に最後に聞かれるはず
 
 拡張機能入れておく
　・Japanese Language Pack
　・Python
　・Visual Studio IntelliCode
　サードパーティ
　・GitLens
　・Git History
pipenvでLockingが無限に終わらないとき

# 1. はじめに
`pipenv`で`Pipfile.lock`を生成するときに，無限に終わらない現象が僕にも起きた．そのとき試してダメだったこと，次善の策のまとめ．

# 2. 環境
- macOS Mojave 10.14.5
- pipenv, version 2018.11.26


# 3. Lockingが終わらない現象
ちなみに僕の場合`librosa`をinstallするところで起きた．

そのままだと大体

```python
pexpect.exceptions.TIMEOUT: <pexpect.popen_spawn.PopenSpawn object at 0x10e008d90>
searcher: searcher_re:
    0: re.compile('\n')
<pexpect.popen_spawn.PopenSpawn object at 0x10e008d90>
searcher: searcher_re:
    0: re.compile('\n')
```

という感じでタイムアウトする．
もしくは，

```shell
$ pipenv install
Pipfile.lock (e35831) out of date, updating to (a55cbb)…
Locking [packages] dependencies…
```

このLockingが全く終わらない．

# 4. 試してダメだったこと
## 4.1. `PIPENV_INSTALL_TIMEOUT`, `PIPENV_TIMEOUT` の設定を長くする．
似たようなissueが大量に引っかかって，そこでこれで解決したと言われてた方法．
これでもダメだった．今回の僕の場合は長くしても終わらなかった．

## 4.2. 仮想環境のpythonのバージョンを下げる
もともと`3.7.2`でやってたが，installしようとしているpackageが`3.6.8`ではCIが通っていたので`3.6.8`に下げたがダメだった．

## 4.3. pipのversionを下げる．
調べてみると`pipenv`のバージョンが`2018.7.1`ぐらいだった時代にpipのバージョンが新しすぎるとこの現象が起きていたらしい．
というわけで似たような感じかなと思って仮想環境内のpipのversionを`19.2.1`から`18.1`に下げた．ダメだった．
ちなみに`18.0`に下げてもダメだった．

# 5. うまくいった方法
## 5.1 `pip`を使う
`pipenv shell`で仮想環境内に入った後に，`pip install hoge`でインストールする．`pipenv install hoge`ではなく．

なんのための`Pipfile`だというお気持ちになるのでオススメはしない．

## 5.2 `Pipfile.lock`を生成しない
`PIPENV_SKIP_LOCK=true`の環境変数を定義しておくと`Pipfile.lock`を生成しなくなる．

```shell
$ PIPENV_SKIP_LOCK=true pipenv install
```

buildしたマシンの情報やpythonモジュールのversionのハッシュ値などが保存されていて，`Pipfile`を変更した時に差分だけインストールして早くなるとか旨味があるのだろうが，動かないよりはマシなのでなくてもいいと割り切る．


`Pipfile.lock`を生成しない方法としては，環境変数を指定する以外にも`pipenv install`時のオプションが準備されている．（[参考](https://pipenv-fork.readthedocs.io/en/latest/basics.html#pipenv-install)）

```shell
$ pipenv install --skip-lock
```

（これはコメントにて[515hikaruさん](https://qiita.com/515hikaru)に教えていただいたやり方です．感謝です．）



## 6. 終わりに
結論としてはlockしないという道しかなかったという事になる．
Leetcode #222: Count Complete Tree Nodes

```swift
func countNodes(_ root: TreeNode?) -> Int {
    let leftHeight = getLeftHeight(root)
    let rightHeight = getRightHeight(root)
    if leftHeight == rightHeight {
        return 1 << leftHeight - 1
    } else {
        return 1 + countNodes(root?.left) + countNodes(root?.right)
    }
}

func getLeftHeight(_ node: TreeNode?) -> Int {
    if node == nil {
        return 0
    }
    return 1 + getLeftHeight(node?.left)
}

func getRightHeight(_ node: TreeNode?) -> Int {
    if node == nil {
        return 0
    }
    return 1 + getRightHeight(node?.right)
}
```
HTMLで外部ファイル埋め込み：JavascriptやCSSを一個のhtmlファイルに詰め込む

# 概要
rmarkdownパッケージのpandoc_self_contained_html関数を使う。
あるhtmlファイル内で参照している外部jsファイルやcssファイルの内容を埋め込んだhtmlを新規作成して保存できる。
（試してないが参照している画像も埋め込まれるのではと思われる。）
全情報を一個のhtmlに詰め込んで、配布用にしたい場合に使う。
RNotebookでもこの仕組みを使っているように見える

# キーワード：
standalone html、self-contained html

# 仕様
rmarkdown::pandoc_self_contained_html(input, output)：
inputは入力用htmlファイルのパス。
outputは出力先のパス。


# 仕組み：
pandocではmarkdownをhtmlに変換する際に --self-contained モードで変換するオプションがある。
rmarkdownパッケージではこれをそのまま使っているようだ。

# 仕組みの細かい話：
pandocで「html->html」のself-contained変換は恐らくできない。未対応。
一方で、「markdown -> html」の変換は可能。
htmlファイルをmarkdownファイルであるとみなして、pandocの「markdown_strinct -> html」への変換をかけると、実質的に「html->html」のself-contained変換ができる。

<!--
また、「markdown_strict -> html」で変換することにしておけば、markdownファイル中でインデント等を使っていてもいい。
-->
【Rails】ridgepole導入

# 環境

- Rails 5.2.3
- [ridgepole](https://github.com/winebarrel/ridgepole) 0.7.8

# migrationからridgepoleに移行を検討したほうがよい状況とは？

- 多くの開発者がいて、migrationがコンフリクトする。
- 複数システムで同じDBを見ており、それぞれのシステムで同じschema情報が必要。
- 開発初期でschema情報がコロコロ変わる（※というわけで、はじめからridgepoleもお勧め）。

# Gemのインストール

```ruby:Gemfile
gem 'ridgepole'
```

# 現在のschema情報を元に、Schemafileを生成

```shell
bundle install ridgepole -c config/database.yml --export -o db/Schemafile

cat db/Schemafile
```

# 不要なファイルを削除

- db/schema.rb
- db/migrate/*

```shell
git rm db/schema.rb
git rm -r db/migrate/
```

# rake taskを追加

```ruby:lib/tasks/ridgepole.rake
# frozen_string_literal: true

namespace :ridgepole do
  desc 'Apply database schema'
  task apply: :environment do
    ridgepole('--apply')
  end

  desc 'Export database schema'
  task export: :environment do
    ridgepole('--export')
  end

  private

  def ridgepole(*options)
    command = ['bundle exec ridgepole -f db/Schemafile', '-c config/database.yml', "-E #{Rails.env}"]
    system((command + options).join(' '))

    unless Rails.env.production?
      Rake::Task['db:schema:dump'].invoke
      Rake::Task['db:test:prepare'].invoke
      Rails.root.join('db/schema.rb').delete
    end
  end
end
```

以下を参考にさせて頂きました。

- https://qiita.com/lhside/items/0dcad79d9b801e34bc7c
- https://qiita.com/tos-miyake/items/a2e8cde4bff965713e0c
- https://hokaccha.hatenablog.com/entry/2018/05/09/000951

# rails_helper修正

このままでは、`rspec`コマンドを実行した際に、`rails_helper`内で`ActiveRecord::Migration.maintain_test_schema!`が実行され、TEST環境のテーブルが全て削除される。

```
/Users/foo/src/github.com/bar/baz/db/schema.rb doesn't exist yet. 
Run `rails db:migrate` to create it, then try again.
If you do not intend to use a database, 
you should instead alter /Users/foo/src/github.com/bar/baz/config/application.rb to limit the frameworks that will be loaded.
```

migrationは使わないので、`rails_helper`の以下の行をコメントアウト（または削除）する。

```ruby:spec/rails_helper.rb
# ActiveRecord::Migration.maintain_test_schema!
```

# rspec実行前に、db schemaが作成されるようにする（※任意）

```ruby:spec/spec_helper.rb

require 'rake'
 :
 :

RSpec.configure do |config|
  config.before(:suite) do
    Rails.application.load_tasks    
    Rake.application['ridgepole:apply'].invoke
  end
end
```

# Circle CIの設定変更（※任意）

もし、↑の変更をしない場合は、Circle CIでdb schemaが作られるように以下の設定をする。

```ruby:.circleci/config.yml
      - run:
          name: Database setup
          command: bundle exec rails ridgepole:apply RAILS_ENV=test
```

# 以降、modelをgenerateする時は、`--skip-migration`を付けるのを忘れずに。

```shell
rails g model Foo --skip-migration
```
スターリンの勢いに乗っておこう

# 仕様のようなもの
数値は画面から入力
最大10個
0を入れられたらそこで終了
折角だから(?)リスト構造で粛清感を出してみる。
優しいので(?)同値の粛清は勘弁してあげる。

## 逃げ口上
今どきこの書き方・・・とかいうのは勘弁してください。
サックリ作って動けばOK
入力のバリデーション？なにそれ？

## 環境
WSL上のubuntu(18.04.2)
gcc7.4.0

## ソース
```stalin.c
#include<stdio.h>
#include<stdlib.h>

#define MAX 10

typedef struct v{
    unsigned int value;
    struct v *next;
}LIST;

void eliminate(LIST*);
void purge(LIST*);

void main(void){
    LIST top,*p,*c;

    top.next=NULL;
    p=&top;

    for(int i=0;i<MAX;i++){
        c=malloc(sizeof(LIST));
        if(c==NULL){
            fprintf(stderr,"No enough memory.");
            exit(1);
        }
        printf("%2d= ",i+1);
        scanf("%d",&c->value);
        if(c->value==0){
            free(c);
            break;
        }
        c->next=NULL;
        p=p->next=c;
    }

    eliminate(top.next);

    for(p=top.next;p!=NULL;p=p->next){
        printf("%d,",p->value);
    }
    putchar('\n');
}

void eliminate(LIST *p){
    while(!(p==NULL || p->next==NULL)){
        if(p->value > p->next->value){
            LIST *target=p->next;
            p->next=p->next->next;
            purge(target);
        }else{
            p=p->next;
        }
    }
}

void purge(LIST *target){
    free(target);
}
```

## 解説的なもの
肝心な`eliminate`とネタ的に`purge`を関数化してみました。
whileの条件がややこしいのはNULLアクセスでコケさせたくなかったのが表れてます。
ただし処理系とかコンパイラによってはwhileがうまく動かないかもしれません。
左から順に評価して、その時点で評価が確定したら後ろには行かないことを期待しています。
basename ：実行ファイルのファイル名を変数に代入する[備忘録]

# やりたいこと
 出力ファイルの名前をつけるときに、実行しているスクリプト名や引数に取っているファイル名をいじったものをつけたい。
 ただ、パスは長くなるのでいらない。拡張子も同様

　でも毎回手で入力するとしんどい

# 環境
レッドハットエンタープライズのCentOS 7です。

```
bash-4.2$ uname -r
3.10.0-957.5.1.el7.x86_64
bash-4.2$ cat /etc/redhat-release 
CentOS Linux release 7.6.1810 (Core) 
```

## basename
ファイル名からディレクトリと接尾辞を取り除いてくれるすごいコマンド

とりあえずman コマンドで使い方を。
>basename, dirname -- return filename or directory portion of pathname

気が利きますね。という感じ
>SYNOPSIS
      basename string [suffix]
      basename [-a] [-s suffix] string [...]
      dirname string

dirname でdirが取れるのは初めて知った。

これだけでは、どんなコマンドかわからないので、説明をみると、
>The basename utility deletes any prefix ending with the last slash `/'
     character present in string (after first stripping trailing slashes), and
     a suffix, if given.  The suffix is not stripped if it is identical to the
     remaining characters in string.  The resulting filename is written to the
     standard output.  A non-existent suffix is ignored.  If -a is specified,
     then every argument is treated as a string as if basename were invoked
     with just one argument.  If -s is specified, then the suffix is taken as
     its argument, and all other arguments are treated as a string.

とあるので、最後の/まで切ってくれる上に、suffix（接尾辞）を指定してあげると（最後につくなら拡張子でなくても)消去してくれるみたい。
　ただし、接尾辞が文字中に複数ある場合は消去しないみたい。

# コマンド
##例1　shellスクリプトのファイル名をprefixにしたいとき


```
prefix=`basename $0 .sh`
```

##例2　PATH aにあるtxt fileをprefixにする

```
prefix=`basename PATH/TO/TXT/FILE/~.txt .txt`
```

で〜がprefixに入る。

##例3　複数のパスを繋げる
　basename -a オプション,出力をデフォルトの改行ではなくnullにする^z オプションを使う
　例えば、スクリプト名と引数1の名前を繋げたい時には、

```
`prefix -a -z $0 $1`
```

###注
-z　オプションがあるかは環境によりそうです。（ちなみに僕のMac 10.14　にはなかった。)
また、-a optionをつけるとsuffixはつけれなさそう。。（多分方法はあるんだろうけど不明）

##例４　basenameの結果を変数に渡す
どの程度まで変数を代入できるのかが全くわからない。
このぐらいまで分解しないと実行できなかった。また調べる。

```test.sh
li_asm=("0" "3" "5" "10" "20" )
li_min_ol=("0" "1000" "2000" "5000" "10000" )
seq_path=("${read_１}" "${read_2}")

a=$((SGE_TASK_ID%5))
b=$((SGE_TASK_ID/5%5))
c=$((SGE_TASK_ID%2))

asm=${li_asm[a]}
min_ol=${li_min_ol[b]}
seq=${seq_path[c]}
echo " seq = ${seq}"

prefix="$(basename ${seq} .fq)_${asm}_${min_ol}"  
out_dir="${work_dir}/flye/${prefix}"
```

ちゃんと演算子を入れることはできる。
less コマンドよく使うもの[備忘録]

# less コマンド
ファイルの中身を見るときに使うもの
head とかと違って全体がみれる上、moreよりも検索機能とかがあるので便利
## コマンド
`less file_name`
で使える
`file_name` には複数のファイルを指定できる。space 区切り
:nで次のファイル、:pで前のファイル

*が使えるので、エラーファイルやスクリプトファイルを一気に確認したいときによく用いる
例　`less *.sh`

## 検索
less を使って開いた画面の中で
/検索したい文字　で検索（カーソル位置より後方検索）
?検索したい文字　で検索（カーソル位置より前方検索）

## 行を表示する
`less -N`
Python3のdatetimeに存在するnaiveとawareについて

Pythonの日付変換の処理を書いていた時にハマったので、
アウトプットしておきます。

##環境
Python3.7
##datetimeについて

Pythonでは日時や時間を利用する際に、標準ライブラリとしてdatetimeが用意されており、
datetimeにはnaiveとawareというものが存在します。

とりあえず試しに現在日時をそれぞれ別の方法で取得してみます。
※変数名が悪いとかはスルーしてください。

```Python
import time
from datetime import datetime

if __name__ == "__main__":

    now1 = datetime.now()
    print(now1)

    time.sleep(3)

    JST = timezone(timedelta(hours=+9), 'JST')
    now2 = datetime.now(JST)
    print(now2)

    if now1 < now2:
        print('hello world')
```

そうするとこのような例外が発生しました。

```console
2019-07-31 19:07:06.168798
2019-07-31 19:07:09.170117+09:00
例外が発生しました: TypeError
can't compare offset-naive and offset-aware datetimes
```

##ここに書かれていたnaiveとawareの違いについて

Pythonのドキュメントにも書いてありました。
>aware オブジェクトは他の aware オブジェクトとの相対関係を把握出来るように、タイムゾーンや夏時間の情報のような、アルゴリズム的で政治的な適用可能な時間調節に関する知識を持っています。aware オブジェクトは解釈の余地のない特定の実時刻を表現するのに利用されます 。

>naive オブジェクトには他の日付時刻オブジェクトとの相対関係を把握するのに足る情報が含まれません。あるプログラム内の数字がメートルを表わしているのか、マイルなのか、それとも質量なのかがプログラムによって異なるように、naive オブジェクトが協定世界時 (UTC) なのか、現地時間なのか、それとも他のタイムゾーンなのかはそのプログラムに依存します。Naive オブジェクトはいくつかの現実的な側面を無視してしまうというコストを無視すれば、簡単に理解でき、うまく利用することができます。

##つまり…

naiveはタイムゾーン情報を持たないdatetimeオブジェクトで、
awareはタイムゾーン情報を持ったdatetimeオブジェクトと言い換えることが出来そうです。

さらにnaiveとawareは比較出来ないようです。
普通に考えて、どこの時間か分からないnow1と日本時間として設定したnow2を
比較出来る訳がなかったということですね。

間違いあればご指摘頂けると幸いです。

##参考
datetime --- 基本的な日付型および時間型
https://docs.python.org/ja/3.7/library/datetime.html
<webview>からBrowserViewへの移行


これは [Gotanda.js #12 in ZEALS](https://gotandajs.connpass.com/event/132152/) で発表した内容からTIPSを抜き出した記事です。

元Slide: https://speakerdeck.com/nekobato/migration-to-browserwindow-in-electron

``` package.json
{
  "dependencies": {
    "electron": "5.0.4",
  },
}
```

Electron公式では`BrowserView`を`<webview>`の代わりに使うことを推奨しています。

BrowserViewは可能な操作が`<webview>`に比べてまだ少なく、またmain process上で管理するため、`<webview>`とは些か勝手が違ってきます。
ここでは、`BrowserView`で`<webview>`を操作してきた手法を置換するためのTIPSを紹介します。

### 基本的な操作

Before

``` webview.js
const webview = document.querySelector('webview');

// 表示するWeb Pageを変更する
webview.src = 'https://yahoo.co.jp';

// 戻れるなら戻る
if (webview.canGoBack()) {
  webview.goBack();
}

// いけたらいく
if (webview.canGoForward()) {
  webview.goForward();
}

// 更新
webview.reload();
```

After

``` BrowserView-renderer.js
const { ipcRenderer } = require('electron');

ipcRenderer.send('SET_URL', { url: 'https://yahoo.co.jp' });
ipcRenderer.send('BACK');
ipcRenderer.send('FORWARD');
ipcRenderer.send('RELOAD');
```

``` BrowserView-main.js
ipcMain.on('SET_URL', (_, payload) => {
  webView.webContents.loadURL(payload.url);
});

ipcMain.on('BACK', () => {
  if (webView.webContents.canGoBack()) {
    webView.webContents.goBack();
  }
});

ipcMain.on('FORWARD', () => {
  if (webView.webContents.canGoForward()) {
    webView.webContents.goForward();
  }
});

ipcMain.on('RELOAD', () => {
  webView.webContents.reload();
});
```

基本的にRendererとコミュニケーションしたい場合はイベントを送るという手法を採用しています。

### URLの変更をRendererで検知する


``` js
function setUrl(url: string): void {
  mainWindow.webContents.send(types.SET_URL, {
    url,
    // ついでにcanGoBackとcanGoForwardを報告する
    canGoBack: webView.webContents.canGoBack(),
    canGoForward: webView.webContents.goForward(),
  });
}

webView.webContents.on('did-navigate', (_, url) => {
  setUrl(url);
});

webView.webContents.on('did-navigate-in-page', (_, url) => {
  setUrl(url);
});
```

### サイズを可変にする

#### ウィンドウサイズに合わせて可変にする

``` BrowserView-main.js
mainWindow.on('will-resize', (_, { width, height }) => {
  webView.setBounds({
    x: 0,
    y: 0,
    width,
    height,
  });
});
```

#### レイアウトに合わせて可変にする

``` BrowserView-renderer.js
const webviewArea = document.querySelector('.webview-area');
ipcRendeerer.send('SET_BOUNDS', {
  x: webviewArea.offsetLeft,
  y: webviewArea.offsetTop,
  width: webviewArea.innerWidth,
  height: webviewArea.innerHeight
});
```


``` BrowserView-main.js
ipcMain.on('SET_BOUNDS', (_, { x, y, width, height }) => {
  webView.setBounds({
    x,
    y,
    width,
    height
  });
});
```

### DevToolsを開く時に邪魔なので隠す

BrowserViewはWebおよびDevToolsよりも上に重なって表示されるため、BrowserWindowに表示されているWebのデバッグ中は邪魔です。DevToolsを表示中は隠す処理を書いておくと便利です。

``` BrowserView-main.js
mainWindow.webContents.on('devtools-opened', () => {
  webView.setBounds({
    x,
    y,
    // hide() みたいな便利な関数は無いので、見えないようにサイズ変更する
    0,
    0
  });
});

mainWindow.webContents.on('devtools-closed', () => {
  webView.setBounds({
    x,
    y,
    defaultWidth,
    defaultHeight
  });
});
```

### BrowserViewの見た目をCSSで変えたい

無理だよ
Amplify (js)の PubSubを使ってAWS IoT Core にメッセージをPublishする

* Amplify からAWS IoT CoreへMQTTのメッセージをPublishしたく、試しました。（vueを利用した場合の実装例です）
* CognitoのFederated Identity を利用して認証機能を実現します。
 * https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/identity-pools.html


# 基本的なやりかた
https://aws-amplify.github.io/docs/js/pubsub

### MQTT 接続

``` js
Auth.currentCredentials().then(info => {
  const cognitoIdentityId = info._identityId;
  console.log("cognito identity id", cognitoIdentityId); // debug
    Amplify.addPluggable(new AWSIoTProvider({
        aws_pubsub_region: 'ap-northeast-1',
        aws_pubsub_endpoint: 'wss://xxxxx.iot.ap-northeast-1.amazonaws.com/mqtt',
        clientId: 'your-client-id'
       }));
});
```
### Cognito ログイン画面
``` html
    <amplify-authenticator></amplify-authenticator>
```

### publish
``` js
import { PubSub } from 'aws-amplify';
export default {
  // 中略
  methods: {
    publish: async function () {
        await PubSub.publish('v1/topic/abc', {
            "key": "value"
        });
    }
  }

```

# ハマったところ
`errorCode: 8, errorMessage: AMQJS0008I Socket closed.`

PubSub.publishのエラーで上記が出た。

こちらの記事を参考にして、Cognito のIdentity IDに対して、コマンドライン上からIoTのポリシーをアタッチすることで解決しました。
https://qiita.com/poruruba/items/34d4d7247d152b1ec933

``` sh
aws iot attach-policy --policy-name "<IoT Coreで作成したポリシー>" --target <Identity ID>
```
Identity ID は、GUI上で、CognitoのFederated Identity のページで、Identity Browserを選択すると表示されます。上述のMQTT接続のところで、 `info._identityId;` でも取得できます。
openpyxlで改ページをしたい

# 目的
openpyxlでグラフ挿入しつつ、グラフの途中で改ページされないようにしたい

# ググった
- 一番最初に参考にした記事（このままだと動かない）
    - https://stackoverrun.com/ja/q/9970846

```python
from openpyxl import Workbook 
from openpyxl.worksheet.pagebreak import Break 

wb = Workbook() 
ws = wb.active 
row_number = 20 # the row that you want to insert page break 
page_break = Break(id=row_number) # create Break obj 
ws.page_breaks.append(page_break) # insert page break 
```

# 結論
#### `ws.page_breaks[0].append(page_break)`
で解決できます。

## ドキュメントを確認
- ws.page_breaksを調べる
    - https://openpyxl.readthedocs.io/en/stable/_modules/openpyxl/worksheet/worksheet.html
    - どうやらpage_breaksはリストのよう。だからappend使えてたのね。

```python
class Worksheet(_WorkbookChild):
    ...
    def _setup(self):
        self.row_breaks = RowBreak()
        self.col_breaks = ColBreak()
        self.page_breaks = [self.row_breaks, self.col_breaks]
    ...
```

- Rowbreak, ColBreakを調べる
    - https://openpyxl.readthedocs.io/en/stable/_modules/openpyxl/worksheet/pagebreak.html#PageBreak
    - `brk = Sequence(expected_type=Break, allow_none=True)`
        - Breakはここに追加すれば良いみたい
    - `def append(self, brk=None): ...`
        - PgaeBreak.append(Break)で追加されるっぽい<br>
       　  → `ws.page_breaks[0].append(page_break)` やん

```python
class PageBreak(Serialisable):

    tagname = "rowBreaks"

    count = Integer(allow_none=True)
    manualBreakCount = Integer(allow_none=True)
    brk = Sequence(expected_type=Break, allow_none=True)

    __elements__ = ('brk',)
    __attrs__ = ("count", "manualBreakCount",)

    def __init__(self,
                 count=None,
                 manualBreakCount=None,
                 brk=(),
                ):
        self.brk = brk


    def __bool__(self):
        return len(self.brk) > 0

    __nonzero__ = __bool__

    def __len__(self):
        return len(self.brk)


    @property
    def count(self):
        return len(self)


    @property
    def manualBreakCount(self):
        return len(self)


    def append(self, brk=None):
        """
        Add a page break
        """
        vals = list(self.brk)
        if not isinstance(brk, Break):
            brk = Break(id=self.count+1)
        vals.append(brk)
        self.brk = vals



RowBreak = PageBreak
```
AndroidX移行 gradleファイル編

AndroidX に移行する場合に少しハマったのでメモしておく

#1.影響範囲が大きいので少しずつ変えたい
移行したいが影響が怖いので少しずつ移行したいとか、自分の担当範囲だけ移行したいという人向けの方法
AndroidX に移行する為、build.gradle の dependencies の記載を変えていくのだが、何に変えるのかというと
↓に公式サイトにマッピング表があったのでこれを見ながら移行すると簡単だった。
[Android Developer 公式 AndroidX への移行](https://developer.android.com/jetpack/androidx/migrate)

##移行例
EmptyActvityの場合
(Start a new Android Studio project からプロジェクトを新規作成するテンプレート一覧の中のActivity)

```gradle:build.gradle
dependencies {
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
}
```

を移行するのであれば


```gradle:build.gradle
dependencies {
    implementation 'androidx.appcompat:appcompat:1.0.２'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
}
```

として、そして、Sync Now をクリック
（※最新版でない場合AndroidStudioがワーニングを出すのでそれに従って再度更新する）

そのあとソースコードのエラーを直していけばよい
面倒だが少しずつ移行できる

#2.影響範囲は気にせず自動で全て変換
AndroidStudioの機能を使う
小さいプロジェクトであればこの方法が良い

Refactor > Migrate to AndroidX

![Screen.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264726/5c5000b2-ebc9-28ce-a501-35bf8bb1818c.png)

細かいところまで自動で変換してくれる！

#AndroidXとは
新しいAndroid拡張機能ライブラリ
これまでのSupportライブラリは今後AndroidXになっていくとGoogle I/Oで発表された
ssh_exchange_identification と MaxStartups

# 背景
某システムで、ssh 接続した際に下記のようなエラーが稀に出るという現象が発生し出しました。

```
ssh_exchange_identification: Connection closed by remote host
```

このエラー自体はよく見かけるエラーで、IP アドレスが間違っているとか、フィルタリングされているとか、基本的に設定や接続方法に問題があるというイメージでした。
実際、少しググって見ましたが、やはり上記のようなケースの情報がほとんどで、これらのケースでは問題を解決しない限りは何度実行してもこのエラーが 100% 発生します。
従って、**稀に発生する** 今回の現象は明らかに異なる原因でした。

結論としては、`MaxStartups` という sshd の設定値が関係しており、この設定値を引き上げることで問題が解決しました。
自分的な感覚では少々レアな現象だったと思うので、メモ的に残しておこうと思います。

# MaxStartups とは

sshd_config の日本語訳では下記の様に記載されています。

> MaxStartups (最大起動数)
    認証されていない段階の接続をSSH デーモンが最大でどれだけ受けつけるかを指定します。
    この値を超えた (認証されていない段階の) 接続は捨てられます。
    この状態は (すでに接続したクライアントの) 認証が成功するか、そのLoginGraceTime(ログイン猶予時間) が切れるまで続きます。
    …

つまり ssh 接続した瞬間から認証OKとなるまでの間の最大接続数です。
他のサイトを見ていると単なる同時接続数のように記載しているサイトが非常に多い印象ですが、単純な ssh の同時接続数ではありません。
あくまでも、**ssh 接続した瞬間から認証OKとなるまで** の非常に短い間の同時接続数です。
認証OK後の接続数は MaxStartups には無関係ですので注意が必要です。

## 設定値
CentOS7 などのデフォルト設定では `10:30:100` になっています。
これは、非認証な接続が 10 を超えるとそれ以降の接続を 30% の確率で拒絶し、さらに 100 に達した時点でそれ以降の接続を全て拒絶するという設定になります。
通常、非認証な接続が一気に 10 も来ることはほとんどの環境では無いと思いますので、いわゆる不正アクセス対策のための設定と考えて良いと思います。
上記の **拒絶** パターンの際に、下記のエラーが表示されます。

```
ssh_exchange_identification: Connection closed by remote host
```

今回は、この `MaxStartups` の値を引き上げることで問題を解消することができました。

## 2019/09/09 追記

hiroaki_sengoku さんより、下記のように指摘をいただきました。（コメント欄参照）

> MaxStartups の値を引き上げるのは、ssh サーバの負荷をそれだけ上げてしまうことになってしまうのではないでしょうか？

まったくもってその通りです。

本来は、**背景** に記載しておくべきだったのですが、本文中で下記のように解消したと書いた環境はインターネットに接続していないプライベートな環境、つまり不正アクセスが皆無な環境下でした。

> 今回は、この `MaxStartups` の値を引き上げることで問題を解消することができました。

従って、本稿は不正アクセスが大量に来ることによって引き起こされる `ssh_exchange_identification` の問題を `MaxStartups` の値を引き上げることによって解消することを勧めるものではありません。
※場合によっては効果も見込めますが、良い方法ではない

本稿はあくまでも、`ssh_exchange_identification` と `MaxStartups` の関係に焦点を絞った内容となります。

不正アクセスに対する対応については、これも hiroaki_sengoku さんがコメント欄で書かれていますが、iptables などで sshd に接続する前に対処するのが王道でしょう。
もう少し詳しい話が下記に記載されていますが、この方法はスマートでとても良いと思います。 
https://www.facebook.com/sengoku.hiroaki/posts/2380178762095810 

# おまけ
非常に短い時間での同時接続数なので、普通の手段で行なっていてはかなり面倒なことになります。
ただ単にエラー表示を再現させるだけなら、1 とか 2 あたりの小さな数値を設定すれば簡単に再現できますが、例えば 10 だったものを 20 にするとどの程度効果があるのか？といった検証では、最低でも 10 以上の同時接続を発生させる必要があります。
真面目にマルチプロセス／マルチスレッド的なプログラムを作成しても良いですが、私は Mac の Iterm2 の Broardcast Input を使ってこの検証を行いました。
この方法だと、単純に同時接続を発生させたい分だけターミナルを開いて一気に実行でき、結果も単純に個々のターミナルを確認すれば良いだけなのでとてもお手軽です。
IntelliJが起動出来なかった時(Mac, idea:2019.2)

コンソールで起動してみたら

```sh
$ /path/to/IntelliJ/Contents/MacOS/idea
2019-07-31 18:58:10.483 idea[1064:19215] allVms required 1.8*,1.8+
2019-07-31 18:58:10.487 idea[1064:19219] Value of IDEA_VM_OPTIONS is (null)
2019-07-31 18:58:10.487 idea[1064:19219] Processing VMOptions file at /Users/Leo.K/Library/Preferences/IntelliJIdea2019.2/idea.vmoptions
2019-07-31 18:58:10.487 idea[1064:19219] Done
OpenJDK 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated in version 9.0 and will likely be removed in a future release.
Error occurred during initialization of VM
Initial heap size set to a larger value than the maximum heap size
```

/Users/Leo.K/Library/Preferences/IntelliJIdea2019.2/idea.vmoptionsファイル削除

```sh
$ mv /Users/Leo.K/Library/Preferences/IntelliJIdea2019.2/idea.vmoptions /tmp/
```
C++でスターリンソート

#スターリンソートとは
配列を強引にソートします
ソートされていない要素は粛清(削除)されます

例）
[1,5,2,4,6,6,4,8]
これをソートすると
[1,5,6,8]
となる

※ネタかつ初心者クオリティのコードになりますのでご注意ください
作成に当たり先駆者様のコードを参考にしています

###参考にさせて頂いた先駆者様
[計算量O(n)の画期的なソートアルゴリズムであるスターリンソートをHaskell で実装してみた #Haskell]
(https://qiita.com/Tatsuki-I/items/380d6bd06515b872b2b2) 
[計算量O(n)で噂のスターリンソートを実装してみた]
(https://qiita.com/MeilCli/items/721526d716851e92192a)
[話題の粛清ソートアルゴリズム「スターリンソート」をPythonで実装した]
(https://qiita.com/Sirloin/items/c9e5c74be3366df65bce)


#実装
```StalinSort.cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
    vector<int>data={1, 2, 1, 1, 4, 3, 9};

    int tmp=data[0]-1;

    for(int i=0;i<data.size();++i){
        if(tmp>=data[i]){
            data.erase(data.begin()+i);
            --i;
        }else{
            tmp=data[i];
        }
    }
    for(int j=0;j<data.size();++j){
        cout<<data[j]<<endl;
    }
}
```

実行結果

```
1
2
4
9
```

##まとめ
たぶんこれで大丈夫、、なはず、、
何か変な部分があったら教えてください
Splunkのサーチモードの違いについて

いまいち自分でもちゃんと理解しきれていないところがあったので、サーチモードの違いについて整理しました。
# TL:DR
- Splunkは「高速モード」「スマートモード」「詳細モード」というサーチモードがあるよ
- Splunkデフォルトのサーチモードはスマートモードだよ
- Splunkはサーチモードと変換コマンドの有無によって、フィールドの自動抽出をするか判断するよ
- 変換コマンドとはSplunkのサーチコマンドの区別の一種だよ
- フィールドの自動抽出はデータの中身からフィールドと値の組み合わせをSplunkが自動判断してくれる機能だよ
- フィールドの自動抽出はする時よりしない時のほうがサーチ結果を返すスピードが速いよ
- 高速モードは自動抽出しないから他のモードよりサーチ結果を返すスピードが速いよ

# サーチモードとは
 - Splunkはサーチ時に3種類のサーチモードを選択することができます。
 - Splunkはサーチ実行時にサーチ文に変換コマンドが含まれているかによってフィールドの自動抽出を行います。
 - サーチモードは、保存済みサーチ(レポート/アラート)ごとに設定を保存できます。
 - ダッシュボードのサーチは高速モードになります。

| モード | 概要 |
|:-:|:--|
| 高速モード(Fast) | 変換コマンドの有無によらずフィールドの自動抽出を行わない。 |
| スマートモード(Smart) | 変換コマンドがある場合はフィールドの自動抽出を行わず、変換コマンドがない場合はフィールドの自動抽出を行う。※Splunkデフォルトのサーチモード |
| 詳細モード(Detail) | 変換コマンドの有無によらずフィールドの自動抽出を行う。|

変換コマンド？フィールドの自動抽出？は次項に説明します。

# 変換コマンドと非変換コマンドとは
Splunkはサーチ時に様々なSplunk専用コマンド(※)を組み合わせてサーチを行うことができますが、コマンドに応じて変換サーチ(transforming search)と非変換サーチコマンド(non-transforming search)という区別がされています。

※Splunk専用コマンドのことをサーチ処理言語(SearchProcessingLanguage as SPL)と呼んだりします。

|種類| 主なコマンド |
|:-:|:--|
|変換| stats,table,chart,timechart,top,rare,geostats,xyseries|
|非変換| 上記以外* |
ざっくりいうと、サーチ結果を表形式などに"変換"するコマンドを変換という扱いにしているようです。*詳細はマニュアルをご参照ください。
https://docs.splunk.com/Documentation/Splunk/latest/Search/Aboutreportingcommands
https://docs.splunk.com/Documentation/Splunk/latest/SearchReference/Commandsbytype#Transforming_commands

##フィールドの自動抽出とは
データに gendar=male など、Key=Valueという文字列が含まれている場合に、Splunkがその組み合わせを「フィールド＝値」として自動的にフィールドの抽出をしてくれる機能です。
※json/csv/xmlなど構造化データをサーチする場合もある程度データ構造に従って自動抽出してくれるようです。

フィールド自動抽出は便利な機能ですが、一般的にサーチにかかる時間が自動抽出をしない場合より長くなります。特に1つのデータにたくさん文字列が含まれていると、それだけ自動抽出にかかる時間を要することになります。高速モードは自動抽出を一切行わないため、自動抽出を行うモード（スマート/詳細）よりもサーチが"高速"になります。

## まとめ

サーチモードとフィールドの自動抽出の関連をまとめると以下になります。

| ↓サーチ文に       || 高速モード | スマートモード | 詳細モード |
|:-:|--:|:-:|:-:|:-:|
| 変換コマンドがある    |→| フィールド自動抽出しない | フィールド自動抽出しない | フィールド自動抽出する |
| 変換コマンドがない |→| フィールド自動抽出しない | フィールド自動抽出する | フィールド自動抽出する |

### （余談1）サーチモードの使い分けについて
Splunkにデータを取り込んだ初期段階で、データに「どんなデータが含まれているか？」「データの出現回数や頻度に何らかの傾向があるか？」といったことが判っていることは少ないと思います。スマートモードや詳細モードはそのような場合に"あたり"をつけるのに向いていると思います。
一方、データの分析がある程度進み、結果をダッシュボードやレポートで見せる段階では高速モードを使って必要最低限のフィールドを表示する(処理する)・・・というのがSplunkを使ってデータ分析結果を活用するにはベターかなと思います。

### （余談2）保存済みサーチ(レポート/アラート)のサーチモードについて
保存済みサーチ（レポート/アラート）のサーチモードは、保存した時点のサーチモードが適用されます。つまり、詳細モードで実行したサーチを保存すると、その保存済みサーチは詳細モードで実行されます。（手動実行した場合のみ。）

一度保存したサーチのサーチモードを変える方法は、2019/7/31時点の最新版(7.3.0)では3通りのやり方があるようです。
1.「サーチ、レポート、アラート」画面で変更したいサーチの「編集」リンクから「詳細編集」（Advanced Edit）を開き、パラメータdisplay.page.search.modeの値を変更する。

2.保存済みサーチをサーチで開き、サーチモードを変更した状態で再度サーチを実行し、その状態で上書き保存する。

3.設定ファイル(savedsearches.conf)を直接修正する。※修正後に要splunk再起動

なお、現最新バージョン(7.3.0)のSplunkのGUIでは「サーチ、レポート、アラート」画面上で保存済みサーチのサーチモードを確認することができないようです。このあたり、次バージョン以降改善してほしいなあと思います。。。
hostsファイルの設定を即時反映させる方法

hostsファイルを変更してもブラウザで反映されず、再起動してみたり、シークレットウインドウを開いてみたりと検証作業などで手間取ることがあったので調査。

## 検証環境
- Windows 10 pro
- Google Chrome 75.0.3770.142
- Opera 62.0.3331.99
- Firefox 68.0.1
- Internet Explorer 11.1387.15063.0
- Edge 40.15063.674.0
- Safari 5.1.7


## Google Chrome / Opera
- hostsファイルを変更
- 下記ページにアクセスして「Clear host cache」ボタンを押してホストキャッシュをクリア
　[chrome://net-internals/#dns](chrome://net-internals/#dns)

- 下記ページにアクセスして「Flush socket pools」ボタンを押してソケットプールの消去
  [chrome://net-internals/#sockets](chrome://net-internals/#sockets)

## Firefox

`about:config` とアドレスバーに入力して `network.dnsCacheExpiration` を0にするとキャッシュを使わずに名前解決をするようになるのでhostsが即時反映される。

## Internet Explorer / Edge / Safari

- ブラウザの再起動以外の方法での即時反映方法がわからなかった。
- Chromeと同じようにDNSキャッシュの削除 + ソケットプールの消去で実現できると思って調査したが後者の方法がわからなかった。DNSキャッシュの削除方法を参考までに下記に記載。

### DNSキャッシュの削除

1. コマンドプロンプトなどを使って `ipconfig /flushdns` を実行
2. `ipconfig /displaydns` を実行してDNSキャッシュを確認する

### ソケットプールの削除

？？？？？？？？？

## まとめ

Chrome / Operaの方法が一番ラクで確実。

Firefoxの方法は設定を直接変更してDNSキャッシュを使わないようにするので検証以外の用途で使う場合は素直に再起動する方法が良いかもしれない。

IE,Edge,safariに関しては再起動。
プログラミング初心者が気づかないホームページ作成の罠

[未来電子テクノロジー](https://www.miraidenshi-tech.jp/intern-content/program/)でインターンをしている<@y_mishima_miraidenshi>です。
プログラミング学習を始めて1ヶ月ほど経過し、現在ホームページ作成に取り組んでいます。
その際、僕が解決に手間取ってしまった問題を忘れないよう記録しておこうと思います。
プログラミング初心者であるため、内容に誤りがあるかもしれません。
もし、誤りがあれば修正するのでどんどん指摘してください。


#初期設定の罠

ホームページ作成にあたり、まずはヘッダー作成に取り組みます。
ホームページに飛べるようリンクを埋め込んだロゴと内容を示したリストを作成することを考え以下のようなコードを記述します。
 <img width="435" alt="初期設定コード1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449719/0414452c-7cd1-43b5-a01f-d5ed756cdde0.png">
出力は下図のようになりました。
 <img width="363" alt="初期設定1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449719/67d3edba-60bd-b684-f5d9-d9b040ca74f2.png">
CSSで何か記述したわけでもないのに、ロゴとリストの左端が合っていませんね。
この原因は、ページのコードを見ればすぐに解決します。
 <img width="602" alt="初期設定2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449719/f6064b81-a932-395a-8f04-61f0adac3ee2.png">
薄緑色がpadding、薄オレンジ色がmarginを表しています。
そうです、初期設定でpaddingとmarginが勝手に設定されていたんです。
どうりで端が合わないわけですね。
このpaddingとmarginを無くせば、下図のようにきれいな出力になります。
 <img width="363" alt="初期設定3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449719/1eebc95d-3322-4041-ea83-d31c5573abdd.png">
このように初期の設定値の影響で出力が期待通りにならないことがあるので確認する必要がありますね。
僕はこの原因が分からず、ずっと苦戦してしまいました…

#おわりに

実際にホームページ作成をしてみることで、理解できていない部分が明確になってインプット学習とは違った学びが得られていると実感します。
今後もさらなるレベルアップに向け、学習していきたいと思います。
LatexでのAlgorithmの書き方(論文、技術報告書)

# 0. 概要
データ解析等をしていると`入力→前処理→処理→後処理→出力`等と入力から出力を得るまでに複雑な処理をしないといけない場合がありますよね。この時、文章だけではどうしても読者に伝わりづらいことがあります。その時に用いるのが疑似コード、アルゴリズムを用いた文章表現です。

例えばこんなやつです。
![Ses4T.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95636/ef71c288-ac7b-98c9-d2c1-c5c185652277.png)
論文でよく見ますよね。これを使えば処理の流れが説明しやすいです。
ところで、これってどうやって生成するんだ？？っていうのを説明していきます。

# 1. Latexを始める
おもむろに`https://ja.overleaf.com/`へアクセスしてアカウントを作成し、空のプロジェクトを生成する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95636/b09220f5-a6a6-0d40-7725-2185726d40aa.png)
こんな画面が表示されれば、後はLatexを書いていくだけである。

# 2. Algorithmを作る
取り合えず、IEEEのテンプレートでザックり作ってみる。

``` latex
\documentclass{IEEEtran}
\usepackage{algorithm,algorithmic}
\begin{document}
 \begin{algorithm}
 \caption{Algorithm for ...}
 \begin{algorithmic}[1]
 \renewcommand{\algorithmicrequire}{\textbf{Input:}}
 \renewcommand{\algorithmicensure}{\textbf{Output:}}
 \REQUIRE in
 \ENSURE  out
 \\ \textit{Initialisation} :
  \STATE first statement
 \\ \textit{LOOP Process}
  \FOR {$i = l-2$ to $0$}
  \STATE statements..
  \IF {($i \ne 0$)}
  \STATE statement..
  \ENDIF
  \ENDFOR
 \RETURN $P$ 
 \end{algorithmic} 
 \end{algorithm}
\end{document}
```
【Ruby】例外処理まとめ

# 概要
Rubyの例外処理に関して最低限必要な知識を簡単なコードと共にまとめました。

# 基本文法
例外処理の基本は以下の様な形式になります。

```ruby
begin 
  # エラーを発生させる可能性のあるコード。
rescue => e # 例外オブジェクトを代入した変数。
  # begin~rescueの間でエラーが発生した場合に実行されるコード。
end
```

## コード例

```ruby
begin 
  raise # エラーを発生させます。
rescue => e
  p e #=> RuntimeError
end
```

# 関連メソッド


| Method 	| Explanation 	| 
|---	|---|	
| Object#class|エラーのクラスを返します。|  
| Kernel#raise| エラーを発生させます。|  	 
| Exception#backtrace|エラーのバックトレースを返します。|
| Exception#message|エラーのメッセージを返します。|

## コード例

```ruby
begin 
  raise StandardError.new("Message")
rescue => e
  p e.class #=> StandardError
  p e.message #=> "Message"
  p e.backtrace #=> ["(repl):4:in `<main>'", "/run_dir/repl.rb:41:in `eval'", "/run_dir/repl.rb:41:in `run'", "/run_dir/repl.rb:57:in `handle_eval'", "/run_dir/repl.rb:170:in `start'", "/run_dir/repl.rb:177:in `start'", "/run_dir/repl.rb:181:in `<main>'"]
end
```

# Ensure
`ensure`を使用する事でエラーの有無に関わらず処理を実行する事ができます。

## コード例1(エラーがない場合)

```ruby
begin 
  "no Error"
rescue => e
  p e.message # エラーはないので実行されません。
ensure 
  p "絶対実行" #=> 絶対実行
end
```

## コード例2(エラーが発生した場合)

```ruby
begin 
  raise StandardError.new('error')
rescue => e
  p e.message #=> error
ensure 
  p "絶対実行" #=> 絶対実行
end
```

# Retry
文字通り処理を再実行します。

## コード例

```ruby
file = ARGV[0]

begin
  io = File.open( file )
rescue
  # ファイルを開く際にエラーが発生した場合は処理が行われる。
  sleep( 10 )
  # begin ~ rescue内の処理を再び実行します。
  retry
end
```

# Rescue修飾子
`if`修飾子のように `rescue`を修飾子として使用する事ができます。

## コード例

```ruby
raise "Error" rescue p "rescued" #=> rescued
```

# メソッド内の例外

メソッド内では`begin`と`end`を省略して以下のように書く事ができます。

```ruby
def method
  # エラーを発生させる可能性のあるコード。
 rescue => e 
  # エラー発生時の処理。
end
```

## コード例

``` ruby
def method
 raise 'error'
 rescue => e 
  p e.message #=> error
 ensure
  p 'ensured' #=> ensured
end
method #=> "error"
```

# 複数の例外処理

以下のように対応するエラー毎に複数の`rescue`を記載する事で、各エラー毎に別の対応をする事ができます。

```ruby
begin 
  rescue Exception1, Exception2 => e
  # Exception1 か Exception2が発生した際に処理が実行される。
  rescue Exception3 => e
  # Exception3が発生した際に処理が実行される。
  rescue => e
   # Exception1,2,3以外の例外が発生した際に処理が実行される。
end
```


## コード例

```ruby
begin 
  raise StandardError
  rescue StandardError, RangeError   
    p 'Standard or Range Error'
  rescue RuntimeError
    p 'Runtime Error'
  rescue => e
    p 'some other error'
end

#=> "Standard or Range Error"
```

# カスタム例外の作成
以下の記事にカスタム例外の作成方法をまとめました。
[【Ruby】カスタム例外を作成する簡単３ステップ - Qiita](https://qiita.com/k-penguin-sato/items/3d8ce4e71520da2d68c4)

# 参照
[Ruby Exception handling - DEV Community 👩‍💻👨‍💻](https://dev.to/k_penguin_sato/ruby-exception-handling-2098)
React videoファイルのサムネイルを簡易的に表示したい(;´･ω･)

Create react app --typescript
で作ったプロジェクトに、ビデオのサムネイル的なもの表示したいが良さげなコンポーネントがみつからない。
ビデオは再生せず、ビデオのワンシーン一部分を切り出して画像だけ、ひょこっと出したいのですが、よさげなコンポーネントが見つかりません。|・`ω・)

react-video-thumbnail
https://www.npmjs.com/package/react-video-thumbnail
が良さげだったので、引っ張ってきました。

HtmlElementの<Canvas>タグを使用して、ビデオの一部を切り取って

```
yarn add react-video-thumbnail
```

importしてきました。

```
C:/Users/imo/e/components/qiita.tsx
TypeScript error in C:/Users/imo/e/components/qiita.tsx(7,28):
Could not find a declaration file for module 'react-video-thumbnail'. '/node_modules/react-video-thumbnail/dist/bundle.js' implicitly has an 'any' type.
  Try `npm install @types/react-video-thumbnail` if it exists or add a new declaration (.d.ts) file containing `declare module 'react-video-thumbnail';`  TS7016

     5 | import Typography from '@material-ui/core/Typography';
     6 | import Boardcss from './StatsusBoard.module.css';
  >  7 | import VideoThumbnail from 'react-video-thumbnail';
       |                            ^
     8 |
     9 | 
    10 | interface qiitaProps {
```

.d.ts　型宣言ファイルがないようです。TypeScriptをサポートしていないようなので雲いきが怪しいですが、仕切り直しに@type 

 ```
npm install @types/react-video-thumbnail
```

404エラーになりました。

anyタイプの型付けを行わない形で読み込みました。


```
const VideoThumbnail = require('react-video-thumbnail')
```

```JavaScript
  <VideoThumbnail
 videoUrl="https://dl.dropboxusercontent.com/s/7b21gtvsvicavoh/statue-of-admiral-yi-no-audio.mp4?dl=1"
 width={120}
 height={80}
  />
```
実際に実行しました。
<img width="359" alt="dddd.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426556/d84fc086-af45-e4b6-b43c-2f307d568e14.png">
表示されました。

画面ロード時に、動画ファイルの元の大きさで一瞬表示されることがあり、、タイミングによっては動画ファイルが再生できてしまったりしｍさう。色々試してみてチューニングが必要そうです。
または、別になにか良いコンポーネントがないか再度探し始める必要がありそうです
【随時更新予定】GAEでwebサイトをデプロイする際にapp.yamlの記述で気をつけること。

こんにちは。
私はいわゆる昔ながらのwebデザイナーでありコーダーやってました（現在はたまにやる程度）。モダンwebと呼ばれるフロントエンド界隈にはあまり詳しくなく、これまでFTPを使ったアップロードで済んでいたような、シンプルなwebサイト制作が多かったのですが、勤務先のサーバー環境がGCP系（主にGAE Google App Engine）になったことで、いろいろ新しく覚えることが増えたので備忘録として残していきます。
##トラフィックの少ない静的サイトはGAEと相性が良いみたい
GAEには無料枠というものがあり、トラフィックの少ないサイトはGAEにデプロイすることで固定費を抑えるできることがわかったので、現在勤務先では積極的に採用していく方針となってます。無料枠に関しては[こちらの記事](https://koni.hateblo.jp/entry/2016/01/06/130613)に詳しく書かれてました。
##app.yamlのハンドラーに苦戦
適当に書いてたらエラーの嵐。GAEでhtmlのデプロイはリファレンス少なくて結構困りました。ここから試行錯誤で対応です。
###httpsに対応&リダイレクトさせる
```app.yaml
runtime: php55
api_version: 1
service: <サービス名>
handlers:
  - url: /
    script: index.php
    # これ↓
    secure: always
```
こちらはドキュメントルートにアクセスした際に、index.phpを呼び出すように設定。httpsに対応させるため、**secure: always**と記述します。こうすることで、httpにアクセスしても、自動的にhttpsへリダイレクトしてくれます。（GAEってこの一行でssl対応できるからありがたい）ただし、あくまで指定したURLしか対応しないので複数ページがあればすべて記述が必要なので注意。全部一括でhttpsにしてくれる方法あったら教えて下さい。
###末尾スラッシュなしにアクセスした際の挙動をコントロール
```app.yaml
runtime: php55
api_version: 1
service: <サービス名>
handlers:
  - url: /<サブディレクトリ名>/
    static_files: <サブディレクトリ名>/index.html
    upload: <サブディレクトリ名>/index.html
    secure: always

  - url: /<サブディレクトリ名>
    script: <サブディレクトリ名>/index.php
    secure: always
```
```php:index.php
<?php
$dom = (empty($_SERVER['HTTPS']) ? 'http://' : 'https://') . $_SERVER['HTTP_HOST'];
?>
<!DOCTYPE html>
<html>
<head>
	<title>サイトタイトル</title>
	<meta charset="UTF-8">
	<meta name=”robots” content=”noindex”>
	<meta http-equiv="refresh" content="0 ; URL=<?php echo $dom; ?>/<サブディレクトリ名>/">
</head>
<body>
</body>

</html>
```
app.yamlにはスラッシュありの場合の読み込み先と、スラッシュなしの場合の読み込み先は個別に指定する必要があります。じゃないと、指定していない方にアクセスすると普通にエラーになります。ということで、スラッシュなしのURLにアクセスした際に、リダイレクト用のindex.phpを用意してそれを読み込ませることで対応させました。瞬時に切り替わるのでユーザー側に不便はないですが、おそらくやり方としては全然スマートじゃないのでもっといい方法あったら教えて下さい。
##今後の更新予定
app.yamlの書き方覚えたら追加していくのと、あとはNUXT.js使ったサイトを作ったので、そのあたりで覚えたことがあれば書いていきます。多分。
Jupyter Notebook起動時に開く初期ディレクトリをうまく指定できなかったお話。


Jupyter Notebook環境構築を行っていたとき、あることで1時間くらい時間を溶かしてしまったmacユーザー```hoge```さんのお話です。

##1. Jupyter起動時に開くディレクトリを変更したい
Jupyter Notebookを起動したとき、デフォルトではユーザーのホームディレクトリ一覧が表示されます。なにかと不便なので```jupyter```ディレクトリを作成し、これをデフォルトのディレクトリにしたいと```hoge```さんは思いました。

```zsh

$ /Users/hoge/ #デフォルト設定ではここだが…

$ /Users/hoge/Documents/jupyter #起動時にここを開くようにしたい
```

##2. Jupyter Notebook設定ファイル（jupyter_notebook_config.py）の生成
「まずはTerminalでJupyter Notebook用の設定ファイルを作成しよう。生成されたかどうかちゃんとチェックも。」

```zsh
$ jupyter notebook --generate-config #jupyter_notebook_config.pyの生成
$ ls -a ~ #隠しディレクトリを表示
. .. .vim .zshrc .jupyter …

$ cd .jupyter #.jupyterに入る
$ ls 
custom                        jupyter_notebook_config.py
jupyter_nbconvert_config.json migrated
jupyter_notebook_config.json  nbconfig
```
「できた。」
設定ファイルは、ホームディレクトリの隠しフォルダである```~/.jupyter/```に生成されました。

##3. jupyter_notebook_config.py の中身をいじる
jupyter_notebook_config.pyの中身を見てみようと思った```hoge```さんは、全然慣れていない（hjkl移動もしてない）けどなんとなくかっこいいと思っている```vim```でこれを開きました。

```zsh
$ vi jupyter_notebook_config.py #viとvimは同じコマンドにしてある

# Configuration file for jupyter-notebook.
 
#------------------------------------------------------------------------------
# Application(SingletonConfigurable) configuration
#------------------------------------------------------------------------------

## This is an application.

## The date format used by logging formatters for %(asctime)s
#c.Application.log_datefmt = '%Y-%m-%d %H:%M:%S'

︙

#c.NotebookApp.notebook_dir = ' ' #261行目のこれを編集する

```
ディレクトリを変更するためにはどうやら261行目のコメントアウトを消して、```c.NotebookApp.notebook_dir```に好きなパスを指定してあげればいいとインターネットにいる人たちが書いた記事の多くには書いてあったから以下のように書いたそうです。

```zsh
c.NotebookApp.notebook_dir = '~/Documents/jupyter'
```
しかし…

##4. 「パスを指定してもうまくいかない！」 
「jupyterを起動したら開けないんだが？」

```zsh

$ jupyter notebook

[C 18:07:55.548 NotebookApp] Bad config encountered during initialization:
[C 18:07:55.548 NotebookApp] No such notebook dir: ''/Users/hoge/.jupyter/~/Documents/jupyter'' 
```

「なんで```.jupyter```直下から```~```が始まっちゃうの？そんな読み方しないでほしい。じゃあ```~```記号を使わないで書けばちゃんと読み取って許してくれるのかな？」

```zsh
c.NotebookApp.notebook_dir = '/Users/hoge/Documents/jupyter' #書き直しました

$ jupyter notebook #ちゃんと起動しました
```

起動しましたね。ちなみに無いとは思いますが```Users```の前の```/```を忘れるとこんなことになります。

```zsh

c.NotebookApp.notebook_dir = 'Users/hoge/Documents/jupyter'

$ jupyter notebook 

[C 18:16:30.026 NotebookApp] Bad config encountered during initialization:
[C 18:16:30.026 NotebookApp] No such notebook dir: ''/Users/hoge/.jupyter/Users/hoge/Documents/jupyter''
```
Python OpenCV Mat Typeの取得

#想定している状況
OpenCVを用いて、Laplacianフィルタなどをかける場合
cv2.(input,   **CV_8U**) のように、Mat Type(CV_8Uなどの値）を指定する必要がある。


C++やC#ならばこのMatTypeは　input.depth() で得られる。
しかし、Pythonの場合　input の画像はNumpyで読み込まれるため、Mat Typeを得ることができない。そのため毎回input画像の型によってプログラムを書き直す必要性がある。

#打開策
Numpy で　input画像のチャンネル数とデータ型を調べる。
得られた情報をもとにif文でMat Typeを判別

#具体的には

チャンネル数の調べ方　　

if np.ndim(input) == 3:
     _, _, ch = input.shape

elif np.ndim(input) ==2:   #グレースケールの場合
    ch = 1

データ型の調べ方

input.dtype  ##uint8 などのような値が得られる


これらの情報を元にMat Type を判別する

<img width="503" alt="スクリーンショット 2019-07-31 17.50.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264607/9d8df71f-cc61-4376-1f79-1444fd9c84d2.png">

引用：http://ninghang.blogspot.com/2012/11/list-of-mat-type-in-opencv.html
この表を見るとチャンネル数とデータ型によってMat Typeの数字が決まることが確認できる。

幸い、cv2.Laplacianなどで指定するMatTypeは数字である。（CV_8Uの中身は数字）



<img width="526" alt="スクリーンショット 2019-07-31 18.14.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264607/ef029184-24f4-20aa-e489-b73e999ea03e.png">

このように書けば大丈夫なはず。

#問題点
どちらにせよめんどくさい。
もっと綺麗な書き方
もしくは、簡単にやるやり方を知ってる方いらしたら教えてください。
Fortran 多次元配列のアクセス順序による計算時間の違い


いつものようにNAGFortranのページでFortran Tipsを読み返していたら[こんなページ](https://www.nag-j.co.jp/fortran/tips/tips_ArrayIndexingTip.html#_ArrayIndexingTip)を見つけたので、実際に確かめてみました。三次元配列同士の積を、配列の大きさを50-1000まで変えて計算しました。

190801 コードを一部修正しました。

## コード
```cal_array.f90
program main
  implicit none
  integer :: i,j,k,n
  real(kind=8),allocatable ::  a(:,:,:) , b(:,:,:)
  real(kind=8) :: t1,t2,s1,s2

  do  n = 50,1000,25
    allocate(a(n,n,n))
    allocate(b(n,n,n))
    call random_number(a)
    call random_number(b)
!----------- right -----------!
    call cpu_time(t1)
    do i = 1,n
       do j = 1,n
          do k = 1,n
             a(i,j,k) = a(i,j,k) * b(i,j,k)
          end do
       end do
    end do
    call cpu_time(t2)
 !----------- right -----------!
 !----------- left-----------!
    call cpu_time(s1)
    do i = 1,n
       do j = 1,n
          do k = 1,n
             a(k,j,i) = a(k,j,i) * b(k,j,i)
          end do
       end do
    end do
    call cpu_time(s2)
 !----------- left -----------!
  print*, n, t2-t1, s2-s1
  deallocate(a)
  deallocate(b)
  end do
end     program main
```

## 結果
ノイズを減らすために、実際には5回計算を行い算術平均を取っています。
![five-ave.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472846/4dd01165-0330-3541-44c1-8759b22b90cb.png)

配列の大きさが500を超えたあたりから右側からアクセスした場合の計算時間が大幅に増加しています。一方で左側からアクセスした場合は緩やかにしか変化していません。
小さい配列しか扱わなければそこまで気にしなくても良いのかもしれませんが、大規模な計算をする場合、配列のアクセス順序によって計算時間のパフォーマンスが目に見えて変わりうるという結果になりました。

## 余談
N=1000の計算だとメモリが16GB前後必要でした。実行される際はお気をつけて…。
Windows＋AMDなGPUの組み合わせで機械学習簡単にやるにはPlaidMLがおすすめ？

# 機械学習の勉強はじめました
ここしばらく色々とトレンド追うのをサボってましたが、余裕が出てきたのでやっと機械学習の勉強を始めました。
かなり周回遅れなきもするけど、いろんな参考書見ながらちょっとずつ頑張ってます。
知識ゼロからやってるので本記事で的はずれなこと書いているかもしれませんが生暖かく見てください。

# ディープラーニング用ライブラリ
さて、ディープラーニングの勉強始めてまずフルスクラッチ系の参考書籍で、ライブラリを使わずに理論的に説明しているものを勉強しました。
それと並行してライブラリを使っていかに簡単に実装するかも調べてみました。
有名所で勉強始める前から知っているTensorFlowなんかがいいのかなと思いつつ少し調べて色々とわかってきたのでそれを書き留めておきます。
その他いくつかライブラリやフレームワークあるのがわかりましたが一番大きな壁がGPUでした。

TensorFlow等のメジャーな機械学習ライブラリはCUDAでnVidiaのGPUには対応しているのですが、根っからのAMD党でデスクトップにはRadeon RX580、ノートPCもRyzen 3700uを搭載している自分の環境ではGPU支援を使うことができませんでした。
CPUのみだときついのでGPU支援環境を求めて色々調べることに

## CUDA
まずAMD対応の前にCUDAの話を
先に述べたとおりCUDAならTensorFlowやJava用ライブラリのDeeplearning4Jで対応していました。
ココらへんが機械学習をやるならnVidia一強になっている所以ですね。

## Rocm
AMD環境で使う方法を調べるとまずRocm(Radeon Open Compute)(https://github.com/RadeonOpenCompute/ROCm)という環境があることを知りました。
nVidiaのCUDAに相当するGPGPU環境です。
Rocm用TensorFlowも用意されており、これならRadeonでもイケるようです。
しかしこれを使うにはハードルがあって、OSがUbuntuでなければいけません。
自作PCなデスクトップならともかく、容量の少ないノート環境でデュアルブートはしたくなかったので他にもっと簡単な環境はないかなと調べました。

## OpenCL
GPGPUでオープンな規格といえばOpenCL
これに対応しているものを探そうとしましたがなかなかありません。
DeepLearning4Jが対応しようとしているみたいですがまだ実装はされていませんでした。
そのような中見つけたのがPlaidML(https://github.com/plaidml/plaidml)
TensorFlowと同じくPython用機械学習ライブラリなのですが、こちらはOpenCL対応！
pipでインストールできてWindows＋AMDな環境でGPU支援ができました。

さらにフロントエンドとしてKerasが使用できるため、TensorFlow＋Kerasを使っている参考資料だとほぼそのまま流用する事ができます。
試した感じだとこれが一番楽にGPU支援できそうな感じです。

# 最後に
ここまで頑張って環境作ったけどちょっとしたことやるならGoogle ColaboratoryのGPU環境でやったほうが何倍も速かった、辛い……
Vuetify初心者の備忘録① グリッドシステムについて

Vuetifyでわかんなくて調べたことを出来るだけ平易な言葉でメモっていきます。
また、出来るだけカタカナ語はこの記事の中で完結するようにします。
間違っていたらお教えください。

#前置き
###Vuetifyとは
vue.jsでマテリアルデザインを実現するためのUIフレームワークです！
↓Vuetify公式
https://vuetifyjs.com/ja/
https://github.com/vuetifyjs/vuetify

###マテリアルデザイン
Googleさんが言い出した、「ユーザーさんにとってわかりやすくて操作しやすいページの作り方」です！
「ポップアップみたいに画面の上の方にウインドウが出てきたら影をつけようね！」とか、
「ボタンとボタンの間はこれぐらい間隔をあけてね！」とかめちゃめちゃ事細かに決めてあります。
そんな複雑なCSS書いてられるか！って人のためにVuetifyが簡単に実現してくれます！
↓Googleさんのマテリアルデザイン指南
https://material.io/

###グリッドシステム
スイスのデザイナーさんが1981年に考えた、デザインの手法だよ！
マテリアルデザインには必要不可欠な概念で、最初は、紙ベースの表現で用いられていたけど、最近になってWebデザインに流用されてきたよ！
グリッド＝格子　つまり格子状に切ったブロックそれぞれに情報を配置していくことで、
規則性が生まれたり、情報の関係性を視覚的に捉えたりできて、見る人にとって、欲しい情報がわかりやすく表現できるよ！

###ブレークポイント
vuetifyのグリッドシステムでは、フレックスボックスと言われる、「CSSに`display:flex`が指定された要素」の横幅を１２分割して、そのうちのグリッド何個分って指定をするんだけど、
「画面サイズや表示するデバイスによって、グリッド何個分を変えたい！」って思った時の「画面サイズの境界線」だよ！
詳しくは、下記の公式ガイドラインの表を見てみてね！
https://vuetifyjs.com/ja/customization/breakpoints#breakpoints

#グリッドシステムを作るためのタグ

###v-app
Vuetifyは、このタグの中で使ってね！このタグの中じゃないと正常に動作しないよ！

###v-container
レイアウトをいじる範囲を示すコンテナだよ！
`padding`がついてるから、真ん中に寄ったレイアウトになるね！
子要素に`padding`効かせたいときは`grid-list`を指定するよ！
特徴：
・`width: 100%;`だが、`max-width`はブレークポイントに従って段階的に設定されている
・`max-width`を常に親要素に合わせたい場合は、タグのプロパティに`fluid`を指定する
・`margin-right: auto; margin-left: auto;`により子要素が左右中央寄せとなる
・上下中央寄せにするには、`fill-height`プロパティをタグに指定する
・設定で変更できるが、`padding`が初期値12pxと設定されている

###v-layout
まとまりをあらわして、子要素の並び方を制御するよ！
デフォルトでは、CSSの`display: flex;`が効いてて、直下の要素が横並びになるよ！
縦並びにしたいときは、`column`プロパティを入れようね！
グリッドシステムを効かせたいときは`wrap`プロパティを入れようね！横幅がいっぱい（グリッド１２個分超え）になったら改行してくれるよ！
特徴：
・`display: flex;`が指定されている
・タグの要素に`column`を指定すると縦並びになり、`reverse`を指定すると並び順を逆にできる。併用も可能
・デフォルトでは、`flex-wrap: nowrap;`が指定してあり、横幅いっぱいになっても改行されずに続いていくが、
　`wrap`プロパティを指定すると、`flex-wrap: wrap;`となり、横幅に応じて、自動で改行される。

###v-flex
横幅の指定を行うよ！オフセットっていう、要素の左側にmarginをいれたりできるよ！
CSSの`flex: 1 1 auto`を自動的に入れてくれるよ！
参考:http://www.htmq.com/css/flex.shtml
グリッドシステムで位置の指定を行う対象だよ！

```html:例
<!-- 左側に横幅1/12の空白、5/12の範囲にテキストエリアがあって、残りの右側6/12は空白 -->
<v-flex offset-xs1 xs5>
  <textarea />
</v-flex>
```
特徴
・デフォルトでは`max-width: 100%`が設定されているが、例の`xs5`などのブレークポイントとサイズの指定があった場合は、`max-width`と`flex-basis`がそれに応じて設定され、`flex-grow: 0`が指定されて横に伸びなくなる
・例のように`offset-xs1`などのoffset-[ブレークポイント][サイズ]の指定があった場合は、指定に応じた値が`margin-left`に設定される

#以上
一応、vuetifyのソースを見ながら書いたのですが、何か間違いなどがありましたらご指摘いただきたいです！
よろしくお願いいたします。
プログラミングが気になる人向けのまずは触ってみ講座(html css編 position)

##　あらすじ
前回はhtmlとcssで表示する位置を調整する方法その１を学びました。marginとpaddingは似ているようでちょっと違うので、違いはよく覚えておいてくださいね。
なんと今回の生徒方は僕のヒントなしで解けたようです。2回目にしては難易度上げすぎたかな？と思っていたのですが、素晴らしい・・！どんな解答になったのか楽しみです。
8/９追記、生徒曰くheight100%,width100%が状況に応じて形が変わる事がイメージ難しかったようです、それも相まってpaddingとmarginに及ぼす影響も難しかったようですね。前回の実演が甘かっなと痛感しつつ再度実演しました。この講座の宿題が見たい生徒及び読者さんしばらくお待ちください。

##　宿題の答え
<img width="1137" alt="宿題2解答.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281672/b5f84ded-daad-fe4d-b1c2-f0f7ca8bf28b.png">

ぱっと見こうなっていれば正解です。日本の国旗を作る発展問題は、今回は白い部分は親要素にpaddingをかけて、赤丸はmarginで調整してあげるとうまくいきますね。

##　今回の目的
　positionという位置を調整する方法を覚える。
相変わらず使用頻度が高いもの以外は省略してるので各自検索してください。

#　position
>ボックスの配置方法（基準位置）が、相対位置か絶対位置かを指定する際に使用します。[詳細はこちら](http://www.htmq.com/style/position.shtml)

なんのこっちゃだと思いますが、少し説明します。

##　position:static
positionを特に設定していないとこれに設定されています。基準位置を特に設定しません。
要素を上書きして初期化したいときに使うぐらいなので、使う頻度は多くありません。

##　position: absolute
基準から移動する場所を決定します。例えば　absoluteが適用されている要素にtop:20px;を追加すると、基準から20pxずれることになります。他にもleft,right,bottomがあります。
基準に関しては何も設定していなければ画面の左上端が基準になります。もし親にstatic以外のポジションが適用されていればその親の左上端が基準になります。

##　position: relative
>相対位置への配置となります。positionプロパティでstaticを指定した場合に表示される位置が基準位置となります。

とは書いているものの、普段使っている印象だとabsoluteの要素の基準を決めるために親要素に設定する使い方が多いです。

##　position: fixed
設定方法はabsoluteと同様ですが、fixedで固定されたものはどう画面を移動しようとその場に止まって動きません。ヘッダーを常時表示させたい、サイドバーを常に横に置きたい時に用います。

##サンプル
サンプルを用意しました。positionがどういった動きをするのか手探りで試してみましょう。

```class3.html
<html>
  <head>
    <title>class3</title>
    <link rel="stylesheet" type="text/css" href="reset.css">
    <link rel="stylesheet" type="text/css" href="class3.css">
  </head>
  <body>
    <header>title:class3</header>
    <div class="content">
      <div class="content" id="content1">
        <div class="block">position:static</div>
      </div>
      <div class="content" id="content2">
        <div class="block">position:static</div>
      </div>
      <div class="content" id="content3">
        <div class="block">position:static</div>
      </div>
      <div class="content" id="content4">
        <div class="block">position:static</div>
      </div>
      <div class="content" id="content5">
        <div class="block">position:static</div>
      </div>
      <div class="content" id="content6">
        <div class="block">position:static</div>
      </div>
    </div>
  </body>
</html>
```

```class3.css
body{
  height:200%:
  width:200%;
}
header{
  height:150px;
  width:100%;
  background-color: orange;
  font-size:32px;
  padding:20px;
/*  position: fixed;
  top:0;
  left:0;*/
}
.content{
  height:400px;
  width:100%;
}
.content:nth-child(2n-1){
  background-color:#CCC;
}
.content:nth-child(2n){
  background-color:#EEE;
}
.block{
  height:300px;
  width:300px;
  font-size:32px;
}

#content1 .block{
  background-color: red;
}
#content2 .block{
  background-color: green;
}

#content3 .block{
  background-color: blue;
}
#content4 .block{
  background-color: skyblue;
}
#content5 .block{
  background-color: yellow;
}
#content6 .block{
  background-color: pink;
}
```

##宿題
授業終了後に追加します。