OmniAICreator/Qiita-1.07M huggingface dataset:
IAMユーザーで請求ダッシュボードを閲覧できるようにするには

IAMユーザーでAWS請求ダッシュボードを閲覧する方法について、自身の備忘録も兼ねて載せておきたいと思います。

#事象：IAMユーザーで請求ダッシュボードの閲覧ができない

画面右上のアカウント名をクリックし、「請求ダッシュボード」を押すと・・・。
![WS000000.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/714364af-617f-17b0-bedb-0b3b8d11a51c.jpeg)

「アクセス権限が必要です。」とメッセージが出力される。
うーむ、どうやら権限設定が必要のようだ。
![WS000001.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/9bbf66b5-f8da-df1d-d8c6-45db7d23b60a.jpeg)

#閲覧ポリシーの割り当て
まずは閲覧ポリシーの割り当てを行ってみる。
Aministrator権限のあるユーザーにてログイン後、IAMユーザーのマネジメントコンソールの左ペインから「ユーザー」をクリックし、閲覧権限を与えたいユーザーを選択する。
![WS000002.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/65fe7bfa-8232-1dad-7cab-1fffe439e6b8.jpeg)

「アクセス権限」タブを選択後、「アクセス権限の追加」をクリックする。
![WS000003.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/6cc7057b-a010-3fe9-c944-13c8c1e5bc20.jpeg)

画面遷移後、「既存のポリシーを直接アタッチ」をクリックし、アタッチするポリシーを選ぶ。
今回は請求ダッシュボードの閲覧のみを行えるようにしたいので、「AWSBillingReadOnlyAccess」にチェックを入れて「次のステップ：確認」をクリックする。
![WS000004.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/860878bd-4876-3180-fa21-289e4096f602.jpeg)

ポリシーの確認画面が表示されるので、問題なければ「アクセス権限の追加」をクリックする。
![WS000005.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/30ccb42a-f63c-7e1b-005d-dc04e332a468.jpeg)

画面上部に「New feature to generate a policy based on CloudTrail events.」と表示されればポリシーのアタッチは成功です。
アクセス権限タブの適用済みポリシーの中に「AWSBillingReadOnlyAccess」が追加されているはずです。
![WS000006.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/5e355658-3c73-1dbd-6065-46b282c34f9a.jpeg)

#再トライ
IAMユーザーを切り替えて、再トライ！
しかし、画面は変わらず・・・。
![WS000001.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/bd782a4d-dd8a-e997-9143-dff52eb7d760.jpeg)

#IAMアクセスのアクティブ化
どうやらrootユーザーにてIAMアクセスのアクティブ化を有効にする設定が必要らしい。
rootユーザーにてログインし直し、画面右上のアカウント名をクリックして「アカウント」を押下する。
![WS000008.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/0c2e0c99-8ce2-4979-ae61-aa0d00ba7d7b.jpeg)

アカウントページを下までスクロールすると、「IAM ユーザー/ロールによる請求情報へのアクセス」という項目があるので、「編集」をクリックする。
![WS000009.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/629682ae-841d-77c8-a676-7881fcf42681.jpeg)

「IAMアクセスのアクティブ化」のチェックボックスが現れるので、チェックを入れて「更新」ボタンをクリックする。
![WS000012.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/4b590848-d489-8ffd-99ba-9e1c8ef56747.jpeg)

「IAM ユーザー/ロールによる請求情報へのアクセスは有効になっています。」と表示されれば設定変更は成功。
![WS000013.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/7b45fcb7-95e3-bc07-1ced-45ecade2b5cd.jpeg)

##再々トライ
IAMユーザーに切り替えて、「請求ダッシュボード」を押してみる。すると・・・。
![WS000000.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/60ec03e5-4855-82e1-8719-54a64cafbc5f.jpeg)

ダッシュボードが表示されるようになりました！
![WS000014.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/c1fdfad4-d363-6856-2356-87d8cdf10497.jpeg)
【Ruby のまずいコード】文字列を文字の配列にする

# お題

文字列（例えば `"Ruby"`）を文字の配列（`["R", "u", "b" ,"y"]`）に変換してください。

# コード

```rb
str = "Ruby"

chars = str.split("")
```

# 改善

このコードはとくにまずいということはないと思いますが，この目的には専用のメソッド [String#chars](https://docs.ruby-lang.org/ja/3.0.0/method/String/i/chars.html) があるので，それを使えばいいでしょう。

```rb
str = "Ruby"

chars = str.chars
```

速度面では変わらないようです。
`chars` のメリットは簡潔なことですが，意図が分かりやすいとは言えるかと思います。
[String#split](https://docs.ruby-lang.org/ja/3.0.0/method/String/i/split.html) の仕様はかなり複雑で，筆者もその全ては記憶していません。たとえば，以下のコードで，結果をすべて正確に言えますか？（私は怪しいです）

```rb
str = "  A  B  "

p str.split      # => ["A", "B"]
p str.split("")  # => [" ", " ", "A", " ", " ", "B", " ", " "]
p str.split(" ") # => ["A", "B"]
p str.split(nil) # => ["A", "B"]
$; = "A"
p str.split      # => ["  ", "  B  "]
p str.split(nil) # => ["  ", "  B  "]
```
Goで2つの日付間の日数を取得する

## 概要
2つの日付間の日数を取得する処理を書く機会があったので備忘録的に書き残します。

## 実装
```main.go
package main

import (
	"fmt"
	"time"
)

func main() {
	start := time.Date(2021, 12, 28, 0, 0, 0, 0, time.Local)
	end := time.Date(2022, 1, 2, 0, 0, 0, 0, time.Local)
	// 日付間の日数を取得
	diffDays := end.Sub(start).Hours() / 24
	fmt.Println(diffDays)

	// 日数分処理を行う
	for i := 0; i <= int(diffDays); i++ {
		addDate := start.AddDate(0, 0, i)
		fmt.Println(addDate)
		// ...処理
	}
}
```

↑を実行すると出力結果は以下のようになります。

```text
5
2021-12-28 00:00:00 +0000 UTC
2021-12-29 00:00:00 +0000 UTC
2021-12-30 00:00:00 +0000 UTC
2021-12-31 00:00:00 +0000 UTC
2022-01-01 00:00:00 +0000 UTC
2022-01-02 00:00:00 +0000 UTC
```


### 解説
まず、 `end.Sub(start)`で２つの日付の差分を取得します。
`Sub`メソッドの定義は以下のようになっていて、Duration型が返ってきます。

```go
func (t Time) Sub(u Time) Duration
```

Durationの定義はint64のエイリアス型になっていて、時間を取得する`Hours()`メソッドが定義されています。

```go
type Duration int64

func (d Duration) Hours() float64
```

`Hours()`メソッドで取得した時間を1日の時間(=24)で割ってあげれば差の日数が取得できます。

```go
end.Sub(start).Hours() / 24
```

## 参考
https://pkg.go.dev/time#Time.Sub
https://pkg.go.dev/time#Duration
https://pkg.go.dev/time#Duration.Hours
f.selectへのclassに苦労した件

# 今回はf.selectにBootstrapを当てる際に苦労したので短いですが備忘録として書いていきます！
使っている環境
- Vscode
- Rails 5.2.6
- ruby 2.6.6
## 目次
- [初めに](#初めに)
- [やりたかった事](#やりたかった事)
- [このコードで苦戦しました](#苦戦したコード)
- [どうしたらうまくいったか](#こうしたら上手くいきました)
- [最後に](#最後に)

## 初めに
- 何か不手際などあればご指摘いただけるとありがたいです。🙇

## やりたかった事
セレクトタグのフォームを整えたかった。

## 苦戦したコード
```
<%= f.select :amount, [[1, 1], ["2", 2]], include_blank: "個数選択", class: 'form-control' %>
``` 
まず以下の記事などを参考にしたときHTMLオプションは第四引数に書けばいいのかと思っていました。しかし、なーぜかうまくいかない.....

### 参考
[【Rails】完全理解 formでセレクトボックスをつくるselectの使い方](https://310nae.com/rails-selectbox/#:~:text=user_id%22%2C%20class%3A%20%22user_class%22%20%7D%20%25%3E-,HTML%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3%20OK%E4%BE%8B,-%3C%25%3D%20form.select%20%3Auser_id)（参照日時2021/11/21）
 [railsでBootstrapのselectタグのCSSを使う](http://www2.trip-mania.jp/papers?tag=Bootstrap)（参照日時2021/11/21）



## こうしたら上手くいきました

```
<%= f.select :amount, [[1, 1], ["2", 2]], {include_blank: "個数選択"}, class: 'form-control' %>
```
参考記事にもあったのですが、空じゃなくても第三引数のは｛｝必要なんですね！コードは正直です（泣）💦

## 最後に
 これに限らず、活用しきれてないメソッドがまだまだあるはずなので、頑張っていきたいと思います！
STM32L010とHT16K33(I2C)でLチカ HAL(VSCのcubeIED)


1.SCLとSDAを接続、プルアップも忘れずに
2.電源の接続
3.下記のソースコードを書き込む
4.コンパイル実行で表示されたら終了
5.おわり

注意
VSCは、難しい(省略)

目的
I2Cのテスト

nu_l010_i2c_1内をいろいろ適当にコピー


https://os.mbed.com/users/caa45040/code/f303_h_p1/



主なソース



```c++



int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */

#define ADDR        (0x70<<1)  //  address

    uint8_t buf[16];

    buf[0]=0x21;
    HAL_I2C_Master_Transmit(&hi2c1, ADDR, buf, 1, 3000);HAL_Delay(1);

    buf[0]=0x81;
    HAL_I2C_Master_Transmit(&hi2c1, ADDR, buf, 1, 3000);HAL_Delay(1);

    buf[0]=0xef;
    HAL_I2C_Master_Transmit(&hi2c1, ADDR, buf, 1, 3000);HAL_Delay(1);

    for(int ii=0;ii<16;ii++){
        buf[0]=ii;
        buf[1]=0x00;
        HAL_I2C_Master_Transmit(&hi2c1, ADDR, buf, 2, 3000);HAL_Delay(1);
    }//for



  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */



    while(1) {

        

            buf[0]=0;
            buf[1]=1;
            HAL_I2C_Master_Transmit(&hi2c1, ADDR, buf, 2, 3000);HAL_Delay(600);

            buf[0]=0;
            buf[1]=0;
            HAL_I2C_Master_Transmit(&hi2c1, ADDR, buf, 2, 3000);HAL_Delay(600);


        
    }//while



    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}






```
プロジェクトのスクリーンショットを表示する

プロジェクトページのリンクをHTMLやブログに貼り付けても単にリンクが表示されるだけで、どんな画面のプロジェクトなのかわかりません。
実はScratchには（おそらく非公式ですが）、プロジェクトのスクリーンショットの画像へのリンクが用意されています。具体的には以下のリンクになります。画像サイズは横幅と縦幅で設定できることができますが、おおよそ3:2にすると良さそうです。

`https://cdn2.scratch.mit.edu/get_image/project/(プロジェクトID)_(横幅)x(縦幅).png`

サンプルプロジェクト

https://scratch.mit.edu/projects/604757806

![スクリーンショット](https://cdn2.scratch.mit.edu/get_image/project/604757806_480x320.png)
devise current_userをインスタンス変数に代入する

#ログインユーザーのデータをインスタンス変数に代入する

###環境
rails ５.２.６
使用Gem：devise

#記述方法

```ruby
インスタンス変数 = current_user
```

current_userはDevise使用時にだけ使えるメソッド
ログインユーザーの（Userモデルで定義している）カラム情報を呼び出す事ができる

イコールの右側にcurrent_userとすることで、インスタンス変数に代入が可能
kicsでInfrastructure-as-Codeの静的解析をしよう

# kicsとは

Infrastructure-as-CodeのためのOSSアナライザー
セキュリティの脆弱性、コンプライアンスの問題、およびインフラストラクチャの構成ミスを
早期に検知することができる

https://docs.kics.io/latest/

# kicsを使用するメリット

- デプロイなしでチェック可能
- 人間によるレビューよりも短い時間でチェック可能
- 高度な知識を持つレビュアーがいなくてもチェック可能

# 使用方法

## config構成

- CLI、CI(GitLab)いずれの場合でも共通

```yaml:kics.config.yaml
path: scan
verbose: true
log-file: true
output-path: "results"
report-formats:
  - html
  - sarif
  - glsast
```

## 実行方法

### CLIの場合

https://docs.kics.io/latest/getting-started/#binary

- 下記URLからダウンロード、パスを通す

https://github.com/Checkmarx/kics/releases

```powershell
kics scan  --config kics.config.yaml
```

### CI(GitLab)の場合

https://github.com/Checkmarx/kics/blob/master/examples/gitlab/KICS.v3.gitlabci.yaml

- GitLab、GitLab-runnerの構成方法は省略
- 下記のようにCIを構成する

```yaml:.gitlab-ci.yml
kics-scan:
  image: 
    name: checkmarx/kics:latest
    entrypoint: [""]
  script:
    - kics scan --config kics.config.yaml
  artifacts:
    paths:
      - results
    reports:
      sast: results/gl-sast-results.json
    when: always
```

## レポート

### html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161516/05704c33-3370-9817-8a25-afe7ad9062e4.png)

### sarif

- VSCode拡張で参照可能

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161516/a9fad479-bb8f-f083-5dee-105074bde194.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/161516/b7c32101-44d6-87e6-e77f-405fd7b07526.png)
SQL ビューの基礎知識について

#記事内容

- **ビューとは**
- **ビューの作成**
- **ビューの削除**

#ビューとは
**データを取り出す`SELECT文だけ`を保存する仮想的なテーブルのこと**

##テーブルとビューの違い
- **`テーブル`**
 - **実際のデータを保存**
- **`ビュー`**
 - **SELECT文を保存するのみで、データを持たない**

##**ビューのメリット**
 - **必要なデータが複数のテーブルにまたがる場合などの複雑な集約を行いやすくなる**
 - **使用頻度が高いSELECT文をビューにすることで使い回すことができる**
 - **データを保存しないので記憶装置の容量を節約できる**

##ビューの制限
- **order by句を使用できない**
- **ビューに対する変更には制限があり、下記の条件をみたす場合のみ更新が可能**
 - **`select句`に`distinct`が含まれていないこと**
 - **`from句`に含まれるテーブルが1つのみであること**
 - **`group by句`を使用していないこと**
 - **`haing句`を使用していないこと**

:::note alert
ビューとテーブルの更新は連動して行われるため、集約されたビューは更新できない
:::

#ビューの作成
**create view文を使用**

```sql
-- 構文
create view ビュー名（<ビューの列名1>, <ビューの列名2>, ...）
as
<select文>

-- 都道府県別のユーザー数を取得したデータをビューに保存
create view prefecture_user_counts(name, count)
as
select
  p.name name,
  count(*) count
from
  users u
inner join
  prefectures p
on u.prefecture_id = p.id
group by
  u.prefecture_id;
```

##ビューの使用方法

```sql
-- 構文
select
  <ビューの列名1>,
  <ビューの列名2>,...
from
  <ビュー名>;

-- prifecture_user_countsを使用する場合
select
  name,
  count
from
  prifecture_user_counts;
```

##ビューの削除
**drop view文を使用**

```sql
-- 構文
drop view <ビュー名>;
```

##参考記事

https://www.udemy.com/course/standard-sql-for-beginners
【Swift】Swift初心者でも分かるMVVM

#はじめに
Swiftを学び始めて1ヶ月が経ち、MVVMというアーキテクチャがあることを知りました。

MVVMって何？MVCと何が違うの？という方向けのためにMVVMについてまとめてみました。

※具体的なコード例はSwiftで書かれているものを参考にしています。

#MVVMはデータバインディングをする

![mvvmIllust.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/933058/ffe3ee27-f1cd-f731-3e98-0d7650661a24.jpeg)
出典：[ソフトウェアアーキテクチャー…？MVCやMVVMってなに！？](https://digitalidentity.co.jp/blog/creative/mvc-mvvm.html
)

MVVMはViewとView ModelとModelからなります。

MVCはViewとControllerとModelからなるので、比較するとControllerとView Modelの部分が違いますね。

この２つの違いはView Modelの方がデータバインディングをするということです。

#データバインディングとは？
データバインディングとは、ViewとView Modelを結び付ける仕組みのことです。
データの値を結び付けるので、データバインディングと呼ばれています。

データバインディングの特徴は、ViewとView Modelどちらかで値が書き変われば、値が変化するたびにViewとView Model、両方の値が変更されるという点です。

これはつまり、ユーザーが画面上で何らかの処理した場合でも、コンピューター上やサーバ上で何らかの処理があった場合でもViewとView Modelそれぞれに変更が反映されるということです。

MVCだとModelから受け取った情報をControllerを介してViewに伝えるのに対して、
MVVMはModelから情報を受け取り、View Modelに情報が反映されることで、自動的にViewにも同じ変更が反映されます。

#MVVMを使った方がいい場面
データバインディングをすることがMVVMの特徴でしたが、このアーキテクチャはどんな場面で有効になるのでしょうか。
MVVMが有効なシーンは、データバインディングを活かすことができるものになります。

データバインディングを行うMVVMは、Viewで変更があっても、Modelで変更があっても、お互いに更新を反映する機能を持っています。
そこで、ユーザーの入力した情報をすぐに反映したり、サーバ側で自動的にデータを更新する頻度の多いサービスでは、MVVMの方が適しているでしょう。


（ちなみにVue.jsはMVVMを採用しています。[記事](https://design.dena.com/engineering/vue-js%E3%81%A7%E3%81%AF%E3%81%98%E3%82%81%E3%82%8Bmvvm%E5%85%A5%E9%96%80)のTodoリストもMVVMの設計でできています。）

#MVVMを実装した具体的なコード

以下にMVVMで記述されたコード例が載っているのでSwiftがわかる方なら目を通してみてもいいかもしれません。
SwiftでMVVMを使うときはシンプルに記述できるということでRxSwiftがよく使われますが、学習コストが高く初心者が理解するのは少し難しかったりします。
なので、RxSwiftを使用していないパターンも載せておきます。

・RxSwiftを使っていないパターン
[【Swift】MVVMを勉強してみたPart3](https://qiita.com/REON/items/60b9fb8fc01e5cc478e5
)


・RxSwiftを使ったパターン
[iOSアプリ設計大全集 2016](https://qiita.com/tattn/items/d4b95af0b60c3849243a
)


#終わりに
データバインディングをしているという概念的なもののイメージを掴んでから、
実際のコードを見てみるとMVVMがどんな役割を持ったアーキテクチャーなのかがより理解できたように思います。
MVVMについてより理解を深めたいときは下記の記事も参考にしてみて下さい。

#参考


https://qiita.com/AbeTatsuhiro/items/6686ce00c9dcfb59ad3f

https://laptrinhx.com/iosapuriakitekucha-bi-jiao-jian-tao-cocoa-mvc-mvvm-mvp-cleanarchtecture-3832902000/


https://sssslide.com/speakerdeck.com/takasek/jian-kang-de-namvvm-shu-itemasuka-mvvmantipatanji

https://academy.realm.io/jp/posts/slug-max-alexander-mvvm-rxswift/
切れ目のないループ再生

ループ音楽や環境音を連続して再生したい時があります。その時、繰り返しブロックの中に「終わるまで〜〜の音を鳴らす」を使うと、繰り返しの瞬間に一瞬音が途切れてしまいます。代わりに「〜〜の音を鳴らす」と「〜〜秒待つ」の組み合わせを使うことで途切れずに再生することができます。待つ時間は、音の長さより0.1秒くらい少ないくらいが丁度良いみたいです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75307/9e9545a9-43d9-8b4d-f7aa-58b443ed9575.png" width="50%"></img>

サンプルプロジェクト

https://scratch.mit.edu/projects/600931888
![スクリーンショット](https://cdn2.scratch.mit.edu/get_image/project/600931888_480x320.png)
MFAデバイスを使用している際のsls deployを実行するまで


## 目的
Serverless Frameworkを用いてAWSにデプロイする際に、IAMのユーザがMFAであった際に、セッショントークンが必要となる。その際のセッショントークンの取得方法と設定方法をまとめた。

## 環境
```
ShiroUz@MBP serverless % sls -v
Serverless: Running "serverless" installed locally (in service node_modules)
Framework Core: 2.66.1 (local)
Plugin: 5.5.1
SDK: 4.3.0
Components: 3.18.0

ShiroUz@MBP serverless % sw_vers
ProductName:    macOS
ProductVersion: 11.6
BuildVersion:   20G165

ShiroUz@MBP serverless % aws --version
aws-cli/2.3.4 Python/3.9.7 Darwin/20.6.0 source/x86_64 prompt/off
```


## セッショントークンの取得
MFAデバイスを使用しているため以下の対応が必要でした。

```
ShiroUz@MBP layer % aws sts get-session-token --serial-number MFA_ARN --token-code MFA_TOKEN_CODE --region us-east-1 --profile PROFILE_NAME
{
    "Credentials": {
        "AccessKeyId": "xxxxxxxxx",
        "SecretAccessKey": "yyyyyyyyyy",
        "SessionToken": "zzzzzzzzzzzz",
        "Expiration": "2021-11-21T17:57:30+00:00"
    }
}
```

MFA_ARN: IAMのユーザで確認できるMFAのARN (e.g.`arn:aws:iam::yyyyyyyyyy:user/xxx`)
MFA_TOKEN_CODE: MFAのデバイスで確認できる6桁の数値
PROFILE_NAME:~/.aws/configに記載のあるプロファイル名


## セッショントークン等の設定
`$ sls deploy`を実行するためにも、以下のようにして、アクセスキー、シークレットキー、セッショントークンを設定する必要があります。なお、credentialに書き込んでいないのは、Expirationが設定されているため、直接環境変数に設定しても、問題ないと判断しているからです。

```
ShiroUz@MBP  serverless % export AWS_ACCESS_KEY_ID=xxxxxxxxx
ShiroUz@MBP  serverless % export AWS_SECRET_ACCESS_KEY=yyyyyyyyyy
ShiroUz@MBP  serverless % export AWS_SESSION_TOKEN=zzzzzzzzzzzz
```
完了後、`sls deploy`が可能となる。
MySQL をインストールできない

#環境

Centos7（Dockerにて起動）


#問題

MySQL をインストールしようとしましたが、以下のエラーが発生しました。

```
yum --enablerepo=centos-sclo-rh -y install rh-mysql80-mysql-server
Loaded plugins: fastestmirror, ovl

Error getting repository data for centos-sclo-rh, repository not found
```

#原因
エラー文にはcentos-sclo-rhが見つからないと書いてあります。
CentOS SCLo Software collections がインストールされていないので、MySQL がインストールできないようです。


#対処法
CentOS SCLo Software collections をインストールすればOKです。

```
yum -y install centos-release-scl-rh centos-release-scl
```

これで、再度実行します。

```
yum --enablerepo=centos-sclo-rh -y install rh-mysql80-mysql-server
```

無事にMySQL がインストールできました。
じゃんけんゲーム

```python:jyanken.py
import random

count = 1
jyanken = ['グー', 'チョキ', 'パー']

def kati():
    print('-----------------------------------')
    print('あなたの勝ち')
    print('あなたは' + jyanken[int_te] + '相手は' + jyanken[aite])
    print(f'{count}回目で勝負がつきました')
    
def make():
    print('-----------------------------------')
    print('相手の勝ち')
    print('あなたは' + jyanken[int_te] + '相手は' + jyanken[aite])
    print(f'{count}回目で勝負がつきました')

#最初に手を決める部分、グーは1、チョキは2、パーは3に変換
while True:
    te = input('手を決めて下さい：グー=g、チョキ=c、パー=p')
    if te == 'g':
        int_te = 0

    elif te == 'c':
        int_te = 1

    elif te == 'p':
        int_te = 2

    else:
        print('間違った入力がされました。')
        count += 1
        continue

    #相手の手をランダムで決める
    aite = random.randint(0,2)
    
    if int_te - aite == 0:
        print('あいこ')
        count += 1
        continue
    
    elif int_te == 0 and aite == 1:
        kati()
        break
    elif int_te == 0 and aite == 2:
        make()
        break
    elif int_te == 1 and aite == 0:
        make()
        break
    elif int_te == 1 and aite == 2:
        kati()
        break
    elif int_te == 2 and aite == 0:
        kati()
        break
    else:
        make()
        break
```
PySideで印刷した

Pythonで、帳票を印刷するアプリ書こうと思って、どうやったら印刷出来るんだろうと色々ググってみたけど、結局Qt使う事にして、それならPySideで印刷する方法を調べてたけど、しっくりするサンプルが無かったので、作ってみた。

とりあえず、QPrinterオブジェクト作っておいて、QPrintDialogでユーザーにプリンターを選択させて、設定されたQPrinterオブジェクトをQPainterオブジェクトに渡して、QPainterオブジェクトで描画するという手順だった

```python:
import sys
from PySide6.QtWidgets import QApplication
from PySide6.QtPrintSupport import QPrintDialog, QPrinter
from PySide6.QtGui import QImage, QPainter


def print_dialog(printer_obj):
    dialog = QPrintDialog(printer_obj, None)
    dialog.setWindowTitle("Print Document")
    return dialog


def print_image(printer_obj):
    painter = QPainter(printer_obj)
    # draw_squares(painter)

    draw_text(painter)
    draw_squares(painter)


def draw_text(painter):
    font = painter.font()
    font.setPixelSize(48)

    painter.setFont(font)
    painter.drawText(100, 100, "TEST:あいうえお")


def draw_squares(painter):
    # 横線を引く
    for i in range(0, 10):
        painter.drawLine(0, i * 10, 100, i * 10)

    # 縦を引く
    for i in range(0, 10):
        painter.drawLine(i * 10, 0, i * 10, 100)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    printer = QPrinter()
    dialog = print_dialog(printer)
    if dialog.exec():
        print_image(printer)
```
風船的な動き

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BalloonMover : MonoBehaviour
{

    private Vector3 objectpos;
    public float speed = 0.001f;

    void Start()
    {
        //ゲーム開始時のオブジェクトを取得する
        objectpos = transform.position;

    }

    void Update()
    {
        if (objectpos.y <= 50)
        {
            transform.position = new Vector3(objectpos.x, objectpos.y += speed , objectpos.z);
            objectpos.y *= 1.01f;
        }

        Debug.Log(objectpos.y);

    }
}
人材営業職からエンジニアになってみて

# 前職の内容
前職では、医療系の人材紹介会社でキャリアコンサルタント(CA)と法人営業(RA)として働いておりました。
新卒から3.5年くらい働いて、今はエンジニアとしてHRテック系の会社にいます。

# エンジニアになろうと思ったきっかけ
エンジニアになろうと思ったのは、前職の業務内容の一部をGASやスクレイピングなどを使って業務効率化した事がキッカケでした。

前職は体育会系の雰囲気があり、数字を上げるには行動量だ！と言って非効率なやり方で仕事をしている事が多かったのですが、

僕自身、そういった非効率な作業がすごく嫌いで、どうにか効率化できないかと調べまくっていたところ、スクレイピングやGoogleAppScriptという技術で、今の仕事内容を自動化できるという事が分かり、独学で実装してみました。

すると、1時間くらい掛かっていた作業がボタン1つで終わったので、とても感動した事を覚えています。
そこから営業よりも、このような仕組みを考えたり作業を効率化する方が向いているのでは？と考え、エンジニアとして転職するべく、プログラミングの勉強をはじめました。

# エンジニアとして働いてみた感想(前職と比べてどう変わったか)
多くの部分で変わった事があるので、大きく2つに分けてお伝えしようかと思います。

## ハード面(勤務時間や仕事内容など)
### 勤務時間が圧倒的に短くなりました。
前職では、月の残業時間が40時かんを超えるのは当たり前でしたが、今ではほとんど残業していません。
残業しなければならない業務量なのであれば、どうにか自動化できる部分がないか考えたり、とにかく行動料でカバーするような考え方をする人がいません。
在宅とリモートを選べるので、働き方の柔軟性もあがったと思います。

### コミュニケーションは9割チャットです
営業していた際は、出社していた事もあって、メンバーや上司とのコミュニケーションは半分以上口頭で撮っていましたが、今はMTGや1on1以外はチャットでのコミュニケーションになっています。
個人的にはチャットの方が密に話せて良いと思っています。笑

### 追うのは数字ではなくリリース
営業では毎月の売上数字を目標として追うことになると思います。営業では毎月月末になると社内がピリピリしていました。
エンジニアでは、新機能や追加機能のリリースタイミングで忙しくなります。

## ソフト面(考え方など)

### 人間関係はとてもフラット
新卒の時から人間関係で悩んだ事はなかったのですが、前職よりも上司との距離が近く、密にコミュニケーションを取る事もあって風通しが良いと感じます。
また、前職では週に1回くらい上司の怒鳴り声が聞こえていたのですが、今では怒鳴るような人は一人もいません。笑

### クライアントがいない
営業はクライアントがありきの職業ですが、基本的に自社開発系の企業に在籍するエンジニアはクライアントと直接やり取りする事はありません。
営業は会社の顔という事もあって、クライアント第一で仕事していましたが、今はクライアントに左右される事はありません。
※もちろん、バグ改善や使い易い機能開発は前提ですが。

## 今後はどんなエンジニアを目指したいか
長期的には、サービスの全体を管理する立ち位置、CTOやPMのような職種で働きたいと考えております。個人的には技術を追い求め続ける性格には向かないと感じており、マネジメントの立ち位置で社会に貢献したいと考えております。

とはいえ、まだまだ技術力もポンコツなので短期的には1人前のエンジニアとしてゴリゴリ開発して、どこでも通用するようなスキルセットを身に付けていきます。
WinUI3 Desktopでダークモードに対応する (Windows App SDK)

WinUI3はダークモードに標準で対応している、ことになっています。

Windowsの設定でアプリのダークモードを有効にすると…。

![p1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/568364/4ce919c2-824d-16e9-cd72-11953a3a73af.png)

なんということでしょう。タイトルバーだけ、ダークではありません。

各UI要素にはRequestedThemeというプロパティがあり、動的にテーマを設定できます。しかしこれはWindowには適用されません。

タイトルバーにもWindowsのテーマを適用するには、タイトルバーを非表示にして、自前のタイトルバーをXAMLで作ります。

``` xml:MainWindow.xaml
<Window
    x:Class="Sample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Sample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    >

    <Grid Grid.RowDefinitions="Auto,*">
        <StackPanel Grid.Row="0" Height="35" Orientation="Horizontal" Spacing="15" x:Name="TitleBar" HorizontalAlignment="Stretch" VerticalAlignment="Top">
            <TextBlock VerticalAlignment="Center" Text="MyApp" />
        </StackPanel>
        <NavigationView
            Grid.Row="1"
            SelectionChanged="NavigationView_SelectionChanged"
            Loaded="NavigationView_Loaded">
            <NavigationView.MenuItems>
                <NavigationViewItem Content="Menu Item1" Tag="SamplePage1" x:Name="SamplePage1Item" >
                    <NavigationViewItem.Icon>
                        <SymbolIcon Symbol="Play"/>
                    </NavigationViewItem.Icon>
                </NavigationViewItem>
            </NavigationView.MenuItems>
            <Frame x:Name="contentFrame"/>
        </NavigationView>
    </Grid>
</Window>
```

Grid.Row="0"がタイトルバーです。このサンプルにはアプリのアイコンがありません。アプリのアイコンを付けたい人は、TextBlockの前にImageを置いてください。

``` cs:MainWindow.cs
public sealed partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();

        ExtendsContentIntoTitleBar = true;
        SetTitleBar(TitleBar);
    }
}
```

そしてコード側で、元のタイトルバーを無効にして、XAMLで作ったタイトルバーに差し替えます。

![p2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/568364/6a818f50-ad65-dc79-23c6-1246fea01b2b.png)

これでタイトルバーにもテーマが適用されるようになりました。
【Flutter/ Dart】CocoaPods could not find compatible versions for pod "stripe_ios" のエラーを解消する方法

## 概要

- オンライン決済処理をアリモノを使って作ろうとした
- [stripe.com](https://stripe.com/jp)というサービスが良さそうだったので採用
- [Flutter用のライブラリ](https://pub.dev/packages/flutter_stripe)も開発されている
- サンプルを書いて実行しようとすると表題のエラーが発生

## 原因
公式ドキュメントを読んでいなかったこと。

>
iOS
Compatible with apps targeting iOS 11 or above.

と書いてあったので

## 解決方法

```
platform :ios, '**.*'
```

を

```
platform :ios, '11.0'
```

にしてあげるとビルドできました！
AfterEffects シェイプ リピーターで増やす。

#■リピーター
数を増やす事ができる。

###▼①シェイプで線を書くとする。
![スクリーンショット 2021-11-21 16.39.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1558142/7873b62f-5dea-1585-d48e-894f201cf46a.png)

###▼②コンテンツ右あたりの追加からリピーターを追加。
![スクリーンショット 2021-11-21 16.40.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1558142/07a5ea7a-8102-eeca-9903-23df4e27a2f9.png)

デフォルトでコピー数が3になっている。(数が増えている。)
![スクリーンショット 2021-11-21 16.41.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1558142/887bf47d-cd12-19f3-c8c6-fda7514a276d.png)

###▼トランスフォームリピーターの位置を0にすると元ある場所で重なる。
![スクリーンショット 2021-11-21 16.46.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1558142/1f5f6acf-9d09-aaf1-9dcb-9e8155e245ef.png)
![スクリーンショット 2021-11-21 16.39.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1558142/e0f651a6-04bc-117e-0a46-5655be56031f.png)

###▼回転を加えると円を描くように広がる。
リピーター
コピー数 12

トランスフォームリピーター
位置 0
回転 30
回転の数値は360÷コピー数で決める。

![スクリーンショット 2021-11-21 16.51.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1558142/b004e34c-7dc4-6755-ad10-8deb40146c97.png)
SSIについて

# はじめに
業務中SSIを使用しているページを見かけた。
SSIについてその際に初めて知ったので、かんたんにまとめる。
***※間違えている可能性があるため、必ず他の情報も参考にしてください***

# SSIとは？
SSIとは、***Server Side Include***の略で、Webサーバーの機能の１つ。
HTML内にWebサーバー側で実行するコマンドを記載することで、サーバー側で実行しその結果を返す仕組み。サーバー側で実行して、その結果を返しているためクライアント側では通常のHTMLとして見える。

SSIは以下のように、HTML内で記述する。

```html
<!--#コマンド名 属性名="値"-->
```

ただ、SSIはどのサーバーでも使えるわけではなく、SSIをサポートしていて、SSIを許可する設定をする必要がある。HTMLのコメントの記法であることから、サポートしていない場合はそのままコメントとしてブラウザ側では無視される。



## メリット
### ・共通ファイルの分離

多くのサイトが、ヘッダーやフッターなど他のページと共通している部分がある。
それを各ページでそれぞれ実装すると、もし修正が必要になった場合すべてのヘッダーやフッターを修正しなければいけなくなってしまう。

そこで、共通して使用する箇所に関しては、別ファイルで用意しておき各ページでそのファイルを呼び出して使用することでメンテナンス性の向上（修正したい場合は、そのファイルを修正するだけで良い。）を図ることができる。

ちなみにファイル読みこみのコマンドは「file」と「virtual」がある。

```html
<!--#include file="～" -->
<!--#include virtual="～" -->
```

違いとしては、
・<!--#include file="～" -->
カレントディレクトリからの相対パスでパスを指定する必要がある。絶対パスは使用できず、相対パスを用いて上の階層を指定することができない。

・<!--#include virtual="～" -->
ルートディレクトリから始まる任意のパス（絶対パス）で指定する。

こういった違いがあり、fileだと絶対パスが使用できずかつ上の階層を指定できないこともあり、基本的にvirtualを使用するという認識で良い。


### ・動的な情報の出力
HTMLのみでは静的な情報しか表示できないが、SSIを使用することで「サイトの更新時間」や「アクセスカウンター」「ファイルの更新日」など動的なコンテンツ表示することができる。


## デメリット
SSIは、使用できるWebサーバーでかつ設定さえしていればHTML内のどこでも記述することができる。
そのため、サーバー側ではどこにSSIコマンドが記述されているかHTMLファイルを解析する必要がある。

SSIコマンドが少しであれば、それほど負荷はかからないがあまりにも多いと負荷が大きくなってしまい処理時間がかかってしまう。こういったデメリットを踏まえて、使用する必要がある。


## 拡張子
SSIコマンドを含んだHTMLの拡張子は一般的には***「.shtml」***とする。
ただ、***.htaccess***で設定することで***「.html」***のままSSIを使用することができる。


# おわり
今回はSSIについてざっくりとまとめた。
SSIについて知らなかったため、「この拡張子が.htmlだから静的なページだ」と思っていたら実はSSIを使用していて動的にページを生成していたなんてことがありました。

以上。

# 参考

https://www.tohoho-web.com/wwwssi.htm

https://allabout.co.jp/gm/gc/23773/

https://www.scollabo.com/banban/ssi/ssi_001.html

http://www.slis.tsukuba.ac.jp/~matsumoto.makoto.fm/ssi.html
[GCP] Container failed to start. Failed to start and then listen on the port defined by the PORT environment variable.

# Cloud Runデプロイ時にエラー


> Container failed to start. Failed to start and then listen on the port defined by the PORT environment variable.

# 対処法
CloudRun起動時に、`0.0.0.0:8080`に対してヘルスチェックが通らず、エラーとなっていた。
`PORT`環境変数によって、portのマッピングを自動で設定してくれるが、未指定の場合、デフォルトで`8080`となるそう。
serverのlistenしているポートが3000となっていたので、環境変数`PORT`を読むように変更した。

### 問題のコード
```main.go
func main() {
        log.Print("starting server...")
        http.HandleFunc("/", handler)

        // Start HTTP server.
        if err := http.ListenAndServe(":3000", nil); err != nil {
                log.Fatal(err)
        }
}

func handler(w http.ResponseWriter, r *http.Request) {
        name := os.Getenv("NAME")
        if name == "" {
                name = "World"
        }
        fmt.Fprintf(w, "Hello %s!\n", name)
}
```
### 修正後
```main.go
func main() {
        log.Print("starting server...")
        http.HandleFunc("/", handler)

        // 追加
        port := os.Getenv("PORT")
        if port == "" {
                port = "8080"
        }

        // Start HTTP server.
        if err := http.ListenAndServe(":"+port, nil); err != nil {
                log.Fatal(err)
        }
}

func handler(w http.ResponseWriter, r *http.Request) {
        name := os.Getenv("NAME")
        if name == "" {
                name = "World"
        }
        fmt.Fprintf(w, "Hello %s!\n", name)
}
```

# デバッグ過程
今回のエラーに関しては、GCPのトラブルシューティングに沿ってデバッグした。
ありがたいmm

https://cloud.google.com/run/docs/troubleshooting

### ステップ１
> コンテナ イメージをローカルで実行できることを確認します。コンテナ イメージをローカルで実行できない場合は、まず問題をローカルで診断して修正する必要があります。

下記コマンド実行、`https://localhost:3000`にアクセス。OK。

```zsh
$ docker run -it IMAGE_NAME
```


### ステップ2

> コンテナ ランタイムの契約に記載されているように、コンテナが想定ポートでリクエストをリッスンしていることを確認します。コンテナは、Cloud Run によって定義され、PORT 環境変数で指定されているポートで受信リクエストをリッスンする必要があります。

下記のコマンド実行。`https://localhost:8080`にアクセス。動かない、、

```zsh
$ PORT=8080 && docker run -it IMAGE_NAME
```

main.goを見たら、portが即値で入っていました。。。
直して、無事動いた。

### これでも動かない場合
公式のトラブルシューティングにてmm

https://cloud.google.com/run/docs/troubleshooting
[SwiftUI]ScrollViewの副作用を抑制する

## 0. 概要

SwiftUIのScrollViewには副作用があり、ビューの配置の仕方によって周囲のビューの動作が決定します。
例えば、次のようなコードはScrollViewの中のTextのみならずNaviagtionのタイトルも連動してスクロールするようになります。

```swift
struct ContentView: View {
    var body: some View {
        NavigationView {
            ScrollView {
                Text("view")
            }
            .navigationTitle("Title")
            .navigationBarTitleDisplayMode(.large)
        }
    }
}
```



![Simulator Screen Recording - iPhone 13 mini - 2021-11-21 at 16.54.13.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24979/70499e77-4c4a-9ede-1989-34c71c1aa638.gif)

この挙動はiOSの標準的な挙動なので悪戯に無効化する必要はありませんが、どうしても無効化したい場合次のようなワークアラウンドがあります。

## ワークアラウンド

ScrollViewの副作用は

1. NavigationViewのルートにScrollViewが配置されている
2. ScrollViewが親ビューの上部に隣接している

ことで発生するため、これらを回避することで副作用を抑制させることができます。

```swift
struct ContentView: View {
    var body: some View {
        NavigationView {
            ZStack(alignment: .top) {
                Rectangle().foregroundColor(.white) // 1
                ScrollView {
                    Text("view")
                }.offset(y: 1) // 2
            }
            .navigationTitle("Title")
            .navigationBarTitleDisplayMode(.large)
        }
    }
}
```

1で間に挟むビューは一定の不透明度が必要なため、.clearやopacity(0)を使うことはできません。
SQL テーブルの結合について

#記事内容
- **テーブルの結合とは**
- **主キーと外部キーとは**
- **内部結合**
- **内部結合 + 絞り込み**
- **片方のテーブルの情報が全て出力されるテーブルの結合**
- **テーブルの足し算を行う集合演算子**

#テーブルの結合とは
- **テーブル同士をある条件で結合すること**

##主キーと外部キーとは

- **主キー(Primary Key, PK)**
 - **一つの行を特定できる列のこと**

- **外部キー(Foreign Key, FK)**
 - **他テーブルとの関連付けに使用する列のこと**
 - **関連付けられた先のテーブルでは`主キー`になる**


##inner join
- **内部結合でテーブル同士を結合**
 - **複数テーブルの結合も可能**

```sql
-- 構文
select
  テーブル名1.列名,
  テーブル名2.列名
from
  テーブル名1
inner join
  テーブル名2
  on テーブル名1.列名 = テーブル名2.列名; 

-- ユーザーテーブルと都道府県テーブルを結合し、ユーザー名と都道府県名を取得

select
  users.name
  prefectures.name
from
  users
inner join
  prefectures
on users.prefectures_id = prefetures.id;

-- prefectures_id = ユーザーテーブル内に存在し、都道府県テーブルと関連付けられた外部キー
-- prefectures = 都道府県テーブル
-- prefectures.name = 都道府県名
```

##as
- **テーブルに別名をつけることができる**
 - **記述量を減らし、可読性も向上**

```sql
-- テーブル名の 「users」 を 「u」　に変更する場合
... from users as u

-- 「as」 は省略可
... from users u
```

###内部結合 + 絞り込み
**where句で絞り込みを行いながら、内部結合でテーブルを結合**

```sql
-- ユーザーテーブルと都道府県テーブルを結合し、女性のユーザーと都道府県名を取得

-- gender = 1:男性 2:女性

select
  users.id,
  prefeuctures.name
from
  users
inner join
  prefectures
on user.prefecture_id = prefectures.id
where user.gender = 2;
```


##outer join
**片方のテーブルの情報が全て出力されるテーブルの結合**

:::note alert
値が null のデータも全て出力される
:::

- **種類**
 - `left outer join`  ・・・ **左側(from句で最初に書いたテーブル)をマスタとする**
 - `right outer join` ・・・ **右側(from句で後に書いたテーブル)をマスタとする**

```sql
-- 構文
select
  テーブル名1.列名,
  テーブル名2.列名 ・・・
from
  テーブル名1
left outer join
  テーブル名2
on テーブル名1.列名 = テーブル名2.列名;
```

##union
- **テーブルの足し算を行う集合演算子**
 - **ベースとなる`select文`の結果に`union`の後に記載した`select文`の結果を足し算する**

- **注意点**
 - **テーブル1とテーブル2で列数を合わせる必要がある**
 - **同じ位置にあるカラムの`データ型`は一致している必要がある**

```sql
-- 構文
select 列1, ... from テーブル名1
union
select 列2, ... from テーブル名2

-- ユーザーテーブルと管理者テーブルを足し合わせて取得
select name, email from users
union
select name, email from admin_users;

-- 重複行も取得したい場合、allを付ける
union all
```

- **句について**
 - **`where`,`group by`,`having`といった句をつけることができる**
 - **ただし、`order by`だけは全体として最後に`1つ`しか記述できない**

```sql
-- ユーザーテーブルから男性のみ、管理者テーブルからは女性のみを取得し
-- ２つのテーブルを足し合わせた結果を性別順に並び替え

select name, email gender from users where gender = 1
union all
select name, email gender from admin_users where gender = 2
order by gender;
```

##参考記事

https://www.udemy.com/course/standard-sql-for-beginners
WinUI3 Desktopでウィンドウのサイズを変更する (Windows App SDK)

WinUI3 Desktopでアプリを作ると、ウィンドウのサイズが自動的に決められてしまいます。 Microsoft.UI.Xaml.WindowクラスにはWidthやHeightといったプロパティがありません。

ウィンドウのサイズを指定するには、AppWindowのインスタンスを取得します。

``` cs
using Microsoft.UI;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using System;
using Windows.Graphics;

public sealed partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();

        IntPtr hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
        WindowId myWndId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hWnd);
        AppWindow appWindow = AppWindow.GetFromWindowId(myWndId);

        appWindow.Resize(new SizeInt32(800, 600));
    }
}
```

ウィンドウサイズを指定したいだけなのに、いきなりきな臭いコードです。将来的にはもっと簡単になるんじゃないかと思いますが…。

このコード、packagedなアプリでは動きますが、unpackagedなアプリではTargetInvocationExceptionの例外が出て動きません(Windows App SDK 1.0現在)。app.manifestにsupportedOSを追加することで、unpackagedなアプリでも動作するようになることが知られています。

``` xml:app.manifest
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <assemblyIdentity version="1.0.0.0" name="Sample.app"/>

  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <!-- The combination of below two tags have the following effect:
           1) Per-Monitor for >= Windows 10 Anniversary Update
           2) System < Windows 10 Anniversary Update
      -->
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
      <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
    </windowsSettings>
  </application>
  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <!-- Windows 10 -->
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
    </application>
  </compatibility>
</assembly>
```

この回避策は、いずれ不要になるものと思われます。

packagedとunpackagedの違いについてはこちらで解説しています。

https://qiita.com/hayashida-katsutoshi/items/eba4fe2e9332e87cdc8f
This dependency was not foundを解決したい

<h2>問題</h2>
nuxt.jsでFirebaseを利用しようとした時に、
This dependency was not foundというエラーが出た。

```javascript:firebase.js
import firebase from 'firebase'
const config = {
    apiKey: process.env.FIREBASE_API_KEY,
    authDomain: process.env.FIREBASE_AUTH_DOMAIN,
    projectId: process.env.FIREBASE_PROJECT_ID,
    storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
    messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID,
    appId: process.env.FIREBASE_APP_ID,
    measurementId: process.env.FIREBASE_MEASUREMENT_ID,
}

if (!firebase.apps.length) {
    firebase.initializeApp(config)
}

export default firebase

```
<h2>バージョン情報</h2>
|ライブラリ|バージョン|
|:---|:---:|
|nuxt.js|2.15.8|
|Firebase|9.22.0|

<h2>解決</h2>
原因としては、firebaseV8からV9に上がったことでimportの仕方に変更があったためだ。
上記のコードを以下のように書き換えてください。

```javascript:firebase.js
import { initializeApp } from 'firebase/app';

const config = {
    apiKey: process.env.FIREBASE_API_KEY,
    authDomain: process.env.FIREBASE_AUTH_DOMAIN,
    projectId: process.env.FIREBASE_PROJECT_ID,
    storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
    messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID,
    appId: process.env.FIREBASE_APP_ID,
    measurementId: process.env.FIREBASE_MEASUREMENT_ID,
};

const firebaseApp = initializeApp(config);

export default {firebaseApp};
```

firebaseV8ではimport firebase from "app/firebase"となっていて利用しないメソッドも全てimportしていたが、firebaseV9になって、queryやgetFireStoreなど必要なメソッドのみをimportできるようになった。

firebaseを利用する場合は、 V8と変わらずimportして関数を呼び出せば大丈夫。

<h2>参考資料</h2>
<h4>公式ドキュメント</h4>
https://firebase.google.com/docs/web/setup
個人で作ったアプリを予算5000円でGoogle広告してみた時の話

![landscape.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/618374/2434c2b3-bbe8-dea0-1c81-b1093bd6c09d.png)
Flutterで作成したアプリ「Favcovery」をGoogle Play Storeでリリースしました。
ダウンロード数を伸ばすためにTwitterでツイートしたのですが、フォロワーが11人しかいないため全く効果はありませんでした（笑）

そこで、広告プラットフォームを活用してアプリのダウンロード数を伸ばすことにしました。

[FavcoveryをGoogle Play Storeでダウンロード](https://play.google.com/store/apps/details?id=com.favapp.favcovery)

このページでグラフ付きで紹介しているのでぜひ見てください！
https://yukiit.com/programming/2145/

#作ったアプリについて

![landscape.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/618374/1792a7ab-9da4-bdbe-cd12-85f49cc66dea.png)


今回作ったアプリ「[Favcovery](https://play.google.com/store/apps/details?id=com.favapp.favcovery)」は音楽(とくにEDM)を共有することを目的としています。

自分のお気に入りの曲を投稿して世界中の人と共有したり、似たジャンルから新たな曲を見つけることができます。

今は人数が全然いないので共有されている曲数が少ないのですが、将来的にはこのアプリが多くの人にとって曲を見つける選択肢となるようにしたいなと思っています。

シェアの方法は簡単で、YouTube動画のURLを貼り付けてその曲のジャンルを選択します。

また、自分のお気に入りのジャンルを指定すれば、それに合った条件の曲を一覧で表示します。
気に入った曲があれば「いいね」して、自分のライブラリに含めることができます。

１０言語近くにローカライズして出来るだけ全世界のユーザーに使ってもらえるようにしています。

#Google広告を使う

TwitterやインスタなどのSNSでの広告や、有料プレスリリースの依頼、Google広告などがある中で僕はGoogle広告を使用することにしました。

Google広告にした理由は下の感じです。

* 広告配信の幅が広そう
* 他のプラットフォームより簡単そう
* "Google"という謎の安心感
* Play StoreがGoogleの物だから
* なんか一番簡単そう

という、曖昧な理由で決めました。

#予算は5000円

僕は「趣味で使うお金は自分で作ったサービスから得た収益のみ」という風に自分と約束しています（笑）
そのため使える金額がそこまで多くありません。

そこで今回使える金額は5000円までという風にしました。というか初めてGoogle広告を使うのでその恐怖から金額を低くしました。

#キャンペーンを作る

ここから１日あたりの予算や配信期間、単価、配信言語、配信地域、タイトル、説明文、画像、動画などを設定していきます。

###１日当たりの予算

予算は5000円なので、１日の予算は1000円にしました。

### 配信期間

期間は予算的に５日なのですが、５日以内に5000円を超えればそこで終了とします。

###単価

アプリの広告の平均単価は28円らしいのですが、僕は20円にしました。

### 配信言語

配信言語は英語のみにしました。

### 配信地域

配信地域を「全世界」にしたのですが、先ほどの配信言語を考えるとアメリアやヨーロッパ、インドやアフリカなどが基本的な地域になりそうです。

### タイトルや説明文

ここはストアページに書いてあるようなことを書きました。特筆するようなことは書いてません。

### 画像や動画

画像はストアページに使っている物を使用しました。
動画はGoogle広告が自動で作ってくれました。画像として追加した物から作成してくれるみたいです。
でもGoogleは自分で作った動画を使用するよう勧めているので、動画をキレイに作れる方は自分で作った方がよさそうです。

#結果

結果は以下の表のようになりました。


|| 数値 |
|:-:|:-:|
|配信期間|  ５日 |
|合計費用|5323円|
|広告表示回数|25.3万回|
|クリック数|1460回|
|平均クリック単価|4円|
|アプリインストール数|291回|
|主な表示国|インド、ブラジル、フィリピン、パキスタン、トルコ、アルゼンチン|

個人的に驚いたのが「広告表示国」の上位にブラジルがあることですね。
ブラジルでは英語はあまり話さないので今回の広告を理解できたのかは不明です。

個人的に英語圏でかつEDMが流行っているヨーロッパやアメリカがメインになると思っていました。

また、

これ以外のデータは下リンクのページでグラフと一緒に紹介しています。
https://yukiit.com/programming/2145/

#最後に

Flutterを勉強し始めて、ようやく公開出来たアプリ。
せっかくリリースしたのでできるだけ多くの人にダウンロードしてもらいたいという願いがあります。
その願いをかなえるべく今回はGoogle広告を試してみました。

今回紹介した数値が、今後広告を配信しようとしている個人アプリ/ゲーム開発者の助けになれたらいいなと思います。

費用5000円ほどでアプリインストール数は291回。
これが多いか少ないかは不明なので今度は他プラットフォームで試してみたいと思います。

ここまで読んでいただきありがとうございました。

# 追記

先日、日本をターゲットとしたアプリを公開して広告を出稿したのですが本記事とは全く異なる結果になりました。

Favcoveryは5000円で291ダウンロードもありましたが、日本向けだと同じ額で50ダウンロードきりました。
配信先を日本に限定しているため表示先が少なくなってしまったからなのでしょうか。
ITエンジニアについて

# SEってなぁに
System Engineer の略です。
「こんなものがあったらいいよね」という発想を、ITの技術を駆使して、世の中に還元する人たちのことです。

# Web系ってよく聞くよね
昨今よく聞くweb系エンジニアっていったい何なのか。
WebはこのQiitaや、各種SNS等、一般ユーザー向けwebサービスまたはWebアプリケーションを開発する人を指すことが多いです。いくつかご紹介

## フロントエンド
画面のボタンの配置や(デザイナー)ボタンを押したときの動作を作る人。
次のバックエンドさんと事前にどういう情報をどのような形式でやり取りするのかを綿密に話して決めておく必要がある。

## バックエンド
フロントエンドはユーザーが直接触るのに対して、バックエンドはユーザーがほとんど触らない部分を作ります。

例としては、検索とか。
フロントから検索したい文字列が事前に決めておかれたデータ形式で渡された時に、バックエンドさんは実際に合致する結果をデータベースから引っ張り出し、順番を組み替えて、フロントエンドさんが読める形式で渡す仕事をします。

## データベースエンジニア
データベースサーバー(データを格納しておくサーバー)を立てて、どういう情報をどういう形式で保存していくかを考える人たち。

例として、ユーザー管理のTodoリストがあった場合

**投稿テーブル**

|ユーザー名|投稿タイトル|投稿詳細|投稿表示|
| --- | --- | --- | --- | 
|ano|ごはん食べる|今日はカツカレー| 表示する|
|ぼく|掃除|風呂掃除|表示しない|

**ユーザーテーブル**

|ユーザー名|mailAddr|
|---|---|---|
|ぼく|hoge@huga.ano|
|ano|ano@anonymous.clm|

こんな感じ。最近はNoSQLとかもあるから、プロダクトに沿ったデータベースサーバーを立てる必要がある。

## インフラエンジニア
サーバーの構成やスペック、ネットワークの配線等を考える人。
メディアで取り上げられたり、SNSでバズると一気にトラフィックが増えてサーバーが落ちるなんてことも。
それを防ぐためにロードバランサ入れたり、RAID構成組んだり、リージョン分けてリスク分散する等もします。
Linuxが多いのかな。

# Webまとめ
これらのほとんどすべての領域をできる人は **フルスタックエンジニア** なんて呼ばれて周りから羨望のまなざしで見つめられるよ。
また、体感、SEはWebを使ったシステム作成が多くなってきているので、webは食わず嫌いしては通れない道だとも思います。
javaなら[spring](https://spring.io/), pythonなら [Flask](https://flask.palletsprojects.com/en/2.0.x/), [Django](https://docs.djangoproject.com/ja/3.2/), PHPなら[cakePHP](https://cakephp.org/jp), [laravel](http://laravel.jp/)とかでチュートリアルを学ぶのがおすすめ。

初心者に勧めるのであればPythonのFlaskが一番簡単だと思う。
その次にRuby on railsとか。

# クラウドエンジニア
最近ホットな aws とか Microsoft Azure, Google Cloud Platform, Firebaseとか。
オンプレミスではなく、インターネットクラウドサービスを活用してシステムを構築することができる人たち。
クラウド上でインフラを作ったり、クラウド上のサーバーにサービスをデプロイしたりできる人達。
また、各種クラウドサービスに強みとコストに違いがあるので、サービスに合わせてそれらを比較検討する力も大切

# IoT
Internet of Things
モノのインターネット化
簡単に言うと、各情報機器を、インターネットと接続してインターネット越しに機器から情報を得たり、操作したりをする技術名。
IoTエンジニアはよりハードウェアに近い部分の知識と技術が必要。
もともとIoTはM2M通信のプロトコルをいうのであって...(面倒くさいオタク)

# テスタ
プロダクトの品質テストを行う人たち。
テストケースを作成し、すべてのケースが予定通りの動作をするかを確認する人たち。
また、不正な入力をした場合に、アプリやサービスが止まらないか等の確認も行う。

# セキュリティ
テスタと似ているが、さらにセキュリティの部分に特化した人たち。
いつの時代もセキュリティは必要なので、需要は絶えないし、稼げる。
ただ、難易度も高く、雰囲気的には初学者にやさしくない雰囲気がある。
セキュリティやりたかったら、まずはたくさんの技術に触れて、ボキャブラリｗ増やすところから始めたほうがいい。

# 社内SE
ちょっと見たことが無いし、知らない。。。
社内用のシステムを社内で作る人たちのことらしい。

# データサイエンティスト
ITエンジニアなのかはわからないが、情報工学をエンジニアリングしているってところでは、ITエンジニアかもしれない。(雑)
過去の大量のデータや、実測した値をもとに何らかの予測を立てて検証する人たち。
ITコンサル備忘録　その１

こんにちは！
外資ITコンサルの早２年目のMr.Tachibanaです。

今後の私の記事は主に３点を重点的に書きたいと思っています。
①ITコンサルの現実
②サイバーセキュリティ・AI系の知識
③エンジニアにとって有益な情報


①に関しては、就活や転職の方々に少しでも有益な情報があるように提供したいと思っています。
②に関しては、主に技術的な内容を備忘録のためにみなさんにも共有したいなと思いました。
③に関しては、エンジニア（エンジニアに限らず）にとって有益だなと思った情報があれば共有したいなと思っています。

## 今日は①の「ITコンサルの現実」について
みなさんITコンサルと聞くとキラキラしたイメージだと思いませんか？
実は、結論から言うとめちゃくちゃ地味な仕事が９割をしめます！残りの１割がプレゼンや提案のところで、これがあるからキラキラしているようなイメージがもたれているのだと思います。
私の1日の仕事を書きますと、
9:00-9:30 雑務（メールチェックなど）
9:30-10:30　朝会
10:30-12:00 業務
12:00-13:00 ランチ
13:00-15:00　業務
15:00-18:00　打ち合わせ
18:00-20:00　業務

というようなサイクルですね。
ちなみに業務はめちゃくちゃ細かくて地味です。
例えば、開発ツールの検証、WBSの作成・更新、打ち合わせ資料の作成など、テクニカルで細かいです。これは、本当に向き不向きがあるので自分の大学のころを振り返ってみてみてください。細かい作業は得意ですか？細部まで検討できますか？必要なもの不要なものを切り捨てできますか？など再度振り返ってみてみてください。となると、転職や就職して失敗したなと思わないようになるでしょう。正直、人事が説明会で言っていることはかなり上の話で実際の業務とはすごくかけ離れています。もちろん、大きな事言わないと夢見ている学生や他の業種の方は集まりませんよね。ただ、大きな労力を使ってコンサルに入ったのに半年でやめるのはもったいないと思います。なので、就職と転職はつねに現実を見て行ってくださいね。

## 今日の締め
今日は下記の内容を持って帰っていただければよいかなと思います。
①ITコンサルは地味な仕事が９割
②日頃の自分を振りかって細かい作業はできるかでコンサルに行くか考えてください
③常に現実を見て就職活動を！

やはり現実を見るには生で働いている人と人脈を作るのが一番だと思います。
下記のサイトではそのような若くて一番エネルギーがあるかたを集めていますので興味あればみてみてください。
https://www.tokyoeliteclub.com/

ありがとうございました！！
次回は、AWSの自動運転レースのコード紹介をしたいと思っています。
【C#】.NET6のBlazor WebAssemblyのJS呼び出しは200倍早い

## 導入
前回記事( https://qiita.com/Kujiro/items/f6d09167031320ae17bb )に引き続き、Blazor WebAssemblyのパフォーマンス改善の話です。
.NET6でC# => JS でのバイト配列の取り扱いが変わりました。破壊的変更ということでMicrosoftの方でも紹介されています。( https://docs.microsoft.com/ja-jp/dotnet/core/compatibility/aspnet-core/6.0/byte-array-interop )
実際何が変わったか試してみました。

## 何が変わったか
まずこんな感じのJavascriptを書きます。ファイルはwwwroot直下に配置するものとします。

```JS:TestScript.js
export function ByteArrayTest(arg) {
    console.log(arg);
}
```
次にC#から呼び出します。

```CS:Index.razor
// @inject IJSRuntime JSRuntime; <= これが書いてある前提
private async Task Hoge()
{
    var module = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./TestScript.js");
    var array = Enumerable.Range(1, 1 << 20).Select(x => (byte)x).ToArray();
    await module.InvokeVoidAsync("ByteArrayTest", array);
}
```

.NET5で実行するとBase64エンコードされた文字列が表示されます。

```plaintext:console
AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFy
(以下略、1.4MB)
```

.NET6で実行するとUint8Arrayが表示されます。

```plaintext:console
Uint8Array(1048576)
```

確かに破壊的変更です。破壊的変更に結構慎重なC#/.NETで破壊的変更になるということは  Base64エンコードのオーバヘッドが消えた分のパフォーマンス改善は結構大きいのでしょうか？
ちなみに、C#側のbyte[]とJS側のUInt8Arrayは流石に共有はされていません。それぞれ独立に書き換えられます。

## パフォーマンス測定
実際どれくらい差が出るのか試してみました。
PC環境は前回の記事と同様、.NET5/.NET6ともAOTはなしでReleaseビルドにします。
JS側の関数は空にします(単に呼び出しのオーバヘッドだけを測ります)

```JS:TestScript.js
export function ByteArrayTest(arg) {}
```

C#側のコードは10回実行して平均と最大をとります。
引数のサイズは1MBになるようにしています。

```CS:Index.Razor
// @inject IJSRuntime JSRuntime
private async Task DoCallTest()
{
    var module = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./TestScript.js");
    var array = Enumerable.Range(1, 1 << 20).Select(x => (byte)x).ToArray();
    List<TimeSpan> list = new();

    for (int i = 0; i < 10; i++)
    {
        var stopwatch = System.Diagnostics.Stopwatch.StartNew();
        await module.InvokeVoidAsync("ByteArrayTest", array);
        stopwatch.Stop();
        list.Add(stopwatch.Elapsed);
    }
    Result = ($"arg-size={array.Length},ave:{list.Select(x => x.TotalMilliseconds).Average()}ms,max={list.Max().TotalMilliseconds}ms");
}
```

## 結果
|環境|平均|最大|
|:-:|:-:|:-:|
|.NET5|450ms|471ms|
|.NET6|2.02ms|10.9ms|

220倍早いです。全然違いますね。

## 感想
`Span<T>`も渡せたらいいのに...
JS呼び出しの目的ってJS相互運用のみならず単にIndexedDB使いたいとかWeb Workers API使いたいとかっていうケースも多いので
stringとかもそのままUnit8Arrayで渡せると高速化できそうですね。
【Python】Pandas で株価データを取得する（その４）

# 【Python】Pandas で株価データを取得する（その４）

## はじめに

[前回](https://qiita.com/tnozoo/items/b81f89d5f7a3830d5d64)書いた株価データを取得するコードは問題があった

- 取得したい銘柄のコードをPythonコードの中に直に書いている

今回は，[前回](https://qiita.com/tnozoo/items/b81f89d5f7a3830d5d64)のコードを次のように書きかえてみる

- Excel ファイルにある銘柄一覧から株価データを取得するコード

## Pandas の read_excel で Excel 読み込みが簡単にできる

まずは Excel ファイルを用意する

用意した Excel ファイルは，
A列に銘柄コード（列名: code），B列に銘柄名（列名: company）となっている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385512/94060b34-48f3-7b94-905a-ce160b31704a.png)
pandas を import し，

```python
import pandas as pd;
```

あとは，read_excel で読み込んだ銘柄コード列，銘柄名列をそれぞれリストに変換

```python
df = pd.read_excel('step04.xlsx', sheet_name = 'Sheet1', dtype = str);
codeList = df['code'].tolist();
companyList = df['company'].tolist();
```

まとめると，次のようなコードになる

```python:step04.py
import pandas as pd;
import pandas_datareader.data as pdr;
import datetime;
from dateutil.relativedelta import relativedelta;

def getToday():
    return datetime.datetime.now();

def getMonthAgo(day, month):
    return (day - relativedelta(months = month));

def main(codeList, companyList):
    ed = getToday();
    st = getMonthAgo(ed, 12);
    for code, company in zip(codeList, companyList):
        df = pdr.DataReader(code + '.T', 'yahoo', st, ed);
        print('%s [%s]-[%s]' % (company, df.head(1).index[-1], df.tail(1).index[-1]));

if __name__ == '__main__':
    df = pd.read_excel('step04.xlsx', sheet_name = 'Sheet1', dtype = str);
    codeList = df['code'].tolist();
    companyList = df['company'].tolist();
    main(codeList, companyList);
```

実行した結果は次のようだ

```
❯ python step04.py
トヨタ [2020-11-24 00:00:00]-[2021-11-19 00:00:00]
日産 [2020-11-24 00:00:00]-[2021-11-19 00:00:00]
ホンダ [2020-11-24 00:00:00]-[2021-11-19 00:00:00]
```

## おわりに

Excel ファイルに書かれた銘柄の
１年前から現在までの期間で株価データを取得することができた

便利すぎるぜ，Python

株価値動き分析のための，最初の一歩を踏み出せた気がする

今後は，

- ローソク足
- MACD
- 一目均衡表
- ボリンジャーバンド

などのチャートを描き，
売買のタイミングを教えてくれるようなコードを書いてみるつもりだ
UnityでAndroidでビルドした後にSlackにapkを自動アップロードする

とにかく便利なので、Unityでモバイルゲームを作っている人はみんなやってほしい。他のメンバーへのapk共有にも便利。

## 事前準備
https://api.slack.com/apps の「Create New App」から slack appを作成します。

左のサイドバーから `OAuth & Permissions`　にアクセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151852/9b025e01-b92b-b5e6-7fe7-e67e413a90f8.png)

`Bot Token Scopes` に以下を追加。

* `files:read`
* `files:write`
* `chat:write`


`Install Workspace` で自身のワークスペースに連携しましょう。 `Bot User OAuth Token` に `xoxb-` で始まるbotトークンをコピーしておきます。

## スクリプトの作成

`Editor/` ディレクトリの下（ない場合は作成して良い）に次のスクリプトを配置する。

```C#
using System.Collections.Specialized;
using System.Net;
using System.Text;
using UnityEditor;
using UnityEditor.Callbacks;
using Debug = UnityEngine.Debug;

namespace Editor
{
    public static class SlackPoster
    {
        [PostProcessBuild]
        public static void OnPostProcessBuild(BuildTarget target, string path) {
            if (target == BuildTarget.Android) {
                Post(path);
            }
        }
        
        private static void Post(string path) 
        {
            var client = new WebClient();
            var parameters = new NameValueCollection();
            parameters["token"] = "トークン";
            parameters["channels"] = "channel名";
            parameters["initial_comment"] = "できたよ。";
            client.QueryString = parameters;

            byte[] responseBytes = client.UploadFile("https://slack.com/api/files.upload", path);
            string responseString = Encoding.UTF8.GetString(responseBytes); 
            Debug.Log(responseString);
        }
    }
}
```

`parameters["channels"]` にapkをアップロードするチャンネル名(先頭`#`は含まない)を指定し、
`parameters["token"]` に先ほどコピーしたbotトークンを指定しておいてください。

**ただし、botトークンは秘匿情報なので、ソースコードに直書きした場合は、パブリックリポジトリにコミットしてはいけません！**

上記のファイルを `.gitignore` に追加するなどの対応をしましょう。