OmniAICreator/Qiita-1.07M huggingface dataset:
【Python】indexメソッドを駆使してキーワードの置換を行う方法

# 概要

以下のようなテキストが連携されるプログラムがあるとします。

> text = "私は今新宿駅。1時間圏内に渋谷駅がある。また、同じ1時間圏内に横浜駅がある。"

ただし、たまに、一文切り落とされ（渋谷駅のパートが削られ）、以下のようにも連携されるとします。

> text2 = "私は今新宿駅。また、同じ1時間圏内に横浜駅がある。"

そんな場合に、「また、同じ」のみを削除するにはどうすればいいか？
ちょっと頭使ったので...以下に紹介します。

Pythonの`index`メソッドは、指定した要素がリストや文字列などのイテラブル（反復可能な）オブジェクト内で初めて出現する位置（インデックス）を返します。

以下公式ドキュメントです。

https://docs.python.org/ja/3/tutorial/datastructures.html



## サンプルコード

以下の関数により実現できました。

```py
def replace_phrase_in_text(text, key_word, new_word):
    if key_word in text and new_word not in text[:text.index(key_word)]:
        text = text.replace(key_word, new_word)
    return text

key_word = 'また、同じ1時間圏内に'
new_word = '1時間圏内に'

text = "私は今新宿駅。1時間圏内に渋谷駅がある。また、同じ1時間圏内に横浜駅がある。"
text2 = "私は今新宿駅。また、同じ1時間圏内に横浜駅がある。"

new_text = replace_phrase_in_text(text, key_word, new_word)
print(new_text)
# "私は今新宿駅。1時間圏内に渋谷駅がある。また、同じ1時間圏内に横浜駅がある。"

new_text2 = replace_phrase_in_text(text2, key_word, new_word)
print(new_text2)
# "私は今新宿駅。1時間圏内に横浜駅がある。"
```

少し分かりづらいですが、分解すると以下の通り。

`if key_word in text`は、`key_word`が`text`内に存在するかどうかをチェックします。

`text.index(key_word)`は`key_word`が`text`内で初めて出現するインデックスを返します。
そして、`text[:text.index(key_word)]`はそのインデックスまでの`text`の部分を取得します。

結果として、`new_word not in text[:text.index(key_word)]`は、`new_word`が`text`の最初から`key_word`が初めて出現するインデックスまでの部分に存在しないかどうかをチェックします。

これらの条件をうまく成立させないと、一つ目の`text`の方で予期せぬカットが発生したりします。

`new_word`が`text`の最初から`key_word`が初めて出現するインデックスまでの部分に存在しない場合、というのは、つまり、前半部分の余計な`'1時間圏内に'`をカットしないようにするための条件となっています。

`find`メソッドについては以前こちらの記事でも紹介したので、ご参考までに。

https://qiita.com/Ryo-0131/items/13115e90b5d2f19b46cc
【JavaScript】プロトタイプとは

# プロトタイプとは
「プロトタイプ（prototype）」とは、オブジェクト指向プログラミングにおいて、あるオブジェクトが他のオブジェクトから継承する機能やプロパティを定義するための仕組みです。

例えば、以下のコードでは、Animalというオブジェクトが定義され、そのプロトタイプとしてAnimal.prototypeが設定されています。そして、DogというオブジェクトがAnimalを継承し、新しいプロパティやメソッドを追加しています。
```js
// Animalオブジェクトの定義
function Animal(name) {
  this.name = name;
}

// Animalオブジェクトのプロトタイプにspeakメソッドを追加
Animal.prototype.speak = function() {
  console.log(this.name + ' makes a noise.');
};

// Dogオブジェクトの定義（Animalを継承）
function Dog(name) {
  Animal.call(this, name);
}

// DogオブジェクトがAnimalオブジェクトを継承
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

// Dogオブジェクトのプロトタイプにbarkメソッドを追加
Dog.prototype.bark = function() {
  console.log(this.name + ' barks.');
};

// 使用例
const dog = new Dog('Max');
dog.speak(); // Max makes a noise.
dog.bark();  // Max barks.
```
JavaScriptでは、プロトタイプを介してメソッドやプロパティをオブジェクトに追加することが一般的です。これにより、すべてのオブジェクトのインスタンスが同じメソッドやプロパティを共有できます。そのため、Animal.prototype.speakを定義すると、Animalオブジェクトのインスタンスだけでなく、Dogオブジェクトのインスタンスもspeakメソッドを利用できるようになります。
Stripe テスト環境のデータをすべて削除してリセットする方法

## 概要

Stripeのテスト環境にてデータをすべて削除し、リセットする方法を簡単にまとめる。

## 方法

1. Stripeにブラウザでログインする。
1. 開発者をクリックする。

    ![CleanShot 2024-04-01 at 21.20.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/0d2097b9-98dc-8614-1b30-b92e1992aa00.png)

1. すべてのテストデータを削除...をクリックする。

    ![CleanShot 2024-04-01 at 21.20.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/7ec36a3d-8a1c-1e5d-c9fc-18236b79c5d4.png)

1. 削除対象のデータがあればおそらく「削除を開始」のボタンがクリックできるはずなのでこちらを押下する。もちろんテスト環境のすべてのデータは削除されるので注意する。

    ![CleanShot 2024-04-01 at 21.20.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/cf0914b8-b8fc-3c25-bc36-a9dbcb0fa3d4.png)

1. データがあると下記のように削除予定の件数が表示される。

    ![CleanShot 2024-04-01 at 21.22.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/92771ad5-a711-7ca7-bc4a-9a0940cc9e71.png)

1. あたりまえだがデータが多ければ多い被度削除には時間がかかるはずなので気ままに待機する。

    ![CleanShot 2024-04-01 at 21.23.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/78341f34-962a-9d23-88a2-f61ff8d4806d.png)


## 参考文献

https://docs.stripe.com/test-mode?locale=ja-JP#delete-test-data
filterでイラストをベタ塗りにする



https://qiita.com/eltociear/items/39bcd78befdbd2c4b58c

こちらの記事を見た時に、イラストでも同じことができるかなと、次のようなコードを書きました。

```css
img {
  /* 赤くする */
  filter: invert(15%) sepia(95%) saturate(6932%) hue-rotate(358deg) brightness(95%) contrast(112%);
}
```

失敗。
![スクリーンショット 2024-04-01 21.04.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704882/d68e92a7-bd16-73f3-a265-969a9391dfc3.png)

よく見たら「黒い画像を」って書いてありました。

なので画像を黒くしてから、ラッパーの方に適用させます。
```css
.wrapper {
  /* 赤くする */
  filter: invert(15%) sepia(95%) saturate(6932%) hue-rotate(358deg) brightness(95%) contrast(112%);

}
img {
  /* 黒くする */
  filter: brightness(0);
}
```
```html
 <div class="wrapper">
   <img src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/other/official-artwork/1.png" alt="">
 </div>
```
![スクリーンショット 2024-04-01 21.07.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704882/6125ad7c-bf2e-fd4a-380d-45ff75252b73.png)

OK。

ちなみにこんなツールもありました
https://codepen.io/sosuke/pen/Pjoqqp
このツールを使えば好きな色にすることができます。
【Vue.js】v-forで作成した複数のボタンコンポーネントに対してダブルクリック防止処理を実装する

## はじめに

Vue.jsで、`v-for`を使って複数のボタンコンポーネントを作成し、1つ1つのボタンに対してダブルクリックの防止処理を実装しました。

## 環境

- Vue.js 3.4.21
- Composition API

## サンプルコード

Vue SFC Playgroundで試せます。

https://play.vuejs.org/#__PROD__eNqFVMFu00AQ/ZWVhVRHGLulcAlpBS09wAFQKae4Ul17nG672bW865Aq8iGJKoEQQkJc4AdAIPEDHPgYq+pvMLtrO2lBIYdkd/bNzJuZN5k4j7LMHxXgdJ2ejHOaKSJBFdl2yOkwE7kiE5JD6uFXFCs6Ao8IvgOpyOFVlkQKSEnSXAzJGgZZe9B67RRKCV4/+YG96kQaE/IgIKM7GOTq07dq+pNRqUIeCy4V0Wey1aZz+xseueuRzcMOOlrIsQm2D6nBpW7fvF2n5bodsrVNJiEn+MF01ozJLt++r6Y/Ln9fVNMvlx9mVxdfq9nHav69mv2q5vNq/qaafq5m76xjm8ofRawATNg/xFylTtjQOYl4wsBWuMtofIYoly7Sa5Rg4DMxcI/qvtya0NsbJYk1HJIjHY7oxh/QIYhCXWd/g0SfHvoIfUxldMwgcdOISbARSo/cX1/vIEG89gI7UBwlXhQMM4YdwBshvYSOzAGPlpG9EDuVrdBxKTp4BMug3MwkdBpI9wzOEaEBC+NDUwqa/+oGtmLJF+eFIGCmPEJT4gLrLCrE2rB7+Fw2PjVN0ihqgl6YmZRlzb/Wlq0rsIX1grZcx3OUxBGkdOCfSsFR6KatoROLYUYZ5M8zRXFEodNtGh46EWPi9VNjU3kBXmOPTyA++4f9VI61LXRe5CAhH0HotG8qygeA/dPPey+fwRjP7eNQJAVD9IrHfUD5FJqjhe0UusP5Es6wfWIWj/LBgdwbK+CyKUoTteKwdeMS7q4ofUF3079n/FBO2MXFCv/nv+LmP4LdEiobwdZb28o25JE85zFJC44rjyNeFrdRfMeyW4Rot9H8Ij8dJYGUctgbZ0KCO1mOQsy+rtoHK0DbglbKyzx0E1sdd5ParNegJdUqtieZUCTY7gU27A1Bln8AEl3g7g==

### 呼び出し側（親）

```vue:App.vue
<script setup>
import { ref, reactive, onBeforeUpdate } from 'vue';
import Button from './Button.vue';

// Button用のlist
const list = reactive([1, 2, 3]);

const buttonRef = ref([]);
onBeforeUpdate(() => {
    buttonRef.value = [];
});

const handleButtonClick = (i) => {
  setTimeout(() => {
    buttonRef.value[i].setDisabled(false);
  }, 500)
};
</script>

<template>
  <div>
    <Button
      v-for="(item, i) in list"
      :key="item"
      @click="handleButtonClick(i)"
      :ref="el => { if (el) buttonRef[i] = el }"
    >
      Button {{ item }}
    </Button>
  </div>
</template>
```

#### `onBeforeUpdate`についての補足

DOMツリーの更新前に必ず`buttonRef.value`をリセットし、値が増え続けないようにします。
以下の記事を参考に実装しました。

https://tekrog.com/vue3-v-for-and-ref#google_vignette

### ボタンコンポーネント（子）

ボタンコンポーネントは以下の記事で紹介したものと同一です。
（つまり、ボタンコンポーネント自体は変更不要でそのまま`v-for`で利用できます）

https://qiita.com/wsigma21/items/117294102df68a46f29f

```vue:Button.vue
<script setup>
import { ref } from 'vue';
const isDisabled = ref(false);

async function setDisabled(value) {
  isDisabled.value = value
}

defineExpose({ setDisabled });
</script>

<template>
  <button
    @click="setDisabled(true)"
    :disabled="isDisabled"
    ><slot /></button>
</template>
```

## 終わりに

いつものことながらあまりComposition APIの情報がなく、いろいろな記事を参考に組み合わせてなんとか実装できました。

以下の記事を書いてくださった方々、ありがとうございました。

## 参考

### v-forの中で子コンポーネントを参照する方法

https://tekrog.com/vue3-v-for-and-ref#google_vignette

https://qiita.com/b_tanukiudon_rk/items/886811bffc59b3ddc8cc

### 公式：onBeforeUpdate()

https://ja.vuejs.org/api/composition-api-lifecycle#onbeforeupdate
Hire teachers online|Indiana global teachers 

"Indiana is the culmination of teachers' mission to provide teachers with the best schools they wish to join. We will help them grow and succeed and make a long-lasting career in Teaching. As a leading job portal for teachers, Indiana Global Teachers specializes in connecting passionate educators with rewarding positions nationwide. Teachers can seamlessly register and apply for many job vacancies through our use![uploading...0]()
r-friendly platform or app. Educational institutions can elevate their recruitment experience by effortlessly posting teaching positions and hiring teaching staff through our portal. Our dedicated teacher job placement team ensures personalized support."
CSS Position 属性のまとめ

positionについてまとめ！

## position 種類
- static
- absolute
- relative
- fixed


## static
- 何も指定しなければ自動でstatic 扱い
- top, left などを指定しても効かない
- z-index を指定しても効かない


## relative
- top, left などを指定できる
- z-index を指定できる
- **z-index が効かなければ、relative にする**

## absolute
- 親要素を基準とする
- **基準としたい親要素にはrelativeを使用する**
- relativeがない場合は、bodyタグが基準となる
- top, left を指定できる
- z-indexを指定できる

## fixed
- **ウインドウ全体を基準とする**
- top, left を指定できる
- z-indexを指定できる
【生成AIアプリ100チャレンジ】（9）某SNS風チャット

# 公開サイト

https://ai.nuevo.jp/chat_bot/chat/

# 開発環境

|              |              |
|:------------:|:------------:|
| Server       | lightSail    |
| Language     | Python3.11   |
| Framework    | Django       |
| DB           | sqlite3      |

ローカル環境ではPythonのvenvを使用。エディタはvs codeです。

# 目的
ChatGPTとのトークを某SNS風のデザインにしました。
過去のリクエスト、レスポンスをSESSIONに保存し、格納。ChatGPTとのトークがよりフレンドリーな感じになりました。
これから、このレイアウトをベースに、ChatGPT同士で会話させたり、違うプロンプトを入れたChatGPTに質問し、異なる答えと投票システムを入れて、エヴァンゲリオンのマギシステムを再現できたらなって思っている。マギシステムはそれっぽいデザインに変えるかもしれない。

# コード
```python:qiita.rb
@login_required
    OPENAI_API_KEY = os.environ['OPENAI_API_KEY']
    user_message = request.POST.get('message') 
    conversation = request.session.get('conversation', [])
    conversation.append(user_message)
    prompt = " ".join(conversation)
    client = OpenAI(
        api_key = OPENAI_API_KEY,
    )
    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=[
            {
                "role": "system",
                "content": "日本語で応答してください"
            },
            {
                "role": "user",
                "content": prompt
            },
        ],
    )
    bot_response = response.choices[0].message.content
    bot_response = bot_response.replace("\n", "<br>")
    conversation.append(bot_response)
    request.session['conversation'] = conversation
    return JsonResponse({'message': bot_response})
def chat_view(request):
    full_url = request.build_absolute_uri('/')
    app_name = "chat_bot"
    return render(request, 'chat.html', {'domain': full_url,'app_name': app_name})

```

# アプリ画面
![スクリーンショット 2024-04-01 20.57.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398694/5c97ae08-1ffa-867c-f34c-92a17cb908aa.png)


# 感想
　しばらくはこの画面をベースにして、生成AIのAPIを組み合わせてやっていくと思う。今回はデザインばかりの対応をしてしまったが、デザインさえできてしまえば、あとは組み合わせたAPIが量産できるので、今後いろいろやっていきたい。
　ユーザーログインシステムにしたらユーザーのアイコンを設置とかできるんだろうな、とは可能性はいろいろある。
元自（元自衛官）って実際どぎゃんね？

敬礼！　直れ！　...元海上自衛隊　の薪　大尉（元）です！

　　　雨の日も風の日も大海原上空を飛んできましたが、それも今は昔、IT業界では羽すら生えてない現状の３４歳、独身です。...そう、やばいです。立派なエンジニアの卵（！？）を目指して「早く孵化した〜い」そんな、今日この頃。
   
  さて、左も右も分からないままでは、流石にまずい。とのことで、今回、Elixirへ入門し、勉強に勤しむこととなりました。生暖かい目で見守るもしくは、温めて貰えたら幸いです。

   日々の勉学内容を共有の意味も込めて、アウトプット致します。




**基礎となる関数等**

```
iex(1)> h()
```
ヘルパーh（）を呼び出す



```
iex(5)> String.length("Hello World")
11
```
文字列内の Unicode 文字数を返します。（スペース含む）



```
iex(7)> String.reverse("stressed")
"desserts"
```
指定された文字列を反転する。


**最後に**
　ここからか...そう思った貴方へ.....『同情するなら教えとくれ！！』
【HTML/CSS】ブラウザ画面の高さ/横幅いっぱいに背景を設定する

imgに対してobject-fit: coverを付けることで、アス比が崩れることなく横幅いっぱいに画像を貼れる。

ただし、imgのサイズが確定していないといけないため、

```css
img {
	width: 100%;
	height: 100vh;
	object-fit: cover;
}
```

と書くことで、縦横のサイズを指定する必要がある。

vhはviewport heightの略で、現在のviewportの高さを100[％]として指定できる。


このままだと、画像の中心を基準にトリミングされてしまうので、例えば上部を基準にトリミングしたい場合は

```css
img {
	width: 100%;
	height: 100vh;
	object-fit: cover;
	object-position: top;
}
```

と指定する。
【Vue.js】ボタンコンポーネント内でダブルクリック防止処理を実装する

## はじめに

Vue.jsでボタンコンポーネントを作成し、ボタンのダブルクリック対策を実装しました。

## 環境

- Vue.js 3.4.21
- Composition API

## サンプルコード

Vue SFC Playgroundで試せます。

https://play.vuejs.org/#eNqVUsGO0zAQ/ZWRL5tKVbIScClpBbv0AAdAyx59ySaTrncdO4rtUlTl3xnbiVMBqsQp9szLmzfP78w+9n1+dMg2rDT1IHoLBq3rd1yJrteDhTMM2MII7aA7uCHozfvUu3PWajW18iJePZ3HcFVrZSw8heoDkWw9VbYKvbn7XKlGYvzzXor6lVDZCrY7OHMFXsyj6FA7m11UYSHNj5V0mBPukzDVk8Qmaytp0E8BGNfw7vZ2xdVI17KIG9JudLHY9bKySDeAshHHcKBj1BIvAB9qL2rL2V9CsxVnM4r2IkgSNTcmSpiMmgZMPsXBRZxcFkkPWzNryJxWHPIXoxU9TVias1p3vZA4fOutIPM428x2cFZJqX9+CTU7OFzP9foZ69d/1F/Mydc4+z6gweGInKWerYYD2tje//iKJzqnZqcbJwl9pfmARkvnNUbYnfPWDRe4oPZzCJFQh0ezP1lUZl7KC42vF/emQN1fWX2R+yZ/G/6j9yYXlzj+Z7pjMoWZEzUFN+WKq8r8UjW0TtVejidN6Qt5XEV1C0WMKRGFL+nzLA22QuH+1GuD2fmSBUY/51pgY9aiBSmjlzq8iSmhm2YqE2gRlWJaGqktFLuyiLR/BHL8Db/0ZJo=

### 呼び出し側（親）

```vue:App.vue
<script setup>
import { ref } from 'vue';
import Button from './Button.vue';

const buttonRef = ref();

const handleButtonClick = () => {
  // ボタンクリック時の処理をここに書く
  // 仮の処理として、setTimeoutで0.5秒立ってからdisabled解除する
  setTimeout(() => {
    buttonRef.value.setDisabled(false);
  }, 500)
};
</script>

<template>
  <div>
    <Button
      @click="handleButtonClick()"
      ref="buttonRef"
    >
      ボタン
    </Button>
  </div>
</template>
```

### ボタンコンポーネント（子）

```vue:Button.vue
<script setup>
import { ref } from 'vue';

const isDisabled = ref(false);

async function setDisabled(value) {
  isDisabled.value = value
}

defineExpose({ setDisabled });
</script>

<template>
  <button
    @click="setDisabled(true)"
    :disabled="isDisabled"
    ><slot /></button>
</template>
```

### 補足

「Vue.js3では子コンポーネントのルートのネイティブイベントをフォールスルーしてくれる挙動」であるため、子コンポーネントで`@click`に指定したメソッドが呼ばれた時、親コンポーネントの`@click`に指定したメソッドも実行してくれるようです。
つまり、**わざわざ`emit`で親のメソッドを呼ぶ必要はない**ようです。

https://qiita.com/ddg171/items/4baa4391c4b91d432cb3

## 終わりに

複数のボタンコンポーネントに対して実装する方法については別途記事を作成しました。

https://qiita.com/wsigma21/items/117294102df68a46f29f

## 参考

https://ja.vuejs.org/guide/essentials/template-refs#ref-on-component
UnityHubからエディターがインストールできないときの導入方法(Windows)

*** 
unity Hubをインストールし，その後のエディターのインストールをする過程で失敗したので，３つの手順で対処法を紹介します．

エディターインストールに失敗した時の様子↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3738334/fc671487-7d9a-cac3-d76e-032ff24e31c7.png)
何度試してもインストールができない:cold_sweat:


## 手順１　UnityHubのダウンロード

#### 1.[Unityダウンロードサイト](https://unity.com/ja/download)にアクセスし，プランと価格を確認する→を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3738334/d5618b6e-3e57-2275-3847-0eec22f2bbb0.png)



#### 2.個人プランを選択（学生プラン等を使用の方はそちらを選択してください）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3738334/efd3b3c0-2821-783d-5b06-5a23a46a2323.png)

#### 3.ダウンロードしたUnityHubSetupを起動
（この画面では，エディターが既にインストール済みのため，2023.2.15f1が表示されていますが，導入時は何もないはずです）また，アカウントを作成し，サインインも行ってください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3738334/6b8e358f-4419-8816-5b73-d31d95512038.png)


## 手順２　エディターをダウンロードする

#### 1.[Unityエディターのダウンロードサイト](https://unity.com/releases/editor/archive)にアクセスし，導入したいエディターを選択しWindows用ダウンロードを選択
![スクリーンショット 2024-04-01 195958.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3738334/f3ac3537-b98d-9c80-9946-8826372132f2.png)

#### 2.ダウンロードしたSetupを起動し，黄色の部分にチェックを入れる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3738334/d7c45567-8d99-0923-8c7b-46fd3c7157d1.png)

#### 3.そのままNext>を選択し，任意の場所にダウンロード


## 手順3　UnityHubとの接続
###### 手順２でUnityHubを経由せずにダウンロードをしたため，このままでは新規プロジェクトを作成することや管理ができません．それを可能にするため，接続を行います．
#### 1.手順１でインストールしたUnityHubを開き，右上のリストに追加を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3738334/e4efb40a-0596-9e33-e4f4-bdaa7a390467.png)

#### 2.手順２でダウンロードしたものの中から，Unity.exeを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3738334/e1e5b3de-2b6e-55e8-3fc2-cb2db7819220.png)

お疲れさまでした:blush:　これで完了です！！


## 参照
https://redhologerbera.hatenablog.com/entry/2022/05/14/202855
CakePhpメモ

```
◆ action 指定方法
<form name="telFrm" method="post" action="../../contest/confirm/" />
コントロール名 / 関数名

◆ Postデータの取得
<input type="text" name="tel" value="123" />
$tel = $this->request->getData("tel");

◆ viewに渡す変数データ設定 複数可能
$tel = "123";
$name = "mark";
$this->set(compact('tel','mark'));

◆ DBデータ登録
use Cake\ORM\TableRegistry;
//テーブル名 names 登録カラム name    テーブル構造：id   name
$namesTable = TableRegistry::getTableLocator()->get('Names');
$data = [];
$name = $namesTable->newEntity($data);
$name->name = '岸田';
$namesTable->save($name)

◆ DBデータ更新
$name = $namesTable->get(27);  //id=27のデータを更新する
$name->name = '新しい名前';
$namesTable->save($name);

◆ DBデータ削除
$name = $namesTable->get(27);  //id=27のデータを削除する
$namesTable->delete($name);

◆ DBデータ検索
$names = $this->Names->find();
$this->set(compact('names'));
zsh の `PROMPT` で変数や条件分岐を扱う

# きっかけと困ったことと対応

iTerm を使っていた際は、zsh の`precmd`でプロンプトとして好きにテキストを表示していました。
（条件での出しわけとか改行とか、プログラマティックに色々書きやすいから）

が、iTerm ではなく Warp を使用すると、`precmd`で表示していたテキストがブロックの最後に表示されてしまいました。

https://github.com/warpdotdev/Warp/issues/3116

> Closing as resolved, this has been fixed in recent version of Warp!

2023年の8月に最新バージョンで直ったとされているんですが自分の手元だとまだ起きます。悲しい。

しょうがないので `precmd` を使うのをやめて、`PROMPT`1本で勝負することにしました。

`PROMPT` は単なる環境変数なので、動的に値を変えるようにするためには独自の方法を使用する必要があります。

# `PROMPT` 内で変数や条件分岐を使う方法

## 独自の関数を使う

いきなり最終的な答えですが、カスタム関数を毎回実行するようにできるので、`precmd`などで定義していた内容をこの方法で指定するだけでOKです。

https://zsh.sourceforge.io/Doc/Release/Prompt-Expansion.html

> PROMPT_SUBSTオプションが設定されている場合、プロンプト文字列は最初に パラメータ展開、コマンド置換、算術展開が行われる。展開参照。

```shell
# この1行が必要
setopt PROMPT_SUBST

# 直接書く
CUSTOM_COMMAND='$(echo HOGEHOGE)'

# 定義済みの function
function hogehoge() {
  echo HOGEHOGE
}
CUSTOM_COMMAND='$(hogehoge)'
```

注意点としてはシングルクオーテーションを使っているところです。
ダブルクオーテーションにするとその場で実行されてしまうので、期待通りに動きません。`$(echo HOGEHOGE)`という文字列がそのまま`PROMPT`内に入る必要があります。

一つ関数を用意してそこに好きなコマンドを書けば完了です。

他の記法も一応書いておきます。記述量は減らせるかもしれません。

## 現在のディレクトリ

https://zsh.sourceforge.io/Doc/Release/Prompt-Expansion.html#Shell-state

```
# 絶対パス
PROMPT=%/

# ホームディレクトリからの相対パス
PROMPT=%~
```

これでコマンドの実行ごとに現在のディレクトリを表示してくれます。

## 改行

方法は

https://zsh.sourceforge.io/FAQ/zshfaq03.html

の中の "3.13: How do I get a newline in my prompt?" に書かれています。

`PROMPT`の中では`$'\n'`を使うことで改行になります。

```
PROMPT=line1$'\n'line2
```

これで2行になります。

## 条件分岐

https://zsh.sourceforge.io/Doc/Release/Prompt-Expansion.html#Conditional-Substrings-in-Prompts

```
%(x.true-text.false-text)
```

という記法を使うと、`PROMPT`内で条件分岐を書けます。
`x` には独自に定められた1文字が入りますが、例えば`?`を使用すれば、前のコマンドの終了ステータスが成功か失敗かを参照できます。

例えば以下のように書くことで前のコマンドの結果に応じてプロンプトを変更できます。

```
PROMPT=%(?.SUCCESS.FAILED)
```

`?`以外にもあるので上記のドキュメントから使いたいものを選んでください。

# 使用例

```shell
CURRENT_DIRECTORY=%~
PROMPT_NEW_LINE=$'\n'
CUSTOM_COMMAND='$(echo HOGEHOGE)'
PROMPT=%(?,SUCCESS,FAILED)
export PROMPT="${PROMPT_NEW_LINE}...${CURRENT_DIRECTORY}...${CUSTOM_COMMAND}...${PROMPT}..."
```

# プロンプトの最後に改行が入る問題は Warp のアップデート待ち

普通のターミナルソフトならプロンプトの直後にコマンドを打てる（それを想定した`PROMPT`を書いている人も多いと思う）。

が、Warp に関しては`PROMPT`の後に現状必ず改行が入る。

https://github.com/warpdotdev/Warp/issues/2304#issuecomment-1907563006

これがそのイシュー。一見サクッとした機能追加に見えて、実は Warp のコアを修正する必要があるらしく、めちゃくちゃ重いアップデートになるとのこと。

特殊なことをしてると大変だ...他の機能も含め、Warp の今後のアップデートに期待です。
【はじめに】備忘録を書こう。

## はじめに
この投稿は「QiitaのMarkdown記法の練習、初投稿の練習」の投稿です。

## 備忘録を書こう
これから今まで勉強してきた事の、備忘録を書いていこうと思います。

エンジニアとしての情報収集、技術のインプット&アウトプットはとても大切です。日々の勉強の成果とするも良し、初心に帰るのも良し、などメリットは沢山あります。

私自身、インターネットのエンジニアの方々の技術を学ばせていただき、大変参考になりました。これからは自分の技術力も誰かの参考になれば嬉しいな、と思っています。

## 終わりに
【JavaScript、Git、フレームワーク】などの投稿をしていきたいです。
間違っている点、至らぬ技術などもあると思いますが、何卒優しい目で見守っていただければ幸いです。

- 更新頻度は無理をしすぎない程度に。

今回はここまで。
【Elixir基礎】iexでhelp関数が実はめっちゃ便利説

Elixirに全力を注いでいるこーへーです。今日も最高の１日にします！

色々と前置きは省きますが、僕は30代からプログラミングを始めて(他言語経験なし)、Elixirという超コスパの良い言語にであったのでこれに挑戦しまくっている者です。

ということで、本日はiexでhelp関数が実はHexDocs見るのと変わらないことに気がついたというお話です。

## help == HexDocs
稼業外に、String.reverseで文字列を逆順にするということに挑戦していたのですが(そもそもreverseをしらなかった)、使い方が分からず、HexDocsを捜索していたんですね。

文字列を逆順にすることはできたのですが、その後、HexDocsで表示される内容は、iexのhelpで表示される内容と同じということがわかったんですね。

HexDocs
![スクリーンショット 2024-04-01 20.38.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2670710/62304b42-7861-1816-f29d-863ceafa14b7.png)

iex h(String.reverse)
![スクリーンショット 2024-04-01 20.38.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2670710/d18fa492-a1f7-28f1-4fbf-5a1c2d8011b8.png)

毎日新しい発見ですね。これから、活用していこうと思います。
自動化に対する私の考え方

# これはなんですか
オートメーションなどと言われているものよりももっと身近な自動化に対するアプローチと考え方についてのエッセイ。

## 自動化について
反復的な作業をコンピュータにやらせて人間がやらなくてよくすること。

## メリット
* 単純に人間様の工数があいて他のことができる

## デメリット
* 作成や導入にコストがかかる、そのコストを払ってなお楽できるかどうかが分水嶺になりがち
* 結果に対する評価が必要
* セキュリティや技術的な課題、たとえば個人情報を扱う場合などめんどくさい場合がある
* 導入できることに気づく人がいなければ自動化されない

# 戦略
## 防具としての自動化
主に人間が楽したり、ヒューマンエラーを防止する意図があるもの
一度作ってしまえば最後まで大きく変えることはないように思える。
たとえばCI/CD、月次レポートの作成
バックエンドの管理から外れるちょい作業ツール

## 武器としての自動化
すでに行われている自動化に対し、評価や結果をフィードバックし、さらなる発展につなげるための自動化。
ダイナミックにものごとが動くため、ある意味自動化のための自動化でもあり、営み自身であることも。
得られる恩恵に対し常にコストがかかる傾向があり、継続しなければ陳腐化するし、常に構い続けなければならないため、するかどうかは考えどころ。
たとえばAIによる改善, RPA, UnitTest

# たとえばこんなとき導入したよ
* （守）SendGridのバウンスメールリストからの消し込みをslack botでやれるようにした（作成３時間）
* （守）APIの決済失敗時のログをslackに垂れ流して確認しやすくする(作成２時間)
* （守）毎日０時に試験環境をクリアしてshutdownする(作成30分)
* （攻）事務の人がバックエンドで２時間とかかって作っていたものをバッチ化してCSVを吐き出す、そしてそれが延々と改善され続ける(7時間くらい)
* （攻）ぼーだいなログをAIに食わせて日々の指標や観点を叩き出して事業の判断に使う(初期導入３０ｈ、フィードバックやメンテナンス時間は詳細不明)

傾向として攻めのものを作ろうとするとバチクソ時間かかるし手間もかかるけど、まもりのものは多少コストオーバーになると思っても運用時間でペイできるし、ミスもなくなるから作って良いと思う。

自動化できないかなーってことを念頭におきながら生きていると、システムと業務に対するカンみたいなものが醸成されてくるような気がします。

特に守りの自動化は一度動き出すと呪いの装備みたいに外せなくなります。
AHC031参加録 (プレテスト 197位)

# 本記事の内容
- 自分の解法
- 期間中の動き

# contest url

https://atcoder.jp/contests/ahc031

# 問題内容
1000*1000の空間に特定の面積以上をもつ長方形敷き詰める
- N日これを連続して行う
- 面積を敷き詰めた後の仕分け線の「取り除き、追加」がコスト
-「取り除き、追加」が重複している部分はコスト0
- 初日の配置もコスト0
- コストを最小にする

# 自分の解法
- 重視したのはできるだけ面積が正方形の形に近くように配置
- しき詰めるときは無駄のないように端っこから詰めていく

- ![スクリーンショット 2024-04-01 19.43.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3292016/639b9fcb-adbc-1321-5151-6c0f5880baff.png)

# 期間中の動き
## 03/22 ~ 03/23
- 各面積を高さ1000の長方形を同じ方向に敷き詰めた

## 03/24 ~ 03/25
- 高さがすこしずづ小さくなるようにしき詰める向きを
    - 横
    - 縦
　の交互になるようにする事で改善した

## 03/27 ~ 03/28
- 別サイトコンテストに出ていた
    - codingame spring challenge 2024
     
https://www.codingame.com/contests/spring-challenge-2024-fiverr

- 結果 143 rd / 2664
- 応用情報とっているけどSQL知識が抜けてたので難しかった

## ~ 04/01
- 長方形から正方形のほうがスコア改善するので修正した

# 本解法の問題点
- 一定のコスト削減まで可能だったがこれ以上劇的にスコアを良くすることが難しい
- コスト削減する一番の方法である「重複している所のスコア0」を有効活用いない

# 自分より上位解法を見た感じ
- 「重複している所のスコア0」の活用を
    - 初日:今後変化しない高さ1000の長方形を同じ方向に敷き詰める
    - これをさらに切り分ける事で各日の要件を満たしのコストの改善を行っていた

# まとめ
- プレテスト 197位
- 最終順位 ?
- 途中まで積み上げたスコアが行き詰まり、改善する際には別方針を考えるのが重要
【JavaScript】typeof演算子とは

# typeof演算子とは
`typeof`演算子は値のデータ型を返す演算子です。

# 組み込み型(プリミティブ型)の場合
```js
window.onload = function () {
    // typeofの使用例

    // Number
    console.log( 'typeof 1 = ' + (typeof 1) );
    console.log( 'typeof 1.41 = ' + (typeof 1.41) );
    console.log( 'typeof Math.PI = ' + (typeof Math.PI) );
    console.log( 'typeof Infitity = ' + (typeof Infinity) );

    // String
    console.log( 'typeof "" = ' + (typeof "") );
    console.log( 'typeof "abc" = ' + (typeof "abc") );
    console.log( 'typeof "123" = ' + (typeof "123") );
    console.log( 'typeof (typeof 0) = ' + (typeof (typeof 0)) );

    // Boolean
    console.log( 'typeof true = ' + (typeof true) );
    console.log( 'typeof false = ' + (typeof false) );

    // Undefined
    console.log( 'typeof undefined = ' + (typeof undefined) );
}
```
結果
```
// Number
typeof 1 = number
typeof 1.41 = number
typeof Math.PI = number
typeof Infitity = number

// String
typeof "" = string
typeof "abc" = string
typeof "123" = string
typeof (typeof 0) = string

// Boolean
typeof true = boolean
typeof false = boolean

// Undefined
typeof undefined = undefined
```

# 関数やオブジェクト型の場合
```js
window.onload = function () {
    // Function
    console.log( 'typeof function () { } = ' + (typeof function () { }) );
    console.log( 'typeof class abc { } = ' + (typeof class abc { }) );
    console.log( 'typeof Math.abs = ' + (typeof Math.abs) );

    // Object
    console.log( 'typeof { prop: 1 } =' + (typeof { prop: 1 }) );

    // nullはObject型です。
    console.log( 'typeof null = ' + (typeof null) );

    // Date()やString()のラッパーオブジェクトはObjectと判定されます。
    console.log( 'typeof new String("abc") = ' + (typeof new String("abc")) );

    // Array は Objectと判定されます。
    console.log( 'typeof [1, 2, 3] = ' + (typeof [1, 2, 3]) );

    // Array.isArray や Object.prototype.toString.call などで
    // 普通のオブジェクトと配列を区別できます。
    console.log( 'Array.isArray({ prop: 1 }) = ' + (Array.isArray({ prop: 1 })) );
    console.log( 'Array.isArray([1, 2, 3]) = ' + Array.isArray([1, 2, 3]) );
}
```
結果
```
// Function
typeof function () { } = function
typeof class abc { } = function
typeof Math.abs = function

// Object
typeof { prop: 1 } =object

// nullはObject型です。
typeof null = object

// Date()やString()のラッパーオブジェクトはObjectと判定されます。
typeof new String("abc") = object

// Array は Objectと判定されます。
typeof [1, 2, 3] = object

// Array.isArray や Object.prototype.toString.call などで
// 普通のオブジェクトと配列を区別できます。
Array.isArray({ prop: 1 }) = false
Array.isArray([1, 2, 3]) = true
```
未経験からSIerに転職して1ヶ月経ったので振り返ってみる

どうも、初心者12冠エンジニアのアスカです。電機メーカー研究職から転職してちょうど１ヶ月経過したので思う所を綴りたいと思います。これから転職を考えている方の参考になれば幸いです。

ちなみにインフラ案件のPL候補という枠で採用されました。
あくまで業界歴1ヶ月という短い経験の感想なので一般論ではない事を念頭にしてください。

# どんな業務？
基本的には上流の設計から下流の構築まで行う業務です。案件や、どの段階から参画するかによって実際にやる事はまちまちな気がします。
実際に自分がアサインされたのはAIベンチャーのサービスをクラウドに移行する案件で、キックオフから参入しました。

基本設計フェイズから始まっており、週次でお客様と打ち合わせを繰り返し、構成の基本方針を詰めていっています。

すでにデータセンターで動いているものがあるため、EC2のミドルウェアやパッチ適用、マルウェア対策まで固まっているので時間は無いけど比較的やりやすい案件なのかな？と思っています。
# どんな力が必要？
ざっくりいうと国語力な気がします。少し分解すると
1. 情報収集と整理する力
1. 資料作成力
1. コミュニケーション能力

IT知識だけでは出来ないお仕事だと感じます。

## 1.情報収集と整理する能力
特に新しい案件に挑戦する時、見た事のない要件や触った事の無いAWSのサービスを使わなければいけない場面には多々出会います。
その時にしっかり調査を行って整理して伝えられるかどうかがお客さんの信頼にも繋がりますし、自らの成長にも繋がります。

## 2.資料作成力
情報を収集して整理しても、お客さんにしっかり伝えられなければ意味がありません。ストーリー立てをして資料を作成して体裁を整えて、最大限伝える努力をしなければなりません。

## 3.コミュケーション能力
ざっくりコミュケーション能力といっても、複数分類出来ると思います。
- 伝える力
事前に準備した説明をする事はもちろん、打ち合わせ当日に柔軟にお客さんの質問に答える事も求められます。
- 聞く力
お客さんも自ら漏れなく要件を提示してくれる訳ではないので、打ち合わせの中で引き出す必要があります。
- 伝える力×聞く力
こちらもビジネスなので、お客さんの要望には応えつつ、自社の利益にもなるような誘導も必要です。

話す、書く、聞くとIT知識を複合的に駆使して**上手く立ち回るために俗にいうコミュ力が必須です**。
# どう鍛えていく？
大きく3つ程、必要な力を挙げましたが、自分にはどれも足りていません。どれも実務経験のみで得ていこうというのも限りない時間が必要です、それならどうしましょうか。
##  情報収集は自分で
好きな分野であれば,苦もなく、職務以外で情報収集が出来ます。プライベートでAWSを使ったサービスを作ったり、勉強会に参加する事で自分の中への情報の蓄積は加速すると思います。
幸い自分は好きな分野に入れたので、上記の方法で鍛えていこうと思います。
## 資料作成の場数は登壇で
資料作成やコミュ力は場数が必要ですが、これに関しても職務以外に場は設けられています。そう、勉強会です。誰に何を伝えたいのかを定めてストーリー立てをして資料作り、当日は柔軟に質問に答えていく。また集まった人同士で様々な話題を話す事もコミュケーション力向上の一助になると思います。

# 総じて
長々?と書きましたが、転職して期待通りの仕事が出来て満足しています。目の前の顧客の欲しいシステムのベストを目指して提案、構築していくステップは楽しくて仕方がないです。
開発も好きなので、詳細設計を終える事が楽しみです。
Web API The Good Partsのまとめ Part3

前回の検索とクエリパラメータの設計が途中だったのでもう一度そこの最初から

### 検索とクエリパラメータの設計

- データ一覧を取得するエンドポイントに絞り込みをかけて検索させる
    - 絞り込みするのに必要なのがクエリパラメータ
- クエリパラメータの取得数と取得位置
    - page/per_pageやlimit/offsetなどが一般的
    - limit/offsetの方が自由度が高い
        - これらは取得位置を相対的に指定するものだが、これには
            1. データ量が増えれば増えるほど時間がかかる
            2. 更新頻度の高いデータの場合、データの不整合が起こりうる
            という問題点がある。
        - 絶対位置で取得することもある
            - 指定したID/日時よりも前
    - クエリパラメータでqをパラメータとして使う場合、全文検索・部分一致を許容することが多い。
        - qであらゆるパラメータの値から部分一致も含めて検索する
    - クエリパラメータとパスの使い分け
        - 一意なリソースを表すのに必要な情報かどうか
        - 省略可能かどうか

### ログインとOAuth

- OAuthとは、別のサービスAで登録している情報を利用するために、ユーザーがトークンを利用してサービスBでサービスAの情報を利用できるようにする認証システムのこと。
    - 例えばBasic認証などの場合(Resource Owner Password Credentials)のリクエスト
        
        ```markdown
        POST /v1/oauth2/token HTTP/1.1
        Host: api.example.com
        Authorization: Basic houawreIYfaw48HAF
        Content-Type: application/x-www-form-urlencodeded
        
        grant_type=password&username=mosnipe&password=abc&scope=api
        ```
        
        - APIのパスやエンドポイント
            - OAuthは現在バージョンが2.0のためoauth2などとしている
            - エンドポイントはtokenやaccess_tokenなどが一般的
            - Authorizationヘッダはアクセスするサービスが何か？やクライアントアプリケーションが何かを特定するための情報。
            →アプリケーションごとにAPIのアクセス数を制限する場合などに利用する
            →許可していないアプリケーションをブロックする場合などに利用する
                - リクエストボディにclient_id/client_secretという名前で入れることも可能
            
            ```markdown
            HTTP/1.1 200 OK
            Content-Type: application/json
            Catch-Control: no-store
            Pragma: no-cache
            
            {
            "access_token": "vak77K39nkalak",
            "token_type": "bearer",
            "expires_in": 2629743,
            "refresh_token": "kagahka38Ijg30Kr",
            }
            ```
            
            - bearerはOAuth2.0用のトークン形式
            - expires_inはアクセストークンの有効期限
            - refresh_tokenはトークンが有効期限切れの際に再発行してもらうために使用するトークン
            - アクセストークン発行後はユーザネームやパスワードを利用する必要はない

### HATEOAS

…Hypermedia as the engine of application state

- API設計の別の手法
- 返すデータにURIを含み、次に行う行動や取得するデータが分かるように設計すること。
- この設計では、Content-Typeヘッダにどんなデータ形式かを詳細に記す
    - 通常は
        - JSON→application/json
        - XML→application/xml
    - HATEOASでは
        - application/vnd.companyname.user.detail.vi+jsonのようになる。
- メリット
    - クライアントがURIを知る必要がないので、変更しやすい
        - URIを簡潔にしなくて良い
        - APIにおけるURIの間違いによるバグを減らすことができる。
- まだこの設計を導入するのは時期尚早

### まとめ

1. 覚えやすく、どんな機能を持つかがひと目でわかるエンドポイントにする
2. 適切なHTTPメソッドを利用する
3. 適切な英単語を利用し、単数形、複数形にも注意する
4. 認証にはOAuth2.0を使う


### 感想
- 検索の仕様や実装をまだ知らないけど、基本はデータ一覧を取得するエンドポイントに絞り込みをかける方法なのだろうか？
- OAuthはトークンの概念があまり分かっていないころInstagramのAPIを使ってデータ取得をしようとして何度もinvalid tokenのエラーを返されていた記憶があります。
- HATEOASは初めて知った概念ですが、APIでURIを取ってくるって理解をしてます。なんとなくセキュリティ上怖い感覚があります。杞憂か…
ABC165 E-Rotation Matching

自分の構築方法が公式解説やユーザ解説に載っていなかったので。

# 問題
https://atcoder.jp/contests/abc165/tasks/abc165_e

* $M$個の対戦場があり、それぞれに$2$つずつ相異なる数字を重複のないように割り振る
* $N$人にはあらかじめ$1$～$N$の番号が割り振られており、各ラウンドにおいて自分の番号と対戦場に割り振られた番号が一致すればそこへ行き、相手と対戦をする
* 各ラウンドの終了後に、それぞれに割り当てられた番号を$+1$する。但し$N+1$は$1$とする。(1-indexedで考える$\mathrm{mod} N$ のようなもの)
* この工程を$N$ラウンド繰り返したとき、どの$2$人も$2$回以上同じ組み合わせで対戦しないような$M$個の対戦場への数値の割り振り方を構築せよ

# 制約
* $1 \leq M$
* $2M+1 \leq N \leq 200000$

# 解説
前提として、$N$を固定したときにできるだけ$M$を大きくした方が全体の対戦数が増え同じ組み合わせでマッチするリスクが高まりそう。そこで、できるだけ$M$が大きい場合でも条件を満たす割り当て方法を検討し、それがより条件の緩い$M$が小さい場合でも適用できるかを考える順番でいく。

まずは愚直に割り当てるとどうなるかを考えてみる。
例えば$N=7, M=3$について、3個の対戦場への割り当てを
* 1-2
* 3-4
* 5-6
とするとどうなるだろう。
便宜上7人をABCDEFGとアルファベットで表記するとすると、最初はA=1,B=2,...,G=7だから、1ラウンド目は(A,B),(C,D),(E,F)の3組が対戦することになる。3ラウンド目まで飛ばすと各自の番号が+2ずつされているので、(F,G),(A,B),(C,D)が対戦することになるが、これは1ラウンド目と(A,B),(C,D)が重複してしまっている。

このような重複がなぜ起こるかというと、単純なことで割り当てる数字のペアの差が、複数の対戦場の間で等しくなっているため。全部で$N$ラウンドあるということは、ある人がすべての番号付けを経験するわけだから、もしペアの差が等しくなるような対戦場が複数あれば、一度どちらかでマッチした後に番号の+1を繰り返すと、必ずもう片方でもマッチすることになる。
つまり、複数の対戦場でペアの数字が等しくなる場合は避けなければならない。

では、入力例2のように、
* 1-7
* 2-6
* 3-5

と、 **片方は1からインクリメント、マッチングする相手をNからデクリメントする** のはどうだろう。これだと2数の差は上から順に$N-2, N-4, ...$ と2ずつ減っていくので、重複することはない。もちろん 5-3のようなペアが出てくるまでラウンドを繰り返せば重複が起こるが、問題の制約で $2M+1 \leq N$があるので、左側の数が一番大きくなる$M$のときでも、右側の$N-M$について制約を変形すると $M+1 \leq N-M$が成り立つから常に右側の数は左側の数より大きく、上記のような心配はない。

実際、実はこの方法で$N$が奇数の時は正解になる。
しかし、 **$N$が偶数の場合に失敗する** ことがある。例えば $N=6, M=2$を考えてみる。
* 1-6
* 2-5

と割り当てる場合を考えると、1ラウンド目では(A,F),(B,E)となる。 これが4ラウンド目になると+3されているので(D,C),(E,B)となる。よく見ると(B,E)が被ってしまっている。こうなる理由は単純で、左側から右側を見たときの差3と右側から1をはさんで左側を見たときの差3が一致してしまっているから。今の例でいうと$2-5$を採用するのは実質的に$5-8$も同時採用してしまっていることになっており、これだと差が同じものが2回出てきてはいけないというルールに反してしまう。


そもそもこの問題は、差が$N/2$になるような2数が出てくる場合に起こることで、実は$N=4m+2$のような場合にのみ起こる。というのは$N$が偶数のときにこれまで説明したようなペアの作り方をすると2数の差が必ず奇数になるため。$N=4m$のような形の場合は$N/2$も偶数になるのでこの事例を考慮する必要がない。また、$N=4m+2$のときとりうる最大の$M$は$M=2m$のときで、2数の差は大きい方から$4m+1,4m-1, 4m-3,4m-5,...$と続き、最終的に$M=2m$個のペアをとると最後の差は$3$となる。この中に$2m+1$が含まれている場合、それを飛ばして$2m$のペアを代わりに採用して同様の操作を続けても最後の差は$2$までしか小さくならないため、全ての差が重複しないようにできる。
上述の$N=6,M=2$の事例の場合は、2-5の代わりに差が2の2-4や3-5を採用すれば回避できる。

実はこれでも$N=4m$の場合に失敗する場合がある。
例えば$N=8, M=3$を考えると、同様の操作で差が$7,5,3$のペアを構築できるが、実は差が5のペアと差が3のペアは裏返しの関係になっている。具体的には$左側+5=右側$のとき、$右側+3=左側+N$の関係が成り立っているので、一度差が5のペアでマッチした後+3すると、入れ替わりで再度マッチしてしまう。$N=4m$の場合はこのパターンを回避する必要がある。この場合も差の最小値は3であるため、どこかで既に作ったペアの差と一致するような事例に遭遇した場合、そこからペアの差をさらに1だけ小さくして操作を継続すれば、それ以降のペアで同様の事例が起こらないし、最小でも2なので条件を満たすことになる。


最後にここまでの議論を踏まえて、$M$が小さい場合にも適用できるかを考えるが、この構築方法は既に作ったペアの差とこれから作るペアの差が被らないようにするもので、$M$の値にかかわらず適用できる。したがって、この方法で構築すれば$M$が小さい場合にも対応できる。

# 解答
(1,N), (2,N-1),(3,N-2),...のように、(1,N)から始めて、左側の数を1増やし右側の数を1減らしながら割り当てを$M$組作る。
但し$N$が偶数の場合は構築中に以下のような状況になった場合、左側の数字だけを1増やしてからペアを作って、操作を続行する。
* 2数の差が$N/2$と一致したとき
* 既に作成したペアの2数の差のいずれかと、今作ろうとしているペアの2数の差の和が$N$に等しくなるとき

# AC例
2数の差が$N/2$に等しくなる場合については、最初からN/2を既に存在するペアの差の候補として管理しておけばよく、本コードでもそのようにすることで$N$が偶数のときの場合分けを、後者のみで済むようにしている。
https://atcoder.jp/contests/abc165/submissions/51932116
Pythonで「日付や時刻を表す文字列からインスタンスを生成する」の動作を確認してみた

# 概要

Pythonで「日付や時刻を表す文字列からインスタンスを生成する」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/python/date/index5.html

# 実装

以下のファイルを作成しました。
```sample.py
import datetime

str1 = "2020/07/22 13:37:4:33217"
str2 = "07/22/2020 PM 1:37:4:33217"
str3 = "July 22,2020 13:37:4:33217+09:00"

dt1 = datetime.datetime.strptime(str1, "%Y/%m/%d %H:%M:%S:%f")
dt2 = datetime.datetime.strptime(str2, "%m/%d/%Y %p %I:%M:%S:%f")
dt3 = datetime.datetime.strptime(str3, "%B %d,%Y %H:%M:%S:%f%z")

print(dt1)
print(dt2)
print(dt3)
```

以下のコマンドを実行しました。
```
$ python3 sample.py 
2020-07-22 13:37:04.332170
2020-07-22 13:37:04.332170
2020-07-22 13:37:04.332170+09:00
```

# まとめ

何かの役に立てばと。
Docker イメージからの Lambda 関数の「Runtime.InvalidEntrypoint」エラー

ローカルで動いていたのに、「Runtime.InvalidEntrypoint」が発生した時のメモ

### 起きたこと
DockerfileをECRにpushし、lambdaでイメージを選択して動かすと、Runtime.InvalidEntrypointとなる
```
{"errorType":"Runtime.InvalidEntrypoint","errorMessage":"RequestId: ID Error: fork/exec /lambda-entrypoint.sh: exec format error"}
```
OS：M2 mac
色々調べてみたがDockerイメージのアーキテクチャがarm64とx86_64で違うらしい。
```bash
$docker build --platform linux/x86_64 -t docker-image:test .
```
buildの時にplatformを変更しても、特に改善されない...

### 解決
lambdaのイメージを選択するところでpushした最新のイメージを選択していなかったことが原因でした。。。また、ここでアーキテクチャも選べるので、buildする時にplatform設定するか、ここで選ぶかのどちらでも良さそうです。

![スクリーンショット 2024-04-01 19.31.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2819600/42a2d32b-3bf7-eeaa-f571-a962728b404d.png)

### 最後に
めっっちゃ単純でしたが結構ハマったので、同じ方の手助けになれば幸いです！
[Google Calendar API(V3)] Javaでカレンダーとイベントの色を取得する

Google Calendar API V3(Java)を使用して、
Googleカレンダーのカレンダーとイベントの色を取得する
についてご紹介します。

下記の色を取得できます。
・カレンダーに指定できる色
<img width=320 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114621/e2cff1d2-6070-a6df-2df6-ae05abd4d92e.png">

・イベントに指定できる色
<img width=240 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114621/cd0e65ad-eaa2-0e3b-79b2-7873f0039302.png">

:::note info
APIを利用する環境の準備から始める場合や、コードを実行する際は、
[⧉[Google Calendar API(V3)] JavaでCalendar APIを使う](https://qiita.com/doran/items/c735c7b05c0a2ed4bfdb)
を参照ください。
:::

|No||目次|
|---|---|---|
|1||[色を取得](#1-色を取得)|
||1|[スコープ](#11-スコープ)|
||2|[実行](#12-実行)|
||3|[レスポンスの内容](#13-レスポンスの内容)|

## 1. 色を取得
Googleカレンダーのカレンダーとイベントの色を取得します。

### 1.1. スコープ
このAPIを実行するには、以下のいずれかのスコープを指定してください。
```
CalendarScopes.CALENDAR
CalendarScopes.CALENDAR_READONLY
```
[⧉[Google Calendar API(V3)] JavaでCalendar APIを使う(2.2 Driveインスタンスを取得)](https://qiita.com/doran/items/c735c7b05c0a2ed4bfdb#22-calendarインスタンスを取得)
でスコープを指定してください。

### 1.2. 実行

```java
public static void main(String[] args) throws Exception{
    Calendar calendar = getCalendar();
    
    Calendar.Colors colors = calendar.colors();
    Calendar.Colors.Get get = colors.get();
    
    Colors res = get.execute();
    System.out.println(res);
}
```
#### 1.2.1. HTTPリクエスト
GET:　https:\//www.googleapis.com/calendar/v3/colors
が実行されます。

#### 1.2.2. クエリパラメータ
クエリパラメータはありません。

### 1.3. レスポンスの内容

#### Colors
|メソッド|戻り値|説明|
|---|---|---|
|getKind|String|リソースの種類<br>固定文字列："calendar#colors"|
|getUpdated|DateTime|カラーパレットの最終更新日時|
|getCalendar|Map<String,[ColorDefinition](#colordefinition)>|カレンダーの色を表すグローバルパレット|
|getEvent|Map<String,[ColorDefinition](#colordefinition)>|イベントの色を表すグローバルパレット|

#### ColorDefinition
|メソッド|戻り値|説明|
|---|---|---|
|foreground|String|前景色|
|background|String|背景色|	

<br>
<br>
おしまい。。
Xcode dyld: Library not loaded: /usr/lib/swift/libswiftWebKit.dylib Error

# 実機iPhoneでのビルドエラーについて

アプリ開発中に、特定のiOSバージョンでのみで発生するビルドエラーについて解決策を共有します。

## 発生したエラー

実機iPhoneでアプリをビルドした際に以下のエラーが発生しました。
```
dyld: Library not loaded: /usr/lib/swift/libswiftWebKit.dylib
Referenced from: /private/var/containers/Bundle/Application/E769A0A2-3190-46BA-96D9-C09B62826EA3/Runner.app/Frameworks/flutter_inappwebview.framework/flutter_inappwebview
Reason: image not found
(lldb)
```

上記のビルドエラーが発生した、端末とバージョンは以下になります。
```
iPhone: 11
iOS: 13.6.1
```

## ・ 調査

[Stack Overflow](https://stackoverflow.com/questions/69520336/dyld-library-not-loaded-usr-lib-swift-libswiftwebkit-dylib)にて似た症状の報告を発見。

そこではiOS 13.1.2で同様の問題が発生していました。
さまざまな試行錯誤が報告されていましたが、根本的な解決には至っていない様子でした。
また、iOS 14ではこの問題が発生しないことも分かりました。

## ・ 解決策

最終的に、iOS 17を搭載した実機でビルドしたところ、エラーが解消されました。
【GitHub】フォークとクローンの違い

## 最初に
2024年4月を迎え、多くの方々が新社会人としての一歩を踏み出したり、転職を機に新しい環境へと移行したりしています。私自身も、転職をきっかけに新しいチームでのGitHubの運用方法に合わせて環境設定を行いました。その際、「フォーク（Fork）とクローン（Clone）の違いってなんだろう？」と疑問に思ったことが記憶に新しいです。そんなわけで、このタイミングで、その疑問について掘り下げ、記事にしてみることにしました。

# GitHubのフォーク(Fork)とクローン(Clone)の違い

GitHub上でプロジェクトに取り組む際、**フォーク(Fork)** と **クローン(Clone)** は、コードのコピーを作成する上で欠かせない二つの操作です。しかし、これらの操作はどのように異なり、どのような状況で使い分けるべきなのでしょうか？この記事では、フォークとクローンの基本的な違いと、それぞれの使用シナリオについて解説します。

## フォーク(Fork)とは？

フォークは、GitHub上の他人のリポジトリを自分のアカウント下にコピーする操作です。この操作により作成されるリポジトリは、オリジナルのリポジトリとは独立しており、自分の変更を自由に加えることができます。フォークは、オープンソースプロジェクトに貢献したいが直接アクセス権を持たない場合や、既存のプロジェクトを基に新しいプロジェクトを始めたいときに役立ちます。

### フォークの主な使用シナリオ

- オープンソースプロジェクトへの貢献
- プロジェクトのベースとしての利用

## クローン(Clone)とは？

クローンは、GitHubリポジトリを自分のローカル環境にコピーする操作です。このコピーを通じて、リポジトリの内容をローカルで閲覧、編集、実行することが可能になります。クローンは、開発作業を始める前の準備段階でよく使用され、ローカルとリモートリポジトリ間で変更を同期させるための基盤となります。

### クローンの主な使用シナリオ

- ローカルでの開発作業
- コントリビューション前のテスト

## フォークとクローンの違い

- **フォーク**はGitHub上での操作であり、リポジトリの独立したコピーを自分のアカウント下に作成します。
- **クローン**はローカルマシン上での操作であり、リポジトリのコピーをローカル環境に作成します。


## まとめ
これらの操作は、開発プロセスの異なる段階で役立ちます。フォークはプロジェクトに貢献したいが直接アクセス権がない場合や、プロジェクトを自分でカスタマイズしたいときに使用します。一方、クローンは実際の開発作業を始める前にリポジトリをローカルに持ってくるために使用されます。
【JavaScript】Setオブジェクトとは

# Setオブジェクトとは
セットオブジェクトには以下の特徴があります。
- 値が一意であることが保証されている
- 順序を持たず、インデックスでアクセスできない

# 値が一意であることが保証されている
以下のコードは、Setオブジェクトを使用して一意な値のコレクションを作成し、その動作を示しています。

```javascript
// Setオブジェクトの作成
const mySet = new Set();

// 値の追加
mySet.add(1);
mySet.add(2);
mySet.add(3);
mySet.add(1); // 既に1が含まれているため、無視される

// サイズの確認
console.log("セットのサイズ:", mySet.size); // 出力: セットのサイズ: 3

// 値の重複が無視されることを確認
console.log("セット内の値:", mySet); // 出力: セット内の値: Set(3) { 1, 2, 3 }

// 値の比較は厳密な等価性で行われることを確認
console.log("1がセットに含まれているか:", mySet.has(1)); // 出力: 1がセットに含まれているか: true
console.log("文字列の'1'がセットに含まれているか:", mySet.has("1")); // 出力: 文字列の'1'がセットに含まれているか: false
```

このコードでは、最初に空のSetオブジェクトを作成し、それにいくつかの値を追加しています。その際、同じ値が複数回追加されている場合でも、重複する値は無視されます。また、値の比較には厳密な等価性が使用されるため、異なるデータ型や厳密に等しいでない値はセット内で一意なものとして扱われます。

# 順序を持たず、インデックスでアクセスできない
Setオブジェクトは、要素の順序を保持しないデータ構造です。つまり、要素が追加された順序で格納されるわけではなく、Set内の要素は自動的にソートされることもありません。そのため、Setオブジェクトではインデックスを使用して要素にアクセスすることはできません。

例えば、次のようにSetオブジェクトを使用していくつかの要素を追加した場合を考えてみましょう。

```javascript
const mySet = new Set();

mySet.add("apple");
mySet.add("banana");
mySet.add("orange");
```

このとき、`mySet`内の要素の順序は`["apple", "banana", "orange"]`という順序である保証はありません。要素が追加された順序を保持することはありません。そのため、インデックスを使用して`mySet`内の要素にアクセスすることはできません。

代わりに、Setオブジェクトのメソッド（例: `has`, `add`, `delete`など）を使用して要素を操作します。また、Set内の要素を反復処理するためには、`forEach`や`for...of`などの反復処理構文を使用することが一般的です。
Dart/Flutter whereメソッドの使用方法

## whereメソッドを使って条件に一致する要素を抽出する方法
 コレクション内の要素を条件に基づいてフィルタリングする際に
 便利なのが`where`メソッドです。
 
 この記事では、`where`メソッドの基本的な使い方を紹介し、
 例を通して活用法を解説します。

## whereメソッドとは？
`where`メソッドは、リストやセットなどのコレクション内の要素に対して
特定の条件を適用し、条件を満たす要素を新しい`Iterable`として
返すメソッドです。条件に基づいてデータを絞り込みたい場合に役立ちます。


## 実際のコード例
以下の例では、Personクラスを定義し、名前と年齢を
プロパティとして持っています。

いくつかのPersonインスタンスをリストに格納し、`where`メソッドを
使って年齢が25歳以上の人物のみをフィルタリングしています。
```dart:使用方法
void main() {
  List<Person> people = [
    Person(name: 'Alice', age: 30),
    Person(name: 'Bob', age: 20),
    Person(name: 'Charlie', age: 25),
  ];

  Iterable<Person> adults = people.where((person) => person.age >= 25);

  for (Person person in adults) {
    print('${person.name}, ${person.age}');
  }
}

class Person {
  String name;
  int age;

  Person({required this.name, required this.age});
}


// 出力結果
Alice, 30
Charlie, 25
```

>このコードでは、whereメソッドを使用して、リストpeopleから年齢が25歳以上の人物だけを抽出しています。

条件に一致する各要素に対して、名前と年齢が出力されます。

## まとめ
`where`メソッドを使うことで、簡単に条件に一致する
コレクション内の要素を抽出することができます。

この方法は、データをフィルタリングしたり、特定の条件に基づいて操作を
行いたい場合に有効です。

# 告知
最後にお知らせとなりますが、イーディーエーでは一緒に働くエンジニアを
募集しております。詳しくは採用情報ページをご確認ください。

https://eda-inc.jp/recruit/

みなさまからのご応募をお待ちしております。
Vueで動的にコンポーネントを追加・削除するには？(script setup構文にて)

# はじめに
Vue.jsで開発をしている時に、タイトルみたいなことをしたくなったことが出てきました。
検索すると方法自体は結構出てきたのですが、`<script setup>`構文だとどんな感じになるのかだと情報が少なかったので備忘録も兼ねて残しておきたいと思います。

### なぜそんなことが必要なのか？
…と言われると若干詰まります。だって使用するのがわかっているのであれば、最初からそのコンポーネントを記述しておいて`v-if`なり`v-show`なりで制御すればいいだけの話。`:is`とかも使えます。
となると用途としてはかなり限定的にはなるのですが、例えば何かしらのライブラリを使用していてそこで動的に生成された要素内にコンポーネントをマウントしたい時でしょうか。
自分もまさに[Wijmo](https://developer.mescius.jp/wijmo?utm_medium=link&utm_source=demo-wijm)というライブラリを使用していて、そこで追加された要素に対して共通デザインで使用しているコンポーネントを適用したい！という事があったので実装方法を調査しました。

# 方法
ということで実際のコードは下記のようになります。（色々簡略化しています）
```vue
<script setup>
import { createApp, ref } from 'vue';
import AddComponent from './any-add-component.vue';

// ~~ 色々と省略 ~~

/** 動的なコンポーネントの追加 */
function addComponentDynamically (props = {}) {
  const app = createApp(AddComponent, props);
  const wrapper = document.createElement('div');

  app.mount(wrapper);
  document.body.appendChild(wrapper);
}

/** 動的なコンポーネントの削除 */
function removeComponentDynamically (app, wrapper) {
  app.unmount();
  wrapper.remove();
}
</script>

<!-- 以下略 -->
```
簡易的に解説していきます。
`createApp`でimportしたコンポーネントを第1引数に設定してアプリケーション（今回は`app`）を生成し、その後適当なラッピング要素を作成した後に`app.mount()`でその要素へマウントします。
その後、そのラッピング要素をDOMへ追加することで動的な追加が完了します。（今回はbodyですが、好きな場所へ追加してOKです）
また、`createApp`の第2引数に渡すとそのコンポーネントのpropsを設定できます。

コンポーネントを削除したい場合は、生成したアプリケーションを`app.unmount()`でマウント解除した後、不要になったラッピング要素を削除します。

意外と簡単ですね。
実際に使用する際はクラスへ処理をまとめておくなどして、もう少し活用しやすい形に整形しておくとよいです。

#### 追加したコンポーネントでのイベント
上記に応用して、追加したコンポーネントでのイベントを設定することもできます。
```vue
<script setup>
import { createApp, ref } from 'vue';
import AnyAddComponent from './any-add-component.vue';

// ~~ 色々と省略 ~~

/** 動的なコンポーネントの追加 */
function addComponentDynamically (props = {}) {
  const app = createApp(AnyAddComponent, props);
  const wrapper = document.createElement('div');

  app.mount(wrapper);
  document.body.appendChild(wrapper);
}

/** 動的に追加したコンポーネントのクリックイベント */
function onClickAddComponent () {
  console.log('clicked!');
}

addComponentDynamically({ onClick: onClickAddComponent });

// 以下略
```
上記のように、`on`を使用してイベントハンドラを設定すると可能になります。
当然、追加したコンポーネントでのroot elementなど気を付けるべき点はありますが、ある程度汎用的に使えます。

# 課題
通常の子コンポーネントを設定する方法と違って、下記の点が出来ません。
- 親コンポーネントで設定したリアクティブなデータを渡し、そのデータを変更しても追加したコンポーネントへその値を即時に反映させることが出来ない。（マウントした時点の`props`で固定化されてしまう）
→一応、`ref`や`reactive`などで宣言したオブジェクトをそのまま渡すことで実現は出来るようだが、何だか間違った方法にしか思えない…
- 追加したコンポーネントで設定した`emits`を親で受け取ることが出来ない。
つまり、`props`として`v-model`や`@{emits}`を無理やり書いても動作しない。

そもそもアプリケーションとしてのインスタンスが異なっているから致し方ないのかもしれません。
ただ、自分が知らないだけかもしれないのでもしこういう方法があるよ！という方は是非お願いします。

# 余談
基本的に自分はVueで`<script setup>`構文を使用しているのですが、調べているとヒットはしてもこの構文での情報が無いことが多々あります。
もちろん記述方法が少し変わっているだけなのでそれが分かっていればどうということは無いのですが、今回のようにちょっと特殊なことをしようとすると上手く変換出来るまで時間が掛かる事があります。
慣れていくしかないですね…

# 参考
- [アプリケーション API | Vue.js](https://ja.vuejs.org/api/application.html#createapp)
- [Vue.jsで動的にコンポーネントを生成・削除・マウントする方法](https://qiita.com/s_yasunaga/items/05e56fad4631f7bc7fe9)
↑`<script setup>`構文ではないので、そのままは使えないのですが参考にさせていただきました
タイ語モデルTyphoon-7Bは「แม่อย่าเก็บไว้คนเดียว」をどうトークナイズするのか

Kunat Pipatanakul, Phatrasek Jirabovonvisut, Potsawee Manakul, Sittipong Sripaisarnmongkol, Ruangsak Patomwong, Pathomporn Chokchainant, Kasima Tharnpipitchai『[Typhoon: Thai Large Language Models](https://arxiv.org/abs/2312.13951)』を読みつつ、この「[Typhoon-7B](https://huggingface.co/scb10x/typhoon-7b)」のトークナイザがどうなっているのか気になった。というのも、論文には

> In this work, we base our tokenizer on Mistral-7B tokenizer, but we further train an additional Thai subword tokenizer with 5,000 tokens and integrate it with the original tokenizer. This new tokenizer is created by training a SentencePiece model on around 8 million samples randomly selected from the Thai subset of MC4 data.

という風に、SentencePieceで「Thai subword tokenizer」を実装したと書かれているものの、「[Thai Character Cluster](https://doi.org/10.1145/355214.355225)」(คลัสเตอร์อักษรไทย)に関する記述がないのだ。ちょっと試してみよう。

```
>>> from transformers import AutoTokenizer
>>> tkz=AutoTokenizer.from_pretrained("scb10x/typhoon-7b")
>>> print(tkz.convert_ids_to_tokens(tkz("แม่อย่าเก็บไว้คนเดียว")["input_ids"]))
['
', '▁แม', '่อย', '่า', 'เก็บ', 'ไว้', 'คน', 'เดียว']
```

「แม่อย่าเก็บไว้คนเดียว」をトークナイズしてみたところ、最初の2単語「แม่」「อย่า」の切れ目が明らかにおかしい。もう少し細かくみてみよう。

```
>>> for t in tkz.convert_ids_to_tokens(tkz("แม่อย่าเก็บไว้คนเดียว")["input_ids"]):
...   print(" ",t)
...
  

  ▁แม
  ่อย
  ่า
  เก็บ
  ไว้
  คน
  เดียว
```

声調記号のU+0E48「THAI CHARACTER MAI EK」が、子音の後ではなくトークンの頭にあって、かなりマズイ事態になっている。こういうの、どうしたらいいのかなあ。
忘備録　Unity コンポーネントの値の取得方法

Inspectorでアタッチされているコンポーネントを確認し、そこにあるコンポーネントの何を取得したいのかを確認する

例えばTransformコンポーネントのpositionの値を取得したい場合

public Transform TransformValue;
Vector3 positionValue = TransformValue.position;


GetComponentメソッドを使った方法

public Transform TransFormValue;
positionValue = GetComponent<Transform>();

上記の2つの方法がやりやすそう
Dart finalとlateとは？

# finalとlateの理解と活用

`final`と`late`は便利なキーワードです。

変数の初期化と管理に関して重要な役割を担っています。

この記事では、それぞれのキーワードの特徴と使用方法を
具体的な例とともに解説します。

## finalキーワードとは？

`final`キーワードは変数を不変にします。

つまり `final`で宣言された変数には一度だけ値を
割り当てることができ、その後はその値を変更することはできません。

コード内で変更されるべきでない値を扱う際に有効です。

### finalの使用例

```dart: 例
final String name = 'Alice';
// name = 'Bob'; // コンパイルエラーになります。
```

上記の例では、name変数に`Alice`が割り当てられていますが
`final` キーワードのため、値を変更することはできません。

## lateキーワードとは？
`late`キーワードは変数の初期化を遅らせることができます。

変数が宣言された時点ではなく、後で初期化したい場合や
初期化にコストがかかる場合に有効です。

```dart:lateの使用例
late String description;

void initialize() {
  description = 'This is a late initialization.';
}
```

例では、 `description` 変数は `initialize` メソッドが
呼び出されるまで初期化されません。

`late` を使用することで、初期化のタイミングを自由に選ぶことができます。

# まとめ
`final` と `late` キーワードは、変数の初期化と不変性を
管理する上で有効なキーワードです。

`final` , `late`キーワードを適切に使用することで
安全性、保守性の高いコードになります。

# 告知
最後にお知らせとなりますが、イーディーエーでは一緒に働くエンジニアを
募集しております。詳しくは採用情報ページをご確認ください。

https://eda-inc.jp/recruit/

みなさまからのご応募をお待ちしております。
【影響なし】XZ Utils Backdoor（CVE-2024-3094）のPVEへの影響確認


:::note info
CVE-2024-3094の対象となるXZ Utilsが含まれているDebianのバージョンは`unstable`となります。
PVEの現行最新版8.1のDebianは`bookworm`となるため、対象外となります。
:::


## TL;DR

- XZ Utils Backdoor（CVE-2024-3094）のPVEへの影響確認
  - Debianベースのため。
- 結果、影響なし。
  - ベースになっているDebianのバージョンで、XZ Utilsの対象バージョンが利用されてないため。
- 念のため、実機でも確認。

## 概要

「CVSS 3」のベーススコアが「10.0」（Critical）で、Debianも対象だったため確認しました。
結果としてはDebianの`unstable`（検証版）のみが対象であるため、Proxmoxはもちろん商用環境のほとんどでは影響がなさそうです。

※本脆弱性そのものよりも、意図的に不正なコードを仕組むということが、OSSの文化へ与える影響の方が大きいかもしれません。

## 脆弱性の概要
以下がよくまとまっていましたので、参考にしました。
https://piyolog.hatenadiary.jp/entry/2024/04/01/035321


Debianへの影響は以下を見るのがよさそうです。
https://security-tracker.debian.org/tracker/CVE-2024-3094


脆弱性そのものよりも、背景的な部分（OSS開発者が意図的に行った点、買収の可能性がある点）などは以下がわかりやすかったです。
https://forest.watch.impress.co.jp/docs/news/1580604.html


## PVEのDebianのバージョン
`Based on Debian Bookworm (12.2)`の通りですので、本脆弱の対象外となります。

https://pve.proxmox.com/wiki/Roadmap#Proxmox_VE_8.1


## 実機の確認結果
### 確認用スクリプト
前述のまとめ記事内からも紹介されていますが、以下のスクリプトを実行しバージョンを確認します。
※XZ Utilsのコマンドを使ってもバージョン確認は可能ですが、非推奨です。
https://twitter.com/kostastsale/status/1773890846250926445

```
for xz_p in $(type -a xz | awk '{print $NF}' | uniq); do strings "$xz_p" | grep "xz (XZ Utils)" || echo "No match found for $xz_p"; done
```

### 確認結果
#### PVEのバージョン確認

```
root@demo-pve1:~# pveversion 
pve-manager/8.1.4/ec5affc9e41f1d79 (running kernel: 6.5.11-7-pve)
```

#### Debianのバージョン確認
```
root@demo-pve1:~# cat /etc/os-release 
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
```

#### スクリプトの実行
```
root@demo-pve1:~# cd /tmp/
root@demo-pve1:/tmp# vi check.sh
root@demo-pve1:/tmp# chmod 700 check.sh 
root@demo-pve1:/tmp# ./check.sh 
xz (XZ Utils) 5.4.1
xz (XZ Utils) 5.4.1
```


## 参考

https://pve.proxmox.com/wiki/Roadmap#Proxmox_VE_8.1

https://security-tracker.debian.org/tracker/CVE-2024-3094

https://piyolog.hatenadiary.jp/entry/2024/04/01/035321

https://forest.watch.impress.co.jp/docs/news/1580604.html

https://twitter.com/kostastsale/status/1773890846250926445
【GASでAPIを叩いたら401エラーが出た】Exception: Request failed for https://script.google.com returned code 401　

# 結論 

:::note info
oauthScopesに`https://www.googleapis.com/auth/drive` 追加で解決！
:::

GoogleChatAPIでメッセージを投稿するbot機能を作っていたところ、GASの認証エラーで投稿ができず。

いろいろと試した結果、スコープの設定がまずかったよう。

`https://www.googleapis.com/auth/drive`
を`appsscript.json`の`oauthScopes`に追加したことでエラーは解消できた。

# 注意点
oauthScopesは実は諸刃の剣。

oauthScopesの記載がなければ、自動で必要なスコープが追加される。
つまり自動スコープ追加を止めてしまうため、必要なスコープを正確に記載しておく必要がある。

さらにユーザー権限やシートの共有状況も認証エラーの時には確認する。

# 参考リンク
[stackoverflow.com](https://stackoverflow.com/questions/48812174/unauthorized-401-error-while-execute-as-me?newreg=7cb9b021bc70429ba8f5de404347286a)