OmniAICreator/Qiita-1.07M huggingface dataset:
webサイトから入力したデータをFirebase CloudFirestoreに保存

#やりたかった事
webサイトの入力フォームから入力された「名前」と「所在地」を、Firebase CloudFirestoreに保存する。
今回はVue.jsで実装

#環境
・Firebase CloudFirestore
・Visual Studio Code
・Vue.js

#準備
##Firebase CloudFirestoreで格納データを作成
Firebase CloudFirestoreで格納するデータ型を作成する方法は以下を参考にして下さい。
必要な情報は
・SDN情報
・コレクション名
・格納データ名
[Firebase CloudFirestoreの使い方を初心者が解説してみた](https://qiita.com/misa_m/items/0afbd063ff13b49f2729)

##Visual Studio Code
新しいjsファイルを作成
npm初期化

```
npm i
```

#作り方
##作成したjsファイルに以下を入力
今回、名前、所在地を格納するデータベースを作成しました。

```
<!DOCTYPE html>
<html lang="ja">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>WEBサイトから取得したデータをFirebase CloudFirestoreに保存</title>
</head>

<body>
  <div id="app">
    <ul v-for="data in allData" :key="data.id" class="menu-list">
      <li>
        {{data.name}} / {{data.age}}
      </li>
    </ul>
    
    <p>
      名前：<input v-model="name" placeholder="名前">
      所在地：<input v-model="age" placeholder="年齢">
      <button v-on:click='post'>送信</button>
    </p>
  </div>

  <script src="https://unpkg.com/vue"></script>
  <script src="https://www.gstatic.com/firebasejs/7.2.3/firebase-app.js"></script>
  <script src="https://www.gstatic.com/firebasejs/7.2.3/firebase-firestore.js"></script>
  <script>
    // Your web app's Firebase configuration
    const firebaseConfig = {
      apiKey: "",
      authDomain: "",
      databaseURL: "",
      projectId: "",
      storageBucket: "",
      messagingSenderId: "",
      appId: ""
    };
    // Initialize Firebase
    firebase.initializeApp(firebaseConfig);
    const db = firebase.firestore();

    const app = new Vue({
      el: '#app',
      data: {
        allData: [],
        name: '',
        age: 0
      },
      mounted: async function () {
        db.collection('memos').onSnapshot(snapshot => {
          // データベースに変更があった場合実行される
          console.log('on snapshot!');
          // 更新されたデータだけでなく、全て取得される
          this.allData = [];
          snapshot.forEach(doc => {
            // console.log(doc);
            this.allData.push(doc.data());
          });
        });
      },
      methods: {
        //データ追加
        post: async function () {
          await db.collection("user").add({
            name: this.name,
            age: this.age
          });
        }
      }
    })
  </script>

</body>

</html>
```

自分の環境に変更しないといけない箇所
Firebase CloudFirestoreで発行されたSDK情報に書き換えます。

```
 // Your web app's Firebase configuration
    const firebaseConfig = {
      apiKey: "",
      authDomain: "",
      databaseURL: "",
      projectId: "",
      storageBucket: "",
      messagingSenderId: "",
      appId: ""
    };
```

「await db.collection("user").add({」のuserの箇所は、Firebase CloudFirestoreで作成したコレクション名に変えます。

```
      methods: {
        //データ追加
        post: async function () {
          await db.collection("user").add({
            name: this.name,
            age: this.age
          });
        }
```

#完成
これで、webサイトから入力した名前、所在地の値がFirebase CloudFirestoreへ保存されます。
お問い合わせフォームの入力内容等、保存しておくことが可能になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/820683/7d35bd20-e7b3-c2d1-00a5-5bfa04766764.png)
「セキュリティ・キャンプ・ミニ　in 沖縄」でやったこと！

初めてブートキャンプに参加しましたので、~~学校の先生にお願いされたので~~ここに5つ残します！

* セキュリティ・キャンプとは？
* きっかけ
* なぜやろうと思った？
* 講義の詳細・感想
* 最後に


## セキュリティ・キャンプとは？
公式様ページ：[セキュリティ・キャンプについて](https://www.ipa.go.jp/jinzai/camp/index.html)
セキュリティ・キャンプとは２０１３年から**IPA(情報処理推進機構)**が行っている**学生に対して**セキュリティに関する高度な技術教育を実施し、次世代を担う情報セキュリティ人材を発掘・育成するプロジェクトです。

やはり専門の講師などお呼びするのでもちろん書類選考があります！応募書類にはいくつか質問が用意されており、その質問の回答内容で決めるそうです。

質問には**会社でセキュリティ面で〇〇があった時あなたの対処法は？**など質問がありました。

しかも**学生に対して**なので、実際に講義を受けられるのは**[現在学校に通っている人]****[２５歳以下]**のみに限られます。学校を卒業してしまうと応募すらできなくなってしまいます...

基本は３泊４日でセキュリティの講義など受けるものですが、今年はコロナのせいもあり、**ミニ**になり１日だけの講義となりました。
##きっかけ
きっかけとしては、やはり学校の先生からのおすすめが一番大きかったと思います。自身もこんなプロジェクトがあることすら知らなかったです。

##なぜやろうと思った？
いろいろ理由がありますが個人的なことを言うと
####おもしろそうだから　
です。
こんな単純な理由で応募しても構いません。もちろん書類に「おもしろそうだから」とは書きません！w
ただ「おもしろそう〜」って思ったらやったほうがいいです。なぜなら**やる前から面白いと予想できている**からです。皆さんの趣味でも同じことが言えると思います。そんなのおもしろくないはずがない！(この意見には個人差があります)

##講義の詳細・感想
講義項目として今回は
**[セキュリティの考え方や倫理]**
**[ログ解析]**
**[ペネトレーションテスト入門]**
この３つを１０時から１８時まで昼休憩などはさみながら行いました。

まず**[セキュリティの考え方や倫理]**では参加者でグループを決められ講師から出されるセキュリティ関連のお題に対して話し合いをする講義でした。この講義に**応募した理由は皆さん共通なわけです。**初対面にもかかわらず楽しく話し合いができました！(ちなみに私は明治大学の３年生の方と友達になり連絡先なども交換しました。)

次に**[ログ解析]**です。こちらは実際に会社で起きたことを想定して１人のセキュリティ班としてログ解析を行います。個人的にはこの講義が一番面白かったです。まず講師側からログのあるZIPファイルを渡されます。その後、講師の方から「攻撃者を探せ」などの問題が出題されます。会社を想定していますので、攻撃を受けた人からの証言など聞いて答えを導き出します。(もう完全にひらめきクイズ番組ナゾ〇レやっている気分でした)

最後に**[ペネトレーションテスト入門]**の講義を行いました。ペネトレーションテストとは、自身で作ったセキュリティに対して本当に大丈夫なのかをテストするために**自分で自分のセキュリティに攻撃を仕掛けてテストを行うこと**です。今回こちらの講義ではブラウザ版で仮想マシンというPCの中で２台目のPCを動かし、その仮想マシンを乗っ取ることを行いました。乗っ取る時にパスワードを解析するのですが、その時に安易なパスワードを設定すると自分でも簡単に見つけることができ、改めてパスワードの複雑化が大事だと思いました。(最近ではグーグルさんの自動パスワード生成使ってます)

##最後に
本当に講義内容は全て役に立つもので、学校の授業で習ったことを復習することもできたし、新しい技術も学べることのできる最高のプロジェクトでした！個人的には来年も行けたら行きたいなって思う程です。

特にITカレッジ沖縄の・・・
###サイバーセキュリティ科の人！！
**本当にオススメにします！行って絶対に損しません！**

以上で報告を終わります。このページをみて行きたいと思ってくれたら嬉しいです。

改めて公式ページを貼っておきます。応募の方法など公式ページをご覧ください。
公式様ページ：[セキュリティ・キャンプについて](https://www.ipa.go.jp/jinzai/camp/index.html)
個人開発のWebサービスを開始して2ヶ月後の所感

この記事は[個人アプリ/サービス開発の進め方と運用、得た学び - 02【PR】 Lenovo Advent Calendar 2020](https://qiita.com/advent-calendar/2020/lenovo_app_02)の20日目の記事です。

# Skillfulsについて
2ヶ月前の10/18日に [Skillfuls](https://skillfuls.dev) というプログラマのスキル記録サービスを個人開発でリリースしました。
リリースしたときに、技術構成などは以下のQiita記事に書いたところ沢山のLGTMをもらうことができ、とても励みになりました。

[プログラマのスキルを記録できるサービスを作ってみた【個人開発】]
(https://qiita.com/HYuta999/items/28f1526447637ad87941)

URL: https://skillfuls.dev/

最近はあまりSkillfulsの開発の時間をとれず、新機能などは実装できなかったので運用面とアクセス解析をまとめてみます…

# 数字で見るSkillfuls
2ヶ月の間にデータベースに記録されたレコードを集計して表にしました。
単純計算で1ユーザあたり6つのスキルを登録してくれている計算になりますが、実際には多い人と少ない人が極端なような気がします。
チームでスキルマップを作れるという機能を頑張って実装したのに、あまり使ってもらえず少しショックでした😓

|  項目  |  結果  |
| ---- | ---- |
|  ユーザ数  |  252  |
|  スキルの種類  | 115   |
|全ユーザの登録スキル|1595|
|チーム数|10|

## 👑 登録数ランキング
ユーザが登録したスキルのトップ5は以下のようになりました。
GitHubなどが発表している人気言語ランキングとそんなに変わらないような感じですね。

|  順位  |  スキル  |登録数|
| ---- | ---- |----|
|  1  | JavaScript|102|
|  2  |  Python  |89|
|3|HTML|69|
|4|Java|68|
|5|PHP|67|


## 📈 成長させたいスキルランキング
また、全ユーザの登録スキルのうち成長させたいと思っているスキルの数は352で、上位のスキルは以下のようになりました。
１,2位は登録ランキングと変わらずで、3位にTypeScriptがランクインしていますね。
ここ数年で一気に注目されていますし、成長させたいと思っているエンジニアも多いのでしょう。また、Node.jsやReact,Vueが17人で同順の5位になりました。


|  順位  |  スキル  |登録数|
| ---- | ---- |----|
|  1  |   JavaScript |34|
|  2  |   Python |29|
|3|TypeScript|22|
|4|docker|19|
|5|Node.js|17|
|5|React|17|
|5|Vue.js|17|

# 運用について
インフラの構成は前の記事に書いた通りで、HerokuでNuxtのProxyとSSRを行っていて、nest.jsで開発したAPIサーバはGoogle Cloudの2コア/2ギガのVMで動いています。
料金は月額700円くらいです。

メモリは割と余裕があるはずなのですが、たまにpm2がフリーズしてしまうことがあるのでCloud Monitoringで5分毎にリクエストを投げて死活監視をしています。リクエストが失敗するとGoogleCloudのスマホアプリにインシデントとして通知が来るので、現在は手動で対処しています。時間があるときに原因解明をしたいですね…
余談ですが、APIのリクエストを複数リージョンから送信できるのですが、サーバ費用の安いUSリージョンに置いているため、アメリカに比べてアジアからだと6倍位レイテンシが大きいことがわかります。やはり、東京リージョンを使うのが一番いいですね…

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110137/4f9b5c12-3a33-bb05-424c-3ee7e5833ba6.png)


# 個人開発のモチベーション

ユーザが登録して継続的に使ってくれるようなサービスを開発したのは、Skillfulsが自分にとっては初めてでしたが、252名の方に使ってもらえたのでとても嬉しく思いました！
ただ、チームの機能を想定していたほど使ってもらえなかったりと、思い通りにいかないということも実感しました。また、継続的に利用してもらうのはスマホアプリに比べて難しそうです。
ドメインはとりあえず1年で契約しているので、最低でも1年間は運用していこうと思います！

では、21日の記事は「Qiita殿堂入りアプリを作成した話（二番煎じ）」です！

## おまけ

このAdvent Calendarは[個人アプリ/サービス開発の進め方と運用、得た学び - 02【PR】 Lenovo Advent Calendar 2020](https://qiita.com/advent-calendar/2020/lenovo_app_02)ということで、Lenovoさんがスポンサーなので少しThinkPadの話をします。

僕はThinkPadファンで、現在もRyzen7,16GBのThinkPad X395というノートPCを使っています。
以前はX1 Carbonという上位機種を使っていましたが、Ryzenを使ってみたかったので昨年このThinkPadに買い替えました。
ThinkPadはキーボードが打ちやすかったりハードウェアがしっかりしているなど、好きなところは色々ありますが、自分にとって一番嬉しいのがLinuxとの互換が割としっかりしているところです。
個人的に開発OSではUbuntuが一番使いやすいと思っており、このSkillfulsもUbuntu上で全て開発しました。
公式サイトで情報を公開されており、UbuntuやREHLが使えるそうです。WIFIや指紋認証なども、Ubuntuで特に問題なく使えているのでとても助かります！
（発売直後はドライバが無い場合もありますが…）
https://support.lenovo.com/jp/ja/solutions/pd031426-linux-for-personal-systems


以上、あまり知られていないかもしれないThinkPadの魅力でした。
自作言語(コンパイラ作成)の進め方

[42tokyo Advent Calendar 2020](https://adventar.org/calendars/5125)の20日目の記事です。
<br>
私は一ヶ月ほど前まで自作言語の開発をしていました。[作ったやつ](https://github.com/kechigon/klang)
自作言語に関する知識がゼロの状態から開発を始めたため、どのように進めていけばいいのかわからず苦労しました。そこで、自作言語に興味があっても進め方がわからない人に向けてオススメの進め方をまとめてみました。ぜひ参考にしてみてください！！
<br>
※この進め方はc++の知識を前提としています
#まずコンパイラの理論を学ぶ
ここでソースコードというテキストファイルが、どのように目的コードへ翻訳されていくのか一通りイメージできるようになっておきましょう。基本的に「構文解析→AST生成→目的コードへコンパイル」という流れになっています。実装もこの流れで行うといいでしょう。<br>
ASTとは簡単に言ってしまうと「コードから必要な意味だけ抽出した木構造」です。こいつをもとに最終的なコンパイルを行います。<br>
各処理のアルゴリズムや中間表現についても学んでおきましょう。この後詳しく説明しますが、構文解析にbisonというツールを使い、目的コードをllvmIRにするのがお勧めで、bisonはLALR(1)のアルゴリズムを理解しておく必要があり、llvmIRは三番地コードなどの中間表現を知っておく必要があります。
#構文解析器(パーサー)を作る
コンパイラの理論を学んだら実装に移ります。ここで作るものは、文字列を定義した構文にパターンマッチさせるパーサーと呼ばれるものです。これはflexやbisonなどのツールを使えば、フルスクラッチより簡単に作れるのでオススメです。私はflex、bisonの使い方を以下のサイトで学びました<br>
 http://aquamentus.com/flex_bison.html
 http://www.asahi-net.or.jp/~wg5k-ickw/html/online/flex2.5.4/flex_toc.html
 https://web.sfc.wide.ad.jp/~sagawa/gnujdoc/bison-1.28/
<br>
まずflexでトークン(構文解析での最小単位)に分けるプログラムを作成します。これを字句解析器といいます。次に、字句解析器によって分けられたトークンをbisonで作成したパーサーでパターンマッチさせます。このパターンマッチングは非常にバグりやすいので、先ほど言ったLALR(1)のアルゴリズムをしっかりと理解しておく必要があります。また、ここで構文をたくさん定義して言語仕様を大きくしてしまうと、この後の開発が大変なので自作言語初心者は最低限の仕様にしておきましょう。
#AST生成のアルゴリズムを書く
定義した文法にマッチしたら木構造のノードを作成し、それをつなげて最終的にASTが出来上がるようなアルゴリズムを書きます。具体的な実装方法はこのサイトが参考になります。<br>
https://www.kancloud.cn/digest/xf-llvm/162262
<br>
このサイトも構文解析にflex、bisonを使っているのでわかりやすいと思います。解説と公開されているコードを読み込み実装方法を学びましょう。ASTは目的コードへのコンパイルがしやすくなるために作るものなので、コンパイル方法がこの時点で決まっていると作りやすいでしょう。
#目的コードへコンパイルする処理を書く
最後にASTをトラバースし、目的コードへコンパイルする処理を書きます。その方法も先ほどのサイトを参考にするといいです。ここで何を目的コードにするかですが、llvmIRをオススメします。llvmIRを作成すると、llvmのツールによってマルチプラットフォームでの実行、最適化などを行ってくれます。llvmIRへAPIを使用してコンパイルしていきます。llvmIRの仕様やAPIの使い方は以下のサイトが参考になります。<br>
https://qiita.com/sakasin/items/097fa676ccfd117acaa2#%E7%B5%84%E3%81%BF%E8%BE%BC%E3%81%BF%E9%96%A2%E6%95%B0
https://itchyny.hatenablog.com/entry/2017/03/06/100000
<br>
llvmは仕様が膨大で目的に合うAPIを見つけるのも一苦労ですが（正直この作業が開発全体で一番きつかった）、根気でドキュメントを読み漁りましょう。<br>
すべてのコンパイル処理を書き終わったら「構文解析→AST生成→目的コードへコンパイル」の流れを実装し終わり、自作言語の完成です！！
#最後に
自作言語開発全体を通してとにかく情報収集が大変だったので、参考になったサイトのリンクを貼りつつ、抑えるべきポイントをまとめました。最後まで読んでいただきありがとうございました。
<br>
明日は、私と同じ高校で低レイヤー好き同士のyaitoが担当します。ぜひご覧ください！！
ホスティングサーバの/binディレクトリをrm -rfしてしまったおじさんの昔話

# はじめに
この記事は[本番環境でやらかしちゃった人 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/yarakashi-production) 21日目の記事になります。

# 発端
今から10年くらい前の話ですが、当時サーバーエンジニアをやっていた"ぼく"は、その日、上司に依頼されて自社のサービスとして運営していたホスティングサーバ内の不要なデータの整理をしておりました。

で、どっかの不要なbinディレクトリを中身ごと削除しようとした際、とりあえず`rm -rf`と入力して、続けて`bin`と入力しようとし、間違えて`/bin`と入力してしまいます。

```bash
# rm -rf /bin
```

ここまでならよくある話ではありました。
そこで「あ、やべぇ、スラッシュ消さなきゃ」と思いながらバックスペースキーを押して`/`を削除しようとしました。というか間違いなくバックスペースキーは押したんです。ただそこで気が緩んでしまい、"ぼく"はコンソールの内容も確認せずにそのままエンターキーを押してしまったのです。
**カチャカチャカチャ、ッターン！**

```bash:"ぼく"の脳内で実行したコマンド
# rm -rf bin
```

```bash:実際に実行してしまったコマンド
# rm -rf /bin
```

**＼(^o^)／ｵﾜﾀ**

# 惨劇はなぜおこってしまったのか

この時、"ぼく"がTelnetでログインしていたのは古いSolarisサーバでした。
CentOSなどの割と後発のUNIX系のOSではデフォルトでもバックスペースキーを押下するとちゃんと一つ前に戻って文字を削除しますが、"ぼく"がログインしていたサーバではバックスペースキーを押下しても何も起こらない設定になっていました。

とはいえ、サーバによる設定の差は惨劇の一因でしかなく、主因はあくまでも確認不足。
ちゃんと目視で確認して、スラッシュが削除されていることを確認してからエンターキーを押せばこの惨劇を防ぐことは出来たはずでした。

~~一部を除いて~~ご理解のあるお客様ばかりだったので、また上司にリカバリー作業でのご助力をいただいたおかげで、金銭的な面でもデータ的な面でもそれほど大きな損害にはならなかったことは不幸中の幸いでした。
~~まぁミスした張本人なんで何も言う資格はないんですけど、普段から金払いが悪いアレなユーザーほどこっちのシステム障害のときに長々と文句を言ってくるのはホント何でなんでしょうね~~

# 二度と惨劇を起こさないためにどうしたのか

とても初歩的で簡単な事ですが、コマンドを叩く前、OKボタンを押す前、取引先にメールを送る前etc、一呼吸置いて内容を確認し間違いがないことを確かめてからアクションを起こすようにしました。

一見当たり前に思えることではあるんですが、その当たり前のことが当たり前に出来ない人が確認不足によるミスを起こすのもまた事実ですし、そもそも「間違いがないこと」を確認するには正しいやり方を理解していないといけない訳で、そう考えると言うのは簡単だけど常に実現するのは意外と難しいことなのかなぁという気もします。

ただこういう事書くとめっちゃ怒られそうなんですけど、取り返しがつく若いうちにやらかしておいた方が長い目で見ると後々の糧になるんじゃないかなぁ・・・・・・とはぶっちゃけちょっと思ったりしています。
basicnetwork.performrequest: unexpected response code 301

Volleyを使ってAPIのJSONデータをGETリクエストし、画面上にデータを表示する段階でぼくが詰まったエラーについて書きます。
（日本語の情報がなかったので）

##これってどんなエラー？
HTTPエラー301なので、リクエストされたリソースの URL が永遠に変更されたことを示しているとのこと。つまり、リクエストしたURLがもう存在しないということだそうです。

##原因
URLをシンプルに間違えていた。（APIではないURLをリクエストしていた。）

##解決策
正しいAPIのURLに直す。

参考記事
https://www.xspdf.com/resolution/50749783.html#:~:text=performRequest%3A%20Unexpected%20response%20code%20301%20%2C%20HTTP%20code%20301%20means%20%22,reach%20is%20no%20longer%20there.&text=%22moved%20permanently%22.-,This%20means%20the%20URL%20you're%20trying,reach%20is%20no%20longer%20there.
[AtCoder]AtCoder Beginner Contest 186 A~C問題


# A問題

```c++
#include <bits/stdc++.h>
using namespace std;

int main()
{
    int n,w;

    cin >> n >> w;
    cout << (n/w) << endl;

    return 0;
}

```

# B問題
すべてのブロックの合計から、最もブロックの少ないマスのブロック数をマスの数だけ引く。

```c++
#include <bits/stdc++.h>
using namespace std;

int main()
{
    int h,w,a;
    cin >> h >> w;
    
    int x = 100; // 0 <= A <= 100より
    int sum = 0;
    for(int i = 0; i < h*w; i++){
        cin >> a;
        x = min(x, a);
        sum += a;
    }

    cout << (sum - x * h * w) << endl;

    return 0;
}

```

# C問題
問題文通りに愚直に全探索する。

```c++
#include <bits/stdc++.h>
using namespace std;

// numをbase進数で表したときにxを含むか
bool contain_x(int num, int base, int x){
    while( num > 0 ){
        if((num % base) == x){
            return true;
        }
        num /= base;
    }
    return false;
}

int main()
{
    int n;
    cin >> n;

    int ans = 0;
    for(int i = 1; i <= n; i++){
        if( contain_x(i, 8, 7) == false && contain_x(i, 10, 7) == false ){
            ans++;
        }
    }

    cout << ans << endl;

    return 0;
}


```
JavaScript~書き方~

#はじめに
今回初めてこういった記事を書くので読みにくかもしれないですが
今後エンジニアとして活躍するには必要な経験かと思い始めてみました。
勉強中の身なので高度な情報であったり現場での開発については発信出来ませんが
自分の学習記録を残すことで同じプログラミング初学者の力に少しでもなれたらと思っています。

#JavaScriptの書き方
基本的なJavaScript記述の仕方は

```Javascript:Javascript
<script>JavaScriptでしたい処理</script>
```

になります。
これだとイメージが沸きにくいと思うのでHTMLで「はじめまして」と
画面上部に表示されるように命令文を書いてみます。

```HTML:html
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8">
 <title></title>
 <link rel="stylesheet" href="style.css"/>
 <script>
   alert('はじめまして');
 </script>
</head>
<body></body>
</html>
```
これでhtmlファイルを開いてもらうとポップアップで「はじめまして」と表示されます。
基本的にJavascriptはどこに記載してもいいのでbodyタグに記載しても大丈夫です。
scriptタグに記載している;は文の終了を表しています。
またcssのように別ファイルにJavaScriptを記載してそれを読み込むことも可能です。
例えばapp.jsというJavaScriptファイルを作りそれを読み込む場合は

```HAML:html
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8">
 <title></title>
 <link rel="stylesheet" href="style.css"/>
 <!--app.jsを読み込むための記載-->
 <script src="app.js"></script>
</head>
<body></body>
</html>
```
と記載することで読み込むことが出来ます。そしてapp.jsの中に

```JavaScript:app.js
alert('はじめまして');
```
と記載することで最初と同じように「はじめまして」が表示されます。
#終わりに
人生で初めてプログラミングを学習するにあたって様々なサイトを参考に勉強しました。
まだまだ始めたばかりでかなり初歩的な内容ですが今後も勉強を続け
読んだ時に復習になり尚且つ皆様の役に立つ内容を投稿できることを目指して頑張っていきます。
Zorin OSとStarLabsの紹介

表題のとおりです。

Zorin OSを使っている方は一定数いそうですが、
Zorin OSがメインOSとしてインストールされたハードを買っているマニアは日本にいない、つまり自分は希少種なのではないかと思い紹介記事を投稿することにしました。
また、Linuxがプリインストールされたパソコンのベンダーが少なく知られていない状況は良心的な世界ではないのではと思った背景もあります。

# [Zorin OS](https://zorinos.com/)とは
Ubuntuベース、つまりDebian系のLinuxディストリビューションです。
MacとWindowsの代替になることを謳っています。
コミュニティ内のどこかで言われていたのですが、WindowsからLinuxへ移行したい初心者の方向けに良いとも。
実際触り始めのときも今も（Windows+Mac)/2 な感覚はあります。WindowsやLinuxのパソコンをもともと使っていたMacユーザーでところどころMacのキーにイラッとする人にも向いていると思います。基本的にりんごと窓が嫌いな人には合いそうです。

違う系統のパソコンにZorinを入れる、あるいは仮想環境でZorinを起動するパターンはしたことはないので
これらに関しては他の記事をあたってください。トラブルシュートなどは情報量の多いUbuntuの方が参考になることが多いです。

共同創業者はArtyom ZorinとKyrill Zorinで、10代のころに着想したようです。2008年にUbuntuを初めて動かしてみた彼らは従来のOSよりとても起動や処理が速く、カスタマイズ性や柔軟性も優にあり、ウイルスに感染する心配もなかった、ようです。そして「WindowsやMacよりどの点においても素晴らしいのになぜ皆使わないのか？」と考え、一般的なコンピューターのユーザーであった父にLinuxを見せたそうですがLinuxは一般的なユーザー向けにデザインされていないと気づきました。その後、彼らはUIもUXも素晴らしく馴染みのあるディストリビューションを作ろうと決めました。
[ネタの元](https://itsfoss.com/zorin-os-interview/)
2010年の彼らの写真が某魔法学校の人に似てますね。

# [Star Labs](https://starlabs.systems/)とは
イギリスの会社で、ノートパソコンのベンダーです。
[Star Labsの創業背景](https://starlabs.systems/pages/about-us)
[こちらのページ](https://starlabs.systems/pages/laptops)を見るとわかりますがZorinはもちろんUbuntuやMint、Manjeroなどのプリインストールを選択でき、同じスペックのWindowsやMacのものと比べてはるかに価格が安いです。最高です。もうiOSアプリを開発する、iOSブラウザの検証以外でMacを使うことはないのではないでしょうか（言い過ぎ）。

UXはどうかというと、基本的に軽快感があります。ただ、未だ日本ユーザー向けには作られていないため英語が理解できること、多少の環境的なことは調べて解決できることが条件になります。また、日本に向けたマーケティングやロジスティクスも整っていないため我慢強さ？が必要です。あとCSの人とメール等でコミュニケーションできる能力があるとところどころ助かって良いです。

# まとめ
特に当該組織からアフィリエイト報酬などをもらっているわけではもちろんなく、ただただ心から愛しているプロダクトを紹介させていただきました。
他に良さげなLinuxのパソコンのベンダーをご存じの方がいましたら是非教えてください。Linuxを広めていきましょう。
そして皆さん、ブランド価値や既存の一般的な手法だけを盲信せずに、もっと比較したり考えたりした上で適したものを見極めることを怠らないようにしていきませんか。
簡単なカウントアプリを作ろう

##はじめに
こんにちは！今回はAndroidアプリ開発初心者向けに、簡単なカウントアプリを作っていきたいと思います😏
最初にJava、次にKotlinで書いていきます！

##カウントアプリを作って行こう！

今回作るアプリはこんなアプリです。
ボタンをタップすると上のTextViewの数字が増えていきます。

まずは見た目の部分である、Activity_Main.xmlを編集します。
TextViewとButtonがひとつずつあれば大丈夫です。

```xml:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="36dp"
        android:text="0"
        android:textSize="36sp"
        app:layout_constraintBottom_toTopOf="@+id/button"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="280dp"
        android:text="PLUS"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
```
今回はConstraintLayoutで作成してます。



##カウントアプリ(Java編)

Buttonを押したときの処理を書いていきます。

```Java:MainActyvity.Java

public class MainActivity extends AppCompatActivity {

    int count = 0;
    TextView textView;
    Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = findViewById(R.id.textView);
        button = findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                count += 1;
                textView.setText(String.valueOf(count));
            }
        });
    }
}
```

##カウントアプリ（Kotlin編）

Javaと同じく、Buttonを押したときの処理を書いていきます。


```kotlin:MainActyvity.kt

class MainActivity : AppCompatActivity() {

    var count = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        button.setOnClickListener {
            count += 1
            textView.text = count.toString()
        }
    }
}
```

##最後に

応用でクリックすると数字が減るボタンや、０にリセットされるボタンを作ってみても良いかもしれません😎
今日はここまで！
electron button click試す


環境構築にはこちらを使用
https://github.com/electron/electron-quick-start-typescript

src/main.tsでメインプロセスの処理。windows作成時にindex.htmlが読み込まれ、src/renderer.tsが読み込まれる。

```
$ tree -l 1 -I node_modules .
.
├── LICENSE.md
├── README.md
├── dist
│   ├── main.js
│   ├── main.js.map
│   ├── preload.js
│   ├── preload.js.map
│   ├── renderer.js
│   └── renderer.js.map
├── index.html
├── package-lock.json
├── package.json
├── src
│   ├── main.ts
│   ├── preload.ts
│   └── renderer.ts
├── tsconfig.json
└── yarn.lock
```


index.htmlにbuttonを追加。

```index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World!</title>
    <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
    <meta
      http-equiv="Content-Security-Policy"
      content="default-src 'self'; script-src 'self'"
    />
    <meta
      http-equiv="X-Content-Security-Policy"
      content="default-src 'self'; script-src 'self'"
    />
  </head>
  <body>
    <input id="csvLoad" type="button" value="読み込み"/>
    <!-- You can also require other files to run in this process -->
    <script src="./dist/renderer.js"></script>
  </body>
</html>

```


src/renderer.tsでbuttonのonClickに処理を追加。

```src/renderer.ts
document.getElementById('csvLoad').onclick = () => {
    console.log('aaaaaa')
}
```

結果
![スクリーンショット 2020-12-20 1.41.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278474/e9c5f55a-ae11-77c6-8127-4a7da5d5829f.png)
半年間レビュアーとして指摘したこと

ここ半年ぐらい、スクラムでチームを組んでプロジェクトを進めていましたが、
プログラムに関しては、自分がマジリクを受けてレビューしてOKだったらマージするスタンスを取っていました。

レビューの中でメンバーに対して指摘したことを厳選して６つにまとめてみました。
rubyで開発していましたので、ruby寄りの部分があると思いますが、基本的にどの言語でも言えるものかなと思います。


## 1. クラス名は名詞、メソッド名は動詞にする

``` ruby
# NG
class RequestUser
  def email
    ...
  end
end
```

オブジェクト指向では、基本的にクラス名は名詞、メソッド名は動詞になります。

クラスはオブジェクトであって、物なので、名詞をつけるようにしましょう。
メソッドは何かしらの動作をするものなので、動詞をつけるようにしましょう。

``` ruby
# OK
class UserRequests
  def send_email
    ...
  end
end
```

## 2. 変数名は単数なのか複数なのか明確にする

``` ruby
# NG
user = User.all
```

`User.all`でユーザーテーブルの全てのデータを取得しています。複数のユーザーが返ってくるはずですが、変数名が`user`なので、単体のユーザーかな？と勘違いしてしまいます。
配列などの複数のデータが入る変数名は複数形、単体の場合の変数名は単数形と、必ず命名するようにします。

``` ruby
# OK
users = User.all
```

## 3. 判定処理で逆の逆は避けたい

``` ruby
# NG
if !notSelected
```

えーっと・・・selectedの逆の逆・・？？
コードを見る時に処理が２つも追加されていて可読性が落ちてしまいます。notやunがつくような変数自体を出来る限り使わないようにしたほうが良いと思います。

``` ruby
# OK
if selected
```

## 4. あとで修正するものは # TODO をつける

``` ruby
# NG
# ダミーデータを設定、あとで修正する
user_name = "cure_milky"
```

仕様が決まってなくて、とりあえずダミーデータを設定することがあります。コメントを残すのは良いですが、仕様を決めることすら忘れ去られて、ずっとそのままになってしまうことがあります。
せめて、コメントに`TODO`を入れた方が良いと思います。IDEなどでコード内に`TODO`があれば一覧で出してくれることが多いので気づきやすいです。（それでも忘れることもあります。。）


``` ruby
# OK
# TODO: ダミーデータを設定、あとで修正する
user_name = "cure_milky"
```

## 5. ポジティブボタンは右、ネガティブボタンは左に配置する

**NG**
![FireShot Capture 014 - Edit fiddle - JSFiddle - Code Playground - jsfiddle.net.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113289/39a18b76-0287-d86a-bbda-7479180ea449.png)

ボタンが全部右に寄っていて、パット見でどれも同じように見えて視認性が悪いです。
次に進むもの（ポジティブなもの）は右に置いて強調する、戻るもの（ネガティブなもの）は左に寄せるようにした方がわかりやすく、押し間違いが発生しにくくなります。

**OK**
![FireShot Capture 011 - Edit fiddle - JSFiddle - Code Playground - jsfiddle.net.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113289/5db328fd-aa67-d862-c629-0ab2e05e9056.png)


## 6. ダイアログは簡潔に、ボタンの表現もわかりやすくする
**NG**
![FireShot Capture 017 - Edit fiddle - JSFiddle - Code Playground - jsfiddle.net.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113289/9dd11acc-f226-d549-8cf9-3ddd36d0f291.png)

よくあるダイアログですが、文章が少し冗長で内容を理解するのに時間がかかってしまいます。こんなダイアログだと、何も考えずに「はい」を押してしまいそうです。
ダイアログでは、文章は何をするかを簡潔に明確にして、ボタンの表現も何をするのかを書いてあげると断然わかりやすくなります。

**OK**
![FireShot Capture 020 - Edit fiddle - JSFiddle - Code Playground - jsfiddle.net.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113289/0043f653-5198-0182-0306-930917f7de57.png)
ActiveRecordのorをinjectするとSQLのネストが深くなる問題 (Rails 6.0まで)

## (追記)

Rails6.1からは、下に書いたクエリのネスト問題は解消されたようです。
[More concise Arel Or ast and make Or visitor non recursive by kamipo · Pull Request #39051 · rails/rails](https://github.com/rails/rails/pull/39051)
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Rails 6.1ではorを重ねてもネストが深くならなくなりました🆕 <a href="https://t.co/JaaedR3ebS">https://t.co/JaaedR3ebS</a></p>&mdash; Ryuta Kamizono (@kamipo) <a href="https://twitter.com/kamipo/status/1340499942255652866?ref_src=twsrc%5Etfw">December 20, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
教えて&治して下さりありがとうございます!

この記事は、それ以前のRailsでの解決案として参考にしえてもらえるとです。(記事のRailsは`6.0.3.4`です)

---


身長と体重の組があるから普通体型の人を抽出して! みたいなクエリを組み立てる話です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694808/2c3bd57d-fe2a-ff3a-aa0c-4ab6c61d7d7e.png)

```ruby
height_and_weight = [
  [150..159, 50..55],
  [160..169, 56..62],
  [170..179, 63..70],
  [180..189, 71..77]
]
```

## `inject`と`or`ではイマイチ

なんとなくArrayの`inject`とActiveRecordの`or`メソッドで書けそうですが、
これらをそのまま使うとイマイチなことになってしまいます。

```ruby
puts height_and_weight.inject(User.none) { |r, (h, w)|
  r.or(User.where(heigt: h, weight: w))
}.to_sql
```

```sql:出力(整形済み)
SELECT
  `users`.*
FROM
  `users`
WHERE
  (
    (
      (
        `users`.`heigt` BETWEEN 150 AND 159
      AND `users`.`weight` BETWEEN 50 AND 55
      OR  `users`.`heigt` BETWEEN 160 AND 169
      AND `users`.`weight` BETWEEN 56 AND 62
      )
    OR  `users`.`heigt` BETWEEN 170 AND 179
    AND `users`.`weight` BETWEEN 63 AND 70
    )
  OR  `users`.`heigt` BETWEEN 180 AND 189
  AND `users`.`weight` BETWEEN 71 AND 77
  )
```

目的の絞り込み自体はできるのですが、条件が増えるほどSQLのネストが深くなってしまいます。

## 文字列で頑張る

解決案ひとつめは、WHERE句内を文字列で作る方法です。

`sanitize_sql_array`でSQLインジェクション対策をしつつ条件を組み立てます。

```ruby
w = height_and_weight.map { |(h, w)|
  ActiveRecord::Base.send(:sanitize_sql_array,([
    '(height BETWEEN ? AND ? AND weight BETWEEN ? AND ?)',
    h.first, h.last, w.first, w.last
  ]))
}.join(" OR ")
puts User.where(w).to_sql
```

```sql:出力
SELECT
  `users`.*
FROM
  `users`
WHERE
  (
    (
      height BETWEEN 150 AND 159
    AND weight BETWEEN 50 AND 55
    )
  OR  (
      height BETWEEN 160 AND 169
    AND weight BETWEEN 56 AND 62
    )
  OR  (
      height BETWEEN 170 AND 179
    AND weight BETWEEN 63 AND 70
    )
  OR  (
      height BETWEEN 180 AND 189
    AND weight BETWEEN 71 AND 77
    )
  )
```

いいかんじになりました。

## Arelで頑張る

解決案ふたつめは、Arelで頑張る方法です。

```ruby
u = User.arel_table
puts User.where(
  height_and_weight.map {|(h, w)|
    Arel::Nodes::And.new([u[:height].between(h), u[:weight].between(w)])
  }.inject { |r, w|
    Arel::Nodes::Or.new(r, w)
  }
).to_sql
```

複雑ですね...

```sql:出力
SELECT
  `users`.*
FROM
  `users`
WHERE
  `users`.`height` BETWEEN 150 AND 159
AND `users`.`weight` BETWEEN 50 AND 55
OR  `users`.`height` BETWEEN 160 AND 169
AND `users`.`weight` BETWEEN 56 AND 62
OR  `users`.`height` BETWEEN 170 AND 179
AND `users`.`weight` BETWEEN 63 AND 70
OR  `users`.`height` BETWEEN 180 AND 189
AND `users`.`weight` BETWEEN 71 AND 77
```

出力されるSQLはシンプルになりました。
ANDのほうがORよりも結合の優先順位が高いので、括弧は無しで大丈夫です。
electron typescript環境構築

electron公式のstarterを使用する。
https://github.com/electron/electron-quick-start-typescript


```
git clone https://github.com/electron/electron-quick-start-typescript
cd electron-quick-start-typescript
yarn 
# electronを起動
yarn start
# 別タブで
yarn watch
```

![スクリーンショット 2020-12-20 1.22.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278474/172dd97f-1ce3-bafa-13b5-8a9e8a7a2929.png)
ドローンの色々

[ACCESS Advent Calendar 2020](https://qiita.com/advent-calendar/2020/access) の19日目の記事となります！

本当は別記事をかきたかったのすが、間に合わなかったので、なんとなくドローンの種類を書いてみます。

# 基本的な分類

* マルチコプター
* シングルコプター
* 固定翼機

## マルチコプター

普通のドローンはこのイメージです。3つ以上（通常4つ以上）のプロペラで構成されます。通常、モーター・プロペラしか可動部が無くシンプルなため安価でメンテナンス性が高く、ドローンが一般に使われるようになった原動力です。（例えば、この後に出てくるシングルローターのように改変ピッチではありません。と言っても今後は様々な理由で可動部が増えていくと思います。）


|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38555/819b7dba-b80f-d1fc-d513-99b7bced102a.png)DJI Mavic Mini 2 [画像引用元](https://store.dji.com/jp/product/mini-2-jp?vid=99441)|
|---|


## シングルコプター

いわゆるラジコンヘリです。かなり昔から存在し、技術的にはこなれていますが、操縦が難しい、メンテナンスコストも高いなどの欠点を持ちます。メンテナンスコストが高いのは、ラジコンヘリの多くがエンジンを使っている事、そして可変ピッチであり可動部が複雑なことが理由です。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38555/2e334606-ebf7-b870-0637-d5a072c7dc46.png)YAMAHA [画像引用元](https://www.yamaha-motor.co.jp/ums/heli/agri.html)|
|---|


## 固定翼機

ようはラジコン飛行機です。翼があり、長距離フライトが可能です。マルチコプターが10kmも飛べば長い中、固定翼機は100kmほどの飛行の可能性があります。一方、翼の分、機体が大きくなる、などの欠点があります。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38555/9c8b842e-7ba7-e7da-128f-0a2cdeb5bf2d.png)[画像引用元](http://drone-next.jp/news/whatnew/wingcopter/)|
|---|

# いろいろなマルチコプター

マルチコプターの中でもいろいろなものがあります。

一般的にドローンの形というと、以下のようなイメージではないでしょうか。下に脚が伸びているような形です。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38555/6a1a85fa-9264-72c1-9894-dbcb13a8b6f1.png) DJI Phantom 4 [画像引用元](https://www.dji.com/jp/products/phantom)|
|---|

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38555/449bad4d-e065-6776-94b6-f3199c0ee60e.png) ACSL PF-2 [画像引用元](https://www.harada-bussan.jp/product_detail/pf2/)|
|---|

これは、下側に重心があり、離着陸が安定する機体です。ドローンは、着陸時のリスクが最も高く、下側に重心のある事は大きなメリットです。
一方、こういった機体は巡行時の性能に制限をうけます。というのも、ドローンは巡行時、後ろ側のプロペラをより早く回して前傾姿勢をとりますが、下側に重心があると水平に戻る力働くためです。

例えば、以下のような機体は、より中心に重心があります。小型機を中心にこういった形状が多くなっています。離発着時の安定性には制限がありつつも、巡行時の性能が高くなっています。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38555/c82a4383-a0ec-7d63-b3b4-ea3735c9e7d4.png) DJI Mavic Mini 2 [画像引用元](https://store.dji.com/jp/product/mini-2-jp?vid=99441)|
|---|

フレームの形で言うと様々な変わり種がでてきました。
Amazonは巡行時に最適化した物流用ドローンを発表しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38555/a2d9c553-8336-2bf6-d4b6-f8317b18c163.png) Amazon Prime Air [画像引用元](https://techcrunch.com/2019/06/05/a-first-look-at-amazons-new-delivery-drone/)|
|---|

以下はエアロネクストのNext Deliveryでこちらも巡行時に最適化されているようです。
※ こちらは私の勤め先のACCESSの協業先で、中立的に書けないので、ここでは細かく触れないようにします

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38555/8ba45f98-99a8-19a0-ffb4-4caaed3673c9.png) AeroNext Next Delivery [画像引用元](http://drone-next.jp/news/aeronext-5/)|
|---|

以下のような変わった形のものもあります。プロペラが平行で無く段違いとなっています。これも巡行時の性能を出すためのものです。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38555/d84e3a73-b03c-aec0-05c2-76fb5ab5b615.png) Manma [画像引用元](https://www.suasnews.com/2020/09/uk-retailer-tescos-to-trial-drone-delivery-with-manna/)|
|---|
Flash Advent Calendar 19日目 - OSS活動で得られた事 -

今日は休日なので小休憩もかねて
OSSで得られた経験などについて書きたいと思います。

# ソースが公開される

OSSなので当たり前ですが、自分の実装したソースが誰でも見れる場所に公開されます。
OSSを始める最初の障壁なのですが、一番敷居が高い障壁でもあると思います。

自分の場合は、誰にどのように評価されても
ありがとうございます！っという気持ちと
頂いた意見を全てプラスの言葉に変換して実装に反映する！！
たとえどんな失敗があっても訂正すれば良い！！
っという強い気持ちを持ってメンテナンスを行いましたw

このメンテナンスする作業が一番スキルアップに繋がったと思います。
肝も座りますw


# ネットでみていた有名・優秀な方達から意見がもらえる

実装するのに参考にしてるサイトの会社・個人の方
国内・国外問わずOSSで有名な人達からの意見や知識がいただけます。
本当に多くの方から沢山の事を学ばせて頂きました。
これは、OSS活動した事で得られたとても貴重な体験だと思っています。

直接・間接的に教えていただいた事は全てとても貴重な体験で
エンジニア業を行う上で、凄く支えになる体験となりました。

世の中で天才と呼ばれる人達は物事をどのように見ているのか
スキルをどのように磨いているのか
etc...

本当に沢山の事を学ばせて頂きました。

「千里の道も一歩から」ということわざがありますが
本当にその通りで、何かを始めるのに年齢や経験など関係ないという事を学びました。
何事も始める事が大切だと思います。

では、本実はこの辺で終わろうと思います。
明日は紀平さんの記事で「JIT 高速化について」です。
FIREへの道

# ■Goals

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213492/36e570c9-9c32-3785-9e3d-a35da0fd6cbd.jpeg"  width="640px">


投資による収入を増やし、<font color="LightCoral">**FIRE**</font>(financial independence retire early）することが目的です

# ■基本的な考え

収入を増やし、支出を抑え、*入金力*を増やす

入金率 : 投資に回せる資金

=> <font color="LightCoral">**資産収入を増やす**</font>

# ■資産収入を増やす方法

◎   <font color="LightCoral">個別株投資</font>   ： 企業分析の楽しみがある  
△   投資信託     ： 楽しくない  
○   米国index投資   ：  いつまで続くかはわからない  
◎   高配当株投資    :   堅実だけと分散は必要  
×   不動産投資      :   そんな資金力ない  

# ■個別株投資の歩き方

とても難しい・・・

テクニカル？ファンダメンタル？  
グロース？バリュー？  
トレンド？テーマ姓？  

=> <font color="LightCoral">**しっかり企業の価値を見極められるようになる！！**</font>

というわけで中小企業診断士の知識を身につけることにしました。
SPARQLで別グラフをLEFT JOIN, INNER JOINする

SPARQLでSQLみたいなJOINをしたいのです。（これがSPARQLとして行うべきなのかどうかは別にして）

まずは、メインクエリとして、１つのグラフをSELECTするSPARQLを書きます。

```lang:SPARQL
SELECT *
FROM <graph1>
WHERE {
  ?s <商品コード> ?code
 .?s <商品名> ?name
}
LIMIT 3
```

商品コードと商品名がとれました。
> [code],[name]
> A01,にんじん
> A02,じゃがいも
> A03,ピーマン

* * *

次に、他のグラフをLEFT JOINしてみます。
JOINするグラフは、WHEREの中に、サブクエリとして書きます。
連結キーは ?code で、メインクエリとサブクエリで同じ名前にすることで、連結されます。

```lang:SPARQL
SELECT *
FROM <graph1>
WHERE {
  ?s <商品コード> ?code
 .?s <商品名> ?name

 .OPTIONAL{
   SELECT ?code ?price
   FROM <graph2>
   WHERE {
     ?s <商品コード> ?code
     .?s <お値段> ?price
   }
 }

}
LIMIT 3
```

他のグラフからお値段も取ってこれました。

> [code],[name],[price]
> A01,にんじん,100
> A02,じゃがいも,50
> A03,ピーマン,

* * *

続いて、LEFT JOINをINNER JOINに変えてみます。
サブクエリのOPTIONALを取るだけです。

```lang:SPARQL
SELECT *
FROM <graph1>
WHERE {
  ?s <商品コード> ?code
 .?s <商品名> ?name

 .{
   SELECT ?code ?price
   FROM <graph2>
   WHERE {
     ?s <商品コード> ?code
     .?s <お値段> ?price
   }
 }

}
LIMIT 3
```

こうすると、JOINした先のグラフに無いデータは出てきません。

> [code],[name],[price]
> A01,にんじん,100
> A02,じゃがいも,50

このSPARQLはVirtuoso対応です。
サブクエリを複数書くことで、いくつでも連結できます。
他にも連結方法は有ると思いますが、この方法がわかりやすく、サブクエリ内でFILTERなどもできるので、活用しています。

* * *

ついでに、
連結キーが、トリプルでいうところの ?s ?p ?o の ?o で結びつけた例を紹介しましたが、
私が遭遇した、メインクエリの?oとサブクエリの?sで結び付けたい場合は、以下のように書きます。
サブクエリのSELECTの?sを文字列に変換し、別名として?codeを割り当てます。

```lang:SPARQL
SELECT *
FROM <graph1>
WHERE {
  ?s <商品コード> ?code
 .?s <商品名> ?name

 .{
   SELECT (str(?s) AS ?code) ?price
   FROM <graph2>
   WHERE {
     ?s <お値段> ?price
   }
 }

}
LIMIT 3
```

これでうまく連結されました。
現場からは以上です！

（５年前の記事が下書きとして発見されたので投稿してみました。記事は完成していたのに、なぜ投稿してなかったのかは謎です。）
Notionで日付をメンションする

アルプ株式会社でエンジニアをしています、集約のエンティティ@pictinyです。
これは[Notion Advent Calendar 2020](https://qiita.com/advent-calendar/2020/notion) 19日目のエントリです。
18日目は[Notionでタスクの状態を絵文字で可視化する](https://qiita.com/pictiny/items/6d0665e03769a3283b6e)でした。

# メンション
Notionではテキストにメンションを埋め込むことができます。
テキスト中で `@` を打ち込むと、メンションをすることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427952/a967e89f-245b-cba6-a95e-f16333667ce3.png)

## 日付メンション
`@` の後に特定の日付を入力することで、日付のメンションができます。
日付メンションを作ると、表示フォーマットを変更したりリマインドを設定することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/427952/240af8c0-cb39-a8c9-bf8f-0a7a2af7c2d3.png)

# まとめ
公式ドキュメントは[Reminders & @-mentions](https://www.notion.so/Reminders-mentions-777c3d4b488c4e3696f2cc9940cceb2c)にありますので、そちらもご覧ください。
Mapbox GL JSスタイリング - ベクトルタイル内データの可視化

##はじめに
[「Mapbox GL JSスタイリング - 誰でも楽しめる地図デザイン」](https://qiita.com/moritoru/items/d439f2c3806ba5f635c6) の続編として、ここではベクトルタイルのデータにスタイルを設定して可視化する方法を説明します。

Mapbox GL JSでは、ベクトルタイル（MVT形式）を可視化するために、どのデータをどのスタイルで表示するかをstyle.jsonに記述します。

ベクトルタイルに存在しないデータは可視化できませんが、データが存在していればスタイルを設定して可視化することができます。

Mapboxや、MapTilerのサービスで標準的に提供されている地図のスタイルは、ベクトルタイルに存在している全てのデータが可視化されているとは限りません。むしろ、スタイル設定されずに可視化されていないデータが一定程度存在します。

##事前準備
前回の記事の[「事前準備」](https://qiita.com/moritoru/items/d439f2c3806ba5f635c6#事前準備) と同様に、MapTilerでアカウントを取得して、JP MIERUNE Streetsを選び、右下にある･･･（赤○で囲った部分）をクリックし、Edit a copyを選択します。

今回は、東京ディズニーリゾート（千葉県浦安市）付近を表示します。
![スクリーンショット 2020-12-19 15.14.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531580/7d5fc9f6-290c-daaa-5eb0-d27de282f694.png)
よく見ると、ディズニーリゾートを囲むように走っている「ディズニーリゾートライン」というモノレールが表示されていません。駅名だけが表示されています（2020年12月19日現在）。

##ベクトルタイルを調べる
画面右上の「VIEW」からInspectを選択します（通常はMapになっています）。
![スクリーンショット 2020-12-19 15.15.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531580/16df3ec3-88cd-dd1c-3755-d7cfaee6fde3.png)

すると、下のような画面が表示されます。この画面は、ベクトルタイルとして提供されているデータを見ることができ、画面をクリックすることで、表示されているズームレベルに格納されている、ライン、ベクトル、ポイント各形式のデータのデータ属性を細かく参照することもできます。

* Inspect画面

この画面をよく見ると、ディズニーリゾートラインに相当するラインが存在していることがわかります。
![スクリーンショット 2020-12-19 23.23.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531580/c7538a06-9192-5411-ae1e-fb4b9baf50c9.png)



では、そのラインをクリックしてみましょう。objectのidがtransportation、classがmonorailとなっているLineStringであることが判明します。
![スクリーンショット 2020-12-19 15.27.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531580/485764f2-cc4b-2d5f-82b4-87978617d8db.png)

一方、railway関連のレイヤを確認してみると、monorailは見当たりません。

![スクリーンショット 2020-12-19 15.33.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531580/c6199832-77d7-b91f-0f7b-89991377ef8b.png)
なお、レイヤの名称にmonorailが無くても、それぞれのレイヤが参照しているclassにmonorailが含まれている場合もあり得ますので、念のために各レイヤが参照しているclassを確認しておきましょう。

##レイヤを作成してスタイルを設定
どれか1つのrailway関連のレイヤをコピーして、monorailのレイヤを作成します。コピーして作った新しいレイヤで、Filterの設定をclass==monorailとします。Paint propertiesでズームの変化に対応した色やラインの太さを好みに応じて設定して下さい。
![スクリーンショット 2020-12-19 15.46.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531580/9f615d13-5ef1-5969-1a46-e48fbaad4b4f.png)

私は、通常の鉄道よりもやや細めのライン設定を施しました。無事にディズニーリゾートラインが表示されるようになりました。めでたしめでたし。。
![スクリーンショット 2020-12-19 16.13.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531580/f033d065-af62-8afc-3577-6ae64afb196d.png)

##最後に - この設定は全国のmonorailに波及します
今回設定したmonorailのレイヤは、ディズニーリゾートラインだけが対象では無く、全国あまねくclass==monorailが対象となります[^1]。

例えば千葉県佐倉市の「ユーカリが丘線」はclass==monorailとして設定されています。今までは「ユーカリが丘線」や千葉市の「千葉モノレール」はJP MIERUNE Streets地図には表示されていなかったのですが、今回の設定によって表示されるようになります。

[^1]: 東京モノレール羽田線は、ベクトルタイルでclass==light_railとして設定されているので、もともと表示されています。

* class==monorail設定前の表示
![スクリーンショット 2020-12-20 0.28.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531580/2fecd57f-3284-91ba-aab8-43d47196d396.png)
ユーカリが丘線の駅名だけが表示されています。


* class==monorail設定後の表示
![スクリーンショット 2020-12-20 0.27.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531580/5a250edd-f844-630c-3cd1-b0441c03ec1d.png)
駅名とモノレールの路線が表示されるようになりました。
C言語+MPIのtips（MPI_Scatterv）

MPI_Scattervは「あるプロセスが持つデータを，任意に分割して，各々のプロセスに配分する関数」。
※MPI_Scatterは「あるプロセスが持つデータを，等分して，各々のプロセスに配分する関数」であったことに注意。

【目的】
あるプロセスに存在する一次元配列 send から適当な数（eachsz）の要素だけ取り出して、各々のプロセスにある一次元配列 recv に代入することでMPI_Scatterv の機能を知る。

【使用するもの】
open-mpi

【環境】 
$ mpicc —version
 Apple clang version 11.0.3 (clang-1103.0.32.29)  
Target: x86_64-apple-darwin19.6.0  
Thread model: posix  
InstalledDir: /Library/Developer/CommandLineTools/usr/bin 

【方法】

```c:Scatterv.c 
#include<stdio.h>
#include<mpi.h>

int main(int argc, char **argv){
  int i;
  int my_rank, num_proc;
  int send[20];
  int recv[10];
  int eachsz[2] = {3,8};
  int place[2];

  MPI_Init(&argc, &argv);
  MPI_Comm_size(MPI_COMM_WORLD, &num_proc);
  MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

  for(i=0;i<10;i++) recv[i] = -1;

  if(my_rank == 1){
        for(i=0;i<20;i++) send[i] = i;
        for(i=0;i<2;i++) place[i] = 10*i;
  }

  MPI_Scatterv(send, eachsz, place, MPI_INT, recv, eachsz[my_rank], MPI_INT, 1,MPI_COMM_WORLD);

  printf("myrank %d:", my_rank);
  for(i=0;i<10;i++) printf(" %2d",recv[i]);
  printf("\n");

MPI_Finalize();
return 0;
}
```

【結果】
mpicc コマンドでコンパイル、mpirun コマンドでプロセス数を２にして実行。

```
$ mpicc Scatterv.c
$ mpirun -np 2 ./a.out
myrank 0:  0  1  2 -1 -1 -1 -1 -1 -1 -1
myrank 1: 10 11 12 13 14 15 16 17 -1 -1
```

【考察（何が起きたのか）】
まずプロセス０と１でそれぞれ send[0]、send[1]、…、send[19] が生成される。
プロセス０と１でそれぞれ recv[0]、recv[1]、…、recv[9] が生成される。
プロセス０と１でそれぞれ eachsz[0]（=3）、eachsz[1]（=8） が生成される。
プロセス０と１でそれぞれ place[0]、place[1] が生成される。

それぞれのプロセスでのfor文で値が格納される。 
at プロセス０ recv[0]=-1、 recv[1]=-1、…、recv[9]=-1
at プロセス１ recv[0]=-1、 recv[1]=-1、…、recv[9]=-1
 at プロセス１　send[0]=0、send[1]=1、…、send[19] =19 
at プロセス１　place[0]=0、place[1]=10

MPI_Scattervによって「send」から各プロセスに個数「eachsz」のデータが送られる。各プロセスに送られるデータの場所（配列のインデックス）は「place」。つまり、place[0]=0なのでsend[0]から数えてeachsz[0]個のデータ、place[1]=10なのでsend[10]から数えてeachsz[1]個のデータが送信される。
送るデータの型は整数（int）「MPI_INT」。各プロセスの「recv」は、それぞれ「eachsz[my_rank] 」個の要素を受け取る。つまり、プロセス０は３個（eachsz[0]=3）、プロセス１は８個（eachsz[1]=8）の要素を受け取る。受け取るデータの型は整数（int）「MPI_INT」。データはプロセス「１」から送信される。
よって
at プロセス０
recv[0]（= プロセス１の send[0]）=0、
recv[1]（= プロセス１の send[1]）=1、
recv[2]（= プロセス１の send[2]）=2
となる。さらに
at プロセス１
recv[0]（= プロセス１の send[10]）=10、
recv[1]（= プロセス１の send[11]）=11、
…、
recv[7]（= プロセス１の send[17]）=17
となる。

それぞれのプロセスで recv が表示されて終了。

【参考】 
「mpi 並列プログラミング」と検索すると、より正確でより情報量の多い資料が見つかります。
Atomでフォントの拡大縮小

最近、目が悪くなってきたせいでデフォルトの大きさだとなにも見えない

##フォントの拡大
マイナスでも大きくなった

```
shift + command + '+'
shift + command + '-'
```
##フォントの縮小
マイナスかアンダーバーで小さくなった

```
command + '-'
command + '_'
shift + command + '_'
```
量子アニーリングで全加算器を作り、加算を行う

ふと思いました。
量子ゲートではよく足し算を計算することをデモすることがあるのですが、
量子アニーリングでは足し算を計算させることをちゃんと説明しているのは少ないなと。
なら、作ってみようと思いました。

#はじめに
足し算を行うために必要なのは、全加算器をひたすら繋げていくことだけです。
量子アニーリングでどのように組めばいいのかを考えます。
加算器については、説明してくれている人がいるので、そちらに任せます。

#量子アニーリング全加算器
普通の回路同様、1,0のビット単位で計算を考えます。
単純にand, xorを実装することはできないので、以下のように考えます。
$a_i$：$a$の$i$桁の値
$b_i$：$b$の$i$桁の値
$c_i$：$c$の$i$桁の値
$s_i$：$i$桁の繰り上げ

```math 
 a_i + b_i + s_{i-1} = c_i + 2s_i
```
この時に

```math 
s_{-1} = 0\\
\sum_i\{(a_i + b_i + s_{i-1} - c_i - 2s_i)^2\} = 0
```
が成り立つようにすれば良い。

これを展開すると

```math 
a_i + b_i + s_{i-1} + c_i + 4s_i \\
+ 2a_ib_i + 2a_is_{i-1} +2b_is_{i-1} +4c_is_i\\
- 2a_ic_i - 4a_is_i 
- 2b_ic_i - 4b_is_i 
- 2s_{i-1}c_i - 4s_{i-1}s_i \\
 = 0
```
となる。
これをpythonで書くと

```python 
dict_qubo[(f"A{i}", f"A{i}")] = 0.2
dict_qubo[(f"B{i}", f"B{i}")] = 0.2
dict_qubo[(f"s{i+1}", f"s{i+1}")] = 0.8
dict_qubo[(f"R{i}", f"R{i}")] = 0.2
dict_qubo[(f"A{i}", f"B{i}")] = 0.4
dict_qubo[(f"A{i}", f"R{i}")] = -0.4
dict_qubo[(f"B{i}", f"R{i}")] = -0.4
dict_qubo[(f"A{i}", f"s{i+1}")] = -0.8
dict_qubo[(f"B{i}", f"s{i+1}")] = -0.8
dict_qubo[(f"R{i}", f"s{i+1}")] = 0.8
if i != 0:
    dict_qubo[(f"s{i}", f"s{i}")] += 0.2
    dict_qubo[(f"A{i}", f"s{i}")] = 0.4
    dict_qubo[(f"B{i}", f"s{i}")] = 0.4
    dict_qubo[(f"R{i}", f"s{i}")] = -0.4
    dict_qubo[(f"s{i}", f"s{i+1}")] = -0.8
```
となる。
ちなみに、桁数はD-Waveに乗る限り載せられます。
(Advantageであれば、$2^{500}$同士の計算も可能であることを確認しています。ただ、正しい結果が返ってくることとは別です。)

実装したコードは、下記に置いておきます。
https://github.com/yuzo63/dwave_adder


# 実行結果
最大値を$2^5$(n_digits=5)なら、

```
16 + 16 = 32
8 + 30 = 38
7 + 16 = 23
8 + 4 = 12
…
30 + 19 = 49
25 + 23 = 48
13 + 19 = 32
正しい結果　　： 49 / 100
正しいパターン： 48
```

最大値を$2^{50}$(n_digits=50)にしたとき、

```
166594504156925 + 700719128793454 = 867313632950379
962493425599632 + 867630342215456 = 1830123767815088
正しい結果　　： 2 / 1000
正しいパターン： 2
```
何回か計算をすればわかると思いますが、同じ結果にはならず毎度違う結果になると思います。

# わかること
今回、計算の際に、a,b,cの値を指定せずに計算を行っています。
つまりは　$0$~$2^n$と$0$~$2^n$のどれかが確率的に計算されることになります。
これがよく量子コンピュータは並列で計算されているといわれる所以です。
(実際は計算行った際に観測しているので結果1つしか返ってこないんですけどね。。。)
特定の足し算や特定の解を持つ足し算の組み合わせを知りたい場合は、a,b,cをそれぞれ固定する必要がありますが、それはまた今後。

# 参考
実装したコード
https://github.com/yuzo63/dwave_adder

先駆者たち
https://qiita.com/abenben/items/1ccc51cd5d9ba18b30c1
https://qiita.com/YuichiroMinato/items/e5ed269c0a18d19d8390
https://qiita.com/navitime_tech/items/a9ec5784901c7f8bfb57
https://docs.dwavesys.com/docs/latest/c_handbook_8.html
dynamodbで配列の取り扱いについて

今回はdynamodbのデータの操作方法でとても詰まったのでそれを記事にしたいと思います。

dynamodbの個人的なメリット

* 実は無期限の無料利用枠。25GBのストレージ量であれば常に無料で利用可能
* 普段Vueを書いているのでjavascriptの記述で書けるのは魅力的(lambdaのランタイムにNode.jsを選択)

dynamodbはテーブルの正規化ができないので、なるべく少ないテーブル数で構築するのが好ましいらしい。

### まず簡易掲示板を作ると仮定する
期待するテーブル: PostsテーブルとCommentsテーブル

- Postsテーブルのスキーマ
- 
```
id: number
name: string
text: string
```

- Commentsテーブルのスキーマ
- 
```
id: string
post_id: string
name: string
comment: string
```

サンプルデータをdynamodbで表現すると

```json
{
 "id": "1",
 "name": "テスト１",
 "text": "初めての投稿",
 "comments": [
  {
   "id": "1",
   "name": "テスト２",
   "comment": "コメント1"
  },
  {
   "id": "2",
   "name": "テスト3",
   "comment": "コメント2"
  }
 ]
}

```

### comments配列に要素を追加するには
set文にlist_append関数を用いると実現可能。
以下のようなparamsをdocumentClientのupdateメソッドの引数に渡してあげるだけ

```javascript

const AWS = require('aws-sdk');
const documentClient = new AWS.DynamoDB.DocumentClient();

const newComment = {
   id: "3",
   name: "テスト4",
   comment: "コメント3"
};

const params = {
  TableName: "tableName",
  Key: {
    id: "1"
  },
  UpdateExpression: `SET #key = list_append(#key, :value)`,
  ExpressionAttributeNames: {
    '#key': "comments",
  },
  ExpressionAttributeValues: {
    ':value': [newComment]
  },
};

await documentClient
      .update(params)
      .promise();

```

### 解説
dynamodbではsql文のようなものをUpdateExpressionに書くことができる。
`SET #key = list_append(#key, :value)`
list_append関数はデータの追加というより配列の結合である。comments配列と[newComment]配列を連結するイメージ。

`#key`はプレースホルダーでExpressionAttributeNamesに割り当てたい名前を与えてあげる。
dynamodbには予約語が多いが、プレースホルダーを使うと回避できる。
[dynamodbの予約語リスト]
(https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/ReservedWords.html)

`:value`もプレースホルダーでExpressionAttributeValuesで割り当てたい変数を代入する

### では先ほど追加したオブジェクトのcommentを'hogehoge'に更新しよう

```javascript

const updateComment = {
   id: "3",
   name: "テスト4",
   comment: "hogehoge"
};

const params = {
  TableName: "tableName",
  Key: {
    id: "1"
  },
  UpdateExpression: `set #key[?]= :value`, // インデックスがわからない。。
  ExpressionAttributeNames: {
    '#key': "comments"
  },
  ExpressionAttributeValues: {
    ':value': updateComment
  },
};

```

自分はここでどハマりました。
comments配列のインデックスがわからないとコメントの更新ができない
`#key`配列をループで回すことができれば代入できそうだが、、

### 解決策
思い切ってデータ構造を変える。comments配列からオブジェクトに変換し、idを外に出す

```json
{
 "id": "1",
 "name": "テスト１",
 "text": "初めての投稿",
 "comments": {
   "1": {
     "name": "テスト２",
     "comment": "コメント1"
   },
   "2": {
     "name": "テスト3",
     "comment": "コメント2"
   }
 }
}

```

こうすると

```javascript
const updateComment = {
   id: "3",
   name: "テスト4",
   comment: "hogehoge"
};
const params = {
  TableName: "tableName",
  Key: {
    id: "1"
  },
  UpdateExpression: `set #key.#id = :value`,
  ExpressionAttributeNames: {
    '#key': "comments",
    '#id': updateComment.id
  },
  ExpressionAttributeValues: {
    ':value': updateComment
  },
};

```
こうすることで配列のインデックスに悩まされることから解放されました。
### まとめ
dynamodbでは配列の末尾に要素を追加するならlist_apend関数が使える。
でも更新するのは難しい！！
「こうしたらできるよ！」とかあったらコメントいただけたら嬉しいです。
Flutterでダイアログを開く際に非同期処理をする

本記事は [CBcloud Advent Calendar 2020](https://qiita.com/advent-calendar/2020/cbcloud)の20日目の記事です．

自分はCBcloudに，toCサービスである[PickGo 買い物](https://pickgo.town/shopping/)のアプリを主に担当するモバイルアプリエンジニアとして参画しています．
PickGo 買い物は，プロのドライバーさんに買い物を代行してもらえ，**欲しい物が当日すぐに届くアプリ**です．
現在送料無料キャンペーンをやっているので良かったらこの機会に是非試してみてください！

この記事では，自分が業務中に編み出したテクニックの一つを紹介します．

# ダイアログを出す時に非同期処理をしたい

ユーザーの操作からダイアログを出すとき，その内容をAPIから取得したいシチュエーションを考えます．

↓これ
![async.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154601/851fe1df-a249-6bf2-fb13-179c8e7cdeb1.gif)

何かしら非同期で通信している場合は，ロード中であることをこのようにインジケーターを出すことで親切になります．これは別に元のページでやっても良いのですが，どうせダイアログを出すのであればダイアログ上でやったほうがなんか見た目も良い気がします．

これを実現するために，まずダイアログのWidget上で普通のページ用Widgetと同じように`StatefulWidget`でいう`initState`（`ChangeNotifier`でいうコンストラクタ）で非同期処理をすることを考えました．

…しかしただやるだけではうまく行かず．ちょっと前の話なので記憶が曖昧ですが，確かProviderでうまく`ChangeNotifier`を呼び出せなかったことが原因だったと思います．おとなしく`StatefukWidget`を使ってたらできていたかもしれませんが，`StatefulWidget`をなるべく使いたくない気持ちが勝って更に探っていました．


# 実装方法

色々考えたところ，以下の方法で落ち着きました．

1. `showDialog`のラッパー関数を用意する
2. 内部で`Provider.value`を使い，ViewModel的な役割を果たすControllerを利用する
3. ラッパーの引数に実際に行う非同期処理の内容と，その結果を含んだ`WidgetBuilder`的なものを定義しておく

実装はこのようになります．

```dart

typedef ResultBuilder<R> = Widget Function(BuildContext, R);
typedef PreProcess<R> = Future<R> Function();

Future<T> showAsyncDialog<T, R>({
  BuildContext context,
  ResultBuilder<R> resultDialogBuilder,
  PreProcess<R> process,
}) async {
  final controller = _AsyncDialogController(process: process);

  final dialogResult = await showDialog(
      context: context,
      builder: (context) {
        final dialog = Builder(
          builder: (context) {
            final isLoading = context.select(
                (_AsyncDialogController<R> controller) => controller.isLoading);
            final result = context.select(
                (_AsyncDialogController<R> controller) => controller.result);
            return isLoading
                ? const PlaceholderDialog()
                : resultDialogBuilder(context, result);
          },
        );

        return ChangeNotifierProvider.value(
          value: controller,
          child: dialog,
        );
      });

  return dialogResult;
}

class _AsyncDialogController<T> extends ChangeNotifier {
  _AsyncDialogController({this.process}) {
    Future(() async {
      result = await process();
      isLoading = false;
      notifyListeners();
    });
  }

  bool isLoading = true;
  final Future<T> Function() process;
  T result;
}
```

ダイアログ中のProviderアクセスは https://stackoverflow.com/questions/57968453/how-to-access-provider-providers-in-dialogs-in-flutter を参考にしました．

`PlaceholderDialog`はロード中に出すダイアログで，結果のダイアログとは別物にしてあります．
ここの実装を工夫すれば処理完了した時にアニメーション付きで結果のダイアログがスムーズに出せそうな気がします．

利用側はこんな感じです．

```dart
TextButton(
  onPressed: () => showAsyncDialog<void, String>(
    context: context,
    resultDialogBuilder: (context, result) => AlertDialog(
      content: Text(result),
    ),
    process: () async {
      await Future.delayed(const Duration(seconds: 2));
      return 'hoge';
    },
  ),
  child: Text('Tap me'),
),
```

実装してみればなんてことのないものでしたが，個人的に作っておくと結構便利だなと思いました．