OmniAICreator/Qiita-1.07M huggingface dataset:
Rで一元配置分散分析（対応あり）をやってみる

ID01～ID10 の10人が、Ctrl、Type21、Type22 の３種類の何かを試し、100点満点の得点をそれぞれつけた場合について分析します。
データはこんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2533476/2cc5db75-a07f-89f4-5e50-552a343528f0.png)

まずはライブラリとデータの読み込み
```R
library("multcomp")
data <- read.delim("clipboard",header=T)
```

## 対応のある分散分析

モデルを定義して、IDを変数にすることで「対応あり」と解釈することができる。
参考：http://whitewell.sakura.ne.jp/R/Rstatistics-06.html
```R
summary(aov(F01~ID+type, data=data))
```
出力
```
            Df Sum Sq Mean Sq F value   Pr(>F)    
ID           9   4682   520.2  12.189 5.54e-06 ***
type         2    181    90.5   2.121    0.149    
Residuals   18    768    42.7                     
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ 
```
残念ながら、type による差はなさそうです。


## Tukeyの方法で、有意差のあるペアを見つける

分散分析せずに、最初からこっちだけのほうがいい説もあります。
参考：https://toukeier.hatenablog.com/entry/how-to-do-tukey-test/

```R
TukeyHSD(aov(F01~ID+type, data=data))
```
今回は不要な ID の組合せも全部計算されちゃうので、出力は省略。
PowerShellで画像取得効率化ツール作成

# 概要
　エビデンスとして、スクリーンショットを取る作業があります。
　１つ１つは単純で短時間で済む作業なのですが、量が増えると無視できない工数になります。

githubリンク
https://github.com/RYA234/ImageGetToolByPowerShell

### 従来の作業　
1.PrintScreenキーを押す
  2. ペイントを起動する
  3. 貼り付ける
  4. 名前を入力して保存する。
  5.完了

**1**分ぐらい掛かります。
### 本ツールを使った場合
1.PrintScreenキーを押す
2.マウスで該当する名前を入力する
3.完了

**20**秒に縮めることができます。
入力ミスを減らすことにもつながり手戻り工数を減らせます。
パターン化された定型作業に効果を発揮します。

# 開発環境
Windows：10
IDE:Windows PowerShell ISE


PowerShellを選定した理由：
windows7以上で動作環境が標準搭載されているためです。
スクリプトを動かすPCがお客様管理でしたので、余計なソフトをインストールできません。
powershellのスクリプトであれば環境を汚さず運用できるので、powershellを選択しました。



# フォルダ構成
3.フォルダ構成：
root/
├GetImage.ps1	:メインスクリプト
├data.txt	：データベース部分。
├使い方.txt	：
└output/	：画像の出力先。data.txtの１行目をフォルダ名になります。	
      └ ABC1234/	：data.txtの１行目がABC1234の場合

# データの構造
```data.txt 
ABC1234
画像 画像の保存先（フォルダ） 説明
工程1 大分類1 〇〇〇〇〇
工程2 大分類1 △△△△△
工程3 大分類1 □□□□□□□□□
_工程4 大分類1 ▼▼▼▼▼▼▼▼▼
*_工程5(数値入力) 大分類1 検査値を入力してください

```
１行目：フォルダ名
２行目：ヘッダー（データ処理には使わないです。編集しないようお願いします。）
３行目以降：データ部分になります。

１列目：画像名　拡張子は必要ないです。*はワイルドカードです。
２列目：画像の保存先：保存する画像のフォルダ名を入力します。
３列目：説明　注意点などがあればご記入します。

# 使い方
（１）Windows PowerShell ISEを起動して本スクリプトを開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/0fda7b83-595e-1a2f-9798-49b545d9bbf1.png)

（２）スクリプト実行ボタンを押します。
（３）PrintScreenボタン(赤三角のアイコン)を押します。
（４）リストボックスが表示され、保存したい画像の名称を選択します。
（５）画像が保存されます。
（６）スクリプトを終了するには　操作の停止を実行します。

使用例：GIFアニメ
![Image_get_no_wild.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/543f44f9-b1b3-595f-4212-fc95bfbce631.gif)
RedirectとFoward

RedirectとFoward

意味：特定のURLにアクセスするとページが切り替えられる2つの方法のこと。
　　　ページを切り替える主体が異なる。Redirectは主体がClientであるが、FowardはServerである。
　　　FowardはServerがClientのリクエストを処理するため、Clientが見るURLは変わらない。
　　　注意事項！！）Clientはユーザー（人間）ではなく、Browser（画面）を意味！

 
2. 処理過程の例（JSP）カード会社に連絡する顧客
   Redi 1. 顧客がカード紛失申告をしようと連絡したが（1回目の要請）、限度額照会の方につながる
   　　2. 顧客に紛失部の電話番号を知らせて、そちらに連絡するように言う（1回目の回答）
   　　3. 電話が再び紛失部につながる（2回目の要請）
    　　4. 紛失部で顧客のリクエストを処理する（2回目の回答）

　Fowa 1. 顧客がカード紛失申告をしようと会社に連絡したが（1回目の要請）、
　　　　　限度額照会の方につながる
 　　　　2. 限度額照会の方から紛失部に連絡して顧客の要請を伝える（顧客の要請は1度だけ）
　　　　3. 顧客の要求を処理する（2回目の回答）
新人研修課題 クローラー作成記1

## はじめに
こんにちは、株式会社エーアイセキュリティラボ　新入社員の[大桶](https://www.wantedly.com/companies/aeyeseclab/post_articles/406902)です。
4月に入社した後、主に業務に必要な知識の習得に励んでいます。
現在、知識習得の一つのまとめとして簡易的なクローラーを作成しており、その中で苦戦したところなどをqiitaで書いていこうと思います。
クローラーとはWeb上の文書や画像を自動的に巡回して収集するプログラムのことです。
今回の記事では、要件と必要なスキル、開始当初のクローラーのイメージについて書いていきます。


## 要件
今回作成する簡易クローラーの要件は以下のようになります。
知識の習得度合いを測ることを目的に要件を定義してもらいました。

- 指定されたURLを起点に巡回を実施する
- リンクを巡回できること
    - Webページからaタグを検出してリンクされたページにアクセスしていくことを指す
- フォームを巡回できること
    - Webページ内のformタグを検出し、何らかの内容をフォームに入力して適切なリクエストが送信できることを指す
- ログインを実施できること
    - ログインフォームにあらかじめ登録されたID/PWを入力し、その後発行されたセッションIDを管理してログイン状態を保つ
- 高速化のための並行実行ができること
    - Node.jsのイベントループによる並行実行を活用して高速化を行う
- 並行実行数を指定できること
- 巡回結果はデータベースに保存すること
- データベースにはURL、ページタイトル、ステータスコード、リクエスト、レスポンスを保存すること
- 巡回結果をCSV出力できること
- 巡回を停止・再開できること
- 開発言語はNode.jsを使用すること
    - AeyeScanは主にNode.jsで書かれているため、Node.jsに慣れる意味で開発言語にNode.jsが指定されている


## 必要なスキル
|名前 |簡単な解説 |
|---|---|
|JavaScript|インタープリタ型のプログラミング言語で、Webページでよく使用されるプログラミング言語として知られる。(参考: [mdn web docs](https://developer.mozilla.org/ja/docs/Web/JavaScript))|
|Node.js|Node.js はスケーラブルなネットワークアプリケーションを構築するために設計された非同期型のイベント駆動の JavaScript 環境です。([公式サイト](https://nodejs.org/ja/about/)より)|
|HTTP|HyperText Transfer Protocolの略。今回作成するクローラーでは「HTTPリクエストを送信→レスポンスから新たなリクエストの候補を作成」を繰り返します。|
|SQL|Structured Query Languageの略。データベースを操作するための言語。今回は送信したリクエストとレスポンスなどの情報をデータベースに保存するために使用します。|
|HTML|Hyper Text Markup Languageの略。Webページの作成に広く使用される言語。今回は巡回対象のページの作成に使用しました。|
|PHP|Webページの作成に使用される言語。今回は巡回対象のページの作成に使用しました。|
|正規表現|特定の並びの文字列を指定するための表現。今回は受け取ったレスポンスから特定のHTMLタグを取り出すためなどに使用します。|

私が入社してからの2ヶ月間は主に以上の項目の学習に努めておりました。まだまだ学ぶことは多いですが、学習内容の一つのまとめとして今回の簡易クローラーを作成します。


## 当初のクローラーのイメージ
今回の課題の前にすでにaタグからリンクを巡回するコードは作成しておりました。
そちらの課題が終わった時には、formタグの巡回も同じようにタグを取得して処理すればできそうで、ログインもformの一種なのでformタグが巡回できればこちらもできるだろうと甘く考えていました。

実際にはformタグからformを埋めるためにはaタグからリンクを取得するよりも検討すべきことが多く、またログイン処理も単純にformを埋めるだけでは終わらないのですが、ここでどのような問題があるのかは次回以降の記事で書いていきます。


## おわりに
今回の記事ではクローラーについての説明や開始当初の想定などについて書きました。
現在はコーディングを進めている途中で、開始当初には想定できていなかった問題に行き当たることもすでにありました。
次回の記事ではそのような問題の紹介と、それをどのように解決したかについて書いていこうと思います。
お名前ドットコムで取得したドメインをexchange onlineで受信する

レジストラ：お名前ドットコム
DNS：お名前ドットコム

## 目標
- お名前ドットコムで取得したドメインのDNSは、お名前ドットコムで。DNSレコードをMicrosoftにする。
- exchange onlineでアカウントを作成しメールを受信する。

## Micsosoft365の設定
1. Microsoft365にログイン
2. 「アプリ起動ツール」から「管理」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2709822/eea86680-7320-cbff-f6c1-251d6f560b3b.png)

3. 左メニュー「すべてを表示」から「設定」⇒「ドメイン」を選択
4. 「ドメインの追加」を選択
         「ドメインの追加」が表示されない場合はグローバル管理者の権限がないため、権限のある人に付与してもらってください。
5. exchange onlineに追加したいドメインを入力し、画面下部の「このドメインを使用する」を選択
6. ドメインを所有していることを確認するため、「ドメインのDNSレコードにTXTレコードを追加する」を選択し「続行」

**ここで一旦お名前ドットコムの設定に移ります**


## お名前ドットコムの設定
### ネームサーバの設定
① 「お名前.com Navi」の上部メニューから「ネームサーバの設定」⇒「ドメインのDNS設定」を選択し、対象のドメインにチェックを入れて「次へ」
② DNSレコード設定を利用する - 「設定する」を選択
③ ホスト名とVALUE、TTLを入力後「追加」をし、画面下部の「確認画面へ進む」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2709822/57902554-023f-5dc2-47e4-d238ddfe7d6c.png)

**ここで一旦microsoft365の設定に移ります**

## Micsosoft365の設定
7. 先ほどのTXTレコード設定内容画面（ドメインを確認する）の画面下部「確認」を選択し、ドメインのTXTレコードを確認する
8. ドメインの管理方法を選択します。今回はDNSをお名前ドットコムで設定するため、「自分のDNSレコードを追加する」を選択し「続行」
9. ExchangeとExchange Online Protectionにチェックを入れる。他は必要があれば入れるが、メールだけの場合はチェックは不要。
   MXレコード、CNAMEレコード、TXTレコードをメモしておく。

**ここで一旦お名前ドットコムの設定に移ります**

## お名前ドットコムの設定
1. 先ほど同様にDNSレコードの追加画面に遷移する（対象ドメインを間違えないように）
2. メモしておいたMXレコード、CNAMEレコード、TXTレコードを設定する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2709822/5ca0a148-5392-acbc-5a33-feb07c62c177.png)
3. 確認画面で正しいことを確認し、「設定する」

**ここで一旦microsoft365の設定に移ります**

## Micsosoft365の設定
10. 「続行」を押し、DNSが正しく設定されていることを確認する
11. ネームサーバの設定に問題なければ、セットアップが完了

## アクティブユーザの追加
1. 左メニュー「ドメイン」のページから、該当のドメインを選択する
2. ユーザタブを選択し、「アクティブユーザー」に移動する
3. ユーザーの追加を選択し、必要な情報を入力してアカウントの作成を行う
お名前ドットコムで取得したドメインをexchange onlineで受信する　その２

レジストラ：お名前ドットコム
DNS：Microsoft

## 目標
- お名前ドットコムで取得したドメインのレジストラ情報を変更し、DNSをMicrosoftに向ける。
- exchange onlineでアカウントを作成しメールを受信する。

## Micsosoft365の設定
1. Microsoft365にログイン
2. 「アプリ起動ツール」から「管理」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2709822/eea86680-7320-cbff-f6c1-251d6f560b3b.png)

3. 左メニュー「すべてを表示」から「設定」⇒「ドメイン」を選択
4. 「ドメインの追加」を選択
         「ドメインの追加」が表示されない場合はグローバル管理者の権限がないため、権限のある人に付与してもらってください。
5. exchange onlineに追加したいドメインを入力し、画面下部の「このドメインを使用する」を選択
6. ドメインを所有していることを確認するため、「ドメインのDNSレコードにTXTレコードを追加する」を選択し「続行」

**ここで一旦お名前ドットコムの設定に移ります**


## お名前ドットコムの設定
### ネームサーバの設定
① 「お名前.com Navi」の上部メニューから「ネームサーバの設定」⇒「ドメインのDNS設定」を選択し、対象のドメインにチェックを入れて「次へ」
② DNSレコード設定を利用する - 「設定する」を選択
③ ホスト名とVALUE、TTLを入力後「追加」をし、画面下部の「確認画面へ進む」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2709822/57902554-023f-5dc2-47e4-d238ddfe7d6c.png)

**ここで一旦microsoft365の設定に移ります**

## Micsosoft365の設定
7. 先ほどのTXTレコード設定内容画面（ドメインを確認する）の画面下部「確認」を選択し、ドメインのTXTレコードを確認する
8. ドメインの管理方法を選択します。今回はDNSをMicrosoftで設定するため、「自分の代わりにオンラインサービスを設定する」を選択し「続行」
9. ExchangeとExchange Online Protectionにチェックを入れる。他は必要があれば入れるが、メールだけの場合はチェックは不要。
11. Webサイトのレコードの追加画面では、Webサーバを運用している場合は「レコードの追加」等の設定をする必要があるが、今回はWebサーバはないので何も行わずに「続行」する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2709822/a3c58dfc-393c-4ade-402b-addf73fbaf81.png)
12. ネームサーバーを更新する画面では、お名前ドットコムのレジストラに登録するDNSサーバが表示されるのでメモしておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2709822/db88a9ff-0030-943b-5fec-b9266429ffff.png)

**ここで一旦お名前ドットコムの設定に移ります**

## お名前ドットコムの設定
1. DNSの設定画面を開く（お名前.com Naviトップページ⇒ネームサーバーの設定⇒ネームサーバーの設定）
2. ドメインの選択から、対象のドメインをチェック
3. ネームサーバーの選択では「その他のサービス」タブをクリック
4. 「その他のネームサーバーを使う」にチェックを入れ、先ほどのMicrosoftのDNSを設定し「確認」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2709822/8b3cf000-6e5f-725e-881a-8879569c6c0c.png)
5. 対象のドメインとDNS内容を確認し、「OK」
6. 設定後の画面で対象のドメインが「お名前.com」から「その他」に変わっていることを確認する。（その他をクリック）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2709822/56f667bf-a986-e612-3614-744cfff4085b.png)

**ここで一旦microsoft365の設定に移ります**

## Micsosoft365の設定
10. 「続行」を押し、DNSが正しく設定されていることを確認する（設定反映に時間がかかる）
googleのDNSは比較的早いため、心配ならコマンドで確認できます
~~~
nslookup -type=ns 対象のdomain 8.8.8.8
サーバー:  dns.google
Address:  8.8.8.8

権限のない回答:
対象のdomain      nameserver = ns1.bdm.microsoftonline.com
対象のdomain      nameserver = ns2.bdm.microsoftonline.com
対象のdomain      nameserver = ns3.bdm.microsoftonline.com
対象のdomain      nameserver = ns4.bdm.microsoftonline.com
~~~

11. ネームサーバの設定に問題なければ、セットアップが完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2709822/67e658da-20b8-7105-7da8-23eefaa5aade.png)

## アクティブユーザの追加
1. 左メニュー「ドメイン」のページから、該当のドメインを選択する
2. ユーザタブを選択し、「アクティブユーザー」に移動する
3. ユーザーの追加を選択し、必要な情報を入力してアカウントの作成を行う
sqlite3でPython変数を正しくバインドする方法

:::note warn
 記事の内容はあくまで個人の考えに基づくものであり、組織を代表するものではありません。
:::

sqlite3を使って開発をする中で、よろしくない方法でPython変数をバインドしていた。
社内のコードレビューでご指摘いただき、事前に気づくことができた。
備忘も兼ねてまとめておく。

# アンチパターン

もともと下記のような方法でPython変数をバインドしていた。
```python
import sqlite3

name = "test user"
age = 20

con = sqlite3.connect('example.db')
cur = con.cursor()
cur.execute("create table user(id integer primary key autoincrement, name text, age integer);")
cur.execute("insert into user(name, age) values('{}', {});".format(name, age))
con.commit()
con.close()
```
上記方法でも、エラーなく動作はする。

しかし、下記の通り、Pythonの文字列操作でクエリを組み立てる方法は、SQLインジェクション攻撃に対して脆弱であると[公式ドキュメント](https://docs.python.org/ja/3/library/sqlite3.html)で説明されている。

>SQL operations usually need to use values from Python variables. However, beware of using Python's string operations to assemble queries, as they are vulnerable to SQL injection attacks


:::note info
SQLインジェクション（英: SQL injection）とは、アプリケーションのセキュリティ上の不備を意図的に利用し、アプリケーションが想定しないSQL文を実行させることにより、データベースシステムを不正に操作する攻撃方法のこと。また、その攻撃を可能とする脆弱性のことである。[wikipediaより](https://ja.wikipedia.org/wiki/SQL%E3%82%A4%E3%83%B3%E3%82%B8%E3%82%A7%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3)
:::

# 正しい方法

公式ドキュメントに記載されている方法は2パターンある。

## パターン1: qmark style

- SQLの値を挿入する箇所に`?`を配置する
- cursorのexecute()メソッドの第二引数に`?`の数と同じ要素数のタプルを渡す
- `?`の数とタプルの要素数が一致しない場合、`ProgrammingError`が発生する

```python
cur.execute("insert into user(name, age) values(?, ?);", (name, age))
```

## パターン2: named style

- SQLの値を挿入する箇所に名前付きパラメータ(`:`と`任意の名前`を組み合わせたもの)を指定する
- cursorのexecute()メソッドの第二引数に名前付きパラメータ全てのキーを持つdictを渡す
- 名前付きパラメータがdictのキーに含まれない場合`ProgrammingError`が発生し、余分なキーについては無視される
```python
cur.execute("insert into user(name, age) values(:name, :age);", {"name": name, "age": age})
```
インデックスをどのカラムに作ればいいか迷った時の３つの設計方針

こちらの記事は

「いつも何となくカラムにインデックスを作成している」
「インデックスをどのカラムに作ればいいのかわからない」

という方に向けた記事です。

過去の私がそうだったので、この記事が上記のような方にとって役に立つ記事になれば嬉しい限りです。

※こちらの記事ではB-treeインデックスを対象としています。

## インデックス作成における３つの設計指針

前置きが長いのは苦手なので、早速結論です。以下の３つの設計指針が存在します。

### 指針1. 大規模なテーブルに対して作成する
データ量が多い場合にインデックスを作成しましょう。データ量が少ない場合はインデックスを作成しても効果がありません。

目安としては「レコード数が1万件以上」です。

※ただしストレージやサーバーの性能など環境要因によって変わるために、あくまでも目安です。

### 指針2. カーディナリティの高い列に作成する

インデックスを作るときは、カーディナリティの高い列を選ぶようにしましょう。

こちらの目安としては、特定のキー値を指定したときに、全体のレコード数の5%程度に絞り込めるだけのカーディナリティがあることです。

例えば３６５日のうち１日を指定するSELECT文を考えるとすれば、(1/365)*100=0.3％となるため、このカラムにインデックスを作成する意味はある、と判断できます。

#### 補足：カーディナリティとは？
カーディナリティとは、特定の列の値がどれくらいの種類を持つかということを表す概念です。

例えば性別というカラムであれば、「男性」「女性」「その他」の３種類が想定されるので、カーディナリティは３となります。



### 指針3. SQL文でWHERE句の選択条件、または結合条件に使用されている列に作成する

これは当然ですが、SQL文で検索条件や結合条件として使用されているカラムに対してインデックスを作成するようにしましょう。

## インデックスに関するその他の注意事項

### 主キーおよび一意制約の列には作成が不要
上記のように「主キーおよび一意制約の列には作成が不要」です。

DBMSは主キー制約や一意制約を作成するさい、内部的にはインデックスを作成しているからです。

### インデックスは更新性能を劣化させる
インデックスは作成すればするほど、更新性能を劣化させてしまいます。これはインデックスによって得られる恩恵とトレードオフであるため、極力無駄なインデックスは作成しないようにしましょう。

ちなみに更新性能を劣化させるのは、インデックスがテーブルとは独立してDBMS内に存在しているためです。これによりインデックスが作成されている対象のカラム値が更新されると、インデックス内に保持している値も変えなければいけなくなります。

### 定期的なメンテナンス（再作成）を行う

インデックスはテーブルのデータが更新されていくと、長期的には構造が崩れて劣化していくため、インデックスは定期的にメンテナンス（再作成）を行いましょう。

このコマンドは各種DBによって異なるので、適宜マニュアルを参照してください。

## 終わりに

以上が、インデックス設計の3つの指針です。

ちなみに今回の記事は以下の書籍をもとにしているので、詳しく知りたい方はよければどうぞ。

https://www.amazon.co.jp/%E9%81%94%E4%BA%BA%E3%81%AB%E5%AD%A6%E3%81%B6DB%E8%A8%AD%E8%A8%88-%E5%BE%B9%E5%BA%95%E6%8C%87%E5%8D%97%E6%9B%B8-%E5%88%9D%E7%B4%9A%E8%80%85%E3%81%A7%E7%B5%82%E3%82%8F%E3%82%8A%E3%81%9F%E3%81%8F%E3%81%AA%E3%81%84%E3%81%82%E3%81%AA%E3%81%9F%E3%81%B8-%E3%83%9F%E3%83%83%E3%82%AF/dp/4798124702
[Android] 簡単にSnackBarの背景色を変えてみる

# 初めに
今回SnackBarの背景色を変更したい時に悩むことがあったのでここにメモとして残そうと思う。

![Screenshot_20220617-154458 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1209385/3699876d-bad4-ccd9-e8ae-55e98530d5ac.png)



# 動作の内容

```kotlin
//MainActivity.kt

val snackbar = Snackbar.make(findViewById(android.R.id.content),"タイトルが入力されていません。", Snackbar.LENGTH_SHORT)
//R.color.errorはColor.xmlを参照する。
//詳しくは下記URLまで、
snackbar.view.setBackgroundResource(R.color.error)
snackbar.show()
```

##### Color.xmlについて
https://qiita.com/konifar/items/68f196dc7acacfcf40cf

# 動作の解説

##### スナックバーの作成
今回は、インスタンス化することにより、スナックバーの見た目を変更する。
```kotlin
val snackbar = Snackbar.make([表示される場所],[表示される文字], [表示される長さ])
```

##### 背景色の変更
```kotlin
snackbar.view.setBackgroundResource([カラーXMLの中に書いてある色を指定する。])
```

##### スナックバーの表示
```kotlin
snackbar.show()
```

# 参考資料

https://developer.android.com/training/snackbar/action?hl=ja

https://www.fixes.pub/program/44722.html
Mac で FastText のインストールが失敗する問題の対処法

いつからか分からないけど、Mac で [FastText](https://fasttext.cc/) のインストールがエラーになってしまうようになった。

```
src/autotune.cc:447:5: error: expected unqualified-id
　　　　　　　　LOG_VAL_NAN(currentScore, currentScore)
　　　　　　　　^
src/autotune.cc:25:14: note: expanded from macro 'LOG_VAL_NAN'
　　　　　　　　if (std::isnan(val)) { 
　　　　　　　　　　　　　　　　　　　　　　　　　　　^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/math.h:165:5: note: expanded from macro 'isnan'
　　　　　　　　( sizeof(x) == sizeof(float)  ? __inline_isnanf((float)(x))          \
　　　　　　　　^
1 error generated.
error: command '/usr/bin/clang' failed with exit code 1
```

GCC のヘッダがいかれちゃってるような感じ。

この解決方法は[ここ](https://freeman.vc/notes/installing-fasttext-on-an-m1-mac)にあった。

M1 Mac でエラーになるよ、って書いてあるけど、M1 Mac じゃない私の MacBook Air でもこの現象が発生する。おそらくは M1 Mac 用に GCC ライブラリをアップデートして、このバグが入り込んじゃったんじゃないかと推測する。

対処法は、結局悪さをしているライブラリ（ヘッダ）を一時退避する、ってだけ。

```
% sudo mv /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include user_include_temp
% pip install fasttext
% sudo mv user_include_temp /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include
```

上記を全然関係ないディレクトリ（例えば自分の Home ディレクトリ）でやれば良い。
マジックナンバー ってなに？

## 勉強前イメージ

わからん！

## 調査

### マジックナンバー とは

マジックナンバーとはファイルの先頭に記載されている識別子で、これをみることによってファイルの種類を判別することが出来ます。
先頭数バイトで記載されていて、そこに記載されている数値で判別します。
もちろん空のファイルとかだと識別子がない場合もあります。

そのマジックナンバー(識別子)でファイルの種類を確認する方法が `fileコマンド` になります。
fileコマンドは見たい対象のファイルの識別子を確認し、マジックナンバーのリストと照らし合わせて判別します。

例えば、シェルスクリプトなら以下のように表示されます。

```
[root@localhost ~]# file test.sh 
test.sh: Bourne-Again shell script, ASCII text executable
```

中が何も書かれていないファイルであれば以下のように empty と表示されます。

```
[root@localhost ~]# touch test1.sh
[root@localhost ~]# file test1.sh 
test1.sh: empty
```

fileコマンドで照らし合わせるマジックナンバーのリストはディストリビューションによっても違いますが
CentOS7 だと `/usr/share/file/magic` になります。

### 拡張子とマジックナンバーが違ったら？

- textファイルを用意する

`ASCII text` と表示されました。

```
[root@localhost ~]# cat test.txt 
test
[root@localhost ~]# file test.txt 
test.txt: ASCII text
```

- textファイルの中身をシェルスクリプトに変更

textファイルの拡張子で中身をシェルスクリプトにすると
fileコマンドではシェルスクリプトと判定されました。
これはファイルの中身(先頭)を確認して判定しているので、拡張子によらず中身が変わればfileコマンドでも判定が変わるようです。

```
[root@localhost ~]# cat test.txt 
#!/usr/bin/bash
echo "test"
[root@localhost ~]# file test.txt 
test.txt: Bourne-Again shell script, ASCII text executable
```

## 勉強後イメージ

拡張子の意義ってなんだろう・・・わかんなくなってきた
 
## 参考

- [fileコマンドとファイルのマジックナンバーについて](https://t-wakasugi.hatenablog.com/entry/2019/10/22/192843)
- [ファイルの内容を調べるには](https://atmarkit.itmedia.co.jp/flinux/rensai/linuxtips/018ditecfile.html)
SCSSで疑似Ripple Effectを実装する


![ezgif.com-gif-maker2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580849/73dc57e6-ae6a-12e9-74f8-a284f44e630d.gif)

## まずRipple Effect（リップルエフェクト）とは？

ReactやVueを用いたプロダクトでよく見る、クリックすると波紋（Ripple）が拡がるように見えるエフェクトで、マイクロインタラクションとして機能し、

- クリックした
- 押し込んでいる
- クリックが終わった

を視覚的に伝えることができます。これは、UXデザインの文脈でいえば、「[ニールセンの10のヒューリスティクス](https://hrism.hatenablog.com/entry/2022/01/12/073000)」の#1「システム状況の可視化」を効果的に実装することができます。

先述のように、ReactやVue、Angularといった、UI部分にも大きくタッチするフレームワークやライブラリでは比較的簡単に実装できますが、Webのプロダクトは上記以外のフレームワークをメインとしているケースも少なからずあります。今回ご紹介するのは、そういった場合に、**SCSS（SASS）のみで擬似的にリップルエフェクトを実装する**手段です。

## SCSSでの実装方法

`has-pseudo-ripple-effect`クラスがついたときに、その部分をクリックするとリップルエフェクトが走る、という方針で実装します。

また、下記では、平文のフォントの色（`$your-font-color`）を透過させたものがリップルの色になります。```#353535```の部分を書き換えたりすれば簡単に色を変えられます。

```scss
// リップルカラーの定義
$your-font-color: #353535;

@function color-Convert-Hex-to-RGB($value:$your-font-color) {
    @return (red($value),
        green($value),
        blue($value));
}

// クラス定義
.has-pseudo-ripple-effect {
    outline: 2px solid transparent;
    outline-offset: -4px;
    background-color: transparent;
    transition-property: outline background-color;
    transition-duration: 0.3s;
    transition-timing-function: ease-out;
    position: relative;
    z-index: 1;

    &::after {
        content: "";
        position: absolute;
        background-color: transparent;
        width: 100%;
        height: 100%;
        border-radius: 45%;
        transition-property: border-radius background-color transform;
        transition-duration: 0.2s;
        transition-timing-function: ease-in;
        top: 0;
        left: 0;
        pointer-events: none;
        transform: scale(0.9);
        z-index: -1;
    }

    &:hover {
        outline-color: rgba(#{color-Convert-Hex-to-RGB()}, 0.2);
        background-color: rgba(#{color-Convert-Hex-to-RGB()}, 0.2);
    }

    &:active {
        outline-width: 4px;
        outline-color: rgba(#{color-Convert-Hex-to-RGB()}, 0.6);
        background-color: transparent;
        overflow: hidden;

        &::after {
            overflow: hidden;
            border-radius: 0;
            background-color: rgba(#{color-Convert-Hex-to-RGB()}, 0.6);
            mix-blend-mode: multiply;
            transform: scale(1);
        }

    }

}
```

### 実装イメージ

![ezgif.com-gif-maker2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580849/73dc57e6-ae6a-12e9-74f8-a284f44e630d.gif)

### 弱点
![ezgif.com-gif-maker (2).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580849/2ed1db32-bb4e-0c25-e93d-03321207d99e.gif)
まんまるボタンなどに適用すると絶妙にキモい挙動になります。これは対応方法を探している途中なので、現段階では使い所を選んでご使用ください。直せたら追記します。
hashcatのルールファイルでワードリストを自動生成

「password」という単語と、「best64.rule」というhashcatのルールファイルを与えて、以下のようなワードリストを自動生成する：
```
password
drowssap
PASSWORD
Password
password0
password1
password2
...
password01
password02
password11
...
passw123
passwman
passwdog
1password
thepassword
dassword
massword
...
```

単語を与えれば自動でその単語をパスワードとして使われそうな形に加工してる。

# 作り方

```bash
hashcat --stdout --force <単語が入ったファイル> -r <ルールファイル>
```

今回は例として「password」という単語からワードリストを生成するので、origin.txtという名のファイル名に「password」と書き込んでおく：

```bash
┌──(kali㉿kali)-[~]
└─$ cat origin.txt
password
```

ルールファイルは/usr/share/hashcat/rules/にある：

```bash
┌──(kali㉿kali)-[/usr/share/hashcat/rules]
└─$ ls            
Incisive-leetspeak.rule                         generated2.rule
InsidePro-HashManager.rule                      hybrid
InsidePro-PasswordsPro.rule                     leetspeak.rule
T0XlC-insert_00-99_1950-2050_toprules_0_F.rule  oscommerce.rule
T0XlC-insert_space_and_special_0_F.rule         rockyou-30000.rule
T0XlC-insert_top_100_passwords_1_G.rule         specific.rule
T0XlC.rule                                      toggles1.rule
T0XlCv1.rule                                    toggles2.rule
best64.rule                                     toggles3.rule
combinator.rule                                 toggles4.rule
d3ad0ne.rule                                    toggles5.rule
dive.rule                                       unix-ninja-leetspeak.rule
```

個人的にはbest64.ruleをよく使ってます。

加工したい単語が入ったファイル（origin.txt）とルールファイル（/usr/share/hashcat/rules/best64.rule）が用意できたので、これらを次のように`hashcat`に与えてやる：

```code:bash
hashcat --stdout --force origin.txt -r /usr/share/hashcat/rules/best64.rule > newpass.txt
```

これで、新たなワードリストnewpass.txtが作成される（リダイレクトしないと、上記のコマンドの実行結果はすべて標準出力されてしまいます）。

# ルールファイルの内容について

上で使用したルールファイルbest64.ruleの中身には以下のような記述がある：

```
## nothing, reverse, case... base stuff
:
r
u
T0

## simple number append
$0
$1
$2
...
## high frequency overwrite at end
] $a
] ] $s
...
```

それぞれには意味があって

- `:` = 何もしない（nothing）
- `r` = 単語の文字列を反転させる（reverse）
- `T0` = 0文字目の大文字・小文字を反転（Toggle 0）
- `$1` = 単語の末尾に「1」を付ける
- `$0 $2` = 単語の末尾に「02」を付ける
- `$s` = 単語の末尾に「s」を付ける
- `] $a` = 単語の末尾の一文字を消して、末尾に「a」を付ける

詳しくは以下を参照：

https://hashcat.net/wiki/doku.php?id=rule_based_attack
【保存版】GCP Associate Cloud Engineer解説動画用リンク集【Google Cloud】

UdemyおよびYouTubeの動画内で紹介させて頂いたリンクについて、こちらでまとめております。
UdemyとYouTubeで公開している範囲が異なります。下記表に公開範囲をまとめております。

| チャプター | Udemy | YouTube |
|:-----------|:-----------|:-----------|
| 1.GCPとは  | 公開| 公開|
| 2.学習の進め方 | 公開| 公開|
| 3.GCPをはじめよう |公開（ハンズオン含む）| 公開（ハンズオン含まない） |
| 4.各種サービスの紹介 | 公開（ハンズオン含む）| 公開（ハンズオン含まない） |
| 5.まとめ |公開（問題演習含む）|公開（問題演習含まない）|

## 0.参考リンク
[Githubリンク(※本サイトと同じリンク集です)](https://github.com/maruchintech/udemy-gcp-ace/blob/main/README.md)
[Udemy: GCP Associate Cloud Engineerトレーニング](https://www.udemy.com/course/2022gcp-associate-cloud-engineer-google-cloud/?referralCode=26AD9FD65E32A13FA320)
[YouTubeチャンネル](https://www.youtube.com/c/Maruchintechch?sub_confirmation=1)

## 1.GCPとは
https://cloud.google.com/free/docs/aws-azure-gcp-service-comparison?hl=ja

## 2.学習の進め方
https://www.youtube.com/channel/UCxl3AizmA_6YC4lpeycP8kA

https://cloud.google.com/training/getstarted?hl=ja

https://cloud.google.com/certification/cloud-engineer?hl=ja

## 3.GCPをはじめよう
https://cloud.google.com/?hl=ja

## 4.各種サービスの紹介
https://cloud.google.com/appengine/docs/the-appengine-environments

https://cloud.google.com/functions/docs/tutorials/pubsub#functions-prepare-environment-python

https://cloud.google.com/blog/ja/products/gcp/optimizing-your-cloud-storage-performance-google-cloud-performance-atlas

https://storage.googleapis.com/gweb-cloudblog-publish/images/Which-Database_v07-10-21_1.max-2000x2000.jpeg

## 5.まとめ
### 問題演習
https://cloud.google.com/iam/docs/understanding-roles

https://cloud.google.com/iam/docs/understanding-custom-roles

https://cloud.google.com/pubsub/docs/overview

https://cloud.google.com/network-connectivity/docs/vpn/concepts/overview

https://cloud.google.com/storage/docs/lifecycle

https://cloud.google.com/storage/docs/storage-classes

https://cloud.google.com/bigtable/docs/overview

https://cloud.google.com/kubernetes-engine/docs/how-to/exposing-apps

https://cloud.google.com/run/docs/quickstarts

https://cloud.google.com/blog/ja/products/containers-kubernetes/when-to-use-google-kubernetes-engine-vs-cloud-run-for-containers

https://cloud.google.com/vpc/docs/create-modify-vpc-networks

https://cloud.google.com/vpc/docs/alias-ip

https://cloud.google.com/compute/docs/ip-addresses/reserve-static-external-ip-address

https://cloud.google.com/vpc/docs/bring-your-own-ip

https://cloud.google.com/foundation-toolkit

https://cloud.google.com/vpc/docs/create-modify-vpc-networks#expand-subnet

https://cloud.google.com/dns/docs/tutorials/create-domain-tutorial

https://cloud.google.com/billing/docs/how-to/export-data-bigquery

https://cloud.google.com/compute/docs/labeling-resources#common-uses

https://cloud.google.com/compute/docs/labeling-resources#labels_tags

https://cloud.google.com/bigquery/docs

https://cloud.google.com/kubernetes-engine/docs/concepts/autopilot-overview

https://cloud.google.com/storage

https://cloud.google.com/transfer-appliance/docs/4.0/overview

https://cloud.google.com/compute/quotas

https://cloud.google.com/products/calculator

https://cloud.google.com/compute/docs/sustained-use-discounts
Herokuデプロイ後にnode_modulesがおかしくなった。

これが原因だと特定はできていないのですが、`Nuxt.js`で`axios`で`BaseURL`を`Process.env`で指定するとき、
```nuxt.config.js
modules: [
    '@nuxtjs/axios',
  ],

  axios: {
    baseURL: process.env.BASE_URL
  },
```
こう記述することで、`localhost`ではなく`Heroku`の`url`を見てくれるようになるのですが、その後別のプロジェクトでnpmインストールした時に下記エラーが出て来るようになりました。
```
ERROR  (node:18) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 3)
| (Use `node --trace-warnings ...` to show where the warning was created)
```
`Vue` `Nuxt` `Express` `Sequelize` `Axios` `Postgres`を`docker-compose`で回していて、`node_modules`や`package-lock.json`を削除して`npm i`したり、動いていたgitブランチをプルしてきたりと色々試したのですが、反応なく。辿り着いた最後の手段です。
```settings.json
{
    "makefile.extensionOutputFolder": "./.vscode"
}
```

```
.PHONY: deps

deps:
	rm -rf node_modules
	docker compose run --no-deps --rm app npm ci
```

ルート直下に`Makefile`を置きターゲット`(deps)`を記述、`node_modules`を削除して`docker-compose`から`npm ci`させます。
ODレーティング

# はじめに
この記事は[Markovのレーティングシステム](https://qiita.com/takenakadx/items/a231dcf543f51856ccb2)の続きである。今回は、ODレーティング(Offense and Defense rating)について解説する。


# OD レーティング
ODレーティングではレートrを次のように定義する。
``` math
r_i = \frac{o_i}  {d_i}
```

ここで、$o_i,d_i$はそれぞれオフェンスレートとディフェンスレートであり、それぞれスコア行列$A = [a_{ij}]_{m \times m}$を利用して次のように決定される。

``` math
o_j = \frac{a_{1j}}{d_1} + \frac{a_{2j}}{d_2} + \cdots + \frac{a_{mj}}{d_m}
```

``` math
d_i = \frac{a_{i1}} {o_1} + \frac{a_{i2}}{o_2} + \cdots + \frac{a_{im}}{o_m}
```

ここで、オフェンスレートとディフェンスレートがそれぞれに依存しているため、cyclicalな問題になってしまう事が分かると思う。そこで、i番目のオフェンスレート$\vec{o}_i$とディフェンスレート$\vec{d}_i$を次のように決定し、収束するまでiを大きくすることでレートを導出する。

``` math
\vec{o}_i = A^T ( A \vec{o}_{i-1}^{\div})^{\div}
```
``` math
\vec{d}_i = A^T ( A \vec{d}_{i-1}^{\div})^{\div}
```

($\vec{x}^{\div} = (1/x_1,1/x_2,\cdots,1/x_m)^T$)
($\vec{o} = \vec{d} = \vec{e} = (1,1,\cdots,1)^T$)

## スコア行列Aについて
スコア行列はチームiがチームjから取った総得点を行列要素$a_{ij}$とする行列である。

オフェンスレートとディフェンスレートが収束するかどうかはこのスコア行列の性質に依存する。そこで、このスコア行列が必ず収束するように、スコア行列を変換する。

スコア行列をどのように変換するかというと次のような対角行列 $ R,C$を両側からかければいい。
``` math
[C]_{ii} = \frac{1}{[\vec{e}^T A]_i}
```
``` math
[R]_{ii} = \frac{1}{[AC \vec{e}]_i}
```

``` math 
A \rightarrow R A C
```
これを、Aの行和・列和が1になるまで繰り返す。
# 例題
[前回](https://qiita.com/takenakadx/items/a231dcf543f51856ccb2)と同様にRLCSのデータを利用してレートを導出する。
まず、スコア行列を
``` math
\begin{pmatrix}
 0  & 8 &  3 & 12 & 6 \\
 8 &  0 & 3 &  2 &  7 \\
 12 &  9 &  0 &  6 &  9 \\
 8 &  9 &  3 &  0 & 9 \\
 11 & 13 &  3 & 10 & 0
\end{pmatrix}
```
と定義する。
これを利用して、$\vec{r}_{20}$まで導出した。
20回目でのレートは以下のようになった。

|  order  |    team    |    rate    |  def rate  |  off rate  |
| ------- | ---------- | ---------- | ---------- | ---------- |
|    1    |     V1     |   1.683    |   0.721    |   1.213    |
|    2    |    RGE     |   1.254    |   1.071    |   1.343    |
|    3    |    OXG     |   0.978    |   0.958    |   0.937    |
|    4    |     SQ     |   0.910    |   1.233    |   1.122    |
|    5    |    VOLT    |   0.407    |   1.034    |   0.421    |

この結果を見ると、[Massey](https://qiita.com/takenakadx/items/d06921bc9e5741e1a1d6)や[Colley](https://qiita.com/takenakadx/items/c16d1515a08251dc552f)の方法で導出したレートと同じである事が分かる。
# 終わりに
今回、ODレーティングについて解説を行った。offenceとdefenceのレートを算出する方法は[Massey](https://qiita.com/takenakadx/items/d06921bc9e5741e1a1d6)の方法の時にも行ったので、その結果と今回の結果を見比べてみても面白いかもしれない。
[自分用メモ] よく使うGitコマンド

# 状況を確認する
```shell
git status
```

# 変更差分を確認する
```shell
git diff
```

# ステージングエリアに追加する
```shell
git add ファイル名orフォルダ名
```

# ステージングエリアへの追加をキャンセルする
```shell
git restore --staged ファイル名orフォルダ名
```

# 編集した未コミットのファイルを編集前の状態に戻す
```shell
git restore ファイル名orフォルダ名
```

# ステージングエリアに追加済みのものをコミットする
```shell
git commit -m "分かりやすいメッセージ"
```

# 直前のコミットのメッセージを修正する
```shell
git commit --amend
```

# ブランチを一覧する
```shell
git branch
```

# ブランチを削除する
```shell
git branch -D ブランチ名
```

# ブランチを移動する
```shell
git switch ブランチ名
```

# ブランチを新規作成＋移動する
```shell
git switch -c ブランチ名
```

# リモートブランチからローカルブランチを新規作成＋移動する
```shell
git switch -c ローカルブランチ名 origin/リモートブランチ名
```

# リモートリポジトリ（GitHub）にプッシュする
```shell
git push origin ブランチ名
```

# リモートリポジトリから最新情報を取得する
```shell
git fetch
```

# ローカルリポジトリのmasterを最新にする
```shell
git switch master
git merge origin/master
```

> `git merge` は、現在のローカルブランチに指定したブランチをマージする

# 現在のブランチに、最新化したmasterをマージする
```shell
git switch ブランチ名
git merge master
```

# 不要な追跡ブランチを削除する
```shell
git remote prune origin
```

# 未コミットの変更を一時退避する
```shell
git stash push
```

# 一時退避した変更を取り出す
```shell
git stash pop
```

# コミット履歴を見る
```shell
git log
```

> コミット履歴はコマンドよりIntelliJ IDEAや[Sourcetree](https://www.sourcetreeapp.com/)を使ったほうが見やすいです

# 直前のコミットをキャンセルする
```shell
git reset --soft HEAD^
```

> `--soft` を `--hard` に変更すると、コミット取り消しだけでなくファイルの内容もコミット前の状態に戻る

# 指定したコミットハッシュまで戻る
```shell
git revert 戻りたいコミットのハッシュ
```
mysqlの外部接続

①ｐｃのポートをあける（ファイアーウォール）
3306
https://support.borndigital.co.jp/hc/ja/articles/360002711593-Windows10%E3%81%A7%E7%89%B9%E5%AE%9A%E3%81%AE%E3%83%9D%E3%83%BC%E3%83%88%E3%82%92%E9%96%8B%E6%94%BE%E3%81%99%E3%82%8B

②mysqlのユーザーに接続許可をあたえる
通常最初はローカルホストのみなので％ですべてOKに変えるか新しいユーザを作成する
https://self-development.info/%e3%80%90%e3%82%b3%e3%83%94%e3%83%9a%e3%81%a0%e3%81%91%e3%81%a7ok%e3%80%91mysql%e3%81%b8%e3%81%ae%e5%a4%96%e9%83%a8%e6%8e%a5%e7%b6%9a%e3%82%92%e8%a8%b1%e5%8f%af%e3%81%99%e3%82%8b%e6%96%b9%e6%b3%95/

③8.1の最新版だとさらに
データベースにも許可を与える必要があるので注意する。
高校生が地域のパン屋さんで作るLINEBOT

## 高校生がLINEBOTを作ってみた
東京に本社があるMelon de melon さんでLINEbotを作らせていただきました！
では、どんな風に作ったのか作業工程を見ていきましょう！

目次

[１．お店紹介](#1お店紹介)
[２．ペルソナ分析](#2ペルソナ分析)
[３．LINEBOT](#3LINEBOT)
[４．感想](#4感想)

## 1.お店紹介
まず、私たちが作らせてもらったお店について紹介します。

商　店　名：Melon de melon
本社　住所:東京都中央区日本橋人形町2‐25‐15　MS日本橋ビル10階
特　　　色：メロンパンの専門店

島田市や掛川市にもありお手ごろな価格で本格的でおいしい色々な
メロンパンが食べられるお店です。季節限定メニューもあり
一年を通して様々なな種類のメロンパンが食べられます。

![images.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2662190/70b10258-09b9-e029-651a-b86930cf339c.png)


＜Melon de melonさんのこだわり＞
ふんわり柔らかなブリオッシュタイプのパン生地にアーモンドパウダーを加えたビス生地を使用した一番人気のプレーンメロンパンをはじめ、
ヨーロッパ産発酵バターをたっぷり使ったクロワッサンなど世界各国の美味しい高級食材を厳選して焼き上げました。

## 2.ペルソナ分析とカスタマージャーニーマップ
次にLINEBOTを作る過程で作った、ペルソナ分析についてです。
ペルソナとは商品を作る際に、買い手目線により近づくために
架空の人物を作りその目線になって考えることです。

年齢　　　　　　　　35歳
性別　　　　　　　　男性
職業　　　　　　　　会社員
移住地　　　　　　　静岡県掛川市
家族構成　　　　　　妻・娘
趣味　　　　　　　　休日の読書

加藤俊太。静岡県掛川市に住む３５歳の会社員。
休日には、昼食終わりに一人でコーヒーを飲みながら読書をすることを趣味としている。
年収は５００万くらいで、妻の加藤文子と娘の加藤きらりと三人家族で暮らしている。
　
＜カスタマージャーニーマップ＞
　
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2662190/f3a3fa23-d8d3-b354-b25a-108d0710276f.png)





## 3．LINEBOT
次に私たちが作ったLINEBOTについて紹介していきたいと思います。

リッチメニュー
リッチメニューとはLINEBOTを使う際にホーム画面の下にあるメニューの
ことを言います


![unnamed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2662190/72a1b0ea-0e5b-1ab2-af9e-bcd665e373ea.png)

つくるときの工夫：
作る際にはまず一番に見やすさを重視しました。パッと見たときにごちゃごちゃしていては
見にくいと思いシンプルで分かりやすくなるよう、配色などにもこだわりました。
そして、アイコンなどにもこだわりました。シンプルではあるけれどなるべく、
おしゃれに見えるように工夫をして、一番お客様が見たいであろうメニューを一番上に
大きくするなどの見やすさだけではなく、使いやすさにも重点を置いて
作りました。
![unnamed.png1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2662190/725578c2-355d-d5b0-9937-8ae5ba3488b5.png)

店舗一覧：このアイコンをタップすると公式のページに飛ぶことができどこの県にお店があるかがわかります。

![unnamed.png3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2662190/273d3184-ed46-44a4-14ff-8aa7f6e673a1.png)
SNS:このアイコンタップすると、Melon de melon さんのInstagramとTwitterの公式アカウント
　　に飛ぶことができます。

![unnamed.png4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2662190/e2a53ceb-446c-19ac-fa8f-bcb45bfcc585.png)


会社概要：このアイコンをタップすると、公式WEBサイトの会社概要に行くことができ、そこでは会社の住所や電話番号などの情報が載っています。

LINE友達登録はこちらかお願いします！！
![QR.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2662190/3569a386-8a6e-c2b1-ea04-248e781b40e9.png)



## 4．感想
最初はお店のこともよく知らずに作っていましたが、作っていく過程で
「こんなところにもあったんだ」「こんな商品も売ってるんだ」という
新しい発見がたくさんありました。
作っている過程でとくにリッチメニューを作る際などには、
誰が使うのか、どんな人に使ってもらいたいかなどを考えて作りました。
見えない相手のことを考えながら作るということがとても難しかったですが、
協力しながら作っていくことはとても楽しくいい経験に
なりました。写真を使ったりもして作ることでの良さなどにも気づけ
色々なことを参考にしてオリジナルの作品ができたと思います。
初めてのことで、わからないことだらけでしたが工夫を重ねて
作っていけたので良かったです。


[link-1]:
[link-2]:
[link-3]:
[link-4]:
[link-5]:
[link-6]:
Windowsで開発したPHPをCentOSにデプロイしたときに起きやすいエラー

|[../](https://qiita.com/taconana/items/d382d08a83a2a67f3b6a) |
|---|

Windowsで開発したPHPをCentOS Stream 8環境にデプロイしたときに、いくつかエラーやワーニングが出ていたのでメモしておく。軽微な内容です。

## DBの接続先を切り替えておくこと

DBの接続情報が異なる場合、例えば、dbname,user,passwordが異なると、以下の感じのエラーになる。
```
PHP Fatal error:  Uncaught TypeError: Return value of common\\integration\\PersistenceBase::pdo() 
must be an instance of PDO, null returned in /common/integration/PersistenceBase.php:45
```
環境を判別して制御を切り替えるように記述しておくこと。
```php
  public static function isWindows() : bool {
    return (DIRECTORY_SEPARATOR == '\\');
  }
  ...
  if (self::isWindows()){
  	...
  } else {
  	...
  }
```

## パス表現でバックスラッシュ(\\)を混在させないこと

パスを表現するとき、Windowsでは以下のようにバックスラッシュ(\\)を使ってもエラーにならないが、
```php
  require_once(__DIR__."/common\integration\CommonProps.php");
```
CentOSではエラーになる。
```
PHP Warning:  require_once(/common\\integration\\CommonProps.php): 
failed to open stream: No such file or directory in common/integration/HelloProps.php on line 3
```
スラッシュ(/)で統一しておこう。
```php
  require_once(__DIR__."/common/integration/CommonProps.php");
```
※誤記があったので修正しました。(バッククォート --> バックスラッシュ)

## $_SESSION['xxx']はisset()でチェックすること

Windowsでは、$_SESSION['xxx']で要素がない場合にもエラーにならなかったが、CentOSではエラーになる。
```php
  const THIS_CONTEXT = 'context-users';
  $context = $_SESSION[self::THIS_CONTEXT];
```
の場合、以下のようなエラーが出る。
```
PHP Notice:  Undefined index: context-users in /users/presentation/UsersContext.php on line 42, 
referer: http://kankeri.com/users/
```
isset()のチェックを挟むのを忘れてはいけない。
```php
  const THIS_CONTEXT = 'context-users';
  $context = null;
  if (isset($_SESSION[self::THIS_CONTEXT])){
    $context = $_SESSION[self::THIS_CONTEXT];
  }
```
※コメントをいただきましたが、上記はOS環境の違いではなく、PHPの設定(php.ini)の差異によるようです。`error_reporting = E_ALL`あたりの設定が影響している。

## エラーログには日本語を含めないこと

エラーログに日本語などマルチバイトのコードを含めると、ログが読みにくい。エンコードを指定できるエディタなどで開けば問題ないのかもしれないが、moreやcatでは読みにくい。大量のログの中で目立たせるために「■」を使っていたが「@@@」に変更した。
```php
  error_log('■ ' . $sql . ' --> ' . $cnt);
```
のような日本語の埋込みはやめた。
```php
  const TRACE_PREFIX = '@@@ ';
  error_log(self::TRACE_PREFIX . $sql . ' --> ' . $cnt);
```

|[../](https://qiita.com/taconana/items/d382d08a83a2a67f3b6a) |
|---|
絵文字で遊んでみるElixir

プログラムを学ぶにあたって、数字や文字だけより絵文字で遊んでみたら楽しいかな？
と言う観点で考えてみました


# いっぬを探せ！

この中に一匹だけ🐩がいます

```Elixir
List.duplicate("🐑",99) ++ ["🐩"]
|> Enum.shuffle()
|> Enum.chunk_every(10)
```

実行結果
```Elixir
[
  ["🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑"],
  ["🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑"],
  ["🐩", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑"],
  ["🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑"],
  ["🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑"],
  ["🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑"],
  ["🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑"],
  ["🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑"],
  ["🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑"],
  ["🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑", "🐑"]
]
```

このプログラムは
・🐑を99匹、🐩を1匹生成します
・100匹をシャッフルします
・10匹ずつの塊にします

# スロット
ランダムで10回スロットの抽選をします

```Elixir
defmodule Slot do
  defp reel, do: ["🐵", "🐱", "🐹"]
  defp lottery, do: reel() |> Enum.random()
  defp lotteries, do: Enum.reduce(1..3, [], fn _, acc -> acc ++ [lottery()] end)
  defp judgement?(reel, reels), do: Enum.all?(reels, fn x -> reel == x end)
  defp judge_disp(true), do: "🎯"
  defp judge_disp(false), do: "☹" 
  def run do 
    reels = lotteries()
    base_reel = List.first(reels)
    judge = judgement?(base_reel, reels) |> judge_disp()
    %{reels: reels, judge: judge}
  end
end

Enum.each(1..9, fn _ -> Slot.run() |> IO.inspect() end)
```

実行結果

```Elixir
%{judge: "☹", reels: ["🐹", "🐵", "🐱"]}
%{judge: "☹", reels: ["🐱", "🐹", "🐵"]}
%{judge: "🎯", reels: ["🐵", "🐵", "🐵"]}
%{judge: "☹", reels: ["🐱", "🐹", "🐵"]}
%{judge: "☹", reels: ["🐹", "🐵", "🐵"]}
%{judge: "☹", reels: ["🐵", "🐵", "🐹"]}
%{judge: "☹", reels: ["🐵", "🐵", "🐹"]}
%{judge: "☹", reels: ["🐹", "🐱", "🐱"]}
%{judge: "🎯", reels: ["🐵", "🐵", "🐵"]}

```

このプログラムは
・reel　絵文字のパターンをリスト化します
・lottery　上記の絵文字でランダムで１匹抽出します
・lotteries ３匹の絵柄の抽選結果を作成します
・judgement?　３匹が一致している時はtrueを返却します
・judge_disp　true,falseを絵文字に変換します
・run スロットを実行します。
　　　　・リール作成
　　　　・先頭のリールを取得
　　　　・先頭のリールとすべてのリールを比較してする→結果を元に絵文字に変換
　　　　・マップ形式で出力

・runを１０回繰り返す
GASを使ってEn→Ja翻訳するスクリプト

# GoogleAppsScript(GAS)でシートを別のシートに翻訳して反映する
簡単な文章なら翻訳で利用可能そうなスクリプトを作ってみました。
GoogleApppScript自体使うのが初めてなので、用例が微妙かなと思います。
スケジュールを組んで実行ができるようなので日次で実行して、英語用のSpreadSheetの内容が日本語に翻訳されてるように更新するくらいはできるのかもと思います。

本当は前回実行の差分だけとって更新があったセルだけを更新とか...もろもろできたらいいんですが、まだまだ初学者なのでいったんここまでで区切りを付けました。

適当に作ったので間違ってるかもです。

```javascript
function translateToJapanese() {
  //　Spread SheetのID
  const targetSpreadsheet = SpreadsheetApp.openById("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
  // 翻訳元のシート
  const originSheet = targetSpreadsheet.getSheetByName('English');
  // 翻訳結果の反映先のシート
  const destinationSheet = targetSpreadsheet.getSheetByName('日本語');

  const lastRow = originSheet.getLastRow();
  const lastColumnNumber = originSheet.getLastColumn();
  const lastColumn = getAlpabetColumnName(originSheet.getRange(1, lastColumnNumber));

  for (var row = 1; row < lastRow + 1; row++) {
    // 初期のカラムとして「A」を取得するようにする
    var columnAlphabet = "A"
    // カラムを右にずらしながら翻訳の実施
    for (var j = 1; j < lastColumnNumber + 1; j++) {
      var rangeText = columnAlphabet + row;
      var sourceRange = originSheet.getRange(rangeText);

      if (!sourceRange.isBlank()) {
        // 翻訳対象のテキストが含まれるセルの値取得
        var sourceDoc = sourceRange.getValue();
        // 翻訳結果を保存するセルの範囲を取得
        var destRange = destinationSheet.getRange(columnAlphabet + row);
        // 翻訳を実行（en → ja）
        var translate = LanguageApp.translate(sourceDoc, "en", "ja");
        // 翻訳結果をdestRangeに保存
        destRange.setValue(translate);
      }
      // 次に値が含まれるカラムをアルファベットで取得
      columnAlphabet = getAlpabetColumnName(sourceRange.getNextDataCell(SpreadsheetApp.Direction.NEXT));
    }
  }
  //Rangeからアルファベットの列名を取得する
  function getAlpabetColumnName(range) {
    return range.getA1Notation().replace(/\d/, '');
  }
}


```
ROS2でgnssとimuを利用して、自己位置推定(実装の備忘録）

## これ実装済み前提です
IMUドライバ
　https://github.com/technoroad/ADI_IMU_TR_Driver_ROS2
　参考 https://qiita.com/m2_labo/items/db32061bf3cbfd8f721e

GNSS 
　https://github.com/KumarRobotics/ublox/tree/galactic-devel
　参考 https://qiita.com/m2_labo/items/1ddf05a03a1871ff4a28

basic roboto localization
　https://automaticaddison.com/how-to-use-gps-with-the-robot-localization-package-ros-2/
　参考　作成中

## base_robot_localizationの設定とrobot_localizationの設定を変更
## ①ros2/src/basic_mobile_robot/basic_mobile_bot_v6.launch.py
変更前
```
remappings=[('imu', 'imu/data'),
                ('gps/fix', 'gps/fix'), 
                ('gps/filtered', 'gps/filtered'),
                ('odometry/gps', 'odometry/gps'),
                ('odometry/filtered', 'odometry/global')])
```

変更後
```
remappings=[('imu', 'imu/data_raw'),
                ('gps/fix', 'fix'), 
                ('gps/filtered', 'gps/filtered'),
                ('odometry/gps', 'odometry/gps'),
                ('odometry/filtered', 'odometry/global')])
```

## ②ros2/src/basic_mobile_robot/config/ekf_with_gps.yaml
134、284行目あたり
変更前
```
imu0: imu/data
```
変更後
```
imu0: imu/data_raw
```

## ③ros2/src/models/basic_mobile_bot_v1.urdf
変更前
```
  <joint name="imu_joint" type="fixed">
    <parent link="base_link"/>
    <child link="imu_link"/>
    <origin xyz="-0.10 0 0.05" rpy="0 0 0"/>
  </joint>

  <link name="imu_link"/>
```
```
  <joint name="gps_joint" type="fixed">
    <parent link="base_link"/>
    <child link="gps_link"/>
    <origin xyz="0.10 0 0.05" rpy="0 0 0"/>
  </joint>

  <link name="gps_link"/>
```
変更後
```
  <joint name="imu_joint" type="fixed">
    <parent link="base_link"/>
    <child link="imu"/>
    <origin xyz="-0.10 0 0.05" rpy="0 0 0"/>
  </joint>
  <link name="imu"/> 
```
```
   <joint name="gps_joint" type="fixed">
    <parent link="base_link"/>
    <child link="gps"/>
    <origin xyz="0.10 0 0.05" rpy="0 0 0"/>
  </joint>

  <link name="gps"/>
```

### ④ros2/src/models/basic_mobile_bot_description/model.sdf
変更前
```
<link name="imu_link">
```
```
<link name="gps_link">
```
変更後
```
<link name="imu">
```
```
<link name="gps">
```

## 実行＆確認
f9pとimuをPCに接続
```
cd ros2
colcon build
source install/setup.bash
```
以下すべて別のターミナルで実施
gpsとimuを入れ込んで、ekfさせるノードの実行
```
cd ros2
source install/setup.bash
ros2 launch basic_mobile_robot basic_mobile_bot_v6.launch.py
```
gpsノードの実行
```
cd ros2
source install/setup.bash
ros2 launch ublox_gps ublox_gps_node-launch.py
```
imuノードの実行(ttyACM1は実際のシリアルポートに合わせてください）
```
cd ros2
source install/setup.bash
ros2 launch adi_imu_tr_driver_ros2 adis_rcv_csv.launch.py mode:=Register device:=/dev/ttyACM1
```

確認
```
cd ros2
source install/setup.bash
rqt_graph
```
以下の画像が表示されればOK
![f9pADI.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2378923/e8c106d3-1f48-e93b-245f-76322a242767.png)


```
cd ros2
source install/setup.bash
ros2 topic echo /odometry/gps
```
反応あればOK！（反応なければデータいっていない）


次は出力を実環境に持っていく。
CentOS Stream 8にPHP PDOのMySQLドライバをインストールする手順

|[../](https://qiita.com/taconana/items/d382d08a83a2a67f3b6a) |
|---|

CentOS Stream 8でMySQLをインストールし、PHPからアクセスを試みるが、PDOの接続で「could not find driver」のエラーが出た。
```
could not find driver
Uncaught TypeError: Return value of PersistenceBase::pdo() 
must be an instance of PDO, null returned in ...
```
MySQLコンソールで接続できることは確認し、dsnやuser/passwordを間違えていないことは確認済み。
```
// dsn = mysql:dbname=test;host=localhost;port=3306;charset=utf8
// user = root
// password = xxx

$ mysql -uroot -p test
enter password: xxx
```
MySQLドライバは個別にインストールする必要があるということが分かった。初期状態ではpdo_sqliteしか入っていない。SQLiteは、非常に軽いオープンソースのDBMSらしい。

MySQLドライバ(pdo_mysql)を追加でインストールした。

```bash
$ php -m | grep pdo
pdo_sqlite

$ dnf install php-mysqlnd
php-mysqlnd  x86_64  7.4.19-2.module_el8.6.0+1075+ab70be85  appstream   193 k

$ php -m | grep pdo
pdo_mysql
pdo_sqlite
```
PHPからPDOで接続できるようになった。

|[../](https://qiita.com/taconana/items/d382d08a83a2a67f3b6a) |
|---|
絵だけで分かった気になるオブジェクト指向 トランザクションスクリプトとドメインモデル


ここでいうトランザクションスクリプトとドメインモデルは、PoEAAのドメインレイヤーの実装パターンの話です。

## ドメイン駆動設計とドメインモデル

最近流行りの **ドメイン駆動設計**は、一言で言うと、これです。
* ドメインモデルに、DIP（依存関係逆転の原則）を適用してアーキテクチャ転換する。
* により、ドメインモデルの精度をビジネスドメインに近づける。
* により、ビジネスドメインの変化に追従出来るようになり、反復開発が可能になる。

1行目が、分かりやすくデザパタチックになっているため、こればかり利用することを`軽量`とか呼んだりしますね。
`軽量`でも、保守性への貢献が非常に高く、それが実感されてる時代になった感じです。

ですが、`軽量`だけでも、少しだけ難しいんですよね。
なぜかというと、ドメイン駆動設計が、そもそもドメインモデルを前提としています。
日本では**ドメインモデルよりも、トランザクションスクリプトで開発される** ことが多かったのです。

その馴染みの無さからか、トランザクションスクリプトにDIP適用した感じの `軽量` が散見されています。

この記事では、そもそもドメイン駆動設計が前提にしてる、ドメインモデルってなんだよ。を絵で分かりやすく。

## トランザクションスクリプトとドメインモデル

![トランザクションスクリプトとドメインモデル.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29715/f802729e-09df-4f8d-7e6c-c556c0697e6e.png)
SwiftUIでLIstの背景色を変更する。


# はじめに
今回はSwiftUIで多用されるであろうListの背景色を変更する手順を紹介したいと思います。

Listに対して.backgroundColorで変更したい所ですが、現状は対応していないようで、 
 **UITableView.appearance()** を使って変更します。

```swift:ContentView
import SwiftUI

struct MenuList: Identifiable {
    var id = UUID()
    var name : String
}

struct ContentView: View {
    
    @State private var menuList = [
        MenuList(name: "menu1"),
        MenuList(name: "menu2"),
        MenuList(name: "menu3"),
    ]
    
    var body: some View {
        List {
            ForEach(menuList) { index in
                Button(action: {
                    print("セルが押されました")
                }) {
                    Text(index.name)
                }
                .foregroundColor(.black)
            }
        }
    }
}
```
<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2428088/f5bf71aa-8da0-f19f-f197-48f643c47d7e.png" width = 300％>

フォーマットではグレーの背景色が適用されます。

### 背景色を変えてみよう!!

コード全文です。
```swift:ContentView
import SwiftUI

struct MenuList: Identifiable {
    var id = UUID()
    var name : String
}

struct ContentView: View {
    
    @State private var menuList = [
        MenuList(name: "menu1"),
        MenuList(name: "menu2"),
        MenuList(name: "menu3"),
    ]
    
    var body: some View {
        List {
            ForEach(menuList) { index in
                Button(action: {
                    print("セルが押されました")
                }) {
                    Text(index.name)
                }
                .foregroundColor(.black)
            }
        }
        //追加
                .backgroundColor(.blue)
    }
}

//追加
extension List {
    
    func backgroundColor(_ color: Color) -> some View {
        UITableView.appearance().backgroundColor = UIColor(color)
        return self
    }
}

```
<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2428088/a32e6204-eb00-f23e-771d-5c69cfeb9983.png" width = 300％>

無事背景色を変更出来ました!!
extensionでメソッドを切り出す事で、backgroundColorとして設定出来るようにしました!!

以上です!!
Power Automate Desktopでブラウザ（カレンダー）にテキスト入力できないときの対処法

# はじめに
　Power Automate DesktopでDatePicker(下記画像参照ください)を操作する必要がありました。基本は「Webページ上のテキストフィールドに入力する」アクションでテキスト入力するべきとだと思います。
　しかし対象のWebシステムによってはテキスト入力がロックされていてテキスト入力できない場合があります。（というか最近自分が遭遇しました。）
　自分はここでだいぶハマってしまったのでこの場合の抜け道を紹介したいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711408/9fb5dcdb-9082-34ca-1b63-9dde31f9be72.png)


# 目次
<!-- タイトルとアンカー名を編集 -->
1. [今回実現したいこと](#Chapter1)
1. [実現方法](#Chapter2)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# 今回実現したいこと
　今回はこちらの[Datepickerサンプル](https://jqueryui.com/datepicker/)の日付の変換をしてみたいと思います。直接テキスト入力できずカレンダーのUIをクリックする形で入力しなければいけない場合を想定しています。

<a id="#Chapter2"></a>
# 方法
下記の手順で行えます。
- chrome「検証」でidを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711408/0b7605f2-be80-639a-20a3-2b1b59eaf4fb.png)

- PowerAutomateDesktopの「web ページでJavaScript関数を実行します」アクションで下記関数を入力します。document.getElementById("datepicker")では上記で調べたIdを入力してください。
value ="25/10/2022"の日付は、選びたい日付を入力してください。

```言語名:
function ExecuteScript() { document.getElementById("datepicker").value ="25/10/2022"}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2711408/6683582f-ce30-22a4-8ee6-78048c00caa2.png)

<a id="#summary"></a>
# まとめ
以上の方法で入力が行えると思います。
datepickerに限らず、「Webページ上のテキストフィールドに入力する」アクション、「ウィンドウ内のテキストフィールドに入力する」アクションでテキスト入力ができないときに試してみるといい方法だと思います。

同じことで困っている方の助けになればうれしいです。
不明点あればメッセージください。

<a id="#reference"></a>
# 参考文献・関連記事
- [この件に関してのPAD communityでの質問と回答](https://powerusers.microsoft.com/t5/Power-Automate-Desktop/How-to-Click-Datepicker-It-is-a-situation-where-you-cannot-enter/m-p/1615282#M14765)
ブラウザだけで複数コピペ保存・共有が出来るWebサイト

個人的に困っていた事を解消するサイトを作ったので紹介させて下さい。

# コピのすけとは
ブラウザだけでパソコンやスマホ間で、複数コピペの保存・共有が出来るサイトです。
入力内容は保存及び共有時に暗号化されます。

https://copypaste.stingrey.xyz/

# 困っていた事
ちょっとしたコピペの繰り返しや、他の端末(パソコンからスマホ等)に送りたい時、
アプリや連携サービスを使うまでも無いのになと、少し手間に感じていました。

このちょっとした手間を解消するために「コピのすけ」サイトを作成しました。

# 機能
#### 複数テキスト枠でのコピー機能
テキスト枠が複数あり、それぞれの内容を「コピー」ボタンでクリップボードにコピー出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297571/b8820f97-8b9c-cb07-9070-fbd864b497c1.png)

#### 保存
暗号化したコピー内容をブラウザに保存出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297571/1f2d9b5b-cfab-62d1-715a-fc8378dcae21.png)

#### URL共有
URLでコピー内容を共有出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297571/69c72b6a-da72-db74-9e54-9ee9e30aa7a8.png)

#### リアルタイム共有
複数端末でコピー内容をリアルタイムに共有出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297571/1dedf782-bac2-b163-5968-2f1080a7c57e.png)

# こだわりポイント
- スマホを考慮し、ボタン配置や操作性などの対策を行っています。
- テキストエリアがコピーする内容に応じて自動調整します。
- セキュリティを考慮し、暗号化対策を行い、安全性を高めています。


同じ事でお困りな方がいましたら、ぜひご活用下さい。

https://copypaste.stingrey.xyz/