OmniAICreator/Qiita-1.07M huggingface dataset:
RemoteUserMiddlewareとDjango認証を併用する方法

#背景
前提記事：[Django + Shibboleth with RemoteUserMiddleware](https://qiita.com/hiro-jp/items/9d5a20baebc1c7d8f911)

Shibboleth認証が通って、`http://localhost/admin`にアクセスできたと思ったら、Djangoのログインができない（そんなユーザー存在しないようなことを言われる）。

#原因
公式ドキュメント曰く、
>Be aware that this particular setup disables authentication with the default ModelBackend. This means that if the REMOTE_USER value is not set then the user is unable to log in, even using Django’s admin interface. 
>>この設定は通常のModelsBackendによる認証を無効化してしまうので気を付けてください。例えば、REMOTE_USERがセットされていない場合、Django adminを含めてユーザーは全くログインできなくなってしまいます。

>Adding 'django.contrib.auth.backends.ModelBackend' to the AUTHENTICATION_BACKENDS list will use ModelBackend as a fallback if REMOTE_USER is absent, which will solve these issues.
>>解決法としては、AUTHENTICATION_BACKENDS に'django.contrib.auth.backends.ModelBackend'を追加することによって、REMOTE_USERがセットされなかった場合のフォールバックとしてModelBackendを使用することができるようになります。

##解決策
ModelBackendを追加。

```python:settings.py
AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.RemoteUserBackend',
    'django.contrib.auth.backends.ModelBackend', # ←追加
)
```

#参考：admin画面をShibbolethから除外したい
例えばドメインが`http://localhost/`だとすると、admin画面にアクセスするための`http://localhost/admin/`でもShibboleth認証が動いてしまう。admin画面にアクセスする権限をShibboleth認証とは切り離したい場合は邪魔になる（現状では、Shibboleth認証でログインしてから、続けてDjangoの認証画面が出てくる）。

##方策
アプリの特定のロケーションのみShibboleth管理下から外す。

```httpd.conf
<Location /admin>
     AuthType None
     Require all granted
</Location>

<Location /static>
     AuthType None
     Require all granted
</Location>
```

**注意**：`<Location /admin/>`（最後に'/'がついている）としてしまうと、`http://localhost/admin`（最後に'/'がない）は**Shibboleth認証の管理下に置かれてしまう**。

**注意**：admin画面で用いるcssファイルにShibboleth認証がかかってしまうのを防ぐため、`/static`も管理下から外す必要がある。ただしこの設定では`/static`は完全に公開されてしまうので、Djangoのログイン画面に関係のないコンテンツの画像などにもアクセスできるようになってしまい正直おすすめできない。本来は公開用のstaticを分けて設けるなどしたほうがよい。

以上。
【備忘録】javascriptでフォームの選択値を取得する

### javascriptでフォームの選択値を取得する方法/設定する方法

##### プルダウン

```console:html
<select id="pulldown">
  <option value="1">トマト</option>
  <option value="2">カボチャ</option>  
  <option value="3" selected>キュウリ</option>  
</select>
```

```console:js（取得）
// JavaScript
var val = document.getElementById("pulldown").value;
// jQuery
var val = $("#pulldown").val();
```

```console:js（設定）
// JavaScript
document.getElementById("pulldown").value = "2"
// jQuery
$("#pulldown").val("2")
```
【swift5】xcode urlリンクする方法

<blockquote class="twitter-tweet"><p lang="und" dir="ltr"><a href="https://twitter.com/hashtag/xcode?src=hash&amp;ref_src=twsrc%5Etfw">#xcode</a> <a href="https://twitter.com/hashtag/swift?src=hash&amp;ref_src=twsrc%5Etfw">#swift</a> <a href="https://t.co/tfBkwhZOKa">pic.twitter.com/tfBkwhZOKa</a></p>&mdash; aa2302 (@aa23021) <a href="https://twitter.com/aa23021/status/1257684475435073538?ref_src=twsrc%5Etfw">May 5, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script><img width="828" alt="スクリーンショット 2020-05-05 23.48.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/627010/fbd427c6-7f77-c8e3-607d-75bd6dec1429.png">

【学んだ点】
・ボタンを使ってURLリンクする方法
SwiftUI 4泊5日の旅（4日目：実装例② PageView）

# はじめに

[前回](https://qiita.com/knagauchi/items/90fbf8a32926881e1b12)同様思いついたレイアウトを作っていきますが、今日は全然捗らなかったので途中経過です。

# PageView的なもの
[ConcentricOnboarding](https://github.com/exyte/ConcentricOnboarding)を使って旅日記を作っています。
<img width="424" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277107/5dccfefd-aa7c-b1a5-c137-7a4d189a18f8.png">

```Swift:ContentView.swift
import SwiftUI
import ConcentricOnboarding

struct ContentView: View {
    var body: some View {
        let pages = (0...3).map { i in
            AnyView(PageView(imageName: "pic\(i)", text: Data.texts[i]))
        }
        let colors = (0...3).map { i in
            Color("color\(i)")
        }
        return ConcentricOnboardingView(pages: pages, bgColors: colors)
    }
}

struct PageView: View {
    var imageName: String
    var text: String
    var body: some View {
        let imageSize = UIImage(named: imageName)!.size
        let aspect = imageSize.width / imageSize.height
        return
            VStack(alignment: .center, spacing: 30) {
                Image(imageName)
                    .resizable()
                    .aspectRatio(aspect, contentMode: .fill)
                    .frame(width: 300, height: 450)
                    .cornerRadius(20)
                    .shadow(radius: 10.0)
                Text(text)
                    .font(Font.system(size: 24, weight: .bold, design: .rounded))
                    .foregroundColor(.black)
                    .shadow(radius: 3.0)
            }.padding(10)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        PageView(imageName: "pic1", text: "バチカン")
    }
}

struct Data {
    static let texts: [String] = [
        "イタリア(ローマ)",
        "バチカン",
        "クルーズ船",
        "モンテネグロ"
    ]
}
```
こんだけのコードですが、動かすと↓おしゃれにページ送りできます。
<img width="188" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277107/fa325898-06e2-fddc-67c4-3256f2582c9a.gif">
アプリ使い始めのチュートリアルにも使えますね。
各ページをViewで用意すればよいのが楽なポイント。

最終的には1ページ1枚ではなく、[WaterfallGrid](https://github.com/paololeonardi/WaterfallGrid)とかも併用して何枚かずつ出したいです。

# 最後に
さて、今日のSwiftUI旅のグルメは沖縄料理です😋
<img width="480" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277107/0b9239c1-e674-3ddb-801c-9410da5f7791.jpeg">
<img width="480" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277107/027748a4-9b8c-7ad3-e358-4d6ea3f2bc61.jpeg">
<img width="480" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277107/06bc6ab2-25e5-e195-f5ca-a17a0066e7f5.jpeg">
<img width="480" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277107/a3f10363-b7a3-326f-42b0-da7f8a4bf497.jpeg">
※写真は2018年夏旅行のものです

束の間の旅行でしたが、[次回](https://qiita.com/knagauchi/items/ff3d3d3ca3278631adeb)が最終日です。
Mac に VMware をインストールして、Ubuntu を立ち上げるまで

2010年のVMwareの書籍を中古で購入して、今でもできるのか？と思ったけれど、あまりに古すぎて同じ手順ではいきませんでした。
せっかくなので、自分のMacにVMwareをダウンロード〜インストールして、Ubuntuを立ち上げるまで調べてやってみました。

## VMware Fusion のダウンロード

1. [VMware](https://www.vmware.com/jp.html) のページにアクセス
1. 「製品」 > 「すべてを表示」を選択
1. 「パーソナルデスクトップ」から「Mac用のFusion」の「評価版の無償ダウンロード」を選択
1. [VMware Fusion または Fusion Pro の試用](https://www.vmware.com/jp/products/fusion/fusion-evaluation.html) のページが開いたら、「Fusion XX.X Pro の試用」の **今すぐダウンロード** をクリック（ダウンロードに10分強かかりました・・・）
![20200505_IMG_0001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244560/3b6390bf-2d3c-a01c-858c-8e022558f802.png)


## Ubuntu のダウンロード
1. [Ubuntu](https://www.ubuntulinux.jp/) のページにアクセス
1. 「Ubuntuのダウンロード」をクリック
1. 「jp.ubuntu.comのダウンロードページへ」をクリック
1. 「Ubuntu Desktop」の「ダウンロード」をクリック（ダウンロードに30分以上かかりました・・・）
![20200505_IMG_0002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244560/ea301feb-c826-875f-bb30-59c36e6c3b1e.png)


## VMware Fusion のインストール

1. ダウンロードした **Fusion の dmgファイル** を開く
1. 「VWMare Fusion.app」をダブルクリックしてインストールする
1. 確認ウィンドウで「開く」をクリックする
1. 条項を確認して、問題なければ「同意する」をクリックする
1. 「VMware Fusion XX.X を 30 日間試用したいです。」を選択し、「続ける」をクリックする
1. Professional を選択し、「続ける」をクリックする
1. 最後の画面で「完了」をクリックする

## Ubuntu のインストール

1. VMware Fusion の「インストール方法を選択」で、「ディスクまたはイメージからインストール」が選択された状態で、「続ける」をクリック
1. **Ubuntu の ISOファイル** をドラッグ&ドロップして、「続ける」をクリック
1. 「簡易インストールを使用」にチェックを入れた状態で、必要事項を入力し、「続ける」をクリック
1. 確認画面の内容で問題がなければ、「終了」をクリック
1. Ubuntuが立ち上がるのを待ちます。
![20200505_IMG_0003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244560/4ddb754d-f8db-9fad-c774-ffac677b8084.png)

## 終わりに

そんなに詰まるポイントもなく、Ubuntuのインストールまで行けました。
VMwareの試用期間は30日間なので、お勉強してみようと思います。

会社ではあまり意識せずに利用していたけれど、最近無知であることを悔やんだので、とりあえず触ってみて感触だけでも掴みたい・・・と思っています。
Swiftコードから自動的にUML図を生成する方法

SwiftのコードからUML（クラス図）を生成するスクリプト([palaniraja/swiftuml](https://github.com/palaniraja/swiftuml))を公開している方がいたので紹介します．

肥大化したプロジェクトを理解するためにクラス図などのダイアグラムを用いると便利です．JavaならInteliJ Ideaの機能を用いて生成するなど方法がありますが，XcodeやApp CodeにはSwift用のそのような機能は残念ながら存在しません．swiftumlのスクリプトを使ってPlantUML（テキストベースのUML記述言語）を出力すれば，PlantUMLのソフトを使ってダイアグラムを表示できます．

<img width="1558" alt="Screenshot 2020-05-05 at 22.30.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327967/32b1d472-122e-c067-fff0-ba6b6442389d.png">


#　環境を準備する
- swiftですのでmacOSを対象とします．

### swiftuml実行環境
- swiftumlのスクリプトを実行するために以下をbrewでインストールでします．

```:zsh
brew install sourcekitten
brew install jq
```

- 必要に応じてNode.jsをインストールしてください．

### PlantUML実行環境

- PlantUMLを[公式ページ](https://plantuml.com/ja/)からダウンロードします．
- 必要に応じてJDKをインストールしてください．

また，ダイアグラムの描画に以下のコマンドが必要です．

```:zsh
brew install graphviz
```

**このソフトを使わなくてもweb上で描画するシステムもあります．**

# swiftumlスクリプトを実行する

[GitHub(palaniraja/swiftuml)](https://github.com/palaniraja/swiftuml)から必要なプログラムを入手します．沢山のファイルがありますが，必要なのは次の二つです．

- plantuml.js
- plantuml.sh

この二つを適当な場所に配置します．


スクリプトは次のコマンドで実行します．このコマンドは，directory_name以下の階層に存在する全ての.swiftファイルを対象にしてPlantUMLを生成し，uml.txtに書き出します．

```:zsh
find directory_name | grep .swift |  xargs -L 1 sh plantuml.sh | grep -v @enduml | grep -v @startuml >> uml.txt
```

筆者の環境では，Resourcesに入っているswiftgenによって生成されたファイルが上手く扱えなかったため，無視するようにしました．

```:zsh
find directory_name | grep .swift | grep -v Resources |  xargs -L 1 sh plantuml.sh | grep -v @enduml | grep -v @startuml >> uml.txt
```

### コマンドの補足説明

PlantUMLで記述されたファイルは<span>@</span>startumlで始まり，<span>@</span>endumlで終わります．上のコマンドでは読み込んだswiftファイル毎にこれらのキーワードが付加されてしまうため，一旦全て削除しています．（| grep -v <span>@</span>enduml | grep -v <span>@</span>startuml の部分）

# ダイアグラムを描画する

まず，**uml.txtのファイルを開き，ファイルの先頭行に<span>@</span>startuml，最後の行の後に<span>@</span>endumlを追加**します．（先ほどのコマンドで全て消してしまったため追加する必要があります．本来は追加するためにsedコマンドを書きたかったのですが，macだとややこしいのでやめました）

**[公式ページ](https://plantuml.com/ja/)からダウンロードしたjavaアプリを起動しuml.txtを選択**します．

ダイアグラムが表示されます．

<img width="1558" alt="Screenshot 2020-05-05 at 22.30.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327967/32b1d472-122e-c067-fff0-ba6b6442389d.png">

# 問題点等

使ってみたところ以下のような問題点がありました．解決策をご存じの方おられましたら教えていただけると幸いです．

- 大規模すぎるとPlantUMLのソフトで一部しか表示できない（途中から切れてしまいます）
- 表示されるのは継承関係のみでそのほかの関係性は表示されません．（どのクラスを利用しているなど）
- 最新のSwiftの記法に対応していない部分があります（下図，PlantUMLの問題で<span>&</span>を使った継承など）

<img width="1050" alt="Screenshot 2020-05-05 at 23.44.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327967/8d249f2d-cb6a-503e-ead6-3897bfad83a4.png">
Laravelでcssやjsが効かない時の解決方法

#はじめに
laravelで初めて開発していた時にcssとjsを使おうとしたが効かなかったので解決方法を載せておきます

#原因
publicフォルダにcssとjsフォルダがなかったため、blade.phpで使えなかった
resourcesフォルダーにcssとjsのフォルダはあるが移動させないと使えないので
Laravel初心者の方は注意が必要です！

#解決方法
resourcesフォルダからpublicにフォルダを移動させるかpublicフォルダで新しく作ってください
そして、以下のように[<font color="LimeGreen">asset関数</fontcolor>](https://laraweb.net/knowledge/835/)を使ってください
これを使うとpublic限定で使うことができるので
どこのフォルダでcssやjsを使っているかわかりやすくなります

````
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="{{ asset('/css/sample.css') }}">
  <scriptsrc="{{ asset('/js/sample.js') }}"></script>
  <img alt="文字表示" src="{{ asset('/img/sample.png') }}">
  <title>Document</title>
</head>

#ディレクトリ構成
public---css--sample.css
          |
        　js--sample.js
　　　　　 |
          img--sample.png
````

##最後に
cssやjsが効かない時は、必ずどこのフォルダに置いてあるか確認しましょう
あと、Laravalのフォルダ構成が気になる人は
こちらの[<font color="LimeGreen">Laravel 6 ディレクトリ・ファイル構造</fontcolor>](https://qiita.com/ucan-lab/items/4ad7daf12422498ab491)を見てください
AmplitudeダッシュボードAPIを叩く時の5つの注意点

ReactNative、Expo環境でのログ解析デファクトスタンダードのAmplitude(ExpoSDK37からはfirebase analyticsも使えるようになりました)。
無料枠でもダッシュボードが充実しまくっているのでかなり満足なのですが、生のデータを扱いたくなりました。
てことでGUIに頼らずにデータを得られるAmplitudeAPIでハマったところをまとめます。
公式ドキュメントは[こちら](https://help.amplitude.com/hc/en-us/articles/205469748-Dashboard-Rest-API-Export-Amplitude-Dashboard-Data)。

# 5つの注意点
## おとなしくCurlを使う
公式ドキュメントを見てみると、サンプルコードが全部Curl。
なんでやねん。
ちょっとのぞいてみると

```
curl -u API_Key:Secret_Key 'https://amplitude.com/api/2/events/segmentation?e=\{"event_type":"Share%20Song","filters":\[\{"subprop_type":"event","subprop_key":"SocialChannel","subprop_op":"is","subprop_value":\["facebook"\]\}\]\}&m=totals&start=20141001&end=20141004&i=7&g=country'
```

とな。
{}と[]がバックスラッシュでエスケープされていたり、半角スペースはエンコードされていたり、パラメタがネストしていたり、Curlで書くにはとてもめんどくさそう。
ってことで、Pythonのrequestsで頑張ってみましたが、結構時間がかかりそうだったので諦めて、Curlを使うことに。
と言ってもターミナルで実行できても嬉しくないので、Pythonのsubprocessモジュールを使って、curlコマンドを実行することにしました。
変数はテンプレートリテラルで埋め込めばよろし。
requestsとかでできた人いたらぜひ教えてください！

## User ID => user_id
APIのパラメタでUser IDを指定したい時のkeyは**user_id**です。
Amplitudeのダッシュボードにある、デフォルトのユーザープロパティUser IDを指すkeyですが、そのままUser IDだとダメ。
エンコードしてUser%20IDでもダメ。
user_id。
ドキュメントにも全然書いてなかった…。

## 自分で作ったプロパティにはgp:をつける
例:"Age" => "gp:Age"
User ID(APIでのkeyはuser_id)など、Amplitudeがデフォルトで用意してくれているプロパティを指定する場合はそのままでいいのですが、自分で設定したプロパティは、プロパティ名の前にgp:をつける必要があります。

## エンコードする
パラメタで指定するvalueも全部エンコードして使わないとダメです。
Amplitudeのドキュメントにもあるエンコード用のサイトはさっきSSL証明書が切れてしまったので、[こちらのサイト](https://tech-unlimited.com/urlencode.html)とかでエンコードすればよろし。
あと、無駄なスペースは全部消すこと。

## {}と[]をバックスラッシュでエスケープ
{}と[]はバックスラッシュでエスケープします。
パラメタからcurlコマンドを自動生成するときは "{" => "\\{" とかで置換すればよろし(置換時にエスケープを無効化したりちょっと面倒かも)。



# 上記を踏まえたコマンドの例
例えば、自分で設定したNameプロパティ(Name => gp:Name)が田中(田中 => %E7%94%B0%E4%B8%AD)であるユーザーの、音楽を再生するイベント(Play Music => Play%20Music)の再生時間("duration")を2020年3月9日から2020年4月9日まで全部足したい時は以下。

```
curl -u API_KEY:SECRET_KEY 'https://amplitude.com/api/2/events/segmentation?e=\{"event_type":"Play%20Music","filters":\[\{"subprop_type":"user","subprop_key":"gp:Name","subprop_op":"is","subprop_value":\["%E7%94%B0%E4%B8%AD"\]\}\],"group_by":\[\{"type":"event","value":"duration"\}\]\}&start=20200309&end=20200409'
```

#まとめ
てな感じで、いくつかハマりどころがありましたが、上記を守れば、APIを自由に叩けると思います。
間違ったフォーマットで書いても、ほぼ全くエラー箇所教えてくれないのでちょいきつかったです。
誰かのお役に立てれば！
[Django]migrateをやり直す

#[Django]migrateをやり直す

Django初学者のメモになります。
DB構築をする際にModelを書き直し、migrateをやり直りたい時があったのですが、いろいろとエラーしたりと苦労したので解決策を備忘録します。

[環境]
Django 2.01
python 3.7.2

##想定

- app名「recipe」を作成
- userモデルをカスタマイズしたuserモデルへ変更※
- migrateをやり直したい

※1.いろいろとtipsを覗いたが、カスタマイズUserにする際には、一度migrateをやり直した方が早いと思った。
   なので、アプリケーションを作成する際には、最初にカスタマイズUserを作成するべき。

※2.ちなみにカスタマイズuserモデルの作成方法は以下の記事参照
[ジャンゴ(django)のカスタムユーザーモデル(Custom User Model)](https://dev-yakuza.github.io/django/custom-user-model/)


##やり直し手順

「migrateをやり直したい」ここの手順を下記に記載する。

###1.過去のmigrate履歴を確認

```
# 過去のmigrate履歴が見れる
>python manage.py showmigrations
```

```
admin
 [X] 0001_initial
 [X] 0002_logentry_remove_auto_add
 [X] 0003_logentry_add_action_flag_choices
auth
 [X] 0001_initial
 [X] 0002_alter_permission_name_max_length
 [X] 0003_alter_user_email_max_length
 [X] 0004_alter_user_username_opts
 [X] 0005_alter_user_last_login_null
 [X] 0006_require_contenttypes_0002
 [X] 0007_alter_validators_add_error_messages
 [X] 0008_alter_user_username_max_length
 [X] 0009_alter_user_last_name_max_length
 [X] 0010_alter_group_name_max_length
 [X] 0011_update_proxy_permissions
contenttypes
 [X] 0001_initial
 [X] 0002_remove_content_type_name
recipe
 [X] 0001_initial
sessions
 [X] 0001_initial
```

結果は上記の通りで[]にxがついているのがmigrteが適応されている履歴になる。
recipeにも[x]がついているので適応済と判断できる。

###2.テーブルを全て削除

接続先のDBの中の、過去にmigrateして生成したテーブルを全て削除(drop)する。


###3.appのmigrationsフォルダの中身を削除

[app名].migrationsのフォルダ中身を全て削除
（今回の場合は、recipe.migrations）

###4. migrate履歴の削除

以下の--fakeオプションのついたコマンドで履歴を削除する。
（カスタマイズUserを適応するやり直しの際には、全て削除しなければ解決しなかったので、adminからsectionsまですべて削除した。）

```
>python3 manage.py migrate --fake [削除対象] zero

#例:これでrecipeの履歴が削除される
#>python3 manage.py migrate --fake recipe zero
```

履歴が削除されたかを1と同様のコマンドで確認

```
admin
 [ ] 0001_initial
 [ ] 0002_logentry_remove_auto_add
 [ ] 0003_logentry_add_action_flag_choices
auth
 [ ] 0001_initial
 [ ] 0002_alter_permission_name_max_length
 [ ] 0003_alter_user_email_max_length
 [ ] 0004_alter_user_username_opts
 [ ] 0005_alter_user_last_login_null
 [ ] 0006_require_contenttypes_0002
 [ ] 0007_alter_validators_add_error_messages
 [ ] 0008_alter_user_username_max_length
 [ ] 0009_alter_user_last_name_max_length
 [ ] 0010_alter_group_name_max_length
 [ ] 0011_update_proxy_permissions
contenttypes
 [ ] 0001_initial
 [ ] 0002_remove_content_type_name
recipe
 [ ] 0001_initial
sessions
 [ ] 0001_initial
```

すべての履歴が削除されていることを確認。

###5.appのmigrationファイルを生成

いつもの通りmigrationファイル生成

```
>python manage.py makemigrations [app名]
```

###6.migrateを実行

いつもの通りmigrateを実行

```
>python manage.py migrate
```

これでDBを確認し、テーブルが生成されていることを確認する。

以上になります。
間違いなどありましたら、ご指摘をお願いいたします。

##参考

[Django マイグレーション　まとめ](https://qiita.com/okoppe8/items/c9f8372d5ac9a9679396)
[manage.py migrateをおかしな感じにやってしまった。](https://qiita.com/ajitama/items/130b2f31abd855937a93)
DockerfileでのCOPYとbind mountの関係性

最近ローカル開発環境はDocker composeで本番環境はGKEという環境でちょっと気になったことがありました。

本番環境のGKEにはGitHub Actionsを使ってイメージのビルド→ECRへのイメージアップロード→GKEへのデプロイを行っています。

ただこのGitHub Actionsの中でローカル開発環境のDocker composeで使っているDockerfileをsedやechoなどで一部変更しています。

もしくは環境によってDockerfileの名前を変えて使い分けてたりします。

これよくよく考えてみるとコンテナのポータビリティを損なっていませんかね？

個人的にはなるべく環境によってDockerfileを変えたくないなと思っています。

具体的にはどうことかいうと
※以下のファイルは説明のため簡略化しています

### ローカル開発環境のDockerfile
```docker
FROM nginx
EXPOSE 80
```

### ローカル開発環境のdocker-compose.yml
```yaml
version: "3"
services:
  nginx:
    build:
      context: .
    ports:
      - "80:80"
    restart: always
    volumes:
      - ./src:/var/www
```

### 本番環境のDockerfile
```dockerfile
FROM nginx
EXPOSE 80
COPY --chown=nginx:nginx ./src /var/www
```

ローカル開発環境はdocker-compose.ymlでbind mountしてるのでイメージに/src配下を含まないようにしている。

対して本番環境はイメージの/src配下を含まないといけないのでGitHub Actionsの中で`COPY --chown=nginx:nginx ./src /var/www`を追記している状況です。

これってよくよく考えてみるとどっちも本番環境のDockerfileを使えばいいんじゃないですかね？

というのもDockerfileでCOPYしてビルドしたとしてもbind mountしたら/var/wwwの配下がビルドされた時点よりもbind mountが優先されるならばそれでいいんではないでしょうか？

ということでbind mountが必ず優先されるのか実験です。


# 実験環境
## フォルダ構成
```
qiita
├── Dockerfile
├── docker-compose.yml
└── src
    └── copy.html
```

### Dockerfileの内容
```docker
FROM nginx
EXPOSE 80
COPY --chown=nginx:nginx ./src /var/www
```

### docker-compose.ymlの内容
```yaml
version: "3"
services:
  nginx:
    build:
      context: .
    ports:
      - "80:80"
    restart: always
    volumes:
      - ./src:/var/www
```

この状態でビルドしてコンテナを立ち上げます。

```bash
$ docker-compose up -d
```

/var/www配下を確認します。

```bash
$ docker-compose exec nginx ls -hl /var/www
total 4.0K
-rw-r--r-- 1 root root 17 May  5 13:09 copy.html
```

この状態でsrc/copy.htmlを削除し、ビルドし直さずにコンテナを立ち上げなおしてsrc/copy.htmlがなくなっているか確認します。

```bash
$ rm -f src/copy.html
$ docker-compose stop
Stopping qiita_nginx_1 ... done
$ docker-compose up -d
Starting qiita_nginx_1 ... done
$ docker-compose exec nginx ls -hl /var/www
total 0
```

ではこの状態で今後はsrc/copy_2.htmlを作成し、ビルドし直さずにコンテナを立ち上げなおしてsrc/copy_2.htmlのみとなってるか確認します。

```bash
$ touch src/copy_2.html
$ docker-compose stop
Stopping qiita_nginx_1 ... done
$ docker-compose up -d
Starting qiita_nginx_1 ... done
$ docker-compose exec nginx ls -hl /var/www
total 0
-rw-r--r-- 1 root root 0 May  5 13:55 copy_2.html
```

想定通りsrc/copy_2.htmlのみが存在します。

ではこの状態でsrc/copy_2.htmlの中身を変更し、ビルドし直さずにコンテナを立ち上げなおしてsrc/copy_2.htmlの中身の変更が反映されているか確認します。

```bash
$ echo "qiita test" >> src/copy_2.html
$ docker-compose stop
Stopping qiita_nginx_1 ... done
$ docker-compose up -d
Starting qiita_nginx_1 ... done
$ docker-compose exec nginx ls -hl /var/www
total 4.0K
-rw-r--r-- 1 root root 11 May  5 14:00 copy_2.html
$ docker-compose exec nginx cat /var/www/copy_2.html
qiita test
```

こちらも想定通りsrc/copy_2.htmlの変更内容がコンテナから見たときに反映されています。

この実験からビルドした状態がどうであれbind mountしたらその時のマウント元の内容が反映されることがわかりました。

つまり最初に述べたように本番環境のDockerfileを使えばいいってことです！！

これで環境ごとのDockerfileの差分が1つ減りました!!
めでたし、めでたし...とはいきません

既に気付いてる方もいるかもしれませんがbind mountではファイルの権限が`nginx:nginx`になっていません。

この権限周りについては後日ちゃんと調べたいと思います。
※ちなみにdocker-compose.ymlのvolumesのオプションに権限を設定に関するものはありません
Route53とELBを使ったhttpsアクセス

#前提
ドメインの取得完了済み
（自分は<code>お名前ドットコム</code>を使用したのでそれに沿って書いていきます）

#本題
取得したドメインとRoute53を紐付け、最終的にはhttps通信できるように実装していきます。

##Route53と独自ドメインの紐付け
###Route53にドメインを登録
ドメインを扱うにあたり、まずAWSのRoute53へドメインを登録。

AWSコンソールのトップからRoute53と検索し、Route53のコンソールへと移動。
ホストゾーンの作成。
作成が正常に完了すると、NSレコードと呼ばれる値が割り振られる。
これで、Route53の初期設定は完了。

###お名前ドットコムのネームサーバーを変更
お名前ドットコムへアクセスし、他のネームサーバーを利用をクリック。
4つのドメインを入力して確認画面へ進む。
変更完了画面になれば、お名前ドットコムでのネームサーバー設定は完了。

###ドメインとEC2インスタンスのIPアドレスを紐付ける
次はドメインとEC2のIPアドレスを紐付け、独自ドメイン経由でアプリケーションを使えるようにしていきます。
一旦EC2のコンソールへ移動しIPV4パブリックIPをコピー。
Route53のコンソールに戻る。
レコードセットの作成。
・名前には何も入力しない
・タイプはA IPv4アドレスのまま
・値にはコピーしたEC2インスタンスのパブリックIPアドレスを入力
追加したAタイプの値にEC2のパブリックIPが記載されていれば設定は完了。

この設定により、DNS（名前解決）サービスに登録され、ドメインでアクセスが来た際にアクセス先をIPアドレスに変換する仕組みを利用できるようになった。

##AWS Certificate Managerでの証明書取得
現状だとhttp通信でしかアプリケーションを利用できない状態。
近年は常時SSL化が推奨されていているみたいです。
Google Chromeではhttp通信のままだと<code>保護されていない通信</code>と出ます。

そのため、https通信のための証明書を準備していきます。

###ACMの初期設定
AWSコンソールのトップからACMのコンソール（Certificateと検索）へと移動します。
証明書のプロビジョニングの方の今すぐ始めるをクリック。
パブリック証明書を選択して証明書のリクエストをクリック。
無事ダウンロードができれば、ACMの設定は一旦終了。

###Route53で所有権の確認
ACMで証明書の発行を行うためにはドメインの所有権を確認しなければならないため、DNSを用いて確認。
Route53のコンソールへ移動。
レコードセットの作成。
ここで先ほどダウンロードしたDNS設定を確認。
ダウンロードした DNS_Configuration.csvを開く。
（タイプはCNAMEを選択・Record Valueは値全てをコピー）
入力が終わったら5分〜15分ほど待ちます。
その後、ACMのコンソールに戻り画面を更新し、証明書が<code>発行済み</code>になっていれば所有確認は完了。

##ELBの立ち上げ
ELB（Elastic Load Blancer）
ELBを使い、https通信でアプリケーションを使えるよう設定。

###ELBの概要と役割
・ELBの役割
ELBは通常、ロードバランサーと呼ばれている。
つまり負荷のバランスを取る装置のこと。

例えばWebサーバーに負荷がかかりやすいアプリケーションの場合、使用例としては複数のサーバーに負荷を振り分ける。

例えばアクセスが増大した際にEC2の負荷が増加（CPUやメモリの使用量が増える）。
こういった場合、同じ処理を行うEC2を2台に増やすことで負荷を分散できる。
ただ、ELBを置かずにEC2を増やすだけだと、負荷を分散できない。
ここでELBを通して、アクセスを捌くことによって負荷を分散することができる。

・ELBのもう1つの役割
負荷の大きいアプリケーションを構築しない場合は、EC2を2台用意する必要はありません。
そのため、ELBは証明書を使ったセキュアな通信のために利用。

具体的には外部とやりとりする通信を簡単に暗号化できる。
VPC外とやりとりする際にセキュアはhttps通信を用いて、通信内容が外部に読み取られても安全な仕組みを作る。
対して、VPC内はプライベートなAWSのネットワークなので、暗号化しないhttp通信でやりとりする。
こういった仕組みをELBを用いて構築することにより、簡単にセキュアなネットワークを構築することができる。

###EC2コンソールからELBを立ち上げる
ELBは1日あたり約65円の料金がかかるため注意。
EC2コンソールのロードバランサーをクリック。
5分程度でELBの構築が完了。

###Route53の設定変更
これまでは以下のような流れでアプリケーションが動いていました。

１、ブラウザから独自ドメインにアクセス
２、Route53を通じでEC2にアクセスが渡る
３、EC2やRDSで処理して、ブラウザに結果を返す

しかし、今回はELBの証明書を挟むため、以下のような流れに変更します。

１、ブラウザから独自ドメインにアクセス
２、Route53を通じでELBにアクセスが渡る
３、ELBからEC2にアクセスを流す
４、EC2やRDSで処理して、ブラウザに結果を返す

2の部分であるRoute53の設定を変更していきます。
Route53のコンソールに移動。
ホストゾーン → 本教材のドメインをクリック。
タイプAの行をクリック。
右側の設定詳細にあるエイリアスをはいに変更。
アクセスを向ける先を作ったばかりのロードバランサーに変更。
変更したタイプAの値が<code>ALIAS ・・・ </code>となっていれば、アクセスのルーティング先が変更完了。
httpsでアクセスできたら完了です。
☆の出力

// JavaScript 課題集
// 【課題内容】
// ＝ルール＝
// ・言語は javascript とします。
// ・出力方法は問いません。
// ・一つのファイルに問１～問6までを全部出力させて下さい。
// ・一つの問いに対して★または☆は一つだけ書いて出力させて下さい。

// for(var i=1; i<=25; i++){
//   if(i % 2 == 1) {
//     document.write("★");
//   } else {
//     document.write("☆")
//   };
//   if(i % 5 == 0) {
//     document.write("<br>")
//   };
// };
// 問1
document.write("<br>=====================================<br>");

for (let y = 0; y < 5; y++) {
  for (let x = 0; x < 5; x++) {
    if ((x + y) % 2 === 0) {
      document.write("★");
    } else {
      document.write("☆");
    }
  }
  document.write("<br>");
}

document.write("<br>=====================================<br>");

// x には左から何番目の星を処理しているかが入っている
// y には上から何番目の星を処理しているかが入っている

// 問 2
for (let y = 0; y < 5; y++) {
  for (let x = 0; x < 5; x++) {
    // x と y が同じときだけ白い星にする
    if (x === y) {
      document.write("☆");
    } else {
      document.write("★");
    }
  }
  document.write("<br>");
}

document.write("<br>");

document.write("<br>=====================================<br>");
// 問 3
for (let y = 0; y < 5; y++) {
  for (let x = 0; x < 5; x++) {
    // 1 行目なら左から 2 番目の星を表示する処理をキャンセルする
    // 2 行目なら左から 3 番目の星を表示する処理をキャンセルする
    if (x > y) break;
    // 5と４となりブレイク
    // x と y が同じときだけ白い星にする
    if (x === y) {
      document.write("☆");
    } else {
      document.write("★");
    }
  }
  document.write("<br>");
}
rails tutorial (rails6)備忘録2

【環境】
・mac OS Mojave
・バージョン10.14.6（18G2022）
・Visual Studio Code 

学習テーマ
rails tutorialの勉強の備忘録として残す。

1. [rails tutorial (rails6)備忘録](https://qiita.com/m_masashi/items/0c9c2b81ca735f61a9c3)
1. [rails tutorial (rails6)備忘録2](https://qiita.com/m_masashi/items/34f37fcf9457868b357f) 

## Hello worldを表示


```ruby
mba-2:hello_app {myname}$ bundle install
```

```ruby:/Users/{myname}/projects/rails6_tutorial/hello_app/app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  def hello
    render html: "Hello World!"
  end
end
```

```ruby:/Users/{myname}/projects/rails6_tutorial/hello_app/config/routes.rb

Rails.application.routes.draw do
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
  root 'application#hello'
end
```

`画面`
![hello.world](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313771/f5530c25-6902-1c8c-4e7e-02b0e3357476.png)



```
$ git add .
$ git commit -m "exec hello world"
$ git push origin master
```




















**前回**
[rails tutorial (rails6)備忘録](https://qiita.com/m_masashi/items/0c9c2b81ca735f61a9c3)


## 参考にした記事（いつもありがとうございます）
LINEBotをみんなで作ろう〜AWSアカウントを作るぞ編〜【6日目】

この記事は下記の [#GWアドベントカレンダー](https://gw-advent.9wick.com/calendars/2020/72) の 6日目の記事になります。

1週間でサーバレスLINEBotを生み出す( @inoue2002  ） | GWアドベントカレンダー

# はじめに
こちらの内容は超初心者向けです。
[公式ドキュメント](https://developers.line.biz/ja/docs/messaging-api/overview/#messaging-api%E3%81%AE%E4%BB%95%E7%B5%84%E3%81%BF)を読める方はこちらをお読みいただく方が正確です。

[昨日の記事](https://qiita.com/drafts/35fab5b7901aa94fafd2)をご覧になってない方はぜひ。
こちらの記事はGWアドベントカレンダーを通してLINEBotをサーバレスで作れるようになろう！ということを目標に書いている記事です。

LINEBotは作れるけどAWSでサーバーレスを作ってみたい！方向けの記事です

昨日の記事で複雑な処理ができるLINEBotが作れました。それをサーバーレスにしていきましょう！！
すでにAWSアカウントをお持ちの方はログインできるかどうか確認してみてください。

#AWSアカウントを作成
[AWSコンソール](https://aws.amazon.com/jp/)に行く
右上の「コンソールにサインイン」をクリック
<img width="1425" alt="スクリーンショット 2020-05-05 14.17.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488939/e47557dc-f3cb-6396-d3b2-0dd4d6d0d068.png">
「新しいAWSアカウントを作成」をクリック
<img width="1025" alt="スクリーンショット 2020-05-05 14.20.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488939/17afaa0e-bd1a-a950-b3d5-287941851ed1.png">
各項目を入力します。
<img width="1008" alt="スクリーンショット 2020-05-05 13.53.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488939/3edb0360-9f58-2235-b3fe-e1d4d1780432.png">
請求先の住所や支払い方法などを入力し、以下の画面が表示されると成功です！
（個人的なLINEBotを作る程度ならば請求は発生しませんが、請求先の情報は入力しないとアカウントを作成できません）
<img width="1437" alt="スクリーンショット 2020-05-05 13.58.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488939/d8ff4a9b-b0ac-d109-59a9-e04c881fd89f.png">

#Lambdaとは
明日からLambdaの設定に入っていきます。
ぜひ[ドキュメント](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/welcome.html)を参考にイメージを掴んでおくと開発しやすいと思います。

#終わりに
とても軽いqiitaが出来上がりました。それだけAWSアカウント取得は手軽だということです。

本記事：[LINEBotをみんなで作ろう〜AWSアカウントを作るぞ編](https://qiita.com/inoue2002/items/ad945981150c859911fc)
次の記事：[LINEBotをみんなで作ろう〜レイヤーとAPIgateway設定編](https://qiita.com/inoue2002/items/ab226d9836a891b01bc9)

[LINEBotをみんなで作ろう〜環境構築編〜](https://qiita.com/inoue2002/items/a87df2b520f8b6e37f42)
[LINEBotをみんなで作ろう〜LINEBot is 何？編](https://qiita.com/inoue2002/items/3a5019c07801bcf5ff75)
[LINEBotをみんなで作ろう〜おうむ返しbotを作ろう編〜](https://qiita.com/inoue2002/items/dcf40d5ebfe2454796fa)
[LINEBotをみんなで作ろう〜色々なメッセージを送ってみよう編](https://qiita.com/inoue2002/items/35fab5b7901aa94fafd2)
[LINEBotをみんなで作ろう〜Messageを分岐させるぞ編](https://qiita.com/inoue2002/items/650eca3f7dd6a5fccb63)
[LINEBotをみんなで作ろう〜コードを実装編](https://qiita.com/inoue2002/items/dbbd862d6149c83f6513)
踏み台サーバー経由公開鍵認証でSSHログインする設定

# はじめに
  今回は「クライアント-->踏み台->サーバー１」でSSHログインする場合、公開鍵認証の設定方法を説明します。
  
# 環境

||OS|IP|ユーザー|
|:--:|:--:|:--:|:--:|
|クライアント|WSL2 on Window 10 バージョン2004(OSビルド19041.208)|192.168.56.100|-|
|踏み台|CentOS 7.8(2003)|192.168.56.114|user|
|サーバー１|CentOS 7.8(2003)|192.168.56.21|user|

# 手順

##公開鍵認証

### key pair作成
よりセキュアのed25519暗号化アルゴリズム、　パスフレーズなしで秘密鍵ペアを作成し、~/.ssh/id_ed25519という名前で保存します。  

```
ssh-keygen -t ed25519 -N "" -C "okcoder@desktop-wsl" -f ~/.ssh/id_ed25519
```
~/.sshフォルダにid_ed25519、id_ed25519.pub二つファイルが作成されます。


### 公開鍵転送
公開鍵を踏み台に転送します。

```
ssh-copy-id user@192.168.56.114
```
パスワードが聞かれますが、踏み台のパスワードを入力します。


### 確認
下記コマンドで踏み台のバージョンが表示されれば、鍵転送が完了しました。

```bash
ssh user@192.168.56.114 uname -a
```

## .ssh/config登録
接続先情報を.ssh/configに登録して、サーバー名だけでログインできるようにします。

### 登録
```bash
cat <<EOF | tee -a ~/.ssh/config
Host bastion
    HostName 192.168.56.114
    User user

EOF
```

### 確認

.ssh/configに登録したサーバー名bastionでSSHログインできることを確認します。

```bash
ssh bastion uname -a
```
## 踏み台経由接続設定

### .ssh/config追加
.ssh/configに踏み台サーバー経由でサーバー１へログイン情報を登録します。

```bash
cat <<EOF | tee -a ~/.ssh/config
Host server1
    HostName 192.168.56.21
    User user
    ProxyCommand ssh -W %h:%p bastion
EOF
```

### 公開鍵転送
公開鍵をサーバー１に転送します。

```
ssh-copy-id  server1
```
パスワードが聞かれます。サーバー１のパスワードを入力します。

### 確認
サーバー１へ接続できることを確認します。

```bash
ssh server1 uname -a
```

#### .ssh/config確認 

問題がなければ、.ssh/configファイルの内容は以下の通りです。

```~/.ssh/config
Host bastion
    HostName 192.168.56.114
    User user

Host server1
    HostName 192.168.56.21
    User user
    ProxyCommand ssh -W %h:%p bastion
```

## 参考資料
- [CentOS7.3でSSH接続(公開鍵認証)する方法](https://qiita.com/uhooi/items/137de4578534c8e7e7f2)
- [~/.ssh/config による快適 SSH 環境](https://qiita.com/oohira/items/7deae31469cfbbd740c1)
- [多段SSHの設定を.ssh/configにまとめる](https://qiita.com/ik-fib/items/12e4fab4478e360a82a1)
- [2017年版 SSH公開鍵認証で使用する秘密鍵ペアの作り方](https://qiita.com/wnoguchi/items/a72a042bb8159c35d056)
JavaScriptを使って文字カウントアプリを作る

#JavaScriptを使って文字カウントアプリを作ろう！

完成見本
[![Image from Gyazo](https://i.gyazo.com/2d101360da10348d3cabf21bc66dfeba.gif)](https://gyazo.com/2d101360da10348d3cabf21bc66dfeba)
はじめに、HTMLファイルを作成します。

```index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>文字カウントアプリ</title>
  </head>
  <body>
    <script>

    </script>
</body>
</html>
```
文字を入力するテキストエリアを作ります。

```index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>文字カウントアプリ</title>
  </head>
  <body>
    <textarea id="text" cols="50" rows="7"></textarea>
    <p id="count">0文字</p>
    
    <script>

    </script>
</body>
</html>
```

[![Image from Gyazo](https://i.gyazo.com/c58825b828fe9d05e4ad2461018f7b88.png)](https://gyazo.com/c58825b828fe9d05e4ad2461018f7b88)
テキストエリアができました。

このテキストエリアに文章を入力していくと、p要素に現在の文字数がリアルタイムに出力されるようにしていきます。

ここからjavascriptの記載をしていきます。
まず、テキストエリアと文字数を表示するHTML要素のID属性をgetElementById()を利用して取得します。

```index.html

<script>
    const text = document.getElementById("text");
    const count = document.getElementById("count");
</script>
```

取得したテキストエリアの要素にイベント処理を追加していきます。
addEventListener()を利用します。addEventListener()とは、様々なイベント処理を実行できるメソッドです。

```index.html
<script>
    const text = document.getElementById("text");
    const count = document.getElementById("count");
    
    text.addEventListener("keyup", () => {

        // 文字数をカウントする処理を記述する

    });
</script>
```

イベントはkeyupです。これは、キーを押して離した瞬間に毎回イベントが実行されます。
1文字ずつ入力するたびに文字数をカウントして出力することができます。

文字数を取得するには、valueプロパティから文字列をまずは取得します。そのあとにlengthプロパティを使えば文字数を得られます。

```index.html
    <script>
      const text = document.getElementById("text");
      const count = document.getElementById("count");

      text.addEventListener("keyup", () => {
        const inputText = text.value;
        count.textContent = inputText.length + "文字";
});
    </script>
```
これで、文字カウントアプリは完成です。

間違い等ありましたらご指摘いただければ幸いです。
最後までご覧いただき、ありがとうございました。
man-dbのマニュアルの日本語訳

##[man-db](http://www.nongnu.org/man-db/)のマニュアルの[日本語訳](https://github.com/ysatoautonomous/jm-draft/wiki#man-db)

man-db の man ページを日本語へ翻訳しています。

man-db-2.9.0 の man ページが所々翻訳されていない状態なので [man-db-2.3.0 の翻訳](https://linuxjm.osdn.jp/INDEX/misc.html#man-db) をベースに更新してみました。

### 更新履歴
* 2020/12/27: man-db-2.9.0 lexgrog(1) を追加。
* 2020/07/02: man-db-2.9.0 manpath(5), accessdb(8), catman(8), mandb(8) を追加。
* 2020/07/01: man-db-2.9.0 manpath(1), whatis(1), zsoelim(1) を追加。
* 2020/05/12: man-db-2.9.0 apropos(1) を追加。
* 2020/05/05: man-db-2.9.0 man(1) を追加。

### man-db-2.9.0
#### 対応ディストリビューション
* Fedora 32

#### マニュアルのリンク一覧
[apropos(1)](https://ysatoautonomous.github.io/jm-draft/man2html/man-db/man-db-2.9.0/draft/man1/apropos.1.html)
[lexgrog(1)](https://ysatoautonomous.github.io/jm-draft/man2html/man-db/man-db-2.9.0/draft/man1/lexgrog.1.html)
[man(1)](https://ysatoautonomous.github.io/jm-draft/man2html/man-db/man-db-2.9.0/draft/man1/man.1.html)
[manpath(1)](https://ysatoautonomous.github.io/jm-draft/man2html/man-db/man-db-2.9.0/draft/man1/manpath.1.html)
[whatis(1)](https://ysatoautonomous.github.io/jm-draft/man2html/man-db/man-db-2.9.0/draft/man1/whatis.1.html)
[zsoelim(1)](https://ysatoautonomous.github.io/jm-draft/man2html/man-db/man-db-2.9.0/draft/man1/zsoelim.1.html)

[manpath(5)](https://ysatoautonomous.github.io/jm-draft/man2html/man-db/man-db-2.9.0/draft/man5/manpath.5.html)

[accessdb(8)](https://ysatoautonomous.github.io/jm-draft/man2html/man-db/man-db-2.9.0/draft/man8/accessdb.8.html)
[catman(8)](https://ysatoautonomous.github.io/jm-draft/man2html/man-db/man-db-2.9.0/draft/man8/catman.8.html)
[mandb(8)](https://ysatoautonomous.github.io/jm-draft/man2html/man-db/man-db-2.9.0/draft/man8/mandb.8.html)

### roff 版の入手先
https://github.com/ysatoautonomous/jm-draft.git
tee コマンドを使って 画面出力しつつ pipe で別コマンドにも渡す

:warning: Git Bash (mintty) で試しましたが、他の環境では 異なる結果を確認しました(調査中)

----

tee コマンドで `/dev/stderr` に出力することで画面にも出るようにできる。

```console
$ cat sep.txt
----
$
$ echo hoge | tee /dev/stderr | cat sep.txt - sep.txt
hoge
----
hoge
----
$
$ echo hoge | tee /dev/stdout | cat sep.txt - sep.txt
----
hoge
hoge
----
$
```

※ `/dev/stdout` を使うと、両方 pipe されて `cat` に渡る点に注意


## 実用例
curl telnet に HTTPリクエストを送りつつ画面にも出力したいとき

```console
$ echo -e "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n" | tee /dev/stderr | curl -s telnet://example.com:80
GET / HTTP/1.1
Host: example.com


HTTP/1.1 200 OK
Age: 250082
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Tue, 05 May 2020 14:10:05 GMT
Etag: "3147526947+ident"
Expires: Tue, 12 May 2020 14:10:05 GMT
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Server: ECS (sjc/4E76)
Vary: Accept-Encoding
X-Cache: HIT
Content-Length: 1256

<!doctype html>
<html>
<head>
    <title>Example Domain</title>

    <meta charset="utf-8" />
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style type="text/css">
(後略)
```

前半の

```
GET / HTTP/1.1
Host: example.com


```
の部分が `tee /dev/stderr` からの標準エラー出力

後半の

```
HTTP/1.1 200 OK
Accept-Ranges: bytes
Age: 433530
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Tue, 05 May 2020 14:02:02 GMT
Etag: "3147526947+ident"
Expires: Tue, 12 May 2020 14:02:02 GMT
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Server: ECS (sjc/4E74)
Vary: Accept-Encoding
X-Cache: HIT
Content-Length: 1256

<!doctype html>
<html>
<head>
    <title>Example Domain</title>

    <meta charset="utf-8" />
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style type="text/css">
(後略)
```

の部分が `curl` からの標準出力

## 注意点
画面出力に標準エラー出力を使って問題ないか仕様や制約を要確認

## 参考
- [【 tee 】コマンド――標準出力とファイルの両方に出力する：Linux基本コマンドTips（65） - ＠IT](https://www.atmarkit.co.jp/ait/articles/1611/16/news022.html#sample1)
Cloud Composerでの定数ファイルのファイルパスの指定方法

# 背景
Cloud Composerでyamlファイルのような定数ファイルを読み込みたい場合。

# やり方
以下のように `/home/airflow/gcs/dags...` の絶対パスを指定する。

```py
f = open("/home/airflow/gcs/dags/sample.yml", "r+")
data = yaml.load(f, Loader=yaml.FullLoader)
print(data)
```
AWSでWebサーバーを構築する！

今回は、Udemyで学習しながらAWSでWebサーバーを構築する。

#VPCでネットワーク作成
[VPCでネットワークを構築してみる](https://qiita.com/r_saiki/items/573f5b8659152936b912)を参照。

#EC2を作成
[AWSでEC2を作成する](https://qiita.com/r_saiki/items/dfc6122aaeb830256cf8)を参照。

#SSH接続
EC2の作成時に作成したpemファイルを指定してSSH接続。クライアントPCのOS、SSHソフトによって接続方法が違うので、おのおの合わせてもらう。

**必要情報**
IPv4パブリックIP：18.182.15.135(EC2のインスタンスメニュー参照)
ユーザー名：ec2-user(固定)
pemファイル：EC2起動時にダウンロードしたpemファイル

~~~:ubuntu16.04
$ sudo ssh -i /(保存フォルダのパス)/aws-key-webserver.pem ec2-user@18.182.15.135
Are you sure you want to continue connecting (yes/no)? yes
[ec2-user@ip-10-0-10-10 ~]$ 
~~~

~~~:Mac
$ sudo ssh ec2-user@18.182.15.135 -i /(保存フォルダのパス)/aws-key-webserver.pem -p 22
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
[ec2-user@ip-10-0-10-10 ~]$ 
~~~

#Apacheのインストール＆実行確認
以下のコマンドを実行。

~~~:EC2
[ec2-user@ip-10-0-10-10 ~]$ sudo yum update -y　＃パッケージの更新
[ec2-user@ip-10-0-10-10 ~]$ sudo yum -y install httpd　＃Apacheインストール
[ec2-user@ip-10-0-10-10 ~]$ sudo systemctl start httpd　＃Apache起動
[ec2-user@ip-10-0-10-10 ~]$ sudo systemctl status httpd　＃ステータス確認
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
　　＃active (running)と出ていれば起動成功！！
   Active: active (running) since 火 2020-05-05 09:35:23 UTC; 1min 13s ago
     Docs: man:httpd.service(8)
 Main PID: 1082 (httpd)
   Status: "Total requests: 0; Idle/Busy workers 100/0;Requests/sec: 0; Bytes served/sec:   0 B/sec"
   CGroup: /system.slice/httpd.service
           ├─1082 /usr/sbin/httpd -DFOREGROUND
           ├─1083 /usr/sbin/httpd -DFOREGROUND
           ├─1084 /usr/sbin/httpd -DFOREGROUND
           ├─1085 /usr/sbin/httpd -DFOREGROUND
           ├─1086 /usr/sbin/httpd -DFOREGROUND
           └─1087 /usr/sbin/httpd -DFOREGROUND

 5月 05 09:35:22 ip-10-0-10-10.ap-northeast-1.compute.internal systemd[1]: Starting The Apache HTTP Server...
 5月 05 09:35:23 ip-10-0-10-10.ap-northeast-1.compute.internal systemd[1]: Started The Apache HTTP Server.
~~~

サーバー起動時に自動でApacheが起動されるようにする。

~~~
[ec2-user@ip-10-0-10-10 ~]$ sudo systemctl enable httpd
[ec2-user@ip-10-0-10-10 ~]$ sudo systemctl is-enabled httpd
enabled
~~~

#ファイアウォールの設定
現時点では、SSH用のポート番号22しかアクセスできないので、ブラウザではアクセスできない。今からポート番号80を開けてブラウザでアクセスできるようにする。
EC2のメニューを開き、インスタンスを選択して、したメニューの説明タブのセキュリティグループ名を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558865/812ce423-46c8-5aae-3010-810ac1f40bf0.png)
インバウンドルールタブを選択して、インバウンドルールの編集を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558865/57cc506e-5060-f303-516c-5b2cdb86ed21.png)
以下のようにHTTPのルールを追加して、ルールの保存を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558865/614eb4d2-a6d8-30c5-6822-2f328c5830d8.png)
セキュリティグループにHTTPが追加される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558865/e729625d-6d97-ed0f-8ec5-f1c08787471d.png)
アクセスできるか確認→下のApache初期ページが表示されたら成功！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558865/5f7b789a-588b-2bcd-7844-e2d14c2ea77e.png)

#終わりに
Webサーバー構築までさくっと完了して良かった。習いながら慣れるのが一番最強な気がする^^
次回はDBサーバーも作っていきたい！
Django初体験の私が、文字だけでは理解しにくい用語と意味をひたすらノックしてみた

#はじめに
Django初体験の自分が理解できる言葉でひたすらメモしています。
そのためDjangoの熟練度によっては理解しにくい人もいるかと思います、ご了承ください。

わかりにくい箇所は私の大好きな二郎系ラーメンに例えて説明します。
自分が例えて楽しく理解できるものにしたため、二郎系がわからない人はすみません。
知らなくてもあまり支障はないと思いますが笑

※自身が文字を見ただけでは理解しにくいと感じた用語のみメモしているため、初心者がこの記事1つで用語を網羅できるというものではありません、ご了承ください。
#用語
###startproject（二郎系ラーメン屋OPEN!）
djangoグッズを呼び出すための呪文。


以下のようにターミナルを使って呼び出すことができます。

~~~
$django-admin startproject jirou #最後はフォルダ名、ここでは便宜上jirouとします。
$python3 manage.py runserver #開発サーバ起動

(省略)
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
~~~

ブラウザで`http://127.0.0.1:8000/`と打ち込み、「The install worked successfully! Congratulations!」と出てきたら完成、お店ができました。

###manage.py
・ターミナルでアプリ作成や、開発サーバを開く時に処理を行う場所
（例）

```
python manage.py runserver　#開発サーバ起動
```

###＿init＿py
・「Python使ってますよ！」とPythonに宣言するだけのファイルであり、中身は空っぽ。
・特に意味について深く考える必要はなさげ。

###urls.py（注文受付）
・サイトごとのURLを保存しておく場所。
・複数アプリになる場合に整理できて便利。
流れ
1.URLのリクエストが来る。
「二郎系300gニンニクマシマシください！」
2.指定のURLを表示するよう`views.py`へ情報を流す。
「二郎系300gニンニクマシマシ入りましたー！」
######urlpatterns = [= [path('jirou/', oishii),]
・リクエストを受けて指示を出すもの。
`jirou`ていう注文が入ると、`oishii`に書かれたデータを表示する指示を出す。
では`oishii`というデータはどこにどんなふうに書くのかというとこちら

```urls.py
from .views import oishii
urlpatterns = [
    path('jirou/', oishii)
]
```

ここで`views.py`から`oishii`を読み込むよーて宣言しといて、、、

```views.py
from django.http import HttpResponse
def oishii(request):
    returnobject=HttpResponse('jirou')
    return HttpResponse('おいしい！')
```

`request`は要求を受け取ったということを視覚的にわかりやすくするものであり、基本カッコ内はこれを入れる。
`jirou`という注文を前述の`http://127.0.0.1:8000/`の後に打ち込むと、、、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607405/3688d9aa-7bf9-3bf3-b76a-95f9818afdab.png)


上手にできました！！！
全体の流れは以下の通り。
1.`http://127.0.0.1:8000/jirou`によって、`urls.py`が、「`oishii`を読み込め」と注文。
2.`views.py`に書かれた`oishii`を読み込む。
3.`return HttpResponse('おいしい！')`によって、「おいしい！」と出力するよう`urls.py`へ連絡を返す。
4.「おいしい！」と出力される。

######urlpatterns = [= [path('jirou/',`この箇所の特殊な書き方`),]
・`include(◯◯◯.urls)`で、そのフォルダ（アプリ）内のurls.pyを引っ張ってくる。
その際importを以下のように指定。

```startprojectファイル/urls.py
from django.urls import path,include #末尾にincludeを追加。
```


###models.py（冷蔵庫などの具材）
・入力フォームやクラスなどを整理しておく場所（ニンニク置き場、油置き場等）。

###views.py（厨房）
・送られた要求に対して、適切なページを表示して返す処理を行う場所。
・models.pyから入力フォームやクラスなどを受け取る(ニンニクマシマシ取ってくれー)

具体的には、
・HTTPリクエストを受ける。
（urls.py）「二郎系300gニンニクマシマシ入りましたー！」
・HTTPレスポンスを返す。
(views.py)「ヘイかしこまり！」
といった仕事を行っている。
・受けた注文によって持ってくるhtmlが異なる（300gは`a.html`、400gは`b.html`など）。

###csrf(クロスサイトリクエストフォージェリ)
・直訳すると、「サイトをまたいで偽造のリクエストを送信する」こと。
・つまり自身が公開するサイトに、悪人が変な処理を促す恐れがあるということ。
・Djangoでは、HTMLに`{csrf_token}`という記述をすることで対策できる。

###'DIRS': [BASE_DIR,'templates'],
・htmlファイルは'templates'に入ってますよ！と宣言している。
###renderメソッド
使用例

```
def index(request):
    return render(request, 'A/index.html')
```

・Aのindex.htmlを返す。
・renderは「与える」とか「提供する」という意味。
#最後に
この記事を読んだdjango初心者の人が、同じように理解に役立ててくれれば嬉しいです！

今後も理解しにくい用語が出てくる度に更新していきます！
##おまけ
図解でめちゃ理解しやすかったサイト
https://djangobrothers.com/tutorials/memo_app/mtv/
デプロイで沼からハマってた私を救ってくれた神サイト
http://makimakimakino.hatenablog.com/entry/2019/01/13/200729
ArrowsM03（Android）の通知（電話、Lineなど）をiPhone（iOS）へ通知する方法

####作成経緯
スマホ2台持ち（ArrowsM03、iPhone11）でスマートウォッチ購入検討。
安価なスマートウォッチは2台のペアリングができない？
「PebbleTime」ならAndroidとiPhoneの同時接続する手順を見つけたが安くない。
ならばArrowsM03の通知をiPhone11へ通知。
その通知をiPhone11とペアリングしたスマートウォッチで受信。
####懸念事項
IFTTTの通知をスマートウォッチで受信できるか！
ここ大事ですが…　事前検証ができない＾＾；
####閑話休題　作成方法
![i01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145508/19862afc-50ca-9c51-d266-ae942ef027cc.png)
![i02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145508/6aa92b07-b6a2-e87c-805d-4b946f466406.png)
![i03.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145508/e5b3ef82-5d78-2908-bd87-2bd0037788a4.png)
![i04.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145508/aa24857e-34a9-d80b-5543-73be1f8d592d.png)
![i05.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145508/8ed8a698-19cb-4d0f-a88f-7ef17e86efc4.png)
![i06.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145508/a8fc6a80-bd75-0bbc-e12c-6ec13210d9e2.png)
![i07.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145508/9e1b3a8c-73fd-2ca5-4372-2022e109c746.png)
####テスト結果
嫁のArrowsM03から私のArrowsM03に電話した時のiPhoneのスクショ
↓
![i10.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145508/b640b60e-99db-2785-f641-658bea13a695.png)
嫁のArrowsM03から私のArrowsM03にLINE電話した時のiPhoneのスクショ
↓
![i11.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145508/48ded5f6-a37d-372f-e163-b4ba6390d5d1.png)
既存のLaravelプロジェクトにLaradockを導入する

# 既存のLaravelプロジェクトにLaradockを導入する
既存のLaravelプロジェクトをLaradock化する案件に遭遇しました。

新規にLaradock環境とLaravelプロジェクトを構築する手順は多く見つかるのですが、既存のLaravelプロジェクトにLaradockを導入する記事は見当たらなかったので、忘れない内に手順を記事にします。


# フォルダー構成
こんな感じのフォルダー構成の `project-hoge` というLaravelプロジェクトがもともとあるとします。

```
project-hoge/
 ├ .env : laravelプロジェクトの設定ファイル
 ├ composer.json
 └ （中略）
```

上記を最終的に以下のようにします。

```
project-hoge/
 ├ .env : laravelプロジェクトの設定ファイル
 ├ composer.json
 ├ （中略）
 └ laradock/
    └ （中略）
```



# laradockフォルダーを作成する

カレントディレクトリーが `project-hoge` フォルダーの状態で、以下のコマンドを実行します。

```bash
git submodule add https://github.com/Laradock/laradock.git
```

すると、 `laradock` フォルダーが生成され、その中にLaradockのソースコードが展開されます。

以上でLaradockの導入完了です。

後の手順は、新規にLaradockのプロジェクトを作成する場合と、変わりません。  `laradock/.env` を編集して、Laradockの設定をしていきましょう。



# さいごに
本記事作成にあたり、以下の記事を参考にしました。ありがとうございました。

- [Laradock / Getting Started / A.1](https://laradock.io/getting-started/#A1)
- [Laradockを使ったLaravel開発環境構築](https://qiita.com/J_Shell/items/695a30fd38444d065ae5)
Linuxで動作するデスクトップアプリをAdobe AIRで作る（Ubuntuの場合）

# はじめに

UbuntuでHello Worldを表示するデスクトップアプリを作成します。
また、パッケージングするところまでの手順を書きます。
IDEは利用せずに、コマンドでコンパイル等を行います。
Wineを利用してAdobe AIRを動作させます。

## アプリの完成イメージ

![tmp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102121/4adc0a68-d097-8205-6c73-eab925bce257.png)

## 試した環境/バージョン

Ubuntu 20.04
Apache Flex 4.16.1
Adobe AIR 32

# 事前準備
winetricksでAdobe AIRをインストールしておく

```
$ winetricks adobeair
```

# 環境作成

## Apache Flex SDKとAdobe AIR SDKのダウンロード

以下から、Linux用のapache-flex-sdk-4.16.1-bin.tar.gzをダウンロード
http://flex.apache.org/download-binaries.html

以下から、Windows用のAdobeAIRSDK.zipをダウンロード
https://www.adobe.com/devnet/air/air-sdk-download.html
　※青色のダウンロードボタンではなく、以下のリンクからダウンロードする
　　Note: Flex users will need to download the original AIR SDK without the new compiler.
　　　Download Mac  |  Download Windows

## 解凍してマージ

マージするためのフォルダーを作成
（今回はホームにFlex4.16.1_AIR32という名前のフォルダーを作成）

apache-flex-sdk-4.16.1-bin.tar.gzを解凍した中身を上記のフォルダーに配置

その後、AdobeAIRSDK.zipを解凍した中身を上書きで上記のフォルダーに配置

## 環境変数の設定

```
$ export AIR_HOME=~/Flex4.16.1_AIR32
$ export PATH="$AIR_HOME/bin:$PATH"
```

## 確認

以下のコマンドが利用できるようになったことを確認する

```
$ amxmlc -version
Version 4.16.1 build 20171115
```

# アプリの作成、実行

## mxmlの作成

```mxml:Main.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
					   xmlns:s="library://ns.adobe.com/flex/spark"
					   xmlns:mx="library://ns.adobe.com/flex/mx"
					   width="400" height="300" fontFamily="Meiryo">

	<fx:Script>
		<![CDATA[

			import mx.controls.Alert;

			/**
			 * アラートを表示する処理
			 */
			private function showMessage():void {
				
				// アラートを表示
				Alert.show('Hello World');
			}

		]]>
	</fx:Script>

	<!-- ラベル -->
	<s:Label left="10" top="10" text="Click the button."/>

	<!-- ボタン -->
	<s:Button left="10" top="40" label="Click Me" 
		click="showMessage();" />

</s:WindowedApplication>
```

## コンパイル

以下を実行するとMain.swfが作成される

```
$ amxmlc Main.mxml
```

## application.xmlの作成

```application.xml
<?xml version="1.0" encoding="utf-8" ?>
<application xmlns="http://ns.adobe.com/air/application/32.0">
	<id>MyApplication</id>
	<versionNumber>1.0</versionNumber>
	<filename>MyApplication</filename>
	<initialWindow>
		<content>Main.swf</content>
	</initialWindow>
</application>
```

## アプリの実行

以下を実行するとデスクトップアプリが起動する

```
$ wine ~/Flex4.16.1_AIR32/bin/adl.exe application.xml
```

# パッケージング

## 証明書の作成

以下を実行
※最初に作成するときの１回のみ実行する

```
$ java -jar ~/Flex4.16.1_AIR32/lib/adt.jar -certificate -cn "TestCert" 2048-RSA "TestCert.p12" pass
```

TestCert.p12が作成される

## パッケージング

以下を実行

```
$ java -jar ~/Flex4.16.1_AIR32/lib/adt.jar -package -tsa none -storetype pkcs12 -keystore "TestCert.p12" -storepass pass MyApplication.air application.xml Main.swf
```

MyApplication.airが作成される

このMyApplication.airを右クリックして、Adobe AIR Application Installerで開くことで作成したアプリをインストールすることができる

とりあえず今回はここまで
tsoaを使ってAPIドキュメントを自動生成

## tsoa

[tsoa](https://tsoa-community.github.io/docs/)とは、TypeScriptとNodeを使用してOpenAPI準拠のREST APIを生成するためのモジュール。
2020-05-05時点の最新バージョンはv3.0.8。

- APIの唯一の信頼できる情報源としてのTypeScriptコントローラーとモデル
- Express、Hapi、Koa対応
- エンドポイントの説明などにはjsdocを使用

### メリット

- コメントと実装のずれがなくなる（JSDocで管理するモジュールもあるが、いつかずれる）
- ドキュメント上からリクエストが投げれる

### デメリット

- デコレーター祭り
- route.tsをプレコンパイルする必要があり、開発環境が少しだけ複雑に

## 導入方法

[Introduction \| tsoa](https://tsoa-community.github.io/docs/introduction.html#goal)を順に進めれば、以下のようなAPIドキュメントが `http://localhost:3000/docs` に表示されます。

<img width="661" alt="スクリーンショット 2020-05-05 22.31.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510204/a23d4757-f41d-6e61-49d5-f22c433b99d7.png">

Controller部分をデコレーターを使用した書き方にする必要があり、
既存プロジェクトに導入するにはそこそこな作業が発生しそう。

JavaでOpenAPI準拠のREST APIを生成する場合は以下が参考になります。
https://qiita.com/ririkku/items/6e416d13567c6ee9e633

## その他

tsoaのドキュメントのリポジトリ
https://github.com/tsoa-community/docs