OmniAICreator/Qiita-1.07M huggingface dataset:
fetch()でもaxios.get()でも解決しないリダイレクトループに遭遇した話

最近個人開発しているアプリでは、`@remix-run/node`の`fetch()`を使って特定のURLのメタ情報を取得するようにしていました。

あるとき、`https://engineerteam.note.jp/n/nb49d32f5bede`に対して`fetch()`を呼び出す機会がありました。

https://engineerteam.note.jp/n/nb49d32f5bede

```ts
const response = await fetch(url);
```

ところが、これを呼び出してみたところ`Premature close`というエラーが発生してしまいました。

```shell
/workspaces/example-app/node_modules/@remix-run/web-fetch/src/fetch.js:342
    const error = Object.assign(new Error('Premature close'), {
                                ^
Error: Premature close
    at TLSSocket.onSocketClose (/workspaces/example-app/node_modules/@remix-run/web-fetch/src/fetch.js:342:33)
    at TLSSocket.emit (node:events:525:35)
    at node:net:301:12
    at TCP.done (node:_tls_wrap:588:7)
```

色々オプションを設定してみましたが、エラーの発生を防ぐことはできませんでした。

```ts
const response = await fetch(url, {
  method: "GET",
  redirect: "follow",
  follow: 10,
});
```

調べてみても、同じような問題に引っ掛かっている人がいないため、なかなか答えを見つけられませんでした。
そこで、これは`fetch()`特有の問題なのかと思い、試しに`axios`を使ってみることにしました。


```ts
import axios from 'axios'
...
const res = await axios.get(url)
```

今度はより詳細なエラーが発生しました。
内容を確認してみると、リダイレクトの回数が多すぎるということがわかりました。
おそらく、`fetch()`でもこの問題が発生しているため`Premature close`というエラーが発生していたのだと思います。

```shell
Error [ERR_FR_TOO_MANY_REDIRECTS]: Maximum number of redirects exceeded
    at Function.AxiosError.from (/workspaces/example-app/node_modules/axios/lib/core/AxiosError.js:89:14)
    at RedirectableRequest.handleRequestError (/workspaces/example-app/node_modules/axios/lib/adapters/http.js:577:25)
    at RedirectableRequest.emit (node:events:513:28)
    at RedirectableRequest._processResponse (/workspaces/example-app/node_modules/follow-redirects/index.js:371:10)
    at NodeClientRequest.RedirectableRequest._onNativeResponse (/workspaces/example-app/node_modules/follow-redirects/index.js:62:10)
```

より詳細なエラーの内容がわかったので、これをもとに色々調べてみると、こちらの投稿を見つけました。

https://stackoverflow.com/questions/59851293/node-js-simple-get-with-axios-module-throwing-error-max-redirects-exceeded

投稿者の方が抱えていた問題の原因は、サーバー側によるクッキーを使ったステートの検証によるリダイレクトのループの発生のようです。
つまり、リクエスト先のサーバー側で、本来ならクエリーとして渡すべき情報をクッキーによって管理しているため、そのデータの有無により永遠にリダイレクトされるといった問題のようです。

つまり、ここで必要なのは**Cookie Jar**の機能ということになります。

Cookie Jarとは、簡単にいうと、特定のウェブサイトのクッキーを保存・管理するためのコンテナ機能のことです。
この機能がNode.jsで動作する`axios`や`fetch()`ではデフォルトでサポートされていないため、何も設定しない状態でリクエストを送っても先ほどのようなエラーが発生してしまいます。

そこで、この問題を解決するために`axios-cookiejar-support`というライブラリを使うことにしました。

https://github.com/3846masa/axios-cookiejar-support

今回、`axios`を使うにあたってレスポンスとして文字列ではなく`ArrayBuffer`としてデータを取得する必要があるため、`responseType: "arraybuffer"`を指定しています。

```ts
const jar = new CookieJar();
const client = wrapper(axios.create({ jar }));
const result = await client.get(url, {
  maxRedirects: 10,
  responseType: "arraybuffer",
});
```

実行した結果、無事エラーがでることなくレスポンスを取得することに成功しました。

リダイレクトループにハマってから原因を特定するまでに結構な時間を要してしまいました。
そもそも、何が原因で`Premature close`エラーが発生しているのかわからなかったためです。
みなさまも、同じような問題に遭遇した際は、クッキーの問題かどうかを考えてみると良いかもしれません。
【opencv&python】マスクの着用の有無を判定するプログラム 

## 導入
昨今の情勢でマスクの着用の有無を気にする人々が増えた。

今回はマスクの着用の有無を簡単に判定できるプログラムを紹介する。

## 内容
マスクの着用の有無の判定は以下二つの手法が考えられる。

1. マスク着用の有無のデータそれぞれを学習したモデルで判定
1. opencvを用いて判定

今回は簡単のため2を採用する。

opencvにおいてマスクの着用のプログラムの方針は以下である。
ここで、画像内には必ず顔が一つ写っていると仮定する。

1. opencvで画像内の顔を検出
1. 判定された顔領域内において、opencvで口を検出
1. 顔が検出できない場合または口が検出できない場合はマスクを着用、口がある場合はマスク未着用と判定

:::note warn
実用化を考えた場合は、顔を検出できない場合は判定不可とするべきである。

今回はマスクによって顔が隠れたため顔が検出できないと仮定した。
:::

それぞれの検出は`cascade`の`detectMultiScale()`を用いる。

また顔が検出された場合及び口が検出された場合に、それらが正しく検出されたかを確認するために画像内にバウンディングボックスの描画を行う。

バウンディングボックスは`cv2.rectangle()`で簡単に描画可能である。

ここで口の検出は以下のように偽陽性が多い。

![no_mask_incorrect.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/487820/9ac2daac-fe3f-65c1-1c60-71a52ff6a2a7.png)
以下の記事を参考に領域の削除を行う。

https://zenn.dev/sergicalsix/articles/f82eb4a5fcfc66



## プログラム


https://github.com/sergicalsix/Detection

```python
import cv2
import numpy as np

def detection_mask(img_path):
    face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
    mouth_cascade = cv2.CascadeClassifier('haarcascade_mcs_mouth.xml')
    
    img = cv2.imread(img_path)

    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    faces = face_cascade.detectMultiScale(gray, 1.3, 5)

    mask_flag = True
    if len(faces) > 0:
        (x,y,w,h) = faces[0] #最初の一人

        roi_gray = gray[y:y+h, x:x+w]

        roi_color = img[y:y+h, x:x+w]

        cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)

        tmp_mouth = mouth_cascade.detectMultiScale(roi_gray)

        if len(tmp_mouth) > 0:
            #tmp_mouth_len = len(tmp_mouth)
            tmp_mouth = tmp_mouth[np.argsort(tmp_mouth[:, 1])]
            (mx,my,mw,mh) =  tmp_mouth[-1] #口候補のうち一番下にあるもの

            cv2.rectangle(roi_color,(mx,my),(mx+mw,my+mh),(0,255,255),2)
            mask_flag = False

    if mask_flag:
        print('mask!!')
    else:
        print('no mask!!')
    
    cv2.imshow("Image", img)
    cv2.waitKey(5000)
    cv2.destroyAllWindows()
```
paiza.ioでnadesiko その4

# 概要
paiza.ioでnadesikoやってみた。
練習問題、やってみた。

# 練習問題
湯婆婆を書け。

# サンプルコード

```

「
契約書
甲は油屋当主として、乙を油屋に雇用することを契約し、
労働に伴う対価の支払いを右の通り、約定する。
なお、一日の労働の対価は金百円とする。
甲　油屋当主　湯婆婆

乙
契約書だよ。そこに名前を書きな」と尋ねる。
それを名前に代入。
「フン。{名前}というのかい。贅沢な名だねぇ。」と言う。
名前を文字列分解。
それを配列シャッフル
それの1から1文字抜き出して新しい名前に代入。
「今からお前の名前は{新しい名前}だ。
いいかい、{新しい名前}だよ。分かったら返事をするんだ、{新しい名前}!!」と言う。

```

# 実行結果

```
契約書
甲は油屋当主として、乙を油屋に雇用することを契約し、
労働に伴う対価の支払いを右の通り、約定する。
なお、一日の労働の対価は金百円とする。
甲　油屋当主　湯婆婆

乙
契約書だよ。そこに名前を書きなフン。マツコ・デラックスというのかい。贅沢な名だねぇ。
今からお前の名前はッだ。
いいかい、ッだよ。分かったら返事をするんだ、ッ!!
```

# 成果物

https://paiza.io/projects/Wn-eVDO2JGdWn5djOvqN1w


以上。
paiza.ioでnadesiko その3

# 概要
paiza.ioでnadesikoやってみた。
練習問題、やってみた。

# 練習問題
fizzbuzzを書け。


# サンプルコード

```

Nを1から100まで繰り返す
    もし、(N % 3 = 0)かつ(N % 5 = 0)ならば「fizzbuzz」と表示。
    違えば、もし、N % 3 = 0ならば「fizz」と表示。
    違えば、もし、N % 5 = 0ならば「buzz」と表示。
    違えば、Nを表示。
ここまで。


```

# 実行結果

```
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz
16
17
fizz
19
buzz
fizz
22
23
fizz
buzz
26
fizz
28
29
fizzbuzz
31
32
fizz
34
buzz
fizz
37
38
fizz
buzz
41
fizz
43
44
fizzbuzz
46
47
fizz
49
buzz
fizz
52
53
fizz
buzz
56
fizz
58
59
fizzbuzz
61
62
fizz
64
buzz
fizz
67
68
fizz
buzz
71
fizz
73
74
fizzbuzz
76
77
fizz
79
buzz
fizz
82
83
fizz
buzz
86
fizz
88
89
fizzbuzz
91
92
fizz
94
buzz
fizz
97
98
fizz
buzz

```

# 成果物

https://paiza.io/projects/RDjDbBRaYv82qQvSUvt9pw

以上。
paiza.ioでnadesiko その2

# 概要
paiza.ioでnadesikoやってみた。
おかしい、追加がおかしい。

# サンプルコード

```
A=「ABCDE」
B=「abcde」
AにBを追加。
Aを表示。　　　
＃ ABCDEabcdeが表示される
```

# 実行結果

```
ABCDE
```

# 成果物

https://paiza.io/projects/2ff5hoz0lTtvw74gULQRhA

以上。
Azure Databricks の使用量の確認方法

:::note
Unity CatalogのSystem Tableがリリースされた事で、[こちらの方法](https://qiita.com/maroon-db/items/b89d47009948206ac064)でも確認出来るようになりました。
:::


# はじめに

Databricksのコストを確認する方法は Azure と AWS/GCPでは異なります。AWS/GCPの場合は[こちら](https://qiita.com/maroon-db/items/ddb433882150824d31f6)です。理由はAzureの場合は Azureのサービスに組み込まれているため Azure Consoleから確認する必要があるためです。

# Azure Consoleから Databricksサービス費用を確認する方法

Azureサービスのコスト分析をする方法として、**コスト分析** というサービスメニューがあります。
[クイック スタート:コスト分析を使用してコストを調査および分析する](https://learn.microsoft.com/ja-jp/azure/cost-management-billing/costs/quick-acm-cost-analysis)

コスト分析でコストを確認するには、Azure portal でスコープを開き、メニューで [コスト分析] を選択します。 たとえば、 [サブスクリプション] に移動し、一覧からサブスクリプションを選択して、メニューから [コスト分析] を選択します。

コスト分析で別のスコープに切り替えるには、 [スコープ] ピルを使用します。


<iframe width="800" height="400" src="https://www.youtube.com/embed/mfxysF-kTFA" title="How to use Cost Management in the Azure portal | Azure Portal Series" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>


# Databricks使用量を確認

それではいくつかのパターンで見てみましょう。今回は**Scope**に**Subscription**が選択されているのを確認します。

### トータルコストの確認

filter条件で　**Service name** を選択。Valueに **azure databricks**を選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2206424/26202191-1970-bf3c-b2a9-30854ab72c18.png)



### Workspace単位でのコストの確認

Group by の箇所で**Resouce**を選択。　
(下の図はグラフを Columnに変更しているため見た目が異なってます。)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2206424/59456544-36fe-a07b-993f-607701829804.png)

特定のWorkspace環境を見たい場合は、Filter条件で選択すればOK

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2206424/154d61ec-c3fc-b59f-24d1-ed1a5ae53a01.png)


### Cluster Type毎の確認

All-Purposeや、Jobs,SQLなどのDBUタイプ毎に使用状況を確認するには **meter**を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2206424/de6d7fc2-8aa4-47a1-fe88-355fb328a9e7.png)


### Tag毎の確認

Tag毎の確認をするには、**tag**を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2206424/b5d9e8e6-ec4f-6edf-2026-94209c0005a6.png)


### Azureインフラコストの確認

Azureサービス側のストレージやVM費用の金額を確認するには、Scopeで　Workspaceが含まれている管理対象のResource Groupを選択します。その後グルーピングやフィルタを使用して、さらにコストを分割することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2206424/e9c9ae5c-d7d0-10b8-75b8-d688aa34f06e.png)


管理対象のResource Groupが不明という方は、サービスでAzure Databricksを検索して、対象のワークスペースをクリックすると以下のページが表示されます。こちらに管理対象のResource Groupが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2206424/69ee5e18-eb79-5262-074b-bb17a378e499.png)



### ダウンロード

手元で分析したい場合は、ExcelやCSVとしてダウンロード出来ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2206424/7bfbae9c-4fda-1db5-973f-6345ca07d387.png)


# 最後に

Azureとそれ以外で確認方法が異なるのはちょっと不便ですが、基本的に同じことは出来そうですし、インフラコストも含めて確認できるのは便利ですね。
paiza.ioでnadesiko

# 概要
paiza.ioでnadesikoやってみた。

# サンプルコード

```

「Hello world」と表示。
「なでしこのバージョン」と表示。
ナデシコバージョンを表示。
「ナデシコランタイム」と表示。
ナデシコランタイムを表示。
「コマンドライン」と表示。
コマンドラインを表示。
「ナデシコエンジン」と表示。
ナデシコエンジンを表示。


```

# 実行結果

```
Hello world
なでしこのバージョン
3.3.63
ナデシコランタイム
node
コマンドライン
/usr/local/bin/node,/usr/local/bin/cnako3,Main.nako3
ナデシコエンジン
nadesi.com/v3

```

# 成果物

https://paiza.io/projects/bSCUvwe_rvDeB1U0gJ6aow


以上。
入門GOプログラミング言語　Lesson1　Hello world

# Go言語とは
- コンパイラ言語
- C＋＋やJavaのように静的にコンパイルされる言語の安全性と性能を持ち、Pythonのような動的な型をもつインタープリタの軽さと楽しさがある言語
- メモリを効率よく使うことが容易で、エラーを起こしにくくなっている

## 私が学ぶ動機
将来的にサーバーサイドの主流になるといわれているGo言語をエンジニアとして学ばなければいけないと思ったから

## 開発環境
Go Playground
- https://goplay.tools/

### パッケージと関数

```go
package main

import (
	"fmt"
)

func main() {
	fmt.Println("Hello, 世界")
}
```

- `package` : ソースファイルのコード群のこと（Pythonでいうモジュールかな？）
- `import` : このコードが使用するパッケージを指定 `()`でくくる
- `main`パッケージの`main`関数から実行が始まる

```golang:関数の定義
func main() {
fmt.Println("Hello World!!")
}
```
セミコロンをつける必要がない

```go:
func main() 
{
fmt.Println("Hello World!!")
}
```
波かっこの場所が悪いからエラーが出る

### 練習問題(10ページ)　解答例
```golang
package main

import (
	"fmt"
)

func main() {
	fmt.Println("Hello, world")
	fmt.Println("Hello, 世界")
}
```

----
メモ
随時更新中
切り取り&スケッチで直接の蛍光ペンを引く【Windowsスクショ】

定規を使いましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3127414/8c287d65-9562-1016-9edb-d04be309289a.png)
HTMLメモ:button要素のtype属性について

JavaのservletやJSPの勉強でHTMLの勉強をもう一度やるにあたって
`<button>`要素の勉強をすることになった
# button要素のtype
type属性はbuttonにおいて、どのような動作をするボタンかを指定できる。
既定の指定。
- `type="submit"`
サブミットボタン。
フォームの入力内容をサーバに送信する。
- `type=reset`
リセットボタン。
フォームの入力内容をリセットする。
- `type=button`
何の既定の動作もないボタン。
マクロでjsonデータを作ってみる

```makuro
Sub Macro1()

    '型定義
    Dim wb As Workbook
    Dim ws As Worksheet
    Dim startDt As Date
    Dim endDt As Date
    Dim countd As Integer
    Dim timestamp As String
    Dim A As String
    Dim B As String
    Dim C As String
    Dim K As String
    Dim jsonData As String
    Dim jsonOutput As String
    Dim jsonList As String
    
    Set wb = ThisWorkbook
    Set ws = wb.Sheets("Sheet1")
    
    '日付範囲の設定 CDate = 文字列2023/2/2をDate型に変換
    startDt = CDate(ws.Range("B1").Value)
    endDt = CDate(ws.Range("C1").Value)
    
    'JSONデータの生成
    For D = startDt To endDt '(例: 2023/2/2～2023/2/5)分ループ
        'データの取得
        timestamp = Format(D, "yyyymmdd")
        A = ws.Range("B2").Value
        B = ws.Range("B3").Value
        C = ws.Range("B4").Value
        K = ws.Range("B6").Value
        countd = ws.Range("B5").Value 'ネストJSON数
        
        'JSONデータの生成
        jsonList = ""
        If countd > 0 Then
            For i = 1 To countd
                jsonList = jsonList & """count" & i & """:{""あいう"": " & K & "}"
                If i < countd Then
                    jsonList = jsonList & "," 'jsonList生成した"count1": {"K": 4000}を「,」で繋ぐ
                End If
            Next i
            jsonList = """list"": {" & jsonList & "}" '"count1": {"あいう": 4000},"count2": {"あいう": 4000}
        Else
            jsonList = """list"": {""number"": 0, ""D"": " & D & "}"  '←無くても良い。
        End If
        
        '取得したデータまとめる
        jsonData = "{""timeStamp"": " & timestamp & ", ""A"": " & A & ", ""B"": " & B & ", ""C"": " & C & ", " & jsonList & "}"
        
        'JSONデータを配列に追加
        jsonOutput = jsonOutput & jsonData
        If D < endDt Then
            jsonOutput = jsonOutput & ","
        End If
    Next D 'ループ終了
    
    'JSONデータの出力
    Open "C:\Users\socia\OneDrive\デスクトップ\output.json" For Output As #1
    Print #1, "[" & jsonOutput & "]"
    Close #1
    MsgBox "JSONデータ生成完了"
End Sub



```

![スクリーンショット 2023-03-04 095732.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677104/5588c9ca-4934-d0c6-689a-be2b1982752f.png)


<h1>意味</h1>

```
■ For Next
For カウンタ名 = 初期値 To 到達値
    処理
Next カウンタ名
→
JavaScript：
　var startDate = new Date("2023-02-01");
　var endDate = new Date("2023-02-03");
　for (var d = startDate; d < endDate; d.setDate(d.getDate() + 1)) {
 　 console.log(d.getFullYear() + '/' + (d.getMonth() + 1) + '/' + d.getDate());
　}

■ if For
→B5セルの入力値が0より大きければ、ループ(For)する。
 →1～カウント数分ループ。
 If countd > 0 Then
  For i = 1 To countd
    ～～～～～～
  Next i
 End If

■ jsonData = 
→ネストjson作成のため、親objとその中で生成される子objを1つのjsonに連結するため。
{"timeStamp":20230202,
 "A":1000,
 "B":2000,
 "C":3000,
 "list":{
   "count1":{"あいう":4000},
      "count2":{"あいう":4000}
     }
}

■ jsonOutput = jsonOutput & jsonData
→jsonDataと同様に、jsonDataは各日付毎に親と子objを連結して1日単位で1つのjsonを生成していました。
 jsonOutputでは、jsonDataで1日単位のjsonを連結して範囲内の日付を連結した1つのjsonを生成します。
→例：
    {
        "timeStamp": 20230201,
　　　　~~~~~~
    },
    {
        "timeStamp": 20230202,
       ~~~~~~~~
    },

```
XPシード、エンチャントテーブルクラッキングって何???

こんにちは、Unknown(Akkey57492)です。
この記事では、Minecraftの「Xpシード」と「エンチャテーブルクラック」について少し説明します。

私自身ほとんどやったこともないですし、成功したことも無いので...まぁ頭の片隅に入れておく程度でどうぞ。

# まず前提知識
とりあえずXpシードやらエンチャクラックやらわけわからないと思います。
これらを簡単に説明しますね。
### Xpシードとは?
Xpシードとは、いわゆるエンチャントテーブルに使われるシードです。
ランダムにエンチャントを行えるように、シードが用意されているんです。
### エンチャントテーブル クラッキングとは?
松明(ほとんどの場合)を利用して、Xpシードをクラッキングします。
そして、自分が欲しいエンチャントを設定して乱数調整します。
そうすると、エンチャントテーブルからクッソ強いエンチャントを手に入れる事が出来ます。

# なぜそこまでしてクラッキングを?
正直、Xpシードの特定や、その後の乱数調整ははたから見ると面倒くさそうです。
ただ、実際は慣れれば20分足らずでクラッキングできてしまいます。

クラッキングすると「好きなエンチャント」を「複数」つけれます。
もっと簡単にまとめると

- エンチャントほしい
- 超楽して最強のエンチャントしたい
- エンチャテーブルクラックしてエンチャントつけよう

って事ですね(?)

# それやばくね? どうやって対策するの...
簡単です。
PaperMCやPaperMCのforkにサーバーを変更しましょう。
「へ?」と思うかもしれませんが、本当にそれだけです。

PaperMCは、クラッキングに対する対策が充てられています。
そのためサーバーソフトを変更するだけです。

ただ、別の解決方法はありません。
プラグインやほかのツールを利用した阻止は現実的ではありません。

# まとめ
いかがでしたでしょうか。
この記事は、対策ってよりはXpシードについて話したかっただけです...w
しっかりと対策をしないと、どっかのたけのこみたいになります(あそこはPaperだったのでできませんでしたが)

- PaperMCへの変更を推奨
- どれだけ小規模でもあり得る

これらのことを肝に銘じて、サーバー運営を頑張ってください!

では :)
「スッキリわかるSQL入門」で詰まったところ②



# 目次

[1. はじめに](#1はじめに)
[2. 今回のゴール](#2今回のゴール)
[3. 詰まったところと原因](#3詰まったところと原因)
[3-1. シングルクォーテーションとダブルクォーテーションが曖昧](#3-1シングルクォーテーションとダブルクォーテーションが曖昧)
[復習：部分検索](#復習部分検索)
[3-2. テーブルに入っているデータ同士を比較する方法を知らない](#3-2テーブルに入っているデータ同士を比較する方法を知らない)
[3-3. UPDATEの基本構文が曖昧](#3-3updateの基本構文が曖昧)
[4. おわりに](#4おわりに)


# 1.はじめに

現在、基本的なSQL文が書けるように下記の書籍を進めています。

https://www.amazon.co.jp/%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%8F%E3%81%8B%E3%82%8BSQL%E5%85%A5%E9%96%80-%E7%AC%AC3%E7%89%88-%E3%83%89%E3%83%AA%E3%83%AB256%E5%95%8F%E4%BB%98%E3%81%8D-%E3%82%B9%E3%83%83%E3%82%AD%E3%83%AA%E3%82%8F%E3%81%8B%E3%82%8B%E5%85%A5%E9%96%80%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E4%B8%AD%E5%B1%B1/dp/4295013390/ref=asc_df_4295013390/?tag=jpgo-22&linkCode=df0&hvadid=553968464768&hvpos=&hvnetw=g&hvrand=14494930281878848962&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1009461&hvtargid=pla-1598950080935&psc=1&th=1&psc=1

各章に練習問題があり、詰まったところをまとめていきたいと思います。

▼①はこちら

https://qiita.com/mihooo24/items/550849acce20ee1d3504


# 2.今回のゴール

「なぜ間違えたのか」を理解して落とし込むこととします。


# 3.詰まったところと原因

## 3-1.シングルクォーテーションとダブルクォーテーションが曖昧

部分検索のSQL文を考える問題がありました。

リテラルにダブルクォーテーションを使用したところ、エラーとなりました。

```sql
SELECT * FROM 家計簿
-- "%購入%"とするとエラーになる
WHERE メモ LIKE '%購入%'
```

ダブルクォーテーションを使用する場合もあるようですが、基本的にシングルクォーテーションを使うようです。

https://style.potepan.com/articles/24875.html#SQL

### 復習：部分検索

| 項目 | 内容 | 
|:-----------|:-----------|
| _（アンダースコア）| 任意の1文字 | 
| %| 任意の0文字以上の文字列 | 
| '%購入%'| 文字列を含むもの | 
| '%購入'| 最後に文字列を含むもの（今回だと「〜購入」など） | 
| '購入%'| 最初に文字列を含むもの（今回だと「購入〜」） | 

## 3-2.テーブルに入っているデータ同士を比較する方法を知らない

以下のような成績表のテーブルがあるとします。

| 名前 | 英語の点数 | 数学の点数 | 
|:-----------|:-----------|:-----------|
| 太郎くん| 80 | 80 | 
| 花子さん| 70 | 92 |

これまで「太郎くんの英語の点数は70点より高いか低いか」というような **「テーブル内のデータと指定されたデータの比較」** をする問題はありました。

しかし、今回の成績表テーブルにおける「英語と数学の点数が一致しているデータ」というような **「データ同士の比較」** をしたことがなく戸惑いました。

一致するデータ、一致しないデータを取得するSQL文は以下のようになります。

```sql
-- 一致するデータ
SELECT *
FROM 成績表
WHERE 英語 = 数学 -- 太郎くんのデータが取得できる

-- 一致しないデータ
SELECT *
FROM 成績表
WHERE 英語 <> 数学 -- 花子さんのデータが取得できる
```

## 3-3.UPDATEの基本構文が曖昧

前回の記事と同じ見出しになってしまいますが、またUPDATEのところで詰まってしまいました…

基本構文は以下です。

```sql
UPDATE テーブル名
SET 列名1 = 値1, 列名2 = 値2 ...
(WHERE 修飾)
```
複数の列に対して同じ値を更新する場合はIN句を使用します。
▼例：値1と値2を含むデータのA列の値を一括でBにする場合

```sql
UPDATE テーブル名
SET 列名A = 値B
WHERE 式(列名が来ることもある) IN (値1, 値2) --カッコ内に列挙した複数の値のいずれかにデータが合致するか判定
```

# 4.おわりに

今回も前回に引き続き、参考書を進める中で詰まった3箇所について復習していきました。

原因を掴んで理解することが、上達への近道ではないかと思います。実務では複雑なものもあったりするので、自己学習で一つずつ紐解きながら積み上げていきたいと思います。

読んでいただき、ありがとうございました。
RaspberryPi with Python環境のアップデートコマンドまとめ

## Python ライブラリアップデート
```sh
pip-review --auto
```
pip-reviewが使えなかった場合
```sh
pip3 freeze --local | grep -v '^\-e' | cut -d = -f 1 | xargs pip3 install -U pip
```

## RaspberryPi ディストリビューション、ライブラリ、ファームウェアアップデート
```sh
sudo apt update
sudo apt -y upgrade
sudo apt dist-upgrade -y
sudo rpi-update
sudo apt autoremove -y
sudo reboot
```
10分でできるGasからChatGPTを呼び出す方法

# APIのKeyを生成する

・OpenAIのサイトでAPIキーを作成
[OpneAiのサイト](https://openai.com/product)

・ アカウント作成後、PersonalのView API KEysをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/ba993d61-73c3-6030-0f4f-a851f0f9beae.png)


・Create New secret Keyをクリック
すぐに秘密鍵が作成されるので、表示された秘密鍵をコピー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/d46586e3-0fc4-a5c1-afdb-ce563176b8c2.png)

## Google Apps Script
・googleスプレットシートを作成し、拡張機能のApps Scriptをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/d59091e0-471e-6e78-8c7f-d3f7cca52fca.png)

・設定ボタンのスクリプトプロパティに先ほどの秘密鍵を登録
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/e98aab2c-8952-0865-7110-5ce74d018ecd.png)

・スクリプトを作成
max_tokensは文字数ですので、必要に応じて変更してください
```gas

function ApiChatGPT() {
  const apiKey = ScriptProperties.getProperty('ChatGPTAPIKey');
  const apiUrl = 'https://api.openai.com/v1/chat/completions';
  const messages = [{'role': 'user', 'content': 'ChatGPTをどう使ったらよいですか？'}];
  const maxTokens = 500;
 
  const headers = {
    'Authorization':'Bearer '+ apiKey,
    'Content-type': 'application/json',
    'X-Slack-No-Retry': 1
  };
  const options = {
    'muteHttpExceptions' : true,
    'headers': headers, 
    'method': 'POST',
    'payload': JSON.stringify({
      'model': 'gpt-3.5-turbo',
      'max_tokens' : maxTokens,
      'temperature' : 0.9,
      'messages': messages})
  };
  const response = JSON.parse(UrlFetchApp.fetch(apiUrl, options).getContentText());
  console.log(response.choices[0].message.content);
}

```

・実行ボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/acaeffbf-03b5-a5ba-d2ab-7ec4b659d2cc.png)

・初めて実行する場合は承認する必要があります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/807e1ed6-5760-4297-54ac-cc62806716d7.png)

# 無料枠について
・下記にアクセスしてあとどれくらい使用できるか確認できます
https://platform.openai.com/account/usage

他の情報だと18ドル分使えるとのことでしたが、2023/3/4時点だと無料枠は5ドルでした
無料枠が終わった後は下記の金額になります
※暫く運用してどれくらいで無料枠を使いきるか検証したいと思います

1000トークンあたり、約0.2円 ($0.002)
&&演算子と||演算子の挙動

IF分やwhileループなどによく使われる&&と||だが、私はよく挙動を勘違いするのでメモ。

#### &&演算子
&&演算子は左辺の式をまず評価する。左辺の式の値がfalseに変換される場合、左辺の式をそのまま返す。右辺の値は評価しない。もし、左辺の式がtrueに変換される値の場合、右辺の式を評価し、その値を返す。
例:
``` javascript
false && true; // false
'' && 'foo';   // ""
2 && 0;        // 0
'foo' && 4;    // 4
```
#### ||演算子
||演算子は左辺の式をまず評価する。もしこの式の値がtrueの場合、左辺の式をそのまま返す。右辺の値は評価しない。もし左辺の値がfalseに変換される値の場合は右辺の式を評価しこの値を返す。
例：
``` javascript
false && true; // true
'' && 'foo';   // 'foo'
2 && 0;        // 2
'foo' && 4;    // 'foo'
```
※注意
&&演算子と同じように、右辺の式が評価させれない場合があることを意図的に利用したい場合を除けば、副作用を伴う式を右辺の式に利用しない。
``` javascript
// maxWidthがtrueに変換される値であれば、この値を使う。falseに変換される値であれば、
// preferencesオブジェクトの値を使う。この値もtrueに変換される値でなければ、定数を使う。
let max = maxWidth || preferences.maxWidth || 500;
```

#### 参考
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_AND

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_OR
Azure関連の最近の記事のメモ 2023/03/04


https://azure.microsoft.com/ja-jp/blog/3-microsoft-azure-ai-product-features-that-accelerate-language-learning/

言語の学習にAIプロダクトを活用できることが紹介されています。

1. Azure Cognitive Servicesのテキスト翻訳機能で、この機能を使用することで、複数の言語間でテキストを簡単に翻訳できます。
1. Azure Cognitive Servicesの言語理解機能で、この機能を使用することで、文章の意味を理解し、自然言語での応答を生成できます。
1. Azure Machine Learningのテキスト分類機能で、この機能を使用することで、テキストを分類し、自動的にラベル付けできます。

事例としてはPearson、Beijing Hongdandan Visually Impaired Service Center、Duolingo、HelloTalk、Berlitzがあげられていました。

https://azure.microsoft.com/ja-jp/blog/whats-new-in-azure-data-ai-azure-is-best-place-to-build-and-run-ai-workloads/

* Azure Machine Learningは、MLOps、オープンソースの相互運用性、データプライバシー、セキュリティ、およびリアルタイムデータ処理をサポートする統合ツールです
* Microsoft Intelligent Data Platformは、T-Mobile、BP、Amadeusといった業界のリーダー企業が活用しています
* 今月プレビュー版として発表されたMicrosoft PurviewのAdaptive Protectionは、Insider Risk Managementの機械学習を活用し、人々がどのようにデータに接しているかを分析するのに活用できます
* Responsible AI Toolboxは、AIシステムの説明可能性（explainability）、バイアスの検出と軽減、プライバシー保護、倫理的配慮など、Responsible AIに関するさまざまな側面をカバーするツールが含まれています。例えば、Fairlearnというツールは、データセット内のバイアスを検出し、軽減するためのツールであり、InterpretMLは、AIモデルの決定根拠を解釈するためのツールであり、Data Protection Managerは、プライバシー保護のためのツールです。Responsible AI Toolboxは、開発者やデータサイエンティストがAIシステムのResponsible AIを実現するために使用できる一連のツールであり、企業がより正確で信頼性の高いAIシステムを構築することができるよう支援しています。
* Responsible AI mitigations libraryは、ツールボックスのFairlearn公平性評価ツールを補完するもので、モデルのトレーニング中に適用される緩和策に重点を置いています。
* Responsible AI trackerは、モデルの比較と検証を容易にするために、さまざまな緩和策の有効性を示すビジュアライゼーションを使用しています。

https://azure.microsoft.com/ja-jp/blog/farming-from-space-how-orbital-data-is-unlocking-novel-agriculture-insights/

気象データの分析にAzureのHPCを活用しているという話です。

Tomorrow.ioと協業し、地域に密着した高解像度の気象予測モデルへのアクセスが可能になり、主に気候変動に強い農業の支援と零細農家の収穫生産性の最適化支援に取り組んでいるそうです。

気象データの分析に活用されているのがAzure HBv2 VMです。各Azure HBv2 VMは、120個のAMD EPYCTM CPUコアと480GBのメモリを搭載し、計算流体力学、陽解法有限要素解析、地震処理、貯水池モデリング、気象シミュレーションなどのアプリケーションで力を発揮しています。

https://azure.microsoft.com/ja-jp/blog/microsoft-and-rockwell-automation-collaborate-on-digital-solutions-for-manufacturers/

マイクロソフトとロックウェル・オートメーションが提携し、製造業におけるデジタルソリューションの開発に取り組むそうです。
AzureのIoTサービスやAIツールを活用して、生産ラインの監視や制御、生産設備のメンテナンス、品質管理などの業務を改善するためのデジタルソリューションを開発することが計画されています。

https://blogs.windows.com/japan/2023/02/24/hololens2-informatix-gyroeyeholo/

インフォマティクスが提供するMR投影ソリューション「GyroEye Holo TS+」は、建設業界で使われる2D CAD図面や3Dモデル、画像ファイルをMRデータに変換するシステムで、マイクロソフトのHoloLens 2で現実の空間にホログラムを表示することができます。

GyroEye Holo の開発時の壁は「HoloLens 2 の空間認識可能範囲」

* 千代田測器の自動追尾トータルステーション「杭ナビ」との連携で解決できた。
* 自動追尾トータルステーションはワンマン測量や ICT 建機との連携などで利用される測量機器。
* 本体から 100～130 メートルの測定範囲を持つ杭ナビと HoloLens 2 を Wi-Fi で接続することで、広い範囲の位置情報を正確に MR データと合成して重ねて確認できるようになった

GyroEye Holo TS+ の優れた点

* 通常、MR は位置合わせ時に現場に AR マーカーを設置して認識させる。マーカー設置にわずかでも狂いがあった場合は、特に道路のような大きなモデルでは、位置や角度を精度高く表示させるのは困難です。
* GyroEye Holo TS+ は、杭ナビによる既知点の設定後、その情報を MR デバイスに転送することで、マーカーを一切使わずに、自動で図面やモデルを正確に現実空間に重畳できる
* ヘルメットに付けたプリズムと杭ナビでMRデバイスの位置を常に高精度に追跡することで、数 10 メートル移動してもズレが大きくならない補正機能が実装されている

完成形がわかる利点

* 若手社員への教育にも活用できる
* 遠隔地からリアルタイムで作業指示や検査確認も可能となる
* 地元住民への説明や発注元の立ち会い検査の際に MR で完成形を共有できる
GASをVS Codeで全部書きたい(既存PJT・デプロイ)

# はじめに
GASのスクリプトをChromeで書くと，拡張機能とか使えなくてめんどくさいので，VS Codeにて環境構築（？）をしました．（お気持ちは「さいごに」に書きました）

https://qiita.com/Lintaro/items/d9633ddd2140202bb438

基本的には上の記事に従って，諸々インストールして，```clasp create "TITLE"```で新規プロジェクトを作成して，終わりです．
ただ，
<b>1. 新規プロジェクトではなく，既存のを引っ張りたい</b>
<b>2. デプロイの方法がよく分からない</b>
ので，この記事にまとめました．

# 既存のPJTを引っ張って書きたい場合
## 選択肢1：
```
clasp clone
```
でプロジェクトを選択する

## 選択肢2：
選択肢1で選択したいものが表示されればよいのですが，されないときもあります．（ファイル構成がごちゃってるとか？）
そんなときは，```clasp login```した後に，appscript.jsonと.clasp.jsonを書きます．

```appscript.json
{
  "timeZone": "Asia/Tokyo",
  "dependencies": {},
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "webapp": {
    "executeAs": "USER_DEPLOYING",
    "access": "ANYONE_ANONYMOUS"
  }
}
```

```.clasp.json
{
"scriptId":AppScriptのURL中の，固有そうな文字列
"rootDir":PJTを起きたい場所
}
```
の2つを書き，
```
clasp pull
```

# デプロイ
```clasp deploy```
これで万事解決かと思いきや，，deploymentIdが変更されるから，めんどくさい
（Lineの設定画面にあるWebhook URLを毎回変える必要がある）

なので，

https://github.com/google/clasp#deploy

に従って，```clasp deploy --deploymentId abcd1234 (redeploy and create new version)```的な風に書く
ただ，これだと毎回deploymentIdを指定する必要があり，めんどくさい
そのため，batファイルを作り，
```deplot.bat
clasp push & clasp deploy -i --deploymentId -d %1
```
これを，```./deploy.bat 適当なコメント（スペースなし）```の様に書くと，push,deployがされて幸せになる

<b>deploymentId</b>はAppScriptの「デプロイ」→「デプロイ ID」から見ることが出来る．
（Windows以外の方は，.batじゃなくて.shにすればいけるのかも？）
（&を書かずに複数行で書いた時，最初の行しか実行されないのはなぜ...）

# 最後に
最初の方はChromeで書いていたが，スペルミスが連発し嫌になったのでまとめました．拡張機能モリモリのVS Codeはやはり良い．
あと，毎回「デプロイ」→「デプロイを管理」→「編集マーク」...とクリックの回数が減って超楽になった．
Discord.js/voiceで音楽Botを作っている方へ 注意喚起

## Discord音楽Botがバグり始めた
具体的な内容としては、数十秒経過したあとに自動で停止され、解除できないというものです。これはDiscord.jsが悪いわけではなく、Discord API側の仕様のようです。

## 対策
VoiceConnectionを呼び出した後に
```javascript
VoiceConnection.on('stateChange', (old_state, new_state) => {
    if (old_state.status === VoiceConnectionStatus.Ready && new_state.status === VoiceConnectionStatus.Connecting) {
        VoiceConnection.configureNetworking();
    }
});
```
を挿入するだけです。
数十秒ごとに短い沈黙がありますが、まぁ個人開発の用途であれば気にする必要はないでしょう。
なんにせよ、そのうちDiscord.js側で対応してくれると思います。

それまで少し辛抱しましょう。

### 追記
Discord側でVCのロケーション設定をシンガポールにすると上のコードを追加しないでも普通に再生されるようです。

### 更に追記
やはりAPI側のようです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2920761/385bf956-3cf7-858c-0c94-8a935f40f661.png)

https://discord.com/channels/222078108977594368/992166350640386090/1080624069097041951

そのうちほぼ確実に修正されるでしょう(discordjs側で)

この変更がかなり重大なイシューを引き起こしたようなので一時的に変更を戻しているようです。
3/16にもう一度有効化されるようなのでDiscord.jsにアプデがくるまで待ちましょう。
Googleデジタルマーケティング＆Eコマース：デジタルマーケティング＆Eコマースとは？

# はじめに

”Googleデジタルマーケティング＆Eコマース プロフェッショナル認定証"　の受講が完了しました(2022/3/3)。私がこのコースから得られた素晴らしい体験を、テーマごとに分割して、わかりやすくご紹介しています。興味を持たれた方は、是非下記を受講してみてください。

https://jp.coursera.org/professional-certificates/google-digital-marketing-ecommerce

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2358573/77505f22-0d8f-b3af-4f9c-ed148bcefd65.png" width="800">

# Eコマースとは？

Eコマースとは、オンラインで商品やサービスを売買することを指す広義の言葉です。

| 分類  | 例  | 
| :--- | :--- | 
| モノ | 書籍や家庭用品など | 
| デジタル | 電子書籍やオンライン講座など | 
| サービス | 旅行や通院など | 
| ソフト | ワープロや写真編集ソフトなど | 

Eコマースビジネスを始めるにあたって、実店舗は必要ありません。多くの小売業者は、実店舗とEコマースサイトを併設していますが、完全にオンラインで展開している業者もいます。

店舗を維持するコストがかからないため、これまで以上に簡単にビジネスを始められるようになり、世界中の多くの人々がオンライン市場に参入するようになったのです。

しかし、それは同時に、Eコマース市場が急速に混み合ってきたことも意味しています。そのため、企業は自社を差別化し、顧客の注目を集めるために広告をオンライン化し、それがデジタルマーケティングにつながったのです。

# デジタルマーケティングとは？

デジタルチャネルとは、企業がオンラインでターゲットとする消費者に到達するために使用できるあらゆる通信手段やプラットフォームのことです。

***<font color="MediumVioletRed">『消費者を顧客にすることを目的に、デジタルチャネルを通じてオンライン上で消費者にアプローチすること』</font>***

デジタルチャネルは

- ウェブサイト
- 検索エンジン
- 電子メール
- ソーシャルメディア・プラットフォーム

がこれにあたります。

つまり、Eコマースとデジタルマーケティングの関係性は、こうなります。

| 分類  | 内容  | 
| :--- | :--- | 
| Eコーマス | オンラインで製品を販売することを目的とする | 
| デジタルマーケティング | それを実現するためにビジネスを支援する　| 

# デジタルマーケティングの利点

デジタルマーケティングは、印刷広告や看板などの従来のマーケティングと似ていますが、企業と消費者の双方にとって、さらにいくつかの利点があります。

#### <font color="MediumBlue">費用対効果が高い</font>

広告予算は、テレビ、ラジオ、印刷メディアで行うよりも、オンラインで行う方がはるかに多くなります。これは、デジタルマーケティング担当者が、適切な広告を、適切なオーディエンスに、適切なタイミングで提供することを、非常に具体的に行えるからです。

また、ソーシャルメディアなどのプラットフォームを通じて、お客さまが情報を広めてくれる可能性もあります。

#### <font color="MediumBlue">多くの人々にリーチする</font>

新聞やラジオ局などのローカルなプラットフォームに依存する従来のキャンペーンよりも、より多くの人々にリーチすることができます。

デジタルマーケティングは、新しい、時にはグローバルな市場でブランドを認知させ、売上を伸ばし、さまざまな人々が製品やサービスを利用できるようにすることができるのです。

#### <font color="MediumBlue">より早く結果を出す</font>

紙媒体の新聞広告で欲しい商品に出会っても、後でその商品を購入することを覚えているかどうかは別です。しかし、デジタル広告では、お客様がその場でアクションを起こすことができるため、購入に至る可能性が高まります。

#### <font color="MediumBlue">顧客との信頼関係を構築する</font>

企業は直接的なコミュニケーションを通じて顧客との関係を構築することができます。Eメールやソーシャルメディアなどのチャネルでは、従来のマーケティングでは太刀打ちできないパーソナライゼーションのレベルが実現できます。

この数十年の間に、Eコマースとデジタルマーケティングはビジネスを根本的に変えました。Eコマースの目的は売上を上げることですが、デジタルマーケティングは顧客とつながり、関係を構築することで、ビジネスの成功を支援します。
蟹さんのイーサーネットコンバータ

mrubyも動かしている蟹さんのルーター兼イーサーネットコンバータをノーマルで使ってます。

つないでるのではZRouterでビルドした自作オーディオプレーヤーでmpg123を動かしてmp3のストリーミングをきいています。

WBGOをきいていたときにはあまりなかったのですが、JAZZ Sakuraをきいているとセッションが頻繁に切れます。

自作オーディオプレーヤーも疑ったのですがLANにつないで試したところ9時間以上試して問題がなかったので白だと思います。

JAZZ Sakuraはカナダの会社が運営しているようで、tracerouteで見るとWBGOより遠いです。

現象的には自作オーディオプレーヤーにtelnetで入ってmpg123を起動しているのですが、おそらくtelnetの通信に障害が発生してFreeBSDがtelnetを落としてしまい、結果mpg123も落ちるという感じです。

再生中はmpg123のコマンドオペレーションも反応が悪いです。

切れた後にFreeBSDのログを見るとEtherがDownしたログが残っているので、蟹さんがリブートしているのかもしれません。

パケットの流れ方によって、不具合が発生してしまうのかもしれません。負荷の低い使い方であれば問題なさそうなんですが。

蟹さんは11nですが、古いMarvellの11gのモジュールを試したら安定してます。mp3のストリーミングは11gでも十分です。

やっぱ蟹だね。
Notion APIでデータベースを操作する

NotionAPIを使うことで、Notion上のデータベースを効率的に操作することができます。
Notion上で日記を書いているのですが、効率的に書きたいことがあったので調査しました。
ここでは、NotionAPIを使って、データをフィルターするAPIとデータを追加するAPIの記述方法をメモ程度に残します。

今回はPythonを使用します。

# 事前準備
Notion側でAPIを使うための設定が必要になります。
以下の記事を参考にしてください。
https://programming-zero.net/notion-api-setting/

NotionAPIでデータベースを操作するにはデータベースIDが必要です。
データベースのURLをコピーし、`https://www.notion.so/`と`?v=`後に続く部分がデータベースIDになります。

以下のようなURLであった場合、`testa12345cd67890ef12ab34cd5test`がデータベースIDになります。
```
https://www.notion.so/testa12345cd67890ef12ab34cd5test?v=...
```

# データをフィルターする
NotionAPIで特定のデータを取得することができます。
たとえば、今日の日付に該当するデータを取得する場合、以下のように記述します。

```python
import requests
import datetime
import pytz

today = datetime.datetime.now(pytz.timezone('Asia/Tokyo'))
date = format(today, '%Y-%m-%d')

url = "https://api.notion.com/v1/databases/" + DATABASE_ID + "/query"

headers = {
    "Accept": "application/json",
    "Notion-Version": "2022-06-28",
    "Authorization": "Bearer " + NOTION_API_KEY
}

# データ取得
data = {
    "filter": {
        "property": "日付",
        "date": {
            "equals": date
        }
    }
}

response = requests.post(url, headers=headers, json=data)
data = response.json()
print(data)
```

# データを追加する
NotionAPIを使って、データベースに新しいデータを追加することができます。
たとえば、今日の日付に該当するデータを追加する場合、以下のように記述します。

```python
import requests
import datetime
import pytz

today = datetime.datetime.now(pytz.timezone('Asia/Tokyo'))
date = format(today, '%Y-%m-%d')

headers = {
        "Accept": "application/json",
        "Notion-Version": "2022-06-28",
        "Authorization": "Bearer " + NOTION_API_KEY
}

url = 'https://api.notion.com/v1/pages'

# データ追加
data = {
    "parent": {
        "database_id": DATABASE_ID
    },
    "properties": {
    "Name": {
        "title": [
        {
            "text": {
                "content": date
            }
        }
        ],
    },
    "日付": {
        "date": {
            "start": date
            }
        },
    },
}
response = requests.post(url, headers=headers, json=data)
```

# 感想
NotionAPIを使いこなせばNotionのでできることが非常に増えそうです。
色々なAPIを調べて使いこなしていきたいですね！
【Laravel】マルチログイン対応

# 手順

1.モデル、マイグレーション作成
2.ルート設定
3.ルートサービスプロバイダ設定
4.ガード設定
5.ミドルウェア設定
6.リクエストクラス設定
7.コントローラー&ブレード作成

# 1.モデル、マイグレーション作成

```
php artisan make:model Test -m
php artisan make:migration create_text_password_rests
```

app/models　フォルダの自動生成
Authenticatableを継承

# 2.ルート作成

web.phpとauth.php

# 3.ルートサービスプロバイダ設定
App/Provider/RouuteServiceProvider.php
ホームURLを設定

# 4.ガード設定

Laravel標準の認証機能。
セッションストレージとクッキーを使用して状態を維持するセッションが用意されている。
```php:config/auth.phpp
'guards' => [
    'gurd-name' => [
        'driver' => 'session',
        'provider' => 'users',
    ],
],

//ルートでauth:ガード名で認証されたユーザにアクセス許可
Route::get('test',function()
{
    ->middleweae('auth:guard-name')
}


'passwords' => [
    'users' => [
        'provider' => 'users',
        'table' => 'password_resets',
        // 60日間の期限
        'expire' => 60,
        // ログイン失敗時にログイン制限をかける時間 60秒
        'throttle' => 60,
    ],
```
参考になる記事

https://qiita.com/tomoeine/items/40a966bf3801633cf90f

# 5.ミドルウェア設定
ユーザが未認証の場合のリダイレクト処理
Midleware/Authenticate.php
 
ログイン済みユーザーがアクセスしてきたらリダイレクト処理
```php:Midleware/RedirectlfAuthenticate.php
//　ガード設定対象のユーザーか
Auth::guard(self::GUARD_USER)->check()

//受信リクエストが名前つきルートに一致するか
if($request->routels('user.*')){
}
```

# 6.リクエストクラス設定
App/Http/REquest/Auth/LoginRequest.php

ログインフォームに入力された値からパスワードを比較し、認証。

# 7.コントローラー&ブレード作成

App/Http/Controller/Auth
resources/views/auth

バリデーション
namespace
UnityのWebGLビルドのローカル確認方法とエラー対応

UnityのWebGLビルドにおける、ローカルでのチェックや状況に応じて出てしまうエラー対応方法のメモです。（Unity Version: Unity2021.3.15f1）

UnityのWebGL出力ファイルについて
------
UnityでWebGLプラットフォームを選択してビルドすると、以下のようなファイル群が出力されます。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97161/7d243215-067f-b8fd-adc1-6254dd45003a.png width=200px>

しかしindex.htmlを単純にファイルブラウザから起動しても再生はできません。ローカルのWebサーバを立ち上げる必要があります。

順当な方法
-----
一番簡単な方法はUnityエディタ上からBuild And Runをクリックすることです。これでビルドと同時にローカルのWebサーバーをUnity側で立ててくれます。ただし、この方法だとUnityを起動していないと確認できない点がネックです。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97161/93b3eb29-5691-e687-8bdf-46af35529498.png width=720px>

他のWebサーバーでの確認
--------
ローカルでWebサーバーを立てる方法はいくつかあります。例えばビルド先のフォルダに移動後、以下のようなコマンドを実行することでもできます。こちらはお手軽なので、自分は他の用途でもよく使います。

```sh
$ python3 -m http.server 8000　
# Webブラウザからhttp://localhost:8000にアクセス可能
```

しかし、UnityのWebGLビルドにおいては、上記のコマンドでのWebサーバーでアクセスすると以下のようなエラーがでてしまいます。

> Unable to parse Build/test.framework.js.br!
If using custom web server, verify that web server is sending .br files with HTTP Response Header "Content-Encoding: br". Brotli compression may not be supported over HTTP connections. Migrate your server to use HTTPS.

これは、立ち上げたWebサーバーがBrotliという圧縮形式での送信にうまく対応できていないためのようです。

このような場合は、以下のPlayer Settings→WebGLタブ→Publishing Settings→Compression Formatの項目をGzipもしくはDisabledにすると解消できます。

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97161/d368affa-8d2c-97b1-8397-9d6240d675ad.png width=720px>

本質的な対応でないですが、簡易的なローカルでの確認や、何らかの理由で上記圧縮フォーマットに対応できない場合はこの設定を試すとよいと思います。

参考
----
- https://stackoverflow.com/questions/72453065/unable-to-parse-build-build-framework-js-br
秋月電子通商ｎＲＦ５２８４０使用ＢＬＥマイコンボードでCircuitPython （ダメだった件）

　CircuitPython 8.0.3を利用します。マイコンボードは、秋月電子通商の下記の製品です。CircuitPythonはサポートされていません。
　　　[nRF52840BLE マイコン・ボード](https://akizukidenshi.com/download/ds/akizuki/AE-NRF52840.pdf)
　しかし、
　　　[ArduinoIDE にボードマネージャーを入れる手順](https://akizukidenshi.com/download/ds/akizuki/ae-nrf52840_board_manager_inst.pdf)
によると、Feather nRF52840 Expressをまねたように見えます。

### CircuitPython 8.0.3
　https://circuitpython.org/board/feather_nrf52840_express/ から、UF2ファイルをダウンロードします。
![c101.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/66e922a5-c065-365c-4464-4a133f083f32.png)

　マイコン・ボード上のresetを二度すばやく押し、ボード・ドライブFTHER840BOOTをエクスプローラに表示します。そのドライブに、ダウンロードしたUF2ファイルをドロップします。
コピーが終わっても、CIRCUITPYドライブはエクスプローラに表示されません。つまり、何らかの理由で失敗したと思われます。


　別のボードを試します。
　nRF52840で検索して、SSCI ISP1807 Dev Boardをクリックします。
![2023-03-03 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/10575b61-994a-a054-e599-9fba78cbfe83.png)
　このUF2ファイルをダウンロードし、boot0状態にしたドライブへ、ドラッグします。
　今度はCIRCUITPYドライブがエクスプローラに表示されます。

### ピン配置は異なる
　製品が異なるので、ピンの名称と、ボード上のピンは一致しません。利用できるピンは下記のとおりです。
![c102.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/0b039715-fef6-acf4-46b0-280dddec40d5.png)

##### SPI
　SPIの出力は、ピンにオシロスコープのプローブを当てれば検出できます。
　クロックSCK、出力のMOSIピンは特定できましたが、MISOが不明です。
　表示器には利用できますが、センサなどにはこのままでは利用できません。
![2023-03-03 (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/321b0ad7-fca0-7aa2-3d1b-ae43b50b719c.png)

##### I2C
　見つかりません。
　SSCI ISP1807 Dev BoardのArduino IDEをセットアップすると、


```cpp
#define PIN_WIRE_SDA         (19)
#define PIN_WIRE_SCL         (23)

#define PIN_WIRE1_SDA        (26)
#define PIN_WIRE1_SCL        (27)
```

2系統あるようですが、I2Cのプルアップ付きボードをつないで探ってみましたが、見つかりませんでした

##### I/Oピン
　ディジタルI/OやアナログI/Oは探せば出てきます。

### ということで失敗に終わりました
携帯動画変換君をWindows10で使おうとしたらavscheck.exeの暴走でひどい目に遭った話

## きっかけ
動画ファイルをプレイヤーで開くと時間表示が異常だった(シークすると違う秒数部分に飛ばされる)
ネットで検索すると「携帯動画変換君を使って秒数訂正すればいいよー」という情報を見つけたのでさっそくDLしてやってみた。(今回の場合は最終更新2005.12.01のVer 0.34をダウンロードした)
そうしたら**avscheck.exe**というファイルが立ち上がったものの何かがおかしい。
コマンドプロンプトを☓ボタンで消そうとしても応答なしになるだけですぐに戻ってしまう。
おかしいなと思ってタスクマネージャーを開いたら大変なことになっていた。
![IMG_3702.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576615/ba485492-61bf-1316-99d9-60e0b1ee5c3b.jpeg)
ブラクラの如く大量にプロセスが生成されているではないか！！
しかも`taskkill`で消してもまたぞろぞろと出てくる。

## こうなった時、まずしてほしいこと
### ①無限ループバッチでtaskkillを実行し続ける
```bat:loop.bat
:Label
taskkill /im avscheck.exe /F
goto :Label
```
**一刻も早く**このバッチファイルを作成して実行するか、PCを強制終了すること。
これでひとまずPCがメモリ不足で死ぬことはなくなる。
### ②avscheck.exeをリネームする
avscheck.exeは携帯動画変換君のフォルダの`cores`というフォルダにある。
そこでターミナルを開くか、そこまで`cd`で移動する。
そして`ren`でリネームする。
```
ren avscheck.exe avsscheck.exe
```
これで暴走が止まる。
①でループ実行させているバッチはCtrl+C→Yキーで停止させること。

## 教訓
昔のソフトを実行する時は自分に近しい環境の人が動作したかを確認するようにしよう。
暴走やエラーが起こるようであれば先人の対処を真似しよう。
また、できれば問題解決の際には新しく、自分の使用しているOSで動作確認が取れているソフトを使うようにしよう。
TypeORMのQueryBuilder.get*()の選び方

## はじめに
.get〇〇()の選び方だけ知りたい人は分岐①②を踏みましょう。
typeORMでselect文を作りたい！ || データがUndefinedになった！という人へ。


*  事象
取得データ：undefinedになる。
エラーログ：無し。

* デバック手順
①DB接続は成功している
②DBにデータが入っている
③クエリは適切
.getQuery()/.getParameter()を最後の.get〇〇()等と置き換えてログに出力する。
""など余計なものを消して、パラメーターをセットしてDB直接検索したら欲しいデータが取れた。
→???

## 結論
受け取る型をEntiry定義していなかったため、.getMany()で取得できなかった。「Raw」をつけたら解決。
分岐①②を見て.get①②()を選ぶ。


### 分岐①受け取る型はEntity？Rawなし：Rawあり
* Entityとして定義してある型で受け取るときはRawをつけない（.getOne()/.getMany()）
* その場で作ったInterfaceなど、Entiryとして定義してない型で受け取りたいとき＝Rawをつける（getRawOne()/.getRawMany()）

### 分岐②取得するデータ（レコード）は単数か？One：Many
* １レコードのみ取得したいとき＝One
※「1カラム」じゃなくて「1行」。配列じゃなければOKなので、.addSelect()も使える。
* 複数レコード（配列[]）の形で取得したいとき＝Many

## リファレンス：公式
https://typeorm.io/select-query-builder#using-subqueries
英語は易しめでいろんな例が載ってる。使えそうなメソッドを探すのにちょうどいい。
ただ、難しめの挙動（subQueryやaddwhere）は理解するのがちょっと大変だった。

## TypeORMの良いところ
* Entityと自動的に結びついてくれるため、呼び出すのが楽。
* 直感的でわかりやすい。カンでメソッド名が当たる(leftjoinはinnerjoin)。以下例。
.queryBuilder()
.select().addSelect().from().addfrom().innerjoin().where().andwhere().orWhere().get〇〇()
* 結構力技が使えるのがツボ。SQLベタ書きできるし、ベタ書きと組み合わせても使える。subQueryのsubquery突っ込んでも動く。

## 最後に
1年目よわよわエンジニアの七転八倒記第1稿でした。次はこれだけあればいける！集を書いてみたいです。事象の原因を切り分けるの難しいし時間かかるし、公式読んでも気が付かないし、時間が無限に欲しい。
記事や勉強法おすすめとツッコミお待ちしてます。
HTTPのPOSTとGETについて

# HTTPとは

>HTTPとは「Hyper Text Transfer Protocol」の略です。WWW（World Wide Web）上でWebサーバとクライアントが、HTML（Hyper Text Markup Langage = Webページを記述するための言語）で書かれた文章などの情報をやり取りするときに使われる通信手段（プロトコル）を意味しております。
(引用元)https://www.nic.ad.jp/ja/basics/terms/http.html

##### プロトコルとは

情報をやり取りするための約束事（共通言語）のことを言います。「通信規約」「通信プロトコル」等と呼ぶ場合もあります。


# HTTPSとは

>HTTPによる通信をより安全にしたプロトコルを *「HTTP(HTTP over SSL/TLS)」* と言います。
HTTPSは、通信内容が暗号化されていないHTTPとは違い通信内容が暗号化されている！
（引用先）https://medium-company.com/http/#HTTP-2

# HTTPのメソッド

### HTTP GET

指定されたURIのリソース（Webサイトの内容など）を取り出す、「HTTP/０.９」のバージョンから存在するHTTPの基本的なメソッド。
・ *他人に見られたくない情報は、GETでは送らない* 


HTTP GETの動作↓
・クライアント：URIを指定
・Webサーバ：指定されたURIのリソースを返却

### HTTP POST

HTTP POSTではクライアントからの入力内容をWebサーバに送ることが出来ます！
お問い合わせフォームや登録画面などから利用者が入力した内容をWebサーバに送りデータベースに蓄積する際に使用されます。
・ *バイナリデータを送信したい場合* 
・ *他の人に見られたくない情報を送る場合（パスワードなど）* 

HTTP POSTの動作↓
・クライアント：入力内容をWebサーバに送る
・Webサーバ：クライアントからの入力内容を受け取り、GETと同じようにクライアントへリソースを返却する。

# その他メソッド

PUT
・・・指定したリソースを保存する。URIにリソースが存在しない場合、WebサーバにそのURIのリソースを作成

DELETE
・・・指定したURIのリソースを削除する

OPTION
・・・Websa-bagaサポートしているバージョンなどを調査する

HEAD
・・・HTTPヘッダ情報を取得する

TRANCE
・・・Webサーバまでの経路情報を取得

CONNECT
・・・プロキシサーバを経由する際に使用する。

# HTTPのステータスコード

HTTPのステータスコードとは、リクエストに対する処理結果を示すコードです。ステータスコードは3桁の数字で表し次のような分類に分けられています。

100番台：情報（Informational）
200番台：正常（Success）
300番台：リダイレクション（Redirection）
400番台：クライアントエラー（Client Error）
500番台：サーバーエラー（Server Error）

# 参考にさせていただいたサイト

https://qiita.com/Sekky0905/items/dff3d0da059d6f5bfabf
https://medium-company.com/http/#HTTP-2
https://www.nic.ad.jp/ja/basics/terms/http.html
[IDMC]IBM DB2 for i(AS/400)からデータを取得する

## はじめに
Informatica Intelligent Data Management Cloud(IDMC/旧称IICS)でのちょっとしたTipsを纏めていきます。日々の活動の中で検証した結果記録であり、忘れやすい自分のためのメモですが、少しでも皆様のお役に立てればと思い公開していきます。記述方法など試行錯誤しており随時更新するかもしれません。

## この記事のゴール：IDMC データ統合における IBM DB2 for i(AS/400)への接続と連携が作成出来るようになる
この記事ではIBM DB2 for i(AS/400)への接続設定とマッピング作成時の設定例をメモしています。

尚この記事の内容は、R41 で検証しています。

### JDBCドライバの取得と配置
今回はJDBCを利用するためIBM様のサイトから”IBM Toolbox for Java JDBCドライバー” jt400.jar ファイルを取得し、SecureAgentの任意の場所に配置します。自分の場合以下の場所に配置しました。
```
C:\INFA\SA\drivers\jdbc\AS400\jt400-10.4.jar
```

## JDBC_IC 接続の設定
コネクタは ”JDBC_IC”タイプを選択し、以下のように設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985453/3990e7d7-ba8e-c42a-adc3-e616f5436407.png)
見て頂ければ分かるかと思いますが以下のような値を適宜設定しました。
|項目名  |設定値  |コメント  |
|---|---|---|
|接続名  |(任意)  |IDMC CDIの接続リストで表示される名称。わかりやすく付けるのがコツです  |
|タイプ  |JDBC_IC  |今回はJDBCを利用するのでコレ  |
|ランタイム環境  |任意のSecureAgent  |JDBC Jarを配置したSecureAgentを選択します  |
|JDBC接続URL  |jdbc:as400://(AS400サーバのHost名 or IPアドレス);libraries=(デフォルトSQLスキーマ等) |JDBC接続設定URL。詳細はIBM様のサイトで確認ください  |
|JDBC Jarディレクトリ  |Jarが配置されたフォルダのパス |フルパスではなくjarファイルが置かれたディレクトリまでを記述|
|JDBC Driver Class Name  |com.ibm.as400.access.AS400JDBCDriver |固定文字列 左の通り入力する|
|スキーマ  |(接続先スキーマ名)  |入力必須ではなく任意  |
|ユーザ名  |(接続先ユーザ名)  |入力必須  |
|パスワード  |(接続先ユーザのパスワード)  |入力必須  |

接続テストを行い、成功したら保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985453/a424f1fa-6b7b-1f4e-c729-8636c56e214e.png)

## マッピング作成：ソース設定
接続さえうまく出来ればあとは普通にデータを取得出来ますので特に難しい事はありません。
いつも通り、ソーストランスフォーメーションのソースプロパティの「接続」に今回作成した接続を選択し、「オブジェクト」の選択ボタンを押すと
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985453/c22a306f-f805-c4bf-a5ef-640ffec59949.png)
該当のスキーマのオブジェクトが一覧できますので、取得したいオブジェクトを選択すればOK。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985453/3f7df287-f01e-5766-6107-6e2314ad988d.png)
プレビューも出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985453/f18e9de3-cd44-89da-dcdd-5d8b8ab94bac.png)
後は適宜データ編集を行い、任意のターゲットにロードするマッピングに仕上げましょう。
今回はAS400 DB2からデータを取得し、特定の条件の場合はPostgresにロード、条件に合わない物はチェックファイルに出力する、と言うような処理を作ってみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985453/9f6d77ef-6294-7a23-3434-05f4a1106dc7.png)
以上です。何かのお役に立てば幸いです。
Spring Boot勉強③ Thymeleafの使い方

# はじめに
<!-- 発端や概要を記載 -->
https://qiita.com/fattolys/items/9567a412bf1703948731
前回の続き

ThymeleafでHello Worldを表示したけど、どうやって？HTMLでの表現方法？について調べてみた

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [表示の仕組み](#Chapter1)
1. [表現方法](#Chapter2)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# 表示の仕組み
```Java:HelloWorldController.java
/*ここまで省略*/
@Controller
public class HelloWorldController {
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String helloWorld(Model model) {
        model.addAttribute("message", "Hello World!!");
        return "index";
    }
}
```
```HTML:index.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Hello</title>
    <meta charset="utf-8" />
  </head>
  <body>
    <h1>任意タイトル</h1>
    <h2><span th:text="${message}"></span></h2>
  </body>
</html>
```
上記構成の場合、HelloWorldController.javaでは
```Java:HelloWorldController.java
        model.addAttribute("message", "Hello World");
```
にてテンプレート（HTML）に渡す変数("message")を model.addAttribute で登録している
その後、

```Java:HelloWorldController.java
        return "index";
```
で戻り値に表示するHTMLのテンプレートファイル名(index)を指定


index.htmlでは、
```HTML:index.html
<html xmlns:th="http://www.thymeleaf.org"></html>
```
htmlタグに上記を記載し、Thymeleaf のテンプレートであることを明示
```HTML:index.html
<span th:text="${message}"></span>
```
上記でControllerで設定した変数("message")を指定することでHTMLとしては以下のように解釈される
```HTML:index.html
<span Hello World></span>
```
<a id="#Chapter2"></a>
# 表現方法
TBD
<a id="#reference"></a>
# 参考文献
- [Thymeleafの使い方！](https://style.potepan.com/articles/35390.html)
- [Thymeleafとは？](https://camp.trainocate.co.jp/magazine/about-thymeleaf/)
kubectl コマンド集（工事中）

よく使うけどよく忘れるコマンドをまとめていく
思いつき次第追加していきます

### コンテナのシェルを取りたい
```
kubectl exec --tty --stdin -c ${コンテナ名} ${Pod名} -- /bin/bash
```

### ネームスペースを切り替えたい
```
kubectl config get-contexts  // contextの一覧を表示
kubectl config use-context ${コンテキスト名}
```

### ラベルを消したい
```
kubectl label node ${キー名}-
```

### StorageClassの表示
```
kubectl describe storageclass
```
PythonでExcelから年度ごとのデータを抜き出して平均を計算したい件

# やりたいこと
- 案件A～Cがあるが、**各年度**にこなした案件総数の平均値が欲しい
- たとえば「2020-07-08」に得た総案件数156の平均値**31.2**が重要
- 2020-07-09, 2020-07-10, ... と多数あるこれらを年度ごとに集計したい

# 参考文献
https://ai-inter1.com/pandas-timeseries/#st-toc-h-6
https://an-engineer-note.com/?p=683

# ソリューション

正直、泥臭すぎる気がしている…もっといい書き方があるのではないかと思うが分からないし、速度上問題ないのでこれで実行中。

~~~
# df_org(DataFrame)に以下のように入っているとする

     案件A    案件B    案件C  date_index
 0      23       0        0  2020-07-08
 1      17       0        0  2020-07-08
 2       0       0       67  2020-07-08
 3      19       0        0  2020-07-08
 4      30       0        0  2020-07-08
 ...
40       0       0       10  2022-04-01
41       0       0        8  2022-06-01
42       0       0        8  2022-06-01
43       0       0        8  2022-06-01
44       0       0        4  2022-10-01
~~~

```Python:make_report_by_fyear.py
def make_report_by_fyear(df_org):
    # 作業用df_work
    # ずらしのためにindexに指定
    df_work["date_index"] = pd.to_datetime(df_org["date_index"])
    df_work.set_index("date_index", inplace=True)
    # 3ヶ月ずらしで「年度」の数字を作る
    df_work = df_work.shift(-3,freq="M")
    # 案件はいずれか
    df_work['総案件'] = df_work.sum(axis=1)
    # indexを解除
    df_work.reset_index(inplace=True)

    # 案件数の月ごと合計と案件レコード数
    df_monthly_sum = df_work.groupby(pd.Grouper(key="date_index", freq="M")).sum()
    df_monthly_size = df_work.groupby(pd.Grouper(key="date_index", freq="M")).size()
    df_monthly_total = pd.concat([df_monthly_sum, df_monthly_size], axis=1)

    # 案件数の年度ごとの合計
    df_fyear_sum = df_monthly_total.resample('Y').sum()
    df_fyear_sum["平均○○数"] = df_fyear_sum.iloc[:,3] / df_fyear_sum.iloc[:,4]
    # 「xx年度」の文字列を作る
    df_fyear_sum.reset_index(inplace=True)
    df_fyear_sum["年度"] = df_fyear_sum['date_index'].dt.strftime('%Y年度')
    df_fyear_sum.set_index("年度", inplace=True)

    return df_fyear_sum
```
Spring Boot勉強② Hello World

# はじめに
<!-- 発端や概要を記載 -->
https://qiita.com/fattolys/items/cdbed27782de02b66b0d

前回の続き、プロジェクト作成後にThymeleafを用いてHello Worldを表示させるまでを行う

https://medium-company.com/spring-boot-thymeleaf/

を参考に実施

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [パッケージ構成](#Chapter1)
1. [HTML,Controllerの作成](#Chapter2)
1. [Spring Bootプロジェクトの起動](#Chapter3)
1. [HTML,Controllerの関係性](#Chapter4)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# パッケージ構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508643/6c1e93eb-3015-0016-369c-3bc2e0f1d782.png)


<a id="#Chapter2"></a>
# HTML,Controllerの作成
①「resources」-「templates」配下にindex.htmlを作成
※「resources」-「templates」フォルダ配下が参照されるのはThymeleafのデフォルト、変更も可
```HTML:index.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Hello</title>
    <meta charset="utf-8" />
  </head>
  <body>
    <h1>任意タイトル</h1>
    <h2><span th:text="${message}"></span></h2>
  </body>
</html>
```

②com.example.demo.controllerパッケージ配下にHelloWorldController.javaを作成
```Java:HelloWorldController.java
package com.example.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class HelloWorldController {
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String helloWorld(Model model) {
        model.addAttribute("message", "Hello World!!");
        return "index";
    }
}
```

<a id="#Chapter3"></a>
# Spring Bootプロジェクトの起動
①プロジェクトを右クリック→「実行」→「Spring boot アプリケーション」を選択してSpring Bootプロジェクトを起動
②ブラウザで「http://localhost:8080/」にアクセス

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508643/276faff2-9eeb-57de-3c7e-cdf4635704bc.png)

<a id="#Chapter4"></a>
# HTML,Controllerの関係性
アノテーションを基にRequestに応じてControllerのメソッドを実行し、returnで指定されたページに遷移する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508643/657259ac-d7e6-6c48-65ed-3b803481239c.png)




<a id="#reference"></a>
# 参考文献
- [Spring Boot＋Thymeleafで”Hello World”を作成する](https://medium-company.com/spring-boot-thymeleaf/
)
- [アノテーションについて](https://camp.trainocate.co.jp/magazine/spring-annotation/)