OmniAICreator/Qiita-1.07M huggingface dataset:
pythonでCの関数だけではなく、構造体も参照する方法



pythonから、C言語（シェアードライブラリ）の関数を呼び出す例はありますが、同じようにデータを取り出すやり方です。
C言語のdata構造体をアドレスで参照している場合、pythonでは、下記の様にする必要がありました。

C言語側のdata構造体を指すdata_table_ptrからpython側でdataインスタンスを生成します。

```c:C言語
struct data_table {
	int				attr;
	char			*data;
};
const struct data_table data = {
	.attr		= 100,
	.data		= "文字列",
};
const struct data_table *data_table_ptr = &data;   ･･･C①
  :
void functionA(const struct data_table *ptr)   ･･･C③
{
	attr = ptr->attr;   ･･･C②
      :
}
  :
   functionA(data_table_ptr);
  :
```


```python:python
# dllの読み込み処理は省略
from ctypes import *
class data_table(Structure):
    _fields_ = [("attr", c_int),
                ("sata", c_char_p]
  :
data = cast(dll.data_table_ptr,POINTER(POINTER(data_table))).contents.contents   ･･･python①
  :
attr = data.attr   ･･･python②
  :
  :
dll.functionA.restype = None
dll.functionA.argtypes = [POINTER(data_table)]   ･･･python③
def functionA(data):
    dll.functionA(data)
  :
functionA(data)
```
C①：c言語側のdata_table_ptrは、data構造体のアドレス（ポインタ）を入れるエリアであり、
　　そのエリアが指す先のアドレス（ポインタ）にdata構造体の実態があります。

　　data構造体を直接参照するのであれば、
　　data = cast(dll.data,POINTER(data_table)).contents
　　です。　

　　data_table_ptr経由では、dataをもう一度ポインタ参照していることになります。
　　２度ポインター参照しているので、python側では、これをそのままコーディングします。

python①：python側では、data_table_ptrをPOINTER(POINTER(data_table))にキャストした後に、
　　.contents.contentsでdataインスタンスを取り出すことが出来ます。
　　
python②：dataインスタンスが取り出せたので、python側では、data.attrでデータが参照できます。

python③：c言語側の関数(functionA)を呼び出す場合、アドレス（ポインタ）に変換する為、
　　functionA.argtypes = [POINTER(data_table)]
　　と指定することにより、dataのアドレスが、C言語側に渡ります。
C③：呼び出されたfunctionA関数ではポインタ参照でデータを参照できます。

これで、C言語、pythonのどちらからでも、データも関数も使用できるようになりました。
【ASP.NET Core】セッションに保存できる文字列長の限界を検証してみた

## 課題
ASP.NET Coreで利用できるセッション（Microsoft.AspNetCore.Http.HttpContext.Session）にはどのくらいの長さの文字列を格納できるのか？

サイズオーバーを起こすと後々大変なので、検証してみることにしました。

## 結論

1,000万字の1バイト文字（約10GB）の文字でも収めることができました。

但し、セッションはマシンメモリを消耗しますので、これほどのサイズを格納する前に設計の見直しが必要でしょう。

とはいえ、多少長い程度の情報であれば問題なく格納できることが分かりました。

## （参考）検証に使用した環境とコード

環境は.NET6.0、Docker+Linuxでプロジェクトを作成しています。

セッションに格納した後、リダイレクト先で表示します。

### HomeController.cs
```C#
public IActionResult Index() {

    var sb = new System.Text.StringBuilder();
    for (int i = 0; i < 10000000; i++) {
        sb.Append('a');
    }

    //10,000,000文字の変数をセッションに保存
    HttpContext.Session.SetString("hoge", sb.ToString());

    return RedirectToAction("Result");
}

public IActionResult Result() {
    //10,000,000文字の変数をセッションから取り出して表示
    ViewBag.Result = HttpContext.Session.GetString("hoge");

    return View();
}
```

### Razor（Result.cshtml）
```C#
<p>
    @ViewBag.Result
</p>
```
React で 19路盤の碁盤 を作ってみた

# 19路盤の碁盤

完成品 ↓

https://igo-goban.de.r.appspot.com

https://github.com/YmBIgo/goban

# 石を取る

https://github.com/YmBIgo/goban/blob/master/src/components/Goban.tsx#L514

石をブロックとして数えてから、囲われているかを確認しました。
useState だと 描画絡みで変数保持するのが難しいと思ったので、useRef で内部変数を保持しました。
また、石のブロックを取得するのに何も考えないとループしてしまうので、探索時には石を戻らないのと、２次元情報を保持して同一ベクトルが出てきた場合は処理を飛ばす（石探索が例えば「下→右→上→左」の順番になるとループが生じてしまう）のような処理を実装した。

https://github.com/YmBIgo/goban/blob/5893dbe407ba9495167073ea393f0a179e60cf56/src/components/Goban.tsx#L313

数えられたブロックで、forEach 文を回すところから始まっています。
全てのブロックで、ブロックの周りが違う色の石で囲われているかを確認して、石を取っています。

# コウ

https://github.com/YmBIgo/goban/blob/5893dbe407ba9495167073ea393f0a179e60cf56/src/components/Goban.tsx#L408 

# 自殺手

https://github.com/YmBIgo/goban/blob/5893dbe407ba9495167073ea393f0a179e60cf56/src/components/Goban.tsx#L118

ただ自殺手か判定するのみならず、取れる石があった場合は自殺手の判定を止める必要があって、苦労しました（155行目からや245行目から）。

# 棋譜自動再生

https://github.com/YmBIgo/goban/blob/8ac34546f7d62bc1b9780a2761c085730451a47d/src/components/Goban.tsx#L667

SGF ファイルをアップロードすることで、棋譜再生ができる機能も作りました。棋譜の再生「開始」「停止」「再開始」ができます。
JavaでHTTPリクエストのPOSTメソッドでAPI呼び出しサンプル

# HTTPリクエストにてAPI呼び出し
OAuth認証などで取得したアクセストークンを用いて、
外部APIに対してJSONパラメータをリクエストする処理のサンプル

### パラメータ説明
` setTimeout() ：タイムアウト値をセットするメソッド`
` "api.endpoint.co.jp　：外部連携APIのエンドポインt"`
` accessToken　：アクセストークン`

### 処理
```
// URLオブジェクト作成
URL url =new URL(API_PATH);
//httpsコネクターをオープン
HttpURLConnection con = (HttpURLConnection) url.openConnection();
// タイムアウト時間を設定
con.setConnectTimeout(setTimeout());
// メソッドをPOSTに設定
con.setDoOutput(true);
con.setDoInput(true);
con.setRequestMethod("POST");
// リクエストヘッダーの追加
con.setRequestProperty("Host", "api.endpoint.co.jp");
con.setRequestProperty("Authorization", "Bearer " + accessToken);
con.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
con.setRequestProperty("Accept", "application/json");
// 接続する
con.connect();
// リクエストボディへの書き込み
OutputStreamWriter os= new OutputStreamWriter(con.getOutputStream());
os.write(jsonParam);
os.close();
```
Rubyの配列に要素を追加するメソッド比較

# 配列に要素を追加するメソッド
配列に要素を追加するメソッドは主にこんな感じ（もっと色々あるかもしれない、またあれば追記する）
```
<<
push
concat
insert
unshift
+
```
## `<<`メソッド, `push`メソッド
引数のオブジェクトを自分の末尾に追加する。
```ruby
ary = [1, 2, 3]
# => [1, 2, 3]
ary << 4
# => [1, 2, 3, 4]
ary.push(5)
# => [1, 2, 3, 4, 5]
```

## `concat`メソッド
引数の配列を自分の末尾に追加する。破壊的メソッド。
```ruby
ary = [1,2,3]
# => [1, 2, 3]
ary.concat([4, 5])
# => [1, 2, 3, 4, 5]
ary
# => [1, 2, 3, 4, 5]
```

## `insert`メソッド
第一引数で指定された位置に、第二引数以降のオブジェクトを挿入する。破壊的メソッド。
```ruby
ary = [1, 2, 3]
# => [1, 2, 3]
ary.insert(1, "a", "b", "c")
# => [1, "a", "b", "c", 2, 3]
ary
# => [1, "a", "b", "c", 2, 3]
```

## `unshift`メソッド
引数のオブジェクトを配列の先頭に追加する。破壊的メソッド。
```ruby
ary = [1, 2, 3]
# => [1, 2, 3]
ary.unshift(-1, 0)
# => [-1, 0, 1, 2, 3]
ary
# => [-1, 0, 1, 2, 3]
```

## `+`メソッド
自分と与えられた配列を連結した新しい配列を返す。配列以外のオブジェクトを与えた場合はto_aryメソッドで型変換が行われる。
```ruby
ary1 = [1, 2, 3]
# => [1, 2, 3]
ary2 = ary1 + [4, 5, 6]
# => [1, 2, 3, 4, 5, 6]
ary1.object_id == ary2.object_id
# => false
```
クッソ初心者がエラー起こしまくった備忘録

Python初学者が関数のところでSyntaxErrorを起こしまくったので原因と解決法を備忘録として残す。


```
>>>|def f(x):
...|   return x+1
...|f(2)
   |　　　
   |SyntaxError: invalid syntax
```
IDLE shellの左端も表記しているので、[>>>]や[...]を意図的に含んでいる。

defで関数を定義した後、直後でf(2)のように関数を呼びだそうとしたら、
上記のようにSyntaxErrorと表記された。

そこでreturnとf(2)を一行開けた状態にしたところ

```
>>>|def f(x):
...|    return x+1
...|
>>>|f(2)
   |3
```
このように出力された。

前者ではまだf(x)が定義される前にf(2)を呼び出していたということだろうか？

IDLE shellの左側にある[>>>]と[...]の違いがあるが、
[...]の中にある場合は一連の流れだからまだ定義し終わっていないということなのだろうか？
JavaでString型の日付や日時の比較をする

# JavaでString型の日付や日時の比較をする

例えば以下のような２つのString型で表された日付を考える

```
String date1 = "2022-1-1";
String date2 = "2022-1-5";
```

## String型の日付の比較

### ①SimpleDateFormatのオブジェクトを生成
```
SimpleDateFormat sdFormat = new SimpleDateFormat("yyyy-MM-dd");
```
### ②比較する
```
// date1がdate2よりまえの場合
sdFormat.parse(date1).compareTo(sdFormat.parse(date2)) == -1

// date1がdate2よりあとの場合
sdFormat.parse(date1).compareTo(sdFormat.parse(date2)) == 1

// date1がdate2と同じ日の場合
sdFormat.parse(date1).compareTo(sdFormat.parse(date2)) == 0
```
## String型の日時の比較
### ①SimpleDateFormatのオブジェクトを生成
```
SimpleDateFormat sdFormatDateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
```

### ②比較する
```
// date1がdate2よりまえの場合
sdFormat.parse(date1).compareTo(sdFormat.parse(date2)) == -1

// date1がdate2よりあとの場合
sdFormat.parse(date1).compareTo(sdFormat.parse(date2)) == 1

// date1がdate2と同じ日の場合
sdFormat.parse(date1).compareTo(sdFormat.parse(date2)) == 0
```
市場分析(marketing)でするとよいこと

いくつかのネットサービス（を＆で）市場分析(marketing)をしながら、主催者と協力して盛り上げる努力をしてきた。

市場分析でするとよいことをいくつか記録する。

# 誤字、言い間違い、勘違い、などはできるだけその場ですぐに対応する

市場分析で大事なのは速度感です。
あ、速いなと思われたら半分うまくいっているかもしれません。

その場で、すぐに対応したり、その日のうちに対応したりするとよいでしょう。

指摘をしてくださった方のお名前を書く了承が得られれば、名前を掲示して訂正するとよい。

間違いを消したり、無かったかのようなことにするのは、市場分析として危ういかもしれません。

# 多様な意見を探す

できるだけたくさんの意見を探すとよい。
例えば、誰かが、一方向だけの意見を述べていたら、実時間で、その場で違う方向を示唆するとよい。
その場で示唆すると、反応から市場分析の専門家かどうかがわかる。

著名な人を呼べばいいのではないことは主催者ならわかっているはず。

勉強会選びで手を抜く３つの気をつけること

https://qiita.com/kaizen_nagoya/items/9e442881cc85d252918c

その場で実時間で行動が取れてこそ、市場分析屋さんだと思ってもらえる。

ネットの記録を、Datarobotなどのような機械学習ソフトにかければ、過去の市場分析は可能である。

現地現物で、その日、その場で対応するのが市場分析屋さんだと思うとよいでしょう。

# 三つ以上の房を探す

多様な意見をいっぱい集めたら、対象となる房を３つ感じるとよい。

事業化するにあたって、予備とその予備の３つは用意しておかないと、競合他者にしてやられたときに、二の矢、三の矢が打てない。一の矢が情報漏洩で競合他者に出し抜かれても、なおかつ勝ちに行く方法はあるかもしれない。

「三方よし」への三つのあり方

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

# 誰が市場分析者によいか

新人でもいい、学生のインターンでもいい、顧客でもいい。
三つ以上の房を探すのに、三つ以上の得意分野を持った市場分析担当者がいるとよい。

実時間で問題を解決すれば、市場はついてくるかもしれない。

最後まで経緯がわかる記録を残す組織についていくとよい。
市場分析の専門家として長く尊敬されるかもしれない。

#  まとめに代えて

新人プログラマ応援 - みんなで新人を育てよう！

https://qiita.com/official-events/3f21c92121aa125807b4

今、Qiitaでは、「データに関する記事を書こう！」という行事をやっている。

https://qiita.com/official-events/30be12dd14c0aad2c1c2

この文章は、テーマ2『データに関する記事を書こう！』参加記事でもあります。

@torifukukaiou【毎日自動更新】新人プログラマ応援 - みんなで新人を育てよう！（2022年04月） LGTMランキング！

https://qiita.com/torifukukaiou/items/18dad64ba99aa5a40f95

@torifukukaiou 【毎日自動更新】データに関する記事を書こう！ LGTMランキング！

https://qiita.com/torifukukaiou/items/b10fa94764aaaa2c6db1


DoCAP 芸術でも技術でも運動でも

https://qiita.com/kaizen_nagoya/items/28321da8285a5884c7ca



＜この記事は個人の過去の経験に基づく個人の感想です。現在所属する組織、業務とは関係がありません。＞

# 文書履歴(document history)
ver. 0.01 初稿 　20220419
ver. 0.02 ありがとう追記 20230504

## 最後までおよみいただきありがとうございました。

いいね　💚、フォローをお願いします。

####  Thank you very much for reading to the last sentence.

Please press the like icon 💚　and follow me for your happy life.
失敗やミスがあっても前向きになれる名言集をLINEbotで引き出せるようにしてみた

## 失敗が続いても前向きになれる言葉をいつでもLINEbotで引き出せるようにしたい

### 完成品
![image_123986672.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2620988/b8f96249-f60c-1f78-28d4-94ecaf5f0cf4.jpeg)

　最近職場でも家でもミスで落ち込むことが多くなった。そんな時、前向きな言葉を得られる名言集をLINEbotで参照できるよう作ってみた。未だすべてを確認していないが、早速「Never regret If it's　good,it'wonderful.If it's wonderful.if it's bad,it's experience. 」はすごいと思った。難しい知識がなくてLINEbotが作れることを知った。WEB APIというものを活用して、JSONを変換し、テキストを表示することにチャレンジしてみた。

## 作成したLINE Bot
　1～224までの番号を入れると割り当てられた番号に対応する名言集が出てくる
　それ以外の数字を入れるとそのコードは存在しませんといった表示が戻るようにする

## 整えた環境
- make
- 名言集API　(zennから引用）　
- LINE Bot


## 作成手順
- LINEDevelopersの登録から始め、makeを使って、WatchEventとSend a Reply Massageを設定
- オウム返しの設定をして受け取ったLINEメッセージがそのまま返信されるようにする
- それぞれのモジュールの間にHTTPのモジュールを入れ、そこにAPIのJASONコードをいれてJASONの内容がそのまま返信されるようにする
- 次にJASONのモジュールを入れて、JASONの解釈を行い名言集の文字だけが返信されるようにする
- 次に任意の番号1～224を入れるとそれぞれに対応した名言集が返されるよう数字の部分を入力番号に置き換える
- 今度はRouterをモジュールの間に入れて、該当の数字のみ返信し、それ以外は「その番号は対応していません」が表示されるように設定。
- RunOnceを使いながら手順を一つ一つ確認しながら進めていく

### makeのシナリオ![make①.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2620988/fe2bc199-5471-d31c-ae9c-fe5c6a21ca76.jpeg)

今回使用したAPI
https://api.adviceslip.com/#top

## 分かったこと　難しかったこと
　プログラミングの知識がなくても、LINEbotの作成が行えることが分かった。手順の一つ一つでつまずきながらもそれを質問して、何度も試してみて得たことは大きいことが分かった。
　今回は初歩の初歩。わからない言葉は何度も調べてイメージできるようにすることが大切。まだまだこれからですが、頑張っていきます。
Go + MySQL で BULK INSERTしてみた

# はじめに
Go で MySQL を操作する処理を書いているときに、BULK INSERT したいと思うときがありました。
日本語だと、外部パッケージに頼らずに BULK INSERT するための情報があまりなかったので、記事で残そうと思います。

念の為の説明ですが、BULK INSERT とは、複数レコードを一回のINSERTで作成することを言います。
# 結論(コード)
早速ですがこちらが実装したコードです。
```main.go
package main

import (
	"database/sql"
	"fmt"
	"log"

	_ "github.com/go-sql-driver/mysql"
)

var DB *sql.DB

// DBと接続
func init() {
	// databaseはあらかじめ作成しておく
	dsn := "root:root@(127.0.0.1:3306)/test?interpolateParams=true"

	var err error
	DB, err = sql.Open("mysql", dsn)
	if err != nil {
		log.Fatal("OpenError: ", err)
	}

	if err := DB.Ping(); err != nil {
		log.Fatal("PingError: ", err)
	}
}

func main() {

	// tableを作成
	_, err := DB.Exec(`create table if not exists names(id int, name varchar(20), primary key(id))`)
	if err != nil {
		log.Fatal("Exec to create table error: ", err)
	}

	// insert文の用意
	s := []string{"hoge", "fuga", "piyo"}

	insert := "INSERT INTO names(id, name) VALUES "

	vals := make([]any, 0, len(s))
	for i, k := range s {
		insert += fmt.Sprintf(`(%v, ?),`, i)
		vals = append(vals, k)
	}
	insert = insert[:len(insert)-1]

	fmt.Println(insert)

	// prepareして実行
	stmt, err := DB.Prepare(insert)
	if err != nil {
		log.Fatal("Prepare error: ", err)
	}

	if _, err := stmt.Exec(vals...); err != nil {
		log.Fatal("Exec error: ", err)
	}
}

```
実行後のターミナル画面（作成したinsert文を標準出力）
```zsh
% go run main.go
INSERT INTO names(id, name) VALUES (0, ?),(1, ?),(2, ?)
```

結果
```
mysql> select * from names;
+----+------+
| id | name |
+----+------+
|  0 | hoge |
|  1 | fuga |
|  2 | piyo |
+----+------+
3 rows in set (0.00 sec)
```
# 解説
`sql.Open` や `Prepare` 、`Exec` については解説しません。情報がたくさんあるので、他サイトや記事を参考にしていただきたいです。

今回見るのは、insert文を作成したこちらの処理になります。
```go
	s := []string{"hoge", "fuga", "piyo"}

	insert := "INSERT INTO names(id, name) VALUES "

	vals := make([]any, 0, len(s))
	for i, k := range s {
		insert += fmt.Sprintf(`(%v, ?),`, i)
		vals = append(vals, k)
	}
	insert = insert[:len(insert)-1]
```

for文を使って、作成するレコードの数だけ `(%v, ?),` をinsert文に追加しています。
for文が終わった後、末尾のカンマを取り除いています。
言わずもがなと思いますが、for文の文字列 `k` を直接 insert文 に入れずに `?` を使うのはSQLインジェクション対策です。

また、any型で新しくスライスを作り直しているのは、`stmt.Exec(vals...)` を使う時の引数に、string型のスライスは引数として使えないからです（今後、言語の仕様が変わって使えるようになるかもしれません）
`vals` に入れる要素の数は明白なため、 `make`で capacity を指定しています。

insert文と引数に入れる `vals` ができれば、あとは普通にSQLの処理を書くだけです。

# 最後に
Go で BULK INSERT を行う方法を記述しました。
Go と MySQL 両方の処理速度を考えなければならないので、もっと良い書き方があるかもしれません。
どちらもまだ知識不足なので、今後アップデートしていければなと思います。
MySQLを学習するための準備

## 背景

業務でMySQLを使用しているので、この辺で基本から学びなおして、知識の整理をする。
ということで、まずは自宅PCにMySQLの動作環境を構築する。

## 参考サイト

https://www.dbonline.jp/mysql/install/index1.html#section1

## ポイント
MySQLインストーラーのウィザードが起動したとき、使わないものをインストールしても仕方ないので、
Customを指定し、以下を選択する。

- MySQL Server 
- MySQL Workbench (GUIで操作しやすい・見やすい)
- MySQL Shell (シェルから操作できる。)
- Connector/J (Javaで操作することを見越して)


そのままデフォルトで進み、

ユーザーの追加をする。
Windows Service のフェーズで、
「Configure MySQL Server as a Windows Service」(Windowsのサービスとして設定)にチェックを入れる。



### サービスとは

> サービスにすると、誰も Windows にログオンをしなくてもプログラムを起動できます。
～中略～
> このため、Web サーバーなどサーバー・プログラムのように、対話的にログインを必要としないプログラムを実装する場合に向いているのです。

https://www.keicode.com/windows/what-is-nt-service.php

### インストール完了
インストール完了後、MySQLWorkbenchが起動し、MySQLが使用できる状態になっている。
また、WindowsのFireWallの設定も変更されているため、3306のポートも空いている。

※ Windows のポートが開いているかどうかは、power shellにて、以下のコマンドで確認できる。

```
Test-NetConnection -ComputerName localhost -Port 3306
```
「TcpTestSucceeded : True 」と表示されていれば、ポートは解放されている。

### テストデータのインポート



都市情報などのテスト用のデータが公式から出ている。
MySQL workbenchから、Server > Data Import > ZIPを解凍した.sqlファイルをインポートする。

https://qiita.com/S-T/items/923cf689ee5f44525457

### SQL実行

あとはSELECTなどで遊んでみる。

### 今後はこのへんをやりたい


https://products.sint.co.jp/siob/blog/executeplan

https://qiita.com/pugiemonn/items/2edf5d7967fb45dd5196

が、今日はここまで。
勉強会選びで手を抜く３つの気をつけること

勉強会について、すこしつよつよに書いたことがある。

勉強会(IT系)をすべて当たりにする方法。仮説（124）

https://qiita.com/kaizen_nagoya/items/9f001a79ab4162220406

逆も真なので、すこしよわよわなことも書いて見る。

勉強会で嫌な思いをしないために気をつけるといいことを３つあげる。
自分が発表すれば、する必要がない心配であり、自分が発表しないことが一番悪いことだと思うとよい。

逆も真：社会人が最初に確かめるとよいこと。

https://qiita.com/kaizen_nagoya/items/39afe4a728a31b903ddc

# 題名で選ばない

流行りもので、題名で飛びつくとろくなことがないことは経験則。
詐欺師は、題名で儲けるという話を聞いたことがあるかないかは定かではない。

名古屋Reject会議 という行事があった。

https://mzp.hatenadiary.org/entry/20110228/reject

twitterでは一人しか言及してくださらなかったし、
ニコ動でも一人がコメントしてくれただけだった。

それでも、13人中、ニコ動での再生数は３位だった。
マイナな言語は、再生数が少ない。
発表が最後から二番目だった。
人の発表の単語を取り込んだ。
という効果があったかもしれない。

プログラミング言語教育のXYZ。 仮説（52）

https://qiita.com/kaizen_nagoya/items/1950c5810fb5c0b07be4

# 人で選ばない

JAXA/IPA クリティカルソフトウェアワークショップ WOCS言語関連発表(改定版)

https://qiita.com/kaizen_nagoya/items/4789832baf494cb74626

招待講演は、講師の方にお金をお支払いし、交通費を負担して講演していただく。

一般講演は、講演料はいただかないものの、交通費は自費で発表していただく。

アンケート結果を見ると、一般講演の方が、役に立ったという意見をたくさんいただいた。

招待講演は、主催者団体の組織的な意向で決まる可能性がある。
一般講演は、プログラム委員長が誘ってくると、他の委員はRejectしづらいかもしれない。

いえ、実際にRejectされたり、一般講演社がこんなコメントをもらうなら発表しないという人が何人か現れたかもしれない。
プログラム委員長の責務として、どういう人が、どういう目的できているから、発表して、参加者の意見をもらわないとそんだよという説得をすることになったかどうかは記録しない。

結果として、人名が有名かどうかではなく、発表の中身がしっかりしたものは高い評価を得た。


# 組織名で選ばない

この組織だから大丈夫だと思ってはいけない。

主催者が、何を考えているかを確かめたり、

https://techblog.yahoo.co.jp/datascience/nagoya-deep-learning/

過去動画があれば、動画を見て確かめるとよい。

https://www.facebook.com/mlnagoya

いいかげんな行事をしても、その責任を取ろうとしないような組織の行事に出た人が悪いかもしれない。
主催者を吊るし上げない参加者が悪いかもしれない。

#  まとめに代えて

新人プログラマ応援 - みんなで新人を育てよう！

https://qiita.com/official-events/3f21c92121aa125807b4

今、Qiitaでは、「データに関する記事を書こう！」という行事をやっている。

https://qiita.com/official-events/30be12dd14c0aad2c1c2

この文章は、テーマ2『データに関する記事を書こう！』参加記事でもあります。


いくつかの事項は、データを取ってから追記できればいいかもしれない。

@torifukukaiou【毎日自動更新】新人プログラマ応援 - みんなで新人を育てよう！（2022年04月） LGTMランキング！

https://qiita.com/torifukukaiou/items/18dad64ba99aa5a40f95

@torifukukaiou 【毎日自動更新】データに関する記事を書こう！ LGTMランキング！

https://qiita.com/torifukukaiou/items/b10fa94764aaaa2c6db1


DoCAP 芸術でも技術でも運動でも

https://qiita.com/kaizen_nagoya/items/28321da8285a5884c7ca
GitHubのテキストエリアで等幅フォントを使う

いつの間にか設定できるようになってた。

1. <https://github.com/settings/appearance> を開く
2. `Markdown editor font preference` で `Use a fixed-width (monospace) font when editing Markdown` にチェックを入れる

チェックなし（プロポーショナルフォント）

![proportional.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177113/ea18a6d9-f6f1-7090-ed17-b19a718f826f.png)

チェックあり（等幅フォント）

![monospace.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177113/1eb2773d-9cd1-0696-aeb6-f7b5f9fe59f8.png)

## 参考

- [GitHub 上での執筆とフォーマットについて - GitHub Docs](https://docs.github.com/ja/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/about-writing-and-formatting-on-github)
- [Fixed-width font support in Markdown-enabled fields | GitHub Changelog](https://github.blog/changelog/2021-10-12-fixed-width-font-support-in-markdown-enabled-fields/)
FastAPIでBasic認証

# 公式情報

 - APIにbasic認証: https://fastapi.tiangolo.com/advanced/security/http-basic-auth/
 - staticファイルにBasic認証: https://github.com/tiangolo/fastapi/issues/858

片方だけでいい場合は、公式の実装をそのまま利用すればよい。この記事では、両方にBasic認証をかけてみる。

# API/static filesそれぞれにBasic認証を実装する

## Basic認証用のモジュール

id/passは環境変数で指定する想定

```python:basic_auth.py
import secrets
import os

from fastapi import HTTPException, status, Request, Depends
from fastapi.staticfiles import StaticFiles
from fastapi.security import HTTPBasic, HTTPBasicCredentials

security = HTTPBasic()


def auth_basic(credentials: HTTPBasicCredentials):
    correct_username = secrets.compare_digest(
        credentials.username, os.environ.get("BASIC_USER"))
    correct_password = secrets.compare_digest(
        credentials.password, os.environ.get("BASIC_PASSWORD"))
    if not (correct_username and correct_password):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect email or password",
            headers={"WWW-Authenticate": "Basic"},
        )


def verify_from_api(credentials: HTTPBasicCredentials = Depends(security)):
    auth_basic(credentials)


class AuthStaticFiles(StaticFiles):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)

    async def __call__(self, scope, receive, send) -> None:
        assert scope["type"] == "http"

        request = Request(scope, receive)
        credentials = await security(request)
        auth_basic(credentials)
        await super().__call__(scope, receive, send)
```

## Basic認証用のモジュールを利用してコントローラを実装

```python
from fastapi import FastAPI, HTTPException, status, UploadFile, File, Request, Depends
from basic_auth import verify_from_api, AuthStaticFiles

app = FastAPI()
app.mount("/static", AuthStaticFiles(directory="static"), name="static")


@app.get("/api/me")
def me(_ = Depends(verify_from_api)):
    return {"message": "authorized"}
```

# コードの解説

`security = HTTPBasic()` 
 - https://github.com/tiangolo/fastapi/blob/22528373bba6a654323de416ad5c867cbadb81bb/fastapi/security/http.py#L48
 - Basic認証をするためのクラス

`credentials = await security(request)`
 - https://github.com/tiangolo/fastapi/blob/22528373bba6a654323de416ad5c867cbadb81bb/fastapi/security/http.py#L61
 - requestからauthorizationヘッダの情報を受け取る
 - ここではバリデーションとbase64デコードのみ行い、実際の認証は行わない
 - バリデーションNGは401レスポンスをraiseする。問題なければcredentials(デコードされたusername, passwordを保持するクラス)を返す

`auth_basic(credentials)`
 - ここでユーザ名・パスワードの認証を行う
 - 実体はこんな感じ `correct_username = secrets.compare_digest(credentials.username, os.environ.get("BASIC_USER"))`
 - `secrets.compare_digest` は、タイミング攻撃を防ぐような安全な文字列比較メソッド
Splunkカスタムアラートアクションを利用してスクリプトを実行させる

業務でSplunkのアラート時にスクリプトを実行したいという要件があり、その際にカスタムアラートアクションを利用したので、動作確認の内容を記載していきます。

## カスタムアラートアクション用のApp構成  
※動作確認のために必要なもので対応してます。

```
test_alert
 ┣bin
 ┃ ┗test.py
 ┣defaut
 ┃ ┣alert_actions.conf 
 ┃ ┗app.conf
 ┗metadata
   ┗default.meta
```

## app.confの記載
アプリに関するパッケージとUIの情報を記載します。

```
[package]
check_for_updates = false   ： Splunkbaseへのアップデートチェックの無効化

[ui]
is_visible = false          ： SplunkWeb上のGUI表示の無効化
```
## alert_actions.confの記載  
このファイルでアラート時のアクション内容を設定します。  
アラートアクションの名前であったり、アラート時にスクリプトを連携したい場合はここで定義したりしていきます。  
以下のような設定をすることでスクリプトに渡すパラメータを設定することが可能です。
```
param.[パラメータ名] = [パラメータ値]
```
尚、パラメータ値に「SPLUNK_ARG environment variable」で準備されている環境変数をいれることで検索結果のイベント数等をパラメータ値として指定することが可能です。  
デフォルトで準備されているパラメータもあります。

```
[test_alert]                
is_custom = 1                                   ：カスタムアラートアクションを利用する場合は1にする
label = My Alert Action                         ：SplunkWeb上でのカスタムアラートアクションの名前
payload_format = json                           ：スクリプトへ渡される場合のペイロード形式
disabled = 0                                    ：スタンザの有効化(有効にする場合は0にする)
alert.execute.cmd = test.py                     ：アラート発生時に実行するスクリプト名
# Custom params
param.result_count = $job.resultCount$          :「result_count」パラメータ名で値に検索結果のイベント数を設定
param.search_query = $job.search$               :「search_query」パラメータ名で値に検索クエリを設定
param.test = abc                                :「test」パラメータ名で値に「abc」を設定
```
準備されている環境変数は下記を参照　　
https://docs.splunk.com/Documentation/Splunk/latest/AdvancedDev/CustomAlertConvertScripted#Accessing_script_argument_values_in_a_custom_alert_action

## default.metaの記載
Appの権限の定義を記載します。
下記は作成Appに対してすべてのユーザから読み込みを許可、書き込みはadminユーザのみに許可を設定しています。

```
[]
access = read : [ * ], write : [ admin ]
export = system
```

## スクリプトの記載(test.py)
アラート時に実行するスクリプトを作成していきます。  
今回は、Splunkからの渡されたパラメータの値を確認しやすくするためだけに
「/tmp/test.txt」のテキストにパラメータ値を記載するだけのスクリプトになっています。


```
import sys
import os
import json

path = "/tmp/test.txt"
d = json.loads(sys.stdin.read())

file = open(path, 'w', encoding='utf-8')
file.write(str(d['configuration']['result_count'])+'\n')
file.write(str(d['configuration']['search_query'])+'\n')
file.write(str(d['configuration']['test'])+'\n')
file.close()
```

## Appを適用してアラートを設定する
カスタムアラートアクションのAppが作成されたら、AppをSplunkに適用してアラート作成時にアクションでに作成したカスタムアクションが表示されているので適用するだけとなります。
GUI上での表示名は「alert_actions.conf」の「label」で設定した名前が表示されます。

![アラート設定.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1397176/0e52ba79-27ff-fc3b-26e0-ab3cd23973e8.png)


## さいごに
実際にカスタムアラートアクションで利用するスクリプトでは、Splunkで用意されているライブラリではがなかったので、App内にライブラリを準備して読み込ませてからスクリプトを実行させるみたいないことも実施してました。
今後、機会があればその辺も記載したいなと思います。
ElasticsearchでDateと判別される文字列の種類を調べてみた


以前こんな記事を書きました

https://qiita.com/uturned0/items/ddc8197186110b5d21d2


このときは何も考えずにdateを入れたらtextになってしまって、それを後からなんとかした話でした。

新しくindexを作るに当たって、勝手にdateになるformatを調べました。詳細はここのDate detectionという項目に説明があります。

https://www.elastic.co/guide/en/elasticsearch/reference/7.17/dynamic-field-mapping.html

自分でformatを指定することもできますが、mappingも面倒なので、document側でcontrolすることにします。


# test documents

これを流しました。

```rb
delete test
put test

# text
PUT test/_doc/a
{
  "a": "2022/1/1"
}

# date
PUT test/_doc/b
{
  "b": "2022/12/31"
}

# date
PUT test/_doc/c
{
  "c": "2022-12-31"
}

# text
PUT test/_doc/d
{
  "d": "2022-12-31 12:34:56"
}

# date
PUT test/_doc/e
{
  "e": "2022-12-31T12:34:56"
}

# date
PUT test/_doc/f
{
  "f": "2022-12-31T12:34:56.000"
}

# text
PUT test/_doc/g
{
  "g": "2022-12-31 12:34:56.000"
}

# date
PUT test/_doc/h
{
  "h": "2022-12-31T12:34:56+0900"
}

# text
PUT test/_doc/i
{
  "i": "2022-12-31 12:34:56+0900"
}


# date
PUT test/_doc/j
{
  "j": "2022-04-22T15:23:32.769446"
}


# date
PUT test/_doc/k
{
  "k": "2022-08-19T02:57:23.084Z"
}


# text
PUT test/_doc/l
{
  "l": "Thu Aug 25 2022 00:00:00 GMT+0900 (Japan Standard Time)"
}



get test/_mapping
```


# Result

結果。

```rb
{
  "test" : {
    "mappings" : {
      "properties" : {
        "a" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "b" : {
          "type" : "date",
          "format" : "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis"
        },
        "c" : {
          "type" : "date"
        },
        "d" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "e" : {
          "type" : "date"
        },
        "f" : {
          "type" : "date"
        },
        "g" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "h" : {
          "type" : "date"
        },
        "i" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "j" : {
          "type" : "date"
        },
        "k" : {
          "type" : "date"
        },
        "l" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

```


inputから来る形式を、それぞれいい感じに変換してあげればよさそうです。


# Pythonの場合は `datetime.now().isoformat()` でok

```py
from datetime import datetime
datetime.now().isoformat()       # '2022-04-22T15:23:32.769446'
```
JavaScriptメモ

# 基本文法
- コメントアウト
//

- 変数の定義
```javascript
let 変数名 = value;
```
- 定数の定義
```javascript
const 定数名　= value;
```

- テンプレートリテラル
```javascript
`${変数or定数}`; (テンプレートリテラルを用いる時は、バッククオートを使う。)
```

- if
```javascript
if (条件式){
	処理;
}else if(条件式２){
}else{
}
```

- 　条件式の複数指定
	- かつ　&&
	- または ||

- switch文
```javascript
switch(条件の値){
	case 値１:条件の値が値１と等しい時の処理
		break;
	default: 処理
		break;
}
```

- while文
```javascript
while (条件式）{
	処理
}
```

- for文
```javascript
for (変数定義;条件式;変数の更新){
	処理
}
```

- オブジェクトの作り方
	プロパティと呼ばれる名前をつけて管理する。
```javascript
	{プロパティ1:値1,プロパティ２:値２}
```

- オブジェクトと関数
	オブジェクトの値部分には関数を用いることも可能
```javascript
{プロパティ名:()=>{
	処理
		}
	};
```

- 関数の定義（アロー関数）
```javascript
	const 定数名= (引数名)=>{
	処理
	}
```
	
- クラスの生成
```javascript
class クラス名{
	}
```

- インスタンスの生成
```javascript
new クラス名()
```

-コンストラクタとは
インスタンスを生成するときに実行したい処理や設定を追加する機能
```javascript
clss クラス名{
		constructor(){
		処理
		}
}
```

- コンストラクタにプロパティを追加
```javascript
class クラス名(){
		constructor(変数名){
			this.プロパティ名=変数名;
		}
	}
```

- メソッドの定義
	メソッドとは；インスタンスのもつ処理動作のこと
```javascript
	class クラス名{
		メソッド名（）{
		}
	}
```

- メソッド内でインスタンスの値を使う
```javascript
this.プロパティ名
```
- メソッド内で他の滅ソドを呼び出す。
```javascript
this.メソッド名()
```

- 継承
```javascript
class 子クラス名 extends 親クラス{
}
```

- コンストラクタのオーバーライド
```javascript
class 子クラス　extends 親クラス{
	constructor(){
		super();
		小クラスのコンストラクタの処理
		}
	}
```
- ファイルを分割し、読み込む(defaultエクスポート）
```javascript
1. 分割したファイルを他のファイルから呼び出し可能な状態にする
	class Animal{
	…
	}
	export default クラス名;
2. 呼び出し可能な.jsファイルをインポートする
	import クラス名 from 読み込みたいファイルのパス
	

- ファイルを分割し、読み込む（名前付きエクスポート）
1.呼び出し可能な状態にする。
	cosnt dog1 =　値１
	const dog2 = 値２
	export {dog1,dog2};

2. インポートする
	import{dog1.dog2} from './ファイル名'
```

- パッケージのimport
```javascript
import 定数名　from 'パッケージ名';
```

- 配列の最後に要素を追加
```javascript
 配列名.push(要素);
```
 
- コールバック関数
ある他の関数に引数として渡される関数のこと


- find メソッド(条件に合う変数を配列の中から一つ返してくれる）
```javascript
配列.find((変数名)=>{
	return 条件;
	});
```
	
- filterメソッド（条件に合う要素を全て取り出す）
```javascript
配列名.filter((変数名)=>{
	return　条件;
	});
```

- map関数(配列内の全ての要素に処理を行い、戻り値から新しい配列を作成するメソッド）
```javascript
配列名.map((変数名)=>{
 return 処理;
 });
```
OpenCVでパノラマ合成

>参考
[Python+OpenCVでstitching　パノラマ画像生成をやってみた](https://tech-blog.s-yoshiki.com/entry/36/#%E3%82%BD%E3%83%BC%E3%82%B9)

* csvインストールコマンド
```bash
python3 -m pip install opencv-python
python3 -m pip install opencv-contrib-python
```

* Stitcher_create：openCVのバージョンアップで関数変更↓
```python
import argparse
import cv2

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Stitch given images.')
    parser.add_argument("inputs", metavar='input', type=str, nargs='+', help='input file')
    parser.add_argument("--output", type=str, default='a.png', help='output file (default=a.png)')
    args = parser.parse_args()

    input_images = []
    for i in args.inputs:
        image = cv2.imread(i)
        if image is None:
            print(f'Error: Unable to open file "{i}".')
            exit()
        input_images.append(image)

    if len(input_images) == 1:
        cv2.imwrite(args.output, input_images[0])
    else:
        stitcher = cv2.Stitcher_create(mode=1) #mode=0 カメラ画像 mode=1 スキャン画像
        stitched = stitcher.stitch(input_images)
        cv2.imwrite(args.output, stitched[1])
```
* コマンド
`python3 main.py --output ./dst.jpg ./src1.jpg  ./src2.jpg ./src3.jpg`
【Swift・PDFKit】文字列・画像をPDF化する方法

# 文字列・画像をPDF化
以下のコードはサイズとPDF化したい文字列、画像を受け取り、PDFをData型に変換して返す処理になります。
Data型で返しているので、返り値をそのままActivityViewControllerに渡せば、それでPDFの共有ができます。
調べるのにちょっと手こずったので備忘録として残しておきます。

```swift
import UIKit
import PDFKit

class PDFUtils {
    var pdfData = NSMutableData()
    var render = UIPrintPageRenderer()
    let a3Width: CGFloat = 841.8
    let a3Height: CGFloat = 1190.5
    let a4Width: CGFloat = 595.2
    let a4Height: CGFloat = 841.8
    let a5Width: CGFloat = 419.5
    let a5Height: CGFloat = 595.2
    let b3Width: CGFloat = 1031.8
    let b3Height: CGFloat = 1459.8
    let b4Width: CGFloat = 728.5
    let b4Height: CGFloat = 1031.8
    let b5Width: CGFloat = 515.9
    let b5Height: CGFloat = 728.5

    func createPDFfromImages(images: [UIImage], size: String) -> Data {
        let pdfData = NSMutableData()
        for index in 0..<images.count {
            UIGraphicsBeginPDFContextToData(pdfData, getPDFPageFrame(size: size), nil)
            UIGraphicsBeginPDFPageWithInfo(getPDFPageFrame(size: size), nil)
            guard let pdfContext = UIGraphicsGetCurrentContext() else { return Data() }
            let imageView = UIImageView(frame: getPDFPageFrame(size: size))
            imageView.image = images[index]
            imageView.contentMode = .scaleAspectFit
            imageView.layer.render(in: pdfContext)
            UIGraphicsEndPDFContext()
        }
        return pdfData as Data
    }

    func createPDFfromString(size: String, text: String) -> Data {
        render = UIPrintPageRenderer()
        render.addPrintFormatter(UIMarkupTextPrintFormatter(markupText: text), startingAtPageAt: 0)
        render.setValue(getPDFPageFrame(size: size), forKey: "paperRect")
        render.setValue(getPDFPageFrame(size: size), forKey: "printableRect")

        pdfData = NSMutableData()
        UIGraphicsBeginPDFContextToData(pdfData, .zero, nil)

        for i in 0..<render.numberOfPages {
            UIGraphicsBeginPDFPage()
            render.drawPage(at: i, in: UIGraphicsGetPDFContextBounds())
        }

        UIGraphicsEndPDFContext()
        return pdfData as Data
    }
    
    private func getPDFPageFrame(size: String) -> CGRect {
        switch size {
        case "A3": return CGRect(x: 0, y: 0, width: a3Width, height: a3Height)
        case "A4": return CGRect(x: 0, y: 0, width: a4Width, height: a4Height)
        case "A5": return CGRect(x: 0, y: 0, width: a5Width, height: a5Height)
        case "B3": return CGRect(x: 0, y: 0, width: b3Width, height: b3Height)
        case "B4": return CGRect(x: 0, y: 0, width: b4Width, height: b4Height)
        case "B5": return CGRect(x: 0, y: 0, width: b5Width, height: b5Height)
        default: return CGRect(x: 0, y: 0, width: a4Width, height: a4Height)
        }
    }
}
```
Rubyでソースコードの文字コードを設定する

# マジックコメントについて
Ruby2.0以降ならデフォルトでUTF-8が入っているので、マジックコメントで文字コードを特に指定する必要はない。


# 書き方
大文字・小文字を区別しない、`coding: エンコーディング名` が正しければ、その前後には任意の文字列を並べることができる。

```
# encoding: 文字コード名
```
もしくは
```
# coding: 文字コード名
```

## 具体的な指定例
US-ASCIIを指定する場合
```
# coding: us-ascii
# encoding: us-ascii
# CODING: US-ASCII
...
```
ファイルを iconv で UTF-16 BOM 付きに変換するメモ

Windows 推奨は UTF-16 LE.(BOM つき)

時々 UTF-16 LE に変換しないといけないときもある.

https://stackoverflow.com/questions/8923866/convert-utf8-to-utf16-using-iconv

ありがとうございます.

```
( printf "\xff\xfe" ; iconv -f utf-8 -t utf-16le UTF-8-FILE ) > UTF-16-FILE
```
[blender]オブジェクトの表面に沿ってベジェカーブを描く方法


表面に複雑な凹凸をつけるテクニックの一つとして、
丁度探し求めていたテクニックだったので日本語にしてメモしておきます。

https://twitter.com/JanvandenHemel/status/1516137848944082947?s=20&t=mo9DSX1clJkxutOfmXouZg


1 オブジェクトモードに変更し、shift＋A　＞　ベジェカーブを選択し、ベジェカーブを追加。
![スクリーンショット 2022-04-19 202719.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308792/4bb3ef7c-225c-cfea-148b-09ac557f71cd.png)

2 マテリアルタブを選び、適用したいマテリアルを選択する。(なければ新規から追加![スクリーンショット 2022-04-19 202826.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308792/a48afdde-1171-d665-1187-85f5fd13881f.png)
)

3 オブジェクトデータプロパティのタブを選び、ベベルの項目内の深度の値を任意の値に変える（ここでは0.01に設定）
![スクリーンショット 2022-04-19 203023.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308792/911b0408-05e0-dfe5-cdc3-7d69c0e352ff.png)

4 編集モードに変更し、全選択して今あるカーブを削除。
5 左側のツールバーからドローを選択
![スクリーンショット 2022-04-19 203323.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308792/1fa9abda-450e-f82e-1b57-c77c6b83c419.png)

6 そのまま右側の一番上のタブを選び、オフセットをサーフェイスにする。
 テーパー開始を１、その真下の終了も１に設定。
![スクリーンショット 2022-04-19 203739.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308792/7a84147b-66b2-2d14-f4c6-f194922e854f.png)

7 これでオブジェクトの表面に手書きが出来るので描き始める。必要に応じてベベルの項目内の深度の値を調整する。

8 ベベルないの項目の丸めを断面にして変更することで違った描写にすることも可能。
Twitterクローンを作ります #13 ログインまわりの修正

前回ログイン必須画面の処理を追加しましたが、リロードする度にログインが必要な実装になってしまっていたので修正していきましょう。

ログイン済みユーザーの情報を返してあげるAPIを追加します。

```python:server/apis/login.py
from flask import jsonify, request, session
from apis import login_required
from models.user import User
from main import app

...


@app.route('/api/session', methods=['GET'])
@login_required()
def get_session():
    return jsonify(session['user'])
```

ログアウト後のlogin_requiredの挙動に問題があったのでこちらも修正しておきます。

```python:server/apis/__init__.py
import functools
from flask import session, jsonify


def login_required(status=401):
    def wrapper(f):
        @functools.wraps(f)
        def _wrapper(*args, **kwargs):
            if 'user' not in session or not session['user'] or '_id' not in session['user']:
                return jsonify({'error': { 'message': '権限がありません' }}), status
            return f(*args, **kwargs)
        return _wrapper
    return wrapper

```

画面側のstoreにログイン済みユーザー情報がなければこのAPIを呼び出してログイン済みか確認するようにしましょう。

```javascript:client/src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

import UIkit from 'uikit'
import Icons from 'uikit/dist/js/uikit-icons'
import 'uikit/dist/css/uikit.min.css'
UIkit.use(Icons)

router.beforeEach(async (to, from, next) => {
  if (to.matched.some(record => record.meta.loginRequired)) {
    let user = store.state.userLoggedIn;
    if (user && user._id) {
      next();
    } else {
      await store.dispatch('loginCheck')
        .catch(() => {
          // noop
        });
      user = store.state.userLoggedIn;
      if (user && user._id) {
        next();
      } else {
        next({ path: '/login' });
      }
    }
  } else {
    next();
  }
});

createApp(App).use(store).use(router).mount('#app')
```


```javascript:client/src/store/index.js
import { createStore } from 'vuex'
import router from '@/router';

import axios from 'axios';
import UIkit from 'uikit';

export default createStore({
  state: {
    userLoggedIn: undefined,
    posts: []
  },
  getters: {
  },
  mutations: {
    setUserLoggedIn (state, user) {
      state.userLoggedIn = user;
    },
    setPosts (state, posts) {
      state.posts = posts;
    }
  },
  actions: {
...
    async loginCheck ({ commit }) {
      const resp = await axios.get('/api/session');
      commit('setUserLoggedIn', resp.data);
    },

...

  },
  modules: {
  }
})

```

ひとまずこれでいいでしょう。
ローカルPCでPytorch環境構築/windows/gpu

# 自前のGPUでPyTorchを動かすための前準備(Windows)

https://qiita.com/Katan/items/da622e6c081272d8ecb5

# gpu を有効化

```

pip install torch==1.9.0+cu111 torchvision==0.10.0+cu111 torchaudio===0.9.0 -f https://download.pytorch.org/whl/torch_stable.html

python -c "import torch; print(torch.cuda.is_available())"

```

# pytorch
conda install matplotlib
conda install pytorch
conda install pytorch torchvision -c pytorch
conda install tqdm
pip install opencv-python
# error
jupyter notebookでgpu

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555658/449811f2-479a-b1d1-4b25-8189f65b5be3.png)

https://qiita.com/NNNiNiNNN/items/493ffe662eab7a6b22a5

# PyTorchのインストール後torchvisionで「エントリポイントが見つかりません」のエラーが出る問題

https://qiita.com/Mopepe51/items/1664284400fdec9f59cb
＃

＃
pip install opencv-python
Twitterクローンを作ります #5 Vuex

ログイン画面の実装のまえに、Vuexでデータを管理するように修正しておきましょう。

# Vuexを利用

store/index.js を下記のように修正します。

```js:client/src/store/index.js
import { createStore } from 'vuex'
import router from '@/router';

import axios from 'axios';
import UIkit from 'uikit';

export default createStore({
  state: {
    userLoggedIn: undefined
  },
  getters: {
  },
  mutations: {
    setUserLoggedIn (state, user) {
      state.userLoggedIn = user;
    }
  },
  actions: {
    registerUser ({ commit }, user) {
      axios.post('/api/users', user).then(resp => {
        commit('setUserLoggedIn', resp.data);
        router.push('/');
      })
      .catch(error => {
        UIkit.notification(error.response.data.error.message, {status: 'danger'});
      });
    }
  },
  modules: {
  }
})
```

RegisterView.vue は下記のように修正します。

```vue:client/src/views/RegisterView.vue

...

<script>
import { ref } from 'vue';
import { useStore } from 'vuex';

export default {
    setup() {
        const store = useStore();

        const displayName = ref("");
        const username = ref("");
        const password = ref("");
        const passwordConfirm = ref("");
        const email = ref("");
        const onClick = () => {
            var user = {
                display_name: displayName.value,
                username: username.value,
                password: password.value,
                email: email.value
            };

            store.dispatch('registerUser', user);
        };
        return {
            displayName,
            username,
            password,
            passwordConfirm,
            email,
            onClick
        };
    },
}
</script>
```

挙動は前回と変わりませんが、storeを利用することでログイン済みユーザーの情報を様々な箇所から参照することができるようになりました。

次回こそログイン画面を作成していきましょう。
Twitterクローンを作ります #3 DBの設定

前回はユーザー登録情報を画面からAPIへ送信するところまで作成しました。
今回はDBとの接続部分を行っていきます。

# MongoDBのセットアップ

ベースにしている[udemyの講座](https://www.udemy.com/course/create-a-twitter-clone-with-nodejs-socketio-and-mongodb/)と同様に、DBにはMongoDBを利用していこうと思います。

ユーザー登録がまだの場合の手順を記載しますので、すでに登録済みの方は適宜読み飛ばしてください。
https://www.mongodb.com/ にアクセスして "Start Free" をクリックします。

![スクリーンショット 2022-03-12 14.56.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2536525/cedcf9e2-215e-464c-c6b2-d9a0151e5710.png)


Googleアカウントでのサインアップか、名前等を直接入力して登録する方法を選択できます。お好みの方を選択して登録してください。

![スクリーンショット 2022-03-12 14.56.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2536525/6b496696-269d-a46f-0f1a-bfd473588be3.png)

利用規約の同意等の画面を進めていくと次の画面が表示されると思います。今回はFreeプランで進めていきますので、右端の"Create"ボタンをクリックします。

![スクリーンショット 2022-03-12 15.01.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2536525/8c9d56e6-51b2-6fda-748d-d794d9e86bb3.png)



次に、クラスタ作成画面が表示されます。
"Cloud Provider & Region"はお好みのものを選択してください。僕は"aws"の"Tokyo(ap-northeast-1)"を選択しました。
"Cluster Tier" と "Additional Settings" はデフォルトのままで構いません。
"Cluster Name" は "ToittaCluster" としました。
入力が完了したら "Create Cluster" をクリックします。

![スクリーンショット 2022-03-12 15.09.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2536525/150aa4a8-419c-050e-f68a-29d02c053c2c.png)


今度は "Security Quickstart" 画面が表示されます。
今回は認証方法に "Username and Password" を利用しようと思いますのでこちらを選択してください。僕はユーザー名を "admin" とし、パスワードに適当な文字列を設定しました。

![スクリーンショット 2022-03-12 15.21.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2536525/2f89a64d-4c67-db4d-4218-81baf39e600a.png)


その下にある "IP Access List" はアクセス可能なIPアドレスを指定します。本来は適切に設定すべきではありますがここでは一旦 "0.0.0.0/0" のみを指定してどこからでもアクセスできるようにしておきます。



ここまで完了したらクラスタがデプロイされて利用可能になるはずです。

クラスタ名の横の "Connect" ボタンをクリックし、"Connect your application" を選択すると接続情報を表示してくれます。
今回はPythonから利用するので、"DRIVER" を "Python", "VERSION" を "3.12 or later" にして表示される文字列をメモしておきましょう。

これでMongoDBのセットアップは完了です。

# Python側のセットアップ

ここからはPython側のセットアップを行っていきます。
まずは下記のように requirements.txt に pymongo を追加していきます。

```server/requirements.txt
Flask
pymongo[srv]
```

下記を実行しpymongoのインストールとconstraints.txtの更新をしておきます。

```
$ cd /path/to/project/server
$ pip install -r requirements.txt -c constraints.txt
$ pip freeze > constraints.txt
```

これでPythonからMongoDBが利用可能になっているはずなので確認しておきましょう。

```
$ python
>>> from pymongo.mongo_client import MongoClient
>>> from pymongo.server_api import ServerApi
>>> client = MongoClient("mongodb+srv://admin:XXXXXXX@toittacluster.YYYYYYY.mongodb.net/myFirstDatabase?retryWrites=true&w=majority", server_api=ServerApi('1'))
>>> db = client.test_database
>>> test_collection = db.test_collection
>>> result = test_collection.insert_one({"name": "hoge", "value": "fuga", "age": 100})
```

MongoClient の引数には先程メモした値を利用します。`admin:XXXXXXX`の部分は設定したMongoDBアクセス用のIDとパスワードに書き換えてください。
上記コードを実行したあとでMongoDBの画面へ行くとデータが追加されていることが確認できると思います。

![スクリーンショット 2022-03-12 15.59.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2536525/39c237da-efea-c2c1-a40a-91e06e696b7b.png)

これでDBのセットアップが完了しました。次回からユーザー登録機能の続きを実装していきます。
pythonでデータベースを使う sqlite3

## ライブラリをインポート
```
import sqlite3
```

## データベースを作成・保存
データベースのファイル名を決め、接続する。
データベースがなければ作成する
```
filename = ('stock.db')
conn = sqlite3.connect(filename, isolation_level=None)
```

## テーブルを作成してみましょう
executeでテーブルをどうするのか指示を出します
CREATE TABLE ：というテーブル作成
```python
import sqlite3
DB = ('stock.db')
conn = sqlite3.connect(DB, isolation_level=None)

cursor = conn.cursor()
sql = """CREATE TABLE stock(id int, name text,price int, dividend int)"""
cursor.execute(sql)
conn.commit()
conn.close()

```
## テーブルの値を挿入する
INSERT INTO ** VALUES：**というテーブルに値を挿入する
```python
import sqlite3
DB = ('stock.db')
conn = sqlite3.connect(DB, isolation_level=None)

cursor = conn.cursor()
cursor.execute("INSERT INTO stock VALUES (8591,'Orix',2338,86)")
cursor.execute("INSERT INTO stock VALUES (3244,'Samty',2078,90)")
conn.commit()
conn.close()
```
## 保存したテーブル情報を参照してみましょう
stockから全レコードを取得する。
SELECTの後に列名を記入することで、1列のみも取得できる
```python
import sqlite3
DB = ('stock.db')
conn = sqlite3.connect(DB, isolation_level=None)

cursor = conn.cursor()
sql = """SELECT * FROM stock"""
cursor.execute(sql)
print(cursor.fetchall())
conn.close()
```

## テーブル名の変更
ALTER TABLE A RENAME TO B：Aというテーブル名からBというテーブル名に変更
```
import sqlite3
DB = ('stock.db')
conn = sqlite3.connect(DB, isolation_level=None)

cursor = conn.cursor()

sql = """ALTER TABLE stock RENAME TO newStock"""

conn.execute(sql)
conn.commit()
conn.close()
```

## データベース情報をpandas形式に変更
```
import pandas as pd
import sqlite3

DB = ('stock.db')
conn = sqlite3.connect(DB, isolation_level=None)

df = pd.read_sql('SELECT * FROM stock', conn)
print(df.head())

conn.close()
````

## 動画
<iframe width="560" height="315" src="https://www.youtube.com/embed/kVXuyVkcXwU" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
00_Illustrator

ショートカットキー

shift x 線と塗りの入れ替え 
h 手のひらツール
z　ズームツール
ctl 0 元画面サイズ

ctrl y　アウトライン表示

ctrl 2 図形ロック

ctrl shift z 前に進む


#ロゴ作成選手権
ロゴ作成　参考サイド
https://www.youtube.com/watch?v=RnY9u-ZR8vE

参考サイト
https://www.youtube.com/watch?v=RnY9u-ZR8vE
例)
概要　デザインの会社
特徴　少人数、実力思考
目的・ゴール　会社の認知
コンセプト　光と影
印象　革新的や斬新さ

ロゴタイプ
1 シンボルマーク
キャッチなーマークで顧客を引き付ける
対象　BtoC

2 会社名
会社名を確実に認知してもらう。
対象　BtoB

3　シンボルマーク＋会社名
1と2のいい所取り
汎用性が高い。
対象　BtoC、BtoB

男性受けか
女性受けかという視点

#イラスト選手権

名づけ方法
https://kobostock.jp/kotsu-naming/
C# ObservableCollection<T>で大量の要素を追加したいとき

ObservableCollectionに大量の要素を追加したいとき
AddRangeみたいな一気に要素を追加するメソッドがないので、基本的には以下のように一個づつ要素を追加してあげる必要がある。
```ObservableCollection.cs
foreach (var item in items)
{
    // Collection = ObservableCollectionのインスタンス
    Collection.Add(item);
}
```
要素を追加するごとに、NotifyCollectionChangedイベントが発火するので
そのたびUIが更新されて、固まってしまう。
そこで以下のように、ObservableCollectionを継承してAddRangeのようなメソッドを作成する。
```ObservableCollectionEX.cs
public class ObservableCollectionEX<T> : ObservableCollection<T>
{
    public void AddRange(IEnumerable<T> addItems)
    {
        if (addItems == null)
        {
            throw new ArgumentNullException(nameof(addItems));
        }

        foreach (var item in addItems)
        {
            Items.Add(item);
        }

        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }
}
```
こうすることで、大量の要素が追加された後に一回だけ、NotifyCollectionChangedイベントが発火するので
比較的、UIが固まることなく更新される。

NotifyCollectionChangedEventArgsの引数は、以下を参考にNotifyCollectionChangedAction.Resetを設定する。

https://docs.microsoft.com/ja-jp/dotnet/api/system.collections.specialized.notifycollectionchangedaction?view=net-6.0
javaScript クロージャーってナンジャ

 ## javaScriptのクロージャーでちょっと詰まった話

javaScriptの学習を進めていくと、一度クロージャの壁にぶち当たる。

クロージャーに入る前に、まずは変数のスコープについておさらいしてみる。

```javascript:qiita.js
function test(val) {
  return val;
}

console.log(test('テスト')) // テスト

console.log(val); // エラー Uncaught ReferenceError: val is not defined at...
```

上記コードのように、関数内で定義された変数 val を関数外で取得しようとしても、エラーになり、これにはスコープが影響している。

スコープにはいくつか種類があり、それぞれ参照範囲が異なる。
詳しくはこちらの記事を参考にしてほしい。

[Javascript のクロージャについて](https://qiita.com/sekir11/items/2117cb4e8883f3011402)

:::note warn
おねがい
上記の記事で満足してしまうかもしれないが、この記事に戻ってきてほしい
:::


スコープの種類とクロージャーの概要について理解できたところで、ここからが本題。
私が詰まったところの説明をする。

```javascript:qiita.js
const counterGenerator = (val) => {
  let i = val;
  return () => i += 1;
}

const test = counterGenerator(0);
test(); // 1
test(); // 2
test(); // 3
test(); // 4
```

上記コードを理解いただけただろうか。
関数test() を実行するたびに、返される値が変化（今回はカウントアップ）していくのである。
私は、初めこれにかなりの違和感を感じた。
同じく違和感を感じた初心者諸君、これから一緒にコード内容を紐解いていこう。

:::note alert
注意
ここからは誤った解釈があるかもしれない。先に謝っておく。
（コメントで教えて下さい）
:::

まずはクロージャー部分
```javascript:qiita.js
const counterGenerator = (val) => {
  let i = val;
  return () => i += 1;
}
```
関数 counterGenerator は、数値型の引数を一つとり、返り値として関数を返す。

この関数 counterGenerator に引数0を渡して呼び出し、返り値 test を変数に入れてみる。
```javascript:qiita.js
const test = counterGenerator(0);
```

これで、変数 test には関数が代入された。
この test に、呼び出し演算子 () をつけて関数の呼び出しができる。
```javascript:qiita.js
test(); // 1
test(); // 2
test(); // 3
test(); // 4
```
この部分だ。何度みても違和感しかない。

関数 test() を実行するたびに、関数内の変数 i がカウントアップされ、その値が返されてくる。
今回はそういう関数を、関数 counterGeneratorn 内で定義した。

この変数 i をプライベート変数といい、外部から直接操作したり、取得することができない。

その名の通りプライベートな変数だ。

test() だとぱっと見、なんの関数を実行しているのかわからないため、改めて定義する関数名を気をつけないといけないと感じた。
例えば、countUp() とか。


javaScriptの奥は深い。また詰まったことがあったら投稿する。以上。
Googleの最新のAIエンジンは、画像処理を新たな次元に進化させる

こちらの記事は sciencealert Blog 英文の翻訳です。https://www.sciencealert.com/google-s-latest-photo-ai-makes-zoom-and-enhance-a-reality

皆さんもSF映画やテレビ番組をご覧になったことがあるのではないでしょうか。 顔のアップやナンバープレートなど、細部を強調するためにズームインするシーンもあります。そして、いわゆる拡散モデルに基づくGoogleの最新のAIエンジンは、このような芸当ができるようになっているのです。 これは、他の類似画像から超知的に推測し、カメラが当初とらえられなかったディテールを写真に加えるというもので、実は習得が難しいプロセスなのです。

この技術をGoogleはnatural image synthesisと呼んでいます。 このAIモデルは小さく、ブロック状、ぼやけた、ピクセル化された写真を自然により鮮明な画像に加工しくれます。原画と完全に一致しないかもしれませんが、人間の目としては十分に本物に近いと思います。
![56.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2298092/928eb5f4-1c06-8658-0453-638030b4657f.jpeg)
Googleはこの作業のために、実は2つの新しいツールをリリースしています。 SR3（Super Resolution via Repetitive Refinement）と呼ばれるもので、画像にノイズや予測できないものを加え、それを逆に除去することで、画像編集ソフトが休日の写真をシャープにするような効果が得られます。 SR3は、膨大な画像データベースと機械学習による確率的な計算によって、低解像度のブロック状画像からフル解像度の画像を生成することができるのです。

2つ目のツールは、CDM（拡散モデル）です。 Googleは、これらを「パイプライン」と呼び、SR3を含む拡散モデルを誘導して、画像の解像度を高品質に向上させることができるとしています。また、画像の画質も上げます。 強化されたモデルを使って、より大きな画像を作ることができるのです。 Googleは、異なる解像度で異なる強化モデルを使用することで、CDMは他の画像拡大方式に勝てるとしています。 
![55.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2298092/d0b30ee0-3e6e-427a-e68d-afb779dabc6e.jpeg)
要するに、SR3とCDMの最終結果は印象的です。 50人の人間のボランティアを対象とした標準的なテストでは、SR3が生成した顔画像が本物の写真と間違われる割合は約50％で、完璧なアルゴリズムであれば50％のスコアを達成することが期待されることを考えると、あまりにも印象的な結果であった。 この画像は、オリジナルと完全に一致するものではなく、高度な確率論的数学に基づいて慎重に計算されたシミュレーションであることです。

Googleは、2つのツールを互いに戦わせて結果を洗練させで、GAN（Generative Adversarial Network）などの他の選択よりも良い結果をもたらすと述べています。 Googleは、新しいAIエンジンとその関連技術から、顔やその他の自然物の画像を向上させるだけでなく、確率的モデリングの他の分野でも、さらなる成果を上げることを約束しています。
同様の画像拡大ツールは、ソフトウェアのダウンロードを必要とせず、オンラインのみで処理できる手軽なものが登場しています。 例：[VanceAI](https://vanceai.com/ja/image-enlarger/)、[Waifu2x](http://waifu2x.udp.jp/)などです。