OmniAICreator/Qiita-1.07M huggingface dataset:
GitHub Actionsを利用してXserverに自動デプロイする

# 目的

（現状）
ローカル開発→作業ブランチPush→masterにマージ→**XserverにFileZillaにてデプロイ**

（理想）
ローカル開発→作業ブランチPush→masterにマージ→**Xserverに自動デプロイ**

GitHubと連動して自動デプロイを行う場合はCircleCIを利用するのが一般的かなと思っていたのですが、GitHub Actionsでもできるとのことでしたので調べてやってみました。

# 各種設定

### 1. Xserverの設定

特に必要ありません。

### 2. GitHub Actionsの設定
#### 2.1 GitHubのsettingsにてFTP情報を設定する
GitHub対象リポジトリの`settings > secrets`にて下記情報を設定します。

- FTP_SERVER：ftpサーバのホスト
- FTP_USERNAME：ftpサーバのアカウント名
- FTP_PASSWORD：ftpサーバのパスワード

[FTPソフトの設定 | レンタルサーバー【エックスサーバー】](https://www.xserver.ne.jp/manual/man_ftp_setting.php)

ここで設定した値はyml記述時に利用します。

#### 2.2 deploy.ymlの作成
対象リポジトリ直下に`.github/workflows/`ディレクトリを作成し、その下に`deploy.yml`ファイルを設置します。このファイルにデプロイ時の指示を記述していきます。

今回はビルドはないので純粋にデプロイだけ行います。

```yml:.github/workflows/deploy.yml
on:
  push:
    branches:
      - master
name: Deploy
jobs:
  FTP-Deploy-Action:
    name: FTP-Deploy-Action
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@master
      - name: FTP-Deploy-Action
        uses: SamKirkland/FTP-Deploy-Action@2.0.0
        env:
          FTP_SERVER: ${{ secrets.FTP_SERVER }}
          FTP_USERNAME: ${{ secrets.FTP_USERNAME }}
          FTP_PASSWORD: ${{ secrets.FTP_PASSWORD }}
          LOCAL_DIR: ./
          REMOTE_DIR: /デプロイ対象のサイト/public_html/
```

# 実施
上記で設定が完了したので、実際に試してみます。

作業ブランチをmasterにマージすると設定したアクションが動き出します。

![スクリーンショット 2020-10-27 20.34.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/378711/4d86a86e-0de2-de92-6f39-73e063902ac5.png)


無事完了したようです！

![スクリーンショット 2020-10-27 20.37.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/378711/c13ddf84-7b5e-9240-14bd-a855546118a8.png)


サイトを確認したところデプロイできておりました🎉

# 最後に
今回は単純にデプロイしただけでしたが、フロントのソースをビルドした後にデプロイみたいなことも簡単にできそうでしたので機会があれば試してみたいと思います。


# 参考
[GitHub Actionsを使ってFTP自動デプロイ（Webサイト公開）を実現！ソフトを使った手動アップロードを卒業する](https://arrown-blog.com/githubactions-ftp-deploy/)
"オブジェクト指向"は存在しなし、"オブジェクト"と言う表現は使わない。

# 前提
- <strong>PHPに関してです(特にJavascriptは異なります)

- <strong>細かなことはいったん省き、考え方に個人的な線引きをしておきたい

- 変数、関数、プロパティ、メソッドの表記の使い分けはこの記事の本質から逸れるため、わかり易く日本語の「変数」「関数」で統一しています

- 人によって異なる部分は多いと思いますので他の記事で補完してください m(_ _)m


# 対象
- クラスとインスタンスはなんとなくわかるが(この記事では詳細な説明は省くため)、結局`オブジェクトやオブジェクト指向ってなんだっけ？`ともやもやしている方

 

# まず"オブジェクト"の定義

### 定義

よくみかける「変数と関数の集合体」という表現が誤解を生んでいると思う。
これでは以下もオブジェクトということになるが、これはオブジェクトでは無い。
※ ただの変数と関数が1つずつあるだけである。

```php
$name = '田中太郎';

function printName($name)
{
   echo 'こんにちは、' . $name;
}

//実行: printName();
//結果: こんにちは、田中太郎
```
誤解を生まない表現としては以下3点をクリアしている必要がある。

`①変数と関数がグルーピング`されており、`②必ずグループ名がある`。
また`③グルーピングするための書き方は言語によって決まった書き方がある`。

### ではオブジェクトとは
①②③を適応してオブジェクト化していく。

```php
class グループ名 //←②グループ名
{ //←①(グルーピングの始まり)
  private $name; // ←③(グルーピング内での変数の書き方)
  public function __counstruct($name) // ←③(グルーピング内での関数の書き方)
  {
     $this->name = $name;
  }
  public function printName() // ←③(グルーピング内での関数の書き方)
  {
     echo 'こんにちは、' . $this->name;
  }
} //←①(グルーピングの終わり)

//実行: 
//$インスタンス名 = new グループ名('田中太郎');
//$インスタンス名->printName();
 
//結果: 
こんにちは、田中太郎
```
これはPHPの場合です。
※Javascriptでは書き方は変わるが大抵の場合は①②③はクリアしている。
要は、プログラミング言語ごとに区切って考えれば何がオブジェクトで何がオブジェクトでは無いかは明確に説明できるため、まずはオブジェクトに関しては曖昧な状態から脱却できる。

`オブジェクトとは「変数と関数をひとまとめにしたクラスを作るプログラミングの手法」`


# オブジェクトという表現は極力避ける
まずPHPを書いていてオブジェクトは出てこない。
①②③の定義を元にグルーピングしたデータが一切出てこないと言うわけではなく、ご存知の通り表現が`class(＝オブジェクト)とinstance(＝オブジェクト)`のどちらかを使う。そのため、曖昧な認識から脱却するためには「オブジェクト」という曖昧な表現は極力避けると混乱しにくい。

# 結局オブジェクト指向とは
特に初学者向けの記事や質問に多いがこれは人に聞かない方がいいと思う、なぜなら人によって説明の仕方が違い余計混乱するからだ。

ただ、あえていうなら`たくさんのオブジェクトがあるシステム`、そして`classとinstanceを使えば理解していることと同じ`だよー。これで十分なのではないかと思った。

# メモ
### PHP
連想配列 ≠ オブジェクト
https://coinbaby8.com/different-between-object-and-array.html

### Javascript
連想配列 = オブジェクト
https://qiita.com/zero_046/items/19488a1a190edb7307b9#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88object
AWSアソシエイト資格3冠した自分の勉強法

# はじめに
AWSアソシエイト資格3冠達成したので、自分が行ってきた勉強法をつらつら書いていこうと思います
Qiita投稿自体初めて＋文章力がないためお手柔らかにお願いします🙇‍♂️

# 筆者のスペック
Sier系企業2年目
AWSでの業務経験4ヶ月程度
基本情報しか資格ない（）

超低いです

# なぜAWSアソシエイト資格を取得しようと思ったのか？
業務上必要という以前にかっこよかったから（）
あとはアソシエイト資格はソリューションアーキテクト、デベロッパーオペレーション、システムオペレーションの3つあるのですが、知識レベルでは類似している問題が多いため、並行して取得できるのはコスパいいなと思ったからです

# どうやって勉強したか？
以下のステップに沿って勉強していきました。

### 1.基礎知識のインプット
AWSって何それ？状態から始めたので、体系的に学べる参考書を選びました。
アソシエイト系の本は一杯あるので、自分に合うものを選んだ方がいいと思います、
自分は以下の本を買いました

[この1冊で合格! AWS認定ソリューションアーキテクト - アソシエイト テキスト&問題集 (日本語) 単行本](https://www.amazon.co.jp/この1冊で合格-AWS認定ソリューションアーキテクト-アソシエイト-テキスト-問題集/dp/4046042036/ref=nodl_)

### 2.AWS勉強用アカウントの登録
書籍の知識だけでは限界があるので、AWSに登録しました。
登録するとお金かかるよ、、って心配でしたが、勉強する程度なら月100円行かないくらいで済ませられるので大丈夫です

ただ、最低限の設定は行ったほうが良いです。セキュリティ的に
・2段階認証は有効化する
・ルートユーザーではなく、IAMユーザーを使用する
・請求額をメール通知する用に設定する
~~（NATを消し忘れて3000円くらい請求された人もいます）~~

### 3.問題集を反復
色んな問題集を試しましたが、以下サイトの問題集が最高です！
[koiwaclub](https://aws.koiwaclub.com/)

AWS試験の公式模試をベースに問題が作成されていて、一番本番形式に則した問題集かと思います。
udemyも購入したのですが、75問解き終わらないと回答が見られないのと、ニッチな問題が多くて自分には合いませんでした（個人差あるとは思います）

問題集の使い方としては、間違った理由によって以下のように対応しました
A.用語がわからなかった
⇨参考書、ホワイトペーパで復習
B.コンソール上での使い方がわからなかった
⇨AWSマネジメントコンソールで機能を触ってみる
C.根底のIT知識が不足していた
⇨ググる。オンプレとクラウドでどのように対応しているか確認する

個人的にBとCが大事だと思っています。
Bについては、AWSサービスを触ってみる機会になるし、構築しなくても実際の使い方を学ぶことでイメージが数倍つきやすくなると思います。

Cについては新人向けかもしれないですが、単純に基盤系の知識が付くからです。
自分は元々アプリ寄りの人間で、基盤周りやネットワークはイメージつきにくくて敬遠してました。
ただ、クラウドで簡単に基盤構築できるので、基礎的な知識を後付けで学ぶことができました。
AWSの用語だけでなく、背景の技術についても合わせて勉強すると一石二鳥なので、めんどくさがらずに逐一調べていくといいと思います。

問題集を解いて、間違った理由に従って調べるというのを反復することで、他のアソシエイト資格でも使える知識が身につくかと思います。

# 誰と勉強したか？

自分は真面目系クズなので、強制的に勉強するように以下の勉強用アプリを使用していました

[みんチャレ](https://minchalle.com/)

5人1グループで毎日勉強した結果を共有し合うため、毎日勉強する習慣が付きました

また、技術的知見の高い方からSEではないけどIT知識を勉強している方など、多種多様で刺激になりました
感謝、感謝です

# 終わりに

初めてQiita記事書きましたが、全然技術的知見のない内容になりました汗
他のAWS資格を取得したら別途また記事にしてまとめようと思います。
稚拙な文章ですが、ここまで読んでいただきありがとうございました。
ActiveHashはアソシエーションをしっかり設定しよう

※結果を知りたい方は下の方までスクロールしてください。

# エラー発生

商品を出品する機能を実装中のこと…


![d812404dd725355d1e491026dce6f911.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/814517/fe493bc0-b0ed-c832-2e9d-7d0376f350ac.png)
何これ…初めて見た…


# 原因を探る

コントローラーの記述は間違ってないよね…

```ruby:item_controller.rb&nbsp;一部割愛
class ItemsController < ApplicationController

  def create
    @item = Item.new(item_params)
    if @item.valid?
      @item.save
      redirect_to root_path
    else
      render :new
    end
  end

  private
  def item_params
    params.require(:item).permit(:name, :info, :price, :category_id, :status_id, :delivery_charge_id, :shipment_source_id, :date_of_shipment_id).merge(user_id: current_user.id)
  end

end

```
うん…大丈夫

ええー
じゃあモデルかなぁ

```ruby:item.rb
class Item < ApplicationRecord

  validates :name, :info, :price, presence: true
  validates :category_id, :status_id, :delivery_charge_id, :shipment_source_id, :date_of_shipment_id, numericality: { other_than: 1 }

  belongs_to :user
  has_many   :comments
  has_one    :buyer

  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to_active_hash :category, :status, :delivery_charge, :shipment_source, :date_of_shipment
end
```

いや、記述の抜け漏れもないし、半角全角もスペルも大丈夫
バリデーションも大丈夫（←これが落とし穴）

ビューファイル（割愛）は…うーん大丈夫そう

そして、インターネットの海を彷徨うこと30分…
本当にわからん

しゃあないか

# 助け舟を呼ぶことに

大海に投げ出されたような気分だったのでもうこれは人に聞くしかあるまい
某短期講習中なので頼もしい方々に聞くことはできる

早速原因究明に向けて色々と思案してくださった
ありがたや〜😌

…

これを、あれを試し、色々触っていった結果どうやらモデルの記述に問題があった模様

```
class Item < ApplicationRecord

  validates :name, :info, presence: true
  validates :price, presence: true
  validates :category_id, :status_id, :delivery_charge_id, :shipment_source_id, :date_of_shipment_id, numericality: { other_than: 1 }

  belongs_to :user
  has_many   :comments
  has_one    :buyer

  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to_active_hash :category
  belongs_to_active_hash :status
  belongs_to_active_hash :delivery_charge
  belongs_to_active_hash :shipment_source
  belongs_to_active_hash :date_of_shipment

end

```
<br>
↓つまりはこの部分↓


```
  belongs_to_active_hash :category
  belongs_to_active_hash :status
  belongs_to_active_hash :delivery_charge
  belongs_to_active_hash :shipment_source
  belongs_to_active_hash :date_of_shipment
```

ここを別々に書くだけ！
バリデーションなんやからまとめて書かせてくれや…と思ったが、


この話をしていると聞いていたうちの一人が
<br>
<br>
<br>
「それバリデーションじゃなくてアソシエーションですよ」
<br>
<br>
<br>
…まじかぁ…
まじかぁぁぁぁ！！！

恥ずかしいぃ！///
そういやそうだわ！思いっっきりBelongs_toって書いてあるし！
なんなら俺がActiveHashを導入してた時にrails gで生成してたものは？

モデルだよ！
モデルを生成してたんだよ！
それを関連付けるんだからアソシエーション以外に何があんの！

知らなかったとはいえ思いつく材料は目の前にあった訳だ
反省するとともに判断材料が増えたので一歩前進したと思う
<br>
本当に今回は勉強になった
真摯に対応してくれた方ありがとうございました
react + typescriptでローカルから画像を選択してプレビュー画面を表示させる方法

## やりたいこと
ローカルにある画像ファイルを選択して、プレビューを表示させたい！


## コード

```
export const UploadImage: React.FC = () = {
    const imageHander = (event: ChangeEvent<HTMLInputElement>) => {
        if (event.target.files === null) {
            return;
        }
        const file = event.target.files[0];
        if (file === null) {
            return;
        }
        let imgTag = document.getElementById("preview") as HTMLImageElement;
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = () => {
            const result: string = reader.result as string;
            imgTag.src = result;
        }
    };
    return (
        <div>
            <input type="file" accept="image/png, image/jpeg, image/gif" onChange={imageHander} />
            <img id="preview" src=""></img>
       </div>
    );
}
```

## 解説


```
let imgTag = document.getElementById("preview") as HTMLImageElement;
```

ここでは、`HTMLImageElement`に型を変換しています。これは、デフォルトでは`document.getElementById("preview")`の型が`HTMLElement | null`となっており、このままでは`src`パラメータの設定ができないからです。


```
reader.onload = () => {
    const result: string = reader.result as string;
    imgTag.src = result;
}
```
ここでは`reader.result`の型を`string`に変換しています。これは、デフォルトでは`reader.result`の型が`string | ArrayBuffer | null`となっており、新たな`src`の値として与えることができないためです。
これでスポットリクエストのキャンセルし忘れとさらばだ！

# 概要

　開発環境にEC2のスポットインスタンスを利用することはよくあると思います。その中でも「**永続的リクエスト**」を使っているとついついインスタンスだけを「終了」し、スポットリクエストをキャンセルし忘れることありませんか？リクエスト有効期間内であれば、自動的に同じタイプのインスタンスがゾンビのごとくのように再作成され、無駄な課金が発生します。
　インスタンスの削除時にスポットリクエストからキャンセルするように運用手順で決めていてもついつい忘れがちなので、自動化する方法を紹介します。

前提条件のまとめ

- スポットインスタンスを使用している
- 永続的リクエストである
- リクエスト有効期限内である

# 構成

EventBridgeを使用することで、インスタンス終了イベント時に指定したLambdaを実行し、スポットリクエストをキャンセルします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30522/dda5a741-2ba2-e825-3557-160991475df8.png)

# EventBridge

イベントとしてインスタンスの状態変更通知で「Terminated」を追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30522/21d73318-1f59-2631-c206-72f8408a23cd.png)

```json:eventbridge.json
{
  "detail-type": [
    "EC2 Instance State-change Notification"
  ],
  "source": [
    "aws.ec2"
  ],
  "detail": {
    "state": [
      "terminated"
    ]
  }
}
```

# Lambda

Lambdaにアタッチされているロールに以下の権限（インスタンスの情報取得、スポットリクエストのキャンセル）を含めればOKです。

```json:role.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ec2:CancelSpotInstanceRequests",
                "ec2:DescribeInstances"
            ],
            "Resource": "*"
        }
    ]
}
```

EventBridgeから渡される変数は以下になります。
同時に複数のインスタンスを削除した場合でも、1つずつのイベントとして送られますので、
Lambda側では基本的に単数を想定した実装でよいでしょう。

```json:event.json
{
  "version": "0",
  "id": "xxxxxxxxxxxxxxxxxxxxxx",
  "detail-type": "EC2 Instance State-change Notification",
  "source": "aws.ec2",
  "account": "xxxxxxxxxx",
  "time": "2020-10-26T09:28:11Z",
  "region": "ap-northeast-1",
  "resources": [
    "arn:aws:ec2:ap-northeast-1:xxxxxx:instance/i-xxxxxxxxxxxx"
  ],
  "detail": {
    "instance-id": "i-xxxxxxxxxxxx",
    "state": "terminated"
  }
}
```

eventのinstance-idからインスタンスの情報を取得し、関連するスポットリクエストをキャンセルする。

```python:cancle_spotrequest.py

import json
import boto3

def lambda_handler(event, context):
    '''
    EC2インスタンス削除時に関連するスポットリクエストをキャンセルする
    '''

    print('--------event----------')
    print(event)
    print('------------------')

    client = boto3.client('ec2')

    event_detail = event['detail']
    if event_detail['state'] != 'terminated':
        return

    # インスタンスIDで終了済みのスポットインスタンスを取得する
    response = client.describe_instances(
                    Filters=[{
                        'Name': 'instance-state-name',
                        'Values': ['terminated']
                    },{
                        'Name': 'instance-lifecycle',
                        'Values': ['spot']
                    }],
                    InstanceIds=[event_detail['instance-id']]
                )

    # 対象がなければ、終了
    if len(response['Reservations']) <= 0:
        return

    spot_request_id = ''
    for reservations in response['Reservations']:
        for ins in reservations['Instances']:
            spot_request_id = ins['SpotInstanceRequestId']

    print('--------cancel id----------')
    print(spot_request_id)
    print('------------------')

    # スポットリクエストをキャンセル
    client.cancel_spot_instance_requests(SpotInstanceRequestIds=[spot_request_id])

```
LaravelのEloquentでポリモーフィック関連

# ポリモーフィック関連とは
あるエンティティが複数のテーブルを参照しているような状態のこと。
アンチパターンにもあるとおり基本的に使用しない最後の手段的なイメージだが使った方が便利なケースもある。今回は使っても良さそうなケースに当てはまって触ってみたのでその備忘録。

# 要件
コンテンツ→設定一覧→記録一覧（ポリモーフィック ）→記録詳細のよう繋げ方をしたい。
ポリモーフィック関連にしない場合には例えばあんまり好ましくないけれど絶対に上限が決まっている場合には、それぞれのテーブルの外部キー用のカラムを作成してsettingテーブルに持たせるとか、テーブルを増やして対応するとかになると思う。

登場テーブル一覧

 * contents
 * settings
 * setting_measurables
 * measure_a_recordings
 * measure_a_records
 * measure_b_recordings
 * measure_b_records
 * measure_c_recordings
 * measure_c_records

リレーションのイメージ
![ポリモーフィック .png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209804/613cc88e-af96-e854-f23d-1c865350e587.png)

#マイグレーション
ポリモーフィック関連に使用するテーブル（setting_measurables）のマイグレーションに関してだけ書く。ポリモーフィック関連を使用する場合マイグレーションの段階でmorphを使うど便利、リレーションに必要なカラムを指定したキーワードから作成してくれる。マイグレーションファイルを見たときにポリモーフィック関連を使用することが明示的にわかるので便利。

```php:create_setting_measurables_table.php
public function up()
    {
        Schema::create('setting_measurables', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->unsignedBigInteger('setting_id');
            $table->foreign('setting_id')->references('id')->on('settings')->onDelete('cascade');
            $table->morphs('measurable'); // measurable_id, measurable_typeを作成
            $table->timestamps();
        });
    }
```

#モデル

```php
class Setting extends Model
{
    protected $fillable = ['content_id'];

    public function measureARecordings()
    {
        return $this->morphedByMany(
            'App\Models\MeasureARecording',
            'measurable', //morphsに指定したカラム名
            'setting_measurables' //テーブル名
        );
    }

    public function measureBRecordings()
    {
        return $this->morphedByMany(
            'App\Models\MeasureBRecording',
            'measurable',
            'setting_measurables'
        );
    }

    public function measureCRecordings()
    {
        return $this->morphedByMany(
            'App\Models\MeasureCRecordings',
            'measurable',
            'setting_measurables'
        );
    }
}

```

#呼び出し
withでEagerLoadingももちろんできる。

```php

public function getMeasureArecording($content_id)
{
    return Content::with([
        'settings',
        'settings.measureARecordings',
        'settings.measureBRecordings',
        'settings.measureCRecordings',
    ])->find($content_id);
}

```

#保存
```php

public function storeSettingMeasurable(Request $request)
{
    SettingMeasurable::create([
        'setting_id' => $request->input('setting_id'),
        'measurable_id' => $request->input('recording_id'), //それぞれのレコーディングテーブルの外部キー
        'measurable_type' => 'App\Models\MeasureARecording' //namespace含む対象モデル名
    ]);
}

# まとめ
ORMだと随所でポリモーフィックであることを明示できるのと、呼び出しがより簡潔になるので利用してみたが、慎重にCURDしないと不整合が起きるので、頻繁には使わない方がいい。ORMを使用しないならより複雑な処理が必要になるはずなのでORMで無い場合にも避けるべきだとは思った。
【vue】methodsの省略表記と注意点（アロー関数は使えない）

#【vue】methodsの省略表記と注意点

・OK：functionを使わない省略表記を使うのが一般的。
・NG：アロー関数を使う


```js:省略表記
methods:{
    メソッド名(){
      処理
    }
 }
```

メソッド名の後ろにカッコを直接つける。




<br>
##NG事例（アロー関数）
アロー関数を使った場合、処理の中でプロパティを呼び出すことができない。

```js:NG事例（アロー関数）
export default {
  data(){
    return{
      text: "ボタン"
    }
  },
  methods:{
    メソッド名:()=>{
      console.log(this.text)
    }
 }
}
```

```:エラー内容
[Vue warn]: Error in v-on handler: "TypeError: Cannot read property 'text' of undefined"
```

textを正しく設定してるのに、呼び出すことができない。


<br>
##参考（３つの処理）

1. 省略形
2. function使用（冗長表記）
3. アロー関数（NG事例）

```vue:Methods.vue
<template>
  <div>
    <v-btn @click="showConsole1">
      {{text}}1
    </v-btn>

    <br>
    
    <v-btn @click="showConsole2">
      {{text}}2
    </v-btn>
    
    <br>
    
    <v-btn @click="showConsole3">
      {{text}}3
    </v-btn>
  </div>
</template>

<script>
export default {
  data(){
    return{
      text: "ボタン"
    }
  },
  methods:{
    showConsole1(){
      console.log("showConsole1：", this.text)
    },
    showConsole2:function(){
      console.log("showConsole2：", this.text)
    },
    showConsole3:()=>{
      console.log("showConsole3：", this.text)
    }
  }
}
</script>
```

**▼ブラウザの表記**

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/3185cef1-e7b2-c8a7-095f-83700627cc46.png)|
|:--|


**▼実行結果**

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/3b0a9abc-38a4-aac5-5cd0-d3e9b47e52b3.png)|
|:--|

ボタン１、２は正常に作動するが、アロー関数を用いた３はエラーとなる。
便利そうなAA

Github などで見かけた便利そうな AA をメモしてく

## 目次

 * リクエストフロー

## リクエストフロー

```
┌────────────────────┐
│      Consumer      │
└────────────────────┘
           │
           ▼
┌────────────────────┐
│GET / HTTP/1.1      │
│Accept: */*         │
│Host: mockbin.com   │
└────────────────────┘
           │             ┌─────────────────────────────────────────┐
           ▼             │{                                        │
┌────────────────────┐   │  "public_dns": "mockbin.com",           │
│        Kong        │───│  "target_url": "http://173.236.235.78/" │
└────────────────────┘   │}                                        │
           │             └─────────────────────────────────────────┘
           ▼
┌────────────────────┐
│GET / HTTP/1.1      │
│Accept: */*         │
│Host: 173.236.235.78│
└────────────────────┘
           │             ┌─────────────────────────────────────────┐
           ▼             │{                                        │
┌────────────────────┐   │  "public_dns": "mockbin.com",           │
│        Kong        │───│  "target_url": "http://mockbin.org/"    │
└────────────────────┘   │}                                        │
           │             └─────────────────────────────────────────┘
           ▼
┌────────────────────┐
│  API not found :(  │
└────────────────────┘

           x
┌────────────────────┐
│    mockbin.org     │
└────────────────────┘
```

[use the requested Host header in the proxied request · Issue #444 · Kong/kong](https://github.com/Kong/kong/issues/444)
クリックイベントでMouseかEnterキーかを判定する

## 動機

`button`要素はクリックした時にfocusがあたった状態になるので、
デザインの再現の際に、不都合があることがあります。

```css
button:focus {
    outline: none;
}
```

上記のようにfocus時のスタイルを消してしまえば、いったんは良いのですが、
キーボードでアクセスした時に、その`button`がfocusされているのか視覚的に分からないため、アクセシビリティ的には良くありません。

ですので、マウスでクリックした時はfocus時のスタイルを消し、キーボードアクセスでfocusされた時は、スタイルを残せるようにJavaScriptで判定したいと思います。

## 実装例

```js
const button = document.querySelector('button');

const onClickButton = (event) => {
    if (event.detail !== 0) {
        event.currentTarget.style.outline = 'none';
    }
}

const onFocusButton = (event) => {
    event.currentTarget.style.outline = '';
}

button.addEventListener('click', onClickButton, false);
button.addEventListener('focus', onFocusButton, false);
```

## 解説

### `onClickButton`の箇所

clickイベントの時、引数eventにはMouseEventオブジェクトが入ります。
MouseEventには（自分が確認した限り）、keydown時の`event.key`のように押下されたキーを判定できるプロパティが無かったため、`event.detail !== 0`で、マウスのクリックなのか、Enterキーなのかを判定しました。

`event.detail`が何かと言うと、クリック数を読み取り専用で返してくれるプロパティのようです。

[UIEvent.detail - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/UIEvent/detail)

ですので、今回はクリック数がゼロかどうかで、MouseかEnterかを判定しています。
つまり、

`event.detail !== 0`は、クリック数が**0以外**の時なので、
Mouseでクリックされた時の挙動を記述します。

Mouseでクリックされた時は`event.currentTarget.style.outline = 'none';`でfocus時のスタイルを消します。もっと詳細にスタイルを指定したい場合は、`classList.add('className')`でクラス制御でスタイルを変更しても良いかもしれません。

### `onFocusButton`の箇所

`onFocusButton`では、focusが当たった時に、`onClickButton`で消したスタイルを元に戻す記述をしています。

`event.currentTarget.style.outline = '';`で空文字を代入しているのは、既存のスタイル（ブラウザのデフォルトスタイルや、CSSで指定したスタイル）が再度適用できるようにです。

## まとめ

以上、clickイベント時にMouseかEnterキーかを判定して、
focus時のスタイルをコントロールする方法を紹介しました。
より良い方法がありましたら、是非コメントを頂けたら幸いです。
Pythonでcsvに書き込みを行う


##目的：テキストファイル等に、何かを書き込みたい場合に使用する

```
# 'w'について
('test.csv', 'w', encoding='utf-8')
```
|表記|概要|
:---|:---|:---|
|r|読み込み|
|w|新規で書き込み|
|a|追記で書き込み|
|r+|追記の書き込み読み込みファイルが存在しない場合はエラーになる|
|w+|新規の書き込みと読み込みファイルがない場合作成|
|a+|追記の書き込みと読み込み、ファイルがない場合作成|


###Hello Worldと書き込みを行う

```hello.py

#
with open('test.csv', 'w', encoding='utf-8') as f:
    f.write('Hello World\n')

print('書き込みました。')



-----result------
書き込みました。

```
```test.csv
Hellor World
```

##複数の行を出力するときの処理
```lang.py

lang = ['SQL',
        'Java',
        'Ruby',
        'PHP',
        'Python']

with open('lang.csv', 'w', encoding = 'utf-8') as f:
    for item in lang:
        f.write(item + '\n')
print('書き込みしました。')

```

##実行結果
```lang.csv
SQL
Java
Ruby
PHP
Python
```

##応用 日付の操作

```time.py

from datetime import datetime

now = datetime.now()
#print(now) 2020-10-27 19:56:15.019242

str_now = f'{now:%Y/%m/%d %H:%M}'
#print(str_now) 2020/10/27 19:56

with open('time.csv', 'w', encoding='utf-8') as f:
    f.write(str_now + ' - 休日\n')

print('書き込みました。')


```
##実行結果

```time.csv

2020/10/27 20:00 - 休日
```
Vueのvalueプロパティ。親で定義してないのに子のpropsにvalueがある理由。

#Vueのvalueプロパティ。親で定義してないのに子のpropsにvalueがある理由。

子のpropsにvalueがあるのに、親のどこを探してもvalueがなくデータ元が不明すぎて散々悩んだので、その解決法について。

>＞propsの役割
親から子へのデータ受け渡しで、子のpropsプロパティに受け取る変数を定義する。


##結論

v-modelで渡すデータの初期設定がvalueだった。。(text要素の場合)

```vue:親
<TextFiled
   v-model="rows"
/>
```

```js:子(TextField)
export default {
  props:{
    value={},
  }
```

親の`v-model="rows"`でrowsという変数をTextFieldに渡している。

このとき、データはvalueに格納されている。

つまり、親から子へのデータ受け渡しだけに着目すると、以下２つは同じになる。

`v-model="rows"`
  　　⇅
`:value="rows"`




##v-modelのデフォルトの変数

| 要素 | 初期プロパティ名 | 初期イベント名 |
|:-:|:-:|:-:|
| text要素/textarea要素  | value  | input  |
| チェックボックス/ラジオボタン | checked  | change  |
| セレクトボックス  | value | change  |


[(公式) v-modelの基本的な使用方法](https://vuejs.org/v2/guide/forms.html#Basic-Usage)
Google Play Androidアプリの64bit対応

#Google Play のアプリ 64bit対応

設定は簡単ですが、メモ代わりに載せておきます

##ビルドで必要なのでNDKを入れる

・Unityで、Edit > Preferences > External Tools > NDK

downloadボタンから入手(互換性がないとビルドできない場合があるので、Unity上からダウンロートしてください) 

##ダウンロードして回答したpathに変更
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/2f2c432c-4ded-29a8-36bc-62d7a85a535c.png) 
##64bitの設定を行う
下記の設定を行い再度apkを作成しgoogle playにアップしてください

File > Build Setting > Player Settings > Other Setting 

・Scripting Backend 「IL2CPP」に変更

・Target Architectures 「ARM64」に変更

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771936/2f0f0e23-304a-0e32-219b-4f20d4e29457.png)
エンコードと文字コードはちがうの？

#文字コードについて
復習用　エンコード/文字コード/マルチバイト文字　についてのノート

* **UTF-8はエンコード形式**
* **Unicode(UCS2/4)は文字コード**
    * UCS2/4をエンコードする方式のこと

## エンコードと文字コードはちがうの？
* 文字コードは**サイズ固定**
    * UCS2：16bit 
    * UCS4：32bit
* **エンコード方式**がUTF-8 
    * **1~6byte可変長**
    * たとえば日本語ではE3で始まることが多いので3byte (E3 xx xxで日本語1文字)
    * UTF16/32もあるがあまり使われてない
    * UTF8が可変長で1~6byteなのがポイント

* **US-ASCII**：英数字などの**7bit文字**
    * **1byteではない**ことがポイント
    * 0000 0000 
    * 0111 1111
    * 最上位ビットが1ならダブルバイト/マルチバイト文字(=US-ASCII(Alpha numeric)文字ではない)
        * 2バイト文字とは、文字コードのうち、1文字を2バイトで表現する文字の総称
        * **上位ビットが1ならダブルバイト文字/マルチバイト文字で2~6バイトの可変長で表現される**
    * US-ASCIIであろうが日本語だろうが全部の文字がUTF8でかける
    * しかも変更することなくUS-ASCIIも書ける
    * **UTF8はUS-ASCIIと完全な互換性がありかつ全部の文字をかける**
    * →**とりあえずUTF8とかいとけばいい！🙆‍♀️**

##ダブルバイト文字とマルチバイト文字は？
* ダブルバイト文字(DBCS)：Unicodeという文字キャラクターコードが主流になる前に存在
    * Windows/AIX,Shift_JIS
    * HP-UX(Linux系)/EUC
    * IBMメインフレーム/EBCIDIC
    * これらOSに紐づく文字コードは大体**2バイト文字**という
* Unicodeできた当初は世界中の文字位は16biitで書けると思われていて、Unicode=16bitであった
    * 中国、日本語などJIS規格で文字が増えて16bitではかけない！
    * →UCS4誕生
* 文字コードに割り当てるキャラクターコードは32bitまで拡張し、そもそも2バイト文字は無くなった
    * UTF8:1~6バイト
    * UTF16:2バイト
    * UTF32:4バイト
    * →複数バイトとして現在は**マルチバイト**というのが適切！
Spree::Taxonomyのカラムを解説

solidus使おうとすると、初心者はイメージ掴みにくいですよね。
この記事を読まれていると言うことは少し全体像が掴めて、「Spree::Taxon」にはどう言ったカラムが存在するんだ？」と言うところなのかなと思います。:point_up:
そこで今回は「Spree::Taxon」内のカラムについて簡潔に紹介と説明をしていきます。

##Solidusのバージョン
solidus 2.0.9

##カラムの紹介と説明

Spree::Taxonomyのid=1をのぞいてみましょう。
![スクリーンショット 2020-10-27 7.07.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696807/900bed31-f4dc-7fb4-3da7-d515eb77a5c8.png)
それではここにあるカラムについて説明します。

###id
id。

###name
分類（taxonomy）名。

###create_at
分類（taxonomy）が作られた時間。

###update_at
分類（taxonomy）が更新された時間。

###position
Taxonomyリスト中におけるPositionが設定される。
例えば、2つのTaxonomyがある場合、１または２となる。


<関連情報>
Spree::Productのカラムを解説
https://qiita.com/roooll12/items/92b370741a53c8dd268c

Spree::Taxonのカラムを解説
https://qiita.com/roooll12/items/6f1dda6c5f4ea16e0c4c


駆け出しsolidus開発者にとってSpree::Taxonモデルを理解する糧になれば幸いです！
ServiceNow - テーブル列のラベル一覧又は名前一覧を表示するスクリプト

#概要
仕様書を作成する場合にテーブル列一覧をExcelに記述する場合がある。アプリケーションナビゲータの「Tables」から列一覧を表示することはできるが、仕様書にコピーペするのが面倒。
その場合のために作成したスクリプトです。

#実装
バックグラウンドスクリプトから次を実行する。

```
var tableName = 'cmdb_ci_ip_switch';

//var col = 'label';  // 'label', 'name', 'type'
var col = 'name';
//var col = 'type';

var values = [];


var fields = new GlideRecord('sys_dictionary');
fields.addQuery('name', tableName);
fields.addEncodedQuery('internal_type!=collection^ORinternal_type=NULL');
fields.query();
while(fields.next()) {
  //gs.info(fields.column_label.toString()+ ',' + fields.element.toString());
  switch(col) {
    case 'name':
      values.push(fields.element.toString());
      break;
    case 'type':
      values.push(fields.internal_type.toString());
      break;
    default:
      values.push(fields.column_label.toString());
  }
}
var valueString = values.toString();
valueString = valueString.replace(/,/g, '\n');
gs.print(valueString);
```
ツイートを感情分析したデータをDBに格納し、PowerBIで分析してみた

自分用の備忘録として書きます

#はじめに
今回やったことは以下Microsoft Learnを見ながらやりました。
LogicAppsでツイートの取得からDBの格納まで一通り学べます。

Logic Apps を使用して自動的にデータをルートし、処理する - Learn 
https://docs.microsoft.com/ja-jp/learn/modules/route-and-process-data-logic-apps/

せっかくなのでやったことを忘れないように記事に残します。

#本記事の内容
・ロジックアプリの作成
・DBのデータをPowerBIで読み込み

#今回の構成
以下の構成で分析していく
![zu1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/301050/8dcac19c-af2e-4a73-3086-f983211ff06a.png)


#事前準備
１）Azure上でDBを構築（構築手順は割愛）
コストを抑えるためにサーバレスタイプのDBを作成

![db1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/301050/cdb2d96d-2ed3-1813-d10b-d0dab4e0cfa8.png)

２）DBに接続し、データを格納するテーブルを作成

#ロジックアプリの作成
１）Azureにログインし、LogicAppを新規作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/301050/2c0f1d57-4ca9-ddb7-ca57-a08a9c53594c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/301050/1089fc6e-55b0-cedc-e207-ec7076a3a31a.png)

２）トリガーとして「新しいツイートが投稿されたら」を選ぶ
![logicApps_tw.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/301050/f6d4da85-8a31-06fe-62ce-460cdb2ea5d9.png)

３）一通り作ったものが以下
※最近FF14のパッチで「南方ボズヤ戦線（通称：ボズヤ）」というコンテンツが追加されたので、その件に関するツイートを10分毎に取り込み、感情を分析
※また、条件でスコアが0以上のものにしているのは、感情スコアがNullになることがあったので、Nullの場合はDBにデータを入れずに終了。感情スコアが出たものだけDBにデータを入れるように作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/301050/25381582-b8ec-3c01-6fea-b532284a839f.png)

４）実行結果（いいねの数がカウントされない・・別途調べます）
感情スコアが0.99以上なのでとてもポジティブ感情ということがわかる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/301050/2d3a3174-a8fa-9634-d684-9330155828c3.png)

５）DBにもちゃんとデータが格納されていることを確認！
![22222.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/301050/588d3a95-8dfc-77c2-fb18-ce5ecdc71359.png)

#DBのデータをPowerBIで読み込む
１）AzureポータルのSQLServer画面左側の「Power BI(プレビュー)」をクリック
![azure-sql.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/301050/2a6fd266-c909-58b4-3424-69e43af48273.png)

２）「はじめに」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/301050/f333cd0f-2a81-1cbc-39e7-140eb88b3bad.png)

３）ダウンロードしたファイルを開くとPowerBIが起動する
読み込みたいテーブルを選択し、読み込みをクリック
![BI_tw_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/301050/6611cc8c-4fad-0bf3-e0f4-de97aacb761f.png)

４）あとは好きなように分析！
（感情分析のスコアがどういった基準でつけてるのか・・・特定のキーワードを見てポジティブかネガティブか判断してるのかしら・・）
![11111.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/301050/c83163a5-4aba-5bb9-aa24-b64191f920f5.png)


#おわりに
次回はLogicAppsを使ってMicrosoft Formsで得た回答データをExcelに格納する方法について書いていこうと思います。

#参考
・Text Analytics サービスを使用してテキストを分析する
https://docs.microsoft.com/ja-jp/learn/modules/analyze-text-with-text-analytics-service/

・Azure Logic Apps を使用して SQL データベースのワークフローを自動化する
https://docs.microsoft.com/ja-jp/azure/connectors/connectors-create-api-sqlazure
【GCP】ローカルのDockerイメージをContainer RegistryにPushするまで

# 概要
ローカル環境で開発してビルドしたコンテナイメージを、ローカルから「Container Registry」のリポジトリにプッシュするための作業

# 参考
https://cloud.google.com/container-registry/docs/pushing-and-pulling#push_the_tagged_image_to

# 手順
## 1. gcloudの設定

1. gcloudコマンドをローカル環境にインストール
    - https://cloud.google.com/sdk/docs/quickstart-macos?hl=ja 
2. 初期設定
    - `gcloud init`

## 2. イメージのPush/Pull用サービスアカウント作成
自分のユーザーアカウントを使う場合、プロジェクトがいろいろと紐づいているとプロジェクトIDの選択ミスが怖いので、専用のサービスアカウントを作る。

1. サービスアカウント作成
    - コンソールで作業
2. 権限設定
    - 「Container Registry」のコンテナイメージはCloud Storageで管理され、権限も、Cloud Storageの「ストレージ管理者」権限を付与するだけ。
    - https://cloud.google.com/container-registry/docs/access-control#grant
https://cloud.google.com/sdk/docs/authorizing?hl=ja#authorizing_with_a_service_account
3. サービスアカウントのキーを作成し、ローカルで認証設定
    - `gcloud auth activate-service-account`
    - https://cloud.google.com/sdk/docs/authorizing?hl=ja#authorizing_with_a_service_account

## 3. Docker 認証設定
gcloud をDockerの認証ヘルパーとして使用するための設定

1. ローカルで `gcloud auth configure-docker` を実行

## 4. Dockerイメージのプッシュ

※ もし複数アカウントがある場合は以下でアカウントを切り替える
`gcloud config set account [ACCOUNT]`

1. ローカル イメージにレジストリ名でタグ付けする
    - 命名規則 : [HOSTNAME]/[PROJECT-ID]/[IMAGE]
        - [HOSTNAME] : 以下から選ぶ。これでイメージを保存する場所が決まる。
            - gcr.io は米国内のデータセンターでイメージをホストしていますが、今後は場所が変更される可能性があります。
            - us.gcr.io は米国内のデータセンターでイメージをホストしていますが、gcr.io によってホストされるイメージからは独立したストレージ バケットです。
            - eu.gcr.io は、欧州連合でイメージをホストします。
            - asia.gcr.io は、アジアのデータセンターでイメージをホストします。
        - [PROJECT-ID] : 対象のGoogle CloudプロジェクトのプロジェクトID
        - [IMAGE] : コンテナイメージの名前
    - タグ付けコマンド :  `docker tag [ローカル イメージ名またはイメージ ID] [レジストリ名]:[タグ(未指定はlatest)]` 
2. プッシュ
    - `docker push [レジストリ名]:[タグ(未指定はlatest)]`

新規でプッシュすると、Container Registry上にリポジトリができる。
Rails モデルとテーブルの命名規則

##データベースのクラス名
データベースのテーブル名はモデル名のクラス名を複数系にしたものでありスネークケースで命名する
**スネークケースとは** ：すべてを小文字にし、単語の区切りを_で繋ぐ書き方
##モデルのクラス名	
モデルのクラス名は単数系でキャメルケースで命名する						
**キャメルケースとは**：各単語の頭文字を大文字にする、_は使用しない書き方					モデルのクラスはキャメルケースで単数系
Rythm.js を利用したかったけど出来なかったメモ

#Rythm.js利用失敗メモ
　音楽を再生し、そのリズムに合わせて指定したHTML要素がアニメーションしてダンスするライブラリを使いたかったが、動かなかった。
　いつか使おうと思ったときにどこまでやったか振り返れるようにしておこうと思う。

<B>使おうとおもったライブラリ</B>
http://okazari.github.io/Rythm.js/

#ダメだったソース
参考サイトを参考に、下記埋め込みをしたが、
対象の画像が動くこともなく、音も出なかった。

```html:index.html
    <!-- 標準スタイルの「rythm-bass」を設定 -->
    <div class="rythm-bass">
        <!-- スピーカーの画像を設置 -->
        <img src="speaker.png" />
    </div>
```

```js:script.js
var rythm = new Rythm();
// 再生したい音楽ファイルを選択
rythm.setMusic( 'ここに再生したいmp3のurlを記載した' );
// rythm.jsを起動して音楽再生
rythm.start();
```

#実施した切り分け→結果は全てダメ
１．bassの設定が入れたい音楽との相性が悪い？（低音が響かないと動かないとか、高音がでないと動かないなど）
→利用クラスを"rythm-bass"以外に設定してみた。
rythm-medium
rythm-high

２．CDNの記載ミスがないか
↓サイト情報
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737339/2573b4ea-959d-71b7-0b92-20792c42bef2.png)
↓Codepen設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737339/7ab322c0-1798-b856-acea-21c17dfbd8e9.png)

３．音楽ファイルの記載方法
３－１．最初、対象mp3ファイルを「ファイルなう」でurl化して
rythm.setMusic( 'ここに再生したいmp3のurlを記載した' );
に埋め込んだ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737339/0a72f47e-f773-00d2-ef54-443101dc072b.png)

３－２．サンプルコードでは/test.mpsというurlだったので、
ファイルアップローダで、/XXXX.mp3というurlを作り、
rythm.setMusic( 'ここに再生したいmp3のurlを記載した' );
に埋め込んだ。

#参考URL
メインサイト
http://okazari.github.io/Rythm.js/
https://github.com/Okazari/Rythm.js

サンプルコードあり。
https://paiza.hatenablog.com/entry/2017/03/31/%E5%88%9D%E5%BF%83%E8%80%85%E3%81%A7%E3%82%82%E7%B0%A1%E5%8D%98%E3%81%ABWeb%E3%82%B5%E3%82%A4%E3%83%88%E3%82%92%E9%9D%A2%E7%99%BD%E3%81%8F%E3%81%A7%E3%81%8D%E3%82%8BJavaScript%E3%83%A9%E3%82%A4%E3%83%96#-Rythmjs-
Uncaught ReferenceError: Vue is not definedが起こった話

## はじめに
Vue.jsをCDN読み込みで簡単なミニアプリを使う際に起こったエラーです。
備忘録のため残しておきます。初学者のため間違えがあればご指摘下さい！


## Uncaught ReferenceError: Vue is not defined
vue.jsの動作確認をするため以下のコードを記述したところvue.jsが読み込まれませんでした。


```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
  <link rel="stylesheet" href="vue.css">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <p>現在{{ number }}回クリックされています</p>
    <button>カウントアップ</button>
  </div>
  <script src="vue.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</body>
</html>

```

```javascript
//vue.js

new Vue({
  el: '#app',
  data: {
    number: 0
  }
})
```

<!--解決策-->
解決策は簡単。
下から3行目のVueを使うためのCDNをjsが読み込まれるより上に記述するだけです。
headタグの中に入れるかbodyタグの一番上に記述しましょう。

```html
<!--　修正後 -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <link rel="stylesheet" href="vue.css">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <p>現在{{ number }}回クリックされています</p>
    <button>カウントアップ</button>
  </div>
  <script src="vue.js"></script>
</body>
</html>

```
## 最後に
Vue.jsの超初心者の方の助けになれば幸いです。
PyTorchでRTX 3090を使う

~~※2020/10/24日時点の情報です。~~
**10/28日にPyTorch 1.7が公開され，それに伴いCUDA11に対応・RTX3090でも利用可能となっています。**

そのため，単にPyTorch 1.7に上げればRTX3080/3090でも使えます。

apexのインストールは，以下で出来ました。
https://github.com/NVIDIA/apex/issues/988#issuecomment-726343453

---

以下は古い情報です。

## 課題
PyTorch 1.6では，現状RTX 3080/3090に対応しておらず，以下のようなエラーを吐きます。

```
GeForce RTX 3090 with CUDA capability sm_86 is not compatible with the current PyTorch installation.
```

## 解決方法

対処方法は，開発版のPyTorch 1.8を入れることです。

```bash
pip install --pre torch torchvision -f https://download.pytorch.org/whl/nightly/cu110/torch_nightly.html
```

cu110となっていますが，cuda11.1を使っていても動くので問題ありません。


### バージョン情報
NVIDIA-SMI 455.23.05    Driver Version: 455.23.05    CUDA Version: 11.1/Ubuntu 20.04

## 結果
以前は2070 SUPERを使っていたのですが，学習速度が3倍程度早くなりました。あと，jaxは普通に動きました。


## Ref.
- https://discuss.pytorch.org/t/rtx-3000-support/98158
[UE4] OculusQuestでつかんだ物がめり込まないようにする

# はじめに
UE4でVRのアプリを作成するときにVRテンプレートを使っているのですが、つかんだ物が他の物にめり込んでしまうため、テーブルの上にコップを置くときに吹き飛んでしまうような症状が発生します(これはテーブル側も動かせる物だった場合)。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">テーブルの上にコップを置いただけなのに吹き飛んでしまう <a href="https://t.co/IZIcyQ6Ukh">pic.twitter.com/IZIcyQ6Ukh</a></p>&mdash; 高浜 (@SatoshiTakahama) <a href="https://twitter.com/SatoshiTakahama/status/1320216799309221888?ref_src=twsrc%5Etfw">October 25, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

これは、手を放したときに、つかんでいた物のコライダーとめり込んだ物のコライダーが反応するために発生していますが、VRテンプレートではつかんだ物はコントローラにアタッチされる(子になる)ことと、VRではコントローラは実際の手の動きに追従させるため(そうしないと違和感が発生する)手が他の物にめり込むことが許容されることから、このような状況になります。
つかんだ物をコントローラにアタッチするかわりに、つかんだ物をPhysicsHandleでコントローラに追従する方法に変更することで、めり込まないようにすることができました。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">PhysicsHandleを使うことで、期待したような動作になった <a href="https://t.co/Kxpv8PpWWs">pic.twitter.com/Kxpv8PpWWs</a></p>&mdash; 高浜 (@SatoshiTakahama) <a href="https://twitter.com/SatoshiTakahama/status/1320659111667625984?ref_src=twsrc%5Etfw">October 26, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 環境
Windows10
UnrealEngine 4.25.4

# 作り方
・プロジェクトはVRテンプレートを使用します。
・VirtualRealityBPフォルダ=>BlueprintsフォルダにあるBP_PickupCubeの編集画面を起動します。
・PhysicsHandle型のPhysicsHandleと、SceneComponent型のAttatch、Boolean型のGrabの3個の変数を追加します。
・Pickupイベントの処理を以下のように差し替えます。PhysicsHandleを生成して、コントローラとつかんだ物をくっつけています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/4d3cf336-9a9e-513b-b3f8-8ecff4918f2f.png)
・Dropイベントの処理を以下のように差し替えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/6961b781-6636-12b2-0336-fa433abe2cba.png)
・Tickイベントの処理を以下のように作成します。コントローラの位置をPhysicsHandleに設定して、つかんだ物が追従できるようにしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/190751cf-fa1c-ad9c-fadf-bc4edcab25da.png)
・次に、VirtualRealityBPフォルダ=>BlueprintsフォルダにあるBP_MotionControllerの編集画面を起動します。
・ReleaseActorの処理を以下のように、?IsValidノードとDropノードを直接つなぐように修正します。これは、コントローラの左右を判定するために入っていたと思われる処理ですが、今回Attatchしないので正しく機能しません。左右の判定自体は、AttatchActorが有効かどうかの判定だけでできているため、この処理をとばしても問題なく動作しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/d75f0649-bbf7-25be-746e-0492f3f770ef.png)
・Tickイベントの上から３番目の処理を以下のように、SetCollisionEnabledノードの手前に?IsValidノードを追加します。ここは手を握ったときにコライダーを有効にしている処理ですが、物をつかんでいるときはコライダーではじかれないように修正します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215278/f66b2d31-cb50-5652-5671-a7100daf6678.png)

# 参考資料
・[ue4-masterのブログ](https://ameblo.jp/ue4-master/entry-12539390523.html)
PhysicsHandleを使って物をつかむ方法を参考(というかほぼそのままですが)にさせていただきました。

・[[UE4] Physics系コンポーネントのパラメータ調整リファレンス](https://historia.co.jp/archives/7512/)
PhysicsHandleのパラメータ調整するときに参考になります。
MongoDBのログローテート設定

MongoDBのログローテーションをしたくて調べて設定してみました。（バージョンは3.4）

## やりたいこと
ログは1日1回ローテーションしたい。
ローテーション後のログファイルは mongod.log_yyyymmdd という名前をつけたい。
自動圧縮したい。
溜め続けるのではなく一定期間が経過したら自動削除したい。

## やったこと
logrotateで以下のように設定

```
# vi /etc/logrotate.d/mongod

/usr/local/var/log/mongodb/mongod.log
{
    missingok
    daily
    dateext
    rotate 30
    create
    compress
    delaycompress
    postrotate
      /bin/kill -SIGUSR1 `cat /var/run/mongodb/mongod.pid 2> /dev/null` 2> /dev/null || true
      find /data/mongodb/logs -type f -size 0 -regextype posix-awk -regex "^\/usr\/local\/var\/log\/mongodb\/mongod\.log\.[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}-[0-9]{2}-[0-9]{2}$" -execdir rm {} \; >/dev/null 2>&1
    endscript
}
```

## メモ
kill -SIGUSR1 でMongoDBのログローテートを行うと、MongoDBが mongod.log.yyyy-mm-ddTxx-xx-xx という名前の空ログファイルを作ってしまうので find を使用して消している。

create ではなくnocreate にすると、MongoDBがログファイルを見失って
ローテーションのタイミングでMongoDBが異常終了する。

## 参考先
[Automating MongoDB Log Rotation](https://www.percona.com/blog/2018/09/27/automating-mongodb-log-rotation/)
ServiceNow - 階層選択フィールの作成

#概要
参照フィールドの選択に基づいて他選択フィールドの内容を変える

今回の例では「会社」参照フィールドで選択された子会社をリストコレクタかから選択可能にする

#実装
次のように参照型とリストコレクタの変数を定義する。
![subsidiary_1_20201022.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/f783da24-400b-78af-89b0-cbcab831246a.png)

![subsidiary_2_20201022.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/9e82b8a0-92e7-dba0-9180-00bfd2ea2263.png)

変数vrm_vendor_lookupのonChangeスクリプト

```
function onChange(control, oldValue, newValue, isLoading) {
    if (isLoading || newValue == '') {
        return;
    }

    var vendorGA = new GlideAjax('GetVendorLocations');
    vendorGA.addParam('sysparm_name', 'get_locations');
    vendorGA.addParam('sysparm_vendor_id', newValue);
    vendorGA.getXMLAnswer(function(answer) {
        var subsidiary  = JSON.parse(answer);
		g_form.setValue('vrm_new_satellite_existing_location', subsidiary);
    });
}
```

スクリプトインクルード

```
var GetVendorLocations = Class.create();
GetVendorLocations.prototype = Object.extendsObject(AbstractAjaxProcessor, {

    get_locations: function() {

        var locations = [];
        var vendorID = this.getParameter('sysparm_vendor_id');

        var satelliteOffice = new GlideRecord('core_company');
        satelliteOffice.addQuery('parent.sys_id', vendorID);
        //satelliteOffice.addQuery('vendor', true);
        satelliteOffice.query();
        gs.log('Denis has this ID ' + vendorID);
        while (satelliteOffice.next()) {

            locations.push(satelliteOffice.sys_id.toString());
        }
        return JSON.stringify(locations);
    },

    type: 'GetVendorLocations '
});
```

上のコードを実装すると次のように子会社がリストコレクタに選択される。
![subsidiary_3_20201022.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/a582b8ed-9762-4a62-04f0-4cafbaf20c76.png)
しかし、ユーザはまだ登録されている会社すべてを選択することが可能。
![subsidiary_4_20201022.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/a898ea29-1f0a-a35d-f7ca-71c846001252.png)

子会社のみ選択可能にするにはReference qualifierを指定する。
![subsidiary_5_20201022.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/3083216c-abe8-b2ad-3f3a-ad37a783792c.png)

指定すると子会社のみ選択可能になる。
![subsidiary_6_20201022.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698027/276da993-4d1d-d010-e875-818660cb8e09.png)
DNSとは？


参考資料にあるサイトは分かりやすいので、参考サイトを読めば理解できるが頭を整理するために書いてみる。

#ドメインとIPアドレス
ドメインとIPアドレスはインターネット上の住所である。２つの違いは、誰のための住所であるかだ。IPアドレスがコンピュータのための住所で数字の羅列で表現される。数字の羅列では、人からは判断することが出来ない。そこで、人でもわかる様に出来たのがドメインだ。

#DNS
人がドメインという住所で検索した時に、ドメイン のままだとコンピュータは判断できない。コンピュータが判断できるようにするためにドメインを対応するipアドレスに翻訳（変換）する必要がある。その役目を担っているのがDNSである。

###権威DNSサーバとキャッシュDNSサーバ
DNSには権威DNSサーバとキャッシュDNSサーバの２つのサーバがある。権威DNSはドメインとipアドレスの対応表を持っており、ドメイン名に対応したipアドレスを返す。キャッシュDNSサーバーは、一度リクエストがあったドメインに関しての対応表を一定期間保持しレスポンスを速くする。

#DNSレコード
ドメイン名とIPアドレスの対応表をゾーンファイルといい。その１行１行を*DNSレコード*という。

**Aレコード（Adressレコード）**
`remacre.jp. IN A 59.106.27.217`

**MXレコード（Mail Exchange）**
「MXレコード」は対象ドメイン宛のメールの配送先（メールサーバ）のホスト名を定義するレコードです。

**NSレコード**

ネームサーバー（Name Server）の略でNSレコードだそうです。

（例）
remacre.jp. IN NS 01.dnsv.jp.

意味：ドメインremacre.jpはネームサーバー01.dnsv.jpに問い合わせてね


**CNAMEレコード**
エイリアス的な感じ。

remacre.jp. IN A 59.106.27.217
www.remacre.jp. IN CNAME remacre.jp.

意味：ドメインwww.remacre.jpはドメインremacre.jpと同じですよ。



#参考資料

これを見れば理解できる
https://remacre.jp/homepage/7478
[GraphQL] queryのwhere(条件)を動的に変更するよ

インターンでqueryを動的に変更する場面があって少し悩んだのでメモとして置いておきます。
やりたかったことは、選択されたボタンによって条件を付け加えたり削除したりして動的にクエリを変えて表示されるものを変えたいって感じです。

```
query getProfile{
  profile( //ここ！！！ ) {
   name,
   ...
  }
}
```


#結論
とりあえず結果だけ先に示します。

```
const GET_MEMBERS = gql`
    query getProfile($title: [String!], $name: [String!]) {
      profile(where: {title: {_in: $title}, name: {_in: $name}}, order_by: {name: desc}){
        name
        ...
      }
    }
  `;

  const { data, loading, error } = useQuery(GET_MEMBERS,
    { variables: {
      name: name_selected.length === 0 ? name_all : name_selected,
      title: title_selected.length === 0 ? title_all : title_selected,
    } }
  );
```

##注意するポイント

###クエリの構造自体は静的な状態にしておく
初めはname:やら他のkeyやらを付けたり外したりしようかと考えたのですが、いろいろ調べてみるとクエリの構造を変数として持っちゃうといろいろ不都合があるみたいです。詳しくは以下のURLを参考に。なので、変数になるのはそれぞれのvalueになる部分のみです。
https://qiita.com/Quramy/items/fb579f60e29ccbda3c86

となると、選択されていない時は全て表示されて欲しいので、whereを使いながらも全てに当てはまるようにしなければいけないところが辛い。今回は

```
_in: {[]}
```
こういうことができない(当てはまるものがないとされる)から、予め検索条件が全て入った配列を用意することで対応させました。

###型指定は必須
最初は静的なqueryだったので型指定をしていませんでしたが、variabelsを使う場合には型指定が必須になります。

```
($name: [String!])
```
sqlacodegenを使って既存のMySQLサーバからSQLAlchemyのテーブル定義を生成する

まっさらなAmazonLinux2でやるときの手順です

# 実行環境
OS: AmazonLinux2 (Linux version 4.14.193-149.317.amzn2.x86_64)
python: Python 2.7.18

# やること
```
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python get-pip.py
pip install sqlacodegen pymysql
sqlacodegen mysql+pymysql://user:password@sqlhost/dbname
```

オプション：
--outfile: 標準出力ではなく、ファイルに書き出す
--tables: テーブルを指定
これで標準出力に全テーブルのSQLAlchemy定義が出力されます

公式サイトには`oursql`というのを使うと書いてありますが、この環境では下記エラーが出るため`pymysql`を使います
https://pypi.org/project/sqlacodegen/

```
Traceback (most recent call last):
  File "/home/ec2-user/.local/bin/sqlacodegen", line 8, in <module>
    sys.exit(main())
  File "/home/ec2-user/.local/lib/python2.7/site-packages/sqlacodegen/main.py", line 44, in main
    engine = create_engine(args.url)
  File "/home/ec2-user/.local/lib/python2.7/site-packages/sqlalchemy/engine/__init__.py", line 500, in create_engine
    return strategy.create(*args, **kwargs)
  File "/home/ec2-user/.local/lib/python2.7/site-packages/sqlalchemy/engine/strategies.py", line 61, in create
    entrypoint = u._get_entrypoint()
  File "/home/ec2-user/.local/lib/python2.7/site-packages/sqlalchemy/engine/url.py", line 172, in _get_entrypoint
    cls = registry.load(name)
  File "/home/ec2-user/.local/lib/python2.7/site-packages/sqlalchemy/util/langhelpers.py", line 254, in load
    loader = self.auto_fn(name)
  File "/home/ec2-user/.local/lib/python2.7/site-packages/sqlalchemy/dialects/__init__.py", line 32, in _auto_fn
    dialect, driver = name.split(".")
ValueError: too many values to unpack
```
プロキシ環境下の Docker

Docker おじさんです。

今回は
**「顧客の本番環境がプロキシを通さないとインターネットに出れないことが判明した!!!」**
という状況で焦らないためのメモ。

## Docker のインストール
Debian / Ubuntu 前提で。

プロキシ環境下なので以下は普通に通らないと思うが、`~/.bashrc` とかで環境変数 `http_proxy` などを設定しても `sudo` すると環境変数は引き継がれないのでそのままでは通らない。

``` console
$ sudo apt-get install docker.io
```

`sudo` に `-E` オプションを付ければ環境変数を引き継げば通るが毎回 `-E` をつけるのが面倒なので、別の方法として apt の設定ファイルを書いてしまったほうが楽。

``` :/etc/apt/apt.conf.d/00-proxy
Acquire::http::Proxy "http://{HOST}:{port}";
Acquire::https::Proxy "http://{HOST}:{port}";
```

RHEL / CentOS の人は yum 用の設定方法があると思うので適当にググってやっていって欲しい。

## Docker Engine
`docker pull` などでイメージを落としてくる場合は Docker Engine にプロキシ設定をする必要がある。

単純に環境変数 `HTTP_PROXY` `HTTPS_PROXY` を設定すればいいのだが、最近は Systemd で動いていることがほとんどだと思うので Systemd の設定ファイルで環境変数を指定するのが手っ取り早い。

``` systemd:/lib/systemd/system/docker.service
[Service]
Environment=HTTP_PROXY=http://{HOST}:{port}
Environment=HTTPS_PROXY=http://{HOST}:{port}
```

## Docker イメージのビルド時
Docker イメージのビルド時に限らないが、 `apt-get install` などでインターネットに出たい場合は、そのツールひとつひとつにプロキシ設定をする必要がある。

apt-get や pip などは環境変数を設定するだけでプロキシを通ってくれるので、とりあえず環境変数を設定しておき、個別に対応が必要なツールについては個別に対応していく、となる。ビルド時に環境変数を設定するには Dockerfile に環境変数を指定してもいいが、ARG を使うのがよさそう。

例えば Docker Compose の設定ファイルで args を指定する場合は、サービスの build オプションを以下のように指定する。

``` yml:docker-compose.yml
  build:
    context: .
    args:
      - http_proxy=http://{HOST}:{port}
      - https_proxy=http://{HOST}:{port}
      - HTTP_PROXY=http://{HOST}:{port}
      - HTTPS_PROXY=http://{HOST}:{port}
```

ツールによって対応している環境変数名が大文字だったり小文字だったりするので、両方指定しておいたほうが良い。
(例えば apt-get は大文字の `HTTP_PROXY` を指定しても認識してくれない)

## Docker コンテナ起動時
コンテナ起動時はビルド時と同様にツールひとつひとつにプロキシ設定をする必要があるため、個別対応以外で出来ることといえば環境変数を設定するだけとなる。

コンテナ起動時に毎回環境変数を指定するのは手間なので、 `~/.docker/config.json` を書いておくとコンテナ内に `HTTP_PROXY` などを自動で設定してくれる機能を使うと楽。

``` json:~/.docker/config.json
{
  "proxies": {
    "default": {
      "httpProxy": "http://{HOST}:{port}",
      "httpsProxy": "http://{HOST}:{port}"
    }
  }
}
```

[Configure Docker to use a proxy server | Docker Documentation](https://docs.docker.com/network/proxy/)

**[追記]** これ、どうやら Docker Compose のときには使えないっぽい・・・？

## その他
Docker 以外の設定で環境変数では対応できないやつ (git とか curl とか boto3 とか) そのへんはググって個別によしなに設定する。
Let's Encryptが自動更新されていなかった

3ヶ月前に導入したLet's Encryptだが、なぜか自動更新されていなかった。
一応解決したので備忘録として投稿しておく。
Qiitaに上げるつもりはなかったので、スクショなどを取っていなかったのは反省点。

#環境
ConoHa（CentOS8）

#Apacheがおかしいことに気づく

・Let's Encryptの自動更新の設定をしていたはずだが、なぜか更新されていない。[この記事](https://qiita.com/mkoku/items/3537d9cc7d4c029d886b)を参考にして設定した記憶がある。
・エラー文を読んでもよくわからなかったが、どうもApacheがおかしいらしい（勘）
・以下のコマンドで調べてみるとApacheの起動が失敗していた。「Active: failed (Result: exit-code)」と表示された。

```:ターミナル
$ systemctl status httpd
```

・ステータスをよく読むと「(98)Address already in use」エラーが2つある。443番ポートはNode.jsで既に使用していたため、Apacheが起動できなかったようだ。

→Let's Encryptの更新にはApacheが必要なことに気づく（←アホ）

#Apacheを立て直しLet's Encryptを更新

・Node.jsのプロセスを終了（今回は無理矢理killした）し、Apacheを再起動。今度は正常に動いた。その後Let's Encryptの手動更新を行ったら成功した。

▼Let's Encryptの手動更新

```:ターミナル
$ sudo certbot renew
```

プロセス削除の参考：[Address already in use の対処法](https://qiita.com/arashida/items/8b8d9d2f1f040b2aecf1)
※上記記事は古いhttpdプロセスが残っているのが原因だったが、私の場合はNode.jsのプロセスが443番ポートを使用していたことが原因だった。しかしプロセスの削除方法は同じ。

→Node.jsはApache上で動いているものだと思っていたが、独立して動くものだと理解した。

#一応更新できたが…

・しかしこれでは、Let's Encryptを更新する度にNode.jsを止めてApacheを起動しなければならない。
・Apacheの443番ポートを使用しない設定にすれば、Node.jsと同時に起動出来る。（80番ポートだけ開けておく）
・「/etc/httpd/conf.d/ssl.conf」を書き換えた。「Listen 443 https」をコメントアウトした。

```:/etc/httpd/conf.d/ssl.conf
#
# When we also provide SSL we have to listen to the 
# standard HTTPS port in addition.
#
#Listen 443 https                  //←この行をコメントアウトする

##
##  SSL Global Context
##
##  All SSL configuration in this context applies both to
##  the main server and all SSL-enabled virtual hosts.
##

以下略
```

参考
[Apacheの再起動時に(98)Address already in use が発生!2つの原因と対策](https://youyoukukan.com/archives/server/98-address-alreacy-in-use/)

・Apache再起動後、Let's Encryptの強制更新が成功したので今度は大丈夫そう。次の自動更新は成功してほしい。

▼SSL証明書の有効期限に関わらず、強制的に更新する

```:ターミナル
$ sudo certbot renew --force-renew
```

参考
[Let's EncryptのSSL証明書を手動で更新する方法](https://jsstudy.hatenablog.com/entry/How-to-manually-renew-the-SSL-certificate-of-Lets-Encrypt)


#失敗談
Apacheの443ポートを塞ぐために、firewalldを書き換えてしまった。443ポートの接続をはじく設定にしたらWebアプリに接続できなくなった。（当たり前だ）