OmniAICreator/Qiita-1.07M huggingface dataset:
Chrome拡張をスマホ対応するには？

# Chrome拡張をスマホ対応するには？
- Chrome拡張対応モバイルブラウザを使う
- タッチ操作に対応させる
- 画面が狭くても困らないように調整する

# Chrome拡張対応モバイルブラウザを使う
スマホ版Chromeで拡張機能が使えれば良いのですが、あいにく使えません。
スマホでChrome拡張が使えるブラウザは、以下の様です。

- Android
  - Kiwiブラウザ
  - Yandexブラウザ
- iPhone
  - Orionブラウザ

https://www.bugbugnow.net/2022/01/ios-android-browser.html

まずはこの内どれかをインストールして、目的のChrome拡張が動作するかどうかを見ることになります。ただし、パソコンとスマホで色々違うため、期待通り動かない場合があります。自作拡張機能であれば、動かない原因を一つ一つ修正して、対応させることになります。


# タッチ操作に対応させる
タッチ操作対応には2つの側面があります。

## マウスイベントではなくタッチイベントを適切に処理する
Androidの場合、タッチデバイスでも、ある程度のマウスイベントを同時に発生させてくれるので、意外と動くことが多いです。もちろん、mousemoveイベントなどはタッチデバイスでは原則発生しないため、これらに過度に依存しすぎない様に調整を入れれば良いでしょう。

http://www.macfreek.nl/memory/Touch_and_mouse_with_hover_effects_in_a_web_browser

## マウスほど細かいポイントができないことに注意する
イベント自体は処理できても、指によるタッチでは細かい範囲をクリックしたりが困難です。このため、マウスクリックに比べて余裕を持ったボタンなどの配置をする必要があります。


# 画面が狭くても困らないように調整する
スマホは携帯してナンボなので、パソコンより画面が小さいです。特に普通に縦持ちすると、横幅が非常に狭いです。パソコンでテーブルなど行列で表現した形式そのままだと、操作性が悪くなりがちです。実際に自作Chrome拡張で試してみて、閲覧はまだしも、入力欄が狭いと非常に操作しにくくなりました。

この課題は、入力時に一時的に入力欄を横幅いっぱいに拡大する事で解消できました。

https://youtu.be/Cchk67vGZaQ?t=142

この解決法以外にも、様々な工夫があるので、合うものを取り入れれば良いでしょう。

https://www.site-convert.com/archives/858


# 自作クロム拡張のスマホ対応例
<iframe width="560" height="315" src="https://www.youtube.com/embed/Cchk67vGZaQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
LPC812MAXとDS1307で時間合わせ(LPC812)


x Mbed2リビジョン144です。
x リビジョンを変更してください。


目的
RTCの時間合わせ
タイミングよく実行する

ちゃんと原文を確認してね!!

x 非営利、研究調査目的で引用


-625-

![o_con625.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/b594922c-8fe2-45cf-603d-7698f142a839.jpeg)


![o_con803.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/ca51a7f6-2237-d0ac-66df-65714be834a8.jpeg)




```c++



//i2c_ds1307_set_812_1

#include "mbed.h"

#define HH  17
#define MM  28

int main() {
    char data_read[8];  //i2cバッファー
    data_read[0]=0;
    data_read[1]=0;
    data_read[2]= ( MM /10)*16+( MM %10);
    data_read[3]= ( HH /10)*16+( HH %10);
    data_read[4]=3;    
    data_read[5]=1;
    data_read[6]=1;
    data_read[7]=0x20;

    I2C i2c(P0_10, P0_11); //812
    i2c.write(  (0xD0)  , data_read, 8);

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




```


![o_con833.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/ce20796f-8d19-2f3d-466a-5ebd1a284fc6.jpeg)


-34-
LPC812MAXで時計。(DS1307)(シリアル出力)(LPC812)


x 時間あわせは、別

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


x 無意味に軽量高速化　しかも　わかりやすくした。

目的
DS1307のテスト

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

![o_con802.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/dd4b88bd-c634-eef3-9d00-1e3195ff7588.jpeg)


-625-

![o_con625.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/c75e9b2d-791b-4edc-b7f5-128c99ce09c0.jpeg)



```c++



//i2c_ds1307_SER_812_1

#include "mbed.h"

//         TX    RX
Serial pc(P0_4, P0_0); //812

//       SDA    SCL
I2C i2c(P0_10, P0_11); //812

//メイン関数
int main()
{
    //無限ループ
    while(1) {

        //時間の読み込み
        i2c.write( (0xD0), "\000", 1);
        char read_data[7]; //リードデータ
        i2c.read(  (0xD0) | 1, read_data, 7);

        //時間の表示
        pc.putc( '0'+(read_data[2] >> 4)   );
        pc.putc( '0'+(read_data[2] & 0xf)  );
        pc.putc( '.' );
        pc.putc( '0'+(read_data[1] >> 4)   );
        pc.putc( '0'+(read_data[1] & 0xf)  );
        pc.putc( '.' );
        pc.putc( '0'+(read_data[0] >> 4)   );
        pc.putc( '0'+(read_data[0] & 0xf)  );
        pc.putc( '\r');
        pc.putc( '\n' );

        //1秒待つ
        wait_ms(1000);

    }//while
}//main





```


![o_con833.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/3730fbb9-6cb9-0c0f-971b-96a657e8a8cf.jpeg)


-32-
【Flutter/Dart】Firebaseを使おう

# 1.はじめに
新たに6つのAndroidStudio&Flutter&Firebase記事を書いている。以下は内容、
- **【Flutter/Dart】Firebaseを使おう**
- 【Flutter/Dart】Firebase Authenticationを使って認証アプリを作ろう
https://qiita.com/my_programming/private/2d81229942bc0d61da6b
- 【Flutter/Dart】Firebase/Firestoreを使ったチャットアプリを作ろう
https://qiita.com/my_programming/private/ad0f7a5f7637a1a37842
- 【Flutter/Dart】Firebase/Firestoreを使ったToDoアプリを作ろう
https://qiita.com/my_programming/private/2da77f3a36bf120761c5
- 【Flutter/Dart】Firebase/HostingでWebアプリを外部公開しよう
https://qiita.com/my_programming/private/5950b7e27161dc9ec838
- 【Flutter/Dart】Firebase/Firestoreを使ったBlogアプリを作ろう
https://qiita.com/my_programming/private/6f8515dca825e55d0f07

Firebase とは、Googleが提供している、アプリの構築、改善に役立つアプリ開発プラットフォームである。Firebaseを使うと以下のようなことが可能になる。
- クラウドでのアプリのデータ保存、共有
- ユーザー認証、ログインの実装
- ウェブサイトのデプロイ
<br>
以下では、Firebaseを利用するための環境構築について解説していく。

# 2.Firebaseを使おう
以下のサイトにアクセスする。
https://firebase.google.com/
<br>
右上の`ログイン`を押す。
<img width="400" alt="step2_1_1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/892339/a6f0e272-374a-058c-0d33-d3857856246a.png">
<br>
`使ってみる`を押す。
<img width="400" alt="step2_1_2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/892339/5349c391-4a27-93a1-d26a-e94383fa0664.png">
<br>
`Create Project`を押す。
<img width="400" alt="step2_1_3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/892339/667ce09f-9ab8-7a79-7cd2-0ed7b020021e.png">
<br>
プロジェクト名を入力。
<img width="400" alt="step2_1_4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/892339/e95f7433-aa0e-1bda-9410-8bb566738c0b.png">
<br>
例としてMy First Projectという名前にする。
<img width="400" alt="step2_1_5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/892339/bf3de7a3-267f-f910-a983-691e53e71eac.png">
<br>
続行。
<img width="400" alt="step2_1_6.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/892339/a5351dc1-d9e6-9083-ea3f-e57c51ab69fb.png">
<br>
地域と利用規約を確認しプロジェクト作成。
<img width="400" alt="step2_1_7.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/892339/637b8620-2d9b-3512-e8ee-fd40571cdc80.png">
<br>
準備ができたら続行。
<img width="400" alt="step2_1_8.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/892339/92d05bd5-d50a-5292-b85b-630db25df8a3.png">

<br>
プロジェクトが作成される。
<img width="400" alt="step2_1_9.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/892339/2e558c74-5afd-aae3-40e6-c101a48d013f.png">

# 3.まとめ
今回はFirebaseを利用するための環境構築について学んだ。
AndroidアプリでPythonライブラリを使う 【Chaquopy】

# 概要

Chaquopyを使ってJava/Kotlin製Androidアプリの一部をPythonで実装し、Pythonライブラリを使う方法を紹介します。
本記事ではNumPyで乱数を生成し、Kotlin製Androidアプリの画面に表示します。



# Chaquopyとは

[Chaquopy](https://chaquo.com/chaquopy/)とは、Java/Kotlin製AndroidアプリにPythonの実装を組み込むことができるSDKです。SciPyやPyTorchなど豊富なライブラリに対応しており、JavaやKotlinで扱いにくい処理をPythonで記述できます。

以前はライセンスの制約がありましたが、[2022/07/24にオープンソース化し](https://chaquo.com/chaquopy/chaquopy-is-now-open-source/)、MITライセンスとなったことで使いやすくなりました。

# 使い方
## 環境

- MacBook Pro （2020年モデル / BigSur 11.6.4）
- Android Studio （Bumblebee | 2021.1.1 Patch 2）

## 新規Androidプロジェクトの作成

Python実装を組み込む先のAndroidアプリとして、Empty Activiyの新規プロジェクトを作成します。
プロジェクトの作成方法は[こちら](https://developer.android.com/training/basics/firstapp/creating-project?hl=ja)をご参照ください。

## Chaquopyの追加

[公式の手順](https://chaquo.com/chaquopy/doc/current/android.html)に従い、top level及びmodule levelの`build.gradle`に下記を追加します。

```gradle:build.gradle
plugins {
    id 'com.chaquo.python' version '12.0.1' apply false
}
```

```gradle:build.gradle(:app)
plugins {
    id 'com.android.application'
    id 'com.chaquo.python'
}

...

defaultConfig {
    ndk {
       abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
    }
}
```

## ライブラリ（NumPy）の追加

`build.gradle`（module level）のdefaultConfig内にrequirementを記述し、NumPyを追加します。

```gradle:build.gradle(:app)
python {
    pip {
        install "numpy"
    }
}
```

## Pythonスクリプトの用意

Chaquopyはデフォルトで`src/main/python`のPythonスクリプトを読み込みます。
`chaquopy_test.py`を作成し、`src/main/python`に配置します。

```python:chaquopy_test.py
import numpy as np

def create_random_number():
    return np.random.rand()
```


## KotlinからPythonスクリプトを呼び出し

生成した乱数を画面に表示するため、更新対象のTextViewにidを追加します。

```activity_main.xml
<TextView
    android:id="@+id/text_view"
    ...
/>
```

`create_random_number`を呼び出して乱数を生成し、TextViewを更新します。

```MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Pythonコードを実行する前にPython.start()の呼び出しが必要
        if (!Python.isStarted()) {
            Python.start(AndroidPlatform(this))
        }

        val py = Python.getInstance()
        val module = py.getModule("chaquopy_test") // スクリプト名

        try {
            val randomNumber = module.callAttr("create_random_number").toFloat() // 関数名
            findViewById<TextView>(R.id.text_view).text = randomNumber.toString()
        } catch (e: PyException) {
            Toast.makeText(this, e.message, Toast.LENGTH_LONG).show()
        }
    }
}
```


## 実行

画面に生成した乱数が表示されました。

<img width=300 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2286990/cff730b6-4c0b-3945-15d8-e4a33c21e0f5.png">


# おわりに

Chaquopyを使うと簡単にPythonスクリプトをAndroidアプリに組み込むことができます。対応しているライブラリやバージョン等の制限はありますが、SciPyやNumPyといった有名どころのライブラリを使う上では十分活用できるのではと思います。

別の記事では[Chaquopy+PyTorchでMobileNetv3を動作させる例](https://qiita.com/ta-sr/items/984779da293432f58ee1)を紹介しています。
SQL 学習内容まとめ（命令文編）

# SQL学習内容まとめ（命令文編）
<!-- 発端や概要を記載 -->
SQLの基礎とされる命令文について復習も兼ねてまとめてみました。


# 目次
<!-- タイトルとアンカー名を編集 -->
1. [事前準備](#Chapter1)
1. [INSERT文](#Chapter2)
1. [SELECT文](#Chapter3)
1. [UPDATE文](#Chapter4)
1. [DELETE文](#Chapter5)
<!-- 各チャプター -->
<a id="#Chapter1"></a>
# 1.事前準備
テスト用に事前にテーブルを作成します。
家電の商品データを格納すると仮定して３項目追加しました。

| No |    項目    |    データ型    |
|---:|-------------|------------|
| 1  |  category   |     nchar(32)       |
| 2  |   shohin 　  |    nchar(32)        |
| 3  |   cost      |       int      |

<a id="#Chapter2"></a>
# 2.INSERT文
INSERTを使用することでテーブルにデータを追加できます。
以下のソースで画像のように行が追加されました。

```
INSERT INTO shohinInfo (category,shohin,cost) VALUE ('家電','洗濯機',20000);
```

![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2870401/1bb49a74-c00f-489d-7e4c-79eb408fe189.png)



<a id="#Chapter3"></a>
# 3.SELECT文
SELECT文を使用してテーブルからcategoryの列が食品のデータのみ取得します。

![キャプチャ2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2870401/a181a49e-c8d0-c466-c292-b3e4c9a2a8ba.png)

下記のソースを使用することでcategory列に食品の属性を持ったデータのみ抽出できました。

```
SELECT category,shohin,cost 
from shohinInfo 
WHERE category = '食品'
```

![キャプチャ3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2870401/21aed509-4ee2-d58a-ed81-2786de80e402.png)

<a id="#Chapter4"></a>
# 4.UPDATE文
UPDATE文を使用することで洗濯機の行を更新することができました

変更前
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2870401/1bb49a74-c00f-489d-7e4c-79eb408fe189.png)

変更後
![キャプチャ4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2870401/9f4be1d0-a42d-0e95-cf9e-364152cc8acc.png)

```
UPDATE shohinInfo
 SET cost = 15000
WHERE shohin ='洗濯機'
```

<a id="#Chapter5"></a>
# 5.DELETE文
DELETE文を使用してcategoryの属性が食品であるデータを除去しました。

変更前
![キャプチャ2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2870401/a181a49e-c8d0-c466-c292-b3e4c9a2a8ba.png)

変更後
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2870401/1bb49a74-c00f-489d-7e4c-79eb408fe189.png)
```
DELETE FROM shohinInfo 
WHWRE category = '食品'
```
2022/9/26主にITとかセキュリティの記事

ネット銀悪用の不正送金急増、「フィッシング」の手口が大半…被害に気づかない例も(9/24)
https://www.yomiuri.co.jp/national/20220924-OYT1T50086/

日米豪印外相、各国に「ランサムウエア」への取り組み呼び掛け(9/24)
https://www.bloomberg.co.jp/news/articles/2022-09-24/RIOTBBDWX2PS01?srnd=cojp-v2

話題のスマホもハッキングされる 回避する方法をチェックしよう(9/23)
https://ascii.jp/elem/000/004/106/4106056/amp/

スマホで仮想通貨の管理は時代遅れ？今こそハッキングのリスクを真剣に考える時(9/24)
https://jp.cointelegraph.com/news/opinion-ledger-insight-of-the-week-2022-0924

ウイグル族を標的とした長期的なAndroidモバイル監視キャンペーン展開中(9/24)
https://news.mynavi.jp/techplus/article/20220924-2461995/

BINDに重要な脆弱性、アップデートを(9/24)
https://news.mynavi.jp/techplus/article/20220924-2461408/

超一流の諜報員が教える、ビジネスでも使える最強のスキルとは(9/23)
https://zuuonline.com/archives/241265

9月Webサーバシェア、Cloudflare・LiteSpeed・OpenRestyが増加傾向(9/24)
https://news.mynavi.jp/techplus/article/20220924-2461377/

NFTアプリのApp Store配信に立ちはだかる複数の壁(9/24)
https://iphone-mania.jp/news-490520/

ドナルド・トランプのSNSアプリを止めるときがきたようだ(9/24)
https://forbesjapan.com/articles/detail/50548

業務負荷を減らすwebアプリ【vote】の紹介(9/23)
https://qiita.com/narunblog/items/e70a60e96a56a5372229

2022年版パスワード管理ソフト＆ツールベスト8(9/23)
https://news.mynavi.jp/techplus/article/20220923-2458883/

「四重脅迫」相次ぐ…身代金ウイルス被害拡大が止まらない(9/24)
https://newswitch.jp/p/33854

メール暗号化を自動判定　「脱PPAP」に新手法(9/22)
https://www.nikkei.com/article/DGXZQOUC191M00Z10C22A8000000/

Zoho ManageEngineの脆弱性の活発な悪用を確認、更新を(9/24)
https://news.mynavi.jp/techplus/article/20220924-2461264/

人流やPOSなど、民間データ集約へ新サイト　政府が23年(9/23)
https://www.nikkei.com/article/DGXZQOUA229U60S2A820C2000000/
BiqQueryでGENERATE_DATE_ARRAY関数を使用して日ごとの売上データを集計する

# 背景
商品ごとの売上記録を日ごとに集計し、ダッシュボードやスプレッドシートへ日付が過去のデータから順に出力する。
ここで、商品の購入数を日ごとに集計する際、 過去の日付の購入数データから順にダッシュボードやスプレッドシートへ出力する。
しかし、購入実績がない日付のデータも購入数0として表示させたくても、購入履歴のある日付ごとのみで **`GROUP BY`** 句により集約されるため、購入のない日付が飛んだ状態で表示されてしまう。

例）
 **商品テーブルのイメージ**
商品Aについて、時系列に注文された購入情報が格納されているが、購入された日付の情報のみ格納されている。
![商品Aオーダーテーブル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396777/465391c5-3361-96b2-9519-fd12a8ef4c49.png)
**ダッシュボード等へのグラフ出力イメージ**
上記テーブルから日付（**`order_dt`**）ごとに **`GROUP BY`** 句で集計した場合、注文のない日付は注文点数0としたいが、**2022/06/02**、**2022/06/06**の商品Aの注文がないため、以下のグラフの**2022/06/02**、**2022/06/06**の日付データが飛んだ状態となってしまう。
![日付ごとの商品Aの注文点数.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396777/03f16eed-16f5-cac5-912d-6e7719e376a7.png)

# 目的
集計対象の商品の注文がない日付でも購入数なしデータとして情報を持たせ、ダッシュボード、あるいはスプレッドシートへ表示させるため、そこで **`GENERATE_DATE_ARRAY`** 関数を使用し、集計の期間に必要な全日付を取得して売上記録を日付ごとにソートする。

**説明**
```sql
GENERATE_DATE_ARRAY(start_date, end_date[, INTERVAL INT64_expr date_part])
```
・**`start_date`** : 開始日を入れる
・**`end_date`** : 終了日を入れる
・**`INTERVAL`** : **`INT64_expr`**は**`INT64`**、**`date_part`**は**`DAY`**、**`WEEK`**、**`MONTH`**、**`QUARTER`** または **`YEAR`** を指定する

# 対応方法
連続した日付データを取得するため、ここで **`GENERATE_DATE_ARRAY`** 関数を用いる。
**Step1）**
**`GENERATE_DATE_ARRAY`** 関数を用いて、集計に必要な期間の基準となる日付（以下、基準日）を抽出する。
```sql
SELECT
    GenarateDate
FROM
    UNNEST(GENERATE_DATE_ARRAY('2022-06-01', '2022-06-10')) AS GenarateDate
```

**Step2)**
対象期間の売上データを日付ごとに集計し、Step1で抽出した基準日へ購入日付を結合キーとして外部結合する。
```sql
--データの抽出の対象となる期間を日付ごとに全て取得
WITH GENARATE_TIME AS (
SELECT
    GenarateDate
FROM
    UNNEST(GENERATE_DATE_ARRAY('2022-06-01', '2022-06-10')) AS GenarateDate
)

SELECT
    GenarateDate
    ,GoodsID
    ,GoodsName
    ,DailyQuantity
FROM 
    GENARATE_TIME
    LEFT JOIN (
        SELECT
            OrderDate
            ,GoodsID
            ,GoodsName
            ,SUM(Quantity) AS DailyQuantity
        FROM
            `test_dataset.samle_order_table` order
        WHERE
            OrderDate BETWEEN '2022-06-01' AND '2022-06-10'
        GROUP BY
            OrderDate
            ,GoodsID
            ,GoodsName
        ) ON GenarateDate = OrderDate
;
```

# クエリの実行結果
クエリの実行結果としては、**2022/06/01～2022/06/10**の期間で日付ごとに商品Aの購入数の合計を集計するというものである。

「**`GENERATE_DATE_ARRAY`** 関数による基準日の使用なし」と「**`GENERATE_DATE_ARRAY`** 関数による基準日の使用あり」を比較すると、なしの場合は商品Aの購入のなかった **2022/06/02**、**2022/06/05～2022/06/06**、**2022/06/08～2022/06/09**は、レコード自体が存在しない。

それに対し、ありの場合は購入のなかった日でも連続した日付でデータを取得できている。購入数が **`NULL`** となっているが、気になるようであればクエリで0に更新するか、データポータルへ表示するのであればデータポータル上でも編集が可能となるが、本稿のテーマ外であるため省略。
#### **GENERATE_DATE_ARRAY**関数による基準日の使用<font color="red">なし</font>
![結果_ノーマル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396777/1a49c3d7-5d8c-e993-2dcd-ed7cecabe4f1.png)
#### **GENERATE_DATE_ARRAY**関数による基準日の使用<font color="red">あり</font>
![結果_Genarate_Array.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396777/c2a41eeb-b249-0077-6458-72dd96f54cd1.png)

# 参考
**`GENERATE_DATE_ARRAY`** 関数の使用規約については以下のリンクを参照
https://cloud.google.com/bigquery/docs/reference/standard-sql/array_functions?hl=ja#generate_date_array
スクラム開発をやってみて失敗したことを振り返る

# はじめに
こんにちは。
[株式会社LIFULL](https://lifull.com/)でアプリケーションエンジニアとして[不動産ポータルサイト「LIFULL HOME'S」](https://www.homes.co.jp/)の開発を行なっています。
yamaoです。
早速ですが、今回は半年間私のチームでスクラム開発を行なった結果、**失敗したこと**をいくつか挙げて振り返っていこうと思います。
ぜひ反面教師にして下さい。
ちなみに筆者はサブスクラムマスターとして主にスクラムマスター（以降 SM とする）のサポートをしてましたので、その目線からの振り返りであることをご認識下さい。

# チームについて
- 2022年4月から新たに組成されたチーム
- 企画・デザイナー・エンジニア合わせて 10 人
- スクラムを導入

# 半年間やってみての課題
## モチベーション
- **チームの KPI 設定やすぐにやってしまいたい施策を優先して、メンバーに対してスクラム導入にあたっての説明やモチベーション（動機付け）部分をざっくりと済ましてしまったこと**
    - メンバーのモチベーションがスクラムの運用に、実際は対して影響を及ぼさないんじゃないかと軽視してしまっていた
    - 結果としてスプリントの完了 MTG をやってもチームの運用を改善する様な本質的な意見を出す人が少なくなったり、何より「みんなでチームを上手く回していく」みたいな雰囲気が最後まで作れなかったのもここが尾を引いたのかなと思っている
## ストーリーポイント
- **SP を企画・デザイナー・エンジニア全てのタスクに振っていたこと**
    - 元々は、振り返りの時にチームのどこが進捗悪いのかボトルネックを把握出来た方が良いからという理由
    - 結果としては、それぞれの職種間で 1 ポイントの重みを揃えるのが大変だったり、全部の職種のタスクに SP を振るとなるとその分プランニングポーカーの時間も増える。その割にボトルネックは目に見えて開発フェーズだったので2ヶ月ほどでエンジニアのタスクのみ SP を振る運用に変更した
## スクラムイベント
- **準備からファシリまで全て SM で行なっていたこと**
    - 朝会はかろうじてファシリを輪番で回して SM とメンバーのみの会話にならないように出来ていたが、基本的にスクラムイベントの準備や朝会以外のファシリは SM 側でやってしまっていた。完全に間違いとも言えないとは思うが、結果的にチーム改善のための全てのアクションが SM 起点になってしまった要素の一つだと考えていて、個人的には失敗したなと感じる部分でした
- **計画 MTG が作業となってしまったこと**
    - SM がバックログリファインメントで次スプリントで行えるであろうタスクを前 SP をもとに見積もり、計画 MTG でメンバーと擦り合わせを行なうというやり方であったが、前スプリントの SP をもとに振っているということもあり、メンバーからも特に意見は無く認識を揃えてすぐ終わり...となりがちで作業感が強かった
    - これ自体は問題ではないのだが、バックログリファインメントにメンバーも参加してもらってワイワイしながらタスクを見積もっていった方がメンバーも納得感もって取り組めるし、より多くの意見を拾えるから良かったなと感じている
## ファシリテーション
- スクラムイベントのところでも記載しましたが、**SM だけで回しすぎてしまったこと**
    - MTG アジェンダの作成や準備からファシリまで、適宜振り分けた方が各々メンバー自身でどういう MTG にする必要があるかなど考えてもらうきっかけになるので、より自発的に行動してもらう一助になったのではないかなと考えている

# 次の機会に向けて
私の知識の拡充ももちろんなのですが、やっぱり「チームが自発的に行動しやすい」様にスクラムを運用していけなかったのが一番の反省点かなと思っており、それに紐づく
- **チームの KPI 設定やすぐにやってしまいたい施策を優先して、メンバーに対してスクラム導入にあたっての説明やモチベーション（動機付け）部分をざっくりと済ましてしまったこと**
- **SM だけで回しすぎてしまったこと**

この二つの課題は特に次回のチームでは改善出来る様に動くのが良いなと考えています。
この二つの課題に関してはそもそも行えていないものなので、まずは実践していくことから始めていきます。

# さいごに
チームの成果物を見るとこのスクラム運用のせいで問題があった訳ではなかったのですが、個人的に SM に近い役割をやらせてもらって課題を感じることが多かったのと、失敗談ってあまり記事でみないのでスクラムをしている他の方に「こういうことをやって失敗しましたよ」というのが知れ渡るといいなと思い記事にしてみました。
是非反面教師にしていただけると幸いです。
matplotlibでtickparamsを使ってもticklabelが消えないときの対処法

おそらく対数スケールかつ目盛りが細かすぎる場合にTickが消えないことがあります．

```python
import matplotlib.pyplot as plt

_, ax = plt.subplots()
ax.tick_params(left=False, labelleft=False)
ax.set_yscale('log')
ax.grid(which='minor', color='gray', linestyle=':')
ax.grid(which='major', color='black')
```

このときにAd-hocに対応するためにFontsizeを最小にするほうほうがあります．

```python
ax.tick_params(axis='y', which='major', labelsize=1)
ax.tick_params(axis='y', which='minor', labelsize=1)
```
あるHTML要素配下のテキストを一文字ずつ抽出する

body内に書かれているテキストをJavaScriptで一文字ずつ取得したい！！！というニッチな要望に応える記事です。

## たとえば？
```html
<html>
    <head>
        <title>たとえば？</title>
    </head>
    <body>
        たとえばこのように素のテキストや
        <div>
            いろんな要素が
            <p>入れ子になっている<span>時</span>に</p>
            特定の要素配下のテキストをすべて取得して
        </div>
        <div>
            一文字ずつ
            <p>"た" "と" "え" "ば" "こ" "の" ...</p>
            と出力したい</br>
            みたいな話です。
        </div>
    </body>
</html>
```

## 実装コードと出力結果

### コード
```javascript
//parent自身と自身の配下にあるノードすべてにcallbackをさせる
const makeChildrenToDo = (parent, callback) => {
    const children = parent.childNodes;
    //直下の子要素にこの関数を再帰的に適用する
    children.forEach((child) => {
        makeChildrenToDo(child, callback);
    });
    callback(parent);
}
//element直下にあるテキストを一文字ずつ出力する
const logText = (element) => {
    const nodeValue = element.nodeValue;
    //elementがnodeとしては#textであり、truthyであり、空白文字ではない
    if (element.nodeName === "#text" && nodeValue && nodeValue.match(/\S/g)) {
        const characters = Array.from(nodeValue);
        characters.map((chara) => {
            //charaがtruthyであり、空白文字でない
            if (chara && chara.match(/\S/g)) {
                console.log(chara);
            }
        });
    }
}
const main = () => {
    makeChildrenToDo(document.body, logText);
}
window.onload = main;
```

### コードをheadに入れて読み込んだ時の出力結果
```
た
と
え
ば
こ
の
(略)
話
で
す
。
```
body内のテキストが一文字ずつ出力される。
Linux 「/usr/src/linux/」とmakeコマンドについて

FHS（FileSystem　Hierarchy Standard）は、ファイルシステムの標準的な階層配置を定めたもの。カーネルのソースは 「/usr/src/linux/」に展開するのが一般的。


●「/usr/src/linux/」内のファイル・ディレクトリ

ファイル
・.config カーネルのビルド設定ファイル
・Makefile makeの設定やカーネルバージョンが書いてある

ディレクトリ
・kernel/ カーネル本体
・Documentation/ ドキュメントの類
・arch/ アーキテクチャ固有のコード
・drivers/ デバイスドライバ
・fs/ ファイルシステム
・include/ インクルードファイル(他のファイルから呼び出すコードのまとまり)
・mm/ メモリ管理
・net/ ネットワーク

●make コマンド
ソースをコンパイルしてソフトウェアの実行ファイルを作る（ビルドする）

■カーネルをビルドする際の設定に関係する、代表的な make オプション（ターゲット）の一覧

・make config　対話的に(質問形式)設定を行う
・make menuconfig ターミナル上のGUIで設定を行う
・make xconfig　X上のGUIで設定を行う
・make defconfig デフォルト状態の設定を引き継ぐ
・make oldconfig　現在のカーネルの設定を引き継ぐ
・make cloneconfig (oldconfigとほぼ同じ)
・make clean 設定ファイルを除いて一時ファイル等を削除
・make mrproper 設定ファイルを含めて一時ファイル等を削除

■ビルド対象に関連した動作を指定するターゲット

・make all カーネルとモジュールをビルド
・make install ビルドしたカーネルをインストール
・make modules カーネルモジュールをビルド
・make modules_install カーネルモジュールをインストール
・make rpm ビルド後にrpmパッケージ化
・make rpm-pkg ソースrpmパッケージを作る
・make binrpm-pkg バイナリrpmパッケージを作る
・make deb-pkg Debianパッケージを作る

●ソースからのカーネルのビルドとインストール（再構築）の基本的な手順

カーネルのソースは取得・展開済みであるとし、以下はすべてソースを展開したディレクトリ「/usr/src」直下で行う。

1. make mrproper で設定を初期化
make mrproper で設定ファイルを含めてディレクトリ内を初期化。

2. make oldconfig で設定を行う
初期化された設定を再構築用に設定。設定はカーネルをコンパイル（ビルド）する前に行なう。
他には make config 、make menuconfig 、make xconfig などがある。

3. makeでビルドを行う
単に make とするか、make all とすることで、依存関係の解消、カーネル本体とモジュールのビルド、一時ファイルの削除を自動的に行ってくれる。

4. システムにインストールする
ビルドを行っただけではシステムに配置されてはいないので、インストールを行う。通常、make modules_install としてモジュールをインストールしてから、make install としてカーネル本体をインストールする。
make install によって /boot 以下にカーネルイメージが配置され、ブートローダに新しいカーネルを使う起動設定が追加。

●DKMS(Dynamic Kernel Module Support)
カーネルとカーネルモジュールの依存関係による問題を解消し、カーネルのアップデート時に、自動的にカーネルモジュールを更新するための機能。
DKMSは、カーネルアップデートの際に、カーネルとは独立して自動的にカーネルモジュールをコンパイルし、インストール。 
また、手動によりdkmsコマンドを使ってモジュールを構成したり、対象のカーネルモジュールの状態を表示することも可能。
主要な設定ファイルは各モジュールの設定を行うdkms.confと、全体の設定を行う/etc/dkms/framework.conf。
ddc.vim 導入と asyncomplete.vim 導入（neocomplete.vim からの移行）

# 概要
neocomplete.vim がいつのまにか使えなくなっていたので、ddc.vim という次世代補完プラグインを導入してみた。
設定がこれで正しいのか、正直わからない。
多分動いていると思う。
で、正直よく分からないので、もう一つの次世代補完プラグインである asyncomplete.vim の導入もしてみて、どちらが楽かを比較してみた。


```vim:dein.toml（ddc.vim）
#-- 補完
# 本体
[[plugins]]
repo = 'Shougo/ddc.vim'
on_event = 'InsertEnter'
depends = ['denops.vim']
hook_source = '''
call ddc#custom#patch_global('completionMenu', 'pum.vim')
call ddc#custom#patch_global('sources', ['vim-lsp', 'around', 'file'])
call ddc#custom#patch_global('sourceOptions', {
\    '_': {
\        'matchers': ['matcher_head'],
\        'sorters': ['sorter_rank'],
\        'converters': ['converter_remove_overlap'],
\    },
\    'around': {'mark': 'AROUND'},
\    'vim-lsp': {
\        'mark': 'LSP',
\        'matchers': ['matcher_head'],
\        'forceCompletionPattern': '\.\w*|:\w*|->\w*',
\    },
\    'file': {
\        'mark': 'FILE',
\        'isVolatile': v:true, 
\        'forceCompletionPattern': '\S/\S*'
\    },
\})
call ddc#custom#patch_global('sourceParams', {
\    'around': {'maxSize': 500},
\})
inoremap <Tab> <Cmd>call pum#map#insert_relative(+1)<CR>
inoremap <S-Tab> <Cmd>call pum#map#insert_relative(-1)<CR>
call ddc#enable()
'''
# Deno で Vim プラグインを開発するためのプラグイン
[[plugins]]
repo = 'vim-denops/denops.vim'
# ポップアップウィンドウを表示するプラグイン
[[plugins]]
repo = 'Shougo/pum.vim'
# カーソル周辺の既出単語を補完する Source
[[plugins]]
repo = 'Shougo/ddc-around'
on_source = 'ddc.vim'
# ファイル名を補完する source
[[plugins]]
repo = 'LumaKernel/ddc-file'
on_source = 'ddc.vim'
# 入力中の単語を補完の対象にする Filter
[[plugins]]
repo = 'Shougo/ddc-matcher_head'
on_source = 'ddc.vim'
# 補完候補を適切にソートする Filter
[[plugins]]
repo = 'Shougo/ddc-sorter_rank'
on_source = 'ddc.vim'
# 補完候補の重複を防ぐための Filter
[[plugins]]
repo = 'Shougo/ddc-converter_remove_overlap'
on_source = 'ddc.vim'
# LSP
[[plugins]]
repo = 'mattn/vim-lsp-settings'
[[plugins]]
repo = 'prabirshrestha/vim-lsp'
#-------------------------------------------------------------------------------
```

```vim:dein.toml（asyncomplete.vim）
[[plugins]]
repo = 'prabirshrestha/vim-lsp'
[[plugins]]
repo = 'mattn/vim-lsp-settings'
[[plugins]]
repo = 'prabirshrestha/asyncomplete.vim'
[[plugins]]
repo = 'prabirshrestha/asyncomplete-lsp.vim'
[[plugins]]
repo = 'prabirshrestha/async.vim'
[[plugins]]
repo = 'prabirshrestha/asyncomplete-neosnippet.vim'
```
unreachableを活用しよう

## unreachableってなんですか
`unreachable`とは下記で示される関数のことで、要するに到達して欲しくない & し得ない場所に防御的に使う関数です。

```tsx
export const unreachable = (msg?: string) => {
  throw new Error(msg ?? 'Something went wrong')
}
```

## unreachableの活用方法

私はこの`unreachable`の主に2つのユースケースで使用することが多いです。

**パターン1: 三項演算子のチェック**

```tsx
type SomeUnion = 'foo' | 'bar'
const fooOrBar: SomeUnion = 'foo'
const hogeOrFuga =
  fooOrBar === 'foo'
    ? 'hoge'
    : fooOrBar === 'bar'
    ? 'fuga'
    : unreachable('Unexpected value')
```

TypeScriptの型システムで守られていても、実際に`SomeUnion`の値が入ってくるかは保証できないため、このように`unreachable`で検知できるようにしています。

**パターン2: OptionalのUnwrap**

`unreachable`は`never`型を返す関数です。`never`型を返す関数とはreturnされることの無い関数（throwで中断されたり、無限ループで永遠に終わらないなど）という意味です。

この`never`の特性を活かして下記のようにoptional値の強制Unwrapが可能です。

```tsx
export const API_ENDPOINT = process.env.API_ENDPOINT ?? unreachable("API_ENDPOINT is not defined.)
```

少しだけ解説すると、`process.env.API_ENDPOINT` の型は `string | undefined` として扱われます。

もし`process.env.API_ENDPOINT`が`undefined` だった場合、 `unreachable` が実行されプログラムは中断されるということが型情報から判別可能です。

そのためこの先プログラムが正しく動くという事は、`unreachable`を通らないこと、すなわち `process.env.API_ENDPOINT` は `string` であるという型推論が可能となります。

特に環境変数などの値は相性がよいので、アプリのコードの随所で `process.env` を参照せずに一箇所にまとめてUnwrapし管理すると良いと思います。

### P.S.
特にパターン2のUnwrapのケースでは、`invariant`を使うよりも`unreachable`使ったほうが、スマートな気がするなぁ...なんて
materializecssのautocompleteのソートでハマった

# materializecssのautocomplete
materializecssは、cssフレームワーク。
その中のサジェスト機能を実装できるautocompleteがある。

https://materializecss.com/autocomplete.html

## autocompleteの使い方
```javascript
$(document).ready(function(){
    $('input.autocomplete').autocomplete({
      data: {
        "Apple": null,
        "Microsoft": null,
        "Google": 'https://placehold.it/250x250'
      },
    });
});
```

# sortについて
先ほどのautocompleteの初期化の際に、サジェストに表示される順番のsortについて設定することができる。
```javascript
$(document).ready(function(){
    $('input.autocomplete').autocomplete({
      data: {
        "Apple": null,
        "Microsoft": null,
        "Google": 'https://placehold.it/250x250'
      },
      sortFunction: function() {
        ...
      }
    });
});
```

デフォルトでは、以下の関数が使用されて、自動でソートされる。
```javascript
// Sort function for sorting autocomplete results
function (a, b, inputString) {
  return a.indexOf(inputString) - b.indexOf(inputString);
}
```

## ソートを無効にしたい時にハマった
ソートを無効にしたい場合、以下のように記述されており、falseをreturnすれば良いと思った。
> To disable sorting and use the values as they appear in the data object, use a falsy value.

このように、falseを返すように設定したが、うまく動作しません。
```javascript:うまく動作しない
$(document).ready(function(){
    $('input.autocomplete').autocomplete({
      data: {
        "Apple": null,
        "Microsoft": null,
        "Google": 'https://placehold.it/250x250'
      },
      sortFunction: function() {
        return false;
      }
    });
});
```

実際には、compareFunctionに従って指定する必要があった？ようで、比較に対して等しいということで`0`をreturnすることでソートを無効にすることができた。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

```javascript:ソートが無効になった
$(document).ready(function(){
    $('input.autocomplete').autocomplete({
      data: {
        "Apple": null,
        "Microsoft": null,
        "Google": 'https://placehold.it/250x250'
      },
      sortFunction: function() {
        return 0;
      }
    });
});
```
asyncなscript要素で読み込むライブラリと依存コードを同期的に実行する方法(1)

## asyncなscript要素で読み込むメリットと問題点

ページの読み込み速度は、秒の闘いで、3秒待たされたらお客が半分以下になる世界です。

ところが、JavaScriptやCSSなどは、外部からコード読み込んでいる間、ブラウザのレンダリングをブロックし最初のペイントを遅らせます。

### script要素のasync属性

そこで、script要素にはasyncというコードの読み込みを遅延してくれる属性があります。
（仕様 w3c https://dev.w3.org/html5/spec-LC/scripting-1.html#the-script-element）

これをつけると、そのコードの読み込みを文字通り非同期に遅らせるので、その間ブラウザがロックするのを回避できます。

つまり、最初のペイントまでの時間が速くなるのです。

### 問題点

でも、問題もあります。非同期ですが、例えばjqueryなら標準の自動起動関数$(function(){})はうまく動作せず、DOMContentLoadedもライブラリの読み込み完了を教えてくれず、エラーが出ることがあります。この属性にはcallbackやawaitなどは無いのです。(このシリーズの3回目でscript要素自身のonloadによる対策ついて書いています)

今回は、例えば、メインのHTMLと読み込むライブラリとしてjqueryの2つのファイルを用意して操作を確認してみます。

### コード
今回はアロー関数などは使わずにベーシックな書き方でいきます。

<strong>main.html</strong>
```html
    <script>
    let i=0 //発火順序表示用の変数
    </script>
    <script async src="js/jquery-3.6.1.min.js?1"></script>
    <script>
        // DOMContentLoaded
        document.addEventListener('DOMContentLoaded', function() {
            console.log(++i,': DOMContentLoaded')
        });

        // window.onload
        window.onload = function() {
            console.log(++i,': window.onload ')
        }

        // jqueryの $(function(){})
        $(function(){
            console.log(++i,': $(function(){})')
        })
    </script>
```
<strong>jquery-3.6.1.min.js</strong>
jqueryファイルの最後にコードを追記します。
```js
 //省略
  :
  :
&define.amd&&define("jquery",[],function(){return S});var Yt=C.jQuery,Qt=C.$;return S.noConflict=function(e){return C.$===S&&(C.$=Qt),e&&C.jQuery===S&&(C.jQuery=Yt),S},"undefined"==typeof e&&(C.jQuery=C.$=S),S});

// jquery の最後に読み込んだことを示すconsole.logを書きます
console.log(++i,':(in jqf) at the jquery file end')
```


### 結果
```
Uncaught ReferenceError: $ is not defined
1 ': (in jqf) at the jquery file end'
2 ': DOMContentLoaded'
3 ': window.onload '
```
これが何を意味するかというと、jquery が読込み終わる1の前に「＄」が呼ばれて「$ is not defined」と言われてしまっています。
2,3のイベントはjquery が読込み後に発火しています。

いくつかのサイトでDOMContentLoadedやwindow.onloadは大丈夫と書かれているケースも見かけましたが、

実は、問題なのはこれです。Macで同じコードを試した結果です。
```
Uncaught ReferenceError: $ is not defined
1 ': DOMContentLoaded'
2 ': at the jquery file end'
3 ': window.onload '
```
「2 ': at the jquery file end'」の前に DOMContentLoaded が来てしまっています。つまり、DOMContentLoadedの中でもしjqueryのコードを使えば、jqueryはまだ読み込まれていないので、エラーになります。

やはり、非同期の読み込み終了がいつになるのかはこれではわからないという事のようです。

少なくともDOMContentLoaded も script loaded 後に発火するという保証のないことが証明されました。

### 対策
いつ読み込み終わるかわからなくては、いつエラーが出るかもわからず、使い物になりません。

それなら、どうしたらよいのでしょう？

そこで対策を考えてみました。つづく。

asyncなscript要素で読み込むライブラリと依存コードを同期的に実行する方法(2)
https://qiita.com/toshirot/items/c60d987378ff6bdbaf27

### 関連
次回の、、読み込むライブラリファイルに依存コードを同梱する方法
https://qiita.com/toshirot/items/c60d987378ff6bdbaf27
次々回の、script要素.onloadイベントで読み込み完了を取得する方法
https://qiita.com/toshirot/items/f454c9fdcc78f6d90d01
useStateの配列要素を追加したい場合の記述

はじめに
--
ポートフォリオでuseStateで作成した配列要素を追加したい場面があり、学んだ内容を備忘録として残そうと思います。

前提
--
例えば、果物の情報を格納している配列があったとします。
~~~react
const [fruits, setFruits] = useState([{
    fruitsName: "apple",
    fruitsPrice: 200
  }])
~~~

現状はfruitsの中身は下記のようになっていますが、ここに複数の果物の情報を格納したいとします。
~~~react
fruits = [{fruitsName: "apple", fruitsPrice: 200}]
//理想は下記のように複数の果物の情報を格納していきたい
[{fruitsName: "apple", fruitsPrice: 200}, {fruitsName: "lemon", fruitsPrice: 100}]
~~~

配列要素を追加する方法
--
配列要素に追加をするためには、下記のように記述をします。
~~~react
setFruits(fruit => [...fruit,{ fruitsName: "lemon", fruitsPrice: 100 }])
//fruits = [{fruitsName: "apple", fruitsPrice: 200}, {fruitsName: "lemon", fruitsPrice: 100}]になる
~~~
ちなみに、"..."はスプレッド構文というもので、ものすごく乱暴にざっくりと説明すると、現在のfruitsの配列の情報を全て持ってきてくれるものです。

"...fruits,"を追加したい情報の前に記述して[]で囲むことで、fruitsの配列の最後に"{ fruitsName: "lemon", fruitsPrice: 100 }"を追加する、ということができます。

この配列を追加する方法に＋αの記述をすることで、フォームに入力した値を配列に格納ができるようになります。


参考
--
スプレッド構文も理解まだ浅いと思うのでqiitaにまとめようと思います。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax
ESP32-CAM　開発検証用ボード（回路図）

自作したESP32-CAM用の検証用ボードの回路図を公開します。
回路図はmalmeloで作成しています。
https://motchy99.blog.fc2.com/blog-entry-70.html

表
![ESP32-CAM_Testar_o.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1852162/d888a09a-0733-e559-1090-5788925abcf1.png)

裏
![ESP32-CAM_Testar_u.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1852162/f784cb71-3c82-28f0-4957-4a7a5261465a.png)

回路図だけ見ても分かりずらいので、写真と各パーツについては以下
![コメント.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1852162/a814d199-9d8c-ea8a-ccc6-448dd7d9d368.jpeg)

ユニバーサル基盤で作成
ハードは専門外なので、間違ってても気にしません。
電圧と+-ぐらいしか気にしてません。
（動作検証でLEDに5Vを流して殺してます）

●主な機能
・ESP32-CAMはピンソケットで抜き差し可
・電源供給はmicroUSB、ピン、リポの3つ
・IO4,2,14,15,13,12をLEDに接続
・基盤下のスライドスイッチが電源スイッチ（全入力電源を制御）
・基盤右のスライドスイッチは書き込みのON/OFF（IO0とGNDをジャンプさせます）

上記すべての電源で起動確認済み
正直、昇圧回路で3.7Vリポ1つで起動できるとは思いませんでした。

●補足
写真では基盤上部にESP32の3.3Vへ電力を共有するピンヘッダーがついてますが、試しにやってみましたがESP32は起動しませんでした。
なので回路図には反映されていません。

昇圧回路周りでジャンパー線がごちゃごちゃしてます。
原因は当初、昇圧回路のVO（VOUT）とVI（VIN）をV0、V1と勘違いしたため逆に接続してしまい、後から無理やりジャンプしたためです。

昇圧回路の出力にはコンデンサを挟んだ方がいいのかもしれません。
Kubernetes のサービスとは  (1) 大雑把な理解

# この記事について
Kubernetes の Service は、使い方は分かるけど実体がつかみずらく、漠然と使われることの多いリソースと思う。そこで Service の実体を整理してみる。

# Service の大雑把な理解

まず Kubernetes から離れて、複数台の Web サーバーがあってそれを外部ネットワークに公開したいという場面を考える。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/539081/b4c7d419-9f79-66b7-4bda-b154f57c14bd.png)

この時、大体以下の考慮が必要になる。
- Web サーバーへのアクセスを負荷分散させたい
- Web サーバーの数が増減することがある
- Web サーバーのIPが変わることがある(サーバーが壊れた等)
- Web サーバーで障害が起きたら、それにはリクエストを転送しないようにする
- Web サーバーには、IP アドレスだけでなく名前でアクセスできるようにしたい

そこで以下のように前段にロードバランサーを置くことが一般的。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/539081/6e476572-a140-1b87-8e50-bb357bec2e09.png)

このロードバランサーは Web サーバーの増減や IP 変更の追跡、そして死活を把握する必要がある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/539081/238faa08-294d-97c8-570b-d4bec17ba6c0.png)


これを Kubernetes に置き換えると下図のような感じになる。まず Pod が接続されてるのが Pod Network(または Cluster Network)、Load Balancer の外側が Service Network。そして、図のLoad Balancer には DNS名と IP アドレス(ClusterIPと呼ばれる)が自動で割り当てられる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/539081/75ec63ca-8b33-20d3-c531-bbccfe921752.png)


そして、赤枠の部分を自動で構成してくれるのが Service というリソースになる。手動で構成しようとすると相当大変なので、これを一発で自動構成してくれる Service リソースはとてもありがたいと言える。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/539081/a92e5e4b-7fa8-1886-0f91-fd1fdf3fbbf3.png)


なお、上図の赤枠部分をもう少しちゃんと書くと、Service と Endpoints(または EndpoitSlice) というリソースで役割分担している。Endpoints(または EndpoitSlice) は、Service を作成するとそのペアとして自動で作成される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/539081/58c7f5e6-0b28-a377-c476-ce969028c992.png)


# 何が分かりずらいの？
概念的にはそれほど難しくなさそうだが、では Service がなぜ漠然とするかというと、図に現れたネットワークやロードバランサー、IP 等の実体が何か、それを誰がどこでどう実現してるのか、という Kubernetes 上での実体が掴みづらいところと思う。
それらの実体や構成を行う登場人物を紐解いてみる。

# Kubernetes のコンポーネントについて
実体を紐解くにあたって、どうしても Kubernetes を構成するコンポの知識が必要になる。記事の中にも説明を記載するが、例えば公式サイトにも [Kubernetesのコンポーネント](https://kubernetes.io/ja/docs/concepts/overview/components/) のページがあるので、必要に応じて参照いただければ。

# 続き
- [Kubernetes のサービスとは (2) リソース、API Server、コントローラー](https://qiita.com/nozmiz/items/715913f3026d9ca699bb/)
本番環境でFailed to upgrade to WebSocketエラー

### 状況
ローカルでは投稿に対してのコメントができる(ajax)のに、本番環境ではできていなかった。

### 原因
本番環境でactioncableが使えない状況だった

### 解決方法
```ruby:EC2内
$ sudo vim /etc/nginx/conf.d/rails.conf
```
以下を貼り付ける。
```ruby:/etc/nginx/conf.d/rails.conf
upstream app_server {
  server unix:/var/www/アプリケーション名/shared/tmp/sockets/unicorn.sock;
}

server {
  #省略
# -------------------ここから-------------------
# /cableのパスに対してwebsocketの仕組みを用いるための設定
  location /cable {
    proxy_pass http://app_server/cable;
    proxy_http_version 1.1;
    proxy_set_header Upgrade websocket;
    proxy_set_header Connection Upgrade;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
# -------------------ここまでを追記-------------------
  #省略
}
```
これで、自分はコメント(ajax)ができるようになりました。
### 参考
https://qiita.com/tochisuke221/items/9051d1de935150203660
S３から最新ファイルをダウンロードしてスライドショー表示

ラズパイでフォトフレームを作る際にS3バケットから最新のファイルのみダウンロードして、
表示させようと試みたのでその時の備忘録。
あくまで個人のメモ程度の情報なので、参考にはならないかもしれません…

## S3から最新ファイルを取得するPythonファイルを作る。
まずはラズパイにPythonファイルを作成。
ちなみに、Python環境やS3、AWS-CLIとかの設定は済んでいるものとして今回は割愛します。

```
import os
import boto3

accesskey="*****"
secretkey="*****"
region = '*****'
bucket_name = '****'


#Bucket list cache
def list_files(bucket_name):
    s3 = boto3.client('s3',aws_access_key_id=accesskey,
                      aws_secret_access_key=secretkey,
                      region_name=region)
    contents = []
    for item in s3.list_objects(Bucket=bucket_name)["Contents"]:
        contents.append(item)
        
    return contents
    
#------------------------------------------------------

s3 = boto3.resource('s3')

s3_list = list_files(bucket_name)
Keylist = []
loop_first = True

for i in s3_list:
    if loop_first:
        dl_target_file = i.get("Key")
        mod_datetime = i.get("LastModified")
        Keylist.append(dl_target_file)
        loop_first = False
    
    else:
        if mod_datetime <= i.get("LastModified") and i.get("Key").endswith("png"):
            mod_datetime = i.get("LastModified")
            dl_target_file = i.get("Key")
            Keylist[0] = dl_target_file

file_name = Keylist[0]

# 今回はDocumentディレクトリのimgフォルダ内にpngファイル作る
output = '/home/pi/Documents/img/'+ file_name
print(file_name)
s3.Bucket(bucket_name).download_file(file_name,output)
```
## スライドショー起動設定
fehというビューアーを使う
```
sudo apt-get install feh
```
設定。マニュアル確認
```
man feh
```
起動確認
```
feh -Y -x -q -D 60 -R 3600 -F -Z -r -z ~/Documents/img/
```
CronでPythonファイルを定期実行させる
```
crontab -e 
```
50分おきに実行させる
```
*/50 * * * * python /home/pi/<pythonファイルの絶対パス>
```
cron設定内容の確認　```crontab -l```
実行確認をする  ```less /var/log/syslog | grep cron```
cronステータス確認　```sudo systemctl stats cron```

pythonがなぜか実行されなかったのだが、
実行権限が付与されてなかったのでpythonファイルに```chmod 777 <ファイル名>```で解決。

ちなみに、画面のスリープ状態になるのを解除したい場合はこちらを参考
https://rikoubou.hatenablog.com/entry/2020/06/11/133716

## 参考記事
https://qiita.com/yolo_kiyoshi/items/a4e95084b4cabb694c29

https://lab.sonicmoov.com/development/raspberry-pi-3-digital-photo-frame/

https://algorithm.joho.info/raspberry-pi/cron-python/

https://i-think-it.net/linux-cron-not-be-execute/
Git Flowで開発中のプロジェクトに途中から参加する場合の手順

<h2>きっかけ</h2>
GitFlowで開発中の既に動いているプロジェクトに途中から参加した場合に、

``git flow init``コマンドでエラーが出たので備忘録程度に残しておきます。

<h2>解決方法</h2>
既にdevelopブランチがある場合はこのコマンドでmasterブランチをリモートリポジトリから取り込んでおく。
恐らく逆もしかりでmasterブランチとdevelopブランチの二つが必要。


```
git checkout -b master origin/master
```

作成されたら``git flow init``で初期化。
開発を始めていきましょう！！
【入門】Ruby  eachメソッドの様々な使い方を具体的に紹介

# はじめに
今回は、Rubyに標準で組み込まれている`eachメソッド`について、備忘録としてまとめます。

※おことわり※
基本的に学習内容のアウトプットです。
初学者であるため、間違い等あればご指摘いただけますと嬉しいです。

# この記事の目的
Rubyに標準で組み込まれている`eachメソッド`についてアウトプット

# この記事の内容
1. each_with_index
2. each.with_index
3. eachの入れ子 
4. each_slice
5. each_key
6. each_value


# 1. each_with_index
eachメソッドと同様に、要素の繰り返し処理を行いつつ、その要素が何番目に処理されたものなのか表示するメソッドです。
eachでループを回しつつ、それぞれのデータ（要素）に番号を振りたい時などに使います。

- 書き方
```ruby
配列名.each_with_index do |item, index|

end
```
- 基本的な書き方
```ruby
#書き方①
foods = ["あんぱん", "メロンパン", "食パン"]

foods.each_with_index do |item, index|
 puts "#{index + 1}番目の食べ物は、#{item}です。"
end

#書き方② doとendを省略
foods.each_with_index { |item, index| puts "#{index + 1}番目の食べ物は、#{item}です。" }

# 返り値
1番目の食べ物は、あんぱんです。
2番目の食べ物は、メロンパンです。
3番目の食べ物は、食パンです。
```

- 応用的な書き方
任意の数字が配列の中の何番目に格納されているかを確認します。
存在する場合、「○○は○番目にあります」と返し、存在しない場合は「その数は含まれていません」と返します。
```ruby
def search(target_num, input)

  input.each_with_index do |num, index|
    if num == target_num
      puts "#{num}は、#{index + 1}番目にあります"
      return
    end
  end
  puts "その数は含まれていません"
end

input = [11, 39, 55, 49, 70]

search(11, input)

# 返り値
11は、1番目にあります
```


# 2. each.with_index
こちらはメソッドではなく、`each + with_index`を組み合わせています。
上記の`each_with_index`は添字が０から始まりますが、 `each.with_index`は開始したい番号を指定することができます。
- 書き方
```ruby
配列名.each.with_index(開始したい番号) do |item, index|

end
```

- 具体的な書き方
```ruby
foods = ["あんぱん", "メロンパン", "食パン"]

foods.each.with_index(20) do |item, index|
 puts "#{index}番目の食べ物は、#{item}です。"
end

# 返り値
20番目の食べ物は、あんぱんです。
21番目の食べ物は、メロンパンです。
22番目の食べ物は、食パンです。
```

# 3. eachの入れ子 
以下の配列より、果物の名前とそれぞれの合計額が出力する。
```ruby
fruits_price = [["apple", [200, 250, 220]], ["orange", [100, 120, 80]], ["melon", [1200, 1500]]]

#["apple", [200, 250, 220]という形で1つずつ取り出す
fruits_price.each do |fruit|
	#[200, 250, 220]という形で1つずつ取り出し、sumに自己代入する
    sum = 0
	fruit[1].each do |price|
		sum += price
	end
	puts "#{fruit[0]}の合計金額は#{sum}円です。"
end

# 返り値
appleの合計金額は670円です。
orangeの合計金額は300円です。
melonの合計金額は2700円です。
```

# 4. each_slice
配列の要素を指定した数に分割して出力する。
※分かりやすく出力するため、putsではなく`p`を使用しています。
```ruby
fruits = ["apple", "orange", "melon", "grape", "cherry", "strawberry"]
fruits.each_slice(2) do |fruit|
  p fruit
end

# 返り値
["apple", "orange"]
["melon", "grape"]
["cherry", "strawberry"]

fruits.each_slice(3) do |fruit|
  p fruit
end

# 返り値
["apple", "orange", "melon"]
["grape", "cherry", "strawberry"]
```

# 5. each_key
配列と同様に、ハッシュを`each_keyメソッド`を使ってループします。

```ruby
hash = {one: 1, two: 2, three: 3}
hash.each_key {|key|  puts "#{key}"}

# 返り値
one
two
three
```

# 6. each_value
ハッシュの`value`を取り出したい時は以下のように記述します。
```ruby
hash = {one: 1, two: 2, three: 3}
hash.each_value { |value| puts "#{value}"}

# 返り値
1
2
3
```
お名前.com＋AWS CloudFrontでコンテンツ配信する際のDNS設定方法～第3レベルのサブドメイン～

# はじめに
AWSのネームサーバーを使って対応する方法は[こちら](https://zenn.dev/marumarumeruru/articles/40c33511900e33)の記事が参考になりました。
お名前.comのレンタルサーバーを利用している場合はネームサーバーを変更できないかと思うのでその際は[こちら](https://zoo200.net/cloudfront-ssl-original-domain)の記事が参考になりました。
じゃあこちらの記事で何を書くのかというと、www.サブドメイン.メインドメインという形式の第3レベルのサブドメインを用いるケースでは特殊なやり方が必要だったのでそのやり方を書きます。
（「www.サブドメイン.メインドメインという形式」ってwwwの使い方間違っているのかなとも思いつつ、シンプルに自分用にもメモが欲しかった。）
他にいい方法があったらご教授お願い致します。

# 環境
* お名前.comのレンタルサーバーを利用
（メールサービスを利用している）
* AWS CloudFront
* AWS Certificate Manager

# 1．お名前.comでサブドメイン用のDNSレコードを作成する
目的は、DNSレコードに「default._domainkey.[サブドメイン].[メインドメイン]」を自動生成してもらう目的です。
（上記DNSレコードは本来はメールサービス用の設定な気もするがこれがないとSSL証明書エラーが発生してしまうので追加する）
* まず、レンタルサーバー用のDNS設定画面へ遷移する（以下の赤枠で囲んだメニューから遷移できるやつ）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388393/729114e2-733c-d9e5-c741-82bfa002bc55.png)
* 次にサブドメインを追加する（ドメイン一覧の以下の赤枠で囲んだボタンから追加できる）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388393/d7f915c1-48bd-a098-8176-f5fdf8cdffd8.png)
* サブドメインを追加してしばらくするとたくさんレコードが追加されていると思うので以下のように「default._domainkey.[サブドメイン].[メインドメイン]」形式の「ホスト名」のDNSレコードだけ残してあとは削除する
※　特にwww始まりのは削除しないとwwwを第3レベルのサブドメインに設定したサイトへのアクセスがCloudFrontにならないので注意
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388393/b7cee37b-ec87-62bd-b104-94d5494ade52.png)

# 2. お名前.comでAWS Certificate Managerの検証用CNAMEレコードとCloudFrontのドメイン名CNAMEレコードを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388393/c1a01986-d39e-408d-e268-d9dcfd935a5c.png)

# 3. お名前.comでドメイン一覧から追加したサブドメインを削除する
何故か削除しないとお名前.comで用意した独自ドメインでCloudFront側にアクセスできないので削除します。

## 設定完了！

## 所感
謎が多い設定なので、まだまだ検証の余地ありかなと思います。。
冒頭にも書きましたが、他にいい方法があったらご教授お願い致します。
Makefileで作業ディレクトリを使う、他

## 概要
うまいやり方ないなと思っていたら、思いついたので備忘録として残す。

## 環境

* GNU Make 4.2.1

## Tips

### Makefileで作業ディレクトリを使う

**なぜやるか**

* 作業ディレクトリが固定の場合、並列でmakeをすると悲しいことになる
  * 作業ディレクトリ内のファイルが処理中に書き換えられる

**やり方**

やり方は色々あるが、作ることよりも失敗したときに如何に消すかが問題となる。

解説は後にして、次のように書くと良い。

```makefile
test-mktemp:
    $(eval WORK_DIR := $(shell mktemp -d abcde-XXX))
    bash -c "while test -d /proc/$$PPID; do sleep 0.5; done; rm -fR $(WORK_DIR)" &
    ...好きな処理...
    例) echo "hello" > $(WORK_DIR)/hello.txt
```

**解説**

* 続く行で作業ディレクトリのパスを知りたいので eval で一時ディレクトリのパス名を控える
* makeのプロセスが死ぬまで待って、死んだら作業ディレクトリを削除するコードをバックグラウンドで動かすコードを仕込みます
  * makefile では子プロセスでコマンドが実行されるので、makeのプロセスは `$PPID` で取得します。
     * shell では `trap "rm -fR 作業ディレクトリ" EXIT` で終了時にファイル削除ができるが、`trap`を仕込んでも実行されるのは子プロセス側なので、次の行で有効にはならない

**検証用コード**
成功時と失敗による中断時の双方で動作することを確認するため、終了コードを引数で受け取れるようにする。

```makefile
EXIT_CODE ?= 0
test-mktemp:
    $(eval WORK_DIR := $(shell mktemp -d abcde-XXX))
    bash -c "while test -d /proc/$$PPID; do sleep 0.5; done; rm -fR $(WORK_DIR)" &
    sleep 3
    echo "hello" > $(WORK_DIR)/hello.txt
    cat $(WORK_DIR)/hello.txt
    exit $(EXIT_CODE)
```

以下の通り、 exit した後で、ディレクトリが消え `ls: cannot access` と表示される(期待通りの動作)。

```console
$ make test-mktemp EXIT_CODE=0 & timeout 5 bash -c "while true; do ls -1d abcde-*; sleep 1; done"
[1] 49784
bash -c "while test -d /proc/$PPID; do sleep 0.5; done; rm -fR abcde-O2i" &
sleep 3
abcde-O2i
abcde-O2i
abcde-O2i
echo "hello" > abcde-O2i/hello.txt
cat abcde-O2i/hello.txt
hello
exit 0
# timeout 3 bash -c "while true; do ls -ld abcde-O2i; sleep 1; done"
abcde-O2i
ls: cannot access 'abcde-*': No such file or directory
[1]+  Done                    make test-mktemp EXIT_CODE=0
```

```console
$ make test-mktemp EXIT_CODE=1 & timeout 5 bash -c "while true; do ls -1d abcde-*; sleep 1; done"
[1] 49831
bash -c "while test -d /proc/$PPID; do sleep 0.5; done; rm -fR abcde-zh2" &
sleep 3
abcde-zh2
abcde-zh2
abcde-zh2
echo "hello" > abcde-zh2/hello.txt
cat abcde-zh2/hello.txt
hello
exit 1
make: *** [Makefile:46: test-mktemp] Error 1
abcde-zh2
ls: cannot access 'abcde-*': No such file or directory
[1]+  Exit 2                  make test-mktemp EXIT_CODE=1
```
Joda-Timeで固定の現在時刻を返す


例えば、ユニットテストで現在時刻返すメソッドを固定日付で返したい、などのケースがある。

```gradle
implementation 'joda-time:joda-time:2.11.1'
```

```java
import org.joda.time.DateTime;
import org.joda.time.DateTimeUtils;

public class JodaTImeSsample {
  public static void main(String[] args) {

    DateTimeUtils.setCurrentMillisFixed(DateTime.parse("2010-06-30T01:20").getMillis());
    DateTime now = DateTime.now();
    System.out.println(now); // 2010-06-30T01:20:00.000+09:00

    DateTimeUtils.setCurrentMillisSystem(); // 現在時刻を返すようにリセット
  }
}
```

<code>DateTimeUtils.setCurrentMillisFixed</code>は下記のように```static```変数を書き換える。```volatile```付いてるとはいえ、マルチスレッドで何度も書き換えるのはちょっと怖い。ユニットテストを平行に実行しなければ問題は無い……とは思うが。

```java
    private static volatile MillisProvider cMillisProvider = SYSTEM_MILLIS_PROVIDER;

    public static final void setCurrentMillisFixed(long fixedMillis) throws SecurityException {
        checkPermission();
        cMillisProvider = new FixedMillisProvider(fixedMillis);
        ...
```

新規にJoda-Time使うことは無いと思われるが、既存部分についてはやはり後発の```java.time.Clock```を使う方が良いだろう。

```java
import java.time.Clock;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;

public class JodaTImeSsample {
  public static void main(String[] args) {
    Clock c = Clock.fixed(Instant.parse("2007-12-03T10:15:30.00+09:00"), ZoneId.systemDefault());
    LocalDateTime now = LocalDateTime.now(c);
    System.out.println(now); // 2007-12-03T10:15:30

  }
}

```
Xsd.exeを使ってXsdからクラスを作ろう

# Xsd.exeを使ってXsdからクラスを作ろう

[Xsd.exe公式ドキュメント]([URL](https://learn.microsoft.com/ja-jp/dotnet/standard/serialization/xml-schema-definition-tool-xsd-exe) "XML Schema Definition Tool (Xsd.exe)")

- [Xsd.exeを使ってXsdからクラスを作ろう](#xsdexeを使ってxsdからクラスを作ろう)
  - [ゴール](#ゴール)
  - [開発環境等](#開発環境等)
  - [XMLとXsd](#xmlとxsd)
  - [基本コマンド](#基本コマンド)
  - [オプション解説](#オプション解説)
    - [属性で指定する項目](#属性で指定する項目)
      - [language](#language)
      - [namespace](#namespace)
      - [options](#options)
    - [要素で指定する項目](#要素で指定する項目)
      - [element](#element)
      - [schema](#schema)

## ゴール

- XMLとXsdについて分かる　←　まだ書いてない
- XsdからClassが生成できるようになる
- プログラムからXMLを操作できるようになる ←　まだ書いてない

## 開発環境等

- VisualStudio2022
- C#
- .netflamework

## XMLとXsd

## 基本コマンド

開発者用コマンドプロンプトで実行

```cmd
 xsd {xsdファイル} /p:{オプション設定ファイル(xml)} /outputdir:{出力されるディレクトリ}
 {}は必要ない
```

「/p:」は必須ではないが推奨。次の項目で解説するオプション設定を行う際にコマンドの引数として実行することもできるが、設定ファイルを用いたほうが見やすい。

## オプション解説

### 属性で指定する項目

#### language

- 生成される言語の種類を設定
- C# ⇒ CS
- Visual Basic ⇒ VB

#### namespace

- 生成されるクラスが属する名前空間を設定できる
  
#### options

いくつか設定できる値があるがpropertiesおよび生成されるクラスのメンバについて記載

|  option設定  |  生成されるクラスのメンバ  |
| ---- | ---- |
|  なし  | プロパティ  |
|  properties  |  プロパティ  |
|  none  |  パブリックフィールド  |

ただしプロパティはバッキングフィールドを含むプロパティとなる。

### 要素で指定する項目

#### element

- Xsdファイルにある要素を指定することでその要素のみがクラスとして生成される
- 複数指定可能 全要素を指定する場合何も指定しないのと同じソースが生成される

#### schema

- **ImportしているXsdはここで指定しないと認識されない**
- xsdコマンドのパラメータで指定する以外のXsdファイルを指定することができる
- 複数指定可能