OmniAICreator/Qiita-1.07M huggingface dataset:
LINE × スプレッドシートのススメ(家計簿アプリ編)

# はじめに
最近ですが、LINEでやり取りするトランザクションデータをデータベースではなく、**ユーザのスプレッドシートで直接管理することを推してます**。

メリットとしてはこんな感じです。
1. サービス内でデータを保持しないということは、**データ保持の責任リスクを軽減**できる
2. ユーザに馴染みのあるExcel形式であり、スプレッドシートの機能で可視化できるので**データ分析もしやすい**

このメリットを活かすサービスとして、**家計簿アプリ**を作りました。

# 家計簿アプリについて
## コンセプト
1. 後で家計簿に書こうとしても、ついつい忘れてしまう。なので、**モバイルアプリで買ったその場で登録!!**
2. それでも人間は忘れてしまう。そんな時は、モバイルアプリでちまちま登録せず、**PCでまとめて登録しよう!!**
3. 使い慣れたExcel形式だから、自分の好きなように**データ分析もできる!!**

![2020_AdventCalendar用画像.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16977/873bc482-8252-d3bd-803b-2a32be7c7596.png)

![2020_AdventCalendar用画像 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16977/3effec2b-43a8-3243-e12c-f9b177850af8.png)

一応、以前作ったプレゼンですが、こちらでもコンセプトを語ってます。

[(参考)LIFF×スプレッドシートのススメ](https://speakerdeck.com/macochin/21-ltji-ri)

## 今回の改良点
今までは単純に買ったものをスプレッドシートに書き込むだけでした。
![qiita①.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16977/09ed941f-ac72-3fe3-e2cd-252a911ef64e.png)

巷でこんな声を聞きました。
「買い物してたら、ついつい買いすぎちゃって、月の生活費の予算を超えちゃったわ」

・・・なるほど。
じゃあ、月のトータル金額が見れるようにしましょう。

### サーバー環境
サーバサイドはNode.jsで作っており、スプレッドシートの操作は以下のモジュールを使ってます。
[google-spreadsheet](https://theoephraim.github.io/node-google-spreadsheet/#/)

※Githubにも全ソースを上げてますが、以下のソースコードはQiitaに載せるにあたって分かりやすくするためにGithubのソースコードとは多少異なります。

[家計botアプリ](https://github.com/macochin/i-kakeibot)

まずは月の集計金額を出す必要があるので、query関数をスプレッドシートに書き込んでます。

```javascript
let doc = new GoogleSpreadsheet(sheetId);// スプレッドシートIDを指定

// 認証関連のコードは省略します(※そのうちQiitaに記事書きます)
// スプレッドシート(doc)から、対象のシート(sheet)を取得したところから書きます。

// query関数を書き込むセルの指定
await sheet.loadCells('F1');
let cell = sheet.getCellByA1('F1');
// 関数を書き込む際は「formula」を使います。
cell.formula =  `=query(A:C,"select B,sum(C) where B is not null group by B label B 'sum 買ったもの'",1)`;
sheet.saveUpdatedCells();
```
これで、query関数を用いて集計できました。
![qiita②.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16977/6e979244-2617-4c30-96e0-2b3f2d022149.png)

これだけではツマラナイので、グラフも入れて分かりやすくしてみます。
とはいえ、スプレッドシートの関数でグラフ化ができるのは今のところ少ないようです。

※本当は円グラフを使いたかったのですが、関数ではできないようなので棒グラフにしてみました。

```javascript
// for文でぐるぐる回して、SPARKLINE関数を使って棒グラフを追加してます
for (let i = 2; i <= index; i++) {
  await sheet.loadCells(`H${i}`);
  let cell = sheet.getCellByA1(`H${i}`);
  cell.formula =  `=SPARKLINE(G${i}, {"charttype","bar";"max",MAX(G:G)})`;
  sheet.saveUpdatedCells();
}
sheet.saveUpdatedCells();
```
すると、こんな感じでグラフが出ました
![qiita③.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16977/710fce10-eeca-8067-e429-a91680968bc7.png)

モバイルでも確認できますので、買い物中も見れます
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16977/a00b2fd5-f33c-8a0f-d58c-1f44689c4491.png" width="300px">

### 今後の改良点
実は、買ったもの(商品名)で集計しているので、例えば「生活費」みたいなカテゴリで集計する形にはまだなってません。
今度はその辺りを直したいと思ってます。

# 最後に
今回は改良した部分を中心に記事を書きましたが、そもそもユーザのスプレッドシートに書き込むための設定方法については書いてません。
次回はその辺りを書きたいと思います。
【メモ】Jupyter Notebookでpycodestyle（pep8）を使う方法について

* 製造業出身のデータサイエンティストがお送りする記事
* 今回はJupyterNotebookでpycodestyle（pep8）を使う方法をメモとして残しておきます。

##はじめに
pythonスクリプト（.pyファイル）を使用する時は、他人に見せたりする時やアセットとして残す際にpycodestyle（pep8）を使ってチェックするかと思います。
今回はNotebookも同様にチェックできないかと思い調べたら、方法があることを知りましたのでメモとして残しておきます。

最初に必要なライブラリーをインストールします。

```php
pip install flake8 pycodestyle_magic
```

次にマジックコマンドを使えるようにします。

```php
# magicコマンドを使えるように読み込む
%load_ext pycodestyle_magic
```

最後にチェックしたいコードが書かれたセルにマジックコマンドを最初に入れて実行するだけでスクリプトのチェックができます。

```php
%%pycodestyle

# 必要ライブラリのimport
import pandas as pd
import numpy as np
```

##さいごに
最後まで読んで頂き、ありがとうございました。
凄い簡単で驚きました。notebookを使うことが多いので助かります。

訂正要望がありましたら、ご連絡頂けますと幸いです。
Gitで名前を間違えたまま何回かコミットしてしまったログを修正する

# 事象

新しいPCになって最初のコミットの際に、コミッタの名前とメールアドレスがPCのユーザ名とホスト名になっていたことに（警告が出ていたのにも関わらず）気付かないまま何度かコミットをしてしまった。
個人利用のリポジトリだがログが残るのが気持ち悪いため、修正する。

# 名前、メールアドレスの修正

Gitの設定情報を正しい内容に修正する。

```
$ git config --global --edit
```

viが起動するため、以下のように追記して`esc` + `:wq`

```
# This is Git's per-user configuration file.
[user]
# Please adapt and uncomment the following lines:
#       name = XX YY
#       email = xxyy@xxyy.local
name=mamfrog                 <-- 追記
email=mamfrog@dummy.jp       <-- 追記
```

# コミットを修正

修正したいコミットが何個前のコミットなのかをログで確認する。

```
$ git log
```

二つ前のコミットを修正する場合、以下を実行する。
（三つ前なら`HEAD~3`となる。コミットIDを直接指定してもOK）

```
$ git rebase -i HEAD~2
```

※この時`error: cannot rebase: You have unstaged changes.`といったエラーが発生した場合、コミットしていない変更があるため、コミットまたはスタッシュしておく。

viが起動するため、対象のコミットの先頭の`pick`を`edit`と書き換えて`esc` + `:wq`

```
pick 9cbd3f9 二つ前のコミットメッセージ
pick 7d136e8 一つ前のコミットメッセージ

# Rebase fedede1..7d136e8 onto fedede1 (2 commands)
（以下略）
```

対象のコミットがチェックアウトされた状態になるため、コミッタの修正コミットを行う。

```
$ git commit --amend --reset-author
```

修正が終わったので、リベース完了する。

```
$ git rebase --continue
```

再度`git log`してコミッタが修正されたことを確認。

# 補足

一つ前のコミットだけを修正する場合はリベース不要。
Gitの設定情報を修正後、以下を実行すればOK。

```
$ git commit --amend --reset-author
```

# 参考

[6. rebase -i でコミットを修正する｜サル先生のGit入門【プロジェクト管理ツールBacklog】](https://backlog.com/ja/git-tutorial/stepup/33/)
AWSの基礎(歴史)

#AWSとは

AWSとは、(Amazonの)サーバーを借りれるサービスのこと。

インターネットに接続するブラウザ(chromeとか)からAWSにアクセスして必要なときに必要な分だけ、画面をポチポチしてサーバーを作れて、使えます。またなんと言っても、一台のサーバーを使うのに１分もかかりません。このスピード感が時代にマッチしていました。

また自由度の高いシステム構築スペースを提供するということで、実際にはサーバーだけではなく、AWSは権限管理やネットワークのサービス、監視サービス、ストレージのサービスなどいろいろあります。自由度がかなり高いが、裏を返すと難易度も高いです。


そしてお金も使った分だけ請求がくる従量課金という仕組みをとっています。






#なぜAWSが生まれたのか

Amazonは当初、システム効率が悪く問題を抱えていました。
これはAWSが誕生する以前の話です。例えば、

・担当者しか知らない属人性を抱えている
・サーバーを用意するのに２ヶ月とかかるスピードの遅さ
・拡張性、スケーリングなどの考慮ができていない

といった問題を抱えていました。

これは例えば、アクセスが予想以上にきたり、ビジネスが大きくなってきたときにお客様がいっぱい来るんだけど、対処できるサーバーが用意できない。

要はサービスが継続できないという問題を抱えていました。

#AWS誕生

その問題解決のためにAWSが生まれました。AWSは、Amazonが実際に苦労して作り上げた実践的なサービスです。このシステムを客向けに開始したのが、2006年。現在では多くの企業が利用する超人気サービス(クラウドコンピューティングサービス)となっています。Amazonの売り上げの稼ぎ頭になっており、営業利益ベースだと現在Amazon全体の63%。Amazon全体の利益の半分以上がAWSとなっております。

#オンプレミスの弱点

今までは企業のサーバーの利用するまでの流れは、

⓵自前でサーバーを購入する
⓶サーバーを管理してくれるデータセンターのサービスに申し込む
⓷ラックの中にサーバーを積む(サーバーの設置)
⓸リモートで企業から接続しながら運用していく

これは今ももちろんあります。このような形態をオンプレミス運用すると言ったりします。

##お金の問題

Webサービスを始めるのに、今まではとても初期費用がかかっていました。

Webサービスを始めるには、サーバー(業務用コンピュータ)が必要になります。サーバの上でプログラムが実行されてWebサービスを提供しています。そこで、

・サーバー自体１台100万円はする
・サーバーの適切な空調管理の費用
・サーバー自体のセキュリティの管理(侵入者が来ないように)する必要がある
・サーバーは会社の資産となって固定資産税がかかる場合がある



この変化の激しい時代に初期費用を多くかけることはリスクでもあり、クラウドに比べると金額面で大きなデメリットがあります。

##時間の問題

サーバを導入するのに平気で１ヶ月がかかります。具体的には、

・どの程度高性能なものが必要かスペック見積りする時間
・配送する時間
・データセンターにサーバーを送って設置する手間や時間

とにかく時間的にもスピード感に欠ける部分がありました。

#クラウドサービス

クラウドサービス(クラウドコンピューティング)とは、インターネットなのコンピュータネットワークを経由して、コンピュータ資源をサービスの形で利用する利用形態。

主要なクラウドサービスには、

・AWS(Amazon)
・Azuru(microsoft)
・GCP(Google)

などがあります。

##クラウドサービスのメリット

これらのクラウドサービスのメリットは、

・スピード
・従量課金(使った分だけお金を支払うスタイル)
・拡張が容易
・サーバーのスペック変更が容易

サーバーの設置も撤去も素早く行えること、従来課金によって企業が無駄な出費をすることを防げること、拡張が容易であることで企業の規模が拡大していく時やサーバーにアクセスが集中した時にすぐに対処できること、また変化の多いこの時代に同じマシーンや同じスペックのサーバーを購入して使い続けるのもリスクであるため、途中でスペック変更が容易であることもメリットとなります。


##クラウドが誕生までの歴史

###1970年頃
ホストコンピュータからITサービスが始まりました。
ホストコンピュータとは、独自仕様の大型物理コンピュータのこと。(メインフレーム)
この時代、大企業しかコンピュータを持つことができませんでした。
取り扱うには大変専門的な知識が必要だったり、大変高価なコンピュータという時代でした。

###1980年頃
分散化（サーバークライアント方式）
Webシステムの誕生して、インターネットを通じて多くの人に使われるようになった。

###2000年頃
仮想マシン(VMware)
VMwareのツールが有名です。サーバーの上にサーバーを立てる仮想化技術によってサーバーが簡単に構築できるようになりました。

###2017年頃
日本政府「クラウドバイデフォルト宣言」
日本政府の機関システムは基本的にはAWSを使っていきましょうという宣言になりました。パブリッククラウドは、スタートアップやITベンチャーが多かったのですが、昨今では銀行などのお堅い企業でも使われています。MUFGは、社内システムの一部にクラウドを採用しています



###2024年頃
クラウド市場の拡大
市場規模２兆円超予想
(ブライダル関連市場とほぼ同等)


歴史を振り返ると、過去に分散化や仮想マシーンなどの変化が起こったように、現在IT業界ではオンプレミスからクラウドへの産業革命のようなものが起こっているように感じます。
マークダウン方式でのネストした引用文の書き方（引用の引用）

# はじめに
READMEやgithubのコメント等のマークダウン方式で、引用文の中に引用文を書く方法です。

# 結論
>> ネストしたい引用文

> 引用文
>> ネストしたい引用文

> 引用文

こうするには

```
>> ネストしたい引用文

> 引用文
>> ネストしたい引用文

> 引用文
```
こう書きます。
引用文中でネストを解除するには、いったん改行が必要です。
code build  で EFS  をマウントすると失敗する

aws の公式だと、原因を特定するのはawsビギナーには困難だったため、自分用のメモ

aws code build でEFS をマウントする必要があったので、マウントしようとすると「CLIENT_ERROR: mounting '127.0.0.1:/' failed. connection reset by peer」というエラーになる。

aws 公式に記載されている解決方法を実施しても治らず…

https://docs.aws.amazon.com/codebuild/latest/userguide/sample-efs.html


上記のとおり、セキュリティグループでEFSにアクセスできる設定は行ったし、同一subnet上にEFSも存在している。

結論から言うと、VPCのDNS名前解決をONにする必要がある(File System Mount Using DNS Name Fails)。

https://docs.aws.amazon.com/efs/latest/ug/troubleshooting-efs-mounting.html



今回原因を特定できた方法は、自分構築したVPCで失敗し、CloudFormatinのテンプレートで構築したVPCで成功したため、設定を比較しながら特定することができた。
自分でAWS コンソールマネージャからvpcを構築すると、DNSの設定がデフォルトが'OFF'である。デフォルトがOFFのため、code build EFSがマウントできない。

fargate でDbのマイグレーションを行い、DBをマイグレーションしたＤＢからデータ構造の自動生成(ex: C# のentityframework 、java のjooq)をする際に、インスタンスを起動する必要がなく重宝すると思ったが、調べても同じ悩みを抱えている人がいなかったため、原因が特定するのに時間がかかってしまった。もしかして、データベースからコードの型の自動生成自体がレガシーなのか、それとも初歩すぎる問題で誰も詰まったりしないのかと思った(どっちでも自分的には精神的ダメージ)。
pyenvとvirtualenvを用いたDjangoの環境構築

# 初めに 
インターンで実際の現場に入って１週間ほどしか経ってないのですが、それだけでもたくさん学ぶことがあったので、アウトプットとして記事を書いてみました。

# pyenv,virtualenvを利用した仮想環境の構築

### pyenvとは何か
pyenvは**使用するpythonのバージョンをプロジェクトごとに選ぶことができるもの**。pyenvでは```pip install 3.8.0```などでpythonのバージョンを指定することができる。

インストールできるバージョンの確認などは下記の記事を参考。
>[pyenvでインストール可能なバージョン一覧を表示する方法 \- Qiita]
(https://qiita.com/lighttiger2505/items/9361de2a2951b838f3b7)

### virtualenvとは何か
ローカルに仮想環境を構築することができるもの。その仮想環境の中にライブラリをインストールすることが望ましい。

### 実際のインストールして仮想環境構築するまでの流れ

- pyenvのインストール
```git clone https://github.com/yyuu/pyenv.git ~/.pyenv```

- virtualenvのインストール
```git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv```

- .bash_profileに書き込む（ここら辺はシェルによって変わる。）

```
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
```
**.bash_profileに書き込むことで毎回bash起動時に、上記のコードを読み込むことができる。**

- virtualenvでの仮想環境作成

```
pyenv virtualenv 3.8.0 <仮想環境の名前>
pyenv local <仮想環境の名前>
```
自分は指定したディレクトリ下で、仮想環境を作りたいのでlocal指定している。localがいいのかglobalがいいのかは個人の好みのような気もするが、詳しいところはあまり知らない。

また、作成した仮想環境は```pyenv version```で一覧を見ることができる。

これで仮想環境構築できたので、```pip install django```などして、使いたいライブラリをインストールすればいい。

参考記事
>[pyenv と pyenv\-virtualenv で環境構築 \- Qiita](https://qiita.com/Kodaira_/items/feadfef9add468e3a85b)
[pyenvとpyenv\-virtualenvの自分流使い方 \- Qiita](https://qiita.com/ksato9700/items/5d9eba10fe6b8e064178)

### 詰まったところ

自分はpythonディストリビューションであるanacondaを元々インストールしていたためなのか、環境構築に詰まった。詳しいところはまだよく分からないが、anacondaをdeactivateなどしてから、環境構築を始める必要がある。

また時間があったら調べて、anacondaを入れてる状態から仮想環境を構築するまでの記事を書きたいと思う。

###### 間違いが見つかり次第、随時更新してきたい
投稿一覧画面を作っていて、長文を打ち込むと、文字がはみ出てしまう問題を解決する

今回オリジナルアプリを作るにあたって、検証ツールで、試しにめっちゃ長いアルファベットの文章を打ってみたのですが、そのときに、投稿を作っているブロックからはみ出てしまう問題が発生してしまったので、その解決策を共有していきたいと思います
#実例
![スクリーンショット 2021-03-04 17.59.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/998838/5318dab1-44a6-90ce-365a-695e94dfd202.png)

こんな感じになってしまいます。
これでは、とてもいいUIとは言えませんよね、それを、
![スクリーンショット 2021-03-04 18.01.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/998838/3e7e1f5b-dd93-ca42-385c-2ac65cfab5b4.png)
のように、きちんと枠に収める方法があります

#解決策

HTMLのbodyのCSSの部分に、

```
word-wrap: break-word;
```
をつければ解決します
【UE4】Control Rig試し中②／ぷちコン15進捗 - 2021/03/04

[1]:https://historia.co.jp/ue4petitcon15

[株式会社ヒストリアさん主催の第15回UE4ぷちコン][1]の作業進捗。
Control Rigの続き。

# イマココ

IK/FKの切り替え（というかブレンド）を作成。

1. IKの計算結果をBoneのTransformに直接入れる代わりに、いったんSpaceに保存。
2. そのSpaceの内容と、FKリグとのブレンド(Interpolate)結果をBoneにSetTransformする。

…という形で実現できた。

![20210304_1746.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/9000edfd-74e0-8595-dd56-f1ea91cdd400.gif)

# 気づいたこと

- 上記に書いた通り、計算結果の Transform を変数に保存する感覚で、Space に入れておく方法もありかも？
    - 変数に入れた方が軽い？
    - Space に保存する方が、Rig VM 内で完結して軽い？
    - どっちがいいかわからないから、やりやすい方でよかろうｗ
- Rig Graphが肥大化してきて、エディタ操作が重くなってきた。
    - Auto Compile を OFF にしたら、ちょっと改善した。
- その流れで、編集用のリグ (=DCCツール上で作るような) と、ランタイム用のリグは別で作るべきかもしれない、と思った。
    - 編集用のリグは、いろんなポーズをつけやすい(=エディットしやすい) のが正義。
    - だが、ランタイム用のリグは、用途がもっと限定されて、よりシンプルなものの方が良さそうだ。
        - 例：IK 周りの煩雑なコードを減らしたい
            - 足が地面にええ感じに沿うとか
            - ドアノブをきっちりつかむとか
        - 例：アニメーション再生＋物理をよりシンプルにしたい
            - ボーンを一個一個 Physics に回すより、末端のリグだけ揺らせばよくね？説
    - 色んな体格を一つのリグで解決したい場合は、ちゃんと組むべきかな？
pytrochのmnistがいつの間にかダウンロードできなくなっていていつの間にか解決されていた件

# はじめに

pytorch使ってmnistを試そうと思ったらまさかのダウンロードができなかったので，
ちょっと調べてみました．
とりあえず，日本語がなかった気がするので，おそらくそんなに困っている人はいないと思います．

2021/04/05追記
この日付の時点で調べたところcolabにプリインされているpytorchのバージョンが上がっていて，この問題は起こらなくなっていそうです．  

```
torch 1.8.1+cu101
```

ライブラリやパッケージは結構振り回されるので，何も心配したくない人は
こんな感じで直接ダウンロードして解凍するのが良いと思います．

```python
# MNISTのダウンロード
!wget www.di.ens.fr/~lelarge/MNIST.tar.gz
!tar -zxvf MNIST.tar.gz
# 整形方法を決定
transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,),(0.5,)) ])

# 学習データの読み込み
trainset = torchvision.datasets.MNIST(root="./", train=True, download=False, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size, shuffle=True, num_workers=1)

# テストデータの読み込み
testset = torchvision.datasets.MNIST(root="./", train=False, download=False, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=batch_size, shuffle=False, num_workers=1)
```

## 対象

- colabを使ってpytrochいじっている
- 2021年になってからmnist使っていなかった人

## 内容

こんなエラーがでてmnistダウンロードできずに困っていたところ，
[pytrochのissue](https://github.com/pytorch/vision/issues/1938)では既に解決していた，という話．

```terminal
/usr/lib/python3.7/urllib/request.py in http_error_default(self, req, fp, code, msg, hdrs)
    647 class HTTPDefaultErrorHandler(BaseHandler):
    648     def http_error_default(self, req, fp, code, msg, hdrs):
--> 649         raise HTTPError(req.full_url, code, msg, hdrs, fp)
    650 
    651 class HTTPRedirectHandler(BaseHandler):

HTTPError: HTTP Error 403: Forbidden
```

## バージョン

```
torch 1.7.1+cu101
torchvision 0.8.2+cu101
```

# 解決法

これで解決する．（と書いてある）

```python
from six.moves import urllib
opener = urllib.request.build_opener()
opener.addheaders = [('User-agent', 'Mozilla/5.0')]
urllib.request.install_opener(opener)
```

つまり，トータルこんな感じでかけばオッケーです．

```python
import torch
import torchvision
import torchvision.transforms as transforms
from six.moves import urllib
opener = urllib.request.build_opener()
opener.addheaders = [('User-agent', 'Mozilla/5.0')]
urllib.request.install_opener(opener)

# 学習の設定
## エポック
epochs = 200

## バッチサイズ
batch_size = 20

# 1. 整形方法を決定
transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,),(0.5,)) ])

# 2. 学習データの読み込み
trainset = torchvision.datasets.MNIST(root="./data", train=True, download=True, transform=transform)
train_dataloader = torch.utils.data.DataLoader(trainset, batch_size=batch_size, shuffle=True, num_workers=1)

# 3. テストデータの読み込み
testset = torchvision.datasets.MNIST(root="./data", train=False, download=True, transform=transform)
test_dataloader = torch.utils.data.DataLoader(testset, batch_size=batch_size, shuffle=False, num_workers=1)

print(trainset.data.shape)
```

colab用のスニペットURLおいておきますね．
https://colab.research.google.com/drive/1_APWFBv-yxLDhbbphKU7HEpqG9lvVtRq?usp=sharing

# おわりに
サクッと書いてみました．
~~バージョンによって変わると思うので，そのうちオワコン化すると思います．~~
オワコン化しました．
コンテナ型仮想化技術の仕組み

こんにちは。

前回の記事「[Docker コンテナ構築入門](https://qiita.com/Ewokkkkk/items/1bff6ecb521f30eff8c4)」でDockerでのコンテナ構築方法を説明しました。
今回は__コンテナ型仮想化技術の仕組み__にフォーカスを当てた記事を書いていきます。

特徴とコンテナを構成するNamespace, cgroup, Capabilityについて説明します。

# コンテナ型仮想環境
コンテナ型仮想環境は、__仮想化技術の一種__です。
筆者は以前にOracle社のVirtualBoxを利用した経験があったため、VirtualBoxが該当するホスト型仮想環境と比較して説明します。
ホスト型は、仮想環境ごとにゲストOSを立ち上げるのに対し、コンテナ型は__ホストOSのカーネルを共有__して動作しています。
そのため、他の仮想化技術と比べ起動が__速く__、__軽量__に動作するといったメリットがあります。

![環境比較画像](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453628/8f4d5a81-d9e1-230e-8b2d-9f13f8677043.png)

また、ホストOSと__独立した環境__を作成できるので、管理が楽といったメリットもあります。

# コンテナを構成する代表的なLinuxカーネルの機能

結論から言うと、コンテナは複数の__Linuxカーネルの機能__を組み合わせて構成されており、「コンテナ」と呼ばれる単一の技術でできているわけではありません。

その中でも重要な以下の3つの要素を説明します。

* __Namespace__ "ネームスペース"
* __cgroup__ "コントロールグループ"
* __Capability__ "ケイパビリティ"

## Namespace

__Namespace__は、プロセスが参照するプロセスIDやマウントポイントなど、カーネルリソースを他のプロセスと分離し、ファイルツリーなどが独立したOS環境のように見せる機能です。

日本語では__名前空間__とも呼ばれています。

Namespaceはすべてのプロセスに関連付けられており、デフォルトでは親プロセスと同じNamespaceを参照します。そのため、同じNamespaceに存在する__関係のないプロセス__や__リソース__まで参照できてしまい、__ファイルツリーの干渉__や__マウントなどのファイルシステム__に__影響__を与えてしまう可能性があります。

そこでコンテナは、新たなNamespaceを関連付けることで、__コンテナ内のリソースだけ見えるように隔離__しています。

なお、Namespaceには__7つ__種類が存在し、それぞれ隔離できるリソースは異なります。

| 名前空間 | 定数 | 分離対象 |
|:-:|:-:|:-:|
| IPC | CLONE_NEWIPC | System V IPC, POSIX メッセージキュー |
| Network | CLONE_NEWNET | ネットワークデバイス、スタック、ポートなど |
| Mount | CLONE_NEWNS | マウントポイント |
| PID | CLONE_NEWPID | プロセス ID |
| User | CLONE_NEWUSER | ユーザー ID とグループ ID |
| UTS | CLONE_NEWUTS | ホスト名と NIS ドメイン名 |

ちなみに、`Docker`を介さずLinuxコマンドでNamespaceを作成する方法は、こちらにまとめてあります。
[unshareコマンドで、Namespaceを作成してみる](https://qiita.com/Ewokkkkk/items/f2fc09d09584bcb135da)


## cgroup

__controll group__の略です。

`cgroup`はプロセスを__グループ化__し、グループ化したプロセスに対して__リソースの管理__を行う機能です。

例えばホストが持つCPUやメモリなどの__リソースを制限__することができます。
そうすることで、あるプロセスが多くのCPUやメモリを消費し、動作が遅く不安定になったり、他のプロセスが強制終了したりといったことを__抑制__することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453628/0f29d289-cb69-63ab-9aec-5ebdeba55430.png)

cgroupは具体的に、

* CPU時間・メモリ使用量の制限
* デバイスのアクセス制御
* ネットワーク優先度の設定
* 各リソースの使用量の確認

などといった事ができます。


## Capability

通常プロセスは、__特権（root権限）__あるいは__一般ユーザ権限__で動いています。
特権が必要になるのは、

* __特権ポート__(<1024)を使用する場合
* ネットワークの疎通確認に良く使う`$ping`コマンドなどのように__Rawソケット__を使用する場合
* `$ntpd`などで__システムの時刻を設定__する場合

などが該当します。

しかし、上記のようなプロセスを実行する際に特権すべてを与えてしまうと、プロセスに__脆弱性__があった場合に、不正な操作によりプロセスが持っている権限を悪用され、__システムに悪影響を与える__可能性があり、セキュリティの観点であまり良くありません。

それに対し、特権をさらに__細分化__し、プロセスに特権すべてを与えるのではなく__最小限にする__ことで、脆弱性が発見されて悪用されたとしてもそのプロセスが必要とする最小限の権限しか奪われないため、__被害の範囲を狭める__ことができます。

この__細分化した特権__が__Capability__です。
Oracle Cloud Infrastructure（OCI）のロード・バランサをフレキシブル・ロード・バランサに変更してみた

2020年12月に Oracle Cloud Infrastructure（OCI）のロード・バランサにフレキシブル・ロード・バランサが実装されました。

それまでのロード・バランサは、10Mbps、100Mbps、400Mbps、8000Mbpsの固定帯域幅から選択する必要があったため、ピークに合わせた帯域を選択する必要があり（かつ選択肢が少なかったこともあり）、柔軟性という意味では少し弱い部分がありました。
フレキシブル・ロードバランサでは、ロードバランサの最小帯域幅と最大帯域幅を自由に設定することで、負荷に応じて柔軟にスケールすることができるようになりました。

フレキシブル・ロードバランサが非常に柔軟性に優れていることに加えて、従来の固定帯域幅のロード・バランサは2021年12月までにフレキシブル・ロードバランサに移行する必要があることから、今年（2021年）は従来の固定帯域幅のロード・バランサからフレキシブル・ロードバランサへの移行が多く実施されることになると思います。

そこで簡単に移行できるのか？、以下のマニュアルを元に確認してみました。
https://docs.oracle.com/en-us/iaas/Content/Balance/Tasks/managingloadbalancer.htm#bandwidth

### 1.従来型ロード・バランサの確認

コンソールで従来型ロードバランサを確認してみます。
シェイプが100Mbpsで固定されていることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694576/97be44e4-d4f0-bf13-164c-a8d692e51b1f.png)


### 2.シェイプの更新

画面左上の［シェイプの更新］ボタンを押します。

シェイプ・サイズの選択で従来型ロード・バランサの固定帯域を変更することもできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694576/725790ae-ff4e-a489-ebb7-03b0b16404cd.png)

今回はフレキシブル・ロード・バランサに変更したいので、［フレキシブル・ロード・バランサの使用］チェックボックスをオンにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694576/51feec5e-538c-4878-777d-c39878a9dd9a.png)

すると、最小帯域幅と最大帯域幅を設定するエリアが現れます。
設定したい帯域幅（Mbps）を入力し、［変更の保存］を押します。
※最小帯域幅と最大帯域幅を同じ値にすれば固定帯域幅となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694576/03d3150f-b338-c3bf-1ddd-e9129c1fb5cf.png)

現在のすべての接続は更新プロセス中にリセットされます。
最大1分かかるようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694576/4ae57efc-ad40-e1c5-2e35-f2aedabb780a.png)

### 3.フレキシブル・ロード・バランサの確認

更新作業終了後、フレキシブル・ロード・バランサに変更されていることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694576/9998e329-ece0-8ea5-426b-6d1fbfafb7c5.png)

IPアドレスも従来のままで、とても簡単に変更できることが確認できました。
Dockerとは？

# Dockerとは
`仮想化技術`のひとつ
Docker社が開発した`コンテナ型の仮想環境`を作成、配布、実行するためのプラットフォーム

### 仮想化とは、
1台の物理サーバーを複数の`仮想的なサーバーに分割して利用する`仕組みのこと

## Dockerを使うと
- パソコンやサーバーに`仮想環境`を作り、その上でWebサーバーやデータベースなどを動かすことが可能
- それぞれの`仮想サーバー`で個別にOSやアプリケーションを実行することが可能で、独立したサーバー環境として利用することが可能

##Dockerを使用するメリット
1. Webサーバーやデータベース本体やその設定内容を`ファイル化`できる
2. そうしてファイルを他の人に配布することで、`誰でも同じ環境を構築`可能
3. 作成した`環境を配布`しやすい

## 具体的には
>
開発環境(Windows上)では動いていたけど
Linux(Microsoft WindowsとMacOSの無料の代替物)で動かなかった

上記のようなケースも、開発工程からDockerを活用していくことで防ぎやすくなる

---

開発工程の中で使っていた環境をそのまま本番環境に持っていくことも可能となるため、
環境差分が少なく、環境による問題を減らすことができる
MySQL Installerで「No packages found」が表示された場合の対処法

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463831/1b6b1c93-767d-77f1-b93e-270a836918c7.png)

結構時間取られたので備忘録

# 結論
1. すでにインストール済みの MySQL Installer のアンインストール
2. 2つ目のインストーラ（mysql-installer-community-8.0.23.0.msi）からインストール

自分の場合、以前 MySQL Workbanch のインストールのため MySQL Installer を使用していたので、「設定」→「アプリと機能」からアンインストールしてから試すとエラーなく進めました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463831/652a5173-f5f5-7662-8be5-0e2a0f66103e.png)

# 参考記事
https://stackoverflow.com/questions/65772865/mysql-installer-did-not-find-packages-in-the-current-bundle-suitable-for-install
Cでよくある非同期関数のコールバック関数でラムダ導入子有りのラムダ式を使えるようにしたい

## ことの発端

たまに、というか稀にOSやライブラリのAPIでコールバック関数を引数とする所謂非同期関数があったりする。
例えば、こんな感じ

```cpp
extern "C" int asyncfunc(int p1, int p2, void* refcon, void(*callback)(void*, int));
```
とりあえず、この記事で ```asyncfunc```は p1 と p2 を加算したものを暫く経過してからコールバック関数に渡す非同期関数とします。

さて、MacintoshのToolboxでお馴染み（古い）の refcon が出てきましたが、こいつはコールバックを呼び出す際にそのまま透過して受け取れるポインタで、一般的には何らかのオブジェクトのポインタを渡したりします。（上記の例だとコールバック関数の第１仮引数がrefconになります）
大概Cタイプの非同期関数ってこんな感じじゃないかなと思います。

で、今どきだとラムダ式使ってこんなコードを書いてみたくなりますよね。

```cpp:動作します
asyncfunc(1, 2, nullptr, [](void*, int resp){
   const int n = 10;
   std::cout << resp * n << std::endl;
});
```

おっと、```const int n = 10;```は外に出したいぞ。

```cpp:コンパイルエラー
const int n = 10;
asyncfunc(1, 2, nullptr, [=](void*, int resp){
   std::cout << resp * n << std::endl;
});
```

残念ながら、これはコンパイルエラーになります。

```
error: cannot convert 'main()::<lambda(void*, int)>' to 'void (*)(void*, int)' for argument '4' to 'int asyncfunc(int, int, void*, void (*)(void*, int))'
```

外部変数をキャプチャしちゃうとダメなんです。
この辺、詳しい記事は他にもあるんじゃないかと思いますので割愛します.
で、仕方なく static 関数を定義してオブジェクトを引き回したりするのですが、この手の非同期関数が多くなるとコピペの嵐になるので、何とかできないものかと考えてみました。

## 条件的なやつ

* 非同期関数は必ずコールバック関数を呼び出す（中断するとコールバック関数を呼ばないとかナシ）
* ラムダ式のキャプチャ並びはコピーのみとする（参照にすると生存期間がややこしい）
* 非同期関数は refcon を受け取りコールバック関数にパスしてくれる


## 書いてみた

```cpp
#include <iostream>
#include <tuple>
#include <functional>
#include <thread>
#include <sstream>

extern "C" void asyncfunc(int p1, int p2, void* refcon, void(*callback)(void*, int)) {
  /* std::thread がメモリリークしますが、テストコードなので勘弁してください */
  new std::thread([=](){
    std::this_thread::sleep_for(std::chrono::seconds(2));
    callback(refcon, p1 + p2);
  });
}

template <int N, typename FUNCTION> class staticify;

template <int N, typename RESULT, typename ...ARGS>
  class staticify<N, RESULT (ARGS...)>
{
public:
  using F_RES   = RESULT;
  using F_FUNC  = std::function<RESULT(ARGS...)>;
  using F_TYPE  = RESULT(ARGS...);

private:
  struct wrap_t {
    F_FUNC f;
  };

  F_FUNC  m_func;

  static F_RES sfunc(ARGS ...args){
    auto params = std::tuple<ARGS...>(args...);
    auto w = reinterpret_cast<wrap_t*>(std::get<N>(params));
    auto f = w->f;
    delete w;
    return f(args...);
  } 

public:
  staticify(F_FUNC f): m_func(f) {}
  void* refcon() { return new wrap_t{ .f = m_func }; }
  static F_TYPE* callback() { return &sfunc; }
};

void test(int n) {
  auto st = staticify<0, void(void*, int)>([=](auto /* refcon */, auto resp){
    std::stringstream ss;
    ss << resp * n << ", ";
    /* 本当はブロッキングしないとアカンけど勘弁してください */
    std::cout << ss.str();
  });
  asyncfunc(1, 2, st.refcon(), st.callback());
}

int main(void) {
  std::cout << "before test()" << std::endl;
  test(2);
  test(10);
  test(3);
  test(6);
  std::cout << "after test()" << std::endl;
  std::this_thread::sleep_for(std::chrono::seconds(5));
}
```

```staticify``` のテンプレート第１引数はコールバック関数の第```N```引数に ```refcon``` が入ってくるという大切な指示で、間違えると爆発します。

## 振り返り

* もうちょいうまくやれば、C++17以降のクラステンプレートのテンプレート引数推論を使ってシンプルに書けそう。
* ```wrap_t``` の取り回しなんかは罪悪感しかない。。。
* テンプレートの特殊化やってるけど、これで合ってるのか？　もうちょい考えるところはないのか？
* 最近はCの非同期関数使うケースなんて少ないだろうから誰得？
* ```asyncfunction``` そのものを良い感じに変換できるクラス作ればもっと良いかも。
DataRobotで画像認識を試してみた

## 概要
[DataRobot](https://www.datarobot.com/jp/)はデータファイルをドラッグアンドドロップし数クリックで機械学習予測モデルを完成できるツールです。
実はDataRobotも画像認識のモデルを生成することができるのでそちらの手順を確認していきます。
今回は今や外出する際の必需品となったマスクの装着有無を判定するモデルを作ってみます。

## 学習用データセットの作成
学習用のデータはZip形式でアップロードします。
※データセットは[Kaggle](https://www.kaggle.com/ashishjangra27/face-mask-12k-images-dataset)から拝借しました。

```
mask.zip
│  mask.csv
│
├─WithMask
│  image01.png
│  image02.png
│  image03.png
│
└─WithoutMask
   image04.png
   image05.png
   image06.png
```

CSVの中身は以下のような形で実際の画像ファイルへの相対パスとマスク判定の答え（ラベリング）をbooleanで記載します

```csv
path,is_mask
WithMask/image01.png,TRUE
WithMask/image02.png,TRUE
WithMask/image03.png,TRUE
WithoutMask/image04.png,FALSE
WithoutMask/image05.png,FALSE
WithoutMask/image06.png,FALSE
```

上記のフォルダ構成をZipで固めてDataRobotにアップロードするとデータセットのメタデータや、データ品質が確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/ad3fc863-164c-d952-2a56-ef8c01efad6c.png)

### モデルの作成
モデルの作成はいたって簡単で、ターゲットとなる特徴量を指定して「開始」をクリックするだけです。
少し待っていると複数のモデルが作成され、精度順に並び変えてくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/5d56d31b-56b1-eb31-3522-4faff134cdc4.png)

今回はデプロイ推奨のElastic-Net Classifier (L2 / Binomial Deviance)を見ていきます。
モデルを選択するとそのモデルの評価や、解釈を確認することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/4098ae75-8019-f1e7-89fb-c227f7850b72.png)
ROC曲線や

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/fc84922f-a0de-3f7b-a276-49a6ca3cfa59.png)
アクティベーションマップ（AIがどこを見ているか）も確認できます。

## モデルの使用
DataRobotで作成したモデルはデプロイしないと予測処理に使用することができません。
先程のモデルの「予測」タブからデプロイを実施します。
※デプロイ可能数は契約内容によって異なりますので要確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/5c26130f-dae9-2f58-cfd2-1eda67cf0b8e.png)

デプロイするとモデルへのエンドポイントが払い出され、API経由で予測処理が使用可能になります。ブラウザからの予測も可能なので今回はブラウザから試してみます。

以下の構成でZipファイルを作成します

```
prediction.zip
│  prediction.csv
│  WithMask.png
```

WithMask.png
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/1534bfe2-5722-cdf1-5d71-34518cd0a417.png)

prediction.csv

```
path
WithMask.png
```

作成したZipファイルをアップロードし予測を開始します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/ced532b7-b2e7-3293-18e0-e37bb26e7264.png)

予測が完了すると結果のCSVファイルがダウンロードされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206219/0b18492b-6806-eb49-b511-b5b6fe5682ea.png)
99.9%以上の確率でマスクを着けていると判定されました！

## まとめ
非常に高精度のモデルが数クリックで作成できてしまいました。
画像を扱う分析なので多少アップロードやモデル作成に時間がかかりますが、動画からフレームを切り取って施設に入る際のマスク検知などに活用できそうだなと感じました。
【Android】ボタンの色や形を動的に変更する

xml上での設定ではなく、ボタンの角丸・輪郭・押下時のレイアウト変更を動的に設定する方法のメモ。

# 手順
xmlでボタン作成

```activity_main.xml
<androidx.appcompat.widget.AppCompatButton
    android:id="@+id/button"/>
```

kotlin内でレイアウト定義

```MainActivity.kt
val drawable = GradientDrawable()

//グラデーションにしたい時
//val drawable = GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, intArrayOf(Color.parseColor("#77ccff"), Color.parseColor("#88ddff")))

//ボタンの色指定
drawable.color = ColorStateList.valueOf(Color.parseColor("#99eeff"))

//ボタン押下時・通常時で色を変更したい時
//drawable.color = ColorStateList(
//    arrayOf(intArrayOf(android.R.attr.state_pressed), intArrayOf()),
//    intArrayOf(Color.parseColor("#88ddff"), Color.parseColor("#99eeff"))
//)

//角丸
drawable.cornerRadius = 200f

//輪郭
drawable.setStroke(6, Color.parseColor("#77ccff"))

//上記で設定したdrawableをボタン背景に設定
binding.button.background = drawable
```
ローカルに追跡ブランチを持たずに新規ブランチを生成するエイリアスを作ってみた

# 動機

こちらのツイートを見て「確かに…」と思ったので、サクッと実行するためのエイリアスを作ってみた。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Git無意識&amp;&amp;手癖で触ってるから気づかなかったけど実はmasterブランチを手元にチェックアウトする必要ないな。git fetch origin &amp;&amp; git checkout -b new-branch origin/masterからのgit push -u origin new-branchで良い。</p>&mdash; Toshiyuki Takahashi (@tototoshi) <a href="https://twitter.com/tototoshi/status/1367369992547618818?ref_src=twsrc%5Etfw">March 4, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

追記(2021-03-04): デフォルトブランチ、追跡ブランチ等の名称を変更しました。

追跡ブランチ(tracking branch)とはリモートサーバの状態をローカルにコピーして追従するためのブランチです。
基本的には追跡ブランチを最新の状態にし(pull)、そのブランチから新しい機能追加・修正用のブランチを作ります。
しかし、最新の状態にし忘れてブランチを作ってしまったり、ローカルで変更したものをうっかり追跡ブランチ上でコミットしてしまったりするとリモートの状態とずれてしまうため事故が起こりやすいのも欠点です。

## エイリアスを作るコマンド

デフォルトブランチとは開発時にメインとなるブランチのことで、 `master` だったり、 `develop` や `development` などプロジェクトによってどのブランチがデフォルトなのかは違うため、以下のコマンドを使う前にそれぞれの環境に合わせて読み替えていただきたいです。

`origin` : リモートサーバーの名前。 `git remote -v` などで表示される。
`master` : デフォルトブランチ名。


```
$ git config --local --add alias.nb '!f(){ [ $# -eq 0 ] && echo "Usage: git nb <branch>" && exit; git fetch --tags --prune origin && git switch -c $1 origin/master; };f'
```

作成したエイリアスは次のように使う。

```
$ git nb feature/something
```

エイリアス名 `nb` は new branch として適当につけてますが、使いたい人が打ちやすい名前にすれば良いと思います。

## 解説

コマンドの部分はこんな意味。

- `git config --local` : 現在のプロジェクトの設定を表示したり、更新したりする。自分用の全プロジェクト向けの共通設定は `--global` などで定義可能。
- `--add alias.nb` :  `alias` 設定グループに `nb` を追加する。 `alias` 設定グループに指定した値は `git nb` のようにエイリアスとして追加される。

エイリアスに指定した文字列は `!` で始まる場合シェルスクリプトとして認識される。
この場合、 `f(){ ... }` で関数 `f` を定義して、最後に `f` で実行しているので、引数を含めて実際には `f feature/something` として実行される形となる。

`f` の内容は次のような構成になっている。

- `[ $# -eq 0 ] && echo "Usage: git nb <branch>" && exit;` : 引数がなかったらUsageを表示して終了する。
- `git fetch --tags --prune origin` : タグと削除されたブランチを含め、リモートの最新状態を取得する
- `git switch -c $1 origin/master` : リモートブランチ `origin/master` を基準として、新しいブランチを作成しブランチへ移動する
Java org.springframework.web.httprequestmethodnotsupportedexception: request method 'post' not supported

#DeleteとUpdateメソッドを実行すると
`org.springframework.web.httprequestmethodnotsupportedexception: request method 'post' not supported`というエラーが出る
#解決法
```application.properties
spring.mvc.hiddenmethod.filter.enabled=true
```
を書くだけです。
amplifyの作法 その20

#概要

amplifyの作法、調べてみた。
練習問題やってみた。

#練習問題

ナップザック問題

#参考にしたページ。

https://qiita.com/gorogoroyasu/items/8498f660876c7fdac120

#サンプルコード

```
from amplify import BinaryPoly, gen_symbols, sum_poly, BinaryQuadraticModel, Solver, decode_solution
from amplify.constraint import less_equal
from amplify.client import FixstarsClient

a = [3, 4, 6, 1, 5] 
c = [6, 7, 8, 1, 4] 
q = gen_symbols(BinaryPoly, 5)
f = a[0] * q[0] + a[1] * q[1] + a[2] * q[2] + a[3] * q[3] + a[4] * q[4] 
print(f) 
h0 = less_equal(f, 12)
print(h0)
h1 = -0.1 * (c[0] * q[0] + c[1] * q[1] + c[2] * q[2] + c[3] * q[3] + c[4] * q[4])
print(h1)
H = h0 + h1
model = BinaryQuadraticModel(H)
solver = Solver(client)
result = solver.solve(model)
values = result[0].values
print(values)
print(f"q = {decode_solution(q, values)}")

```


以上。
amplifyの作法 その19

#概要

amplifyの作法、調べてみた。
練習問題やってみた。

#練習問題

サイコロ、振ってみよ。

#サンプルコード

One-hot制約を使う

```
from amplify import BinaryQuadraticModel, Solver, decode_solution
from amplify.client import FixstarsClient
from amplify import BinaryPoly, gen_symbols, sum_poly
from amplify.constraint import equal_to

q = gen_symbols(BinaryPoly, 6)
f = equal_to(sum_poly(q), 1)
print(f)
model = BinaryQuadraticModel(f)
solver = Solver(client)
result = solver.solve(model)
for solution in result:
	values = solution.values
	print(decode_solution(q, values))
 

```

以上。
HTML~フォーム作成③~

前回の記事labelタグのフォーム作成について学びましたね！
次は、boxについて学んで行きましょう😎

#①ドロップダウンリスト
```index.html
<label for="like">あなたの好きな食べ物は？？</label>
<select id="like">
  <option>人参</option>
  <option>ピーマン</option>
  <option>玉ねぎ</option>
</select>
```

質問のセンスの無さは置いといてブラウザで表示するとこうなるかなと思います👌
![スクリーンショット 2021-03-04 14.35.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1033397/8c969ae3-0e6f-c0fe-176a-5e82abe252d2.png)

はい！ドロップアンドリスト完成です！

最初から選択している状態でスタートしたい場合は、select　の中の一つを選んでselectedを付けるとできます！
![スクリーンショット 2021-03-04 14.46.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1033397/ad1fac7e-3b91-d800-0fd9-bf39ef9e2527.png)

#②チェックリスト

それではチェックボックスを作っていきましょう！

```index.html
<fieldset>
<legend>性別を教えて下さい</legend>
<label><input type="checkbox" name="gender" value="man">男</label>
<label><input type="checkbox" name="gender" value="woman">女</label>
<label><input type="checkbox" name="gender" value="other">その他</label>
</fieldset>
```
ここでタグについての説明をしますね！
fieldset▶ここではlabelのグループ化を図っています！
legend▶labelのタイトルを作っています！

ブラウザ上ではこうなります👍
![スクリーンショット 2021-03-04 16.05.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1033397/6e8cd797-559c-6dbd-ba72-20f07cd01f69.png)
クリックするとチェツクが付きます！

上記したチェックボックスは複数選択の際に利用するものなので、
一つだけ選択させる場合はラジオボタンに書き換えていきましょう！

```index.html
<fieldset>
<legend>性別を教えて下さい</legend>
<label><input type="radio" name="gender" value="man">男</label>
<label><input type="radio" name="gender" value="woman" checked>女</label>
<label><input type="radio" name="gender" value="other">その他</label>
</fieldset>
```
はい！こうすると一つのみの選択に変わります！👍

name属性について解説しますと、
フォーム部品を識別するための名前を指定します。

複数のラジオボタンに同じ部品名を付けることで、1つのグループを作ることができます。
ラジオボタンでは、そのグループの中から1つだけを選択することができるのです！

#③ボタン
次はボタンですね！！
結構簡単なのでちゃちゃっとやっちゃいましょう！

```index.html
<input type="button" value="決定">

<button>決定</button>
```
ね、びっくりするぐらい簡単でしょう😂
ブラウザ上だとこんな感じですね👌
![スクリーンショット 2021-03-04 16.39.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1033397/03f60d79-495e-6b04-f607-c57afcb13f7f.png)

どっちでも記述はいいみたいです👌

ちなみにvalue属性とは、input要素の値を指定する属性。テキスト入力欄などにおいては初期入力値、チェックボックスやラジオボタンにおいては選択した時にだけ送信する値、送信ボタンなどにおいてはボタン名を表す。ようです！
Terraformでmoduleから値を取得する

# すごい謎なんですけど

妙にハマって、触りたくないなーと思いながら1日半放置したので、ここに日本語で残しておきます。

# 前提なんですけど

こうやって、`sources/asg/main.tf`にあるモジュールを呼び出しています。

```tf:asg.tf
module "my_asg" {
  source = "./sources/asg"
}
```

`sources/asg/main.tf`では、こんな感じでAuto Scaling Groupを定義しています。

```tf:sources/asg/main.tf
resource "aws_autoscaling_group" "asg" {
  .......
}
```

親ファイル内で、この`my_asg`で定義されたARNを取得しようとします。

```tf:asg.tf
resource "aws_ecs_capacity_provider" "my_cp" {
  auto_scaling_group_provider {
    auto_scaling_group_arn = # ここで定義したARNを使いたい！
  }
}
```

# で、どうしたかと言うと

## モジュールで定義しているリソースにアクセスするには、moduleを使う

子モジュールで定義された内容には`module`を用いてアクセスします。多分もっと適切なドキュメントあると思うんですけど、僕はここで確認しました。

https://www.terraform.io/docs/language/values/outputs.html#accessing-child-module-outputs

> In a parent module, outputs of child modules are available in expressions as module.<MODULE NAME>.<OUTPUT NAME>.

追記：コメントでもっと適切なドキュメントをご教示いただきました！ありがとうございます！

https://www.terraform.io/docs/language/modules/syntax.html#accessing-module-output-values

マジで適切だった。

## モジュール内で定義されてる内容を利用する時は、outputを使う

Terraform歴が浅いからですかね、普通に`resource`はアクセス可能なのかと思ってましたがどうやらそれは叶わず。きちんと、`output`ブロックで定義してやります。

# 結果なんですけど

`sources/asg/main.tf`の方に、`output`ブロックを定義します。

```tf:sources/asg/main.tf
output "arn" {
  value = aws_autoscaling_group.asg.arn
}
```

親モジュールから、アクセスします。

```tf:asg.tf
resource "aws_ecs_capacity_provider" "my_cp" {
  auto_scaling_group_provider {
    auto_scaling_group_arn = module.my_asg.arn # ここで定義したARNを使ってます！！
  }
}
```

こんな感じです。
依存関係出てくるので、必要に応じて`depends_on`使ってやってください。
Discord.js 技術メモ #1

#アクティビティを設定する

Botのアクティビティを設定する

```javascript
client.on("ready", () =>
{
  client.user.setActivity("Yuki | https://discord.gg/CN4dYAVYXW", {type: 'PLAYING'});
});

```

#ファイル読み込み

ファイルを読み込み配列に入れる

```javascript
const fs = require('fs');
const readline = require("readline");
let readdata = [""];

var stream = fs.createReadStream("yuki/read.txt", "utf8");
var reader = readline.createInterface({ input: stream });
reader.on("line", (data) => {
 readdata.push(data)
})
```

#ファイル書き込み

ファイルを書き込む配列に入れる

```javascript
const fs = require('fs');

fs.writeFileSync('yuki/write.txt', 'data');
```

#特定のチャンネルにメッセージを送信する

特定のチャンネルにメッセージを送信する

```javascript
client.channels.cache.get('000000000000000000').send({embed: {
    author: {
      name: "結貴 - Yuki による宣伝",
      icon_url: client.user.avatarURL()
    },
    description: "公式サーバーの招待URL \n https://discord.gg/CN4dYAVYXW",
    color: 10181046,
    timestamp: new Date(),
    footer: {
      icon_url: client.user.avatarURL(),
      text: "結貴 - Yuki"
    }
  }}
)
```

#メンバーにロールを付与する (Role Name)

メッセージの送信者にロールを付与する

```javascript
 const member = message.guild.members.cache.find((member) => member.id === message.author.id)
 member.roles.add(role)
```

#メンバーからロールを剥奪する (Role ID)

メッセージ送信者からロールを剥奪する

```javascript
 const role = message.guild.roles.cache.find((role) => role.id === "000000000000000000")
 const member = message.guild.members.cache.find((member) => member.id === message.author.id)
 member.roles.remove(role)
```

#わからないことがあったら

https://discord.gg/CN4dYAVYXW

ここで質問を受け付けております
【PHP】条件分岐について

##読むのをオススメする人
<strong>・</strong>PHPをはじめたけど条件分岐の仕方がわからない人
<strong>・</strong>条件分岐は知っているけど、どの様に条件分岐が動いているか分かってない人

##条件分岐とは
<p>条件分岐とは、「もしも…」です。</p>
<p>通常は、上から下に全てのプログラムが動く様になっていますが、<strong>条件分岐</strong>を使うと「もしも1」なら1の条件、「もしも2」なら2の条件を実行するという様に条件によってプログラムを動作するかしないかを決める事ができます。</p>
</hr>
##具体例
####例文
`総勢10人の会社の会議でアプリケーションを作ることになりました。
しかし、アプリケーションの内容で揉めています。
そこで、10人で多数決を取ることに`

<span>もし、</span>
<ul>
    <li><strong>Yesが5人以上</strong>であればアプリを作る</li>
    <li><strong>Yesが4人〜3人</strong>なら再検討</li>
    <li><strong>Yesが2人以下</strong>であればアプリを作らない</li>
</ul>

<p>これを<strong>条件分岐</strong>を使い表す事ができます。</p>

```php:test.php
<?php
    if (10 >= 5) {
        //もし、Yesが5以上の場合
        print 'アプリを作る'.PHP_EOL;
    } elseif (4 >= 3) {
        //もし、Yesが4人以下・3人以上の場合
        print 'アプリを作るかを再検討する'.PHP_EOL;
    } else {
        //もし、Yesが2人以下の場合
        print 'アプリは作らない'.PHP_EOL;
    }
```

この様に書くことにより先ほどの状況をプログラムで表す事ができます。

##書き方の説明

```php:説明
<?php
    if (条件) {
        //ifの条件が一致すれば
        ここに記述された事が実行される
    } elseif (条件) {
        //elseifの条件が一致すれば
       ここに記述された事が実行される
    } else {
        //if・elseif以外の条件の場合
        ここに記述された事が実行される
    }
```
条件分岐は、この様に書かれています。
</br>
なので、もしあなたが条件分岐を使いたい時は、上記の通りに書いていけば使用できます。

最後まで読んでいただきありがとうございます。

</br>
<p><strong>次におすすめの記事</strong></p>
[(現在制作中)FizzBuzzの書き方と説明](#)
Flutter bundle IDはどこで確認できる？

#Flutterアプリ、bundle IDはどこで確認する？
アプリ初心者にとっては「bundle ID」がそもそも何なのかわからなかったりする。。
**※AndroidではPackage nameと呼ばれてたりもします！**

Flutterはプロジェクトを作成した時点で、**「デフォルトのbundle ID」**が作成されているので、それを確認してみましょう！！

また、bundle IDを変更する場合も同様の場所からできます。

##Android
`android/app/build.gradle`で確認できます。

※build.gradleは`android/build.gradle`にも存在するので注意！
![スクリーンショット 2021-03-04 15.29.35.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/9f07cee6-1c04-be22-4cdc-9f7be1f8fa6a.jpeg)


```gradle
// 省略
 defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.example.myApp" // これがAndroidのbundle ID
        minSdkVersion 16
        targetSdkVersion 28
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }
// 省略
```

##iOS
Xcodeで`ios/Runner.xcodeproj`を開いて確認します。
![スクリーンショット 2021-03-04 15.39.44.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/df87f9d8-0668-bc9e-802a-e1ed9fd08677.jpeg)

`Runner`をクリックして`General`の項目で確認できます。
All About ACS: 「WARNING: An illegal reflective access operation has occurred」は ACS 1.1.8.3 で対応済み

#「WARNING: An illegal reflective access operation has occurred」は ACS 1.1.8.3 で対応済み

Java 8 と 9 以降の非互換性により Java 8 では問題なくても、Java 9 以降で実行すると、「WARNING: An illegal reflective access operation has occurred」 が発生する場合があります。

https://docs.oracle.com/javase/jp/14/migrate/index.html#JSMIG-GUID-7BB28E4D-99B3-4078-BDC4-FC24180CE82B

ACS でも、この現象が発生していました。
IBM への問い合わせの回答は「動作には問題がないので無視してください。表示を抑制したければ '--illegal-access=deny' を付けてください」でした。

こんな感じですね。

```
java -Xmx1024m --illegal-access=deny -jar acsbundle.jar
```

```
Start_Program\Windows_x84-64\acslaunch_win-64.exe --illegal-access=deny 
```


最近、Java 9 以降で ACS を実行しても、この警告が出ないことに気が付きました。

## ACS 1.1.8.3 以降では発生しない

テストすると ACS 1.1.8.3 以降であれば発生しないようです。

```
C:\acs\Java\jdk-15.0.2\bin>java -jar \acs\acs1186\acsbundle.jar

C:\acs\Java\jdk-15.0.2\bin>java -jar \acs\acs1185\acsbundle.jar

C:\acs\Java\jdk-15.0.2\bin>java -jar \acs\acs1184\acsbundle.jar

C:\acs\Java\jdk-15.0.2\bin>java -jar \acs\acs1183\acsbundle.jar

C:\acs\Java\jdk-15.0.2\bin>java -jar \acs\acs1182\acsbundle.jar
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.ibm.iaccess.base.AcsReflectionUtil$FieldGetter (file:/C:/Users/USER01/AppData/Local/Temp/acs.jar_cache18263177620559265887.dir/4.dat) to field java.security.Provider$Service.aliases
WARNING: Please consider reporting this to the maintainers of com.ibm.iaccess.base.AcsReflectionUtil$FieldGetter
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

C:\acs\Java\jdk-15.0.2\bin>java -jar \acs\acs1181\acsbundle.jar
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.ibm.iaccess.base.AcsReflectionUtil$FieldGetter (file:/C:/Users/USER01/AppData/Local/Temp/acs.jar_cache7552469412634189855.dir/4.dat) to field java.security.Provider$Service.aliases
WARNING: Please consider reporting this to the maintainers of com.ibm.iaccess.base.AcsReflectionUtil$FieldGetter
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
```
「WARNING: All illegal access operations will be denied in a future release」と「将来動かなくなる」と脅されて良い気持ちでない人で、警告抑制のためのオプションを付けるのが嫌な人は、ACS を最新版に更新してみてください。

***
2021-03-04 作成
***
「All About ACS」では IBM i に対する新しいクライアント「IBM i Access Client Solutions」の情報をいろいろ提供していきます。
[記事一覧はこちら](http://qiita.com/6onoda/items/2dc925586d8d3b8644f2)で確認いたけます。

許可の無い転載を禁じます。
この記事は筆者の個人的な責任で無保証で提供しています。
当記事に関してIBMやビジネスパートナーに問い合わせることは、固くお断りします。
***
【個人的備忘】Info.plistのローカライズ/アプリの言語を日本語のみにする

## Info.plistのローカライズ
（0. PROJECTのLocalizationsで対象の言語を追加しておく）
1. 「InfoPlist.strings」のファイル名でStrings Fileを新規作成する
2. 作成したInfoPlist.stringsファイルの「Localization」で言語を選択する
複数言語選択しないと、端末の設定で、アプリごとに言語を選択できる項目が表示されない。
3. 言語ごとのファイルが自動生成されるので、生成されたファイルに内容を記載する
例）Info.plistのBundle nameはプライマリ言語で記載し、
それ以外の言語ファイルに`CFBundleName = "（アプリ名）";`と記載

## アプリの言語を日本語のみにする
Info.plistで以下を追加・変更
Localization native development region: Japan
Localizations: Japanese (ArrayのItem 0に設定）
【テストコードで使用するFakerについて】


テストコードを実行する際、FactryBot内で活躍するFakerについて、
ちょっとした学びがあったので備忘録として残す。

Fakerは無作為に半角数字、半角英語の組み合わせを作ってくれるもの。
パスワードのバリデーションとして、「英数字を含む」という設定が多々見受けられると思う。
基本的にはFakerをそのまま使えば問題ないが、稀に数字のみ、もしくは英語のみという組み合わせになることもある。
そうなってしまうと、バリデーションではじかれてしまうことになる。

そこでFakerに"1a"などの文字列をくっつけてやる。
そうすることで必ず"1a"という数字、英語を含む組み合わせを作ることができる。

```
{'1a' + Faker::Internet.password(min_length: 6)}
```
このような形とする。
HalideとCUDAの連携

Halideについては[こちら](https://halide-lang.org/)

今回はCUDA前提の小話を書きます。
例えば、Halideでこういったスタティックライブラリを作ったとしましょう。

```cpp
void GenerateCPU()
{
  Halide::ImageParam input(Halide::type_of<int>(), 1);
  Halide::Func f;
  Halide::Var x;
  f(x) = x + 1;

  f.compile_to_static_library("libsample", {input}, "sample");
}
```

関数`sample`を、すでに確保してあるメモリ内容に適用することを考えます。

CPU側のメモリなら、Halideではこう書けます。

```cpp
#include <HalideRuntime.h>
#include <HalideBuffer.h>
#include "libsample.h"

void funcCPU()
{
  int h_src[10];
  int h_dst[10];

  for(int i = 0; i < 10; ++i)
    h_src[i] = i;

  Halide::Runtime::Buffer<int> hal_src(h_src, 10);
  Halide::Runtime::Buffer<int> hal_dst(h_dst, 10);

  sample(hal_src, hal_dst);
}
```

`Halide::Runtime::Buffer`のコンストラクタにポインタをとるものがあるので、これを使えば問題ありません。
(`Halide::Buffer`でも同様です)

では、すでに確保してあるGPUメモリを使うにはどうしたらよいのでしょうか。
上述のポインタをとるコンストラクタは、CPUメモリ用のものであり、そのままGPUメモリを指すポインタを渡しても動作しません。
正しくは、以下のように書きます。

```cpp
void GenerateGPU()
{
  Halide::ImageParam input(Halide::type_of<int>(), 1);
  Halide::Func f;
  Halide::Var x;
  f(x) = x + 1;
  
  Var xo, xi;
  f.gpu_tile(x, xo, xi, 32, Halide::TailStrategy::GuardWithIf);
  f.compile_to_static_library("libsampleGPU", {input}, "sampleGPU", Halide::get_host_target().with_feature(Halide::Target::CUDA));
}
```

```cpp
#include <cuda_runtime.h>
#include <HalideRuntime.h>
#include <HalideBuffer.h>
#include <HalideRuntimeCuda.h>
#include "libsampleGPU.h"

void funcGPU()
{
  int h_src[10];
  int h_dst[10];

  for(int i = 0; i < 10; ++i)
    h_src[i] = i;

  int* d_src;
  int* d_dst;
  cudaMalloc(&d_src, sizeof(int)*10);
  cudaMalloc(&d_dst, sizeof(int)*10);
  cudaMemcpy(d_src, h_src, sizeof(int)*10, cudaMemcpyHostToDevice);

  Halide::Runtime::Buffer<int> hal_src(nullptr, 10);
  hal_src.device_wrap_native(halide_cuda_device_interface(), (uint64_t)d_src);
  Halide::Runtime::Buffer<int> hal_dst(nullptr, 10);
  hal_dst.device_wrap_native(halide_cuda_device_interface(), (uint64_t)d_dst);

  sampleGPU(hal_src, hal_dst);

  cudaMemcpy(h_dst, d_dst, sizeof(int)*10, cudaMemcpyDeviceToHost);
}
```
ちょっと手間になりますが、`device_wrap_native`を用いるとうまくできます。
スタティックライブラリ生成時に`gpu_tile`指定をしておくことも忘れずに。
ミソはコンストラクタに`nullptr`を渡してやることでしょうか。
`halide_cuda_device_interface`に当たる部分は、ここに該当するヘッダがいろいろ含まれているので、CUDAだけではなくOpenCLやMetalにも対応可能だと思われます。

メモリコピーは思ったよりも速くありません。高速なプログラムを書くためにも、コピーは可能な限り避けましょう。
ネットワーク設定をDOSで切り替える

# この記事でできること
* IPアドレスの固定⇔自動取得をDOSコマンドで切り替える
* DNSサーバアドレスの固定⇔自動取得をDOSコマンドで切り替える
* プロキシサーバの設定をDOSコマンドでオフにする
* 上記をbatファイル化することで、自動で切り替えられるようにする

# なぜこの様なことをしたか
* 昨今のテレワーク化で、自宅と事務所でネットワーク設定を頻繁に変えることになったので、
  簡単に切り替えれるようにしたかった

# ◆各DOSコマンド
* 下記はおそらく管理者用のDOSで実行する必要があると思います。

## IPアドレスを自動的に取得する
```
netsh interface ipv4 set address "イーサネット" dhcp 
```

## IPアドレスを固定にする
```
netsh interface ipv4 set address "イーサネット" static <固定のIP> <サブネットマスク> <デフォルトゲートウェイ>
```

## DNSサーバのアドレスを自動的に取得する
```
netsh interface ipv4 set dns "イーサネット" dhcp 
```

## DNSサーバのアドレスを固定にする
```
netsh interface ipv4 set dns "イーサネット" static <DNSサーバIP> primary 
```

## プロキシサーバをオフにする
```
reg add "HKEY_CURRENT_USER¥SOFTWARE¥Microsoft¥Windows¥CurrentVersion¥Internet Settings" /f /v ProxyEnable /t reg_dword /d 0
```

# ◆batファイルを管理者権限で実行する
* 上記各コマンドは管理者用DOSで実行する必要があるのですが、イチイチ管理者用DOSを起動するのが面倒でした。
* 必要に応じて上記のコマンドをbatファイルにして保存しておき、そのbatファイルを管理者権限で実行するためのbatファイルを別途作成しました。

## 管理者権限でbatを実行する
```
powershell start-process XXXXXX.bat -verb runas 
```
ST言語はなんでこんなに資料がないんだ

#ST言語を勉強したかったんだ
私的事情でST言語の勉強をしなければならず、Webや書籍を探していました。
がしかし、**全然情報が少ないじゃないか！！！！**

てなわけで、少しずつST言語についてまとめていきますの備忘録。

#そもそもST言語って何？
ST言語って調べると全然出てきませんが、IEC61131-3と調べると出てきます。
ICE61131-3とは、

* ラダーダイアグラム（LD）
* ファンクションブロックダイアグラム（FBD）
* ストラクチャードテキスト（ST）
* インストラクションリスト（IL）
* シーケンシャルファンクションチャート（SFC）

が含まれる制御関係の言語の総称（国際電気標準会議IECってところが決めたらしい）

それぞれ似ている者の、別に全部理解しなきゃいけないわけじゃないっぽい。
自分はとりあえず今後多く使用するであろう`LD`と`ST`だけ勉強する予定。
（他も使う時が来たらまとめよう。。。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167742/9a2f3a07-27f7-7e71-7b9a-6484cb737989.png)

ラダーってこんなやつ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167742/7e1888c1-6b96-c8e6-9597-ec3fede8de30.png)
ST言語ってこんなやつ

#ST言語は高級言語
ST言語はC言語に非常に似ている。
高級言語ってのは人間が使う言葉に近いやつのことをいうらしく、``C``とか``FORTRAN``もそいつらの仲間。
ベースは``PASCAL``を基に設計されているらしい。

ST言語を使う利点は一目瞭然で、言語で書けることだ。
言語で書けると複雑な条件分岐やら多項式の処理やらが簡単にできる。

LDではそううまくはいかず、多項式を書こうと思うと二項に分解したりそれぞれの演算結果を
一時的にメモリに保存したりと色々やっかいなことが生じる。
逆を返せばLDのいいところは視覚的に見れることだ。


#C言語に直せばわかりやすのでは？
ということで、相関表を作ってみた。もっとあると思うが、全部はかけないので一部基礎的な部分をまとめた。

| C | ST |
|:-:|:-:|
| =  | :=  |
| -  |  - |
| +  |  + |
| *  |  * |
| /  |  / |
| %  |  MOD |
| &  |  AND |
| ｜  |  OR |
| ^  |  EXOR |
| ~  |  NOT |
| ++  |   |
| --  |   |

あぁ、ほぼ一緒だ。。。
ただ、インクリメント・ディクリメントはSTにはないみたい。

#じゃあ何が違うって言うんだ！
違いはあります。どっちかというとPythonの文法に近そう。
特にインデントでブロックを表すのはPythonと同じ。

###IF文
Cでは

````
if(条件文){
<実行式>
｝
````
STでは

````
IF <条件> THEN
 <実行式>
END_IF
````

###CASE文
CではCASE文はなく、Switchとなり

````switch.c
switch(式){
  case 定数1:
    式が定数1の時に実行する処理;
    ...
    break;
  case 定数2:
    式が定数2の時に実行する処理;
    ...
    break;

  default:
    どの定数にも一致しない時に実行する処理;
    ...
}
````

STでは

````
CASE 整数式or整数値 OF
  <整数選択値1> : <実行式>
  <整数選択値1> : <実行式>
  <整数選択値1> : <実行式>
ELSE
  <上記以外の時の実行式>
END_CASE;
````
となる。これはPythonのほうが文法的に近いかも（PythonのCASE文は調べてみて）


###FOR文
Cでは`for(条件文){内容}`となり、
STでは

````
FOR ~ TO ~ BY
  <実行式>
END_FOR
````
になる。これもPythonのほうが近い。
また、Cでいうwhile文に近いものもあり、

````
REPEAT
 <実行式>;
UNTIL
 <条件式(BOOL)>
END_REPEAT;
````
という書き方もできる。

#まとめ
とりあえず大まかな部分をまとめてみたが、どうやらC言語、もしくはPythonを知っている人はSTを簡単に覚えられそうだ。
最も、これを制御に組み込むとなると話は別なのだが。。。

次回はより制御寄りのまとめをしようと思う。
【個人的備忘】CocoaPodsを使用してGoogleMobileAdsをインポートする

## 1. CocoaPodsインストール

ターミナル起動
`sudo gem update —-system`
※ruby gemアップデート
`sudo gem install cocoapods`
`pod setup`

※（個人メモ）
cocoapodsについてデフォルトの/usr/binだと書込み権限の問題があったため以下のパスにインストールしているので、アップデートの際は以下のコマンドで行う。
`sudo gem update -n /usr/local/bin cocoapods`

## 2. プロジェクトにPodfile作成してGoogle-Mobile-Ads-SDKインストール

※Xcode閉じておく
`cd プロジェクトのディレクトリ`
`pod init`
※Podfile作成
`vim Podfile`
`i`
※編集モード(insert)
\# Pods for XXの下に
`pod 'Google-Mobile-Ads-SDK'`
`esc`
※編集モード終了
`:wq` もしくは(Shift+z)×2
※保存して終了
`pod install`

※pod updateはPodfile.lockを無視してアップデートを行うコマンド、pod installはPodfile.lockを参照するため勝手にアップデートはされない、インストールを行うコマンド
例）`pod update 'Google-Mobile-Ads-SDK'`

※[!] Unable to add a source with url \`https://cdn.cocoapods.org/` named \`trunk\`.のエラーが出た場合は、
`source 'https://github.com/CocoaPods/Specs.git'`
をPodfileの一番上に追記すると解決する。
さらに[!] CDN: trunk URL couldn't be downloaded: https://cdn.cocoapods.org/CocoaPods-version.yml Response: URL using bad/illegal format or missing URLのエラーがでた場合は、
`pod repo remove trunk`
で解決する。

## 3. Info.plist更新

※Info.plistに以下追加
Key:
`GADApplicationIdentifier`
Type:
`String`
Value:
`AdMobアプリID`

※SKAdNetworkItems キーも追加。
cf）https://developers.google.com/admob/ios/quick-start

※
`<key>GADIsAdManagerApp</key>
<true/>`
上記も追加。（記載しないと"The Google Mobile Ads SDK was initialized without AppMeasurement"のエラーが出るようになりました。2021/06/14追記）

## 4. インポート文
```
import GoogleMobileAds
```

## 5. AdMobになかなか表示されないときの問い合わせ先
https://groups.google.com/g/google-admob-ads-sdk