OmniAICreator/Qiita-1.07M huggingface dataset:
EC-CUBE4 form_widget の内容を特定の項目だけ変更する方法

## はじめに

OneToMany な関係の CollectionType のフォームを作るとき、 `form_widget(form.productItems.vars.prototype)` としたときの内容を変更する方法になります。
※ EC-CUBE 特有の機能ではなく、Symfony の機能です。


## 方法

`{% form_theme form _self %}` が重要です。
これがなければ、次に紹介するブロックを定義しても反映されません。

※ すでに `form_theme` が設定済みの場合は、後ろに追加します。
　管理画面：`{% form_theme form '@admin/Form/bootstrap_4_horizontal_layout.html.twig' _self %}`
　フロント：`{% form_theme form 'Form/form_div_layout.twig' _self %}`

### 通常

次に、`_formname_fieldname_widget` ブロックを用意します。
ブロック名は、ルールがあります。

`EntryType` という名前のフォームに、 `sex` というフィールドがある場合は `_entry_sex_widget` というブロック名になります。

```twig
{% form_theme form _self %}
{% block _formname_fieldname_widget %}
    {%- for choice in choices -%}
        <label>
            <input type="radio" name="{{ full_name }}" id="{{ id }}_{{ loop.index }}" value="{{ choice.value  }}" {% if data and data.id == choice.value %}checked="checked"{% endif %}>
            {{- choice.label -}}
        </label>
    {%- endfor -%}
{% endblock %}
```

※ フォーム部品の `name` 属性を確認して、 `entry[sex]` のようになっていれば上記の方法でカスタマイズできますが
　`sex` となっている場合は、フォーム名が出ていない状態なので、 `_fieldname_widget` というブロック名になります。

### コレクションフィールドの場合

次に、`_formname_fieldname_entry_widget` ブロックを用意します。
ブロック名は、ルールがあります。

`ProductType` という名前のフォームに、 `productItems` という CollectionType のフィールドがある場合は `_product_product_items_entry_widget` というブロック名になります。

```twig
{% form_theme form _self %}
{% block _formname_fieldname_entry_widget %}
    <div>
        <div>
            {{ form_widget(form.name) }}
            {{ form_widget(form.content) }}
        </div>
        <div>
            <button type="button" data-index="{{ name }}">削除</button>
        </div>
    </div>
{% endblock %}
```


ほかにも色々あるので、[公式ドキュメント](https://symfony.com/doc/4.4/form/form_themes.html#form-custom-prototype)を参照ください。
【Python】型ヒントの書き方

Pythonにおいて、Python3.6で追加された型ヒントの書き方をメモしておく。
型ヒントとは、アノテーションを使用して、変数や関数の引数、戻り値などに用いる型を記述すること。

# 型ヒントの書き方
## 変数

```python
<変数名>: <型名> = <値>
# 例
value: int = 10
```
上記のように変数の初期化をしなくても問題ないが、初期化せず変数を使用すると```NameError```が発生する。

## 関数
関数の引数と戻り値の型ヒントの書き方は以下となる。

```python
def <関数名>(<引数名>: <型名>) -> <戻り値の型>:
    #処理内容
# 例
def my_func(value: int) -> int:
    #処理内容
```
もし返り値のない関数の場合は、戻り値の型に```None```を指定する。

## リストと辞書
Python3.9以降でのリストと辞書の型ヒントの書き方は以下となる。
（Python3.8以前は、リストや辞書の要素の型ヒントを記述する場合は、```typing```モジュールをインポートする必要があった。）

```python
# リスト
list[<型名>]
# 例
list[int]

#辞書
values: Dict[<型名>, <型名>]
# 例
values: dict[str, int]
```
Transaction Isolation(トランザクションの分離)


---

# トランザクションの分離とは
##トランザクションとは
1つの作業単位として扱う一連の操作の集まりです。
トランザクション内の操作が全て実行されるか、または全て実行されないことを保証してくれます


## 分離性 (Isolation)
トランザクション中に行われる操作は他のトランザクションに影響を与えない性質です。つまり、それぞれのトランザクションは分離された状態で操作を行わなければなりません。

---

# トランザクションのレベル

## 標準SQL
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318767/98f54119-e778-e10b-38e9-a0b246d25fb1.png)


## Pogresql (v12)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318767/63ed97b3-6b43-f5f0-d038-ade29b95ee9e.png)

---
# リードアンコミッティド
## 分離性
- 他のトランザクションのアンコミッティドのものもう収集されます

## 問題
- トランザクションA: レコードAをテーブルに追加
- トランザクションB: テーブルにSELECTする　→　レコードAが出ます
- トランザクションA: RollBackする 
- トランザクションBの方はレコードA取れましたが、レコードAがDBに入らなかった　→　ダーティリード
- 
---
# リードコミッティド
## 分離性
- PostgreSQLではリードコミッティドがデフォルトの分離レベルです
- 他のトランザクションのまだコミットされていないデータは取得しません。

## 問題
- すでにテブールにレコードAがあります。
- トランザクションA: レコードAをレコードBに更新します。
- トランザクションB: テーブルにまたSELECTする　→　レコードAが出ます（レコードBが出ません） 
- トランザクションA: COMMITする 
- トランザクションB: テーブルにまたSELECTする　→　レコードBが出ます（レコードAが出ません） 
- トランザクションBは２回同じクエリー実行しましたが、結果が違います。 →　反復不能読み取り
---
## 注意
- PostgreSQLの場合、リードアンコミッティドが存在しません。
- 理由はPostgreSQLはMulti-version concurrency controlを使っています。（詳しくはまだ分かりません）
---
# リピータブルリード
## 分離性
- リードコミッティドと同じですが、トランザクション内で同じクエリー実行するといつも同じ結果になります。

## 問題
- すでにテブールにレコードAとレコードBがあります。
- トランザクションA: テーブルの全部のレコードをカウントします。　→　結果は2になります。
- トランザクションB: テーブルにレコードCを追加します。
- トランザクションB: Commitします。
- トランザクションA: テーブルの全部のレコードをカウントします。　→　結果は2になります。
- レコードCが追加されましたが、トランザクションAの結果は3じゃなく、2になります。　→　ファントムリード

---

# シリアライザブル
## 分離性
- 最も厳しいトランザクションの分離性
- トランザクションが同時にではなく、次から次へと、あたかも順に実行されます。

---




# 参考
https://www.postgresql.jp/document/13.0/html/transaction-iso.html
MySQLでカンマ区切りにされた文字列の中から特定の値を取り出す

以下のように、一つのカラムの中にカンマ区切りで複数の値が入っていて、例えば二つ目の値だけ取り出したいとき

```sql
+-------------+
| data        |
+-------------+
| aaa,bbb,ccc |
+-------------+

↓

+--------+
| data_2 |
+--------+
| bbb    |
+--------+
```

こうする

```sql
SELECT
  SUBSTRING_INDEX(SUBSTRING_INDEX(data, ",", 2), ",", -1) AS data_2
FROM
  my_table_name;
```

ただし、↑の方法だと、区切り文字(カンマ)がないとそのまま値を返すので、バグの元になる

```sql
+-------------+
| data        |
+-------------+
| aaa,bbb,ccc |
| xxx         |
+-------------+

↓

+--------+
| data_2 |
+--------+
| bbb    |
| xxx    |
+--------+
```

区切り文字がない場合はNULLを返すようにするには、こうする

```sql
SELECT
  IF(LOCATE(",", data) > 0,
    SUBSTRING_INDEX(SUBSTRING_INDEX(data, ",", 2), ",", -1),
    NULL
  ) AS data_2
FROM
  my_table_name;
```

```sql
+-------------+
| data        |
+-------------+
| aaa,bbb,ccc |
| xxx         |
+-------------+

↓

+--------+
| data_2 |
+--------+
| bbb    |
| NULL   |
+--------+
```

区切り文字があったりなかったりする区切られた中の一つ目を抽出する場合はこんな感じ


```sql
SELECT
  IF(LOCATE(",", data) > 0,
    SUBSTRING_INDEX(SUBSTRING_INDEX(data, ",", 1), ",", -1),
    data
  ) AS data_1
FROM
  my_table_name;
```

```sql
+-------------+
| data        |
+-------------+
| aaa,bbb,ccc |
| xxx         |
+-------------+

↓

+--------+
| data_1 |
+--------+
| aaa    |
| xxx    |
+--------+
```

かしこ。
DBで楽観排他の設計の考え方と実装方法。

#　開発環境

Postgres
Springフレームワーク
Java

# 排他制御が必要になった背景

仕事で初めてデータアクセスの設計を行う事になり、
複数の人がアクセスする可能性のあるテーブルで排他制御が必要になった。

排他制御って基本情報の勉強で少し勉強したくらいなので
実際どう実装するのか調べてみた。


# 楽観的ロックと悲観的ロック

簡単に言うと楽観的の方だと完全には排他ロックできないこともある、と言うことらしい。
複数人で同じデータを編集する場合、同時にそのデータを更新することがある。
この場合ロックの判定が行えないということだった。

悲観ロックの場合、ある人が編集したいデータを取得した時点でロックをかけるので、
同時に更新してしまう心配がない。
だがブラウザを閉じてしまったなどのプログラム的にイレギュラーな操作が起きた場合、
ロックがされたままの状態となり、他の人が編集できなくなるということも起こり得る。

https://qiita.com/NagaokaKenichi/items/73040df85b7bd4e9ecfc

# 今回のプロジェクトではどちらを採用したか

開発コストの面からか楽観ロックを採用することとなった。
複数人で編集の可能性があるといえど、編集者が十数人規模であるため。

# 実装方法

最初の段階では、更新を行うデータが取得したデータと相違ないことを確かめるための属性（カラム）は
レコードの更新日時に設定する事になっていた。

排他制御の議論を進めるにつれ、レコードに比較するための属性を持たせると
削除処理のために複雑な設計にしないといけないことがわかり、
（レコード削除の削除日時を比較するためのレコードが必要）

比較の為の属性は別のテーブルに持たせるという事になった。
Laravel リレーションテーブルの複数の列に対して、複数キーワードでAND検索をする方法

### やりたいこと
* Laravelアプリでkeywordによるフィルタ検索をしたい。
* keywordは複数入力可能で、AND検索とする。
* 検索対象の列は、親テーブルの列+子テーブルの列とする。
* keywordに半角スペースが含まれないものとする。

⇒keyword検索自体はWEBで調べると出てきますが、複数keywordかつリレーションテーブルレコードの検索パターンが載ってませんでしたので、いろいろ組み合わせてどうにか実装できました。

### 検索例
・parentsテーブル [ parent_id, parent_text ]
・childlenテーブル [ child_id, parent_id(外部キー), child_text ]

| parent_text | child_text | keyword1 | keyword2 | Hit | 
|:-:|:-:|:-:|:-:|:-:|
|  おはよう |  こんにちは | おは  | にちは | 〇 |
|  おはよう |  こんにちは | おは  | よう | 〇 |
|  おはよう |  こんにちは |  こん | にちは| 〇| 
|  おはよう |  こんにちは | おは  | ばんは | × |

### ソースコード

```php
use Illuminate\Support\Facades\DB;

$keywordList = ["おは", "にちは"];
$result = DB::table('parents')
    ->join('children', 'parents.parent_id', 'children.parent_id')
    ->where(function($query) use($keywordList){
        foreach ($keywordList as $keyword) {
            $query->where(DB::raw('CONCAT(parents.parent_text, " ", children.child_text)'), 'like', '%'.$keyword.'%');
        }
    });
var_dump($result->toSql()); // SQL文確認
$records = $result->get();
```
LaravelでDB操作する場合、クエリビルダかEloquentを使用しますが、Eloquentだけでは細かいSQL生成ができないため、クエリビルダを使用しました。

### 生成されたSQL

```sql
select * from parents
inner join children parents.parent_id = children.parent_id 
where (
    CONCAT(parents.parent_text, " ", children.child_text) like ? and
    CONCAT(parents.parent_text, " ", children.child_text) like ?
);
```

?には検索キーワードが入ります。CONCATで検索対象の文字列を半角スペースを挟んで結合しています。これでどちらの列にキーワードが入っていても検索に引っかかるようになります。

### 結果をEloquent形式にしたい場合
・クエリビルダとEloquentでは、getしたオブジェクトの構造に若干の違いがありview表示側で修正がいる。
・クエリビルダではリレーションテーブルがたくさんあるとjoin文の記述が面倒。
などの理由から、Eloquent形式で取得したい。

```php
use Illuminate\Support\Facades\DB;
use App\Parent; // Eloquent用モデル

/*
$keywordList = ["おは", "にちは"];
$result = DB::table('parents')
    -> ・・・
省略
*/

// クエリビルダの検索結果からparent_id列のみ取得
$parentIds = $result->pluck('parents.parent_id');

// Eloquentでレコード取得
$parents = Parent::with('child'); 

// Eloquentレコードをクエリビルダの検索結果IDでフィルタリング
$records = $parents->whereIn('parent_id', $parentIds)->get();
```

クエリビルダの検索結果の主キーリストをEloquentで検索しています。

### 最後に
クエリビルダを使用せずにEloquentだけで実装する方法がもしかしたらあるかもしれません。
new TextEncoder() するのは最初の1回だけでいい件


`TextEncoder`や`TextDecoder`は、Uint8Arrayと文字列を相互に変換するAPIです。crypto周りのコードでよく使われています。しかし、書き方によってはパフォーマンスが低下する可能性があります。

## `new TextEncoder()`や`new TextDecoder()`を呼び出すタイミング

以下は文字列をUint8Arrayに変換し、SHA-256でハッシュ化する関数です。

```ts:よくあるパターン
import * as hex from "https://deno.land/std@0.122.0/encoding/hex.ts";

/** SHA-256を使用して文字列をハッシュ化する関数 */
export async function hash(message: string) {
  // 関数が呼び出されるたびに毎回`new TextEncoder()`されている
  const encoded = new TextEncoder().encode(message);
  const hashBuffer = await crypto.subtle.digest("SHA-256", encoded);
  return new TextDecoder().decode(hex.encode(new Uint8Array(hashBuffer)));
}
```

一見すると問題ないように見えますが、このコードでは関数が呼び出されるたびに毎回`TextEncoder`や`TextDecoder`のインスタンスが生成されているため、処理が冗長になっています。

パフォーマンスの観点からは、**`TextEncoder`や`TextDecoder`のインスタンス生成は関数の外で一回だけ行う**のが正解です。

```ts
import * as hex from "https://deno.land/std@0.122.0/encoding/hex.ts";

// 関数の外側で先にインスタンス生成しておく
const encoder = new TextEncoder();
const decoder = new TextDecoder();
/** SHA-256を使用して文字列をハッシュ化する関数 */
export async function hash(message: string) {
  const encoded = encoder.encode(message);
  const hashBuffer = await crypto.subtle.digest("SHA-256", encoded);
  return decoder.decode(hex.encode(new Uint8Array(hashBuffer)));
}
```

## どれくらいパフォーマンスが向上するのか

ベンチマークを取ってみましょう。ベンチマークには https://jsbench.me/ を使用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678625/0018fb23-41bb-d0cf-071e-97ec001e243e.png)

```:結果
毎回インスタンス生成する場合：33.12 ops/s ± 3.24%
先にインスタンス生成する場合：48.21 ops/s ± 1.5%
```

というわけで、`TextEncoder`や`TextDecoder`のインスタンスを**関数の外側で先に生成する場合は、約35%高速**という結果が得られました。

## まとめ

- `new TextEncoder()`や`new TextDecoder()`を関数の中で呼び出すと遅い
- 関数の外で呼び出せば、約35%高速化できる
Photonを利用したオンラインゲーム開発

PhotonはUnity公式が提供しているオンラインゲーム開発プラットフォームです。
Photon Cloudというサーバーを用います。同時接続20人まで無料で利用できます。
別枠で大人数で利用可能な有料プランも用意されています。

Photonの利用手順を解説します。

#photonのアカウント登録
Photonを利用するのにアカウント登録を最初にしておく必要があります。

https://www.photonengine.com/ja/


作成した後はダッシュボードに移るので、アプリケーションの作成をします。

![photon1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2143773/10ceabc5-9a60-9037-2fbc-f845e26d0574.png)

Ｐhotonの種別は [Photon PUN]を選択してください

アプリケーション名は自身が決めた名前を入れてください。

アプリケーションの説明は必須ではないので今回はなしとします。

URLは必須ではないので今回はなしとします。

[作成する]ボタンを押して作成してください。


![photon2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2143773/cfbd7e90-a03a-c6bf-a150-f1728cf3c30d.png)

アプリケーションIDを選択してコピーしてください。

このあとUnityを開いてphotonをインポートします。その際に必要になります。


#Unityを開いてアプリ作成

Unity Hubから3Dアプリケーションを作成します。

![photon4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2143773/eeaa71ff-6d16-8651-2ecc-bb2e5c2401c0.png)


3Dアプリを選択してください。

プロジェクト名を入力してください。

保存先を自分が分かる場所に指定してください。

プロジェクトを作成できたら エディタのメニューから Window > Asset storeをクリックして　アセットストアを開いてください。

[Photon 2]と検索してください。


https://assetstore.unity.com/packages/tools/network/pun-2-free-119922

PUN 2 FREE　を選択してダウンロードしてください。

Window > Package Managerをクリックすると　ダウンロードしたアセットを一覧で表示できます。

![photon5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2143773/6306967d-7d9a-c2ac-7727-d04aa22cf0b6.png)


インポートをクリックしてください。


#photonのアプリケーション設定

photonにさきほど作成したアプリのIDを入力します。
そうすることでphotonが利用できるようになります。

Projectビューから　Photon > PhotonUnityNetworking > Resource　とフォルダを開いていくとPhoton Server Setttingファイルがあるので選択します。
そうするとInspector ビューに内容が表示されます。

![photon6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2143773/63c390b2-1d91-156b-1283-b81b4b718b87.png)

App id PUNの欄に先ほどコピーしたアプリケーションIDを入力してください。

これでphotonが利用できるようになります。


#photonを利用して開発したアプリ
実際にphotonを導入してロビー画面(タイトル、ログイン、部屋作成、メンバーが集まればゲームスタート)とゲーム画面を紹介します。
VRゲームとしてアプリをビルドしています。　VR端末はOculusを対象としています。


![titlePanel1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2143773/8596f9be-c787-91d5-1ae3-8266598b4754.png)

VR太鼓アプリのロビー画面です。
ログインしてホストが部屋を作成します。
他のメンバーが作成された部屋に入ります。
このアプリでは2人のオンラインゲームにしてあります。


![gameRoom1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2143773/a6155efe-6512-ecb8-4626-0c0031f53aef.png)

ゲームをスタートすると目の前に太鼓(円柱オブジェクト)とバチが2本用意してあってOculusハンドを使ってバチを持てます。

太鼓に当たると音が鳴ります。


#まとめ
Photonについての概要と使い方を説明しました。
実際にPhotonを用いたVRゲームの紹介をしました。


#案件募集
チームでUnityアプリ開発やWebアプリケーション開発を承っております。
プロトタイプ製作や技術検証なども対応いたしますので、エンジニアをお探しの方は是非ご相談ください。
Oculus Quest ( Meta Quest ) 向け、スマホ向け、PCのメタバースなどのご相談もお待ちしております。
問い合わせ先はコチラです！
https://forms.gle/Zqu4TKZgx1Vd3Xtm6
[py2rb] itemgetter

# はじめに
移植やってます。
( from python 3.7 to ruby 2.7 )
# itemgetter (Python)
```python
def itemgetter(*items):
    if len(items) == 1:
        item = items[0]
        def g(obj):
            return obj[item]
    else:
        def g(obj):
            return tuple(obj[item] for item in items)
    return g

>>> itemgetter(1)('ABCDEFG')
'B'
>>> itemgetter(1,3,5)('ABCDEFG')
('B', 'D', 'F')
>>> itemgetter(slice(2,None))('ABCDEFG')
'CDEFG'
>>> soldier = dict(rank='captain', name='dotterbart')
>>> itemgetter('rank')(soldier)
'captain'
```
https://docs.python.org/ja/3.7/library/operator.html#operator.itemgetter

便利なのかも。
# def (Ruby)
```ruby
def itemgetter(obj, *items)
  if items.size == 1
    item = items[0]
    def g(obj, *items)
      item = items[0]
      return obj[item]
    end
  else
    def g(obj, *items)
      return items.map{ |item| obj[item] }
    end
  end
  return g(obj, *items)
end

p itemgetter('ABCDEFG', 1)
p itemgetter('ABCDEFG', 1, 3, 5)
p itemgetter('ABCDEFG', 2..)
soldier = {'rank' => 'captain', 'name' => 'dotterbart'}
p itemgetter(soldier, 'rank')

# output
"B"
["B", "D", "F"]
"CDEFG"        
"captain"  
```
引数の順番を合わせるようにブロックを使用した方がかっこいいかもしれないのですが。
# lambda (Ruby)
```ruby
ig1 = lambda { |x| x[1] }
ig2 = lambda { |x| [1, 2, 3].map{ x[_1] } }
ig3 = lambda { |x| (2..x.size.pred).map{ x[_1] }.join('') }
soldier = {'rank' => 'captain', 'name' => 'dotterbart'}
ig4 = lambda { |x| soldier[x] }

p ig1.call('ABCDEF')
p ig2.call('ABCDEF')
p ig3.call('ABCDEF')
p ig4.call('rank')

# output
"B"
["B", "C", "D"]
"CDEF"
"captain" 
```
一つ目の引数と二つ目の引数が同時に呼ばれない様なので、こういうのもありかも。
# class (Ruby)
```ruby
class Itemgetter
  def initialize(*items)
    if items.size == 1
      @item = items[0]
    else
      @items = items
    end
  end

  def g(obj)
    if @item
      obj[@item]
    else
      @items.map{ |item| obj[item] }
    end
  end
end

ig1 = Itemgetter.new(1)
ig2 = Itemgetter.new(1, 2, 3)
ig3 = Itemgetter.new(2..)
ig4 = Itemgetter.new('rank')

p ig1.g('ABCDEF')
p ig2.g('ABCDEF')
p ig3.g('ABCDEF')
soldier = {'rank' => 'captain', 'name' => 'dotterbart'}
p ig4.g(soldier)

# output
"B"
["B", "C", "D"]
"CDEF"
"captain" 
```
クラスの方がスッキリかな。
# メモ
+ Python の itemgetter を学習した
+ 百里を行く者は九十里を半ばとす
Github ActionsでS3でデプロイしてCloudfrontのキャッシュクリアする

### 概要

GithubActionsでよく使う処理で、
S3からデプロイして、Cloudfrontのキャッシュクリアする方法

### YAML

```yaml
name: xxxxx.com deploy

### タグ付けしたときにデプロイする
on:
  push:
    branches-ignore:
      - '**'
    tags:
      - 'v*'

### デプロイ処理
jobs:
  build:
    runs-on: ubuntu-latest
    env:
      # GithubのSecretの設定しておく
      SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
      SENTRY_PUBLISH_RELEASE: true
      SENTRY_LOG_LEVEL: DEBUG
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          # Nodeのバージョンを指定
          node-version: 'xxxxx'
          cache: yarn
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1
      - name: install
        run: yarn install
        working-directory: ./Code/yyyyy/
      - name: yarn build
        run: yarn generate
        working-directory: ./Code/yyyyy/
      - name: S3 sync
        run: aws s3 sync . s3://xxxxx.com --delete --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers --exclude "README.md"
        working-directory: ./Code/yyyyy/dist/
      - name: Clear cache in CloudFront
        uses: chetan/invalidate-cloudfront-action@v1.2
        env:
          DISTRIBUTION: ${{ secrets.DISTRIBUTION_PROD }}
          PATHS: "/*"
          AWS_REGION: ${{ secrets.AWS_REGION }}
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      - name: Notificate Slack Channel
        uses: rtCamp/action-slack-notify@v2
        if: always()
        env:
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
          SLACK_COLOR: ${{ job.status }}
          SLACK_MESSAGE: "Job Result: ${{ job.status }}"
          SLACK_TITLE: Job Result
          SLACK_USERNAME: Job Result Bot
```
Assume Roleについて（クロスアカウントアクセスの実現）

#はじめに
2022年1月より、自社開発企業にSREエンジニアとしてジョインいたしました。
初月はObservabilityの向上に関連したタスクをいくつか行っています。
そのなかで、AWSのAssumeRoleまわりで混乱したので備忘録として残しておきたいと思います。

#AssumeRoleとは
簡単に言うと、STS（Security Token Service）に対して行われるAPIアクションのことです。
最初、名前にRoleとついているだけにIAMロールの種類かと思ってしまいました。ややこしい。。。
このAPIアクションが行われることにより、既存のIAMロールを引き受ける（Assume）ことができます。

#IAM Roleの構成情報
IAM Roleを引き受けることができると書きましたが、そもそもIAM Roleを構成している情報は何でしょうか。
それは以下３つとなります。

・RoleName
・Path
・AssumeRolePolicyDocument

RoleNameはその名の通りロールの名前です。パスはロールを種類ごとにまとめたいときにディレクトリ管理できるものです。
んで、AssumeRolePolicyDocument。（最初はロール？ポリシー？ドキュメント？どれやねん。てなりました）

そもそもIAMRoleは、STSに対してAssumeRoleのアクションをする（sts:AssumeRole）ことにより使えるようになります。
これです。例えばEC2からS3へアクセスしたい場合は、EC2がsts:AssumeRoleしてS3にアクセスできるようになります。
sts:AssumeRoleは、stsに対してRoleARN（例：arn:aws:iam:123456789012:role/role-nameみたいな文字列）を渡して、
一時キーとなるCredentialsを返してもらいます。これにより、先ほどのRoleARNであるIAMロールに設定された権限が一時的に使えるようになるわけです。

ただ、このAssumeRoleがどんなユーザ/リソースからも行えてしまってはセキュリティ的に問題がありますよね。
そこで先ほどのAssumeRolePolicyDocumentにより、sts:AssumeRoleできるユーザ/リソースを指定します。

IAMロール（IAMユーザもグループも）は作成した後でIAMポリシーをアタッチすることができるので、
AssumeRoleされるIAMロールにポリシーをアタッチすることで、特定のリソースにアクセスすることができるようになります。

#クロスアカウントアクセスの実現
最後に例として、AWSとDatadogとの連携について見てみたいと思います。
AWSリソースの各種ログをFirehoseを通してDatadogへストリーミングしたり、Datadog LogsからAWS S3へログアーカイブしたい場合（要はクロスアカウントアクセスです）、sts:AssumeRoleをすることによりAWS⇆Datadogでデータをやり取りできるようになります。

Datadog logsからS3へログアーカイブしたいときのようなDatadogからAWSへの通信が発生する場合は、自分のAWS側のAssumeRolePolicyDocument内でDatadogのアカウントIDを指定します。このAssumeRolePolicyDocumentをIAMロールにアタッチすることで、DatadogとAWS間でクロスアカウントアクセスすることができます。
そして、このロールに対してS3へWriteできるポリシーをアタッチして、それをDatadog側がsts:AssumeRoleすることでS3へのアクセスが可能になります。

#最後に
AssumeRoleについて、やっと理解できました。（間違ってたら言ってください）
（違う問題でTerraformでどう記述するのかみたいなところも課題ではありますが、、、）
今後もAWS、Terraformまわりでログを残しておきたいなあと思ったら投稿したいと思います。

PS）Kubernetesやってるけど、コンポーネントが多すぎる。。。
バブルソート関数について

#この記事を書いた理由
ソート関数を使わずに配列の要素を昇順、または降順に並べ替える関数をつくる際、
「バブルソート関数」というロジックがとてもクレバーだったので備忘録として残しておく。

#コード
```main.php
<?php

$arr = [5,6,1,2];


function customSort($arr){
    
    for($n = 0; $n < count($arr)-1; $n++) {
    
        for($i = 0; $i < count($arr)-1; $i++) {
            
            if($arr[$i] < $arr[$i+1]) {
            $tmp = $arr[$i+1];
            $arr[$i+1] = $arr[$i];
            $arr[$i] = $tmp;
            }

        }
    }
    return $arr;
}

$arr2 = customSort($arr);
var_dump($arr2);
//[1,2,5,6];

?>
```

#解説
全ての要素に関して、隣接する要素と比較し順序が逆であれば入れ替える。これを要素数-1回繰り返すことでソートを行う。なおこの繰り返しは、入れ替えが起こらなくなった時点で（それ以降は何度繰り返しても変化が起こらなくなるので）中断することができる。(Wikipediaより)

```main.php
            if($arr[$i] < $arr[$i+1]) {
            $tmp = $arr[$i+1];
            $arr[$i+1] = $arr[$i];
            $arr[$i] = $tmp;
            }
```



for文の中で実行されている要素とその次の要素と比較して順番が逆だった場合、
$tmpという変数にその次の要素を格納する。
3行目の$arr[$i+1]の配列インデックスが[$i](現在のインデックス)になり、
$arr[$i]が$tmpに格納されていた$arr[$i+1]になるため、
要素の順番の入れ替えが実現できる。

#補足
wikipediaにバブルソートのアルゴリズムを視覚的に表した図がめちゃめちゃ分かりやすいのでリンクを貼っておきます。
[バブルソート出典: フリー百科事典『ウィキペディア（Wikipedia）』](https://ja.wikipedia.org/wiki/%E3%83%90%E3%83%96%E3%83%AB%E3%82%BD%E3%83%BC%E3%83%88)
#Slack で使える #Twitter クローンアプリを作ってリリースした話

先日こんな投稿が #Slack からありました。

https://qiita.com/hello_jun/items/4d420e866a8099a43829

なにか作ろうかなと思っていたのですが、これを期に前々から考えていたTwitterクローンを作ることに決めました。
インストールはこちら：https://slaim.lne.st/slack/install
アプリ名はSlaIMです。Slack専用のインスタントメッセージサービスということで、SlaIMと名付けました。

## 技術
私のQiita記事に何度も出てきていますが、Slackアプリ自体はSlack Bolt for Pythonを基盤にしています。
テンプレはこちらの記事においてあるのでHerokuにデプロイする形ですぐにSlackアプリ開発ができるようになっています。

https://qiita.com/geeorgey/items/ca2942ff054e30587c78

## 画面構成
![Slack___SlaIM___Leave_a_Nest_Co__ltd_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22294/453d00be-f4be-705e-3567-3bf34aa039e0.png)

## 機能面
Twitter同様にpostしたものがタイムラインに流れる機能になってます。
ユーザーのフォローが出来て、フォローしている人のみのタイムラインを見る or 全ての投稿を見るかを選べます。
リプのみ、自分がFavしたもののみを見ることができるとか
文字列検索で投稿やユーザーを検索することが出来ます。
![Slack___SlaIM___Leave_a_Nest_Co__ltd____1_個の新しいアイテム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22294/38358349-f66e-cbb3-74a8-35c0e5c31a53.png)

投稿されたpostは返信/シェア(いわゆるRT）/コメント付きシェアが出来ます。
![Slack___SlaIM___Leave_a_Nest_Co__ltd____1_個の新しいアイテム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22294/e2687fb1-2bb8-26b7-66a5-8ac0138be592.png)

返信が入るとDMに通知が入ります
![Slack___SlaIM___Leave_a_Nest_Co__ltd____1_個の新しいアイテム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22294/667ee36f-e4bd-9d4b-cc0e-a34b11851cf9.png)

ハッシュタグを入れると、このような形でメッセージ詳細画面からハッシュタグ関連postを取得することが出来ます。
![Slack___SlaIM___Leave_a_Nest_Co__ltd____1_個の新しいアイテム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22294/c5f71d72-2b98-d024-4a22-84473cb7d82b.png)

みたいな形で、ざっくりとTwitterの機能面をクローンしてみました。

## 工夫した点
投稿は、SlaIMアプリのDM欄からメッセージ投稿することで行います。
![Slack___SlaIM___Leave_a_Nest_Co__ltd____1_個の新しいアイテム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22294/fe6b10dd-2016-ad66-51cf-88cff5bb0c42.png)

画像投稿もできるようになっています。

### Slackアプリからは画像等のファイルアップロードは出来ない
入力フォームに画像アップロード用の機能を実装することは出来ません。
ファイルURLを記入してそこからファイルを取得しにいってアップするというのは可能ですが、ユーザビリティ的には無理筋でしょう。
そのため、今回はDMに添付された画像をDLし、Pythonのboto3を使ってAWS S3にアップするようなフローにしました。
アップロード時に取得したURLを、Block Kitのimageブロックを使って表示しています。

![Slack___SlaIM___Leave_a_Nest_Co__ltd____1_個の新しいアイテム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22294/5980b250-359f-74b5-7e64-cdbd5f38caaf.png)

### 通知系が実は重要な気がする
メンション時にはDM通知が入るようにしてあるのですが、例えばフォロー時とかRTといったタイミングでも通知を入れたほうがそれっぽくなるような気がします。これについては今後の実装ということで。

実際に作ってみると、Twitterも色々な工夫がされているなと感じます。
今後もアプデしていきますので、よろしければインストールして使ってみてください。

インストールはこちら：https://slaim.lne.st/slack/install

## 最後の砦
ハッカソンには動画エントリーが必要なんだけど、これを作るのが大変ですよね・・・

## 既存の課題
・アプリを再インストールすると、SlaIMユーザーとの紐付けが解除されてしまい、既存ユーザーと紐付ける仕組みがない
・リプライ画面から画像を追加することが出来ないのをどうしようかは今の所解がない
・フォロー/フォロワー画面が無い
【tinyUDP™】UDPをもっと簡単に使える Arduino Library な話

#1. はじめに
WEBを探しまくっても確かにUDPの良い例(分かりやすい例)がありませんが
きっとUDPを扱える方々は ササっとこの辺りは組んでしまうのでわと思われます
昨今のブームで大量のデータ転送(100KByteほど)やそのやりとりを簡単な登録済ライブラリとして作成してみました
空いた時間は LogicやUI の強化に回して頂ければと考えております

https://github.com/chrmlinux/tinyUDP

* まだまだ皆さまの pull request には追い付かないと思われますが　よろしくお願い申し上げます

#2. UDP通信の開始
UDPにて通信をする場合には単純に udp.begin(PORT) すれば良いようで

##2.1. 直書きする場合

``` 
サーバにする場合
WiFi.softAPConfig(SERVER_IP, GW_IP, SUBNET);
WiFi.softAP(ssid, pass);

クライアントにする自宅ルータに接続する場合
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, pass);
WiFi.waitForConnectResult();

で...
udp.begin(PORT);
```

##2.2. tinyUDP™の場合
```
サーバにする場合
tinyUDP tudp(TUDP_RECV);

クライアントにする場合
tinyUDP tudp(TUDP_SEND);
```
だけで完了となります
自動的に TUDP_SERVER側になった方に接続します

#3. tinyUDP™ によるデータ送受信
##3.0. 共通準備
他の library の負荷とならないようにバッファを内部的に new します

```
#define BUF_SIZE (1024 * 80)
tudp.begin(BUF_SIZE);
```

##3.1. TUDP_SEND側から巨大データを送信する場合
バッファを確保サイズを取得後
データに設定を行い転送アレイにput
tudp.send(bool) もしくは tudp.update(bool) で自動的に送信を行います

``` 
static uint8_t c = 0x0;
if (tudp.delay(10)) {                    // 大きいバッファの場合は 10Msec程 delay
  uint8_t *buf = tudp.get();             // バッファ確保
  uint32_t bufSize = tudp.getArySize();  // バッファサイズ取得
  memset(buf, c, bufSize);               // データ設定
  tudp.put(buf, bufSize);                // バッファを転送アレイにput
  Serial.printf(
　　　"send : 0x%02x, size=%d\n", 
　　　c, 
　　　bufSize);
  c = (c + 1) % 256;
  tudp.update(false);                    // 送信
}

```
##3.2. TUDP_RECV側が巨大データを受信する場合

```
if (tudp.isRecv()) {　　　　　　　　　　　  // データが来たか?
  uint8_t *buf = tudp.get();              // 受信バッファ確保
  uint32_t recvSize = tudp.getRecvSize(); // 受信バッファサイズ取得
  Serial.printf(
　　　"recv : 0x%02x, size=%d\n", 
　　　buf[0], 
　　　recvSize);
  tudp.dump(buf, 128);                    // 受信した 先頭128Byteをダンプします
}
tudp.update(false);                       // 受信
```
#4. ライブラリ化に関して
この __tinyUDP™__ を使えば他の処理のことだけを考える事が出来ますので
便利かなぁと思い無理無理ライブラリ化させて頂きました

https://www.arduinolibraries.info/authors/chrmlinux

おかげさまで 2個めのライブラリとなり
気を付けないといけない所が判って来ましたので
もう __あなたの ino ライブラリ化します__ 等々しようかなぁとか

#5. さいごに
申請にあたり 困った時の [lang-ship](https://lang-ship.com/blog/work/arduino-ide-add-library-manager/) さんのページを参考にさせて頂きました
いつもありがとうございます

皆様　末永くよろしくお願い申し上げます
Git コミットIDを使ってコミットを指定してtagを貼る

# 概要

- コミットIDを用いてコミットを指定し、tagを貼る方法をメモ的にまとめる

# 方法

- 下記のコマンドを実行すると当該ブランチの最新コミットにtagを貼ることができる。

    ```terminal
    $ git tag タグ名
    ```

- しかし、下記の様に指定することでコミットを指定してtagを貼ることができる。

    ```terminal
    $ git tag タグ名 コミットID
    ```
pythonテキスト処理問題集

pythonを勉強するにも参考書ばっかりだとモチベーションが上がらないのと、時間がちょっと空いた時にチャレンジできるような問題集を作りたいなと思って作っています。
GitHubで公開していますので初心者の方などはつかってみてください。
テキスト処理なのでpythonにかぎっているわけではないですが。

まだ１０問ぐらいしかないのですが順次足してきます。
ご協力いただける人がいらっしゃったらどんどん追加しちゃってください。
[テキスト処理問題集GitHub](https://github.com/0712kazu/ExampleCollection)
ReactのJestのテストでエラー Consider adding an error boundary to your tree to customize error handling behavior. Visit https://fb.me/react-error-boundaries to learn more about error boundaries.

#背景
Reactアプリ開発のテストをJestで実施しているのだけど、「Consider adding an error boundary to your tree to customize error handling behavior.Visit https://fb.me/react-error-boundaries to learn more about error boundaries.」というエラーに悩まされたので解決方法をまとめておく。

#開発言語 (バージョン情報)
React.js (17.0.2)
Next.js (11.1.2)
TypeScript (4.4.3)
Jest (27.2.2)

#解決策

「react-test-renderer」ではなく「Testing Library」を使用する。

```typescript:sample.spec.tsx
import React from 'react';
import App from './App';
import { render } from '@testing-library/react';

describe('test 1', () => {

  it('test case 1', () => {
    const { container } = render(<App />);
    expect(container).toMatchSnapshot();
  });

});
```


#参考

https://zenn.dev/karamem0/articles/2021_11_09_090000
sphinx: `csv-table`ディレクティブで、行ヘッダ/列ヘッダをコントールする

# 実行環境
* Python 3.9.7
* sphinx 4.4.0
    * sphinx theme: alabaster

# はじめに
sphinxの`csv-table`ディレクティブで、行ヘッダ/列ヘッダをコントールする方法をまとめました。


# 行ヘッダのコントロール

## 行ヘッダなし

```
.. csv-table:: オプションなし

   name,age
   alice,18
   bob,24
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/3cdd65ca-2910-65c7-00c9-a83ea326dc7b.png)

## 行ヘッダが1つ
`header`オプションを指定するか、`header-rows`オプションを`1`にします。

```
.. csv-table:: headerオプションを指定
   :header: name,age
   
   alice,18
   bob,24


.. csv-table:: header-rowsオプションが1
   :header-rows: 1

   name,age
   alice,18
   bob,24

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/d2414312-0f93-feb0-b24c-514f4aff2371.png)

## 行ヘッダが2つ

```
.. csv-table:: header-rowsオプションが1
   :header-rows: 2

   name,age
   alice,18
   bob,24
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/b398e294-1a2c-2a09-4a55-47bee00fb20f.png)


# 列ヘッダのコントロール

## 列ヘッダが1つ
```
.. csv-table:: stub-columns
   :stub-columns: 1

   name,age
   alice,18
   bob,24
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37903/83e005e6-5c56-4bcd-aeef-f8866c53da6a.png)
【React Native】ListItemを勉強したのでサンプルを作ってみた

# 【ReactNative】の ListItem の簡単なサンプル



## 概要

  ReactNativeのListItemを勉強したので簡単なサンプルを作成してみました。

## 実行環境

- Expo snack



## コード

```react
import React from 'react';
import { SafeAreaView, View, FlatList, StyleSheet, Text, StatusBar } from 'react-native';
import { ListItem } from 'react-native-elements';

const DATA = [
  {
    fruitName: 'れもん',
    id: 'First Item',
  },
  {
    fruitName: 'りんご',
    id: 'Second Item',
  },
  {
    fruitName: 'ぶどう',
    id: 'Third Item',
  },
  {
    fruitName: 'マンゴー',
    id: 'Third Item',
  },
  {
    fruitName: 'バナナ',
    id: 'Third Item',
  },
];


const Item = ({ fruitName }) => (
  <Text style={styles.itemTextStyle}>{fruitName}</Text>
);

const App = () => {
  return (
    <SafeAreaView style={styles.container}>
      {DATA.map((l, i) => (
        <ListItem 
          key={i}
          containerStyle={styles.itemStyle}
        >
          <ListItem.Content>
            <ListItem.Title>
              <Item fruitName ={l.fruitName} />
            </ListItem.Title>
          </ListItem.Content>
        </ListItem>
      ))}
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: StatusBar.currentHeight || 0,
    backgroundColor:'pink',
  },
  itemStyle: {
    width: '100%',
    marginTop:'10%',
    backgroundColor: '#d4ffff'
  },
  itemTextStyle: {
    backgroundColor:'#6c95ff',
    color: '#6cff90',
    textAlign:'center'
  }
})

export default App;
```

## ポイント

- DATA： LIstItemで表示するデータを準備
- ListItemタグ:  key, itemごとのstyleを設定
- ListItem.Contentタグ:  ListItem.Title , 他(ListItemSubtitle)など記述
- ListItem.Title、ListItemSubtitleタグ:  itemごとに表示する内容を記述。
例：　本記事だと「れもん」、「りんご」、「ぶどう」‥を記述しています



- ## 実行結果
![2022-01-28 13_43_49-メール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247619/02d28e1b-4cee-9606-cbda-368b4966f974.png)
はじめてのGoogle AIY Voice Kit⑤【ラズパイSSH接続編】

# はじめに
前回のラズパイセットアップ編の記事は[こちら](https://qiita.com/yuzuki6v6/items/4d57572cdd2ff806fcaf)から:information_desk_person:
今回はラズパイSSH接続編です。
いよいよラズパイをSSH接続していきます。


## ラズパイのIPアドレスを調べる
まずは、ラズパイのIPアドレスを調べます。

①ラズパイを起動し、AIY PROJECTの壁紙が表示される画面にします。
![IMG_0758.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/921847/85654bb5-f6c7-b0b2-f119-d83e4516b089.jpeg)

②画像のWi-Fiマークにマウスのカーソルを合わせます。
![img1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/921847/5a163ab2-5a08-8aba-3106-b32e7501d4c1.jpeg)

③「wlan0:Confiqured」の欄にラズパイのIPアドレスが表示されます。
![img2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/921847/353c13b0-dead-d9b9-51f2-85a29a7f25ed.png)

## SSH接続手順
Tera Termからログインできるようにします。

①Tera Termをダウンロードします。
[こちら](https://forest.watch.impress.co.jp/library/software/utf8teraterm/)からダウンロードしました。（無印版をダウンロード）

②Tera Termを起動し、ホスト欄に先程確認したラズパイのIPアドレスを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/921847/3b0867f4-1180-4e54-94fe-5e37c2ee0c60.png)

③続いて、ユーザ名とパスフレーズを入力します。
ユーザ名は【pi】、パスフレーズはラズパイセットアップの際に設定したものを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/921847/053586b9-7b20-3941-2956-333ea6692237.png)

④画像のような表示がされたら、SSH接続は完了です！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/921847/7b1fb3bc-0762-9aad-5390-ebfd3f65381f.png)

# 所感
これで環境構築が完了です。
次からは基本操作のサンプルプログラミングを実行していきます！
API返却物の日付用Deserializer

#最初に
今回は、APIの返却物でよくある日付を変換してくれるDeserializerを備忘録として残しておきます。

###コード

```kotlin:
@ExperimentalSerializationApi
@Serializer(forClass = ZonedDateTime::class)
object ZonedDateTimeSerializer : KSerializer<ZonedDateTime> {
    private val formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME

    override fun deserialize(decoder: Decoder): ZonedDateTime =
        ZonedDateTime.parse(decoder.decodeString(), formatter)

    override fun serialize(encoder: Encoder, value: ZonedDateTime) =
        encoder.encodeString(value.format(formatter))
}
```
変換用コードは上記の通りとなっています。
`String`と`ZonedDateTime`の相互変換ができる様になっています。
返却される形式としては`2017-12-04T11:00:00+09:00`です
呼び出す場合は、返却物を受け取る時のデータクラスにある要素に対して下記を設定するだけです

```kotlin:
@Serializable(with = ZonedDateTimeSerializer::class)
```

###最後に
返却物の日付をユーザー側に表示したいときなどにこちらを使用することで、表示の際の添削や加工がしやすくなります。
自由度が高いため日付だけでなく、他のクラスに変換したいときでも利用することができるので覚えておいて損はありません。
社内のスケジューラーに求める機能と組織文化の違い

国産グループウェアから Microsoft 365 に移行するとき、Outlook のスケジュール機能がしばし問題となります。国産グループウェアの多くは、部や課などの単位でメンバー全員の 1 週間分の予定をひと目で見ることができる「グループスケジューラー」を備えていることが多いです。一方の Outlook では、自分自身で予定を知りたい人を登録し、横並びや重ね合わせをして表示できる形式です。

このスケジューラーの違いが問題になることは多くありますが、以前には国産グループウェアを利用していたこともある僕自身が、この問題を実感として捉えられないのは何故だろうと不思議に思っていました。たまたまこの問題を考える機会があったのですが、もしかしたら働き方、さらには組織文化の違いがあるのではないかと思いました。

# 部内会議の予定の立てかた

例えば、部員全員に参加してほしい会議の予定を立てようとしたときに、グループスケジューラーであれば「みんが都合の良い時間はどこかな…」と探すことが出来て便利ですよね。まず僕には、このメリットが実感できませんでした。

なぜかと考えてみると、僕の周りではこうした会議の予定はあらかじめ数週間前に "誰かに" よって決められ、メンバーは、その会議に参加できるように自分の予定を調整していきます。このとき、会議の予定は月度の締めや決算、その他の状況によって決まるわけですが、各メンバーの予定はあまり重要な要因ではないように思います。

そもそも予定を立てるプロセスが違うので、求める機能も違うのだろうなと思いました。

# メンバーがそれぞれ自分のスケジュールを調整できる
なぜこのように予定を立てられるのかと考えると、ひとつはメンバー全員が自分のスケジュールを調整できる裁量が十分に与えられているからだと思いました。自分の作業時間を確保したり、社内での打合せはもちろん、顧客との打合せ日程を決めるなどして、自分のスケジュールを作るのは自分の権限です。この権限によって、重要な予定と他の予定が重ならないように調整する責任を果たすことができます。

自分ではどうにもならない要因でスケジュールが組まれてしまうような業務に携わっていると、このあたりが難しいかもしないですね。

# 全員参加の会議は全員参加が必須ではない
先ほどの例にもあったように、部内会議には部員全員が参加するのですが、全員参加が必ずしも必須ではありません。全員が参加すべき会議なのに全員参加が必ずしも必須ではないというのは論理的に少々おかしいですが、「全員が参加すべきものであるが、どうにもならない予定があった場合にはその限りではない」という感じです。

そもそも仕事をしていると、どれだけ大事な会議があったとしても、仕事でのトラブルや個人の急用など、会議に出席するどころではない用事というもの考えられます。誰も明文化したり明言したりしているわけではありませんが「会議に参加できるように最大限調整したものの、結果として会議に参加できないことはあるものだ」という考えかたが浸透している気がします。

それでも、会議のテーマに欠かせない人が欠席する場合にはリスケになります。

# その会議に絶対参加するべき人がなんとなく分かっている
先にも書いたように、会議の日程が決まってそれぞれスケジュールを調整した結果、その会議に「絶対参加するべき人」が欠席することが分かった時点でリスケされます。

「絶対参加するべき人」がなぜ分かるかというと、その会議では何が話し合われるのか、誰がその話し合いをリードするのか、誰の意見を聞きたいのか、などなどが事前に共有されているからのような気がします。

そもそも会議の日程も「近藤さんのスケジュールが空いている日はいつ？他の人はいけそう？じゃあその時間で会議にしましょう。集まれない人は仕方ないから」みたいに決まります。みんなのスケジュールが空いている日だから会議をしようということはありません。

# 会議出席依頼は辞退できる
こんな感じなので、自分ではどうしても参加できない時間に会議予定が入っていることがあります。そうした場合には、会議への参加を辞退することができます。

自分がその会議に「絶対参加するべき人」ではない場合、会議は予定通りに行われ、あとから情報を共有してもらうことになります。ちょっと寂しいですが、仕方ないです。

# オンライン会議はあとから見返すことができる
最近はオンライン会議で社内勉強会みたいなことを行う機会も増えました。こうした社内勉強会を企画するときも、トピックスを共有する人の予定を優先して日程を決め、あとは参加できる人が参加するという形になります。

近ごろは「ごめーん、参加できないから録画しておいてー」ということも増え、興味のある人があとからいつでも内容を確認することができるので、ますますトピックスを共有してくれる人の予定が優先されるようになりました。

んまあ、あとからちゃんと録画を観ているかは怪しいときもありますが…。

# 求める機能と組織文化の違い
今回の記事は、あくまでも僕個人の考え方や感じ方に基づいたものですが、そのツールに求める機能は組織文化によっても異なることが多くあるんだろうなと思いました。

これは文化の違いなので、どちらが良い悪いではありません。しかし、実装されている機能についても、それに適した組織文化というものがあるのだとすると、機能を活用するためには組織文化を変えることがあっても良いのかもなとぼんやりと思いました。

今回の例でいうと、たまたま僕の働き方やまわりの文化が Outlook のスケジュールにも適したものだったわけですね。

※そうは言っても、ずっと過去からそうした考え方だったのかは不明。Outlook（Microsoft 365）を利用し始めてから 10 年以上が経過しているわけで、使っているうちにツールに合わせて考えかたや文化が変化した可能性もある…。
パスワード入力フォーム表示・非表示

## はじめに

現在、自己学習の為、既存サイトを模倣したサイトを作成しています。
調べて実装した内容を自分なりにまとめてみました。
※参考にさせて頂いた記事・サイトは[最後](https://qiita.com/meowave/items/465fcb91a9fd06c4a8b3#%E5%8F%82%E8%80%83%E5%BC%95%E7%94%A8)に記載しております。

#### 今回の目標
目のマークを押すと表示・非表示が切り替わる パスワード入力欄の実装
![パスワード入力欄.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517694/6ce29c21-732f-645d-40a0-f51a7eeaa221.png)
色々なサイトで見かける機能ですが、今まであまり気にせず利用していました。
改めて、何故こんな機能が必要なの？？と思い調べると、パスワードは表示すべきか非表示にすべきか、過去、思った以上にたくさんの議論が交わされていた問題のようでした。知らなかった。。。
表示・非表示はどちらにもメリットとデメリットがあり、折衷案としても切り替え機能付きの入力フォームは大変良いのではと思いました。

https://www.nngroup.com/articles/stop-password-masking/


## 実装

#### 仕様の確認と指針
・表示・非表示を切り替える際、画面遷移はない。
  &emsp;&emsp;> JavaScriptを使用
・表示・非表示を切り替えるには、目のアイコンをクリックする。
  &emsp;&emsp;> 目のアイコンは [Font Awesome](https://fontawesome.com/) を使用

#### HTML

```HTML:HTML
 <form method="post" action="遷移先ページ">
    <label for="password">パスワード</label>
    <div id="inputBox">
       <input type="password" id="password" name="password">
       <span id="view">
          <!-- 目のアイコン -->
          <i class="far fa-eye-slash"></i>
       </span>
     </div>
     <button type="submit">送信</button>
 </form>
```

パスワード入力フォームを作成。
ここで作成したものが最初に表示される画面になる為、type="password" と記載、
アイコンも type="password" に対応するものを記載。

#### JavaScript

```JavaScript:js
//  id="view"を取得
let viewicon = document.getElementById('view');

//  id="password"を取得
let inputtype = document.getElementById('password');

//  id="view"クリック時の処理を設定
$('#view').on('click', function () {

       //  passwordからtextへ
       if(inputtype.type === 'password'){
              inputtype.type = 'text';
              viewicon.innerHTML = '<i class="far fa-eye"></i>';

        //  textからpasswordへ
        } else {
               inputtype.type = 'password';
               viewicon.innerHTML = '<i class="far fa-eye-slash"></i>';
        }
});
```

アイコンをクリックした際の処理内容を設定。
input type が password の時は text へ、text の時は password になるよう記載。

#### 備考

アイコンをボタンで表示させる場合は、HTMLの``span``を``button``に書き換え、フォーム送信させたくないので``type="button"``を追記。
```HTML
<button id="view" type="button"><i class="far fa-eye-slash"></i></button>
```

<!-- コメント頂いた内容で修正するため下記コメントアウト

アイコンをボタンで表示させる場合は、HTMLの該当部分をbuttonに書き換える
```HTML
<button id="view"><i class="far fa-eye-slash"></i></button>
```
だけだとフォーム送信が行われてしまうので、
```JavaScript
$('#view').on('click', function (event) {
		event.preventDefault(); 
```

JavaScriptに preventDefault(); を追記し、ボタンの既定の動作をキャンセル。

--->

## さいごに
最後までご覧頂きありがとうございます。
認識違い・間違っている箇所、より適した書き方等がございましたら、是非ご教授頂ければ幸いです。

### 参考・引用
1. 石戸康平. "パスワード入力欄でパスワード表示・非表示を切り替える". GRAYCODE. 2021-02-24. https://gray-code.com/javascript/toggles-between-showing-and-hiding-the-password/, (参照 2022-01-20)
2. @ tomokichi_ruby. "【JavaScript】innerHTM、textContentの違い". Qiita. 2019-07-16. https://qiita.com/tomokichi_ruby/items/3640f0bc64ad6c676206, (参照 2022-01-20) 
3. @ fujiyamaorange. "ボタンには常にtype="button"をつけよう". Zenn. 2023-08-08. https://zenn.dev/fujiyama/articles/496e5e81ba7df9, (参照 2025-04-11)
Date Shifting in Ruby

Rubyにおける二重山括弧「<<」「>>」についてのメモ。
（環境は Ruby 2.0.0 + Rails 4.2.4）

「<<」は文字列の場合は連結、配列の場合は追加となるが、
日付の場合、結論としては月単位の操作を行っていることがわかったが、
どういう理屈で以下の挙動をしているのかよくわからなかった。

```ruby:ruby
require 'date'

now = Time.now
puts now
#=> 2022-01-28 12:43:10 +0900

# 「<< N」で Nヵ月前
puts Date.new(now.year, now.month,  1) << 2  #=> 2021-11-01
puts Date.new(now.year, now.month, -1) << 2  #=> 2021-11-30
puts Date.new(now.year, now.month, -1) << -1 #=> 2022-02-28

# 「>> N」で Nか月後
puts Date.new(now.year, now.month, -1) >> 2 #=> 2022-03-31
puts Date.new(now.year, now.month, -1) >> 3 #=> 2022-04-30

```

（追記）
ちゃんとリファレンスマニュアルを読もう。

https://docs.ruby-lang.org/ja/latest/class/Date.html

以下引用。

#### class Date インスタンスメソッド

##### self << n -> Date
self より n ヶ月前の日付オブジェクトを返します。 n は数値でなければなりません。

```ruby
require 'date'
Date.new(2001,2,3)  <<  1   #=> #<Date: 2001-01-03 ...>
Date.new(2001,2,3)  << -2   #=> #<Date: 2001-04-03 ...>

# 対応する月に同じ日が存在しない時は、代わりにその月の末日が使われます。
Date.new(2001,3,28) << 1   #=> #<Date: 2001-02-28 ...>
Date.new(2001,3,31) << 1   #=> #<Date: 2001-02-28 ...>

# このことは以下のように、もしかすると予期しない振る舞いをするかもしれません。
Date.new(2001,3,31) << 2         #=> #<Date: 2001-01-31 ...>
Date.new(2001,3,31) << 1 << 1    #=> #<Date: 2001-01-28 ...>

Date.new(2001,3,31) << 1 << -1   #=> #<Date: 2001-03-28 ...>
```

##### self >> n -> Date
self から n ヶ月後の日付オブジェクトを返します。 n は数値でなければなりません。

```ruby
require 'date'
Date.new(2001,2,3)  >>  1   #=> #<Date: 2001-03-03 ...>
Date.new(2001,2,3)  >> -2   #=> #<Date: 2000-12-03 ...>

# 対応する月に同じ日が存在しない時は、代わりにその月の末日が使われます。
Date.new(2001,1,28) >> 1   #=> #<Date: 2001-02-28 ...>
Date.new(2001,1,31) >> 1   #=> #<Date: 2001-02-28 ...>

# このことは以下のように、もしかすると予期しない振る舞いをするかもしれません。
Date.new(2001,1,31) >> 2         #=> #<Date: 2001-03-31 ...>
Date.new(2001,1,31) >> 1 >> 1    #=> #<Date: 2001-03-28 ...>

Date.new(2001,1,31) >> 1 >> -1   #=> #<Date: 2001-01-28 ...>
```
React のライブラリのソースコードを読む時に役に立ったサイト

みなさん、React のライブラリのソースコードを読んでますか？

「そんなの難しくて読めない」と思っているあなたに朗報です。
世の中には、React のライブラリのソースコードを、短くしたコードを公開しているサイトがたくさんあります。

ここでは、そんなライブラリを短くしたコードを公開しているサイトを紹介して、皆様の React のライブラリのソースコード読みをより充実 or 始めるきっかけ作りができればと思います。

## redux

https://gist.github.com/gaearon/ffd88b0e4f00b22c3159

下の方の、createStore の部分が読んでて参考になる。


# react-redux

https://github.com/dennis-jiang/Front-End-Knowledges/tree/master/Examples/React/react-redux

まだ全部は読んでないけど、素のソースコードより短くて読みやすい。

# react-router

https://zenn.dev/stin/articles/how-to-develop-react-router

https://github.com/dennis-jiang/Front-End-Knowledges/tree/master/Examples/React/react-router-code/src/myReactRouter

1つ目はコードが分かりやすい上、日本語なので読みやすいです。
2つ目は1つ目のコードを少し難しくした部分があるので、少し読みづらいですが、読めます。

# useState

https://github.com/dennis-jiang/Front-End-Knowledges/tree/master/Examples/React/fiber-and-hooks

まだ読んでない上、とても難しそうですが、暇があれば読んでみたいです。

React 初心者でも、是非とも読んでみて、日頃使っているライブラリの理解を深めてみましょう！
Android 12でCaused by java.lang.IllegalStateException You need to use a Theme.AppCompat theme (or descendant) with this activity.

# 概要
AndroidX Core Splashscreenでスプラッシュ画面を作成するとAndroid 12端末で以下のようなクラッシュが発生することがあった。

```
Caused by java.lang.IllegalStateException You need to use a Theme.AppCompat theme (or descendant) with this activity.
```

不適切なタイミングで`installSplashScreen` を呼ぶと上記のエラーが発生することがある。

# 対策

件のクラッシュは `開発者向けオプション`で`アクティビティを保持しない`をONにしてアプリをバックグラウンドから起動すると高確率で発生する。

クラッシュの原因は `installSplashScreen` を `super.onCreate` の後に呼んでいたため。

```MainActivity.kt
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        installSplashScreen()
        ...
    }
```


`installSplashScreen` は `super.onCreate` の前で呼ぶとクラッシュは発生しなくなった。

```MainActivity.kt
    override fun onCreate(savedInstanceState: Bundle?) {
        installSplashScreen()

        super.onCreate(savedInstanceState)
        ...
    }
```

# あとがき

公式ドキュメントでは英語だと`installSplashScreen`が先だが、日本語では `onCreate`が先に書かれているので注意… :crying_cat_face: 

### 英語
![スクリーンショット 2022-01-25 13.46.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35122/37cc5266-3b42-5bef-b670-49bfdd939a09.png)

### 日本語
![スクリーンショット 2022-01-25 13.46.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35122/7634f557-9ddf-8d70-77a0-517d8254dda9.png)

# 参考
https://issuetracker.google.com/issues/207095795
https://developer.android.com/guide/topics/ui/splash-screen/migrate#migrate_your_splash_screen_implementation
Gnus で S/MIME 署名を行うための設定

Gnus で S/MIME 署名を行うためには，OpenSSL を使う方法と GnuPG（に同梱されている gpgsm コマンド）を使う方法の2通りがある．[EmacsWiki](https://www.emacswiki.org/emacs/GnusSMIME) では，まだ OpenSSL での設定方法が最初に紹介されている．しかし，`mml-smime-use` 変数のドキュメントには以下のように記載があるため，gpgsm コマンドを使う方法を検討する． 

```
If you’re thinking about using OpenSSL, please first read the BUGS section in the manual for the ‘smime’ command that comes with OpenSSL.
We recommend EasyPG.
```

最初に，クライアント証明書を import しなければならないのだが，ここでつまずく．

```shell-session
$ gpgsm -v --import keycert.p12
gpgsm: data error at "data.objectidentifier", offset 67
gpgsm: error at "bag-sequence", offset 49
gpgsm: error parsing or decrypting the PKCS#12 file
gpgsm:     処理数の合計: 0
```

[Mew のマニュアル](https://www.mew.org/ja/feature/smime.html)にしたがって，OpenSSL を使って，秘密鍵と公開鍵を個別に取り出して import せねばならないらしい．

クライアント証明書の形式をPEM形式に変換し，秘密鍵を取り出して，秘密鍵を import する．

```shell-session
$ openssl pkcs12 -in keycert.p12 -out keycert.pem -nodes
$ openssl pkcs12 -in keycert.pem -export -out key.p12 -nocerts -nodes
$ gpgsm -v --import key.p12
```

次に，公開鍵を取り出して，公開鍵を import する．

```shell-session
$ openssl pkcs12 -in keycert.p12 -out certs.pem -nokeys
$ gpgsm -v --import certs.pem
```

正常に import できていれば，以下のコマンドで確認できるはず．

```shell-session
$ gpgsm -kv
```

確認した証明書の鍵 ID を使って署名するように，以下のように設定しておく．

```emacs-lisp
(setq mml-secure-smime-signers '("XXXXXXXXX"))
```
powershellでgitを見やすくつかう

git-bashでもいいけど、gitのためにgit-bashつかうのはだるいのでpowershellでもgitを見やすく使いやすくしたいということで調べた

**結論: posh-gitを使うとよい**

https://github.com/dahlbyk/posh-git#using-posh-git


## インストール

powershellに以下コマンドをいれる

```powershell
PowerShellGet\Install-Module posh-git -Scope CurrentUser -Force
```

このままだとposh-gitが適用されていないので、powershell profileに直接かコマンドで追記して変更を永続化する。

## コマンドで追記(推奨)

```powershell:powershellで実行
Add-PoshGitToProfile
```

## 直接追記

```:powershellprofileの場所を調べる.powershellで実行
$profile
```

```C:\Users\yourname\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1に追記して上書き保存
Import-Module posh-git
```
[M1 mac, Docker] pythonコンテナでpip installしたときにNo matching distribution found for ~ が出る

最近開發環境が変わることが多く、その際の開発をうまく行えるようにwebサーバーの環境立ち上げをdockerで行っていました。
そこで起こったエラーの対処法になります。

## エラー内容

- 他のマシンでは`docker-compose build`の際のpip install が通る
- 特定のマシンで `docker-compose build`したときに以下のエラーが出てpythonのモジュールがinstallできない
- 自分の場合ではpython-copasiが該当しました。

```basic
ERROR: Could not find a version that satisfies the requirement python-copasi (from versions: none)
ERROR: No matching distribution found for python-copasi
```

## 結論

以下と同様の方法でinstallができるようになりました。
https://ryotarch.com/docker/no-matching-manifest-for-linux-arm64-v8-on-m1-mac/

M1 macでコンテナを建てるとplatformが異なる形で生成されるそう、、
docker-composeに以下を追記することでpip installが通るようになりました。

```basic
	platform: linux/x86_64
```
suid sgid スティッキービットをファイルに設定する方法

##suidとは

+ Set User IDの略
+ 一時的に別のUIDのユーザに変更できる機能のこと
+ 実行ファイルに設定する事で、そのプログラムをどのユーザが実行しても、プログラムの所有ユーザの権限で実行することができたりする
+ これが設定された代表的なプログラムに「passwd」コマンドがあります


###設定方法

+ 設定はchmodコマンドで、通常のパーミッションの値に4000を加えた値を設定するか、所有ユーザに「s」という権限を追加します(u+s)。
+ 追加した場合、所有者の実行権限が　x→s　に変化します。

```
$ls -l 
-rwxr-xr-x user group       9  1月 1 00:00 hoge.txt

$chmod 4755 hoge.txt

$ls -l
-rwsr-xr-x user group       9  1月 1 00:00 hoge.txt
```

```
$ls -l 
-rwxr-xr-x user group       9  1月 1 00:00 hoge.txt

$chmod u+s hoge.txt

$ls -l
-rwsr-xr-x user group       9  1月 1 00:00 hoge.txt
```

##guidとは

+ SUIDは所有者の権限で動作するのに対して、SGIDはグループの権限で動作します。
+ SUIDの場合は、　所有者の実行権限が「s」となるが、SGIDではグループの実行権限が「s」となります。
###設定方法

+ 設定はchmodコマンドで、通常のパーミッションの値に2000を加えた値を設定するか、グループに「s」という権限を追加します(u+s)。
+ 追加した場合、グループの実行権限が　x→s　に変化します。

```
$ls -l 
-rwxr-xr-x user group       9  1月 1 00:00 hoge.txt

$chmod 2755 hoge.txt

$ls -l
-rwxr-sr-x user group       9  1月 1 00:00 hoge.txt
```

```
$ls -l 
-rwxr-xr-x user group       9  1月 1 00:00 hoge.txt

$chmod g+s hoge.txt

$ls -l
-rwxr-sr-x user group       9  1月 1 00:00 hoge.txt
```
##スティッキービットとは

+ ディレクトリに設定します
+ スティッキービット（Sticky bit）が設定されたディレクトリ以下のファイルとディレクトリは、実際に設定したアクセス権に関係なく、所有者とrootユーザのみが名前の変更と削除を行えます
+ 使用されるケースは「全ユーザーがファイルを作成できるが作成したファイルを他人がファイル名の変更や削除をできないようにしたい」場合です。
+ /tmpに、スティッキービットが使われています

###設定方法

+ 設定はchmodコマンドで、通常のパーミッションの値に１000を加えた値を設定するか、その他のユーザーに「t」という権限を追加します(o+t)。
+ 追加した場合、その他のユーザーの実行権限が　x→t　に変化します。

```
$ls -l /hoge/hoge.txt
-rwxr-xr-x user group       9  1月 1 00:00 hoge.txt

$chmod 1755 hoge

$ls -l /hoge/hoge.txt
-rwxr-xr-t user group       9  1月 1 00:00 hoge.txt
```

```
$ls -l /hoge/hoge.txt
-rwxr-xr-x user group       9  1月 1 00:00 hoge.txt

$chmod o+t hoge

$ls -l
-rwxr-xr-t user group       9  1月 1 00:00 hoge.txt
```
情報処理安全確保支援士に合格するためのアウトプット（1/n）

#はじめに

##背景
今までは開発側にいたので技術技術を磨いてきたが、年が経って役割が変わり、抽象的な活動が多くなってきた。
また、活動範囲も広くなったため、今まで避けてきたIPAの資格取得を通じて体系的に学んだ方がいいなと思い始めました。

##目的
実務的な内容を通して、体系的なことを学んで今まで以上にITの価値をユーザーに届けられる、
そんなエンジニアになりたいと思っています。

##目標
今さらではありますが、まずは、4月に「情報処理安全確保支援士」の取得に向けて頑張ります。

##ちなみに
エンジニアの皆さんなら分かると思いますが、体系的なものはあまり頭に入ってこない、やる気が出ないというか。
とはいえそうも言ってられないので、どうやってやる気を出すかと。だったら、アウトプットしながら進めれば「やる気」「理解力」のどっちも満たせるんじゃないかと安直に考え、凍結気味だったこのアカウントで投稿を再開しました。

とりあえずやりながら進めていこうと思ってるので、当面は私が理解した内容をつらつらと書いていく感じにします。
「知ってるよ」みたいなことも、振り返りつつやっていければと思います。
どれだけ他の方の役に立つのかは分からない所ありますが、ちょっとずつでもやっていければと思っております。
（持っている資料が少し古かったりするので不足・間違いがあるかもしれませんが、随時Updateしていきます）

ということで、特に順番なども気にせず、ある程度まとめて書いていきます。
いま勉強に使っている資料を開いた所からスタート、というとこでまずは「ＦＷ」から。

#ファイアウォール（FW）
何ぞやというのは敢えて言うものでもないですが、ざっくり言うとシステム上における「防火壁」ですね。
侵入防御などが元々の役割でした。

##FWの種類
- 1. パケットフィルタ型
    - パケットヘッダのIP、ポートなどをインターネット層で判断。
- 2. アプリケーションゲートウェイ型
    - 「１」に加えてペイロード（パケットのデータ部）も含め、アプリケーション層で判断。
    -  HTTP/SMTP/FTPなどのアプリプログラムごとに別々のプロキシを持つ。
- 3. サーキットレベルゲートウェイ型
    - ペイロードの情報はチェックしない
    - トランスポート層で判断、クライアントとコネクションを確立し、クライアントサーバ間で仮想的な通信路（バーチャルサーキット）を確立する。
- 4. ダイナミックパケットフィルタ型
    - 基本的なルールのみを定義しておき、通信内容に応じて動的にアクセス制御ルールを更新し、接続を管理する。
    - 総じてパケットフィルタ型なので、「１」と同じ内容・層でチェックする。（＝アプリ層の内容は見ない）
- 5. ステートフルインスペクション型
    - 基本的には「４」と同じだが、各アプリごとの通信フローなどの情報に基づいて制御を行う。（＝アプリ層の内容を見る）
    - ステート（状態）フル（完全）なので、自身を通過する情報をしっかり見て動的に判断するものということですね。

色々ありますが、総じて見ると「ヘッダ」「データ」「静的」「動的」「どこまで見るか」の違いですね。

「ヘッダ」　　　　「静的」「IP層」　　　　　 →　１
「ヘッダ＋データ」「静的」「IP層」「APP層」　→　２
「ヘッダ」　　　　「静的」「TCP層」　　　　　→　３
「ヘッダ」　　　　「動的」「IP層」　　　　　 →　４
「ヘッダ＋データ」「動的」「IP層」「APP層」　→　５

##FWのアドレス変換返還方法
- NAT
    - パケット中継時にIPアドレスを変換
- NAPT
    - パケット中継時にIPアドレス＋ポート番号を変換

##FWで防げないもの
- OSの脆弱性
    - ポートスキャン、BOF攻撃など
- Webアプリの脆弱性
    - XSS、SQL/OSコマンドインジェクションなど
- DoS系
    - pingとか飛ばしまくってはいかんぞ！
- マルウェア系
    - ウィルス、ワーム、スパイウェアなど
    - ウィルス検知・対策ソフトを入れられる所には入れましょう

##FWの拡張機能
昨今ではもはや普通になっているものも多いと思うが、FWには単なる侵入防御だけでなく、様々な機能がある。実際の状態に合わせて、必要なものを取り入れるのがよいだろう。

- ハイパフォーマンス
- ギガビット対応
- マルチホーミング対応
    - 企業などのNWから複数の経路を通じてインターネットに接続すること
- IPv6対応
- QoS（Quality of Service）
    - プロトコルごとの帯域最大値に基づき、帯域制御を行う
- 高可用性（HA）
    - 負荷分散方式
    - ホットスタンバイ方式
        - 片方は停止していて、異常時に切り替え
    - 自立負荷分散方式
        - ホットスタンバイと同様だが、どちらも並行稼働して負荷分散する
- 負荷分散
    - 上記で既に触れてるけど
- マルチセグメント対応
    - VLANとかに対応
- アプリ層の攻撃に対する防御
    - IPS（侵入防御）などの機能も備えたFWなども多く、アンチウィルスやコンテンツフィルタなど、統合したオールインワン型もおおくなってきている（＝UTM＝Unified Threat Management）
- サンドボックスでのマルウェア検知
    - 遊び場（砂場）は大事だよね

---

とりあえず一発目はこんなとこまで