OmniAICreator/Qiita-1.07M huggingface dataset:
Jiraチケット画面にカスタムフィールドを追加するときに考えている5つのポイント

# はじめに
Jiraはチケットの項目の追加・削除、ワークフローの編集などのカスタマイズが柔軟にでき、様々な業務で活用することができます。

本稿では、カスタマイズをするにあたって、主に私の経験から、考慮したほうがよいだろう内容を紹介したいと思います。


# カスタムフィールド追加時の考慮

### １．カスタムフィールドを追加する前に、Jiraのシステムフィールドが利用できないか検討する
#### フィールドの種類
Jiraで使えるフィールドには、大きく２種類あります。
・システムフィールド
・カスタムフィールド

システムフィールドは、Jiraに元々用意されているフィールドです。
カスタムフィールドは、Jira管理者が追加できるフィールドです。

#### システムフィールドの例：説明フィールド
例えば、説明フィールドには、チケットの情報を表示する際にいくつか特徴的な機能があります
 - フィールドを複数のタブに分けて表示する際にも、どのタブを開いているときにも説明の内容は表示されます。
 - カンバンボード、スクラムボードの課題詳細ビューにおいて、説明は必ず表示されます。また、説明の箇所に移動するボタンもあります。

他にも、システムフィールドを活用するメリットに、Appsでも動作が（たいていは）サポートされることがあります。
例えば、WBSガントチャートのテンプレート機能では、Jiraのシステムフィールドはテンプレートから情報が継承されますが、カスタムフィールドは継承されません。

「説明」という名前が使いづらいという声もあるかも知れませんが、慣れれば違和感無くなっていくものなので、このフィールドは可能な限り活用されることをオススメします。

#### システムフィールドにはどんなものがあるか
代表的なシステムフィールドは、下記のようなものが挙げられます。
・要約
・説明
・担当者
・報告者
・期限
・優先度

システムフィールドかどうかは、管理者メニュー＞課題＞画面で、Typeを見ることで判別できます。


### ２．必須／オプションの設定の要否
フィールドには、入力必須の設定ができます。必須設定されたフィールドが未入力の場合、チケットを作成することができません。
チケット作成時に必ず入力させたい情報が決まっている場合は、カスタムフィールドを用意して、必須の設定にするのが良いでしょう。

ただし、入力必須のフィールドが多いと、チケット作成のハードルが高くなります。
作成時に必要な情報を見極めて設定することをオススメします。


### ３．選択肢の設定
カスタムフィールドのうち一部のフィールドタイプでは、選択肢を設定できます。
チェックボックス／ラジオボタン／選択リスト（単一選択）／選択リスト（複数選択）／選択リスト（カスケード）が該当します。

リストから選択する情報が決まっている場合は、上記のカスタムフィールドを追加するのが良いです。


### ４．レポートで活かせるように設計する
Jiraのチケットは、記録した情報をリアルタイムにレポート出力できる特徴があります。
レポートには、表形式だけでなく、円グラフ・棒グラフ・折れ線グラフ・２次元マトリクスなど、様々な形式があります。

是非とも、最適な分析ができるレポートを出力することもあわせて追加するフィールドを考えてみてください。


### ５．Jiraの機能を活用することで不要なフィールドを作らない
Excel管理表などをJiraチケットに移行するケースでは、チケットの操作で自動的に記録できるような情報も項目として用意されているケースがあるので、注意が必要です。

例えば、課題の解決日などは、チケットのクローズ時に自動で設定させることができます。
それをわざわざフィールドとして持たせる意味があるのか、検討するほうがよいでしょう。

チケット操作の履歴も記録されます。
とある情報の更新者を記録すべく、Excel表では更新者などの項目で持っていることもあるかもしれません。
Jiraに移行するにあたって、分析で必要ならばフィールドとして持たせる意味はありますが、何かあった時の調査が目的であるのならば、チケットの操作履歴で代用できます。（むしろその方がウソをつけませんしね）


# おわりに
Jiraの管理者には、Jiraのシステム面の知識だけでなく、対象の業務やそこでの人の動き方への理解も求められると感じています。
管理者の視点だけでなく利用者の視点も持って、最適なチケット設計、ひいては業務設計ができるようになりたいですね。
【JavaScript】React:条件付きレンダーって？

https://ja.reactjs.org/docs/conditional-rendering.html
こちらを元に学習しています。


#レンダーの条件分岐やってみよう
```react
function UserGreeting(props) {
  return <h1>Welcome back!</h1>;
}

function GuestGreeting(props) {
  return <h1>Please sign up.</h1>;
}
```

この２つのコンポーネントを、以下のコードを加えてログイン状況によって一方だけ表示したいとします。

```react
function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {
    return <UserGreeting />;
  }
  return <GuestGreeting />;
}

ReactDOM.render(
  // falseをtrueにかえると表示が変わる。
  <Greeting isLoggedIn={true} />,
  document.querySelector('body')
);
```

constで宣言した`isLoggedIn`にpropsが代入されています。
それを元に条件分岐ですね。reactの良さが出てきた気がします。

上記の例ではpropsを利用したファンクションコンポーネントの場合だったので、
次はクラスで作成されたステート付きコンポーネントで条件分岐してみます。
先ほどのコードの続きから書いてください。

```react
function LoginButton(props) {
  return (
    <button onClick={props.onClick}>
      Login
    </button>
  );
}

function LogoutButton(props) {
  return (
    <button onClick={props.onClick}>
      Logout
    </button>
  );
}
```

UseGreetingなどのコンポーネントと似ていますが、
イベントハンドラが設定されていて、propsによってその条件が分岐するようです。

そして以下のコードを追加します。

```react
class LoginControl extends React.Component {
  constructor(props) {
    super(props);
    this.handleLoginClick = this.handleLoginClick.bind(this);
    this.handleLogoutClick = this.handleLogoutClick.bind(this);
    this.state = {isLoggedIn: false};
  }

  handleLoginClick() {
    this.setState({isLoggedIn: true});
  }

  handleLogoutClick() {
    this.setState({isLoggedIn: false});
  }

  render() {
    const isLoggedIn = this.state.isLoggedIn;
    let button;

    if (isLoggedIn) {
      button = <LogoutButton onClick={this.handleLogoutClick} />;
    } else {
      button = <LoginButton onClick={this.handleLoginClick} />;
    }

    return (
      <div>
        <Greeting isLoggedIn={isLoggedIn} />
        {button}
      </div>
    );
  }
}

ReactDOM.render(
  <LoginControl />,
  document.getElementById('root')
);
```

先ほどのGreetinコンポーネントもトグルさせています。
条件分岐はできましたが、なかなか長いコードになりましたね。

##もっと色々な条件分岐
###&&を使う

```react
function Mailbox(props) {
  const unreadMessages = props.unreadMessages;
  return (
    <div>
      <h1>Hello!</h1>
      {unreadMessages.length > 0 &&
        <h2>
          You have {unreadMessages.length} unread messages.
        </h2>
      }
    </div>
  );
}

const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
  <Mailbox unreadMessages={messages} />,
  document.getElementById('root')
);
```

これは`&&`を使ったよくあるテクニックですね。&&の左の式が間違っていれば右の式は実行されないというやつです。
lengthがfalseではない→メッセージがある時のみ右の式が実行されて、条件分岐が成功しています。

###三項演算子を使う

```react
render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
    </div>
  );
}
```

isLoggedInがtrueならcurrentlyを、そうでなければnotを返します。
三項演算子は嫌われますが私は好きです。用量を守って利用したいですね。

##コンポーネントをレンダーさせない
レンダーさせたくないときは、出力に`null`でオッケーです。

```react
  if (!props.warn) {
    return null;
  }
```

ただし、コンポーネントのライフサイクルはnullにしても発火するので注意です！
Excelのカラム幅がマシンによって変わってしまう！

最近、帳票出力システムを改修しているときに「んん？？？」となって、
調査に意外と時間がかかってしまいました。

備忘ついでに記事にしておきます。
Windows10での事象です。

## 事象
持込の開発PCで単体テストを実施して、出力されたExcelファイルをエビデンスとしてアップ。
客先PCで取得して、Excelファイルを開くと・・・
カラム幅 **4** で設定していたカラムが
なぜか **33.89** になっていました。

他のカラムも全部微妙にずれている。

## 原因
Windowsのディスプレイ設定で表示スケールが変更されている場合にずれるようです。

>Windows 10 では、モニターの画素密度（ppi）に合った推奨サイズ（拡大率）が自動で設定されます

とのことで、
設定＞システム＞ディスプレイ＞拡大縮小とレイアウト で拡大率を確認してみると

開発PCは**100%**、
客先PC（FullHD 13インチ）は**125%**が自動で設定されていました。

## まとめ
開発PCを拡大率125%に変更して出力し、客先PCで確認すると
カラム幅4で表示されました！
拡大率をどちらかを合わせるのがいいと思います。

参考になったら幸いです。
【ESlint】JavaScriptとTypeScriptが混同しているプロジェクトの.tsxファイルで、ESlintルールの "react/prop-types" を無効にする方法

JavaScriptとTypeScriptが混ざっているプロジェクトなどで、JavaScriptファイル（.js）では `eslint` の `"react/prop-types"` を有効にしたいけど、TypeScriptファイル(.tsx)では無効にしたい場合がある。

# 方法
`eslint` の設定が記述してある `eslintrc.js` などで `tsx` ファイルの時は `"react/prop-types"` を無効にしてあげるように設定する。

```eslint.js
{
    "plugins": ["a-plugin"],
    "overrides": [
        {
            "files": ["**/*.tsx"],
            "rules": {
                "react/prop-types": "off"
            }
        }
    ]
}
```

`overrides` でルールを上書きでき、 `files` でグロブパターンでファイルを指定することができる。
これで `tsx` ファイルでは `"react/prop-types"` の警告がされないようになる。

# 参考
- [Support or ignore prop-types in mixed JS/TypeScript projects](https://github.com/yannickcr/eslint-plugin-react/issues/1461)
- [Configuring ESLint: specifying-processor](https://eslint.org/docs/user-guide/configuring#specifying-processor)
yarn で http server を立てる

## yarn のインストール
https://yarnpkg.com/lang/ja/docs/install

## package.json を作成

```shell
yarn init
```

実行すると, いくつかの項目を入力を促されますが, 特に変更する必要がなければ Enter を押しましょう

## http-serverを追加

```shell
yarn add http-server
```

## package.json を編集

script から実行できるよう, package.json に以下を追記しましょう。

```json
 "scripts": {
    "start": "http-server"
  }
```
index.html を main として立ち上がる package.json は以下のようになります。

```json
{
  "name": "******",
  "version": "1.0.0",
  "main": "index.html",
  "repository": "******.git",
  "author": "******",
  "license": "MIT",
  "scripts": {
    "start": "http-server"
  },
  "dependencies": {
    "http-server": "^0.11.1"
  }
}
```

## yarn を実行

```shell
yarn run start
```

これで, http://localhost:8080 にアクセスすると, `index.html` が表示されると思います。
Apex Triggerの一括処理検証（200件以上）

#結論
・insert / update の場合、200件ごとにトリガーを実行する
・delete / undelete の場合、全件でトリガーを実行する
・DML単位で before、after の順でイベントを処理する

#====== 検証 ======
###1.トリガー作成
```java

trigger XXXXXXTrigger on XXXXXX__c  (before insert, before update, before delete, after insert, after update, after delete, after undelete) {
	if (Trigger.Isbefore && Trigger.Isinsert) {
	    system.debug('before insert:' + Trigger.size);
	}
	
	if (Trigger.Isafter && Trigger.Isinsert) {
	    system.debug('after insert:' + Trigger.size);
	}
	
	if (Trigger.Isbefore && Trigger.Isupdate) {
	    system.debug('before update:' + Trigger.size);
	}
	
	if (Trigger.Isafter && Trigger.Isupdate) {
	    system.debug('after update:' + Trigger.size);
	}
	
	if (Trigger.Isbefore && Trigger.Isdelete) {
	    system.debug('before delete:' + Trigger.size);
	}
	
	if (Trigger.Isafter && Trigger.Isdelete) {
	    system.debug('after delete:' + Trigger.size);
	}
	
	if (Trigger.Isafter && Trigger.Isundelete) {
	    system.debug('after undelete:' + Trigger.size);
	}
}
```

###2.executeAnonymous　で下記のコードを実行する
```java

Savepoint sp = Database.setSavepoint();

System.debug('Insert　処理');
List<XXXXXX__c> xxList = new  List<XXXXXX__c>();
for (Integer i=0;i<1000;i++) {
    xxList.add(new XXXXXX__c());
}
insert xxList;

System.debug('update　処理');
update xxList;

System.debug('delete　処理');
delete xxList;

System.debug('undelete　処理');
undelete xxList;

Database.rollback(sp);
```

###3.出力ログ一覧
16:27:04:003 USER_DEBUG [3]|DEBUG|Insert　処理
16:27:04:106 USER_DEBUG [3]|DEBUG|before insert:200
16:27:04:652 USER_DEBUG [7]|DEBUG|after insert:200
16:27:11:213 USER_DEBUG [3]|DEBUG|before insert:200
16:27:11:880 USER_DEBUG [7]|DEBUG|after insert:200
16:27:18:322 USER_DEBUG [3]|DEBUG|before insert:200
16:27:18:962 USER_DEBUG [7]|DEBUG|after insert:200
16:27:25:083 USER_DEBUG [3]|DEBUG|before insert:200
16:27:25:780 USER_DEBUG [7]|DEBUG|after insert:200
16:27:31:773 USER_DEBUG [3]|DEBUG|before insert:200
16:27:32:405 USER_DEBUG [7]|DEBUG|after insert:200
16:27:39:166 USER_DEBUG [10]|DEBUG|update　処理
16:27:40:681 USER_DEBUG [11]|DEBUG|before update:200
16:27:41:145 USER_DEBUG [15]|DEBUG|after update:200
16:27:42:493 USER_DEBUG [11]|DEBUG|before update:200
16:27:42:950 USER_DEBUG [15]|DEBUG|after update:200
16:27:44:229 USER_DEBUG [11]|DEBUG|before update:200
16:27:44:711 USER_DEBUG [15]|DEBUG|after update:200
16:27:46:549 USER_DEBUG [11]|DEBUG|before update:200
16:27:47:029 USER_DEBUG [15]|DEBUG|after update:200
16:27:48:448 USER_DEBUG [11]|DEBUG|before update:200
16:27:48:942 USER_DEBUG [15]|DEBUG|after update:200
16:27:48:962 USER_DEBUG [13]|DEBUG|delete　処理
16:27:49:462 USER_DEBUG [19]|DEBUG|before delete:1000
16:27:55:448 USER_DEBUG [23]|DEBUG|after delete:1000
16:27:55:476 USER_DEBUG [16]|DEBUG|undelete　処理
16:28:13:820 USER_DEBUG [27]|DEBUG|after undelete:1000
【Airflow on Kubernetes】目次

## 関連記事
- [Kubernetesハンズオン目次](https://qiita.com/Esfahan/items/4fcf51622fed20dffb88)

## 初期設定など
- [DockerイメージのbuildとPodのdeployの仕組みについて](https://qiita.com/Esfahan/items/bf0ae4dbd637ebb0be76)
- [メタデータDBをデフォルトのPostgreSQLからMySQLに変更する](https://qiita.com/Esfahan/items/68da6ba314aca2c21f73)

## DAGを実行する
- [DAGを実行したときのPodの挙動](https://qiita.com/Esfahan/items/e533c357d31cccde97cd)
- [KubernetesPodOperatorの使い方](https://qiita.com/Esfahan/items/c05e108f8f6828da3086)
- [JdbcOperatorの使い方](https://qiita.com/Esfahan/items/bd1f8f342bc7a9dec181)
- [DAGを指定したDockerコンテナで実行する](https://qiita.com/Esfahan/items/e8aebae75b6852afd67e)

## トラブルシューティング
- [トラブルシューティング - k8sにDeployするとImportError: No module named json](https://qiita.com/Esfahan/items/acdb02bd294fd5332aed)
- [トラブルシューティング - WEB UIの/staticディレクトリが500 Internal Server Error](https://qiita.com/Esfahan/items/472a314b714547f4570a)
- [トラブルシューティング - AttributeError: '_jpype.PyJPField' object has no attribute 'getStaticAttribute'](https://qiita.com/Esfahan/items/9d3eaee4e8eb2b4e83f2)

随時追加して行きます。
ABS箱PLCの光学ディバイダーの特徴

PLC スプリッタは、PLC 平面導波路型光スプリッタであり、光スプリッタはファイバリンクにおいて最も重要な受動部品の１つである。 PLC スプリッタは半導体プロセスを使用して製造され、中央局（ＣＯ）から複数のエンドユーザの場所に光信号を分配するための石英基板に基づく集積導波路光パワー分配装置である。 シングル/ダブル光入力を複数の光出力に均等に分割し、光信号をユーザに均等に分配することができますシャントチャネルは通常2チャネル、4チャネル、8チャネルを持ち、32チャネル以上に達することができます。 1×Nまたは2×N。

ABS箱はPLCのディバイダーの包装方法の1つです。 ＡＢＳボックス型の他に、ラック型、ベアライン型、プラグ型、トレイ型などにも分類される。 ABS PLCスプリッタは、PONネットワークで最も一般的に使用されているスプリッタで、次のような特徴があります。

コンパクトで柔軟な設置
ABSボックスの光スプリッタは、内部の光学部品やケーブルをしっかり保護し、設計が簡単で、設置が確実です。 信頼性の高い保護を提供することに加えて、ABSボックスPLCオプティカルスプリッタはさまざまなワイヤリングクローゼットまたはエンクロージャに設置することもできます。 入力ファイバおよび出力ファイバは、石英基板で作られた光導波路の層においてコンパクトでコンパクトであり、それはより容易でより柔軟な配線を提供することができ、そして様々な既存の接続箱に直接設置することができる。 設置スペースを広く取ってください。

均一な配光、優れた安定性
損失は透過光の波長の影響を受けず、挿入損失は低く、分割は均一です。 32チャンネル以上に達することができる多くのシングルチャンネルシャントチャンネルがあります。 Yiyuantong HYC PLCスプリッタは、優れた光学性能、高い安定性、および高い信頼性を備えており、さまざまな環境でさまざまなアプリケーション要件を満たすことができます。 各スプリッタは厳密にGR-1209、GR-1221規格に準拠しており、高い信頼性を保証します。

幅広い用途
ABSボックスタイプのPLC光スプリッタを標準の19インチラックユニットに取り付けるのが一般的です。 ファイバブランチが家に置かれるとき、それはケーブル転送ボックスに設置することができます。 FTTHシステム、受動光ネットワーク、およびケーブルテレビネットワークに適用できます。

![PLC-4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463940/f117a4ce-65e8-42a9-9c65-542b6a7827c8.jpeg)

HYC は光通信受動基本部品の研究開発、製造、販売およびサービスを専門とする国家ハイテク企業です。 同社の主力製品は、光ファイバコネクタ（データセンター高密度光コネクタ）、波長分割マルチプレクサ、光スプリッタ、およびその他の3コア光パッシブインフラストラクチャデバイスで、家庭用光ファイバ、4Gモバイル通信で広く使用されています。 インターネットデータセンター、防衛通信、その他の分野. http://www.hyc-system.com
Gitのブランチ削除で&などの記号が認識されない！の対処

## 起こり: 「ブランチが消せない！？」
VScodeでGitのブランチを作成できるので
調子に乗って記号を使ったブランチを作って見ると作成できてしまった。  

ブランチ名`xxx_A&B`  

ターミナルでブランチを消してみようとすると…

```
$ git branch --delete xxx_A&B
[1] 4596
-bash: B: command not found
MBP:app user_name.projects$ error: branch 'xxx_A' not found.
c
[1]+  Exit 1                  git branch --delete xxx_A
```

消えない！？！？！？

## 記号はエスケープする
記号だからエスケープしないと別の認識をされているのでは？？

```
$ git branch --delete xxx_A\&B
Deleted branch xxx_A&B
```

消せた！！

`\記号`でエスケープすればよかったのか！！  

ふははははははｈ！！
恥ずかしい…
nginxで特定のURLを知っている人のみアクセスできるWebページをCookieを使って実現する

# これはなに
Webの開発環境などパブリックにしたくないWebサイトを
特定の他者に公開したいときや、もしくは自分のモバイル端末などで確認したいときがあります。
そういう場合に、Cookieに秘匿情報を設定することで突破することができます。

ここで、リテラシーの問題やスマホブラウザなど機能的にCookieに値を設定するのが困難な場合があります。
そこで特定のURLのみ公開し、そのURLでCookieをセットします。

# この設定が生きる場面
- SPAなどで**authorizationヘッダを使っているためBasic認証が使えない**
- コワーキングスペースなど公共の場所からアクセスしたいのでIPアドレスでの制限が使えない
- Cookieが容易に変更できないスマホブラウザなどに対応したい

# 設定部分
```nginx

    location = /hogehogehoge {
       add_header Set-Cookie "secret=fugafugafuga";
       return 302 https://$host;
    }

    location / {
        set $interrupt true;

        if ( $cookie_secret = "fugafugafuga" ) {
            set $interrupt false;
        }

        # if ( $geo_office ) {
        #     set $interrupt false;
        # }

        if ( $interrupt = true ) {
            return 403;
        }

        proxy_pass                  http://backend;
    }
```

# 解説

`location = /hogehogehoge`が、秘匿情報をセットするURLになります。
適当な文字を設定しましょう。

cookie `secret`の値に`fugafugafuga`が入り、トップ画面にリダイレクトされます。

`location /`では、条件に基づいて`$interrupt`変数が変更され、
最終的に403を返すかどうかを判定します。

前述したcookie`secret`の値で判断することや、`geo`を使ってIPアドレスで許可することもできます。
UbuntuにNginxをインストールする

# Ubuntuのパッケージを使用する場合
```
$ sudo apt install -y nginx
```
簡単だがnginxのバージョンが少し古い

# Nginxのパッケージを使用する場合
```
# NGINXリポジトリを信頼するための認証キーのダウンロード
$ wget https://nginx.org/keys/nginx_signing.key

# 認証キーのインポート
$ apt-key add nginx_signing.key
  ↑ エラーになる場合は以下のパッケージをインストール
  $ apt install -y gnupg

# 公式リポジトリの URL を Ubuntu に登録
$ vi /etc/apt/sources.list

以下を追記
deb http://nginx.org/packages/ubuntu/ bionic nginx
deb-src http://nginx.org/packages/ubuntu/ bionic nginx

# 設定変更を反映
$ apt update

# インストール
$ apt install -y nginx
```

最新のバージョンをインストールできる
【JavaScript修行】React:イベント処理について

https://ja.reactjs.org/docs/handling-events.html
今日は上記のドキュメントの読み解き作業の覚書になります。

##Reactのイベント処理って？
→DOM要素のイベント処理とそっくり！
ただ異なる文法もある。

```html
<button onclick="event()">
 イベントボタン
</button>
```

Reactだとこのようになる。

```react
<button onclick={event}>
 イベントボタン
</button>
```

 - イベント名をキャメルケースでかく
 - イベントハンドラは文字列ではなく関数を渡す
 
上記２点がJSXとHTMLで異なっている。

##preventDefault()したい時

```react
function ActionLink() {
  function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
  }
  return (
    <a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}

ReactDOM.render(
 <ActionLink />,
  document.querySelector('body')
)
```

ReactではDOM生成後ではなく、
最初にレンダリングされる際に`addEventListener`を呼び出す。

上記はファンクションのコンポーネントでのイベントハンドラ。
クラスでのイベントハンドラはクラスのメソッドになる。
以下の通り。

```javascript
class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    this.handleClick = this.handleClick.bind(this); //注目
  }

  handleClick() {
    this.setState(state => ({
      isToggleOn: !state.isToggleOn //stateをトグル
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

ReactDOM.render(
  <Toggle />,
  document.querySelector('root')
);
```

`this`に注意します。
render部分で書かれている`this.handleClick`の`this`は関数外なのでバインドされていません。
なのでbindしておく必要があります。
→　[bindの学習記録。](https://qiita.com/irico/items/9454622e2f010189df17)

render()で書き出しているボタンには、onclickのイベントハンドラがあり、`this.handleClick`によってstateがトグルされ、それを感知し再描画されます。
その際インナーテキストがトグルの変数によって変わります。

bindが面倒な場合、回避法が２つある。
①パブリッククラスフィールド構文を使う（なんだそれ）
※Stage 3 Proposalらしい。

```javascript
class LoggingButton extends React.Component {
  // 注意: これは実験的な構文になります。
  handleClick = () => {
    console.log('this is:', this);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }
}
```

なんだか不思議な構文です。`()`を無理やりつけたという感じです。詳細求む。
Create React Appではデフォルトで使える構文のようです。

②アロー関数の使用

```javascript

class LoggingButton extends React.Component {
  handleClick() {
    console.log('this is:', this);
  }

  render() {
    return (
      <button onClick={(e) => this.handleClick(e)}>
        Click me
      </button>
    );
  }
}
```

thisには上記の対策をとって倒しましょう！
pythonで画像収集プログラムを書いてみた　２日目　画像の加工

#今回の目標
今回は前回作った、画像収集プログラムに関連して、自動で画像の整形をするプログラムを作ってみたいと思います。画像の整形の内容は、
・縮小拡大
・トリミング
の二つです。この二つを使って、画像収集プログラムで手に入れた画像を、任意の形に自動で加工させることが今回の目標です。画像の加工に使うライブラリはopencvとNumpyです。

#PCスペック
MacBook Air (Retina, 13-inch, 2018)
プロセッサ　1.6 GHz Intel Core i5
メモリ　8 GB 2133 MHz LPDDR3

#opencvのインストール
ターミナルで pip install opencv-python でいけました。

#opencvについて勉強
opencvは画像処理のためのライブラリで、他にも画像処理ができるライブラリとしてPillowなどがあります。今回は簡単な加工のみですので、使うのはどちらでもそんなに違いはないようです。

##画像の読み込みと表示、保存
画像の読み込みにはimread、表示にはimshowというメソッドを用います。

```python

#opencvのインポート
import cv2
import numpy

img=cv2.imread("画像へのパス")
#グレースケールでの読み込み
img2=cv2.imread("画像へのパス",0)

#画像の表示
cv2.show("ウィンドウ名",img)
cv2.waitKey(0)
cv2.destroyAllWindows()

#画像の保存
cv2.imwrite("ファイル名",img)

```
＊imshowメソッドの後ろにwaitKeyとdestroyAllWindowsがないと画像が表示されませんでした。

##画像の加工
opencvでは読み込んだ画像はNumpy配列として操作できるようです。画像の加工の流れですが、

①形が崩れないように拡大縮小して目標のサイズと横幅か縦幅が同じになるようにします。
②トリミングして中央が残るように切り出します。

拡大縮小にはresizeメソッドを利用します。

```python
#img:加工する画像
#width,height:加工後の画像の縦横の長さ

def image_processing(img,height,width):
    #画像の縦、横を取得
    img_height,img_width,ch=img.shape
    #画像の拡大縮小比率を求める
    ratio=max(height/img_height,width/img_width)
    #拡大後の画像の縦横
    img_height_after=math.ceil(img_height*ratio)
    img_width_after=math.ceil(img_width*ratio)
    #画像の拡大縮小
    img_scaled=cv2.resize(img,(img_width_after,img_height_after))

    #画像の左上の座標
    end_height=int((img_height_after/2)-(height/2))
    end_width=int((img_width_after/2)-(width/2))

    #画像のトリミング
    img_processed=img_scaled[end_heigh:end_height+height+1,end_width:end_width+width+1]
    return img_processed
```

#完成したコード
これらをコマンド引数から使用できるようにしたものが下のコードです

```python
"""
入力：加工する画像のパス、縦、横
出力：画像ファイル
"""
import cv2
import numpy
import math
from sys import argv

def image_processing(img,height,width):
    height,width=map(int,(height,width))
    #画像の縦、横を取得
    img_height,img_width,ch=img.shape
    #画像の拡大縮小比率を求める
    ratio=max(height/img_height,width/img_width)
    #拡大後の画像の縦横
    img_height_after=math.ceil(img_height*ratio)
    img_width_after=math.ceil(img_width*ratio)
    #画像の拡大縮小
    img_scaled=cv2.resize(img,(img_width_after,img_height_after))

    #画像の左上の座標
    end_height=int((img_height_after/2)-(height/2))
    end_width=int((img_width_after/2)-(width/2))

    #画像のトリミング
    img_processed=img_scaled[end_height:end_height+height+1,end_width:end_width+width+1]
    return img_processed

if __name__=="__main__":
    path,height,width=argv[1:]
    #画像ファイルの取得
    img=cv2.imread(path)
    print(type(img),path)
    #画像の加工
    img_processed=image_processing(img,height,width)
    #画像の保存
    cv2.imwrite("image_output.jpg",img_processed)

```

#感想
今回載せているプログラムはパスの画像を加工するようにしていますが、ディレクトリの操作を加えるだけで、ディレクトリ内の画像すべてを加工するようにできます。今回Pillowではなくopencvを使ったのは、opencvでは顔の検出ができるみたいで、組み合わせれば顔の画像だけを保存していくことも可能ではないか？と思ったからです。次回は、opencvによる顔の検出、またはスクレイピングの工夫について勉強のメモを投稿したいと思います。
Amazon Kinesis Stream から　AWS CLI を持ち出でレコードを取得する

ストリームへきちんとレコードを送信できているか確認したくなった時のために、覚書程度にCLIの書き方を残しておきます

また初めてkinesis系を利用しましたが、下記のチュートリアルが非常にわかりやすかったです。
[リアルタイムデータ処理を行うサーバーレスアプリケーションを構築する](https://aws.amazon.com/jp/getting-started/projects/build-serverless-real-time-data-processing-app-lambda-kinesis-s3-dynamodb-cognito-athena/2/)
[AWS CLIを使って初めてAmazon Kinesisを使ってみた](https://qiita.com/toshihirock/items/86a7d5144ad54b18bf36)を参考にさせていただきました。

```
# aws kinesis list-streams
{
    "StreamNames": [
        "wildrydes",
        "wildrydes-summary"
    ]
}
```

```
# aws kinesis describe-stream --stream-name wildrydes-summary
{
    "StreamDescription": {
        "KeyId": null,
        "EncryptionType": "NONE",
        "StreamStatus": "ACTIVE",
        "StreamName": "wildrydes-summary",
        "Shards": [
            {
                "ShardId": "shardId-000000000000",
                "HashKeyRange": {
                    "EndingHashKey": "340282366920938463463374607431768211455",
                    "StartingHashKey": "0"
                },
                "SequenceNumberRange": {
                    "StartingSequenceNumber": "49598050274027636832164871047437518224631163117463666690"
                }
            }
        ],
        "StreamARN": "arn:aws:kinesis:us-east-1:986846499074:stream/wildrydes-summary",
        "EnhancedMonitoring": [
            {
                "ShardLevelMetrics": []
            }
        ],
        "StreamCreationTimestamp": 1564389896.0,
        "RetentionPeriodHours": 24
    }
}

```

```
# aws kinesis get-shard-iterator --shard-id shardId-000000000000 --shard-iterator-type TRIM_HORIZON --stream-name wildrydes-summary
{
    "ShardIterator": "AAAAAAAAAAEgynDQ5e7GAzU5jCnxKWfiky7pZ2vuY7kV6AWLp6G23jZPsbCJNs118xC0rb20Jkjh+0uu23PAx7bq5yQVJc9Dv9Uwmmv6q17xDMPuiSdxBkloj6RpRuoO2UjCXb5nq0Uac2KHE7o+QKFv3FN4p60bUYg2AQ2yeVMAXyh2boF8aOyCqbL9ktzP6TB/LA1lzGRIUxtvgWx8fExRiPRlKffP"
}
```

```
aws kinesis get-records --shard-iterator AAAAAAAAAAHFu1JR4Gj7k6UgHJs1tZMWGRtwvgjGPolNk+Eh1GI72dXHKrtxUMD+lR21FII4MXB0JecCkarh3tewMAh+Tw/tPVfhnYoppSR8pyfzgtaWBGovVKwv12cli63Ixf3M1oiRuRQ0fFjJzfxumtXbPNVij67JntAjLt98j7AG6tC7PNOrME0cvkyN5Y2D5nNbbVFT6bkRr+pOOzm7nwT8NtB7OD/kfivMOz3DcbGGLccwaw== | jq '.Records[].Data' -r | base64 -d
```
【Vue】axiosで、デフォルトでCSRFトークンを設定できるようにする

VueとRailsで開発していると, axiosでPOSTリクエスト等を送ったときに以下のエラーが出るかと思います。

```
422 (Unprocessable Entity)
```
csrfトークン対策しなければならないのですが、エラーを防ぐ方法はいくつかあります。

Railsの場合は、`protect_from_forgery`をコメントアウトすれば解決します。



```app/controllers/application_controller.rb 
class ApplicationController < ActionController::Base
  # protect_from_forgery with: :exception ← コメントアウトする
end
```
手っ取り早い対処法ですが、CSRF対策を無効にしてしまうため、根本的な解決策になりません。


CSRF対策するためには、ヘッダーにトークンを含める必要があります。

```js
import axios from 'axios'

axios.defaults.headers.common = {
    'X-Requested-With': 'XMLHttpRequest',
    'X-CSRF-TOKEN' : document.querySelector('meta[name="csrf-token"]').getAttribute('content')
};
```

これでも良いのですが、これを毎回axiosを記述するたびに定義するのは面倒で増えるたびに見通しが悪くなります。
なので、この`csrf-token`が自動でリクエストヘッダーに入るようにしてみました。

##プラグインを作る
適当に`plugins`フォルダを作って、以下ののように記述します。

```app/javascript/packs/plugins/vue-axios.js
const VueAxiosPlugin = {}
export default VueAxiosPlugin.install = function(Vue, { axios }) {
  const csrf_token = document.querySelector('meta[name="csrf-token"]').getAttribute('content')
  axios.defaults.headers.common = {
    "X-Requested-With": "XMLHttpRequest",
    "X-CSRF-Token": csrf_token
  }

  Vue.axios = axios
  Object.defineProperties(Vue.prototype, {
    axios: {
      get () {
        return axios
      }
    }
  })
}
```
ここで`csrf-token`を設定してます。

後はこのプラグインをエントリーファイルに`import`すれば、
`Vue.use`のタイミングで`VueAxiosPlugin.install`が呼び出されるようになります。

```index.js

import Vue from "vue/dist/vue.esm";
import axios from "axios"; // 追加
import VueAxiosPlugin from "./plugins/vue-axios";  // 追加
import App from "./components/App.vue";

Vue.use(VueAxiosPlugin, { axios: axios }) // 追加

new Vue({
  el: "#app",
  render: h => h(App),
})
```

`Vue.use(VueAxiosPlugin, { axios: axios })`では`import`してきた`axios`を引数に渡してるので`import axios from "axios";`を忘れないようにしましょう。

[公式参考](https://jp.vuejs.org/v2/guide/plugins.html#%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E3%81%AE%E8%A8%98%E8%BF%B0)

##axios実行ファイル

```js
export default {
  methods: {
    postComment () {
      const params = { 
        comment: {
          email: "テストコメント",
        }
      }
      axios.post("users/sign_in", params)
        .then(res => {
          console.log(res)
        })
    }
  }
}
```

Vueインスタンスが作られるタイミングでaxiosが設定されてるため、
いちいちヘッダーに`csrfトークン`を含める必要もありません。

これでだいぶスッキリしましたね。

参考: https://tech.medpeer.co.jp/entry/2018/02/26/080000
マイグレーションファイルに重複カラムを書いてしまった時の挙動(rails5とrails6の違い)

下記のようなマイグレーションファイルを作成しました。
実行したらどうなるでしょうか？
環境：Rails 5.2.3, mysql 8.0.16

```ruby:db/migrate/20190731062120_hoge.rb
class Hoge < ActiveRecord::Migration[5.2]
  def change
    create_table :hoges do |t|
      # nameが重複しているぞ！！！
      t.string :name
      t.string :name
    end
  end
end
```
あれ、成功した？！

```ruby
# bundle exec rake db:migrate
== 20190731062120 Hoge: migrating =============================================
-- create_table(:hoges)
   -> 0.0471s
== 20190731062120 Hoge: migrated (0.0512s) ====================================
```
SQLを見ると重複カラムが除かれているみたいです。
意図して除いているのかhashのkeyみたいになっていて意図せず上書きされちゃっているのかコードを見ていないのでわかりませんが正常に動作します。

```sql:log/development.log
CREATE TABLE `hoges` (`id` bigint NOT NULL AUTO_INCREMENT PRIMARY KEY, `name` varchar(255))
```

で、同様のコードをrails6でマイグレーションしてみましょう。
環境：Rails 6.0.0.rc1, mysql 8.0.16

```ruby:db/migrate/20190731053302_hoge.rb
class Hoge < ActiveRecord::Migration[6.0]
  def change
    create_table :hoges do |t|
      t.string :name
      t.string :name
    end
  end
end
```
お、エラーになった。
rails6からは重複しているカラムを除いてくれなくなったみたいです。

```ruby
# bundle exec rake db:migrate
== 20190731053302 Hoge: migrating =============================================
-- create_table(:hoges)
rake aborted!
StandardError: An error has occurred, all later migrations canceled:

you can't define an already defined column 'name'.
```

１テーブルに同じ名前のカラムを書くことはないのでバグですが、正常終了してしまうため気づかずに潜んでいる可能性があります。
Rails6にバージョンアップしたら`rake db:migrate`で1からデータベースを作成しなおしてみたほうがよさそうです。
X-Tech JAWS & JAWS-UGアーキテクチャ専門支部 コラボ勉強会#02 (2019/07/30 18:50〜)　

# はじめに
AWS CDKを現場に導入できたらと思っていて、他の方の導入事例や考え方を学ぶ目的で参加してきました。
簡単な所管と内容について纏めておきます。

※残念ながら途中参加だったため、開始30分は聞けませんでした。。
※認識違いなどありましたらご指摘いただけると嬉しいです。


# Session 1: 仮想通貨取引所 bitbank での IaC の導入と実践
途中参加だったので、最後の方しか聞けませんでしたが、
CDKは開発者には受け入れられないという部分だけ聞いてしまい、理由が気になったままです。。

# Session 2: eurekaにおけるIaCの実践
IaC導入前はサービスリリース頻繁、セキュリティ管理厳しいなどたくさんの悩みがあり、
AWSマルチアカウント管理に絞ってIaCでどう改善したかをお話しされていました。
今の自分の現場はprod/stage含めて１アカウントで運営しているため、
セキュリティ問題の部分はかなり同感でした。

## IaC tools
　ProvisioningはTerraform、Ansible＋Packerを利用
　ServerlessはServerlessFramework利用
　ContainerはFargateなど(だったと思います)

## AWSマルチアカウント化
　AWS Organizations利用
　マルチアカウントで実現したいこと：セキュリティ担保やコストレポート、影響範囲の分離(サービスごと、ステージごと)など
　アカウントの切り方：MasterAccount、eurekaさんのサービス単位(Pairs/couples/corporate)、prod/stage、sandbox
 マルチアカウントの課題：不明アカウント残存、それぞれのアカウントへのログインしなおしが面倒、共通で利用したいリソースが多い

## Terraformでのマルチアカウント管理
　terraform-account-bootstrapを利用
　↓あとで調べる
　https://github.com/ericwestfall/terraform-account-bootstrap

## QA
　IPアドレス管理が煩雑になりがちだが、どう解決されたか？
   →解決策特にない、結局Excelなどでの管理が必要。
　tfstate破損のリスクが怖い。
   →git管理しているため、破損のリスクはない。
　Terraformで管理しなかったものなどあるか？
   →Serverlessはコード管理していない

# Session 3: Infrastructure as Codeに疲れたので、僕たちが本来やりたかったことを整理する+α
JAWSDAYSに参加した際にもお聞きした村主さんのお話。IaCについて色々考えさせられました。

## IaCについていろいろ話した結論
　IaCの概念は良いがツールが追いついていない。マイクロサービスなど他の概念も同じ
　構成の可視化はしたかった。再利用性は捨てた。

## 2019年度のトレンド
　AWS CDK　CFnの動作理解が必須となる。
　Terraform v0.12　for文で書けるようになったが、ここまで書けるならCDKの方が良さそう

## コード化すべきリソース、するべきでないリソース
　CloudTrailやSNS、SQSなど即時反映されるリソースはコード化しやすい。
　逆にDB系やRedshiftはコード化するメリット少ない。

## QA
　コード化しなかった部分はあるか？
　　⇒Auroraのフェールオーバなど運用作業はコード化しなかった
　自動テストはどうしているか？
　　⇒宣言型言語のTerraformではテストしない方針としていた。(処理結果が保証される)

# Session 4:Ansible + CloudFormation を、AWS CDK に移行する方法 level0 (仮)
Cloudformationテンプレート管理をAWS CDKに移管するお話。CDK導入を検討中のため、コードの書き方など参考になった。

## 現行のテンプレート管理
　AnsibleでCloudFormationテンプレートを作成していた。
　AnsibleのCloudFormationモジュールを利用。
　※恐らく下記のモジュール。
　https://docs.ansible.com/ansible/latest/modules/cloudformation_module.html?highlight=cloudformation
　
## AWS CDKへの移行
　移行対象リソースはEC2、VPC、Cloudwatchアラームなど
　移行フローをSTEP1、STEP2に分割して移行した
　STEP1はテンプレートまで、STEP2でスタックの移行を行った
　STEP2完了までの期間は2週間程度（業務をこなしながら）

# Session 5: Ask The Speakers
　・IACを始めるには？
　　⇒SQSやSNSからやってみる
　　⇒単体レベル(EC2一台など)から始めてみる
　　⇒AWS CLIを理解するとCloudFormation入りやすい

　・CFnのテンプレートテストはどうしてる？良いツールあるか？
　　⇒ValidationCheck含めて完璧なツールはない。使えるとしたらCDKくらいか

　・CFnのテンプレート分割方針について
　　⇒サービス単位（他サービスへの影響を少なくできる）
　　⇒ライフサイクル単位

　・IaCでCI/CD実現する場合はブルーグリーンデプロイでデプロイするしかないのか？
　　⇒？？？

　・なぜコード(DockerFile)はすぐに利用不可になるのか？
　　⇒DockerFileはDockerバージョンアップが多いため影響を受けやすい
　　　AWSでいうとAWS APIに依存するがそれほど問題は起きない

　・運用までIaC管理すると障害復旧時のインスタンスIDが変わってしまい、メンテに苦労する
　　⇒特に解決策はない。運用までIaC管理は行わないほうが良さそう。

# 得たこと、纏め
何か答えを求めて参加したのですが、やはり「銀の弾丸など無い」ようでした。
理想はありますが、実現性は別の話ですので、
正しくIaCの性質を理解した上で、案件の状況など含め、
使いどころをきちんと考えないといけないなと感じました。

X-Tech JAWS & JAWS-UGアーキテクチャ専門支部は初めての参加でしたが、
今後もインフラ運用業務改善について考えていけたらと思います。
Azureアーキテクチャガイドまとめ 5 【CQRS】

## はじめに
[**Azureクラウドアプリケーションアーキテクチャガイド**](https://azure.microsoft.com/ja-jp/campaigns/cloud-application-architecture-guide/)より、7つあるアーキテクチャスタイルの一つ、**CQRS**に関してまとめます。

#### 連載目次
[Azureアーキテクチャガイドまとめ 1 【はじめに】](https://qiita.com/Catetin0310/items/74249f333d9fbfccd543)
[Azureアーキテクチャガイドまとめ 2【N層】](https://qiita.com/Catetin0310/items/1ab0ae1130f767d770d3)
[Azureアーキテクチャガイドまとめ 3 【Webキューワーカー】](https://qiita.com/Catetin0310/items/fe0729549faeee843e8a)
[Azureアーキテクチャガイドまとめ 4 【マイクロサービス】](https://qiita.com/Catetin0310/items/06ab890a04baa161cac6)
Azureアーキテクチャガイドまとめ 5 【CQRS】 → 本記事
[Azureアーキテクチャガイドまとめ 6 【イベントドリブンアーキテクチャ】](https://qiita.com/Catetin0310/items/58f65242a7b71620825b)
[Azureアーキテクチャガイドまとめ 7 【ビッグデータアーキテクチャ】](https://qiita.com/Catetin0310/items/d515fc3fdff68b54f408)
[Azureアーキテクチャガイドまとめ 8 【ビッグコンピューティングアーキテクチャ】](https://qiita.com/Catetin0310/items/eebd754637dcda8ad14d)


## 概要
**C**ommand > 状態を変更するコマンド > **Write処理**
**Q**uery > 状態を読み込むクエリ > **Read処理**
**R**esponsibility > **責任**
**S**egregation > **分離**

で、**CQRS** です。
つまり、Write処理とRead処理を適切に切り分けてパフォーマンスを上げよう、というアーキテクチャです。

具体的には、タスクの属性を考慮し、クエリとコマンドに以下のような役割を持たせます。

|**クエリ**|**コマンド**|
|:--:|:--:|
|**読み取り専用**|**書き込み専用** (非同期処理)|
|結果のみ返す|状態の変更のみ行う|
|状態の変更は行わない|結果は返さない|

## 適用条件
読み取りと書き込みが発生する箇所すべてにこれを適用してしまうと、アーキテクチャ全体が過度に複雑になってしまいます。
よって、書き込みと読み取りの分離に明確な利点があるとみなされた場合にのみ採用します。例えば以下のようなケース。

- 読み取りと書き込みでパフォーマンスやスケールの要件が大きく異なる

- 読み取りが極端に多い
- 多くのユーザーが同じデータにアクセスする (共同ドメインなど)


## 構成例
マネージドサービスを活用し、それぞれの処理がスムーズにいくように構築します。
例えばAzure FunctionsとCosmos DBを書き込み側に、App ServiceとSQL DBを読み込み側に配置した、以下のような構成です。
※ [**こちらのスライド**](https://slideship.com/users/@miyake/presentations/2018/04/5JgW9hp3kHDDZi6zzDRxbm/?p=4)を参考にさせていただきました。

![01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/28a85a70-4233-569a-23b4-9ff79cf2e0de.jpeg)


## 利点
- 独立した拡張性
    - 読み取りと書き込みの**ワークロードを独立に拡張**
    - **ロックの競合**を減らせる可能性

- 最適化されたデータスキーマ
    - 読み取り側ではクエリに最適化されたスキーマ
    - 書き込み側では更新に最適化されたスキーマ
- セキュリティ
    - 適切なドメインエンティティ以外がデータを書き込めないようにできる
- 懸念事項を分離し、**保守性と柔軟性**を向上できる
    - 複雑なビジネスロジックのほとんどは書き込み側に存在
    - 読み取りモデルは比較的単純にできる
- クエリを単純化できる


## 課題
- **アプリの設計**が複雑になる場合も

- 高頻度の処理や更新イベントの発生にメッセージングを用いることが多く、**メッセージのエラーや重複**に対処する必要あり
- データベースを分離した場合、読み取りデータが古くなる可能性あり (CQRSは基本的に**結果整合性**)


## ベストプラクティス
[実装の詳細](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs)
[更新の競合を避ける](https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing)
[読み取りモデルのスキーマ最適化](https://docs.microsoft.com/en-us/azure/architecture/patterns/materialized-view)



## まとめ
CQRSアーキテクチャの特徴と、構成例ついて見ていきました。次回はイベントドリブンアーキテクチャについてまとめます。お楽しみに！



## 参考リンク
[**Azureアーキテクチャセンター**](https://docs.microsoft.com/ja-jp/azure/architecture/)
[**Azureクラウドアプリケーションアーキテクチャガイド ダウンロードページ**](https://azure.microsoft.com/ja-jp/campaigns/cloud-application-architecture-guide/)
[**Azure Cosmos DB と Databricks を使ったCQRSパターンとラムダアーキテクチャ**](https://slideship.com/users/@miyake/presentations/2018/04/5JgW9hp3kHDDZi6zzDRxbm/?p=4)
[Android勉強メモ]adbで直接DBにアクセスする

# はじめに
久しぶりのAndroidネタです。とある都合でSQLiteを使うことになったので色々と調べたことを書きます。

# SQLiteとは
SGLiteを使ったアプリ開発については既に[記事](https://qiita.com/kengo_kuwahara/items/a8ef858a9810cad42ca6)が何個かあります。SQL文を書いて直接端末の中にDBを構築してデータ操作を行うためのツールとして主に使われます。

# コマンドラインでDBにアクセスする
adbというコマンドツールを使うと端末に直接アクセスすることができます。adbはAndroidStudioをインストールした後に少しPathを設定しないと使えません。方法は[こちらの記事](https://qiita.com/furusin_oriver/items/f956848788c7a63922bd)を参考にしました。
adbでできることは色々ありますが、今回はDBのアクセスまでのプロセスに絞ります。

まずは、root権限になる必要があるので以下のような操作をします。

```
adb root
adb remount
```

後は、以下のコマンドで端末にアクセスします。余計なファイルを消さないように注意しましょう。

```
adb shell
```

後はDBの場所ですが、事前に`android.sample`というパッケージ名のアプリに`sample.db`というDBのファイルがあったとします。基本DBの場所は`data/data/{パッケージ名}/databases/`にあるので、以下のようにアクセスして起動します。

```
cd data/data/android.sample/databases
sqlite3 sample.db
```
後はSQLiteのコマンドラインが立ち上がるのでそこでSQLなりなんなりを書いてください。SQLの基本は[ここのサイト](https://www.dbonline.jp/sqlite/function/index1.html)を参考にしました。
Cognos Analytics SDK の AuthenticationProvider サンプルの説明

#概要
Cognos Analytics SDKをインストールすると、以下のフォルダに、SDKのカスタム認証用のサンプルが導入されます。
/opt/ibm/cognos/sdk/sdk/java/AuthenticationProvider

JDBCSampleは、以下を含め色々投稿しているので探してみて下さい。
**Cognos SDK でカスタム認証プロバイダーを開発する時に参考になるJDBCSampleの説明**
https://qiita.com/shinyama/items/33b6349916380b8fe960

それ以外のサンプル。すなわち以下の5点について、何に使うのだろう、というのを少し読み解きましたので、共有しておきたいと思います。
※恐らく自分も3日後には忘れそうなので、ある意味自分へのメモも兼ねてｗ
**TrustedSignonSample**
**TrustedSignonReplaceSample**
**TrustedSignonMappingSample**
**MultiTenancyTenantProviderSample**
**MultiTenancyBoundingSetProviderSample**

※ちなみに、マニュアルのこちらに一応記載があるのですが、読んでも全然わかりません。
https://www.ibm.com/support/knowledgecenter/en/SSEP7J_11.1.0/com.ibm.swg.ba.cognos.ca_dg_auth.doc/c_dg_auth_customauthenticationprovidersampleprograms.html

#TrustedSignonSample
SSO S/Wとの連携で使う事が多いと思いますが、SSOポータルで認証後に、認証情報がクッキーに入ってCognosに投げられて来た時に、クッキーからユーザーIDを取り出し、HTTP Header変数にユーザーIDを入れて、認証ネームスペースに転送するような役割です。
転送先の認証ネームスペースは、LDAPで外部IDマッピングで受けても、JDBCSampleのようなカスタム認証で受けても、どちらでもSSOを成立させる事が可能です。

これは何度か実際のプロジェクトで使用した事がありますので、使用頻度はまあまあ有ります。詳細はこちらをご参照下さい。
**Cognos SSO認証でCookieを使用するサンプル**
https://qiita.com/shinyama/items/c7e9088e725b268102f1

#TrustedSignonReplaceSample
基本的にCognosのSSOは、SSO SW側でHTTP Header変数に埋め込まれたユーザーIDを、LDAPでは外部IDマッピングで、JDBCSampleのようなカスタム認証ではjavaソースの中でHeader変数を読み取り、認証ソースにそのユーザーIDが存在するかを確認しSSOを成立させます。
しかしながら、SSO SW側のログイン時にユーザーIDのフォームに「ComputerName\Username」みたいに、\マーク(円マーク)を挟んでコンピューター名とユーザー名を入れてログインしてきた場合、Header変数に「ComputerName\Username」が埋め込まれてくると、Cognosが受け取って認証ソースのユーザーIDと一致させようとした時に、「ComputerName\」が邪魔をして、一致せずSSO認証エラーになったりします。
これを避けるために、この「TrustedSignonReplaceSample」があります。
TrustedSignonReplaceSampleクラスの中で、「ComputerName\Username」を「\」で区切って分割し、「Username」だけを取り出して再度Header変数に「Username」を入れて、認証ネームスペースに転送し、SSOを成立させる事ができます。

#TrustedSignonMappingSample
前述の「TrustedSignonReplaceSample」のドメイン名に対処する版です。
SSO SW側で「Username@DomainName」でログインし、このままCognosに転送されて来た時に、「@DomainName」を外して「Username」を取り出してSSOを成立させるサンプルです。

#MultiTenancyTenantProviderSample
まず、マルチテナントに関してご存じ無い方は、こちらの記事をご参照下さい。
**Cognos Analyticsでのマルチテナントの設定**
https://qiita.com/shinyama/items/683e38fc9826295ce0de

マルチテナントを簡単に言うと、LDAPに登録されているユーザーの「属性」を元に、Cognosコンテンツへのアクセス権限を制御できる機能、という感じです。
「属性」とは、「組織」とか「職位」とかを想像頂ければ、分かり易いかと思います。

この「MultiTenancyTenantProviderSample」は、そういう有効そうな「属性」がユーザー情報に持っていない場合でも、このMultiTenancyTenantProviderSampleクラスが読み込む「usersToTenants.properties」ファイルに、ユーザーIDとテナントIDのマッピングを記載しておく事で、テナントを分ける事ができます。
サンプルで提供されている、usersToTenants.propertiesファイルの内容は以下になります。

```html
jkunze=TenantA
emichel=TenantA
eguimaraes=TenantB
ckim=TenantB
jolsen=TenantC
```

#MultiTenancyBoundingSetProviderSample
このサンプルは、「MultiTenancyTenantProviderSample」の補助を行うもので、具体的には先のマルチテナントの記事の中で、さらに別の属性「departmentNumber」をテナントマッピングに使う件が出てきますが、それと同様に「ユーザーによってはメインのテナントだけでなく、別のテナントにも併せて参加したい」場合に、このサンプルを使用します。

提供されている、「usersToBoundingSets.properties」ファイルの内容を見ればイメージできるかと思いますが、eguimaraesさんは、以下のマッピングなので、先ほどのTenantBだけでなく、TeantAやTenantCにも参加している事になります。

```html
jkunze=TenantA
emichel=TenantA
eguimaraes=TenantB,TeantA,TenantC
ckim=TenantB
jolsen=TenantC,TenantA
aaldridg=TenantA, TeanatB
twise=TenantB
```

以上です。
ちらっとでも見て覚えておけば、どこかで役に立つかもしれません。
plt.plot() の個人用簡易テンプレ

Pythonのmatplotlibというグラフ描画ライブラリで比較的簡単に綺麗なグラフが作成できることを知ったので、個人的メモ。以前、論文執筆や研究発表などの場面でグラフに統一感を出したいときに、Excelで描画のディティールの調整にあくせくしたことがあったので、一度志向を変えて、プログラミング言語付属ライブラリによるグラフ作成に挑戦してみた。クロスプラットフォーム対応グラフ作成ソフトの有名どころとしては「gnuplot」もあるが、デフォルトの外観としてはmatplotlibが個人的に気に入ったので、今後もこちらの可能性を引き続き模索していきたい。

#Python ソースコード
``` python:pyplot.py
import sys
import numpy as np
import matplotlib.pyplot as plt
import csv

argv = sys.argv
input = argv[1]
csvReader = csv.reader(open(input, "r"), delimiter=',')

buffer = []
for row in csvReader:
	dataCols = len(row)
	for i in range(len(row)):
		buffer.append(row[i])

dataRows = int(len(buffer) / dataCols)

# read info from .csv file
dataOffset = 4;
data = [[0 for j in range(dataRows - dataOffset)] for i in range(dataCols)]
for i in range(dataCols):
	for j in range(dataOffset, dataRows):
		data[i][j - dataOffset] = buffer[j * dataCols + i]

# read data from .csv file
infoRows = dataOffset
infoCols = dataCols
info = [[0 for j in range(infoRows)] for i in range(infoCols)]
for i in range(infoCols):
	for j in range(infoRows):
		info[i][j] = buffer[j * infoCols + i]

for i in range(infoCols - 1):
	plt.plot(np.array(data[0], dtype=float), np.array(data[i+1], dtype=float), label=info[i+1][0], marker=info[i+1][1], color=info[i+1][2], linestyle=info[i+1][3])

plt.xlabel("xlabel")
plt.ylabel("ylabel")
plt.legend()
plt.show()
```
# 出力結果
<img width="500" alt="Images01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456394/6924fa1b-a448-42e7-aaf7-2cad7a406d35.png">

#入力ファイル（CSV形式）
```text:sample.csv
label,sin,cos,sin/x
marker,o,v,^
color,red,blue,green
linestyle,-,-.,:
0.1,0.099833417,0.995004165,0.998334166
0.2,0.198669331,0.980066578,0.993346654
0.3,0.295520207,0.955336489,0.985067356

...(中略)...

9.8,-0.366479129,-0.930426272,-0.03739583
9.9,-0.457535894,-0.889191153,-0.046215747
10,-0.544021111,-0.839071529,-0.054402111
```

csvファイルを読み込んだ後、x軸（0列目）に対するy軸（1-3列目）の2次元プロットを行う。冒頭4行は、「ラベル」「マーカー」「色」「線種」を指定。細かなエラーチェックはしていないが、簡易テンプレとしては十分だと思う。

---

途中、引っかかったポイントがひとつ。
ExcelからCSVファイルを出力する際、保存形式「CSV UTF-8 (コンマ区切り) 」では、ファイル先頭に3バイトのバイトオーダーマーク（BOM: Byte Order Mark）が自動で挿入されていて、おそらくそれが原因で

```python
csvReader = csv.reader(open(input, "r"), delimiter=',')
```

では、正しくデータを読み取ってくれなかった（Python 3.7.3）。なので、上記のソースでは、BOMの付かない保存形式「CSV (コンマ区切り) 」で出力したファイルをopenしてあげないと期待した結果とはならない。これのやっかいな点は、テキストエディタで両者を見比べても外観上の違いはなく、バイナリエディタで確認しないとBOMの有無がわからないことにある。

<img width="500" alt="Images02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/456394/4ebf9941-d3da-f36b-437d-7f84ae0a9591.png">
使い物になるUbuntuコンテナを作る

# 前提
dockerコマンドが使えること

# ホスト側
## イメージ取得
```
$ docker pull ubuntu
```

## コンテナ作成
```
# イメージID確認
$ docker images

# コンテナ作成、ログイン
$ docker run --name ubuntu -it ${イメージID} bash
```

# コンテナ側
## aptのプロキシ設定
<font color="Red">※必要な場合のみ</font>

viが使えないため以下のように設定する必要がある

```
$ touch /etc/apt/apt.conf
$ echo 'Acquire::http::Proxy "${プロキシサーバのアドレス}:${ポート}";' >> /etc/apt/apt.conf
$ echo 'Acquire::https::Proxy "${プロキシサーバのアドレス}:${ポート}";' >> /etc/apt/apt.conf
```

## パッケージの更新
```
$ apt update && apt upgrade -y
```

## 必要なパッケージのインストール
```
$ apt install -y curl cron git less sudo vim wget zip
```

## プロキシ設定
```
$ vi ~/.bashrc

以下を追記
export http_proxy=${プロキシサーバのアドレス}:${ポート}
export https_proxy=${プロキシサーバのアドレス}:${ポート}

# 反映
$ source ~/.bashrc
```
Storybook for Vueで動いているのにコンポーネントがマウントされない時は、webpackにvue/dist/vue.esm.jsへのエイリアスを貼らなければいけない

## storybookが動いているのにコンポーネントがマウントされない

![スクリーンショット 2019-07-31 14.47.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264910/5bdbb8a9-3294-2b98-e499-300727069766.png)


<img width="1231" alt="スクリーンショット 2019-07-31 14.48.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264910/199bc93a-86c5-947a-7320-2a41ef2c0e50.png">

こんな感じになりました。こまりました。

## webpack.config.jsにエイリアスを貼る必要があるらしい

[Webpackを使用してVue.jsを走らせるためのメモ - Qiita](https://qiita.com/rsooo/items/0a9caf9ee804874eac03)

色々調べてみたらいっぱいでてきました。

ていうか、公式に書いてありました（泣）

[インストール — Vue.js](https://jp.vuejs.org/v2/guide/installation.html#%E3%83%A9%E3%83%B3%E3%82%BF%E3%82%A4%E3%83%A0-%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%A9%E3%81%A8%E3%83%A9%E3%83%B3%E3%82%BF%E3%82%A4%E3%83%A0%E9%99%90%E5%AE%9A%E3%81%AE%E9%81%95%E3%81%84)

webpackの設定が悪そうです。

.storybook/webpack.config.jsのconfig.resolveのaliasにvueのエイリアスを貼りましょう。

ただ、自分の環境ではなぜかvue$でなく、vueにエイリアスを貼らないと動きませんでした。。。

[Storybookがなぜ必要か？(Vue.js編) - Qiita](https://qiita.com/masaakikunsan/items/dad8d84807918f3a43cb)

↑でも同じ書き方してたんで、間違ってはいないのかなと思います。

```javascript
  config.resolve = {
    alias: {
      vue: 'vue/dist/vue.esm.js'
    }
  };
```

or

```javascript
  config.resolve.alias.vue = 'vue/dist/vue.esm.js';
```

昔のwebpackならこうですね(必要な部分のみ抜粋)

```javascript
module.exports = {
  module: {
    resolve: {
      alias: {
        vue: 'vue/dist/vue.esm.js'
      }
    }
}
```


## 環境(ライブラリ抜粋)

```json
{
  "dependencies": {
    "nuxt": "^2.0.0",
  }
  "devDependencies": {
    "@babel/core": "7.5.5",
    "@storybook/addon-centered": "5.1.9",
    "@storybook/addon-knobs": "5.1.9",
    "@storybook/addon-links": "5.1.9",
    "@storybook/addon-notes": "5.1.9",
    "@storybook/addon-viewport": "5.1.9",
    "@storybook/theming": "5.1.9",
    "@storybook/vue": "5.1.9",
    "babel-loader": "8.0.6",
    "babel-preset-vue": "2.0.2",
    "storybook-readme": "5.0.5",
  }
}
```


## 参考

[インストール — Vue.js](https://jp.vuejs.org/v2/guide/installation.html#%E3%83%A9%E3%83%B3%E3%82%BF%E3%82%A4%E3%83%A0-%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%A9%E3%81%A8%E3%83%A9%E3%83%B3%E3%82%BF%E3%82%A4%E3%83%A0%E9%99%90%E5%AE%9A%E3%81%AE%E9%81%95%E3%81%84)

[Webpackを使用してVue.jsを走らせるためのメモ - Qiita](https://qiita.com/rsooo/items/0a9caf9ee804874eac03)

[JavaScript - Vue.jsの内容がマウントされず、画面表示されない！｜teratail](https://teratail.com/questions/143052)

[vue.js - Webpack fails to mount Vue components - Stack Overflow](https://stackoverflow.com/questions/45654720/webpack-fails-to-mount-vue-components)

[Vue.jsの完全ビルドとランタイムビルドの違い - Qiita](https://qiita.com/sansaisoba/items/58f8176f6e462fe4d591)
【無料】Cloudflareを使ってHerokuで独自ドメインで運用する方法




##Railsアプリケーションのproduction.rbの設定を変更

```config/environments/production.rb
config.force_ssl = true
```

##ドメインを登録する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/109b212f-8cb7-62a5-cd50-1ac70eef2a61.png)

###Freeプランを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/15831352-dc9a-8a8a-444d-ba32efb3a61b.png)


###初期で入ってるのはすべて消す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/070b658e-5c46-8c5b-1b36-3552650e3554.png)


###CNAME-独自ドメイン-Herokuドメイン　で設定する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/85d72494-9277-5ff0-a782-8f69ee6a391c.png)

##ネームサーバーの設定変更

###変更する情報はCLOUFAREのDNSの下部にある
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/ac3efe64-75eb-dcfd-f10d-dca1c8020dd6.png)

###お名前ドットコムでネームサーバーを変更する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/2ae3fae0-b1e7-480a-5f41-97e78fd6056b.png)

##Herokuにてドメインの追加
ドメインを追加するためにはクレジットカードの登録が必要なので、先に登録しておきます。

Personal>'appName'>Setting>Domains and cerfificates でドメインを入力

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/e37eb5c5-6921-ec11-60eb-756099dd5033.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/2f7a7f85-6f14-50ec-a461-b18d954307ad.png)

##CloudFlareでSSL対応設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/bd741edf-c6ea-f24a-0076-a3b13c60568f.png)

###リダイレクトも設定できる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/62ed85c2-9f8e-47b3-dd35-571fb97b7ff4.png)


以上！

##【追記】ドメインを無料で取得する方法
ドメインを無料で取得する方法があるのをご存じでしょうか。
「お名前ドットコム」に登録してメールマガジンを取得していると定期的に下のようなメールが届きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/12feeb5d-70d7-f8a9-541f-ad5bed57bc66.png)

.workなどのドメインであれば本当に無料で取得できてしまいます。
メール内のリンクからドメインを取得すれば1年間はタダで利用できます。
私も実際に5個以上は無料取得しましたよ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346533/62548234-f746-9578-6ca8-2a0b13a8533d.png)


ぜひ利用してみてください！
JavaのNullPointerExceptionのスタックトレースをログに落とす

SpringBootにて
悪しきぬるぽ（真に悪しきはバグを作ったおまえ）が出たときいつも追えなくて困るので、スタックトレースを出すハンドラをControllerの下とかにくっつけておくことにしました。
デバッグに意外と役立つ。

```java
@ExceptionHandler({NullPointerException.class})
public String handleRunTimeException(NullPointerException ex) throws IOException {
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw);
    ex.printStackTrace(pw);
    String stackTraceString = sw.toString();
    log.error(stackTraceString);
    sw.close();
    pw.close();
    return "redirect:error/500";
}
```
threeとbabylonでscreenshot

#概要

threeとbabylonでscreenshotやってみた。

#写真

three

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/90aa1e4c-9c3f-9be0-f50b-da6038243636.png)


babylon

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/42af13c5-e104-f6f8-e298-d26e250c1eef.png)


#成果物

three

https://embed.plnkr.co/hWq1FQZmgWCNnd6LJ8zk/

babylon

https://embed.plnkr.co/533dG1wvNXpznRn9JCDn/

以上。
Linux環境で動作しているpostgresのDB環境をWindowsで再現し開発環境を整える

本記事は、Linux環境で動作しているアプリケーション環境内のPostgresqlサーバの
バックアップをもってWindows環境に再現することを目的とした備忘録です。

# 1.Linux環境からPostgresのバックアップをとる

```sql
pg_dump -F p -f ./filename_to_save.sql.20190730 \
-h 192.168.1.2 \
-U password db_name
```

*上記のコマンドでLinuxで動作しているPostgresのバックアップを保存する*


# 2.Windows上にDockerでPostgresサーバーのコンテナを建てる

*以下のコマンドでPostgresコンテナを作成する*

```docker
docker container create --name p-server #<任意のコンテナ名> \
-p 5432:5432 #<任意のホストOS側ポート名>:<規定のゲスト側ポート名> \
--mount type=bind,src=/C/Users/your-name/postgres/backup,dst=/tmp \
--mount type=volume,src=postgres-server,dst=/var/lib/postgresql/data \
--network postgres-network
-e POSTGRES_USER=user \
-e POSTGRES_DB=user_db \
-e POSTGRES_PASSWORD=user_password \
postgres:latest #<作成もとにしたい任意のコンテナイメージ>
```

(※上記の、コマンド内で --mountというマウント命令を2つ指定しているのは、postgresサーバが参照する
postgresの実データのディレクトリをWindowsホストではマウントできないため、
他のコンテナ側ディレクトリをホストOS側にコンテナマウントして、
そこからバックアップSQLをpostgresコンテナ内で実行するため。)


*上記の用にdockerコマンドを実行した後*

```docker 

docker container start p-server  #<コンテナ作成時に指定したコンテナ名>
```
上記を実行するとコンテナが起動する

```docker
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
d96c3082081d        postgres:latest     "docker-entrypoint.s…"   4 minutes ago       Up About a minute   0.0.0.0:5432->5432/tcp   p-server

```
※上記の用に起動していればOK。

# 3.postgresサーバーコンテナにバックアップのsqlファイルを流し込む。

まずは、バックアップSQLファイルをpostgresサーバーに流し込むため、作成したpostgresコンテナに入る

```docker
# 下記コマンドを実行して、postgresコンテナのターミナルにログインする
docker container exec -it p-server /bin/bash
```
*実行後以下の用にPostgresのターミナルにログインできる*

```docker
C:\Users\your-name>docker container  exec -ti p-server /bin/bash
root@d96c3082081d:/#     
```

ログイン後、手順2のコンテナ作成時にマウントしたホスト側OSとコンテナ側のディレクトリがただしくマウントされているかを調べる。

```docker 
root@d96c3082081d:/tmp# touch index.dat
```
などとしてホスト側でファイルを共有できることを確認後、バックアップのSQLファイルをマウントされたホスト側OSのディレクトリにおいてあげる。
後は任意のpostgres側コマンドで バックアップファイルを実行する。

# 4.ホスト側OSから任意のpostgresGUIアプリなどでDB状況を復帰できたことを確認する。

```ini

host: localhost
user: user # コンテナ作成時に指定したユーザー名
password: user_password # コンテナ作成じに指定したパスワード
database: user_db #同じく作成時にしていした初期DB名
```

上記のデータで再現できれば、ホスト側からでも、他のコンテナからでもアクセスできる。
Rails+PostgreSQL+switch_pointでデッドロック

## switch_pointを導入しようとしただけなんだ
ただR/Wのスプリッティングがしたくてswitch_pointを導入しようとしただけなんだ
ただそれだけのことなんだ
まさかデッドロックするなんて思いもしなかったのさ…

[switch_point](https://github.com/eagletmt/switch_point)

## migrationで死
ググればいくらでも出てくるswitch_point導入記事に倣ってswitch_pointを導入したところ、Railsの `db:migrate:reset` で死んでしまいました
死んだというか、途中で詰まって動かなくなっちゃったんですよね
なにが起きたのでしょう？

### 実行されていたmigration
```ruby
  def change
    add_column :hoge, :fuga, :string

    # 既にあるHogeに対してvalueを追加する
    Hoge.all.each do |h|
      h.fuga = 'piyo'
      h.save!
    end
  end
```

みたいな
カラムを追加するんだけど、既存のレコードはその追加したカラムにvalueを追加するというmigrationでした

な ぜ 詰 ま る

### デッドロック
switch_point入れただけでなんでここで詰まる？と思ったのですが、なんとなくロックっぽい気がしてPostgreSQLの方で確認したところ、やはりデッドロックしていました
なぜ？いままで起きなかったのに？

これは推測の域を出てませんが…
switch_ppointを導入したことで、 `Hoge.all` や `h.save!` といったモデルを利用したコードはswitch_point経由のコネクションとなり、ALTERのコネクション(=migrate taskの張るコネクション)と分離してしまったんじゃないかと思っています

### PostgreSQLはSELECTもロックする
いやいやいや、とはいえデッドロックしないっしょ？
と思い調べていたのですが、PostgreSQLはSELECTも弱いロックを獲得し、それはALTERの獲得するロックと競合するんですね
初めて知りました

参考:
  - https://www.postgresql.jp/document/11/html/explicit-locking.html
  - https://techblog.lclco.com/entry/2018/01/24/070000
  - https://yujisoftware.hatenablog.com/entry/20100310/1268238033

## 結論
上記のようなmigrationファイルがあってなおかつPostgreSQLを使っていると、switch_pointの導入は断念せざるを得ない、と思いました
ちょっと打つ手が思い浮かばないですね…
諦めてoctopusにしようと思いました
SourceTree（windows）で、パスワード（認証情報）が保存されてしまっているのを削除する

C:\Users\[UserName]\AppData\Local\Atlassian\SourceTree
userhostsにリポジトリのホスト名とIDが保存されているので、更新したいアカウントを削除すればOK

編集する際、SourceTreeのアプリケーションは念の為切っておくのがお作法、ってくらい（起動しててもロックかかって無ければ操作できた）