OmniAICreator/Qiita-1.07M huggingface dataset:
micro:bitの入力処理スピードと言語の関係(MakeCodeとPython Editor)

micro:bitは子ども達がプログラミングを学ぶために作られたため、色々なモノを作る敷居が低くとてもおススメなデバイスです。

自分自身ワークショップを開催したりいくつか作品も作りました。

一方で1つ作りたいものでどうしてもうまくいかなかったものが解決したのでここに記します。

## まずは結論
入力処理スピードが必要なものはPythonで作りましょう。MakeCodeでは実現不可と思われます。


## 作りたいもの

シュウォッチ(連射スピード測定マシーン)

https://ja.wikipedia.org/wiki/%E3%82%B7%E3%83%A5%E3%82%A6%E3%82%A9%E3%83%83%E3%83%81


## まずはいつものMakeCodeで

ボタンを押す前は泣き顔、ボタンを押すとハートが表示されるプログラムを作りました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71746/e08ce30c-ef1f-c8a9-2e72-63907941e427.png)

https://makecode.microbit.org/S54989-04801-39650-43278

動作動画がこちらです。
連打に対応できていないのがわかります。

<iframe width="560" height="315" src="https://www.youtube.com/embed/32Z_aENOG-k?si=CkulmdzJ0ZK5U0tg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

## 滅多に使わないmicro:bit Python Editorで


ボタンを押す前は小さなハート、ボタンを押すとハートが表示されるプログラムを作りました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71746/ca0be5cb-9302-6d59-9480-e14cbb4f3298.png)

動作動画がこちらです。
連打にバッチリ対応できているのがわかります。

<iframe width="560" height="315" src="https://www.youtube.com/embed/hUES8aEBh3k?si=fqFHcaEQIz4Hfl_b" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

## まとめ
MakeCodeでは入力情報のリフレッシュサイクルが低く、連打の情報取得は実現不可と思われます。
MakeCodeでできないのは残念ですが、Python Editorを利用すればシュウォッチを作れることがわかりました。
AWS Lambdaでlib64/libc.so.6: version `GLIBC_2.28' not foundの対応

# 状況

[`terraform-aws-modules/terraform-aws-lambda`](https://registry.terraform.io/modules/terraform-aws-modules/lambda/aws/latest) で APIのAuthorizerをデプロイしようとして、`pyjwt[crypto]` でID Tokenを検証しようとしたら、そもそもpyjwtのインポートでエラーが発生。

```
[ERROR] Runtime.ImportModuleError: Unable to import module 'authorizer': /lib64/libc.so.6: version `GLIBC_2.28' not found (required by /var/task/cryptography/hazmat/bindings/_rust.abi3.so)
```


# コード構成


```
├── code
│   ├── authorizer.py
│   ├── poetry.lock
│   └── pyproject.toml
└── main.tf
```

```terraform
module "authorizer_lambda" {
  source  = "terraform-aws-modules/lambda/aws"
  version = "6.0.1"

  function_name = local.function_name
  handler       = "authorizer.handler"
  runtime       = local.runtime

  source_path = [
    "${path.module}/code",
  ]
}
```

# 原因
エラーメッセージの通り、 `GLIBC_2.28` が存在しない。もっと言えば `/var/task/cryptography/hazmat/bindings/_rust.abi3.so` があればいけそう。


# 対応

```sh
# _rust.abi3.soを含んだパッケージを取得
$ pip install --platform manylinux2014_x86_64 --implementation cp  --only-binary=:all: --upgrade --target temp/ cryptography

# 該当のディレクトリを作成
$ mkdir -p cryptography/hazmat/bindings

# pipで準備した_rust.abi3.soをコピー
$ cp -ai temp/cryptography/hazmat/bindings/_rust.abi3.so cryptography/hazmat/bindings/

# pipのパッケージは不要なので削除
$ rm -fR ./temp

# cryptography/hazmat/bindings/_rust.abi3.soが準備できました
$ tree cryptography/
cryptography/
└── hazmat
    └── bindings
        └── _rust.abi3.so
```

あとはTerraform Applyをすれば、`pyjwt[crypto]` でID Tokenを検証ができるようになっています。
【メモ】Trailheadでやったことを備忘用に記録していく（商品、見積、契約　キャンペーン）

## 商品、見積、契約

### 価格表を作成して商品を追跡する

・商品レコードを使用
　⇒商品ベースで管理、顧客に販売する商品を追跡する
　⇒標準価格表として入れておく

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3532370/8b46dfb9-50dd-b27e-ee29-051c1b226f7a.png)

ここに商品をどんどん入れていく

### 顧客見積の設定と契約の追跡を行う

そのまま見積もりをPDFにして出すことができるのね。

## キャンペーンの基本

生成しているリードの数、構築しているパイプラインの額、
マーケティング活動の結果として成立させた商談の数
⇒これらを分析できる。
キャンペーン自体をグループ化したりも可能

「Jamie は最初のキャンペーンを作成しました。Jamie はこれで納得しています。次は Margaret にも納得させる仕事が待っています。」
('ω')大丈夫かなこの会社笑

## キャンペーンの整理

階層で管理する。（大体は3階層）
・最上位レベルは、製品マーケティング活動の積み上げ
・第 2 レベルは、製品の立ち上げや顧客からのフィードバック入手などの大規模なイニシアチブです。
・第 3 レベルは、メールやデモなどの、個別のマーケティングプログラム

親子関係を紐づけて、ここの成果を図る。

## キャンペーンメンバーを識別

・キャンペーンメンバーに
　⇒リード、取引先責任者、そして個人取引先が追加可能

## キャンペーンのレポート
amplify CLIで作成したLambdaをVSCode上でデバックする

# 初めに
amplifyのRest APIを開発していて、ローカルで実行する手順が見つからなかったので、調べて記事にします。

# 手順
1. amplifyプロジェクトの作成
```bash
amplify init # amplifyプロジェクトの作成
amplify add api # amplifyにapiを作成するのと同時にfunction(lambda)の作成
```
2. launch.jsonの作成
```json
{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "aws-sam",
            "request": "direct-invoke",
            "name": "Launch",
            "invokeTarget":{
                "target": "code",
                "projectRoot": "./amplify/backend/function/amplifytest91994be0/src/",
                "lambdaHandler": "index.handler"
            },
            "lambda": {
                "runtime": "nodejs18.x",
                "payload": {
                    "path": "./amplify/backend/function/amplifytest91994be0/src/event.json"
                },
                "environmentVariables": {"REGION": "ap-northeast-1"}
            }
        }
    ]
}
```
今回、Lambdaの環境をNodev18にしました。
projectRootには、LambdaのEventHandlerのフォルダーを指定すればよいです。lambdaHandlerには、ファイル名.関数名でよいです。
lambda.payload.pathには、eventのJsonを記入すればよいです。
eventのJsonはcloud watchでeventを出力させて取得することができます。

3. 実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/893794/5eba01a4-0276-6bdb-d3f0-302d8465be08.png)
画像のとおり実行できるはずです。
実行時、Dockerが必要になるのでお忘れなく
Rで部分和問題をbit全探索で解く

- Rでは、expand.grid関数を使うと、引数のベクトルの全組み合わせを列挙できる
- 下記のように、引数を0:1にして5個繋げれば、 2<sup>5</sup> =32 通りの組み合わせを表示可能

```　R:長さ5、各要素が 1 か 0 のタプルを作成
> Pattern <- expand.grid(0:1, 0:1, 0:1, 0:1, 0:1)
> Pattern
   Var1 Var2 Var3 Var4 Var5
1     0    0    0    0    0
2     1    0    0    0    0
3     0    1    0    0    0
4     1    1    0    0    0
5     0    0    1    0    0
6     1    0    1    0    0
7     0    1    1    0    0
8     1    1    1    0    0
9     0    0    0    1    0
10    1    0    0    1    0
11    0    1    0    1    0
12    1    1    0    1    0
13    0    0    1    1    0
14    1    0    1    1    0
15    0    1    1    1    0
16    1    1    1    1    0
17    0    0    0    0    1
18    1    0    0    0    1
19    0    1    0    0    1
20    1    1    0    0    1
21    0    0    1    0    1
22    1    0    1    0    1
23    0    1    1    0    1
24    1    1    1    0    1
25    0    0    0    1    1
26    1    0    0    1    1
27    0    1    0    1    1
28    1    1    0    1    1
29    0    0    1    1    1
30    1    0    1    1    1
31    0    1    1    1    1
32    1    1    1    1    1
```
- これを用いて、全探索を行ってみる
- 例えば、下記の部分和問題を全探索で解くことを考える
- 例題はこちらから引用：[こわくないbit全探索2 基本編1](https://qiita.com/u2dayo/items/8c1601a61841540b4947)
![スクリーンショット 2023-10-17 22.46.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1313043/12c82be2-6378-8f0b-7a1a-6e5eda3bfa49.png)

- *N*=5, *A*={1,2,3,6,8},*W*=10の場合を考えてみる
```　R:部分和問題を全探索で解く
Pattern <- expand.grid(0:1, 0:1, 0:1, 0:1, 0:1)
A <- c(1, 2, 3, 6, 8)
L <- 5
W <- 10
ans <- 0

for( j in 1:nrow(Pattern)){
    Combi <- c()
    for( i in 1:L ){
        if(Pattern[j,i]){
            Combi <- append(Combi,A[i])
        }
    }
    if( sum(Combi) == W){
        ans = ans + 1
    }
}
print(ans)
```
こんな感じ？
【解決】FlutterでSupabaseに値の追加ができない

こんにちは！atomuです！
今回は少し困ったことに出会ったので久しぶりに記事を書いてみました！

### 【本題】　FlutterでSupabaseに値を追加できない
個人開発でSupabaseを使っていて、ユーザーのGoogle認証まではなんとかいけたのですが。。
ユーザーの名前などの情報をdatabaseを使って保存しようと思ったら！！
**全く追加されないのです！**

まずは私の解決前のコードです☟
```dart
final userId = supabase.auth.currentUser!.id;
final username = _nameController.text.trim();

await supabase.from('profiles').update({
     'username': username,
     // the list has place name
     'places': userPlacesList,
}).eq('id', userId);
                            
}
```
このコードでは、supabase上でprofilesというデータベースを作成しログインしているユーザーのidとusernameとuserPlacesListというリストを格納しようとしています。
eqというのはidというカラムがユーザーのidと等しいところにupdateメソッドを使って値を更新するということです。

しかし、いくらリロードをしても追加されませんでした！
それもそのはず！
調べてみると、updateメソッドでは**今データベース上にある値を更新している**ということで**値の追加はしないのです！**

### 【**解決策**】  updateではなくupsertを使う
こちらが解決後のコードです☟
```dart
final userId = supabase.auth.currentUser!.id;
final username = _nameController.text.trim();

await supabase.from('profiles').upsert({
      'id': userId,
      'username': username,
      'places': userPlacesList,
});
```
このようにupsertメソッドを使うことで、もしprofilesにこのユーザーのidの値が格納されていなかったら新たに列を追加し、profilesに格納されていたらその値を更新するという便利なことができるようになりました！userIdは同じユーザーでは変わらないので、そこでデータがあることの区別をしています。
この問題に丸1日かけ、分からなさすぎてStackOverFlowに投稿しました！（誰からもanswerが来なかった伝説）
（[Database of Supabase UPDATE doesn't work on Flutter](https://stackoverflow.com/questions/77293204/database-of-supabase-update-doesnt-work-on-flutter/77295256#77295256)）

### 【まとめ】
- FlutterでSupabaseに値を追加できない場合はメソッド名を疑う
- 今回の場合はupdateではなくて**upsert**だった
- Supabase面白いーーー

ここまで読んでいただきありがとうございました！
この記事が同じ問題に困っている人に届くことを願っています！
何か質問やここ間違っているよ！みたいなことがあればお気軽にコメントください！

### 【参考】
https://zenn.dev/flutteruniv_dev/articles/crud_with_supabase

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

https://supabase.com/docs/guides/getting-started/tutorials/with-flutter?platform=android&database-method=sql
【メモ】Trailheadでやったことを備忘用に記録していく（Lightning Experience のリードと商談）

## 見込み客としてのリードの作成と取引開始

リードレコード･･･商談前の見込み客状態のもの？

リード⇒商談にステップアップさせる


## 商談の処理

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3532370/6bf9cc0d-979c-ed7a-d65e-d550655f8b4f.png)

商談タブから商談を作る＆責任者を入れてアサインする。

## チームでの販売とクレジットの分割

・取引先チーム：長期
・商談チーム：セールスまで

## パスと Kanban による成功の視覚化

・Kanbanってワードすごい。TOYOTA。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3532370/0d87a455-5d77-c902-2a87-e69e892ec7a5.png)

なるほど、本当にそうだ。工場の奴と同じ、工程ごとに総収益見込みもわかるのな。

おおー、ドラッグで移動できて視覚的にすぐ切り替わるの楽しい
誤操作したときに使えるGitコマンド集

## git addしたファイルを取り消す
```
git reset <file>
```
指定したファイルのステージングを取り消すことができます

## 直前のコミットの取り消し
```
git reset --soft HEAD^
```
間違えたコミットをしたときによく使います
注意：取り消したコミットは元に戻らないです

## 直前のコミットの修正
```
git commit --amend
```
直前のコミットに追加で修正を行うときに使用します

## 修正したけど、一部のファイルだけ元に戻したい時
```
git checkout -- <file>
```
指定したファイルの変更が取り消され、最後のコミット時点の状態に戻ります。

## リモートブランチの削除
```
git push origin --delete <branch_name>
```
誤ったブランチをリモートブランチにpushしたときに使えます

## (おまけ)作業用ブランチに元ブランチの最新内容を取り込む
作業用ブランチ：develop
元ブランチ：master
という設定にします

①元ブランチに切り替えて、最新にする
```
git checkout master
git pull
```

②作業用ブランチに切り替えて、元ブランチをリベースする
```
git checkout develop
git rebase master
```
【Swift】CIFilterで画像にぼかしをかける

# はじめに
CIFilter6日目！

# サンプルアプリ
![Simulator Screen Recording - iPhone 15 - 2023-10-17 at 22.45.02.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/edf96a33-1474-8b6a-6c3e-cac6bce5e8dc.gif)

# 実装
```swift
import SwiftUI

struct ContentView: View {
    private let image = UIImage(named: "sample")!

    @State private var uiImage: UIImage?

    var body: some View {
        ScrollView {
            VStack {
                if let uiImage {
                    Image(uiImage: uiImage)
                        .resizable()
                        .scaledToFit()
                } else {
                    Image(uiImage: image)
                        .resizable()
                        .scaledToFit()
                }

                HStack(spacing: 15) {
                    Button {
                        applyBokehBlurFilter()
                    } label: {
                        Text("適用")
                    }
                    
                    Button {
                        uiImage = nil
                    } label: {
                        Text("リセット")
                    }
                }
            }
            .padding(.horizontal, 20)
        }
    }

    func applyBokehBlurFilter() {
        let context = CIContext()
        let inputImage = CIImage(image: image)!

        guard let bokehBlurFilter = CIFilter(name: "CIBokehBlur", parameters: [
            kCIInputImageKey: inputImage,
            kCIInputRadiusKey: 30.0
        ]) else { return }
        guard let outputImage = bokehBlurFilter.outputImage else { return }
        guard let cgImage = context.createCGImage(outputImage, from: outputImage.extent) else { return }
        self.uiImage = UIImage(cgImage: cgImage)
    }
}
```

# おわり
CIFilterなんでもできますなー
Dockerで「Error response from daemon: Ports are not available: exposing port TCP 0.0.0.0:5432 -> 0.0.0.0:0: listen tcp 0.0.0.0:5432: bind: address already in use」が出た時の対処法

## エラー
Dockerでコンテナを立ち上げようとすると以下のエラーが出て、起動ができなかった。
5432のポートが既に他で使われていることが原因。
```
Error response from daemon: Ports are not available: exposing port TCP 0.0.0.0:5432 -> 0.0.0.0:0: listen tcp 0.0.0.0:5432: bind: address already in use
```
## 解決策
### ①ポートを占有しているアプリケーションを特定する
```
lsof -i :5432
```
何も出ない場合、頭にsudoをつけて再実行。そうするとパスワードが要求されるので、PCログイン時に使っているパスワードを入力。
```
sudo lsof -i :5432
```
```
Password:
```

### ②アプリ特定後、PIDをKillする
```
Password:
COMMAND  PID     USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
postgres 141 postgres    7u  IPv6 0xc658af2b5620d7cf      0t0  TCP *:postgresql (LISTEN)
postgres 141 postgres    8u  IPv4 0xc658af268ae07bdf      0t0  TCP *:postgresql (LISTEN)
```
ポートを利用しているアプリケーションを特定したら、以下の様にPID番号を入力して、killしてあげる。
```
sudo kill 141
```

再度以下を行って、何も表示されなければOK
```
sudo lsof -i :5432
```
deviseの特定のアクションをカスタマイズする

## はじめに
deviseを使っていて特定のアクションをカスタマイズしたい場面は結構あると思います。
その時のメモです。

## 環境
`rails 6.1.6.7`
`ruby 3.0.6`
`devise 4.9.3`

## 状況
私の場合、deviseにconfirmableな設定を追加していました。
ユーザー登録時に追加のアクションをしたかったので、registrations_controller.rbのcreateアクションをカスタマイズすることになります。

カスタマイズをするにあたりdeviseのコードを読んでみるのは非常に参考になりました。
https://github.com/heartcombo/devise/tree/main

## route編集
registrations_controllerを編集するときは明示的に登録系の処理には`users/registrations_controller`を使うように指定する必要があります。

```rb:config/routes.rb
Rails.application.routes.draw do
  devise_for :users, controllers: {
    registrations: 'users/registrations',
  }
end
```

## アクションカスタマイズ
deviseのユーザー新規登録の時はregistrationsコントローラーのcreateアクションが実行されます。

```rb:app/controllers/users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
  def create
    binding.pry
    super
  end
end
```

上記のようにすれば登録時に処理の止めて実際にどんなデータが送られているのか確認することができます。
Dartのsuperとは?

# 公式にも解説あるけどわかりずらい？
https://dart.dev/language/constructors

とりあえずコード書いてどんなことしてくれるのか検証してみたら、定義した親クラスのプロパティとメソッドを参照してくれるようだ。。。

つまり、変数と関数を呼び出すことができるということです。

```dart
// superクラスとは、継承元のクラスのこと。今回だとHogeクラスがsuperクラスになる。
class Hoge {
  String name = 'スーパークラス';
  void sayName() {
    print('継承するクラス');
  }

  void greet() {
    print('Hello');
  }
}

class Fuga extends Hoge {
  String name = 'Fuga';
  void greet() {
    // superを使うと、継承元のクラスのメソッドを呼び出せる
    super.greet();
    print(super.name);
  }
}

void main() {
  fuga.greet();
  fuga.sayName();
}
```

実行結果
```
Connecting to VM Service at ws://127.0.0.1:57814/HJLHuQnwFl0=/ws
Hello
スーパークラス
継承するクラス

Exited.
```

![スクリーンショット 2023-10-17 21.56.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2303722/3e3d1742-33da-754b-737b-8da78e8704c2.png)

## 最後に
superってなんだろうかと毎回調べていることが多かったのですが、やっとわかりました。これであってるのか疑問ですが😅
Gstreamerエレメントを自作するまで - Gstreamerとは -

## 目的

[Gstreamer](https://gstreamer.freedesktop.org/)を使ったアプリケーションの開発が始まってきたので、自分でエレメントを作成できるようになるまでにやったことをメモ書きする

## 目次

1. [Gstreamerとは](https://qiita.com/DaiGuard/items/6b66a45b545eaa9fbdcb)
1. [Pythonでのプラグイン作成](https://qiita.com/DaiGuard/items/05b0f233c4a3296d6677)
1. C++でのElement作成

## Gstreamerとは

### 概要

引用: [GStreamer:Wikipedia](https://ja.wikipedia.org/wiki/GStreamer)

>GStreamer（ジーストリーマー）は、フリー（ライセンスはLGPL）のマルチメディアフレームワーク。
>
>C言語で記述され、主にUNIXで開発されている。ビデオ編集ソフトやストリーミング、そしてメディアプレーヤーなどのようなマルチメディアアプリケーションのベースとなる機能を提供する。クロスプラットフォームとなるよう設計されており、Linux (x86, PowerPC, ARM)、Solaris (x86, SPARC)、OpenSolaris、FreeBSD、OpenBSD、macOS!、Windows、OS/400上で動く。GStreamerではユーザーがライブラリを組み合わせてグラフ構造の処理パイプラインを1から構築する必要がある[1][2]。
>
>核となる部分以外では、プラグインのライブラリ群で構成されている。 動的にロードされ、種々のコーデック、コンテナフォーマット、出力ドライバをサポートしている。 他のプログラミング言語では、Python、Vala、C++、Perl、GNU Guile、Rubyなどにバインディングされている。

図解で示すとGstreamerは複数のElementをPipelineでつないで一つのアプリケーションとして実行できる物と理解した。

- Element: Gstreamerプラグインをロードして実行できる要素単位
- Pad: 各要素を繋ぐための接続部。`src`が出力、`sink`が入力となる
- property: Elementを実行する際に設定するパラメータ
- capabirity: Element同士を繋ぐパイプラインのデータ型

![gst.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171097/156319d5-6173-69d6-9785-ea4abee95937.png)

### 使用方法

#### `gst-inspect-1.0`

Gstreamerプラグインの情報を表示するコマンド

```bash
# 読み込み可能なプラグインのリストを表示
gst-inspect-1.0
# 各プラグインの詳細を表示
gst-inspect-1.0 <plugin name>
```

プラグイン詳細の表示例が以下です

```bash
Pad Templates:
  SINK template: 'sink'
    Availability: Always
    Capabilities:      
        # <capability type>  
  SRC template: 'src'
    Availability: Always
    Capabilities:
        # <capability type>
Element has no clocking capabilities.
Element has no URI handling capabilities.

Pads:
  SINK: 'sink'
    Pad Template: 'sink'
  SRC: 'src'
    Pad Template: 'src'

Element Properties:
  # <property name>     : property description
```


#### `gst-launch-1.0`

Gstreamerパイプラインを起動するためのコマンド

`gst-launch-1.0`コマンドの使用方法を以下に示す
コマンドのつなげ方として ***プラグイン名*** + ***プロパティ*** + ! + ***キャパビリティ***を繰り返すことでパイプラインを作成する。

この際、前後のプラグインのキャパビリティは同じに設定できる必要がある。

![command.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171097/18ff466d-05af-e6a1-f6b8-bea42483eb4c.png)

```bash
# USBカメラから映像を取得してXウインドウに表示するコマンド
gst-launch-1.0 v4l2src device="/dev/video0" ! "video/x-raw,width=640,height=480" ! videoconvert ! ximagesink sync=false
```

## 次へ

次はPythonを使ったプラグインを作成します
[Pythonでのプラグイン作成](https://qiita.com/DaiGuard/items/05b0f233c4a3296d6677)
ONLYOFFICE APIでファイルを変換する方法

## ファイルの変換とダウンロード

ドキュメント変換サービスはONLYOFFICE Document Serverの一部です。これは、ユーザーが後でドキュメントエディターで開いたり、エクスポートするために、あるフォーマットから別のフォーマットにファイルを変換することを可能にします。

ドキュメント変換が必要な場合、主に2つの状況があります。

### ドキュメント編集に必要な中間変換

文書編集者が文書ファイルを正しく扱うためには、編集前にOffice Open XML形式に変換することをお勧めします：

* docx（テキスト文書用
* xlsx（スプレッドシート用
* pptxはプレゼンテーション用です。

参考図と以下の手順で、文書変換のプロセスを説明します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655664/0f9aa6dc-eef4-056a-9437-b7ef8d5602c8.png)

1. ユーザーは、コンピュータのハードディスク・ドライブから、ドキュメント・マネージャーにアップロードするファイルを選択します。
1. ドキュメントマネージャは選択されたファイルをドキュメントストレージサービスにアップロードします。
1. 文書保管サービスは、アップロードされたファイルをONLYOFFICE Document Server文書変換サービスに送り、[変換API](https://api.onlyoffice.com/editors/conversionapi)を使用してOffice Open XMLフォーマットに変換します。
1. 文書変換サービスは選択されたファイルをOffice Open XMLフォーマットに変換します。
1. 文書保管サービスは変換された文書ファイルをダウンロードします。

### ドキュメントのエクスポート

ユーザーがOffice Open XML形式とは異なる形式でファイルをダウンロードする必要がある場合、ONLYOFFICE Document Serverは、文書保管サービスに保存された文書ファイルをエクスポートする前に適切な形式に変換します。

参考図と以下の手順でドキュメントエクスポートのプロセスを説明します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655664/b87b760d-076b-dedb-2778-5a5b6dc328bf.png)

1. ユーザーはドキュメント・マネージャーでファイルを選択し、そのファイルがダウンロードされなければならないフォーマットを選択します。
1. ドキュメントマネージャーはこのユーザーアクションをドキュメントストレージサービスへのリクエストに変換します。
1. 文書保管サービスはアップロードされたファイルをONLYOFFICE Document Server文書変換サービスに送り、[変換API](https://api.onlyoffice.com/editors/conversionapi)を使って適切な形式に変換します。
1. 文書変換サービスは選択されたファイルを適切なフォーマットに変換します。
1. 変換が完了すると、文書保管サービスは変換されたファイルをダウンロードします。
1. 文書保管サービスは、変換が正常に実行されたことを文書マネージャに通知します。
1. 文書管理者は変換されたファイルをダウンロードします。
しゅっとしたseederを作ろう

## まずソースを見て
そう、継承つきのデータモデルのクラスがあるね

```python
from abc import ABC, abstractmethod

class BasePairDataModel(ABC):
    created_at = "YYYY-MM-DD 00:00:00"
    updated_at = "YYYY-MM-DD 00:00:00"
    @abstractmethod
    def return_value(self):
        pass

class AsIsPairDataModel(BasePairDataModel):
    """
    データ構造クラスにラッピングしてそのまま（as is）返す
    """
    def __init__(self, data_a: int, data_b: int):
        self.data_a = data_a
        self.data_b = data_b

    def return_value(self):
        return self.data_a + self.data_b

class TwicePairDataModel(BasePairDataModel):
    """
    データ構造クラスにラッピングして２倍して返す
    """
    def __init__(self, data_c: int, data_d: int):
        self.data_c = data_c
        self.data_d = data_d

    def return_value(self):
        return (self.data_c * 2) + (self.data_d * 2)
```

## つぎに実行パートのソースをみよう
```python
import json
from typing import Callable

def seeding(json_data: str, callback_func: Callable[[int], BasePairDataModel]):
    datas = json.loads(json_data)
    return_value = []
    for data in datas:
        return_value.append(callback_func(data))

    print([x.return_value() for x in return_value])

if __name__ == "__main__":
    data_list_for_as_is = json.dumps([
        {"data_a": 1, "data_b": 2},
        {"data_a": 10, "data_b": 20},
        {"data_a": 5, "data_b": 10},
        {"data_a": 100, "data_b": 200},
        {"data_a": 7, "data_b": 14},
        {"data_a": 50, "data_b": 60},
        {"data_a": 11, "data_b": 12},
        {"data_a": 25, "data_b": 30},
        {"data_a": 18, "data_b": 36},
        {"data_a": 8, "data_b": 16}
    ])
    data_list_for_twice = json.dumps([
        {"data_c": 1, "data_d": 2},
        {"data_c": 10, "data_d": 20},
        {"data_c": 5, "data_d": 10},
        {"data_c": 100, "data_d": 200},
        {"data_c": 7, "data_d": 14},
        {"data_c": 50, "data_d": 60},
        {"data_c": 11, "data_d": 12},
        {"data_c": 25, "data_d": 30},
        {"data_c": 18, "data_d": 36},
        {"data_c": 8, "data_d": 16}
    ])
    seeding(data_list_for_as_is, lambda data: AsIsPairDataModel(data_a=data["data_a"], data_b=data["data_b"]))
    seeding(data_list_for_twice, lambda data: TwicePairDataModel(data_c=data["data_c"], data_d=data["data_d"]))
```

## Console
```
[3, 30, 15, 300, 21, 110, 23, 55, 54, 24]
[6, 60, 30, 600, 42, 220, 46, 110, 108, 48]
```

## なにに注目してほしいのか
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94562/cb2bd9e0-b8f6-0266-7220-3dde7dd9e4c3.png)

2種類のデータモデルクラス（データのキーも全く異なる）を使い分けながら、`seeding` 関数自体は1つで済んでいるというところ！まるでバスクリンを溶かした風呂を手でかきまぜるがごとし（よくわからない例えシリーズ）

つまり、「機構」がひとつなのにまったく違うクラスを Callback として外から投げ込んで処理を定義できる

seederって普段はDjango使ってるからフレームワークに頼ってるんだけど、FastAPIってシーダーがないらしくてね。いろんなデータ源をデータモデルクラスにconvertできる。こういう処理はまさに Seeder といえる。いやー勉強になったわ
Dev Container の Copy Git Config が効かなくて困っている人へ

# 原因

Dockerfile の中などで `git config` をするなどして、コンテナの `~/.gitconfig` を先に作ってしまうと、VS Code が config をコピーしてくるのに失敗します。

# 対処方法

`git config` コマンドは devcontainer.json の `postStartCommand` に書けばよいです。
**注意: `postCreateCommand` にではないです。**

```json
{
  "postStartCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}"
}
```
変数と配列

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/2c32fd1d-a62a-59e2-6735-eca952a4cb39.png)
　コンピュータで扱うデータの個数は、数百万、数千万という規模であることが珍しくありません。これらを単純に並べて格納したのでは、さすがのコンピュータといえども高速な処理はできません。そこで、処理の方法に適した格納方法を考え、首尾よく扱えるようにする必要があります。データの格納方法のことを「データ構造」と言います。代表的なデータ構造として、配列、リスト、木、スタック、キュー、ハッシュがあります。

１：データ型
　データ型は、データの種類のことです。コンピュータでデータを扱うときには、データの種類（整数値、小数値、文字など）が重要になります。代表的なデータ型を下記にまとめます。

「代表的なデータ型」
①整数型：整数値
②小数型：小数値、実数値、浮動小数点
③文字型：１文字
④文字列型：文字列（０字以上の文字の連なり）
⑤論理型：真（true）/偽（false）のどちらかの値しか取らない

２：変数
　数学の変数と同じ概念のものです。データを格納できる箱と考えると良いです。変数には、データを１つだけ格納することができます。すでに、値が格納している変数に別の値を格納すると、元々の値を上書きします。
　また、変数にはデータ型を設定して、入れるデータの種類を制限することが一般的です。例えば、「整数型の変数X」には、整数値以外を格納することはできません。

３：レコード型の変数
　レコード型の変数（構造体変数とも言います）は、複数の項目を持つ「情報カード」のような変数です。レコード型の変数を扱う場合には、どのような項目があるのか、各項目のデータ型は何か、といった形式（フォーマット）を定義します。

４：配列
　配列はしきり付きの大きな箱です。書類棚や学校の靴箱といったイメージです。配列には、仕切りで区切られたマス目がたくさんあります。マス目のことを配列の要素と言います。１要素nに１つのデータを格納できます。要素は要素番号（添え字とも言います）で区別します。先頭要素を０番とする場合と、１番とする場合がありますから、注意する必要があります。

５：二次元配列
　二次元配列は、基盤の目のようにマス目を持つ配列です。行（縦方向）と列（横方向）があります。二次元配列の要素は、
　配列名[行番号, 列番号]
と指定します。
3分で watsonx.ai ！『今、使えるモデルをどうやって調べるの？』


![DALL·E 2023-10-17 20.18.55 - illustration_ A man and a woman stand next to a giant '3-minute hourglass'. Inside the hourglass, tiny 'watsonx.ai' logos and icons fall like sand. Th.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52151/0613e323-494f-bdc9-eff0-30d8a17bbd0e.png)

# はじめに

ついに始まりました『3分で watsonx.ai がわかるシリーズ』:bangbang:
小粒な記事ではありますが、watsonx.aiを使用する上で役にたつ内容をお届けいたします。

忙しいビジネス・ピーポーはなんせ時間がありません。となれば、**ビジネスのためのAI**を紹介する記事が**大切な時間を浪費していけない**というのは自然の摂理です。

ということで、カップラーメンができるまでの間に『わかる』 『試せる』 **3分で watsonx.ai ！** をよろしくお願いいたします。

:::note
この記事は **3分でわかる！試せる！** が第一の特徴です。
:::

# 最初のお題に何を選ぶの？

watsonx.ai は**用途に応じて適切なモデルの選択が可能**という特徴があります。
アップデートが激しい生成AI領域において、watsonx.aiも例外ではありません。

そこで、記念すべき第一弾の記事として、今、使えるモデルを調べる方法をご紹介したいと思います。

# お題

時々聞かれます「今、何のモデルが使えるの？」
現在使えるモデルを調べる方法として最初に思い浮かぶのは**マニュアルを調べる**方法です。
もちろん正攻法な方法ではありますが、 **「俺はマニュアルを調べるよりAPIを叩くぜ！」** というデベロッパーの方にも役にたつ方法をご紹介いたします。

# 「マニュアルで調べればいいのさ」流

はい、[watsonx.ai で使用可能なサポート対象のファウンデーション・モデル](https://dataplatform.cloud.ibm.com/docs/content/wsj/analyze-data/fm-models.html?audience=wdp&context=wx)をクリックしてください。

2023年10月17日現在のスクリーンショットを載せておきます。

**IBM独自モデル**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52151/a6e93d44-0297-048a-08cb-c734650acc40.png)
**Hugging Faceをソースとするモデル**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52151/7af66fb9-232b-6a98-64e3-beb3391d7918.png)

# 「APIを叩けば一発さ」流

こちらのコードを実行してください。

**下順準備**
```shell
$ pip install ibm_watson_machine_learning
```
**Python source code**
```python
from ibm_watson_machine_learning.foundation_models.utils.enums import ModelTypes
import json

print( json.dumps( ModelTypes._member_names_, indent=2 ) )
```
**実行結果**
```
[
  "FLAN_T5_XXL",
  "FLAN_UL2",
  "MT0_XXL",
  "GPT_NEOX",
  "MPT_7B_INSTRUCT2",
  "STARCODER",
  "LLAMA_2_70B_CHAT",
  "GRANITE_13B_INSTRUCT",
  "GRANITE_13B_CHAT"
]

```

:::note
出力がリスト(配列)なので、loopを使って全モデルを試してみる、なんて使い方もありますね:grinning:
:::
# 終わりに

どちらも同じ結果が得られます。お好きな方法で**どうぞ！**

![DALL·E 2023-10-17 22.09.39 - vector_ On an abstract digital background, large numbers representing '3 minutes' are displayed. Below it is the text 'watsonx.ai', surrounded by vari.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52151/8bfe1e83-b318-7d86-8aca-1d3c824f5c5c.png)


# 参考

## オンラインマニュアルから調べる方法

https://dataplatform.cloud.ibm.com/docs/content/wsj/analyze-data/fm-models.html?audience=wdp&context=wx

## APIを直接叩く方法

https://dataplatform.cloud.ibm.com/docs/content/wsj/analyze-data/fm-python-lib.html?audience=wdp&context=wx
Linux(Ubuntu)でタイムゾーンを変更する方法

## タイムゾーンの確認

```bash
$ date

Tue Oct 17 21:12:28 UTC 2023
```

`timedatectl` というコマンドでも確認できます。時刻関連の情報が複数行出てくるので `Time zone`でgrep。

```
$ timedatectl | grep 'Time zone'

               Time zone: UTC (UTC, +0000)
```

## 変更

この `timedatectl` コマンドに `set-timezone` があるのでそちらで指定できます。

```bash
sudo timedatectl set-timezone Asia/Tokyo
```

確認

```
$ date

Tue Oct 17 21:12:28 JST 2023

$ timedatectl | grep 'Time zone'
                 Time zone: Asia/Tokyo (JST, +0900)
```

念のため再起動してもそのままになっていることを確認しておきます。

## 実態について
タイムゾーン設定の実態は、`/etc/localtime` にあるファイル（シンボリックリンク）で決定されている様子。

```bash
ls -latr /etc/localtime

lrwxrwxrwx 1 root root 30 Oct 17 21:10 /etc/localtime -> /usr/share/zoneinfo/Asia/Tokyo
```

なので実際には `/usr/share/zoneinfo/` で指定したいタイムゾーンファイルを見つけてシンボリックリンクを貼る、という方法でもOKです。


参考:

https://qiita.com/azusanakano/items/b39bd22504313884a7c3


https://www.tecmint.com/check-linux-timezone/
[UNITY]uGUIのImageにアタッチしたスクリプトでOnMouseDragイベントが動かない

(UNITY version 2020.3.25f1 Personal)

## 結論(暫定)
OnMouseDragイベントはuGUIのCanvas内に配置するImageでは使えないっぽいので、
IDragHandlerとOnDragを使用する（これにはBox Collider 2DとRigidbody 2Dは不要）

## 試したこと
ドラッグしたいオブジェクトにBox Collider 2Dのコンポーネントを追加しサイズ設定、
Rigidbody 2Dのコンポーネントを追加しボディタイプをキネマティック、
完全なキネマティックコンタクトの使用にチェックを入れた
下記のログを吐くだけのスクリプトをオブジェクトにアタッチして実行してみたが動かず
MainCameraのタグ名がMainCameraになっていることや、EventSystemがあること、
レイキャストターゲットにチェックが入っていることも確認したがダメ
```
using UnityEngine;
using System.Collections;

public class DragTest : MonoBehaviour {
    void OnMouseDrag() {
        Debug.Log("MouseDrag");
    }
}
```
ドラッグしたいオブジェクトがCanvas Groupだったりプレハブだったり、
別のオブジェクトの下に配置していたり、
Instantiateしたものだったりする部分のやり方が悪いのかと思ったが、
Canvasにテスト用にImageオブジェクトを配置して同様にテストしたら、
それすらも動かなかった
まず一番シンプルな状態で試すべきでしたね…

## ではどうするか
パフォーマンス的によく動かすならImageじゃなくてSpriteが良いのかなと思ったが、
アクションが重要なゲームを作っているわけでもないので
ImageのままIDragHandlerとOnDragを使用で実装することにした
canvas groupを使用しているのでそんなにパフォーマンス落ちないんじゃないかな…
と思っているけど、あまりにひどかったら修正します

### 参考にさせて頂いた記事
https://dipross.co.jp/eng/2023/02/unity%E3%81%A7ui%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B%E4%B8%8A%E3%81%A7image%E3%81%A8sprite%E3%81%AE%E9%81%95%E3%81%84.html

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

他
マスタデータ取得API

仕事で複数のマスタテーブルをAPI取得することがあり苦戦したため備忘録として

新米エンジニアです
間違えていたり他にいいやり方があれば優しく教えてください

## 前提
すでにmigrationでテーブルを作成したのちseederでデーターを作成されている状態

## 全体の流れ
routes/api.php→controller→Service→resource→Model

## 1.Resource
**resourceとは**
モデルやモデルコレクションを簡単にJSONデータへと変換してくれる

artisanコマンドでresourceファイルを作成する
```
$ php artisan make:resource TestResource
```

App\Http\Resources\TestResourceが生成される
toArrayの中身を書き換える
※今回は複数のテーブルをAPI取得しましたが２パターンに分かれていたため2つ作成しています

```
<?php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class TwoResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @return array<string, mixed>
     */
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name
        ];
    }
}
```
```
<?php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class ThreeResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @return array<string, mixed>
     */
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email
        ];
    }
}
```


## 2.Service

serviceでResourceを使用してデータを取得する

**::collection**は
・Laravelのelquentリソースクラス内で定義されたメソッド
・モデルのコレクションをリソースのコレクションに変換するときにつかう
```
<?php

namespace App\Services;
use App\Http\Resources\TwoResource;
use App\Http\Resources\ThreeResource;
use App\Models\A;
use App\Models\B;
use App\Models\C;
use App\Models\D;


class TestService
{
    public function createData()
    {

        return [
            'a_table' => TwoResource::collection(A::all()),
            'b_table' => ThreeResource::collection(B::all()),
            'c_table' => TwoResource::collection(C::all()),
            'd_table' => TwoResource::collection(D::all()),
            ];
    }
```

## 3.Controller

**__constructとは**
クラスからインスタンスを生成する際（new を行う際）に最初に実行される関数

```
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Services\TestService;



class TestController extends Controller
{

    private $testService;

    public function __construct(TestService $testService)
    {
        $this->testService = $testService;
    }

    public function getMasterData()
    {
        $jsonData = $this->testService->createData();
       
        return $this->createResponse($jsonData);
    }
   
    private function createResponse(mixed $data): array
    {    
        return ['data' => $data,
                'error' => [
                    'message' => '',
                ]
               ];
    }
   
}

```

postmanで確認したところJSON形式で取得できました。
FlutterのWidgetの基礎part2

# はじめに
前回に引き続きFlutterの基本的なWidgetについて書いていきます。

## Container Widget
Container Widgetは、画面上にボックス空間を確保するWidgetです。
用途は文字通りコンテナで、HTMLのdiv要素のように領域確保したり他のWidgetを入れたりします。
Container Widgetの主要プロパティは以下のものがあります。
|プロパティ|説明|
|:--|:--|
|width|領域の横幅を設定|
|height|領域の縦幅を指定|
|color|領域の色を指定|
|margin|領域のマージン幅を指定|
|padding|領域のパディング幅を指定|
|transform|領域を回転|
|child|子Widgetを設定|
|alignment|子Widgetの位置を指定|

```dart:青色の正方形を描画するサンプル コード
Container(
    color: Colors.blue,
    width: 100.0,
    height: 100.0,
 )
```

## Stateless Widget
Stateless Widgetは、状態(state)を持たないWidgetになります。
画面上の値を変更しようとしても画面は再描画されません。
```dart:サンプル コード
import 'package:flutter/material.dart';
import 'dart:math';

void main() => runApp(StatelessDemo());

class StatelessDemo extends StatelessWidget {
  int checkNumber = 0;
  Random randomNumber = new Random();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('数字は　' + (chkNumber == 1 ? '1' : '0')),
        ),
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.numbers_rounded),
          onPressed: () {
            chkNumber = rdmNumber.nextInt(2);
            print(chkNumber);
          },
        ),
      ),
    );
  }
}
```
StatelessWidgetクラスを継承したState Demoクラスを作成します。
継承することで、Stateless Widgetのメソッドやフィールドにアクセスできます。
オーバーライドする事で、クラス継承時に親クラスのメソッドと同じ名前のメソッドを子クラスで定義し直し、親クラスのメソッドではなく子クラスのメソッドが呼ばれます。

## Stateful Widget
Stateful Widgetは、状態(state)を持つWidgetです。
画面上の値を変更したい場合に画面を再描画できます。
```dart:サンプル コード
import 'package:flutter/material.dart';
import 'dart:math';

void main() => runApp(MyHomePage());

class MyHomePage extends StatefulWidget {
  @override
  State<MyHomePage> createState() => _StatefulDemo();
}

class _StatefulDemo extends State<MyHomePage> {
  int chkNumber = 0;
  Random rdmNumber = new Random();

  @override
  void initState() {
    print("初期処理");
     super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('数字は　' + (chkNumber == 1 ? '1' : '0')),
        ),
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.attach_money),
          onPressed: () {
            setState(() {
              chkNumber = rdmNumber.nextInt(2);
            });
            print(chkNumber);
          },
        ),
      ),
    );
  }
}
```

## まとめ
今回は、Container Widget、Stateless Widget、Stateful Widgetについて簡単にまとめてみました。
まだ理解しきれていない部分も多いので間違っている箇所あればぜひコメントいただけると幸いです。
最後までご覧いただきありがとうございました！
Pythonのurllib.request（urlopen・urlretrieve）でAPIを利用する方法（備忘録）

**※本記事はbing chatを使用して生成しています。**
**※私が最近urllib.requestを使用する機会があり、汎用性が高そうだったため、備忘録として投稿します。**

PythonでWeb APIを利用するときには、標準ライブラリのurllib.requestモジュールを使うことができます。このモジュールには、urlopenとurlretrieveという2つの関数があります。それぞれの使い方と注意点について説明します。

## urlopenの使い方
urlopenは、URLを指定してWebサーバーにリクエストを送り、レスポンスを受け取る関数です。レスポンスは、HTTPResponseオブジェクトとして返されます。HTTPResponseオブジェクトは、ファイルオブジェクトと同じように扱うことができます。例えば、readメソッドでレスポンスの内容を読み込んだり、closeメソッドで接続を閉じたりできます。

urlopenの基本的な使い方は以下のようになります。

```
import urllib.request

url = "https://example.com/api"
response = urllib.request.urlopen(url)
data = response.read()
response.close()

print(data)
```
urlには、Web APIのエンドポイントを指定します。エンドポイントとは、Web APIの機能やリソースにアクセスするためのURLのことです。例えば、天気予報のAPIなら、"https://weather.example.com/api/forecast" のようなURLになるでしょう。

responseには、HTTPResponseオブジェクトが返されます。このオブジェクトから、レスポンスの内容やステータスコードなどの情報を取得することができます。レスポンスの内容は、readメソッドでバイト列として読み込むことができます。バイト列とは、0から255までの整数の並びのことです。バイト列は、decodeメソッドで文字列に変換することができます。例えば、decode("utf-8")とすると、UTF-8という文字コードでバイト列を文字列に変換します。

response.close()は、接続を閉じるためのメソッドです。接続を閉じることで、リソースを解放することができます。接続を閉じるのを忘れると、メモリリークやパフォーマンス低下などの問題が発生する可能性があります。接続を自動的に閉じるためには、with文を使うことがおすすめです。
```
with urllib.request.urlopen(url) as response:
    data = response.read()

print(data)
```
with文は、インデントされたブロック内でオブジェクトを使用した後に自動的にcloseメソッドを呼び出す構文です。with文を使うことで、コードがシンプルになりますし、接続を閉じるのを忘れる心配もありません。

urlopenには、第二引数や第三引数などもあります。第二引数には、POSTやPUTなどのメソッドで送信するデータを指定することができます。データはバイト列かイテラブルオブジェクト（リストやタプルなど）である必要があります。第三引数には、タイムアウト（秒）を指定することができます。タイムアウトとは、レスポンスが返ってくるまで待つ最大時間のことです。タイムアウトを超えた場合は、URLErrorという例外が発生します。

## urlretrieveの使い方
urlretrieveは、URLを指定してWebサーバーにリクエストを送り、レスポンスの内容をファイルに保存する関数です。ファイルのパスは、第二引数で指定することができます。第二引数を省略した場合は、一時ファイルに保存されます。一時ファイルとは、プログラムが終了すると自動的に削除されるファイルのことです。

urlretrieveの基本的な使い方は以下のようになります。
```
import urllib.request

url = "https://example.com/api"
filename = "data.json"
urllib.request.urlretrieve(url, filename)

print("Saved to", filename)
```
urlには、Web APIのエンドポイントを指定します。filenameには、レスポンスの内容を保存するファイルのパスを指定します。ファイルのパスとは、ファイルの場所や名前を表す文字列のことです。例えば、"C:\\Users\\user\\Desktop\\data.json"や"/home/user/Desktop/data.json"のような文字列です。

urlretrieveは、レスポンスの内容をファイルに保存するだけでなく、HTTPResponseオブジェクトも返します。このオブジェクトから、レスポンスの情報を取得することができます。例えば、getheaderメソッドでレスポンスヘッダーの値を取得したり、getcodeメソッドでステータスコードを取得したりできます。
```
response = urllib.request.urlretrieve(url, filename)
print(response[0]) # ファイルのパス
print(response[1]) # HTTPResponseオブジェクト
print(response[1].getheader("Content-Type")) # レスポンスヘッダーの値
print(response[1].getcode()) # ステータスコード
```
urlretrieveには、第三引数や第四引数などもあります。第三引数には、ダウンロードの進捗状況を表示するための関数を指定することができます。この関数は、4つの引数（ブロック番号、ブロックサイズ、合計サイズ、URL）を受け取ります。第四引数には、リクエストヘッダーを指定することができます。リクエストヘッダーとは、Webサーバーに送信する追加情報のことです。例えば、User-AgentやAcceptなどのヘッダーがあります。

## まとめ
Pythonのurllib.requestモジュールには、urlopenとurlretrieveという2つの関数があります。urlopenは、URLを指定してWebサーバーにリクエストを送り、レスポンスを受け取る関数です。urlretrieveは、URLを指定してWebサーバーにリクエストを送り、レスポンスの内容をファイルに保存する関数です。これらの関数を使うことで、Web APIを利用することができます。
ArrayBufferって何者？

### はじめに　
突如出現し、？？？となったものです。

<font color=red>__ArrayBuffer__　バイナリー(0,1のみの2進数で表現される)データを格納するためのオブジェクト</font>

バイナリーデータを扱う際に登場するようです。
メモリ領域を確保してデータを操作をするために使用するようですが、
私はあまり機会がなかったので、触り部分のみですが調べてみた記録です

### まずArrayBuffer()でメモリ空間を確保する
__ArrayBuffer（引数）__
引数に、"確保したいメモリのバイト量"の数値を入れる
　→　インスタンス化と同時に、メモリ空間が指定したバイト数分確保される

```javascript:ArrayBuffer作成
const buf  = new ArrayBuffer(100);
// 100バイトのメモリ空間を確保したArrayBufferオブジェクトが作成される
``` 
### ArrayBufferのデータ操作をするには
主に2つの方法でやるらしい。
__・TypedArray__
__・DataView__

今回はTypedArrayの方法についてちょこっと。
　__TypedArrray:配列風のビュー__
下記のように作ることができる
```javascript:ArrayBufferの操作
const TypedArrayView = new Uint8Array(buf);  
// 先のコードで作成したArrayBufferオブジェクトのメモリ空間へアクセスするための型付き配列を作る
``` 
　__Uint8Array(buf)__ 
バイナリーデータが入った　ArrayBufferオブジェクトを
8bit(符号なし)でアクセスし、整数値の配列に変換
　<font color=gray>(8桁ずつ整数値に変換するイメージですかね。)<font/>



__buf__ は __ArrayBuffer(100)__ で __"100バイトのArrayBufferを作成したもの"__ なので
1byte　=　8bitということをふまえると
　Unit8Array  ・・・100個の整数値
　Unit16Array　　・・・５０個の整数値
　Unit32Array ・・・25個の整数値
の配列を作成できるようです

<font color=gray>※ただしInt64Arrayをしようとすると
 ArrayBufferを8バイトずつ変換しようとするので
 8で割り切れるバイト数じゃないと(今回は100なので)エラーが出るみたい<font/>

__データへのアクセス__
TypeｄArrayView[0] 　とすれば　１つ目の整数値に参照
TypeｄArrayView[1]　とすれば　２つ目の整数値に参照
TypeｄArrayView[4]　とすれば　5つ目の整数値に参照
できるそうです。

__データの書き換え__
仮に1つ目の数字[0]が "5"であったとき
TypeｄArrayView[０]=10　として　書き換えると、
元のArrayBufferデータ(buf)も書き換えられる。
<font color=gray>（伝わるかな)<font/>


 __▪️(参考)型付き配列のサブクラス詳細__ 
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array


### とりあえず
かなり浅い調査ですみません・・・

メモリ領域を確保してデータを操作する、という行為はごく一般的とのことですが、
私にとっては初めてだったので考え方からちょっと苦戦しました。

具体的な操作については徐々に深掘りしていこうと思います。
MATLABでグラフの色や太さを簡潔に設定する方法

# 概要
- MATLABでグラフの色や太さを設定する時，`"Color", "r"`や`"LineWidth", 1.0`などのパラメータを`plot`に与えるが，色や太さを細かく設定しようとすると長くなりがちである．
- さらに，色や太さの設定をコード内で使いまわすことができない．
- cell配列を使えば，簡潔に表記できる上に再利用も行いやすいため，本記事ではその方法を紹介する．

# サンプルコード
```matlab
style1 = {'Color',"r","LineWidth",3.0};
style2 = {'Color',"g","LineWidth",2.0};
style3 = {'Color',"b","LineWidth",1.0};

x = 0:pi/100:2*pi;
y1 = sin(x);
y2 = 2*sin(x);
y3 = 3*sin(x);

plot(x,y1,style1{:});
hold on
plot(x,y2,style2{:});
hold on
plot(x,y3,style3{:});
```
- `style1`や`style2`のように，cell配列内に色や太さを指定するためのパラメータをいつも通り書く．
- `plot`に渡す際は，`style1{:}`や`style2{:}`のように表記する．
- cell配列は`cell{:}`とすることで，配列の各要素を展開して関数に渡すことができる．
就職してから最短で出社できなくなった話

## 目次
-始めに
-出社できなくなった経緯
-診断結果
-倒れたあとの過ごし方（記憶）
-現在の状況

## 始めに
こちらの記事は私個人のただの記録であり、誰かの役に立つことではありませんが、全く予想もしていなかったアクシデントということで多めに見て頂ければ幸いです。
（私個人は現状[高次脳機能障害](http://www.rehab.go.jp/brain_fukyu/rikai/)との診断を受けていますので意味の分からないことを書いていたり、誤字等があれば教えて頂けると嬉しいです。記憶喪失もあるのでマークダウンなど上手く使えていないかもしれません。）
何かおかしな記述をしていたら教えて頂けると助かります。

## 出社できなくなった経緯
私は2021年11月にある企業に入社し、とても楽しくエンジニアとしての道を歩みはじめたところでした。
研修期間中のある日、休憩時間に外出していたところ、急に倒れ心肺停止となりそのまま病院へ運ばれたようです。原因としては[WPW症候群](http://www.hcc.keio.ac.jp/ja/health/2017/05/wpw-wolff-parkinson-white-syndrome.html)という心臓の病気を持っていたらしく、不意に発作が起こり倒れたようです。
倒れた後、心肺停止により頭に血が回らず脳の損傷を受けた（高次脳機能障害）、のが現在の私です。
まぁ全くWPW症候群とは思っていなかったですし、確か一度20歳すぎの心電図で要検査となったことはありますが、その時も調べて（ホルター心電図というもので調べました）結果、問題ないと言われていたはずなんですが。。
その時以外心電図で引っかかったことがなかったので心臓に病気を持ってるということは考えてもいませんでした。
(こんな確率の低い病に侵されるなら同率の宝くじにでも当たりたかったですね笑)

## 診断結果
病院で様々調べて頂いた結果がWPW症候群だったわけですが、それだけではなくいろいろ付随する病気等がありましたので一覧にしておきます。（記憶の範囲で）
・WPW症候群
・QT延長症候群
高次脳機能障害となったことで
・記憶障害
・注意障害
・失語症
付随して
・指先の痺れ（数本）
・味覚障害（塩分のみ）
現状（倒れてから2年）、味覚障害は少しよくなったような、失語症はこれをきちんと伝わる文章でかけていれば大丈夫、心臓にはICDというペースメーカーに似た機械（かつAEDのような電気ショック機能あり）を入れたのでまた心臓が止まっても対処できます。
心臓には[カテーテルアブレーション](https://www.hmedc.or.jp/department/cardiovascular-medicine/abl/)というものを行い不要な神経を潰したので不安はない、はず。
ただICDを入れたので約10年に一度、手術をして器具の入れ替えを行わなければいけません。

幸いだったことは高次脳機能障害となったものの、性格が変わるといった社会的行動障害といったものにはならなかったこと、高次脳機能障害は星野源さん等有名人でもなった方がいるということを知ったことは精神的によかったです。あとは仕事を前述のとおり変えたばかりだったので、環境が新しく、古いタイプの考え方の人がいないというのは大いに助けられました。

## 倒れたあとの過ごし方（記憶）
入院中は記憶が途切れ途切れであまり覚えてはいませんが、手術をして目覚めた?記憶、夢の中でスマホをいじっていて気づいたらアプリの場所が変わっていて「?????!」で目覚めた記憶（恐らくこの時に意識が回復した）、検査、治療が終わり経過観察はリハビリ施設で行われました。
多分この頃には普通にスマホを使っていたので妻とも連絡を取り、（コロナ禍だったので面談が制限されていたため）入院中には現在の服が残り何枚といったことを連絡していた記憶がうっすらあります。
退院してからは施設に通い障害者マーク（ヘルプマーク）も一時期つけましたが、「私が配慮してほしい事と（一般の人が考える）つけていることで配慮して上げたほうがいい事」に差があったのでつけることをやめました。
（誰も悪くはないのですが、【スマホを胸の付近に近づけないで】は伝わらず、席を譲って頂くなど、有難いけど正直どうでもいい配慮が多かった。）

## 現在の状況
現在はリハビリ施設に通っていますが、多くの中途障害者とは違いまだまだ働かなくてはならないので（施設に通う方の私以外は50歳以上）、復職に向けた施設への移行を検討中です。
施設も東京には多くあり、幸いプログラミング等を専門とするところもありました。
ただ、、、こちらの条件（通える場所、プログラミング、かつRubyを教えている）を満たすものは少なく、プログラミングは学べるものの言語はPHPやフロントエンドのものが多い印象でした。（→PHPも条件にあった開発には使うと思いますが、Rubyを使わない理由が分からない。というか多分更新してない＝古いものをわざわざ教わる気はない＝条件に合わない）
中途障害は少ないですし、その他の利用者は精神障害者。となるとそこまでの専門性を求められないことがそういった、"やっているようでやっていない施設"が増える原因なのだろうと思います。

## これからの見通し
上には書ききれなかったので省いた部分が「職場はどうなった？」という部分ですが、有難いことにSlackでの連絡は日常的に続け、大いに励ましてもらいましたが、休職期間が終わる１年が近づいても体力面、スキルから大いに不安があったので一度辞めさせてもらいました。（辞めさせられたでは全くありません。私の意志です。）
職場には入ったばかりで申し訳ないという気持ちと、同期の友人やお世話になった先輩方とはとても名残惜しかったのですが、私のいろいろ中途半端な記憶では役に立たないと理解していたので一度引き、万全……になれるかはまだわかりませんが、万全になったら迷惑をかけてしまった会社に戻りたいと思っています。
私的サーバー構築日誌：オレオレ認証局が認証する証明書

# 能書き

[私的サーバー構築日誌：仕切り直し](https://qiita.com/katz_engineer/items/1f21de2bd9072c260ae6)からの自宅サーバー構築、[前回](https://qiita.com/katz_engineer/items/ff07466662131b72c14c)の続きです。

[証明書の話は以前もやりまして](https://qiita.com/katz_engineer/items/1bb165f5f59c43c0ab6a)、その焼き直しですが。そのまま再掲でも詰まらないので、関連コマンドをDockerコンテナの中に封じ込めます。その辺は[前回同様](https://qiita.com/katz_engineer/items/ff07466662131b72c14c)ですな。

# 目標

- 証明書（サーバー鍵）を作成します。
- easy-rsaを使用して構築したオレオレ認証局で、証明書を認証します。
- [前回](https://qiita.com/katz_engineer/items/ff07466662131b72c14c)構築したDockerコンテナ内で操作します。

# 参考文献

- [easy-rsaで簡単に自宅CA構築+自己証明書発行 - paloma blog](https://paloma69.hatenablog.com/entry/2021/06/26/181027)
- [easy-rsaでプライベートCA(認証局)を作ってオレオレ証明書ではないローカル用TLS証明書の管理をする](https://r-o-head.tk/post/private-ca-with-easy-rsa/)
- [【AWS Client VPN】OpenVPN easy-rsaでサーバ証明書の有効期限を100年にする - (技)DENET 技術ブログ](https://blog.denet.co.jp/easy-rsa_validity/)

## 認証局のDockerコンテナ

[前回](https://qiita.com/katz_engineer/items/ff07466662131b72c14c)構築した通りなら、操作ユーザーは`cert`になります。

```console
CA_USER=cert
```

```console
sudo su $CA_USER
```

Dockerコンテナを起動し、コンテナ内に入ります。

```console
cd
docker compose up -d
docker compose exec -e CA_USER=$USER ca /bin/bash
```

```console:コンテナ内
su $CA_USER
```

[前回](https://qiita.com/katz_engineer/items/ff07466662131b72c14c)構築した通りなら、認証局の名前は`demoCA`になります。

```console:コンテナ内
CA_NAME=demoCA
```

認証局のディレクトリに移動します。

```console:コンテナ内
cd /mnt/$CA_NAME
```

# サーバー鍵

## 有効期限

これから作る証明書の有効期限を100年にしておきます。忘れた頃に期限が切れるとパニクりますので。

[前回](https://qiita.com/katz_engineer/items/ff07466662131b72c14c)の続きでしたら、CAの有効期限は設定しましたが、証明書の有効期限は設定していません。

```console:コンテナ内
grep EASYRSA_CERT_EXPIRE pki/vars
```

この場合は下記のコマンドを実行します。```EASYRSA_CERT_EXPIRE```の設定が済んでいたら下記は不要です。

期間はお好みで。今回は100年にしました。

```console:コンテナ内
echo 'set_var EASYRSA_CERT_EXPIRE "36524"' >>pki/vars
```

## 鍵生成

EasyRSA の新しいバージョンでは、秘密鍵やCSR（Certificate Signing Request、証明書署名要求）を作らなくてよいらしい。コマンド一発で全部やってくれちゃいます。

サーバー名が```example.home```の場合、下記コマンドを実行します。
途中で認証局 demoCA のパスフレーズを要求されますので、それを入力します。

```console:コンテナ内
SV_NAME=example.home
```

```console:コンテナ内
./easyrsa build-server-full $SV_NAME nopass
```

生成された各ファイルは、pkiディレクトリ内の各サブディレクトリに格納されます。

- 秘密鍵: ```pki/private```
- 証明書要求: ```pki/reqs```
- 証明書: ```pki/issued```

## 鍵確認

生成した鍵を確認しましょう。

```console:コンテナ内
openssl x509 -text -in pki/issued/$SV_NAME.crt -text | grep -E "Issuer:|Subject:"
openssl x509 -dates -noout -in pki/issued/$SV_NAME.crt
```

今回はこんな結果になる筈です。有効期限は100年後になっています。

```console:コンテナ内
$ openssl x509 -text -in pki/issued/$SV_NAME.crt -text | grep -E "Issuer:|Subject:"
        Issuer: CN = demoCA
        Subject: CN = example.home
$ openssl x509 -dates -noout -in pki/issued/$SV_NAME.crt
notBefore=Oct 17 09:07:27 2023 GMT
notAfter=Oct 17 09:07:27 2123 GMT
```

## コンテナ停止

鍵を生成できたら、Dockerコンテナは停止しておきましょう。

```console:コンテナ内
exit
exit
```

```console:ホスト側
docker compose down
```

# 仕舞い

鍵を作って署名するのは簡単でした。

本当は、この鍵を仕込んで何かのサーバーが暗号化されるのを確認したかったのですが、それはまた今度。サーバーを何も立てていないので。うーん残念。
Read the Docs がビルドしてくれなくなったときの対処法 (2023/10/16-) (The configuration key "build.os" is required ...)

Python パッケージのドキュメンテーションに Read the Docs を利用している方であって、2023年10月に「何もしていないのに Read the Docs が以下のエラーを吐いてドキュメントをビルドしてくれなくなった」という方向けです。
```
The configuration key "build.os" is required to build your documentation. 
Read more at https://docs.readthedocs.io/en/stable/config-file/v2.html#build-os
```
エラーメッセージにしたがえばよいですが、素直にしたがっていくと修正が3回発生した (私は) のでメモです。

### 参考文献

- [Use build.os instead of build.image on your configuration file &#8212; Read the Docs Blog](https://blog.readthedocs.com/use-build-os-config/)
  - 1回目のビルドエラーのメッセージで検索するとヒットするページで、なるほど 2023/10/16 以降には設定ファイルに `build.os` キーがなければならないとあります。
- [Sphinx Read-The-Docs Theme recognised but not &quot;found&quot; - Stack Overflow](https://stackoverflow.com/questions/69206164/sphinx-read-the-docs-theme-recognised-but-not-found)
  - 3回目のビルドエラーのメッセージで検索するとヒットするページで、`pip install sphinx-rtd-theme` せよとあります (これまでは明示的に設定ファイルでインストールを指示する必要はありませんでした)。
- [Configuration file v2 (.readthedocs.yaml) &mdash; Read the Docs user documentation](https://docs.readthedocs.io/en/stable/config-file/v2.html)
  - .readthedocs.yaml のドキュメントで、各キーの意味や `python.version` は廃止される旨が書いてあります。

### 対処法

以下の 3 点を対応したらビルドできました (私は)。

- .readthedocs.yaml の `build.os` キーにドキュメントをビルドする OS を指定します。
  - `"ubuntu-20.04"` か `"ubuntu-22.04"` を指定するようです。
- .readthedocs.yaml に `build.tools.python` キーに Python のバージョンを指定すると共に、廃止された `python.version` キーを削除します。
- conf.py で `html_theme = 'sphinx_rtd_theme'` としている場合、`sphinx-rtd-theme` の明示的なインストールが必要になったので、pyproject.toml の `pyproject.optional-dependencies` に適当なキー名 (下図では `docs`) で依存性を追加し、.readthedocs.yaml でそのキーを指定します。
  - pyproject.toml でなく setup.py などを利用している方は `extras_require` になると思います ([Optional dependencies](https://setuptools.pypa.io/en/latest/userguide/dependency_management.html#optional-dependencies))

私の場合のファイル差分は以下です。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177688/de6b2ea5-f5f7-145e-f208-0bbf3a6a8499.png)

### 補足: エラーメッセージ

約3ヶ月ぶりにパッケージをメンテナンスしたらドキュメントがビルドされませんでした。 `build.os` キーがないといわれていました (1回目)。
```
The configuration key "build.os" is required to build your documentation. 
Read more at https://docs.readthedocs.io/en/stable/config-file/v2.html#build-os
```
なので[このページ](https://blog.readthedocs.com/use-build-os-config/)を参考に `build` 以下を設定しました。すると `python.version` キーは無効だといわれました (2回目)。
```
Problem in your project's configuration. 
Invalid configuration option "python.version": Make sure the key name is correct.
```
なので `python.version` キーを削除しました。すると `'sphinx_rtd_theme'` はないといわれました (3回目)。
```
We encountered a problem with a command while building your project. 
To resolve this error, double check your project configuration and 
installed dependencies are correct and have not changed recently.

Theme error:
no theme named 'sphinx_rtd_theme' found (missing theme.conf?)
```
なので `pyproject.optional-dependencies` で対応したところ、パッケージのドキュメントがビルドできました (以下)。  
https://cookies-utilities.readthedocs.io/en/latest/
Rsyslogでタイムスタンプをメッセージとして送信すると一部消える

# こんなメッセージを送る

```jsx
2023-10-05 10:35:15 メッセージ
```

# メッセージ内容だけをログに保存させる

```jsx:50-default.conf
$template CustomTemplate,"%msg%\n"
action(type="omfile" file="/var/log/message.log" template="CustomTemplate")
```

# しかしログに年月日と時間が保存されてない！！

実際に保存されるログ

```jsx
35:15 メッセージ
```

# 原因

年月日がホスト名、時間がログのタグ(`systemd[1]:`など)として扱われるため

# 対処方法

メッセージテンプレートでホスト名とログのタグを組み込むことで年月日と時間が保存されるようになる

```jsx
# %年月日% %時%%分:秒 メッセージ%\n
$template CustomTemplate,"%hostname% %syslogtag%%msg%\n"
action(type="omfile" file="/var/log/message.log" template="CustomTemplate")
```