OmniAICreator/Qiita-1.07M huggingface dataset:
Programmars 問題2個 解説

직사각형으로 별 찍기

import java.util.Scanner;

class Solution {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        int b = sc.nextInt();

       for(int i = 0; i < b ; i ++ ){ // 줄의 개수인 b만큼 반복되도록 작성해주고 반복될 때마다 하나씩 증가한다.(0,1,2에서 끝)
           for(int j = 0; j < a; j++){ //한 줄의 찍힌 별의 개수인 a만큼 반복하도록 작성해주고 반복될 때마다 하나씩 증가한다.
​(0,1,2,3,4)
                System.out.print("*"); // for문이 반복되면서 *이 찍히도록 System.out.print("*"); 로 출력되도록 작성해 준다. 
            }
           System.out.println(); // for문을 빠져나와 표시 위치를 다음 행의 동일 위치로 이동시키기 위해 System.out.println(); 을 작성해 준다.
        }
    }
}
우선 출력된 결과를 보면 별이 찍힌 건 한 줄에 5개씩 총 3줄이 찍혀있고 입력된 값을 보면 a=5, b=3이다.

여기서 보면 a는 한 줄에 찍힌 별의 개수, b는 줄의 개수를 나타낸다고 유추해 낼 수 있다.

그럼 여기서 중복 for문을 사용하면 출력된 값과 동일하게 찍어낼 수 있다.

=======================================================================================================================
ー日本語ー

for(inti=0;i<b;i++){ //行数であるbだけ繰り返されるように作成し、繰り返されるたびに一つずつ増加する。

for(int j = 0; j < a:j++){ //一行の写った星の数であるaだけ繰り返すように作成し、繰り返されるたびに一つずつ増加する。

​System.out.print("*"); //for文が繰り返されながら*が写るようにSystem.out.print("*");と出力されるように作成してくれる。

System.out.println(); //for文を抜けて表示位置を次の行の同一位置に移動させるためにSystem.out.println();を作成してくれる。

まず出力された結果を見れば、星が押されたのは一行に5個ずつ計3列が押されており、入力された値を見ればa=5、b=3だ。

ここで見れば、aは一列に撮られた星の個数、bは列の個数を表すと類推できる。

では、ここで重複for文を使えば、出力された値と同じように印刷することができる。


-----------------------------------------------------------------------------------------------------------------------문자열 다루기 기본

class Solution {
  public boolean solution(String s) {
      boolean answer = true;
    
      if(s.length() != 4 && s.length() != 6)    
              answer = false;   // 길이가 4나 6이 아닌 경우 => false
      for(int i=0; i<s.length(); i++)   // 문자열에 숫자가 아닐 경우 => false
                 if(s.charAt(i) >= 'a')  // charAt은 특정 위치의 문자를 반환, 'a'와 같거나 큰 경우 false
              answer = false;
      return answer;
  }
}

s.charAt(i)  -> string을 문자를 char형으로 변경해준다..
'a' -> 97
'A' -> 65
'0' -> 48

-charAT함수에 대해서-
String a = "apple"
system.out.println(a.charAt(0));
결과는 a
-----------------------------------------------------------------------------------------------------------------------
ー日本語ー

class Solution {
public boolean solution(String s) {
boolean answer = true;

if(s.length() != 4 && s.length() != 6)
answer=false;//長さが4や6でない場合=>false
for(int i=0; i<s.length();i++)//文字列に数字でない場合=>false
if(s.charAt(i)>=「a」)//charAtは特定位置の文字を返還、「a」と同じか大きい場合false
answer = false;
return answer;
}
}

s。charAt(i)->stringを文字をchar型に変更する。
'a' -> 97
'A' -> 65
'0' -> 48

-charAT関数について-
String a = "apple"
system.out.println(a.charAt(0));
結果はa
スマートスイッチいろいろ

我が家のスマートスイッチいろいろです。

![IMGP0015.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/9a63e530-9789-760d-923f-361c7e39add6.jpeg)

一番左が、30年くらい前に買ったSONYのターマー(PT-D4W)で二系統の電源を制御できます。いつもはMac mini G4につないだリモコンユニットでFPGA FMチューナーの電源のON/OFFをしています。リモコンのコントローラーはコンデンサーの液漏れでパターン切れしたのをなおしましたが、もうそろそろダメそうです。

二つ目のは20年くらい前に買った、オーム電機製のリモコンです。「最大800Wまで」のシールが貼ってあります。これは受光処理が甘くて、他のリモコンにも反応します。ルーターの焼き直しの時のON/OFFなどに使っています。

三つ目のは秋月のSSRつかった自作赤外線リモコンモジュールです。これはAVRでSONYの12ビット系で信号でコントロールできす。キムチのケースに入れたのでキムッチと呼んでいます。

最後のが去年買った正真正銘のスマートスイッチHS105です。

リモコン系はMacの自作アプリのアルマジロのお使いやBTOのリモコンモジュールをmrubyなどで制御しています。送信系はいろいろあります。

パソコンやスマホで赤外線のコントロールはが出来ますが、やはり棒のほうが便利な気がします。

alexaを使う方法もあるようですが、我が家はインターネットが消滅しても自立して稼動できるネットワークを構築しているので、論外です。

USBの電源でコントロールできるタップがサンワサプライにあります。以前は二千円ちょっとの商品もあったようなのですが、今は一万円を越える商品しかなく購入していません。ルーターのUSBの電源はGPIOで制御できるので、使えるかもしれないのですが。キムッチを応用すれば作れるとは思うのですが。

おまけ

100V側じゃなくDC側にマイコンとリレーを入れたアダプタ。I2Cでスリープ時間を設定する仕様になっています。

![IMGP0017.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/5522d108-321f-c0c5-3554-fcd0d443b5d8.jpeg)
terraform 再入門②

### ▼ 目的
使いそうなCLIを書いておきます

----

### CLI

#### コマンド群
-  terraform state list : tfstateファイルを参照してリソースを見る
-  terraform state show {\<リソース種別\>.\<リソース名\> }:指定したリソース種別のリソース情報を表示する
    -  eg1: data.aws_ami.app
    -  eg2: aws_instance.app_server
-  terraform state mv \<リネーム前リソース名\> \<リネーム後リソース名\> : tfstateファイルのリソース名を変更する
    -  要点: リソース差分なしにするためにはtfstateファイルの変更及びコードの変更の2つが必要
    -  注意点1: どちらか片方のみの場合、削除&新規作成となるため、必ず両方修正すること
    -  eg1: terraform state mv aws_instance.app_server aws_instance.application_server
-  terraform import \<terraformリソース名\> \<AWSリソースID\> : 管理対象外リソースをtfstateファイルに取り込む
    -  eg. aws_instance.testserver i-00070c7173168c015 (既存EC2をtestesrverの名前でtfstateファイルに取り込む)
    -  要点: 取り込んだあとにコード側にも追加しないと差分として扱われる
-  terraform state rm \<tfstateのリソース名\> : tfstateファイルから対象のリソースを消す
    - 要点: tfstateファイルから管理対象から外したいリソースを消すコマンド
    - 注意点1: コードからも削除しないと新規作成になる
    - 注意点2: あくまでtfstateファイルの操作のため、AWS上のリソースは残る。
- terraform refresh : リソースの情報をtfstateファイルに反映させる
    - 要点: 手でEC2等の設定を変更した際にtfstateファイルに取り込む
    - 注意点1: コードも追従しないと差分として検出される

### Meta引数
詳しくは [こちらの記事を参照](https://qiita.com/donko_/items/0e276b45ddea5e39abd7)
- depends_on
- count (指定回数ループさせられる)
    - for_eachと同時に使えない
    - idnexを使うことで数値を扱える(「user_1」,「user_2」の様に出来る)
- for_each(map,setを使ってループできる。listは使えない)
    - リストを使いたい場合は、toset()を使って変換が必要

### lifecycle引数
resourceブロックの中に定義できる。CfnでいうDeletation_policyを登録するのと同じイメージ
- create_before_destroy : リソースを削除する前に作成する(EC2等で使いそう?)
- prevent_destory : 削除防止(RDSなど削除してほしくないものに設定)
- ignore_changes : 指定した属性に変更があったとしても無視する
    - 用途: コード上将来使うが今は仮置きしたい属性等を定義したい時

## リソースの依存関係の見方
- コードをDOT形式に変換、Graphvizで見れる
    - terraform graph > \<file name>.dot
    - \<filename\>をSVGのためviewer(Graphviz)で見る
    - VScodeの場合はコマンドパレットからGraphvizを使う


## 3項演算子
terraformにはif文は存在しないため、分岐をさせたい場合はこれらを駆使する。
例えば、prod/dev等の環境毎に異なる部分で使う。
ClickHouseをWindowsのWSLで動かす

ClickHouseをWindows10で動かしたかったので、WSLで動かしました。

* テスト環境
  * Windows 10 21H2(OSビルド 19044.1706)
  * WSL2
  * Ubuntu 20.04.4 LTS
  * Clickhouse 22.6.1.1985

# 0 WSLでubuntuを導入
まず、以下の記事を参考にしてWindows 10のWSLでubuntuを導入しました。

Windows 10でLinuxを使う(WSL2) - Qiita 

https://qiita.com/whim0321/items/ed76b490daaec152dc69

```powershell
PS C:\temp\wsl> dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart ; dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all
```

# 1 ClickHouse導入
以下の手順でClickhouseのサーバーとクライアントを導入できました。

Installation | ClickHouse Docs 

https://clickhouse.com/docs/en/getting-started/install


```bash
sudo apt-get install -y apt-transport-https ca-certificates dirmngr
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 8919F6BD2B48D754

echo "deb https://packages.clickhouse.com/deb stable main" | sudo tee \
    /etc/apt/sources.list.d/clickhouse.list
sudo apt-get update
sudo apt-get install -y clickhouse-server clickhouse-client
```

なお、特定のバージョンを指定する場合には

```
sudo apt-get install clickhouse-server=22.4.5.9 clickhouse-client=22.4.5.9 clickhouse-common-static=22.4.5.9 
```
で導入します。

https://packages.clickhouse.com/deb/pool/stable/


passwordはインストーラー実行中に以下のように聞かれました。
パスワードを入力してEnterするとインストーラーが続行します。

```
hkwd@ABC:~/clickhouse$ sudo apt-get install -y clickhouse-server clickhouse-client
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
  apport-symptoms dconf-gsettings-backend dconf-service gir1.2-packagekitglib-1.0 glib-networking
  glib-networking-common glib-networking-services gsettings-desktop-schemas libappstream4 libdconf1 libglib2.0-bin

---中略----
 chown -R clickhouse-bridge:clickhouse-bridge '/usr/bin/clickhouse-library-bridge'
Enter password for default user:

```

# 2 ClickHouseサーバー起動

WSLではsystemctlがそのままでは使えず、上の手順の「sudo service clickhouse-server start」は使えませんでしたので、
sudo clickhouse start
で起動しました。テスト用なので自動起動はしていません。

```
hkwd@ABC:~$ sudo clickhouse start
 chown -R clickhouse: '/var/run/clickhouse-server/'
Will run clickhouse su 'clickhouse' /usr/bin/clickhouse-server --config-file /etc/clickhouse-server/config.xml --pid-file /var/run/clickhouse-server/clickhouse-server.pid --daemon
Waiting for server to start
Waiting for server to start
Server started
```

# 3 ClickHouseクライアントを起動

clickhouse-client --password \<password>
で、defaultユーザーでクライアントを起動できます。

```
hkwd@ABC:~$ clickhouse-client --password xxxxx
ClickHouse client version 22.6.1.1985 (official build).
Connecting to localhost:9000 as user default.
Connected to ClickHouse server version 22.6.1 revision 54455.

Warnings:
 * Linux transparent hugepages are set to "always". Check /sys/kernel/mm/transparent_hugepage/enabled

ABC.localdomain :) select 1

SELECT 1

Query id: 50c43eef-b09b-4ffd-937c-7a79759c2937

┌─1─┐
│ 1 │
└───┘

1 row in set. Elapsed: 0.001 sec.

ABC.localdomain :) quit
Bye.
```
【Laravel】Routingのスッキリした書き方

# 結論
### ルートグループコントローラーを指定する
```php
Route::controller(PlacementController::class)
    ->prefix('placements')
    ->as('placements.')
    ->group(function () {
        Route::get('', 'index')->name('index');
        Route::get('/bills', 'bills')->name('bills');
        Route::get('/bills/{bill}/invoice/pdf', 'invoice')->name('pdf.invoice');
    });
```
このように記載することでroutingをスッキリまとめて記述することができました。

私はたいていルートグループコントローラーの上に`middleware`メソッドを利用して以下のように記述しています。

```php
Route::middleware(['auth'])->group(function () {
    Route::controller( UserController::class)
        ->prefix('user')
        ->as('user.')
        ->group(function(){
            Route::get('', 'index')->name('index');
            Route::post('/search', 'search')->name('search');
        });

    Route::controller(PlacementController::class)
        ->prefix('placements')
        ->as('placements.')
        ->group(function () {
            Route::get('', 'index')->name('index');
            Route::get('/bills', 'bills')->name('bills');
            Route::get('/bills/{bill}/invoice/pdf', 'invoice')->name('pdf.invoice');
    });
});
```
routingの結果も載せておきます。
```php
$php artisan route:list --compact
+----------+-------------------------------------+------------------------------------------------------------------+
| Method   | URI                                 | Action                                                           |
+----------+-------------------------------------+------------------------------------------------------------------+
| GET|HEAD | placements                          | App\Http\Controllers\PlacementController@index                   |
| GET|HEAD | placements/bills                    | App\Http\Controllers\PlacementController@bills                   |
| GET|HEAD | placements/bills/{bill}/invoice/pdf | App\Http\Controllers\PlacementController@invoice                 |
| GET|HEAD | user                                | App\Http\Controllers\UserController@index                        |
| POST     | user/search                         | App\Http\Controllers\UserController@search                       |
+----------+-------------------------------------+------------------------------------------------------------------+
```
# 背景
最初はRoute Groupという以下のような記述で配列で渡す方法で記述していましたが、[公式ドキュメント](https://laravel.com/docs/5.3/routing#route-groups)を確認したところ`5.3`からあった方法だったので、新しいバージョンではどうなのかを調べていたところ見つけました。

```php
Route::group(['prefix' => 'main', 'as' => 'main.'], function () {
    Route::get('list','MainController@list')->name('list');
    Route::get('edit','MainController@edit')->name('edit');
    Route::get('search','MainController@search')->name('search');
});
```

# おわり
Laravel8.80から使える、おすすめのrouting記法について書いてみました。
resoucesを使う場合は必要ないかもしれませんが、私はresoucesより明示的に書きたい派なので重宝しています。

もしご指摘等ありましたらコメントいただけると助かります。

# 参考
https://laravel-news.com/laravel-8-80-0

https://laravel.com/docs/9.x/routing#route-group-middleware

https://laravel.com/docs/5.3/routing#route-groups
CML アドレス変更　Cockpit更新


# 自己紹介　初投稿
インフラエンジニアになって、７年目になりますが、はじめてQiitaに
登録し、自分がハマったことについて備忘録として記載します。
皆さんと情報を共有できたら幸いです。

# 本記事の概要
最近、Cisco Modeling Labs（以下CMLと記載）仮想版を再構築しました。
再構築にあたって、CMLのIPアドレス変更とCockpitの更新方法について
ハマりましたので、情報共有されていただきます。
本記事ではCisco Modeling Labs（CentOS版　version 2.1.1）についての
アドレス変更、Cockpitの更新について記載します。

## Cisco Modeling Labsとは
Cisco Modeling Labs は、ネットワーク シミュレーション ツールです。Cisco Modeling Labs を利用すれば、実際のシスコイメージを使って、シスコおよびシスコ以外のネットワークをすばやく簡単にシミュレートできます。

## Cockpitとは
ブラウザでCentOSの管理ができる便利ツールになります。
Cisco Modeling Labsデプロイ後、GUI上でサーバの状態確認をすることができます。

ログイン方法：https://xx.xx.xx.xx:9090

![login.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2723514/be79bdb1-a2b4-7125-169f-8af6b690e059.png)

# CMLアドレス変更
今回は、CLI上でアドレス変更を実施しました。
「インターフェース確認」→「アドレス変更」→「アドレス保存」→「サーバ再起動」の手順で実施しました。
<br>1.インターフェース確認<br>
```
ip a
```
<br>2.アドレス変更
（※XXは上記インターフェース確認時の対象のインターフェースを指定）<br>
```
vi /etc/sysconfig/network-scripts/ifcfg-XX
```
<br>3.アドレス保存
保存する段階で、「>>>readonly (add ! to override)」というエラーメッセージが
出てきたので、下記のコマンドで保存しました。<br>
```
:w !sudo tee %
```

4.サーバ再起動
アドレス変更を適用するために今回はサーバ再起動を実施し、アドレス変更
が完了しました。

# Cockpitが表示できない事象が発生
アドレス変更後に、Cockpitが表示できない事象が発生しました。
急遽調べたところ、更新後にCockpitにログインできない事象が発生する？という
記載がありました。


https://learningnetwork.cisco.com/s/question/0D56e0000BCPtegCQD/anyone-else-having-problems-connecting-to-the-cml-system-administration-cockpit-after-a-recent-update

試しに、下記のコマンドを入力したところ、Cockpitにログインできました。
<br>Cockpitを更新<br>
```
sudo rm /etc/cockpit/ws-certs.d/0-self-signed.cert
sudo systemctl restart cockpit
```

# まとめ
CMLのアドレス変更は、初めて実施したので、ハマったポイントについて
簡単に備忘録として記載しました。
今後も、インフラエンジニアとしてハマったこと、便利なツールなどを
紹介したいと思います。

# 参考文献
https://www.cisco.com/c/ja_jp/products/cloud-systems-management/modeling-labs/index.html

https://genchan.net/it/server/14445/

https://learningnetwork.cisco.com/s/question/0D56e0000BCPtegCQD/anyone-else-having-problems-connecting-to-the-cml-system-administration-cockpit-after-a-recent-update
ランダムなカラーコード（RGBと16進数）を取得する方法

16進数とMath.random()を理解する助けになったので覚書です。

```ruby:16進数のカラーコード生成
var hex_numbers =  ["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"];
var hex = "";

for(var i = 0; i < 6; i++) {
  hex += hex_numbers[Math.floor(Math.random() * hex_numbers.length)];
}

var color_code = `#${hex}`;
```

```ruby:RGBのカラーコード生成
var rgbArr = [];

for(var i = 0; i < 3; i++) {
  rgbArr.push(Math.floor(Math.random() * 256));
}

var color_code = `rgb(${rgbArr[0]}, ${rgbArr[1]}, ${rgbArr[2]})`
```

## 参考サイト
- [Math.random() - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math/random)
- [1. Hex Colors - 15 Beginner JavaScript Projects to Improve Your Front-End Skills! - DEV Community](https://dev.to/codefoxx/15-beginner-javascript-projects-to-improve-your-front-end-skills-5bcj)

RGB→16進数、16進数→RGBの変換は下記が参考になりました。
- [javascript - RGB to hex and hex to RGB - Stack Overflow](https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb)
localhostが繋がらないときに確認すること

# 突然リダイレクトされるようになったローカルサーバ
`http://localhost:8080/hoge/login`を開こうとしたら
`http://localhost/hoge/`にリダイレクトされ、下記画像のように表示されてしまう現象が起こりました（Chrome使用）。
![スクリーンショット 2022-06-23 12.03.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507151/4ea2f551-8e5c-d3da-eccc-ce60014df080.png)

複数のローカル環境を起動していたり、ポート番号が被っていたりしても起こるので
対応の覚書です。


# 1. 起動中のローカルサーバを停止する
ポートがバッティングしている可能性があるため、起動中のローカルサーバを全て停止します。
dockerでサーバを起動している場合もあるため、起動中のコンテナもチェックします。
起動中のコンテナの一覧表示、停止、削除は[docker初心者によるコマンドメモ](https://qiita.com/mog_03/items/ce35483b95ec27ccd109)をご覧ください。


# 2. 使用中のポートを確認する

ターミナルを使って使用中のポートを確認します。
こちらを参考にさせていただきました（Macの場合）
[【Mac】占有portの調べ方と空け方](https://zenn.dev/json_hardcoder/articles/5925798786a07a)

ターミナルで以下を実行
```
$ sudo lsof -P -i:8080
```
使用中のポートがあれば一覧が表示され、なければ特に何も表示されません。
ポートを止める方法は上記の参考サイトをご覧ください。

# 3. 時間を置いてみる、シークレットウィンドウで開いてみる
上記を行っても改善しない場合、試しにシークレットウィンドウでアクセスすると解決することがあります。
少し時間を置いてからアクセスしても解決することがあるようです。
IBM Cloud VPC でシンプルなウェブサイト構築を体験する(2022年版) - 1. VPC作成

この記事は、[IBM Cloud VPCでシンプルなウェブサイト構築を体験する](https://qiita.com/kenichit/items/796b0cff7d09a0f517f6)の構築ステップを説明しています。IBM CloudのUI変更により連載記事構成の変更が必要となったため、2022年版として補足記事を作成しました。

このステップでは、構成図の中の赤い四角で示したVPCとサブネット3つを作成します。2021年版での[VPC作成](https://qiita.com/kenichit/items/73c2e356a14a7a5ab8da)と[サブネット追加](https://qiita.com/kenichit/items/2971f9da1542c2efde80)の両方を実施することに相当します。
![1diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922552/aa8231a6-6d7f-4aa5-cfdd-8a0a8744db07.png)

## ステップ1-1
IBM Cloudコンソールの左上ナビゲーション・メニューをクリックし、「VPCインフラストラクチャー」>「ネットワーク」>「VPC」をクリックします。
![vpc-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922552/937a616e-0ec6-af58-35c7-6caafa8c5902.png)

## ステップ1-2
「仮想プライベート・クラウド」の「作成」ボタンをクリックします。
![vpc-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922552/27dfb53d-5a77-f0a2-d09e-f534ad4e9e50.png)

## ステップ1-3
パラメーター・シートを参照しながらVPC作成に必要な情報である「地域」と「リージョン」を選択し、「名前」と「リソース・グループ」を入力します。
入力が完了したら、「サブネット」表中のゾーン:「東京1」の行にある鉛筆マーク(編集)をクリックします。
#### 補足:
「デフォルト・セキュリティー・グループ」の「SSHを許可」と「pingを許可」にチェックを入れたままにします。この設定により、VPCにデプロイされる仮想サーバーはデフォルトでSSHとping応答ができるようになります。
![vpc-03-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922552/b9e22ecc-43a2-c341-100f-75e4f985510b.png)
サブネットの「名前」をパラメーター・シートにある名前に変更し、右下にある「保存」ボタンをクリックします。
![vpc-03-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922552/b0e6f61e-79ae-82d0-ef1b-1400a983bfc4.png)
同様にゾーン:「東京2」「東京3」の行にあるサブネットの名前をそれぞれ変更します。「サブネット」表中の名前が3箇所変更されたことを確認して、「仮想プライベート・クラウドの作成」ボタンをクリックします。
![vpc-03-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922552/51b1e931-316d-811c-d11f-6710e4e2f542.png)

## ステップ1-4
VPCの名前、作成されたリソース・グループ、サブネットの数が想定通りに作成されたことを確認します。
![vpc-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922552/6e956f86-ee4e-5117-89e4-d15698943e06.png)

## ステップ1-5
「VPCインフラストラクチャー」>「ネットワーク」>「サブネット」をクリックします。サブネットの名前が変更された通りに作成されたことを確認します。
![vpc-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922552/18ffd689-38c7-c1b8-ae70-4f72247aa171.png)

## ステップ1-6
「VPCインフラストラクチャー」>「はじめに」>「VPCレイアウト」をクリックします。「VPCの選択」で作成したVPCと同じ名前を選択します。「サブネット」の囲みに変更された通りの名前でサブネットがあることを確認します。
![vpc-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922552/0f44e8ca-de3e-5891-5dc8-2bdbf94938ad.png)

次に、[仮想サーバー・インスタンス作成](https://qiita.com/kenichit/items/6384aab1a17cddcf41b0)に進みます。
ゆめみのコードチェックをRiverpod×MVVMで作ってみた

# はじめに
[Flutter × Riverpod × MVVMで実現するシンプルな設計(Firebase,WebAPI対応)](https://e2.udemymail.com/ls/click?upn=ZF3sOyS2SxEPIoSZT6Aoc-2BEAPso9xRA49IDbkpAnXinyE1lqmdso2Ml58A25yOutAeSXNQWvJxg6rj-2FqirXtRxWRJ80BVD4nCOI2FLizZovC-2BjbxLqWzRyvcJIiRLNRoXfqFJCgv-2FEfvBX6UyFIFkQ-3D-3DI_LE_QA1h2XVt7v6FiCxQ1tDprLgODuRJ6CvILAn2ERIzTFWC-2BXpuhNjfUc1Z3gFHH63b1w-2BnVvrtBsMfM3BylrSV5-2BF10zzJg0byCjfT-2BFsr0fkhfJ05VEajWShaAlB4CiBlCH2wiAvi4DRKf2WLTqIMF6QGWXkZUOpLu5IKd0DSD41CJZtEw4VHpPIT0Tyy-2BG6hoYM7HT6bEvMFfmzTBexMCtl-2BiQffPeQa07uvLqGUTnDaIYGZjI8b7ikTZWK-2F1RMRdliijLXgoEUfuvKq0P9LZRyrf5-2BYoHQdLiTZJnaVzAM9PCnA-2B8QVd9UsypaV0-2B1Q9borslEfskbmm5zXfBwZOF9gTao9zx9q9JWpMsZyXuGAm8qqUzBE2kBeoVFmeqf4)
をriverpodの学習で修了しました。

その応用としてYUMEMI様のコードチェックに取り組んでみました。
Githubのリポジトリを検索して一覧で見れるようにする課題です。
自分の記録用として記事を書きます。
[株式会社ゆめみ Flutter エンジニアコードチェック課題](https://github.com/yumemi-inc/flutter-engineer-codecheck)

今回作成したコードはこちらのリポジトリに公開しています。
[https://github.com/secretused/yumemi_codecheck](https://github.com/secretused/yumemi_codecheck)
またGithubのAPIとしては以下を使用しています。
[https://docs.github.com/ja/rest/search#search-repositories](https://docs.github.com/ja/rest/search#search-repositories)

## 完成像
<img width="250" alt="ezgif-3-347b35c05b.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1631114/2a5259d7-e5d2-8cda-6f64-971b40af8e02.gif">

# 技術要素
## アーキテクチャ
MVVMを講座で習ったのでそちらを真似て使用しました。
各レイヤーの役割は以下のようになっています。
### View
- 画面の描画
- VMからのデータの呼び出し・書き込み
- FutureProviderを使用し、取得したデータをListViewで描画
### ViewModel
- Formから受け取ったクエリをStateProviderで更新
- AsyncValueを利用して、AutoDisposeFutureProviderFamilyでModelにクエリを渡す
- リストがonTap時のCellの値をStateProviderで更新
### Model
- クエリの整形
- クエリをAPI通信してデータの取得
- willProceedで空のクエリの場合を検知
## 状態管理 
freezed × riverpodで構築
freezedは取得したJSONをJSONクラスとして使用

基本的にriverpodの処理の記述は全てVMで記述
(SharepreferencesのみViewで呼び出し書き込みしています。)

### メリット
多くあると思ったのですが、自分が一番感じたのは
また可読性や簡潔性が高い、テストを導入しやすい。
## ソースコード管理/タスク管理
Github, Github Issue

初めてIsuueベースの開発を行い、個人でも実践を意識して行うことができました。
参考にさせていただいた記事
[一人開発でもissueベース/セルフプルリクエストを使って開発する](https://qiita.com/braveryk7/items/5208263cd06a8878f0c2#github%E4%B8%8A%E3%81%A7%E3%83%97%E3%83%AB%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%81%99%E3%82%8B)
## 初見
**ダークテーマ対応**
SharepreferencesでBool値を保存し、三項演算子でWidgetを変更。
<img width="230" alt="ezgif-3-bf89742356.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1631114/786b2a7c-e16d-772b-47e0-55a09f3b4104.gif">

**画面回転**
三項演算子でもよかったが、デザインも変えたため
LayoutBuilderを使用して縦と横をそれぞれ記述。
**多機種対応**
MediaQueryを使用して画面サイズから計算。
# 改善点と課題
- riverpodの記述方法を臨機応変に考えれるようにしたい。
- SharePreferencesの記述がriverpodの仕様を生かしきれていない
- テストを導入できていない
- 以下Issueを導入したい
[https://github.com/yumemi-inc/flutter-engineer-codecheck/issues/6](https://github.com/yumemi-inc/flutter-engineer-codecheck/issues/6)
# さいごに
コードは載せていませんが、Githubまで飛んでいただけると助かります。
[https://github.com/secretused/yumemi_codecheck](https://github.com/secretused/yumemi_codecheck)

Githubをもっと活用したり、MVVMをさらに意識してnull safetyな開発を心がけたいです。
今後テスト駆動開発かFlutterWebに取り組んでいきたいと思います。
わからないこと

*スクリプト*　台本
*プロンプト*　入力しなさいを示すマークなんだな～
*Active Recordはデータベースからデータを読み出すためのアプローチである。*
*@記号で始まる変数をRubyではインスタンス変数と呼び*
*【キャメルケース】 単語の先頭を大文字にする命名規則です。*

*全ての単語の先頭を大文字にするのがアッパーキャメルケースもしくはパスカルケース*
*先頭の単語だけ小文字にするのがローワーキャメルケースと呼ばれます。*
*モジュールは、関連したメソッドをまとめる方法の１つで、includeメソッドを使ってモジュールを読み込むことができます（ミックスイン（mixed in）とも呼びます）*

*スネークケース 単語の間をアンダーバーでつなぐ命名規則です。DBなどで扱われる値に使用されることが多いようです。*
*ケバブケース 単語の間をハイフンでつなぐ命名規則です。HTMLではclass名であったり、ファイル名などでもよく見かけます。*
*リファクタリング (refactoring) とは、*
コンピュータプログラミングにおいて、プログラムの外部から見た動作を変えずにソースコードの内部構造を整理することである。
<h2>$ touch app/views/static_pages/about.html.erb</h2>

5.3.4リンクのテスト
rails generate integration_test site_layout




*Representational State Transfer (REST)は、*
ウェブAPIの定義に使用されるアーキテクチャスタイルであり、同時にウェブのような分散ハイパーメディアシステムのためのソフトウェアアーキテクチャのスタイルのひとつでもある。

![スクリーンショット 2021-11-28 13.58.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1495496/527acd1c-aa65-133c-1e83-700451100daf.png)
![スクリーンショット 2021-11-28 13.58.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1495496/2b58ade3-8ef0-4ebb-4d91-4fbc0492b7e7.png)

<h1>元に戻す方法</h1>
![スクリーンショット 2021-11-28 16.15.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1495496/ed7451f3-b126-d55b-4b98-9bee16c9c662.png)

<h1>GETやその他のHTTPメソッドについて</h1>
![スクリーンショット 2021-11-28 16.15.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1495496/b0cdae42-2a6b-7255-ebe0-4a2939986698.png)
MicroPythonで16進数のバイト文字列(bytes型)を文字列(str型)に変換 

## 16進数のバイト文字列の変換
MicroPythonで16進数のバイト文字列(bytes型)を文字列(str型)に変換する。
（@inachi 様、変換方法を教えていただ気ありがとうございます。）
```python:変換例
b'6170706c65' →  "apple"
b'6364736c'   →  "cdsl"
b'61626364'   →  "abcd"
b'31323334'   →  "1234"
```
[ESP32でBLEの実装作業【スキャン】](https://qiita.com/KChai/items/753ca056443eca574be4)を参考にして、データ部に格納した文字を取り出そうとした所、16進数のバイト文字列だった。文字列(str型)に変換して、人間が読める状態にしたい。

## MicroPythonで苦戦
インターネットで検索するとbytes.fromhexを使う方法が出てきた。
[Tech Blog - プログラミングに関しての備忘録](https://techblg.app/articles/how-to-convert-hex-to-string-python3/)
```python:Python 3.9.0
>>> hex_bytes = b'6170706c65'
>>> hex_str = hex_bytes.decode("utf-8")
>>> print(bytes.fromhex(hex_str).decode('utf-8'))
apple
```
このコードをMicroPythonで実行する。
```python:MicroPython v1.18
>>> hex_bytes = b'6170706c65'
>>> hex_str = hex_bytes.decode("utf-8")
>>> print(bytes.fromhex(hex_str).decode('utf-8'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'bytes' has no attribute 'fromhex'
```
Python3では実行できたが、MicroPythonではエラーが出てしまった。

## 関数の作成
~~代わりにMicroPythonで使用できる関数を作成した。~~
(　↑関数を作る必要なんてなかった　)
```python:関数
def hex_bytes_to_str(hex_bytes):
    hex_str = hex_bytes.decode()

    return_str = ""
    for i in range(0, len(hex_str), 2):
        char_hex = hex_str[i] + hex_str[i+1]
        return_str+= chr(int(char_hex, 16))

    return return_str
```
```python:MicroPython v1.18
>>> hex_bytes = b'6170706c65'
>>> print(hex_bytes_to_str(hex_bytes))
apple
```
## 組み込み関数で変換
コメントで @inachi 様より変換方法を教えていただいた。
教えていただきありがとうございます。
```python:MicroPython v1.18
>>> import binascii
>>> hex_bytes = b'6170706c65'
>>> print(str(binascii.unhexlify(hex_bytes), 'utf-8'))
apple
```
これで良し。
DatabricksのNotebook上でインポートしたデータを表示する方法

# DatabricksのNotebook上でインポートしたデータを表示する方法

## はじめに
本記事はDatabricksを初めて触る人向けに作成されたものです。ここではDatabricksにデータをインポートする方法を紹介します。
詳細は以下の内容となっています。

- Databricks
    - Notebookとは
- DatabricksのNotebook上でインポートしたデータを表示させる方法
    - クエリの実行
    - 文字化け修正

### DatabricksのNotebookとは
DatabricksのNotebookとは、Databricks内で実行可能なセルやコマンドの集合体のことを指しています。

　Databricks notebookを使用することで、複数人で同じnotebookをリアルタイムで編集・コメント等書き込むことも可能であり、同じnotebook内で複数言語を使用してデータ加工や分析を行うこともできるので非常に使用しやすい機能です。

詳しくは以下の記事に記載しています。
##### 【AI入門】Databricksとは 
https://azure-recipe.kc-cloud.jp/2020/05/databricks-introduction-%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E7%B0%A1%E5%8D%98%E3%81%AB%E3%81%BE%E3%81%A8%E3%82%81%E3%81%A6%E3%81%BF%E3%81%9F/
##### Notebookについて
https://recipe.kc-cloud.jp/archives/17357


## Notebook上でインポートしたデータを表示させる方法
Notebook上でインポートしたデータを表示させる手順としては以下が挙げられます。
- インポートしたデータからテーブルを作成
- クエリを実行

Databricks内でデータをインポートした後に、下記画像にあるようにCreate Table in Notebookを選択することで、自動的にコードが入力され、実行するだけで表示される仕組みになっています。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523621/21b18bcb-48ef-cdc9-e946-e66a93bfcb29.png)


また同様に、Notebookを先に開き画面上部にあるFileを選択、Upload Dataを選択することでもデータをインポートし、コードをそのままコピーすることが可能です。


Databricksはコードだけではなく、クリックベースでも動かすことができる万能なサービスです。データをインポートする詳しい方法については以下の記事を参照してください。

https://qiita.com/konishi5243/private/2a00a0c9badd537a3b85

インポートした状態になると、自動的にコードが書かれ、下記画像のようになるのでクエリを実行させることでファイルを表示することが可能です。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523621/87bc1a87-5ad8-11b5-30fe-2460817d5e7b.png)

しかし、実際に実行してみると下記画像のように文字化けしてしまうことがあります。
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523621/a00b4e70-f202-5d2e-a9f9-650cc6155c89.png)

### 文字化けの修正
日本語のデータが文字化けしてしまった場合は文字コードの変換が必要になります。その際は下記の一文を下記画像にように入れ、実行してください。
```python:python
.option('charset', 'shift-jis')\
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523621/fd7917ae-9eae-e264-45bf-b42c1a5c1cff.png)

 

すると日本語の文字化けを修正することができ、無事にDatabricksのNotebook上でインポートしたデータを表示させることができました！

いかがでしたでしょうか。まだまだDatabricksには様々な便利な機能等がたくさんあります。本記事ではNotebookに表示させるまでを紹介しましたが、別記事ではデータテーブルの構造について等も紹介しています。
ぜひDatabricksを使用し、データ分析等行ってみてください。
Javaのイニシャライザの順番について

# イニシャライザとは
クラスのロード時やinstant時にフィールドを初期化したりするために使うものです。  
ロード時がstaticイニシャライザ(以下、static{})でinstant時がイニシャライザ(以下、{})を用います。　　
この2つのみ(JavaGoldまでの範囲では)なのですが順番や呼び出しがややこしかったので、　　
振り返り用にまとめました。
  
# 基本的なコードと解説
~~~java
class Foo{
	//イニシャライザ
	{System.out.print("A");}
	//コンストラクタ
	Foo() {System.out.print("B");}
}
class Test{
	//staticイニシャライザ
	static {System.out.print("C");}
    //main()
	public static void main(String[] args){
		//インスタンス化
		Foo foo = new Foo();
	}
}
~~~
(見辛いと思い、クラスとmain()のみ改行してます。逆に見辛かったらすみません。)
実行結果です
~~~
CAB
~~~

### 解説
static{}はクラスのロード時に読み込まれるため、main()のあるTestクラスの”C”が最初に出力されます。次にmain()でFooクラスを生成しています。
この時、constructorよりも先に{}が呼び出され、次にconstructorが呼ばれます。
従って順番は”CAB”となります。


# ややこしめのコードと解説
~~~Java
class Foo{
	{System.out.print("A");}
	Foo() {System.out.print("B");}	
}
class Bar{
	//フィールド
	static int i = 1;
	//イニシャライザ
	{System.out.print("D");}
	//staticイニシャライザ
	static {System.out.print("C");}
	//コンストラクタ
	Bar() {System.out.print("E");}
}
class Test{
	//main()
	public static void main(String[] args){
		//Fooクラスのインスタンス化
		Foo foo = new Foo();
		//Barクラスの変数iを出力
		System.out.print(Bar.i);
		//Barクラスのインスタンス化
		Bar bar = new Bar();
	}
}
~~~  
こちらが実行結果になります。
~~~
ABC1DE
~~~
  
### 解説
　最初のmain()の１行目では前述した基本的なコードと同じく、”AB”が出力されます。
　２行目のBarの変数iの出力ですが、変数iはstaticであるため生成は必要ありません。そして処理を行おうとすると、出力の前にstatic{}が実行されます。したがって、”C1”の順で出力されているのがわかります。
　その後、Barクラスを生成し{}とconstructorの処理を行い”DE”と出力されます。この時static{}は1度出力されているため、新たに生成しようが処理はされません。

### 加えて
Barクラスの変数iの出力文を削除して実行すると**ABCDE**となります。コードの順番的にはstatic{}が後なのですが、実行順は{}が後になります。

# 最後に
　僕がこのコードで最初に疑問だったのは、
static{}はmain()とは別のクラスにある場合、最初にロードされないのか？
といったものでした。結果的にクラスが読み込まれるのは呼び出された時なのかぁ
と気づけたのもよかったです。

# 追記
### イニシャライザのことで書き忘れてたのを書いてきます。
・Interfaceでのイニシャライザの記述はコンパイルエラーです。（おそらく）
→書けた方がいましたらコメント共有頂けると有難いです。
・イニシャライザに関して。イニシャライザを持つ親クラスを継承した子クラスをmain()で
生成した際に、子クラスから親クラスのコンストラクタを呼び出しますが、その際にもイニシャライザ
が実行されます。
Azure Functions Core Tool の複数バージョンを切り替える


答え：[Azure Functions Core Tool Version Manager (funcvm)](https://github.com/anthonychu/funcvm) を使います。

Azure Functions Core Tool はほとんど Ver.4 に対応済みになってきているので、当分バージョンを切り替えて使う必要ないかもしれませんが、将来またこのツールのお世話になる可能性があるかもしれないので残しておきます。

## 事前準備

まず、このツールをインストールする前に既に Azure Functions Core Tool をインストールしている場合は全てアンインストールする必要があります。

## インストール

funcvm というツールを使います。当時 Azure Functions の開発チームの中の人だった人が作ったものです。
ただ、このツールは Node.js で動くので、環境に Node.js がインストールされていない場合は先に Node.js のインストールが必要です。

[Node.js 公式ページ](https://nodejs.org/ja/)

Node をインストールしたら、次のコマンドでインストールします。

```
npm install -g @anthonychu/funcvm
```

## 使い方

### Azure Functions Core Tool インストール
まずは funcvm を使って Azure Functions Core Tool をインストールする必要があります。

```
funcvm install <version>
```

Azure Functions Core Tool のバージョン番号はこちらで確認します。
[Azure Functions Core Tool Releases](https://github.com/Azure/azure-functions-core-tools/releases)

例えば、バージョン4.0.4590をインストールする場合はこうなります。

```
funcvm install 4.0.4590
```

### インストールされた Azure Functions Core Tool の一覧

```
$ funcvm list
3.0.3904
3.0.4425
4.0.3971
4.0.4426
4.0.4590 (global)
```

### バージョンの切り替え
```
$ funcvm use 3.0.4425
Using 3.0.4425
```

### 特定ディレクトリでの実行時にバージョンを指定する

.func-version という名前のファイルを作り、ファイルにバージョン番号を書いておくだけで、そのディレクトリでの func コマンド実行は指定したバージョンになります。
（@horihiroさん、ご指摘ありがとうございます）

```text:.func-version
3.0.4425
```

### Azure Functions Core Tool のアンインストール
```
funvm remove <version>
```

## funvm 自体のバージョンを確認

funvm は npm のツールとしてグローバルインストールされていますので、次のコマンドで確認します。

```
$ npm list -g
```

## どこにインストールされたの？

IDEなどのツールによっては、Azure Functions Core Tool の場所をピンポイントで指定しなければならないことがあります。
funcvm は Windows の場合は ユーザーのホームディレクトリに .funcvm\Download というディレクトリを作成し、そこに各バージョンの Azure Functions Core Toolを保持します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222127/345a5a2a-4fa5-576b-7cc0-77fdfdf9bf73.png)

必要な場合は各ディレクトリ内部にある func.exe を 指定すればOKです。
Databricksデータをインポートする方法

# Databricksデータをインポートする方法 

## はじめに

本記事はDatabricksを初めて触る人向けに作成されたものです。ここではDatabricksにデータをインポートする方法を紹介します。 

詳細は以下の内容となっています。 

 

- Databricksとは 

    - Databricksの用途 

- Databricks操作方法 

    - クラスター作成方法 

    - データのインポート方法 

 

## Databricksとは

Databricksとは今北欧で一番の使用率を誇り、世界的にも注目され採用されているクラウド型の統合データ分析基盤です。DatabricksはAI/機械学習に特化しており、ビッグデータを扱うことに長けています。そのため、データエンジニアリング、データサイエンス、機械学習、データ分析の領域に強みがあるのが特徴です。 

 


つまりDatabricksとは、大量のデータを高速に、簡単に分析できる機能をもつサービスということができます。 

 


そんなDatabricksの操作は直感的で、クリックベースを中心に簡単に操作することが可能です。まずは最初の一歩とも言えるデータのインポートについて紹介します。 

 

### Databricks操作方法

今回インポートするために使用するデータは下記のデータ（.CSV）になります。 

 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523621/11e578c4-1eae-e8f4-625b-14ece46d7745.png)

 

Databricksではホーム画面からでも、コードを書くワークスペース上でもインポートすることが可能です。今回紹介するのはUpload Data UIを使用したデータのインポートです。 

 

まずは前準備として cluster を作成する必要があります。clusterを作成していないと、ワークスペースにおいてクエリを実行することができないので注意が必要です。 

 
#### クラスター作成方法

主な手順は以下になります。 

- ホーム画面左タブからComputeを選択しCreate clusterを選択 

- 自分の必要な環境に応じて設定 

- Createを押して作成 

 

まずは下記画像のように、ホーム画面左タブに現れるマーク（Compute）を選択します。 
初めてclusterを作成する場合はこのような画面が出てくるので、Create a clusterを選択します。 


 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523621/946c775f-93fb-43b5-dd18-be5ad709a72a.png)


作成から次の画面は以下のようになるので、自分の環境にあったものを選択します。 

 

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523621/89d1a7d3-96dd-c986-fa9e-dc3d0d770e8e.png)


 

選択し終えた後は上部にあるCreate a clusterを選択し作成することが可能です。 

クラスターを作成したら、次はデータをDatabricks上にアップロードします。 

 

## データのインポート方法

データをインポートする手順は以下になります。 

- ホーム画面のData importまたは左タブ（Data）を選択 

- アップロードするファイルを選択 

- ファイルのアップロード完了を確認し、テーブルを作成、データをインポート 

まずは、ホーム画面のData Importまたは、左側のタブに下記の画像のようなマーク（Data）があるので選択します。 

ホーム画面のData Importを選択すると、ファイルが自動的に開かれるので、インポートしたいデータを選択します。 

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523621/68d84050-96fa-076f-d944-96ce19ddce10.png)


 

 

ファイルを下記画像のようにアップロードできたことを確認したら、そのままCreate Table in Notebookを押すことで、インポートしたデータに対してNotebook上でクエリを走らせることができる画面に行きます。 

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523621/a5586f30-ef58-16d3-4a59-7cf08315c37f.png)


 

下記画像の場所で、クラスターをNotebookに割り当てることができます。 

 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523621/246bc382-e314-89e0-7ec0-eddfc26927a6.png)

 

いかがでしたでしょうか。本記事ではDatabricks内でデータをインポートする方法について紹介しました。次回はNotebookにインポートしたデータを表示させる方法について紹介します。お楽しみに！
AWSのコンテナサービス選択法

# 概要

* 2022年6月23日の時点において、**コンテナ化されたアプリケーションをAWSで実行するためにはどのAWSのサービスを使用すればよいのか迷われる方多いのではないでしょうか。**
* そんな方向けに今回は、AWS Container Heroである[Vlad Ionescu](https://twitter.com/iamvlaaaaaaad/)さんのブログで紹介されている[Flowchart: How should I run containers on AWS?](https://www.vladionescu.me/posts/flowchart-how-should-i-run-containers-on-aws-2021/)の翻訳および最新化したAWSのコンテナサービス選択のためのフローチャートについて紹介していきたいと思います。
* 紹介されているフローチャートの選択で古いものがあるのでそこはアップデートしつつまとめていきます。

## AWSのコンテナサービス選択のためのフローチャート

* **下記のフローチャートに従うことでAWSのどのサービスが適しているのか見つける手助けになれば幸いです。**

![Untitled(3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563635/6a7f0140-dbb7-bdce-d79a-6c6b26928ae5.png)

### 質問の意図

* 質問1で「250人以上のエンジニアがいま​すか？」という質問の意図としては、 250人以上もエンジニアがいる場合、すでにチームがコンテナを動かすための最適解を持っている可能性が高いためです。
* この250人という数字を選んだ理由は、250人以上のエンジニアがいる場合、Dockerを使う時に有料のサブスクリプションを購入しなければならないからです。
* 質問2では、Kubernetesを運用するとなると金がかかる「ブログでは少なくとも毎年100万ドルUSのコストがかかると書いてあるのですが、ケースによると思います。」ためです。

# まとめ/所感

* まとめてみたものの、この方はEKSを押しているようですね。
* 前に[ECS VS EKS VS Lambdaという面白い勉強会](https://jawsug-container.connpass.com/event/244318/)がありましたが、その中でトリさん、西谷さん両者ともAWSのサービスを選定する時の順番としては、Lambda → ECS on Fargate → EC2で考えていき、EKSという選択肢はなるべく取りたくない(Kubernetesをどうしても使いたいとか、俺が運用やるから使わせてくれって人がいない限り)ようでした。
* 確かにKubernetesを使うとなると運用大変になりますし、読者の皆さんもそう思われる方が多いのではないでしょうか。
* まあ、今回はあくまで[Flowchart: How should I run containers on AWS?](https://www.vladionescu.me/posts/flowchart-how-should-i-run-containers-on-aws-2021/)の翻訳/最新化という記事だったので、ここまでとしたいと思います。
* 一読いただきありがとうございました！

# 参考

https://www.vladionescu.me/posts/flowchart-how-should-i-run-containers-on-aws-2021/
UnrealEngine iOSでカメラロールにスクリーンショットを保存する

# 最初に
UE4のバージョンは4.27.1
Xcodeのバージョンは13.1
になります。

Android端末でのスクリーンショットの方法に関しては
https://twitter.com/pafuhana1213/status/960199124367716353
おかずさんが公開しているサンプルで可能です。
https://orenda.co.jp/blog/1791/
こちらの記事でもスクリーンショットの撮影方法に関して書いてくれていますので参考になります。

今回はiOSでカメラロールにスクショを保存する具体的な実装例がなく苦労したので一例として記事にしてみました。


# スクリーンショットを撮る方法

スクリーンショットを撮るには
FScreenshotRequestのRequestScreenshotで行います。
引数は
InFilename	使用するファイル名
bInShowUI	SlateUIを表示するかどうか
bAddFilenameSuffix	自動生成された一意のサフィックスを指定されたファイル名に追加する必要があるかどうか
とあり基本的には
InFilenameに出力先を含めてファイル名を渡す
bInShowUIにUIを表示するかどうかのbool値を渡す
bAddFilenameSuffixは基本的にfalseを渡す
形で使用する事になるかと思います。

## iOSでスクリーンショットを撮影
AndroidはRequestScreenshotで端末内のストレージを指定してInFilenameの引数に渡してあげれば端末内のストレージに保存できるのですがiOSは出力先のパスが取得できないので別の方法をとる必要があります。
※UE4のRequestScreenshotを使わずObjective-CやSwiftのスクリーンショット機能を使えば可能だと思いますがUIを写さないで保存するには一度スクリーンショット前にUIを非表示しないといけなかったりiOSだけスクリーンショットの方法が変わるのでできるだけ撮影部分は共通にしたかった為今回はObjective-CやSwiftのスクリーンショット機能は使用していません。
スクリーンショットを撮る方法でスクリーンショットを撮影出来ますがiOSはアプリ内のフォルダに保存されます。
したがってそこから端末内のストレージに保存する必要があります。

まずカメラロールへの保存は非同期なので保存が完了するまで遅延が発生するので完了を通知する関数を用意する必要があります。
カメラロールへの保存はObjective-Cで行うのでそちらで用意する事なります。
```
///クラスを宣言
@interface ScreenshotSave : NSObject
- (void)onCompleteCapture:(UIImage *)screenImage
didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo;

@end
@implementation ScreenshotSave

//画像保存完了時の関数を実装
- (void)onCompleteCapture:(UIImage *)screenImage
didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
　　//エラーした場合
	if(error)
	{
		UE_LOG(LogTemp, Error, TEXT("Capture Error"));
	}
	else
	{
		UE_LOG(LogTemp, Log, TEXT("Capture success"));
	}
}

@end
#endif

```

```
//保存する画像ファイル名
NSString *ImageName = (NSString*)FPlatformString::TCHARToCFString(*OutFilePath);
//保存する画像を取得
UIImage *Image = [UIImage imageWithContentsOfFile:ImageName];
```
端末内に保存する画像をUIImageで取得します。
```
//上記で用意したクラスのインスタンスを生成する
ScreenshotSave* Saveobj = [[ScreenshotSave alloc] init];
//完了を通知する関数をセレクタに登録
SEL Selector = @selector(onCompleteCapture:didFinishSavingWithError:contextInfo:);
//カメラロールに保存する関数を実行
UIImageWriteToSavedPhotosAlbum(Image, Saveobj,Selector, NULL);
```
これでカメラロールに保存する事ができます。
カメラロールにアクセスする際はInfo.plistにNSPhotoLibraryAddUsageDescriptionを追記する必要があるのでプロジェクト設定->IOS->ExtraPListDataに
`<key>NSPhotoLibraryAddUsageDescription</key>\n<string>アルバムに写真を保存します。</string>\n`
の形で追加してください。
※"アルバムに写真を保存します。"ここは使用目的に合わせて変える事になります。
info.plistにこの記載が無いとUIImageWriteToSavedPhotosAlbum実行時にアプリがクラッシュする事になります。

後始末としてアプリ内に保存したスクリーンショットは削除しておかないといけないで
```
IPlatformFile& PlatformFileManager = FPlatformFileManager::Get().GetPlatformFile();

//ファイルを削除する関数
PlatformFileManager.DeleteFile(ここに削除するスクリーンショットのパスを記載);
```
のような形でアプリ内のスクリーンショットを削除するようにします。

以上がiOSでスクリーンショットをカメラロールに保存する方法になります。

~~カメラロールへのアクセス許可のチェックやアクセス許可のダイアログをスクリーンショット前に表示する方法は別の記事で投稿致します。~~

[UnrealEngine iOSでカメラロールへのアクセス許可を求める]https://qiita.com/usagon/items/d62e7746317073ee458e
カメラロールへのアクセス許可を求める方法の記事を投稿いたしました。
Configure Salesforce CORS Allowlist

全てのAPIをサポートしているわけではないようです。知らんかったなぁ。

[Configure Salesforce CORS Allowlist](https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/extend_code_cors.htm)

These Salesforce technologies support CORS.
+ Apex REST
+ Bulk API
+ Bulk API 2.0
+ Connect REST API
+ Lightning Out
+ REST API
+ Salesforce IoT REST API
+ CRM Analytics REST API
+ User Interface API

ストリーミングサービスはサポートしてないとのこと。

回答
[How to use latest cometd version in Salesforce StreamingAPI](https://salesforce.stackexchange.com/questions/179483/how-to-use-latest-cometd-version-in-salesforce-streamingapi)

質問
+ [CORS error when Subscribing platform events using Cometd](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000Hmq7sSAB)
+ [Streaming API support for CORS](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000BqgSISAZ)
attributeに指定するlocationIdは、locationのlocationIdではない（GoogleMyBusiness API）

# 前置き
GoogleMyBusinessのBusinessInfomationAPIでlocationを更新する際は、location_idを指定する。
locations.attributesを更新するには以下のように行う。

```py

location_location_id = location.get("name").split("/")[-1]
attr_response = self.api.attributes.get(location_id)
attribute_location_id = attr_response["name"].split("/")[1]

attribute = gen_attribute(attribute_location_id)

# attributesAPIにpatchでリクエストするとattributesを更新できる
response = self.api.attributes.patch(location_location_id, attribute, field_mask)


```

attributesを更新する際に、以下のような形で指定する
![スクリーンショット 2022-06-23 12.21.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371540/02b9afb1-d01c-4048-ef31-4788ab4d6ae8.png)
attributes.nameに指定するlocations/{locationId}/attributesのlocationIdは、LocationsのlocationIdではない。


attributesの中身のattributeは以下のような形
![スクリーンショット 2022-06-23 12.21.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371540/505602ed-a634-894e-7918-6b9710dfad8a.png)



```py
# ここのlocation_idは、attribute_location_id
# attribute.getで取得したnameのIDを使う
attribute["name"] = f"""locations/{location_id}/attributes"""

# URLのvalueTypeのattributesの例
attribute["attributes"] = [
    {
        "name": "attributes/" + name,
        "valueType": "URL",
        "uriValues": uri_values # こんな感じの構造 [{ "uri": "https~~"}]
    }
]
```

URL以外のvalueTypeの指定方法については、attributes.listで取得した形を参考にすると良いかも


# 本題
locationを更新する際は、locationIDを使うが、
locationのlocationIDとattributeのlocationIDは同じものを使うわけではない。

```py
attribute["name"] = f"""locations/{attribute_location_id}/attributes"""
```

attributesを更新する際のnameは、locationのlocationIdを指定するが、
attributeの要素、nameに指定するlocationIdは、attribute.getで取得したnameのLocationIdを使う

# まとめ
 ```py
 
location_location_id = location.get("name").split("/")[-1]

attr_res = self.api.attributes.get(location_location_id)

attribute_location_id = attr_res["name"].split("/")[1]

response = self.api.attributes.patch(
    location_location_id,
    gen_attribute(attribute_location_id),
    # field_maskは、attributes.nameをカンマ区切りで繋げた文字列。必須
    field_mask
)

def gen_attribute(attribute_location_id):
    return attributes = {
        #locaiton_id = location.get("name").split("/")[-1],
        "name": f"""locations/{attribute_location_id}/attributes""" 
        "attributes": [
            {
                "name": "attributes/" + attribute_name,
                # attribute_nameは"url_appointment"など文字列
                "valueType": enum (AttributeValueType),
                "values": [value],
                "repeatedEnumValue": {object (RepeatedEnumAttributeValue)},
                "uriValues": [{object (UriAttributeValue)}]
            }
        ]
    }


```


公式ドキュメントにはlocationIdとしか書いてないのですごく紛らわしい
![スクリーンショット 2022-06-23 12.51.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371540/068f1f14-213a-144e-2668-42d32250dee5.png)


locationIDというと紛らわしいのでObjectIDといった方が感覚的にはわかりやすい気がする
VLANに関するメモワール

今回はVLAN間ルーティングで生成されるフレームのフォーマットについて検証しようと思います。
EthernetⅡとdot1qフレームの相違を検証することでなにか見えてくるのではないのかという思惑があります。

構成図は以下の通りです。
![構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710882/c8a50749-bbf9-a1a2-855f-926f43b13a2b.png)
青線がVLAN10,赤線がVLAN20の範囲を表しています。またR1はサブインターフェースを作成しています。

以下にそれぞれのL2セグメント間を通るフレームをまとめます。

①PC1(Fa0/0)→SW(Fa0/1)
![PC1(Fa0:0)→SW(Fa0:1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710882/804c4547-a5cd-6760-3f7e-c3b042bc3b2e.png)


②SW1(Gi0/1)→R1(Gi0/1.10)
![SW(Gi0:1)→R1(Gi0:1.10) .png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710882/bf68dc53-5f9e-09c0-afb9-15ffdb6a44b2.png)

まず以上の２つを比較すると、イーサネットフレームのタイプが変わっていることがわかります。
①EthernetⅡ
②Ethernet 802.1q

このようになっています。Ethernetフレームの部分以外の相違点は特にありません。

Ethernet 802.1qの方は、EthernetⅡに以下の部分が挿入されています。
![dot1q追加部分.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710882/81b8e90d-565b-9e00-cc73-07bb4bda6e85.png)

TPID(Tag　Protocol　Identifier)はIEEE802.1Q VLAN-Tagが続くことを示す
Ether Type値です。0x8100はデフォルトの値です。

TCIは(Tag　Control　Infomaition)はVLANタグ情報などが含まれるフィールドです。
0x000aは16進数なので2進数に直すと0000/0000/0000/1010になります。
これをを10進数に変換すると「10」になります。この値は、vlan 10を表しています。


PC2から生成されるフレームについても見てみます。
③PC2(Fa0/0)→SW(Fa0/2)
![PC2(Fa0:0)→SW(Fa0:2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710882/a7e8c050-a04a-9fd9-3121-b9ff28410c35.png)

④SW1(Gi0/1)→R1(Gi0/1.20)
![SW1(Gi0:1)→R1(Gi0:1.20).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710882/201ce2f3-b50f-263b-f8d4-790e7622c751.png)

TCIは(Tag　Control　Infomaition)を見てみると、値が「0x0014」になっています。
これを2進数に直すと、0000/0000/0001/0100になります。
さらにこれを10進数に直すと「20」になります。これもやはりVLAN20を示しています。


例えば「vlan 10」はvlan情報のタグをフレームに追加するコマンド
「switchport access vlan」は任意のタグをどう処理するかを決定するコマンドですね

※本記事は個人的備忘録になりますが、間違っている点やアドバイスなどあれば積極的にコメントを
頂けますと幸いです。
[intra-mart]IM-BPMのスクリプトタスクでの備忘録


# BPM変数の操作
BPM変数を追加、読み込み、更新、削除できます。
以下の様にスクリプトタスクのデフォルトの関数(run)の引数`entity`を使用します。
```javascript: CRUD [intra-mart BPM スクリプトタスク]
function run (variables, execution, entity) {
  // create
  entity.setVariable("variable_name", "value");
  // read
  entity.getVariable("variable_name");
  // update
  entity.setVariable("varialbe_name", "update_value");
  // delete
  enttiy.removeVariable("variable_name");
}
```
`entity`の中には様々な関数が入っています。
entityの中身については以下のリンクに書かれていると思います。

https://api.intra-mart.jp/bpm/apilist-bpm-javadoc/doc/jp/co/intra_mart/activiti/engine/delegate/VariableScope.html

IM-BPM変数削除処理(removeVariable())を探すのに手間取ったので今回の記事を書きました。  
サンプルとかでBPM変数を削除しているコードは見たことない。。
variablesにもBPM変数の情報が入っているようなのですが、使い分け方がわかりません。

# BPM変数の日付型について
BPM変数には日付型があります。この日付型は`Javaの日付型`でした。
なので、JavaScriptの`new Date()`ではsetVariable()する時に日付型で登録できませんでした。(serializable)ってなる。
そのため、どうにかしてJavaの日付型の日付をsetVariable()する必要があります。
intra-martのスクリプトタスクでは標準Javaクラスが呼び出せました。
[標準Javaクラスとの連携方法](https://document.intra-mart.jp/library/iap/public/development/script_programming_guide/texts/use_java_class/standard_class.html)
実際に標準Javaクラスを呼び出してBPM変数として登録するコードが以下になります。これで日付型となりました。
```javascript: 日付型の登録
function run (variables, execution, entity) {
  // new Date()ではなく java.util.Date()を使う
  entity.setVariable("runDate", new java.util.Date());
}
```
### Java標準クラスの日付を扱うにあたって
Dateのドキュメントを見るとgetMonth()などが非推奨になっています。
代わりにCalendarを使えとなっていますが、よくわからんでした。

https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Date.html

せっかくのスクリプトタスクなので、スクリプトタスク内で操作する時は
JavaScriptのDateに変換して操作しました。
```javascript: intra-mart BPM スクリプトタスク
function run (variables, execution, entity) {
  // runDateには日付型(Javaの)が入っている。
  let runDate = entity.getVariable("runDate");
  // runDateをミリ秒で取得してjsのDateに変換
  let jsDate = new Date(runDate.getTime());
  // これでgetMonthとか使える
  Debug.print(jsDate.getMonth());
}
```
これが悪いのか良いのか分からないですができます。

# imuiListTableのデータを扱う
ユーザタスクに設定した画面にlistTableがあるときのお話です。
listTableのデータについてもJavaの標準クラスを使用する必要があります。
以下のようなリストテーブルのデータを作るとき
|id|name|email|
|--|----|-----|
|1 |unko|unko@example.com|
|2 |test|test@example.com|

データとしては以下のようなデータを渡せばよいのですが、  
JSで作った連想配列？オブジェクト？を渡してもうまく動きませんでした。
```json
[
  {
    id: 1,
    name: "unko",
    email: "unko@example.com"
  },
  {
    id: 2,
    name: "test",
    email: "test@example.com"
  }
]
```
なので、スクリプトタスク内で標準Javaクラスを使用して作ります。
```javascript: ↑の構造のデータを作る。
  // [] の部分
  let arr = new java.util.ArrayList();
  // {}の部分
  let map = new java.util.HashMap();
  // 1行目のデータを作成
  map.put("id", 1);
  map.put("name", "unko");
  map.put("email", "unko@example.com")
  // データを入れた{}を配列に追加する
  arr.add(map)

  ...省略
```
このarrを渡せばうまくデータが表示されるようになっているはず。

# 最後に
こんなの絶対躓くと思ったので書きました。特にBPM変数削除に関してはマジで見つけづらいと思います。
良いのか悪いのかも判断つけられないので、何かあったらコメントして教えてください。
Cloud SQLの手動バックアップ(gcloud)で403エラーが出た

## 背景
現在稼働しているGCPのCloudSQLのバックアップを取得するために、`gcloud sql backups create` コマンドでCloud SQLのバックアップを取得したかった。

## やったこと
```
gcloud auth activate-service-account --key-file=$CI_SERVICE_ACCOUNT
gcloud sql backups create --instance="$DB_INSTANCE_NAME" --description="$SQL_BACKUP_MEMO" --project="$GCP_PROJECT_ID"
```

## 起きたこと
```
ERROR: (gcloud.sql.backups.create) HTTPError 403: The client is not authorized to make this request.
```

## 原因
サービスアカウントにCloud SQLのクライアント権限(cloudsql.client)はあったが、編集者権限はなかった。

## 対策
サービスアカウントにCloud SQL編集者 `cloudsql.editor` の権限をつけてあげればうまくいった。

## 参考
- https://cloud.google.com/iam/docs/understanding-roles?hl=ja#cloud-sql-roles