OmniAICreator/Qiita-1.07M huggingface dataset:
【Flutter】fvmをAndroid Studioで使うときに注意したいこと

# 概要
fvmをAndroid Studioで使用し、fvm global等でバージョン指定を変更した際、Flutter SDKだけでなくDart sdkの指定も注意しましょう。
flutter --verisonコマンドと実態が合わなくなる場合があります。筆者は以下のようなことを経験し、何時間かハマりました。。。

・**チーム開発で自分だけビルドができない**。バージョン揃えているつもりだが、実際にはそう見えているだけ。引数がチームメンバと異なるなど。
・**Dart SDKのバージョンが正しく設定されているはずなのに使用したいAPIが利用できない**(例えば、以下エラー文が表示される)

```
The current Dart SDK version is x.x.x

Because material_banner requires SDK version >=x.x.x <3.0.0, version solving failed.
pub get failed (1; Because material_banner requires SDK version >=x.x.x <3.0.0, version solving failed.)
```

# 確認方法

##①Flutter SDKのバージョンを確認
flutter --versionで指定したバージョンになっているかを確認

```shell-session
$ flutter --version
Flutter 2.5.1 • channel stable • https://github.com/flutter/flutter.git
Framework • revision ffb2ecea52 (5 days ago) • 2021-09-17 15:26:33 -0400
Engine • revision b3af521a05
Tools • Dart 2.14.2 ←🌟🌟🌟ただし、これを見て安心してはいけない！！！🌟🌟🌟
```

念のため、Android Studioのバージョンも確認する

Android Studio > Preferences > Languages & Frameworks > Flutter
※注: 既存プロジェクトのみ(新規PJ作成時には[Flutter][Dart]の項目は表示されない)
![スクリーンショット 2021-09-25 21.41.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1424230/746d303d-8672-e35b-de10-8c62642aefa0.png)

##②Dart SDKのバージョンを確認する
※Flutterのバージョンについては、flutter --versionでケアできますが、Dart SDKは結構忘れがちなので要注意だと思います。

Android Studio > Preferences > Languages & Frameworks > Dart
![スクリーンショット 2021-09-25 21.48.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1424230/ebce4a15-11a0-ccf9-5ae5-486442264c10.png)
画像だと見にくいかもしれないので、パスも念のため記載しておきます。

```
/Users/xxxxxxxxx/fvm/versions/x.x.x/bin/cache/dart-sdk
```

皆さんも筆者が経験したようなことが実際に起きたら、ぜひ一度お試しください。
HTML（基本のタグについて）

今回はHTMLのタグについて説明していこうと思います。
まず前回の基本構文を見ていきましょう。


```

<!DOCTYPE html>
<html lang="ja">
<head>
   <meta charset="utf-8">
   <title>ようこそ</title>
</head>
<body>
　　　　　　<h1>おはよう</h1>
   <p>こんにちわ</p>
</body>
</html>

```
<h1>タグについて</h1>

主にHTMLで重要なタグはDOCTYPE宣言、HTMLタグ、HEADタグ、BODYタグになります。
順番に説明していきます。

<h2>DOCTYPE宣言とは</h2>
HTMLの中でも一番ないといけないタグで私は班長と覚え方で覚えました。
このタグが意味するものは、いまからHTML言語を使うぞという命令をコンピュータに出しています。
これがないとエラーになり機能できなくなります。


<h2>HTMLタグについて</h2>
このタグはこのサイトの文章がHTML言語で書かれた文章を表していて　lang="ja"という意味は
HTML言語のサイトで日本語で書かれているよていう意味になります。

<h2>HEADタグについて</h2>
HTML構築されたサイトの脳みその部分にあたります。
HEADタグの下のとこには大事な情報などが書かれています。

<h2>METAタグについて</h2>
ページを記述している言語
文字エンコーディングを指定しています。また、キーワードや説明文などを記述したりもします。

charset="utf-8"はUTF-8という文字エンコーディングを使うよていう命令です。
また他にdescriptionといった検索した際に出てくる少量の説明部分になります。詳しくは別記事に載せます。


<h2>titleタグについて</h2>
このタグの間に書いた日本語などはブラウザーの上のタブのところの文字としてサイト名などが反映されます。


<h2>BODYタグについて</h2>
HTML文章の体の部部にあたります。またここに書くタグや文章はサイトの文章として出てきます。

<h2>Hタグについて</h2>

Hタグとは見出しタグになり、１〜６まであります。
H1は一番大きく表す最初の見出しでそこからだんだん見出しのサイズか小さくなるにつれて
文字の大きさも変わります。

<h2>Pタグについて</p>

Pタグは段落を表すタグになります。
例えばこんな感じになります。
おはようございます。
<p>おはようございます。</p>

最初のおはようはタグを入れていません。
改めて下にタグをいれたことにより空白が空き、段落ができました。

次回はタグについての続きを書いていこうと思います。
【個人開発】検索サイトのクエリストリングを検索できるwebサービス「searchsearch」をリリースしました！

たとえばQiitaで「AWS ECS docker」について新着順で検索をすると、URLはこうなります。

```
https://qiita.com/search?sort=created&q=AWS+ECS+docker
```

`q=`で検索文字列を、`sort=`でソート順を指定しているみたいですね。

Googleで「Ruby docker image」について期間指定を1年以内にして検索するとこうです。

```
https://www.google.com/search?q=Ruby+docker+image&source=lnt&tbs=qdr:y&sa=X&ved=2ahUKEwi8qee-w5nzAhUTZt4KHQ0GBT8QpwV6BAgBECo&biw=1920&bih=1001&dpr=1
```

同じく`q=`で入力を指定していそうです。他にも色々とクエリストリングが付いています。

Amazonで「Rails」を検索して、並び替えをレビューの評価順にしたときのURLはこう。

```
https://www.amazon.co.jp/s?k=Rails&s=review-rank&__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&qid=1632552586&ref=sr_st_review-rank
```

`k=`はkeywordのkでしょうか。`s=`はsortのsっぽいです。

ほとんどのサイトの検索ページでは、検索文字列やソートやフィルタリングなどのパラメーターをURLのクエリストリングで指定しているんですね。

これらを一元管理できたら滅茶苦茶捗りそう...!

ということで、検索サイトのクエリストリングを検索できるサービスを作りました!!

https://searchsearch.net/search

## サービス紹介

こんな感じの画面です。

サイトごとに利用できるクエリストリングを確認できて、検索用のURLを構築することができます。

まずはパスの検索画面。無限スクロールかつインクリメンタルサーチです。

![search.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694808/ed8ec038-e706-53e4-d9b9-932a20854743.png)

パスの画面。ユーザーの入力を元にURLが組み立てられていきます。

![path.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694808/cd674f0d-4e65-a929-41ca-bbe838e101c5.png)

リンクを押したらQiitaの検索ページへ。クエリストリングが検索結果へ反映されています。

![jump.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694808/41d50755-8c2c-35ff-8f1a-ddcf8ab1e3c8.png)

これでなんでも検索できる!

機能としては、

- URLの検索
- URLの登録
- クエリストリングの登録
- クエリストリングへのコメント
- クリップボードのURLのパース
- クエリストリングから検索用URLの構築
- ログイン機能

等を実装しました。

## 利用した技術

サーバーサイドにRailsを、フロントエンドにReactを使ったSPAです。

ほとんどのページはReactで作っていますが、Deviseが絡んでくるログイン系の画面だけはRailsから直接配信するようにしています。
ここの部分の切り替えについては、開発環境ではhttp-proxy-middlewareで、本番環境ではNginxのパスによるリバースプロキシを設けて実装しました。

サーバーサイドはAPIでのCSRF対策や、Railsのflashの消費周りが苦労しました。
フロントエンドは「ユーザーの入力 ↔ URLのパラメーターの更新 ↔ インクリメンタルサーチの発火」間の連動とかを頑張りました。
デザインまわりはMaterial UIを使ってラクしました。

開発環境はDockerとdocker-composeで構築。

本番環境でもDockerを使っていて、AWS ECS の Docker Compose for Amazon ECS を利用して構築しました。
これは去年の冬から利用可能になったAWSとDockerのサービスで、docker-compose.ymlファイルからAWSのリソースをよしなに作ってくれるサービスです。

[Docker ComposeによるAmazon ECS対応がGAに！コンテナをローカル環境と同じノリでECS環境で起動できるぞ！！ | DevelopersIO](https://dev.classmethod.jp/articles/docker-compose-for-amazon-ecs-now-available/)

実際、実質50行ほどのyamlファイルだけでインフラのほとんどが出来上がっていく様子はなんだか凄かったです。

![searchsearch.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694808/538477ff-c9ea-d335-921f-edf454f73c09.png)


利用した主要な技術を箇条書きするとこんな感じです。

- サーバーサイド
    - Ruby
        - 3.0✨
    - Rails
        - 6.1
        - Devise
- フロントエンド
    - React
        - React Router
        - Material UI
- インフラ
    - Nginx
    - Docker
    - docker-compose
    - AWS
        - ECS
            - Docker Compose for Amazon ECS✨
        - RDS
        - Route53

フレームワークやライブラリは積極的に活用するようにしたつもりです。


# おわりに

リポジトリはこちらです。

https://github.com/tetetratra/searchsearch

searchsearch.net自体の検索オプションを増やしたかったり、お気に入り機能を実装したかったり、テストを書けていなかったり、せっかくRuby3.0なんだから型定義も書いてみたかったり、、、今後やっていきたいなと思っています。

最後に再掲。普段利用しているサイトを登録してみたり、いつもとは違う検索オプションでいつものサイトを検索してみたり。ぜひ使ってみてください！

https://searchsearch.net/search
Bloggerでリンクカードを表示する方法

## Bloggerでリンクカードを表示する方法

BloggerでQiitaのようにリンクカードを表示する方法を調べた。



## リンクカード表示方法

- 下記のコードをコピーして、BloggerのエディタにHTMLとしてペーストします。

- 〇〇〇〇〇をリンク先のURLに変更します。

```html
<iframe class="hatenablogcard" style="display:block;width:100%;height:155px;margin:12px 0;
max-width:680px;" title="%title%" src="https://hatenablog-parts.com/embed?
url=〇〇〇〇〇" frameborder="0" scrolling="no"></iframe>
```



![blogger_editor_001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1894918/379fc5e7-dc94-b8bd-13db-0dfeaf91fb1f.png)





## 表示結果

表示結果は下記のようになります。

![blogger_preview_001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1894918/29b48167-5ae3-50d1-122c-ceac80573507.png)



## Qiitaでのリンクカード表示方法

ちなみにQiitaでのリンクカードの表示方法はもっと簡単です。

下記のようにリンクを書き込むだけです。



```html
（空行）
https://ti32blog.blogspot.com/2021/09/cvisual-studio-2022-preview.html
（空行）
```



**表示結果**

https://ti32blog.blogspot.com/2021/09/cvisual-studio-2022-preview.html



## 参考

[Blogger＊ブログカードを表示する簡単な方法](https://moca-memo.blogspot.com/2019/11/blogger-blogcard.html)

[@Qiita(Increments株式会社)様の記事](https://qiita.com/Qiita/items/c686397e4a0f4f11683d)
(テスト)デプロイした後の更新の流れ

<h2>テストデプロイした後に色々更新していよいよデプロイ！</h2>
<p>なにするかわからない泣</p>
<p>cloud9上では動く(ほぼ完成)のでgit hubにpushしてec2の仮想サーバに移って、git hubからpullしてくればipアドレスで見ることができるそう</p>
<p>今触っているcloud9と仮想のパソコンEC2の考えが理解していなかった私</p>


<h2>cloud9 でEC"に接続する</h2>

```
username:~/environment $ ssh -i ~/.ssh/practice-aws.pem ec2-user@xx.xx.xx.xx

　　　xx.xx.xx.xxはパブリックIPアドレス
```
<h2>gut hubからpullしてくる</h2>
```
[ec2-user@ip-xx.xx.xx.xx ]　cd アプリ名
[ec2-user@ip-xx.xx.xx.xxアプリ名]　git pull 〜
```

```:gemの変更
[ec2-user@ip-xx-xx-xx-xx アプリ名]$ bundle install --path vendor/bundle --without test development
```

```:java/cssの変更
[ec2-user@ip-xx-xx-xx-xx アプリ名]$ bundle exec rails assets:precompile RAILS_ENV=production
```
```:migrationの変更
[ec2-user@ip-xx-xx-xx-xx アプリ名]$ bundle exec rails db:migrate RAILS_ENV=production
```

```:データリセットしたいとき
[ec2-user@ip-xx-xx-xx-xx アプリ名]$ RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1 bundle exec rails db:drop
```
<h2>pumaを停止する</h2>
```
[ec2-user@ip-xx-xx-xx-xx アプリ名]$ kill $(cat tmp/pids/puma.pid)
```
<h2>nginxウェブサーバーを再起動する</h2>
```
[ec2-user@ip-xx-xx-xx-xx アプリ名]$ sudo systemctl restart nginx
```

<h2>アプリケーションサーバーpumaを起動する</h2>
```
[ec2-user@ip-xx-xx-xx-xx アプリ名]$  rails s -e production
```




<h2>上の前に、Pumaの自動起動を設定しておく必要がある</h2>
CompTIA CASP+受験記

#CompTIA CASP+とは
CompTIA CASP+（CompTIA Advanced Security Practitioner）は、CompTIAが提供している以下のセキュリティ資格のうち、最上位の資格です。
（上にあるほど難しく、CySA+とPentest+は同レベル）

* CompTIA Acvanced Security Practitioner
* CompTIA CySA+  |  CompTIA PenTest+
* CompTIA Security+

無事に合格したので後進のために勉強法などを記載します。

CASP+では、最大90問出題され、165分以内に回答します。
詳細は公式サイトをご確認ください。

https://www.comptia.jp/certif/cybersecurity/comptia_casp/

#事前調査
以下の過去記事でも書いている通り、受験する試験の事前調査は非常に重要です。

https://qiita.com/log0417/items/f76eaf0fe947ba10a898

CompTIA CASP+はググっても合格した人の受験記がなく、一部Twitterで合格報告が見られるのみという状況です。
また、試験対策として公式サイトに記載があるのは以下の2つのみです。
１．オンラインまたはオンサイトトレーニングを受講（約23万円かかる）
２．以下から公式テキストを購入する（約25,000円）

https://jp-store.comptia.org/p/CAS-003-JPPP-20-C

さすがに20万円以上するトレーニングを個人で負担することはできないので、公式テキストを購入しました。

#勉強方法
公式テキストを一通り読みました。が、このテキストはあまり出来が良いとは思えません。全体的に読みづらく、英語を直訳しているように思います。
一応頑張って一読したものの、どこまで理解できたかは怪しかったです。

とはいえ、これ以外の勉強法はないようでしたので、このまま受験することにしました。

#試験当日
他の試験と同様に複数の選択肢から選ぶ問題がほとんどです。CompTIAの試験には、これに加えてパフォーマンスベーステスト（シミュレーション問題）があります。私は1問1問じっくり解くことにしました。そのため他の試験よりも時間がかかり、2時間15分ほどかけて解答と見直しを行いました。
試験の内容については一切記載できませんが、勉強の参考になる情報を記載します。

* 公式テキストに書かれている用語は一通り理解しないと解答は難しいと思います。
* 公式サイトにある以下の類似問題が非常に参考になると思います。この類似問題のように、何か状況が与えられて、それに対して適切なものを選択する問題が出ます。つまり、テキスト丸暗記では合格できません。

https://www.comptia.jp/training/samplequestion/comptia_casp/caspcomptia_advanced_security_practitioner.html

* 公式サイトにある出題範囲も目を通すと良いと思います。ここに出てくる単語は理解した方が良いです。

https://www.comptia.jp/pdf/casp_cas-003_objectives_ja.pdf

* 難易度としては、CISSPほどではないものの、CISSPに匹敵する難易度だと感じました。技術的な知見が少ない人には相当難しいと思います。情報処理安全確保試験士、SSCPより難しいと思います。公式には5年以上のセキュリティ経験者を対象にしているとありますが、必要とされる知識の広さに加えて、技術的に細かい点が問われることもあり、それ以上の経験が必要そうです。

#点数について
CASPは合否に関わらず、点数は公開されません。合否のみが表示され、誤答した項目がレポートに記載されます。
[公式の出題範囲](https://www.comptia.jp/pdf/casp_cas-003_objectives_ja.pdf)にあるとおり、1.0～5.0の大項目が5つあり、それぞれに3～5つの小項目が設定されています。
例えば1.1は「ビジネスおよび業界の影響やそれに関連するセキュリティリスクの概要を要約することができる。」です。これが小項目1つになります。この小項目を合計すると、19項目あります。

私が合格した際の不正解があった項目の数は、16でした。つまり、全問正解できた項目は3つしかなく、結構ギリギリだったのかもしれません。
逆にいうと、不合格だった場合は、レポートに書かれている項目の数を数えても意味はありません。自分の苦手分野を把握するために使ったほうが良いと思います。

#CISSP VS CASP+
ISC2が以下のような記事を出していますが、まさにここに書かれているとおりで、CISSPはマネジメント、CASP+は実務者向けです。
CASP+は、CISSP以上の技術力が要求され、その範囲もペネトレーションテスト、フォレンジック、ネットワーク機器の設定に至るまで幅広いです。

https://www.isc2.org/Articles/CISSP-versus-the-CASP-Certification

CompTIAも似たような内容の記事を出しています。コストが低いというのはそのとおりですね。下位資格が同時に更新されるというのもありがたいです。パフォーマンス試験については、私が受験した時は出題数が少なく、ちょっと微妙かなぁという気がしています。5問くらいあった方が良い気がしました。

https://www.comptia.org/blog/casp-vs-cissp

#今後受験する方へ
CompTIAの日本支部サイトには記載がありませんが、米国本部のサイトにはCASP+が新しくなるという情報があります。
これによれば、2021年10月6日から新試験であるCAS-004が開始され、私が受験した現行試験CAS-003は2022年2月で終了するとのことです。
日本語の試験も同時期に終了することが予想されるので、受験する方は対策本がある今のうちに受験した方が良いかもしれません。

https://www.comptia.org/certifications/comptia-advanced-security-practitioner

#試験を終えた感想
さすがに問題集がないというのはあまりに辛いので、ぜひ公式から出してほしいと思います。
ただ試験問題は良くできており、おかしな和訳、表現はなく、正しく判断できれば正解できる問題ばかりで、受験者の知識と経験が問われる良問がそろっていたと思います。これまで様々なセキュリティ資格を受験してきましたが、CASP+の問題は本当に良問だと思いました。問題作成者および翻訳された方に感謝したいと思います。
これでCompTIAのセキュリティ資格は完全制覇しました。CASP+の取得により、CompTIA Stackable CertificationのCSAE、CSIEも同時取得です。

#次の目標

次はFOR572のトレーニングを受けられることになったので、GNFAを受験予定です。GIAC三冠を目指して頑張ります。
【Node.js】Google Map検索を自動化してみた。

Google Map に存在するデータを検索用のキーワードで検索して、取得結果を一覧化するツールを作ってみました。

例えば
Google Map で 
渋谷 マッサージ
道玄坂 マッサージ
恵比寿 マッサージ
代々木 マッサージ
といったキーワードでお店を検索し、検索結果を一覧化する作業を行っていたとしたら
とてもピッタリなツールではないかと思います。


## 作成の背景
今月から入社したスタートアップの出来立ての事業でWeb広告に関する営業をまずはテレアポで行うことになったのですが、
私がチームに入るまでリストの作成を手で行っていたので、自動化を試みました。

最初はPythonかGASとかでスクレイピングがいいのかなと思っていましたが、
Google Maps Platform を使えば一瞬でできました。✌

## 想定ユーザー
* GoogleMap検索で取得した結果から営業先リストを作っている方。

ですが、そのほかにもこんな要望がある方にも使っていただけるツールです。

* Google Map のレビューの高いお店から明日のディナー先を決めたい方
奥さんが明日のディナー先を探していたので、「場所　食べたいもの」で検索してあげたら、100件近く情報を取得できてしまい、結局選びづらいという実績を得ました。でも、まあ、工夫次第で改良は可能だと感じました。

## 事前準備
* Node.jsがインストール済みであること
* Google Cloud Platform（GCP） のアカウントを持っていること
* GCPのアカウントはクレジットカード情報を登録して、課金可能になっていること
　※お金がかかるわけではありません。かからないように予算を設定すれば大丈夫です
* [Places API](https://console.cloud.google.com/apis/library/places-backend.googleapis.com?pli=1)が有効化されていること
* GCPからAPIキーを発行済みであること

## ソースコード
こちらにあります → [Github map-api-create-sales-list-in-nodejs](https://github.com/paths-are/map-api-create-sales-list-in-nodejs)


## インストール
上記リポジトリのreadme.mdにも書いていますが、次のコマンドを実行していきます。

```shell
git clone https://github.com/paths-are/map-api-create-sales-list-in-nodejs.git
cd map-api-create-sales-list-in-nodejs
npm install
cp .env.sample .env
cp search-areas_sample.txt search-areas.txt
cp search-keywords_sample.txt search-keywords.txt
cp search-filters_sample.txt search-filters.txt
mkdir search_result

```

`.env` の **API_KEY** には、ＧＣＰで取得したご自身のＡＰＩキーを設定してください。

## サンプルコードを実行
API_KEYを設定すれば動く状態になっていますので、実行してみます。

```shell
node .
```

正常に実行されると、 検索結果は `./search_result/yyyymmdd_hhmmss` フォルダ配下に出力されます。
出力された `search-result.tsv` をGoogleSpreadSheetに貼り付けてみてください。
こんな感じで出力されるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640981/07ccc36d-4d8a-b926-e3b3-f8808353dacc.png)

## カスタマイズ
上記のサンプル検索では
「浅草 ハンバーグ」で検索されたお店一覧から住所に「浅草」が入っているお店だけを表示しています。
なぜ住所でフィルタを行うかといいますと、そうしないと、浅草以外の情報も取れてしまうからです。
（浅草で検索してるのに、遠方の情報が出てきてもだるいのでこの処理を入れました。）

例えば「浅草 ハンバーグ」「浅草 カレー」「浅草 焼肉」で検索をしたい場合は下記のように `search-*.txt` を用意します。

```txt:search-areas.txt
浅草
```

```txt:search-keywords.txt
ハンバーグ
カレー
焼肉
```
そして `node .` を実行すれば、浅草のハンバーグ、カレー、焼肉店の一覧をとってこれるわけです。


以上！また続きを書くかもです！
GitHub Actions

githubuのリポジトリ画面「Settings」をクリックする
＞＞「option」の「Secrets」をクリック
＞＞「New Secret」をクリックする


![スクリーンショット 2021-09-25 21.21.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1801328/f70eaffd-776e-13c7-4e38-33b0f413144e.png)

３つ設定していく
HOST_NAME : EC2のパブリックIPアドレス
USER_NAME：ec2-user
PRIVATE_KEY：EC2上かCloud9上の~/.ssh/id_rsaの値

<p>IPv4 アドレスをEC２からコピーして</p>
```
Name内に--------------------------------------------
　HOST_NAME                                        |
---------------------------------------------------
Value内に--------------------------------------------
パブリック IPv4 アドレスをEC２からコピーして貼り付ける　　|
------------------------------------------------------
````
```
Name内に----------
　USER_NAME       |
------------------
Value内に----------------
ec2-user　            　|
------------------------
```
<p>コマンドをうってsshをコピーする</p>
```
$ cat ~/.ssh/id_rsa

-----BEGIN RSA PRIVATE KEY-----

:
:

-----END RSA PRIVATE KEY-----
```
```ruby:
以下を含めて~/.ssh/id_rsaの値をコピーする
-----BEGIN RSA PRIVATE KEY-----

:
:

-----END RSA PRIVATE KEY-----
```
```
Name内に----------
　PRIVATE_KEY       |
------------------
Value内に----------------
~/.ssh/id_rsaの値  をコピーして貼り付ける      　|
------------------------
```
![スクリーンショット 2021-09-25 21.32.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1801328/c3623d5c-ea13-5935-0645-8beedff57e4f.png)

<h2>ワークフローを作る</h2>

https://docs.github.com/ja/actions/reference/workflow-syntax-for-github-actions

<p>GitHub Actionsのワークフローのファイル形式はYAML,拡張子は「.yml」</p>
<p>ワークフローではpushやpull request時に行いたいことを設定</p>
<p>アプリケーションルート下におく</p>


<h2>公開鍵をec2サーバーに用意　Cloud9上から公開鍵を転送する</h2>
```
Cloud9側で$ scp -i ~/.ssh/practice-aws.pem ~/.ssh/id_rsa.pub ec2-user@ipアドレス:.ssh/id_rsa.pub
```
<p>EC2サーバーで</p>
```
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
```

<h2>Cloud9環境から、変更をリモートリポジトリにpushする</h2>
ABC87 C - Candies を解いた

https://atcoder.jp/contests/abc087/tasks/arc090_a

![abc87_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/a3459136-fda0-f524-6563-46907ece9bdc.png)
![abc87_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/0f62f3c5-3541-24b8-7946-2e33827fffa4.png)
![abc87_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/14538b59-5133-25a7-7a66-71c086f86f4d.png)
![abc87_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/5bca10dc-4cad-00c5-c7c2-22289a80ff80.png)
![abc87_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/9668ddd0-c1b1-07f4-f013-90a4d83e4e08.png)

全探索でよいのでは？

```Candies.py
N = int(input())
A = [list(map(int,input().split())) for _ in range(2)]

ans = 0
for i in range(N):
    score = 0
    for j in range(N):
        if j == i:
            score += A[0][j]
            score += A[1][j]
        elif j < i:
            score += A[0][j]
        elif j > i:
            score += A[1][j]
    ans = max(ans,score)

print(ans)
```

一応通った
テスト項目観点

# はじめに
テスト項目の観点をメモ書き。
簡単なものしか載っていません。
追加していきたいと思います。


# リンク
・正常にリンクされているか。
・404になっている箇所が無いか。


# ユーザーが入力するページ
（お問い合わせフォームなど）
・入力されていない場合、入力されていない旨を示すエラーが表示されているか。
・確認ボタンを押して確認画面へ行くか。正常な動きをするか。
・電話番号が数字と-のみが入力出来るか。記号、英語など入れてエラーが正常に出るか。
・メールアドレスに@を付けない場合、エラーになるか。
・エラーメッセージが正しい言語で表示されているか。（日本語ページであれば、日本語。英語ページであれば英語。）
・メールアドレスを入力すると、正常にメールは飛ぶか。


# 検索
・検索されたキーワードが正しく表示されるか。
・大量の文字が入らないようになっているか。
・検索された結果について、値段が安い順、高い順が正常に並んでいるか。


# カートに入れる画面
・個数は正常範囲内の数字で入力することが可能か。
（案件により異なる。）
・- マイナス値は入力が出来ないようになっているか。また、購入出来ないようになっているか。


# 決済画面
・購入出来るか。購入されましたの画面が表示されるか。
・ブラウザを戻っても、カゴにある情報が消えないか。
・会員でログインした場合で、購入画面まで行き、その状態で、会員をログアウトすると、そのまま進行しないようになっているか。


# 画面を横向きにする。
・正常に並ぶか。
・位置に崩れは無いか。
・画像など、明らかな大きさ違いは無いか。
・ボタンは正常に表示されるか。
・文字と重なる箇所は無いか。


# メール
・正常に送られているか。
・送り先は合っているか。
・送り主は合っているか。
・文字化けしていないか。
・正しい言語で表示されているか。
・タイトルは正しく表示されているか。
・本文の内容に問題は無いか。
・表示場所に崩れは無いか。
・決済方法とメールの内容が合っているか。
・決済のURLが表示されるか。（表示されないものもある。）



# Lighthouse
・測定して、50点以下になっているところは無いか。



# 参考
https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk?hl=ja
Kubernetes完全ガイド 第2版 第2章まとめ

# なぜk8sが必要か

## 背景

近年、コンテナ技術への注目度が高まり、プロダクションでのコンテナ利用事例も増えてきた。

Dockerはコンテナランタイム(実行環境)であり、Dockerホストを複数台協調させて動作させたり、一元的に管理することはできない。

そのため、一定以上のプロダクションにおいて必要な、複数のホストから構成されるシステムの構築が難しい。

そこで、Kubernetes(k8s)の出番。
...コンテナオーケストレーションエンジン。コンテナ化されたアプリケーションのデプロイ、スケーリング、などの管理を自動化する。

## Kubernetesとは

Kubernetes(k8s)...コンテナオーケストレーションエンジン。コンテナ化されたアプリケーションのデプロイ、スケーリング、などの管理を自動化する。

コンテナオーケストレーションエンジン...k8s以外にも、Docker Swarm mode、Apache Mesosなどがある。k8sは2020年7月時点でプロダクション利用事例が最も多く、コンテナオーケストレーションにおけるデファクトスタンダードとなっている。(これは、大手クラウドプロバイダによるマネージドサービスの提供が大きな要因となっている、らしい)

コンテナ...「なんらかのアプリケーションを実行するようにビルドされたコンテナイメージを元に起動されたワークロード(仮想マシン上で実行されているソフトウェア)」

[ワークロードとは - IT用語辞典](https://e-words.jp/w/%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%AD%E3%83%BC%E3%83%89.html)

## k8sでできること

- 宣言的コードによる管理(Infrastructure as Code)…宣言的なコード(マニフェストファイル)によって、デプロイするコンテナや、周辺リソースの管理が可能。
- スケーリング/オートスケーリング
    - Kubernetesクラスタの形成による複数ホスト(Kubernetes Node)の管理
    - 同一コンテナイメージを元にした複数コンテナ(レプリカ)のデプロイによる負荷分散や耐障害性の確保
    - 負荷に応じたレプリカ数の増減
- スケジューリング…**PodをどのNodeに配置するかを決定すること**であり、デプロイ時のステップの一つである。Affinity, Anti-Affinity機能を用いることで、スケジューリングを調整可能。アプリケーションの特徴、Nodeの性能差などを意識することができ、例えば、ディスクI/Oが多いコンテナをディスクがSSD(I/O速度が速い)のNodeに配置する」といった制御が可能になる。
- リソース管理…スケジューリングの指定がない場合、Nodeのリソース状況(メモリ、CPUの空き状況)に従ってスケジューリングが行われる。そのため、ユーザーはコンテナ配置を管理する必要がない。また、リソース使用状況によって、自動でNodeの増減を行う、クラスタオートスケール機能も存在する。
- セルフヒーリング…コンテナのプロセス監視によって、停止を検知すると、再度コンテナのスケジューリングを実行することで、自動的にコンテナを再デプロイする。これにより、サービスの自動復旧ができる。また、セルフヒーリングの実行条件を変更することも可能。(HTTP/TCPや、シェルスクリプトによるヘルスチェックの成否)
- ロードバランシングとサービスディスカバリ...
    - 複数台で構成されたアプリケーションを１つのアプリケーションとしてユーザーに見せるためにはユーザーからの接続先となる、複数台を束ねたエンドポイントを用意する必要がある。(仮想マシン利用の際には、ロードバランサーを利用するのが一般的)k8sにも、同様のロードバランシング機能(Service, Ingress)があり、設定した条件に合致したコンテナ群へのルーティングを行うエンドポイントを払い出すことが可能である。さらに、k8sは、スケール時のエンドポイントとなるServiceへのコンテナの自動追加・削除、コンテナ障害時の切り離し、コンテナのローリングアップデート時の事前の切り離しなどを自動で実行してくれる。
    - サービスディスカバリ(サービスのネットワーク上の位置を決定すること)は、Serviceで実現可能。マイクロサービス同士で参照する必要がある時に、簡単にシステム全体を連携することができる。
- データ管理…データストアには、冗長化できるetcd(エトセディ)を使用。コンテナ間で共通の設定や、データベースのパスワードなどの情報、を安全かつ冗長化された状態でk8s上で管理できる。(コンテナや、Serviceに関するマニフェスト、コンテナが利用する設定ファイル、認証情報を保存する仕組みがある。)
    - etcd...分散型キーバリューストア。クラスタを組むことで冗長化できる、らしい。
    - 外部エコシステムとの連携が盛ん...今後の章でテーマ別に紹介される、らしい。
Rails6でJavaScriptを書く

# はじめに
初めてRuby on Railsを触ることになり、JavaScriptを使ってみることになった。
うまく動く資料が見当たらなかったため、備忘録として書いておくことにした。

# JavaScriptの実装
## JavaScriptの書く場所
app > javascript > packs
- file下に制作のファイルを作成するのがおすすめ
- 自分はusersというファイルを作成し、その下にjsファイルを作成した
## jsファイルに書くべきこと
- 読み込み時に表示

```js
window.onload = function(){
//中略
//ウィンドウが読み込まれたとき表示する
}
```
- 動作により呼び出す場合

```js:app>javascript>packs>user>common.js
window.onchange = function hogehoge(){
//中略
//自分はonchangeで呼び出しをしたためこのように記載した
}
```

##書いたjsを読み込ませる

```js:app>javascript>packs>application.js
import Rails from "@rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "@rails/activestorage"
import "channels"

Rails.start()
Turbolinks.start()
ActiveStorage.start()
// 追加した
require("./user/common.js")
```
##viewファイル

```erb:app>view>device>registrations>new.html.erb
<!--略-->
  <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
    <%= render "devise/shared/error_messages", resource: resource %>
<div class = "set">
    <div class = "side">
      <%= f.label :icon %>
<!--ファイルを選択したら呼び出し-->
      <%= f.file_field :icon, type:"file", autofocus: true, onchange: "previewImage()" %>
      <%= f.hidden_field :icon_cache %>
      <%= image_tag @user.icon.url,  id: 'preview' %>
      <label>
      <%= f.check_box :remove_icon %>
      画像を削除する
    　</label>
    </div>
<!--略-->
```
Arduino Dueの2ch DACを利用する

# はじめに
本記事はMATLAB Expo2021 LTでの発表「[MATLAB Homeでのモータ制御MBD開発に向けた“脱獄指南書”](https://speakerdeck.com/motorcontrolman/matlab-home-prison-break)」の解説をシリーズ化したものの最初の記事となります。
シリーズ構成案は下記。(完了時期：未定)

①Arduino Dueに３相同期・三角波・相補PWMを打たせる
[②Arduino DueでPWM山同期AD変換を行う](https://qiita.com/motorcontrolman/items/ba2cd0fb200501186194)
[番外編 実質無料! Tiの３相GaNインバータの使い方](https://qiita.com/motorcontrolman/items/95560fd38545637fad2a)
<b>③Arduino Dueの2ch DACを利用する</b>
④MATLAB/SimulinkでArduinoのレジスタを叩く
⑤MATLAB/SimulinkとArduino DueでPWM同期の制御を実現する

色々と試してみて分かった事ですが、<b>MATLAB Homeでコード生成を行った場合は[J-Scope](https://qiita.com/motorcontrolman/items/c1910c5a51fb29a700fd)のようなRAMスコープが使えません</b>。このためDACの利用はかなり重要なポイントとなるため、本記事にて解説を行うものとします。(といってもADCと比べると滅茶苦茶簡単ですが。)

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">MATLAB Homeのコード生成(Embedded Coder未使用)を突き詰めた結果、限界が見えてしまいました。<br>この子、J-Scopeに接続できない=デバッガが使えません。通常の方法で生成されたelfと明らかに挙動が違います、無念。<br>これはちょっと致命的だなぁ…。 <a href="https://t.co/3bhPSBbWWj">pic.twitter.com/3bhPSBbWWj</a></p>&mdash; モータ制御マン (@motorcontrolman) <a href="https://twitter.com/motorcontrolman/status/1439571789496008708?ref_src=twsrc%5Etfw">September 19, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 1. DACを有効化する

下記のソースコードをardinoの初期化関数に記述することでDACが有効化されます。
関数`dacInit`は著者が便宜上定義した関数であって、別に関数化する必要はありません。
ADCの設定と比べ、特に説明するところがないです。
寂しいですね


```c
void dacInit(){
  PMC->PMC_PCER1 = PMC_PCER1_PID38;   // DACC power ON

  DACC->DACC_CR = DACC_CR_SWRST ;    // Reset DACC

  DACC->DACC_MR =
    DACC_MR_TRGEN_DIS | // DACC in free running mode
    DACC_MR_WORD_HALF | // Half-Word transfer
    DACC_MR_TAG_EN;

  DACC->DACC_CHER = DACC_CHER_CH1 | DACC_CHER_CH0;
}
```

# 2. 信号をDACに出力する

下記となります。
関数`dacWrite`は著者が便宜上定義した関数であって、別に関数化する必要はありません。

```c
void dacWrite(uint16_t DAC0, uint16_t DAC1){
    DACC->DACC_CDR = (0 << 12) | DAC0;
    DACC->DACC_CDR = (1 << 12) | DAC1;
}
```

いちいち言う事でもないですが、Arduino DueのDACは12bitとなります。
このため上記関数の入力はuint16ですが、上位4bitは無視されますので注意下さい。

# 3. モータ制御における実際の使用方法

ここまでで終わってしまうと余りにも面白くないので実際の使用方法を記載します。
関数`dacWrite`を、[AD変換の割り込み関数内](https://qiita.com/motorcontrolman/items/ba2cd0fb200501186194)でコールして使います。
モータ制御ではAD変換をPWM山(谷)同期に設定していると思いますので、DACも同様の周期で更新されることなります。

要するに、こうじゃ！

```c
void ADC_Handler() {
  Iu_ad = ADC->ADC_CDR[7];  // Read and clear status register 
  //こいつを消すと動かなくなる。CH7の完了と同期しているから？

  Iv_ad = ADC->ADC_CDR[6];
  Iw_ad = ADC->ADC_CDR[5];

  dacWrite(Iv_ad, Iw_ad)

  PIOB->PIO_ODSR ^= PIO_ODSR_P27; //Lチカ用
}
```
# 参考
上記コードについて、gitの下記にも置いています。

https://github.com/motorcontrolman/motorcontrol/tree/master/Arduino_Due_Vector_Control/IO_LIB

DAC.cpp　と　DAC.hを参照下さい。

# おわりに
書くことがなさすぎて逆に困惑している。
VSCodeの正規表現検索で2つの文字列head_tail, tailの内tailだけを合致する方法

## TLDR
### OKな例
```
(?<!head_)tail
```
### NGな例 
```
[^_]tail
```

## 簡単な解説
head_tailとtailの二つの文字列があった場合、VSCodeの検索機能でtailだけを検索・置換したい。普通の検索では両方とも選んでしまうので、正規表現を用いる。
### OK
`(?<!□)`は否定的後読みであり、その中に書かれた文字列が前に来ると検索にかからないようになっている。この方法だと正常に`tail`を選択することができる。
### NG
`[]`は角かっこの中に含まれる文字のいずれか1文字に該当するものを選択する。したがって、`[^_]`は一文字として扱われるため、`[^_]tail`は`"tail`や`[tail`のように先頭に一文字余計に選択してしまうため、不適
## 参考リンク
https://qiita.com/souhei-etou/items/8b801279dfc711179a45
https://nymemo.com/phpcate/293/
【Python】slackのbotで遊んでみた

## 概要
pythonでslackのbotで応答する内容を設定する処理を作ってみました。

##前提条件
Pythonが既にインストールされていること。
slackのbot設定が完了していること。

##作成するファイル構成
今回作成するファイル構成は以下になります。

```
run.py
slackbot_settings.py
time_now.py
greeting.py
plugins（ディレクトリ）
└mode.py
```

##slackbotのインストール
コンソールを開いて下記のコマンドを実行する。

```
pip install slackbot
```

##run.pyの実装
run.pyはbotを起動する処理を書いてます。

内容は以下になります。

```py
# slackbot ライブラリのの呼び出し
from slackbot.bot import Bot

def main():
    # ボットを起動する。
    bot = Bot()
    bot.run()

if __name__ == "__main__":
    main()
```
<h2 class="title">slackbot_settings.pyの実装</h2>
slackbot_settings.pyはbotに関する設定を書いてます。

内容は以下になります。

```py
# APIトークンの設定
API_TOKEN = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'

# 定型コメント以外への返信コメント
DEFAULT_REPLY = "すみません。そのコメントはよくわかりません。"

# プラグインを追加する
PLUGINS = ['plugins']
```

## mode.pyの実装
mode.pyはbotの応答内容（プラグイン）の処理を書いてます。

内容は以下になります。

```py

#slackbot.botライブラリの呼び出し
#from slackbot.bot import respond_to
from slackbot.bot import listen_to
from slackbot.bot import default_reply
import greeting
import time_now

mode = 0

@listen_to(r'.*')
def listen_func(message):
    global mode
    msg = message.body['text']
    
    if mode == 1:
        greeting_txt = greeting.greet(msg)
        message.send(greeting_txt)
    if mode == 2:
        if msg ==  "いま何時？":
            time_txt = time_now.res_time(msg)
            # 現在時刻を返信する
            message.send(time_txt)

@default_reply()
def default(message):
    global mode
    msg = message.body['text']
    
    if msg ==  "挨拶モード":
        message.send('挨拶モードに変更しました。')
        mode = 1
    elif msg == '時間確認モード':
        message.send('時間確認モードに変更しました。')
        mode = 2
```

■import内容について
respond_toはメンション（@ユーザ名）でメッセージを送信した時に応答するもの（今回は使わないです）
listen_toはメッセージを送信した時に応答するもの
default_replyはメンションでメッセージを送信した時にrespond_toで設定した内容に当てはまらない場合に応答するもの
になります。
greetingとtime_nowはこの後説明するgreeting.pyとtime_now.pyのことです。

■処理内容

- `@default_reply()`について
`global mode`でmodeの変数をグローバル変数にして他の関数でも共通で使えるようにしてます。
`message.body['text']`でこちらが送信したメッセージの内容を取得してます。
「挨拶モード」とメンションで送るとmodeを1に、「時間確認モード」とメンションで送るとmodeを2にしてます。

- `@listen_to(r'.*')について
`正規表現ですべてのメッセージ内容に反応するようにしてます。
modeの値によって呼び出す処理を変えています。

## greeting.pyの実装
挨拶モードで呼び出す処理を書いてます。

内容は以下になります。

```py
def greet(message):

    if message == "おはよう":
        msg = message + '。今日も良い1日を!'
    elif message == "こんにちは":
        msg = message + '。'
    elif message == "こんばんは":
        msg = message + '。良い一日は過ごせましたか？'
    else:
       msg = '挨拶をしてください。'
    
    return msg
```

「おはよう」とメッセージが送られた場合は「おはよう。今日も良い一日を！」
「こんにちは」とメッセージが送られた場合は「こんにちは。」
「こんばんは」とメッセージが送られた場合は「こんばんは。良い一日は過ごせましたか？」
それ以外は「挨拶をしてください。」という文言が戻り値となります。

## time_now.pyの実装
時間確認モードで呼び出す処理を書いてます。

内容は以下になります。

```py
# 時刻を管理するライブラリの呼び出し
import datetime

def res_time(message):
    dt_now = datetime.datetime.now()
    # 現在時刻を返信する文字列に変換する
    time_str = dt_now.strftime('%H時%M分だ。')
    return time_str
```

現在時刻を返信する文言が戻り値となります。

## 実行結果

実行した結果は以下のようになります。（run.pyを実行する）
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2056482/e6619c8b-5b32-aedd-0d0a-9bcaed145a6d.png)
ABC93 C - Same Integers から学んだ

https://atcoder.jp/contests/abc093/tasks/arc094_a

![abc93_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/90d864d1-5a18-55b8-fd44-2b4bb5bbcecd.png)
![abc93_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/eb450237-8f77-b5ac-6c08-57fb8eef2368.png)
![abc93_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/3bcfe891-faa0-be79-97ab-3ce0e37028ab.png)

うーん。さっぱりや。
たまらず、解説ページを開く

https://www.youtube.com/watch?v=HDRfgn_UXLE

説明を聞いて分かったつもりに
なっている気がした。

ちょっとボーっとしてから
思い出しつつ書いてみた。

```SameIntegers.py
a,b,c = map(int,input().split())

m = max(a,b,c)

for i in range(100):
    x = m + i
    if (3*x-(a+b+c))%2 == 0:
        ans = (3*x-(a+b+c))//2
        break
print(ans)
```

***
あれから、真っ新な状態で再チャレンジ。
一応通った。

```abc93c.py
A,B,C = map(int,input().split())
X = [A,B,C]

#方針#
#いずれのアクションも 2 ずつ増えている。
#ってことは、3で割り切れるまで 2 を足した回数が答えでは???
for i in range(10**5):
    if (sum(X) + 2*i)%3 == 0:
        if (sum(X) + 2*i)//3 >= max(X):#但し、3で割った時の値が A,B,C 最大値より小さいとダメ
            print(i)                   #同じ、もしくは max(A,B,C) より大きい必要がある
            exit()
```
Githubにpush時に毎回ユーザ名とパスワード聞かれないようにする

Githubにpushすると、毎回のようにユーザ名とパスワード聞かれるようになっています。

```shell
> D:\sample_project> git push origin master
> Username for 'https://github.com':
```

現在のURLを確認すると以下のようになっています。

```shell
> D:\sample_project> git remote -v
> origin  https://github.com/ユーザ名/リポジトリ名.git (fetch)
> origin  https://github.com/ユーザ名/リポジトリ名.git (push)
```

URLに__ユーザ名とアクセストークン__を追加すれば、問題解決できました。

```shell
> D:\sample_project> git remote set-url origin https://ユーザ名:アクセストークン@github.com/ユーザ名/リポジトリ名.git/
> D:\sample_project> git remote -v
> origin  https://ユーザ名:アクセストークン@github.com/ユーザ名/リポジトリ名.git/ (fetch)
> origin  https://ユーザ名:アクセストークン@github.com/ユーザ名/リポジトリ名.git/ (push)
```

ちなみにGithubのアクセストークンは、__Githubサイト右上の自分のアイコン -> Settings -> Developer Settings -> Personal access tokens__で生成できます。
Andorid 12でカスタム通知を使うときはsetCustomBigContentViewも設定するのを忘れない

Android 12の正式リリースはまだですが、先走ってtargetSdk 31対応をして公式ドキュメントをちゃんと読まずに失敗したので注意喚起
Android 12でtargetSdkを31にするとカスタム通知に関する挙動が変更されます。

https://developer.android.com/about/versions/12/behavior-changes-12?hl=ja#custom-notifications

Android 12でもtargetSdkが31未満の場合、以下のように`setCustomContentView`で設定したRemoteViewsが通知全体に表示されます。妙に角のRが大きい問題がありますが、角部分に重要な情報を配置していなければそれほど問題は無いでしょう。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/6ae2ef96-50c9-1777-d7ca-378e7eb67c72.png)

しかし、targetSdkを31にすると以下のように通知の中の一部にのみにRemoteViewsが表示されるようになります。targetSdkはいずれ上げないといけないので、この制約の中で適切な表現を考える必要がありますね。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/9d89e9d8-01b2-6a5d-469a-a9bf277cefa7.png)

> Android 12 をターゲットとするアプリでは、すべての通知を展開できます。そのため、`setCustomContentView` を使用している場合、通常は `setBigCustomContentView` も使用して、折りたたまれた状態と展開された状態に一貫性を持たせる必要があります。

はい、Android 12ではすべての通知が展開されてしまうため、`setBigCustomContentView` を設定していないと、展開したときに表示されるものがなくなってしまいます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/80afa937-7035-a4f3-8f0c-7727d8dca123.png)

展開させたくなくても展開されてしまうので、 `setBigCustomContentView` でRemoteViewsを設定しておく必要があります、 `setCustomContentView` に指定したものと同じRemoteViewsで問題無いです。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155171/e56c0919-1601-8783-e12a-2ad44f1e7932.png)

なお、DecoratedCustomViewStyleを指定した場合も同様の効果がありますが、Android 12未満でも展開できるカスタム通知を作るためのものですね。
せっかく展開することが強制されるので、展開されたときはよりリッチなUIを提供して、Android 12未満と同様の挙動にさせたい場合はこれを使うのが良いですね。

以上です
Onenoteをmarkdown形式でエクスポートする

2025年にストアアプリ版のサポートが終わるらしいOneNoteユーザーの皆様、いかがお過ごしでしょうか。

OneNoteはとても良くできたツールですが、プログラムコードのシンタックスハイライト機能もなく、かといってペンツールや音声読み上げは使い所が分からない。
帯に短し襷に長しというツールであります。

今回、6年使用したOneNoteから移行する決心を固めたところ、markdownにエクスポートするツールを知ったのでその使い方を記事にします。

## 変換ツールと必要アプリのインストール

Powershellスクリプトです。OneNote側で1ページ1docxに変換したあとpandocでmarkdownに変換しています。

githubからDLします。

https://github.com/leojonathanoh/ConvertOneNote2MarkDown-v2

pandocをインストールします。Chocolateyを使いました。

https://chocolatey.org/

OneNote 2016をインストールします。アプリストア版では使えません。

https://www.onenote.com/Download?omkt=ja-JP

OneStaticをインストールします。閉じたセグメントはエクスポートの対象にならないので、全て開くスクリプトを使うためです。

https://getonetastic.com

### 設定

DLしたら`ps1`スクリプトをエディターで開き、該当箇所を編集します。
スクリプトを**UTF-16LEで保存**することで日本語名のノートブックも指定可能になります。

- `$targetNotebook = ''`: ノートブックの名前。指定なしで全ノートブック対象
- `$usedocx = 2`: 2に設定すると既存のdocxを使って変換するようになる。はじめから2を指定する
- `$keepdocx = 2`: 2でdocxを削除しない。usedocxで使い回すので2
- `$prefixFolders = 2`: サブページは「Page_Subpage.md」のようにprefixesをつけて保存する
- `$medialocation = 1`: 1なら画像はノートブックごとのルートのmediaフォルダにまとめる。2ならページごとに作る。あとで全て同じフォルダにノートを移動する予定なら2

**markdownの変換設定**

 ```powershell
 # Specify the conversion type
 # 1: markdown (Pandoc) - Default
 # 2: commonmark (CommonMark Markdown)
 # 3: gfm (GitHub-Flavored Markdown)
 # 4: markdown_mmd (MultiMarkdown)
 # 5: markdown_phpextra (PHP Markdown Extra)
 # 6: markdown_strict (original unextended Markdown)
 $conversion = 1
 ```

標準はpandoc。ここは色々試してみましょう。

## 実行手順

1. 全ての閉じているセグメントを開きます。
   付属の `Expand all Paragraphs in NoteBook.xml` をonentoe 2016のアドオン `OneStatic` に読み込んで使用します。要インストール。
2. OneNote 2016を管理者権限で開きます。
3. PowerShellを管理者権限で開きます。（私の環境ではこの作業が必須でした）
4. Powershellで`ConvertOneNote2MarkDown-v2`を実行する。
5. 初回はdocxに変換するのでかなり時間がかかります。変換終わるまでお茶でも淹れてデスクから離れよう。

出来上がったmarkdownを見て、気に入らなかったら「markdownの変換設定」を色々変更して試してみましょう。

## 変換後

markdown形式に変換されていますが、OneNote側でペンツールを使ったところは全てペンが画像に変換されています。ほぼ使い物になりません。

テーブルは凝ったことをしていなければだいたい変換できています。

画像はサイズ指定のタグがついていたり、imgeタグになっていたりします。ここはpadocのmarkdownのtype設定によって異なります。

## markdown管理ソフト

変換したmarkdownを管理・編集するソフトです。いろいろあります。

- [Joplin](https://joplinapp.org/)
- [Obsidian](https://obsidian.md/)
- [Visual Studio Code](https://code.visualstudio.com/)

私はVisual Studio Codeにしています。正規表現による一括置換が出来るし使い慣れたエディターなので。足りないところは拡張機能を使って補完しています。vs codeでmarkdownを編集する環境が整ったら記事にするつもりです。

## おわりに

この記事を書いている段階で2週間近くOneNoteを立ち上げていません。6年という長いあいだ使い続けてきました。ありがとうOneNote。
Rails: assets pipelineでrequire_tree . から特定のファイルを除く

プロジェクトの開始時に、app/assets/styleseets下のapplication.cssに、深く考えずに`require_tree .`と書くと、あとで「しまった、ディレクトリ分けしておけばよかった」となります。

```app/assets/styleseets/application.css
/*
 *= require font-awesome
 *= require_tree .
 *= require_self
 */
```

こう書けば、CSSの使い分けができたのに。

```app/assets/styleseets/application.css
/*
 *= require_tree ./main
 */
```

```app/assets/styleseets/admin.css
/*
 *= require_tree ./admin
 */
```

```config/initializers/assets.rb
Rails.application.config.assets.precompile += %w( admin.css )
```

しかし、プロジェクト開始から時間が経ち、styleseetsディレクトリがごちゃごちゃで手を付けられない状態です。

そんなときは、[Sprocketsの機能stub](https://github.com/rails/sprockets#stub)を使います。これで、application.cssからadmin.cssおよびadmin.cssがrequireしているCSS（adminディレクトリ下のCSS）が除外されます。

```app/assets/styleseets/application.css
/*
 *= require font-awesome
 *= require_tree .
 *= require_self
 *= stub ./admin
 */
```

```app/assets/styleseets/admin.css
/*
 *= require_tree ./admin
 */
```

注意する点は、admin.cssおよびadmin.cssがrequireしているCSSに、application.cssで使っているものが含まれると、それも除かれることです。次の例では、application.cssからfont-awesomeが消えます。

```app/assets/styleseets/admin/admin.css
/*
 *= require font-awesome
*/
```

application.cssとadmin.cssでCSSを共有したいときは、拡張子をscssにして`@import`を使います。

```app/assets/styleseets/admin/admin.scss
@import 'font-awesome';
```
【HTML】ツイッター、Googleマップ…等、埋め込み用リンク

# Twitter
[Twitter埋め込みタイムラインウィジェット](https://publish.twitter.com/#)

# Facebook
[Facebookページプラグイン](https://developers.facebook.com/docs/plugins/page-plugin)

# Google Map
[Google Mapコード生成ツール](https://demo.techacademy.jp/webdesign/gmg-new/?_ga=2.183344294.1078906696.1632538769-1633560989.1627637491)

## 方法１：
APIキーの取得が必要（[Google Cloud Platform](https://console.cloud.google.com/home/dashboard?project=api-pro-219905&pli=1)から取得する：「Maps JavaScript API」）

> [API キーを保護する](https://cloud.google.com/docs/authentication/api-keys?hl=ja#securing_an_api_key)
API キーをコードに直接埋め込まないでください。コードに埋め込まれた API キーは、誤って公開されてしまう可能性があります。たとえば、共有するコードからキーを削除し忘れた場合などです。API キーはアプリケーションに埋め込む代わりに、アプリケーションのソースツリー外部にある環境変数やファイル内に保存します。

[Google Maps API キーをHTMLから隠す方法](https://qiita.com/olto3/items/8ade80567d404e0a803a)

[Google Maps APIキーを取得後にまずやっておきたいセキュリティ設定について解説]
(https://torisky.com/google-maps-api%E3%82%92%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B%E5%89%8D%E3%81%AB%E8%A8%AD%E5%AE%9A%E3%81%97%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F%E3%81%84%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86/)


## 方法２：Google Mapからコード取得
[【HTML】Google Mapの埋め込み](https://qiita.com/smkhkc/items/c3607797b5233c8d0edb)
数理計画（python②）

いろいろ見てると、python-lulp  ではなく　python-MIP　の方が良いとの記述を見かけたので調べてみた。

python3.8(32) では使用できないようなので思い切って、python3.8(64)に入れ替えてました。ついでに、VSCに変更しました。

```sample.py
# coding: UTF-8
import sys

def GenPlan():
    try:
        Output = [100, 150, 0, 300, 0, 400, 200]
        Before = 200
        After = 100
        MaxGen = 300
        MinGen = 0
        MAXHld = 500

        #　最適計算
        from mip import Model, minimize, xsum, INTEGER, OptimizationStatus

        problem = Model()

        #製造量
        make = [problem.add_var('make%d'%i, lb = MinGen, ub = MaxGen,  var_type=INTEGER)  for i in range(0,7,1)]
        hold = [problem.add_var('hold%d'%i, lb = 0, ub = MAXHld,  var_type=INTEGER)  for i in range(0,7,1)]

        #目的関数
        problem.objective = minimize(xsum(make))

        #等式制約
        problem += Before + make[0] - Output[0] - hold[0] == 0
        for i in range(1,7,1):
            problem += hold[i-1] + make[i] - Output[i] - hold[i] == 0

        #不等式制約
        for i in range(0,6,1):
            problem += hold[i] >= Output[i+1]
        problem += hold[6] >= After

        problem.optimize()
        print(problem.status == OptimizationStatus.OPTIMAL)
        print(problem.objective_value)
        print([int(problem.vars['hold%d'%i].x)  for i in range(0,7,1)])
        print([int(problem.vars['make%d'%i].x)  for i in range(0,7,1)])

    except:
        print(__name__)
# main
if __name__ == "__main__":
    GenPlan()

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314982/127b5a40-dfa7-9c65-a2a9-012dee164cb9.png)


上側が貯蔵量、下側が製造量

Lulpの場合と最小値は同じですが、説明変数の値が異なることが分かります。
ネットワーク構成

#はじめに
Webシステムの構築は、どういった構成にするのかから始まる。
Webシステムはネットワーク機器やサーバーといった機器と、それらをつなぐネットワークから成り立つ。
Webシステムの用途や要求されるセキュリティレベル、投入できるコストなどによって構成が異なり、最初にネットワークの構成を検討することから始まる。

#ネットワークの分割
Webシステムを構成するネットワークは大きく三種類に分割できる。
①外部ネットワーク
②内部ネットワーク
③DMS

__外部ネットワーク__
組織のメンバーに加え、組織外のメンバー（パートナー、クライアント、）をネットワークに追加して共同作業ができる状態。

__内部ネットワーク__
組織内のメンバーのやりとりが基本。

__DMS__
外部ネットワークと内部ネットワークの境界であり、外部ネットワーク及び内部ネットワーク両方からのアクセスを受けつつ、不正な通信を防ぐ内部ネットワークの通信を最低限とするDMS(DeMilitarized Zone)

#ネットワーク機器の構成
インターネットからの接続があるシステムにおいては、攻撃を防ぐにはファイアーウォールが必須となる。
IDS,IPS,WAFは高価であるので求められるセキュリティ要件によっては導入しないこともある。
金融に関わるシステムなどは攻撃を受けた際に被害が多くなるため、コストを増加させてWAFを導入し策を講じるのが良い。

https://qiita.com/kinoshitaken123/items/6d8750920583f090076c
メソッドチェーンでかけるModifireのデータ構造はどうなっているか

Modifireはたくさんつなげてかけると思うのですが、どうなっているんでしょうか？

```kotlin
Modifier
            .fillMaxWidth()
            .offset(y = targetValue)
            .semantics(mergeDescendants = true) {}
```

**CombinedModifierが作られます。CombinedModifierはouterとinnerのModifireを持ち、CombinedModifierは数珠つなぎにできて、複数個あるときはこのouterの方に同じように連なるだけです。**

```kotlin
class CombinedModifier(
    private val outer: Modifier,
    private val inner: Modifier
) : Modifier {
...
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27388/322e3072-5340-d5af-9254-2eb91a2af997.png)

上記でタイトルの件は終わりです。

---

下記は興味があれば。

## ModifireのComposable関数を渡せるものはどうなっているのか？

そんなに知られていないかもですが、composed{}というのを使うとModifireの変更をComposable関数の中でできるんですよね。そこがどうなっているのかを見てみます。

```kotlin
    MultiMeasureLayout(
        modifier = modifier.semantics { designInfoProvider = measurer } 
```


例えば`Modifier.semantics()`は以下のような形になっていて、`composed() {}`でComposable関数を渡しています。このComposable関数はどこでどうやって使われるの？？ということです。

```kotlin
fun Modifier.semantics(
    mergeDescendants: Boolean = false,
    properties: (SemanticsPropertyReceiver.() -> Unit)
): Modifier = composed( // ← ここでcomposed{}を呼び出している
    inspectorInfo = debugInspectorInfo {
        name = "semantics"
        this.properties["mergeDescendants"] = mergeDescendants
        this.properties["properties"] = properties
    }
) {
    val id = remember { SemanticsModifierCore.generateSemanticsId() }
    SemanticsModifierCore(id, mergeDescendants, clearAndSetSemantics = false, properties)
}
```

**Lauyout()関数などの実際にレイアウトを行うComposableの中でmaterialize()という関数が呼び出されて、materialize()がModifireがもつComposable関数を呼び出していって、その結果がCombinedModifierに入るだけです。**

```kotlin
    val materialized = currentComposer.materialize(modifier)
```

## materialize前
`ComposedModifire`というものが入っている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27388/564f8d8d-fb36-de3d-a71c-b4ea8331d144.png)



## materialize後
composed()で渡されたComposable関数が呼ばれて、SemanticsModifierCoreが入っている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27388/f1892bb1-db58-1106-4154-2a919d4d7572.png)
コマンドラインで Solana  Delegate Stake するメモ

`$SOL` を validator にステーキングを移譲することで, `$SOL` の報酬を得ることができる.

https://www.stakingrewards.com/earn/solana/

2021 年 9 月時点では概ね年利 6.5 % くらい($SOL 自体の PoS ステーキング利率からバリデータのコミッション率(大体 8~10%)を考慮して減少させた率).

GUI で行うこともできると思われるが, ここでは testnet validator 向けに CLI でのやり方をメモ.

Stake を移譲(delegate)する場合は, まずステーキング用のアカウントを作る必要がある.

https://docs.solana.com/cli/delegate-stake

## 大まかな手順

* `$SOL` のアカウント(wallet)があるとする
* 別途ステーキング用のアカウントを作る
* ステーキング用アカウントに `$SOL` を移動する
* ステーキング用アカウントからvalidator の vote account へ `$SOL` を delegate する.

### ステーキングをやめるとき

* unstake, withdraw でアンステークして元のアドレスに `$SOL` を引き出す 

## ステーキング用アカウントの生成

```
$ solana-keygen new --no-passphrase -o stake-account.json
```

その後 `$SOL` をステーキング用アカウントに転送する

```
$ solana create-stake-account --from <KEYPAIR> stake-account.json <AMOUNT> \
    --stake-authority <KEYPAIR> --withdraw-authority <KEYPAIR> \
    --fee-payer <KEYPAIR>
```

fee-payer : トランザクション手数料の払い手であろう. 第三のアカウントでもできるやもしれぬが, 通常はステーキング元のアカウント

## Authority

Solana ではアカウントごとに複数の権限(トランザクションへ sign する権限)を持たせることができる.

https://docs.solana.com/staking/stake-accounts#understanding-account-authorities

stake-authority: ステーキング関連のトランザクションを行う権限 
withdraw-authority: アンステークされたアカウントから $SOL を戻す(withdraw)のと, 新規に stake 用アカウントをつくるための権限
 
stake を withdraw を別にするのもできるであろうが, bot みたいなのを作らないのであれば, 通常は同一アカウントで運用となるかと思われる.

## delegate

最後に, ステーキング用アカウントから validator の vote アカウントに delegate して, デリゲート処理は完了.

```
$ solana delegate-stake --stake-authority <KEYPAIR> <STAKE_ACCOUNT_ADDRESS> <VOTE_ACCOUNT_ADDRESS> \
    --fee-payer <KEYPAIR>
```


```
$ solana stake-account <STAKE_ACCOUNT_ADDRESS>
```

でステーク状況を確認できる.

## 注意点

delegate は epoch 単位となる. したがって delegate してすぐには反映されない.

https://support.exodus.com/article/1551-solana-staking-faq#epoch

epoch は大体 2 日単位.

一度 delegate したのち, `$SOL` が増えたので再度 delegate(re-delegate)したい場合はできないっぽい. 一度 delegate をやめるなどする必要があるっぽい.

## Derive stake

複数の validator にデリゲートしたいとき用



## TODO

* [ ] split stake を調べる
* [ ] Staking 用アカウントに unmineable などから `$SOL` 払い出した場合はどうなるかしらん?
Mac > install anaconda メモ



メモというか殴り書きです。すみません。



brewでinstall

### brew install


```
$ brew install pyenv
$ pyenv -v

...
	pyenv 2.0.7
```



### install可能なリストを表示

```
$ pyenv install -l | grep anaconda

...
  anaconda3-5.2.0
  anaconda3-5.3.0
  anaconda3-5.3.1
```


今回は`5.3.1`をinstall

```
$ pyenv install anaconda3-5.3.1

$ pyenv versions
...
* system
  anaconda3-5.3.1 (set by /Users/atsu/.pyenv/version)
```

### 現在のpythonバージョン確認

```
$ python --version
Python 2.7.16
```


### zshの設定

zshの設定

```
echo 'eval "$(pyenv init --path)"' >> ~/.zshrc
```

変更を反映

```
exec $SHELL -l
```



### anaconda3-5.3.1をアクティブにする

```
$ pyenv global anaconda3-5.3.1
$ pyenv versions
...
  system
* anaconda3-5.3.1 (set by /Users/atsu/.pyenv/version)
```


### pythonバージョン確認

python

```
$ python --version
Python 3.7.0
```



### conda

conda

```
$ conda --v
conda 4.5.11
```

create 

```
conda create --name py python=3.7 anaconda
```

```
Solving environment: done

中略
    zope.interface:                     5.3.0-py37h9ed2024_0
    zstd:                               1.4.5-h41d2c2f_0

Proceed ([y]/n)?
```


update conda

```
conda update -n base -c defaults conda
```
Flutter環境構築のつまずきポイント(初心者向け)

#目次
- [はじめに](#はじめに)
- [環境](#環境)
- [PATHが通らない](#pathが通らない)
- [Android StudioでOpen iOS Simulatorが出来ない](#android-studioでopen-ios-simulatorが出来ない)
- [さいごに](#さいごに)
- [参考](#参考)

#はじめに
Flutterの勉強を始めたいと思い、まずは環境構築をしてみました。基本的には手順通り進みましたが、Flutter初心者の私が引っ掛かったいくつかのポイントをまとめました。Flutter環境構築が上手くいかない方は是非参考にしてみてください。

#環境
- macOS Catalina 10.15.7

#PATHが通らない
flutterをダウンロードして所定の場所に配置して、.zshrcファイルにPATHを追加して保存しましたが、not foundエラーとなってしまいました。

[解決策] source .zshrcを実行してzshrcファイルの変更を反映させると解決しました。つい忘れがちですが、忘れない様にしたいですね。
[【zsh, bash】macでPATHを通す方法 - not found と出てしまった](https://qiita.com/k3ntar0/items/eb8cdbd8eba9da388def)

#Android StudioでOpen iOS Simulatorが出来ない
Android Studioで`Open iOS Simulater`を指定してdebugしても、iOSのシミュレータでの実行が上手くいきませんでした。

[解決策] ターミナルで`flutter doctor`コマンドを実行し、エラーになった箇所を1つずつ解消する。私の場合、3つのエラーと1つの警告が出ていました。

**エラー①Androidのコマンドラインツールがない**
[解決策] Android StudioでSDK  Manager（右上らへんのアイコン）を開き、「SDK Tools」タブから「Android SDK Command-line Tools(latest)」のチェックを入れる。

**エラー②Androidのtoolchainが有効化されていない**
[解決策] `flutter doctor --android-licenses`を実行する。

**エラー③Xcodeインストール後に下記の2つのコマンドを実行していない**
[解決策] 下記コマンドの実行。
`sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer`
`sudo xcodebuild -runFirstLaunch`

**警告①CocoaPodsのバージョンが古い**
[解決策] brewコマンドを使用してCocoaPodsをアップデートする。
[Catalina10.15でCocoaPods1.10.0を入れる方法(Homebrew)](https://qiita.com/1mash0/items/cca017d1b8e48912b752)

全て解消した状態で再度`flutter doctor`を実行すると、この様な画面になり、iOSのシミュレータも無事実行できました👏👏👏(`flutter doctor`便利ですね！！！)
![スクリーンショット 2021-09-25 11.57.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793562/c8fbcb96-851a-ac75-260b-e3189a8a20ff.png)

#さいごに
Flutterの環境構築に関しては、日本語の参考記事も豊富にあり、新しくFlutterを始めたい方にとってはスタートしやすいなという印象を受けました。初心者の私でも1時間ちょっとで環境構築出来ました。これから環境構築する方は、ぜひ下記を参考にチャレンジしてみてください！

#参考
これらの記事が親切で分かりやすいです！
[Flutterの環境構築](https://kboyflutteruniv.com/setup_flutter/)
[絶対にくじけないFlutter開発環境構築(VS Code)](https://ryuichi111std.hatenablog.com/entry/2018/09/09/232158)
[Flutter実践入門 ～環境構築からAndroid/iOS/Webに広告を付けて同時にリリース!!～](https://zenn.dev/kazutxt/books/flutter_practice_introduction/viewer/tutorial_environment#vscode(ide))
Djangoの環境構築

###実行環境

Python 3.9.7
Django 3.2.7
Windows10

###手順
1.Vscodeのインストール
2.Pythonのインストール
3.仮想環境構築
4.プロジェクト作成

####1.Vscodeのインストール
[公式サイト](https://code.visualstudio.com/)にアクセスしてインストール。


####2.Pythonのインストール
[公式サイト](https://www.python.org/)にアクセスしてインストール。
インストールする前に画面の下のチェックボックスの"Add Python3.9 to PATH"にチェックを入れる。
環境変数設定をする際に必要。

####3.仮想環境構築
デスクトップにフォルダを作成（なんでもいい）。
Vscodeで作成したフォルダを開く。
ターミナルを開いて（Ctrl+＠）pythonのversionを確認。

仮想環境を作成するためのPipenvをインストール。

```django:上で作成したフォルダ
pip install pipenv
```

Djangoのインストール

```
pipenv install Django
```

仮想環境を作成するコマンドは

```django:上で作成したフォルダ
python -m venv <仮想環境フォルダ名>
```

次にシステム環境変数にパスを通す。
Windowsのシステム環境変数にパスを通すことで、ターミナル上でプログラム名を入れるだけでプログラムを実行できるようになる。

####4.プロジェクト作成
cd <仮想環境フォルダ名>でフォルダに移動して、プロジェクトを作成。

```django:仮想環境フォルダ
django-admin startproject config .
```

サーバーを起動。（python manage.py runserver）

127.0.0.1:8000で確認。
![成功画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2082391/1c37d076-628d-dd1d-ad4e-9c6af2e3f399.png)


###さいごに
環境構築がこれまで面倒くさかったのでawsのcloud9を使用していたが、そこまで面倒ではなかった。
これから、Djangoの勉強としてECサイトの作成を行っていきたい。