App Engineerの開発ノート

AWS、Flutterや開発活動に役立つツール作りなど

AWS入門~とりあえずWebアプリケーションが公開されるまで

f:id:Simoroid:20210818013157p:plain
AWSを勉強したい・導入したいという場合の
とりあえず最初のWebアプリが公開されるまでの手順です。
所要時間は最速だと20分くらいです。

◇アカウント作成
まずは下記でアカウントを作成します。
https://aws.amazon.com/jp/try-cloud/

個人情報として住所や携帯電話番号、
クレジットカードを差し出す必要があります。
ただし利用に必ずお金が掛かるという訳ではありません。
無料でどこまで使用できるかという情報は下記のサイトにて公開されています。
AWS クラウド無料利用枠 | AWS

あとは住所が英語表記で記載しなければなりませんので、下記のサイトなどを利用すれば楽です。
https://kimini.jp/

◇EC2を起動
AWS マネジメントコンソール(ログイン後のトップページ)から
"仮想マシンの起動"をクリック
基本的には"無料利用枠の対象"の記載がある項目を選択して次へと設定を進めていけば問題無いかと思います。
※本格的にサービスを立ち上げる際は目的に応じたインスタンスタイプの選定が必要です。
f:id:Simoroid:20210818004831p:plainf:id:Simoroid:20210818004835p:plain

◇Elastic Beanstalkを起動
前段と同様にAWS マネジメントコンソールから
"ウェブアプリケーションの構築"をクリック。
任意のアプリケーション名、プラットフォーム情報を入れて、
アプリケーションコードを"サンプルアプリケーション"に設定して、
「アプリケーションの作成」をクリック。
f:id:Simoroid:20210819003013p:plainf:id:Simoroid:20210819003009p:plain

ちなみにEC2などの環境のお金が掛かるため、
Elastic Beanstalk自体にはお金が掛からないようです。
https://aws.amazon.com/jp/elasticbeanstalk/pricing/

その後、Elastic Beanstalk -> アプリケーションから
URLをクリックします。
f:id:Simoroid:20210819003309p:plain
無事にサーバーにアプリが公開されていることが確認できます。
f:id:Simoroid:20210818013400p:plain
以上でAWSを始めてとりあえずアプリを公開になります。
これ以降は独自のアプリ開発やサーバーレスコンピューティングに触れていきたいと思います。
まだAWSの1000分の1も機能を利用してませんが、これだけで何かやった気になる笑

ここまで 読んで頂きありがとうございました。
よければフォローお願いします!

予測できない時代、明日にはどんなサービスが流行るか分からない

f:id:Simoroid:20211120104652p:plain
どうも雑に転職活動中のエンジニアです。
ここ数年で登場してきたサービスによって、動画や音楽などを通した体験が大きく変わりましたね。
そういった予測が難しいことを理解して、少しでも対応できるよう考察していきたいと思います。

新星によるぶち壊し

映像や音楽を通した体験がそれまでそのことを専門でやってきた企業からではなく新星の企業によって置き換えが起こってしまいましたね。
昔は映画をDVDで見ようと思った場合、主にTSUTAYAなどのレンタルビデオショップが当たり前でした、僕の生まれ育った町ではワンダーパニックとかいうローカルなレンタルショップがありました。※仲良くない中学の頃の同級生が働いていてレンタルに気を遣った。。
そういった体験は今やAmazon PrimeNetflixを契約すれば、圧倒的手軽に手に入るようになりましたね。

音楽もそうです、昔はカセットテープでラジオを流して好きな曲が流れたら録音を始めたり、レンタルCDをPCでインポートして、音楽を視聴していましたが、今やSpotifyApple Music等の配信サービスで最新の音楽がすぐに聞けてしまいます。※これによりアーティストの収益は上がったのか、下がったのか?
f:id:Simoroid:20211116004331p:plain

Amazon Primeは元々通販サイトとして利用していたAmazonがいつの間にか配信サービスを始めていて、気づいたら生活に溶け込んでいました。
アマプラやネトフリは等の新星の到来は既存業界で映画や音楽を提供してきた企業でも予測できない事態だったかと思います。

VUCAの時代

これらの予測できない状況をVUCAと呼ばれるようです。※軍事用語がビジネス用語に派生したらしい。

- Volatility(変動性)
流行りの技術は大きく変わります、ブロックチェーン、NFTなど新しい技術が出てきますね。
新しい技術は概念自体は古くから存在しても、ビジネスに転換して成立するタイミングの予測は難しい。
これらの情報をカバーするためには論文調査を一定の頻度を行うことが必要ですが、論文を読み解く力を見つけるにはかなり鍛錬がいりますね。

- Uncertainty(不確実性)
自然現象によって巻き起こる問題は予想できず、予定していた事業が確実にすすめられる保証はありません。
コロナウィルスの蔓延によって飲食店は大ダメージを受けましたよね。
こんな事態を想定した訳もなくオープンしたばかりの店もあったそうです。

- Complexity(複雑性)
ローカルなルールによってある地域で普及しているサービスが同様にその国では使用できないことがあります。
日本で一時、結構流行った仮想通貨は、中国の場合では政府の国家管理経済の方針に反する為、マイニングや取引が中止となったようです。
中国で仮想通貨が「全面禁止」になった理由と、矛盾もはらむ政府の思惑 | WIRED.jp

- Ambiguity(曖昧性)
メディアも多様になり、商品をプロモーションしたいとなった場合、単にテレビなどのマスメディアを使うのではなく、インターネット配信やSNSといった、効果的な宣伝の場を選択する必要があります。
これまでの型が通じない状態になってきています。

まとめ~上記を前提とした柔軟性

逆にこれだけ予測ができないということを予め織り込んでおけば、
スイッチングコストをさげることが大事ということが分かりますね。
企業としては、感染症や環境要因で店舗内でのサービス提供が厳しい場合は
デリバリーサービス(出前館、UberEats...etc)に振り、平時は比重を逆転させる。
f:id:Simoroid:20211116004231g:plain

エンジニアの自分個人としてはリモートワークの環境を整備し※いい机ほしい。
働き方をどちらでも対応できるよう準備しておくとかですかね。
また、新しい技術に積極的に挑戦、サンプルでも何でもいいからとりあえず軽くやってみる、その中で自分が好きだと思えるものは流行とかは考えず、深堀したい。
クラウドやNFT等、興味がある技術の実装を試してみてブログにまとめていけたらいいなと考えています。

ここまで 読んで頂きありがとうございました。
よければフォローお願いします!

リモートワーク生活1年以上たったので~SIerエンジニアの場合

f:id:Simoroid:20211105000529p:plain
どうも準委任契約で働くSIerエンジニアです。
リモートワークが始まり1年以上が経過したので、記録を残します。
結論的にはアプリケーションエンジニアのようにデジタルな知的生産の仕事はいける、生活をする上でそれなりに課題もあるよねという感じです。

リモートワーク生活を続けて2つの側面での気づきがありましたので、
書き残します。
・仕事的な側面
・個人的な側面

仕事的な側面

まず仕事的には結構やっていける印象です。
仕事に関するコミュニケーションはTeams、Slack、Chatworkなどのツールを使えばよいし、深い話をしたい場合はビデオ会議でつなげばよい。
タスク管理はJIRA、backlogなどチケット管理ツールで完結しています。
もし進捗状況に問題があった場合もビデオ会議で話せばなんとかなります。

特にエンジニアの場合、ほぼ頭を使わなくてもいい作業もあったりします。

・設計書の整理(体裁を整えたり、日付をチェックしたり)
・テスト実施して結果を記録、同じ操作の繰り返しが多い

こういう作業だとよりリモートで問題ないなと思います。
テスト作業に関しては環境次第なとこがあって一概にリモートで完結はできないでしょうけど。

あとはやはり対面に勝る即レスは無いと思うので、そういうの大事にしたいお客さんの場合は現場に呼ばれることも少々ある。

デメリットとしてはある意味いつでもオンラインで繋がっている状況がプライベートと仕事の境界をぼやかしてしまってる気がします。
定時が過ぎた後の退勤後も仕事の連絡が気になり、つい仕事用PCを起動したままにしてしまい、
実際に連絡が来るとそのまま少し仕事脳になってしまうことがあります。・・・課題①

チームのメンバーも当たり前のように深夜まで残業している人がいます。
深夜を跨がなければこなせないタスク割り振りになっていること自体が課題に挙げられるべき筈なのですが、
みんな律儀にスケジュールを守るため残業しまくり生活を選んでいます。

そう言えば最近気かないけどどこいった36協定

個人的な側面

仕事でのコミュニケーションは必要最低限で全く問題ないのですが、
肝胆相照らすような営みが無いと、閉ざされて精神的に辛くなるということは正直あります。・・・課題②

シンプルに運動不足になるということもあります、行動範囲がスーパーのみというのが定番になりつつありますからね。・・・課題③

気づいた課題への対応

課題① 仕事とプライベートの切り替え
切りがいいタイミングでちゃんとオフラインになって、仕事のことを考えない、あとはつながらない権利がちゃんと確立してほしいという希望がありますね。

つながらない権利とは、勤務時間外や休日に、仕事上のメールや電話への対応を拒否する権利のことです。

課題②コミュニケーション不足
これはまだ答えが正直ない、新規開拓という観点だとオンラインサロンなどに入ってみるとかですかね、、お金と勇気がいるな。
salon.jp
lounge.dmm.com

課題③運動不足
ジムで運動する、半年でガリガリからボディビルダーみたいになってた友達から言われた「ジムに何しに来たんや」という問いを立て続ける、というアドバイスを胸に毎週追い込んだあと鶏胸肉を食べています。

ここまで 読んで頂きありがとうございました。
よければフォローお願いします!

AWS Innovate – Modern Applications Editionレポ 2021/10/27開催

f:id:Simoroid:20211028015547p:plain業務でも趣味でもAWS開発を行っており、情報収集をしたいと思いAWS主催のイベントに参加してきました。
このイベントはタイトルにもありますが、AWSを活用したモダンアプリケーション開発に関して、新しい技術の紹介や設計思想等がテーマのイベントでした。

ちなみにモダンアプリケーションとは柔軟に増減するアクセス数に適応したり、
ビッグデータの管理やそれらへの高速アクセスが可能だったりするアプリケーションのことのようです。
まあクラウド技術が盛り込まれまくってたらとかそういう感じだと思います。
f:id:Simoroid:20211028004140p:plain

いくつかのセッションに参加しましたので、
その中で個人的に面白いと思ったものを書き残します。

オープニングセッション

いくつかのセッションに参加しましたが、共通してよく言われていたことは
アプリケーションに搭載する機能を細かくAPIで分割することで(=マイクロサービスアーキテクチャ)より高速で実験的な開発が実現でき⇒エンドユーザーの意見を素早く反映させることが出来るメリットがあるという事でした。
確かに仕事でも疎結合APIに分割されていることで、他チームの作っている機能は一旦モックにしておき、
自分たちの担当する機能の開発に時間を注力できるという場面があったな。

f:id:Simoroid:20211028005759p:plainf:id:Simoroid:20211028011132p:plain

中堅中小企業向け_よくあるシステム開発課題の対応方法から学ぶ

こちらはシステム開発における、あるある課題に対応するAWSサービスの紹介でした。
開発者に"IAM"で開発者権限を割り振り、"AWS CloudTrail"で操作を監視する。といったような事例に対する最適な対応方法の話でした。
下記のPDFに詳しく情報が掲載されています。
https://d1.awsstatic.com/whitepapers/ja_JP/modern-application-development-on-aws.pdf
f:id:Simoroid:20211028000155p:plain

ビジネス環境の変化と成長を見据えたモダンアプリケーション開発

こちらは自社のSaasを使用した分だけ課金を行う方式(コンサンプションモデル)でビジネスを展開したい、
となった場合、ユーザーのトレーシングやロギングが重要となってくる。
従来のオンプレでサーバーが複数ある、といったアーキテクチャではこれが厳しい。
そういった課金モデルへも柔軟に適用できることがモダンアプリケーション開発のメリットであると語られていました。

アプリケーション開発者向け_機械学習周辺でのサーバーレス利用方法

こちらはAIエンジニアでない、従来のWebアプリエンジニアでも推論の部分のみの実装で完結できる、
AIサービスを導入すればAIの導入が可能だよねという話でした。
APIに画像だけ渡す呼び出し部分の開発であればまあ深い知識はいらないよね。

f:id:Simoroid:20211028011837p:plainf:id:Simoroid:20211028011817p:plain

モダンアプリケーションへの近道_AWS App Runner のご紹介

これが一番興味深かった。
デプロイやオートスケールなどインフラ的な手間を掛けず、
アプリケーション開発が運用できる新サービスのApp Runnerの紹介でした。
githubソースコードをプッシュするだけでデプロイが可能とのことです。
f:id:Simoroid:20211028010239p:plain

ログの管理などもAWSであれば通常CloudWatchなどを使用しますが、
それもApp Runnnerで確認できるようです。
スタートアップや個人開発者が人件費を掛けずアプリ開発をこれだけで完結できる、
結構便利なものという印象を受けました。
ただ、プライベートエンドポイントはまだ出来ていないなど、大企業が期待する
Webアプリには向かない可能性があるとのことです。
今年の5月にリリースされたサービスとのことでこれから注目ですね。


以上のようにAWSの開発思想やトレンドを知るきっかけになり、勉強になりました。

ここまで 読んで頂きありがとうございました。
よければフォローお願いします!

DynamoDBへのデータ登録を楽にする2~データ削除編

f:id:Simoroid:20211014013907p:plain
f:id:Simoroid:20210928002145p:plain
以前、エクセルファイルをインプットとしたDynamoDBへのデータ登録のツールを作りました。今回はその削除版の一括削除のツールを作成します。
ちなみ登録のツール作成方法は下記です。
ikoda.shop

削除ツールも登録ツール同様、Powershellを使用します。

■ツールの概要
削除するには削除対象テーブルのキーの情報が必要になります。
エクセルファイルを元データとして、シート単位にテーブルの削除したいキー情報を記載しておけば、削除用インプットデータが生成できるツールとします。

■前提条件

登録のツールと同様になりますが、
Excelがインストールされている環境である必要があります。
また現状の仕様ではサポートしている型はBOOLとS(文字列)、N(数値)のみになります。

■実装方法

任意ファイル名でps1ファイルを作成します。

gista6418282318a401aeb9fcb7c171e83f1

■使用方法

1.ツールと"data"フォルダを任意フォルダに配置します。
f:id:Simoroid:20211014011539p:plain

2."data"フォルダに下記のようなエクセルファイルを配置します。
めんどくさいのですが、1行目に"PatitionKey"、"RangeKey"を記載しておく必要があります。
※形式を変えると動かなくなるので要注意
f:id:Simoroid:20211014013010p:plain

3.ツールを右クリック->「PowerShellで実行」をクリックで実行
⇒下記のようにA列で指定したデータセットID名でjsonファイルが出来上がる。

f:id:Simoroid:20211014011522p:plainf:id:Simoroid:20211014011608p:plain
出来上がったファイルにはキーの情報のみが記載されています。
f:id:Simoroid:20211014012045p:plain

4.aws cliでデータ削除
ツールで出力されたjsonファイルをbatch-write-itemのパラメータに渡します。
batch-write-item — AWS CLI 1.20.48 Command Reference

aws dynamodb batch-write-item  --request-items  file://del_data_set1.json --endpoint-url http://localhost:4566

ここまで 読んで頂きありがとうございました。
よければフォローお願いします!

DynamoDBへアクセスを行うJavaのLambda関数の単体テスト実施方法

f:id:Simoroid:20211011015609p:plain
DynamoDBへ書き込み・読み込みを行う関数を効率良く単体テストする方法です。
テストデータの事前投入を簡易化することが今回のメインです。

データ投入に今回はエクセルファイル(拡張子がxlsx)を使用します。
エクセルファイルを使用するメリットとして、その試験に使用したデータがブックでまとめられて分かりやすいという点があると思います。
CSVXMLを使用するとファイルサイズが軽量だと思いますがファイルが分散されて割りと探すのが面倒だということがありました。
テストケースとテストデータ(エクセルファイル)が1対1になっていて欲しいという思いです。
f:id:Simoroid:20211011235230p:plain:w240

■事前準備

全体のソースコードは下記で取得可能です。
ソースコードaws公式が公開しているシンプルなlambdaアプリの
プロジェクトであるjava-basicをべースにして改良しています。

git clone https://github.com/YasuoFromDeadScream/lambda_java_unittest.git

また今回DynamoDBへのアクセスは全てローカル環境で実施する必要であるため、Localstackを使用します。
ikoda.shop

■実装ポイント

1.テスト実施クラスの親クラス - DynamoDBTestBase
エクセルファイルに基づいたデータ投入を行う処理を行うベースとなるクラス。
WorkbookFactoryクラスを使用してエクセルファイルを読み込みます。

    String path = "/data/" + excelFileName;
    try {
      in = getClass().getResourceAsStream(path);
      wb = WorkbookFactory.create(in);

テーブルとGSIを作成します。

    CreateTableRequest createTableRequest = dynamoDBMapper.generateCreateTableRequest(pojoClass);
    createTableRequest.setProvisionedThroughput(new ProvisionedThroughput(5L, 1L));
    // GSIの作成
    if (CollectionUtils.isNotEmpty(createTableRequest.getGlobalSecondaryIndexes())) {
      createTableRequest
          .getGlobalSecondaryIndexes()
          .forEach(
              globalSecondaryIndex -> {
                globalSecondaryIndex.setProvisionedThroughput(new ProvisionedThroughput(1L, 1L));
                globalSecondaryIndex.setProjection(
                    new Projection().withProjectionType(ProjectionType.KEYS_ONLY));
              });
    }
    // テーブル作成
    try {
      amazonDynamoDB.createTable(createTableRequest);

テーブルにレコードを詰め込んでいきます。

      Table table = dynamoDB.getTable(sheet.getSheetName());
      table.putItem(item);

2.テスト実施クラス - InvokeTest
DynamoDBTestBaseを継承します。
junitのバージョンに応じてアノテーションは変わってきますが、
junit5では@BeforeEachと@AfterEach使用して試験実施の前後でDBにデータを入れたり消したりします。

  @BeforeEach
  protected void init() {
    super.init();
  }

  @AfterEach
  protected void tearDown()  {
    try {

テストメソッドの適当なタイミングでデータ投入メソッドを呼び出します。
引数はファイル名を指定するのみです。

  @Test
  void invokeTest() throws IOException, ClassNotFoundException {
    logger.info("Invoke TEST");

    insertTestData("sample.xlsx");

3.Model(POJO)クラス
各テーブルのデータを紐づけるためのModelクラスを作成します。
アノテーションを使用してDynamoDBのキーや項目を設定します。

@DynamoDBTable(tableName = "UserInfo")
public class UserInfo {

    @DynamoDBHashKey(attributeName = "UserId")
    @DynamoDBIndexRangeKey(
            globalSecondaryIndexName = "UserInfoIndex1")
    private String userId;

    @DynamoDBRangeKey(attributeName = "UserName")
    private String userName;
■使用方法

投入するエクセルファイルを下記ディレクトリに配置します。
f:id:Simoroid:20211011012724p:plain
各シート名が作成した前述のpojoクラス名と一致している必要があります。
f:id:Simoroid:20211011013004p:plain
あとはjunitに基づいたテストを実施します。

下記のようにscanを使用してDBに登録されたレコードを参照します。

    String result = handler.handleRequest(event, context);

    List<UserInfo> UserInfoList = new ArrayList<>();
    Map<String, AttributeValue> lastKeyEvaluated = null;
    do {
      DynamoDBScanExpression scanExpression = new DynamoDBScanExpression()
              .withExclusiveStartKey(lastKeyEvaluated);
      ScanResultPage<UserInfo> resultResult = dynamoDBMapper.scanPage(UserInfo.class,scanExpression);
      if(resultResult.getCount() > 0){
        UserInfoList.addAll(resultResult.getResults());
      }
      lastKeyEvaluated = resultResult.getLastEvaluatedKey();
    } while (lastKeyEvaluated != null);

   logger.info(UserInfoList.stream().findFirst().toString());
   assertEquals(UserInfoList.get(0).getAge(),22);

f:id:Simoroid:20211011013514p:plain
コンソールにテーブルの内容が表示されて、
処理結果と期待動作の突合せを行い、処理対象が上手くいっているかを確認します。

以上でDynamoDBにアクセスする関数の単体テスト方法を確立できました。
今後はS3やAuroraなどAWSの色々なサービスをテストできるよう拡張できればいいな。

ここまで 読んで頂きありがとうございました。
よければフォローお願いします!

Indexing APIではてなブログ記事のインデックス登録を自動化

f:id:Simoroid:20211001014154p:plain
自動でGoogle Search Consoleはてなブログ記事をインデックス登録する方法です。
インデックス登録が行われなければGoogle 検索によってブログが表示されません。

インデックスの登録はサイトマップを送信することでGoogleにより実施される仕様とのことですが、はてなブログではそのクロールが中々されずインデックス登録されないことがあるらしいです。

簡単な対応方法はSearch Console(Google Search Console)
でブログ記事のURLを直接入力し、インデックス登録をリクエストすることです。
ただ、記事を書くたびにそんな作業を毎回やりたくないのでツールを作って自動化します。

■ツール概要

1.まず始めに記事のURLを取得します。
先日作成した記事の一覧を抽出するツールを使用します。
ikoda.shop
2.Indexing APIを使用して1.で取得したURLに対してインデックス登録リクエストします。

今回ツールはpython(anacondaを使用)で実装します。

■ツール実装

0.下記よりIndexing APIを使用するための準備を行います。
https://developers.google.com/search/apis/indexing-api/v3/prereqs?hl=ja

1.先日作成した記事の一覧を抽出するツール(ps1ファイル)を用意します。

2.同フォルダに下記のpythonファイルを下記で作成します。
尚、必要なモジュールは下記辺りでダウンロード可能です。
https://anaconda.org/conda-forge/google-auth
https://anaconda.org/conda-forge/google-api-python-client
https://anaconda.org/conda-forge/httplib2

from google.oauth2 import service_account
from googleapiclient.http import BatchHttpRequest
from googleapiclient.discovery import build 
import httplib2
import os

# 0.で取得できるjsonファイルです。
JSON_KEY_FILE = "XXXX.json"
SCOPES = [ "https://www.googleapis.com/auth/indexing" ]

credentials = service_account.Credentials.from_service_account_file(
    JSON_KEY_FILE, scopes=SCOPES)

service = build('indexing', 'v3', credentials=credentials)

def insert_event(request_id, response, exception):
    print(response	)
    print(request_id)
    if exception is not None:
       # Do something with the exception
       pass
    else:
       # Do something with the response
       pass

# "output_articles.ps1"は1.で用意したps1ファイルです。
os.system('powershell -Command' + ' ' +\
          'powershell -ExecutionPolicy RemoteSigned .\\output_articles.ps1 > articles.txt')
articles_list = [] 
with open('./articles.txt') as f:
    for line in f:
       articles_list.append(line.replace("\n",""))

batch = service.new_batch_http_request(callback=insert_event)

for item in articles_list:
	batch.add(service.urlNotifications().publish(
    body={"url": item , "type": "URL_UPDATED"}))

batch.execute()
■ツール実行

pythonファイルを実行
f:id:Simoroid:20211001011812p:plain
⇒リクエストが完了しました。
尚、リクエストなので即時反映される訳ではありません。
翌日あたりにSearch Consoleを覗きにいくと下記のように登録に成功しています!
f:id:Simoroid:20211001011803p:plain

ここまで 読んで頂きありがとうございました。
よければフォローお願いします!

はてなブログの記事一覧をPowerShellだけでお手軽に抽出

f:id:Simoroid:20210929002308p:plain
自分がはてなブログ作成した記事の一覧を抽出するための方法です。
スクレイピングするやり方も一つの手だと思いますが、PowerShellだけでサクッとやることが出来ました。

記事の一覧はブログに紐づくサイトマップを参照することで参照可能です。
自分のはてなブログサイトマップは「https://ikoda.shop/sitemap.xml」のような形式でアクセス可能です。
※100記事以上ある場合にurlの形式が変わってくるようなのですが、とりあえず無視します。

■ツール実装
下記を張り付けて任意のファイル名(拡張子がps1)で保存。

# サイトマップのURLを指定
$url = 'https://ikoda.shop/sitemap.xml'
$res = Invoke-WebRequest $url
$xmlObj = [xml]$res.Content

foreach($sitemap in $xmlObj.sitemapindex.sitemap){
	$res = Invoke-WebRequest $sitemap.loc
	$locObj = [xml]$res.Content
	
	foreach($urlset in $locObj.urlset){
		# 静的ページを省くためフィルタを適用
		if($urlset.url.loc -like "*/entry/*"){
			echo $urlset.url.loc
		}
	}
}
pause

■実行
ツールを右クリック->「PowerShellで実行」をクリックで実行

f:id:Simoroid:20210929001413p:plain
f:id:Simoroid:20210929001422p:plain

こんな感じでとれましたー

ここまで 読んで頂きありがとうございました。
よければフォローお願いします!