OmniAICreator/Qiita-1.07M huggingface dataset:
[2021Sep] Ubuntu で RTL8761B な USB Bluetooth 5 ドングルを使う

# はじめに

Bluetooth が搭載されていないノートパソコンがあり、USB ドングルで Bluetooth 機能を追加していました。

とあるタイミングでドングルを奪われ（笑）、新たに Bluetooth 5 対応のドングルを調達したのですが、これが Ubuntu で動きませんでした。悲劇。

ですが、ちょっとゴニョっとしたら動いたので、メモを残します。


# 結論

Ubuntu 20.04 LTS Focal Fossa は HWE の Kernel 5.11 で動きました。

Ubuntu 18.04 LTS Bionic Beaver は、Ubuntu Kernel Team がビルドしている Kernel 5.11 で動きました。


# レシピ

### 20.04 LTS Focal Fossa

20.04 LTS Focal Fossa はデフォルトで HWE が enable されているハズです。なのでフツーにアップデートしていれば 5.11 になります。

Ubuntu MATE 等では HWE が disable なので、自己責任で enable にしましょう。
（最初コレに気付かず右往左往したのはナイショです。）


### 18.04 LTS Bionic Beaver

18.04 LTS Bionic Beaver は HWE の最新が 5.4 です。オリジナルが 4.15 なので、それに比べれば新しいですが、ドライバが取り込まれたのは 5.8 らしいので、このままでは RTL8761B ドングルは動きません。

ドライバ単体のソースコードを入手してビルドしてロードする、という方法もあるようですが、せっかくパッケージ化された Kernel があるのですから、利用させてもらいましょう。

5.11 の最新は執筆時点で [v5.11.22](https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.11.22/) です。
なお 5.11 を選んだのは Focal Fossa と同じにしようと思ったからです。安直万歳。

さて、必要ファイルは３つです。

- linux-image-unsigned-5.11.0-20-generic
- linux-modules-5.11.0-20-generic
- linux-modules-extra-5.11.0-20-generic

apt install でインストールすれば grub に登録され、フツーに起動できるようになります。


# 注意

RTL8761B ドングルは技適を取得していない商品が涼しい顔で流通しているので注意してください。

技適を取得している商品も別に極端に高額じゃないので安心してください。


# おわりに

先に 20.04 で確認したので、18.04 は 20.04 にアップデート（アップグレード？）しても良かったんですが、半年もすれば 22.04 LTS が出るわけで、いま 20.04 を始める選択はありませんでした。

そして、当初は vanilla kernel をビルドしようと思っていたんですが、Ubuntu Kernel Team の成果物があるじゃないかと思い出して、試してみたら使えた、という次第です。

18.04 でも手軽に新しい Kernel が利用できるなんて、便利すぎますね。Kernel Team に感謝。
[Python]2ページ両面印刷用にPDFを変換

## 目的
自宅のプリンタの両面印刷機能がA4でないと使えないため、下記のように変換
変換前: [0, 1, 2, 3, ...]
変換後: [[0,2], [1,3], ...]
印刷後に裁断し、A5冊子化する

## 環境
- VSCode
- Ubuntu 20.04 LTS(WSL)

## 使用ライブラリ
```
pip install PyPDF2
```

## コード
```pdf_converter.py
import sys
import os
import PyPDF2 as pdf

def main(args):
    file_path = args[1]
    if not os.path.exists(file_path):
        print("Invalid args: No exists file_path")
        sys.exit(-1)
    f = open(file_path, 'rb')
    reader = pdf.PdfFileReader(f)

    page_num = reader.getNumPages()
    media = reader.getPage(0).mediaBox
    page_w = media.upperRight[0]
    page_h = media.upperRight[1]
    print(page_num)
    print(page_w)
    print(page_h)

    writer = pdf.PdfFileWriter()

    for i in range(0, page_num, 4):
        #print(i)
        cnt = 4
        if page_num-i < 4:
            cnt = page_num-i
        page02 = pdf.pdf.PageObject.createBlankPage(width=page_w*2, height=page_h)
        page13 = pdf.pdf.PageObject.createBlankPage(width=page_w*2, height=page_h)

        for j in range(cnt):
            if j==0 or j==3:    #上
                x = 0
            else:               #下
                x = page_w

            if j%2 == 0:    #奇数ページ
                page02.mergeTranslatedPage(reader.getPage(i+j), x, 0, expand=False)
            else:           #偶数ページ
                page13.mergeTranslatedPage(reader.getPage(i+j), x, 0, expand=False)

        # 回転
        page02.rotateClockwise(90)
        page13.rotateCounterClockwise(90)

        # ページ追加
        writer.addPage(page02)
        writer.addPage(page13)
    
    output_path = "./out.pdf"
    output_file = open(output_path, 'wb')
    writer.write(output_file)
    output_file.close()
    f.close()
        

if __name__ == "__main__":
    args = sys.argv
    main(args)
```

## 結果
```
$ python3 pdf_converter.py sample.pdf
```
- 変換前
![sample.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500080/36be13ec-364f-6fb5-6438-2e515f4995a5.png)
- 変換後
![result.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500080/75103e2b-cb43-c84e-0c1d-25f93aa8b3d1.png)


## MEMO
`PyPDF2.mergeScaledTranslatedPage`を使用するつもりだったが、回転と平行移動を共に行った際の挙動が思ったものと違った為、連結後に回転処理を実行

## 参考ページ
- [PyPDF2リファレンス](https://pythonhosted.org/PyPDF2/)
- [A4のPDFをA3に2面付（2in1）する -- Python(PyPDF2)](https://qiita.com/miko/items/054b982700c6219c7fce)
- [A4のPDFを2ページごとのA3に変換・分割する](https://qiita.com/nabe3ch/items/3528923cbd884b3e5a12)
GoogleColabの使い方の勉強

【Google Colabの使い方と簡単なAIの作成とQiitaの使い方勉強】

Google Colabにログイン
https://colab.research.google.com/notebooks/intro.ipynb

注）月の利用量制限があったはず

https://aiacademy.jp/texts/show/?id=164

これを参考に行った。
flutter_hooksでタブ切り替えを実現する

# 背景
Web上には、stateful widgetのtabの実装例はあれど、hooksのパターンが少ないので記載しました。
flutter_hooksには、デフォルトでuseTabControllerのフックを備えているのでそちらを利用しています。

# 実装イメージ
![tab.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1424230/08b98155-fadd-02e0-34a2-0e8205c2b70d.gif)
# 開発環境
mac Big Sur(v11.3, intel)
Android Studio 4.2.2
Xcode 12.5
Flutter 2.5.0
Dart 2.14.0

## プラグイン環境
flutter_hooks: ^0.18.0

# 準備
プラグインをインストールするために、pubspec.yamlのdependenciesにflutter_hooksを追加

```yaml:
dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.2
  flutter_hooks: ^0.18.0  # ←✨追加✨
```
# 実装
以下のflutter_hooksプラグインの公式を参考にして実装しました。
https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useTabController.html

もし、以下ソースコードを簡単に動かしたい場合は、[GitHub](https://github.com/ko-izumi/tabbar_using_hooks)に置いたので参考にしていただければと。


```dart:
class TabBarViewWidget extends HookWidget {
  TabBarViewWidget({Key? key}) : super(key: key);

  /// タブ切り替え画面
  final List<Widget> tabList = [
    const Tab(child: Text('Tab 1')),
    const Tab(child: Text('Tab 2')),
    const Tab(child: Text('Tab 3')),
  ];

  @override
  Widget build(BuildContext context) {
    final _controller = useTabController(initialLength: tabList.length);
    return Column(
      children: [
        /// TabBar(=タブ画面)を表示
        TabBar(
          controller: _controller,
          tabs: tabList,
          labelColor: Theme.of(context).primaryColor,
        ),
        Expanded(
          /// タブの中身を表示するWidget
          child: TabBarView(
            controller: _controller,
            /// タブに表示したいWidgetをchildrenに記載する
            children: const [
              Center(child: Text('Tab 1 View')),
              Center(child: Text('Tab 2 View')),
              Center(child: Text('Tab 3 View')),
            ],
          ),
        )
      ],
    );
  }
}
```

参考のため、呼び出し元も記載しておきます。

```dart:
void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: const Text('TabBar using flutter_hooks'),
        ),
        /// ここで上記のWidgetを呼び出している
        body: TabBarViewWidget(),
      ),
    );
  }
}
```
Markdown のコードブロックを動的に読み込ませる


# 概要

次の処理をするスクリプトである.

下左図のように "Markdown もどき" を書いておき、本スクリプトを適用すると
下右図のように a.rb の内容が展開される、というものである.

動的にマークダウンを更新したいときに役立つのかも知れない.[^1]

|変換前|変換後|
|:----|:----|
|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1246056/d81f6d44-56c6-331a-b4c1-9e2f8d5a7197.png)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1246056/c31722ed-f3fa-bb57-5421-1afd9aa00766.png)|


# コード

## update_mdpre.sh

```bash
#!/bin/bash

ERROR=

test -z "$1" && {
  echo '$1 が指定されていません'
  exit 2
}

# 「^(cat ファイル)$」というパターンに一致したらファイルの存在有無をチェックする
for f in `sed -r -n -e 's%^\(cat (.*)\)$%\1%p' $1`
do
    test ! -f $f && {
        echo "ERROR: 存在しません => <$f>"
        # 見つからないファイルがあったのでエラーフラグを立てておく
        ERROR=1
    }
done

test ! -z "$ERROR" && {
    echo "見つからないファイルがあったため中断します"
    exit 2
}

# 改行区切りで読み出す
IFS=$'\n'

# for line in `cat $1`; do 〜 done だと空行が読み込まれなかったので
# while read line; do〜done を使った
while read line; do
    # 「^(cat ファイル)$」で定義された「ファイル」のパスを得る
    F=`echo $line | sed -n -r 's/^\(cat (.*)\)$/\1/p'`
    if [ ! -z "$F" ]; then
        # ファイルが指定されていたので、cat で表示させる
        cat $F
    else
        # 加工せずに、一行をそのまま表示する
        echo $line
    fi
done < $1

```

# 使い方

```bash
$ update_mdpre.sh <Markdownファイル> > 出力ファイル
```

　

以上

[^1]: もしかしたらすでに動的にファイルを読み込む機能を持つ Markdown エディタが存在しているのかも知れない
【GoogleAppsScript】GASでDeepL APIを叩く

#目的
GOOGLETRANSLATE関数およびLanguageApp.translate()が吐き出すテキストがいまいちなので、GASでもDeepL翻訳を使いたい。

#事前準備
1. DeepL Free APIプランのアカウント(無料)を作成
有料プランに移行しなければ課金はされないが、アカウント作成時にクレジットカード情報の入力を求められる。
ちょっとアレだと思う。

https://www.deepl.com/pro/change-plan?cta=header-pro#developer

1. アカウントページでAPI用認証キーを発行しておく
![qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13281/c2da370d-01d6-6210-f069-74fd99f56864.png)

#GAS
```deepl.gs
const API_KEY = '<あなたのAPI認証キー>';
const API_URL = 'https://api-free.deepl.com/v2/translate';

const FETCH_WAIT = 200;

// DeepL翻訳関数
function deepltranslate(text, src, tgt) {

  let t = text.toString();

  let url = API_URL;

  let content = encodeURI('auth_key=' + API_KEY + '&text=' + t + '&source_lang='+src+'&target_lang='+tgt);

  const postheader = {
    "accept":"gzip, */*",
    "timeout":"20000",
    "Content-Type":"application/x-www-form-urlencoded"
  }  

  const parameters = {
    "method": "post",
    "headers": postheader,
    'payload': content
  }

  // スプレッドシートから大量に呼ばれる可能性があるのでウェイトを入れておく
  Utilities.sleep(FETCH_WAIT);

  try {
    var response = UrlFetchApp.fetch(url, parameters);
  }
  catch (e) {
    Logger.log(e.toString());
    return 'DeepL:Exception';
  }

  let response_code = response.getResponseCode().toString();

  Logger.log(response_code + ':' + url);

  if (response_code != 200) return 'DeepL:HTTP Error(' + response_code + ')'

  // JSONからテキストを取り出す
  let json = JSON.parse(response.getContentText('UTF-8'));
  return json.translations[0].text;

}

// 
function deepltranslateje(text) {
  return deepltranslate(text, 'ja', 'en');
}

function deepltranslateej(text) {
  return deepltranslate(text, 'en', 'ja');
}
```
:::note
Googleスプレッドシート上では、以下のように言語を指定する。
=deepltranslate(A2, "ja", "en")
:::

###備考

https://www.deepl.com/docs-api

#出力

| 原文 | DeepL | Google |
|:-:|:-:|:-:|
| So today, we are going to talk about one of the questions I've been getting the most recently is there anything that can happen for bitcoin right now that would change my bullish mindset.  |  そこで今日は、私が最近よく受ける質問のひとつ、「今、ビットコインに何か起こって、私の強気の考え方が変わることはありますか」についてお話しします。 |  だから今日、私は最近入ってきた質問の1つについて話すつもりです。 |
|  Guys, this is an important video we're talking about bitcoin ethereum and cardano and guys, if you did not know I actually have channels in arabic, I have it in italian and also in hindi. | このビデオは、ビットコイン、イーサリアム、カルダノについての重要なビデオです。  | みんな、これは私たちがBitcoin EthereumとCardanoとGuysについて話している重要なビデオです。 |
|  We're doing weekly giveaways on this channel so make sure to check them out if you're speaking these languages. |このチャンネルでは毎週プレゼントを行っていますので、これらの言語を話す人はぜひチェックしてみてください。   |  私たちはこのチャンネルで毎週の贈り物をしていますので、これらの言語を話している場合は必ずそれらをチェックアウトしてください。 |
StreamDeckの独自Plugin開発のTemplateを実際に書き出すまで

# ゴール

StreamDeckの独自Pluginを開発したい人の第一歩の記事になればと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/ca752b05-dfba-2c95-e72b-6cd152fc18e2.png)


# 手順

- GithubからTemplateをclone
- ディレクトリ、ファイルの文字列を置換
- 配布ファイルを生成

# 参考サイト
https://developer.elgato.com/documentation/stream-deck/sdk/overview/

# GithubからTemplateをclone

https://github.com/elgatosf/streamdeck-plugintemplate

```
git clone git@github.com:elgatosf/streamdeck-plugintemplate.git
```

# ディレクトリ、ファイルの文字列を置換

com.elgato.templateをyour.identifier.pluginに置き換える。

例: `com.iwaken.practice`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/441d8fcd-740c-fe22-b47a-627e4286a212.png)

# 配布ファイルを生成

配布するときは、Sourceを共有するのではなく、streamDeckPluginファイルを書き出して共有する。これはDeveloperToolにより生成することができる。

https://developer.elgato.com/documentation/stream-deck/sdk/exporting-your-plugin/
のDownloadからOSに応じてダウンロード

今回わかりやすいように作業ディレクトリ直下に置く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/de77c54d-c486-75e0-eba8-f8755e0961c5.png)

### Macの場合

```
./DistributionTool -b -i /Sources/your.identifier.plugin.sdPlugin -o Release/
```

### Windowsの場合

```
.\DistributionTool.exe -b -i .\Sources\your.identifier.plugin.sdPlugin\ -o .\Release\ 
```

で生成。
生成されたファイルをダブルクリックするとStreamDeckにインストールされる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/4704a83e-6989-fb18-82ec-26195e269fe0.png)


## 再インストールする場合
StreamDeckにすでにインストールされているとインストールされないため、再度インストールする場合は、StreamDeckからアンインストールしてから行う。

# アイコンの変更
`manifest.json`を開き
IconとImageをvalueを変更します。

```json:manifest.json
{
  "Actions": [
    {
      "Icon": "action/images/iwakenimage",
      "Name": "Example Action",
      "States": [
        {
          "Image": "action/images/iwaken"
        }
      ],
      "Tooltip": "This is an example tooltip",
      "UUID": "com.iwaken.practice.action"
    }
  ],
  "SDKVersion": 2,
  "Author": "Elgato",
  "CodePath": "index.html",
  "PropertyInspectorPath": "propertyinspector/index.html",
  "Description": "Example description",
  "Name": "Stream Deck Template",
  "Icon": "action/images/iwaken",
  "URL": "https://www.elgato.com/en/gaming/stream-deck",
  "Version": "1.0.1",
  "OS": [
    {
      "Platform": "mac",
      "MinimumVersion": "10.11"
    },
    {
      "Platform": "windows",
      "MinimumVersion": "10"
    }
  ],
  "Software": {
    "MinimumVersion": "4.1"
  }
}
```
このように

```
iwaken.png
iwaken@2x.png
iwakeniamge.png
iwakenimage@2x.png
```

を生成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96970/eb21cc66-c4a0-6dc9-42b1-7f7d816ffd93.png)

これらがボタンのiconと右側のメニュー欄のiconに使用されます。
[OutSystems]ポップアップする共通部品を作る

共通部品として、ポップアップさせて使う入力画面や選択画面を作る方法を考えてみます。

Traditional Webでは、UIフレームワーク中にModal（画面内に配置する）とPopup（別の画面として作成する）の2種類がありました。
Reactive Web Appの標準部品にあるPopupは同じ画面内に配置するPopupしかありません。

Reactive Web AppでPopupを使って共通部品を作る方法を検討します。

# 確認環境
Personal Environment(Version 11.13.0 (Build 31107))
Service Studio (Version 11.11.15)

# 方法1：共通部品内にPopupを含めない
## 共通部品はBlockで作成する
独立のBlockとして共通部品を作成し、Public=Yesとする。
これで、他のモジュールからも参照可能。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/9d995789-436f-56c4-86bf-de9e47e7064e.png)

共通部品で何らかの操作をした結果を配置先画面に伝えるには、BlockにEventを作成します。

1. Blockを右クリック > Add Event
1. （Eventに値を渡すとき）追加したEventを右クリック > Add Input Parameter
1. 操作に紐づくScreen Action中に、Trigger Event要素を配置（EventプロパティにはAdd Eventしたものを選択）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/8e05ee95-89f6-7b61-654b-c3c211d160e2.png)

これで、Blockを配置した画面で、部品での選択や検索等の操作を終えたというイベントを受け取れます。
（Blockで起こった変化を配置先画面で知るには、基本的にはEventを使うことになる）

## 配置先画面にPopupを配置
1. 上で作成した共通部品Blockへの参照を利用側モジュールで追加
1. 画面のLocal Variableとして、Boolean型の変数を用意（Popupの表示を制御する変数）
1. 画面にPopupを配置（Service Studio左側のツールボックスからドラッグ＆ドロップで）し、Show Popupプロパティに作成した変数を紐付け
1. Popup内に作成しておいた共通部品を配置。配置した部品のEventに対するHandlerで、共通部品の処理結果を受け取って後処理。ここで制御用変数の値をFalseにしておく

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/fba364df-691c-26e0-0141-f3e1b2db9b2d.png)

# 方法2：共通部品にPopupを含める
方法1では、Popupを配置先画面の方で作っていましたが、こっちの方法では共通部品内にPopupも配置します。

Widget Treeはこんな感じ。Block直下にPopupを配置してあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/355d95b9-4605-7716-dd13-00d82b08a6d9.png)

Input ParameterにPopupを表示するためのBoolean型を持たせ、PopupのShow Popupプロパティに紐付けます。配置先の画面でこのパラメータにTrueを設定するとポップアップが表示される。選択後のイベントハンドラ（配置先画面の）で、パラメータに紐付けてある変数をFalseに戻しておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/e464b97b-b530-3f89-b5fc-8ac687035dd4.png)

# 方法の選択方針
部品としては、方法2で良さそうですね。
同じUIをポップアップ以外でも使うときは方法1を選択する方針でしょうか。
Xamarin.Forms用のPrismでRegionを設定する方法（エラーを回避する方法）

# はじめに

Xamarin.Forms用のPrismでRegionを設定する方法について解説します。
（検索するといくつか解説記事がヒットするのですが、そのままでは使えなかったです。。。）

WPF用のPrismなどは以前からRegionが使えたのですが、Xamarin.Forms用のPrismは8.0から使えるようになったようです。

[Prism Releases](https://github.com/PrismLibrary/Prism/releases)
> Prism 8.0 RTM
> NEW FEATURE - Region support for Prism.Forms is HERE!!!


## 参考にしたページ
- [Regions in Prism for Xamarin.Forms](https://avantipoint.com/blog/post/2020/10/23/regions-in-prism-for-xamarinforms)
- [Prism Regions in Xamarin Forms](https://xamgirl.com/prism-regions-in-xamarin-forms/)

## 環境
- Prism.Forms.Regions : 8.1.97
- Xamarin.Forms : 5.0.0.2083
- Prism.Unity.Forms : 8.1.97

## 結論
参考にしたページのようにRegionを指定することを考えます。

```xml
prism:RegionManager.RegionName="ContentRegion"
```

この場合、Xaml内の名前空間の指定を以下のように変更する必要があります。

(変更前)

```xml
xmlns:prism="http://prismlibrary.com"
```

(変更後)

```xml
xmlns:prism="clr-namespace:Prism.Regions.Xaml;assembly=Prism.Forms.Regions"
```

※実際には以下のように分けた方がが良いと思います。

```xml
xmlns:prism="http://prismlibrary.com"
xmlns:region="clr-namespace:Prism.Regions.Xaml;assembly=Prism.Forms.Regions"

region:RegionManager.RegionName="ContentRegion"
```

## 発生していたエラー

```
Error XFC0000: Cannot resolve type "RegionManager". (XFC0000) (AppName) XamlC
```

## 原因

エラーに書かれている通り、`RegionManager`が見つからないことが原因です。

`RegionManager`を見つけるには、適切な名前空間を使えるようにする必要があると思い、`RegionManager`を適当な箇所でインスタンス化して見ると以下のような表示が見えました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245628/fc449880-dae3-00bd-5f4d-30367f23b2d5.png)

上図より、`RegionManager`は`Prism.Regions.Xaml`名前空間内にいることが判明したのであとはこの名前空間が使えるようにXaml内に記載してあげればOKです。
結局、オブジェクト指向とは。スマッシュブラザーズで例える。

# はじめに
本記事では、オブジェクト指向について私が理解したところまでを記述します。

# オブジェクト指向とは
`object=物体`by Google先生

なるほど、意味わからん。
ということで調べました。

[初心者向けに徹底解説！オブジェクト指向とは？](https://eng-entrance.com/what-oop)
> オブジェクト指向は「概念」だ、ということだ。概念という言葉自体も難しいが、なんとなく意味はわかるだろう。物事や対象を丸ごとひっくる見たときの大まかな理解のことだ。

特に明確な回答はないということだと思います。
私が通学していたスクールではこのように学習しました。

> アプリケーションを作成するときに、登場する役割ごとに分けて実装する方針のことを言います。

色々検索した結果、
`愛`、`車`、`人間`この３つがやたらと出てきました。

`モノ`、`単体`、`ハコ`などという認識だと思います。


## 私はこのように理解しておきます
`愛`や`車`では理解しにくかったので、
`スマッシュブラザーズ`というオブジェクトを考えました。

`スマッシュブラザーズ`の中には多くのキャラクター、つまり`オブジェクト`が山ほどいます。
その中の`ドンキーコング`で説明します。

```
- ドンキーコングはAボタンでジャブをします
- ドンキーコングはBボタンでパンチを溜めます
- ドンキーコングはYボタンでジャンプします
- ドンキーコングはZボタンで掴み技をします
```
があったとします。

ここで`ドンキーコング`というオブジェクト（モノまたはキャラクター）を先に作ったとします。
先に`ドンキーコング`というオブジェクトを作ることで、ボタン操作のみを考えればいいことになります。

```
[ドンキーコング]
- Aボタンでジャブをします
- Bボタンでパンチを溜めます
- Yボタンでジャンプします
- Zボタンで掴み技をします
```
このようにすることで、全ての操作に(ドンキーコングは)という言葉を抜くことができます。

また、追加で`Cボタン`の仕様を決めたとしても、
`ドンキーコング`というオブジェクトは既に存在するので、

```
- Cボタンはスマッシュ攻撃します
```
と機能を追加するだけでドンキーコングのCボタンの技が完成します。

### クラス
`クラス`は、設計図のようなもので、
`属性`と`操作`が中にはあります。

`属性`はスマッシュブラザーズでは、`キャラクター`
`操作`は`Aボタン`や`Bボタン`など。`操作はプログラミング的にメソッドになります`

この設計図を元に、`インスタンス化`したら、
`ドンキーコング`や`ファルコン`、`ガノンドロフ`というオブジェクトが出来上がる。
ということになります。

instance=「事実」「実例」「実態」by Google先生

`ドンキーコング`が`Aボタン`というメソッドを使用したら`ジャブする`という行動になります。
このようにドンキーコングは動きます。

## オブジェクト指向のメリット

- 役割ごとにオブジェクトを分けることで、実装がしやすくなる
- 役割ごとにオブジェクトを分けることで、あとからコードを改変するときも、他のオブジェクトに影響しなくなる（コードの改変がしやすくなる）

逆にいうと、オブジェクト指向を意識しないと以下のようなことが発生します。

- オブジェクト内にさまざまな役割が入り組んでいて、どこに何があるのかわからない
- 1つの機能を変えた途端、その変更とは関係のないはずの機能が動かなくなってしまった



以上です。
このような形で私は`オブジェクト指向`を理解しました。

# 終わりに
私は、多くの時間をrubyに費やしましたが、
何かモノをメソッドで操作したり、インスタンス変数を作ったりと、
あれは正しくオブジェクト指向だったということですね。
学習がある程度できて理解できました。

ある程度学習できたタイミングで今回のように基礎に戻るのも良いかもしれないですね。

以下今回の参考サイトです。
[初心者向けに徹底解説！オブジェクト指向とは？](https://eng-entrance.com/what-oop)
[オブジェクト指向とは？｜知っておきたいプログラミング用語を徹底解説](https://coeteco.jp/articles/10837)
[「オブジェクト指向」とは？プログラミングに必要不可欠な要素を解説！](https://robo-done.com/blog/2021/04/doneship_object_oriented/)
[オブジェクト指向とは？誰でもわかるようにやさしく解説](https://www.sejuku.net/blog/5973)

明日は日曜日ですが、気を引き締めて頑張ります！
The PutObject operation requires non-empty parameterのエラー対応について


下記の記事を参考にs3へ画像を保存する途中でThe PutObject operation requires non-empty parameterのエラーが出たのでその対処法です。

https://qiita.com/nakasan773/items/9436e9b1c60831120aba

##参考にした記事

https://stackoverflow.com/questions/64751415/the-putobject-operation-requires-non-empty-parameter


https://webbibouroku.com/Blog/Article/laravel-env-cache

##確認手順


https://qiita.com/nakasan773/items/9436e9b1c60831120aba

上記記事を参考にcomposerで必要なものを入れたりバケットを作ったり.envを書き換えます。

その後、

```php
php artisan config:cache
もしくは
php artisan cache:clear
```

を実行

1. config/filesystems.phpの設定確認
2. disk arrayのs3の部分を見る
3. .envと比較して.envをきちんと反映しているか確認

![スクリーンショット 2021-09-12 0.44.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670485/c3329de4-a349-e5ae-aa62-199660fcfe70.png)


4. 実行してみて下記でデバック


```php:MainController.php
use Config;

省略----

dd(Config::get('filesystems'));

```


![スクリーンショット 2021-09-12 0.59.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670485/29dd518b-a829-ea1a-ee26-1a639f055379.png)

s3の部分が反映されていない場合にはconfig/filesystems.phpに直接記入してみて動けばcacheがうまく消えていない可能性が高いです。

##感想

自分は古いcacheがうまく消えていなかったのが問題でした。
php artisan cache:clearだけではうまく消えないらしくphp artisan config:cacheを打つとうまく反映されました
ちょっとした工夫を取り入れたGASによる配列操作

GASで`setValues()`を使っていると、値を参照するときにData[0][5]みたいになってコードが読みづらいですよね。
今回は見栄えのよいデータ参照方法を考えてみました。
例えば下のようなスプレッドシートで人物データを取得する場面を考えてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1955768/3a30de9e-84cd-f280-d2a9-faa027af4923.png)

# 従来通り、setValues()を使った方法
シンプルにこんな感じでしょうか。

```
function getData() {
  const Sheet = SpreadsheetApp.getActiveSheet(); // アクティブシート
  const LastRow = Sheet.getLastRow(); // 最終行
  const StartCell = 7;

  // A7～F17までのデータを取得
  const UserValues = Sheet.getRange(`A${StartCell}:F${LastRow}`).getValues();
}
```

実際に取得したデータを確認してみると、こんな感じでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1955768/72017de2-ee1e-76d2-9c1c-3fc554bedad9.png)

ちなみに`UserValues[0]`でデータを取得してみるとこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1955768/be8ed580-d87b-d132-b122-0ad135fbf757.png)

例えば1行目の涼風青葉さんの名前を参照する場合、`UserValues[0][2]`となります。
しかも今回はスプレッドシートのセルを結合しているので、`UserValues[0][4]`は空欄になってしまいます。
うーん、使いづらい。。

# ちょっとだけ工夫してみた
pythonだと辞書型？GASだと連想配列？
呼び方はわからない（というか興味ない）ですが、少しは使いやすくなりました。

```
function getData() {
  const Sheet = SpreadsheetApp.getActiveSheet(); // アクティブシート
  const LastRow = Sheet.getLastRow(); // 最終行

  let userArr = [];
  const StartCell = 7;
  for (let i = StartCell; i < LastRow; i++) {
    userArr[i - StartCell] = {
      idnex: Sheet.getRange(`A${i}`).getValue(), // 番号
      flag: Sheet.getRange(`B${i}`).getValue(), // 参加有無
      name: Sheet.getRange(`C${i}`).getValue(), // 氏名
      address: Sheet.getRange(`D${i}`).getValue(), // メールアドレス
      note: Sheet.getRange(`F${i}`).getValue(), // 備考
    }
  }
}
```

実際に取得したデータはこんな感じでした。ぱっと見、あまり変わってませんね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1955768/21dccb9b-25f1-020d-e1cb-df63bf8ef913.png)

ちなみにさっきと同様`userArr[0]`でデータを取ってくるとこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1955768/323c704d-f6d3-8445-8949-3e7bcb734126.png)

取得データにkeyが付いているので、例えば`葉月しずく`を参照したいときは
`userArr[1].name`もしくは`userArr[1]["name"]`で取ってこれます。他の項目についても同様です。
`name`で名前を指定できるので、ソースコードも少しはわかりやすくなるかもしれない。
一応スプレッドシートの結合部分になる不要データもないので、その辺は心配なし。

# 結論
好み。
私は`setValues()派`。何故なら楽だから。
【Python】【Ruby】約数の総和を出すプログラム！！

　Pythonを学び始めたので、簡単なプログラムからひたすら作っています。今回は約数の総和を出すプログラムを作ってみました。

```python
def calculate_divisor(num):
    divisor = [i for i in range(1,num + 1) if num % i == 0]
    return divisor

def calculate_limited_divisor(num,divisor_range):
    limited_divisor = [i for i in range(1,divisor_range + 1) if num % i == 0]
    return limited_divisor

num = int(input("約数の総和を出したい整数を入力してください："))
divisor_range = int(input("和を出したい約数の範囲を指定してください："))
result = calculate_divisor(num)
result2 = calculate_limited_divisor(num,divisor_range)

print("約数の数は" + str(len(result)) + "です")
print("約数の総和は" + str(sum(result)) + "です")
print((str(divisor_range) + "以下の約数の和は" + str(sum(result2)) + "です"))
```
　このようなコードであり、出力結果は以下のようになります。

```
約数の総和を出したい整数を入力してください：12600
和を出したい約数の範囲を指定してください：5000
約数の数は72です
約数の総和は48360です
5000以下の約数の和は29460です
```

　ただ約数の総和を出すだけでなく、12600の約数のうち、5000以下の約数の和を出すといったこともできるようにしています。
　範囲の指定はそこまで重要な機能ではないと考えたため、範囲の指定をした関数と、範囲の指定をしていない関数を2つ作り、一方を削除しやすいようにしました。この方が見やすいかなとも思いました。
　再利用性を真剣に考えるならもっと抽象化できそうです。


## Rubyで作っていたプログラム

　また以前にはRubyで同じプログラムを作っていました。

https://qiita.com/kim-shun/items/eba96003ad974987d1aa

```ruby
def divisor(num,range)
  num_div = (1..num).select{ |count| num % count == 0 }
  range_div = (1..range).select{ |count| num % count == 0 }
  puts "約数の数は#{num_div.length}です"
  puts "約数の総和は#{num_div.sum}です"
  puts "#{range}以下の約数の和は#{range_div.sum}です"
end


puts "約数の総和を出したい整数を入力してください"
num = gets.to_i
puts "和を出したい約数の範囲を指定してください"
range = gets.to_i
divisor(num,range)
```

<br>

　ツッコミどころは感じつつも、ひとまずブログを書いてコードを見せることがモチベーションになり、コメントをいただくことが勉強になっています。

<br>
.NET 単体テストで IHttpClientFactory を使うメソッドを Mock する

毎回テストを書こうとするたびに忘れてしまうのでメモ。

テスト対象のコードはこんな感じ。

``` C#
public class ProductClass
{
    public ProductClass(IHttpClientFactory httpClientFactory)
    {
        HttpClientFactory = httpClientFactory;
    }

    public IHttpClientFactory HttpClientFactory { get; }

    public async Task<ResponseObject> Get()
    {
        using var client = HttpClientFactory.CreateClient("ClientName");
        using var request = new HttpRequestMessage(HttpMethod.Get, "/request/path");

        var response = await client.SendAsync(request).ConfigureAwait(false);
        if (!response.IsSuccessStatusCode)
        {
            return null;
        }
        var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

        return JsonConvert.DeserializeObject<ResponseObject>(json);
    }
}
```

テストコードはこうなる。
ポイントは `Moq.Protected` を使って `HttpMessageHandler` をモックすること。

```C#
[TestFixture]
[TestOf(typeof(ProductClass))]
public class ProductClassTests
{
    [Test]
    public async Task Get()
    {
        var responseObject = new ResponseObject
        {
            SomeProperty = "value"
        };
        var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
        mockHttpMessageHandler.Protected()
            .Setup<Task<HttpResponseMessage>>(
                "SendAsync",
                ItExpr.IsAny<HttpRequestMessage>(),
                ItExpr.IsAny<CancellationToken>())
            .Returns(() =>
            {
                var response = new HttpResponseMessage
                {
                    StatusCode = HttpStatusCode.OK,
                    Content = new StringContent(JsonSerializer.Serialize(responseObject))
                };
                return Task.FromResult(response);
            });

        var baseUrl = "https://test.example.jp";
        var httpClient = new HttpClient(mockHttpMessageHandler.Object)
        {
            BaseAddress = new Uri(baseUrl)
        };

        var mockHttpClientFactory = new Mock<IHttpClientFactory>();
        mockHttpClientFactory.Setup(m => m.CreateClient(It.IsAny<string>())).Returns(httpClient);

        var targetClient = new MedicalInstituteClient(mockHttpClientFactory.Object);
        var result = await targetClient.Get();

        Assert.That(result, Is.Not.Null);
        Assert.That(result.SomeProperty, Is.EqualTo("value"));

        mockHttpMessageHandler.Protected()
            .Verify(
                "SendAsync",
                Times.Once(),
                ItExpr.Is<HttpRequestMessage>(
                    request => request.Method == HttpMethod.Get
                    && request.RequestUri == new Uri($"{baseUrl}/request/path")),
                ItExpr.IsAny<CancellationToken>());

        mockHttpClientFactory.Verify(m => m.CreateClient(It.Is<string>(s => s == "ClientName")), Times.Once());
    }
}
```

参考サイト
[Mocking HttpClient SendAsync](https://carlpaton.github.io/2021/01/mocking-httpclient-sendasync/)
c++　メンバ関数で error: invalid use of non-static data member

## 概要

c++でclassのメンバ関数でメンバ関数を呼び出そうとした際、

```
error: reference to non-static member function must be called
std::sort(sorted_members.begin(), sorted_members.end(), Population::compare_inds);
```

というエラーが出ました。
自作classを格納したstd::vectorを自作関数でsortしようとした際にエラーとなりました

呼び出したい関数は以下です

```before.cpp
bool compare_inds(const Individual &left, const Individual &right){
    if (left.rank != right.rank)
       {
        return left.rank < right.rank;
       }
    else{
        return left.nc > right.nc;
        }
}
```


## 解決策

メンバ関数compare_indsの前にstaticをつけたら解決しました

```after.cpp
static bool compare_inds(const Individual &left, const Individual &right){
    if (left.rank != right.rank)
       {
        return left.rank < right.rank;
       }
    else{
        return left.nc > right.nc;
        }
}
```

vectorのsortのルールはよくわかっていませんが、classのメンバ変数(std::vector)のsortの条件にメンバ関数を使う際はstaticをつける必要があるみたいです。
SIFT をWSL2上のUbuntuにインストールする

#3行でまとめ
・SIFT WorkstationをWSL2上のUbuntuにインストールするには、WSL2上にインストールしたUbuntuに対して、以下からダウンロードできるスクリプトを使えばOK
https://github.com/teamdfir/sift-cli
・sudo sift install --mode=server だけでOK
・簡単、すぐ起動できる

#SIFTとは
以下にあるフォレンジック、インシデントレスポンス用のツールが入ったLinuxディストリビューションです。
https://www.sans.org/tools/sift-workstation/
インストール方法は上記に書いたとおりです。

#なぜWSL2上で動作させるか
単純に起動が早いからです。あと仮想マシンだとどうしてもディスクを食います。

#WSL上で動作させる場合の注意点
WSLの仕様上、Windowsマシンに接続した物理ディスクをデバイスとして認識しないようです。（fdiskで出てこない）
Windows上でマウントされていれば、/mnt/d/などからディスク内のファイルにアクセスできます。

ほとんどの場合は問題ありませんが、Windowsで通常読み込めないファイルシステム内に必要なファイルがある場合はアクセスできません。
仮想マシン上のSIFTの場合、物理ディスクとして認識できれば（fdiskで出てくれば）、ext3やext4などLinuxが対応しているファイルシステムであればマウント可能です。
※Windowsでも特定のソフトを導入すればext3等のファイルシステムにアクセス可能です。

#使用が想定されるケース
通常はWindowsマシンでフォレンジック調査、ログ解析などを行うが、時々LinuxのコマンドやSIFTに入っている各種ツールが使いたい場合に便利です。
保全したディスクイメージからタイムラインを作成する、メモリダンプをとりあえずvolatilityで見てみる、取り出したレジストリをパースするといった操作が簡単になります。
導入されているツールは公式サイト等を参照してください。

#おまけ
SIFTを導入したユーザの/home/<username>/Desktop/以下にSANSのポスターが配置されます。同じものは以下からダウンロード可能ですが、このポスターは個人的に好きです。特にEvil Huntのポスターは困ったときに役に立っています。
https://www.sans.org/posters/
DynamoDB 用の NoSQL Workbench を使用してみる

https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/workbench.settingup.html

DynamoDB に最適化された Workbench が AWS から提供されました。NoSQL Workbench は、ローカルに構築された DynamoDB にも対応しているので、 今まで aws cli でデータ確認していたところが、グラフィカルにデータを確認できるようになります。

今回は、DynamoDB Local に保存されたデータを NoSQL Workbench を使って確認してみたいと思います。

## セットアップ

**[Operation Builder]**を押下し**[Add connection]**を押下します。
![connection.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/780549/585ed45a-2fe1-7d7a-afc6-d1e194b9d90f.png)

モーダルが表示されるので、**[DynamoDB local]**を選択し、任意の[Connection name]を入力します。[Connection name]を入力したら**[Connect]**を押してコネクションを追加します。
![top.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/780549/529aef61-4ef3-a65f-292d-aa21747d6bb7.png)

コネクションが登録されると、Operation builder のトップ画面に表示されます。
![add-connection.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/780549/db1145d2-f220-7f04-b4f4-1118c283e9cc.png)

追加されたコネクションの**[Open]**を押下すると、データセットが表示されます。
![table-view.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/780549/322b5026-dac3-f824-4dec-f12e02d8607b.png)


## おわりに

NoSQL Workbench は、データのクエリだけでなく、Update や Delete 操作も行うことができます。さらに、データモデルの作成もできます。GUI で DynamoDB を操作できるので、DynamoDB のイメージがつかみやすくなるのではないでしょうか。
NDK at /Users/user.name/Library/Android/sdk/ndk/XX.X.XXXXX did not have a source.properties file エラーが発生する

# やりたいこと
Androidアプリをビルドしたい。

```
./gradlew build
```

# エラー文
以下のエラーが発生。

```
❯ ./gradlew build                                            

FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring project ':renderscript-toolkit'.
> com.android.builder.errors.EvalIssueException: NDK at /Users/user.name/Library/Android/sdk/ndk/21.3.6528147 did not have a source.properties file

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 1s

```

# 原因
対応するバージョンのNDKがインストールされていない。

# 解決策
## NDKのインストール
以下から、エラーログに記載されていたバージョンのNDKをインストールする。
https://developer.android.com/studio/projects/install-ndk#specific-version

## gradle build の実行
```
❯ ./gradlew build    
```
array配列同士の結合


pythonの画像認識の機械学習などで、画像をopencvで読み込ませるとarrayで返ってくる。
データ前処理などで、このarray同士で結合させる場面などはよくあるため、まとめておく。

#array配列同士の結合
ポイント
①numpyのnp.stackメソッドを使用する
②連結すると次元が一つ上がる 　
注意)連結する配列のshape(列数)は必ず一致している必要がある

```
import numpy as np

arr1 = np.arange(3) #array([0, 1, 2])
arr2 = np.arange(3, 6) #array([3, 4, 5])
arr3 = np.arange(6, 9) #array([6, 7, 8])
arr4 = np.arange(9, 12) array([ 9, 10, 11])

#  1次元同士の配列を横に重ねる(2次元になる)
arr5 = np.stack((arr1, arr2, arr3, arr4)) 
　　　　　#array([[ 0,  1,  2],
       　　　　 　[ 3,  4,  5],
       　　　　 　[ 6,  7,  8],
      　　　　 　 [ 9, 10, 11]])
arr5.shape #(4, 3)


arr6 = np.array([[ 3,  1,  2],
       　　　　　　[ 3,  4,  5],
      　　　　　　 [ 6,  7,  8],
     　　　　　　  [ 9, 10, 11]])

#  2次元同士の配列を横に重ねる(3次元になる)
arr7 = np.stack((arr5, arr6))

     　　#array([[[ 0,  1,  2],
       　　　　　  [ 3,  4,  5],
     　　　　　　  [ 6,  7,  8],
    　　　　　　   [ 9, 10, 11]],

   　　　　　　   [[ 3,  1,  2],
    　　　　 　    [ 3,  4,  5],
    　　　　 　    [ 6,  7,  8],
    　　　　 　    [ 9, 10, 11]]])

arr7.shape #(2, 4, 3)

```
【Ruby on Rails】RSpec実行時に意図しないログが吐き出された

# はじめに
今回の出来事に関しては具体的な原因の特定には至れておりません。
そのため、もし具体的な原因が知りたいという方にとっては参考にならない記事になっていること、予めご了承いただけますと幸いです。

# 環境

Ruby 2.6.5
Ruby on Rails 5.2.6

# RSpec実行時に大量のログが出た
オリジナルアプリの機能追加に伴い、RSpecでテストを実行したところ、以下の画像のように意図しないログが吐き出された。

![スクリーンショット 2021-09-07 22.04.28（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739857/73337491-d9ac-9041-5192-7c35b0073a62.png)

どうやら```before do ... end```のブロック内に囲まれたテストデータが作成された時のログのようだ。
(大量のテストデータを作成していてお恥ずかしい限りです。)

画像は一つの```describe```ブロック内のログであり、複数の```describe```ブロックを作成してテストしている場合、毎回このログが出力されるので、どこまでテストが行われているのかわからないし、何より時間がかかりすぎて効率が悪い。

※本来であれば以下のように結果が返ってくると思います。

![スクリーンショット 2021-09-11 23.36.39（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1739857/39afd685-9ce3-0fe3-085a-d6e1f8b23dec.png)

ということで原因を探ってみました。

# gemの```rails_12factor```が原因だった

```git log```を遡ったり、どこのブランチからこんなことになってしまっているのか一つ一つみているうちに、RSpecの実行結果が期待通りのリポジトリ内ではgemの```rails_12factor```がインストールされていなかった。

...そういえばHerokuにデプロイできなくて試しにインストールしていたことを忘れていた。

調べてみるとこのgem、最終リリース日が2014年10月14日であり、だいぶ古いgemであることがわかった。

[参考(RubyGems.orgより)](https://rubygems.org/gems/rails_12factor)

それに伊藤淳一さんも```rails_12factor```は使わない方が良いと仰られている。

[伊藤淳一さんの記事(【初心者必見】RailsアプリをHerokuに公開するのにrails_12factorは不要)](https://qiita.com/jnchito/items/54eb7b3df322fc86675e)

伊藤淳一さんの記事にも書かれていることだが、メンテナンスが止まっており、かつ必要のないgemに関してはインストールすべきではないという良い教訓になった出来事でした。

そのためにも、

・使おうとしているgemがどれほどの人が利用していて
・いつアップデートされて
・バグなどの報告はないか

をきちんと調べる習慣をつけたいと思います。

もし原因がわかる方がいらっしゃたらコメントを頂けますと幸いです。

以上
VB.NET勉強用サンプル集

## 前書き
今後仕事で必要そうなので、VB.NETも触っておくことにした。
とりあえず、今まで[WPF(C#)](https://qiita.com/devneko0510/items/fa9479d4854f52dc7738)で作成していたアプリ達をVBで再現してみようと思う。

## 作成済み（改良の余地しかない）

#### テストアプリ
　　単純計算およびバインディングテスト
　　[VBFormSample01](https://github.com/devneko94/VBFormSample01)
Azure 処理時間の長いAPIの応答が帰ってこない

#起こったこと
・クライアント(Pythonスクリプト)に、AzureVMに構築したAPIの応答が帰ってこない。
・サーバ側(VM)は正常に応答したログが記録されている。
・クライアントをcurlに変更すると何故か正常応答する。

#構成
・Pythonクライアント→インターネット→Azure NSG→VM NIC→Nginx→Glassfish→SpringBoot
・SpringBootはファイル生成処理が挟まる関係上、リクエスト受領後約5分後に応答を返す。

#結論
PublicIPのアイドルタイムアウト設定が初期値4分のままになっていたため。
これにより、4分間パケットのやり取りがないTCPコネクションがAzure側で掃除されていた。
アイドルタイムアウトを10分などに伸ばすと事象解消し正常にAPI応答が受領できるように。

下記がよくまとまっていたが、PublicIPのTCPアイドルタイムアウトが4分で固定と記載されている。
これは誤りで実際は4~30分で設定可能と思われる。
https://jpaztech.github.io/blog/network/snat-options-for-azure-vm/

VMのPublicIPに限らずApplicationGatewayのPublicIPや
LoadBalancer、NATGWなどSNATするもの全てでアイドルタイムアウト設定があるので、
応答に時間がかかるシステム構築では考慮が必要。

日本語の記事はあまり見当たらなかったが、英語だといくつかhitした。
https://docs.microsoft.com/en-us/answers/questions/152494/tcp-connections-dropped-after-approx-5-mins-of-ina.html

#調べたこと①
・Pythonクライアント→localhost(自分のノートPC)→Tomcat→SpringBootでリクエスト→応答あり
・Pythonクライアント→インターネット→Azure NSG→VM NIC→Glassfish→SpringBoot→応答なし
・Pythonクライアント→localhost→VM NIC(lo)→Glassfish→SpringBoot→応答あり
・Pythonクライアント→localhost→VM NIC(lo)→→Nginx→Glassfish→SpringBoot→応答あり
→なんとなくAzureが怪しい、、

#調べたこと②
クライアント側PCをwireshark、VM側をtcpdumpでパケットキャプチャを実施。
クライアント側は、httpsコネクションを受領後音沙汰なし。
netstatするとずっとコネクションはESTSABLISHEDのままとなっていた。

VM側は、コネクション確立後、約5分後正常にパケットを送信していたが、
ACKが帰ってこないため何度かリトライを実施(Azureではコネクションが消されているため)。
その後、FIN_WAIT1しRSTして切断していた。
→そりゃないコネクションにパケットを送っても届かないよね、、、

#調べたこと③
curlすると何故か応答が帰ってくる、、、？？
→wiresharkしたところ、何やらTCP　Keep-Aliveしている。
→そのためAzureでアイドルタイムアウトで消される対象にされず延命されていた。
→でもlinuxのデフォルトTCP　Keep-Aliveは7200秒(=2時間)で始まると聞いたぞ、、？？

```
sysctl -a | grep keepalive
```

でVMの設定を確かめるも、

```
net.ipv4.tcp_keepalive_time = 7200
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_keepalive_probes = 9
```
やはりデフォルトの2時間。


結果、curlの仕様を調べたらすぐに出てきました！
デフォルトで60秒おきにTCP Keep-Aliveしてくれるようです。

https://everything.curl.dev/usingcurl/timeouts
>Use --keepalive-time to specify how often in full seconds you would like the probe to get sent to the peer. The default value is 60 seconds.

ちなみに、linuxのtcp_keepalive_timeの設定値を180秒など短くすることでも本事象は解消できそう。
この辺はシステム特性に応じて検討が必要ですね。

#その他対処方法
Pythonのコード内でTCP Keep-Aliveを実装することもできそう。
通常のrequestsモジュールでは無理なのでsocketとかを使って書いていくみたい。
あまり深入りしなかったので、詳しくは分かりません。
https://www.programcreek.com/python/example/4925/socket.SO_KEEPALIVE

#参考
[TCP Keep-Alive/http Keep-Aliveの仕組みと違い](https://milestone-of-se.nesuke.com/nw-basic/as-nw-engineer/keepalive-tcp-http/)
[https通信をtcpdumpでキャプチャしてWiresharkする方法](https://oji-cloud.net/2019/11/05/post-3360/)
[Azure VM の外部接続 (SNAT) オプション まとめ](https://jpaztech.github.io/blog/network/snat-options-for-azure-vm/)
herokuで独自ドメインを使う方法（お名前.com編）

herokuで独自ドメインを使うときに色々悩んだのでその備忘録として記載しました
基本的には<a href="https://devcenter.heroku.com/ja/articles/custom-domains">公式ドキュメント</a>を読んでいくのが1番確実かと思います。
そこに各ドメインのサイト（今回だとお名前.com）の設定が入ってくる形です。

①ドメインを取得（特に問題ないと思うので省略）
　　　好きなドメインを選んで取得

②Heroku CLI コマンドを利用する
　　　まず以下のように打ちます
※www.example.comは取得した新規のドメイン
なぜwwwを入れるのかは先のページで

```
$cd projects //プロジェクトのあるフォルダへ移動
$heroku login
$heroku domains:add www.example.com
```

その後以下のコマンドを実行

```
$heroku domains                         
=== exampleapp Custom Domains
Domain Name      DNS Record Type DNS Target                                            SNI Endpoint      
www.example.jp CNAME           aaa-12345-aaaaaaa.herokudns.com testaaaa-123456 
```

ここのDNSTargetをメモしておく

③お名前.com側の設定
取得したドメインの設定画面にて
「DNS設定/転送設定」を選択
指定のドメインを選択
![スクリーンショット 2021-09-11 23.15.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633008/b75cfd09-5c65-ef58-5e09-da87dbde2278.png)

「DNSレコード設定を利用する」を選択
![スクリーンショット 2021-09-11 23.12.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633008/34f4444c-25e7-1fd8-1d1e-2759f62bddd9.png)


ページ中段にあるレコードの設定で「CNAME」を選択して先ほどコピーしたDNSTARGEをVALUEにコピー
![スクリーンショット 2021-09-11 23.12.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633008/c746559f-7ad7-c793-0359-3c2505467724.png)

ページの手順に従って設定を完了する
※この後数分から数時間またないと処理が完了しない場合があります。
（私は１０分ほどで完了しました）

④heroku側の設定
heroku側では料金プランが有料プランであればそのまま設定せずに設定したドメインで使えます

![スクリーンショット 2021-09-11 23.21.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633008/10189d97-ff31-38c5-0fd5-45a2b4643faf.png)

念の為herokuのコンソール画面→「settings」からSSLの設定がされているか確認します。
![スクリーンショット 2021-09-11 23.53.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633008/1db4bb0b-b682-eac4-99d8-9f1637735342.png)


きちんと設定が反映されているかターミナルで確認する場合は以下のコマンドです。
has adressの結果は環境によって行数が違うかもしれません

```
$host www.example.com
aaaaa-123456-aaaaa has adress ********
aaaaa-123456-aaaaa has adress ********
aaaaa-123456-aaaaa has adress ********
```

これで指定のドメイン（www.example.com）でherokuのアプリケーションが動きます。


<h1>追記</h1>
herokuのマニュアルだと次にカスタムルートドメイン
(www.example.comだけでなくexample.comでも使えるようにする)
の設定をするように書いてあります。しかしその注意書きで

```
一部の DNS プロバイダーでは、ルートドメインには ​A レコード​ しか使用できません。A レコードには静的 IP が必要なため、残念ながら、A レコードでは Heroku にルートドメインを対応付けることができません。
```

とあります。自分が調べた限りだとお名前.comはこの注意書きに該当するらしくAレコードのみの設定になります。
そのためカスタムルートドメインからの設定は不可となります。
（違っていたらすみません）
AWS S3のメモ

### はじめに
普段AWSのサービスであればS3（Simple Storage Service）は頻繁に使いますので、メモします。

https://aws.amazon.com/jp/s3/

S3,S3-select,S3 Glacier,S3 Glacier Deep Archive,S3 Intelligent-Tieringなど

### 可用性と耐久性
99.999999999% (9 x 11)というすごく良い数字は可用性だという誤解しやすいので、可用性と耐久性の違いを理解する必要があります。

#### 可用性
- S3 標準ストレージクラス: 99.99%
- S3 標準 – IA ストレージクラスおよび S3 Intelligent-Tiering ストレージクラス: 99.9%
- S3 1 ゾーン – IA ストレージクラス: 99.5%
- S3 Glacier および S3 Glacier Deep Archive クラス: 99.99%  ※SLA：99.9%

出典：https://aws.amazon.com/jp/s3/faqs/#Durability_.26_Data_Protection

#### 耐久性
- 99.999999999% (9 x 11：イレブンナイン)　※0.000000001% のオブジェクトの平均年間予測消失率に相当します

出典：https://aws.amazon.com/jp/s3/faqs/#Durability_.26_Data_Protection

### 各サービスの違い
#### 1. S3 標準
頻繁にアクセスするデータに一般的に使用される、あらゆるタイプのデータの汎用ストレージ

#### 2. S3 Intelligent - Tiering 
アクセスパターンが不明または変化するデータの自動コスト削減。高頻度と低頻度自動調整で料金節約

特にバージョニング機能が有効の場合はこの方式でよさそうです。

#### 3. S3 標準 - 低頻度アクセス 
ミリ秒単位のアクセスが必要な、長期保管だがアクセス頻度の低いデータの場合

#### 4. S3 1 ゾーン - 低頻度アクセス
ミリ秒単位のアクセスが必要な、再作成可能なアクセス頻度の低いデータの場合

#### 5. S3 Glacier 
1 分から 12 時間の取り出しオプションを使用した長期バックアップとアーカイブの場合(遅いが、料金安い)

#### 6. S3 Glacier Deep Archive 
1 年に 1〜2 回アクセスされ、12 時間以内に復元できる長期のデータアーカイブの場合(S3 Glacierよりもっと遅い、もっと安い)

料金詳細：https://aws.amazon.com/jp/s3/pricing/

### S3 selectでファイルダウンロードなしで中身確認
Query with S3 Selectを使って、CSV・JSONで簡単で検索できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346425/6caaafbf-88d1-fa43-22a7-18c849922baf.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346425/835dbf25-c8f7-f23b-fd67-f4c2f780c41f.png)

以上
STM32L010のMbedでのHT16K33(I2C)でナイトライダー HAL


1.SCLとSDAを接続、プルアップも忘れずに
2.電源の接続
3.下記のソースコードを書き込む
4.コンパイル実行で表示されたら終了
5.おわり

注意
mbedのリビジョンは、143


![h_con63.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/ddd77768-4411-ffe3-eeb3-def8fff4e758.jpeg)




https://moons.link/post-266/


```c++

#include "mbed.h"

#define ADDR        (0x70<<1)  //  address

int main() {

    __HAL_RCC_GPIOA_CLK_ENABLE();
    
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF1_I2C1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    GPIO_InitStruct.Pin = GPIO_PIN_4;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    __HAL_RCC_I2C1_CLK_ENABLE();


    I2C_HandleTypeDef hi2c1;

    hi2c1.Instance = I2C1;
    hi2c1.Init.Timing = 0x00000708;
    hi2c1.Init.OwnAddress1 = 0;
    hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c1.Init.OwnAddress2 = 0;
    hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
    hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    HAL_I2C_Init(&hi2c1);    
    
    HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE);

    HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0);

    uint8_t buf[16];

    buf[0]=0x21;
    HAL_I2C_Master_Transmit(&hi2c1, ADDR, buf, 1, 3000);wait_ms(1);

    buf[0]=0x81;
    HAL_I2C_Master_Transmit(&hi2c1, ADDR, buf, 1, 3000);wait_ms(1);

    buf[0]=0xef;
    HAL_I2C_Master_Transmit(&hi2c1, ADDR, buf, 1, 3000);wait_ms(1);

    for(int ii=0;ii<16;ii++){
        buf[0]=ii;
        buf[1]=0x00;
        HAL_I2C_Master_Transmit(&hi2c1, ADDR, buf, 2, 3000);wait_ms(1);
    }//for
    
    while(1) {
            
        for(int ii=0;ii<8;ii++){

            buf[0]=0;
            buf[1]= (1<<ii);
            HAL_I2C_Master_Transmit(&hi2c1, ADDR, buf, 2, 3000);wait_ms(600);

            HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
            wait(0.2);
            HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
            wait(0.2);

        }//for
    }//while
}//main



```
リージョン、アベイラビリティゾーンについて

#リージョン、アベイラビリティゾーンについて


リージョン、アベイラビリティゾーンとは以下のようにAWSが所有する
データセンターの集合体の分ける単位のことを指す。


##リージョン(regionとは)
世界をリージョンという単位で区切っており、その単位。
各リージョンは以下記載するAZを2つ以上配置されている。

##アベイラビリティゾーン(Availability Zone : AZ)とは
アベイラビリティゾーンとはリージョン内における複数のデータセンターの集合体を指す。


##リージョンの特徴
リージョンとリージョンの間は完全に分離されており、あるリージョンで
障害が発生した場合も他のリージョンのリージョンへは影響がない

##アベイラビリティゾーンの特徴
アベイラビリティゾーンもリージョンと同様に地理・電源・ネットワークが独立した施設で
構成されているが各AZ間は冗長化された高速なネットワークで接続されている。

そのため同じリージョン内であればアベイラビリティゾーン間でデータを複製したり、
別のアベイラビリティゾーンのリソースを参照することができる。

##可用性を高める仕組みについて
以上の特徴により、複数のアベイラビリティゾーンにリソースを配置することで
可用性を高めることができる。

ただしリージョン全体へ影響する部分に障害が発生した場合にはそのリージョン配下の
全てのアベイラビリティーゾーンに影響が及ぶ恐れがある。

そのため同一リージョンの複数のアベイラビリティーゾーンでシステムを構成するよりも、
複数リージョンでシステムを構成する方がより可用性は高くなる。

##イメージ図
![リージョン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/964073/683f8ce3-a789-26f5-d5ee-62a1c71110e6.png)
GUI有効なLinux環境で、複数のNICを有効にする

　タイトル通りなのですが、複数のNIC（ネットワークインターフェイス）が有効なマシンにGUI有効なLinux環境を構成し、NICの状態を確認すると以下のようになったりします。

```bash:NICの状態の確認
root@debian11:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:cb:4c:49 brd ff:ff:ff:ff:ff:ff
    inet 192.168.56.112/24 brd 192.168.56.255 scope global dynamic noprefixroute enp0s3
       valid_lft 555sec preferred_lft 555sec
    inet6 fe80::a00:27ff:fecb:4c49/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:72:0c:a0 brd ff:ff:ff:ff:ff:ff
 → enp0s3、enp0s8の2つのNICが認識されている

root@debian11:~# nmcli connection show
NAME                UUID                                  TYPE      DEVICE
Wired connection 1  a0195015-9413-4d5c-ba5f-56d2eb6850fe  ethernet  enp0s3
 → nmcliでコネクション情報を表示すると、片方しか表示されない
```

認識されていない方のNICについては、コネクション情報を追加します。

```bash:コネクション情報の追加
root@debian11:~# nmcli connection add type ethernet ifname enp0s8 con-name enp0s8
接続 'enp0s8' (b653076d-48c4-4b2f-a49c-5d7238a81f7a) が正常に追加されました。
 → コネクション情報が追加される

root@debian11:~# nmcli connection show
NAME                UUID                                  TYPE      DEVICE
enp0s8              b653076d-48c4-4b2f-a49c-5d7238a81f7a  ethernet  enp0s8
Wired connection 1  a0195015-9413-4d5c-ba5f-56d2eb6850fe  ethernet  enp0s3
 → enp0s8が追加されていることを確認
```

:::note info
構文の説明：コネクション情報の追加
nmcli connection add type ネットワークの種類 ifname NIC名 con-name コネクション名
:::

　これで複数のNICが利用できるようになるのですが、さらに既定で認識したコネクションの名前（Wired connection 1）をNICの名前と同じになるように変更します

```bash:コネクション名の変更
root@debian11:~# nmcli connection modify 'Wired connection 1' connection.id enp0s3
 → コネクション名Wired connection 1をenp0s3に変更

root@debian11:~# nmcli connection show
NAME    UUID                                  TYPE      DEVICE
enp0s8  b653076d-48c4-4b2f-a49c-5d7238a81f7a  ethernet  enp0s8
enp0s3  a0195015-9413-4d5c-ba5f-56d2eb6850fe  ethernet  enp0s3
```

:::note info
構文の説明：コネクション名の変更
nmcli connection modify 既存のコネクション名 connection.id 変更後のコネクション名
※コネクション名にスペースを含む場合、クォーテーションで囲んで指定
:::

　これでどちらのNICもnmcliコマンドで制御できるようになり、かつ「nmcli connection modify NIC名...」で設定内容を変更できるようになります。
　例えば、enp0s3に割り当てられるIPv4アドレスを固定のものにするには、以下の構文を実行します。

```bash:IPv4アドレスを固定のものに割り当て
nmcli connection modify enp0s3 ipv4.address '192.168.56.22/24'
nmcli connection modify enp0s3 ipv4.method 'manual'
```
binance future api positionがlongかshortか取得方法

### やりたいこと
binance future api使って現在入ってるポジションがlongかshortか取得する

##binance future api使えるように設定

```python
import ccxt
binance = ccxt.binance(config={
    'apiKey': env("API_KEY"),
    'secret': env("API_SECRET"),
    'enableRateLimit': True,
    'options': {
        'defaultType': 'future'
    }
})
```


## long, short区別方法
```python
balance = self.binance.fetch_balance()
positions = balance['info']['positions']
for position in positions:
    if position["symbol"] == self.pair:
        print(float(position['positionAmt']))
        if float(position['positionAmt']) > 0:
        	# LONGで、ETH 0.010で入った場合、0.010が入る
        	print("LONG")
        if float(position['positionAmt']) < 0:
        	# SHORTでETH 0.010で入った場合、-0.010が入る
        	print("SHORT")
        if float(position['positionAmt']) == 0:
        	# どちらも入ってない場合、0.0が入ってくる
        	print("NONE")
```

### position 情報
```json
for position in positions:
    if position["symbol"] == 'ETHUSDT':
        pprint.pprint(position)

{'entryPrice': '0.0',
 'initialMargin': '0',
 'isolated': False,
 'isolatedWallet': '0',
 'leverage': '1',
 'maintMargin': '0',
 'maxNotional': '9.223372036854776E18',
 'notional': '0',
 'openOrderInitialMargin': '0',
 'positionAmt': '0.000',
 'positionInitialMargin': '0',
 'positionSide': 'BOTH',
 'symbol': 'ETHUSDT',
 'unrealizedProfit': '0.00000000',
 'updateTime': '1631366894068'}

```

## こんな面倒なやり方で、自分が入ってるpositionがlongかshortかを区別する理由
position情報は取得できるが、binanceでは、position sideは返してくれないから