OmniAICreator/Qiita-1.07M huggingface dataset:
インターネット向け通信にプロキシはどのように関わるのか

##プロキシサーバって？
家庭などのPCでインターネットに接続する際はあまり関係のない話だが、いち企業がインターネットに通信をしたいとなるとプロキシ（サーバ）を設置することは多い。

プロキシとは、端末からインターネット網の間に、通信の中継役として設置されるサーバのこと。

プロキシを設置すると例えば以下のいいことがある。

######一度アクセスしたサイトへの再アクセスが速くなる

これまでにWebサーバから受信したWebサイトの情報をプロキシ自身のHDDに一時保存（≒キャッシュ）することで、次そのサイトにアクセスする際は、Webサーバまで行かずともプロキシが情報を持っているので、通信の高速化を図ることができる

######特定のURLをアクセス禁止にできる
有害とされるWebサイトやアドレスをリスト化し、それに該当する通信は全て遮断などすることで、セキュリティを脅かすコンテンツにそもそもアクセスできないようにできる


メリットは他にもあるが一旦はこんな感じ。

##プロキシを経由した場合の端末からインターネットまでの通信
プロキシ経由のインターネット通信は図に表すとこんな感じ。

![スクリーンショット 2021-02-19 20.34.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647755/4b7dbb1a-d6a0-b4eb-c494-13e14d041b17.png)



①〜④がどのような通信なのかを、上図で各機器に振っているIPも交えて説明する。


①PC→プロキシサーバ
ブラウザでプロキシ用の設定を行っている場合は、PCからのパケットの宛先IPはWebサーバではなくプロキシサーバとなる。
送信元IP：172.10.1.1　宛先IP：10.1.1.1 

②プロキシサーバ→DNSサーバ
パケットの中にあるHTTPリクエストデータの中には「最終的な目的地であるWebサーバのドメイン」が入っている。で、そのドメインをWebサーバのグローバルIPに名前解決するため、プロキシサーバはDNSサーバにパケットを投げる。
送信元IP：10.1.1.1　宛先IP：10.2.1.1  

③DNSサーバ→プロキシサーバ
DNSサーバはドメインから名前解決をし、WebサーバのIPをプロキシサーバに教える。
送信元IP：10.2.1.1　宛先IP：10.1.1.1

④プロキシサーバ→Webサーバ
Webサーバに向けてパケットを飛ばす。
送信元IP：10.1.1.1　宛先IP：143.100.25.2

##Webexアプリの通信の場合
という感じでプロキシ周りの通信は通常上図の流れになるのだが、今日たまたまWebexアプリの通信について調べている中で、少し仕様の異なる話に出会った。

一応説明しておくと、Webexはオンラインミーティング用のアプリ。 

Webexアプリの通信は図に表すとこんな感じらしい。


![スクリーンショット 2021-02-19 21.09.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/647755/8bdbdd52-0466-f5c4-ec05-35e42d49f0a5.png)


この図ではDNSサーバは省略している。
WebexアプリからWebexを運営しているCisco社のクラウドまでの通信は2手に分かれており、それぞれ以下のように説明できる。

通信A：プロキシサーバを経由するパケット
オンラインミーティング自体を制御する通信。アプリケーション層のプロトコルはHTTPSで、トランスポート層のプロトコルはTCP。

通信B：プロキシサーバを経由しないパケット
映像と音声をオンラインミーティングの参加者のところまで運ぶ通信。アプリケーション層のプロトコルはsRTPで、トランスポート層のプロトコルはUDP。 

どうやら映像や音声の通信をプロキシに乗せてしまうと、プロキシが一部フィルタリングを行うために通信の完全性を保つことがむずかしくなるらしい。要は映像や声が途切れ途切れになる。それは確かに良くない。なので上図のような仕組みになっているようだ。

ZoomとかGoogleMeetとかも同じ仕組みなのかなと少し気になってはいるが、この辺にしておく。Webexの通信、ちょっとおもしろいなと感じた。そういう通信もあるんだな。


##参考
[【図解】httpプロキシサーバの仕組み(http GET/https CONNECTメソッド)や必要性・役割・メリットデメリット・DNSの名前解決の順序 | SEの道標](https://milestone-of-se.nesuke.com/nw-basic/grasp-nw/proxy/#:~:text=%E3%83%97%E3%83%AD%E3%82%AD%E3%82%B7%E3%82%B5%E3%83%BC%E3%83%90%E3%81%A8%E3%81%AF%E3%80%81%E3%82%AF%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%B3%E3%83%88,%E5%BF%9C%E7%AD%94%E3%82%B5%E3%83%BC%E3%83%90%E3%81%AE%E3%81%93%E3%81%A8%E3%81%A7%E3%81%99%E3%80%82&text=%E7%A4%BE%E5%86%85%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%8D%E3%83%83%E3%83%88%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%82%92,%E6%83%85%E5%A0%B1%E3%82%92%E9%9B%86%E4%B8%AD%E7%AE%A1%E7%90%86%E3%81%A7%E3%81%8D%E3%82%8B%E3%80%82)

[WEBプロキシとは？ 仕組みや機能・メリットについて解説｜セキュリティコラム｜株式会社網屋](https://www.amiya.co.jp/column/web_proxy_20200911.html)

[プロキシサーバとは](https://www.infraexpert.com/study/security23.html)

https://www.cisco.com/c/dam/m/ja_jp/solutions/webex/pdf/guide-to-using-webex-safely.pdf
Composer管理しているDrupalのアップデート方法

`drupal/recommended-project`や`drupal/legacy-project`といったComposerテンプレートを使用して構築されたDrupalサイトのアップデートの大まかな流れを説明します。

## ローカルでアップデート&確認

### ファイルの更新
- コアのアップデートをする場合は `composer update drupal/core --with-dependencies`
- 全てのモジュールをアップデートする場合は`composer update --with-dependencies`

### DBのスキーマ更新
- `drush -y updb`もしくはブラウザで`/update.php`から更新

### ファイルのコミット 
- `drush -y cex`で構成のエクスポート
- 全ての変更されたファイルをコミット
    - 内訳は`composer.json`、`composer.lock`、`.htaccess`などcomposer管理されていないファイル、`drush cex`で出てきた構成ファイル

## 本番に反映

### ファイルの同期
- `git pull`
- `composer install`でコアやモジュールファイルをダウンロード

### DBのスキーマ更新
- `drush -y updb`もしくはブラウザで`/update.php`から更新

### 構成の同期
- `drush -y cim`

### キャッシュクリア
- `drush cr`

参考: https://drupal.stackexchange.com/questions/293019/how-do-i-update-configuration-database-after-a-core-update
GitHub Actionsを利用してPull Requestをmasterにマージしたら自動的にタグを打つ

## はじめに
Gitのタグ付けを毎回手動でしていたが、塵も積もれば山となるで時間削減のため自動化しました。どのCIサービスを使っても実装は可能でしたが、GitHub Actionsを使ったらよくありがちな環境変数の設定無しに簡単に導入できたので紹介します。同様の記事も既にありますが、個人メモとして残すためご了承ください。

## 実現したいこと
- Pull Requestをマージしたらリリースタグを打ちたい
    - マージせずに閉じた場合は何もしない
- タグ名は `release-%Y%m%d%H%M`の書式としたい。この辺はお好みで。
    - もちろん日本時間で！

## 設定方法

対象のGitHubリポジトリで以下内容のファイルを `.github/workflows/release_tag.yml` に配置してコミットして終わりです！

```yaml
name: Release Tag
on:
  pull_request:
    branches:
      - master
    types: [closed]
jobs:
  build:
    name: Create Release
    runs-on: ubuntu-latest
    if: github.event.pull_request.merged == true
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
      - name: Set current date
        id: current_date
        env:
          TZ: 'Asia/Tokyo'
        run: echo "current_date=$(date +'%Y%m%d%H%M')" >> $GITHUB_ENV
      - name: Create release
        id: create_release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: release-${{ env.current_date }}
          release_name: release-${{ env.current_date }}
          draft: false
          prerelease: false
```

以降は Pull Request がマージされると以下のようにタグ付けされます！ :tada: 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29755/871f7704-db55-d10b-4305-c7e5b20cb3e8.png)

### 補足

#### ワークフロートリガーの設定

以下により「masterブランチに対する Pull Requestを閉じたら実行する」が設定されます。 `types` でアクティビティタイプ(何をトリガーで発火するか）が選択できるのですが、 `closed` を設定することで「Pull Requestを閉じたら(マージを含む）」になります。本当はここで `merged` が選択でいるといいですけど、なぜかないんですよねぇ。

```yaml
on:
  pull_request:
    branches:
      - master
    types: [closed]
```

#### Pull Requestをマージした時だけ発火させる

`types: [closed]` だけだとマージせずに閉じただけでも発火してしまうので、以下を設定することで Pull Request をマージした時のみジョブが実行されるようにします。

```yaml
if: github.event.pull_request.merged == true
```

#### 日時を含むリリースタグ名を作成する

`release-202102192100` みたいに日時を含むリリースタグ名を以下で作成し環境変数に登録しています。ポイントは :clock1: タイムゾーン設定です。これが無いと UTC となってしまうのでお忘れなく〜！ （最初は気づかず素通りしてました... :sweat_smile: 

```yaml
      - name: Set current date
        id: current_date
        env:
          TZ: 'Asia/Tokyo'
        run: echo "current_date=$(date +'%Y%m%d%H%M')" >> $GITHUB_ENV
```

#### リリースタグを登録されるようにする

公式から提供されている `actions/create-release@v1` アクションを利用すれば簡単です。`tag_name`, `release_name` でお好みのタグ名・リリース名を設定するだけ！

```yaml
      - name: Create release
        id: create_release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: release-${{ env.current_date }}
          release_name: release-${{ env.current_date }}
          draft: false
          prerelease: false
```

## リンク
- [actions/create\-release: An Action to create releases via the GitHub Release API](https://github.com/actions/create-release)
- [actions/checkout: Action for checking out a repo](https://github.com/actions/checkout)
【環境構築】Docker

## docker
仮想環境を構築するための道具（ex,ゲーム機）
環境による差異を少なくするツール

## イメージ　→　dockerhubからコマンド取得　→コマンドがない場合はDockerfileで作成
dockerコンテナを実行する際に必要なもの（ex,ゲームソフト）

## コンテナ　→　docker run(一つずつになる) コンテナ実行
仮想環境そのもの（ex,セーブデータ）
（dockerはdockerエンジン。dokerの上にコンテナが動く）

## Dockerfile
イメージを実行する際に必要なもの、自動設定

## Docker compose　→　コンテナを一元管理。（オーケストレーション）
複数のコンテナから成るサービスを構築・実行する手順を自動的にし、管理を容易にする機能。（rails,mysql→２つコンテナを作る）
【カンニングペーパー】わからなかったワード

私がわかならなかったワードをアウトプットするだけの記事

## Nginx
静的なファイル、画像をpumaの前に返す

## webpacker
Webpackerとは、Webpackを使用してRuby on Rails上でJavaScript開発をするために必要な一連のまとまりを、標準で実装することができるgemパッケージ（Rails6.0より、webpackerが標準実装）

## webpack
CSSやJavaScript、画像などのプログラムを作成する際の部品であるモジュールを、１つのファイルとしてまとめるためのモジュールバンドラー。 Node.jsで、サーバーサイドで動く。 平たく言うと、WebpackはJavaScriptファイルのコーディングにおいて、開発を効率的におこなうことができるよう助けるような役割を担っている。

## Simpacker(≒webpacker)
Webpacker は webpack を知らない人でも簡単に使えるというところがいいところだと思うのですが、もう少しシンプルに webpack とのインテグレーションだけをしてくれるツールがほしいと思い作ったのが Simpacker という 

→Simpackerを導入する際はwebpackを同時にインストールするのが普通。

## yarn = Node.js
(ruby →　gemfile=bundller)(package.json = yarn install)
JavaScriptのパッケージマネージャー
基本的に大量のプログラムで構成されています。その大量のプログラムを一まとめにしたものをパッケージと呼び、そのパッケージを管理するツールがパッケージマネージャーです。

npm(Node.jsをインストールすれば一緒にインストールされる)と互換性がある = 同じpackage.jsonが使える

## Node.jsとは
すべてJavaScriptで開発できる(JavaScriptの開発者が全部JavaScriptで書きたがった)
JavaScriptでサーバーサイドの処理を可能にさせるプログラム

## トランスパイル（post.css）
主にES2015以降の仕様で記述したJavaScriptが古いブラウザなどで動かなく危険性があるため、互換性のあるコードに変換をする処理。

人間が書きやすいものをブラウザが理解できるものに変換する
【カンニングペーパー】おすすめ記事

カンニングペーパーだ

## GitHub

* git hub 必須コマンド　https://qiita.com/nnahito/items/565f8755e70c51532459
* git hub 公開鍵作成　https://git-scm.com/book/ja/v2

## devise

* devise日本語化　
 http://31webcreation.hatenablog.com/entry/translate-devise-to-japanese
* devise　
https://qiita.com/cigalecigales/items/16ce0a9a7e79b9c3974e
*  deviseカラム追加　
https://qiita.com/hz1_d/items/77e440b09a1ddbe56263
* devise　ユーザー名でログインhttp://misatlabmemo.hatenablog.com/entry/2012/08/29/204839
* root設定
https://blog.nextcode.jp/2013/07/deviseroot.html

## rails 6.0
* rails 6　https://skillhub.jp/courses/134/lessons/785
* actiomtext https://qiita.com/tomokiyao/items/3c22ca9cb916d5c99ca4
* rails6 jquery https://qiita.com/iiyama_makoto/items/940b130fd20540fd70f1

## docker
* docker
https://sukkiri.jp/technologies/virtualizers/docker/docker-win_install.html

## svg
* https://tsuchippo.com/htmlcss-svgcolor

## 機能
* フォーム　https://see-ss.com/components/form/
* コメント実装　https://qiita.com/japwork/items/b2a7e61379c88a5e60c8
* いいね非同期　https://qiita.com/naberina/items/c6b5c8d7756cb882fb20

## other
* コマンド一覧（rails tutorial）
https://railstutorial.jp/chapters/beginning?version=5.1#table-unix_commands
* BCrypt＆authenticateについて　
   https://techacademy.jp/magazine/19932
* ターミナルまとめ　
https://qiita.com/Cesaroshun/items/eaf4b4e3f847062ca308
* ローカル環境セットアップ　
  http://railsgirls.jp/install
* テーブルのカラム型　
https://qiita.com/mzmz__02/items/f018b67243175e8f0891
* フォーム　
   https://see-ss.com/components/form/
* コメント実装　
  https://qiita.com/japwork/items/b2a7e61379c88a5e60c8
* css
 https://webliker.info/css-selector-cheat-sheet/
GitとGitHub基礎 Udemy メモ

ターミナルを開く
git init でリポジトリ作成(.git ディレクトリが作成される)
ls -aで見れる　ファイルと同じ階層に作成する

<h4>1　Gitの基本的なワークフロー</h4>
①ファイルの変更をステージングエリアへ追加する (git addコマンド)
②ローカルリポジトリにコミットする （git commitコマンド）
③リモートリポジトリにプッシュする （git pushコマンド）

git add ファイル名

git commitコマンド後コミットメッセージ入力画面が開くので、iを押してから入力開始
終わったらesc→ :wqで保存

GitHubにプッシュするにはリポジトリを用意する必要があるので、ブラウザでGitHubを開き、+ボタンでNew repository(descriptionは入力なし Publicに設定後 Create GitHub
今回はすでに作成されているリポジトリに対して行うので、
…or push an existing repository from the command lineの
git remote add origin https://github.com/ユーザー名/リポジトリ名 が
GitをGitHubに登録するというコマンド
git push -u origin master　で完了

<h4>２　変更をコミットしよう</h4>
<h5>１作業ずつ１コミットするのが原則</h5>
今ある変更をまとめてステージングエリアへ追加したい場合は git add . 
変更にメッセージをつけてリポジトリに記録するのがコミット。
コミットすることで変更がリポジトリ内に時系列で記録される。

<h5>わかりやすいコミットメッセージ</h5>
１行目　変更内容の要約
２行目　空行
３行目　変更した理由

<h6>git commit -vで何の変更をしたか見れる</h6>

git logでコミットの履歴

<h4>３　色々な変更をコミットしよう</h4>
・新規作成
・ファイルの削除
・複数ファイルの変更

削除したファイルをステージングエリアに追加するときは、git rm ファイル名
複数のファイルをステージングエリアに追加は git add .

<h4>４　現在の状況を確認しよう</h4>
git statusはGitリポジトリの今の状況を表示するコマンド(最新のgit commitした状態からの差分)

<h4>５　変更履歴を確認しよう</h4>
git logコマンドでリポジトリにコミットされたログを確認する
commit Auther Date その下にコミットメッセージが表示される
このcommitを打ち消したい・このcommitの状態に自分のリポジトリを戻したい時などに、commitにハッシュ値を指定する

<h5>git logでよく使われるオプション</h5>
git log --oneline 　　　#一行で表示する
git log -p   #差分を表示する(pの後にファイル名を指定すると、そのファイルの変更履歴を見れる)
git log -n 3　　 #最新の３つだけ表示
git log --oneline -n 3　　#一行で表示して、最新の３つだけ表示

<h4>６　変更差分を確認しよう</h4>
add, commitする前に git diffコマンド
git diff　　#ステージとのファイル変更差分を確認
git diff HEAD 　#ステージとコミットの差分

<h4>７　GitHubにプッシュしよう</h4>

git remote add origin リモートリポジトリのURL
\#ローカルリポジトリをリモートリポジトリに登録

git push origin master
\#ローカルリポジトリの内容をリモートリポジトリに送信する
masterはデフォルトのブランチ名　ブランチとは複数人で開発するときのもの

git push origin feature
\#master以外のブランチ（この例はfeatureブランチ）へ送信

GitHubのYour profileからRepositoriesから選択後、URLをコピー

<h4>８　GitHubの画面を確認しよう</h4>

Your profile→RepositoriesからAboutの歯車でDescriptionを追加
Reposotoriesからファイルをクリックして、ファイルの数字をクリックするとURLが生成されるので、行をマークして共有したいときはそのようにする

rawはファイルの生ファイルを見れる（ファイルの中身をコピペしたいときなど）
blameはどの変更を誰がいつしたのか見れる

<h4>９　バージョン管理からファイルを外そう</h4>

.gitignoreファイルに指定することで、ファイルをGitの管理から外すことができる
（自動生成されるファイルや、パスワードが記載されているファイル）

<h6>.gitignoreファイルの書き方</h6>
\#から始まる行はコメント
指定したファイルを除外したい場合はそのままファイル名を書く （例：　index.html　）
プロジェクトのルートディレクトリを明示したい場合は　/ で始める　（例：/root.html　）
ディレクトリ以下を除外したいときはディレクトリ名/ と書く　（例：　dir/　）

<h6>ファイルごとGitの管理から削除</h6>

.gitignoreファイルに書くのを忘れて間違ってコミットしたファイルをGitの管理から削除するには
git rm コマンド
ファイルを削除しただけではGitの管理から外れないので、ファイルを削除した後にgit rmコマンドでGitの管理からも外す
git rm [ファイル名] 　 :ファイルも一緒に削除
git rm -r [ディレクトリ名]　：ディレクトリも一緒に削除
あとでgit statusコマンドでGitの管理からも外れたか確認

git reset HEAD ファイル名　　：もとに戻す
git reset HEADだけではローカルからは消えたままなので、ローカルにも戻したいときは
git checkout ファイル名　　：ローカルにも戻す

<h6>ファイルを残してGitの管理からだけ削除</h6>

git rm --cashed [ファイル名]
（パスワードなどのファイルでローカルには残したいがGitの管理からだけ外したいとき）
※ .gitignoreに指定しないとGitから常に無視されるようにはならないので、.gitignoreに追記してGitの管理からずっと外れるようにするのを忘れないように！
2021年2月19日朝方からSendGridで535 Authentication failed: Bad username / passwordが出始めた話

### 問題
2021年2月19日 朝7時ごろにSentryに通知が来ていて確認したところ、

```
Net::SMTPAuthenticationError
535 Authentication failed: Bad username / password
```

が発生していました。
どうやらAutheticationエラーによってメールが送信されなかったようです。

### 発生後
このエラーが発生して以降、メールが送信できなくなり、
最後に送信できていたのは19日 0時5分でした。  
つまり、エラーが発生する6〜7時間前まではメールが送信できていたことになります。

### 原因
SendGridから告知がされていました。
**2021年2月17日までにSMTPからAPI Keyに認証方式を切り替えろ**、とのことでした。
https://status.sendgrid.com/

```
In progress - For clarification, this is a customer advisory.
There is no maintenance work happening right now. 
We have attempted to notify affected customers in our outreach campaign
and this is an additional step to alert customers of the breaking change 
that will occur if authentication methods are not updated by next Wednesday,
February 17th, as outlined here:
https://sendgrid.com/docs/for-developers/sending-email/upgrade-your-authentication-method-to-api-keys/.
```

```
Scheduled - In order to enhance security for all of our customers,
Twilio SendGrid is requiring existing Essentials customers to update their authentication
to API Keys for all API and SMTP requests by Wednesday, February 17th, 2021.

Customers impacted by this breaking change will experience authentication errors
when making API calls leveraging Basic Authentication. In order to ensure uninterrupted service,
customers must update their authentication method to API keys by following the steps here:
https://sendgrid.com/docs/for-developers/sending-email/upgrade-your-authentication-method-to-api-keys/.
```

### 解決策
SMTPからAPIKeyによる認証方式に切り替えましょう。

### 反省
まったくもって気づきませんでした。
メール来てたっけ？と思い確認しましたが、どうやら来てないようでした。

仮に来てたとしても確認してなかったと思うので、今後こういうメールは確認するようにしたいです。
今後の糧にします。
git pull について簡単にまとめた

#git pull について簡単にまとめた

##What?
pullはリモートリポジトリの変更内容をローカルリポジトリに反映するもの。
また、pullは fetch + merge と考えて良いみたい。
ちなみに、fetchはローカルの追跡ブランチにリモートブランチの状態を反映するもの。

##How?
pullの実行方法は以下の通りです。

```
git pull origin ブランチ名
```
[JavaScript] IIFE (即時実行関数式)

#[JavaScript] IIFE (即時実行関数式)

IIFE (Immediately Invoked Function Expression; 即時実行関数式) は定義されるとすぐに実行される JavaScript の 関数 です。

構文：

```JavaScript
(function () {
    文
})();
```

例：

```JavaScript
(function() {
	console.log('called');
})();
```

コンソールに called と表示されます。
[Swift5] UIViewを『自由変形』する

UIViewを自由変形する。
拡大縮小や回転ではなく『自由変形』である。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134740/3863d144-5154-c286-ee85-f7eff1c78e87.png)

## JoshQuadViewを使う
stackoverflowで見つけた JoshQuadView を拝借するが、Swift5では若干の変更が必要になる。
Swift5で使えるよう修正したものをgistにアップしておいた。
https://gist.github.com/Nouris-Inc/9dcc78ce35116cc2920617ec0576c818

stackoverflow
https://stackoverflow.com/questions/9470493/transforming-a-rectangle-image-into-a-quadrilateral-using-a-catransform3d

中でやっている事は`CATransform3D`による普通のレイヤー変形なので、GLKit (iOS12でdeprecated) など使っていないため安心です。

使い方は、 `transformToFitQuadTopLeft()` に4コーナーの`CGPoint`を渡すだけです。
ただし、layerのアンカーポイントを `CGPoint.zero` にしておかなければ動かないので忘れずに設定すること。

```swift
let view = JoshQuadView(frame: rect)
view.layer.anchorPoint = CGPoint.zero

view.transformToFitQuadTopLeft(tl: p0, tr: p1, bl: p2, br: p3)
```

なお、4コーナーの tl, tr, bl, br は、`TopLeft` `TopRight` `BottomLeft` `BottomRight`である。

## 変形が反転してしまう不具合を防ぐ

4つ角のうち、どこかのコーナーが180度以上に開いてしまうとレイヤーが反転(？)してしまう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134740/848e07ee-08c0-72dd-0b86-04de39eb442a.png)

これを防ぐため、180度以上は開くことができないよう、変形前にチェックする。

CGPointでベクトル計算ができるように、CGPointVector を利用している。
（が、引き算しか使わなかったので、自前で書いてもいいかもしれない）
https://github.com/koher/CGPointVector

```swift
func checkAngle(_ view:UIView, origin:CGPoint) -> Bool {
    var p1:CGPoint = CGPoint.zero
    var p2:CGPoint = CGPoint.zero
    
    if (view == handleTL) {
        p1 = handleTR.center - origin
        p2 = handleBL.center - origin
    } else if (view == handleTR) {
        p1 = handleBR.center - origin
        p2 = handleTL.center - origin
    } else if (view == handleBL) {
        p1 = handleTL.center - origin
        p2 = handleBR.center - origin
    } else if (view == handleBR) {
        p1 = handleBL.center - origin
        p2 = handleTR.center - origin
    }

    let cross = p1.cross(p2)
    return (cross > 0)
}
```

handleTL〜handleBR を受け取って、チェック対象のコーナーを判別し、隣接コーナーをp1, p2としている。
originは角度を確認するコーナーの座標である。

CGPointVectorには、`point.angle()`という角度を取得するメソッドがあるのだが、これは180度を最大値に折り返してしまうため、永久に180度より大きくならない。
なお、分かりやすいように180度と書いているが、実際に返る値はラジアン(180=π)です。

では、どうするのかというと外積を使います。

CGPointVector には内積(dot)はあっても、外積(cross)が無いのでextensionを自作します。
外積の詳しい説明は省きますが、180度以内であれば正の数を、180度を超えると負の数を返します。

```swift
extension CGPoint {
    public func cross(_ other: CGPoint) -> CGFloat {
        return self.x * other.y - self.y * other.x
    }
}
```

これで、変形する前にコーナーが反転しないよう、チェックすることができました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134740/47dcfad4-c5a7-94ba-e51b-92900b7f1f50.png)


**レッツ自由変形！**



Androidでも同じことができるらしいよ！
署名付きURLを使ってカスタムメタデータ付きでファイルをアップロードする方法

# はじめに

署名付き URL を発行した後、HTTP ヘッダーにカスタムメタデータを含めて Cloud Storage にファイルをアップロードしたときに、以下のようなエラーが出てドキュメントを読んでも原因が分からなかったので、この記事を書くことにしました。

```
<?xml version='1.0' encoding='UTF-8'?>
<Error>
    <Code>MalformedSecurityHeader</Code>
    <Message>Your request has a malformed header.</Message>
    <ParameterName>x-goog-meta-foo</ParameterName>
    <Details>Header must be signed</Details>
</Error>
```

# 対象読者

- 署名付き URL を発行して、ブラウザなどからファイルをアップロードする処理を実装している方
- 署名付き URL を発行して、アップロードするファイルにカスタムメタデータを設定したい方

# 本文

## ファイルをアップロードする署名付き URL を発行する処理

```JavaScript:generateV4ReadSignedUrl.js
const {Storage} = require('@google-cloud/storage');

async function main(bucketName, filename) {
  const storage = new Storage();

  const options = {
    version: 'v4',
    action: 'write',
    contentType: 'text/csv',
    expires: Date.now() + 15 * 60 * 1000,
  };

  const [url] = await storage
    .bucket(bucketName)
    .file(filename)
    .getSignedUrl(options);

  console.log(url);
}

main(...process.argv.slice(2));
```

```
$ npm i @google-cloud/storage
$ node generateV4ReadSignedUrl.js my-bucket test.csv
# 署名付き　URL が発行される
```

## カスタムメタデータを設定する方法

カスタムメタデータを設定するには、署名付き URL を発行するとき、つまり getSignedUrl の引数の options に extensionHeaders を設定する必要があるみたい。
これをしないと記事冒頭の MalformedSecurityHeader エラーが出てしまう。

```JavaScript
const options = {
  version: 'v4',
  action: 'write',
  contentType: 'text/csv',
  expires: Date.now() + 15 * 60 * 1000,
  extensionHeaders: {'x-goog-meta-foo': 'bar'},
};
```

また、バケットの CORS 構成の responseHeader にカスタムメタデータのキー名を設定する必要がある。

```json
[
    {
      "origin": ["*"],
      "method": ["*"],
      "responseHeader": ["content-type", "x-goog-meta-foo"]
    }
]
```

## ファイルをアップロードする

発行した署名付き URL に PUT リクエストを送る。
このとき注意してほしいのが extensionHeaders で指定した値をHTTP ヘッダーに含める必要がある。
つまり `x-goog-meta-foo: bar` を含める必要がある。
content-type も含める必要があるかも。

[1] https://cloud.google.com/storage/docs/access-control/signed-urls?hl=ja
[2] https://cloud.google.com/storage/docs/metadata?hl=ja
[3] https://cloud.google.com/storage/docs/access-control/signing-urls-with-helpers?hl=ja#upload-object
Vueでtransitionがうまくいかないとき

動的にサイズを取得してtransitionしてアコーディオンを作っているのにうまくいかない人へ書きます。
# いきなり結言
以下のようにコードを書いていてカクカクするときは、transitionの直下にpaddingやmarginを指定しているか確認しましょう。heightについてtransitionしている場合は、paddingやmarginを0でない値に指定しているとうまくいきません。
というのも、ele.style.height等はpadding等の大きさを含んでないから。じゃないかなと思っていますけど、ちゃんと考えるのめんどくさいので放置しています。
padding等をつけたいときは、transitionに直下に要素を作ってアコーディオンを囲んでしまいましょう。

```
<transition name="accordion" @before-enter="beforeEnter" @enter="enter" @before-leave="beforeLeave" @leave="leave">
アコーディオンのなかみ
</transition>
```

```
methods: {
    beforeEnter(el) {
      el.style.height = '0'
    },
    enter(el) {
      el.style.height = el.scrollHeight + 'px'
    },
    beforeLeave(el) {
      el.style.height = el.scrollHeight + 'px'
    },
    leave(el) {
      el.style.height = '0'
    }
}
```
バリデーション のためにステータスコードを取得する

#概要
ステータスコードが422の場合、バリデーションをフロントに表示したかったので、ステータスコードの取得方法をまとめました。

#解決

```.vue
<script>
export default {
  methods: {
    async submit(){
      await axios.post('/api/account', formData).then(res=>{
        console.log(res.status) 
      }).catch(err => {
        console.log(err.response.status) 
      })
    },
  },
}
</script>
```

ステータスコード
>200の場合:res.status,
エラーの場合:err.response.status
NestJS で加算 (Validation 付き)

こちらのプロジェクトを改造しました。
[NestJS の DTO と Validation の使い方](https://qiita.com/ekzemplaro/items/621ccca751077836fe86)

次のような結果が得られます。

1) 引数が正しい場合

```text
$ http post http://localhost:3000/items aa=23.58 bb=45.19
HTTP/1.1 201 Created
Connection: keep-alive
Content-Length: 5
Content-Type: text/html; charset=utf-8
Date: Fri, 19 Feb 2021 10:59:58 GMT
ETag: W/"5-FuGR3NAEdByFKIjVXtIXUF1c3VA"
Keep-Alive: timeout=5
X-Powered-By: Express

68.77
```

2) 引数に誤りがある場合

```text
$ http post http://localhost:3000/items aa=23.58x bb=45.19
HTTP/1.1 400 Bad Request
Connection: keep-alive
Content-Length: 81
Content-Type: application/json; charset=utf-8
Date: Fri, 19 Feb 2021 11:00:37 GMT
ETag: W/"51-Zwzc1rgvcjQ66LJW52ouMEqR5Yk"
Keep-Alive: timeout=5
X-Powered-By: Express

{
    "error": "Bad Request",
    "message": [
        "aa must be a number string"
    ],
    "statusCode": 400
}
```

改造したのは、次の２つのプログラムです。

```ts:src/items/items.dto.ts
import { IsNotEmpty, IsNumberString } from 'class-validator';

export class CreateItemDTO {

  @IsNotEmpty()
  @IsNumberString()
  aa: number;

  @IsNotEmpty()
  @IsNumberString()
  bb: number;
}
```

```ts:src/items/items.controller.ts
import { Controller, Post, Body } from '@nestjs/common';
import { CreateItemDTO } from './items.dto';


@Controller('items')
export class ItemsController {
  @Post()
  createItem(@Body() createItemDTO: CreateItemDTO) {
	console.log("*** createItem ***")
	var aa:number = Number(createItemDTO.aa)
	var bb:number = Number(createItemDTO.bb)
	console.log("aa =" + aa)
	console.log("bb =" + bb)
	var sum:number = 0.0
	sum = aa + bb
	console.log("sum =" + sum)

    return sum;
  }
}
```
CloudTrailに記録されないS3のデータイベントを取得する

# 問題
IAMの[認証情報レポート](https://console.aws.amazon.com/iam/home?region=ap-northeast-1#/credential_report)をダウンロードして見たときに、アクセスキーを使用してS3にアクセスしている履歴を確認できたがCloudTrailのイベント履歴を検索しても一致するものがない。

※例えばこういう状態
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286189/1c6a9a56-e94b-318b-aebf-c84d420bf567.png)

# 原因
CloudTrailではGetObject、DeleteObject、PutObject等オブジェクトレベルのAPIオペレーションのログはデフォルトでは記録されない。

# 解決方法
CloudTrailで全てのS3のデータイベントを記録するために証跡を作成する。
**※追加料金かかります。**

1. [AWS CloudTrail](https://ap-northeast-1.console.aws.amazon.com/cloudtrail/home?region=ap-northeast-1#/)にアクセス
2. 証跡の作成
3. 証跡名の入力 > ログファイルのSSE-KMS暗号化の有効チェックを外す（ここでは手順を簡易化する為）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286189/e3cee711-cac6-9818-359f-827b2cddc769.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286189/7a97d3c6-41cc-f4b6-3d7b-379346d6b5e0.png)
4. 次へ > イベントタイプ「データイベント」をチェック > 次へ > 証跡の作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286189/39a927a7-d166-24a9-b92e-a2931811e5ac.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286189/83925d1a-ec5c-aff4-afbf-7eed1990bcac.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286189/c65b930e-9eb3-7270-d2fa-4de3155a2ec3.png)

# その他操作・機能
・逆に無効にしたい場合は、証跡またはデータイベントを削除してください。
・高度なデータイベントセレクターを用いることで、writeOnlyイベントのみ記録することも可能
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/286189/bb6f2d50-7fa3-4191-731c-c87ef3917ab4.png)


# 参考
[AWS CloudTrail データイベントで S3 バケットのオブジェクトレベルのログ記録を有効にする方法](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/user-guide/enable-cloudtrail-events.html)
[AWS CloudTrail を使用した Amazon S3 API コールのログ記録](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/cloudtrail-logging.html)
【cookie】secure属性のcookieをhttpで取得できない

タイトル通りだが、secure属性が有効なcookieはhttpの時、`document.cookie()` で取得できない。

そもそも、[(URL に http: を含む) 安全でないサイトは、 Secure 属性を使用してクッキーを設定することができません] (https://developer.mozilla.org/ja/docs/Web/HTTP/Cookies)と記載があるが、同ドメインの場合、httpsでsecure属性を付与したcookieをhttpに持ち歩くことができる。

この場合、httpでは`document.cookie()` でsecure属性のcookieは取得できない。
Animate CC Sound

###Animate CC におけるサウンドの扱い

ブラウザ上でサウンドを再生するにはWEB AUDIO APIなどありますがスマホでは最大発音数の問題があります。

特にゲームにおいては複数の音を同時に扱いますのでこれでは使えません

その点、Animate CC(SoundJS)はスマホにおいても最大発音数の問題はクリアしています。
ブラウザ上でサウンドを扱うには最適ではないかと思っています。

さて、そんなAnimate CCですがサウンドでいくつか苦労しました

デフォルトでhtml上にplaySound()が書き出されますがループ回数くらいしかコントロールできません。

最低レベルとしてサウンドのストップ、ミュートまでは入れたいので組み込んだはいいものの背面に回ったときの処理ができませんでした。

具体的にはスマホで画面を閉じても鳴りっぱなしになってしまいます。

最終的には海外の記事を参考にして次のように落ち着きました。
これでなんとかスマホでも思い通りの挙動になりました

```
//Script
gBgm=playSound(サウンド識別子,ループ回数);//※止める可能性のない効果音などはそのままplaySound

//Global-Script
var gBgm;
function stopSound(){
	if(gBgm==undefined){
		return;
	}
	gBgm.paused ? gBgm.paused = false : gBgm.paused = true;
	gBgm.currentTime = 0;
	gBgm=null;
}
document.addEventListener("visibilitychange", function() {
    stopSound();
});
```

###サウンドの落とし穴 その１

短すぎるサウンドはNG

コンソールでdecode errorが出る場合は短すぎるサウンドがないか見てみるとよいかもしれません。
0.1秒くらいのサウンドはエラーになります。後半に無音をつけてあげれば解決します

###その２

Adobe Auditionで書き出したサウンドにノイズが出る

これは書き出しの際に「マーカーと他のメタデータを含める」にチェックを入れると余分なデータが入るようでサウンドの終わりに「バチッ！」というノイズがのります。
どちらにしてもサウンドに関しては必ず頭とお尻は無音にしないとノイズのもとになります。
Amazon Linux2 で Permission denied (publickey) が出た時の対処法

Amazon Linux2 の EC2 インスタンスに SSH しようとしたら `Permission denied (publickey,gssapi-keyex,gssapi-with-mic).` が出てしまったのでそれの対処をメモとして残しておきます。

## 事象
起こっていた事象としては**入ろうとしているインスタンス側に公開鍵がなかった**でした。
なので、その場合の解決方法を AWS が[解決方法](https://aws.amazon.com/jp/premiumsupport/knowledge-center/ec2-linux-fix-permission-denied-errors/)を提示しています。

確かに SSM なりで公開鍵を追加してあげれば済む問題ですが、ほぼ同じ条件（後述）で別のインスタンスは SSH できていたため腑に落ちなかったので色々調べてみました。

## 調べてみた
まず、 SSH できなかったインスタンスのベースの AMI は Amazon Linux2 をベースにしています。
[packer + CentOS で authorized_keys に公開鍵が登録されない](https://okochang.hatenablog.jp/entry/2013/10/11/101035) という情報があったため、そこかなと思いましたがハズれ・・・。
パーミッション周りかなと思いましたがこれも違う。


途方にくれていた時、上記の「ほぼ同じ条件」というところで、うまくいってた時は Amazon Linux 1 、うまくいかないときは Amazon Linux 2 の違いがあったので、そこかなと考えました。


## 原因
OS の違いが根本的な原因だったわけではなく、真の原因はEC2 起動時に実行される [ユーザーデータ](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/user-data.html) でした。
ユーザーデータは普通のシェル形式ではなく、マルチパート形式で記述することができます。
このマルチパート形式を使っていたのですが、なぜか **Amazon Linux 2 ではマルチパート形式でアスキー文字以外を使用しているとエラーでユーザーデータが実行されない** という不具合があります（Amazon Linux 1 は問題なし）。

どうやら公開鍵の設定は cloud-init で行われているようなので、ユーザーデータが実行されないことで公開鍵も書き込まれなかったようです。そのため、インスタンスに設定した秘密鍵でログインすることができませんでした。

ちなみにセッションマネージャーを使えばこういった鍵問題も気にしなくてよくなりますね。


以上。
再帰的にファイルやディレクトリのRenameを行いたい

### 概要
大量のファイルがあり、名前やディレクトリ名、中身を再帰的に全て置換したいことが業務であった。
あちこち調べて以下のコマンドにたどり着けたのだが、
まとまってなかったので自分のメモを兼ねて投稿

``` shell
// コマンドの中で作成されているバックアップを消すよう
$ find . -name "*.bak" | xargs rm

// ディレクトリ
$ find . -type d | sed 'p;s/hogehoge/fugafuga/g' | xargs -n2 mv
// ファイル名
$ find . -type f | sed 'p;s/hogehoge/fugafuga/g' | xargs -n2 mv
// ファイルの中
$ find . -type f -exec grep -l 'hogehoge' {} \; | xargs sed -i.bak -e 's:hogehoge:fugafuga:g'
```
【Rails】ページごとにタイトルの表示を変える設定 

#はじめに
titleタグのタイトルをページ(view)ごとに、異なる内容を表示する方法です。
以下の画像通り、タイトルに「商品名 - Store」が作成できます。

<img width="300" alt="スクリーンショット 2021-02-19 18.49.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/d73bf503-173e-8e7f-c60d-2fe1e1625780.png">


Qiita初投稿のため、分かりにくい点や間違いがあれば指摘をお願いいたします。


#到達点
以下の4点を達成する
・`products`の`show`ページのタイトルに商品名を表示
　「商品名 - Store」

・`categories`の`show`ページタイトルに、カテゴリー名を表示
　「カテゴリー名 - Store」

・他のページは、固定のタイトルをつける
　「Store」

・`rspec`でテストをグリーンにする

##流れ
① application.html.erbにタイトルの共通化
② application_helper.rbを作成し、タイトルの内容を記述
③ "shared/\_page_title.html.erb"(partial)を作成
④ 各showページに_page_title.html.erbをレンダリング
⑤rspecでhelperのテスト


#①  application.html.erbにタイトルの共通化
application.html.erbのheadタグ内に
<title><%= full_title(yield(:title)) %></title>　と記述します。

```erb:app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title><%= full_title(yield(:title)) %></title>
  </head>
  <body>
　# 省略
```
<br>

#②  application_helper.rbにタイトルの内容を記述


```ruby:app/helpers/application_helper.rb
module ApplicationHelper
  BASE_TITLE = "Store".freeze
  def full_title(page_title)
    if page_title.blank?
      BASE_TITLE
    else
      "#{page_title} - #{BASE_TITLE}"
    end
  end
end
```
`BASE_TITLE`は、定数なので大文字にし、破壊されないよう`freeze`メソッドを使用します。
関数内の引数である`page_title`が空の場合とnilの場合の2つを考慮するため、blankメソッドで確認します。
考慮する理由として、関数は様々なケースを想定するため、関数を呼び出した側でエラーを判定するよりも関数内で考慮するほうが一括で行えて楽なため。
<br>

#③  _page_title.html.erbを作成

各viewで使用するため、sharedフォルダを作成し、_page_title.html.erbを作成します。

```erb:app/views/shared/_page_title.html.erb
<% provide(:title, page_title) %>
 <div class="page-title">
  <h2><%= page_title %></h2>
 </div>
# 省略
```
view内にタイトル文と同じ内容の記述が必要であれば、<%= page_title %> と記述


<br>
#④  各showページに_page_title.html.erbをレンダリング

```erb:/app/views/products/show.html.erb
<%= render partial: 'shared/page_title', locals: { page_title: @product.name } %>
# 省略
```

タイトルに product名-Store が表示されます


```erb:/app/views/products/show.html.erb
<%= render partial: 'shared/page_title', locals: { page_title: @category.name } %>
# 省略
```
同様にタイトルに category名-Store が表示されます
<br>
#⑤  rspecでhelperのテスト

```
$ rails g rspec:helper application
```
Helper specを作成します。
　　

```ruby:spec/helper/application_helper_spec.rb
require 'rails_helper'

RSpec.describe ApplicationHelper do
  describe "#full_title(page_title)" do
    subject { full_title(page_title) }

    context "page_titleが空白の場合" do
      let(:page_title) { "" }

      it { is_expected.to eq("Store") }
    end

    context "page_titleがnilの場合" do
      let(:page_title) { nil }

      it { is_expected.to eq("Store") }
    end

    context "page_titleが存在する場合" do
      let(:page_title) { "sample" }

      it { is_expected.to eq("sample - Store") }
    end
  end
end
```

先程説明したとおり、引数が空白とnilの場合を考慮しテストします。

#参考記事

[Qiitaで良い記事を書く技術](https://qiita.com/t12u/items/8c28484100dfd3a6351b#%E8%AA%AD%E3%81%BF%E6%89%8B%E3%81%AB%E3%81%A8%E3%81%A3%E3%81%A6%E8%AA%AD%E3%81%BF%E3%82%84%E3%81%99%E3%81%8F%E6%9B%B8%E3%81%8F
)
[Qiita(28)画像の大きさ調整](https://qiita.com/kaizen_nagoya/items/cef6ae1fcbdbec9e7be2)
[Markdown記法 サンプル集](https://qiita.com/tbpgr/items/989c6badefff69377da7)
【初心者向け】書いたことが反映されない時(CSS)

#はじめに
CSSに書いたはずのものが何故か反映されない時に、他の記事を試してみたが上手くいかず、イライラする前にチェックするべきことを書きました。

一部のCSSは適用されているのに他のところが適用されていないと思っている場合にも、この方法が有効でしたので、ここに書こうとおもいます。

#解決方法
**1 . `main`と`footer`の初めに`.`を付けない。**

classと間違えて付けてないか確認しましょう。

（例）
・修正前

~~~
.main{
background-color: purple;
}
~~~

・修正後

~~~
main {
background-color: purple;
}
~~~

**2 . CSSを読み込むための名前が間違っていないか確認**

CSSを読み込むためには、headに
**``<link rel="stylesheet" href="読み込みたいファイル名" />``**
と書きます。
その中の、読み込みたいファイル名が間違えていないのか確認します。


**3 . 全角のスペース（　）や全角英数字が入っていないか確認する。**

**4 . カッコやdivタグの数が正しいか確認する。**
インデックスの再構成、再構築

#そもそも中身ちゃんと理解してる？
日々DBへデータが追加されるごとに、どんどんDBのレスポンスが悪くなってくる。
なんとなくインデックスの再構成だったり、再構築をやってみるみたいなことが結構あると思ってます。

自分自身もとりあえずやろう精神がないとは言えないので、詳細な情報をまとめてみました。

#インデックスの断片化って何？？
なんでおそくなるの？
インデックスが断片化してるんじゃない？

####断片化ってなんやねん。

DBは日々更新や削除が行われ、そのたびにインデックスが自動で変更されます。
DBが正常な状態であれば、インデックスのキー値に準拠した順番と物理的なメモリの位置の順序が一致しているはず。
しかし、データの更新で既存のデータを分割して新しいキーを挿入する場合もある、このような変更が大量に行われると、インデックスのキー値に準拠した順番と物理的なメモリの位置の順序が一致しないデータが発生し、断片化している状態になってします。

####なんで断片化すると検索が遅くなるの？
インデックスの断片化が大きい状態では、インデックスが指示しているデータをと検索するために、より多くのI/Oが必要になるため物理的に遅くなる。

####今のDBの断片化状態の確認方法

```sql
--クエリでの確認方法
SELECT a.index_id, name, avg_fragmentation_in_percent  
FROM sys.dm_db_index_physical_stats (DB_ID(N'DbName'), NULL, NULL, NULL, NULL) AS a  
    JOIN sys.indexes AS b 
      ON a.object_id = b.object_id AND a.index_id = b.index_id
WHERE avg_fragmentation_in_percent > 30
```

じゃぁどうやって改善するのかっていうのが、本題のインデックスの再構成、再構築

#インデックスの再構成と再構築の違いってなんやねん。

インデックスの断片化を解消するために利用されるのが、インデックスの再構築、再構成。


インデックスの再構築 (rebuild) と再構成 (reorganize) の違い
 
|                |       再構築 (rebuild)        |       再構成 (reorganize)    |
|:-----------------|-------------------|-------------------|
| 処理対象                |             インデックス全体   |           インデックスのリーフレベルのみ       |
| 同時実行性              |            処理中は処理対象インデックスは使用不可。インデックス全体がロックされる。|       処理中も処理対象インデックスは使用可。処理しているページに対して、そのページの処理中のみロックが保持される       |
| 処理を途中でキャンセルした場合                |  ロールバック |   キャンセルした時点までの処理は有効。   |
| 生成されるトランザクションログレコードの量               |             断片化の度合にほとんど影響されない |      断片化の度合が大きいと多くなる。       |
| 使用するデータファイル内の領域|多い |      少ない     |
|処理完了までに必要な時間|断片化の度合にほとんど影響されない  |    断片化の度合が大きいと長くなる      |

 		
状況にもよるが、先ほどの断片化状態の確認で断片化が30%以上の場合は再構築が望ましい。

また、再構築の場合はインデックスを再作成する。しかし、再作成中は既存のインデックスは削除しない。
そのため一時的にインデックスの容量が2倍になるため、領域を確保する必要がある。

上記のような差があるため、その場にあった対処法を決めたい。
特にロックの範囲が違うので、しっかり同時実行性を担保して実行したいですね。


#最後に
簡単にまとめるとこんな感じ。
ちゃんと理解して使おう。
マテリアルとブループリントで球状の法線を作る

セルルックなどのノンフォトリアル表現では、法線をそのまま出すよりも球状ののっぺりとした法線にしたほうがきれいに見える場合があります。
主にキャラクターの顔周りや、植物などでよく使われる表現です。
今回はUE4のマテリアルとブループリントを使って球状の法線を作る方法をご紹介します。

##マテリアル
シンプルに球状の法線を作るとなると以下のような構成になると思います。
![2021-02-19_18h03_55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369485/c7e05a44-f917-2e45-3f6f-e79deb6491d8.png)
マテリアルのDetailからTangent Space Normalのチェックを切っておきます。
![2021-02-19_18h07_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369485/3b8d8df7-bbc6-21df-412b-705acf1e0bf1.png)

これで立方体でもなめらかな法線に変えることができます。
![2021-02-19_18h05_45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369485/945dcab1-efea-ffff-c239-749231e34827.png)

##オブジェクトの一部にだけ適用する
全体的に法線を丸くしたい場合は上記の方法で十分ですが、キャラクターの顔部分だけなめらかにしたい場合などもあるかと思います。
その場合はブループリントを使うことになります。
こちらのヒストリア様のブログ記事を参考に実装してみました。
[UE4] 動的法線転写について
https://historia.co.jp/archives/11921/

記事にもある通り、頭の位置に置いたコリジョンから位置を取得し、小さいSphereと大きいSphereの間で元の法線とブレンドするというものになります。
![2021-02-19_18h23_56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369485/34140b0b-0cdb-f8fb-e6c5-5b011ce782a2.png)

まずはキャラクターのブループリントからコリジョンを頭の位置に固定します。
頭の位置はアニメーションによって常に動いているので、コリジョンをボーンに追従させる必要があります。
![2021-02-19_18h25_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369485/9e63da73-404a-0b06-36f1-52518deff415.png)
SphereコリジョンをMeshに親子付けしたら、Parent Socketの虫眼鏡マークからHeadボーンを探してアタッチします。
![2021-02-19_18h24_54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369485/3fb5013f-e013-e77e-9fa3-070c7da971a5.png)
これでアニメーションで動いても正確に頭の位置に追従するようになりました。

あとはコリジョンの位置とRadiusを取得し、マテリアル側に渡すだけです。
ヒストリア様の記事とほとんど同じですが、ノードグラフはこんな感じです。
キャラクターBP
![2021-02-19_18h24_16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369485/c5dcfb4f-a472-6ad3-aee3-fc4177833dd4.png)
マテリアル
![2021-02-19_18h38_35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369485/4adf0d5c-e540-91a5-caaa-cbeb9b1d81b8.png)

キャラクター以外にも、植物などに適用するとポリゴン感が軽減されてより馴染みやすくできる場合があります。
元の法線
![2021-02-19_17h36_59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369485/41d43e1b-9858-2b1b-71f5-4b76fbcc4a85.png)
球状法線
![2021-02-19_17h37_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369485/23601389-8d65-e4aa-0744-fda9a145bc5a.png)
「高専キャリア クラウドAI開発講座」_中間報告会編

#どんな記事？
「高専キャリア クラウドAI開発講座」について、進捗を書き記していきます。

その講座なに？ という方は、前回記事を御覧ください。
　　　　→ [「高専キャリア クラウドAI開発講座」に参加してみた @nomukoh](https://qiita.com/nomukoh/items/dd2bd4abed2075ff62ba)

簡単に言うと、"高専キャリア"という団体が主催している "Azureを使ってBotをつくろう"というイベントです。

記事一覧↓
1. [「高専キャリア クラウドAI開発講座」に参加してみた](https://qiita.com/nomukoh/items/dd2bd4abed2075ff62ba)
2. [「高専キャリア クラウドAI開発講座」_中間報告会編](https://qiita.com/nomukoh/items/aa920b6f0dac29a83e89) **→今回の記事**
3. [「高専キャリア クラウドAI開発講座」_Twitter API 登録編](https://qiita.com/nomukoh/items/1032a62ab5b357029856)
4. [「高専キャリア クラウドAI開発講座」_最終報告会編](https://qiita.com/drafts/0d71064cbabc5e3b360c)
#進捗
初級クエスト「オウム返しするTeams BotをAzure上で作る」
**攻略しました！**

中級クエスト「Teams BotをAzure上で作り、プログラムを変更し、おしゃべり内容をカスタマイズする」
**現在進行中...**

初級クエストは おーちょさんの 動画で誰でも作れます！
　↳[【30分でつくれる！】初心者向け Azure Bot開発説明](https://youtu.be/oiqZ7FiKsqM)
![2021-02-14 (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668177/aa0d619b-058b-22df-65de-628b87501632.png)
#中間報告会
先日、中間報告会がありました。
一人ずつ、自己紹介とここまでの進捗を報告。

最後に、良かったプレゼンを一人選ぶということになり、

なんと、**その一人に選んでいただきました！**
ありがとうございます。
![2021-02-19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668177/90769771-12ad-b4fe-5de8-865144324bb4.png)
![2021-02-19 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668177/9d9a8e03-f46d-eed8-3d80-b994517af8f0.png)
**↑ おーちょさん の作ってくださる資料がわかりやすい！**

**それと、、、**
報告会のスライドは ちょまどさん を参考にさせていただきました(笑)
講演をよく見させて頂いております。
[![2021-02-19 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668177/6ea1becd-eb5b-b3a0-cd19-9f1fba18f504.png)](https://youtu.be/m0MH07vcNgE?t=210)
↑　[BitValley2020 - YouTube] 画像をクリックすると該当の動画を開きます
#最後に
最終報告会が３月の中頃にあるはず。
なので、

- Twitterと連携させる
- LINEと連携させる

この２つを目標に頑張りたいと思います。

**ここまで読んでいただきありがとうございました。**
####p.s.
前回Qiita記事を投稿した日に高専キャリアさんが ”お告げまとめサイト” を作ってくださっていました。
→ [クラウドAI開発講座 - お告げまとめ [Hatena Blog]](https://kosen-career.hatenablog.com/cloud-ai-dev)

####Now
- [x]  Azureアカウント作成
- [x]  環境構築
- [x]  おうむ返しBotを作る
- [x]  teamsにアップロード
- [ ]  Twitterと連携
- [ ]  LINEと連携
- [ ]  ・ ・ ・
【Swift】UILabel, UITextField, UITextViewの違い

#はじめに
この記事では、UILabel, UITextField, UITextViewのそれぞれの違いについて簡単にまとめました。
⚠️当方初学のため認識違いがある可能性大です
誤りを見つけた際はコメントにて指摘していただけると幸いです🙇‍♀️🙇‍♂️


#UILabel, UITextField, UITextViewのそれぞれの違い

###UILabel
 - 主に読み取り専用。

###UITextField
 - テキストが長すぎて一度に表示できない場合に、水平方向の文字シーク（実際にはスクロールではない）を提供。通常、短いテキストを入力するために使用する。

###UITextView
 - テキストが長く一度に表示できない場合、垂直スクロールを提供。
【Azure】ApplicationGatewayのドレイン設定の注意点

# 1.はじめに
ApplicationGatewayの動作検証を行う上で躓くポイントがあり、やっと解決ができたので記録。
今回は**ApplicationGatewayの設定値の一つ、ドレインに関するコアなお話**です。

(ApplicationGatewayって何だろう？って方はもう少ししたらその記事を書くのでちょっとお待ちください)
⇒　[【Azure】 Application Gateway 設定を解説する](https://qiita.com/hikaru_motomiya/items/d5fd669e3eb3a8491022)
書いたんですけど、概念の説明というよりは設定値の説明になってしまいました。。。


# 2.ApplicationGatewayの接続のドレインとは

Application Gatewayのバックエンドプールから分散先を削除すると、そのバックエンドプールの分散先へ通信が行われていた場合、クライアントから見れば**突然通信が切断されてしまいます。**

そこで、**ドレイン設定**を利用します。
ドレイン設定を利用すると、**いままで通信していたものは削除されたバックエンドプールの分散先に対して既定の秒数間保持し、それ以外の新規の通信は切り離されたバックエンドプールの分散先へは送信しなくなります。**
これを行うことにより、通信が行われている際にバックエンドプールから分散先を削除しても、その通信完了後に次の通信は他の分散先へ向けて行われるようになるため、通信切断が発生しなくなります。

# 3.ドレインの設定パターン

ドレインは、HTTP設定ごとに設定することができます。
そのため、 **「1つのルーティング規則につき1パラメータ」** を設定することができます。

| ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626338/7483f5b6-6fa2-d0e2-5b30-1763944b10c1.png) |
|:--|

ドレインのデフォルト時間は60秒。
最小値は1秒で、最大値は3600秒。

さて、上記の通りドレインはHTTP設定ごとに設定できるので、次のような形で設定することができます。

| ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626338/33897d15-db97-9d9b-7a57-173224ec52a6.png)|
|:--|

これだと、それぞれの分散対象は30秒、60秒で切断されることになります。

が。が！
実はドレインの設定値は、 **「一つのバックエンドプールに対しては、同じ値となる」** という仕様となっています。
つまり、
上図のような設定を行っても、**長いほうのドレインの設定値が優先される**ようになっています。図でいえば、すべてのドレイン設定が自動的に60秒になります。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626338/4fe5f955-9deb-192c-6750-073c3475c6e6.png)|
|:--|

この仕様については、2021/02/17現在、Microsoftのドキュメント(https://docs.microsoft.com/ja-jp/azure/application-gateway/configuration-http-settings )上では明言されていない仕様です。
といいますか、ドレインの秒設定については、特に説明がないのですよね。。

# 4.終わりに

はい、今回はApplicationGatewayのドレイン設定にはこんな落とし穴があるよ、という記事でした。


~~というかMSさんなんで設定できないようにするかエラー出力しないんですかねぇ~~

# 参考
アプリケーションゲートウェイのHTTPS設定
https://docs.microsoft.com/ja-jp/azure/application-gateway/configuration-http-settings
ubuntuにて初期ユーザー名を変更する

# はじめに
ubuntu-server のdesktop環境にて初期ユーザー名の変更において、[raspbianでのやり方](https://qiita.com/kenchang/items/849c82f16ba5eafe070d)がうまくいかなかったので調べたことのまとめ。
（私の環境では）初期の`ubuntu`ユーザでは何故か`sudo`でパスワードを聞かれず危険。

# 環境
(ubuntu20.04.2 server) + mate-desktop on rpi4

# やりたいこと
desktop環境にて初期設定の`ubuntu`ユーザー名を変更したい。

# 結論
別ユーザーを暫定的に作成し、そのユーザーになってubuntuユーザーの名前を変更する。
その時は**暫定ユーザーのホームディレクトリを作成**する。
名前変更後は`sudo`コマンド時にパスワード入力を求められるようになった。何故かは不明。

# はまり状況
暫定ユーザーのホームディレクトリを作成しないとdesktop環境では暫定ユーザーでログインできなかった。
desktop環境を無効化してから実施しても、何故かうまく行かず。
非desktopのCUI環境であれば、上述のraspbianでのやり方で行けるはずです。

# 具体的なやり方
`ubuntu`ユーザーでログイン。ターミナルを開く。

```bash
$ whoami
ubuntu
$ sudo useradd -m tmp # 暫定のユーサーを作成(ホームディレクトリ付き)。このユーザーは最終的に削除
$ sudo gpasswd -a tmp sudo  # sudoグループに追加
$ sudo passwd tmp # パスワード設定
Enter new UNIX password:
Retype new UNIX password:
Passwd: password updated successfully
$ exit  # logoutする
```

`tmp`ユーザーでログインする。
先程設定した`tmp`ユーザーのパスワードを使用する。
ユーザー名を `ubuntu` --> `kitten` へ変更する。

```bash
$ whoami
tmp
$ sudo usermod -l kitten ubuntu
$ sudo usermod -d /home/kitten -m kitten
$ sudo groupmod -n kitten ubuntu
$ exit  # logoutする
```

`kitten`ユーザーでログインする。
元々の`ubuntu`ユーザーのパスワードを使用する。

```bash
$ whoami
kitten
$ sudo userdel -r tmp  # ホームディレクトリごとtmpユーザーを削除する
$ sudo cat /etc/passwd | grep ubuntu  # ubuntu名はなくなった
$ sudo ls /home
kitten     # ubuntu名はない
```


# 余談

### ホスト名は`hostnamectl`コマンドで変更

```bash
$ sudo hostnamectl set-hostname new_hostname
$ hostnamectl status
```

### デスクトップ環境の無効化と有効化

```bash
$ sudo systemctl get-default  # デフォルト状態の確認
$ sudo systemctl set-default multi-user.target # 無効化
$ sudo systemctl set-default graphical.target # 有効化
```

以上です。
プログラミングスクール卒業！

### 本日、無事に某プログラミングスクールを卒業することができました！

学習中とオリジナルアプリ開発中に、Qiitaに記事を投稿していらっしゃるエンジニアさん達に何度も助けられました。
これからは自分のためにアウトプットの場としてQittaに記事を投稿していきます。
ゆくゆくは自分の書いた記事がプログラミングを勉強しているどこか誰かのお役に立つ日が来たら嬉しいなと思います。

-----
↓にオリジナルアプリで自分が開発したWebアプリのGitHubを載せておきますので興味がある方は是非見ていってください。

【チームでのスケジュール管理アプリ】
https://github.com/yoheitm/grouptask-app
「npm install」を全てcmdで行ってはいけない話

いつものように本番環境ではどのように動くのか試したかったので、以下のコマンドを打つと

```
firebase deploy

update ～ npm i -g firebase-tools
```

的なことを書かれたのでいざ実行するとエラーが発生

```
npm i -g firebase-tools

npm ERR! The operation was rejected by your operating system.
npm ERR! It’s possible that the file was already in use (by a text editor or antivirus),
npm ERR! or that you lack permissions to access it.
npm ERR!
npm ERR! If you believe this might be a permissions issue, please double-check the
npm ERR! permissions of the file and its containing directories, or try running
npm ERR! the command again as root/Administrator (though this is not recommended).
```

npmのエラーは厄介だからこれは時間がかかると思い、案の定２，３時間くらい時間を費やした。

要するに権限が無いよと言う意味。

色々調べてみると、本来なら``C:\Program Files (x86)\nodejs（自分で設定したファイル名）\etc``というフォルダがあるはずなのだが無かった。

なので、一度``npm``のバージョンアップデートしてみる。

```
npm i npm@latest
```

そうすると、無事インストールが完了し``etc``フォルダも作成された。

そして同じように``firebase-tools``を実行すると同じようなエラーが発生😨

```
npm i -g firebase-tools

npm ERR! The operation was rejected by your operating system.
npm ERR! It’s possible that the file was already in use (by a text editor or antivirus),
npm ERR! or that you lack permissions to access it.
npm ERR!
npm ERR! If you believe this might be a permissions issue, please double-check the
npm ERR! permissions of the file and its containing directories, or try running
npm ERR! the command again as root/Administrator (though this is not recommended).
```

このことから、なんでもGitBashでインストールしてはいけないんだなと思った。

なので、Windowsの「Powershell」を「管理者として実行する」と``firebase-tools``をインストールしてみると無事インストールされた！

いや～長かった。

npmのエラーは嫌いです！

以上、「「npm install」を全てcmdで行ってはいけない話」でした！

良ければ、LGTM、コメントお願いします。

また、何か間違っていることがあればご指摘頂けると幸いです。

他にも初心者さん向けに記事を投稿しているので、時間があれば他の記事も見て下さい！！

Thank you for reading
GitHub Actionsを使用してNugetパッケージを自動で公開する

## はじめに
GitHub Actionsを使用してNugetへのPushを自動化することを調べたときのメモです。  

## 参考
下記記事の「Publish NuGet Package」章での内容をメインに実際に動かしながら調べました。
https://netlicensing.medium.com/publish-nuget-packages-using-github-actions-9ac5e97d07d4

## 手順
### ①".github\workflows"内にYAMLファイルを作る。 
以下に示すのは、Nugetプッシュを行うYAMLファイルです。

workflow_runに実行条件を記載しています。詳細を以下に記載します。

- workflow_run：あるworkflowが完了したり、呼び出されたら起動するイベントトリガー
    - workflows:["Build"]：workflowsに登録している`Build`アクションの後に実行します。
    - branches:[ main ]：mainブランチでworkflowsのアクションが行われた際に実行します。  
　　　　　　　　（他のブランチは対象外となる）
    - types: - completed：workflowsで指定したアクションが完了時に実行します。

末尾の方の`with:`以下の内容が重要なところなので後ほど説明します。
jobsの内容については参考にした記事と同じ内容のため、そちらを参照ください。
（Buildの自動化については参考の記事の「Create Actions Workflow」章を参照ください）

```
name: Publish - Nuget

on:
  workflow_run:
    workflows: ["Build"]
    branches: [ main ]
    types:
      - completed

jobs:
  publish-nuget:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - name: Setup .NET
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 3.1.x
    - name: Install dependencies
      run: dotnet restore
      working-directory: src/SlackNotification
    - name: Build
      run: dotnet build src/SlackNotification/SlackNotification.sln --no-restore
    - name: Publish to NuGet
      uses: brandedoutcast/publish-nuget@v2
      with:
        PROJECT_FILE_PATH: src/SlackNotification/SlackNotification.csproj
        VERSION_REGEX: '^\s*<PackageVersion>(.*)<\/PackageVersion>\s*$'
        TAG_FORMAT: '*'
        NUGET_KEY: ${{secrets.NUGET_API_KEY}}
```

### ②NugetのAPIキーを作成する。
Nugetへの公開リクエストを認証するにあたり必要になります。
（APIキーを作成するにあたり、自動公開したいNugetパッケージを1度はアップロードしておかないとキーを関連付ける対象に選べないので注意）
右上のアカウント情報からAPI Keysを選択し、Createから作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1062357/e50398eb-6554-fc39-85a6-7929e6f077f0.png)

下記のように設定し、作成する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1062357/1be652e5-0d65-c0cf-11b0-5cca257568f0.png)


作成後は、APIキーをどこかにコピーしておきます。(作成したタイミングでしか確認できないため)

### ③YAMLファイルの`with:`以下の内容を記載する。

```
      with:
        PROJECT_FILE_PATH: src/SlackNotification/SlackNotification.csproj
        VERSION_REGEX: '^\s*<PackageVersion>(.*)<\/PackageVersion>\s*$'
        TAG_FORMAT: '*'
        NUGET_KEY: ${{secrets.NUGET_API_KEY}}
```
`PROJECT_FILE_PATH`はプロジェクトファイルを指定しますがcsprojの方にNugetの入力項目となる要素を記述しておく必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1062357/a39be4eb-0e06-3bef-20ed-590cf33af52c.png)
`VERSION_REGEX`はプロジェクトファイル内のPackageVersionの内容を正規表現で取り出しています。
PackageVersionだけは今後も手動で更新する必要があります。

`NUGET_KEY`は`${{secrets.NUGET_API_KEY}}`を指定していますが、これはGitのSettingのSecretsで指定した環境変数を取得しています。
GitのSettingsからSecretsのRepository secretsにNugetのAPIキーを設定します。右上のNew repository secretから追加できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1062357/07771d9f-1235-4a28-3fd3-72e73b376ce5.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1062357/658332db-630b-7f61-98da-c8298f905c46.png)

ここまで設定できればmainブランチにプッシュした際にNugetに自動公開されます。
Developers Summit 2021 の「プロダクトマネジメントを組織に宿す取り組み「アジャイル・ブリゲード」の実践」で学んだこと

# はじめに

本稿は、Developers Summit 2021 の以下のセッションで学んだことを書きます。

セッション名：プロダクトマネジメントを組織に宿す取り組み「アジャイル・ブリゲード」の実践
講演者：市谷 聡啓[レッドジャーニー]
セッション詳細：https://event.shoeisha.jp/devsumi/20210218/session/3096/

(『カイゼン・ジャーニー』『チーム・ジャーニー』の著者の人の発表です)

# 学んだこと

DX（デジタルトランスフォーメーション）とは、テクノロジーを活用したサービスや事業を創出し、顧客体験を再定義すること。
それにより「新たな価値」を生み出し続けられる組織になることが最終目標。

以下、DX1周目の苦闘を紹介。

一休さんの屏風のトラDXのような失敗があった。

- 良いロードマップはあるが、その体制がない
- プロジェクトを立ち上げるが、狙いと作戦が弱く遂行で失敗

探索的な取り組みにおける最大の失敗は、何も学べていないこと
(学びがあれば、一定の収穫があったと考えられる)

変革に取り組むと、様々な分断が発生する。

- これまで と これから
- 既存事業 と 新規事業
- 全体 と 詳細
- 経営 と 現場

これまでの影響から隔離した実験場としての組織を別で作る(出島のようなものを作る戦略)。

これまでとこれからでは、求められる「組織能力」が異なるので、従来の評価軸で評価しない。

ただ、出島だけでは組織全体は変わらない。
既存の組織とは、なかなか変化を受け入れられず、衝突することがしばしばある。

したがって、「変革」「アップデート」という概念でなく、「二項動態」という概念を用いる。
概念と役割、組織それぞれの独立性を保ちながら、連携・提携してやっていく。

以下、DX2周目の紹介。

DXは結果が必ずでるわけではないため、活動の方針や決定が噛み合わなくなることが多い。
(全体像が分からないなどの声が紛糾する)

全体を段階（ジャーニー）で分ける。
全体をスケジュールでなく、１～３ヶ月のタイムボックス(ジャーニー)で定める。
各ジャーニーの終わりに、振り返り、全体と個別活動の意思決定をし直す。

経営と現場は、方向性が一致していても、解像度が違うため、不一致が発生する。
そこで、それをつなぐミドルのマネージャーが必要。

個別PJで解決できない全社課題をCoE（Center Of Excellence）に集める。

既存事業と新規事業の不協和問題
新規と既存の分断をメタチーム(CoE)がなんとかする。

対立する2種類のチームをなんとかするCoEを「アジャイルブリゲード」と定義する。
なんとかするのは「やったらいいじゃない」ではなく「ともにやる」。
アジャイルブリゲードは、外部の専門人材も入れて、内部との混在チームにする。

アジャイルブリゲードが組織の対立をなんとかするためには「ブリッツ・トラスト(電撃的な信頼)」を得ること。最初の結果が出すことが最重要。
最初の結果を得るために、持続可能性は無視して、一旦ブレーキを壊してでも、最初の結果を得ることに集中する。

大企業、伝統的な組織ほど「変革の求心力」が求められる。
顧客体験を変えるだけでなく、自分たちの組織を変えるためのプロダクトを作ることが、変革の求心力になる。


# まとめ
組織の変革をすすめるための方法を学ぶことができました。

ちなみに私は、普段はエンジニアリングマネージャーとして、チームの皆で楽しく開発する施策を色々実施しています。詳しくは以下を参照ください。
[1年以上かけて生産性倍増＋成長し続けるチームになった施策を全部公開](https://qiita.com/kojimadev/items/4b28f801863cf4e8f0da)

Twitterでも開発に役立つ情報を発信しています → [@kojimadev](https://twitter.com/kojimadev)