OmniAICreator/Qiita-1.07M huggingface dataset:
docker-composeの変数&複数定義を使用する

## ■docker-compose.yml で変数を使用

```docker-compose.yml
version: "3.7"

x-var: &NAME
  "app-test"

services:
  app:
    container_name: *NAME
```

## ■docker-compose.yml で環境変数を使用

```docker-compose.yml
version: "3.7"

services:
  app:
    # docker-composeを呼び出す前に「NAME」を設定しておく
    container_name: ${NAME}
```

※ 「app:」の個所を「${NAME}:」のように定義は出来ません

## ■複数のdocker-compose.yml の設定をマージして使用

※後からコンテナーを増やしていく際、共通の定義があるなら便利です

```docker-compose-base.yml
version: '3.7'

services:
  app:
    container_name: app-test
    volumes:
      - /common/:/common/
    networks:
      - custom-network
```

```docker-compose-app.yml
version: '3.7'

services:
  app:
    build:
      context: .
      args:
        TEST_1: 123
```

```bash
docker-compose -f docker-compose-base.yml -f docker-compose-app.yml up -d --build
```
styleganはゴールデンクロスに微笑む

# 著作権フリーな人物写真が欲しい

512個の数字を与えるといくらでも作ってくれる
https://github.com/NVlabs/stylegan

tensorflow1x指定なのでgoogle colab上に環境を作成して実行
https://qiita.com/Phoeboooo/items/12d21916de56d125f0be

# 女の人の写真が欲しかった、、
ランダムに数値を生成して何度も実行した中から女の人の写真を選ぶのはつらい、、
何か法則はないものかと思い株価の時系列を突っ込んでみたところ、3/25から過去512日のソニーの株価時系列データを入れたところ以下になった
![sony_2019-02-14-2021-03-25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328600/62899ace-3a32-5ec1-b698-e11bfe2f7733.png)

おっさん、、
ほかの会社ではどうだろうと思い、3/29から過去512日のトヨタの株価データで作成した画像。
かわいい、、
![トヨタ_2019-02-18-2021-03-29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328600/8f085a90-2de8-0dbc-2edd-b400b46f4f1f.png)

# 時系列データを連続して投入してみる
女の人ではないものの値が変われば当然画像も変わるので、moving windowみたいにどんどん値を変えて入れてみればよいのでは？ということでやってみた
![resize_toyota_tile.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328600/763c83fe-b6c9-f7b9-4306-4715681a8986.png)
お、女性が現れた

# いつ女性が現れたのか
トヨタの株価はこんな感じ
![210404トヨタ_stock_price.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328600/b36fdf51-7fad-3655-1f8e-c42030dfbdf4.png)
結構変動している。女の人の顔が出てきたのは大体8月ぐらいなので、下げ傾向が上昇に転じたあたりか、、、ゴールデンクロスした銘柄とかもっと出る！？

# 確かめてみる
2021/3/29時点でゴールデンクロスの可能性のあった銘柄をいくつか確認
巴コーポレーション
![tomoe_2019-02-18-2021-03-29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328600/00879d02-7197-3891-ad04-866363fc6a1e.png)

日本空調サービス
![nihonkutyo_2019-02-18-2021-03-29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328600/723d9243-911a-bd55-8e1f-518a07e37d96.png)

ソネック
![sonec_2019-02-18-2021-03-29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328600/f954e179-9ffd-5fed-21f9-5f559f12a14a.png)

お、当初の目的とは異なるがかわいい赤ちゃんの写真が欲しい場合はゴールデンクロスした銘柄をstyleganに入れればよいようだ

# 余談
出来上がった画像をぼーっと眺めているとゴールデンクロス銘柄の６か月前後過去の画像は女性っぽい
巴コーポレーション(9/30)
![tomoe_2018-08-27-2020-09-30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328600/009b9d7c-01bc-e07c-43fe-dafff1a3cfc0.png)

日本空調サービス(10/6)
![nihonkutyo_2018-08-30-2020-10-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328600/68eda52c-a12c-383c-5322-fbd2dfc53743.png)

ソネック(9/30)
![sonec_2018-08-27-2020-09-30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328600/20c79a53-d55e-457d-6ca8-b229eaff2102.png)

# 最後に
* わらかしのための記事です！！検証などはいい加減です！！
* 生成される画像を制御できるようになってきているみたいなのでいずれもっと効率よく狙った著作権フリーの画像を作ることができるようになるだろう
* それはそれとして動画にすると年連や性別が自然に変化してゆくので面白かった
* 「できた画像をさらに性別判定すればよいのでは？」と思ったが大手クラウドサービスのAIは顔写真から性別を判断しない。
* その他の提供されているAIで試してみたところ「男の娘」と判定されたりした
* そもそも顔だけで「おじさん」と「おばさん」の判別は難しいと思った（私自身が途中でわからなくなっていた、、そういう意味で大手クラウドサービスが性別判定をしていないのはご尤もなのかも）

# 使用したもの
- google colab(tensorflow1xの環境を簡単に作れるのが良かった）
- [stylegan](https://github.com/NVlabs/stylegan) (pretrainedのモデルを使用。都度コピーできるようにgoogle driveに配置）
-  yahoo_finance_api2 (株価取得に使用。share.pyからadj_closeの部分を削除して（KeyError回避のため）
-  処理に詰まるたびにエラーメッセージに合わせて色々なサイトを参照。先人達に感謝
git よく使うコマンド

##コミットのコメント上書き
基本
`git commit --amend -m "新しいコミット名"`
例
`git commit -m "a" `
`git commit --amend -m "b" `

##ワークツリーの取り消し
`git checkout （. or ファイル名）`


##ステージングの取り消し
`git reset （ファイル名） `


##直前のコミット取り消し
ステージングされた変更は残る `git reset --soft HEAD^`
一個前のコミット地点まで戻る  `git reset --hard HEAD^`

##特定のコミット地点まで戻る
コミットのログ表じ　`git log` 
1)`git reset --hard　**********************************`
そのコミット地点まで戻る。それ以降のコミットは消される<br>
2)`git checkout **********************************`
そのコミット地点まで戻る。それ以降のコミットは消されない
Object of class stdClass could not be converted to string

忘れないように書いときます。

index.blade.phpに編集ボタンをhrefでつけようとしたところ
"{{route('bodies.edit',$body)}}でエラー

Object of class stdClass could not be converted to string

cmdでphp artisan route:listでもルーティング先は間違ってないように見える。
と、いろいろ調べた結果
よくわからないがともかく第二引数の$bodyのクラスが文字列として認識されてないらしい。なので、第二引数の部分を
(print_r($body, true))
と書き換えることにより無事成功。破れかぶれ。
誕生日の曜日を確認してみる


Python学習の一環で、自分の生まれた曜日を確認するプログラムを作成してみました。
Zëllerの公式を使うと、1582年10月15日以降の日付から曜日を計算することができます。

整数(int)として年をyear、月をmonth、日をdayとした時、曜日(weekday)は
weekday = (year + (year // 4) - (year // 100) + (year // 400) + ((13*month+8) // 5) + day) % 7　という式で計算できます。
曜日は整数として0が日曜、1が月曜、...、6が土曜となります。
但し、1月と2月はそれぞれ前の年の13月、14月として計算する必要があり, 例えば、2021年1月というのは上の計算式では、2020年13月として計算しなければなりません。

流れとしまして、生年月日入力後、Zëllerの公式を使い、出力するという簡単な流れになります。
使用環境としては、Google Colaboratoryになります。

早速、生年月日の入力欄を設けましょう。int型で表示します。

```python
year = int(input('年> '))
month = int(input('月> '))
day = int(input('日> '))
birthday = str(year)+'年'+str(month)+'月'+str(day)+'日'
```

数値型で入った数字を文字列型に変換し、。1月と2月は、前年のそれぞれ13月・14月として扱います。そして、その場合、前年の年をベースとした13月、14月になり、計算式を入れる。

```python

if month == 1 or month == 2 :
    year = year - 1
    month = month + 12
wkday = (year + (year // 4) - (year // 100) + \
  (year // 400) + ((13*month+8) // 5) + day) % 7
```

曜日は、整数として0が日曜、1が月曜、...、6が土曜となるよう設定します。

```python
if wkday == 0 :
    wkstr = '日曜日'
elif wkday == 1 :
    wkstr = '月曜日'
elif wkday == 2 :
    wkstr = '火曜日'
elif wkday == 3 :
    wkstr = '水曜日'
elif wkday == 4 :
    wkstr = '木曜日'
elif wkday == 5 :
    wkstr = '金曜日'
elif wkday == 6 :
    wkstr = '土曜日'
print(birthday+'は'+wkstr+'です。')
```

**まとめコード**

```python
year = int(input('年> '))
month = int(input('月> '))
day = int(input('日> '))
birthday = str(year)+'年'+str(month)+'月'+str(day)+'日'
if month == 1 or month == 2 :
    year = year - 1
    month = month + 12
wkday = (year + (year // 4) - (year // 100) + \
  (year // 400) + ((13*month+8) // 5) + day) % 7
if wkday == 0 :
    wkstr = '日曜日'
elif wkday == 1 :
    wkstr = '月曜日'
elif wkday == 2 :
    wkstr = '火曜日'
elif wkday == 3 :
    wkstr = '水曜日'
elif wkday == 4 :
    wkstr = '木曜日'
elif wkday == 5 :
    wkstr = '金曜日'
elif wkday == 6 :
    wkstr = '土曜日'
print(birthday+'は'+wkstr+'です。')
```

**出力結果**
例えば、2021年3月31日で試すと、水曜日と表示されています。検証してみましょう。

```
年> 2021
月> 3
日> 31
2021年3月31日は水曜日です。
```
webから確認したカレンダーを見ると、確かに水曜日になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/973091/ec0da682-d8cf-ed2f-38db-e2cd5e9700e9.png)

今回は、誕生日を曜日確認してみるという題目で行いましたが、特に誕生日に限らず、未来の曜日も確認出来ますので、予定計画を作る際に活用できそうです。
[ServerlessFramework]aws-sdkを用いてAWS SNSにメッセージを送信する

aws-sdkを用いてAWS SNSにメッセージを送信する方法を解説します。

## 1. create
```
serverless create -t aws-nodejs-typescript -n send-sns-sample -p ./send-sns-sample
```

## 2. ymlファイルを作成
デフォルトのtsファイルではなく、ymlファイルに変更します。
理由は公式やその他serverlessに関する記事がymlを採用しているためです。

完成型を以下です。
要点のみ解説していきます。

```yml:serverless.yml
service: send-sns-sample

frameworkVersion: '2'

provider:
  name: aws
  runtime: nodejs14.x
  region: ap-northeast-1
  stage: ${opt:stage, self:custom.defaultStage}
  deploymentBucket:
    name: ${self:provider.stage}-serverless-deployment
  profile: ${self:custom.profiles.${self:provider.stage}}
  versionFunctions: false
  logRetentionInDays: 60

plugins:
  - serverless-webpack

custom:
  defaultStage: dev
  webpack:
    webpackConfig: "./webpack.config.js"
    includeModules: true
  profiles:
    dev: k.ikeura
    stg: k.ikeura-staging
    prd: k.ikeura-production
  otherfile:
    environment:
      dev: ${file(./conf/dev.yml)}
      stg: ${file(./conf/stg.yml)}
      prd: ${file(./conf/prd.yml)}

functions:
  index:
    handler: src/handler.index
    environment:
      Topic_Arn: "${self:custom.otherfile.environment.${self:provider.stage}.Topic_Arn}"

resources:
  Resources:
    SNSTopic:
      Type: AWS::SNS::Topic
      Properties:
        DisplayName: SNS Topic
        TopicName: ${self:service}_topic

```

**解説**

- resources以下にSNSトピックの作成を定義しています。
- functions.index.environment.Topic_Arnに環境変数Topic_ArnにトピックのARNの値を持たせています。後述するコード部分で参照します。
    - serverlessでの環境変数設定のベストプラクティスはクラスメソッドさんの[こちらの記事](https://dev.classmethod.jp/articles/serverless-framework-conf-change/)が非常にわかりやすいです。

## 3. ソースコード
まずは完成したソースコードを載せ、要点を解説していきます。

```typescript:sendMessage.ts
import * as AWS from 'aws-sdk'
import type { params, order } from 'types'
export const sendMessage = async (order:order) => {
  const env = process.env
  const SNS = new AWS.SNS({apiVersion: '2010-03-31', region: 'ap-northeast-1'});
  const vendorCode: string = order.vendor_code
  const stringOrder:string = JSON.stringify(order)
  try {
    const params: params = {
      Message: stringOrder,
      MessageAttributes: {
        'vendor_code': {
           DataType: 'String',
           StringValue: vendorCode,
         }
      },
      TopicArn: env.Topic_Arn
    }
    await SNS.publish(params).promise()
  } catch (err) {
    console.log(err)
  }
}
```

解説の前にこの関数の仕様をざっくり説明します。
ショップの受注情報であるorderオブジェクトを受け取り、メッセージ属性vendor_codeにorder.vendorCodeを設定し、snsトピックにstringOrderを送信しています。

**解説**

- ```const SNS = new AWS.SNS({apiVersion: '2010-03-31', region: 'ap-northeast-1'});```でaws-sdk.SNSを定義。
    - requireではなく、importすることをお勧めします。型やメソッドをエディタが参照してくれます。
- paramsを設定します。
    - Message: 送信するメッセージの内容
    - MessageAttributes: 今回はvendor_codeプロパティにorder.vendorCodeを設定している。
    - Topic_Arn: 送信先のトピックARN
- ```await SNS.publish(params).promise()```
    - publishメソッドを用いてトピックにメッセージを送信

## 3. テスト
確認する方法のみ記載します。
AWS CloudWatchのメトリクスからメッセージ受信件数を確認して、送信されたかどうか確認できます。
送信したメッセージを閲覧する方法はないのだろうか。。？？🤔🤔🤔

## 参考リンク

- https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SNS.html
- https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SNS.html#publish-property
AWSでWebアプリをデプロイする方法(Java)③

#請求情報を管理する
実際にAWSを利用していく前に、料金について説明します。AWSは、従量課金制です。
一定料金を超えたらアラートを受け取るように設定することでコストをコントロールします。

###利用環境
OS:MacOS
ブラウザ:Chrome

###前提条件
AWSアカウントの取得が完了している状態(ユーザーの追加は完了していなくても大丈夫です)
まだ、アカウントを追加していない方は[こちら]
(https://qiita.com/kunrenyouAcount/items/97e0008942aea4e191b4)

##現在の課金情報を確認する
AWSアカウントでサインインすると下記の画面が表示されます
※IAMユーザーでは操作できないため、AWSアカウントでサインインし直してください
![スクリーンショット 2021-04-04 1.07.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066052/e3f593d5-56a2-76f5-5a11-a7d03b050e36.png)

画面右上部のアカウント名をクリックし、[マイアカウント]を選択
![スクリーンショット 2021-04-04 11.51.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066052/4ba068da-92ac-61c3-4bea-2d6ac628116a.png)

画面左側の[請求書]を選択
ここで月毎の請求書を確認できます
![スクリーンショット 2021-04-04 1.09.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066052/5b9753c1-468f-7f4e-0571-2879194f4b66.png)

##Cost Explorerを起動する
画面左側の[Cost Explorer]を選択
![スクリーンショット 2021-04-04 1.09.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066052/5d670275-5fbd-d96a-cee1-17a3e7b1ce06.png)

画面右側のオレンジ色の[Cost Explorerを起動]を選択
コストエクスプローラーが情報収集をはじめ、24時間程度経過すると各サービスのコストが表示されるようになります
![スクリーンショット 2021-04-04 1.10.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066052/3087f9c7-a2ff-09a7-dc52-843e7a312dfc.png)

##一定金額を超えたらアラートされるようにする
###予算を作成する
画面左側の[Budgets]を選択
![スクリーンショット 2021-04-04 1.11.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066052/4c1181f9-5efe-7976-230d-73a8f75f5c2d.png)

###予算タイプの選択
[コスト予算]にチェックを入れ、[予算の設定]を選択
![スクリーンショット 2021-04-04 1.12.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066052/67d77a51-dab6-ff30-a186-4c16091cd08e.png)

###名前、期間、予算を入力する
下の図のように入力し、[しきい値を設定する]を選択
![スクリーンショット 2021-04-04 1.13.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066052/0fdec8aa-6d38-76f0-944f-cc6343662feb.png)
![スクリーンショット 2021-04-04 1.14.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066052/f8df6b22-89e5-4baa-0cef-b868195fe82c.png)

###通知を設定する
下の図のように入力し、[予算の確認]を選択
![スクリーンショット 2021-04-04 1.16.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066052/9c5a33e8-c302-f3ec-1633-04cf07988f8b.png)

###確認
間違いがないか確認し、間違いがなければ[作成]を選択
![スクリーンショット 2021-04-04 1.16.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066052/cb617aff-a129-9730-1bd9-c4280bce8bbd.png)

###予算が作成された
![スクリーンショット 2021-04-04 1.17.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1066052/5f39d769-faca-0bca-bd68-c86355bcf04f.png)

#AWSでWebアプリをデプロイする方法④
[EC2インスタンスを作成する](https://qiita.com/kunrenyouAcount/items/9537ecc45d34349e9759)
プログラミング

#プログラミングとはなんでしょう
だれにでも分かりやすいようにまとめてみました。




##1.0 プログラム
パソコンやスマートフォン、ゲームなどのコンピュータや機械は何かを命令しなければ動きません。この命令をあたえるために必要なものがプログラムです。プログラムには、何かを行うための手順や方法が書かれています。テレビのリモコンの＋ボタンをおすと音が大きくなる、これにもプログラムが使われています。コンピュータや機械はこのプログラムの命令通りに動きます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352037/5e17f0a3-b440-f811-ec1b-ec3ae77dd520.png" alt="ロボットを操縦している絵" title="ロボットを操縦している絵" width="400" height="300">










##2.0 プログラミング
プログラムをつくることをプログラミングと言います。プログラミングはパズルのようなものなので、いくつかの手続きを組み合わせて一つのプログラムを作ることもあります。コンピューターが正しく動くように、計算の手順や方法をくわしく書きます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352037/f826c2c2-05eb-dfd7-f9f9-c0ca95890f0d.png" alt="プログラミングを作る女の子" title="プログラミングを作る女の子" width="400" height="300">


















##3.0 プログラミング言語
わかりやすくいえばコンピューターが理解できる言葉＝プログラミング言語であり、コンピューターに命令できる言語のことです。プログラミング言語はプログラミングを行うときにつかう言葉です。プログラミング言語にはC言語、Java(ジャバ)、JavaScript(ジャバスクリプト、Javaとは別の言語)などありますが、ゲームをつくる時に使われるUnity(ユニティー)でつかうのはC#(シーシャープ)とよばれる言語です。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352037/37c66fad-68f9-e4f9-2391-9878b2cfdcc5.png" alt="プログラミング言語" title="プログラミング言語" width="300" height="200">












##4.0 テキストエディタ
パソコン上でプログラムを書くことのできるソフトです。プログラミング言語を入力してプログラムを作るときに使われます。テキストエディタを使えば効率的に早く簡単にプログラムを書けます。Unityと連携しているテキストエディタはVisualStudio(ビジュアルスタジオ)でマイクロソフト社が提供しているアプリケーションで、学生や個人開発者のために無料で公開されています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352037/d6894538-f26d-2b44-0114-1d6d1f6b666f.png" alt="テキストを書く男の人" title="テキストを書く男の人" width="400" height="300">









##5.0 Unity(ユニティー)
ゲームを作るための開発をおこなうかんきょうです。ゲーム開発に必要な機能をはじめから用意してくれていますので、ゲームエンジンとよばれます。
このUnityのおかげでゲームがとても作りやすくなっています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352037/75aad56c-7330-6fbf-36d8-7daed29e13f5.jpeg" alt="VRゲームをする子供たち" title="VRゲームをする子供たち" width="300" height="200"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352037/2bbc0afd-feb5-ec7a-00f2-93bb4e5b9dcf.jpeg" alt="ゲームの結果" title="ゲームの結果" width="300" height="200">
毎回忘れるVBSの引数取得方法をメモってみた

Option Explicit
 
'引数が無い場合は終了する
If Wscript.Arguments.Count = 0 Then
  WScript.Quit
End If
 
'1番目の引数
WScript.Echo "引数1：" & Wscript.Arguments(0)
'2番目の引数
WScript.Echo "引数2：" & Wscript.Arguments(1)
rails カラム追加

##カラムの追加
基本の書き方　
`rails g migration クラス名（=Addカラム名Toテーブル名) カラム名:データ型`
クラス名のカラム名は一つなら、そのカラム名。複数ならColumns。意味あるカラム

##例
1)user_tableにnameカラムを追加
`rails g migration AddNameToUsers name:string`
2)userにsign_in用（複数）追加
`rails g migration AddSing_in_columnToUsers name:string age:integer`
個人開発でエンジニア向けライブ配信サービスをリリースしました🎉

#はじめに
[StackLive](http://stacklive.jp/about)というエンジニア向けライブ配信サービスを作りました。技術記事の解説や、作業風景の配信をしながらエンジニア同士でコミュニケーションがとれるサービスです。
投げ銭機能で対価を得ることも可能となります！
![output.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1008044/cfa3ec54-876b-7dac-272c-fa172f9ba14e.gif)
##使用用途
★QiitaやZenn、自社メディアに投稿した技術記事の解説
・質問コーナー
・作業配信
#作ったきっかけ
結論から言うと、AtCoderという競技プログラミングのYouTubeライブを見たのがきっかけです。そこではエンジニア同士がコミュニケーションを取り合い、スパチャが飛び交っていました。
それを見た時に、有益な技術情報をライブ配信してコミュニケーションが取れるプラットフォームがあれば使いたい！と思ったのがきっかけです。

AtCoderのYoutubeを知らない方はこちら→(https://www.youtube.com/channel/UCtG3StnbhxHxXfE6Q4cPZwQ)

#アーキテクチャ

より詳しい技術やサービス構成につきましては[Zenn](https://zenn.dev/tttch/articles/4564288265213b)で解説してます。興味ある方はこちらもご覧ください！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1008044/a9559f17-8ee3-32c5-2acf-761ed184ee6c.png)

簡単に説明すると、StackLiveはAmplifyを使いサーバーレスで構成されています。なので基本的にはインフラはAWS,フロントエンドはReactを使って作りました。


#大変だった事、苦労したこと
###1.個人開発だった
このサービスは基本的に僕一人で作りました。2020年11月ごろに思いつき、約5ヶ月でリリースしました。僕は社会人なので、平日仕事終わり18時〜3時ごろまでの作業と土日には丸一日の作業時間でした。当時は新卒で仕事を覚えるのと並行して作っていたので、大変だったなぁと思います。

今後は信頼できる仲間を探して、組織としてサービスを運営していきたいなと思っております！
###2.なにを基準にトレンド配信にするか
StackLiveにはトレンドでソートするページがあるのですが、これをなにを基準にしてソートにするか少し悩みました。
結論としては、リアルタイムの視聴者数が多いものからソートするような実装にしています。

具体的にはLambdaの定期実行機能を使って、1分間に1回AgoraのAPIを叩き、特定のチャンネルの視聴者数を取得し、DBを更新するような実装にしています。
※以下が配信周りの構成図です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1008044/b23af0a4-f5ce-2698-7afd-9274b8f967fc.png)

※今後は急上昇で視聴者数が伸びている配信なども合わせてトレンドのアルゴリズムを考えていければと思ってます。

###3.DynamoDBには複数のユニークな値を設定する事ができない。
これはDynamoDBの仕様上の問題らしいのですが、同一カラム内で一意の値を複数作る場合は工夫しなくてはいけないらしいです。
要するに、ユーザーテーブルでIDの他にメールアドレスの重複チェックなどができません。

解決策としては、少し複雑になりますがプライマリキーにはUNIQUE制約があることと、DynamoDBのトランザクション処理を組み合わせてデータの作成、更新、削除を対応しました。

具体的に以下のようなデータを作成するとします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1008044/ef76fee9-7804-0579-894e-693fd39daa85.png)
このままだと次の新規作成時、`id`はユニークな値なので重複するとエラーを吐くのですが、user_idなどは重複していても作成する事ができてしまいます。

そこで、新しいユーザーを作成する時に他にも2つの値を作成します。他の2つの値には
属性名#値とする事で一意の値を実現させてます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1008044/99a04e8e-3d49-5882-b2a0-d14efd2c406f.png)
こうする事で重複があるとエラーを吐き、トランザクション処理が失敗になり、ユーザーが作成する事ができなくする事が可能になりました。



###Amplifyを初めて触った。
このサービスでAmplifyを初めて触りました。基本的には`amplify init` `amplify add api`などのコマンドを打ち込めばインフラが勝手に出来上がります。
便利が故に知らない間にロールが出来てたり、使用上のバグなどに直面したりしてインフラを1から作り直すみたいな事を何度もしました。

またAmplify自体がサービスとして日が浅いので、情報が少ないのも大変な点でした。
これからのアップデート情報を静観していこうと思います。


#まとめ
エンジニア向けのライブ配信サービスをリリースしてみて、個人開発で大変な事もありましたが、Twitter上でお褒めの言葉もいただきとても嬉しかったです。
もし気になった方はぜひ一度、配信をしていただけると嬉しいです。

https://twitter.com/shimizu_taichi_/status/1377923860268376067?s=29
[ServerlessFramework]IAMロールの設定をserverless.yml内で行い、SecretManagerからシークレットを取得する

serverless.yml内でIAMRoleを設定する方法を解説します。
SecretManagerからシークレットを取得する方法は、[こちら](https://qiita.com/iamsukesan/items/37d0d6668c4e43410463)を参考にしてください。

### 1. create
今回はNode.js&TypeScript環境で実行します。

```
serverless create -t aws-nodejs-typescript -n secret-sample -p ./secret-sample
```

### 2. ymlファイルへ変更
serverlessを用いてNode.js&TypeScript環境のlambda関数を作成すると、デフォルトではserverless.tsが設定ファイルとして作成されます。
typeやメソッドなどをエディタが推論してくれて便利ですが、公式や記事にはymlで書かれていることが多いので、僕はymlファイルに変更しています。
エディタやコマンドラインからRenameを行い、yml形式に変更してください。

### 3. serverless.yamlを編集
ひとまず完成形です。

```yml:serverless.yml
service: secret-sample

frameworkVersion: '2'

provider:
  name: aws
  runtime: nodejs14.x
  region: ap-northeast-1
  stage: ${opt:stage, self:custom.defaultStage}
  deploymentBucket:
    name: ${self:provider.stage}-serverless-deployment
  profile: ${self:custom.profiles.${self:provider.stage}}
  versionFunctions: false
  logRetentionInDays: 60
  iam:
    role:
      statements:
        - Effect: Allow
          Action:
            - secretsmanager:GetSecretValue
            - secretsmanager:DescribeSecret
          Resource:
            - !Join
              - ":"
              - - arn
                - aws
                - secretsmanager
                - !Ref AWS::Region
                - !Ref AWS::AccountId
                - secret
                - order-notification-*

plugins:
  - serverless-webpack

custom:
  defaultStage: dev
  webpack:
    webpackConfig: "./webpack.config.js"
    includeModules: true
  profiles:
    dev: k.ikeura
    stg: k.ikeura-staging
    prd: k.ikeura-production
  otherfile:
    environment:
      dev: ${file(./conf/dev.yml)}
      stg: ${file(./conf/stg.yml)}
      prd: ${file(./conf/prd.yml)}

functions:
  index:
    handler: src/handler.index
    environment:
      SECRET_NAME: "${self:custom.otherfile.environment.${self:provider.stage}.SECRET_NAME}"

```

iamroleに関する設定は、以下です。

```yml:serverless.yml
iam:
    role:
      statements:
        - Effect: Allow
          Action:
            - secretsmanager:GetSecretValue
            - secretsmanager:DescribeSecret
          Resource:
            - !Join
              - ":"
              - - arn
                - aws
                - secretsmanager
                - !Ref AWS::Region
                - !Ref AWS::AccountId
                - secret
                - "${self:custom.otherfile.environment.${self:provider.stage}.SECRET_NAME}"-*
```

**注意点**

- ```iam.role.statements```ではなく、```iamRoleStatements:```と書いている記事がありますが、この書き方は非推奨になりました。```iamRoleStatements:```のままdeployすると、warningで非推奨であるというメッセージが出るかと思います。  
- Actionに```secretsmanager:DescribeSecret```を入れている理由はSecretManagerから取得する値をキャッシュ化する際に必要だからです。今回はその実装方法については説明しません。詳しくは[公式](https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/patterns/cache-secrets-using-aws-lambda-extensions.html)を参照。
- Resouce以降はcloudformationの省略記法に習っています。詳しくは[こちらの記事](https://qiita.com/yasuhiroki/items/8463eed1c78123313a6f)を参照。

これでiamroleの設定ができました。
シークレットの参照の方法ですが、今回使用した環境でaws-sdkを用いて参照する方法を[こちらの記事](https://qiita.com/iamsukesan/items/37d0d6668c4e43410463)にまとめています。
【初心者向け】初めてのGitHub導入。バージョン管理開始！


こんにちは。Sです。

みなさんはコードを書いていて「元に戻したい」と思った時、どうしてますか？
あらかじめファイルを複製してバックアップをとる方法もありますが、開発が進むにつれてファイルの量が増えたり、ファイル名が複雑になっていくことで、管理が難しくなって行くと思います。

それを解決するのが、バージョン管理システムの「GitHub」です。

今回はGitHubでバージョン管理を行うために、その導入手順導入の手順を解説していきます！

##STEP1　GitHubアカウントを作成する
まず、[GitHub](https://github.com/)でアカウントを作成します。

【Sign up】からUsername / Email / Password を入力すれば簡単にアカウントを作成できます。
有料のプランも用意されていますが、個人開発であれば無料で使えるFreeプランでまず問題ありません。また、後に変更も可能です。

その後、登録したメールアドレスに認証メールが届くので、内容に従ってユーザー認証を行いアカウント登録を完了させましょう。

##STEP2　リモートリポジトリを作成する
![github_img_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614019/9e197ca5-bd26-66bd-b9d6-696946f1acf4.png)
【Repository name】に任意のリポジトリ名を入力して【Create repository】でリモートリポジトリの作成完了です。


Public / Private を選択できますが、これはリポジトリの可視性を選択することで、リポジトリにアクセスできるユーザを制限することができます。個人開発の場合は基本デフォルトのPublicでいいんじゃないかと思います。[リポジトリの可視性について詳しくはこちら](https://docs.github.com/ja/github/creating-cloning-and-archiving-repositories/about-repository-visibility)


##STEP3　PCにgitをインストールする
ここからは、ターミナルでの操作です。
以下のコマンドを打ってgitをインストールします。

```ruby:ターミナル
 $ sudo apt-get update
 $ sudo apt-get install git
```
インストールが終わったら、下記のコマンドでgitのバージョンを確認します。

```ruby:ターミナル
$ git --version
```
【git version 2.29.2】のようにターミナルに表示されればGitのインストールは完了です。


###初回のみユーザー名とメールアドレスを設定する
Gitを使用するために、ユーザー名とメールアドレスを初回のみ登録する必要があります。

```ruby:ターミナル
 $ git config —global user.name <ユーザー名>
 $ git config —global user.email <メールアドレス>
```
入力が完了したら下記コマンドを打って確認できます。

```ruby:ターミナル
 $ git config --global --list
```

##STEP5　ローカルリポジトリを作成する
下記の手順でローカルリポジトリを作成します。

####1. 作業ディレクトリに移動

```ruby:ターミナル
 $ cd <作業ディレクトリへのパス>
```

####2. Gitリポジトリを作成する
作業を行いたいディレクトリにバージョン管理を行いたいファイルを作成し、下記コマンドを実行します。

```ruby:ターミナル
$ git init
```
こちらを実行すると現在のディレクトリに「.git」というリポジトリを構成するディレクトリが作成されます。【.git】にはGitで使用するファイルが新規に作成されますが、基本中身は触らなくてOKです。

また、今後既に存在するリポジトリの初期化を行いたい場合にもinitコマンドを使用することができます。

####3. ステージング
```ruby:ターミナル
$ git add .
```
今回追加したいファイルをステージングさせます。

####4. 初回のコミット
今回のコミットは”first commit”というコメントで実行しました。こちらのコミットコメントはチーム内のルールに従うなど、任意のもので実行してください。

```ruby:ターミナル
$ git commit -m "first commit"
```

##STEP6　リモートポジトリを登録
次にリモートポジトリを登録する必要があります。GitHub上で、先ほど作成したリポジトリのページに移動し、緑色の【Code】というボタンをクリックすると【https://github.com/ユーザ名/リポジトリ名.git】 のURLが発行されているのでこちらをコピーして、ターミナルに下記のコマンドを実行します。
![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614019/513c69a3-72d0-3dbd-8b74-dc260173d9c6.png)


```ruby:ターミナル
 $ git remote add origin <URLアドレス>
```
確認は下記のコマンドでできます。

```ruby:ターミナル
 $ git remote -v
```

##STEP7　 リモートリポジトリに反映
最後に下記コマンドでリモートリポジトリに反映してGitHub導入完了です。

```ruby:ターミナル
$ git push origin master
```

ここまできたら、あとは作業ブランチを作成してゴリゴリ編集して行きましょう！
C++でPhoton Realtimeを扱う 〜環境構築編〜

# はじめに
無料でオンラインのアプリケーションが作れるサービス、[Photon](https://www.photonengine.com)。結構便利なんですが、日本語・C++使いの僕らには少し困ったことが

***日本語で書かれたC++の資料がほとんどない!!!***

ということで、この記事(シリーズ)ではPhoton (Realtime)をC++で扱うための解説をやっていきます。今回は環境構築編です。

Mac(Xcode)とWindows(Visual Studio)で導入が変わってくるので別々に書いていきます。
~~面倒な人はVSCodeとCMakeでも使ってゴリ押してください~~

※注意
執筆環境がMacなので、Windowsの方の説明はスクショがなく、多少誤りがあるかもしれません。

# Mac (Xcode) でのセットアップ
まずはPhotonSDKをダウンロードしてきましょう。[ここ](https://www.photonengine.com/en-US/sdks#realtime-sdkrealtimemacosx)の「Download SDK」からできます。中身はこんな感じ
![スクリーンショット 2021-04-03 22.39.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596925/05948faf-4f0b-efea-ebde-679f91779505.png)
これを動かさなそうなところに置いておきます。
**記事では /Users/ユーザー名/Documents に PhotonSDK という名前で置いておきます**



次に新しいプロジェクト作成。Xodeを開いたら
「Create a new Xcode project」→「macOS」→「Command Line Tool」
を選択。![スクリーンショット 2021-04-03 22.31.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596925/58092f48-54c2-2fc0-a838-14262506bfb0.png)
適当に名前をつけて適当な場所に置いておきましょう。

さて次はちょっと大変。パスを通していきます。
まずプロジェクトの設定を開いたら、
「Build Settings(All|Combined)」→「Linking」→「Other Linker Flags」
を選択。下の三つを追加します

`-lCommon-cpp_$(CONFIGURATION)_$(PLATFORM_NAME)`
`-lPhoton-cpp_$(CONFIGURATION)_$(PLATFORM_NAME)`
`-lLoadBalancing-cpp_$(CONFIGURATION)_$(PLATFORM_NAME)`

DebugとReleaseどちらも同じになるようにしましょう![スクリーンショット 2021-04-03 22.50.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596925/a952b64f-9ff4-9acc-89f2-152489820801.png)

次に
「Build Settings(All|Combined)」→「Search Paths」→「Header Search Paths」に下記を追加します。

`~/Users/ユーザー名/Documents/PhotonSDK`

最後に、
「Build Settings(All|Combined)」→「Search Paths」→「Library Search Paths」に次の三つを追加します

`/Users/ユーザー名/Documents/PhotonSDK/Common-cpp/lib`
`/Users/ユーザー名/Documents/PhotonSDK/Photon-cpp/lib`
`/Users/ユーザー名/Documents/PhotonSDK/LoadBalancing-cpp/lib`

(「~」を使用すると何故かビルドが通りませんでした)

![スクリーンショット 2021-04-04 11.20.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596925/45a73150-8a09-8b8a-b6b9-32887538e54a.png)

これでMacでのセットアップは終了です。お疲れ様でした。

***...と思ったんですが、どうやら間違っていたみたい。`ExitGames::Common::JString`の変数を宣言するとエラーが出た。なぜ？***

# Windows (Visual Studio) でのセットアップ
まずはPhotonSDKをダウンロードしましょう。[ここ](https://www.photonengine.com/en-US/sdks#realtime-sdkrealtimewindows)の「Download SDK」からダウンロードできます。
ダウンロードしたら、それをあまり動かさなそうなところに置いておきましょう。
**この記事では C:¥Users¥ユーザ名¥Documents に　PhotonSDK という名前で置いておきます**

次にプロジェクトの作成。Visual Studio を開いたら、
「新しいプロジェクトの作成」→「コンソールアプリ」
で作成。適当な名前をつけて適当な場所に置いておきましょう。

パスを通していきます。プロジェクトの設定を開いたら、
「プロパティ」→「C/C++」→「全般」→「追加のインクルードディレクトリ」
に下記を追加します。

`C:\Users\ユーザ名\Documents\PhotonSDK`

次に、
「プロパティ」→「VC++ ディレクトリ」→「ライブラリ ディレクトリ」
に
`C:\Users\ユーザ名\Documents\PhotonSDK`

を追加。
これでWindowsのセットアップは終了です。お疲れ様でした。

# 参考サイト
- [makia - OpenSiv3DとPhotonを連携して将棋ゲームをオンライン化した話](https://qiita.com/makia/items/843eedb37eaf562e122c)
- [C++ コンソール アプリ プロジェクトを作成する](https://docs.microsoft.com/ja-jp/cpp/build/vscpp-step-1-create?view=msvc-160)
長文要約生成APIを利用する前に気をつけたいこと


# はじめに

朝日新聞社が長文要約生成APIを公開しました。

https://www.itmedia.co.jp/news/articles/2104/02/news135.html

面白そうな技術なのでこれを使ってみようと思う方、
このAPIを利用する前に**利用規約**は読みましたか？


この記事では[利用規約](https://cl.asahi.com/api_data/term_api.html)を読んで注意すべきことについて説明します。

## 免責事項
筆者は法律の専門家ではありません。以下の内容は筆者の解釈であり、その内容を鵜呑みにせず、実際に利用規約を読んで各自が判断してください。

# 要約と著作権


[著作権なるほど質問箱](https://pf.bunka.go.jp/chosaku/chosakuken/naruhodo/answer.asp?Q_ID=0000338)によると一般に文章の要約を作成することは程度によっては翻案にあたるそうです。

> ダイジェスト(要約)のようにそれを読めば作品のあらましが分かるというようなものは、著作権者の二次的著作物を創作する権利（翻案権、第２７条)が働くので、要約の作成について著作権者の了解が必要です。（中略）一方、２～３行程度の極く短い内容紹介や「夭折の画家の美しくも哀しい愛の物語」などのキャッチコピー程度のものであれば、著作権が働く利用とは言えず、著作権者の了解の必要ありません。

利用規約では著作権について以下のように定めています。

> # 第３条（知的財産権等）
> 
> 1. 本APIに関する知的財産権及びその他の権利は、すべて甲に帰属する。
> 2. 入力データに著作物が含まれる場合、当該著作物にかかる著作権は、乙または当該著作物について権利を有する第三者に帰属する。乙は、第三者に権利が帰属する著作物を入力データ等に使用する場合、乙の費用と責任において当該第三者から使用許諾を得る等、一切の権利処理を行うものとする。
> 3. 解析データ及び出力データ（以下、「出力データ等」とする）に関する知的財産権及びその他の権利は、すべて甲に帰属する。

つまり

- 入力データの著作権はその著作物の作成者のもの
- 出力データ（要約）の著作権は朝日新聞社のもの
- **利用者の責任で朝日新聞社が要約を作成することの許諾を取得する**

ということになります。したがって、出力データを公開せず、試しに使ってみる場合であっても、著作権者の許諾が必要です。

さらに入力データについて以下の記載があります。

> # 第５条（許諾の条件）
> （中略）
> なお、乙は、甲が入力データまたは出力データを甲のサーバーに複製・保存し、今後甲が開発する機械学習やアルゴリズム等に利用、または解析データを得るために必要な処理または加工等を行うことを無償で全世界的に期限を定めず許諾するものとする。

つまり、「入力データがサーバに保存され、学習データとして利用されること」の許諾も利用者の責任で取得する必要があります。

以上を踏まえると、自身が著作権を有していない著作物を入力とすることは避けた方が無難でしょう。

# 記事の公開

さて要約APIを利用した技術記事を公開する際には以下の規約にも気をつける必要があります。

> # 第１０条（公表）
> 
> 1. 乙は、学術研究や本APIの評価の目的に限り、本APIを使用して得られた研究成果や知見を公表することができる。
> 2. 乙は、公表にあたっては、本APIをもとにしていることを明記し、成果の公表の前にその概要を書面やメール等で甲に報告する。
> 3. 乙は、論文発表の際も、本APIを利用した旨を明記し、提出先の学会、発表年月日とともに論文の別刷りまたはコピーを１部甲に提出するものとする。

すなわち、記事の公開前に朝日新聞社にメールで報告が必要ということです。

また、出力データの公開についても以下の規約に注意する必要があります。

> # 第７条（禁止事項）
> 乙は、本APIや出力データ等の利用にあたり、以下に定める行為をしてはならない。
> （中略）
> （３）APIキー及び出力データ等を第三者に提供すること。

要約の一例を記事に載せることはおそらく大丈夫でしょうが、大量に変換したデータを公開することは許可されていません。

# まとめ

- 入力データは自身が著作権を持っているものに限るようにしましょう。
- APIを利用した記事の公開前に朝日新聞社にメールで報告する必要があります。
SQL Serverを切り口にDatabaseをDIGってみた

こちらにまとめています。
https://scrapbox.io/lrndbprvttng/SQL_Server%E3%82%92%E5%88%87%E3%82%8A%E5%8F%A3%E3%81%ABDatabase%E3%82%92DIG%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%9F
ECSからS3にアクセスする方法

##何をしたいか
ECSでlaravelアプリをホストしています。
サムネイルの表示や更新にS3を利用しているため、ECSでホストしたLaravelアプリからS3にアクセスしたいです。
ECSからS3を利用する場合、開発環境で行っていた方法とは少し異なるため記事にしました。
##開発環境でのやり方
IAMでS3バケットを作成するアカウントを作成します。
そのアカウントでS3バケットを作成します。
.envを以下の様に編集します。

```
AWS_ACCESS_KEY_ID=******************** //先ほど作成したアカウントのアクセスキーID
AWS_SECRET_ACCESS_KEY=******************** //先ほど作成したアカウントのシークレットアクセスキー
AWS_DEFAULT_REGION=ap-northeast-1
AWS_BUCKET=バケット名
AWS_URL=https://s3-ap-northeast-1.amazonaws.com/バケット名/
```
おそらくこれで開発環境で作成したアプリからS3にアクセスできると思います。

##本番環境（ECS）でのやり方
ECSからS3にアクセスする場合ECSタスクロールにS3アクセスのための権限を付与する必用があります。

```json:ecs_task_policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
            "s3:ListBucket",
            "s3:GetObject",
            "s3:GetObjectAcl",
            "s3:PutObject",
            "s3:PutObjectAcl",
            "s3:ReplicateObject",
            "s3:DeleteObject"
            ],
            "Resource":"arn:aws:s3:::バケット名/*"
        }
    ]
}
```
.envは以下の様に編集します。

```
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=ap-northeast-1
AWS_BUCKET=バケット名
AWS_URL=https://s3-ap-northeast-1.amazonaws.com/バケット名/
```

これでECSからS3にアクセスできると思います。
[Azure]ServicePrincipalからPowerBIに接続してみる

#はじめに
本記事では、MicrosoftAzureが提供しているPowerBI APIを利用し、ServicePrincipalからPowerBIアカウントに接続を行う一連の流れを解説して行きます。

# 実行環境
AzureActiveDirectory ：PowerBI接続用にアプリ（ServicePrincipal）を作成します。
PowerShell：Mac版を使用
MicrosoftPowerBIMgmtモジュール：以下のコマンドより、インストールしてください。（最新版がインストールされます。）

```powershell
Install-Module -Name MicrosoftPowerBIMgmt
```

#事前準備
事前準備として、以下の項目を実施します。
・ServicePrincipalの作成
・ServicePrincipalへ自己証明書のインストール

##ServicePrincipalの作成
AzurePortalに接続後、左のブレードからAzureActiveDirectoryを選択、アプリの登録を押下してください。
そして、画面上部の新規登録ボタンを選択、アプリケーションの登録画面に遷移します。下の画面が出てきたらOK

![スクリーンショット 2021-03-24 1.59.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257329/89f90004-f6cc-95ed-4244-3098cce5d21e.png)

パラメータですが、以下で設定します。
名前：Powerbiapp
その他は規定

登録を押すと、以下のようにServicePrincipalが作成されているはずです。
![スクリーンショット 2021-04-03 17.52.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257329/d2404f57-7109-c4c1-b8ec-71a24dd2c48c.png)


出来ましたね。アプリケーションIDとディレクトリ（テナント）IDは接続時に使用するため、控えておきましょう。

##ServicePrincipalへ自己証明書のインストール
ServicePrincipalからPowerBIへ接続する際ですが、証明書認証のみの対応のため、今回は自己証明書をServicePrincipalへインストールします。
（ユーザアカウントを利用する場合はID、パスワードで認証可能です。）
自己証明書の作成方法については本記事では省略します。

それでは、先ほど作成したPowerbiappより証明書とシークレットを選択してください。
選択後、以下の画面が表示されます。
![スクリーンショット 2021-04-03 19.09.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257329/83b492b2-4d1c-bf13-9f43-004706521ba9.png)

この画面から証明書のアップロードを行います。アップロードが正しく完了していると以下のような表示に変わっているはずです。拇印は接続時に使用するため控えておきましょう。
![スクリーンショット 2021-04-03 19.11.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257329/6648a467-bf96-06ba-6f0e-abfd1d64f8e5.png)

#PowerShellから実際に接続してみる
PowerShellを開きまずは以下のコマンドを実行。PowerBIのモジュールをインポートします。

```powershell
Import-Module -Name MicrosoftPowerBIMgmt 
```

次にパラメータの設定を行います。

```powershell
$applicationid = <控えていたアプリケーションID>
$tenantid = <控えていたテナントID>
$thumbprint = <控えていた拇印>
```

準備が整いました。それでは接続してみましょう。以下のスクリプトを実行。

```powershell
Connect-PowerBIServiceAccount -ServicePrincipal -ApplicationId $applicationid -CertificateThumbprint $thumbprint -TenantId $tenantid
```
以下が出力されたら成功です！

```
Environment           : Public
TenantId              : <テナントID>(これは出力されてなくてもOKです。)
ClientId              : <アプリケーションID>
CertificateThumbprint : <拇印>
```

#おまけ
PowerBIアカウントに接続できたら次のコマンドレットを実行してみてください。
これはPowerBI側のワークスペース一覧を取得するコマンドレットです。

```powershell
Get-PowerBIWorkspace
```
実行すると...？あれ、失敗しましたね...

```powershell
Get-PowerBIWorkspace: Operation returned an invalid status code 'Unauthorized'
```
失敗の原因ですが、ServicePrincipalがPowerBI側のリソースをReadする権限がないことに
よるものです。Read権限を付与する方法は次回の記事で書こうと思います。
rails db関係でよく使用するコマンド

##基本のマイグレーションファイルとモデル作成
マイグレーションファイル　`rails g migration クラス名`
モデル　` rails generate model モデル名 カラム名:データ型`

命名規則
クラス名　アクション_テーブル名  ex)create_users
モデル名　大文字 + 単数　　　ex)User

##基本コマンド
データベースにマイグレーションファイルを反映する `rails db:migrate` 
drop(db削除）create(db生成） migrate(反映）を行ってくれる  `rails db:migrate:reset`
現在の状況確認`rake db:version`
一つ前のマイグレーションを無かったことにする`rails db:rollback`
aws-sdkを用いてAWS SecretManagerからシークレットを取得する(Node.js TypeScript)

Node.js&TypeScript&lambda環境、aws-sdkを用いて、AWS SecretManagerからシークレットを取得する方法を解説します。

##  1. aws-sdkをinstall
```
npm install aws-sdk
```

## 2. コードを記述
```typescript:referSecrets.ts
import * as AWS from "aws-sdk";
export const referSecrets = async () => {
  try {
    const secretsManager = new AWS.SecretsManager({
      region: "ap-northeast-1",
    })
    const response = await secretsManager.getSecretValue({
      SecretId: SECRET_NAME,
    }).promise()
    return JSON.parse(response.SecretString)
  } catch(err) {
    return JSON.stringify({err}, null, 2)
  }
}
```

**注意点**

- requireではなく、importを使用する。
    - typeが使用でき、vscodeがメソッドや型を推論してくれます。
- SECRET_NAMEには、シークレット名を記述
- iamroleなどの設定は省いています。

### 参考
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SecretsManager.html#getSecretValue-property
Vercelでデプロイする方法（基本的な流れ）

# 概要

Next.js について学ぶ中で、開発した Web アプリを簡単に公開する方法として、Vercel を使った方法を知ったので、備忘録として記載しておきます。

# Vercel とは

Vercel 社が開発した、Web サイトやアプリを公開するためのプラットフォーム。
ちなみに、Vercel 社はモダンな react 開発のフレームワークとして人気の Next.js も提供しており、Vercel との相性も非常に良い。

# Vercel の特徴

- ユーザーへの公開が容易
- Github と連動して公開可能
- 基本、無料で利用できる

# Vercel でのデプロイの手順

0. Vercel サイトでサインアップ<br>
   下記の Vercel サイトの右上の"Sign Up"から、Git アカウントでサインアップする<br>
   https://vercel.com/
1. サインアップ画面での右上にある"New Repository"をクリックする
2. 画面左の"Import Git Repository"から、公開したいプログラムを選択する
3. "Select Vercel Scope"で、公開元となるアカウントを選択する<br>
   基本は、自分の個人アカウントで良い
4. "Project Name"を指定し、右下の"Deploy"をクリックする<br>
   他の項目はひとまず操作不要

上記作業後、自動でデプロイ処理が実行されます。紙吹雪が舞って、"Congraturations"と表示されたらアプリの公開は完了です。

超簡単！！！！
借金額返済期間プログラム

Python学習一環で、借金を一定額払い続けた場合、どのくらいの返済期間がかかり、借金がなくなるまでの金額を調べるプログラムを作ってみました。

**環境：**
Google colaboratory
**目的：**
借金額から返済までどのくらいの期間がかかり、どのような返済額になっていくのか表示する。

**フロー：**
①　借金額記載
②　利息年率(%)
③　返済額/月
④　借金額と返済額から返済額より借金額が少なくなるまで、月数と金額表示
⑤　返済額より借金額が少なくなった後の月数と返済総額表示

借金の金額と、利息の年利率(%)、月々の返済額を入力すると、毎月、借金がなくなるまで月数と借金の金額を表示し、月々の借金は、借金の利息年利率/12（月割り）分増加するが、返済分だけ減るというイメージのプログラムを作成します。

入力欄を設け、debt, rate, payment変数を作る。今まで返済した合計のカウント並びかかった月数をカウントする為、total = 0, month = 0 と設定する。

```python
debt = int(input('借金額はいくらですか？> '))
rate = float(input('年利率(%)表示して下さい。> '))
payment =  int(input('返済額の設定して下さい。> '))
total = 0
month = 0
```

次にdebtの返済額がどのくらいまで繰り返されるかをWhile文を使って、paymentを下回るまでとします。月数は１ヶ月ずつ増やし、残りの返済額には、debtに利率の12ヶ月の%表記(100)を掛け合わせたものから毎月のpaymentを差し引くようにします。

```python

while debt > payment :
    month += 1
    debt = debt*(1 + rate/12/100) - payment
    print(str(month)+'月: 返済額',payment,'円','残り',\
    int(debt),sep=' ')
    total += payment
```

更にdebtがpaymentを下回った後の返済額と返済を表示します。ここでのdebt変数は、上記debtを基にしたdebtになります。int(total)のtotalは、total +で今までpaymentでの合計値とdebtからの足算になります。

```python
debt = debt*(1 + rate/12/100)
total += debt
print(str(month)+'月: 返済額',int(debt),'円','これで完済になります。','返済総額: ',\
int(total),'円',sep=' ')
```

**まとめコード**

```python
debt = int(input('借金額はいくらですか？> '))
rate = float(input('年利率(%)表示して下さい。> '))
payment =  int(input('返済額の設定して下さい。> '))
total = 0
month = 0
while debt > payment :
    month += 1
    debt = debt*(1 + rate/12/100) - payment
    print(str(month)+'月: 返済額',payment,'円','残り',\
    int(debt),sep=' ')
    total += payment
month += 1
debt = debt*(1 + rate/12/100)
total += debt
print(str(month)+'月: 返済額',int(debt),'円','これで完済になります。','返済総額: ',\
int(total),'円',sep=' ')
```

**出力結果**

```
借金額はいくらですか？> 10000
年利率(%)表示して下さい。> 10
返済額の設定して下さい。> 1000
1月: 返済額 1000 円 残り 9083
2月: 返済額 1000 円 残り 8159
3月: 返済額 1000 円 残り 7227
4月: 返済額 1000 円 残り 6287
5月: 返済額 1000 円 残り 5339
6月: 返済額 1000 円 残り 4384
7月: 返済額 1000 円 残り 3420
8月: 返済額 1000 円 残り 2449
9月: 返済額 1000 円 残り 1469
10月: 返済額 1000 円 残り 481
11月: 返済額 485 円 これで完済になります。 返済総額:  10485 円
```
**振り返り**
while debt > paymentへの理解が最初難しかった点が挙げられます。また、その処理を終え、返済総額に関わるint(total)の理解がなかなかできませんでした。今回は、借金額から利息がかかった状態での返済期間と返済額を表すものでしたが、次回は、逆に、目標設定額を決め、複利にて目標設定額を達成する期間と増加額を表すプログラムを作成したいと思います。
ファイルを作成年月ごとにフォルダ分けするPythonスクリプト

A simple Python script that scans a given directory and its all subdirectories and organizes the files of specified extensions by their creation dates, year and month, in this example.

大量のファイルを作成年月ごとのフォルダに分けて整理するPythonスクリプトです。

- 整理したい複数の拡張子を指定
- ファイル名を作成日時から自分で決めた形式に変更（オプション）

```python:organize_files.py
from pathlib import Path
from itertools import chain
from datetime import datetime
import shutil

#整理したいディレクトリのパスを与える
datdir = Path("/Users/user_name/your_data_folder/")
#整理したいファイルの拡張子を指定する（いくつでも）
ext_list = ["jpg", "jpeg", "png", "PNG"]
files = []
for ext in ext_list:
    #このディレクトリおよびすべてのサブディレクトリを再帰的にスキャンする
    _files = datdir.glob('**/*.%s' % ext)
    files = chain(files, _files)

for i, f in enumerate(files):
    #ファイルの作成日時
    bt = datetime.fromtimestamp(f.stat().st_birthtime)
    #サブフォルダ名の形式を2021_04などとする
    folder_name = "%.4d_%.2d" %(bt.year, bt.month)
    #サブフォルダを作る（すでにあればスキップ）
    subfolder = datdir / folder_name
    try:
        subfolder.mkdir()
    except FileExistsError:
        pass
    #ファイル名の指定
    #1) そのまま変えない場合
    new_file_name = f.name
    #2) 作成日時から作る場合
    # new_file_name = "%.4d%.2d%.2d_%.2d%.2d_%d.%d%s" %(bt.year, bt.month, bt.day, bt.hour, bt.minute, bt.second, bt.microsecond, f.suffix)
    #サブフォルダへの移動
    new_path = shutil.move(f, (subfolder / new_file_name))
    #ログ出力
    print("File %d: %s \n  => %s" %(i, f, ("/".join(new_path.parts[-2:]))))

print("Done!")
```

参考：各ライブラリのドキュメント
ライブラリを使わずにスクロールフェードインアニメーションを実装する

<hr>
【まえがき】
※私は勉強のために敢えて自分でやりましたが、普通に実装したいだけなら
<a href="https://scrollrevealjs.org">ScrollReveal.js</a>というライブラリを使えば一瞬でできます。

<hr>

画面をスクロールしたら要素がふわっと現れるアニメーションを、ライブラリを使わず素のJavaScriptだけで実装してみました。

<p class="codepen" data-height="359" data-theme-id="dark" data-default-tab="js,result" data-user="toshihide2000" data-slug-hash="JjEEeKJ" style="height: 359px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="スクロールフェードイン">
  <span>See the Pen <a href="https://codepen.io/toshihide2000/pen/JjEEeKJ">
  スクロールフェードイン</a> by toshihide (<a href="https://codepen.io/toshihide2000">@toshihide2000</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

この動きを分解すると、

　　　①要素が画面内に現れたら

　　　②フェードインのアニメーションを付与する



というものです。至ってシンプルですが、「①要素が画面内に現れたら」をどうやって判定するかが今回のキモです。

考え方はいろいろあると思いますが、私は<b>「要素が画面内に出現＝スクロール量＞(ページ上端から要素までの距離ーviewportの高さ)」</b>であると考えました。

![explain.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159193/088e1199-d6af-a399-a1d5-81a257e8fcfd.png)


この例だと、201px以上スクロールしたら要素が画面内に入ってくることになります。

つまり、"スクロール量＞(ページ上端から要素までの距離ーviewportの高さ)"がtrueであればアニメーションを付けるという動きを、スクロールするごとに判定させれば良さそうです。

##ページ上端から要素までの距離
<code>getBoundingClientRect()</code>でviewport上端から要素までの距離を取得できます。これにスクロール量を足すことでページ上端から要素までの距離を割り出すことができます。


![setumei.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159193/cc9197fa-4d9b-5aaa-82a8-9a1b7f153313.png)


まとめると、
スクロール量＝<code>window.pageYOffset;</code>
viewport上端から要素までの距離＝<code>getBoundingClientRect().top;</code>
ページ上端から要素までの距離=<code>getBoundingClientRect().top+window.pageYOffset</code>
viewportの高さ=<code>window.innerHeight;</code>
という具合になります。


あとはこれらをif式に当てはめてアニメーションのクラスを付与すれば良いのですが、一つ注意すべき点があります。スクロールした後にリロードすると<code>pageYOffset</code>がリロード時の値を返すので、リロードすると最初からアニメーションがついた状態で読み込まれてしまいます。

なので、苦肉の策ですがwindowのonload時にアニメーションのクラスを外しておく必要があります。


また、フェードインのアニメーションが「透明度を１に近づけながら下から上に移動する」というものなので、要素が画面内に入ってすぐにアニメーションを当ててもアニメーションの特性上、浮き上がってくる動きがちゃんと見えない場合があります。そのため判定の基準を<code>スクロール量＞ページ上端から要素までの距離ーviewportの高さ<b>+viewportの1/4の高さ</b></code>とし、きちんとアニメーションが見えるように余裕を持たせています。


以上、スクロールフェードインアニメーションの実装方法についてでした。



<hr>
<b>趣味でアプリを作っています。見て行ってくれると喜びます。</b>

![kinyoku-100px-icon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159193/e4e3ef0f-f893-59bd-540b-d3c09d83e2ae.png)
[禁欲エボリューション](https://apps.apple.com/jp/app/禁欲エボリューション/id1553966013)


![mem-100px-icon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159193/c4b778ff-7a14-b489-c71e-23fe6f6b7eb8.png)
[文字数制限メモ](https://apps.apple.com/jp/app/文字数制限メモ/id1552651234)
Flutterのimage_pickerで取得した画像の位置情報を知るには

## 全体の流れ
1. [image_picker](https://pub.dev/packages/image_picker) で画像のパス取得
2. 取得したpathから [exif](https://pub.dev/packages/exif)で画像のメタデータを取得
3. その中に位置情報が(保存されてれば)入ってるのでそっから取る

## サンプル
コピペで使えます

```dart
import 'dart:io';

import 'package:image_picker/image_picker.dart';
import 'package:exif/exif.dart';

Future printImageGPS() async {
  final pickedFile = await ImagePicker().getImage(source: ImageSource.gallery);
  final tags = await readExifFromBytes(await File(pickedFile.path).readAsBytes());
  print('latitudeRef: ${tags['GPS GPSLatitudeRef']}');
  print('latitude: ${tags['GPS GPSLatitude']}');
  print('longitudeRef: ${tags['GPS GPSLongitudeRef']}');
  print('longitude: ${tags['GPS GPSLongitude']}');
}
```
結果

```
flutter: latitudeRef: N
flutter: latitude: [35, 28, 3031/100]
flutter: longitudeRef: E
flutter: longitude: [138, 40, 17/25]
```
初めてのRaspberry Pi Pico ㉝ CircuitpythonでBNO055

　BOSCH社の9DoF 方位/慣性計測モジュールBNO055を使います。
###BNO055のおもな出力
　3軸加速度計、3軸磁力計、3軸ジャイロスコープ単独の出力以外にオイラー角やクォータニオンの出力もあります。

- オイラーベクトル
- クォータニオン
- 角速度ベクトル
- 加速度ベクトル
- 磁界強度ベクトル
- 線形加速度ベクトル
- 重力ベクトル
- 気温

###Circuitpython履歴
　PicoのI2C対応。リピーテッド・スタートは初期から対応済み。SCLクロック・ストレッチの対応は、順次行われ、6.2.0-rc.0でfix。

**6.2.0-beta.3** SCLクロック・ストレッチに非対応。対応していないとメッセージが出る
**6.2.0-beta.4** SCLクロック・ストレッチに対応、SDAクロックがスペックを満たしていない。動くこともあるが、途中で止まる
**6.2.0-rc.0** SDAのクロックの修正

###接続
　Adafruitのブレークアウト・ボードを利用します。I2C専用のSTEMMA QTコネクタでPicoと接続します。はんだ付けなどは不要です。

<img width="250" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/9b63fbbb-67ed-3318-20bd-e9af11ea60cd.png">

|STEMMA QTコネクタ（ケーブルの色）  |GPIOピン番号|
|:-----------|:------------:|
|SCL 緑 |GP21|
|SDA 黄（白）|GP20|
|Vcc 赤|3.3V|
|GND 黒|GND|

###プログラム
 examplesに入っていたサンプルです。

```python
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

import time
import board
import busio
import adafruit_bno055

# Use these lines for I2C
i2c = busio.I2C(board.GP21, board.GP20)
sensor = adafruit_bno055.BNO055_I2C(i2c)

# User these lines for UART
# uart = busio.UART(board.TX, board.RX)
# sensor = adafruit_bno055.BNO055_UART(uart)

last_val = 0xFFFF


def temperature():
    global last_val  # pylint: disable=global-statement
    result = sensor.temperature
    if abs(result - last_val) == 128:
        result = sensor.temperature
        if abs(result - last_val) == 128:
            return 0b00111111 & result
    last_val = result
    return result


while True:
    print("Temperature: {} degrees C".format(sensor.temperature))
    """
    print(
        "Temperature: {} degrees C".format(temperature())
    )  # Uncomment if using a Raspberry Pi
    """
    print("Accelerometer (m/s^2): {}".format(sensor.acceleration))
    print("Magnetometer (microteslas): {}".format(sensor.magnetic))
    print("Gyroscope (rad/sec): {}".format(sensor.gyro))
    print("Euler angle: {}".format(sensor.euler))
    print("Quaternion: {}".format(sensor.quaternion))
    print("Linear acceleration (m/s^2): {}".format(sensor.linear_acceleration))
    print("Gravity (m/s^2): {}".format(sensor.gravity))
    print()

    time.sleep(1)
```
　実行例

![bno055.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/026cd7d3-500e-e614-0c7a-a34f27afc487.png)
bundle exec rails db:create出来ない[Rails x PostgreSQL]

#環境
- ローカル環境[mac]
- ruby 2.6.3
- rails 6.1.3
- pg 1.1

#bundle exec rails db:create

##エラー文

```
could not connect to server: No such file or directory
	Is the server running locally and accepting
	connections on Unix domain socket "/tmp/.s.PGSQL.5432"?
Couldn't create 'weather_line_bot_development' database. Please check your configuration.
rails aborted!
```
##解決方法

```
rm /usr/local/var/postgres/postmaster.pid
```
bundle exec rails db:create実行したらエラーになりデータベースが作れませんでした。
色々調べた結果ファイル(postmaster.pid)を消してみたら動きました
Ruby if,elseの問題

## 初めに
初学者です。rubyの問題を私なりに解説することによって定着するのが目的です。間違いなどありましたらご指摘お願いします。

### 問題
以下の条件式をif文を用いて記述してください。

数値numが1以上かつ10以下の範囲であればTrueを出力します。
または、outside_modeがTrueの場合は数値numが0以下、11以上であってもTrueを出力します。
それ以外はFalseを出力する条件を論理演算子&&と||を用いて作りましょう。

```
def in1to10(num, outside_mode)
  # ここに条件式を記述する
end
```
ではまず論理演算子である&&と｜｜の解説からしていきます。
####  &&
&&とは２つの値が真の時に真を返します。
例としては A && B ではAとB両方とも真の場合真を返す、片方でも真でなければfalseを返します。
&&演算子はandとも表せれます。andに変換するとわかりやすくなると思います。ただ基本的には&&の方を使うそうです。

#### ||
||とは2つの値どちらかが真の場合、真を返します。要するにA||Bという式があった場合、AとB両方とも偽の場合は偽になりそれ以外は全て真になります。

では上記２つの論理演算子を使用して回答を書いていきます。

###解説
まず今回は、in1to10メソッドに返す引数は（５,false）にします。

```
def in1to10(num, outside_mode)
end
in1to10(5,false)
```
では条件式をif文を使用して書いていきます。
まず最初に問題文の『数値numが1以上かつ10以下の範囲であればTrueを出力します。』の部分から書いていきます。
１以上、１０以下と２つの条件が指定されています。よって&&を使い条件を２つ記述します。

```
def in1to10(num, outside_mode)
 if(num >= 1 && num <= 10)
   puts "True"
 end
end
in1to10(5,false)
```
続いては『または、outside_modeがTrueの場合は数値numが0以下、11以上であってもTrueを出力します。』の部分です。
ここでは、||を使います。outside_modeがTrueの場合は||の前に式がfalseでもTrueになるからです。

```
def in1to10(num, outside_mode)
  if (num >= 1 && num <= 10) || outside_mode
    puts "True"
  end
end
in1to10(5,false)
```
最後にelseでそれ以外はfalseになる記述を書いたら終了です。

```
def in1to10(num, outside_mode)
  if (num >= 1 && num <= 10) || outside_mode
    puts "True"
  else
    puts "False"
  end
end
in1to10(5,false)
```
また今回の式では最初の５が１以上かつ10以下の数値になっているのでTrueを返します。
Bookmarklet を使って動画の再生位置を自由に指定する

以下の記事を参考にさせて頂きました
[Bookmarklet を 2 つ紹介（動画再生速度の変更、ツイート）](https://qiita.com/irisTa56/items/c47cb1bc1ea74126dc0e)

##コード
```javascript
(() => {
  const inString = prompt('Jump:', '00:00:00');
  if (inString === null || inString === '') return;
  const videos = document.body.getElementsByTagName('video');
  if (videos.length > 0) {
    let m;
    if (m = inString.match(/^(\d{1,2}):(\d{1,2}):(\d{1,2})$/)) {
      videos[0].currentTime = m[1]*3600 + m[2]*60 + m[3]*1;
      return;
    }
    if (m = inString.match(/^[+-]?\d+$/)) {
      videos[0].currentTime += m[0]*1;
      return;
    }
    if (m = inString.match(/^x([0-9](\.\d{1,2})?)$/)) {
      videos[0].playbackRate = m[1]*1;
      return;
    }
  }
})();
```
このコードを以下のサイトなどを使ってbookmarkletに変換します。
[Bookmarklets construction set - Create bookmarklets online](http://js.do/blog/bookmarklets/)

## 使い方
実行したら表示される入力ボックスでジャンプしたい(再生)時間を入力します。

### 再生したい位置を指定する場合
```hh:mm:ss ```
```例：01:00:00 or 1:0:0 ```

### 指定した秒数　巻き戻ししたい場合
```例：-120 → 2分巻き戻し ```

### 指定した秒数　早送りしたい場合
```例：120 → 2分早送り ```

### おまけに再生速度の変更にも対応しました　2021/4/6
```例：x1.5 → 1.5倍速 ```


# ブックマークレットの編集に便利なサイトの紹介

http://iphone-diary.com/?p=9251
RecyclerViewで区切り線をカスタムする。

# はじめに
RecyclerViewのアイテムごとの区切り線をカスタムします。
この記事で分かることは以下の3点です。
- 区切り線の幅(大きさ)を変更する。
- 区切り線の個数を決める。


# 実装
## 1.ItemDecoration()を継承したクラスを作成

```kotlin
class MyDecoration(): RecyclerView.ItemDecoration() {}
```



## 2.`onDraw`

- `onDraw`で描画されるコンテンツは各リサイクラービューのアイテムが描画される前に描画されます。
- ※描画のたびに呼ばれるため重たい処理はしないほうがよさそうです。

```kotlin
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
    
    //描画するアイテムの色などを適当に決めてください。
    private bval paint = Paint().apply { color = Color.BLACK }
    
    //一番下のアイテムの下側のデコレーションはいらないので -1 とする
    val childCount = parent.childCount - 1;

    (0.until(childCount)).forEach { i ->
        val child = parent.getChildAt(i);
　　　　　
        //両端の幅を20pxずつ削ります。
        val left = parent.left + 20
        val right = parent.right - 20
                                   
 　　　　//自身のbottomから1pxの太さとします。
        val top = child.bottom
        val bottom = child.bottom+1
       
　　　　　c.drawRect(Rect(left, top, right, bottom), paint)
    }
    
    
}
```



## 3.その他

**`getItemOffsets`**

- 各アイテムにオフセット(余白)を付与できます。

```kotlin
override fun getItemOffsets() {
    super.getItemOffsets(outRect, view, parent, state)
    //上下に10pxの余白を付ける
    outRect.bottom = 10
    outRect.top = 10
}
```



# 参考

[RecyclerView.LayoutMangerとRecyclerView.ItemDecoration](https://blog.moyuru.io/post/tech/2018/12/itemdecoration/)