OmniAICreator/Qiita-1.07M huggingface dataset:
『初個人開発』AIプラットフォーム（仮）『DIVE_INTO_AI』を作りました。

# はじめに
みなさん、AIについて日々、使ってますか？
昨今、世の中に新規のAIサービスが生まれてます。
しかし、企業が導入するハードルは以前、高いと言われてます。

そのハードルを少してでも下げれると良いかと思い作りました。

### アプリの概要
[https://github.com/tsuru-ken/D_I_AI.git](https://github.com/tsuru-ken/D_I_AI.git)

### 開発言語
- Ruby 3.0.1

- Ruby on Rails 6.1.7

### 使用gem
- Device
- railse-admin
- ransack
- kaminari
- cancancan
- carrierwave
- google-cloud-vision

### なぜ作ろうと思ったのか？
前職でAI需要予測の営業を経験したおりました。
その経験を踏まえて、感じていたことは、企業がAIを導入するには、
様々な問題点があることを感じておりました。
具体的には、下記の問題点を感じてました。
- 費用対効果が読めないので、本格開発ができない。
- AI開発に必要なエンジニアがいない。

なので、それらを解決できるアプリを作りたいと思い制作させていただきました。

### 工夫したこと
登録したAI会社を、コスト感、提供するサービス、AIカテゴリーから検索できること。
すでに公開されているAIサービスと連携して、試してみることができる。

つまり、実際にAIを試してみて、その結果からAI開発会社を検索できるという実際のビジネスをイメージしたところです。

### 今後の展望

- デザインUX・UIの改善
- 未実装のAI機能を実装する
- テータを投入して、学習・推論ができるようにする。
- ChatGPT　とのAPI連携

### アプリ制作を通して感じたこと。
- オリジナルアプリケーションを作るのは、自分の頭の中のビジネスイメージを具体化できるので、楽しい。
- 具体的に、自分のイメージを具体化するためにいざ手を動かしてみると、当たり前ですが、足りないスキルがたくさん出てくる。
- 要件定義、テーブル定義、ER図、画面製図など1から考えてみると、設計段階の重要を感じられる。
paizaラーニング レベルアップ問題集 DPメニュー JavaScript 【連続列】最長減少連続部分列

【連続列】最長減少連続部分列 (paizaランク B 相当)

https://paiza.jp/works/mondai/dp_primer/dp_primer_lis_continuous_boss

# 解答例
人の番号と、配列a、配列dpのインデックスを合わせた。
なので、配列a、配列dpの長さはn+1にした。

reduceとMath.maxで最大値を求めた。
```javascript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");

const [n] = lines[0].split(" ").map(Number);
const a = lines.slice(0).map(Number);//dpと長さn+1に揃えるのでslice(0)とした。
a[0] = 0;//a[0]は見た目上0にしておく。

const dp = Array(n + 1).fill(0);//ここに区間の最長の長さを登録していく。nまでなので長さn+1のArray(n+1)。

dp[1] = 1;

for (let i = 2; i <= n; i++) {
  if (a[i - 1] >= a[i]) {
    dp[i] = dp[i - 1] + 1;
  } else {
    dp[i] = 1;
  }
}

console.log(dp.reduce((a, b) => Math.max(a, b)));
```

# 解答例(C++の場合参考)
配列aは長さn+1,配列dpも長さn+1,aとdpのインデックスiと人i番目は一緒。
aの身長を見ていく時、i=1からにしている。
```javascript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");

const [n] = lines[0].split(" ").map(Number);

const a = Array(n+1);
a[0] = 0;//a[0]は身長0として,a[1]>=a[0]になるようにしている。
for(let i = 1; i <= n; i++){
    a[i] = lines[i];
}

const dp = Array(n + 1);//ここに区間の最長の長さを登録していく。nまでなので長さn+1のArray(n+1)。

dp[0] = 0;//dp[0]は長さなし
for(let i = 1; i <= n; i++){//aの身長i=1から見ていく
    if(a[i-1] >= a[i]){
        dp[i] = dp[i-1] + 1;
    }else{
        dp[i] = 1;
    }
}

console.log(Math.max(...dp)));
```
# 解答例(Python3の場合参考)
実装上、aのsliceで、インデックスi-1とi番目の人が一緒。
なのでdpもインデックスi-1とi番目の人を一緒にした。
```javascript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");

const [n] = lines[0].split(" ").map(Number);
const a = lines.slice(1).map(Number);

dp = Array(n).fill(1);//ここに区間の最長の長さを登録していく。１番目の人インデックス0で、初期値は1なのでfill(1)
for(let i = 1; i <= n; i++){
    if(a[i-1] >= a[i]){
        dp[i] = dp[i-1] + 1;
    }else{
        dp[i] = 1;
    }
}

console.log(Math.max(...dp));
```

# 解答例(Javaの場合参考)
aとdpのインデックスはi番目の人に合わせた。
dpは最後Math.maxで比較するので、fill(0)で初期化。
aは2から見ていく、前問の問題文の通り。

let answer以降は、reduceの動きをfor of　でループするやり方。

```javascript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");

const [n] = lines[0].split(" ").map(Number);

const a = Array(n+1);
a[0] = 0;//a[0]は身長0として,a[1]>=a[0]になるようにしている。
for(let i = 1; i <= n; i++){
    a[i] = lines[i];
}

const dp = Array(n + 1).fill(0);//ここに区間の最長の長さを登録していく。nまでなので長さn+1のArray(n+1)。最後比較するのでfill(0)で初期化。

dp[1] = 1;
for (let i = 2; i <= n; i++) { 
  if (a[i - 1] >= a[i]) {
    dp[i] = dp[i - 1] + 1;
  } else {
    dp[i] = 1;
  }
}

let answer = 1;
for (let val of dp) {
  answer = Math.max(answer, val);
}
console.log(answer);
```
【個人開発】iosアプリ「Custom Wall Clock」をリリースしました

![Simulator Screen Shot - iPhone 14 Pro - 2023-02-28 at 10.47.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366451/95bba977-08e8-00c9-cada-7c73b7d884e4.png)

:::note info
このプロダクトは、株式会社mofmofの「水曜日の個人開発」にサポートされています。
:::

https://indie-dev.mof-mof.co.jp/

好きな画像を画面いっぱいに表示し、時間を確認することのできるカスタム時計アプリ **「Custom Wall Clock」** を作りました。

https://apps.apple.com/us/app/custom-wall-clock/id6445863766

## できること (MVP)
- 好きな画像を選択し画面いっぱいに表示できます。
  - 好きなキャラクターの絵を表示したりするとなかなかエモいので試してほしい！
- 時計の文字を好きな色に変更できます。
  - 画像の色合いによって文字が見えない問題が発生したので急遽取り入れました。

## 今後追加したい機能 (時間がなかった)
- フォルダ選択によるランダムな画像表示機能
  - 見るときによって画像が変わっててたらテンション上がりそう！
- 文字配置変更機能
  - 文字が見づらい問題があるので表示位置変えられるようにしたい！
- 文字サイズ変更機能
  - 画像によって合う文字の大きさが変わるなと実際使ってみて思った！
- 文字フォント変更機能
  - 上と同じ理由！

## 作ろうと思った理由
- 部屋に時計がない（買えばいい）
  - 毎回ipadの画面をタップして表示するかmacのヘッダーを表示するかで使いずらい
- 開発等の作業中に画面真っ暗なのが寂しい
  - 寂しい
- アプリ開発をしてみたい
  - ずっと興味はあったけどなかなか手をつけられなかったのでちょうどいいタイミングだった！

## 使用技術
- flutter 

社内でたまに話題が出ることがあり、自分としても興味があったのでflutterに挑戦してみました！
MVP開発を意識し、最小限のアプリ開発を行おうという意味合いもあり、まずはflutterのみでの開発にしました。
「flutterでスマホアプリが作れるぞ」くらいの認識で開発始めたのでなかなか開発進みませんでした笑

## 開発期間・工程
2023/01/18 ~ 2/22 の約2ヶ月間の水曜日 +α?
- アイデア出し
- flutter tutorial
- 画像表示
- データ保存
- UIの作成・調整
- simulaterでのテスト
- バグ修正
- テキスト見えない問題修正
- apple developer program 登録
- testflightでのテスト
- 色を変えると起こるバグの修正
- 表示がうまくされないバグの修正
- app store connect　でアプリリリースの準備
- app review 提出
- 許可メッセージの日本語化修正
- リリース

最初はandroid studioで開発してたけど、途中からvscodeでの開発でも問題ないことに気づいてそこからペース上がりました。

## 最後に
なんとか実際にリリースをするまで持っていくことができたのでよかったです。
apple developer program にとうとう加入したので今後アプリ作り放題だ！笑
開発の詳細は後日zennでまとめます！
ラズパイDB構築と作業進捗

# この記事の目的
IT初学者の筆者が「RaspberryPi上でDatabaseを構築」しながら、
OS/ネットワーク/セキュリティ/データベースを包括的に学んでいく過程を記録し、
自己理解の援助を目的とする

## 何を作るか/したいか
・RaspberryPi上でDatabaseを構築する。
・Databaseにはある特定の銘柄のID/株価/始値/終値/出来高/高値/安値を記録できるようにする。
・ホストPCからRaspeberryPi上のDBを閲覧できるようにする。


## どう作るか
ChatGPTあるいはBing AIに問い合わせながら作成する。
まずは理屈を理解しなくても良いからとにかく作る。

動くものを作った後で内容の理解を、Qiitaの記事作成を通じて、深める。

## 2023/03/03時点の進捗
以下はAIの力を使って取り合えず実現した作業リスト。
作業ごとに別途記事を作成予定。
- [Raspberry Piのセットアップ](https://qiita.com/guruka/items/07978931991081c93fb9)
   - 初期セットアップ
   - VNC設定
- DataBaseの構築
   - MariaDBのインストール
   - Stock_Value_Table作成
- ホストPCからRaspberry Pi上のDBを参照
   - ホストPCにHeidiSQLをインストール
   - Raspberry Pi側にホストPCからの接続を許可
Elixir 挑戦記 - 地理空間データを扱う

# Elixir 挑戦記

- 統合的アプローチによる学習
- とりあえず手を動かしてみるシリーズ
- 調べたり取り組んだりした内容をひたすら書いていく
- あとで整理してまとめたい

# 地理空間データについて

こちらの記事が分かりやすかったです

https://sorabatake.jp/15589/

## Elixirで扱いやすいファイルフォーマット

### ラスタ形式 → GeoTiff

- Evisionで読込、表示 `Evision.imread/1`
- 衛星データはこれが多い

### ベクタ形式 → GeoJson

- Jason+Geoで読み込み `File.read!/1 |> Jason.decode!/1 |> Geo.JSON.decode!/1`
- MapLibreで表示 `MapLibre.add_geo_source/3`
- gdalwarpも対応 (COG取得用に`System.cmd/3`から使いたい)
- [geojson.io](https://geojson.io) で簡単に作成できる (他形式からの変換も可)
- [行政区域データ](https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N03-v3_1.html
)、[筆ポリゴン](https://open.fude.maff.go.jp/) でサポートされている

# Livebookで地理空間データを読み込んでみる

## Setup

```elixir
Mix.install(
  [
    {:evision, "~> 0.1"},
    {:geo, "~> 3.4"},
    {:jason, "~> 1.4"},
    {:kino, "~>0.8"},
    {:kino_maplibre, "~> 0.1.3"}
  ]
)
```

必要なパッケージをインストール

# GeoTiff

LandBrowserからGeoTiffを取得[^Credit]

```elixir
tif_path = "./sample.tif"

Evision.imread(tif_path)
```
![Mar-02-2023 17-08-01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1666407/dffad53b-5035-a6f6-f23e-491a0d37f269.gif)

非常にシンプルで良き

画像、データ構造のどちらも確認できるのは便利


# GeoJson

行政区域データ(大分県令和４年度)を利用[^Credit2]
参考：[行政区域コード](https://nlftp.mlit.go.jp/ksj/gml/codelist/AdminAreaCd.html)

```elixir
geojson_path = "./N03-22_44_220101.geojson" # 大分県令和４年度の行政区域データ

geojson_data =
  File.read!(geojson_path)
  |> Jason.decode!()
  |> Geo.JSON.decode!()

city_code = "44201" # 大分市の行政区域コード

city_geojson = %Geo.GeometryCollection{
  geometries: Enum.filter(geojson_data.geometries, &(&1.properties["N03_007"] == city_code))
}

coordinates_list = 
  city_geojson.geometries
  |> Enum.map(& &1.coordinates)
  |> List.flatten()

longitudes = 
  coordinates_list
  |> Enum.map(& elem(&1, 0))

latitudes =
  coordinates_list
  |> Enum.map(& elem(&1, 1))

center = {
  (Enum.min(longitudes) + Enum.max(longitudes)) / 2,
  (Enum.min(latitudes) + Enum.max(latitudes)) / 2
}

city_map =
  MapLibre.new(center: center, zoom: 8, style: :terrain)
  |> MapLibre.add_geo_source("city_geojson", city_geojson)
  |> MapLibre.add_layer(
    id: "city_geojson",
    source: "city_geojson",
    type: :fill,
    paint: [fill_color: "#00ff00", fill_opacity: 0.5]
  )
```

![Screenshot 2023-03-02 20.32.32.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1666407/cf1152e6-142e-bee9-f3e5-3b3d2d211ff3.jpeg)

中心座標の計算に少し手間がかかるが、綺麗に表示できた
（SmartCellを使って手動設定も可能、とりあえず確認したいだけならそれで十分そう)

## 参考

https://qiita.com/RyoWakabayashi/items/c87fe1256bcd105d370c

https://qiita.com/RyoWakabayashi/items/4d5ff1a2ae8644d3a7b2


[^Credit]: “ The source data were downloaded from AIST’s LandBrowser,
(https://landbrowser.airc.aist.go.jp/landbrowser/）produced from ESA remote sensing data”）
[^Credit2]: [出典：国土交通省国土数値情報ダウンロードサイト](https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N03-v3_1.html#prefecture44)
【AWS】RDSを7日以上停止するステートマシン

# 最初に

RDSを停止していたと思ったらいつの間にか起動している何てこと結構あると思います！
対策としてよくあるのは、EventBridgeでスケジューリングして、7日間経ったタイミングで起動して停止するというパターンだと思いますが、
StepFunctions使えばそこだけで完結するやんってことに気づいたのです。

# StepFunctions ステートマシン

## フロー

フローは下図の通りです！停止して6日間待ってステータス確認して、停止済みなら一時的に起動してもう一度。それ以外のステータスならSuccessに逃げます。
6日間のところは、ちょっとチキってますｗ

![stepfunctions_graph (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1123830/1f6ea447-7893-1e11-717b-fdb2c8c485d6.png)

## ステートマシン定義

ステートマシンの定義は下記の通りです！

```json
{
  "Comment": "A description of my state machine",
  "StartAt": "RDSクラスターを停止",
  "States": {
    "RDSクラスターを停止": {
      "Type": "Task",
      "Next": "Wait - 6日間",
      "Parameters": {
        "DbClusterIdentifier.$": "$.db_identifer"
      },
      "Resource": "arn:aws:states:::aws-sdk:rds:stopDBCluster",
      "ResultPath": null
    },
    "Wait - 6日間": {
      "Type": "Wait",
      "Seconds": 518400,
      "Next": "DescribeDBClusters"
    },
    "DescribeDBClusters": {
      "Type": "Task",
      "Parameters": {
        "DbClusterIdentifier.$": "$.db_identifer"
      },
      "Resource": "arn:aws:states:::aws-sdk:rds:describeDBClusters",
      "Next": "Choice - クラスターステータス",
      "ResultSelector": {
        "db_identifer.$": "$.DbClusters[0].DbClusterIdentifier",
        "status.$": "$.DbClusters[0].Status"
      }
    },
    "Choice - クラスターステータス": {
      "Type": "Choice",
      "Choices": [
        {
          "Variable": "$.status",
          "StringMatches": "stopped",
          "Next": "RDSクラスターを一時的に起動"
        }
      ],
      "Default": "Success - クラスターが別の要因で起動または削除されました"
    },
    "RDSクラスターを一時的に起動": {
      "Type": "Task",
      "Parameters": {
        "DbClusterIdentifier.$": "$.db_identifer"
      },
      "Resource": "arn:aws:states:::aws-sdk:rds:startDBCluster",
      "ResultPath": null,
      "Next": "Wait - 5分"
    },
    "Wait - 5分": {
      "Type": "Wait",
      "Seconds": 300,
      "Next": "RDSクラスターを停止"
    },
    "Success - クラスターが別の要因で起動または削除されました": {
      "Type": "Succeed"
    }
  }
}
```

入力はこんな感じ！

```json
{
  "db_identifer": "データベース識別子"
}
```

# 最後に

同じデータベースに対して、ステートマシンの実行が重ならないように注意してください！
ご紹介したステートマシンはクラスター用ですが、インスタンスでもAPIをインスタンス用のに変えれば同じようにできます！

以上！ありがとうございました！
テスト90

```vb
Sub Option_Test()

'シートで使うフォームコントロールのオプションボタンの
'動作の確認..._/o(ﾟωﾟ｀)ﾒﾓﾒﾓ

Dim Btn_flg As Boolean
Dim Opt As Variant

Btn_flg = False

With ThisWorkbook.Sheets("PDF回転")

    '名前から角度を取り出す
    For Each Opt In .OptionButtons
    
        If Opt.Value = 1 Then
        
            MsgBox Replace(Opt.Name, "option", "")
            Btn_flg = True
            
        End If
        
    Next Opt


    If Btn_flg = False Then
    
        MsgBox "回転させる角度が選択されていません。選択後に再度ボタンを押下してください。", _
                      vbCritical, "終了"
        Exit Sub
        
    End If

    '全て解除
    For Each Opt In .OptionButtons
    
        Opt.Value = -4146

    Next Opt
    
End With



End Sub
PyAutoGUI メモ


## PyAutoGUIとは

* Python スクリプトでマウスとキーボードを制御して、他アプリケーションとのインタラクションを自動化するためのライブラリ
* 対応OS：Windows、macOS、Linux
* ランタイム：Python2および３
* 主な機能
  * マウスを移動させ、他のアプリケーションのウィンドウをクリックする
  * アプリケーションへキーストロークを送信する
  * スクリーンショットを取得し、与えられた画像（ボタンやチェックボックスなど）を画面上で検出する
  * アプリケーションのウィンドウを検出し、移動、サイズ変更、最大化、最小化、または閉じる
  * アラートボックスやメッセージボックスを表示する

## 事前準備

* インストール

  ```
  pip install pyautogui
  ```



## よく利用する操作

```python
import pyautogui

### モニター・マウス情報の取得
# メインモニターの縦横サイズを取得する
s_width,s_height = pyautogui.size()

#現在のマウス座標の取得
x,y = pyautogui.position()

### マウス移動
# マウスを指定座標に移動する
pyautogui.moveTo(100,150)

# マウスを指定ピクセル分移動する
pyautogui.move(400, 0)

### クリック系操作
# クリック
pyautogui.click()
# 右クリック
pyautogui.click(button='right')
# マウスを指定座標に移動してクリック
pyautogui.click(100,200)
# ダブルクリック
pyautogui.doubleClick()

### キー入力・押下
# キー入力
# 例：0.25秒間隔でHello PyAutoGUI!と入力する
pyautogui.write('Hello PyAutoGUI!',interval=0.25)
# キー押下
pyautogui.press('esc')

# 特定キーを押下しながら、操作する
# 例：shiftキーを押下しながら、Leftキーを4回押下する。※4回押下後Shiftキーは解放される。
with pyautogui.hold('shift'):
    pyautogui.press(['left','left','left','left'])
```

## 参考情報

* [Welcome to PyAutoGUI’s documentation!](https://pyautogui.readthedocs.io/en/latest/)
[Servicenow] 　個人インスタンスを作成しよう

 
はじめに
-
・servicenowの案件に携わることになり、自分が経験したことや教えていただいたことをアウトプットしていきたいと思います。

・本記事では、無料の個人開発者インスタンスを作成する内容になります。

個人インスタンスを作成
-
ServiceNowは、学習したり、実験するために使用することを目的として、無料の個人開発者インスタンス (Personal Developer Instances) を提供してくれます。


１.まずは、自分のServiceNowIDを取得しましょう。
※ServiceNowIDの作成は、以下の方法以外にもあるので、あくまで一つの方法として見てください。


・右上の「sign in」をクリックする。
![スクリーンショット 2023-03-02 15.57.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3154654/f7f62b67-0165-2c78-2f4d-494d3a7ee08e.png)

・画面を下にスクロールし、「Get a ServiceNow ID →」をクリックする。
![スクリーンショット 2023-03-02 19.10.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3154654/b24a4115-3649-51e6-7114-ab4b90bd138a.png)

・アカウントの情報を入力する。
![スクリーンショット 2023-03-02 19.14.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3154654/e5399d4b-a0b0-36ca-ce5a-b9a78ed841b0.png)

・アカウント情報に登録したメールアドレスに以下のようなメールが届くので、
「Verify Email」をクリックする。
その後にメール認証コードを求められるので、それを通るとServicenow ID作成完了です。
![スクリーンショット 2023-03-02 19.17.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3154654/044cc79c-44a4-e88f-cde3-a1353c17e826.png)

2.個人インスタンスを作成しましょう。
・作成したServiceNowIDでログインし、「start Building」をクリックしてインスタンスを作成する。
※インスタンスの作成に置いて、長いときは何時間も掛かります。また、作成した後もインスタンスを起動するときは、「start Building」をクリックしてください。
![スクリーンショット 2023-03-02 19.25.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3154654/05da831b-9c40-0932-62cf-f22d1caa606f.png)

・インスタンスが作成されると、自分のプロフィールを参照した際に、以下のように出てきます。
![スクリーンショット 2023-03-02 19.27.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3154654/1eb37340-9445-1b1c-acf7-77bc5c6b1587.png)



上記が出てくると、個人インスタンスの作成は終了です。
ただし、インスタンスを作成したとしても、10日間インスタンスを起動しなければ、削除されるので注意してください。一応ServiceNowから注意喚起のメールが来ます。
→過去に10日間ほったらかしにして自分のインスタンスが消えてしまいました。。

終わりに
-
以上で、個人インスタント作成の説明は終了ですが、まだまだServiceNowに関して知識が浅いので、有識者の方が記事を読んだ際、訂正箇所などある場合メッセージ頂けると非常にありがたいです！初心者の方でも、ここが分からないとかあれば御意見よろしくお願いいたします。

最後まで、読んていただきありがとうございました！
【SwiftUI】よくある感じのくるくるインジケーター


![Simulator-Screen-Recording-iPhone-14-Pro-2023-03-02-at-19.29.13.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2648522/6590b2d5-0e05-5cef-0b04-7e9af2711eb2.gif)


``` swift
struct SpinnerView: View {
    @State private var showSpinner = false
    @State private var degree: Int = 270
    @State private var spinnerLength = 0.6
    
    var body: some View {
        ZStack {
            VStack {
                Button {
                    showSpinner.toggle()
                } label: {
                    Text("show spinner")
                }
            }
            if showSpinner {
                Circle()
                    .trim(from: 0.0, to: spinnerLength)
                    .stroke(.green, style: StrokeStyle(lineWidth: 8.0, lineCap: .square, lineJoin: .round))
                    .animation(Animation.easeIn(duration: 1.5).repeatForever(autoreverses: true), value: spinnerLength)
                    .frame(width: 60, height: 60)
                    .rotationEffect(Angle(degrees: Double(degree)))
                    .animation(Animation.linear(duration: 1).repeatForever(autoreverses: false), value: degree)
                    .onAppear {
                        degree = 270 + 360
                        spinnerLength = 0
                    }
            }
        }
    }
}
```
PenguinHack参加記録

「PenguinHack」というハッカソンに参加したので、振り返りつつ感想を残しておこうと思います。

# PenguinHackについて
PenguinHackは九州工業大学 飯塚キャンパスで開催された、初心者向けハッカソンです。参加者一人一人にメンターが付き、初心者でも１つのプロダクトが作れるように支援していただける環境で開発できます。
開催日前にもパネルディスカッションやブートキャンプなど勉強会を開かれていて、ハッカソン参加者以外にも開発の機会を増やす活動をされていました。
今回の応募は倍率が約３倍になったらしく、当選したあとにそれを聞いてちょっと震えました…

PenguinHackの[HP](https://hackspenguin.studio.site/)、[Twitter](https://twitter.com/hacks_penguin)はこちらからどうぞ

## 審査基準・ルール
参加者は「世の中を便利に」「飯塚を楽しく」「自分の生活を便利に」という3つのテーマのうち一つを選び、開発します。
初心者が一人で制作するため、どうしても時間や技術力が足りないような部分はメンターさんが一部開発することが許可されていました。（実質参加者とメンターの2人チームで開発してる気分でした。）
審査は参加者が開発した部分に対し行われます。

アイデア、UI・機能実装完成度、技術力の三項目を基準に審査されます。

## 表彰
最優秀賞　1名
優秀賞　1名
審査員賞　3名
Comet賞　1名
エラー賞　1名

## 審査員の方々

- 安永　卓生　教授
九州工業大学　副学長
- 成瀬　弁宣　氏
GMOインタネットグループ　デベロッパーエンジェリスト
- 三谷　章太郎　氏
パイプドビッツ執行役員CSQO

# 自己紹介
今年度の秋頃から、大学のサークルで開発してる人が多かったことがきっかけでWeb開発に興味を持ちだした初心者です。プログラム書くのもパソコン触るのも授業以外では殆どない…という状況でした。
11月末に初めてハッカソンに参加したときは右も左も分からず悔しくも完成させることが出来ませんでした…
PenguinHackには1on1で見てくれると聞き、１度は何か完成したモノを作りたい！メンターさんに助けてもらいたい！という気持ちで参加を申し込んだ次第です。

# 成果
アプリ名「[TODOのなかまたち](https://jolly-dune-046b90900.2.azurestaticapps.net/)」
[github](https://github.com/powaaaaa/penguin-hack-f)はこちらからどうぞ！

- Todoにその難易度やモチベーション、カテゴリを選択し、追加ボタンを押すと画面右側のリストに追加されるアプリ
- Todoの数に応じて中央のアシカのイラストが変化する
- イラストやレイアウトにこだわり、(ハッカソンによくあるtodoアプリなのはともかく)ぱっと見て完成度が高そうな見た目にした
- フロントエンドはReact（参加者担当）、バックエンドはAzure Fanction（メンター担当）
- ログイン画面
![スクリーンショット_20230228_220112.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2822706/b7ce9a59-d033-85ec-cf6f-a339bddb977b.png)
- ホーム画面
![スクリーンショット_20230228_220234.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2822706/9fae03df-c8e2-1055-0212-5da3493a2216.png)


審査員賞をいただきました。ありがとうございます！

# 本番前
本番1週間前に始まったブートキャンプでReactやcss講座、VPSやdockerとふれあったりする勉強会がありました。急ごしらえだったと聞いたのですが、このとき頂いた資料でこのハッカソンを乗り切ったくらいにはめちゃめちゃありがたくて分かりやすいものでした！
ブートキャンプ中は講座と同時にアイデア出しや開発を進めていき、その日の進捗をdiscoedチャンネルに報告します。このとき、他の人がどんなことしてるのかが分かるのは個人的に嬉しかったです。
私は本番までにアイデア出しとある程度のアプリ機能、イラストを作成しておきました。

# 本番
初めにメンターさんに作りたい物と現在の進捗を報告し、見た目を整えていく方針になりました。1日目は3時間ほど私がレイアウトを整え、その間メンターさんがバックエンド側を作っていただくという計画でしたが、実際は私が発表のギリギリまで見た目の調整に時間を掛けてしまいました。機能の追加もしつつであったのでそんなもんかもしれませんが、取り組む時間を決めて開発することの大切さが分かりました。特にレイアウトは……
発表はすごく緊張し、噛み噛みのしゃべりでしたが作ったものを審査員の方々に説明できることが嬉しかったです。Todoアプリというシンプルなものですが、形になった物を人に見せて評価していただける機会はなかなかないので、参加して良かったと感じました。
表彰ではレイアウトを評価していただき、三谷さん賞を頂きました。メンターさんに尋ねながらの出来でしたが、当日のほとんどの時間を掛けた部分が評価され本当に嬉しかったです。

# 感想
やはり技術力の足りなさを実感しました。しかしハッカソン参加前よりは格段にReactやCSSを理解できたなと思います。今後の勉強のモチベにもなりました！周りの言ってる用語が少しずつ理解できてるのが嬉しいです。

ここまでご覧いただきありがとうございました！
[個人開発]アイデア募集・投稿アプリ

# 初めに
　プログラミングスクールの卒業課題として自作アプリを開発しました。せっかくなのでQiitaに投稿することにしました

# アプリ概要(アプリ名:アイデアマン)
　ユーザーが気軽にアイデアを募集・投稿することができ、問題解決の助けになります。

https://github.com/sasaki2931/ideaapp

### 開発言語
・Ruby 3.0.1 

・Ruby on Rails 6.1.7

### 使用Gem

・Device
・railse-admin
・ransack
・kaminari

# なぜ作ったか？
　私は卒業課題を作る上で何を作ろうかと非常に悩みました。悩みに悩んだ結果何も浮かばず、それなれば人の手を借りよう!!ということで気軽にアイデアを得ることができるこのアプリを開発することにしました。

# 意識したこと
・チーム開発を意識してイシューを作成し、ブランチを分けて開発した


# 今後の展望
・フロント部分がまだ寂しいのでそこを進める
・アイデアを投稿するユーザーに対するメリットが薄いのでその部分の開発
・募集者に対して質問できるコメント機能をつける

# 卒業アプリ制作を通して
　このアプリを開発することによりプログラミングで出来ることの深さを学ぶことができました。しかし、その分自分の技術不足も痛感したのでもっと学んでいきたいです。またアプリをバージョンアップしたらその都度投稿したいと思うのでよろしくお願いします。
React Queryってなんぞや

# React Queryとは&なぜ使う必要が
- サーバーとの処理などを良い感じにやってくれるライブラリ

- Reactは状態の変化には強いが、サーバーとのやり取りのあたりはそこまで力を入れていない

- つまり開発者やチームによってAPIのハンドリングなどが異なる

 

# 詳しく
- fetchやaxiosの代わりに、ではなくそれらを使った上でReact Queryを使う

```ts
import { useQuery } from 'react-query'
const fetchUsers = async () => {
  const res = await fetch('https://jsonplaceholder.typicode.com/users');
  return res.json();
};

const result = useQuery('users', fetchUsers);
console.log(result)
```
- ↑今のところ特に使い所なさそう…が

```ts
 const { data, isLoading, isError, error } = useQuery('users', fetchUsers);
```
- 色んなプロパティを用意してくれているみたい

- `isLoading = true` の時はローディング画面にしておく、や `isError = true` のときはエラー画面を表示するなど

- 処理が返ってきていないときはisLoadingという変数を用意して…と自分たちで実装しなくて良くなる

- キャッシュがとても良いらしい
    - キャッシュを用いて先ほどの data のように値を返し、さらにバックグラウンドでfetchしているので差分があればfetch後に返す値を変えてくれる

# 参考
- https://react-query-v3.tanstack.com/overview
- https://reffect.co.jp/react/react-use-query
PLATEAU SDK for Unityを触ってみた

## はじめに
マップとして読み込んだのは
- 大阪
- 東京

の2つのみで、他の都市のマップについては調べてません

公式の解説としては
https://project-plateau.github.io/PLATEAU-SDK-for-Unity/
の方が詳しくのっているのでそこを参照してください。

## 使い方
### Assetインポート
https://assetstore.unity.com/packages/tools/utilities/plateau-sdk-for-unity-245703

AssetManagerからダウンロード後importを行う
インポート後に上部メニューにPLATEAUのメニューが出来るので
そのメニューの中の`PLATEAU SDK`を押すことでメニューを開くことができる

### モデルデータのインポート方法
方法としてはローカルからファイルを選択して読み込む方法 or サーバーから読み込む方法
基本はサーバー側からの方がお手軽に可能でしたが、接続先の設定の問題なのか
データセットが大阪と宮城しか選択できない状態になってました。
![osaka_and_miyagi](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165363/ea5f9e4e-89cd-a6bb-6b88-1a98a25b388b.png)
多分、別のやり方はあるとは思いますが、公式に載ってなかったので今回はパス

#### サーバーからの読み込み
![server](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165363/d9918b51-1176-b8f9-c0f7-455709f69b99.png)
①,②,③の順番にやればOK
公式にも記述はあったが、基準座標系についてはデータセットに入れたものから近いものを選択しておくと良いみたいでした

#### ローカルからの読み込み
都市モデルデータを以下のサイトからダウンロードする
`CityGML`の項目のものをダウンロードしてこればUnitySDKで使用可能
https://www.geospatial.jp/ckan/dataset/plateau

フォルダパスにダウンロードして解凍をしたフォルダを選択すれば
サーバーからの読み込み同様に使用可能です

### 読み込みデータの命名の分類
![data_name](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165363/ffe4ea6a-3dbb-6d5c-17fe-9dd536ae0950.png)
わかってる範囲で
- tran : 道路 
- bldg : 建物系
- frn : 道路の線、文字、ガードレールなど
- veg : 植え込み、木など

### 雑感
- 範囲選択で地図のシーンになりますが、あまりに範囲を広くするとメモリの問題で落ちるので、パワーの無いPCの場合は取得範囲を狭めるなどの必要はありそうでした
- 大阪と東京の一部のみ読み込んでみた形になりますが、基本的には真っ白の構造物になっており、自分でが見つけた範囲で言えば東京の新宿の一部はカラーテクスチャが一部貼ってありました
![ss_shinjyuku](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165363/4ae161d0-6823-f1e7-ad0b-79077a877b30.png)
- 各道路、構造物の大きさについてはそれなりの大きさであり、そのまま車のモデルを読み込み走らせることも可能だと思います
↓試しにunityのど標準のキューブを道路に設置したもの
![cube](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/165363/4518f1fd-cddf-e918-8e68-a78393f8b73c.png)
- 動的に外側からモデルの読み込みとかは、ロードの重さの問題で個人的には難しそうという感じがしました
- ZENRINのモデルの代用が出来るかでいえば、テクスチャが貼ってある部分が少ないので使用用途によっては可能という感じでしょうか・・・？
「統計検定２級」に２回目で合格した顛末と勉強法

# はじめに
統計学に興味をもち、キチンと勉強をしたくなり、なんらかの目標をたてるべく「統計検定」の存在を知った。

# 無謀な挑戦（準１級。。。）
すこしなめて2022年７月から「統計検定 **準１級** 」の勉強を始めました。
まず準備した参考書は以下のとおり
 https://www.toukei-kentei.jp/prepare/books/#book-01
[日本統計学会公式認定　統計検定１級対応　「統計学」](https://www.gakujutsu.co.jp/product/978-4-7806-0852-6/)
[日本統計学会公式認定　統計検定準１級　公式問題集](https://jitsumu.hondana.jp/book/b590880.html)
 
参考書を読んでもまったく理解できず。早々（２週間後）に諦めました。もう少し謙虚になって２級を目指して勉強をすることにしました。

# ２級に向けての学習開始
2022年8月から学習開始。12月に受験をする。（不合格）
## 問題集①
問題集は、以下の認定本を購入。

[日本統計学会公式認定　統計検定２級　公式問題集［2018～2021年］](https://jitsumu.hondana.jp/book/b590884.html)
２０１８年から２０２１年までの試験問題（紙ベース）の過去問と解説が掲載されています。

最初は問題の内容がちんぷんかんぷんでした。
とりあえず、回答と解説を読んで、「こんなものなんだ」と納得したふりをして最終的に以下のe-learnigと参考書を基に **８周** 位した。
いずれの回も同じ問題傾向で、問題のパターンに慣れていった。

## e-learning
会社で受講できるUdemyを活用。
[統計検定®2級対策講座](https://www.udemy.com/course/toukei-kentei/)
問題を解くのに必要な基本的な統計知識を丁寧に解説。ぜんぶで９時間ですが、内容は良いです。
問題文の意味が少し見えてきた感じ。

## 受験（１回目 １２月下旬）そして不合格
問題集を何度も繰り返し、過去問であれば８割以上は解ける状態で受験。
同じような問題が出れば楽勝、と思いきや、本番（CBT）の傾向がかなり違って焦る。
たとえて言うなら、普段の練習で直球ドストライクばかりの練習で結構打てると自信をもって、
本番の打席に立ったら、甘い球だけど変化球がかなりきて撃沈。

また受験をした場所が小さなパソコン教室で、周りがうるさい、計算用紙筆記用具が使いにくい、でペースを乱された（言い訳）

結果、正答率５０％で「不合格」

# 再学習
もう少し本質的な理解が必要と思い、以下の参考書を通読。

## 参考書
[中原　治　著　基礎から学ぶ統計学](https://www.yodosha.co.jp/yodobook/book/9784758121217/)
帰無仮説、一元配置分散分析など、分かってそうで分かりにくい統計知識を豊富なカラーページと現実問題に置き換えての解説が、非常にしっくり理解できる。
読み物としても、読みやすい。

## 問題集②
[日本統計学会公式認定　統計検定２級　公式問題集［CBT対応版］](https://jitsumu.hondana.jp/book/b614221.html)
CBT版じゃなかったら、という言い訳をし、この問題集を購入。
しかし、内容は問題集①の内容が再編集された感じ。（①の問題集だけでもよかったかな。。）
ただ①には掲載されていない問題もあり、最終的な微調整という意味では、意味があったかも。

ですので、再勉強でも問題集①をもう３週位しました。

# 再受験（２回目　２月下旬）合格！
前回の反省から、受験場所を変更しました。結果は、だいぶマシに受験することができました。

また、１回目を受験したから今回は正解を選べた、というところもあり２回受験したから合格できた、と言われてもしょうがない、手ごたえでした。

とはいえ、正答率が８割は言っていないので、「なんとか合格した。」という感じでした。
まだまだ勉強が必要ですね。。

今後は、Kaggleなど実践的なコーディングにも挑戦したいですね。
準１級は、まだまだ勉強して理解できる気がしないので、当分はパス。
Private Endpoint が有効な(パブリックネットワークアクセスが無効な) App Service に デプロイを行う方法　その 3

# はじめに

https://qiita.com/georgeOsdDev@github/items/1827c2a5bc15db214cff

に対する回避策 3 となります。
この記事では、Web Apps 側に zip ファイルをアップロードすることなく、src-url を指定することで、Web Apps 側 からアプリケーションコードを取得することでデプロイを実現します。

https://learn.microsoft.com/ja-jp/azure/app-service/deploy-zip?tabs=cli#deploy-a-zip-package

> Web アプリのネットワーク構成によっては、ローカル環境からサイトへの直接アクセスがブロックされる場合があります。 このシナリオでコードをデプロイするには、Web アプリからアクセス可能なストレージ システムに ZIP を公開し、Web アプリに ZIP を push するのではなく、ストレージの場所から ZIP を pull するようにアプリをトリガーするとよいでしょう。 詳細は、「本アーティクルのネットワークで保護された Web アプリへのデプロイ」を参照してください。


# 回避策

ストレージアカウント上など、URLのみでインターネット経由でアクセス可能な場所に zip ファイルを配置します。
以下のAPIを用いて、packageUriを指定します。

https://learn.microsoft.com/ja-jp/rest/api/appservice/web-apps/create-one-deploy-operation

Azure Management API の呼び出しには[az rest](https://learn.microsoft.com/ja-jp/cli/azure/reference-index?view=azure-cli-latest#az-rest) コマンドを利用します。

az rest コマンドは Management API を呼び出す場合の認証の手間がかなり楽になるので覚えておくと便利です。


```bash
az storage blob upload --account-name $STORAGE_ACCOUNT -c $CONTAINER -f app.zip
APP_URL=$(az storage blob generate-sas --full-uri --permissions r --expiry `date -u -d "10 minutes" '+%Y-%m-%dT%H:%MZ'` --account-name $STORAGE_ACCOUNT -c $CONTAINER -n app.zip | xargs)
az rest --method PUT \
        --uri https://management.azure.com/subscriptions/${SUBSCRIPTION}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.Web/sites/${WEBAPP}/extensions/onedeploy?api-version=2022-03-01 \
        --body '{ 
            "properties": { 
                "properties": {
                    "packageUri": "'"${APP_URL}"'"
                }, 
                "type": "zip",
            }
        }'
```


一時的に BLOB コンテナに配置する方法の詳細については、下記参考に記載のブログ記事を参照してください。

# 参考

下記ブログ記事にあるとおり、az cli では現時点(2.45.0)では、az webapp deploy --src-url を使う方法では、SCM サイトのエンドポイントが使われるため、アクセスできずにエラーとなります。
そのため、記事にあるとおり、Azure management API を利用する必要があります。

https://azure.github.io/AppService/2021/03/01/deploying-to-network-secured-sites-2.html
paizaラーニング レベルアップ問題集 DPメニュー JavaScript 最安値を達成するには 2

最安値を達成するには 2 (paizaランク B 相当)

https://paiza.jp/works/mondai/dp_primer/dp_primer_apples_step1

# 解答例
とりあえず、うまくいかないところも含めて、最小値を求める。
dpの初期値は、n個以上買う時はn+5個で十分、最小値を求めるので、初期値は無限大。

うまくいかないところ、n個以上での最安値を埋めていく。
dp2を用意して、dpを元に作っていく。
最小値を求めるのに、dpのi以上をsliceしてreduceを用いた。
```javascript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");

const [n, a, b] = lines[0].split(" ").map(Number);
//とりあえず、うまくいかないところも含めて、最小値を求める。
const dp = Array(n + 5).fill(Infinity);//n個以上買う時はn+5個で十分、最小値を求めるので、初期値は無限大
dp[0] = 0;//0個の時は0円
for (let i = 1; i < n + 5; i++) {
  if (i >= 2) {
    dp[i] = Math.min(dp[i], dp[i - 2] + a);
  } 
  if(i >= 5){
    dp[i] = Math.min(dp[i], dp[i - 5] + b);
  }
}
//うまくいかないところ、買い方を工夫した結果、買ったりんごが n+1 個以上になってもよい
const dp2 = Array(n + 5);// n 個以上のりんごを買うのに必要な金額の最小値の配列
for (let i = 1; i < n + 5; i++) {
  //dpのインデックスi以上での最小値
  dp2[i] = dp.slice(i).reduce((a, b) => Math.min(a, b));
}
console.log(dp2[n]);
```
dp2無しでも、dpを書き換える形でできる。前から変えていけば、後には影響が出ない。
```javascript
//うまくいかないところ、n個以上での最安値を埋めていく
// n 個以上のりんごを買うのに必要な金額の最小値
for (let i = 1; i < n + 5; i++) {
  //dpのインデックスi以上での最小値
  dp[i] = dp.slice(i).reduce((a, b) => Math.min(a, b));
}
console.log(dp[n]);
```
Azure Administrator(AZ-104)：Azure でのストレージの実装と管理「BLOBコンテナ」

Microsoft Learnを用いたMicrosoft Azure Administrator(AZ-104)の試験内容をまとめる投稿です。
この投稿ではMicrosoft Learnで学ぶ内容をできるだけ簡潔にまとめております。
Azureの勉強を一から始め、AZ-900取得後の資格としてAZ-104取得を目指している方の参考になれば幸いです。
※AZ-900の内容は本投稿では省略しております。再度復習したい方は下記をご参照ください。
[Azure Fundamentals(AZ-900)：試験合格に向けた学習内容のまとめ](https://qiita.com/fsd-jume/items/e4ec76959adb547ac5e8)

## 今回の学習内容
**◆「BLOBコンテナ」**
◇対応するMicrosoft Learn ラーニングパス
[AZ-104:Azure でのストレージの実装と管理](https://learn.microsoft.com/ja-jp/training/paths/az-104-manage-storage/)
◇対応するモジュール
[BLOB コンテナーを作成する](https://learn.microsoft.com/ja-jp/training/modules/configure-blob-storage/3-create-blob-containers)

※前回の投稿は下記から確認できます。
[Azure Administrator(AZ-104)：Azure でのストレージの実装と管理「Azure Blob Storage」](https://qiita.com/fsd-jume/items/568c5ce5379e1be718f7)

## BLOBコンテナ
### コンテナとBLOBの構成に関する特性
・すべてのBLOBはいずれかのコンテナに必ず存在
・1つのストレージアカウントに含めることができるコンテナの数：無制限
・1つのコンテナに格納できるBLOBの数：無制限
・コンテナはAzure Portalでも作成可能

### コンテナの構成(設定内容)
**◆名前**
・コンテナ名はストレージアカウント内で一意である必要あり
⇒コンテナ/BLOBアドレスを指定する際に使用するURIの一部になるため
※URI：Uniform Resource Identifier
・コンテナ名の規則
　-長さは3～63文字まで
　-英小文字/数字/ダッシュ(-)文字のみ使用可能
　-先頭は英文字/数字
　-2つ以上の連続するダッシュ(-)文字は不可

**◆パブリックアクセスレベル**
・コンテナ/BLOBへのパブリックアクセス可否を指定
※ストレージアカウントでもパブリックアクセス可否を設定可能
　-非公開(既定)：コンテナ/BLOBへのパブリックアクセス禁止
　-BLOB：BLOBに対してのみパブリック読み取りアクセスを許可
　-コンテナ：BLOB/コンテナ全体へのパブリック読み取りアクセスを許可

## 次の学習内容
**◆BLOBアクセス層**

https://qiita.com/fsd-jume/items/fbb890c5802d71a98066

## 学習内容をまとめたページの一覧

https://qiita.com/fsd-jume/items/6eda24728c9c03c36bc3
mplfinanceを使って株や仮想通貨のロウソク足を表示させる

# ■ 概要
mplfinanceという株価や仮想通貨のチャートを表示できるツールを使い、ローソク足を表示させる。

一連のコードは↓

https://github.com/xx-z/cryptocurrency-analysis/blob/master/mplfinance.ipynb

# ■ 環境
mplfinance : 0.12.9b7
pandas : 1.3.5

# ■ 実装
## (1) データ収集
前回の記事と同様にyfinanceでビットコインのデータを収集しました。
データの詳細としては、2022年の日足のデータを収集しました。
```
!pip install yfinance
```
```python
#yfinanceとpandasをインポート
import yfinance as yf
import pandas as pd

#取得するデータ詳細
name = 'BTC-USD'
start = '2022-01-01'
end = '2022-12-31'

#データのダウンロード
df = yf.download(tickers=name, start=start, end=end)
df.head()
```
詳しくは前回の記事をご覧ください。

https://qiita.com/__x__/items/6af051cb6b4017a52bd5

## ( 2 ) mplfinanceをインストールする
```
!pip install mplfinance
```

## ( 3 ) 簡単なロウソク足を表示する
```python
import mplfinance as mpf

mpf.plot(df, type="candle", figratio = (3, 2), volume=True, style="yahoo")
```
<img width="400" alt="mplfinance_1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1582644/98fb38b3-1399-2ed8-f35d-93e174856405.png">

● type : グラフの種類
　candle(ロウソク足), line(折れ線グラフ), renko(練行足), pnf(ポイント&フィギュア)
● figratio : 表示サイズを変える
● volume : 出来高の表示
● style : グラフのスタイル（色など）
　binance, blueskies, brasil, charles, checkers, classic, default, ibd, kenan, mike, nightclouds, sas, starsandstripes, yahoo

## ( 4 ) 時間指定してみる
datetimeを使用して時間指定を行う。
```python
import datetime as dt

df_r = df[dt.datetime(2022, 10, 1):dt.datetime(2022, 11, 1)]
mpf.plot(df_r, type="candle", figratio = (3, 2), volume=True, style="yahoo")
```
<img width="400" alt="mplfinance_2" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1582644/09982608-151f-d667-f273-a2e9b7024065.png">


他の指定方法として
```python
#2022年10月1日〜
df_r = df[dt.datetime(2022, 10, 1):]
#〜2022年2月1日
df_r = df[:dt.datetime(2022, 2, 1)]

#前から100日分
df_r = df.head(100)
#後ろから100日分
df_r = df.tail(100)
```


# ■ 参考文献
https://github.com/matplotlib/mplfinance/wiki
Teams上のExcelファイルをPower BI Desktopで開く


`Power BI Desktop`を使ってレポートを作成する際に、Teams上のExcelなどExcel Onlineのファイルはパスが取得できないと思い込んでたのですが、先日マイクロソフトサポートの方に教えていただいたので共有します。


取り込み方法としては、こんなフローです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885406/4bd4eba8-16ee-1495-d310-8d8080d2d0a0.png)


# Teams上で共有されているEXCELのパスを取得する
Teams上のEXCELファイルを開いて編集ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885406/6429bb28-66cd-4e6e-a36e-4fe257bf1815.png)

その後、選択画面が出てくるので、「Excelで開く」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885406/0271e788-853a-7c2b-b55a-f3a9ddd9ec26.png)

EXCELファイルを開いたら「情報」⇒「パスのコピー」を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885406/d4a0185b-677c-9e1c-8964-4a004ea76def.png)
Webサイト上のURLが取得できるので、これをテキストファイルにはってメモしておきます。

# Power BI Desktopでファイルを読み込む
まず、Power BI Desktopアプリを立ち上げて、データを取得⇒Webを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885406/c50168b9-72e7-da9f-af1b-1565cd1b0e1b.png)
指定するとポップアップ画面が開くので、ここに先ほどメモしたURLを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885406/9d0b669f-988e-63f8-9516-2ff3393a2f3c.png)

入力する際に、末尾のパラメータ`?web=1`は不要なので消します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885406/172f03ec-9ba0-f95b-3825-93bf849fee14.png)

すると、ファイルがバッチリ読めてます！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885406/72f091ff-77fb-4e27-9146-d9910b38620f.png)

# まとめ
Teams上のEXCELファイルは、チーム内で共有されたファイルなので無料版のPower BI Desktopではファイルを読むことができないと思ってました。
（これまで自分が試した方法は、データ取得時にSharepointリストや Sharepoint Onlineリストからパスを読み込もうとしていましたが、どれもエラーになっていたためPower BI Serviceを使わないと無理なのかなと思っていました。）
今回、ちょっと裏技チックな内容をヒアリングできて得した気分でした。
読み込む手順が若干面倒ではありますが、知っててお得なスキルだと思いますのでぜひご活用ください。
mlflow.log_artifactでエラーが出る


`mlflow ui`コマンドで，デフォルトの`127.0.0.1:5000`にMLFlowを起動して，`mlflow.log_artifact()`を実行したらエラーが吐かれた．
```
raise MlflowException(
mlflow.exceptions.MlflowException: The configured tracking uri scheme: 'file' is invalid for use with the proxy mlflow-artifact scheme. The allowed tracking schemes are: {'https', 'http'}
```
社内のPCで作業しているのでproxyを踏んでしまっているのか詳細は不明だが，tracking_uriを指定すれば解決した．

```python
mlflow.set_tracking_uri("http://127.0.0.1:5000")
ChatGPT APIをSwiftで使ってみる。

## はじめに
最近、ChatGPT APIがリリースされたので、さっそく使ってみました。

今回リリースされたモデルは、以前のGPT-3.5系のモデルよりも1/10のコストで利用できるみたいです。
以下、Introducing ChatGPT and Whisper APIsより。
> The ChatGPT model family we are releasing today, gpt-3.5-turbo, is the same model used in the ChatGPT product. It is priced at $0.002 per 1k tokens, which is 10x cheaper than our existing GPT-3.5 models. 

[前回](https://qiita.com/district_13_bm/items/c8f4af7ef3065b14780d)は`text-davinci-003`を利用したChatGPTライクな音声対話アプリを作ったのですが、今回はChatGPTに搭載されている言語モデルの`gpt-3.5-turbo`を利用したサンプルアプリを作ってみます。

サンプルアプリはGitHubに公開していますので、興味ある方はご覧ください。

## サンプルアプリ
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655077/d23b6b84-9c1d-d232-e40e-54aba02ebb6d.gif" width="300">

## GitHub
https://github.com/mlballack/ChatGPTAPISampleiOSApp

## ChatGPT APIの実装
まず、Alamofireを利用してChatGPT APIと連携します。（OpenAISwiftに`gpt-3.5-turbo`のモデル選択が見当たらず、Alamofireで実装しています。）

[公式ドキュメント](https://platform.openai.com/docs/guides/chat/introduction)のリクエストのフォーマット通りに、Alamofireでパラメータ設定を行います。

```swift
let headers: HTTPHeaders = [
    "Content-type": "application/json",
    "Authorization":"Bearer \(token)" // OpenAIのAPI_KEYを指定
]

let parameters: [String: Any] = [
    "model": "gpt-3.5-turbo",
    "messages": messages
]

AF.request(
    "https://api.openai.com/v1/chat/completions",
    method: .post,
    parameters: parameters,
    encoding: JSONEncoding.default,
    headers: headers
).responseData(completionHandler: { response in
    switch response.result {
    case .success(let data):
        // 成功後の処理
        break
    case .failure(let error):
        // 失敗後の処理
        break
    }
})
```
parameters内の`model`には、`gpt-3.5-turbo`を、`messages`には、roleとcontentからなるmessageオブジェクトの配列を渡します。roleは`user`, `system`, `assistant`のいずれかを指定します。

実際に以下のような例を考えると、
```
チャットの例
user: こんにちは。
assistant: こんにちは。
user: Swiftについて教えて。
```
messagesは以下のように記述されます。
```swift
let messages = [
    ["role": "user", "content":"こんにちは。"],
    ["role": "assistant", "content":"こんにちは。"],
    ["role": "user", "content":"Swiftについて教えて。"]
]
```
さらに次のように、`system`を指定することで、アシスタントのふるまいを設定することも可能なようです。以下の例では、アシスタントに「人間と会話するチャットボット」のように振る舞ってもらえるはずです。
```swift
let messages = [
    ["role": "system", "content":"あなたは人間と会話するチャットボットです。"],
    ["role": "user", "content":"こんにちは。"],
    ["role": "assistant", "content":"こんにちは。"]
]
```
上記のように、アシスタントとユーザーの会話の履歴ごと、APIに渡すことで、アシスタントと会話を続けることが可能になります。会話の履歴がないとsingle-turnな単調な一問一答になります。

## 最後に
今回は、ChatGPT APIを使ってサンプルアプリを作ってみました。

最近、ChatGPTをよく使いますが本当に便利ですね。ただChatGPTをより良く使うには、使う側の能力（適切な質問を行うなど）も重要だなと実感しています。最近では、[Prompt Engineering](https://note.com/sangmin/n/n170bdfd624bc)といった言葉も耳にしますし。
私は質問を考えるのに時間がかかるので、ChatGPTへの質問を考えるAIみたいなのもあれば嬉しいですね。

Whisper APIもリリースされたので、そっちも使ってみようと思います。

## 参考URL
- [Introducing ChatGPT and Whisper APIs](https://openai.com/blog/introducing-chatgpt-and-whisper-apis)
- [ChatGPT APIを使ってAIキャラクターを作ってみる！](https://qiita.com/sakasegawa/items/db2cff79bd14faf2c8e0)
- [Multi-turn conversations: What are they, and why do they matter for your customers?](https://poly.ai/multi-turn-conversations-what-are-they-and-why-do-they-matter-for-your-customers/)
- [これから、"Prompt Engineering"の話をします…](https://note.com/sangmin/n/n170bdfd624bc)
Uncaught (in promise) RangeError: Maximum call stack size exceeded

### vee-validateのバージョンが最新だと起こるエラーだった

### 解決策
いつも通りnode_modules吹き飛ばして
```
rm -r node_modules/
rm package-lock.json
```

packcage.josnでvee-validateバージョン指定
```
"vee-validate": "~4.5"
```

再度インストール
```
npm install
```
4.5まで下げたら起こらなくなった。
laravelにあるEloquentのwith関数を使ってみる

## はじめに
リレーションの関係にある親モデルと子モデルのデータを一度に取得したいと考え、`with関数`にたどり着く。
これまで使ってこなかったのでどのような関数なのか理解するためにまとめていく。

## 前提(モデル定義)
親モデル(User)と子モデル(UserCourse)は以下のようにリレーション関係にある。
```Controller.php
class User extends Model
{
    public function userCourses()
    {
        return $this->hasMany(UserCourse::class);
    }
}

class UserCourse extends Model
{
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

```

### with関数を使ってみる
with関数を使用して、UserモデルとUserCourseモデルを一度に取得する場合は、以下のように書く。
```
$users = User::with('userCourses')->get();
```

これにより、Userモデルのインスタンスが取得され、各UserインスタンスにはuserCoursesリレーションに関連するUserCourseモデルのインスタンスが含まる。

また下記のように1件だけ取ってくるなども可能。
```
$user = User::with('userCourses')->find($id);
```

以上。
ROS2 パッケージ作成

# ROS2 パッケージ作成
今回はROS2におけるワークフォルダの作成とパッケージの作成を行う。

## ワークスペースとパッケージの作成
まずはワークスペースの作り方だが、ここはUnixのコマンドそのままである。
今回はtutorial_wsという名前にしたがわかりやすい名前なら何でも良い。最後にワークスペースであることがわかるように_wsと付けることを推奨する。
```
    mkdir -p tutorial_ws/src
    cd tutorial_ws
```
構文の説明を軽くすると、`mkdir`はディレクトリの作成。`-p`は`mkdir`のオプション引数であり、必要となる親ディレクトリの作成も行わせるというコマンドである。
なので、やっていることは
```
    mkdir tutorial_ws
    cd tutorial_ws
    mkdir src    
```
と一緒だが、面倒なので上記のように記述されることが多々ある。
`ls`コマンドで確認すると、srcディレクトリが存在する。
以下のようにディレクトリが構成される。
- tutorial_ws
    - src

続いて、パッケージの作成に移る。
```
    source /opt/ros/foxy/setup.bash
    cd src
    ros2 pkg create --build-type ament_python tutorial_package
```
1行目については、後述の注意を参照して欲しい。
srcディレクトリにて
3行目のコマンドを実行してtutorial_packageを作成する。pythonを用いてコーディングする際は、`ament_python`を使用する。
最後の第5変数に作成するパッケージ名を入力する。
実行すると、srcディレクトリにtutorial_packageが作成され、tutorial_packageを確認すると以下のようになっている。
- tutorial_package
    - package.xml
    - resource
    - setup.cfg
    - setup.py
    - test
    - tutorial_package ←ココ
今後、pythonでコーディングを行う際は、src/turorial_package/tutorial_packageディレクトリにプログラミングしていくことになる。

## ビルド
作成したROSパッケージを利用するには、ws全体をビルドする必要がある。
```
    cd ~/tutorial_ws
    colcon build
```
`Summary: 1 package finished [0.79s]`と表示されればビルド完了である。
ビルド後に`ls`コマンドでワークスペースを確認すると
- build
- install
- log
- src
4つのディレクトリが存在する。
また、ビルド後はワークスペースの環境変数が変化するので、
```
    . install/setup.bash
```
を入力して、ワークスペースとターミナルを再設定する。

## 注意
新しいターミナルを開いた際には毎回使用するワークスペースにて
```
    source /opt/ros/foxy/setup.bash
```
上記のコマンドを入力する必要がある。
これは現在使用しているターミナルにROS2のワークスペースであることを認識させるための作業である。
初めのうちは、よくこれを忘れていてエラーを起こすので注意しよう。

## 参考文献
科学情報出版株式会社 『ロボットプログラミング ROS2の実装・実践』-実用ロボットの開発- 日本大学 内木場 文男[著]
第4章 ROS2のプログラミング P.34-P.36
Go言語で重複する要素を取り除く方法

### はじめに
Go言語での重複処理ってどうやって書くんだろう？！ということで調べてみました。
1つの配列、2つの配列の比較でコードを書いてみる。

### 1つの配列の中での重複処理の場合
下記のようなコードがあった場合の重複処理の流れをGo言語で説明します。
重複しているのは`abc123`の値です。

```go
userIDs := []string{"abc123", "def456", "ghi789", "abc123"}
userIDsMap := make(map[string]bool)
uniqUserIDs := [] string{}

for _, id := range userIDs {
    if !userIDsMap[id] {
        userIDsMap[id] = true
        uniqUserIDs = append(uniqUserIDs, id)
    }
}

fmt.Printf("%v", uniqUserIDs) // ["abc123", "def456", "ghi789"]
```

### 配列2つの比較して重複処理をする場合
下記のようなコードがあった場合の重複処理の流れをGo言語で説明します。
重複しているのは`abc123`の値です。

このコードでは、重複を除いた要素をマップに格納することができます。
これは、マップのキーに同じ値を2回追加しようとする場合、最初のキーの値が上書きされるためです。マップは、キーがユニークである必要があるため、同じキーを2度追加することはできません。

```go
userIDs := []string{"abc123", "def456", "ghi789", "abc123"}
chatIDs := []string{"jkl012", "mno345", "abc123", "pqr678"}

chatIDMap := make(map[string]bool)
for _, userID := range userIDs {
    chatIDMap[userID] = true
}
for _, chatID := range chatIDs {
    chatIDMap[chatID] = true
}

chatIDList := make([]string, 0, len(chatIDMap))
for chatID := range chatIDMap {
    chatIDList = append(chatIDList, chatID)
}

for chatID := range chatIDMap {
    fmt.Printf("chatIDMap: %s\n", chatID)
}
```

出力結果は以下のようになります。

```go
chatIDMap: abc123
chatIDMap: def456
chatIDMap: ghi789
chatIDMap: jkl012
chatIDMap: mno345
chatIDMap: pqr678
```
`abc123` という要素が `userIDs` と `chatIDs` の両方に含まれているため、重複しています。
しかし、`chatIDMap` では、 `abc123` のキーは1つだけであり、それに対応する値は `true` となっています。
重複した要素が除外され、ユニークな要素のみがマップに格納されることになります。
has_many :through 関連付け

```rb
class Physician < ApplicationRecord
  has_many :appointments
  has_many :patients, through: :appointments
end

class Appointment < ApplicationRecord
  belongs_to :physician
  belongs_to :patient
end

class Patient < ApplicationRecord
  has_many :appointments
  has_many :physicians, through: :appointments
end
```
has_many :through関連付けは、```他方のモデルと「多対多」のつながりを設定```する場合によく使われます。

この関連付けでは、```2つのモデルの間に「第3のモデル」（joinモデル）が介在し、それを経由（through）して相手のモデルの「0個以上」のインスタンスとマッチ```します

## 多対多の問題点
両者のエンティティが共通キーとなる列を保持していないため、両エンティティを結合した情報を得ることができない。

## 出典
https://www.shoeisha.co.jp/book/detail/9784798124704

## 関連付けで他のモデルも呼び出すことができる。
through: :sectionsを指定することにより、Railsは以下の文を理解できるようになります。
```rb
@document.paragraphs
```
## 出典
https://railsguides.jp/association_basics.html#has-many%E9%96%A2%E9%80%A3%E4%BB%98%E3%81%91:~:text=2.4%20has_many%20%3Athrough%E9%96%A2%E9%80%A3%E4%BB%98%E3%81%91

### 気づき
関連実態を設けることで他のモデルを呼ぶことができるのか。

```rb
class Physician < ApplicationRecord
  has_many :appointments
  has_many :patients, through: :appointments
end

class Appointment < ApplicationRecord
  belongs_to :physician
  belongs_to :patient
end

class Patient < ApplicationRecord
  has_many :appointments
  has_many :physicians, through: :appointments
end
```
```through:```を設定することで関連実態を設定できる。

# 感想
まだまだ気づけていないことが多そうだ。
実践しつつ学んでいきたい。
tableの中のテキストをスクロールバーなしでスクロールする方法(マウスでドラッグするとすべてのテキストが見える)

## tableで文字があふれるのをなんとかしたい

tableで想定しているサイズから文字があふれる場合、

overflow: scroll;
overflow: hidden;
overflow: scroll;

による対処だったり、white-space: nowrap;を指定せずに改行させる対処法だったりがあるかと思います。

それらの対処法以外でサイズ内に収めつつ、テキストをドラッグすることにより表示可能とする方法です。
↓のResultでテキストが切れている箇所を右にドラッグしてください。テキストがカットされておらず、すべて表示&選択可能です。


<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="xxaqJgG" data-user="taole33" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/taole33/pen/xxaqJgG">
  Untitled</a> by Shirai (<a href="https://codepen.io/taole33">@taole33</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>


## なにをやっているか
結果だけ得たい方は↑のhtmlとcssをパクってコピれば大丈夫と思います。
が、それぞれの記述でなにをやってるか知りたい方はこのまま読み進めてください。
やっていることは「スクロールバーなしでスクロールする」です

table下のtdにcssを適用しています。
```
.scroll-but-notscrollbar td {
    overflow: scroll;
    white-space: nowrap;
    scrollbar-width: none;
    -ms-overflow-style: none;
  }
```

↓改行ナシとしています
```
white-space: nowrap;
```

↓スクロールあり。このままだとスクロールバーが表示されてしまう。
```
overflow: scroll;
```

↓スクロールバーを消しています。ブラウザによりスクロールバーを消す方法が違うので、ブラウザ毎に記述が必要です。
```
  -ms-overflow-style: none; /* IE対応 */
   scrollbar-width: none; /* Firefox 対応 */


  .scroll-but-notscrollbar td::-webkit-scrollbar {
    display: none;　/* Chrome, Safari,Edge対応 */
  }
```
kroki.ioを用いてダイアログを図形データに変換するモジュール

pythonで標記のモジュールを作成した。

図形データをsvgやpngなどにした場合に、Jupyter上で変換結果を表示する際の処理を共通化するため、そのための前処理も行うものとしている。

### [kroki.io](https://kroki.io/)とは
各種のダイアログを同じAPIで図形データに変換するもの。本家のフリーサービスを用いる他、独自のサーバー上で動かすことも可能。

# 必要モジュール
下記のモジュールが必要ゆえ、インストールしていないならば、pipコマンドなどでインストールする。

# コード
```python
import requests

from IPython.display import SVG
from IPython.display import Image

def kroki(diagram, diagram_type, output_format="png", url="https://kroki.io"):
    """ ダイアグラムを図形データに変換する
    Args:
        diagram (str) : ダイアグラムを定義した文字列
        diagram_type (str) : ダイアグラムのタイプ("mermaid", "graphviz", "plantuml"など)
            指定できる値はhttps://kroki.io/examples.htmlを参照のこと
            (ダイアグラムのタイプを指定する文字列としてURLに含める文字列をこの引数に指定のこと)
        output_format (str) : 出力データのフォーマット
        url (str) : kroki webサーバーのurl
            独自サーバーを用いる場合以外は省略可
    Return:
        data : 図形データのバイナリーデータ
        img : jupyter 上に図形を表示するためのオブジェクト
              displya(img)とすることで、jupyter上で表示される
    """
            
    res = requests.post(
        url=f"{url}/{diagram_type.lower()}/{output_format.lower()}",
        headers = {'content-type': 'text/plain'},
        data=diagram
    )
    data=res.content
    if output_format == "svg":
        img = SVG(data=data)
    else:
        img = Image(data=data)
    return data,img
```

### 使用例
以下は、jupyter上での実行例

```python
diagram = """
digraph G {
  Hello->World
}
"""

data,img=kroki(diagram, "graphviz", "svg")
display(img)
```

![img](https://kroki.io/graphviz/svg/eNpTUFBQSMlML0osyFBwV6jmUgADj9ScnHxdu_D8opwUsFAtANc1Cpo=)
WooCommerceの商品追加をプログラムから行う

# なにこれ
WooCommerceの商品追加をプログラムから動的に行いたい時にどうすればよいのかについて書いたもの
バリエーションのある商品を対象とする。

そのメモ

# コード（結論）

```php

// 新しい可変商品を作成
$product = new WC_Product_Variable();

// 商品情報を設定
$product->set_name( '可変商品名' ); // 商品名を設定
$product->set_description( '商品説明' ); // 商品説明を設定
$product->set_regular_price( '1000' ); // 通常価格を設定
$product->set_status( 'publish' ); // 公開状態を設定

// 商品バリエーションを作成
$attribute1 = new WC_Product_Attribute();
$attribute1->set_name( 'color' );
$attribute1->set_options( array( 'red', 'green', 'blue' ) );
$attribute1->set_visible( true ); // フロントエンドで表示するかどうか
$attribute1->set_variation( true ); // バリエーションで使用するかどうか

$attribute2 = new WC_Product_Attribute();
$attribute2->set_name( 'size' );
$attribute2->set_options( array( 'small', 'medium', 'large' ) );
$attribute2->set_visible( true ); // フロントエンドで表示するかどうか
$attribute2->set_variation( true ); // バリエーションで使用するかどうか

$product->set_attributes( array( $attribute1, $attribute2 ) ); // 属性を設定

// 商品の保存、商品IDの取得
$product_id = $product->save();

// 商品バリエーションを追加
$variation = new WC_Product_Variation();
$variation->set_attributes( array(
    'color' => 'red',
    'size' => 'small'
) ); // 属性を設定
$variation->set_regular_price( '1100' ); // 通常価格を設定
$variation->set_parent_id( $product_id  ); // 商品との紐づけ
$variation->save();

// 商品の更新
$product->save();

```

# 手順とか
* 商品を登録する
* バリエーションで利用する属性を追加する
* 属性で定義したものをキーにバリエーションを作成する
* 作成したバリエーションと商品ID（post_id）を紐づける

# 気になるところ
既存の属性を利用する場合はどうすればいいのか？
多分WC_Product_Attributeのインスタンスを作るときにID指定すればいいんじゃなかろうかと思うがまだ試していない。
CodeBuildが”BUILD_TIMED_OUT: Build has timed out.”でエラーになる

## これは何？
CodeBuild のトラブルシューティングメモ。

## 環境について
```
Github -> CodePipeline -> CodeBuild -> EFS
```
Github へのプッシュイベントを受けて CodePipeline が着火。
CodeBuild にてビルド後、 EFS へデプロイする構成。

## 事象
CodeBuild のビルドが ```BUILD_TIMED_OUT: Build has timed out.```のエラーになる。（問題なくビルドが動いていた環境で突如エラーが出るようになった。）

＜エラー時のスクリーンショット＞
![9ee8110b-3556-46f2-9114-493f0b8ac7b9-960x461r.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1287372/838520ae-04dd-01b9-c42f-1a258aab98e8.png)


＜確認したポイント＞
- CodeBuild の構成変更はしておらず、S3 からダウンロードするソースアーティファクトのサイズも成功していたビルドと大差なし。

- IAM や S3 といったポリシー周りの設定変更もなかった。

## 原因
結論としては、原因不明で調査終了。

原因の切り分け作業中に何故か復旧した。
AWS サポートに障害情報を確認したが特に障害は発生していないということで、
これ以上の調査は難しいということになり調査は打ち切りられた。

## CodeBuild のトラブルシューティング
迷宮入りしてしまったが CodeBuild のトラブルシューティングで何をやったのかメモとして残しておく。

#### 1. ビルドのタイムアウトを10分などに伸ばしてビルドを実行する
ビルドタイムアウトの時間がデフォルトの「5分」で設定されていた。
エラーメッセージ的にタイムアウトのエラーであった為、一時的にプロジェクトのタイムアウトの時間を「10分」などでビルドする。

#### 2.エラーになったソースアーティファクトを使用してビルドを実行する
Github のコードが関連するかの切り分け。

CodeBuild のデバッグとして、「高度なビルドの上書き」が可能なのでこれを使う。
対象プロジェクトを選択後、「上書きビルドで開始する」->「高度なビルドの上書き」からソースプロバイダーを選択可能。
エラーになったビルドのソースアーティファクトを指定してビルドする。

#### 3.CodeBuild から S3 をソースプロバイダとしてビルドを実行する
CodePipeline からの実行が起因するかの切り分け。
また、Github のソースコードに原因があるかの切り分けのために Github のソースコードを利用せず、別途事前にサンプルファイルを S3 に ZIP をアップロードし、「高度なビルドの上書き」にてビルド可能か試す。

#### 4.ソースプロバイダーで「ソースがありません」を指定してビルドする
S3 への接続による問題かの切り分け。
「上書きビルドで開始する」->「高度なビルドの上書き」によってソースプロバイダーが選択できますのでこちらで「ソースがありません」を選択可能。
buidspec.ymlの指定が出来ないので「ビルドコマンドの挿入」で適当なOSコマンドを指定してビルド実行。

#### 5.CodeBuild プロジェクトから一度 EFS の設定を外してビルドする
EFS との接続の問題がある場合、DOWNLOAD_SOURCE にてエラーになることがあるとのこと。（AWS サポートの回答より）
> 現時点の動きでは DOWNLOAD_SOURCE フェーズにて EFS のマウント処理が実施されます。
> 例えば EFS 側のセキュリティグループのインバウンドが許可されていない場合、DOWNLOAD_SOURCE フェーズにて「CLIENT_ERROR: mounting '127.0.0.1:/' failed. connection reset by peer」というエラーになり、ビルドが失敗します。
> 今回のエラーはタイムアウトであり上記とは異なりますが、DOWNLOAD_SOURCE フェーズにて EFS のマウント処理が行われる為、DOWNLOAD_SOURCE フェーズにて問題が発生した場合には切り分けの一つとして EFS の確認を行う方法は有効であると考えております。

一度 EFS の設定を外して EFS が起因するかの切り分ける。
「高度なビルドの上書き」では EFS の設定解除がない為、一時的に EFS の設定を CodeBuild プロジェクトから解除してからビルドする。

以上