OmniAICreator/Qiita-1.07M huggingface dataset:
Sinatraを使ってHeroku drainログをTDへ送るAppを作った時にハマった記録

#はじめに
Heroku drainからhttp経由でログを取得し、TDへ送るアプリをsinatraで作っていた時ハマった時のことを記録として残す。
Heroku drainからログをpostで受け取る形式のアプリを作った。(Sinatraは初めて)
#最初はクラシック形式で作成。
```app_main.rb
require 'sinatra'
require 'sinatra/reloader' if development?
require 'td'
require 'date'
TreasureData::Logger.open('DB名',
    :apikey=>ENV['TD_API_KEY'],
    :auto_create_table=>true)
post '/' do
・・・　requestの内容をパースする処理　・・・
　TD.event.post('テーブル名',{送るデータ})
end
```
ここで一つ注意点。
・TreasureData::Logger.openはpostのなかに記述してはいけない
理由は簡単。 postされるたびTreasureData::Logger.openが実行されるため
最終的にはThread errorでログが受け取れない状態に陥る。

この記述にすると大体5分間隔でbufferに蓄積したデータをTDへpostする。

#モジュールに書き直し
後々のメンテナンス性や拡張性、可読性を考えモジュール化させる。

```app_main2.rb
require 'sinatra/base'
require 'sinatra/reloader' 
require 'td'
require 'date'
require 'ltsv'
require "concurrent/map"
require './object_ext'　#.present?が使いたかったために拡張

class MyApp < Sinatra::Base
    configure :development do
        register Sinatra::Reloader
    end

    before do

    　#TD初期設定
    　TreasureData::Logger.open('DB名',
        :apikey=>ENV['TD_API_KEY'],
        :auto_create_table=>true)

        class Lib
            include ObjectExtension

            def log_parser(log)
              ・・・　受け取ったログをパースしてhashで返す　・・・
　　　　　　　end
       end
       paser = Lib.new

　　end　　
      post '/' do
        ・・・　logを受け取りlog_parser(log)でパースする　・・・
        TD.event.post('テーブル名',{送るデータ})
      end
end
```

・ここでのミス
　beforeを使ったこと
実際のところ前処理をする必要は今回のアプリには無かったが、
beforeで事前に色々と設定や処理などをするものと勘違いしていたためまたもやThread errorの連発。
何が起きていたかと言うと、herokuからドレインされたログを受ける度にbeforeが呼ばれTreasureData::Logger.openを
呼び出すと処理を行っていた。そのため、今度はbufferに溜まるのを待たずに即TDにpostする現象に見舞われblockされてしまう状況に陥った。

```app_main2.rb
require 'sinatra/base'
require 'sinatra/reloader' 
require 'td'
require 'date'
require 'ltsv'
require "concurrent/map"
require './object_ext'　#.present?が使いたかったために拡張

class MyApp < Sinatra::Base
    configure :development do
        register Sinatra::Reloader
    end

    　#TD初期設定
    　TreasureData::Logger.open('DB名',
        :apikey=>ENV['TD_API_KEY'],
        :auto_create_table=>true)

        class Lib
            include ObjectExtension

            def log_parser(log)
              ・・・　受け取ったログをパースしてhashで返す　・・・
　　　　　　　end
        end
            paser = Lib.new
　　
      post '/' do
        ・・・　logを受け取りlog_parser(log)でパースする　・・・
        TD.event.post('テーブル名',{送るデータ})
      end
end
MyApp.run!
```

結果から言うとbeforeは要らなかった。
これで、約5分間隔でTDへpostする様に安定した。

#結論
TreasureData::Logger.openは一回呼び出せばそれで良い代物であって、
何度も呼び出される様な場所に記述をしてはいけない。
DB接続がない状態でassets:precompileを行う


本番とは違う環境だったり、Dockerfile内でassets:precompileを行ったりするときにDB接続でエラーになるときがある。これを回避する方法ってあるのかなと思ったので調べてみた

## activerecord-nulldb-adapterを使う

github
https://github.com/nulldb/nulldb


```Gemfile
gem 'activerecord-nulldb-adapter'
```

```config/database.yml
default: &default
  adapter: <%= ENV['DB_ADAPTER'] ||= "mysql2" %>
```

database.ymlに環境変数で`DB_ADAPTER`を指定する。

```
$ DB_ADAPTER=nulldb bundle exec rake assets:precompile
```

上記を実行すればDB接続なしでprecompileできる



## 参考

Rails × ECS でオートスケーリング＆検証環境の自動構築
https://tech.medpeer.co.jp/entry/2018/06/20/080000
AWSのRDSで接続エラーにハマった話


## 記事概要

- 趣味で使っているRedmineをコンテナ環境に移行したいなと思って、Redmine内のMySQLをマネージドサービスのRDSに移行しようとした
- セキュリティグループなど適切に設定した（つもりだった）
- バックアップファイルをEC2（redmineが稼働中）からRDSにエクスポートしようとしたところでエラー
- 最初は接続出来たような気がするのに、しばらく日にちが経った後に接続しようとしたらエラー…？

## 遭遇したエラー

普通につながるかどうか具体的にはこんなエラーが出る

```
ubuntu@ip-10-0-0-167:~$  mysql -h xxxxxx-database-1.xxxxxx.ap-northeast-1.rds.amazonaws.com -u <username> -p

ERROR 2003 (HY000): Can't connect to MySQL server on 'xxxxxx-database-1.cluster-xxxxxx.ap-northeast-1.rds.amazonaws.com' (60)
```

普通にググると「セキュリティグループの設定見直せ！」というアドバイスが出てくるが、そんなことはわかっている。

## 原因調査

RDSの基本がわかっていなかったが、

- 複数のAZをまたがったサブネットグループを登録する
- セキュリティグループも複数登録可能

という条件でサブネットを登録する必要がある。

ということでVPCを選択した時に全てのサブネットをグループに含めてしまった。

これがいけない。

本来ならプライベートサブネットA,Bでグループを作るつもりが、全然関係ないプライベートサブネットCが紛れ込んでいた。

プライベートサブネットCのネットワークACLはガチガチに制限されているため、アクセス元のコンテナがあるサブネットから通信は出来ない。

最初は接続出来たという謎についても何となく原因がわかった。

RDSではプライマリインスタンスとスタンバイインスタンスが複数のサブネットに配置される。

そうなるとプライマリインスタンスが…

①サブネットA/Bに配置された場合 → 接続可能
②サブネットCに配置された場合 → 接続不可

という現象が起きる。

今回は最初①で接続出来たのに、RDSのインスタンスの設定をもう一回やり直した時に②になってしまったようだ。

## 対処方法

サブネットグループに登録するサブネットのネットワークACLを確認する。
LaravelをMacにインストールしてみよう！

##概要
macOSにローカル開発環境としてLaravelをインストール

公式サイト
https://readouble.com/laravel/6.x/ja/installation.html

##前提

###環境　
　macOS HighSierra 10.13.16
　Homebrew 2.2.9
　Composer 1.9.3
　PHP 7.4.3 
　Laravel 7.0.8


###インストール済みソフト
　Homebrew（macOS用パッケージマネージャー）
　＞日本語サイト：[Homebrew](https://brew.sh/index_ja)
　＞インストール参考記事：[Homebrew使い方まとめ](https://qiita.com/vintersnow/items/fca0be79cdc28bd2f5e4)

##準備

###Composerインストール
　PHP用ライブラリ依存管理ツールをインストール

```
$ brew install composer
```

　＞参考記事：[PHPのライブラリ管理ツール「Composer」入門](https://weblabo.oscasierra.net/php-composer-1/)


##インストール

###Laraverlインストール
　Composerを使ってインストール

```
$ composer global require "laravel/installer"
```

　PATHを通す

~/.bash_profile または ~/.bashrc にパスを追加（お使いの設定により）

```~/.bash_profile
export PATH=$PATH:/usr/local/bin:$HOME/.composer/vendor/bin
```

　パス確認（値は環境依存）

```
$ echo $PATH
usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
```

　設定反映

```
$ source .bash_profile
```

　パス確認

```
$ echo $PATH
usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/Users/{ユーザー名}/.composer/vendor/bin
```

　末尾に `:/Users/{ユーザー名}/.composer/vendor/bin` が追加されていることを確認


 プロジェクト作成

```
$ laravel new {任意のプロジェクト名}
```

　成功のメッセージを確認

```
Package manifest generated successfully.
Application ready! Build something amazing.
```

　動作確認　作成したプロジェクトに移動して**artisan**でバージョン確認＆サーバを起動

```
$ cd PROJECT
$ php artisan --version
Laravel Framework 7.0.8
$ php artisan serve
Laravel development server started: http://127.0.0.1:8000
```

　ブラウザで表示
<img width="874" alt="ローカルサーバ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599693/cb09e4da-18d4-f594-3658-b70af3503875.png">


以上です。

##参考記事
Mac OSにLaravelローカル開発環境構築
https://qiita.com/da-sugi/items/7ee7a458aad4209bab01

Mac OSにLaravel 5.7を導入する方法
https://qiita.com/nemui_/items/a62637a6aa173cbb8b09
Pythonアプリケーションにおすすめなコンテナイメージ

Pythonアプリケーションの実行環境としてどのDockerイメージを選べばいいのか、迷ったことはありませんか。自分は毎回悩んでから公式イメージに落ち着くという判断になりがちだったので、ここではっきりさせておこうと思い比較してみることにしました。皆さんの参考になれば嬉しいです。


## イメージ選択の評価項目

イメージを選ぶとき、以下の観点があると思います。

| 観点       |       内容 |
|:-----------------|:------------------|
| 安定性                  |頻繁にファイル構成や内容が変わるようでは長期的な使用は難しいため、ある程度の安定性が必要です(あまりないとは思いますが)。 <br> そのため、公式に近いイメージを使いたいところです。|
| イメージサイズ             |一番定量的に評価できるのがイメージのサイズになります。これは小さければ小さいほどありがたいですね。|
| セキュリティのアップデート     |セキュリティのアップデートはOSのディストリビューションごとに異なりますが、いつまでサポートしているのかを確認する必要があります。|
| Pythonがインストール済みか  |自分でインストールすることも可能ですが、元からインストールされているほうが手間とビルド時の時間を節約できます。|



## メジャーなディストリビューションの場合

標準的なディストリビューションを使用すれば安定性とセキュリティアップデートのサポート期間も確認できるため非常に安定しています。
しかし、Pythonのアプリケーションを実行するには不要な共通パッケージも多く含まれており、イメージサイズが大きくなりがちです。また、Pythonの最新バージョンは自身でインストールする必要があります。

## Alpine Linuxの場合
イメージを小さくするならalpine-linuxが真っ先に候補に上がるのではないでしょうか。しかし、以下のリンクの記事によるとalpineを使用することで最終的にイメージの容量増加やビルド時間の増大など様々な問題が発生してしまうようです。
[Using Alpine can make Python Docker builds 50× slower](https://pythonspeed.com/articles/alpine-docker-python/)

記事で言及されている内容をまとめると以下のようになります。

* pipでPyPIのライブラリをインストールする際、エラーが起きてしまう可能性がある。alpineではGNUバージョンのCライブラリではなくmusl Cライブラリが使用されているのが原因。
* GNUバージョンで使用できるbinary形式のものがPyPIではメジャーだが、muslの環境で使用する場合は用意されているbinaryを使用できず、ほとんどコンパイルし直さなければならない。そのためビルド時間が伸びてしまう。
* musl Cライブラリを使用していることによる予想し辛いバグが出る可能性が存在する

そのため、alpineは素のイメージサイズは小さいのですが、Pythonの実行環境としては不安が残ります。

## Docker公式のPythonイメージ
PythonをDockerで使う場合は基本的にこのイメージを使う人が多いのではないでしょうか。大まかにタグの種類は以下になります。

| イメージ種類       |   最新の一つ前のタグ(2020/03時点)   | サイズ | 備考 |
|:-----------------|:------------------|:---|:---|
| alpine           |   3.8.1-alpine3.11   |  109MB  | こちらにもAlpineのイメージが存在しますが、上記に記載したデメリットがあるためお勧めではありません。 |
| buster           |  3.8.1-buster        | 933MB | Debianの最新バージョンであるBusterをベースとしたイメージです。多くの基本的なパッケージがインストールされているため軽量ではありませんが、汎用的な用途の場合はこちらを使うといいでしょう。 |
| buster-slim      |  3.8.1-slim-buster   | 193MB | Debianのイメージの内の共通パッケージを省き、その分イメージサイズが小さくなったバージョンです。Pythonアプリケーションのみを使用するのであれば問題はなさそうです。 |

タグを比較してみると、メインのDebianイメージに加えてslimバージョンも存在していることが分かります。こちらはPythonの実行に特化したイメージで、それ以外の多くの機能をバッサリ落としているようです。python-dockerページの注意書きに、「Python実行用途のみでイメージサイズに厳しい制限がある場合にslimを使用し、それ以外ではデフォルトのイメージをお勧めします」と記載してありました。コンテナ内でどこまで実行するかによって選択が変わってきますね。


## 結論

上記の検討結果から、Pythonアプリケーションをシンプルに動作させるのに適したDockerImageはDebian Buster slimという結論に至りました。イメージサイズは198MBで中々コンパクトですね。
【Laravel , Docker】laradockで開発環境構築

#【laradock】macでの環境構築
macでlaravelの開発環境であるlaradockを構築をする流れです。


#導入の流れ
macでlaradockを使えるようにするためには、gitとdockerをインストールする必要があります。

- xcodeのインストール（gitが使えるようになる）
- Dockerのインストール
- laradockのインストール

#xcodeのインストール
事前にアップルIDが必要になります。

アップルストアからインストールします、これでgitが使えるようになります。


#laradockのインストール

dockerで環境構築するフォルダの作成
laradockのインストール

```
$ mkdir laravel_docker && cd laravel_docker
$ mkdir project01 && cd project01
$ git clone https://github.com/Laradock/laradock.git
```

#.envファイルの作成

.envファイルはlaradockの設定ファイル

```
$ cd laradock
$ cp env-example .env
```

##laradockの設定ファイルの編集（.env）

###nginxの設定

```
### NGINX #################################################

- NGINX_HOST_HTTP_PORT=80
+ NGINX_HOST_HTTP_PORT=8888
NGINX_HOST_HTTPS_PORT=443
NGINX_HOST_LOG_PATH=./logs/nginx/
NGINX_SITES_PATH=./nginx/sites/
NGINX_PHP_UPSTREAM_CONTAINER=php-fpm
NGINX_PHP_UPSTREAM_PORT=9000
NGINX_SSL_PATH=./nginx/ssl/
```

###mysqlを使用する場合の設定

```
### MYSQL #################################################

- MYSQL_VERSION=latest
+ MYSQL_VERSION=5.7
MYSQL_DATABASE=default
MYSQL_USER=default
MYSQL_PASSWORD=secret
MYSQL_PORT=3306
MYSQL_ROOT_PASSWORD=root
MYSQL_ENTRYPOINT_INITDB=./mysql/docker-entrypoint-initdb.d
```

#コンテナの作成

```
$ docker-compose up -d nginx
Recreating laradock_docker-in-docker_1 ... done
Recreating laradock_workspace_1        ... done
Recreating laradock_php-fpm_1          ... done
Recreating laradock_nginx_1            ... done
```

##workspaceにログイン

```
$ docker-compose exec --user=laradock workspace /bin/bash
laradock@a651667e1cfc:/var/www$ 
```

##composerを使って、インストール

```
laradock@a651667e1cfc:/var/www$ composer create-project --prefer-dist laravel/laravel="5.8" myapp
```

##laradockの.envファイルの編集

```
# Point to the path of your applications code on your host
- APP_CODE_PATH_HOST=../
+ APP_CODE_PATH_HOST=../myapp
```

##myappのデータベースを設定する（.envファイルを編集）

###mysqlを使用する場合

```
変更前
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret

変更後
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=default
DB_USERNAME=root
DB_PASSWORD=root
```

###sqliteを使用する場合

```
変更前
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret

変更後
DB_CONNECTION=sqlite
```

##ブラウザから確認する
以下にアクセスしてlaravelが表示されていれば、成功です。
お疲れ様でした。

[localhost:8888](http://localhost:8888)

![スクリーンショット 2020-03-10 10.12.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420746/62019d15-e6de-516e-fcc5-5704356d47b8.png)
外部キーを複数設定したい場合のテーブル設計

# 概要
以下のようなテーブルを想定する。

userテーブル

| id | name | pet |
|:-:|:-:|:-:|
|  user1| 太郎  |   |
|  user2 | 花子  |   |

dogテーブル

| id | name |
|:-:|:-:|
| dog1  | ポチ  |

catテーブル

| id | name |
|:-:|:-:|
| cat1  | タマ  |

userテーブルのpetカラムに外部キーをdogテーブルのidとcatテーブルのidと２つ設定したいが、
外部キーは１つだけしか設定できない。

# 解決法１:参照先の親テーブルを作成する
userテーブル

| id | name | pet |
|:-:|:-:|:-:|
|  user1| 太郎  | pet1  |
|  user2 | 花子  |  pet2 |

petテーブル

| id |
|:-:|
|  pet1 |
|  pet2 |

dogテーブル

| id | name |
|:-:|:-:|
| pet1  | ポチ  |

catテーブル

| id | name |
|:-:|:-:|
| pet2  | タマ  |

petテーブルという親テーブルを作成し
userテーブルのpetカラムの外部キーを１つにする。

# 解決法２:子テーブルを作成する
userテーブル

| id | name |
|:-:|:-:|
|  user1| 太郎  |
|  user2 | 花子  |

user_dogテーブル

| id | dog |
|:-:|:-:|
|  user1 | dog1  |

user_catテーブル

| 1 | 2 |
|:-:|:-:|
|  user2 | cat2  |

dogテーブル

| id | name |
|:-:|:-:|
| dog1  | ポチ  |

catテーブル

| id | name |
|:-:|:-:|
| cat1  | タマ  |

user_dogテーブルとuser_catテーブルをというように外部キーによって異なるテーブルを作成する。
ちなみにテーブル情報を取得する際はuser_dogとuser_catをUNIONで和集合を作成しuserテーブルにJOINする。
基本情報技術者　テクノロジ系　第9章　擬似言語プログラム、基本的な処理、二次元配列を利用した処理

[基本情報技術者試験](https://qiita.com/savaniased/items/d3f94da4f087e178cb69)
こちらより


# 擬似言語プログラム

簡単なプログラムの理解のような物
▲や■を用いて、プログラムを表記します。


## ←　(代入)
基本的な変数の書き方と似たような形

a ← 5

## ▲ (条件分岐)
条件成立時の処理か

成立、未成立時の処理を書く

## ■(繰り返し)
繰り返し処理を行う処理

### 前判定型ループに
条件が最初に成立していること前提で

最初に繰り返し条件を書いておき
成立している間続ける

### 後判定型ループ
未成立でも一度は処理をすること前提で

最後に繰り返し条件を書いておき
成立する間最初に戻り続ける。


### for型ループ
繰り返し回数が決まっているのが場合に多く用いられます。

プログラムのforのように
前判定で条件を書いて処理をする形

下記のような形です。
i:0 , i<10 ,1 

## 関数
小さくまとまったプログラムのような物
基本的なプログラム理解していれば解けます。

### 引数
呼び出し元から関数に、必要情報として渡す値

### 返却値
関数の処理結果

## 文字列
文字と文字列を区別して扱います。

### 文字
常に一文字

### 文字列
0文字以上の文字列が並んだもの

### EOS (End Of String)
終端文字という意味で
文字列の最後についています。

制御文字(画面上に表示されない特殊な文字)の一つです。

### クォート
文字はシングルクォート(')
文字列はダブルクォート(")を用いて表します。

# 基本的な処理

## 交換処理
変数の中身を入れ替える処理のことです。

## 配列のコピー
配列のコピーを行う処理です。

コピー先に同じ要素番号のデータを順次入れていくわけです。

## 配列に空きスペースを作る
後方の要素から順に処理していきます。

## 配列の空きスペースを埋める
前方の要素から処理していきます。

## 最大値、最小値を見つける
端の値を仮の最大値(最小値)として設定して
隣の数字と比較して、最大値(最小値)であれば更新し
同じ処理を隣隣と続けていく

# 二次元配列を利用した処理
二重ループを用いて、処理を行います。

二次元配列だと i[A][B]といった形で
座標データが設定されていいます。

まずAの値を示すループを作成して
Aループ内にBループをつくることで
全データを網羅できるようにします。

出力したデータを90度回転などしたい場合は
座標データを計算して、処理内容を修正していきます。
DjangoのAbstractUserモデルにlast_loginが用意されているのにアップデートされない

##Django Rest Frameworkでログインするとlast_loginに更新日が入らない

Django Rest Frameworkを使っていて、アプリユーザーなどにログインしてもらった際にlast_login入ってないなぁと。

これは既知の問題で、last_loginはどうやら今のままでは入らないと。

https://stackoverflow.com/questions/28613102/last-login-field-is-not-updated-when-authenticating-using-tokenauthentication-in

##wrapperを作成し、その中でlast_loginを更新

stackoverflowの通り、update_last_loginを使用してlast_loginを更新するwrapperクラスを作成しました。

```
from rest_framework.authtoken.models import Token
from rest_framework.authtoken.views import ObtainAuthToken
from django.contrib.auth.models import update_last_login
from rest_framework.response import Response
from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED

def get_or_create_token(user):
    token, created = Token.objects.get_or_create(user=user)
    update_last_login(None, user)
    return Response({'token': token.key},
                    status=HTTP_201_CREATED if getattr(user, 'is_new', False) else HTTP_200_OK)

class AuthTokenHandler(ObtainAuthToken):
    def post(self, request):
        serializer = self.serializer_class(data=request.data, context={'request': request})
        if serializer.is_valid(raise_exception=True):
            return get_or_create_token(serializer.validated_data['user'])
```

本来はAuthTokenHandlerクラスに更にserializerを追加して、SNSログインなども出来ているようにしていますが、こんな感じで`get_or_create_token`内で`last_login`をアップデートするようにし、無事解決しました。
Mac Visual Studio Code 導入時に「悪質なソフトウェアかどうかを・・・」と出た話

# 目的

- 題名の問題を解決した時の話をまとめる。

# エラー内容

- Visual Studio Codeのアプリケーションを起動した時に下記のウインドウが開き、アプリが開かない。

    ```
    “Visual Studio Code”が悪質なソフトウェアかどうかをAppleでは確認できないため、このソフトウェアは開けません。

    このソフトウェアはアップデートが必要です。詳しくは開発元にお問い合わせください。

    このファイルは“Chrome”により今日の14:37にcode.visualstudio.comからダウンロードされました。
    ```

![スクリーンショット 2020-03-09 14.48.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/a27f5513-aa66-ffbe-f135-5d187b103343.png)

# 解決方法

1. 「control」を押下しながらダウンロードの「Visual Studio Code」をクリックする。
1. 「開く」をクリックする。  
![スクリーンショット 2020-03-09 14.52.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/e222d407-fa23-2060-238d-4b3e60f7a916.png)
1. 下記のウインドウが開くので「開く」をクリックする。  
![スクリーンショット 2020-03-09 14.54.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/9f7a22e8-d5a3-4d32-2b32-a3832a9b9d7c.png)
1. 正常にアプリを起動する事ができた。  
![スクリーンショット 2020-03-09 14.55.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/243529c9-b732-b7b4-5d2e-edf5a51007be.png)
Wordpress カスタムフィールドプラグイン「smart custom fields」の使い方メモ

#Wordpress カスタムフィールドプラグイン「smart custom fields」の使い方メモ

##ちょっと前置き
今までは[Advanced Custom Fields](https://www.advancedcustomfields.com/)を使っていて問題はなかったのですが
オプションページ、繰り返し機能が有料版にしかないため有料版を購入しようかと調べていたら
無料かつオプションページ、繰り返し機能が付いているプラグインがあったので使い方を調べつつ
自分用のメモとして書いていきます。

実行環境
Windows 10
Xampp

|種類|バージョン|
|:-----------------:|:------------------:|:------------------:|
|php|7.3|
|Wordpress|5.3

##とりあえずインストール
プラグインの新規追加から「smart custom fields」を検索
![smart custom fields.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598642/e5f88296-500d-3835-c94a-d2e28b2f79ec.png)
※未検証と出ているけど問題はないみたい・・・？


##基本的な使い方
###入力部分
インストールが完了したらサイドバーにある「smart custom fields」→「新規追加」
ページ転移したら「カスタムフィールド」内の「フィールドを追加」をクリック
![FireShot  #275  - http.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598642/95354099-501c-cb05-9974-dd3c92a4e8fd.png)
そしたらこんな画面になるのでちょっと解説

|カスタムフィールド|説明
|:-----------------:|:------------------|:------------------:|
|タイトル|表示されるタイトル
|繰り返し| ONにすると複数回入力できるようになる |
|タイプ*|テキストとか画像とか、入力するものを選択
|ラベル|わかりやすい名前
|名前*|わかりやすい名前、**呼び出し時に使う可能性有**
|デフォルト|説明するまでもない初期値
|手順|そのまま、わかりやすい手順を書く
|メモ|メモ・・・？

とりあえずこんな感じに入力したら
![FireShot  #276  - http.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598642/6fe06972-b437-7dbf-d04a-fab56edf7005.png)
右サイドバーの「投稿」をONにして保存。
そうすると投稿編集画面の下部にこんな感じに現れます。
![FireShot  #277  - http.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598642/fd792ae6-c90d-23ce-d3ac-f12b5f9c3a3e.png)

これでひとまず入力部分は完成？です。

###出力部分
入力するだけでは出力してくれないので出力部分を書かないといけません・・・
今回は投稿ページなので通常はsingle.phpを編集します。
※index.phpだったりしますのでご注意をｗ
※確認には[show current template](https://ja.wordpress.org/plugins/show-current-template/)がおススメです

single.phpの中で「the_content()」の関数を探します。
これは投稿編集ページのコンテンツ部分を出力するコードですので
これの周辺に書くことが多いかと思います。

```single.php
<?php the_content(); ?>
<?php echo SCF::get('名前'); ?>
```

とりあえずこんな感じに書くと
![FireShot  #278  - http.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/598642/4c9631df-da45-59cb-4e49-b208eea7677a.png)

表示されるようになります。
OCI コンパートメント階層についての挙動まとめ

#はじめに
Oracle Cloud Infrastructure(OCI)で、コンパートメントが階層になっていて各層にリソースがあるときにオペレーションによって見え方や挙動が微妙に異なる為、まとめ。
※まだ少しなので今後も気づいたときにUpdate

#コンパートメントとは
OCIの各リソース（Computeや仮想NIC、サブネット、ルート表、ストレージなど様々なすべての定義）は必ずどこか１つのコンパートメントに入れる必要があります。
ポリシーによって、グループへコンパートメントに対しての権限を与えることで、認証・認可でいうところの認可の管理をシンプルに構成できます。

例えば、

- 部門Aの人（グループ）は、 自部門に権限委任されたコンパートメントAのリソースのみ管理できる
- ネットワーク管理者（グループ）は、コンパートメントB（ネットワークリソースのみ）を管理できる
- バックアップ管理者（グループ）は、コンパートメントC（ストレージ）を読み取り、コンパートメントD（バックアップ保管用）にバックアップする権限だけ与える
　など

その他、詳細はマニュアルにて。
https://docs.cloud.oracle.com/ja-jp/iaas/Content/Identity/Tasks/managingcompartments.htm


#コンパートメントを階層化した際の、リソース毎の挙動

###権限(認可)：
上位コンパートメントの権限があれば、下位コンパートメントに権限は継承される

###GUIコンソール：
権限はあっても選択したコンパートメントに配置されているリソースしか見えない。下位コンパートメントに配置されたリソースの管理はGUIから都度切り替える必要がある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266598/e7f2e337-2d86-3f4e-6f00-21fbe5dc8217.png)


###コスト分析：
選択したコンパートメントおよび下位コンパートメントの合算金額となる。下位コンパートメントを選択すれば該当コンパートメント以下の合算となる。

###コンパートメントエクスプローラ：
選択したコンパートメントのリソースのみ確認できる。以下のチェックを入れることでコスト分析同様に、下位コンパートメントのリソースをすべて含んだ形で確認できる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266598/a1bc0fa4-6ab1-8433-ea6b-e5819485ba82.png)


###イベント・サービス：
イベント・サービスの検知範囲は、イベント・サービスを配置するコンパートメント及びその配下すべて。
下位コンパートメント内で発生したイベントもすべて検知対象となり、指定することはできない。

###バックアップ作成とか：
バックアップ元とバックアップ先のコンパートメントを分ける場合は、元に対してRead、先に対してManage権限が必要



#【他、TIPS】

- リソースをコンパートメント間で移動できる。ただし、双方のManage権限が必要

- ユーザ、グループ、コンパートメントはグローバルリソースのため、リージョン間で情報は同期されており、ルートコンパートメント（テナンシ）にしか存在できない。

- ポリシーは他のリソース同様に各コンパートメントに配置する。

- 最近、ネットワークリソースという概念が誕生し、接続元IPアドレスよって認可範囲を限定できるようになった。（2020年3月現在はObject Srorageへのアクセスのみ）
Swift ArgumentParser におけるプロパティの定義順の重要性

今回はタイトル通り ArgumentParser を使っている時のプロパティの定義順の重要性について書きます。v0.0.2 で実際に経験していた範囲ですが、まだ ArgumentParser のソースコードを読んだ内容ではないこと、今後のバージョンで変わりうることをご了承ください。

## 前回のエントリのつづき

```swift
import ArgumentParser

struct MyEcho: ParsableCommand {

    static var configuration = CommandConfiguration(commandName: "myEcho")

    struct Version: ParsableArguments {
        @Flag()
        var version: Bool

        func validate() throws {
            if version { throw CleanExit.message("1.0.0") }
        }
    }

    @OptionGroup()
    var version: Version

    @Argument()
    var text: String

    func run() throws {
        print(text)
    }
}

MyEcho.main()
```

上記サンプルコードは[前回の記事](https://qiita.com/griffin_stewie/items/902900372834f81f261a)で紹介した、必須引数とバージョンフラグの両立をするためのコード例です。詳しい内容は前回のエントリを参照ください。

実はこの上記のコードでも前回解決した問題を再び発生させることが出来ます。

## 問題再燃サンプル

```swift
import ArgumentParser

struct MyEcho: ParsableCommand {

    static var configuration = CommandConfiguration(commandName: "myEcho")

    struct Version: ParsableArguments {
        @Flag()
        var version: Bool

        func validate() throws {
            if version { throw CleanExit.message("1.0.0") }
        }
    }

    @Argument()
    var text: String

    @OptionGroup()
    var version: Version

    func run() throws {
        print(text)
    }
}

MyEcho.main()
```

何が変わったかわかりますか？

text プロパティと version プロパティの定義順を変更して text プロパティを先に持ってきました。これだけで

```sh
% myEcho --version
Error: Missing expected argument '<text>'
Usage: myEcho <text> [--version]
```

というエラーになります。

## 結論（経験上）

プロパティの定義順に処理が進むので先に解決して欲しいものは先に書くべし。

もしくは `@Argument()` は必ず最後に書くべしとも言えます。

`@OptionGroup()` の Property Wrapper の init 時に `ParsableArguments` の `func validate() throws` が実行されます。上からプロパティを埋めていくように ArgumentParser は動作しているようなので、引数を処理している最中に `struct Version` のイニシャライズの段階でバリデーション処理でこける（バージョン番号を出力して正常扱いで終了）ために、`@Argument() var text: String` に到達しない。これが、期待する動作を手に入れていたころのコードでした。

プロパティの定義順を text を先にすると、ArgumentParser が引数の処理をしているときに text プロパティに代入するべき値が存在しないため version プロパティの処理をする前に必須項目が欠如しているとしてエラーになります。

## Help や Usage にも影響あり

```sh
% myEcho --version
Error: Missing expected argument '<text>'
Usage: myEcho <text> [--version]
```

このエラー時の Usage の出力をみると引数 text の後ろに version フラグが書かれています。

ためしに前回のエントリの完成形コードを引数もフラグもなしで実行すると

```
Error: Missing expected argument '<text>'
Usage: myEcho [--version] <text>
```

このように version のあとに text が来ています。

プロパティの定義順によって出力される説明の順番にも影響を与えています。

## さらに僕がハマった罠

僕が実際に書いていたコードで、外から引数として与えられはしない固定値としてプロパティに保持したいものがありました。今手元で再現できないのですが、たしか Decodable に対応してないというコンパイルエラーが出ていました。`ParsableCommand` は `ParsableArguments` に準拠しています。さらに `ParsableArguments` は `Decodable` に準拠しています。よって、 `ParsableCommand` は `Decodable` である必要があるのです。ただし、別に Decodable である必要性がなかったプロパティだったので CodingKey を定義して除外できるようにしました。

するとさっきまで動いていたバージョン番号の出力が引数がないと怒られるようになりました。

ずっと謎だったのですが、最終的に分かったことは CodingKey に列挙している case がプロパティの定義順通りになっていなかったからでした。

このせいで結構な時間が溶けていました。

## まとめ

プロパティの定義順は

- パース処理の順番
- Usage や Help の出力の順番
- CodingKey を定義する場合はプロパティの定義順に揃える

ということでした。

常に順番を意識してコードを書きましょう！
Djangoのキャッシュサーバーにfirebaseを使ってみた

##使用背景

会社で運用しているプロダクトではAWSのRedisをキャッシュサーバーとして使っているのですが、自分で使う分には高いし、VPC内からしかアクセス出来ないし(proxyかますなどすれば出来るけど)で、面倒なので他にキャッシュサーバーとして使えるものがないかを探しました。

##簡易なキャッシュ方法

###メモリに乗せる

一番簡単な方法がローカルのメモリに乗せる方法かと思いますが、テストであればこれで十分ですが、本番では不十分なことが多いです。

```
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'default',
        'TIMEOUT': 24 * 60 * 60
    }
```

###DBに乗せる

DBにテーブルを作って、その中にキャッシュデータを作って、それを読みに行くというもの。
当然DBへの負荷が増えますし、DBが肥大化していきます。

```
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'cache_table',
        'TIMEOUT': 24 * 60 * 60
    }
}
```

テーブル作ることが必須。

```
python manage.py createcachetable
```

##Firebaseで出来ないか考える

AWSは使えないし、メモリやDBではしんどいしということが考えたのが、最近良く使うFirebaseのサービスでした。
Firebaseで調べると、なんとパッケージを作ってくれている人がいるではないか。
https://github.com/christippett/django-firebase-cache

ということで、このパッケージを使ってみることにしました。

##導入

使い方は簡易的な上記のものに比べると少し面倒です。

パッケージのインストール。

```
pip install django-firebase-cache
```

CACHESにセット。

```
CACHES = {
    'default': {
        'BACKEND': 'django_firebase_cache.FirestoreCache',
        'LOCATION': 'collection_name',
        'TIMEOUT': 24 * 60 * 60
    }
}
```

Firebaseのcredentialファイルをセットし、パスを通す。
ここが少し迷ったのですが、以下のような感じで、`GOOGLE_APPLICATION_CREDENTIALS`という環境変数にパスを通す必要があります。ドキュメントが全然充実してない、、

```
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = './client_credentials.json'
```

以上で設定完了です。
これで、実際に動かしてみるとFirebaseのFireStore上にデータが入ることが確認出来るかと思います。

##ここから罠が…

ここまででキャッシュは出来るようになったものの、意外と直ぐに無料枠の上限に達してしまいました。。
その場合、当然エラーが返ってくるのですが、そこでエラーを回避する処理をしておらずサイトが数時間死んでいる状態というのが続いていました。。

ちゃんとお金を払うなり、エラー処理をするなりしましょう。
CentOS8にDocker環境でGrowiをセットアップした備忘録

# はじめに
CentOS8のインストールからdocker環境でのGrowi立ち上げまでの手順備忘録

# OSセットアップ
CentOSのインストールは最小構成でインストールした。

# 手順

## ひとまず更新と再起動
```
$ dnf update
$ dnf upgrade
$ reboot
```
※CentOS8からyumでなくdnfになっています。

## Gitのインストール
```
$ dnf -y intall git
```
## Docker-ceのインストール
```
$ dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
$ dnf --nobest install docker-ce
```
※依存性の問題で最新がインストールできないので``--no-best``オプションをつけてインストールが必要

```
$ systemctl start docker
$ systemctl enable docker
```
※自動起動に設定しておく

## docker-composeのインストール
```
$ curl -L "https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ chmod +x /usr/local/bin/docker-compose
```
RedhatがRHEL8よりDockerでなくPodman推しになったため、パッケージマネージャでインストールできなくなっているらしい。

## Growiセットアップ
```
$ git clone https://github.com/weseek/growi-docker-compose.git
$ cd growi-docker-compose
$ vi docker-comopose.yml
```
docker-compose.ymlの変更点は
- services:app:portsを``3000:3000``に変更
- environmentの``PASSWORD_SEED``を変更
- restartを``always``に変更
- volumesにホストのディレクトリを設定

起動
```
$ docker-compose up -d
```

## elasticsearchのプラグインインストールで失敗する場合

``UnknownHost``のエラーが出る場合、DNS名前解決ができていない。
CentOS8からnftabelsはdockerが設定できないため、iptablesを設定するようにする。

```
$ systemctl stop firewalld
$ systemctl disable firewalld
$ dnf install iptables-services
$ systemctl enable iptables
$ systemctl start iptables
```
apt-getとyumの対応表

lpicの受験をするにあたって、パッケージ管理のコマンドが中々覚えられないので、対応表にまとめることにした。[LinuC イージス参考(ほぼ引用)](https://www.infraeye.com/study/studyz4.html)

#オプション比較

|apt-getコマンドのオプション  |説明  |
|---|---|
|-d  |ダウンロードのみ行う  |
|-s  | システムは変更せず、表示のみを行う |
|--purge  |設定ファイルごとパッケージ削除（removeコマンドと一緒に指定）  |

|yumコマンドのオプション  |説明  |
|---|---|
|-y  |すべての質問に yes と回答  |

#サブコマンド比較

##apt-getとyum

|apt-getのサブコマンド |yumのサブコマンド |説明  |
|---|---|---|
|clean | |パッケージファイルの削除 |
|dist-upgrade | |Debianのシステムを最新にアップグレードする |
|install |install  |パッケージをインストール |
|remove | remove |パッケージのアンイストール|
|update |  |インストール可能なパッケージの「一覧」を更新 |
|upgrade | update |システムの全パッケージを最新版にアップグレードする |

##apt-cacheとyum

|apt-cacheのサブコマンド |yumのサブコマンド |説明  |
|---|---|---|
||check-update|アップデート対象となるパッケージ一覧を表示|
|show|info|パッケージ詳細情報の表示|
||list|パッケージ情報をリスト表示|
||repolist|リポジトリ一覧の表示|
|search|search,search all|パッケージ情報をキーワードで検索|
||grouplist|パッケージグループのリスト表示|
||groupinstall|指定したグループのパッケージをインストール|
|showpkg||パッケージのバージョン、依存関係を表示|
|depends||パッケージが依存するパッケージの一覧を表示|

とりあえずまとめましたが、またコマンドを実際に使ったりして、対応表を修正していこうと思います！
🌏【QUIC】ChromeにてQUICを有効にする方法


## 内容

HTTP-over-QUIC→HTTP/3

## 環境

Google Chromeバージョン: 80.0.3987.132（Official Build） （64 ビット）

## やったこと

chromeで下記URLにアクセス

```
chrome://flags/#enable-quic
```

quicで検索し、Experimental QUIC protocolをEnabledに変更してchromeを再起動する

![S__25403450.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188242/a124e15a-8bda-cf23-d65f-cc089ddb3276.jpeg)

## その他

flagsには試験運用中の機能が色々あるので合間に試してみたい

```
chrome://flags
```
初心者向け入門書を読んでみた 第2弾

以前執筆した「[初心者向け入門書2冊を比較してみた](https://qiita.com/Haruka_mm_0950/items/3d5cffbf2b7d621418d7)」という記事で、紹介した本それぞれについて記事を書くと言っていたのにずっと放置していたので、1冊ずつ紹介していきます。
今回は『[基礎からのプログラミングリテラシー](https://www.amazon.co.jp/%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E3%81%AE%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%83%AA%E3%83%86%E3%83%A9%E3%82%B7%E3%83%BC-%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF%E3%81%AE%E3%81%97%E3%81%8F%E3%81%BF%E3%81%8B%E3%82%89%E6%8A%80%E8%A1%93%E6%9B%B8%E3%81%AE%E9%81%B8%E3%81%B3%E6%96%B9%E3%81%BE%E3%81%A7%E5%8E%B3%E9%81%B8%E3%82%AD%E3%83%BC%E3%83%AF%E3%83%BC%E3%83%89%E3%82%92%E3%81%8F%E3%82%89%E3%81%B9%E3%81%A6%E5%AD%A6%E3%81%B6-%E5%A2%97%E4%BA%95-%E6%95%8F%E5%85%8B/dp/4297105144/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%83%AA%E3%83%86%E3%83%A9%E3%82%B7%E3%83%BC&qid=1573986725&s=books&sr=1-1)』を紹介します。


#どんな本？
表紙にも書かれているとおり「用語集」です。
「あの言葉とこの言葉、似てるけど何が違うんだろう？」と疑問に思った時に開く本です。
なので、[以前の記事](https://qiita.com/Haruka_mm_0950/items/3d5cffbf2b7d621418d7)で書いたように「そもそもプログラミングって何？」という状態でいきなり読むと、ちんぷんかんぷんです。
[こちら](https://qiita.com/Haruka_mm_0950/items/2c9307784c772cf81ab4)で紹介した入門書を読んだ後に読むことをおすすめします。


#おすすめしたい理由
この本をおすすめしたい理由は、以下の3点です。

**1. 同じ場面で使われる単語を比較しながら理解できる**
**2. 概念だけでなく業界構造や職種も網羅**
**3. 技術書の選び方もレクチャー**

以下でひとつずつ説明していきます。


##1. 似たような単語を比較しながら理解できる
似たような単語を比較しながら、それぞれがどういったものか、それぞれの違いは何か、ということを説明していくのが、この本の基本的な内容です。
1つの内容につき、2～3ページほどで説明していることが多いので「あれとこれの意味、なんだっけ？」と疑問に思った時にすぐに調べることができます。
また、違いが分かることで、別の機会に該当の単語に触れた時に混乱が少なくて済むようになります。
ちなみに、著書内で取り上げられているのは「ディレクトリとフォルダ」「コーディングとプログラミング」「フレームワークとライブラリ」などです。


##2. 概念だけでなく開発スタイルや職種も網羅
[初心者向け入門書を読んでみた 第1弾](https://qiita.com/Haruka_mm_0950/items/2c9307784c772cf81ab4)で紹介した本は、プログラミングの概念や考え方の説明がメインでしたが、今回の本は開発スタイルや職種についても触れています。
例を挙げると「ウォーターフォールとアジャイル」「システムエンジニアとプログラマー」など。
プログラミングの概念だけでなく、業界用語も網羅しています。
業界のことも少しだけ知ることができます。


##3. 技術書の選び方もレクチャー
この本は用語集ですが、巻末に技術書の選び方についても書かれています。素晴らしき親切設計。
最初にこちらの本を買ってしまった場合は、先に技術書の選び方のページだけ読むのもありかもしれません。
ちなみに、著書では「図解の多い本がおすすめ」と述べています。
慣れてくれば文字だけでもいいかもしれませんが、初心者だったり、活字が苦手な方には図解があったほうが理解が進むでしょう。


#まとめ
冒頭から述べているとおり「用語集」なので、全体像をつかむなら別の本をおすすめします。
(以前の記事で紹介した『[改訂3版 これからはじめるプログラミング 基礎の基礎](https://www.amazon.co.jp/%E6%94%B9%E8%A8%823%E7%89%88-%E3%81%93%E3%82%8C%E3%81%8B%E3%82%89%E3%81%AF%E3%81%98%E3%82%81%E3%82%8B%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%E5%9F%BA%E7%A4%8E%E3%81%AE%E5%9F%BA%E7%A4%8E-%E8%B0%B7%E5%B0%BB-%E3%81%8B%E3%81%8A%E3%82%8A/dp/4297101181)』など)
ですが、手元に置いておくことでいつでも振り返ることができるので、リファレンスとして持っておくのは良いかと思います。


#関連記事
[初心者向け入門書2冊を比較してみた](https://qiita.com/Haruka_mm_0950/items/3d5cffbf2b7d621418d7)
[初心者向け入門書を読んでみた 第1弾](https://qiita.com/Haruka_mm_0950/items/2c9307784c772cf81ab4)
初心者から始めるJava、クラス宣言・オブジェクト生成

#はじめに
この記事は備忘録である。
参考書レベルの内容だが、本記事に掲載するコードについては、
**間違えた**ものが中心となる。これは実際にコーディング中に間違えた部分を掲載し、自分で反省するために投稿するという目的によるもの。
また、後日にJavaSilver試験問題の勉強を兼ねて復習するため、深い部分の話はここでは触れない。

なお今回は間違えを扱わない。クラスの話はJavaにおいて重要なうえ、狙って間違えられるほど僕の理解も進んでいない。定義を正しい形で再確認するため、ご容赦いただきたい。
##環境
言語：Java11、JDK13.0.2
動作環境：Windows10

#クラス

```Java:Hello,world!.java
class helloWorld
{
public static void main(String[] args)
  {
    System.out.println("Hello,world!");
  }
}
```
これは一番簡単なプログラムであり、Javaにおける`Hello,world!`出力を行うものである。最初の行に出てきているが、今回のテーマは**クラス(`class`)**。Javaを扱う上で必ず扱う機能となる。
参考書の[「やさしいJava　第7版」](http://mana.on.coocan.jp/yasaj.html)によると
>クラスとは、
>モノの状態・性質や、それにかかわる機能をまとめながらプログラムを作成していくために使う概念

である。今の僕の理解だと`class`は、具体的な個々のモノを扱う前に参考となる見本、いわば雛型を用意する認識だ。

##オブジェクト

```Java:Cat.java
class Cat
{
String name;
double weight;
double size;
String color;
int ID;
String voice;
//挙げ始めるとキリがない！！
}
```
このクラスには「一般的な猫」が持つステータスのごく一部を宣言させた。だがこれは「僕の猫」の特徴が入っているわけではない。
実際に「僕の猫」ステータスを持つ`mycat`をメインメソッドの処理中に作ってみる。

```Java:myCat.java
class myCat
{
  public static void main(String[] args)
  {
    Cat mycat = new Cat();
    //mycat変数にCatクラスのオブジェクトを生成
    
    mycat.name = "テト";
    mycat.color = "brown";
    mycat.ID = 3;

   System.out.println("僕の猫、名前は" + mycat.name + "。");
   System.out.println("色は" + mycat.color + "、" + mycat.ID + "番目の猫だ。");
  }
}

//出力結果：僕の猫、名前はテト。
//色はbrown、3番目の猫だ。
```
`class Cat`で定義され、`Cat mycat = new Cat();`でmycatに作られたのが**オブジェクト(object)**あるいは**インスタンス(instance)**である。

#終わりに
次回の予定は、プログラムを触った人なら必ず最初に書く`Hello,World!`を出力するプログラムを扱うつもりだ。本来なら真っ先に書くべきだとは思ったが、`Python`から入った身としては`Java`の`Hello,World`は最初からクラスを使う必要がありとても難しかったため、ここまで待った。

次の次の回では、今回割愛した**フィールド**や**メソッド**を扱う予定。
今回は内容が薄かったが、ここから先があまり自信がない部分なので、今の実力の指標として分けさせてもらう。
#参考
出来るだけ自分で変数や式を書いてコンパイルしているので、完全に引用する場合はその旨記述する。

[やさしいJava 第7版](http://mana.on.coocan.jp/yasaj.html)
[Java SE11 Silver 問題集](https://book.impress.co.jp/books/1118101186)（通称黒本）
columnコマンドをUbuntuにインストール

columnコマンドは短いたくさんの出力を端末上で複数列に表示して見やすくしてくれるコマンドです。表形式、マルチカラムみたいになります。

例えばですが、まずはcolumnコマンドを使わないとこういう出力になるコマンドがあるとします。

```console
$ seq 1 30
1
2
3
4
5
...
```

縦に長くなって見づらい場合です。

これをcolumnコマンドを使うとこうなります。

```console
$ seq 1 30 | column
1       4       7       10      13      16      19      22      25      28
2       5       8       11      14      17      20      23      26      29
3       6       9       12      15      18      21      24      27      30
```

端末の横幅に合わせて列を調整してくれます。

`-x` を付けると、横方向になります。

```console
$ seq 1 30 | column -x
1       2       3       4       5       6       7       8       9       10
11      12      13      14      15      16      17      18      19      20
21      22      23      24      25      26      27      28      29      30
```

lsコマンドではcolumnを付けなくても勝手にcolumnと同じような動きになってくれますが、これと同じことを他のコマンドでも使いたい場合に便利ですね。

```console
$ ls /
bin   dev  home  lib32  libx32  media  opt   root  sbin  sys  usr
boot  etc  lib   lib64  md      mnt    proc  run   srv   tmp  var
```

# インストール

columnコマンドはUbuntuの最小構成だとインストールされてないようで、`bsdmainutils`という名前のパッケージでインストールできました（Ubuntu 19.10）。

```console
$ sudo apt update
$ sudo apt install bsdmainutils
```

（CentOSでは最小の構成でも入っていそう）

# bsdmainutilsについて

`bsdmainutils` にはいくつかのコマンドが含まれています。以下でインストールされたファイルがわかります。

```console
$ dpkg -L bsdmainutils
```

`/usr/bin` には以下のコマンドがインストールされました。

- bsd-from
- bsd-write
- calendar
- col
- colrm
- column
- hexdump
- look
- lorder
- ncal
- printerbanner
- ul

詳細は未調査です。以上。
[Kaggle] ep.1 - タイタニックでなんとなく雰囲気を掴む

# tldr
サンプルのタイタニックをやってみました。

目次は[こちら](https://qiita.com/kentakozuka/items/7cbb3006540d3dc9573a)

# 始める

参考図書は以下を使います。

- 「[Kaggleで勝つデータ分析の技術](https://www.amazon.co.jp/gp/product/B07YTDBC3Z/ref=ppx_yo_dt_b_d_asin_title_o02?ie=UTF8&psc=1)」

# コード
# データの読み込み

Google Driveからデータを読み込む準備をします。
以下を実行すると認証・認可画面に飛ばされて、Googleアカウントでログインすると認証コードがコピーできます。
それを入力するとGoogle Driveがマウントされます。

```python
from google.colab import drive
drive.mount('/content/drive')
```

次に色々なライブラリのインポートを行ったのちに、Google Driveからトレーニングデータとテストデータを読み込みます。

```python
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import statsmodels.api as sm
import numpy as np

train = pd.read_csv("/content/drive/My Drive/Colab Notebooks/data/titanic/train.csv")
test = pd.read_csv("/content/drive/My Drive/Colab Notebooks/data/titanic/test.csv")
```

# 学習データとテストデータを特徴量と目的変数に分ける

```python
#学習データを特徴量と目的変数に分ける
train_x=train.drop(['Survived'],axis=1)
train_y=train['Survived']

#テストデータは特徴量のみなので、そのままで良い
test_x=test.copy(
```

# 不要なデータを取り除く

```python
from sklearn.preprocessing import LabelEncoder

# PassengerIdの削除
train_x = train_x.drop(['PassengerId'], axis=1)
test_x = test_x.drop(['PassengerId'], axis=1)

# Name, Ticket and Cabinの削除
train_x = train_x.drop(['Name', 'Ticket', 'Cabin'], axis=1)
test_x = test_x.drop(['Name', 'Ticket', 'Cabin'], axis=1)

# label encodingを文字列に適用する
for c in ['Sex', 'Embarked']:
  le = LabelEncoder()
  le.fit(train_x[c].fillna('NA'))

  train_x[c] = le.transform(train_x[c].fillna('NA'))
  test_x[c] = le.transform(test_x[c].fillna('NA'))
```

# モデルを作成する
```python
from xgboost import XGBClassifier

# モデルを作成して、学習する
model = XGBClassifier(n_estimators=20, random_state=71)
model.fit(train_x, train_y)

# テストデータの予測値を確立で出す
pred = model.predict_proba(test_x)[:, 1]

# テストデータの予測値を2値に変換
pred_label = np.where(pred > 0.5, 1, 0)

# 提出用のファイルを作成
submission = pd.DataFrame({'PassengerId': test['PassengerId'], 'Survived': pred_label})
submission.to_csv('submission_first.csv', index=False
```
[Kaggle] ep.3 - データセット

# tldr
Kaggleにおけるデータセットについて勉強した

## データセットとは
コンペで提供されるデータのこと

## データセットの種類

### テーブルデータ

### 外部データ

### 時系列データ

### 画像や自然言語などのデータ
【随時更新】firebase Tips集

# firestore

## indexをファイルで管理する

indexはWebコンソールでも設定できるが、複数環境で共通のindexを使いたい場合はファイル(`firestore.indexes.json`)で管理するほうがよい。

運用としては
1. エラーログに出てくるURLからWebコンソールでindexを追加
2. `firestore.indexes.json`をダウンロード
3. ローカルリポジトリの`firestore.indexes.json`に上書き
の手順が楽そう。

`firestore.indexes.json`のダウンロード&上書き方法

```bash

# firestore.indexes.jsonのあるディレクトリへ
cd your-project 

firebase firestore:indexes > firestore.indexes.json
```

*deployするとjsonでコンソールの設定が上書きされるので忘れずにjsonに反映すること

# cloud functions
## cloud functionsで環境変数を使う

API KEYなど重要な情報を扱うとき。

```bash
firebase functions:config:set aws.apikey=XXXXXXXXXXXX

# 確認
firebase functions:config:get
```

## cloud functionsのconfigをエミュレーターに反映

```bash
cd functions
firebase functions:config:get > .runtimeconfig.json
```
[Kaggle] ep.X - 線形モデル

# tldr

線形モデルについて学習しました。

# 線形モデル

単体では精度は高くなく、GBDTやニューラルネットに勝てることはほぼない。
アンサンブルの１つのモデルやスタッキングの最終層に適用するなどの使いみちが主になる。

回帰タスクの場合は以下のような線形モデルになる

```math
y = b_0 + b_1 x_1 + b_2 x_2 + \dots
```

学習するのは各変数に対する係数`b_0, b_1, b_2, ...` 。

分類タスクの場合はロジスティック回帰モデルが使われる。
ロジスティック回帰とは、線形回帰にシグモイド関数を適用することにより予測値の取りうる範囲を(0,1)に制限し、確率を予測するモデルとしたもの。

```math
y\prime = b_0 + b_1 x_1 + b_2 x_2 + \dots
\\
y = \frac{1}{1 + exp(-y\prime)}
```

# 特徴

- 特徴量は数値
- 欠損値を扱うことはできない
- GBDTやニューラルネットと比較して精度は高くない
- 非線形性を表現するためには、明示的に特徴量を作成する必要がある
- 相互作用を表現するためには、明示的に特徴量を作成する必要がある
- 特徴量は基本的には標準化が必要
- 特徴量を作るときに丁寧な処理が必要
- L1正則化を行った場合、予測に寄与していない特徴量の係数が0になる性質がある

# 主なライブラリ

- scikit-learnのlinear-modelモジュール
- vowpal wabbit

# 目的関数

## 回帰の場合

平均2乗誤差を最小化するように学習する

## 分類の場合

2値分類の場合はloglossを最小化するように学習する。
マルチクラス分類の場合はone-vs-restと呼ばれる方法とmulti-class loglossを最小化する方法の2種類ある。


# ハイパーパラメータ

チューニングが必要なパラメータは基本的に正則化の強さを表す係数のみ。
【ClozeTS】TypeScript穴埋めクイズ#2 (Tuples)

[ClozeTS]とは、TypeScriptの穴埋めクイズです。コードの一部が「穴」になっていて、その部分に適切なコードを当てはめて解く形式のクイズです。

[ClozeTS]: https://qiita.com/suin/items/3090ce2d1b1407577006

## 問題

このTypeScriptコードの中の`__MISSING_CODE__`を適切なコードに置き換えて、コードを完成してください。

```typescript
let x: __MISSING_CODE__;
x = ["hello", 10];
x = ["cool!", 20];
x = [10, "hello"]; // Error
x = [10]; // Error
x = ["hello"]; // Error
```

→**[TypeScript Playgroundでコードを書く](http://www.typescriptlang.org/play/?esModuleInterop=false&declaration=false&module=1&ssl=1&ssc=8&pln=1&pc=24#code/DYUwLgBAHgXBD68CyBJAymlA5A4vAwgPIAiAoogNwBQUEAvBANoBEAFiMMAPbMA0EARgAMAXWq0GLAMZcuwAIR8IAJlHj6TYfzYduzMRAD0hiKQBOZrmZobGwg8dMWrNyTs48HJ85bNA)**←

__ルール__

* コメントで`Error`と書かれた行は、**コンパイルエラーになる**ようにする。
* それ以外の行は、コンパイルエラーにならないようにする。
* 型に`any`は使ってはならない。(any縛り)
* `__MISSING_CODE__`の部分以外は変更してはならない。
* コードを書く際にはTypeScript Playgroundをお使いください。(バージョンやコンパイル設定統一のため)

__ヒント__

* [基本の型 | TypeScript 日本語ハンドブック | js STUDIO](http://js.studio-kingdom.com/typescript/handbook/basic_types#tuple)

__解けたら__

* 回答はコメント欄に投稿する。(任意)
* 自分と同じ回答がある場合、投稿の代わりに「いいね」する。(任意)
* 気に入った回答には「いいね」する。(任意)
* 技巧輝く回答には、ちょっとした解説を添える。(任意)
* →[Q.なぜコメントしたり、いいねするといいの？](https://qiita.com/suin/items/3090ce2d1b1407577006#2-%E3%82%B3%E3%83%A1%E3%83%B3%E3%83%88%E6%AC%84%E3%81%A7%E5%9B%9E%E7%AD%94%E3%82%92%E5%85%B1%E6%9C%89%E3%81%99%E3%82%8B)

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">【ClozeTS】TypeScript穴埋めクイズ#2 (Tuples)<a href="https://t.co/bTLoZZ46f6">https://t.co/bTLoZZ46f6</a><br><br>このクイズの難しさはどのくらいでしたか？</p>&mdash; suin (@suin) <a href="https://twitter.com/suin/status/1237165450967961601?ref_src=twsrc%5Etfw">March 9, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
[Kaggle] ep.3 - 評価指標

# tldr

評価指標について勉強しました。

# 評価指標の種類

## 回帰における評価指標

### RMSE

`Root Mean Squared Error`

各レコードの目的変数の真の値と予測値の差の2乗の合算値を平方根取ったもの

```math
RMSE = \sqrt{\frac{1}{n}\sum_{i=1}^{n} (y_i-\hat{y_i})^2}
```

`scikitlearn`の`metrics.mean_squared_error`で計算可能

### RMSLE

`Root Mean Squared Logarithmic Error`

真の値と予測値の対数をそれぞれとったあとの差の二乗の平均の平方根


```math
RMSLE = \sqrt{\frac{1}{n}\sum_{i=1}^{n} (\log(1 + y_i) - \log(1 + \hat{y_i}))^2}
```

> 目的変数が裾の重い分布を持ち、変換しないままだと大きな値の影響が強い場合や、真の値と予測値の比率に着目したい場合に用いられる。上式の二乗括弧内の式において、となることからも、この指標は比率に着目していることが分かる

`scikitlearn`の`metrics.mean_squared_log_error`で計算可能

### MAE

`Mean Absolute Error`

真の値と予測値の差の絶対値の平均によって計算される。

```math
MAE = \frac{1}{n} \sum_{i=1}^{n} |y_i = \hat{y_i}|
```

> MAEは外れ値の影響を低減した形での評価に適した関数

`scikitlearn`の`metrics.mean_absolute_error`を用いて計算可能

### 決定係数

```math
R^2
```

`scikitlearn`の`metrics.r2_score`で計算可能

## 二値分類における評価指標～正例か負例かを予測値とする場合

二値分類の評価指標は以下の2つに分けられます。

- 各レコードが正例であるか負例であるかを予測値とし、それに対して評価を行う評価指標
- 各レコードが正例である確率を予測値とし、それに対して評価を行う評価指標

### 前提となる知識

#### 混同行列

`Confusion matrix`

#### 正答率 (Accuracy) と誤答率 (Error rate)

#### 適合率 (presition) と再現率 (recall)

#### F1-scoreとFβ-score

```math
F_1 = \frac{2}{\frac{1}{recall} + \frac{1}{precision}} = \frac{2 \cdot recall \cdot precision}{recall + precision} = \frac{2TP}{2TP + FP + FN}
```

```math
F_{\beta} = \frac{(1+\beta^2)}{\frac{\beta^2}{recall} + \frac{1}{precision}} = \frac{(1+\beta^2) \cdot recall \cdot precision}{recall + \beta^2precision}
```

#### MCC
`Matthews Correlation Coefficient`

不均衡なデータに対してモデルの性能を適切に評価しやすい指標

```math
MCC = \frac{TP \cdot TN = FP \cdot FN}{\sqrt{(TP + FP)(TP+FN)(TN+FP)(TN+FN)}}
```


### 各レコードが正例であるか負例であるかを予測値とし、それに対して評価を行う評価指標

#### logloss
分類タスクでの代表的な評価指標

- 低い方が良い指標

```math
logloss = -\frac{1}{N} \sum_{i=1}^{N} (y_i \log p_i + (1-y_i) \log(1-p_i)) = -\frac{1}{N} \sum_{i=1}^{N} \log \acute{p}_i
```

#### AUC
`Area Under the ROC Curve`
vueでfullcalender + localstorage

#概要

vueでfullcalender + localstorageやって見た。

#閃き

calenderに、localstorage使えば、アプリになるんじゃね。

#写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/2c7e25b7-0e49-1478-7205-cf95399e7069.png)


#成果物

https://embed.plnkr.co/plunk/4zb0FyCd3Y5RPFTHFg7O

以上。
GCE メモリ使用量 (インスタンス作成直後)

## `free` コマンドで確認

* `Debian 9`が一番使用メモリ少なかった。

| 名称 | 使用メモリ(MB) |
|:--|--:|
| CentOS 6 | 144 |
| CentOS 7 | 165 |
| CentOS 8 | 220 |
| ContainerOptimized 69 | 127 |
| Debian 9 | 84 |
| Debian 10 | 132 |
| Ubuntu 16.04 | 112 |
| Ubuntu 18.04 minimal | 165 |

## スワップ設定

* [How to enable swap/swapfile on Google container optimized OS on GCE? - Stack Overflow](https://stackoverflow.com/questions/58210222/how-to-enable-swap-swapfile-on-google-container-optimized-os-on-gce)

```sh
sudo -s

# container optimized OS ではswaponに以下が必要
sysctl vm.disk_based_swap=1

# 2GBのスワップファイル作成
fallocate -l 2G /home/swapfile
chmod 600 /home/swapfile
mkswap /home/swapfile
swapon /home/swapfile
echo "/home/swapfile none swap sw,nofail 0 0" >> /etc/fstab
```

もしくは cloud-initに以下記載

```yaml
bootcmd:
- sysctl vm.disk_based_swap=1
- fallocate -l 2G /var/swapfile
- chmod 600 /var/swapfile
- mkswap /var/swapfile
- swapon /var/swapfile
```

### coder-server

```sh
mkdir -p $HOME/coder/{home,data}
chmod 777 $HOME/coder/{home,data}
```

```sh:port80が空いているか確認
docker run -it \
  -p 80:80 \
  nginx
```

```sh
docker run -it \
  -p 80:80 \
  -e PASSWORD=hogehoge \
  -v $HOME/coder/home:/home/coder/ \
  -v $HOME/coder/data:/home/coder/project/code-server \
  codercom/code-server code-server
```


----

## VirtualBoxをインストール

※ GCEではvirtualboxで仮想マシンを動かすことはできませんでした。(`vt-x is not available`)

```sh
apt-get update

dpkg -i "virtualbox-6.1_6.1.4-136177~Debian~stretch_amd64.deb"
apt-get -f install -y
apt install -y gcc make perl linux-headers-amd64

sudo /sbin/vboxconfig
```

```sh:extension
sudo VBoxManage extpack install \
 Oracle_VM_VirtualBox_Extension_Pack-6.1.4.vbox-extpack
```

### VNC server

```sh
apt install -y tightvncserver

vncserver :0
# パスワード入力
```

```sh
DISPLAY=:0 virtualbox
```
sudoではリダイレクト書き込みができない。その対応策。 

##sudoでリダイレクト書き込みをしようとしたら、Permission denied
オーナーがrootのあるファイルに、sudoで権限付与されたコマンドの出力結果をファイルに書き込もうとしたところ、Permisson deniedが出て書き込みできませんでした。
その対処法を見つけたので記します。

###環境
RaspberryPi4 + Raspbian Buster(10.3)
ラスパイ上で起きた現象ですが、Linux全般に言えると思います。

###現象

例えば、wpa_supplicant.confという、オーナーがrootのファイルに、$wpa_passphrase コマンドの出力結果を追記しようとしたとします。

```
$sudo wpa_passphrase SSID PASSPHRASE >> /etc/wpa_supplicant/wpa_supplicant.conf　
```

以下のエラーが出ます。

```
-bash: /etc/wpa_supplicant/wpa_supplicant.conf: Permission denied
```

###原因
なぜなら、sudoで権限を得るのはsudoの後に入力されるコマンド（この場合、wpa_passphraseコマンド）のみで、リダイレクト（>>）は一般ユーザーで実行されてしまうためです。

###対処方法
リダイレクトの代わりにteeコマンドを使うことで書き込みが出来ます。

```
$sudo wpa_passphrase SSID PASSPHRASE |sudo tee -a /etc/wpa_supplicant/wpa_supplicant.conf
```

-a コマンドは既存ファイルに追記するteeコマンドのオプションです。
結果、以下のように書き込まれます。

```
pi@raspberrypi:~ $ sudo cat /etc/wpa_supplicant/wpa_supplicant.conf

～中略～

network={
        ssid="SSID"
        #psk="PASSPHRASE"
        psk=[暗号化されたパスフレーズ]
}
```
[Kaggle] ep.X - ニューラルネット

# tldr

ニューラルネットについて学習しました。


# ニューラルネットとは

テーブルデータに対しては、中間層が2から4層程度の全結合層からなる多層パーセプトロン（Multi Layer Perceptron）という構造がよく使用される。

ある層のユニット `i` の出力値 `z_i`については、以下のように計算される

```math
u_i = \sum_j z \prime_i w_i, j
```

## シグモイド関数

出力値は[0,1]になる。

```math
f(x) = \frac{1}{1+exp(-x)}
```

## ソフトマックス関数

出力値を(0,1)に制限し、またそれぞれの出力の和は1となる

```math
f_i (x_1, x_2, \dots , x_k) = \frac{exp(x_i)}{\sum_{k=1}^{K} exp(x_k)}
```

## 特徴

- 特徴量は数値
- 欠損値を扱うことができない
- 非線形や変数間の相互作用が反映される
- スケーリングの必要がある
- ハイパーパラメータ次第で精度がでないことがある
- 他クラス分類に比較的強い
- GPUでの高速化
- GBDTに比べるとモデリングやチューニングに手間がかかる

## 主なライブラリ

- keras
- pytorch
- chainer
- tensorflow
Rim fdraw As require ’pop->File->Draw'

#ファイルの有無を調べなければインストール
```
Sik pop　＠popのインストール
echo Sik pop @こうすれば同時にログも取れて安心(あればtrueなければfalse)
```

```
Rim require "pop" @ライブラリの取り込み
Rim fdraw As require "pop->file->draw"
```

Rimはファイル自身。requireは文字列の名前空間を探す。asは別名を作成

```
@代入にはset簡単でしょ
n set loop t of count 10 to if t->mod 2 = 1:{1,t->tostr}:{2,t->tostr}
call T t->add1 n 0

@メソッド定義
Trait T
bind f h m n = h->each->(m)->append n
Trait end

@メソッド定義
Method T extends Trait
@めんどくさけりゃusing ? repeat $だぜ!
using bind repeat $
$add1 h m = f h m 1 @h->each->(0)->inc とも書ける
$inc h m = h->each->(m)->inc
$dec h m = h->each->(m)->dec 
Proc Construct me-lily ,grp set {}
Lily grp set grp
img set{fdraw'{}'->Format C:\Data\Mg.png ->Image 1}
ndir set nodir
chdir img->(0)->Getdir
Lily geekimg set img
Proc End-> nil
Method End
```
Gatsby.js でTypeScriptの型検査をする

Gatsby.jsでTypeScriptを使うとなると、公式の `gatsby-plugin-typescript` が選択肢に上がるのですが、このプラグインは、babelによってTypeScriptをトランスパイルしているため型検査が効きません。

VSCodeやIntelliJなどのエディタで見れば型エラーはわかるのですが、やっぱり型検査をしたいですよね。

ということでGatsby.jsで型検査をするための設定例を書きます。

# 型検査の有効化
TypeScriptモジュールを追加して、tscコマンドで型検査だけそちらで行うようにするだけです。

### 1. TypeScriptの追加
tscコマンドを使うためにTypeScriptをdevDependencyに追加します。

```
yarn add -D typescript 
```

### 2. tsconfig.jsonの追加
TypeScriptの設定ファイルである `tsconfig.json` を作成します。
方針に合わせて適宜必要な設定を入れてください。

```
npx tsc --init
```


### 3. package.jsonの修正
あとはtscの実行をscriptsに追加するだけです。
`type-check` で型検査を実行します。 `noEmit` は型検査だけ実行してJSファイルの出力は行わないというオプションです。

```json
  "scripts": {
    ...
    "build": "npm run type-check && gatsby build",
    "type-check": "tsc --noEmit",
  },
```

上の設定ではbuild前にtype-checkを実行するように設定していますが、git の pre commit に追加してcommit前に実行するようにしても良いと思います。


# 終わりに
以上、「GatsbyでTypeScriptの型検査をする」でした。
書いてみたら特段Gatsby.jsならではではなくBabelでTypeScriptをトランスパイルした経験がある方ならば当たり前のこととなってしまいました。。

ただ自分は最初 `gatsby-plugin-typescript` も型検査するものと勘違いしていて、詰まったのでまとめました。

もっとより良い方法あればコメントなどで教えて頂けると嬉しいです!!!!
初心者によるプログラミング学習ログ 258日目

#100日チャレンジの258日目
twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。
100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。
258日目は、

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">おはようございます<br>258日目<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/1237106675519074310?ref_src=twsrc%5Etfw">March 9, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>