OmniAICreator/Qiita-1.07M huggingface dataset:
【Xcode13】プロジェクトの名前を変える手順

#何の記事？
Xcodeのプロジェクト名を変更する方法です。


#プロジェクト名を変更

プロジェクト名の変更は、Targetのフォルダをクリックしてリネームすることによりできます。
![スクリーンショット 2021-12-20 12.30.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620139/eb887eda-3d8d-e1db-49bf-6e0a7bd93b44.png)

いくつかの項目も自動で変更してくれるようになっています。
![スクリーンショット 2021-12-20 12.31.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620139/19ab8265-1aa7-cece-cc67-0df93a8416be.png)

さらにエントリポイント（@main)のスクリプトの名前を書き換えます。
![スクリーンショット 2021-12-20 12.32.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620139/aabdac6b-2741-e09b-b5c5-b9a0c104a93c.png)

CoreDataを用いている場合には、.xcdatamodeldファイルもリネームしてしまいましょう。
![スクリーンショット 2021-12-20 15.04.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620139/68df1d44-f741-22d9-a15c-2cd6926330bc.png)


一応これで変更完了なのですが、エラーでアプリが立ち上がらなくなるときがあります。その際によく出るエラーとその対策を示します。


#エラー１：Build input file cannot be found: xxx Info.plist
Info.plistの参照先が間違っていますよというメッセージです。
Target＞Build Settings＞Packaging＞Info.plist File
の部分を新しいファイル名に書き換えれば、エラーは消えます。

![スクリーンショット 2021-12-20 12.37.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620139/784b2354-9bfa-0092-b0ac-0d4a8e9ff551.png)

#エラー2： One of the paths in DEVELOPMENT_ASSET_PATHS does not exist: 
Target＞Build Settings＞Deploymentの、"●●●/Preview Content"を、新しい名前に書き換える必要があります。
![スクリーンショット 2021-12-20 12.54.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620139/5db5b40e-e89b-06d3-98a0-46c71fc5fc3c.png)

#エラー3: Thread 1: Fatal error: UnsafeRawBufferPointer with negative count
CoreDataを用いているスクリプトの場合、.xcdatamodeldファイルん名前とPersistentControllerのContainerのファイルの名前が一致していないとこのエラーが出ます。Containerのファイル名を書き換えてあげましょう。大文字と小文字を間違えないように。
![スクリーンショット 2021-12-20 13.12.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620139/b552b215-9978-6e46-e4d2-5e8c3fe9dc9c.png)


#おまけ: Bundle Identifierの変更
アプリの配布の際に変更が必要になることがあります。Target＞Signing & Capabilities＞Bundle Identifierから変更できます。
![スクリーンショット 2021-12-20 13.02.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620139/2f30c64c-083f-b158-d999-3d4a1b3556c0.png)


#まとめ
Xcodeでプロジェクト名を変更する際にハマりやすかったところをまとめました。参考になれば幸いです。
UnityでMayaのリグを再現してAnimationRiggingでキャラクタを制御する

本記事は[QualiArts Advent Calendar 2021](https://qiita.com/advent-calendar/2021/qualiarts)の21日目の記事となります。

# 概要
UnityとMaya双方で簡単な人形のリグを作成し、コントローラのアニメーションを受け渡すことでキャラクタの制御を行います。

| Maya | Unity |
| --- | --- |
| ![AnimationShortMaya.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/fc320ac5-2687-af4c-17cd-80f296f4789b.gif) | ![AnimationShortUnity.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/3f26b785-ec8a-5087-4f1b-87693a989a53.gif) |

# リギング
アニメーションを付ける際にスキニングされた骨を直接動かして作業するのは大変です。
そこで効率的に作業できるようにコントローラを作成することがあり、このコントローラや制御機構を作る作業をリギングと呼びます。
(この記事ではスキニングを含まないものとします。)
今回は手足のIK、指の一括操作、いくつかのコンストレイントを用いて人形のリグを作成しました。
Unityには[AnimationRigging](https://docs.unity3d.com/ja/2020.3/Manual/com.unity.animation.rigging.html)という機能があり、TwoBoneIKやコンストレイントを設定することができます。
MayaとUnityで同様のリギングを行い、コントローラのアニメーションを流すことで、コントローラーに応じてキャラが動いていることが確認できます。

| Maya | Unity |
| --- | --- |
| ![AnimationMayaLong.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/f0b93b1f-ce37-cda2-7bf0-2c9beff807af.gif) | ![AnimationUnityLong.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/875acdcf-16e0-249e-d68a-3521e9af7f15.gif) |

自作とした機構として、指の一括制御を紹介したいと思います。
手はジョイントも多くモーション付けが大変になりがちで、キーとしても多くなってしまいます。
プロジェクト要件次第ですが、単純な握りだけでよいのであれば一括で操作することも検討できるかと思います。
以下の動画ではコントローラの回転を、各指に一括して与えている様子です。
親指とその他の指は動きが大きく異なるため、別々に操作できるようにしてあります。
<img width="400" alt="HandMaya.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/a6167a2b-5d9b-938a-5358-33e30d92688a.gif">

# アニメーション
一般的にはMayaで作成したアニメーションを基本骨にベイクしてUnityに渡すことになると思います。
ただ今回はUnityとMayaで同一のリグを組む事できているので、ベイクをせずにコントローラのアニメーションを渡します。
ベイクする工程がない代わりにUnityではランタイムでリグを介した動きとなっています。

| | 1：Mayaでモーション作成 | ２：Mayaでベイク | 3：Unityでモーション適応 |
| --- | --- | --- | --- |
| 一般的なケース | ![RigMaya.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/8d52b131-6506-b161-2a79-8d393fc3d950.png) | ![JointMaya.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/3c274365-0cd6-63ca-77d1-c47a17ac7879.png) | ![JointUnity.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/ef4ab6ab-2190-1ff2-99f0-d0e22d7483ac.png) | 
| 今回のケース | ![RigMaya.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/316e3003-97a3-63c5-14e0-ae985bf572c3.png) | なし | ![RigJointUnity.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/878081/25c90657-e472-3964-526a-374e8fd22a13.png) | 

# 感想と考察
UnityとMaya双方で簡単な人形のリグを作成し、コントローラのアニメーションを受け渡すことでキャラクタの制御を行いました。

**メリット**
MayaとUnityでリグを共通化できているため、特殊な動作でも完全に再現することが可能です。
基本人体はベイクし、特殊な機構だけリギングするなどハイブリッドな使い方でも十分有効です。
例えば手足の伸縮や変形、武器の持ち替えなど特殊な動作をさせたい場合に、対応方法の選択肢に入ると思います。
リグ次第ではリダクション時に累積しやすい末端の誤差(特に足滑り)を抑制したり、アニメーションファイルの容量削減も期待できます。

**デメリット**
リグの共通化はハードルが高く、エンジニアというよりリガーとして能力が求められると感じました。
各コンポーネントの挙動を把握し、UnityかMayaか、コンポーネントか階層か、どこで辻褄を合わせるのか考えながら共通化する必要があります。
例えばUnityのTwoBoneIkは完全なワールド合わせでは無いように見えたため、独自のコンポーネントを作成するか、階層を工夫して使用する必要があると感じました。(勘違いであれば申し訳ないです...)
さらに複雑なリグを組んだ場合、ランタイムで負荷がかかってしまうため、使用する際には注意する必要があります。

**最後に**
UnityのAnimarionRiggingの執筆時点でのバージョンは1.1で正式版ですが、あまり活用事例を聞きません。
この記事が皆様の参考になれば幸いです。
CP/M 備忘録

昔懐かしCP/M。思い出してメモ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/59546e0f-d20d-41ec-c54d-20dc553b2cdc.png)

# 基礎知識

CP/M は intel の 8ビットCPU である i8080 用に作られた DOS (Disk Operating System)。
CP/M は intel 8086 用の CP/M-86 、モトローラ 68000 用の CP/M-68K などもあるが、通常 CP/M と言えば i8080 用の CP/M-80 を指す。
CP/M-80は 1976年発売。執筆時の2021年の45年前！
ザイログの Z80は、i8080 とバイナリ上位互換であり、Z80 命令としてリロケータブルアドレスな命令を備えている。なので1980年台当時はZ80のプログラムをCP/M上で動かすことが多く行われていたが、CP/M自体はi8080命令セットのみで作成されているため、CP/Mのシステムをメモリ上で再配置するには再コンパイルなどのテクニックが必要。それが動作や操作に影響を及ぼしているのが特徴である。

# メモリサイズ

- 上記は62K CP/M のアドレス。CP/Mは8080命令セットで作成されているためリロケータブルではない。
-  他のメモリサイズの場合はそれに合わせてバイナリを作成しインストールする。

リロケータブルの意味は、プログラムを別のアドレスに置くことができるという意味。8080命令セットはジャンプ命令がアドレス絶対番地指定のため、このような制約がある。8080上位互換のZ80命令セットはジャンプ命令が相対番地指定できるようになり、リロケータブルがある程度可能になった。

# CCP/BDOS領域の侵害

- CCPのエリアは ユーザアプリが動作している間は使用しないので、ユーザプログラムにより破壊しても良い。  
- BDOSの機能も使わないアプリケーションの場合は、BDOS領域も破壊しても良い。
- 破壊されたCCP/BDOSはリブート時に再ロードされる。


# BIOS

- BIOS は各マシン向けにカスタマイズされ、CBIOS (Customized BIOS)と呼称されていた。CBIOS は通常ソースコードが提供されていて、メモリの配置位置を再アセンブルして調整することが行われていた。

- 上記がロードされた状態で、BIOS先頭(上図ではF200H) にジャンプすれば a> プロンプトが出るらしい。(BDOSは動かない状態)

# エミュレーター

IMSAI Altair 8800 のシュミレーターと併せ、CP/Mイメージが公開されている。
https://schorn.ch/altair.html

実機がなくても MS-Windows/Mac/Linux などで動かすことができる。

# コマンドインタプリタ

パイプやリダイレクトはじっそうされてい
標準入力、標準出力の概念はあった? なかった?
【2021.12.20】海外Web3ニュース

#１．TerraがTVLでEthereumに次ぐ2位に
・BSCを抜いて、TerraがTVL（Total Value Locked、BSC等のチェーン上のDeFiにロックされている暗号資産の合計額）でEthereumに次ぐ2位に
・そのTerraで今最も多いTVLをもつプロジェクトは、Anchor
・Anchorは、信頼できる預金商品を提供することを主な目的としたDeFiプロトコルで、UST（TerraUSD、Terraステーブルコイン）を預けることで安定した利回りを受け取ることができる

https://u.today/terra-becomes-second-biggest-defi-platform-behind-only-ethereum

●コメント
たしかに今年BSCが伸び悩んでいるのに対して、Terraが伸びている（下記BSCとTerraのTVL推移チャート参照：https://defillama.com/chainsより）

BSC
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2411201/103fca27-736a-2516-2e52-b44bca790951.png)
Terra
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2411201/520c99de-4253-9ad4-e68a-200bf681cc7d.png)


#２．5年後2027年仮想通貨利用者は5倍の10億人に
・現在2億人程度が仮想通貨利用者（ウォレットをもっている）
・これはインターネットの1997年の利用者数と一緒
・そのため、このまま増加が続けば2027年には10億人ほどになる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2411201/bf76e288-d836-f3cf-5752-5595342eeea2.png)

https://cryptoslate.com/internet-vs-crypto-adoption-chart-predicts-1-billion-users-by-2027/

●コメント
a16zの政策提言レポートでも2021年がインターネットの1997年ということは言われていた（P13）
https://a16z.com/wp-content/uploads/2021/10/How-to-Win-the-Future-Deck.pdf
また10億人になるというのは、CoinbaseのPresidentが言っていた
https://blockworks.co/coinbase-president-crypto-on-pace-for-1-billion-users-within-5-years/
ただ今回の記事の図がわかりやすいため掲載
mapshaperを使って地図データを軽量化する

# 概要

mapshaperへの地図（図形）データの取り込み方、軽量化についてメモします。

# 今回使用するデータ

国土数値情報より、静岡県の津波浸水想定データ（シェープファイル）を利用します。
記載にあるとおり、各所の利用条件には注意してください。

https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-A40-v2_0.html


# 地図データを軽量化する

### 1. mapshaperを開き、シェープファイルを読み込ませる

https://mapshaper.org/

```
A40-16_22.dbf
A40_16_22.prj
A40_16_22.shp
A40_16_22.shx
```

* 上記のファイル群をドラッグ&ドロップ。
    * shpだけではダメ。dbfには図形の属性、shpには座標、shxにはこれらのインデックス情報（対応関係）が記されており、座標系を定義するprjとあわせて一括で取り込むようにします。

### 2. import Optionsを指定してインポートを実行

* import Optionsに下記を入力し、「Import」ボタンを押してください。
    * `encoding=sjis`
    * これは日本語の記載を含むdbfを読み込むため。他のケースでうまくいかない場合はdbfのエンコード形式を確認。
* 他のオプションは一旦そのままでいいと思います。
* うまくいくと、中央に地図（図形）データのプレビューが表示されます。読み込みファイルに問題があった場合は、中央上のファイル名を押した先で確認できます。

### 3. 「Console」を開いてデータを変換する

```
% --dissolve
```

* これは図形をまとめる（融合する）コマンドです。用途によりますが軽量化のため、ここでは複数の階層をもっている浸水域を1層に統合しちゃいます。

![mapshaper.org_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390349/c01297aa-b9f5-03e6-ded1-dcc6e21d120c.png)
↓
![mapshaper.org_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390349/fcd482f5-94f6-c8c5-1b02-82934f56f290.png)

* シンプルになりました。

```
% -proj wgs84
```

* これは座標系をWGS84に変換するコマンドです。一度出力したデータの緯度経度が「おかしいな？」と思ったら試してみてください。

### 4. 「Simplify」を開いてデータを簡略化する

* 設定そのままで「Apply」ボタンを押したあと、どれだけ簡単にするか（100%-0%）をスライダーで調整。
* 簡略化なので、浸水域のようなポリゴンデータではラインもぐちゃぐちゃになります。……それは実用面としてどうなの？実際には加工の旨も説明しておくとよいでしょう。


### 5. 「Export」を開いてデータをファイル出力する

* 下図はLeafletでの表示例です。

![rapture_20211220110034.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390349/d1d7132b-d238-fdfc-7766-fc4c8fadbaa6.png)
【初心者向け】newとgetInstance()の違い

##こんにちは。
いろいろなテキストやネットのコードを見ててインスタンスを生成するときに、newを使うときとgetInstance()を使うときが出てきて、扱いの違いがわからなかったので調べてみた。

##new演算子
あるクラスから実体のあるインスタンスオブジェクトを取得する

##getInstance()メソッド
あるクラスから実体のあるインスタンスオブジェクトを取得する

##（🔰）一緒に見える
（🔰）でもgetInstance()はSingletonパターンというものであることがわかった！

##getInstance()はSingletonパターン
###Singletonパターンとは
デザインパターンの一つ。
<b>「あるクラスのインスタンスが常にたった1つしか存在していない」</b>
という状態を実現したいときに使用される。

###Singletonのメリット
複数のインスタンスを作られると困る場面では
必ず一つしか作れないようにできる。

###Singletonのデメリット
どこのクラスからでも常に同じインスタンスを使用することになるため、
グローバル変数と同じような扱いで、どこからでも変更ができたり、
クラス同士の結合度が高くなってしまう。

###まとめ
Singletonパターンを採用しているクラスのインスタンスを取得するときには
getInstance()メソッドを使用しよう

##さいごに
new演算子は何個も中身の違うインスタンスを取得できるクラスに対して使用し、
getInstance()メソッドはたった一つのインスタンスしか取得できない
Singletonパターンのクラスに対して使用する。

javaAPIの中にもnewできないクラスがあるため、知っておくことが必要。
（ex..Calendarクラス）
FlexboxLayoutManagerを利用した際のEditTextのfocusについて

会社ではRecyclerViewにいろいろなサイズ幅のViewを入れるフリーレイアウト機能みたいなのがあり、そこでFlexboxLayoutManagerを利用してRecyclerViewを利用しています。
その際にEditTextが入った時にフォーカスが外れるという現象に遭遇しちょっと調べた内容をまとめておきます。

下記条件が揃った時のみですが、フォーカスが強制的に外れます。。。
1. softInputModeをadjustResize
2. EditTextをキーボードが隠れる位置に配置

LinearLayoutManagerの場合
<img alt="linearLayoutManager" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1893524/f6a2edd8-a8e0-45ff-23e1-923c79271f64.gif" width="320">

FlexboxLayoutManagerの場合
<img alt="linearLayoutManager" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1893524/f8aad4da-002e-e7ef-8637-2fb86632d160.gif" width="320">

キーボードが表示された際に画面サイズの変更が行われた際、EditTextの要素が画面外になることで、フォーカスが外れてしまいます。
LinearLayoutManagerやGridLayoutManagerでは問題なく動作していた。。。

ソースコードの中を覗くと、LinearLayoutManagerでその調整が入っているようでした。
結構長々と説明が記載されてます。

ソースコードのコメントを抜粋

```FlexboxLayoutManager.java->onLayoutChildの内部
// This case relates to when the anchor child is the focused view and due to layout
// shrinking the focused view fell outside the viewport, e.g. when soft keyboard shows
// up after tapping an EditText which shrinks RV causing the focused view (The tapped
// EditText which is the anchor child) to get kicked out of the screen. Will update the
// anchor coordinate in order to make sure that the focused view is laid out. Otherwise,
// the available space in layoutState will be calculated as negative preventing the
// focused view from being laid out in fill.
// Note that we won't update the anchor position between layout passes (refer to
// TestResizingRelayoutWithAutoMeasure), which happens if we were to call
// updateAnchorInfoForLayout for an anchor that's not the focused view (e.g. a reference
// child which can change between layout passes). 
```

読む限りではまさに発生している事象の内容っぽい。
LinearLayoutManagerに処理が入っているため、GridLayoutManagerではLinearLayoutManagerを継承しているため問題は発生しない様子。。。
FlexBoxLayoutManagerはLinearLayoutManagerを継承はしておらずで、特にadjustResizeのところの考慮が入っていないのでダメっぽい？

FlexboxLayoutManagerで色々試してみたところ、同様にonLayoutChildrenでレイアウトの処理がされてそう。
その時に同じようにfocusされているviewに対しての条件などは含まれていなさそうなので、Viewが確定された時にフォーカスが外れて、再度onLayoutChildrenが呼ばれているようだった。

onLayoutChildrenが呼ばれたタイミングのレイアウト状態としては、フォーカスされたViewが隠れたままになっているので、親のonLayoutChildrenが呼ばれるよりも先にフォーカスされたViewを移動させる形で、下記で対応した。
このタイミングであればfocusedChildはnullになっていないので問題なかった。


``` kotlin
private class CustomFlexboxLayoutManager(
    context: Context,
    private val recyclerView: RecyclerView
) : FlexboxLayoutManager(context) {
    private var preLayoutHeight = 0

    override fun onLayoutChildren(
        recycler: RecyclerView.Recycler?,
        state: RecyclerView.State?
    ) {
        // Layout確定前に画面内にフォーカスされたViewが入るように移動する
        // キーボードの表示がされた際の判定
        if (preLayoutHeight > recyclerView.height) {
            focusedChild?.let {
                scrollToPosition(getPosition(it))
            }
        }
        preLayoutHeight = recyclerView.height

        super.onLayoutChildren(recycler, state)
    }
    }
```

色々調べてみたんですが、この辺りの処理を対応しているような海外の記事もなく、adjustPanにする方法で回避などはあったのですがadjsutPanは推奨ではなさそうなのと、チームメンバーからもadjustResizeで対応した方が良さそうというアドバイスをもらったので今回の形で対応してみました。
他にこのやり方良さそうなドアれば教えてもらえると嬉しいです！
centos で vsftpd ftp

今回は centosstream8。
FTPサーバーを立てましょう。

#ftpをインスコします

```
dnf -y install vsftpd
```

#設定ファイル編集

```/etc/vsftpd/vsftpd.conf

# コメントを外す

chroot_local_user=YES
chroot_list_enable=YES

#追記
pasv_enable=YES
pasv_min_port=60001
pasv_max_port=60010
force_dot_files=YES
use_localtime=YES

```

#ユーザー追加

vim /etc/vsftpd/chroot_list

```

hideki

```

#firewall を オープン

```

firewall-cmd --zone=public --add-service=http --permanent
firewall-cmd --reload

```


#起動

```

systemctl start vsftpd
systemctl enable vsftpd

```

`OK`
Grid Layout

# Grid Layout

とてもわかりやすい記事がありましたので、以下のサイトを見ながら進めていきます。

https://qiita.com/kura07/items/e633b35e33e43240d363

# 補足

##### セマンティックについて

セマンティックHTMLまたはセマンティックマークアップは、単なる表示ではなく、Webページに**意味**を導入するHTMLです。
これらを正しく使用することで、ページとそのコンテンツの意味がブラウザに明確になります。その明確さは検索エンジンにも伝達され、適切なクエリに対して適切なページが配信されるようになっています。

https://www.greelane.com/ja/科学技術数学/コンピュータサイエンス/why-use-semantic-html-3468271/
普通のエンジニアとしてOSSにコントリビュートする時に考えていること

こんにちは[とるめん](https://twitter.com/qwyngg)です。
この記事は[グロービスアドベントカレンダー2021](https://qiita.com/advent-calendar/2021/globis)の20日目の記事です。
先日は@maKunugiさんの[グロースハックに関するお話](205738ce97c47bac634a)でした。
この記事ではOSSへの貢献について考えていることを書きます。

# 概要
最近Log4jの脆弱性等でOSSが話題になりましたね。普段お世話になっているライブラリへの貢献を意識した方も多いのではないでしょうか。ですが「キッカケがない..」「難しそう...」といった理由でまだ一歩踏み出していない方もいると思います。
私自身も凄腕エンジニアではありませんし、バリバリ貢献しているわけではないのですが、多少はOSSに貢献した経験があるので自分なりに意識していることについて書こうと思います。

# 貢献へのきっかけ
OSS貢献してみたいけどどこから初めていいかわからないという方が多いと思います。私がオススメするのは業務で使っているOSSから始める方法です。
業務では使っているOSSのドキュメントを読んだりテストを見る機会が多いです。その中でtypoを見つけたら直してしまいましょう。他の人がコード読む時のスピードがもしかしたら早くなるかもしれませんし、翻訳にかけやすくなったりするかも知れません。
業務で使っているOSSにテストが足りないと思ったら足してもらう提案もいいと思います。[^1]　将来業務で言語やフレームワークをアップデートする時に絶対に役に立ちます。
実際にコードを修正したりするための時間やレポジトリへの理解がない場合はissueをたてるのもいいでしょう。
業務ではエッジケースが発生することが多く、OSSに追加して欲しい機能というのが出てきやすいです。ぜひ自分の使っているライブラリには変更や修正が提案できるんだという意識をもってみてください。

# 実際に貢献する時考えること

## READMEを読む
これが一番大事です。必要な情報はだいたいのってます。
貢献に対する具体的な方法はCONTRIBUTINGという見出しや別ファイルで記載されていることが多いです。

## 過去issueを見る
過去のissueを見るとレポジトリの空気感がわかります。自分は主に以下の観点で見ています。

#### 自分の考えている問題と同じような既存のissueやPRはないか？
既に同じ内容のissueやPRがあるならついてるコメント等全部読んだりして解決しているのかわざと解決していないのか確認します。同じ内容のissueを乱立されてもメンテナーの方は困ってしまいます。過去バージョンに対して同じ内容でissueが立っているのを見つけた場合は「現行バージョンでもこんな風に再現します」という風にコメントするのも良いと思います。
#### GitHub以外にissueについて議論しているフォーラム的なものはあるか？
大きめなOSSだとGitHub以外にメールフォーム等議論の場が存在する場合があります。それを認識しないで提案やissueを行うと色々すっ飛ばし兼ねないので確認しておくと良いでしょう。
Ruby on Railsなんかはセキュリティに関する問題は別口で起案してほしいと明記されてますね。[^2]
#### 問題の再現スクリプトはどんなふうに書かれているのか？
バグでも機能追加でも現状のコードの動作を説明する必要があると思います。その際に再現スクリプトがあるとメンテナの方が確認しやすいです。他のissue立てている人のスクリプトを参考にすると分かりやすいスクリプトになり、良いissueやPRになると思います。
#### closeされているissueはどんな理由でcloseされているのか？　
closeされているissueもチラ見すると良いと思います。コメント等からメンテナの方の方針がわかります。
#### どんなCIを行っているのか？
CIの内容もレポジトリにより様々なので見ておくと良いでしょう。コードの修正をするときに気にかけるべき内容がわかります。依存ライブラリのバージョンを複数検証していたり独自のドキュメント精査を行っていたり色々あります。
#### issueやPRのテンプレート的なものはあるか？
issueやPRを試しに立てようとしてみてテンプレートの内容を確認するのもオススメです。提案内容を説明する文章を考える時の骨子になってくれます。
#### コミットメッセージはどのように書かれているか?
コミットメッセージに独自のルールがあったりするレポジトリもあるので確認すると良いでしょう。特になさそうだったらWhyを意識する通常のコミットメッセージでも問題ないと思います。
#### PRにはコードやテスト以外に含めるべきものはあるか？
変更と一緒にCHANGELOGも追記する必要があるレポジトリもあります。他の方のPRを見てコードやテストの修正以外にも変更しているファイルがあるか確認すると良いでしょう。
#### メンテナーの方がコードにどんな指摘をしているのか？
とっても大事ですね。多めのコメントがついてるPRをみたりすると良いでしょう。

### issueやPRのコメントをちゃんと書く
僕も完全にできているわけではないんですが、以下のようなことを気をつけると良いんじゃないかと思います。

#### 自分が報告している問題はちゃんと説明する。再現スクリプトを書いたりコードの実行結果を記載する
過去issueを見る、でも書きましたが、問題をコードで説明できていると分かりやすいPRになります。コード以外にも参照リンクを貼ったり等色々できることはあると思います。
#### issueには自分が使用しているライブラリのバージョンを記載する
これも検証しやすくなるのでおすすめです。
#### 既存issueを治すPRならちゃんとfix #xxxとつける
大事ですね。

## 最後に
これ以外にもこんなこと見てるよ！考えてるよ！という人がいたらぜひコメントで教えて下さい！
また、ここまで色々書いてきましたが、PRやissueをやたらめったらたてることが良いことではありません。メンテナーとしても自分が管理しているコードに他人のコードをいれるのは色々リスクがあります。
以下はRubyコミュニティでのOSS関するリンクですが、参考になると思います。

- https://github.com/rails/rails/pull/13771#issuecomment-32746700
- https://speakerdeck.com/knu/ossdejie-guo-wochu-sufang-fa

[^1]: [例](https://github.com/brendon/acts_as_list/pull/393)、CIの時間が長くなったりして迷惑かもしれないのでレポジトリの空気を読んだ上で
[^2]: https://rubyonrails.org/security
APRESIA NPシリーズのファームウェア更新の方法　備忘録

## 概要
APRESIA NP2000シリーズのファームウェア更新をしたので
その備忘録です。ちょっと内容が古いです。

****
## 参考サイト
https://www.apresia.jp/products/ent/np/usersguide/management/top.html?p=NP_updt_t_update_stack.html
ファームウェアのアップデート
****

## 実際のコマンドをまとめたもの
スタックしたりSDカードブートの影響で少々マニュアルとコマンドが違うため、記録しています。

### ①show boot
### スタックしている場合 ②copy tftp: flash:
```
Address of remote host []? 192.168.3.147　<- tftpサーバーです
Source filename []? AEOS-NP2000_R10801.had
Destination filename []? /c:/AEOS-NP2000_R10801.had
```
### スタックしていない場合 ②copy tftp: flash:
```
Address of remote host []? 192.168.3.147　<- tftpサーバーです
Source filename []? AEOS-NP2000_R10801.had
Destination filename []? AEOS-NP2000_R10801.had
```
### ③dir　
ファイルがローカルフラッシュ上にあるのを確認する（SDカードブートの場合はSDにコピー backup cloneをあとで実行します。）
### ④configure terminal
### ⑤boot image AEOS-NP2000_R10801.had
ここでbootファイルを指定しています。
#### SDカードブートを設定している場合！！！☆backup cloneをここで実行！！！！
### ⑥end　→reboot 　→show version
コマンド分け忘れました

### ⑦show boot
### ⑧copy boot

### スタックしている場合 ⑨copy flash: flash:
bootファイルの場所を確認します。

```
Source filename []? /c:/AEOS-NP2000_R10801.had
Destination filename []? /c:/AEOS-NP2000_R10801sec.had
```
### スタックしていない場合 ⑨copy flash: flash:
bootファイルの場所を確認します。

```
Source filename []? AEOS-NP2000_R10801.had
Destination filename []? AEOS-NP2000_R10801sec.had
```
### ⑩show boot
### ⑪con t
### ⑫boot image  AEOS-NP2000_R10801sec.had secondary
### ⑬end
### ⑭show boot
```
Unit 1
(Configured)
 Primary boot image: /c:/AEOS-NP2000_R10801.had
 Primary boot config: /c:/primary.cfg
 Secondary boot image: /c:/AEOS-NP2000_R10801sec.had
 Secondary boot config: /c:/secondary.cfg
*(SD Card)
 Primary boot image: /c:/AEOS-NP2000_R10801.had
 Primary boot config: /c:/primary.cfg


Note: * indicates the used boot information.
```
### ⑮dir
```
Directory of /c:
1   -rw       7184260 Mar 09 2020 17:31:39  AEOS-NP2000_R10801sec.had
2   -rw          2071 Jul 18 2018 16:40:51  secondary.cfg
3   -rw       7184260 Mar 09 2020 16:37:01  AEOS-NP2000_R10801.had
4   -rw       6991424 Jul 18 2018 16:35:52  AEOS-NP2000_R10401.had
5   -rw       6991424 Jul 18 2018 16:36:22  AEOS-NP2000_R10401sec.had
6   -rw         15568 Mar 09 2020 17:08:32  primary.cfg
7   d--             0 Mar 09 2020 08:29:35  system

30656000 bytes total (1690112 bytes free)
```
### ⑯delete AEOS-NP2000_R10401.had
古いファームウェアを削除しています。

```
Delete AEOS-NP2000_R10401.had? (y/n) [n]  y
File is deleted.
```
### ⑰delete AEOS-NP2000_R10401sec.had
古いファームウェアを削除しています。

```
Delete AEOS-NP2000_R10401sec.had? (y/n) [n]  y
File is deleted.
```
### ⑱dir
```
Directory of /c:
1   -rw       7184260 Mar 09 2020 17:31:39  AEOS-NP2000_R10801sec.had
2   -rw          2071 Jul 18 2018 16:40:51  secondary.cfg
3   -rw       7184260 Mar 09 2020 16:37:01  AEOS-NP2000_R10801.had
4   -rw         15568 Mar 09 2020 17:08:32  primary.cfg
5   d--             0 Mar 09 2020 08:29:35  system

30656000 bytes total (15674880 bytes free)

```
PowerAppの逆引き数式シート

# 概要
これはPowreAppでやりたいことから、逆引きしてその方法（数式）をまとめたチートシートです。

## グローバル変数を設定したい
```
Set(
    inputGuestUserId, #変数名
    userid_input.Text #テキストボックス.テキスト内容
);

```
## 一致するものがあるかデータから検索する
これを見たら詳しく記載があります。
https://docs.microsoft.com/ja-jp/powerapps/maker/canvas-apps/functions/function-filter-lookup

```
例）
            LookUp(
                develop_UserList, #データ名
                user_id = GuestUserID #データの列名　検索するデータ
            )
```
## エラーメッセージを通知する
詳しく
https://docs.microsoft.com/ja-jp/powerapps/maker/canvas-apps/functions/function-showerror

```
    Notify(
        "ユーザーIDの登録がありません",　#メッセージ内容
        NotificationType.Error　#エラーの種類
    )
```
## 画面遷移
```
Navigate(GuestUserOderTop_Screen,ScreenTransition.Cover) #Navigate(スクリーン名,移動時のアニメーション)
```

## 表示するリストの一部だけ表示する
```
    Filter(
        develop_menuList, #データ名
        invaid = false #条件（今回はinvaidがfalseのものを表示)
    )
```
## 表示するリストの順番を変える
```
Sort(
   devlop_menuList # データ名
    ),
    menu_date,　#データの列名
    If(
        SortDescending1,  #変数にTrueかFalseが入っている
        Descending, #降順
        Ascending #昇順
    )
)
```
```
Sort([データ名],[データの列名],[降順か昇順か（Descending,Asending)])
```

## 表示するリストの降順と昇順を切り替える
```
UpdateContext({SortDescending1: !SortDescending1})
```
## データの再読み込みをさせたい
```
Refresh([@develop_menuList])
```

## 新しいデータを登録したい
```
SubmitForm(OderEditForm)
```
フォームに対してデータを送ると考えてください

## Timerを使ってアニメーションさせたい
TimerはStartやResetのオプションを細かく設定しないと、うまく動作しません。
そのためSetを使って変数を用意してください。参考：色を変化させて変わった感を出す例

```
varTimerR = Resetオプションの変数
varTimerS = Startオプションの変数

スタート時：
スタートさせるボタン等のOnSelect
Set(varTimerR, true);
Set(varTimerS, true)

カウントン中変化させたい値：
TimerのDurationを1000(1秒)に設定しています

表示させているGullaryなどのFillオプション等
RGBAの変化で色の変化を演出
RGBA(10,10,10,0.2 - Countdown.Value/1000)

カウント終了時：
TimerのOnTimerEnd
Set(varTimerS ,false);
Set(varTimerR,false)

```

## 入力されているテキストボックスなどを初期値にしたい

```
Reset([要素]);
```

## ローカル変数を作成したい
```
UpdateContext({CountT:0});
//CountTという変数を0に設定しています
```

## 有効化無効化
```
DisplayMode.Edit　//有効化（編集可能)
DisplayMode.View //みるだけ
DisplayMode.Disable //無効化
```

## リストのアイテムを作成してから、Patchで新規のアイテムをリストに追加する
### 先にClearCollectで作成することで、UID（アイテムの固有のID）を取得することができるのです。

```
ClearCollect(CreateRcord,
    Patch(list,
        Defaults(list),{
            'user_e-mail':User().Email,
        }
    )
);

Patch(inq_list,
    Defaults(inq_list),{
        inquiry_id: First(CreateRcord).id
    }
);



```
p5.jsで3Dモデルを描いてみる

この記事は Qiita p5.js アドベントカレンダー22日目の記事です。

p5.jsの関数について今までつらつらと記事を投稿してきたのですが、**WEBGLモード**を触ってないことに気づいたので今回試してみようと思います。

## さっそく試してみる
3Dの物体を描くにはcreateCanvasの第三引数に`WEBGL`を追加してあげます。

```javascript
function setup() {
  createCanvas(400, 400, WEBGL);
}

let angle = 0

function draw() {
  background(0)
  normalMaterial()
  rotateX(noise(angle)*7)
  rotateY(angle)
  angle = angle + 0.01
  box(100)
}
```
![画面収録-2021-12-20-10.22.25.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358229/0fba761b-acd6-e4a9-3939-75b9c88a2d97.gif)


途中覚えたてのnoiseで遊んじゃっていますが、`box()`を描画できています！
しかもこの行数で。驚きです。

`normalMaterial()`は光の影響を受けない物体を描画するために実行するもので、テストのときなどに使用する素材です。

では光の影響を受ける物体を描画してみましょう。

```javascript
function draw() {
  background(0)
  noStroke()
  ambientLight(60, 60, 60);
  pointLight(255, 255, 255, 50, 100, 100);
  
  ambientMaterial(255, 0, 100)
  rotateX(noise(angle)*7)
  rotateY(angle)
  angle = angle + 0.01
  box(100)
}
```
![画面収録-2021-12-20-10.55.14.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358229/c339dae8-60b8-aecc-c181-8591f0bb4697.gif)

光があたっていますね！
`ambientLight()`で全体的に少し光を当て、`pointLight()`で１点に向けて光をあてています。

```javascript
ambientLight(60, 60, 60);
pointLight(255, 255, 255, 50, 100, 100);
```

今回使用している`ambientMaterial()`は光の影響を受ける物体を描画することができます。
また引数に色の情報を渡すことで物体に色をつけることができました。

```javascript
ambientMaterial(255, 0, 100)
```

### GeometryとMaterial
ここまでMaterialという関数を使用してきましたが、実はこれがなくても動きます。

```javascript
function draw() {
  background(0)
  rotateX(noise(angle)*7)
  rotateY(angle)
  angle = angle + 0.01
  box(100)
}
```
![画面収録-2021-12-20-11.22.49.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358229/59fdd8a4-80ec-436b-0b9a-380dca980115.gif)


これは`Geometry（形の骨格となるもの、ここでいうbox）`がちゃんと実行されているからなんですね。
今までのambientMaterial()などは`Material（表面を整えるもの、素材の決定）`のことで、これがあることで物体に色がついたり、光があたる表現が可能になります。

Three.jsを触っていると必ず両方使用するのですが、p5だとさわり始めはこの概念が混在しそうだなと思いました。
にしてもこの行数で3Dを描画できるというのは本当に楽です。すごい。

### Z軸を利用する
WEBGLモードにするとX軸、Y軸に加えてZ軸がおもしろい表現をしてくれます。
次のようにして適当にトーラス（円環面）を追加し、boxのZ軸を180にしてみました。

```javascript
function draw() {
  background(0)
  angle = angle + 0.01
  rotateX(noise(angle)*7)
  rotateY(angle) 
  
  push()
  translate(0, 0, 180);
  box(100)
  pop()
  
  push()
  torus(30, 10);
  pop()
}
```

![画面収録-2021-12-20-11.47.32.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358229/23cc8c48-97f1-ca09-14d7-73eb254361aa.gif)


奥行きがでて表現にぐっと面白みが増しました！
なんだかわくわくしますね！

## まとめ
p5はとても簡単に3Dモデルを描画できますね。
他のツールと比べると簡単すぎるくらいの印象を受けました。

他にも`specularMaterial（）`で鏡面反射な素材にしてみたり、カメラやインタラクションの追加も簡単に行うことができます。
いろいろ試して遊んでみましょう〜〜〜！

## 参考
[p5.js reference](https://p5js.org/reference/)
Elasticsearch-sudachi で sudachi.json をつかわずに設定を追加する

## まとめ

[Elasticsearch-sudachi](https://github.com/WorksApplications/elasticsearch-sudachi) で Sudachi の設定をかえたいとき、`additional_settings` をつかえば直接設定を追加できます。


## 従来の方法

辞書をデフォルトの system_core.dic 以外に切り替えたり、ユーザ辞書を追加したいとき、以前は Sudachi.json を用意して `settings_path` でファイルを指定する必要がありました。

```json
{
  "settings": {
    "index": {
      "analysis": {
        "tokenizer": {
          "sudachi_tokenizer": {
            "type": "sudachi_tokenizer",
            "settings_path": "sudachi/sudachi.json"
          }
        },
        "analyzer": {
          "sudachi_analyzer": {
            "filter": [],
            "tokenizer": "sudachi_tokenizer",
            "type": "custom"
          }
        }
      }
    }
  }
}
```

設定が複数の箇所に分散するため非常にわずらわしく管理しづらい状況でした。

## あたらしい方法

バージョン2.1.0から `additional_settings` をつかって直接 sudachi.json の内容を指定できるようになりました。

```JSON
"tokenizer": {
  "sudachi_tokenizer": {
    "type": "sudachi_tokenizer",
    "additional_settings": "{\"systemDict\":\"system_full.dic\",\"userDict\":[\"user.dic\"]}"
  }
}
```

指定した JSON は Sudachi のコマンドラインの `-s` オプションをつかったときと同様に解釈されます。[^1]

[以前紹介した](https://qiita.com/kazuma-t/items/499474d96ead21a37185) `allowEmptyMorpheme` もおなじように指定できます。

```JSON
"tokenizer": {
  "sudachi_tokenizer": {
    "type": "sudachi_tokenizer",
    "additional_settings": "{\"systemDict\":\"system_full.dic\",\"allowEmptyMorpheme\":false}"
  }
}
```

JSONを文字列に押し込んでいるので若干かきづらいですが、余分なファイルをつくることなくすっきり管理できます。

ではよい Sudachi life を。

[^1]: デフォルトの設定ファイルに対して、重複する項目は上書き、ないものは追加。
[UE4] Bink2ForUnrealのヘルプとコマンドライン実行

検証バージョン：UE4.27.0

#1. 概要
　UE4.27からBinkがエンジンに組み込まれるようになり、標準機能として利用できるようになりました。
https://www.unrealengine.com/en-US/blog/bink-video-and-bink-audio-now-available-in-unreal-engine-for-free

　Binkを使うにあたって、動画の1つ1つを連番画像からコンバートするような作業が結構手間だったりするのですが、手動ではなくコマンドラインから実行することもできます。

#2. 方法
 Binkの各処理をコマンドラインから実行する方法やどのようなコマンドが指定可能かは、ヘルプにてご確認ください。
以下はBinkアプリケーションのディレクトリに移動した後、ヘルプコマンドを実行する例です。

```:Bink2ForUnrealのヘルプ操作例
D:\>cd D:\Launcher\UE_4.27\Engine\Binaries\ThirdParty\Bink
D:\Launcher\UE_4.27\Engine\Binaries\ThirdParty\Bink>Bink2ForUnreal /?
```

コマンドのヘルプ部分だけを抜粋すると以下のようになります。

```:Binkアプリケーションのヘルプ
Bink2ForUnreal /?
```

これを実行すると以下のように各オプションのヘルプが表示されます。
![2021-12-20_11h38_50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101019/31355fed-19d2-f867-1c91-09f5197de3a9.png)

ここに出てくる***Bink2c***や***BinkMix***といったコマンドは、このツールのどのオプションを利用するかを指定するものです。
(実際にBinkアプリケーションを手動で起動した際には以下の赤枠のようにGUIが存在しています)

![2021-12-20_11h24_43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101019/cdde6e8c-174b-ec9b-6495-6f0d86d55b48.png)

各オプションの機能を利用する場合は以下のようなオプション付きのヘルプ"/?"を指定します。

```:コンバーダーのヘルプ
Bink2ForUnreal BinkConv /?
```
このコマンドを実行すると、以下のように必要なコマンド引数とオプションが表示されます。
![2021-12-20_11h47_59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101019/96923047-98d4-2a6e-87d0-2f1dd36a319a.png)

　このようにコマンドラインから実行できることも把握しておくと、ワークフローを自動化できたり自分の欲しいオプションを見つけるのに役立ちます。
Amazon Lightsail を使ってみたはなし

# はじめに

この記事は JSL (日本システム技研) Advent Calendar 2021 - Qiita 20日目の記事です。

毎年恒例、一人アニバーサリー記念です。:tada:
現場を離れているせいで、いよいよネタが無くなってきました。

たまたま案件で使用した[Amazon Lightsail](https://aws.amazon.com/jp/lightsail/ "Amazon Lightsail")を使う機会があったので、特徴や使ってみた感想を書きます。

# Amazon Lightsail とは
AWSが提供するVPSです。月額定額3.5$（*1）から始められるのが特徴でEC2と同様の使用感で扱えます。
インスタンス立ち上げ時も以下のように用途に応じて、プランを提案してくれるので非常に便利です。

*1 厳密いうと、通信料は上限あり、超過分は課金されます。

![Lightsail-plan.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20512/4d9a4755-7939-8afe-8541-ad4eb33c3cd9.gif)

* メリット
  * 月額固定料金でEC2を実行できる
  * [Bitnami](https://bitnami.com/stacks)のアプリケーションテンプレートを使用できる
  * ブラウザからSSH接続が可能

* デメリット
  * 月額固定のためインスタンスを停止しても課金されてしまう
  * 他アカウントからの移行ができない？
  * Autoscalingが出来ない。大規模なアプリケーション開発には向いていない（ただし手動では増やせる）
    
# 今回のゴール
+ Lightsailについて調べてみる
+ Lightsail上でBitnamiのDjangoテンプレートを使用してみる

# インスタンスを立ち上げてみる
ひとまずOSのみ（Amazon Linux2）を選択して、その他は、特になにも設定しなくても、以下のような感じでブラウザよりSSH接続可能です。いわゆるAmazon Linux2のAMIイメージのインスタンスが起動します。

 レンタルサーバーだとパーミッションの制限がありスクラッチ開発で使いづらいですが、`Lightsail`は月額固定でAmazon EC2が使用できるため小規模開発やランニングコストが気になる時に使用すると良いと思いした。

![Screen Shot 2021-12-17 at 20.17.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20512/6a1131bc-15b7-0d6a-eb8a-a3cda908b56b.png)


# Djangoテンプレートをでインスタンスを立ち上げてみる

次にDjangoテンプレートを使用してインスタンスを起動してみます。
5$/月以上のプランでないと使用できないようです。

また、デフォルトではユーザーが`ec2-user`ではなく、`bitnami`になったり、OSは`Debian`が起動するようです。

![Screen Shot 2021-12-17 at 20.29.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20512/0eb4a00e-bebe-d974-553a-8498905cad4d.png)
バージョン確認
```$ cat /etc/debian_version
10.11
```

## Djangoテンプレートの各種バージョン
テンプレートによってインストールされたライブラリを確認してみます

```
$ python --version
Python 3.8.12
```

pipを確認すると、MySQL、PostgreSQL、Sqliteへの接続ライブラリがインストールされている模様。

```
$ pip freeze
asgiref==3.4.1
backports.entry-points-selectable==1.1.1
distlib==0.3.3
Django==3.2.9
filelock==3.3.2
mysqlclient==1.4.6
platformdirs==2.4.0
psycopg2==2.9.2
pytz==2021.3
six==1.16.0
sqlparse==0.4.2
virtualenv==20.10.0
```

* WebサーバーはApache・・
* DBもMySQL、PostgreSQL、Sqlite

```
$ httpd -v
Server version: Apache/2.4.51 (Unix)
Server built:   Oct  7 2021 18:37:56

$ mysql --version
mysql  Ver 15.1 Distrib 10.6.5-MariaDB, for Linux (x86_64) using readline 5.1

$ psql --version
psql (PostgreSQL) 11.14

$ sqlite3 -version
3.27.2 2019-02-25 16:06:06 bd49a8271d650fa89e446b42e513b595a717b9212c91dd384aab871fc1d0alt
1
```

テンプレートを見た感覚ですが、同一インスタンス内にアプリケーション/DBサーバーを同居させる前提のようです。

# DjangoをWebサーバー上で起動してみる

[Bitnamiの公式チュートリアル](https://docs.bitnami.com/general/infrastructure/django/get-started/deploy-django-project/)通りに立ち上げてみました。
`Apache + mod_wsgi`へのデプロイ例でした。
もう少しモダンな`nginx + gunicorn`のような構成の方が人気でそうな気がするのだけど・・（とはいえこの構成自体もだいぶ枯れているような）。

# 感想
* LightSailは、月額固定でEC2を立ち上げられると考えれば、個人利用や小規模開発には使えると思いました。
* bitnamiのDjangoテンプレートをを使用した場合、プロジェクトをEC2上で作成しないとメリットが無いように思いました。gitを使用することを考慮すると、ローカル環境でDjangoプロジェクトを作成してデプロイした方が開発しやすく感じました。
* bitnamiの公式チュートリアルをもう少しモダンなものに変えると初学者にオススメしやすいと思いました。
Laravel Docker AWS EC2デプロイ⑤

前回に続き、今回はDNSの設定をしていきます！

##前回

https://qiita.com/yyy752/items/b9d7674fc349f669e801

https://qiita.com/yyy752/items/601646d3683869521f9b

https://qiita.com/yyy752/items/9cec9c44e8a389cb9c18

https://qiita.com/yyy752/items/ce4d38a21b0a01b2be2e

##初めに
EC2では、自動でグローバルIPとドメインが割り当てられます。
（その値はEC2のダッシュボードで確認できます。）

`ここで割り当てられるドメインとIPは定期的に変更されてしまう`為、 せっかくユーザーがWebサイトをお気に入りに登録してくれても、`そのうちリンク切れになってしまいます。`

その為、`グローバルIPを固定して独自ドメインと紐付けることでドメインが変わらないようにする必要があります。`

そして、AWSではDNSの設定を`Route 53`というサービスで行います。
今回はそのRoute 53を使って設定を進めていきます！

##ドメイン取得
ドメインはAWSやお名前.comなどで購入することができますが、AWSは高いので今回はお名前.comで購入しました！
※下記がお名前.comの公式サイトになりますが、`名前.com`で検索するとよくわからない偽サイトに繋がるのでご注意を。

https://www.onamae.com/

購入時にオプションを選択できますが、セキュリティ面を考慮して、ドメインプロテクションとWhois情報公開代行を追加しました。
ここで、SSL証明書の発行も可能ですが、2万円程かかってしまうのと、AWSで無料発行できるため今回はやめておきます。

![スクリーンショット 2021-12-19 21.04.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601015/609f9dd4-b2d0-1cd6-0206-be61b0f86e5b.png)

##DNSの設定
###固定IPの設定
DNSの設定を行うにあたり、まずグローバルIPを固定する必要があります。
IPを固定するには`Elastic IP`というコンポーネントを使い、EC2インスタンスへアタッチします。

こちらの記事を参考に進めていきます。

https://qiita.com/Jerid/items/d5dd3a29ed9a0e374493

※Elastic IPの関連付けを行うと固定IPが設定されますが、固定IPを使用している場合、インスタンス停止中は課金がされてしまいます。ですので、インスタンスを停止する時はElastic IPの関連付け解除も忘れずに！

・関連付け解除手順の参考記事

https://qiita.com/r_saiki/items/6e8aefead1e2adebc43c

###設定
こちらの記事を参考に進めていきます。
なお、現在の表示画面と参考記事の画面が異なりますので、下記に記載した現在の画面も参考にしてください。

https://qiita.com/r_saiki/items/bd49b7b7106bb0d85bd6#dns%E3%81%AE%E8%A8%AD%E5%AE%9A

![スクリーンショット 2021-12-19 23.11.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601015/a2565f75-551e-5fe7-d8cb-fc942ceb34fa.png)

###DNSの確認
各種設定が完了したら、ターミナルから設定の確認をしていきます！

SSHでログインし、以下のコマンドで設定されたネームサーバーを確認してみてください。

```お名前.comのネームサーバー情報が未反映の時はお名前.comのDNSのまま
[ec2-user@ip-10-0-10-10 ~]$ dig aws-dns-practice.work NS +short
dns2.onamae.com.
dns1.onamae.com.
```

```反映されるとAWSのRoute53に変更される
[ec2-user@ip-10-0-10-10 ~]$ dig aws-dns-practice.work NS +short
#設定したネームサーバーが表示される。
```

無事設定の確認ができました。
それでは、登録した独自のドメインでブラウザからアクセスしてみてください。
アプリ画面が表示されれば成功です！

今回の記事はここまでにします。
次回からEC2インスタンスの冗長化を進めていきます！
Firebaseを本番環境と開発環境で切り替えてみた（iOS）

# 投稿の経緯
個人開発でバックエンドにFirebaseを使う場合に、これまでは本番環境でそのまま開発していました。
しかし本番環境を操作すると誤ってユーザーデータを削除してしまう可能性もあり危険です。

なので開発環境と本番環境を使い分けるときにおこなった方法を紹介します。

# 対象者
- 本番環境のFirebaseで開発を進めている人
- Firebaseの接続先を本番/開発で切り替えたい人

# Firebaseプロジェクトの作成
https://firebase.google.com/docs/ios/setup?hl=ja

Firebase を Apple プロジェクトに追加するを参考にして、Firebaseプロジェクトを本番用と開発用の2点作成します。開発用プロジェクトは本番用と区別できるように名前を変えておくのがおすすめです。（xxxTestとかxxxStageとか）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643372/02aa9e9d-e40d-28a5-fed1-8c21917eb5b1.png)

プロジェクトを作成したらそれぞれの`GoogleService-info`をダウンロードします。
こちらも名前を区別できるようにしておきましょう。

ダウンロードしたファイルをXcodeに追加します。
![Qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643372/b9c3ddc7-2e60-9df1-0036-d8b43faf0a79.png)

# 環境を分岐
次に先ほど追加した`GoogleService-info`を本番環境と開発環境で切り替えるためのコードを`AppDelegate`に書きます。

```AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {

    /////省略/////

    firebaseConfigure() 
    return true
}

private func firebaseConfigure() {
    #if DEBUG
        let filePath = Bundle.main.path(forResource: "GoogleService-Stage-Info", ofType: "plist")
    #else
        let filePath = Bundle.main.path(forResource: "GoogleService-Info", ofType: "plist")
    #endif

    guard let filePath = filePath else {
        return
    }

    guard let options = FirebaseOptions(contentsOfFile: filePath) else {
        return
    }

    FirebaseApp.configure(options: options)
}
```

このように書くことで、Build CongigurationがDebugの時は`GoogleService-Stage-Info`を、Debugじゃない場合は`GoogleService-Info`を使ってFirebaseの接続先を切り替えることができます。

この時点でFirestoreの保存・取得・削除などの処理を開発環境で実施することができます。

# 本番環境の動作確認方法
以下の画像の赤枠の部分を選択
![スクリーンショット 2021-12-17 0.02.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643372/50adcdaa-7ccd-9e31-ba04-4ca06782dd8c.png)
Edit Scheme...を選択
![スクリーンショット 2021-12-17 0.01.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643372/70de7540-12cb-ca4f-ec42-372bb7e01fb2.png)
/Run/Build Configuration/ のDebugをReleaseに変更してビルド
![スクリーンショット 2021-12-17 0.02.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643372/ac2f3fb4-8b66-71c0-2ee8-67fb5a2626b8.png)

以上の手順でプロジェクトを本番環境に向けることができます。本番環境のFirebaseを確認したい場合は試してみてください。

# おわりに
最後までご覧いただきありがとうございました！
こうしたほうがいいや、ここはちょっと違うなど気になる箇所があった場合ご教示いただけると幸いです。
Linux入門 3-3 ハードリンクとシンボリックリンク

[](参照ソース)
[Udemyの動画講座]:https://www.udemy.com/course/linuxlpic/?utm_source=bene-content-marketing&utm_campaign=normal&utm_content=story&utm_term=career&utm_medium=udemyads
[Linux入門 3-2]:https://qiita.com/hoglet/items/c6af8d1bd5c256b0369a
[Linux入門 3-4]:https://qiita.com/hoglet/items/70f50d82f5895055b402

# はじめに
Linux初学者である自分向け用の記事です。[Udemyの動画講座]を参考にしました。
僕の勉強法は`動画を見る`→`実際に動かしてみる`→`問題演習`という流れです。

前回まで：[Linux入門 3-2]

***
# 3. LinuC 101 Ver .10.0(問題、テスト、演習)
## ハードリンクとシンボリックリンク
Linuxのファイルシステムでは、「ファイルの中身」「ファイルの属性や管理情報」は別に保存されていて、 i ノードは「ファイルの属性や管理情報」が保存されています。iノード には以下の情報書かれている
・ファイルの種別
・ファイルサイズ
・アクセス権
・所有者
・リンク
・ディスク上の物理的な保存場所（ブロック番号）
iノードを確認するには

```
ls -i
```

ファイルに対してリンクを作成することができ、リンクにはハードリンク、シンボリックリンクがある

```
ln ファイル名 リンク先 : ハードリンクの作成
ln -s ファイル名 リンク先 : シンボリックリンクの作成
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2217966/4d137218-c12a-2032-9c36-ee82a42d864d.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2217966/5d72eb8f-c25a-5471-40d9-35bf66543e16.png)

### ハードリンク

iノードが同じであることが確認できる。
つまり、test.txtとtest_hard.txtは全く一緒だから、どちらかを編集したら、もう一方も反映される。
→バックアップの用途で利用すると便利

```s
[test@localhost 03]$ vi test.txt
[test@localhost 03]$ ln test.txt test_hard.txt
[test@localhost 03]$ cat test_hard.txt
リンクの作成
[test@localhost 03]$ ls -li
合計 8
25291931 -rw-r--r--. 2 test my_group 19 12月  7 08:06 test.txt
25291931 -rw-r--r--. 2 test my_group 19 12月  7 08:06 test_hard.txt
```

### シンボリックリンク
どちらかを編集したら、もう一方も反映される。指しているファイルの削除、移動、リネームをすると利用できなくなる
→ファイル、ディレクトリへの簡易なリンクとして利用できる

```s
[test@localhost 03]$ vi test.txt
[test@localhost 03]$ ln -s test.txt test_symbolic.txt
[test@localhost 03]$ ls -li
合計 8
25291931 -rw-r--r--. 2 test my_group 28 12月  7 08:10 test.txt
25291931 -rw-r--r--. 2 test my_group 28 12月  7 08:10 test_hard.txt
25291930 lrwxrwxrwx. 1 test my_group  8 12月  7 08:13 test_symbolic.txt -> test.txt
[test@localhost 03]$ vi test_symbolic.txt
[test@localhost 03]$ cat test.txt
リンクの作成
symbolic
[test@localhost 03]$ mv test.txt test_bk.txt
[test@localhost 03]$ ls -il
合計 8
25291931 -rw-r--r--. 2 test my_group 28 12月  7 08:17 test_bk.txt
25291931 -rw-r--r--. 2 test my_group 28 12月  7 08:17 test_hard.txt
25291930 lrwxrwxrwx. 1 test my_group  8 12月  7 08:13 test_symbolic.txt -> test.txt
```


*To Be Continued...*
[Linux入門 3-4] へ
***
Vimをちょっとだけ使いやすくする設定【Vim】

# はじめに

皆さんは開発する際のエディタとして何を使っているだろうか?
最近は言語を問わず`VSCode`という方も多いと思うが，CLI環境のLinuxでの開発となると話は変わってくる．
だいたい，派閥としては`vi(vim)`, `emacs`, `nano`等があげられるが，その中でも比較的簡単にカスタマイズしやすく拡張性もあるのが，`vim`である．`vim`というと操作が独特で拒否感を持っている方も一定数いると思うが，自分好みに魔改造することで，ほぼVSCode並のエディタにすることも可能である．今回は，そんな拒否感を持っている方のためにも使いやすいように軽くカスタマイズを試みようと思う．

※本当にVSCode並に魔改造したい人は↓
[vimって極めればvscode並のIDEになるんじゃないの？](https://qiita.com/ulwlu/items/98901f4c4f0683e7aa57)

# `.vimrc`の編集

vimの設定を変更するためには，ホームディレクトリに`.vimrc`ファイルを作成し，vim専用の言語で設定を行う必要がある．

```vim:~/.vimrc
set number " 行番号の追加
set cursorline " 編集中の行をハイライト
set ruler " 右下にカーソルの位置を表示
set showcmd " 入力中のコマンドを表示
set title " タイトルの追加
syntax enable " シンタックスハイライトを有効化
set wildmenu " vim上からファイルを選択できる機能を有効化
set ambiwidth=double " 全角文字の重なりを解消
set backspace=indent,eol,start " 挿入モードでbackspaceを使って削除を可能に
set laststatus=2 " ステータスバーを2行表示
set history=1000 " コマンドの履歴を1000件保存
set showmatch " 対応する括弧をハイライト
set smartindent " 前の行のインデントを保持
set clipboard+=unnamed " ヤンクの結果をクリップボードに保存
set noerrorbells " エラーの表示時にビープ音を鳴らさない
set mouse=a " マウスの有効化

set shiftwidth=0 " タブの設定(タブ幅4の場合)
set softtabstop=4
set tabstop=4

autocmd FileType python setlocal tabstop=4 " 言語ごとにタブ幅を設定する場合

set hlsearch " 検索結果をハイライト
set incsearch " 最初の一文字を入力した時点から検索開始
set wrapscan " ファイル末尾に到達すると再び先頭から検索
```

# dein.vim(プラグイン)のインストール ※さらに改造したい人向け

### ホームディレクトリにdein用のディレクトリを作成し，作業ディレクトリを移動

```terminal
mkdir -p ~/.cache/dein && cd $_
```

### curlでインストール用のShellScriptをダウンロード

```terminal
curl https://raw.githubusercontent.com/Shougo/dein.vim/master/bin/installer.sh > installer.sh
```

### インストール実行

```terminal
sh ./installer.sh ~/.cache/dein
```

### 出力されたコードを`~/.vimrc`に追記

```vim:~/.vimrc
"dein Scripts-----------------------------

if &compatible
  set nocompatible               " Be iMproved
endif

" ~ 中略 ~

if dein#check_install() " ここの3行がコメントアウトされている場合は外す
  call dein#install()   " ※外さないとdeinに追加したプラグインがインストールされません
endif

"End dein Scripts-------------------------
```

※dein.vim(GitHub) - https://github.com/Shougo/dein.vim

# プラグインの追加方法

上記のdeinの導入時に.vimrcに貼り付けたスクリプトに追記してプラグインを追加

```vim:~/.vimrc
" ~ 略 ~

" Add or remove your plugins here:
"call dein#add('Shougo/neosnippet.vim')
"call dein#add('Shougo/neosnippet-snippets')

" ~ ここに追記 ~

" Required:
call dein#end()

" ~ 略 ~
```

# テーマの追加(プラグイン導入例)

今回は，例としてdeinにayuとlightlineというテーマプラグインを導入する．

```vim:~/.vimrc
" ~ 略 ~

" Add or remove your plugins here:
"call dein#add('Shougo/neosnippet.vim')
"call dein#add('Shougo/neosnippet-snippets')

" ~ 追加行 ここから ~
 call dein#add('ayu-theme/ayu-vim')
 call dein#add('itchyny/lightline.vim')
" ~ 追加行 ここまで ~

" Required:
call dein#end()

" ~ 中略 ~

"End dein Scripts-------------------------

" ~ 追加行 ここから (ayu-themeの設定) ~
set termguicolors     " enable true colors support
"let ayucolor="light"  " for light version of theme
"let ayucolor="mirage" " for mirage version of theme
let ayucolor="dark"   " for dark version of theme
colorscheme ayu
" ~ 追加行 ここまで ~

" ~ 略 ~
```

上記の通り.vimrcに追記してvimを起動すると，自動的に必要なものがダウンロードされ，テーマが適用された状態でvimが開く．

※ayu-theme/ayu-vim(GitHub) - https://github.com/ayu-theme/ayu-vim
※itchyny/lightline.vim(GitHub) - https://github.com/itchyny/lightline.vim
クリスマスに向けてリア充を逃がさず爆破する弓を作る


もうすぐクリスマスな時期になりましたね！リア充がわきますね！目障りなリア充は爆破してしまいましょう。逃げられても大丈夫なように矢を追尾させ、確実に〇れるようにしてしまいましょう。

##動作環境
php 8.0以降
PMMP4.0.0

##仕様
弓を放った際に一番近いエンティティを取得し、それに向けて弓の進行方向を変えます。
また、着弾時に爆発するようにします。
実装方法は矢のクラスをオーバーライドする方法で行きます。


##ソースコード


```php
<?php
namespace riajyu;
use pocketmine\entity\projectile\Arrow;
use pocketmine\entity\{
	Entity,
	Living,
    Location
};
use pocketmine\world\World;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\world\Explosion;
use pocketmine\event\entity\ProjectileHitEvent;
use pocketmine\world\sound\ArrowHitSound;

final class HomingMissileArrow extends Arrow{
    protected $gravity = 0;
	protected $damage = 3.0;
	protected $punchKnockback = 2.0;
	private $shooter;
	private $level;

    
	public function __construct(Location $location, ?CompoundTag $nbt = null, ?Entity $entity = null, bool $critical = false , ?World $level = null){
		parent::__construct(
			$location,
			$entity,
			$critical,
			$nbt
		);
		if($entity === null) return;
		//$this->setMotion($entity->getDirectionVector()->normalize()->multiply(0.2));
		$this->shooter = $entity;
		$this->level = $level;
	}

	public function entityBaseTick(int $tick = 1):bool{
 	  $newTarget = $this->level->getNearestEntity($this->getLocation(), 50.0, Living::class);
          if($newTarget instanceof Living){
            if($this->shooter === null){
	      $currentTarget = null;
	    }else{
              if($this->shooter->getId() !== $newTarget->getId()){
	        $currentTarget = $newTarget;
	      }else{
	        $currentTarget = null;
	      }
	    }
	  }else{
            $currentTarget = null;
          }

	  if($currentTarget !== null){
		$vector = $currentTarget->getPosition()->add(0, $currentTarget->getEyeHeight() / 2, 0)->subtract($this->getLocation()->getX(),$this->getLocation()->getY(),$this->getLocation()->getZ())->divide(75.0);

		$distance = $vector->lengthSquared();
		if($distance < 1){
		  $diff = $vector->normalize()->multiply(5 * (1 - sqrt($distance)) ** 2);
		  $this->motion->x += $diff->x;
		  $this->motion->y += $diff->y;
		  $this->motion->z += $diff->z;
		}
	  }
		if($this->closed){
			return false;
		}
	
		$hasUpdate = parent::entityBaseTick($tick);
	
		if($this->blockHit !== null){
			$this->collideTicks += $tick;
			if($this->collideTicks > 1200){
				$this->flagForDespawn();
				$hasUpdate = true;
			}
		}else{
			$this->collideTicks = 0;
		}
	
		return $hasUpdate;
	}
	
	protected function onHit(ProjectileHitEvent $event) : void{
		$this->setCritical(false);
		$this->broadcastSound(new ArrowHitSound());
		$explosion = new Explosion($event->getEntity()->location->asLocation(), 3);
		$explosion->explodeB();
	}
}
```

以上です。
Basic認証とフォーム認証(Cookieを使ったセッション管理)の仕組み


インターネットを通じたWEBサービス(例えば、Google,  Amazon, Instagram等)を利用する際、「認証」をする機会がたくさんあります。
この記事では基礎的な認証の仕組みのBasic認証とフォーム認証(Cookieを使ったセッション管理の仕組み)についてまとめました。

# そもそも認証って？
認証とは、**サービスの利用者が確かに本人であることを確認すること**です。

## Basic認証
HTTPで定義される認証方式の一つで、もっとも単純な実装方式です。
冒頭で挙げたような一般的なWEBサービスの認証として利用されることはほとんどありませんが、開発現場において本番リリース前のサイト/サービス等へのアクセスを特定の人だけに限定するための認証としてよく使われます。

### Basic認証の仕組み
1. クライアントがBasic認証を必要とするページへのアクセスのリクエストをサーバへ送付する
1. `401 Unauthorized`が返され、クライアントのブラウザ上にはID/PASSWORDの入力画面が表示される
1. 入力されたID/PASSWORDを`[ID]:[PASSWORD]`の形でBase64エンコードした`SUTjgaDjgog6UGFzc3dvcmTjgaDjgog=`がAuthorizationヘッダとしてHTTPリクエストメッセージ内に追加されクライアントからサーバへ再送信される
1. ID/PASSWORDが合っていた場合は、クライアントのブラウザにリクエストしたページが表示される 
![Basic認証.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/912982/166c3b65-04a1-8bc8-eaef-a3e42224adf7.png)






### Basic認証はリクエストのたびに「はじめまして」状態
HTTPの特徴として「ステートレス」という性質があります。
一度認証したとしてもその認証状態を維持することができません。このため、ブラウザがリクエストメッセージにAuthorizationヘッダを自動的に付与し、リクエストのたびに認証を行ってページを表示しています。[^2]
[^2]: Basic認証はブラウザを閉じると、再びアクセスする際に認証情報の入力を求められる。
![HTTPのステートレスは毎回はじめまして.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/912982/b372df64-809f-8bc6-2de4-5544cae0baee.png)







## フォーム認証(Cookieを使ったセッション管理)
Basic認証は、ステートレス(クライアントの状態を保持できない)ですが、WEBアプリケーションの目的によっては、ステートフル(状態を維持)にしておきたい場合(例：ECサイトのカートなど)があります。そんなときに便利なのがフォーム認証(Cookieを使ったセッション管理)です。
ここでのフォーム認証とは、HTMLフォームでID/PASSWORDを入力し、アプリケーション側で認証する方式を指します。


### Cookieとは？
HTTPで状態を記憶するために使われる仕組みがCookieです。
サーバからクライアントのブラウザに対して送付されるデータ(Cookie)を使って、セッション管理の機能を実現しています。

```
Set-Cookie: <cookie-name>=<cookie-value>
```


### Cookieを使用したセッション管理の仕組み
1. クライアントは、ログインページへアクセスするためにリクエストを送る
1. サーバは、クライアントに対してログインを要求する
1. クライアントはID/PASSWORDを入力してリクエストを送る
1. サーバは認証を行い、サーバ内にセッション情報(状態)を記録した上で、Cookie(セッションID)を発行[^3]しクライアントブラウザに記録するよう指示する。

[^3]: Cookie自体にデータを保持させるのではなく、サーバに格納しているセッション情報にアクセスするためのキーとしてセッションIDをCookieとして付与している。Cookieは発行時に属性値を設定が可能で、例えばCookie値の有効期限などを設定することができる。
![フォーム認証(セッション管理)の仕組み.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/912982/c64c3502-929d-154a-3c7c-c01b809438c1.png)


### 認証後は、セッション管理で状態維持
HTTPには状態を保持できないというステートレスという性質がありました。
しかし、CookieにセッションIDを持たせ、それをキーとしてサーバに記録したセッション情報(状態)を参照させることで、状態を保持することが可能となり、初回以降のアクセスでは認証は不要となります。[^4]
[^4]: セッションの有効期限が設定さている場合は、期限が切れた時点で再ログインが必要。また設定されていない場合も、ブラウザを終了後は同様。
![セッションで状態維持ステートフル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/912982/f2781ae7-ce74-d9d2-e028-1d1091296aef.png)


# まとめ
Basic認証・セッション管理どちらであっても、クライアント側で「ID/PASSWORD入力→ログイン」という操作を行う人間からするとほぼ同じことをしているように見えますが、その認証の仕組みは全く異なっています。

|  | Basic認証 |セッション管理  |
|---|---|---|
|状態の維持  |できない |できる(サーバで保存)  |
|ログイン  |毎回実施  |初回のみ実施 |
|ブラウザで記録  |ID/PASSWORD  |セッションID |


# 参考文献
- [体系的に学ぶ 安全なWebアプリケーションの作り方 第2版](https://www.sbcr.jp/product/4797393163/)
- [MDN Web Doc](https://developer.mozilla.org/ja/)
    - [HTTP 認証](https://developer.mozilla.org/ja/docs/Web/HTTP/Authentication#basic_authentication_scheme)
    - [HTTP Cookie の使用](https://developer.mozilla.org/ja/docs/Web/HTTP/Cookies)
Goでgorilla/mux使用時、URIの「/」→「//」にするとどうなるか

## Goでサーバを立ち上げる
のは簡単です。
ルートに、URIと関数をセットで登録し、起動すればOKです。
パッケージは、`gorilla/mux`を使っています。
URIをいじった際のメソッド（`GET`、`POST`）を追いたいので、標準エラー出力とレスポンスにメソッドの中身を出力しています。
なぜ標準エラー出力かのツッコミは、一旦置いといてください。

```go
import (
	"net/http"
	"github.com/gorilla/mux"
)

func main() {
	r := mux.NewRouter()
	r.HandleFunc("/api/out", out)
	http.ListenAndServe(":8080", r)
}

func out(w http.ResponseWriter, r *http.Request) {
	method := r.Method
	println(method)
	w.Write([]byte(method))
}
```

## 正しいURIでアクセス
してみます。上記ソースを起動し、API Clientからアクセスしてみましょう。
**アクセス**
`http://localhost:8080/api/out`
**出力**
`POST`
意図したとおりに動作しています。

それでは次は
## 「/」=>「//」にしてアクセス
してみます。「/api<font color="Red">/</font>out」=>「/api<font color="Red">//</font>out」になっていることにご留意ください。同じく
**アクセス**
`http://localhost:8080/api//out`
**出力**
`GET`
勝手に`GET`に変わっていることが分かります。

そもそも
## 違うURIでアクセスできてしまうのが問題
なのではないでしょうか。

実は、muxのRouterは、「/」が複数続いた際にそのまま使うか、Cleanしてから使うかを決めるフィールド`skipClean`を持っています。
デフォルト値は`false`で、きれいにCleanしてから使っているので、「//」でもリクエストが通ってしまいます。
まあ、メソッドが`POST`=>`GET`に変わってしまうので、リクエストボディが受け取れず正しい処理はできないでしょう。

```go
	// If true, when the path pattern is "/path//to", accessing "/path//to"
	// will not redirect
	skipClean bool
```

## URIを厳密にチェックするには
上記`skipClean`を`true`にすれば良いでしょう。
`mux`から`Router`を生成する際に、このフィールドに`true`をセットします。

```go
r := mux.NewRouter().SkipClean(true)
```
このようにすることで、「/」=>「//」でアクセスできなくなります。
**アクセス**
`http://localhost:8080/api//out`
**出力**
`404 page not found`

ソースの完成形はこちら

```go
import (
	"net/http"
	"github.com/gorilla/mux"
)

func main() {
	r := mux.NewRouter().SkipClean(true)
	r.HandleFunc("/api/out", out)
	http.ListenAndServe(":8080", r)
}

func out(w http.ResponseWriter, r *http.Request) {
	method := r.Method
	println(method)
	w.Write([]byte(method))
}
```