OmniAICreator/Qiita-1.07M huggingface dataset:
PowerBIService の改ページ対応レポートで表示されるレコードが自動でDISTINCTされる仕様について

# はじめに
Power BI Serviceのセマンティックモデルから何百万行ものデータをファイル出力する検証を行っていた際に、改ページ対応レポート機能を試してのですが、ファイル出力後の行数とデータソースの行数が微妙にあっておらずつまったので自身の備忘もかねて共有します。

# この記事で伝えたいこと
改ページ対応レポートで表示されるレコードは自動でDISTINCTされるので、重複行も含めてすべて出力したい場合は一意となるカラムを含めて出力すること

# 検証
### 事前準備
事前にAzure Data Lake Storage Gen2(ADLS)上に配置したparquetファイルをAzure Synapse AnalyticsのサーバレスSQLプールでviewとして読み込み、そちらをPower BI DesktopからPower BI Serviceへ発行しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269528/180e13ab-ee83-34c3-39a0-a3173bbb7b99.png)


今回使用するデータは以下です。
| ID  | Gender | LstName | FstName | 
| --- | ------ | -------- | ------- | 
| 01  | M      | 鈴木     | 太郎    | 
| 02  | F      | 鈴木     | 志保    | 
| 03  | M      | 山中     | 達也    | 
| 04  | M      | 青木     | 健一    | 
| 05  | F      | 山下     | 朋美    | 
| 06  | F      | 松本     | 良子    | 
| 07  | F      | 谷口     | 薫      | 
| 08  | M      | 上村     | 直樹    | 
| 09  | F      | 渡辺     | 加奈子  | 
| 10  | M      | 鈴木     | 和義    | 

### 検証手順
セマンティックモデルstudentsにて「改ページ対応レポートの作成」を選択します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269528/4da0e3bb-ff2a-388e-96bd-8193961f6cfd.png)

Power BI Desktopのレポート作成画面と同様に右端にデータとデータのカラムが表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269528/3b767a9f-cefc-25d7-675a-db66a0a55086.png)

試しにすべて選択すると全10レコードが表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269528/bb44e6b8-17b3-b9fc-e015-e55067b54207.png)


が例えばGenderとLstNameのみを表示すると"M"の鈴木さんがDISTINCTされ、全部で9レコードになっている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269528/c033e685-68eb-934e-8c66-5758b2edfec8.png)

もっとわかりやすい例をあげるとGenderのみを表示するとFとMのみが表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269528/b2de5c57-d9ac-81ff-e8e7-c3c1a0f0c98d.png)

Genderのみを選択しcsv出力する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269528/e6f9d2dc-f737-5f6f-29db-1580eeedd9e7.png)

ダウロードしたファイルをvscodeで開いてもFとMのみが出力されているのが確認できる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269528/92c76fdc-0eb3-16ac-48f3-f9de78e521e6.png)
windows 設定メモ

```
------Micorosoft アカウントPCから削除方法
対象PC以外のPCまたはスマホにログインする
関連のデバイスPCを削除する

対象のPCへログインする、ユーザとメールアドレスのとここに
該当マイクロソフトアカウントを削除する。

注意：上記の手順ないと削除ボタンが表示しない。
Typescriptで型を定義するときはinterfaceが基本的には推奨されているらしい

# 概要

- 型定義するときに`type`と`interface`二つの方法があるが、どちらが良いか迷ったので調べた
- インターフェイスを使うと、ビルド成果物の中の`d.tsファイル`の容量が小さくなるらしい

## Interface（インターフェース）

```typescript
interface User {
    name: string;
}

interface User {
    age: number;
}

// User型は自動的に { name: string; age: number; } にマージされる
```

- **拡張可能（拡張性）**: `interface`は拡張可能です。これは、同じ名前の`interface`を複数回宣言すると、それらが自動的にマージされることを意味します
- **新しい型の作成**: オブジェクトや関数の型を定義するために使用されます
- **宣言のマージ**: 同じ名前のインターフェースが存在する場合、それらの宣言は一つのインターフェースにマージされます


## Type（型エイリアス）

```typescript
type User = {
    name: string;
    age: number;
};

type Employee = User & {
    company: string;
};
```

- **非拡張可能**: `type`は拡張できません。同じ名前で複数の`type`を宣言することはできません
- **ユニオン型や交差型などの複雑な型の作成**: `type`はプリミティブ、ユニオン、交差、タプルなど、任意の複雑な型の作成に使用できます
- **型の再利用**: 既存の型を組み合わせて新しい型を作ることができます


## typeとinterfaceの違いまとめ

- **拡張性**: `interface`は拡張可能であり、同じ名前のインターフェースが自動的にマージされますが、`type`は拡張できません
- **複雑な型の作成**: `type`はより複雑な型の表現（ユニオン型、交差型、タプルなど）に適しています
- **使用の推奨**: 一般的に、オブジェクトの型を定義する場合は`interface`が推奨されますが、より複雑な型の操作が必要な場合は`type`が適しています

https://typescriptbook.jp/reference/object-oriented/interface/interface-vs-type-alias

# 本題

## Googleさん的にはインターフェイスを推奨しているらしい

> TypeScript は、型式 に名前を付けるための型エイリアスをサポートしています 。これは、プリミティブ、ユニオン、タプル、およびその他のタイプに名前を付けるために使用できます。
> ただし、オブジェクトの型を宣言する場合は、オブジェクト リテラル式の型エイリアスの代わりにインターフェイスを使用します。

https://google.github.io/styleguide/tsguide.html#interfaces-vs-type-aliases

## インターフェイスを使うと、d.tsファイルの容量が小さくなるらしい

> 昨日、コードを 1 行変更することで TypeScript 宣言を 700KB から 7KB に縮小しました 🔥

https://ncjamieson.com/prefer-interfaces/

## つまりどういうこと

`type`エイリアスを使用して複雑な型を定義すると、TypeScriptのコンパイラはこれをインラインで展開してしまう可能性があります。
これは、出力される`.d.ts`ファイルのサイズを大きくすることがあります。

```typescript
type Point = {
  x: number;
  y: number;
};

type Circle = {
  center: Point;
  radius: number;
};
```

上記の例で、`Circle`型は`Point`型を使用しています。
コンパイラがこれをインラインで展開すると、`Point`型の定義が`Circle`型に直接含まれる形になります。

## interfaceの例

`interface`を使用すると、TypeScriptのコンパイラは名前での参照を維持し、`.d.ts`ファイルがコンパクトに保たれる傾向があります。

```typescript
interface Point {
  x: number;
  y: number;
}

interface Circle {
  center: Point;
  radius: number;
}
```

この場合、`Circle`インターフェースは`Point`インターフェースを名前で参照します。
このため、`.d.ts`ファイルにおいては`Point`の定義が直接`Circle`に組み込まれることはありません。

# まとめ

- 型定義には基本的にinterfaceを使おう
- 複雑な型（ユニオン型、交差型、タプルなど）が必要なときはtypeを使うときもある
Ruby +α メモず

# はじめに
メモ群なので、気になった見出しをご覧ください！
# メモず
## Rubyのファイル名はすべて小文字
例：`my_script.rb`
スネークケースと呼ばれる、「小文字 & `_`」で命名するのが一般的。
これはRailsも同じ。

### 他の言語の命名規則
#### JS：キャメルケース / ケバブケース
例：`myScript.js` / `my-script.js`

####  Java：パスカルケース
例：`MyClass.java`

## 複数行コメントアウト
=begin から =endまで
ただし、インデントすることができない（らしい）
よって、コードの中では`#`を使うのが一般的で、
=begin / =endはドキュメントコメントとして使用されることが多い。

例
```rb
def my_method
	p "Hello, World"
=begin
ここがコメント
複数行でも大丈夫
インデントはできない
=end
	# あるいは、これがコメント
	# これもコメント
end
```

## irb １行ずつ実行（デバック・簡易試行）
`irb.binding`とコードに書くと、その時点で一時停止してくれる

## 雑記：三項演算子・`{}.method`・`do`を使わない書き方
```rb
def chapter04_05(array)
  # 5の倍数を0に置き換えて、新しい配列の合計を返す
  return array.map {|e| e % 5 == 0 ? 0 : e}.sum
end

p chapter04_05([1, 2, 3, 4, 5])
```
この書き方でいいんだ・・・・・・！

## 雑記：配列の操作
`return [array[1], array[2]]` 原始的 とびとびのインデックスにも対応可能
`array - ['RUNTEQ', 25.6]` 初めて見た書き方。Ruby固有の書き方`array - [element]`
`array.values_at(0, 2)` インデックス`0`と`2`の要素を取り出す
`array[1, 2]` １番目の要素から2つを取り出す
`array[1..5]` スプレッド構文

## 雑記：`uniq`メソッド、すごい
```rb
array = [1, 2, 2, 3, 4, 4, 5]
unique_array = array.uniq
puts unique_array.inspect # => [1, 2, 3, 4, 5]
```
## 雑記：破壊的メソッド`!`
`!`をつけると破壊的メソッドであるという概念。面白い。
[`!`をつけない破壊的メソッド](https://qiita.com/k-penguin-sato/items/ab2267ca99d5aedcc40a)もある。

## 雑記：メソッドの`()`の省略
> Rubyでは引数がない、またはオプショナルな引数を使用しない場合、メソッドの`()`（括弧）を省略することができます。これはRubyの構文の柔軟性の一部であり、コードをより自然な形で書くことを可能にします。
> 
> たとえば、`join`メソッドは配列の要素を連結して文字列に変換します。このメソッドはオプショナルな引数を取り、それは連結する際の区切り文字を指定するために使います。区切り文字を指定しない場合は、デフォルトで要素が直接連結されます。
> 
> 括弧を使用する例：
> ```ruby
> array = ['a', 'b', 'c']
> puts array.join() # "abc"
> ```
> 
> 括弧を省略する例：
> ```ruby
> array = ['a', 'b', 'c']
> puts array.join # "abc"
> ```
> 
> 両方の例では、`join`メソッドが引数なしで呼び出されており、結果は同じです。Rubyではこのようにメソッド呼び出しの際に括弧を省略することがよく行われます。ただし、複数の引数がある場合や、括弧を省略することでコードの意図が不明確になる場合は、括弧を付けることが推奨されます。
Microsoft Fabric One Lake 外部ショートカット利用時の監査ログの出方と現時点での注意

## はじめに

Azure Data Lake Storage Gen 2 (以下,ADLS)へのショートカットを作ると、ショートカット先にアクセス権のない人でもアクセスできるようになるので、ADLSから見たときに誰がどのようにアクセスしたことになってるのか確認してみました。

注意：2024/02/07時点の情報です

## 確認

### Azure Portal での操作

はじめに、普通に使ったときのログの確認から。Azure Portal を通じて、ADLS上にファイルを置いた際のログです。私の開発用アカウントlocaldevがどこから何をしたのかが見えています。※Put BlobがBlob APIによるファイル配置

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/785b0598-ecb0-e1b6-4010-f82894646c83.png)

### ショートカット作成からファイル配置

次にショートカットを組織アカウントによる認証で作成し、ファイルを置いた際のログです。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/1cd4f589-2ec9-da80-b29a-c3c04e90a9e6.png)


Log Analytics からは以下のようなログを切り取ってみました。ListFilesystemDirあたりがショートカット作成と思われます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/463ab6b1-5925-a9a5-6f43-a270ce3013fd.png)


[DelegationSAS](https://learn.microsoft.com/ja-jp/rest/api/storageservices/create-user-delegation-sas)が使われており、誰が実施したかは不明になっていることがわかります。
※CreatePathFile～FlushFileの一連の流れがADLSのAPIによるファイル配置

また、一連の操作の送信元のIPが内部IPだけになっていることからもFabric からのアクセスが、ユーザー委任SASで実行されていることがわかります。

ちなみにこのあと何回かファイル表示をすると、そのたびに埋め込まれた資格情報によりGetUserDelegationKeyでユーザー委任SASを取得して認証に使っていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281819/75f2e41c-0363-1983-abdb-78a2e1b4dddf.png)


## わかったこと

現状、ショートカット先での監査は不十分になるので注意。

想定通りですが、SSOできるようにしてもらうか、レイクハウス上で操作内容を取得できるようにしてほしい

少なくともLakehouse上の監査は将来的には来るとは思います。（以下が想定するものは可はさておき）

https://learn.microsoft.com/ja-jp/fabric/release-plan/admin-governance#Fabric-monitor
【UiPath】Pick処理の落とし穴

# はじめに
- 本記事はUiPathの「Pick（分岐を選択）」処理に焦点を当てた技術投稿です。
- 環境はStudio 2023.10.0、クラシックアクティビティ。

## Pickは便利
Pick（分岐を選択）アクティビティは想定される要素が複数種類あるとき、無駄な待機時間を発生させない点で優れています。

下図は「天気予報の結果次第で洗濯物を干すか決める」ロボットをPick処理で作ったサンプルです。

![画像1_Pick.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3688659/b51dadc6-9266-0731-8290-c78cd5c70252.png)



上記の処理は天気が晴れでも雨でもほぼ同時に要素を認識して次の処理に進みます。

一方、もしもPick処理を用いずにIFとElementExists（要素の存在を確認）のみで処理を構築すると、
1番目の候補が表示された場合はすぐに処理が進みますが、
2番目の候補が表示された場合は最初の候補のタイムアウトを待つため無駄な待機時間が発生します。

## 誤検知について
記事タイトルの「落とし穴」と形容した部分です。

当然ながら天気は「晴れ」「雨」のみではありません。
今回は天気が「雪」だった場合に先ほどの処理（つまり雪を想定していない）を動かした結果を見てみましょう。

![画像2_誤検知.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3688659/ea4cf7fb-90f4-f2db-de75-4c0231e4d0bc.png)


**「雪」であるのに「晴れ」であると判定されてしまいました。**
これでは洗濯物はびしょ濡れです。

「晴れ」「雨」しかロボットには設定していないので正確に判定できないのは仕方ありません。
しかし、想定した要素が見つからない場合はエラーで止まって欲しいですよね？

**なぜこんな事が起きたのでしょうか？**

```※なお、今回は「晴れ」と判定した結果を載せましたが、ランダムで「雨」にも分岐します。Pickに設置したアクティビティは左側から完了するとは限らないためです。```

## Pickのトリガーの仕組み
端的に言えば、リトライスコープとPickは全く別物であるためです。

![画像4_PickとRetryScopeの違い.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3688659/b34007ec-70cb-66b3-702b-9fcb8cf103ba.png)



外観が似ているため誤解を招きやすいですが、
- リトライスコープは条件部に設置したElementExists（要素の存在を確認）の結果を判定している。
- Pickのトリガー部は単純に「実行できたか？」しか見ていないようです。よってElementExists（要素の存在を確認）の結果がFalseであっても「実行できている」ため、
**最初にトリガー部を完了しきった分岐のActionを実行します。**

## 対策
ElementExists（要素の存在を確認）と名前が似ているFindElement（要素を探す）を設置してみた際の結果を見てみましょう。

![画像3_Find.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3688659/a321d3d3-5f72-41ed-f2ed-de7a24e299f9.png)


**Actionは実行されず、無事トリガー部でエラー停止する事が出来ました。**

最後まで処理を完了することはできませんが、これがもし業務であったならば
**想定された要素が見つからないとき、適当な分岐を進む**
よりはずっと安全ですね。

## まとめ
- Pickのトリガー部とElementExists（要素の存在を確認）は相性が良くない！！
- Pickのトリガー部にはタイムアウト時にエラーが発生するアクティビティの設置を推奨！！

[他、自社ブログでもUiPath記事を投稿しております。](https://bstyle-value-technologies.blogspot.com/search/label/UiPath "UiPath記事")
Javaのエスケープシークエンス

# 始めに
Javaを含めた言語には単体では表示できない記号が存在します。

例えば''（シングルクォーテーション）や""（ダブルクォーテーション）はString型やchar型の宣言で使用される為、文字列中に入っているとエラーになってしまいます。

※文字列中に”が登場すると、そこが文末であるとみなされるのでエラーとなります。

エラーを回避しつつ、’や”を文字列中に表示する際、用いるのがエスケープシーケンスです。

# エスケープシーケンス

<table>
<caption>エスケープシーケンスの具体例</caption>
  <thead>
   <tr>
      <th>表記</th> <th>意味</th>
    </tr>
  </thead>
  <tr>
    <td> ¥' </td> <td>'（シングルクォーテーション）</td>
  </tr>
  <tr>
    <td> ¥" </td> <td>"（ダブルクォーテーション）</td>
  </tr>
  <tr>
    <td> ¥¥ </td> <td>¥（円記号）</td>
  </tr>
  <tr>
    <td> ¥n </td> <td>改行</td>
  </tr>
</table>

この表では¥（円記号）で表記しますが、\（バックスラッシュ）でも表記可能です。
ただし、¥¥は\¥となります。
【PowerAutomate】”SharePointへのHTTP要求の送信”で陥ったエラー

こんにちは！
M365（特にSharePoint,Power Automate,Power Apps,Teams）に関する記事やちょっとした小ネタなどをご紹介していきます。

# はじめに
Power Automateを使ってSharePointリスト内のハイパーリンク列の情報を別のリストにコピーするフローを作成した際、”SharePointにHTTP要求を送信します” アクションで陥ったエラーについて記載したいと思います。
仕様なのかバグなのか、、、原因までは突き止められていませんが、何かの参考になれば嬉しいです。

# 作成したフロー
最初に作成したフローは以下の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3587034/39e02372-9a76-f241-b23b-25f99a12984a.png)

フローを実行したところ、以下のエラーが表示されてしまいました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3587034/8ef5c5c5-3399-a5a8-a63a-b3e2a8e06930.png)

コピー先のリストを変更して試したところうまくいくケースもあったため、ソースを比較してみたところ、⑥（または⑥'）で最後に指定したリストの内部名に記号（ここでは[ _ ]（アンダースコア））が含まれているかどうかの違いがありました。

# 回避方法：リストの内部名を変更
リストの内部名を変更することでエラーを回避できるのではと考え、試してみることにしました。
内部名はUIでは変更できませんが、以下のPowerShellコマンドで変更することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3587034/3df5d988-4686-875c-a1a7-276ffb65fd48.png)
※ 内部名を変更すると、リストのURLが変わってしまうため、ナビゲーションリンクや他の場所からリンクを貼っている場合は注意が必要です。

# フローの再実行
フロー側でも⑥および⑥' のリストの内部名を修正し、再度実行してみます。
今度こそ、と思った矢先、同じエラーが出てしまいました。。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3587034/5c94a871-97ff-3bbd-bc33-047177d36a10.png)

根拠はありませんでしたが、リストの内部名の最初が大文字だったらどうだろうかと思い、再度以下のように内部名を変更してフローも修正してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3587034/3056e782-a144-4ba1-a4ee-ce65e217e0c7.png)

実行した結果、フローが正常に完了し、コピー先のリストにアイテムがきれいにコピーされました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3587034/ee6d6095-7d5e-982c-37cd-a33cafe8e549.png)

# まとめ
HTTP要求の送信アクションはこれまであまり使ったことが無く、技術的な追及を後回しにとりあえず実装するところから取り掛かってしまった結果、思わぬところではまってしまいました。
今回はSharePoint側の内部名を工夫して回避ができましたが、本来それがエラーの原因となりうるものだったのか、本質的なところは引き続き探っていきたいと思います。

# 最後に
ハイパーリンク列のコピー方法について本記事では詳細は触れませんでしたが、とある方のブログ記事を参考にさせていただきました。
とても分かりやすく、また実現したかった結果も得られることができ大変感謝しております。
リンク掲載は控えさせていただきますが、気になる方は「PowerAutomate ハイパーリンク列 コピー」で検索していただくと出会えるかもしれません。
Windowsのbat（コマンドプロンプト）でregファイル実行時に『続行しますか？』の確認が出ないようにする

# 概要

regファイル実行時に下記ダイアログが出ないようにしたい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/d4c532fb-6c6b-ceba-6433-049e2cecd7f3.png)

> 情報を追加すると、値が変更または削除されてしまい、コンポーネントが正常に動作しなくなることがあります。
> ※※を信頼しない場合は、レジストリに追加しないでください。
> 続行しますか？

# やり方

レジストリーエディターのexeに ```/s``` を渡して **サイレント実行** 。

```bat:
regedit.exe /s ※regファイルパス
```

# 参考サイトさん

http://nonsubject.arinco.org/2010/10/reg_01.html

# バージョン

Microsoft Windows [Version 10.0.19045.3996]
[Office製Word]HRESULT 0x80004005エラーでファイルが開けないときの対処法

非officeツールで編集したドキュメントファイルを開こうとして、データ破損があると次のような
エラーが出力されることがある。

![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759593/700f29cb-a784-8b31-5c1d-ee85907971e5.png)

「OK」ボタンを押して開くのを、一旦あきらめる。

![1タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759593/fa967773-d29c-6a0a-7d4d-98480f57e89f.png)

次のエラーも「OK」で閉じる。
![2タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759593/30465540-8684-cfe0-1ff4-41f4e991b176.png)


〇ここで、ファイルを修復して開くを試してみる。

wordの「ファイル」タブをクリックし、「開く」を選択する。

![３タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759593/510e1a64-b7c6-ac12-37e2-3ada3ad714c3.png)

開く対象ファイルを選択し、「開く(o)」右隣の▼アイコンをクリックしてメニューを開く。メニュー中の「開いて修復(E)」を選択する。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759593/81b7c807-c12a-e02d-4336-6b825cd431c1.png)

コンバータで開くかの確認ポップアップは無視して、「開く」を押下すると、こちらでは修復して開けた。
![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2759593/722568dd-2a50-4488-62e0-14556f8b8d84.png)


以上。
GR公開したアプリ

GR発表したアプリ
https://appexchangejp.salesforce.com/appxListingDetail?listingId=a0N3A00000FnBvUUAV

・開発環境：
①任意環境で開発⏩未管理パッケージなどでパートナ用の開発環境（開発組織）へリリース⏩
②パートナ用の開発環境（開発組織）で開発⏩
スキャン⏩PartnerCom紐付け⏩リスト作成⏩管理パッケージ⏩レビュー⏩公開

1. ISV / OEMパートナーになる
パートナ契約後にパートナ用の開発環境（開発組織）を入手できます。
また、パートナー向けのコミュニティサイト(Partner Community)のアカウントも入手できます。
2. アプリケーションの開発
入手した開発環境でアプリを開発する
3. LMAと環境ハブの申請
・LMA(License Management Application)とは
AppExchangeで公開する自社アプリケーションのライセンスを管理するアプリケーション
・環境ハブとは
各種組織（テスト用、パートナー向け開発用、デモ用）を生成するアプリケーション
4. セキュリティレビュー向けのコードスキャン
SandBoxの全体スキャンされ、結果はStep6でアップロード必要
※テストクラスの予想実際比較なかったりのエラー。コードのエラー箇所が明確的
5. 開発組織とPartner Communityの関連付け
Partner Communityのアカウントでサイトへログインしてから、開発環境へ接続
https://developer.salesforce.com/docs/atlas.ja-jp.packagingGuide.meta/packagingGuide/appexchange_publish_organizations.htm
6. AppExchangeに公開するページ（リスト）の作成
Partner Communityサイトで操作
メールアドレスなどの情報記入
https://developer.salesforce.com/docs/atlas.ja-jp.packagingGuide.meta/packagingGuide/appexchange_publish_listings.htm
7. セキュリティレビュ－の準備
パッケージ開発組織でリリースパッケージの作成（アップロード）を行います。
8. セキュリティレビューの申請
「Partner Community」 -「公開管理コンソール」で対象のアプリケーションのセキュリティレビューの申請を実施してください。
初回アプリケーションの申請完了後に、2営業日以内にSalesforceの担当者からセキュリティレビューの注文書のケースが発行されます。
※エラー情報が曖昧、場所特定や直しが難い
9. 注文書と手順書の準備と提出
注文書の準備とセキュリティレビューの審査対象のアプリケーションの概要や簡単な操作手順を作成し、
上記8.で発行されたケースに添付してください。また、準備が完了した場合はその旨をケースに返答してください。
10. 合否
合否については後日セキュリティレビュー申請者宛にメールで通知されます。
なお、結果が「不合格」だった場合は、
「コードの修正」->「コードスキャン」->「リリースパッケージの作成＆アップロード」->「公開管理コンソールでのセキュリティレビューの申請」->「ケースでレビュー再依頼」（以降不合格の場合はこのループ）
※なお、不合格になった場合でリリースパッケージを再作成する度にバージョンが上がりますが、これは仕方ありません。
11. AppExchangeへの公開
無事セキュリティレビューが「合格」になりましたら、公開管理コンソールで該当のアプリケーション（バージョン）を「公開」状態に設定

参考：
①お客様のパートナーアカウントをもらって、有料／無料の手続き違いを整理
②LMAと環境ハブの申請　は何か確認要
③NameSpace はどうやって申請するか確認要

注意：
アクション⏩Lightning Webコンポーネント　の組合せはモバイルにサポートされてない
Laravelにてtextのバリデーションをした時の勘違い

Laravelにてtextのバリデーションをした時の勘違い


```migration.php
$table->text('sample1');
```


マイグレーションでデータベースを作成する際、text型で宣言した項目をリクエストクラスでバリデーションしようとした際、以下のようにtext型としてバリデートしようとしてしまったが、'text'というバリデーションルールはLaravelには存在しないとのこと。

```SampleRequest.php
'sample1' => [
    'required',
    'text',
    'max:65535',
],
```


調べたところ、Laravelのデータ型としてのStringとtextの違いは格納可能な文字列サイズの違いであって、中に格納される文字列型としては両方String型という認識なのではないかと思われる。
そのため、以下のようにstring型でバリデーションしたところ上手くいきました。


```SampleRequest.php
'sample1' => [
     'required',
     'string',
     'max:65535',
],
 ```  

単純な躓きでした。
OOM killerについて



# OOM killerとは
OOM killer(Out of Memory Killer)は、Linuxカーネルに実装されたメモリ管理機能の一つ。
システムのメモリが物理的に不足した時に、特定のプロセスを強制終了する機能のこと。
OOM killerは、大量のメモリを消費している使用効率の悪いプロセスから優先して強制終了する。

OOM killerが起きると下記にエラーログが出力される。
```
grep -i kill /var/log/messages*
```

強制終了されたプロセスの再起動を行う必要があるがそもそもメモリー不足で起きているので原因を解決してから再起動しなければ再発する可能性が高い。


# OOM killerが起きないようにする
OOM killerは主にメモリ不足で起こる。
そのため下記の対策が必要になる。
- メモリを増やす
- swap領域を増やす

OOM killerを無効にする対策もあるらしいが非推奨らしい。
awk を使用して特定のシンボル名のサイズを readelf -s の出力から抽出

`awk` を使用して特定のシンボル名（この例では `hoge`）のサイズを `readelf -s` の出力から抽出し、それを別のテキストファイルに記載されているサイズ値と比較するスクリプトを組み合わせる方法を紹介します。このスクリプトは次のステップで構成されます。

1. `readelf -s` を使用して ELF ファイルからシンボルとそのサイズを抽出します。
2. 特定のシンボル名に対応するサイズを見つけます。
3. 別のテキストファイルから期待されるサイズ値を読み込みます。
4. 両方のサイズ値を比較し、一致しているかどうかを報告します。

以下のシェルスクリプトは、これらのステップを実装しています。

```sh
#!/bin/sh

# ELFファイルとサイズが記載されたテキストファイルのパス
elf_file="your_elf_file_path_here.elf"
size_file="expected_size_file_path_here.txt"

# 特定のシンボル名
symbol_name="hoge"

# readelfから特定のシンボルのサイズを抽出
symbol_size=$(readelf -s $elf_file | awk -v name="$symbol_name" '$8 == name {print $3}')

# テキストファイルから期待されるサイズを読み込み
expected_size=$(cat $size_file)

# サイズを比較
if [ "$symbol_size" = "$expected_size" ]; then
    echo "サイズが一致します: $symbol_size"
else
    echo "サイズが一致しません。期待されるサイズ: $expected_size, 実際のサイズ: $symbol_size"
fi
```

このスクリプトを実行する前に、`elf_file` と `size_file` 変数を適切なファイルパスに設定してください。`size_file` には、比較するための期待されるサイズ値が含まれている必要があります。

`awk` の `-v` オプションを使用して、`awk` スクリプト内でシェル変数の値を使用しています。これにより、特定のシンボル名に基づいてサイズを抽出できます。そして、抽出したサイズとテキストファイルから読み込んだ期待されるサイズを比較しています。

このスクリプトは、サイズが一致するかどうかに基づいてメッセージを表示します。サイズが一致しない場合は、期待されるサイズと実際のサイズの両方を報告します。
UnityとSwiftで曜日をIntでやりとりするときの注意

Unityでは
日曜0
月曜1
火曜2
水曜3
木曜4
金曜5
土曜6

Swiftでは
日曜1
月曜2
火曜3
水曜4
木曜5
金曜6
土曜7

めちゃくちゃハマった時間無駄にした
tblsを使ってmysqlのDB定義書をエクセルで出力

## やりたいこと

mysqlのテーブル定義書をエクセルで出力したい。

## 方法
tblsを使ってみました

## 環境
centos7

## tblsのインストール

```
 export TBLS_VERSION=1.73.2
 yum install https://github.com/k1LoW/tbls/releases/download/v$TBLS_VERSION/tbls_$TBLS_VERSION-1_amd64.rpm
 ```

## 出力
```
tbls out mysql://user:pass@hostname:3306/dbname -t xlsx -o schema.xlsx
```

## まとめ
インストールから出力まで5分もかからずできました。

テーブル定義書の作成を自動化したい人は是非試してみてください。


### 参考
・[tbls github](https://github.com/k1LoW/tbls?tab=readme-ov-file)

・[tblsがデータソースとしてBigQuery / Amazon Redshiftに、出力フォーマットとしてxlsx / PlantUMLに対応した etc.](https://k1low.hatenablog.com/entry/2019/05/27/083000)
【Python】文字列の先頭・末尾n文字を削除する方法

◆問題
文字列の先頭・末尾n文字を削除する方法が分からなかった。

◆対処法
スライスを使用すればできた。

```python:slice.py
txt = 'あいうえお'
print(txt[:-2]) #末尾から2文字を削除
print(txt[4:]) #先頭から4文字を削除

# 実行結果
あいう
お
```
【Python】カタカナやひらがなをそれぞれに変更する方法

◆問題
カタカナやひらがなをそれぞれに変更する方法が分からなかった。

◆対処法
「jaconv」を使用すればできた。

```python:kana_hira.py
import jaconv

word1 = "ヤサイ"
change_word_hira = jaconv.kata2hira(word1)
print(change_word_hira)

word2 = "らーめん"
change_word_kana = jaconv.hira2kata(word2)
print(change_word_kana)

# 実行結果
やさい
ラーメン

```
VSCodeのバージョンによってレンタルサーバのOSバージョン等で、ssh接続出来ない事有り

私共の利用しているレンタルサーバVPSにおいてVSCode ssh接続時
![スクリーンショット 2024-02-07 14.53.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/b565a82c-3722-2d6e-08ba-cc4d04e26e4c.png)
Remote SSHを使用するために必要な「glibc」や「licstdc++」のパッケージ（あるいはそのバージョン）が、リモートサーバーにインストールされていない（あるいはできない）ために発生しています。と言う原因で、結局VSCodeのバージョンを下げ、VSCodeの自動更新をnoneに設定しました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/d9da0f35-f1c2-52e6-96ed-05eac29a51a2.png" width="80%">
ちなみに
CentOS Linux release 7.9.2009
VSCode1.86と言う条件で起きました。
現在VSCode1.85.2のバージョンで実行しています。
C#.NETでtnspingの標準出力が取得できない件の対応

# 現象

手動でコマンドプロンプトを開いて ```tnsping ※※``` と入力すると問題無く実行できる。

でもC#のexeで ```tnsping ※※``` の標準出力を取得しようとすると下記例外になってしまう。

> 'tnsping' は、内部コマンドまたは外部コマンド、操作可能なプログラムまたはバッチ ファイルとして認識されていません。

コマンドプロンプト上では ```tnsping``` はコマンドとして認識されているのに、なぜC#のexe経由でやると認識されないのだ？

# 対応

C#のコードで ```tnsping``` と書いていた部分を、下記のような **tnsping.exeのフルパス** にしたら標準出力取得できました。

```※Oracleクライアントインストール先フォルダー\product\11.2.0\client_1\BIN\tnsping.exe```

# 原因はOracleクライアントインストール直後に実行していた可能性が高いです

Oracleクライアントインストールが終わって、しばらく使うなど再起動などが入ると **フルパスでなくても想定通りに動作** しました。
```tnsping``` のコマンドに対するパスが通っていなかったと思われます。

ですが、
**Oracleクライアントインストール直後（再起動などを挟まず）にtnspingの動作確認をするexe**
という要件だったので、やむなくフルパスを指定るする方法をとりました…。


# ソースコード

```C#:
using System;
using System.Diagnostics;

namespace Sampleple
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string res_ = "";    

            Process process_ = new Process();

            process_.StartInfo.FileName = @"C:\Windows\SysWOW64\cmd.exe";

            //下記は問題無く『ipconfig /all』の結果が取得できました。
            //process_.StartInfo.Arguments = "/c ipconfig /all";

            //同じ要領で下記をやるとなぜかtnspngがコマンドとして認識されない…。
            process_.StartInfo.Arguments = "/c tnsping wmsng";

            //tnspingをtnsping.exeのフルパスに変えると想定通りの結果が取得できました。
            //process_.StartInfo.Arguments = "/c ※Oracleクライアントインストールフォルダー\\Oracle\\product\\11.2.0\\client_1\\BIN\\tnsping.exe wmsng";

            process_.StartInfo.RedirectStandardOutput = true;
            process_.StartInfo.RedirectStandardError = true;
            process_.StartInfo.UseShellExecute = false;

            process_.Start();
            process_.WaitForExit();

            res_ += process_.StandardOutput.ReadToEnd();
            res_ += process_.StandardError.ReadToEnd();

            Console.WriteLine(res_);

            Console.ReadLine();
        }
    }
}
```

# 蛇足

「コマンドがなんか通らない…」ってなったら、とりあえずフルパスで指定。

# バージョン

Microsoft Windows [Version 10.0.19045.3996]
SQL*Plus: Release 11.2.0.1.0 Production
DOMについて復習

# DOM（Document Object Model）について

DOMは、**HTMLの情報をプログラムが扱いやすい形式でメモリ上に保存するための仕組みである。**

HTMLが解析されると、DOMへと変換される。JavaScriptでHTMLを操作する際は、このDOMを介して行われる。


DOMへの変換やレンダリングの仕組みは以下の記事がわかりやすい。

https://zenn.dev/ak/articles/c28fa3a9ba7edb



## DOMの構造

DOMの構造は、文書をツリー形式で表現する。このツリーは、文書の階層構造を模倣し、各ノードが文書内の特定の部分（例えば、要素、属性、テキストなど）に対応する。このツリー状の構造により、プログラマは文書の特定の部分を簡単に識別し、操作できるようになる。

### ノードの種類
ノードには以下の5つの種類が存在する。

- テキストノード: 文書内のテキストを表す。
- コメントノード: HTMLのコメントを表す。
- ドキュメントタイプノード: 文書のDOCTYPEを表す。
- 要素ノード: HTMLの要素（タグ）を表す。
- ドキュメントノード: 全体の文書を表す。


これらのノードは、文書内の情報をkeyとvalueのペアとして保持し、DOMツリー内でツリー状に組織される。



 ## JavaScriptによるDOMの操作
Webページの動的な変更、ユーザーインタラクションの応答、そしてリアルタイムでのコンテンツの更新が可能となる。

### 要素の取得
<details><summary>サンプルコード</summary>
document.querySelectorやdocument.getElementByIdなどのメソッドを利用して、DOMツリー内の特定の要素を取得する。


```js
// HTML要素の取得
let result = document.documentElement

// head要素の取得
result = document.head

//bodyの取得
result = document.body

//子ノードをすべて取得
result = document.body.childNodes

//子ノードを持っているかどうか
document.body.childNodes.hasChildNodes()

//一番最初の子ノードをしとく
document.body.childNodes.firstChild
```
```tsx

//cssで指定されているクラス、idを取得、タグも可能
result = document.querySelector(ccsセレクター)
document.querySelector(".select")
document.querySelector("p")

//全部のpタグを取得する
document.querySelectorAll("p")

//idによって、要素を取得する。(documentインターフェースのみ存在)
document.getElementById('title')

//name属性によって、要素を取得する
document.getElementsByName('hello')

//要素のタグから、取得
document.getElementsByTagName('p')

//クラスの名前から、要素を取得
document.getElementsByClassName('class')

//href属性がある要素を取得
document.links
```

</details>


### 要素の作成と挿入
<details><summary>サンプルコード</summary>


```tsx
//body要素のhtmlを取得
document.body.innerHTML
//body要素のhtmlを右側のものに全て置き換える
document.body.innerHTML = '<h1>hello</h1><div>hello</div>'

//取得した要素の後ろに追加する。（一度要素のものを削除してから、もう一度書き換えている）
document.querySelector("div").innerHTML += '<p>hello</p>'

//取得した要素の、前、後ろに新しい要素を加える（insertAdjacentHTMLの第一引数に、afterbegin,beforebegin等を指定）
document.querySelector("div").insertAdjacentHTML("afterbegin", '<h1>あいうえお</h1>')

```

```js
//要素を作成する
let p = document.createElement('p')
p.innerHTML = "HEllo"

//テキストノードを作成する
document.createTextNode('textだお')

document.body.innerHTML = "<div>hello</div>"

//取得した要素の閉じタグの前に挿入する.(beforeendと同じ)
let result = document.querySelector("div").append(p)

//取得した要素のタグのうしろに挿入する.(afterbeginと同じ)
document.querySelector("div").prepend(p)

//取得した要素のタグの前に挿入する.(beforebeginと同じ)
document.querySelector("div").before(p)

//取得した要素のとじタグの後ろに挿入する.(afterendと同じ)
document.querySelector("div").before(p)

document.querySelector("div").append("text me")

```

</details>


## innerHTMLやinsertAdjacentHTMLを使う際のセキュリティ上の注意
innerHTMLやinsertAdjacentHTMLを使用する際は、XSS（クロスサイトスクリプティング）攻撃に注意する必要がある。XSSとは悪意のあるスクリプトがWebページに注入されることにより発生する。innerHTMLやinsertAdjacentHTMLのようなメソッドを使用する際には、挿入されるコンテンツが安全であることを確認する必要がある。これを避ける一つの方法は、**textContentプロパティ**を使用して、HTMLタグではなくテキストのみを挿入することである。

https://www.shadan-kun.com/waf_websecurity/xss/

## 要素の削除、置換
remove: 要素自身とその子要素を削除する。
replaceWith: 要素を別のノードに置き換える。
これらのメソッドを利用することで、動的なWebページの作成や管理が可能になる。

https://developer.mozilla.org/ja/docs/Web/API/HTMLSelectElement/remove


https://developer.mozilla.org/ja/docs/Web/API/Element/replaceWith
AWSのConnection Drainingについて事例を用いて理解するの備忘録

### Connection Drainingを有効にした場合のデータ処理の流れについて


#### 事例
ウェブアプリケーションのバックエンドには複数のデータベースサーバーがあり、ヘルスチェックはデータベースの接続状態を確認します。しかし、データベースにネットワーク的な問題が発生し、ヘルスチェックが一時的に失敗します。

#### 要因
データベースのネットワーク接続がタイムアウトし、ヘルスチェックが失敗します。この場合、データベースは一時的な問題により一時的にアクセス不能となっています。

#### 処理完了のための措置
Connection Drainingにより、ヘルスチェックの失敗したデータベースに新しいリクエストが送信されなくなりますが、既存のリクエストやセッションは引き続き処理されます。データベースの問題が一時的であり、ヘルスチェックが失敗した後も、データベースが回復する可能性があります。そのため、Connection Drainingによって、ユーザーが利用中のセッションやリクエストを中断することなく、サービスを継続することができます。

このように、Connection Drainingはヘルスチェックに失敗する状況でも、既存のリクエストやセッションを完了させることで、サービスの安定性を確保します。

ここは違う、ここはこの方がいいかな？等々ございましたらアドバイスいただけますと幸いです。
最後まで見ていただきありがとうございました。
【Python】画面をスクロールする方法

◆問題
画面のスクロールができず、要素の取得やクリックができなかった。

◆対処法
「driver.switch_to.window」を使用したらできた。

```python:after.py
# 最下部までスクロール
driver.execute_script('window.scrollTo(0, document.body.scrollHeight);')

# 最上部までスクロールする
driver.execute_script("window.scrollTo(0, 0)")

# X座標に0ピクセル、Y座標に500ピクセルスクロールする
driver.execute_script("window.scrollTo(0, 500)")
```
【Python】ウインドウの切り替え方法

◆問題
新規ウインドウを立ち上げた際に、切り替え方法が分からず操作できなかった。

◆対処法
「driver.switch_to.window」を使用したらできた。

```python:after.py
new_handles = driver.window_handles
driver.switch_to.window(new_handles[0]) # 1番目のウインドウ
driver.switch_to.window(new_handles[1]) # 2番目のウインドウ
...
driver.switch_to.window(new_handles[-1]) # 最後のウインドウ
```
実務でPandasとMatplotlibを使う時がやっと来た

# はじめに

AWS エンジニアになる前は Python を独学で学び、Pandas や Matplotlib などデータ分析に関わるライブラリを触ってきました。

実務で使うことはあるのかと思っていましたが、ようやく学んだことを活かせる時が来たので記事にしようと思います。

# どんな業務で扱うことになったのか？

AWS エンジニア(インフラ担当)として、**『AWS リソースの使用状況を月次で報告する』** という月一の定例業務が発生することになりました。

EC2 インスタンスの 1 ヶ月の CPU やメモリの使用率などの推移を見て、今後のキャパシティプランニングに役立てる目的のためです。

私がジョインしているプロジェクトでは、システムの機能ごとに複数の AWS アカウントを使用し、かつ EC2 インスタンスを冗長化しているためサーバ数が多い状況です。
手作業で各サーバの CPU、メモリ使用率を確認していては月一の作業に対しての工数がかかってしまいます。

そこで、以下の方法で『工数がかかりすぎる問題』を解決しました。

[![Image from Gyazo](https://i.gyazo.com/0a98360263c80651019a1c89598fb64a.png)](https://gyazo.com/0a98360263c80651019a1c89598fb64a)

# Lambda で CloudWatch のメトリクスを取得して統計データを Pandas と Matplotlib でグラフ化する

今回、**『1 ヶ月の統計データを可視化して報告すること』** が最大の要件でした。
その要件を満たすため、以下の二通りを検討しました。

案 1)
CSV ファイルの出力までを Lambda で実装して、グラフ作成は VBA を実装してエクセル内で行う

案 2)
CSV ファイルの出力とグラフの作成まで Lambda で実装する

**『手作業をなくすこと』** と **『実装の手間を省くこと』** を前提に検討し、全ての処理を Lambda 内で完結できる案 1 を採用しました。
(実を言うと、Pandas と Matplotlib を使う機会チャンスだったからという、個人的な理由も少なからずありますが、、、)

# 実際に導入してみた結果

個人の感想としては良い感じです。
ただ、検討段階で **『報告資料にどのようにグラフを挿入するか』** という点では見積もりが甘い部分がありました。

結局、グラフを一つ一つ貼り付けていく工数が発生してしまいました。これは、案 2 を採用していたとしても **『VBA でグラフの貼り付け位置を指定する』** という(難易度の高そうな)実装が必要だったと思います。

# 改善点

**『手作業をなくすこと』** を前提条件にしているので、見積もりが甘かった点を VBA で修正する感じになりそうです。

# さいごに

AWS エンジニアもプログラミング言語(特に Python)は絶対にできた方がいいということが今回の業務で実証されました。
今まで学習してきたことが無駄にならなくてよかったです。
ドキュメント作成のいろは



# 参考にした記事など

[ドキュメント作成時のあるあるアンチパターン20](https://qiita.com/tamikura@github/items/625b94b6046113403728)

[仕様書の書き方](https://qiita.com/ko1/items/9f5f1a2683ea54f12362)

[ドキュメント作成スキル向上を目指す人向けおすすめ記事まとめ](https://qiita.com/yasuoyasuo/items/1eb7298f91a44dce7abc)

# 具体的に書く

## 何が、なぜ、どのように、などを具体的に書いて、わかりやすくする

画面名、URL、などの情報は出来るだけつける

**例)レビューチケット(backlogとか)**

- どこをどのように修正したのかを明確に示す
    - ドキュメントの修正なら、何行目、とか項目名○○、とかパっと移動できるような情報を示す
    - コードの修正なら、行数を書いておき、修正箇所をコピペで張るとかするとわかりやすい気がする
- 修正の理由（背景）を書く
    
    →レビュワーはどこを見ればよいかがすぐわかり、その修正の妥当性についても書いてある理由から判断できる
    

## 定量化する

明日→2023/1/11

数分→5分

# 前提(理由)を書く

例えば仕様書を見てこの処理いらなくね？と思うのがあっても、実は必要な理由があったりする

そういうのを書いてくれていると後から入ってきた人にも伝わりやすい。

前提を知らない人が修正して、バグになっちゃうかもしれない。

## ただ、書きすぎても…

要件を簡潔に伝えた方が分かりやすい場合もある。

伝言とか依頼とかは「結局何をすればいいの？」「結局どうなったの？」がわからないとつらい

# 分かりやすい言葉で書く

自分ははじめ、渡された資料の中に意味の分からない略語があった

一般的ではない略語（プロジェクト内で使われているものなど）を使用する場合は、文書内で初めて出てくるときには説明を入れておく。
　→後から入ってきた人にも伝わりやすい。

表記漏れは混乱を生むのでなくす（用語を統一）

# 箇条書きを使う

箇条書きにすることで、各項目が独立し全体イメージが把握しやすくなる。

```
修正点は以下の３点です。
	・ほにゃほにゃ
	・ほげほげ
	・むにゃむにゃ
```

※特に箇条書きが入れ子構造になる場合は、インデントにも気を付ける

```
・ほげほげ
		・ほげほげ２
		・ほげほげ３
・ほにゃほにゃ
		・ほにゃほにゃ２
```

# 打消し線も活用する

消すより打消し線を使った方が、流れがわかって良い場合がある

```
~~ほにゃほにゃほにゃほにゃ~~
【追記】2023/1/10の打合せで、上記は行わないことになりました
理由は～～～～
```

これっていつ決定したんだっけ？昔と変わったんだっけ？なんでだっけ？を知りたい時があるよね

# 既存のドキュメントを踏襲する

テンプレートがあったりするのでそれを利用することで書式がそろって見やすくなる

# **何も考えずに既存のドキュメントをコピーしない**

既存のドキュメントを流用する場合でも、わかりにくいと感じたところ、不足していると感じたところは追加する。

元々こうだったので、、とか、誰々さんがこう書いていたので、、とかは良くない。

# まとめ

結局は、他の人が見たときにどう思うか？と客観的に見ることが大切。
自分が分かるだけでは意味が無い。
AWS StepfunctionsとSWFの違い

## はじめに
AWS SAPの勉強中、SWFについて不明瞭だったこと、
StepfunctionsとSWFの違いが理解できていなかったことから、
これらについて勉強しました。
ドキュメントやちょっと動かしてみて得られた知見を共有します。

## 想定読者
SWFについて不明瞭な人。

## まず、SWFとは
Amazon SWF(Simple Workflow Service)とは、フルマネージド型のワークフローサービスです。
処理のステート管理やタスク間のコーディネートが行える、
Stepfunctionsの前身といえるサービスです。

SWFはワークフローを作成し、タスクや状態を管理するものであり、
実際に処理をするワーカーと呼ばれるものが別途必要です。

ワーカーとは、SWFエンドポイントに通信できる
任意のコンピューティングデバイス（EC2、オンプレ等）で動作するプログラムのことです。
以下の言語で開発できます。

* 開発言語
Java、.NET、Node.js、PHP、PHP バージョン 2、Python および Ruby

また、ワーカーには種類があります。
SWFを実行する場合には、それぞれ実装する必要があります。

* ワークフロースターター
ワークフローを開始するもの。
例として、eコマースにおけるウェブサイトに相当。
* ディサイダー
ワークフローでアクティビティタスクの流れを制御するもの。
ワークフローの履歴を分析し、次のステップを決定する。
* アクティビティ
ワークフローでタスクを実行するもの。

現在では、新規アプリケーションの開発にはStepfunctionsの利用が推奨されており、Stepfunctionsでニーズが満たせない場合にSWFを検討するよう公式が明言しています。
[よくある質問 - Amazon SWF](https://aws.amazon.com/jp/swf/faqs/)

## SWFを検討するケース
先に記した通り、基本的にはStepfunctionsで問題ないです。
しかし、下記の様なSWFを検討するケースもあります。

* プロセスにおいて介入する外部信号が必要な場合
例えば、ワークフローの途中に人間の命令が必要な場合。
eコマースにおける注文処理にて、
ユーザーから注文キャンセルを受け取る場合などが例に挙げられる。
[シグナル - Amazon SWF](https://docs.aws.amazon.com/ja_jp/amazonswf/latest/developerguide/swf-dev-adv-signals.html)
その他にも、人間の判断が必要なもの（承認系とか）であれば、SWFを検討できる。

* 結果を親に返す子プロセスを起動する場合
これはStepfunctionsでも親ステートマシンから子ステートマシンを呼び出すことによって、
実現出来る気がするんですが、どうなんでしょうか…。
[AWS Step Functions のよくある質問 - SWFとの使い分け](https://aws.amazon.com/jp/step-functions/faqs/)

## おわりに
まず、SWFではワーカーの知識・実装が必要であるため、お手軽にできるものではないなと感じました。AWSコンソール上で完結しないので、軽く実装してみよっかなができないところも微妙ポイントです。開発環境を整えて、実装したプログラムをデプロイする必要があります。

Stepfunctionsでは、Lambdaを使ってサーバーレスにしたり、ユースケースに応じたテンプレートが存在したりするのでなおさらSWFの重さを感じました。
![ステートマシンのテンプレート](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/380272/ce436bdf-be80-c6a5-d7d1-b8c30c4d7bfe.png)

また、Stepfunctionsはフローが視覚化されていますが、SWFでは視覚化されていません。
実行されたイベントがログ形式で表示されるのみなので、Stepfunctionsと比較してしまうと直感的ではありません。
![SWFの実行画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/380272/62985bab-7a33-957c-5ed8-2f53e3200e60.png)

以上から、基本的にはStepfunctionsを使っておけば良いということが理解できました。
資格試験の対策としての勉強でしたが、いい勉強になりました。
【Python】画面外の要素をクリックする方法

◆問題
XPATHなどで指定し「.click()」でクリックしようとすると、できないことがあった。

◆対処法
「execute_script」を使用したらできた。

```python:before.py
driver.find_element(By.XPATH, ***).click()
```

```python:after.py
click_element = driver.find_element(By.XPATH, ***)
driver.execute_script("arguments[0].click();", click_element)
```
Pythonで始める音声認識：faster-whisperを使った簡単なガイド

音声認識技術は、私たちの生活やビジネスに革命をもたらしています。特に、ポッドキャストのテキスト化、会議の議事録作成、音声コマンドを使った操作など、その用途は日々広がりを見せています。しかし、多くの人々が直面しているのは、技術の複雑さと実装の難しさです。ここで、Pythonユーザーに朗報です。`faster-whisper`は、音声認識を簡単に、そして速く行うためのツールです。

https://github.com/SYSTRAN/faster-whisper

# 対象読者
この記事は、Pythonに慣れ親しんでいるが、音声認識技術を使ってみたいと考えているプログラマーや開発者、また音声データをテキストに変換したい研究者やコンテンツクリエイターを対象としています。

# 解決したい問題
音声データをテキストに変換する過程の複雑さと時間を削減し、誰もが簡単に高精度な音声認識を実現できるようにすることがこの記事の目的です。

# はじめに
音声認識技術の進化は目覚ましいものがありますが、それを実際に使いこなすには専門知識が必要とされがちです。`faster-whisper`は、このギャップを埋めるために開発されたライブラリであり、特にPythonを使った開発に親しんでいる人々にとって、非常に有用なツールです。

# faster-whisperの導入方法
導入方法については以下の通りとなります。

## 1. インストール:
`faster-whisper`のインストールは簡単です。ターミナルまたはコマンドプロンプトを開き、以下のコマンドを実行してください。
```sh
pip install faster-whisper
```

## 2. モデルの読み込み:
Pythonスクリプト内で、以下のようにして`faster-whisper`から`WhisperModel`クラスをインポートし、必要なモデルを読み込みます。
```python
from faster_whisper import WhisperModel
model = WhisperModel("small", device="cpu")  # GPUを使用する場合は "cuda" を指定
```

## 3. 音声ファイルの変換:
変換したい音声ファイルのパスを指定し、`transcribe`メソッドを呼び出します。
```python
audio_path = "C:/temp/test.wav"
segments, _ = model.transcribe(audio_path)
```

## 4. テキストの出力:
最後に、認識されたテキストを出力します。
```python
transcription = ''
for segment in segments:
   transcription += str(segment.text) + '\n'
print(transcription)
```

# 結論
`faster-whisper`を使用することで、Python開発者や音声データを扱うすべての人々は、音声認識の複雑さを気にすることなく、迅速かつ正確にテキストへの変換を実現できます。このガイドが、音声認識技術の利用を始める一歩となり、さらなる探求への扉を開くことを願っています。

# まとめ
音声認識技術は、日々進化し続けていますが、`faster-whisper`のようなツールによって、その恩恵をより多くの人が手軽に享受できるようになりました。この記事が、音声認識の世界へのあなたの旅の始まりに役立つことを願っています。
【Python】.textで要素が取得できない場合の対処法

◆問題
XPATHなどで指定する際に、空白があると上手く取得できないことがあった。

◆対処法
「.text」部分を「.get_attribute("textContent")」に置き換えると取得できた。

```python:before.py
element = driver.find_element(By.XPATH, ***).text
```

```python:after.py
element = driver.find_element(By.XPATH, ***).get_attribute("textContent")
```
DatePickerにフォーカスが当たったときに背景色を変更する

## 単純に

IsFocusedでは駄目だった

## 実装
IsKeyboardFocusWithinを使えばOK！

```C#:xaml
<Style TargetType="DatePicker">   
    <Style.Triggers>
        <Trigger Property="IsKeyboardFocusWithin" Value="True">
            <Setter Property="Background" Value="#ffef85"/>
        </Trigger>
    </Style.Triggers>
</Style>
```

## 感謝
https://stackoverflow.com/questions/47811827/how-to-trigger-isfocused-on-datepickertextbox-in-wpf

## 参考
https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.uielement.iskeyboardfocuswithin?view=windowsdesktop-8.0
EC2におけるresolve.conf設定情報が上書きされる問題の解決方法

## 概要
過去に、EC2サーバーにおいて、/etc/resolv.confファイルにネームサーバーや検証用ドメインの情報を手動で追加した経験があります。しかし、サーバーを再起動すると、これらの設定情報が上書きされてしまう問題が発生しました。

## 原因
この問題は、NetworkManagerが/etc/resolv.confファイルを自動的に管理するため発生します。NetworkManagerは、起動時に/etc/resolv.confファイルを読み込み、DHCPサーバーから取得したDNS情報を設定します。そのため、手動で設定した情報は、NetworkManagerが起動するたびに上書きされてしまいます。

## 解決方法
- NetworkManagerの設定変更
/etc/NetworkManager/NetworkManager.conf ファイルに以下の設定を追記します
```
[main]
plugins=XXXX
;  ここ（設定しないと、OS再起動されると、設定情報が上書きされます）
dns=none  
```
この設定により、NetworkManagerは/etc/resolv.confファイルを管理しなくなります。
- NetworkManagerサービスを再起動します
```
sudo systemctl restart NetworkManager
```
・ 設定例
以下の例では、/etc/resolv.confファイルにローカルドメインとGoogleのネームサーバーを追加しています。
```
;ローカルドメインを検索対象として追加
search ap-northeast-1.compute.internal {dbfocus.local}
nameserver 10.10.0.2
;Googleの名前解決サーバーを参照するように設定します
nameserver 8.8.8.8
```
富岳でesuparのアイヌ語係り受け解析をムリヤリ動かすには

[昨日の記事](https://qiita.com/KoichiYasuoka/items/56e4e60f42d654bab672)で書いたesuparによるアイヌ語係り受け解析プログラムを、スーパーコンピュータ「富岳」のPyTorch-1.13.0で動かすことを試みた。しかし、富岳のPyTorch-1.13.0はコンパイル時に`USE_LAPACK=1`を指定しておらず、`torch.nn.init.orthogonal_()`まわりで

```
  File "/vol0004/apps/oss/spack-v0.19/opt/spack/linux-rhel8-a64fx/fj-4.8.1/py-torch-1.13.0-glqavnhys6plsjklw2bp3tkkh5ysyrqh/lib/python3.10/site-packages/torch/nn/init.py", line 484, in orthogonal_
    q, r = torch.linalg.qr(flattened)
RuntimeError: Calling torch.geqrf on a CPU tensor requires compiling PyTorch with LAPACK. Please use PyTorch built with LAPACK support.
```

という悲しいエラーが出て、動かすことができなかった。仕方ないので、富岳のPyTorchを最新の[PyTorch-2.2.0](https://pypi.org/project/torch/2.2.0/)に入れ替えた上、`TOKENIZERS_PARALLELISM=false`で[tokenizerをなだめつつ](https://qiita.com/KoichiYasuoka/items/545e6eefcd7a41737eec)、esuparを動かすことにした。

```
#! /bin/bash
#PJM -L rscgrp=small
#PJM -L elapse=1:00:00
#PJM -L node=1
#PJM -j
#PJM -S

. /vol0004/apps/oss/spack/share/spack/setup-env.sh
spack load py-numpy@1.23.4/hcqp4u5
G=`id | sed 's/^.*gid=[0-9]*(\([^)]*\)).*$/\1/'`
set `ls -d /vol*/$G /vol*/data/$G` $HOME
export PYTHONUSERBASE=$1/esupar
export PATH=$PYTHONUSERBASE/bin:$PATH
export TMPDIR=$PYTHONUSERBASE/tmp
mkdir -p $TMPDIR
pip3 install -U torch typing_extensions --user
pip3 install -U esupar --user

P=$TMPDIR/esupar.$PJM_JOBID.$$.py
cat << 'EOF' > $P
import esupar
nlp=esupar.load("ain")
doc=nlp("オラ エアシㇼ アイヌウタㇻ クヌカㇻ")
import deplacy
print(deplacy.to_conllu(doc))
deplacy.render(doc)
EOF
env TOKENIZERS_PARALLELISM=false python3 $P
```

富岳のログインノードから`pjsub`してみたところ、ジョブ待ち・インストール・ダウンロード等も含め、20分ほどで以下の結果が得られた。

```
1	オラ	ora	SCONJ	接続詞	_	6	advmod	_	_
2	エアシㇼ	easir	ADV	副詞	_	6	advmod	_	_
3	アイヌ	ainu	NOUN	名詞	_	4	nmod	_	SpaceAfter=No
4	ウタㇻ	utar	NOUN	名詞	_	6	obj	_	_
5	ク	ku	PART	人称接辞	_	6	nsubj	_	SpaceAfter=No
6	ヌカㇻ	nukar	VERB	他動詞	_	0	root	_	SpaceAfter=No


オラ     SCONJ <══════╗ advmod
エアシㇼ ADV   <════╗ ║ advmod
アイヌ   NOUN  <╗   ║ ║ nmod
ウタㇻ   NOUN  ═╝<╗ ║ ║ obj
ク       PART  <╗ ║ ║ ║ nsubj
ヌカㇻ   VERB  ═╝═╝═╝═╝ root
```

「オラ エアシㇼ アイヌウタㇻ クヌカㇻ」という例文が、ちゃんと係り受け解析できているようだ。ただ、このやり方だと、manylinux2014_aarch64のバイナリをそのまま使ってしまうため、富岳のa64fxがイマイチ生かせていない。また、rustのスレッド周りを避けてしまっているので、tokenizersが遅くなってしまっている。つまり、[SuPar-UniDicと同じ問題を抱えている](https://qiita.com/KoichiYasuoka/items/e76c9d626941bdf7fe75)のだけど、やはり私の手には余る感じだ。誰か代わりに解決してくれないかなあ。
'user_id'としない場合のmigration・modelの俺的まとめ

個人的に頭にまとまったので忘備記録として、

## migration側

$table->foreignId()の中に普通は'親テーブル名_id'として外部キー設定をすると、'親テーブル名_id'が子のcolumnとして認識されると同時に、親と子で親テーブルIDと'親テーブル名_id'のcolumnが自動的に紐づくため、楽ちん。

### テーブルが自動的に認識され、user_id = 親のID が自動で認識されるパターン
$table->foreignId('user_id')->constrained();

がしかし、foreignId('user1')などcolumnを好きな名前にしたい！とすると上記のルールは通用しなくなり、laravel上でどのテーブルと接続するのかわからなくなる。そこで任意のcolumn名を付ける場合は、constrained()の引数の中に親のテーブル名を入力してlaravel側に認識させる必要がある。


$table->foreignId('user1')->constrained('users');
$table->foreignId('子のcolumn名として付けたい名前')->constrained('親テーブル名');

## model側

上記コードで親テーブルは認識したが、user1とどの親のテーブルのcolumnsと紐づくかまだ設定していない。そのため、model上でuser1とどの親のcolumnsとidを一致させるか設定しなければならない。
ここで親のテーブル主IDと紐づけるか、親テーブルの他のcolumnと紐づけるかでmodelの書き方が異なる。

### 親の主IDに紐づけるパターン
public function firstUser (){
    return $this->belongsTo(Parent::class, 'user1') //(親のエロクワントモデル、親と紐づける子のcolumn名)
}
ようは第三引数にわざわざ親のid columを設定しなくても勝手にuser1 = 親のIDと認識してくれる。

### 親テーブルの他のcolumnsに紐づけるパターン
public function firstUser (){
    return $this->belongsTo(Parent::class, 'user1', 'hoge') //(親のエロクワントモデル、親と紐づける子のcolumn名, 親テーブルが持つcolumn名)
}
単純に、user1 に親テーブルのどのcolumnを紐づけますか？というのを設定しているに過ぎない。(ここでは 子テーブルのcolumn'user1'と親テーブルのcolumn'hoge')が繋がったことを意味している。


誤字脱字修正
スクレイピングのエラー(FileNotFoundError: [WinError 2] 指定されたファイルが見つかりません。)対応

Pythonで実装したスクレイピングプログラムを実行した際に、
***FileNotFoundError: [WinError 2] 指定されたファイルが見つかりません。***
のエラーが出た際のエラー対応についてまとめました。

環境 
OS Windows 11
Anaconda  2023-09のバージョン
Python    3.11.5


>今回の背景
①プロジェクトメンバー1名にPythonで実装したスクレイピングツールを実行すると上記のエラーが発生した。
②他のメンバーの方は問題なくスクレイピングツールが実行でき、処理が正常終了した。

処理結果の画像
![Qiita.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1055346/1adbb5aa-e395-6e07-1d78-18d19ab0b51e.jpeg)

私が実践したこと
(1)pythonのパッケージツールであるpipのインストールlistを取得して頂いた。
(2)正常に実行できている私のpipのインストールlistとWinMergeアプリケーションで比較
(3)エラーが出たメンバーとseleniumライブラリのバージョンを合わせる。
(4)スクレイピングツールを実行し、エラーが再現できた。

エラーが出ないように以下の作業を実施
> 1.　以下のコマンドを実行する
```
pip install -U selenium
```
>2 以下のコマンドを実行し、seleniumのバージョンを確認する。
```
pip list | findstr selenium
```
2のコマンドの結果

![Qiita3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1055346/b52c1937-cb35-611a-3249-3a021a2742a9.jpeg)


***原因***

seleniumライブラリのver3.141.0のバグが原因でした。
![Qiita2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1055346/b4b7e2da-a223-3726-f126-2f2581dea1e2.jpeg)
【AWS】Systems ManagerでEC2へ接続する方法


セッションマネージャーを使うと、ブラウザのAWSマネジメントコンソールから、対象のEC2インスタンスにSSHの設定無しでアクセスすることができる。

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager-getting-started.html

### Session Manager を許可する IAM ポリシー の作成
1. IAM コンソールを開く
1. ポリシーを選択し、ポリシーの作成を選択
1. JSONタブを選択
1. 下記のJSONを張り付ける
    key-name を、使用する AWS KMS key の Amazon リソースネーム (ARN) に置き換え
    ```
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "ssm:UpdateInstanceInformation",
                    "ssmmessages:CreateControlChannel",
                    "ssmmessages:CreateDataChannel",
                    "ssmmessages:OpenControlChannel",
                    "ssmmessages:OpenDataChannel"
                ],
                "Resource": "*"
            },
            {
                "Effect": "Allow",
                "Action": [
                    "kms:Decrypt"
                ],
                "Resource": "key-name"
            }
        ]
    }
    ```
1. 次へ、次へを押す
1. 名前に```SessionManagerPermissions```を入れる
1. ポリシーの作成を押す

### Session Manager の許可ポリシーを付与した IAM ロール の作成
1. ロール -> ロールを作成を押す
1. AWS サービスで、ユースケースはEC2を選択する
1. 次へを押す
1. アクセス許可を追加で、```SessionManagerPermissions```にチェックを入れる
1. ```SecretsManagerReadWrite, AmazonSSMManagedInstanceCore, AmazonSSMManagedEC2InstanceDefaultPolicy```にチェックを入れる
1. 次へを押す
1. ロール名に、```MySessionManagerRole```を入れる
1. ロールの作成を押す
1. 作成したロールはインスタンスへアタッチする

10分ほど待つと、接続できるようになる。
再起動すると、つながるようになるかも。

## ec2-userでログインする方法
セッションマネージャーは、デフォルトでssm-userでログインし、/aws/以下のファイルのみマウントされている。そのため、SSHで立ち上げた環境設定をセッションマネージャーでは引き継げない。セッションマネージャーには、ルート権限が与えられておらず、カスタムスクリプトを実行できない場合がある。

1. セッションマネージャーを開く
1. 設定のタブを開く
1. Linux shell profileに下記を記載する
'''
bash
sudo su - ec2-user
'''

## まとめ
今回は、Systems Managerを用いて、セキュアにEC2へアクセスする方法を紹介した。
Ubuntu＆HHKB(日本語配列)でMacライクに英数⇔かなを切り替える方法

## 環境
- OS: Ubuntu 23.10 日本語 Remix
- キーボード: HHKB Professional HYBRID Type-S 日本語配列／墨
- 日本語入力: Mozc

## 設定方法
「設定」→「キーボード」→「キーボードショートカット」→「ショートカットの表示とカスタマイズ」をクリック
![keyboard1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8328/2b7481c5-4956-c46a-427a-4247ccace5c1.jpeg)

「独自のショートカット」をクリック
＋ボタンをクリックする。

### 日本語入力への切り替え
名前:任意でOK
コマンド: `ibus engine mozc-jp`
ショートカット: 選択後、スペースの右隣りのキーを押します

![Screenshot from 2024-02-07 11-32-50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8328/784c8bd7-11ee-8391-a749-a8b08de6e27f.png)

:::note warn
私の環境ではショートカットキーが何故か「Hangul」となっていますが使用に問題はありません。
:::

### 英数への切り替え
名前:任意でOK
コマンド: `ibus engine xkb:jp::jpn`
ショートカット: 選択後、スペースの左隣りのキーを押します
[linux]よく使うコマンドをPATHに登録してどこからでも呼び出せるようにする方法

## 🎯概要

<aside>
💡 頻繁に実行するコマンドは/usr/local/binに登録していつでも呼び出せるようにすると便利

</aside>

- コマンドを登録する

```bash
nano /usr/local/bin/{command-name}
chmod +x /usr/local/bin/{command-name}

# もしPATHが通っていない場合以下を実行
# export PATH=$PATH:/usr/local/bin
```

- コマンドの内容

（例）docker composeからコンテナを起動して立ち上げる場合（`run-container`）

```bash
#!/bin/bash

# コンテナ名を引数から取得
CONTAINER_NAME=$1

if [ -z "$CONTAINER_NAME" ]; then
  echo "コンテナ名を引数に指定してください。"
  exit 1
fi

# Docker Composeコマンドを実行
echo "Docker Composeで${CONTAINER_NAME}を処理しています..."
# 必要とあれば追加
# docker compose down
# docker compose build $CONTAINER_NAME
docker compose up $CONTAINER_NAME -d

# コンテナに入る
echo "${CONTAINER_NAME}コンテナに入ります..."
docker compose exec $CONTAINER_NAME /bin/bash
```

- コマンドを使用する

```bash
run-container {container-name}
```
alpineでpLaTeXを使えるようにする

# 概要
alpine linux上でpLaTeXを使えるようにする手順。ディストリビューションとして[Tex Live](https://www.tug.org/texlive/)を利用する。

# インストール
タイムゾーンの設定。
```bash
# apk add --no-cache tzdata
# cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
# apk del tzdata
```

依存パッケージのインストール。
```bash
# apk add --no-cache perl tar wget xz fontconfig
```

Tex Liveのインストール。
```bash
# cd /var/tmp
# cat <<EOF >texlive.profile
selected_scheme scheme-basic
tlpdbopt_install_docfiles 0
tlpdbopt_install_srcfiles 0
EOF

# wget -nv https://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz
# tar -xzf ./install-tl-unx.tar.gz --strip-components=1
# ./install-tl --profile=texlive.profile
# /usr/local/texlive/2023/bin/x86_64-linuxmusl/tlmgr install \
  collection-fontsrecommended collection-langjapanese collection-latexextra latexmk
```

# 動作確認
```bash
# cat <<EOF >test.tex
\documentclass{jsarticle}
\begin{document}
日本語のテスト
\end{document}
EOF

# /usr/local/texlive/2023/bin/x86_64-linuxmusl/platex test.tex
# /usr/local/texlive/2023/bin/x86_64-linuxmust/dvipdfm test.dvi
```

test.pdfができる。おしまい。
[CSS]Animation学びなおし

# keyword
- animation-property
- keyframe-property

#### サンプル

##### index.html
```
 <div class="spinner">
      <div class="spinner__dot">
        <div class="spinner__dot--first"></div>
        <div class="spinner__dot--second"></div>
        <div class="spinner__dot--third"></div>
      </div>
    </div>
```

##### index.scss
```
.rect {
  display: inline-block;
  width: 70px;
  height: 70px;

  background-color: black;
  // sk-bouncedelayというキーフレームアニメーションを1.4秒間適用します
  animation: sk-bouncedelay 1.4s;
  // easeによって始めと終わりがゆっくりとなるようにします
  animation-timing-function: ease;
  // アニメーション開始までの遅延を指定します
  animation-delay: 3s;
  // アニメーションの動作回数を指定したいとき
  // animation-iteration-count: 4;
  // アニメーションを無限に繰り返します
  animation-iteration-count: infinite;

  animation-direction: alternate;

}

// @keyframes {キーフレームの名前}
// 0%と100%の時のアニメーション状態を記述すること
// 途中(10%や50%)のアニメーション状態も記述可能。
@keyframes sk-bouncedelay {
  0% {
    transform: scale(0);
    background-color: orange;
  }
  50% {
    transform: scale(2);
    background-color: pink;
  }

  100% {
    transform: scale(1);
    background-color: yellow;
  }

  //  from ~ toでも0% ~ 100%の代わりになる
  // from {
  //   transform: scale(0);
  // }

  // to {
  //   transform: scale(1)
  // }
}
```



## Mixin
### 役割
アニメーションの設定を関数で表現できます。
scssファイルでのみ利用できます。

#### 例
##### index.scss
```
@mixin animation($name) {
  animation-name: $name;
}


// 呼び出し側
.sample {
 @include animation($name: sampleKey)
}

```

### メリット
- 呼び出し側でアニメーションの設定をしなくて良い
- mixinで作成した関数を利用するとデフォルト値が利用できる


#### 例2
##### index.scss
```
// 引数にデフォルト値を設定できるので、複数に同じ設定をしなくてよい
@mixin animation(
  $name,
  $duration: 1.6s,
  $delay: 3s,
  $iteration-count: infinite,
  $timing-function: ease
) {
  animation: {
    name: $name;
    duration: $duration;
    delay: $delay;
    iteration-count: $iteration-count;
    timing-function: $timing-function;
  }
  background: {
    color: black;
  }

  // 上記は以下のような設定でも同様に動作する。
  // animation-name: $name;
  // animation-duration: $duration;
  // animation-delay: $delay;
  // animation-iteration-count: $iteration-count;
  
}
```


## Mixinのファイル分割
##### 階層
```
- mixin
  - _mx-animation.scss
- index.scss
```

##### index.scss
```
// インポート
@use "mixin/mx_animation" as mxn;

// 利用
.sampleCls {
 @include mxn.animation($name: sample-keyframe);
}

```

- mixinファイルは_(アンダーバー)を先頭につけること(scssがほかのファイルにエクスポートされるファイルと認識させるため)