OmniAICreator/Qiita-1.07M huggingface dataset:
python GUI入門　 QtDesigner + pySide　カスタムウィンドウ:GUIの部品化

# 実行サンプル
MainWindow画面にCustomWidget として部品化したものを複数埋め込みできる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423803/8570eab6-5fa0-13a6-df33-f128aca51c03.png)


# 実行環境
windows10
python3.9.5
Qt5.1.5 (QtDesigner6.0.2コミュニティ)

pythonモジュール：pySide6（pipでインストールしておく）

# 実行手順
ソースコードを作成する
windowsコマンドプロンプトでプログラム作成したフォルダに移動し、下記実行する
```
python mainwindow.py 
```

# ソースコード作成手順
以下を参照。
python GUI入門　 QtDesigner + pySide 基礎
https://qiita.com/taiko1/items/c19d75ba09d60ae5f5a6

■　作成時の注意点： Ui_CustomWidget
CustomWidget.ui のトップオブジェクトは、オブジェクト名を CustomWidget にする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423803/6473d9ec-d35a-6495-0ea9-aaee4e8cf26a.png)

PySide6-uic コマンドで　Ui_CustomWidget.py として作成すると
Ui_CustomWidget の記述が入ったものになる。

CustomWidget.py の中で Ui_CustomWidget　を記述して、GUIフォームとして取り扱えるようにする。
```
from Ui_CustomWidget import Ui_CustomWidget 

# カスタムWidget
class CustomWidget(QtWidgets.QWidget):

    def __init__(self, title =None, path=None, parent=None):
        super(CustomWidget, self).__init__(parent)

        self.ui = Ui_CustomWidget()
        self.ui.setupUi(self)
```

# ソースコード
https://github.com/sakurataiko1/Python_GUI_pySide/tree/main/pySide6_customWidget

下記で構成される。
CustomWidget.py
CustomWidget.ui
MainWindow.py
MainWindow.ui
pySide6_customWidget.pyproject
Ui_CustomWidget.py
Ui_MainWindow.py


# 関連資料
https://fereria.github.io/reincarnation_tech/11_PySide/00_Tutorial/04_widgets/
Google Colabでmmdetection3dを試す（学習編）

# 概要

[以前の記事](https://qiita.com/np_hsgw/items/2c843d91f2fb62009661)ではmmdetection3dがGoogle Colab環境でもある程度動きそうだというところまで試した。今回は実際に学習が行えることを確認したので、その詳細について記事にする。

## 前提条件

* 使用するmmdetection3dはv1.0.0rc6です。
* nuScenesデータセットの`v1.0-mini`を使用して学習する。
* 学習時間短縮のためGPUはA100を使用した。
    * Colab Proを契約してランタイムのGPUクラスをプレミアムに設定
* 学習済みモデルの検証は行わない。

## 結果

学習自体は約2時間40分程度で完了。

## 詳細

* 事前準備
    * Google DriveにnuScenesデータセットの`v1.0-mini`をアップロードする。
* コードの詳細
    * 処理の流れ
        * Google Driveのマウント
        * データセットをColab上にコピー
        * 解凍
        * mmdetection3dの環境構築
        * データセットをmmdetection3dに読み込ませるための準備
        * 学習
    * 環境構築は前回記事とほぼ同じだが、Google Colabがデフォルトでpython3.9以上のバージョンであるため、`networkx`ライブラリをver2.5に更新する処理を追加している。
        * エラーメッセージが出るがプログラムの実行には問題なし。

```python
# Commented out IPython magic to ensure Python compatibility.
from google.colab import drive
drive.mount('/content/drive')
%cp "./drive/MyDrive/Colab Notebooks/v1.0-mini.tar" ./


# Commented out IPython magic to ensure Python compatibility.
!tar -xvf v1.0-mini.tar

!pip3 install openmim
!mim install mmcv-full==1.7.0

!mim install mmdet

# Commented out IPython magic to ensure Python compatibility.
# mim経由でのインストールはかなり時間がかかる
#!mim install mmsegmentation
# 手動インストールなら早い
!git clone https://github.com/open-mmlab/mmsegmentation.git
%cd mmsegmentation
!pip install -e .
%cd ..

# Commented out IPython magic to ensure Python compatibility.
!git clone https://github.com/open-mmlab/mmdetection3d.git
%cd mmdetection3d
!pip install -e .

!pip install networkx==2.5


# Commented out IPython magic to ensure Python compatibility.
%cd /content/mmdetection3d/

# Commented out IPython magic to ensure Python compatibility.
%mkdir data/nuscenes
%cd data/nuscenes
!ln -s /content/maps/ maps && ln -s /content/samples/ samples && ln -s /content/sweeps/ sweeps && ln -s /content/v1.0-mini/ v1.0-mini


# Commented out IPython magic to ensure Python compatibility.
%cd /content/mmdetection3d/
!python tools/create_data.py nuscenes --root-path ./data/nuscenes --version v1.0-mini --out-dir ./data/nuscenes --extra-tag nuscenes

# Commented out IPython magic to ensure Python compatibility.
# 1つのGPUでトレーニングする
%mkdir work_dir
!python tools/train.py  configs/centerpoint/centerpoint_01voxel_second_secfpn_circlenms_4x8_cyclic_20e_nus.py --work-dir work_dir



```
[Python]フォルダzip圧縮、展開

# はじめに
フォルダの圧縮、展開を自動化に便利なように
他のスクリプトから呼び出せる形の関数を作成したみました。
圧縮については指定したフォルダ以下のサブディレクトリ含むすべて対象になっています。

# ソースコード
## 関数
```python:zip.py
#######################################################
# How to use
# zip.zipFolder(".\FolderName")
#######################################################

import os, zipfile

zipExtension = '.zip'

def zipFolder(folderPath):
    zipFolder = folderPath + zipExtension
    print(zipFolder)
    with zipfile.ZipFile(zipFolder,'w') as myzip:
        for folder, subfolders, files in os.walk(folderPath):
            myzip.write(folder)
            for file in files:
                myzip.write(os.path.join(older,file))

#######################################################
# How to use
# zip.unzipFolder(".\FolderName")
#######################################################

import os, zipfile

zipExtension = '.zip'

def unzipFolder(folderPath):
    unzipFoler = folderPath + zipExtension
    print(unzipFoler)
    with zipfile.ZipFile(unzipFoler, 'r') as zf:
        zf.extractall(r'.\\'
```
## 呼び出し側
```python:main.py
import zip

folderPath = ".\test"
destinationFolder = ".\out"

# 指定したフォルダをzip圧縮する
zip.zipFolder(folderPath)
# 指定したzipフォルダを展開する
zip.unzipFolder(destinationFolder)
```
# 参考文献
[1.Pythonで指定フォルダ配下のサブフォルダとファイルを全てZIP圧縮する方法](https://tonari-it.com/python-zipfile-walk/)
2.Python コードレシピ集 黒住敬之著 技術評論社
WordPressで大きな画像ファイルをアップロードする


# WordPressでデフォルトのアップロードより多めにアップロードする

そのためにphp.iniの設定が必要になります

まず、設定ファイルを開いて


```bash
sudo vim /etc/php/7.4/apache2/php.ini
```


```php.ini
upload_max_filesize = 2104M
post_max_size = 2104M
memory_limit = 1052M
```

該当箇所を編集します。

これでおしまい。
error TS2307: Cannot find moduleが出た時の対処方法

エラー文の通り、何かしらの原因でtypescriptコンパイラがソースファイルを見つけられていない、という事象が起きています。

なので、typescriptコンパイラが「どういう考えで」「どのパス」に対象のソースファイルを探しに行っているのかを知ることが出来れば、原因が特定できそうです。

## コンパイラのファイル探しの挙動を見る方法
下記のどちらかを行うことで、typescriptコンパイラのファイル探しの挙動をみることが出来ます。（[参考](https://www.typescriptlang.org/docs/handbook/module-resolution.html#tracing-module-resolution)）
- `tsc`でコンパイル時に`--traceResolution`オプションを付ける
- `tsconfig.json`の`traceResolution`を`true`に設定しコンパイルする

このようなログが出るようになります↓
```
======== Resolving module './infra/logger/LoggerModule.js' from '/app/AppModule.ts'. ========
Step #0: Explicitly specified module resolution kind: 'Node16'.
Step #0: Resolving in ESM mode with conditions 'node', 'import', 'types'.
Step #0: Loading module as file / folder, candidate module location '/app/infra/logger/LoggerModule.js', target file type 'TypeScript'.
Step #0: File name '/app/infra/logger/LoggerModule.js' has a '.js' extension - stripping it.
Step #0: File '/app/infra/logger/LoggerModule.ts' exist - use it as a name resolution result.
Step #0: ======== Module name './infra/logger/LoggerModule.js' was successfully resolved to '/app/infra/logger/LoggerModule.ts'. ========
```
`/app/AppModule.ts`でimportされている`./infra/logger/LoggerModule.js`について、`Node16`というモジュール解決方法に従って`/app/infra/logger/LoggerModule.ts`というパスを探しに行っていることが分かります。

## 疑うポイント
下記以外にも疑うポイントたくさんあると思います！切り分けていきましょう！

### コンパイラ設定は合っているが対象ファイルがない
- `npm install` / `yarn install`忘れていませんか？
- ファイル名の大文字小文字だけを変えた場合、その改名がgit commitできていますか？

### 対象ファイルはあるがコンパイラ設定が誤っている
- [baseUrl](https://www.typescriptlang.org/tsconfig#baseUrl)は正しく設定されていますか？
- [moduleResolution](https://www.typescriptlang.org/tsconfig#moduleResolution)は正しく設定されていますか？
- [moduleDetection](https://www.typescriptlang.org/tsconfig#moduleDetection)は正しく設定されていますか？

ちなみに僕は「ファイル名の大文字小文字だけを変えた」時に改名がgit commitできておらず、ローカルではビルド成功するのにCDでだけ落ちており、数時間詰まりました。ファ●ク
slackbotを作り、Pythonで通知するぜ ファイル添付も

# 下準備


ファイルの添付もするので、 `files:write`スコープもオンにしとおく

Scopes

```
chat:write
chat:write.customize
files:write
```

参考
https://www.whizz-tech.co.jp/5857/


# エラーがでるねんけど
このアプリはこのワークスペースにボットをインストールする許可を要求していますが、現在、ボットを使用するための設定がされていません。この問題を解決するため

https://the-simple.jp/slack-nobotuser


# うまくチャンネルが登録できない場合

windows slack アプリの左上

その他 > App

先程作ったbotをクリック

チャンネルをクリック。


上の人アイコン

インテグレーション、アプリを追加する。

でアプリを追加して

テストページよりテストできる

https://api.slack.com/methods/chat.postMessage/test

`OK`

# 早速 python sdk 入れようじゃないの


インスコ❤

```
pip install slack-sdk
```


tokenはあなたのトークンを指定。
pythonhogeは、あなたのチャンネル名。

```test.py

from slack_sdk import WebClient
client = WebClient(token='your-3333-777-xxx3333333999')

try:
    response = client.chat_postMessage(channel='#pythonhoge', text="Hello world!")
    assert response["message"]["text"] == "Hello world!"
except SlackApiError as e:
    # You will get a SlackApiError if "ok" is False
    assert e.response["ok"] is False
    assert e.response["error"]  # str like 'invalid_auth', 'channel_not_found'
    print(f"Got an error: {e.response['error']}")


```

これで通知されます。

# ファイルもアップロードしたいねんって

・token
・画像
・アップするチャンネル名
・アップした時のテキスト

をそれぞれ指定。

```test.py
from slack_sdk import WebClient

def file_upload():
    client = WebClient(token='your-token')
    filepath= r"your.png" #相対パス
    response = client.chat_postMessage(channel='#your', text="画像をアップしますよ")
    response = client.files_upload(channels='#your', file=filepath)
    return print(response)

file_upload()

```
【Java】+=, concat, StringBuilderの処理速度比較

# 経緯

Java本格入門の「文字列操作を極める」の章で紹介されていた、実行速度の違いをただ実行するだけ。

https://gihyo.jp/book/2017/978-4-7741-8909-3

# StringBuilder

https://qiita.com/atsuk0r0/items/1208b5fead98676bc3c7

# 方法

`System.currentTimeMillis()`メソッドを使って差分を取る

```java
long start = System.currentTimeMillis();
...
...
long end = System.currentTimeMillis();
System.out.println("実行時間[ms]: " + (end - start));
```

## +=

```java:Main.java
public class Main {
    public final static int SIZE;

    public static void main(String[] args) {
        String s = "";

        long start = System.currentTimeMillis();
        for (int i = 0; i < SIZE; i++) {
            s += "a";
        }
        long end = System.currentTimeMillis();
        System.out.println("実行時間[ms]: " + (end - start));
    }
}
```

## concat

```java:Main.java
public class Main {
    public final static int SIZE;

    public static void main(String[] args) {
        String s = "";

        long start = System.currentTimeMillis();
        for (int i = 0; i < SIZE; i++) {
            s.concat("a");
        }
        long end = System.currentTimeMillis();
        System.out.println("実行時間[ms]: " + (end - start));
    }
}
```


## StringBuider

```java:Main.java
public class Main {
    public final static int SIZE;

    public static void main(String[] args) {
        String s = "";
        StringBuilder builder = new StringBuilder();

        long start = System.currentTimeMillis();
        for (int i = 0; i < SIZE; i++) {
            builder.append("a");
        }
        long end = System.currentTimeMillis();
        System.out.println("実行時間[ms]: " + (end - start));
    }
}
```


# SIZE = 10_000


```zsh:+=
実行時間[ms]: 61
```

```zsh:concat
実行時間[ms]: 2
```

```zsh:StringBuilder
実行時間[ms]: 2
```

# SIZE = 100_000


```zsh:+=
実行時間[ms]: 1524
```

```zsh:concat
実行時間[ms]: 9
```

```zsh:StringBuilder
実行時間[ms]: 12
```

# SIZE = 1_000_000


```zsh:+=
実行時間[ms]: 69499
```

```zsh:concat
実行時間[ms]: 36
```

```zsh:StringBuilder
実行時間[ms]: 28
```

# SIZE = 10_000_000

> `+=`はもうやめます


```zsh:concat
実行時間[ms]: 170
```

```zsh:StringBuilder
実行時間[ms]: 86
```

# SIZE = 100_000_000

```zsh:concat
実行時間[ms]: 867
```

```zsh:StringBuilder
実行時間[ms]: 550
```

# SIZE = 1_000_000_000

```zsh:concat
実行時間[ms]: 5903
```

```zsh:StringBuilder
実行時間[ms]: 5352
```

# StringBuffer

`StringBuilder`とメソッドは全て同じで、スレッドセーフ（マルチスレッドでも問題なく動作する）があるかどうか。


# 結論

* 結局バッファリングする`StringBuilder`が一番早い
* ちょっとした文字列連結は`+=`でいい。


> Every string builder has a capacity. As long as the length of the character sequence contained in the string builder does not exceed the capacity, **it is not necessary to allocate a new internal buffer.** If the internal buffer overflows, it is automatically made larger.

https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/StringBuilder.html
Flutterのアニメーションで四角を動かしてみる

# はじめに
　前回、Flutterのアニメーションについて学習しました。

https://qiita.com/y5347M/items/c115932d3bbf15df0f1d


応用として四角がかわいく（？）動くようにしました。
変化する値としては以下の4つです。
- サイズ
- 透明度
- 色
- 傾き

![try2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2433961/bc571d31-5f8b-f29d-2857-f4b7f08b258a.gif)

# コード
注意点として、ColorだけはTweenではなくColorTweenクラスをつかってTweenオブジェクトを生成するところです。

```dart:main.dart
import 'package:flutter/material.dart';
import 'dart:math';

void main() => runApp(const LogoApp());

class AnimatedLogo extends AnimatedWidget {
  const AnimatedLogo({super.key, required Animation<double> animation})
      : super(listenable: animation);

  // Make the Tweens static because they don't change.
  static final _opacityTween = Tween<double>(begin: 0.1, end: 1);
  static final _sizeTween = Tween<double>(begin: 0, end: 300);
  static final _transformTween = Tween<double>(begin: 0, end: 90);
  static final _colorTween = ColorTween(begin: Colors.grey, end: Colors.pink);

  @override
  Widget build(BuildContext context) {
    final animation = listenable as Animation<double>;
    return Center(
      child: Opacity(
        opacity: _opacityTween.evaluate(animation),
        child: Container(
          transform: Matrix4.rotationZ(_transformTween.evaluate(animation) * pi / 180),
          margin: const EdgeInsets.symmetric(vertical: 10),
          height: _sizeTween.evaluate(animation),
          width: _sizeTween.evaluate(animation),
          decoration: BoxDecoration(
            color: _colorTween.evaluate(animation),
            borderRadius: BorderRadius.circular(16.0),
          ),
        ),
      ),
    );
  }
}

class LogoApp extends StatefulWidget {
  const LogoApp({super.key});

  @override
  State<LogoApp> createState() => _LogoAppState();
}

class _LogoAppState extends State<LogoApp> with SingleTickerProviderStateMixin {
  late Animation<double> animation;
  late AnimationController controller;

  @override
  void initState() {
    super.initState();
    controller =
        AnimationController(duration: const Duration(seconds: 2), vsync: this);
    animation = CurvedAnimation(parent: controller, curve: Curves.bounceIn)
      ..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          controller.reverse();
        } else if (status == AnimationStatus.dismissed) {
          controller.forward();
        }
      });
    controller.forward();
  }

  @override
  Widget build(BuildContext context) => AnimatedLogo(animation: animation);

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }
}
```
Django 仮想環境の構築

- ファイル内に仮想環境”myvenv”を作成
    
    ※なぜか一回”myenv”で作成したので作りなおした
    

```bash
python3 -m venv myvenv
```

- 仮想環境に入るコマンド

ポートフォリオサイトを新しくするのに、どうせならdjangoの勉強もかねて実装してみようかの試み

```bash
.\myenv\Scripts\activate
```

↑エラーが出た。セキュリティ上の問題らしい

＜解決法①＞
以下のコードを実行すれば設定が変わる
```
Set-ExecutionPolicy RemoteSigned
```
＜解決法②＞
vscodeのデフォルト設定で制限がかかっているので、setting.jsonに以下の記述を追加。すでに記述がある場合は”,”を追加することを忘れずに

参照（[https://qiita.com/startours777/items/2d35f2c6de12071a4c77](https://qiita.com/startours777/items/2d35f2c6de12071a4c77)）

```bash
"terminal.integrated.env.windows":{
"PSExecutinpolicyPreference":"RemoteSigned"
}
```

無事入れました

後は→[https://zenn.dev/hathle/books/django-render-book/viewer/02_project](https://zenn.dev/hathle/books/django-render-book/viewer/02_project)

の通り
ネットマーケティング検定

2022年7月31日にネットマーケティング検定を受験しました。
合格(2022/8/23)したので記事を書いておきます。
次受ける方の参考になれば幸いです。

## 受験理由
■１ネットマーケティングの知識を仕事で使う可能性があるため

## 感想
■１ 学習教材1はゆっくりでも7日ほどで読み終わりますので、その後は学習教材2で問題を解き続ければ受かると思います。
	
## 学習教材
■１ ネットマーケティング検定公式テキスト インターネットマーケティング 基礎編 第3版（藤井裕之  (著), サーティファイWeb利用・技術認定委員会 (監修), 2019, インプレス）
■２ ネットマーケティング検定過去問題集 第4版（サーティファイWeb利用技術認定委員会, 2022, ウイネット）

## 学習方法
■１ 公式テキスト（学習教材１）実施
・・・１週間でテキストを一通り読む
■２ 問題集（学習教材２）実施
・・・問題集を３回ほど実施

## 反省点
■１ 特になし。

## 試験前にやっておいてよかったこと等
■１ 問題集で間違えた箇所をネットで調べてスクショして、試験前に何度も復習した点。
コマンドラインからずんだもん（VOICEVOX）に音声ファイルを作らせる！たった７行で

Colaboratory を使って ChatGPT -> VOICEVOX をものすごいシンプルなコードで繋いでいる方がいました！すごい！コードみじかっ！

https://www.youtube.com/watch?v=pD6ARHN_Jz4

とくにずんだもん（VOICEVOX）の短さに感動したので転載したいと思います。

まずはVOICEVOXのインストールに５行。（WSL2-Ubuntu22.04でやってます）

```
curl -sSfL https://github.com/VOICEVOX/voicevox_core/releases/latest/download/download.sh | bash -s
cd voicevox_core/
wget https://github.com/VOICEVOX/voicevox_core/releases/download/0.14.1/voicevox_core-0.14.1+cpu-cp38-abi3-linux_x86_64.whl
pip install voicevox_core-0.14.1+cpu-cp38-abi3-linux_x86_64.whl
wget https://raw.githubusercontent.com/VOICEVOX/voicevox_core/main/example/python/run.py
```

つぎにテキストデータから音声ファイル（wav）の生成に２行

```
sed -i "/SPEAKER_ID =/c SPEAKER_ID = 1" run.py
python ./run.py ./open_jtalk_dic_utf_8-1.11 "ここにしゃべらせたい内容がはいるよ" ./data.wav
```

こんだけ。短いっすね。無料っすね。すごいっすね。

長文を生成した音声ファイルとコマンドも貼っておきます。
```SPEAKER_ID = 1``` はゆっくりな声のずんだもんだけど、これを3にして少し早口のずんだもんにして生成しました。

```
sed -i "/SPEAKER_ID =/c SPEAKER_ID = 3" run.py
python ./run.py ./open_jtalk_dic_utf_8-1.11 "新型コロナの感染症法上の位置づけが「5類」に移行したあとの医療提供体制について、政府は、幅広い医療機関で患者を受け入れ
てもらうなどとする方針を決めました。これまでコロナ患者を診療していない医療機関の協力を得るため、支援制度などを丁寧に説明して理解を求めることにしています。

政府は10日、感染症法上の位置づけが5月8日に「5類」に移行したあとの医療費負担などの具体的な方針を決め、現在は窓口負担が無料となっている医療費のうち、検査や陽性が判明したあとの外来診療の費用は自己負担が生じることになりました。

ただ、受診控えを防ぐため高額な治療薬は引き続き無料とします。

一方、医療提供体制は、幅広い医療機関で受診できるよう、現在よりも2万以上多い、最大でおよそ6万4000の医療機関で受け入れる体制を目指すとしています。

このためには、これまでコロナ患者を診療していない医療機関の協力も必要なことから、政府は、感染対策に必要な設備の導入などを支援するとともに、医療機関の間で入院患者の
受け入れを調整した場合に支払う診療報酬を新設するなどとしています。

政府は、こうした支援制度について、来週から都道府県などを対象にした説明会を開くなどして丁寧に説明し、理解を求めたいとしています" ./data.wav
```

元にしたテキストはこちらから参照しまいた。

https://www3.nhk.or.jp/news/html/20230311/k10014004831000.html

生成した音声はこんなです。とくに違和感なく内容が頭に入ってきます。

https://drive.google.com/file/d/1qVZeBoYQQlck3q10DfevY9mnZyO6WJMK/view?usp=sharing
Python基本文法4(ライブラリ、モジュール 編)

# 概要
[MySQL勉強まとめ3](https://qiita.com/iwhg0211/items/b162d6d05a7e8df98133)の続きです。
個人的な勉強のまとめなので、もし修正があればご指摘いただけるとありがたいです。

# 目次
- モジュールの設定
- ライブラリの設定

# モジュール

モジュールを使おう
>モジュールとは、Pythonのコードが書かれたファイルのことです。
別ファイルをモジュールとして読み込むことでそこに書かれたコードを利用することができます。
今までコードを記述していたscript.pyもモジュールです。ここでは関数の定義部分をscript.pyからutils.pyに移します。
（progateの説明より）

>import
importを使うことでモジュールを読み込むことができます。
モジュールを読み込んで使いたいファイルに、「import モジュール名」と書くことで読み込むことができます。
モジュール名はファイル名から拡張子（.py）を取り除いたものとなります。
（progateの説明より）

```Python:script.py
import utils

# utils.py をモジュールとして読み込んでください
print('じゃんけんをはじめます')
player_name = input('名前を入力してください：')
print('何を出しますか？（0: グー, 1: チョキ, 2: パー）')
player_hand = int(input('数字で入力してください：'))

# utils モジュール内の関数 validate を呼び出してください
if utils.validate(player_hand):
    computer_hand = 1

    if player_name == '':
        # utils モジュール内の関数 print_hand を呼び出してください
        utils.print_hand(player_hand)
    else:
        # utils モジュール内の関数 print_hand を呼び出してください
        utils.print_hand(player_hand, player_name)

    # utils モジュール内の関数 print_hand を呼び出してください
    utils.print_hand(computer_hand, 'コンピュータ')
    
    # utils モジュール内の関数 judge を呼び出してください
    result = utils.judge(player_hand, computer_hand)
    print('結果は' + result + 'でした')
else:
    print('正しい数値を入力してください')
```
```Python:utils.py
# 3つの関数のコードを貼り付けてください
def validate(hand):
    if hand < 0 or hand > 2:
        return False
    return True

def print_hand(hand, name='ゲスト'):
    hands = ['グー', 'チョキ', 'パー']
    print(name + 'は' + hands[hand] + 'を出しました')

def judge(player, computer):
    if player == computer:
        return '引き分け'
    elif player == 0 and computer == 1:
        return '勝ち'
    elif player == 1 and computer == 2:
        return '勝ち'
    elif player == 2 and computer == 0:
        return '勝ち'
    else:
        return '負け'
```

このようにモジュールは別ファイルにコードを置いて、コードをシンプルにするための方法です。
呼び出す時はモジュール名.関数名
で記述する。


# ライブラリ
>先程は自分でモジュールを作りましたが、Pythonには便利なモジュールがいくつか用意されています。これらのあらかじめ用意されているモジュールは標準ライブラリと呼ばれ、importを用いて読み込むことで便利な関数を利用できるようになります。
（progateの説明より）

ライブラリについては上記の通りです。

```Python:script.py
import utils
import random
# random モジュールを読み込んでください

print('じゃんけんをはじめます')
player_name = input('名前を入力してください：')
print('何を出しますか？（0: グー, 1: チョキ, 2: パー）')
player_hand = int(input('数字で入力してください：'))

if utils.validate(player_hand):
    # randint を用いて 0 から 2 までの数値を取得し、変数 computer_hand に代入してください
    computer_hand = random.randint(0,2)
    
    if player_name == '':
        utils.print_hand(player_hand)
    else:
        utils.print_hand(player_hand, player_name)

    utils.print_hand(computer_hand, 'コンピューター')
    
    result = utils.judge(player_hand, computer_hand)
    print('結果は' + result + 'でした')
else:
    print('正しい数値を入力してください')
```
random.randint(0,2)で0〜2の数値をランダムで取得する。
データベースを基本からまとめてみた【DB接続の仕組みとJDBCの基本】

## データベース接続の仕組み
①データベース(DB)：データを整理・蓄積したもの
②JDBC：JavaプログラムとDBを繋ぐクラス・インターフェイスなどの集まり
- JDBC API : JDKに含まれる
- JDBCドライバ : DB開発元が公開
③SQL: DBを操作する言語　※ SQL(Stuructred Query Language)
⇨ データベースを操作するために使われる構造化問い合わせ言語
##### ※ JDBCがDBの違いを吸収するため、DBが異なってもJavaのプログラムはほぼ変わらない

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/939638/27f26229-d9eb-e399-28f7-04dcebfdb6f6.png)

## 参考サイト
[【JavaDB1】DB接続の仕組みやJDBCとは何かを基本から理解しよう！](https://www.youtube.com/watch?v=fkR1htEk6FU)
[【IT初心者向け】JDBCとは？そのメリットやデータベース操作方法を解説！
](https://ryonotes.com/what-is-jdbc/)
社内Ruby3新機能勉強会資料 ~RBSとは~

## この記事は何
Qiita株式会社では技術的な勉強会を定期的に開催しています。
この記事はRuby3から導入されたRBSについて発表をしたときの社内の資料をQiita用に修正したものです。

---

## RBSとは
RBSというと大体二つの意味で話す。

- ruby3.0から導入されたRubyの型定義を記述するための言語。(RBS=Ruby Signeture) →この記事では便宜上`RBS`と書く
- RBSファイルを扱うためのgem (https://github.com/ruby/rbs) →この記事では便宜上`rbs`と書く
    - 標準ライブラリ/組み込みクラスの型ドキュメント
        - 特定の型に対しての親情報やメソッドの型情報を逆引きできる
    - RBSの解析

https://github.com/ruby/rbs より

>RBS is a language to describe the structure of Ruby programs. You can write down the definition of a class or module: methods defined in the class, instance variables and their types, and inheritance/mix-in relations. It also allows declaring constants and global variables.

---

RBS自体は言語の定義でしかないので、これ自体に意味はない。
実際の業務では以下の二つのライブラリを用いることで、Rubyのプログラミングに型の恩恵を受けられるようになる

- TypeProf
    - 型注釈のない Ruby コードを解析する静的型解析ライブラリ
- Steep
    - Ruby の静的型検査ライブラリ
    - LSPも含む

RBSではなく、RBIというStripeが独自に開発した型定義言語もある（Sorbetで利用）

https://github.com/sorbet/sorbet

---

ちなみにRBSとSorbetのプロジェクトは密接にコミュニケーションをとっているらしく、相互変換を行えるようにしていく模様

https://developer.squareup.com/blog/the-state-of-ruby-3-typing/#sorbet-and-rbs

https://sorbet.org/blog/2020/07/30/ruby-3-rbs-sorbet

https://github.com/sorbet/sorbet/pull/2828

ここを読むと`Tapioca`というプロジェクトでRBS→RBIを実現できそう。

https://github.com/Shopify/tapioca

元々はRubyの標準もRBI想定していた模様。（SorbetのRBIとは別のものを指している可能性もあり)

https://logmi.jp/tech/articles/321280

---

## 背景とコンセプト
- Ruby3の3本の柱
    - パフォーマンスの改善
    - Concurrency
    - 静的解析→この中で生まれたのがRBS


---

- 2010年代に入ってから静的型付け言語の人気が高まっており、動的型付け言語でも型注釈を提供する流れが出てきた
    - 2010年前後に現れた言語: Go, TypeScript, Swift, Kotlin, etc...
    - システムの大規模化の中で、静的型付けの強みである「保守性」「パフォーマンス」が注目されてきた
        - LSPやIDEなどの開発環境の進化
        - トラフィックの大規模化
        - https://www.oracle.com/webfolder/technetwork/jp/javamagazine/Java-JF18-editorial.pdf

---

- 動的型付け言語の静的解析は「保守性」の部分を担保するためのアプローチ
    - Python: https://docs.python.org/ja/3/library/typing.html
    - PHP: https://www.php.net/manual/ja/language.types.declarations.php
- Rubyのアプローチは他の動的言語の型注釈とは違い、「型の情報は既存のRubyコードとは完全に分離する」というアプローチをとっている
    - 理由
        - Rubyは思想として「既存のRubyの書きごこち」を重要視している
            - やりたいことをシンプルに記述できる
            - 「書いていて楽しい言語」
        - 型に対しても、できるだけ書き手が考えなくても良い状態を目指している
            - 既存のコードからの型推論（TypeProf）
            - →アウトプットとして別のファイルに書き出す
    - Ref
        - https://logmi.jp/tech/articles/321280
        - https://www.youtube.com/watch?v=2g9R7PUCEXo&t=2022s

---

## RBSの現状
GitHubでの`*.rbs`の検索結果→19,000ファイルほど

https://github.com/search?p=1&q=extension%3Arbs&type=Code

`rbs_collection`を使うことで、gemにrbsファイルがあればその情報を取り込むことができる。

https://github.com/ruby/rbs/blob/master/docs/collection.md

また、`gems_rbs_collection`にgemのRBSが定義されている→npmの`@types`と同じようなイメージ

https://github.com/ruby/gem_rbs_collection/tree/main/gems
Google アナリティクス個人認定資格

2022年9月9日にGoogle アナリティクス個人認定資格（GAIQ）を受験しました。
合格(2022/9/9)したので記事を書いておきます。
次受ける方の参考になれば幸いです。

## 受験理由
■１ マーケティングの勉強になると思ったから

## 感想
■１ 学習教材を全て理解すれば、合格すると思います。
■２ 有効期限は１年ですので、継続的に使用する人は来年も受験が必要のようですが、仕組みだけを何となく知っておきたい人は特に必要ないと思います。
	
## 学習教材
■１いちばんやさしい Googleアナリティクス 入門教室（小川・工藤, 2019, ソーテック社）
■２ <a href="https://support.google.com/analytics/answer/3424288?hl=ja">Google アナリティクス初級者向けコース</a>
■３ <a href="https://support.google.com/analytics/answer/3424288?hl=ja">Google アナリティクス上級者向けコース</a>

## 学習方法
■１ 学習教材１実施
・・・2日で読み終える。学習教材２～３をやりながら、こちらの教材で重要な点にマーカーを引いたり、付属の問題で100点をとれるまで繰り返し解く。
■２ 学習教材２実施
・・・2日で一通り終える。
■３ 学習教材３実施
・・・2日で一通り終える。

## 反省点
■１ 特になし。

## 試験前にやっておいてよかったこと等
■１ 『いちばんやさしい Googleアナリティクス 入門教室』の問題を100％解けるようにするため、試験前に間違った箇所を何度も復習した点。
Yahoo!広告 ディスプレイ広告 アドバンスト

2022年9月2日にYahoo!広告 認定資格（Yahoo!広告 ディスプレイ広告 アドバンスト認定試験）を受験しました。
合格(2022/9/2)したので記事を書いておきます。
次受ける方の参考になれば幸いです。

## 受験理由
■１ 広告やマーケティングの勉強になるかと思ったから

## 感想
■１ Yahoo!広告 キャンパスに登録すると学習コンテンツが見れますので、それを1-2日で覚えれば受かると思います。
■２ 有効期限は１年ですので、継続的に使用する人は来年も受験が必要のようですが、仕組みだけを何となく知っておきたい人は特に必要ないと思います。
■３ 学習方法や期間はベーシックと同じです。
	
## 学習教材
■１<a href="https://marketing.yahoo.co.jp/service/yahooads/yahooads_campus/">Yahoo!広告 キャンパスの学習コンテンツ<a/>

## 学習方法
■１ 公式テキスト（学習教材１）実施
・・・1-2日で1-2周する。

## 反省点
■１ 特になし。

## 試験前にやっておいてよかったこと等
■１ 見慣れない用語などが多かったので体に慣らすため、ノートに書いたり、声に出して読んでみたりした点。
Yahoo!広告 ベーシック

2022年9月2日にYahoo!広告 認定資格（Yahoo!広告 ベーシック認定試験）を受験しました。
合格(2022/9/2)したので記事を書いておきます。
次受ける方の参考になれば幸いです。

## 受験理由
■１ 広告やマーケティングの勉強になるかと思ったから

## 感想
■１ Yahoo!広告 キャンパスに登録すると学習コンテンツが見れますので、それを1-2日で覚えれば受かると思います。
■２ 有効期限は１年ですので、継続的に使用する人は来年も受験が必要のようですが、仕組みだけを何となく知っておきたい人は特に必要ないと思います。
	
## 学習教材
■１<a href="https://marketing.yahoo.co.jp/service/yahooads/yahooads_campus/">Yahoo!広告 キャンパスの学習コンテンツ<a/>

## 学習方法
■１ 公式テキスト（学習教材１）実施
・・・1-2日で1-2周する。

## 反省点
■１ 特になし。

## 試験前にやっておいてよかったこと等
■１ 見慣れない用語などが多かったので体に慣らすため、ノートに書いたり、声に出して読んでみたりした点。
「CORBAってなんですか？」※超ざっくり自己理解まとめ

## 経緯と対象読者
現在のお仕事でC++のプログラムをいじっているのですが、<br>たびたび出てくる「CORBA」を理解できずにいました。
ググってみたところ、「Common Object Request Broker Architecture」の略であることはわかったのですが、中身はさっぱり理解できず悶々と日々を過ごしていました。。。
ついに先輩に聞いてみたところ、「分散処理基盤」だと教えてもらい、どうやら古い技術であることが判明。
これに変わる新しい技術があるんじゃないか？<br>と疑問に思い調査し、自分なりにわかったことをまとめます。
対象読者：CORBAを理解できなかった頃の自分(業界歴1年程度のなんちゃってITエンジニア)

# 結論
<h4>閉ざされた組織内では理にかなっている仕組みのようだ。

CORBAは分散処理基盤だと教えてくれた先輩の言葉を自分なりに記すと、<br>「社内にいくつかあるサーバから欲しい処理を呼び出してくれるやつ」らしい。
ここでのメリットは、
<h6>①呼び出すのに必要な処理を書かなくて済む<br>②言語問わず欲しい処理を呼び出せる<h6>

ということらしい。

そして、メリット②を実現するのに必要なのが「IDL」というものみたいだ。<br>IDLがこっち側の言語ソース(スタブ)とあっち側の言語ソース(スケルトン)を作ってくれるお陰で実現するらしい。

また、調べているうちにCORBAのような「散らばった処理を呼び出してくれるやつ(RPC)」は他にも「DCOM」というものがあるそうだが、CORBAとDCOMはプロトコルが異なるため通信できないらしい。

そこで、異なったオブジェクト間を通信するために登場したのが「SOAP」。
SOAPはIDLが担っていた役をXMLに変え、HTTPに乗せて通信する。
現在のWebサービスでよく使われているRESTの前身のようなものらしい。

## おわりに
当たり前に使ってる仕組みの裏では色んな仕組みがあって、<br>その変遷の歴史を知れました。<br>頭の中に散らばっていた知識がつながって嬉しくなりました。
「仮説を立て」て答えを探すと宝探しみたいで面白いことがわかってよかったです。

あざした。
enebularでalexaスキル その12

# 概要
enebularで、alexaスキルのwebhookを返してみた。
練習問題やってみた。

# 練習問題
chatGPTを組み込め

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/b815a56d-19c8-b4c5-3796-46f7b27bf17c.png)

# 方針
- きっかけ
「アレクサ　チャットボットを開いて」と言うと
「チャットボットです。」と答える。
- 起動
「テスト」と言うと
「わかりました。」と答える。
- 実行
「牛丼は好きですか」と問うと
答える。

# 嵌まった点

payload.choices[0].message.content
は、だめ。
payload.choices.0.message.content
が、正義。

# フロー

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/a01b8afd-d279-c646-c9a1-263f53c68894.png)

以上。
歌ってみた動画のタイトルから楽曲名を取得する  (huggingface AutoTrain編)

# まとめ
* ユースケースがハマるならautoTrainはかなり便利
* 文章要約タスクとして、タイトル取得問題が解ける
* 正解率 93.81% (515/549)

# やりたいこと
歌ってみた動画のタイトルと説明文からタイトルだけを抜き出したい
例: https://www.youtube.com/watch?v=X4IvjtfivNk
入力: ドクター＝ファンクビート／nyanyannya feat.レオス・ヴィンセント\nvo.レオス・ヴィンセント...(以下略 
出力: ドクター＝ファンクビート

# 今までの流れ
1. 正規表現で頑張る編: https://qiita.com/miyatsuki/items/cb0ce6ae0e48cf42b1c8
2. OpenAI(GPT-3)編: https://qiita.com/miyatsuki/items/6429340dae118392f117

# やったこと
HuggingFace autoTrainのsummarization(文章要約)タスクとして、楽曲名取得タスクを解く

### HuggingFace autoTrain
HuggingFaceが提供しているAutoMLサービス
自然言語処理、画像認識、テーブルデータ処理に対応

学習データと元となるモデルを指定することで学習データに合わせたfine-tuningを実施してくれる
(デフォルトだと元のモデルも自動で選んでくれる)

https://huggingface.co/autotrain

具体的な使い方はこちらの記事などを参考にしてください
https://qiita.com/relu/items/129de82967d99ee4c398

### 学習データの準備

以下のようなjsonlファイルを用意する
正解データ(今回はsong_title)と入力データ(今回はtext)のカラムを用意してデータを入れておく
カラム名は任意に設定可能で、学習に不要なカラムが入っていても良い

```json
{"video_id": "kZ2dYR9ustU", "song_title": "トンデモワンダーズ", "text": "『トンデモワンダーズ』ハモリに合わせて歌って？ #shorts..."}
{"video_id": "yU5_w__2FBo", "song_title": "secret base〜君がくれたもの〜", "text": "【ロボ子さん】secret base〜君がくれたもの〜【VTuberコンピレーションアルバム「IMAGINATION vol.1」】\nみんなが幸せな気持ちになってくれるように..."}
{"video_id": "6liKX4gI-68", "song_title": "ヴァンパイア", "text": "【ハロウィン2021】ヴァンパイア/DECO*27 踊ってみた♦歌ってみた【相羽ういは/にじさんじ】\n吸っち..."}
```

なお、trainとvalidationのsplitは自動で実行してくれるので、分けて準備する必要はない
(個別に指定することも可能)

### 学習後モデルの利用

画像のように、普通のhuggingface モデルとして利用できる
![スクリーンショット 2023-03-11 15.02.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176335/292de082-24e3-29cf-4a1e-67f07e6e78b7.png)

# 精度

正解率 93.81% (515/549)

### 推定に成功した例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176335/364d3cec-525f-49ec-52fb-579e148bd29d.png)

### 推定に失敗した例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176335/762ff2ae-5ca9-51df-d862-3b33db9b8788.png)

# コスト

### 学習
* 通常アカウント: 3000行まで無料
* Proアカウント: 10000行まで無料

### 推定
* 通常のhuggingfaceモデルの利用料金に準拠(なので、基本的に無料)
  * inferenceAPIも利用可能

# 所感
* コスト・精度ともに、一旦満足できる水準
* ただ、ハロ/ハワユは相変わらず認識できず
* 既存のtokenizerが利用されるので、全角->半角変換が勝手に行われる問題がある
* 次は他の情報とまとめて取得できないかを検討していきたい
    * 例: 歌い手の名前抽出、カバー元のアーティスト名の抽出 など
Glacierに保存したオブジェクトをまとめて復元するシェルスクリプト

# はじめに
Amazon S3にはストレージクラスと呼ばれる、データの保管料金を節約する機能があります。
主に利用頻度の少ないデータを保管する際に使う機能となり、データの取り出しかかる時間や費用の増加、可用性が低下などを許容する代わりに、データ保管にかかる料金を節約できます。
つまり、S3に保存されているオブジェクトの使用頻度や可用性に合わせてストレージクラスを変更させることで日々のS3の利用料金を抑えることが可能となります。
そして、**ストレージクラスの一つがGlacier**となります。

このGlacier、保存されているオブジェクトは一度復元というステップを踏まないとデータを取り出すことができません。
この特徴のため、今回S3のオブジェクトを別アカウントのS3に移動させようとして`s3 sync`コマンドを実行したところ以下のようなエラーが発生しました。

:::note alert
Object is of storage class GLACIER. Unable to perform copy operations on GLACIER objects. You must restore the object to be able to perform the operation. See aws s3 copy help for additional parameter options to ignore or force these transfers.
:::

そのため、オブジェクトを復元してからsyncコマンドを実行すればいいだけの話なのですが、復元はオブジェクトごとにしか実行することができず、大量のオブジェクトがあるバケットに対して復元を実行しようとする場合、数千/数万回マウスをカチカチしなければならなくなります。

そこで今回はAWS CLIをインストールしたMacOSで実行/放置しておくだけで、勝手にGlacierに保管されているオブジェクトを復元してくれるシェルスクリプトを作成してみました。

# シェルスクリプトファイルの中身

restore_glacier_objects.sh
```
#!/bin/bash
​
bucket=$1
prefix=$2
​
aws s3api list-objects --bucket $bucket --prefix "$prefix" --query "Contents[?StorageClass=='GLACIER'].[Key]" --output text | while read object; do
  echo "Restoring object $object from $bucket"
  aws s3api restore-object --bucket $bucket --key "$object" --restore-request '{"Days":3,"GlacierJobParameters":{"Tier":"Bulk"}}'
done
```

**実行時のコマンド**
シェルスクリプトを保存したディレクトリへ移動し、以下を実行
`sh restore_glacier_objects.sh <バケット名> <プレフィックス>`

**例**
バケット名：s3-test
プレフィックス：s3://s3-test/page1/
とした場合

`sh restore_glacier_objects.sh s3-test page1/`

## 仕様の解説
- 変数としてバケット名とプレフィックス（パスみたいなもの）を与える
- AWS CLIの`s3api list-objects`を使用してストレージクラスがGlacierのオブジェクトを抽出
- 抽出したオブジェクトなくなるまで、1つずつループで復元
- 復元されている期間は3日
- 大容量取り出し（Bulk）を使用することで取り出しにかかる費用を抑える

# 注意点
**AWS CloudShellでの大量オブジェクトの復元は非推奨**です。

というのもAWS CloudShellには以下のような制約があります。

> ・非アクティブセッション:AWS CloudShellは対話型のシェル環境であり、20～30 分にわたってキーボードとポインタを使った操作がない場合、シェルセッションは終了します。実行中のプロセスは、操作数としてカウントされません。
> ・実行時間が長いセッション:約 12 時間連続して実行されているシェルセッションは、ユーザーがその期間に定期的に操作している場合でも、自動的に終了します。

https://docs.aws.amazon.com/ja_jp/cloudshell/latest/userguide/limits.html

また、コンピューティング能力も高くないため、大量のオブジェクトを復元しようとすると時間がかかってしまいます。
そのため、プレフィックスをうまく切ってシェルスクリプトを実行したり、定期的にAWS CloudShellの画面で何かしらのキーを叩く（Automatorを使ってもいい？）必要があり、シェルスクリプトを作ったとしても結構大変なので、**AWS CloudShellではなく、ローカルにAWS CLIをインストールしてシェルスクリプトをを実行する方がいいかと思います。**
小道具：短い HTML 構文のテスト

"&amp;amp;" などの構文を直接入力して試すための小道具です。

処理は、入力タグ(textarea)の value を出力タグ(td)の innerHTML に代入するだけです。

<p class="codepen" data-height="240" data-default-tab="result" data-slug-hash="wvEppLP" data-user="ikiuo" style="height: 240px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/ikiuo/pen/wvEppLP">
  HTML構文のテスト</a> by Ikiuo (<a href="https://codepen.io/ikiuo">@ikiuo</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>


```html:test.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>innerHTML テスト</title>
  </head>
  <body>
    <table border="1">
      <tr><th>入<br/>力</th><td>
	  <textarea cols="80" rows="6" oninput="out.innerHTML=this.value"></textarea>
      </td></tr>
      <tr><th>出<br/>力</th><td id="out"></td></tr>
    </table>
  </body>
</html>
```

JavaScript は oninput 内の <code>out.innerHTML=this.value</code> のみ
dockerで構築したrailsアプリにwebpackerをインストールする方法

インストールしたいディレクトリに移動したらターミナルに以下のコマンドを入力してください。
~~~
docker-compose run web rails webpacker:install
~~~
Webpacker successfully installed 🎉 🍰
とlogに表示されていれば完了です。
LPIC-1 101

2022年8月28日にLPIC-1 Exam 101を受験しました。
合格(2022/8/28)したので記事を書いておきます。
次受ける方の参考になれば幸いです。

## 受験理由
■１ Linuxを仕事で頻繁に使う可能性があるため基礎知識を身につけておきたいから

## 感想
■１ 『Linux教科書 LPICレベル1 スピードマスター問題集 Version5.0対応』を一週間で一周した後、間違った問題を3-4周ほど一週間で実施して9割ほど取れるようになれば合格すると思います。
■２ Linuxを仕事で使用している人からするとそこまで難しくないです。
	
## 学習教材
■１ Linux教科書 LPICレベル1 スピードマスター問題集 Version5.0対応（山本・大竹, 2019, 翔泳社）

## 学習方法
■１ 公式テキスト（学習教材１）実施
・・・最初から問題集を解く。問題集は9割以上取れるようになるまで繰り返す。

## 反省点
■１ LPIC-1 Exam 102まで手が回らなかった点。

## 試験前にやっておいてよかったこと等
■１ よく間違える問題にチェックを付けて試験直前に何度も見直したこと。
Flutter リリース済みのアプリをアップデートする手順

# はじめに
iOS、Androidのネイティブ開発ではXcode, Android Studioを使ってアプリのバージョンを上げてストアに申請し、アップデートする流れかと思います。

しかしFlutterに用意されているやり方はちょっと違って、それで最初のうちは混乱しがちでした。。
なので一連の操作の流れをここにまとめたいと思います。

アップデート方法に関してはいろいろなやり方があるっぽいので、この記事は「あくまで私の場合は」と言う点だけご了承お願いします！

**※CI/CDを使わない、完全ローカルでの作業となります。**

# pubspec.yamlを編集
pubspec.yaml内の

```yaml
version: 1.0.5+4
```

の部分を変更します。

例えば

```yaml
 version: ○.○.○+△
```

**iosの場合「○.○.○」の所がversion、「△」がビルド番号**

https://developer.apple.com/library/archive/technotes/tn2420/_index.html

**androidの場合「○.○.○」の所がversionName、「△」がversionCode**

https://developer.android.com/studio/publish/versioning?hl=ja

# ビルドして新しいバージョンを反映させる
ここであるあるなのだが、pubspec.yamlを編集したからすぐにバージョン番号が反映されるかと言うと、そんなことはない。。。

「Xcodeでarchiveを作成してもバージョンが変わっていない！！！」と言う感じです。。:sweat:

https://zenn.dev/tatukane/articles/f59ffcc0cc45ea

## iOSの場合

```console
flutter pub get
flutter build ios
```

iosフォルダ内の`Runner.xcworkspace`からXcodeを開き

![Screenshot 2025-01-08 at 13.36.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/073582e8-e761-2f4a-ec05-f013f2365283.png)


Distribution Appボタンからarchiveを作成して送信

## Androidの場合

```console
flutter clean
flutter build appbundle
```

`build/app/outputs/bundle/release/`の場所にaabファイルが出力されます

もしKeystoreファイルが見つからないエラーが出た場合は、`key.properties`ファイルを`android`ディレクトリ配下に作成していない可能性があります。

https://qiita.com/kokogento/items/b11eadeee3d4b1143497

```properties:android/key.properties
storePassword=your_password
keyPassword=your_password
keyAlias=key0
storeFile=./keystore
```
safariでdatetime_localを使ったときに「有効な値を入力してください」と言われる

## 何が起きたか
safariでdatetime_localのフォームを使い、値を必須とした状態(requireオプションをつける)で、デフォルト値を設定しているにもかかわらず、submitしようとした時に「有効な値を入れてください」と言われる。

## 原因
デフォルト値が秒まで入っていると値として認識してくれないことが原因
```
OK例
"2023-03-09T20:41:00+09:00"

NG例
"2023-03-09T20:41:31+09:00"
```

## 解決策
デフォルト値を入れる時に、フォーマット変更して秒は端折るように強制すると問題は起きなくなる。
ただ強引なので他の方法検討した方がいいかもしれない。

## 気をつけなければと感じたこと
レコードの値をデフォルト値とする場合、datetime_localとかのフォームで飛ばした値は秒以降が端折られるのでこの問題が起きない。
プログラム内で取得した秒を含む日時をそのままレコードに保存した場合は秒まで入るので問題が起きる。

## そのほか
chromeでは起きない
firefoxはそもそもdatetime_localに対応していないらしい
Bronze DBA Oracle DatabaseFundamentals

2022年8月16日にBronze DBA Oracle DatabaseFundamentalsを受験しました。
合格(2022/8/16)したので記事を書いておきます。
次受ける方の参考になれば幸いです。

## 受験理由
■１ データベースの基礎知識を身につけたかったため

## 感想
■１ 半年ほど業務でデータベースやSQLを触ったことある人であれば、1週間ほどオラクルマスター教科書 Bronze DBA Oracle Database Fundamentalsを勉強すれば取得可能なレベルかと思います。
	
## 学習教材
■１オラクルマスター教科書 Bronze DBA Oracle Database Fundamentals（渡部亮太ら, 2020, 翔泳社）

## 学習方法
■１ 公式テキスト（学習教材１）実施
・・・テキストを一通り読み、その後、巻末問題を3-4週ほど実施

## 反省点
■１ 特になし。

## 試験前にやっておいてよかったこと等
■１ よく間違える問題にチェックを付けて試験直前に何度も見直したこと。
Qiita記事のFacebookでの紹介の再現



![154257108_5055801291156559_1185411931892475775_n.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51423/38c06f84-66d3-bb5d-5cfc-253575a6ed66.jpeg)

FacebookでQiitaの記事を紹介しても、そのURLの中身が変わっていると、Qiitaに飛んでもらっても、なにがなんだかわからない。　

自己記事でなければ、当時の記事を再現することはむつかしい。
画像情報を文字情報に変換することと、埋め込みURLを明示することくらいかも。


柏原一雄 https://www.facebook.com/profile.php?id=100011754548292 a h
石津和紀さん https://www.facebook.com/kazunori.ishizu のおかげで、
Qita いいね
daily 8位に入りました。ありがとうございました。お二人が、二つの記事にいいねで合計
4が効いている。
https://gita.com/hikarut/items..



Autosar list of reference, abbreviation and term. (1-47/237): English(40d) (OL) (2020/02/26 22:44:45)

https://qiita.com/kaizen_nagoya/items/10b0fe6530bacdf376f9


固定電話IP網移行 (OL 617a) (2020/02/26 22:16:01)

https://qiita.com/kaizen_nagoya/items/b0a37c9194928f0eaa33

﻿ITEA Deliverable (Obtal (2020/02/26 21:06:36)

https://qiita.com/kaizen_nagoya/items/5124f83b6496012dbe80

﻿﻿researchmap 848 - 880- (8d) tOutal (2020/02/25 22:34:34)
﻿researchmap y.2 CURLoU**MUn** (Outl (2020/02/25 22:16:29)
﻿slideshare top 10 (2616\a) (2020/02/25 15:47:49)
﻿﻿Auk (like, hoby and life work) & Uto 70%58>*#Ш(C*+, python and Verilog HDLJ (9616a)
(2020/02/25 15:00:47)
初コーディングテスト

ある会社のコーディングテスト受けてみました〜


## 問題の内容
下記の文章に、「大文字と数字がいくつ含まれているのかを20分で答えろ」でした。
（文章はBBCから適当にコピったものです😂)

``` 
The UK will give France almost £500m over three years to help stop migrants crossing the Channel in small boats.
The cash was announced at a summit in Paris between UK Prime Minister Rishi Sunak and President Emmanuel Macron, who said France would also contribute.
The money will go towards an extra 500 officers and a new detention centre in France, but this will not be fully operational until the end of 2026.
The UK had planned to pay France around £63m this year to tackle the problem.
This new package appears to at least double that amount, with the UK pledging £120m in 2023-24.
France will also step up its funding of enforcement but has not said by how much.
``` 

## 結果
20分以内にできなかったことがかなり悔しいです。。。
30分あればできた！😂
少しづつAtCode触っていこうと思います！

## 自分のコード
もっと簡単な方法があると思うので、教えていただけると嬉しいです🙇

```
<?php
// Your code here!
$total = 0;
$input = 'The UK will give France almost £500m over three years to help stop migrants crossing the Channel in small boats.
The cash was announced at a summit in Paris between UK Prime Minister Rishi Sunak and President Emmanuel Macron, who said France would also contribute.
The money will go towards an extra 500 officers and a new detention centre in France, but this will not be fully operational until the end of 2026.
The UK had planned to pay France around £63m this year to tackle the problem.
This new package appears to at least double that amount, with the UK pledging £120m in 2023-24.
France will also step up its funding of enforcement but has not said by how much.';
$capital_letter_arr = [
    'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Z'
    ];
$num_arr = [
    '1','2','3','4','5','6','7','8','9','0'
    ];


$capital_letter_length = count($capital_letter_arr);
$num_length = count($num_arr);

for ($i = 0; $i < $capital_letter_length; $i++) {
    $capital_count = substr_count($input, $capital_letter_arr[$i]);
    $total += $capital_count;
}

for ($k = 0; $k < $num_length; $k++) {
    $num_count = substr_count($input, $num_arr[$k]);
    $total += $num_count;
}

echo $total; //48
?>
```
カラムに指定するreferences型とは？

## はじめに

カラム作成時に使う型は様々ありますが、references型というものを改めて学んだのでアウトプットしたいと思います。

## references型とは？
references（直訳すると”参照”）型とは、新規作成するテーブルのカラムに、もともとあるテーブルを指定する場合に使います。


## 使用する方法

```
rails g model comment board:references name:string comment:text
```
こちらを解説します。
commentテーブルに”board:references”と書くとBoardモデルと紐づけるためのboard_idカラムが作成されます。
後ろのnameとcommentのカラムは従来通りの記述ですね。

models/comment.rbを開くと
```
class Comment < ApplicationRecord
  belongs_to :board　#ここが追加されます
end
```
”belongs_to :board”が自動で追記されます。
これは、commentに対してboardは１つしかないという事を表します。
逆の意味が　has_manyになりますね。1対多ってやつです。
has_manyは自分で記述します。

最後にマイグレーションファイルを見ると
```
class CreateComments < ActiveRecord::Migration[6.1]
  def change
    create_table :comments do |t|
      t.references :board, null: false, foreign_key: true　#ここがreferencesの文章！
      t.string :name, null: false
      t.text :comment, null: false
      t.timestamps
    end
  end
end
```

こんな感じになってます。
``t.references``
カラムが他のテーブルを参照しているという事

``null: false``
空欄を許可しないという事

``foreign_key: true``
外部キーであるという事
**外部キーとは**
指定したカラムの値のみしか使えないようにす制限の事



## おわりに
rails db:migrateをしたら完成です！
ありがとうございました^^
FFmpeg で動画やオーディオ（音声）のファイル形式を簡単に変換する

## 概要
[FFmpeg（エフエフエムペグ）](https://ffmpeg.org/)は、動画・音声のデータを簡単に記録・変換・再生できる、無料のコマンドツールです。

尚、今回は詳細に説明しませんが、FFmpeg はこれ以外にも非常に応用が効く、控えめに言って **"神ツール"** です。

背景としては、私が動画制作の仕事では mac を使用してるため、いつも書き出す動画ファイルは `.mov`
しかし、「mov ではなく mp4 にして欲しい」とご要望があったため、「わざわざ動画制作ツールから書き出し直さなくてもよい方法ないかな？」と思って見つけたのが **FFmpeg** です。

ちなみに、mp4 ファイル等の動画から「オーディオのみ」を書き出して音声ファイルを抽出した時にも、macOS だと `m4a` で書き出してしまいますが、これを `mp3` ファイルにしたい時などにも使えます。

## FFmpeg インストール

mac ユーザーなので、Homebrew 使ってインストールしました
（Windows の方は[公式サイト](https://ffmpeg.org/)の導入方法をご覧くださいませ）

```bash
brew install ffmpeg
```

インストールできたか確認

```bash
# バージョン確認コマンド
ffmpeg -version

# 実行結果
ffmpeg version 5.1.2 Copyright (c) 2000-2022 the FFmpeg developers
 :
```

## 使い方

### 基本
基本的な使用方法は

```
ffmpeg {オプション} ({入力ファイルオプション} -i {入力ファイルパス}) ({入力ファイルオプション} {出力ファイルパス})
```

### サンプル
例）カレントディレクトリの `.mov` の動画を `.mp4` に変換するコマンド

```
ffmpeg -i input.mov output.mp4
```
##### 👇 実行結果
実行後に数秒待つと、無事に変換完了（変換対象のファイルサイズによっては、少し時間がかかる）。
変換前のファイルは消えることなく、`.mp4` 形式でコピーが作られた。

![ffmpeg実行サンプル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/787582/3506517f-50b4-878b-8c09-1b92f0b8ecbb.png)

- input: 変換前のファイル
- output: 変換後のファイル

動画再生自体も問題なくできた👍
ファイル名は日本語が入っていても問題なく変換できましたが、できれば半角英数字のみの方がより安心かなと個人的には思いました。

### m4a → mp3 に変換
オーディオファイル（音声ファイル）を変換したい場合、例えば、概要に記載した様に `.m4a` ファイルから `.mp3` ファイルを作成する場合も同様です。

```bash
ffmpeg -i input.m4a output.mp3
```

非常に簡単ですね。

### mp4（動画）→ mp3（音声抽出）に変換
動画ファイルから直接オーディオファイルだけを抽出する場合は、以下の様なコマンドで抜けます。

```bash
ffmpeg -i input.mp4 -vn -acodec libmp3lame -ab 192k output.mp3
```

- `-vn`: 映像を無視
- `-ab 192k`: 音質（ビットレート）設定

## ヘルプコマンド
以下でコマンドのヘルプが表示されるので、オプション指定など調べられます

```bash
ffmpeg -h
```
JupyterNotebook をスクリプトのように実行できる Pepermill についてのメモ

# この記事はなに？
JupyterNotebook を pythonスクリプトのように実行できる pythonライブラリ Pepermill について自分が調べたものをまとめたものです。

# 公式
https://papermill.readthedocs.io/en/latest/index.html

# Papermillとは
PepermillはPythonベースのオープンソースのパッケージで、JupyterNotebookを実行し、Notebookのパラメータを変更して、複数のバージョンを生成できるようにするツールです。

# インストール
```
pip install papermill
```

# Jupyter Notebookを実行する方法
## パラメータの設定
まずは実行する Notebookを作成し、以下の手順で変数を定義します。
1.  View, Cell Toolbar, Tags からタグ付けツールバーを有効にする
2. セルの右上にあるテキストボックスにパラメータを入力する
3. Add tagをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164843/0bbbbccb-577b-ff24-d17f-3af3ef978862.png)

こうすることで、変数をPepermillのパラメータとすることができます。
papermillはnotebook内のparametersタグが付いたをセルを探しに行って、セル内の変数を書き換えることができます。

## Notebookの実行
Pepermillを使用してNotebookを実行するには、以下のコマンドを使用します。
```bash
papermill input_notebook.ipynb output_notebook.ipynb -p parameter1 value1 -p parameter2 value2 ...
```
* input_notebook.ipynb 入力ノートブックのファイルパス
* output_notebook.ipynbは出力ノートブックのファイルパス
* -p  でノートブック内のパラメータの値を指定できます。

コマンドを実行すると、**入力ノートブックに設定したパラメータの値を -p で指定した値に書き換えて実行**し、出力ノートブックに結果を保存することができます。

## pythonスクリプトからNotebookを実行
以下のように, pythonスクリプトから実行することもできます。
```python
import papermill as pm

# パラメータを辞書形式で定義
parameters = {"param1": 10, "param2": "hello"}

# notebookを実行
pm.execute_notebook(
   input_path='input.ipynb',
   output_path='output.ipynb',
   parameters=parameters
)
```

# まとめ
異なるパラメータセットを使用して同じノートブックを繰り返し実行する必要がある場合は、Pepermillを使うと便利そうです。
例えばグラフ作成に使用する変数をパラメータ化し、異なるグラフや表を簡単に生成するなどの利用法が考えられそうです。
また、POCで使用したNotebookをそのまま機械学習、データ分析のパイプラインに使用したりもできそうです。
【Linux】ps aux | [i]nit コマンドでinitプロセスだけを表示する小技

# initプロセス以外も表示される
「initプロセスが見たい！実行中のプロセスからinitを検索してみよう！」
```
$ ps aux | grep init
ubuntu    136856  0.0  0.5   9212  5216 pts/0    Ss   04:18   0:00 /usr/bin/bash --init-file /home/ubuntu/.vscode-server/bin/xxxxxxx/out/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh
ubuntu    136945  0.0  0.2   7004  2056 pts/0    S+   04:18   0:00 grep --color=auto init
```
「あれ？なんか一つ余計なのも表示されてる。」
この方法だと、`grep`コマンド自体にも`init`という文字列が含まれているため、検索に引っかかってしまいます。
```
ubuntu    136945  0.0  0.2   7004  2056 pts/0    S+   04:18   0:00 grep ←ここ --color=auto init
```

# initプロセスだけを表示する
検索の仕方を変えてみましょう。
`init`を`[i]nit`に変えてみてください。
```
$ ps aux | grep [i]nit
ubuntu    136856  0.0  0.5   9212  5216 pts/0    Ss   04:18   0:00 /usr/bin/bash --init-file /home/ubuntu/.vscode-server/bin/xxxxxxx/out/vs/workbench/contrib/terminal/browser/media/shellIntegration-bash.sh
```
無事にinitプロセスだけ表示されました！

# なぜ？
- 「`init`という文字列は`init`と`[i]nit`という正規表現で検索される。
- しかし、`[i]nit`という文字列は`[i]nit`という正規表現には検索されない。
- なぜなら、文字列`[i]nit`には`i`と`nit`の間に文字列`]`が含まれているから。

そもそも、`[i]nit`という正規表現は文字列`i`と文字列`nit`が結合した（日本語が合っているかわからない）文字列という意味です。しかしそんな文字列は`init`という文字列しか存在しません。つまり、`[i]nit`という正規表現は`init`という文字列のみを検索します。

`grep`コマンドのプロセス含まれていた`init`という文字列が、`[i]nit`という文字列に変わり、`grep`コマンドのプロセスが検索されないようになりました！

# 参考
https://atmarkit.itmedia.co.jp/ait/articles/1603/28/news022.html

https://docs.oracle.com/cd/E19253-01/816-3946/6ma6m5bn9/index.html

https://qiita.com/miyuki_samitani/items/559fb28faa3888bce526
Atom S3 でハマったこと

## M5 Atom S3 で発生するいくつかの問題
　やっと在庫が復活した M5Stack  社の Atom S3 を入手して、使ってみましたが、まだ環境が整っていないようで、次のような問題が発生しました。

### macOS 上（AppleシリコンのMac）で発生した問題
#### M5Berner で UIFlow用のファームウェアが書き込めない
　シリアルポートは ```/dev/tty.usbmodem1101``` がそれらしいので選択して書き込もうとするも、エラーで書き込めない（S3は少し反応している）

#### Arduino IDE では、コンパイル時にエラーになる
　シリアルポートは上記と同じものを選択、ボードは ```M5 Atom S3``` を選択して「接続」と出ているが、コンパイルしようとすると、次のエラーが出る。
```
bash: /esptool: No such file or directory

exit status 127

Compilation error: exit status 127
```

### 仕方なく、Windows機で試してみた結果

 Windowsでは、Arduino IDE で無事スケッチが書き込めて普通に使えた。
![IMG_8752D.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16491/447fb429-84ef-380d-234d-de3727c5826b.jpeg)

ただ、書き込むたびに、ポートとボードを選択し直す必要があります。

### Windows機でも発生する問題

#### UIFlowが使えない
　M5Berner での書き込みはできるのだが、API-Key が表示されず、UIFlowと連携できない。
（S3のUIFlow はまだ、アルファー版のようなので、今後に期待する）

### 購入時に入っていた状態に戻す方法
購入してすぐにUSB-Cに接続すると表示されるサンプルプログラムに戻すには、
本家サイトに書き込み用アプリ（Windows版のみ）が用意されています。 http://docs.m5stack.com/en/core/AtomS3 
の、Related Link　にある、
"AtomS3 Demo Easyloader Download"
をクリックしてダウンロードできます。

### おまけ
　M5Berner で UIFlow 用のファームウェアを書き込むと、なぜかシリアルポートが変更になり、その後、何もできなくなって困りました。
これを解決するには、リセットボタンだけではダメで、リセットボタンとボタンA（画面）を同時にクリック・ホールド（2秒くらい）してリセットボタンを先に放すことで、画面表示が無くなり、元のシリアルポートが使えるようになりました。

### 先達のコメントを歓迎します
　S3を使い始めたばかりで、つまづいたことを書きましたが、「これで解決するよ」など先達のコメントを歓迎します。

　上記の問題は、本家のサポートサイトに送りましたので、回答があり次第、ここで共有しようと思います。

### 【追記】　M1 Macで M5Berner で書き込めるようになった。
　M5Stack社から返信があり、次の手順でUIFlowの書き込みができました。
本家サイトの AtomS3 の説明ページにちゃんと書いてあったのでした。
”Reminder: If you need to burn the firmware, please press and hold the reset button (about 2 seconds) until the internal green LED lights up, then you can release it, at this time the device has entered download mode and waited for burning."


1. リセットボタンを長押し（約2秒、内部の緑色LEDが点くまで）
1. 書き込み用のポートが現れるので、それを指定して書き込み

#### UIFlow はオンライン版の UIFlow 2.0 を使う
　Atom S3 は専用のオンライン版UIFlowを使う
URLは https://uiflow2.m5stack.com/ を使う。
USBで接続後、UIFlow 2.0 でログインするとS3を選択できるようになる。
![IMG_8765D.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16491/8771e1ae-7205-4e33-9568-fc5a8352bffc.jpeg)

### 【追記】M1 Mac上 Arduino IDE でS3が使えるようになった
　設定が不足していたようです。
　これで、M1 Mac mini では改善しましたが、M1 MacBook Air では改善しませんでした。
 → 念の為、 ~/Document/Library/ 以下のファイルを削除して、必要なライブラリーをインストールしなおしたら、問題が解決してコンパイルができるようになりました。


#### ボードの追加
　Arduino IDE 設定の「追加のボードマネージャのURL」に
```
https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/arduino/package_m5stack_index.json
```
を追加して、ボードマネージャで M5Stack をインストールします。
#### ライブラリーの追加
M5AtomS3 ライブラリーをインストールするのですが、エラーがありました。
私の場合、Adafruit のものが邪魔しているとのエラー（白文字なので読まなかった）が出ていたので、以下の二つをフォルダーごと削除して、インストールしなおしました。
```
~/Documents/Arduino/libraries/Adafruit_Sensor
~/Documents/Arduino/libraries/Adafruit_Unified_Sensor
```
これで無事、コンパイル、書き込みができました。

これらの躓き情報が、誰かの役に立てば嬉しい。