OmniAICreator/Qiita-1.07M huggingface dataset:
Windowsアプリケーションの自動化-Python編①-

今更ですが、Pythonで`win32gui`と、`win32con`を使ってWindowsアプリケーションを操作する手順を勉強したのでメモ

参考URL
 - [Pythonで子ウィンドウハンドルを取得する方法](http://bttb.s1.valueserver.jp/wordpress/blog/2017/09/30/python%e3%81%a7%e5%ad%90%e3%82%a6%e3%82%a4%e3%83%b3%e3%83%89%e3%82%a6%e3%83%8f%e3%83%b3%e3%83%89%e3%83%ab%e3%82%92%e5%8f%96%e5%be%97%e3%81%99%e3%82%8b%e6%96%b9%e6%b3%95enumchildwindows/)
 - [CComboBox クラス|Microsoft](https://docs.microsoft.com/ja-jp/cpp/mfc/reference/ccombobox-class?view=msvc-160#showdropdown) 

##構成環境
 - Windows10
 - Anaconda3 2019.10
 - Python3.7.4

##Windowsアプリケーションの操作
`win32gui`は、Anaconda環境なら標準でインストール済み

一応よくあるファイル選択ダイアログのフォルダパス選択操作を想定しています

###クラス名とハンドル名を取得する
```Python:winapi.py
import array
import win32gui
import win32con

def run():
    # 親ウィンドウハンドル(識別番号)とそのクラス名、ハンドル名を取得
    p_handle = win32gui.FindWindow(None,"XXX") # アプリケーションのタイトル文字列など入力
    p_class_name = win32gui.GetClassName(p_handle)
    p_handle_name = win32gui.GetWindowText(p_handle)
    handles_dict = {str(p_handle): [p_class_name,p_handle_name]}
    print('p',hex(p_handle),p_class_name,p_handle_name)

    # 親ウィンドウハンドルの子ウィンドウハンドルを配列に格納
    c_handles = array.array("i")  # 子ウィンドウハンドルは複数あることを想定し配列を作成
    win32gui.EnumChildWindows(p_handle,lambda handle,list: list.append(handle),c_handles)

    # 子ウィンドウハンドルとそのクラス名、ハンドル名を列挙
    for ch in c_handles:
        c_class_name = win32gui.GetClassName(ch)
        c_handle_name = win32gui.GetWindowText(ch)
        print('c',hex(ch),c_class_name,c_handle_name)
        handles_dict[str(ch)] = [c_class_name,c_handle_name]
        
    # ここでは、ComboBoxのウィンドウハンドルを操作してフォルダパスを選択する
    combobox = [k for k,v in handles_dict.items() if str(v[0]).lower() == 'combobox']  # わざわざ辞書にしなくても良いかも
    win32gui.SendMessage(handles_dict[combobox[0]], win32con.CB_SHOWDROPDOWN, True, 0)  # ドロップダウンを表示する
    win32gui.SendMessage(handles_dict[combobox[0]], win32con.CB_GETCURSEL)  # 選択されている文字列の番号
    win32gui.SendMessage(handles_dict[combobox[0]], win32con.WM_GETTEXTLENGTH)  # 選択されている文字列の長さ
    win32gui.SendMessage(handles_dict[combobox[0]], win32con.CB_FINDSTRINGEXACT, 0, "XXX")  # 指定した[文字列]の番号
    win32gui.SendMessage(handles_dict[combobox[0]], win32con.CB_SETCURSEL, XX)  # 指定した[番号]の文字列を選択する
    win32gui.SendMessage(handles_dict[combobox[0]], win32con.VK_RETURN)  # Enterキー押下してフォルダを決定する

   # このあとに[はい]のボタンを押す処理とかetc

if __name__ == '__main__':
    run()

```

とまあ、ざっとこんな感じですかね

###EnumChildWindowsのコールバック関数の処理について
`win32gui.EnumChildWindows(p_handle,lambda handle,list: list.append(handle),c_handles)`
↑のラムダ式の部分は下記のようにも書けます(参考URLより)

```Python:enum_child_windows_proc.py
def enum_child_windows_proc(handle, list):
        list.append(handle)
       return 1

win32gui.EnumChildWindows(p_handle,enum_child_windows_proc,c_handles)
```

そういえば`win32api`ライブラリは使ってなかった

##まとめ
コンボボックス内の文字列を取得する方法が謎なのでコンボボックス内の文字列の番号から探す力技で実装
あと、ウィンドウハンドルを探すのに苦労した
Visual Studio の Spy++というツールがない場合にウィンドウハンドルとクラス名,ハンドル名を効率よく探す方法を検討したいですね

:arrow_backward: [前回の記事] | [次回の記事](https://qiita.com/kurosworld/items/529b8447b0ab61ea0dcd) :arrow_forward:
Rails エラーメッセージを日本語化したいとき

私自身の備忘録のためにも記事を投稿してみたいと思います。

##Railsでエラーメッセージを日本語化したい場合

###言語設定の変更
まずはconfigのapplication.rbファイルを下記のように編集します。

```ruby:config/application.rb
# 中略
module Pictweet
 class Application < Rails::Application
   # Initialize configuration defaults for originally generated Rails version.
   config.load_defaults 6.0

   # 日本語の言語設定
   config.i18n.default_locale = :ja
　　# 省略
 end
end
```


###Gemの導入

日本語に対応する'rails-i18n'というGemを導入します。

```ruby:gemfile
gem 'rails-i18n'
```

上記を記述したらターミナルでbundle installを実行。

これで「〜を記入してください」などの日本語化はできていると思います。
ですが、カラム名などは日本語化できていなので、次はその設定をしていきます。

###Localeファイルの作成
####deviseを導入している場合
localeファイルに対応する日本語を記述していくことで日本語化しています。
deviseを使ってユーザー登録等を導入されている方は下記の方法が便利かもしれないです。

config/localesディレクトリに、devise.ja.ymlというファイルを作成します。

https://github.com/tigrish/devise-i18n/blob/master/rails/locales/ja.yml

上記URLに記載されている記述を全て作成したymlファイルにコピペしましょう。
これでユーザー登録関係の一部のカラム名の日本語化はできているはずです。

####自分で設定したカラム名の日本語化

config/localesディレクトリに、ja.ymlというファイルを作成します。
作成したら例のように編集していきましょう。

```ruby:config/locales/ja.yml
ja:
 activerecord:
   attributes:
     user:
       nickname: ニックネーム
     tweet:
       text: テキスト
       image: 画像
```

この例であれば、nicknameとtext,imageが日本語化されます。


これでエラーメッセージの日本語化はできると思います！
【python】緯度経度をUTM座標に変換する

#はじめに
緯度経度、皆さん聞いたことがあると思いますが、東経・西経、北緯・南緯で表示される座標で、地球上での位置を示すものです。
しかしながら、GISを扱う上では緯度経度だけではなくUTM座標（ユニバーサル横メルカトル）が用いられることも少なくありません。
今回の記事では緯度経度の座標（地理座標）からUTM座標をpythonで取得する方法を記します。

UTMの解説についてはウィキペディアをご覧ください。
https://ja.wikipedia.org/wiki/%E3%83%A6%E3%83%8B%E3%83%90%E3%83%BC%E3%82%B5%E3%83%AB%E6%A8%AA%E3%83%A1%E3%83%AB%E3%82%AB%E3%83%88%E3%83%AB%E5%9B%B3%E6%B3%95
まあ、この中に変換式も書いてあるのですが難しいので・・・（私もよくわかっていません）

#コード
座標値を取得するには、pyprojというモジュールを使用します。
pythonでProjection(投影座標系、測地系の変換関数的な)を扱うためのライブラリ的なものです。
まずはインポートが必要ですね。

```python
from pyproj import Proj
```

緯度経度の設定をし、UTM座標値を取得します。
お試しであれば適当な数値でOKです。

```python
lon = 137.5
lat = 38.5

#UTMゾーンを求める
e2u_zone = int(divmod(lon, 6)[0])+31

#地理座標（緯度経度）からUTM座標系に変換するProjectionを設定する。
e2u_conv = Proj(proj = 'utm', zone = e2u_zone, ellps = 'WGS84') 

#座標値の取得
utmx, utmy = e2u_conv(lon, lat)

if lat < 0:
    utmy = utmy + 10000000
    
print(" UTM zone is ", e2u_zone, "\n", \
     "UTM Easting is ", utmx, "[m]\n", \
     "UTM Northing is ", utmy, "[m]")
```

出力結果

```python
 UTM zone is  53 
 UTM Easting is  718010.4028220479 [m]
 UTM Northing is  4264255.315546167 [m]
```

これでUTMでの座標値を得ることができました。
思ったより簡単に取得できました。
Beytoioの中身(toio SDK for Unityでtoioをベイ化)

# この記事でできること
- toio SDK for Unity を導入した直後に、あなたのtoioがベイ化します。

# どんなことをやったか
- チュートリアルでtoioの制御について一通り~~遊んだ~~触れたあと、
- ①時間経過で回転速度をあげてみた
    - 「cube.Move」の使用
- ②衝突判定をつけてみた(音が鳴る)
    - 「cube.PlayPresetSound」の使用
- ③衝突時に逆回転するようにした
    - 「OnCollision」の使用
    - 逆回転は、「cube.Move」内の引数に対して-1をかけることによって実現

# 実際の動画はコチラから
- [Beytoio VS インペリアルドラゴン(止まらない回転)](https://youtu.be/AxXphv2tZBc)
![BeytoioVSインペリアルドラゴンアイキャッチ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191635/8a8da2ce-dfe9-149d-519c-c7051215a0b2.jpeg)

# 環境設定について
- [toio SDK for Unity で、iPhoneなどでtoio実機に接続するまでのざっくりとした流れ(無課金でok)](https://qiita.com/sanpeita/items/57d318340d59b59b318e)

# コード
- プロジェクト内から、試行錯誤したゴミコメントを消したので、コピペして動かなかったらご連絡ください。

```

using UnityEngine;
using toio;

namespace toio.tutorial
{
    public class BasicScene : MonoBehaviour
    {
        float intervalTime = 0.05f;
        float elapsedTime = 0;
        Cube cube;

        int RotNum = 3;

        // 非同期初期化
        // C#標準機能であるasync/awaitキーワードを使用する事で、検索・接続それぞれで終了待ちする
        // async: 非同期キーワード
        // await: 待機キーワード
        async void Start()
        {
            // Bluetoothデバイスを検索
            var peripheral = await new NearestScanner().Scan();
            // デバイスへ接続してCube変数を生成
            cube = await new CubeConnecter().Connect(peripheral);
            // コールバック登録
            cube.collisionCallback.AddListener("BasicScene", OnCollision);
        }

        void Update()
        {
            // Cube変数の生成が完了するまで早期リターン
            if (null == cube) { return; }
            // 経過時間を計測
            elapsedTime += Time.deltaTime;

                cube.Move( (RotNum * (int)elapsedTime), (-1 * RotNum * (int)elapsedTime), 0);
        }

        void OnCollision(Cube c)
        {
            cube.PlayPresetSound(2);
            RotNum = -1 * RotNum;
        }
    }
}


```

---

#その他の情報
- [toio Advent Calendar 2020](https://qiita.com/advent-calendar/2020/toiotomo)
- 21日のアドベントカレンダーの記事…[12月に1248キーを自作してみたお話と、ベイtoioのお話](https://qiita.com/sanpeita/items/c72ecaa8bd844233e585)
- [フリー回転搭載ベイtoio VS インペリアルドラゴン](https://youtu.be/JnIEB_0A-A0)(Youtube)
- [1248キーで鬼ごっこtoio](https://youtu.be/uZbYI9jwQeA)(Youtube)
- @wotakuroさんの、[toioとボトルマンと 3Dプリンターの可能性](https://qiita.com/wotakuro/items/54635be62a6a3b589418)(toio Advent Calendar 2020：15日目)
- @HrshTkgさんの、[toioを使ったデジタルなチョロQ](https://qiita.com/HrshTkg/items/97c823646256ddabc4bf)(toio Advent Calendar 2020：11日目)
標高図を背景にした地図が描きたい

# 目的
地形の起伏とか標高が分かるような日本地図を背景にして、地点をプロットしたような地図が描きたい。できるだけ楽して良い感じに！
![標高図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/917414/3e8074e8-42c1-b61f-1b4c-ff8494a5429a.png)


# 準備
 - [地理院地図](https://maps.gsi.go.jp/)
 - QGIS3.4以上でやりました


# 手順
## 標高図の準備
1. [地理院地図](https://maps.gsi.go.jp/)にいく
2. 地理院地図のメニューから`標高・土地の凹凸` > `自分で作る色別標高図` を選択
3. `自分で作る色別標高図`の色指定のウィンドウが出るので、好きなようにカスタマイズ
 
 - いくつかカラーパターンも用意してあります。
 - 標高の階級も増減できます。
 - グラデーション・陰影も試してみる
 - 最低標高の色を白以外にすると、背景と区別がつきやすくなる
![スクリーンショット 2020-11-29 17.33.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/917414/bef03d8e-6eab-3c45-d15c-394f2c984d1f.png)
4. 色の指定ができたら、`スタイルをファイルに保存`して、次回`スタイルをファイルから読み込み` (やり直すときに色指定を最初からやり直さなくて便利)
5. `上記の内容で地図に反映`を押して小窓を閉じる。
6. 上部メニューから `設定` > `中心十字線`をOFF
![スクリーンショット 2020-11-29 17.39.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/917414/6b495eb1-67d7-77cc-8711-068f880cb945.png)

## 地理院地図上で地点を追加する場合
 1. すでに地点のファイルがある場合、上部メニューから `ツール` > `作図ファイル` > `ファイルからデータを読み込み`
 1. ポイントのアイコンやラベルを編集する
 1. そのまま印刷したりpdfにする場合、メニューの`印刷`
 1. 画像や他のウェブサイトで利用する場合、メニューの`共有`> 目的に応じて選ぶ
 1. 地点のファイルがない場合は、上部メニューから `ツール` > `作図ファイル`を選んで地点を追加したり編集したりする。
![スクリーンショット 2020-11-29 17.47.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/917414/10d298b4-981a-b4da-6880-5454d5a99b57.png)

## QGIS上で地点を追加する場合 

#### 地理院地図で標高図を出力

 1. メニューの`共有`> `画像を保存`と`ワールドファイルを保存`[^1]の両方で保存する。これで座標情報付きの画像として取り込めるようになる
![スクリーンショット 2020-11-29 17.56.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/917414/b9f8b1a6-6950-dab8-a30a-4a6f75a59928.png)
 [^1]: ワールドファイルについて, https://maps.gsi.go.jp/help/howtouse.html 

#### QGISで編集

 1. メニューの`レイヤ` > `レイヤの追加` > `ラスタレイヤの追加`で出力した画像を選ぶ 
 1. 取り込んだ標高図レイヤーの`プロパティ`を開いて、`ソース` > `ソースの座標参照系の設定` をWGS 84 / Pseudo-Mercator EPSG: 3857にする
 1. 地点のshpファイルなど色々追加して編集する
【アウトプット】　Guardの導入

Guardを使うと、ファイルが保存されたと同時にそのファイルのテストが行われるので、いちいちコマンドを打たなくてもよくなる。

##導入
GemfileにGemfileの :test グループと :development グループguard-rspec を追加。

```php:Gemfile
group :development, :test do
  gem 'guard-rspec', require: false
end
```
そして、bundle install。

それから、Guardfileを追加。

```
$ bundle exec guard init rspec
```
実行するには、次のコマンドを実行。

```
$ bundle exec guard
```
すると、guardが起動し、ファイルの監視が始まる。これを維持しておくと、ソースコードやテストコードを編集した時、RSpecが自動で実行される。
ECSを使うときに必要なポートを設定すべき3大箇所

## 前提
- 構成ECS＋ALB

##この解説の目的
ECSのネットワーク周りの設定でどこに何を設定すべきか度々わからなくなるので自分のための忘備録。
この設定をどこか間違えると502 Bat Gatewayとか受け取れます。
HTTPのみでSSLしない場合は、面倒なのですべてのポートを80に合わせて置くと、すべてのポートを80にしておけばいいので便利です。

この解説で取り扱う所:
ECSを使う時にポートを使う箇所のみ

### お断り
この解説は編集時(2020/11/27)時点でのAWSコンソール上の記述をもとにしているため,
用語が変わってしまう可能性があります。

## 目次
1. タスク定義のポート
1. ECSのクラスター、サービスの追加時のロードバランサ
1. セキュリティグループに追加すべきポート

## 1．タスク定義のポート
前提:
すでにECRにリポジトリがあり、イメージがpushされている

ECS/タスク定義/コンテナの編集
ポートマッピング/コンテナポート
- ここにはコンテナ化しているアプリが受け付けているポートを書く
- プロトコルは特にUDPに設定していない限りtcp

例: GolangのEcho使うと以下のようにサーバ起動時のportを指定するが、
ここに書かれているポート番号「1323」

```go:main.go
e.Logger.Fatal(e.Start(":1323"))
```

## 2.ECSのクラスター、サービスの追加時のロードバランサ

この解説に含まれるもの
ECSの既存クラスターに新しくサービスを追加する際の「ロードバランサ用のコンテナ」のセクションのみ

設定箇所の用語の説明:
- プロダクションポート
└ ALBが外から受け付けるポート、HTTPを受け付けるなら80．HTTPSを受け付けるなら443など
- プロダクションリスナープロトコル
└ALBが外から受け取るプロトコル
└例:サイトをssl化している場合はHTTPS443を設定する
└※注意※これはコンテナが受け付けているポートではない
- ターゲットグループ
└このECSのサービスを含めるターゲットグループ
└これをALBに登録することで、特定のパスへのアクセスを指定のターゲットグループ(サービス)へ転送する
- ターゲットグループのプロトコル
└ターゲットグループ内で使用されるプロトコル
└HTTP, HTTPSなど、大体はhttpだと思う
- パスパターン
└このサービスに転送すべきパスパターン
└後でALBのリスナーのルールから変更可能
- ヘルスチェックパス
└ALBからヘルスチェックが実行されてるので正常時に200を返却するURLを用意する
└ /health_check といったpathを用意しておくのが一般的

## 3.セキュリティグループに追加すべきポート
- すべてのプロトコル、すべてのポートを開放していない限り以下を設定する
- 2で設定したターゲットグループのプロトコル、1で設定しているコンテナポートを設定しておく
例:アプリがTCP 1323ポートで動いている場合は
カスタムポート TCP 1323 ソース:属するVPC

ここの設定をしていないと、ALBからヘルスチェックですら到達できないので、ECS上で起動しているけどヘルスチェックで失敗する時はここも確認する
matplotlibで日本語フォントを使うには

ちょっと調べたら「matplotlibrcの書き換え」とか、沢山方法はあるみたいですが、なんだか面倒だったので一番簡単かと思われる方法をメモしておきます。


# ttfファイルのダウンロード
[IPAexフォント/IPAフォント](https://ipafont.ipa.go.jp/old/ipafont/download.html)
準備として、例えば上のようなサイトとかからTTFフォントのファイルをダウンロードします。

# 設定
試しに、簡単な折れ線グラフにラベルをつけてみます。

```.py
%matplotlib inline
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties


font_path= "ttfファイルのPATH"
font_prop =matplotlib.font_manager.FontProperties(fname=font_path,size=20)

x = [1,2, 3, 4, 5]
y = [5, 1, 3, 2, 4]


plt.xlabel('xラベル',fontproperties=font_prop)
plt.ylabel('yラベル',fontproperties=font_prop)
plt.plot(x, y)
plt.show()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287296/0a7e3062-8c43-c5f1-8faf-0fabded770ed.png)



参考
-
[matplotlibで日本語フォントを使うサンプル](https://gist.github.com/yamakk/1246530/773838e24e230416bb99bc32b73a4584311010cc)
[matplotlibで日本語](https://qiita.com/canard0328/items/a859bffc9c9e11368f37)
TypeScript: 配列の長さを宣言する

## やりたいこと

```
const numbers = [1, 2, 4, 5] as const
const foo = ['f', 'o', 'o'] as const


let numbers_len1: Length<typeof numbers> = 4; //OK
let numbers_len2: Length<typeof numbers> = 5; //エラー
let foo_len1: Length<typeof numbers> = 3; //OK
let foo_len2: Length<typeof numbers> = 4; //エラー

```

となるように，配列の長さを宣言するLength typeを作りたい。


## 結論
- 解決法１

```
type Length<T extends ReadonlyArray<any>> = T['length']
```

- 解決法２

```
type Length<T extends readonly any[]> = T['length']
```

- 解決法３

```
type Length<T extends any> = T extends { length : infer R } ? R : never;
```



## 解説

すべてGenericsを使っています。
ジェネリクスに関しては色んな方が分かりやすい記事をあげているのでそちらを参考にしてください。
https://qiita.com/uhyo/items/e2fdef2d3236b9bfe74a#%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%AA%E3%82%AF%E3%82%B9




### 解決法１
```
type Length<T extends ReadonlyArray<any>> = T['length']
```

[ReadonlyArray](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#improvements-for-readonlyarray-and-readonly-tuples)という型がTypeScriptに用意されています。

> The ReadonlyArray type describes Arrays that can only be read from
> 
```
function foo(arr: ReadonlyArray<string>) {
  arr.slice(); // okay
  arr.push("hello!"); // error!
}
```

名前の通り，配列を変更するようなメソッドは使えませんが，今回のようにlengthを取得することはできます。


### 解決法２


```
type Length<T extends readonly any[]> = T['length']
```

解決法１とほぼ同じです。

今回は配列をas constでreadonlyとしているので，
`type Length<T extends any[]> = T['length']` 
とすると以下のエラーが発生してしまうので注意してください。

> The type 'readonly [1, 2, 4, 5]' is 'readonly' and cannot be assigned to the mutable type 'any[]'.


### 解決法３

```
type Length<T extends any> = T extends { length : infer R } ? R : never;
```

inferについては[こちらの記事](https://qiita.com/ringtail003/items/733aff32ddad7d4fda90)が分かりやすいです。

T.lengthが存在する場合はそのlengthを返し，存在しない場合はneverを返しています。


## 補足
[TypeChallenge](https://github.com/type-challenges/type-challenges)というサイトに問題がたくさん載っていて，その中の[Length of Tuple](https://github.com/type-challenges/type-challenges/blob/master/questions/18-easy-tuple-length/README.md)という問題になっています。

上記以外にもたくさん解答があるので参考にしてください。
https://github.com/type-challenges/type-challenges/issues?q=label%3A18+label%3Aanswer
Railsの名前空間

#概要
アプリケーションにて管理者専用画面を作ろうとした際、名前空間(namespace)という概念を採用したのでどのようなものなのか簡単にまとめてみます。

#名前空間とは
元々のクラスに対しモジュールを追加したクラスを新たに作成する。その時、元々のクラスとモジュールを追加したクラスは別物と区別されます。その状態を**別の名前空間にある**という。

```ruby:例
# 下記二つのクラスは別物と区別される
Admin::UsersController
UsersController
```

このように二つのコントローラを分ければ、管理者と一般ユーザーを容易に別のコントローラで分けることができます。

#ディレクトリの設定
名前空間を使った場合、ディレクトリは名前空間ごとにサブディレクトリを作ります。

#名前空間を使ったルーティングの設定
ルーティングの設定はnamespaceメソッドを使用し、引数に名前空間の名前をシンボルで設定し、ブロックで囲みます。

```ruby:例
namespace :admin do
  root "top#index"
  resources :users
end
```

urlパスは/adminからそれぞれのアクションへルーティングが設定されます。
パスの指定は下記のような例があります。

```:例
<%= link_to "管理者用ページ", :admin_root %>
<%= link_to "ユーザー新規作成(管理者用)", :new_admin_users %>
<%= link_to "ユーザー一覧(管理者用)", :admin_users %>
<%= link_to "ユーザー編集(管理者用)", [:edit, :admin, :user] %>
```

```ruby:例
class Admin::UsersController < Admin::Base
#省略
redirect_to [:admin, @user]
```

#補足
名前空間を使用する、特にコントローラを分ける際、コントローラによって操作や表示を切り替える場面は多くあると思います。kind_ofメソッドを使えばコントローラによって条件分岐等をする際便利です。

```:例
<% if controller.kind_of?(Admin::UsersController) %>
```

#まとめ
名前空間について簡単にまとめました。
簡単なアプリケーションであれば、一つずつ条件分岐すれば良いのですが、複雑なアプリケーションにそのようには行かないので、便利な機能でありプログラミングらしい機能だなと思いました。
AtCoder 生活101日目

[前回](https://qiita.com/flandrescarlet237/items/458296042bf9bdfd97d5)

#101日目
今回は灰色diffを3問ときました。

|問題|難易度|自力で解けた|かかった時間|
|:-:|:-:|:-:|---|---|
|ABC055|B|◯|3分35秒|
|ABC100|C|◯|16分44秒|
|ABC144|C|✕|46分41秒|


##[ABC055_B](https://atcoder.jp/contests/abc055/tasks/abc055_b)

```c++

#include <bits/stdc++.h>
#define rep(i,n) for(int i = 0;i < (n);i++)
using namespace std;
using ll = long long;
using pii = pair<int,int>;

const int INF = 2e9;
const int MOD = 1e9 + 7;

int main(){
    int n;
    cin >> n;
    ll ans = 1;
    rep(i,n){
        ans *= (i+1);
        ans %= MOD;
    }
    cout << ans << endl;
}

```

解くのにかかった時間：3分35秒


##[ABC100_C](https://atcoder.jp/contests/abc100/tasks/abc100_c)

```c++

#include <bits/stdc++.h>
#define rep(i,n) for(int i = 0;i < (n);i++)
using namespace std;
using ll = long long;
using pii = pair<int,int>;

const int INF = 2e9;

int CN(ll n){
    int cnt = 0;
    while(n%2 == 0 && n != 0){
        n /= 2;
        cnt++;
    }
    return cnt;
}

int main(){
    int n;
    cin >> n;
    vector<ll> a(n);
    rep(i,n)cin >> a[i];
    ll cnt = 0;
    rep(i,n){
        cnt += CN(a[i]);
    }
    cout << cnt << endl;
}

```

解くのにかかった時間：16分44秒


##[ABC144_C](https://atcoder.jp/contests/abc144/tasks/abc144_c )

```c++

#include <bits/stdc++.h>
#define rep(i,n) for(int i = 0;i < (n);i++)
using namespace std;
using ll = long long;
using pii = pair<int,int>;

const int INF = 2e9;

int main(){
    ll n;
    cin >> n;
    ll ans = INF;
    ll s,t;
    ll x = sqrt(n);
    for(int i = 1;i < x+1;i++){
        if(n%i == 0){
           s = i; 
        }
    }
    t = n/s;
    cout << t + s - 2 << endl;
}

```

解くのにかかった時間：42分21秒
感想：全然通らなくて解説見てもアプローチ一緒で自力解決するのにものすごい時間食われた。


###最後に
少しずつだが感覚を取り戻せてきた気がする。次からはもう少し難しめな問題も挑戦していこうかと思う。
Goでコールグラフを自作してみた

[フューチャー Advent Calendar 2020](https://qiita.com/advent-calendar/2020/future)の8日目の記事です。

普段はJavaの静的解析をすることが多いですが、今回はGoの静的解析に手をつけてみました。本記事ではGoでコールグラフ自作をしてみたいと思います。すでに[ofabry/go-callvis: Visualize call graph of a Go program using dot (Graphviz)](https://github.com/ofabry/go-callvis)といったコールグラフ作成ツールがありますが、今回はあえてコールグラフを自作して既存のツールを使うだけではできない拡張をしてみました。

なお私はGoはあまり書いたことがないのでツッコミどころは多々あるかと思います。気になる点などございましたらご指摘いただけると幸いです。

## シンプルなコールグラフ作成

GoではGoのソースコードの静的解析を行うライブラリが準標準パッケージとして用意されているようで、それを使うだけで簡単にコールグラフを可視化することができました。まずは何も考えずにコールグラフを作成してみました。

今回は[isucon/isucon10-qualify: ISUCON10予選](https://github.com/isucon/isucon10-qualify)のソースコードを対象にコールグラフを作成してみましょう。コールグラフは関数をノード、関数呼び出しをエッジとしており、ノードには`パッケージ名.関数名`というラベルを、エッジには`file=ファイル名, Line=行番号`というラベルを表示しています。

## 解析結果 その1（何も考えず全て表示）

下記のようなグラフになりました（オリジナルの画像は大きすぎるせいかQiitaにアップロードできなかったので縮小しています）
解析に使用したソースコードは[解析結果 その1](https://gist.github.com/tanzaku/9e3aa4d01bdf5b607a46a3cdb240289a)です。

![graph_base.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385850/6e4319e4-8a2a-a5ec-d90d-aa42c99877ac.png)

あまりにも巨大で何が何だかよくわかりませんね。グラフを見てみると、ISUCONではそんなに重要でないログ出力などが多数含まれています。まずは特に重要なCRUDに注目したいということで、思い切ってcalleeがsql, sqlx以外のpackageへ繋がるエッジは除外してみましょう。

## 解析結果 その2（sql,sqlx以外のエッジを除去）

これくらいなら全容が把握できそうと思える規模になってきました。
解析に使用したソースコードは[解析結果 その2](https://gist.github.com/tanzaku/53d63742556463c49c8f9c027eab500f)です。

![graph_crud.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385850/77130b15-c336-53ab-cfa4-8803f458e80b.png)

これを見ればどの関数でCRUDが行われているか把握できそうですね。
ただし、これだけではどのエンドポイントからどのCRUDが行われているかわからないので今度はエンドポイントを表すノードを追加してみましょう。

## 解析結果 その3（エンドポイントのノードを追加）

どのエンドポイントでCRUDが行われているかわかるようになりました。本当はどのテーブルのどのカラムにアクセスしているかといった情報も載せたかったのですが、そこまでは手が回りませんでした。
解析に使用したソースコードは[解析結果 その3](https://gist.github.com/tanzaku/a17360e6f39afbb5df7c9b033cc9e824)です。
（わかりやすいようにエンドポイントはlightgreenで着色しています）
![graph_add_endpoint.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385850/080b6867-82b5-0c1c-faad-38f2fec80abb.png)

## まとめ

Goの準標準パッケージがとても充実しており、サクッと静的解析できて素晴らしいなと感動しました。

単にコールグラフを作るだけなら既存のツール[^1]を使えば済みますが、自作することで自由にカスタマイズすることができ、知りたいこと、伝えたいことにフォーカスしたコールグラフが作成できそうですね。

また今回のようにCRUDだけに注目するのではなく、開発したアプリをうまく可視化することで後からチームに入ってきた人が設計を理解する資料の一つとして使ったり、あるいは既存のLintでは対応できない項目のチェックができたり[^2]とうまく活用すれば静的解析はとても有用そうだと思いました。

（余談ですがssautilパッケージのAllPackages関数は[ssautil · pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/go/ssa/ssautil#AllPackages)のドキュメントには `Load function in LoadAllSyntax mode.` と書かれているので `LoadAllSyntax` という定数でモード指定することを推奨しているような気がするのですが、この[packages · pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/go/packages)をみると`LoadAllSyntax`はdeprecatedなんですよね。使うべきなのかそうでないのか…）

## 参考

- [逆引きGoによる静的解析入門 - tenntenn - BOOTH](https://booth.pm/ja/items/1319394)
- [ofabry/go-callvis: Visualize call graph of a Go program using dot (Graphviz)](https://github.com/ofabry/go-callvis)


[^1]: [ofabry/go-callvis: Visualize call graph of a Go program using dot (Graphviz)](https://github.com/ofabry/go-callvis)
[^2]: [特定の関数やメソッドの呼び出しを検知するLinterを作った - tenntenn.dev](https://tenntenn.dev/ja/posts/called/)
pythonでjsonの配列にアクセスする

pythonでjsonの配列にアクセスする時のメモ

jsonファイル

```json:test.json
{
    "section1":{
        "key":"key1",
        "number": [ 
                    ["a", "b"],
                    ["c", "d"],
                    ["e", "f"]
                  ]
    },

    "section2":{
        "key":"key2",
        "number": 2
    }
}
```

pythonファイル

```python:test.py
import json

json_open = open('test.json', 'r')
json_load = json.load(json_open)

print(json_load)
print(json_load["section1"]["number"][0])
print(json_load["section1"]["number"][1])
print(json_load["section1"]["number"][2])
print(json_load["section1"]["number"][0][0])
print(json_load["section1"]["number"][0][1])
```

実行

```shell
$ python test.py
{'section1': {'key': 'key1', 'number': [['a', 'b'], ['c', 'd'], ['e', 'f']]}, 'section2': {'key': 'key2', 'number': 2}}
['a', 'b']
['c', 'd']
['e', 'f']
a
b
```

# 参考
[非エンジニアのためのJSON入門](https://qiita.com/shuntaro_tamura/items/5a92c517a7d95d655505)
【React】 AWSにデプロイする

# はじめに

React を習得するまでの軌跡をメモっていく備忘録的な記事です。

## AWS の S3 にデプロイする

S3 の静的サイトホスティング機能を使ってデプロイします。

### 準備

サンプルコードを clone してきます。
中身は redux-toolkit の公式サイトで紹介されているサンプルのTODOアプリです。

~~~
$ git clone https://github.com/reduxjs/rtk-convert-todos-example.git
~~~

アプリのディレクトリに移動し yarn build を実行します。

~~~
$ cd rtk-convert-todos-example
rtk-convert-todos-example $ yarn build
~~~

アプリの中に新しく build というディレクトリができたと思います。
確認してみましょう。

~~~
rtk-convert-todos-example $ ls
README.md	jsconfig.json	package.json	src
build		node_modules	public		yarn.lock
~~~

build ディレクトリができていますね。
build ディレクトリの中身も見てみましょう。

~~~
rtk-convert-todos-example $ ls build
asset-manifest.json
favicon.ico
index.html
logo192.png
logo512.png
manifest.json
precache-manifest.4cc66b9b5865646273439dd929f332c4.js
robots.txt
service-worker.js
static
~~~

色々なファイルができていますね。

これらをS3にアップロードします。


### デプロイしていく

まずS3バケットを作りましょう。
「バケットを作成」と言うボタンをクリックしてください。

![スクリーンショット 2020-11-29 23.31.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559794/dfe96b12-ab4d-fcab-db7b-f0e584346138.png)



バケット名を入力してください。
他の設定などは全てデフォルトで大丈夫です。

![スクリーンショット 2020-11-29 23.26.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559794/6c8bb523-5e97-bf46-7016-af3d4c3de451.png)

バケットの作成ができたらS3のバケット一覧画面から先ほど作ったバケットを選択するとバケットの編集画面に遷移します。

![スクリーンショット 2020-11-29 23.36.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559794/bc1572af-2657-5503-4019-8e49f0eb5f45.png)


この中でプロバティというタブをクリックすると静的ウェブサイトホスティングという項目が出てきます。
この項目の設定を変更したいので編集ボタンをクリックします。

![スクリーンショット 2020-11-29 23.39.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559794/371c289c-f0eb-a2f9-03dc-c8514bac88c2.png)


- 静的webサイトホスティングを有効に
- インデックスドキュメントは index.htmlと入力してください。
- エラードキュメントは error.htmlと入力してください。
- 他はデフォルトで大丈夫です。

設定ができたらバケットの編集画面からオブジェクトタブをクリックしてファイルをアップロードします。
build ディレクトリの中身をそのままドラッグアンドドロップで大丈夫です。

このままだとアクセスできないので設定をを変更します。
バケットの編集画面からアクセス許可のタブをクリックしてください。
 

バケットポリシーを設定します。。
`arn:aws:s3:::awsexamplebucket1`の部分を自分の ARN に変えてそのままコピペして貼り付けるだけで大丈夫です。

~~~
{
  "Version":"2012-10-17",
  "Statement":[
    {
      "Sid":"PublicRead",
      "Effect":"Allow",
      "Principal": "*",
      "Action":["s3:GetObject","s3:GetObjectVersion"],
      "Resource":["arn:aws:s3:::awsexamplebucket1/*"]
    }
  ]
}
~~~

ブロックパブリックアクセスは上の二つだけチェックして他はチェックを外してください。
![スクリーンショット 2020-11-29 23.46.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559794/eaa12e66-c1d2-7b86-4847-e705ae575be0.png)

プロパティの静的ウェブサイトホスティングの項目に記載のあるURLにアクセスし、以下のようなTODOアプリが表示されたら成功です。

![スクリーンショット 2020-11-29 23.53.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559794/c1157f2e-af6e-7a5f-1a0e-73e71041dd2f.png)
ExcelのセルへのペーストをテキストだけにするAHKスクリプト

# ExcelのセルへのペーストをテキストだけにするAHKスクリプト

ウェブサイトなどからエクセルのセルにコピペした際にフォント情報までコピーされるのが煩わしかったので，テキストのみのペーストをするAHKコードを書いた．無変換+vに割当て．

```abap:excel_paste_value

#UseHook

#IfWinActive, ahk_exe EXCEL.EXE

vk1D & v:: ;無変換+v
	KeyWait, vk1D, T0.01
	If(ErrorLevel)
	{
		ClipSaved := ClipboardAll ;もとのクリップボードを保存
		Clipboard = %Clipboard% ;テキストデータのみの取り込み
		Send, ^v ;ペースト
		Sleep, 100 
		Clipboard := ClipSaved ;もとのクリップボードデータの復元(Sleepが無いとペーストより先に復元されてしまう)
		ClipSaved = 
		KeyWait,vk1D

		Return
	}

```
--------------------
- 古いAHKだと無変換キーが `vk1Dsc07B`かも
- AHKのシンタックスハイライトを実装してほしい
− 2020/12/16追記 忌まわしきセル結合を消せてなかったので対応する必要がある
TableViewセルの作り方 その１（Prototype Cells）（忘備録）

##手順

###1. Prototype Cellの追加とセルの設定
 - Storyboardで配置したTableViewを選択
 - Attributes inspectorでPrototype Cellsの数を増やす

![スクリーンショット 2020-11-29 22.51.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918084/c87db033-1667-6ca3-2e27-de64605f1168.png)

###2. セルのUITableViewCellクラスの設定

 - コードでUITableViewCellのClassを作成する（下記Code参照）
 - StoryboardのPrototypeCellを選択してIdentity inspectorでCustomClassに作成したClassを設定

![スクリーンショット 2020-12-01 23.25.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918084/f8f51ef4-4005-c653-7e52-f8d4a2e4f749.png)

###3. セルのIDを設定
 - StoryboardでCellを選択しAttributes inspectorのIdentifireにセルのIDを設定

![スクリーンショット 2020-12-01 23.22.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918084/ec6ce304-974d-cf2d-c8ce-132b27224b70.png)


###4. ViewControllerとUITableViewCellとの接続

TableViewはViewControllerクラスに接続して、CellのUIはUITableViewCellのクラスに接続する。
※先にClassを指定しておかないとつながらない。
※接続時にエラーが出るなどうまくいかない場合は一度ビルドする。

###コード

```ViewController.swift
import UIKit

class ListViewController: UIViewController {
  
  private let cellId = "cellId"
  
//TableViewの接続
  @IBOutlet weak var listTableView: UITableView!

  override func viewDidLoad() {
    super.viewDidLoad()
    
    listTableView.delegate = self
    listTableView.dataSource = self 
  }
}

// MARK: - UITableViewDelegate, UITableViewDataSource
extension listViewController: UITableViewDelegate, UITableViewDataSource{
  //Cellの高さ
  func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 80
  }
  //セルの個数
  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 10
  }
  //cellの中身を設定
  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = listTableView.dequeueReusableCell(withIdentifier: cellId, for:indexPath)
    //cellIdはストーリーボード側のセルにも設定する
    return cell
  }
}


// MARK: - UITableViewCell
class ListTableViewCell: UITableViewCell{
  
//CellのUIをOutlet接続
  @IBOutlet weak var imageView: UIImageView!
  @IBOutlet weak var msgLabel: UILabel!

  //awakeFromNibは「func」のみの方を選択
  //StoryBoardやxibファイルからインスタンス化される場合に呼ばれる
  //Nibファイルが開かれ、使用準備が完了。
  override func awakeFromNib() {
    super.awakeFromNib()

    //UIのプロパティーなどを記述
    imageView.layer.cornerRadius = 35
  }

  //セルの選択された状態を設定し、オプションで状態間の遷移をアニメーション化する
  override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)
  }
```
GDALをインストールするときに「Solving environment： faild ~」となった際の対処法

#この記事は・・・
pythonで地理空間情報を扱えるGDALをインストールする際に環境設定がうまく行かなかったようで、色々と対処をしたのでその記録です。
結果として、インストール中にしばらく待つだけで解決してたかもしれないので、参考にされる方は自己責任でお願いします。

#インストールを行った環境
Anaconda3　ver.1.7.2
python 3.7.9

#不具合の内容
まずはcondaコマンドを使ってインストールを試行しました。

```
conda install -c conda-forge gdal
```

その結果、「Solving environment： faild ~」となってインストールが完了しません。
確か5分ほどはインストールがすすまずに同じようなメッセージが続きました。

一旦インストールを中断して対処法を探しました。

#対処法
##対処1
・Anacondaのアップデート
これは当たり前ですかね。以下のコマンドを実行してAnacondaのすべてのパッケージを最新にアップデートしました。

```
conda update --all
```

しかし相変わらず同様のエラーが出てインストールが完了しない。

##対処2
・環境変数の設定
以下の記事を参考にして環境変数を追加しました。

「anacondaでconda createを実行しようとすると「 Solving environment: failed 」と出て実行できなかった」
https://qiita.com/kizul/items/43a15a21346d121907c6

それでも相変わらずエラーが出ます・・・

##対処3
・バージョンを指定してインストール
以下の記事を参考にしました。

「【超初歩】AnacondaにGDALをインストールしてみた」
https://qiita.com/skperfarming/items/34b18d7cdce20982aa03

どうやらバージョンを指定したほうがいいらしい？
バージョンの確認は以下のコマンドで可能です。

```
conda search gdal
```
結果

![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/584833/6452cb59-4dc8-5fdb-cd1d-aca4760dfccb.png)

本記事執筆時点（2020/11）では、3.0.2が最新のようです。
以下を実行する。

```
conda install gdal==3.0.2
```

これでも同じようなエラーが出ます。

#結局・・・
対処法3を適用してもだめだったので、プロンプトをそのまま放置して更に対処法探しを再開します。
すると10分くらい経ったところで処理が進みました！

え？

インストールするときにある程度のところでプロンプトの表示が更新されるので、ログは拾えていませんが（真っ黒になって遡れなくなる）、インストール自体は完了したらしい。
動作確認のためにpythonコンソールで以下を実行。

```
>>>from osgeo import gdal
>>>
```

え？通った・・・？
あまり腑に落ちませんが、時間の問題ってだけで待っていればインストールできたのではないかと思います。
必要だったとしたらバージョンの指定で、環境変数は必要ないかもしれません。
ちょっと疑問は残りましたが、GDALが使えるようになったのでOKとしましょう。
【Vue.js】cowsayをブラウザ上に表示させてみた

# はじめに
![スクリーンショット 2020-11-29 23.07.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635852/c0acc67c-9388-4085-8b36-dea0038e2981.png)
cowsayがかわいいのでVue.jsでブラウザ上に表示させたくなりました。

# インストール
[cowsay-browser](https://www.npmjs.com/package/cowsay-browser)を使用します。

```:ターミナル
npm install cowsay-browser
```

# インポート
`cowsay-browser`をインポートします。

とりあえずコンソールに表示させてみます。

```Vuejs:App.vue
<script>
import cowsay from 'cowsay-browser'

export default {
  created() {
    console.log(cowsay.say({text : "Hello!"}));
  }
}
</script>
```
![スクリーンショット 2020-11-29 23.19.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635852/d848aa5f-5bd9-8500-dc7f-d6b8556c8653.png)

来た！！

あとはブラウザに表示させるだけです。

# ブラウザへ

```Vuejs:App.vue
<template>
  <div>
    <pre>{{ cowsay }}</pre>
  </div>
</template>

<script>
import cowsay from 'cowsay-browser'
export default {
  data() {
    return {
      cowsay: '' 
    }
  },
  created() {
    this.cowsay = cowsay.say({text : "Hello!"});
  }
}
</script>
```

![スクリーンショット 2020-11-29 23.23.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635852/ec687ed6-ba66-e48d-0cf6-47245d75bcc8.png)

***

な、なんかズレて...る.......

# 調整する

せっかくなので少しソースコードをいじります。
node_modules>cowsay-browser>lib>cow-definitions.jsをいじればいけそうです。

```javascript:cow-definitions.js

//-------省略


  "default": "$the_cow = <<\"EOC\";\r\n        $thoughts   ^__^\r\n         $thoughts  ( $eyes )\\\\_____\r\n             (__)\\\\              )\\\\/\\\\\r\n             $tongue       ||-------w |\r\n                      ||             ||\r\nEOC\r\n",


//-------省略
```

![スクリーンショット 2020-11-29 23.36.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635852/5fec360c-8937-c5ef-5c95-1774923dbeeb.png)
・・・まあいいでしょう！（投げやり）

# おしまい
![スクリーンショット 2020-11-29 23.47.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635852/4b189bdc-d70a-8cad-3339-12c4e03488db.png)
mp3を一括でCBR 320k 48Khzにアップコンバートするコマンド

# これは何
特定のビットレート以下のmp3を一括でアップコンバートするコマンド。
もちろん、もとの音質が悪すぎる場合はやっても効果はないです。mp3って非可逆圧縮だし。

# source
[tknr/upconvert\_mp3](https://github.com/tknr/upconvert_mp3)

# requires
ffmpeg
sox

# install
cloneしてから

```
install.sh
```

で /usr/local/bin/upconvert_mp3 が配置される

# usage
```
upconvert_mp3 [-b アップコンバート先ビットレート デフォは320] [-t これ以下のビットレートなら320kにアップコンバートするよという指定 デフォは160] [-r アップコンバート先ビットレート デフォは48000] [-d 対象フォルダ]
```

以上!((c)厚切りジェイソン)
30代からのプログラミング勉強　５日目（HTML/CSS入門編）

時間があまりとれなかったので本日は少なめです…が、習慣化したいので投稿はしていきたいと思います。

##学習内容
昨日から引き続き。


###CSS

```CSS:枠線を消す
div {
  border: none;
}
```
デフォルトで入っている枠線を消すことが出来る。

```CSS:任意部分に枠線を引く
div {
  border-bottom: 1px solid #d1d1d1;
}
```
上記の様に記入した場合領域の`下部`に`1px`の`グレー`の`実線`が入る。例により`top`、`right`、`left`にそれぞれ置き換える事で引かれる場所の指定が可能。

```CSS:文字サイズ調整
div {
  font-size: 1.2em;
}
```
上記の場合だと元々設定された値の1.2倍の大きさになる。

```CSS:角を丸める
button {
  border-radius: 5px;
}
```
この様にするとボタンの角が5ピクセル分丸くなる。

##所感
本日は不完全燃焼…明日の休みに一気に進めていきたいところ。
ドメインを取得して、Route53を使ってIPアドレスと紐付けた

#はじめに
　現在作成中のポートフォリオのアプリにちゃんとURLを付けたくて、Route53とドメインを他で取得して、IPアドレスに紐づけた。

##流れ
1. お名前.comでドメインを取得
2. AWSのRoute53で紐付け
3. お名前.comでネームサーバーを変更

###1. お名前.comでドメインを取得
　
お名前.comにサインアップして、ドメインを購入。300円弱。

###2. AWSのRoute53で紐付け
　Route53でホストゾーンの作成をする。そのホストゾーンで先程取得したドメインと以前からデプロイしていたIPアドレスを紐づける。
この紐づけるというのは、ドメイン名で接続すれば、Route53側でドメイン名をIPアドレスに読み替えて、IPアドレスに接続してくれるということ。

###3. お名前.comでネームサーバーを変更
　お名前.comでネームサーバーを登録する。先のRoute53でドメインを登録した時に、4つ生成されるものを、お名前.comに登録する感じ。

##最後に
これで、URLで接続できるようになったが、httpのため、`安全ではありません`の表示がでる。やはり、httpsで接続できるようにするべきなのか、悩む。
音源を一括でmp3に変換するコマンド

# 枕

1.USBメモリでDJする場合
[rekordbox – CLOUD\-CONNECTED PROFESSIONAL DJ PLATFORM](https://rekordbox.com/ja/2020/11/new-rekordbox-tutorial-series/)
経由でUSBメモリに音源を転送する際に、Windowsだと対応機種に読み込ませるために
USBメモリをFAT32でしかフォーマットできないため、USBメモリの上限が32GBである

2.iPhoneでDJする場合
[DJ App for iPad and iPhone \- djay by Algoriddim](https://www.algoriddim.com/djay-ios)
で使用するためにiPhoneに音源を転送する必要がある(Spotify連携はしたことがないし、連携対応自体ディスコンになっている)が、
自分が所有している初代iPhone SEの容量が128GBである

# つまり
wavとかflacみたいな非可逆圧縮音声ファイルだとすぐ容量が一杯になっちゃうの。
そこでmp3ながらもDJでの使用に差し支えない(個人の感想です)CBR 320K 48Khzの音質に圧縮する必要がある。

# src
[tknr/convert\_to\_mp3](https://github.com/tknr/convert_to_mp3)

# require

lame
sox
[gitベースのstaticビルドのffmpeg 64bit 最新版をインストールするshell \- Qiita](https://qiita.com/geishagirlskoume/items/4f3a5bf94c1e7da655ee) のffmpeg

# install
cloneしてから

```
bash install.sh
```

で /usr/local/bin/convert_to_mp3 が配置される。

# usage
```
convert_to_mp3 [一括でmp3へ変換したいフォルダ]
```


以上!((c)厚切りジェイソン)
ローカルでPHP+Composer環境を作ってちょっとテストしたいとき

## 事前準備

- Windows10
    - wsl2+Ubuntuをセットアップしておく
    - wsl2+Ubuntu上でPHPをインストールする

```bash
sudo apt update
sudo apt install php7.4
# 必要に応じて各モジュールもインストール(php7.4-zipやphp7.4-xmlなど)
```

## 手順

- composer取得
    - [https://getcomposer.org/download/](https://getcomposer.org/download/)
- composer init実行

```bash
php composer.phar init
# いろいろ聞かれるが全部Enter or Noを選択
```
- composerを使って試したいパッケージ等をインストール

```bash
# 例: MessagePackを試してみる
php composer.phar require rybakit/msgpack
```

- dump-autoload実行

```bash
php composer.phar dump-autoload
```

- 次のようなディレクトリ構成が作成される

```none
+
|-- composer.json
|-- composer.lock
|-- composer.phar
|-- vendor
    |-- [requireしたpackage群]
```

- 直下に作成したスクリプトの一番最初の列に下記を追加

```php
<?php
require __DIR__ . '/vendor/autoload.php';
```

- 実行

```php
php test.php
```
Java abstractキーワード

#１，abstractとは
abstractクラスは、インスタンス化することができませんが、サブクラス（子クラス）を持つことができます。
abstractメソッドは、実装しない宣言です、

#２，ソースコード

```java:Main.java
public class Main {

	public static void main(String[] args) {

		// abstract = abstract classes cannot be instantiated, but they can have a subclass
		//            abstract methods are declared without an implementation
		Car car = new Car();
		car.go();
	}
}
```
>スーパークラス（親クラス）には、abstractがついているのでインスタンス化できません👇

```java:Vehicle.java
public abstract class Vehicle {

	abstract void go();
}

```
>親クラスに、abstractメソッドがあるので、必ずオーバーライドする必要があります👇

```java:Car.java
public class Car extends Vehicle {

	@Override
	void go() {
		System.out.println("The driver is driving the car.");
	}
}

```
Linux 標準シェル（bash）の主な環境設定ファイル

#【Linux 標準シェル（bash）の主な環境設定ファイル】

##全ユーザー

<strong>bash起動時に読み込み</strong>

・/etc/bash.bashrc
→bash起動時に実行させたい処理（Debian系)　

・/etc/bash.rc
→bash起動時に実行させたい処理（RedHat系）

<strong>ログイン時</strong>

・/etc/profile
→環境変数、利用環境にかかわるもの

##各ユーザー 個別

<strong>ログイン時</strong>

・~/.bash_profile 
→環境変数などユーザー環境にかかわるもの

※ このファイルのパーミッションには、読み取り権が必要。
このホームディレクトリの所有者であるユーザは読み書き権限を持つ。

・~/.bash_login
→/bash_profileがない場合の読み込み次候補（/.bash_profileと内容同じ）

・~/.profile
→/.bash_loginがない場合の読み込み次候補（/.bash_profileと内容同じ）

<strong>bash起動時</strong>

・~/.bashrc 
→bash起動時に実行させたい処理

<strong>ログアウト時</strong>

・~/.bash_logout
→ログアウト時に実行させたい処理
[Flutter 開発]Error retrieving thread information: (ipc/send) invalid destination port　のエラーに対する解決法

Flutter開発中、iOSのシミュレータを使ってRunすると、途中でConsoleに以下のメッセージが連続して出没した、、、
`[VERBOSE-2:profiler_metrics_ios.mm(184)] Error retrieving thread information: (ipc/send) invalid destination port`


ということで、今後の自分のための備忘録です。
[参考記事](https://github.com/flutter/flutter/issues/63025)を参考に試してみました。


##解決法
PCの再起動
[Azure Functions] 一定確率で少し待ってから応答を返す関数 (C#)

# はじめに

LBの動作やアプリ側の挙動確認のため、一定の確率で応答に時間をかけてから返すサービスを作っておきたいなー…と思いたち、Azure Functions で簡単に作ってみました。

# 環境

* .NET Core 3.1

# コード

Visual Studio 2019 のテンプレートから HTTP Trigger で作成。

```C#
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace Random10SecFunction01
{
    public static class Function1
    {
        [FunctionName("Random10SecFunction01")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            int WAIT_TIME = 10; // seconds
            Random rnd = new Random(Environment.TickCount);

            if (rnd.Next(0,99) < 10)
            {
                log.LogInformation("Wait...");
                await Task.Delay(WAIT_TIME * 1000);
            }

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data = JsonConvert.DeserializeObject(requestBody);

            string responseMessage = "This HTTP triggered function executed successfully.";

            return new OkObjectResult(responseMessage);
        }
    }
}
```

## Usage

下記のようにアクセスすると、既定では90%の確率で即時応答、10%の確率で10秒間待ってレスポンスを返します。

```
<URL>/Random10SecFunction01
```
閉じられたネットワーク内のiPadを自動で時刻調整できるように設定する

# 概要

インターネット接続のないLAN内にいるiPadの時刻が徐々にずれてきたので、時刻設定を自動でできるようにしてみた。

MacやiOSで使用するNTPサーバのFQDNは[エンタープライズネットワークで Apple 製品を使う \- Apple サポート](https://support.apple.com/ja-jp/HT210060)で確認できるので、LAN内にDNSサーバとNTPサーバを設置し、LAN内に設置したNTPサーバを指すようにDNSレコードを設定すればよい。

# 設定

閉じられたネットワークとインターネットの両方に接続できるマシンを準備。
今回は下記の設定。

* OS: Ubuntu 20.04.1 LTS
* IP:
  * (閉じられたネットワーク側)192.168.20.199/24
  * (インターネットに接続できる側)DHCP

## unboundのインストールと設定

今回はDNSサーバとしてunboundを仕様(bindだと設定が面倒すぎた)。

~~~bash
sudo apt install unbound -y
~~~

設定ファイルは下記のように設定。

~~~/etc/unbound/unbound.conf.d/unbound.conf
server:
        verbosity: 1
        interface: 192.168.20.199
        access-control: 192.168.20.0/24 allow
        use-syslog: yes # DNSクエリの監視用
        log-queries: yes #

        local-data: "time.apple.com IN A 192.168.20.199"
        local-data: "time-ios.apple.com IN A 192.168.20.199"
        local-data: "time-macos.apple.com IN A 192.168.20.199"

python:

remote-control:

forward-zone:
        name: "."
        forward-addr: 8.8.8.8
        forward-addr: 8.8.4.4
~~~

`time.apple.com`、`time-ios.apple.com`、`time-macos.apple.com`のAレコードはNTPサーバのIPアドレスを指定する(iPadなら`time-macos`は不要のはずだけど、とりあえず)。
今回は同一マシンにDNSサーバとNTPサーバを立てるので`interface`と同じアドレスを指定しているが、すでに他のNTPサーバがあるならそちらのIPアドレスを指定する。

`use-syslog: yes`と`log-queries: yes`はiPadからのDNSクエリを確認するために設定。
上手くいったあとは削除して良い。

設定ファイルの編集が済んだらサービスを再起動。

~~~
sudo systemctl restart unbound
~~~

## NTPサーバのインストールと設定

次にNTPサーバをインストールして設定。

~~~
sudo apt install ntp -y
~~~

完全に好みだが、基準とするNTPサーバはUbuntuのデフォルトで用意されているものをすべてコメントアウトして[INTERNET MULTIFEED CO\.](https://www.mfeed.ad.jp/ntp/detail.html)で用意されているものを利用した。

~~~:/etc/ntp.conf
#pool 0.ubuntu.pool.ntp.org iburst
#pool 1.ubuntu.pool.ntp.org iburst
#pool 2.ubuntu.pool.ntp.org iburst
#pool 3.ubuntu.pool.ntp.org iburst
server ntp1.jst.mfeed.ad.jp iburst
server ntp2.jst.mfeed.ad.jp iburst
server ntp3.jst.mfeed.ad.jp iburst

# Use Ubuntu's ntp server as a fallback.
#pool ntp.ubuntu.com
~~~

ちなみに、LXDなどコンテナでNTPサーバを起動する時は、時刻合わせはホスト側が行うので、以下のように自分のローカル時刻を使うよう指定する。stratumの値は15以下のお好みの値で。

~~~:/etc/ntp.conf
server 127.127.1.0 prefer
fudge 127.127.1.0 stratum 10
~~~

こちらも設定後にサービス再起動。

~~~
sudo systemctl restart ntp
~~~

NTPサーバの動作確認のため、`ntpdate`をインストールして確認。

~~~
sudo apt install ntpdate
~~~

~~~bash
$ sudo ntpdate -q 192.168.20.199
server 192.168.20.199, stratum 3, offset -0.000027, delay 0.02574
27 Nov 06:08:09 ntpdate[5915]: adjust time server 192.168.20.199 offset -0.000027 sec
~~~

## iPadの設定

iPadのWi-Fi設定で、DNSサーバを「手動」で「`192.168.20.199`」(今回の例では)に設定。

確認していないが、もしDHCPを使用しているなら、DHCPサーバのオプションでDNSサーバを`192.168.20.199`に設定すれば大丈夫なはず。

あとはしばらく待てば`time-ios.apple.com`へのDNSクエリが来て、自動で時刻が調整されているはず。
駆け出しエンジニア の学習記録　2日目Git,GitHub 中編

<h1>メモ</h1>git pullは一気にしてくれるから一見楽だが今自分のいるブランチに統合されてしまうので注意が必要
↳hogeブランチに居る　masterブランチの情報をmasterブランチに統合したい　→pull→hogeに統合される　

ブランチはただのポインタ　同時に加発できる
HEADはいま自分がいるブランチ
ブランチを分ける
開発自体はトピックブランチで作成するようにする
プルリクエスト手順
①Maseterブランチを最新に更新
②ブランチを作成
③ファイルを変更
④変更をコミット
⑤Githubへプッシュ
⑥プルリクエストを送る
⑦コードレビュー
⑧プルリクエストをマージ
⑨ブランチをマージ
GitHub　Flowが基本



<h1>使用したコマンド</h1>

・git commit --amend 直前のコミットをやり直す　リモートリポジトリの分はやり直し×
・git remote -v リモートの情報を確認できる
・git remote add 名前　リポURL　新しく登録
・git fectch リモートリポからローカルリポに取り込む
・git merge ローカルリポからワーカツリーに取り込む
・git pull origin master リモートからワークツリーまで一気に取り込む
・git remote show origin より詳しい情報が見れる
・git remote rename <旧名前> <新名前> リモートの名前を変更
・git remote rm <リモート名> リモートの名前を削除　
・git branch <ブランチ名>　ブランチを作成
・git checkout <既存のブランチ名> 既存のブランチに移動
・git checkout -b　<新ブランチ名> 新しくブランチ作成し移動もする
・meregは３種類　
・git branch -m<ブランチ名>　自分が作業しているブランチ名を変更
・git branch -d <ブランチ名> ブランチを削除　
・git branch -D <ブランチ名>　ブランチを強制削除
ページの最大幅の設定【css】

やりたいこと

・ページ全体を中央に配置する。
幅いっぱいのコンテンツを最大幅960pxに制限してそれ以上横に広がらないようにする。

（ページ全体の幅を固定せずに最大幅だけを設定する手法は、webサイトをモバイル末端の小さい画面にも
対応させるための重要なテクニック）


1.＜div class="wrapper"＞の最大幅を設定する。

```
body{
  margin:0 0 0 0;
}
.wrapper{
  margin:0 auto 0 auto;
  max-width: 960px;
}
```
解説

　ページの最大幅を設定して横に長くなりすぎないようにしつつ、ウィンドウが最大幅以下であれば、それに合わせて縮小するように作るのが一般的

ブロックボックスで表示されているコンテンツはウィンドウ幅に合わせて伸びたり縮んだりする。。ウィンドウに合わせて全体の幅が伸縮するのはそのため。

.wrapper{
 margin:0 auto 0 auto;
  max-width: 960px;
}
と設定することにより、右左のマージン値を「auto」にする。
こうしておくとマージンの大きさが自動で調節され、ウィンドウ幅960px以上の時はページが常に中央に配置される
gitの「マージできない😧」に効くalias

タイトルは大げさでした。
「マージできない」問題を一発で解決するようなものではありません。

# はじめに

このaliasは何処かで拾ったもので完全にｎ番煎じですが、これを使うようにしてから落ち着いてマージ作業が行えるようになりました。
ちょいちょいカスタマイズして現在の見た目に落ち着いていますので、使い所も含めて紹介します。

# 設定方法・使い方

```ini:~/.gitconfig
[alias]
	tree = log --graph --all --date=short --format=\"%x09%C(cyan)[%cd]%Creset %C(cyan bold)%<(20)%an%Creset%C(yellow)%h%Creset %C(magenta reverse)%d%Creset %s\"
```

使い方は`git tree`と実行するだけです（表示内容は[googletestのリポジトリ](https://github.com/google/googletest/tree/master/googletest)から拝借させていただきました）。
![スクリーンショット 2020-11-29 221133.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5708/827d25d7-e59a-1d60-1e94-02bf410c90a1.png)
GUIなツールでは良くある表示ですが、HEAD以外のブランチも含めて俯瞰（ふかん）しているのが特徴です。

# 使い時・使い所

`git merge`や`git rebase`でCONFLICTしてパニックになる前に使いましょう。

手順としては一手間増えるのですが、git初心者にオススメするのは、

**`git pull`ではなく`git fetch`を使う**

ことです。

`git pull`というのは「`git fetch`と`git merge`を同時に実行」するコマンドです。
`git merge`は2つのブランチを合流させるコマンドで、これが（`git pull`において）CONFLICTを生む原因です。

では、`git fetch`とは何でしょうか？
`git fetch`はローカルリポジトリをリモートリポジトリと同期するコマンドです。同期すると言ってもワーク領域は書き換えません。`git branch -a`などで目にすることがあると思いますが、`remotes/origin/main`などの`.git`ディレクトリの中で管理されている領域を書き換えるだけです。

つまり、`git fetch`は**ワーク領域への副作用が無い**ので**気兼ねなく実行**出来るのです。

## 利用シーン

1. 2人が同時にmainブランチの同じファイル・同じ箇所に修正をする。
2. 1人目が先にリモートリポジトリにpush。
3. 2人目がリモートリポジトリにpushするが失敗、「`git pull`で変更を統合しろ（英語）」的なメッセージが出てくる。

ここで愚直に`git pull`すると当然CONFLICTします。そこで`git fetch`と`git tree`の出番になります。

```sh
$ git fetch
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 263 bytes | 13.00 KiB/s, done.
From github.com:utkamioka/example-git-tree
   8519b35..f387f46  main       -> origin/main
$ git tree
*       [2020-11-29] Yutaka Kamioka      89fcafc  (HEAD -> main) update readme second
| *     [2020-11-29] Yutaka Kamioka      f387f46  (origin/main, origin/HEAD) update readme first
|/
*       [2020-11-29] Yutaka Kamioka      8519b35  first commit
```

リモートリポジトリoriginのmainブランチ（`f387f46`）は、現在の作業場所（`HEAD`=`89fcafc`）の派生元（`8519b35`）から枝分かれしていることから、既にコミットが進んでいることがわかります。
この状態で、`git diff origin/main`（`git diff f387f46`とかでも可）で合流したいブランチとの差分を求めることができます。

```sh
$ git diff origin/main --name-only
README.md
$ git diff origin/main
（省略）
```

こうして、合流先ブランチと差分があること、そして差分があるファイル名やその位置を、マージ実施前に知ることができ、"CONFLICT"の文字列に慌てることなく、マージ作業に取り掛かることが出来ます。

# 終わりに

残念ですが、現時点ではマージそのものを簡単にする道具はありません。

マージは、プログラムコードから意図を読み取り、それを活かしつつ、別の意図をコードとして追加する、高次でクリエイティブな活動ですが、現在のAIにはそれを可能にする読解力は有りません。

しかし、マージを楽にする手法や手段は存在します。

プログラムコードを単機能でコンパクトな関数に分割し分かりやすい名前を与える、テストしやすいコードにした上で、しっかりとテストコードを記述し、機械的に検証できる環境を用意する、、、などです。
いわゆる「良いコード」はマージを楽にするコードと言えます。


gitのaliasを紹介するだけの小ネタのつもりでしたが、無駄に長くなってしまいました。😅
Rails 一意性 DB メモ

Railsでは、`データを保存段階でバリデーション`をかけてもだめ

なぜか？
DBレベルでも一意性を保証しなければならない

どういうことか…？
保存をする(フィルタリング)段階で「一意性」を設定しても
`リクエストを連続`で送ってしまうと同じユーザーが作成されてしまうらしい
→だから、DBレベルでも一意性を保証しないといけない
ヘルパーメソッドの概要

ヘルパーメソッドの中でも[form_withメソッド]の中身がまだ完璧に覚えていないので言語化しながら記事を投稿したいと思います。

フォームを実装するために、HTMLのformタグの代わりにform_withメソッドを用いる。rubyとして取り扱われるので<%= %>で囲む。
form_withメソッドを使う利点はUrlパスやRubyの埋め込みができるためです。

では早速form_withメソッドの中身を記述し概要を確認します。

<%= form_with url:~~~path, method::post, local:true do |form|%>
<% end %>

~~~はターミナルでrails routesで確認したパスを指定します。

では一つずつ解説します。

url:~~~path  リクエストを送信したいパスを指定　　(例)newアクションからcreateアクションに遷移する際のパスを指定。

method::post(オプション)  送信するHTTPメソッドを指定する。POST意味[送信する、作成する]これもrails routesで確認したのを指定する

local:true  HTMLとしてフォームを送信するために記述する。

もし違うよってことがありましたら指摘の方よろしくお願いします！！
名前の付け方　備忘録

リーダーブルコードを読み学んだ変数や、関数、クラスなどに対しての命名方法をまとめる。

##名前に情報を詰め込む
名前は短いコメントだと思えばいい。短くてもいい名前をつければ、それだけ多くの情報を伝えることができる。
以下は情報を詰め込んだ名前をつけるための方法をまとめる。

###明確な単語を選ぶ
「名前に情報を詰め込む」には、情報が明確に伝わる単語を選ぶべき。

```
class BinaryTree {
     int Size();
     ...
}   
```
Size（）メソッドが何を返すかわからない？？　ツリーの高さ？　ノードの数？　ツリーのメモリ消費？？
伝わる名前をつけるなら、それぞれHeight( ), NumNodes( ), MemoryBytes( )になる。

###汎用的な名前は避ける
エンティティの値や目的を表した名前を選ぶ

例えば、i・j・kなどの名前はインデックスやループイテレータでよく使われるが、より伝わるようにするべきである。

```
for (int i = o; i < clubs.size(); i++)
  for(int j = o; j < clubs[i].members.size(); j++)
     for(int k = 0; k < users.size(); k++)
      if(clubs[i].members[k] == users[j])
        cout << "user[" << j << "] is in club[" << i << "] << endl;
```
if文にあるmembers[]とuser[]のインデックスが逆になっているが、一目見ただけではバグがわからないだろう。
i,j,kではなく、club_i・members_i・users_iのような説明的な名前にすることで、バグば目立ちやすくなる。


###接尾辞や接頭辞を使って情報を追加する
絶対に知らせなきゃいけない大切な情報があれば、「単語」を変数名に追加すればいい。

時間やバイト数のように計測できるものであれば、変数名に単位を入れるといい。

```
var start_ms = (new Date)).getTime()
```

上記のようにすることで、start_msがミリ秒を返すことがわかり、バグが発生しにくくなる。

### 名前の長さを決める
スコープが小さければ短い名前でもいい。下記ではmという変数名には情報が含まれていないが、コードを理解するのに必要な情報がすぐそばにあるから把握できる。


```
if (debug) {
    map<string, int> m;
    LookUpNamesNumbers(&m);
    Print(m);
}
```
mがクラスのグローバル変数では、コードが読みにくくなるので、やめるべき。スコープが大きい時は、名前に十分な情報を詰め込んで明確にする必要がある。

### 名前のフォーマットで情報を伝える
定数は大文字などと決めておけば、コードの理解がしやすくなるので、フォーマットは意識すべきである。

参考:リーダブルコード
新入社員がAWS Solution Architect Associate-C02に合格できた話

#新入社員がAWS Solution Architect Associate-C02に合格できた話

Qiita初投稿になります。
よろしくお願いいたします。

今回は先日合格しましたAWS SAA-C02についての勉強法、合格するために必要なものを書いていきたいと思います！！！
筆者はSAA-C02の参考書などが見つからず苦労したため、合格できずに苦労している方や今から受ける方などに参考になればと思います。

#目次
[1.はじめに](#1-はじめに)
[2.受験１～３回目](#2-受験１～３回目)
[3.受験４回目](#3-受験４回目)
[4.おすすめ勉強法](#4-おすすめ勉強法)
[5.まとめ](#5-まとめ)

#1. はじめに
筆者のスペックを書いていきます。

●社会人１年目の社会人、クラウドに触り始めたのは半年ほど前から
●業務でAWSなどのクラウド構築に従事、主要サービスは作成、説明可能
●３か月前にCloud Practitioner取得

続いては実際に受験した際の勉強法や感想などを書いていきます。

#2. 受験１～３回目
`受験１回目`
>・勉強時間
１日１時間×２週間
・勉強法
Udemyの問題集を２割、iPhoneのアプリ8割くらい
・結果
652点(720点合格)
・感想
今回は圧倒的な勉強時間不足。もっとUdemyやるべきだった。。(Udemyは５割くらいしか取れていなかったです。。)

`受験２回目`
>・前回の受験から空けた期間
２週間程度(AWSの資格は再受験の場合、2週間空けないと再受験できないのです。。)
・勉強時間
１日１時間×２週間
・勉強法
Udemyの問題集を5割、iPhoneのアプ5割+３日間のオンライン講座（バウチャー付き）
・結果
624点(720点合格)
・感想
オンライン講座を受けたことで受かると決め込んでいたため勉強に身が入らないことが多かった

`受験３回目`
>・前回の受験から空けた期間
２週間程度
・勉強時間
１日１時間×２週間
・勉強法
今回はUdemy＋Udemyで間違えた選択肢などの解説をエクセルなどにまとめた(Udemyは7割まで取れるようにした、エクセルは作成したがあまり復習できなかった。。)
・結果
700点(720点合格)
・感想
試験範囲の中で触ったことがないサービスについてとにかく触るようにした。（しかし、触ったことがないサービス＝あまりメジャーでないサービスだったので試験に役に立ったかといわれると。。）
20点分は運が悪かったと割り切ったが試験直後は見直しをもっとしっかりしていれば。。。と後悔しましたw

#3. 受験４回目
>・前回の受験から空けた期間
3週間程度
・勉強時間
１日１時間×２週間
・勉強法
Udemy＋Udemyで間違えた選択肢などの解説をエクセルなどにまとめ、寝る前などに読み物として読んでいた(Udemyは8割以上取れるようにしました)
・結果
729点(720点合格)←とてもギリギリでした。。。
・感想
エクセルで作成した読み物を完璧にしたことが大きかった。
後は受験４回目だったので、ここで落ちたら再受験まで少し時間空けようと考えていた。そのため今までの３回の受験より気合が入っていた。

#4. おすすめ勉強法
一番おすすめの勉強法は「Udemy」の問題集をひたすら解くことです。
この問題集で8割～9割取れるようにしていけばよい結果が手に入るかな？と思います（あくまで個人の意見です）
また、AWSアカウントを持っている方は実際に触れてみることもいいかなと思いました。（特にEC2、S3に関しては問題に直接絡んでくることもあったかなと思います！）

#5. まとめ
まとめとして筆者がAWS SAA-C02での後悔などを記載します。
まず一番の後悔は金銭面です。。
ただ、Cloud Practitionerを合格していた時のバウチャー(試験50%オフ)のものとオンライン講座のバウチャーがあったためまだ出費を抑えられました（それでも出費は出費ですが）
また、AWS公式の模擬試験も受験しなかったため、受験していればよかったかなと思いました。

<br/><br/><br/>
いかがでしたでしょうか？
筆者の生の声をなるべく詳細に書いたつもりなので、受験の際は参考にしていただければと思います。
次回はAzureの資格受験の体験談を書ければと思います！
次回もよろしくお願いいたします！