OmniAICreator/Qiita-1.07M huggingface dataset:
NervesのIExをカスタマイズしたい

NervesのIExをカスタマイズして色んな情報を表示できたらもっと便利になるのではないでしょうか？

![customizing-iex-in-nerves 2021-05-08 at 11 06 14 AM](https://user-images.githubusercontent.com/7563926/117544080-9e20ed00-afed-11eb-9e1c-033afa8ede3b.gif)


## TL;DR

- [Nerves](https://www.nerves-project.org/)プロジェクト内の`rootfs_overlay/etc/iex.exs`ファイルを探す。
- `rootfs_overlay/etc/iex.exs`で自由にElixirプログラミングを楽しむ。

これは一例です。

```elixir
NervesMOTD.print()

# Add Toolshed helpers to the IEx session
use Toolshed

# I2Cの接続状況を表示
if Code.ensure_loaded?(Circuits.I2C) do
  IO.puts("")
  Circuits.I2C.detect_devices()
end

# お天気情報を表示
try do
  IO.puts("")
  weather()
rescue
  _e -> nil
end

# エイリアスを定義しておくと便利かも
alias HelloNerves.Worker
```

- `rootfs_overlay/etc/.iex.exs`で好きなようにElixirプログラミングするだけです。
- [Toolshed](https://hexdocs.pm/toolshed/Toolshed.html)の関数に便利なものがいくつかあります。（例、`weather/0`、`uname/0`）
- `Circuits.I2C.detect_devices/0`を呼んで、接続されているI2C周辺機器を表示すると便利な場合があるかもしれません。
- IExでよく使うモジュールを予め`alias`しておけば、後々楽になるかもしれません。
- `weather/0`を使用する上での注意点としては、インターネット接続が必要なことと、[`:inets`](http://erlang.org/doc/man/inets.html)が`mix.exs`ファイルの`extra_application`に含まれている必要があることです。
- 万一`.iex.exs`実行時にでエラーが発生した場合、エラー以降の処理が実行されないので注意が必要です。

```elixir:lib/hello_nerves/application.ex
def application do
  [
    mod: {HelloNerves.Application, []},
    extra_applications: [:logger, :runtime_tools, :inets]
  ]
end
```

## Elixirの`.iex.exs`ファイル

IExが起動するときに読み込まれるファイルです。詳しくは[IExドキュメント](https://hexdocs.pm/iex/IEx.html#module-the-iex-exs-file)をご覧ください。

## Nervesの`.iex.exs`ファイル

[`.iex.exs`ファイルのテンプレート](https://github.com/nerves-project/nerves_bootstrap/blob/main/templates/new/rootfs_overlay/etc/iex.exs)は、[nerves_bootstrap](https://hexdocs.pm/nerves_bootstrap)リポジトリーにあります。

## More info

おーはらさんのスライドに日本語で包括的に説明されています。Awesome!
https://twitter.com/ohrdev/status/1474968395087237121

:tada::tada::tada:

https://join.slack.com/t/elixirjp/shared_invite/zt-ae8m5bad-WW69GH1w4iuafm1tKNgd~w

https://autoracex.connpass.com/
ARFoundation 複数のImageに別のキャラを表示する

Imageを設定し、サイズを調整する
![2043B1CB-E53E-49D9-ADE5-55D65F3EADD7.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/55c0fc9c-3f5d-84f2-c04c-b76525ccad3c.jpeg)

Characterのサイズを合わせる
![59C8A8A9-93DC-4C7E-B424-431F1109454A_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/75400f71-43eb-c65a-23c3-1904bf055236.jpeg)

```C#:ImageManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;

public class ImageManager : MonoBehaviour
{
    //イメージトラッキングの結果を取得するためのクラス
    ARTrackedImageManager m_TrackedImageManager;

    //画像に重ねて表示するPrefabのList
    [SerializeField]
    private List<GameObject> prefabs;

    void Start()
    {
        //GameObject にアタッチされている ARTrackedImageManager を取得
        m_TrackedImageManager = GetComponent<ARTrackedImageManager>();

        //ARTrackedImage の変更時に実行する関数をセット
        m_TrackedImageManager.trackedImagesChanged += OnTrackedImagesChanged;
    }

    //ARTrackedImageの変更時に実行される関数
    void OnTrackedImagesChanged(ARTrackedImagesChangedEventArgs eventArgs)
    {
        //新たに追加(検知)された画像に対して実行
        foreach (var trackedImage in eventArgs.added)
        {
            //ReferenceImage の Name が"image1"の画像に対する処理
            if (trackedImage.referenceImage.name == "image1")
            {
                //検知した画像を parent にして、Prefab から GameObject を作成する
                Instantiate(prefabs[0], trackedImage.transform);
            }
            //ReferenceImage の Name が"image2"の画像に対する処理
            if (trackedImage.referenceImage.name == "image2")
            {
                //検知した画像を parent にして、Prefab から GameObject を作成する
                Instantiate(prefabs[1], trackedImage.transform);
            }
        }
    }
}
```

ARSessionOriginのARTrackedImageManagerの値を変更し、ImageManager.csをアタッチして、プレハブをアタッチする
![9A0DDFA3-66EE-4399-B9C3-8DFFD5B41546.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/269d6210-f443-872e-b8d0-cdef8d678b1b.jpeg)
【algorithm】アルゴリズムまとめ

#はじめに
アルゴリズムの記事をまとめていこうと思います

#algorithm

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

https://qiita.com/REON/items/968b8cbb6c1eec5aa0af

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

https://qiita.com/REON/items/93fbbb49ebea477fa88f

https://qiita.com/REON/items/7a9436c5da7c8900e524

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

https://qiita.com/REON/items/4795590653c38b0b3d1f

https://qiita.com/REON/items/31a60f74dbc2b8d9e6e0




#おわりに
アルゴリズム楽しい！
wordpressの公開URLを変更したい方､ご注意！巷の誤情報に惑わされないでください｡

<h1> 結論

wordpressの公開URLを変更したいと思い､ググって色々実施したものの､どうも上手くいかない｡｡｡

そんなあなた､もしまだ以下を試していなければ､試してください｡

wp-config.phpでの定義を以下の通り変更｡(URLご自身のものに変えてくださいね)
define( 'WP_SITEURL', 'http://example.com/wordpress/wp' );
→こっちが､管理ファイルのアドレス｡
define( 'WP_HOME', 'http://example.com/wordpress' );
→こっちが､公開URL

…僕はこれで解決しました｡
本当にコンテンツSEOの弊害だと思うのですが､巷に流れている解説記事には､殆どが(僕が確認した限りではすべてが)
上記について逆で書かれています｡
まぁ､公式の詳細まで確認しない僕も行けないのですが､､､｡

<h2>詳細(公式から引用｡)

日本語的に､SITEURLとHOMEって､意味合いが逆のように思ってしまうんですよね｡
しかもどの記事もそういうふうに記載しているから､そりゃそう思い込んでしまう｡
でも､逆でした｡

<h3>WP_SITEURL #WP_SITEURL

WP_SITEURL は WordPress アドレス (URL) を定義します。
<h6>ここで定義する値は、WordPress のコアファイルが存在する URL です。 

http:// の部分は含める必要があります。最後のスラッシュ “/” は含めないでください。 wp-config.php でこの値を設定すると、 wp-options テーブルの値よりも優先されます。これを追加することで、サイトを読み込む時のデータベースの呼び出し回数を減らすことができます。
ドメイン名 example.com の wordpress ディレクトリに WordPress がインストールされている場合、 WP_SITEURL を次のように指定します。
define( 'WP_SITEURL', 'http://example.com/wordpress' );

<h3>ブログのアドレス (URL) #ブログのアドレス (URL)

WP_HOME は WP_SITEURL と同様に wp_opsions テーブルの値よりも優先されますが、データベースの値は変更されません。
<h6>home は WordPress にアクセスするためにユーザーがブラウザに入力するアドレスです。

http:// の部分は含める必要があります。最後のスラッシュ “/” は含めないでください。 これを追加することで、サイトを読み込む時のデータベースの呼び出し回数を減らすことができます。
define( 'WP_HOME', 'http://example.com/wordpress' );

<h3>公式

https://ja.wordpress.org/support/article/editing-wp-config-php/
ルーティングについて(Laravelでウェブアプリを作ろう)


###ルーティングとは
特定のアドレスにアクセスした時、どの処理を呼び出して実行するか。それを管理するのが「ルーティング」です。実際の処理が記載されているというよりあくまでどの処理かの紐付けを行なっているだけです。具体的に実行すべき処理は「コントローラー」に記載されています。

####前提条件
プロジェクトの作成が終わっている状態
まだ作成できていない方は[こちら](https://qiita.com/kunrenyouAcount/items/ef790c5ead01e2a88297)

####実際のアプリでは
プロジェクトの作成が完了すると以下のコマンドでサーバーを立ち上げてアプリを使うことができます。

```terminal:サーバーの起動(ターミナル)
php artisan serve
```

実行後に表示されるURLをブラウザで開くとLaravelのページが表示されると思います。
これはアプリ内の``resouces/views/welcome.blade.php``が表示されている状態です。
このファイルを開く、という指定は``routes/web.php``内に記載されています。

```php:デフォルト(routes/web.php)
<?php
use Illuminate\Support\Facades\Route;

//ここで「welcome」の指定がある
Route::get('/', function(){
    return view('welcome');
});

```

view関数で指定することで、自動的にresouces/views内のファイルという指定がされるというわけです。
例えば、view関数でファイルを分けずにweb.php内に直接htmlを記述することも可能です(本来はこういう使い方をすることはないが、動きの理解として。)

```php:view関数を使わずにべた書き(routes/web.php)
Route::get('test', function () {
   return '<html><body><h1>Hello</h1><p>This is sample page.</p></body></html>';
}
```

サーバーの起動後``http://localhost:8000/test``に接続すると記述した内容が表示されていることがわかる。

他にリクエストされた時のパラメーターを利用する方法もある。

```php:必須パラメーターの利用(routes/web.php)
Route::get('test/{str}', function ($str) {
   return '<html><body><h1>Hello</h1><p>This is sample page.</p><p>{$str}</p></body></html>';
}
```

サーバーの起動後``http://localhost:8000/test/好きな単語``に接続すると好きな言葉に記載した内容が表示されていることがわかる。上記のパラメーターは「必須パラメーター」というもので記載しないとエラーになります。対して「任意パラメーター」の書き方は以下のように``「？」をつける``＋``デフォルト値を設定する``だけです。

```php:任意パラメーターの利用(routes/web.php)
Route::get('test/{str?}', function ($str='no contents.') {
   return '<html><body><h1>Hello</h1><p>This is sample page.</p><p>{$str}</p></body></html>';
}
```
【ゼロからのOS自作入門】WSLでHelloWorldするまで

## はじめに
ゼロからのOS自作入門を買いました。
壊れても良いノートPCが手元になかったため、WSLを使ってOS起動しようとしましたが
第一章のハローワールドから結構詰まってしまったので、上手くいった手順を書き残しておきます。

## 環境
* Windows10
* WSL2（Ubuntu）

## 手順
### WSL2をセットアップする
書籍の「付録A 開発環境のインストール」の「A.01 WSLのインストール」と「A.02 WSLでQEMUを使う準備」を手順通りに行います。
ここは私の環境では特に問題なく完了しました。

### Ubuntuをインストールする
Microsoft Storeを開いてUbuntuをインストールします。
検索するといくつか候補がでますが、私は一番上をインストールしました。
![store.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130234/5a3e6073-2eb4-49f0-a961-efb9a3812f25.png)
インストールが完了し、Ubuntuを起動するとコンソール画面が表示されます。（GUIで表示されるものと思っていたため少し戸惑いましたが、WSLはGUI表示に対応していないそうですね・・）

コンソールでユーザー名とパスワードを設定するよう言われるので、それに従います。

### ハローワールドする
ここから本題の「Hello, World!」を表示するOSを立ち上げます。
まず初めに、書籍ではバイナリエディタでプログラムを写経することがオススメされていましたが、そこで詰まりそうだったためサポートサイトで提供されている完成ファイルを使用しています。

#### 環境構築
Ubuntuのコンソールでプログラムをエミュレートするための環境を構築します。
私はここで詰まったのですが、書籍ではなくサポート用のGithubに手順が記載されています。

https://github.com/uchan-nos/mikanos-build

まず、「ビルド環境の構築 > リポジトリのダウンロード」を行います。
Ubuntuのコンソールで下記コマンドを順番に実行します。

```
$ sudo apt update
$ sudo apt install git
$ cd $HOME
$ git clone https://github.com/uchan-nos/mikanos-build.git osbook
```

lsコマンドでosbookディレクトリができているのが確認できました。
続いて、「ビルド環境の構築 > 開発ツールの導入」を行います。
Ubuntuのコンソールで下記コマンドを順番に実行します。

```
$ sudo apt install ansible
$ cd $HOME/osbook/devenv
$ ansible-playbook -K -i ansible_inventory ansible_provision.yml
```

しばらく待つと、処理が完了して入力可能な状態になりました。
![console01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130234/a440f7dc-6fa9-8413-e7b8-87dfc272fa35.png)
lsコマンドでedk2というディレクトリができているのが確認できます。
続いて、もしかすると不要かもしれませんが手順に記載されている下記コマンドも実行しました。

> セットアップが上手くいけば `iasl` というコマンドがインストールされ，`$HOME/edk2` というディレクトリが生成されているはずです。 これらがなければセットアップが失敗しています。

```
$ iasl -v
$ ls $HOME/edk2
```

> WSL 上の Ubuntu で上記のコマンドを実行すると，`$HOME/.profile` に `DISPLAY` 環境変数の設定が追加されます。 この設定を有効にするにはターミナルを再起動するか，次のコマンドを実行する必要があります。

```
$ source $HOME/.profile
```

#### ハローワールド プログラムの実行
書籍に戻り、「1.4 エミュレータでのやり方」を進めていきます。
まず、ハローワールドプログラムをDLします。（本当は写経すべきですが）
Ubuntuのコンソールで下記実行します。

```
$ curl -O https://raw.githubusercontent.com/uchan-nos/mikanos-build/master/day01/bin/hello.efi
```

lsコマンドで「hello.efi」というファイルをDLできたのが確認できます。
続いて、ディスクイメージ作成のために下記を実行します。

```
$ qemu-img create -f raw disk.img 200M
$ mkfs.fat -n 'MIKAN OS' -s 2 -f 2 -R 32 disk.img
$ mkdir -p mnt
$ sudo mount -o loop disk.img mnt
$ sudo mkdir -p mnt/EFI/BOOT
$ sudo cp hello.efi mnt/EFI/BOOT/BOOTX64.EFI
$ sudo umount mnt
```

lsコマンドで「disk.img」というファイルができたのが確認できます。
続いて、ディスクイメージをQEMUで起動するために下記を実行します。

```
$ qemu-system-x86_64 -drive if=pflash,file=$HOME/osbook/devenv/OVMF_CODE.fd -drive if=pflash,file=$HOME/osbook/devenv/OVMF_VARS.fd -hda disk.img
```

QEMUのウィンドウが立ち上がり、「Hello, world!」が表示されました！
![console02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130234/1316fbcb-6264-0314-36ea-5268464a46cd.png)
![hello_world.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130234/2b7950be-9c83-ef2b-2e20-3c16c11cadbf.png)

## 終わりに
冒頭から詰まって心折れそうになりましたが、何とかハローワールドすることができました。
今後も詰まりまくる予感がしていますが、折れずに続けていきたいなと思います。

## 参考サイト
https://zenn.dev/karaage0703/scraps/b2705131673377
Angular ソース構造メモ

備忘録

シンプルなやつ

# 用語メモ

| 用語 | 説明 |
| :-: | :-- |
| モジュール | Angularアプリの構成部品を束ねる<br>コンポーネントやサービスを内包する<br>起動時に呼び出されるモジュールをルートモジュール or メインモジュールと呼ぶ  |
| コンポーネント | ページを構成するUI部品を定義する |
| デコレーター | クラスやプロパティ、メソッド、引数に対して構成情報を付与するための仕組み |


- モジュール: Angularアプリの構成部品を束ねる
コンポーネントやサービスを内包する
起動時に呼び出されるモジュールをルートモジュール or メインモジュールと呼ぶ。
コンポーネント: 


## 画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404257/a4fe79bf-6d63-50ad-9edc-98c7df3d727c.png)

## ソース
~~~Index.html
<!DOCTYPE html>
<html>
  <head>
    <title>Angular QuickStart</title>
    <base href="/">
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="styles.css">

    <!-- Polyfill(s) for older browsers -->
    <script src="node_modules/core-js/client/shim.min.js"></script>

    <script src="node_modules/zone.js/dist/zone.js"></script>
    <script src="node_modules/systemjs/dist/system.src.js"></script>

    <script src="systemjs.config.js"></script>
    <script>
      System.import('main.js').catch(function(err){ console.error(err); });
    </script>
  </head>

  <body>
    <!-- このmy-appに挿入される -->
    <my-app>Loading AppComponent content here ...</my-app>
  </body>
</html>

~~~

~~~app.module.ts
import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";

import { AppComponent } from "./app.component";
import { AppComponentDetail1 } from "./app.component_detail1";
import { AppComponentDetail2 } from "./app.component_detail2";

@NgModule({
  //imports: 現在のモジュールで利用する他のモジュール
  imports: [BrowserModule],
  // declarations: 現在のモジュールに属するコンポーネント
  declarations: [AppComponent, AppComponentDetail1, AppComponentDetail2],
  // アプリで最初に起動すべき最上位のコンポーネント
  bootstrap: [AppComponent],
})
export class AppModule {}

~~~


~~~app.component.ts

import { Component } from "@angular/core";

@Component({
  // selector: コンポーネントを適用すべき要素を表すセレクター式
  selector: "my-app",
      // template: コンポーネントを適用すべきビュー
  template: `
    <h1>Hello {{ name }}</h1>
    <div>
      <my-app-detail1>...1</my-app-detail1>
      <my-app-detail2>...2</my-app-detail2>
    </div>
  `,
})
export class AppComponent {
  name = "Angular";
}

~~~
~~~app.component_detail1.ts
import { Component } from "@angular/core";

@Component({
  selector: "my-app-detail1",
  template: `<p>Detail-1</p>`,
})
export class AppComponentDetail1 {}

~~~
~~~app.component_detail2.ts
import { Component } from "@angular/core";

@Component({
  selector: "my-app-detail2",
  template: `<p>Detail-2</p>`,
})
export class AppComponentDetail1 {}

~~~


## 仕組み

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/404257/7c2e1d06-1171-da1a-6878-24c53745ac49.png)

app-moduleは各コンポーネントとルートモジュールを定義している
【AtCoder解説】python ABC200 (提供：京セラ様) A,B,C,D

https://atcoder.jp/contests/abc200

#A問題
100で割って割り切れるならそれが答え、そうでなければ切り上げ(100で割った商+1)を行う。

```python:Answer
N=int(input())
# 100で割った余りで分類
# 割り切れる
if N%100==0:
    print(N//100)
# 割り切れない
else:
    print(N//100+1)
```

またはmathのceil関数を使うと切り上げを勝手にやってくれる。

```python:Answer
import math
N=int(input())
print(math.ceil(N/100))
```

#B問題
問題文をそのまま実装する。
200を付け足すというのは文字列にしてから処理すると簡単。

```python:Answer
N,K=map(int, input().split())

for i in range(K):
    # もし200で割り切れるなら
    if N%200==0:
        N//=200
    # 200で割り切れないなら
    else:
        # 文字列にする
        N=str(N)
        # 200を後ろに付け足す
        N=N+"200"
        # 数値に戻す
        N=int(N)
print(N)
```

#C問題
全部の組を見るとO(N^2)になって間に合わない。
まず200の倍数になる＝200で割り切れると変換
ai-ajが200で割り切れるということはai,ajを200で割ったあまりは同じはず。
(401と201は401-201=200で200で割り切れる。あまりだけ見ると401%200=1、201%200=1で同じ)
なので同じ余りの組は何個作れるか？と聞いている。
例えば余り10の数がAの中に5個あったら([210 , 410 , 610 , 810 , 1010])、組み合わせ5C2=(5*(5-1))/2で10組作れる。
手順としては
1. Aの要素を200で割った余りを計算し、余り0,1,2,...,199となる数がそれぞれ何個あるのかカウントする。
2. それぞれについて組をいくつ作れるか計算
という形。

```python:Answer
N=int(input())
A=list(map(int, input().split()))

# 余りが0,1,2,...,199までそれぞれ何個あるのかを格納するリスト
amari_list=[0]*200

for i in A:
    # 余りを計算
    amari=i%200
    # 余りをカウント
    amari_list[amari]+=1

ans=0

for i in amari_list:
    # 2つ以上あるなら
    if i>=2:
        # iC2=(i*(i-1))//2)が余りを作ることができる組の数
        ans+=(i*(i-1))//2

print(ans)
```

#D問題
要するにAから適当に何個か持ってきた組を2つ作り、それを足した結果がmod200で同じになるようにしろということ。
全部の組は2^200通りあるので間に合わない。
しかしよくよく考えると余りは0~199まで200通りしかないので、201個のパターンを作れば絶対に一組は同じ余りになるものが存在する。
Noとなるのはそもそも201通り作れない場合にしか存在しない。(N=<7)
具体的にはbit探索で201パターンの余りを計算、その作り方を連想配列(dict)に保存。重複が出たら復元して出力する。


```python:Answer
N=int(input())
A=list(map(int, input().split()))
dic=dict()

# Nが7以下の場合は1~2^Nだけ探索して終わるように
# 8以上の場合は201組作るだけでよい
for i in range(1,min(2**N,202)):
    goukei=0
    # bit探索
    for shift in range(N):
        if i>>shift & 1 ==1:
            goukei+=A[shift]
    # 合計を200で割った余りに変換
    goukei%=200
    # もし初めて出た余りなら
    if goukei not in dic:
        # キーを余り、値をbitの値にして保存しておく
        dic[goukei]=i
    # すでに出たことのある余りなら
    else:
        # 入力例1なら
        # A1のみ＝00001=1=b
        b=dic[goukei]
        # A3とA4=01100=12=c
        c=i
        b_list=[]
        c_list=[]

        for shift in range(N):
            # 復元する
            if b>>shift & 1==1:
                b_list.append(shift+1)
            if c>>shift & 1==1:
                c_list.append(shift+1)
        print("Yes")
        print(len(b_list),*b_list)
        print(len(c_list),*c_list)
        exit()
        
print("No")
```
Railsの多対多の関係でのレコード追加について

## 何をしたか
Railsで多対多の関係もモデルがあった時に、レコード追加をどうできるのかが気になったため試しました。

## 今回の例
今回は下記のモデルを使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1057421/61e41094-1438-b3e7-8af0-2c34dfedbf93.png)

```ruby:movie.rb
class Movie < ApplicationRecord
  has_many :movie_tags
  has_many :tags, through: :movie_tags
  accepts_nested_attributes_for :tags
end
```

```ruby:tag.rb
class Tag < ApplicationRecord
  has_many :movie_tags
  has_many :movies, through: :movie_tags
  accepts_nested_attributes_for :movies
end
```

```ruby:movie_tag.rb
class MovieTag < ApplicationRecord
  belongs_to :movie
  belongs_to :tag
end
```

## レコード追加をしてみる
まずは既存のtagに紐づくmovieのレコードを追加したいと思います。

```ruby
Tag.find_by(name: 'ジブリ').movies.create(title: 'もののけ姫')

Tag.find_by(name: 'ジブリ').movies.pluck(:title)
#=> ['もののけ姫']
```
問題なくできました。

次はtagとそれに紐づくmovieを同時にレコードを追加してみます。

```ruby
Tag.create(name: 'ピクサー', movies_attributes: [{title: 'カーズ'}, {title: 'トイ・ストーリー'}])

Tag.find_by(name: 'ピクサー').movies.pluck(:title)
#=> ["カーズ", "トイ・ストーリー"]
```
こちらも問題なくできました。

もちろん逆にmovieとそれに紐づくtagを同時にレコードを追加する場合もできました。

```ruby
Movie.create(title: '君の名は。', tags_attributes: [{name: '青春'}, {name: '新海'}])

Movie.find_by(title: '君の名は。').tags.pluck(:name)
#=> ["青春", "新海"]
```

中間テーブルがあるのに、中間テーブルを意識せずにレコードを追加できるのでとても使いやすいなと思いました。

## 参考
https://railsguides.jp/association_basics.html#has-many-through%E9%96%A2%E9%80%A3%E4%BB%98%E3%81%91
Pythonで特定の国を特定の色で分類したインタラクティブな世界地図を作る (folium)

# はじめに

Pythonで地図の描画によく使われるであるfoliumで、グループAの国は赤色でグルーブBの国は青色で塗り分けたみたいな地図を作るのはどうしたらいいんだろう...となったのでまとめさせていただきます

ちなみに以下の図のような地図にしてHTMLに出力することができます

- スクリーンショット
![スクリーンショット 2021-05-02 2.52.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638747/5e3468ad-a698-b465-2c4b-c25670e2abb8.png)

- 出力されたHTML

https://sentencebird.github.io/onion-and-green_onion/negi_tamanegi_map.html

- （ちなみにこの記事書くのに使いました）

https://note.com/hogenosuke/n/n9939059b4c6c

# foliumで作れる地図

依存ライブラリ

```
folium==0.11.0
geopandas==0.9.0
```

以下の記事のようにコロプレス図と呼ばれる大小関係（eg: 都道府県別の新規コロナウイルス感染者数の日本地図）を表す地図は`Choropleth`というメソッドでmapオブジェクトに表示できるようです。この場合、どの国がどの色になるのかは連続的な（シーケンシャルな）カラーマップと対応する値で自動で決まります。しかしこれではカテゴリごとの色分けは不可能です

https://techray.hatenablog.com/entry/2019/12/16/200248

そこでたどり着いたのが次の記事で、この実装の国を各カテゴリに色分けしている部分のみを取り出して紹介したいと思います

https://towardsdatascience.com/visualizing-global-status-of-covid-19-using-folium-52797b5dcc19

# geopandasから国境のJSONを読んでfoliumで表示
```python
import folium
import geopandas as gpd

gdf = gpd.read_file('https://raw.githubusercontent.com/johan/world.geo.json/master/countries.geo.json') # ローカルに落としてからでもよい
```
このgdfには各国の国境を描く緯度・経度のセットが入っています
![スクリーンショット 2021-05-09 2.13.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638747/688bdf78-1e4f-05ef-5114-eda98d173eb8.png)
これらの国を何らかの基準でカテゴリ分けします
今回はAから始まる国とBから始まる国の2カテゴリにしてみます

```python
gdf['Group'] = ''
gdf.loc[gdf.name.str.startswith("A"), 'Group'] = 'A'
gdf.loc[gdf.name.str.startswith("B"), 'Group'] = 'B'
```

[folium.GeoJson](https://python-visualization.github.io/folium/modules.html#folium.features.GeoJson)にこのdataFrameの該当行を渡し、描画の設定をすることで好きな色で国に色をつけられます

```python
m = folium.Map(location=[0, 0], zoom_start=2)

folium.GeoJson(gdf[gdf['Group']=='A'], 
               # レンダリングする表示の線や色の設定ができます
               style_function=lambda x: {'fillColor': 'red', 'color': 'red'}, 
               # マウスホバー時のツールチップの設定ができます
               tooltip=folium.features.GeoJsonTooltip(fields=['name', 'Group'],labels=True, sticky=True)
               ).add_to(m)
folium.GeoJson(gdf[gdf['Group']=='B'], 
               style_function=lambda x: {'fillColor': 'blue', 'color': 'blue'}, 
               tooltip=folium.features.GeoJsonTooltip(fields=['name', 'Group'],labels=True, sticky=True)
               ).add_to(m)m
```
これによりできたmapオブジェクト`m`は次のような表示になります。ホバーした国には指定したカラムの情報が表示されます
![スクリーンショット 2021-05-09 2.20.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638747/fe23510e-97b4-d6ba-b319-e8122f2731f5.png)
オリジナルアプリ開発#2【Railsプロジェクトの作成】

現在、転職先の企業へのアピールポイントになるポートフォリオ作成（オリジナルアプリ開発）をしています。
私は、タスク管理ツールの完成を目指しています。

今回は、Railsの新規プロジェクトの立ち上げを行います。

##Railsの新規プロジェクト作成
RailsでWebアプリケーションを作成します。（Rails6の環境がある前提）。

rails newコマンドを入力します。

```ruby:ターミナル
rails new [作成するアプリケーション名]
```

ここでは、　『TaskApp』　という名前のアプリケーションを作成します。

```ruby:ターミナル
rails new TaskApp
```

命令文のrailsとnewの間にRailsのバージョンを入力すると、Railsのバージョンを指定できます。


## 作成したディレクトリに移動する
cdコマンドを使って、新たに作成した『TaskApp』ディレクトリに移動します。

<details><summary>cdとは</summary>
「cd」は、change directory（ディレクトリを移動する）の略です。

```ruby:ターミナル
cd [移動したいディレクトリ名]
```

```ruby:ターミナル
cd TaskApp
```

コマンドを実行すると、『TaskApp』ディレクトリに移動します。

## ローカルサーバーを起動
ローカルサーバーを立ち上げるには、次のコマンドを入力します。

```ruby:ターミナル
rails s
```
ローカルサーバーを起動するときはターミナルで新規タブ(command+T)を
開いて行うと今までの作業と混同しなくて済みます。

うまくサーバーが起動すると、ターミナルで次のように表示されます。

```ruby:ターミナル
=> Booting Puma
=> Rails 6.0.3.7 application starting in development 
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 4.3.7 (ruby 2.6.5-p114), codename: Mysterious Traveller
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://127.0.0.1:3000
* Listening on tcp://[::1]:3000
Use Ctrl-C to stop
```

##Railsのデフォルトページを表示

ローカルサーバーを起動したら、ブラウザで「http://localhost:3000/ 」にアクセスします。

次の画像のようにRailsのデフォルトページが表示されていれば、うまく動作しています。
![Rails初期画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1210417/9450fd3f-e278-e920-bfc7-6d63019e94f6.png)

##GitとGitHubに連携
GitとGitHubでファイルの変更修正のバージョン管理を行うために連携します。

1.立ち上げたアプリのローカルリポジトリを作成する。
2.commitする。
3.リモートリポジトリを作成する。（「Keep this code private」にチェックが入っていると非公開になってしまうので、チェックを外して、「Publish Repository」をクリックする。）
4.pushする。

##自動整形ツールを導入
コードの品質を担保するために、自動整形ツールを導入します。
導入方法は下の記事を参考にしてみてください。

https://qiita.com/kyohhh/items/203eeab6cf3229471ed4

以上です。
Raspberry Pi上で物体検出（SSDなど）をやってみる tensorflow

# 0. はじめに
こちら↓ で、もっさり動作すぎたので、もっと軽量モデルで動かしてみよう。

https://qiita.com/hamanhuman/items/d9a52b0e23044cd820de

※といっても、こちらの完全なる写経です。今はそれでよいのだ。
（写経というよりもコピペでしかない説。。）
　ありがたや、ありがたや。。。神である。

https://qiita.com/karaage0703/items/8c3197d11f61812546a9


- Raspberry Piモデル：32bit
    - model name : ARMv7 Processor rev 3 (v7l)
    - Model : Raspberry Pi 4 Model B Rev 1.2

# 1. Object Detection API で物体検出
TensorFlowの物体検出ライブラリ"Object Detection API"を利用しやす。

ある程度ライブラリの環境構築は前にやっていたのだが、
結構カオスであったので念のため最初からコマンドを実行。
が、謎に"termcolor"パッケージがないと怒られるので、個別でインストール。

無事にラズパイでも動作。
色んなモデルで実行してみた。

- efficidentdet
- ssdlite-mobilenet
- ssd_inception


![detection_各種.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384185/b88d0dad-20ca-887c-2bc4-7301188f9ee9.png)

推論速度と精度はトレードオフなんだけど、これくらいだと精度は気にならない。速度の速いモデルが好きになるな。


# 2. おわり
別のライブラリ＆モデルでも物体検出してみた。

"Model Zoo"ってのでもう少し別のモデルもやってみつつも、
何か**スキルとして身につける方向**にも足を延ばしていかねば。

でも、楽しい。これ大事ね。
指定した一時間の中央値を計算


#python
`200523_N.MWDH_U_bp10-20_sqr.s`の15時〜１６時の中央値を求める場合
``$ python sac_median.py 200523_N.MWDH_U_bp10-20_sqr.s 15``

```sac_median.py
import obspy
from obspy import read
import numpy as np
import sys

#コマンドラインから引数
file = sys.argv[1]
hour = sys.argv[2]
#数値に変換
hour = int(hour)

#サンプリング周波数
samplerate = 100

#sacファイル読み込み
sac1 = read(file, debug_headers=True)#読み込みたいファイルをここに入力
#振幅データ（縦軸）
y = sac1[0].data


##時間（横軸）．
#time = np.arange(0, len(y))/samplerate

#指定した時刻〜一時間後の時刻までの中央値を計算
median = np.median(y[hour*360000:(hour+1)*360000])
median = median*1e-9 #m/sからnm/sへ変換
print(median)
```
#fortran
`200523_N.MWDH_U_bp10-20_sqr.s`の15時〜１６時の中央値を求める場合
``$ gfortran -o median sac_median.f95`` #コンパイル
``$ ./median 200523_N.MWDH_U_bp10-20_sqr.s 15`` #実行

```sac_median.f95
program main
 implicit none
 integer i, a(40), max, npts, hour
 real b(70),c(2), dt, med
 real, allocatable :: x(:), y(:)
 character :: file1*80, arg*10, khd(48)*4
 
  if(iargc()>0) then
    call getarg (1, file1) !コマンドラインで引数!
    call getarg (2, arg) !コマンドラインで引数所得
    read(arg,*) hour
 endif
 
 max=10000000
 allocate (x(max),y(max))
 call arsac(file1,b,a,khd,x,max)
  npts = a(10)
  dt = b(1)
  do i = hour*360000+1,(hour+1)*360000+1
     y(i-hour*360000) = x(i)
  enddo
  call median(y, med, 360000)
  med = med*1e-9 !m/sからnm/sへ変換
 write(*,*)med
end program main
!########################################################
subroutine arsac(fn,fhd,nhd,khd,y,maxy)
  real fhd(70),y(maxy)
  integer nhd(40),i,i1,i2,i3,npts
  character khd(48)*4,fn*80
  
  open(1,file=fn,access='direct',recl=632,status='old')
  read(1,rec=1)(fhd(i1),i1=1,70),(nhd(i2),i2=1,40),(khd(i3),i3=1,48)
  npts=nhd(10)
  close(1)
  open(1,file=fn,access='direct',recl=4,status='old')
  do i=1,npts
!     read(1,rec=i+158,end=100)y(i)     Mar.1 H.A
     read(1,rec=i+158)y(i)
  enddo
! 100 continue
  close(1)
  return
end subroutine arsac
!#####################################################
subroutine median(a, med, n)
  implicit none
  integer,intent(in):: n
  real,intent(inout):: a(n)
  real,intent(inout):: med
  integer i, m
  real am

!バブルソート（遅い）
!  do i = 1, n-1 !sort a
!     am = minval(a(i+1:n))
!     m  = minloc(a(i+1:n), 1) + i
!     if (a(i) > am) then
!        a(m) = a(i)
!        a(i) = am
!     endif
!  enddo

  call quicksort(a,1,360001)
  
  if(mod(n, 2) /= 0) then !median of a(:)
     med = a((n-1)/2+1)
  else
     med = 0.5*(a(n/2)+a(n/2+1))
  endif
end subroutine median

!##############################################
recursive subroutine quicksort(a, first, last)
  implicit none
  real  a(*)
  integer first, last
  integer i, j
  real  x, t
 
  x = a( (first+last) / 2 )
  i = first
  j = last
  do
     do while (a(i) < x)
        i=i+1
     end do
     do while (x < a(j))
        j=j-1
     end do
     if (i >= j) exit
     t = a(i);  a(i) = a(j);  a(j) = t
     i=i+1
     j=j-1
  end do
  if (first < i - 1) call quicksort(a, first, i - 1)
  if (j + 1 < last)  call quicksort(a, j + 1, last)
end subroutine quicksort
```
Oracle APEXでフォーム付き対話モードレポートに文書ファイルをアップロード

APEXのフォーム付き対話モードレポートを通して、文書データ（ExcelやWordなど）を一覧表示、アップロード、ダウンロードできるやり方を記載します。文書データに関してはDBにBLOB型で持たせます。

# 画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85051/e92de78c-f9f5-767b-d293-5c260ee5c136.png)

# 手順サマリ
1. テーブル作成
1. フォーム付き対話モードレポートの作成
1. フォームのBLOB列のページアイテムプロパティにBLOB補足情報列を入力

# 手順詳細
### テーブル作成
DOC列がドキュメントファイルを格納するBLOB列で、その他のDOC_FILENAME、DOC_MIMETYPE、DOC_CHARSET、DOC_LASTUPDが追加の補足列になります。
これらの補足列があることでドキュメントファイルが扱いやすくなります。
以下はSQLワークショップからID列を新規順序作成で指定して作成したときに生成されるSQLです。シーケンスと自動採番のトリガーまで生成してくれます。

```
CREATE table "DOCUMENTS" (
    "ID"           NUMBER,
    "NAME"         VARCHAR2(256),
    "DOC"          BLOB,
    "DOC_FILENAME" VARCHAR2(512),
    "DOC_MIMETYPE" VARCHAR2(512),
    "DOC_CHARSET"  VARCHAR2(512),
    "DOC_LASTUPD"  DATE,
    constraint  "DOCUMENTS_PK" primary key ("ID")
)
/

CREATE sequence "DOCUMENTS_SEQ" 
/

CREATE trigger "BI_DOCUMENTS"  
  before insert on "DOCUMENTS"              
  for each row 
begin  
  if :NEW."ID" is null then
    select "DOCUMENTS_SEQ".nextval into :NEW."ID" from sys.dual;
  end if;
end;
/   

```
### 対話モードレポートの作成
先ほど作成したテーブル（DOCUMENTS）をもとにフォーム付き対話モードレポートを持つアプリケーションを作成します。
方法はいろいろありますが、SQLワークショップからDOCUMENTSを指定してアプリケーション作成ボタンを押下して始める方法が早いです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85051/f152deb2-b669-b98e-d336-ece575887bb5.png)

特に何もいじらずアプリケーション作成ボタンを押せば、以下のようなフォーム付きの対話モードレポートができあがります。まだデータがないので何もない表示されてません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85051/6b6ced1e-ff73-9aa1-9614-ca7c419f5f51.png)

文書を登録するために、以下の順で、作成ボタンからフォームを呼び出し、文書名（リスト上の文書の名前）を入力し、文書ファイルをダイアログまたはドラッグアンドドロップで選択後、作成ボタンを押します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85051/ae78ae70-298b-b770-29f5-727f8b798035.png)

すると以下のような行が追加されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85051/6ab6a3c3-986f-286e-db3f-f7aa0f644f5f.png)

ここで鉛筆マークをクリックすると、該当行を編集するフォームに飛ぶのですが、ここにダウンロードリンクがあり、ファイルのダウンロードができます。しかし、ダウンロードファイルはdownloadという名前で拡張子も何もないファイルがダウンロードされてしまい、このままでは使いにくい感じです。（一応、ダウンロード後に元ファイル名にリネームしてに戻せば使えます）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85051/ca33e0d7-f36e-fb50-f645-64ad24124286.png)
### フォームのBLOB列のページアイテムプロパティにBLOB補足情報列を入力

そこで先ほどのDOC_FILENAME、DOC_MIMETYPE、DOC_CHARSET、DOC_LASTUPDが追加の補足列をフォームに設定してファイルのアップロードと同時に名前情報などがテーブルに保存されるようにします。
方法としては、フォームの編集画面から、BLOB列のページアイテム(今回はP4_DOC)を選択して、プロパティにそれぞれ以下のように設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85051/3b4b3122-0beb-cf0e-7ce5-c26c3d54e8de.png)

この設定のあと、もう一度フォームからtest.xlsxを名前test2としてアップロードしてダウンロード用のファイルダイアログを見ると、以下のようにちゃんと、元のファイル名でダウンロードされます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85051/84fe743d-bc97-0193-5d4b-c76563460743.png)

この時のDOCUMETSテーブルの状態をオブジェクトブラウザで見ると以下のような形になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85051/86d6002a-f0a1-a558-a60d-a01c4fcfe1b3.png)

# 参考
[日日是Oracle APEX:簡単な文書管理アプリケーションを作成する](http://apexugj.blogspot.com/2020/08/simple-doc-mgmt.html)
こちらのサイトでは、文書ファイルのレポート内でのダウンロードリンクのつくり方、直リンクによるダウンロードや全文検索の追加の手順などまで記載されています。
docker composeでWordPressを試したときの失敗談

Dockerの学習をぼちぼち進めている。

Software Design誌の2020年12月号の第1特集に、Docker Composeの初歩としてWordPressを動かすサンプルが掲載されている。これを動かすまでの過程で一つハマったので、備忘として記録しておく。ハマりの原因は、もちろん自分のミスにある。

# やろうとしたこと
- 雑誌に掲載している`docker-compose.yml` を使用して、WordPressとMySQLのコンテナからなるアプリケーションを実行する。
- なお雑誌掲載の `docker-compose.yml` は、[Docker Hubの公式WordPressイメージ](https://hub.docker.com/_/wordpress)に載っているものとほぼ同じ内容。

# ハマりの内容
- `docker-compose.yml` を作成する際に編集を誤り、WordPressコンテナとMySQLコンテナのそれぞれに設定するDBユーザー名(WORDPRESS_DB_USER, MYSQL_USER)が一致しない状態になっていた。
- この状態で`docker-compose up`でアプリケーションを起動し、`http://localhost:8080/` のURLでWordPressにアクセスしようとしたところ、(当然の結果として)WordPressがデータベースの接続に失敗し、ブラウザに　"Error Establishing a Database Connection"のエラーメッセージが出た。同時に、MySQLコンテナに下記のログが出た。 

```
[Note] Access denied for user 'exampleuser'@'172.19.0.3' (using password: YES)
```

- `docker-compose.yml` の誤りを修正した後で、コンテナとイメージを削除して再度アプリケーションを起動しようとしたが、エラーが解消されなかった。
- 雑誌掲載の `docker-compose.yml` の代わりに、公式WordPressイメージのサンプルをまるまる上書きコピーしてアプリケーションを起動しても、同じくエラーが解消されなかった。

# 原因
- 最初に誤った `docker-compose.yml` を使用してコンテナを起動したときに、誤った設定情報をもとにWordPress用/MySQL用のそれぞれにボリュームができた。
- `docker-compose.yml`を修正しても、一度できたボリュームは前回の誤った設定を保持したままになっていた。
- 2回目以降に起動したコンテナが誤った設定を持ったままのボリュームを参照していたために、エラーが解消されなかった。

# 対応
誤った`docker-compose.yml`をもとにできたボリュームを削除してアプリケーションを再起動し、正しい設定でボリュームを再作成する。

- `docker-compose down -v` でコンテナと同時にボリュームも消す

```
% docker-compose down -v
Removing wordpress-sd2020dec_wordpress_1 ... done
Removing wordpress-sd2020dec_db_1        ... done
Removing network wordpress-sd2020dec_default
Removing volume wordpress-sd2020dec_wordpress
Removing volume wordpress-sd2020dec_db
```

- `docker-compose up` でアプリケーションを再起動すると、ボリュームが正しい設定で再作成される

# 余談：`docker compose rm -v`ではボリュームが消えない(2021/05/09時点)
Docker Desktop for Mac/for Windowsのバージョン3.2.1以降では、dockerコマンドにcompose CLIが統合されている。そのため、ハイフンをつけない`docker compose down -v`コマンドでもボリュームが消せるはずなのだけれど、実際にはボリュームが削除されなかった(Docker version 20.10.6, build 370c289 on macOS Big Sur 11.3.1)。

この事象はcompose CLIのIssuesで報告されていて(https://github.com/docker/compose-cli/issues/1553) 、修正のプルリクエストも上がっている(https://github.com/docker/compose-cli/pull/1618) ようなので、いずれ修正版がリリースされるのだろう。

# 余談：解決までの経緯
- [Docker Hubの公式WordPressイメージ](https://hub.docker.com/_/wordpress)を見たが、収穫なし
- `docker wordpress access denied for user` をキーワードにググったところ、今回に類似した事象の報告として https://forums.docker.com/t/wordpress-example-in-docker-compose-fails/30438 を発見。日本語でも同様のことを書いたブログ記事があった(https://swan-once.com/docker-compose-yml_forwordpress/) 。
- これらの記事では、解決法として「`docker-compose.yml`を修正し、MySQL用ボリュームをマウントする先のディレクトリー設定を、元の `/var/lib/mysql` から `/var/lib/mysql2` などに変更する」という方法が示されていた
- しかし「公式サイトのサンプルを変えないと動かない」というのは不自然で、真の解決法は別にあるはず
- コンテナ自体は前回起動時のことを覚えていないはずだし、…と考えた結果、「ボリュームに古い情報が残っている」ことに気づいた
AR Foundation イメージトラッキングを使う

ReferenceImageLibraryを作成する
![56A6D8EF-6966-4084-8AF7-A4AECAB2419E.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/e32e4e2e-d29e-d407-07f3-3bb8b3749e75.jpeg)

Imageをprojectに入れる
![4D6A3DEA-8DD4-44DA-989B-3650C2F592FA_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/0a5bed72-412b-0016-acac-93b7fac2b98c.jpeg)

ReferenceLibraryのAdd Imageを押す
![019ABF77-E0A1-4F6A-ABAC-BA6334623AFA_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/47eed33f-7877-002c-08ba-aab9eb68845e.jpeg)

Imageをアタッチして、SpecifySizeをチェック、Xのサイズを調整する。（１で１m、0.2で２０㎝）
![13996303-1CAF-43F7-99E7-665C44AEA8D7_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/52ab2005-dccc-11ce-cc53-e95adc94f394.jpeg)

CharacterのサイズをImageサイズに合わせる
![CBAF6A29-8641-48F4-BD68-71536F2AB5D2.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/352f1a7b-2a47-d8d9-ee84-674e9ceac926.jpeg)

AR Originの各項目を設定する。（Max Numberでオブジェクトをいくつまで表示するか決めれる）
![4E5625FA-2FC4-4AF3-8969-EF406629FE63.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/b6d179ea-058b-e9ea-b26c-912a5f9a96ee.jpeg)
Julia で継承的なことを書く

## 概要
Juliaには型の階層があり、構造体を宣言する際にsupertypeを指定することができるが、supertypeになるのは抽象型のみであって、具象型に対してサブタイプを作ることはできない。このため、クラスベースのプログラミング言語で行うような差分コードだけを追加するようなことができない。

ではどうするかというと、supertypeに当たるものをメンバとして保持しておき、関数をフォワードする。しかしたくさん関数があると大変面倒なので、マクロを使う。


## やりたいこと
Javaで例をあげる。

```Java
class A {
  void f0() {System.out.println("A::f0");}
  void f1() {System.out.println("A::f1");}
}
```
のようなクラスに対して、`f1`だけ再定義したクラスBを作りたいとする。Javaだと次のように継承して書けばいい。

``` Java
class B extends A {
  void f1() {System.out.println("B::f1");}
}
```

## Juliaでの書き方

ベースとなる構造体Aはこんな感じで書く。

``` Julia
struct A end
f0(a::A) = println("f0(A)")
f1(a::A) = println("f1(A)")
```

これを再利用して構造体Bを定義するには次のように書く。

``` Julia
struct B a::A end
f0(b::B) = f0(b.a)
f1(b::B) = println("f1(B)")
```
`f0`を再利用するために、型`A`を型`B`のメンバとして保持しておき、`f0`は`A`のものを呼出している。関数1つだけなら、こう書くのは簡単だが、再利用したい関数が大量にあったらたまらない。

## @forward マクロを使った書き方

このような定型的な定義を生成してくれるマクロがパッケージ`MacroTools`に用意されている。定義は単純なので自作している人も多数いるようだ。

``` Julia
import MacroTools
@MacroTools.forward B.a f0
```
とすると、

``` Julia
f0(b::B) = f0(b.a)
```
が自動生成される。本当は引数のついた大層なものが定義されるようだが。

この例だとなんともありがたみに欠けるが、このマクロは関数名を列挙できるので大量の関数を持つような型でも簡単に差分プログラミングできる。

## 所感
しかし、なんで具象型のサブタイピングを許さないんだろうか。ほぼ同じ発想でオブジェクト指向を構成しているCLOSではごく普通に許しているし、あまつさえ謎めいた多重継承までサポートしている。そのせいで呼び出される汎関数を実行時に決定するのが大きな負荷になっていたが、このあたりが重くて遅くなるのを嫌ったのか? だとすると性能命のJuliaっぽい。
next.jsでreactのcreateContextをviewとデータを切り離して綺麗に書く方法

開発環境：
macOSX catalina バージョン10.15.7
visualStudioCode
react
next.js

***createContextを綺麗に書く方法を教わったので、備忘録***
---

以下のような書き方をして、Contextを定義する
そうすることによって、viewとデータを切り離すことができ、可読性が高まるとのこと

```
import React, { useReducer, createContext } from "react";
import reducer from "./reducer";

const tagList = [];

const MyContext = createContext("");
const Store = ({ children }) => {
  const [state, dispatch] = useReducer(reducer, tagList);
  return (
    <MyContext.Provider value={{ state, dispatch }}>
      {children}
    </MyContext.Provider>
  );
};

export { MyContext, Store };
```

以下のようにContextを下位コンポーネントにつなぐ

```
import "../styles/globals.css";
import React from "react";
import { Store } from "../store/store";

function MyApp({ Component, pageProps }) {
  return (
    <Store>
      <Component {...pageProps} />
    </Store>
  );
}

export default MyApp;
```
公共交通オープデータセンターのGTFS-RTを触ってみよう！

# 公共交通オープデータセンターとは

公共交通オープデータ協議会に参画している事業者が持つデータを集約し一般に公開しているサービスです。
鉄道をはじめ、バス、飛行機、船舶などの静的・動的データを利用することができます。

https://www.odpt.org/

# 東京都交通局のAPIを使ってみよう

## 事前準備物
- 公共交通オープデータセンターの開発者登録（登録は[こちら](https://developer.odpt.org/ja/info)）<br>※ユーザー登録の完了まで最長２営業日ほどかかりますが、１日後くらいには承認のメールが届き使えるようになります。
- Docker環境、docker-compose環境
    - [MacOSの場合](https://qiita.com/tomokei5634/items/7b1e7a121d5d7bc12116)
    - [WindowsOSの場合](https://qiita.com/ksh-fthr/items/6b1242c010fac7395a45)

## アクセストークンの取得方法

① 開発者サイトにアクセスする 

https://developer.odpt.org/

② アカウント欄からアクセストークンの確認・追加のページ(添付画像の赤枠)を開く

![アクセストークンの場所1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426516/2aafa644-2018-7089-7578-8857b00daeb4.png)

③ デフォルトアプリケーション欄のアクセストークン(添付画像の黒帯部分)をコピペ

![アクセストークンの場所2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426516/4fc07e68-31e7-4ee1-feb2-353247f390c2.png)

## 環境構築

① GTFS簡易ツールをクローン

```bash:ターミナル
$ git clone https://github.com/Kaas59/GTFS-Python
```
https://github.com/Kaas59/GTFS-Python

② アクセストークンを環境変数に設定

```bash:ターミナル
# 作業ディレクトリに入る
$ cd GTFS-Python

# .envファイルを作成
$ cp .env.sample .env

# .envファイルにアクセストークンをペースト
$ nano .env
```

```text:.env
token=ここにアクセストークンをペースト
```

② Dockerイメージをビルド

```bash:ターミナル
# makeコマンド環境がある人
$ make build

# makeコマンド環境が無い人
$ docker-compose build
```

③ コンテナを起動

```bash:ターミナル
# makeコマンド環境がある人
$ make up

# makeコマンド環境が無い人
$ docker-compose up
```

④ コンテナにアクセス

```bash:ターミナル
# makeコマンド環境がある人
$ make exec

# makeコマンド環境が無い人
$ docker-compose exec python3 bash
```

## 使ってみる

今回使用するデータは「東京都交通局のバスのロケーション情報」です。
このデータは、GTFS-RTという形式で提供されている。また、データのフォーマットはGoogleが定めた「Protocol Buffers」という形式でバイナリ化されて送られてくる。そのため、そのままでは人間が読み取ることはできないのでデコーディングし理解可能な状態にする必要がある。

https://ckan.odpt.org/dataset/b_bus_gtfs_rt-toei/resource/4b720e5d-55e3-4a4d-abe3-db5086f0cef0

### 実際にロケーション情報を取得してみる

```bash:ターミナル(コンテナ内)
# makeコマンド環境がある人
$ make gtfs

# makeコマンド環境が無い人
$ python3 main.py
```

# 最後に

今回利用した公共交通オープデータセンターの他にも様々なデータを提供しているところがありますのでぜひ使ってみてください。

https://developer.tokyometroapp.jp/ja/info

https://tokyochallenge.odpt.org/



# おまけ「今回使用したProtocol Buffersについて」

Protocol BuffersはAPIを通してデータを送信する前に特定の形式にそってエンコードされており、通常その形式がわからないとデコーディングすることはかなり困難である。しかし、公共交通オープデータセンター内でその詳細な形式は公開されていない。だが、[GTFS-JP](https://www.gtfs.jp/)とい団体と国土交通省により日本での形式のサンプル(Googleが配布しているものと同じ)が配布されており、そちらを利用することでデコーディングを行うことが出来ます。

https://www.mlit.go.jp/sogoseisaku/transport/sosei_transport_tk_000112.html

https://www.mlit.go.jp/common/001283242.pdf

https://developers.google.com/transit/gtfs-realtime/gtfs-realtime.proto
protocolを使ってenumが特定のcaseを持っていることを表す

APIレスポンスをenumにマッピングする際、当てはまるものがなければunknownにしたい時がありました。
愚直に書くと以下のようになります。

```swift
enum Enum: String {
    case a
    case b
    case unknown
}

extension Enum {
    init(rawValue: RawValue) {
        self = Self(rawValue: rawValue) ?? .unknown
    }
}
```

しかし、以下のようなProtocolに準拠すると特定のcaseが存在することを明示的に表すことができます。

```swift
protocol HasUnknown, CaseIterable {
    static var unknown: Self { get }
}

enum Enum: String, HasUnknown {
    case a
    case b
    case unknown
}
```

そして、以下のようにprotocol extensionでinitを宣言しておけば、enumごとにマッピング処理を書く必要がなくなります。

```swift
extension HasUnknown where Self: RawRepresentable, RawValue: Equatable {
    init(rawValue: RawValue) {
        self = Self.allCases.first(where: { $0.rawValue == rawValue }) ?? .unknown
    }
}
```

以下のようにinitができます

```swift
let a = Enum(rawValue: "a") // case a
let unknown = Enum(rawValue: "others") // case unknown
```

### Revision

2021/05/09 @takehito-koshimizu さんのアドバイスでマッピング処理がシンプルになり、CaseIterableに準拠する必要もなくなりました。ありがとうございます！

2021/05/11 と思いましたが、やはり既存で用意されているrawValueを使ったOptional initはコンパイルエラーは出ないものの、
実行時に無限ループとなりました。若干冗長ではありますがCaseIterableに準拠する必要があります。
Gatsby-microCMSブログで画像を表示するcomponentを作りました

## こまったこと

microCMSでは、gatsby-plugin-imageに対応していないため
graphqlで画像データが渡ってこず、URLだけ渡ってくる仕様。
どうやって画像の最適化をしようかな

## microCMS運営さんにチャットで問い合わせ

チャットで問い合わせをしました。
>いつもお世話になります。 GatsbyとmicroCMSでブログを作ろうとしています。 gatsby-plugin-imageで>microCMSの画像を扱いたいのですが、graphqlのデータを見ると、urlとwidthとheightしかわたってきてい>ないので、扱うことができません。 なにかやり方があるかご教示お願いしたいです

ご丁寧に対応いただき、次のことがわかりました。
・ImgixというCDNを通して、APIを利用するとよい

あとから考えれば、ドキュメントなどをしっかり読めばわかりそうなことでした😅

## [Imgix](https://www.imgix.com/)を使って画像を最適化

### [Imgix](https://www.imgix.com/)とは

公式サイトより

>Powerful image processing, simple API
imgix transforms, optimizes, and intelligently caches your entire image library for fast websites and apps using simple and robust URL parameters.

>強力な画像処理、シンプルなAPI
imgixは、シンプルで堅牢なURLパラメーターを使用して、高速なWebサイトやアプリ用に画像ライブラリ全体を変換、最適化、およびインテリジェントにキャッシュします。 

microCMSの画像タイプのコンテンツは基本的にこのCDNを通ってくるということなので
ここのAPIでできることが基本的にできるということです。

### やりたいこと

1. レンダリングのときに、画像のサイズ、容量を節約
1. サイズの調整やトリミング

### Imgixでは

[Rendering API](https://docs.imgix.com/apis/rendering)を使うとできそう。

画像URLの最後に`?`をつけて、その後にいろいろなパラメータを付けることで、画像に対していろいろな処理ができます。
例えば

```
https://<graphqlで渡ってきた画像のurl>?w=200
```

とすると、画像の幅を２００（ｐｘ？）に設定できます。
その後ろに`&`でつなげれば、複数のパラメータを付けることができます。

いろいろオートの設定もありました。
例えば
1. 画像の圧縮　`auto=compress`
基本的には７５％。`q=`で圧縮率を指定することもできます。
2. フォーマット選択　`auto=format`
対応しているブラウザなら、自動でwebp形式に変換してくれる。
3. 画像のトリミング　`ar=2:1&fit=crop&fp-y=0.5"`
アスペクト比と中心を決めてトリミングできます。切り抜いた部分以外はデータとしても削除。（残す設定もできる）

とりあえず、今回のプロジェクトでは、
この３つを設定することにしました。

ブログの記事ごとのアイキャッチ画像に対して
これらの加工をして、
各記事ページタイトルのバックにおくことにしました。

### 実装したコード

- 各記事のテンプレートファイル post-template.js

```javascript
<MicroCmsImage									 
  url={data.microcmsPosts.eye_catch.url}									 
  compress="auto=compress"									 
  format="auto=format"									 
  ar="ar=2:1&fit=crop&fp-y=0.5"
/>								/>
```

- 画像をレンダリングするコンポーネント　microcmsimage.js

```javascript
import React from "react"
import styled from "styled-components"

export default function MicroCmsImg(props) {
  // imgタグを親要素に対して幅いっぱいに表示する
  const ImgWrapper = styled.img`
    width: 100%;
  `
  const { url } = props // 画像のURL
  // url以外のパラメータを１つの文字列型変数にセット
  let array = Object.values(props)
  let param = ""
  array.map(function (elem) {
  // propsの最初はurlなのでそれは入れない
    if (array.indexOf(elem) !== 0) {
      //最初の要素は?をつける
      if (array.indexOf(elem) == 1) {
        param = `?${elem}`
      } else {
        param = `${param}&${a}`
      }
    }
  })

  return (
    <>
　　　// imgのsrcにurlとparamをつなげたものをセット
     <ImgWrapper src={url + param} alt="" />
    </>
  )
}

```

## Imgixではもっといろいろできます。
例えば、画像にフィルターをかけることもできます。
モザイク加工したり、blur効果つけたり。
顔認識でそこにクローズアップとか。
文字入れたり、ノイズリダクションに回転。

gatsbyプロジェクトでは、
対応していればgatsby-plugin-imageが使えますが、
そうでないプロジェクトなら、
これを使うのもいいかもしれません。
Application.cfcについて

# Application.cfc

Application.cfcは必ず最初に実行される。
どのコードをどのタイミングで実行するのか指定できる。今回は`onRequestStart` このタイミングでrequest.nameにhogeを入れる。

demo.htmlでrequest.nameを使うことができるし、ほかのhtmlでも共有して使うことができる。
普通はsessionとかcookieとかの記録をする。

注意：ファイル名のAは必ず大文字で。

# コード

### demo.html

```html
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
    <cfoutput>#request.name#</cfoutput>
  
</body>
</html>
```

### Application.cfc その①

```html
<cfcomponent>

    <!---application名以外はデフォルト--->
    <cfset This.name = "MyApp">

    <!---cfmページが呼ばれたときに最初に必ず--->
    <cffunction name="onRequestStart">

        <cfset request.name = "hoge">
     
    </cffunction>

</cfcomponent>
```

### Application.cfc その②

```java
component {

    this.name = "MyApp";
  
    public void function onRequestStart() {
  

        var request.name = "taro";
  
    }
  
  }
```

# 参考

[http://coldfusion.blog.shinobi.jp/coldfusionのタグ/application.cfcでエラー処理](http://coldfusion.blog.shinobi.jp/coldfusion%E3%81%AE%E3%82%BF%E3%82%B0/application.cfc%E3%81%A7%E3%82%A8%E3%83%A9%E3%83%BC%E5%87%A6%E7%90%86)

[https://gist.github.com/learncfinaweek/4121263](https://gist.github.com/learncfinaweek/4121263)
iOSショートカットでゴミの日をSiriに聞く

<h1>はじめに</h1>
一人暮らしを始めて2年が経ったけど未だにゴミの日を覚えてないから、簡単にゴミの日を教えてくれるショートカットを作ってみたよ。
<h1>挙動について</h1>
・ショートカットを直接実行することで通知として返答する
<img width="700" alt="IMG_0111.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1013591/80988524-e79e-888a-99df-82827289fb91.jpeg">
・Siriに聞くと音声フィードバックしてくれる
<img width="700" alt="IMG_0112.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1013591/3648933c-d922-f53a-5f56-e1732b1a8462.jpeg">
<h1>導入</h1>
下のリンクでショートカットを入手して、適宜各々の環境に合わせて編集してね。
<br>
https://www.icloud.com/shortcuts/4ecd9948c77141f5ae766b3669d2fbc9
<h1>仕組み</h1>
<img width="500" alt="qiita_01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1013591/5e5459b4-ddfe-8233-34bb-4bdebeba6169.png">

基本的にはif文で各曜日ごとにメッセージをプレビューとして設定する。
プレビューで設定することによって自分で実行した際にはテキストメッセージで返して、Siriに頼んだときは音声フィードバックで教えてくれるよ。
<br>
曜日の抽出方法は、現在の日付で日付フォーマットを「カスタム」にして
<img width="500" alt="qiita_01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1013591/7dc7b4d5-74d0-7474-0a72-19702ad87856.jpeg">
「カスタムフォーマット」の値を曜日を表す「EEE」に設定し
<img width="500" alt="qiita_01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1013591/858f402b-1070-fceb-9668-e794d3ae9fad.jpeg">
<img width="500" alt="qiita_01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1013591/6cd9dc4b-3917-fd76-cb7b-b33be5ff9dd1.jpeg">
その値を本体言語に合わせて、「月火水木金土日」で分け、英語なら「Mon,Tue,Wed,Thu,Fri,Sat,Sun」で分ける。
あとは好きな文章を入力して完成。
scikit-fdaをjupyter labで使いたいだけ・・・。ほんとそれだけ。

scikit-fdaをインストールするときにちょっと困ったので、解決方法を共有しておきます。

# FDAについて
本題は、ただのトラブルシュートなのでscikit-fdaや関数データ解析（Functional data analysis; FDA）について簡単にまとめておきます。

経時測定データ（時間の経過や位置の変化に応じて繰り返し計測されたデータ）に対して、得られたデータと着目する事象を統計モデルによって明らかにするためにはいくつかの問題が生じます。問題は観測データの特性に依存しています。例えば、観測時点数の増加がそのままデータの次元の増加につながり推定量が不安定になることや欠損などの理由で個体ごとに観測時点数が不均一であったり、観測時点が不揃いであることから古典的な多変量解析手法を直接適用することが困難であったりします。
これらの問題を解決するため、個々のデータを関数化し、得られた関数をデータとして扱う方法が確立されました。これがFDAの基本概念です。

そんなFDAのpythonパッケージがscikit-fdaです。
scikit-fdaについては下記を参考にしてください。
https://fda.readthedocs.io/en/latest/
これのチュートリアルをするときに問題が発生しました。
ということでここからが本題です。

# エラー① Could not import the lzma moduleが出てimportが完了しない
OS 10.14.6
python 3.8.2

scikit-fdaをpipでインストールした後、いざjupyterLabでimportしようとしたら
Could not import the lzma moduleが出てimportが完了しません。チュートリアルが進みません。

## 解決方法
結局はxzをinstall（xz形式の圧縮ファイル扱えるようにする）→ pythonを再度インストールで解決しました。
pyenvでのバージョン管理をしていたので、下記のように実施しました。

```
$ brew install xz
$ pip freeze > requirements.txt # uninstallするのでパッケージを戻せるように
$ pyenv uninstall 3.8.2
$ pip install requirements.txt # パッケージ環境を元に戻す
$ pyenv install 3.8.2
```
これでscikit-fdaをjupyerLabでimportできました。
と思ったら違うエラー出ました。

# エラー② ValueError: numpy.ndarray size changed, may indicate binary incompatibility. Expected 88 from C header, got 80 from PyObjectが出てimportが完了しない

次に当たり前のように違うエラーがでて、importのところでコケてチュートリアルが進みません。

## 解決方法
numpyのバージョン依存らしいので（[参照](https://stackoverflow.com/questions/66060487/valueerror-numpy-ndarray-size-changed-may-indicate-binary-incompatibility-exp)）
numpy                 1.19.2をアップデートしました。

```
pip uninstall numpy
pip install numpy
```
これで自分の場合は、numpy1.19.2 → numpy1.20.2で解決しました。
以上でscikit-fdaをjupyterLabで使用できるようになりました。

この2行が遠かった・・・。
同じ苦しみを味わっている方のお役に立てればと心より願っております。
【nasne用】シンプルなニコニコ実況表示ソフトを作った。【Python】

# はじめに
2020年11月、『ニコニコ実況リニューアル、torne等との連携サービス終了』というニュースが全nasneユーザーを震撼させた。
それから数ヶ月後の先日、バッファロー版nasneが発売されたが、ニコニコ実況に代わるサービスは現れず、私は今日も一人寂しく録画を消化するのであった…


というわけで（？）、やっぱりニコニコ実況のないnasneは味気ないですよね。
今回も ないなら作ろうの精神で、nasneと連携してニコニコ実況を表示する簡単なPC用GUIアプリを作ってみました。
これで録画視聴が捗りますね！
![tmjxg-1rn27.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501281/091dacda-2950-bd89-a07f-5e76385a2047.gif)
PC TV Plus（右、PC用のnasne再生ソフト）で動画の再生を開始すると自動的に実況（左）が流れ始めます。
スマートフォンで動画の再生を開始しても、同様にPC上で実況の再生が自動開始されます。

追記
`Pydroid3`というAndroidアプリで実行したところ、スマートフォンでも普通に動作しました。

（作ってる途中で気づいたけど、今年の1月ごろ？に同じことをやってる人がいました。）


# 機能

### できること
・nasneで再生されている動画を自動検出しての再生
・任意の時間帯の実況の表示
・再生速度の変更（1.0~2.0倍）
・シュートカット操作による、再生一時停止、10秒ごとの時間送り戻し、再生速度調節
・シークバーによる再生位置の調節

### できないこと
・再生位置の検出

### やってないこと
・オーバレイ表示
・コメントの重なり軽減処理

### 確認してないこと
・PS4で再生したときの挙動
・ローカルチャンネルの番組を再生したときの挙動
・バッファロー版での動作確認

# 使い方
### 必要なもの
・プログラム本体

https://github.com/Cartelet0423/niconico_jikkyo_player_for_nasne_pc

・Python
・PyQt5、PyQtGraphなどのライブラリのインストール（AnacondaでPython環境を構築した場合は予めインストールされてそう）

### 準備、実行
・`nico.pyw`をテキストエディターで開いて、20行目にお使いのnasneのIPアドレスを入力
・`nico.pyw`を実行（ダブルクリックでできなければPythonのインストールフォルダにある`pythonw.exe`に関連付けを行ってから）

### 操作方法
#### キーボードショートカット
・再生停止：　スペースキー
・再生速度調節：　カーソルキー上下
・10秒送り戻し：　カーソルキー左右
・実況データの取得（主にnasneと連携しない場合に使用）：　エンターキー
・表示領域リセット：　Rキー

#### nasneと連携する場合
起動して放っておけば勝手に再生が始まるので、再生状態に合わせて速度、位置を調節します。

#### 単体で使用する場合
・シークバーの上の日時をお好みの時間に調節
・画面左上のメニューよりチャンネルを選択
・エンターキーを押して実況データを取得
・スペースキーを押して再生を開始

![009pl-jmr87.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/501281/45c6ac08-88b1-3265-1d8c-dd5c55b5c9e6.gif)
PC TV Plusを重ねての使用例


# 作り方、内部処理とか

#### 実況データ
実況データに関しては、[有志でニコニコ実況の過去ログを取得できるAPIを運営している方](https://jikkyo.tsukumijima.net/)がいらっしゃるので、そちらから取得しています。
取得したデータには色んな情報が含まれていますが（プレミアムユーザーか？など）、今回はコメント、投稿時間、コマンドを使用しています。

コメントの文字数と乱数によって流れる位置、速度を決定し、コマンドに応じてフォント、文字サイズ、位置、色などを変更しています。

#### GUI
GUIは`Qt Designer`で作成しました。
こちらもAnacondaでPython環境を構築した場合は最初からインストールされています。
`Tkinter`や`PySimpleGUI`などもいいですが、より直感的にレイアウトを構築できるので割とおすすめです。

今回`Qt Designer`を採用した理由には、流れるコメントの実装に非常に軽量なグラフライブラリである`PyQtGraph`を使用したかったからというものあります。
Pythonのグラフライブラリというと`Matplotlib`などがありますが、今回のように画面更新を行う用途では`PyQtGraph`の方が圧倒的に高速に描画を行うことができます。
とはいえ文字を流すためのライブラリではないので、今回のケースではもっと適したライブラリが存在しそうな気もしますが（そのようなライブラリをご存知の方がいましたらコメントで教えていただけますと助かります）。

#### nasne連携
ウェブブラウザなどでnasneのIPにアクセスすると、nasneの各種設定を行うことができます、そこで行われている通信を見るとnasneとデータのやり取りを行うAPIが用意されていることが判ります。
そこで、少しググるとAPIの一覧がまとめられているサイトが幾つか存在しますので、目的に応じたAPIをPythonから叩いてあげるとnasneの状態を取得することができます。
具体的には、
`http://{nasneのIPアドレス}:64210/status/dtcpipClientListGet`
で現在接続している`torne`などの情報、
`http://{nasneのIPアドレス}:64220/recorded/titleListGet?searchCriteria=0&filter=0&startingIndex=0&requestedCount=0&sortCriteria=0&withDescriptionLong=0&withUserData=0&id={番組のID}`
で指定した録画番組の情報
が得られます。

5秒毎に再生されている録画番組をnasneに問い合わせて、アプリケーションに反映しています。

# 参考
先人（チャンネルのリストを一部お借りしました。）

https://github.com/nyumen/komenasne

救世主（API有り難い…）

https://jikkyo.tsukumijima.net/

nasne APIいっぱい載ってる。有り難い…

https://github.com/naokiy/node-nasne