OmniAICreator/Qiita-1.07M huggingface dataset:
Power Automate を使用する際の注意点～初学者が躓きやすいポイント2選～

**はじめに**
---
Power Automate for Desktop を使いたくて Mac ユーザーから Windows ユーザーに乗り換えたのにも関わらず、下調べが甘かったことや、Power Automate for Desktop の仕様変更のせいで、期待通りに使用できなかった経験から得た教訓を共有します。今後、Power Automate・Power Automate for Desktop の使用を検討している人の参考になれば幸いです。

**Power Automate で実現したかったこと**
---
私が、Power Automate でやりたかったことは以下の２つです。

①　Power Automate で Outlookに接続する
②　Power Automate と Power Automate for Desktop を接続する

とても基本的な内容ではありますが、初学者には躓きやすいポイントがあったので解説も交えながら説明していきます。

**個人アカウントと組織アカウントの違いを知る**
---
単刀直入に言うと、Power AutomateをOutlook等のMicrosoft製品と連携して使用するには組織アカウントが必要です。Microsoftには、個人が使用するための個人アカウントと企業や学校等の組織で使用するための組織アカウントがあります。どちらもアカウント自体は無料で作成できるのですが、いくつかの点で違いがあります。

　|組織アカウント|個人アカウント
---|---|---
独自ドメインの取得|　　　〇|　　　×　
アカウント管理|Azure ADの管理者|　　個人
企業向けサービスの使用|　　　〇|　　　×

私のように個人で使用していても、Power Automateのような企業向けのサービスを使用するユーザーは組織アカウントを用意する必要があります。

下の画像はPower Automateから個人アカウントで使用していたOutlookに接続しようとしたときのエラーログです。組織アカウントを使用するようにというエラーが出ました。

![スクリーンショット 2023-10-19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3533137/882b0af1-c412-cb3b-ab65-1cf40991ddf4.png)


Microsoft Office 製品搭載の PC を使用していて Outlook が使用できる状態にある場合でも、それは個人アカウントに紐づいているので Power Automate と接続することはできません。独学で Power Automate の学習をする方やフリーランスとして Power Automate を扱うことを検討している方は、組織アカウントを用意する必要があることをご注意下さい。

組織アカウントと個人アカウントの違いを解説している参考動画あるので、気になる方はご確認下さい。

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

**Power Automate と Power Automate for Desktop の連携に非対応なOS**
---
Power Automateを使用するうえで、Power Automate と Power Automate for Desktop の連携して１つの自動化フローを作ることがあるかと思います。例えば、Power Automate for Desktopで定義したローカル環境で行われる自動化フローをPower Automateで定義したアクションをトリガーにして自動実行する等です。

Microsoft Learnに同様のことをしているものがあったので、よりイメージを膨らませたい方は以下をご覧ください。

https://learn.microsoft.com/ja-jp/training/modules/integrate-flow-outlook/3-cloud-flow

Power Automate と Power Automate for Desktop の連携するには、

① 直接接続
② データゲートウェイの設定

のいづれかが必要でした。しかし、2023年6~9月頃に仕様の変更があり②のデータゲートウェイを介しての接続ができなくなりました。そのため、①の直接接続をすることにより、両者を連携するしかなくなりました。ここで重要なのは、その直接接続に対応していないOSがあることです。

:::note alert
Windows 10 Home または Windows 11 Home を実行しているコンピュータでは、直接接続を利用できません。
:::

この制限により、上記以外のエディションのPCを使用する必要があります。
私の場合は、Windows 11 Home を使用していたので、Windows 11 Pro へアップグレードすることにより、直接接続ができるようになりました。アップグレードに掛かった費用が約1.3万し、痛い思いをしました（笑）

**まとめ**
---
・Power Automate を使い倒すなら組織アカウントが必要
・Power Automate と Power Automate for Desktop の連携は、Windows 10/11 Home では不可能

最後までご覧頂きありがとうございました！
はじめてのリーダ業務で気を付けたいこと

# はじめに

新任リーダとして気を付けたいことを2つまとめました。
一つは前任のリーダがいるときの引継ぎ時に役立たせたいまとめ。
もう一つは、引継ぎ後のリーダ業務を進める際の注意点となっています。

## 前任の資料やナレッジを確認する
リーダとして最初の作業をする前の下準備になります。
自分がリーダになった時に前任者がいる場合は、以下のような内容を引継ぎしましょう。

- リーダとして行っていたタスクの一覧
- オフィシャル以外でまとめている資料一覧
- メンバとのコミュニケーションの取り方
- メンバの性格や得意な作業
- 定常的に行われている会議体とその内容
- プロジェクトのステークホルダ
- 他チームのコミュニケーションの窓口

公式な資料やドキュメントに記載されていない、もしくはされにくい箇所を聞き出してプロジェクトにフィットすることがポイントになります。また、注意点としては、上記のような内容を引き継いだ時にそれらをどのようにして活用していくの見極めが必要になってきます。前のリーダのやり方や方針をすべて引き継いだところで自分にそのスタイルや考え方が合うとも限りません。あくまで引き出しの一つとして考えて、活用できるものだけを活用するという感じが望ましいと思います。

## リーダになってから気を付けたいこと
ここからは、リーダになってからの行動として気を付けたほうがよいポイントをまとめました。
リーダ経験がある人は、心当たりがありそうなところがないかチェックしましょう。

- 自分でタスクを抱えてしまう
- タスクを振るだけの伝書鳩になっている
- メンバを頼りきれていない
- メンバにタスクを頼みずらい
- 相談できるメンバを作れていない
- 無駄な時間をなるべくなくす

以下、それぞれについて詳細な心配点を記載していきます。
※ただし、メンバーの数や案件への入り方によって、下記に限る話ではないため見極めは必要になります。

### 自分でタスクを抱えてしまう

自分が一番作業をしなければいけないとか、タスクを持たなければいけないと思ってしまい、管理作業と相まってタスク過多になりがちです。

リーダにはリーダの作業があるため、リーダ業務以外のタスクを持つにしても最小限のタスクを請け負う形にしましょう。
また、作業タスクの見積もり時に自分を工数に含めないようにしましょう。
メンバ分の工数のみで見積もりをしないと、巻き取らないといけない形になってしまいます。
その結果、タスクもこなしてかつ管理もおざなりになるという結果を迎えてしまうことも起こり得ます。

### タスクを振るだけの伝書鳩になっている

メンバに指示を伝えなければならない状態は多々あるかと思います。
ただし、そのままメンバに伝達するのでは、本当にただの伝書鳩になってしまいます。
方針や意図を理解したうえで、メンバが納得いくような内容を伝えましょう。きちんと作業内容に実を付けたうえで、メンバに伝えるようにしましょう。

### メンバを頼りきれていない

仕事を誰かに振るというのは、説明やそのための資料作成もあるため意外と骨が折れる作業です。だからといって、メンバに作業を振らないというのは絶対にダメなことです。

また、説明をするより自分がやったほうが早いときもあるという発想に至るときもあります。これはメンバの能力に対して信用ができないと考えてしまい、結果として自分が作業してしまうという背景があります。
ただ、それを続けていくと、自分のタスクも減らないしメンバのスキルが育たないという負のスパイラルが生まれます。はじめは大変かもしれませんが、きちんと作業はメンバに振るという癖をつけましょう。

### メンバにタスクを頼みづらい

リーダとメンバという構成を考えた時にいろいろなケースが考えられると思います。例えば、年上のメンバや自分よりもスキルが高いメンバがいることもあるでしょう。
ただし、リーダはそういったことを気にしてはいけません。なぜならば、リーダは役割であって上下関係とは関係がないからです。

リーダはチームを成功に導くことをすることが目的であって命令するという立場ではありません。
とはいえ、メンバも人間なので押しつけや強要をするのではなくお願いするという気持ちを大切にしましょう。メンバへのリスペクトをすることを忘れないようにしましょう。

### 相談できるメンバを作れていない

「チームメンバ全員と相談できるチーム体制」
これが一番の理想的な状態だと思います。実際にはそうなることはまずありません。では、どうしていけばいいかというと、相談できるメンバを一人でも多く作ることです。
相談内容にもいろいろあると思います。技術的なことやコミュニケーションのことなど課題は山積みだと思います。
メンバには、それぞれ得意な分野や苦手な分野があると思います。
きちんとメンバの特性を理解したうえで、相談役が作れることが大事だと思います。

### 無駄な時間をなるべくなくす

長時間の業務が続くと効率化する方向に意識を向けることができなくなっていきがちです。メンバの報告を待つ時間、なんでもかんでも割込みを受け付けてしまう等とよく考えると、タスクに無駄が発生しているのではないかということはあるはずだと思います。
(実際に効率よくタスクを回し続けても長時間稼働になってしまう時もあるので、そこは切り分けを。)

一旦、自分の作業を見直したうえで、無駄がないかを考えてみるとよいと思います。また、ずっと長時間稼働をしていると自分の作業効率が目減りしていくことは覚えておきましょう。毎日同じように仕事をしているつもりでも、実際はそうではないことがあります。
加えてメンタル不調や仕事への意欲がなくなることによる退職を考えてしまう等も起こり得ます。惰性や慣性、思いつきなどでしてしまっている作業を見つめなおしてみてもらえるといいと思います。

# さいごに

まわりで困っているリーダがいたことと、自分の過去の経験談を基にずらっと書き出してみました。
この記事を見て、少しでもスムーズにリーダ業務に入れると良いなと思います。
【備忘録】Linuxのswpファイルの消し方

Linuxのswapファイルの消し方がわからなくて困ったので備忘録として。

1,.swpファイルの一覧を表示する
```ls -a | grep -E '\.swp$'```
普通のlsでは表示されないのでls -aで表示、さらにgrep -E '\.swp$で末尾が.swpになるものを表示します。

2,普通にrmで削除
```rm 〇〇.swp```

これだけで良いらしいです。
シンプルですが自分が躓いたのでメモしておきます。
Python のlaunchファイルをスクリプトとして直接実行する [ROS 2]

# 概要　

launchファイルだけ作成したいときに、わざわざROS 2パッケージを作るのが面倒くさいので、直接Pythonスクリプトとして実行したかった


# 作成したlaunchファイル


ROS 2のtalkerとlistenerデモノードを同時に起動する例


```sample.launch.py
#!/usr/bin/env python3
import launch
from launch_ros.actions import Node
from launch import LaunchService

def generate_launch_description():
    return launch.LaunchDescription([
        Node(
            package='demo_nodes_cpp', 
            executable='talker',
            name='talker',
            output='screen'
        ),
        Node(
            package='demo_nodes_cpp',
            executable='listener',
            name='listener',
            output='screen'
        )
    ])

if __name__ == '__main__':
    ls = LaunchService()
    ls.include_launch_description(generate_launch_description())
    ls.run()
```

適当な場所にsample.launch.pyという名前でlaunchファイルを作って保存する。

pythonで実行する

```bash
python3 sample.launch.py
```

または実行権限を付与して直接実行

```bash
sudo chmod +x sample.launch.py 
./sample.launch.py 
```

通常のlaunchファイルの下に以下を追加するだけ
ros2 launchでは　'if __name__ == '__main__':'
以下は実行されないので,そのままros2 pkgのlaunchに置いて使用できる。

```python
if __name__ == '__main__':
    ls = LaunchService()
    ls.include_launch_description(generate_launch_description())
    ls.run()
```




# 追記　

記事を書いたあとにros2 launchコマンドでパッケージを作らなくても実行できることを知った。
パッケージを作らずにlaunchだけ実行したい場合は以下のコマンドでよさそう。

```bash
ros2 launch sample.launch.py 
```


https://zenn.dev/shotaak/articles/69ab5bb8ad5dc3


# 参考


https://zenn.dev/uedake/articles/ros2_launch1_basic

https://zenn.dev/uedake/articles/ros2_launch2_substitution
Udemy flaskコースの備忘録


webアプリフレームワーク

Java -> spring framework
Ruby -> ruby on rails
php -> laravel
python -> flask（学習コスト低）, django（学習コスト高）

VSCodeでディレクトリ開くときはmyproject配下で
VScodeのターミナルをbashに変更
ターミナルで下記実行
$ export FLASK_APP=app
$ export FLASK_ENV=development
*flask runは下記に変更*
$ flask run --debugger --reload


**SQLite**

ターミナルから
sqlite3 database名.db

SQLiteでテーブル作成間違えた場合
$drop table テーブル名
を実行する、しかしテーブルのデータも消えてしまうので注意

$insert into テーブル名;
でテーブルにデータを入力
$select 項目名 from テーブル名;
でデータを取得する
$update テーブル名 set 項目名1 = 値1, 項目名2 = 値2 where 条件;
データの更新
$delete from テーブル名 where 条件;
データの削除


DBのトランザクション
BEGIN -> DELETE1 -> ROLLBACK ->　DELETE2 -> COMMIT 
BEGIN：トランザクションの開始
DELETE1 memo; :間違えて削除してしまった
ROLLBACK; :削除の処理前に戻る
DELETE2; :正しくデータを削除した
COMMIT； :処理を確定させる
Goで同じ瞬間か比較してみた

## 今回のゴール

UTC時刻と東京の時刻を同じ瞬間に定義されたものなのか、比較することをコードでアウトプットする。

## 実践

最終的なコードは以下です。

```main.go
    second := int((9 * time.Hour).Seconds())
	location := time.FixedZone("Asia/Tokyo", second)

	fmt.Println(second)
	fmt.Println(location)

	timeTokyo := time.Date(2023, 10, 19, 9, 0, 0, 0, location)
	timeUTC := time.Date(2023, 10, 19, 0, 0, 0, 0, time.UTC)

	fmt.Println(timeTokyo)
	fmt.Println(timeUTC)

	compareCharacterEqual := timeTokyo == timeUTC
	compareEqual := timeTokyo.Equal(timeUTC)

	fmt.Println(compareCharacterEqual)
	fmt.Println(compareEqual)
```

```
32400
Asia/Tokyo
2023-10-19 09:00:00 +0900 Asia/Tokyo
2023-10-19 00:00:00 +0000 UTC
false
true
```

1. `second := int((9 * time.Hour).Seconds())`
    
    ここでは、9時間を秒数に変換しています。`time.Hour`は時間を表す型で、1時間をナノ秒で表現したものです。これに9を掛けることで9時間をナノ秒で表現し、その後`.Seconds()`メソッドを使って秒数に変換しています。
    
2. `location := time.FixedZone("Asia/Tokyo", second)`
    
    ここでは、"Asia/Tokyo"というタイムゾーンを持つlocationオブジェクトを作成しています。このタイムゾーンはUTCからの時差が9時間であることを示しています。
    
3. `fmt.Println(second)`
    
    これは、先ほど計算した秒数（9時間）を出力します。
    
4. `fmt.Println(location)`
    
    これは、作成したlocationオブジェクト（"Asia/Tokyo"タイムゾーン）を出力します。
    
5. `timeTokyo := time.Date(2023, 10, 19, 9, 0, 0, 0, location)`
    
    ここでは、"Asia/Tokyo"タイムゾーンで2023年10月19日9時0分0秒のtimeオブジェクトを作成しています。
    
6. `timeUTC := time.Date(2023, 10, 19, 0, 0, 0, 0, time.UTC)`
    
    ここでは、UTCタイムゾーンで2023年10月19日0時0分0秒のtimeオブジェクトを作成しています。
    
7. `fmt.Println(timeTokyo)`
    
    これは、先ほど作成したtimeTokyoオブジェクト（"Asia/Tokyo"タイムゾーンの時間）を出力します。
    
8. `fmt.Println(timeUTC)`
    
    これは、先ほど作成したtimeUTCオブジェクト（UTCタイムゾーンの時間）を出力します。
    
9. `compareCharacterEqual := timeTokyo == timeUTC`
    
    これは、timeTokyoとtimeUTCが同じ時間を表しているかどうかを比較しています。ただし、この比較はタイムゾーンも考慮に入れます。つまり、同じ瞬間を指していてもタイムゾーンが異なる場合、この比較はfalseを返します。
    
10. `compareEqual := timeTokyo.Equal(timeUTC)`
    
    これは、timeTokyoとtimeUTCが同じ瞬間を指しているかどうかを比較しています。この比較はタイムゾーンを無視します。つまり、同じ瞬間を指していてもタイムゾーンが異なる場合でも、この比較はtrueを返します。
    
11. `fmt.Println(compareCharacterEqual)`
    
    これは、先ほどの`==`による比較結果（タイムゾーンも考慮した結果）を出力します。
    
12. `fmt.Println(compareEqual)`
    
    これは、先ほどの`.Equal()`メソッドによる比較結果（タイムゾーン無視した結果）を出力します。
    

## 分かったこと

`.Equal`メソッドはタイムゾーンを考慮しない結果を出力するため、比較する二つの時間が同じ時間ではなく同じ瞬間であるかを示す。

## そもそもタイムゾーンとは

ある特定の地域が協定世界時(UTC)からどれだけずれているかを示す。例えば、「Asia/Tokyo」タイムゾーンはUTC+9と表し、日本の標準時間が協定世界時より9時間進んでいることを示します。

## おわり

上記のアウトプットで指摘等ありましたら、ご気軽にコメントいただければ幸いです。

## 参考記事
https://qiita.com/taizo/items/acbee530bd33c803dab4

https://docs.informatica.com/ja_jp/master-data-management/multidomain-mdm/10-2-hotfix-2/_business-entity-services-guide_multidomain-mdm_10-2-hotfix-2_ditamap/GUID-809086BD-86BB-436B-835F-E47A3E9A4FC3/GUID-10CBB7AB-55A7-4E2F-8C6A-159FDA915366.html

https://pkg.go.dev/time#Time.Equal
ASP.NETにおけるレシートOCR開発-折れ曲がりによって二分されたレシートの補正-

# 検証編
## 前回まで

前回の記事ではレシートの左右で回転角度が異なるときに別で回転するソリューションを提案しました。
前回の記事はこちらからチェックできます！

https://qiita.com/y-okada1412/items/c752f8c41a4444241576

## 概要
前回提案したソリューションが正しいかどうかを実際のデータをもとに計算で確認していきたいと思います。結果がうまくいかなかった際にはその改善も随時行います。そして検証に使用するデータは次に示すレシート画像から取得したJSONデータから抜粋します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3566779/1abe52d0-e875-725f-3074-b8efa10987d6.png)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3566779/0399cb42-56bb-f8af-f21a-f037d8c547f2.png)



## データを利用して計算してみる 
今回使用するデータは先ほど示した Text 要素を使用していきます。まず一番大きな要素は
「セブン-イレブン」なのでこの左の縦辺の傾き`Langle`と中心座標$ (𝑙𝐶_𝑥,𝑙𝐶_𝑦) $、右の縦辺の傾き`Rangle`と中心座標$ (𝑟𝐶_𝑥, 𝑟𝐶_𝑦) $を求めます。下記の図を参考にしてください。



<html>
<div align="center">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3566779/f2c9d127-0535-6ba2-db02-dc62a529a18a.png">
</div>
</html>
そしてこの値はこちらです。
$$ lC_x = \frac{187+179}{2}=183 $$

$$ lC_y = \frac{347+421}{2}=384 $$

$$ Langle = \frac{347-421}{187-179}=-9.25 $$

$$ rC_x = \frac{228+221}{2}=224.5 $$

$$ rC_y = \frac{351+424}{2}=387.5 $$

$$ Rangle = \frac{351-424}{228-221}=-10.429 $$

次に、傾きを利用して回転角を求めます。前回示していた式は
$$ \theta = 90-\tan^{-1}(angle) $$

でしたが、今回 `angle` がマイナスになっており `90` 度に合わせようとすると `170` 度ほど回転
させてしまいました。つまり行のデータがさかさまになってしまったので、これを防止しま
す。また `C#`の `Math` ライブラリで `Atan` を使用すると、返り値は弧度法であることが分かりました。これらを考慮して式を次のように変更しました。
$$
\theta = (\frac{\pi}{2}-|\tan^{-1}(angle)|)*\frac{angle}{|angle|}
$$

これにより$ \theta_{left} $と$ \theta_{right}$の値は

$$ \theta_{left} = -0.1077 $$

$$ \theta_{right} = -0.0956 $$

と計算できます。この$ \theta $とそれぞれの中心座標で、`セブン-イレブン`の `BoundingBox` を回転させます。

$$ \hat{x} = C_x + (x-C_x)*\cos\theta - (y-C_y) * \sin\theta $$

$$ \hat{y} = C_y + (x-C_x)*\sin\theta + (y-C_y) * \cos\theta $$

$ \theta_{left} $と$ \theta_{right} $、$ (𝑙𝐶_𝑥,𝑙𝐶_𝑦) $と$ (𝑙𝐶_𝑥,𝑙𝐶_𝑦) $を利用して四頂点を回転結果がこちらになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3566779/eccac69d-e5d6-67ce-20c6-ecb73a8306d3.png)

この二通りで計算した要素中心座標から`y`座標の差`div`を計算します。$ \theta_{left} $で得られた要素の中心`y`座標を`Left`、$ \theta_{right} $で得られた要素の中心`y`座標を`Right`として計算をすると

$$ div = Left - Right = -4.23 $$
となりました。`Left`のほうが大きいと`+`、`Right`のほうが大きいと`-`になります。
最後になりますが、`セブン-イレブン`の要素から得られた回転角度と`div`を利用して`お`や`釣`、`￥3000`の要素の移動を行います。今回は$ \theta_{left} $ と$ \theta_{right}$を有効活用して行いますが、将来的には要素それぞれで補正を行うと思います。
左側には`お`と`釣`、右側に`￥3000`があるので`￥3000`の要素の`y`座標には`div`を足します。
その結果の座標が次になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3566779/0eb14814-ad08-0773-1116-6aa145eca511.png)

この結果と元の`BoundingBox`の座標を比較すると、縦の座標右側の要素と近づいたと思いますが、要素がより傾いてしまっているのが確認できます。
今回使用した画像は、比較的きれいに撮影できているにもかかわらず、この傾きの変化が起こってしまっているので、要素は個々に回転角度を設定する方がよさそうですね。


## さいごに
次回以降ではこのプログラムを作成し、行の判別の正当性を検討します。
また、これらを利用したOCRは、LINEからどなたでも無料でご利用いただけますので、
ぜひ試してください！

https://receiptroller.com/ja


また、OCRのでも体験がこちらのページからできます！

https://ocr.receiptroller.com/read-receipt


次の記事。コードを作成しました。

https://qiita.com/y-okada1412/items/4a4a78ffc4cd6a0d7485
iOS simulatorでURL Schemeを起動する(ただのURLでもOK)

シミュレーターでURLスキーマを起動する方法です。
10年以上アプリ開発してますが、初めて知りました。(たぶん)

```
# URL Schemeの場合
/usr/bin/xcrun simctl openurl booted "yourscheme://hoge"

# URLの場合
/usr/bin/xcrun simctl openurl booted "https://google.co.jp"
```
Salesforceのカスタマーラベルのリスト

### 要件
セールスフォースのカスタマーラベルをリストするため、なんの方法はよいか
### 調査
いろな方法がありますが、SFDXでRetrieveする
https://salesforce.stackexchange.com/questions/310123/retrieve-custom-translations-for-a-custom-label-via-the-metadata-api


### 方法
①ManifestのPackage.xmlを用意する

```
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <fullName>MyPkg</fullName>
    <types>
      <members>*</members>
      <name>CustomLabels</name>
    </types>
    <version>59.0</version>
</Package>
```

②Terminalで下記コマンドを実行する

```
sf project retrieve start --manifest manifest/package_bak1.xml -o sndevf01
Retrieving v59.0 metadata from hucq@n-cast.co.jp.sndev using the v59.0 SOAP API
Preparing retrieve request... Succeeded

Retrieved Source
==============================================================================================
| State   Name         Type         Path
| ─────── ──────────── ──────────── ────────────────────────────────────────────────────────── 
| Created CustomLabels CustomLabels force-app\main\default\labels\CustomLabels.labels-meta.xml
```
※ -o orgnizationの別名、旧-u

③上記②のXMLファイルからCsvに変換する
https://data.page/xml/csv

４、Excelに張り付ける

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/801991/0df8373c-405a-2938-f4e9-9d2dce46c051.png)
インターネットにつながっていないOIDC OPをIAMにIDプロバイダーとして登録する

基本的に以下のドキュメントの内容なのですが、正にOPがインターネット上で稼働してなくてもできるよ。必要なのはOpenID Provider Configuration Informationとjwks_uriをインターネット上で公開することだけだよ。ということです。

まったくインターネットを使わないということであれば無理そうです。

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_providers_create_oidc.html

## 手順

1. パブリックドメインを取得する。
2. プライベートホストゾーンをパブリックドメイン(パブリックホストゾーン)と同名で作成する
3. OIDCサーバーをプライベートなネットワークに上記のドメインを使用して構築する
    3.1. ホストを auth.example.com, issuer が auth.example.com/realms/main とします。
    3.2. 同名のパブリックドメインを取得しているので、証明書はACMで取得するのが簡単です。
4. インターネット上でOpenID Provider Configuration Information、および jwks_uriで示されるドキュメントをOIDCサーバーと同じURLで公開します。(S3 + CloudFront + ACM が簡単ですが、どんな方法でも構いません)
   以下はKeycloakで構築した時のURLの例です。(レルムはmainとしています)  
   これらをcurlなどで取得して公開します。鍵のローテーション時に自動でアップできるとよいですが、ローテーションの時間を決めることができれば、それに合わせて定期的にアップするのでもよいと思います。閉域VPC内からだとS3へVPCエンドポイントでアクセスしたり、SNSで他アカウントと連携したりして公開しましょう。
   - https://auth.example.com/realms/main/.well-known/openid-configuration
   - https://auth.example.com/realms/main/protocol/openid-connect/certs

5. IAM にOIDCプロバイダーを登録する
   - IDプロバイダーは https://auth.example.com/realms/main で登録します。
   - 内部的にはAWSが `.well-known/openid-configuration` と `jwks_uri` にアクセスします
     コンソールでの追加を想定しています。それ以外の場合はSSL証明書のthumbprintの登録が必要です。
6. IAM に登録したOIDCプロバイダを信頼するロールを登録する
   以下のような信頼関係ポリシーを持ったロールを作成します
   ```json
   {
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Principal": {
          "Federated": "arn:aws:iam::<ACCOUNT-ID>:oidc-provider/auth.example.com/realms/main"
        },
        "Action": "sts:AssumeRoleWithWebIdentity",
         "Condition": {
           "StringEquals": {
             "auth.example.com/realms/main:aud": "example"
           }
         }
      }
    ]
   }
   ```

上記設定ではclient_idはexampleとしています。
これで認証時に受け取ったid_tokenを使用してAssumeRoleWithWebIdentityすればAssumeRoleした一時クレデンシャルを取得できます。閉域VPC内からということであれば、stsサービスのVPCエンドポイントが必要になります。

```bash
aws sts assume-role-with-web-identity \
  --role-arn "$role_arn" \
  --role-session-name "$session" \
  --web-identity-token "$id_token"
```

## まとめ

要するに以下の条件を満たしていればよいということですね。
- issuerはhttpsでなければならない
- OpenID Provider Configuration Informationにインターネット経由でアクセスできなければならない
- jwks_uriはhttpsでなければならず、やはりインターネット経由でアクセスできなければならない

## 注意事項

その他の注意事項としては以下のようなことに気を付けましょう。

トークンの署名はRS256のみです。Keycloakの既定はRS256ですが、気を付けないといけませんね。
  > - https://docs.aws.amazon.com/ja_jp/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html
  > - https://docs.aws.amazon.com/cli/latest/reference/sts/assume-role-with-web-identity.html

> The OAuth 2.0 access token or OpenID Connect ID token that is provided by the identity provider. Your application must get this token by authenticating the user who is using your application with a web identity provider before the application makes an AssumeRoleWithWebIdentity call. Only tokens with RSA algorithms (RS256) are supported.

`.well-known/openid-configuration`, `jwks_uri` ともに content-typeは `application/json` です。

Keycloakから OIDC Provider Infomationを取得するときはバックチャネルでのアクセスはやめておくのが無難です。httpで返ってきたり、ホスト名がlocalhostになっていたりします。
Gitのコマンド

## Git
**Gitは分散型バージョン管理システムで、ソフトウェア開発プロジェクトでのコード管理に不可欠なツールです。**
Gitを理解するために、重要な３つの要素があるので把握してください。

・**ワークツリー**　　　：ワークスペースのこと。つまりプロジェクトを作成しているファイル
・**ステージ**　　　　　：ローカルリポジトリへコミットする準備を行う場所
・**ローカルリポジトリ**：自身のPCに存在するリポジトリ。変更履歴やコミット履歴が存在。

今回は、Gitの基本的なコマンドを9個紹介します！

# 1. git init
**.gitディレクトリ**、つまりは<font color="Red">**ローカルリポジトリ**</font>を作成するためのコマンド。
**cdコマンド**にてプロジェクトのディレクトリへ移動し、このコマンドを実行してください。

```bash
cd プロジェクトのディレクトリ
git init
```
**lsコマンド**を実行して、.gitディレクトリが作成されているかどうかを確認してください。
```bash
// すべてのファイルを確認
ls -a

// 結果
.  ..  .git
```

# 2. git clone
GitHub等に存在する**リモートリポジトリ**を複製してローカルに作成します。
```bash
git clone リモートリポジトリのURL
```
**lsコマンド**を実行して、リポジトリが複製されているか確認できます。



# 3. git add
リポジトリに変更を追加したいファイルを**ステージ**に追加します。
```bash
git add ファイル名

// すべてのファイルをステージへ追加
git add .
```

# 4. git commit
ステージに存在する変更ファイルを**gitディレクトリ**、つまりは<font color="Red">**ローカルリポジトリ**</font>へ追加する。

追加される内容は以下の四つ。
・**現在のワークツリーの状況のスナップショット** 
　<font color="Red">**(ステージへ追加していないファイルは保存されない)**</font>
・**作成者**
・**日付**
・**コミットメッセージ** (変更内容の要点)

```bash
git commit

// メッセージを追加できる
git commit -m "追加したいメッセージ"
// commitする前に、変更する内容を確認できる
git commit -v
```

# 5. git status
現在の**ステージ**の状況、<font color="Red">**どのファイルが変更されているのか**</font>確認できる。
**ローカルリポジトリー**と**ステージ**、**ステージ**と**ワークツリー**との差異を確認することができる。

<font color="Red">commitコマンドを実行する前に、このコマンドを実行して確認する癖は付けたほうがいい。</font>

```bash
git status
```

# 6. git diff
現在の**ファイルの変更差分**の状況、<font color="Red">**どのような内容の変更がされているのか**</font>確認できる。
**ステージ**と**ワークツリー**、**ローカルリポジトリー**と**ステージ**との<font color="Red">**ファイルの変更差分**</font>を確認することができる。

<font color="Red">commitコマンドを実行する前に、このコマンドを実行して確認する癖は付けたほうがいい。</font>

```bash
// git addする前の変更分
git diff
git diff <ファイル名>

// git addした後の変更分
git diff --staged
```
# 7. git log
**ファイルの変更履歴**を確認できる。


```bash
git log
// 一行で表示する
git log --oneline
// ファイルの変更差分を表示する
git log -p <ファイル名>
// 表示するコミット数を制限する
git log -n <コミット数>
```

# 8. git rm
**ファイルの削除を記録するためには、git addではないコマンドが必要**
**rmコマンド**で、**ワークツリー**、**リポジトリ**からファイルが削除される。
**ステージ**では、ファイルが削除された履歴が残る。

```bash
// ファイルごと削除 ワークツリーからも削除される
git rm <ファイル名>
git rm -r <ディレクトリ名>

//ファイルを残したい時 リポジトリから削除される　→　git視点では、新規ファイルとして理解される
git rm --cached <ファイル名>
```

# 9. git mv
**<font color="Red">ファイルの移動コマンド</font>**、または、**<font color="Red">ファイル名の変更コマンド</font>**
**ステージ**にも、ファイル名変更の履歴が残る。
```bash
git mv <旧ファイル名> <新ファイル名>

// 以下のコマンドと同じ
mv <旧ファイル名> <新ファイル名>
git rm <旧ファイル>
git add <新ファイル>
```

# まとめ
**GitHubへのpushのやり方等は次回紹介します！**

今回紹介したものは、gitでよく使用されるコマンドの一部です。
他にも様々なコマンドがあるので、調べてみてくださいね。
shell array loop

```sh
#!/bin/sh

indices="MXWOEW Index,UKX Index,INDU Index,SX5E Index,IFB1 Index,FT1 Index,HI1 Index,TP1 Index,CO1 Comdty,CL1 Comdty,GC1 Comdty,USDCNY Curncy"

IFS=, # Set Internal Field Separator to comma
for index in $indices; do
   echo $index
done
```

next line
```sh
#!/bin/sh

indices="MXWOEW Index,
UKX Index,
INDU Index,
SX5E Index,
IFB1 Index,
FT1 Index,
HI1 Index,
TP1 Index,
CO1 Comdty,
CL1 Comdty,
GC1 Comdty,
USDCNY Curncy"

IFS=,$'\n' # Set Internal Field Separator to comma
for index in $indices; do
   echo $index
done
```
【備忘録】GitHubにプライベートレポジトリを作成し、コマンドラインからコードをアップロードする

# 注意
この情報は2023/10/24時点でのものになります。また、Windows上でAnacondaを利用して仮想環境の作成からアップロードまでを行っています。

# 前書き
現状管理しているDjango+PythonanywhereのWebサイトに加えて、新しく別のWebサイトを作成することにしました。それで、以前は特に理由もなかったのでパブリックなレポジトリを利用していましたが、今回は諸々の理由と勉強を兼ねてプライベートなレポジトリを利用することにしました。

例のごとくGitHubを利用してコードを管理し、そこからPythonanywhereにデプロイすることにしましたが、そもそものGitHubにコードをアップする段階でしこたまつまづきました。

# 地獄
皆さんご存じでしょうが、GitHubはコードホスティングプラットフォームです。多くの利用者に対応するため、様々なシステムから使えるようになっています。また、その歴史も古く設立は2008年だとかなんとか。今なお利便性やセキュリティ向上のために、繰り返しシステムがアップデートされています。多分名実ともに世界一のサービスでしょうね。

それで、結果として何が生まれるかというと、そもそも自分とシステムの構成が異なる方だったり、既に変わってしまった仕様で溢れる**情報地獄**です。有志の方々が無償で公開してくれる情報にはいつも助けてもらっていますが、こればっかりは参ってしまいます。多分Googleとこの手の調べ事が致命的に相性が良くないのでしょうね。

私自身、GitHubの仕組みをしっかりと理解できているとは言えませんし、本当に苦戦しました。とりあえずなんとかかんとかpushまではこぎつけたので、次は苦しまないように備忘録代わりに過程を残しておきます。

# 手順
以下が、一連の手順となります。

## 1.) 仮想環境の作成
これがなければ始まりません。Anacondaを起動して、以下のコマンドラインでdjangoとgitをダウンロードします。

```
conda create -n 仮想環境名 python=3.8 django git
```

## 2.) フォルダの作成+初期化
プロジェクト用のフォルダを作成し、中に入った上で初期化を行います。README.mdも併せて作成しています。

```
mkdir website
cd website
echo "first commit" >> README.md
git init
```

## 3.) プライベートレポジトリの作成
次はGitHubにアクセスして、プライベートレポジトリを作成します。レポジトリの欄から、Newをクリックし、PublicからPrivateにレポジトリを切り替えて作成するだけです。

## 4.) addとcommit、ブランチの切り替え

途中まではGitHubのサイト上に記載してある手順と同じです。
```
git add README.md
git commit -m "first commit."
git branch -M main
```

ただ、ここからが異なっていて、以下の手順そのままに入力すると、ユーザ名とパスワードの入力を求められますが、正しく入力しても「2021年8月13日にパスワードによる認証は撤廃されたよ」と出てきて認証エラーを吐きます。(これは結構な罠なのでは…)

```
git remote add origin https://github.com/ユーザ名/レポジトリ名.git
git push -u origin main
```

## 5.) パーソナルアクセストークンの作成と再認証

ここでGitHubのサイトに戻ります。そのまま右上のユーザーアイコンをクリックし、Settings->Developer Settingsへ移行。画面左側にあるPersonal Access TokenからClassicなキーを作成します。権限は適当にrepoでチェックをいれておけば良いです。作成したらクリップボードのマークをクリックして、コピーしておきましょう。

※2023/10/24追記
このトークンは後ほど利用します。テキストファイルなどで保存しておくようにしましょう。

## 6.) あらためてremoteしてpush
先程remoteしたせいで、以下が「もう設定されているよ」と言われて通りません。多分はじめからこれやってたら通ると思います。

```
git remote add origin https://コピーしたアクセストークン@github.com/ユーザ名/レポジトリ名.git
```

ということで以下のオプションをつけて再設定

```
git remote set-url origin https://コピーしたアクセストークン@github.com/ユーザ名/レポジトリ名.git
```

最後にpush。

```
git push --set-upstream origin main
```

## 7.) PythonAnywhere上でのデプロイ(2023/10/24追記)
デプロイできました。なんだか若干動作が怪しいですが、とりあえずPythonAnywhere上で動いているのでヨシしてます。

で、結論からいうと、途中まではQiitaやDjangoGirls上で説明してもらっている内容と同じです。APIトークンを作成し、Bash上でpythonanywhereをインストールします。

```
pip3 install --user pythonanywhere
```

異なるのはその後で、自動的にダウンロードしてデプロイしてもらう段階で、以下のコードを走らせると、つづがなくデプロイが終わります。

```
pa_autoconfigure_django.py --python=3.9 https://コピーしたアクセストークン@github.com/GitHubのユーザ名/リポジトリ名.git
```

ステータスメッセージを見ても今ひとつ何が起きているかわからないので、自分のようにここでつまずく人も多いのではないでしょうか。

# まとめ
以上になります。明らかに効率が悪いですが、とりあえずpushできて、デプロイまでできたのでOKです。

# 参考サイト様
[GitHubアクセストークン認証](https://zenn.dev/technicarium/articles/5bf0647056fb87)
[DjangoアプリをPythonAnywhereにデプロイする方法](https://qiita.com/Pumpkin1e18/items/9b6fc79ad32769ec2b9d)
[DjangoGirls: デプロイ!](https://tutorial.djangogirls.org/ja/deploy/)
【Java・学習ログ15】コレクションについて～リストの基本～


教本に沿ってやってみたシリーズ、『第16章』その１。
≪使用教材≫スッキリわかるJava入門　第3版　スッキリわかるシリーズ

## 1. コレクションとは
順序のつけてデータを格納する配列構造をリストと総称する。
コレクション（コレクションフレームワーク）とは、APIで用意されたデータをまとめて格納するための入れ物クラスのことである。

## 2. ArrayList
コレクションクラスの中で最も理解しやすい一つ。
基本データ型以外のインスタンスを格納できる。配列のように宣言時に箱の数を指定する必要がなく、足りなければ随時箱が追加される。

データ型を使う場合にはjava.lang.Integerのように**ラッパークラス**を使い、**ジェネリクス文法**でクラス型を記述する。
#### 基本データ型とラッパークラス
| | | | |
|-|-|-|-|
|byte|java.lang.Byte|short|java.lang.Short|
|int|java.lang.Integer|long|java.lang.Long|
|float|java.lang.Float|double|java.lang.Double|
|char|java.lang.Character|boolean|java.lang.Boolean|

《使用方法》
1. import文を記述
1. <>を使って、格納するインスタンスの型（またはラッパークラス）を指定
```java
import java.util.ArrayList;

public class Main {
	public static void main(String[] args) {
		ArrayList<Integer> points = new ArrayList<Integer>(); // 宣言
		points.add(10);
		points.add(80);
		points.add(75);
		for (int i : points) { // 拡張for文で要素を取り出し
			System.out.println(i);
		}
	}
}
```
#### ArrayListに用意された主なメソッド
|操作|戻り値|メソッド|機能|
|-|-|-|-|
|追加|boolean|add(要素)|リストの最後に要素を追加|
| |void|add(int,要素)|リストのint番目に要素を追加|
| | |set(int,要素)|上書き|
|取得||get(int)|int番目の要素を取り出す|
|調査|int|size()|格納されている要素数を返す|
| |boolean|isEmpty()|要素数がゼロかを判定|
| |boolean|contains(要素)|指定した要素が含まれるかを判定|
| |int|indexOf(要素)|指定した要素が何番目にあるかを検索|
|削除|void|clear()|要素をすべて削除する|
| ||remove(int)|int番目の要素を削除する|

#### Iteratorメソッド
箱を指す矢印のようなもの。**java.util.Iterator<～>型**のインスタンスを得ることで使用できるが、iteratorメソッドを呼び出すことで自動的にインスタンス化されるため、newをする必要がない。
このとき、取得されるイテレータは先頭の箱より前を示している。
```
Iterator<リスト要素の型> it = リスト要素の型.iterator();
```
また、イテレータに対して行える操作は下記の２つのみである。
-  hasNext()　次の要素を指せるかを判定
-  next()　次の要素を指し、その内容を返す。

# 3. LinkedList
使用方法や用途はArrayListとほぼ変わらないが、内部の作りに違いがある。
ArrayList = 配列を応用　LinkedList = **連結リスト**を応用

インデックス（番号）の降られていない数珠つなぎの箱を用いたリスト。
リスト途中の要素に対して行った追加や削除の処理がArrayよりも早く行える。
ただし、番号を振っていない分、〇番目の要素を取り出すといったいような処理が苦手。

# 4. ざっくりList型
どちらもjava.util.Listインタフェースを実装しているため、List名を型とすれば同列に扱うことが可能である。どちらのリストも扱えるよう、曖昧に示したほうが後々得である。
```java
// List(インタフェース名を)型にしてインスタンスを生成
List<String> list = new ArrayList<String>(); 
// 引数にList(インタフェース名を)型を利用
public static void println(List<String> list) {
    for (String s: list) {
        System.out.println(s);
    }
}
```
<hr>

(簡易メモ)

1. Listクラスは配列と異なり使いたい要素数に順応し随時箱を用意してくれる
1. 基本データ型のインスタンスを格納する場合はラッパークラスを使う
絞り込み機能をfilter関数で作るチュートリアル

# 初めに

ホームページのお知らせにある年次のボタンをクリックすると、
対象のお知らせが表示される絞り込み機能を実装しました。

# コード

### HTML

各ボタンにデータ属性でdata-yearで値を持たせています。
お知らせについては、今回はJSのデータ構造の理解を深めるためにHTMLに埋め込みませんでした。


```html:index.html

<button data-year="all">All</button>
<button data-year="2021">2021</button>
<button data-year="2022">2022</button>
<button data-year="2023">2023</button>

<ul class="news">
         
</ul>

```


### JavaScript

クリックしたボタンのデータ属性がallなら全件表示して、all以外ならfilter関数でnewsList配列のyearプロパティと一致したオブジェクトを抽出してHTMLにレンダリングしています。

```javascript:script.js

const newsList = [
    {title: "ニュース1", year: 2021},
    {title: "ニュース2", year: 2022},
    {title: "ニュース3", year: 2023},
    {title: "ニュース4", year: 2021},
    {title: "ニュース5", year: 2022},
]

const info = document.querySelector('.news');

// newsListをHTMLに表示したい
newsList.map((news) => {
    const li   = document.createElement('li');
    li.textContent = news.title;
    info.appendChild(li);
})

document.querySelectorAll('.btn').forEach((btn) => {
    btn.addEventListener('click', () => {
        filterNews(btn.dataset.year);
    })
})

function filterNews(yearStr) {
    // クリックしたボタンのデータ属性が all なら お知らせを全件表示
    if (yearStr === "all") {
        renderList(newsList)
    } else {
        // all 以外なら クリックしたボタンのデータ属性と同じnewsList配列のyearプロパティを持つオブジェクトを抽出してrenderList関数の引数に渡す
        renderList(newsList.filter((news) => news.year == yearStr));
    }
}

function renderList(filters) {
    info.innerHTML = filters.map(news => `<li>${news.title}</li>`).join("")
}

```

# 終わりに

同じことをやるにしても、色々な方法があるので状況に応じて組み合わせていきたいと思います。
PHPでSQLite3をつかうには?をLaravelアプリケーションを作ってみて確認する

## PHPでSQLite3をつかうには？

PHPでSQLite3を使うために、どのようなライブラリーを用意すればいいのか知りたいです。
たとえばRubyの世界では [sqlite3-ruby](https://github.com/sparklemotion/sqlite3-ruby) というgemがよく使われています。
PHPの世界にもこのようなライブラリーがあるのでしょうか？

[https://laravel.com/docs/10.x/database#introduction](https://laravel.com/docs/10.x/database#introduction) によると、LaravelはSQLite3をサポートしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15964/c9e68e42-c36e-e1db-9757-0af8742d2f0c.png)

LaravelでSQLite3を使うアプリケーションを作成すれば、PHPでSQLite3を使うときに必要な環境設定がわかるはずです。


実行環境はWSL2上のUbuntuです。
Composerはインストール出来ているものとします。

## Laravelアプリケーションの作成


空のLaravelアプリケーションを作ります。
[https://laravel.com/docs/10.x#your-first-laravel-project](https://laravel.com/docs/10.x#your-first-laravel-project) の指示に従って、次のコマンドを実行します。

```sh
composer create-project laravel/laravel example-app
```

起動するか確認します。

```sh
cd example-app
php artisan serve
```

http://localhost:8000/ を開く次の画面がひらき、Laravelアプリケーションが作成出来たことがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15964/072f1354-273c-82a1-0932-cc6fe3a2a754.png)

## SQLite3を使う

.evnファイルを編集します。

```sh
DB_CONNECTION=sqlite

```

Laravelでは.envファイルで使用するDBを変更するようです。
ここで指定したキーで `config/database.php` から設定を探してDBに接続するようです。

```php
    'connections' => [

        'sqlite' => [
            'driver' => 'sqlite',
            'url' => env('DATABASE_URL'),
            'database' => env('DB_DATABASE', database_path('database.sqlite')),
            'prefix' => '',
            'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
        ],
```

使用するSQLite3のデータファイルは `database.sqlite` と言う名前のようです。
空ファイルを作成しましょう。

```sh
touch database/database.sqlite
```

## SQLite3が動くか確認するためにマイグレーションする

DBの設定ができたのでマイグレーションしてみます。


```sh
php artisan migrate
```

次のようなエラーがでました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15964/62afbd70-fe20-4ab2-659a-887104568546.png)

SQLite3のドライバーが無いそうです。

## SQLite3のドライバーPDO_SQLITEをインストールする

PHPには[PDO](https://www.php.net/manual/ja/book.pdo.php)というデータベース接続用のインターフェースがあります。
.NETでのADO.NETのようなものです。
この中に[PDO_SQLITE](https://www.php.net/manual/ja/ref.pdo-sqlite.php)があります。
これが前述のエラーメッセージで無いといわれたドライバーです。

PDO_SQLはPHP本体の拡張モジュールとして提供されています。
UbuntuではPHPの拡張モジュールをaptパッケージでインストールします。
パッケージを探します。

```sh
apt-cache search php-sqlite
```

![image (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15964/986effb9-541b-574b-9773-cf85d002728a.png)

aptパッケージはPHPのバージョンごと分かれています。
自分が使っているPHPのバージョンと一致したパッケージをインストールします。

```sh
sudo apt install php8.2-sqlite3
```

もう一度マイグレーションを実行すると動きます。

```sh
php artisan migrate
```

![image (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15964/0de9c2be-f166-d82c-cc1b-1a42f5ce14df.png)

## まとめ

PHPではSQLite3用のドライバーは、PHP本体の拡張モジュールとして提供されています。
また、PHPでDBに接続するクラスはPDOと呼ばれています。

## 参考

- [【laravel】データベースの設定（SQLiteの例） #Laravel6 - Qiita](https://qiita.com/gone0021/items/106b176012439841a3d9)
paiza.ioでelixir その257

# 概要
paiza.ioでelixirやってみた。
elixirで3Dが、やりたい。
3Dモデリングしたい。


# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/12438409-2732-8e8f-6c71-ea43131dc0fd.png)

# サンプルコード

```
for j <- 0..3 do
    for i <- 0..3 do
        r = 100
	    d = :math.sin((j / 3) * :math.pi)
	    y = :math.cos((j / 3) * :math.pi) * r
		x = :math.cos((i / 3) * :math.pi * 2) * r * d
		z = :math.sin((i / 3) * :math.pi * 2) * r * d
	    IO.puts "p #{x} #{y} #{z}"
    end
end

for j <- 0..2 do
    for i <- 0..2 do
		b = i + j * 4 + 1;
		if (b == 11) do
    	    IO.puts "s #{b} #{b + 1} #{b + 4} #{b + 4}"
	    else
	        IO.puts "s #{b} #{b + 1} #{b + 4} #{b + 5}"
	    end
    end
end

```

# 実行結果

```
p 0.0 100.0 0.0
p 0.0 100.0 0.0
p 0.0 100.0 0.0
p 0.0 100.0 0.0
p 86.60254037844386 50.000000000000014 0.0
p -43.30127018922191 50.000000000000014 75.0
p -43.30127018922197 50.000000000000014 -74.99999999999997
p 86.60254037844386 50.000000000000014 -2.1211504774498136e-14
p 86.60254037844388 -49.99999999999998 0.0
p -43.30127018922192 -49.99999999999998 75.00000000000001
p -43.301270189221974 -49.99999999999998 -74.99999999999997
p 86.60254037844388 -49.99999999999998 -2.121150477449814e-14
p 1.2246467991473532e-14 -100.0 0.0
p -6.123233995736764e-15 -100.0 1.060575238724907e-14
p -6.123233995736772e-15 -100.0 -1.0605752387249065e-14
p 1.2246467991473532e-14 -100.0 -2.9995195653237154e-30
s 1 2 5 6
s 2 3 6 7
s 3 4 7 8
s 5 6 9 10
s 6 7 10 11
s 7 8 11 12
s 9 10 13 14
s 10 11 14 15
s 11 12 15 15
```

# 成果物

https://paiza.io/projects/J3SFKcuKLN4Kk9QWSJ0w5Q

以上。
Youtubeのタイムスタンプ作成を補助する拡張機能を作ってみた話

## 目次
[1. はじめに](#1-はじめに)  
[2. 作ったアプリについて](#2-作ったアプリについて)  
[3. 開発の流れ](#3-開発の流れ)  
[4. プロジェクトを通して学んだこと](#4-プロジェクトを通して学んだこと)  

## 1. はじめに
Youtubeでタイムスタンプを手軽に打てるようにする拡張機能を作成したのでその記録を記します。

**参考: Youtubeのタイムスタンプ機能とは**  
Youtubeでは、コメント欄に「11:03」のように時間を記載すると、動画内のその時間へ移るリンクを書くことができます。
本アプリは、このような動画内の特定の時間を表すタイムスタンプを手軽に残せるようにした拡張機能です。

## 2. 作ったアプリについて
[2-1 アプリの概要](#2-1-アプリの概要)  
[2-2 アプリの3つの特徴](#2-2-アプリの3つの特徴)  
[2-3 アプリの画面](#2-3-アプリの画面)  

### 2-1 アプリの概要
Youtubeで動画を視聴中に「+ボタン」を押すとその時点でのタイムスタンプを押すことができます。  
「コピーボタン」を押すとタイムスタンプの内容をクリップボードにコピーしてそのままコメントすることができます。

![アプリ画面](https://i.gyazo.com/1afc8fbfc80847c29bf486aae6b3998b.png)

### 2-2 アプリの特徴
[1. タイムスタンプの時間を一括で変更できる](#1-タイムスタンプの時間を一括で変更できる)  
[2. ダークテーマに対応](#2-ダークテーマに対応)

#### 1. タイムスタンプの時間を一括で変更できる
タイムスタンプを作っていると、しばしば「全部の時間を5秒早めたい」ということがあります。  
例えば、何か面白いポイントでタイムスタンプをつけたとき、文脈を把握するために、その少し前から再生ができるようにしたくなります。

このような需要に対応するために、時間を一括で⚪︎秒ずらすことができる、オフセット機能を搭載しました。

#### 2. ダークテーマに対応
この拡張機能は、見た目についてもこだわりました。Youtubeで使われているテーマ(ライトテーマ、ダークテーマ)を自動で読み取り、そのテーマに合った配色になるようにしました。

![ライトテーマ](https://i.gyazo.com/976fbff7d419913728a00759bb442655.png)
![ダークテーマ](https://i.gyazo.com/f4547116f7ba73ae93c3481ac3b5f13e.png)

### 2-3 アプリの使い方
![アプリ画面](https://i.gyazo.com/1afc8fbfc80847c29bf486aae6b3998b.png)

- スタンプを追加  
プラスボタンを押すとスタンプを追加することができます
- リンクへ飛ぶ  
タイムスタンプを残した動画内のポイントに移ることができます
- 並び替えon/off
並び替えをonにすると時間順に並びます。offにするとタイムスタンプを追加した順に並びます。


## 3. 開発の流れ
2023年2月〜3月で要件定義・開発を行いました。開発全体を通して設計・実装を全て1人で行いました。

|時期|内容|
|--|--|
|2月|要件定義・開発|
|3月|開発|

### 使用技術

- Typescript
- React
- テスト: jest

## 4. プロジェクトを通して学んだこと
- chrome拡張機能の作成・公開の流れを把握できた
- 既存の拡張機能を調査して、新たにどのような機能があると便利か考えるという事業的な思考を体験できた
Xcode15でビルド時にSandbox: rsync(xxxxx) deny(1) file-read-data~のエラーが発生

Xcode15でビルド時に下記のエラーが発生。

```
Sandbox: rsync(xxxxx) deny(1) file-read-data '使用しているライブラリ関連のパスのようなもの'
```

Build SettingsのUser Script SandboxingをNoに設定してあげることで解決。

参考
https://developer.apple.com/forums/thread/731041

より詳しく書いてあったもの
https://zenn.dev/feb19/articles/c3e6ec545383bb

以上です。
Goならわかるシステムプログラミング Wrap Up

# わたしは

ebikunです。CARTA HOLDINGSというアドテクなどなどをやっている愉快な企業の新卒内定者であります。
会社のお金で[Goならわかるシステムプログラミング第2版](https://www.amazon.co.jp/Go%E3%81%AA%E3%82%89%E3%82%8F%E3%81%8B%E3%82%8B%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%E7%AC%AC2%E7%89%88-%E6%B8%8B%E5%B7%9D%E3%82%88%E3%81%97%E3%81%8D/dp/4908686122/ref=sr_1_1?crid=1ASV7V0RZEKEL&keywords=go%E3%81%AA%E3%82%89%E5%88%86%E3%81%8B%E3%82%8B%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1697437864&sprefix=Go%E3%81%AA%E3%82%89%2Caps%2C159&sr=8-1)を買ってもらったので今日はそのwrap upを書いていこうと思います。本の内容上Go言語特有の解説がまぁまぁなウェイトで入っていましたが、ここではそれは割愛しメインとなるシステムプログラミングの内容と自身の興味にフォーカスします。

# この本では

PHPなどのプログラミング言語はファイルを開く、メモリを確保するなどの様々なOSの機能を実行時に呼び出している。このようにOSの機能を呼び出すことをシステムプログラミングという。本書はシステムプログラミングについてOSが内部でどんな仕事をしているのかをGo言語を題材に見ていく。

# 5章 システムコール

- システムコールとは「特権モードでOSの機能を呼び出すこと」
- OSの仕事はメモリなどの各種資源の管理とファイル読み書きなどの外部入出力機能の提供である
- プログラムの実行単位のことをプロセスという
- 昔はプロセス管理はOSの仕事ではなかった
    - Windows3.0ではプロセスが別のプロセスのメモリにもアクセスできた
    - Windows3.1ではプロセスがCPUを別のプロセスに自分で回していた
- 今はプロセスの管理もOSの仕事の1つである
- OSの仕事を支えるハードウェアであるCPUには「動作モード」という仕組みがある
    - 動作モードはソフトウェアによって変わり、それによって実行して良いハードウェアとしての機能を制限している
    - 動作モードには「特権モード」と「ユーザモード」がある
- OSはユーザによる強制終了などの強い操作を実行できなければならないので、その他のアプリのプロセスより強い特権モードで起動する
- 逆に一般のアプリケーションは強い操作ができないユーザモードで起動する。
- 動作モードによって、できる操作がCPUのハードウェアレベルで切り分けられている！
- しかし一般アプリからもメモリアクセスや外部入出力をしたい！（それはそう）
- そこで ***システムコール*** を使ってユーザモードのアプリから特権モードでしか使えない機能を使っちゃおうってわけ
- システムコールを呼び出すと呼び出された側は特権モードで動作する

## じゃあシステムコールがないとどうなるのか

- 実はCPUの命令自体はユーザモードでもほとんど使える
- でも計算結果をメモリやファイルに格納したりネットワーク通信で外部に送信したり画面に表示したりするのは特権モードにしかできない。
- だから特権モードを呼べるシステムコールがないと ***計算結果が無駄になる！***
- 実際にはシステムコールがなければ計算のためのデータをメモリから読み込んだり、計算を行うためのメモリを確保したりプロセスを立ち上げることもできない（ので ***計算も満足にできない***）

## POSIX

- OS間で共通なシステムコールのインターフェース
- 実際にはC言語の関数シグネチャとして定義されている
- Go言語もPOSIXのインターフェースに準拠している
- ただしsyscallパッケージ（システムコールのパッケージ）以下のドキュメントはGo言語にはほぼない。必要ならC言語のシステムコールのドキュメントを参照すること。
- システムコール以下のLinuxカーネルはC言語で動作する

## ちなみに

- POSIXは「システムコールのOS間のポータビリティを維持する」ことが目的
- よって本来ならPOSIXに準拠しているGo言語が、各OSのシステムコールをいちいち番号指定して呼び出すのは推奨されない。（C言語の関数使えって話。）だがそれによってクロスコンパイルが容易になり様々なOS上で動くバイナリが簡単に作れるようになった。が、システムコールをいちいち番号指定して呼ぶとなぜポータビリティが損なわれるのかはよくわからなかった。
- が、とにかくGo言語はシステムコールの各OS対応を自力で頑張っていて、それによってクロスコンパイルが容易になっている。

# 19章 Go言語とコンテナ

まずは仮想化一般についての話。

- 仮想化とは「ホストOSの上に複数のOSやシステムを安全に共存させて、ピークの異なる複数のサービスをまとめるなどして効率的にハードウェアを使う」ための技術
- 特に複数のOSが共存できるというのがmiso。

仮想化はいくつかの分類方法がある。

- エミュレーション：CPUを完全にエミュレートする。ホストとは異なるアーキテクチャのCPUを使えるが、パフォーマンスは大きく落ちる
- ネイティブ仮想化：CPUのエミュレーションを行わない高速な仮想化。

- 完全仮想化：ホストOSの上にハイパーバイザを入れてその上で複数のゲストOSを動かす。センシティブな処理はハイパーバイザが割り込んで処理するのでゲストOSは自分が仮想化されていることを意識しなくて良いが、割り込みは発生するのでパフォーマンスは悪い。ただしCPUの進化により現在ではほぼ克服されている。
- 準完全仮想化：ハードの上に直接ハイパーバイザを入れてその上でホストOSとゲストOSを同列に動かす。ゲストOSは自分が仮想化されていることを意識しないといけない。センシティブな処理はハイパーバイザを呼び出すようにする。割り込みが発生しないので完全仮想化よりはパフォーマンス面で有利。
Xcode15でCocoaPods使用時にDT_TOOLCHAIN_DIR cannot be used to evaluate~のエラーが発生

Xcode15でビルド時に下記のエラーが発生してビルドできず。

```
DT_TOOLCHAIN_DIR cannot be used to evaluate LIBRARY_SEARCH_PATHS, use TOOLCHAIN_DIR instead
```

CocoaPods 1.13.0で修正されたようです。(発生した環境は1.11.xでした。)
https://github.com/CocoaPods/CocoaPods/issues/12065

Release Notes
https://github.com/CocoaPods/CocoaPods/releases

Xcodeのアップデート時にはCocoaPods周りのエラーがでがちなので注視していきたいです。(その点においてはSwift Package Managerの方が良いのかもしれない)

以上です。
基本情報自分に何が足りてないのかを分析した

# 概要

基本情報10月と11月を受けた結果ですが

10月
午前660 合格
午後570 不合格
11月
午前640 合格
午後565 不合格

でした。

ここは午前に受かった理由と午後に落ちた理由を分析し、反省して次に繋げられるようにアウトプットした記事です。

# なぜ分析しようと思ったか
きっかけは格ゲーのスマブラ（大乱闘スマッシュブラザーズ）でして、今の強さは上位数0.4%のとこにいます。（戦闘力から計算して）
まー0.4と言っても1000万中の4万人ですからこうしてみると微妙です。

本題

対戦のリプレイを撮ってそれを何度も見返して反省点を探すようにしました。それをトッププレイヤーと見比べて、自分に何が足りてないかを編み出し、それを実践で使う。というのを繰り返して今の地位にいます。

これを基本情報に落とし込むと、解いた問題と解答and解説を見て、何が足りてないかを編み出す。のような感じですね。

今思うとなんでやってなかったんだ？って思います。

慢心です。恥ずい！

一応午前には合格してるのでその勉強法も載せておきます。

# 午前学習戦略
過去問道場をひたすら解きまくること。

https://www.fe-siken.com/fekakomon.php

私の場合は令和元年から平成26年春期までの範囲で解いていました。

午前試験は過去問と同じ問題が出題されます。大体35問くらいです。今日受けてきたら大体それくらい

60問中36問が合格ラインなので
過去問を解きまくることが重要です。

# 私がやっている過去問道場の使い方

完全に理解している問題は基本スルーしますが、間違った問題や、理解していない問題は、スクリーンショットを撮って赤いマークにチェックしています。

再度問題を解き、理解するまで数周します。

アルゴ系問題は理解必須の問題なので、基本撮っていますね。ちなみに朝に解くことが多いです。
どこかの記事で夜が記憶しやすく朝は理解することに長けているとあったので、これもオススメです。やってみたらマジですね。

# 午後結果
10月は
時間が足りませんでした。
問題は今までphpを書いていたからかそんなに難しく感じることはありませんでしたが、1問に時間がかかりすぎました。

11月は
時間は20分余り、見直すには十分な時間でした。
あ、これ受かったな、と思ったのもつかの間、不合格でした。

# 反省点
まず一つ、難しい問題から逃げていたこと。

見ただけで、逃げたくなる問題が何個かありますが、これがよくなかった。
向きあわなきゃそりゃ試験で落とされるよねっていう。

スマブラは難しいことは300回繰り返したのに、、、

二つ、プログラムを理解していなかった。
php書いていたので、ある程度は理解していましたがその中でも苦手分野はありました。
特にclassの部分、帯域変数ですね。

一応3周したので、それでもだめだったということは、難しい問題を理解することに逃げ、理解せずに解いたことと、
自分を慢心し、プログラムを甘く見て、ほかの問題に回していたこと。

三つ、スケジュール管理できていなかった。

基本暇になったら午前問題解いてましたが、（例えば電車とか会社の休憩中とか）
今日はこのくらいの量を解くというのをやっていませんでした。

試験日に合わせて今日はこれくらい解く。というのを前もって設定するべきでした。

時間指定は敢えてしません。個人的に量と質でやる量を決めた方が時間による焦りが減ってより集中できるからです。

勿論本番想定は時間を設定しています。

この三つですね。

# 終わりに
まとめると
+ 難しい問題を理解することに逃げ、理解せずに解いたこと。
+ 自分を慢心し、プログラムを甘く見て、ほかの問題に回していたこと。
この二つが原因と考えられます。
+ 1日に解く量を決めて、スケジュール管理をする

まだほかにもありそうですが、一旦ここをメインで復習します。

12月14日に再受験します。！絶対受かる！受かってみせる！
asdf, python環境構築手順メモ

### 環境
- OS: windows11, WSL(Ubuntu 22.04.2 LTS)
- バージョン管理: asdf v0.13.1
- 仮想環境、パッケージ管理: poetry version 1.1.14

### 手順
#### asdfでpythonをインストール
1. WSL上のubuntuで依存関係をインストール
```
sudo apt update; sudo apt install build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev curl \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
```
2. adsfのpythonプラグインをインストール
```
asdf plugin-add python
```
3. python環境構築
プロジェクトディレクトリ上で実行
```
echo 'python 3.11.3' > .tool-versions \
asdf install \
```

--- 

#### asdfでPoetryをインストール 
1. asdfでPoetryのインストール
```
asdf plugin-add poetry
```

---

### Poetryでプロジェクトの初期化
1. プロジェクトの初期化
```
poetry init
```
2. pythonのパッケージを当該ディレクトリ以下に置く
```
poetry config virtualenvs.in-project true --local
```
3. Poetryで使うpythonの指定
```
poetry env use <xxx>
```
Javaで複数文字列の前方一致

```
// 複数文字列の先頭から共通部分を抜き出す 
public class PrefixOfMultiStrings {
	public static void main(String[] args) {
		String[] strs = { "123", "1234", "12" };

		String prefix = strs[0];
		for (int i = 1; i < strs.length; i++) {
			if (strs[i].length() < prefix.length()) {
				prefix = prefix.substring(0, strs[i].length());
			}
			for (int j = 0; j < prefix.length(); j++) {
				if (prefix.charAt(j) != strs[i].charAt(j)) {
					prefix = prefix.substring(0, j);
					break;
				}
			}
		}

		System.out.printf("prefix=[%s]%n", prefix);
	}
}
```
Minitest: Nokogiriを使ってHTML文字列をテストする

# 概要

今回はRails Minitestにまつわるお話です。

`render :json`で返却されるHTML文字列をテストする際に詰まってしまったことがありました。
その際、Nokogiriを使用してテストする方法を学んだので紹介します。

# 解決したい課題

下記のようにHTML文字列をjson形式で返却するメソッドがあったとします。
みなさんはこのメソッドの返り値が正しいことをどうやってテストしますか？

```ruby:fuga_controller.rb
# HTML文字列を返却するメソッド
def return_html
    new_html = render_to_string(partial: 'hoge')
    render json: { html: new_html }
end
```
```erb:_hoge.html.erb
<div class = "parent">
    <div class = "child">
        <!-- コメント -->
        <p>返却されるHTMLです。</p>
    </div>
</div>
```

# Nokogiriを使わない方法
まずは返却されるHTML文字列をそのままテストします。
例えば...

```ruby:fuga_controller_test.rb
expected_string =
'<div class = "parent">
    <div class = "child">
        <!-- コメント -->
        <p>返却されるHTMLです。</p>
    </div>
</div>'

assert_equal(expected_string, @response.parsed_body['html'])
```
一見、これでテストができているように見えます。

しかし、このテストには欠点があります。
それは、返却されるhtmlと**全く同じ文字列**を期待値として書かなければならないということです。

つまり...

:::note warn
- htmlにコメントが入っている場合、それも`expected_string`に含めなければならない
- 改行や空白に気を使わなければならない
:::

上記のような状況が発生します。

コメントを変更した際や、インデントを変えた際にもこのテストは落ちてしまうことになりますが、これはMinitestで確認したい内容から外れていますよね。

# Nokogiriを使った方法

Nokogiriを使用するとこのような問題点を解決することができます。
下記がNokogiriを使用して書いたテストです。

```ruby:fuga_controller_test.rb
assert_select(Nokogiri::HTML(@response.parsed_body['html']), 'div.parent') do
    assert_select('div.child') do
        assert_select('p', text: '返却されるHTMLです。')
    end
end
```

`Nokogiri::HTML(HTML文字列)`によってHTML文字列を`Nokogiri::HTML4::Document`に変換しています。

そのため、`assert_select`を使えるようになり、viewのテストとして記述することが可能になりました。

前述のようなコメントアウトや空白に影響されないテストになっていて、より本質的なテストができています。

# まとめ

今回はHTML文字列をテストするMinitestの例についてご紹介しました。

Nokogiriを使用することで、`render :json`でHTML文字列を返却した際でもHTMLとしてテストすることが可能になります。

Nokogiriで検索するとスクレイピングでの使用例は多く出てくるのですが、このようにviewのテストをする際にも有効なのだと学びました。


## 留意点
gemが入っていない場合はインストールが必要です。

## 参考
https://nokogiri.org/index.html
Flaskでurl_quoteが見つからなくなった問題

Flaskを使ってAPIサーバーを書いていたら、開発環境を更新したタイミングでサーバー起動時に`url_quote`が見つからないというエラーが出るようになってしまった。

```
Traceback (most recent call last):                                                                                                                                                
  File "/usr/local/bin/flask", line 5, in <module>                                                                                                                                
    from flask.cli import main
  File "/usr/local/lib/python3.9/site-packages/flask/__init__.py", line 5, in <module>
    from .app import Flask as Flask
  File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 30, in <module>
    from werkzeug.urls import url_quote
ImportError: cannot import name 'url_quote' from 'werkzeug.urls' (/usr/local/lib/python3.9/site-packages/werkzeug/urls.py)
```

# 原因
## Werkzeugのアップデートによるurl_quoteの廃止
2023年9月30日に、Flaskが参照している[Werkzeug](https://werkzeug.palletsprojects.com/en/3.0.x/)というライブラリのメジャーアップデートがあり3.0.0がリリースされた。

https://github.com/pallets/werkzeug/issues/2789

Werkzeug 3.0.0で`url_quote`が廃止されたが、Flaskの古いバージョンはこのメソッドを参照している。

## Flask側でのWerkzeugのバージョン指定の問題
古いバージョンのFlaskではWerkzeugのバージョンが細かく指定されていなかったため、破壊的変更を含むWerkzeug `3.0.0` がリリースされたタイミング以降にDependencyを解決しようとすると、Werkzeug `3.0.0`がインストールされるような形になってしまった。

```
"Werkzeug >= 2.2.2",
```


https://github.com/pallets/flask/blob/2.2.2/setup.py

# 回避方法
## Flaskのバージョンを上げる
Flask `2.3.3`以降では、使用するWerkzergのバージョンが明示的に指定されているため問題が起きない。なので、使用するFlaskを`2.3.3`以降のバージョンにバージョンアップする。

```
Flask==2.3.3
```

## Werkzeugのバージョンを明示的に指定する
なんらかの理由でFlaskのバージョンアップができない場合は、`requirements.txt`などでWerkzeug 2.x系を使用するように明示的に指定する。

```
Werkzeug==2.3.7
```
[ERROR] Malformed \uxxxx encodingが出たときの対処法

Javaプロジェクトをビルドした際に`[ERROR] Malformed \uxxxx encoding`というエラーが出ました。

# 原因
何らかの原因でファイルの中に不正な`\uxxxx`が含まれていてデコードできないからです。

# 解決方法
`\uxxxx`が含まれるファイルを探して削除しました。

```
$ grep -rnw ~/ -e '\u0000'
```
見つかったら削除して再ビルドしてみましょう。

```
$ rm -rf [対象ファイルのパス]
```
plunkerでthree.js その2


# 概要
plunkerでthree.jsやってみた。
練習問題やってみた。

# 練習問題
モデリング言語をパースして描画するsandboxを作れ。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/98fe2515-6b96-9a17-f99d-4d46f21e69fb.png)


# サンプルコード

```

function run() {
	var code = document.getElementById("code");
	var width = 400; 
	var height = 400;
	var scene = new THREE.Scene();
	scene.add(new THREE.AmbientLight(0xffffff));
	var camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000);
	var renderer = new THREE.WebGLRenderer();
	renderer.setSize(width, height);
	var container = document.createElement('div');
	document.body.appendChild(container);
	container.appendChild(renderer.domElement);	
	camera.position.set(0, 100, 400);
	scene.background = new THREE.Color(0xeeeeee);
	scene.add(new THREE.GridHelper(400, 10));
	var controls = new THREE.OrbitControls(camera, container);
	var geometry = new THREE.Geometry();
	var norml = new THREE.Vector3(0, 0, 1);
	var textArray = code.value.split(/\r\n|\r|\n/);
	for (var i = 0; i < textArray.length; i++)
	{
		var line = textArray[i];
		if (line.indexOf('p ') === 0)
		{
			var tmp = line.split(' ');
			geometry.vertices.push(new THREE.Vector3(tmp[1], tmp[2], tmp[3]));
		}
		else if (line.indexOf('s ') === 0)
		{
			var tmp = line.split(' ');
			geometry.faces.push(new THREE.Face3(tmp[1] - 1, tmp[2] - 1, tmp[3] - 1, [norml, norml, norml]));
			geometry.faces.push(new THREE.Face3(tmp[4] - 1, tmp[3] - 1, tmp[2] - 1, [norml, norml, norml]));
		}
	}	
	geometry.computeFaceNormals();
	geometry.computeVertexNormals();
	var materials = [
		new THREE.MeshLambertMaterial({
			color: 0xffffff
		}),
		new THREE.MeshBasicMaterial({
			color: 0x3333ff, 
			wireframe: true,
			transparent: true
		})
	];
	var mesh = new THREE.SceneUtils.createMultiMaterialObject(geometry, materials);
	mesh.position.z = -5;
	scene.add(mesh);

function tick() {
  controls.update();
	renderer.render(scene, camera);
  requestAnimationFrame(tick);
}
tick();
}




```

# 成果物

https://embed.plnkr.co/plunk/wqZmZHBNTuzFFoJa


以上。
pythonを使ってbacklogの課題を一括削除してみた

## 1. 経緯
backlogの古い課題を削除して容量を確保する方針になりました。
backlogの課題は1件ずつしか消せない仕様のため、
1万件とかあったら何日かかるの？ってくらい大変です。
その為、今回作成したプログラムで、まとめて消しちゃおうって寸法なわけです。

## 2. 開発環境
pythonで作成しました。
バージョンは3.12.0(64bit)
インストールは↓のURLから試してね
https://www.python.jp/install/windows/install.html

## 3. APIキーの登録
Backlog APIを使うためにAPIキーを登録しておきます。
https://support-ja.backlog.com/hc/ja/articles/360035641754-API%E3%81%AE%E8%A8%AD%E5%AE%9A

## 4. 削除課題の選定
高度な検索を利用して削除する範囲を決めます。
今回は状態は全て選択し、日付タブに移動して
更新日を2016/1/1～2021/12/31を指定しました。
この条件で検索した後、「・・・」からCSVをダウンロードします。
以下のイメージのようにIDが出力されますので、「ID」を後にでてくるcsvを張り付けてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3577498/c6b50adf-1ac8-8095-4e34-20a259dfad72.png)

※課題キーとは？
URL上にもブラウザ構成内にも表示されません。
CSVなどでエクスポートしてIDの欄が課題キーになります。
（この謎の解決に数日かかりました。）

## 5. プログラムの作成

C:\py\backlogcsv削除.py
上記パスにプログラムを置きます。

#### このプログラムの解説
api_keyはURLを参照して確認してください。
space_idは「https://xxx.backlog.jp」のxxxをコピペしてください。
・backlogの契約によって.backlog.jp　または、backlog.comは変更が必要になります。
・c:\\py\\issue_ids.csvのパスに課題キーを入力する必要があります。※課題キーは4番読んでね。
　
```python:backlogcsvファイルを読んで削除.py
import requests
import csv

# APIキーとエンドポイントの設定
api_key = "xxx"
space_id = "xxx"

# CSVから課題IDを読み込む
issue_ids = []
with open('c:\\py\\issue_ids.csv', 'r') as csvfile:  # パスを指定：ｃドライブのフォルダを指定してます。
    reader = csv.reader(csvfile)
    for row in reader:
        issue_ids.append(row[0])  # CSVの1列目が課題IDと仮定

# 各課題IDに対して削除のリクエストを送信
for issue_id in issue_ids:
    url = f"https://{space_id}.backlog.jp/api/v2/issues/{issue_id}?apiKey={api_key}"
    response = requests.delete(url)

print("処理が完了しました。")

```

削除テストはテスト領域を適当に作って行って下さい。
本番データを誤って削除しても、責任は負えません。


以上、十分注意して削除してくださいね。

#### 付録
csvの中身はこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3577498/af4e1bc5-dd1e-7a69-b6b9-176646f798d5.png)