OmniAICreator/Qiita-1.07M huggingface dataset:
LINEのトーク履歴をDataframeに変換する

# 目標

LINEからテキストファイルで出力したトーク履歴を、以下のようなPandas Dataframeに落とし込みます。

| date      | time  | by         | content    | 
| --------- | ----- | ---------- | ---------- | 
| 2022/2/14 | 10:10 | テスト太郎 | hoge hoge  |  | 
| 2022/2/14 | 10:11 | テスト花子 | [スタンプ] |  | 

# コード
`Dataframe.append`はコスパが悪いようなので、まずは各列のリストを作り、最後にDataframeに変換するようにしました。

```Python
import re
import pandas as pd


def lineHistoryToDf(filePath):
​
    regex = re.compile('^[0-9]{4}/[0-9]{1,2}/[0-9]{1,2}\(.\)$')
    date, time, by, content = [], [], [], []
​
    with open(filePath) as f:
        f = f.readlines()[3:-1]
        for line in f:
            l = line.rstrip('\r\n')
            if len(l.split('\t')) > 2:
                nl = l.split('\t', 2)
                date.append(today[:-3])
                time.append(nl[0])
                by.append(nl[1])
                content.append(nl[2])
            elif len(l.split('\t')) == 2:
                nl = l.split('\t', 1)
                date.append(today[:-3])
                time.append(nl[0])
                by.append(None)
                content.append(nl[1])
            elif regex.match(line):
                today = l
            else:
                content[-1] += l
        df = pd.DataFrame(data={'date': date, 'time': time, 'by': by, 'content': content},
                                columns=['date', 'time', 'by', 'content'])
    return df
```

以下は遅いのでおすすめしません。

```python
import re
import pandas as pd

filePath = '~/line_log.txt'

df = pd.DataFrame(columns=['date','time','by','content'])
regex = re.compile('^[0-9]{4}/[0-9]{1,2}/[0-9]{1,2}\(.\)$')

with open(filePath) as f:
    f = f.readlines()
    for line in f:
        l = line.rstrip('\r\n')
        if len(l.split('\t', 2)) > 2:
            nl = l.split('\t')
            nl.insert(0, today[:-3])
            nls = pd.Series(nl, index = df.columns)
            df = df.append(nls, ignore_index=True)
        elif regex.match(line):
            today = l
        else:
            df.iat[-1,-1] += l
```

# 考え方

- テキストファイルの冒頭2行はトーク履歴ではないためスキップする。
- 1行のタブ数が3つ以上の場合
    - 会話のログであると判定する。左から読んで2つ目のタブ文字までを区切り文字とし、それ以降のタブ文字は無視する。
- 1行のタブが2つ以下の場合
    - 日付の場合：該当行以降のdateとして設定する。
    - 日付以外の場合：前の会話内容の続きであると判定して直前の会話内容として追記する。

なおcontentに「[ファイル]」「[画像]」「[スタンプ]」などのメタ表記が含まれるため、別途columnとしてflagを立ててあげるとより解析しやすくなります。[こちら](https://hattomo.github.io/posts/main/21/q1/0304-python-line/)のサイトが参考になりそうです。
KtorでREST APIを作成する

hello worldまで（更新中）

・intelliJ
・java 11
・gradle

#### intelliJにktorのプラグインをインストールする
「File」→「Settings」→「plugin」→「ktor」で検索し、インストール

#### プロジェクトの作成
ktorのプラグインがインストールされていると、「File」→「New」→「Project」から、ktorプロジェクトを作成できる。

初期から使うものがわかっている場合はTemplatingにチェックを入れてから次へ
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272827/13026464-799e-9659-380d-56fbaf7fcf53.png)

GroupIdとArtifactIdを入力して次へ（パッケージ名となります）
![1.5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272827/67432a2a-b8c9-005b-d432-bb1c8e3da05f.png)

プロジェクト名を入力して作成
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272827/b6e1189b-ecbe-bb64-47a8-4ef5906fae95.png)

#### Getメソッドの作成
src/Application.ktが作成されているので、この中にGetで呼び出すAPIの処理を記述してみる。

```kotlin
package com.example

import io.ktor.application.*
import io.ktor.response.*
import io.ktor.request.*
import io.ktor.routing.*

fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)

@Suppress("unused") // Referenced in application.conf
@kotlin.jvm.JvmOverloads
fun Application.module(testing: Boolean = false) {
    routing {
        get("/hello") {
            call.respond("HELLO WORLD!")
        }
    }
}

```

#### 実行してみる
「Edit Configirations...」をクリックして左上の＋ボタンから「Application」を選択し、下記のように設定する
Main Classには「io.ktor.server.netty.EngineMain」を設定する（プロジェクト作成時に設定したもの）
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272827/8c40b29c-7ddf-9318-6dfe-611754fb28dd.png)

右下の「Apply」をクリックしてから「OK」をクリックすることで「Run」ボタン（右向きの緑色の三角形ボタン）が活性化するのでクリック
下記のようなログが表示されて止まっていれば成功

```
2022-02-14 01:51:40.947 [main] INFO  Application - Autoreload is disabled because the development mode is off.
2022-02-14 01:51:41.986 [main] INFO  Application - Responding at http://0.0.0.0:8080
```

コマンドプロンプトを開いてAPIをたたいてみるとちゃんと返却される
もう少し勉強する

```
$ echo localhost:8080/hello
> HELLO WORLD!
```
UITextField以外からキーボードを表示する

UITextField以外からキーボードを表示する方法を紹介します。
以下の画像ではUIViewをカスタマイズしてUITextFieldっぽく見せています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197742/824afeac-b308-cdf8-36ac-5c0c31bfd8a6.png" width=300>

# 必須実装

UIViewに準拠した独自のViewを作成し、以下の実装を行う必要があります。

- canBecomeFirstResponder
- canResignFirstResponder
- becomeFirstResponder()

ViewをタップしたタイミングでbecomeFirstResponder()を呼び出すことで、キーボードを表示することができます。


# Tips

### UIControlを継承することでtapイベントを取得する
UIControlではtouchUpInsideなどのイベントを取得することができるので、init時にaddTargetを呼び出しtap時の処理を登録します。
UITapGestureRecognizerなどの追加は不要です。

### inputViewの設定で独自のViewをkeyboard部分に設定する
下のコードでは、UIDatePickerをinputViewに設定することで、キーボード部分で時間を設定できるようにしています。

### inputAccessoryViewでkeyboardの上部のViewを設定する
下のコードでは、UIToolbarをinputAccessoryViewに設定し、ボタン押下でキーボードを閉じています。
autoresizingMaskに.flexibleHeightを指定しないと正しく表示できなかったので注意が必要です。

### return押下でキーボードを閉じる
UIKeyInputに準拠することでキーボードの入力イベントを取得することができます。
returnを押した時には insertText 関数に textが `"\n"` として渡ってくるのでその判定の上で `resignFirstResponder()` を呼び出します。

# コード全体

```swift
import UIKit

final class CustomInputView: UIControl {
    override var canBecomeFirstResponder: Bool { !isFirstResponder }
    override var canResignFirstResponder: Bool { isFirstResponder }
    override var inputAccessoryView: UIView? { toolbar }
    override var inputView: UIView? { datePicker }

    private lazy var toolbar: UIToolbar = {
        let toolbar = UIToolbar()
        toolbar.autoresizingMask = .flexibleHeight
        toolbar.setItems([
            UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelButtonTapped)),
            UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil),
            UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneButtonTapped))
        ], animated: false)
        return toolbar
    }()

    let datePicker: UIDatePicker = {
        let picker = UIDatePicker()
        picker.datePickerMode = .countDownTimer
        picker.preferredDatePickerStyle = .wheels
        return picker
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        configure()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        configure()
    }

    private func configure() {
        addTarget(self, action: #selector(itemTapped), for: .touchUpInside)
    }

    @objc private func itemTapped() {
        if isFirstResponder {
            resignFirstResponder()
        }
        else {
            becomeFirstResponder()
        }
    }

    @objc private func cancelButtonTapped() {
        resignFirstResponder()
    }

    @objc private func doneButtonTapped() {
        resignFirstResponder()
    }
}

extension CustomInputView: UIKeyInput {
    var hasText: Bool { false }

    func insertText(_ text: String) {
        if text == "\n" {
            resignFirstResponder()
        }
    }

    func deleteBackward() {}
}
```
net-toolsを捨ててiproute2へ

### 経緯
頑なにnet-toolsのifconfigに慣れ親しんでいたのだが、OSバージョンアップして後から入れるのは面倒なのでそろそろ覚えたい

### 参考
[iproute2:wikipedia](https://ja.wikipedia.org/wiki/Iproute2)
[ipコマンドチートシート](https://access.redhat.com/sites/default/files/attachments/rh_ip_command_cheatsheet_1214_jcs_print_ja4.pdf)

---

### 覚えておきたいもの   
|iproute2コマンド|net-toolsコマンド|役割|
|:--|:--|:--|
|ip addr|ifconfig|IPアドレス確認|
|ss|netstat|ネットワーク状態確認|

---

### ip addrで覚えたいもの   
- インタフェースアップダウン   
`ip addr set eth0 up`   
インタフェースアップさせる   
`ip addr set eth0 down`   
インタフェースダウンさせる

-----

- IPアドレス全部表示   
`ip addr show`   
インタフェースとIPアドレスが表示される
インタフェース名は`1: lo:`から始まる部分の`lo`部分
IPアドレスは`inet`部分

-----

- 特定インタフェースのIPアドレスを表示   
`ip addr show eth0`

---

### ssで覚えたいもの
- 使用中ポート全表示    
`ss -atn`   

|オプション|解説|
|:--|:--|
|a|LISTEN, no-LISTENの全ソケット|
|t|TCPソケット|
|n|数字表示|
[React] 関数コンポーネントのpropsの渡し方と分割代入

## 概要
Reactの学習を進めるなかで、「関数コンポーネントでpropsを渡す際の記述が何通りかあるけど違いはなんだっけ？」と混乱したので整理します。
結論として、ここでは分割代入を使用しているパターンとそうでないパターンについて簡単にまとめます。

## 分割代入とは
[MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)によると

>分割代入 (Destructuring assignment) 構文は、配列から値を取り出して、あるいはオブジェクトからプロパティを取り出して別個の変数に代入することを可能にする JavaScript の式です。

配列の要素やオブジェクトのプロパティを好きに取り出して、変数（定数）に代入することができます。

## Reactでのpropsの渡し方
ここでは`name`と`age`をpropsとして渡す`<Profile />`コンポーネントを例にしてみます。

### 1.　「props.XX」と書く渡し方
まずは分割代入を使わない書き方だと下記のようになります。
各propsに対して`props.XX`と記述する必要があり、数が多いと煩雑です。

```react
export const Profile = (props) => {
 return (
  <p>私の名前は{props.name}です。{props.age}歳です。</p>
 )
```

### 2. propsを分割代入する渡し方
ここで`<Profile />`コンポーネントのpropsの中身をみてみます。
例えば、`<Profile name="Yamada" age="26" />`としたときのpropsは下記の通りです。

```
{　name: "Yamada",　age: "26"　}
```
このように**propsはオブジェクト**なので分割代入ができます。

というわけで、propsを分割代入すると以下のように書けます。

```react
export const Profile = (props) => {
 // propsを分割代入
 const { name, age } = props;

 return (
  <p>`私の名前は{name}です。{age}歳です。`</p>
 )
```

毎回`props.XX`と書く必要がなくなり、スッキリしましたね！

### 3. さらに引数の段階で分割代入
さらに、引数にpropsを渡す段階で分割代入すると以下のようになります。

```react
// 引数にpropsを渡す段階で分割代入
export const Profile = ({ name, age }) => {

 return (
  <p>`私の名前は{name}です。{age}歳です。`</p>
 )
```
propsのプロパティをオブジェクトとして直接渡している、ということですかね。
見た目的には一番スッキリ。

## まとめ
propsを渡す記述はいくつかありますが、どのパターンもやってることは一緒なので、プロジェクトのルールや好みで選択するのがよいかと思います。

## 記事を書いてみて
色んな記述を見て混乱していたのは「propsはオブジェクトである」ということを当初よく分かっていなかったののが大きいように思います。

[公式ドキュメント](https://ja.reactjs.org/docs/components-and-props.html#:~:text=React%20%E3%81%8C%E3%83%A6%E3%83%BC%E3%82%B6%E5%AE%9A%E7%BE%A9%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%82%92%E8%A6%8B%E3%81%A4%E3%81%91%E3%81%9F%E5%A0%B4%E5%90%88%E3%80%81JSX%20%E3%81%AB%E6%9B%B8%E3%81%8B%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%E5%B1%9E%E6%80%A7%E3%81%A8%E5%AD%90%E8%A6%81%E7%B4%A0%E3%82%92%E5%8D%98%E4%B8%80%E3%81%AE%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%A8%E3%81%97%E3%81%A6%E3%81%93%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%AB%E6%B8%A1%E3%81%97%E3%81%BE%E3%81%99%E3%80%82%E3%81%93%E3%81%AE%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%AE%E3%81%93%E3%81%A8%E3%82%92%20%E2%80%9Cprops%E2%80%9D%20%E3%81%A8%E5%91%BC%E3%81%B3%E3%81%BE%E3%81%99%E3%80%82)にもこのように書いてありましたw

>React がユーザ定義のコンポーネントを見つけた場合、JSX に書かれている属性と子要素を単一のオブジェクトとしてこのコンポーネントに渡します。このオブジェクトのことを “props” と呼びます。
Ubuntu 20.04でCommand line toolsのダウンロードからAndroidエミュレーターを動かすまで

## はじめに

Android Studio経由の説明が多いので、Command line toolsのダウンロードからAndroidエミュレーターを動かすまでの手順を残しておく。

## 環境変数ANDROID_SDK_ROOTの設定

Command line toolsはじめ、sdkをインストールするフォルダのルートをANDROID_SDK_ROOTとして環境変数に設定する。

例えば、/home/user/android/sdkを環境変数に設定する場合は、以下の通り。
~/.bashrcに書いておく。

```bash
$ export ANDROID_SDK_ROOT=/home/user/android/sdk
```

## javaのインストール

aptコマンドを使って、openjdkをインストールする。今回はopenjdk-17を使用した。
あとはPATHを通しておく。

```bash
JAVA_HOME="/usr/lib/jvm/java-1.17.0-openjdk-amd64"
```

## Command line toolsのダウンロード

以下からCommand line toolsの最新版をダウンロードする。

https://developer.android.com/studio?hl=ja#command-tools

## Command line toolsのインストール

ダウンロードしたzipファイルを展開する。
展開したフォルダ名はtoolsフォルダとして以下のよう配置にする必要がある。

```
$ANDROID_SDK_ROOT
└── cmdline-tools
   └── tools
```

## sdkmanagerによるパッケージのインストール

$ANDROID_SDK_ROOT/cmdline-tools/tools/binにあるsdkmanagerを使用してパッケージをインストールする。

エミュレータを動かすためにインストールしたパッケージは以下の通り。

- emulator
- build-tools;*
- platform-tools
- platforms;*
- system-images;* 

```bash
$ ./sdkmanager --install "<package name>"
```

sdkmanagerコマンドの詳細は以下。

https://developer.android.com/studio/command-line/sdkmanager?hl=ja

## avdの生成

エミュレーターで動かす仮想イメージ(avd)を生成するため、$ANDROID_SDK_ROOT/cmdline-tools/tools/binにあるavdmanagerを使用する。
今回の例では細かなオプションの指定は省略。

```bash
$ ./avdmanager create avd -n "<avd name>" -p "<system-images name>"
```

avdmanagerコマンドの詳細は以下。

https://developer.android.com/studio/command-line/avdmanager?hl=ja

## エミュレーターの実行

$ANDROID_SDK_ROOT/emulatorにあるemulatorでエミュレーターを実行する。

```bash
$ ./emulator @<avd name>
```

emulatorコマンドの詳細は以下。

https://developer.android.com/studio/run/emulator-commandline?hl=ja

kvmの実行権限がない等々のエラーが出力される場合は、出力内容を参照してエラーを解消する。(kvmグループにuserを追加して再起動)

## 参考情報

Android Studioからエミュレーターを起動する際の情報は公式で。

https://developer.android.com/studio/run/emulator?hl=ja
ユニットテストのメソッドのメモ

|	メソッド	|	説明	|
|	:--	|	:--	|
|	assert(式 [, メッセージ])	|	式が真ならば成功	|
|	assert_equal(変数1, 変数2 [, メッセージ])	|	変数1と変数2が等しければ成功	|
|	assert_not_equal(変数1, 変数2 [, メッセージ])	|	変数1と変数2が等しくなければ成功	|
|	assert_nil(変数 [, メッセージ])	|	変数がnilならば成功	|
|	assert_not_nil(変数 [, メッセージ])	|	変数がnilじゃなければ成功	|
|	assert_match(正規表現, 文字列 [, メッセージ])	|	正規表現に文字列がマッチすれば成功	|
|	assert_no_match(正規表現, 文字列 [, メッセージ])	|	正規表現に文字列がマッチしなければ成功	|
|	assert_raise(例外1, 例外2 [, 例外3…]) { }	|	ブロックを実行して例外1,2が発生し、その例外がexpected_exception_klassクラスならば成功	|
|	assert_nothing_raised(例外1, 例外2 [, 例外3…]) { .. }	|	ブロックを実行して例外1,2がおきなけらば成功	|
|	assert_in_delta(expected_float, actual_float, delta, message=””)	|		|
|	flunk([メッセージ])	|	常に失敗。未定義のテストケースなどを暫定的に失敗させたりする場合に利用	|
|	assert_difference(expressions, difference = 1, message = nil, 6block)	|	ブロック実行後にexpressionsの値がdifferenceの分だけ変わっていれば成功	|
|	assert_no_difference(expressions, message = nil, &block)	|	ブロック実行前後でexpressionsの値が変わっていなければ成功	|


参照：[ユニットテストで使うメソッド](https://railsdoc.com/page/method_unit_test)
Datadog の GitHub Apps Integration を有効化する


## はじめに

- Datadog の Continuous Integration Visibility (CI Visibility) を有効化するため GitHub Apps Integration の設定を行った際の手順を記載します
- 記事途中にも記載していますが現在ベータ版のため変更となっている場合もあります

### 設定に用いたアカウント種別

- Datadog
  - Free Plan
- GitHub
  - Personal Account

GitHub は Personal Account と Organization によって設定手順が若干異なるようです。

## Github Apps Integration の有効化手順

:::note warn
ベータ版の機能のため変更になっている場合もあります
:::

### Datadog の Integration 設定を開く

[APIs (Integrations) | Datadog](https://app.datadoghq.com/account/settings#integrations)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55950/d771b325-b4a5-451e-ce3e-3b8537eb1ee4.png)

検索フォームに "GitHub Apps" と入力し検索結果に表示される "GitHub Apps" を選択します

### GitHub App を作成する

`+ Link GitHub Account` をクリックします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55950/29910f99-720b-9573-57b0-023a45700c5b.png)

Configure で Organization か Personal Account を選択します
この後のステップで作成する GitHub Apps が切り替わるようです

また、有効にする権限を選択します。
今回は、検証のためすべての権限に `Read` 権限を付与しました

準備が整ったら "Create App in GitHub" をクリックします
クリックすると GitHub に遷移し GitHub Apps を作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55950/a18414f7-046a-e4e3-b407-60c2e04a5c5b.png)

Datadog と GitHub を連携する App 名を入力します
App 名を入力したら "Create GitHub App for YOUR_USER_NAME" をクリックします

![github.com_settings_apps_manifest(Nest Hub).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55950/b0709bc7-a097-02f3-5436-64c312c2eb10.png)

作成が終わったら Datadog に戻ります

### GitHub Apps Integration を有効化する

Datadog 側に戻ると GitHub Apps Integration を有効化する画面に切り替わっています
先ほど作成した GitHub App と連携するために "Install GitHub App" をクリックします

クリックすると 先ほど作成した GitHub App との連携画面に遷移します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55950/8ab54464-b615-2209-74bd-ed02d7853f31.png)

すべてのレポジトリか、必要なレポジトリを選択し "Install & Authorize" をクリックします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55950/77013970-680b-6432-db28-cfb490f00adf.png)

連携が成功すると Datadog 側の設定が切り替わり以下のような画面となります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55950/9c116585-3eb1-5f17-144c-1a55d863c255.png)

## 最後に

GitHub Apps も Datadog 側で定義してもらえるため連携自体は簡単に行うことができました、

今回 GitHub Apps Integration を有効化した理由は Continuous Integration Visibility (CI Visibility) を有効化するためでした。
Continuous Integration Visibility (CI Visibility) については別記事で記載します。

## Reference

https://docs.datadoghq.com/integrations/github_apps/

※ ドキュメントは英語のみの提供です
【個人的メモ】 EC2からSageMakerを扱う

# EC2(Linux) controls SageMaker instances
 - AWSのEC2インスタンスからSageMakerを操作して無駄遣い防止などをするためのメモ
 - シェルスクリプト作るときの参考用

###  前提
 - AWS Cli(v2) がLinux上にインストールされていること
 - aws configureでアクセスキーなどが設定済みであること

### 基本
```
$ aws sagemaker <サブコマンド> <パラメータ>
```

### サブコマンド一覧を表示(ヘルプ)
```
$ aws sagemaker help
```

### インスタンスの状態を確認する(json)
```
$ aws sagemaker list-notebook-instances
```
 - 下記形式のjsonを得られる  

```
{
    "NotebookInstances": [
        {
            "NotebookInstanceName": "<インスタンス名>",
            "NotebookInstanceArn": "arn:aws:sagemaker:<リージョン>:<XXXXXXXXXX>:notebook-instance/<インスタンス名？>",
            "NotebookInstanceStatus": "<状態(Pending等)>",
            "Url": "<インスタンス名>-<ランダム値？>.<リージョン>.sagemaker.aws",
            "InstanceType": "<インスタンスのタイプ(ml.t2.medium等)>",
            "CreationTime": "20XX-XX-XXT00:00:00.000000+09:00",
            "LastModifiedTime": "20XX-XX-XXT00:00:00.000000+09:00",
            "NotebookInstanceLifecycleConfigName": "<ライフサイクル設定名>"
        }
    ]
}
```

### インスタンス起動
```
$ aws sagemaker start-notebook-instance --notebook-instance-name <インスタンス名>
```
 - 終了コード：<0:正常><0以外:失敗>

### インスタンス停止
```
$ aws sagemaker stop-notebook-instance --notebook-instance-name <インスタンス名>
```
 - 終了コード：<0:正常><0以外:失敗>  

-----
### 参考
[sagemaker — AWS CLI 2.4.18 Command Reference](https://awscli.amazonaws.com/v2/documentation/api/2.4.18/reference/sagemaker/index.html#cli-aws-sagemaker)
【Flutter】permission_handlerでios固有のモーダルが表示されない

permission_handlerを使用すると、OS固有の権限許可モーダルを任意のタイミングで表示することができますが、今回iosにてカメラの許可モーダルを表示することができない事象が発生したので、解決策を備忘録として残しておきます。


``` dart
// permission_handlerを使用すると、下記で権限許可モーダルを任意の場所に呼び出すことができます。
await Permission.camera.request()
```

⬇︎これです

![permission.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2466417/824acfae-d38f-87ce-c09f-f9879ca65c4d.jpeg)

### 結論

Podfileを下記のように編集する。

デフォルトの下記を

```perl
post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)
  end
end
```

次のように変更する。

```perl
post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)
# ここから
    target.build_configurations.each do |config|
      config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
        '$(inherited)',
        'PERMISSION_CAMERA=1', 　# ⇦ここに追加したい権限書く
      ]
    end
# ここまで
  end
end
```

## その他の権限について

```
        ## dart: PermissionGroup.calendar
        # 'PERMISSION_EVENTS=1',

        ## dart: PermissionGroup.reminders
        # 'PERMISSION_REMINDERS=1',

        ## dart: PermissionGroup.contacts
        # 'PERMISSION_CONTACTS=1',

        ## dart: PermissionGroup.microphone
        # 'PERMISSION_MICROPHONE=1',

        ## dart: PermissionGroup.speech
        # 'PERMISSION_SPEECH_RECOGNIZER=1',

        ## dart: PermissionGroup.photos
        # 'PERMISSION_PHOTOS=1',

        ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse]
        # 'PERMISSION_LOCATION=1',

        ## dart: PermissionGroup.notification
        # 'PERMISSION_NOTIFICATIONS=1',

        ## dart: PermissionGroup.mediaLibrary
        # 'PERMISSION_MEDIA_LIBRARY=1',

        ## dart: PermissionGroup.sensors
        # 'PERMISSION_SENSORS=1',

        ## dart: PermissionGroup.bluetooth
        # 'PERMISSION_BLUETOOTH=1',

        ## dart: PermissionGroup.appTrackingTransparency
        # 'PERMISSION_APP_TRACKING_TRANSPARENCY=1',

        ## dart: PermissionGroup.criticalAlerts
        # 'PERMISSION_CRITICAL_ALERTS=1'

```

## 参考

https://pub.dev/packages/permission_handler

https://github.com/Baseflow/flutter-permission-handler/issues/588
100日でSQLの達人になる@LeetCode! Day13 <not in (select文)>

## 183. Customers Who Never Order （問題レベル: Easy）課金不要
今日の問題はこれ。
今まで発注の無い顧客名をリストアップするという問題。

基本的な問題であったが
`NOT IN`の使い方をきっちり覚えておらず、`!=`を使うのと混同してしまった。

ポイントは`NOT IN (SELECT文)`。
`NOT IN`が比較しているのは一つの値ではなく、テーブル内の全ての値！

追記：実はこれはDay8と同じポイントになります。まぁ重要ですし、復習なのでそのままにしておきます！
* [LeetCode](https://leetcode.com/)の問題は、`MS SQL Server`で解いています。
会話の中でよく登場するモデル・フレームワーク

# はじめに
会話の中でよく登場するモデル・フレームワークが説明されている資料や記事をまとめておく。
今後、誰かに説明するときに便利なようにまとめておく。
必要に応じて、随時追加していく。

# よく使うモデル・フレームワーク
## 品質モデル（品質特性）
### ISO/IEC 9126-1
https://www.meti.go.jp/policy/it_policy/softseibi/metrics/product_metrics.pdf

### ISO/IEC 25010 
https://www.ipa.go.jp/archive/files/000065855.pdf

https://www.ipa.go.jp/archive/files/000065866.pdf


## 狩野モデル
https://www.juse.or.jp/faq_knowledge/knowledge/index.html#

## SECIモデル
https://coach.co.jp/interview/20200121.html

## GQM
https://www.slideshare.net/hironoriwashizaki/gqm20130912

## PDCA
https://www.juse.or.jp/solution/point02/03.html

http://www.juse.or.jp/upload/files/mailnews/BC/BC%20News_13.pdf

以下は、狩野紀昭氏のコメント
> 企業の実務において重要かどうかの基準は、「お客に役立つ」「お金になる」だと思います。どんなに立派な P あるいは C であっても、それだけでは、「お客の役に立たないし、お金にもなりません。」しかし、D だけでは、「十分にお客の役に立てない、あるいは、余り大きなお金は得られない」かもしれないが、「若干はお客の役に立ち、お金にもなります。」品質管理にしろ、生産管理にしろ、歴史的には、Do-Do-Do-…で来たのですが、それをもっと価値あるモノにしようとして P、C、A が導入されてきたのであり、P、D、C、A は対等ではなく、D が一番基本にあり、その D を有効で効率よくするために P、C、A があるのです。

## ふりかえりのフレームワーク

### KPT
http://objectclub.jp/download/files/pf/RetrospectiveMeetingGuide.pdf

### YWT
https://www.jmac.co.jp/glossary/2021/09/ywt.html
Install HashLink virtual machine for Haxe on Mac

↓English below↓

## 目的
Haxe言語のHashLink VMをインスとる仕方の優しいガイドです。

## 仕方

- Haxeをインストール: https://haxe.org/download/

- git cloneでgithubからHashLinkをダウンロードしてhttps://github.com/HaxeFoundation/hashlink

- 新しい作られた`hashlink`フォルダーに移動して、`brew bundle`を走行する

- brewのsymlinkが悪かったらbrewで修正する

- 同じフォルダーのなかに`make`、`sudo make codesign_osx`そして`make install`を走行する。

- `hl`を走行してみて、もし成功だったらこんなメッセージが現れる:

![Screen Shot 2022-02-14 at 00.16.08.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282576/68cacfe5-e50d-2005-6cd3-24d1ac44723e.jpeg)

`hl`がだめだったら、PATHにhashlinkが付いていないかもしれない。私の`hl`は`/usr/local/bin/hl`のなかにあります。

### English

## Purpose
This is just a simple guide to install the HashLink VM for the programming langauge Haxe. It's not too complicated but I've had some trouble with it whenever I've tried so I thought I'd just document how I did it.

## Process

- First install Haxe: https://haxe.org/download/

- Download HashLink from github: https://github.com/HaxeFoundation/hashlink : there is a guide there install hashlink as well. I used it to make this but just made some things more explicit. I used git clone for this.

- Enter the newly created hashlink folder and run `brew bundle`, which will install the packages from the brewfile in the hashlink folder.

- Check to make sure all packages have been installed, fix any symlinks which may be broken for the new packages

- In the same folder, run `make` then `sudo make codesign_osx` then `make install`

- Run `hl` to see if it has been successfully installed. If it has, you should get a message like this: 

![Screen Shot 2022-02-14 at 00.16.08.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282576/68cacfe5-e50d-2005-6cd3-24d1ac44723e.jpeg)

If you get a message like `command not found`, you may need to add hashlink to your PATH. My hl is located in `/usr/local/bin/hl` which was already in my PATH.
ruby -v でrbenvで指定したバージョンが表示されない時の対処法

## 実行環境
- macOS Monterey 12.2.1
- rbenv 1.2.0

## 事象
rbenvでローカルバージョンを指定したのにruby -vするとシステムのrubyバージョンが表示される。
```shell:ターミナル
$ rbenv local 2.7.5
$ ruby -v
ruby 2.6.8p205 (2021-07-07 revision 67951) [universal.x86_64-darwin21]
```
2.7.5になってない！なんで！？という状態です。

## 原因
**パスが通っていないことが多い。**

- rubyコマンドがどのディレクトリの実行ファイルを呼んでいるか確認してみましょう
```shell:ターミナル
which ruby
/usr/bin/ruby #←これ、macのRuby
```
rbenvのパスは`/Users/`**macのユーザ名**`/.rbenv/shims:`なので、
これのパスを通してやる必要があります。

ちなみにパスを通すというのは**PATHという環境変数にrbenvのプログラムが格納されているディレクトリを追加する**ことを言います。

- 現在のパスを確認してみましょう
```shell:ターミナル
echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
```
上記にrbenvのパスがないことが分かると思います。

## 対策
rbenvのパスを通すために、まずはご自分のmacでは何のシェルが使われているか確認してみましょう。
```shell:ターミナル
echo $SHELL
/bin/zsh
```

>macOS Catalina から、Mac は zsh をデフォルトのログインシェルおよびインタラクティブシェルとして使うようになります。
引用元：[zsh を Mac のデフォルトシェルとして使う](https://support.apple.com/ja-jp/HT208050)

.zshrcに以下を追記します。
(使用しているのがbashであれば.bash_profileに追記してください)
`echo eval "$(rbenv init -)" >> .zshrc`

シェルへの変更を反映します。
```shell:ターミナル
source ~./zshrc
```

再度、パスを確認してみます。
```shell:ターミナル
echo $PATH
/Users/**macのユーザ名**/.rbenv/shims:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
```
パスは左から優先して読み込まれます。
この場合、rbenvのパスが優先されることになります。


最後に、アプリのディレクトリに移動してRubyバージョンを確認してみます。
```shell:ターミナル
ruby -v
ruby 2.7.5p203 (2021-11-24 revision f69aeb8314) [x86_64-darwin21]
```

念の為、一個上の階層に移動してRubyのバージョンを確認してみます。
```shell:ターミナル
ruby -v
ruby 2.6.8p205 (2021-07-07 revision 67951) [universal.x86_64-darwin21]
```
ローカルバージョンも、グローバルバージョンも想定通りになりました。
macOSアプリのメニューバーアイコンのデザイン

## 追記(2024-12-17)

下記もわかりやすい記事で参考になります
[Designing macOS menu bar extras](https://bjango.com/articles/designingmenubarextras/)

>色は無視されるため、テンプレート画像アートワークは単色アイコンとして作成する必要があります。必要に応じて、さまざまなレベルの不透明度を使用して陰影を付けることができます。これは、音量や Wi-Fi の強度などの状態を示すためによく使用されます。Apple は通常、無効な要素を示すために 35% の不透明度を使用します。

---

## 概要
- 以下のようにメニューバーアイコンを作って表示してみる。

<img width="400" alt="image" src="https://i.imgur.com/gCEpooq.jpg">

- HIGによるとメニューバーアイコンにはテンプレートイメージを使う。
- つまり黒と透明度のみでデザインされた画像とすることが推奨。
    - [Menu Bar Extras](https://developer.apple.com/design/human-interface-guidelines/macos/extensions/menu-bar-extras/)
    > Use a template image to represent your menu bar extra. A template image discards color information and uses a mask to produce the appearance you see onscreen. Template images automatically adapt to the user’s appearance settings, so they look good on both dark and light menu bars, and when your menu bar extra is selected.
    - ライト/ダークモードで視認しやすい色で表示されるのが嬉しい。
    - Appleのものを見ると基本テンプレート画像なのでそれに調和させる。（Siriは多分例外）
    - [Providing Images for Different Appearances](https://developer.apple.com/documentation/uikit/uiimage/providing_images_for_different_appearances)
- 画像の高さは28pxとする。(公式な記載がないので私の感覚)

## GitHub
- [qiita\-menubar\-icon\-design](https://github.com/pommdau/qiita-menubar-icon-design)
    - イラストレータとXcodeのプロジェクトをそれぞれ配置。

## イラストレータでの画像の作成/出力
- 塗りには黒のみを使用。
- 不透明度の変更による表現は可能。

<img width="600" alt="image" src="https://i.imgur.com/7ubQpbT.jpg">

- 1x,2x,3x用にそれぞれ14,28,42pxで出力。

<img width="400" alt="image" src="https://i.imgur.com/gmR9qmW.jpg">

## Xcode
### Assetsの設定
- `Render As`で`Template Image`を選択。

<img width="800" alt="image" src="https://i.imgur.com/sn9L3KZ.jpg">

### 実装

- メニューバーにアイコンを表示するだけの実装。
- AppDelegateで`StatusBarIconController`のインスタンスをプロパティと持たせておく。
    - 実際の運用では`Notification`でアイコンを変更したいことがあるので。

```swift
import AppKit

class StatusBarIconController: NSObject {
    
    // MARK: - Properties
    
    private let systemStatusItem: NSStatusItem

    private var menubarIconStandard: NSImage {
        return NSImage(named:NSImage.Name("MenubarIcon"))!
    }
    
    // MARK: - LifeCycle
    
    override init() {
        systemStatusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
        super.init()
        systemStatusItem.button?.image = menubarIconStandard
    }
}
```

## テンプレート画像の反転した状態を確認
- `Accfessibility>Display`から`Reduce trasparency`でテンプレート画像の表示を変更でき、ライト/ダークモードの時の確認がそれぞれできる。

<img width="600" alt="image" src="https://i.imgur.com/DFn96dT.jpg">

<img width="400" alt="image" src="https://i.imgur.com/gCEpooq.jpg">

<img width="400" alt="image" src="https://i.imgur.com/Y6mLS1p.jpg">
【Golang】gqlgen、gin、GORMを使ったプロジェクトテンプレート

# はじめに

Goの学習のためgin、gqlgen、GORMを使ってGraphQLのAPIを作成しました。
備忘のためにプロジェクトのテンプレートとその説明を残します。

作成したテンプレートは以下に公開しています。

https://github.com/Ruketa/go-gqlgen-gin-template

# 環境
- Golang  バージョン 1.17
- 使用ライブラリ、FW
    - Gin : Web Framework : https://github.com/gin-gonic/gin
    - Gorm : ORM library : https://github.com/go-gorm/gorm
    - Gorm PostgreSQL Driver : https://github.com/go-gorm/postgres
    - INI : INI file package : https://pkg.go.dev/gopkg.in/ini.v1
    - gqlgen : GraphQL library : https://github.com/99designs/gqlgen
- 使用DB：PostgreSQL


# プロジェクト解説

## 構成

プロジェクトの構成は以下の通りです。

```
├─db
│  ├─db.go
│  └─dbconfig.ini
├─graph
│  ├─generated
│  │  └─generated.go
│  ├─model
│  │  ├─models_gen.go
│  │  └─todo.go
│  ├─resolver.go
│  ├─schema.graphqls
│  └─schema.resolvers.go
├─router
│  └─router.go
├─go.mod
├─gqlgen.yml
└─server.go
```

- db
  db関連のファイルを入れています。
  dbconfig.iniにDB接続設定を定義します。環境に合わせて編集します。
  postgreSQL以外を使用する場合はそれに合わせたドライバーをインストールします。
  db.goでgormでのDBオブジェクトの作成、DB接続、マイグレーションを行います。

- graph
  gqlgenの以下コマンドで自動作成されるgraphql関連の（model、shcema、resolver）の定義ファイル
  ```
  go run github.com/99designs/gqlgen init
  ```
  model、schema.resolvers.goあたりを修正していきます。

- router
  Ginを使ってルーティングを定義しています

- server.go
  プロジェクトのエントリーポイント。
　Webサーバ、DBの初期化、起動を行います。


## 使用方法

### 依存パッケージの読み込み
以下のコマンドを実行して依存パッケージを取り込みます。
```
go mod tidy
```
実行後は`go.sum`というファイルが出来ます。

### サーバ起動
```
go run server.go
```
サーバが起動します。
デフォルトでは`http://localhost:8000/query`でgraphQLでのリクエストを受け付けます。
何か適当にクライアントを用意してリクエストすると、Todoデータの作成、取得が行えます。

fetchAPIを使って確認したコードは以下の通りです。
- todoデータ作成
```javascript
fetch("http://localhost:8000/query",{
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    query: `
      mutation createTodo {
        createTodo(input: { text: "todo", userId: "2" }) {
          text
          done
          userId
        }
      }
     `
    })
  })
```

- todoデータ取得
```javascript
fetch("http://localhost:8000/query",{
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    query: `
      query findTodos {
          todos {
            text
            done
            userId
          }
        }
    `
  })
})
```
# おわりに

簡単ですが以上となります。
基本的にはgqlgenで初期化したプロジェクト構成をベースにして、gin,gormを導入したような構成になっています。
今後も何か改善したらレポジトリを更新していこうと思います。
Amazonで金額指定して、検索したい！！

Amazon で検索をかけるときに金額指定を行いたいのですが、何故かamazonの金額指定は、「0~1500」、「1500~10000」というざっくりした範囲しかありません。
なぜ、詳細な数字が指定できる便利機能が存在しないんだ！！！！！

ということで作成しましたww

# 作成したページとリンク
作成した内容（htmlファイル 40行分だけですがw）は以下の github でページを公開してあります。

https://nagajun1.github.io/amazon_product_search/

ページデザインはこんな感じ...というか、デザインにこだわらなかったため、これだけしかないですｗ
（画面は、修正前のものです。）
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/762492/f8ef473d-89a3-b937-983f-e441d6e4464d.png">

各項目を入力し、「検索」を押下すると、そのまま検索結果のページに飛ぶ仕様です。
例えば、商品名「紙」、金額上限「30000」、金額下限「20000」で検索すると、本当にその価格帯の「紙」が結果として出てきますW！
フィッシングが怖い！（フィッシングできる項目が、検索内容だけですがW）という方は、以下のコードで html ファイルを作成し、それをchromeで開いてください。

# コード
コードは、htmlとJavaScriptだけで完結しています。
ロジックとしては、amazon の URL にパラメータとして、`low-price`と`high-price`を設定して検索を行えば、今回実装したことと同じことができます。
本来は、URLの書き換えで行える内容なのですが、今回は、その作業を JavaScript で行える様な処理を作成しました。
github でページを公開するためにコードを上げる必要があったので、下記がそのリポジトリとなります。（index.html しかないですがw）

https://github.com/NagaJun1/amazon_product_search

ソースコードは、以下の通りです。

```index.html
<html lang="ja">

<head>
    <title>Amazon検索 金額指定</title>
</head>

<body>
    <h1>Amazon検索 金額指定</h1>
    <label>商品名</br></label>
    <input type="text" id="product_name" value="">
    <label style="background-color:red"></br>金額上限</br></label>
    <input type="text" id="high_price" value="">
    <label style="background-color:skyblue"></br>金額下限</br></label>
    <input type="text" id="low_price" value="">
    <div></br></div>
    <input type="button" id="btn_execute" value="検索" onclick="openAmazon()">
    <script>
        /** amazonへの画面遷移実行 */
        function openAmazon() {
            // amazon のURL
            let amazonUrl = 'https://www.amazon.co.jp/s?';

            // 商品名の設定
            amazonUrl += "k=" + document.getElementById("product_name").value;

            // 下限金額の設定
            let low_price = document.getElementById("low_price").value;
            amazonUrl += "&low-price=" + low_price;

            // 上限金額の設定
            let high_price = document.getElementById("high_price").value;
            amazonUrl += "&high-price=" + high_price;
            if (Number(low_price) < Number(high_price)) {
                // 画面遷移処理
                window.location.href = amazonUrl;
            } else {
                alert("価格設定が、検索可能な状態にありません！");
            }
        }
    </script>
</body>

</html>
```

# 終わりに
今回の本筋と話が変わりますが、フィッシング詐欺には注意しましょう！！
（amazonは何処へ...）

# 補足
・今回のロジックは URL で金額を指定しているため、スマホアプリだと、金額指定ができません！（なんでだよ！）
・上限金額が下限金額を下回っていると、amazon で検索条件が無効化されます。
AWSロードマップ(EC2 Auto Scaling)

#目次
[1.はじめに](#1-はじめに)
[2.用語](#2-用語)
[3.ドローンでクラウドを利用](#3-ドローンでクラウドを利用)

# 1.はじめに
ドローン✖︎クラウドの記事をよく見るけど、どうゆう仕組みで連携してるのか分からなかったので
[AWSロードマップ](https://qiita.com/KurokawaKouhei/items/4e9aa3b526f3f233bf85 "Qiita Home")で勉強をしたいと思います！
(まずはざっくり覚えて徐々に深堀していく、仕事でAWS少し触ったぐらい)

#### EC2 Auto Scalingとは
- 忙しくなってきたでーって通知が来たら、あらかじめ設定してた値に合わせて自動でリソースを追加
- 落ち着いてきたらリソースを自動で減らす

# 2. 用語
![スクリーンショット 2022-03-05 11.48.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2181084/28ffd13d-4ae0-b232-1a1e-2e1a05b1e237.png)


#### Launch Templates
- インスタンスの情報を決めてテンプレートを作成できる
    - それ以降はテンプレートから作成する事によって、手間を少し減らせる

#### Launch configuration
- Auto Scaling においてどのようなインスタンスを起動するかという設定

#### クールダウン期間
- Auto Scalingが連続で実行されないようにするために、新しいインスタンスの処理が開始されるまでの待ち時間

#### オートスケーリンググループ
- EC2のまとまりを作れる(最小(1)/最大(4)/希望(2)台数を指定して作成)
    - 最初は2台で起動し、スケーリングポリシーと負荷状況によって1-4の間で柔軟に変化する

#### オートスケーリングポリシー
- CPU使用率を50%にして設定すると、オートスケーリングがEC2インスタンスを調整して40%くらいに維持するとか
- CPU使用率が50%~60%の場合、2つのインスタンスを追加し、60%を超えると4つのインスタンスを追加するとか

# 3. ドローンでクラウドを利用
EC2 Auto Scalingをドローンに絡めてみると、
- 災害時にリソースを増やしてドローンカメラの映像をリアルタイムで監視。
- 物流で配送数が多い/少ない場合に合わせてリソースを柔軟に調整。
ドローンでクラウド利用時は、状況に合わせてリソースを増やしたり減らしたりを出来た方が無駄が少ないんかなと思う！
AWS；請求アラームの作成手順

- AWS の予想請求額が指定した閾値を超過したときに通知を送信するアラームを作成
    - アラームの作成手順が昨年から変更となっていたため覚書として記録
- 現状、東京リージョンでは設定できない？
- 動作未確認

（以下編集中）

# 1. 請求アラートの有効化
アラーム作成前の前提条件として、請求アラートを有効化しておく必要がある。

(1) 検索窓に「Billing」と入力し、AWS Billing Dashboarへ遷移
(2) ナビゲーションペインの「設定」-「請求設定」より
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2010632/0816881e-4d1a-d339-550a-0d6015113f29.png)


# 2. アラームの作成
(1) CloudWatchのダッシュボードにて、
(2) ナビゲーションペイン「アラーム」-「請求」より
 　 ※ 東京リージョンでは請求メトリクスが表示されなかったため、バージニアリージョンで実行
>（ CloudWatchのユーザーガイドより抜粋 ）
必要に応じて、リージョンを米国東部 (バージニア) に変更します。請求メトリクスデータは、このリージョンに保存され、世界全体の請求額を示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2010632/7fb2caa4-9a79-89f3-f851-1a4c32f64a24.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2010632/81b35129-1406-6f4d-acd2-fbb746593d3e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2010632/b712b8b7-c489-9079-d8a9-cbdee1ade2aa.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2010632/a4045d3b-07e0-e5b6-70d1-bec80653b866.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2010632/a6d417fa-352d-5794-e81d-34fd7a4b8afb.png)
- ダッシュボードにて作成したアラームと、その状態が「OK」となったことを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2010632/a5b0512c-2ff4-513f-dc42-b1d9518668f1.png)
- Amazon SNS のダッシュボードから、トピックが追加されていることが確認できる
- トピック作成時に指定したEメールアドレス宛て、「AWS Notifications」というタイトルで確認メールが届いているはずなので、「Confirm subscription」をクリック
    - なぜか迷惑メールにフィルタリングされていた
- ブラウザで成功の旨のメッセージを確認できたら、サブスクリプションのステータスが「保留中の確認」から「確認済み」へと変化する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2010632/c33b3f8b-f461-a74f-37c0-4d78604a7cca.png)
エンジニアの皆さんに技術記事を書くときに心がけてほしいこと

[yamaday0u](https://twitter.com/yamaday0u)です。
※2022年から技術系の記事は[個人ブログ](https://yamaday0u.net/category/programmer/)に投稿しております。ぜひこちらもご覧ください→[yamaday0u Blog](https://yamaday0u.net/category/programmer/)

今回は技術的な話ではなく、Qiitaなどで技術記事を書くときに皆さんにお願いしたいことについて書きます。

## What

技術記事を書くときに皆さんにお願いしたいこと。
それは
**参考資料を掲載すること**と、
なるべく**公式ドキュメントを載せること**です。

## Why
参考資料を載せてほしい理由は、記事を読んだ人に自走力をつけてもらうよう促すためです。

公式ドキュメントを載せれば、公式ドキュメントを参照する意識を醸成したり、ドキュメントの読み方まで伝授できます。

原典や一次情報から情報を知ることは正しい知識をつける上で非常に重要です。

**正しい知識は問題解決のときに活かせる汎用性のある知恵になります。**

ぼく自身、いろんな方の技術記事を読んで、自分の問題解決に活かしていますが、その方が参考にしたサイトを何も載せていないと、「この人は何を読んでこの解決法に至ったんだろう？」と惜しい気持ちになります。

また同じ問題で詰まったとき、その人の記事だけが頼りになってしまいますし、時間が経てば記事の情報が古くなって使えなくなってしまいます。

参考にした公式ドキュメントのリンクが掲載されていれば、公式ドキュメントの情報が更新されている可能性が高いので、問題解決がしやすくなります。

手前味噌ですが、ぼくがQiitaで記事を書くときは必ず参考にしたサイトのリンクを最後に載せています。
例えば以下の記事で下の写真のように参考資料として、記事を書くときに参考にしたサイトの一覧を記載しています。


https://qiita.com/yamaday0u/items/ee8acb35709bcc8c7fc7


![スクリーンショット 2022-03-05 22.22.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/849306/790f147f-32d5-6285-6c5d-e7600aadaa7d.png)


こんな感じで参考資料を技術記事で掲載してくれる方が増えると、ぼく自身の学習も捗るので、ぜひ心がけてくれると嬉しいです。
LibreElecの文字を大きくする

## これは何の話？

転がってたラズパイを
実家に転がってたプロジェクター (黄色端子) に繋いだら
文字が潰れて読めなかったのをどうにかした時のメモです。

## 方針：スキンを改変する

デフォルトの`estuary`をadd-onとしてコピーして、設定ファイルを編集します。
今回は、`bigestuary`と名付けました。

### スキンをコピーする  

```bash
cp -r /usr/share/kodi/addons/skin.estuary ~/.kodi/addons/skin.bigestuary2
```
デフォルトスキンのディレクトリは編集権限がないので、
add-onディレクトリにコピーして設定ファイルを編集します。

この時、ディレクトリ名を変更しておく必要があります。

### コピーしたスキンの名称を変える

変更箇所は2つ
- ディレクトリ名
- コピーしたディレクトリ直下の`addons.xml`
    - `id=`の部分
    - `name=`の部分

```~/.kodi/addons/skin.bigestuary/addons.xml
<addon id="skin.bigestuary" version="2.0.27" name="bigestuary" provider-name="phil65, Ichabod Fletchman">
```

### Fontのサイズを書き換える
コピーしたフォルダ内の`./xml/Fonts.xml`にある`<size>99</size>`を変更するとフォントサイズが変わります。

私は一律に`+10`にしました。

後のスキン設定でフォントに`Arial`を指定するので、
後半の`<fontset id="Arial" idloc="31053">`から下の変更でOKです。

### add-onsメニューから有効化する
Kodiの画面上にて
1. `歯車`アイコン
1. `Add-ons`
1. `All`
1. `My add-ons`
1. `bigestuary`(自分で付けた名前)
1. `Auto-update`をオフ
1. `Enable`
1. `Use`

### フォントを変える

Kodiの画面上にて
1. `歯車`アイコン
1. `Interface`
1. `Skin`
1. `Fonts`
1. `Arial based`
簡単！FlexBoxで作るトグルボタン

トグルボタンと言うのは次のようなやつです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680862/070b0904-e8ef-8e90-7ac2-e3132a227dee.png)
クリックすると、中の白い丸が左右に動きます。ﾋｭｯﾋｭｯ！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680862/30c8a783-67f9-28f8-3f9b-1cf7071b3512.png)
こいつをさっくり作る方法を考えてみます。
# FlexBoxの中にdivを三つ並べる
```html
<div id="container" class="container">
  <div id="left"></div>
  <div class="switch"></div>
  <div id="right"></div>
</div>
```
真ん中のclass="switch"のやつがﾋｭﾝﾋｭﾝ動く白い丸になります。
それっぽくスタイルを整えてみます。
```css
.container {
  border-radius: 9999px;
  background-color: gray;
  width: 45px;
  display: flex;
  margin: 5px;
  padding: 1.5px;
}
.switch{
  background-color: white;
  height: 15px;
  width: 15px;
  border-radius: 9999px;
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680862/6cd88078-25af-812c-5be7-b4c56ce02237.png)
見た目はそれっぽくなりました。
しかし、もちろん現時点ではクリックしても動きません。
こいつを左右に動かすにはどうしたらいいでしょう？
# 左右のdivの幅をflexで変える
勘のいい方は既にお気づきの通り、左右の空divがキーとなります。
たとえば白い丸を右に動かしたければ、

- 左の空divの幅をいっぱいに広げる
- 右の空divの幅をゼロにする

という手順により達成できます。
左に動かしたければ左右を逆にすればいいだけです。
「幅をいっぱいに広げる」「幅をゼロにする」作業は、flexで実装可能です。
```css
//幅がゼロ
.close{
  flex: none;
}
//幅がいっぱい
.open{
  flex: auto;
}
```
あとは「コンテナをクリックすると、左右の空divのクラスが切り替わる」という仕組みを作るだけです。
ReactやVueなら秒で実装できますが、ここはvanilla JSでやってみましょう。
# JavaScriptでイベントリスナをくっつける

```js
//コンテナと左右の空divを拾う
const container = document.getElementById("container");
const left = document.getElementById("left");
const right = document.getElementById("right");

//要素を受け取り、open/closeクラスを逆にする関数
const toggleIsOpen = (el) => {
  const isOpen = el.classList.contains("open");
  if (isOpen) {
    el.classList.remove("open");
    el.classList.add("close");
  } else {
    el.classList.remove("close");
    el.classList.add("open");
  }
};

//上記関数を使い左右の空divのopen/closeクラスを書き換える
const switchButton = () => {
  toggleIsOpen(left);
  toggleIsOpen(right);
};
//コンテナをクリックしたらその関数を実行する
container.addEventListener("click", switchButton, false);
```
# open/closeの初期クラスを加える
上記のJavaScriptは、「対象エレメントのクラスリストにopenがあればそれをcloseに書き換える」「closeがあればopenに書き換える」という仕組みなので、openクラスとcloseクラスを左右の空divに付け加える必要があります。
```html
<div id="container" class="container">
  <div id="left" class="close"></div>
  <div class="switch">
  </div>
  <div id="right" class="open">
  </div>
</div>
```
# アニメーションを付ける
左右の空divに``transition-duration``を付ければ、一瞬で切り替わらずにﾋｭｯﾋｭｯと動かすことができます。
私はスピード感のあるアニメーションが好きなので、0.1秒でﾋｭｯ!!!と切り替わるように設定します。
```css
.space{
  transition-duration: 100ms;
}
```
左右の空divに上記クラスを書き加えれば、アニメーションが実装できます。

```html
<div id="container" class="container">
  <div id="left" class="close space"></div>
  <div class="switch">
  </div>
  <div id="right" class="open space">
  </div>
</div>
```
これで完成。
**ね、簡単でしょ？**

# Codepen
https://codepen.io/skipeverylunch/pen/WNXmroJ?editors=1111

# 参考
[Applying transition on flexbox justify-content property -StackOverFlow](https://stackoverflow.com/questions/39080958/applying-transition-on-flexbox-justify-content-property)
Qiita初投稿！

## 初投稿

はじめまして！　webエンジニア目指して日々勉強しております！

日々学習していて、知識のアウトプットが足りていないと思いこれから色々な記事を投稿していきたいと思います！

間違った知識があった場合はご教授頂けると幸いです！
OSSECエージェントとOSSECマネージャーの通信について

# はじめに
OSSECエージェントとOSSECマネージャーの通信について記事にしました。

# 構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321513/b952e8d0-806d-7503-cc7d-9bdf70ec7583.png)


# OSSECサーバーのポート番号について
エージェントとOSSECサーバー間の通信は、一般的にセキュアモードではポート1514/udpで行われます。ossec-remotedでsyslogモードを使用する場合、ポート514がデフォルトとなります（UDPとTCPの両方がサポートされています）。これらのポートは、ossec.conf の remote セクションで設定可能である。

一般的には、syslogよりもセキュアな接続方式が好まれます。また、ossec-remoted の syslog サポートの代わりに、外部の syslog デーモン (rsyslog や syslog-ng など) を使用することも可能です。

# おわりに
今回の記事は以上です。では、また。
【Project Euler】Problem 93: 四則演算で連続数

* 本記事は[ProjectEuler](https://projecteuler.net/about)の「100番以下の問題の説明は記載可能」という規定に基づいて回答のヒントが書かれていますので、自分である程度考えてみてから読まれることをお勧めします。

### 問題 93.四則演算で連続数

原文 [Problem 93: Arithmetic expressions](https://projecteuler.net/problem=93)

**問題の要約: 4つの数字を使って四則演算を行った結果を1から順番に並べたとき、最も連続が長く続くような4つの数字を求めよ**

いわゆる[テンパズル(Wikipedia)](https://ja.wikipedia.org/wiki/%E3%83%86%E3%83%B3%E3%83%91%E3%82%BA%E3%83%AB)で10だけでなく、1から順番に数を一番連続で作れる4つの数字はどれかという問題です。

この手の問題はカッコとかがあると扱いがややこしいので[逆ポーランド記法(Wikipedia)](https://ja.wikipedia.org/wiki/%E9%80%86%E3%83%9D%E3%83%BC%E3%83%A9%E3%83%B3%E3%83%89%E8%A8%98%E6%B3%95)を使うと簡略化できます。以下のように考えます。

1. 数字は4個、演算子は3個ある
1. スタックに数字をプッシュしていく
1. スタックに数字が2つ以上あったら演算子を適用して、上の2つをポップして演算してスタックに返す
1. 2.か3．を繰り返して、残りの数字と演算子がなくなったらスタックに残った数字が答。
1. この答えが自然数だったら重複を除くためにsetに入れていく。

これを再帰関数でで実装したのが**revPol**です。引数に(スタック, 残りの数字のリスト, 残りの演算子の数)を渡します。

```python 
from operator import add, sub, truediv, mul
from copy import copy
opefunc = dict({'*':mul,'/':truediv, '+':add, '-':sub})

def isNnum(n): # return True if n is natural number
  return int(n) == n and n > 0

 # Reverse Polish: stack, remaining numbers, remaining operator count
def revPol(stk, nlist, on):  
  if len(stk) == 1 and len(nlist) == 0 and on == 0:  # calcuration complete 
    if isNnum(stk[0]):          # if natural number
      ansSet.add(int(stk[0]))   # add to answer set 
    return
  ## ----- use an operator ------
  if len(stk) >= 2 and on > 0:
    stk1 = copy(stk)
    a2, a1 = stk1.pop(), stk1.pop()
    for o1 in list(opefunc.keys()):       # for all operators
      if o1 == '/' and a2 == 0: continue  # avoid zero devide
      revPol(copy(stk1)+[opefunc[o1](a1, a2)], nlist, on-1)
  ## ----- use an number -----
  if len(nlist) > 0:
    revPol(copy(stk)+[nlist[0]], copy(nlist)[1:], on) # push number to stack and remove from nlist
  return

ansSet = set()
revPol([], [1,2,3,4], 3)  # stack, numbers, #of operand
print(ansSet)
# {1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 13, 14, 15, 20, 21, 24, 25, 28, 36}
```
これは[1,2,3,4]をその順番で使った場合なので、これを順列すべてについての結果の和集合を取り、１からの連続する個数をチェックするのが次の**contNums**です。ここで[1,2,3,4]からは28まで連続することが確認できました。

```Python
def contNums(nn):
  ansSet.clear()     # clear answer set
  for nlist in permutations(nn,4):  # for all permutations
    revPol([], list(nlist), 3)      # collect result numbers to ansSet
  for i in count(1): # check 1-n continues numbers in the set 
    if i not in ansSet: break
  return (i-1)
print(contNums([1,2,3,4]))
# 28
```

後は4つの数字の組み合わせを1から9の中から選んで一番長く連続する組み合わせを探せば良いことになります。

```python 
digit = range(1,10)
cmax, cmaxNL, ansSet = 0, [], set()
for nn in combinations(digit,4):
  cont  = contNums(nn)
  if cont > cmax: 
    cmax, cmaxNL = cont,  "".join(map(str,nn))

print(f"Answer = {cmaxNL} (continued up to {cmax}).")
```
（開発環境：Google Colab）
ケバブケース・キャメルケース・スネークケース

# ケバブケース
単語同士を-(ハイフン)で繋げる
first-time
単語が肉、ハイフンが串でケバブのように見えるからケバブケース
ただし、一般的なプログラミング言語では使われない。ハイフンは四足演算の引くを表すためエラーが発生する恐れがあるため

# キャメルケース
後の単語の先頭を大文字にして繋げる
firstTime
FirstTiem
小文字と大文字で凸凹してる様がまるでラクダ(camel)のようだからキャメルケース

# スネークケース
単語同士を_(アンダースコア)で繋ぐ
first_time
_がまるで地を這う蛇のようだからスネークケース


参照

https://wa3.i-3-i.info/word16380.html
mmapの引数int protについて

## 背景
Linuxのシステムコールmmapを使うときの３番目の引数protを実際の数値で指定するときに困りました。glibcのソースコードに定義が書いてあるかと思っていましたが見当たらない（これは自分の探しが足りない可能性がある）ので自分のメモ用のためにもここに書くことにしました。

## フラグの具体値（10進数）
PROT_EXEC = 4
PROT_READ = 1
PROT_WRITE = 2
PROT_NONE = 0

## 実際に値で指定するとき
フラグを指定するときはPROT_NONEを指定するかそれ以外のフラグのビット毎の論理和を指定するとありました。フラグはすべて２の累乗数ですから、フラグの値の10進数の和を指定するだけで十分だとわかりました。
【C】初めてのC言語（1. Hello world）

# はじめに

これまでに業務でJavaやC#は使ってきたけれども、C言語は全く使ったことがありません。
職場には「C言語を知らずにプログラマーを名乗るな」と言う方も居るので、一念発起してC言語を勉強してみることにしました。

# 学習環境

* 今回は[paiza.io](https://paiza.io/ja/projects/new)のC言語のエディタを使いました。

# サンプルコード

## Hello world

* 何はともあれ、最初は`Hello world`ということで書いてみました。
* 最初の行の`#include <stdio.h>`では、標準入出力の関数を呼び出すための記述です。
  * `#include <stdio.h>`を付けることで、3行目の`printf`関数が呼び出せるようになるそうです。
  * Javaだとライブラリを特に読み込まなくても標準入出力を使えたので、C言語とは大きな違いを感じました。
* main関数は必ず1つ存在する。
  * これはJavaのmainメソッドと同じですね。
* main関数の引数が無い場合、誤って引数を付けてしまうことが無いように明示的に`void`を書いた方が良い。[参考URL](https://qiita.com/fuwasegu/items/8893b2b8a7f05c67482a#comment-527b98551afc53fb47f2)
  * Javaの場合は引数が無ければカッコ内は空欄になるので、この辺りも大きく異なる点ですね。

```c:Main.c
#include <stdio.h>
main(void){
    printf("Hello,world!");
}
```

## コメントと戻り値

* 単一行のコメントは「\/\/」、複数行のコメントは「\/* ... *\/」で表現します。
  * コメントの書き方はJavaと全く同じ。
* 戻り値がint型なので、とりあえず0を返す。
  * Hello worldのサンプルコードだと、こんな感じのコードが多いかもしれません。

```c:Main.c
#include <stdio.h>
int main(void){
    // コメントです
    printf("Hello,world!");
    /*
    戻り値がint型なので
    ここで0を返す。
    */
    return 0;
}
```


# 参考URL

* [#include <stdio.h>はおまじないじゃないぞ。](https://qiita.com/fuwasegu/items/8893b2b8a7f05c67482a)
* [猫でもわかるプログラミングＣ言語編 - 第１章　ともかく作ってみよう](http://www.kumei.ne.jp/c_lang/intro/no_01.htm)
* [猫でもわかるプログラミングＣ言語編 - 第２章　動かしてみよう](http://www.kumei.ne.jp/c_lang/intro/no_02.htm)
* [コメントの書き方 | Programming Place Plus　Ｃ言語編　第５章](https://programming-place.net/ppp/contents/c/005.html)
【Java】カレンダー作成

　1月までJavaをしばらく触っていなかったため、過去にRubyで作ったことのあるプログラムをJavaで作ってみることにしました。今回はカレンダー作成問題です。

[アウトプットのネタに困ったらこれ!?](https://blog.jnito.com/entry/2019/05/03/121235)
↑こちらの記事を参考にして問題を解いています。

[【Ruby】カレンダー作成問題を解く](https://qiita.com/kim-shun/items/632799a0050bba84173c)

問題は、次のような形式で今月のカレンダーを表示させることです。

```
     April 2013
Su Mo Tu We Th Fr Sa
    1  2  3  4  5  6
 7  8  9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
```

　今回Javaで作ってみたプログラムはこちらです。今月だけでなく、他の年の他の月も確認したかったため、年と月の変数のみ切り分けました。

```java
package example;

import java.util.Calendar;
import java.util.Collections;

public class CreateCalendar {

	public static void main(String[] args) {
		Calendar cl = Calendar.getInstance();
		
		int thisYear = cl.get(Calendar.YEAR); //今年
		int thisMonth = cl.get(Calendar.MONTH); //今月(1月=0、2月=1であるため配列monthの添字に使用)
		outputCalendar(thisYear,thisMonth);
		
		//他の年、他の月の場合の確認用
		System.out.println("\n");
		int otherYear = 2013; //西暦を入力
		int otherMonth = 4; //月を入力
		outputCalendar(otherYear,otherMonth - 1);
		
	}
	
	public static void outputCalendar(int inputYear, int inputMonth) {
		Calendar cl = Calendar.getInstance();
		
		String[] month = {"January","February","March","April","May","June",
				"July","August","September","October","November","December"};
		String[] week = {"Su","Mo","Tu","We","Th","Fr","Sa"};
		
		int firstDay = 1; //月の初日
		//月の初日の曜日(日曜日=1、月曜日=2であるため-1をして配列weekの添字に使用)
		cl.set(inputYear,inputMonth,firstDay);
		int firstDayWeek = cl.get(Calendar.DAY_OF_WEEK) - 1; 
		int lastDay = cl.getActualMaximum(Calendar.DAY_OF_MONTH); //月の最終日

		System.out.print("     " + month[inputMonth] + " " +  inputYear); //年と月を出力
		System.out.println(); 

		//カレンダーの曜日を出力
		for (int i = 0; i < week.length; i++) {
			System.out.printf("%2s ",week[i]);
		}
		System.out.println();
		//初日が何曜日かに合わせて空白を出力
		System.out.print(String.join("", Collections.nCopies(firstDayWeek, "   ")));
		//日付を出力
		for (int i = firstDay; i <= lastDay; i++) {
			System.out.printf("%2d ",i);
			if ((firstDayWeek + i) % 7 == 0) {
				System.out.println();
			}			
		}
	}
}

```

 こちらが出力結果です。

```
     March 2022
Su Mo Tu We Th Fr Sa 
       1  2  3  4  5 
 6  7  8  9 10 11 12 
13 14 15 16 17 18 19 
20 21 22 23 24 25 26 
27 28 29 30 31 

     April 2013
Su Mo Tu We Th Fr Sa 
    1  2  3  4  5  6 
 7  8  9 10 11 12 13 
14 15 16 17 18 19 20 
21 22 23 24 25 26 27 
28 29 30 
```