OmniAICreator/Qiita-1.07M huggingface dataset:
パーフェクトRubyonRails備忘録4

# RackとRailsの関係

- Rackとは
    - Webアプリケーションサーバ(Puma, Unicorn)とWebアプリケーションフレームワーク間のインターフェイスを共通化した仕様であり、実装となるライブラリである。
    - RailsがPuma上で動作しているのもRackのおかげ
    - Rackとフレームワークの間で機能するRackミドルウェアという機構を持つので、処理を挟むことができる。
- Rackに必要なインターフェイス
    - callメソッドを定義する
    - callメソッドは、envもしくはenvironmentと命名する引数を一つ受け取る
    - callメソッドは次の値を配列で返さなければならない
        - HTTPステータスコードを表す**数値オブジェクト**
        - HTTPヘッダーを表す**ハッシュオブジェクト**
        - レスポンスボディとなる文字列を含んだ**配列風オブジェクト**
    - 例
        
        ```ruby
        class App
          def call(env)
            status = 200
            headers = {"Content-Type" => "text/plain"}
            body = ["sample"]
            [status, headers, body]
          end
        end
        ```
        
    - Rackが利用するエントリーポイント用のファイルとしてconfig.ruを作成する
        
        ```ruby
        require "rack"
        require_relative "app"
        
        run App.new # 例のAppクラスのインスタンスをrunに渡す
        ```
        
    - `rackup`でRackアプリケーションを起動する
        - 事前にrackをインストールしておく
    - localhost:9292へアクセスするとcallメソッドで実装した戻り値が確認できる
- callが受け取る引数envについて
    - 引数として受け取る値は、HTTPリクエストに関する情報
    - すなわち、Rackアプリケーションとは、HTTPリクエストを受け取り、HTTPレスポンスを返すアプリケーションである
- Railsとの関係
    - RailsもRackアプリケーション(例で作成してAppクラスインスタンス)のため、rackupでRailsアプリケーションを起動することができる
    - config.ruファイルを確認すると以下のような記述がある。
        - `run Rails.application`
        - ここでRailsアプリケーションオブジェクトを渡している

# DBの管理

- RailsによるDB関連のタスク一覧
    
    
    | コマンド | 概要 |
    | --- | --- |
    | rails db:create | DBを作成する |
    | rails db:drop | DBを削除する |
    | rails db:migrate | マイグレーションファイルの内容をDBに反映する |
    | rails db:migrate:status | マイグレーションファイルの反映状況を確認する |
    | rails db:prepare | DBが存在すればdb:migrateを、しなければdb:setupを実行 |
    | rails db:reset | DBを削除し(db:drop)、db:setupを実行 |
    | rails db:rollback | 実行したマイグレーションを取り消す |
    | rails db:schema:dump | DBの構成をdb/schema.rbへ出力する |
    | rails db:schema:load | db/schema.rbの内容をDBへ反映する（マイグレーションをスキップできる） |
    | rails db:seed | db/seeds.rbの内容を反映する |
    | rails db:seed:replant | DBの内容をTRUNCATEし、db:seedを実行する |
    | rails db:setup | db:migrate、db:schema:load、db:seedを実行する |
    | rails db:version | マイグレーションのバージョンを表示する |
【paiza×Qiita】対象問題を解いてみた【D問題編】

# はじめに
近々，全く分野の異なる開発にチャレンジする機会があり，そちらの技術をキャッチアップするためにコーディングをしていたが，エラーが続き……
そんな萎えていたところに，面白そうなこちらのイベントを発見した．

という訳で，気分転換に，サクッと解いてみた．
気分転換が目的なので，解説や裏どりが雑かもしれませんが，それでも良ければ読んでやってください．

:::note
言語は普段の研究で利用しているPythonです
:::

**コードの一覧**

https://github.com/Yorozuya-59/paiza_qiita_colab/tree/main


# N倍の文字列

https://paiza.jp/works/mondai/d_rank_skillcheck_archive/square

`*`をN回繰り返す問題です．
Pythonには文字列の演算が用意されているので，そちらを活用すれば良いでしょう．

```python
N = int(input())

print('*' * N)
```


# Eメールアドレス

https://paiza.jp/works/mondai/d_rank_skillcheck_archive/email_address

こちらの問題も「N倍の文字列」と同じく，文字列の操作ですね．
文字列の加算でも書けると思いますが，慣れているf文字列を使いました．

```python
s = input()
t = input()

print(f'{s}@{t}')
```


# 足し算

https://paiza.jp/works/mondai/d_rank_skillcheck_sample/addition

特に，説明する部分もなさそうですが，言及しておくとすれば……
「print関数には文字列以外にも渡すことができる」という程度でしょうか．

```python
a, b = map(int, input().split())

print(a + b)
```

これだけではあまりなので，先の問題のf文字列に関連して……

```python
# a = 3, b = 7
print(f'{a + b = }')
>> a + b = 10
```

という書き方もできたりします．
デバッグの時に非常に便利ですね．


# 一番小さい値

https://paiza.jp/works/mondai/d_rank_skillcheck_sample/min_num

本問題も特に言及することもないような気がしますが，関連して少し発展的な内容を．
min関数やprint関数のように，引数を任意の個数だけ受け取ることができるような引数を可変長引数と言います．
可変長引数の詳細な説明は本記事では扱いませんが，使いこなせるようになると非常に便利です．

```python
n1 = int(input())
n2 = int(input())
n3 = int(input())
n4 = int(input())
n5 = int(input())

print(min(n1, n2, n3, n4, n5))
```


# 文字の一致

https://paiza.jp/works/mondai/d_rank_skillcheck_sample/diff_str

基本的な条件分岐の記法を問う問題ですね．

```python
a = input()
b = input()

if a == b:
    print('OK')
else:
    print('NG')
```

上記のような書き方でも問題ないのですが，非常に長いコードになってきた時に，全て上記のような書き方をしていると冗長になりがちです．
そんな時は，以下のように1行で書くようにするとスッキリして見えます．（三項演算子）

```python
a = input()
b = input()

print('OK' if a == b else 'NG')
```

紹介はしましたが，無理して使う必要は無いと思います．
私自身，初学者の頃は「三項演算子が読み易いなんてあり得ない！」と考えていましたが，しばらくすると自然と使い始め，段々と読みやすく感じるようになりました．
時間が解決してくれると思いますので，上記の回答例は参考までに．


# 最後に
今回の対象問題（Dランク）は以上です．
問題自体は非常に簡単なものなので，脱線した説明が多かったと思いますが，如何でしたでしょうか？
【React】フックについて

## UseReducer

```ReactApp.js

import { useReducer } from "react";
import "./App.css";
import InfoContext from "./index";
import { type } from "@testing-library/user-event/dist/type";



//reducer 関数は、現在の state と action を受け取り、新しい state を返す
const reducer = (state, action) => {
  switch (action.type) {
    case "increment":
      return state + 1;
    case "decrement":
      return state - 1;
    default:
      return state;
  }
}


function App() {

//useReducer フックを使って、state と dispatch を取得
const [state, dispatch] = useReducer(reducer, 0);
  return (
    <div className="App">
      <h1>UseReducer</h1>
      <p>カウント：{state}</p>
      <button onClick={() => dispatch({type:"increment"})}>+</button>
      <button onClick={() => dispatch({type:"decrement"})}>-</button>
    </div>
  );

}
export default App;
```


## UseMemo

```React:App.js


import { useMemo, useState } from "react";
import "./App.css";
import InfoContext from "./index";
import { type } from "@testing-library/user-event/dist/type";


function App() {

  const [count01, setCount01] = useState(0);
  const [count02, setCount02] = useState(0);
  //useState フックを使って、count01 と count02 という2つの状態変数を定義

  const square = useMemo(() => {
    let i = 0;
    while (i < 200000) {
      i++;
    }
    return count02 * count02;
    
  }, [count02]);
  //useMemo フックを使って、count02 の値が変わったときにのみ再計算される square という変数を定義
  //計算は count02 の2乗を求めるもので、意図的に重い計算（ループ）が含ませる
  //useMemo フックは、依存配列 [count02] に基づいてキャッシュを管理する
  //count02 が変更されたときだけ再計算が行われ、それ以外のレンダリングではキャッシュされた値が使用される
  //useMemo フックを使用することで、count01 の更新に伴う再レンダリングでも、count02 の2乗の計算は再実行されず、パフォーマンスが向上する！！


  return (
    <div className="App">      
      <h1>UseMemo</h1>
      <div>カウント1:{count01}</div>
      <div>カウント2:{count02}</div>
      <div>カウント2の2乗:{square}</div>
      <button onClick={()=>setCount01(count01+1)}>+</button>
      <button onClick={()=>setCount02(count02+1)}>+</button>
    </div>
  );

}
export default App;



```

## useCallback


```React:App.js
import { Children } from "./Children";
import { useCallback, useState } from "react";

export const App = () => {
  const [count, setCount] = useState(0);  // 数値型の状態変数 count を定義
  const [open, setOpen] = useState(true); // 真偽値型の状態変数 open を定義

  // count をインクリメントする関数
  const onClickCountUp = () => setCount(count + 1);

  // open を false に設定する関数（関数は依存配列に基づいてメモ化される）
  const onClickOpen = useCallback(() => setOpen(false), [open]);

  return (
    <div>
      <h1>親コンポーネント</h1>
      <button onClick={onClickCountUp}>親ボタン</button>
      <p>{count}</p>
      <Children open={open} onClickOpen={onClickOpen} />
    </div>
  );
};

export default App;

```


```React:Children.js

import React, { memo } from 'react';

export const Children = memo((props) => {
  const { open, onClickOpen } = props;

//open の値が true から false に変わると、子コンポーネントがアンマウントされる。
//open の値が true のままであれば、onClickOpen 関数を呼び出しても子コンポーネントが再レンダリングされない。

  return (
    <>
      {open ? (
        <div>
          <h1>子コンポーネント</h1>
          <button onClick={onClickOpen}>子ボタン</button>
        </div>
      ) : null}
    </>
  );
});


```
（if文復習）scriptタグの位置でエラーがでた話。

お疲れ様です。

実家へ帰ったり法要があったりで久々の投稿です。皆様体調などいかがでしょうか？
私は何度目かの蓄膿症を発症しましたが、治ってきているような感じもあり元気にしています:relaxed:

そして、実家にいる間、MDNさんやudemyさんを使い、自信のないJSのif文やfor文の復習をしておりました。
今日は約1時間if文の復習をしました。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="wvLpVXg" data-pen-title="Untitled" data-user="mtzkmy" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/mtzkmy/pen/wvLpVXg">
  Untitled</a> by mtzkmy (<a href="https://codepen.io/mtzkmy>@mtzkmy</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

MDNさんの[「JavaScript building blocks」](https://developer.mozilla.org/ja/docs/Learn/JavaScript/Building_blocks/conditionals)というページの中にある教材を使いました。

教えてくださったcodepenさんが便利すぎて、教えていただいて本当に感謝の限りです！コードと表示結果を1つでまとめられるなんてすばらしい…
各コードの説明については、コード内のコメントアウト通りですので、割愛いたします。

タイトルにありますエラーの話ですが、とても初歩的なことですので、読み飛ばしていただいて大丈夫です:sob:

結論から申し上げますと、HTML内のscriptタグを body の直後に置いていると、JS内の select.addEventListener("change", setWeather); でtypeErrorが出ましたが、 scriptタグが /body の直前に置くと改善されたというものです。

エラーが出たときは、綴りのミスかーと思い、該当のコードを見直しておりましたがわからず。その後20分くらい直前のコードにミスがないかなど確認しておりましたが、最終的にchatGPT先生にコードを貼り付け確認していただき、提示される改善策を試していたところ、scriptタグの位置を訂正しただけでエラー解消となりました。結局綴りミスはありませんでしたが、位置だけでエラーって出るんだなぁとよい経験になりました。

次回からはちゃんと /body 直前に置きます…！
XSS 脆弱性とその対応策について

タイトルの通りです。
とはいえ、XSS 脆弱性を知るためにまずはブラウザに備わる SOP という機能について説明します。

## Same Origin Policy (SOP) とは

Same Origin Policy (SOP) は、Webブラウザの保護機構であり、セキュリティ対策の一環として、ルールに基づいて Origin 間の書き込みや読み込みを制限します。

### Origin の決定

SOPでは、以下の3つの要素に基づいてOriginが決まります：

1. **スキーム（Scheme）**: 例: `https`
2. **ホスト名（Hostname）**: 例: `example.com`
3. **ポート番号（Port Number）**: 例: `443`

例えば、`https://example.com:443/some/path` の場合：

- **スキーム**: `https`
- **ホスト名**: `example.com`
- **ポート番号**: `443`

このURLが示すOriginは、`https://example.com:443` です。

#### 同一Originの場合

- 読み込み、書き込みが可能です。

#### 異なるOriginの場合

- 読み込み不可。
- 書き込み許可制（CORS）

### SOP の動作原理

通信を行うソースコードが埋め込まれたWebページが、その通信先のOriginを比較して判断します。

## Cross-Site Scripting (XSS) 脆弱性

Cross-Site Scripting (XSS) は、JavaScriptやHTMLタグを何らかの方法でWebページに注入し、それを用いて情報を盗んだり、Webアプリケーション内で不正な操作を行う攻撃手法です。このような脆弱性を「XSS脆弱性」と呼びます。
上述の通り Origin をまたぐ通信は制約があるのでおこなれませんが、同一 Origin だった場合は特に制約がないためこの脆弱性が存在する可能性があります。

### XSS の種類

1. **Reflected XSS**
   - 攻撃で取得した内容を画面に表示する手法。

2. **Stored XSS**
   - リクエストに含まれた悪意のある値がデータベースに保存され、その後別のリクエストで使用される手法。

3. **DOM-based XSS**
   - 取得した値をDOMを操作して表示させる手法。

### XSS 脆弱性のリスク

- **Cookie奪取**
  - JavaScriptで `document.cookie` にアクセスされてしまう。

- **Cookie付きリクエストによる不正操作**
  - 同一Origin内で任意のURLを入れてリソースを直接操作。

- **フィッシング**
  - DOM操作を通じて、偽のフォームを表示し、クレジットカード情報などを盗む。

### XSS 対策

1. **出力の際のエスケープ処理**
   - 特にReflected XSSとStored XSSに有効です。
   - `innerHTML` や `eval` など、HTMLとして解釈されるAPIは使用せず、DOM APIを利用します。

2. **HTMLエスケープ**
   - HTMLタグ内にエスケープ処理を施す。
   - `href` 属性の場合、スキームのチェックを行い、`http://` などの正当なスキームであることを確認します。

3. **Cookieに HttpOnly 属性を付ける**
   - JavaScriptからのアクセスを防ぎます。

4. **Content Security Policy (CSP) の活用**
   - コンテンツの制限を通じて、悪意のあるスクリプトの実行を防ぎます。
LaravelでAccess-Control-Allow-Originエラー【CORS】

CORSを設定しよう

```bash
php artisan config:publish cors
php artisan config:clear
```

すべてのリクエストに設定するには、`config/cors.php`を変更してね

```php:config/cors.php
// 変更前
'paths' => ['api/*', 'sanctum/csrf-cookie'],
// 変更後
'paths' => ['*', 'sanctum/csrf-cookie'],
```

エラー内容
```js
Access to fetch at 'https://example.jp' from origin 'https://example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
```
【GitHub】IssueをURLクエリから作成する際にテンプレートを使用する方法

IssueをURLクエリから作成する際にテンプレートを使用するにはテンプレートを`?template=issue_form.yml`のように指定します。

```
https://github.com/sample/repo/issues/new?template=issue_form.yml
```


https://docs.github.com/ja/issues/tracking-your-work-with-issues/creating-an-issue#creating-an-issue-from-a-url-query
EV3DEVでジャイロセンサを強制リセットする方法

# 環境
EV3DEV上で動作する任意のアプリケーションで実行できる。
コードサンプルはMicroPython。
# 問題
ジャイロセンサを利用していると、動いていないのに値が常に変動する場合がある。
# 解決策
ジャイロセンサのモードをGYRO-CALに設定すれば良い。
例えば、標準のドライバを利用して以下のように記述できる。
`echo GYRO-CAL > /sys/class/lego-sensor/sensor<id>/mode`
※ここでのIDはジャイロセンサが接続されているポートとは異なる。詳細は以下を参照。

https://qiita.com/WriterOsle/items/de46cc3fced6ac3e7a3c

# 実装
os.system()で実装する。[^KEY]
``` main.py
# get sensor id
sensor_id = 0
dirs = os.listdir('/sys/class/lego-sensor')
for _dir in dirs:
    address_file = open('/sys/class/lego-sensor/' + _dir + '/address')
    address = address_file.read()
    address_file.close()
    if address == 'in' + str(1):
        sensor_id = int(_dir.replace('sensor', ''))

# do forced reset
os.system('echo GYRO-CAL > /sys/class/lego-sensor/sensor' + str(sensor_id) + '/mode')
os.system('echo GYRO-ANG > /sys/class/lego-sensor/sensor' + str(sensor_id) + '/mode')

```

[^KEY]: subprocessはMicroPythonでは(少なくとも初期状態では)利用できない。
EV3DEVでドライバで使うセンサーのIDを取得する

# やること
EV3DEVのドライバで直接参照できるIDを取得する。
# 方法
`/sys/class/lego-sensor`内の各ディレクトリの`address`ファイルを読み取り、それを物理ポートと照合する。
# 実装例
``` main.py
def sensor_port_to_id(port: int) -> int:
    dirs = os.listdir('/sys/class/lego-sensor')
    for _dir in dirs:
        address_file = open('/sys/class/lego-sensor/' + _dir + '/address')
        address = address_file.read()
        address_file.close()
        if address == 'in' + str(port):
            return int(_dir.replace('sensor', ''))
        return 0
```
# 参考文献
https://docs.ev3dev.org/projects/lego-linux-drivers/en/ev3dev-stretch/
Spring Security でログイン後にCSRFトークンがCookieに設定されない問題への対処方

# はじめに
Spring Security でCookieによるCSRF対策を実施している場合、クライアント側ではCookieの"XSRF-TOKEN"を読み取ります。
しかし、ログイン認証処理後やログアウト後は、Cookieがクリアされてしまいます。
それにより、ログイン後にCookieを取得することが出来なく、処理を続行することができません。
デフォルトの設定だとうまくいきませんのでひと工夫が必要です。

# 解決策
解決策は、公式サイトに書いてあります。
https://spring.pleiades.io/spring-security/reference/servlet/exploits/csrf.html#csrf-integration-javascript-spa


CookieにCSRFトークンを出力するためのフィルタを新たに作成
※公式サイトより一部引用

```java:新たに作成するFilter
final class CsrfCookieFilter extends OncePerRequestFilter {

	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		CsrfToken csrfToken = (CsrfToken) request.getAttribute("_csrf");
		// Render the token value to a cookie by causing the deferred token to be loaded
		csrfToken.getToken();

		filterChain.doFilter(request, response);
	}
}
```

上記クラスをSecurityConfigに追加

```java:SecurityConfig

@Configuration
@EnableWebSecurity
public class SecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		http
			// ...
			.csrf((csrf) -> csrf
				.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())   
				// ...
			)
			.addFilterAfter(new CsrfCookieFilter(), BasicAuthenticationFilter.class); // 新たに作成したFilterを追加
		return http.build();
	}
}
```
これにより、ログイン後やログアウト後にもCSRFトークンがCookieに設定されるようになります。

# 最後に
Spring SecurityのCSRF対策機能では、シングルページアプリケーションやRestAPIの場合、Cookieを利用してCSRF対策を行うことが必須となりますが、ここで述べた問題だけでなく、[シングルページアプリケーションやRestAPIにおけるSpring Security でのCSRF対策](https://qiita.com/norippe3/items/f01758056f07fe47ec0a)でも述べた問題もあり、デフォルトの状態だと動かなかったりします。
前述の通り公式サイトに書いてはいるのですが、それ以外にはなかなか情報がなかったため、こちらに記載しました。
バーチャルブラウザウェブアプリ n*eko を試してみた

# *n\*eko* ってなに？

***n\*eko*** は browser を streaming してくれる web app で、docker で host 可能

見ていただいたほうが早い

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573317/67912c30-4d4d-d8a4-82f0-bf5ccb6e79b3.png)

# 参考

* https://github.com/m1k1o/neko/tree/master
* https://www.vksec.com/300_neko%E6%90%AD%E5%BB%BA%E8%AE%B0%E5%BD%95.html

# 所感

* 良かったところ
    * 導入らくちん
        * もともとは使い捨てのブラウザを用意したくて仮想のUbuntuのブラウザをRDPやらVNC等々でリモートアクセスしていたが、使えるところまでひと手間なのに対し、  
          n\*ekoであれば、dockerで建てるだけ (エラーもあったが)
    * ホスト側の負荷が軽い
        * ベンチ取っていないが、上述の仮想Ubuntuの場合より 2分の1 〜 3分の1くらいの負荷で済んでいる気がする
        * ブラウザゲーはやってみていないのでわからないが、CPU 1コア割当なので期待できなさそう
* イマイチなところ
    * フォント
        * しかたないが、用途的に気にならないのでOK
* ほか
    * 操作感はちょっと早くしたIP-KVMみたいな

# 導入方法 と エラー

## 導入: docker compose

networkを host (NATしない) 形式にしないと後述ハマったエラーのエラーでにゃんこアイコンを眺め続けることになる

```yaml:compose.yml
services:
  neko:
    container_name: neko
    image: "m1k1o/neko:firefox"
    restart: "unless-stopped"
    shm_size: "3gb"
    expose:
      - "8080"
      - "8081/tcp"
      - "8082/udp"
    network_mode: host
    environment:
      NEKO_SCREEN: 1600x900@60
      NEKO_PASSWORD: neko
      NEKO_PASSWORD_ADMIN: nyanko
      NEKO_TCPMUX: 8081
      NEKO_UDPMUX: 8082
```

`NEKO_SCREEN` 設定値はdockerコンテナで `x11-xserver-utils` を `apt` で入れて、 `xrandr` を叩くと一覧取れる
n\*ekoにログインしたあと選択肢から変更可だが、自分はあとから変えて長期稼働大丈夫かわからんので最初から使う設定で入れるように書き直し&upし直し

## ハマったエラー

NATが悪さしているっぽかった
NATが悪いときはNATしないのが一番

```
WRN negotiation is needed module=webrtc
ERR creating offer failed error="InvalidModificationError: invalid proposed signaling state transition: have-local-offer->SetLocal(offer)->have-local-offer" module=webrtc
```

* https://github.com/m1k1o/neko/issues/406
    * 投稿時点では未解決で、 `NEKO_NAT1TO1` も設定してみたがNG
S3とGitHub Actionsを使った静的Webサイトのデプロイは思ったよりも簡単だった！

こんにちは！この記事は、私が初めてAWSのS3とGitHub Actionsを使って静的Webサイトをデプロイした時の備忘録です。今回はAstroを使ってWeb作成をしてみました。結論から言うと、S3を使ったCICDは想像以上に簡単でした。ここでは、私が行った手順を説明していきます。

## 前提条件

このガイドを進める前に、以下のツールとアカウントが必要です：

- コマンドラインインターフェース（CLI）の基本的な操作スキル
- Git（バージョン管理システム）
- AWS CLI（インストール済み）
- AWSアカウント
- GitHubアカウント
- Node.js（プロジェクトに応じたバージョン）
- 静的サイトジェネレーター（例：Astro）の基本知識
  ※ フレームワークは使いたいのを使ってください。
 
上記の準備ができていることを確認してから、以下の手順に進んでください。

# AWSとGitHubを使用した静的Webサイトのデプロイ手順

## 1. IAMの作成
クレデンシャルの情報を取得します。
- 起動経路:
  - IAM > ユーザー > アクセスキーの作成
  - アクセスキーとシークレットアクセスキーを取得します。
  - ユーザーにはS3のフルアクセス権限が必要です。

## 2. S3の作成
- 静的Webホスティングの設定を行います。

## 3. GitHubでの設定
1. GitHubにログイン
   - ブラウザでGitHubにアクセス

2. リポジトリを作成

3. GitHub Secretsの設定確認手順
   a. 該当のリポジトリに移動する
   b. リポジトリの設定ページに移動
　・リポジトリのメインページで、上部のタブから「Settings」をクリック
   c. Secretsのページに移動する
　・左側のサイドバーから「Secrets and variables」>「Actions」をクリック
   d. 以下の4つのシークレットを作成します：
　・AWS_ACCESS_KEY_ID
　・AWS_SECRET_ACCESS_KEY
　・AWS_REGION
　・S3_BUCKET
   
   【参考】
   各シークレットは下記の様に記入
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812002/977776a6-e54e-c0a8-a844-1a0ff44517d6.png)

## 4. GitHub Actionsワークフロー作成手順

1. GitHubリポジトリにアクセス
   - ブラウザでGitHubにログインし、対象のリポジトリページを開く

2. Actionsタブに移動
   - リポジトリのメインページ上部にある「Actions」タブをクリック

3. 新しいワークフローの作成
   - 「New workflow」ボタンをクリックし
   - または「set up a workflow yourself」リンクをクリックし

4. ワークフローファイルの編集
   - `.github/workflows/deploy.yml` という名前のファイルが自動的に作成されます。
   - 以下のコードをコピーして、エディタに貼り付けます：

```yaml
name: Deploy to S3

on:
  push:
    branches:
      - main  # メインブランチ名に応じて変更（例：master）

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3

    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '20'  # プロジェクトに合わせて変更可能

    - name: Install dependencies
      run: npm ci

    - name: Build Astro site
      run: npm run build

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v4
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ${{ secrets.AWS_REGION }}

    - name: Deploy to S3
      run: |
        aws s3 sync dist/ s3://${{ secrets.S3_BUCKET }} --delete
```

## まとめ

以上が、S3とGitHub Actionsを使った静的Webサイトのデプロイ手順です。最初は難しそうに見えましたが、実際にやってみると驚くほど簡単でした。特に、GitHub Actionsの設定さえ済ませてしまえば、あとは自動的にデプロイが行われるので、とても便利です。
ABC367振り返り


[前回の振り返り](https://qiita.com/comet725/items/85e1f5ee3369faf4e028)

今日はABC開催日だったので参加結果を振り返る

https://atcoder.jp/contests/abc367

今回はBCDの3完、A問題が沼って3ペナしたのでブッチしてしまいました😅

# A

適当にじっそうしたら3回WA
原因がよく分からず、時間もったいないのでパス

# B

文字列を`.`でセパレートして
第2項が0なら第1項をint、
それ以外なら文字列全体をfloatに変換

## ソースコード

```python:main.py
s = input()
i,f = list(map(int,s.split('.')))
x = int(i) if f == 0 else float(s) 
print(x)
```

# C

配列が条件を満たす数を総当り計算
考えうる配列を直積でイテレーションする。


## ソースコード

```python:main.py
import sys
from itertools import product
def rI(): return int(sys.stdin.readline().rstrip())
def rLI(): return list(map(int,sys.stdin.readline().rstrip().split()))
def rS(): return sys.stdin.readline().rstrip()
def rLS(): return list(sys.stdin.readline().rstrip().split())
def err(*args): print(*args, file=sys.stderr)

def main():
    N, K = rLI()
    R = rLI()
    B = [list(range(1,r+1)) for r in R]
    for p in product(*B):
        if sum(p) % K == 0:
            print(*p)
    
if __name__ == '__main__':
    main()

```

# D

2週分累積和の剰余をだして
それぞれの休憩所から時計回りにN-1箇所巡ったとき
休憩所1から今の休憩所までかかる歩数の剰余が一致する数を答えに加算

自分の言葉ではこの説明が限界…

## ソースコード

```python:main.py
import sys
from collections import defaultdict, Counter

def rI(): return int(sys.stdin.readline().rstrip())
def rLI(): return list(map(int,sys.stdin.readline().rstrip().split()))
def rS(): return sys.stdin.readline().rstrip()
def rLS(): return list(sys.stdin.readline().rstrip().split())
def err(*args): print(*args, file=sys.stderr)


def main():
    N, M = rLI()
    A = rLI()
    S = [0] + A
    S += A
    T = [0] * len(S)
    for i in range(1,2*N+1):
        S[i] += S[i-1]
        T[i] = S[i] % M
    c = Counter(T[:N])
    m = defaultdict(lambda: 0)
    for k,v in c.items():
        m[k]=v
    # err(S)
    # err(dict(m))
    ans = 0
    for i in range(N):
        t0, tn = T[i], T[N+i]
        m[t0] -=1
        # err(T[i],dict(m),T[i+1:N+i],[s-S[i] for s in S[i+1:N+i]])
        ans += m[t0]
        # err(ans, m[t0]) 
        m[tn] +=1
        
    print(ans)
    
if __name__ == '__main__':
    main()

```

# E

線形代数の置換的なものをマッチングに応用したら…
とかおもってグラフならまだ自分は実装できないと思いパス

この考察は全然的外れでダブリングとかいう方法すればいいみたい。

# F

セグ木でカウントしようとしたけどTLE
ハッシュ値を出して累積和とかそんなん知らんて…

# G

ギリギリまでFやってたから見る時間なかった。
最近XORの問題多くない？

# まとめ

A問題に沼って150点落としたが今回もD問題を解くことができた。

E以降の解けなかった問題は実装したことないアルゴリズムを使用する必要があり、
そのあたりの知識を蓄える必要がある。
GitHub の Saved Replies でコードレビューに心理的安全性を！


## はじめに

コードレビューをする際に、「個人の好みかなぁ」というコメントを付けるのをためらったことはありませんか？レビュイーに正しく意図を伝えて心理的安全性を高めたいと思い、Saved Replies を使ってコメント種別をつけることにしました。

## コメント種別

|略語|意味|説明|
|----|----|----|
|MUST|必須：Must|修正されないとApproveできません。修正のアクションが必要です。|
|IMO|提案：In My Opinion|個人的な見解や軽微な提案です。タスク化や修正等のアクションが必要です。|
|Q|質問：Question|質問です。回答のアクションが必要です。|
|NR|お手すきで：No Rush|不急なので今やるかはおまかせします。タスク化や修正等のアクションが必要です。|
|NITS|あらさがし：Nitpick|重箱の隅をつつく提案です。やってもいいがやらなくてもよいです。アクションは不要です。|
|FYI|参考までに：For Your Information|参考までに共有します。アクションは不要です。|

## Saved Replies

返信テンプレートともいいます。Saved Replies を活用することで、手間なくコメントをつけることができます。

### 設定方法

1. <https://github.com/settings/replies> へアクセス
1. タイトルとコメントを記載
1. Add saved reply をクリックし保存

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/e1b4589a-19da-6361-adaa-2fb278608009.png)

### 返信テンプレート例

```md
**[MUST: 必須]**[^1]

xxx

[^1]: 修正されないとApproveできません。修正のアクションが必要です。
```

```md
**[IMO: 提案]**[^1]

xxx

[^1]: 個人的な見解や軽微な提案です。タスク化や修正等のアクションが必要です。
```

```md
**[Q: 質問]**[^1]

xxx

[^1]: 質問です。回答のアクションが必要です。
```

```md
**[NR: お手すきで]**[^1]

xxx

[^1]: 不急なので今やるかはおまかせします。タスク化や修正等のアクションが必要です。
```

```md
**[NITS: あらさがし]**[^1]

xxx

[^1]: 重箱の隅をつつく提案です。やってもいいがやらなくてもよいです。アクションは不要です。
```

```md
**[FYI: 参考までに]**[^1]

xxx

[^1]: 参考までに共有します。アクションは不要です。
```

### 使用例

Saved replies をクリックすることで、返信が選択できます。タイトルで検索も可能です。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/4a7bbc38-909e-493e-2104-760584c74848.png)
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/941320a3-8aed-813e-82fa-4774fa5beeae.png)

実際にコメントすると、以下のような感じになります。

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/4c314bfc-805f-c984-02a7-5ea2da1ee929.png)
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/55f14aa3-995d-5a0a-f396-b903ea78042d.png)
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/22c50015-91e5-5321-01a7-0fa5a610618f.png)
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/a8741f54-c358-2748-6074-c51459431301.png)
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/d9c5b7b1-c561-9cf5-6333-5f1559838c79.png)
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/3731da68-cd18-7dec-5363-28431fa0f783.png)

## まとめ

レビュアーとしては軽い提案のつもりでも、レビュイーには厳しい指摘コメントばかりに見えることがあります。Saved Replies を駆使して、意図を正確に伝えられると快適なコードレビューになると思います！
[SQL] [DML] 表の結合

# 一覧表
|SQL文|和名|詳細|
|:--|:--|:--|
|UNION<br>UNION DISTINCT|和|`SELECT * FROM A UNION SELECT * FROM B`<br>重複行を除いて出力する|
|UNION ALL|和|`SELECT * FROM A UNION ALL SELECT * FROM B`<br>重複行も含んで出力する|
|INTERSECT|共通|`SELECT * FROM A INTERSECT SELECT * FROM B`|
|EXCEPT|差|`SELECT * FROM A EXCEPT SELECT * FROM B`|
|CROSS JOIN|直積|`SELECT * FROM A CROSS JOIN B`<br>`SELECT * FROM A CROSS JOIN SELECT * FROM A, B`|
|INNER JOIN|内部結合|`SELECT * FROM A INNER JOIN B ON A.* = B.*`<br>＊で結合する、結合する両方の表に存在する行だけ取り出す|
|LEFT OUTER JOIN|左外部結合|`SELECT * FROM A LEFT OUTER JOIN B ON A.* = B.*`<br>＊で結合する、結合する左の表に存在する行だけ取り出す<br>（右の行の存在しない行はNULL）|
|RIGHT OUTER JOIN|右外部結合|`SELECT * FROM A RIGHT OUTER JOIN B ON A.* = B.*`<br>＊で結合する、結合する右の表に存在する行だけ取り出す<br>（左の行の存在しない行はNULL）|


# 例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/e383758e-3040-5dfd-7cb5-d35e415bb998.png)

## 和(UNION)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/ddd89435-e702-f072-8eb1-9efdb4afc490.png)

## 直積(CROSS JOIN)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/703785cf-bfd0-8e11-96ee-6c67f3995dd9.png)

## 内部結合(INNER JOIN) 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2955010/cc112c39-354e-987f-8619-a4dc122b7756.png)


# 参考リンク
- [令和3秋29_UNION_JOIN](https://www.ap-siken.com/kakomon/03_aki/q29.html)
- [令和2秋39_UNION ALL](https://www.ap-siken.com/kakomon/26_haru/q28.html)
既存プロジェクトへのTauriの追加

公式が既存プロジェクトへの追加方法を提示してくれているので追加は簡単 [(Tauri 公式)](https://tauri.app/v1/guides/getting-started/setup/integrate/)

インストールとAPIの呼び出しを行った
- Cargo のインストール
- プロジェクトへの Tauri の追加
- Tauri API の呼び出し
- Rust プロセスの呼び出し

※ Tauri 2.0 では import 対象など変更必要 (2024/10/7 追記)

## Cargo のインストール

インストールが必要

Windowsではインストーラーからのインストールしかない模様

Visual Studio のインストールも併せて行われる

[Cargo 公式](https://doc.rust-lang.org/cargo/getting-started/installation.html)

## プロジェクトへの Tauri の追加

プロジェクトディレクトリでインストールコマンド実行
実行時にいくつか質問される。後で `tauri.conf.json` から修正可能

```shell
npm install --save-dev @tauri-apps/cli
```

以下の項目は 既存プロジェクトに合わせるように設定が必要

- 4.*What is the URL of your dev server?*
- *5.What is your frontend dev command?*
- 6.*What is your frontend build command?*

React プロジェクトでデフォルトの状態から変えていなければ、

(4)dev serverは`[http://localhost:3000](http://localhost:3000/)`, (5)dev commandは`npm run start`, (6)build commandは`npm run build` を設定

これらの設定は `npm run tauri dev`, `npm run tauri build` を行った時に、Tauri の処理に先立ってコマンドが実行される模様

最後にエラー対策で `tauri.conf.json` の identifier をデフォルトから変更する
名称は初期のものでなければなんでも可

## Tauri API の呼び出し

例として [fs](https://tauri.app/v1/api/js/fs) (file system) を使用

`src-tauri/tauri.conf.json` の allowlist に fs を追加
scopeに関しては設定しなくても良いが設定しておく

```json
"tauri": {
  "allowlist": {
    "fs": {
      "scope": ["$APPCONFIG/*"],
      "readFile": true,
      "writeFile": true,
      "readDir": true,
      "createDir": true,
      "exists": true
    }
  }
}
```

JavaScript 側
```jsx
import { exists, BaseDirectory, readTextFile, writeTextFile } from '@tauri-apps/api/fs';

export const readSetting = async () => {
    const directory = BaseDirectory.AppConfig
    const fileName = 'conf.json'
    const existSetting = await exists(fileName, { dir: directory });

    if(!existSetting){
        await writeTextFile(fileName, JSON.stringify(DefaultSetting), { dir: directory });
    }
    const config = await readTextFile(fileName, { dir: directory });
    return {
        config: JSON.parse(config)
    }
}

const DefaultSetting = {
    color: '#8833AA'
}
```

## Rust プロセスの呼び出し

`src-tauri/src/main.rs` でコマンドを定義し `invoke_handler` で追加

```Rust
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

#[tauri::command]
fn greet(name: &str) -> String {
   format!("Hello, {}!", name)
}

fn main() {
  tauri::Builder::default()
    .invoke_handler(tauri::generate_handler![greet])
    .run(tauri::generate_context!())
    .expect("error while running tauri application");
}
```

JavaScript 側
```jsx
import { invoke } from '@tauri-apps/api'

export const readSetting = async () => {
	return await invoke('greet', { name: 'World' })
}
```
複数のSVGファイルをPDFファイルに変換する方法

MacでSVGファイルを扱うにはGapplinを用いることが有名ですが、複数のSVGファイルをPDF化するにはいちいち保存しない解けないので面倒ですよね

そこで、Pythonで指定したフォルダ内のSVGファイルをPDFに変換するコードを書いてみました。

```python:svg2pdf.py
import os
from tkinter import filedialog
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPDF

def convert_svg_to_pdf(input_folder):
    # 出力フォルダを作成
    output_folder = os.path.join(input_folder, "pdf_output")
    os.makedirs(output_folder, exist_ok=True)

    # 入力フォルダ内のすべてのSVGファイルを処理
    for filename in os.listdir(input_folder):
        if filename.lower().endswith('.svg'):
            input_path = os.path.join(input_folder, filename)
            output_path = os.path.join(output_folder, f"{os.path.splitext(filename)[0]}.pdf")

            try:
                # SVGファイルを読み込む
                drawing = svg2rlg(input_path)
                
                # SVGをPDFに変換して保存する
                renderPDF.drawToFile(drawing, output_path)
                print(f"変換成功: {filename}")
            except Exception as e:
                print(f"変換失敗: {filename} - エラー: {str(e)}")

# フォルダ選択ダイアログを表示
input_folder = filedialog.askdirectory(title="SVGファイルを含むフォルダを選択してください")

if input_folder:
    convert_svg_to_pdf(input_folder)
    print("変換プロセスが完了しました。")
else:
    print("フォルダが選択されませんでした。")
```

実行前に以下の、モジュールをインストールしておきましょう！
```SVGLIB
pip install svglib reportlab
```
```TKINTER
brew install python-tk
```
RDS のエンジンバージョンアップグレード時にはパラメータグループを確認しよう！


## 概要

RDS を運用していると、エンジンバージョンのアップグレードが必要になります。単にエンジンバージョンを変更するだけでは問題が起きる可能性があるため、パラメータグループを確認しましょう。今回はその確認に便利なパラメータグループの比較機能を紹介します。

![overview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/0f21f98f-6433-cd6e-09f8-4c0d66d09ada.png)

### パラメータグループとは

パラメータグループとは、DB インスタンスやクラスターに適用されるエンジンの設定値の集合です。RDS の作成時に特に設定していなかった、という場合はデフォルトのパラメータグループが割り当てられているはずです。DB のパラメータは動作やパフォーマンスのチューニングに重要な要素です。

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/parameter-groups-overview.html

### なぜパラメータグループを確認するのか

- アプリケーションの動作やパフォーマンスに影響を及ぼさないため
- パラメータグループ自体や静的パラメータの変更には DB の再起動が必要になるため

## パラメータグループ比較

パラメータグループには数百のパラメータがあり、手動でひとつずつ確認していくのは大変です。パラメータグループの比較を活用していきましょう。

### 既存のパラメータグループとデフォルトのパラメータグループを比較

まずは現在のパラメータグループがデフォルト値とどのような差分があるか確認しましょう。
デフォルトのパラメータグループは RDS での利用状況で存在有無が変わるため、まずデフォルト値のパラメータグループを作成します。

![create_parameter_group1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/11ea50dd-b536-6dea-945c-634da3e175b9.png)
![create_parameter_group2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/890520f1-c1f6-5ef0-a375-8cba7c497648.png)

作成できたらパラメータグループ一覧画面に戻ります。2 つのパラメータグループを選択し、アクション＞比較をクリックすることで、既存のパラメータグループに対する意図した設定変更を調べることができます。

:::note warn
DB インスタンスパラメータグループと DB クラスターパラメータグループは比較することができません
:::

![compare_parameter_group1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/1b01f492-2cea-77b4-ab0d-00ff6460ab09.png)
![compare_parameter_group2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/8cc46b58-ad89-552c-800f-9665a1672e35.png)

既存のパラメータグループに加えている変更の多くはアップグレード後も適用すべきだと考えられます。結果を確認して設定を検討してください。

### 旧バージョンと新バージョンのデフォルトのパラメータグループを比較

エンジンバージョンが異なると、設定値の変更、設定項目の追加・削除があります。これもパラメータグループの比較を使うことで簡単に調べることができます。
新バージョンのパラメータグループファミリーでデフォルト値のパラメータグループを作成してください。その後同じように旧バージョンのパラメータグループと比較を行うだけです。

![compare_parameter_group3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/35b0194c-9ad9-0dd4-02e6-1a1e086769f6.png)
![compare_parameter_group4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/9cecfd97-19bb-e7ee-1b2b-698d657e6446.png)

こちらも内容を吟味し、新しいパラメータグループに設定する内容を検討してください。

## DB エンジンバージョンのアップグレード

パラメータグループの検討ができたら DB エンジンバージョンのアップグレードに着手しましょう。一般的にはまず開発環境に適用し、以下の点を確認するとよいでしょう。

- エンジンアップグレードの実施手順
- アップグレード作業時間・サービスダウンタイム
- アップグレード後のアプリケーション動作とパフォーマンス
- 万が一に備えた切り戻し方法・連絡・体制・指揮系統

## まとめ

RDS の運用を任されたが DB の設計や構築はしていないという方に、パラメータグループの存在とパラメータグループの比較によるアップグレード時の調査方法が伝われば幸いです！
自己主権型/分散型アイデンティティ技術調査ホワイトペーパーを読んでみた


ごきげんよう、Jorduです。
今回はTOYOTA CONIQさんが発表している[自己主権型/分散型アイデンティティ技術調査ホワイトペーパー](https://digita-ru.toyotaconiq-alpha.co.jp/contents/y_ssNGVc "自己主権型/分散型アイデンティティ技術調査ホワイトペーパー")を読みました。
こうしていると学生時代の輪読を思い出しますね。

ここの解釈違うかもなどありましたら優しくコメントいただけると勉強になるので喜びます📚


# 1. はじめに

### 背景

・デジタルアイデンティティの利用が活発になり我々の生活が便利になる一方で、さまざまなリスクも生まれている

・リスクへの対応策
① SSI
自分のデータは自分で管理、提供する自己主権型アイデンティティという思想(サービス側で管理されると、どの情報がどこで使われているか、保管されているか把握しきれない)

② DID
特定のサービスに依存しないよう(例 googleアカウントで連携してたけど、アカウント停止であちこちのサービスにアクセスできない！、google側にどのサービスと連携しているか知られてしまう)
にアイデンティティの置き場所は分散しようという思想

### 目的
・想定読者 : 「自己主権型/分散型アイデンティティ」のビジネスへの適用に悩む、ビジネス企画・推進、決裁に関わる方

・目的 : 自己主権型/分散型アイデンティティを用いたデジタル社会実現のための技術理解を助けること、社会実装に向けた課題を示すこと


# 2. 移動体験におけるユースケース

### チケットのデジタル化
パッケージ旅行を予約し、電車・バス・レンタカーなどの移動手段をデジタルIDウォレットを通じて利用する

### マーケティングプラットフォーム
MaaSアプリが位置情報と旅程から移動先のクーポンなどをおすすめ

# 3. 自己主権型/分散型アイデンティティを構成する要素
下記4つのレイヤーがある

レイヤー4 ガバナンスフレームワーク
・検証者が検証可能なクレデンシャルに関する信頼について答えるためのレイヤー
・信頼性保証のために行政機関や業界団体が定めるポリシーや契約

レイヤー3 クレデンシャル
・検証可能なクレデンシャルの相互運用をサポートするレイヤー
・検証可能なクレデンシャルの発行・提供・検証を扱う

レイヤー2 安全なコミュニケーションと通信プロトコル
・信頼されたコミュニケーションを確立するためのレイヤー
・検証可能なクレデンシャルを管理するデジタルIDウォレットとウォレットを介した発行者・検証者・所有者間の通信プロトコル

レイヤー1 識別子と公開鍵
・識別子と公開鍵が定義と管理されるレイヤー
・DIDの仕様とDIDドキュメントを発行者・検証者が参照できる状態で管理する


### レイヤー4 ガバナンスフレームワークの事例
・欧州における電子商取引のための規則eIDAS
→QTSP(適格サービストラストプロバイダ)の監査により、SPやIdPの信頼性が向上
→EU加盟国のQTSPがトラステッド・リスト(信頼できる事業者一覧)に集約される

### レイヤー3 クレデンシャル
・VCの技術仕様
→W3C : データモデル
→IETF : 選択的開示に関するデータフォーマット

・発行者と検証者の参加制限
→VCは発行者から所有者に正しく発行されたかは保証するが、発行者を信頼できるかはわからないから
→検証者に提供した情報がどう活用されるかわからないから

### レイヤー2 安全なコミュニケーションと通信プロトコル
・ウォレットの主要機能
→VC管理、ウォレット利用時の認証、通知、VC格納、検証可能なプレゼンテーションの提供、履歴管理

・通信プロトコル
①遠隔型
→ウォレットとサーバ間のデータのやり取りに利用
→既存のWebサービスやモバイルアプリを大きく変更せずにVCを受け渡すためのプロトコルであるOpenID for Verifiable Credentialsの仕様群がある

②近接型
→クライアント同士のやり取りに利用
→インターフェースはNFC、Bluetooth、QRコードなど

### レイヤー1 識別子と公開鍵
・識別子(DID)は同じDIDの仕組みの中で個人や組織を一意に識別するもので、生成には複数の手段がある(例 デバイスが生成する公開鍵と秘密鍵のキーペアのうち、公開鍵を使って生成)

・公開鍵とDIDの管理方法は集中管理と、複数のデータベースで管理したり端末で管理する分散管理がある

# 4. 今後の展望

### 業界動向
・SMART Health Card : 医療分野のVC標準化、コロナのワクチン接種証明書がこちらの標準に従っている

・eIDAS 2.0 Large Scale Pilot : ARFの社会実装に向けた取り組み。行政サービスの利用、モバイル運転免許証の提示など11個のユースケースがある

・Trusted Web : DFFT(Data Free Flow with
Trust)の実現に向けた「特定のサービスに過度に依存せずに、データ自体とデータのやり取りを検証できる領域を拡大し、Trustを向上する仕組み」

### テクノロジーの標準化
各レイヤーごとのに標準化が進んでいるが、相互に影響されることも少なくないため整理する取り組みもある

### 課題
・レイヤー4 : 運営主体の設立

・レイヤー3 : 業界ごとのユースケースに合わせたVC仕様、参加制限、既存認証との相互接続性

・レイヤー2 : 標準的なUI/UXが定まっていない

・レイヤー1 : 相互運用に適したDIDドキュメントの管理方法
CakePHPでドラッグアンドドロップで表示順を並び替える。

## 参考にした記事

https://qiita.com/teshimaaaaa1101/items/c6acb8879f02c54eb378

上記の記事を参考にして、ドラッグアンドドロップでのデータの表示順並べ替え機能を実装していたところ、時折、うまくいかない（保存されない）ことがあった。
原因が分かったので、その対応策を備忘録的に記録しておきます。
## 原因について
下記は、参考にした記事から引用したもの。
新たな表示順を割り振る箇所。

        for ($i = 0; $i < count($article_list); $i++) {
            $num = $result[$i];
            $article_list[$num]['Article']['order'] = $i;
            $this->Article->save($article_list[$num]);
        }

原因は、参考記事の方法だと表示順のカラムとなるorderの値が連番になっていないといけないからだった。
私が、開発していたwebアプリでは、並べ替え機能の他に削除機能も搭載していたから、削除した際に連番ではなくなってしまう。
考えられる対策としては、削除をするか、並べ替えをするときに、再度、番号を昇順で付け直すことだろう。
削除機能は、CakephpのpostLinkで実装していたので、今回は、後者を選んだ。
引用したコードの前に下記のコードを実行すれば行けるはず。

        for ($i = 0; $i < count($article_list); $i++) {
            $article_list[$i]['Article']['order'] = $i;
            $this->Article->save($article_list[$num]);
        }

もっと良い方法があれば、コメントで教えてください。
【UE5】傾斜フローマップをランタイムで計算する

# 概要
マテリアルで傾斜ベクトルを計算し、テクスチャを使わずにフローマップによる流体表現を行います。
ランタイムで計算を行うので、様々な形状やアクタの回転にも対応できます。
![fl1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149393/b3049760-d513-51e4-a7ca-44790d88acfd.gif)
エンジンバージョンは5.4.3を使用しました。

# 実装
### 傾斜ベクトルの求め方
傾斜ベクトルの求め方はHoudiniのSOPノードLabs FlowmapにあるSlopeメソッドを参考にしました。
![スクリーンショット 2024-08-17 185248.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149393/9ef7cc61-b234-8c5d-814d-a1c5bf68bf62.png)
内部の処理を見ると、法線と下方向のベクトルの外積から従法線を出し、更に従法線と法線の外積で傾斜ベクトルを計算しています。
![スクリーンショット 2024-08-17 185312.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149393/8511be51-4414-148c-d6ae-71da827d5b1a.png)
同じ処理をUEのマテリアルで再現すると以下のような感じになります。
![スクリーンショット 2024-08-17 185047.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149393/0f876c41-2800-f208-fb9b-7ac956615812.png)
Normalizeするかどうかはお好みで。
![スクリーンショット 2024-08-17 190756.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149393/b02fde7d-47b0-6c66-88e6-9b21203d47a3.png)
XYだけの値に見えますが、傾斜ベクトルは上を向くことがないのでZチャンネルにはマイナスの値が入っており、ちゃんとワールド空間のベクトルになっています。

### Flow Map
マテリアルでは便利なFlow Map関数がいくつか用意されていますが、今回はFlowMaps_Simpleを使用します。
![スクリーンショット 2024-08-17 193007.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149393/9a409b33-3609-742a-e339-71f3068bddf0.png)
Diffuse、もしくはNormal MapインプットにFlow Mapで歪ませるテクスチャオブジェクトを刺します。
Flow Vector Mapには先ほど計算した傾斜ベクトルを入力するのですが、本来ここにはテクスチャのFlow Mapを入力するため、計算したベクトルをワールド空間からタンジェント空間に変換します。
Transformノードを挟み、ノードのDetailsからSourceをWorld Space、DestinationをTangent Spaceに設定します。
![スクリーンショット 2024-08-17 195951.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149393/23287d0b-d7c6-f6b0-ebcf-d70ec360046f.png)
出力される値がRGBなのでMaskノードでRGに変換し、Gチャンネルが逆なので-1を乗算して反転させます。
![スクリーンショット 2024-08-17 195754.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149393/7b78904f-8d07-e8b2-09b0-23e18249afdc.png)
UVのスケールやスピードの調整、ベクトルの大きさをお好みで調整するといい感じになります。
![スクリーンショット 2024-08-17 200825.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149393/e8aaeabf-4fd0-cf0a-ae41-f8affd0bf838.png)

# 制限
* メッシュの法線が正しい方向を向いていることが前提になります
* 法線の再計算を行わないWorld Position Offset後は正確な傾斜を計算できません
* タンジェント空間での計算なのでUVシームによってテクスチャの切れ目が発生します
![スクリーンショット 2024-08-17 202223.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149393/3b1de35a-600e-ffe1-3842-6e8f176551a8.png)
* UVアイランド毎のスケールの違いなどによって流れる速度や見え方が変わります
![fl2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149393/b1e8ce48-f04e-b635-8274-edbdd089cd29.gif)
EventBridge のフィルターにプレフィックス・サフィックス・以外・大文字小文字無視の条件が追加されました！


## 概要

Twitter で EventBridge のルールのフィルタリングがパワーアップしたとの情報をキャッチし、実際に調べてみました！

https://twitter.com/nickste/status/1753513030984536380

## ドキュメント確認

AWS の公式ドキュメントを確認すると `Prefix matching`, `Suffix matching`, `Anything-but matching`, `Equals-ignore-case matching` が追加されています！

https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-create-pattern-operators.html

## 実際に確認

EventBridge で実際にイベントパターンを作って確認します。今回はサンプルイベントに `EC2 Instance Launch Unsccessful` イベントを選び、ASG 名を `anything-but` および `prefix` 条件でフィルタリングしてみます。

シチュエーションとしては基本的にはイベントを発火したいが、障害を模したリソース（プレフィックスが broken）では発火させないというケースを想定しています。

![sample-event.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/edbb5af0-7215-a499-29a4-1bf26d634ac0.png)
![filtering-result1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/acdf8815-a509-9a6c-af9d-a65e73c93738.png)
![filtering-result2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/9e844516-99a3-1f2a-2a47-7fd96b5ffd90.png)

```json:event-pattern.json
{
  "source": ["aws.autoscaling"],
  "detail-type": ["EC2 Instance Launch Unsuccessful"],
  "detail": {
    "AutoScalingGroupName": [{
      "anything-but": {
        "prefix": "broken"
      }
    }]
  }
}
```

ASG 名のプレフィックスが broken のイベントのみ一致しない（除外できている）ため、新しいフィルター条件 `anything-but`, `prefix` が正しく機能していることが確認できました！

## まとめ

EventBridge 単体でフィルタリングできていなかった処理をシンプルにできる可能性があり、嬉しいアップデートだと思います！
EventBridge のルールにワイルドカードがサポートされました！


## 概要

EventBridge がより便利になるアップデートが行われました！
ルールの中でワイルドカード `*` が使用できるようになり、より柔軟な条件を簡単に表現することが可能になりました。

## 公式ページ

https://aws.amazon.com/jp/about-aws/whats-new/2023/10/amazon-eventbridge-wildcard-filters-rules/

https://aws.amazon.com/jp/blogs/news/aws-weekly-20231002/

## 検証内容

IAM で何かしらのリソースが作成されたら、監査人へ通知する仕組みを作成します。
CloudTrail より `iam:create*` に該当する API コールを EventBridge で拾い、SNS 経由でメール通知します。

![architecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/ceb33d00-4cf5-2dd1-a86f-d1eb8ae0230b.png)

:::note
セキュリティ向上を目的とする場合、このような自前の作り込みは避けて SecurityHub や GuardDuty を利用しましょう。
:::

## 構築

:::note warn
IAM の API コールは `us-east-1` リージョンに記録されます。そのため検証リソースはすべてバージニア北部に作成する必要があります。
:::

### SNS

まずは SNS トピックを作成します。タイプはスタンダードを選びます。その他の設定はデフォルトで問題ありません。
次にサブスクリプションの作成をします。プロトコルにEMAILを選び、メールアドレスを設定します。
確認メールが届くので、リンクをクリックします。ステータスが確認済みになればOKです。

![sns.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/3a9622e3-807e-b52d-725b-f7207166bad9.png)

### EventBridge

次に EventBridge ルールを作成します。イベントバスは `default` でOKです。

![eventbridge1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/07cbd97f-5b15-66c9-9775-8db2ff9375fb.png)

イベントソースは AWS イベントまたは EventBridge パートナーイベントを選択します。

![eventbridge2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/e3321df0-affb-4f5b-937b-47adcc5891c5.png)

イベントパターンは以下のように設定します。
ここが今回の肝で `"eventName": [{"wildcard": "Create*"}]` と指定しています。

```json
{
  "source": ["aws.iam"],
  "detail-type": ["AWS API Call via CloudTrail"],
  "detail": {
    "eventSource": ["iam.amazonaws.com"],
    "eventName": [{
      "wildcard": "Create*"
    }]
  }
}
```

![eventbridge3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/b4f962a6-d61d-963e-8084-a3717508139b.png)

:::note
イベントタイプの仕様１から直接記入すると、記号が自動エスケープされて意図した記載ができません。「パターンを編集」から直接 `json` を記入します。
:::

:::note warn
単に `"eventName": ["Create*"]` と書いた場合、意図したワイルドカード動作になりません。詳しい記法は以下を参考にしてください。2023/10/29時点では英語ページにのみワイルドカードの記載があります。

https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-create-pattern-operators.html
:::

ターゲットは作成済みの SNS トピックを選択します。

![eventbridge4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/8ba31248-fe04-ef0e-9149-c793ee571339.png)

以上で構築は完了です！

## 動作確認

適当な IAM ロールを作成します。信頼されたエンティティに EC2 を選択し、ポリシーのアタッチはしません。

![test1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/e547dbda-9045-a356-ab28-b7dcf0cb0437.png)

CloudTrail のイベント履歴を確認すると `CreateRole` と `CreateInstanceProfile` が呼び出されていることが分かります。
EC2 を信頼関係に選んだため、IntanceProfile も自動的に作成されます。

![test2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/dd441f5a-6578-e9ed-12f3-1c56662bc784.png)

メールを確認すると `Create` から始まる API の呼び出しについて 2 件の通知が届いています。成功です！

![test3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3852183/6ca2f9ba-5c14-e447-e1c6-e39f9f07084c.png)

## まとめ

EventBridge のルールでワイルドカードが使えるようになり、より簡単にイベント駆動型システムを組めるようになりそうです。
一方 IAM ポリシーの感覚で `*` をつけるだけでは期待した動作とならないので注意が必要です。
Rubyプログラミング考え方｛その４：3行のデータの入力 (paizaランク D 相当)｝

https://paiza.jp/works/mondai/stdin/stdin_3_line

**ステップ1: 要件の分析**
- 標準入力で3行の文字列が与えられます。それぞれの文字列をそのまま3行で出力するプログラムを作成します。
- 各行の文字列は1文字以上100文字以下で、英小文字、大文字、数字、または半角スペースを含むことができます。

**ステップ2: 擬似コードの設計**
1. 標準入力から3行の文字列を順番に取得します。
2. 取得した各文字列をそのまま出力します。

**ステップ3: コメント付きRubyコードの作成**

```ruby
# 1行目の文字列を取得
a = gets.chomp
# 2行目の文字列を取得
b = gets.chomp
# 3行目の文字列を取得
c = gets.chomp

# 1行目の文字列を出力
puts a
# 2行目の文字列を出力
puts b
# 3行目の文字列を出力
puts c
```

**ステップ4: コードの解説**
- **標準入力の取得:** `gets.chomp`を使って、各行の入力を取得し、末尾の改行を削除します。
- **出力:** `puts`を使用して、取得した各文字列をそのまま出力します。

このコードをRuby環境で実行すると、入力された3行の文字列がそのまま出力されます。
7daysToDieのマルチサーバでSAVEデータを定期的にバックアップを取得する（Conoha for Games）

# はじめに
Conoha for Gamesで7daysToDieのマルチサーバを立てて遊んでいるのですが、SAVEデータをバックアップ取っていないことに不安を覚えたのでその対応をした備忘録です。

# やったこと

### 0. 要件
- 1日1回AM9時にSAVEデータをバックアップすること
- バックアップファイルは10世代残して削除すること


### 1. バックアップスクリプトの作成
まず、バックアップ処理を行うスクリプトを作成します。
以下のスクリプトを`/opt/backup_script.sh`というファイルに保存します。

```bash
#!/bin/bash

# バックアップの保存先ディレクトリ
BACKUP_DIR="/opt/backup"

# アーカイブするディレクトリ
SOURCE_DIR="/home/sdtd/.local/share/7DaysToDie/Saves/"

# 現在の日付を取得
DATE=$(date +"%Y%m%d")

# アーカイブのファイル名
ARCHIVE_NAME="backup_$DATE.tar.gz"

# アーカイブの作成
tar -czf $BACKUP_DIR/$ARCHIVE_NAME -C $SOURCE_DIR .

# 最大10世代分のアーカイブを残し、それ以上古いものを削除
cd $BACKUP_DIR
ls -t | grep 'backup_.*\.tar\.gz' | sed -e '1,10d' | xargs -d '\n' rm -f
```

### 2. スクリプトの実行権限を付与
スクリプトに実行権限を付与します。

```bash
sudo chmod +x /opt/backup_script.sh
```

### 3. cronジョブの設定
次に、毎日AM9時にこのスクリプトが実行されるようにcronジョブを設定します。

```bash
sudo crontab -e
```

以下の行を追加して保存します。

```bash
0 9 * * * /opt/backup_script.sh
```

### 4. 設定の確認
設定が正しく行われたかを確認するため、次のコマンドでcronジョブが設定されているか確認します。

```bash
sudo crontab -l
```

以上で、毎日AM9時に指定されたディレクトリのバックアップが`/opt/backup`に作成され、10世代分のアーカイブが保持されるようになります。

# 最後に
バックアップとってない！と思い立ってChatGPT先生に全て作ってもらったのでリアル5分で完了しました。時代ですね。ありがたい。（この記事もほとんどChatGPTのアウトプットを張り付けただけです）
GitHub Actions Importerインストール時、 "gh-actions-importer unsupported for linux-arm64. "エラーが出た際の対処法

GitHub Actions Importerを使い、CircleCIからGitHub Actionsへの移行を行っていた際に発生したエラーと解決の備忘録。

# 環境
- M1 Mac
- Docker(ubuntu)

# エラー発生状況
下記を参考にし、GitHub Actions Importerを用いて『CI/CDをCircleCIからGitHub Actionsへの移行』を行なっていた。

https://docs.github.com/ja/actions/migrating-to-github-actions/using-github-actions-importer-to-automate-migrations/migrating-from-circleci-with-github-actions-importer


その際、下記のコマンドを使用してGitHub CLI拡張機能の『GitHub Actions Importer』をインストールしようとしていた際にエラーが発生。

```tex
gh extension install github/gh-actions-importer
```

※以下、発生したエラー。

```
gh extension install github/gh-actions-importer gh-actions-importer unsupported for linux-arm64. Open an issue: `gh issue create -R github/gh-actions-importer -t'Support linux-arm64'`
```


# 解説
このエラーは『GitHub Actions Importerがlinux-arm64をサポートしていないよ』というもの。

私が使っていたMacがM1(arm64)だったために発生した。

※下記コマンドでCPUアーキテクチャを確認可能。

```
uname -m
```

# 解決
Dockerにて、PCとは別のCPUアーキテクチャを指定し立ち上げてやることで解決。

以下、使用したDockerベースイメージ。
```Dockerfile
FROM --platform=linux/amd64 ubuntu:22.04 AS base
```

※```--platform```でCPUアーキテクチャを指定してあげないと、デフォルトでは buildを実行するPCのアーキテクチャでビルドされてしまうので注意。


# 参考
https://www.famlog.jp/article/4127

https://qiita.com/sakai00kou/items/b83994c97d8d970a7d5b
【アップデート】Control Towerでバージョン選択が可能になりました

こんばんは。Koderaです。

Control Towerからランディングゾーンのバージョンが選べるようになりました。
https://aws.amazon.com/about-aws/whats-new/2024/08/aws-control-tower-landing-zone-version-selection/

## アップデート内容
ランディング ゾーンの更新、リセット、またはアップグレード操作時にバージョンを選べるようになりました。
ランディング ゾーン バージョン 3.1 以降が対象です。現在のバージョンでランディング ゾーンをインプレースで更新またはリセットしたり、選択したバージョンへアップグレードできるようになりました。

## アップデートのメリット
Control Towerはマルチアカウント管理に必須のサービスで使われている方多いかと思います。
本アップデートのメリットはなんといっても、ランディング ゾーンのバージョンを事前に評価しやすくなり、アップデート計画を立てやすくなることですよね。

## Control Towerをセットアップしてみる
(1) 「ランディングゾーンの設定」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858908/30ad8852-c5cd-d2f7-ce48-f87e83905031.png)

(2) 料金の確認とリージョンの選択をします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858908/c35c25e0-bf64-5077-7953-62664ecea56e.png)

(3) ホームリージョンを設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858908/f4f74b7f-9cf7-596c-6092-e3c86363723a.png)

(4) ホームリージョン以外のガバナンス対象とする追加リージョンを選びます。
デフォルトはホームリージョンにしかチェックがついていないので、有効化したいリージョンへチェックします。
※(2/29）になっているのは、東京リージョンにチェックを入れています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858908/4348cf01-5f3b-5b42-88bb-755ea791fe57.png)

(5) リージョン拒否設定を行い、「次へ」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858908/62fdbf05-e0af-746f-15a4-2d88a590240c.png)

(6) OUの設定を行います。ここではデフォルトのままとします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858908/e89d0458-f1db-4973-2205-6044add06520.png)

(7) ログアーカイブアカウントと監査アカウントを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858908/a9e0ebec-721a-ab60-6361-71fbada96a21.png)

(8) その他の設定を行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858908/eb9f84b8-3799-3c81-5cb1-9b00257bcb94.png)

ここではオプション設定はなしで「次へ」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858908/30b05d98-653d-bd36-b4d8-39a12622e221.png)

(9) 「ランディングゾーンの設定」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858908/86879253-9b1e-c911-13cf-508be658d549.png)

(10) ランディングゾーン設定中です。最初は作成完了までに60分と表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858908/ec653637-9dce-3a59-a676-9fa7f7872c19.png)

(11) 設定完了しました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858908/c38e09ff-ba45-1ce6-fbef-6d1b277fd3b0.png)


## バージョンを確認してみる
(1) ランディングゾーンのバージョンを確認するには、AWSマネジメントコンソールより、「ランディングゾーン設定」から現在のバージョンが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3858908/0f0950f3-6dfb-e557-b15e-86ae47eb71cc.png)

(2) 初期セットアップした環境なので、2023年12月にリリースされた3.3が適用されていました。
ランディングゾーンをリセットしても、ランディングゾーンバージョンは更新されません。


ということで、アップデートそのものの確認はできなかったのですが、次3.4バージョンがでたときに試してみたいと思います。