OmniAICreator/Qiita-1.07M huggingface dataset:
Reactでグラフを動的に更新する

## やりたいこと
　Reactでグラフを動的に更新したい。
![react_chart.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2632494/174e6b15-ab55-b035-d2a8-d581e43b74c1.gif)

## 前提
+ react 18.2.0
+ chart.js 3.9.1
+ react-chartjs-2 4.3.1

## やり方
次のようにコンポーネントを作る。

##### Mainコンポーネント(親)
　他のコンポーネントを呼び出す要素。ソースコードではApp関数。
　データの変数をstateとして宣言し、子コンポーネントにstateを渡す。

##### グラフ描画コンポーネント(子)
　データ整形やグラフの設定管理を行う要素。ソースコードではSampleChart関数。
　データ(props)を整形し、importしたグラフコンポーネント(例. Line)に渡す。

このようにコンポーネントを作ると、次のような流れでグラフが動的に更新される。

1. グラフの値(**state**)を更新する
1. グラフの値(**props**)が更新される
1. グラフが再レンダリングされる

![react_chart.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2632494/174e6b15-ab55-b035-d2a8-d581e43b74c1.gif)

## ソースコード
~~~React:app.js
import React, { useState} from "react";
import { Line } from "react-chartjs-2";

import {
  Chart as ChartJS,
  CategoryScale,
  LinearScale,
  PointElement,
  LineElement,
  Title,
  Tooltip,
  Legend,
} from 'chart.js';

ChartJS.register(
    CategoryScale,
    LinearScale,
    PointElement,
    LineElement,
    Title,
    Tooltip,
    Legend
  );

function SampleChart(props) {
  const labels = ["2022-01", "2022-02", "2022-03", "2022-04", 
  "2022-05", "2022-06", "2022-07", "2022-08", 
  "2022-09", "2022-10", "2022-11", "2022-12"]

  const GraphData = {
    labels: labels, 
    datasets: [
      {
        label: "Sample", 
        data: props.data, 
        borderColor: 'rgb(255, 99, 132)',
        backgroundColor: 'rgba(255, 99, 132, 0.5)',
      }
    ], 
  };

  const options = {
    maintainAspectRatio: false, 
    responsive: true, 
    plugins: {
      legend: {
        position: 'top', 
      },
      title: {
        display: true,
        text: 'Sample-Chart',
      }, 
    }, 
  };

  return (
    <div className="Chart">
      <Line options={options} data={GraphData} height={400} width={800} />
    </div>
  )
  
}

function App() {
  let initial_data = []
  for (let i=0; i< 12; i++) {
    initial_data.push(Math.random());
  }
  const [data, setData] = useState(initial_data);

  return (
    <div className="App">
      <SampleChart data={data} />
      <button type="button" onClick={() => {
        let random_data = []
        for (let i=0; i < 12; i++) {
          random_data.push(Math.random());
        }
        setData(random_data);
      }}
      >ランダム</button>
    </div>
  );
}

export default App;

~~~

## まとめ
　Reactはすばらしいです。
【Flutter】プロジェクトをgit cloneしたらアプリが動かないときの対処法

# はじめに
Flutterのソースをgithubにあげて別端末でクローンして動かそうとしたら
「Target of URI doesn't exist 'package:flutter/material.dart'」とでてしまい
動かすことができなかったので調べてみた。

# 環境
Windows 11
VS Code 1.71.0
Flutter 3.3.0

# 解決策
コマンドプロンプトで動かしたいソースが入ったフォルダに移動し、以下のコマンドを実行してエディタを再起動する。

```:対処法
flutter pub get
```

# 参考資料
[Visual Studio Code - Target of URI doesn't exist 'package:flutter/material.dart'](https://stackoverflow.com/questions/44909653/visual-studio-code-target-of-uri-doesnt-exist-packageflutter-material-dart)
インターネットゲートウェイとNATゲートウェイ

# インターネットゲートウェイ
**インターネットゲートウェイ**は、インターネットとの接続を担う。
EC2上のインスタンスにWebサイトをおいた場合、Webサイトの閲覧者は、該当のWebページが欲しいというリクエストを送ってくる。このリクエストは、DNSで変換され、パブリックIPアドレスを宛先として送られてくる。しかしながら、EC2インスタンスには、プライベートIPアドレスしか設定できない。**インターネットゲートウェイがリクエストとEC2インスタンスの結び付きの情報を持っており、宛先をプライベートIPアドレスに変換して、該当のEC2インスタンスにリクエストを送る。**
# NATゲートウェイ
車内だけで使いたいサーバーであっても、ソフトウェアのアップデート等でインターネットに接続したいときがある。この場合は、**NATゲートウェイ**を使用する。**NATゲートウェイは、サブネットからインターネットに接続できるが、インターネットからサブネットに接続できないようにすることが可能。**
LPC812MAXで3分タイマー (秋月シリアル7セグ)



x mbed2リビジョン144
x リビジョンの変更がわかる人むけ


目的
GPIOのテスト


![o_con711.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/00a61719-273d-d853-fc0e-ba62735ef203.jpeg)


```c++



// gpio_7seg_3min_812_1

#include "mbed.h"

//*******   ******   *****  *****
//     *         *   *      *
//    *         *    *****  *  ***
//  *       ****     *      *    *
//  *       *        *      *    *
//  *        *****   *****  *****


int kk;
#define oun_min() for(kk=0;kk<60;kk++){wait_ms(1000);}


#define swclk1  P0_16    //B 9
#define swdio1  P0_17    //G 8
#define en1     P0_7     //R 7


//GPIOの初期化
DigitalOut swdclk(swclk1);
DigitalOut swdio(swdio1);
DigitalOut en(en1);

char seg[32] = {
    0x00,  //0 @ -> ' '
    0x77,  //1 A  o
    0x7c,  //2 B     　combined use "6"
    0x39,  //3 C
    0x5e,  //4 D
    0x79,  //5 E  o
    0x71,  //6 F
    0x3d,  //7 G

    0x76,  //8 H  o
    0x06,  //9 I    　combined use "1"
    0x1e,  //10 J
    0x75,  //11 K
    0x38,  //12 L  o
    0x15,  //13 M
    0x37,  //14 N  o
    0x3f,  //15 O  o　combined use "0"

    0x73,   //16 P
    0x67,   //17 Q　combined use "9"
    0x50,   //18 R
    0x6d,   //19 S　combined use "5"
    0x78,   //20 T
    0x3e,   //21 U
    0x1c,   //22 V
    0x2a,   //23 W  o
    0x64,   //24 X

    0x6e,   //25 Y
    0x5b,   //26 Z　combined use "2"
    0x4f,   //27 [  --> "3"
    0x66,   //28 \  --> "4"
    0x27,   //29 ]  --> "7"
    0x7f,   //26 ^  --> "8"
    0x08    //31 _
};


void seg1(char v)
{
    for(int jj=0; jj<8; jj++) {
        if( (v<<jj) & 0x80 ) {
            swdio=1; //ビットが1
        } else {
            swdio=0; //ビットが0
        }//endif
        swdclk=1;
        swdclk=0; //clk
    }//for
    en=1;
    en=0;
}//seg1


char nn[]= {'O','I','Z','[','\\','S','B', ']','^','Q'};

int comma1=0; // コンマ(小数点)の有効フラグ　1で有効　0無効

//7segの一文字出力 nana_seg
int ns_putc(char ch)
{

    if(ch == ' ') {
        ch = '@';
    } else if(ch == '.') {
        return(0);
    } else if (ch >= '0' && ch <= '9' ) {
        ch = nn[ch-'0'];
    }

    if( comma1 != 0 ) {
        comma1 = (0x80);
    }
    seg1(seg[ch-64] | comma1  );
    comma1 = 0;

    //戻り値
    return(0);
}//ns_putc

//文字列の表示 nana_seg
int ns_printf(char *str1)
{

    //文字の中身がゼロか
    while(*str1) {

        //コンマの処理
        comma1=0;
        if( (*(str1+1) ) == '.' ) {
            comma1=1;
        }

        //一文字出力
        ns_putc(*str1 ++);

    } //while

    //戻り値
    return(0);
}//ns_printf


//メイン関数
int main()
{

    //7セグの初期化
    en=0;
    swdclk=0;
    swdio=0;
    wait_ms(200); //debug

    ns_printf( (char *)"STAR");
    wait_ms(700); //debug

    //3分をカウント
    ns_printf( (char *)"   0." );
    oun_min()
    ns_printf( (char *)"   1." );
    oun_min()
    ns_printf( (char *)"   2." );
    oun_min()
    ns_printf( (char *)"   3." );

    while(1) {} //無限ループ

}//main




```



![o_con833.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/f83b89d1-31de-3f29-a34a-d7976a12b7c9.jpeg)


-4-
【Linux】テキストを環境変数の値に置き換える方法【envsubst】

## テキストを環境変数の値に置き換える方法
`envsubst`コマンドを使用することでテキストを環境変数の値に置き換えられます。
以下のように使用します。

```sample.template
${GREETING}
```
```zsh:ターミナル
$ export GREETING=Hello && envsubst < ./sample.template > ./sample.txt

または

$ GREETING=Hello envsubst < ./sample.template > ./sample.txt

```

```sample.txt
Hello
```
ルーティングとNAT

# ネットワークとルーティング
ネットワークとは、複数のパソコンを互いに通信できるように接続した状態のこと。
パソコンが普及する前は、パソコン同士を一対一で直接繋ぐネットワークがあったが、現在はLANやWAN、インターネットの形でルータを介したデータのやり取りがほとんどである。
会社のようにたくさんパソコンがある環境では、パソコンを一対一で繋ぐと線が多くなるので現実的ではない。そこで、**ルーターにデータを送り、ルーターから目的の相手へ送信してもらう仕組み**にする。これを**ルーティング**という。
# IPアドレスとゲートウェイ
ルーター経由で各パソコンにデータを届けるためには、相手を識別する必要がある。この相手を識別するために必要なのが、**IPアドレス**。
IPアドレスは、クライアントパソコンやサーバーだけでなく、ルーターなどのネットワーク内のすべてのホストに対して設定される。
相手にデータを送信したいときは、宛先のIPアドレスを指定する。
そのテータは、まずネットワーク同士を接続しているルーターに届けられる。ルーターは自分のネットワーク内のホスト宛なら、データをそのホストに届けられるが、
そうでなければ、さらに別のルーターに転送される。
ルーターには、どこに送れば相手の近くに届けられるかが、予め設定されていて、このようにバケツリレーで、データを届けられる。
ルーターはネットワークの門となる位置にあることから、**ゲートウェイ**とも呼ばれる。ゲートウェイの内「自分以外の全てに接続されているもの」のことを**デフォルトゲートウェイ**と呼ばれる。
# IPマスカレード（NAPT）
同じ会社内パソコンにデータを届けたい場合は、ルーターが宛先を知っているが、離れた場所に住む友人にデータを送る場合は、インターネット上のサービスを使用することがほとんどである。つまり、**LAN内以外は、基本的にインターネットを経由するということ。**
LANからインターネットにデータを転送するときに、LAN側の出入り口となるのが、**ゲートウェイ**。ゲートウェイとは役割のことを指すので、実際に担当する機器としては、**ルーターがゲートウェイ相当する役割を果たす。**
ゲートウェイはLANから送られてきたデータをインターネットに転送し、インターネットからきたデータを対象の機器に送る。
現在は、LANの中の機器は、すべてのプライベートIPアドレスが振られる傾向にある。しかし、インターネット上ではグローバルIPアドレスがなければ識別できないので、ゲートウェイがプライベートIPアドレスをグローバルIPアドレスを変換し、同じ家庭内や社内の人は、一つのグローバルIPアドレスを共同で使用する。この変換を担当するのが**IPマスカレード**（NAPT）。
# NAT
IPマスカレードを使うと中から外へは出ていけるが、外から入って来ることはできない。IPマスカレードは、中から外へのリクエストに対し、外から中へのレスポンスは返すが、**外からのリクエストには答えない。**　
ただし、これはクライアントのケースで、サーバーをLANの中におく場合は、当然外からのリクエストにも応える必要がある。この場合、IPマスカレードの設定で、サーバーだけを双方向に通信できるようにする。しかし、IPマスカレードでは、１つのグローバルIPアドレスしか設定できないので、複数台で構成するときは、グローバルIPアドレスが複数設定できる**NAT**(Network Address Transition)を使用する。
## IPマスカレードとNATの違い
IPマスカレードとNATは良く似ているが、
IPマスカレードは一対多であるのに対して、NATは多対多。
IPマスカレードはポート番号の変換もするが、NATはポート番号の変換はしない。
オリジナルアプリ　内山農園



# はじめに

こんにちは。@Taro_Kanameです。卒業制作で初めて製作したオリジナルアプリです。このアプリは、実家の兼業農家で起こりうる、B級品の食品ロス問題を少しでも解決できたらと思い製作しました。

# アプリ開発のきっかけ
私の実家は兼業農家をしています。農協で販売できるものA級品は余ることはありませんが、B級品となったものは毎回コンテナ約1箱〜多い時は5箱分を処分しています。ご近所も農家が多く、畑にまだ食べられる野菜や果物がよく大量に捨てられています。
またB級品の中でも状態がいいものは、捨てるのも勿体無いため両親が知り合いに1件1件電話をして、安価もしくは無料で渡しています。これに伴いもう一つ問題になってくるのが、野菜に欠けた費用に対して収益が少なくなるため、毎年赤字へと繋がっています。
![イメージ写真.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667900/f6ccc2a3-db99-8c6a-3ac6-57330073d812.png)

# 使用環境
・ruby 3.0.1
・Ruby on Rails 6.0.3
・PostgreSQL 14.4
・AWS EC2
・AWS S3

# 解決のために
### 1. TOPページに収穫予定の野菜を掲載
まずは収穫される予定の野菜を、周知してもらうことが大切だと考えました。
### 2. 20%OFF料金（市場価格）を目立たせる
今までは0円〜安価で渡していた野菜を、適正価格（B級品として）より20%OFF価格を目立たせることにより、この農家に興味を持ってもらいます。
### 3. 野菜&果物のお気に入り機能
ユーザーは自分がお気に入りした野菜や果物をマイページで確認することができます。この機能によって、1度購入を検討した野菜＆果物がすぐに出てくれば、購入してもらえる可能性が高くなります。
![スクリーンショット 2022-09-02 15.38.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667900/9b9813a1-4ea7-d340-a6d4-ec51dce00cd7.png)

### 4. メール通知機能
アプリ以外でも野菜の周知をしてもらう必要があると考え、この機能をつけました。管理者が新規登録をすると同時に登録ユーザーのメールアドレスにその内容がメールで届きます。

### 5.　一つのアプリで農業スケジュールも
管理者（農家）は今後の農業スケジュールも登録ができます。これによりこのアプリ1つで販売とスケジュール管理ができます。

# 使い方
新規登録を行わなくても、収穫状況情報が見れます。
登録ユーザーのみしか見れないという限定を付けると、野菜の購入可能性が低くなると考えたからです。

### 1.　新規登録をするとお気に入りすることができます。
また未ログインの場合は、お気に入りボタンが押せません。（画像は未ログイン時）せっかくお気に入りボタンを押しておいたのに、ログインしてなかったから、お気に入りが消えちゃった。という経験があり、そのお気に入りした商品が覚え出せなく、再購入のきっかけを失ったことがあったため、この機能をつけました。![スクリーンショット 2022-09-02 16.08.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667900/cb3da91d-2af8-a44c-336f-94f8a81854da.png)


### 2.　お気に入り野菜＆果物はマイページで確認ができます。
![スクリーンショット 2022-09-02 16.04.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667900/3554fbe7-e4cb-7302-313d-145a60f8a61a.png)

### 3.　管理者は新規野菜や果物を登録ができます。
登録ボタンを押したと同時にユーザーにメールが届きます。
![スクリーンショット 2022-09-02 15.38.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667900/c2080603-2a33-2543-4890-31c8b4fa4f76.png)
![スクリーンショット-2022-09-02-16.10.01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667900/a4aa38c2-9500-49db-0c8c-7085a680d687.gif)

# 今後の展開
### 1.　LINE通知機能
スマホユーザー用にLINE通知機能をつけます。
### 2.　農業スケジュールに天気予報表示
農業をする上で重要なポイントとなってくる天気予報を表示させます。
### 3.　農業スケジュール詳細ページにコメント機能
詳細ページに予定だけではなく、その日作業した内容をコメントできるようにコメント機能をつけます。

# 最後に
最後までお読みいただきありがとうございます。毎回畑に捨てられている野菜を見るたびに、勿体無いなーと感じておりました。また苦労して作った野菜や果物なのに、赤字続き。作る意欲も薄れていく両親を見て、少しでも役に立てればいいと思い製作したアプリです。初めて作ったアプリですので、今後の展開する機能はもちろんさらなるブラッシュアップをしていきたいと思っております。

http://3.114.161.24/
UTF-8で全角を2、半角を1とカウントしたい場合はmb_strwidthを使う

# 概要

めったに必要な場面は無いけれど、UTF-8で入力した文字列をShift-JISで送信する際に、上限バイト数の制限が必要な場面があり文字数が揃わなかったので迷いました。
UTF-8は可変バイト数？らしく1文字3バイトとカウントされたりする。


## 関数

**strlen** = 文字列のバイト数を取得（文字コードによって変わる）

**mb_strwidth** = 文字列の幅を取得（全角は2、半角は1とカウント）

（追記：2022-09-03 0:01）コメントいただきましたが、 `mb_strwidth` だとギリシャ文字、ロシア文字などは全角の文字でも1とカウントされるみたいです。
日本語以外や、日本語でも記号などが含まれる文字列の場合は、想定した動きにならない可能性があるのでご注意ください。

# strlen

## 文字コードがShift-JISの場合

```php:php
echo strlen("あいうえお");
// 10

echo strlen("ABCDE");
// 5
```



## 文字コードがUTF-8の場合

```php:php
echo strlen("あいうえお");
// 15

echo strlen("ABCDE");
// 5
```

# mb_strwidth

## 文字コードがShift-JISの場合

```php:php
echo mb_strwidth("あいうえお");
// 10

echo mb_strwidth("ABCDE");
// 5
```



## 文字コードがUTF-8の場合

```php:php
echo mb_strwidth("あいうえお");
// 10

echo mb_strwidth("ABCDE");
// 5
```
How to use dictionary without 'KeyError' in python?

# How to use dictionary without 'KeyError' in python?

`dict` is a built-in data type of Python that can store key and value combinations of data.

## dict

```python
d = {'count': 0}
print(d['count'])

>> 0

d['count'] += 1
print(d['count'])

>> 1
```

It can be used by mapping the value to the existing key as above.

```python
print( d['name'] )

>> Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 1
```

Accessing a key that does not exist may throw a KeyError exception.

This is also the reason why you need to initialize the value to a specific key of the dictionary in order to use the dict without problems.

## defaultdict

```python
from collections import defaultdict

dd = defaultdict(int)
dd['count'] += 1
print( dd['count'] )

>> 1
```
 
So I prefer the defaultdict, which can be used without initializing the key.

It's good because you don't have to write logic to check and initialize the key whenever you need it.
... and it also improves code readability.

However, I think you can freely choose according to your code style.

## More deeper

It was nice to use defaultdict without initializing a specific key.

but I thought,
`Isn't it possible to use a deeper level without initializing it?`

```python
from collections import defaultdict

student = defaultdict()
student[1][3][21]['name'] = 'John'

>> Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 1
```

If you write it like the example above, you may get 'KeyError'.

### Use factory function

```python
from collections import defaultdict

def deeper():
  return defaultdict(deeper)

d = deeper()

d['human']['name']['first'] = 'John'

print(d)

defaultdict(<function deeper at 0x7fbd70256cb0>, {'human': defaultdict(<function deeper at 0x7fbd70256cb0>, {'name': defaultdict(<function deeper at 0x7fbd70256cb0>, {'first': 'John'})})})
```

much better

when accessing an uninitialized {key:value}, you can lazyly assign a defaultdict.
CSS

１．はじめに
　　本ブログではUdemyのWeb Developer Bootcampを受講した中で、
　学習した内容のアウトプットを兼ねてWeb開発の手法を記載していく。
　
２．概要
　　前回HTMLについて学習しWEBページ全体の構造やどこに何がどの順番であるかなどをタグ付けすることで表していることが分かった。
　WEB画面の色や字の見た目などのスタイルを設定することができるCSSについて記載する。

３．本文
・CSSの役割
　　文書の構造を表すHTMLに対してCSSは文書の「見た目」を記述することができる。
　HTMLファイルの中にスタイルを記述することも可能だが、
　HTMLファイル(index.htmlなど)とは別にCSSファイル(style.cssなど)を定義することが一般的であり、推奨されている。

・CSSの基本構文
　　CSSを別ファイルとして記述するということは何かしらの形でHTMLファイルとCSSファイルを紐づける必要がある。
　CSSを適用する際は以下のようにHTML内のlinkタグ内にCSSファイルのパスを記述する必要がある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780477/9d09c9d4-8e1c-6bd3-7ba7-51e7dae9acc4.png)

　上記の関連付けが完了していればCSSにスタイルを記述していくだけでHTMLファイルを開いたときにスタイルが適用されるようになる。
　以下にCSSの基本的な構成を示す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780477/bf59336a-7d5f-59d7-06af-883981d0b256.png)
　大きく3つの部品で構成されておりそれぞれ、セレクター・プロパティ・バリューと呼ぶ。

　設定例：h1（セレクター）のフォントサイズ（プロパティ）を10px（バリュー）に設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780477/5b964191-c2e2-ccb2-445f-7e2f9906d3d1.png)


・セレクター
　　「HTMLのどの部分にスタイルをあてるか」を記述する。
　HTML側で指定したタグやid、crassを記述することで、その後記述するスタイルが該当するタグ等に適用される。

　セレクターの例
　HTMLタグ：
　HTMLファイルで記述したタグをセレクターとして使用することができる。（h1、div、pなど）
　id：
　inputとlabelを紐づけるために使用したidだが、CSSの適用対象としても設定可能。
　crass：
　id同様任意のHTMLタグにcrass属性を設定することができる。（idと異なり一意である必要はない）
　など…

・プロパティ
　　セレクターにて「どこにあてるか」を記述したので次は「何をあてるか」である。
　「文字の太さ」や「背景の色」、「枠の幅」などセレクターで選ばれている部分について設定値を変更したい項目を指す。

　プロパティの例
　font-size：フォントのサイズ
　color：文字色
　background-color：背景色
　border：その要素の境界線
　など…

・バリュー
　　セレクター及びプロパティで「どの項目の何を」まで記述されているので残りは実際の設定値を記述する必要がある。
　「10px」や「赤色」、「本体の2倍の幅」など数値や大きさを指す。

・その他のCSS記述方法
　　基本構文のように書くのではなく既存のHTMLタグ内にスタイルを記述することやstyleタグ内でスタイルを記述することも可能だが、
　こちらは非推奨とされている。
　理由としては複数のHTMLに対して共通のCSSを充てることが難しい、
　異なるCSSをあてたいときにHTMLごと書き直す必要がある、などがある。

　タグ内に記述したスタイル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780477/b9f00b24-01db-77d4-e76b-3346732be2fa.png)
　headタグ内にstyleタグで記述したスタイル
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2780477/5a94575c-3c8c-d6d4-82c9-9a4c9ed67aec.png)

４．感想
　記述ルールや構造自体を理解することは難しくなかったが、HTMLのタグ同様プロパティの数がとても多くて（すべて覚える必要がないにしても）どれが重要か分けることに苦労した。
線形代数


# 線形代数

12 固有値固有ベクトル：バウンディングボックスを作る時に使う。
https://www.youtube.com/watch?v=_TgBFx0jwRQ

13 対角化
https://www.youtube.com/watch?v=FTC_aekgqCg

# ベクトル空間
https://www.youtube.com/watch?v=F0mkAiRiLik&list=PLp8nqzIroHbdGUBBw0poPww8U-adRTCyW

# ベクトル解析
https://www.youtube.com/watch?v=ZS51xsn7onA&list=PLp8nqzIroHbdGUBBw0poPww8U-adRTCyW&index=6

https://www.youtube.com/watch?v=cB38FzDgc0c&list=PLoJM-P-S8JC7ZBL8lDdDwwJanY6f5Ve2K
maya python カメラを選択

```python
import maya.cmds as cmds

# Get all cameras first
cameras = cmds.ls(type=('camera'), l=True)

# Let's filter all startup / default cameras
startup_cameras = [camera for camera in cameras if cmds.camera(cmds.listRelatives(camera, parent=True)[0], startupCamera=True, q=True)]

# non-default cameras are easy to find now.
non_startup_cameras = list(set(cameras) - set(startup_cameras))

# Let's get their respective transform names, just in-case
non_startup_cameras_transforms = map(lambda x: cmds.listRelatives(x, parent=True)[0], non_startup_cameras)
cmds.select(non_startup_cameras_transforms)
```
【PySpark】縦持ちデータを横持ちに変換(pivot)してデータを集計してみた

# はじめに
本記事では PySpark でデータ加工や分析をされている方向けに、簡易的な縦持ちのテーブルを横持ちで見れる形へと回転するような変換をしていきます。

一般的にデータを見るという点では横持ちのテーブルの方が整っており、行の数も少なく見やすいのではないかと思います。
一方でデータ加工には縦持ちのテーブルの方が行に対してより複雑な情報を加えたりなど柔軟に操作できます。
縦に更新されていくデータを、表の見やすさために横持ちへ変換することが使用用途として考えられます。

# 使用する関数について
今回は横持ち変換をするために、 pivot という関数を使用します。
pivot は回転軸という意味を持ち、縦に続いていたデータを回転させて横に続くようなテーブルへと変換してくれます。

Pandasでは日本語で解説されている文献が多いものの、PySpark では少ないので記事にしてみました。

# 本記事のスタートとゴール
スタートは以下のカラムを持つ、ある試験で受験者がそれぞれ3科目試験を受けた際の点数が縦に記録されたテーブルを用意します。

・taker_no : 受験者の番号(6人)
・subject : 試験科目(3科目)
・score : 試験の点数(100点満点)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704291/283826a8-a5e7-7bde-8f51-3cdc6298a303.png)

ゴールは上記の試験の点数を横持ちに変換して、受験者の試験の得点が試験科目ごとに横に展開される状態にすることです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704291/4307111b-b877-6db8-8e24-026d8e309d2d.png)

# 作業環境
・Databricks を使用
・バージョン: Apache Spark 3.2.1
# 縦持ちテーブルの横持ち変換
まず縦持ちのテーブルを用意しましょう。
```python
# データ作成
data = [
    (1,"国語",85), 
    (2,"国語",45), 
    (3,"国語",95),
    (4,"国語",30), 
    (5,"国語",55), 
    (6,"国語",50),
    (1,"数学",100), 
    (2,"数学",70),
    (3,"数学",65),
    (4,"数学",45), 
    (5,"数学",15),
    (6,"数学",35),
    (1,"英語",65),
    (2,"英語",55),
    (3,"英語",75),
    (4,"英語",75),
    (5,"英語",80),
    (6,"英語",40),
]

columns= ["taker_no","subject","score"]
df = spark.createDataFrame(data = data, schema = columns)

display(df)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704291/9c347e54-ff21-4711-fd5a-4c9a02317665.png)

次に作成したデータを横持ちに変換していきます。

縦持ちテーブルだと、現状3科目の試験の点数が縦に記録されているので受験者1人につき3行存在します。
これを1行で横持ちに試験の点数を並べていくので、まず受験者ごとに groupby していきます。
次に、pivot を使用します。引数には横持ちにしていく試験科目である 「subject」 を指定します。

最後に横持ちに展開したカラムに「score」を埋めていくのですが、ここでひとつ注意点があります。
groupby した後には max や avg など集計関数を仕様上使わなければなりません。
今回のデータではグルーピングした際に値は唯一無二になるので、集計関数を使う意味はないのですが、やむを得ず使用した形になります。 max を使用しましたが、他でも問題ありません。(count など値が変化する関数は NG )
※ グルーピングした際に値が複数存在する場合はどのような集計するか用途によって考える必要があります。

```python
# 横持ち変換
df = df.groupby("taker_no").pivot("subject").max("score")
display(df.orderBy("taker_no"))
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704291/be4faa46-f4ee-6686-02bb-7f11b59c9101.png)

横持ちにテーブルを変換できたことを確認しました。
# 注意点
PySpark の pivot によって行われる処理は他の一般的な PySpark の変換処理に比べ、重いものとなっております。
本記事で使用したような小さいデータでは問題なく実行されますが、大規模なデータを扱う際にテーブルの列が数百～数千増えるような pivot の処理を実行するとうまく処理が完了されない可能性がありますので注意が必要です。

# まとめ
pivot を使用することにより、縦持ちのデータを横持ちへと変換してみました。
これによりテーブルを見やすくできたのではないかと思います。
用途によって利用していただければと思います。
Outlookで受信メールの本文を常にテキスト形式で開く設定

# 概要

「メール本文のリンクについて、 **リンク先URLに問題無いか確認できるように表示** したい」
「メール本文のフォント種類や大きさや色などの **スタイルが適用されない状態に** したい」

といった時。

# やり方

『オプション』。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/1de9ea55-2bda-e9b2-05dc-4b88e633f357.png)

『トラストセンター』 ⇒ 『トラストセンターの設定』。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/9ea58dd6-2a2e-a5f6-914a-0427d59468b2.png)

『電子メールのセキュリティ』
の
『すべての標準メールをテキスト形式で表示する』
『すべてのデジタル署名されたメールをテキスト形式で表示する』
のチェックをONに。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/71f15a8b-aca0-cec1-e784-8ef0c193557a.png)

# 参考サイトさん

https://www.c-3.co.jp/blog/archives/204

# バージョン

Microsoft Windows [Version 10.0.22631.4037]
Microsoft Outlook for Microsoft 365 MSO (バージョン 2407 ビルド 16.0.17830.20166) 32 ビット
ビルドアクション MauiFontで埋め込んだttf・otfファイルをStreamとして読み込む


https://docs.microsoft.com/ja-jp/dotnet/maui/platform-integration/storage/file-system-helpers?tabs=windows#platform-differences

ビルドアクションMauiAssetsやResources/Rawについてしか細かい記載がないが、ビルドアクションがMauiFontでも読めるっぽい。
`アプリ パッケージにバンドルされているファイルを開くには、`とあって、どのビルドアクションまで対応してるのか詳細まではいまいち・・・。

![スクリーンショット 2022-09-02 145138.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92451/9d35b434-53a8-a3a7-f988-de59e31a59e3.png)

```c#
// FileSystem: Microsoft.Maui.Storage.FileSystem
// Stream: System.IO.Stream
Stream stream = FileSystem.Current.OpenAppPackageFileAsync("NotoSansJP-Regular.otf").Result;
```

  　　
　
　
　
　

[SkiaSharp](https://github.com/mono/SkiaSharp)のSKTypefaceの生成に埋め込んだフォントを使いたかった。

```c#
var typeface = SkiaSharp.SKTypeface.FromStream(stream);
```
Herokuの代替になりそうなもの17個

mediumに書いた記事をシンプルなリストにしました。

#### Fly.io 
https://fly.io/

#### render 
https://render.com/

#### Railway 
https://railway.app/

#### pythonanywhere
こちらは名前の通りpython専用です 
https://pythonanywhere.com

#### APPLIKU 
https://appliku.com/

#### Adaptable 
https://adaptable.io/

#### Qoddi 
https://qoddi.com/

#### Deta Cloud 
https://www.deta.sh/

#### Engine Yard 
https://www.engineyard.com/

#### OCI Cloud 
https://www.oracle.com/cloud/free/

### IDEと一体型のサービス
#### Glitch 
https://glitch.com/

#### replit 
https://replit.com/

### 今後ローンチ予定のサービス
#### Nopeus 
https://nopeus-co-salfati-group.vercel.app/

### 自前でホスティングする場合の代替ソフトウェア
#### Coolify 
https://coolify.io/

#### Capover 
https://caprover.com/

#### dokku 
https://dokku.com/

#### piku 
https://github.com/piku/piku
SOLID原則の S (Single Responsibility)　単一責任の原則について調べてみた

## そもそもSOLID原則とは
オブジェクト指向プログラミングにおいて変更しやすい・理解しやすい・再利用しやすいモジュールを設計・開発するための原則です。下記５つの原則の頭文字を取ってSOLID原則と呼ばれています

 - Single Responsibility Principle: 単一責任の原則
 - Open-Closed Principle: 開放閉鎖の原則
 - Liskov Substitution Principle: リスコフの置換原則
 - Interface Segregation Principle: インターフェイス分離の原則
 - Dependency Inversion Principle: 依存性逆転の原則

要するに**誰でもメンテナンスしやすいコードを書くためのルール**です

## なぜメンテナンスしやすいコードを書く必要があるのか

メンテナンスしづらいコードは...
新規参入した人が既存のコードを読みづらい、理解に時間がかかる
新しいコードを追加しずらい、追加するのに時間やリファクタリングが必要になる、追加すると不具合が発生する
既存のコードを再利用しづらい

こんな事を感じたことはないですか?
→ **メンテナンスしやすいコードを書くためのルールに則ろう**

## SOLID原則のS Single Responsibility  単一責任の原則について

ソフトウェアを構成する個々のモジュールの責任は、たったひとつにするべきという原則です。

対象Aと対象Bに関して責任を負っているモジュールがあった場合、Aの動作のためのコードとBの動作のためのコードが一体になってしまっていることになります。そうすると、Aの動作に関する改修をしたつもりが、その影響がBにも及んでしまいバグが生まれてしまう可能性があります。

正確には...
「単一責任の原則」は「一つのクラスは一つの役割を持たせる」と勘違いされやすいそうですが
「**一つのクラスは単一の利用者や機能に対して責務を負う**」が正しいそうです。


同じようなコードを記載しないというDon't Repeat Yourself　の頭文字を取ったDRY原則があります。
同じようなコードやロジック、メソッドであっても対象、責任が違えば単一責任の原則にもDRY原則にも違反しません。


## 所感
道具の存在と使い方を知っていれば必要となったときに　約立つように、原則の存在と正しい使用方法をしっておくべきだなと思いました。
maya python slect curves by name

```python
import maya.cmds as cmds
curve_transforms = [cmds.listRelatives(i, p=1, type='transform')[0] for i
in cmds.ls(type='nurbsCurve', o=1, r=1, ni=1)]
selectList = []
for c in curve_transforms:
    if "Root" in c or "Neck" in c:
        selectList.append(c)
print(selectList)
cmds.select(selectList)
```
docker-composeで自動Flyway

## モチベーション
開発環境などでFlywayなどのマイグレーションツールを使うとき、自動でマイグレーションして欲しいですよね。今時の開発環境なら大体DBはローカルでdocker-compose upでシュッと立ち上げる人が多いとおもいます。Flywayもcomposeに登録しておけばFlyway自動で適用できるんじゃね…？となってやってみたんですが、思ったよりハマりどころが多かったのでメモを残します。

MySQL + Flywayの組み合わせでやりましたが、他の組み合わせでも参考になるかもしれません。

## 基本方針
Flyway公式のdockerイメージを使います。

https://github.com/flyway/flyway-docker
https://hub.docker.com/r/flyway/flyway/

また、DB設定(特にパスワード)は.envに書くようにします。だいたいこんな感じになります。

```yaml
  db:
    image: mysql:8.0.30
    ports:
      - "3306:3306"
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci --ngram_token_size=2
    healthcheck:
      test: MYSQL_PWD=${ENV_MYSQL_PASSWORD} mysql -h127.0.0.1 -P3306 -u... -e "quit"
    volumes:
      - /var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=${ENV_MYSQL_ROOT_PASSWORD}
      - MYSQL_PASSWORD=${ENV_MYSQL_PASSWORD}
      - MYSQL_DATABASE=...
      - MYSQL_USER=...
```

`healthcheck`は後ほど説明します。

つづけてFlywayはこんな感じです。

```yaml
  flyway:
    image: flyway/flyway:9.2.1
    command: -url=jdbc:mysql://db -schemas=... -user=root -password=${ENV_MYSQL_ROOT_PASSWORD} migrate
    volumes:
      - ./flyway/sql:/flyway/sql
      - ./flyway/drivers:/flyway/drivers
    depends_on:
      db:
        condition: service_healthy
```

depends_onとDBのURLに先程設定したdbを指定していきます。SQLは./flyway/sqlにおけば、そのファイルを対象にマイグレーションしてくれます。

## なぜかConnection failする
実はFlywayのイメージには、MySQLのドライバーが入ってないのか、古いのかわからないですが、うまくMySQLに繋いでくれません。もうちょっとエラーメッセージ分かりやすくしてくれないかな。`./flyway/drivers`のようなディレクトリを作り、JDBCドライバーをダウンロードして置き、volumeでマウントするか追加したイメージを作るかすれば動きます。

## DB起動中にFlywayが実行されてしまう
DBの起動時にFlywayが実行を試みるものの、DBが起動していないので失敗することがあります。新しいdocker-composeに追加された、依存先にあわせて起動をdelayする機能を使えば、簡単に制御可能です。

今回やりたいのはDBがport待ち受け状態になったらFlywayを実行することなので、health_checkでDBのportを監視しつつ、checkをpassしたら依存するイメージFlywayを実行するようにします。`depends_on`を以下のようにします。

```yaml
depends_on:
  db:
    condition: service_healthy
```

conditionに指定できるのは他にもいくつかあります。

これでおそらく動きます。docker-composeで快適な開発ライフを。
DrawSQLとかいう神アプリめっけ

みなさん、いかがお過ごしでしょうか。

自分は学生生活、最後の夏休みが終わり国家試験の対策が始まりました。
データベースの問題に書かれているER図を見てふと思ったことがあるんですよ。ER図から自動的にcreate table文を生成するアプリがあれば超便利だなと。世界のどこかにないかと思いまして調べてみたところありました。

ブラウザ上で作図ができて自動的にcreate table文を生成してくれる便利なサイト
* [DrawSQL](https://drawsql.app/)

# サブスクライブ
|HOBBYIST|STARTER|GROWTH|LARGE|
|-------|-|-------|------|
|$ 0/months|$ 15/months|$ 49/months|$ 99/months|
|$ 0/years|$ 135/years|$ 441/years|$ 990/years|
|Public diagrams only|5 private diagrams|∞ private diagrams|All features from growth|
|15 tables/diagram|50 tables/diagram|200 tables/diagram|Unlimited tables/diagram|
|1 user|1user|Up to 5 users | 
|||Diagram versioning and access controls|Enterprise SLA and controls|

一応オープンソースプロジェクトのために別の無料プランがあるみたいです。


# それでなにがすごいの？

**うっとうしい作図をしなくて済む**
Figma だったり Googleのdraw.io だったりは、テキスト配置してグループ化して...
とかなり複雑な操作が必要で、かなり操作慣れてからでないと作図ができなかいじゃないですか。かなり致命的ですよね。
このサイト名のとおりDBのためのアプリなので、元から
表や列の記載やコメントも付与できるのですごい良き。
しかも関係を表すための矢印をかけますので間違いに気づきやすくなりますね。
（コメントに１０行とか書くバカはいないと信じてる。まさかね。）

MySQL、PostgreSQL、Microsoft SQLServer、MariaDBに対応していてそれぞれの記述構文でsqlファイルをエクスポートしてくれるっぽい

かなりの数のテンプレートが存在しているので、作ろうと思ってる似たようなサービスを探して見つけて、それを基準に追加していくって感じで作成することができますね。

# 終わりに
2020年くらいにDrawSQLの記事がいくつかあるのでそちら見てみても良いかもしれません。
便利なサイト DrawSQL 開発にどうですかね？
え？お金問題？学生なのでわかりません！プロジェクトに携わっている人に一度相談してみては？

それでは、みなさんよい１日を～
RailsコードをGoで書き直して、FFIを使ったらメモリリークした話




先日、[速度改善のためRailsコードをGoで書き直して、FFIを使ってみた](https://qiita.com/t_mapico/items/9eadf5bee5561c3fb589) という記事を書いたのですが、
このコードがメモリリークを起こしてしまいました。。


golang初心者のため、C.Cstringがgoのメモリ解放の管理から外れているいうことを把握していませんでした。。


```
return  C.CString(string(resultJSON)) 
```
となっているとこを deferで解放するようにしました。

```
ret := C.CString(string(resultJSON)) 
defer C.free(unsafe.Pointer(ret))

return ret
```


メモリリークしないか1時間くらい動かしてチェック

```

end_time = (Time.now + 60 * 60).to_i

while (Time.now.to_i < end_time)
    # ObjectSpaceはデフォルトがバイト表示
    # psのrssはデフォルトがキロバイト表示
    # Process.pidはカレントプロセスのプロセスID
    puts "[BEFORE] memsize_of_all: #{(ObjectSpace.memsize_of_all * 0.001 * 0.001).round(2)} MB, rss: #{(`ps -o rss= -p #{Process.pid}`.to_i * 0.001).round(2)} MB"
    
   　Ffi::Sample.sampleCalc({:test=>"test"}.to_json)
    
    
    puts "[AFTER] memsize_of_all: #{(ObjectSpace.memsize_of_all * 0.001 * 0.001).round(2)} MB, rss: #{(`ps -o rss= -p #{Process.pid}`.to_i * 0.001).round(2)} MB"
end

```

メモリが増えてないのでOK!
```
[BEFORE] memsize_of_all: 56.8 MB, rss: 173.32 MB
[AFTER] memsize_of_all: 57.76 MB, rss: 173.59 MB
[BEFORE] memsize_of_all: 57.76 MB, rss: 173.59 MB
[AFTER] memsize_of_all: 58.72 MB, rss: 173.59 MB
          :
          :
[BEFORE] memsize_of_all: 53.9 MB, rss: 173.36 MB
[AFTER] memsize_of_all: 54.87 MB, rss: 173.36 MB
[BEFORE] memsize_of_all: 54.87 MB, rss: 173.36 MB
[AFTER] memsize_of_all: 55.83 MB, rss: 173.36 MB
```


ちなみに修正前は、下記のように大変な結果になっていました。。
```
[BEFORE] memsize_of_all: 53.04 MB, rss: 156.92 MB
[AFTER] memsize_of_all: 42.35 MB, rss: 161.63 MB
[BEFORE] memsize_of_all: 42.36 MB, rss: 161.63 MB
[AFTER] memsize_of_all: 43.32 MB, rss: 161.64 MB
          :
          :
[BEFORE] memsize_of_all: 37.1 MB, rss: 2116.28 MB
[AFTER] memsize_of_all: 38.06 MB, rss: 2116.28 MB
[BEFORE] memsize_of_all: 38.06 MB, rss: 2116.28 MB
[AFTER] memsize_of_all: 39.02 MB, rss: 2115.34 MB
```

メモリリークしてないか、気になる場合はチェックした方がいいですね:disappointed_relieved:



### 参考
・[Rubyのメモリ使用量の計測をmemsize_of_allとpsコマンドで行う](https://nishinatoshiharu.com/ruby-profile-memory-usage/)

・[go初心者によるcgoメモリプロファイリング改善に向けた試行錯誤](https://qiita.com/taiyo/items/bf766bd9c5e9e7438f41)
windowsで複数バージョンのNodeJsを管理する(nvm-windows) , うまく切り替えを行けない場合の解決策（2022年）

# windows環境でnvmの使用でひとつのシステム内に 複数のバージョンの Node.js をインストールして運用したいですが、nvm useでバージョンの切り替えはうまくいけませんでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500065/3abee468-af33-4642-e560-5ca914018a4e.png)

```
exit status 145
exit status 1
```

## 解決方法
いろいろ調べると、nodejsのインストールパスを半角スペースなしのpathに変更すると解決できる噂もがあります、私の場合確かに半角スペースがるのパスにインストールされている。
ですが、nvm, nodejsをuninstallし、改めて半角スペースなしのパスに再インストールすることにしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500065/5c38dd62-3351-bec8-e344-154d0b68311f.png)

## ①nvm, nodejsをアンインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500065/9d39af99-cbaa-90c8-e9f3-3824b04f207d.png)

## ②nvm-setup.exeをインストールする

### 最新のnvm for windowsアプリを取得する
https://github.com/coreybutler/nvm-windows/releases/
nvm-setup.exe
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500065/41aa25cf-8ba1-803a-10df-7b9b5a0d7fcd.png)

### nodejsのパスをCドライバ直下にしました　※半角スペースなし
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500065/71d28ccb-4c1f-6040-6dfc-552e6dae95ec.png)

## ③nvmでnodeJsバージョン管理を行い、nodeJsをインストールする
### インストール完了しました、現時点nodeは入れてないので何も認識されません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500065/f7ae3fc3-5b90-3664-14be-d9f4242aa1c8.png)

### ※管理者※でCMDを開き<br>指定バージョンのnodejsをインストールを行う。複数のバージョンをインストール場合、順番にインストールすればよいと
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500065/29cd2fa6-a711-1cca-4b68-2a1e2e1589e0.png)

### インストールが完了できれば、nvm lsでインストールされたnodejsバージョンを確認することができます。
```
nvm ls
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500065/34114dcb-5198-91ec-5c9a-b97f648e44ad.png)

## ④nvmでnodeJsバージョンを切り替える
使用中のバージョンを切り替える場合、nvm use で切り替える
```
nvm use XX.XX.XX
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500065/768ef132-9607-e681-ef31-b64318a7b53e.png)
GASでYoutubeの動画を検索して、自動で再生リストに追加するプログラムを作ってみた。

## はじめに
毎週複数の同じ検索ワードで検索しては、再生リストに追加してYoutube動画を見ていました。
それが面倒になり、自動化できないかプログラミングしてみました。
[PythonでYoutubeの動画を検索して、自動で再生リストに追加するプログラムを作ってみた。](https://qiita.com/drafts/f376c092160ba1a4d2e5/)
上記のGASバージョンです。
Pythonで週一定期実行したかったのですが、方法がみつからず。
GASなら定期実行ができるので移植しました。

## 環境
- google app script
- youtube api v3
- windows 10

## 仕様
- 7日以内にアップロードされた動画を対象とする
- 各検索ワードに対して、関連度が高い1つの動画を再生リストに追加する
- すでに再生リストに含まれる動画は重複しないようにする

## 流れ
1. youtubeの認証を通す
1. 7日前の日付を取得する
1. 検索ワードで検索結果を取得する
1. すでに再生リストに含まれるかチェックする
1. 検索された動画を再生リストに追加する
## つまづいたところ
- Youtube appのマニュアルのJavascriptの記述では実行できない
    - javascriptじゃないのかよ！！！

## コード
``` javascript

function searchVideosByKeywords(keywords,strLastWeek){
  var videoIdArray = []
  for(let indKeyword=0; indKeyword < keywords.length;indKeyword++){
    var searchResponse = YouTube.Search.list(
      "id,snippet",
      {
        q: keywords[indKeyword],
        type: "video",
        regionCode: 'jp',
        maxResults: 1,
        publishedAfter: strLastWeek,
      },
    );
    // console.log(searchResponse['items'][0]['id']['videoId']);
    // console.log(searchResponse['items'][0]['snippet']['title']);
    videoIdArray.push(searchResponse['items'][0]['id']['videoId']);
  }
  return videoIdArray;
}

function insertVideosIntoPlaylist(playlistItemsListResponse,videoIdArray,strPlaylist){
  var videoAlready = []
  for (let itemVideo in playlistItemsListResponse["items"]){
    videoAlready.push(playlistItemsListResponse["items"][itemVideo]["snippet"]["resourceId"]["videoId"]);
  }
  // var id = "q4qYRIJzlCs";
  for (let indVideo in videoIdArray){
    if(! isExistInArray(videoIdArray[indVideo],videoAlready)){
      var playlistItemInsertResponse = YouTube.PlaylistItems.insert(
        {snippet:{
          playlistId: strPlaylist,
          resourceId:{
            videoId: videoIdArray[indVideo],
            kind:"youtube#video",
          }
        }
        },
        "snippet",
      );
    }

  }

}

function collectNogizakaRadio(){
  const PLAYLIST_ID = "PLophPL_kQhKnXBP3y78orNmdNZDxNmMQS"
  var keywordArray = [];
  keywordArray.push('乃木坂');
  keywordArray.push('日向坂');
  keywordArray.push('欅坂');

  var dtNow = new Date();
  var dtLastWeek = new Date();
  dtLastWeek.setDate(dtNow.getDate() - 7);
  // console.log(dtLastWeek);
  const strLastWeek = dtLastWeek.toJSON();
  // console.log(strLastWeek);

  var videoIdArray = searchVideosByKeywords(keywordArray,strLastWeek);

  var playlistItemsListResponse = YouTube.PlaylistItems.list(
    "snippet",
    {
      playlistId: PLAYLIST_ID
    }
  );
  insertVideosIntoPlaylist(playlistItemsListResponse,videoIdArray,PLAYLIST_ID);
  console.log("done");
}

function isExistInArray(str,ary){
  var bool = false;
  for(let ind in ary){
    bool = bool || (str == ary[ind]);
  }
  return bool;
}
``` 
## おわりに
このプログラムで以下を含みます。
1. 特定のキーワードでYoutube動画検索したときの結果の取得
1. 特定のYoutube再生リストの動画の取得
1. 特定のYoutube再生リストに特定の動画を追加する

Youtubeのときと違って、トークンとか管理しなくていいのは楽。
しかし、なぜAPIごとの記法が異なるのか、たどり着くまで大変だった。

これで運用してみたいと思います。

## 困っていること
Youtubeアカウントをメインアカウントではなく、
ブラインドアカウントから再生リストを操作したいのですが、できません。
方法をご存じの方がいたら教えてください。
Pythonでよく使うこと。コード、コマンド、スクレイピング、Anaconda、selenium

個人的によく使うことをメモしておきます。使うんだけど忘れちゃうので。
思いついたらどんどん加筆していきます。

# 仮想環境をbaseに切り替えるコマンド

```
$ conda activate
(base) $
```

参考）Conda コマンド
https://www.python.jp/install/anaconda/conda.html


# Google ChromeとChromeDriverのバージョン不一致のとき
ChromeDriverのinstall

```
$ pip3 install chromedriver-binary==79.0.3945.36.0
```
chromeのバージョンのひとつ下くらいのDriverのバーションをインストールする

参考）【Python/Selenium】ChromeDriverバージョンエラー対処法
https://yuki.world/python-chrome-driver-version-error/

chromedriverリリース履歴
https://pypi.org/project/chromedriver-binary/#history

# Seleniumのバージョン確認
```
$ pip show selenium
```
# Seleniumのバージョン最新版にアップデート
```
$ pip install -U selenium
```

# Google ChromeとChromeDriverのバージョン不一致のとき　更新版
Selenium 4.6から、Selenium自体にChromeDriver自動更新機能「Selenium Manager」が搭載されたことで、このシンプルな記述だけで済むようなりました。
```py
from selenium import webdriver
 
driver = webdriver.Chrome()
```
参考）【Selenium】ChromeDriver自動更新で楽する方法【Python】
https://yuki.world/python-selenium-chromedriver-auto-update/

# seleniumのoption
headlessとか

```py
from selenium import webdriver

options = webdriver.ChromeOptions()
# 必須
options.add_argument('--headless')
options.add_argument('--disable-gpu')
# エラーの許容
options.add_argument('--ignore-certificate-errors')
options.add_argument('--allow-running-insecure-content')
options.add_argument('--disable-web-security')
```
参考）headless chromeをPythonのseleniumから動かして引数を考えた (Ubuntu 16.04)
https://vaaaaaanquish.hatenablog.com/entry/2017/06/06/194546
Laravelでweb.phpの変更がキャッシュで反映されない場合のtips

## バージョン
- Laravel v9.21.6
- PHP v8.1.8

## やりたいこと
Laravelのルーティングが反映されない場合、`bootstrap/cache/routes-v7.php`を消すと反映されるようになります。
```
 root/
    ├ app/
    ├ bootstrap/
        └ cache/
            　├ config.php
            　├ packages.php
            　├ services.php
            　├ routes-v7.php // このファイルを消す
```
社内用語ワードウルフをやってみたら盛り上がった！

社内交流+ドメイン知識獲得を目的に社内用語ワードウルフを開催しました。

## 背景

技術組織内にサブプロジェクトとして組織開発というものがありその活動の一環です。
1Qは技術組織内が主でしたがKPTで他部門との交流も行いたいとのことで7月は「ウソつき自己紹介」、8月はこちらの「社内用語ワードウルフ」を開催しました。
準備は大変だったものの、盛り上がったので紹介します。

## ワードウルフとは

当日使った資料を引用

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692378/8381ad12-477a-c817-7d66-d02692cf1951.png)


お題に社内用語を交えるというのが社内用語ワードウルフです。軽く見た感じ他でやった人いなさそう

例えば取引先の名称を出したり、ビジネスロジックの名称を出したり、弊社だと自動車ローン関連の用語も取り入れました。

## お題の準備

1. 用語集を作る
    1. 社内用語をひたすら列挙していきます。
2. お題を作る
    1. 社内用語に対向する用語をえいやで決めます。（対向は社内用語に縛らないほうがやりやすいと思います）
    2. 多数派に類似する広く知られている用語、少数派に社内用語とかにすると、少数派の逆転勝利のしやすさを防げる気がする。

## 実施方法

社内周知しつつ15時からの30分で実施しました。meetを使いオンライン形式です。
説明8分、ゲーム15分、感想7分のタイトなスケジュール。

細かい部分は当日使った資料を

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692378/fe327a94-6e7b-37bb-4223-629216b6325f.png)



一応ゲームマスター1人、グループ複数でも行えるようにしました。
結果的にはゲームマスター2人と2グループ(4人ずつ)で各ブレイクアウトルームに入り行いました。

慣れてくればゲームマスターが1人でも行けそうですが、初回ということもあり、話す人のローテーションとかタイムマネジメントとか含めると、結果的にはグループ毎にゲームマスターがついたほうが安全な気がします。

## 感想とフィードバック

### 開催時間

2つのお題で終わってしまったので、消化不良感はありました。とはいえ15時頃に1時間枠取るのもハードルが高い気がして悩みどころです。

実際に参加者の方のフィードバックはバラバラでした

- もう少しやりたかった
- 説明の部分を省けば30分でいいかも
- 1時間欲しいかも
- 夜に飲みながらやってもいいかも

### 盛り上がり度合い

ワードウルフ+社内用語ということで、かなり盛り上がりました。

次のお題を出す際に、ゲームマスターがSlackでお題を出す時間が、空白になるかと思っていましたが、ちょうど直前のお題の感想をみんなで言い合っていてちょうどいい感じでした。
盛り上がっているので、ゲームマスターもコメントしたくなるところですが、次のお題を出すのに専念しました。

### 細かい部分

- お題の数に限りがある。10個くらいしかまだ作れていません。継続的に行い、ネタ切れを避けるには、それなりにお題作りを行う必要がありそうです。
    - 用語集を作り問題に落とすところは、それなりに幅広いドメイン知識を持ってる人がやる必要がある+まぁまぁ時間がかかるのでネックだったりします
        - 用語集という意味だと普段から言語化されているに越したことはないので、そういった取り組みのきっかけにも使えるかもしれません。
- ドメイン知識が身につくというより、身についている前提になりがち。本気でやるなら予習資料を作る必要がありそう
    - 理解度を深める取っ掛かりとしては良いかもしれません。誰を少数派にするかは理解度を考慮する必要もあるかもしれません。
- 参加者が固定化されつつあります。もとい技術メンバーも参加率が低いのも少し課題です。
    - ここらへんはQ毎に行うKPTに取り上げます。

## 終わりに
社内ワークショップというと、色々な取り組みがあるかと思いますが、自分が思いつきトライしてみて盛り上がった部分もあり、手前味噌ですが、他社でやってみても面白そうなので書き出してみました。
LPC812MAXでソフトウェアシリアルを使い「A」を連続出力する(1000bps)


x mbed2リビジョン144
x リビジョンの変更がわかる人むけ



目的
デバッグのテスト

出力先は、 P0_7 RED

![o_con710.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/19062876-4677-6644-9c7e-260f6f96802f.jpeg)


![o_con709.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/24f146c5-237c-b2eb-9002-708144e43763.jpeg)


```c++



//S_SER_A_A_A_812_1

#include "mbed.h"

//仮想シリアルへの一文字出力 1000bps
DigitalOut TX(P0_7);
#define UART_DELAY 1
void pc_putc(char ch)
{
    TX=1;
    TX=0;//Start
    wait_ms(UART_DELAY);

    for(int ii=0; ii<8; ii++) { //Data x 8
        TX=(ch>>ii)&1;
        wait_ms(UART_DELAY);
    }; //for

    TX=1;//Stop
    wait_ms(UART_DELAY);

} //pc_putc

//メイン関数
int main()
{

    //無限ループ
    while(1) {

        //'A'の出力
        pc_putc( 'A' );

        //1秒待つ
        wait_ms(1000);

    }//while

}//main



```



![o_con833.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/8d7546c3-2b0e-31a5-e477-2cac7e1b573d.jpeg)



-3-
ReactとChart.jsで列車ダイヤグラムを作成するwebアプリを作った話

## 概要

[A列車で行こう はじまる観光計画(steam)](https://store.steampowered.com/app/1685460/)用にダイヤグラムを作成するwebアプリを作ってみました。
ご利用は[こちら](https://tenpamk2-blog.netlify.app/apps/react-diagram-maker/)からどうぞ❗
ソースコードは[github](https://github.com/tenpaMk2/react-diagram-maker)で。

主要Techは下記の通り。

- [Vite](https://vitejs.dev/)
- [React](https://reactjs.org/)
- [Tailwind CSS](https://tailwindcss.com/)
- [Chart.js](https://www.chartjs.org/)
    - [react-chartjs-2](https://react-chartjs-2.js.org/)
- [TypeScript](https://www.typescriptlang.org/)

スクショは以下。バージョンうｐ前なので、ちょっと見た目が違うのはご容赦。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214979/8513bf01-5ab0-3835-ce0a-af999730256a.png)
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214979/de09ceed-b4bc-58ce-b402-56f5595b10de.png)
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214979/ba07c2f0-b774-2122-79f1-ebad47ca28db.png)

## モチベ

TLDR: はじまるA列車専用のダイヤ作成ソフトが欲しい。

A列車で行こう、楽しいよね❗
このゲーム最大の特徴は、ダイヤを細かく設定できることだと思ってます(他の都市開発ゲーではできないものが多い)。
そこで、ダイヤグラム作成ソフトがあると便利。

既存のダイヤグラム作成ソフトについては[カメロング氏のウェブサイト](https://kamelong.com/blog/2019-09-01/index.php)が詳しいです。
なかでも一番有名なのはOuDia(ないしはOuDiaSecond)でしょう。

OuDiaは素晴らしいソフトですが、**個人的に**以下が気に入らないです。

1. **繰り返し回数設定がない**
2. 多機能すぎてどこをいじれば良いか分かりづらい
3. (古い、古すぎる...)
   - いや2017年にも更新されてるからそこまででもないんだけど。

1番の繰り返し設定とは、おそらくはじまるA列車特有の概念です。
はじまるA列車では、上りと下りの1周分の時刻設定をしたあと、それを何回繰り返すのかを指定できます。
(逆に言うと、2周目以降を違う経路にしたりはできない。)

で、OuDiaにはこの概念がないので、繰り返し設定する場合は**手動で時刻設定をコピペする必要があります**。
これが忘れるのなんの...😭
忘れた状態で別のダイヤを数時間いじくり回して、いざゲーム側で設定すると...列車が衝突😇
そうなると修正にまた数時間かかるわけです。やってられん❗

ということで、手動コピペの必要がないダイヤ設定アプリが欲しかったわけですね。

## 技術

### Q: 「Viteどう❓」

早い。ヤバイ。

### Q: 「Reactどう❓」

強い。ヤバイ。
本アプリみたいに、入力欄だらけでそれがリアルタイムで反映されるようなアプリには最適。
生のJSだけでやってたら絶対完成しなかったと思う。

ただ、難しさも当然ある。
最初は[Lifting State Up](https://reactjs.org/docs/lifting-state-up.html)も知らずに作ったので、同一要素を複数の状態で管理して、バグだらけだった...。
修正する際はほぼフル書き直し。
状態設計は最初にきちんとやらないとマズイ。

他にもColocationとかいうのも学ぶ必要があるらしい。
これはまだ理解してない。だれか教えて。

### Q: 「Chart.jsどう❓」

楽しい。柔軟性が高い。
本アプリみたいに、x軸が時刻で、y軸が駅名、みたいなグラフを作れるのは強い。

ただ、ちょっとパフォーマンスが心配かな。
繰り返しを10ぐらいにするとちょっとガクついた。
本格的にダイヤを組む人には辛いかも。要改善。

### Q: 「Tailwind CSSどう❓」

う〜ん❓
便利っぽいんだけど、結局生のCSS書いてるのと変わらん部分もあった。
[Flowbite](https://flowbite.com/)くんは便利だけどさ。

## 余談

- ❌: 「ダイ**ア**グラム」
- ⭕: 「ダイ**ヤ**グラム」

らしい。鉄道的には。

## あとがき

ご意見ご要望、歓迎です。
近くにA列車プレーヤがいたら宣伝してくれると幸いです。
Swift文字列検索/置換まとめ

何度も忘れては検索してしまうため、まとめ。随時更新。

### 対象文字列
```swift
var targetString = "My name is Swift Ganbaru Man, I'm a guy studying Swift."
```

### 特定の文字列で始まっているか？
```swift
targetString.contains("Swift") // true
targetString.contains("Python") // false
```

### 特定の文字列で終わっているか？
```swift
targetString.hasSuffix(".") // true
targetString.hasSuffix("!!") // false
```

### 全体置換
```swift
// My name is Python Ganbaru Man, I'm a guy studying Python.
targetString.replacingOccurrences(of: "Swift", with: "Python")

// My name is Swift Ganbaru Woman, I'm a lady studying Swift.
targetString.replacingOccurrences(of: "Man", with: "Woman").replacingOccurrences(of: "guy", with: "lady")
```

### 一つ目だけ置換
```swift
let range = targetString.range(of: "Swift")
// My name is Objective-C Ganbaru Man, I'm a guy studying Swift.
targetString.replacingCharacters(in: range!, with: "Objective-C")
```
QGISで色々なWeb地図を表示させる

# ネット上の地図データは、どのように表示されているか？
GoogleMap や国土地理院のWeb地図は、「[Web Map Tile Service](https://ja.wikipedia.org/wiki/%E3%82%A6%E3%82%A7%E3%83%96%E3%83%9E%E3%83%83%E3%83%97%E3%82%BF%E3%82%A4%E3%83%AB%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9)」(以下、WMTS) と呼ばれる規格に則って作られたタイル状に切り分けられた画像データで表示されています。
国土地理院の下記のページが、大変分かりやすく解説されています。

https://maps.gsi.go.jp/development/siyou.html

多くのWeb地図がこの規格を元にして作られています。
そして、この規格に則ったデータであれば、QGIS で表示する事が可能です。
# QGIS で WMTS を表示する具体的な方法
QGIS のウインドウの(変えていなければ)左側にある「ブラウザ」のツリーの中にある「XYZ Tiles」を右クリックし、コンテキストメニューから「新しい接続」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2555080/3651e4f8-934d-c652-fa40-3a701dc74ad4.png)
表示されたダイアログの赤枠の所を記載・設定して「OK」を押下します。
+ 名前：適当な名前を設定して下さい、その名前でツリーに表示されます
+ URL：後述のURLを指定します
+ 最小・最大ズームレベル：後述の通り各地図にあった物を設定します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2555080/38936b50-9dbc-e142-297b-b0c2e385f432.png)
# GoogleMap を表示してみる
それでは GoogleMap を表示してみましょう。
ブラウザでGoogleMapを開くと、標準で出てくる地図は、下記のURLになります。
`https://mt1.google.com/vt/lyrs=r&x={x}&y={y}&z={z}`
最小ズームレベルは`0`、最大ズームレベルは`18`です。
名前に記載した名称でツリーに表示されているので、それを「レイヤ」のツリーにドラッグ&ドロップしましょう。
GoogleMap が表示されたはずです。
GoogleMapは、下記の様な種類があります。
一番上が普通の地図、二番目が航空写真です。
私はGoogleMapの中では、この二つを最もよく使います。
|表示地図|URL|MinZoom|MaxZoom|
|:-:|:--|:-:|:-:|
|Google Streets|https://mt1.google.com/vt/lyrs=r&x={x}&y={y}&z={z}|0|18|
|Google Satellite|https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}|0|18|
|Google Satellite Hybrid|https://mt1.google.com/vt/lyrs=y&x={x}&y={y}&z={z}|0|18|
|Google Maps|https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}|0|18|
|Google Roads|https://mt1.google.com/vt/lyrs=h&x={x}&y={y}&z={z}|0|18|
|Google Terrain|https://mt1.google.com/vt/lyrs=t&x={x}&y={y}&z={z}|0|18|
# 国土地理院の電子国土Webを表示してみる
昔から地図を扱ってきた人なら、地理院の地図が一番馴染みがあるのでは？
あと、登山やハイキングには、便利な地図です。
|表示地図|URL|MinZoom|MaxZoom|
|:-:|:--|:-:|:-:|
|標準地図|https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png|5|18|

その他にもたくさんの種類の地図が表示できます。
詳しくは下記のサイトの、「詳細情報」以降をご覧ください。

https://maps.gsi.go.jp/development/ichiran.html
# OpenStreetMap を表示してみる
ODbL 1.0 のライセンスで利用できる地図です。
利用に対する自由度が高いのが良いですね。
|表示地図|URL|MinZoom|MaxZoom|
|:-:|:--|:-:|:-:|
|Standard|https://tile.openstreetmap.org/{z}/{x}/{y}.png|0|19|

その他にもたくさんの種類の地図が表示できます。
詳しくは下記をご覧ください。

https://wiki.openstreetmap.org/wiki/Tiles
# マピオンを表示してみる
マピオンは、行政界がとても見やすいので、重宝する地図です。
これが QGIS で表示できれば、便利ですよね。
|表示地図|URL|MinZoom|MaxZoom|
|:-:|:--|:-:|:-:|
|Standard|https://cm02.mapion.co.jp/m2/tile/{z}/{x}/{y}.png?usr=atlas_org&amp;v=2.6|6|19|
# 十分注意して使用してください
それぞれの地図には、使用に対してライセンスが定められています。
それぞれのライセンスに従って、使用しましょう。
個人のPCで個人的にQGIS上で表示して利用する分には問題ないと思いますが、
+ 印刷する
+ 配布する
+ 不特定多数が見れる状態にする

等の行為は許諾が必要だったりします。
十分注意してください。
異なるバージョンのNode.jsを同居させて切り替えて使う

昔のプログラムをサクッと確認したいだけなのに、Node.jsのバージョンが合わずにビルドでエラーを吐いてストレス。。。
という状況に陥ったため、
Node.jsのバージョン管理であるnvmをインストールして利用しました。

**試した環境**
OS: Windows 11

## 通常の方法での最新のNode.jsのインストール
Node.jsのダウンロードページから、Windows用のインストーラー(.msi)が配布されているので、
それを取得し、インストールを行う。
https://nodejs.org/ja/download/

### Node.jsが正常にインストールされたかの確認
Windows PowerShellを起動し、以下のコマンドを実行しバージョン情報が表示されれば、成功です。
```console
PS C:\shell> node -v
v16.17.0
```

## nvmのインストール
こちらも、インストーラー(.exe)が配布されているので、取得しインストールを行う。
https://github.com/coreybutler/nvm-windows/releases

### nvmが正常にインストールされたかの確認
Windows PowerShellを起動し、以下のコマンドを実行しバージョン情報が表示されれば、成功です。
※この記事を最初から試していた方は、一度ターミナルを閉じてから開き直さないと、コマンドが見つかりませんと表示されるので注意です。
```console
PS C:\shell> nvm v
1.1.9
```
## nvmでよく利用する操作の説明
複数バージョンを切り替えたいというニーズの場合に、必要となる操作を記載しておきます。
1. 利用可能なバージョンのリストを取得
1. 特定バージョンのNode.jsのインストール
1. インストール済みのNode.jsの確認
1. 使用するNode.jsのバージョンを指定

### 利用可能なバージョンのリストを取得
```console
PS C:\shell> nvm ls available

|   CURRENT    |     LTS      |  OLD STABLE  | OLD UNSTABLE |
|--------------|--------------|--------------|--------------|
|    18.7.0    |   16.17.0    |   0.12.18    |   0.11.16    |
|    18.6.0    |   16.16.0    |   0.12.17    |   0.11.15    |
|    18.5.0    |   16.15.1    |   0.12.16    |   0.11.14    |
(以下略)
```

### 特定バージョンのNode.jsのインストール
[arch]はデフォルトでシステムのものが使われるので、特に指定の必要はありません。
```console
PS C:\shell> nvm install (バージョン|latest|lts) [arch]
Downloading node.js version **.*.* (******)... 
Extracting...
Complete


Installation complete. If you want to use this version, type

nvm use **.*.*
```

### インストール済みのNode.jsの確認
*がついているものが現在使用されているもの
```terminal
PS C:\shell> nvm ls

    18.7.0
    14.18.0
  * 12.22.12 (Currently using 64-bit executable)
```


### 使用するNode.jsのバージョンを指定
[arch]はデフォルトでシステムのものが使われるので、特に指定の必要はありません。
```terminal
PS C:\shell> nvm use (バージョン|latest|lts) [arch]
Now using node v**.*.* (******)
```
※以下のように、文字化けのエラーコードが出力された場合、Windows PowerShellを「管理者として実行」してください。
```terminal
PS C:\shell> nvm use latest
exit status 5: �A�N�Z�X�����ۂ����܂����B

exit status 1: ���ɑ��݂����t�@�C�����쐬���邱�Ƃ͂ł��܂����B
```

他の使い方などを知りたい人は、helpを参照してください。
(存在しないオプションを指定すればhelpが表示されます。)
```terminal
PS C:\shell> nvm help

Running version 1.1.9.

Usage:

  nvm arch                     : Show if node is running in 32 or 64 bit mode.
  nvm current                  : Display active version.
(以下略)
```
OpenPyxlの備忘録

## はじめに
### 使用しているもの
`openpyxl   3.0.10`

```python
# 前提コード
import openpyxl

wb = openpyxl.Workbook()
```

### 注意
間違いやもっとこうした方がいい、みたいのがあるかも

## 内容
### get_なんたらは基本使わない
調べるとよく出てくる、
`wb.get_sheet_by_name('Sheet1')`
なんかはもう古いみたい。
他にもなにやら新しくなっているものがあり、ちょいちょい怒られる。
以下新旧対照表
|内容|新|旧|
|---|---|---|
|シート名を指定する|wb["Sheet1"]|wb.get_sheet_by_name('Sheet1')|
|シートを消す|wb.remove(worksheet=wb["Sheet1"])|wb.remove_sheet(wb.get_sheet_by_name('Sheet1'))|
|シート一覧の取得|wb.sheetnames|wb.get_sheet_names()|


## おわりｽﾞｲ₍₍ (ง ˘ω˘ )ว ⁾⁾ｽﾞｲ