OmniAICreator/Qiita-1.07M huggingface dataset:
システムの開発手法、ユーザインタフェース、コード設計と入力のチェック、テスト

#システムの開発手法
　代表的な開発手法以下の通り

　**・ウォータフォールモデル**
　　開発としてはもっとも古くからあるもので、要件定義、システム設計、プログラミング、テストと
　　各工程を順番に進めていくもの

　**・プロトタイピングモデル**
　　開発初期の段階で試作品を作りそれを利用者に確認してもらうことで開発側との意識ずれを防ぐ手法
　　※大規模なシステム開発には向いてない
　**・スパイラルモデル**
　　システムを複数のサブシステムに分割して、それぞれのサブシステム事に開発を進めていく手法

#ユーザインタフェース
　ユーザインタフェースはシステムに人の手がふれる部分。
　システムの「使いやすさ」に直結する。

　**・CUI**
　　画面に表示されるのは文字だけでそのコンピュータに対して入力するのも文字だけ。
　　文字を打ち込むことで命令を伝えて処理させていた。
　　このような文字ベースの方式をCUIと呼ぶ

　**GUI**
　　画面にアイコンやボタンを表示して、それをマウスなどのポインティングデバイスで操作して
　　命令を伝えるといったグラフィカルな操作方式がGUIと呼ぶ

#モジュールの分割技法
　分割技法のうち「データの流れ」に着目した技法は以下の通り
　
　**・STS分割割**
　　プログラムを入力処理、変換処理、出力処理という３つのモジュール構造に分割する方法
　**・トランザクション分割法**
　　プログラムを一連の処理(トランザクション)単位に分割する方法
　**・共通機能分割法**
　　プログラム中の共通機能をモジュールとして分割する方法

#モジュールの独立性を測る尺度

　**・モジュール強度**
　モジュール内の機能が、内部でどのように関連ついているか示す尺度
　これが高いほどモジュールの独理性が高くて好もしい。
　図
　**・モジュール結合度**
　モジュールが他のモジュールとどのように結合するかを示す尺度
　これが弱いほどモジュールの独立性が高くて好ましい。
　図
　
#テスト
　作成したプログラムはテスト工程で各種検証を行い
　欠陥を洗い出しと回収を行うことで完成に至る。
　
#テストの流れ
　テストはまず、部品単位の信頼性を確保するところから始まる
　そのために行われるのが**単体テスト**です。このテストは核モジュールごとにテストを行って、誤りがないかを検証する。
　単体テストが終わると次に待つのが**結合テスト**
　結合テストでは複数のモジュールをつなぎあわせて検証を行い、モジュール間のインタフェースが正常に機能しているか
　確認する。

#ブラックボックステストとホワイトボックステスト
　
　**・ブラックボックステスト**
　ブラックボックステストは、モジュールの内部構造は意識せず、入力に対して適切な出力が仕様通りに
　得られるかを検証する。
　**・ホワイトボックステスト**
　ホワイトボックステストは、逆にモジュールの内部構造が正しく作られているかを検証する。
　入力と出力は構造をテストするための種過ぎない

#テストデータの決めごと
　**・同値分割**
　　同値分割は、データは二を種類ごとのグループに分け、それぞれから代表的な値を抜きだして
　　テストデータに用いる
　**限界値分析**
　　限界値分析は、上記グループの境目部分を重点的にチェックします。この方法は
　　協会前後の値をテストデータに用いる。


#トップダウンテストとボトムアップテスト
　結合テストでモジュール間のインタフェースを確認する方法は以下２種類

　**・トップダウンテスト**
　　上位モジュールから、先にテストを済ませていくのがトップダウンテスト
　**ボトムアップテスト**
　　トップダウンテストとは逆に書きモジュールからテストを行うのがボトムアップテスト

#以上
ASP.NET Web APIの自動デシリアライズでInternal Server Error(500)

# 現象

クライアントからASP.NetのWebApiを呼び出した際に、自動でパラメータがデシリアライズされるが、
あるデータクラスで受け取ろうとした場合に、HttpStatusCode:500を吹いてエラーになる。

```C#:***Controller.cs
        [HttpPost()]
        public async Task<ActionResult> Post(Photo photo)
        {
            return Ok();
        }
```

```C#:Photo.cs
    public class Photo{
        public string name{get;set;}
        public string src{get;set;}

        public Photo(string name, string src){
            this.name = name;
            this.src = src;
        }
    }
```

```:送りつけてるデータ
    { name: "aaa", src: "ccc"}
```

```:エラー内容
System.NotSupportedException: Deserialization of reference types without parameterless constructor is not supported. Type '*****.Models.Photo'
   at System.Text.Json.ThrowHelper.ThrowNotSupportedException_DeserializeCreateObjectDelegateIsNull(Type invalidType)
```

# 原因
デシリアライズ時に引数無しのコンストラクタが無いため、エラーとなっていた。
そりゃそうか。。。

```C#:Photo.cs
    public class Photo{
        public string name{get;set;}
        public string src{get;set;}

        public Photo(){}

        public Photo(string name, string src){
            this.name = name;
            this.src = src;
        }
    }
```
validate()メソッドを使って自動で作成されたパスを使用しなくする(Nuxt.js)

## なぜ必要か
Nuxt.jsでは/pagesディレクトリ内にvueファイルを作成すると自動でパスを作成してくれる機能がある。
しかし、pages/user/settingsみたいにuserパスを使わずsettingsパスのみを使いたい場合にもuserパスが使われてしまうので、使用できないようにする。
## やり方
使用したくないパスのファイルに以下を記述

```/pages/user.vue
<script>
export default {
  // 追加
  validate ({ route }) {
    return route.name !== 'user'
  }
}
</script>
```

# 解説
validate() はパスのアクセスを管理するメソッド。このメソッドによって使用したくないパスの管理ができる。

route.name !== 'user' はルート名が’user’ではない時にパスを通す。

これで/userにアクセスしても４０４エラーが表示される
tar.gzが展開できない

# はじめに
tarでtar.gzファイルを展開しようとしたところ、エラーが出てうまくいかないという事象に遭遇したため、トラブルシューティングと解決方法をまとめてみｍた。

# 結論
curlでtar.gzファイルが正しくダウンロードできていなかった。curlコマンドを見直して解決

# 切り分け
fiileコマンドを使うことでtarファイルであることを確認できる。

## 正しいtar.gzファイル

```console:
[root@redmine: # file ruby-2.6.5.tar.gz
ruby-2.6.5.tar.gz: gzip compressed data, was "ruby-2.6.5.tar", from Unix, last modified: Tue Oct 1 20:01:03 2019, max compression
```

## curlが失敗していたtar.gzファイル

```console:
[root@redmine: # file ruby-2.6.5.tar.gz
ruby-2.6.5.tar.gz: XML 1.0 documen, ASCII text
```
cronでシェルスクリプトを実行する

#はじめに
cronでシェルスクリプトを実行するタスクがあり、色々コマンドを実行したため備忘録を残します。

#cronとは
cronとはスクリプトを自動で実行してくれるデーモンプロセスです。
決まった命令をこの時間に実行して欲しいという場合に有効で、バッチ処理に似たような処理と認識しています。

今回はデータベースの古いファイル(3日前以前)を夜間4時に削除するというシェルスクリプトを作成しました。

#cron実行
cron実行までの流れ
###まずはcron登録
cronを実行するにはcrontabへ実行したいファイルを新規に登録します。

```
$ crontab -e
```

実行するとviエディタが開くので、キーボードのiを押してINSERTモードにします。
今回はsample.shファイルを早朝4時に実行するという命令をcrontabに登録しました。

```
04 00 * * * /root/bin/sample.sh
~
~
~
~
~
```

登録後は:wqで保存し終了します。

実行時間のコマンドなどは以下のページを参考にしました。

「クーロン(cron)をさわってみるお」 https://qiita.com/katsukii/items/d5f90a6e4592d1414f99
dotnet csproj 向け nuget/nuspec プロパティー参考例

.NET Framework の頃は `nuget pack` で nupkg を作成する際に、パッケージ情報を記した `TheApp.nuspec` を別途用意する方法が恒例でありましたが…

.NET Core からは `dotnet pack` で nupkg を作成する際に、パッケージ情報を `TheApp.csproj` で指定するようになりました。関連するプロパティー名称がパッと出てこないので、自分用にまとめました。

TheApp.csproj

```xml
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net40</TargetFramework>

    <PackageId>TheApp</PackageId>
    <Version>0.1.0</Version>
    <PackageReadmeFile>README.md</PackageReadmeFile>
    <Authors>me</Authors>
    <Company>me</Company>
    <Description>Some text.</Description>
    <!-- https://spdx.org/licenses/ -->
    <PackageLicenseExpression>LGPL-2.1-or-later</PackageLicenseExpression>
    <PackageProjectUrl>https://github.com/owner/repo</PackageProjectUrl>
    <RepositoryUrl>https://github.com/owner/repo.git</RepositoryUrl>
    <RepositoryType>git</RepositoryType>
  </PropertyGroup>

  <ItemGroup>
    <None Include="../README.md" Pack="true" PackagePath="\" />
  </ItemGroup>
</Project>
```

SPDX License List: https://spdx.org/licenses/

よく見る・よく使うライセンス：

- `Apache-2.0`
- `BSD-2-Clause`
- `GPL-2.0-or-later`
- `LGPL-2.1-or-later`
- `MIT`

参考:

- [MSBuild ターゲットとしての NuGet の pack と restore | Microsoft Docs](https://docs.microsoft.com/ja-jp/nuget/reference/msbuild-targets)
- [.NET Core の csproj 形式に追加されたもの - .NET Core CLI | Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/core/tools/csproj#nuget-metadata-properties)
Python3 | リスト・タプル・辞書

# リスト
* 複数の値をまとめることができる
* __[ ]（ブラケットの角括弧）__を使う
* 各要素は , （カンマ）で区切る

```python
a = [apple, banana, orange]
```

## 各要素の取り出し
変数名の直後に[ ]をつけ、数値を代入すると各要素が取り出せる。

```python
a = ['フシギダネ', 'ヒトカゲ', 'ゼニガメ']

print(a[0]) # フシギダネ
print(a[1]) # ヒトカゲ
print(a[2]) # ゼニガメ
```

 : を使うことでリストのまま取り出せる。

```python
a = ['フシギダネ', 'ヒトカゲ', 'ゼニガメ']

print(a[0:3]) # ['フシギダネ', 'ヒトカゲ', 'ゼニガメ']
```

## リストの中のリスト
リストの中にリストを収納できる。このとき、[ ] で取り出せるのは、
リストの中のリストだけであることに注意。

```python
a = [['フシギダネ', 'ヒトカゲ', 'ゼニガメ'], ['チコリータ', 'ヒノアラシ', 'ワニノコ']]

print(a[0]) # ['フシギダネ', 'ヒトカゲ', 'ゼニガメ']
print(a[1]) # ['チコリータ', 'ヒノアラシ', 'ワニノコ']
```

# タプル
* リストと同じく複数の値をまとめることができる
※ただし、各要素の追加や消去、場所の移動などはできない
* __( )（パーレンの丸括弧）__を使う
* 各要素は , （カンマ）で区切る

```python
b = {'キモリ', 'アチャモ', 'ミズゴロウ'}
```

### リストとタプルの違いは？
リストとタプルの大きな違いは__mutable(変更可能)__か
ということである。

「変更可能のほうが便利じゃないか」と思われるかもしれないが、
タプルにすると変わってほしくないデータに対して便利になる。

例えば、地図の緯度経度など__半不変的なデータ__は変更して欲しくないので、
このようなときにタプルが使われる。


# 辞書
* key(キー)とvalue(バリュー)の組合わせで使われる
※これをkey value pair(キーバリューペア)という
* リストと同じくmutable(変更可能)
* __{ }（ブレースの波括弧）__を使う

```python
c = {'ナエトル': 'Grass', 'ヒコザル': 'Fire', 'ポッチャマ': 'Water'}

print(c['ナエトル']) # 'Grass'
print(c) # {'ナエトル': 'Grass', 'ヒコザル': 'Fire', 'ポッチャマ': 'Water'}
```

## 要素の入れ替え・追加
キー自体に代入することで、要素の入れ替えができる。

```python
c['ナエトル'] = '草'
print(c['ナエトル']) # '草'
```

同様にキーとバリューをセットにすると、要素の追加ができる。

```python
c = {'ナエトル': 'Grass', 'ヒコザル': 'Fire', 'ポッチャマ': 'Water'}

c['ピカチュウ'] = 'Electric'
print(c) # {'ナエトル': 'Grass', 'ヒコザル': 'Fire', 'ポッチャマ': 'Water', 'ピカチュウ': 'Electric'}

```
iOS14 IDFA取得時の挙動を実機で検証してみる

### 2020/09/16：追記
iOS14 GMでも、**同じ挙動となる**事を確認しました。
日本時間 9月17日にリリースされる正式版でも恐らく同じ動きになる可能性が高いと思われます。

### 2020/09/17：追記
iOS14 正式版でも予想通り**同じ挙動**ですね。
Firebaseや広告SDKなどからも軒並みアップデートのお知らせが来ていますが、この仕様への対応と思われます。


## 概要

iOS14（ベータ版）では、**常にisAdvertisingTrackingEnabledがfalse**を返してくる様です。

AdSupport Frameworkの**isAdvertisingTrackingEnabled**は

iOS13までの「追跡型広告を制限」をチェックする為のフラグでしたが

iOS14で**Deprecated**となりました。

先日リリースされたiOS14 beta8で、実際の挙動について検証してみました。


## 環境
- xcode12.0 beta 6
- iOS14 beta8
- iPhoneX(トラッキング制限設定無し)

## 結果

結果は以下の通り

|ビルド  |isAdvertisingTrackingEnabled  |IDFA  |
|---|---|---|
|iOS13向け|false  |取得OK  |
|iOS14向け（IDFA許諾は未決定。ダイアログ出していない）  |false  |取得OK  |

やはり、ユーザのIDFA許諾状況に依らず、**isAdvertisingTrackingEnabledは常にfalse**が返ってくる結果でした。

つまり、現在リリースしているアプリをiOS14で実行した場合。

**iOS13で追跡型広告を制限（LAT）していなかったユーザ**であっても、iOS14では**「制限あり」と判断**してしまいます。
（従来コードのままだと、IDFAを取得しないフローに流れてしまう）

## 懸念

多くのアプリが、**isAdvertisingTrackingEnabled**をチェックせずにIDFAを取得するフローは、審査上取っていないと思います。

このままの仕様でリリースされた場合、

せっかくIDFA許諾必須化が来年初旬まで延期されたにも関わらず

この挙動に対応していないアプリからは**「IDFAが取得出来ない」**状況になる可能性が高いです。


## 対策

この仕様への対策として

**AppTrackingTransparencyの許諾ステータスをチェック**

↓

**許諾済み以外の場合、まずIDFAを取りにいき**

↓

**返値がゼロ以外であれば、そのままIDFA使用**

と言ったパターンなどが考えられます。

例えば

```swift
func isAvailableIDFA() -> Bool {
        if #available(iOS 14.0, *) {
            if ATTrackingManager.trackingAuthorizationStatus == .authorized {
                return true
            }else{
                // .authorized以外
                // 有効なIDFAか?
                return !isZeroIDFA()
            }
        }else{
            // iOS13以下
            return ASIdentifierManager.shared().isAdvertisingTrackingEnabled
        }
}

func isZeroIDFA() -> Bool {
        return (ASIdentifierManager.shared().advertisingIdentifier.uuidString == UUID(uuid: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)).uuidString)
}
```

ただ、この辺りの最終的な挙動はもうすぐ出るであろうGM版で、どうなるかまだわかりません。

引き続き、チェックしていきたいと思います。

---
参考
https://developer.apple.com/documentation/adsupport/asidentifiermanager/1614148-isadvertisingtrackingenabled
https://developer.apple.com/documentation/apptrackingtransparency
UnrealEngine4 ゲームプレイフレームワークについて各種機能を簡単に解説！

##Unrealに書いてある公式リファレンスを見て....

読んでみたものの個人的には難しく書いてあってよくわからない！
開発していると普通に使ってるけど本当に理解してる？
なんてことありませんか？
今回はそこを簡単に説明していこうと思います。

あくまでもこれなんだっけって思ったときに
最低限必要な知識として解説します。

下記がフレームワーク回りを説明している記事
https://docs.unrealengine.com/ja/Gameplay/Framework/QuickReference/index.html

##解説

<img width="600" alt="度とラジアン.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/712841/7e9d1fc6-3e10-338d-ecbc-3406c84e3383.png">

###UObject
 UE4で定義される多くのクラスはUObjectを継承しています。
UObjectに関してはポインタにUPROPERTYをつけることによりエンジン側でメモリを管理してくれます。


###Actor
Level(World上)に配置可能なオブジェクトです。
もちろん、ゲームプレイ中にSpawnやDestoryすることが可能ですべてのActorの基本クラス。
(Unityで言うところのGameObject)
Componentを追加で付与することもできます。
他にも様々なタイプのActorが存在しています。
例
StaticMeshActor :壁や床などのMesh
TriggerActor : イベントによって実行可能トリガー
PlayerStartActor : その名の通りプレイヤーがスタートする位置を決める


###Component
Componentには様々なタイプが存在していてそれぞれがActorにアタッチができます。
例
#####ActorComponent 
再利用可能なComponentとして作成されており、できるだけ１つのActorに依存しないように作成します。
Transformやコリジョンはありません。
#####SceneComponent
Transformを所持しており位置、回転、サイズなどWorld上で操作可能です。
#####PrimitiveComponent
物理、コリジョン（ボックス、カプセル、球体）、オーバーラップなど
#####StaticMeshComponent
壁や床などのMesh


###Pawn
プレイヤーやAIによって制御可能なすべてのActorの基本クラス。
キャラクターなどを作成する際に最低限必要な機能があるのでその用途で使われます。
その他にも物理的な表現が可能だったりContorollerを所有することが可能。


###Character
Pawnクラスより高度な機能を備えたCharactorクラスでPawnを継承したクラス。
Pawnより人型のキャラクター作成に向いていて、
歩行、走行、ジャンプ、飛行、水泳を行るようにComponentが付属しています。


###Controller
Pawnに指示を出すためのActorです。
ControllerにはPlayerControllerとAIControllerの２つがあります。

#####PlayerController
基本的にはプレイヤーにジャンプや移動などをさせるときにこの機能を使います。
しかしPawnなどに実装すべてを書くことが可能なのでその点を注意しましょう。
用途としては
クライアントに複数のプレイヤーがいたり、動的にプレイヤーを変更したいなど複数のニーズがある場合に使うのがいいでしょう。
#####AIController
ずばりAI的な行動するときに使うものです。
PlayerContollerはプレイヤーの入力を待つものですがAIContollerはゲームワールドの入力に対応していて
ワールドを観察し行動など選択します。NPCなどに使います。


###HUD
ゲーム画面に出てくるHUD(Headup Display)を制御するクラス
PlayerContorollerから取得することができます。
１つのLevelにつき１つのHUDを作成することができます。
HUDにはUserWidget（UI）をつけることで現在のHPなどを表示することが可能です。

###Camera
CameraActorとPlayerCameraManagerが存在しています。
#####CameraActor
ワールドに配置可能なカメラ。プレイヤーに依存しない。
#####PlayerCameraManager
PlayerContorollerに紐付けされていて
プレイヤーがどのようにみているのかをプレイヤー視点で表します。


###GameMode
ゲームの定義（例：勝敗やゲームルール）
GamoModeはサーバー上でのみ存在していてプレイ中に変化してはいけませんしプレイヤーの一時的なデータを保有してはいけません。

###GameState
ゲームの状態（例：スコア、プレイヤーリスト）
接続されたプレイヤーのリストやスコアを保持します。
すべてのサーバー上とクライアント上に存在しています。

###PlayerState
プレイヤー個人（例：残機や名前）
自身のステータスを管理します。
プレイヤー一人一人に存在していて
すべてのサーバー上とクライアント上に存在しています。
しかしAIはPlayerStateを持ちません。
※PlayerStateと聞くとプレイヤーのすべての状態管理するように思いがちですが実際はPawnなどに実装し、残機やPawnが死んだあとも継続して残りづづけるものなどをPlayerStateに書くようしましょう。

###Interface
ある情報を共有するためのものです。
複数のActorのクラスに設定することが可能です。
これを使うことにより異なるオブジェクトを同タイプのオブジェクトと判断したりいずれかが実行されたときに伝えることができます。

###GameInstance
GameInstance はエンジンが起動するとき真っ先に 1 つ生成され、エンジンの電源を落とすまで破壊も差し替えも行われません常にシングルトンとして動作します！）
ゆえに、ゲーム全体に関わる挙動を定義するのに最適なオブジェクトです。
アクターではないのでレベルに依存しません。
よって、レベルを跨いでも存在し続けられるので、
レベル遷移しても保持しておきたい値をキャッシュするのに最適なオブジェクトです。
DefaultEngine.iniで設定することが可能です。

##まとめ
UnrealEngineには様々な機能があり複雑でわかりにくい！なんてことがあるでしょう。
ですがこれらを的確に正確に使うことで今後の管理などが楽になります。
みなさんもぜひ勉強してUnrealマスターになりましょう！

##最後に
以上でゲームプレイフレームワークについて各種機能の解説は終了です。
間違っていたりした場合は教えてください。
Introduction to Functional Programming in Rust写経

[YOW! Lambda Jam 2019 - Amit Dev - Introduction to Functional Programming in Rust](https://www.youtube.com/watch?v=9x7W3_KKKeA)という動画を見たら、簡潔なコードサンプルがたくさん紹介されていたのでメモする。

# [YOW! Lambda Jam 2019 - Amit Dev - Introduction to Functional Programming in Rust](https://www.youtube.com/watch?v=9x7W3_KKKeA)

## 0 value

```rust:Rust
enum Void {}
```

```haskell:Haskell
data Void
```

## 1 value

```rust:Rust
enum Unit {
    Unit
}
// or
()
```

```haskell:Haskell
data Unit = Unit
-- or
()
```

## 1 + 1

```rust:Rust
enum Direction {
    Up,
    Down
}
// or
bool
```

```haskell:Haskell
data Direction = Up | Down
-- or
Boolean
```

## 1 + A

```rust:Rust
enum Option<A> {
    Some(A),
    None
}
```

```haskell:Haskell
data Maybe a = Just a | Nothing
```

## A * Boolean

```rust:Rust
(A, B)
// or
struct Tuple { a: A, b: B }
```

```haskell:Haskell
data (a, b) = (a, b)
```

## L = 1 + AL

```rust:Rust
enum List<A> {
    Nil,
    Cons(A, Box<List<A>>)
}
```

Rustでは、Boxを使って可変を表現する。

```haskell:Haskell
data List a =
            Nil |
            Cons a (List a)
```

## Pattern Matching

```rust:Rust
struct Person {
    name: String,
    address: Option<String>
}
//...
match person {
    Person { name, address : Some(s) }
        => (name, s.len()),
    Person { name, address : None}
        => (name, 0)
}
```

## Pattern Matching

```rust:Rust
fn age_type(age: Option<i32>) -> & static str {
    match age {
        Some(val) if val < 0    => "Negative",
        Some(val @ 0 ... 18)    => "Less than 18",
        Some(val) if val > 150  => "Over 150",
        Some(val)               => "Adult",
        None                    => "Empty"
    }
}
```

## Factorial - Take 1

```rust:Rust
fn factorial(n: u64) -> u64 {
    match n {
        0 | 1 => 1,
        n     => n * factorial(n - 1),
    }
}
```

## Factorial - Take 2

```rust:Rust
fn factorial(n: u64) -> u64 {
    (1..n+1).fold(1, |acc, i| acc * i)
}
```

```rust:Rust
use std::ops::Mul;

fn factorial(n:u64) -> u64 {
    (1..n+1).fold(1, Mul::mul)
}
```

# 振り返り
1. Youtubeにはもっとたくさんの簡潔なコード例が紹介されているようだ。手になじむように書いていこう。
Nuxt.jsで本番リリースするために必要な細々したこと

## はじめに

Nuxt.jsを利用して開発したサービスを本番リリースする時に、忘れがちな変更しておいたほうがいいところなどを備忘録的にまとめます。

### favicon.ico

`static/favicon.ico`にNuxt.jsのfaviconが残っているので、自分たちのサービスアイコンに変更しましょう。

### タイトル

デフォルトの設定が、nuxt.config.jsに設定されており、そのままにすると、`npm_package_name`がブラウザのタイトルに設定されて、格好悪いです。

変更しておきましょう。

```
title: process.env.npm_package_name || '',
```
↓

```
title: 'サービス名を指定しよう',
```

### 外部scriptの読み込み

例えば、Twitterのフィードを表示する場合に、Twitterの設定画面から出力したhtmlを貼り付けても、`yarn dev`で起動した場合は、問題なく動きますが、`yarn build&yarn start`で動かすとうまく動かなくなります。

```
<a class="twitter-timeline" href="https://twitter.com/TwitterDev?ref_src=twsrc%5Etfw">Tweets by TwitterDev</a> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
```

`yarn build`した際に、script部分がなくなってしまうぽいです。

このような時は、nuxt.config.jsにscriptを読み込ませる設定をしましょう。

head項目のところに追加します。

```
head: {
・・・
・・・
・・・
    script: [{
      src: 'https://platform.twitter.com/widgets.js', body: true
    }]
  },
```

`body: true` というオプションを渡すことで、 `</body>` タグの直前に読み込ませることが可能です。

### axiosのリクエスト先

vue.jsからのhttpリクエストを行う際に利用するモジュールに、axiosを選択することが多いかと思います。
そして、開発時には、サーバサイドのAPIのURLが、localhostで、本番の場合、ドメインを指定することがあるかと思います。

そのような場合は、きちんと書き換える必要があります。

nuxt.config.js内のaxiosの設定が、以下のようになっている場合、
.envファイルを作成して、設定が必要です。

```
axios: {
  baseURL: process.env.BASE_URL || 'http://localhost:3000'
},
```

```.env
BASE_URL="https://api.service.com/"
API_URL="https://api.service.com/"
```

API_URLもaxiosから参照されているという記事をみたことがある気がするので、念の為設定しておりますが、BASE_URLだけでも問題ないかもしれません。ここは確認できていないです。

また、.envファイルは、gitignoreに登録して、pushしないように注意してください。

### deamon化

仮にサーバサイドの処理を、Nuxt.jsを利用して作成している場合にプロセスをdeamon化する必要があります。
利用可能なモジュールは色々ありますが、今回は、[forever](https://github.com/foreversd/forever)を利用してdeamon化します。

package.jsonのstartコマンドを以下に書き換えます。

```
"start": "nuxt start",
```
↓

```
"start": "forever start -c 'nuxt start' ./",
```

これでdeamon化できます。

### 最後に

アプリケーションを作成して、いざ本番環境へリリースする時に、細々した変更などを忘れてしまうことが多いかと思います。再度リリースのやり直しなど、結構面倒なので、忘れずに対応しておくことをおすすめします。

Subroqは、企業のフリーランスエンジニアの採用や活用を支援するサービスを提供しております。また、フリーランスエンジニア向けの記事も書いておりますので、興味ある方は是非、ご一読いただければと思います。

https://subroq.com
CapistranoでGit LFSを使う

[Git LFS](https://git-lfs.github.com/)で管理されたファイルがあるリポジトリをcapistrano(3.14.1)で配備してもリンクのまま配備されてしまいます。ホスト側にgit-lfsをインストールしてみたのですが結果は変わらずでした。

という訳で当面の回避策です。まずは、目的のファイル(例:`public/foo.mp4`)をrsyncやscpコマンドなどで、capistranoのsharedフォルダにコピーしておきます。

```rsync
rsync -avz public/foo.mp4 host:myproject/shared/public/
```

sharedフォルダから、配備するアプリにファイルをコピーするコマンドは以下のように記述します。

```ruby:config/deploy.rb
append :linked_files, "public/foo.mp4"
```

ローカル環境などからcurrent(例:`myproject/current/public/`)に直接コピーしても、その場では動きますが、次のリリースを配備するときにディレクトリごと置き換わってしまうため、この一手間が必要です。
Dockerコマンド超省略版

ターミナルからコンテナ作成〜dockerhubリポジトリ作成までの最低限のコマンドをまとめました。
### イメージ作成
※ cd でdockerfileのあるディレクトリに予め移動

```shell
docker build -t --force-rm=true (イメージ名):(タグ) .
```
--force-rm：ビルド失敗したらイメージ削除
### コンテナ作成+起動
/bin/bach は任意の実行コマンドに変更可

```shell
docker run --runtime=nvidia --rm -v (マウント先ディレクトリ):(コンテナ内でのディレクトリ名)\\
--name (コンテナ名) -it (イメージ名) /bin/bash
```
--runtime=nvidia：ランタイム指定（たぶん2020年時点で変更されている）
--rm：実行終了時にコンテナ削除
-v：DockerコンテナにホストOSのディレクトリを共有する
### dockerhubに上げるリポジトリ作成
```shell
docker commit (コンテナ名) (リポジトリ名):(タグ)
```
### dockerhubにアップする
```shell
docker login # ユーザ名とパスワードを求められる
docker push (リポジトリ名):(タグ)
```
# (おまけ)Docker操作
```shell
docker images -a # イメージ一覧
docker rmi (イメージID) # イメージ削除
docker ps -a # コンテナ一覧
docker rm (コンテナID) # コンテナ削除
docker start -i (コンテナID) # コンテナ起動
```
-a：未使用のイメージ、コンテナも表示
macでatomを透過させる際にハマったのでメモ

✏️この記事について
------------
iTerm2を透過した際に、「ついでにAtomも透過しよう」とふと思い立って透過しようとしたが、ハマってしまったので、その際のメモを備忘録がわりに書きます

参考にしたのは、[ここ](https://m12watanabe1a.hatenablog.com/entry/2018/08/30/234251)や[ここ](https://qiita.com/exy81/items/adf45cee9da0ac091874)のサイト

✨教訓👉ビルドに失敗したらファイル丸ごと入れ替える✨
------------

[Atom公式](https://flight-manual.atom.io/hacking-atom/sections/hacking-on-atom-core/)のドキュメントによれば、
>- macOS 10.9 or later
>- Node.js 6.x or later (we recommend installing it via nvm)
>- npm 3.10.x or later (run npm install -g npm)
>- Python v2.7.x
>- Command Line Tools for Xcode (run xcode-select --install to install)

が必要らしいが、Xcodeをインストール**しないまま**作業を進めてしまい、いけないいけないと思い、Xcodeをインストール。

(App Storeだとぎりぎりのところでダウンロードが失敗したので、[Apple Developer](https://developer.apple.com/jp/xcode/resources/)のサイトからダウンロードすることをおすすめします)

そして、再度```script/build```でビルド。しかし、エラー...
```ERR_PACKAGE_PATH_NOT_EXPORTED```で先に進まなくなりました。

まあ、Atomの透過はどうでもいいやと諦めてGitHubから持ってきた**クローンを全て削除**

翌日、「もう一回やってみよう」と思いたち、もう一度GitHubからクローンを取得したところ、何故か成功🤔

ディレクトリが汚染されてたのかな...🤑

[ここ](https://github.com/atom/atom/issues/18540)にも、
>Does running ```script/clean``` before building again clear things up for you?

って書いてありましたね...😅
もしかしたら、```git clone```し直さなくても、```script/clean```でいけたのかも...


追記:Tree-viewを透過する方法
------------
Style.less内で、

```
.tree-view {
    background-color: transparent;
}
```
とするだけです
(Style.lessは、
設定→テーマ→「Atom は<font color="DeepSkyBlue">スタイルシート</font>を編集してスタイルを変更することもできます。」
から
または```~/.atom```にあります)


参考サイト様
------------
[Atomを透過する　〜Mac編〜 - ほそぼそとやっていくブログ](https://m12watanabe1a.hatenablog.com/entry/2018/08/30/234251)
[MacOSでAtomを透明化する時のメモ - Qiita](https://qiita.com/exy81/items/adf45cee9da0ac091874)
[Mac: Script/bootstrap fails to install apm · Issue #18540 · atom/atom](https://github.com/atom/atom/issues/18540)
[いまさらながらAtomのStyle.lessとか設定してみる - Qiita](https://qiita.com/KTakata/items/23876605d71345e6449a)
PowershellでDNSレコードを登録&削除する

## 1.環境
OS:windows Server2016
DNS:OS標準のDNS機能

## 2.事前準備
以下のコマンドでpowershellが実行可能にしておきます。

```powershell
Set-ExecutionPolicy RemoteSigned
```

あと、powershellの実行はDNSサーバで行うこととします。自分のPCからリモートで実行したい場合は、
リモートサーバー管理ツール（RSAT）を導入する必要があります。それは別の記事で記載します。

## 3.DNSレコードの登録
以下のAレコードおよびPTRレコードを登録することとします。

＜登録するレコード＞
ホスト名：hostname1
IP:192.168.0.1
ドメイン：test.co.jp

powershellのコマンドはこんな感じなります。-CreatePtrをつけておくと、逆引きも作ってくれます。
※当然逆引きのゾーンファイルは作成済みであることが前提。

```powershell
Add-DNSServerResourceRecordA -ZoneName test.co.jp -Name hostname1 -IPv4Address 192.168.0.1 -CreatePtr
```

今回利用したAdd-DNSServerResourceRecordAのReferenceページはここ！
[Add-DnsServerResourceRecordA](https://docs.microsoft.com/en-us/powershell/module/dnsserver/add-dnsserverresourcerecorda?view=win10-ps)

## 4.DNSレコードの削除
先ほど登録したAレコード及びPTRレコードを削除することとします。

powershellのコマンドはこんな感じなります。


```powershell:PTR消さないパターン
Remove-DnsServerResourceRecord  -ZoneName test.co.jp -RRType A -Name hostname1 -Force
```

-RecordDataをつけておくと、逆引きを同時に削除します。

```powershell:PTR消すパターン
Remove-DnsServerResourceRecord  -ZoneName test.co.jp -RRType A -Name hostname1 -RecordData 192.168.0.1 -Force
```

-ForceをつけないとY/Nが聞かれます

```powershell:Y/Nパターン
Remove-DnsServerResourceRecord  -ZoneName test.co.jp -RRType A -Name hostname1

確認
GC001PPAD001 サーバー上のゾーン test.co.jp から、タイプ A の、hostname1 という名前で設定されている DNS リソースレコードが削除されます。続行しますか?
[Y] はい(Y)  [N] いいえ(N)  [S] 中断(S)  [?] ヘルプ (既定値は "Y"): n
```

今回利用したRemove-DnsServerResourceRecordのReferenceページはここ！
[Remove-DnsServerResourceRecord](https://docs.microsoft.com/en-us/powershell/module/dnsserver/remove-dnsserverresourcerecord?view=win10-ps)


## 5.PJごとに使いまわせるようにExcelでテンプレを作ってます
excelでこんな感じのテンプレートを作っておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693852/00f4e593-7f6d-7bed-ef3a-542b35ab05ea.png)
グレーアウトした列は固定値、白抜きは可変値とし、Scriptの列（I列）をコピーしてpowershellで実行することで一括でレコードを登録できるようにしています。

※I列はこんな感じの数式を入れています。"=B3&" "&C3&" "&D3&" "&E3&" "&F3&" "&G3&" "&H3"

めちゃめちゃクラシカルな感じですが、担当にやってもらう分にはこんな感じのほうが引き渡しやすいという結論に至ってます。
【解決済】heroku loginでハマった時の対処法

# 環境
Mac Catalina 10.15.6
zsh 5.7.1 (x86_64-apple-darwin19.0)
heroku/7.42.13 darwin-x64 node-v12.16.2

# 現象
ターミナルで
`heroku login`

"heroku" Error: tunneling socket could not be established, cause=getaddrinfo ENOTFOUND proxy.server.com

と出る。これで30分くらい溶かしました...


# 解決方法
ターミナルで
`export HTTP_PROXY=""`
`export HTTPS_PROXY=""`
を実行するだけ。

# 解決に至った経緯
`heroku --version`
とすると
 ›   Warning: HTTPS_PROXY set to https://proxy.server.com:8000
 ›   Warning: HTTP_PROXY set to http://proxy.server.com:8000
heroku/7.42.13 darwin-x64 node-v12.16.2

と出たので、`HTTPS_PROXY`, `HTTP_PROXY`のsetをなくせばいいのではないかと気づいた。
BracketsのプラグインEmmetのショートカットを追加する

BracketsにプラグインのEmmetを入れている。
Emmetには開始タグから終了タグまでをまるっと選択する便利な「Balance」という機能がある。
めちゃくちゃ便利なので多用するのだけど、ショートカットがイマイチ複雑で使いづらかったので、カスタマイズしてみた。

Bracketsの「デバッグ」→「ユーザーキーマップ」を開き、下記のように記述する。

```json:keymap.json
{
    "documentation": "https://github.com/adobe/brackets/wiki/User-Key-Bindings",
    "overrides": {
        "Ctrl-Shift-A": "io.emmet.balance_outward",
        "Ctrl-Shift-B": "io.emmet.balance_inward"
    }
}

```

これでショートカットを
Balance（outward)はCtrl+Shift+A
Balance（inward)はCtrl+Shift+B
に設定された。

【参考にさせていただいたページ】
コーダーの8割が知らないEmmetの隠れ機能！開始タグと終了タグは自動選択！
https://qiita.com/Qiita/items/c686397e4a0f4f11683d

Bracketsのショートカットを変更してカスタマイズする方法
https://qiita.com/assialiholic/items/95b1f3502d7c03aed1be
JavaScript while文

　javascriptのwhile文の書き方です。

```
while(条件式) {
    繰り返し実行する処理。条件式がtrueの間繰り返される
}
```

　while文では条件式がtrueの間、繰り返し処理が実行されます。

```
  let i = 1;
  while(i <= 10) {
	console.log(i);
	i += 1;
  }
```

　このような書き方をすると、変数iが10以下の場合に繰り返し処理が実行されることになります。
`console.log(i)`でコンソールに数字が表示された後、`i += 1;`で変数iを再定義しています。繰り返されるごとに変数iに+1される形です。変数iが11になると条件式がfalseになるので、条件式がtrueになる10回目の繰り返しまでで処理は終了になります。
プレイヤーをタップした場所に動かす【Unity】


画面の一部分を押している間、その場所に少しずつ移動します。

プレイヤー（動かしたいObject）Script内の、Update()に以下を追加

```c#
void Update()
    {
        // タップしている状態
        if (Input.GetMouseButton(0))
        {
            //transform.position = プレイヤーの現在地
            //change = タップしている場所
            Vector3 change = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            change.x -= transform.position.x;
            change.y -= transform.position.y;
            change.z = 0;
            // RigidBodyの場合
            MyRigidBody.MovePosition(
                transform.position + change * Time.deltaTime
            );
            // その他
            //transform.position = Vector3.Lerp(transform.position, change, 2f * Time.deltaTime);
            
        }
    }

```

これで完了です。
S3からオブジェクトを取得したときは解放を忘れずに！

# 環境

- Java8
- AWS SDK for Java 1.11

# 現象

S3からオブジェクト取得時に、以下のようなエラーが発生した。

```
org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
```

# 問題のコード

```java
public InputStream getFile(String bucketName,String prefix){
  try{
    GetObjectRequest request = new GetObjectRequest(bucketName, prefix);
    S3Object object = s3client.getObject(request); // s3clientはシングルトンインスタンス変数として生成済み
    return object.getObjectContent();
  } catch(AmazonServiceException e){
    throw e;
  }
}
```

# 原因

S3Objectを取得した際に、解放処理が行われていないため。
S3内部でHTTPコネクションプールサイズを持っており、デフォルトで<b>50</b>となっている。
これを越えると上記のエラーが発生。

# 解決方法

## その１ S3クライアントのラッパークラスなどで行う場合

```java
public InputStream getFile(String bucketName,String prefix){
  GetObjectRequest request = new GetObjectRequest(bucketName, prefix);
  try(S3Object object = s3client.getObject(request)){
    // メモリに展開。ここでS3Objectの参照をなくす
    byte[] file = IOUtils.toByteArray(object.getObjectContent());
    // byte[]からInputStreamにして返却
    return new ByteArrayInputStream(file);
  } catch(AmazonServiceException e){
    throw e;
  } catch(IOException e){
    throw new RuntimeException(e);
  }
}
```

<b><font color="red">一時的にメモリに展開しているので注意が必要。</font></b>
解放処理を行う関係で、```InputStream```をそのまま返却できない。

## その２ 呼び出し側で解放する場合

```java
public static main(String[] args){
  try(S3Object object = getFile("hoge","fuga")){
    〜処理〜
  }catch (IOException e) {
    throw new RuntimeException(e);
  }
}

public S3Object getFile(String bucketName,String prefix){
  try{
    GetObjectRequest request = new GetObjectRequest(bucketName, prefix);
    return s3client.getObject(request);
  } catch(AmazonServiceException e){
    throw e;
  }
}
```

解放処理を呼び出しごとに行う必要があるが、```InputStream```を扱える。
【Excel】並べ替えが思ったようにされない？もしかしたら「よみがな」が原因かも

例として下のようなリストがあったとして
性別ごとに、年齢が高い順に並べ替えようとした際に上手くいかないケースがありました。

| 名前 | 性別 | 年齢 |
|:-:|:-:|:-:|
| 太郎 | 男 |  30 |
| 春子 | 女 | 30 |
| 夏子 | 女 | 25 |
| 次郎 | 男 | 20 |
| 三郎 | 男 | 19 |
| 秋子 | 女 | 23 |


:point_down_tone2:

| 名前 | 性別 | 年齢 |
|:-:|:-:|:-:|
| 太郎 | 男 |  30 |
| 三郎 | 男 | 19 |
| 春子 | 女 | 30 |
| 夏子 | 女 | 25 |
| 秋子 | 女 | 23 |
| 次郎 | 男 | 20 |

__あれ、次郎君！？__:thinking:

最初は性別のセルに余計な全角スペースなどが入っていて別の性別扱いされてしまったのかと思いましたが、どうもそうではありません。

結論を言うと、原因は__「よみがな」__でした。
上の5人はそれぞれ「おとこ」「おんな」という読みで入力していましたが次郎君だけ男性の「だん」という読みで変換されていたんですね。
* * *
Excelがよみがなも情報として記録しているという事は知識としては知っていましたが、普段は意識しないため原因に気づくまで少し時間がかかりました。
特に複数人で編集する場合なんかは、人によってどういうよみがなで漢字変換するかが違ったりするんじゃないかと思います。
ASP.NET Core の IHttpClientFactory を使うときの注意点

IHttpClientFactory を使うと、使い方に癖のある HttpClient をいい感じに使えるようにしてくれます。

[ASP.NET Core で IHttpClientFactory を使用して HTTP 要求を行う](https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/http-requests?view=aspnetcore-3.1)

IHttpClientFactory から CreateClient することで、いい感じに使いまわしたり適切なタイミングで破棄したり色々やってくれるので便利です。名前付きクライアントを使うと、IHttpClientFactory には依存せずに設定した通りに構成された HttpClient が渡されて、もっといい感じになります。

IHttpClientFactory を使う上で重要なのは HttpClient のインスタンスを必要な時に生成して不要になったら手放す(Dispose はしなくていい)という感じで作ることです。

## Singleton?　

なので、Singleton クラスに HttpClient を DI したり型指定されたクライアントを DI したりすると台無しになってしまいます。型指定されたクライアントは Transient で DI コンテナに登録されているのに Singleton のクラスに DI すると、ずっと同じインスタンスが使いまわされてしまいます。

例えば以下のように…

```csharp
// DI コンテナへの登録処理
services.AddHttpClient();
services.AddSingleton<SomeSingleton>();

// SomeSingleton の定義
class SomeSingleton
{
    private readonly HttpClient _httpClient; // 私はいつ開放されるの！？

    public SomeSingleton(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    // 省略
}
```

## ということで

なので、IHttpClientFactory を DI するようにするか Singleton じゃなくて Scoped か Transient で管理するようにしましょう。
Sequelizeでdevelopment/production用のseedを分けたい

## はじめに

node.jsでサーバサイドの処理を作成するときにORMとして、[Sequelize](https://sequelize.org/)を利用しています。

その際に、開発用と本番用でseedを分けて管理したくなったので、それについて書かせていただきます。

## どのようなケースか？

例えば、以下のようなテーブルがあった場合、

```
id, request_url
```

開発用にseedで作成するデータは、このようになります。

```
1, http://localhost:3000/user
2, http://localhost:3000/login
3, http://localhost:3000/company
```

しかし、これは開発用のデータのため、本番でこのseedを実行しても、うまくアプリケーションが動かないです。

そのため、本番用のseedでは、ドメインを指定して、データを作成したい。

```
1, https://api.subroq.com/user
2, https://api.subroq.com/login
3, https://api.subroq.com/company
```

このようなケースです。

## どのように対応するのか？

対応方法としては、seedを分けて、実行時にフォルダを指定します。

フォルダ構成としては、こんな感じ。

```
seeders/
├── development
│   ├── 20200808080637-users.js
│   ├── 20200808101006-categories.js
│   ├── 20200808101050-questions.js
│   └── 20200911180200-validations.js
└── production
    ├── 20200808101006-categories.js
    ├── 20200808101050-questions.js
    └── 20200911180200-validations.js
```

seedを実行する際にフォルダの指定をすれば、うまいこと動きます。

開発用

```
NODE_ENV="development" node_modules/.bin/sequelize db:seed:all --seeders-path "seeders/production"
```

本番用

```production
NODE_ENV="production" node_modules/.bin/sequelize db:seed:all --seeders-path "seeders/production"
```

## 最後に
seedの管理は非常に大事で、これを怠ったことで、環境構築ができなくなったり、難しくなったりすることが多々あります。
それを防ぐためにも、利用しているORMを理解して、それに合わせた管理をするのが大事だと思います。

Subroqは、企業のフリーランスエンジニアの採用や活用を支援するサービスを提供しております。また、フリーランスエンジニア向けの記事も書いておりますので、興味ある方は是非、ご一読いただければと思います。

https://subroq.com
画像にマウスオーバーすると背景をグラデーションにしてメニューが出るようにする

Youtubeの動画や[freepik](https://jp.freepik.com/home)のように、画像にホバーすると画像にオーバレイすると、メニューが出てきて、メニューの背景にはグラデーションが掛かったデザインがありますが、それを実現するサンプルです。（追記：10/5　文字がアニメーションで現れるように変更）

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="css,result" data-user="emesh" data-slug-hash="QWNxvgW" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="QWNxvgW">
  <span>See the Pen <a href="https://codepen.io/emesh/pen/QWNxvgW">
  QWNxvgW</a> by emesh (<a href="https://codepen.io/emesh">@emesh</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>


定義要件としては、
1.ホバーすると画像がグラデーションになる
2.下にメニューが表示される
3.画像からでもリンクできると言う点が必要でした。

まずグラデーションはHTMLにマスクの要素を用意し、それをCSSで調整するようにしています。画像のリンクはそのままではできないのでよくある要素全体に拡大するコードを使っていますが、そのコードではメニューにも影響を及ぼし、文字が一つの場所に集合してしまうというバグにも影響が及ぼすので下記のコードでpositionをキャンセルさせることにしています。

```
    figcaption a {
            position: initial !important;
            color: #fff;
        }
```
参考になりましたらどうぞ。

#おまけ
ホバーするとメニューが表示するのではなく常時メニューを表示させたい場合にはこちらを。

<p class="codepen" data-height="265" data-theme-id="dark" data-default-tab="css,result" data-user="emesh" data-slug-hash="oNxyewL" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="メニューを常時表示したいとき">
  <span>See the Pen <a href="https://codepen.io/emesh/pen/oNxyewL">
  メニューを常時表示したいとき</a> by emesh (<a href="https://codepen.io/emesh">@emesh</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

#参考サイト
[CSSのみで実装できる、画像と相性が良さそうなホバーエフェクト 15](https://www.nxworld.net/tips/css-image-hover-effects.html)
[Hover Effect Ideas](https://tympanus.net/Development/HoverEffectIdeas/index.html)
Unity 開発に関する 50 の Tips 〜ベストプラクティス〜（2016 Edition）

![20200910152454.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55937/704f4ced-1277-8fc4-7a59-1200b7d4c463.png)

この記事は「[Unity開発に関する50のTips　〜ベストプラクティス〜（翻訳）](https://warapuri.com/post/28972633000/unity%E9%96%8B%E7%99%BA%E3%81%AB%E9%96%A2%E3%81%99%E3%82%8B50%E3%81%AEtips-%E3%83%99%E3%82%B9%E3%83%88%E3%83%97%E3%83%A9%E3%82%AF%E3%83%86%E3%82%A3%E3%82%B9%E7%BF%BB%E8%A8%B3)」を読んでとても参考になったので、その続編になる「[50 Tips and Best Practices for Unity (2016 Edition)](https://www.gamasutra.com/blogs/HermanTulleken/20160812/279100/50_Tips_and_Best_Practices_for_Unity_2016_Edition.php)」の内容を超訳（勉強のため個人的に意訳・誤訳）したものです。

[ブログにも掲載しています](https://shikaku-sh.hatenablog.com/entry/unity-tips-and-best-practices-2016)が、５日作業の結構な労力だったので Qiita にも掲載しておきます。（辺境の[ブログ](https://shikaku-sh.hatenablog.com/entry/unity-tips-and-best-practices-2016)と [twitter](https://twitter.com/sh1_twi) をよろしくしてくれると幸いであります😃）

> 変なことを書いていたり、誤訳等あったらごめんなさい。仕事から帰ってきてから趣味でやっていたので、疲れたところなんかは、翻訳ツールが増えてます。まわりくどく感じた文の省略や、省略による文脈の欠落もあるかもしれません。（そのあたりは、2012 年版の翻訳と同じで、諸々あらかじめご了承ください）
> コメントに書いているのは、個人的にメモとして加筆しています。
> （括弧）の内容は、訳した元々の文章から括弧をされていたり、個人的に加筆したものがあります。

<br />

----

# リンク先の移動

テストで記事を zenn に移動させてみました。

本の形式にしたので、読みやすくなっているかと思います。zenn がダメなら[ブログにも掲載しています](https://shikaku-sh.hatenablog.com/entry/unity-tips-and-best-practices-2016)ので、そちらを参照ください。

- [zenn - Unity 開発に関する 50 の Tips 〜ベストプラクティス〜（2016 Edition）](https://zenn.dev/sh1ch/books/4f49e00cfd92be082e1c)
React appをFirebaseにデプロイ


# Reactとは
Reactとは、UIを作成するための、Facebookが開発したJavaScript用ライブラリです。Facebook、Yahoo、Qiita、Wantedlyなども採用しています。
詳細: https://ja.reactjs.org/

## Reactのコンセプト

- Declarative（宣言的である）

- Component-Based（コンポーネント思考がベースになっている）

- Learn Once, Write Anywhere（他の分野にも適応できる）

# Firebaseとは
Googleが運営するクラウドプラットフォーム。無料枠があり、HerokuのGoogle版。
詳細: https://firebase.google.com/?hl=ja

# Firebaseの導入

以下のコマンドをターミナルで実行し、Firebase－CLIをインストール。

```
$ npm install -g firebase-tools
```

Googleアカウントを紐づけ

```
$ firebase login     // 実行後、メールアドレスなどを入力する
```

## Firebaseの初期化

以下を実行してFirebaseを初期化

```
$ firebase init
```

初期化後、以下のようにターミナルから、色々聞かれるので

```
     ######## #### ########  ######## ########     ###     ######  ########
     ##        ##  ##     ## ##       ##     ##  ##   ##  ##       ##
     ######    ##  ########  ######   ########  #########  ######  ######
     ##        ##  ##    ##  ##       ##     ## ##     ##       ## ##
     ##       #### ##     ## ######## ########  ##     ##  ######  ########

❯◯ Database: Deploy Firebase Realtime Database Rules
 ◯ Firestore: Deploy rules and create indexes for Firestore
 ◯ Functions: Configure and deploy Cloud Functions
 ◯ Hosting: Configure and deploy Firebase Hosting sites
 ◯ Storage: Deploy Cloud Storage security rules
 ◯ Emulators: Set up local emulators for Firebase features
```

> ◯ Hosting: Configure and deploy Firebase Hosting sites

を選択し、 **スペースキー** を押した後に **Enter**

## option

次にoptionを聞かれるので

```
? Please select an option: (Use arrow keys)
❯ Use an existing project 
  Create a new project 
  Add Firebase to an existing Google Cloud Platform project 
  Don't set up a default project 
```

## すでにFirebaseプロジェクトがある場合

Firebase内に、すでにプロジェクトを作成してたら以下を選択し **Enter**
プロジェクトを選択し **Enter** 

> Use an existing project 

## Firebaseプロジェクトがない場合
初めて作成する時には以下を選択し **Enter**

> Create a new project 

次にFirebaseのブラウザからプロジェクトを作成する
プロジェクトの作成は以下参照
https://qiita.com/Watakatsu/items/667f45081a6dfbc11074

プロジェクトとローカルのフォルダを紐づけ

```
$ firebase use --add
```

## デプロイ

```
$ firebase deploy
```

以上
テーブルをinnodb_file_per_tableもしくは特定のディレクトリのテーブルスペースに一気に移動したい時に使うSQLを作成するSQL

データ容量が不足して、テーブルスペースを削除したいけど、テーブルスペースを削除するにはテーブルスペースに格納されているデータを別のテーブルスペースに移さないといけない！
そんな時に利用するALTER TABEL文を一気に作成するクエリです。
innodb_file_per_tableテーブルスペースの場合だけ、データ削除によってテーブルに空き領域が出来たときには、ちゃんと必要な分だけ容量を確保するようにMysqlは動きます。
テーブルスペースの場合は、空き容量を回収してくれないので、削除しないとダメなので、運用がちょっと面倒。

#テーブルをinnodb_file_per_tableもしくは特定のディレクトリのテーブルスペースに一気に移動したい時に使うSQLを作成するSQL

```sql:
SELECT
    a.NAME AS space_name,
    b.NAME AS table_name,
    CONCAT( "ALTER TABLE " , REPLACE( b.NAME , "/", "_") , " TABLESPACE innodb_file_per_table;" ) as "innodb_file_per_tableに移動するSQL",
    CONCAT( "DROP TABLESPACE " , a.NAME , " ENGINE=INNODB;" )  as "テーブルスペースを削除るSQL",
    CONCAT( "CREATE TABLESPACE `" , REPLACE( b.NAME , "/", "_") , "` ADD DATAFILE '<テーブルスペースを作成するディレクトリ>", REPLACE( b.NAME , "/", "_") , ".ibd' FILE_BLOCK_SIZE=8192 Engine=InnoDB;" ) as "特定のディレクトリにテーブルごとにテーブルスペースを作成するSQL",
    CONCAT( "ALTER TABLE " , REPLACE( b.NAME , "/", ".") , " TABLESPACE = `" , REPLACE( b.NAME , "/", "_") , "`;" ) as "特定のディレクトリのテーブルごとのテーブルスペースにテーブルを移動するSQL"
FROM
    information_schema.INNODB_SYS_TABLESPACES a,
    information_schema.INNODB_SYS_TABLES b 
WHERE
    a.SPACE = b.SPACE 
    AND a.NAME LIKE '<テーブルスペース名>' -- テーブルスペース単位で指定したい場合はこちら
    #AND b.NAME LIKE 'scuel_common' -- データベース単位で指定したい場合はこちら
    #AND b.NAME NOT IN ('<除外したいテーブル名>')
    ;
```
mindの研究 その5

#概要

mindが謎なので調べてみた。
vistaに入れた。
win32api叩いてみた。
hellowold書いてみた。

写真

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/e5b07164-aa5b-950c-8987-0afd3edb2301.jpeg)


#サンプルコード

```
メインとは
　パス名は　文字列実体情報
　結果は　変数
　答えは　文字列実体
　文字1は　文字列実体
　「hello world!」を　文字1に　入れ
　文字１の　アドレスを得て
　パス名長さで　文字列実体を獲得し　パス名に　入れ
　パス名を　文字列実体を参照し　アドレスを得て
　パス名の　追加余裕をつみ
　"user32"と　"MessageBoxA"で
　ＡＰＩ呼出し４　結果に　入れ
　エラー？　ならば
　　エラー文字列を　一行表示し　終り
　つぎに
　結果が　０より　大きい　ならば
　　答えを　一行表示し
　さもなければ
　　「取得できませんでした」を　一行表示し
　つぎに




```


以上。
Let's EncryptをCloudFrontに導入する

## はじめに

httpsでWebサービスを利用するために必要なSSL証明書ですが、最近は、[Let's Encrypt](https://letsencrypt.org/ja/)という無料で利用できるものが存在します。

これを利用して、CloudFrontに設定するための手順を記載します。

## 導入までの流れ

以下の通りです。

1. certbotのインストール
* 証明書の発行
* IAMへ登録
* CloudFrontへ設定

certbotのインストールや証明書の発行などは、Amazon Linux2上で行なっております。

### certbotのインストール

最初に、SSL証明書に発行に必要な鍵などを作成してくれる、certbotというツールをインストールします。

これは、わかりやすくまとめてある記事がありますので、そちらを参照ください。

[Amazon Linux2とLet's EncryptでSSL対応サーバを0から爆速構築](https://qiita.com/MysteriousMonkey/items/4d3d857c0e68d4bfff39)

### 証明書の発行

以下のようなコマンドを発行します。

```
sudo certbot certonly --manual --domain subroq.com
```

コマンドの`--manual`の部分を`--nginx`に変更すると、勝手に`nginx.conf`にSSLの記述を追記してくれてます。

もし、nginxにSSL証明書を設定する場合は、変更してみてください。

また、`--domain subroq.com`の部分は、複数指定することが可能です。

例えば、

```
sudo certbot certonly --manual --domain subroq.com --domain console.subroq.com
```

のように、サブドメインなしとサブドメイン付きの証明書を一度に発行することが可能です。

### IAMへ登録

certbotのコマンドを実行すると、`/etc/letsencrypt/live/`というフォルダが作成され、その配下に指定したドメイン毎にフォルダと必要な鍵等々が作成されます。

今回だと、`/etc/letsencrypt/live/subroq.com`というフォルダが作成されました。

次にこれらをIAMに登録します。

コマンドは、以下の通りです。

```
sudo aws iam upload-server-certificate --server-certificate-name subroq.com-ssl \
--certificate-body file:///etc/letsencrypt/live/subroq.com/cert.pem \
--private-key file:///etc/letsencrypt/live/subroq.com/privkey.pem \
--certificate-chain file:///etc/letsencrypt/live/subroq.com/chain.pem \
--path /cloudfront/subroq/
```

`aws`を利用するので、必ずインストールしておいてください。

### CloudFrontへ設定

最後にアップロードした証明書をCloudFrontに設定します。

まずは、対象のDistributionsを選択します。

![スクリーンショット 2020-09-14 15.26.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685523/2e9c5250-2578-3d8e-1205-feb6ff40a05f.png)

次に、そのDistributionsを編集します。

![スクリーンショット 2020-09-14 15.27.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685523/fbe05ca1-bb73-1166-be5d-0f845f68c8e5.png)

![スクリーンショット 2020-09-14 15.27.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685523/9542fa5e-da0d-ffff-5652-911a949b45e8.png)

上記、画像のCustom SSL Certificate (example.com)を選択すると、今回追加した証明書が表示されます。

ここに表示される名前は、先ほどawsコマンド実行時に、指定した`--server-certificate-name`の値です。

それを選択することで無事設定が完了です。

設定が反映されるまでに10分程度？かかるらしいです。

![スクリーンショット 2020-09-14 15.32.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685523/82ad9bc9-2f06-b960-781d-9927139f3c76.png)

## 最後に

昔は、SSL証明書にお金がかかっていましたが、このようなサービスが登場し、気軽にhttps化できるようになりました。

Chromeブラウザなどでは、httpsでなければCookieなどの制御がうまくいかないこともあり、httpsの利用は必須になっているため、ありがたいです。

Subroqは、企業のフリーランスエンジニアの採用や活用を支援するサービスを提供しております。また、フリーランスエンジニア向けの記事も書いておりますので、興味ある方は是非、ご一読いただければと思います。

https://subroq.com
過去の投稿欄、いいね欄の追加

GeekSalon名古屋メンターの吉田です！

オリジナル開発でマイページにいいね欄(いいねした投稿をマイページに表示)をつけたいという受講生が何人かいたので記事にしました！
良ければ参考にして下さい。
(カラム名などはGeektwitterのものをそのまま使っています)

##過去の投稿欄の作成
いいね欄の前にこの機能をつけた方が多いと思うので、こちらのコードを紹介して**「いいね欄はその応用で作れる！」**ということを理解してもらおうと思います。
この機能は必要ないという方は飛ばしてもらって構いませんが、参考までに一読しておいて下さい。

まずは以下のコードを`users_controller.rb` に追加しましょう

```ruby:users_controller.rb
class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
    <!--ここから-->
    @tweets = @user.tweets
    <!--ここまで-->
  end
end
```

これにより@tweetsというインスタンス変数にユーザーモデル(@user)がもつその人の投稿(tweets)が代入されました。これをviewsで使いましょう
以下のコードを`users>show.html.erb`の下の方に挿入して下さい

```ruby:users>show.html.erb
<h2>過去の投稿</h2>
    <% @tweets.each do |tweet| %>
    <div class="user-tweet">
        <hr>
        <p style="word-break: break-all;"><span>投稿本文: </span>
        <%=link_to tweet
.body, tweet_path(tweet.id) %></p>
    </div>    
    <% end %> 
```

これで過去の投稿本文が表示されるようになりました。本文ではなくタイトルが良いという方は、bodyの部分をtitleなどに変更して下さい。

##いいね欄の実装
いよいよいいね欄の実装ですが、やることは先の機能とあまり変わりません。
まずは「いいねした投稿」がどのようにuserモデルと結びついているか確認しましょう。

```ruby:models>user.rb
class User < ApplicationRecord
  has_many :tweets, dependent: :destroy
  has_many :likes, dependent: :destroy
  has_many :liked_tweets, through: :likes, source: :tweet
  has_many :comments, dependent: :destroy

  def already_liked?(tweet)
    self.likes.exists?(tweet_id: tweet.id)
  end
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
  validates :name, presence: true #追記
  validates :profile, length: { maximum: 200 } #追記
end
```

`has_many:tweets`が先ほど使った「自分の投稿」ですね。そして
「いいねした投稿」は`has_many :liked_tweets`です。これを使いましょう。
以下のように記述して下さい。

```ruby:users_controller.rb
class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
    @tweets = @user.tweets
    <!--ここから-->
    @likes = @user.liked_tweets
    <!--ここまで-->
  end
end
```

そしてviewsの方は

```ruby:users>show.html.erb
<h2>いいね欄</h2>
    <% @likes.each do |like| %>
    <div class="like-tweet">
        <hr>
        <p style="word-break: break-all;"><span>投稿タグ: </span>
        <%=link_to like.body, tweet_path(like.id) %></p>
    </div>    
    <% end %> 
```
となります。
こちらも本文ではなくタイトルにしたい場合bodyをtitleなどに変更してください。

####以上です。お疲れ様でした！
ArduinoJson でJsonデータとして送信でいなかった

# ArduinoJson でJsonデータとして送信でいなかった

ESP32 や M5stack などで通信するときセンサーの複数のデータをわかりやすく送信するのに Json 形式で送信出ればいいと考えました。

ArduinoJson というライブラリがあり、これを使用することで簡単に Json 形式で送信できるようです。

## 使用してみよう

```Arduino:testJson.ino
#include <ArduinoJson.h>

char pubMessage[512];

void setup(){
    Serial.begin(115200);
}

void loop(){
  String data = buildJson();
  data.toCharArray(pubMessage, data.length());
  Serial.println(pubMessage);
  delay(1000);
}

String buildJson()
{
  String json = "";
  const int capacity = JSON_OBJECT_SIZE(20);
  StaticJsonDocument<capacity> doc;
  DynamicJsonDocument logs(64);
  int val1, val2;
  val1 = 0;
  doc["Sensing_A"] = val1;
  val2 = 0;
  doc["Sensing_B"] = val2;

  serializeJson(doc, json);

  return json;
}
```

結果確認

```
{"Sensing_A":0,"Sensing_B":0
{"Sensing_A":0,"Sensing_B":0
{"Sensing_A":0,"Sensing_B":0
{"Sensing_A":0,"Sensing_B":0
```

このデータを送信しても送信先では、Json と認識できないし変換もできません。


## コード修正
原因と考えられるのがこのコードです

```
data.toCharArray(pubMessage, data.length());
```

この部分のデータの長さを示すのが 1 文字足りないと考えられます。なので、このコードを修正します。

```
data.toCharArray(pubMessage, data.length() + 1);
```

修正結果

```
{"Sensing_A":0,"Sensing_B":0}
{"Sensing_A":0,"Sensing_B":0}
{"Sensing_A":0,"Sensing_B":0}
{"Sensing_A":0,"Sensing_B":0}
```

これで送信して変換、Json と認識できるようになりました。
仮想環境の共有をする方法 [requirements.txtについて]

## はじめに

仮想環境をGitで共有するについて話が上がったのですが、さっぱりだったので調べてみました。


## 仮想環境とは
わかっている方は読み飛ばしていただいて結構です。

[統合開発環境(IDE) vs. 仮想環境(virtual environment)](https://qiita.com/tamahassam/items/6090eff4257043c1bfda)

## 具体的方法
仮想環境をGitで共有する具体的な方法について以下に書きます。[こちらの記事](https://hiropon-progra.com/?p=82)を参考にしました。

仮想環境をGitで共有するというのは、誰かが仮想環境を作りそれをチームで共有するということ**ではなく**、各々がそれぞれのpc内に新規にPython仮想環境を作り、その中で**requirements.txt**という、そのプロジェクトで必要なパッケージライブラリを記載したファイルを読み込むということ。つまり、**Gitでrequirements.txtを共有**すればいいということです。


## requirements.txtについて
ここに現在の環境に入っているパッケージライブラリの一覧を取得します。具体的には、ターミナルで以下のコマンドを実行しましょう。

```
pip freeze > requirements.txt
```

これでプロジェクト内にrequirements.txtが生成されるはずなので、これをGitHub上に上げます。

## 一括インストール
requirements.txtが入ったプロジェクトを保存するだけではパッケージライブラリはまだ仮想環境において使える状態にはありません。それをインストールするためには以下のコマンドをターミナルで実行する必要があります。

```
pip install -r requirements.txt
```

これで、パッケージライブラリの共有は完了となります。


## 終わりに
仮想環境の共有という日本語は誤解を生み出してしまいそうで、正しくはパッケージライブラリの共有ですが、日常会話では前者が使われることが多い気がする（？）ので、題名はそのままにしておきます。

## 参考
https://hitoribucho.com/post/20190309191626
DockerのJenkins経由でNuxtアプリをfirebase deploy

# やりたいこと
- （目標）URLを叩くと、PULLして、Firebase deployする

# Dockerfile
```
FROM jenkins

USER root
RUN cd tmp/ \
    && wget https://updates.jenkins-ci.org/latest/jenkins.war \
    && mv ./jenkins.war /usr/share/jenkins/

USER jenkins
```

# docker-compose.yml
```
version: "3"

services:
  jenkins:
    build: .
    ports:
      - 8080:8080
    volumes:
      - ./jenkins_home:/var/jenkins_home
```

# Dockerコマンドで構築
```
docker-compose up
```
http://localhost:8080/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166346/ec1fb874-47b1-b7bd-2878-34a0d1394adc.png)
Jenkinsはこれで、構築完了。
空のジョブを一つ作成して、実行しておけば、workspaceができる。
このworkspaceでpullできるように構築する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166346/808ab07f-a59d-51a1-6c83-8c49cfee4093.png)
保存
![i
mage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166346/c10f83ef-823a-fbc5-fe24-a12ba1894974.png)
ビルド実行

# Nuxtアプリをビルドしてデプロイできる環境を構築
```
# ログイン
docker-compose exec jenkins bash  

# sshキーの作成
ssh-keygen 
ls ~/.ssh 
eval `ssh-agent` 
ssh-add ~/.ssh/id_rsa
cat ~/.ssh/id_rsa.pub # これをバックログのSSH公開鍵に設定

# NVM
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
source /root/.bashrc
nvm install stable

# sudoコマンドインストール
apt update  
apt-get -qq update
apt install -y sudo  
apt-get install build-essential

# ジョブのディレクトリに移動
cd "var/jenkins_home/workspace/My Job"
git clone バックログのSSHのURL

# Nuxtのビルド
npm run i && npm run generate

# firebaseコマンドのインストール
curl -sL https://firebase.tools | bash
firebase login --no-localhost 
# firebase loginはトークンを画面コピーしてターミナルに貼れば認証される

```
これで、NuxtプロジェクトがビルドできていればOK！

## Jenkinsの設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166346/355fb60f-3c76-6dd0-696c-827cce8cabd9.png)
ビルドトリガーはURLを叩くと、このジョブが走る設定です。
画面の例だと、
http://localhost:8080/job/amazing-master/build?token=testtesttest
これで、このバッチが動きます。

#Jenkinsシェルの実行
```
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
cd "My Job"
git pull origin master
npm i && npm run generate
firebase deploy
```
- npmコマンドの設定
- git pull 
- nuxt generate
- firebase deploy
を設定

これで、、、
http://localhost:8080/job/amazing-master/build?token=testtesttest

を叩いて、デプロイできれば成功です。
ローカルのdocker環境で作ったWebアプリをAWSに移行する方法

# 背景
ローカル環境でWebアプリを作っていたのでAWS上のサーバへ移行した。AWSでサーバを立てたことなかったので有識者に教えてもらいながらやってみた。忘れそうなので今後の自分のためにサーバ上でdockerを動かすところまでの手順を残しておく。

# 本編
大まかな作業手順はこう。
1. AWSにEC2インスタンスを立てる
2. 立てたサーバの中でdockerをインストールする
3. gitlabからアプリケーションをクローンする

### 実際に行った手順
実際の手順は以下のようにした。ただし今回、EC2インスタンスの作り方は割愛する。

#### サーバに入るまで
1. AWSのEC2インスタンスを作る(詳細は今後書くかもしれない)
2. 1ができると`.pem`がついたファイルができるのでこれは`~/.ssh/`大切に保存しておく。
3. AWSのEC2のページにipアドレスがあるのでsshする。`ssh xx.xxx.xx.xxx`やってみたけどできなかった。
4. ユーザ名をつけてやってみた。`ssh ubuntu@xx.xxx.xx.xxx`やってみたけどできなかった。
5. エラーログがみたい時`ssh -v ubuntu@xx.xxx.xx.xxx`
6. `ssh -i ~/.ssh/xxx.pem ubuntu@xx.xxx.xx.xxxでxxx.pem`コマンドで入れた。xxx.pemというキーを使ってubuntuに入りますよコマンドらしい。


#### サーバにて
1. gitlabにあるリポジトリをサーバ側にsshでクローンしたい。いきなりクローンができないので、まずは`ssh-keygen`でキーペアを作る。3回質問されるが特に何もなければEnterを3回押すだけ。
2. `.ssh/id_rsa.pub`というキーができているはずなのでその中身をコピーしてgitlab上で公開鍵を記入するところ(設定とかからいけたはず)にペーストする。
3. サーバ上でdockerをインストールする。`sudo apt update`をまずやって`sudo apt install docker.io`する。
4. `docker ps`できるか確認。権限がなかったので`sudo usermod -aG docker $USER`という呪文を唱えた。
5. ログアウトしてもう一度ログインして`docker ps`したら確認できた。
6. `sudo apt install docker-compose`でdocker-composeをインストール。
7. `docker-compose up`すれば起動するはず。落としたい時は`docker-compose down`または`docker-compose stop`すれば良い。ちなみに、バックグラウンド実行したい時は`docker-compose up -d`でできる。

# まとめ
ローカルのdocker環境で動かしているWebアプリをAWSに移行した。AWSのサーバ内に入るまでの内容とサーバに入ってdockerを動かすまでの内容の話をした。おそらく他のやり方もあるので参考に。