OmniAICreator/Qiita-1.07M huggingface dataset:
GoogleTagManagerを使ってHTML要素の追加や削除を行う


## まえがき
webアプリケーションで特定条件時のみ画面のカスタマイズを行いたい場合に、あんまりソースコードにif文いっぱい書きたくないな……と思ったのでGoogleTagManager（以下GTM）を使用することにしました。
Analyticsと組み合わせて使われることが多い（と思われる）GTMですが、Javascriptを使用してソースコード本体に手を加えずにHTML要素のカスタマイズを行うこともできます。

## タグ作成
GTMから「新しいタグを作成」を押下し、「タグの設定」を選択します。
![スクリーンショット 2020-02-05 10.50.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496427/c81bd85c-8741-e298-72a2-b780be902982.png)

タグタイプで「カスタムHTML」を選択します。
![スクリーンショット 2020-02-05 11.16.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496427/95727aa9-1ae5-cf0e-ef65-bf905c6ee1bc.png)

タグの設定を行う
![スクリーンショット 2020-02-05 11.17.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496427/2b336c96-dc81-8927-7e8e-3be2d255843f.png)
「HTML」の箇所にJavascriptを記載します。
今回はシンプルにdiv要素の追加を行うことにします。要素の削除や、CSSスタイルの変更も可能です。
Javascriptは「[ライブラリを使わない素のJavaScriptでDOM操作](https://qiita.com/kouh/items/dfc14d25ccb4e50afe89)」を参考にさせていただきました。

```html
<script>
  var container = document.querySelector('.test-tag');
  container.innerHTML = '<div>グーグルタグマネージャテスト挿入</div>';
</script>
```

詳細設定から、タグ配信の優先度を100に設定しておきました。
タグを複数設定した場合、詳細設定でそれぞれのタグの優先順位や順序付けが可能なので色々調整が効きます。

## トリガー作成
タグの作成が完了したら「トリガーの選択」右上にある「＋」マークからトリガーを新規追加します。

今回トリガーは「ページビュー > ページビュー」にしました。
![スクリーンショット 2020-02-05 11.32.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496427/4bb7aeae-c876-5257-1224-78915f8007bd.png)

サンプルでは特定IDのページだけカスタム画面を見せたいという設定なので、「一部のページビュー」を選択して条件を記載します。
![スクリーンショット 2020-02-05 11.33.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496427/ff6b2505-dffc-e605-a9dc-34d315f12721.png)

## サイトに差し込み用の要素を仕込む
``` html
<div class="test-tag"></div>
```
メッセージを差し込みたい位置に、GTMで指定したクラスを入れておきます。
これだけ。

プレビューで確認し、問題なければ公開します。
[GTMのプレビューと公開を正しく行おう](https://ferret-plus.com/curriculums/10466)

## メリット

- if文でソースコードを汚さずに済む。
- デプロイ不要。画像やリンクの追加も楽。
- かなり柔軟に設定できるので、慣れるとソースがりがり書くよりスムーズ。
- GTMのバージョン管理も便利。
- 運用者と開発者が異なっており、細かい変更が定期的に入る箇所の修正を運用者が行える（ニュースとか？）。

## デメリット

- うっかり不具合があった場合に、原因がGTMに記述したscriptなのかソースコード本体側にあるのかの検証がややめんどうくさい。
- 使用しているクラスやIDの管理をきちんと行わないと、後日混乱しやすい。（「あれ、このクラス使ってない？いらないなら消していい？」「あーそれGTMで使ってます」）
- Git上でソースコードと合わせて一括でバージョン管理できない。

## まとめ
トリガーにCookieを使用することで、LPページ踏んだお客さんにはフォームにキャンペーンコード入力欄を表示するけど、LPページ見てないお客さんにはキャンペーンコード入力欄は非表示にするよ！
Javascriptにエラーがあったときにブラウザでアラート出すよ！
QAページのスクロール距離が長い場合に、ヘルプチャットへの誘導を行うよ！
などなど、いろんなことがGTMでできました。
便利ですが、チーム開発では管理がやや煩雑になるなあという印象はあるため、うまく使っていきたいと思います。
数万件以上のデータを移行するスクリプトを実行する前にやっておくと良いこと

## やっておくと良いこと

大体が失敗から学んだものです。

###  ログは出そう

以下のログは最低限出しておくと、なんやかんや役に立つ。

- 引数
- 開始時間
- 対象のid
- 対象のidの合計
- 実行時間
- 終了時間

どこまでスクリプトが実行されたか分からないと不安になるし、テストの段階から逐一実行時間を記録しておくと本番環境でどれくらい時間がかかるか予測できる。

### ログとイムスタンプはセットにしておく

全てのログにタイムスタンプ必須でつけた方が良い。問題が起きた時に調査しやすくなる。

### 本番のデータを事前に確認する

Redashとかで本番のデータを絶対に確認しておく。おそらく想定外のパターンが見つかる。。
綺麗なデータしかないというのは理想だが、スクリプトを実行する前に潰せる可能性があるものは、事前に潰しておきたい。

### ドライランモードをつくっておく

DBを書き換える前に気軽にリハーサルできるようにしておく。ドライランが成功していると安心感が全然違う。
デバッグにも役に立つので必須。

### 本番相当のデータでテストしておく

インテグレーション環境のQAで問題がなかったにも関わらず、本番環境では問題が出たりする。
何やかんやデータが大きいと色々出てくる。
本番DBをマスクしてコピーした環境を用意して本番相当のデータでテストすると安心できる。

自分が経験したのは以下。

1. 絶対に落ちないと思っていたapiが落ちた
前任者しかしらないデータパターンが存在していた。

2. メモリ不足
普通にメモリ不足で落ちた。普段ローカルで開発していると無限ループの時ぐらいしかないので焦った。

3. 概算と明らかに数がずれている
本番相当のデータにスクリプトを流すと、概算と数千のレベルでずれがあることが分かった。そのおかげで本番実行前に対策ができた。

### 途中で失敗しても続きからできるようにしておく

3時間かかるスクリプトで2時間59分の時にエラーが発生したら、最初からやり直すのは不毛だ。
ロールバックして最初からやり直さなくてすむようにしておきたい。

idの範囲指定とかが出来れば、途中からやり直しができるし、並列実行が出来るので時間の節約になる。

### 自社のサーバーに負荷をかけない

internal apiを短時間で叩きすぎてしまわないように注意する。スクリプト実行で社内サーバーを落としてしまったら悲惨だ。

### スクリプトを流すとことでユーザーに迷惑をかけないか確認する

ユーザーのリクエストを捌くサーバーに、移行スクリプトの処理をさせてしまうことで、ユーザーのUXを下げてしまう可能性がある。
夜間にするとか、作業用のサーバーを立てるとかしよう。

### スクリプト実行中は他のことに集中できない

本番のスクリプト実行時は、そわそわして他の作業が手につかない。
この時間に何か予定を入れるのはやめておこう。
作業中に誤って、consoleのコマンドを押してしまう可能性もあるし。
Power Apps でゲーム作成をして学んだノウハウ -1- ゲーム内タイマーを作ろう 

ふと、僕も他の猛者みたいに Power Apps でゲームを作ってみようと思い、さっそくインベーダーゲームを作ってみました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Power Apps で作るインベーダーゲーム。ゲームとしてちゃんと作っていくとクリアするのが難しくなってきた。<a href="https://twitter.com/hashtag/jppug?src=hash&amp;ref_src=twsrc%5Etfw">#jppug</a> <a href="https://twitter.com/hashtag/jpaug?src=hash&amp;ref_src=twsrc%5Etfw">#jpaug</a> <a href="https://t.co/KKj3cBWKuo">pic.twitter.com/KKj3cBWKuo</a></p>&mdash; Ota Hirofumi (@hrfmjp) <a href="https://twitter.com/hrfmjp/status/1223946914611093504?ref_src=twsrc%5Etfw">February 2, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

ゲームを作りながら学んだノウハウをいくつかに分けて Qiita に書き残しておこうかと思います。

#ゲーム内タイマーを作る
ゲームのようにアニメーションなどを行いたい場合はタイマーがあると便利です。そこで Power Apps で作るゲーム作成でもタイマーを作ります。

##タイマーコントロール
Power Apps には「タイマー」コントロールが用意されていますので、基本的にはこちらを利用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167110/b4b79c37-dbcd-a431-5cd7-c8a8f0304c88.png)

このタイマーコントロールは Value プロパティとしてタイマーが動き出してから 1/1000 秒単位の経過時間を返してくれます。が、大きな問題点としてその値の精度は 1/1000 秒単位ではありません。値を観察していると、下二桁は「00」または「50」のいずれかになるようです。

これは良くありませんね。とは言えそもそも 1/1000 秒単位での精度を求めるゲームを作るつもりもないので、ここは割り切って次の値を使おうと思います。

```PowerApps
Timer1.Value/50
```

Timer1 はタイマーコントロールの名前ですね。50 で割ることで、この値はタイマーがスタートすると 0 から 1 ずつシリアルに増加する使いやすい値になります。

##タイマーの値はスライダーコントロールに保持する
ゲームの作成を進めるにあたって、タイマーにより作られた時間を色んな場面で参照しなくてはなりません。必要な度にタイマーコントロールから値を取得するのも良し、なのですが、Power Apps の「スライダー」コントロールを使うと便利でした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167110/441b02dd-2287-95b6-5786-e0efe736e405.png)

このスライダーコントロールの「Default」と「Max」プロパティに先ほどの計算式を入れておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167110/1d97b7bd-de28-e030-4143-53e0df9a5504.png)

するとどうでしょうか？タイマーが動き出すと、このスライダーコントロールの「Value」プロパティが自動的に 0 から 1 ずつ増えていきます。Power Apps では、計算式に含まれる値が変化すると自動で再計算が行われるためです。この動作に慣れておくと、Power Apps でのアプリ作成がとても楽になります。

また、値が増えるたびにスライダーコントロールの「OnChange」が実行されるため、時間が変わったら何かするといった処理も加えることができます。 

#まとめ
Power Apps でゲームを作るときに「タイマー」コントロールをそのまま使おうと思うと使い勝手がよくありませんでした。そこで精度を落とした自作タイマーを作ることにしました。

その自作タイマーを作るときにスライダーコントロールを活用すると、値を取り出すのも便利で、かつ、時間によって何かの処理を実行できる便利なタイマーを作成できました。

といった形で、またいくつかゲーム作成時に考えたノウハウを投稿していきたいと思います。
VSCodeを使って素朴に素朴にNode + TypeScript

学習用に。

## 必要なもの

### 事前に準備するもの

* Node.js
* VSCode

### 途中でインストールするもの

* `typescript`

## 手順

### 1. `npm init`

いろいろ聞かれますが全部Enterで返事しておきます。

### 2. `npm install typescript --save-dev` でTypeScriptのインストール

### 3. `npx typescript --init` で`tsconfig.json`を生成

### 4. 生成された`tsconfig.json`をいじる  

* `"sourceMap: true"` の行は使いたいのでコメントアウト解除
* `"outDir": "./"` の行はコメントアウト解除して`"outDir": "./dist"` とでもしておきましょう。
* `"rootDir": "./src"`などとすることで、ソースファイルのルートディレクトリを設定できます。

あとはそのままでいいんじゃないかなと思います。必要になったら変更で。

### 5. VSCode上でビルドの設定をする

1. エディタ上でコマンドパレットを開き(F1)、`task configure task`と入力 => 「テンプレートからtasks.jsonを生成」でEnter => 「Others」を選びます。要は`./.vscode/tasks.json`ができればいいです。
2. 下記を参考にビルドタスクを追加します。`label`はただの識別名なので適当で。

```json:./.vscode/tasks.json
{
// tasks.json 形式の詳細についての資料は、
    // https://go.microsoft.com/fwlink/?LinkId=733558 をご覧ください
    "version": "2.0.0",
    "tasks": [
        {
            "label": "typescript build",
            "type": "shell",
            "command": "node ./node_modules/typescript/bin/tsc",
            "group": "build"
        }
    ]
}
```

### 6. VSCode上でデバッグの設定をする

1. エディタ左側のメニューから虫アイコンをクリックし、`launch.json`ファイルを作成する
2. デバッグの種類を聞かれたらNode.jsを選択
3. 生成された`launch.json`をいじる  
   `"program": "${workspaceFolder}\\dist\\index.js"` のように変更して、実行するJSファイルのパスを変更。  
   `typescript`により生成されたファイルを実行したいので、`dist`フォルダ内にある(これから作られるのでまだない)`index.js`を指定。  
   デバッグする前にビルドしたいので、`"preLaunchTask": "先ほど設定したタスクの適当な名前"`を追記。

```json:./.vscode/launch.json
{
    // IntelliSense を使用して利用可能な属性を学べます。
    // 既存の属性の説明をホバーして表示します。
    // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "プログラムの起動",
            "skipFiles": [
                "<node_internals>/**"
            ],
            "program": "${workspaceFolder}\\dist\\index.js",
            "preLaunchTask": "typescript build"
        }
    ]
}
```

ここまでで環境構築自体は終わりです。お疲れ様でした。参考までにHelloWorldします。

### 7. `./src/index.ts`を作成

```ts:./src/index.ts
const hw: string = 'hello world';
console.log(hw);
```

あとはF5キーを押すことで、ビルド => 完了次第デバッグ開始されます。ブレークポイント置けば止まるし、普通にデバッグできます。

実体としてはかなり素朴な内容で、tscでビルドして、終わったらVSCode + Nodeのデバッガでデバッグするというものです。  
VSCodeで「デバッグ前のタスク」を実行できるので、これを利用しています。

## 背景

Vue + TypeScriptをやったことがあるのですが、TypeScriptの設定はvue-cliに任せきりだったので、
Node.js + TypeScriptをシンプルに試してみたかったのでした。

## 参考

[TypeScript + Node.js プロジェクトのはじめかた2019 - Qiita](https://qiita.com/notakaos/items/3bbd2293e2ff286d9f49#%E6%88%90%E6%9E%9C%E7%89%A9)

## 筆者の環境

* Windows 10
* VSCode 1.14.1
* Node.js v8.12.0
yukicoder No.976を解く。

#yukicoder No.976

##問題
>
正の整数$M$が与えられます。$2^{128}$を$M$で割った余りを求めてください。
入力
$M$
$M$は$1≤M<2^{60}$
 を満たす整数です。

>出力$M$での余りを出力し、改行してください。


##解く！
```math
a_1 \equiv b_1　(mod　m),a_2 \equiv b_2　(mod　m),...,a_n \equiv b_n　(mod　m)　の時\\
a_1a_2...a_n \equiv b_1b_2...b_n　(mod　m)　であり\\
　\\
a \equiv b　(mod　m),c \equiv ad　(mod　m)の時\\
c \equiv bd　(mod　m)なので\\
　\\
a_1a_2 \equiv b_1b_2　\equiv x_2　(mod　m)\\
a_1a_2a_3 \equiv b_1b_2b_3 \equiv x_2b_3 \equiv x_3　(mod　m)\\
a_1a_2a_3a_4 \equiv b_1b_2b_3b_4 \equiv x_3b_4 \equiv x_4　(mod　m)\\
.\\.\\.\\
a_1a_2a_3...a_n \equiv x_{n-1}b_n　(mod　m)\\
```

よって以下のコードで解ける。

```cpp:976.cpp
#include<iostream>
#include<cmath>

#define REP(i,N) for(int i=0,__i=N;i<__i;++i)

typedef unsigned long long ll;

ll M;

bool input(){
	using namespace std;
	cin>>M;
	if(M<1||M>pow(2,60))
		return false;
	return true;
}

ll solve(){
	using namespace std;
	ll res=1;
	REP(i,128){
		res=(res*2)%M;
	}
	return res;
}

int main(){
	using namespace std;
	if(!input())
		return -1;
	ll n=solve();
	cout<<n<<endl;
}
```

```sh:
$ echo 1152919305583591425|./a.out
3377698646784256
```
【RSpec】重複のバリデーションエラーを回避するFactoryBotの書き方

ユーザー登録でemailを重複させないようにバリデーションをかけましが、テストのときにでFactoryBotで複数ユーザを予め生成する必要があったので方法を調べました。シーケンスを使ってユニークなデータを生成するやり方です。備忘録として残します。

問題点
-

ファクトリーで複数のユーザをセットアップする際に、emailをバリデーションでユニークなデータとして設定している場合、下記のようにするとテストコードが走る前に例外が発生します。

```ruby:spec/factories/users.rb
FactoryBot.define do
  factory :user do
    user_name { "tester" }
    email { "tester@example.com" }
    password { "password" }
  end
end
```

```ruby:spec/models/user_spec.rb
  it "複数のユーザー登録" do
    user1 = FactoryBot.create(:user)
    user2 = FactoryBot.create(:user)
  end
```

これでテストを実行すると、当然ですが次のようなバリデーションエラーが発生します。

```bash:ターミナル
Failures:
  1) 複数のユーザー登録
     Failure/Error: user2 = FactoryBot.create(:user)
     
     ActiveRecord::RecordInvalid:
       バリデーションに失敗しました: メールアドレスはすでに存在します
```

解決策
-
シーケンスを使います。シーケンスはファクトリから新しいオブジェクトを作成するたびにカウンタの値を1づつ増やしながら値を設定します。

```ruby:spec/factories/users.rb
FactoryBot.define do
  factory :user do
    user_name { "tester" }
    sequence(:email) { |n| "tester#{n}@example.com" }
    password { "password" }
  end
end
```

`email { "tester@example.com" }`を`sequence(:email) { |n| "tester#{n}@example.com" }`と書き換えることで、userが生成されるたびに`ｎ`が１づつ増えていき、`tester1@example.com``tester２@example.com`のようにユニークで連続したemailが設定されます。

```bash:ターミナル
#見やすいように加工してあります
user1
<User id: 13, 
user_name: "tester", 
email: "tester1@example.com", 
password: "password", 
created_at: "2020-02-05 01:56:36", 
updated_at: "2020-02-05 01:56:36">
```

```bash:ターミナル
#見やすいように加工してあります
user2
<User id: 14, 
user_name: "tester", 
email: "tester2@example.com", 
password: "password",
created_at: "2020-02-05 01:57:21", 
updated_at: "2020-02-05 01:57:21">
```
gRPC の使い方 (python)

参考ページ
[Python Quick Start](https://grpc.io/docs/quickstart/python/)

必要なライブラリーのインストール

```bash
sudo python -m pip install grpcio
sudo python -m pip install grpcio-tools
```

設定ファイル、サーバープログラム、クライアントプログラムの３つが必要です。

設定ファイル

```text:helloworld.proto

syntax = "proto3";

package helloworld;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
  rpc SayHello2 (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}
```

サーバープログラム

```py:greeter_server.py
import sys
from concurrent import futures
import logging

import grpc

import helloworld_pb2
import helloworld_pb2_grpc


class Greeter(helloworld_pb2_grpc.GreeterServicer):

    def SayHello(self, request, context):
        sys.stderr.write("*** SayHello ***\n")
        str_out = 'Test Hello, %s!' % request.name
        sys.stderr.write(str_out + "\n")
        return helloworld_pb2.HelloReply(message=str_out)

    def SayHello2(self, request, context):
        sys.stderr.write("*** SayHello2 ***\n")
        str_out = 'Test2 Hello again, %s!' % request.name
        sys.stderr.write(str_out + "\n")
        return helloworld_pb2.HelloReply(message=str_out)


def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
    server.add_insecure_port('[::]:50051')
    server.start()
    server.wait_for_termination()


if __name__ == '__main__':
    logging.basicConfig()
    serve()
```

クライアントプログラム

```py:greeter_client.py
from __future__ import print_function
import logging

import grpc

import helloworld_pb2
import helloworld_pb2_grpc


def run():
    with grpc.insecure_channel('localhost:50051') as channel:
        stub = helloworld_pb2_grpc.GreeterStub(channel)
        response = stub.SayHello(helloworld_pb2.HelloRequest(name='John'))
        print("Greeter client received: " + response.message)
        response = stub.SayHello2(helloworld_pb2.HelloRequest(name='Tom'))
        print("Greeter client received: " + response.message)

if __name__ == '__main__':
    logging.basicConfig()
    run()
```

gRPC のコードを作成します。

実行前

```text
$ tree
.
├── greeter_client.py
├── greeter_server.py
└── helloworld.proto
```

スクリプト

```bash
python -m grpc_tools.protoc -I. \
	--python_out=. \
	--grpc_python_out=. \
	./helloworld.proto
```

実行後

```text
$ tree
.
├── greeter_client.py
├── greeter_server.py
├── helloworld_pb2_grpc.py
├── helloworld_pb2.py
└── helloworld.proto
```

サーバープログラムの起動

```bash
python greeter_server.py
```

クライアントプログラムの実行

```text
$ python greeter_client.py 
Greeter client received: Test Hello, John!
Greeter client received: Test2 Hello again, Tom!
```

サーバーのコンソールには次のようなメッセージが出ます。

```text
$ python greeter_server.py 
*** SayHello ***
Test Hello, John!
*** SayHello2 ***
Test2 Hello again, Tom!
```
GitHub 基礎用語　1

#はじめに
[Gitについてこちらをクリック願います。](https://qiita.com/raigakun/items/fe8e5dee9714dcd1ea57)
Git,GitHubを学んでいく上で、用語等を中心に整理していきます。
もうすでにご存知の方、省略の仕方等ご存知でしたら、ご教授願います。

#GitHubとは
Gitの仕組みを利用したWebサービスのこと。

リモート環境の用意をするのに用いる。

#リモートリポジトリの用意
ターミナルへ入力することを前提とする。

git remote add　：　ローカルリポジトリとリモートリポジトリを結びつける。
git push　：　ローカルリポジトリでのコミットをリモートリポジトリ(origin)に反映する操作のこと
origin　：　リモートリポジトリの場所の別名


#ブランチ

masterブランチ　：　主流のコード
トピックブランチ　：　並行作業（修正や削除等）時に作成する。
　　　　　　　　　　→主に機能ごとにブランチ（トピック）を作成し、中身を編集する。

#プルリクエスト

コミュニケーションが取れる掲示板的な役割がある。
コメント履歴と各コミットにおける変更修正にコメントをつけることができる。

###プルリクエスト作成のポイント

①タイトル
　[WIP]をタイトル文頭につける　：　作業中の意味　Work In Progress
　[WIP]を外す　　　　　：　実装が一旦完了した場合、外す。
　　　　　　　　　　　　　　→　レビューを依頼する時は、外す。

②内容
　わかりやすく書くことが大事。
　What　どのような実装をしているのか
　Why　なぜこの実装が必要なのか
　＊　マークダウン表記で書くこと


#LGTM
 Looks good to me　：　コードに問題がないので、マージ（結合）していいよ！
　
その後、トピックブランチからmasterブランチへ統合する。

#さいごに
日々勉強中ですので、随時更新します。
皆様の復習にご活用頂けますと幸いです。
Ruby　コーティング規約について　構文編　3

# はじめに
[レイアウト編はこちらをクリック願います。](https://qiita.com/raigakun/items/7416db5b4d70ea93046e)
[構文編 2 はこちらをクリック願います。](https://qiita.com/raigakun/items/80ba30671d7b2b18c44e)
Rubyの基礎を学習中の方に向けて記載致します。
私自身これからチーム開発を行う上で大事にしたい。知っておきたいことをOutputします。

#構文について
① 否定形のときはifよりunlessを優先的に使う。(もしくは||構文を使う。) 

```qiita.rb
# 悪い例
do_something if !some_condition

# 悪い例
do_something if not some_condition

# 良い例
do_something unless some_condition

# 良い例(||を使う場合）
some_condition || do_something
```

② unlessをelse付きで使ってはいけない。 肯定条件を先にしてから書き換える。

```qiita.rb
# 悪い例
unless success?
  puts 'fail'
else
  puts 'success'
end

# 良い例
if success?
  puts 'success'
else
  puts 'fail'
end
```

#さいごに
毎日更新します。
皆様の復習等にご活用頂けますと幸いです。
fish で一つ前のディレクトリにcdする

# zshではどうしていたか

* pushdコマンド
    * カレントディレクトリパスを保存
* popdコマンド
    * stackからパス(一つ前のカレントディレクトリ)を取り出す
* dirsコマンド
    * stackの確認

これはcdではなくカレントディレクトリを履歴(stack)に保存しておいて,取り出して移動するためのコマンド.

zshではこれをcdするたびに自動化してくれる設定がある.

```
setopt AUTO_PUSHD
```

これにより適宜一個前に戻りたいとき,popdコマンドで一つ前のカレントディレクトリに戻れる.

# fishではどうか

zshでは設定ファイルをautoにしなければいけなかったが,fishでは最初から標準コマンドがあった.

* prevd
    * stackの前に移る
* nextd
    * stackの次に移る
* dirh
    * cdの移動履歴

これのほうが楽ちん！

# zコマンドでいいのでは
zコマンドは移動したことのあるディレクトリの頭文字を入れるだけで,サジェストしてくれる便利なコマンド.
zコマンドは便利だがディレクトリの名前を入れたり,tabを押したり少しインタラクティブな動作が必要だが,直近のディレクトリに戻りたいだけならば今回のコマンド群のほうがいい.

# 参考文献
https://medium.com/veltra-engineering/fish-shell-cd-history-bd70999b99a6
gcloud configについて（SDK設定の追加／切り替え／削除など）

# 概要

若干探したので、備忘録。

# 初期化／作成

```sh
gcloud config configurations create <config name>
```
以下のコマンドでも一応大丈夫（厳密にはsdk初期化コマンド）。

```sh
gcloud init
```

# 切り替え

```sh
gcloud config configurations activate <config name>
```

# 削除

```sh
gcloud config configurations delete <config name>
```

# 設定の一覧表示

```sh
gcloud config configurations list
```

# 参考

- gcloud config：[https://cloud.google.com/sdk/gcloud/reference/config](https://cloud.google.com/sdk/gcloud/reference/config)
UIDocumentBrowserViewController ベースのコードを mac catalyst 化する際に遭遇したエラーの対処方法の記録

iOS アプリのプロジェクトを mac catalyst (UIKitForMac) 化する実験を行なっていましたが、`UIDocumentBrowserViewController` ベースのアプリ（実際はただの実験コード）を catalyst 化する際に出たエラーの対処方法を将来の自分と、エラーメッセージを元に検索してきた方の為にメモ。


実際の実行時のログはこんな感じ。

```.console
[User Defaults] Couldn't write values for keys (
    ApplicationAccessibilityEnabled
) in CFPrefsPlistSource<0x600002c02380> (Domain: com.apple.Accessibility, User: kCFPreferencesCurrentUser, ByHost: No, Container: (null), Contents Need Refresh: Yes): setting preferences outside an application's container requires user-preference-write or file-write-data sandbox access
[User Defaults] Couldn't write values for keys (
    AccessibilityEnabled
) in CFPrefsPlistSource<0x600002c02380> (Domain: com.apple.Accessibility, User: kCFPreferencesCurrentUser, ByHost: No, Container: (null), Contents Need Refresh: No): setting preferences outside an application's container requires user-preference-write or file-write-data sandbox access
[User Defaults] Couldn't write values for keys (
    FullKeyboardAccessFocusRingEnabled
) in CFPrefsPlistSource<0x600002c02380> (Domain: com.apple.Accessibility, User: kCFPreferencesCurrentUser, ByHost: No, Container: (null), Contents Need Refresh: No): setting preferences outside an application's container requires user-preference-write or file-write-data sandbox access
[User Defaults] Couldn't write values for keys (
    ApplicationAccessibilityEnabled
) in CFPrefsPlistSource<0x600002c02380> (Domain: com.apple.Accessibility, User: kCFPreferencesCurrentUser, ByHost: No, Container: (null), Contents Need Refresh: No): setting preferences outside an application's container requires user-preference-write or file-write-data sandbox access
Metal API Validation Enabled
[OpenSavePanels] ERROR: Unable to display open panel: your app is missing the User Selected File Read app sandbox entitlement. Please ensure that your app's target capabilities include the proper entitlements.
```

これが、検索キーワードが悪買ったのか、ヒットに恵まれなかったので…自分でいろいろ調べた結果、`.entitlements` に `com.apple.security.files.user-selected.read-write` キーに対して `true` を指定すればとりあえず先に進めることがわかりました。

```.xml
<dict>
	// ... snip ...
	<key>com.apple.security.files.user-selected.read-write</key>
	<true/>
</dict>
```

執筆時点の Xcode のバージョンは `Version 11.3.1 (11C504)` Swift のバージョンは以下のとおりです。

```.console
$ swift --version
Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
Target: x86_64-apple-darwin19.3.0
```
【Rails6】jQueryがなかなか使い始められない人へ

## Rails6になってjQueryの設定が大きく変わった！

自作アプリの開発に取り掛かろうとした矢先、jsが全く動かせなくて滅茶苦茶焦りました。
それで調べてみたら、Rails6からjQueryの設定方法がガラリと変わっているらしいです。
このせいで2〜3時間無駄にしたのではないのだろうか・・・まだまだ精進が足りない。

### どう変わったのか？
まだまだ勉強中のため詳しいことはまだ分かりませんが、触りの部分だけ紹介します。
いいから使えるようにしたい、という場合は下の方にある[設定手順](https://qiita.com/iiyama_makoto/items/940b130fd20540fd70f1#rails6%E3%81%A7%E3%81%AE%E8%A8%AD%E5%AE%9A%E6%89%8B%E9%A0%86)から読み進めてください。

1.　gemが必要ではなくなった
今までは`'jquery-rails'`gemをインストールしていましたが、Rails6からはgemの追加が必要なくなります。
代わりにwebpackで必要な情報をインストールしていきます。

2.　jQuery関連ファイルの保存フォルダが違う場所にある
かつてはapp/assets/javascriptsフォルダに保存していましたが、今後はapp/javascriptフォルダに変更となります。

## Rails6での設定手順
1.ターミナル、アプリのフォルダで下記のコマンドを実行します。

```:ターミナル
yarn add jquery
```
2.webpackの設定ファイルを編集します。

```js:config/webpack/environment.js
const { environment } = require('@rails/webpacker')
// 以下を追記
const webpack = require('webpack')
environment.plugins.prepend('Provide',
  new webpack.ProvidePlugin({
    $: 'jquery/src/jquery',
    jQuery: 'jquery/src/jquery'
  })
)
// ここまで
module.exports = environment
```
3.application.jsファイルを編集します。

```js:app/javascript/packs/application.js
// (前略)
require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
require("jquery")  // ←の1行を追加
// (後略)
```

4.自身のjqueryファイルを作成、読み込ませます。
作成するjsファイルは、javascriptフォルダに保存します。

```js:app/javascript/test.js
$(function() {
  console.log("test");
});
```
```js:app/javascript/packs/application.js
// (前略)
require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
require("jquery")
require("test.js")  // ←の1行を追加
// (後略)
```

フォルダを作って保存する場合は、`require("(フォルダ名)/(ファイル名).js")`を追加してあげると読み込んでくれるようになります。
作成したjsファイルがなかなか読み込まれずに苦戦しました。
ですがこれでRails6でも心置きなくjQueryに取り組めそうです。


### 参考
- [Introducing jQuery in Rails 6 Using Webpacker](https://www.botreetechnologies.com/blog/introducing-jquery-in-rails-6-using-webpacker)
DynamoDBの1項目（フィールド）のサイズ上限

2020年1月現在
１文字ずつ入れてやった結果、
属性名、属性値含めて全部で409600byteまで（たぶん）
文字コードはUTF-8っぽい。

参考情報
[DynamoDB での制限](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Limits.html)
[DynamoDB 項目のサイズ](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/CapacityUnitCalculations.html)
GHEのbackup-utilsで`Pruning 1 failed snapshot(s) ...`

Github Enterpriseでお世話になりがちな[backup-utils](https://github.com/github/backup-utils)。

## 現象

Jenkins上で実施していたら、先日以下のようなエラー。

```
Backing up GitHub Pages ...
Backing up storage data ...
Backing up custom Git hooks ...
Backing up Elasticsearch indices ...
Pruning 1 failed snapshot(s) ...
touch: cannot touch '<path>/workspace/ghebackup/backup/20200101T000000/incomplete': Permission denied
Makefile:3: recipe for target 'backup' failed
make: *** [backup] Error 1
Build step 'Execute shell' marked build as failure
```

バックアップ自体は成功しているっぽいのに。

## 解決策

`<path>/workspace/ghebackup/backup/20200101T000000/incomplete`のファイルを削除して再度実行。

## 原因
2020/1/1のバックアップが別要因で失敗していた。その要因は既に取り除いた。
その際に、`<path>/workspace/ghebackup/backup/20200101T000000/incomplete`が吐き出される。このファイルはroot所有になっていた。
以下の実装の通り、どうも他の日付の`incomplete`が残っていても今回のバックアップをエラーとしてしまう様子。
（コードは<https://github.com/github/backup-utils/blob/v2.19.2/share/github-backup-utils/ghe-prune-snapshots#L24-L30>より。githubコードの埋め込みはできないみたい）

```sh
prune_dirs="$(ls -1 "$GHE_DATA_DIR"/[0-9]*/incomplete 2>/dev/null || true)"
prune_num=$(echo "$prune_dirs" | grep -v '^$' | wc -l)

if [ $prune_num -gt 0 ]; then
  echo Pruning $prune_num "failed snapshot(s) ..."
  echo "$prune_dirs" | sed 's@/incomplete$@@' | prune_snapshot
fi
```
GitLabプライベートリポジトリのrawリンクをCLIでダウンロードする

Download gitlab private repository's raw link using CLI

GitLab 11.5.1から、PRIVATE-TOKENヘッダを使用してrawリンクのダウンロードができなくなりました (cf https://about.gitlab.com/releases/2018/11/28/security-release-gitlab-11-dot-5-dot-1-released/ Improper Enforcement of Token Scope)。
rawリンクが渡されたらURLをパース・変換して、ついでにファイル自体もダウンロードもできるようにしてみました。

```py
#!/usr/bin/python
#gitlab_download

import os
import sys
import json
import shutil
from contextlib import closing

if sys.version_info[0]>=3:
    import http.client as httplib
    from urllib.request import urlparse
    binstdout = sys.stdout.buffer
else:
    import httplib
    from urlparse import urlparse
    binstdout = sys.stdout

def parse_gitlaburl(urlstr):
    url = urlparse(urlstr)
    a=url.path[1:].split('/')
    projname='/'.join([a[0],a[1]])
    if a[2]=='-':
        a.pop(2)
    if a[2]=='raw' or a[2]=='blob':
        revision=a[3]
        filepath='%2F'.join(a[4:])
        url_suffix='/repository/files/'+filepath+'/raw?ref='+revision
    elif a[2]=='jobs':
        assert a[4]=='artifacts'
        jobID=a[3]
        if a[5]=='download':
            url_suffix='/jobs/'+jobID+'/artifacts'
        elif a[5]=='raw' or a[5]=='file':
            filepath='/'.join(a[6:])
            url_suffix='/jobs/'+jobID+'/artifacts/'+filepath
        else:
            assert False
    else:
        raise Exception('unknown URL type %s'%a[2])
    return projname, url_suffix

def download_file(urlstr, token, fout):
    projname, url_suffix = parse_gitlaburl(urlstr)
    url = urlparse(urlstr)
    with closing(httplib.HTTPSConnection(url.hostname,port=url.port)) as https:
        https.request('GET','/api/v4/projects?search_namespaces=true&search='+projname,None,{'Authorization':'Bearer '+token})
        resp = https.getresponse()
        jso = json.loads(resp.read())
        proj = next(e for e in jso if e['path_with_namespace']==projname)
        resolvedPath = '/api/v4/projects/'+str(proj['id'])+url_suffix
        sys.stderr.write('resolved: https://%s%s\n'%(url.netloc,resolvedPath))
        https.request('GET',resolvedPath,None,{'Authorization':'Bearer '+token})
        resp = https.getresponse()
        #print(resp.getheaders())
        shutil.copyfileobj(resp,fout)

def get_token(**kwargs):
    url = urlparse(kwargs['url'])
    token = os.environ.get('gitlab_token_'+url.hostname.replace('.','_'),'')
    if not token:
        ### custom logic comes here
        pass
    return token

if __name__ == "__main__":
    token = get_token(url=sys.argv[1])
    download_file(sys.argv[1], token, binstdout)
```

## 200602

プロジェクト名からプロジェクトIDに変換する際、`search_namespaces=true`を与えるようにしました。

## 210511

ci artifactをダウンロードできるようにしました。あと、再利用しやすくしました。
Apexジョブをスケジュールするおよび注意事項

<h2>１　Apexファイルを作成する</h2>
TrailHeadから盗んだソース（Email送信するだけ）のだが、確認するのが十分だと。
![キャプチャ1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578884/932b76fa-794b-7079-4449-1919cfdf745e.png)

<h2>２　Wapperクラスを作成する</h2>
～EmailManagerを呼び出すだけ、実際は作らなくてもできる気がするけど、～
～addressには自分のMailアドレスを記入～
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578884/11161d06-608f-bd2c-c1b3-428a261bf6a3.png)


ジョブにするApexの書き方の注意事項：
  　  １：implements Schedulable（Schedulableを必ず実装する）implements Schedulable、execute メソッドの呼び出し
  　    　  実装されたメソッドは global または public として宣言する必要があります。
  　  ２：1の繰り返しチェックすること

<h2>３　GUIから「APEXをスケジュール」設定</h2>

![キャプチャ3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578884/d638e802-73af-7b08-09b1-d7c5fccdb860.png)
![キャプチャ4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578884/940825aa-4816-7352-9997-a1483573b88d.png)
次はジョブ名称を決めて、頻度を自由に設定して保存する。![キャプチャ5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578884/6dd5f283-b49d-cde5-cf62-e399b7582c46.png)


<h2>４　確認するには、「Apex　ジョブ」、「スケジュール済みジョブ」のビュー</h2>
![キャプチャ6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578884/5d793b20-458e-7a5e-b452-24702eb38807.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578884/fba7fa5b-7797-ab63-8705-1030c20d1db6.png)


状況が完了したら、自分のMailを確認して、送信されたね！
WindowsのVSCodeでPHPのお手軽実行環境を構築

# Windows の VSCode で PHP のお手軽実行環境を構築
Windows10 の VSCode(git bash)で PHP7 のお手軽実行環境の構築手順です。
目的は PHP の勉強など、短いコードを書いてすぐ実行できるようにするためです。

# PHP の設定
## PHP をダウンロード
https://windows.php.net/download/
適当なバージョンの`x64 Thread Safe`のzipをダウンロードし好きなところに展開
今回は展開されたディレクトリ名を`php`に変更して`C:\php\`のようにCドライブ直下に配置

## Pathの追加
1. コントロールパネル>システムとセキュリティ>システムでシステムの詳細設定を押下
2. システムのプロパティが表示され、詳細設定タブを選択し、環境変数ボタンを押下
3. ~のユーザー環境変数の変数: `Path`を選択し編集ボタンを押下
4. 環境変数名の編集が表示され、新規ボタンを押下し、`C:\php\`の追加

# vscode の設定
## VSCode の TERMINAL を Git Bash に変更する
この記事が参考になりました。感謝です。
[WindowsのVSCodeでGit Bashをターミナルに設定する](https://qiita.com/psychoroid/items/63cc0ece70fce0f0cfc0)
## 導入拡張機能
Extensionsから下記の拡張機能をインストールする。
- [PHP Intelephense](https://github.com/felixfbecker/vscode-php-intellisense)
- [Code Runner](https://github.com/formulahendry/vscode-code-runner)

## settings.json 追記
`Ctrl+Shift+p`で`Preferences: Open Settings (json)`を選択し下記を追記する。

```
"php.validate.executablePath": "C:\\php\\php-win.exe",
"php.executablePath": "C:\\php\\php-win.exe",
"php.suggest.basic": false,
"code-runner.executorMap": {
  "php": "/c/php/php"
},
// 出力先をTERMINALにする
"code-runner.clearPreviousOutput": true,
"code-runner.runInTerminal": true,
```

## Code Runner で PHP のコードを実行
任意の PHP ファイルを開き`Ctrl+Alt+n`で実行！
TERMINAL に結果が表示されたら完了です。

### 実行でエラーが出たとき
- `C:/php/php.exe: error while loading shared libraries: api-ms-win-crt-locale-l1-1-0.dll: cannot open shared object file: No such file or directory`
https://www.microsoft.com/ja-jp/download/confirmation.aspx?id=48145
ダウンロードしたものを実行してインストール

- `PHP Warning:  'vcruntime140.dll' 14.0 is not compatible with this PHP build linked with 14.16 in Unknown on line 0`
https://visualstudio.microsoft.com/ja/downloads/
「Visual Studio 2019 の Microsoft Visual C++ 再頒布可能パッケージ」のx64を選択しダウンロード
ダウンロードしたものを実行してインストール
typescript の AST を使って一部コードを自動生成した話

仕事でDB接続層を新規のアーキテクチャーに移行することがあったのですが、
* 同じコードを延々と書く
* DBのカラムとかを目視で確認する
* テストもほぼ同じ

↑のせいでつらすぎたので、AST を使ってコードを自動生成出来ないかなとやったときのメモです。

# ASTとは
ASTとは抽象構文木(Abstract syntax tree) といって、　使用する言語に対して意味があるもの(if, else などの予約語や カッコなどの普遍的に意味を持つもの)のみを抽出して、それを木構造にしたものです。

このASTのツールを使うとコードを自動生成したり、一部のコードを置換したりできます。


# 今回の要件
今回は Repositoryパターンといって、DBの接続部分をラップするオブジェクトを作って、そこで各テーブルの差異や命名規則をアプリケーション部分側で考えることなく使用できるようにします。

なので、　DBのテーブル毎に

* データを保持するクラス
* データベースに接続するクラス

の2つが必要になります。

新規アーキテクチャーでは、sequelize を使うので、文法もsequelize に則る必要がある。

## どこを自動生成すべき? 
結論から言って、2クラス全てを自動生成するのは非常に辛いです。

* 単純に時間がかかりすぎる
* クラスの構造が少し変わるだけで修正に時間が取られそう
* これを保守することはリスクとリターンから考えて果たして良いことか? 
* スニペットで代替できる部分がある

特に昨今のスニペット作成機能が結構強力で、テンプレートを自作スニペットで用意する方が、
後々の変更などを含めて簡単に追加、修正が行えます。

なので、DBの単純にDBのスキーマ情報を取得してASTで変数やオブジェクトの形で加工するという工程をASTを用いて行うことにしました。
理由として

* DBの部分なのでミスが起こると大きな問題になる
* 目視で書いたコードと実際にDBを見るのはつらすぎる

特に2番目が凶悪で、書いた本人とレビュワーの双方が披露していきます。

なので、仮のファイルを生成して、そこにDBのカラム情報に関する情報を変数として生成することにしました。

# 設計
## DBの情報読み取り
typesciprtから適当にDBに繋いで以下の情報を取得します。

DBの対象テーブルの　カラムやデータ型、インデックスや外部キーの情報がほしかったので、
`information_schema.COLUMN` から対象テーブルの

* DATA_TYPE : データの型
* COLUMN_NAME : カラム名
* COLUMN_TYPE : データ型の詳しい情報 (bigint(10) unsignedなど)
* IS_NULLABLE : null許容
* COLUMN_KEY : primary_keyなどのキー情報
* COLUMN_DEFAULT : デフォルト値
* EXTRA : auto_increment などの特殊な設定

`information_schema.STATISTICS` から対象テーブルの
* NON_UNIQUE : ユニークキー制約の有無
* INDEX_NAME : インデックスの名前
* COLUMN_NAME : 上2つに紐づくカラムの名前

を取得します。

## ASTでコード生成

### ファイル生成
```typescript

import {Project} from "ts-morph"

const project = new Project({);
const createdFile = project.createSourceFile("filename.ts",
{// ファイルに生成するオブジェクトなど}
);

project.save(); // 保存
```

## interface, enum生成
普通であれば専用の関数があるのですが、面倒だったので初期化時に生成するようにしました。

```typescript

import {Project} from "ts-morph"

const project = new Project({);
const createdFile = project.createSourceFile("filename.ts",
{ 
    enums: [
        {
            name: "Fields", // enumの名前
            isExported: true, // exportするか?
            members: testList, // {name: string, value:string}の配列
        },
    ],
    interfaces: [
        {
             name: "Attributes", // interfaceの名前
             isExported: true, // export するか?
             properties: testList2, // {name: string, type: string}の配列
        },
});

project.save(); // 保存
```

### 変数生成
```typescript

createdFile.addVariableStatement({
    declarationKind: VariableDeclarationKind.Const, // 変数の状態 const or let を定義
    declarations: [{ // 実際に入れる値を入れる
        name: "myNumber",
        initializer: "5"
    }, {
        name: "myString",
        type: "string",
        initializer: `'my string'`
    }]
});
```

## マージ
あとは、スニペットとASTでされたそれぞれのコードを手作業でマージします。

# 最後に　
目的自体は達成できたのですが、筋が悪いことをしてるような、もうちょっといい方法があるような気がします。
また、今回はASTの機能の一部しか使ってないので、興味がある方はちゃんと見ることをおすすめします。
それでは良いASTライフを
UILabelの行数を調べる方法

UILabelの行数に応じてフォントサイズを変更したりしたかったので[こちら](https://dev.classmethod.jp/smartphone/uilabel-line-number/)を参考にExtensionとして実装しました
やや使いにくそうでしたので、Swift5に対応してExtensionとして切り出して引数を必要としない形にしました。

## 環境

Swift 5
Xcode 11.2.1

## 行数を調べるExtension

行数を計算したいUILabelで利用してください

```Swift

extension UILabel {
  
  /// 行数を返す
  func lineNumber() -> Int {
    let oneLineRect  =  "a".boundingRect(
      with: self.bounds.size,
      options: .usesLineFragmentOrigin,
      attributes: [NSAttributedString.Key.font: self.font ?? UIFont()],
      context: nil
    )
    let boundingRect = (self.text ?? "").boundingRect(
      with: self.bounds.size,
      options: .usesLineFragmentOrigin,
      attributes: [NSAttributedString.Key.font: self.font ?? UIFont()],
      context: nil
    )
    
    return Int(boundingRect.height / oneLineRect.height)
  }
  
}
```


## 参考

[UILabel の行数を調べる方法 - Developers.io](https://dev.classmethod.jp/smartphone/uilabel-line-number/)
Git 基礎用語　1

#はじめに
Git,GitHubを学んでいく上で、用語等を中心に整理していきます。
もうすでにご存知の方、省略の仕方等ご存知でしたら、ご教授願います。

#リポジトリ
リポジトリ　：　バージョン管理をするための入れ物（変更履歴を保管）

以下、２種類のリポジトリがある。
　　　
ローカルリポジトリ　：　自分のPC上に置くリポジトリ　
リモートリポジトリ　：　外部サーバーやネットワークに置くリポジトリ


#ローカルリポジトリの作成
ターミナルへ入力することを前提とする。

git init　：　当該ディレクトリをGitの管理下におく。
ls .git　：　隠しディレクトリである.gitがあるかどうか確認する。


#インデックス
バージョンを記録するためにファイルを一時的に登録する場所のこと

以下、ターミナルへ入力することを前提とする。

git status　：　インデックスに追加されている変更修正、されていない変更修正を確認することができる。
git add　：　インデックスに追加、変更修正記録の対象とすることができる。


#コミット
インデックスに追加された変更修正をバージョン記録する操作のこと

git commit -m 'タイトル名'

#ログ
コミットの履歴のこと　

git log　：　修正をインデックスに追加する。


#さいごに
日々勉強中ですので、随時更新します。
皆様の復習にご活用頂けますと幸いです。
Craft CMS のテンプレートで正規表現、置換周りを拡張してくれる Regex Replace Twig Filter プラグイン

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8890/e956f20d-0714-a58d-3586-f8d7090195dd.png)

This plugin adds PHP's preg_replace function as a Twig filter.

ということで、Craft CMS のテンプレートで正規表現、置換周りを拡張してくれるプラグイン

> Regex Replace Twig Filter
> https://plugins.craftcms.com/regex-replace-twig-filter

テンプレートの処理の中でデフォルトで足りなくなりそうな時は使えるかもしれない。
[memo] Ionicの**Controllerのcreateメソッドのinterface

備忘録です。よく探すことになるので。Ionic Coreからimportすると様々なinterfaceを取得することできますよー！

```ts
import { ToastOptions } from '@ionic/core/dist/types/components/toast/toast-interface';
import { ModalOptions } from '@ionic/core/dist/types/components/modal/modal-interface';
import { ModalOptions } from '@ionic/core/dist/types/components/modal/modal-interface';
import { AlertOptions } from '@ionic/core/dist/types/components/alert/alert-interface';
import { ActionSheetOptions } from '@ionic/core/dist/types/components/action-sheet/action-sheet-interface';
```
MojaveからCatalinaへのアップデート　bundlerエラー

MojaveからCatalinaへのアップデートをして、Reilsを立ち上げた際、bundle関連のエラーが出て２時間ほど時間を無駄にしたので、対応策を記しておく。


私の場合は「Command Line Tools」を入れ直す必要があった。

調べてみると、大幅なOSアップデート時には「Command Line Tools」を入れ直す必要がある。

「$ xcode-select --install」

上記で「Command Line Tools」を入れ直したあとは、bundleを再インストールしてエラーは解決した。
aiohttp Server でいちばん雑に CORS 対応する方法

aiohttp Server で API サーバを実装する場合の CORS[^cors] 対応は、aiohttp 公式で [aiohttp_cors](https://github.com/aio-libs/aiohttp-cors) というモジュールが用意されている。

[^cors]: [オリジン間リソース共有 (CORS) - HTTP | MDN](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS)

しかし Usage を読んでみると、各リソースと各ルートについて `cors.add` でラップする必要があり、どうも一筋縄ではいかない雰囲気。細かく設定ができるのは便利だが、「今はとにかくすべてのリクエストを許可したいんや」というケースもある。

そこで今回は、aiohttp_cors を使わずに雑に CORS 対応する方法について書く。

``` python
from aiohttp import web

@web.middleware
async def cors_middleware(request, handler):
    response = await handler(request)
    response.headers['Access-Control-Allow-Origin'] = '*'
    return response

app = web.Application(middlewares=[cors_middleware])
```

**終わりです。**

すべてのレスポンスに `Access-Control-Allow-Origin: *` ヘッダを追加するだけ。

「さすがに `*` はどうなの」という場合は環境変数で許可する Origin を指定できるようにするといい。

``` python
import os
from aiohttp import web

@web.middleware
async def cors_middleware(request, handler):
    response = await handler(request)
    response.headers['Access-Control-Allow-Origin'] = os.environ.get('CORS_ALLOW_ORIGIN', '*')
    return response

app = web.Application(middlewares=[cors_middleware])
```

ちなみに Preflight Request が飛ぶケースには対応していない。
対応したければ全ての `OPTION` リクエストに対してよしなに返すやつを作ったらいい。

本当に雑な話なので、セキュリティに大丈夫なのとかそのへんの話は各自よしなに考えていってほしい。

## [追記] もうちょっとちゃんとした版
- [2022.01 追記] Preflight Request にも対応した
- [2022.02 追記] HTTPException を raise した場合も CORS ヘッダを付与するようにした

``` python
from os import getenv
from aiohttp import web

@web.middleware
async def cors_middleware(request, handler):
    headers = {
        "Access-Control-Allow-Headers": "*",
        "Access-Control-Allow-Methods": "*",
        "Access-Control-Allow-Origin": getenv("CORS_ALLOW_ORIGIN", "*"),
    }
    if request.method == "OPTIONS":
        return web.Response(headers=headers)
    try:
        response = await handler(request)
        for key, value in headers.items():
            response.headers[key] = value
        return response
    except web.HTTPException as e:
        for key, value in headers.items():
            e.headers[key] = value
        raise e

app = web.Application(middlewares=[cors_middleware])
```

## [追記] Cookie をあつかう場合
Cookie を扱う場合は以下の変更が必要になる。

- `Access-Control-Allow-Credentials` ヘッダに `true` を設定する必要がある
- `Access-Control-Allow-Headers` に `*` を指定できなくなるので個別設定する

``` python
@web.middleware
async def cors_middleware(request, handler):
    headers = {
        "Access-Control-Allow-Headers": "Content-Type",  # 使用するヘッダを追加していく
        "Access-Control-Allow-Methods": "*",
        "Access-Control-Allow-Credentials": "true",
        "Access-Control-Allow-Origin": getenv("CORS_ALLOW_ORIGIN", "*"),
    }
    if request.method == "OPTIONS":
        return web.Response(headers=headers)
    try:
        response = await handler(request)
        for key, value in headers.items():
            response.headers[key] = value
        return response
    except web.HTTPException as e:
        for key, value in headers.items():
            e.headers[key] = value
        raise e
```
Samba 設定

sudo apt-get -y install samba
sudo mkdir /home/share
sudo chmod 777 /home/share
sudo gedit /etc/samba/smb.con

51行目：コメント解除
interfaces = 127.0.0.0/8

58行目：コメント解除
bind interfaces only = yes

[Share]
    path = /home/share
    writable = yes
    guest ok = yes
    guest only = yes
    create mode = 0777
    directory mode = 0777

sudo systemctl restart smbd
細かいことはいいから特定のAPIエンドポイントのOkHttpログをtailする

Androidの開発をしてると、特定のAPIに対するリクエストとレスポンスを確認したいことって、あると思います。

普通にlogcatを眺めるだけだと、目的外のログもぶわぁーって出てしまって涙目ですよね。

皆どうしてるんですかね？私はこうしてます。(pidcatを利用)

以下、`v1/users/register` というパスを含むリクエストとレスポンスを確認するとします。

### リクエストを確認

##### コマンド
```
pidcat com.sample.package -t OkHttp | awk '/-->.*v1\/users\/register, /--> END/'
```

##### ログ

```
                 OkHttp  D  --> POST https://api.sample.com/v1/users/register http/1.1
                         D  Content-Type: application/json; charset=UTF-8
                         D  Content-Length: 170
                         D  {"user":{"app_version":"2.4.0","device_id":"5a3fe389-da50-4083-a811-24c77093e64b","device_name":"generic_x86","os_type":"Android","os_version":"9"}}
                         D  --> END POST (170-byte body)
```

### レスポンスを確認

##### コマンド
```
pidcat com.sample.package -t OkHttp | awk '/<--.*v1\/users\/register, /<-- END/'
```

##### ログ
```

                         D  <-- 200  https://api.sample.com/v1/users/register (8942ms)
                         D  date: Wed, 05 Feb 2020 00:24:05 GMT
                         D  content-type: application/json; charset=utf-8
                         D  server: nginx
                         D  vary: Accept-Encoding
                         D  cache-control: no-cache
                         D  x-runtime: 0.110749
                         D  x-frame-options: deny
                         D  {"status": 200}
                         D  <-- END HTTP (17-byte body)
```

awkして、該当のログを引っこ抜いているだけなので、特に解説はしません。

細かいツッコミはなしで。。。
AWSCDKでVPCをデプロイする

# はじめに

AWSCDKはTypeScriptやPythonといったプログラミング言語でCloudFormationのテンプレートを生成できるフレームワークです。
今回はAWSCDK(TypeScript)でVPCをデプロイする書き方を紹介していきます。

## 必要なパッケージ

VPC関係の定義は `@aws-cdk/aws-ec2` にあります。

```terminal
$ npm i -D @aws-cdk/aws-ec2
```

## Stackファイルを書く

```ts
import cdk = require("@aws-cdk/core")
import {
  DefaultInstanceTenancy,
  RouterType,
  Vpc,
  Subnet,
  CfnInternetGateway,
  CfnVPCGatewayAttachment
} from "@aws-cdk/aws-ec2"

export class CreateVPCStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props)

    const vpc = new Vpc(this, "cdk-vpc", {
      cidr: "10.0.0.0/16",
      defaultInstanceTenancy: DefaultInstanceTenancy.DEFAULT,
      enableDnsSupport: true,
      enableDnsHostnames: true,
      subnetConfiguration: []
    })

    const pubSubnet = new Subnet(this, "PublicSubnet1c", {
      availabilityZone: "us-west-2c",
      vpcId: vpc.vpcId,
      cidrBlock: "10.0.0.0/24"
    })
    new Subnet(this, "PrivateSubnet1c", {
      availabilityZone: "us-west-2c",
      vpcId: vpc.vpcId,
      cidrBlock: "10.0.1.0/24"
    })
    new Subnet(this, "PrivateSubnet1d", {
      availabilityZone: "us-west-2c",
      vpcId: vpc.vpcId,
      cidrBlock: "10.0.2.0/24"
    })

    const internetGateway = new CfnInternetGateway(this, "InternetGateway", {})
    new CfnVPCGatewayAttachment(this, "gateway", {
      vpcId: vpc.vpcId,
      internetGatewayId: internetGateway.ref
    })

    pubSubnet.addRoute("PubSubnetRoute", {
      routerType: RouterType.GATEWAY,
      routerId: internetGateway.ref
    })
  }
}
```

## Stackファイルの説明

### VPC

各パラメータを渡してVPCを構築します。
`subnetConfiguration` を指定しなければいくつかSubnetが用意されます。
今回はSubnetを自分で構築したいので、 `subnetConfiguration` に `[]` を指定します。

```ts
const vpc = new Vpc(this, "cdk-vpc", {
  cidr: "10.0.0.0/16",
  defaultInstanceTenancy: DefaultInstanceTenancy.DEFAULT,
  enableDnsSupport: true,
  enableDnsHostnames: true,
  subnetConfiguration: []
})
```

### Subnets

ここではPublicのSubnetを一つとPrivateのSubnetを2つ作っています。

```ts
const pubSubnet = new Subnet(this, "PublicSubnet1c", {
  availabilityZone: "us-west-2c",
  vpcId: vpc.vpcId,
  cidrBlock: "10.0.0.0/24"
})
new Subnet(this, "PrivateSubnet1c", {
  availabilityZone: "us-west-2c",
  vpcId: vpc.vpcId,
  cidrBlock: "10.0.1.0/24"
})
new Subnet(this, "PrivateSubnet1d", {
  availabilityZone: "us-west-2c",
  vpcId: vpc.vpcId,
  cidrBlock: "10.0.2.0/24"
})
```

PublicのSubnetに外からアクセスするためのインターフェースを定義します。

```ts
const internetGateway = new CfnInternetGateway(this, "InternetGateway", {})
new CfnVPCGatewayAttachment(this, "gateway", {
  vpcId: vpc.vpcId,
  internetGatewayId: internetGateway.ref
})

pubSubnet.addRoute("PubSubnetRoute", {
  routerType: RouterType.GATEWAY,
  routerId: internetGateway.ref
})
```

## さいごに

これでVPCをCDKでデプロイすることができるようになりました。
次回はこのVPCを利用してRDSのデプロイをしていこうと思います。
ではまた！！！
Retweet is not permissible for this status.

調べても見つからなかったのでメモを残します。

現象：
TwitterAPIにてにリツイート実施時に以下のエラーとなりました。

「Retweet is not permissible for this status.」

原因：
リツイート対象のツイートを書いたユーザが非公開ユーザだったため。

解決方法：
user.protected=trueは非公開ユーザなので、
上記の条件の場合はリツイートしない。

※
また、自分のツイートに対してリツイートしようとした場合にも同様のエラーメッセージが出力される模様。
chromebookのlinux(ベータ版)のdebianを最新版(v10.x buster)にアップグレードする

# はじめに
もともとchromebookでVScodeをインストールしようとしていたが、日本語化にあたって現状のdeibian(v9.x strech)ではパッケーがないfctix-mozcが、最新版（v10.x buster）には存在する事がわかり、これを機に最新化することに。

# 環境
機種：chromebook C101PA
ChromOSのバージョン：79.0

# やったこと
### linux（ベータ版）の有効化
chromebookの設定画面からlinux(ベータ版)の有効化を実施。(詳細割愛）

### 現状のdebianのバージョンを確認＆stretchの最新版へアップデート

以下のコマンドでバージョン確認

```
$ more /etc/debian_version
9.9　　←　現在のdebianのバージョン
```

現状stretch(9.x版)の最新版へアップデート。
※余談ですが`apt-get`コマンドを使用しようと思ったのですが、`apt`コマンドを使うべし！とのサイトが多々有りそれに従いました。

```
$ sudo apt update
$ sudo apt -y upgrade
```

### source.listを最新版へ変更

```
$ sudo apt edit-sources
```

上記コマンド実行するとviが開くので、以下のviコマンドで"stretch"の部分を"buster"に変更&保存

```
:%s/stretch/buster/g
:wq
```

### 最新版にアップグレード

パッケージリストを更新し、アップグレード発動！（apt upgradeコマンド実行後、１時間位かかりました）

※upgradeによって、パッケージが409個最新化、75個新たにインストールされる模様。

```
$ sudo apt update
$ sudo apt upgrade -y
〜　略　〜
409 upgraded, 75 newly installed, 0 to remove and 3 not upgraded.
Need to get 217 MB of archives.
After this operation, 283 MB of additional disk space will be used.
〜　略　〜
$ sudo apt dist-upgrade -y
$ sudo apt autoremove
```

終わったら、バージョンの確認。debian(codenameはbuster)の10.2が適用されているのがわかります。

```
$ more /etc/debian_version
10.2
$ more /etc/os-release
PRETTY_NAME="Debian GNU/Linux 10 (buster)"
NAME="Debian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
```
以上で、完了！

# 終わりに
windows7→10へのアップグレードくらいな労力・時間が必要かと思っていたが、以外と簡単だった。実働時間は１時間ちょっと。事前の調査も30分ほど。困ったエラーも発生せず。
ちなみに、debianは他のディストリビューション同様にメジャーバージョン毎に愛称(codename)があり、次版はbullseyeとのこと。

 - v9.x:stretch
 - v10.x:buster ←　現状の最新の安定版
 - v11.x:bullseye　←　現状のテスト版。つまり将来の安定版


# 参考にした情報

- [debian公式サイト：busterへのアップグレード方法](https://www.debian.org/releases/buster/mips64el/release-notes/ch-upgrading.ja.html)
　とりあえず一通りサラッと読みました。


- [apt-getは、もう古い。aptを使いなさい。](https://zarat.hatenablog.com/entry/2019/03/13/115400)
なぜaptコマンドを使うのかという理由の理解のため
- [「apt-get」はもう古い？新しい「apt」コマンドを使ったUbuntuのパッケージ管理](https://linuxfan.info/package-management-ubuntu)
なぜaptコマンドを使うのかという理由と、aptコマンドの使い方を参考にさせてもらいました。

- [ChromebookのLinux (ベータ版)のDebian 9 (stretch) を 10 (buster) にアップグレード](https://devlights.hatenablog.com/entry/2019/11/08/142211)
　手順を参考にさせてもらいました。
[第1回] 最適化とは？ - 数理最適化を学ぶ勉強資料

#:straight_ruler: はじめに


数理最適化を初めて学ぶ勉強資料の1回目です。
これから各回を通して、数理最適化を学んでいきましょう。

　**数理最適化**

と聞くと、初めて聞くとか、何だか難しそう…と聞こえますが、構えるほどではありません。
「そっかぁ、こんな考え方で、こんなふうに解くんだ～」
それを学んでいきましょう。エンジニアとして新しい知識を学べば、他の分野でもそれを応用でき、メリットがあるに違いありません。
ついでにこれで仕事になれば食い扶ちになるかな!?

#:straight_ruler: 教材

本記事では、数理最適化モデルについて参考テキスト「Pythonによる問題解決シリーズ　データ分析ライブラリーを用いた最適化モデルの作り方」の練習問題などを見ながら進めていきます。テキストの詳細は以下です。

■参考テキスト
「Pythonによる問題解決シリーズ　データ分析ライブラリーを用いた最適化モデルの作り方」
　斉藤努[著] ／ 近代科学社[出版]

![001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399135/9f01c1d8-51ca-2731-4b29-0e452d6754d2.jpeg)


#:straight_ruler: 数理最適化とは？

参考テキストから引用します。最適化とは、以下のような問題を解決するための手段となります。

:one: 自宅の最寄り駅から会社へ行くのに最短時間の経路を知りたい。
:two: リュックサックに入れる商品の価値の合計を最大化したい。
:three: 倉庫から工場へ原料を輸送する費用を最小化したい。

また、最適化と機械学習とは以下の違いがあります。

**機械学習**
　過去を物指しに未来を知る
**最適化**
　モデルを物指しに未来を決める

モデルとは何か?この後はモデルについて解説して参ります。

#:straight_ruler: 最適化モデル

モデルとは、現実問題を数式などに置き換えて何らかの解を算出できる形にしたものです。最短経路を探索する場合は、探索経路を表現する数式を考えモデルとします。また、リュックサックの詰め物問題は、詰めた状態を表す数式を考えモデルとします。

モデルを構築した後、次の作業はソルバーと言われるコンビュータのソフトを使用して解答を得る作業に入ります。

ソルバーには有料のものと無料のものがあります。
ここでは、ソルバーとして無料の**CBC**(Coin Or branch and Cut)を使用します。
また、組み合わせ最適化を解くための専用ライブラリである、Google社が提供している**OR-Tools**を使用します。

このOR-ToolsはPythonで書かれています。
OR-Toolsについては以下をご参照下さい。

■Googleのフリーツール「OR-Tools」
https://developers.google.com/optimization

#:straight_ruler: モデルの構成要素と制約条件

モデルを構築するにあたり、以下の3つの構成要素があります。

①**変数**
　モデル上で様々な値を取り得る数値の入れ物。数式を当てはめる対象となるもの。
②**目的関数**
　良い解を探すための指標。変数を使った数式を用いて関数として表し、その関数が最大か最小となるように計算することで解を求める。
③**制約条件**
　変数の組み合わせや数式としてで守るべき条件。

制約条件は次のいずれかの書き方をします。複数の条件を指定できますが、指定した条件を全て守らなければなりません。
　`数式 ≧ 数式`
　`数式 ＝ 数式`
　`数式 ≦ 数式`
※ここで、≠ ＜ ＞ は使用できません。

モデルは数式を使って表現するので数理モデルと呼ばれます。
また、厳密に数式だけでモデルを表現することを定式化する、といいます。


#:straight_ruler: 最適化の種類

最適化問題には以下の3種類があります。

![001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399135/773101c2-a5f3-7c85-197b-de1c763a4b0c.jpeg)

:one: 線形最適化問題
　(LP：Linear programming Problem)
　連続変数しか使用できない。目的関数と制約条件は線形の式でなければならない。問題は簡単に解ける。制約条件の数が数千の問題でも解かれている。
:two: 混合整数最適化問題
　(MIP：Mixed Integer programming Problem)
　連続変数と離散変数が使用できる。目的関数と制約条件は線形の式でなければならない。基本的には簡単に解けない。変数や制約条件の数が少なければ解きやすい。
:three: 一般の最適化問題
　変数、目的関数、制約条件に制限が無い。研究では非線形最適化問題(NLP：Non-Linear programming Problem)という分類で扱われている。解くのは場合によっては解けるが、基本的には難しい。

※連続変数とは、実数値を取る変数です。一方、離散変数とは、整数のようにとびとびの値だけを取れる変数です。

#:straight_ruler: 終わりに

次回は第2回目、典型問題についての予定です。お読み頂けたら幸いです。

当記事については、著者も最適化の入門者です。誤解・誤植等至る所にあると思いますので、お気軽にご意見やご指摘などお寄せ下さい。