OmniAICreator/Qiita-1.07M huggingface dataset:
anyenv + pyenv で WARNING: pyenv init - no longer sets PATH が発生する

# 現象

anyenv 経由で pyenv をインストールして、python バージョンをセットした。しかし、pyenv の python を見てくれない。

```terminal
$ pyenv versions
  system
* 3.9.4 (set by /Users/kaori/.anyenv/envs/pyenv/version)

$ which python
/usr/bin/python
```

また、ターミナル起動時に以下のワーニングが発生。

```terminal
WARNING: pyenv init - no longer sets PATH
```

## 実行環境
* MacBook Pro (13-inch, M1, 2020)
* OS Version 11.3.1 
* anyenv 1.1.2
* pyenv 1.2.27

本現象は、2021/05/10 時点で確認。

# 原因

[WARNING: pyenv init - no longer sets PATH](https://github.com/anyenv/anyenv/issues/89) にあった。
最近アップデートされた pyenv (v1.2.27) で shims にパスが通らなくなってしまった。


# 暫定対策

Issue にあるように、`anyenv init` の後で shims にパスを通す。
（anyenv init で PATH が上書きされるため、init の後に書く）
ただし、anyenv init 時点でパスが通ってないため、ターミナル起動時の WARNING は消えない。

```terminal:~/.zshrc
eval "$(anyenv init -)"
export PATH=$PYENV_ROOT/shims:$PATH
```

WARNINGが気になる場合は、1.2.26 時点の pyenv を `/Users/username/.anyenv/envs/`に展開すればよい。
ローカルでgitignoreしていたファイルも含めてBitriseでビルドしたい


# はじめに
今回は多くの企業で利用されているモバイルアプリCI/CDのBitriseを自分のアプリでも動かしてみようと思いBitriseで環境を構築しました。
その際GitHub上にプッシュしていないAPIキーの入ったplistファイルをBitrise上でどう生成させるかという壁に直面したのでそれを記事にしました。

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [Bitrise導入](#Bitrise導入)
2. [Secretsの設定とファイルの生成](#Secretsの設定とファイルの生成)

<!-- 各チャプター -->
<a id="#Bitrise導入"></a>
# Bitrise導入
今回はiOSアプリで開発をしたので以下の公式手順を元にBitriseにiOSアプリを追加します。
https://devcenter.bitrise.io/jp/getting-started/getting-started-with-ios-apps/

試しにビルドしましたがこの時点ではまだリモートリポジトリのファイルをBitriseに移しただけなので当然テスト時に下のエラーが発生します。

```
❌  error: Build input file cannot be found: '/Users/vagrant/git/[アプリ名]/Resources/Key.plist' (in target '[アプリ名]' from project '[アプリ名]')
```
今回はAPIキーの内容をKey.plistに保存するようにしています。
ここからビルド時にファイルKey.pistのファイルを生成するようにワークフローを追加していきます。

<a id="#Secretsの設定とファイルの生成"></a>
# Secretsの設定とファイルの生成

![スクリーンショット 0003-05-10 15.16.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/571358/da4c2d0d-64b4-1781-0901-35f4e41d6491.png)

BitriseのWorkFlowエディタ内のSecretsでシークレット環境変数を設定できるのでそこで.gitignoreしていたファイルの内容をコピペして貼り付けます。ただファイルの中身は数十行になっておりそれらを1行にして管理したかったのでbase64でエンコードした状態で値を設定しました。

base64については下の記事を参考にしてください。
https://qiita.com/PlanetMeron/items/2905e2d0aa7fe46a36d4

Expose for Pull Requests? の設定はデフォルトでは❎ になっていますがこれだとGitHubでプルリクエストを出してBitriseを回すときにこのSecretsが利用できずエラーになってしまうため✅ にします。


次にWorkflowでSecretsを利用してファイルの生成をします。

![スクリーンショット 0003-05-10 15.29.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/571358/6784a8ed-6f03-c3ba-de2f-0cc594286601.png)

Workflowsの項目で + ボタンからStepの追加をします。今回はファイルを生成するためにシェルスクリプトを利用するのでScriptという名前のステップを追加します。（画像でいうと上から3つめ）
アプリをクローンしてからファイルを生成しなければ実行は失敗するので必ずGit Clone Repositoryの後にステップを追加するようにしてください。

その後Scriptのステップを押すとScriptの内容を入力するテキストがあるのでそこで

```
echo ${NEWS_API_KEY_PLIST_BASE} | base64 --decode > [アプリ名]/[ignoreしたファイルパス]
```
を記述することによってテスト時にignoreしたファイルが生成され${NES_API_KEY_PLIST_BASE}の中身が書き込まれます。今回はbase64で値をエンコーディングしていたため書き込み時にデコードさせていますが特に必要がない場合は```|base64 --decode```の部分を消去して実行してください。

この状態でもう一度Bitriseを実行します。

![スクリーンショット 0003-05-10 15.42.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/571358/cdf2a447-ba80-0121-2746-29bf6770cda8.png)

![スクリーンショット 0003-05-10 15.44.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/571358/545ab6cf-582d-e06d-5118-da9de4c54383.png)

今度はビルド成功させることができました。

# さいごに
そもそもなぜこういった機密な情報をGitHub上にあげてはいけないのでしょうか。リポジトリを公開するならまだしもprivateリポジトリにしてセキュリティ面を保証していれば問題ないのではないでしょうか。

https://unit42.paloaltonetworks.jp/codecov-bash-uploader/

https://about.codecov.io/security-update/

2021年1月〜4月頃、CodecovのBash Uploaderを改竄し、不正に取得した認証情報を使用してGitHubに不正アクセスされるケースがありました。
このように安易にAPI情報や顧客情報などを残すとたとえセキュリティ面を保証していても認証情報がGitHub以外のツールから不正に盗まれ覗かれてしまう危険性があるので、今回のようにテスト時のみ機密情報の入ったファイルを生成し、GitHub上のレポジトリに残さないようにすることが重要だと思います。



# 参考文献
- [Bitrise](https://www.bitrise.io/)
- [base64ってなんぞ？？理解のために実装してみた](https://qiita.com/PlanetMeron/items/2905e2d0aa7fe46a36d4)
CodeDeployでEC2をデプロイするための設定作業

CodeDeployでEC2をデプロイできるように、事前の設定作業が必要なので、大まかな流れだけをまとめてみた。

## EC2側の設定
  - アタッチするIAMロールの設定  
  (参考: [Step 4: Create an IAM instance profile for your Amazon EC2 instances](https://docs.aws.amazon.com/codedeploy/latest/userguide/getting-started-create-iam-instance-profile.html))
    - ポリシーの作成
    - ロールの作成
  - タグの設定
  - CodeDeployエージェントをインストールする
  
### CodeDeployエージェント

#### CodeDeploy agentを起動しているか

```bash
sudo systemctl status codedeploy-agent
```

#### CodeDeployログの確認

```bash
sudo tail -f /var/log/aws/codedeploy-agent/codedeploy-agent.log
sudo tail -f /opt/codedeploy-agent/deployment-root/deployment-logs/codedeploy-agent-deployments.log
```

## CodeDeploy側の設定
  - アプリケーションの作成
  - デプロイグループの作成  
    EC2に設定したタグでデプロイ対象を指定する

## 参考
- [Configure an Amazon EC2 instance to work with CodeDeploy](https://docs.aws.amazon.com/codedeploy/latest/userguide/instances-ec2-configure.html)
- [Step 4: Create an IAM instance profile for your Amazon EC2 instances](https://docs.aws.amazon.com/codedeploy/latest/userguide/getting-started-create-iam-instance-profile.html)
コードで画面遷移 swift

#■何故コードで画面遷移するのか？
■画面が多い場合
Main.Storyboard上で画面遷移すると蜘蛛の巣上に遷移同士の線が重なってしまうため
見にくい

■ログイン画面があるアプリ
ログインした事がある場合とない場合で始まりの画面が違う
ない場合はログイン画面でIDやパスワードを打つ画面を表示する必要がある。
ある場合ログイン画面を飛ばして最初の画面を表示しなければならない。
こういった条件をコードで書く。

Main.Storyboardは基本使わない。

#■Main.Storyboardを消す。
まず初めに
そのまま消すとエラーになる。

この記事通りにするとエラー消えます！
めちゃわかりやすく載ってます！
https://qiita.com/sakiyamaK/items/cf95112a28e84b4c6dff

#■1
準備
今時は1つのStoryboardに1つのViewControllerが基本なので

FistViewControllerとFist.Storyboard用意 紐づける
SecondeViewControllerとSeconde.Storyboard用意 紐づける

互いのStoryboardにする事
■UIView用意
■is initial View Controllerにチェック

First.StoryboardにButtonを設置

#2
新たにRouter.swiftを用意
初めの画面を用意するshowRootメソッドを準備する。

``` swift
import UIKit

class Router {
    
   static  func showRouter(window:UIWindow?) {
        let vc = UIStoryboard.init(name: "First", bundle: nil).instantiateInitialViewController() as! FirstViewController
        let nav = UINavigationController(rootViewController: vc)
        window?.rootViewController = nav
        window?.makeKeyAndVisible()
    }
}
```

#3
AppDelegate.swiftにて先ほどのshowRouterメソッドを呼び出す。

``` swift
import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var window: UIWindow?
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        let window = UIWindow(frame: UIScreen.main.bounds)
        self.window = window
        Router.showRoot(window: window)
        return true
    }
}
```
ここまでで最初の画面は表示できている。
次にbuttonを押して画面遷移をしていくコードを書く

#4
Router.swiftに下記コードを足していく！

``` swift
    static func showSeconde(from: UIViewController) {
        let vc = UIStoryboard.init(name: "Seconde", bundle: nil).instantiateInitialViewController() as! SecondeViewController
        show(from: from, next: vc)
    }
  
//実際に画面遷移するコード  
//NavigationControllerならば横からスライド方式で遷移
//そうでなければModalで遷移下から画面が出てくる。
  static func show(from: UIViewController, next: UIViewController) {
        if let nav = from.navigationController {
            nav.pushViewController(next, animated: true)
        } else {
            from.present(next, animated: true, completion: nil)
        }
    }
```

#5
FistViewController

``` swift
import UIKit

class FirstViewController: UIViewController {

  //ボタンを紐づけてボタンを押したらshowSwcondeメソッドを呼ぶ
    @IBAction func nextButton(_ sender: Any) {
        Router.showSeconde(from: self)
    }
}
```

これでコードで画面遷移が行えます。

![コードで画面遷移gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1099804/266aac03-5101-f755-1391-391548b5dece.gif)

以上です。
これを基本にアプリ作成を行なっていった方が良さそうです！！
CloudWatchLogsの特定の文字列を含むログをSlackに転送する -後編-

#slackへのbotの導入やlambdaのアップロードまで

https://qiita.com/ms2geki/items/e808a9ae0e0003e5e796





#サブスクリプションフィルターの設定
対象となるロググループのコンソール画面よりサブスクリプションフィルターを設定します


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659469/1d1338df-7b08-c280-2c4c-1beffd7742b2.png)





#lambdaのトリガーとなる文字列を指定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659469/ee2e7930-2c02-8c20-d387-cb54933c195e.png)

今回はERRORもしくはerrorという文字列を含む場合に指定のlambdaを実行するように設定します。

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/FilterAndPatternSyntax.html

これで完成です。
データベースを操作する際に使うメソッドの整理

##この記事を書く目的
データベースを操作するメソッドの使い方、違いがうまく分からないので理解を深めると共に整理する為

##メソッド
query
prepare
bindParam
bindValue
execute
fetch
fetchAll


##データベースを操作する手順

①データベースに接続する。
②実行したいSQL文をセットする。
③SQLに対してパラメーターをセットする。【任意】
④実際にSQLを実行する。
⑤結果を取得する。【任意】
⑥データーベースから切断する。



##query
・指定したSQL文をデータベースに対して発行してくれる役割
・queryで実行まで行う（execute必要ない）

```php
// SQL文の組み立て（クエリの組み立て）
$sql = "SELECT * FROM member";
// queryの結果は配列で返ってくる
$stmt = $pdo->query($sql);
```

##prepare
・実行したいSQL文の中に「変動値」が入る場合に使用
・SQL文の実行準備を行い文オブジェクトを返す

```php
// SQL文の組み立て（クエリの組み立て）
$sql = "SELECT * FROM member WHERE email=?";
// 変動値をSQL文に含める準備
$stmt = $pdo->prepare($sql);
// 変動値を含んだSQLを実行
$stmt->execute(array($_POST(email));
```

##bindParam
・第二引数にはパラメータにバインドする「変数」を指定
・値を指定することはできない
・値の参照を受け取る
・execute()関数を使用した際にバインドが確定


```php
$stmt = $pdo->prepare("select * from member where email = :e-mail");
//セットする変数を定義
$email = example.jp;
//第二引数に変数をセットする
$stmt->bindParam("email",$email);
//結果表示
$stmt->execute();
$result = $stmt->fetch();
echo "email = ".$result['email']; // example.jp と表示
//以降は変数の中身を変えてexecuteを実行するだけ
$email = example_1.jp;
//結果表示
$stmt->execute();
$result = $stmt->fetch();
echo "email = ".$result['email']; // example_1.jp と表示
```
##bindValue
・変数の値をバインドするための関数

```php
$stmt = $pdo->prepare("select * from member where email = :e-mail");
//セットする変数を定義
$email = example.jp;
//第二引数に変数をセットする
$stmt->bindvalue("email",$email);
//結果表示
$stmt->execute();
$result = $stmt->fetch();
echo "email = ".$result['email']; // example.jp と表示
//変数の中身を変えても表示は一緒
$email = example_1.jp;
//結果表示
$stmt->execute();
$result = $stmt->fetch();
echo "email = ".$result['email']; // example.jp と表示
```

##execute
・PHPの標準関数でプリペアドステートメントを実行する際に使われる関数
・プリペアドステートメントは、SQL文で値が変わる可能性がある箇所に対して、変数のように別の文字列を入れておき、後で置き換える仕組み

```php
// SQL文の組み立て（クエリの組み立て）
$sql = "SELECT * FROM member";
// プリペアドステートメントの作成
$stmt = $pdo->prepare($sql);
// クエリの実行
$stmt->execute();
```



##fetch
・該当するデータを1行返す


![データベース](https://i.gyazo.com/6a80b70989690d4c7b0732efec9ba69d.png)


```php
$sql = "SELECT * FROM member";
// プリペアドステートメントの作成
$stmt = $pdo->query($sql);
// クエリの実行
$stmts = $stmt->fetch();
var_dump($stmts);
```

<結果>
array(6) { 
["id"]=> string(1) "1" 
[0]=> string(1) "1" 
["name"]=> string(6) "田中" 
[1]=> string(6) "田中" 
["age"]=> string(2) "40" 
[2]=> string(2) "40" }

##fetchAll
・該当するすべてのデータを返す

```php
$sql = "SELECT * FROM list";
// プリペアドステートメントの作成
$stmt = $db->query($sql);
// クエリの実行
$stmts = $stmt->fetchAll();
var_dump($stmts);
```

<結果>
array(2) { [0]=> array(6) 
{ ["id"]=> string(1) "1" [0]=> string(1) "1" 
["name"]=> string(6) "田中" [1]=> string(6) "田中" 
["age"]=> string(2) "40" [2]=> string(2) "40" } 
[1]=> array(6) { 
["id"]=> string(1) "2" [0]=> string(1) "2" 
["name"]=> string(6) "佐藤" [1]=> string(6) "佐藤" 
["age"]=> string(2) "35" [2]=> string(2) "35" } 
}

##学んだこと
・queryは実行まで行う（execute必要ない）
・bindParamとbindValueの違い
・値の参照の意味
・fetch,fetchAllの取得内容
勉強記録　DNS編

お久しぶりです。
最近ちょこちょこ勉強してたものをまとめます。

#復習
ドメイン名前区間
…木構造を使ったインターネットに接続されたホストもの名前の空間

#ネームサーバ
名前空間を管理するもの
…ドメイン名前空間を管轄して、名前に対する問い合わせに答えるサーバ
つまりURLのIPを教えてもらうこと

##ネームサーバの配置
各節（node）に配置される。それぞれの子だけを知っている
example.co.jpは隣に位置するnew.example.ne.jpのことは知らない

###ネームサーバの管理する範囲のことをゾーンという


自分が管理するゾーンの情報を持っているデータベース
基本的にはドメイン名とIPアドレスを持っている
ほかにも情報があるがそれらネームサーバーが持つ情報のことをリソースレコードという

|所有者      |---|そのドメインの名前|
|:----------|------|----------------|
|名前 　　　 |可変長|リソースレコードの名前|      
|タイプ      |16bit|リソースのタイプ|
|クラス      |16bit|クラス。通常は0*0001の価をとる|
|TTL        |32bit|リソースレコードのキャッシュ時間（秒）|
|RD長       |16bit|RDATAの長さ（オクテット）|
|RDATA      |可変長|リソースの中身|

|3min.co.jp |
|:----------|
|www|   
|0001|
|0001|
|8640|
|4|
|192.168.0.1|
 よくわからない…けど

「3min.co.jp」の「www」という名前のホストは「192.168.0.1」である。という意味らしい


##タイプについて
|コード　    |名前|意味|
|:----------|------|----------------|
|1|A|ホストのアドレス|      
|2|NS|そのドメインが管理するネームサーバ|
|5|CNAME|ホストの別名（エイリアス）|
|6|SOA|ゾーンの情報|
|12|PTR|ポインタ。逆引きに使用する|
|15|MX|そのドメインのメールサーバ|


こういうものなのか…

##Aレコード
ちょっと深堀
アドレスのこと、基本となるリソースレコードのこと
…ドメイン名とIPアドレスの対応を記述する.
ネームサーバはドメイン名の問い合わせに対してこのレコードを使用する

##NSレコード
そのドメインとそのドメインの下のドメインを管理するネームサーバ…？？？？？

そもそもDNSサーバにはDNSキャッシュ、権威DNSサーバがある
基本的にキャッシュサーバが受け答えをして、対応できないときに権威サーバに問い合わせる

権威サーバはゾーンファイルを見て、役割を果たすが、
その中の情報にNSレコードがある　　　ほう…
```
【ドメイン名】      IN NS         【DNSサーバ名】
```
書き方はこんな感じ

つまりドメイン名に対して、【DNSサーバ名】に尋ねて下さいっていう感じ
委託してるイメージで大丈夫だと思います。

ちなみに自分がサーバを立てたときはこの辺がちんぷんかんぷんでした（今も自信はないです）

##CNAMEレコード
NSレコードとちょっと違う役割の人
```
【別名】     IN CNAME            【元のドメイン名】
```
あだ名と本名みたいな関係

```
sub.example.com.     IN CNAME            hoge.example.com.
hoge.example.com.     IN A            198.51.100.2
```

```
sub.example.com.     IN A            198.51.100.2
hoge.example.com.     IN A            198.51.100.2
```

なるほど

##SOAレコード
権威サーバが担当するゾーン情報が記されている

```
【ドメイン名】     【クラス名】 SOA 【DNSサーバのドメイン名】 【連絡先】 (
        【シリアル番号】
        【更新チェックの間隔】
        【リトライ間隔】
        【問い合わせ諦めるぜ期間】
        【ネガティブキャッシュの有効期限】 )
```

```
@     IN SOA ns1.example.com. postmaster.example.com. (
        2014033101
        10800
        3600
        604800
        86400 )

```


【DNSサーバのドメイン名】以前は決まり文句らしいです
【DNSサーバのドメイン名】はそのゾーンファイルを使うDNSサーバを記す
その他はここに記されています…
https://wa3.i-3-i.info/word12285.html
（まとめようと思ったけど読んだほうが早いです…）


##PTRレコード
逆引き用のドメインだけど必須ではないので飛ばします

##MXレコード
そのドメインのメールサーバを定義するためのレコード

```
example.com.    IN MX 10     mail.example.com.
example.com.    IN MX 20     mail2.example.com.
```
そのドメインに対するメールが送られてきた際にメールをお届けするメールサーバを指定
ドメイン名『example.com』宛に来たメールは、メールサーバ『mail.example.com』に届けてください」を表現している




##nslookup

仕事でもよく使うし、きっとインフラの方々はよく使うと思います
DNSサーバと通信して名前解決の正引きと逆引きができる

名前解決…ドメイン名とIPアドレスの関連付けを調べること
自分でやってみたけど、ようやく何してるかわかりましたね…
（一応LinuCレベル1の取得の時に覚えた記憶があるだけ）

nslookupコマンドを使うと、DNS問い合わせを手動で実施できる。
詳細デバックモードにすれば、問い合わせと応答の中身を確認できる。
問い合わせるリソースレコードのタイプを変更できる。
問い合わせるサーバも変更できる。
devise gemのユーザー情報アップデートの方法

Railsでdeviseのgemをインストールし、ユーザー登録機能は実装し終わった方で、
## 登録情報の編集機能を実装したい方向けです。

注意点が２つあります。

- 編集時はcurrent_passwordが要求されること。
- application_controller.rbにメソッドを呼び出す記述が必要なこと。

## current_passwordの追加
編集画面のビューの入力フォームにcurrent_passwordを追加してください。
その他は設定したカラム名に準じます。

```user/registrations/edit.html.erb

<%= form_with model: @user, url: user_registration_path, local: true do |f| %>
略
<%= f.password_field :current_password %>

```

しかし、これだけではupdateを実行してもエラーは出ないのですが、updateもされません。
以下の記載が必要になります。


## application_controller.rbへ追記

updateアクションを加える場合、以下の追記が必要になります。

```controller/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?
  before_action :configure_account_update_params, if: :devise_controller?

  protected

  def configure_permitted_parameters　登録機能実装時に記述したメソッドです。
    devise_parameter_sanitizer.permit(:sign_up, keys: [:カラム名])
  end

  def configure_account_update_params　こちらがupdate機能実装の際に追記するメソッドです。
    devise_parameter_sanitizer.permit(:account_update, keys: [:カラム名])
  end
end

```
これでupdateアクションに対してもストロングパラメーターを設定、updateが実行できるようになります。

なお、この追記に関しては
rails g devise:controllers users
を実行した際に生成される既成のdeviseコントローラー(registration_controller.rb)内に書いてあります。

以上です。
参考になれば幸いです。
【AWS】セキュリティグループとネットワークACL

#プログラミング勉強日記
2021年5月10日

#セキュリティグループ
　インスタンスへのトラフィックのアクセス可否を設定する。なので、EC2のアクセス制御はセキュリティグループによって行う。EC2に対する権限の設定はIAMで行うが、どこのPCが・どのユーザがサーバーにアクセスできるのかということはセキュリティグループが通信の制御をしている。

　例えば、EC2インスタンスをWebサーバーにしてホームページを作った場合、HTTPのトラフィックのアクセスが許可されていないとみることができない。以下のような設定だと、セキュリティグループはポート22のSSHのみを許可している。つまり、ホームページを作ってもホームページにアクセスできない設定状況になっている。EC2インスタンスの内部の操作をするためにはSSHプロトコルを使ってアクセスをする。
　

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/c95fbcbd-6f02-11d2-3033-32534b2fcb92.png)

　それぞれのEC2インスタンスに対して1つずつセキュリティグループを設定する。同じ設定であれば1つのセキュリティグループで複数のEC2インスタンスに共有して使うこともできる。


#ネットワークACL
　トラフィック制御の1つでサブネットに対するトラフィック制御を実施する。要するに、仮想ネットワーク自体に制御するためにはネットワークACLを使う。


#セキュリティグループとネットワークACLの違い
　トラフィック設定はセキュリティグループかネットワークACLを使う。

| セキュリティグループ設定 | ネットワークACLs設定 |
|:--:|:--:|
| サーバー単位で適用する | VPC/サブネット単位で適用する |
| ステートフル(インバウンド※1 のみの設定でアウトバウンド※2 も許可される) | ステートレス(インバウンド設定のみではアウトバウンドは許可されない) | 
| 許可のみをin/outで指定 | 許可と拒否をin/outで指定 |
| デフォルトではセキュリティグループ内通信のみ許可 | デフォルトではすべての通信を許可 |
| すべてのルールを適用 | 番号の順序通りに適用(複数の通信制御を設定した場合、上のだけ適用されて後ろは適用されないこともある) |

※1 インバウンド：トラフィック制御の入り口(外からEC2インスタンスにくるトラフィック)
※2 アウトバウンド：外部に通信を出すこと(EC2インスタンスから外に通信を出す)
【paiza Aランクレベルアップメニュー】 陣取りの手間 Java編

paiza Aランクレベルアップメニュー
https://paiza.jp/works/mondai/a_rank_level_up_problems/problem_index?language_uid=java

Javaで挑戦中。22問目で詰まっている。
https://paiza.jp/works/mondai/a_rank_level_up_problems/a_rank_camp_step5
うまく？マークが記載されないのだが、毎回打ち直してエネルギー使ってるのが最高に非効率だと気が付く。
「さあここから処理を考えるぞ」というタイミングで疲れ切っていてヒントを呑み込めないのはどうかと……

・毎度コードを書き直すのが大変
・せっかくアカウント持ってるんだからQiita使え
・問題集は解答を外部に記載しても良い
　ということなので、まずは21問目の回答を備忘録として置いておく。
https://paiza.jp/works/mondai/a_rank_level_up_problems/a_rank_camp_step4

```java:Main.java
import java.util.*;
import java.util.Queue;
import java.util.ArrayDeque;


public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        int h = sc.nextInt();
        int w = sc.nextInt();
        String map[][] = new String[h][w];  //陣
        
        Queue<XY> q = new ArrayDeque<>();   //キュー
        
        for(int i=0; i<h; i++){ //初期化
            String temp = sc.next();
            for(int j=0; j<w; j++){
                map[i][j] = String.valueOf(temp.charAt(j));
                if(map[i][j].equals("*")){
                    map[i][j] = "0";    //最初は0に書き換える
                    q.add(new XY(i, j, 1)); //スタート地点（初期値のy, x, 1が入っている）
                }
            }
        }
        
        while(q.size() > 0){
            XY xy = q.poll();
            int y = xy.y;
            int x = xy.x;
            int d = xy.d;
            
            if(y > 0 && map[y-1][x].equals(".")){   //上
                map[y-1][x] = String.valueOf(d);
                q.add(new XY(y-1, x, d+1));
            }
            if(y < h-1 && map[y+1][x].equals(".")){   //下
                map[y+1][x] = String.valueOf(d);
                q.add(new XY(y+1, x, d+1));
            }
            if(x < w-1 && map[y][x+1].equals(".")){   //右
                map[y][x+1] = String.valueOf(d);
                q.add(new XY(y, x+1, d+1));
            }
            if(x > 0 && map[y][x-1].equals(".")){   //上
                map[y][x-1] = String.valueOf(d);
                q.add(new XY(y, x-1, d+1));
            }
        }
        
        for(int i=0; i<h; i++){ //出力
            for(int j=0; j<w; j++){
                System.out.print(map[i][j]);
            }
            System.out.println("");
        }
    }
}

class XY{
    int y;
    int x;
    int d;
    
    XY(int y, int x, int d){
        this.y = y;
        this.x = x;
        this.d = d;
    }
}
```

参考：
https://qiita.com/aja_min/items/fed640d6835eb343eedf
https://jpliterature.hatenablog.com/entry/java-breadth-first-search-1

「あ、そうか。クラスを作れば三次配列めいたことができるのか……」
「お前は大学やオンラインスクールで何をやっとったんじゃ」

　使わないと忘れるということですね。いやはや。
バリデーションをまとめる方法

#はじめに
アウトプット用に書かせて頂きます。

ユーザー管理機能を実装するためにuserテーブルにバリデーションをかけ、コードレビューをして頂いた回答で同じバリデーションをかけるときはまとめる事ができるという事を知りました。


#with_options  do
下記の記述でまとめる事ができます。

```.rb
with_options do
#記述
end
```

ではまずwith_optionsを使わないコードを記述します。

```user.rb
class User < ApplicationRecord
 
      validates :nickname, presence: true
      validates :birth_day, presence: true
      validates :first_name, presence: true 
      validates :last_name, presence: true
      validates :first_name_kana, presence: true
      validates :last_name_kana, presence: true
end

#presence trueとは空では登録できないようにするバリデーション

```

全てprecence: trueと同じバリデーションをかけているのでひとまとめにします。

```user.rb
class User < ApplicationRecord

    with_options presence: true do
      validates :nickname
      validates :birth_day
      validates :first_name
      validates :last_name
      validates :first_name_kana
      validates :last_name_kana
    end
end
```
これでひとまとめにする事ができます。
しかしprecence true以外にもバリデーションをする時が多いと思います。

```user.rb
class User < ApplicationRecord
 
      validates :nickname, presence: true 
      validates :birth_day, presence: true 
      validates :family_name, presence: true,
                             format: { with: /\A[ぁ-んァ-ヶ一-龥々]/ }
      validates :first_name presence: true,
                            format: { with: /\A[ぁ-んァ-ヶ一-龥々]/ }
      validates :family_name_kana, presence: true,
                                   format: {with: /\A[\p{katakana}　ー－&&[^ -~｡-ﾟ]]+\z/ }
      validates :first_name_kana, presence: true, 
                                  format: {with: /\A[\p{katakana}　ー－&&[^ -~｡-ﾟ]]+\z/ }
      
end
```
上記の記述で下記の正規表現を使いました。

|         正規表現                     |     意味                  | 
|:------------------------------------|:-------------------------|
|/\A[ぁ-んァ-ヶ一-龥々]/                  | 全角ひらがな、全角カタカナ、漢字 |  
|/\A[\p{katakana}　ー－&&[^ -~｡-ﾟ]]+\z/                      | 全角カタカナ　　　　

このような時にwith_optionsの中にwith_optionsを入れ子のようにする事ができます。

```user.rb
class User < ApplicationRecord
 
    #全行にpresence: trueをする
    with_options presence: true do
      validates :nickname
      validates :birth_day

      #この２行だけformat: { with: /\A[ぁ-んァ-ヶ一-龥々]/ }
      with_options format: { with: /\A[ぁ-んァ-ヶ一-龥々]/ } do
       validates :family_name 
       validates :first_name
      end
      #この２行だけ {with: /\A[\p{katakana}　ー－&&[^ -~｡-ﾟ]]+\z/ }
      with_options format: {with: /\A[\p{katakana}　ー－&&[^ -~｡-ﾟ]]+\z/ } do
       validates :family_name_kana
       validates :first_name_kana
      end
     end
end
```

以上です。
Model Zoo コレクション

AIモデルがまとめられているホームページ（Model Zoo等）のメモを残しておきます。
ほぼ自分用のまとめ記事です。他にも良いホームページを見つけたら、随時追加していきたい。

もし下記の他に有用なホームページをご存じの方がいらっしゃいましたらぜひコメントで教えて下さい！

# AIモデルまとめサイト（Model Zoo等）
TensorFlow Model Garden
https://github.com/tensorflow/models

ModelZoo
https://modelzoo.co/

paperswithcode.com
https://paperswithcode.com/

PINTO_model_zoo
https://github.com/PINTO0309/PINTO_model_zoo

genforce Model Zoo
https://github.com/genforce/genforce/blob/master/MODEL_ZOO.md

Neural Network Libraries（事前学習済みモデル）
https://nnabla.readthedocs.io/en/latest/python/api/models.html

# おまけ
Netron
https://netron.app/
※AIモデルの内部構造をビジュアライズしてくれるツール
android studioで起こったpodエラーの対処


#android studioにてflutter iosをrunすると以下のエラーが発生

```
The sandbox is not in sync with the Podfile.lock. 
Run 'pod install' or update your CocoaPods installation.
```

エラー内容を翻訳すると
####「サンドボックスはPodfile.lockと同期していません。 「podinstall」を実行するか、CocoaPodsインストールを更新します。」
とのこと、、、



#解決法

android studioのターミナルからプロジェクトディレクトリ/iosフォルダに行き

podの存在を確認

```
$ pod outdated
```

すると

```
Updating spec repo `trunk`
```
と表示されたのでpod自体はインストールされているようで

```
$ pod update
```

を実行！
自分の場合はpodファイルがあったので updateするとビルドに成功しました！

もしpodがインストールされていなかった場合は

```
$ pod install 
```

を実行してインストールしてください。
blenderの座標軸方向と、視点切り替えについて

##はじめに
blenderの座標軸方向と、視点切り替えについて、これまで、漫然と覚えていたことを、自分なりに整理してみた。

##初期画面における座標軸
![20210509-06-01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684864/50188679-b02f-fc55-dd6d-2c82518c6fd1.jpeg)
初期画面の、立方体が置かれた座標軸は、図のようになっている。blenderの３Ｄビューポート右上に、常に向きは表示されているが、分かりやすく書き込んでみた。
ｘ軸の正が手前、ｙ軸の正が奥、となっており、直感的な向きとずれているが、blenderは、３次元座標に右手系を使っているので、このような配置になる。

##スザンヌを置いた時の、ローカル座標
![20210509-06-02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684864/aa115006-f6aa-3dd8-7dbc-64195a4a7f72.jpeg)
立方体を削除して、スザンヌを置いてみる。
この際、スザンヌのローカル座標は、グローバル座標を引き継ぐので、ローカル座標のｙの正方向が、スザンヌにとっては後ろ向き、ローカル座標のｘの正方向が、スザンヌにとっては左向きとなる。
直感的には、スザンヌの顔の向きが、ｘ軸正方向のように思えるが、そうではない。
ただ、モデリングをする際には、この配置は望ましいものとなる。モデリングでは、左右対称を良く利用するが、blenderでは、ミラーモディファイアのデフォルトで対称としているのは、ｘ軸となっている。そして、ｘ軸の正が右に向かうようにモデルを置くと、モデルの正面方向は、ｙ軸の負の方向、つまり、図の状況となる。

##テンキーによる視点切り替えについて
「１」を押した場合
![20210509-06-03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684864/e808d25e-5a7c-04ac-daf1-2fbda65bdbe6.jpeg)
モデルが、ｙ軸負の方向を向いているので、その正面となるのは、ｙ軸の正方向となる。テンキー「１」によって、視点がｙ軸の正方向へと向かう。
この時、ｘ軸正が右、ｚ軸正が上になる

「３」を押した場合
テンキー「３」は、「１」の状態から右方向へ動いて、スザンヌを横から見ることになる。
![20210509-06-04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684864/ffcf75f2-f8bb-511f-0981-94356c6f9715.jpeg)
テンキーにおける、「１」と「３」の位置関係の通りにカメラが動く訳である。
この時、ｙ軸正が右、ｚ軸正が上になる。

視点と座標軸方向との関係で言えば、「１」の時には、ｙ軸上の正の方向を向いていたのだが、「３」だと、ｘ軸上の負の方向を向くことになる。ここも、直感と反する。

「７」を押した場合
テンキー「７」は、「１」の状態から上方向へ動いて、スザンヌを上から見ることになる。
![20210509-06-05.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684864/4e3a9d9d-073b-d843-df12-ef1386f57bff.jpeg)
テンキーにおける、「１」と「７」の位置関係の通りにカメラが動く訳である。
この時、ｘ軸正が右、ｙ軸正が上になる。

##まとめ
結局、使い続けて、慣れていくしかない。今日もblenderを頑張ろうと思いました。
![20210509-06-07.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684864/9a4512b9-5f1b-5a4d-a98b-4a8f8f26744d.jpeg)
イベントモニタリング ⇒ イベントモニタリングの使用開始

１．イベントモニタリングを使用できるシナリオは次のうちどれですか?
２．組織の新しいアプリケーションを開発しているとします。Salesforce のベストプラクティスによると、最初に検討すべきことは何ですか?
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634241/1595c5c3-cbcf-0438-0797-b20330a40a97.png)
京セラプログラミングコンテスト2021（AtCoder Beginner Contest 200）備忘録

https://atcoder.jp/contests/abc200


結果
リアタイ不参加
A：すぐできた
B：すぐできた
C：解説みて自分で記述
D：未
E：未
F：未



A - Century
入力された数字が何世紀か答える問題。
100年ってどっち世紀だっけ？　っていうところだけ場合わけして割り算の商を出力するだけ。
即回答。

```php
#include <bits/stdc++.h>
#include <math.h>
using namespace std;

int main() {
  int N;
  cin>>N;
  int ans;
  if(N%100==0){
  cout << N/100 <<endl;
  }
  else{
    cout << N/100+1<<endl;
  }

  }

```


B - 200th ABC-200
整数Nに対して、ある操作をK回やる。
①Nが200の倍数の時は、200で割る
②上記以外は、下に200を追加する。

①の操作は簡単。
②の操作も、実際は1000を掛けて200を足すだけなので、簡単に算数的に全部記載可能。
ｹﾀが大きくなるので、とりあえずunsigned long longででっかくブッ込んどく。

②に５－１０分くらいで気づいて、すぐできた。


```php
#include <bits/stdc++.h>
#include <math.h>
using namespace std;

int main() {
  unsigned long long N,K;
  cin>>N>>K;
  
  for(int i=0;i<K;i++){
  	if(N%200==0){
    N=N/200; 
  	}
    else{
    N=N*1000+200;
    }
  }
  cout<<N<<endl;
  }
```
C - Ringo's Favorite Numbers 2
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1112433/d6fc73bf-4337-cc6d-ca3e-18dfd4c5a5eb.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1112433/becbbe81-d9cc-81d4-2b1a-487ce1b475b1.png)

最大でN=2E5なので、全探索だと2E5 C 2=1E10くらいなのでTLEになる。
なるだろうな、と思ってｺｰﾄﾞ書いたがやっぱりなった。
自分では気づけなかったので解説を見る。

「数列中から任意のAi,Aj 2数を選び、Ai-Aj が200の倍数になる個数」を
「数列中で200で割ったときのあまりが同じになるものを抽出し、
　あまりが同じになった数の組合せの数」と読み替える。

例でいうと、
元数列：[1]123 [2]223 [3]123 [4]523 [5]200 [6]2000
について、各数を200でわってあまりを出すと、
余数列：[1]123 [2]23  [3]123 [4]123 [5]0   [6]0
となる。同じ余りの数、例えば[1]123と[4]523は差が200の倍数になってる。
ｺｺが気づきﾎﾟｲﾝﾄ。つまり、
「同じ余りの数の組合せ＝差が200の倍数になる組合せ」
ということ。
余り123は[1],[3],[4]の3つなので、3C2で3通りの組合せがある。
余り0は[5],[6]の2つなので、2C2で1通りの組合せ。
足して合計4通りが答えになる。
よって一般的に書くと、
・元数列全てを200で割ってあまりを出し、1~199のﾊﾞｹｯﾄで個数をｶｳﾝﾄする。
・2以上の各ﾊﾞｹｯﾄで、nC2を計算して組合せの数を算出
・組合せの数を全部足す
とやればよいってことになる。

「同じ余りの数＝差が200の倍数になる」が分かれば、なんとなくﾊﾞｹｯﾄｿｰﾄでやれるってところに気づけそう。
分かればできるけどｼﾘｰｽﾞなので、経験値が大事ってことで終了。

```php
#include <bits/stdc++.h>
#include <math.h>
using namespace std;
 
int main() {
    long N;
    long A[2500000];
    map<long, long>B;
    long ans =0;
    cin>>N;

    for(long i=0;i<N;i++){
        cin>>A[i];
        B[A[i]%200]=B[A[i]%200]+1;//各余りの数をｶｳﾝﾄする
    }

    for(int i=0;i<200;i++){//200余りは0~199
        if(B[i]>1){
          ans=ans+(B[i]*(B[i]-1))/2; //2個を選ぶのでnC2
        }
    }
    cout<<ans<<endl;
}

```
【Rails】Amazon SESの署名バージョン４に対応させる

# はじめに
RailsでAmazon SESの署名バージョンを３から４に対応させたときの備忘録です。
SESのライブラリは`gem 'aws-ses'`を使っていました。
人によってファイルの設定やリージョンなどは異なるので、あくまで参考程度にしてください。
## 環境
* Rails 6.0.3.7
* ruby 2.6.5
* MacOS
* `gem 'aws-ses', '~> 0.6'`

# エラー内容

> FATAL -- :
AWS::SES::ResponseError (InvalidClientTokenId - Signature Version 3 requests are deprecated from March 1, 2021. From that date on, we are progressively rejecting such requests. To resolve the issue you must migrate to Signature Version 4. If you are self-signing your requests, refer to the documentation for Authenticating requests to the Amazon SES API [1] with Signature Version 4 [2]. If you are not self-signing your requests, simply update your SDK/CLI to the latest version. [1] https://docs.aws.amazon.com/ses/latest/DeveloperGuide/using-ses-api-authentication.html [2] https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html):

google翻訳
> 致命的-：
AWS :: SES :: ResponseError（InvalidClientTokenId-署名バージョン3のリクエストは2021年3月1日から非推奨になりました。その日以降、このようなリクエストは段階的に拒否されます。問題を解決するには、署名バージョン4に移行する必要があります。 -リクエストに署名するには、署名バージョン4 [2]を使用したAmazonSES API [1]へのリクエストの認証に関するドキュメントを参照してください。リクエストに自己署名しない場合は、SDK / CLIを最新バージョンに更新してください。[ 1] https://docs.aws.amazon.com/ses/latest/DeveloperGuide/using-ses-api-authentication.html [2] https://docs.aws.amazon.com/general/latest/gr/ sigv4-create-canonical-request.html）：

エラーの内容通り、署名バージョンを４に移行させる必要があるそうです。
# やったこと

**`gem 'aws-ses', '~> 0.6'`を　`gem aws-ses-v4`に変えた。**

[aws-ses](https://github.com/drewblas/aws-ses/issues/83)のissuesをみると、バージョン４に移行することについて結構多くの人が話していました。
`gem aws-ses-v4`は`gem 'aws-ses'`を署名バージョン４に対応させたgemです。
他にもAWSが推奨している`aws-sdk-rails`というGemがあるそうですが、そちらに移行させる時間はなさそうだったので今回は`aws-ses-v4`を使うことにしました。
できれば公式が推奨している方を使うべきだと思います。

## Gemを変更

```diff_ruby:Gemfile
- gem 'aws-ses', '~> 0.6'
+ gem "aws-ses-v4", require: "aws/ses"
```
```shell
$ bundle install
```
## aws.rbの変更
ここら辺は人によって違うかもしれません。
各々のメールの設定に合わせてください。
ちなみに私は最終的に以下のようになりました。

```ruby:config/initializers/aws.rb
ActionMailer::Base.add_delivery_method :ses,
  AWS::SES::Base,
  access_key_id: Rails.application.credentials.aws_ses_access_key_id,
  secret_access_key: Rails.application.credentials.aws_ses_secret_access_key,
  server: 'email.リージョン名.amazonaws.com', #人によって違います
  region: 'リージョン名' #SESのリージョンを指定。 例：us-east-2

```
以下のエラーが出た時はSESのリージョンが間違っている可能性があります。

```shell
SignatureDoesNotMatch - Credential should be scoped to a valid region, not 'ap-northeast-1'
```
また、awsのアクセスキーなどを記載するcredentials.yml.encには、以下のコマンドで確認・編集できます。

```shell
EDITOR=vim rails credentials:edit
```

以上です。


# 参考
* [aws-ses GitHub](https://github.com/drewblas/aws-ses)
* [aws-ses-v4 GitHub](https://github.com/drewblas/aws-ses/issues/83#issuecomment-8171611240)
Python でマイクをミュート（Windows10）

ビデオ会議中にミュートにしたくて検索したら近いものがありました。
　https://stackoverflow.com/questions/65510997/python-control-microphone-level-using-pywin32-windows-10


##ミュートしたいとき

```python:mute-on.py
import win32api
WM_APPCOMMAND = 0x319

MIC_MUTE = 24
MIC_DOWN = 25
MIC_UP = 26

win32api.SendMessage(-1, WM_APPCOMMAND, 0x30292, MIC_MUTE * 0x10000)
```

##ミュート解除

```python:mute-off.py
import win32api
WM_APPCOMMAND = 0x319

MIC_MUTE = 24
MIC_DOWN = 25
MIC_UP = 26

win32api.SendMessage(-1, WM_APPCOMMAND, 0x30292, MIC_DOWN * 0x10000)
win32api.SendMessage(-1, WM_APPCOMMAND, 0x30292, MIC_UP * 0x10000)
```


各種数字は以下を参照
https://docs.microsoft.com/ja-jp/windows/win32/inputdev/wm-appcommand


上記ファイルをそれぞれBATで呼び出すようにして、BATのショートカットをデスクトップに作成
ショートカットのプロパティから「ショートカットキー」を登録しておけば、キー操作のみでミュートのオン・オフが操作できます。


こういうのでいいんだよね・・
PowerShell 使う方法だとなかなか複雑だったので、Pythonで簡単にできてよかったです。
　・・PowerShell は何だか方向が間違っているような・・・
エクセルのフォントを統一したい

のですがググって出ていた
[＜238＞ Office文書の混在したフォントを統一する - ブログ　〔情報リテラシー研究会〕](https://blog.goo.ne.jp/yh-asaka/e/9d1855d7808549a81dca9f4717703a91)
では一々変換元のフォントを指定しないと駄目っぽいので
元フォントが不明な時も出来る方法を探したいなー
OS XのアップデートしたらDockerが使えなくなった

### 事象の説明
OS Xのソフトウェア・アップデートを行いました。
すると、「Docker Desktop is starting...」とステータスに表示されたまま変わらず、Dockerが起動しなくなりました。

### 環境

使用しているPC

```
MacBook Pro (13-inch, M1, 2020)
チップ Apple M1
```

アップデートしたOSのversion

```
macOS Big Sur ver 11.3.1
```

### 解決方法
以下のページで「AppleチップのMac」を押して、Dockerをインストールし、使用していたDockerと置き換えたところ解決しました。

https://matsuand.github.io/docs.docker.jp.onthefly/docker-for-mac/install/

元々M1チップMacは従来のインストールだとDockerは使えませんでした。
そのため、以下のページを参考に使えるように設定しました。

https://www.docker.com/blog/download-and-try-the-tech-preview-of-docker-desktop-for-m1/

現在はM1チップに対応したDockerがリリースされているので、そちらをインストールすれば大丈夫です。
CloudWatchLogsの特定の文字列を含むログをSlackに転送する -前編-








#slack apiにアクセスしてアプリを作成
botの作成の仕方やslackへのメッセージ投稿の仕方は以下の記事で紹介しています。

https://qiita.com/ms2geki/items/f63757edf705dc5df537

#Pythonのコードのディレクトリ構造

ディレクトリ構造は以下のようになっています

```shell:ディレクトリ構造
sendLogToSlack
├── lambda_function.py
├── postslack.py
└── slack_sdk
```

#slack_sdkのインストール
slack_sdkはlambdaの標準モジュールではないので、
pipでインストールしてからzipでパッケージ化する必要があります。

```bash:slack_sdkをパッケージに含める
mkdir sendLogToSlack
cd sendLogToSlack
pip install slack_sdk -t ./ 
```

#lambda_function.py


```lambda_function.py
import zlib
import base64
import postslack
import json

def lambda_handler(event, context):
    data = zlib.decompress(base64.b64decode(event['awslogs']['data']), 16+zlib.MAX_WBITS)
    data_json = json.loads(data)
    log_json = json.loads(json.dumps(data_json["logEvents"][0], ensure_ascii=False))
    postslack.SendSlackMessage(str(log_json))
```
こちらの記事を参考にさせて頂きました。

https://dev.classmethod.jp/articles/notification_cloudwatchlogs_subscriptoinfilter/


#postslack.py


```postslack.py
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError

def SendSlackMessage(message):
    client = WebClient(token='your_token') 
    response=client.chat_postMessage(channel='your_channel', text=message)
```

slack_sdkの使い方に関してはこちらの記事で紹介しています。



https://qiita.com/ms2geki/items/f63757edf705dc5df537



#パッケージ化
lambdaにアップロードする為にzipコマンドでパッケージ化します。



```shell:sendLogToSlack
zip -r sendslack *
```

#lambdaにアップロード

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659469/c0c13d23-7184-7d8c-28d8-b2ff3f946151.png)




#続き
ここまで出来れば残りの作業はもう少しです。
CloudWatchLogsの特定の文字列を含むログをSlackに転送する-後編-に続きます。

https://qiita.com/ms2geki/items/2b5073c69149165ac6fd
【GAS入門】Google Driveのファイル一覧を作成する

# TL;DR
Google Driveのファイル一覧をスプレッドシートに作成する、Google App Scriptを作成しました。
スプレッドシートを自分のフォルダにコピーするだけで使えます。

（画像はテンプレートを表示しています。スクリプトを実行すると自分のファイル一覧が取得できます。）
![スクリーンショット 2021-05-08 0.39.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146971/731b8d49-db78-a180-435a-cd8af840f97b.png)


# 背景
ファイルの保存先として、Google Driveを使っている企業はかなり存在すると思います。
一方でWikiなどのツールが社内で使われていない場合、Google Driveがドキュメントをまとめる役割を持ちます。Googleの素晴らしい技術により、検索は高速なため困ることはほとんどありませんが、フォルダの階層が多い場合などの一覧性という点では問題があります。
つまり今回のテーマは、**「Google Driveにファイルの一覧性を付加する」**です。

（ちなみに弊社ではConfluenceを活用しているので、上記の状態には当たりません。しかし所属しているチームでは、Google Driveを多用しているので、今回のツールを作成することとなりました。）

# ポイント
- 使いやすさを考え、ユーザーやフォルダ固有の設定が不要な実装としました
- 簡単に、すぐに動くため、GASの理解にも役立つと考えました

# 利用方法
1. [ファイル一覧のスプレッドシート](https://docs.google.com/spreadsheets/d/1Vd8fmv-lezxc4CVgC2qzZDsr4DY4oJo-mXq7goVdoSU/edit?usp=sharing)を自分のドライブに保存する。（ファイル > コピーを作成）
1. スクリプトを実行 or トリガーを設定する

## 2.の詳細
一度だけ実行する場合は「スクリプトを実行」を、継続的にフォルダ内のファイルを確認したい場合は「トリガーを設定する」を確認してください。

まずは、スクリプトを開きます。
Spreadsheetを開いて、以下の手順で進めます。　（Spreadsheetのアップデートにより、多少方法が異なることもあります）

- 新しいバージョン：拡張機能 > Apps Script
- 古いバージョン：ツール > スクリプトエディタ

### スクリプトを実行 
myFunctionが選択されていることを確認して、実行を押してください！

### トリガーを設定する
左メニューの目覚まし時計アイコン > トリガー > 右下のトリガーを追加
から、起動時や特定の時間に実行するトリガーを設定。

以上です！

# 実装詳細
利用するだけなら、上記の手順だけです。
せっかくなので、実装の詳細を説明します。

```javascript:コード.gs
function myFunction() {
  // 一覧にしたいフォルダの階層を指定してください。
  // 0の場合、スプレッドシートが存在するフォルダのみのファイル一覧が表示されます。
  const depth = 1;

  // getActive（）で結びついているスプレッドシートを取得
  const spreadSheet = SpreadsheetApp.getActive();
  const id = spreadSheet.getId();
  folderRoot = DriveApp.getFileById(id).getParents().next();
  // デフォルトの'シート1'をそのまま利用
  const sheet = spreadSheet.getSheetByName('シート1');

  // １行目は見出しなので、２行目以降にファイル一覧を表示
  const rowInit = 2;
  const rowLast = sheet.getLastRow();
  // すでにデータがある場合、一旦クリア
  if (rowLast > 1) {
    sheet.getRange(rowInit, 1, rowLast - rowInit + 1, 100).clear();
  }

  // depthに合わせてフォルダを探索
  digFolders(folderRoot, sheet, depth)
}

function digFolders(rootFolder, sheet, depth) {
  // 現在のフォルダのファイル一覧を取得
  listFiles(rootFolder, sheet);

  // depthが0になるまで探索
  if (depth > 0) {
    const folders = rootFolder.getFolders();
    while (folders.hasNext()) {
      const folder = folders.next();
      // depthを1減らして、再帰実行
      digFolders(folder, sheet, depth - 1)
    }
  }
}

function listFiles(folder, sheet) {
  const files = folder.getFiles();
  let row = sheet.getLastRow() + 1;

  // 次のファイルが存在する場合、処理を継続
  // １ファイルごとに１行ずつスプレッドシートに書き込み
  while (files.hasNext()) {
    const file = files.next();
    // ハイパーリンクをそのまま書き込み
    const folderValue = '=HYPERLINK("' + folder.getUrl() + '","' + folder.getName() + '")';
    sheet.getRange(row, 1).setValue(folderValue);
    const fileValue = '=HYPERLINK("' + file.getUrl() + '","' + file.getName() + '")';
    sheet.getRange(row, 2).setValue(fileValue);
    const fileValueEn = '=HYPERLINK("' + file.getUrl() + '",' + 'GOOGLETRANSLATE("' + file.getName() + '", "ja", "en")' + ')';
    sheet.getRange(row, 3).setValue(fileValueEn);
    sheet.getRange(row, 4).setValue(file.getLastUpdated());

    row = row + 1;
  }
}
```

# まとめ
コピーしてスクリプトを実行するだけなので、ぜひ試してみてください！
便利なGASを使うきっかけになれば、幸いです。
【CloudWatch Logs Insight】サンプルクエリ

2xx 系のメッセージログを抽出する
-
```
fields @message
| filter (status < 300)
| display @message
| limit 10
```

特定の送信元 IP アドレス以外の 送信元 IP アドレスごとのリクエスト数をカウントする
-
```
fields @message
| filter ip not in ["<除外したい IP アドレス1>", "<除外したい IP アドレス2>", ...]
| stats count(*) as count by ip
| sort count desc
| limit 10
```

送信元 IP アドレス, リクエストメソッド, リクエストURI ごとのリクエスト数をカウントする
-
```
fields @message
| stats count(*) as count by ip, httpMethod, resourcePath, status
| sort count desc
| limit 10
```
上記のサンプルの[参考サイト](https://blog.serverworks.co.jp/insight-restapi-access-log)


送信元 IP ごとにカウント
-
```
fields @message
| filter @logStream =~ /<ログストリーム名>/
| parse @message '* * * [*] "* * *" * "*" "*"' as srcIpAddress, srcUser, remoteUser, timestamp, httpMethod, requestUri, protocol, statusCode, transferredData, referer, userAgent
| filter requestUri = "/"
| filter statusCode =~ /2\d\d/
| stats count(*) as count by srcIpAddress
| sort count desc
| limit 10
```
parseコマンドの[参考サイト](https://blog.serverworks.co.jp/cw-insight-httpd-access_log)
SwiftをPlaygroundsで書こう

## Playgroundsとは
[Playgrounds](https://www.apple.com/jp/swift/playgrounds/)とはAppleが開発したSwiftの書き方を学べるmac/ipadアプリです。最近はmicro bitやLEGO、ドローンといったものとの連携も見られ始めています。教育的側面が強く子供向けというイメージがあるかもしれませんが、「ちょっとSwiftで試したいことがあるけどわざわざXCodeで確認するのもなー」といった時に重宝します。

## UIViewControllerを書く
### 準備
「書く」という表現が適切かはわかりませんが。とりあえず、Xcodeを立ち上げて最初に開かれる状態を再現します。`import PlaygroundSupport`を最初に`PlaygroundPage.current.liveView = ViewControlelr()`を最後に加えなければいけません。

```swift
import UIKit
import PlaygroundSupport

class ViewControlelr: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        print("viewDidLoad")
    }
}

PlaygroundPage.current.liveView = ViewControlelr()
```

実行すると、それらしきものができていることがわかります。
![スクリーンショット 2021-05-10 12.18.45.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549093/74a644d3-cab8-75ba-1892-62e463603c32.jpeg)


### 背景色を変更する
これはPlaygroundsならではというわけではありませんが。

```swift
import UIKit
import PlaygroundSupport

class ViewControlelr: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .gray
        print("viewDidLoad")
    }
}

PlaygroundPage.current.liveView = ViewControlelr()
```

背景色を変更し、先程の黒い画面がViewを表していることが確認されました。
![スクリーンショット 2021-05-10 12.19.45.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549093/b73d61d6-24d2-4893-65e4-2667ca38ae2e.jpeg)

右下の赤く光っているボタンを押すと、メッセージが表示されます。
【php】ゼロ・プラス・マイナスを繰り返し判定する

```PHP
<?php
    $count = trim(fgets(STDIN));
    
     echo "受け取った整数".$count . "\n";

    for ($i = 0; $i < $count; $i++) {
        $number = trim(fgets(STDIN));

        if ($number == 0) {
            echo $number . "は0\n";
        } elseif ($number > 0) {
           echo $number . "はプラス\n";
        } else {
           echo $number . "はマイナス\n";
        }
    }
?>

```
1. 標準入力から整数を 1 個受け取る

2. 受け取った整数を表示する

3. 受け取った整数回分、以下の処理を繰り返す

 a. さらに標準入力から整数を 1 個受け取る

 b. その整数が 0 の場合、以下のメッセージを表示する

 c. その整数が 0 より大きい場合、以下のメッセージを表示する

 d. それ以外の場合、以下のメッセージを表示する
laravel newInstance() メソッドの定義場所 個人メモ

# 目的

- 各モデルクラスでインスタンスを作るときに使用する`newInstance()`メソッドの記載場所をメモ的にまとめておく

# 場所

- `アプリ名ディレクトリ/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php`の中に記載されている。
- 下記に定義部分を抜粋して記載する。

    ```アプリ名ディレクトリ/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php
    /**
     * Create a new instance of the given model.
     *
     * @param  array  $attributes
     * @param  bool  $exists
     * @return static
     */
    public function newInstance($attributes = [], $exists = false)
    {
        // This method just provides a convenient way for us to generate fresh model
        // instances of this current model. It is particularly useful during the
        // hydration of new objects via the Eloquent query builder instances.
        $model = new static((array) $attributes);

        $model->exists = $exists;

        $model->setConnection(
            $this->getConnectionName()
        );

        $model->setTable($this->getTable());

        return $model;
    }
    ```

- 各モデルクラスは`アプリ名ディレクトリ/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php`に記載されているModelクラスを継承して作成されている。そのため各モデルクラスでも`newInstance()`メソッドを使うことができる。
ベイズの定理を使って感染率を計算してみる

新型コロナの感染率と陽性率は異なると書いたので、ベイズの定理を使って陽性と出た人が実際に感染している確率を確認してみました。

前提として下記の数値を用意しました（下記の数値を利用していますが、ばらつきがありますので凡そです）。
https://www.centerforhealthsecurity.org/covid-19TestingToolkit/serology/Serology-based-tests-for-COVID-19.html

・感度は70%
（新型コロナウイルス感染症患者を正しく陽性と診断する確率）

・特異度は90%
（新型コロナウイルスに感染していない患者を正しく陰性と診断する確率）


表にすると

|  |罹患  |非罹患  |
|---|---|---|
|陽性  |0.7  |0.1（偽陽性）  |
|陰性  |0.3（偽陰性）  |0.9  |

・有病率は0.1%
（新型コロナウイルスに実際にかかっている人の割合。これはデータが実際とれないので仮定ですが、感覚的にはもっと少ないですよね）
とします。

ベイズの定理は、P(A|B)=P(B|A)*P(A)   /P(B)
です。ちなみにP(A|B)は、事象Bの条件で事象Aが起きる確率を表します。

これに当てはめると、
0.7×0.001 / 0.001×0.7+(1-0.001)×0.1 = 0.0007 / 0.1006 = 0.00695
=>0.695%

思ったより少ないですよね。つまり陽性と判定されても実際に感染している率は非常に低いです。
逆にいうと、陰性と判定されても実際には感染している率は結構あるのです。
つまり、PCRを全員にというのは、無意味というより有害な策なのです。

ちなみにベイズの定理は、有名なところでは迷惑メールの判定にも使われております。
AIに興味ある人は勉強しましょう。
R tips 従属・独立変数に変数を指定したい場合

# はじめに
Rでの回帰分析などの関数(`lm`)を使う場合、従属変数、独立変数をチルダで指定する。この指定はベクトルで行われるが、for文で連続して回帰分析を行いたい場合、変数の指定方法がややこしい。その方法を備忘録として残しておく。

データは「[RでReal estate valuationの基礎分析](https://qiita.com/ryamamoto0406/items/8ac0bb8e5368a8cf8d6d)」で扱った、[Real estate valuation](https://archive.ics.uci.edu/ml/datasets/Real+estate+valuation+data+set)データセットを用いた。

# エラーが出るコード

```R:コード
library(openxlsx)
df <- read.xlsx("./Real_estate_valuation_data_set.xlsx")

coln <- colnames(df) #列名を保存しておく
colnames(df) <- c("No","X1","X2","X3","X4","X5","X6","Y") #新しい名前を付けておく
col_x <- c("X1","X2","X3","X4","X5","X6") #独立変数


for (x in col_x) {
  res <- lm(Y~x, df)
}
```

独立変数にX1, X2, ..., X6 を代入したいのだが、~でしているのはベクトルのため、エラーがでる。

```:出力
Error in model.frame.default(formula = Y ~ x, data = df, drop.unused.levels = TRUE) : 
  variable lengths differ (found for 'x')
```

これを回避するため `eval` 関数を使う。

# `eval` 関数を用いたコード
上記の for 文部分を以下に書き換える。

```R:コード
for (x in col_x) {
  eval(parse(text=paste0("res_", x," <- lm(Y~", x, ", df)")))
}

summary(res_X3)
```

```:出力
Call:
lm(formula = Y ~ X3, data = df)

Residuals:
    Min      1Q  Median      3Q     Max 
-35.396  -6.007  -1.195   4.831  73.483 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) 45.8514271  0.6526105   70.26   <2e-16 ***
X3          -0.0072621  0.0003925  -18.50   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 10.07 on 412 degrees of freedom
Multiple R-squared:  0.4538,	Adjusted R-squared:  0.4524 
F-statistic: 342.2 on 1 and 412 DF,  p-value: < 2.2e-16
```

ちゃんとX3を独立変数として指定した場合の回帰分析結果が出力された。

# おわりに
今回は`eval`関数を用いた方法を紹介したが、もっとスマートな方法を知っている方がいましたら、是非コメント下さい。
【Redash】Dashboard をコピー（複製）する


# 1. はじめに
　データ分析基盤をマーケター向けに作成しており、可視化ツールとしてredashを採用しています。redashは非エンジニアの方でもsqlが書ければ、手軽にデータをプロットできるので使い勝手が良いです。しかしながら、特定の機能についてはAPIを叩く必要があります。タイトルの通り、DashboardのコピーについてはGUIからはできませんが、APIを叩いて複製する方法があったので共有します。

# 2. 環境・前提
①コピーしたいダッシュボードのurlを確認
　ex) https://redash.example.com/dashboard/example_test_board<br>

②python実行環境 (python > 3.x)

# 3. 準備

1. redash_host(urlのホスト部分）
    - https://redash.example.com/
1. Slug(urlの最後の部分）
    - example_test_board
1. User API key
    - Redashログイン>右上のアイコンクリック>Edit Profile>API Key を確認<br>
1. 複製クエリ名を考える(元のクエリ名の頭に付与される)
    - copy_smoto_



# 4. 方法
① [redash-toolbelt](https://github.com/getredash/redash-toolbelt)をクローンする（※redash製のAPI簡易ラッパーです）
② クローンしたコード example/clone_dashboard_and_queries.py を実行

```
python clone_dashboard_andqueries.py {redash_host} {slug} {コピー名}

ex) python clone_dashboard_and_queries.py https://redash.example.com/ example_test_board copy_smoto_
```

③ API Key を問われるので、確認した API Key を入力

```
[xxx/redash-toolbelt/redash_toolbelt/examples] % python clone_dashboard_and_queries.py https://redash.example.com/ example_test_board copy_smoto_
API Key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

④ コピー結果の確認（redash）

```
ダッシュボード名: Copy of: example_test_board
クエリ: copy_smoto_xxxx
```

## 5. 備考
- ダッシュボードを複製すると、クエリも全てコピーされます（テストでクエリがたくさんあるボードをコピーすると、削除するのが大変です）
- User API Key の取り扱いには注意してください （以下引用）
 
>All the API calls support authentication with an API key. Redash has two types of API keys:
>User API Key: has the same permissions as the user who owns it. Can be found on a user profile page.
>Query API Key: has access only to the query and its results. Can be found on the query page.
>Whenever possible we recommend using a Query API key.

## 参考
- https://redash.io/help/user-guide/integrations-and-api/api
- https://github.com/getredash/redash-toolbelt
Githubとのやり取りで使用するコマンドについて

Githubとやり取りする際のターミナル上でのコマンドに関してまとめます。
出力はあくまでも例となります。

◎リモートリポジトリを表示

```
% git remote
>origin

#URLを表示
% git remote -v
>origin	git@github.com:アプリ名.git (fetch)
 origin	git@github.com:アプリ名.git (push)
```


◎リモートリポジトリの新規追加

```
git remote add [リモート名] [リモートURL]
```
上記コマンドは、Github上で、「Repositories」→「new」同じ意味。
![スクリーンショット 2021-05-09 21.31.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1340120/8376fb62-af9d-6b0c-220a-10ed4d552c86.png)


◎フェッチとプル
リモートリポジトリから情報を取得する方法は2パターンあり、それがフェッチとプルです。

```
#フェッチの場合
git fetch [リモート名]
>remote: 〜〜〜
 remote: 〜〜〜
　略
 From github.com:アプリ名


#プルの場合
git pull
>同上

#省略せずに書くと、
git pull [リモート名][ブランチ名]
```

このフェッチとプルの違いは、リモートリポジトリから取得した情報を一気にワークツリーまで持ってくるかどうかです。
フェッチの場合、フェッチコマンドを入力した時点ではローカルリポジトリに情報を持ってきているだけです。そのためワークツリーまで情報を持ってこようとすると、統合するための「git merge」コマンドを入力しなければいけません。
反対にプルの場合は、一気にワークツリーまで情報取得してくるので、いちいちmaergeを用いる必要がありません。

※プルコマンドの注意点
一見便利なプルコマンドですが、別ブランチの情報を取得する時は注意が必要です。
例えば現在masterブランチにいるとしてmainブランチの情報を取得してしまうと、ブランチが異なっているためファイルの中身が混在してしまう可能性があります。



◎リモートリポジトリの詳細情報を確認

```
git remote show [リモート名]
>* remote origin
   Fetch URL: ~~~
   Push  URL: ~~~
   HEAD branch: main
   Remote branch:
     main tracked
   Local branch configured for 'git pull':
     main merges with remote main
   Local ref configured for 'git push':
     main pushes to main (local out of date)
```
最初に出てきた「git remote」より詳細情報を表示します。
上から、フェッチとプルのURL/リモートブランチ名/HEADブランチ/git pullの動き/git pushの動きが表示されています。

◎リモートリポジトリの削除、修正

```
#削除する場合
git remote rm [リモート名]

#修正する場合
git remote rename [旧リモート名][新リモート名]
```
rmはリムーブの省略です。

以上です。
[Webを支える技術]Webの用途とURIについて

# Webの用途
- Webサイト
    - サイト、ブログ、ショッピング、動画投稿、画像......
    - さまざまなサイトをサーバーの裏側を知らなくてもブラウザさえあれば利用できる
- ユーザーインターフェース
    - HTMLとCSSを使用して構築している例が多い
        - Netflix
        - Switch
        - テレビ
        - 各種ソフトウェア
        - ルーターの設定
- API
    - 主にプログラムで使用する、データを取得したりする

## URI
Uniform Resource Identifierの略
URIとは、Web上にあるソースの場所を表すプロトコルです。
たとえば、このような形のURLがあったとします

```url:URL
https://www.google.com/search?q=aaaa&rlz=1C1FQRR_jaJP939JP939&oq=aaaa&aqs=chrome..69i57j0i4i433j0i4l5j0l2j0i4.1251j0j7&sourceid=chrome&ie=UTF-8
```

これはURIの構文に分解するとこのようになります。
URIスキーム `https://`
ホスト名　`www.google.com`
パス名　`/serch?`
クエリパラメータ　`q=aaaa&rlz=1C1FQRR_jaJP939JP939&oq=aaaa&aqs=chrome..69i57j0i4i433j0i4l5j0l2j0i4.1251j0j7&sourceid=chrome&ie=UTF-8`

このような、URLの書き方を策定したものがURIとなります(厳密には違う)
URIの説明はこちらの記事が一番わかりやすいとおもいます。

https://qiita.com/Zuishin/items/3bd56117ab08ec2ec818

関係性としては

- URI
  - URL
  - URN

のような形になっています。

## URIを作るときの考え方
良いURIは次の三つがあげられます。

- リソースの名前であること
- 寿命が長い
- ブラウザがアドレス欄に表示する

これら三つを意識したURIが良いURIと思います。
CoolURIとも呼ばれます。

このような経験をしたことがあると思います。

- 昔見たURLにアクセスしたら404だった
- URLにアクセスしたら望んでたものと違うサイトだった

Webサービスを運用していく上でURI(上の例で言えばパス名など)を変更しないというのは難しいものだと思います。なので、作るときになるべく変わりにくい設計で作る必要があります。

#### 言語に依存した、拡張子やファイル名を含まない
これを含んでしまうと言語に左右されたWebページとなってしまい、もし言語を変えようとした場合、URIが変わってしまいます。

```uri:not_cool_URI
https://sample/directry/home.php
https://sample/directry/HomeServret
```

#### メソッドやセッションIDを含まない
これを含むURIは、システムがリファクタリングされた際に変更となる可能性があります。
メソッドを含む場合、メソッド名が変更となったときには、URIが変わってしまいます。

```uri:not_cool_URI
https://sample/directry/home?action=userPage
```

セッションIDを含む場合、IDが変わってしまうとURIが変わってしまいます。

```uri:not_cool_URI
httos://sample/directry/home?session=123142323
```

### URIはリソースを含めて名詞にする
URIとは、リソースの名前です。なので、名詞にする必要があります。
例を見ながら解説します

```uri:not_cool_uri
https://sample/user/show/micchili
```

URIはHTTPのメソッドと同じになるように作成するように心がけましょう。
このURIの場合`show`の部分が問題です。URIでアクセスすると、サーバーからHTTPメソッドが返されますが、HTTPは単一のメソッドです。つまり、このURIでは`show`と書かれている通り、リソースを取得することがわかりますが、URIが動詞となっています。
URIとHTTPは名詞と動詞の関係となるように作成しましょう。

### URIを変更したとき
良いURIとは、変わらないURIです。しかし、時にはどうしても変更となってしまう場合があります。そういったときには、リダイレクトを使って古いURIにアクセスした人を新しいURIへ転送してあげましょう。