OmniAICreator/Qiita-1.07M huggingface dataset:
Google Apps ScriptでChatworkのBotを作成してみた

# きっかけ

弁当の注文を紙で運用していたが、数える手間や、注文し忘れたまま
誤って他の人の弁当を食べてしまう問題が発生していたため、
Chatworkのリアクションを活用して改善することになった。

# 事前準備

API Tokenを発行する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627583/8dab8994-10b7-342d-7e31-b52087227c4f.png)

ルームIDを確認する(URLの#!rid以降)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627583/de304bba-6197-14e1-842f-34e218b6a2cc.png)

# 作成手順

Googleドライブで「Google Apps Script」をクリックする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627583/85d0f9ed-02e7-c589-46e4-24e43b1e561c.png)

ライブラリの＋をクリックし、スクリプトIDを入力→検索→追加
スクリプトIDは下記

```
1nf253qsOnZ-RcdcFu1Y2v4pGwTuuDxN5EbuvKEZprBWg764tjwA5fLav
```

GitHubにも記載されている

https://github.com/cw-shibuya/chatwork-client-gas

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627583/f62d75ed-bb0f-aecb-bbe7-711ab1a9969c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627583/aaf30078-10bf-712f-4353-6645280d545d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627583/afbf21a2-86a4-216a-dad3-dce51ce6eeca.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627583/582d574b-3adc-ad6e-bc82-ab16c90adf13.png)

ライブラリに「ChatWorkClient」が追加された

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627583/b2490aea-d206-3940-cc6c-cd3e6abcfcb3.png)

# 実装サンプル

```js
function main() {
    var client = ChatWorkClient.factory({token: 'API Token'});
    client.sendMessage({room_id: 000000000, body: "メッセージ"});
}
```

# その他

メッセージに装飾タグを付けることができる

https://go.chatwork.com/ja/column/usage/usage-010.html
典型90問006 Smallest SubsequenceをPythonで解く！

# はじめに
AtCoder現在茶色(年内には緑が目標！）のあんこちゃん(@Chunky_RBP_chan)です。
典型問題は抑えとかねばということで、★2〜★5に取り組んでいます。
Pythonで取り組まれている方も多いと思うので自分の解答をシェアしたいと思います！

# 問題
https://atcoder.jp/contests/typical90/tasks/typical90_f

# 解法
入力
N K
S
に対して、まずN-K文字目までをheappushし、その後N文字目まで次の操作を繰り返すことで答えが得られます。

**操作**
①N-(K-1)<=i<=Nを満たすiに対して、各iごとにSのi文字目をheappushする。
②以前でた文字より右にあるものが取り出されるまでheappopし続ける。
③取り出された文字を以前出た文字の右に付け加える。


## なぜうまくいくか
$N=5、K=3、S=a_1a_2a_3a_4a_5$のとき
答えの文字列が$b_1b_2b_3$とすると
$b_1$は必ず$a_1、a_2、a_3$の中にあります。なぜなら$b_1=a_4$であれば$b_2=a_5$であり、$b_3$は存在しなくなるからです。
今$b_1=a_2$だとすると$b_2$は$a_2$より右側にある辞書順が早い文字なので$a_3、a_4$のどちらかです。
しかし、$b_2$を選ぶ前heapqには$a_1、a_3、a_4$が入っているため、$a_1$が出た場合はもう一度heappopすれば$a_3、a_4$から$b_2$を選べます。
以上から、
①N-(K-1)<=i<=Nを満たすiに対して、各iごとにSのi文字目をheappushする。
②以前でた文字より右にあるものが取り出されるまでheappopし続ける。
③取り出された文字を以前出た文字の右に付け加える。
の操作を繰り返すことで答えの文字列が得られます。



```python
import heapq

N,K = map(int, input().split())
S = input()
Q = []
for i in range(N-K):
    heapq.heappush(Q,(S[i],i))
pre_ind = -1
ans = ''
for i in range(N-K,N):
    heapq.heappush(Q,(S[i],i))
    while True:
        st,ind = heapq.heappop(Q)
        if ind > pre_ind:
            ans = ans + st
            pre_ind = ind
            break
print(ans)
「Stringを==とequalsで比較する際の違いを教えてください」と面接官に言われたら


面接官「Stringを==とequalsで比較する際の違いを教えてください」

自分「== はインスタンスの同一性を比較する一方、equalsはObjectによって定義されるメソッドで、同値性の比較に使われます。」

自分「従ってStringを比較するとき、==では同じ文字列でも違うインスンスの場合にfalseが返って来てしまうことがあるため、通常はequalsを使用します。」

面接官「はい、完璧です。」

自分「より詳細に言うと、Stringを定数として使用する場合はJVMのLDC命令によって定数プールからインスタンスが確保されるため、これら定数プールの文字列を比較する場合は==でもtrueが返ってきます。」

自分「逆に、文字列をプログラムで動的に構築する場合は定数プールとは関係ない全く新しいStringインスタンスが構築されるため、==はfalseとなります。」

面接「なるほど。」

## String Constant Pool（文字列定数プール）とは

Javaで文字列リテラルを表現する場合、文字列は定数プールから確保される。これにより、同じ文字列が登場した場合にメモリの使用量を削減することができる。

```java
String a = "test";
String b = "test";

System.out.println(a == b); // true
```

ただし、文字列をプログラムで動的に構築する場合は新しくStringインスタンスが構築される。

```java
String a = "t";
String b = "t";
for(int i = 0; i < 3; i++) {
    a += "e";
    b += "e";
}

System.out.println(a == b); // false
```

---

自分「以上によりStringは==で比較できないわけですが、String#internメソッドを使用することで、文字列を明示的に定数プールに格納することができます。これにより、LDC命令により確保された文字列と動的に確保された文字列を==で比較することが可能になります。」

面接官「（へぇー）」

自分「今、internメソッドなんて使ったことないしどうでもいい、そう考えましたね？確かに文字列を==で比較するためにわざわざinternメソッドを使用することはありません。ですがsynchronizedとinternを組み合わせることで、複雑な同期処理が簡単にできるようになる場合があります。」

面接官「（この人怖い...）」

## String#internとは

Javadocより抜粋
```
public String intern()

文字列オブジェクトの正準表現を返します。
文字列のプールは、初期状態では空で、クラスStringによってプライベートに保持されます。

internメソッドが呼び出されたときに、equals(Object)メソッドによってこのStringオブジェクトに等しいと判定される文字列がプールにすでにあった場合は、プール内の該当する文字列が返されます。そうでない場合は、このStringオブジェクトがプールに追加され、このStringオブジェクトへの参照が返されます。

したがって、任意の2つの文字列sとtについて、s.intern() == t.intern()がtrueになるのは、s.equals(t)がtrueの場合だけです。
```

どういうことかというと、internを呼び出したとき

1. 文字列が定数プールにあるか確認
2. ある場合は定数プールの文字列を返す。ない場合は定数プールに文字列を追加してStringを返す。

という挙動になる。以下のコードを見て欲しい。

```java
String a = "teee";
String b = "t";
for(int i = 0; i < 3; i++) {
    b += "e";
}

System.out.println(a == b.intern()); // true
```

このコードでは一見falseを表示すると思うかもしれないが、実際のところteeeという文字列は変数aを宣言した時点で定数プールに格納されているので、b#internを呼び出すとaが返ってくる。従ってこの場合はtrueになる。

これになんの意味があるのかと思うのかもしれないが、internはsynchronizedと組み合わせることで真価を発揮する。例えばファイルにデータをスレッドセーフに保存するようなメソッドを考えてみて欲しい。

```java
public synchronized void saveData(Path path, String contents) throws IOException {
    Files.writeString(path, contents);
}
```

これでも動くことは動く。だがよく考えてみれば、もしファイルが違うのであればsynchronizedによってロックをかける必要はない。そこでString#internを使う方法がある。

```java
public void saveData(Path path, String contents) throws IOException {
    String absolutePath = path.toAbsolutePath().normalize().toString();
    synchronized ((getClass().getCanonicalName() + "-" + absolutePath).intern()) {
        Files.writeString(path, contents);
    }
}
```

このように書くことで、absolutePathが同じであればsynchronizedによるブロックが発生し、そうでなければブロックは発生しない。これにより簡潔で効率的な同期処理が可能となる。

ここで
```
getClass().getCanonicalName()
```
を呼び出しているのは、absolutePathだけだともしかしたら他のライブラリ等によってロックとして利用されている可能性があり、最悪の場合デッドロックが発生する可能性があるためである。getClass().getCanonicalName()等の文字列を前後に連結させることで、デッドロックが発生する可能性を事実上0にできる。

だがレビュアーに何か言われたりメンバーが混乱するようであれば、大人しく

```java
Set<String> lock = Collections.newSetFromMap(new ConcurrentHashMap<>());
```

を使った実装に書き換えたほうが良いかもしれない。
CSVファイルと同じ名前のディレクトリを作成しCSVファイルを格納

```python
import shutil
import os

for f in os.listdir(path='.'):
    if os.path.splitext(f)[1]=='.csv':
        dir_name=os.path.splitext(f)[0]
        os.mkdir(dir_name)
        shutil.move(f, dir_name)
```
Laravel + Docker + PHPUnit + GitHubActions テストカバレッジをPRに出力する

# 概要

先日、[phperkaigi2022](https://phperkaigi.jp/2022/)に参加してテスト結果の見える化とテスト文化を根付かせるための活動がよかったので、実際に導入してみた

なお、ワークフローについてもっと良い方法をご存知の方は、マサカリいただけると助かります

https://speakerdeck.com/twada/growing-reliable-code-phperkaigi-2022

https://speakerdeck.com/kazatohiei/phperkaigi2022?slide=33

https://zenn.dev/ysit/articles/github-actions-test-summary

# やり方

## ワークフローを定義します

カバレッジを全て表示すると見づらいので必要な箇所だけを切り取りしてPRコメントに出力するようにします

![スクリーンショット 2022-04-13 1.05.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555632/39fd7965-6516-fa12-6735-c8b5807ec9c6.png)

## ブラウザ上でカバレッジを見たい場合

出力形式はいくつかあるので公式を参考に設定ください

https://phpunit.readthedocs.io/ja/latest/textui.html#textui-clioptions

HTML形式で出力したい場合は以下のコマンドをLaravelコンテナ内で実行してください

```bash
phpdbg -qrr ./vendor/bin/phpunit --coverage-html  ./coverage
``` 

## 解説

MySQLコンテナ起動後、実行するまでに時間を要しますがテストが先に開始されると`Connection Refused`で接続ができません。

今回は3分弱時間を置いてからテストプロセスに進めるように設定しました

https://stackoverflow.com/questions/62446815/docker-mysql-github-actions-connection-refused

```yml
docker-compose exec -T laravel bash -c "sleep 200"
```

ワークフローの実行契機を設定します

今回は`main`ブランチにプルリクエストを発行すると実行されるトリガーを設定します

```yml
on:
  # PR契機
  pull_request:
    branches: [ main ]
```


```yml:.github/workflows/test.yml
name: PhpUnitCoverage

on:
  # PR契機
  pull_request:
    branches: [ main ]

jobs:
  build:
    # 実行環境
    runs-on: ubuntu-latest
    steps:
      # $GITHUB_WORKSPACE配下のリポジトリをチェックアウトしてアクセス可能にする
      - uses: actions/checkout@v2

      - name: dokcer-compose Laravel Init
        run: |
          docker-compose up -d
          docker-compose exec -T laravel bash -c "composer install"
          docker-compose exec -T laravel bash -c "cp .env.example .env"
          docker-compose exec -T laravel bash -c "php artisan key:generate"
          docker-compose exec -T laravel bash -c "php artisan config:cache"
          docker-compose exec -T laravel bash -c "sleep 200"

      - name: Exec Phpunit
        run: |
          docker-compose exec -T laravel bash -c "phpdbg -qrr ./vendor/bin/phpunit --coverage-text --colors=never > storage/logs/coverage.log"
          docker-compose exec -T laravel bash -c "cat storage/logs/coverage.log"

      - name: Cat Test Result
        run: |
          cat ./src/laravel/storage/logs/coverage.log
        if: ${{ failure() }}

      - name: Sed Coverage Report
        run: |
          sed -E "s/"$'\E'"\[([0-9]{1,2}(;[0-9]{1,2})*)?m//g" | \
          grep "Code Coverage Report:" -A6 ./src/laravel/storage/logs/coverage.log | sed -e "s/^ *//" | sed -e "s/ *$//" | sed -e "/^ *$/d" > ./src/laravel/storage/logs/coverage-summary.log

      - name: Read coverage summary
        id: coverage-summary
        uses: juliangruber/read-file-action@v1
        with:
          path: ./src/laravel/storage/logs/coverage-summary.log

      - name: Comment Coverage Summary
        uses: marocchino/sticky-pull-request-comment@v2
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          header: coverage-summary
          message: |
            ## Coverage Summary
            ${{ steps.coverage-summary.outputs.content }}
```
terraform.tfstateファイルをS3で管理する

terraform.tfstateファイルをS3で管理する時にError refreshing state: BucketRegionError: incorrect region, the bucket is not in 'ap-northeast-1' region at endpoint '' status code: 301, request id: , host id:というエラーが出て困った。その解決の手順を記録します。

初期化します。

```shell:
terraform init
```

以下を記述して

```tf:provider.tf
provider "aws"{
      region = "ap-northeast-1"
      profile = "default"
}

terraform {
      required_version = "~> 1.1.7"
      required_providers {
            aws = {
                  source  = "hashicorp/aws"
                  version = "~> 4.0"
            }
      }
      # backend "s3" {
      #       bucket = "terraform-state-ymktmk"
      #       region = "ap-northeast-1"
      #       profile = "default"
      #       key = "terraform.tfstate"
      #       encrypt = true
      #       dynamodb_table = "terraform_state_lock"
      # }
}

resource "aws_s3_bucket" "terraform_state" {
      bucket = "<被らない名前で>"
      lifecycle {
            prevent_destroy = true
      }
      versioning {
            enabled = true
      }
}

resource "aws_dynamodb_table" "terraform_state_lock" {
      name = "<被らない名前で>"
      read_capacity = 1
      write_capacity = 1
      hash_key = "LockID"

      attribute {
      name = "LockID"
      type = "S"
      }
}

```

S3とDynamoDBを作成する

```shell
terraform apply
```


provider.tfのコメントアウトを元に戻して

```
terraform init
```

以下のように聞かれるのでyesを入力してEnterを押す。これでterraform.tfstateファイルをS3で管理することができるようになった。terraform applyでS3バケットを作成した後にterraform initでterraform.tfstateをS3で管理するようにしなければいけなかったっぽい。

```
Do you want to copy existing state to the new backend?
  Pre-existing state was found while migrating the previous "local" backend to the
  newly configured "s3" backend. No existing state was found in the newly
  configured "s3" backend. Do you want to copy this state to the new "s3"
  backend? Enter "yes" to copy and "no" to start with an empty state.
```
Grafanaの描くグラフ画像に手っ取り早くタイムスタンプを入れる

Grafanaには[Image rendering](https://grafana.com/docs/grafana/latest/image-rendering/)という、指定したパネルをPNG画像として取り出す機能があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117513/659fc320-9a4c-13f4-d90b-5534ad16ec80.png)
やり方そのものは簡単で、Share PanelにあるDirect link rendered imageを叩くだけ。セッションがあるブラウザで叩いてもいいし、API TokenをBearer tokenとしcURLで叩いてもいい。

![グラフ例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117513/6318c952-b01f-49a9-3f81-1b82484a2480.png)

こんな感じで、パネルに描かれたグラフを画像として取ってこれます。

## 本題
Image renderingには画像を生成した時刻を描き込む機能がありません。画像に生成時間がないので、保存した画像が何時のやつかがわからない。

Image renderingが[Puppeteer](https://github.com/puppeteer/puppeteer)で指定したグラフを描画して保存する仕掛けなので、Grafanaに表示されてない情報を入れることは考えてなさそう。

選択肢はいくつかあって

- ImageMagickでがんばる
- Grafanaを改造する

ぐらいが思いつくのですがどちらも面倒。で、Grafanaのドキュメントを読み漁ってみたところ、取り敢えずの解をみつけたので書いておきます。

### パネルタイトルにタイムスタンプを入れる
Grafanaのパネルタイトルには変数が使えます。

> `Panel titles and metric queries can refer to variables using two different syntaxes:`
> https://grafana.com/docs/grafana/latest/variables/syntax/

で、ここで使える変数にはグラフの開始および終了時刻がある。

> `Grafana has two built in time range variables: $__from and $__to.`
> https://grafana.com/docs/grafana/latest/variables/variable-types/global-variables/#__from-and-__to

Image renderingさせるパネルの表示幅が「現在から過去n時間まで」だったら、`$__to`は現在時刻を表すことになります[^to-as-now]。

[^to-as-now]: この前提が満たされないときは、今回書いた技は使えない。「取り敢えずの解」って書いたのはこのへん。

また、`$__to:date:(フォーマット文字列)`でよろしく時刻をフォーマットできるとあるので、ロケール依存[^locale]ですが`LLLL`がわかりやすそうなので、これを含んだ文字列をパネルタイトルに設定。

[^locale]: ブラウザで叩くとユーザが設定したロケールですが、API Keyだと設定の[rendering_language](https://grafana.com/docs/grafana/latest/administration/configuration/#rendering_language)が参照されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117513/817885a5-bcd5-5386-a9e7-75cfbd0a96d2.png)

パネルタイトルの変数は最初に表示された時点から更新されないのでブラウザで表示しっぱなしだと無意味なんですが、Image renderingする場合は一度表示したらブラウザ(Headless Chrome)ごと捨てるので問題がない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117513/99e5325b-e3bb-f29c-6853-83d55b164712.png)


これで、Direct link rendered imageで取れる画像に描画時刻を入れることができました。
yarnでcreate-react-appをするには？

Reactのアプリの雛形を作成するコマンドといえば
```
npx create-react-app my-app
```
に馴染みがあるのではないでしょうか。
私も特に疑問も持たずに、これまでこのコマンドでアプリを生成してきました。

しかし、これだと開発を進めていく際に`yarn`コマンドでパッケージの追加を使うと`package-lock.json`と`yarn.lock`がどちらもある状態になってしまい気持ち悪いことになります。

一旦、`package-lock.json`と`node_modulesディレクトリ`を削除して、`yarn install`で入れ直すことで解決できますが、それも二度手間。できれば気持ちよくReactの開発をスタートさせたいものです。

では、「yarnでcreate-react-appする」にはどうすればいいのか？

## Yarnでcreate React Appする
それが、こちら。
```
yarn create react-app my-app
```
このコマンドを実行することでmy-appというプロジェクトが作成されます。
`npx`の時は**create-react-app**でしたが、`yarn`の場合は**create react-app**となっている点に注意です。

また、typescriptで構築したい場合は
```
yarn create react-app my-app --template typescript
```
とすればOK。

これで気兼ねなく`yarn add`でバンバンnodeパッケージをインストールしたり削除したりできます笑

### 参考
https://create-react-app.dev/docs/getting-started/#yarn
https://create-react-app.dev/docs/adding-typescript/#installation
【MySQL】SQL文のDMLのうちUPDATEを学び直し

SQL文はWEB開発においてDBはめちゃくちゃ大事だよ、覚えるべきだよ！と散々言われているにも関わらず後回しにしがちな寺です。
今クラウド関係の勉強に注力していることもありSQLの知識が抜け落ちつつあるので学び直している次第です。

普段から使っていれば自然と身につくことではあるのですが、そのうち血反吐吐くくらいノックして身につけます！

## UPDATEとは
大別して3つに分類されるSQL文のうちDMLのひとつで、レコード内容を「更新」するコマンドです。

:::note
データ定義：DDL
データ操作：DML
データ生後：DCL
:::

### DMLとは
`SELECT`, `INSERT`, `UPDATE`, `DELETE`の4つを指します。

:::note
それぞれSQL操作のうち、検索・新規登録・更新・削除を行います。
:::

### CRUD処理
SQLのDMLはWeb開発などにおけるCRUD処理にそれぞれ対応します。

| CRUD | 説明 | SQL(DML) |
|----|----|----|
| Create | 生成 | INSERT |
| Read | 読み取り | SELECT |
| Update | 更新 | UPDATE |
| Delete | 削除 | DELETE |

## UPDATEの使い方
UPDATEコマンドは`UPDATE テーブル名 SET カラム名 = 更新値;`のように記述します。

カラムを複数指定する場合は、カラム名とデータをを`,`（カンマ）で区切ります。

データを一括更新したいときはこのようにシンプルな書き方をします。

:::note warn
このクエリだとテーブル内のカラムの値が更新値で全て書き変わってしまいます。
うっかり事故らないようWHERE句で更新対象を絞るようにしましょう。
:::

特定のデータのみ更新するよう`WEHERE`句を指定し条件に一致するデータを更新します。
以降のSQLコマンド操作は仮想環境[Envader](https://envader.plus)を使用しています。

```sql
UPDATE テーブル名 SET カラム1=データ1, カラム2=データ2... WHERE name="satou" ;
```

### その他の条件指定
指定する条件を`ORDER BY`で並び替えたり`LIMIT`で絞り込んだりすることもできます。

```sql
UPDATE sample SET test_id=3 ORDER BY user_id DESC LIMIT 6;
```
参考：[MySQL UPDATEの基本](https://envader.plus/course/2/scenario/1049/)


テーブル`sample`のカラム`test_id`の値を`user_id`で`DESC`(降順)に並び替え出力結果の上位6つを3に書き換えるという指定内容です。
このORDER BYで並び替えLIMITで制限する使い方は結構使うと思うのでしっかり身に着けたいところ。

## 学んだこと
* UPDATEコマンドを使用したデータの更新方法
* WHERE句で絞らない場合対象の値全てが更新されてしまうので注意

触れば思い出すものの思い出すまで若干（けっこう）時間が掛かってしまうので、息を吐くようにSQL文を書けるようになりたいです。

## 参考資料
https://envader.plus/course

https://26gram.com/mysql-update

https://lightgauge.net/database/sqlserver/8193/

### 前回学んだINSERT文
https://qiita.com/Terralien/items/dd8ce60d056fe0a2eb4d
15byteより小さいファイルをゴミとして特定のディレクトリへ移動する。



```python
import shutil
import os

os.mkdir('trash')

def isTrash(file):
    return os.path.getsize(file) < 15

for f in os.listdir(path='.'):
    if isTrash(f):
        shutil.move(f, 'trash')
    elif os.path.isfile(f):
        print('file operation:' + f)

```
高度試験の勉強方法（ITサービスマネージャ）

※まだ合格していない人の自分用雑メモ
　　→合格しました（令和5年度 春期に、本番リリースと本番影響について熱く語ったら「A」もらえた）

# 午前1
https://qiita.com/seigen2414/items/69c726b099e31a7b25c1

# 午前2
* ITILが全体的に多いが、ITILそのものについては午後では出ない。
* 開発や運用等の経験があれば、ある程度は当たり前の範囲で回答可能。
* 問題管理、インシデント管理、等のなんとか管理辺りは整理しておく。

# 午後1
* 他の区分に比べて、非常に読みやすい。
* 問題文の行ったり来たりが非常に少ない。
* 開発や運用等の経験があれば、ある程度は当たり前の範囲で回答可能。
* 午後問題の解き方（問題文の中から根拠を探す）に慣れていればほぼ勉強不要。
* 印刷するもの
  * A4、空白ページ除外、「PDFに合わせる（=A4の中で大きくする）」
  * 以下だけやればある程度網羅できてる。午後2を意識したネタ集めとして解く。
  * R1（2019）-問1,問2,問3
  * H30（2018）-問1,問2,問3
  * H29（2017）-問2（問題管理および変更管理）

# 午後2
## おさえること
* 情報システムの概要ではなく、ITサービスの概要を書く。
* アーキテクトではない。
* 管理者目線を忘れない。
* RTO/RPOだけでなく、RLOのことも忘れない。
* MTBF/MTTRだけでなく、MTRS（平均サービス回復時間：Mean Time to Restore Service）のことも忘れない。
* 1つだけではなく、複数の視点で書く。
* 印刷するもの
  * A4、空白ページ除外、「PDFに合わせる（=A4の中で大きくする）」
  * 問題、解答、講評
* 問題文の読み込み、解答と講評から何を求められているか、どういう論文がNGか確認。
* 以下写経する。最近の傾向的にこれでほとんど網羅できてる。（三好さんベース）
    * R1（2019）-問1,問2
    * H30（2018）-問2 ※問1は印刷のみ
    * H24-問1
    * H22-問3

## 良い論文、良くない論文
* × ITサービスマネージャとしての視点が足りない、担当者目線
* 顧客対応系
  * 日頃から顧客事業への貢献を意識している
  * 顧客の事業環境を正しく理解している
  * 顧客志向の高いレベルでのマネジメント活動
    * 顧客満足の把握と改善
    * 利害関係者間の調整
  * × 事業関係管理に対する経験、知見の不足
* サービス可用性、SLA系
  * 顧客と合意した具体的なSLA
  * SLAに対して、監視した事象や測定項目
  * 測定結果とどのように分析したか
  * 対応が必要と考えた課題と改善策
  * × 測定項目や評価指標が明確でない
  * × 複数ではなく1つの視点でしか評価を行っていない（例えば、品質と性能の片方にしか触れていない）
  * × 定量的に分析していない
【Next.js】ルーティングの設定方法

## はじめに
　本記事は、プログラミング初学者が学習を進めていて疑問に思った点について調べた結果を備忘録も兼ねてまとめたものです。
　そのため、記事の内容に誤りが含まれている可能性があります。ご容赦ください。
　間違いを見つけた方は、お手数ですが、ご指摘いただけますと幸いです。

## ルーティングの設定方法
### Reactの場合
Reactの場合には`react-router-dom`を使用して以下のようにルーティングの設定をします。

```Router.jsx
    <BrowserRouter>
      <Routes>
        <Route path="sign_in" element={<SignIn />} />
        <Route path="sign_up" element={<SignUp />} />
        <Route path="mypage" element={<PrivateRoute><Header /><MyPage /></PrivateRoute>} />
        <Route path="todo" element={<PrivateRoute><Header /><PageTodo /></PrivateRoute>} />
        <Route path="*" element={<Page404 />} />
      </Routes>
    </BrowserRouter>
```

### Next.jsの場合
Next.jsの場合には、`pages`フォルダにファイルを作成することでルーティングを設定できます。
具体的には以下の通りです。

#### `pages`フォルダにファイルを作成する
まず、`pages`フォルダにフォルダを追加します。
今回は、`posts`フォルダを追加します。
次に、`posts`フォルダの中にファイルを作成します。
今回は、`samplePost.js`ファイルを作成します。
![スクリーンショット 2022-04-12 23.56.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/c6e6813b-28c8-8c22-eb03-cfcab27d41a8.png)
このようにすることで、http://localhost:3000/posts/samplePost で`samplePost.js`の中身が表示されます。

#### 内容を記述する
ファイルの作成ができたら、内容を記述していきます。

```samplePost.js
export default function() {
  return (
    <>
      <h1>samplePost</h1>
      <p>samplePostのページが表示されています。</p>
    </>
  );
}
```

#### ローカルサーバーを立ち上げる
ターミナルで`npm run dev`を実行するとローカルサーバーを立ち上げることができます。
```:ターミナル
$ npm run dev
```

#### ブラウザで表示を確認する
`posts`フォルダ内の`samplPost.js`の内容が表示されるか確認します。
ブラウザを開いて、http://localhost:3000/posts/samplePost にアクセスします。
すると以下のように`samplePost.js`に記述した内容が表示されます。

![スクリーンショット 2022-04-12 23.46.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/bc31552b-2122-0071-3c09-851aba7fba7b.png)

上記のように、`pages`フォルダにフォルダやファイルを作成することでルーティングを設定することができます。
一度は聞いたことがある「ドメイン駆動設計」の紹介と実践談

# 紹介

システムが扱う領域を、ドメインといいます。
銀行システムなら、銀行業務のドメインです。

このドメインを中心に据えた、
「設計の進め方」と「デザインパターン」が、
がドメイン駆動設計として、提唱されています。

英語では「domain-driven design」と表記され、略称は「DDD」です。

## 設計の進め方

大まかな流れを紹介します。

### ドメインモデル

ドメインの専門家と協力して、設計を進めていきます。
銀行システムなら、銀行員です。

専門家から引き出した知識を、ドメインモデルに整理していきます。

### ユビキタス言語

ドメインには専門用語があります。
銀行システムなら、当座などです。

それらをユビキタス言語に整理することで、「認識齟齬」や「表記ゆれ」を防ぎます。

## デザインパターン

代表的なものを紹介します。

### Layered Architecture

プログラムを、4つのレイヤーに分割します。
分割することで、読みやすくて変更しやすいプログラムになります。

| レイヤー           | 説明                                                             |
| :---------------: | :-------------------------------------------------------------: |
| プレゼンテーション   | ユーザに対して情報を表示し、ユーザの命令を解釈する。                     |
| アプリケーション    | アプリケーションの活動を調整する薄いレイヤ。<br>ビジネスロジックを含まない。 |
| ドメイン           | ドメインについての情報を含むレイヤ。業務ソフトウエアの心臓部。             |
| インフラストラクチャ | 他のすべてのレイヤを補助するライブラリとして働く。                       |

### Value Object

つぎの例のように、値をオブジェクトにします。

#### Value Objectを使わない例

```java:メインロジック
  private void sendMessage(String to, String message) {
    validate(message);
    send(to, message);
  }

  private void validate(String message) {
    // 禁則文字が含まれていないかチェックする。
  }

  private void send(String to, String message) {
    // 送信する。
  }
```

#### Value Objectを使った例

```java:メインロジック
  private void sendMessage(Account to, Message message) { // GOOD: 引数が分かりやすい。
    message.validate();
    send(to, message); // GOOD: 引数の順番を間違えてsend(message, to)にしたら、コンパイルエラーになる。
  }

  private void send(Account to, Message message) {
    // 送信する。
  }
```

```java:値：Message
/**
 * メッセージ。
 */
public class Message {

  private final String value;

  public Message(String value) {
    this.value = value;
  }

  public String getValue() {
    return value;
  }

  // POINT: メインロジックから切り出す。
  // GOOD: 再利用しやすい。
  // GOOD: メインロジックの肥大化を防げる。
  public void validate() {
    // 禁則文字が含まれていないかチェックする。
  }
}
```

```java:値：Account
/**
 * アカウント。
 * 例：A1234
 */
public class Account {

  private final String value;

  public Account(String value) {
    this.value = value;
    // POINT: 5桁の英数字という決まりがあるなら、ここでアサーションをしてもよい。
  }

  public String getValue() {
    return value;
  }

  // POINT: アカウントに関する処理をつくってもよい。
  public boolean isTemporary() {
    return value.startWith("T"); // T1234など、Tで始まるときに仮登録中とみなす。
  }
} // POINT: toString, equals, hashCodeをオーバーライドしてもよい。
```

# 実践談

人気なだけに、いい設計手法だと感じました。

しかし、銀の弾丸ではないです。

「ドメイン駆動設計」で失敗したプロジェクトも見てきましたし、
「ドメイン駆動設計」で成功したプロジェクトも見てきました。

プロジェクトに合わせて、どこまで取り入れるかが大事です。
デザインパターンだけを取り入れてもいいと思います。
（Layered ArchitectureとValue Objectだけでも）

実践するときは、どのように落とし込むか、迷うものです。
周囲に相談しましょう！

会社のテーマ活動でも、実践してみたいなと思っています！

# もっと知りたい

もっと知りたいときは、書籍を読んでください。
わたしは要約版を読みました。（原点はキツかった）

- [エリック・エヴァンスのドメイン駆動設計](https://www.shoeisha.co.jp/book/detail/9784798126708)
    - 原点
    - 読みにくい（557ページ）
- [Domain Driven Design（ドメイン駆動設計） Quickly](https://www.infoq.com/jp/minibooks/domain-driven-design-quickly/)
    - 要約版
    - 読みやすい（81ページ）

今なら、もっといい書籍がありそうです。
自分に合った書籍を選んでください。
非接触で心拍数を計測する

# 概要

前回は [24GHz-mmWave-Radar-Sensor-Sleep-Breathing-Monitoring-Module](https://www.seeedstudio.com/24GHz-mmWave-Radar-Sensor-Sleep-Breathing-Monitoring-Module-p-5304.html) を使用したが、今回は [60GHz mmWave Radar Sensor - Breathing and Heartbeat Module](https://www.seeedstudio.com/60GHz-mmWave-Radar-Sensor-Breathing-and-Heartbeat-Module-p-5305.html) を試してみる。こちらは心拍数が計測できる。

![](https://media-cdn.seeedstudio.com/media/catalog/product/cache/b2267b506d4e4594666ef83a79896a9a/1/0/101990886_front-05.jpg)


# 試行

このボードは分析結果の数値をシリアルで渡してくれるので、M5Stackと [GROVE - 4ピン-ジャンパメスケーブル](https://www.switch-science.com/catalog/1048/) で繋いで読み取る。
Groveの21ピンをrx、22ピンをtxに割り当て、それぞれボードのtx、rxに接続する。

```cpp:main.cpp
#include <M5Stack.h>

HardwareSerial serial_ext(2);

#define MESSAGE_HEAD_1 0x53
#define MESSAGE_HEAD_2 0x59
#define MESSAGE_TAIL_1 0x54
#define MESSAGE_TAIL_2 0x43
int data[20] = {0};
int i, j = 0;
int Msg, Msg_prev;

void setup() {
  M5.begin();
  M5.Lcd.fillScreen(TFT_NAVY);

  M5.Lcd.setTextColor(TFT_CYAN);
  M5.Lcd.setTextSize(2);
  M5.Lcd.drawString("Breathing rate:", 0, 0);
  M5.Lcd.drawString("Heart rate:", 0, 120);

  serial_ext.begin(115200, SERIAL_8N1, 21, 22);

  Serial.print("Ready.");
}

void loop() {
  if (serial_ext.available() > 0) {
    Msg_prev = Msg;
    Msg = serial_ext.read();
    if (Msg_prev == MESSAGE_TAIL_1 && Msg == MESSAGE_TAIL_2) {
      if (data[2] == 0x81 && data[3] == 0x05 && data[5] == 0x01) {
        M5.Lcd.fillRect(40, 40, 100, 60, TFT_NAVY);
        M5.Lcd.setCursor(40, 40);
        M5.Lcd.setTextSize(6);
        M5.Lcd.printf("%d", data[6]);
        Serial.printf("Breathing rate: %d\n", data[6]);
      } else if (data[2] == 0x81 && data[3] == 0x02 && data[5] == 0x01) {
        M5.Lcd.fillRect(40, 160, 100, 60, TFT_NAVY);
        M5.Lcd.setCursor(40, 160);
        M5.Lcd.setTextSize(6);
        M5.Lcd.printf("%d", data[6]);
        Serial.printf("Heart rate: %d\n", data[6]);
      } else {
        for (j = 0; j < 20; j++) {
          Serial.printf("%02x ", data[j]);
        }
        Serial.println("");
      }
      i = 0;
    } else {
      data[i] = Msg;
      if (i < 19) i++;
    }
  } else {
    delay(25);
  }
  M5.update();
}

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555397/ad99c5fd-6207-9cdf-0940-fc2c527ed59e.png)




# 課題

ドキュメントが役に立たない。
こちらも、受信はできるものの、ボードに対してコマンド送信がまだうまくいかない。
Flutter pub.devの私用パッケージまとめメモ

#### [flutter_native_splash](https://pub.dev/packages/flutter_native_splash)
splash画面用パッケージ
```bash
# 変更反映する時はこれする（しないと画像変わらない）
# After adding your settings, run the following command in the terminal
flutter pub run flutter_native_splash:create
```

#### [logger](https://pub.dev/packages/logger_flutter)
ログ出力用パッケージ
```bash
# install
flutter pub add logger
```
```dart
# You can log with different levels:
logger.v("Verbose log");
logger.d("Debug log");
logger.i("Info log");
logger.w("Warning log");
logger.e("Error log");
logger.wtf("What a terrible failure log");
# To show only specific log levels, you can set:
Logger.level = Level.warning;
# demo
logger.d('Log message with 2 methods');
loggerNoStack.i('Info message');
loggerNoStack.w('Just a warning!');
logger.e('Error! Something bad happened', 'Test Error');
loggerNoStack.v({'key': 5, 'value': 'something'});
Logger(printer: SimplePrinter(colors: true)).v('boom');
```
![logger demo](https://raw.githubusercontent.com/leisim/logger/master/art/screenshot.png)

随時追記予定
WSL2上でwebpackのホットリロードが効かない

# はじめに

https://www.amazon.co.jp/TypeScript%E3%83%8F%E3%83%B3%E3%82%BA%E3%82%AA%E3%83%B3-%E6%8E%8C%E7%94%B0%E6%B4%A5%E8%80%B6%E4%B9%83/dp/4798065331/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=64VNKFDB5VQ9&keywords=TypeScript+%E3%83%8F%E3%83%B3%E3%82%BA%E3%82%AA%E3%83%B3&qid=1649774005&sprefix=typescript+%E3%81%AF%E3%82%93%E3%81%9A%E3%81%8An%2Caps%2C194&sr=8-1

上記の本を参考にTypeScriptの勉強をしていたところ、webpack serveによる自動ビルドがうまく働かず少し悩んだため、解決策を備忘録として残しておきます。

# 状況

webpack serveでサーバーを起動することは出来るが、サーバー起動中にファイルを修正・保存しても再ビルド・ページの更新が行われない。

ただしブラウザで見ると「Live Reloading enabled.」という表示が出る。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592455/c636fed0-fe9f-be33-4433-982e2ce53d3e.png)

# 原因・解決策

プロジェクトをマウント先のドライブに於いていたことが原因。
プロジェクトを```mnt/c```配下から```~```に移動することで解決した。

# 参考文献

* [wsl2が異常に遅くてホットリロードも効かないとき - blog.tamaosa.com](https://blog.tamaosa.com/2020/wsl2/)
* [WSLでホットリロード効かない or コンパイル遅すぎ問題 - Qiita](https://qiita.com/Ningensei848/items/5c00c02d4080050ecac2)
jsonで中間プロパティが存在しないときに使えるオプショナルチェーン


APIなどでjsonを取得時、中間プロパティが存在しない場合
オプショナルチェーンという方法で解決できたため記載します。

## 先に結論
##### 解決したコード
```javascript:sample-answer.js
// リクエストを投げる処理
console.log(data.items[i].volumeInfo.imageLinks?.thumbnail);
```

以下の配列で`thumbnail`が欲しいのに`imageLinks`のプロパティすらないって場合
`console.log(data.items[i].volumeInfo.imageLinks.thumbnail);`

オプショナルチェーン [?] を利用することで左側のプロパティが存在するかチェックし、
存在しなければundefinedを返してくれます。

## 動作環境
ローカル環境でHTML, CSS, JS, jQueryを使用
　※Chromeで動作確認

## 解決したい課題
今回はGoogle Books APIを利用して簡単なWEBアプリを作成する際に発生しました。
APIで40件取得したところ以下のようにエラーが発生します。

##### 投げたリクエスト
`https://www.googleapis.com/books/v1/volumes?q=aws&maxResults=40`

##### 正常なレスポンス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551636/6bac5af6-5655-a5a6-485c-081be8192ef8.png)

##### サンプルコード
```javascript:sample.js
// リクエストを投げる処理
console.log(data.items[i].volumeInfo.imageLinks.thumbnail);
```

##### エラー結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551636/c9b7b99d-0d46-fb4f-c320-dc390ec7584c.png)

`data.items[i].volumeInfo.imageLinks.thumbnail`が取得できずエラーになっていますが、
返ってきたAPIを確認すると`imageLinks`自体が存在しないアイテムがあるようです。

undefinedの場所が固定であればifで条件分岐ができますが、
対応方法に悩んでいた（ネストも多いしめんどくさい・・・・・）
ところオプショナルチェーンで解決できました。


## 対応方法

##### オプショナルチェーン
> JavaScriptのオプショナルチェーン?.は、オブジェクトのプロパティが存在しない場合でも、
> エラーを起こさずにプロパティを参照できる安全な方法です。

プロパティ自体が存在しない場合上記のようにエラーが発生し処理が止まってしまいます。
オプショナルチェーンを使用すれば結果は`null`もしくは`undefined`で返却されるため処理の停止は避けられます。

##### 解決したコード
```javascript:sample-answer.js
// リクエストを投げる処理
console.log(data.items[i].volumeInfo.imageLinks?.thumbnail);
```
? を入れるとこのプロパティにアクセスした場合、
左側のプロパティが存在するかをチェックし、存在しなければ`undefined`と返却されます。

極端ですが以下のように複数使用することもOKです。
※ただし、? 以前の変数は定義されている必要があります。`data`の定義は必要です。
```javascript:sample-answer02.js
// リクエストを投げる処理
console.log(data?.items[i]?.volumeInfo?.imageLinks?.thumbnail);
```

## 結果
無事undefinedが返ってきて処理が止まらずに済みました～！！

## 参考記事
https://typescriptbook.jp/reference/values-types-variables/object/optional-chaining 

https://yutaro-blog.net/2022/01/03/javascript-typescript-operator/
【BigQuery】ファネル分析用のクエリ

# やったこと
・BigQueryでファネル分析のためのクエリを書いた
・SQLだけで順序を取り扱うのが:thinking: → :dizzy_face:だったので[UDF（ユーザー定義関数）](https://cloud.google.com/bigquery/docs/reference/standard-sql/user-defined-functions?hl=ja "標準 SQL ユーザー定義関数")を使った
・ファネルの層が増えて（減って）も（そこそこ）簡単に拡張できるように努力した
# ファネル分析とは
![ファネル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342142/330751d8-7271-316f-50a5-1ed23f1c748b.png)
こんなふうに、STEP1 → STEP2 → STEP3 → STEP4 と順番にステップを踏んだ人の数を集計して、各ステップの成績（達成人数）を可視化して改善につなげる分析手法
# 前提条件
・以下のようなレコードが与えられる（user_idはユーザーごとのユニークなID。createdはSTEPを達成した時刻）
|user_id  |event_id  |created  |
|---|---|---|
|1  |STEP1  |2022-04-12 00:00:00  |
|1  |STEP3  |2022-04-12 01:00:00  |
|1  |STEP2  |2022-04-12 02:00:00  |
|1  |STEP4  |2022-04-12 03:00:00  |

・STEPが順番に実行された場合のみ集計対象とする（上の場合だと、STEP1 → STEP2 → STEP3 → STEP4 の順番に実行されたのはSTEP1とSTEP2までなので、この2つのレコードだけを集計対象にしたい）

# クエリ
では早速（サンプル用のデータも書いていますのでそのままコピペで動きます）
```SQL
-- イベントIDの配列（時系列にソート済み）を受け取り、達成したSTEP数を返す関数
CREATE TEMP FUNCTION achievedSteps(userId INT64, userActions ARRAY<STRING>)
  RETURNS ARRAY<INT64>
  LANGUAGE js AS r"""
  const funnels = ["STEP1", "STEP2", "STEP3", "STEP4"];
  let ret = new Array(funnels.length);
  let idx = 0;
  for (const action of userActions){
    if (action === funnels[idx]){
      ret[idx] = userId;
      idx++;
    }    
  };
  return ret;
  """;

-- サンプルデータの作成
WITH samples AS (
  -- user_id: 1
  SELECT 1 user_id, "STEP1" event_id, "2022-04-12 00:00:00" created UNION ALL 
  SELECT 1 user_id, "STEP3" event_id, "2022-04-12 01:00:00" created UNION ALL 
  SELECT 1 user_id, "STEP2" event_id, "2022-04-12 02:00:00" created UNION ALL 
  SELECT 1 user_id, "STEP4" event_id, "2022-04-12 03:00:00" created UNION ALL

  -- user_id: 2
  SELECT 2 user_id, "STEP1" event_id, "2022-04-12 00:00:00" created UNION ALL 
  SELECT 2 user_id, "STEP2" event_id, "2022-04-12 01:00:00" created UNION ALL 
  SELECT 2 user_id, "STEP3" event_id, "2022-04-12 02:00:00" created UNION ALL 
  SELECT 2 user_id, "STEP4" event_id, "2022-04-12 03:00:00" created UNION ALL

  -- user_id: 3
  SELECT 3 user_id, "STEP4" event_id, "2022-04-12 00:00:00" created UNION ALL 
  SELECT 3 user_id, "STEP1" event_id, "2022-04-12 01:00:00" created UNION ALL 
  SELECT 3 user_id, "STEP2" event_id, "2022-04-12 02:00:00" created UNION ALL 
  SELECT 3 user_id, "STEP3" event_id, "2022-04-12 03:00:00" created
) 

-- -- ファネル用集計データの作成
SELECT 
  COUNT(DISTINCT achievedIds[SAFE_OFFSET(0)]) step1,
  COUNT(DISTINCT achievedIds[SAFE_OFFSET(1)]) step2,
  COUNT(DISTINCT achievedIds[SAFE_OFFSET(2)]) step3,
  COUNT(DISTINCT achievedIds[SAFE_OFFSET(3)]) step4,
FROM (
  SELECT 
    achievedSteps(user_id, ARRAY_AGG(event_id ORDER BY created)) achievedIds
  FROM 
    samples
  GROUP BY 
    user_id);

-- => {  "step1": "3",  "step2": "3",  "step3": "2",  "step4": "1"}
-- user_id: 1 はSTEP2まで達成
-- user_id: 2 はSTEP4まで達成
-- user_id: 3 はSTEP3まで達成　なので期待通りの結果が取得できた！！
```
# 感想
・UDF強い
・なんでもSQLでやろうとするとツライ

# 次回予告
「GA4のデータをBigQuery連携してデータポータルから見る」の巻？
【メモ】Kotlinのクラスと継承

## はじめに
改めて継承などについて学んだので、かなりコンパクトにまとめました。
※間違っている部分があれば指摘していただけますと幸いです。

## 用語の概要

- クラス階層
    - クラスが親と子の階層構造で構成されている配置のこと
    - 階層図は通常親が子の上に表示するように描かれる
- 子・サブクラス
    - 階層構造で他のクラスの下にある全てのクラス
- 親・スーパークラス・基底クラス
    - 1つ以上の子クラスを持つ全てのクラス
- ルート・トップレベルクラス
    - クラス階層の最上位（またはルート）にあるクラス
- 継承
    - 子クラスが親クラスの全てのプロパティとメソッドを含む（継承する）ことを意味する
    - これによりコードの共有や再利用が可能になる

## 抽象クラスとは？

- 完全に実装されていないため、インスタンス化出来ないクラスのこと
- スケッチのようなもの
    - スケッチ（抽象クラス）を使用して、実際のオブジェクトインスタンスをビルドするための設計図（クラス）を作成する
- 宣言は`abstract`で始める
- 抽象クラス・関数に`open`アノテーションを付ける必要は無い
 ``` kotlin
abstract class Polygon {
    abstract fun draw()
}

class Rectangle : Polygon() {
    override fun draw() {
        // draw the rectangle
    }
}
```
- 抽象化されていない`open`メンバを、抽象化されたメンバでオーバーライド出来る
``` kotlin
open class Polygon {
    open fun draw() {
        // some default polygon drawing method
    }
}

abstract class WildShape : Polygon() {
    // Classes that inherit WildShape need to provide their own
    // draw method instead of using the default on Polygon
    abstract override fun draw()
}
```

## 継承について

- 継承できるのは`abstract`か、`open`キーワードでマークされたもののみ
    - ※Kotlinのクラス・メソッドはデフォルトでfinal
- メソッドや属性をオーバーライドするには、`override`修飾子が必要

```kotlin
open class Dog {                
    open fun sayHello() {       
        println("wow wow!")
    }
}

class Yorkshire : Dog() {       
    override fun sayHello() {   
        println("wif wif!")
    }
}

fun main() {
    val dog: Dog = Yorkshire()
    dog.sayHello() // wif wif!
}
```

- 親で定義されている関数を呼び出すときは`super`キーワードを使用

```kotlin
abstract class Dwelling {
    
    abstract fun floorArea(): Double
}

open class RoundHut(val radius: Double) : Dwelling() {
    
    override fun floorArea(): Double {
        return 3.14 * radius * radius
    }
}

class RoundTower(
    radius: Double,
    val floors: Int
) : RoundHut(radius) {
    
    override fun floorArea(): Double {
        return super.floorArea() * floors
    }
}

fun main() {
    val roundHut = RoundHut(5.0)
    println(roundHut.floorArea()) // 3.14 * 5 * 5
    
    val roundTower = RoundTower(5.0, 3)
    println(roundTower.floorArea()) // 3.14 * 5 * 5 * 3
}

/**
* 出力結果
*
* 78.5
* 235.5
*/
```

## 参考資料

- [Abstract classes](https://kotlinlang.org/docs/classes.html#abstract-classes)
- [Inheritance](https://play.kotlinlang.org/byExample/01_introduction/07_Inheritance)
- [Classes and inheritance in Kotlin](https://developer.android.com/codelabs/basic-android-kotlin-training-classes-and-inheritance?continue=https%3A%2F%2Fdeveloper.android.com%2Fcourses%2Fpathways%2Fandroid-basics-kotlin-unit-2-pathway-1%23codelab-https%3A%2F%2Fdeveloper.android.com%2Fcodelabs%2Fbasic-android-kotlin-training-classes-and-inheritance#0)


## おわりに
ここまで読んでいただき、ありがとうございました。
何かありましたらコメントをお願いします。
【備忘録】SSHでラズパイを再起動/シャットダウンする


SSH等でラズパイを動かす際、安全に再起動/シャットダウンするコマンドをメモしておく。

## 再起動
`sudo reboot`
`sudo shutdown -r now` 

上記のコマンドを打ち込むことにより再起動ができる。

## シャットダウン
`sudo shutdown -h now`

上記のコマンドを打ち込んでしばらくすると緑色のLEDが消える。
⇒電源をOFF（ケーブルを抜く）

## 参考
https://www.out48.com/archives/936/
http://raspi.seesaa.net/article/414984088.html
基本情報技術者試験対策　29日目

基本情報技術者試験勉強　29日目
-
この記事の目的
-
今年の5月に基本情報技術者試験を合格するために、過去問で間違えた箇所をただまとめる自分のための記事

プロフィール
-
・文系大学の３年生
・ITパスポートは保有
・ウェブアプリやサイト作成を個人で行ったことがある程度
・猫好き

今日の目標
-
午前問題で正答率8割を目指す。

間違った箇所
-
1、ファジング
ファズデータの生成、検査対象への送信、挙動の監視を自動で行うファグツール

2、SIEM(Security Information and Event Management)
複数のログデータを創刊分析し、不正アクセスを検知する。

3、ファブレス
製造設備を持たず、商品の企画、設計、開発を行う

4、スナップショットダンプ
プログラム中の特定の命令文が実行されるたびに、その時のメモリやレジスタの内容を出力するテスト支援ツール

5、テストカバレッジ分析
プロフラムの品質を定量的に把握するために、テストの網羅率を測定、分析する

6、アサーションチェック
アサーションをプログラムの適切な箇所に挿入し、実行時にその部分のアサーションが成立しているかを検査し、プログラムの正当性を測る
アサーションとは、プログラムの実行中に、使用されている変数の間で論理的に成り立つ条件

7、裁量労働制
特定の専門業務や企画業務において、労働時間は、笑顔の労働時間に関係なく、労使間で予め取り決めた労働時間とみなす。

8、CDP(Career Development Program)
企業が継続雇用の前提として、従業員に対して他社でも通用する技術風力の維持責任を求める一方、企業も従業員の能力開発を積極的に支援


9、オーダ記法
アルゴリズムの計算量が実行時に処理するデータ量によってどのように増加するか、また、アルゴリズムの実行時間を表す

10、ベースラインモデル
モデル化の第一段階として、現在達成されているパフォーマンスを正確に反映したモデルを作成

11、静電センサー
コンピュータに情報を入力する

12、シュリンクラップ契約
ソフトウェアの購入者がパッケージを開封することで使用許諾契約に同意したとみなす。

振り返り
-
午前問題を80問解いたが、テクノロジ系が正答率６１％、マネジメント系が７０%、ストラテジ系が６８％だった。合格点は行けているが、危うい。やはり計算問題の正答率が低いことと問題自体を暗記していて、深く理解していないことが悩み。計算問題はまずはじっくり一つ一つ解いて、自分の中で納得できるぐらい意味を噛み砕く。


>引用
基本情報技術者試験ドットコム
https://www.fe-siken.com
ビルドした時にminSdkVersionの差異でエラーが出たのでメモ

Flutterでビルドした時にminSdkVersionでエラーが出たのでメモ

```gradle:android\app\build.gradle
    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.example.hello_world"
        // minSdkVersion 16
        minSdkVersion 17
        targetSdkVersion 30
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }
```
VS Code と google drive で複数 PC のローカルファイルを同期する

# はじめに

VS Code([ダウンロード](https://code.visualstudio.com/Download)、[github repository](https://github.com/microsoft/vscode))便利ですね！


僕は複数 PC 使用し、メモ書きに VS Code をフル活用しているのですが、
メモが PC 毎に分散して困ってます。。
出社と自宅勤務を繰り返すと「あ、あっちのメモ欲しい」と。。

VS Code と google drive を組合せて複数 PC でローカルファイル同期環境作ったので手順まとめます。

# 環境

以下、環境は Ubuntu, Mac, Windows 書いてますが、
好きなやつだけやってもらえば OK です。

- mac 10.15.7
- Windows 10 Pro
- Ubuntu 16.04
- VS Code

# 準備

## VS Code

### VS Code のアカウント同期

後述の自動保存がやりたいことなのですが、　
アカウント同期しておくとどれかの PC の VS Code で1回やれば良いので楽です。

アカウント同期しない場合は手動で全 PC で自動保存設定をやれば OK です。

### 自動保存を有効化

設定→「Files: Auto Save」を「afterDelay」に設定
＃他でも良いはずだけど未確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35514/e603ad8e-54c9-0e60-9da8-eea97d091ab2.png)

## mac

「パソコン版 Google ドライブ」をインストール。
https://support.google.com/drive/answer/7329379

## Windows

「パソコン版 Google ドライブ」をインストール。
https://support.google.com/drive/answer/7329379 // ↑の mac と同じ

## Ubuntu 

### インストール

```sh
$ sudo add-apt-repository ppa:alessandro-strada/ppa
$ sudo apt-get update
$ sudo apt-get install google-drive-ocamlfuse
```

### 認証

```sh
$ google-drive-ocamlfuse 
[21018:21018:0100/000000.110430:ERROR:sandbox_linux.cc(377)] InitializeSandbox() called with multiple threads in process gpu-process.
Access token retrieved correctly.
```

### マウント

```sh
$ mkdir ~/google-drive
$ google-drive-ocamlfuse ~/google-drive/
```

### ファイル確認

```sh
$ ls ~/google-drive
```

### 参考

https://qiita.com/cabbage_lettuce/items/c4544b3e5cd28caf04bc

# マウント先

僕は以下の場所にマウントされました。

## mac

```
/Volumes/GoogleDrive
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35514/66b82061-acc4-21f4-249b-9d4de323e83d.png)

## Windows

```
G:\
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35514/986c07f1-0aea-7939-4789-03c8887adf4f.png)


## Ubuntu

```sh
$ ls ~/google-drive
```

# ファイル同期

適当にテキストファイルを作り google drive にアップ。
各 PC からファイルを開き、適当に編集すると数秒のラグののち、同期されます！

＃スクショは Windows のですが、まぁ全部一緒なので他のは略

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35514/7018839f-a244-3e03-3ee8-4269c4fb71a6.png)

# その他

## コンフリクト時の動作

自動反映される前に別 PC で同じ行を編集すると
「後勝ち」もしくは「コンフリクト解消 UI 表示」になりました（どちらになるかの条件不明）。
どちらにしても僕は時間を求めない（日毎レベル：とある日は出社、とある日は自宅勤務）ので全く問題ないですが、
短時間で複数 PC で操作する必要がある人はもう少し考えないといけなそうです。

## 「Visual Studio Code for the Web」だとどうなる？

Web アプリの「Visual Studio Code for the Web」( https://vscode.dev/ )でも試しましたが、手間が増えるのでおすすめしません。
・ページリロードするとファイル選択都度しなきゃいけないのが手間
・自動保存設定してても自動更新されない（ページリロードで反映される）
Rails + React + docker-compose をcapybaraで操作するのにハマった記録

初投稿です。

理解してしまえば簡単なのですが…
結構な時間ハマったので記事に残しておきます。

参考にさせていただいた記事↓ありがとうございます

https://qiita.com/ijufumi/items/badde64d530e6bade382

# 今回の目的
現在、React+Railsのアプリケーションをdocker-composeの環境で制作していまして、
E2Eテストを行うにあたって、Rails側からcapybaraとseleniumを使って操作が必要でした。

# ハマった箇所
dockerコンテナ内からホストOSのlocalhostに接続するという概念。
そもそもdockerの仕組みをよく理解して使っていなかったのが問題でした。




```:docker-compose.yml
chrome:
    image: selenium/standalone-chrome-debug:latest
    ports:
      - 4444:4444
      - 5900:5900
```
docker-compose.ymlに上記を追加
テスト中の様子を見たいのでchrome-debugのコンテナイメージを作成


```ruby:Gemfile
group :development, :test do
...
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
end

```

使ったGemはこの２つ（rspecとかは入っている前提で）
```ruby:rails_helper.rb
Capybara.register_driver :remote_chrome do |app|
  url = "http://chrome:4444/wd/hub"
  caps = ::Selenium::WebDriver::Remote::Capabilities.chrome(
    "goog:chromeOptions" => {
      "args" => [
        "no-sandbox",
        "disable-gpu",
        "window-size=1200,900"
      ]
    }
  )
  Capybara::Selenium::Driver.new(app, browser: :remote, url: url, capabilities: caps)
```
capybaraさんで使うremote_chromeを設定
ここまでの設定は結構参考になるものが多く理解できていましたが。。。

```ruby:rails_helper.rb
config.before(:each, type: :system, js: true) do
    driven_by :remote_chrome
    Capybara.app_host = "http://ホストPCのIPアドレス:ポート番号"
  end
```
jsを使ったテストには先ほど設定したremote_chromeを使うと指定

ここから躓きポイント。
ここで安易に`Capybara.app_host=ｈttp://localhost`としたのだが当然繋がるはずもなく…
ここで言うlocalhostというのは、chromeコンテナ内でのローカルホストの事。
では次に試してみたのがfrontコンテナ（react)のIPである`172.18.xxx.x:3000`
とりあえず繋がる…がしかしcompose upする度に毎回変わるし、corsの設定もうまくいかずRailsとのやりとりができない。。

そこで参考記事に出会い、ホストPCのIPを入力すればいいとのこと。
環境設定→ネットワーク→wifi or Ethernet→詳細→TCP/IPタブ　にあります。
![スクリーンショット 2022-04-12 22.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2512596/eb9c7f9c-ff58-fd58-47c1-6262ce0c2765.gif)

無事繋がりました。corsの設定も問題ないようです。
環境変数に入れてしまえばIPが変わっても動きます。

# まとめ
コンテナ１つにIPアドレスを持っていて互いにそれを使って接続できる。
コンテナからホストPCにもIPアドレスを使って接続できる。
この理解が浅かったので時間を食ってしまいましたが、いい学びになりました。

# 訂正

```ruby:rails_helper.rb
config.before(:each, type: :system, js: true) do
    driven_by :remote_chrome
    Capybara.app_host = "http://front:ポート番号" #今回はReactが入ってるコンテナ名がfrontのため
  end
```
ご指摘いただいた通り、IP指定しなくても`http://コンテナ名：ポート番号`で繋げました！
DockerでRails(web)が立ち上がらずにExit 127と出る場合の対処法

# 経緯
`docker-compose run up`などでコンテナを起動させると、dbは立ち上がるが、Rails(web)のほうが立ち上がらず、`docker-compose ps`で起動状態を確かめると `Exit 127`と表示されました。

# 結論
`docker-compose.yml`ファイル内の文法ミス

# 原因
まず、なぜ`Exit 127`という状態になるのか考えました。
最初に、dockerで終了したコンテナのログを見てみます。
```
xxx_db_1    docker-entrypoint.sh postgres    Up         5432/tcp
xxx_web_1   entrypoint.sh bash -c rm - ...   Exit 127 
```
つぎに、`xxx_web_1`のログを見てみます。
```
% docker logs xxx_web_1
bash: line 1:  bin/rails: No such file or directory
```
`bin/rails` というファイルやディレクトリがありません。

Dockerの設定ファイルで`bin/rails`の箇所を探します。
```ruby:dokcer-compose.yml
web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && \
                      bin/rails db:create && \ 
                      bundle exec rails s -p 3000 -b '0.0.0.0'"
```
`&&`のあとにくる`\`これは何の意味があるのか。これが原因と思って、消して再度起動させてみました。
```ruby:dokcer-compose.yml
command: bash -c "rm -f tmp/pids/server.pid &&
                      bin/rails db:create &&
                      bundle exec rails s -p 3000 -b '0.0.0.0'"
```
```
% docker-compose ps   
          Name                        Command               State           Ports         
------------------------------------------------------------------------------------------
xxx_db_1    docker-entrypoint.sh postgres    Up      5432/tcp              
xxx_web_1   entrypoint.sh bash -c rm - ...   Up      0.0.0.0:3000->3000/tcp
```
Rails(web)が立ち上がりました。
Railsのbinding.irbで処理を止めて変数に代入しようとするとArgumentErrorがでる

# エラーの説明
動作などを確認する際にbinding.irbで処理を止めて変数に値を代入するような処理を行うと
このようなエラーが表示される。
エラーが表示されても変数の代入は行われるし、
binding.irbで処理を止めない場合も問題なく処理は行われる。
なお、binding.irbを記載する箇所、変数や値はどれでもエラーが出るので関係ない模様。
```
irb:001:0> a = 1
/Users/ユーザーネーム/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/hirb-0.7.3/lib/hirb/view.rb:186:in `output_value': wrong number of arguments (given 1, expected 0) (ArgumentError)                                                    
        from <internal:prelude>:5:in `irb'                                                   
        from /Users/ユーザーネーム/workspace/runteq/cook_cost/app/controllers/recipes_controller.rb:9:in `index'
        from /Users/ユーザーネーム/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/actionpack-6.1.4.6/lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'                                                               
        from /Users/ユーザーネーム/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/actionpack-6.1.4.6/lib/abstract_controller/base.rb:228:in `process_action'                                                                               
        from /Users/ユーザーネーム/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/actionpack-6.1.4.6/lib/action_controller/metal/rendering.rb:30:in `process_action'                                                                       
        from /Users/ユーザーネーム/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/actionpack-6.1.4.6/lib/abstract_controller/callbacks.rb:42:in `block in process_action'                                                                  in `process_action'
        from /Users/ユーザーネーム/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/actionpack-6.1.4.6/lib/action_controller/metal/instrumentation.rb:34:in `block in process_action'
        from /Users/ユーザーネーム/.rbenv/versions/3.1.0/lib/ruby/gems/3.1.0/gems/activesupport-6.1.4.6/lib/active_support/notifications.rb:203:in `block in instrument'
        ... 63 levels...
irb:002:0> a
=> 1
```

# バージョンなど
Ruby 3.1.0
Rails 6.1.4.6
hirb 0.7.3

# 原因
ログに記載がある通り、hirbが原因の模様。
詳しい原因を調べてみたが、見つからなかった。

# 対処法
Gemfileから下記を削除。
```
gem 'hirb'
#あれば削除
gem 'hirb-unicode-steakknife'
```

bundle installを実行。

# まとめ
エラーが表示されてしまうものの、処理は問題なく実行されているので、
gemを削除する必要はないのかもしれない。
【備忘録】.phpから別の.phpを実行する

web開発初心者の備忘録です。
ガラパゴスでも自家消費用だからへーきへーき。
# ポイント
include関数とrequire関数を使用することで、外部の.phpを参照する事ができる。(.phpに限らずファイルなら何でも読み込める？未検証。)
それぞれの違いは以下の通り。
- include関数　→　ファイルを読み込めなかった際、E_WARNINGを発生させるが、処理は強行する。
- require関数　→　ファイルを読み込めなかった際、E_COMPILE_ERRORを発生させて、処理も止まる。

https://www.php.net/manual/ja/function.require.php
# ファイル構成
```
IISでルートに設定しているフォルダ
　└ test
　　　├ main.html
　　　├ main.php
　　　├ lib.php
　　　├ main.js
　　　└ jquery-3.6.0.js
```
# ソースコード
```html:main.html
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8"/>
    <title>test</title>

    <script type="text/javascript" src="jquery-3.6.0.js"></script>
    <script type="text/javascript" src="main.js"></script>
</head>

<body>
    <button onclick="hoge()">実行</button>
</body>

<script type="text/javascript" src="main.js"></script>

</html>
```
```javascript:main.js
function hoge() {
    $.ajax({
        type: "GET",
        url: "../test/main.php",
        timeout: 5000
    }).done(($data) => {
        console.log("done");
        console.log($data);
    }).fail(($data) => {
        console.log("fail");
        console.log($data);
    }).always(() => {
        console.log("always");
    });
}
```
```php:main.php
<?php    
    require('lib.php');
    sleep(3);

    echo sample();
?>
```
```php:lib.php
<?php    
    function sample() {
        return "関数呼び出し成功!!";
    }
?>
```
# 結果
![スクリーンショット 2022-04-12 230050.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2628832/031fef48-18fb-d834-18ab-24dc919b6359.jpeg)
いいね
# 最後に
ヘッダファイルっぽく書けるようになり、遺伝子に刻み込まれたC言語も喜んでいます。
- 初学者の備忘録です。
- 片手間でやっているので、記述が曖昧＆雑です。
- 動作したコードをそのまま載せていますが、摩訶不思議な力によりほかの環境では動かないかもしれません。