OmniAICreator/Qiita-1.07M huggingface dataset:
Material UIのData Gridでブラウザーバックに対応する

# 初めに

https://qiita.com/urbsny/items/3667167a800883033407

に関するTipsです。

# 本題
DataGridって便利ですよね。
React × Material UIで言うと、下記のようなライブラリがあります。

- https://material-ui.com/components/data-grid
- https://github.com/mbrn/material-table
- https://github.com/gregnb/mui-datatables

DataGridを使うことで、

- ページネーション
- フィルター
- ソート

などが簡単に実装できてしまいます。ただ、
**ブラウザーバックをするとページやフィルター、ソートがリセットされてしまう。**
というのを問題の一つと感じています。（特にデータ件数が詳細画面への遷移も多いAdmin系の画面だとより一層感じます。）

その解決の解決策として、２つあるかと思います。

## 解決案その1
reduxなどのステート管理の仕組みを利用し、ページやフィルター情報を画面毎に保持しておき
再度画面が表示された際にページやフィルターの初期値として、ステートの情報をセットします。
ただ、この方法だと

- 画面毎にステートを管理する必要があり共通化しずらい。
- 通常の遷移の場合でもステートからセットされてしまう為、ステートのリセットや無視する実装が必要。

という問題があります。

## 解決案その２
URLパラメータにページやフィルター情報を含め、ページ操作などが行われた際にURLをreplaceします。
この方法だと、

- 共通化がし易い。
- ステート管理が不要。
- ページやフィルターを含めた状態のURLをブックマークやシェア出来る。

というメリットがあります。

### 実装方法
下記コードがその実装方法になります。

https://github.com/PaykeDeveloper/payke-hinagata-frontend/blob/43555d35ba5128cdc3e3f74693e15e68e15c8c4c/src/view/base/material-ui/DataGrid.tsx#L95

ポイントは、
DataGridのonPageChangeやonSortModelChangeのイベントを受け取り、
そのデータを[qs](https://www.npmjs.com/package/qs)というライブラリーを使用してURLに変換しています。
同様にqsを使ってURLからデータを復元し、DataGridにセットします。
※ 脆弱性は未検証です。

各画面では、このDataGridを利用するだけで特に意識することなくブラウザーバックによる
ページやソートの復元が実現できます。

URLのイメージはこんな感じになります。

![Apr-03-2021 23-46-41.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621435/864a7a76-6cab-4b64-f8b4-6f34f9bb8b1c.gif)

ブラウザーバックでは一覧の状態が保持され、リンクをクリックした場合は初期状態になっています。
SPAって何？

Reactを勉強しててSPAという言葉よく聞くようになり、なんとなくの理解だった為改めて文字に起こしてアウトプットしていきたいと思います！

一番下に参考にした記事を載せておきます！

#SPAってなに？
SPAとはSingle Page Application（シングルページアプリケーション）のことです。
簡潔にまとめると、必要な部分だけ更新して、必要ないところはそのままの表示にすることです！

今までのwebアプリケーションの仕組みは、何かアクション（クリックなど）をすると、
①サーバーにリクエスト
②サーバー側でHTMLを生成
③②で生成されたHTMLを受け取り、ブラウザで描画する
流れでした。

従来の仕組みだと不要なデータまで更新される為、表示するまでに時間がかかっていました。

###そこでSPAの登場！！
①ユーザーがアクションを起こす
②①のアクションに必要なものだけをサーバーにリクエスト
③帰ってきたデータをJSで処理してHTMLで表示する
流れに変わりました！

SPAの仕組みを利用することでユーザーのサービス利用時間が長くなる=購入確率などが高くなる=会社の売り上げに貢献！！←少し飛躍しすぎました。。。

だから今SPAへの温度感が非常に高まってるとか。。。

#その他メリット
他のメリットデメリットについては他記事でも乗ってるので興味のある方はそちらを参考にしてみてください！
ここではざっくり説明していきます

###①よりリットなweb表現ができる
ReactやVue.jsなどのライブラリやフレームワークが誕生したことによって、簡単に様々な物が実装可能なり、いろんなUIを表現することができるようになりました！

###②ネイティブアプリの代用ができる
ここに関しては自分自身が体験してない為、あまり実感が湧きませんがSPAを導入することで
ネイティブアプリで実装されてたことがSPAでも表現することが可能とのことです！！←いずれここも体験してみたいです！

#最後に
どうやらSPAは何かを実装する上でデファクトスタンダードそう。これからもSPAを意識しながら学習に取り組んでいきたいと思います！！

参考記事
https://rara-world.com/spa-single_page-merit/
https://www.oro.com/ja/technology/001/
Next.jsとContentfulを連携する方法

Next.jsとヘッドレスCMSのContentfulを連携する方法になります。

## パッケージcontentfulをインストール
まずは、contentfulをインストールします。

```
npm install contentful
```

```
yarn add contentful
```

https://yarnpkg.com/package/contentful

## Contentfulのapiキーの設定をする

```contentful.ts
const contentful = require('contentful')

const config = {
  space: process.env.CTF_SPACE_ID,
  accessToken: process.env.CTF_CDA_ACCESS_TOKEN
}

export const createClient = () => {
  return contentful.createClient(config)
}
```

```.env.local
CTF_SPACE_ID=YOUR ID
CTF_CDA_ACCESS_TOKEN=YOUR ACCESS TOKEN
```

contenfulの設定をします。space idやaccess tokenはContenfulのダッシュボードから確認することができます。

### ES6 importでも使用できます。

```contentful.ts
import * as contentful from 'contentful'
const config = {
  space: process.env.CTF_SPACE_ID,
  accessToken: process.env.CTF_CDA_ACCESS_TOKEN
}

export const createClient = () => {
  return contentful.createClient(config)
}
```
https://github.com/contentful/contentful.js/blob/master/ADVANCED.md


## Contentfulからデータを取得する

Contentfulからデータを取得します。

```posts.tsx

import React from 'react'
import { GetStaticProps } from 'next'
import { createClient } from '../library/contentful' // 上記で作成したcontentful.ts

const Posts = ({ posts }) => {
  return (
    <div>
      {posts &&
        posts.items.map((post) => (
          <div>
            <p>{post.fields.title}</p>
            <p>{post.fields.content}</p>
          </div>
        ))}
    </div>
  )
}

export default Posts

export const getStaticProps: GetStaticProps = async () => {
  const response = await getAllPosts()

  // responseが無ければ404にリダイレクトする
  if (!response) {
    return {
      notFound: true
    }
  }
  return {
    props: { posts: response }
  }
}

const getAllPosts = async () => {
  const client = createClient()
  try {
    const response = await client
      .getEntries({
        content_type: 'work',
        order: '-sys.createdAt'
      })
      .catch((error) => {
        return error
      })
    return response
  } catch(error) {
    throw new Error(error.message)
  }
}


```

上記の例では、Content Modeleがworkの物全て（記事一覧）を取得しています。

https://www.contentful.com/developers/docs/references/content-delivery-api/
Reactのコンポーネントのメリットは何か。

Reactを触っていると『コンポーネント』という言葉を頻繁に耳にします。
どのようなことか概念は分かっているのですが、以下に言語化して理解を深めたいと思います。

##コンポーネントとは？
コンポーネントを直訳すると『構成要素』『部品』や『コンピュータ機器やソフトウェアの部品』『ステレオで、チューナー・アンプ・プレーヤー・スピーカーなどの単独の機器』のことを表しますが、Reactでは『UI の一部分となるビュー (View) を切り出したもの』を表しています。

そもそもUIって何のことか曖昧だったのでついでに調べてみました。
UI（ユーザーインターフェイス）はユーザー（利用者）と製品やサービスとのインターフェース（接点）すべてのことを意味するということ。
具体的にはGoogleのトップページは大変シンプルでユーザーに分かりやすいように設計されているので優れているとUI言えます。そもそも今、目に入っているwebページもUIです。

##コンポーネント化するメリットは何か？
コンポーネント化をすることのメリットは何があるのか。
それはViewを切り出したものを使い回せることが一番大きいと思います。
コンポーネントごとにjs/jsxファイルを用意して、それを組み合わせてUIを構築・開発していきます。例えばボタンをコンポーネント化させることで、トップページで使ったボタンをユーザーページでも再利用することができます。つまり一つコンポーネントを作っておけば、そのコンポーネントを呼び出せば簡単に使い回すことができるということです。
（ちなみにHeaderやFooterなどもコンポーネント化させることができます！）

これによりコードの記述量が減ったり、メンテナンス性が向上したりします。
他にもメリットはありますが以上のことからViewを切り出したものを使い回せることが一番大きいと思います。

##最後に
コンポーネントをもっと深く知りたい方はぜひ公式のドキュメントの三目並べを作ってもらうのが一番理解出来るかと思います！





参考記事・サイト

https://react.keicode.com/basics/react-component.php

https://ja.reactjs.org/
【python】File "<stdin>", line 1のエラーの解決法


## 現象

VSCodeでpythonを実行しようとしたところ、以下のようなエラーが出て実行できませんでした。

    >>> /usr/local/bin/python /home/workspace/test/test.py
       File "<stdin>", line 1
        /usr/local/bin/python /home/workspace/test/test.py
        ^
    SyntaxError: invalid syntax

デバッガーでは普通に実行できるし、
ターミナルを開いてコマンドラインから実行しても動く。

## 解決法

VSCodeのコンソールで、pythonが対話モードになったままだった。
なので、exit()で対話モードを抜けて、実行すると問題なく実行できました。

めでたしめでたし
演算子リスト




#算術演算子
記号 |	効果
-----|-----------------
+    |	加算
-    |	減算(マイナス符号）
*    |	乗算
/    |	除算
%    |	余り
**   |	累乗
.    |	文字列結合

#代入演算子
記号 |	効果
-----|-------------------
=    |	代入
+=   |	加算して代入
-=   |	減算して代入
*=   |	乗算して代入
/=   |	除算して代入
%=   |	乗余して代入
**=  |	累乗して代入
.=   |	文字列として結合(追加)

#比較演算子
記号 |	効果
-----|-------------------------
　== |	値が等しければtrue
　!= |	値が等しくなければtrue
　>  |	値が大きければtrue
　<  |	値が小さければtrue
　>= |	値が同じか大きければtrue
　<= |	値が同じが小さければtrue
　eq |	文字列として等しければtrue
　ne |	文字列として等しくなければture
　lt |	文字コードが大きければtrue
　gt |	文字コードが小さければtrue
　le |	文字コードが同じか大きければtrue
　ge |	文字コードが同じか小さければture
　cmp|	大きければ－1、等しければ0、小さければ1
　=~ |	正規表現。指定文字列があればtrue
　!~ |	正規表現。指定文字列がなければtrue
　!  |	否定。真のとき偽、偽のとき真
　<=>|	値が大きければ-1、等しければ0、小さければ1

     

#論理演算子

記号 |	効果
----|---------------------------------
　&& |	条件が両方成立すればtrue (AND)
 ｜｜|	どちらかの条件が成立すればtrue (OR)
&   |	ANDを返す
｜   |	ORを返す
^   |	XORを返す
(&,｜,^)=   |	指定論理を抽出して代入
Firebase StorageでURL経由の直接ダウンロード方法

# やりたかったこと
- NuxtでWEBページを作成していた
- そのWEBページの中でFirebase Storageに格納したファイルをダウンロードしたかった
- WEBページ上で表示とかではなく、ローカルにダウンロードがしたかった

# 結論
- 公式で解説していた「URL 経由でデータをダウンロードする」で実現可能だった
- CORSの設定も併せて設定する必要はあった

# CORS設定前のエラー
- 「header is present on the requested resource.」といった内容のエラーが発生

# 実際のjavascriptコーディング(参考程度)
> downloadFile(file) {
      var xhr = new XMLHttpRequest();
      xhr.responseType = 'blob';
      xhr.open('GET', "https://firebasestorage.googleapis.com/{******}");
      xhr.onload = function(event) {
        var blob = xhr.response;
        // blobオブジェクトを指すURLオブジェクト
        var objURL = window.URL.createObjectURL(blob);
        // リンクを生成し、JavaScriptからクリック
        var objLink = document.createElement('a');
        document.body.appendChild(objLink);
        objLink.href = objURL;
        objLink.download = "{download時の名前}";
        objLink.click();
      };
      xhr.send();
    },

- 通信時の処理は.onloadに記載
- .sendで通信を開始

# 参考
- [ウェブでファイルをダウンロードする](https://firebase.google.com/docs/storage/web/download-files?hl=ja)
- [gsutilをインストールする](https://cloud.google.com/storage/docs/gsutil_install?hl=ja)
LinuC合格用 1週間でLPICの基礎が学べる本 1日目まとめ

![1日目まとめ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1124047/27afdee7-4e0c-2ba1-5eac-ddc4ca67b90d.png)
Swaggerについて調べてみた(Dockerバージョン)

前回Swaggerについて調べて実際に使ってみました。
前回はwebからyamlファイルを生成し作成する方法でしたが、今回はDockerを使った方法を試してみます。

前回と同じくまだDockerについて浅い知識しかないのでご指摘などありましたらご連絡いただけますと幸いです。

前回の記事は以下です。
[Swaggerについて調べてみた](https://qiita.com/mumucochimu/items/8bc6e234467f55a7d591)

今回参考にさせていただいた記事は以下です。ありがとうございます！
[UI開発にSwaggerで作ったmockサーバーを使う](https://fintan.jp/?p=3561)
[Swaggerの概要をまとめてみた。](https://qiita.com/gcyata/items/342073fa7607fd4082bd)

## DockerでSwagger Editorを立ち上げる

DockerHubにあるイメージをpullします。
以下が公式のイメージです。
[swaggerapi/swagger-editor](https://hub.docker.com/r/swaggerapi/swagger-editor/)

![スクリーンショット 2021-04-03 22.00.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1051152/de0817c9-959a-ea46-fb11-249170edcfa4.png)

上記の画像にあるようにコマンドを実行していきます。

```ターミナル
$ docker pull swaggerapi/swagger-editor
$ docker run -d -p 80:8080 swaggerapi/swagger-editor
```

成功すると上記の場合`localhost`で下記のようにSwagger Editorが開きます。

![スクリーンショット 2021-04-03 22.05.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1051152/0393dfec-f09d-6449-8c54-150f0614e7e8.png)

ここで編集をしていくということですね。

## mockサーバーを作成する

こちらもDockerHubにあるイメージをpullします。
以下が公式のイメージです。
[swaggerapi/swagger-codegen-cli](https://hub.docker.com/r/swaggerapi/swagger-codegen-cli)

![スクリーンショット 2021-04-03 22.00.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1051152/86323000-b893-52a2-87d3-56f178aaac73.png)


上記の画像にあるようにコマンドを実行していきます。

```ターミナル
$ docker pull swaggerapi/swagger-codegen-cli
```

## HTMLでUIを表示する

localhostで開いているSwagger Editorで下記の画像のように操作をします。
`Generate Server`から開発環境に合わせたものを選びます。
今回私は`nodejs-server`を選択しました。

![スクリーンショット 2021-04-03 22.44.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1051152/de7c43f9-3282-b281-c257-228ec7be4388.png)


ファイルがダウンロードされたら、ダウンロードしたディレクトリまで移動しましょう。

```ターミナル
$ cd nodejs-server-server
```

そして以下のコマンドを入力します。

```ターミナル
$ npm install
$ node index.js
```

そうすると私の場合は以下のような表示が出ます。

```ターミナル
Your server is listening on port 3000 (http://localhost:3000)
Swagger-ui is available on http://localhost:3000/docs
```

私はyamlに`host: localhost:3000`と指定した為、上記のような表示になるわけです。
そして記載されているようにUIを開くには`http://localhost:3000/docs`を開いてあげればOKです。

![スクリーンショット 2021-04-03 22.43.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1051152/72707cf3-3068-337a-6333-c68a6605bb5c.png)


できました！

DockerやAPIのこと理解できていないの悔しいので勉強します...
PhpStormでMermaidを利用できるようにする

PhpStormでMermaidが利用できるようになっていたことを皆さんはご存知でしたか？
設定をちょっと変更するだけですぐに利用できるのでご共有です:grinning:

> Mermaidとは？
Mermaidは、テキストやコードを使って図を作成することができるツールです。
Markdownファイル中で、図を動的に作成・変更することができます。

[About Mermaid](https://mermaid-js.github.io/mermaid/#/)

### 手順
**1.[Settings/Preferences]の[ Languages \& Frameworks | Markdown]を開く**
**2.Markdown ExtensionsのMermaidにチェックを入れる**
![スクリーンショット 2021-04-03 22.17.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94596/c27796f5-c6a1-5b62-1b51-818e8d95c1ab.png)
**3.[Apply]を選択して、[OK]する**

### 試しにクラス図を書いてみる
Mermaidがちゃんと動いてくれるか、クラス図を書いて試してみましょう。

```markdown:Markdown
```mermaid
classDiagram
class AbstractClass{
    templateMethod()
    PrimitiveOperation1()
    PrimitiveOperation2()
}

class ConcreteMethod{
    PrimitiveOperation1()
    PrimitiveOperation2()
}

AbstractClass <|-- ConcreteMethod
\```（←コピペした際はバックスラッシュを消してください）
```

上記の記載をすると下記のような図が表示されます。
![スクリーンショット 2021-04-03 22.35.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94596/a193b8aa-e104-2d75-2e38-ba0f0232786a.png)

Mermaidはクラス図だけでなく、様々な図を書くことができるので、興味のある方はドキュメントをご覧になってください。
[Diagrams that mermaid can render](https://mermaid-js.github.io/mermaid/#/README?id=diagrams-that-mermaid-can-render)

少しでもお役立てたら幸いです:bow:
MQTTでAWS DynamoDBに保存

デバイスに接続されたセンサーからのデータをAWS DynamoDBに保存するとき、MQTTでデータを受け取ってDynamoDBに記録する部分を紹介します。
<img width="700" alt="MySokuteiESP32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1226137/6f356fb3-fa90-cffc-6f34-4fb02bbe6d05.png">
この方法では、デバイスからはJSONで送りさえすれば、JSONのキーごとにバラしてDynamoDBに記録できます。デバイスに埋め込むプログラム側でキーを自由に決められるため、データ確認には便利です。

```json:JSON
{
    "key1": "value1",
    "key2": "value2",
    ...
}
```

なお、AWSアカウントは開設済みで、AWSコンソールには AdministratorAccess のポリシーがアタッチされたIAMユーザでログインしていることが前提です。

# DynamoDBテーブルの作成

センサデータを記録するための DynamoDB テーブルを作成します。

1. [DynamoDB コンソール](https://console.aws.amazon.com/dynamodb/home) を開き、**Create Table** をクリックする。
1. **Create DynamoDB table** において：

    a. **Table name** を `dht22_ddb_table` と付ける。
    b. **Primary key** は次のように入力する。
      - **Partition key** に `device_id` と入力し、右側のリストから `String`を選ぶ。
      - **Add sort key** にチェックの上で `server_timestamp` と入力し、右側のリストから `Number` を選ぶ。
    
    c. ページの最下部の **Create** をクリックする。

# IoT ルールの作成

パブリッシュされたメッセージをキーごとに分解して、DynamoDBテーブルの各列に記録できるようにします。 

1. [AWS Iot コンソール](https://console.aws.amazon.com/iot/home)で、**Act** > **Rules** を選ぶ。
1. **Create** をクリックする。
1. **Name** を`dht22_ddb_rule` と付ける。
1. **Rule query statement** において、以下のように入力する。

    ```sql
    SELECT '01'       as device_id
         ,timestamp() as server_timestamp
         ,*
    FROM 'esp32/pub'
    ```

JSONのキーを使ってSQLを組み立てています。Partition key の device_id は、ここでは固定値にします。Sort key には、タイムスタンプを取得します。`*`の部分がJSONのキーを表していますが、次のアクションの指定により、バラしてDynamoDBに記録してくれます。

1. **Set one or more actions** において、**Add action** をクリックし、**Split message into multiple columns of a DynamoDB table (DynamoDBv2)** を選ぶ。

1. **Configure action** をクリックする。
1. **Table name** で、先ほど作成した `dht22_ddb_table` を選ぶ。
1. **Choose or create a role to grant AWS IoT access to perform this action** において、**Create role** を選ぶ。
1. **Create a new role** の画面で、**Name** を `dht22_ddb_role` と付けて、**Create role** をクリックする。
1. **Add action** をクリックする。
1. **Create rule** をクリックする。

# MQTT test client でのテスト

試しに esp32/pub にパブリッシュして、DynamoDB に記録できることを確認します。

1. [AWS Iot コンソール](https://console.aws.amazon.com/iot/home)で、**Test** を選ぶ。
1. **Topic name** に `esp32/pub` と入力する。
1. **Message payload** は、デフォルトのまま：

    ```
    {
      "message": "Hello from AWS IoT console"
    }
    ```

    にして、**Publish** をクリックする。

1. [DynamoDB コンソール](https://console.aws.amazon.com/dynamodb/home) を開き、**Tables** を選ぶ。
1. **dht22_ddb_table** を選び、**Items** タブで "message" カラムに "Hello from AWS IoT console" が記録されていることが確認できる。

#参考
- [DynamoDB テーブルにデバイスデータを保存する](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/dynamodb-v2-rule-action.html)
- [AWS IoT 開発者ガイド - DynamoDBv2](https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/dynamodb-v2-rule-action.html)
TypeScript奮闘記 No.04 『Module編』

# Module 

JavaScriptにModuleが導入された

ES6形式のModuleを使用する事ができるが、それ以外の場合は トランスパイルが必要。

- Asynchronous Module Definition (AMD)
    - ブラウザ向けのコードによく使用される
    - `define` を使ってModuleを定義する
- CommonJS
    - Node.jsで使用される形式
    - Moduleの定義には `module.exports`を使用し依存関係を定義するには `require` を使用する
- Universal Module Definition（UMD)
    - Module定義のスタイルを統一的に書けるようにしたい、という試みから生まれた（ってことらしい
    - ブラウザとNode.jsの両方で使用できる
- ES6
    - exportキーワードでモジュールを定義し、importで依存関係を定義する


## Export

Moduleからコードをエクスポートすると、そのコードを他のモジュールで使用できるようになる。

```typescript
export interface Item {
    name: string;
    unitPrice: number;
}
```

またこのような書き方もできる

```typescript
 interface Item {
  name: string;
  unitPrice: number;
}

export { Item }
```

## import 

```typescript
import { Item } from "./item

// use Item Interface..
```

## default

defaultキーワードを使うことでデフォルトでエクスポートできるタスクをいっこに限定する

```typescript
export default interface Item {
    name: string;
    unitPrice: number;
};
```

次はもっと詳細にかいてみる
[Rails]正規表現でバリデーションしてみよう

#はじめに
私の過去の記事で,ユーザ管理機能の実装でdeviseをご紹介しました。その際に特別触れることはありませんでしたが、実はdeviseではemailのアドレス登録で@をつけることが必須です。
当時は、便利だな〜と思いましたがその仕組みが気になり、調べていくと、、、
「正規表現」といものと巡り合ったのでこの記事にてご紹介します。


#正規表現とは
正規表現とは、文字列の一部を抽出あるいは置換をしたり、文字列が制約を満たしているかを調べるための表現方法です。

たとえば、あるアンケートで電話番号と郵便番号を書かせるフォームがあったとします。
その時にただの空欄ボックスであった場合にハイフンをつけたりつけなかったり、いろんな人がでてきて管理がしづらいですよね。なので、正規表現によってハイフンが入っていたら取り除いたりするわけです。
このように文字列に特定の文字が含まれているかを確認することや、特定の文字を取り除くなどの操作を行うための技術が正規表現です。

#正規表現の基礎

まずは正規表現を利用するための3つのメソッドをご紹介します。
・subメソッド
・matchメソッド
・gsubメソッド

###subメソッド

subメソッドは、文字列の指定した部分を別の文字列に置き換えるためのメソッドです。
操作する文字列は//で囲ってやって、第2引数に置換後の文字列を入れます

こんな感じです

```irb
irb(main):001:0> str = "ラーメンを食べる"
=> "ラーメンを食べる"

irb(main):002:0> str.sub(/ラーメン/,"チャーハン")
=> "テャーハンを食べる"
```

###matchメソッド

matchメソッドは、指定した文字列がある文字列に含まれているか否かをチェックするためのメソッドです。
これはみた方が理解が早いので以下に例を示します。

```irb
irb(main):001:0> str = "Hello, World"
=> "Hello, World"

irb(main):002:0> str.match(/Hello/)
=> #<MatchData "Hello">

irb(main):003:0> str.match(/Good/)
=> nil
```

戻り値には、MatchDataという種類のオブジェクトで返されます。

###gsubメソッド
指定の文字列すべてを置換します。
subと似ていますね。ただし、subの場合、最初にマッチした文字列に対してのみで、gsubは全てです。
そう、gとはgrobalのこと、全てなのです！！！！（笑）

```irb
irb(main):001:0> tel = '090-1234-5678'
=> "090-1234-5678"

irb(main):002:0> tel.sub(/-/,'')
=> "0901234-5678"
# 最初のハイフンしか置換されない

irb(main):003:0> tel.gsub(/-/,'')
=> "09012345678"
```

#いよいよバリデーションの準備です！！
ここまでで、なんとなく基本的な部分は理解できましたか？？
ここからはさっそくバリデーションをかける準備です。

今回はパスワードに4文字以上という制限をかけましょう。

先に結論から言うと、こんな感じにします。

```user.rb
validates :password,format:{with: /[a-z\d]{4,}/i }
```
初見殺しすぎますよね。。。わかります。。。。

でも焦らない！一つづつ見ていきましょう。
まず、/[a-z\d]{4,}/iの部分を分解してみましょう。

[a-z]
\d
{n, m}
i

###[a-z]
角括弧[]を使用することで角括弧で囲まれた文字のうちいずれか１つがマッチするかをチェックしています。-(ハイフン)で範囲を設定することができます。
今回はアルファベットのaからzまでのいずれかにマッチという意味になります。
実際にmatchを使って見てみます

```irb
irb(main):001:0> 'debug'.match(/[a-c]/)
=> nil
```

###\d
これは数字を表します。なお、このような文字を特殊文字といいます。

###{n, m}
直前の文字が少なくとも n 回、多くても m 回出現するものにマッチすることを確認します。

###i
iはオプションで、大文字・小文字を区別せずに検索します。


#もう意味はわかりましたか？？

ここまでこればもう意味はなんとなくわかってきたはず！！
もう一度さっきのバリデーションをみてみましょう

```user.rb
validates :password,format:{with: /\A[a-z\d]{4,}\z/i }
```
/[a-z\d]{4,}/i を読むと、
[a-z\d]（英数字を）
{4,}（最低4回）
/i(大文字小文字区別なく)
と言う意味になります！！！

追記（2021年4月4日）：<br>英数字4文字以上のパスワードにするためには、文字列の最初ですと言う意味を持つ\Aと文字列の末尾ですよと言う芋を持つ\zが必要です。詳しくはこちらをどうぞ。<br>https://qiita.com/itsumoonazicode/items/e3c7886909ce68986c9a

この制約でのフォーマットをバリデーションをかけると上記のようになるわけです。

#おわりに

以上、正規表現についてざっくりですがご紹介いたしました、
ほかにもたくさん表現の仕方があるので興味のある方は調べてみてください！！
Socket.io3は、2以前とuseの走るタイミングが違う？

# 問題
放置してたプロジェクトを久しぶりに開き、npmのパッケージを何も考えずにアップデートしたら、今まで通ってたプログラムが通らなくなった。いろいろ探した結果、問題の部分はこんな感じ。

```typescript
io.use(function (socket, next){
    sessionMiddleWare(socket.request, socket.request.res, next)
})

// ...

io.on("connection", (socket) => {
    var userid = socket.request.session.userid //ここがエラーになる

// ...
```

もともと `socket.request`に`session`は存在しないのだが、useでそれを付加し使えるようにしている。ところがこのuseが何らかの原因で走っていなかった。

# 解決策

socket.ioのバージョンを4.0.1から2.4.1に戻した。3系ではダメだった。

# 原因
探してもそのものズバリの事象は見つからなかったのだが、、バージョンアップでuseの走るタイミングが変わったとしか思えない。詳しい人がいたら教えてください。
Visual Stadio 2019で保存した時にコードの整形する方法

題記の通りなのですが、いちいちコードフォーマットを実行するのが面倒だったので、Visual Stadio 2019でも保存した時にコードの整形したいと思って調査いたしました。

下記のページに載ってました。

> ファイルを保存するたびにコード スタイル設定を適用する場合、Code Cleanup on Save という拡張機能をお勧めします。

https://docs.microsoft.com/ja-jp/visualstudio/ide/code-styles-and-code-cleanup?view=vs-2019

## 実際に行ったこと

1. Visual Stadio 2019を開いて、メニューの[拡張機能] > [拡張機能の管理]をクリックします。

2. 拡張機能の管理画面が開くので、検索ボックスで「Code Cleanup on Save」と検索してください。

3. 「Code Cleanup on Save」をダウンロードして、Visual Stadio 2019を再起動してください。

4. もう一度[拡張機能の管理]を開いてこうなっていれば成功ですね！

|![キャプチャ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624898/5d7d4755-ec7b-020f-0c58-1e4b754fe5d5.jpeg)|
|:--|

あとはEditerConfigを好みに合わせて修正していただいて、ヘッダーの分析からコードのクリーンアップの構成も設定してください。

|![キャプチャ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624898/6fe73a03-6711-9b0e-3e4d-2a49b3d76bd6.jpeg)|
|:--|

保存すれば、下記のようにいい感じになります。

保存前

|![キャプチャ2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624898/e39c7225-3ea4-3b8e-411f-92ae86bde0c5.jpeg)|
|:--|

保存後

|![キャプチャ3.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/624898/e4dae554-2237-0e34-edb7-4151ebfd4157.jpeg)|
|:--|

できました。
PySide2をゼロから学んでいく～目次～

# はじめに
PythonでGUI開発をするためのライブラリ「PySide2」の基本的な使い方を、いくつかの段階に分けて説明していきます。

当ページは投稿者が今までに記載したページの総リンクになります。

# 環境
以下の通りになります。

* Windows 10
* Python 3.8以降

# 目次

* [#0 環境構築](https://qiita.com/karakuri-t910/items/f0736a322a6ba217a36c)
* [#1 ウィンドウ](https://qiita.com/karakuri-t910/items/7d2aac29d979f2413162)
* [#2 ボタン](https://qiita.com/karakuri-t910/items/5aae0ba3bed05eeb5109)
* [#3 ラベル](https://qiita.com/karakuri-t910/items/1bdbcbf8b4b92555c123)
* [#4 ラジオボタン](https://qiita.com/karakuri-t910/items/e54e771c576d2a0aa11a)
* [#5 チェックボックス](https://qiita.com/karakuri-t910/items/03debf242efd944eecc2)
* [#6 コンボボックス](https://qiita.com/karakuri-t910/items/bfd18dffbe2674a3b478)

# 参考文献

* 公式リファレンス
    * [Qt for Python Modules](https://doc.qt.io/qtforpython-5/api.html)
        * [Qt Modules (PySide2で使用できる全モジュール一覧)](https://doc.qt.io/qtforpython-5/modules.html)
* 学習サービス
    * [LearnPyQt](https://www.mfitzp.com/courses/pyqt/)
【go】ローカルの自作パッケージをインポートする

## 概要
ローカルのパッケージをインポートする際にはまったのでメモ。

## 結論
先に結論から書くと、
GOPATH配下にインポートしたいパッケージを配置して、`go.mod`の`replace`でプロジェクトディレクトリの`go.mod`とリンクさせる必要がありました。


## やりたいこと
mainパッケージから別パッケージをインポートして使いたい。
例えば、以下のようなディレクトリ構成で、`main.go`から`first_module.go`をインポートして使う。

```bash:ディレクトリ構成
work/
├── main.go
└── modules
    └── first_module.go
```
数値を渡したら合計値を計算して返す、といった内容で作ります。

```bash:main.go
package main

import (
	"fmt"
)

func main() {
	sl := []int{10, 20, 30}
	r := modules.Calculate(sl...)
	fmt.Println(r)
}
```
```bash:first_modules.go
package modules

func Calculate(i ...int) int {
	var num int
	for _, v := range i {
		num += v
	}

	return num
}
```


（goのバージョンは以下です。）

```bash:goのバージョン
go version go1.15.2
```

## 解決までの過程
上記の構成のままでは、以下のエラーとなり`first_module.go`はインポートできません。

```go:main.go
import (
	"fmt"

	"./modules"
)
```
```:エラー
could not import ./modules (no required module provides package "./modules")
```
`go.mod`を作っていなかった...
ということで作成します。

```:bash
go mod init work
```

GOPATH配下にインポートしたいモジュールをコピーして、`require`で指定します。
`module`には、プロジェクトのモジュール名を記載します。

```go:go.mod
require github.com/work/modules

module work

go 1.15
```

`go.mod`を作成したので、一度実行してみます。

```bash:エラー
$ go run main.go 
go: errors parsing go.mod:
/work/go.mod:1: usage: require module/path v1.1.1
```

どうやらモジュールにバージョンを付与しないと行けないようなので、追記します。

```
require github.com/work/modules
```
再度実行してみますが、unknown revisionとか言われます。

```bash:エラー
$ go run main.go 
go: github.com/work/modules@v1.1.1: reading github.com/work/modules/go.mod at revision v1.1.1: unknown revision v1.1.1
```

GOPATH配下にインポートするモジュールを作成するだけではダメで、
以下のように`replace`で、プロジェクトディレクトリにリンクさせないといけないようです。

```go:go.mod
require github.com/work/modules v1.1.1

replace github.com/work/modules => ./modules

module work

go 1.15
```

これでOKと思いきや、以下のエラーに。
インポートするモジュールを置いているディレクトリにも`go.mod`を作成する必要がありました。

```bash:エラー
$ go run main.go 
go: github.com/work/modules@v1.1.1: parsing modules/go.mod: open /work/modules/go.mod: no such file or directory
```
ということで、`go.mod`を作成し再度実行。

```bash
$ go run main.go 
60
```

うまく行きました。

最終的なディレクトリ構成は以下のようになりました。

```bash
work/
├── go.mod
├── main.go
└── modules
    ├── first_module.go
    └── go.mod
```

##【備考】 Go modules(vgo)について
基本的に、プロジェクトディレクトリはGOPATH配下に作成しないといけない、と思っていましたが、
go1.11から`Go modules(vgo)`が標準装備となり、すべてGOPATH配下に配置しないといけないということはなくなりました。
`go.mod`をプロジェクトルートに配置することでvgoモードで動作し、自分の好きなところにプロジェクトを作成できます。


`vgo`:
　モジュール管理ツール。`go.mod`ファイルで依存モジュールやバージョンを管理する。

`go.mod`: 
　node.jsでいうpackage.jsonのようなイメージ。

`go env`で`GO111MODULE=on`にすることで`Go modules(vgo)`が有効になります。
（-w オプションを付けて環境変数を設定）

```bash:GO111MODULE
$ go env -w GO111MODULE=on
$ go env
GO111MODULE="on"
```

※ なお、go 1.13以降は、`GO111MODULE=on`にしなくてもデフォルトで有効な状態になっています。
新大学1年生に向けてPCの選び方

<h1>はじめに</h1>
<p>初めまして。この度大学を卒業しました。</p>
<p>この大学生活で，WindowsとMac，iPad，iPhoneなどさまざまな機器を購入し活用して参りました。また，この新型コロナウイルスの感染拡大を受けて大学の授業がオンラインになったりなど変化を経験してきました。</p>

<p>今回は，大学の授業の形態も変わってきた中で，今後PCの購入を検討する新1年生に向けて参考になるように選び方を紹介していきたいと思います。</p>

<h1>結局，PCで何をするのか</h1>
<p>やはり，決め手となるのは「PCをどのような用途で利用するのか」です。</p>
・動画視聴
・ゲーム
・レポート作成(Word,Excel,PowerPoint等)
・動画編集
・プログラミング
・オンラインミーティング（Zoom等）
などなどあるかと思います。
何をするかによって，CPUどのくらいかや容量どうするかなどが変わってきます。

<p>僕はPCでレポート作成５割，プログラミング２割，Zoom会議2割，その他１割くらいの利用でした。
やはり，レポート課題や卒論などが大半でした。また，オンラインでの授業も多く，Zoomを開きながらWordなどを開いたりしていることもあり，メモリは8GB以上あると快適に使えると思います。</p>

<h1>Windows or Mac?</h1>
<p>WindowsのPCがいいのか，Macがいいのか迷っている方も多いかと思います。</p>

<strong>結論，好みです！</strong>

<p>結論は好みでいいかと思います。基本的に大学で扱うもので，Windowsでしか使えないソフトやMacでしか使えないものみたいなOSに依存したソフトを使うことはありません！！</p>
<p>とはいえ，例外はあります。実体験として，卒論を書く際にデータ処理に用いたソフトがWindowsでしか使えないものが２つほどありました。しかし，その時限りですごく困ったというわけではありませんでした。また，デザインをやる人はMacがおすすめです。グラフィックはMacの方が優れていると思います。以下にMacとWindowsの違いについてまとめます。</p>



|  |Windows|Mac|
|:-|:-|:-|
|メリット|<dt>・アプリケーションが豊富</dt><dt>・ゲームが豊富</dt><dt>・多くの人が利用しているためトラブルに対処してもらいやすい</dt>|<dt>・スタイリッシュでかっこいい</dt><dt>・画質が良い</dt>|
|デメリット|<dt>・ウイルスに弱い</dt><dt>・画質が悪い</dt>|<dt>・オフィスソフトの動作が重い</dt><dt>・外部端子が少ない</dt><dt>高い</dt>|

<h1>予算</h1>
<p>予算が10万以下なのであれば，Windows一択になります。しかし，15万くらいなのであれば，Macもおすすめです。最近では，Macでも10万以下のモデルもあるのでお買い得だと思います。</p>

<strong>ちなみに僕は，初めは予算少なめで，とりあえず1年生の時に使えればいい程度に思っていたので，WindowsPCを10万くらいにして，アルバイトで貯めたお金で，20万超えのMacBookproを購入しました。</strong>

<h1>サイズ</h1>
<p>サイズに関して，大学生はよく持ち運ぶことが多いので</p>

<p><strong>13インチ(型)</strong>ノートパソコンがいいと思います。</p>

<p>僕はほぼ毎日リュックにはPCを持ち歩いていましたので，軽い方が疲れにくくなくいいです。</P>

<h1>おすすめしないタイプ</h1>
<p>これはかなり個人的な意見になりますが，2in1と言われるようなタブレット一体型のPCはおすすめしません。その理由は，タブレットとして利用したりすることにより，PCの寿命やバッテリーのもちが悪い，またよくフリーズするからです。（僕自身使ったことはないのですが，利用している人から聞いた話になります。）</p>

<p>また，これも個人的な意見ですが，Surfaceのような外付けのキーボードのタイプは，キーが打ちにくいのと，僕のようなプログラムを書くためにキーボードの使用頻度の多い人にとっては，キーボードと机の間に隙間があることにより揺れたりするので，やりづらそうなのでおすすめしません。</p>

<h1>まとめ</h1>
<p>結局のところ，どんなスペックがいいの？と思われているかと思います。</p>
<p>以下の表に僕がおすすめのスペックをまとめます。ぜひ，参考にしてください。</p>

| 項目 | スペック |
|:-:|:-:|
| OS  |  Windows/Mac |
| CPU | intel core i5/i7  |
|メインメモリ | SSD 8GB以上 |
| ストレージ | 512GB以上  |
| 画面サイズ | 13インチ |
| 本体重さ | 1.5kg以下  |

<p>実際にはCPUのコア数や動作周波数，ストレージにHDD+SSDのようなものがあったり，CPUには第4世代などといった細かい違いがありますが，まずは，単純に表のスペックであれば，大学生活で使う分には十分快適に使えるかと思います。</p>

<h1>さいごに</h1>
<p>今年，大学を卒業して大学生活は本当にあっという間でした。また，高校生までとは違ってやりたいことが本当にできる貴重な時間でもあります。ぜひ，色々なことを学び，挑戦し，多くの経験をして欲しいと思います！ぜひ，頑張ってください！</p>
【ミライトデザイン社内勉強会#23】「IDDD本から理解するドメイン駆動設計」輪読会~第14章「アプリケーション」~

### 前回の記事
[【ミライトデザイン社内勉強会#22】「IDDD本から理解するドメイン駆動設計」輪読会~第13章「分散システム設計」~ - Qiita](https://qiita.com/tkek321/items/ecaaf790124e0b0213bf)

## [実践DDD本 第14章「アプリケーション」～ドメインモデルを利用するクライアント～ (1/3)：CodeZine（コードジン）](https://codezine.jp/article/detail/11221)

### `ユースケースに最適化したクエリによる取得`はDTOではなく値オブジェクトに設定して返すとあるが、なんのために値オブジェクトにしているのかがよくわからない

[p1](https://codezine.jp/article/detail/11221)

- Valueオブジェクトのコンストラクタに整合性チェックのためのアサーションが書いてある前提なのかも
    - DBから再構築する際にはチェックはいらないことの方が多い（生成するときにチェックしているので、再構築の時はチェックはいらない前提）
- 値オブジェクトとDTOの違いは、DTOはDBに存在しない値は存在しないが、値オブジェクトは振る舞いを持っている
    - 値オブジェクトにあるメソッドを使えば、DBにない値も取得できる
        - 例えば、DBには税抜き金額と税率しかないが、値オブジェクトの場合は、税込の金額を計算して返す。みたいなこともできる。
- 値オブジェクトをUI層で使用することで依存ちゃってないか？
    - p2のコラムで詳細を書いてる。

### `（2）複数の集約へ参照を保持するDPOを返送`で`集約の保持する情報をDTOアセンブラに公開する必要があるかもしれません。`とあるがそれを避ける理由って？

[p1](https://codezine.jp/article/detail/11221)

- 集約内部の情報を外部にできるだけ公開したくないからかも
    - 集約にDTO作るメソッドを作れば、外部に公開しなくて済むよってことを言ってる気がする。
- 集約がDTOに依存している方がまずいのでは？
    - 集約と一対一のオブジェクトをドメイン側で作成すれば、DTO毎に集約側にメソッドが増える。みたいなことはなくなる。

### プレゼンテーションモデルのイメージがよくわからない。Vue.jsのstateみたいな感じ？

[p2](https://codezine.jp/article/detail/11221?p=2)

- どっちかというとhooksに近い気がする
- DTOとの違いは振る舞いを持っていること
- 画面依存のメソッドを持っているモデル
    - メッセージを赤にするとか
    - ログインしている場合は、メッセージを変えるとか
- UI専用のロジックを持ったモデルの様なもの
[Microsoft] Azure AD B2Cがめっさわかりにくいので図にまとめた

# そもそもAzure AD B2Cってなんなのさ？

> https://docs.microsoft.com/ja-jp/azure/active-directory-b2c/overview
> 
> Azure Active Directory B2C は、サービスとしての企業-消費者間 (B2C) ID が提供されます。 顧客は、好みのソーシャル、エンタープライズ、またはローカル アカウント ID を使用して、アプリケーションや API にシングル サインオン アクセスできます。

ふむ。全然わからん。

自分の理解では、OAuthでいうところの、認可サーバ兼クライアントアプリです。

いろいろある認証プロバイダ（FacebookやGoogle等）に対してはクライアントアプリとして振る舞い、あなたが作る真のクライアントアプリに対しては認可サーバとして振る舞います。
（ということなんだと思う）

# Azure AD B2Cを利用するときにやること

Azure AD B2Cがわかりにくいのは、テナントが2つ登場することです。

図にまとめてみました。

![AzureADB2C-Guide.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59475/80ddee8d-0a8e-370d-ea56-b25c6a78f3f6.png)

①〜③は、既存のAzure ADを認可サーバとして使う場合に必要な作業です。FacebookやGoogleを使う場合は必要ありません。

⑧のところで、あなたの作成するアプリケーションのURLを登録します。


# 参考リンク

* [Microsoftが出しているドキュメントの中では、これが一番わかりやすいかも](https://docs.microsoft.com/en-us/azure/active-directory-b2c/add-identity-provider)
* [【2019年12月版】Quarkus、Azure Functionsに載せるは天国。AD B2C で OIDC は地獄。](https://qiita.com/koinori/items/8a2f1a2be0c15c662fe3)


# それにしても……

MicrosoftはいろんなところのCookieを食わせるため、リダイレクト多過ぎなんですよね。
ここでさらにB2Cかませると、さらにリダイレクトが増えまして、UX的にいけてない。
Coberturaでのカバレッジ計測で嵌った経路作成

# はじめに

`Cobertura`を導入しカバレッジを計測しようと思ったのですが、なかなか実行できなかったので、解決するまでに必要な手順をまとめておこうと思います。

# 環境

* macOS 11.0.1
* VSCode 1.54.3
* JDK 11.0.10
* Cobertura 2.1.1

# Homebrew で dos2unix をインストール

`dos2unix` はファイルの改行コード(`CRLF` -> `LF`)に変更するためのコマンドです。

``` 
brew install dos2unix
```

# cobertura-instrument.sh をUNIX (LF) 形式に変換

シェルスクリプトは`DOS`(`CRLF`)形式なので、`UNIX`(`LF`)形式に変換します。

```
dos2unix cobertura-instrument.sh
```

# Cobertura でカバレッジを計測の経路を作成

カバレッジの計測を行う、テストクラスを指定

```
cobertura-instrument.sh Test.class
```

以下が表示されると成功です。

```
Cobertura 2.1.1 - GNU GPL License (NO WARRANTY) - See COPYRIGHT file
[INFO] Cobertura: Saved information on 0 classes.
[INFO] Cobertura: Saved information on 0 classes.
```

# さいごに

エラーが発生した際は、`cobertura-instrument.sh`の`Could not find or load main class`が表示されたため、問題点を理解するのに苦労しました。
まさか、改行コードが悪さをしていたとは思いもしなかったので、次回に同様の問題が起きたときは改善方法の一つとして試してみようと思いました。

# 参考文献

* [Error: Could not find or load main class net.sourceforge.cobertura.instrument.InstrumentMain · Issue #241 · cobertura/cobertura](https://github.com/cobertura/cobertura/issues/241)
Javascriptでマイクから生データを取り出す

# はじめに

マイクで取得したデータを、数値の配列にしたいだけなのに、苦労した話です。

調べるとScriptProcessorNodeを使ったものがいくつか出てきますが、非推奨っぽい。
AudioWorkletで代用してね、という話もあるが、これは扱いにくそう。
MediaRecorderからWav形式に変換できる方法もあるようだが、そこからうまいこと取り出すのも大変。
もっと簡単にできる方法があると思う。

# 結論

1. MediaRecorderでMediaStreamからデータを取得し適当な音声ファイル形式に出力
1. FileReaderにより音声ファイルをArrayBuffer形式に変換
1. AudioContext.decodeAudioDataによりArrayBufferをAudioBuffer形式に変換
1. AudioBufferからgetChannelDataなどにより生データの取得

※取得される値の詳細は[AudioBuffer](https://developer.mozilla.org/ja/docs/Web/API/AudioBuffer)を参照してください。WAV形式で保管される数値とは異なります。
※コードは後述

# 調べたこと

## ScriptProcessorNode

次の方の記事に書いてあるような方法になります。

https://qiita.com/optimisuke/items/f1434d4a46afd667adc6

ただ[mozilla](https://developer.mozilla.org/ja/docs/Web/API/ScriptProcessorNode)によると、本機能は廃止対象とのことです。なので長期使用を考える場合は、これを使わない方法が必要となります。

## AudioWorklet

ScriptProcessorNodeの代替を調べると、AudioWorkletが出てきます。

次の方の記事が詳しいです。

https://qiita.com/ryoyakawai/items/1160586653330ccbf4a4

む、難しいです。また、ファイル数が増えることや、実装行数が増えることもちょっといただけません。
私はただ、音声データの配列が欲しいだけなのです。

## MediaRecorder

やはりこれで何とかしないと、とは思うのですが、うまく検索できませんでした。

## Audio要素

Audio要素で再生するのは簡単ですね。
ふむ、ではここに格納されたデータを取得してうまいことできる方法は、と思ったのですが、見つけられませんでした。

## decodeAudioData

音声ファイルをAudioBufferに変換するものだそうです。
音声ファイルはMediaRecorderで生成できるので、あとはAudioBufferから生データを取り出せれば、できます。

# まとめ

手順は以下の通りです。

まず、MediaDevicesからMediaStreamを取得します。

``` Javascript
let audioStream = null
navigator.mediaDevices.getUserMedia({audio: true}).then(stream => {
    audioStream = stream
})
```

次に、MediaRecorderを作成します。
そしてEventListenerでデータの取得・変換を行うようにします。

```Javascript
chunks = []

const mediaRecorder = new MediaRecorder(audioStream, {
    mimeType: 'audio/webm'
})
mediaRecorder.addEventListener('dataavailable', e => {
    if (e.data.size > 0) {
        chunks.push(e.data);
    }
})
mediaRecorder.addEventListener('stop', e => {
    const blob = new Blob(chunks)
    const reader = new FileReader()
    reader.readAsArrayBuffer(blob)
    reader.onload = () => {
        audioCtx.decodeAudioData(reader.result).then(buf => {
            const b = buf.getChannelData(0)
            console.log(b)
        })
    }
})
```

あとは適切なタイミングでMediaRecorderを開始・停止するだけでになります。

```Javascript
mediaRecorder.start()
// some process
mediaRecorder.stop()
```

# 完成コード

https://github.com/ai-on-browser/ai-on-browser.github.io/blob/master/data/audio.js

# おまけ

そもそもなぜ必要だったかというと、

https://ai-on-browser.github.io/

でマイクからの音声をデータとして扱えるようにするためです。
よかったら見てもらえると嬉しいです。
AWS Amplifyで爆速でSSLの独自ドメイン静的サイトをデプロイする

# はじめに

以前S3+CloudFront+Route53構成でSSLの独自ドメインサイトを書きました。
[SSLの独自ドメイン静的Webサイトを低コストで15分で立ち上げる (Route53 + S3 + CloudFront + AWS Certificate Manager)](https://qiita.com/yakitatata/items/c432522a865f534b769e)
[CloudFront + S3 構成でのリダイレクト設定
](https://qiita.com/yakitatata/items/f0393eeb4a72d3aa1e81)

もっと簡単で楽に運用する方法を探していたらAmplifyで超簡単にできたので書いていこうと思います。


# 注意
自分はAmplifyについては知ったばっかりの超ど素人ですので、
これはアンチパターンかもしれません。
使うかどうかの判断はご自分で判断お願いします。

# 前提
+ AWSアカウント
+ 独自ドメインの取得
+ 独自ドメインのNSをRoute53に向けている
+ 静的サイトはGitで管理している


# 構築
## Amplifyにアプリをデプロイ
サービス一覧からAmplifyに入り、New App -> Host web app 選択

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238561/40fb5a82-7c8d-87d4-c170-52b21004749c.png)|
|:--|

使っているGitを選択（今回はGitHub）

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238561/e9c6288e-c522-fd64-31f9-02130f0811b1.png)|
|:--|


リポジトリとブランチを選択して次へ
※Organizationsのリポジトリが出てこない場合は、
https://github.com/settings/applications
にアクセスし、awsの認証情報を削除し、再度アクセスすると権限付与画面が出てくるので、そこで組織を選択すればできるようになります。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238561/87240d0b-5c87-4d7c-5004-ef8a4dbd53b1.png)|
|:--|

任意のアプリ名を入力して次へ

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238561/fa854a8f-4027-b1a0-95cc-c4611bbd5cce.png)|
|:--|

そのままデプロイ

## カスタムドメインの設定
作成したアプリを選択している状態で左のメニューからドメインの管理を選択
※Route53でホストゾーンを作成していること

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238561/d6a98901-7839-e2d5-e142-3b57945189ff.png)|
|:--|

好きなようにカスタマイズして保存（スクショはデフォルト）

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238561/355d5517-6afe-e4c4-4483-db2489d31a31.png)|
|:--|

このようにSSL証明書の作成が始まります。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238561/214326d6-4995-6937-6ee0-b775111f0b03.png)|
|:--|

同時にRoute53の設定もしてくれます。全部終わるまで5分前後です。

以上です。独自ドメインのURLでアクセスできるか見てみましょう。


# 料金

https://aws.amazon.com/jp/amplify/pricing/

めちゃくちゃデプロイしなければS3+CloudFront構成と変わらないんじゃないかな？
まあ、安い

# 最後に
大阪リージョンはまだ無いようです。

【気に入ったところ】

+ S3+CloudFront構成も簡単だけどこいつはもっと簡単
+ 特に何もしなくてもデフォルトでGit連携の自動デプロイになっているところ
+ リダイレクト設定も簡単
+ ブランチも簡単に管理対象に含めることができる
+ ブランチ毎にBesic認証がつけられるところ
+ モニタリングがついている

【気にいらないところ】

+ デプロイがちょっと長い（手動でS3に上げるよりは早い）

【気になったところ（無知故に）】
Amplifyが多機能すぎて(本来バックエンドで力を発揮するサービスっぽい）
ググると開発者向けの記事がかなりヒットするので、
静的Webサイトだけの為に使うのって、ありなのかな？

【その他】
キャッシュの設定はどこ？
jsx,tsxでEmmetを使用する方法

#はじめに
ReactでEmmetが使えたら便利だな〜って思って調べたら利用出来たのでご紹介します。
VScodeだと素の状態でもEmmetがインストールされているのでおすすめです。

##方法

方法はsetting.jsonを弄るだけ。
``command + ,`` ``(Windows: Ctrl + ,)``で設定を開きます。
検索に**setting.json**と入れて**setting.jsonを編集**をクリック

その後**setting.json**に

```setting.json
{
  "emmet.triggerExpansionOnTab": true,
  "emmet.includeLanguages": {
        "javascript": "javascriptreact",
        "typescript": "typescriptreact",
    },
}
```

を入れればtsx,jsxでEmmetが使用できます。

#さいごに
Emmetを愛していたのでEmmetが使用できない環境は苦痛でしたが解決しました。
Emmetを使い慣れてる人にはおすすめです。
試験の合格判定プログラム

##問題

総合力を重視する paiza 大学の入試では 1 次試験 (英語、数学、理科、国語、地理歴史の 5 科目で各 100 点満点) の成績で2段階選抜を行います。2段階選抜を通過する条件は以下のようになっています。

全科目の合計得点が 350 点以上
理系の受験者の場合は理系 2 科目 (数学、理科) の合計得点が 160 点以上
文系の受験者の場合は文系 2 科目 (国語、地理歴史) の合計得点が 160 点以上
受験者それぞれの各科目の点数が入力されるので、何人2段階選抜を通過できるかを求めてください。

![スクリーンショット 2021-04-03 20.27.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918117/e1fa7a06-b3b4-e5dd-24e7-089e007b4c73.png)

受験者 2 は全科目の合計は 350 点以上ですが文系 2 科目の合計が 160 点未満なので不合格。一方受験者 4 は理系 2 科目の合計は 160 点以上ですが全科目の合計が 350 点未満なので不合格となります。

→ 通過人数: 2 人

getsで入力される値は以下の通りです。

```
5
s 70 78 82 57 74
l 68 81 81 60 78
s 63 76 55 80 75
s 90 100 96 10 10
l 88 78 81 97 93
```

```
n = gets.chomp.to_i

ret = 0
n.times do |i|
  arr = gets.chomp.split(' ')
  sl = arr[0]
  scores = arr[1..-1].map(&:to_i)
  sum = scores.inject(0) { |sum, n| sum = sum + n }
  #puts sum

  if sum < 350
    next
  end

  en = scores[0]
  mt = scores[1]
  sc = scores[2]
  jp = scores[3]
  gh = scores[4]
  
  if sl == "s"
    next if (mt + sc ) < 160
  else
    next if (jp + gh) < 160
  end

  ret = ret + 1
end

puts ret

=> 2
```
ライブラリとフレームワーク

##投稿動機
[なぜReactが好きなのか答えられない人へ]
(https://qiita.com/mqtsuo02/items/5701238e666e20416664 "")を読んでいる途中で、`ライブラリ`と`フレームワーク`の理解ができていないということに気づいたので、自分なりに調べてまとめようと思いました。
また、引用先が英語のサイトしかないですが、この記事は`プログラミング学習`と`英語学習`どちらも含めて行っています。

→`結論`
→`ライブラリ` VS `フレームワーク`

##結論
・`どちらも一般的に使用されるコードを簡単に使用することができる`
・`コントロールするものの違い`。`フレームワーク`は開発者に必要なものを要求する。`ライブラリ`は開発者が必要なものを探す。(`フレームワーク`＞開発側、　`ライブラリ`＜開発側)

##`ライブラリ` VS `フレームワーク`
**ライブラリ**
→もともと設計が済んでいる
→もともと`ライブラリ`がプレインストールされていて、`フレームワーク`と`ライブラリ`を自動的に比べて最適な方を使ってくれる
→アプリケーションの環境を作るのが簡単
→たくさんの必要な`ライブラリ`を使える
→すぐに開発ができる

**フレームワーク**
→専門的なタスクのみに使うことができる
→開発者が必要なものを探す
[自分メモ] Gitリポジトリをzipに圧縮

#概要
GitHubのリポジトリをメール等でファイルで送る必要がある時などに利用できる、zipにまとめる方法をメモします。

#方法

リポジトリを全て圧縮する場合

--formatでファイル型を指定
--outputでファイル名を指定

```
git archive HEAD --format=zip --output=hoge.zip
```

特定のディレクトリを圧縮する場合

--prefixでディレクトリの指定

```
git archive HEAD --prefix=app/ --output=hoge.zip
```
【Unity】InputSystemのInputControlから「押されているか」を簡単に検知したい

※ InputSystemのPreview版を使用している記事です。
正式バージョンでは使用方法が変更されている可能性があります

----

まず、UnityのInputSystemとは

* キーボードの左キーを押したとき
* ゲームパッドの左キーを押したとき
* uGUIで作った左移動ボタンを押したとき

などなど.. 入力側が異なってもコード側で意識せずに処理できる新しい入力システムです

InputSystem自体は素晴らしい記事が沢山あるのでカット

<br>
今回は InputSystem を使用している場合の **「キー（orボタン）が押されているか」** 判定取得の記事になります。

しかも従来のInput.GetKeyライクに扱いたい。(つまりinterfaceを継承したりせずに簡単に扱いたい）
単純に「Updateメソッドで"押され続けているか"」を取りたいときあると思うんですよね

```C#
// Input時代の書き方
void Update()
{
    if (Input.GetKey(KeyCode.LeftArrow))
    {
        // 左キー(orボタン）が押されている
    }
}
```

InputSystemのInputControlを使用している場合、該当するものがどれかわからずに悩みました...
<br>

まず、以下のような移動に関するaInputControlを作成しました。

「キーボードの左を押したとき」と「画面上の左ボタンを押した時」に同じ処理をさせたいので ActionType は Button にしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553138/4c9cea77-ebf6-0f52-46ce-c57afa535d8c.png)

結果として、InputSystem v1.0.x の時は以下の形で取得することができました

```C#
void Update()
{
    // moveはInputControl
    if (move.Left.ReadValue<float>() > 0f)
    {
        // 左キー(orボタン）が押されている
    }
}
```

ActionTypeがボタンの場合floatでReadValueができるようなクラス設計になっていました。
なので、キーやボタンが押されている場合 `ReadValue<float>()` で値が返ってくるので判定ができます。


しかし、 **直感的でもなく気持ち悪さが残る..** (float...
<br>
現在の最新である **InputSystem v1.1.0-preview3** を入れた所、以下のような形で取得できるようになっていました。

(リファレンス)
https://docs.unity3d.com/Packages/com.unity.inputsystem@1.1/manual/Actions.html


```C#
void Update()
{
    // moveはInputControl
    if (move.Left.IsPressed())
    {
        // 左キー(orボタン）が押されている
    }
}
```

**IsPressed！！**
すごくスマート、そして直感的な形でとれるようになりました。  終わり

----

以前も isPressed 変数自体はあり外からはアクセスできないようになっていましたが `IsPressed()` メソッドとして公開されるようになっていました。

https://github.com/Unity-Technologies/InputSystem/blob/df871319560eca94b9d80cec38b55a6d15ac2735/Packages/com.unity.inputsystem/InputSystem/Actions/InputAction.cs#L1051-L1059


リポジトリ覗いてみても v1.1.0 で中身大幅に変わってますね。
これ以外にも沢山機能が追加されていそうです。


<br>
今回の内容はブログにも書いてあります
https://toshizabeth.hatenablog.com/
homebrew -v するとno git repostitory と出てanyenvをインストールできなかった問題

homebrewをインストールして、その後にanyenvをインストールしようとしたときに問題が起こったので共有します。
# そもそもやろうとしていたこと
https://qiita.com/kyosuke5_20/items/eece817eb283fc9d214f

こちらの記事の内容に従ってmac(intel)にNode.jsをインストールしようとしていた。
その際、homebrewインストール後にanyenvをインストールしようとした際に問題が発生した。

# homebrewのインストール
https://brew.sh/index_ja.html

公式ページからダウンロードをした。

# 発生した問題
homebrew-coreの部分がno git  repositoryとなってしまう。

```
Homebrew 3.0.10
Homebrew/homebrew-core (no git repository)
Homebrew/homebrew-cask (git revision xxxxxxx; last commit 2021-04-03)
```

anyenvをインストールしようとすると、できず。

```
$ brew install anyenv
==> Searching for similarly named formulae...
Error: No similarly named formulae found.
Error: No available formula or cask with the name "anyenv".
==> Searching for a previously deleted formula (in the last month)...
Error: No previously deleted formula found.
==> Searching taps on GitHub...
Error: No formulae found in taps.
```

# brew doctorで見てみた
brewの不具合はbrew doctorを実行するとわかるらしいことを知ったので、実行。

```
$ brew doctor
Please note that these warnings are just used to help the Homebrew maintainers
with debugging if you file an issue. If everything you use Homebrew for is
working fine: please don't worry or file an issue; just ignore this. Thanks!

Warning: Some taps are not on the default git origin branch and may not receive
updates. If this is a surprise to you, check out the default branch with:
  git -C $(brew --repo homebrew/core) checkout master

```

`git -C $(brew --repo homebrew/core) checkout master`を実行すると解決できそうですね。

# 解決
上の`git -C $(brew --repo homebrew/core) checkout master`を実行したら解決。

```
$ brew -v 
Homebrew 3.0.10
Homebrew/homebrew-core (git revision xxxxxx; last commit 2021-04-03)
Homebrew/homebrew-cask (git revision xxxxxx; last commit 2021-04-03)
```

# 参考サイト
https://original-game.com/homebrew/
HTMLで絵を書く

![Image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171432/49f3eff0-eb8e-b862-25d9-0c44abb91c87.png)

上の画像のようなものが作れます。

```html:index.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <title></title>
  <meta charset="utf-8" />
</head>
<body style="background-color:#D0D0D0;">
  <div class="parent">
    <div class="bg">
      <canvas id="SimpleCanvas" width="640" height="640" style="background-color:#FFFFFF;"></canvas>
      <canvas id="SimpleCanvas-layer2" width="120" height="120" style="background-color:rgba(255,0,0,0);;"></canvas>
      <canvas id="SimpleCanvas-layerFont1" width="120" height="120" style="background-color:rgba(0,0,0,0);;"></canvas>
    </div>
  </div>
</body>
<link rel="stylesheet" href="./layout.css" type="text/css">
<script type="text/javascript" src="./draw.js"></script>
</html>
```


```CSS:layout.cs
.parent {
    width: 720px;
    height: 0px;
    position: relative; /*relativeに設定*/
    padding: 0em 0em;
    margin:0;
    z-index: 0;
}
.l1 {
    top: 20px;
    left: 0px;
    width: 720px; 
    padding: 0em 0em;
    position: relative; 
    z-index: 2;
}
.bg {
    top: 0px;   /*動的に変更されるので適当*/
    left: 0px;  /*動的に変更されるので適当*/
    width: 400px; /*撮影枠サイズ*/ 
    height: 60px; /*撮影枠サイズ*/
    position: relative; /*absoluteに設定*/
    padding: 0em 0em;
    z-index: 1;
}

.bg canvas {
    position: absolute;
}
```

```js:draw.js
function draw_1Pattern(step){
  console.log(width,height,pixels.length,width*height*4)
  // ピクセル単位で操作できる
  var cnt = 0
  for (var x = 0; x < width; ++x) {
    for (var y = 0; y < height; ++y) {
      var base = (y * width + x) * 4;
      if((Math.floor(x/step))%2 == 0){
        pixels[base + 0] = 38
        pixels[base + 1] = 31
        pixels[base + 2] = 135
        pixels[base + 3] = 255

      }
      else{
        pixels[base + 0] = 0
        pixels[base + 1] = 133
        pixels[base + 2] = 84
        pixels[base + 3] = 255

      }
    }
  }
}

var canvas = document.getElementById('SimpleCanvas');
canvas.width = screen.width*0.9
canvas.height = screen.height*0.8
var context = canvas.getContext('2d');

// キャンバス全体のピクセル情報を取得
var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
var width = imageData.width, height = imageData.height;
var pixels = imageData.data;  // ピクセル配列：RGBA4要素で1ピクセル
//console.log(pixels)
var step = 160//ボーダーの横幅ピクセル
draw_1Pattern(step)
//console.log(pixels)
// 変更した内容をキャンバスに書き戻す
context.putImageData(imageData, 0, 0);
```
よく使うシェルスクリプト

## ファイル出力

```shell
# hoge.txt の内容を出力
cat hoge.txt
```

リダイレクト「>」を使えば別のファイルに書き出す事も可能

```shell
# hoge.txt の内容を fuga.txt に書き出す
cat hoge.txt > fuga.txt
```

## ディレクトリ作成

```shell
# hoge ディレクトリを作成
mkdir hoge
```

-p オプションをつければ階層ごと作成できる

```shell
mkdir -p hoge/fuga

# 階層はこんな感じ
hoge
 +- fuga
```

こんな書き方もできる

```shell
mkdir -p /hoge/{a1/a2,b1/b2/}

# 階層はこんな感じ
hoge
 +- a1
     +- a2
 +- b1
     +- b2
```

## ファイルコピー

```shell
# cp コピー元 コピー先
cp hoge.txt fuga.txt
```

-r をつけるとディレクトリごとコピーもできる

```shell
# hoge ディレクトリにあるもの全て fuga ディレクトリにコピー
cp -r hoge fuga
```

## ファイル置換

```shell
# hoge.txt にある全ての hoge を fuga に置換
sed -e "s/hoge/fuga/g" hoge.txt
```

-e をつなげれば複数の内容を一気に置換できる

```shell
# hoge.txt にある全ての hoge を fuga に、aaaa を bbbb に変換
sed -e "s/hoge/fuga/g" -e "s/aaaa/bbbb/g"　hoge.txt
```

置換したものを新しいファイルとして出力することもできる

```shell
# hoge.txt にある全ての hoge を fuga に置換して　fuga.txt として出力
sed "s/hoge/fuga/g" hoge.txt > fuga.txt
```

長くなって見づらくなったら「\」で改行もできる（これは sed に限らず、どのコマンドでも可能）

```shell
sed -e "s/hoge/fuga/g" \　
    -e "s/aaaa/bbbb/g" \
    hoge.txt
```
Ruby ハッシュの値の取得方法

ハッシュには３種類の定義方法があります。
①キーに文字列を使う方法
　hash1 = { "sample" => "例" }
②キーにシンボルを使う方法
　hash2 = { :sample => "例" }
③キーにシンボルを使う方法（②よりもシンプル）
　hash3 = { sample: "例" }　

①を使用した場合のハッシュの値の取得の仕方は、ハッシュ["取得したい値のキー"]です。

例）

```ruby:qiita.rb
favorites = { "fruit" => "いちご", "subject" => "数学" }
puts favorites["fruit"]
```

②と③を使用した場合のハッシュの値の取得の仕方は、ハッシュ[:取得したい値のキー]です。

例）

```ruby:qiita.rb
favorites = { :fruit => "いちご", :subject => "数学" }
puts favorites[:subject]
favorites = { fruit:  "いちご", subject: "数学" }
puts favorites[:subject]
```

ハッシュの定義方法によって、値の取得の仕方が異なります。
【Swift】RxSwiftまとめ

#はじめに
自分のRxSwiftに関する記事をまとめておきます。

#まとめ

##参考になった記事まとめ

https://qiita.com/REON/items/8339621f9087b98ea86b

##勉強してみたシリーズ

https://qiita.com/REON/items/48e61c3af14ea6f18241

https://qiita.com/REON/items/11694c756e51bbbb801b

https://qiita.com/REON/items/aa8f9a6c72e01fd56272

https://qiita.com/REON/items/c986ff93e67e3693324c

https://qiita.com/REON/items/1f6f8af79241b51158bd

https://qiita.com/REON/items/8fd68bb59c0e6dbdbc3f

https://qiita.com/REON/items/dbceb1ce5a8977734352

https://qiita.com/REON/items/8ded3fcc1151d5776da8

https://qiita.com/REON/items/08a19b644e2aac75eb83

https://qiita.com/REON/items/f1a845479f03797c17e8

https://qiita.com/REON/items/5bb8c535ccfe0c869133

##Twitterで教えてもらったシリーズ

https://qiita.com/REON/items/f4a938bcc1f41fe106c7

https://qiita.com/REON/items/c7f3d72995170f472701

##サロンで教えてもらったシリーズ

https://qiita.com/REON/items/f5455cb458151dde0c54

#おわりに
RxSwift理解できる日が来るのだろうか、、、🤔
ImportError libgl.so.1 cannot open shared object file no such file or directory を解決したい 

# はじめに
<!-- 発端や概要を記載 -->
opencvを使った、Djangoのデプロイについて、
ハマったので、個人備忘録を残します。
知識不足だったのは以下の2点。(2021/03/30現在)

- staticファイルの取扱いについて
- opencvのライブラリ

以下は、GitHub に push したDjango プロジェクトを
Heroku にデプロイする時の話です。

デプロイ後、
Webアプリを起動すると、ブラウザに以下の文章が表示され、
何をしたらいいのかよく分からない状態に陥りました。

```
Not Found

The requested resource was not found on this server.
```

今回はこのエラーに対する解決策を残します。


# 目次
<!-- タイトルとアンカー名を編集 -->
1. [開発環境](#開発環境)
1. [Not Found の原因は opencv なので opencv-python-headless に変更して解決する](#not-found-の原因は-opencv-なので-opencv-python-headless-に変更して解決する)
1. [アプリケーションサーバーで静的ファイルを参照できるようにpython manage.py collectstaticを実行する](#アプリケーションサーバーで静的ファイルを参照できるようにpython-managepy-collectstaticを実行する)
1. [参考文献](#参考文献)

<!-- 各チャプター -->
<a id="#開発環境"></a>
# 開発環境
MacBook Air 2017
macOS Catalina 10.15.16

dj-database-url==0.5.0
Django==3.1.7
django-heroku==0.3.1
gunicorn==20.1.0
mediapipe==0.8.3.1
numpy==1.20.2
opencv-python==4.5.1.48

venv (python -m venv venv)

<a id="#Not Found の原因は opencv なので opencv-python-headless に変更して解決する"></a>
# Not Found の原因は opencv なので opencv-python-headless に変更して解決する

まずは原因を探すために以下を入力。

```
(venv) % heroku logs --tail
```

すると、ログの中間あたりに次のようなエラーが記録されていました。

```
(venv) % ImportError libgl.so.1 cannot open shared object file no such file or directory
```

調べてみると、
[herokuでOpenCVを利用する [Python3]](https://qiita.com/haru1843/items/210cb08024195b9d1bc8)
を見つけ、同じような手順でbuildpacks、
Aptfileを追加してもエラーは解消されなかった。

そもそも ImportError: libSM.so.6:..ではなく、
...so.1:なんだけどな...
と思いながらさらに調べていくと、
以下にたどり着きました。
[Importerror: libgl.so.1: cannot open shared object file: no such file or directory opencv error](https://discuss.streamlit.io/t/importerror-libgl-so-1-cannot-open-shared-object-file-no-such-file-or-directory-opencv-error/7031/10)

以下のように、
requirements.txtを編集したら良かったみたいです。

>```python:requirements.txt
traitlets==4.3.3
tzlocal==2.1
urllib3==1.26.2
validators==0.18.1
watchdog==0.10.4
wcwidth==0.2.5
webencodings==0.5.1
widgetsnbextension==3.5.1
wincertstore==0.2
zipp==3.4.0
opencv-python--headless==4.5.1.48
```

上記のように、opencvライブラリは
--headless を含めたバージョンへの変更が必要だったみたいです。


<a id="#アプリケーションサーバーで静的ファイルを参照できるようにpython-manage.py collectstaticを実行する"></a>
# アプリケーションサーバーで静的ファイルを参照できるようにpython manage.py collectstaticを実行する

これでデプロイは成功したかのように思えましたが、
ブラウザ上での表示は変わらず Not Found.. のままでした。

何も表示されないのは、さすがにおかしいと思い、
静的ファイル関連で調べていくと、
以下の記事が見つかりました。

[Djangoにおける静的ファイル(static file)の取り扱い](https://qiita.com/saira/items/a1c565c4a2eace268a07)

この記事を参考に、
ターミナル上で以下を実行しました。

```terminal
(venv) % python manage.py collectstatic
```

これを実行し、
GitHub と Heroku への更新を反映させると、
無事アプリが表示されました。



Opencv は便利だけど大体導入でつまづく...。





<a id="#reference"></a>
# 参考文献
- [herokuでOpenCVを利用する [Python3]](https://qiita.com/haru1843/items/210cb08024195b9d1bc8)
- [Djangoにおける静的ファイル(static file)の取り扱い](https://qiita.com/saira/items/a1c565c4a2eace268a07)
- [DjangoアプリをHerokuにデプロイする方法](https://qiita.com/frosty/items/66f5dff8fc723387108c)