OmniAICreator/Qiita-1.07M huggingface dataset:
AIOpsって何？なるべく分かりやすくざっくり説明します

#バズワード「AIOps」
DevOps, MLOps, ChatOps, DataOps……
この〇〇Opsというワードが近年のIT業界のトレンドになってきてますよね。
これらのワードは定着するものもあれば消えていくものもあるんですが、今後浸透する可能性の有りそうな**AIOps**というワードについて私なりに調べた結果を共有したいと思います。
（ちなみに初出は2016年頃にガートナー社が提唱したそうです）

##AIOpsを一言で表す
AIOpsを提唱したガートナー社の定義としては


「ビッグデータ、人工知能 (AI) 、機械学習を組み合わせて、可用性やパフォーマンス監視、イベントの相関付けと分析、ITサービスの管理、自動化といったIT運用のさまざまなプロセスやタスクを改善または部分的に刷新するようなソフトウェアシステム」（意訳）

つまりもっと簡潔に述べるならば

**AIOpsとは「主にインフラの障害対応等を自動化する取り組みや考え方」**のことと言えます。

これをもう少し理解しやすく「DevOps」というワードを引き合いに出したいんですが、というのも私の理解としては**AIOpsはDevOpsの延長線上にあるような概念**です。

##DevOpsとは？
DevOpsとはDevelopment(開発)とOperation(運用)をかけ合わせた用語です。
wikipediaには
>開発担当者と運用担当者が連携して協力する（さらに両担当者の境目もあいまいにする）開発手法

と記載されていますが**「運用ではなく開発になるべく多くのリソースを割くための取り組みや考え方」**と表現したほうが実情を端的に表しているのではないでしょうか。

DevOpsはシステム開発を担う多くの企業で取り入れられていますが、その前提には**運用業務により開発にリソースを割いたほうが企業としての付加価値を乗せやすい**という考えがあります。

例えばシステム運用の際には「問い合わせ対応」「定常業務」「障害対応」「インフラ管理」などの業務がありますが今やコンテナ技術、ChatBot、クラウドコンピューティング等を通じてかなりの部分が自動化できるようになりました。つまりもはや運用業務に人員を割かずとも開発チームが運用も兼任することで従来支払っていた運用コスト（人的リソース）を大きく削減することが可能になったわけです。

開発と運用が統合されDevOpsチームとして再編されたり、運用の自動化に際してツールが導入されたりすると分かりやすいですが、**改めてDevOpsとは企業価値を高めるために開発と運用に投入するリソースを調整するための取り組みや考えのことと言えます。**

## AIOps は DevOps の延長線上にある
さて、上記の話の中で具体的な運用業務をいくつか挙げましたが、勿論これまでのDevOpsの取り組みでは自動化が難しい部分というのも存在します。それが「障害対応」です。

障害対応は大きく分けて監視・原因究明・対応策検討・実行というフェーズが存在しますが、これら一連の流れを自動化しようとすると明らかに従来のルールベースでは対応が不可能です。特に原因究明と対応策検討については複雑な判断が必要となるためDevOpsが浸透したとはいえこの部分については人の判断が必要でした。

**しかしもしこの部分にAIを適用することができれば「障害対応」さえも自動化が可能になるはず。
このように「何かしらの運用業務をAIで自動化する考えや仕組み」がAIOpsと呼ばれ大手ITベンダーにて研究が進められています。**

またAIOpsの機能を包括的に提供するツールは**AIOpsプラットフォーム**と呼ばれガートナー社の「日本における未来志向型インフラ・テクノロジのハイプ・サイクル：2020年」においても黎明期のテクノロジーとして登場しています。


#実際どういう技術が使われている？
多くのAIOpsはログ・リソース・イベント通知・過去の障害対応状況等をリアルタイムに監視することで障害発生時に対応します。また、自然言語処理等の技術を使うことで通知メッセージから障害発生の兆候や影響範囲等を検知してアラートを出すことで障害を未然に防ぐような機能が搭載されていたりします。

例えばIBMのWatson AIOpsの場合は定常運用時のステータスを自動で学習し、逸脱した値を検知するとアラートを出すようなロジックがあるみたいです。


#代表的なツール
2020年11月現在、主に以下のベンダーからツールが提供されています。日本ではIBMやSplunkの製品が話題に上がることが多いですが日本国内でのAIOpsの具体的な導入事例は見つからなかったです。

* IBM
* Splunk
* CA Technologies
* VMware
* Microfocus
* HCL Technologies
* BMC Software
* Moogsoft
* FixStream

#所感
当たり前ですが日本語の情報はかなり少ないですが何か詳細が分かり次第追記していきます。実際に利用した方などいれば情報を共有していただければ嬉しいです。

#参考リンク
https://www.gartner.com/smarterwithgartner/how-to-get-started-with-aiops/
https://www.ibm.com/cloud/learn/aiops?mhsrc=ibmsearch_a&mhq=aiops
https://www.gartner.com/jp/newsroom/press-releases/pr-20200910
Freebsd portsの覚書

* Ports Collectionのインストール  
  Collectionをダウンロードして/usr/portsに展開している

```shell
# portsnap fetch
# portsnap extract
```

* Ports Collectionのアップデート

```shell
# portsnap fetch
# portsnap update
```

* アプリの検索

```shell
# whereis devel/autoconf
```

* アプリのインストール

```shell
# whereis devel/automake
automake: /usr/ports/devel/automake
# cd /usr/ports/devel/automake
# make config
# make
# make install
# make clean
```
before_actionとは？

# はじめに
今回はアプリ開発を通じて`before_action`とはどういう働きをしているのか学習していきます。

#before_actonとは？
railsのコントローラーのアクションを実行する前に処理を行いたいときや、同じ記述の処理をまとめたい時に使います。

基本的な書き方は以下です

```tests_controller.rb
   before_action :処理させたいメソッド名
```
この場合だと、同じコントローラーに定義されている各メソッドの実行の前に、指定したメソッドによる処理が行われます。

もしくはresourcesメソッドと同じようにonlyやexceptなどでアクションの限定をすることもできます。

```tests_controller.rb
before_action :処理させたいメソッド名, only: [:アクション1,:アクション2]
```
この場合はアクション１と２が実行される前にのみ、指定した「処理したいメソッド」が実行されます。


#実際の使用例

```categories_controller.rb
class CategoriesController < ApplicationController
  def index
    @categorys = Category.all
    @category = Category.new
  end

  def create
    @category = Category.new(category_params)
    if @category.save
      redirect_to categories_path
    else
      @categorys = Category.all
      render :index
    end
  end

  def edit
    @category = Category.find(params[:id])     ⇦処理が被っている
  end

  def update
    @category = Category.find(params[:id])      ⇦処理が被っている
    if @category.update(category_params)
      redirect_to categories_path
    else
      render :edit
    end
  end

  def search
    @categorys = Category.where(is_valid: true)
    @category = Category.find(params[:id])　　　　　⇦処理が被っている
    @q = @category.notes.all.ransack(params[:q])
    @notes = @q.result(distinct: true)
    @title = @category.name
    render 'notes/index'
  end


  private

  def category_params
    params.require(:category).permit(:name, :is_valid)
  end
end
```

みてもらうと分かりますが、editとupdateとsearchにおいて記述が被っています

そのため、上記のコードをリファクタリングし、

```categories_controller.rb
class CategoriesController < ApplicationController
  before_action :set_category, only: [:edit, :update, :search]　　　　⇦追加


  def index
    @categorys = Category.all
    @category = Category.new
  end

  def create
    @category = Category.new(category_params)
    if @category.save
      redirect_to categories_path
    else
      @categorys = Category.all
      render :index
    end
  end

  def edit
  end

  def update
    if @category.update(category_params)
      redirect_to categories_path
    else
      render :edit
    end
  end

  def search
    @categorys = Category.where(is_valid: true)
    @q = @category.notes.all.ransack(params[:q])
    @notes = @q.result(distinct: true)
    @title = @category.name
    render 'notes/index'
  end


  private

  def category_params
    params.require(:category).permit(:name, :is_valid)
  end

  def set_category
    @category = Category.find(params[:id])       ⇦共通の処理をまとめている
  end
end
```
共通の処理をset_categoryというメソッドでまとめ、updateアクションとeditアクションとsearchアクションの実行の際にbefore_actionで呼び出しています。

#authenticate_user!
```
before_action :authenticate_user!
```
上記はdeviseを導入した際に使えるようになるメソッドである「authenticate_user!」があります。ログインしていない場合はログイン画面に遷移させるメソッドです。

よく、Amazonなどの通販サイトなどを使用していると分かりますが、商品の閲覧はログインしていなくても出来るけど、購入に進むとログインを求められますよね。

このように何らかのアクションを実行する前に行なって欲しい共通の処理をbefore_actionでは指定します。


#最後に
今回は`before_action`がどういう働きをしているのか何となくわかりました。
参考になれば幸いです。
他にもわかったことがあれば随時更新していきます。
seq コマンド 

## seqコマンドについて学習したので、記事にします。

### 数値を出力する
【コマンド例】
#### seq 10
1から10までの数値を出力する

#### seq -w
先頭を0で埋めて桁数を揃える

#### seq 5 10
開始する数値と終了する数値を指定して出力する

#### seq 1 2 10
1から10までの数値を2ずつ増やしながら出力する

#### seq -s x 10
数値に区切りを入れる
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/866385/86f8753e-9043-70c8-08ae-f9baaaabff18.png)
キーチェーンとそのコマンドたち

## きっかけ

最近キーチェーンを調べなければならないシーンがあったのですが、circleCI上での話だったのでCUIしか使えず。。。
GUIでしかキーチェーンの操作したことがなかった僕はとても困ったので記事にしました。

## キーチェーン概要

<img width="40%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/738919/f04d8816-b6a1-d3a2-bbea-56433b073200.png">

赤い枠の部分がキーチェーンたちで、「ログイン」が1個のキーチェーンになってます。
そして青い枠で、選択されているキーチェーン内にある項目の何を表示するかの絞り込みを行ってます。

システムが認識できるキーチェインは2つで、
システムのキーチェインが1つとユーザーのキーチェインが1つのみになります。たぶん。。

### キーチェイン作成

`security create-keychain {{キーチェーンパス}}`

### キーチェイン一覧

`security list-keychains`

システム側とユーザー側とで設定されているキーチェイン2つを表示します。
`-d u` オプションでユーザーのキーチェーンが確認できます。

### 読み込むキーチェインを追加します。

`security list-keychains -s {{キーチェーンパス}}`

### キーチェインに証明書を追加します。

`security import {{証明書パス}} -k {{キーチェーンパス}} -P {{password}} -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild`

`-T`オプションで、パスワードなしで許可するアプリを設定します。複数指定可能です。

### キーチェインの設定を行います。

`security set-keychain-settings -t 3600 -l {{キーチェーンパス}}`

`-l`オプションは、スリープした時にキーチェーンをロックします。
`-t 3600`オプションは、3600秒後にキーチェーンをロックします。

## 実際にやってみよう！

### キーチェーン一覧

まずはキーチェーン一覧を見てみます。
`/Users/maruiyugo/Library/Keychains/login.keychain-db`が画像の「ログイン」というキーチェーンです。
`/Library/Keychains/System.keychain`が「システム」キーチェーンですね。

```
$ security list-keychains
    "/Users/maruiyugo/Library/Keychains/login.keychain-db"
    "/Library/Keychains/System.keychain"
```

<img width="40%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/738919/9110f70d-b202-27df-ea45-794776c9624b.png">

### キーチェーン作成と設定

`marui.keychain-db`キーチェーンを作成し、キーチェーンの読み込みを行いました。
最後にキーチェーンのリストを表示させています。
すると`login.keychain-db`が`marui.keychain-db`に入れ替わったではありませんか！
キーチェーンアクセスをみても「ログイン」が「marui」になっています。

```
$ security create-keychain ~/Library/Keychains/marui.keychain-db
    password for new keychain:
    retype password for new keychain:
$ security list-keychains -s ~/Library/Keychains/marui.keychain-db
$ security list-keychains
    "/Users/maruiyugo/Library/Keychains/marui.keychain-db"
    "/Library/Keychains/System.keychain"
```
パスワードの保存などはまだしていないため中身は空っぽです。
<img width="40%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/738919/3e1edc4f-95b9-96a0-bfd1-0070194b4df6.png">

### キーチェインに証明書を追加

適当なp12ファイルを追加してみました。

```
$ security import {{p12}} -k ~/Library/Keychains/marui.keychain-db -P {{password}} -T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild
```

一覧にp12ファイルが表示されました。
<img width="40%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/738919/160a8021-80a7-1ac4-2a5e-4574915b55f0.png">

キーの中身を見てみると、オプションで指定した「codesign」「security」「productbuild」が許可されています。
<img width="40%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/738919/d61e2066-288f-d76e-373b-8b85380aad98.png">


## まとめ

キーチェーンは今まで流されるままに使っていたので、今回調べて詳しくなれてよかったです。
記事がよかった!とかためになった!とか思ったら、励みになるのでLGTMおしてください！ないてよろこびます(๑>◡<๑)
【Vagrant】VagrantでLAMP開発環境を整える（centos+apache+MySQL+PHP）

自分用のメモとして残します。


#やり方
##1.VagrantのBoxダウンロード～mysql、apache、phpインストール

いろいろ探しましたが、Masaki Yamadaさんのスタッフブログに投稿されたものが一番わかりやすく且つ丁寧で、初心者でも構築しやすいと思います。

[（外部サイト）VirtualBox + Vagrantで「CentOS7 + LAMP環境」を構築する](https://www.willstyle.co.jp/blog/2832/ "（外部サイト）VirtualBox + Vagrantで「CentOS7 + LAMP環境」を構築する")




手順通りであれば http://192.168.33.10/phpmyadmin にアクセスしてPHPMyAdminが表示されれば、ひとまずLAMP環境がきちんと構築できています。
尚デフォルトドキュメントルートは`/var/www/html`になっています。


尚、CentOSのタイムゾーン、mysqlのmy.cnf調整等は必要なので、後述で調整の仕方を説明します。

##2.調整等
###ホストOS側調整
####ゲストOSマシンのスペックを指定

お好みではありますが、Vagrantファイルに下記を追記してゲストOSのスペックを調整しましょう。


```shell:Vagrantファイル
#※追記するのは`Vagrant.configure("2") do |config|`の内側です。
  config.vm.provider "virtualbox" do |vb|
    vb.cpus = 2
    vb.memory = 2048
    vb.gui = true
  end
```
`vb.gui = true`はゲストOSの画面を表示するオプションです。
私だけかもしれませんが、たまにvagrant upに失敗するため、GUIを表示させないと問題の切り分けや、ゲストOS側での調査もできないので、個人的には設定するのをおすすめします！


###ゲストOS側（CentOS側）調整
以降の作業をする前にとりあえず、rootに切り替える。

```shell
sudo su -　
#rootに切り替わり、カレントディレクトりが/rootになる
```


####MySQLのMy.cnfを調整してマルチバイト対応
下記の記事を参考に調整。
[（参考記事）mysqlで日本語を扱えるようにする](https://www.willstyle.co.jp/blog/2832/ "mysqlで日本語を扱えるようにする")


####CentOSのタイムゾーンを日本に設定

```shell
timedatectl set-timezone Asia/Tokyo
```

####CentOSにインストールされているパッケージのアップデート
カーネル等の更新も、もしかしたらあるため、めちゃくちゃ時間かかると思います。

```shell
yum update
# -yオプション付けると確認をスキップ
```

**※セキュリティアップデートだけでよい人は以下を実行**

```shell
yum --security update
```


#最後に
ここまで構築しておけば、調子がよくなければ、LAMP構築の状態のboxから開始できるようになるため、boxファイルを作成することをお勧めします。
[(参考)【Vagrant】現在のOSイメージをvagrantのboxとして保存して他のエンジニアに共有する。](https://qiita.com/msht0511/items/05f70b3f4b886e9597a0 "【Vagrant】現在のOSイメージをvagrantのboxとして保存して他のエンジニアに共有する。")


以上。
ディレクトを掘っていき、ディレクトリパス＋ファイル名の一覧を作成する

ディレクトリ掘っていって、**ディレクトリパス＋ファイル名の一覧**を作成したい時がごく稀にたま～によくあるのでメモ的に残しておきます。

## ディレクトリ＋ファイルのリスト作成のサンプル

```
find * -type f
```

で出来ます。 @angel_p_57 さんありがとうございます！！

## 今回のディレクトリ構成

```
01_hokkaido
└ 001_sapporo
  └xxxxx.jpg
  └xxxxx.jpg
  └xxxxx.jpg
└ 002_obihiro
└ 003_hakodate
  ⁝
02_aomori
└ 002_aomori
  ⁝
03_iwate
⁝
```

## 過去の苦労

```
ls -1 | while read LINE
do
    PREFECTURE=${LINE}
    ls -1 "${PREFECTURE}" | while read LINE2
    do
        CITY="${LINE2}"
        ls -1 "${PREFECTURE}"/"${LINE2}" | while read LINE3
        do
            FILE="${LINE3}"
            echo "${PREFECTURE}"/"${CITY}"/"${FILE}"
        done
    done
done
```

再帰関数を使えばもう少しうまく書けるかもしれない。
つよつよエンジニアの変態ワンライナーの人がいたら教えてください。
新しいElastic Load Balancerが来たぞ！

#えぇ！？セキュリティアプライアンスでスケーリングを！？
できらぁ！！
[Introducing AWS Gateway Load Balancer](https://aws.amazon.com/jp/about-aws/whats-new/2020/11/introducing-aws-gateway-load-balancer/)

要約すると、第三者パーティのセキュリティアプライアンス（FortinetとかDeepSecurityとか）が
実装されたELBが使えるよって感じかな。

**え、ヤバない？**

今までインスタンス毎にCloud One Workload Security(旧:Deep Security as a Service)とか入れてたのを、
こいつフロントにかますだけで良くなるってことでしょ？

**ヤバない？**

まだ日本には実装されていないので、シドニーリージョンとかで試してみようかな。
ただ、アプライアンスのライセンス費用がどれくらいかかるのか、それが気になるところ。

[AWS ゲートウェイロードバランサー製品概要](https://aws.amazon.com/jp/elasticloadbalancing/gateway-load-balancer/)

今後の構成は、[Cloudfront+AWS WAF]-[AWS ゲートウェイロードバランサー]-[EC2]-[RDS]とかで
お手軽セキュア構成とか組めちゃうのかな。


【追記】
[ドキュメント](https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/gateway/getting-started.html)見たら、
[internet]－[Cloudfront+AWS WAF]－[VPC Endpoint]－[EC2]－[RDS]
　　　　　　　　　　　　　　　　　　　｜
　　　　　　　　　　　　　　[AWS ゲートウェイロードバランサー]－[セキュリティアプライアンスEC2群]

こんな感じの構成になるぽい。
VPC Endpointで繋いで外も内もトラフィックはAWS GWLBを経由する形に。
【Vue.js】コンポーネントを使うとうまく表示されない時の解決策

#はじめに
Vue.jsを学習している最中にコンポーネントの使い方について躓いたところがあったので、
記録かつ同じ所で躓いた方のためになればと思い、投稿します。

#コンポーネントとは？
[公式サイト](https://jp.vuejs.org/v2/guide/index.html)引用
>Vue においては、「コンポーネント」は本質的にはあらかじめ定義されたオプションを持つ Vue インスタンスです。

簡単に言い換えると独自のHTMLタグを再利用したいときに使用するものですかね。

##使ってみる
jsファイルに"user-item"というコンポーネントを作成。

```javascript:sample.js

Vue.component('user-item', {
  props: ['user']
  template: '<li>{{ user.name }}</li>'
})

new Vue({
  el: "app-user"
  data: {
    users: [
      {id: 001, name: "Sato"},
      {id: 002, name: "Tanaka"},
      {id: 003, name: "Suzuki"},
    ]
  } 
```

HTML側で"user-item"タグを使用する。

```html:sample.html
    <div id="app-user">
      <ol>
        <user-item
          v-for="user in users"
          v-bind:user="user"
          v-bind:key="user.id"
        ></user-item>
      </ol>
    </div>
```

画面での表示はこうなります。
1. Sato
2. Tanaka
3. Suzuki

#躓いたポイント
上記のようにV-forを使ってテーブルでも同じことがしたいと思い試したところ、うまくいきませんでした。
試したコード

```javascript:table.js

Vue.component('user-table', {
  props: ['user'],
  template: '\
    <tr>\
      <td>{{ user.id }}</td>\
      <td>{{ user.name }}</td>\
    </tr>\
    '
})

new Vue({
  el: "#app-table",
  data: {
    users: [
      {id: 001, name: "Sato"},
      {id: 002, name: "Tanaka"},
      {id: 003, name: "Suzuki"},
    ]
  }
});
```

```html:table.html

    <div id="app-table">
      <table>
        <thead>
          <tr>
            <th>ID</th>
            <th>NAME</th>
          </tr>
        </thead>
        <tbody>
          <user-table
            v-for="user in users"
            v-bind:user="user"
            v-bind:key="user.id"
          ></user-table>
        </tbody>
      </table>
    </div>
```

画面での表示
1Sato
2Tanaka
3Suzuki
**ID** **NAME**

ヘッダーが一番最後にきてしまっています。

#解決策
**HTMLにはタグの入れ子にルールがあり、なんでも入れれるわけではありません。**
tbodyタグに関して[MDN](https://developer.mozilla.org/ja/docs/Web/HTML/Element/tbody)調べると、
>許可されている内容 : 0 個以上の tr 要素

つまり、今回のuser-tableタグはHTMLのルールに引っかかっていることが分かりました。

そんな場合にVueではis属性というものが提供されています。
is属性を使用したHTMLコード

```html:table.html(修正後)

    <div id="app-table">
      <table>
        <thead>
          <tr>
            <th>ID</th>
            <th>NAME</th>
          </tr>
        </thead>
        <tbody>
          <tr is="user-table"
            v-for="user in users"
            v-bind:user="user"
            v-bind:key="user.id"
          ></tr>
        </tbody>
      </table>
    </div>
```
画面での表示
![table.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660498/c52dd2a5-03a8-56a3-5174-602822379d5b.png)

うまく表示できました。

#まとめ

HTMLの入れ子タグにはルールがあるので、is属性を使って回避しました。
[Unity]ドライブの空き容量が少ない場合の対処

備忘用

やあ、４ヵ月ぶりですね。
元気に３Ｄゲーム作成して遊んでいます。

＜はじめに＞
この作業を行い、発生したいかなる事象に関して当方は一切の責任を取りません。

＜経緯＞
うちのノートＰＣ、１２０ＧＢしか容量ないねん。
空き容量が２ＧＢしかない。Unityしかやってないのにおかしいやんけ！！

＜やったこと＞
１．ネットで落ちてるなんやかんやの空き容量の確保作業。
　（ディスクのクリーンアップ、CCleaner、不要アプリ削除、他）
２．Unityの古いパッケージファイルの削除（※※今回の作業※※）

Unity様が開発しているいくつかのパッケージが容量を圧迫してました。
使っているバージョン以外は不要なので削除します。

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353494/eba0bf1b-5c17-59f0-be3f-95440d9aecfd.png)


※最新版ダウンロードしたときに古いバージョン消してくれてもいいやんけ・・・
　って思ったけど複数のプロジェクト抱えてそれぞれ別バージョンを使っている場合とか
　考慮しているんだろうきっと。
Vue.jsの$refsがundefinedになってしまう問題

```
console.log(this.$refs.hoge)
```
としても、undefinedが返ってしまってくる場合について、ハマったのでまとめておきます。

# 二つの原因
+ createdでthis.$refsの処理をしている
+ v-showではなく、v-ifを使っている

# createdでthis.$refsの処理をしている
``` index.vue
<template>
  <div ref="hoge">
    ~
  </div>
</template>
<script>
export default{
  created(){
    const hoge = this.$refs.hoge
    // 何らかの処理
  }
}
</script>
```

createdではなく、mountedを使うとうまくいきました。
基本的に、createdはDOM処理未完了、mountedはDOM処理完了の状態ですが、refを使う場合は該当のDOMが読み込まれていないといけません。
ページ描写時にrefの処理をするときは、mountedに記載しておいたほうがよさそうです。
createdでもうまくいくことがありましたが、ページの重さによるようです。

# v-showではなく、v-ifを使っている
前述したとおりDOMが生成されていないとrefの処理ができませんが、v-ifを使うとDOMがそもそも生成されません。
v-showならば、DOMを生成しつつdisplay:none;にしてくれるので、refの処理が通ります。

通らない例

``` index.vue
<template>
  <div ref="hoge" v-if="isHogeExist">
    ~
  </div>
  <p v-else>hogeはないよ</p>
  <button @click="isHogeExist = !isHogeExist"></button>
</template>
<script>
export default{
  data(){
    return{
      isHogeExist:false
    }
  }

  mounted(){
    const hoge = this.$refs.hoge
    // 何らかの処理
  }
}
</script>
```

通る例

``` index.vue
<template>
  <div ref="hoge" v-show="isHogeExist">
    ~
  </div>
  <p v-show="!isHogeExist">Hogeはないよ</p>
  <button @click="isHogeExist = !isHogeExist"></button>
</template>
<script>
export default{
  data(){
    return{
      isHogeExist:false
    }
  }

  mounted(){
    const hoge = this.$refs.hoge
    // 何らかの処理
  }
}
</script>
```

以上です。
solhintのすゝめ

# 結論
Solidityのコードフォーマット、セキュリティチェックは[solhint](https://github.com/protofire/solhint)を使おう

# 経緯

1. 今まで[solium](ttps://github.com/duaraghav8/Ethlint)を使って、lintをかけていた
2. 新しいモジュールの開発はSolidity0.5系から0.6系に変更することにした
3. soliumの開発が現在止まっており、0.6から使えるようになったoverrideやabstractなどの構文に対応していなかった、とても困った
4. そういえば[openzeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts)は0.6で書かれていたはず、あっちはどうしてるんだろうと思い調べた
5. [openzeppelinはsolhintなるものを使っていた。](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/package.json#L21)
6. 試しに使ってみたらめっちゃいい感じだった。

# soliumからsolhitへの移行手順
１. uninstall & install
npmやyarnで置き換えて、package.jsonなどを更新

```
例)
npm uninstall ethlint   // soliumはethlintに入っている。
npm install solhint
```

２. 無視ファイルのリネーム
中身の形式はそのままなので、ファイル名だけ変更すればOK

```
.soliumignoreを.solhintignoreに変更する
```

３. 設定ファイルの修正
設定ファイルを修正し、中身を書き換える。基本的な記述方法は同じだが、細かい設定は[solhintのdocs](https://github.com/protofire/solhint/blob/HEAD/docs/rules.md)を参照して修正する

```
.soliumrc.jsonを.solhint.jsonに変更する
```

```
例)
.soliumrc.jsonの中身
{
	"extends": "solium:recommended",
	"plugins": ["security"],
	"rules": {
		"indentation": ["error", "tab"]
	}
}

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

.solhint.jsonの中身
{
	"extends": "solhint:recommended",
	"rules": {
		"no-empty-blocks": "off",
		"compiler-version": ["error", "0.6.12"]
	}
}
```

４. エディターの設定変更
以下はVSコードの場合

```
Code->Preference->Settings
からの
Search settingsで「solidity」で検索
Solidity:Linterを「solhint」に設定
```

# package.jsonのscripts設定
pre-commitなどでlintをかけている場合、コマンドが変更されるので、修正する。
細かなオプションは[solhintのreadme](https://github.com/protofire/solhint/blob/master/README.md)を参照のこと。

```
例)
[soliumの場合]
solium --dir contracts --fix

[solhintの場合]
solhint --fix --max-warnings 0 \"contracts/**/*.sol\"
```
LTS版ではないNode.jsを使用することによるAngularのng serveエラー(仮説)

# 背景
先日Macを購入し、MacでAngularの環境構築していたところ、ng serveの実行エラーで3日ほどハマりました。このエラーは結局解決したのですが解決方法に確証はありません。ですが、同じ原因で詰まっている人がいるかもしれないと思ったため、チェックポイントの一つとして僕が陥ったエラー原因の仮説をここに残します。

# 環境 (エラー解決前)
* Mac (Version 10.15.7)
* Node.js (15.0.1)
* Angular CLI (11.0.1)


# 発生したエラー
上記環境でng serveコマンドを打ったところ以下のエラーが出力されました。

```ERROR.txt
ERROR in ./src/app/shared/theme/styles.scss (./node_modules/css-
loader/dist/cjs.js??ref--13-1!./node_modules/postcss-loader/src??
embedded!./node_modules/resolve-url-loader??ref--13-
3!./node_modules/sass-loader/dist/cjs.js??ref--13-
4!./src/app/shared/theme/styles.scss)
Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: Can't find stylesheet to import.
```

# Angular導入の前提条件
Angular CLIを導入するためにはNode.jsが必要となりますが、前提条件として "LTS版のNode.js" (2020/11/13時点での最新LTSはv14.15.0) がインストールされていることが必要らしいです。
> Angular は Node.js の現行またはアクティブLTS、メンテナンスLTS バージョンを必要とします。
> [Angular -ローカル環境とワークスペースのセットアップ](https://angular.jp/guide/setup-local)


# Node.jsのバージョン切り替え
僕がインストールしたNode.jsはLTS版ではないv15.0.1であったため、v14.15.0のNode.jsをインストールした後で以下コマンドを打ってNode.jsのバージョンを切り替えました。

```
nodebrew ls
nodebrew use v14.15.0
node -v
```

"v14.15.0"と表示されていれば切り替え完了です。LTS版のNode.jsに切り替えた後で(更にゴチャゴチャした後)ng serveコマンドを打つとコンパイルが正常に完了し、ローカル環境のブラウザにページを表示させることができました。

# まとめ
エラー原因と解決方法がマッチしていたのかは分かりませんが、公式ドキュメントを見る限りNode.jsバージョンの違いが悪さをしていたことは間違いなさそうです。
Railsにて簡易ログイン機能を実装する

#概要
業務未経験からITエンジニアへの転職を目指すため、Ruby on Railsを用いてポートフォリオを作成している。

ログイン機能を実装したポートフォリオを作成する場合、機能のほとんどがログインを行わないと使用できないため、機能を確認するためログインをしなければならない（ユーザー名、パスワードを確認するか、新規登録をする）という手間がかかってしまう。

本来、アプリケーションとしては必要ない機能ですが、勉強の一環として、また、自分のポートフォリオを見ていただく際、採用者の方に手間を取らせないために簡単にログインができる機能を実装する。

#開発環境
Ruby:2.6.3
Ruby on Rails:5.2.0

#説明に入る前に
機能を実装する際、参考にさせて頂いた記事を添付いたします。
・[簡単ログイン・ゲストログイン機能の実装方法（ポートフォリオ用）](https://qiita.com/take18k_tech/items/35f9b5883f5be4c6e104")
非常に参考になりました。基本はこちらを参照して頂ければ問題ないと思います。
ありがとうございました。
私の場合、Deviseという機能を使用していなかったため、Deviseを使用しない方法で実装しました。
ユーザーはuser Model、controllerにて処理している前提とします。
#1.SessionsControllerを作成

```:ターミナル
$ rails g controller sessions 
```

上記でSessionsControllerを作成

#2.SessionsControllerを編集

```ruby:/app/controller/sessions_controller.rb
class SessionsController < ApplicationController
  def create
    user = User.find_by(name: params[:name])
    if user&.authenticate(params[:password])
      session[:user_id] = user.id
      redirect_to :root
    else
      render template: "users/login_form"
    end
  end

  def destroy
    session.delete(:user_id)
    redirect_to :root
  end

# 以下ゲストログイン用アクション
  def guest_login
    user = User.guest
    session[:user_id] = user.id
    redirect_to :root, notice: "ゲストユーザーとしてログインしました。"
  end
end
```
create、destroyはログイン機能をsessions controllerで管理する際必要なので記載します。リダイレクト、レンダリング先は任意で設定します。
自分用メモ: &.は左辺オブジェクトがnilの時、nilを返し、nilでない時は右辺のメソッドを呼び出す。

アクション名は任意で設定します。
guestメソッドは次項のUser Modelにて定義します。

#3.User Modelを編集

```ruby:/app/assets/models/user.rb
# 省略
   def self.guest
    find_or_create_by!(name: 'guest') do |user|
      user.assign_attributes({
      email: "guest@example.com",
      birthday: "1990-01-01",
      sex: 3})
      user.password = SecureRandom.urlsafe_base64
    end
  end
```
私の場合、userテーブルにはいくつかのカラムがあるのでguestログインする際、様々な情報をassign_attributesを使って埋め込んでいます。
特に必要なければ省略可能です。

#4.ルーティングの設定

```ruby:/config/routes.rb
  # 省略
  resource :session, only: [:create, :destroy] do
    post "guest_login", on: :collection
  end
```
guest_loginへのルーティングを設定します。

#5.リンクの作成
```:/app/assets/views/~/view.html.erb
<%= link_to "簡易ログイン", :guest_login_session, method: :post %>
```
必要箇所に上記を埋め込みます。
#まとめ
以上で簡易ログイン機能は実装できます。
ポイントは3.項の**find_or_create_by!**です。
引数nameから'guest'を探し、該当するデータがあればそれを返し、なければ新たに作成ができます。このように設定すれば、guestユーザーを削除されて場合でも、再び'guest'としてログインができます。

私はある程度、アプリケーションを作成してから追加で導入したため、説明が抜けている場面もあるとは思います。不備がございましたら申し訳ございません。
私が参照させて頂いた記事やその他記事を参考に自分に合った方法にて実装して頂けると幸いです。
#最後に余談
この記事が初投稿となりますが、記事を書く際、改めて言葉の意味など再確認する機会が多く、非常に勉強となりました。
覚えたことを発信することでより理解が深まるということを再確認しました。
今後は、勉強もそうですが、投稿も頑張っていきたいと思います。
【.dqy】Excelのあまり知られていない機能

#Microsoft Query
Excelには外部データに接続するための機能としてMicrosoft Queryというものがある。
ExcelやAcccess、DBをデータソースとして引っ張ってくることができる機能だ。
場所は[データ]→[データの取得]→[その他のデータ ソースから]→[Microsoft Query]から行ける
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362978/81798274-1359-3244-a366-064763994654.png)

が、正直使いどころがない。
Accessを使う人のPCにはAccessが入っているだろうし、Excelは開けばいい。
DBを使っている人はむしろExcelを使うか疑問だ。
そうでなくても接続を追加すればいい。

#dqyファイル
Microsoft Queryから出力できるファイル形式に.dqyというものがある。
これは、開くとデータソースに直接アクセスできるというものだ。
本来ならMicrosoft Queryから出力するが、テキストエディタで簡単に作れる。

```sample.dqy
XLODBC
1
DRIVER={Driver};SERVER={ServerName};UID={UserID};PWD={Password};APP={Excelのバージョン等};WSID={ServerName};DATABASE={DatabaseName}
SQL文
```

パスワード等は書かなければ、ファイルを開いたときに聞かれるようになる。
感覚としては、ファイル化されたViewのようなものだろう。

開くとこんな感じになる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362978/5b9ad4fb-e693-a0bc-6cb3-c34116a27f88.png)
slackで複数行のremind投稿をする方法


slackで複数行のremindを投稿するコードのメモ投稿です。（コピペして使えるように）

##  やりたいこと
slackのremindで、毎週月曜日の10時にチームやグループ内に定例MTGのリマンドとアジェンダを共有する。


---
/remind me "
本日はNN時から定例MTGを行います。
◆アジェンダ
\`\`\`
 ・全体共有連絡
 ・Aプロジェクト進捗確認
 ・Bプロジェクト進捗確認
 ・その他連絡事項（何かあれば）
\`\`\`
" every Monday at 10:00

---
**me**のところは投稿したいチャンネル名に変更する。(#generalとか）

qiitaの\`\`\`で囲んだコードにしたかったんですが、単純コピペできるようにするにはこの形じゃないと無理そうだったので、見た目ちょっとアレですが実用性を重視しました。


## 投稿結果
![スクリーンショット 2020-11-13 11.14.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242038/b0fc9107-5c51-ee47-3142-2260214de9bd.png)
pythonで折れ線グラフと目盛線

ごく稀に必要になるので，自分用にメモ

#モンテカルロ法を例に

```
import random
import math

result = []
in_circle = 0
out_circle = 0
for i in range( 100000 ):
  x = random.uniform( -1.0, 1.0 )
  y = random.uniform( -1.0, 1.0 )
  distance = math.sqrt( x ** 2 + y ** 2 )
  if distance <= 1:
    in_circle += 1
  else:
    out_circle += 1
  result.append( ( in_circle / ( in_circle + out_circle ) ) * 4)
```


```
import numpy as np
import matplotlib.pyplot as plt

plt.figure(figsize=(28,21))
plt.plot(range(1, len(result)+1), result, "-o")
plt.ylabel('area')
plt.xlabel('num of experiments') 
plt.xticks(np.arange(0, len(result) + 1, 10000))
plt.yticks(np.arange(0, 4.5, 0.1))
plt.plot([0, len(result)], [math.pi, math.pi], "red", linestyle='solid') 
plt.grid()
plt.show()
```


![ダウンロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431266/3e2a70ad-b216-f230-1b34-5f6f8b739311.png)
[mac]スクリーンショットを超快適にしよう

Macでスクリーンショットを利用する際のtipsをシェアします。

# スクリーンショットする際のショートカットキー

**Command + Shift + 3**
画面全体をキャプチャ。

**Command + Shit + 4**
マウスで選択した範囲のみキャプチャ。
マウスカーソルの形状が変わるのでキャプチャしたい範囲をドラッグで決める。
ESCでキャンセル。

# 保存せず、そのままクリップボードにコピーしたい場合

これ超便利！知らない人は人生半分損してる。。。
ドキュメント貼り付け作業が捗ります。

**Command + Shift + Control + 3**
画面全体

**Command + Shit + Control + 4**
マウス選択の範囲。

上記のショートカットキー＋Controlキーを押すだけ。

# 保存場所を変更
デフォルトではデスクトップに保存されますが、任意のディレクトリに移動できます。
デスクトップにスクショ溜まるのうざいので、これは良い！
コマンドラインから設定し、再起動すれば反映されます。

↓今回は ~/Downloads/ に設定していますが、別のディレクトリも指定可能。

```zsh:terminal
$ defaults write com.apple.screencapture location ~/Downloads/　
↓デフォルトに戻す場合はこちら。設定値を削除するイメージです。
$ defaults delete com.apple.screencapture location
```

↓やっぱりデフォルトに戻したい場合。

```zsh:terminal
$ defaults delete com.apple.screencapture location
```

# 保存形式を変更

デフォルトではpngで保存されます。
複数のファイル形式を指定できます。
用途に応じて保存時に形式変更できるので最高！
こちらもコマンドラインから設定し、再起動すれば反映されます。

↓今回はjpgで保存する場合のコマンド。

```zsh:terminal
defaults write com.apple.screencapture type jpg;
```

# まとめ
これであなたのスクリーンショットライフは超快適になること間違いなしですね！

# 参考
- [macOSのスクリーンショット設定を変更する](https://qiita.com/tocomi/items/8c8e8f8202ea6da2c46d)
- [Macでスクリーンショットを撮る方法と保存先＆形式を変える方法](https://qiita.com/mamohacy/items/559af38aacb7a17a1600)
🔰モデル作成後のモデルの関連付けでわかった親と子

<p>ポートフォリオ作成中でアソシエーションを行った際にわかったことメモ…</p>
<h1>モデル同士のデータの関係性を記述</h1>
<h3>サイトの詳細</h3>
<p>ユーザはアカウントを持ちお店に対して口コミができる
<br>タグ検索によりお店が複数ヒットする
<br>ヒットしたお店にはお店情報と口コミが反映される
<br>ユーザは口コミに対していいねできる
<h3>使った機能</h3>
<div class="list">
<ul>
 <li>コメント機能</li>
 <p></p>
 <li>いいね機能</li>
 <p></p>
 <li>タグ機能</li>
 <p></p>
</ul>
</div>
</p>

<h3>作成したモデルにアソシエーションを記述していく</h3>
<p>belongs_to :モデル
<br>・これによりこのモデルが親ということがわかる
</p>
<p>has_may :モデル
<br>・このモデルにたくさんの子がいる
</p>
<h3>作成したモデルと関連付け</h3>
<ul>
 <li>user</li>
 <p>has_many :posts
 <br>私はたくさんの子（post）を持っていますよ
 </p>
 <li>post</li>
 <p>belongs_to :user
 <br>userの子供です
 <br>belongs_to :shop
 <br>shopの子供です
 </p>
 <li>like</li>
 <p>belongs_to :user
 <br>belong_to :post
 </p>
 <li>tag</li>
 <p>has_many :shops</p>
 <li>shop</li>
 <p>has_many :posts
 <br>has_many :tags
 </p>
 <li>shop_tag</li>
 <p>belong_to :shop 
 <br>belongs_to :tag</p>
</ul>

<h3>書いた理由</h3>
<p>英語がもともとできないので役割の理解に苦しむことが多かったので通訳するように書いてみました。
<br>不慣れなことなので間違いがございましたらご指摘よろしくお願いします。
</p>
awk 複数ファイルの取り扱い


個人的につまづいたところをピックアップしました。
pythonとか他の言語で書けよって話かもしれませんが、awk好きな人にどうぞ。

#ファイルから1行ずつ読み込む
$0が更新される。

```
awk 'BEGIN {while ((getline < "file1")>0)
               {
                   action
               }
           }'

ワンライナー
awk 'BEGIN {while((getline<"file1")>0){print $0;}}'
```

#ファイルから変数xに読み込む。
変数に読み込むことため、$0は更新されない。

```
awk 'BEGIN {while ((getline x < "file1") >0 ){print x}}'
```

#ファイルから変数xに読み込み、splitで分割
splitの使い方
split(strings, array, separator)
strings : 分割対象の文字列
array : データの格納先
separator : 区切り文字
array[index]で分割後のデータにアクセス可能

```
awk 'BEGIN {while ((getline x < "file1") >0 ) {split(x,array);print array[index]}}'
```


#複数ファイル読み込み(今回は2つのファイル)

```
awk 'BEGIN {while((getline<"file1")>0)
                {while((getline<"file2")>0)
                    {
                        action
                    }
                }
                close("file2")
            }'
ワンライナー
awk 'BEGIN{while((getline<"file1")>0){while((getline<"file2")>0{print $0}}close("file2")}'
```


#使用例
while文をネスト

```
awk 'BEGIN{OFS="\t"; while ((getline<"file1")>0){count=0; while((getline var <"file2")>0){split(var,array); if($2<=array[2] && array[3] <= $3){count++;}}close("file2");print $1, $2,$3,count}}'
```
3分アジャイル アジャイルソフトウェア開発宣言

私たちは、ソフトウェア開発の実践
あるいは実践を手助けをする活動を通じて、
よりよい開発方法を見つけだそうとしている。
この活動を通して、私たちは以下の価値に至った。

---
## プロセスやツールよりも〇〇を、

---
## プロセスやツールよりも〇〇を、

A. 正しいテスト
B. より良い習慣
C. 個人と対話
D. 検査と適応

---
## 包括的なドキュメントよりも〇〇を、

---
## 包括的なドキュメントよりも〇〇を、

A. 編集可能なドキュメント
B. 動くソフトウェア
C. 包括的なテスト
D. チームの合意

---
## 契約交渉よりも〇〇を、

---
## 契約交渉よりも〇〇を、

A. 顧客との衝突
B. 顧客との協調
C. 顧客との駆け引き
D. 顧客との合意

---
## 計画に従うことよりも〇〇を、

---
## 計画に従うことよりも〇〇を、

A. 変化への対応
B. 計画の見直し
C. 期限の延長
D. 顧客との合意

---

価値とする。すなわち、左記のことがらに価値があることを
認めながらも、私たちは右記のことがらにより価値をおく。

---

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47327/6ad68516-0505-6953-cc08-a2ee817c0234.png)


---
## デイリー

- 開発チームがスプリントゴールを達成するために、私が昨日やったことは何か？
- 開発チームがスプリントゴールを達成するために、私が今日やることは何か？
- 私や開発チームがスプリントゴールを達成する上で、障害となる物を目撃したか？
Azure API Management 作ってみた


## Azure API Management (APIM) とは
API Management は、Azure が提供するマネージドのAPI ゲートウェイサービスです。
API の一元管理や、監視、分析、セキュリティ、保護などのサービスも簡単に統合できます。

## APIM 主な機能
- API ゲートウェイ
    - バックエンドサービスへのルーティング
    - API Key、JWT Token (OAuth 2.0 / OpenID Connect)、証明書などの認証機能
    - 使用量クォータとレート制限
    - コード修正なしで、API変換
    - API キャッシュ
    - API 監視 (Application Insights)
- 開発者ポータル
    - API ドキュメントの閲覧
    - API テスト

## APIM の料金体系

||使用量| DEVELOPER|BASIC|STANDARD|PREMIUM
---|---|---|---|---|---|
使用目的|| 開発者|　エントリレベル|中容量	|大容量または<br/>エンタープライズ|
料金| ¥476 / 100 万件コール <br>最初の 100 万件は無料| ¥7.37/時間	|¥22.58/時間|¥105.36/時間|¥428.85/時間|


## APIM 構築してみた
1. API Management service 画面から新規インスタンスを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160072/3ca99752-6e8b-4113-0ff8-e4380c405d4f.png)

2. 必要な情報を入力し、**[Review + create]** ボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160072/5ee121d2-d777-2308-abc7-1c31b364cece.png)

3. 確認画面で [create] ボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/160072/7740c21a-9d0f-958d-2b1c-4f3cd88c50f4.png)

4. 作成完了まで　**15 ~ 45** 分ぐらいかかりまして、インスタンス作成完了後、Administrator にメールが届きます。
ServiceNow - 明示的にロールが付与されているかを確認する

#概要
g.user.hasRoleExactly()はadminロールをもつユーザだと必ずtrueが返される。明示的にロールが付与されているかを確認スクリプトです。

##スクリプトインクルード

```
var UserRole = Class.create();
UserRole.prototype = Object.extendsObject(AbstractAjaxProcessor, {
    userHasCustomerHRRole: function() {
        var roleName = this.getParameter('sysparm_role_name');
        var gr = new GlideRecord('sys_user_has_role');
        gr.addQuery('user', gs.getUserID());
	gr.addQuery('role.name', 'itiservice');
        gr.query();
        return gr.next();
    },
    type: 'UserRole'
});
```

クライアントスクリプト

```
function onLoad() {
    var ajax = new GlideAjax('UserRole');
    ajax.addParam('sysparm_name', 'userHasCustomerHRRole');
    ajax.addParam('sysparm_role_name', 'itiservice'); // 確認するロール名
    ajax.getXMLAnswer(function(answer) {
		alert(answer);
        if (answer == 'true') {
            g_form.setReadOnly('category', true);  // ロールが付与されている場合はcategoryフィールドを読取り専用にする
        }
    });
}
```
[AWS CloudFormation] IoTルールの定義

# `AWS::IoT::TopicRule`を使用したIoTルール定義

構文については[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-iot-topicrule.html)参照
ただし、以下のように記載されている`YAML`例が`YAML`ではなく`JSON`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/b2e36820-700a-0f33-8afe-bf52e8001407.png)

英語サイトの場合は、`YAML`例はちゃんと`YAML`になっている
ただし、bool値の箇所が`'true'`と文字列になっている（ただしくは`true`）等の誤りがあったりするので注意
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/c697c705-f744-b35b-bbd9-269daba81c41.png)

ということで以下が実際のIoTルール定義

```yaml

  # IoTルール
  EdgeRecvMessageTopicRule:
    Type: AWS::IoT::TopicRule
    Properties:
      TopicRulePayload:
        RuleDisabled: false
        Sql: SELECT * FROM '+/info'
        Actions: # IoTルールに合致した場合に実行するアクション（今回はLambda）
          - Lambda:
              FunctionArn: !GetAtt EdgeRecvMessageHook.Arn

  # IoTルールに合致した場合にフックされるLambda定義
  EdgeRecvMessageHook:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub '${StackName}_EdgeRecvMessageHook'
      CodeUri: Edge-Recv-Message/
      Handler: function.lambda_handler
      Runtime: python3.8

  # IoTからLambdaを実行する権限付与定義
  EdgeRecvMessageHookPermission:
      Type: AWS::Lambda::Permission
      Properties:
        Action: lambda:InvokeFunction
        FunctionName: !GetAtt EdgeRecvMessageHook.Arn 
        Principal: iot.amazonaws.com
```

## IoTルールの名前について

```yaml
  EdgeRecvMessageTopicRule:
    Type: AWS::IoT::TopicRule
    Properties:
      RuleName:
        !Sub '${StackName}_EdgeRecvMessage'
      TopicRulePayload:
        RuleDisabled: false
        Sql: SELECT * FROM '+/info'
        Actions:
          - Lambda:
              FunctionArn: !GetAtt EdgeRecvMessageHook.Arn
```

上記のようにスタック名をprefixにした`RuleName`にしようと考えたが、
スタック名に`-`が入っていたためエラーとなった。

IoTルールの名前には`_`は使用できるが、`-`は使用できない。
逆にCloudFormationのスタック名には`-`は使用できるが、`_`は使用できない。
ちなみにS3バケット名はスタック名と同様、`-`は使用できるが、`_`は使用できない。

`RuleName`は必須項目ではないので、自動生成される名前で逃げる手はあり。
自動生成されたルール名にはprefixとしてスタック名から`-`を除いた文字列が付く。
JavaScript 正規表現をchromeの検証モードで確認する

# 目的

- 正規表現の確認をchromeの検証モードでする方法をまとめる

# 前提情報

- Macでの確認方法をまとめる

# 方法

1. chromeを起動する。
1. 「Command」+「Option」+「I」もしくは「F12」を押下する。
1. 下記のように検証モードが起動する。

    ![新しいタブ_と_JavaScript_正規表現をchromeの検証モードで確認する_md_—_laravel6_session_verify.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/e03732be-1f9d-0451-f736-cabfc026aaf4.png)

1. 「Console」をクリックする。

    ![新しいタブ-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/d23ced90-119e-9db2-8320-0be6ca92e035.png)

1. 「https://qiita.com/miriwo は筆者のQiitaのホームです」という文字列の「https://qiita.com/miriwo」をヒットさせたいときの正規表現を確認したいときはコンソールに下記のように記載する。.exec()メソッドの公式ドキュメントのリンクはこちら→[http://js.studio-kingdom.com/javascript/regexp/exec](http://js.studio-kingdom.com/javascript/regexp/exec)

    ```console
    /正規表現/.exec('https://qiita.com/miriwo は筆者のQiitaのホームです');
    ```
1. URLを検索する正規表現は下記とする。（`?`は直前の文字が有るか無いか、`[^]`は内部に記載された内容のいずれかにマッチしないか、`\s`は垂直タブ以外のすべての空白文字であるか、`*`は直前の文字が繰り返さないか、`/g`は修飾子で繰り返しマッチを行う、をそれぞれ表している。）

    ```console
    /https?:\/\/[^\s]*/g
    ```
1. 上記を踏まえてコンソールに記載する内容を下記に記載する。

    ```console
    /https?:\/\/[^\s]*/g.exec('https://qiita.com/miriwo は筆者のQiitaのホームです');
    ```
1. 上記の内容をconsoleに入力する。

    ![新しいタブ-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/574b1ebd-0538-0836-7992-78966f6f358f.png)

1. 入力後Enterを押下する。下記のように結果が表示されるので矢印が指している右三角をクリックする。

    ![新しいタブ-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/543df34e-95e0-8e84-f12b-3e54839b261a.png)

1. 下記のように表示されヒットした内容（上の方の矢印）とヒットした内容（下の方の矢印）が格納されているインデックス番号が表示される。

    ![新しいタブ-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/4b09e826-d915-c1a5-f07c-3c2d9a25c1ec.png)

1. 本方法は自分が組み立てた正規表現文が、欲する文字列を取得できるかを確かめるために利用する。検索元文字列を固定して正規表現部分を修正てゆくことで気軽に検証しつつ正規表現文を考えることができる。
Windowsサービスのとりあえず知っておきたいコマンドラインからの起動・停止

# Windowsサービスの起動・停止をコマンドで実行したい

Windowsサービスの停止や起動を含むスクリプトを作るために、scコマンドを覚えましょう。
Windowsサービスを管理するためにとりあえず知っておきたいコマンドをまとめます。

## scコマンド

### サービス一覧 - 全部

```
sc query
```

### サービス一覧 - サービス名のみ

```
sc query | findstr /B SERVICE_NAME
```

### サービス一覧 - サービス名+状態

```
sc query | findstr /R "SERVICE_NAME STATE"
```

### サービス状態確認 - サービス名指定  
サービス名指定(service-name)

```
sc query service-name
```

### サービス状態確認 - サービス名指定 - サービス名+状態  
サービス名指定(service-name)

```
sc query service-name | findstr /R "SERVICE_NAME STATE"
```

### サービス停止  
サービス名指定(service-name)

```
sc stop service-name
```

### サービス開始  
サービス名指定(service-name)

```
sc start service-name
```

## おまけ

Windowsサービスの停止・起動がからむスクリプトを作るとき、ファイル作ったり、ファイルコピーしたりしたいかもしれません。Windowsのコマンドはこちらです。

### 空ファイルを作る  
ファイルパス指定(file-path\file-name)

```
type nul > file-path\file-name
```

### フォルダ下の全ファイルコピー  
入力フォルダ、出力フォルダ指定(from-directory-path to-directory-path)

```
xcopy /e from-directory-path to-directory-path
```
[iOS14]UIDatePickerを用いたカレンダー選択の見た目

#初めに
iOS14からUIDatePickerを用いた日付選択時の見た目が大きく変わっているそうです。
変更点については[こちら](https://qiita.com/kj_trsm/items/a53b0b3f7e1bc7c06106)の記事でまとめて頂いてます。
※上記記事はswift用なのでObjective-Cでは若干異なっています
業務でiOS14以上の場合には以前のカレンダー表示に戻す処理を実装する必要がありましたので紹介します。

#実装例
・xcode12での実装

```obj-c

if (@available(iOS 14.0, *)) {
    //iOS14以上の場合は見た目を合わせるよ
    datePicker.preferredDatePickerStyle = UIDatePickerStyleWheels;;
} else {
    //元のままだから何もしないよ
}
```
上記実装はxcode12以上でないとビルドエラーが出るようです。
##動作確認
実装した結果、iOS14のシミュレーター上で動作確認したところ
![英語版カレンダー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400181/4ed8c355-b683-d2b8-3804-a968ecec2f80.png)

あれ、なんか英語になってる・・・？

##調査
どうやらシミュレーターの設定によるっぽいので、シミュレーターの設定から言語を日本語に変更する必要がありました。
変更した結果
![日本語版.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400181/a2209470-110c-a94f-83b5-db8ddbe15a8d.png)
問題なさそうでした。
自宅でWeb制作している人向けのリンク一覧

#自宅でWeb制作している人に役立つと思われるリンク集です。
##前書き
自宅でWeb制作している人のための情報を集めたリンク集です。
クラウドやDockerにデータベース入れたりサーバー入れたりみたいな情報も
扱っていきたいと思います。

##リンク集
早見表・cheatSheetと言われているものです。
https://qiita.com/gina/items/f6847309d4038d576f89
要件定義　書き方　
←　大規模システム用ですが参考にはなると思います。
https://qiita.com/gina/items/e3d27c78701e039844d7
テストデータ作成
←　参考になると思います。
https://qiita.com/gina/items/4eb954492771e335df49
GIT　手順書フォルダ
←　エクササイズが特徴です。
https://qiita.com/gina/items/d278ec7a00fa56adc55b
JavaScriptHack Hackフォルダ　Form編
←　JavaScriptつらいですよね。
https://qiita.com/gina/items/3aa0174eda82532d68ea
JavaScriptHack Hackフォルダ　オブジェクト指向編/Dom編
←　Domつらいですよね。
https://qiita.com/gina/items/c4d45f50955bbc2bd5d5
Linux　コマンド　１６　手順書フォルダ（完了）
←　Progateだと足りないし・・・他だと多いし・・・自作ですがよろしく。
https://qiita.com/gina/items/db24e22299747b031534
AWS EC2にHTMLをアップロードする
←　こういう情報って本当にないので参考になると思います。
https://qiita.com/gina/items/c3a166d13e0d31ed5c4c
Pythonの環境構築です
私はこれ使っています。
https://qiita.com/7110/items/1aa5968022373e99ae28
Principalに指定したリソースがないとIAM Roleの作成に失敗する

#概要

AWSでクロスアカウントでアクセスする際にAssumeRoleを行うための設定をします。
例えばアクセス元のアカウントをA、アクセス先のアカウントをBとすると、アカウントBのAWSアカウントにAssumeRoleを許可するためのIAM Roleを作成します。
今回、このアカウントBに該当するアカウントで、IAM Roleを作成しようとして失敗しました。オチとしてはタイトルの通りなのですが、なぜ失敗したのか原因を調べたところ、IAMってちゃんと考えられてるな、と感心したので記事にしました。

#構成

今回はAWS Organizationsでアカウント管理をしている環境において、メンバーアカウントのLambdaからマスターアカウントのOrganizationsサービスが提供しているAPIを実行する場合を例として取り上げたいと思います。Organizationsの部分が例としては少し特殊かと思いますが、基本的にクロスアカウントでAPIを実行する場合は同じような構成になるかと思います。

![qiita_assumerole.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316261/79985dfc-4aaf-5772-951e-305cd31840c5.png)


#試したこと

メンバーアカウント側のLambdaの実装は後回しにして、ひとまずマスターアカウント側でIAMRoleを作成するためにCFnで以下のテンプレートを用意しました。
パラメータのMemberAccountIdにはアクセス元のAWSアカウント番号が入ります。

```yaml
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  PrincipalOrgID:
    Type: 'String'
  MemberAccountId:
    Type: 'String'
Resources:
  IAMRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: '2008-10-17'
        Statement:
        - Effect: 'Allow'
          Principal:
            AWS: !Sub 'arn:aws:iam::${MemberAccountId}:role/ichi0124-hogehoge-fugafuga'
          Action: 'sts:AssumeRole'
      Policies:
      - PolicyDocument:
          Version: 2012-10-17'
          Statement:
            - Effect: 'Allow'
              Action:
                - 'organizations:DescribeAccount'
              Resource: !Sub 'arn:aws:organizations::${AWS::AccountId}:account/${PrincipalOrgID}/${MemberAccountId}'
        PolicyName: 'get-organizations'
      RoleName: !Sub 'organizational-information-for-${MemberAccountId}'
```


マスターアカウントでこのテンプレートからCFnスタックを作成し、これでメンバーアカウント側の実装に集中できるぞ、と思ったのですが、作成時にエラーが発生しました。エラー内容は以下の通りです。

![iam_error.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316261/af890160-e1e4-32dc-c1e1-70ebf5a5aa48.jpeg)

#エラーの原因

`Invalid principal in policy` とイベントにあるのでprincipalの定義を中心にCFnテンプレートを見返したのですが、書き方的にはおかしいところはなかったため、ドキュメントを読み返しました。

そして、[こちらのドキュメント](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements_principal.html)にたどり着きました。注目すべきは以下の記載です。

> ロールのPrincipal要素に、特定のIAMロールを指し示すARNが含まれている場合、そのARNはポリシーを保存するときにロールの一意のプリンシパルIDに変換されます

今回エラーになった原因は、Principal要素に記載したIAMロールのARNをプリンシパルIDに変換しようとしたが、対象のIAMロールが存在しないために変換に失敗した、ということになります。明記はされていませんでしたが、Principal要素に記載したARNをプリンシパルIDに変換する際に実体が存在するかどうかの確認をIAMロールの作成時に行っているようです。この事実を知りませんでした。


# なぜこのような仕様になっているか

これについては以下の記載に集約されていました。

>ロールを削除して再作成することにより、誰かがそのユーザーの特権をエスカレートするリスクを緩和できます。通常、この ID はコンソールには表示されません。これは、信頼ポリシーが表示されるときに、ロールの ARN への逆変換が行われるためです。ただし、ロールを削除すると、関係が壊れます。ロールを再作成した場合でも、ポリシーは適用されません。これは、新しいロールは信頼ポリシーに保存されている ID と一致しない新しいプリンシパル ID を持っているためです。この場合、プリンシパル ID はコンソールに表示されます。これは、AWS が有効な ARN に ID をマッピングできなくなるためです。その結果、信頼ポリシーの Principal エレメントで参照されているロールを削除して再作成する場合は、ロールを編集して正しくなくなったプリンシパル ID を正しい ARN に置き換える必要があります。ポリシーを保存するときに、ARN は再びロールの新しいプリンシパル ID に変換されます。

概要をかいつまむと、単純にIAMロールのARNの文字列をチェックする場合だとロールを同名で再作成することで意図しない誰かに権限を奪われるリスクがある。しかし、ARNを独自のプリンシパルIDに変換することで、再作成時には同名のIAMロールであっても別のプリンシパルIDに変換されるため、上記の可能性を潰すことができる、ということのようです。

#おわりに

今回初めて知ったことではありますが、この動作仕様はかなり重要なもので、なるほどと思いました。
色々と考えて作られており、知らないうちに守られているんだなということを実感しました。
PHPのerror_log関数を使用しての仮想環境vagrantへのpath

自分用忘備録
var_dump等で値を確認できない時。
仮想環境vagrant上で開発時にデスクトップ上にerror_logファイルを作成しようとしたが、仮想環境のpathが違い少しハマった。
### 経緯
画面がエラーで表示されず、値を返さない裏側の処理があり、
デバッグで変数情報をファイル出力するerror_log関数で追っていくことにした。

開いているディレクトリは権限があり、
error_log(print_r($Data,true),"3","/vagrant/system/debug.log");

$Data ＝ 値を確認したい変数をセット
/vagrant/system/ ＝ vagrant上のpath(ディレクトリsystem以下にファイルが作成される)
debug.log = 新規ファイル名（なんでも構わない）

ファイルが作成された後は同じファイル名で再度叩くと同ファイルに値の内容が上書きされる。
## vagranのpath確認コマンド
```
$vagrant up
↓
$vagrant ssh（vagrantへログイン）
↓
[vagrant@localhost ~] $cd /vagrant/
 複数のファイルorディレクトリ名    system/
↓
[vagrant@localhost ~]$cd /vagrant/system/
↓
[vagrant@localhost system]$pwd
/vagrant/system
↓
[vagrant@localhost system]$ls (念の為systemディレクトリ内ファイル確認)
```
問題なさそうなら、値を調べたい箇所に以下error_log関数を記述。
error_log(print_r($Data,true),"3","/vagrant/system/新規ファイル名");
Windowsのショートカット(.lnk)のショートカットキーが効かなくなった話

Windowsのデスクトップにエディタなどのショートカットを置いて、「ショートカットキー」のところにキーを登録すると、そのアプリを1ストロークで開くことができて便利なのだが、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365182/6be337bf-9a7c-600d-29c7-afe6bc3e235f.png)

ある日突然この機能が効かなくなった。

なんでだろうと思ったら、いつの間にかデスクトップフォルダがOneDriveで共有されるようになっていた。(そういえばWindowsの更新時に「OneDriveでいろいろ共有しますか」みたいなことを聞かれた気が……)

デスクトップフォルダのOneDrive共有を解除したら、元通り使えるようになりました。めでたしめでたし。
【1分解決】Vue.jsで小技を用いてフォームを作ってみる

#はじめに
本記事へのアクセスありがとうございます。
投稿主はプログラミング初心者であり、この方法が**「最適解」**かは分かりません。
しかし、動作は検証済みです。

こんなやり方もできるんだ〜程度に見てもらえれば幸いです。

#さっそくスタート
この記事では下記の環境のフォームを作成します。

・インプットタグでenterキーを押すと、次のインプットタグへ遷移する
・2つ目のタグ内には半角数字のみを出力する

```vuejs
 <div>
    <input
      type="text"
      v-model="formOne"
      @keypress.enter="focusWord"
      autofocus
    />
    <input
      type="text"
      ref="focusWord"
      v-model="formTwo"
    />
  </div>
```

```javascript
data() {
    return {
      formOne: "",
      formTwo: "",
    };
  },
  watch: {
    formTwo: function (v) {
      this.formTwo = v.replace(/[Ａ-Ｚａ-ｚ０-９]/g, function (s) {
        return String.fromCharCode(s.charCodeAt(0) - 65248);
      });
      this.formTwo = v
        .replace(/[^0-9０-９]/g, "")
        .replace(/[０-９]/g, (s) =>
          String.fromCharCode(s.charCodeAt(0) - 0xfee0)
        );
    },
  },
  methods: {
    firstWord() {
      this.$refs.focusWord.focus();
    },
  },
```
#おわり
結論として、watchを利用してリアルタイムに文字判断をしてfocusメソッドを用いて遷移させましょう。

少しでも役に立ったと思う方がいましたらLGTMをお願いします🙇‍♂️
ユーザプロファイルに基づく認証済みユーザの @AuraEnabled Apex メソッドへのアクセスの制限 

このリリースノートの件です。
https://releasenotes.docs.salesforce.com/ja-jp/winter21/release-notes/rn_lc_restrict_apex_authenticated_users.htm

単に権限がありませんと出るかと思っていましたが、コミュニティーではコンポーネントが表示されないように報告されています。

https://trailblazers.salesforce.com/answers?id=9064S000000DKWy

I am trying to help a client with their community. At some point in the last month, a couple of custom lightning components stopped showing up in their community. (The last confirmed use was about a month ago, though they only started getting complaints this week.)

静的リソースも同じようになるみたいなので覚えておかないといけないですね。

Lightning コンポーネントの安全な静的リソースの有効化 (更新)
https://releasenotes.docs.salesforce.com/ja-jp/winter21/release-notes/rn_lc_secure_static_resources_update.htm

今のところ11/29以降が要注意。
Gitで間違えたブランチにAddやCommitしてしまった時に使うコマンド

Gitの詳しい記事はいくらでもあるので初心者向けの内容です。
最近良く使うのでまとめてみました。


## ```feature/b```に変更を入れたいのに、実はaddを```feature/a```でやってしまっていた！！
これでaddを取り消しできます。

```
git reset HEAD
```

1ファイルだけの場合は、ファイル名をつけましょう。

```
git reset HEAD test.txt
```


その後、stashで変更を保存し、

```
git stash
```

ブランチを```feature/b```に変更

```
git checkout feature/b
```

これで、```feature/b```保存した変更を反映

```
git stash pop
```

後は、改めて、addし直すだけです。


## ```feature/b```に変更を入れたいのに、実はcommitを```feature/a```でやってしまっていた！！
これでcommitを取り消しできます。
（```HEAD^```でローカルブランチのHEADを1つ手前に移動、しかし、```--soft```なのでローカルのファイルはいじらない、というコマンドです）

```
git reset --soft HEAD^
```

その後の流れはaddのときと一緒。stashで変更を保存し、

```
git stash
```

ブランチを```feature/b```に変更

```
git checkout feature/b
```

これで、```feature/b```保存した変更を反映

```
git stash pop
```
Reactを学ぶVIII 〜ライフサイクルUpdateとUnmountを使う〜

## ■ はじめに

タイトルについて記事にしました。
この記事で得る内容は以下の通りです。

・ Reactの基礎知識が増える
・ ライフサイクル（Update及びUnmount）の実演

## ■ 例（前回の続き）

前回、いいねボタンを作って、ボタンをクリックするとカウントアップした所までやりましたので
次にライフサイクル（Update及びUnmout）を実際に使ってみたいと思います

![カウントアップされていく.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/772631/cb9169bc-0ca1-5992-0e44-80a410e53b30.gif)

## ■ componentDidUpdate使用例

内容は、いいね数が10以上になると0に戻るという処理にします

```react:Blog.jsx
componentDidUpdate() {
  if (this.count.state >= 10) {
  this.setState({count:0});
  }
}
```

いいね数が10以上になると0に戻りました

![componentDidUpdate.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/772631/6ca0f68d-27df-6065-f23f-6ca0e1fccb55.gif)

## ■ componentWillUnmount記述例

ページを変えるとイベントリスナーが不要になるので`add`だった所を`remove`に変えます

```react:Blog.jsx
componentWillUnmount() {
  document.getElementById("counter").removeEventListener("click",this.countUp);
}
```

リスナーの解除を行う事で、リソースが開放され、サーバーに負荷が掛からなくなります
OBSでYoutubeのメンバー限定配信のコメントを取り込む

OBSではブラウザソースを使用することでYoutubeのコメントを取り込むことができます。
しかし、メンバー限定配信については通常の方法では取り込むことができません。
この記事では取り込む方法について解説します。
(あまりお勧めはできません。)

**以下の内容は何が起こっても自己責任で実行してください。**
**OBSやChromeのバージョンによってはうまく動かない可能性があります。**

**検証バージョン**
**Chrome  86.0.4240.193**
**OBS 26.02**

## 概要

メンバー限定配信のコメントを取り込めない理由は単純で、OBSのブラウザではYoutubeにログインしていないからです。
コメントを取り込むためにはOBSのブラウザでYoutubeにログインする必要があります。
OBSのブラウザには対話機能があり、ある程度の操作が可能です。
この機能を使用してYoutubeへログインできれば何も問題はありませんが失敗することがあります。
(ここでログイン可能な方はこれ以降の操作は必要ありません。)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42193/8281c92f-6fcc-ea9b-a101-f31e8e5410e0.png)

これはOBSが内蔵しているブラウザのバージョンが最新のChromeよりも古いため起こります。
今回は**ログイン情報が記載されたファイルを直接書き換える**ことで無理やりログイン状態に変更します。

## 必要なもの

* メンバー限定配信を見れるアカウント
* 最新バージョンのChrome
* 最新バージョンのOBS
* Python3系
* [yaegaki/OBSCookieImporter](https://github.com/yaegaki/OBSCookieImporter)

## 手順

### 1. OBSでYoutubeをブラウザソースとして追加する

[トップページ](https://youtube.com)でいいのでソースを追加します。

### 2. ChromeのデフォルトユーザーでYoutubeにログインする

メンバー限定配信を見れるアカウントでログインします。

### 3. OBSCookieImporterを実行する

実行には`OBSCookieImporter`は`cryptography`というライブラリに依存しています。
実行前に以下のコマンドでインストールします。

```sh
$ pip install cryptography
```

`cryptography`のインストール後にOBSCookieImporterに含まれるpythonスクリプトを実行します。
この時、ChromeとOBSは必ず終了しておいてください。

```sh
$ python main.py
```

実行すると以下のようなログが出力されます。
最後に`complete!`と出ていれば成功です。

```
replace host:.youtube.com name:APISID
replace host:.youtube.com name:CONSENT
replace host:.youtube.com name:HSID
replace host:.youtube.com name:LOGIN_INFO
replace host:.youtube.com name:NID
replace host:.youtube.com name:PREF
replace host:.youtube.com name:SAPISID
replace host:.youtube.com name:SID
replace host:.youtube.com name:SIDCC
replace host:.youtube.com name:SSID
replace host:.youtube.com name:VISITOR_INFO1_LIVE
replace host:.youtube.com name:YSC
replace host:.youtube.com name:__Secure-3PAPISID
replace host:.youtube.com name:__Secure-3PSID
replace host:.youtube.com name:__Secure-3PSIDCC
replace host:.youtube.com name:_ga
replace host:.youtube.com name:_gcl_au
replace host:.youtube.com name:s_gl
replace host:.youtube.com name:wide
complete!
```

### 4. OBSを開いてログインできているか確認する

最初に追加したYoutubeのページでログイン状態になっていれば成功です。
後はメンバー限定配信のソースを追加すれば完了です。

## 技術的な話

技術的にはChromeのクッキーをOBSのブラウザのクッキーに上書きしています。
少し面倒なのはChromeのv80以降でクッキーの保存方法に変更が入っていることです。

参考:[AESで暗号化されたWindows ChromeのCookieを復号する【python】](https://qiita.com/taizan_hokuto/items/bff1a1ccd65655e1c386)

OBSのブラウザのクッキーはv80より前の形式で保存されているためそのままファイルをコピーするだけではうまく動きません。
[yaegaki/OBSCookieImporter](https://github.com/yaegaki/OBSCookieImporter)ではChromeのクッキーを読み込んで復号した後、改めてOBSのクッキーに暗号化して書き込むということを行っています。

## 最後に

結構面倒なので現状は諦めたほうがいいと思います。
また、この方法で実際にできるかどうか確かめたわけではありません。
もしやってみてできたという方がいればコメントください。