OmniAICreator/Qiita-1.07M huggingface dataset:
LINE Messaging API まとめ

:::note info
自分の脳内整理のために、LIFF APIリファレンスを見ながら、まとめたものです。
公式ドキュメントを参照することを強くお勧めします。
↓公式リファレンス
https://developers.line.biz/ja/reference/liff/
:::

## リッチメニューの作成方法

```json
POST https://api.line.me/v2/bot/richmenu
```

リッチメニューを表示する方法は画像をアップロードしたのち、下記2ついずれかの方法をとる

- デフォルトのリッチメニューを設定する
- リッチメニューとユーザーをリンクする

上記エンドポイントに対して下記内容をsendする

- ヘッダー
    - Authorization：Bearer `{channel access token}`
    - Content-Type：application/json
- ボディ
    - リッチメニューオブジェクト
        - size
        - selected:デフォルトでリッチメニューを表示するか否か
        - name
        - chatBarText
        - areas: Array
            - bounds
                - x
                - y
                - width
                - height
            - action

レスポンスとして、richMenuIdが返ってくる

## リッチメニューオブジェクトの検証

```json
POST https://api.line.me/v2/bot/richmenu/validate
```

## リッチメニューの画像をアップロードする

```json
POST https://api-data.line.me/v2/bot/richmenu/{richMenuId}/content
```

以下要件をみたす画像をアップ

- 画像フォーマット：JPEGまたはPNG
- 画像の幅サイズ（ピクセル）：800以上、2500以下
- 画像の高さサイズ（ピクセル）：250以上
- 画像のアスペクト比（幅÷高さ）：1.45以上
- 最大ファイルサイズ：1MB

ヘッダーにAutherizationとContent-Typeを付与し、パスパラメータにrichMenuIdを渡してエンドポイントを叩く。

## ****リッチメニューの画像をダウンロードする****

```json
GET https://api-data.line.me/v2/bot/richmenu/{richMenuId}/content
```

ヘッダーにAutherizationとContent-Typeを付与し、パスパラメータにrichMenuIdを渡してエンドポイントを叩く。

## ****リッチメニューの配列を取得する****

```json
GET https://api.line.me/v2/bot/richmenu/list
```

作成したリッチメニュー全てを配列で取得。

ヘッダーにAutherizationとContent-Typeを付与してたたく。

## ****リッチメニューを取得する****

```json
GET https://api.line.me/v2/bot/richmenu/{richMenuId}
```

## デフォルトのリッチメニューを設定する

```json
POST https://api.line.me/v2/bot/user/all/richmenu/{richMenuId}
```

## ****リッチメニューエイリアスを作成する****

```json
POST https://api.line.me/v2/bot/richmenu/alias
```

```json
# リッチメニューエイリアスAを作成したい場合の例
curl -v -X POST https://api.line.me/v2/bot/richmenu/alias \
-H 'Authorization: Bearer {channel access token}' \
-H 'Content-Type: application/json' \
-d \
'{
    "richMenuAliasId": "richmenu-alias-a",
    "richMenuId": "richmenu-862e6ad6c267d2ddf3f42bc78554f6a4"
}'

# リッチメニューエイリアスBを作成したい場合の例
curl -v -X POST https://api.line.me/v2/bot/richmenu/alias \
-H 'Authorization: Bearer {channel access token}' \
-H 'Content-Type: application/json' \
-d \
'{
    "richMenuAliasId":"richmenu-alias-b",
    "richMenuId":"richmenu-88c05ef6921ae53f8b58a25f3a65faf7"
}'
```

任意のリッチメニューに対して、エイリアスIDを付与する。

## ****リッチメニューエイリアスの情報を取得する****

```json
GET https://api.line.me/v2/bot/richmenu/alias/{richMenuAliasId}
```
Jetpack Compose でチュートリアル風の Text を表示する

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367893/a6e00f66-30e1-5157-4533-73f714beb526.gif" />


Compose でこんなものを作りました。
Android View を使っていたときはこういうのを作るのはとても大変でしたが Compose だと楽になったなとしみじみしたので記念に。


```kotlin:
@Composable
fun TutorialText(
    modifier: Modifier = Modifier,
    coroutineScope: CoroutineScope = rememberCoroutineScope(),
    intervalMilliSec: Long = 100L,
    style: TextStyle = LocalTextStyle.current,
    message: String,
) {

    var text by remember {
        mutableStateOf("")
    }

    DisposableEffect(Unit) {
        coroutineScope.launch {
            for (c in message) run {
                text += c
                delay(intervalMilliSec)
            }
        }
        onDispose {
            coroutineScope.cancel()
        }
    }

    Text(
        modifier = modifier.clickable(
            interactionSource = remember { MutableInteractionSource() },
            indication = null,
        ) {
            coroutineScope.cancel()
            text = message
        },
        text = text,
        style = style,
    )
}

@Preview
@Composable
fun TutorialTextPreview() {
    Surface {
        TutorialText(
            modifier = Modifier.padding(8.dp),
            message = "これはお試しのチュートリアルです。ちょっと長めの文章にするために尺を稼いでいます。今日はとても暑かったのでブラックサンダーアイスを買いました。",
            style = TextStyle(
                fontSize = 16.sp,
                color = Color.Red,
            )
        )
    }
}

@Preview
@Composable
fun TutorialTextPreview2() {
    Surface {
        TutorialText(
            modifier = Modifier.padding(8.dp),
            message = "これはお試しのチュートリアルです。ちょっと長めの文章にするために尺を稼いでいます。今日はとても暑かったのでブラックサンダーアイスを買いました。",
            intervalMilliSec = 50L,
        )
    }
}
```



簡単に説明すると

```kotlin
    DisposableEffect(Unit) {
        coroutineScope.launch {
            for (c in message) run {
                text += c
                delay(intervalMilliSec)
            }
        }
        onDispose {
            coroutineScope.cancel()
        }
    }
```

一定時間ごとに文字列を変更しています。
また、 `DisposableEffect` を用いてこの TutorialText が表示されなくなったタイミングで `CouroutineScope` を閉じています。

```kotlin
    Text(
        modifier = modifier.clickable(
            interactionSource = remember { MutableInteractionSource() },
            indication = null,
        ) {
            coroutineScope.cancel()
            text = message
        },
        text = text,
        style = style,
    )
```

クリックされたら CoroutineScope を閉じてメッセージを一気に表示する仕様にしています。
また、 `indication = null` でクリック時の ripple effect を消しています。

気合を入れて書こうと永遠に書き終わらなくて頓挫してしまうので、これくらいのシンプルな内容が良いですね。
Leetcode 852. Peak Index in a Mountain Array

https://leetcode.com/problems/peak-index-in-a-mountain-array/description/

# アプローチ1
## Brute-force

```java
class Solution {
    public int peakIndexInMountainArray(int[] arr) {
        int before = 0;
        for (int i = 0; i < arr.length; i++) {
            if (before <= arr[i]) {
                before = arr[i];
                continue;
            }
            return i - 1;
        }
        return before;
    }
}
```


# アプローチ2
## 二分探索

```java
class Solution {
    public int peakIndexInMountainArray(int[] arr) {
        int left = 0;
        int right = arr.length - 1;

        while (left < right) {
            int mid = (left + right) / 2;

            if (arr[mid] < arr[mid + 1]) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return left;
    }
}
```
【0日目】React（Next.js）学習記録

職業訓練に通う19歳！

行きたい会社でフロントエンジニアとして働くためにポートフォリオを作らないと行けない！

職業人講話やYouTubeとかでQiitaとかに学習記録的なのを投稿するといいって耳にしたので
始めてみます。:fist:

文字だけだと殺風景なので趣味で撮った写真でも載せときます

![DSC_1500.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3520307/9b5fbf4b-eb04-b22d-aa14-7015574b48de.jpeg)
【Go】config.iniファイルの読み込み

# はじめに
Go言語の勉強メモです。
config.iniで指定してあるAPIキーを読み込ませる部分の実装になります。

# フォルダ階層
config/
├ main.go
├ config.ini
├ go.mod
├ config/
  |        └ config.go

# パッケージのインストール
config.goファイル内の、"gopkg.in/ini.v1"パッケージを以下の手順でインストールする。

・go mod init sample（任意の名前）
→ go.modの作成（go関連のパッケージをインストールするのに必要）
・go get gopkg.in/ini.v1

# 実装
```ini:config.ini
; セクションヘッダー
[api_info]
api_key = XXXXXXXXXX
api_secret = YYYYYYYYY
```

```go:config.go
package config

//必要なパッケージのインポート
import (
	"log"
	"os"
	"gopkg.in/ini.v1"
)

type ConfigList struct {
	ApiKey    string
	ApiSecret string
}

var Config ConfigList

func init() {
	cfg, err := ini.Load("config.ini")
	if err != nil {
		log.Printf("failed to init file: %v", err)
		os.Exit(1)
	}

	Config = ConfigList{
		ApiKey:    cfg.Section("api_info").Key("api_key").String(),
		ApiSecret: cfg.Section("api_info").Key("api_secret").String(),
	}
}
```

```go:main.go
package main

import (
	"sample/config"
	"fmt"
)

// 読み込ませたAPIキーを表示させる
func main() {
	fmt.Println(config.Config.ApiKey)
	fmt.Println(config.Config.ApiSecret)
}
```

ターミナルで、go run main.goのコマンドを叩き、ApiKeyとApiSecretの中身が表示されれば成功！

# 参考
[現役シリコンバレーエンジニアが教えるGo入門 + 応用でビットコインのシストレFintechアプリの開発](https://www.udemy.com/course/go-fintech/)
PythonでWord(.docx)のネストされた表を取得する

## まとめ
Word内の表の中の表(ネストされた表)はpython-docxで中身を取得できる

## 背景
以前、職場で行われた実験をデータベース化したときのことです。
いろいろ壁はあったのですが、その中で最も扱いに苦労したものに実験条件の抽出があります。
どういうことかというと、各実験での実験計画書がwordで書かれており、使用する材料は表の中の表、すなわちネストされた表として記載されてました。
↓のような感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3471244/051c34b2-25cb-cc9a-541e-8f6ecf105315.png)

Wordの表を扱うのすら面倒なのに、その中にネストされた表を抽出するのはめちゃくちゃ怠かったです。
当時はいろいろ試した記憶がありますが、この方法に落ち着きました。

## 方法
```python:code1
import docx

def get_nested_table(doc):#ネストされた表を取り出すジェネレータ関数
    for table in doc.tables:
        for row in table.rows:
            for cell in row.cells:
                yield from cell.tables
    yield None

doc=docx.Document('ワードファイルのパス')
nest=next(get_nested_table(doc))


for i in range(3): #確認用
    for j in range(3):
        print(nest.cell(i,j).text)
```

親表の中の一つ一つのセルをみて、表がないかどうか確認しています。
ジェネレータ関数にすることで表が2つ以上ある場合にも対処を考えられる余地を持たせてます。
ただし、関数を呼び出すときに`next`を忘れるとジェネレータ自体を呼び出してしまいますので注意。


```python:結果
No.
主原料
副原料
1
AA001
AD1
2
AA002
AD1
```

ということでネスト表の中身を抽出することができました。実際には、表が2つある場合とか、別途工夫が必要になることもあるでしょう。
【ネットワーク】IPアドレス・サブネットマスク・CIDR


### IPアドレス
インターネット上の住所
コーピュータやデバイスが
インターネット上の特定の場所にあることを示している。

IPv4では「xxx.xxx.xxx.xxx」（例：192.168.1.1）
IPv6では「xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx」
の形式で表現される。

### サブネットマスク
IPアドレスの範囲を表すもの
例「255.255.255.0」=/24(CIDR)
ネットワーク部とホスト部に分けるための「仕切り」

「どこまでが同じネットワークか」
「どこまでが個々のコンピュータやデバイスか」を決めるもの

ネットワーク部
グループやネットワークを識別するための部分
特定のネットワークのアドレスを示す。

ホスト部
個々のデバイスを特定するための部分
デバイスを一意に識別するための情報

0.0.0.0〜255.255.255.255
255⇔11111111(8bit) 1はネットワーク
0⇔00000000(8bit) 0は個々のコンピュータやデバイス

例えば「255.255.255.0」のサブネットマスクは、
IPアドレスの最初の3つの数値がネットワーク部で、
最後の1つの数値が個々のコンピューターやデバイスを示している。




## CIDR（Classless Inter-Domain Routing）
IPアドレスのネットワーク部とホスト部の長さを表す方法
例えば
「192.168.1.0/24」という表記は、
IPアドレスの
最初の24bit(8bit×3)がネットワーク部で、
残りの8bitがホスト部を示す。

つまり、
/31の場合、左側31個の1が確定
1〜1 . 1〜1 . 1〜1 . 11111110 

右はじの一つだけが0or1の2通り
ということは、
192.168.15.36/31
→192.168.15.36/32
→192.168.15.37/32

とりあえず覚えておくべきもの
172.12.16.15/32
→172.12.16.15(1個)
172.12.16.15/31
→172.12.16.15・172.12.16.16(2個)
/30(4個 2^2)
/29(8個 2^3)
/28(16個)
/27(32個)
/26(64個)
/25(128個)

172.12.16.15/24(256個 0〜255)
15からスタートすると、第4オクテットが255を超えてしまう
結果は、172.12.16.0/32〜172.12.16.255(256個)
これ以降はもう暗算で出せないから、計算機を使った方がいい
シェルスクリプトでcurlコマンドを連続実行する

# 実現したいこと
「連番データの入ったCSVファイルの値でHTTPのPOSTリクエストをデータ数分（1000件ほど）実行したい」
# ポイントは以下の二つ
* CSVファイルからfor（loop）文で1件ずつデータを取り出す
* 取り出した値をリクエストボディに埋め込んでcurlリクエストを投げる

# ループ文の書き方とCSVファイルの読み込み方
##### 使用するCSVデータファイル
```data.csv
id,name,age
1,yamada_taro,15
2,yamada_hanako,14
3,suzuki_ichiro,20
・・・以下1000行
```
##### 読み込み処理の記述
while read文でテキストファイルの文字列を一行ずつ取得することができる。
【参考】
https://qiita.com/SoarTec-lab/items/4475ba6de612fba3f163

```sample.sh
#!/bin/bash
CSVDATA=data.csv
while read LINE || [ -n "${LINE}" ];
do
id=$(echo $LINE | cut -d, -f 1)
name=$(echo $LINE | cut -d, -f 2)
age=$(echo $LINE | cut -d, -f 3)
echo "id: $id, name: $name, age: $age"
done < $CSVDATA
```
`while read LINE || [ -n "${LINE}" ];`
単純にwhile read LINE do とするCSVファイルの最終行が実行されない事がある。
原因はデータファイルの最終行で行で改行していない事。
|| [ -n "${LINE}" ]とすることで最終行が改行文字でない場合も空行でなければ処理する、というような動作をさせることができる


https://qiita.com/Ets/items/a7fa24b138b8ee883dac

CSVから一行ずつ取り出した後はcut文を使い
`id=$(echo $LINE | cut -d, -f 1)`
とする事で任意の位置の文字列を変数に格納できる。
（ここでは変数idに1列目左端の文字列を格納している）

# curlリクエストの実行
loop処理で1列目のデータを取得できれば後はそのままcurlを実行すれば良い
```sample.sh
#!/usr/bin/bash
CSVDATA=data.csv
ReadCount=1
HOST_URL="http://sample.com"
URL=samplePost
while read LINE || [ -n "${LINE}" ];
do
id=$(echo $LINE | cut -d, -f 1)
name=$(echo $LINE | cut -d, -f 2)
age=$(echo $LINE | cut -d, -f 3)
if [ $ReadCount != 1 ]; then
 curl -L-X POST ${HOST_URL}/${URL} -H "id: ${Id}" -d @- << EOS
{
    "name":${name},
    "age":${age}
}
EOS
else
fi
  let ReadCount++
done < $CSVDATA
```
ReadCountを用意することでCSV一行目のヘッダー行を取り出さないようにしている。
（if文でReadCount = 1の時に処理をスキップ）

-dの部分がリクエストのボディにあたる。
@- << EOSで標準入力を埋め込み、Json型リクエストボディの中で変数を扱えるようにしている。
これでCSVファイルを読み込みながらcurlリクエストが自動で実行されるスクリプトの完成です。

# 実行する前に！
スクリプトを組んでループ文で1000件POSTリクエストを送るのは慎重に行いましょう（自戒）。無限ループなど起きていたら発狂ものものです。
必ず実行する前に実行環境で処理中断のコマンドを調べてから実行することをおすすめします。
GitBashならCtrl + C！
[ubuntu22.04].runファイルでNVIDIA ドライバをインストールする手順

## ディスプレイサーバーをX11に切り替える

ubuntu22.04はWaylandがデフォルトのディスプレイサーバーになっているので、以下の記事などを参考にしてディスプレイサーバーをX11に切り替える。

https://jp.moyens.net/how-to/220737/



## インストールされているNVIDIAドライバの削除

```bash
sudo apt remove --purge nvidia*
```




## NVIDIAのサイトから.runファイルをダウンロード

https://www.nvidia.co.jp/Download/index.aspx?lang=jp

実行権限をつける

```bash
sudo chmod +x NVIDIA-Linux-x86_64-525.60.11.run
```


## コンソールモードにする

［Ctrl］＋［Alt］＋［F6］キー を押してコンソールモードに切り替えログインする


## GUIサービスの停止

```bash
sudo service lightdm stop
```

## インストーラを実行して再起動

```bash
 sudo ./NVIDIA-Linux-x86_64-525.60.11.run
 reboot
```

## 動作確認

```bash
nvidia-smi
```

# 参考



https://qiita.com/ozota/items/28b7e1fbf5015f907638
モノレポ管理していたFrontend/Backendで分けたくなった場合のやり方

## これは何
FrontendとBackendをモノレポで管理していて、途中で、FrontendとBackendで分けたくなった場合の方法の備忘録

## やり方
- 対象となるリポジトリをcloneしてくる
` git clone https://github.com/username/app-name.git`
- server / client と2つのリポジトリに分かれてることを確認
`git filter-branch --subdirectory-filter 対象のサブディレクトリ(ここでは client ) HEAD`
    - 注意すべきこととして、git `fileter-branch` コマンドは、ルートディレクトリで行うこと
- 新しくGitHub上に要した場所にpush
- 完了

## `git filter-branch` コマンドとは何者？
Gitのリポジトリ履歴を再書き込みするための強力なツール。
主な目的は、履歴の内容をフィルタリングしたり、部分的に切り出したりして、リポジトリの歴史を変更すること。
これを使うことで、過去のコミットを修正、削除、統合、リネーム、特定のディレクトリやファイルのみを含む新しいリポジトリを作成することができる

- `subdirectory-filter <directory>`
指定したディレクトリ以下のファイルやディレクトリのみを抽出して、それ以外の履歴を削除する。
サブディレクトリをアタらいいリポジトリとして分離するのによく用いる
【作業メモ】GCPリソースをTerraformコードとしてエクスポートする

Cloud ShellからリソースをTerraformコードにエクスポートできる。コマンドは2023/7/25時点ではbeta版。ベータ版のコマンドはgcloud beta (コマンド)になるのね

とりあえずプロジェクト配下のリソースを全てエクスポートする
（プロジェクトにはハンズオンで試しに作ったリソースがちょろっと残っている）



## 1. Config ConnectorのCLIをインストール

CloudShellで以下を実行

```
sudo apt-get install google-cloud-sdk-config-connector
```

## 2. Cloud Asset API を有効にする

GoogleCloudリソースの資産管理をするAPIなのかな
```
gcloud services enable cloudasset.googleapis.com
```
## 3. エクスポート

このコマンドだとproject指定しているのにprojectがemptyだよって言われた
```
gcloud beta resource-config bulk-export --path=<エクスポート先ディレクトリ> --project=<projectID> --resource-format=terraform
```

<br>
のでgcloud config set project <プロジェクトID>でデフォルトプロジェクトを設定して以下コマンドを実行したらエクスポートできた

```
gcloud beta resource-config bulk-export  --path=<エクスポート先ディレクトリ>  --resource-format=terraform
```

エクスポート先のフォルダ内はこんな感じ。それぞれのフォルダの中に.tfファイルが入っている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3458266/e037f55f-7d6f-31a5-5dd6-9a1722f11086.png)

IAMServceAccountの情報なんかもエクスポートされてた


## 4. 感想
実行するたびにプロジェクト配下のリソース全て.tfにするのも時間かかるので、
リソースを指定してエクスポートする方法とか、エクスポートがサポートされていないリソースを今後整理したい


## 5. 参考サイト

##### エクスポート方法の詳細

https://cloud.google.com/docs/terraform/resource-management/export?hl=ja

##### ベータコマンドについて

https://cloud.google.com/sdk/gcloud/reference/beta

##### デフォルトのプロジェクト設定について

https://cloud.google.com/artifact-registry/docs/repositories/gcloud-defaults?hl=ja
【SwiftUI】Twitterの投稿ボタンを再現する

# はじめに
Twitterの右下にある投稿ボタンを作ってみます。
押すと色は変化せず、大きさが変化するようなボタンのスタイルです。

# サンプルアプリ
![Simulator Screen Recording - iPhone 14 Pro - 2023-07-25 at 21.41.20.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/a805261b-da68-ed30-c142-2bf544810df0.gif)

# 実装
```swift
struct TwitterPostButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .foregroundStyle(.white)
            .frame(width: 60, height: 60)
            .background(.blue, in: Circle())
            .scaleEffect(configuration.isPressed ? 0.9 : 1.0)
            .animation(.spring(), value: configuration.isPressed)
            .shadow(radius: 3)
            .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottomTrailing)
            .padding(15)
    }
}

extension ButtonStyle where Self == TwitterPostButtonStyle {
    static var twitterPostButton: TwitterPostButtonStyle {
        .init()
    }
}
```

# 使い方
```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        Button {
            // タップアクション
        } label: {
            Image(systemName: "plus")
                .resizable()
                .frame(width: 18, height: 18)
        }
        .buttonStyle(.twitterPostButton)
    }
}
```

# おわり
今回は長押しは再現しませんでした。
いい方法が思い浮かばなかったので長押しは機能に追加しませんでした。
長押しのアニメーションもかっこいいのでいつか再現したいです
GitHubにPushするときは1回のPushを10MBくらいにした方が良いのでスクリプトを書いた

# はじめに
GitHubに大量のファイルをPushしたらサイズ制限で弾かれた。
１つのファイルはLFSを使用するまで大きくないものの、1回のPushの容量が大きいと制限がかかるみたいです。
というわけで、10MBぐらいずつadd&commitしてpushするスクリプトを書いた。

```bash
#!/bin/bash

# 現在のディレクトリがGitリポジトリであることを確認
if [ ! -d .git ] && ! git rev-parse --git-dir > /dev/null 2>&1; then
    echo "Error: must run this script in a Git repository"
    exit 1
fi

# カレントディレクトリを保存
root_dir=$(pwd)

# ファイルサイズの合計を保持する変数を初期化
total_size=0

# 10MBのサイズをバイト単位に変換
commit_size=$((10*1024*1024))

# カレントディレクトリ内のすべてのファイルを再帰的に走査
find . -type f | while read file
do
    # ファイルのサイズを取得
    file_size=$(stat -f%z "$file")

    # ファイルをステージングエリアに追加
    git add "$file"

    # ファイルサイズを合計に加算
    total_size=$((total_size + file_size))

    # 合計サイズが10MBを超えたらコミットとプッシュを実行
    if [ $total_size -ge $commit_size ]; then
        git commit -m "automated commit from script"

        # pushが3分経っても終わらない場合は再試行
        while true; do
            timeout 180 git push && break
            echo "Push timed out, retrying..."
        done

        # ファイルサイズの合計をリセット（新たなコミットのため）
        total_size=0
    fi
done

# 最後のコミットとプッシュを行う（合計サイズが10MBに達していない場合）
git commit -m "final automated commit from script"

# pushが3分経っても終わらない場合は再試行
while true; do
    timeout 180 git push && break
    echo "Push timed out, retrying..."
done

```

今回は以上です！
chatGPT先生のタイトルです（「AIを恐れる必要はない！ 生成AIがもたらす未来」）

## はじめに
タイトルは先生のお言葉です。恐縮です。（本文は一般人のワタシが担当します）
生成AIを毎日使用しています。毎日使用しているので、OUTPUTしたくて今回投稿しました。
（ただ書きたかっただけです。それだけでそれ以上でもそれ以下でもありません。）

## 言いたいこと

いきなり本題です。
使ったことが無い人に対してです。

**「使わないのはなぜですか？」**

直接的な言い方となり申し訳ないですが、それぐらいの衝撃であり
これからの時代（というか今まさに）世界の変革が始まっていると思っています。

恐らくQiitaのようなサイトを活用している方は使用している人が多い（というか大多数？）かもしれませんが、私の仕事がIT系ではないこと、もとい地方という環境下では
「生成AI、、あぁニュースのあれね（笑）」や「AI？怖くない？」や「何ができるの？検索と一緒では？」という回答で埋め尽くされているのが悲しいですが実情です。（もちろん一部の使用している方はいらっしゃいます。そういう方は仲間です！普段わりとぼっちなので嬉しい限りです）

今はスタート地点です。生成AIについて皆が情報を取得して活用から始まり
企業の生産性向上⇔コストダウン/金儲け/いやいやセキュリティとの天秤/国が規制だ・・と様々な方面の話もありますが今は性悪説ということで話を進めます。

まず企業は生産性を向上させたいでしょう。世界と戦えなくなるから。
恐らく近い展望としては活用できる企業が（先端企業は現状始まっていそう）
copilotなどのアプリの組み込まれた先生（生成AI)にメンター的ポジションというかコーダ（どのレベルかはおいておく）ポジションで現れ徹底的に人を減らしに動くでしょう。（これは実際に営業の方が提案したときに、人を◯人減らせるの？　の体現ですね。きっと凄まじいですよ、笑えないレベルに）

そのときに笑って、もしくはAI？なにそれ？という状況ですむのでしょうか。
（すむポジションの方は上から笑ってみましょう。。あなたは選ばれた人間です。

間違いなく世界に置いていかれます（世界を目指している企業でもないですが、世界の競合他社はボーっとしていますかね？）
賢い人は自動化を進めて、いつかあなたの仕事を奪うでしょう。
その時になって考えますか？

まず使用してほしいです。
そして生成AIや、より将来をワクワクさせるような展開が訪れ活用する側になれるように
私は毎日壁打ちしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448426/0a56180c-85eb-cfce-6188-c0e9f2fd163c.png)

※プロのライタでお願いしました。
　どうでしょうか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448426/d95e4478-fce3-873f-2ee2-99ad3c11200f.png)


長文、かなりの乱文失礼しました。
（最後に、、、本当に生成AIくんは強い相棒ですね。毎日使えば使うほどスルメです。のめり込みます。のめり込みましょう。あと私は普段、性善説です。というか社会に出るまで性悪説/性善説についての感覚が薄かった（若かったのでしょう。））
[AWS Q&A 365][EI]AWSのよくある問題の毎日5選 #98

# Q1: Amazon Elastic Inference Developer Guideにはどのようなセキュリティ対策が記載されていますか？
A1: そのガイドには、Identity and Access Management (IAM)、IDでの認証、ポリシーを使用したアクセス管理、ログ取りとモニタリング、コンプライアンスの検証、インフラセキュリティ、設定と脆弱性分析などのセキュリティ対策が記載されています。

# Q2: Elastic Inferenceのセキュリティグループをどのように設定しますか？
A2: そのガイドでは、Elastic Inferenceのセキュリティグループを設定する方法について説明があります。"Elastic Inferenceのセキュリティグループを設定する"セクションを確認し、手順に沿って設定することを推奨します。

# Q3: CloudWatch Metricsを使ってElastic Inferenceをモニタリングする情報はありますか？
A3: はい、ガイドにはCloudWatch Metricsを使ってElastic Inferenceをモニタリングする情報が含まれています。Elastic Inferenceのメトリクスと次元に関する詳細、さらにはCloudWatchのアラームを作成してElastic Inferenceをモニタリングする方法について説明しています。

# Q4: Amazon Elastic Inferenceを使用する際に考慮すべきセキュリティ上の注意点は何ですか？
A4: そのガイドでは、インフラセキュリティ、設定と脆弱性分析、ログ取りとモニタリング、コンプライアンスの検証、そしてレジリエンスなどの考慮点について触れています。詳細な情報を得るために、ガイド内の関連セクションを確認することが推奨されています。

# Q5: その文書にはAmazon Elastic Inferenceに関連する特定のセキュリティ機能はありますか？
A5: はい、そのガイドでは、Amazon Elastic Inferenceに関連する様々なセキュリティ機能、例えばIdentity and Access Management (IAM)、IDでの認証、ポリシーを使用したアクセス管理、ログ取りとモニタリング、コンプライアンスの検証、そしてインフラセキュリティについて議論しています。また、セキュリティグループの設定方法や、CloudWatch Metricsを使ったモニタリングについての情報も提供しています。
[AWS Q&A 365][EI]Daily Five Common Questions #98

# Q1: What security measures are mentioned in the Amazon Elastic Inference Developer Guide? 
A1: The guide mentions security measures such as Identity and Access Management (IAM), authenticating with identities, managing access using policies, logging and monitoring, compliance validation, infrastructure security, and configuration and vulnerability analysis. 

# Q2: How can I configure my security groups for Elastic Inference? 
A2: The guide provides instructions on configuring your security groups for Elastic Inference. It is recommended to review the "Configuring Your Security Groups for Elastic Inference" section for step-by-step instructions. 

# Q3: Is there any information about using CloudWatch Metrics to monitor Elastic Inference? 
A3: Yes, the guide includes information on using CloudWatch Metrics to monitor Elastic Inference. It provides details on Elastic Inference metrics and dimensions, as well as creating CloudWatch alarms to monitor Elastic Inference. 

# Q4: What security considerations should be taken into account when using Amazon Elastic Inference? 
A4: The guide mentions considerations such as infrastructure security, configuration and vulnerability analysis, logging and monitoring, compliance validation, and resilience. It is recommended to review the relevant sections in the guide for detailed information. 
# Q5: Are there any specific security features related to Amazon Elastic Inference in the document? 
A5: Yes, the guide discusses various security features related to Amazon Elastic Inference, including Identity and Access Management (IAM), authenticating with identities, managing access using policies, logging and monitoring, compliance validation, and infrastructure security. It also provides information on configuring security groups and using CloudWatch Metrics for monitoring.
undefined method 'new' for モデル名:Moduleと出た

プログラミングスクールにて絶賛Railsの学習中の者です。
アプリ作成中にタイトルのようなエラーが起きたので、解決法と共に共有します。
## 起きたこと
ブログ機能実装の演習で、Blogという名前のアプリでBlogというモデルを作ったら、コントローラで以下のようなエラーが出ました。

```
NomethodError undefined method 'new' for Blog:Module
```
翻訳すると「モジュールとしてBlogが認識されている」となります。

（モジュールとは、クラスメソッドとは違います。複数のクラスでメソッドを共同利用できる便利さがありますが、一方でクラスのようにインスタンスの生成はできません。継承もできません。）

最初コントローラ内のnewアクション名か、周辺のコードが間違っているのかと思い確認してみました。ですがどうみてもその周辺に間違いはなさそう。

## 分析
調べてみると、config/application.rb の記述が確かに`Module Blog`となっていました。

どうやらRailsはアプリ名をそのままモジュール名としてconfig/application.rb に自動的に生成するようです。今回の場合、アプリ名がBlog、そして `rails g model` のモデル生成もBlogで行っていました。
そのため名前が混線し、このNomethodError はモジュール名が被っているせいでモデル名を呼び出せないのが原因と判明しました。**アプリ名とモデル名は同じにしてはならない**ということです。

## 解決まで
以上の原因のため、アプリ名を変更すれば解決します。
具体的には下記の方法がありました。

  1. アプリを作り直す(推奨）
  2. `rename`のGemを使ってアプリ名を変更する

**基本的には1を推奨します**。
ですがせっかくなので、今回は「もしアプリを消せない状況だったらどうするか」と仮定してrenameを使用してみました。これについては参考記事に詳細が書いてありますので、そちらを紹介します。
　[[Rails]rails newした後からアプリ名を変更する方法]("https://qiita.com/ryoya-s/items/66e426f1a0dd5d87cd6f")

結論から言うとrenameでアプリ名、つまりモジュール名を変更することには成功しました。が、やはり手動で細かい所を直す必要が多少あり、労力を考えるとやはりそもそも作り直す方が個人制作の上では速いと感じました。

## アプリケーション名の命名規則
Railsの命名規則は厳しいと聞いていたので、ではアプリ名にも規則があるのか？と講師に確認してみました。

結論としては「無い」とのことです。大文字小文字やハイフン、_のどれを使うかといった決まりは無い。ただし今回のように**モデル名と同じにしてしまうとエラーが出てしまう**ので、そこだけ気を付けるべし、と教わりました。

## 終わりに
最初エラーを見た時はまさかアプリ名が原因とは思わなかったので、良い経験になりました。今後はもう同じエラーは起こさないと思います。

ここまで読んでくださり、ありがとうございました。
テスト101

```vb


Sub SQL_IN()

Dim str_SQL As String
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim bbb As String

'IN句を使ったSQL...〆('ω' )

Set cn = CurrentProject.Connection
str_SQL = "SELECT * FROM T_練習"

rs.Open str_SQL, cn, adOpenDynamic, adLockOptimistic

With rs

    .MoveFirst
    
    Do Until .EOF = True

        If .Fields("管理コード").Value = "002" _
        Or .Fields("管理コード").Value = "A01" _
        Or .Fields("管理コード").Value = "C14" Then
            
            bbb = bbb & "'" & .Fields("管理コード").Value & "' ,"
        
        End If
        
        .MoveNext
        
    Loop

End With

bbb = Left(bbb, Len(bbb) - 1)

Set rs = Nothing

str_SQL = "SELECT 商品コード FROM T_練習 WHERE 管理コード IN (" & bbb & ")"

rs.Open str_SQL, cn, adOpenDynamic, adLockOptimistic


With rs

    .MoveFirst
    
    Do Until .EOF = True

        Debug.Print .Fields("商品コード").Value
        
        .MoveNext
        
    Loop

End With

Set rs = Nothing
Set cn = Nothing

End Sub
【SwiftUI】macアプリで新しいタブを開く方法

# はじめに
Safariのように、新しいタブを開けるmacアプリの作り方を紹介します。

# やり方
## コード全体
```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Button {
                createNewTab()
            } label: {
                Text("Open new tab")
            }
        }
        .padding()
    }
    
    func createNewTab() {
        let text = Text("Hello new tab!")
            .frame(maxWidth: .infinity, maxHeight: .infinity)
        
        let window = NSWindow()
        
        window.contentView = NSHostingView(rootView: text)
        window.title = "New Tab"
        window.styleMask = [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView]
        
        if let keyWindow = NSApp.keyWindow {
            keyWindow.tabGroup?.addWindow(window)
        }
        
        let _ = NSWindowController(window: window)
    }
}
```

## ポイント
### 1. `NSWindow`を作る
```swift
let window = NSWindow()
```
### 2. `NSWindow`の`contentView`に`NSHostingView`を設定する
```swift
window.contentView = NSHostingView(rootView: text)
```
こうすることで、SwiftUIのViewを`NSWindow`に表示できます。
### 3. `NSWindow`の`title`を設定する
```swift
window.title = "New Tab"
```
### 4. `NSWindow`の`styleMask`を設定する
```swift
window.styleMask = [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView]
```
これがないと、基本的なウィンドウ操作ができません。
### 5. `NSWindow`を`NSApp.keyWindow`の`tabGroup`に追加する
```swift
if let keyWindow = NSApp.keyWindow {
    keyWindow.tabGroup?.addWindow(window)
}
```
`NSApp.keyWindow`で現在アクティブなウィンドウを取得し、取得したウィンドウの`tabGroup`に`NSWindow`を追加します。
### 6. `NSWindowController`を作る
```swift
let _ = NSWindowController(window: window)
```
これがないと、タブを閉じた時にクラッシュします。

# おわりに
新しいタブを開く方法を紹介しました。この方法を使えば、Safariのようなタブを中心としたアプリを作ることができます。

# デモ動画

https://twitter.com/shota_appdev/status/1683815927585058816?s=61&t=eMbFYKnWSYQzpMS76FVOkA
LaravelでAuthデータをViewに表示できて嬉しかった話

### Laravelでデータベースのデータをいい感じに表示できてうれしい

![スクリーンショット 2023-07-25 20.58.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3357049/1d92ba26-0db3-7f9d-a755-31717ead3e38.png)

最近作っているサイト
名前とか取れました、嬉しい

### コードはこんな感じ
もでる
```
    protected $fillable = [
        'name',
        'email',
        'password',
        'business_hours',
        'phone_number',
        'prefecture',
        'url',
    ];
```


こんとろら
```
public function index()
    {
        // ログインしているユーザーの情報を取得
        $object = Auth::user();
        // ユーザー情報を変数に格納
        $name = $object->name;
        $email = $object->email;
        $phone_number = $object->phone_number;
        $prefecture = $object->prefecture;
        $business_hours = $object->business_hours;
        $url = $object->url;

        // ユーザー情報をviewに渡す
        return view(
            'showUser',
            [
                'name' => $name,
                'email' => $email,
                'phone_number' => $phone_number,
                'prefecture' => $prefecture,
                'business_hours' => $business_hours,
                'url' => $url
            ]
        );
```

びゅー
```
<div class="p-6 bg-white border-b border-gray-200">
<p>Name: {{ $name }}</p>
<p>E-mail: {{ $email }}</p>
<p>Phone: {{ $phone_number }}</p>
<p>Prefecture: {{ $prefecture }}</p>
<p>Hours: {{ $business_hours }}</p>
<p>URL: {{ $url }}</p>
</div>
```

一部ですがこんな感じ

、、、大変！
MVCモデルに慣れてはきたものの、
命名を雑にしてわけわからんくなってしまったのも懐かしい（今日の昼）

拡張子書かなくても読み取ってくれるのはいいけど、
命名規則をばっちり決めないと、わけわからんくなっちゃいますわ

### まとめ
つーことで、明日は、
・別のテーブルにもデータを格納
・検索機能の追加
・レビュー投稿画面の追加
の３本です。

来週もまた見てくださいね！
じゃん、けん、ぽん
うふふふふふふふふ。



おわり。
Javaの文字列について学習してみた

# 概要
Javaの文字列について学習してみました。以下のページを参考にしました。

文字列(Stringクラス)

https://www.javadrive.jp/start/string/

文字列を作成する

https://www.javadrive.jp/start/string/index2.html

数値を文字列に変換する

https://www.javadrive.jp/start/string/index11.html

文字列を数値に変換する

https://www.javadrive.jp/start/string/index12.html

文字列と文字列を比較する(String.equals)

https://www.javadrive.jp/start/string/index4.html

文字列と文字列の大きさを比較する(String.compareTo)

https://www.javadrive.jp/start/string/index13.html

文字列の長さを取得する(String.length)

https://www.javadrive.jp/start/string/index6.html

文字列の文字の数(コードポイントの数)を取得する(String.codePointCount)

https://www.javadrive.jp/start/string/index9.html

文字列から指定したインデックスの文字を取得する(String.charAt)

https://www.javadrive.jp/start/string/index5.html

文字列から指定したインデックスのUnicodeコードポイントを取得する(String.codePointAt)

https://www.javadrive.jp/start/string/index10.html

文字列から開始と終了インデックスを指定して部分文字列を取得する(String.substring)

https://www.javadrive.jp/start/string/index7.html

# まとめ
何かの役に立てばと。
webpack制作まとめ

## package.json
```
npm init
```

### 変更点
```package.json
"license": "UNLISENCED",
```

## 入れるもの

- pug(htmlコンパイル)
- stylus(cssコンパイル)※Sass使う場合は変える
- ES6(babel)
- TypeScript（jsコンパイル）
- 画像圧縮
- ブラウザシンク

### 最新バージョンの確認
```
npm view ここにインストールするもの

▼ex
npm view webpack

▼バージョン指定で入れる場合
npm install --save-dev webpack@X.X.X
```

### インストール内容

今回がdevDependenciesに入れるため`--save-dev`でインストールする。
```
npm install --save-dev webpack
npm install --save-dev webpack-cli
npm install --save-dev css-loader
npm install --save-dev style-loader
npm install --save-dev mini-css-extract-plugin
npm install --save-dev stylus
npm install --save-dev stylus-loader
npm install --save-dev html-webpack-plugin
npm install --save-dev pug-html-loader
npm install --save-dev html-loader
npm install --save-dev clean-webpack-plugin
npm install --save-dev webpack-dev-server
npm install --save-dev babel-loader
npm install --save-dev @babel/core
npm install --save-dev @babel/preset-env
npm install --save-dev image-webpack-loader
npm install --save-dev react
npm install --save-dev react-dom
npm install --save-dev @types/node
npm install --save-dev @babel/preset-react
npm install --save-dev typescript
npm install --save-dev ts-loader
npm install --save-dev @types/react
```

### 一括で入れる
```
npm install --save-dev webpack webpack-cli css-loader style-loader mini-css-extract-plugin stylus stylus-loader html-webpack-plugin pug-html-loader html-loader clean-webpack-plugin webpack-dev-server babel-loader @babel/core @babel/preset-env image-webpack-loader react react-dom @types/node @babel/preset-react typescript ts-loader @types/react
```

## ディレクトリ構成

```
webpack
├─ node_modules
├─ package.json
├─ package-lock.json
├─ webpack.config.js
├─ tsconfig.json
├─ src
│ ├─ pug
│ │ ├─ about
│ │ │  └─ index.pug
│ │ └─ index.pug
│ ├─ style
│ ├─ js
│ └─ images
└─ dist
  ├─ css
  ├─ js
  ├─ images
  ├─ about
  │  └─ index.pug
  └─ index.html
```
## 実行コマンド
```
npm run start //開発
npm run build //本番
```

## webpack書き方注意

- module内のuseの読み込みは上からではなく下から上に読み込み進んでいく
- vueを入れる場合はバージョンによって書き方が変わる
Rubocopの導入方法

# Rubocopとは
RubocopはRubyの静的コード解析ツールです。「インデントが揃っていない」「余分な改行・スペースがある」などの指摘をRubyStyleGuideに基づいて行ってくれます。

# Rubocopを導入
Gemfileに以下を追記する。
```
group :development do
  gem 'rubocop', require: false
end
```
```
bundle install
```
```
touch .rubocop.yml
```
.rubocop.ymlに以下を記載する。（コピペ推奨）
```
AllCops:
# 除外するディレクトリ（自動生成されたファイル）
# デフォルト設定にある"vendor/**/*"が無効化されないように記述
 Exclude:
   - "vendor/**/*" # rubocop config/default.yml
   - "db/**/*"
   - "config/**/*"
   - "bin/*"
   - "node_modules/**/*"
   - "Gemfile"


# 1行あたりの文字数をチェックする
Layout/LineLength:
 Max: 130
# 下記ファイルはチェックの対象から外す
 Exclude:
   - "Rakefile"
   - "spec/rails_helper.rb"
   - "spec/spec_helper.rb"

# RSpecは1つのブロックあたりの行数が多くなるため、チェックの除外から外す
# ブロック内の行数をチェックする
Metrics/BlockLength:
 Exclude:
   - "spec/**/*"

# Assignment: 変数への代入
# Branch: メソッド呼び出し
# Condition: 条件文
# 上記項目をRubocopが計算して基準値を超えると警告を出す（上記頭文字をとって'Abc'）
Metrics/AbcSize:
 Max: 50

# メソッドの中身が複雑になっていないか、Rubocopが計算して基準値を超えると警告を出す
Metrics/PerceivedComplexity:
 Max: 8

# 循環的複雑度が高すぎないかをチェック（ifやforなどを1メソッド内で使いすぎている）
Metrics/CyclomaticComplexity:
 Max: 10

# メソッドの行数が多すぎないかをチェック
Metrics/MethodLength:
 Max: 30

# ネストが深すぎないかをチェック（if文のネストもチェック）
Metrics/BlockNesting:
 Max: 5

# クラスの行数をチェック（無効）
Metrics/ClassLength:
 Enabled: false

# 空メソッドの場合に、1行のスタイルにしない　NG例：def style1; end
Style/EmptyMethod:
 EnforcedStyle: expanded

# クラス内にクラスが定義されていないかチェック（無効）
Style/ClassAndModuleChildren:
 Enabled: false

# 日本語でのコメントを許可
Style/AsciiComments:
 Enabled: false

# クラスやモジュール定義前に、それらの説明書きがあるかをチェック（無効）
Style/Documentation:
 Enabled: false

# ％i（）構文を使用していないシンボルで構成される配列リテラルをチェック（無効）
Style/SymbolArray:
 Enabled: false

# 文字列に値が代入されて変わっていないかチェック（無効）
Style/FrozenStringLiteralComment:
 Enabled: false

# メソッドパラメータ名の最小文字数を設定
Naming/MethodParameterName:
 MinNameLength: 1
```

Rubocopには、他にも以下のようなデフォルトの標準設定がしてあります（一部抜粋）
| Rubocop |標準設定 | 備考 |
|:-----------|------------:|:------------:|
| 文字列       | シングルクォーテーション|式展開や文字列内にシングルクォーテーションがある場合はダブルクォーテーションを使います|
| 変数名とメソッド名| スネークケースで定義する|      |

デフォルトの設定内容の詳細は、RubocopのGitHubにある[default.yml](https://github.com/rubocop/rubocop/blob/master/config/default.yml)のファイルの中身から確認することができます。

# Rubocopを実行
Rubocopを実行するにはターミナルで以下のコマンドを実行します。
```
bundle exec rubocop
```
チェック内容を自動で修正させることもできます。
```
bundle exec rubocop -a
```
ユーザー登録機能の実装


# 実装準備

Gemfileの最後の行に記載する
```
gem 'devise'
```
Gemをインストールする(ターミナル)
```
bundle install
```
サーバーを起動する（反映するタイミングがサーバー起動時）(ターミナル)
```
rails s
```

追加したdeviseというGemの「設定関連に使用するファイル」を自動で生成する(ターミナル)
```
rails g devise:install
```

deviseのUserモデルを作成する(ターミナル）
```
rails g devise user
```
routes.rbに以下のルーティングが自動的に追記されているかを確認する。
```
devise_for :users
```
# テーブルの作成
下記ファイルが作成されている
db/migrate/20XXXXXXXXX_devise_create_users.rb
どのようなテーブルを作るか確認＆追記をする。


マイグレーションの実行
```
rails db:migrate
```
（Sequel Proでusersテーブルを確認）

一度ローカルサーバーを再起動する
```
rails s
```

# deviseのビューファイルの作成
```
rails g devise:views
```

編集をする
「※サインアップ画面はapp/views/devise/registrations/new.html.erb、
　　ログイン画面のビューはapp/views/devise/sessions/new.html.erbというビューファイルが対応しています。」



``maxlengthオプション``(文字数規制)をつけ、入力フォームに追記する（○○はカラム名）
```
      <div class="field">
        <%= f.label :○○○○ %> <em>(6 characters maximum)</em><br />
        <%= f.text_field :○○○○, autofocus: true, maxlength: "6" %>
      </div>
```
※ ↑の``autofocus: true,``を入れるとそこの入力欄が入力待ちになった状態でページが開かれる。。


# コントローラーの編集
```
before_action :configure_permitted_parameters, if: :devise_controller?

  private
  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:○○○○])
  end

```
ソフトウェア開発の基礎

# 目次
1. [ソフトウェアとは](#ソフトウェアとは)
1. [ソフトウェアの種類](#ソフトウェアの種類)
1. [ソフトウェア開発の主な手法](#ソフトウェア開発の主な手法)

# ソフトウェアとは
「コンピュータに対し命令を出すプログラム」を指す言葉

# ソフトウェアの種類
1. [基本ソフトウェア](#基本ソフトウェア)
1. [応用ソフトウェア](#応用ソフトウェア)

### 基本ソフトウェア
別名「**OS**」。アプリケーションが動作するベースとなるプログラムを指す

▼基本ソフトウェアの例(PC)
・Windows
・macOS
・Linux

▼基本ソフトウェアの例(スマホ)
・iOS
・Android

### 応用ソフトウェア
別名「**アプリケーションソフトウェア**」。基本ソフトウェア上で動作するソフトウェア。
特定のタスクを実行するための手段として使うソフトウェアで、パソコンに直接インストールするできるソフトや、インストールなしでWebブラウザ上で動作するソフトもある。

▼応用ソフトウェアの例
・チャットツール
・インターネットブラウザ
・セキュリティソフト

<a href="https://ibb.co/DWtTZDs"><img src="https://i.ibb.co/CBVXrLs/c-2104-031-01-1024x805-png.webp" alt="c-2104-031-01-1024x805-png" border="0"></a>


# ソフトウェア開発の主な手法
1. [ウォーターフォール開発](#ウォーターフォール開発)
1. [アジャイル開発](#アジャイル開発)
1. [ウォーターフォール開発とアジャイル開発の違い](#ウォーターフォール開発とアジャイル開発の違い)
1. [どの手法を採用するべきか](#どの手法を採用するべきか)

### ウォーターフォール開発
**▼概要**
上流⇒中流⇒下流と、一方向に開発工程を進める手法
決まった期間で行う為、工数清算や人員確保がしやすく、品質を一定レベルに保つことが出来る
**▼メリット**
１）PMにとって全体進捗を把握しやすく管理しやすい
２）性質上、上流段階から詳細に認識合わせをするため、進行度を容易に図ることが出来る
**▼デメリット**
１）要件がきちんと把握できていなかった場合、やり直しが難しい
２）手戻りが発生すると工数が増える
**手法を正しく行う為に必要なこと**
途中からユーザーの意見を取り入れにくいため、要件定義の段階で入念な仕様の確認が求められる。

<a href="https://ibb.co/ggrQKdV"><img src="https://i.ibb.co/nkw4JBC/c-2104-031-02-1024x624-png.webp" alt="c-2104-031-02-1024x624-png" border="0"><img src="https://i.ibb.co/1fdvnK9/c-2104-031-03-1024x624-png.webp" alt="c-2104-031-03-1024x624-png" border="0"></a>


### アジャイル開発
**▼概要**
小さな機能ごとに上流から下流までの工程を進めていく手法
一ヶ月程度で企画からテスト検証まで行い、次の機能に取りかかる為スピード感がある
**▼メリット**
１）小さな単位で開発をしている為、不具合があっても戻る工程が少ない
２）開発途中でユーザーとフィードバックを行い確認をしながら進めることが出来る
**▼デメリット**
仕様・要件ごとにスケジュールを設定する為、全体のスケジュールや進捗具合が把握しずらい

### ウォーターフォール開発とアジャイル開発の違い
<img src="https://www.qbook.jp/column/blogimages/0634df6e29389885ede41e9425423430_1.png">


### どの手法を採用するべきか
プロジェクトの**目的**や**規模**に合わせて適切な開発モデルを選択することが大切

**▼ウォーターフォール開発**
**大規模プロジェクト向け**
メリットである開発・完成への<font color="red">**共通認識の深めやすさ**</font>やスケジュールなどの<font color="red">**全体管理のしやすさ**</font>は大規模プロジェクトでは中心的に使われる手法とされる

**▼アジャイル開発**
**小規模な開発向け**
メリットである<font color="red">**進行途中のフットワークの軽さ**</font>は、少人数の開発向けの手法とされる
AWS未経験者がAWS Certified Machine Learning - Specialtyに1.5ヵ月で合格する方法

# はじめに
筆者はAWS使用経験はゼロの初心者(GCPは少し触ったことある程度)ですが、先日AWS Certified Machine Learning - Specialtyに合格できたので、合格までの道筋を共有します
generalist向けの試験と比べると、specialty試験についての情報は比較的少ないので、記録に残そうと思いました

本記事の対象者
【AWSがそもそも何なのかよくわからない/業務でガッツリ使用したことはない】が
【自己研鑽やスキルアピール等、何等かの目的で、機械学習関連の資格取得に興味がある】人

正直、初めてサンプル問題を解いたときは、データサイエンスの知識問題は解けるものもあったものの、GCP関連の問題がさっぱりわかりませんでした
ですが、そんな人でもなんとか1.5ヵ月で合格水準まで達することが出来たので、参考になれば幸いです

# AWS Certified Machine Learning - Specialtyの基本情報
時間: 試験完了までに 180 分
コスト: 300 USD 
問題数: 65問
https://aws.amazon.com/jp/certification/certified-machine-learning-specialty/

体感としては機械学習関連の知識問題とGCPのサービスに関する知識問題が半々ぐらいに出題されていたと思います（アバウトですみません）

そのため、GCPサービスの利用経験者または機械学習の実装経験者は知識のベースがあるので若干有利ですが、ベースが無い人でも問題演習等でカバー可能な範囲内だと思います

# 合格までにやったこと
最も最速で合格をゲットするならば、【問題を解きまくる】につきます

本来は講義動画や公式ドキュメント、ハンズオンでの実践等を通して、基礎の理解から丁寧に知識を積み上げ、学習を進めることが理想であると思いますが、これには非常に時間が掛かりますし、学習スケジュールの組み立てや管理も少し大変です

そこで、【限られたスケジュールの中で試験に合格すること】を最優先とし、頻出出題パターンの解を頭に叩き込むことで、頻出問題で確実にスコアを稼ぐことを目指します

具体的に取り組んだものは

①AWS公式サンプル問題を解く(10問×2回)

実際の問題に最も近いので、手始めにこちらの問題を解き、出題傾向を把握すると良いと思います
https://d1.awsstatic.com/ja_JP/training-and-certification/docs-ml/AWS-Certified-Machine-Learning-Specialty_Sample-Questions.pdf

②Udemyの予想問題を解く(10問×1回, 65問×2回 / 4時間ほど)

他の問題集でも良いと思いますが、私は以下のリンクの問題集を利用しました
Udemyはレビュー数や☆スコアが確認できるので、評価が良いものを購入すれば良いと思います
英語版なので、必要に応じてgoogle翻訳等を使うと便利です

https://www.udemy.com/course/aws-machine-learning-practice-exam/

知らない単語等が出てくれば都度調べることで、徐々にAWSへの理解が深まります
（初回は50%、2回目は80%の正解率でした）
 
③pass4testのテスト(210問×1回 / 8時間ほど)
レビュー等が無い海外サイトの購入になるので少し不安でしたが、問題の内容等は実際の試験と大きく乖離は無く、結果としては購入して正解でした
時間が足りず、こちらは一周しか解いていません

※注意点としては、PDF版ではなく、PCテストエンジンまたはオンラインテストエンジンのオプションを付けた方が良いということです（私はPDF版で購入したのですが、スクロール時に答えが視界に入ってしまうので、操作性が非常に悪く後悔しました）

https://www.pass4test.com/AWS-Certified-Machine-Learning-Specialty-exam-questions.html

# 試験当日について

65問を解くのに3時間も時間が与えられるので、たっぷり時間を掛けて解くことができます
自分の場合は試験の数時間後に試験の関連会社?からメールが届き、合格の通知が来ました
さらに、試験の2日後にはAmazonから正式に合格の通知メールが届きます

試験後はAWSの他の試験にも使える50％割引バウチャーがもらえるので、また別の試験にもチャレンジしたいですね
JestでLocalStorageのモックテストを行う際の問題解決

# 課題

JavaScriptのテストフレームワークであるJestを使用してLocalStorageの処理のテストを実施しようとしたところ、下記のようなエラーが出てうまくいかない。

エラー１：
TypeError: jest.spyOn(...).mockImplementation is not a function
エラー２：
SecurityError: localStorage is not available for opaque origins

# 解決方法
* jest-environment-jsdomをインストール、設定
* LocalStorageのメソッドを直接spyするのではなく、`Storage.prototype`をspyする

# 詳しい手順・実装内容

以下の実装により問題を解決しました：

まず、LocalStorageのメソッドを直接spyするのではなく、`Storage.prototype`をspyする方法に切り替えました。
これにより、`TypeError: jest.spyOn(...).mockImplementation is not a function`というエラーが解消しました。

```javascript
jest.spyOn(Storage.prototype, "setItem").mockImplementation(jest.fn());
jest.spyOn(Storage.prototype, "getItem").mockImplementation((key) => {
  return mock_value;
});

expect(Storage.prototype.setItem).toHaveBeenCalledWith(
  "mock_key",
  "mock_value"
);
```

次に、"SecurityError: localStorage is not available for opaque origins"ですが、ググってみると設定ファイルにtestURLを指定すれば解決するという[記事](https://qiita.com/knaot0/items/8292ffd43f0cfe640c0b)を見つけましたが、testURLを指定するとワーニングが出てうまくいきませんでした（Jestのバージョンは29.6.1）

```
Deprecation Warning:
Option "testURL" was replaced by passing the URL via "testEnvironmentOptions.url".
Please update your configuration.
```
色々調べた結果、jest-environment-jsdomを使うことで解決ができました。

まず、インストール
```bash
npm i jest-environment-jsdom
```

その後、jestの設定ファイルに下記を設定
```javascript
module.exports = {
  testEnvironment: "jsdom",
};
```

これで先のテストコードと合わせて無事にテストを実施することができました。
アドフリくん実装方法の紹介

アプリに動画リワード広告を導入するにあたって、アドフリくんを導入することになりましたので実装方法について、ご紹介します。

## 1. インポートの設定
```swift
import ADFMovieReward
```

## 2. インスタンスの設定
```swift
class ViewController: UIViewController {
    var movieAd: ADFmyMovieReward?

    override func viewDidLoad() {
        self.movieAd = ADFmyMovieReward.getInstance("IDを入れる", delegate: self)
    }
}
```

## 3.動画の再生
・再生の準備ができているか確認し、再生する。
・動画が再生されたら、カウントを0に戻す。
・読み込みができない際は、1秒待ってから再度トライする。
・20回トライしても広告を読み込めなかった場合は、エラーのアラートを表示してカウントを0に戻す。
```swift
    var tryCount = 0 
    
    func movieNow() {
        if !SVProgressHUD.isVisible() {
            SVProgressHUD.show()
        }
        
        if tryCount > 20 {
            SVProgressHUD.dismiss()
            // 20回超えたのでカウントを0に戻す
            tryCount = 0
            AlertControllerHelper.defaultOnly(viewController: self, title: "エラー", message: "動画の読み込みに失敗しました。時間をおいて再度試してみてください。", defaultButtonText: "OK", complication: nil)
            return
        }
        
        if ADFmyMovieReward.isSupportedOSVersion() {
            // 再生の準備ができているか確認し、再生する。
            if let movieAd = self.movieAd {
                if movieAd.isPrepared() {
                    SVProgressHUD.dismiss()
                    // 再生されたらカウントを0に戻す
                    tryCount = 0
                    movieAd.play(withPresenting: self)
                } else {
                    tryCount += 1
                    // 読み込みができない際は、1秒待ってから再度トライする。
                    Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(movieNow), userInfo: nil, repeats: false)
                }
            }
        } else {
            SVProgressHUD.dismiss()
        }
    }
```

## 全体のコード
```swift:ViewController.swift
import ADFMovieReward

class ViewController: UIViewController {
    var movieAd: ADFmyMovieReward?
    var tryCount = 0

    override func viewDidLoad() {
        self.movieAd = ADFmyMovieReward.getInstance("IDを入れる", delegate: self)
    }
    
    @IBaction func onAdButtonTapped(_ sender: Any) {
        movieNow()
    }

    func movieNow() {
        if !SVProgressHUD.isVisible() {
            SVProgressHUD.show()
        }
        
        if tryCount > 20 {
            SVProgressHUD.dismiss()
            tryCount = 0
            AlertControllerHelper.defaultOnly(viewController: self, title: "エラー", message: "動画の読み込みに失敗しました。時間をおいて再度試してみてください。", defaultButtonText: "OK", complication: nil)
            return
        }
        
        if ADFmyMovieReward.isSupportedOSVersion() {
            if let movieAd = self.movieAd {
                if movieAd.isPrepared() {
                    SVProgressHUD.dismiss()
                    tryCount = 0
                    movieAd.play(withPresenting: self)
                } else {
                    tryCount += 1
                    Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(movieNow), userInfo: nil, repeats: false)
                }
            }
        } else {
            SVProgressHUD.dismiss()
        }
    }
}
```
タスク管理　コンテキスト切り替え

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/6e62b031-01b7-1a0b-0ea6-04e15b061951.png)
　コントテキスト切り替えとは、実行状態のタスクを切り替えることです。切り替えの方式には、プリエンプティブ、ノンプリエンプティブ方式があります。

１：プリエンプティブ方式
　「待ち時間（タイムスライス）切れ」や「優先度の高いタスク」が実行可能状態になった」というきっかけで、OSが強制的に介入し、実行状態のタスクを別のタスクに切り替える方式です。このようなきっかけをプリエンプションと言います。

　OSが強制的に介入してタスクを切り替えるため、タスクが異常な動作（暴走）をしたとしても、他のタスクに切り替わります。この結果、他のタスクは何事もなく実行状態に移り、処理が進みます。つまり、あるタスクがプログラムの不備（バグ）により暴走したとしても、他のタスクには何も影響を与えず、システム全体が停止してしまうような事態にはなりません。

　現在、私たちが利用しているOS（Windows、MacOS、Linuxなd）は、プリエンプティブ方式を採用しています。

２：ノンプリエンプティブ方法式
　タスクが自らCPUを手放して、タスクを切り替える方式です。OSが強制的に介入する仕組みを実装しなくて良い分、OS本体を簡略化できます。
　一方、タスクが異常な動作（暴走）をすると、みずからCPUを手放すことは無くなりますから、他のタスクは実行状態に移れなくなります。この結果、あるタスクがプログラムの不備（バグ）により暴走すると、システム全体が停止てしまう状態となります。
ExtendScript Toolkit(ESTK)のダウンロード先のリンク

最近のAdobeスクリプトのデバッグには、VSCodeの拡張機能である「ExtendScript Debugger」を使うと思います。

https://marketplace.visualstudio.com/items?itemName=Adobe.extendscript-debug

ただ、昔、旧ツールである **ExtendScript Toolkit(ESTK)** のダウンロード先を探したことがあったので、ツールのダウンロード先のリンクを忘れないように記録しようと思います。

・Adobe-CEP

https://github.com/Adobe-CEP/CEP-Resources/tree/master/ExtendScript-Toolkit

・Adobe Support Community

https://community.adobe.com/t5/download-install-discussions/how-can-i-download-extendscript-toolkit-for-cs6-in-the-creative-cloud/td-p/4564136
AutoHotkey

## はじめに
pythonなど勉強中。ハードからソフトまで。
現時点はchatGPTを中心に勉強中。
初学者です。前向きに進んでいます。
アドバイスなどあればぜひお願いします。

## 目的
省人化もとい、自分の生産性向上を目指すために
chatGPTといつもどおり会話していたところ、AutoHotkeyの話がでる。
調査したところ、これは・・・と脱線。。

なお以下サイトを参考にさせていただきました。
感謝します。

https://linuxfan.info/windows-emacs-keybindings

https://qiita.com/ryoheiszk/items/092cc5d76838cb5a13f1

## AutoHotkeyとは
chatGPT先生曰く、「AutoHotkeyは、あなたのキーボードとマウスに魔法をかけて、「私の意のままに！」と叫ぶ自由奔放なウィザードです。」だそうです。

素敵ですね。

## どんなことができる？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448426/9d3e6b96-cd70-a1fb-f710-4070a634512d.png)

これは面白い。今まではpuautoguiを用いてごりごりやっていたのをもっと完結にできる？（RPAはこちらも方が速いのか？)
やってみる価値はありそう。
生産性向上に申し分なし。

## 暫定OUTPUT
キーバインドをemacs風に
また一部引用などをショートカットを活用
＊実際、コマンドを理解する必要があるため、
　emacs統一はありがたい。。

他にも辞書てきなことができたり、複雑なことも可能だが
まずはここまで。
ChatGPT Pluginを触ってみる

created by en-japan Yue.Pu

## ChatGPT Pluginとは
https://openai.com/blog/chatgpt-plugins
<font color="red">現時点では課金アカウントしか使えません</font>
* 公式的Doc:
https://platform.openai.com/docs/plugins/introduction
* サンプルpluginのGitリポジトリ:
https://github.com/openai/plugins-quickstart​
サンプル簡単なTodo Listリポジトリです。
リポジトリ中に作業必要なファイルが以下4つ:
![截屏2023-07-12 20.16.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456096/f5f2bd04-2064-138f-7abf-1f7a81f96fa9.png)
- Main.py：メインのエントリーファイルであり、プラグインのルートやリクエストの処理ロジックを定義する役割を担います。このファイルでは、プラグインのインターフェースとそれに対応する処理関数を定義し、ChatGPTからのリクエストを処理し、適切なレスポンスを返すことができます。​
- Requirements.txt：必要とする依存関係とバージョン情報が記載されています。正しい依存関係を指定することで、プラグインが実行時に必要なライブラリやモジュールを持つことができます。​
- Openapi.yaml：OpenAPI仕様に準拠したファイルであり、プラグインのインターフェースや関連情報（パス、パラメータ、リクエストボディ、レスポンスなど）を記述します。これは、プラグインのAPIを文書化し、他の開発者がプラグインのAPIを理解し、使用するためのツールとして利用できます。​
- ai-plugin.json:プラグインのメタデータと設定情報を定義することです。これは特定の形式に従ったJSONファイルであり、プラグインの属性、機能、その他の関連情報を記述するために使用されます。​

## 使ってみよう
環境:macOS
* (option)python仮想環境を作り
    * ソフトをインストール
        * pip install virtualenv
    * 仮想環境を作り
        * virtualenv myEnv
        * cd myEnv
    * 環境を接続
        * source bin/activate
* リポジトリをclone
    * git clone git@github.com:openai/plugins-quickstart.git
    * cd plugins-quickstart
* Readme通りSetup
    * pip install -r requirements.txt
    * python main.py
* plugin機能をオン
    * GPTのサイトを開け、ログインする。https://chat.openai.com
    * 左下の3点→「Settings」をクリックします。「Beta features」をクリックし、[Plugins]の右にあるトグルボタンをクリック
    * TOP画面に戻り、[New chat]をクリックし、「GPT-4」をクリックし「Plugins」をクリックします。
    * その直下の[Plugin store]をクリックし、右下の「Develop your own plugin」を押します。
    * Enter your website domain画面でhttp://localhost:5003を入力します。
    * [Find manifest file]を押すと接続できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456096/d8c012b6-75ff-68c4-b8c0-74fa8d2c6e05.png)

## サンプルpluginを使ってみましょう
> これからやりたいことを記録ください。
18時に買い物
19時に食事
20時に遊ぶ
21時に寝る

> 今日のスケジュールは何?

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456096/4456dd3d-059e-b888-aa36-9d9646a164bb.png)

> 22時の予定を追加したい
22時に友達に電話する

> 今日のスケジュールは?

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456096/b8f86c88-b172-50a2-043c-f18f69b116a1.png)

# 終わり・感想
サンプルpluginの処理部分は簡単なので、plugin内で全部できますが、
普通は、APIを呼び出す機能をpluginに入れます。chatGPTはpluginを経由して、特定のサーバーにアクセスします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3456096/fd7a2d09-30ca-4ff6-4308-cf4d5a401087.png)

​

​

​
TSLintをコマンドで実行する

## きっかけ
node.js/Angularの開発でTSLintを導入しています。
全体をまるっと出力してファイルごとにチェック結果を見たい！と思って実行コマンドを調べた備忘録です。
※インストール／設定ファイル等はPJの都合で設定済でした。

## こうした
VSCodeのターミナルから下記のコマンドを実行
```powershell:コマンド
ng lint > ./result.txt
```

ソースファイルが多いとコンソールをはみ出るので適当なファイルに吐いて、
ごにょごにょしました。

:::note warn
※記事投稿時点でTSLintは非推奨です。特にこだわりがない場合はESLintなど別のリンカーの利用を検討してください。
【Android】GoogleMapの専用UIの位置を変える【Kotlin】

# はじめに
GoogleMapを用いたアプリでは　GoogleMapUIがあり、GoogleMapの操作をUI行うことができます。
ズーム、コンパス表示、現在地ボタン、屋内で使われる階層別で表示できるレベルピッカー、マーカーをタップした時に現れるマップツールバー　などがあり　基本的にマップの上端、下端、左端、右端の位置に表示されます。
詳しくは　分かりやすくまとめてくれている記事やAndroid公式を見てもらえればと思います。

今回は、その表示位置を変更する方法を記事に残しておこうと思います。

# 実践
公式では、

>コントロールを上端、下端、左端、または右端から移動するには、GoogleMap オブジェクトにパディングを追加します。


とあります。


```
 googleMap.setPadding(0,0,0,0)
```
引数には　第一引数から順に　left,top,right,bottom　の順に入れていきます。



# 参考

https://developers.google.com/maps/documentation/android-sdk/controls?hl=j


https://qiita.com/unpi/items/07592c2643d655ec51a2