OmniAICreator/Qiita-1.07M huggingface dataset:
Cの基本６ ~関数~　備忘録

### はじめに
私は初心者である。この備忘録を参考にされようとしている他の初心者の方は、ここに書かれていることを鵜呑みになさらぬようお願いしたい。何か間違いを見つけた方はコメント欄でご報告頂きたい。

___

## 制御構造　続き

### `goto`文による飛び越し
これまでの「上から順に」、「場合分け」、「繰り返し」の３つの他に例外的に使われる制御構造が「飛び越し」。`goto`文とラベルを使う。
下記のコードは何の意味もないただの二重ループだ。`goto`の使用例らしいから一応貼っとく。(それにしても例が悪すぎやしないか笑)
```c
    int i, j, data;

    for (i = 0; i < 10; i++) {
        for (j = 0; j < 10; j++){
            scanf("%d", &data);
            if (data < 0) 
            goto finish;
            printf("%d, %d = %d\n", i, j, data);
        }
    }
    finish:
    printf("finish\n");
```

*Cの文法には`goto`文による飛び越しが用意されいているが、プログラムの構造の分かりやすさを保つにはできるだけ使わないほうが良いらしい。*

___

## 関数
C言語での関数の定義は以下。
```c
    int f(int x) {
        return 2 * x + 1;
    }
```
上記だと`f`が関数だ。`x`が引数で`{}`で囲まれた部分を関数の本体という。

`main`でこの関数を書いたら、エラーが出た。私はこの`main`なる代物を勝手にクラスだと思っているのだけれども、Cではクラス(仮)内で関数の宣言はできないようだ。(`main`関数については下記で触れている。)

私の書いた関数と`main`の組み合わせは以下。
```c
    int f(int x) {
        return 2 * x + 1;
    }
    int main(void) {
    int a = 10;
    printf("%d\n", f(a));
    return 0;
    }    // 結果は21
```
##### 仮引数と実引数
引数には二種類ある。関数を定義するための仮引数（`int f(int x)`の`x`）、
実際に関数で使うための実引数（`f(a)`の``a）だ。

##### 戻り値
`return`文に出会うと関数の実行は終了する。`return`文は`return 式;`の形式で書く。
`return`文の式の値が呼び出し元に返されるわけだが、その値を戻り値という。

##### 引数の値渡し
関数を実行したときのように、関数の呼び出しから戻り値にかけて引数の引き渡しが起こる様を値渡しと呼ぶ。

```c
    double add(double a, double b) {
    return a + b;
    }
    int main(void) {
    double x = 10.5;
    double y = 21.7;
    printf("%f\n", add(x, y));
    return 0;
    }
```
上記のコードでは引数が２つある。仮引数の数は0個以上であれば幾つでも良い。
仮引数を複数指定するにはカンマで区切る。関数を呼び出すときの実引数は仮引数の数に一致している必要がある。

##### `main`関数
`main`は関数だったのか？！`int main (void)`は戻り値が`int`型で引数は無いことを表しているそうだ。
プログラムは起動すると`main`関数を呼び出し、最後の`return`文はプログラムの実行終了を表す。`main`関数が返す`int`型の戻り値はプログラムが正常に終了するときはゼロとし、そうで無いときはゼロ以外にする習わしがあるそうだ。`main`関数の戻り値はOSを通じてシェルやコマンドプロンプトなどに返されるとのこと。
```c
int main(void) {
    int age;

    printf("Your age? ");
    scanf("%d", &age);
    if (age < 0) {
        printf("Bad age!\n");
        return 1;
    }
    printf("You are %d years old.\n", age);
    return 0;
}
```
上記のコードでは0歳以下の年齢を打ち込むと`return 1;`となるが、`0`で終了する時と同じように終了したように見えた。

##### 戻り値の`void`
戻り値が`void`の関数も作れるようだ。本体が`printf`で何かを表示させたいだけの時に使える。

今日は運転の練習で、首都高デビューしました。
___

> 今回の内容は富永和人氏の[新しいC言語の教科書](https://www.amazon.co.jp/%E6%96%B0%E3%81%97%E3%81%84C%E8%A8%80%E8%AA%9E%E3%81%AE%E6%95%99%E7%A7%91%E6%9B%B8-%E5%86%A8%E6%B0%B8%E5%92%8C%E4%BA%BA-ebook/dp/B07P1TC98P)を参考に書き留めてます。
MySQLを利用しようとしたら、【アクセスが拒否されました】とでた

## 背景
　自作したWebアプリが、ひとまずの完成を迎えたということもあり初めて公開しようとしたのですが、そのためにはDBがMySQLやPostgreSQLでないとだめみたいでした。そこで練習用に作成していたWebアプリで使用していたDBをMySQLに変更しようと思いMySQLのインストール含め、もろもろやってみました。
## 概要
+ インストーラーがうまく動作しない。
+ そのせいなのか、MySQL Shellの動作が少しおかしく感じる場所がある。
+ MySQL Shellでの操作をあきらめ、コマンドプロンプトで操作することにする。
+ __サーバーが起動していないのでは？？__
## インストーラーがうまく動作しない
　写真を撮り忘れてしまうという痛恨のミスを行ってしまったため、画像がないのですが、Pythonに関する部分が✖になっていました。MySQL Shellの挙動が変であるか、元からの使用なのかは微妙なところです。
## コマンドプロンプトで操作する
　Pathの設定がまだな人はこちらを参照してください。

https://www.javadrive.jp/mysql/connect/index6.html

　コマンドプロンプト（以下cmd）を利用しようとしました。しかし、 __mysql__ と入力してもエラーメッセージが出るだけでした。
```cmd:エラー
ERROR 2003 (HY000): Can't connect to MySQL server on 'localhost:3306' (10061)
```
エラーメッセージで調べたところ、ヤフーのものなどが出てきましたが、うまく解決まで行けているようには見えませんでした。

その後いろいろ調べてみた結果、__そもそもサーバーが起動されていないのではないか__ という結論に至りました。調べる方法はこのような具合です。
``` cmd:コマンド
 mysqladmin ping
```
結果がこのように帰ってきた場合は、接続されています。1つ目は __正常__ です。2つ目は __接続はできていますが、パスワードを入力する必要があります。__
```cmd:コマンド1
mysqld is alive
```
```cmd:コマンド2
mysqladmin: connect to server at 'localhost' failed
error: 'Access denied for user 'ODBC'@'localhost' (using password: NO)'
```
しかし、次のように出てきた場合は接続されていません。これは単純に、 __サーバーが起動されていないことを示しています。__
```cmd:コマンド3
mysqladmin: connect to server at 'localhost' failed
error: 'Can't connect to MySQL server on 'localhost' (10061)'
Check that mysqld is running on localhost and that the port is 3306.
You can check this by doing 'telnet localhost 3306'
```
　コマンド２に当たる方は↓のURLを参考にしてください。

http://mysql.javarou.com/dat/000409.html

　コマンド3の状況の方は下記注意点と合わせて下のサイトを参照してください。

https://webkaru.net/mysql/windows-service-start-stop/

## 接続に関しての注意点
　注意点は、パソコンの管理者権限がないといけないという点になります。私の場合、父のパソコンを借用という形になるので、__管理者権限__ で苦労しました。

:::note warn
警告
cmdからの場合はcmdを管理者権限で開く必要があります
:::
:::note warn
警告
上記サイトに従って、自動化する場合は管理者権限を持つアカウントでログインしないと、そもそも自動化のボタンを押すことができません。
:::
:::note warn
警告
自動化した場合は、再起動が必要です。再起動しない場合は、cmdに入力をしても変わらずエラーが出続けます。
:::
　要は、なんにしても __管理者権限__ が重要だということです。
　__再起動__ は忘れずに...
## まとめ
　最終的には、そもそもサーバーが起動されていないということが自分の場合は、問題でした。MySQL Shellに関してはまだ試していないですが、おそらく異常はないのではないかと思います。新しい環境の設定は初心者🔰の自分にとっては、毎回様々な問題が出る難題です。少しでも初期環境設定に苦しむ皆様のお役に立てたら幸いです。
「インシデントにどう対応してきたか？みんなで学ぶポストモーテム Lunch LT」参加レポート #LT_findy

2月9日、「[インシデントにどう対応してきたか？みんなで学ぶポストモーテム Lunch LT](https://findy.connpass.com/event/273197/)」に参加しました。

## LT①『ポストモーテムはじめました』
https://speakerdeck.com/nwiizo/posutomotemuhazimemasita

スピーカーは株式会社スリーシェイク [@nwiizo](https://twitter.com/nwiizo)さん。

まずはポストモーテムという概念そのものに関する説明から。
SREにおいては障害や失敗が発生したら、解決したらOKではない。失敗から学び、同じ過ちを繰り返さないためポストモーテムの実施が重要とのことです。
ポストモーテムはSREの文脈で語られることが多いキーワードですが、約10年前からあるもの。SREにおいては、さまざまな活動の中のひとつに組み込まれているそうです（つまり、これをやっていればSREとしてOKというものではなく、多角的な活動が必要）。

また、ポストモーテムは特定の型が決まっているものではなく、現場によって適切な形は異なりますが、以下については必須と考えているとのことです。
- 明確さ
    - 読み手が主題を間違えないドキュメント
- 具体的アクションアイテム
    - 組織でどのように対応するか決めておく
- 非難を行わない
    - 心理的な安全性を確保する
    - 人ではなくプロセスに焦点を置く
- 周辺への影響度の深さ
    - 運用者として誇れる仕事を
    - 解決に至るまでに使われたソフトウェアなども記載しておくとより良いポストモーテムになる
- 即時性と簡潔さ
    - リアルタイム性を大事にする
    - 担当者間でタイムラインでコミュニケーションをとっているとGood

お勧めのドキュメントとして『[SRE WEEKLY](http://sreweekly.com/)』も挙げられていました。メール、またはRSSで購読できるようなので、SREに興味がある人は読んでみるといいのではないでしょうか。

## LT②『ポストモーテム運用を支える文化と技術』
https://speakerdeck.com/chaspy/culture-and-technology-supporting-postmortem-operations

スピーカーは株式会社リクルート [@chaspy](https://twitter.com/chaspy_)さん。

障害発生後にポストモーテムを作る文化は現状でできているそうで、日常的にどのように実践しているのか話していただきました。

障害が誰かひとりのせいにならないように工夫していて、複数人でのレビューなどで共同で作業するよう心がけているとのことです。
また、オンボーディングで過去に作ったポストモーテムの読書会を開くことで、過去の知見を活かしているようです。
ポストモーテムは日々増えていくので全部読むのは現実的に不可能ということで、「おすすめ」ラベルをつけて読む対象を絞り込む工夫もされているそうです。

また、ポストモーテムを文化として定着させるために、最初はSREが主体で（ポストモーテムを書くよう）言い続ける、（自らポストモーテムを）書き続ける、ブログを公開するなどが大事とのことです。

「重要な障害を防ぐ」、「適切なリスクを取る」、「念の為の確認を簡単に行う」といったことも重視していて、そのために以下の取組を行っているそうです。
- 負荷テスト
- Canary Release
- E2E Test Automation
- データベースリストア

## LT③『All for One なポストモーテム運用と工夫』
スピーカーは株式会社メルカリ [@Fumiya_Kume](https://twitter.com/Fumiya_Kume)さん。

メルカリさんでは2017年からポストモーテムを運用を開始し、現在はSREだけでなくあらゆる職種で運用しているとのことです。
インシデントの定義を「お客様に影響を与える予期せぬサービスの中断や品質の低下」としているため、SRE以外にもポストモーテムが定着しているとのこと。
組織形態の変化に対応してSlackコマンド、Botの導入、Blameless（これは初耳だったので後で調べてみたいです）の導入など、日々変化を続けていくことが重要という話が印象に残りました。

## LT④『Postmortem as a textbook』
https://speakerdeck.com/line_developers/postmortem-as-a-textbook

スピーカーはLINE株式会社 [@maruloop](https://twitter.com/maruloop)さん。

ポストモーテムから他チームが学びを得るためには、以下が重要というお話でした。
- 読むだけで、システムの概要が理解できる
- 問題と解決策の間に飛躍がない
    - コンテキストを知らない人が対応策を読んでも疑問を持たれないような内容にする

共有会議の前段階として以下の取組を行い、結果的に品質も向上し、共有会議自体の時短にもなったとのことです。
- 全体共有の前に執筆のための会議を開く
- ファシリテートはSREが行う
- SREが担当する他チームも呼ぶ

## 最後に
どのLTも共通して「人ではなく問題自体に注目する」ための取り組みをされている印象を持ちました。
障害対応と聞くとどうしてもネガティブなイメージが先行しがちですが、個人が責められる心配がない環境で、障害対応を通じて新しい学びを得たり、よりよいプロダクトを作るためのチームが作れると考えると、そんなに悪いものでもないような気がしてきますね。
弊社もポストモーテムは手探りながらも導入していますが、SREに限らず全チームで障害に前向きに取り組める文化を育てていきたいものです。

また、LTで紹介されていた技術も「魔法のように問題解決してくれる最新の○○！」ではなく、昔から語られている基礎的なものばかりでした。安定したプロダクトを作るには基礎を疎かにせず、地道な積み重ねしかないのだなと感じました。
[Jest][備忘録] mockFn.mockImplementation(fn)に引数を渡さなかったら?

# TL;DR

`undefined`が返る

# 試してみたコード

環境は

```text
    "jest": "^28.1.3",
    "ts-jest": "^28.0.8",
    "typescript": "^4.9.3",
```

1~3はオマケ

```sample.spec.ts
const obj = {
  sampleAdd: function (num: number) {
    return num + 10;
  },
};

beforeEach(() => {
  jest.clearAllMocks();
  jest.resetAllMocks();
  jest.restoreAllMocks();
});

it('1', () => {
  expect(obj.sampleAdd(10)).toBe(20);
});

it('2', () => {
  const spy = jest.spyOn(obj, 'sampleAdd');
  expect(obj.sampleAdd(2)).toBe(12);
  expect(spy).toHaveBeenCalledTimes(1);
});

it('3', () => {
  const spy = jest.spyOn(obj, 'sampleAdd').mockImplementation((num: number) => {
    return num + 100;
  });
  expect(obj.sampleAdd(2)).toBe(102);
  expect(spy).toHaveBeenCalledTimes(1);
});

it('4', () => {
  const spy = jest.spyOn(obj, 'sampleAdd').mockImplementation();
  expect(obj.sampleAdd(2)).toBeUndefined(); // undefinedを期待してPASSする
  expect(spy).toHaveBeenCalledTimes(1);
});

```

# 参照

https://jestjs.io/ja/docs/mock-function-api#mockfnmockimplementationfn
web技術の基本を学ぶ

# 学習の意図
プログラミング学んでいく上で、土台となる基本的な技術
# 内容
- ステートフル
    - 以前のセッション状態を保持して、その後の処理結果に反映させる通信プロトコルやアプリケーション
    - もっと言うと、以前にユーザーが操作した情報を保存しておいて、後でその情報をそのまま活用できる状態にしておくこと
    - ECサイトのカート機能など
- ステートレス
    - 以前のセッション情報を保持せず、前後の状況に関係なくその都度いつも同じレスポンスを返すようなプロトコルやアプリケーション
    - 一般的な会社のHPなど
- リクエスト
    - クライアントからサーバーにWebサーバーにある情報を要求すること
    - リクエストは、クライアントからサーバーへのHTTPリクエストとして行われる
- レスポンス
    - リクエストに応じてサーバーからクライアントに返す情報のこと
- クッキー
    - クライアントがサーバーに要求した情報を記憶しておくための仕組み
    - ステーフルなWEBサイト等に使われる
- プロトコル
    - ネットワーク上で通信を行うために適用される決まり事
    - クライアントとサーバー間で情報をやり取りするために使用される
    - これがないと信号や横断歩道がない道路のような状態になり、機能しない
- ポート番号
    - ネットワーク上で通信を行うために使用される識別子
    - ポート番号を使用することで、クライアントとサーバー間で特定の種類の通信を行うことができる
秋月のカラーOLED 0.95インチで遊ぶ(STM32G071)P-14435



x 過去ログをみよ
x Arduino UNOと配線は、同じ

目的
カラーOLEDのテスト

SSD1331その互換機の標準的なライブラリになっている
Adafruit SSD1331　+ Adafruit GFXのインストール で
文字列を表示して遊ぶ

1.Adafruit SSD1331 OLED Driver Library for Arduino を　インストール
2.Adafruit GFX Library を　インストール

[QT095B]
通販コード　P-14435
発売日　2019/09/02

sclk 13　, SCL
mosi 11 , SDA
cs 10 , CS
rst 9 , RES
dc 8 , DC

3.3V , 3.3V
GND , GND



https://akizukidenshi.com/catalog/g/gP-14435/


https://qiita.com/caa45040/items/39360e3f2950dd7ad879


https://qiita.com/caa45040/items/3c57c159be0fd0f7a718


https://qiita.com/caa45040/items/35a7ee9c49a6d78bd535


https://qiita.com/caa45040/items/574231109a31cb6c55eb




![o_cop378.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/69be68ab-ad00-76cb-c974-2b85a7c1f5b3.jpeg)





Arduino UNOのプログラムと完全に同じ




```c++



//test_ssd1331_uno_0207

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1331.h>
#include <SPI.h>


// You can use any (4 or) 5 pins
#define sclk 13
#define mosi 11
#define cs   10
#define rst  9
#define dc   8


// Color definitions
#define BLACK           0x0000
#define BLUE            0x001F
#define RED             0xF800
#define GREEN           0x07E0
#define CYAN            0x07FF
#define MAGENTA         0xF81F
#define YELLOW          0xFFE0
#define WHITE           0xFFFF


Adafruit_SSD1331 display = Adafruit_SSD1331(&SPI, cs, dc, rst);

//初期化
void setup() {

  display.begin();

  //display.fillScreen(BLACK);

}//setup


//メインループ
void loop() {

  // 画面表示をクリア
  display.fillScreen(BLACK);

  // テキストサイズを設定
  display.setTextSize(3);
  // テキスト色を設定
  display.setTextColor(WHITE);
  // テキストの開始位置を設定
  display.setCursor(0, 10);


  // 1行目に数字を表示
  display.println("UNO");

  delay(1000); //1秒待つ

}//loop



```
Codilityのコーディング試験を受けてみて🤯📝

# はじめに

Codility のコーディング試験を受けたので、どんな感じだったか書いていきたいと思います😃

# Codility とは？

https://www.codility.com/

世界最大のコーディング試験サービスで、AmazonやIntelなどの大手グローバル企業や、日本だとメルカリやスマートニュースなどで採用されています。
開発者のコ​​ーディングスキルをテストし、エビデンスに基づいた採用決定を行うための、最高評価の技術面接プラットフォーム、とのことです。

# 事前準備

Codility のサイトで練習問題を解けます。

https://app.codility.com/programmers/

他の方の体験記事を参考に Lesson8 までの Easy を一通りやりました。

最初の方は簡単でしたが、途中から数学の試験を受けている気分...
む、むずかしい...
特にパフォーマンスの得点が伸びない😭

これは繰り返し解かないと初見では無理だなと思いました。
逆にいうと数学の問題のように何回も解いていたら高得点得られそうだなとも。

ちなみにサイト上では答えを教えてくれません。

「codility + （問題名）」とかで検索すると 100% Correct Solution をあげている人がいるので探してみてください。

私は JavaScript で受けたのでこの方の回答を参考にしました。

https://github.com/yaseenshaik/codility-solutions-javascript

考え方はこの方の記事を参考にしました。

https://zenn.dev/paraches/articles/codility_lesson_1_4

# いざ本番！

全 3 問で時間は 100 分。
コーヒー☕️ とチョコ🍫 を用意して、いざ試験本番！

最初の 2 問はパフォーマンスは採点対象外で、正確性のみクリアすれば良かったです。
特に捻らずとも問題通りにコーディングしていけば大丈夫でした。

残すはあと 1 問！ と意気込みましたが...

🤯🤯🤯

いやぁ全然解けませんでした🥺
この問題だけパフォーマンスの採点ありで、まさに練習問題で解いたような内容でしたが、時間配分を間違えたのもあり惨敗 ...OTL
とりあえずガード節で 10% いただきました（笑）
答えに辿り着かなくても点もらえるみたいです。


# 感想

結構楽しかったです！
また試験受けたいぐらい（笑）

Codility の操作方法とか採点基準を知るためにも、練習問題を解いておいて損はないです。
時間に余裕がある方は本番前にやっておくことをオススメします🤗
ESP32でYDLidar GS2を動かす①

# 結論
**BaudRate を921600にしたらURAT通信できるのです！！**
**しかしこのことはDeveropmentマニュアルには書いていないのです！**

### 配線
下記のようにつなげればOKです。

《ESP32》 - 《GS2センサー》
Rx(16ピン) - Tx
Tx(17ピン) - Rx
3.3V - Vcc
GNG - GND

ESP32からの電流供給量が足りるか不安でしたが、
3台繋げても計測開始されるところまでは確認できました。
コネクタのタイプはJSTのZHコネクタが入ります。

## 参考コード
``` Arduino:参考コード
//　各コマンド
uint8_t sensorCount[] = {0xA5, 0xA5, 0xA5, 0xA5, 0x00, 0x60, 0x00, 0x00, 0x60};
uint8_t sensorVer[] = {0xA5, 0xA5, 0xA5, 0xA5, 0x00, 0x62, 0x00, 0x00, 0x62};
uint8_t sensorParam[] = {0xA5, 0xA5, 0xA5, 0xA5, 0x00, 0x61, 0x00, 0x00, 0x61};
uint8_t scanStart[] = {0xA5, 0xA5, 0xA5, 0xA5, 0x00, 0x63, 0x00, 0x00, 0x63};
uint8_t scanStop[] = {0xA5, 0xA5, 0xA5, 0xA5, 0x00, 0x64, 0x00, 0x00, 0x64};
uint8_t reset[] = {0xA5, 0xA5, 0xA5, 0xA5, 0x00, 0x67, 0x00, 0x00, 0x67};

void setup()
{
  // ArduinoIDEのシリアルモニタはBoudRateが921600に対応していなかったため、SerialとSerial2で役割を分けました
  Serial.begin(115200);　// シリアルモニタに出力用
  Serial2.begin(921600);　// YDLidarGS2との通信用
　
　// コマンドをバイナリで送信する　ここでは接続しているセンサー数をチェックするコマンドを送信した例
  Serial2.write(&sensorCount[0], sizeof(sensorCount));
}

void loop() {
  // 受信したバイナリデータ1バイト分を区切って16進数表記した例
  if (Serial2.available() >= 1)　// 1バイトのデータが到着した場合
  {                                  
    int binaryData = Serial2.read(); // シリアルから1バイト読み込み
    Serial.print("0x");              // 16進数表記のプレフィックス
    Serial.println(binaryData, HEX); // 16進数で表示
  }
}
```
各コマンドによって送られてくるバイト数が異なるため、参考コードでは1バイト区切りで表示させています。
計測時は継続してデータが送られるため処理方法はこれから考えます。
【自動化】pyautoguiでクリックマクロ　画像を渡してその範囲内でランダム化してクリックしてもらう

## １．はじめに
　何か悪いことをしたい人のために、記録を残しておきます。

## ２．必要な知識
　・Python（ループとか分岐とか使って好きに組める）
　・pyautoguiのインストール
　・threadingの使い方とか
　・Windowsのスクショツールの使い方

## ３．研究概要？
　５年前ぐらいに挫折したプログラムを再度作り直してみました。
　プログラムの中身を公開するというよりは、作り方のヒントをまとめます。

## ４．作り方のヒント

### あくまでヒントです。組み立ててオリジナルマクロを作ろう！

##### まずはライブラリのインポート
```python
import pyautogui as pag
import random as rand
import time
import threading
```

##### クリックする関数
　引数のiconには何をクリックしたいかを渡すわけです。
　そうすると、保存してある画像を読み込んで、その範囲内でランダムにクリックしてくれます。
　__正直、これを動かすだけでもかなり楽しい。__
```python
def click(icon):
    Left,Top,Wig,Hei = pag.locateOnScreen("./img/"+icon+".png")
    x=Left + rand.randint(0,Wig)
    y=Top + rand.randint(0,Hei)
    print(icon,"=",x,y)
    #pag.moveTo(x,y)
    pag.click(x, y)
    time.sleep(1)
```

##### グローバル変数
　gasと時間を管理したいですね。
　変数が足りなければ追加してもよいですね。
```python
gas = 0
count2 = 0
```
　他の関数で使うときは、以下の表記が必要になります。
```python
global count2
```

##### 時間を管理する
　ただのカウントアップですね。実に簡単。
```python
def countup2():
    global count2
    while(1):
        count2 = count2 +1
        time.sleep(1)
```

##### ↑はスレッドで実行します
```python
thread2 = threading.Thread(target=countup2)
thread2.start()
```

##### 時間が経過したら処理しましょう
```python
global count2
while(1):
    if(count2>=14400):
        reloadhome() #画面遷移して再度メニューに戻る
        if pag.locateOnScreen("./img/○○.png"): #もしもこの画像が画面上にあったなら
            kakunin()
```

##### gasが０なら補給をすると
```python
def hokyu():
    global gas
    click("○○")
    click("○○")
    click("○○")
    click("○○")
    gas=1
```


## ５．画像の準備
　windowsに標準搭載されているSnipping Toolというのがおすすめです。
　![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171041/b19e90b7-7380-6061-a76b-bb282ae99d90.png)

## ６．おわりに
　足りないところを埋めるパズルみたいになりましたね。
　ifとかwhileとか使ってやってみてください。

　ただ単にclickを動かすだけでも結構楽しいので、ぜひやってみてください。

## ７．参考文献
> 【自動化】Pythonでマウスとキーボードを操る
> https://qiita.com/konitech913/items/301bb63c8a69c3fcb1bd
【JavaScript】【jQuery】配列同士の検索 some()の中でincludes()

コールバック関数は最強

# コード some ※OR条件
```javascript
process.stdin.resume();
process.stdin.setEncoding('utf8');

var data = [3, 5, 4, 2, 7];
var search_1 = [1,6];
var search_2 = [1,3];
var search_3 = [2,7];
var search_4 = [2];

var result = search_1.some((v) => data.includes(v));
console.log(result);

var result = search_2.some((v) => data.includes(v));
console.log(result);

var result = search_3.some(function(v){return data.includes(v)});
console.log(result);

var result = search_4.some(function(v){return data.includes(v)});
console.log(result);
```

# 結果
```javascript
false
true
true
true
```

# コード every ※AND条件
```javascript
var arr = [3, 5, 8];
var item_1 = [3,5];
var item_2 = [1,5];
var item_3 = [5];
var result = item_1.every(function(v){return arr.includes(v)});
// ↓これでもOK
console.log(result);
var result = item_2.every((v) => arr.includes(v));
console.log(result);
var result = item_3.every((v) => arr.includes(v));
console.log(result);
```

# 結果
```javascript
true
false
true
```
Web API: The Good Parts読んだ

# 何の本？
>Web APIの設計、開発、運用についての解説書。APIは設計次第で使いづらいものになってしまうだけでなく公開後の保守運用も難しくなってしまいます。そのためAPIを美しく設計することがとても重要です。本書では「設計の美しいAPIは、使いやすい、変更しやすい、頑強である、恥ずかしくない」という考えのもと、APIをどのように設計し運用すればより効果的なのか、ありがちな罠や落とし穴を避けるにはどういう点に気をつけなければいけないのかを明らかにします。ターゲットは、URIにアクセスするとXMLやJSONなどのデータが返ってくるシンプルなタイプ――XML over HTTP方式やJSON over HTTP方式――のAPIです。読者は、Web API設計の考え方と手法を知ることができます。

[引用元-oreilly](https://www.oreilly.co.jp/books/9784873116860/)


ウェブAPIについて、その中でもHTTPでエンドポイントにアクセスすることでJSONを返すAPIの設計について書かれている。

# よかったこと
APIに関する基礎知識を身につけることができた。
APIの設計というと、エンドポイントの設計やレスポンスデータの設計ばかりをイメージしていたが、HTTPヘッダなどをどのように設定すべきであるのか等、セキュリティの観点からの実装などが特に参考になった。

## 美しいAPIを設計するポイント
* 仕様が決定しているものについては仕様に従う
* そうでないものについて、デファクトスタンダードが存在している場合にはそれに従う
### エンドポイントの設計
* エンドポイントについて覚えやすく、それがどんなものなのか一目でわかる
* GETの安定性？を損なわない　GETで何かの更新や、削除を行わない（WEB技術にも記載があった）
### レスポンスデータの設計
* 取得数と取得位置のクエリパラメータを返す際に、取得位置を相対位置にするとずれる
* レスポンスデータの設計では、どのような情報をどう返すのかを設計する。
* 例えば友達一覧であれば、友達のどの情報を返すのか？　何度もアクセスしなければならないAPIはchatty APIと呼ばれ、利用者の手間を増やし、トラフィックを増加させ、いいことが何もない。。
* WEBAPIは単なるデータベースのアクセスインターフェイスではなくアプリケーションのインターフェイスであるべきであるから、アプリケーションの特性を踏まえた利用者が利用しやすい設計が必要。
* レスポンスグループの利用も有効的
* 続きがあるときはhasnext: true  にしたり、次のページを取得するためのトークンやURIを指定したりして続きをとりやすいようにしてあげる
### HTTPの仕様を最大限利用する
* HTTPレスポンスのステータスコードは適切なものを選ぶ
* メディアタイプはapplivation/jsonで返す 自分で新しいメディアタイプを指定して返すこともできる
### キャッシュの必要性
* キャッシュできるものはキャッシュしてサーバの負担を減らしつつ、最新のものが出たらちゃんと更新させる
* キャッシュにはValidation Model（検証モデル）とHeuristic Expiration（発見的期限切れ）があり、検証モデルでは現状のキャッシュが有効かどうか確認するリクエストを送り、更新されていたときにのみデータを返し、更新の必要がないときは304を返す。このとき、Last-ModifiedとEtagというレスポンスヘッダを用いて返される。
* 発見的期限切れにおいてはサーバ側が明確な期限を与えなかった場合に、クライアントがキャッシュの期限を自分で決める。基本的にはChache-controlやExpiresなどを用いてキャッシュの期限を返してあげるべきである。
* Cache-Controlヘッダにおいて、privateに指定されたものはクライアントのみがキャッシュでき、CDNやプロキシのような仲介エージェントはキャッシュできないが、反対に逆にpublicにおいてはキャッシュをプロキシにおいて異なるユーザ間で共有することができる。
* no-storeにおいてはキャッシュは禁止され、no-cacheにおいては毎回Etagを利用してバージョンの更新がないかを確認しなければならない。
* EtagはApacheにおいてはサーバーが２台ある場合にはそれぞれ同じバージョンにおいても別のEtagが生成されてしまうため、キャッシュがうまく働かなくなってしまうことがある。（参考のURLを参照）

最初に述べられているように、仕様やデファクトスタンダードに則った利用しやすいAPIを構築するためのノウハウが、HTTPそのものの仕様にも触れられながら分かりやすく記載されていて、知識を整理することに役立った。ユースケースを想定してものを作ることが設計の基礎なのだということがとてもよくわかった。巻末にAPI設計時のチェックリストが記載されているので、参考にしたい。

## 今後ちゃんと調べたいところ
OAuthによる認証の詳細
キャッシュの構造、とくにメモリーやディスクに保存される場合の挙動

## 参考
https://www.oreilly.co.jp/books/9784873116860/

https://www.cloudflare.com/ja-jp/learning/cdn/glossary/what-is-cache-control/

https://blog.redbox.ne.jp/http-header-tuning.html
libcurlをWindowsでビルドする

curlのWindowsバイナリ版からlibcurlを利用しようと思って、ダウンロードしたのですが、Windowsバイナリ版のcurlは、Mingw-w64でビルドされているようなので使うことを断念。curlのソースコードからビルドして利用することにしました。

## 必要なアプリケーション

 * curl
 * Visual Studio

 ## アプリケーションのインストール

 ### Visual Studioのインストール

Visual Stuido 2022 Commnunity を以下からダウンロードしてインストールします。

https://visualstudio.microsoft.com/ja/free-developer-offers/

### curlのインストール

以下のURLから curl のソースコードを取得します。

https://curl.se/download.html


### curlのビルド

### 圧縮ファイルの展開

curlの圧縮ファイルを展開します。

```
> tar xvf curl-7.87.0.tar.gz
```

展開されて出来た　curl-7.87.0\winbuildフォルダにある[README.md](https://github.com/curl/curl/tree/master/winbuild)にVisual C++でのビルド方法が記載されいます。

### Visual Studio用 コマンドプロンプトを 起動

64bit版のlibcurlを作成する場合、x64 Native Tools Command Prompt for VS 2022 を起動します。

カレントディレクトリを curl-7.87.0\winbuild に移動します。

```
> cd curl-7.87.0\winbuild
```

以下のコマンドでビルドします。

```
> nmake /f Makefile.vc mode=dll
```

エラーが出ていなければ、以下のフォルダに開発に必要となるヘッダファイル、dll, lib が格納されます。
vaio-p(vpcp11alj)

# debianメモ
機種：vaio-p(vpcp11alj)
CPU：Atom Z560 2.13GHz
MEM：2GB
SSD：256GB

# liveイメージでdebian11 xfceをインストール
USBメモリから。OK

# まずはapt update
sudo apt update

# wifiアダプタが認識されない
①iwlwifi-5150-ucode-8.24.2.2.tgzを解凍してiwlwifi-5150-2.ucodeをUSBメモリにコピー
https://www.intel.co.jp/content/www/jp/ja/support/articles/000005511/wireless.html
②USBメモリより/lib/firmwareにコピーして再起動→認識される。

# chromiumをインストール
sudo apt install cromium

# firefoxをアンインストール
sudo apt remove firefox*
※言語パックが沢山ある

# bluetooth関連
## daemon確認
/etc/init.d/bluetooth status
## 起動
/etc/init.d/bluetooth start
## GUIツールのインストール(順にgnome,KDE,GTK)
sudo apt-get install sudo gnome-bluetooth
sudo apt-get install bluedevil
sudo apt-get install blueman
※xfceはGTK

## GUIツールで設定
①bluetoothをオンにする
②デバイス
③一覧から右クリックで接続

# ウィンドウマネージャをxmonadに変更
## xmonadをインストール
sudo apt -y install xmonad
・・・作成中・・・
Laradockのmysqlコンテナ内で複数DBを立ち上げる

# Laradockで複数DBを立ち上げたい
１つのLaradockで複数のプロジェクトを開発していたり、テスト用などで別のデータベースが欲しい場合があると思います。
今回は通常のローカル開発用のDBに加えて、テスト用のDBもコンテナ立ち上げ時に作成したいなあと思ったので、その時の方法をメモします。

この方法を発見するまでは、[tableplus](https://tableplus.com/) などのmysqlクライアントからDBを追加するようにしていました。

# どうやるか
DockerではMysqlコンテナ起動時に、`/docker-entrypoint-initdb.d` にマウントしたディレクトリ内の.sqlの拡張子のファイルを読み込んでそのSQLを実行します。

Laradockの `mysql/docker-entrypoint-initdb.d` 配下にexampleでsqlファイルが置いてあった！

https://github.com/laradock/laradock/blob/master/mysql/docker-entrypoint-initdb.d/createdb.sql.example

これを使って、追加のDBを作成していきます。

# 初回起動の場合

mysqlコンテナの初回起動の場合は、上記のcreatedb.sqlファイルにDB作成するsqlを追記するだけです。

```bash
$pwd
/laradock

## 用意されてるexampleコピーして、createdb.sqlを作成
$cp mysql/docker-entrypoint-initdb.d/createdb.sql.example createdb.sql
##ファイルを開く
$vim mysql/docker-entrypoint-initdb.d/createdb.sql
```

一番下の`//FLUSH PRIVILEGES`よりも上に以下を追加します。すでにDBをもう一個作るsqlがコメントアウトされてるので、そのDB名だけ書き換えるでもok.

```sql
CREATE DATABASE IF NOT EXISTS `任意のDB名` COLLATE 'utf8_general_ci' ;
GRANT ALL ON `任意のDB名`.* TO 'default'@'%' ;
```

コンテナを立ち上げる
```bash
$ docker-compose up mysql
```


# すでに初回起動してる場合はどうする？

もう`docker-compose up`してるんだよなーっていう時は手動でcreatedb.sqlを実行する形になります

まずは、↑の手順で`mysql/docker-entrypoint-initdb.d/createdb.sql`を作成して
以下を実行するだけです。

```bash
$ docker-compose exec mysql bash
$ mysql -u root -p < /docker-entrypoint-initdb.d/createdb.sql
```

初期データの投入とかもこれでできちゃいますね。

# 参考
公式にめっちゃ書いてあった
https://laradock.io/documentation/#create-multiple-databases
docker imagesでkubernetesでbuildしたイメージが表示されない

# はじめに

実務でkubernetesを使うことがほとんどになり、ローカルにminikube環境を作ったところ問題が起きたのでまとめます

# 問題

skaffoldを利用してコンテナイメージをbuildして作成したイメージを確認しようとい以下のコマンドをたたきました

```
watanabejin@watanabejin:~/workspace/robin/environments$ docker images
REPOSITORY                                                              TAG                                                                IMAGE ID       CREATED         SIZE
```

しかしイメージが何も表示されません
再度イメージをビルドするとキャッシュがきいている状態でした

# 解決方法


以下のコマンドを実行したところ、表示されるようになりました

```
$ eval $(minikube -p minikube docker-env)
```

minikubeとdockerを接続した感じかと思われます

# おわりに

スマホで記事を書いてるのですが、かなり難しいです。でも電車でかけるのはメリットなんですよね

# 参考

https://github.com/GoogleContainerTools/skaffold/issues/5185
見やすいコードを書くためにPSR-12を見て学ぶ

## はじめに
キャメルケースやケバブケースなど、コードを書くにあたって適切な書き方があるのはなんとなく知っていたが、認識としてある程度のルール化がされていることを知った。
それが`PSR-12`とのこと。

行の長さはどのくらいにしなければいけない、だったり
メソッド名の前に単一のアンダースコアをつけてはいけないなどルールが記されている。
https://www.php-fig.org/psr/psr-12/#44-methods-and-functions%EF%BC%89

こういうのがあるんだぞー。
というのを常に忘れないためにも備忘録として残す。

## 今回参考にした箇所
備忘録だったのでほぼほぼこの記事の役目は終了しましたが、今回実際に何をするために確認したのかも書いておく。

### メソッドを書く場合どのケースで書くべきか

```
<?php

namespace Vendor\Package;

class ClassName
{
    public function fooBarBaz($arg1, &$arg2, $arg3 = [])
    {
        // method body
    }
}
```
- 一般的に小文字スタートで他の単語を繋ぐ場合は大文字をくっつけるキャメルケースが主流だが、その確認
- やはりメソッド名は公式でもキャメルケースで記載している

## 他参考になったこと
#### phpファイルの終了タグ
phpファイルだと認識をさせる`<? php ?>`だが、終了タグの`?>`は記載してもしなくてもどちらでも良いという認識だったのだが、公式を見ると`終了?>タグを省略しなければなりません。`とまで断言している。

#### 行の長さ
行の長さに関して、厳格なルールはないが、原則として`120文字でなければならない`とのこと。
また行の長さに関しては、`80文字より長くすべきではない`とのこと。

#### インデント
コードは、インデント レベルごとに 4 つのスペースのインデントを使用しなければならず (MUST)、インデントにタブを使用してはなりません。とのこと。知らなかった。

## まとめ
などなど知ってそうで知らないことまでたくさん書いてあるので、良いコードを書く上で必読だと思いました。
リーダブルコードなども併せて読んで、良いコードが書けるように努力していく。

以上
SVN 「バージョン管理下にありません」の時の対応

## 概要
MACでsnailSVNというクライアントツールを使って修正ファイルをコミットしようとしたら、以下のようなエラーがでました。

```
svn: E200009: 'XXXX' is not under version control
```

## 原因
隠しファイルとして二重で存在していた。

## 対応方法
隠しファイルを削除してコミットできた。
[Prisma] db migrate時に毎回データを削除されそうになる

```:環境
prisma: ^4.7.1
db: postgresql(supabase)
```

# 問題
以前prisma-postgresqlの拡張機能を試しました。

https://qiita.com/www_y118/items/349435ad1e093ff53435

これ以降 `prisma migrate dev`するたびにデータが失われることが求められます。これは非常に困る。

実際のエラー
```bash
The following is a summary of the differences between the expected database schema given your migrations files, and the actual schema of the database.

It should be understood as the set of changes to get from the expected schema to the actual schema.

[+] Added extensions
  - uuid-ossp

- The following migration(s) are applied to the database but missing from the local migrations directory: 20230xxxxxx_migration

✔ We need to reset the "public" schema at "db.xxxxx.supabase.co:5432"
Do you want to continue? All data will be lost. … no
```

# 解決法
正攻法でない気がしますが、とりあえず拡張の部分を消すとデータの削除は防げます。
```js:schema.prisma
generator client {
  provider        = "prisma-client-js"
  // 削除 previewFeatures = ["postgresqlExtensions"]
}

datasource db {
  provider   = "postgresql"
  url        = env("DATABASE_URL")
  // 削除 extensions = [citext(schema: "public"), uuid_ossp(map: "uuid-ossp")]
}
```

# やったこと
dbからschemapullしたあとにmigrateしてもダメでした。
1. `prisma db pull`
1. `prisma migrate dev`

おそらくsupabase側のextensionsと衝突してる気がします。
ちなみにsupabase側の`uuid-ossp`は停止できなかった。
![スクリーンショット 2023-02-09 18.27.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/787586/5068a46c-596b-aa81-1173-9f840e2ddb60.png)
OpenSSL の使い方練習: ECDSA


[OpenSSL の使い方練習: 単純な証明書チェーンを作る - Qiita](https://qiita.com/propella/items/626c6586248287dcf302) と同じですが、楕円曲線というのを使うと鍵がすごく短くて済むので試してみました。単に鍵を作るコマンドが違うだけですが後で参考にするためここに載せます。

## ルート証明書を作る

鍵を作る

    openssl ecparam -name prime256v1 -genkey -noout > root.key

鍵の中を見る

    openssl pkey -text -noout < root.key

ルート証明書を作る

    openssl req -x509 -days 36500 -subj "/CN=Tama Root CA" -key root.key  > root.crt

ルート証明書の中を見る

    openssl x509 -text -noout < root.crt

## S/MIME 用の証明書を作る

S/MIME 用鍵を作る

    openssl ecparam -name prime256v1 -genkey -noout > signer.key

S/MIME 用証明書要求 CRS を作る

    openssl req -new -subj "/L=Musashi/CN=kodaira.example.com" -key signer.key > signer.csr

S/MIME 用証明書要求 CRS を確認

    openssl req -text -noout < signer.csr

signer.conf という名前で設定ファイルを作る。

```conf
basicConstraints = critical,CA:FALSE
keyUsage = critical,digitalSignature,keyEncipherment
extendedKeyUsage = emailProtection
```

S/MIME 用 CSR をルート証明書で署名する

    openssl x509 -req -days 36500 -CA root.crt -CAkey root.key -CAcreateserial -extfile signer.conf < signer.csr > signer.crt

S/MIME 用証明書を確認

    openssl x509 -text -noout -purpose < signer.crt

## 参考

* [TUTORIAL: How to Generate Secure Self-Signed Server and Client Certificates with OpenSSL - The Devolutions Blog](https://blog.devolutions.net/2020/07/tutorial-how-to-generate-secure-self-signed-server-and-client-certificates-with-openssl/)
* [OpenSSLで楕円曲線暗号（Elliptic Curve Cryptography: ECC）を使用した自己証明書を作成する方法 - Qiita](https://qiita.com/yasushi-jp/items/240590b26a2a5696cf33)
顧客分析の手順 - 分析フォーマットの適用例：パーセンタイルプロファイリング 解約想定顧客の利益構造 

:::note
この本書は2017年4月1日にTeradata Japanのブログに掲載された内容を、再掲載したものです。
掲載内容の正確性・完全性・信頼性・最新性を保証するものではございません。
また、修正が必要な箇所や、ご要望についてはコメントをよろしくお願いします。
:::


著者 山本 泰史 （やまもと やすし）


# 顧客分析の手順

## 第16回： 解約想定顧客の利益構造
今回はパーセンタイルプロファイリングを用い、顧客リテンションを目的とした分析例をご紹介します。


### 分析の前提
この分析例では、解約確率が高い顧客を対象にパーセンタイルプロファイリングを実施します。ここでは、データマイニングの作業を通じて、既に解約確率を顧客毎に付与済みであることを前提としています。解約確率 - これは離反確率、休眠確率と言い換えても良いですが - の高い顧客が、どのような定量的パフォーマンスを有しているかを把握することは重要です。

企業が「解約されて困る」場合、それはその顧客が自社の利益構成の一部を占めており、解約によってそれが減損するためです。これを裏返すと、赤字になってしまっている顧客が解約することは、「困らない」ということでもあります。

冷徹なコトを言うつもりはないですが、八方美人になんでも提供できる企業というのは稀です。従って自社のビジネス形態に合致した顧客もいらっしゃれば、合致しない顧客も確実にいらっしゃいます。日常的な企業活動の中で、このような顧客との取引が発生し、それが継続することも有り得えます。このとき、無理に取引や関係を継続し、赤字を発生させてしまうことは好ましいことではありません。その赤字を補填するのは、自社の商品やサービスに対してより多くの利益金額を与えてくれている優良な顧客であり、このような優良顧客にとっても、自社にとっても、報われない関係が長く続くことは得策ではありません。

もちろん顧客は自らが得られる価値に対して支出し、企業はそれに対して対価を払い、差分としての利益をプールします。利益は税金、株式配当等の形で企業のステークホルダーに対して分配されるだけでなく、投資として事業活動の継続／発展をするためにも用いられます。従って他の顧客、他の商品、他のチャネル、他の投資対象に投資されることは一定の範囲内において認められます。しかしこれも回収されるという見込みがあって成り立つものです。


### 解約顧客の利益性
このため、ここでは解約が想定される顧客の利益額に基づいてパーセンタイルプロファイリングを適用します。図25A がその分析例ですが、対象セグメントとして解約確率0.7以上の顧客に絞り込み、この顧客を対象として分析を実施しています。そして利益金額を基準に 7つのグループに分割し、それぞれのグループが有している利益パフォーマンスを把握しています。

<img width="700" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2768546/c337a277-4718-2f94-8329-ab4f5d51b212.png">

これを見るに、ランク1 の約4,400万円の利益をもたらしてくれる 410名が解約の危機にあるという事実はショッキングです。これらの顧客を維持すべきという意見に異を唱えることはないと思います。そして、利益額が赤字になっているのは、ランク6、およびランク7 の顧客群です（もしかしたらランク5 の顧客群も）。これは、図25B を見るとさらに明らかです。

<img width="700" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2768546/156e433e-c757-541e-5d3c-ab70c57b7610.png">

### アプローチの方向性
まず、利益貢献度が高い顧客に関して。何らかの維持施策が必要であることは明らかです。これらの顧客プロファイルをさらに確認して、どのような顧客群か、何か不満の傾向があるのかを把握することが必要です。また確率をはじき出した数式が、どの変数を大きな確率上昇要素として捉えているかも参考になると思います。

そして、赤字もしくは利益額の薄い顧客群に関して。まずは赤字の原因を理解し、それらを改善する可能性があるのかを判断します。大別すればそれは、無用なキャンペーン案内経費をかけてしまっているのか、そもそも商品／サービス原価が顧客支出額と伴っていない構造になっているのか、のいずれかです。前者の場合には単純にこれ以上の経費支出をストップします。そしてこれによって利益構造が改善するのであれば、解約阻止の施策の実施対象として含めます。

一方、後者の場合は何のアクションも必要ありません。維持施策の経費が効けば、これまで以上に赤字を増大させることになります。残念ですが、このままではこれらの顧客群とはこれ以上ビジネスできません。もちろん契約上取引を継続しなければならないのであれば、それはもう勉強料として最低限の赤字を覚悟しなければなりませんが、もしそうでないならば、このような赤字をもたらしている商品／サービスの価格を見直すことも必要です。

但し、マーケティングだけでなく、企業全体の問題としてこの問題点を捉えた場合には、価格を見直す前にすべきことがあります。とるべき手順としては以下の通りです。


１．商品／サービスの機能や属性の中で、無用な経費（顧客に求められていないサブ機能やサービス）が存在しているかどうかを確認し、そのような経費支出の原因が存在しているのであれば、それらの機能やサービスを取りやめる。
２．更なる経費支出をもカバーするような高い価格設定をできる機能／属性を追加する、もしくは別の商品／サービスで利益回収する、等の手段により赤字をカバーできるよう商品／サービス体系を改善する
３．１． および ２． を以ってしても利益構造が改善しない場合、当該商品／サービスに関する価格設定、価格構造を見直す。これによって赤字につながる取引を実質的にストップする。
要は、提供している商品／サービスや、その組み合わせ、そして機能要素に手を加える余地があるかを検討することが必要です。これはどちらかというと商品/サービス開発分野の専門となります。組み合わせの仕方で顧客支出額を改善できる、もしくは顧客満足に大きな影響を与えずに商品／サービス原価を改善できる点があるかを探すことができれば、これらの顧客からの利益を改善することが可能となります。

価格は顧客が購入／利用を決定するにあたって検討する要素の 1つでしかありませんが、それによって顧客の支出が決定されるため、重要な要素でもあります。また、競合他社との関係の中で競争力のある価格であることも求められます。従って、企業としてはこれを機会にコスト構造を改善できるのであれば、まずそれを検討すべきです。

次回からは、クロスセグメント分析を利用した分析例についてご紹介します。



#### Teradata Vantageへのお問合せ
[Teradata Vantage へのお問合せ](https://www.teradata.jp/About-Us/Contact)
kintoneでコピーボタンを設置する

kintoneでは標準機能に加えて、JavaScriptやプラグインを使えば自由にカスタマイズできるようです。
今回はコールセンターでの作業効率化のため、電話番号のコピーボタンを実装しました。

# 前提
- kintoneでデータの管理をしている方。
- kintoneのカスタマイズをしたい方。
- kintoneにコピーボタンを実装したい方。

上記のような内容を実装したい方は、ぜひ参考にしてみてください。

# 完成系
```kintone_customize.js
(() => {

  'use strict';

  // 詳細画面でイベントを宣言
  kintone.events.on('app.record.detail.show', event => {

    // ボタンを設置
    let CopyButton = document.createElement('button');
    CopyButton.innerHTML = 'copy';
    CopyButton.id = '電話番号';
    CopyButton.style.borderRadius = '10px';
    CopyButton.style.marginLeft = '20px';
    CopyButton.style.marginTop = '10px';
    CopyButton.style.marginBottom = '10px';

    // クリップボードにコピー
    let phoneNumber = kintone.app.record.getFieldElement("電話番号");
    CopyButton.addEventListener('click', function() {
      const phoneNumberText = phoneNumber.firstElementChild.textContent;
      copytoClipboarad(phoneNumberText);
    });

    // コピーを実行
    phoneNumber.appendChild(CopyButton);
　
    // コピー後の挙動
    async function copytoClipboarad(target) {
      await navigator.clipboard.writeText(target)
      CopyButton.style.color = 'green'
      CopyButton.style.borderColor = 'green';
      CopyButton.innerHTML = 'copied';
    };

  });
})()
```

# 解説
#### イベントを宣言
```kintone_customize.js
  kintone.events.on('app.record.detail.show', event => {
```
これはkintoneの記法で、ここでは詳細画面を選択。
他にも一覧画面や作成画面なども指定できるようです。
- 一覧画面
```kintone.events.on('app.record.index.show', event => {```
- 作成画面
```kintone.events.on('app.record.create.show', event => {```


#### ボタンを設置
```kintone_customize.js
    // ボタンを置きますよと宣言
    let CopyButton = document.createElement('button');
    // ボタンのHTML
    CopyButton.innerHTML = 'copy';
    // フィールドコードを取得
    CopyButton.id = '電話番号';
    // CSSを定義
    CopyButton.style.borderRadius = '10px';
    CopyButton.style.marginLeft = '20px';
    CopyButton.style.marginTop = '10px';
    CopyButton.style.marginBottom = '10px';
```
```CopyButton.id```の部分で配置する箇所を決めています。
kintoneではフィールドコードというもの（JavaScriptでいう「id」）を指定することができて、これはkintone側で設定できます。

#### クリップボードにコピー
```kintone_customize.js
    // フィールドコードの内容をphoneNumberに格納
    let phoneNumber = kintone.app.record.getFieldElement("電話番号");
    // ボタンをクリックした時の挙動
    CopyButton.addEventListener('click', function() {
　    // コピーしたい内容をphoneNumberTextに格納
      const phoneNumberText = phoneNumber.firstElementChild.textContent;
      // phoneNumberTextをクリップボードにコピー
      copytoClipboarad(phoneNumberText);
    });
```
```const phoneNumberText = phoneNumber.firstElementChild.textContent;```はユーザー画面の検証ツールでHTMLを確認し、それに合わせて変えるイメージ。

#### コピー後の挙動
```kintone_customize.js
    async function copytoClipboarad(target) {
      await navigator.clipboard.writeText(target)
      // CSSを定義
      CopyButton.style.color = 'green'
      CopyButton.style.borderColor = 'green';
      CopyButton.innerHTML = 'copied';
    };

```
コピーできたかを目視でわかるよう、ボタンの色と文字を変更。



# 最後に
たった一つのボタンですが、こちらを実装したことで作業のストレスは格段と減り、効率はぐんっと伸びました。
他にもCSSでデザインを一変させてみたり、プラグインで機能を追加できたりなど、アイデア次第でさまざまなカスタマイズができるみたいです。
実際に働いている方の要望に応えられるよう、技術力も高めていきたいですね。
いまさらながら、色々な y=x^n のグラフを描いてみた

　$y=x^2$ は数学で初めて習った曲線の関数です。その後、もっと一般的に $y=x^n$ などという関数も出てきて、$dx^n/dx=nx^{n-1}$ が成り立つことも教わりました。あれやこれやで、$y=x^n$ については既に完全にマスターしたつもりになって今に至りました。

　しかし、よくよく考えてみれば。自分でグラフを描いたことがあるのは $n=-1$（双曲線）、$0$（水平線）、$0.5$（平方根）、$1$（直線）、$2$（放物線）、$3$（3次曲線） 程度しかありません。これだけでは、$y=x^n$ の具体的な特徴を身体で知ったことにはなりません。このままでは、問題解決のための新たな直観的な発想も湧き難いのではないでしょうか？

　ということで、とりとめもなく色々と描いてみました。
 
![Fig_21A.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/932484/70b0d7ae-5cf8-9fd4-e228-e004aa8ca2dc.png)

いまさらながらですが、これを見て下記が実感できました。
+ 　$n$ が非常に大きくなると、ほぼ直角に接続された直線に近づく。
+ 　$x{=}0$ において二階微分が存在し、$0$ 以外の値を持つのは $n{=}2$ の場合のみ ということの視覚的理解。
+ 　テイラー展開で、いくら次数を上げても、収束半径の縛りから逃れられない現実。
Githubのリポジトリ設定で管理者も含めて直pushを禁止にする設定


## 設定場所
```
対象のリポジトリ - Settings - Branches - Branch protection rules
```

## 設定
管理者も含めて全員プルリクエスト必須（直push禁止）にするには、下記の設定2つにチェックを入れる必要があります。

```
// プルリクエスト必須となる（直pushできなくなる）
□ Require a pull request before merging

// 管理者権限の人も、ルールの対象にする
□ Do not allow bypassing the above settings 
```

## 直push時のpushエラーログ

```bash
remote: error: GH006: Protected branch update failed for refs/heads/main.
remote: error: Changes must be made through a pull request.
To github.com:daijinload/test2.git
 ! [remote rejected] main -> main (protected branch hook declined)
error: failed to push some refs to 'github.com:daijinload/test2.git'
```

よしっ！！

## 余談
一時的にforce pushが必要となった場合、ルール内に一時的に許可できる設定`Allow force pushes` があったりします。(・∀・)ｲｲﾈ!!

## ひとこと
個人のリポジトリで試したのですが、設定入れてもなぜかpush出来てしまい、少しハマりました。

上述した管理者権限の人も対象にする設定が必要というオチでした。

ちょっと分かりづらかったですが、ルールを複数設定出来たり、対象ブランチのワイルドカード指定もできるで、柔軟に設定できそうです。

複数人で開発していると、間違いなどあると思うので、設定を入れておくと良いと思います。
EC2 RHEL環境にLaravel環境を構築

# EC2 RHEL環境にLaravel環境を構築
:::note warn
EC2を構築済みであり、SSHで接続できることが前提
:::
## EC2へSSH接続
1\. EC2へSSH接続
2\. roo権限にする
```
$ sudo su -
```
## PHPをインストール
```
$ yum install wget
$ wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
$ wget https://rpms.remirepo.net/enterprise/remi-release-7.rpm
$ rpm -Uvh remi-release-7.rpm epel-release-latest-7.noarch.rpm
$ subscription-manager repos --enable=rhel-7-server-optional-rpms
$ yum install yum-utils
$ yum module install php:7.2
$ yum install php php-gd php-pdo php-xml php-sqlsrv php-mysql php-mbstring php-pear php-devel php-mcrypt re2c gcc-c++ gcc
$ yum install php-zip
```
## bcp、sqlcmdをインストール
```
$ yum install mssql-tools
$ echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile
$ echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
$ source ~/.bashrc
```
## composerをインストール
```
$ curl -sS https://getcomposer.org/installer | php
$ mv composer.phar /usr/local/bin/composer
$ chmod +x /usr/local/bin/composer
```
## Laravel5.7インストール(プロジェクト作成)
```
$ cd /var/www/html ←DocumentRootディレクトリ
$ composer create-project "laravel/laravel=5.7.*" xxxxx ←プロジェクト名
```
## 権限設定
```
$ cd /var/www/html
$ chmod -R 777 xxxx ←プロジェクト名
$ cd xxxx/
$ chmod -R 777 storage
$ chmod -R 777 bootstrap/cache
$ composer require intervention/image
```
## httpd開始・自動起動設定
```
$ service httpd start
$ systemctl enable httpd.service
```
## firewallにhttp許可 ※再起動
```
$ sudo su -
$ yum install firewalld
$ systemctl start firewalld
$ systemctl enable firewalld
$ systemctl status firewalld
$ firewall-cmd --add-service=http --zone=public --permanent
$ firewall-cmd --add-service=https --zone=public --permanent
```
## Apacheの設定変更
```
$ vim /etc/httpd/conf/httpd.conf
以下を記載
DocumentRoot "/var/www/html/xxxx/public"

$ service httpd restart
```
## タイムゾーンの設定変更
```
$ timedatectl set-timezone Asia/Tokyo
$ timedatectl set-ntp yes
$ vim /etc/php.ini
以下を変更
;date.timezone =
↓
date.timezone = Asia/Tokyo
```
## クーロンインストール
```
$ yum install cronie
$ systemctl enable crond.service
$ systemctl start crond.service
$ timedatectl set-timezone Asia/Tokyo
$ ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
$ systemctl restart crond
```
## ログの書き込み権限エラー解消
```
$ setenforce 0
$ vim /etc/selinux/config
SELINUX=disabled
```
## cssがhttp通信になる問題
・参照ページ：[https対応したLaravelプロジェクトでassetを使う時の注意点](https://qiita.com/e_tyubo/items/c25df0c545b1af8494c7, "https対応したLaravelプロジェクトでassetを使う時の注意点")
Azure Administrator(AZ-104)：Azure での ID とガバナンスの管理「Azure ADセルフサービスパスワードリセットの詳細」

Microsoft Learnを用いたMicrosoft Azure Administrator(AZ-104)の試験内容をまとめる投稿です。
この投稿ではMicrosoft Learnで学ぶ内容をできるだけ簡潔にまとめております。
Azureの勉強を一から始め、AZ-900取得後の資格としてAZ-104取得を目指している方の参考になれば幸いです。
※AZ-900の内容は本投稿では省略しております。再度復習したい方は下記をご参照ください。
[Azure Fundamentals(AZ-900)：試験合格に向けた学習内容のまとめ](https://qiita.com/fsd-jume/items/e4ec76959adb547ac5e8)

## 今回の学習内容
**◆「Azure ADセルフサービスパスワードリセットの詳細」**
◇対応するMicrosoft Learn ラーニングパス
[AZ-104:Azure での ID とガバナンスの管理](https://learn.microsoft.com/ja-jp/training/paths/az-104-manage-identities-governance/)
◇対応するモジュール
[Azure Active Directory のセルフサービス パスワード リセット とは](https://learn.microsoft.com/ja-jp/training/modules/allow-users-reset-their-password/2-self-service-password-reset)

※前回の投稿は下記から確認できます。
[Azure Administrator(AZ-104)：Azure での ID とガバナンスの管理「Azure AD B2Bによるゲストユーザアクセス」](https://qiita.com/fsd-jume/items/ac40cb4f222801b2d397)

## Azure ADセルフサービスパスワードリセットの詳細
### セルフサービスパスワードリセット(SSPR)
AZ-104学習まとめの以前の投稿でも扱っておりますので、復習したい方は下記をご参照ください。
[Azure Administrator(AZ-104)：Azure での ID とガバナンスの管理「Azure ADのセルフサービスパスワードリセット」](https://qiita.com/fsd-jume/items/e3b7e1cfd6878a59bc13)

**◆SSPRを使用する理由**
・Azure ADサインイン後はすべてのユーザがパスワード変更可能
⇒サインイン前やパスワード忘れ/有効期限切れの場合は不可
⇒SSPRを使用することでWebブラウザ/サインイン画面でリセット可能
・ユーザが自分でパスワードの問題に対処可能
　-管理者の負担減
　-ユーザの対応待ち時間の削減

**◆SSPRの仕組み(リセットポータルの場合)**
①ローカライズ：ブラウザのロケール設定から適切な言語でポータルを表示
②確認：下記を実施し、ユーザIDとボットではないことを確認
　-Email or ユーザ名を入力
　-CAPTCHAの文字を入力
③認証：IDの認証に必要なデータを入力(コードの入力など)
④パスワードのリセット：認証に合格後、新しいパスワードを入力して確認
⑤通知：リセットしたことをユーザにメールで送信

**◆SSPRユーザエクスペリエンスのカスタマイズ**
・サインインページ/ポータル画面に会社のロゴを追加可能
⇒パスワードリセットの適切な場所にいることをユーザに知らせることが可能
・管理者への連絡用リンク(メールアドレス/URL)を設定可能
⇒SSPRについてサポートを求める際に使用

**◆認証方法**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851723/3c65617a-68aa-4826-5e7c-0be63018b3f6.png)

**◆認証方法の最小数**
・ユーザが設定する必要がある認証方法の最小数(1or2)を指定可能
・セキュリティの質問の最小数を指定可能
　-ユーザが設定する必要がある質問の最小数
　-ユーザが回答する必要がある質問の最小数
・指定されている最小数の方法に必要な情報を登録
⇒ユーザがSSPRに登録されたものとみなす

### パスワードリセットの認証
**◆認証方法の推奨設定**
・2つ以上の認証方法を有効
・主要な方法はモバイルアプリの通知/コード
⇒モバイルデバイスを持たないユーザ向けにEmail/会社電話も有効
・携帯電話は、不正なSMSメッセージを送信可能なため、非推奨
・セキュリティの質問は回答を他人に知られる可能性があるため、最も非推奨
⇒少なくとも1つの他の方法と組み合わせた場合のみ使用

**◆管理者アカウント**
・デフォルトでSSPRが有効
・常に2つの強力な認証方法が必要
⇒セキュリティの質問は使用不可

### SSPRの通知
**◆パスワードのリセットについてユーザーに通知しますか?**
・ユーザのパスワードが変更されたことを通知可能
・通知先：変更されたユーザのプライマリ/セカンダリメールアドレス

**◆他の管理者が自分のパスワードをリセットしたときに、すべての管理者に通知しますか?**
・ある管理者が自身のパスワード変更時に、他の管理者に通知可能
・通知先：変更した管理者以外の管理者のプライマリメールアドレス

### ライセンス要件
・使用可能なパスワードリセット機能はAzure ADのエディションにより異なる

**◆サインインしているユーザ**
・エディションに関係なく、自身のパスワードを変更可能

**◆サインインしていないユーザ**
・下記のエディションでSSPRを使用可能
　-Azure AD Premium P1/P2
　-Microsoft 365 Business Standard/Premium
　-Microsoft 365 Apps for business

**◆オンプレミスの書き戻しを含むハイブリッドユーザ**
・下記のエディションでSSPRを使用可能
　-Azure AD Premium P1/P2
　-Microsoft 365 Business Premium
　-Microsoft 365 Apps for business

## 次の学習内容
**◆Azure AD SSPRオプション**

https://qiita.com/fsd-jume/items/98028f85ea752d9195b3

## 学習内容をまとめたページの一覧

https://qiita.com/fsd-jume/items/6eda24728c9c03c36bc3
pythonでAPIのレスポンスで取得したjson形式（に見える）データを利用する

PythonからAPIを使って、データを取得したときに、json形式だと思ったら、そうではなかったので、その対応をした記録です。

質問だったら、間違いなく:beginner:を付けるような内容ですが、あとになってあの時どうやってここに辿り着いたんだろうと思った時のために、メモを残しました。


最初に試したこと
```
import os.path
p = "curl https://hoge.jp/results/123456789"
req = os.system(p)
```
変数reqに値が入るかと思ったら入りませんでした。
そこで姑息な手段かと思いつつも、結果をファイルに出力しました
```
import os.path
p = "curl https://hoge.jp/results/123456789 > result.json"
#req = os.system(p)
```

これで<b>“やりたいこと”</b>はできましたがカッコ悪いので、「requests.get」を使うことにしました。

```
import requests
response = requests.get(
    'https://hoge.jp/results/123456789'
)
json_load = json.load(json_open)
json_val  = json_load["results"]
```
「TypeError: byte indices must be integers or slices, not str」となりました。
なんのことだか、ちっともわからないので、printすると、jsonデータの先頭に“b”がついていて、その後ろはシングルクォートで囲まれていました。
```
b'{"results":[{"from"
```

先頭の“b”はバイト型を表しているとわかり、文字型に変換しました。
```
json_load = response.content.decode('utf-8')
json_val  = json_load["results"]
```
すると今度は、
「TypeError: string indices must be integers」のエラーです。
json形式ってただの文字に見えて、辞書型でないとダメらしい。
ということで次は文字型を辞書型に変換しました。

```
json_data = response.content.decode('utf-8')
json_load = json.loads(json_data)
json_val  = json_load["results"]
```
最終的にはこのコードで、APIで得られた結果から、キーresultの内容を取得することができました。
[XCode][Swift]XCodeで日本語文字列リテラルを検索する方法

# はじめに
iOSアプリを多言語対応する場合、言語別に`Localizable.strings`を作成して文言を切替可能にする方法が一般的です。
最初から`Localizable.strings`にアプリ上で使う文言を設定していればよいのですが、日本語専用のつもりで直接コード上の文字列リテラルに文言を書き込んで開発を進めていた場合が問題です。
後から多言語対応するにはコード上に散らばった文言を全て見つけ出して`Localizable.strings`に移行する必要があります。
この記事ではXCodeの正規表現検索機能を使って日本語文字列リテラルを検索する方法を紹介します。

# 環境
XCode 14.2

# 方法
以下のサンプルコードで検索にヒットする様子を確認してみましょう。

```swift
print(NSLocalizedString("Hello World", comment: "greetings")) // 英語なのでヒットしない

print("ひらがな") // ヒットする
print("カタカナ") // ヒットする
print("漢字") // ヒットする
print("あのイーハトーヴォのすきとおった風") // ヒットする
print("Hello ワールド") // 英語を一部含んでいてもヒットする
```

1. XCodeのFind>Regular Expression を選択
2. 入力欄に `".*[一-龥ぁ-んァ-ヶ]+.*"`を入力して決定

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/720855/226161c6-9bea-69ec-51a8-9a5fc38479ca.png" width=320>
<br>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/720855/4b96b636-dcf9-a855-2c13-aad5ee7dd148.png" width=320>
データの結合 - concatかmergeか

# concatかmergeか
共通のカラムを持つデータフレーム同士を結合する場合に、concatやmergeが使われます。

どういう場面でconcatを使って、mergeを使うのはどういう場面なのでしょうか。
・mergeは共通の変数（カラム）を持つデータフレーム同士を結合する
・2つのファイル（データフレーム）と結合する時はmerge
・同じ列名同士で横につなげたい時はconcat

# 題材
データサイエンティスト協会が出している[100本ノック - 構造化データ加工編](https://github.com/The-Japan-DataScientist-Society/100knocks-preprocess)を題材に使用します。


# 実例 - concat
19問目を使ってconcatの実例を示します。

>問題
レシート明細データフレーム（df_receipt）に対し、1件あたりの売上金額（amount）が高い順にランクを付与し、先頭10件を抽出し表示せよ。
項目は顧客ID（customer_id）、売上金額（amount）、付与したランクを表示させること。
なお、売上金額（amount）が等しい場合は同一順位を付与するものとする。

本題に入る前にdf_receiptを呼び出して、変数名や中身を見てみましょう。

```python
df_receipt = pd.read_csv('皆さんの保存場所/receipt.csv')
df_receipt.head()
```
出力結果はこちら。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688182/2e1271a9-e210-24bf-46b1-43b38d842f60.png)

"sales_ymd"から"amount"まで9つの変数があることがわかります。問題文によると"amount"の順位を作って、"customer_id"、"amount"、"amount"の順位で表示させることを求めています。

<b>同一データフレーム内の必要な項目を抽出してつなぎ合わせる時に*concat*を使います。</b>

```python
df_tmp = pd.concat([df_receipt[['customer_id','amount']],df_receipt['amount'].rank(method='min', ascending=False)], axis=1)
df_tmp.columns = ['customer_id', 'amount', 'ranking']
df_tmp.head(10)
```

> <b>concatのコードの型</b>
pd.concat('変数1', '変数2', ..., '変数n', axis=1)
並べたい順に変数名を記述します。

### axisについて
```axis=1```と書く事で、横方向にデータが連結されます。書かないと```axis=0```として実行されて、縦方向にデータが連結されます。


# 実例 - merge
36問目を使ってmergeの実例を示します。

>問題
レシート明細データフレーム（df_receipt）の全項目と店舗データフレーム（df_store）の店舗名（store_name）が出力されるように、レシート明細データフレームと店舗データフレームを内部結合し、結合後のデータを10件表示せよ。

df_receiptとdf_storeの二つのデータフレームを結合させるので、mergeを使います。

mergeをするには結合したいデータフレームそれぞれに共通した変数があることが必要です。それを軸に結合します。

df_receiptとdf_storeのそれぞれの変数を調べてみます。
```python
print('df_receiptの変数名')
print(df_receipt.columns)
print()
print("df_storeの変数名")
print (df_store.columns)
```

> df_receiptの変数名
Index(['sales_ymd', 'sales_epoch', 'store_cd', 'receipt_no', 'receipt_sub_no',
       'customer_id', 'product_cd', 'quantity', 'amount'],
      dtype='object')
> df_storeの変数名
Index(['store_cd', 'store_name', 'prefecture_cd', 'prefecture', 'address',
       'address_kana', 'tel_no', 'longitude', 'latitude', 'floor_area'],
      dtype='object')

という結果を得られます。mergeの対象は
・df_receiptの全項目
・df_storeの'store_name'のみ
です。そしてそれぞれのデータフレームで共通して使われている変数を軸とします。それが'store_cd'です。

注意しなければならないのは、mergeされるdf_storeの抽出対象変数に軸となる'store_cd'を含める事です。

mergeを次のコードで実行します。
```python
pd.merge(df_receipt,df_store[['store_cd','store_name']].how='inner', on='store_cd').head(10)
```

出力結果はこちら。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688182/3a51bc5c-39d0-e240-ced8-1442c0bd154b.png)

mergeしたdf_storeの'store_name'が一番右側に結合されています。

> <b>mergeのコードの型</b>
pd.merge('データフレーム1', 'データフレーム2'.how='結合方法',on='軸となる変数')

## mergeの結合方法について
how=の後で結合方法を指定しますが、4つの方法があります。
inner：内部結合
left：左結合
right：右結合
outer：完全外部結合

ここで説明すると長くなりそうなので、**mergeの結合方法** について別途投稿したいと思います。
起動テンプレートのAMIをSSMパラメータで指定する

# 背景
アップデートで、EC2起動テンプレートのAMI指定欄にSSMパラメータを指定することができるようになりました。
これにより、AMI更新時に起動テンプレートのAMI欄を修正して新規バージョンを発行する必要がなくなりました。

https://aws.amazon.com/jp/about-aws/whats-new/2023/01/amazon-ec2-launch-templates-aws-systems-manager-parameters-amis/

# 試してみる

ssm パラメータを作成し、amiを参照する流れを試してみます。
パラメータにラベルをアタッチし、ラベルからバージョンを参照します。
amiを更新する際にはパラメータをoverwriteし、ラベルの付け替えを行います。

![更新イメージ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/964a60a2-8972-d0b8-27c1-4388c7c61b68.png)


## パラメータの作成
AMIのIDを管理するパラメータを作成します。
Amazon Linux2から作成した自己所有のAMIを設定しています。

```shell
aws ssm put-parameter \
    --name "/amis/custom-image" \
    --type "String" \
    --data-type "aws:ec2:image" \
    --value "ami-0b2abc514ca314069" 
```

更に、新規作成したパラメータのバージョンにラベル：`Current`を設定します。

```shell
aws ssm label-parameter-version \
    --name "/amis/custom-image" \
    --labels "Current" \
    --parameter-version 1
```

パラメータの作成が完了しました。

![スクリーンショット 2023-02-09 111033.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/cd9f29ad-636d-fd3e-fc6e-19394b08f9a5.png)

## 起動テンプレートの作成

EC2のコンソールから起動テンプレートを作成します。
SSMパラメータの参照はAMI設定の箇所で行います。

Browse more AMIsを選択。
![スクリーンショット 2023-02-09 105357.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/3c39e89c-d1ae-9956-23c3-c7a54dd80720.png)

検索窓の△から「カスタム値/Systems Managerパラメータを指定」を選択。

![スクリーンショット 2023-02-09 105448.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/3bac5c18-67f6-0121-e875-2be44ff97b6b.png)

ssmパラメータの文字列を入力します。
入力方法は色々ありますが、今回はlabelで管理したいのでlabelを入力に含めています。
`resolve:ssm/amis/custom-image:Current`
![スクリーンショット 2023-02-09 112353.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/cd0d09f1-d757-d7f2-c1ad-66a06e3b4dda.png)

他は任意に設定し、作成を行います。
## 起動の確認
上記で作成した起動テンプレートからインスタンスを起動すると、ssmパラメータのamiが参照されていることを確認できました。

![スクリーンショット 2023-02-09 114313.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/e6aece40-1714-a57d-27f2-5346e08debf4.png)

amiの更新も確認してみます。
パラメータをoverwriteし、Currentラベルを付け替えます。

```shell
aws ssm put-parameter \
    --overwrite \
    --name "/amis/custom-image" \
    --type "String" \
    --data-type "aws:ec2:image" \
    --value "ami-082762d8b0e73e89c" 

aws ssm label-parameter-version \
    --name "/amis/custom-image" \
    --labels "Current" \
    --parameter-version 2
```

![スクリーンショット 2023-02-09 121418.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/278263fe-b1ea-ea8b-ca25-0e61f7ad1c1c.png)

この状態でインスタンスを起動すると、パラメータバージョン2のamiが参照されました。

![スクリーンショット 2023-02-09 122015.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675893/03b643a8-5480-a3ff-f6e5-dd447d189a5b.png)


# まとめ
EC2起動テンプレートのAMI指定欄にSSMパラメータを指定することができるようになりました。これにより、パラメータを更新するだけで起動テンプレートのAMIを変更することができます。
AMIの指定をSSMパラメータに寄せるのか、起動テンプレート内で指定し新しいバージョンを発行するのかで運用フローが分かれそうですね。個人的にはSSMパラメータに寄せたほうが楽になるかなと思います。
ただ、Image Builderと連携していれば自動でAMIを更新して新バージョンを発行してくれるそうなので、SSM パラメータは不要であると思います。

https://docs.aws.amazon.com/ja_jp/imagebuilder/latest/userguide/dist-using-launch-template.html