OmniAICreator/Qiita-1.07M huggingface dataset:
面倒なレスポンシブモックアップ画像を秒で生成するサービスを作った

## ある日のボク「モックアップ画像つくるの、だるくね？」

こういうモックアップ画像つくるのって面倒だよな？

面倒さで言えば、夏休みの宿題の進捗を
逐一確認してくるママくらい面倒だ！

*宿題のガントチャートが冷蔵庫に貼ってあるって何回言ったらわかるんだ！*

![A3B61638-6717-41AC-83AE-85393C1F6052.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560551/18de2247-0dac-0e37-5467-4fb622c4b7e8.jpeg)

*ちなみにこの画像はボクがいつかの夏休みの宿題でつくったWeb寄書きアプリのものさ*


## モックアップ生成を超かんたんにしたい！

次の夏休みにボクはこんなことを思ったんだ

**URLか画像を入力して**
**ボタンを押すだけで**
**モックアップ画像を生成したい！**
ってね

そしてできたサービスがこれさ！

[Works Thumbnail Genrator](https://works-thumbnail-generator.vercel.app/)
![3AA9D71E-7A5F-45E6-8866-562CB5A4DB1D.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560551/a4287031-f1f1-82ec-48a1-205f9d133ccb.jpeg)


> え〜っ！なにこれーっ！

そうそう
そういう通販番組みたいなリアクションがほしかったんだ

これを使えば、URLや画像から
いい感じのモックアップ画像を秒で生成してくれる！

> すご〜い！
> でも、ワタシに使いこなせるかしら〜？

安心してくれ！
使い方はとってもかんたんなんだ

![Screen Shot 0003-12-19 at 19.07.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560551/9586f9bf-3fdc-2b80-729e-7fa0199abab6.png)

1. URLまたは画像を入力する
1. 背景色を選ぶ
![Screen Shot 0003-12-19 at 19.08.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560551/6df63df6-a716-7cb8-3aa8-bda71da04e2a.png)

1. ボタンを押す

![Screen Shot 0003-12-19 at 19.09.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560551/be7d7770-e9ff-cd29-b3f9-4fe45e19e222.png)

たったこれだけだ！

> ほんとうに？
> とってもかんたん！




## 工夫したところ

実はこれだけじゃないんだ

> まだ何かあるの？


もちろんさ！

**1. プレビューがみられる**

URLや画像、背景色、モックアップパターンを変えると
ファーストビューのプレビューに反映されるんだ！

ボタンを押す前に、仕上がりをイメージすることができる！


**2. URLから作るのも、2回目以降は爆速**

スクリーンショットを取得する方法を
いろいろ試した結果、
Google PageSpeed Insights API を使っている

だから、どうしてもURLから画像を生成するとき
APIのレスポンスに時間がかかるんだ

そこで、1度結果を取得したらstateに保存し、
2回目以降は、URLが変わらなければ
初回に取得したデータからモックアップを生成することで
爆速を実現したんだ！


> すってき〜っ！
> でも、お高いんじゃない？


なんと無料で提供しているんだ１

> む、む、む、むりょうぅぅぅぅうう？！

そうなんだ！ぜひ使ってみてくれよ！


## さいごに

ここまで読んでくれてありがとう！

これは
[身の回りの困りごとを楽しく解決！【PR】Works Human Intelligence Advent Calendar 2021](https://qiita.com/advent-calendar/2021/works-hi
) の21日目の記事さ

身の回りっていうには少しニッチな内容だけど
まあ多めにみてくれよな！

**Follow ME !!!**
**I'm sure to follow you back!**
twitter: [@marty_ojiya](https://twitter.com/marty_ojiya)
新米エンジニアが3ヶ月間で学んだこと

##はじめに
__技術についての記事じゃないです！！すみません！！__

初めまして、新米エンジニアの竹ノ内と申します！
9月からエンジニアとして働いております！！

今回は年のおわりということで、いままでの3ヶ月の学びを
ざっくりとふりかえってみます！

もしなにか間違っていることやアドバイスなどありましたら
ぜひなんでもご意見いただきたいです！！


##これまで
###1ヶ月目
__会社での仕事__

- 開発環境の構築
- webシステムの改修

__読んだ本__

- いちばんやさしいPHPの教本
- 基礎からのMySQL

__できたこと__

- 会社のふんいきに慣れた
- 開発環境になれて、支障なく業務にあたれるようになった（gitやvagrantの簡単な操作や、ソースコードを自力で探して修正できる）
- chromedevtoolやvardumpの使い方などがわかり、ある程度は自力でデバッグできるようになった
- 初めて実際に使われているシステムにプログラムを実装した


###2ヶ月目

__会社での仕事__

- webシステムの改修

__読んだ本__

- 新しいLinuxの教科書
- スラスラわかるPHP

__できたこと__

- 多少、なにが問題なのか切りわけて見れるようになった（フロント側での問題か・サーバー側か、どこでデータを渡すのに失敗しているのかなど）
- 開発しているシステムについて、全体のイメージがなんとなく掴めてきた（どこでどんな処理をしているのか、どのファイルからどのファイルにデータを渡しているのかなど）
- 初めて仕様書づくりをした


###3ヶ月目

__会社での仕事__

- webシステムの改修

__読んだ本__

- PHP本格入門：上
- javascriptprimer（途中まで）

__できたこと__

- CRUDの簡単なシステムを自作した
- MVCモデルのことがようやくざっくり理解できてきて、ソースコードを読む速度が上がった
- ソースコードで意味がわからないところがかなり減ってきた


##感想とこれから

###感想

会社で主に使うのがPHPとJavaScriptだったので、
そこを中心に勉強しました。

PHPはそこそこ理解が深まってきていますが、
JavaScriptの方がすこし勉強たりてないことに気づきました。
仕事でもJavaScriptでわからないことが多いです。
来月からはJavaScriptについても勉強していきたいです。

LinuxやMySQLは、今の段階でここまで深くやらなくてもよかったかな？
本でなら体系的に学んでいけると思いましたが、ここの知識はまだそこまで使っていないです。
このへんはまだネットでググった知識で十分だったかもしれません。

なんにせよ、
しょーじき「もっと勉強できるな。。。」と感じております汗
勉強することの取捨選択だけじゃなくて、
勉強量ももうすこし増やしていかないとなー。。。

ちゃんと時間つくれば週に一冊くらいは技術書読んでいけると思うし、
足引っぱらないように、もっとやらねば(´-ω-`)

早くエンジニアとして一人前になりたいです٩( 'ω' )و 


###これから

開発の仕事はたのしいし、勉強していけば知識はふえますが
いまだにわからないことが多すぎて、
「ほんとにしっかり前に進めているのか？」と不安になります汗

でも、あんまり不安がってても途中で力尽きちゃいそうなので、
いまは仕事や勉強など、自分にできることを集中して
しっかりやっていこうと思います٩( 'ω' )و 


##最後に
今回は会社の方のよびかけで記事を書く機会を得ました。

じつは前から「記事を書いてみよう！」と思ってはいましたが
しょーじき手がつけられていませんでした。。。
いい機会をもらえてよかったです。

技術についての記事を書くことはまだ自信がなかったのでさけましたが、
つぎからは少しずつ技術についての記事にもチャレンジしてみようと思います・・・！

最後までお読みいただき、ありがとうございましたm(_ _)m
ペンの高速描画

ペンによる描画を行うとき、普通に実装すると一回の描画に1/30秒かかってしまいます。関数の描画を行おうとすると、ゆっくりとしたアニメーションになってしまいます（これは、教育的な側面を持つScratchとしてはあるべき動作だと思います）。
しかし3Dグラフィックなどで描画の過程を見せたくない場合は、再描画をしないブロックの中で描画を行うと、一瞬で描画が完了します。
サンプルでは、「描画」ボタンをクリックすると、ゆっくりとsin関数が描画されます。「高速描画」ボタンをクリックすると、一瞬でcos関数が描画されます。その違いを確認してみてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75307/587816d9-45e8-6a36-ef0d-32e406f87715.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75307/362e7398-288e-294e-a338-f83d4883189a.png)

サンプルプロジェクト
https://scratch.mit.edu/projects/619123259

![スクリーンショット](https://cdn2.scratch.mit.edu/get_image/project/619123259_480x320.png)
セキスペ合格のためにやったこと【令和3年秋季】

# 背景
もともと高度情報処理資格をなにか取りたくて、令和3年春季のネットワークスペシャリスト試験を受けたのですが、残念ながら[不合格でした。](https://qiita.com/foxtail1979/items/5fcdab0a85b230fb3c08)

来年の春にリベンジしようと思っていますので、知識が錆びつくのを防ぐために、関連知識の多い情報処理安全確保支援士試験を受けることにしました。
なお、合格しても登録はしないつもりなので、情報処理安全確保支援士試験合格者という扱いになリます。
弊社はこれでも合格報奨金が出るので、ラッキーちゃラッキーかもしれません。逆に言うと、報奨金が出るのに登録を推奨しないのはどうなんだろうとも思います。。

せっかくなので、誰かの役に立てばいいなと思って自分なりの勉強方法や使用した教材なんかを記録として残しておきます。

## 試験結果は合格でした。
結果から言うと、無事に合格できました！それなりに手応えがあったのでいけるかなとは思っていました。
高度情報区分の試験に合格したのは初めてなので、正直ホッとしています。

![IMG_2833.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581105/5a104d34-9525-9921-9046-e4189c766d55.jpeg)

午前１が最も低い得点でヒヤヒヤしました笑

## 使った教材
勉強に使った教材は次の通りです。

https://www.amazon.co.jp/dp/479816867X

https://www.amazon.co.jp/dp/4865752137

https://www.amazon.co.jp/dp/4532415462

これは絶版だったので、国会図書館まで行って閲覧してきました。
いまAmazonで見ると中古で高騰してますが入手はできるみたいですね。

https://www.amazon.co.jp/dp/4434258613/

午前対策は安定の過去問です。
午前1は応用情報処理試験の直近4〜6回を解きました。
直近3回は過去問の再利用が少ないとの情報を見かけたからです。

https://www.ap-siken.com/

午前２は直近6年分を繰り返し解いていました。

https://www.sc-siken.com/

## 勉強方針
基本的に下記のスケジュールです。

### 6月〜7月
・「情報処理教科書　情報処理安全確保支援士　2021年版」を流し読みする
　ざっくり流し読みして、馴染みのない知識があればその分野を読み込みます。それ以外の分野はほんとうに斜め読み程度です。

### 8月
・午前2の過去問を解き始める。Webサイトを利用して、通勤時間でスマホでぽちぽち解いていました。
・「2021　情報処理安全確保支援士「専門知識+午後問題」の重点対策(重点対策シリーズ)」　で午後問題に対する考え方を身につける。今回の試験合格MVPだと思います。午後問題にどう挑んだら良いか、ほんとうに分かりやすかったです。

### 9月
・「支援士18 情報処理安全確保支援士試験2018年度(春・秋)の午後問題を徹底解説」を国会図書館で閲覧する。国会図書館の書籍は館内での閲覧のみ可能です。
収録問題数が少ない分、解説がとても丁寧で、記述問題に対してどう回答を組み立てれば良いのか、考え方が分かりやすかったです。

・情報処理安全確保支援士の過去問(午後)を解き始める。
　

・「うかる！情報処理安全確保支援士　午後問題集」を通勤時間帯に流し読みする。Amazonレビューで直前対策にオススメとの評判を見て購入しました。確かに最初からこれを読んで学習するのは無理があると思いました。

### 10月
・午前1の過去問を解き始める。Webサイトを利用して、通勤時間でスマホでぽちぽち解いていました。

## まとめ
やはり高度試験は午後問題、特に記述問題の対策が合否を分けると思います。
個人的には、学習のもっと早い段階で下記に取り組み始めてもよかったかなと思いました。

https://www.amazon.co.jp/dp/4865752137

これ以外の本は正直あってもなくてもよかったかなという印象です。
知識を身につけることはもちろん大事ですが、出題者が求める回答を組み上げる能力は、繰り返し訓練が必要だなと感じました。情報処理安全確保支援士試験の受験を考えている方の参考になれば幸いです。
疑問点があれば、コメントいただけるとありがたいです。

次はネットワークスペシャリストにリベンジかな。
SpringBootで個人的に便利だと思った記法

# はじめに
[豊田高専 Advent Calendar 2021](https://qiita.com/advent-calendar/2021/nit_toyota)、19日目の記事になります。
SpringBootを触ってきて、個人的に便利だと思った記法をいくつか紹介しようかと思います。

# 時間の扱い方
SpringBootにおいて時間を扱う際は[Clock](https://docs.oracle.com/javase/jp/8/docs/api/java/time/Clock.html)をBean定義しておくとテストが書きやすい。
テストを書く際は`Before`, `BeforeEach`でテストしたい日付の[Instant](https://docs.oracle.com/javase/jp/8/docs/api/java/time/Instant.html)を定義し、`getClock`をモック化する。

```java:ClockConfig.java
@Configuration
public class ClockConfig {
    @Bean
    public Clock getClock() {
        return Clock.system(ZoneId.of("Asia/Tokyo"));
    }
}
```
```java:Sample.java
@Component
@RequiredArgsConstructor
public class Sample {
    private final ClockConfig clockConfig
    
    public void hoge() {
         Clock clock = clockConfig.getClock();
         LocalDateTime localDateTime = LocalDateTime.now(clock);
    }
}
```
```java:SampleTest.java
@SpringBootTest(classes = Sample.class)
public class SampleTest {
    @Autowired
    Sample sample;

    @MockBean
    ClockConfig clockConfig;

    @BeforeEach
    public void beforeEach() {
        //clockの初期化
        Instant instant = Instant.parse("2021-01-01T09:45:32Z");
        doReturn(Clock.fixed(instant, ZoneId.of("Asia/Tokyo")).when(clockConfig).getClock();
    }
}
```
# メトリクスの集め方
Micrometerを用いてExceptionの発生数などの任意のメトリクスを自由に取ることができます。
取得したメトリクスはPromethusで可視化することが可能です。

pom.xmlにモニタリングツールを追加します。

```xml:pom.xml
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-prometheus</artifactId>
        </dependency>
    </dependencies>
```

任意のExceptionの発生数をカウントするClassを作成します。
Metrics.counterの引数は`メトリクス名`,`タグ名`,`タグ詳細`になります。
サンプルコードで取得可能なメトリクス形式は以下のようになります。

```
api_exception_count_total{exception="IOException",} 0.0
api_exception_count_total{exception="Exception",} 0.0
```
```java:ExceptionCounter.java
@Component
public class ExceptionCounter {
    private final Counter ioException;
    private final Counter exception;

    public ExceptionCounter() {
        this.ioException = Metrics.counter("api.exception.count", "exception", "IOException");
        this.exception = Metrics.counter("api.exception.count", "exception", "Exception");
    }

    public void incrementIoException() {
        this.ioException.increment();
    }

    public void incrementException() {
        this.exception.increment();
    }
}
```
このClassを例外ハンドリングしているClassでインジェクションし、各Exceptionに合わせたincrementメソッドを実行すればMicrometerを用いた計測が可能です。

デフォルトではpromethusエンドポイントの一部しか公開されていないので、application.propertiesに以下を追加してエンドポイントを開放します。

```properties:application.properties
management.endpoints.web.exposure.include=prometheus
```
動作確認は`http://localhost:8080/actuator/prometheus`にアクセスすることで可能です。
# さいごに
Junit5のParameterizedTestについてのおまけを書こうと思いましたが、時間がないので断念しました。
コメント等つけば書くかもです。
Grammarlyのベンチマーキング

# 概要
みんな大好き[Grammarly](https://www.grammarly.com/)はGECベンチマーク上だとどのくらいの精度になるのか気になりすぎて夜しか眠れなかったので検証してみたというお話です。

# 検証
デベロッパー向けに[beta版のAPI](https://developer.grammarly.com/)が一応用意されているようですが、今回の用途（&その他もろもろのオーバーヘッド）を考えると、手元のGrammarly（有料版）を使った方が早そうだったのでそちらの環境で検証しました。その代わり?、有料版のGrammarlyに関しては、スペル・文法誤りなどいわゆる古典的なGECがフォーカスしてきたminimal editだけでなく、文章全体の流暢性や可読性など考慮したfluency editも提供してくれるため、そのあたりの差異も合わせて見ていこうと思います。

※ Minimal editとFluency editについては、先日書いた[こちらの記事](https://qiita.com/chemical_tree/items/33d409548f7e11728da7)で軽く触れているのでご覧ください。

# 設定
### モデル
- **Grammarly Basic**
    - Correctnessに関する修正を採用したときのシステム出力（minimal editの気持ち）
    - Correctness: スペル・文法・句読点の改善に関する修正
- **Grammarly Advanced**
    - Correctnessに加えて、Clarity, Engagement, Deliveryに関する修正を採用したときのシステム出力（fluency editの気持ち）
    - Clarity: 文章の可読性の改善に関する修正（e.g., conciseness, clarity, readability）
    - Engagement: 文章をより魅力的かつ効果的にするための修正（e.g., vocabulary, variety）
    - Delivery: 読み手に正しい印象を与えるための修正（e.g, formality, sensitivity）

### 評価
- 評価データ: JFLEG test
- 評価尺度: GLEU

CoNLL-2014ではなくJFLEGを選択したのは、Grammarly Advancedを考えると、fluency-editに対応したJFLEGを用いた方がそのポテンシャルを評価できるかなと思ったからです。

# 結果


| モデル| GLEU |
|:---| ---: |
| [Stahlberg&Kumar.（2021）](https://aclanthology.org/2021.bea-1.4.pdf)| 64.7 |
| [Mita et al.（2020）](https://aclanthology.org/2020.findings-emnlp.26.pdf)| 63.7 |
| [Kiyono et al.（2019）](https://aclanthology.org/D19-1119.pdf)| 61.4 |
| [Junczys-Dowmunt et al.（2018）](https://aclanthology.org/N18-1055.pdf)| 59.9 |
| [Chollampatt et al.（2018）](https://www.aaai.org/ocs/index.php/AAAI/AAAI18/paper/viewFile/17308/16137)| 57.5 
| Grammarly Basic| 56.7 |
| Grammarly Advanced| 52.6 |

Grammarly Basicの精度はCNN Seq2Seq（Chollampatt+2018）くらいの精度でした。
個人的には思ったより低いなと感じましたが、Grammarlyが出した高性能GECモデル [GECToR](https://arxiv.org/pdf/2005.12592.pdf)は、なぜかJFLEGだけ評価されていないので実際のところどうなんでしょう（もちろん、GECToRをそのままプロダクトに入れているわけではないと思いますが...）。
あと、BasicよりもAdvancedの方が低いという少し意外な結果になりました。ただし、上に書いたようにAdvancedは厳密に言うと、単純に文の流暢性に関する修正だけでなく、より高次な修正（clarity, engagement, deliver）もしているので、決して最終アウトプットの質がBasicよりも低いか、と言われるとそうでもないように見えます（むしろ質は高くなっていると感じます）。このあたりは、スペル・文法誤りなどの低次な修正に比べて、文書全体の読みやすさやなど高次な修正における妥当なリファレンスはより多岐にわたる（varianceが大きい）ので、リファレンスあり評価の限界という側面は大いにあるように感じます。

# おわりに
Grammarlyの性能をGECの既存ベンチマーク上で測ってみたという話をしました。やはり実際にプロダクトに落とし込む上では単にニューラルでポンという話ではなく、モデルの軽量化含めてプロダクト側でいろいろ泥臭いことがあるかと想像するのでそのあたりのリアル話は気になりますね。
ということで（!?）、詳細は別途正式にアナウンスがあるかと思いますが、私の所属する理研AIP主催で来年の頭あたりにGrammarlyの人たちをお呼びしてトークをしてもらう予定です。上のような踏み込んだ話も聞けると思うのでもし興味がある方はぜひご参加ください（ステマ）！
React hooksでapiなどの非同期処理(async/await)を実施する方法と注意点

reactでAPIアクセスなどの非同期な処理を実施したい。
割と常識的な内容ですが、初心者の頃にうまくピンポイントな記事に巡り合う事ができなかったので書きました。

# React hookでasync/await 非同期処理を実施する方法

非同期処理を実施するためには副作用フックと呼ばれるuseEffectを使います。
https://ja.reactjs.org/docs/hooks-effect.html

useEffectは第一引数に関数を受け取りその関数内で非同期な処理を実行することができます。

```JSX
import { useEffect, useState } from 'react';

function ExampleComponent {
    const [state, setState] = useState("");
    useEffect(() => {
        // useEffect自体ではasyncの関数を受け取れないので内部で関数を定義して呼び出す。
        const access_db = async () => {
            const response = await fetch("http://example.com/nanika.json");
            const body = await response.json();
            setState(body); // stateに反映する
        };
        access_db();
    }, []);

    // stateに応じた描画
    return <pre>{state.toString()}</pre> 
}
```

上記では第二引数に空配列を指定しているので、useEffectはコンポーネントが生きている間に一回のみ実行されるようになっています。

# useEffectの第二引数を誤ると無限ループが発生する

公式の第二引数についての説明はなかなか抽象的で何を言っているのか分かりづらいと思います。
分かりやすく説明すると、useEffectの中身を再度実行するためのトリガーになる変数(stateやprops)を配列には入れておきます。

最初の例ではコンポーネントがレンダリングされるとき一回のみuseEffect内の処理が実施されてほしいので空配列を指定しています。

この引数の指定を間違えても一見うまく動いてるように見える事が多いのですが、内部ではレンダリングの無限ループが始まります。
最初の例のプログラムでは下記のような書き方をした場合無限ループに陥ります。

```Typescript
// JSXに使われているすべての変数（stateやprops）の変化に反応する
useEffect(() => {/*非同期処理*/}) 

// stateの全変化に反応する
useEffect(() => {/*非同期処理*/}, [state])
```

reactではstateの状態が変化した時に再度レンダリングが走るので…

初回レンダリング→遅れてuseEffect内の処理がステートを更新→ステートが状態変化したので再度useEffectの処理→ステートが状態変化したので再度useEffectの処理…

上記の様な無限ループに陥ります。

# useEffectの第二引数にあえて指定する場合

第二引数にはあえてもう一度useEffect内の処理をもう一度実施したいときにそのトリガーになる変数（stateやprops）を指定します。

下記の例では、propsから送られてきたcountが変更された際に違うapiにアクセスさせたいので、useEffectの第二引数にcountを指定しています。

```JSX
function ExampleComponent(props: {
  count: number
}) {
    const [state, setState] = useState("");
    useEffect(() => {
        // useEffectではasyncの関数を受け取れないので内部で関数を定義して呼び出す。
        const access_db = async () => {
            // countに応じてアクセスするAPIを変えなければならない
            const url = "http://example.com/"+props.count.toString()+"/nanika.json";
            const response = await fetch(url);
            const body = await response.json();
            setState(body); // stateに反映する
        };
        access_db();
    }, [props.count]);
    // stateに応じた描画
    return (<pre>{state.toString()}</pre>);
}
```

countが更新されるときのみuseEffectが再実行されるようになります。
Ruby: stripe API 使い方 (List all customers)

こちらのページの続きです。
[stripe API 使い方 (List all customers)](https://qiita.com/ekzemplaro/items/ed152ef41f1e81811519)

#Ruby Faraday でカスタマーの一覧を取得#

```rb:get_customers_faraday.rb
#! /usr/bin/ruby
#
#	get_customers_faraday.rb
#
#					Dec/19/2021
# ---------------------------------------------------------------------
require 'faraday'
require 'json'
require "dotenv"
Dotenv.load
secret_key = ENV['SECRET_KEY']

STDERR.puts "*** 開始 ***"
#
url="https://api.stripe.com/v1/customers"
#
headers = {"Authorization": "Bearer " + secret_key}
res = Faraday.get(url, params = nil, headers = headers)

puts    res.status
json_str = res.body

dict_aa=JSON.parse(json_str)

puts dict_aa["data"].length
#
dict_aa["data"].each  do |unit|
	puts unit["id"]
end
#
STDERR.puts "*** 終了 ***"
# ---------------------------------------------------------------------
```

実行結果

```text
$ ./get_customers_faraday.rb 
*** 開始 ***
200
4
cus_KmrIU4hzWqYt7R
cus_KmoG4k1wiKxSDc
cus_KmnqmJhBAvPGMq
cus_KmnpiRFjm8he97
*** 終了 ***
```

#Ruby sdk でカスタマーの一覧を取得#

sdk のインストール

```bash
sudo gem install stripe
```

```rb:get_customers_sdk.rb
#! /usr/bin/ruby
#
#	get_customers_sdk.rb
#
#					Dec/19/2021
# ---------------------------------------------------------------------
require 'stripe'
require "dotenv"
Dotenv.load
Stripe.api_key = ENV['SECRET_KEY']

cc = Stripe::Customer.list({limit: 10})

puts cc["data"].length
#
cc["data"].each  do |unit|
	puts unit["id"]
end
# ---------------------------------------------------------------------
```

実行結果

```text
$ ./get_customers_sdk.rb 
4
cus_KmrIU4hzWqYt7R
cus_KmoG4k1wiKxSDc
cus_KmnqmJhBAvPGMq
cus_KmnpiRFjm8he97
```
Bootstrapと Fontawesome で綺麗なLINEアイコンを作る

##プロローグ

アプリ版Noteのフローティングアイコンの様に，綺麗なLINEアイコンを作りたい！
と思った場合，Twiterアイコンのようには単純には作れなかったので以下にソースコードを共有します．

##完成イメージ
ちなみに完成図は以下，

![スクリーンショット 2021-12-19 18.55.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1900756/a4f1340c-0f03-cdb9-ad27-dd9d62ffc0da.png)


完成リンクは以下．

https://mini.kaedeee.com

##ソースコード
参考までに，Twitterアイコン用のソースコード量よりもLINEアイコン用ソースコードの方が多いことが見て取れます！


```
<div class="fixed-action-btn position-fixed bottom-0 start-0 " style="height: 65px; width: 185px;">
  <section class="text-center">
    <!-- twitter share -->
    <button class="btn btn-floating btn-dark btn-lg ripple-surface" style="min-width: 45px; background-color:#1DA1F2"
      type="button" onclick="share2Twitter()">
      <i class="fab fa-twitter fa-lg"></i>
    </button>
    <!-- line share -->
    <button class="btn btn-floating btn-dark btn-lg ripple-surface" style="min-width: 45px; background-color:#00B900"
      type="button" onclick="share2Line()">
      <i class="fas fa-circle fa-lg" style="color: #ffffff;"></i>
      <i class="fab fa-line fa-2x" style="color: #00B900;position:relative; top: -45px;"></i>
    </button>
    <!-- web share api-->
    <button class="btn btn-floating btn-light btn-lg ripple-surface" style="min-width: 45px; background-color:#ffffff"
      type="button" onclick="share()">
      <i class="fas fa-share-alt"></i>
    </button>
  </section>
  <!-- Menu button -->
</div>
```

##おしまい
終わり
学びながら個人開発するって難しいよな！

## 使ったことない技術で個人開発をするボク
カタカタカタ…

「うーむ、調べないとわからないな！」

カタカタカタ…

カタカタカタ
カタカタカタ…

「おやおや、何だかエラーがでてるじゃないか！」
カタカタカタ…

「ジーザス…思い通りの結果にならない」

「そうこうしているうちに、始業の時間だ！」
「まいったよ、思ったより進まなかった！」


## 思ったより進まない日々が続く

少し勉強した程度の使ったことがない言語や
フレームワーク、ライブラリで個人開発をすると

思ったよりも進まないことが多くないかい？

ボクはよくあるんだ

特に、平日とかの
まとまった時間がとれない日さ

ひどいときは
> ここ数日何をしていたんだろう…

そんな気持ちになってくる！

一方で
ノリノリで開発できてる時期もあるんだぜ？

いったここの違いはなんなんだ！
って思わないかい？

## 背伸びした技術で個人開発するときの、浮き沈み

それはそうとキミは何で個人開発をしているんだい？

もちろん個人開発をやる目的は、十人十色さ

そんななかでも、**自分の成長のため**っていうのは
少しはあったりしないかい？
どうだい？


きっと、YESと答えたそこのキミは

使ったことのない技術を使ったり
やったことのない設計手法をとったり

みたいに、少し背伸びをした個人開発をしていると思うんだ

背伸びをしていても（していなくても）

 - 開発が思うように進んでいる
 - エラーやバグを解消できた
 - リリースできた

そんなときは、ノリに乗って開発ができているはずだ！

**浮き沈みでいえば浮いた状態**だな！
言うなれば、クリームソーダのバニラアイスさ

沈んでるのを見たことがないだろう？
*(あれはいったいどういう原理だい？)*



しかし一方で、背伸びした技術で開発しているが故に

 - 使い方を理解しきれておらず、思うような結果にならない
 - 使い方を理解しきれておらず、エラーが解消できない
 - 今のやり方がベストプラクティスに思えない

ということが起きる！

そのときは
**自分の成長を実感しずらく**
**開発も進まないので**
**パソコンに向かうのがちょっと億劫になる**のさ

浮き沈みでいえば**沈んだ状態**だな！

ミルクティーに沈むタピオカみたいに、奥底に沈んでいるんだ
太いストローを使わないと飲めやしない


そんなときは、進捗だけじゃなく
自分の成長すらも停滞しているように錯覚してしまう！



## 停滞しているようにみえるけど、キミは成長している。


キミはパソコンの前で藻掻いている

そうだろう？

少なくともボクはそうさ


だからこそ、前進できないとより沈むわけだが…

少し冷静になって考えてみたら

こう思えたんだ

**進捗は停滞していても**
**前進するために藻掻いたすべては**
**キミの成長に繋がっている**

ってね


なぜなら藻掻いているときに

いろんなことを調べてインプットしているだろう？
いろんなコードを書いて試行錯誤するだろう？

**それらをして得られるほぼすべては、**
**新しい発見だから**なんだ


かの有名なエジソンの言葉を
キミも聞いたことがあるだろう？

> **私は失敗したことがない。**
> **ただ、うまくいかない方法を1万通りの見つけただけだ。**



## 確かにそうかもしれないけど、そう思い続けるのは難しい


正論、それはときに人の精神を激しく攻撃する

きっとこの例もそうなんだ

すべて自分の成長に繋がっていると思いたくても
なかなか思えない瞬間はどうしてもある


だからボクは、**自分が思うだけでなく
客観的に成長を可視化してくれるものがほしい！**
と思ったんだ


## いまつくっているもの


これは今ボクが個人開発でつくっている
成長を可視化する、個人開発者向けSNSのダッシュボード画面さ
*（正直まだ人に見せられるものではないんだけど…）*

![Screen Shot 0003-12-19 at 18.33.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560551/678f0afa-d3cb-f6d8-29f3-2b899f73650c.png)


個人開発のプロジェクトを作成して
プロジェクトについてのタスクを管理しながら
進捗があると経験値やレベルがあがっていくという
ゲーミフィケーションをいれたものをイメージしていてね

`個人開発者向けSNS`と謳っているのは
その進捗をタイムラインで共有して称賛し合ったり、応援し合ったりできたら
最高だなと思って、そういう機能をいれたいからなんだ


まだまだボク個人が実験的に使いながら、改修している段階で
十分ブラッシュアップができたら
ちゃんと作り込んでいきたいと思ったいるよ！

個人開発をもっと楽しく、もっとワクワクするものにできたらいいな！

完成したらぜひ使ってくれよ！



## だいじょうぶ、向き合った分だけキミ（ボク）は必ず成長している

ここまで読んでくれてありがとう！

ボクと同じように背伸びした個人開発で
思うように進捗できないと感じている人を
勇気づけられたら嬉しいよ

これからも楽しんで個人開発やっていこう！


**Follow ME !!!**
**I'm sure to follow you back!**
twitter: [@marty_ojiya](https://twitter.com/marty_ojiya)
RPA関白宣言

この記事は、[PERSOL PROCESS & TECHNOLOGY Advent Calendar 2021](https://qiita.com/advent-calendar/2021/ppt) の 19日目の記事です。

---

ふだんはRPAを使った業務効率化の支援を実施しています。
このたび機会をいただいたのでRPAの紹介をしようと思ったのですが、なぜかこのタイトルだけが先に浮かんでしまったので、すみませんが書かせてください。


---

仕事を自動化する前に　言っておきたい事がある

かなりきびしい話もするが　俺の本音を聴いておけ

整頓前に依頼しないで　要件丸投げするのもやめろ

手順はぜんぶ書け　抜け漏れなしでヨロ（しく）

出来る範囲で構わないから

忘れてくれるな　ルールも決まらぬ仕事に

自動化実現するなど無理ってことを

お前にはお前にしかできない事もあるから

それ以外は口出しせず　黙ってロボに任せてくれ

---
電子地図関連のお仕事をする際の基本 ～その①～

# はじめに

この記事は、なかなか人が増えない地図データ作成チームのために書いてます。

私は、直近の6，7年ほど防災系のシステム構築を担当しています。

防災系のシステムというと、避難所のデータ管理であったり、備蓄物資の管理、緊急時の市職員への連絡といった機能を提供しています。

この防災システム構築作業の中には、ハザードマップに関するものもあります。
災害の発生個所や洪水や津波といった危険個所をブラウザの地図画面に表示する、といったものなのですが、

この表示される災害用の地図データ作成というのが、人手がかかる厄介な代物なんですが、
育成面でも手のかかる、人員の定着し辛い物でもあるんです。。。

何故、人員が定着し辛いか？

それは、実際に作業をするまでの敷居が高く、また内容もマニアックなのでプログラミングの様に応用が利きづらい面もあり、一度人員が固定されてしまうとその人ばかりに作業が集中してしまうのです。

こうした事象を軽減する意味でも基本的な知識を順を追って説明しようというのが、この記事の主旨になります。

実際、一度知識を入れてしまえば、私の体感で恐縮ですが６，７割の作業は新卒１，２年目の方で対応できるものです。

なので、Webアプリケーションで地図サービスを扱う取っ掛かりの読み物として頂くのもいいかと思います。

# まずは完成系をイメージするところから始める

知識が無い状態からいきなり地図データ作成を、と言っても無理なのは目に見えているのでまずは完成系のハザードマップを見てイメージをつかみます。

防災システムのハザードマップというと、近年は各都道府県ごとに構築されていて、サイト検索をかければすぐにもヒットするかと思います。
例えば、東京都のハザードマップは、[東京都防災マップ](https://map.bosai.metro.tokyo.lg.jp/)という名前で公開されているのですが、トップ画面にハザードマップが表示されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145985/6bc5d9b7-bb32-badc-67ed-624d0e78068c.png)

この画像の例では、南多摩駅の付近で土砂災害が発生するかもしれない場所を見るために、左側のメニューから土砂災害警戒区域に関する情報にチェックを入れて画面に表示させています。

こんな風に地図に対して、災害情報を重ね合わせることで機能として提供していると思って下さい。

# どんな仕事として依頼されるのか？

次に実際に作業依頼としてどんなものがあるかというと、大抵は地図の上に出す災害情報の更新や追加だったりするわけです。

* 「〇〇県の浸水想定区域に関する情報が更新されたので、データを入れ替えてほしい」
* 「新規の避難所に関するデータを追加してほしい」
* 「新しい道路を追加してほしい」

依頼としてはこんな感じですね。地図自体のデータを更新するといった作業はほぼ来ないと思います。
（あることはあるんですがね、、、今後別枠で。）

依頼を受けた時点でベテランさんになってくると

* まずはベースとなる地図データを[国土数値情報](https://nlftp.mlit.go.jp/ksj/)のサイトからDLして
* あるいは地方自治体の担当者の方に、更新データを受領して
* 担当しているシステムの測地系と座標系をチェックして
* データの加工。属性情報の増減を考えて
* ブラウザ側で描画できるよう `geojson`形式のファイルに変換して
* 納期までに何人月かかるかな？

といった作業の流れと、地域による人手の計算を始めるわけです。
そして、納期の期間が短いと新人さんへのスキトラを諦めることになるのです。

そんな訳にも行かないので、以降は

* まずは地図が表示される大まかな仕組みを知る

（ここから先は別記事になるかと。）

* 次にその仕組みの中で取り扱ってるデータについて知る
* 作業の準備としてツールを用意する



# そもそもなんで防災マップって表示されるのか？

さて、そもそも何故ブラウザ上で地図って閲覧できるのでしょうか。
ハザードマップもそうですが、Google マップ なんかも近くのお店で検索してアイコンが表示されたりする訳ですが一体どうなっているのか。

結論から書いてしまうとGISサービスを提供するサーバがあって、そのサーバに対してアプリケーションサーバからリクエストを送信して、
その結果を元にブラウザがマップを表示しているからです。

はい、ザ・ポカンとする話になりました。当然です。
少しずつかみ砕いていきます。一般的なWebアプリケーションの仕組みというのはここでは割愛させてもらいますが。

おおよそ、下の様な流れでページを表示しているわけです。

![picture1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145985/57449e37-1499-9dc0-82ac-2dd99cc6374f.png)


地図を表示するというのは`GIS`という地図の表示に特化したシステムが居ると考えて下さい。
このGISから提供されている各種のサービスを利用して、Webサーバでブラウザ上に表示される地図画面を構築しているというわけです。

GIS の明確な定義に関しては、下記のサイトや他の地図サービスを提供している企業のサイトに記載されています。

https://www.mlit.go.jp/kokudoseisaku/gis/guidance/guidance_1.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145985/0e344fa2-a4d9-cf6f-6977-51f7d0259610.png)

* GIS(Geographic Information System: 地理情報システム)：
位置空間に関する情報を基本となる地図上に重ね合わせ、情報を視覚化し、分析、統合管理するシステム

ちょっと硬くて分かりにくい表現ですが、要はベースとなる`背景地図`の上に、`レイヤー`とよばれる地図データの層を重ねることで

このレイヤーが扱う情報は、地物（建物、道路、河川）や事象（人口分布、天気、渋滞情報）など多岐に渡り、表示/非表示を切り替えたり、データが持つ属性情報、例えば建物なら店名や住所といった情報を付与して地図上に表示できるようになります。

# さて、ここまで来て

ざっくりとになりますが、ここまで読んで頂ければ
`地図データの作成` ≒ `レイヤーの作成`

と言うのが分かるかと思います。
そして、レイヤーってどう作成するのか？という話になりますが、はっきり言って専用のソフトを使えばデータ読み込むだけで大半は片が付く楽な作業です。



電子的な地図データの取り扱いが分かっていればという前提が必要ですが、、、、

次回はその辺りを説明したいと思います。
1セグメント全断の土曜日(Part3)

これは [本番環境でやらかしちゃった人 Advent Calendar 2021](https://qiita.com/advent-calendar/2021/yarakashi-production) 19日目です。[昨日](https://qiita.com/debu-despot/items/f83788bb45f72d733f43)は debu-despot さんによる要件スコープとブラウザ環境に苦しむお話でした。

個人的には6日目の kaizen_nagoya さんによる[「配電盤の電源を切る」](https://qiita.com/kaizen_nagoya/items/5fee2f3a4fb3cede675c)を読んでから何かを思い出してしまい安眠と心の平穏が失われています。いえ、絶対書きません。もう忘れるんだ..僕決めたんだ..

## tl;dr 兼 原因と対策

Outboundの通信のsource IP addressは確認しましょう
トリッキーな回避策を行う場合は影響(副作用)をしっかり洗い出しましょう
冷静な判断ができるように障害対応の体制は整えましょう

## 前回までのあらすじ

本投稿は 本番環境でやらかしちゃった人 Advent Calendar [2019](https://qiita.com/Words4MyRegret/items/e0b70aff25412655b9ed "1セグメント全断の土曜日") [2020](https://qiita.com/Words4MyRegret/items/937a531772c820a8dc5c "1セグメント全断の土曜日 Part2") からの連作となっております。2019では一つ目のセグメントが機器交換後の確認漏れにより、2020ではCDN経由でもオリジンサーバーが気を失うほどのアクセス過多により二つ目のセグメントが全断に至りました。しかし終わりではありません。

## 経過

第一セグメントが落ちた後、原因となったサーバーを切り離して調査していた段階では第一セグメントの復旧にはFirewallのエンジニアを呼び出す必要がありそうだと判断していました(並行して調査も行っていたので、2019で書いた通り最大同時接続数が縮退していたと後に判明したので結果的にFirewallに詳しいエンジニアを待たずに対処はできました)

そこで回線帯域もFirewall性能も当時一番ハイスペックな構成だった第三セグメントに該当サーバーを移設することで復旧を試みました。サーバーのIPアドレスとDNS Aレコードは第三セグメントのIPアドレスに変更します。さらに監視やシステム連携のために旧IPアドレス宛ての通信も残るのでコアスイッチ以下に/32でスタティックルートを第三セグメント宛てに向けてFirewallでNATさせることで旧IPアドレスでのアクセスも第三セグメントに流します。

セグメント移行作業は該当の全サーバーで完了し、動作確認も取れました。ウェブのアクセスを解放する前にいったんお客様へ連絡して動作確認をお願いします。

やれやれと一息ついたのもつかの間、お客様からは「途中から反応が無くなった」との連絡が入り、ほぼ同時に第三セグメントのサーバーすべての監視からアラートが飛んできまたのですっ

## 詳しい原因

トラフィックがループしていました...
・ホスティングサービスということでWebminのようなコンパネを提供していましたが、コンパネが旧アドレスにbindされた状態で起動していました

・お客様の複数のサーバーにまたがる操作をコンパネから行うと、サーバーから自発的に送信されるOutbound通信が発生します
　src:第一セグメント → dst:第三セグメント という通信が第三セグメントに移設したサーバーから発生
　L2レベルでdstへ到達した後、
　応答をsrcである第一セグメントのアドレスへ替えそうとするので当ホスティングサービスのセグメント間通信用のルートへ向かい、
　リクエストが無いのにリプライが来たと判定されて非対称通信がdenyされ、
　denyメッセージ(再送リクエストだったかもです。記憶が曖昧です)が追加した/32のルーティングで移設したサーバーへ返り、
　サーバーからは再送が行われ... という状況でした

## 復旧

第三セグメントはFirewallは落ちずにスイッチ配下の機器のみ監視が落ちている状態でした。現地ラックへ行き、まずは移設したサーバー達のケーブルをいったん抜き、次にLEDが真っ赤なL2スイッチ達を再起動してひとまず復旧しました。
スイッチは再起動してしまったので直近のログは見られなかったのですが、移設したサーバーを調べるとコンパネのログが異常に肥大化していました。内容を確認してbindアドレスを第三セグメントのものに変更して完全復旧しました。

## 反省点

```shell
grep "第一セグメントのプレフィックス" -r /etc
```

でIPアドレス変更作業後の確認を行ったため、/usr 以下にあったコンパネの設定ファイルを見落としたのが敗因でした。
また、作業後にも `netstat` を一度見ていれば気付けたと思います。
第一、第二セグメントの障害を捌きながら並行しての対応だったので漏れてしまいましたね...

## さらなる反省点

土曜日だったとは言え私がインシデントコマンダーとアラートの通知受けと作業者を兼ねて捌いていたのも敗因でした。第三セグメントについては完全に作業の不備です。
第一セグメントのFirewallの復旧見込みが分からなかったので復旧を優先するとしても、コアスイッチに/32のルーティングを追加してまで行うこの対処はおそらくベストではなかったと思います。

## 補足

いろいろありましたが障害自体は復旧しました。
しかし山のようなアラートとお客様からのお問い合わせ(クレーム)が残っています。。。

次回、最終話「Leyer8の死闘、一斉連絡と一斉監視再開が招いたアラート倍増の怪」
できればもうｶｷﾀｸﾅｲﾃﾞｽ
[Amplify] graphqlスキーマ編集した後に、mockでquery叩くたびに`Query condition missed key schema element `で怒られる

## はじめに
これは、DB操作に不慣れな弱々フロントエンドエンジニアのつまづき記録です〜〜〜

## 環境
- aws-amplify
- next.js


queryやmutationはamplify mock apiコマンドを使用したmockを叩いています！


##状況
下記記事を参考に　多対多のリレーション作成のためにgraphql schemaを下記に変更

変更前

```
type Resource @model {
  id: ID!
  categoryId: ID!
  userId: ID!
  title: String!
  url: String!
  category: Category @connection(fields: ["categoryId"])
}

type User @model {
  id: ID!
  name: String!
  email: String!
  profileImagePath: String!
  progressRate: Int!
  resourcesCount: Int!
  posts: [Post] @connection(keyName: "postsByUserId", fields: ["id"])
}


````

変更後

````
type Resource @model {
  id: ID!
  categoryId: ID!
  userId: ID!
  title: String!
  url: String!
  category: Category @connection(fields: ["categoryId"])
  users: [ResourceUser] @connection(keyName: "byResource", fields: ["id"])
}

type ResourceUser
  @model(queries: null)
  @key(name: "byResource", fields: ["resourceId", "userId"])
  @key(name: "byUser", fields: ["userId", "resourceId"]) {
  id: ID!
  resourceId: ID!
  userId: ID!
  resource: Resource! @connection(fields: ["resourceId"])
  user: User! @connection(fields: ["userId"])
}
type User @model {
  id: ID!
  name: String!
  email: String!
  profileImagePath: String!
  progressRate: Int!
  resourcesCount: Int!
  posts: [Post] @connection(keyName: "postsByUserId", fields: ["id"])
  resources: [ResourceUser] @connection(keyName: "byUser", fields: ["id"])
}

```


https://docs.amplify.aws/cli-legacy/graphql-transformer/connection/

これで、多対多のリレーション行ける〜〜と舞い上がってたら、




```javascript
const fetchCurrentUser = async (userId: string) => {
  try {
    return (await API.graphql({
      query: getUser,
      variables: {
        id: userId,
      },
    })) as { data: GetUserQuery }
  } catch (error) {
    console.error(error)
  }
}


```

って感じでクエリ叩いてるところで、`Query condition missed key schema element `でめっちゃ怒られました。

## 結論
理由わからず奮闘しましたが、
mock-dataが古いから新しいスキーマと型合ってないけど大丈夫か？と怒られてるだけでした。


なので、amplifyディレクトリ内のmock-dataを削除して、`amplify mock api`
を叩き直せば解決しました。




## 終わりに
リレーションとかDBがらみの設定変更したら、DBリセットするの忘れんように要注意じゃ~~








## 参考文献

https://github.com/aws-amplify/amplify-cli/issues/2210
AtCoder Beginner Contest 006をやった(Java)

AtCoder Beginner Contest 006をやった。

B問題だから簡単！ということではなくて、今回のB問題は緑相当でしたし・・・
C問題も緑だし、、C問題は解説見たけど意識が遠のいていく感じがしたのでまた今度で()

##[A](https://atcoder.jp/contests/abc006/tasks/abc006_1)
FizzBuzzの問題です。プログラム学び始めたときはお世話になりました。。。
いろんな実装方法があるかと思いますが、僕は剰余で。

```Java
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        // Your code here!
        Scanner scan = new Scanner(System.in);
        ArrayList<Integer> list = new ArrayList<Integer>();
        
        list.add(scan.nextInt());
        
        if(list.get(0) % 3 == 0){
            System.out.println("YES");
        } else {
            System.out.println("NO");
        }
    }
}

```

##[B](https://atcoder.jp/contests/abc006/tasks/abc006_2)
正直、自力で解けなかったので解説見ました。
解説に書いてあることが本当かを紙に書きながらあっているか確認して、、、(アナログ)
例えば、27項目を生成するときは
(list.get(26-3) + list.get(26-2) + list.get(26-1)) % 10007
とそれぞれの項に、都度10007の剰余をした和は上の計算式と同じになるか、、、みたいな。
小学校の分配法則を理解できていなかった主です(泣)。

```Java
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        // Your code here!
        Scanner scan = new Scanner(System.in);
        ArrayList<Long> list = new ArrayList<Long>();
        
        int scInt = scan.nextInt();
        list.add(0L);
        list.add(0L);
        list.add(1L);
        
        if(scInt <= 3){
            System.out.println(list.get(scInt - 1) % 10007);  
        } else {
            for(int i = 3; i <= scInt; i++){
                list.add(i, ((list.get(i-3) % 10007) + (list.get(i-2) % 10007) + (list.get(i-1) % 10007)));
                if(list.get(i) >= 10007){
                  list.set(i, list.get(i) % 10007);
                }
            }
            System.out.println(list.get(scInt - 1));
        }
    }
}


```
[UiPath] Orchestratorを使うなら記録機能を！

この記事は、[UiPath Advent Calendar (produced with UiPath Friends)](https://qiita.com/advent-calendar/2021/uipath) の 16日目の記事です。
（間に合いませんでした…………）

----

:::note warn
【おことわり】
この機能は、オンプレミスの Orchestrator か、もしくはEnterpriseライセンスプランのCloud Orchestratorでのみ利用可能です。
:::

# 記録機能って？

UiPath Orchestrator には、2020.10 以上のバージョンから「記録機能」が実装されています。
これはジョブが失敗した場合に、そのジョブで実施した操作のスクリーンショットを自動的に取得・保存し、Orchestratorから確認またはダウンロードできる機能です。

# 記録機能を有効にする

記録機能は、機能を利用したいプロセスごとに設定を有効化する必要があります。
設定は、プロセスの新規作成または編集の画面に存在しており、「記録機能を有効化」を ON にすることで有効になります。
ここには以下の設定項目があります。

- 表示スケール（%）
    - 保存される画像の、解像度に対する大きさの割合を指定します。
    - デフォルトは 100 です。25 ～ 100 の数値を指定します。
- 頻度（ミリ秒）
    - スクリーンショットを取得する頻度を指定します。
    - デフォルトは 500 です。250 ～ 10,000 の数値を指定します。
- 期間（秒）
    - スクリーンショットを取得する時間を指定します。
    - デフォルトは 40 です。1 ～ 120 の数値を指定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36038/1dd7c1ee-9ab5-628e-92f8-e0adf4cc0c81.png)


# 記録される条件

記録機能が実際に動作するのは、対象のジョブが失敗した場合のみです。この「失敗」というのは、ジョブとしての失敗を指します。
もう少し具体的にいうと、例外がメインエントリポイント（デフォルトはMain.xamlです）においてもキャッチされなかった場合が該当します。
逆に、ジョブが最終的に例外によって終了しなければジョブとしては失敗とならないため、記録機能は動作しません。よく、処理が失敗した場合であってもジョブとしては成功となるような実装となっているケースを見受けますが、この場合も同様に、記録機能は動作しません。

# どんなふうに記録されるか？

記録の確認方法は2つあります。

## Orchestrator上で確認する

Orchestrator上で確認するには、失敗したジョブの詳細を表示します。
正しく取得されていれば、下記画像のように詳細表示の下部に、スクリーンショットのメニューが表示されます。
画像の下部にあるメニューで表示する画像を切り替えたり、また画像をクリックすることで画像の生データを表示させることが出来ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36038/11a99c07-bfbb-b4da-efde-84b52a963863.png)

## ダウンロードして確認する

画像はすべて一括してダウンロードできます。
ダウンロードするには、ジョブのメニューから「記録のダウンロード」を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36038/2f05490b-a16b-b38e-6f96-75c13c05ddcd.png)

クリックすると、すべてのスクリーンショットが含まれるZIPファイルをダウンロードできます。ダウンロード後にファイルを展開して、画像を確認することが出来ます。


# さいごに

いかがでしたでしょうか。
この機能を活用することで、保守などに関わるみなさまのご負担が少しでも軽減できれば幸いです。
レプリケーションがマスターサーバーへ与える負荷

【疑問】
レプリケーションがマスターサーバーへ与える負荷はあるのか、また、スレーブが増えた場合でも変わらないのか。

【結論】
ストリーミングレプリケーションが、マスターサーバへ与える負荷は、WALファイルの転送処理がほとんど。
つまりWALファイルをストレージから読み出し、ネットワーク経由で送出することであり、CPU負荷はほとんどない。
また転送すべきWALのデータ量は、マスタ側の更新量に依存(レプリケーション初期化時の全コピーは除く)
マスタ側の I/O (ネットワーク) 負荷が一番影響する。
マスタ側の更新量が多くなったり、スレーブサーバが増えると、その分ネットワークへの負荷が増える。
Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https.

## エラー内容
DockerComposeで、3000ポートにフロントサーバー（Next.js）、8080ポートにAPIサーバー（golang）を立ち上げて、フロントからAPIを取得しにいくと、下記のエラーが発生しました。

```
Access to XMLHttpRequest at 'back:8080' from origin 'http://localhost:3000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https.
```

## 原因
CORSの規定により、ブラウザの仕様で、頭文字のhttpやhttpsがついてない異なるオリジンへのリクエストは制限されているみたいです。
https://stackoverflow.com/questions/10752055/cross-origin-requests-are-only-supported-for-http-error-when-loading-a-local

僕は、フロント側でhttp://をつけて無かったので、ダメだったみたいです。

```js:
axios.get("back:8080")
// とか
axios.get("localhost:8080")
```

## 解決策
ちゃんと、http://をつけてあげるといいです。

```js:
axios.get("http://127.0.0.1:8080")
// とか
axios.get("http://localhost:8080")
```
dockerでpython(34)

docker で pythonするとき、Anacondaを利用してきた。

最近は、Anacondaに入っているライブラリを使わない用事もあり、
https://hub.docker.com/_/python

を利用している。githubはこちららしい。
https://github.com/docker-library/python

早速起動してみる。

```macOS:bash
$ docker run -v /tmp/python:/tmp/python -it python /bin/bash
Unable to find image 'python:latest' locally
latest: Pulling from library/python
5e0b432e8ba9: Pull complete 
a84cfd68b5ce: Pull complete 
e8b8f2315954: Pull complete 
0598fa43a7e7: Pull complete 
83098237b6d3: Pull complete 
b92c73d4de9a: Pull complete 
c387e200448c: Pull complete 
2a8d9e948b85: Pull complete 
b32ac80c02a3: Pull complete 
Digest: sha256:e78ea3ee9f77c569c68c98de106f06b20bb6f137303abba4362c2b8a92184969
Status: Downloaded newer image for python:latest
```

理由の一つは上記のようにモジュールに分かれていて、更新のある部分だけでよい点かもしれない。
各モジュールの構成は未調査。
https://github.com/docker-library/python/blob/master/3.10/alpine3.15/Dockerfile

Dockerfileを見ると、aptで何を入れているかがわかる。
python では、pipを入れていることがわかる。
# Windowsでpython
自分の記事で、viewsが一番多いのは、Windowsにpythonを導入する記事。

M.S.WindowsにPython3 (Anaconda3) を導入する（7つの罠）
https://qiita.com/kaizen_nagoya/items/7bfd7ecdc4e8edcbd679

# 今日のエラー
ディレクトリ（フォルダ）指定の /  を抜かした。

```macOS:bash
$ docker run -v tmp/python:tmp/python -it python /bin/bash

docker: Error response from daemon: invalid volume specification: 'tmp/python:tmp/python': invalid mount config for type "volume": invalid mount path: 'tmp/python' mount path must be absolute.
See 'docker run --help'.

```

# 参考資料
docker(18) なぜdockerでpython/Rを使って機械学習するか 書籍・ソース一覧作成中 (目標100)
https://qiita.com/kaizen_nagoya/items/ddd12477544bf5ba85e2

言語処理100本ノックをdockerで。python覚えるのに最適。docker(19) python(1)
https://qiita.com/kaizen_nagoya/items/7e7eb7c543e0c18438c4

あなたもdocker, 私もdocker。docker(130)
https://qiita.com/kaizen_nagoya/items/8f2746f10f30b575d0a8

資料集 [あなたもdocker私もdocker一覧] docker(0)
https://qiita.com/kaizen_nagoya/items/45699eefd62677f69c1d
### 最後までおよみいただきありがとうございました。
いいね　💚、フォローをお願いします。
####  Thank you very much for reading to the last sentence.
Please press the like icon 💚　and follow me for your happy life.
ディープラーニングの際に個人的によく使うpythonコードまとめ

この記事は[**Python Advent Calendar 2021**](https://qiita.com/advent-calendar/2021/python) カレンダー1の19日目の記事です。よろしくお願いします。

TensorflowやPytorchなどのディープラーニングフレームワークを使用するときに目的に合わせてよく使うコード例をまとめてみようという記事になります。参考になれば幸いです。
# 目次
1.画像のパスのリストを作成
2.ハイパーパラメータをまとめたconfigファイルを作成
3.pythonファイルで引数を取る

# 環境
M1 Mac
python: 3.8.12

# 1.画像のパスのリストを作成したい
あるディレクトリ内の画像のパスをリスト化することで、for文で一気にファイル名を変更したり、削除や移動、画像への色々な処理などを行えます。

```python
import glob

# trainディレクトリ内の画像パスをリスト化
# 「*」にすることでtrainディレクトリ以下の全てのファイルを指定できる
img_path_list = glob.glob('./train/*')
```
画像のパス名を0001.png, 0002.pngといったように順番関係のあるものにしている場合は上記コードだけだと順番がバラバラになってしまうので注意です。

```python
# リスト.sort()でファイル名を見て昇順ソート
img_path_list.sort()
```

例えば以下のように書くことでディレクトリ内の画像をnddarray化してリサイズすることが可能です。

```python
import cv2

for path in img_path_list:
    img = cv2.imread(path)
    img = cv2.resize(128, 128)
```

「画像のパスをリスト化する」作業はディープラーニングをやってる中でよく使います。


# 2.モデルの設定（学習率、画像サイズなど）をまとめたい
ディープラーニングや機械学習ではJupyter notebook・Jupyter labなどのnotebook形式で実行される方が多いと思いますが、各セルでoptimizerの設定や、モデルの定義、データの読み込みなどを書いて実行していきがちですよね。

特にコンペだと何回も何回もハイパラを変更して実行することになるので、変更箇所はすぐにわかるようにしたい、すぐにアクセスできるようにしたい。

と言うことで辞書形式で設定値をまとめておくと楽です。

`easydict`というライブラリを使います。
下記コマンドでインストール。

```shell
pip install easydict # pip

conda install -c conda-forge easydict # conda
```

以下`cfg.py`というpythonファイルに各種設定をまとめる例になります。

```python:cfg.py
from easydict import EasyDict as edict

# 空の辞書を作成
Cfg = edict()

# Cfg.キー名 = 値 の形式で設定値を書いていく
Cfg.batch_size = 32
Cfg.optimizer = 'adam'
Cfg.loss = 'categorical_crossentropy'
Cfg.learning_rate = 0.001
Cfg.height = 256
Cfg.width = 256
Cfg.checkpoint_dir = './checkpoints/'
Cfg.Cutmix = True
```

こんな感じで必要な設定項目をまとめたら

```python
from cfg import Cfg

config = Cfg

# Cfg.キー名で各値にアクセスできる
Cfg.batch_size
# -> 32
```

こうしておくと変更する場所が一箇所で済むので非常に楽です。
特に論文モデルの公式実装ではこうしたconfigファイルが書かれていることが多いです。

# 3.pythonファイルで引数を取りたい
普段、機械学習やディープラーニングを実行する環境がnotebook形式だと、いざ実務などで実行スクリプトを書くとなったときに困ってしまうと思います（自分がそうでした）。

`argparse`ライブラリを使って引数指定をしてみましょう

以下推論時の画像サイズ及び画像パスを引数に指定した推論実行ファイル`infer.py`の例です。

```python:infer.py
import argparse

# 他に必要なものインポート
# ---------------------------
# 引数の設定
parcer = argparse.ArgumentParser(description='推論実行ファイル')
parser.add_argument('img_path', type=str, help='画像のパス') # 「--」無しだと必須の引数
parser.add_argument('--img_height', type=int, help='画像の高さ', default=256) # 「--」付きだとオプション引数
parser.add_argument('--img_width', type=int, help='画像の幅', default=256)

# 引数の値をまとめて取得
args = parser.parse_args()

# 引数の値を取り出して変数に代入
img_path = args.img_path
height = args.img_height
width = args.img_width

# 推論実行関数
def infer(img_path, height, width):
   # 省略

# ---------------------

if __name__ == '__main__':
    infer(img_path, height, width)
```

こうしたスクリプトを書いてコンソール上で以下のように入力すると

```shell
python infer.py './train/img_001.png' 128 128
```

`'./train/img_001.png'`という画像を縦128, 横128のサイズで推論を実行することができます。

# まとめ
実務に携わるようになって使うようになったもの、勉強したものをまとめました。
他にもマルチスレッド処理など、まだまだpythonの知識が足りないので勉強していきます。
Datastreamを使ってCloud SQLのCDCデータをBigQueryに格納する

以下の記事の設定が完了していることを前提にしているので、事前にお読みください。
以下の記事ではCDCデータをGCSに格納しました。
しかし、このままですと扱いづらいので、GCSに格納されたデータをBigQueryにもロードしてみます。

https://qiita.com/shiozaki/items/ea0b94198a02f43d1a6d

GCSに格納されたCDCをBigQueryにロードするためにはDataflowを使います。
そのためのテンプレートが用意されたいるので、これを使います。

https://cloud.google.com/dataflow/docs/guides/templates/provided-streaming#datastream-to-bigquery

# GCSのPubSub通知を有効化する
GCSバケットにファイルが配置されたことをDataflowに通知するための設定を行います。

```sh
# GCSのPubSub通知のためのPubSub Topicを作成
gsutil notification create -t test-datastream -f json gs://test-datastream-20211219

# 上で作成したTopicからDataflowが読み出しを行うためのSubscriptionを作成
gcloud pubsub subscriptions create test-datastream --topic=test-datastream
```

# BigQueryにデータセットを作成する
ロードされたデータを格納するためのデータセットをBigQueryに作成します。

```sh
# CDCデータそのものを格納するためのデータセット
bq mk --dataset test_datastream_log

# 定期的にCDCデータを反映した結果を格納するためのデータセット
bq mk --dataset test_datastream_final
```

# Dataflow JOBの作成
最後にDataflow JOBを作成します。

```sh
gcloud beta dataflow flex-template run test-datastream \
  --template-file-gcs-location gs://dataflow-templates-us-central1/latest/flex/Cloud_Datastream_to_BigQuery \
  --region us-central1 \
  --parameters inputFilePattern=gs://test-datastream-20211219,\
gcsPubSubSubscription=projects/<プロジェクトID>/subscriptions/test-datastream,\
inputFileFormat=json,\
outputStagingDatasetTemplate=test_datastream_log,\
outputDatasetTemplate=test_datastream_final,\
deadLetterQueueDirectory=gs://test-datastream-20211219/dlq
```

この後しばらく待つとDataflow JOBが動きだし、test_datastream_logとtest_datastream_finalにテーブルが作成されます。

# BigQueryのテーブルにクエリを実行する
しばらく待つと、以下の2つのテーブルが生成されることが分かります。

上のテーブルにはCloud SQLから読みだしたCDCデータそのものが格納されています。
そのため、過去の特定の時点での情報を参照することに活用できます。
例えば、商品テーブルで考えれば過去時点での価格や在庫などが時系列データとして活用できます。

下のテーブルはそのCDCデータを定期的にBigQueryに対して反映し、Cloud SQLと同等になるように再構成されたテーブルです。
異種間データベースレプリケーションのようなものだと考えれば分かりやすいです。
Dataflowが `mergeFrequencyMinutes` 間隔でBigQueryのMERGE文を実行して再構成を行っています。
この値はデフォルトでは5分ですが、変更することも可能です。
費用とデータ鮮度のトレードオフになるので、実際に運用する際には適切な値にチューニングする必要がありそうです。

```
test_datastream_log.users_log
test_datastream_final.users
```
koa.jsの基礎

## はじめに
- Node.jsで使用されるサーバー側の軽量フレームワーク。
- サーバーを素早く提供してくれる。
- 最小構成かつ手軽にアプリケーションを作成可能。
- 初学者にとっては、新しいライブラリを一から作ることになるため、構築力が身に付く。

## 環境
- Mac
- Node v17.2.0

## 開発
```
$ mkdir sample_koa; cd $_
$ npm init -y
$ npm i koa
$ npm i -D nodemon
// nodemon:Node.jsではプロセスを再起動する必要があるが、
nodemonを使用してプロセスを自動的に再起動してくれる。
```

- index.jsを作成・記述する。
```
＄　touch index.js
```

- index.js

```
const Koa = require('koa')
const app = new Koa()

app.listen(3000,() => {
    console.log("server start")
})
```

- package.json
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
の部分を
```
"scripts": {
    "dev": "nodemon index.js"
  },
```
に変更する。

## ミドルウェア
-  OSとアプリケーション間の複雑な処理をするソフトウェアのこと。
-  koaはルーティング機能がついていないため、実装する。

```
$ npm i koa-router
```

- index.js

```
const Koa = require('koa')
const app = new Koa()

app.use(async ctx => {
  // ミドルウェア
  ctx.body = "Hello World"
})

app.listen(3000,() => {
    console.log("server start")
})
```

- 確認
```
$ npm run dev
```
- ブラウザでlocalhost:3000と入力、"Hello World"と表示されたらOK。
[競プロ] 単調スタックを使ったLIS (Longest Increase Subsequence)解法

[こちらの記事](https://qiita.com/awesam/items/458fb6330be4ab75c815)ではスタック構造体を使った単調スタックの説明を行った。
これとは別に配列を使った単調スタックの実装があるので解説を行う。
配列を使うメリットとしてはソート済みの配列になるので配列に対して二分探索が可能となる。
これを使ってLIS問題を実装する。

## 考え方

LISというのはある配列Aからいくつかの要素を排除することで得られる部分配列の中で、単調増加になっているものの最大配列サイズを見つける問題。

例えば下記配列Aがあるとする

```
A[] = {1 2 5 4 10 3}
```

考え方としては、配列Sを作成し下記のように定義する。

```
S[i] = 配列Aから長さiの部分列を作成したときの最後の要素
```

S[i]は小さければ小さいほど、後に選択できる要素の可能性が大きくなるので貪欲に小さい数を選ぶことで配列Sを作成できる。
配列Aから順番に要素を取り出し、配列Sのどこに当てはまるかを二分探索を使って探していく。

```
S[] = {1 2 3 10}
```

注意が必要なのは作成した配列Sは実際のLIS配列ではないということ。
あくまで長さiの部分配列の最終要素の配列である。
上記の例では配列Aで3は10の前にあるのでこの部分配列は作成できない。

## 実装

```c++
int lengthOfLIS(vector<int>& nums) {
    vector<int> stack;
    for (int i: nums) {
        if (stack.empty() || i > stack.back()) stack.push_back(i);
        else *lower_bound(stack.begin(), stack.end(), i) = i;
    }
        
    return stack.size();
}
```

## 関連問題

[300. Longest Increasing Subsequence](https://leetcode.com/problems/longest-increasing-subsequence/)

[2111. Minimum Operations to Make the Array K-Increasing](https://leetcode.com/problems/minimum-operations-to-make-the-array-k-increasing/)
AWS Certified Data Analytics - Specialty 合格しました

先日、AWS認定データアナリティクス専門知識の試験を受験し、合格しました！
その記録を残しておきます。

AWSの認定資格としては今年7月以来です。

- 2021年7月 [AWS Certified Developer - Associate 合格しました - Qiita](https://qiita.com/suzuki-navi/items/dfb343130da83d560ce4)

私の所属会社ではAWSなどのクラウドベンダーの資格取得が推奨されています。受験料はもちろん、合格したときに報奨金も出してくれるので、業務でAWSを触るようになってからAWSの資格を少しずつ取るようにしています。AWSの資格としては今回が6個目です。

今回のData Analytics Specialtyは昨年登場した試験で、同じタイミングでBig Data Specialtyが廃止になっているので、たぶん内容は似ているんじゃないかと思ってます。Big Data Specialtyは2年前に取りました。

- 2019年10月 [AWS Certified Big Data - Specialty 合格しました - Qiita](https://qiita.com/suzuki-navi/items/8b2fe5a35a4439013461)

# 勉強方法

7月に受験したときは、Udemyの模擬試験を買って勉強しましたが、今回はなにも買いませんでした。2年前のBig Data Specialtyと似たもんだろうと思って軽く考えてたのもあります。なので、まずは2年前の自分のメモを見返しました。

Black Beltの資料も改めて見直しました。Kinesis、EMR、Glue、Athena、Redshift、QuickSightあたりです。

それから公式の無料の解説付きの模擬試験が最近リリースされたので、それは解きました。調べながら解いたので正答率は不明ですが、調べずにわかった問題は半分も及ばなかったと思います。

# 試験当日

65問180分。寝不足で集中力がまったくなくて、65問一巡するのに150分ぐらいかけてしまいました。途中ぼーっとしてた時間もあります。ぜんぜんわからない問題が多くて、ダメかもなって思ってました。見直しフラグはほとんどの問題に付けていたので、フラグの意味がなかったです。

残り30分で時間のある限りで1問目から見返しました。見返しの時間では、頭がすっきりしてきたのか、スラスラと解けました。回答が間違ってるのに気が付いて直した問題もあります。40問ぐらい見返したところでタイムアップでした。

相変わらず日本語問題文の誤訳や、そうでなくても読み取りづらい文章が多いです。そういうところだけ英語を見て問題の意味理解を補完します。

# 結果

スコア812でした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/490207/d5ff572e-ec68-ce21-a7b4-acf4933b5214.png)

# 所感

Kinesis、QuickSightはいっぱい登場した印象です。どちらも触ったことないので、勉強しておいてよかったです。

GlueとEMRもよく出てきました。使い分けはわかっておいたほうがよさそうです。AthenaとRedshiftも同じくです。DMSやDataSyncというのもありますね。

Elasticsearch Serviceはリアルタイム性のあるダッシュボードという位置づけです。試験ではサービス名がまだ古いままでした。

S3のコスト削減のために、ライフサイクルルールでストレージクラスを設定するのは必須ですね。データレイクのファイルフォーマットとして、Parquet、Avro、Snappyといったキーワードの理解も必要です。

あとはCloudWatch LogsのサブスクリプションでKinesisに流すとか、Kinesisの中でLambdaで処理するとか、DynamoDBストリームをLambdaで受けるとか。
Dataframeで条件満足する行のみに対し合計値を算出する

A列が1, B列が2 である行のC列の合計値

```python:test.py
import pandas as pd

df1 = pd.DataFrame([[1, 1, 12],
                    [1, 2, 11],
                    [1, 1, 18],
                    [2, 2, 19],
                    [2, 1, 10],
                    [2, 2, 14],
                    [1, 1, 15],
                    [1, 2, 17],
                    [1, 1, 19]],
                   columns=['A', 'B', 'C'])

sum_of_c = df1.loc[(df1['A'] == 1) & (df1['B'] == 2), 'C'].sum()

print('sum={}'.format(sum_of_c))
```
出力結果

```
sum=28
```
プリレンダリングしたcanvasの解像度も上げたい

canvasでの描画を最適化する方法の一つとして、「プリレンダリング」がある。
プリレンダリングとは、ページに表示しないcanvas要素（以降"オフスクリーンcanvas"と呼ぶ）を作って事前に色々描画しておき、オフスクリーンcanvas自体をメインのcanvasに描画するという手法である。
プリレンダリングについては[ここ](https://developer.mozilla.org/ja/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas#pre-render_similar_primitives_or_repeating_objects_on_an_offscreen_canvas)に詳しく書いてある。

また、canvasをCSSで拡大していたり高解像度のデバイスを使っていたりすると、canvasがぼやけてしまう。
そんなときは`window.devicePixelRatio`を使ってcanvasの描画サイズを拡大してあげるとイイカンジになる。
`window.devicePixelRatio`については[ここ](https://developer.mozilla.org/ja/docs/Web/API/Window/devicePixelRatio)に詳しく書いてある。

さて、オフスクリーンcanvasを使うと、`window.devicePixelRatio`で解像度を調整していても、オフスクリーンcanvasを描画した部分がぼやけてしまうことがある。
そんなときはオフスクリーンcanvasの描画サイズも拡大してあげればよい。

```script.js
const appSize = {width: 200, height: 300};//200×300の大きさのアプリを作りたい。

/* <canvas id="main-canvas"></canvas>がすでにページにあるものとする。 */

const mainCanvas = document.getElementById('main-canvas');
const resolution = window.devicePixelRatio || 1;//デバイスの解像度

//CSSスタイルでのcanvasの大きさ(px)を取得
const styleWidth = mainCanvas.clientWidth;
const styleHeight = mainCanvas.clientHeight;

//メインcanvasの描画サイズを変更
mainCanvas.width = styleWidth * resolution;
const appCanvasRatio = mainCanvas.width/appSize.width;//アプリの大きさとcanvasの描画サイズの比

//コンテキストの拡大
const cxt = mainCanvas.getContext('2d');
cxt.scale(appCanvasRatio, appCanvasRatio);

//オフスクリーンcanvasの準備
const offscreenCanvas = document.createElement('canvas');

//オフスクリーンcanvasの描画サイズ変更　ただし適したサイズ（小さい方がいい）にしないと結果重くなってオフスクリーンの意味がなくなる
offscreenCanvas.width = mainCanvas.width;
offscreenCanvas.height = mainCanvas.height;

//オフスクリーンcanvasのコンテキストも拡大
const ocxt = offscreenCanvas.getContext('2d');
ocxt.scale(appCanvasRatio, appCanvasRatio);
/*
    ocxtでの描画処理
*/

//オフスクリーンcanvasをメインcanvasに描画
const offX = 30;//オフスクリーンを描画する座標位置
const offY = 30;

const ratioInverse = 1/appCanvasRatio;//逆数
const wid = offscreenCanvas.width;
const hei = offscreenCanvas.height;
cxt.drawImage(offscreenCanvas,
              0, 0, wid, hei,
              offX, offY, wid*ratioInverse, hei*ratioInverse);
```

cxtもocxtも拡大しているため、オフスクリーンcanvasを写し取るときのサイズは`appCanvasRatio`の逆数倍にしないといけない。
これでオフスクリーンcanvasの解像度もイイカンジにすることができる。

もしcanvasのスタイルをブラウザの大きさに対してレスポンシブにしているときは、`document.addEventListener('resize', リサイズ処理)`で上手いことやればよい。
flutter バグ解消(CocoaPodsのver際によるエラー)

#事象　
firebase_authのインストール後、fluutter run実行。その際に下記エラーが発生。デフォルトのpodのversionは9.0だが、インストール対象のライブラリが9.0以上でないとインストールできないことが原因のようだ。

```dart:実行結果とエラー内容
~/develop/study/photoapp/ios $ flutter run
    [!] Automatically assigning platform `iOS` with version `9.0` on target `Runner` because no platform was specified. Please specify a platform for this target in your Podfile. See
    `https://guides.cocoapods.org/syntax/podfile.html#platform`.

```

#修正方法
Podfileの二行目を修正。

```dart:Podfileの修正箇所
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'　
platform :ios, '１２.0'　←この行を追加する。

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
```