OmniAICreator/Qiita-1.07M huggingface dataset:
HTML5プロフェッショナル レベル2 から学んだこと

## はじめに

フロントの勉強を踏まえてHTML5プロフェッショナル レベル2を受験しました。
結果は合格することができました。
ただ資格を取るのではなく、対象の資格を受験または問題集を解くことで
自分がフロントの知識として学んだことを共有しようと思い記事にします。

## 資格について
HTML5プロフェッショナル認定試験には以下があります。  
・HTML5プロフェッショナル レベル1
・HTML5プロフェッショナル レベル2

レベル1の出題範囲は**HTML・CSSが50%、残りの50%がjavascript**
レベル2の出題範囲は**javascript100%**になります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2338886/3daf76e4-0dfb-1b21-984a-7a0e21f1e4c6.png)



「レベル2、HTML関係ないやんけぇ！！！」って思うかもしれないですが
javascriptはhtml5と切っても切れない関係です。

ちなみにレベル1、レベル2両方取得して初めて有効になります。
自分はレベル2から受験しました。順番は特に決まりがありません。
そのかわりレベル1を取得しないと有効にならない為、レベル1の受験が必要になります。

## レベル2の内容について

出題内容は以下になります。

・javascript文法
・javascriptAPI
・グラフィック・アニメーション
・マルチメディア
・ストレージ
・通信
・デバイスアクセス
・パフォーマンスとオンライン
・セキュリティモデル

全部大事なことなんですが、全て説明してると肥大化する為、特に学んでよかったなと思う以下3つを紹介していこうと思います。
・javascript文法
・javascriptAPI
・ストレージ

### javascript文法

実はjavascript文法を蔑ろにしながら開発をしていた為、今回の勉強で学ぶ事が多かったです。主に勉強になった点は以下の内容です。
・プリミティブ型と、オブジェクト型
・変数の巻き上げ
・URLエンコード


ここでは「変数の巻き上げ」について、公式の過去問から1問だけ抜粋して紹介します。

#### 変数の巻き上げ

>以下のスクリプトを実行した出力結果として正しいものを選択しなさい。 
function fn() {
 　{
 　　var x = 'a';
 　}
  　console.log(x);
}  
fn();

A.エラーになり、何も出力されない
B.undefined
C.NULL
D.a

答えはD
var変数を使うと変数の巻き上げが発生します。
宣言部分から最も近い関数スコープ、もしくはグローバルスコープから対象の変数を探します。
var変数を使ってはいけないと言われる理由の1つかもしれないですね。
ちなみにlet変数に置き換えるとエラーになります。

### javascriptAPI

自分が最もやってよかったと思う箇所はここです。
今後絶対使える知識が多いのでオススメです。例えば以下の内容が対象です。
・documentオブジェクト
・Elementイベント
・History
・イベントハンドラ・イベントクエリ

documentオブジェクトのプロパティとElementのイベント処理の量はとんでもないくらい多いです。
全部は覚えなくてもいいとは思いますが
documentはquerySelector()の使い方、Elementは入力項目のイベント(select、input、change、blurなど)を学べます。
どのイベントで何ができるかを知っていると開発の選択肢が増えると思います。

他にも以下の内容をはじめとして、終わりが見えないくらいイベント処理の用意がされています。
・MouseEvent
・TouchEvent
・キーボードイベント



### ストレージ
sessionStorage、localStorageが対象となる内容です。
ある現場で「データが更新されない！」って報告されていたことがありました。
調べてみたらlocalStorageに値をセットしていました。
localStorageは1度セットするとデータを消さない限り永久に保持し続けます。
ブラウザを閉じても保持します。

sessionStorageはタブ毎にsession情報を持つので、対象のタブを消すと破棄されます。
別タブに遷移した際にデータを保持するときとかに優れています。

なので認証情報とかをsessionで持つ場合などwebStorageを知ってるだけで、誤った設計などは少なくなるのではと思います。

## 現場で使えるのか
思ってる以上に使えました。
資格勉強だと、「いつ使うんや・・・」みたいな問題が多かったりするので、低めに見積もってたのですがかなり使えました。

今のプロジェクトで使えた箇所として以下です。

・javascript文法
=>使用言語はtypescriptだが、エンコード処理、各インスタンスプロパティなど幅広く使えた。

・javascriptAPI
=>入力イベントからの拡張、history操作による画面遷移などで使用できます。

・グラフィックス・アニメーション
=>SVGを使用している為、SVGを理解する良い機会になった。
またSVGのメリット・デメリットなども知れた為、なぜ利用されているかなど学ぶ事ができた。

・ストレージ
=>タブ分けをする画面が多く、sessionStorageを管理する為に使用。
また、ごく一部だが永続的な情報を持たせるために、localStorageでデータを保持する画面があったのでなぜ使用しているか理解できた。

・通信
=>webSocketを使用している。
使うための記述方法などで使用。
ws、wssプロトコルの違いなど。

・パフォーマンスとオフライン
=>非同期処理で使用。
webサービスを作るにあたって非同期処理は当たり前になってきてる為、使える場面が多かった。

・セキュリティモデル
=>同一オリジン制約を行っている。
クロスオリジン対策で画像読み込み時、異なるオリジンのデータがある場合などエラー処理を行うよう設定されている。
なぜエラーになるのかが読み取れるように理解できた。

## おまけ
ここからはレベル2資格受験するにあたっての話になるのですが、個人的にはjavascript未経験者にはキツイかなと思います。
理由はコードリーディングが多いからです。
なので慣れたらレベル2を受けてみることをオススメします。

合格はしたんですが、実は結構ギリギリでした。
自分の勉強方法は参考書と公式過去問、模試テスト2回を4週くらいしました。
問題の「～～全て選べ」タイプがかなり多く、「え、こんな仕様あったっけ」とか、ひっかけとかでボコボコにされてるので、何週もするのではなく、参考書の説明欄一字一句まで覚える勢いでやった方がいいのかなって思いました。
RedshiftのUNLOADコマンドを試してみた

# 背景・目的
Redshiftのドキュメントの手順に倣い、RedshiftのデータをS3にUNLOADする。

# 内容
## 概要
### UNLOADの特徴
- クエリの結果をS3にエクスポートする。
- ファイルの形式には、テキスト、CSV、Parquet、JSON等指定が可能
    - デフォルトではパイプ（|）で区切られる。
- Parquetでエクスポートすると、テキスト形式と比較し、最大2倍高速で、ストレージ使用量も最大6倍少なくなる。
### 構文
```
UNLOAD ('select-statement')
TO 's3://object-path/name-prefix'
authorization
[ option [ ... ] ]
  

where option is
{ [ FORMAT [ AS ] ] CSV | PARQUET | JSON
| PARTITION BY ( column_name [, ... ] ) [ INCLUDE ]
| MANIFEST [ VERBOSE ] 
| HEADER           
| DELIMITER [ AS ] 'delimiter-char' 
| FIXEDWIDTH [ AS ] 'fixedwidth-spec'   
| ENCRYPTED [ AUTO ]
| BZIP2  
| GZIP 
| ZSTD
| ADDQUOTES 
| NULL [ AS ] 'null-string'
| ESCAPE
| ALLOWOVERWRITE
| CLEANPATH
| PARALLEL [ { ON | TRUE } | { OFF | FALSE } ]
| MAXFILESIZE [AS] max-size [ MB | GB ]
| ROWGROUPSIZE [AS] size [ MB | GB ] 
| REGION [AS] 'aws-region' }
| IAM_ROLE { default | 'arn:aws:iam::<AWS アカウント-id>:role/<role-name>' }

```
## 事前準備
- なお、事前に[こちら](https://qiita.com/zumastee/items/a71b1f6e3266c76f596a)でRedshiftのデータベースやテーブル、データのロードは完了している。
- UNLOADの際には、IAMポリシーに以下の権限を付与しておく。
    - s3:GetObject
    - s3:PutObject
    - s3:ListBucket

## 実践
https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/r_UNLOAD_command_examples.html

- 上記を参考にUNLOADを試してみる。

### パイプ区切りファイルへの VENUE のアンロード（デフォルト区切り文字）
#### 実行前
- redshift上のデータ件数を確認する。

```
select COUNT(1) from venue

count
===
202
```

```
unload ('select * from venue')
to 's3://{バケット名}/unload/venue/' 
iam_role 'arn:aws:iam::{アカウントID}:role/{ロール名}';
```

#### 実行後
- s3コマンドでファイルが出来ているか確認する。12ファイルに分割されて出力されている。
```
% aws s3 ls {バケット名}/unload/venue/
2022-03-16 22:50:09        456 0000_part_00
2022-03-16 22:50:09        725 0001_part_00
2022-03-16 22:50:09        571 0002_part_00
2022-03-16 22:50:09        828 0003_part_00
2022-03-16 22:50:09        756 0004_part_00
2022-03-16 22:50:09        761 0005_part_00
2022-03-16 22:50:09        689 0006_part_00
2022-03-16 22:50:09        608 0007_part_00
2022-03-16 22:50:09        533 0008_part_00
2022-03-16 22:50:09        678 0009_part_00
2022-03-16 22:50:09        516 0010_part_00
2022-03-16 22:50:09        635 0011_part_00
% 
```

- 件数を確認してみる。
- 合計すると202件でテーブルの出力結果と一致する。
```
% for i in `seq 0 11`;do PREFIX=`printf %04d $i`; aws s3 cp s3://{バケット名}/unload/venue/$PREFIX\_part_00 - | wc -l ;done
      12
      19
      16
      22
      19
      21
      18
      15
      14
      17
      13
      16
% 
```

- データフォーマットも確認してみる。
- 確かに、デフォルトのパイプ区切りで出力されている。
```
% aws s3 cp s3://{バケット名}/unload/venue/0000_part_00 - | head -5
5|Gillette Stadium|Foxborough|MA|68756
33|Ford Center|Oklahoma City|OK|0
42|FedExForum|Memphis|TN|0
46|Nassau Veterans Memorial Coliseum|Uniondale|NY|0
66|HP Pavilion at San Jose|San Jose|CA|0
% 
```

# 考察
- UNLOADコマンドを実行することで、簡単にロードができる。
- 基本的な書き方は理解できた。他にもオプションがあるので、今後確認していく。

# 参考
https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/r_UNLOAD.html
Jetpack Composeで両端にmarginを効かせたborderを作りたい

Heightが1dpのSpacerにpadding追加しただけだと、意図したborder（罫線）が作れなかったのでメモ。

# やりたいこと
以下のような両端にmarginを効かせたborderを作りたい。
![スクリーンショット 2022-03-16 22.51.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323027/efd10790-24cc-294f-9148-cb2b2cb17c25.png)

backgroundを塗りつぶして、高さを1dpにして、borderを作成することはよくあると思います。

例えば、Qiitaの見出し下線みたいなborderを作りたいとします。
そこで両端にpaddingを効かせても、backgroundを塗りつぶしてしまっているので意図した表現ができません。

```kotlin
@Composable
fun border() {
    Spacer(
        modifier = Modifier
            .background(Color.DarkGray)
            .fillMaxWidth()
            .padding(horizontal = 30.dp)
            .height(1.dp)
    )
}
```
![スクリーンショット 2022-03-16 22.59.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323027/b85532fd-a69c-009c-0a23-407239fd9a79.png)
上図のPreviewで見ての通り、paddingは効いていますが、backgroundを塗りつぶしてしまっているので、普通の罫線になっています。

xmlで実装するときはmarginがあったのでそれでよかったんですが、Jetpack Composeにはmarginがないので、工夫する必要があります。

# やり方
paddingを効かせたBoxで包みましょう。
```kotlin
@Composable
fun border() {
    Box(
        modifier = Modifier
            .wrapContentHeight()
            .fillMaxWidth()
            .padding(horizontal = 30.dp)
    ) {
        Spacer(
            modifier = Modifier
                .fillMaxWidth()
                .background(Color.DarkGray)
                .height(1.dp)
        )
    }
}
```

![スクリーンショット 2022-03-16 22.51.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323027/efd10790-24cc-294f-9148-cb2b2cb17c25.png)

ん〜やっぱりmargin欲しくなってしまう私はまだJetpack Compose初心者なのかもしれません(泣)
Elasticsearchの環境をDockerで作ってみる

# 概要
Docker環境で気軽にElasticsearchの環境を構築し、データを入れるまでのメモです。

Elasticで紹介されているDockerにインストール方法は[こちら](https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html)を参照ください。またDocker Hubは[こちら](https://hub.docker.com/_/elasticsearch)を参照ください。

# Dockerにインストール
Dockerファイルとdocker-compose.yamlはこんな感じです。

``` text:Dockerfile
FROM docker.elastic.co/elasticsearch/elasticsearch:8.1.0
RUN elasticsearch-plugin install analysis-kuromoji
```
必要に応じて、kuromoji等のプラグインのインストールが可能です。

``` text:docker-compose.yaml
version: '3'
services:
  es:
    build: ./es
    container_name: elasticsearch-v8010
    environment:
      - node.name=elasticsearch
      - discovery.type=single-node
      - cluster.name=es-docker-cluster
      - "ES_JAVA_OPTS=-Xms4096m -Xmx4096m"
      - xpack.security.enabled=false
      - http.port=9200
    ports:
      - 9200:9200
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - es-data:/usr/share/elasticsearch/data
  kibana:
    image: docker.elastic.co/kibana/kibana:8.1.0
    ports:
      - 5601:5601
    environment:
      ELASTICSEARCH_HOSTS: http://elasticsearch-v8010:9200
volumes:
  es-data: null
```

Dockerファイルをビルドし、起動します。
```bash
docker-compose build
docker-compose up -d
```

Elasticsearchの起動確認をします。
* Elasticsearch
http://localhost:9200
* Kibana
http://localhost:5601/app/home#/

# データを入れてみる
Elasticsearchの環境が構築できたのでkibanaのDev Toolsからデータを入れてみます。
まずはmappingを定義します。
```
PUT sample_index
{
  "mappings": {
    "properties": {
      "item_name":{
        "type": "text",
        "analyzer": "standard"
      }
    }
  }
}
```

次にデータを登録します。
```
POST /sample_index/_bulk
{"index": {"_id": 1}}
{"item_name" : "シャツ"}
{"index": {"_id": 2}}
{"item_name" : "パンツ"}
{"index": {"_id": 3}}
{"item_name" : "帽子"}
```

登録されていることを確認します。
```
GET /sample_index/_search
{
  "size":10
}
```
LinuxでMySqlのコネクション数をモニタリングしたい



## 概要
タイトル通り、このSQLの結果とか監視したい時に使える方法です。
```sql
SELECT * FROM information_schema.PROCESSLIST;
```
https://qiita.com/snaka/items/b6e7500c96e04c131d9e

## 準備
指定したコマンドを定期的に実行できるwatchコマンドをインストール。
詳しくは下の記事参照。

https://qiita.com/shtnkgm/items/2aa204f2b52f24d02ff3


### watchコマンドが使えるか確認
このコマンドで1秒ごとに現在時刻を更新していればwatchは機能している。
（終わる時はCntl+cを押すことでモニタリングを切ることができる。）
```
 watch -n 1 date 
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66209/91552485-b21e-a70d-f520-9fc01eda74a9.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66209/80d5063d-6e2a-4564-3a27-e628c5e3672c.png)





## モニタリング実施
MySqlのrootユーザーで概要と同じSQLをwatchコマンドで実行。
```
watch -n 1 "mysql -u root -p${MYSQL_YOUR_ROOT_PASSWORD} --table  -Be 'SELECT * FROM information_schema.PROCESSLIST;'"
```
注意) `${MYSQL_YOUR_ROOT_PASSWORD}`は環境変数からMySqlのrootユーザーのパスワードを取得していたりするので各自の環境に合わせてダブルクォーテーション内のmysqlコマンドのユーザーやパスワードの書き換えが必要。

### 実行結果表示例
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f36363230392f34366330353336342d633261612d383939392d616538652d6130363964626533623366622e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66209/2d539231-1081-b792-9d7c-2170becc423f.png)


この状態でSQLを実行するプログラムを動かすと状態が刻一刻と変動していくのがわかる。


###
AWSアカウント作成/ 初めてのAWS忘備録①

## アカウント作成する前に
AWSには、異なる2つのユーザタイプがある。

・AWSアカウント作成時に生成される``ルートユーザー（アカウント所有者）``

・ルートユーザまたはアカウントのIAM管理者によって作成される``IAMユーザー``

## ルートユーザーとは
AWSアカウントを作成した時に用意したEメールアドレスとパスワードを使用してサインインできるユーザーのこと。アカウント所有者なので、AWS上のサービスほぼ全てを制限なく実行が可能。

## IAMとは
IAMユーザーを理解する前に、IAMって？から理解した方がわかりやすい。

IAMとは「Identity and Access Management」の略で、その名のとおり``IDとアクセス権を管理する機能``。
IAMを使用すれば、誰がどのサービスにアクセスできるのかを、許可または拒否することができる。
全ての人が全てのサービスやデータに対してアクセス権を持つというのは安全ではないので、必要な人に、必要最低限の権限のみを付与することが推奨されている。

管理機能が必要な理由として、アカウント１つでも使うことはできるが、システムの種類（メインシステム・サブシステムなど）や環境の用途（開発用・本番用など）に応じてアカウントを分けた方が、セキュリティや運用面におけるメリットが高いから。

## IAMユーザー／IAMポリシー／IAMロール
#### IAMユーザー
IAMユーザーとは人に与えられるIDのこと。ユーザー名とパスワードが付与され、AWSアカウントにログインする際に必要となる。

１つのAWSアカウントの中に複数のユーザーを作ることができ、従業員１人ずつ個別のIAMユーザーを作成することが推奨されている。

新しく作ったIAMユーザーには、デフォルトでは何のアクセス許可も与えられていない。後述のIAMポリシーを割り当てることによって、必要なアクセス許可を付与することができる。

#### IAMポリシー
IAMポリシーとは、「何に対して」「どのような操作を」「できるか（できないか）」の権限を記述したドキュメントで、許可証のようなもの。これをIAMユーザーや後述のIAMロールに割り当てることで、「誰が」その権限を持つのかといったことを決定する。

**ポリシーの例**
AdministratorAccess：管理者権限で全部許可
ReadOnlyAccess：見るだけ許可
AmazonS3ReadOnlyAccess：S3を見るだけ許可

#### IAMロール
IAMロールとは、役割のようなもの。前述のポリシー（権限）を束ねることができ、それを代表する概念的な名前を付けることができる。

例えば、コーヒーショップの従業員が1日の中で様々な役割を担当する場合、IAMロールを使って必要なアクセス許可を一時的に付与することができる。

```
ロール：レジ係　→　ポリシー：レジシステムへのアクセス権など
ロール：在庫管理係　→　ポリシー：在庫システムへのアクセス権・更新権限など
ロール：オンライン注文係　→　ポリシー：オンラインシステムへのアクセス権・更新権限など
```
IAMロールでは、どの時点でも１つの役割しか担当できないようにし、切り替えて使うことができる。切り替えると以前のロールの権限は取り消され、次の新しいロールの権限が与えられる。

``レジ係　→　在庫管理係　→　オンライン注文係``
このように、IAMロールは権限を一時的に付与する必要がある状況に適しています

## ルートアカウントの作成
ルートアカウントやIAMがどんなものか理解したら、[公式の手順](https://aws.amazon.com/jp/register-flow/)に沿って、ルートアカウントを作成。

## IAMユーザーの作成
IAMでユーザー作成するために、所属するグループの定義から始める。

#### IAMグループ作成
コンソール画面の上部にある検索フォームからIAMを検索して、IAMの画面へ移動。
左メニュー内の「個のユーザーグループ」から「グループ作成」に進む。

```
グループ名： 任意のものでOK
アクセス許可ポリシーをアタッチ：　 （例）検索窓で「AdministratorAccess」を検索しチェック
```

#### IAMユーザー作成
上記と同じく、IAMのコンソール画面の左メニュー内の「ユーザー」から「ユーザーを追加」に進む。
下記内容でユーザを作成。

```
ユーザ名： 任意のものでOK
AWS 認証情報タイプを選択： パスワード - AWSマネジメントコンソールへのアクセス
コンソールのパスワード： カスタムパスワード、任意のパスワードを入力
パスワードリセットが必要： チェックなし
アクセス権限： 先ほど作成したIAMグループにチェック
タグの追加： なし
```

作成が終わったら作成したIAMユーザーでコンソール画面にログインできるか確認。

この段階で「ルートアカウント」「作成したIAMユーザーアカウント」の2つがある。
基本的にAWS上での作業はrootアカウントは利用せずに、新しく作成したIAMユーザーアカウントを利用して進めていく。

## budgets設定
``budgets``とはAWS上で使用している各種リソースの使用状況を監視して、**設定した金額を超えた場合はアラートを通知してくれる**サービス。
budgetsにてサポートされている予約のアラートは、下記の5つのサービスに対して。

●Amazon EC2
●Amazon RDS
●Amazon Redshift
●Amazon ElastiCache
●Amazon Elasticsearch

---
AWSは無料枠で利用できるクラウドサービスもあるが、基本的には有料のサービスになっている。
そのため意図しない課金が出ないように予算のアラート設定が必須になる。

コンソール画面の検索窓から「budget」と検索して「AWS Budgets」のサービスを開き、「予算を作成」に進む。
下記の内容で作成。

```
#予算タイプを選択
予算タイプ：コスト予算

#詳細
予算名：任意の名前
予算額を設定(ここは任意のものでOK)
間隔：月別
予算有効日：定期予算
開始月：現在の年月
予算設定方法：固定
予算額：10.00
予算のスコープ：すべてデフォルト設定でOK

#アラートの設定
閾値：任意の%
トリガー：実績
Eメールの受信者：受信するメールアドレス

#アクションのアタッチ
そのまま
```

## 参考記事
[IT未経験の初心者がIAMを理解しようとしてみた](https://dev.classmethod.jp/articles/aws-iam-beginner/)
[AWS Budgetsとは？コスト予算の設定](https://www.skyarch.net/column/aws-budgets/#:~:text=AWS%20Budgets%E3%81%AE%E6%A6%82%E8%A6%81,%E3%81%97%E3%81%A6%E3%81%8F%E3%82%8C%E3%82%8B%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%A7%E3%81%99%E3%80%82)
【備忘録】Django Excelダウンロード

# 経緯
データアップロード処理記載後、txt形式は正常にダウンロードができたが、
Excelのみダウンロード後、開いた際に「ExcelでファイルXXX.xlsxを開くことができません。ファイル形式またはファイル拡張子が正しくありません。ファイルが破損しておらず、ファイル拡張子とファイル形式が一致していることを確認してください。」エラーが出る。

対応した内容を個人的備忘録として残しておく。

# 参考にさせて頂いたサイト
1. Djangoダウンロードについて
非常に参考になりました。ありがとうございます！
https://blog.narito.ninja/detail/93/

2. Markdown記法（投稿はじめてなので・・・）
https://qiita.com/tbpgr/items/989c6badefff69377da7

# 各ファイルの記載
## models.py
~~~python
from django.db import models

class UploadFile(models.Model):
    file = models.FileField('ファイル')

    def __str__(self):
        return self.file.url
~~~
## forms.py
~~~python
class DocumentForm(forms.ModelForm):
    class Meta:
        model = Document
        fields = ('document', )
~~~
## views.py
~~~python
import mimetypes
import shutil
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.views import generic
from .models import UploadFile

def download(request, pk):
    upload_file = get_object_or_404(Document, pk=pk)
    file = upload_file.file  # ファイル本体
    name = file.name  # ファイル名

    # ファイル名からmimetypeを推測。拡張子がないファイル等は、application/octet-stream
    response = HttpResponse(content_type=mimetypes.guess_type(name)[0] or 'application/octet-stream')

    # Content-Dispositionでダウンロードの強制
    response['Content-Disposition'] = f'attachment; filename={name}'

    # HttpResponseに、ファイルの内容を書き込む
    shutil.copyfileobj(file, response)

    return response
~~~
## html
~~~html
<a href="{% url 'app:download' uploadfile.pk %}">{{ uploadfile }}
~~~
## urls.py
~~~python
urlpatterns = [
    path('download/<int:pk>/', views.download, name='download'),
]
~~~

# 結果
無事ダウンロードできるようになりました。
Swift「DIって何？なんでテスタブルなの？」

## はじめに
この記事はメンター企画で使用した記事なので、
一部説明が省かれている箇所があります。ご了承ください。

## この記事でわかること
- DIが何をしているのか
    - 抽象化
    - 具象の注入
- なぜテスタブルになるのか
    - UserDefaultsを例にしてみる
    - mockoloを例に見てみる(省略されています)

## DIが何をしているのか
DIがやっていることは 「パラメータを抽象化し、外部から具象を注入する」 ことです。
この意味がわかればDIの正体がわかります。
また、１つのユースケースを通してなぜDIがテスタブルと関係があるのかを学びます。

DIのやり方は以下の通りです。

1.抽象化のためのProtocol(インターフェース)を定義

```Swift
protocol HogeType {
   func hoge()
}
```

2.initializerのパラメータにHogeType型のパラメータを定義

```Swift
class ExampleClass {
    let dependency: HogeType
    init(dependency: HogeType) { // 抽象化したパラメータを定義。実態に依存しなくなる。
        self.dependency = dependency
        self.dependency.hoge() // "hoge" or "mock"
    }
}
```

3.注入するクラスをHogeTypeに準拠させる

```Swift
class Dependency: HogeType {
    func hoge() {
        print("hoge")
    }
}
class DependencyMock: HogeType {
    func hoge() {
        print("mock")
    }
}
```

4.場合に応じて注入するクラスを分ける

```Swift
let example = ExampleClas(dependency: Dependency()) // 具象を注入し始めて実行時に具象化される
example.hoge() // "hoge"

let exampleMock = ExampleClass(dependency: DependencyMock())
exampleMock.hoge() // "mock"
```

HogeTypeに準拠したクラスは`Dependency`と`DependencyMock`の２つ
つまり、抽象化とは定義に対して実態が1:1で結びついていない状態
インスタンス生成時に具象を代入するということは、
HogeTypeに準拠したクラスを注入するということなので
ここで初めて定義に対して実態が1:1になる
(= 1：多の抽象に対し具象を代入し、1:1の状態にする)

これはつまり、定義に対して複数の実態を代入することができるということで、
クラスAをよりテスト向きに実装したMockクラスAも代入できるということ
テストのためにDIが使われるのは、
ディスクキャッシュやAPI、シングルトンなど、テスト環境では不都合な状態があるからであり、
それらを擬似的な別の何かの処理に置き換えたいからである。

ディスクキャッシュ・シングルトンがテスト環境で不都合であるのは、
影響範囲が広いためにあるテスト結果が他のテスト結果に影響を及ぼしてしまうためです。

APIがテスト環境で不都合であるのは、
サーバーの状態に依存するために期待値が変化し得ること、
実行頻度の高いテストにおいて時間のかかる通信処理は負債になること
などが挙げられます。

次のセクションでは、DIができることはテスタブルなのかどうかというテーマと一緒に
ディスクキャッシュをメモリキャッシュに置き換える例や、
モックの自動生成ライブラリを使った置き換えの例を紹介する。


## DIができることはテスタブルなのか？
A. 大体その認識で良いと思っています。
パラメータを抽象化することによって実態に依存しなくなることは
モッククラスに差し替え可能な状態なのでテスタブルと言えます。
ただ、あくまでパラメータの抽象化によってできることの１つがモックへの差し替えであって、
テストのためだけにDIが存在するわけではありません。

この辺りの認識を深めるには、DIを活用した実装例をユースケースごとに知っていくのが良いかと思います。

### ユースケース1： ディスクキャッシュからメモリキャッシュに置き換える
[ テスト環境でディスクキャッシュを使いたくないので、UserDefaultsをDIする ](https://qiita.com/Sossiii/items/a789dcafafeec3b09ce6)
### ユースケース2： Mockoloで生成したクラスを代入してみる
CTAProjectを元に説明


## 終わりに
DIによる抽象化と具象の注入について理解は深まりましたでしょうか！
pd.SeriesでもGroupby集計はできる

# TL;DR;

1. グループ化用のリスト`group_list`を用意する。
2. `pd.Series.groupby(group_list)`で集計できる。


# 例

1年分の売り上げデータ(乱数)を生成して、月毎に合計を計算する。

```python:売り上げの生成
>>> daily_sales = pd.Series(
    np.random.randint(0, 100, 365),
    index=pd.date_range("2021-01-01", periods=365)
)

>>> daily_sales
"""
2021-01-01     3
2021-01-02    71
2021-01-03    40
2021-01-04    80
2021-01-05     6
              ..
2021-12-27    78
2021-12-28    90
2021-12-29    86
2021-12-30    30
2021-12-31    46
Freq: D, Length: 365, dtype: int64
"""
```

```python:Groupby用のリストを作成。月毎にまとめる。
>>> daily_sales_ym = ["{:%Y%m}".format(ymd) for ymd in daily_sales.index]

>>> daily_sales_ym
"""
['202101',
 '202101',
 '202101',
 '202101',
 '202101',
    :
 '202112',
 '202112',
 '202112',
 '202112']
"""
```

```python:Groupbyで集計する
>>> daily_sales.groupby(by=daily_sales_ym).sum()
"""
202101    1631
202102    1320
202103    1710
202104    1405
202105    1634
202106    1788
202107    1484
202108    1539
202109    1573
202110    1349
202111    1653
202112    1277
dtype: int64
"""
```

よかった。いちいち`reset_index()`呼び出して日付の列入っている`DataFrame`作らないといけないと思った。`Series`でもできるんだ。

# 参考

https://pandas.pydata.org/docs/reference/api/pandas.Series.groupby.html?highlight=groupby#pandas.Series.groupby
Portainerバージョンアップ手順

# はじめに
Dockerデスクトップのダッシュボードのように、GUIでDocker環境管理を行うことができるPortainerのバージョンをアップデートしたかったのですが、意外と参考になる記事がQiitaになかったので、備忘録として残しておきます。


# 環境
```
docker -v
```
Docker version 20.10.12

```
docker compose version
```
Docker Compose version v2.1.1

Ubuntu 20.40(WSL2)


# Portainerアップデート

###### portainerコンテナの停止
```
docker stop portainer
```

###### portainerコンテナの削除
```
docker rm portainer
```

###### portainerコンテナ起動
```
docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:2.11.1
```

portainer-ce:2.11.1
↑「2.11.1」の箇所はその時の最新バージョンを指定してください。

volumeは削除しないので、以前のログイン情報で管理画面へログインできます。


# おまけ
最新バージョンの確認はPortainer公式ドキュメント or Githubで確認できます。
各ページ「Deployment」下記に記載されているPortainer起動コマンドは、アップデート時に打つコマンドと同じなのでそれをそのまま打ってもらっても大丈夫です。

###### 公式ドキュメント
https://docs.portainer.io/v/ce-2.11/start/install/server/docker/wsl

###### Github
https://github.com/portainer/portainer-docs/blob/ce-2.11/start/install/server/docker/wsl.md
そのsupervisord.serviceファイルちゃんと動きますか？

## supervisord.serviceファイルとは

supervisorをsystemctlコマンド動くように登録するための設定ファイルです。
以下のディレクトリに**supervisord.service**ファイルを用意します。

```bash
/etc/systemd/system/
```

## 先人の知恵

これまで多くの方が、このファイルの作成方法を指南してくださっています。

https://blog.e2info.co.jp/2021/04/11/amazon-linux-2_supervisor/

https://nyan.blog/2021/05/21/laravel7-xsupervisor%E3%82%92%E5%B0%8E%E5%85%A5%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B%EF%BC%81/

https://blog.shinki.net/posts/amazon-ilnux-2-supervisor

設定ファイルの中身は大体以下のような感じです。

```shell:supervisord.service
[Unit]
Documentation=http://supervisord.org
After=network.target

[Service]
Type=forking
ExecStart=/usr/local/bin/supervisord -c /etc/supervisord/supervisord.conf
ExecReload=/usr/local/bin/supervisorctl reload
ExecStop=/usr/local/bin/supervisorctl shutdown
User=root

[Install]
WantedBy=multi-user.target
```

しかし、私の環境では上記ファイル内容では正しくsystemctlコマンドが動きませんでした。

## 問題点

以下のsystemctlコマンドがうまく動きませんした。

```bash
# 再起動
systemctl restart supervisord

# 停止
systemctl stop supervisord
```

出現したエラーは以下の通りです。

```bash
supervisord[12]: Traceback (most recent call last):
supervisord[12]: File "/usr/local/bin/supervisord", line 5, in <module>
supervisord[12]: from supervisor.supervisord import main
supervisord[12]: ModuleNotFoundError: No module named 'supervisor'
```

```bash
error: <class 'ConnectionRefusedError'>, [Errno 111] Connection refused: file: /usr/lib64/python3.7/socket.py line: 716
```

## 解決策

色んなサイトを巡りましたが、中々解決には至りませんでした。
しかし、以下のStackOverFlowに答えがありました。

https://stackoverflow.com/questions/17005404/supervisorctl-not-respecting-my-configuration

要約すると、、、
supervisorctlコマンドにも、`-c`オプションをつけてconfファイルのパス(supervisord.conf)を指定してやるべきとのことです。
supervisorctlコマンドは、`-c`オプションがない場合、デフォルトで下記のパスに設定ファイルを探しに行くそうです。

```bash
$CWD/supervisord.conf
$CWD/etc/supervisord.conf
/etc/supervisord.conf
```

なので、上記パス以外にconfファイルを作成している方は、supervisorctlコマンドにも`-c`オプションをつけてあげてください。

私の場合は`/etc/supervisord/`ディレクトリにconfファイルを作成していたので、`-c`オプションが必要でした。
以下のような設定ファイルに変更したところエラーなく動きました。

```bash
[Unit]
Documentation=http://supervisord.org
After=network.target

[Service]
Type=forking
ExecStart=/usr/local/bin/supervisord -c /etc/supervisord/supervisord.conf
# -cオプション 追記
ExecReload=/usr/local/bin/supervisorctl -c /etc/supervisord/supervisord.conf reload
# -c オプション追記
ExecStop=/usr/local/bin/supervisorctl -c /etc/supervisord/supervisord.conf shutdown
User=root

[Install]
WantedBy=multi-user.target
```

## 最後に

supervisorctlコマンドには、-cオプションは要らないものだと勝手に思い込んでいました。。
もっと柔軟な考え方ができる頭が欲しいです。。

同じようなエラーで困っている方の助けになれば、幸いです。
EC2からgithubにssh接続

# 概要
日常の仕事でec2からgithubのリポジトリをcloneしたり、pullしたりする事がありますが、
毎回ユーザー名とパスワードで接続することができますが。
現在、githubの仕様でユーザー名とパスワードで接続場合はアクセストークンで2回認証しないといけないです。
毎回githubにアクセストークン作成のは結構ややこしいですね。
もしsshでgithubに接続すれば、ユーザー名とパスワードの入力は要らなくなります。楽になります。

# 手順

## ec2にec2にアクセスして、ユーザーを切り替え
```
$ sudo su --login ec2-user
```
## 以下のコマンドでssh鍵を作成

```
ssh-keygen -o
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ec2-user/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/ec2-user/.ssh/id_rsa.
Your public key has been saved in /home/ec2-user/.ssh/id_rsa.pub.
The key fingerprint is:

```

enterキーを押して、ssh全ての設定はディフォルトにします。


## 公開鍵とプライベートキーを確認

```
cd ~/.ssh
ls
uthorized_keys  id_rsa  id_rsa.pub
```
id_rsa.pubは公開鍵です。
id_rsaはプライベートキーです。

## 公開鍵をgithubに保存
```
cat id_rsa.pub
```
id_rsa.pubの内容をコピーして以下写真のkeyにペーストして保存します。

![截屏2022-03-16 22.01.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2531066/51835c50-373d-8231-45e3-33ef7093fac0.png)


## ec2にgithubにssh接続確認

```
ssh -T git@github.com
The authenticity of host 'github.com (xxx.xxx.xxx.xxx)' can't be established.
ECDSA key fingerprint is SHA256:p2QAMXNIC1TJYWeIOttrVc98/R1BUFWu3/LiyKgUfQM.
ECDSA key fingerprint is MD5:7b:99:81:1e:4c:91:a5:0d:5a:2e:2e:80:13:3f:24:ca.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'github.com,xxx.xxx.xxx.xxx' (ECDSA) to the list of known hosts.
Hi xxxxxx! You've successfully authenticated, but GitHub does not provide shell access.
```
You've successfully authenticatedメッセージが出れば、成功！
Oppkey　DevRel 記事アーカイブ

https://dzone.com/articles/live-video-mobile-apps-with-flutter

https://dzone.com/articles/flutter-20-state-management-introduction-with-prov

https://dzone.com/articles/5-advantages-of-dart-over-javascript-python-and-ba

https://dzone.com/articles/open-networking-for-network-switches-how-the-open

https://dzone.com/articles/messageformat-is-working-hard-to-make-themselves-o

Node.js --> 

https://dzone.com/articles/interview-with-bethany-griggs

https://dzone.com/articles/the-future-of-apis-and-api-monetization


Node.js --> 

https://dzone.com/articles/what-can-be-done-to-strengthen-the-nodejs-package

https://dzone.com/articles/apis-and-breaking-change-how-implementing-apis-for

https://www.codeproject.com/Articles/1230250/Tips-for-Developers-to-Improve-Technical-Presentat

https://devs.theta360.guide/ricoh-theta-usb-api/

https://devs.theta360.guide/how-to-reset-ricoh-theta-compass/

https://devs.theta360.guide/ricoh-theta-lens-replacement/

https://devs.theta360.guide/ricoh-theta-battery-replacement/

https://devs.theta360.guide/how-to-convert-360-images-to-video/

Node.js --> 

https://openjsf.org/blog/2021/10/25/openjs-world-2021-keynote-recap-node-js-the-new-and-the-experimental/

https://openjsf.org/blog/2021/09/08/why-satisfying-user-needs-is-not-a-zero-sum-game-an-interview-with-nick-oleary-node-red/


https://openjsf.org/blog/2020/04/14/you-told-us-openjs-node-certification-helps-you-stand-out/

https://www.r-consortium.org/blog/2022/01/26/r-ladies-galapagos-chapter-on-collaborations-challenges-and-opportunities-during-the-pandemic


https://www.r-consortium.org/blog/2022/01/12/salt-lake-city-r-user-group-looks-to-meld-in-person-and-online-activities


https://www.r-consortium.org/blog/2021/12/17/calgary-r-user-group-on-the-importance-of-math-education


https://www.r-consortium.org/blog/2021/12/13/oslo-user-groups-diverse-and-inclusive-environment-has-fostered-a-resilient-r-community
PRML式(6.35)

# フィッシャーカーネルと白色化
式(6.35)に関して、"フィッシャースコアの共分散行列であり、フィッシャーカーネルは、スコアの白色化に対応している"とある。どういう意味か考える。

式(6.32)のスコア$\boldsymbol{g}$の共分散行列の逆行列を$G^T G$の形で表現できるとすると、白色化されたスコアは$G\boldsymbol{g}$と表現できる。(https://wonderfuru.com/%E3%83%87%E3%83%BC%E3%82%BF%E3%81%AE%E7%99%BD%E8%89%B2%E5%8C%96-2-2/)

(6.33)の$(G\boldsymbol{g}_{x})^T G\boldsymbol{g}_x'$と変形できる。$G\boldsymbol{g}$は白色化されている。
herokuにあげた後にエラー発生

## エラー画面
[![Image from Gyazo](https://i.gyazo.com/2cf8bd6b44cb884d27f2982b66d5a8b9.png)](https://gyazo.com/2cf8bd6b44cb884d27f2982b66d5a8b9)

- ログを見るように言われているのターミナルで下記を実行
```
heroku logs --tail --app <<アプリケーション名>>
```

- ログで下記のエラーを発見
```
ActiveRecord::StatementInvalid: Mysql2::Error: Table 'resolutions' already exists
```
- resolutionsテーブルは既に存在しているというエラー
- herokuにアップ後デーブルを一度作成し直したのが原因と思われる
- `heroku run rails db:migrate:status`で確認してみます。
[![Image from Gyazo](https://i.gyazo.com/e0eaeab60ab9b8b01449e0fda6b044ae.png)](https://gyazo.com/e0eaeab60ab9b8b01449e0fda6b044ae)
- NOFILEが残っているので下記コマンドを実行
- 一度データベースを壊して再度構築するコマンドらしい
```
heroku run DISABLE_DATABASE_ENVIRONMENT_CHECK=1 rails db:drop db:create db:migrate
```
- 実行後
[![Image from Gyazo](https://i.gyazo.com/36458c736cdd5218729e4f9b047a0ecf.png)](https://gyazo.com/36458c736cdd5218729e4f9b047a0ecf)
- 無事再構築され、herokuでも正常に作動しました。

## 結論
設計の時にちゃんとテーブル設計をしていた方が良い
Kotlin KoansでKotlin入門　第１１回：Sealed classes

# はじめに
公式の問題集[「Kotlin Koans」](https://play.kotlinlang.org/koans/overview)を解きながらKotlinを学習します。

過去記事はこちら
- Introduction
  - [第０回：Kotlin Koansについて](https://qiita.com/kosuke1/items/41d192af63485bfc8cb8)
  - [第１回：Simple Functions](https://qiita.com/kosuke1/items/5862a3ece96082a62e67)
  - [第２回：Named arguments](https://qiita.com/kosuke1/items/2af11262852ee41b5da7)
  - [第３回：Default arguments](https://qiita.com/kosuke1/items/16cb8ac780df58dc8054)
  - [第４回：Triple-quoted strings](https://qiita.com/kosuke1/items/52cfeed2c49b0252d40e)
  - [第５回：String templates](https://qiita.com/kosuke1/items/0221bbbc5bc70847be6f)
  - [第６回：Nullable types](https://qiita.com/kosuke1/items/aa96e422c5313b6961bc)
  - [第７回：Nothing type](https://qiita.com/kosuke1/items/1ca0e48820d58c9dfe16)
  - [第８回：Lambdas](https://qiita.com/kosuke1/items/8de74f9491e003127f53)
- Classes
  - [第９回：Data classes](https://qiita.com/kosuke1/items/1be2de1b4406b8d914bf) 
  - [第１０回：Smart casts](https://qiita.com/kosuke1/items/50bdecaa0740eb0e1a17)

# 問題
[Sealed classes](https://play.kotlinlang.org/koans/Classes/Sealed%20classes/Task.kt)

前のタスクの解決策を再利用しますが、インターフェイスを[sealed interface](https://kotlinlang.org/docs/sealed-classes.html?_ga=2.33229054.1581259709.1647433434-406738180.1646311119)に置き換えてください。そうすると、```when``` の ```else``` 分岐が不要になります。

修正前のコード
```Kotlin
fun eval(expr: Expr): Int =
        when (expr) {
            is Num -> TODO()
            is Sum -> TODO()
        }

interface Expr
class Num(val value: Int) : TODO()
class Sum(val left: Expr, val right: Expr) : TODO()
```


# 問題のポイント
[sealed classes](https://kotlinlang.org/docs/sealed-classes.html#sealed-classes-and-when-expression)を使用する主な利点は、when式で使用するときに発揮されます。その文がすべてのケースをカバーしていることを確認できれば、文にelse節を追加する必要はありません。ただし、これはwhenをステートメントとしてではなく、式として（結果を使って）使用した場合のみ有効です。

```Kotlin
fun log(e: Error) = when(e) {
    is FileReadError -> { println("Error while reading file ${e.file}") }
    is DatabaseError -> { println("Error while reading from database ${e.source}") }
    RuntimeError ->  { println("Runtime error") }
    // the `else` clause is not required because all the cases are covered
}
```

# 解答例
```Kotlin
fun eval(expr: Expr): Int =
        when (expr) {
            is Num -> expr.value
            is Sum -> eval(expr.left) + eval(expr.right)
        }

sealed interface Expr
class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr
```
Kotlinでpythonのデコレータを再現したい

## 背景
Kotlinでコード書いてる時Pythonで言うところのデコレータを使いたかったが、検索しても見つけられませんでした。
クラス委譲というものが出てきましたが、コレジャナイ感。
C系とjava系だからそんなものかと思いつつ、とりあえず書いてみたという話です。

## 補足 デコレータって？
関数やクラスを文字通り「装飾」する機能のこと。これにより既存の関数やクラスの中身を直接触らず、その外側から機能を追加したり書き換えたりすることができる。
詳しくは[この記事](https://qiita.com/beginnerNeko/items/b39baac8c254d5f587d8)を見てください。

## Pythonのデコレータの例
さっき貼った記事のコードと同じです。
### コード
```decorater.py
#デコレータを定義
def greet(func):
    def inner(*args,**kwargs):
        print("こんにちは。")
        result = func(*args,**kwargs)
        print("よろしくお願いします。")
        return result
    return inner
#使い方
@greet
def myName(name):
    print(f"私は{name}です。")
    return "挨拶 終"
    
print(myName("ねこでべろん"))
```
デコレータによって装飾された引数をとる新たな関数が返され、それを引数付きで実行することで結果を得ています。
### 結果
```
こんにちは。
私はねこでべろんです。
よろしくお願いします。
挨拶 終
```

## kotlinで再現
とりあえず素直に書き変えようとすると、、、
```kotlin
fun <R> greet(func:(funcの引数の型)->R):(funcの引数の型)->R{
}
```
無理です。
`funcの引数の型`は引数の個数も種類もこの時点では決まってないので書けません。
種類が決まっていないのは対応できますが、数が決まっていないのがきついです。可変長引数も使って試行錯誤してみましたが私には無理でした。
諦めて少しロジックを変えます。
### コード
```kotlin
//デコレータを定義
fun <T> greet(func:()->T):()->T{
    fun wrapper():T{
        println("こんにちは。")
        val result = func()
        println("よろしくお願いします。")
        return result
    }
    return ::wrapper
}
//デコレータに渡すための処理
fun myName(name:String):String{
    //実際の処理
    fun _myName():String{
        println("私は${name}です。")
        return "挨拶 終"
    }
    return greet(::_myName)()
}

fun main() {
   println(myName("ねこでべろん"))
}
```
引数が邪魔なので、デコレータに与える関数を引数に特化させます。
デコレータからは引数に特化しかつ装飾された関数が返ってきます。
これを実行することで結果が得られるというわけです。
実行部分だけ見れば似ていますが、内部的には全然違います。
### 結果
```
こんにちは。
私はねこでべろんです。
よろしくお願いします。
挨拶 終
```
## 一般化
とりあえず載せます。
```Kotlin
//デコレータ
fun <T> decorater(func:()->T):()->T{
    fun wrapper():T{
        ToDo()
        val result = func()
        ToDo()
        return result

    }
    return ::wrapper
}
//関数
//Typeは同じ型
fun function(arguments):Type{
    fun _function():Type{
        ToDo(arguments)
        return result
    }
    return decorater(::_function)()
}
```
## 最後に
今回はPythonのデコレータを再現してみました。
完全再現という訳には行かなかったのが少し悔しいです。
Pythonが動的型付け、Kotlinが静的型付けということでやはり型で苦労しましたね。
完成したものも各方面から怒られそうですが、その方々には加筆してもらうつもりです。
記事の内容に誤りがあればコメントや加筆等よろしくお願いします。
React: Window Resize イベントで React Component のサイズ取得方法

# Window Resize イベントで React Component のサイズ取得方法

- なかなかベストプラクティスに落ち着くことができなかったので、メモとして残しておきます。
- 特に、`_.debounce()` でラップしないでうまく実装する方法がなかったのか。
- もっと良い実装があれば、アップデートしていきます。

## TL,DR;

  - `resize` イベントハンドラー利用します。
  - `ref` を通じて、`getBoundingClientRect()` でコンポーネントのサイズを取得します。
  - `state` にコンポーネントのサイズを格納していきます。
  - 無闇やたらとハンドラを呼び出したくないので、Lodash の debounce を使ってます。
    - ウィンドウ最大化ボタンのためにも実は debounce は必須。

### Hook 形式でも書けるけど、とりあえず Class Component 形式で紹介します。

```jsx
import React from 'react';
import _ from 'lodash';

class MyComponent extends React.Component {
  state = {
    size: {
      width: 0,
      height: 0,
    },
  };

  ref = React.createRef();

  handleWindowResize = _.debounce(() => {
    const size = this.ref.current.getBoundingClientRect();
    this.setState({ size });
  });

  componentDidMount() {
    this.handleWindowResize();
    window.addEventListener('resize', this.handleWindowResize);
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.handleWindowResize);
  }

  render() {
    const { size } = this.state;
    return (
      <div ref={this.ref}>
        Component size is {size.width} x {size.height}.
      </div>
    );
  }
}
```

### Hook API を使った場合の Function Component の実装

```jsx
import React from 'react';
import _ from 'lodash';

const MyComponent = () => {
  const ref = React.useRef(null);

  const [size, setSize] = React.useState({
    width: 0,
    height: 0,
  });

  const handleWindowResize = _.debounce(() => {
    const { width, height } = ref.current.getBoundingClientRect();
    setSize({ width, height });
  }, 100);

  React.useLayoutEffect(() => {
    handleWindowResize();                                                                                         
    window.addEventListener('resize', handleWindowResize);
    return () => window.removeEventListener('resize', handleWindowResize);
  });

  return (
    <div ref={ref}>
      Component size is {size.width} x {size.height}.
    </div>
  );
};
```
ajaxでsubmit時と同じ情報を送る方法

# はじめに
* ajaxを使用してファイルをpostで送るときに詰まったので備忘録として残しておきます。

# .serialize()が使えない
* .serialize() や.serializeArray()を使用すると性質上勝手にform内のinput type=file属性の要素が除外されてしまうようです。
なので上記2つの方法を使用した正攻法でのファイル転送は行えません。

※それでも無理やり送ろうとする場合は別でfile属性の要素を取得してbase64などの方式でエンコードを行い、上記のデータの後ろにJSONなどでくっつけてcontroller側でデコードを行えば、やってできないことはないかもしれないです（未確認）。

# ajaxで情報をpost送信する 
```index.html
  <form id="account_form" enctype="multipart/form-data" method="post">
    <div class="email-area">
      <span>メールアドレス：</span>
      <input type="text" id="email" name="email"/>
    </div>
    <div class="nick-name-area">
      <span>ニックネーム：</span>
      <input type="text" id="nick_name" name="nick_name"/>
    </div>
    <div class="file-area">
      <span>添付ファイル:</span>
      <input type="file" id="file_data" name="file_data" />
    </div>
    <div class="submit-area">
      <input type="button" id="submit_btn" value="送信" onclick="post_with_ajax()"/>
    </div>
  </form>
```
例えばこんな入力フォームがあったとします。
```index.js
function post_with_ajax() {
  let formData = $('#account_form');
  $.ajax({
    type:  "post",
    url:   "/accountForm",
    data:  formData.serialize(),
  }).done(function(resData) {
    //成功時の処理
  }).fail(function(resData) {
    //エラー時の処理
  });
}
```
.serialize()が使用できれば上記の記述で/accountFormにデータが送れます。
ところが.serialize()は**無言でファイルデータを送信対象から外してしまう**ため、今回のフォームに使用すると添付ファイルデータは**送信対象外**となってしまいます。
なので、下記のように書き換えます。

```index.js
$("#submit_btn").click(function () {
  //formセレクタを取得
  let form = $('#account_form').get(0);
  //FormData オブジェクトを作成
  let formData = new FormData( form );

  //ajax実行
  $.ajax({
    url : "/accountForm",
    dataType: "html",
    type : "post",
    data : formData,  // dataに FormDataを指定
    processData: false,  //ajaxがdataを整形しない指定
    contentType: false  //contentTypeもfalseに指定
  }).done(function(resData) {
    //成功時の処理
  }).fail(function(resData) {
    //エラー時の処理
  });
});

```
こう書き換えることで、ajaxを通さずsubmitでフォーム送信した時と同じデータが、/account_formに送られるようになります。


# 参考文献
https://stackoverflow.com/questions/4545081/how-to-do-file-upload-using-jquery-serialization

https://arimodoki.mydns.jp/promenade/hy_jquery_postajax.html
Flutterのバージョンを上げたら、git@github.com: Permission denied (publickey). と怒られた

## Flutterのバージョンあげたらエラーが出た
半年ぶりくらいにFlutterのバージョンを上げたら、以下のエラーが出ました。
・Flutterのバージョンを2.10.3に更新
・Visual Studio Codeにてビルドを実施

>Error output from CocoaPods:
↳
         Cloning into '謎のURL'...
         git@github.com: Permission denied (publickey).
         fatal: Could not read from remote repository.
         Please make sure you have the correct access rights
         and the repository exists.


## 試したこと
### その1： GitHubのssh接続
以下の記事に沿ってやってみましたが、既に実施済みでした。
(そもそも、このFlutterプロジェクトではGitHubを利用していない・・・)

https://qiita.com/shizuma/items/2b2f873a0034839e47ce

### その2: キャッシュを消して、flutter packages getする
以下の記事に沿ってやってみましたが、こちらもダメでした。
[Flutter git@github.com: Permission denied (publickey)で落ちる](https://note.com/t0_inoue/n/n1ad330177449)
記事で紹介されているのと同様「sshキーにパスフレーズを設定している」ので、これが原因くさいというのがわかってきました。

### その3: ターミナルにて「pod install」と「pod repo update」をする
Flutterプロジェクトフォルダの下のiosフォルダに移動して、ターミナルにて上記コマンドを実行することで解決できました。
(ターミナルで実行時もパスフレーズを求められたので、打ち込むことで解決)

どうやら実行中にsshのパスフレーズを入力する必要があり、Visual Studio Codeでのビルドではここで引っかかっていたようです。

誰かの参考になれば！
<備忘録>Herokuデプロイ時にエラー発生 / UndefinedTable

# Herokuにデータベースを作成する。
railsアプリをデプロイしたがエラー発生

```
2022-03-16T11:32:52.061551+00:00 app[web.1]: [53d442bd-fd35-4dfb-9c9f-eb1fc62006c8] ActionView::Template::Error (PG::UndefinedTable: ERROR:  relation "users" does not exist
```

userテーブルが見つからないよと


## Herokuでもデータベースを作成
ローカルでデータベースを作成するのと同じように
Herokuでもデータベースを作成しないといけないみたい

```
$ heroku run db:migrate
```
モデルを作成、変更したら忘れないように

以上
<備忘録>railsで scaffoldを使ってアプリ作成。

# scaffold を使用をしてアプリ作成。
railsを知るためにscaffoldをつかって簡単にアプリを作ってみる。

## scaffoldとは
モデルやコントローラー、ビューを作っていき、さらに必要なルーティングを作成してくれる便利なものです。

### どうやるか
```
$ rails g(generate) scaffold <モデル名(単数)> <属性　例：name:string,email:integer>
```

上記のコマンドで　MVCとルーティングができるんです。

model作成後は
```
$ rails db:migrate
```
で、migrationファイル(データベースの設計書)の作成
を忘れないように

以上

### 参考文献
https://techacademy.jp/magazine/7204

https://qiita.com/jackie0922youhei/items/09a7b081e40506f07358
初心者ブロックチェーンに挑戦する　15


# 座礁3日目

## 本筋と違う、けど、私には必要な努力

　第一章の課題をひととおり終えたけど、作品を提出できないまま３日がたった。私がこだわっているのは、ブロックチェーンとも、イーサリアムとも、関係のない部分だ。

- サイトの見た目にこだわっている。

 というのはちょっと違う。マイニングを待っている間の「あれ、これ、ちゃんと動いてるかな」という何秒かを、画像の遷移で表現したいのだ。

　だけれども、私は今回使っているReactのコードを書いたことがない。java scriptさえ、初歩の初歩しか知らない。コードを提供してくれた人と同じことをするわけではないので、テキストのコードと、もらったコードと、自分のコードを穴が開くほど見比べて、そこから自分のやりたいことを導き出すという、こんな非効率的なやり方もなかったものだ。

- 詰まったら質問せよ

　その鉄則、知ってはいるんだけどね。

　ともかく、こうかなと思ったら書いてみて、エラーを読んで、直して、じゃあここを変えたらどうなるかな、あ、そう来たか、じゃあこっちはどうだ、と際限なくtry&errorを繰り返す。エラーコードは親切な道しるべだということがよくわかる。そっちは行けませんよ、ここは入れませんよ、と押し返されながら、そうか、ここなら通れるのか、という道が見えてくる。

　問題はエラーが出なくなったあとだ。エラーはないけど動かない。画像が出ない。画像が変なところに出る。画像が変な形になる・・・etc.　でも、最初はCSSファイルのありかもわかってなかったんだから、ずいぶん進歩したじゃないか、とわれながら思うよ。
　課題の本筋とは、はずれているけどね。

　ともかく、第一の画像をそれらしい場所に表示することには成功した。でも、画像はあと２枚あるのです。しかもそれを条件によって入れ替えなきゃならない。

-　ガンダーラは遠いよ〜

## 読書百遍、韋編三絶




https://qiita.com/ytnd0928/items/22704b1c47c20e1bd83f
[LINEbot]毎朝プログラミングに関する記事を通知してくれるbotを作った話

# はじめに
![スクリーンショット 2022-03-16 17.49.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2305872/247bbcb4-879b-9b92-3ade-9fed41baefa3.png)
LINE MessageAPIを使ってプログラミングに関する記事を通知してくれるbotを作ってみました！
![スクリーンショット 2022-03-16 17.51.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2305872/4d18696f-2758-d420-fd59-d083214b4568.png)

# どんなbotか
![スクリーンショット 2022-03-16 17.21.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2305872/2dc34596-3837-79ed-d33c-57b1bbca87c5.png)
毎朝7時にQiitaでストックが10以上の記事を5件、プログラミングに関するニュースを10件通知してくれます。

気になった記事はurlから閲覧します。

# なぜ作ったのか
みなさんは普段からニュースを見る習慣はありますか?
私はあまり見る習慣がなく、習慣をつけようとしても、結局は三日坊主の状態でした。
![neochi_computer_woman.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2305872/304c695d-fd3a-fe4c-7f5a-a6bc2b723139.png)

では、どうすれば習慣化できるのかと考えた時に、「LINEは毎日使うものだから通知してくれればニュースをみる習慣ができるんじゃないか」と思いました。

それに加え、私はQiitaをよく利用しているため、「Qiita内で注目の記事を教えてくれれば嬉しいなあ...。」と思いました。

以上の二つから、このbotを作成しました。

# 今後実装すること
## 1.キーワードを指定する機能
現状、キーワードを指定できないので自分が欲しい分野だけのニュース等を通知することはできないですが、replyMessageを使って実装していきます.
## 2.追加時の処理
botの追加時にニュース通知をする

### 最後に
自分の悩みや課題を解決できる様に形にできたことが何よりも嬉しかったです。

今後はユーザーにとって使いやすい機能を模索していきます!

ご覧いただきありがとうございました!

【GitHub】
https://github.com/suba327777/LINE-Engineer-News

### 参考リンク
>Qiita API v2 documentaition - Qiita:Developer
>https://qiita.com/api/v2/docs

>Everything - Documentation - News API
>https://newsapi.org/docs/endpoints/everything

>Messaging APIリファレンス
>https://developers.line.biz/ja/reference/messaging-api/#send-broadcast-message

>axiosでの認証
>https://qiita.com/hirohero/items/8199cda2fada7432887e

>axiosとQiita APIを使ったサンプルアプリ
>https://qiita.com/tkmd35/items/6ab8c4e6e37178f81472

>Heroku Schedulerの設定方法
>https://qiita.com/pythonista/items/2eab3e3acad88c5b759e
Ubuntu でサウンドデバイスが認識されなくなったときの解決

pulseaudioを再起動する

```
$ pulseaudio --kill 
$ pulseaudio --start
```

## Refs
- [How to Fix the No Sound Issue in Ubuntu - Make Tech Easier](https://www.maketecheasier.com/fix-no-sound-issue-ubuntu/#:~:text=When%20experiencing%20sound%20issues%20on,see%20if%20it's%20paired%20correctly.)
- [PulseAudio - Wikipedia](https://en.wikipedia.org/wiki/PulseAudio)
TTGO T-Display で MicroPython を使ってみた 続編

以前はディスプレイのライブラリーを導入済みのファームを使っていたが，

https://qiita.com/numeru55/items/935ce1136992b7f39a72

今回は ESP32 用の generic ファームを使いつつ，ST7789のドライバーを導入するという手法を使ってみた。

# まずは generic ファーム導入

https://micropython.org/download/esp32/

ここから

https://micropython.org/resources/firmware/esp32-20220117-v1.18.bin

をダウンロードしました。安直に，Thonnyを使ってファームをアップデートしました。こんな感じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533274/52f9d797-7e06-765a-d01c-8e792f03e89c.png)

そのままthonnyでREPLすればきちんと書き込めたか確認できますね。

# ST7789ドライバーとフォント導入

以下を clone します。

https://github.com/russhughes/st7789py_mpy

```lib```フォルダーにある```st7789py.py```をTTGOにコピーします。

フォントは```fonts```に入ってディレクトリーごとTTGOにコピーします。**時間がかかりますので気長に待ちます。**

```
cd fonts/
ampy --port=/dev/cu.SLAB_USBtoUART put romfonts/
ampy --port=/dev/cu.SLAB_USBtoUART put truetype/
```

# 動作確認

```examples/ttgo_tdisplay/truetype/noto_fonts.py``` を実行してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533274/b115910b-70f0-22dc-c112-e6d0caec0b3d.png)

ビットマップのサンプルも用意してみました。

```hello_world.py
from machine import Pin, SoftSPI
import st7789py as st7789

from romfonts import vga2_16x32 as font

def main():
    spi = SoftSPI(
        baudrate=20000000,
        polarity=1,
        phase=0,
        sck=Pin(18),
        mosi=Pin(19),
        miso=Pin(13))

    tft = st7789.ST7789(
        spi,
        135,
        240,
        reset=Pin(23, Pin.OUT),
        cs=Pin(5, Pin.OUT),
        dc=Pin(16, Pin.OUT),
        backlight=Pin(4, Pin.OUT),
        rotation=1)
    
    tft.text(
        font,
        "Hello world!",
        0,0,
        st7789.color565(255,255,255),
        st7789.color565(0,0,0)
    )
main()
```

# 注意事項

遅いとのことですが... 上記サンプルは確かに「ヌルッ」と描画されます。まあこんなもんかな。
IT業界1年目のコーダが使ってみて、作業効率爆上がったと感じたおすすめツール

IT業界に未経験から入って早1年程。。。
未だにマークアップくらいしかまともに出来ないぺーぺーぱーぱーが、おすすめするツールやサイトをまとめました。
使ってみると喉にささった魚の小骨が取れるくらい、スッキリしながら作業進められますよ！(??)

## 参考にしているサイト
+ エラーの英文読めない！ 公式ドキュメントオール英語読めない時はコピペ翻訳です笑 google翻訳より好き
[deepl](https://www.deepl.com/ja/translator)
+ flexboxのプロパティについて思い出せない時  
[flexbox チートシート](https://www.webcreatorbox.com/tech/css-flexbox-cheat-sheet)
+ htmlの入れ子のルールが分からない時  
[HTML5 入れ子チートシート](https://yoshikawaweb.com/element/)
+ css Grid Layoutの書き方が分からない時  
[CSSグリッドジェネレーター](https://cssgrid-generator.netlify.app/)  
+ 欲しい情報が個人HPや企業のブログ等でヒットしたら、理解を深めるためにドキュメントで確認する！
[MDN Web Docs](https://developer.mozilla.org/ja/docs/Web)  
+ おまけ　最近やっとJSONに触れる機会が多くなってきたので、、、JSONデータを読みやすくしてくれます！
[jsonformatter](https://jsonformatter.curiousconcept.com/) 

## ツール
+ ピクセルパーフェクトを目指すために  
XDやAiデータを元におおよその値でマークアップした後、ブラウザ拡張ツール「PerfectPixel」を使うようにしたところマークアップする速度も上がりました！  
+ 素早くスタイルを記述するために  
Sassを使ってCSSを書くのがメチャクチャ効率的に感じます。純粋なCSSしか知らなかった自分的にはSCSS記法のがすんなり馴染めました。※具体的な導入方法や使い方はググってみてください;;
+ 頑張らなくてもいい事は頑張らない  
エディタの入力補完機能(Emmet)を使う、プラグインを使う。参考までに私が使っているエディタ「VS Code」のプラグインを紹介します、他にも色々あるのでぜひ調べてみてください。  
 `英語読めない`：[Japanese Language Pack for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=MS-CEINTL.vscode-language-pack-ja)  
 `文字やコードが見づらい`:[Bracket Pair Colorizer2](https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer) や [Indent Rainbow](https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow)  
 `どのファイルが何のファイルかわかりづらい`:[Material Icon Theme](https://marketplace.visualstudio.com/items?itemName=PKief.material-icon-theme)  


### あとがき
筆者の拙い投稿をご覧頂きありがとうございます。この情報でアウトプット力ついていくのか不安を感じてますので、少しでも気になるところや改善できそうなところがあれば優しくご指摘頂けると助かります。理解が深まるたびにこちらの投稿を更新する予定です。
Mailcatcherインストール時のエラー

# 環境

Mac OS Monterey 12.3
Ruby on Rails 7.0.2.2

# Mailcatcherがインストールできない

Mailcatcherはsmtpサーバを立てて、Mailerで送信するメールをブラウザ上で確認することができるgemです。

Mailcatcherは`bundle`コマンドでインストールすると正常に動作しないとのことで、
```
$ gem install mailcatcher
```

を実行しました。

しかし、エラー。。。

```
Building native extensions. This could take a while...
ERROR:  Error installing mailcatcher:
        ERROR: Failed to build gem native extension.

    current directory: /Users/xxxx/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/thin-1.5.1/ext/thin_parser
/Users/xxxx/.rbenv/versions/3.1.0/bin/ruby -I /Users/xxxx/.rbenv/versions/3.1.0/lib/ruby/site_ruby/3.1.0 -r ./siteconf20220316-25856-2wb19k.rb extconf.rb
checking for main() in -lc... yes
creating Makefile

current directory: /Users/xxxx/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/thin-1.5.1/ext/thin_parser
make DESTDIR\= clean

current directory: /Users/xxxx/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/thin-1.5.1/ext/thin_parser
make DESTDIR\=
compiling parser.c
parser.rl:112:17: warning: comparison of integers of different signs: 'long' and 'unsigned long' [-Wsign-compare]
  assert(pe - p == len - off && "pointers aren't same distance");
         ~~~~~~ ^  ~~~~~~~~~
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/assert.h:99:25: note: expanded from macro 'assert'
    (__builtin_expect(!(e), 0) ? __assert_rtn(__func__, __ASSERT_FILE_NAME, __LINE__, #e) : (void)0)
                        ^
parser.rl:142:7: error: implicit declaration of function 'thin_http_parser_has_error' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
  if (thin_http_parser_has_error(parser) ) {
      ^
parser.rl:142:7: note: did you mean 'http_parser_has_error'?
./parser.h:44:5: note: 'http_parser_has_error' declared here
int http_parser_has_error(http_parser *parser);
    ^
parser.rl:144:14: error: implicit declaration of function 'thin_http_parser_is_finished' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
  } else if (thin_http_parser_is_finished(parser) ) {
             ^
1 warning and 2 errors generated.
make: *** [parser.o] Error 1

make failed, exit code 2

Gem files will remain installed in /Users/xxxx/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/thin-1.5.1 for inspection.
Results logged to /Users/xxxx/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/extensions/x86_64-darwin-21/3.1.0/thin-1.5.1/gem_make.out
```
thin_parserのエラー？ よくわかりません

# Thinのインストールで解決

GitHubにIssueが上がっていました。

[https://github.com/sj26/mailcatcher/issues/430](https://github.com/sj26/mailcatcher/issues/430)

アプリケーションサーバのThinをインストールしたら解決！

```
$ gem install thin -v '1.5.1' -- --with-cflags="-Wno-error=implicit-function-declaration"
$ gem install mailcatcher
```

Thinはアプリケーションサーバーで、RailsではデフォルトでPumaが使われています。