OmniAICreator/Qiita-1.07M huggingface dataset:
Ruby4

# 問題

```Ruby
class Article

  def initialize(author, title, content)
    @author = author
    @title = title
    @content = content
  end

end
```

上記のコードに追加を行い、以下の出力結果を得られるようにしてください。ただし、クラスとインスタンスを使用するものとします。

```Ruby:ターミナル
著者: 阿部
タイトル: Rubyの素晴らしさについて
本文: Awesome Ruby!
```

<br>
<br>
<br>

# 模範解答

```Ruby:模範解答
class Article

  def initialize(author, title, content)
    @author = author
    @title = title
    @content = content
  end

  def author
    @author
  end

  def title
    @title
  end

  def content
    @content
  end

end

article = Article.new("阿部", "Rubyの素晴らしさについて", "Awesome Ruby!")
puts "著者: #{article.author}"
puts "タイトル: #{article.title}"
puts "本文: #{article.content}"
```

# 【解説】
（23行目）
Article,newでインスタンスを生成します。
変数articleに代入します。その際に、阿部、Rubyの素晴らしさについて、Awesome Ruby!の3つ実引数を指定します。

（3〜7行目）
initializeメソッドを定義して、インスタンス変数を宣言しました。
実引数として指定した値を、仮引数のauthor、 title、contentにそれぞれ渡しています。

そうすることにより、initializeメソッドで宣言されたインスタンス変数に、阿部、Rubyの素晴らしさについて、Awesome Ruby!という3つの値が代入されます。

（9〜19行目）
上記インスタンス変数の値を返すための専用のメソッドをそれぞれ定義しています。

（24〜26行目）
最後に、9〜19行目で定義づけたメソッドを呼び出しています。
data.sqlを使ってテストコードを簡略化してみる

<h2>data.sqlとは</h2>
data.sqlを使用して、テストコードを簡略にしてみた。<br>
data.sqlを使用すると、アプリケーションをロード時にテスト用とか初期にDBにqueryを実行したい時に役に立ちます。
data.sqlの配置パスは・・・src/resources/data.sql！

<h2>data.sql適用前</h2>

下のロジックではfindByBloodType()からgivenPerson()にてPerson Entityにデータを挿入して
ロジックを確認しています。
```java
@Autowired
private PersonRepository personRepository;

@Test
void findByBloodType() {
    givenPerson("martin",10,"A");
    givenPerson("david",9,"B");
    givenPerson("dennis",8,"O");
    givenPerson("sophia",7,"AB");
    givenPerson("benny",6,"A");
   
    List<Person> result = personRepository.findByBloodType("A");

    assertThat(result.size()).isEqualTo(2);
    assertThat(result.get(0).getName()).isEqualTo("martin");
    assertThat(result.get(1).getName()).isEqualTo("benny");
}

private void givenPerson(String name, int age, String bloodType) {
    givenPerson(name, age ,bloodType, null);
}

private void givenPerson(String name, int age, String bloodType, LocalDate birthday) {
    Person person = new Person(name, age,bloodType);
    person.setBirthday(new Birthday(birthday));
    personRepository.save(person);
}
```


<h2>data.sql適用後</h2>

data.sqlにgivenPerson()にて登録したデータのinsert文を作成します。
```java:src/resources/data.sql
insert into person(`id`, `name`, `age`,`blood_type`, `year_of_birthday`,`month_of_birthday`,`day_of_birthday`) values(1,'martin',10, 'A',null,null,null);
insert into person(`id`, `name`, `age`,`blood_type`, `year_of_birthday`,`month_of_birthday`,`day_of_birthday`) values(2,'david',9, 'B',null,null,null);
insert into person(`id`, `name`, `age`,`blood_type`, `year_of_birthday`,`month_of_birthday`,`day_of_birthday`) values(3,'dennis',8, 'O',null,null,null);
insert into person(`id`, `name`, `age`,`blood_type`, `year_of_birthday`,`month_of_birthday`,`day_of_birthday`) values(4,'sophia',7, 'AB',null,null,null);
insert into person(`id`, `name`, `age`,`blood_type`, `year_of_birthday`,`month_of_birthday`,`day_of_birthday`) values(5,'benny',6, 'A',null,null,null);
```
data.sqlに書いたdmlによりデータは作成されるので、givenPerson()は省くことができます。
```java
@Autowired
private PersonRepository personRepository;

@Test
void findByBloodType() {
    List<Person> result = personRepository.findByBloodType("A");

    assertThat(result.size()).isEqualTo(2);
    assertThat(result.get(0).getName()).isEqualTo("martin");
    assertThat(result.get(1).getName()).isEqualTo("benny");
}
```
givenPerson()を削除して、data.sqlを適用した結果、問題なく確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3097775/8ab58066-6866-9eb1-1acd-88e3c0ecc92f.png)
webrick を 1.8.0 に上げたら死んだ件

webrick を使ったウェブアプリを多数保守してるんだが，先日（2023 年 1 月 27日），webrick の 1.8.0 がリリースされたので早速アップデートしたところ，

```
FrozenError: can't modify frozen String: ""
```

が出て，軒並み死んだ。

当初，原因が分からず困っていたが，その日のうちにバージョン 1.8.1 が出て解決した。

1.8.0 で `frozen_string_literal: true` にしたのに

```rb
@body = ''
```

を修正してなかったバグだったぽい。
FreeBSDのUSB HUB

FreeBSDで[uhubctlというオープンソース](https://qiita.com/yamori813/items/a368e95eb91777d00837)がビルドはできるのですが、正常に動作しないので調べたところusbconfigとusb_hubにその機能が実装されているため、コンフリクトして上手く動かないようです。FreeBSD/amd64 13Rで確認しました。

ワインをこぼしてつぶしてしまったApple ProキーボードにはAlcor Micro社のAU9432というチップが使われています。なにかに使えるかと思って基板だけとってありました。

このチップはHUBを内蔵していて、その下にキーボードとUSBポートが2つ出ています。

![ApplePRO.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/5be30e82-4bfb-621c-0188-118d34b19c53.png)

2ポートのUSBにはそれぞれGANGPWRN(39),DP2PWRUP(41)が出ているのでPer-Port（Individualモード）でもギャング（まとめて処理する方式）でもPowerコントロールできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/59e8fa1d-517f-cdc6-b552-61b4b8b268a0.png)

Apple ProキーボードはAnalog Integrations社のAIC1525というSOP8のPowerコントロールチップを使っていて、このチップは一系統しか制御できないのでギャングになります。AIC1525のCTLはAU9432のGANGPWRNにつながっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/d3ba4436-cc5f-ec90-9e11-4bfa2525c671.png)

当初このチップはEEPROMかと思っていたのですが、EEPROMなら本体チップ(AU9432)のすぐ近くに置くはずが、すこし離れていて、よく見たらPowerコントロールチップでした。

そもそもFreeBSDのusbconfigでのPowerコントロールはギャングにしか対応していなくて試してみると以下のようになります。

```
ugen0.2: <Mitsumi Electric Hub in Apple Extended USB Keyboard> at usbus0, cfg=0 md=HOST spd=FULL (12Mbps) pwr=SAVE (50mA)
ugen0.3: <Mitsumi Electric Apple Extended USB Keyboard> at usbus0, cfg=255 md=HOST spd=FULL (12Mbps) pwr=OFF (50mA)
ugen0.4: <Ralink 802.11 n WLAN> at usbus0, cfg=255 md=HOST spd=FULL (12Mbps) pwr=OFF (100mA)
```

この状態で、

```
% sudo usbconfig -d ugen0.2 power_off
```

するとギャングが実行されて、ugen0.3,ugen0.4が見えなくなって、USBポートの電源の5Vも出なくなっているのが確認できます。

同じ状態でugen0.4をpower_offするとデバイスがPowerオフになりますが、給電はされたままです。

usbconfigのmanページに

```
     Power off the device on USB bus 1 at address 2:

           usbconfig ugen1.2 power_off

```

-dが抜けています。おそらく誰も使ってないんでしょうね。

Powerコントロールが無いHUBでpower_offすると給電は行われたまま、ロジックがオフになり、接続されたデバイスが見えなくなるようです。

FreeBSD/mips 12-STABLE(RT3883,AR9341)でも同じように動きました。

usbconfigの今の仕様だとPer-Portをサポートできないので、こうなってしまっているのかもしれません。

大抵のHUBのチップはギャングかPer-Portをサポートしていますが、Powerコントロールが実装されていないケースが多いので、実質的に使えないのも混乱している一因です。

誰かPer-Portのサポート方法を考えてみませんか？

USBの電源でON/OFFできるタップがあるようです。ちょっとお高いようなので、秋月のSSRで自作してみたいと思っています。
競プロ回答

https://atcoder.jp/contests/typical90/tasks/typical90_a

~~~c++
#include <iostream>
#include <string>
#include <vector>
using namespace std;

long long N, L, K;
long long A[1 << 18];

bool validate(long long mid){
  long long check_p = 0;
  long long cnt = 0;
  
  for(int i=0; i<N; i++){
    if(A[i] - check_p >= mid && L - A[i] >= mid){
      check_p = A[i];
      cnt++;
    }
  }
  if(cnt >= K){
    return true;
  }
  return false;
}

int main() {
  cin >> N >> L;
  cin >> K;
  for (int i = 0; i < N; i++){
    cin >> A[i];
  }
  
  long long min = -1;
  long long max = L / (K + 1) + 1;
  bool flag = true;

  while(flag){
    long long mid = (min + max) / 2;
    if(validate(mid)){
      min = mid;
    }else{
      max = mid;
    }
    
    if(max - min <= 1){
      flag = false;
    }
  }

  cout << min << endl;
  return 0;
}
~~~
JavaScript非同期処理をこう解釈した記事。

JavaScriptの非同期処理に関して、前より理解が深まった気がしてるので、ひとまず現時点の理解力を記録するために記事にした。

あとから見返して、全然違うじゃん…となったらそれはそれでご愛嬌だと思うことにします。あくまで備忘録。

### 該当コード
この後に自分が解釈した箇所の参照として、①~⑤の番号を振っています。
コードは、独習JavaScriptテキストの内容であり、直列の非同期処理がうまく処理されないコードとされています。
```Javascript
let count = 0;
    function promiseFactory() {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                count++;
                console.log(`${count}回目のコールです。時刻：[${new Date().toTimeString()}]`);
                if (count === 3) { // 3回目のコールでエラー
                    reject(count);
                } else {
                    resolve(count);
                }
            }, 1000);
        });
    }
    const instance = promiseFactory(); // -------①
    instance
        .then(() => { return instance; }) // -------②
        .then(() => { return instance; }) // -------③
        .then(() => { return instance; }) // -------④
        .catch(errorCount => {
            console.error(`エラーに飛びました。現在のカウントは ${errorCount} です。`);
        }).finally(() => {
            console.log("処理を終了します。");
        });

    // ⑤ ==================
    // > 1回目のコールです。時刻：[16:50:00 GMT+0900 (日本標準時)] 
    // > 処理を終了します。
    // =====================
```

### 自分の解釈
1. __定数の定義とともに関数の実行__
→①ですでにpromiseFactory()を実行済みで、コンソールに表示される一行目はこのタイミングで実行されることによる表示。※実際に①だけ残して、開発ツールもしくはnodeコマンドを実行すると、同じ結果がコンソールに表示される。

2. __始めに定義された定数の使い回し__
→②③④で返されている定数instanceは①で実行されたものと変わらず、再度promiseFactory関数が実行されるわけではないので、同関数の内部にあるcountのインクリメントもconsole.log(...)も実行はされない。

4. __非同期処理関数内から関数スコープ外の変数を使用するのは御法度__
→then()の中でコールバック関数で返されている定数instanceをpromiseFactory()にすると、再度関数が実行されるので1,2,3回目と処理は進みますが、グローバル変数にあるトップレベルの変数などを非同期処理関数内で参照して、処理を加えるのは御法度。


3. __⑤の出力結果は、resolve、rejectの条件処理とは関係ない__
→理由として②③④が何も実行されない処理のためコメントアウトすると、
```JavaScript
    const instance = promiseFactory(); // 
    instance
    .finally(() => {
        console.log("処理を終了します。");
    });
```
となり、初回のpromiseFactory()の実行によるPromiseオブジェクトの戻り値を格納した定数に、.finally()がつながっているだけの処理と変わらず、resolve,rejectの条件分岐を介さない処理と同じだと考えています。


1,2に関しては問題ないかと思うのですが、特に3,4に対するこれらの感覚、解釈は合っているのでしょうか？
私の考え方や間違いがある場合、ぜひ指摘していただけると嬉しいです。
シェルスクリプトでWEBページの更新を検知してDiscordに通知するやつ

# ソースコード
```bash
#!/bin/bash

LAST_MODIFIED="Thu, 17 Oct 2019 07:18:26 GMT"
URL="https://example.com"
DISCORD_WEBHOOK_ADDRESS=""

LM=$( \
    curl -I -s ${URL} \
    | grep --ignore-case "Last-Modified" \
    | sed -e "s/Last-Modified: //i" -e "s/\r//" \
)

if [ ! "$LAST_MODIFIED" = "$LM" ]; then
    curl -X POST -H "Content-Type: application/json" \
        -d '{"content": "Last-Modified is changed at <t:'$(date -d "$LM" +%s)'>. ('"$LM"')"}' \
        ${DISCORD_WEBHOOK_ADDRESS}
fi
```

# 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/210679/84a0eb35-0025-93b0-0aa0-9e99f60ebf40.png)

# 解説
## 変数宣言
```bash
LAST_MODIFIED="Thu, 17 Oct 2019 07:18:26 GMT"
URL="https://example.com"
DISCORD_WEBHOOK_ADDRESS=""
```
`LAST_MODIFIED` 手動で最終更新日を入れておく
`URL` 更新をチェックしたいサイトのアドレス
`DISCORD_WEBHOOK_ADDRESS` WEBページに更新があったときに通知するwebhookのアドレス

## Last-Modifiedの取得
```bash
LM=$( \
	curl -I --silent ${URL} \
	| grep --ignore-case "Last-Modified" \
	| sed -e "s/Last-Modified: //i" -e "s/\r//" \
)
```
`curl -I -s ${URL}` URLのヘッダのみを取得する．サイレントモードで実行する
`grep --ignore-case "Last-Modified"` 大文字小文字を無視して “Last-Modified” の文字列を探す．サイトによって “Last-Modified” だったり “last-modified”だったりしたので
`sed -e "s/Last-Modified: //i" -e "s/\r//"` ”Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT”という文字列を受け取り日時のみを返す．ついでにCR文字を消す

## if
取得した`Last-Modified`の値が手動で入力した値と同じか単純に比較しているだけ．

## webhookのポスト
```bash
curl -X POST -H "Content-Type: application/json" \
    -d '{"content": "Last-Modified is changed at <t:'$(date -d "$LM" +%s)'>. ('"$LM"')"}' \
    ${DISCORD_WEBHOOK_ADDRESS}
```
`<t:'$(date -d "$LM" +%s)'>` Last-ModifiedはGMTらしいのでローカル時間に変換してあげる．
> グリニッジ標準時。 HTTP における時刻は常にグリニッジ標準時で表され、ローカル時刻になることはありません。
> 
[Last-Modified - HTTP | MDN](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Last-Modified)
discordでは `<t:TIMESTAMP>` の形式でUnix Timestampを送ると良い感じにユーザのロケールとタイムゾーンにしてくれる．
[Discord Developer Portal - API Docs for Bots and Developers](https://discord.com/developers/docs/reference#message-formatting)
`date` コマンドに-dオプションで変換したい時間を入れて+%sでUnix Timestamp で出力する．
`"$LM"` Last-Modifiedの値にスペースが入っているのでスペース込みで1つの文字列扱いにするためにダブルクォーテーションで囲んでおく．

`curl`の-dオプションの引数をjson形式にする関係でシングルクォーテーションで囲んでいるが，これだとコマンド置換や変数展開ができない．そこで変数展開が必要な前後で文字列を区切っている(Python だと `'str1' + 'str2'` と書くような感じ．)．Bashだと+が不要なのでそのままつなげればよい(`'str1''str2'`)．このときに見やすくするために `'` と `$` の間にスペースを入れると当然ながら別の引数として認識されてしまう．

# 実行方法
crontabやsystemd timerを利用して何分かおきに走らせたりするといいのではないでしょうか．
```bash
# crontab -e
*/5 * * * * PATH_TO_SCRIPT
```

# おわりに
いかがでしたか．RSSなどが無いサイトで更新をチェックしたいときに使えるTipsでした．
変数を配列で持てば複数サイトにも対応できそうですね．
`Last-Modified` をヘッダに入れてないサイトに対しては無力ですが(笑)．そんな時は`ETag`とか見たら良いんじゃないでしょうか．
しらんけど
【TypeScript】省略可能プロパティが省略されていないことを確認する（自作型）

# 【TypeScript】省略可能プロパティが省略されていないことを確認する（自作型）

TypeScriptはObject型を定義するときに、`?`を付けることで省略可能であることを定義できます。

```ts
type Hoge = { foo: string, bar?: number };
```

これはこれで便利なのですが、場合によってはpropertyを指定し忘れることによるバグの原因にもなってしまいます。

```ts
type ManyProp = { a?: string, b?: string, c?: string, d?: string, e?: string };
const createManyProp = (someObject: any):ManyProp => {
  const { foo: {a, b}, bar: {c, d}, e } = someObject;
  return {
    a: a,
    b: b || undefined,
    c: c,
    d: d || 'default',
    // 忘れ去られたe　←エラーにならず…
  };
};
```

あるべき論でいえば「省略可能にするなよ」と言いたくなりますが、複雑な開発だと「大体の場所では省略可能としておきながら、ここだけは指定し忘れそうで怖い」みたいなことが起こります。
（自分の場合、いま開発しているものの中で関数をラップする開発があり、ラップ対象の関数の引数がいくつか省略可能としておきたいのですが、ラップする以上ちゃんと省略可能なものも含めてすべての引数を渡せていることを担保したいという要求がありました。）

## 今回作成した型～OptionalChecker～

ということで、こんな型を用意してあげる：

```ts
type OptionalKey<T> = { [k in keyof T]: undefined extends T[k] ? k : never }[keyof T];
type OptionalChecker<T> = T & { [k in OptionalKey<T>]: T[k] | undefined };
```

すると、エラーをはいてくれます。

```ts
type ManyProp = { a?: string, b?: string, c?: string, d?: string, e?: string };
const createManyProp = (someObject: any):OptionalChecker<ManyProp> => {
  const { foo: {a, b}, bar: {c, d}, e } = someObject;
  return {
    a: a,
    b: b || undefined,
    c: c,
    d: d || 'default',
    // 忘れ去られたe　← !!!TypeError!!!
  };
};
```

## 参考：コード全体

VSCodeとかに張り付けてみてね。

```ts
type OptionalKey<T> = { [k in keyof T]: undefined extends T[k] ? k : never }[keyof T];
type OptionalChecker<T> = T & { [k in OptionalKey<T>]: T[k] | undefined };

type ManyProp = { a?: string, b?: string, c?: string, d?: string, e?: string };

const createManyProp = (someObject: any):ManyProp => {
  const { foo: {a, b}, bar: {c, d}, e } = someObject;
  return {
    a: a,
    b: b || undefined,
    c: c,
    d: d || 'default',
    // 忘れ去られたe　←エラーにならず…
  };
};

const createManyProp_error = (someObject: any):OptionalChecker<ManyProp> => {
  const { foo: {a, b}, bar: {c, d}, e } = someObject;
  return {
    a: a,
    b: b || undefined,
    c: c,
    d: d || 'default',
    // 忘れ去られたe　← !!!TypeError!!!
  };
};
```
AWS CDK - Assets

# Assets

CDK ライブラリやアプリケーションにバンドルできるローカルファイル 、ディレクトリ、または Docker イメージです。

# S3 アセット

CDK が S3 にアップロードするローカルファイルおよびディレクトリです。

[aws-s3-assets](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_s3_assets-readme.html) モジュールを通じて、パッケージ化し S3 へアップロードすることが可能です。

## Lambda 関数の例

[from_asset](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda.Code.html#static-fromwbrassetpath-options) で、ディレクトリの内容をバンドルし、それを関数のソースコードとして使用します。

```python
from aws_cdk import Stack
from constructs import Construct
from aws_cdk import aws_lambda as lambda_

import os.path
dirname = os.path.dirname(__file__)

class HelloAssetStack(Stack):
    def __init__(self, scope: Construct, id: str, **kwargs):
        super().__init__(scope, id, **kwargs)

        lambda_.Function(self, 'myLambdaFunction',
            code=lambda_.Code.from_asset(os.path.join(dirname, 'handler')),
            runtime=lambda_.Runtime.PYTHON_3_9,
            handler="index.lambda_handler")
```


# Docker イメージアセット

CDK は、ローカルの Docker イメージをアセットとしてバンドルすることもできます。

## 例

ローカルでビルドし、ECR に push する Docker イメージを定義しています。
イメージはローカルの Dockerfile でビルドされ、CDK CLI またはアプリの CI/CD パイプラインによって ECR にアップロードされ、CDK アプリで自然に参照することができます。
この例では、Dockerfile は、CDK が Docker イメージを構築する my-image ディレクトリにあります。ビルド時に、CDK はイメージを ECR リポジトリに push します。

```python
from aws_cdk.aws_ecr_assets import DockerImageAsset

import os.path
dirname = os.path.dirname(__file__)

asset = DockerImageAsset(self, 'MyBuildImage',
    directory=os.path.join(dirname, 'my-image'))
```
【Eclipse】サーバー・ランタイム環境からApacheが削除されてしまった場合の対処方法

### 【概要】
サーバー・ランタイム環境からApacheが削除されてしまった場合の対処方法を備忘録として残します。

### 【経緯】
SpotBugsというプラグインを追加した際に、何故か既存のプラグインが一部削除されてしまいました。
その削除対象にサーバー・ランタイム用のプラグインも含まれており、サーバー・ランタイム環境から削除されたようです。

### 【環境】
Eclipse Version: 2022-12 (4.26.0)


### 【発生事象】
メニュー -> ウィンドウ -> 設定 から
サーバー -> ランタイム環境 の画面を表示して、追加ボタンを押下します。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121997/5d69e3e9-af11-0967-f889-7d224bf4a81c.png)

サーバー・ランタイム環境の一覧が表示されますが、Apacheが存在しないことが確認できます。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121997/666907cc-43ad-5e8e-1e0d-9e7265acd7b7.png)

### 【対処方法】
[Eclipse Enterprise Java and Web Developer Tools](https://marketplace.eclipse.org/content/eclipse-enterprise-java-and-web-developer-tools)というプラグインをインストールするだけです。

#### 1. プラグインのインストール
メニュー -> ヘルプ -> Eclipse マーケットプレース から
`Eclipse Enterprise Java and Web Developer Tools`を検索文字列として検索します。
検索結果の`Eclipse Enterprise Java and Web Developer Tools 3.28`をインストールします。

![1-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121997/6286a9fb-11a0-805f-125d-e646f567c21e.png)

選択されたフィーチャーはデフォルトのままで良いです。
![1-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121997/82ca1252-3052-8360-3328-74c04d84b5d2.png)

私の環境ではライセンスのレビュー画面が表示されましたが、皆さんの環境では表示されないかもしれないです。
![1-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121997/c8f2a13b-b46c-f9a1-87ba-3f731edb003d.png)

署名信頼のためのチェックを入れます。
![1-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121997/01bf24b8-ee4b-9efa-37d4-9b2968d2cee8.png)

#### 2. Eclipse再起動
![1-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121997/f136a38e-b624-b29a-d9e6-b6985ec8d748.png)

#### 3. Apache追加確認
再起動後にサーバー・ランタイム環境を確認するとApacheが追加されていることが確認できます。
![1-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121997/ed4e6dc2-e6b1-fb75-1d04-9de963c626ff.png)
![1-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121997/2eff49b3-ba65-3a37-e98c-02ff2e80029b.png)

### 【参考サイト】
[Cannot get Apache Tomcat server 9 or 10 to appear in my server list.](https://www.reddit.com/r/eclipse/comments/lmqxm2/cannot_get_apache_tomcat_server_9_or_10_to_appear/)
【Vim】行数の表示／非表示

# はじめに
スマホ（Android）で開発するのでVimの環境構築は必須です。

# 動作環境
* Sony Xperia 10 IV
* Android OS 12
* UserLAnd 3.1.4
* Ubuntu 20.04.5 LTS
* Vim 8.1.3741

# 一時的に切り替えたい場合
* 表示
```vim
:set number
```

* 非表示
```vim
:set nonumber
```

# デフォルト設定にしたい場合
* 表示
```~/.vimrc
set number
```

* 非表示
```~/.vimrc
set nonumber
```

# スクリーンショット
* 表示
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118198/28eb815a-a886-9b1e-962f-0c805e2a40d7.png" width=50%>

* 非表示
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118198/d82e16a5-bd77-228a-7315-d5e572d62c87.png" width=50%>
【iOS】エミュレーターにキーボードを表示する方法

最近iOSの開発を勉強中で、自分は良くエミュレーターで確認することが多いのですが、iOSのエミュレーターでキーボードが表示されなかったので、残しておこうと思いました。

# キーボード表示方法
I/O -> keyboard -> Toggle Software Keyboardをクリックします。
これで表示されました。

![スクリーンショット 2023-01-29 14.35.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274615/2e03248f-8bc9-ebb0-ad84-623c2430323a.png)
Unity 2D Game KitをインポートするとRuleTileなんちゃらが出て実行できない

2021.3.17f1で2D Game KitをPackageManagerからインポートすると、
RuleTileなんちゃらのエラーが出て実行できませんでした。
この問題の解決方法と調べ方をメモっておきます。初心者向けと思います。

■解決方法
プロジェクトフォルダある所の、
Assets\2DGamekit\Utilities\Editor\RuleTileEditor.csを削除します。
Unityを再度起動します。
（この時Unityのバージョンがどうのと言われますが、
　そこは別問題なので変換するなどよしなにします）

■調べ方
unity.comで2D Game Kit RuleTileで検索すると、
色々と情報が出てきて書いていました。

■環境
UnityHub3.4.1
Unity2021.3.17f1
2DGameKit1.9.5

■この問題の原因
私なりの理解ですが。
RuleTileクラスが2重定義されてコンパイルエラーになっていた。
そこで、不要な方を削除したのコンパイルが通って実行できたようです。

2重定義になったのは、
2D Game Kitが作られた当時はRuleTileというのは公式がサポートしてなかったが、
新しいバージョンのUnityではサポートされたので、
同じクラスが2個定義されてコンパイルエラーになったようです。
多分、そんなニュアンスであっていると思います。

このような問題は2D Game Kitに限らずあると思うので、
知っておくと似たような問題にぶつかった時に早く解決できそうです。

まだ、よく分かっていない問題。
2D Game Kitのリリースページには
Updated to 2021.3 and ported to URP
URPに移植と書いてたんですが2D URPプロジェクトでインポートすると、
テクスチャがピンクになる現象になりました。
？？？
Composerで[ Composer with `--ignore-platform-req=ext-fileinfo`]エラー解消方法

# エラー内容
composer installでエラー内容：
```php
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Your lock file does not contain a compatible set of packages. Please run composer update.

  Problem 1
    - league/mime-type-detection is locked to version 1.11.0 and an update of this package was not requested.
    - league/mime-type-detection 1.11.0 requires ext-fileinfo * -> it is missing from your system. Install or enable PHP's fileinfo extension.
  Problem 2
    - league/mime-type-detection 1.11.0 requires ext-fileinfo * -> it is missing from your system. Install or enable PHP's fileinfo extension.
    - livewire/livewire v2.11.0 requires league/mime-type-detection ^1.9 -> satisfiable by league/mime-type-detection[1.11.0].
    - livewire/livewire is locked to version v2.11.0 and an update of this package was not requested.

To enable extensions, verify that they are enabled in your .ini files:
    - C:\php\php.ini
You can also run `php --ini` in a terminal to see which files are used by PHP in CLI mode.
Alternatively, you can run Composer with `--ignore-platform-req=ext-fileinfo` to temporarily ignore these required extensions.
```

composer updateでエラー内容：
```php 
Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - league/mime-type-detection[1.4.0, ..., 1.11.0] require ext-fileinfo * -> it is missing from your system. Install or enable PHP's fileinfo extension.
    - livewire/livewire[v2.11.0, ..., v2.11.1] require league/mime-type-detection ^1.9 -> satisfiable by league/mime-type-detection[1.9.0, 1.10.0, 1.11.0].
    - Root composer.json requires livewire/livewire ^2.11 -> satisfiable by livewire/livewire[v2.11.0, v2.11.1].

To enable extensions, verify that they are enabled in your .ini files:
    - C:\php\php.ini
You can also run `php --ini` in a terminal to see which files are used by PHP in CLI mode.
Alternatively, you can run Composer with `--ignore-platform-req=ext-fileinfo` to temporarily ignore these required extensions.

Use the option --with-all-dependen-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.
```

# エラー解消方法／ PHPのiniファイルを変更
```php.ini
extension=fileinfo
```
CakePHP4で出力内容をガラケー用に半角カナ・Shift_JIS化（一括置換）する

　むかーし昔、ガラケー用サイトは文字コードがShift_JISで、通信量削減のためにカタカナは半角にするのが推奨でした。
　出力前に共通処理で変換かけてたりしたなあと思い出しつつ、今CakePHPで同じことをやろうとするなら afterFilter で一括でやってしまいたいなあと思って調べたけれど、なかなか良い例がなかったので、サンプルを書いておきます。

```PHP:AppController.php
    public function afterFilter(EventInterface $event)
    {
        // 出力前の HTML<body> を $body へ
        $this->getResponse()->getBody()->rewind();
        $body = $this->getResponse()->getBody()->getContents();

        // ここに変換する処理を書く
        $body = mb_convert_kana($body, "sk"); // 半角化
        $body = mb_convert_encoding($body, "SJIS-win"); // Shift_JIS化

        // こんな感じで文字列を置き換えたりとかも
        $body = str_replace('変換前', '変換後', $body);

        // 出力
        return $this->getResponse()->withStringBody($body);
    }
```
　User-Agentでガラケーかどうか判定して処理するとか、ヘッダーに文字コード指定を入れてあげたりとかも、ここでまとめてやって良いと思います。
　このへんは他に例がいっぱいあるので省略。

　ちなみにCakePHP3くらいまでは $this->output の中に出力内容が入っていたような覚えがあるけれど、4では書き方が変わっています。
　公式ドキュメントでは getStringBody() という全文取れるようなメソッドが紹介されていますがなぜか存在せず。
　getBody() で取り出せるのはStreamInterface型なので、出力するHTMLのサイズが巨大なときは、readメソッドで少しづつ読み込んで処理するのが使用メモリ量や処理速度の面では良いでしょう。

公式ドキュメント
https://book.cakephp.org/4/ja/core-libraries/httpclient.html#id12

　作っていて思い出したのはガラケーのことなのですが、実際やりたかったことは「㈱」「㍍」などの機種依存文字を普通の文字列に置き換えること。
　本来はDBやAPIから値を取り出すときに変換してあげるべきなのでしょうけれど、どこで使われているのかもはや追い切れないときはこのような方法に。

　そして表示する文字数が変わってしまうと困るので、無理矢理文字を小さくして並べたりといったアクロバティックな変換も。

~~~html
<span style='display:inline-block; font-size:50%; line-height:100%;'>メー<br/>トル</span>
<span style='display:inline-block; transform: scaleX(0.8); letter-spacing:-0.3ex;'>(株)</span>
~~~

　いっそのことFont Awesomeの次のバージョンに機種依存文字が全部入ってくれたら楽なのになあ。
Composerで[The zip extension and unzip/7z commands are both missing]エラー解消対応 Windows環境


Composerでパッケージを入手しようとした場合、zip extensionが見つからないとのエラーが出た時の対処法を説明します。
エラー内容：
```php
Failed to download psr/container from dist: The zip extension and unzip/7z commands are both missing, skipping.                                           
The php.ini used by your command-line PHP is: C:\php\php.ini                   
    Now trying to download from source
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592268/7b8daa8c-fa8a-15bc-e289-d78ef18d35a8.png)


```php
C:\Windows\System32>composer update
Composer could not find a composer.json file in C:\Windows\System32
To initialize a project, please create a composer.json file. See https://getcomposer.org/basic-usage
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592268/f841a143-5be0-2498-bc88-ddd8270b7854.png)
パッケージが無いの理由なであるため、update後にもう一度実行すればエラーが解消されない場合、
PHP 設定ファイルから以下のように設定すとなっているかの確認を行ってください。
コメントアウトを外して下記ように設定することで上記エラーの解消となります。
```php.ini
extension=zip
```
Web技術の基本 Chapter2　まとめ

## webを実現するコンピューターネットワーク

- ネットワーク上で情報やサービスを提供する役割を持つコンピューターのことをサーバーという。
- スマートフォンやパソコンなどの情報を表示する媒体をクライアントという。
- インターネットにつながるためにインターネットサービスプロバイダーが提供するサービスを利用しなければいけない。(例)KDDIなど

## インターネットの標準プロトコル

- ネットワークに接続された機器同士が通信をする際に決められた共通のルールをプロトコルという。(お互いに同じプロトコルを使用しなければいけない)
- インターネットのさまざまなサービスを実現するためのプロトコルの集まりをTCP/IP(Transmission Control Protocol/Internet Protocol)という。
- TCP/IPの中にHTTPも含まれており、HTTPの足りない部分を補っている。

## TCP/IPについて

- TCP/IPは4つの階層(レイヤー)に分かれている。
    - アプリケーション層
        - (役割)アプリケーションごとのやりとりを規定(HTTPなど)
    - トランスポート層
        - データの分割や品質保証の規定(TCPなど)
            - TCPは、送信側と受信側でお互いに確認をとりながら通信を行う(webサイトやメールなどで使用される)
    - インターネット層
        - ネットワーク間の通信規格(IPなど)
    - ネットワークインターフェース層
        - コネクタ形状や周波数といったハード。ウェアに関する規定(WiFiなど)
    
    この4つの層が連携することによりインターネット通信が可能になっている。
    
- データの流れとしては、下から順にネットワークインターフェース層→インターネット層→トランスポート層→アプリケーション層で行っている。

## IPアドレスとポート番号

- IPアドレスとは、インターネットに接続されたコンピューターに必ず命名されており、データの行き先を管理するために利用されている。(住所のようなもの)
- ポート番号とは、コンピューターが提供するサービスをしてする番号。
    - IPアドレスでは接続したいコンピューターを指定できますが、サービスまで指定できないためポート番号を用いる
    - webサーバーは80番を使用。

## URLとドメイン

- webサイトを閲覧する際に用いられる文字列をURL(Uniform Resource Locator)という。
- ドメインとは、IPアドレスと同じ役割を持つ文字列という。(IPアドレスが覚えにくいためドメインを使用する)
    - http://example.com:80/index.html
        
        スキーム名://ホスト名(ドメイン名):ポート名/パス名
        

## DNS

- ドメインをIPアドレスに変換する仕組みをDNS(Domain Name System)という。
    - ドメインを使用する際に、IPアドレスに一度変換して接続する必要があるためDNSを使う。(携帯で例をすると　名前をタップ → 電話帳からさがす → 電話番号に変換して発信)

## HTTP

- HTTP(Hyper Text Yransfer Protocol)とは、webサイトとサーバーとのやり取りの手順や内容を決めた指標です。
    - やり取り手順
        
        ①ブラウザにURLを入力、またはリンクをクリック。
        
        ②URLやリンク情報に基づいてwebサーバーにデータを要求。
        
        ③ブラウザにより受け取った要求を解析。
        
        ④解析した結果により、要求されたデータをwebブラウザに送信。
        
        ⑤webブラウザは、受け取ったデータを解析しHTMLを生成、表示。
GASでLINEに入荷通知を送る

# はじめに
突然ですが，みなさんはKeyballをご存じですか？

Keyballは[白銀ラボさん](https://shirogane-lab.com)で販売されている左右分離型の自作キーボードで，トラックボールと一体化されているのが非常に魅力的です。

https://shirogane-lab.com/products/keyball39

しかしこのキーボード，人気過ぎて再販されてもすぐに売り切れてしまいます。そこで今回は，商品が入荷されたらLINEに通知してくれるようなシステムを作りたいと思います。


# 概要
GASとLINE Notifyを使って，商品の入荷(webサイトの更新)をLINEで通知してくれるシステムの構築

# 実装
### LINE Notifyの連携
こちらの記事を参考にLINE Notifyの連携を行いました。トークンが入手できていればOKです。

https://tetsuooo.net/gas/2739/

### プログラムの作成

作成したプログラムは以下になります。
```javascript
function detect_updates() {
  const token = 'LINE Notifyで取得したトークン'
  const lineNotifyApi = 'https://notify-api.line.me/api/notify';

  const url = 'https://shirogane-lab.com/products/keyball61'
  const html = UrlFetchApp.fetch(url).getContentText('UTF-8');

  const $ = Cheerio.load(html);
  const $text = $('.product-form__submit').children('span').text();

  if ($text.replace(/\r?\n/g, '') !== '売り切れ') {
    let message = '\nkeyball入荷されたかも！\n\n' + url;
    const options =
    {
        "method"  : "post",
        "payload" : {"message": message},
        "headers" : {"Authorization":"Bearer " + token}
    };
    UrlFetchApp.fetch(lineNotifyApi, options);
  }
}
```

今回は，Cheerioライブラリを使うので，GASにCheerioライブラリを追加しておいてください。

https://yamamtoblog.com/gas-screiping/

また，スクレイピングを行う際は，事前にサイトの利用規約やRobots.txtを確認しておきましょう。

https://umano-ie.com/scraping-rules/

以降プログラムの解説です。

```javascript
const url = 'https://shirogane-lab.com/products/keyball61'
```

変更を感知したいサイトのurlを指定してください。今回はKeyball61のurl。

```javascript
const html = UrlFetchApp.fetch(url).getContentText('UTF-8');

const $ = Cheerio.load(html);
const $text = $('.product-form__submit').children('span').text();
```

fetchでページのソースコードを持ってきた後に，Cheerioライブラリを利用してほしい要素を取得します。

サイトを確認すると，購入ボタンの中の文字が「売り切れ」か「カートに追加する」の二択になっていることがわかるので，そこを見て入荷の判断をすればよいことがわかります。

開発者ツールでサイトのソースコードを確認すると，今回はproduct-form__submitクラスのなかのspanタグの中の文字列を取得すればよいこともわかります。(サイトごとにここは考え直す必要があります)


あとは，Cheerioライブラリの記法にしたがって記述するだけです。詳しくはドキュメントを参考にしてみてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/359441/0e585926-8663-df3c-acb5-719f657481ff.png)

```javascript
if ($text.replace(/\r?\n/g, '') !== '売り切れ') {
    ...
```

購入ボタンの中の文字列が「売り切れ」かどうかを判定します。$textは改行文字を含んでいるため，改行文字を消した後に比較する必要があります。こいつのせいで無駄に時間を消費しました...。

あとは，GASの機能であるトリガーを利用して，今回作成した関数を定期実行してあげれば完了です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/359441/c8eaa47f-04e1-3a3b-521b-fd5ddbd3f8ea.png)

最後に，ちゃんと通知が来るか，売り切れていない商品でテストしてみます。

![68374.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/359441/13654c65-389d-1fd5-3bde-040ea7c83852.jpeg)

これで，ページが更新されたタイミングでLINE通知が来るシステムが構築できました。

# おわりに
Keyballﾎｼｲﾖ..
Laravelで主に使用してきたデバック方法

## 前置き
Laravelでの開発をスムーズに進めるために必要な方法になると思います。
実務経験から主に使っているデバック方法を紹介します。

## 紹介するデバック
以下3つを紹介します。

・dd()
・dump()
・Logファザード(Log::~)

dd()とdump()はビューに出力を行い、Logファザードはlogs/laravel.logに出力されます。

## dd()
dd()は、使用した時点で処理を終了させます。
その為、それ以降の処理を行うことはありません。
```php
      $array = [
                 'a' => 'あ',
                 'i' => 'い'
             ];
      dd($array);// ここで処理止まる

      $a = $array['a'];
```
上記の場合、最後の行の$aの部分の処理は行われません。
🔽出力結果
![スクリーンショット 2023-01-29 13.16.56のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819422/77a6215d-207d-ef39-bc65-ba8ad83b0a85.png)


## dump()
dump()は、使用した時点での内容を表示します。
dd()とは違い、使用した後の処理も継続しておこなわれます。
```php
      $array = [
                 'a' => 'あ',
                 'i' => 'い'
             ];
      dump($array);// ↓このあとも処理継続

      $a = $array['a'];
```
上記の場合、ビューに処理結果を表示しつつ、$arrayの内容もビューに表示されます。
🔽出力結果
![スクリーンショット 2023-01-29 13.16.56のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819422/9d47a57d-8580-4954-5a90-059f7ca2c7f9.png)
dd()を使用した時と表示方法は同じです。


## dd()とdump()の併用
dd()とdump()を使うこともできます。
```php
      $array = [
                 'a' => 'あ',
                 'i' => 'い'
             ];
      dump($array);// ↓このあとも処理継続

      $array['u'] = 'う';

      dd($array);
```
上記のどうなるでしょうか？
最初にdump()の内容が出力され、その後にdd()の内容が出力されます。
🔽出力結果
![スクリーンショット 2023-01-29 13.16.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819422/60aff95e-5beb-f8d2-a71a-14ff7f0204c3.png)
$arrayの内容が変わっていることを確認することができます。


## Logファザード(Log::~)
dd()のように、使用した時点で後続処理が止まることはありません。

Logファザードは、8つのログレベルが存在しています。
ログレベルは、以下の記事を参考にするとわかりやすいでしょう。
[Laravel 8.x ログ](https://readouble.com/laravel/8.x/ja/logging.html#:~:text=%E3%83%AD%E3%82%B0-,%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8,-%E3%81%AE%E6%9B%B8%E3%81%8D%E8%BE%BC%E3%81%BF)

```php
      $a = 'a';
      Log::info($a);

      // 出力結果: a
```
配列やオブジェクトの場合は、文字列にしてから表示する必要があります。
```php
      $array = [
                 1 => 'one',
                 2 => 'two'
             ];
      Log::info(json_encode($array));
      
      // 出力結果: {“1”:“one”,“2”:“two”}
```

## まとめ
変数など確認できる方法を知っておくと、開発がスムーズになります。
参考の1つになれば幸いです。

## 参考文献
[Laravel 8.x ログ](https://readouble.com/laravel/8.x/ja/logging.html#:~:text=%E3%83%AD%E3%82%B0-,%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8,-%E3%81%AE%E6%9B%B8%E3%81%8D%E8%BE%BC%E3%81%BF)
[json_encode-Manual-PHP](https://www.php.net/manual/ja/function.json-encode.php)
[Laravelでできるいろいろなデバッグ方法](https://zenn.dev/qljmssqh/articles/290f8611a9ca7e)
LOLチャンピオン一覧を取得してみよう

前提
・GAS実行方法を知っている
・LOLのJSON取得URLを知っている
知らない人は以下参考

https://qiita.com/gungungggun/items/9e0752e4ba6e7eeb813a

https://qiita.com/hikozuma/items/b3b6f717fb064e03985b

チャンピオン一覧の取得方法は以下の通りです。

``` GAS
function getChampionNames() {
  var url = "https://ddragon.leagueoflegends.com/cdn/13.1.1/data/ja_JP/champion.json";
  var response = UrlFetchApp.fetch(url);
  var json = JSON.parse(response.getContentText());
  var championData = json.data;
  var names = [];
  for (var key in championData) {
    names.push(championData[key].name);
  }
  console.log(names);

  return names;
}
```


応用編（チャンピオン達のスキルを取得してみよう）
``` GAS
const VERSION = "13.1.1";
const URL = `https://ddragon.leagueoflegends.com/cdn/${VERSION}/data/ja_JP/`;

function createChampionSheet() {
    // Get Champion IDs from the API
    const championIds = getChampionIds();
    console.log("Champion IDs: ", championIds);

    // Loop through each champion ID to get their data
    for (const championId of championIds) {
        myFunction(championId);
    }
}

function getChampionIds() {
    // Fetch Champion data from the API
    const url = `${URL}champion.json`;
    const json = UrlFetchApp.fetch(url).getContentText();
    const data = JSON.parse(json);
    const championData = data.data;

    // Extract champion IDs from the data
    const championIds = Object.keys(championData);
    console.log("Champion IDs: ", championIds);

    return championIds;
}

function myFunction(championId) {
    // Fetch champion data from the API
    const url = `${URL}champion/${championId}.json`;
    const response = UrlFetchApp.fetch(url);
    const data = JSON.parse(response.getContentText());
    console.log("Champion Data: ", data);

    // Get the active spreadsheet
    const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();

    // Create sheet if it doesn't exist, otherwise get the sheet
    let sheet = spreadsheet.getSheetByName(championId);
    if (!sheet) {
        sheet = spreadsheet.insertSheet(championId);
    }else{
      // Clear the sheet
      sheet.clear();
    }

    const champion = data.data[championId];
    // Get champion skills data
    const skills = champion.spells;
    console.log("Champion Skills1: ", skills);

    // Prepare data for writing to sheet
    const skillName = [];
    const skillDescription = [];
    const skillImageUrl = [];
    for (const skill of skills) {
        skillName.push(skill.name);
        skillDescription.push(skill.description);
        skillImageUrl.push(
          `=Image("https://ddragon.leagueoflegends.com/cdn/${VERSION}/img/spell/${skill.image.full}")`
          );
    console.log("Champion Skills2: ", skills);
    }

    // Write data to sheet
    sheet.appendRow([champion.name, champion.title, champion.blurb]);
    sheet.appendRow(["スキル名", "スキルの説明", "スキルの画像URL"]);
    for (let i = 0; i < skills.length; i++) {
        sheet.appendRow([skillName[i], skillDescription[i].replace(/<br>/g, "\n"), skillImageUrl[i]]);
        console.log("Champion Skills3: ", skills);
    }
}
```
PythonにおけるLinterとFormatterのテンプレ

プロジェクト毎にLinterやFormatterの設定をするのはめんどくさいので、いつでも使い回せるように、pipを使ってpythonのテンプレートを作っておこうと思います。

## ツール
以下のパッケージを使用しています。
- black
- isort
- flake8


## 設定ファイル
```toml:pyproject.toml
[tool.black]
line-length = 88

[tool.isort]
profile = "black"
line_length = 88
```

```.flake8
[flake8]
max-line-length = 88
extend-ignore = E203
```

```json:.vscode/settings.json
{
  "python.linting.enabled": true,
  "python.linting.pylintEnabled": false,
  "python.linting.flake8Enabled": true,
  "python.linting.lintOnSave": true,
  "python.formatting.provider": "black",
  "python.formatting.blackArgs": [
      "--line-length",
      "88"
  ],
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
      "source.organizeImports": true
  }
}
```

```Makefile:Makefile
install:
	pip install --upgrade pip
	pip install -r requirements.txt

uninstall:
	pip install --upgrade pip
	pip freeze | xargs pip uninstall -y

freeze:
	pip install --upgrade pip
	pip freeze > requirements.txt

format:
	black src
	isort src

lint:
	flake8 src
```

## 使用例
まず、必要なライブラリをインストールします。
```sh:zsh
pip install black isort flake8
```

適宜、FormatterやLinterを実行します。
```sh:zsh
make format
# or 
make lint
```

## 参考
[1] [Pythonのコードフォーマッターについての個人的ベストプラクティス](https://qiita.com/sin9270/items/85e2dab4c0144c79987d)
gradioのgr.Interfaceについて

# はじめに
gradioを使えば簡単な機械学習のデモアプリが作れます．
公式のドキュメント
https://www.gradio.app/docs/
公式のクイックスタート
https://gradio.app/quickstart/

上記のサイトを見れば分かると思いますが，ここでは自分の解釈を書いていきます．

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [gr.Interfaceについて](#Chapter1)
1. [複数入力のとき](#Chapter2)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# gr.Interfaceについて
gradioを扱う上で一番大事なところかつ，ここさえ分かっていればOKなところです．
必要な引数が，fn,inputs,outputsの3つあります．


下のコードは，入力が画像，出力がラベルである，画像の識別問題です．（公式サイトにあるコード）
今回は識別はせずに固定値を出力しているようにしています．
```py
import gradio as gr

def image_classifier(inp):
    return {'cat': 0.3, 'dog': 0.7}

demo = gr.Interface(fn=image_classifier, inputs="image", outputs="label")
demo.launch()
```
簡単に書くと，fnという関数にinputsの値を引数として渡して，その出力をoutputsとするよみたいな感じです．
そのとき，inputsの型とoutputsの型を事前に決めておいてねという感じです．
型が決まらないと，UIの方の入力ボックスが決まらないからですね．

```py
def fn(inputs):
    return outputs

outputs = fn(inputs)
```



<a id="#Chapter2"></a>
# 複数入力のとき
入力が複数のときは，inputs=[]にするといいです．
出力が複数あるときも同じくoutputs=[]でいいです．
inputsの中身順番と，fnの引数の順番は通じているから，合わせるようにしないといけません．
```py
import gradio as gr

def greet(firstname, lastname):
    name = firstname + ' ' +lastname
    return name, len(firstname + lastname)

demo = gr.Interface(
    fn=greet,
    inputs=["text", "text"],
    outputs=["text", "text"],
)
demo.launch()

```

<a id="#reference"></a>
# 参考文献

| No |    内容     |    URL    |
|---:|-------------|------------|
| 1  |         公式のドキュメント    |     https://www.gradio.app/docs/       |
| 2  |            公式のクイックスタート |      https://gradio.app/quickstart/      |
[Rails7]でcredentials.yml.encをVSCodeで開けなかったので、その解決法

# はじめに

credentials.yml.encをVSCodeで編集しようとした際に、開けなかったのでその解決法です。

【環境】

-ハードウェア情報
MacOS Monterey(version: 12.6.2)

-ソフトウェア情報
・Ruby Version: ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-darwin21]
・Rails Version:  7.0.4.2

# 発生した問題

```bash
% EDITOR="code --wait" rails credentials:edit
File encrypted and saved.
```

と表示されて、ファイルが開かないという状況。

# 解決法

結論、VSCodeのパスが通っていないことが原因でした。

確認のため、プロジェクトフォルダでcodeコマンドを実行しても認識してなかったら同じ現象だと思われます。

```bash
% code .
zsh: command not found: code
```

VSCode内でパスを通すことができるので、（⇧⌘P）でコマンドパレットを開きます。

フォームが現れたら「>shell command」と入力して、

“シェルコマンド: PATH内に’code’コマンドをインストールします”を選択します。

![vscode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2570178/c74f4c96-a3c1-daf1-bdd8-f0c28b0170e8.png)
これで、パスが通りCodeコマンドが使えるようになります。

再度、開くか挑戦。

```bash
% EDITOR="code --wait" rails credentials:edit
```

無事、開けました😂

```yaml
# aws:
#   access_key_id: 123
#   secret_access_key: 345

# Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.
secret_key_base: ebe9deaddb85570bfef...
```
# 参考
VS Code公式ドキュメント: [https://code.visualstudio.com/docs/setup/mac](https://code.visualstudio.com/docs/setup/mac)
standard_init_linux.go:228: exec user process caused: no such file or directory


# 概要
Dockerfileで参考サイトからコピペしてきたものを、alpineベースに変更する際に発生。
タイトルのようなエラーメッセージからはわかりにくいので解決方法を共有しておく。

# 解決方法
entrypoint.shなどのシェルファイルの記述を `bash` -> `ash`　に変更します。

```diff_shell:entrypoint.sh
-#!/bin/bash
+#!/bin/ash
```

# 参考
原因は他のパターンもあるらしいので詳しく記載されている方のリンク貼っておきます。
https://qiita.com/kabik/items/5591f62c0ef6ddef5db2
https://dev.classmethod.jp/articles/how-to-fix-standard-init-linux-error/
https://rikeiin.hatenablog.com/entry/2021/01/25/163901
TypeError: Invalid comparison between dtype=datetime64[ns, UTC] and datetime



TypeError: Invalid comparison between dtype=datetime64[ns, UTC] and datetime

- 片方にタイムゾーンがあり、もう片方にタイムゾーンがない場合は比較できない
- データ形式を合わせる必要がある

DataFrame
```
          price   size                 timestamp
0      23000.50  0.001 2023-01-28 21:58:48+00:00
1      23000.00  0.008 2023-01-28 21:58:51+00:00
2      23000.00  0.001 2023-01-28 21:58:51+00:00
3      22999.50  0.001 2023-01-28 21:58:51+00:00
4      22999.50  0.016 2023-01-28 21:58:51+00:00
```

x
```py
df = df[df['timestamp'] > dt.datetime(2023,1,29)]
```

◯
```py
time = pd.Timestamp('2023-01-29 00:00:00+00:00')
df = df[df['timestamp'] > time]
```


https://github.com/dask/dask/issues/7986
Unity PackageManagerでThere are no assets.が表示される

Unityを久々に触ったら、
UnityのPackageManagerを開くとThere are no assets.と表示されました。

前にも同じような事があり、
直すのに時間が取られるのでメモっておきます。

■環境
Unity 2021.3.11.f1
UnityHub 3.4.1

■この問題のきっかけと考えられる操作
・Wifiルーターの初期化とかしました。
・Unityの別のバージョンをインストールしました。

■解決方法
UnityHubでサインインし直す。
手順はUnityHubの歯車マークからSignOut→SignInします。

原因は良く分かりませんが、
サインインが上手くいってないのでしょう。
ABC287回答メモ

0.はじめに
　Cのグラフ問題にてこずるも、Dはすんなり解けたので
　意外と高レートをゲットできました。
　ただ、Cはもう少し頑張れば時間内AC頂けたと思うので
　その点は反省・・・。

1.A - Majority
　A問題なので素直に順に読んでカウントして
　過半数が賛成だったらYesを出力。で作りました。
　工夫というか、面倒だったので、賛成判定は
　インプット文字列の文字数で判断しました。

　https://atcoder.jp/contests/abc287/submissions/38379714

2.B - Postal Card
　S文字列は下3桁をリストに入れておいて
　T文字列は辞書登録。
　最後にリストを頭から辞書にあるかチェックしてカウントを
　最後に表示。
　と素直に解きました。

　https://atcoder.jp/contests/abc287/submissions/38386377

3.C - Path Graph?
　パスグラフは各頂点が一直線に並ぶと理解し
　単純に、各頂点について、辺の頂点として現れる数をカウント
　　→各頂点のカウントが、1が2つ、そのほかが２
　となればいいのでは！と思い実装。
　　→そんな簡単な話でもなくAC30、WA6
　意外といけるかもと微調整するもうまくいかず
　ググると閉路判定が必要ということで、そこらへん含めて実装
　→AC33、WA3　→なんか根本的な問題かなと思いすっ飛ばしました。

　その後解説を見ると、頂点数-辺数＝１という条件もあったので
　それを付け加えたら、AC頂けました・・・。
　条件自体は気づいていたので、実装できず無念です・・・。

　https://atcoder.jp/contests/abc287/submissions/38405605

4.D - Match or Not
　自分的には、C問題レベルな気がしながらときはじめ

　考え方
　　先頭からみていって一致する部分と
　　末尾から見ていって一致する部分で
　　Tの文字列が作れるか？を簡単に判断できる方法を検討
　実装方法
　　1)リストFCは、先頭からTとSを一文字ずつ比較し
　　先頭から一致しなかった場合(同じ文字orどちらかが？ではない場合)文字数を保持
　　実際は一致しなくなったらあとは１でいいけど面倒なのでそのように実装
　　例）
　　　aabaa
　　　aaaa
　　　FC：0,0,1,1

　　2)リストBCは、末尾からTとSを一文字ずつ比較し
　　末尾から一致しなかった文字数を保持
　　実際は一致しなくなったらあとは１でいいけど面倒なのでそのように実装
　　例）
　　　aabaa
　　　aaaa
　　　BC：1,1,0,0

   3)xを0からlen(T)まで以下の判定
　　xが0の時(後方一致判定)
　　　BC[x]の値が0ならYes違えばNo(例だとNo)
　　xがlen(T)と同じ場合(前方一致判定)
　　　FC[x]の値が0ならYes違えばNo(例だとNo)
　　xがそれ以外の場合
　　　FC[x-1]とBC[x]の合計が0ならYesそれ以外No
　　　→例だと、x＝2の時、Yes
　　出力例）
　　　No
　　　No
　　　Yes
　　　No
　　　No
　TLEだけ心配でしたが、余裕でした。

　https://atcoder.jp/contests/abc287/submissions/38413239

5.E - Karuta
　残り30分位でとりかかってみるも、AC17、TLE16。
　時間を減らす工夫が思いつきませんでした。
　ユーザー解説に、ソートすれば前後の文字との比較で済むとあり
　目からうろこでした・・・。
　ソートしてからチェックすれば、TLEも出ずAC頂けました。

　実装
　　1)文字列のリストをLに格納
　　2)LをソートしたリストSLを作成
　　3)SLを先頭から読み込み
　　　前後の文字列と戦闘から比較して
　　　辞書にキーを文字列、値を一致する数が多い方を登録
　　4)Lを先頭から読みこみ、文字列で辞書を検索して
　　　値を表示

　https://atcoder.jp/contests/abc287/submissions/38437825　

以上
neosでlogix その102

# 概要
neosでlogixやってみる。
logixを、俺コードで表現してみる。

# 参考にしたページ

smalllight

https://logix-educational-institute.github.io/NeosVRJP-Techbook/examples/SmallLight.html


# 俺コード

右クリックで小さく。
ｒキーで大きくなる。

```
{_, _, _, _, a, b, _, _, _, _} = StandardController GetActiveUser <Right>
c = a
	|> ? 1.03,1.03,1.03 0.97,0.97,0.97

{_, d, _, _, _, _} = Raycaster 0,1,0 0,1,0 1000 false

e = d
	|> GetSlot
	|> GetObjectRoot

f = | a b

g = FireWhileTrue e
	|> LocalImpulseTimeout 0.25

Slot.Active = e
	|> GlobalTransform
	|> X c
	|> SetGlobalScale f g


```

以上。
[Google Cloud][Cloud SQL] Cloud SQLを削除すると、同名インスタンス作成時にタイムラグが発生。Terraform での対処方法を紹介

# 問題点
「Cloud SQL インスタンス削除の後に同じ名前のインスタンスを作成する際にタイムラグが発生する」という問題があります。
これは、Cloud SQL インスタンスを削除すると、そのインスタンス名は数日間保持されるためです。
そのため、インスタンスを削除して直ぐに同じ名前でインスタンスを作成することはできません。

# 対象方法の例
この問題を解決するためには、インスタンス名にタイムスタンプを使用することが有効です。

以下は、タイムスタンプを使用した `Google Cloud SQL` インスタンスを作成する `Terraform` のサンプルです。

```terraform
resource "google_sql_database_instance" "example" {
  name          = "example-${timestamp()}"
  region        = "us-central"
  database_version = "POSTGRES_11"
  settings {
    tier = "db-f1-micro"
  }
}
```

このように、インスタンス名にタイムスタンプを付けることで、同じ名前のインスタンスを作成しないようにすることができます。

もしくは、以下のようにすることができます。
```terraform
locals {
    timestamp = timestamp()
}

resource "google_sql_database_instance" "example" {
  name          = "example-${local.timestamp}"
  region        = "us-central"
  database_version = "POSTGRES_11"
  settings {
    tier = "db-f1-micro"
  }
}
```
作成した日付を付けることもできます。
```terraform
resource "google_sql_database_instance" "example" {
  name          = "example-${formatdate("yyyy-MM-dd-HH-mm-ss", timestamp())}"
  region        = "us-central"
  database_version = "POSTGRES_11"
  settings {
    tier = "db-f1-micro"
  }
}
```
上記のコードは、現在の日時をyyyy-MM-dd-HH-mm-ss形式で取得し、インスタンス名に加えて、インスタンスを作成します。
これにより、同じ名前のインスタンスを作成しないようにすることができます。

https://developer.hashicorp.com/terraform/language/functions/timeadd

注意点：上記のコードで使用している formatdate 関数は、Terraform v0.13.0 以降で使用可能な組み込み関数です。そのため、それ以前のバージョンの Terraform では、外部のライブラリやプラグインを使用する必要があります。
PlayをGraalVMで動かす（コンパイルタイムDI編）

以前、[PlayをGraalVMで動かす記事](https://qiita.com/kijuky/items/ab3d1aecc9e4466145f9)を書いて、Playが[Guice](https://github.com/google/guice/wiki/Motivation)（ランタイムDI）ベースなことに愚痴ってたら「[コンパイルタイムDIもある](https://www.playframework.com/documentation/2.8.x/ScalaCompileTimeDependencyInjection)よ」とアドバイスを受けたので、試してみました。

https://twitter.com/gakuzzzz/status/1571052080592457729

https://www.playframework.com/documentation/2.8.x/ScalaCompileTimeDependencyInjection

# やってみた

早速ですが、コード差分です。

https://github.com/kijuky/play-on-graalvm/compare/main...feature/compile-time-di

仕事でPlayのバージョンアップ([2.3->2.4](https://www.playframework.com/documentation/2.8.x/Migration24))をやっていて、そこで[DIについて調べることがあった](https://www.playframework.com/documentation/2.8.x/Migration24#Dependency-Injection)ので、コードの修正についてはそこまでつまづくことがなかったです。基本的には下記の通り。

- Guice関連の依存ライブラリを`build.sbt`から外す。
- `@Inject`や`@Singleton`など、ランタイムDI関連のアノテーションを外す。
- 独自の[ApplicationLoader](https://www.playframework.com/documentation/2.8.x/api/scala/play/api/ApplicationLoader.html)を作る。基本的には後述するApplicationComponentを作って`.application`を呼び出す実装にする。こうすると、テスト時にApplicationComponentを再利用できる。
- [BuildInComponentsFromContext](https://www.playframework.com/documentation/2.8.x/api/scala/play/api/BuiltInComponentsFromContext.html)を継承した独自のApplicationComponentを作る。InjectedRoutesGeneratorによって作られたrouter.Routesクラスをインスタンス化するために必要なコントローラーをせっせと作る。[MacWire](https://github.com/softwaremill/macwire/blob/master/README.md)を使わない場合、コンストラクタ引数の順序に注意する。

より詳しい方法はこちら。

https://loicdescotte.github.io/posts/play24-compile-time-di/

https://dvirf1.github.io/play-tutorial/posts/compile-time-dependency-injection/

# 感想

目論見通り、[reflect-config.json](https://www.graalvm.org/22.0/reference-manual/native-image/Reflection/#manual-configuration)からGuice関連のクラスの定義が減っていました。しかし、[akka](https://akka.io/docs/)や[Logback](https://logback.qos.ch/documentation.html)の内部で[Class.forName](https://docs.oracle.com/javase/jp/19/docs/api/java.base/java/lang/Class.html#forName(java.lang.String))を多用しているようで、reflect-config.jsonを完全に無くすことはできませんでした。ただ、今回得られたreflect-config.jsonをPlay本体に加えることで、コンパイルタイムDIを採用している場合にGraalVM化する手間を多少は省けるのではないかなぁと考えています。※ApplicationLoaderだけはどうしてもreflect-config.jsonに追加する必要がある... Play本体を改修して、play.application.loaderのクラスから動的にreflect-config.jsonを作るのはありかもしれない。

Guice版もコンパイルタイムDI版も、結局は同じだけクラスをコンパイルする必要があるので、コンパイル時間は双方そんなに変わりませんでした。Guice版は依存関係をランタイムで解決するのでコンパイルが早いのが特徴ですが、GraalVMとしてビルドしてしまうとそのメリットがなくなってしまいますね。。

また、Guice版は、DI対象が増えるとreflect-config.jsonに追記が必要になりますが、コンパイルタイムDI版はその必要がありません。運用面を考えると、コンパイルタイムDI版の方が手軽かもしれません。

# まとめ

PlayのコンパイルタイムDI版でGraalVM化してみました。必要なreflect-config.jsonが少なくなり、運用面でGuice版より有利になるので、GraalVM化するならコンパイルタイムDI版の方が良さそうです。

最近では、[OpenJDKにはGraalVMが付いてくるらしい](https://www.publickey1.jp/blog/22/openjdkgraalvmopenjdk.html)ですし、[Quarkus](https://ja.quarkus.io/guides/building-native-image)や[Spring Booot](https://spring.pleiades.io/spring-boot/docs/current/reference/html/native-image.html)はGraalVMオプションが標準で付いているので、Playもその波に乗れると嬉しいですね（[マージしてほしい...](https://github.com/playframework/playframework/pull/11371)）。