OmniAICreator/Qiita-1.07M huggingface dataset:
調和振動子の運動を数値的に解く（TeX・Tikzで数値計算）

$$
\def\DIS{\displaystyle}
\def\fraction(#1/#2){\frac{#1}{#2}}
\def\ff(#1/#2){\frac{#1}{#2}}
\def\dd#1#2#3{\frac{d ^{#1}#2}{d #3^{#1}}}
\def\pdd#1#2{\frac{\partial ^{#1}#2}{\partial #3^{#1}}}
\def\bi#1#2{{}{#1}! , \mathrm C{#2}}
\def\bm{\boldsymbol}
$$

# 調和振動子の方程式

ばね定数 $k$, 自然長 $\ell$ のバネにつながった質点の運動方程式は

$$ m \dd{2}{x}{t} = -k(x-\ell) $$

$m$ は質点の質量。

この方程式の右辺は次のように書き換えます。

$$ - \ff(k/m) \ff((x-x_0)/|x-x_0|) (|x-x_0| - \ell) $$

$x_0$はばねのもう一方の端点の座標です。このように書き換えておくと，ばねの右側か左側かによらず同じ式が使えます。この関数はTeXでは次のように書きます。

```tex
\def\funcAccelPX#1#2#3#4#5{
    (-(#1-#3)/abs(#1-#3)*\paraK*(abs(#1-#3) - \Nlength)/(#5))}%
```

この調和振動子の微分方程式をTeXで数値的に解きます。

https://youtu.be/ErUNg6D16js
[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/ErUNg6D16js/0.jpg)](http://www.youtube.com/watch?v=ErUNg6D16js)



積分の手法はこちら
https://qiita.com/hironarin/items/cc4e1c8f961155a8e511


# TeX

tikzpictureの中身以外は以下のようになります。

```tex
%計算回数
\def\stepB{60}%1秒の刻み幅
\def\stepA{20}%時間
%カウンター定義
\newcount\countA%
\newcount\countB%

%%%%%%%%%%%%%%%%%%%%%%%%%
%物理パラメータ 定数
%%%%%%%%%%%%%%%%%%%%%%%%%
        \tikzmath{
        int \ParNum ;
        \ParNum=1; %粒子数
        \Nlength = 6;%ばねの自然
        \paraK=3;%ばね定数
        \ceiling = 8;%ばねの端点の座標（固定）
        \mass{1} = 0.5;%質点の質量
		}

\tikzmath{
    %時間刻み幅の設定
    real \dT;
    \dT = 1 / \stepB;
}


%微分方程式の右辺
%#1 x座標	 #2 速度x成分 #3ばねのもう片方の端点の座標 #4ばねのもう片方の端点の速度 #5質点の質量
\def\funcAccelX#1#2{#2}%dH/dp_x
\def\funcAccelPX#1#2#3#4#5{
    (
    -(#1-#3)/abs(#1-#3)*\paraK*(abs(#1-#3) - \Nlength)/(#5))}%-dH/dx
%%%%%%%%%%%%%%%%%%%%%%%%%





%ぬこの初期値を代入
\tikzmath{
    \iqXNuko{1} = 4;
    \ivXNuko{1} = 0;
}
%グローバル変数に代入する
\countA = 0 \loop\ifnum\countA < \ParNum{
    \tikzmath{
        int \intCount;
        \intCount = \countA + 1;
    }
    \global\expandafter\edef\csname variXCdNuko[\intCount] \endcsname{\iqXNuko{\intCount}}%初期位置を代入
    \global\expandafter\edef\csname variXVelocityNuko[\intCount] \endcsname{\ivXNuko{\intCount}}%初速度を代入
}
\advance\countA by1\repeat %







\countA = 0 \loop\ifnum\countA < \stepA
{
\countB = 0 \loop\ifnum\countB < \stepB
{



\begin{tikzpicture}

%%%%ここで描画

\end{tikzpicture}





%%%数値計算ルンゲクッタ
\tikzmath{
    \NqtXTako = \csname variXCdNuko[1] \endcsname;
    \NvtXTako = \csname variXVelocityNuko[1] \endcsname;
}


\tikzmath{
    real \variFuji;
    \dummy{1}=\NqtXTako;
    \dummy{2}=\NvtXTako;
    \NatXTako = \funcAccelX{\dummy{1}}{\dummy{2}};
    \NatPXTako =  \funcAccelPX{\dummy{1}}{\dummy{2}}{\ceiling}{0}{\mass{1}};
%
%
    \dummy{1}=\NqtXTako + 0.5 * \NatXTako *\dT;
    \dummy{2}=\NvtXTako + 0.5 * \NatPXTako * \dT;
    \NatXTako = \funcAccelX{\dummy{1}}{\dummy{2}};
    \NatPXTako =  \funcAccelPX{\dummy{1}}{\dummy{2}}{\ceiling}{0}{\mass{1}};
%
%
    \NvtXTako = \NvtXTako +  \dT  * \NatPXTako;
    \NqtXTako = \NqtXTako + \NatXTako * \dT;
    %
}
%計算結果を代入
\global\expandafter\edef\csname variXCdNuko[1] \endcsname{\NqtXTako}
\global\expandafter\edef\csname variXVelocityNuko[1] \endcsname{\NvtXTako}


%計算終了，次のページへ
\newpage 
}%loop \countB
\advance\countB by1\repeat

}%loop \countA
\advance\countA by1\repeat
```
日付＋乱数で64ビット長のIDを作る

<!-- https://qiita.com/sator_imaging/items/576781d95367d5856624 -->

簡単に言えば [ULID（128ビット）](https://github.com/ulid/spec) の 64 ビット版で同一ファイル内で重複しなければ良い、という時に使うモノ。

Unity で使われる ID は `long` である場合が多く、しかし Ulid は `long long`。ということで 8 バイトの ULID 的なモノが必要な時もあるでしょう。


https://github.com/sator-imaging/Half-Ulid



### 構造

`YearOffset(7) Month(4) Day(5) Hour(5) Minute(6) Second(6) Millisec(10)` 計43ビット  
＋  
`乱数か連番` 21ビット  


タイムスタンプは ULID の 48 ビットより 5 ビット短く、ミリ秒毎に作れる数も必要十分（2,097,152個）。対応年数は最大で基準年から128年間。

ULID 同様に作成順にソートも可能なはず。


実行結果 👉 https://dotnetfiddle.net/pmC9kz



```csharp
using System;

public class Program
{
	const int YEAR_ORIGIN = 2000;
	const int ID_MAX = 2097151;  // 2 ^ 21 - 1;

	public static void Main()
	{
		var rng = new Random();
		var now = DateTime.UtcNow;

		// randomize lower bits.
		long id = (long)(now.Year - YEAR_ORIGIN) << 57;
		id |= (long)now.Month << 53;
		id |= (long)now.Day << 48;
		//id |= (long)now.DayOfYear << 48;
		id |= (long)now.Hour << 43;
		id |= (long)now.Minute << 37;
		id |= (long)now.Second << 31;
		id |= (long)now.Millisecond << 21;
		id |= rng.Next(0, ID_MAX);
		Console.WriteLine("random lower: " + id.ToString("X2") + ": " + id);


		// randomize upper bits.
		id = (long)(now.Year - YEAR_ORIGIN) << 36;
		id |= (long)now.Month << 32;
		id |= (long)now.Day << 27;
		//id |= (long)now.DayOfYear << 27;
		id |= (long)now.Hour << 22;
		id |= (long)now.Minute << 16;
		id |= (long)now.Second << 10;
		id |= (long)now.Millisecond;
		id |= ((long)rng.Next(0, ID_MAX)) << 43;
		Console.WriteLine("random upper: " + id.ToString("X2") + ": " + id);


		// set sign bit.
		id |= long.MinValue;  // 0x80L << 56;
		Console.WriteLine("set sign bit: " + id.ToString("X2") + ": " + id);
		

		// remove sign bit.
		id &= ~long.MinValue;
		Console.WriteLine(" no sign bit: " + id.ToString("X2") + ": " + id);
	}
}
```


--


ID の正負で動作を変えるような事をやる場合は相対日時を下位ビットにしたほうが良いんだろうけど、日付順の並び替えが面倒になる。もどかしい。


以上です。お疲れ様でした。
【PHP】PHPと簡単なアルゴリズム

# 合計値
`合計値`とは、すべての値を足した値です。

# PHPで合計値
```index.php
<?php
    // データを配列に用意します
    $a = array(1,3,10,2,8);
    // 合計値を０に初期化します
    $sum = 0;
    // データの個数だけ繰り返します
    for ($i=0; $i<count($a); $i++) {
    // 各値を足します
        $sum += $a[$i];
    }
    // 結果を表示します
    print("合計=".$sum);
?>
```
```
合計=24
```

# 最大値
`最大値`とは、すべての値で最も大きな値です。

# PHPで最大値
```index.php
<?php
    // データを配列に用意します
    $a = array(1,3,10,2,8);
    // 最大値に最初の値を入れて初期化します
    $max = $a[0];
    // ２つ目から最後まで、繰り返します
    for ($i=1; $i<count($a); $i++) {
    // もし最大値よりも値が大きければ
        if ($max < $a[i]) {
            // 最大値を値で上書きします
            $max = $a[$i];
        }
    }

    // 結果を表示します
    print("最大値=",$sum);
?>
```
```
最大値=10
```

# データの交換
`データの交換`とは、２つの変数の値を入れ替えることです。

# PHPでデータの交換
```index.php
<?php
    // 交換前のデータです
    $a = 10;
    $b = 20;

    // tに、aの値を入れます
    $t = $a;
    // aに、bの値を入れます
    $a = $b;
    // bに、待避させたtの値を入れます
    $b = $t;

    // 結果を表示します
    print("a=".$a."b=".$b);
?>
```
```
a=20,b=10
```

# 参考
https://www.amazon.co.jp/gp/product/4839977097/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1
【pyinstaller】boxsdkを使用したpythonアプリの実行ファイル作成の際の注意点

## 1.はじめに

boxsdkを使用したpythonアプリの実行ファイルを作成した際に私がかなりつまづいたことについて、備忘録も兼ねて記事を書きます。（初めての記事投稿なので、お手柔らかにお願いいたします:beginner:）

## 2.実行環境
Windows11
python     : 3.7.9
pyinstaller: 5.8.0
boxsdk     : 3.3.0

## 3.発生したエラー
ターミナルからpythonコマンドで実行する分には何も問題なく処理が行われるのに、実行ファイルを作って実行してみたら何やら以下のようなエラーが出る…
`AttributeError: module 'boxsdk.object' has no attribute 'recent_item'`

何やらpyinstallerで実行ファイルを作成する際にboxsdkに関連したエラーが起きてそう！
そう思って解決策を探したのですがなかなか見つからず…
やっとの思いで見つけた解決策をここに記載します！！

これは、pyinstallerで実行ファイルを作成する際にboxsdkのモジュールがインポートされていないから起きているエラーのようです。
そのため、ここではpyinstallerで実行ファイルを作成する際にモジュールをインポートする方法をご紹介します！

## 4.解決策
### 1. specファイルを作成する
まずはpyinstallerでspecファイルを作成します
`pyinstaller (実行したいpythonファイル名) --onefile`
例えば、`pyinstaller sample.py --onefile`

実行が終わるとbuldフォルダとdistフォルダとspecファイルが作成されていると思います。
buildフォルダは実行ファイルの作成に使用するものらしいですがあまり気にしなくて大丈夫です。
distフォルダは作成された実行ファイルが格納されています。
specファイルは、アプリのソースファイル群からrpmパッケージを作成するための指示を記述したファイルです。

### 2.specファイルのhiddenimportsを編集する
上の手順で作成されたspecファイルを開くと、`hiddenimports=[]`という項目があると思います。実行ファイルにboxsdkのモジュールをインポートするために、ここに記入していきます。
```spec
hidenimports = [
    'boxsdk.object.collaboration',
    'boxsdk.object.collaboration_whitelist',
    'boxsdk.object.collaboration_whitelist_entry',
    'boxsdk.object.collaboration_whitelist_exempt_target',
    'boxsdk.object.collection',
    'boxsdk.object.comment',
    'boxsdk.object.device_pinner',
    'boxsdk.object.enterprise',
    'boxsdk.object.events',
    'boxsdk.object.event',
    'boxsdk.object.file',
    'boxsdk.object.file_version',
    'boxsdk.object.file_version_retention',
    'boxsdk.object.folder',
    'boxsdk.object.group',
    'boxsdk.object.group_membership',
    'boxsdk.object.legal_hold',
    'boxsdk.object.legal_hold_policy',
    'boxsdk.object.legal_hold_policy_assignment',
    'boxsdk.object.metadata_cascade_policy',
    'boxsdk.object.metadata_template',
    'boxsdk.object.recent_item',
    'boxsdk.object.retention_policy',
    'boxsdk.object.retention_policy_assignment',
    'boxsdk.object.search',
    'boxsdk.object.storage_policy',
    'boxsdk.object.storage_policy_assignment',
    'boxsdk.object.terms_of_service',
    'boxsdk.object.terms_of_service_user_status',
    'boxsdk.object.trash',
    'boxsdk.object.task',
    'boxsdk.object.task_assignment',
    'boxsdk.object.user',
    'boxsdk.object.upload_session',
    'boxsdk.object.webhook',
    'boxsdk.object.watermark',
    'boxsdk.object.web_link'
]
```
boxsdkのモジュール全部をインポートする必要はないと思いますが、何のモジュールが必要かわからなかったので私は全部記入しました。

### 3. specファイルを使用して実行ファイルの作成
これでboxsdkのモジュールがインポートされた実行ファイルを作成する準備が整いました！
ターミナル上で以下のようなコマンドを実行します。
`pyinstaller (specファイル名)`
例えば、`pyinstaller sample.spec`
私の場合はこれでdistフォルダにboxsdkのモジュールがインポートされた実行ファイルが作成され、うまく動作しました！

もし他に必要なモジュールがインポートされていなかったら同じ方法を試してみて下さい！

見ていただき有難うございました！:bow_tone1:

## 参考情報
https://github.com/box/box-python-sdk/issues/368
DockerでRails/MySQLの環境構築


## はじめに

DockerでRailsとMySQLの環境を構築するにあたって、調べてもよくわからない設定があったりして混乱したので、とりあえずRailsアプリケーションが動かせる最低限の環境を作り、この状態から必要な要素を随時追加していくというやり方を取りました。

## ディレクトリ構成
```bash
.
├── .devcontainer
│   └── devcontainer.json
├── .gitignore
├── app
│   ├── Gemfile
│   └── Gemfile.lock
├── compose.yml
└── docker
    ├── api
    │   └── Dockerfile
    └── db
```
今回は構成要素が少ないので、`docker/`以下の`Dockerfile`はプロジェクトルートに配置するプレーンな構成の方がわかりやすかったかもしれません。
以下で紹介する以外のファイルは無くても問題ありませんが、ディレクトリ構成を変更する場合は`Dockerfile`及び`compose.yml`の編集が必要になる場合があります。

## 各ファイルの準備

コンテナ内でRailsプロジェクトを生成するため、Gemfileに下記の内容を記述しておきます。
```:app/Gemfile
source "https://rubygems.org"
gem "rails", "~> 7.0.5"
```

```Dockerfile:docker/api/Dockerfile
FROM ruby:3.2.2

WORKDIR /app

COPY app/Gemfile* ./

RUN bundle install

CMD ["rails", "server", "-b", "0.0.0.0"]
```

```compose.yml
version: "3.9"

services:
  api:
    build:
      context: .
      dockerfile: ./docker/api/Dockerfile
    ports:
      - "3000:3000"
    depends_on:
      - db
    stdin_open: true
    tty: true
    volumes:
      - ./app:/app

  db:
    image: mysql
    ports:
      - 3306:3306
    environment:
      MYSQL_ROOT_PASSWORD: password
```


## 環境構築

最初にイメージをビルドします。
```bash
$ docker compose build
```

下記のコマンドでコンテナ内にRailsプロジェクトを生成します。
`Dockerfile`で`WORKDIR /app`を指定し、下記のコマンドで`.`を使ってカレントディレクトリ指定することで、コンテナ内の`/app`にプロジェクトが展開されて生成されます。
`compose.yml`に設定を記述しているので、ホスト側にもプロジェクトの内容が同期されます。
```bash
docker compose run --rm api rails new . --database=mysql --api
```

上記のコマンドによって`/app`内に新たなGemfileが生成されますが、既にGemfileが存在しているため下記の表示が出て一時ストップされます。
既存の内容は置き換えてしまって問題ないので、Yを入力するかEnterでそのまま進めます。これで新しいRailsプロジェクトに適したデフォルトの Gemfile が生成されます。
```bash
conflict  Gemfile
Overwrite /app/Gemfile? (enter "h" for help) [Ynaqdhm] 
```

この後設定ファイルを編集する必要があるのですが、Dockerコンテナ内で作成されたファイルは`root`として作成されるため、ホスト側から編集しようとするとパーミッションエラーが発生します。
その前に下記のコマンドでカレントディレクトリ以下の全てのファイルとフォルダのオーナーを現在のユーザーに変更します。
```bash
sudo chown -R $USER:$USER .
```

データベースへの接続に`compose.yml`で指定したパスワードとサービス名を使用するため、ホスト側から`app/config/database.yml`を下記のように編集します。内容は適宜置き換えてください。
```yml:config/database.yml
default: &default
  # 省略
  password: password
  host: db
```

再度ビルドしてコンテナを起動します。
```bash
docker compose build
docker compose up -d
```

この状態で http://localhost:3000/ にアクセスすると、`ActiveRecord::NoDatabaseError`というエラーメッセージが表示されます。
データベースが作成されていないことが原因なので、下記のコマンドでデータベースを作成します。

```bash
docker compose run --rm api rails db:create
```

再度 http://localhost:3000/ にアクセスすると無事に起動できているはずです。
![スクリーンショット 2023-06-18 224704.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3340928/cce14c3d-c418-429b-89a8-947c86dfda73.png)



## あとがき
Dockerは便利ですがまだ不慣れで、必要な設定の選定がいつも大変です。アドバイス等がありましたら、ぜひご教授いただきたく存じます。
MicroPython で RP2040 の PIO を使うサンプル その3

# レジスタ x が32ビット扱えていることを確認する

もちろん問題ありませんでした

```main.py
import rp2

@rp2.asm_pio()

def prog():
    set(x,0)
    jmp(x_dec,"JMP")	# x=x-1, then if x is not zero, jump to "JMP"
    label("JMP")
    in_(x,32)	# x -> ISR 32bit
    push()		# ISR ->RX FIFO

state_machine = rp2.StateMachine(0, prog)

state_machine.active(1)

print("get",state_machine.get()) # 4294967295 が返される
```

# 実行時間を`freq=`で指定する

```main.py
import machine, rp2

@rp2.asm_pio(
    set_init=rp2.PIO.OUT_HIGH
    )

def prog():
    set(pins,0)        # takes 100usec ( = 1/10kHz ) 
    set(pins,1)

state_machine = rp2.StateMachine(
    0, prog,
    freq=10_000,
    set_base=machine.Pin(26)
    )

state_machine.active(1)
```

D0 <- P26 です。
![スクリーンショット 2023-07-08 16.06.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533274/4e5d19c7-2129-6330-27d0-eb4dde74bfcd.png)


# ループで時間調整をする

```main.py
import machine, rp2

@rp2.asm_pio(
    set_init=rp2.PIO.OUT_HIGH
    )

def prog():
    set(pins,0)        # takes 100usec ( = 1/10kHz ) 
    set(x,3)           # takes 100usec
    label("loop")
    jmp(x_dec,"loop")  # takes 400usec ( = (3+1)*100usec )
    set(pins,1)

state_machine = rp2.StateMachine(
    0, prog,
    freq=10_000,
    set_base=machine.Pin(26)
    )

state_machine.active(1)
```

D0 <- P26 です。
![スクリーンショット 2023-07-08 15.36.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533274/7f57c2ab-8c4e-725f-c8be-41b3ebb57c92.png)


# （応用）P26が0になっている時間を計測

```main.py
import machine

machine.Pin(26, machine.Pin.OUT, value=1)

# start PWM. L takes 50msec = 1/10Hz*0.5(duty)
machine.PWM(machine.Pin(26)).freq(10)
machine.PWM(machine.Pin(26)).duty_u16(32768)

import rp2

@rp2.asm_pio()

def prog():
    set(x,0)
    wait(1, gpio, 26) # wait until P26 goes 1
    wait(0, gpio, 26) # wait until P26 goes 0
    label("loop")
    jmp(x_dec,"JMP")  # 1 clock:  x=x-1, then if x is not zero, jump to "JMP"
    label("JMP")
    in_(pins,1)       # 1 clock: (in)pins -> ISR
    mov(y, isr)       # 1 clock:
    jmp(not_y,"loop") # 1 clock: if y==0, jump to "loop"
    in_(x,32)	# x -> ISR 32bit
    push()		# ISR ->RX FIFO

state_machine = rp2.StateMachine(
    0, prog,
    in_base=machine.Pin(26)                             
    )

state_machine.active(1)
print("activate")

a=state_machine.get()
print("get", a)
print("count", 2**32-1-a) # 32ビットの最大値からの差分
print(((2**32-1-a)*4+1)/125_000_000,"sec") # 1カウント 4クロックを掛け算

```

実行例
```
>>> %Run -c $EDITOR_CONTENT
activate
get 4293404814
count 1562481
0.0499994 sec
>>> 
```

# おしまい

IRQが使えないヘタレなので，これでおしまいです...

かなりクセ強ですが，PIO，なかなかおもしろいです。
ラベルを除く，32個しか命令を使えないし，少し記述を間違えただけでうまく動かないし...
それでもMicroPythonなら，デバッグの方法を模索しながら試すのはむしろ楽しみと言えます。

ニーモニックの動き，使うクロック数を意識しながらプログラムを組むのは，今となっては斬新な印象を受けますね。

シリパラ変換器のサポートプログラムぐらいなら，楽しみながらすぐできそうですね。データをPIOに送れば順にシリパラに送ってくれるとか。少し特殊仕様のUARTとか。
Python書き方メモ(1)：loggingライブラリ

# はじめに
私は、業務外でよくPythonでコードを書いているのですが、ログをファイルに出力するのにloggingライブラリを使用しています。
メモとしてloggingライブラリの書き方を残したいと思います。

# loggingライブラリのインストール
```
pip install logging
```
・Python3の場合
```
pip3 install logging
```

# loggingライブラリの宣言
```
import logging
```

# ログの基本設定(ファイル名、ログレベルの設定)
```
logging.basicConfig(filename='log/log_0.log' level=logging.INFO)
```

・ファイル名の指定(相対パスでの指定)
filename=以降の部分は、どのディレクトリからpyファイルを動作させるかによって、書き方が変わります。相対パスを指定する際は、注意してください。
今回は、以下の条件の下、logフォルダのlog_0.logというファイルにログを書き込むよう設定しています。
[条件]
1\. フォルダ「A」の中にlogフォルダとsrcフォルダを配置
2\. Pyファイルを実行する場合は、一度「A」にcdでディレクトリを移動してから起動

・ログレベルの指定
logging.INFOを指定しています。
出力可能なログレベルは、INFO・WARNING・ERROR・CRITICALです。

# ログの出力
```
import datetime
import logging

// 現在日時
// YYYY-MM-DD形式で出力
current_date = datetime.datetime.now().strftime('%Y-%m-%d')

logging.basicConfig(filename='log/log_0.log' level=logging.INFO)

logging.info(current_date + ' ' + 'ログレベル：INFO')
logging.warning(current_date + ' ' + 'ログレベル：WARNING')
logging.error(current_date + ' ' + 'ログレベル：ERROR')
logging.critical(current_date + ' ' + 'ログレベル：CRITICAL')

```
## こんな感じでログが出る
```
INFO:root:2023-07-01 ログレベル：INFO
ERROR:root:2023-07-02 ログレベル：ERROR
```

以上、loggingライブラリ書き方メモでした。
@ModelAttributeでちょっとはまった話。

使用環境
- フレームワーク　springBoot:3.1.1
- 使用言語：Kotlin

メモで記載します。学習中Formオブジェクトをバインドしてタイムリーフ表示を実施したところ、エラーが発生しました。

## エラー
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.

Sat Jul 08 22:40:05 JST 2023
There was an unexpected error (type=Internal Server Error, status=500).
An error happened during template parsing (template: "URL [file:src/main/resources/templates/issues/creationForm.html]")
org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "URL [file:src/main/resources/templates/issues/creationForm.html]")

## ソースコード
### Controller
```kotlin:com/example/its/web/issue/IssueController.kt
@Controller
@RequestMapping("/issues")
class IssueController() {
    @GetMapping("/creationForm")
    fun register(@ModelAttribute form: IssueForm): String {
        return "issues/creationForm"
    }
}
```

### Form
```kotlin:com/example/its/web/issue/IssueForm.kt
data class IssueForm(
    val summary: String?,
    val description: String?
)
```

### Thymeleaf
```kotlin:templates/issues/creationForm.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>課題作成 | 課題管理アプリケーション</title>
</head>
<body>
<h1>課題作成</h1>
<form th:action="@{/issues}" th:method="post" th:object="${form}">
    <div>
        <label for="summaryInput">概要</label>
        <input type="text" id="summaryInput" th:field="*{summary}">
    </div>
    <div>
        <label for="descriptionInput">説明</label>
        <input type="textarea"  row="10" id="descriptionInput" th:field="*{description}">
    </div>
    <div>
        <input type="submit">
    </div>
</form>
</body>
</html>
```

## 解決策
__Thymeleafの`th:object="${form}`を`th:object="${issueForm}"`とすることで改善__

## 原因
コントローラーメソッドの引数名として form を指定した場合でも、@ModelAttribute("issueForm") のように明示的に指定しない限り、デフォルトの名前はクラス名の先頭を小文字にしたものになるため（この場合は "issueForm"）。

普通にmodel.addAttributeでもいけるんでしょうが、へーとなった夜でした
rex0220 計算式プラグイン ６ヶ月後の前日

[計算式プラグイン](https://qiita.com/rex0220/items/ae83c6d5ce50ff7a9a73)で６ヶ月後の前日計算を行ってみました。

# 概要

結果が分かりやすいように、テーブルに日付、６ヶ月後、６か月後の前日を表示します。
開始日付、終了日付に指定した範囲をテーブルに展開します。
「６ヶ月後の前日」の計算式は、下記のように簡単に記述できます。

- 計算式の例
DATE_ADD(DATE_ADD(日付,6,"month"),-1,"day") // ６ヶ月後の前日


![2023-07-08_23h07_51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/1a82394c-5b43-684b-d971-1d58b9f05478.png)

# 画面レイアウト

開始日付と終了日付。テーブルには、番号と日付を並べます。

![2023-07-08_23h06_26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/1c34f577-fe37-749b-8226-6d1dc28868c3.png)

# 計算式プラグイン設定

開始日付と終了日付の日数をテーブル行数にします。
日付は、開始日付にテーブル行位置を加算
※「日付_６ヶ月後の前日」の計算式は LET 関数を使っています。

![2023-07-08_23h05_55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/f9c1e1ae-0b87-8f89-51ea-d2c46f18d1b4.png)

```.js
// テーブル
DATE_DIFF(開始日付,終了日付,"days")+1

// 番号
ROWNO(テーブル)+1

// 日付
DATE_ADD(開始日付,ROWNO(テーブル),"day")

// 日付_６ヶ月後
DATE_ADD(日付,6,"month")

// 日付_６ヶ月後の前日
LET(
  a,DATE_ADD(日付,6,"month"),  // ６ヶ月後
  DATE_ADD(a,-1,"day")  // ６ヶ月後の前日
)
```

# LET 関数の解説

LET 関数で変数を使うと、ネストが深い計算式を分かりやすく記述できます。

```LET 関数を使わない例.js
DATE_ADD(DATE_ADD(日付,6,"month"),-1,"day") // ６ヶ月後の前日
```

変数a に６ヶ月後の日付を入れて、a の前日を求めます。
```LET 関数を使った例.js
LET(
  a,DATE_ADD(日付,6,"month"),  // ６ヶ月後
  DATE_ADD(a,-1,"day")  // ６ヶ月後の前日
)
```

# DATE_ADD 関数（日付加算）の解説

日付、日時に指定した単位(type)の値を加算します。
マイナスの値を加算することで、減算できます。

- DATE_ADD(formula|"TODAY", num, type[, format])
    - formula ： fieldcode, string, number, "TODAY"
        - fieldcode： 日付
        - string： (ex:"2023-07-12")
        - number： (ex:1689151920) ※ "2023-07-12" の UNIX時間
        - "TODAY"： 本日の日時 "YYYY-MM-DD HH:MM"
    - num： 数値、formula
    - type : "year", "month", "week", "day", "hour", "minute", "second"
    - format ： default("YYYY-MM-DD")
        - ※DATE_ADDは、moment.js というライブラリを使っており、その書式が使えます。
        - [moment.js の書式](https://momentjs.com/docs/#/displaying/format/)
静的型付け言語の仕様

新しくkotlin言語を学ぶことになったので、静的型付けの仕様をアウトプットする。

PythonやJavaScriptなどの動的型付け言語は以下のようなコードは許される
``` py
x = 10
print(x)  // 10

x = "Hello world"
print(x) // Hello world

```
一方、JavaやKotlinで同じことをすると、
``` kotlin
fun main() {
    var num = 10
    num = "Hello world"
    // Type mismatch: inferred type is String but Int was expected
}
```
エラーとなる。最初にInt型として宣言されたので、それ以外の型は受け付けなくなる。


でも、型変換する方法はあり、以下のような書き方がある。
``` kotlin 
 val t : String = "50"
 val i : Int = Integer.String.toInt(t)
```
文字列から数値、
``` kotlin 
 val a : Int =  400
 val s : String = a.toString()
```
数値から文字列に変換できる。

#### 参考

https://qiita.com/nimani/items/040dd28717eabe3ea781

https://pouhon.net/kotlin-infer/1022/
【SwiftUI】ポンポン跳ねるボールの作り方

# はじめに
SwiftUIでスーパーボールのように跳ねるボールを作ります。

# 対象者
SwiftUIの基本的な使い方を知っている人

# やり方
    
```swift
import SwiftUI

struct ContentView: View {
    // ボールの位置
    @State private var y: CGFloat = 0

    // ボールの速度
    @State private var velocity: CGFloat = 0

    // アニメーション中かどうか
    @State private var isAnimating: Bool = false
    
    // 重力加速度
    // メートルをポイントに置き換えて考えている
    private let gravity: CGFloat = 9.8

    // 反発係数
    private let bounce: CGFloat = 0.8
    
    // ボールのサイズ
    private let ballSize: CGFloat = 70
    
    // タイマー
    private let timer = Timer.publish(every: 0.01, on: .main, in: .common).autoconnect()
    
    var body: some View {
        GeometryReader { geometry in
            ZStack {
                Color.white
                Circle()
                    .fill(.red)
                    .frame(width: ballSize, height: ballSize)
                    .position(x: geometry.size.width / 2, y: y)
            }
            .onTapGesture {
                // タップしたらアニメーションを開始する
                startAnimation()
            }
            .onReceive(timer) { _ in
                if isAnimating {
                    // 0.01秒ごとにボールの位置を更新する
                    updatePosition(height: geometry.size.height)
                }
            }
        }
        .ignoresSafeArea()
    }
    
    private func startAnimation() {
        if isAnimating {
            // 2回目以降はボールの位置と速度を初期位置に戻す
            y = 0
            velocity = 0 
        } else {
            isAnimating = true
        }
    }
    
    private func updatePosition(height: CGFloat) {
        // 速度に重力加速度を加える
        velocity += gravity

        // ボールの位置を更新する
        // 0.01秒ごとに更新するので、1/100倍する
        y += (velocity / 100)
        
        // ボールが床に着いたら反発する
        if y > height - ballSize / 2 {
            y = height - ballSize / 2
            velocity *= -bounce
        }
    }
}
```

# おわりに
SwiftUIでスーパーボールのように跳ねるボールを作りました。この記事が参考になったと思ってくださった方はいいねとフォローしていただけると励みになります☺️
【SQL Server】拡張イベント①

Oracle Databaseを使用しているお客様がSQL Serverを検討する際に気にされる点がいくつかありますが、その一つにSQLによる性能劣化があります。

Oracle DatabaseではStatspackやAWRレポートでDBの稼働統計を取得し、SQLの性能調査を行うことができます。
SQL Serverでは、**「拡張イベント」** を使用することで上記とほぼ同様のことが行えます。

本記事では拡張イベントの概要について記載します。

## 拡張イベントとは

SQL Server内で発生したイベント情報や、それに関連する情報を記録することができる機能です。
MS公式ドキュメントでは以下のように記載されています。

>拡張イベント アーキテクチャを使用すると、ユーザーは、SQL Server、Azure SQL Database、Azure SQL Managed >Instanceのパフォーマンスの問題のトラブルシューティングや特定に必要なデータをできるだけ多くまたは少なく収集できます。★

拡張イベントが使用できる前は、SQLトレースやSQL Server Profilerという機能があったようですが、それらは非推奨となっているようなので拡張イベントを使用するようにしましょう。

## 拡張イベントで設定する項目

**イベントを選択**
例)
&emsp;&emsp;SQLの情報を取得する
&emsp;&emsp;ストアドプロシージャの情報を取得する
&emsp;&emsp;バッチ処理の情報を取得する

**選択したイベントから取得する情報を指定**
例）
&emsp;&emsp;SQLの全文
&emsp;&emsp;CPU実行時間
&emsp;&emsp;物理読み込み量

**取得する情報のフィルタリング**
例）
&emsp;&emsp;実行時間が10秒以上

上記で設定した情報はリアルタイムで確認することも可能ですが、xelファイルとして作成してある時点の性能状態と比較するといったことも可能です。

#### 参照サイト

■拡張イベントの概要
　https://learn.microsoft.com/ja-jp/sql/relational-databases/extended-events/extended-events?view=sql-server-ver15

■CREATE EVENT SESSION (Transact-SQL)
　https://learn.microsoft.com/ja-jp/sql/t-sql/statements/create-event-session-transact-sql?view=sql-server-ver16

■SQL:StmtCompleted イベント クラス
　https://learn.microsoft.com/ja-jp/sql/relational-databases/event-classes/sql-stmtcompleted-event-class?view=sql-server-ver16
初投稿

初めまして、よーです。
来年の4月から、SIerでSEとして働くことが決まったので備忘録も兼ねて自分のペースで学んだことを投稿していこうと思います。
## 自己紹介
・休学中の経済学部の4年生（23歳）
・プログラミング経験は授業とゼミでのR言語
・来年の4月から金融系のSIerに入社予定
## 入社までの取り組み
・基本情報技術者試験の勉強（今年の9月までには取る予定）
・Javaの勉強
## 最後に
自由気ままにアウトプットしていこうと思っています。よろしくお願いします！
AWSのS3 Selectを使ってみた

S3でSQL文が使えるんですね。知らなかったです。
さっそく使ってみました。

入力となるJSONファイルはS3上にこんな感じである前提です。

```json:test/data.json
{
	"info": "This is sample",
	"data_list": [
		{
			"x": 1,
			"value": 11,
			"comment": "comment 1-1"
		},
		{
			"x": 1,
			"value": 12,
			"comment": "comment 1-2"
		},
		{
			"x": 2,
			"value": "21",
			"comment": "comment 2-1"
		},
		{
			"x": 2,
			"value": 22,
			"comment": "comment 2-2"
		}
	]
}
```

そして、コードです。

```js
var AWS = require('aws-sdk');
AWS.config.update({
  region: "ap-northeast-1",
});
var s3  = new AWS.S3({
});

const S3SELECT_DELIMITER = '\n';

const sql = 'SELECT * FROM s3object[*].data_list[*] AS s';

	const params = {
		Bucket: 'bucket-test',
		Key: 'test/data.json',
		ExpressionType: 'SQL',
		Expression: sql,
		InputSerialization: {
			JSON: {
				Type: "DOCUMENT"
			}
		},
		OutputSerialization: {
			JSON: {
				RecordDelimiter: S3SELECT_DELIMITER
			}
		}
	};

	var result = await s3.selectObjectContent(params).promise();
	console.log(result);

	const events = result.Payload;
	let list = [];
	for await (const chunk of events) {
		if( chunk.Records){
			var t1 = chunk.Records.Payload;
			var t2 = t1.toString();
			var t3 = t2.split(S3SELECT_DELIMITER);
			for( const item of t3){
				if( item )
					list.push(JSON.parse(item));
			}	
		}
	}
	console.log(JSON.stringify(list, null, '\t'));
```

結果は以下のように出力されます。

```
[
	{
		"x": 1,
		"value": 11,
		"comment": "comment 1-1"
	},
	{
		"x": 1,
		"value": 12,
		"comment": "comment 1-2"
	},
	{
		"x": 2,
		"value": "21",
		"comment": "comment 2-1"
	},
	{
		"x": 2,
		"value": 22,
		"comment": "comment 2-2"
	}
]
```

後処理の部分がわかりにくいかもしれませんが、result.Payloadは、Readable Streamです。

以下の部分がSQL文に相当します。JSONの中のdata_listをSQLの対象にしています。

```js
const sql = 'SELECT * FROM s3object[*].data_list[*] AS s';
```

また、一番やりたかった出力をフィルタリングしたい場合は、例えば以下のように書き換えると

```js
const sql = 'SELECT s.x, s.value FROM s3object[*].data_list[*] AS s WHERE s.x = 1';
```

以下のような出力となります。

```
[
	{
		"x": 1,
		"value": 11
	},
	{
		"x": 1,
		"value": 12
	}
]
```

ちなみに、今回は入力ファイルがJSONの場合でしたが、もしJSON Linesの場合は、以下の部分を

```js
			JSON: {
				Type: "DOCUMENT"
			}
```

以下のように変えます。

```js
			JSON: {
				Type: "LINES"
			}
```

入力ファイルとしてCSVの場合が多いかもしれませんが、詳細は以下ご参照ください。

（参考）
　https://aws.amazon.com/jp/blogs/developer/introducing-support-for-amazon-s3-select-in-the-aws-sdk-for-javascript/
　https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#selectObjectContent-property

ちなみに、ちゃんとMINIOでも動いてくれますよっ

# おわりに

うーん、ルートが配列のJsonファイルはダメっぽいなあ

以上
【Python】OpenAIのWhisperで音声文字起こしアプリを作成！

# はじめに
OpanAI社の音声文字認識エンジンのWhisperを使って、音声文字起こしするプログラムを作成しました。
プログラムはPythonからAPIでWhisperを使って、音声文字認識する形式です。
約2分の音声を試したところは、Whisperの音声文字認識の精度は99%とAmiVoiceCloudPlatform(96%)以上の精度でした。
2分の動画を約9秒で変換できるなど、非常に使い勝手の良いAPIです。
価格は1分あたり0.9円（0.006ドル）です。
ただし、Whisperのインプットの音声ファイルの容量は25Mバイトですので、それ以上のファイルは分割する必要があります。


# 環境
Windows10
Python3.8.8
VSCode

# 使用ライブラリー
openai
pydub
tkinter
openpyxl
pandas

# 処理の流れ:
今回作成した処理は、音声ファイルをインプットに、1分単位に音声を分割し、その音声をOpenAIのWhisperという音声文字認識エンジンをAPIで接続し、文字認識した文字をエクセルにセットするプログラムです。
また、1分単位に分割したファイルへのハイパーリンクを設定することで、変換後の文字を見ながら、音声ファイルをすぐに開ける構成にしています。
![OpenAI_Whisper_105.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1361368/a90995ca-6a02-7233-0550-28571c13f357.png)



# YouTubeでの解説：
上記の作業の流れをYoutubeで詳しく解説していますので、ぜひ、ご覧ください。
<iframe width="560" height="315" src="https://www.youtube.com/embed/RikW7r1zIy8" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" loading="lazy" allowfullscreen></iframe>

# サンプルソース
YouTubeで紹介している１つ目の処理のプログラムソースです。
```Python:whisper0.py
import openai
import os
openai.api_key = os.getenv("OPENAI_API_KEY")

audio_file= open("./sample1.wav", "rb")
transcript = openai.Audio.transcribe("whisper-1", audio_file)

print(str(transcript["text"]))
```

# 完成版プログラム
完成プログラムは、以下のYoutubeの概要欄に限定公開したQiitaのURLを公開していますので、そちら経由でご覧ください。
https://youtu.be/RikW7r1zIy8


# 最後に：
今回は、音声ファイルをインプットに音声を文字変換するプログラムをご紹介しました。
今後も、役立ちそうなプログラムをご紹介していきたいと思います。
Jetson Orin Nanoで YOLOv8を動かす

* Jetson Orin Nano 8GB
* logicool C270N
* micro SDXC 128GB
* JetPack 5.1.1 (Ubuntu 20.04.5 LTS, Python 3.8.10, OpenCV 4.5.4)

## パッケージ一覧の更新等
sudo apt update
sudo apt install nano
sudo apt install python3-pip

## torchのインストール
参考：https://wiki.seeedstudio.com/YOLOv8-DeepStream-TRT-Jetson/

sudo apt install libopenblas-base libopenmpi-dev

wget https://developer.download.nvidia.com/compute/redist/jp/v50/pytorch/torch-1.12.0a0+2c916ef.nv22.3-cp38-cp38-linux_aarch64.whl -O torch-1.12.0a0+2c916ef.nv22.3-cp38-cp38-linux_aarch64.whl

pip3 install torch-1.12.0a0+2c916ef.nv22.3-cp38-cp38-linux_aarch64.whl

## torchvisionのインストール
sudo apt install -y libjpeg-dev zlib1g-dev

git clone --branch v0.13.0 https://github.com/pytorch/vision torchvision

cd torchvision
python3 setup.py install --user
cd

## その他ライブラリのインストール
sudo pip3 install tqdm==4.65.0
sudo pip3 install seaborn==0.12.2
sudo pip3 install psutil==5.9.5

## YOLOv8のインストール
参考：https://i7y.org/yolov8-on-jetson-nano/

git clone https://github.com/ultralytics/ultralytics
cd ultralytics/

```:requirements.txt（全行、無効にしておきます。）
# matplotlib>=3.2.2
# opencv-python>=4.6.0
# Pillow>=7.1.2
```
cd
sudo pip3 install ultralytics/

## YOLOv8の動作確認
yolo task=detect mode=predict model=yolov8n.pt source=0 show=True imgsz=256

:::note info
Jetson Orin Nano：1 frame：0.0254s（39.37fps）
:::
Code Interpreterをいっぱい使ってみたかったけどそもそもデータがなくて何もできなかった話

# 最初に
待ちに待ったCode Interpreter。
でもどうやって使うのかわかんない人も多いと思います。
私もです。

何に使うか決まっていないまま出てきたので、とりあえず予習としてみていた動画をそのまま手元で動かしてみようと思います。
データがないやつはできないです。

参考にした動画はこれです。

https://www.youtube.com/watch?v=O8GUH0_htRM&t=551s

# その前に結論
タイトルの通りデータがないとできること少ねぇ・・・
上の動画を紹介できればこの記事の99％は完了したようなもの

# 3D surface map

```
Create a 3d surface map from this data. Output  downloadable HTML file.
```

fileの場所

https://github.com/plotly/datasets/blob/master/volcano.csv

出力
```
The data appears to be a 2D grid of values, with each column labeled from V1 to V61. This sort of data is often used to represent a 3D surface where the two dimensions are spatial (x, y) and the values in the grid represent a third dimension (z). 

Let's use the column and row indices as the x and y coordinates and the values as the z coordinates to create a 3D surface plot. We'll use Plotly, a Python graphing library, to create the plot and save it as an interactive HTML file.

I have generated the 3D surface plot and saved it as an interactive HTML file. You can download it using the link below:

```

出力されたHTMLファイルの張り方が分からなかったので画像だけになります。
データを使えばだれでも同じものは作れるはずです。
![volcano.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193625/1c5c9cb0-0e62-c316-dbd2-22a8be637b44.png)

すっご・・・

# Time series range slider and selectors
データがなかったので(kaggleとかにあるのかな・・・？)、データから作ってもらい、Time series range slider and selectorっていう表を作りました。
こんなグラフの名前知らんて・・・

出来たのがこれ、
![stock.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193625/58141ebc-0f32-2cbc-4368-5eadaf34606f.png)

色んな種類のグラフの名前を調べたくなった。

# 色々試して分かったこと
* 動画内ではもっと多くのことをやっていたが、そもそもデータがないとデータサイエンスも何もできない(当たり前)
* グラフの種類を知り、効果的なグラフの選択ができるようになれば、もっと便利に使える
* 動画内では音声の出力とかもやっていたのですごいなぁーって思った。
* データはkaggleとかにあるのかなぁ。。。
* もっといろんな使い方を調べる必要あり
IFの条件をリストで管理しよう

# TL:DR
PythonでIF文で条件判定する際,値を直接指定するよりも条件をリストに格納したほうが保守性・可読性ともにいいよ,という話です。なんだかんだ説明するよりもコードを見たほうが早いので早速見てみましょう。

## 直接指定の場合
例えば下記のようなA or BのいずれかでPrintするといったとき、こんな感じで書くと思います。
```Python
if (hoge == 'aaa') or (hoge == 'bbb'):
    print('Hello world')
```

この場合、条件に変更が生じてしまうと、if文をいじくる必要があるわけですね。
値そのものが変わったり、判定すべき値が増えるとなるとめんどうです。
また、含めたい条件が増えれば増えるほどコードの文量が増えて可読性が落ちてしまいます。

## リスト管理の場合


```Python
conditions = ['aaa','bbb']  # 条件を格納した変数
if hoge in ['aaa','bbb']:
    print('Hello world')
```
すっきりしていますね。
条件の増減や値の変更があっても、格納部分をいじくってしまえばOKです。
コードは短いほうが可読性があがり、読み手に処理の意図を伝えやすくなります。
#07 ブックマークレットでボタンをクリックしたいときにIDが振られていないときの対処法

### 動機：ブックマークレットでログインを楽したい。
とあるログインフォームがIDとパスワードを保存できないうえに、プルダウンメニューもありというめんどくさい仕様で毎度手間だったのでブックマークレットでID、パスワードの入力、プルダウンメニューの選択、ログインボタンを押すをやってもらおうと思ったのだが、詰まったところがあった。

### 課題：フォームにIDが振られていない
IDもnameも属性が振られていないので
document.getElementsByNameやdocument.getElementsByIdが使えないとなって困った。

### 解決策：document.allを使う。
document.allですべての要素をリストで取得できる。なのでnをあらかじめ調査しておけば、
以下のようにボタンを押してもらえる。

~~~javascript:javascript
document.all[n].click();
~~~
モダンアクティビティを使ってみた(Excel編Part4～最初と最後のデータ行を検索？なにそれ？～)

## はじめに
①本記事は、2023年7月開催の「UiPathブログ 発信チャレンジサマー」の8日目のブログです。
ブログの詳細、参加方法については以下のブログを参照ください。
https://note.com/shumpei_w/n/nd082bdf28853
②このブログ情報は、2023/7時点の情報です。
③UiPathはCommunity Edition、Versionは2023.6.1を使用しています。

## 前回のおさらい
第1回、第2回目、第3回は以下をご覧ください。
・モダンアクティビティを使ってみた(Excel編)
https://qiita.com/saosao885/items/3401b0d8708cc5fb3d3c
・モダンアクティビティを使ってみた(Excel編Part2～グラフも作れるのかや？～)
https://qiita.com/saosao885/items/c27b9171317481b37530
・モダンアクティビティを使ってみた(Excel編Part3～グラフを取得？更新？知っちょん？～)
https://qiita.com/saosao885/items/b27d891e44a56418204b

3回目までにグラフを扱うアクティビティを学びました。
4回目は何をしましょうかね～？

## 今回は？
クラシックになくて、モダンにあるやつで探してみよう！
ということで、アレコレ探してみると、「最初/最後のデータ行を検索」アクティビティというものが(´・ω・)なにそれ？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/e0005ca3-96dc-1659-0c04-55afb83d78a3.png)

「最初と最後のデータ行を検索」というアクティビティは、どんなことができるのでしょうか。
公式のドキュメントを見てみましょう。
https://docs.uipath.com/ja/activities/other/latest/productivity/find-first-last-data-row-x
<b>指定したシート、範囲または表内で、データの開始行と最後の行の番号を検索します。</b>

プロパティは以下わかる範囲でまとめました。(これだけあれば大丈夫な...はず)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/5dc28e15-b133-e78b-0bc1-8bd6e9b0c559.png)
なるほど( ..)φメモメモ...じゃどんな感じなのか、使ってみましょう。
## やってみよう
以下のサンプルデータを用意します。
(中身は特にツッコむ要素なし)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/9d9854a4-3049-43e8-6321-4e828e64c0a8.png)

## 使ってみる
まずは、ソースを設定します。シート名を"Sheet1"に設定しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/cf4a5985-f3ae-65e0-073a-3c57e8eadb80.png)
今回は先頭行をヘッダーにするので、チェックはつけたまま。
列名は「出身県」で設定しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/7ccbfba4-2f9e-368f-883c-4f85552496ba.png)
これで実行した結果をログに出してみると...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/46d56a9e-afed-aee5-9902-a5a9fd85f715.png)
ほほう、ヘッダーの1行目は無視して、最初行のデータは2行目、最終行のデータの行番号の6行目を取得できました。
ちなみに、表示行のみでチェックを入れるとどうなるのか見てみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/36ba2765-166f-8d63-66e7-33f35e06976a.png)
表示行の場合は1行目がヘッダーではなくなるので、列名が"出身県"のままだとエラーになります。
なので、列名はB列の"B"と記載しましょう。
「表示行のみ」にチェックを入れて実行してみると...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/4fe65cb6-f701-6828-9213-c4eaeae45483.png)
最初の行が1行目になりましたね。
## つまりこういうこと？
ヘッダーor表示行のチェック、最後の行or最初の空の行によって出力される数字も変わってきます。
先程のデータで調べるとこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/99a5782c-d381-93cf-5c81-f563c070bb11.png)

## おまけ
先程のファイルのデータにちょいと行を増やしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/4d11083b-dcfd-4eaa-07c7-12ce5b71fcf0.png)
「先頭行をヘッダーとする」と、「表示行のみ」を両方チェックするとどうなるのでしょうか？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/969ff9af-d4c9-8d55-2750-49e66e4f0427.png)
結果は以下の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/dd6f9d05-8d64-0d90-75e7-c6a03454fa50.png)
最後の行が「先頭行をヘッダーとする」をチェックをしただけの時と同じでした。
(別にエラーにならないのか...なるほど)


## まとめ
最初の行、最後の行の位置を取得できるのは便利だと思いました。
(もしかしたらあまり使わないかも...？)
皆様も機会があれば使ってみてください。

最後までお読みいただきありがとうございました。
Storybook + Vue 3 + Vuexを使う方法

Vue3のコンポーネントかつVuexのストアへのアクセスのあるコンポーネントをStorybookで描画する際にあまりドキュメントがなかったので、備忘録としてメモっときます。


storybook vuexとかでググるとStack Overflowの記事などもでてきますがどれも`vue.use(Vuex)`を用いるvue2向けの手法や現在storybookではdeprecated になっている`config.js`を用いるものばかりでした。


Storybookの公式ではPiniaを用いたケースしか載っておらず、Piniaは型推論も効きますし便利ではありますが、Storybookでコンポーネントやページのデザイン検証が必要な規模のプロジェクトはまだまだVuex使っているところも多い気がします。そんな人々の助けになればと。
```.storybook/preview.ts
import type { Preview } from "@storybook/vue3"
import { setup } from "@storybook/vue3";
import { createStore } from "vuex"
const store = createStore({hogehoge})
setup(app => {app.use(store)})

const preview: Preview = {
  ...
}

```

これで`this.$store` への参照をStorybook内でレンダリングされたコンポーネントでも行うことができコミットなどのミューテーションも行うことができます。
【Laravel】Breeze + InertiaでフロントエンドをSPA化する

# やりたいこと
LaravelプロジェクトにLaravel BreezeとInertiaを導入して、フロントエンドをSPA化していきます。

# 動作環境
* PC：Macbook
* CPU：Intel
* OS：MacOS Ventura 13.4
* Laravel：Laravel9.x, Sail

# 導入
### 1. Laravel Breezeをインストール
以下のコマンドを実行します。

```
$ sail composer require laravel/breeze --dev
```

### 2. Inertiaを導入する
以下のコマンドを実行します。
フロントエンドにReactとVue.jsのどちらを使用するかでコマンドが異なります。

```
# Vue.jsを使用する場合
$ sail php artisan breeze:install vue

# Reactを使用する場合
$ sail php artisan breeze:install react

# nodeパッケージをインストール（上のコマンド内で実行される場合は不要）
$ npm install
```

# 実行
以下のコマンドを実行してフロントエンドのサーバを立ち上げることができます。

```
$ npm run dev
```

<br>
以上です。
AWS Amplify + RDSでPrismaアプリをデプロイ

AWS Amplifyは、GitリポジトリにソースコードをプッシュするだけでNext.jsアプリをデプロイしてくれる便利なホスティングサービスです。今回は、Next.jsとPrismaで作成したアプリをAmplify上で動かしてみます。

# RDSの準備

RDSでMySQLサーバーを立ち上げる手順は割愛します。

## ファイアウォールの設定

EC2からRDSに接続するのは簡単ですが、AmplifyからRDSに接続する方法は公式ではサポートされていません。少々トリッキーな方法が必要です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147207/53627fc0-89f4-bd78-08f7-8ba0c85deb9b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147207/519d36b1-2128-4107-608a-e83bd2c4c011.png)

セキュリティグループを新規作成し、インバウンドでTCP/3306 (MySQL)を許可します。

:::note warn
AmplifyのIPアドレスが不明なので一旦すべての接続元 `0.0.0.0/0` を許可していますが、これだと誰でも接続できてしまいますので、AmplifyのIPアドレスが判明したら接続元は制限しておくべきです。
:::

## データベースの作成

適当なMySQL接続ツールで `CREATE DATABASE` 文を流してください。

# Amplifyの準備

Amplifyを選択して、「ウェブアプリケーションをホスト」を選んで必要情報を入力してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147207/545e3318-5dbb-5814-eca4-5e55f0813852.png)

設定が終わると自動的にデプロイが始まります。

## 環境変数(.env)の設定

環境変数は管理コンソールから設定できますが、実はこれだけでは動きません。ここで設定した環境変数はビルド時に有効ですが、アプリ起動時には有効にはならないためです。アプリ起動時にも有効にするには一手間必要です。

`amplify.yml` の build → command を以下のように修正します。

```yml:amplify.yml
    build:
      commands:
        - echo "SLACK_CLIENT_ID=$SLACK_CLIENT_ID" >> .env
        - echo "SLACK_CLIENT_SECRET=$SLACK_CLIENT_SECRET" >> .env
        - echo "NEXTAUTH_URL=$NEXTAUTH_URL" >> .env
        - echo "NEXTAUTH_SECRET=$NEXTAUTH_SECRET" >> .env
        - echo "DATABASE_URL=$DATABASE_URL" >> .env
        - npm run build
        - npx prisma migrate deploy
        - npx prisma db seed
```

トリッキーな方法ですが、公式で案内されている方法です……

https://docs.aws.amazon.com/ja_jp/amplify/latest/userguide/environment-variables.html#access-env-vars

:::note info
ここで修正した `amplify.yml` はGitリポジトリのルートディレクトリに置いておくのがおすすめです。
:::

## 再デプロイ

「このバージョンを再デプロイ」というボタンを押すとデプロイが始まります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147207/c6365f47-da8a-d634-8949-1840fdf95093.png)

以降、Gitリポジトリにプッシュするだけでデプロイできるようになります。

# デプロイしたアプリがうまく動かない場合

**CloudWatch** で実行ログを見ることができます。
pythonでDataFrameを.texに埋め込んでpdfで出力する

## はじめに
この記事では python 3.9.13 を使って、Jupyter Notebook 環境でコーディングしてます。
ファイル名などは適宜読み替えてください。

また、tex のインストールが必要です。

## やりたいこと

python で DataFrame 作成
↓
DataFrame を TeX に書き出し
↓
TeX のエディターでコンパイル、pdf 出力

一連の動作を python で全部やってもらいたいです。

### 必要なモジュール
必要なモジュールを以下に示します。

```python:python
# モジュールのインポート

import numpy as np
import pandas as pd
import os
import subprocess

!pip install Jinja2
from jinja2 import Template, Environment, FileSystemLoader
```

numpy、pandas はテスト用の DataFrame 作成に、
os、subprocess は tex ファイルのコンパイルに使用します。

jinja2 は今回は tex のテンプレートを作成するのに使用しました。 


### DataFrame を tex の書式に変更

まず、テスト用に適当な DataFrame を作成します。
作った DataFrame に対して、 pandas のメソッドである .to_latex を呼び、tex の書式に書き下します。

```python:python
# 埋め込むdf作成
df = pd.DataFrame(np.arange(32).reshape(8,4), columns=list("abcd"))

# dfをtexの書式に変更
print(df.to_latex())

# 出力
print(df.to_latex())
```

実行結果は以下の通りです。

\begin{tabular}{lrrrr}
\toprule
{} &   a &   b &   c &   d \\
\midrule
0 &   0 &   1 &   2 &   3 \\
1 &   4 &   5 &   6 &   7 \\
2 &   8 &   9 &  10 &  11 \\
3 &  12 &  13 &  14 &  15 \\
4 &  16 &  17 &  18 &  19 \\
5 &  20 &  21 &  22 &  23 \\
6 &  24 &  25 &  26 &  27 \\
7 &  28 &  29 &  30 &  31 \\
\bottomrule
\end{tabular}

.to_latex() は色々なオプションがあるので、詳しくは参考サイトをご覧ください↓
[【python】pandasのDataFrameをLaTeX出力](
https://www.haya-programming.com/entry/2018/05/31/020009)


### jinja2 によるテンプレートへの埋め込み

次に、jinja2 で tex のテンプレートを作成します。

```jinja:tex_temp.j2
\documentclass[11pt,a4paper]{jsarticle}
%
\usepackage[dvips]{graphicx}

・
・
・

\newcommand{\rot}{\mathrm{rot}\,}  
%
\pagestyle{myheadings}
%

\begin{document}

{{ glaph }}

\end{document}
```

jinja2 では、{{ }} 内の変数名を指定することで 任意の文字列を埋め込むことができます。

作った jinja2 のファイルを読み込んで、埋め込みます。

```python:python
#テンプレート読み込み
env = Environment(loader=FileSystemLoader('./', encoding='UTF-8'))
tmpl = env.get_template('tex_temp.j2')

# 挿入するやつの指定
ren_s = tmpl.render(glaph=df.to_latex())
```

### テンプレートに埋め込んだものを tex ファイルに変換

モジュール：os と、open() を使って、任意のディレクトリ内に .tex ファイルを作成します。

```python:python
# 新しくファイル作ってそこに書き込む関数の作成
def save_file_at_dir(dir_path, filename, file_content, mode='w'):
    os.makedirs(dir_path, exist_ok=True)
    with open(os.path.join(dir_path, filename), mode) as f:
        f.write(file_content)

# 実行
save_file_at_dir('F:\study', 'test_2.tex', ren_s)
```

### コンパイルして pdf ファイルの作成

最後に、モジュール：subprocess を使って、.tex ファイルをコンパイルします。

subprocess とは、指定したコマンドをコマンドプロンプトで実行してくれるモジュールです。

```python:python
subprocess.run(['platex', r'F:\study\test_2.tex'])
subprocess.run(['dvipdfmx', r'F:\study\test_2'])
```

python の実行結果に returncode=0 が表示されていればコンパイル成功です。

.tex ファイルと同じディレクトリに内に新しく .pdf ファイルが生成されます。

## おわりに
私は、 jinja2 でテンプレートを作成するときに文字コードの変換でこけたので、文字コードの変換ができるテキストエディタ（terapadとか）をダウンロードしておくといいかもしれません。

# 参考サイト
・[テンプレートエンジンの使い方（jinja2）](https://myafu-python.com/syntax/library/jinja2/)
・[【python】pandasのDataFrameをLaTeX出力](
https://www.haya-programming.com/entry/2018/05/31/020009)
・[Pythonで新しいディレクトリにファイルを作成・保存](https://note.nkmk.me/python-save-file-at-new-dir/)
プログラミング初心者が学ぶ「再帰」

## はじめに
前回の記事で、抽象化というプログラミングの基本的な概念を説明しました。
[プログラミング初心者が学ぶ「抽象化」](https://qiita.com/as0088to/items/87cf9d0d61e1eb479251)

今回は「**再帰**」について学びます。「再帰」を理解するために自分なりにまとめてみようと思います。私自身まだ学習途中なので、何か間違いがあるかもしれません。もしご指摘やアドバイスがありましたら、ぜひコメント欄からお知らせください。
プログラミングにおいて、再帰は非常に重要な概念で、繰り返しを必要とする処理を簡潔に記述するために使用されます。
## 再帰とは
再帰とは、**あるプロセスが自分自身を参照、または自分自身を含む振る舞いを示すこと**を指します。この概念は、自然科学、数学、芸術、哲学、そしてコンピュータサイエンスなど、多くの分野で利用されます。

マトリョーシカ人形を思い浮かべてみてください。最初の大きな人形を開けると、その中にさらに小さな同じ形の人形が入っています。それを開けると、さらに小さな人形が出てきます。この繰り返しを最後の最小の人形に辿り着くまで続けます。ここで、大きな人形から最小の人形へと進むこのプロセスが再帰の一例と言えます。

プログラミングで使わる再帰は、再帰関数、再帰プログラミングと呼ばれています。**再帰関数**とは、**ある関数において自分自身を再度呼び出す関数**のことを指します。一見難しく思えるかもしれませんが適切に利用すると、複雑な問題を簡単に解決することができます。
　
簡単な例を挙げると、階乗の計算があります。

Pythonで「5の階乗」を記述すると
```Python
def factorial(n):
    if n == 1:
        return 1
    else:
        return n * factorial(n-1)

print(factorial(5))  # Output: 120
```
「5の階乗」は「5と、4の階乗の掛け算」、「4の階乗」は「4と、3の階乗の掛け算」…という風に、関数が自身を呼び出すことで計算が進行していきます。。最終的には、「1の階乗」が1と定義されているので、計算はそこで止まり、全ての掛け算の結果を返します。
このコードでは、factorial(5)は5 * factorial(4)と処理され、これはさらに5 * (4 * factorial(3))と処理されます。このプロセスはnが1になるまで続きます。そのため、factorial(5)は最終的に5 * 4 * 3 * 2 * 1と評価され、その結果は120になります。このように、自分自身を再び呼び出す関数を再帰関数と呼びます。

再帰関数を理解するためには、主に**2つの重要な構成要素**を理解する必要があります。
* **ベースケース**：ループが終了する条件。つまり、再帰呼び出しを止める条件です。これがないと、関数は無限に自身を呼び続け、プログラムは無限ループに陥ってしまいます。

* **再帰ケース**：ベースケースに到達するまで、関数が自身を呼び出す部分です。

先ほどの関数で考えると、

```Python
#ベースケース　この部分がないと無限に関数が呼び出される。
if n == 1: 
    return 1

#再帰ケース　自分自身を呼び出す。
else: 
    return n * factorial(n-1)
```
## 再帰のデメリット
再帰には多くのメリットがある一方で、デメリットも存在します。

**デメリット**
* 関数が自分自身を深く呼び出す場合、コンピュータのメモリが不足する可能性があります。これを「スタックオーバーフロー」と呼びます。
* 非再帰的なプログラムに比べて、再帰は計算リソース（時間やメモリ）を多く消費する可能性があります。
## まとめ
再帰はプログラミングの基本的な概念であり、その使用方法を理解することは非常に重要です。再帰を適切に用いると、難しい問題をシンプルに表現することができ、コードが整理され、読みやすくなります。

しかし、扱いに注意する必要があります。適切なベースケースを設定しなければ、関数が永遠に自分自身を呼び出し続け、プログラムが停止しなくなる「無限ループ」に陥る可能性があります。

また、再帰関数が深く自身を呼び出す場合は、コンピュータのメモリを大量に消費し、パフォーマンスに影響を与える可能性があります。そのため、再帰を使用する際には、その効果と限界を理解し、適切なケースで使用することが求められます。また、再帰の深さを理解し、不要な深さを避けることも重要です。
oxゲーム (TicTacToe)を作ったので学んだことをシェア

## tl;dr
* `python`をつかってconsoleで動くoxゲームを作りました。ソフトウェア・アーキテクチャ構築練習のために、**スケーラビリティ**、**コードの読みやすさ**、**使いやすさ** を考慮して作成しています。
* `CPU vs CPU`, `CPU vs Player`, `Player vs Player`の3モードを制作しています。ゆくゆくはネットワークでの対戦機能も追加したり、Console以外でのinput / outputも追加してみたいと思います。
* ゲームとしては特に難しいロジックはないですが、コードを読みやすくすることや、モジュール同士の組み合わせなどに想定以上に時間がかかりました。ただ自分で満足いく形になった時はレゴブロックを完成させたような達成感を味わえました。

#### 制作物
Publicにしているため、もしよければ、コードレビューいただけると大変嬉しいです。
https://github.com/ZawaPaP/TicTacToe

### 学んだこと
* コード内にマジックナンバーは使わない
    * マジックナンバーは何を意味しているのかわからない。`Enum`などを使うようにする

* 関数はBehaviorを表す
    * 各関数をどのクラスに配置するべきかに悩まされた。一つ指標になりそうなのが、関数は`behavior`を表すということ。関数名を動詞にするというのと相まって、しっくり来た
    * クラス、インスタンス変数に直接アクセスするのではなく、関数を使ってアクセスする。以下は例だがクラスの定数を取得するだけの関数を作成して、外部モジュールからは関数を使用して、アクセスする。
```python
from game_mark import GameMark
from typing import Tuple

class BoardCell:
    def __init__(self) -> None:
        self.mark = GameMark.EMPTY.value

class GameBoard:
    ROW = 3
    COLUMN = 3

    def __init__(self) -> None:
        self.board = [[BoardCell() for _ in range(self.column())] for _ in range(self.row())]

    @staticmethod
    def row() -> int:
        return GameBoard.ROW

    @staticmethod
    def column() -> int:
        return GameBoard.COLUMN

```

* 再帰について
    * 再帰はコードを追いづらく、エラーハンドリングもしづらいため可能な限り使わない。
    * ツリーやグラフなど親でも子でも帰ってくるデータが同じように見えるケースの場合のみ、使用を検討する

* 命名
    * Handlerという名前をつけるなら、Handler内で処理を完結させ、Returnしないのが基本

* Enum
    * Enumとは Enum（列挙型）は、プログラミングにおいて特定の値の集合を表現するためのデータ型です。Enumは、あるデータが特定の値の中から選ばれることを保証するために使用する。

* IOとIO Controllerを分ける意味は？ 
    * IOはデータの入出力や外部リソースの操作に関する責任を持ち、IOコントローラモジュールはデータの制御やビジネスロジックに関する責任を持つ。これにより、コードの再利用性やテスト容易性が向上し、各モジュールの責務が明確になる。

* ＠staticmethod 
    * 静的メソッドは、クラスの中で共有のユーティリティ関数や、インスタンスに依存しない処理を実装する場合に便利。インスタンスの状態にアクセスする必要がない場合や、外部の依存関係を持たない単純な処理を実行する場合に使用。

* try-exceptについて 
    * 予期できるエラーは例外処理をすべき。予期できないエラーは異なる処理をしてexitすべき。例外処理は低い階層ではなく、controllerなどの層で制御を行う。そうすることにより例外発生した際の処理をまとめて書きやすくなる。
【Xcode】ビルド成功時に紙吹雪を散らす

# はじめに
いま参加してる開発チームの方に面白いことを教えてもらったのでやってみました！

https://twitter.com/dqhieu/status/1615908850493947908?s=20

# やりかた
### 「Raycast」をダウンロードします

https://www.raycast.com/

![スクリーンショット 2023-07-08 19.52.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/cb0036b0-eef6-cfe4-4549-70be15b675f8.png)

### シェルスクリプトを作成します
```:ターミナル
touch confetti_shortcut.sh
```

```:ターミナル
open confetti_shortcut.sh
```

```confetti_shortcut.sh
#!/bin/bash
open raycast://confetti
exit;
```

### パーミッションを設定する
```:ターミナル
chmod +x confetti_shortcut.sh
```

### Xcodeに設定する
「Settings...」を選択します
![スクリーンショット 2023-07-08 20.06.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/4354ca9c-d027-5194-4404-66d90a1d2e1b.png)

「Behaviors」を選択します
「Succeeds」を選択します
「Run」をオンにして先ほど作成したシェルスクリプトを設定します
![スクリーンショット 2023-07-08 20.26.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/30c850d2-c777-8ca8-0bfe-98522ae8ac8c.png)

# 試してみる
![tgv9k-gyhmn.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/012fb284-2d80-54c5-6586-a15f2e426ac7.gif)

# おわり
気に入りました笑
技育CAMP vol.5に参加した話

# 初めに
こんにちは、Akira_0809です。
アウトプットをするために初めての記事投稿に挑戦してみました。
今回は技育CAMPのvol.5に即席チームで参加した話です。
# 技育CAMPとは
https://talent.supporterz.jp/events/2ceb6278-e220-4675-b367-ca4f15af8d27/

サポーターズ主催のオンラインハッカソンです。月に1回から２回あります。
今後も参加していきたいですね。
# 作品
作品名は「わりかんじ」です。
割り勘をする際に大きめのお札しかないことがあると思います。しかも、複数人がそんな状況に、
誰が何円かなんて覚えられません。

そんな時にwebアプリとLINEbotの2つのプラットフォームで快適な割り勘を提供します。

## webアプリの紹介
左の画面で支払い金額や参加者を追加します。そうすると、一人当たりの金額が表示されます。
参加者が払う金額を入力することでお釣りや不足が確認できます。
右の画面で過去の割り勘を確認することができます。
　　　![わりかんじ　フロント　入力フォーム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3241738/5c48ef0d-9ee0-39ce-e8d3-96d7cd8c017a.png)　　　　![わりかんじ　フロント　履歴](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3241738/829b986d-2c09-dcea-f909-54a844b229b6.png)

## LINEbotの紹介

ツイッターの動画のように「わりかんじ」と発言すると割り勘が開始されます。
合計金額を入力して個人の金額を入力し「終了」と発言するかグループ内のすべてのユーザーが入力すると、一人一人のお釣りを確認できます。
LINEbotのほうには残念ながら履歴を確認する機能はついていません。

https://twitter.com/Akira08092/status/1677641661051191297?s=20


作品のプレゼンテーションを貼っておきます。

https://www.canva.com/design/DAFncqD8sYA/VxWb1X-BzvyktG3dTFo5kQ/view?utm_content=DAFncqD8sYA&utm_campaign=designshare&utm_medium=link&utm_source=publishsharelink

## 作品のURL
webアプリ

https://warikanji.xpadev.net

LINEbot

https://line.me/R/ti/p/@864wahma?from=page&accountId=864wahma

# 担当した所
今回はバックエンドを担当しました。
初めてのバックエンドでしたが完成させることができたのでよかったです。
また、LINEbotの所は一人で作りました！
![システム構成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3241738/b72f7134-a781-3fa3-099e-9b1c38580807.png)
Pythonのフレームワークであるdjangoを使ってAPIを構築しました。
そして、ユーザー認証にはGitHub Oauthを使用しました。


# 感想
初めてのバックエンド開発でしたが完成させることができてよかったです。
しかし、Dockerについての知識が不足していて迷惑をかけてしまった所があったのでもっと勉強します！
即席チームで完成させること自体がすごいことなのでチームメンバーには感謝してもしきれません。
楽しかったです！
# 最後に
初めての記事投稿でしたが最後まで書ききることができたのでよかったです。
今後もハッカソンや開発のことを記事にしていきたいと思います。
最後まで読んでいただきありがとうございました。
またね！