OmniAICreator/Qiita-1.07M huggingface dataset:
無課金男子「無料クレジット保留にしつつ請求先アカウント設定できませんか？(∀｀*ゞ)」GCPサポート「できない」

# 概要

GCPのCloud Functions(以下CF)でSlackへの投稿等やりたいなと思うようになる。
しかしCFは請求先アカウント設定しないと、外部へのリクエストを制限されている。
請求先アカウント設定はいいんだけど、12か月の無料クレジット約3万円はスタートしたくない・・・。
ということで、12か月の無料クレジットを保留にしつつ、課金アカウント設定だけできないかとサポートに問い合わせた話です。

# 読者対象

- GCPを今後始めようとしている方
- AWS Lambda、Azure Functions、GCP CFのいずれのFaaSで勉強開始しようとしている方


# どうして12か月の無料クレジットを保留にしたいのか？

がっつりGCPを利用するときに開放したく、ちょっと外部アクセスするためだけにカウントダウンを開始しなくない乞食魂:sweat_smile:


# クレカ登録していないのにGCPって使えるの？

恐らくGCPからアカウント作成した場合、登録途中でクレカ登録して課金アカウント設定がされているはずです。
しかし、Firebaseが自動で作成した場合、クレカ登録していませんので、利用できるんだけど課金設定されてない、という変わった状態になっていると思われます。
全部が利用できるわけではなく、Firebaseが提供している一部が利用可能というのが正解かと思われます。

FirebaseのCloud FunctionsやCloud Storageを使用すると、GCPのアカウントをFirebaseが自動で作成します。
通常GCPを意識することはないのですが、”使用状況”＝＞"View quota"で画面遷移すると、自動で作成されたGCPにアクセスできます。



# サポートより回答

タイトルで結論を出している通り、無料クレジット保留という行為は不可。
NGの根拠はこれがすべてでした。

https://cloud.google.com/free/docs/gcp-free-tier?hl=ja

>12 か月間の $300 相当の無料トライアルは、最初の請求先アカウントを設定すると、自動的に開始されます。

請求先アカウントを設定すると、**自動的に開始**。
それなら回避はどうあがいても無理ですね:joy:


# まとめ

CFを使った外部への通信は、無料トライアルを開始しない以上利用することはできません。
ライバルであるAzureについても、アカウント登録と当時に無料クレジットのカウントダウンが開始されるので状況は同じです。
AWSについてはそもそも無料クレジットがないですが、12ヶ月無料の製品がいくつかあるため、カウントダウン開始という意味では同じです。
クレカ登録なしでGoogle内専用とはいえ、Functionsが利用できるというのが特例だととらえるべきでしょう。
決めろ、覚悟、GCPのみの12か月:scream:
Windows Server 2016にGit for Windowsをインストールし、複数人開発でバージョン管理システムを作成するとき、sshは通るのにgit cloneがエラーになるときの対処法

#はじめに

会社内でGitを利用した開発ソースコードのバージョン管理システムを構築するにあたり、Windows ServerにGit For Windowsをインストールして複数人開発でのバージョン管理システムを作成するとき、参考サイトのように設定しながら構築作業を進めていたところ、次のようなエラーに悩まされたのでその時の対処法をメモする。

##発生したエラー
Windows ServerでOpenSSHのsshdを起動し、開発用PCからssh接続によりgit cloneしたとき、下記のようなエラーが発生しクローン出来なかった。

    [ユーザー名]@[コンピューター名] MINGW64 ~
    $ git clone ssh://[ユーザー名]@[サーバーのIPアドレス]/c:/repos/test.git
    Cloning into 'test.git'...
    [ユーザー名]@[サーバーのIPアドレス]'s password:
    
    
    fatal: Could not read from remote repository.
    
    Please make sure you have the correct access rights
    and the repository exists.


Windows ServerでGit For Windowsのsshdを起動したときは上記エラーは発生せずcloneができる。しかしながら接続するユーザー名でsshdを起動しないと下記のような別のエラーが発生したので対処法を考えなけらばならなくなった。

Windows Serverの方でadministratorにて/usr/bin/sshd.exeを起動し、クライアントからadministrator以外の接続ユーザー名でssh接続したときWindows Server側で発生するエラーは下記のようなものであった。

    debug1: temporarily_use_uid: 1049696/1049089 (e=1049076/1049089)
    seteuid 1049696: Operation not permitted
    debug1: do_cleanup
    debug1: Killing privsep child 7364



##構築するバージョン管理システムのイメージ
![ソース管理環境構築イメージ.jpg](https://qiita-image-store.s3.amazonaws.com/0/303278/39d63345-e7c6-4bbf-5b0c-cb44cdeadc82.jpeg)

#インストールしたソフト
##Window Server 2016
* Git for Windows (2.21.0) 64-bit version
* Win32-OpenSSH v7.9.0.0p1-Beta

##開発作業用PC
* Git for Windows (2.21.0) 64-bit version


#バージョン管理システム作成時に参考にしたサイト

* [Windows10パソコン上にGitサーバを立ててみた - LinuxサーバがないけどGitサーバを運用したい場合の対処法](http://imamachi-n.hatenablog.com/entry/2018/06/09/170331)
* [LinuxからWindows ServerにSSHでログインできるまでの環境設定](https://qiita.com/M_Nagata/items/722a9970dcc2a0b71612)


#対処方法
参考にしたサイトのように設定するとエラーが発生して思うように動作しなかったので、次のような手順を追加した。

1. Window Server上のGit For Windowsの各コマンドが保存されているフォルダにパスを通す。
2. Window Server上のユーザーにリモートリポジトリへのアクセス権（読み/書き）を追加する。
3. Window Server上のOpenSSHのデフォルトシェルをGit for Windowsのbashへ変更する。


##1. Window Server上のGit For Windowsの各コマンドが保存されているフォルダにパスを通す。

コントロールパネルのシステムの詳細設定を開き、「環境変数」を開く。

次のような環境変数を追加する。

・ C:\Program Files\Git\cmd
・ C:\Program Files\Git\usr\bin
・ C:\Program Files\Git\bin
・ C:\Program Files\Git\mingw64\bin
・ C:\Program Files\Git\mingw64\libexec\git-core

##2. Window Server上のユーザーにリモートリポジトリへのアクセス権（読み/書き）を追加する。
Active Directoryにて開発者用のグループやポリシーを作成している場合は、開発者グループの書き込み権限をGitのリポジトリのフォルダに付与する。

##3. Window Server上のOpenSSHのデフォルトシェルをGit for Windowsのbashへ変更する。
    New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Program Files\Git\git-bash.exe" -PropertyType String -Force 

#確認
## OpenSSHのsshdを起動する。
1. 2. 3. を設定したのち、net start sshdによりOpenSSHのsshdを起動する。
※念のためPsExec64にて、system権限で起動する。

## git clone
作業用PCからssh接続にてgit cloneすると下記のように成功する。

    [ユーザー名]@[コンピューター名] MINGW64 ~/source
    $ git clone ssh://[ユーザー名]@[サーバーのIPアドレス]/c/repos/test.git
    Cloning into 'test'...
    [ユーザー名]@[サーバーのIPアドレス]'s password:
    warning: You appear to have cloned an empty repository.
[未経験者による初回投稿]binary_search in python

#binary_serach

##①リストの中央値、最小値、最大値を設定する。
関数定義の中で、最小値は0, 最大値はリストの大きさを測るlen関数を用いて(リストのインデックス番号は0から始まるため)-1をする。
注意が必要なのは、ここで言う数値はインデックス番号であってリスト内の要素ではないことです。必ず対象の数値を出力する場合はlist(今回の場合はnumbers)[low or mid or high]となります。

##②while構文を用いて論理上lowとhighの間で中央値とtarget_numberを比較して探索対象を削る
while low <= high:とすることで、論理上繰り返しの中でlowがhighを超えないように中央値とtarget_numberの比較を実行するようにした。

##③中央値とtarget_numberが一致した場合に、戻り値として[target_numberは○○番目です]と返す。
if numbers[mid] == target_number:
    return str(target_number) + "は" + str(mid)+ "番目です"
上記のように書くことで、関数定義ブロック外でprint(binary_search())以外のコードを書く必要がなくなりました。
なぜこのようなことを記載するかというと、最初関数内で上記の文章を返すコードを書かずにブロック外で書いてしまい、迷走してしまったためです。

##④中央値とtarget_numberが異なる場合はlow(high)をmid+1(highであれば-1)にする。
中央値がtarget_numberより低ければ、中央値をlow+1に変更することで探索対象リストを狭めていく。大きければ、highをmid -1 することで同様に探索対象リストを狭めます。狭めた後にwhile以降にあるようにlow <= highになるまで繰り返します。ここでif文の中でreturnをした後にbreakをしてもいいかもしれません。

##⑤最後はprintで関数を読み戻す
最後はprint(binary_search(numbers, target_number)を出力して値を確認します。
下記コードになります。

```py
def binary_search(numbers, target_number):
    #中央値をmidとする。
    #リストの最小値をlow, 最大値をhighとする。
    low = 0
    high = len(numbers)-1
    
    while low <= high:
        mid = (low + high)//2
        
        if numbers[mid] == target_number:
           return str(target_number) + "は" + str(mid) + "番目です"
        elif numbers[mid] < target_number:
            low = mid + 1
        else:
            high = mid - 1
                
# 探索するデータ
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
# 探索したい値
target_number = 11
# バイナリーサーチの実行
print(binary_search(numbers, target_number))
```
Dockerでvolumeが正しくマウントされない

# 問題
Windows10 & Docker for windows & WSLを使用している場合に、
dockerコマンド、または、docker-composeコマンドでvolumeを使用しようとすると、
volumeが正しくマウントされない (ディレクトリだけあってファイルがなかったりする)。

例：

```
└── src
    └── test.go
```

こんなディレクトリを作成して

```
docker run -v ./:/go/src/ -it golang
```
docker run しても

```
/go# ls -la ./src/
total 8
drwxrwxrwx 2 root root 4096 Apr  6 01:19 .
drwxrwxrwx 4 root root 4096 Apr  6 01:19 ..
```
ファイルがない

# 原因
WSL(Windows Subsystem for Linux)が原因でした。
WSLではCドライブが、/cではなく、/mnt/cにマウントされていることが原因で正しく動作しないようです。
(コマンドプロンプトからdockerコマンドを実行すれば正しく動作しました。)

# 対応策
以下の設定ファイルを作成し、Windowsのリスタートを行います。

※Windowsのバージョンによって対応方法が変わるので詳しくは以下をご確認ください。
https://nickjanetakis.com/blog/setting-up-docker-for-windows-and-wsl-to-work-flawlessly

```
sudo nano /etc/wsl.conf

# Now make it look like this and save the file when you're done:
[automount]
root = /
options = "metadata"
```

# まとめ
上記の設定でdocker-composeでは、問題なく動作するようになりました。
dockerコマンドでは、相対パスでは相変わらず正しくマウントできませんでしたが、
絶対パスであれば正しくマウントできました。
#jq コマンドで出力されるダブルクォートを #perl  で削除する例

# jq 

there is double quotation 

```
$ echo '["A\\nB\\nC"]' | jq  '.[]'
"A\nB\nC"
```

# jq --raw-output

there is not double quotation but new lines 

```
$ echo '["A\\nB\\nC"]' | jq --raw-output '.[]'
A
B
C
```

# perl replace

i tried this

```
$ echo '["A\\nB\\nC"]' | jq '.[]' | perl -pe 's/^"|"$//g'
A\nB\nC
```


# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/1114








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
Vyperでエラー: InvalidTypeException

# エラー内容

```bash
Traceback (most recent call last):
  File "/Users/foobar/vyper-env/bin/vyper", line 4, in <module>
    __import__('pkg_resources').run_script('vyper==0.1.0b9', 'vyper')
  File "/Users/foobar/vyper-env/lib/python3.6/site-packages/pkg_resources/__init__.py", line 743, in run_script
    self.require(requires)[0].run_script(script_name, ns)
  File "/Users/foobar/vyper-env/lib/python3.6/site-packages/pkg_resources/__init__.py", line 1498, in run_script
    exec(code, namespace, namespace)
  File "/Users/foobar/vyper-env/lib/python3.6/site-packages/vyper-0.1.0b9-py3.6.egg/EGG-INFO/scripts/vyper", line 153, in <module>
    interface_codes=interface_codes
  File "/Users/foobar/vyper-env/lib/python3.6/site-packages/vyper-0.1.0b9-py3.6.egg/vyper/compiler.py", line 227, in compile_codes
    exc_handler(contract_name, exc)
  File "/Users/foobar/vyper-env/lib/python3.6/site-packages/vyper-0.1.0b9-py3.6.egg/EGG-INFO/scripts/vyper", line 82, in exc_handler
    raise exception
  File "/Users/foobar/vyper-env/lib/python3.6/site-packages/vyper-0.1.0b9-py3.6.egg/vyper/compiler.py", line 223, in compile_codes
    interface_codes=interface_codes,
  File "/Users/foobar/vyper-env/lib/python3.6/site-packages/vyper-0.1.0b9-py3.6.egg/vyper/compiler.py", line 144, in _mk_abi_output
    return mk_full_signature(code, interface_codes=interface_codes)
  File "/Users/foobar/vyper-env/lib/python3.6/site-packages/vyper-0.1.0b9-py3.6.egg/vyper/compiler.py", line 68, in mk_full_signature
    abi = sig_utils.mk_full_signature(parser.parse_to_ast(code), *args, **kwargs)
  File "/Users/foobar/vyper-env/lib/python3.6/site-packages/vyper-0.1.0b9-py3.6.egg/vyper/signatures/sig_utils.py", line 73, in mk_full_signature
    global_ctx = GlobalContext.get_global_context(code, interface_codes=interface_codes)
  File "/Users/foobar/vyper-env/lib/python3.6/site-packages/vyper-0.1.0b9-py3.6.egg/vyper/parser/global_context.py", line 111, in get_global_context
    global_ctx.add_globals_and_events(item)
  File "/Users/foobar/vyper-env/lib/python3.6/site-packages/vyper-0.1.0b9-py3.6.egg/vyper/parser/global_context.py", line 490, in add_globals_and_events
    constants=self._constants
  File "/Users/foobar/vyper-env/lib/python3.6/site-packages/vyper-0.1.0b9-py3.6.egg/vyper/types/types.py", line 428, in parse_type
    unit = parse_unit(argz[0], custom_units=custom_units)
  File "/Users/foobar/vyper-env/lib/python3.6/site-packages/vyper-0.1.0b9-py3.6.egg/vyper/types/types.py", line 296, in parse_unit
    raise InvalidTypeException("Invalid base unit", item)
vyper.exceptions.InvalidTypeException: line 11: Invalid base unit

```

# 原因
Vyperのバージョンが不適切。

# 対策
Vyperのバージョンを合わせる。
現状、Vyperはマイナーバージョンが異なっていてもエラーとなる場合が多々あるので、きっちり合わせたほうが無難。
PowershellとAWSCLIでAWS EC2のセキュリティグループを抽出した話

#動機
初投稿です。
AWSのマネジメントコンソールでセキュリティグループの閲覧をしていて、
セキュリティグループとかインバウンドとかチクチク押すのめんどいなと思いまして。
本記事投稿当時、Powershellで作業するのがマイブームであったということもあり、
ちょいとチャレンジした次第です。

#やりたいこと
GroupIDに対し、インバウンドに表示されるルールの見たい項目を配列として格納し、
CSV形式でいい感じに出力したい。

#使ったもの
- Powershell
- AWSCLI

#できたもの
```hoge.ps1
#配列の出力先のファイル名の記述
$LogFolder = 'C:\hoge\results'
$TimeStamp = (Get-Date -Format 'yyyyMMdd-HHmmss')
$ResultCsv = $LogFolder + '\' + 'result_' + $TimeStamp + '.csv'

function main {
    #配列の宣言とaws ec2 describe-security-groupsで持ってきたjson文を
    #AWS_jsonにオブジェクトとして格納
    $list = @()
    $AWS_json = aws ec2 describe-security-groups | ConvertFrom-Json

    #配列の作成    
    foreach($x in $AWS_json.SecurityGroups){
        foreach($y in $x.IpPermissions){
            foreach($z in $y.IpRanges){
                $list += New-Object PSObject -Property @{
                    TagName=$x.Tags.Value 
                    GroupName=$x.GroupName 
                    GroupID=$x.GroupID
                    Protocol=$y.IpProtocol
                    Port=$y.ToPort
                    Source=$z.CidrIp
                    Description=$z.Description
                }
            }
            foreach($z in $y.UserIdGroupPairs){
                $list += New-Object PSObject -Property @{
                    TagName=$x.Tags.Value 
                    GroupName=$x.GroupName 
                    GroupID=$x.GroupID
                    Protocol=$y.IpProtocol
                    Port=$y.ToPort
                    Source=$z.GroupID
                    Description=$z.Description
                }
            }
        }
    }
    #表示順変更
    $list = $list | Select-Object `
        "TagName" , "GroupName" , "GroupID" , `
        "Protocol" , "Port" , `
        "Source" , "Description"
    
    #配列をCSVファイルに出力
    $list | Export-Csv -Path $ResultCsv
}

main

```

#できたものからできたもの
大方こんな感じ。
「-1」と入っているのはAWSのコンソールから見たときの「すべて」に相当するようです。

TagName | GroupName | GroupID | Protocol | Port | Source | Description
----- | ----- | ----- | ----- | ----- | ----- | -----
hoge | hoge | sg-hogehogehoge | tcp | 8080 | 0.0.0.0/0 | hoge
hoge | hoge | sg-hogehogehoge | tcp | 22 | 0.0.0.0/0 | hoge
 | default | sg-hogehogehoge | -1 |  | sg-hogehogehoge | hoge
hoge | hoge | sg-hogehogehoge | tcp | 80 | 0.0.0.0/0 | hoge
hoge | hoge | sg-hogehogehoge | tcp | 443 | 0.0.0.0/0 | hoge

#所感
あまりjsonファイルに触れたことがなかったため、いい勉強になりました。
そしてPowershellでのjsonファイル整形が意外と面白かったです。json好きになりました。
ソース文について、3重ループがちょっと気持ち悪い気がしてます。
今回はNew-Objectだけで記述しましたが、Add-Memberを活用したやり方のが自分は好みです。
一応上記のソース文を最終盤にしてますが、もっといい書きっぷりがあると思って色々試行錯誤してます。
プログラミング自体ご無沙汰なもんで。。。
以上、初投稿でした。
PlayFab Party とはなんぞ？

PlayFabでChatシステムが実装できるようになりましたよ
という話
※まだパブリックプレビュー中(2019年3月現在)

### PlayFab Party とは
Speech to Text と　Text to Speech によるユーザコミュニケーション用ツール
Azure の Azure Speech Services を利用して
チャットをリアルタイム翻訳も行うことができるので、ワールドワイドなマルチプレイを行うことができるようになります。
(なので機能的にはP2PではなくRelayサーバを介して通信する)
現状Windows7,10,XboxOne のみですが、2019年8月にはiOS,Android,NintendoSwitchも対応するようになる予定

### 具体的にどんな機能なの？
・PlayFabIDを利用してデバイス認証を行い、DTSLのようなプロトコルで暗号化
・Azure上にあるRelayサーバを介して、パーティネットワークを作成しデータ通信を実施
・このパーティーネットワークにプレイヤーのオーディオデバイスをバインドしてリアルタイムチャット通信を実現
　テキストチャットもサポート
・プレイヤーの音声とテキストチャットのリアルタイム翻訳を実現

### どうやって実装するの？
PlayFabParty用SDKを導入することで設定することができます。
ライブラリはすでに公開済みの様子
(この辺りはもう少し情報が出てきたら追記したいと思います)


### で、お高いんでしょ？
PlayFabの基本費用から追加で利用分で支払う必要があります(Azureのサーバを利用するので)
かかる費用は大きく分けて下記3つ

1.ネットワークに接続しているユーザ分：パーティチャットを作成もしくは参加すると課金
2.チャット時間：アクティブに話をされている時間(秒単位)　　　　　　　 
3.ネットワーク：PlayFabの中継サーバと音声サーバから送信されるデータ量

細かい料金に関しては[こちら](https://docs.microsoft.com/en-us/gaming/playfab/features/multiplayer/networking/pricing)
Kotlinのwhen句

Kotlinのwhen句はとても柔軟です。

実行結果は変数に付与することも可能です。

仕様は下記のページを参照できます。
https://kotlinlang.org/docs/reference/control-flow.html#when-expression

```KotlinTest.kt
fun main() {

    //性別
    val genderCode = 1

    //単一判断値
    when (genderCode) {
        1 -> println("男性")
        2 -> println("女性")
        else -> {
            println("性別はわからない")
        }
    }

    //複数判断値
    when (genderCode) {
        1,2 -> println("性別設定あり")
        else -> {
            println("性別設定なし")
        }
    }

    //関数結果は判断値
    when (genderCode) {
        parseInt("1"),parseInt("2") -> {
            println("性別設定あり")
        }
        else -> {
            println("性別設定なし")
        }
    }

    //範囲内であるか
    val validNumbers = listOf(1, 5, 7)
    val index = 5
    when (index) {
        in 1..10 -> println("1～１０に存在する")
        in validNumbers -> println("配列に存在する")
        !in 10..20 -> println("10～２０に存在しない")
        else -> println("判断できない")
    }

    //Whenの結果は変数に付与できる
    println(hasPrefix("prefixdata"))
}

/**
 * prefixで始めた文字列？
 *
 */
fun hasPrefix(x: Any) = when(x) {
    is String -> x.startsWith("prefix")
    else -> false
}

```

実行結果
>男性
性別設定あり
性別設定あり
1～１０に存在する
true

判断結果は変数に付与できることで、Nest階層の深さを削減しやすいです。

以上
[Rails] Action CableでWebsocketが繋がらない（原因はconfig）

# 問題
Action CableでWebsocketが繋がらない。
bashには下の様なログがひたすら出続ける。

```bash:bash
Started GET "/cable" for 10.0.2.2 at 2019-04-08 08:30:09 +0100
Started GET "/cable/" [WebSocket] for 10.0.2.2 at 2019-04-08 08:30:09 +0100
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
RoomChannel is transmitting the subscription confirmation
Started GET "/cable" for 10.0.2.2 at 2019-04-08 08:30:09 +0100
Started GET "/cable/" [WebSocket] for 10.0.2.2 at 2019-04-08 08:30:09 +0100
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
RoomChannel is transmitting the subscription confirmation
Started GET "/cable" for 10.0.2.2 at 2019-04-08 08:30:18 +0100
Started GET "/cable/" [WebSocket] for 10.0.2.2 at 2019-04-08 08:30:18 +0100
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
RoomChannel is transmitting the subscription confirmation
```

# 原因

config/environments/development.rbで以下の設定をしていた事が原因だった。

```ruby:config/environments/development.rb
config.reload_classes_only_on_change = false
```

# 解法
コメントアウトするか削除すればよい。
[備忘録]AngularCLIでコンポーネントを作成する方法

# Angularのコンポーネント作成方法
`ng generate component コンポーネント名` で作成できる

```
MakinoMacBook-Pro:ngDragDrop makimatsu$ ng generate component drag_drop
CREATE src/app/drag-drop/drag-drop.component.scss (0 bytes)
CREATE src/app/drag-drop/drag-drop.component.html (28 bytes)
CREATE src/app/drag-drop/drag-drop.component.spec.ts (643 bytes)
CREATE src/app/drag-drop/drag-drop.component.ts (281 bytes)
UPDATE src/app/app.module.ts (406 bytes)
```

手で`/Src` 直下にコンポーネントフォルダ作ったらエラー出た


# 実行結果
`/Src/app` の中に`drag-drop`フォルダができたよ
![image.png](https://qiita-image-store.s3.amazonaws.com/0/331389/545ae185-1fed-0a58-e215-283b67b39f5b.png)
チーム開発でよく使うgitコマンド


## 1. リポジトリを取ってくる
開発したいプロジェクトのリポジトリをリモートから取ってくる。

```
git clone [リポジトリURL]
```
リポジトリURLは
・GitLab：Cloneボタンを押下し、HTTPのURLをコピーして貼り付ける。
・Github：Clone or downloadボタンを押下し、Use HTTPを押下してURLをコピーして貼り付ける。

## 2. リポジトリのデータの最新の情報を取得する
コードは最新だが、ブランチの情報が入っていないため、
fetchコマンドを使って最新の情報を取得する。

```
git fetch
```

## 3. 作業したい該当のブランチに移動する
既にブランチが作られている場合は以下のコマンドのみでOK。

```
git checkout [ブランチ名]
```

まだ作られていない場合は新たに作る必要があるので、

```
git  checkout -b [ブランチ名]
```
で作った後、checkoutする。

## 4.コードを書き終えたら編集ファイルをステージングに上げる
編集したファイルをステージングにあげて、コミットしたいファイルとそうでないファイルを分ける。
ステージングにあげたファイルはコミットしたいファイルになる。
編集したファイルの全てをあげる時は。

```
 git add . 
```
編集したファイルの一部をあげる時は、

```
git status
```

でファイルパスを確認し、

```
 git add [$filepath]
```

##### 番外編)
編集を全て取り消したい時は、

```
 git checkout -- .
```

編集を一部だけ取り消したい場合は、

```
 git checkout [$file_path]
```

## 5. ステージングにあげたファイルをコミット
リモートにあげる一つ手前の段階に上げる。
その際に***どのように編集したかがわかるような***メッセージが必要なので、

```
git commit -m "[メッセージ]"
```
でコミットする。

## 6. コミットしたファイルをリモートに上げる
リモートにあげる際は、

```
git push origin [ブランチ名]
```
で上げることができる。
これで一通りのやりとりは終了。
僕のいるチームはこの後にレビュワーと呼ばれるコードの管理人がいるのでその人のチェックが入る。
修正が必要なら修正。
修正が不要ならこのまま進む。

## 7. 自分が上げた複数のコミットを１つにまとめる
ファイルの編集→修正→修正...と続いていくと、
複数のコミットが散財してしまうので1つにまとめる。

```
git rebase -i [自分が担当した一つ前のコミットID]
```
上記コマンドで今までのコミットがエディタで表示される。
最初のコミットを残して他をfixupにする(fでも可)。
終わったらエディタを保存して終了する。

## 8. まとめ終わったコミットをpush

```
git push -f  origin feature/branch
```
自分の他コミットと衝突してしまうため、-fで強制的にpushしてしまう。

※git push -f は他コミットを無視して強制的にpushしてしまうので、
自分の担当以外のコミットを打ち消して上書きしまうので使用するときは最大の注意を払う。

## 9. developブランチに移る
コミットをdevelopに反映するためにブランチを移動させる。

```
git checkout develop
```

## 10. コミットを反映させる

```
git cherry-pick [まとめたコミットID]
```
上記コマンドでdevelopにコミットを反映することができる。

## 11. 反映させたコミットをpush

```
git push develop
```
これで自分の担当した実装をプロジェクトに反映することができる。
今年の言語はRust その４



Rustを学びます

![rustacean-orig-noshadow(1).png](https://qiita-image-store.s3.amazonaws.com/0/62413/6434e827-0d08-be8e-a391-72a43ca21994.png)
http://rustacean.net/

## 参考
勉強ページは日本語ドキュメント

[プログラミング言語Rust](https://doc.rust-jp.rs/)

Rustの日本語ドキュメント 2nd Edition
https://doc.rust-jp.rs/book/second-edition/

オリジナル
https://doc.rust-lang.org/book/



## 3. Common Programming Concepts

## 3.3 関数の動作法

関数名はPythonのようにスネークケース

```rust
fn main() {
    anoter_function(5, 10);    
    
}


fn anoter_function(x: i32, y: i32){
    println!("The value of x is: {}", x);
    println!("The value of y is: {}", y);
}

```

### 関数本体は、文と式を含む。

ちょっと何言っているかわからない。

> Rustは「式指向言語」

文とは statement
> 文とは、なんらかの動作をして値を返さない命令です。 

式とは expression
> 式は結果値に評価されます。

```rust
fn main() {
    
    let x = 999; // statement
    
    let y = {
        let x = 3;
        x + 1   // expression
    }; // statement
    
    println!("y is: {}", y);
    println!("x is: {}", x);
}
```

### 戻り値のある関数

```rust
fn main() {
    
    let x = five();
    
    println!("x is: {}", x);
}

fn five() -> i32{
    5
}

==
x is: 5

```

```rust
fn main(){

    let x = plus_one(5);
    
    println!("x is {}", x);
    
}

fn plus_one(x: i32) -> i32{
    x + 1
}

==
x is 6

```


特に特筆すべきはありませんでした。

次回はifです
[備忘録]Angularプロジェクト作成(ng new)でエラー

# Angularで新規プロジェクト作成しようとするとエラーが出たよ
```
MakinoMacBook-Pro:makimatsu makimatsu$ ng new ng_dragDrop
? Would you like to add Angular routing? No
? Which stylesheet format would you like to use? SCSS   [ http://sass-lang.com   ]
Schematic input does not validate against the Schema: {"name":"ng_dragDrop","version":"7.0.6","routing":false,"style":"scss"}
Errors:

  Data path ".name" should match format "html-selector".
```

# 原因
プロジェクト名にアンダーバーが入っているとダメらしい
名前を変更したら作成できた！

```
MakinoMacBook-Pro:makimatsu makimatsu$ ng new ngDragDrop
? Would you like to add Angular routing? No
? Which stylesheet format would you like to use? SCSS   [ http://sass-lang.com   ]
CREATE ngDragDrop/README.md (1027 bytes)
CREATE ngDragDrop/angular.json (3895 bytes)
CREATE ngDragDrop/package.json (1319 bytes)
CREATE ngDragDrop/tsconfig.json (408 bytes)
```
主にFirefoxでflexを使ったときにwidthが効かないときがある

## HTML

```html

<div class="wrap">
  <input type="text">
  <span>-</span>
  <input type="text">
</div>
```

## SCSS

```scss
.wrap {
  display: flex;
  align-items: center;
  width: 300px;
  span {
    display: block;
    width: 20px;
    text-align: center;
  }
  input {
    flex: 1;
  }
}
```

これだとspanのwidthが効かない

## bugfix

```scss
.wrap {
  input {
    min-width: 0;
  }
}
```

多分幅が足りない？押し出されちゃって効かないっぽい。
主にfirefoxで起こる。

デモ：[flexを使ったときにwidthが効かないときがある](https://codepen.io/ituki_b/pen/pBExZm)
参考：https://stackoverflow.com/questions/34199345/text-overflow-ellipsis-and-flex-not-working-on-firefox
Azure App Serviceで一部のディレクトリのみCache-Controlヘッダ（など）を編集する

# はじめに
[前回](https://qiita.com/ume814/items/fcaa72a82f655d05796d)の続き。
特定のディレクトリ以下だけ、キャッシュ制御を行う。
#方針
前回、キャッシュを保存しないためのヘッダを追加した。
そのヘッダを、特定のディレクトリ以下では追加しないようにする。
#方法
前回作成した ```web.config``` に、以下の内容を追加する。

```
<location path="ここに対象のディレクトリ">
    <system.webServer>
        <httpProtocol>
            <customHeaders>
                <remove name="Cache-Control" />
                <remove name="Pragma" />
            </customHeaders>
        </httpProtocol>
    </system.webServer>
</location>
```

どこに追加するかというと、```<location>``` の下。フルで書くと

```web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.webServer>
        <httpProtocol>
            <customHeaders>
                <add name="Cache-Control" value="no-store" />
                <add name="Pragma" value="no-cache" />
            </customHeaders>
        </httpProtocol>
    </system.webServer>
    <location path="対象のディレクトリ">
        <system.webServer>
            <httpProtocol>
                <customHeaders>
                    <remove name="Cache-Control" />
                    <remove name="Pragma" />
                </customHeaders>
            </httpProtocol>
        </system.webServer>
    </location>
</configuration>

```
となる。

# おわりに
複数のディレクトリを1つの ```location``` で表せれば、便利なのだが。
ABC - 093- A&B&C

#AtCoder ABC 093 A&B&C
[AtCoder - 093](https://atcoder.jp/contests/abc093)

#A問題

 - 文字列の中に`a,b,c`がそれぞれ1文字ずつ含まれていれば並び替えで`abc`を作ることは可能

```java
	private void solveA() {
		Scanner scanner = null;
		String s = "";

		try {
			scanner = new Scanner(System.in);
			s = scanner.next();

			char[] wk = s.toCharArray();

			int cntA = 0;
			int cntB = 0;
			int cntC = 0;

			for (int i = 0; i < wk.length; i++) {
				char c = wk[i];
				if (c == 'a' && cntA == 0) {
					cntA++;
				} else if (c == 'b' && cntB == 0) {
					cntB++;
				} else if (c == 'c' && cntC == 0) {
					cntC++;
				}
			}

			System.out.println((cntA + cntB + cntC) == 3 ? "Yes" : "No");

		} finally {
			if (scanner != null) {
				scanner.close();
			}
		}
	}

```

#B問題

 - 何も考えずにA～Bまでループ
    - 前からK番目
    - 後ろからK番目
 
 - 速度もとめるなら二つのループか？
     - A～min(B,A+K)までループ
     - min(A,B-K)～Bまでループ



```java
	private void solveB() {
		Scanner scanner = null;
		int numA = 0;
		int numB = 0;
		int numK = 0;

		try {
			scanner = new Scanner(System.in);
			numA = scanner.nextInt();
			numB = scanner.nextInt();
			numK = scanner.nextInt();

			List<Integer> wk = new ArrayList<Integer>();
			for (int i = numA; i <= numB; i++) {
				if (i < numA + numK || numB - numK < i) {
					wk.add(i);
				}
			}

			for (int i = 0; i < wk.size(); i++) {
				System.out.println(wk.get(i));
			}

		} finally {
			if (scanner != null) {
				scanner.close();
			}
		}
	}
```

#C問題

 - コードのコメントに色々記載


```
{1,2,3}　という並びの場合
可能であれば、3に合わせるのが最小手数に見えるが、、、
 -> 3にあわせようとする
    -> 1,2にそれぞれ+1する
    -> {2,3,3} となり無理

 -> 3+1=4にあわせようとする
    -> 1に+2する {3,2,3}
    -> 2に+2する {3,4,3}
    -> 1,3に+1する {4,4,4}

操作は常に+2するので、埋め合わせる数は偶数でないといけない
なので、最大値に合わせた場合に埋め合わせる数の総計が偶数となるか奇数となるかで分岐
偶数なら/2をすればよく、奇数なら+3（3つの数字全てに+1）することで偶数に変換する
```

```java
	private void solveC() {

		try (Scanner scanner = new Scanner(System.in)) {

			int[] wk = new int[3];
			wk[0] = scanner.nextInt();
			wk[1] = scanner.nextInt();
			wk[2] = scanner.nextInt();

			Arrays.sort(wk);

			/*
			 * 基準となる値の計算
			 * 全て最大値に合わせる前提
			 */
			int m3 = wk[2] * 3;
			/*
			 * 最大値に合わせてよいのか？
			 * 現在の総計と最大値に全てあわせた場合の偶奇が同じなら、
			 * 埋めなくてはいけない数値は偶数
			 * 違う場合は、埋めなくてはいけない数値が奇数
			 *  - 奇数に偶数を足しても奇数/偶数に偶数を足しても偶数
			 */
			boolean isEqual = (wk[0] + wk[1] + wk[2]) % 2 == m3 % 2;

			int targetNum = 0;
			int res = 0;
			/*
			 * 埋める数値が奇数の場合、そのままでは埋められないので
			 * 合わせる数値を+1する
			 */
			if (isEqual) {
				targetNum = wk[2];
			} else {
				targetNum = wk[2] + 1;
			}

			/*
			 * 埋めなくてはいけない差分の数値を合計して2で割る
			 */
			for (int i = 0; i < wk.length; i++) {
				res += (targetNum - wk[i]);
			}
			res /= 2;

			//			/*
			//			 * 1つ1つ何回操作するのか試しているパターン
			//			 */
			//			boolean isPlusOne = false;
			//			for (int i = 0; i < wk.length; i++) {
			//				//常に+2の操作パターン
			//				res += (targetNum - wk[i]) / 2;
			//				if (!isPlusOne) {
			//					//あまりがあったということは、二つに+1ずつする操作があるということ
			//					isPlusOne = (targetNum - wk[i]) % 2 != 0;
			//				}
			//			}
			//
			//			/*
			//			 * 二つに+1する操作
			//			 */
			//			if (isPlusOne) {
			//				res++;
			//			}

			System.out.println(res);

		}
	}
```
メモ化から学ぶ早期リターン

# お世話になっている方からの課題
業務の合間でようやく手をつけられたので、ここにその奮闘記を記す。数学、勉強しなければならないという思いが強まった今日この頃です。

## 指令:フィボナッチ数列のマトリクスを作るメソッドを再帰処理を用いて作りあげよ
マトリクス部分も実装はできているのですが、今回はトピックには関係がないので、割愛します。
最初、自分がこれ作った時は、再帰処理を利用していないものだったので、頭を悩ませたんですが、結構再帰処理の例としてよくフィボナッチ数列使われるんですねぇ・・・

```
def calc_fibonacci 
  array = [0,1]
  (1..(@fields * @records)).each do |index|
    fibo_num = array[index - 1] + array[index]
    array.push(fibo_num)
  end
end
```
上記が再帰を使わない自分の最初のフィボナッチメソッドなんですが隣り合う数字の和が次の数字となるのならば、ループさせている変数の片方を-1してやれば、隣り合う数字の和という式を実現できる発想でした。

## 再帰使えよ・・・再帰使えよおおおおおおぉぉぉぉ！！！
というわけで、再帰を考えていきます。

```fibo.rb
index calc_fibonacci
when 0 then
  0
when 1 then
  1
else
  calc_fibonacci(index - 2) + calc_fibonacci(index - 1)
end
```

これが再帰処理になります。おい、なんだindexって、変数ねぇぞと思うかもしれませんが、これは、まだ未完成のコードです。ここからメモ化の実装を入れていきますが、その前に再帰についての説明をします。

####再帰処理
コマンドオプションにもよくある-rのことです。recursiveですね。一旦最深部まで降りて登ってくるイメージです。例えば、rmコマンドも再帰オプションを使うと、削除対象がディレクトリの深いものだと一旦最深部まで降り、そこから削除を開始して最後に一番最初のディレクトリを消去する挙動をとります。
最初の再起を使っていないメソッドはフィボナッチ数を全て出してくれるのと違って、この再帰を使ったメソッドはn番目のフィボナッチ数を出してくれるものです。
入力に対する求めることができるモノが違います。しかし、どちらのメソッドを用いてもマトリクスを作ることはできます。この辺、面白いと感じます。
**求め方、実装の仕方、つまり、中身は違うけど、求められているものは求めることができる、数学っぽいですね。エンジニアとしても非常に大事なことです。**
関数の中に同じ関数があるので、引数が計算されると0か1が得られるまで何度も計算がなされて、その分岐された最終結果が加算されることでフィボナッチ数が求められるというものです。

## メモ化
ですが、このコード、重複計算が多く、引数の数が大きくなればなるほどメソッドのコール回数も増えるので、時間がかかります。そこで、メモ化を実装します。

```memo_fibo.rb
  @@memo = {}

  def calc_fibonacci(index)
    return @@memo[index] if @@memo.has_key?(index)

    @@memo[index] =
      case index
      when 0 then
        0
      when 1 then
        1
      else
        calc_fibonacci(index - 2) + calc_fibonacci(index - 1)
      end
    return @@memo[index]
  end
```
上から見ていきます。
haz_key?メソッドを用いて、配列indexの中に同じキーを持つバリューがあれば、trueを行い、その時点で処理を終了させるreturnが書かれています。
そして、その後に、先ほどのフィボナッチ数を求めていき、配列の中に処理結果を入れていけるように、**case文そのものを配列に代入しています。**ここ、個人的に驚いたのですが、式ならば代入可能、確かにそうですが、＝で結べる視点が横にしかなかった（x = 0のような）ので、ここでの視点は縦なんですよね。

```
x = 
case index
when
.
.
when
.
.
```
コードを読む視点の高さを1個手に入れた感がありました。**式ならば、いくら長くてもその結果を代入できる。**

再帰的に一度計算した結果が配列のなかにあれば、処理を終わらしてくれて、無い時だけ、has_key?のfalseが返って、下の処理が走るようになる実装がコードの最初になされているので、重複されている計算がされず、結果として、高速化できます。

## 早期リターン
この時の、条件が満たされている時には、処理を終わらせる、つまりそれ以下に書かれた処理は実行されないようにすることで、ifのネストや、else句の記述量を増加させないようにするテクニックを、早期リターンと呼びます。
codebuild artifactがS3に上がってくれない。

## 事象

```失敗したログ
[Container] 2019/04/08 07:11:19 Assembling file list
[Container] 2019/04/08 07:11:19 Expanding test.txt
[Container] 2019/04/08 07:11:19 Skipping invalid artifact path test.txt
[Container] 2019/04/08 07:11:19 Phase complete: UPLOAD_ARTIFACTS State: FAILED
[Container] 2019/04/08 07:11:19 Phase context status code: CLIENT_ERROR Message: no matching artifact paths found
```
Codebuildでartifactのアップロード先をS3にするも失敗。
ファイルは作られているように見えるが、ちゃんとアップロードされない。

## 原因
buildspec.ymlの中で別のディレクトリに移動して作業をしてたから。
どうやらデフォルトディレクトリ以外にartifactを置いてもアップロードされないみたい。

## 例
### 失敗する例
```buildspec.yml
version: 0.2

phases:
  test:
    - mkdir -p hoge
    - cd hoge
    - echo "hoge" > test.txt

artifacts:
  files:
    - test.txt

```

### 成功する例
```buildspec.yml
version: 0.2

phases:
  test:
    - DEFAULT=`pwd`
    - mkdir -p hoge
    - cd hoge
    - cd $DEFAULT
    - echo "hoge" > test.txt

artifacts:
  files:
    - test.txt
```

元のディレクトリに戻ってからファイルを作成したらちゃんと動いた。

デフォルトディレクトリは下記のように固定されてないので、
まず最初に取得しておく必要があり？(環境変数であるかも)

```
/codebuild/output/src123456789/src/github.com/[user]/[repo]
```
---
- 2019/4/9追記

環境変数ありました。
CODEBUILD_SRC_DIR: CodeBuild がビルドに使用するディレクトリパス (例: /tmp/src123456789/src)。
https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-env-ref-env-vars.html
【docker-compose】Railsサーバが起動しない場合の対処法

##はじめに
Dockerを使ってRailsアプリケーション開発時にハマった箇所をアウトプットとして残しております。

Docker勉強中のため間違った見解があればご指摘よろしくおねがいします。


##問題
Railsサーバ(localhost:3000に設定しています)へ接続する際、サーバへアクセスできない。
なお、下記の状態のようにコンテナ起動は未起動になっている。

##状態

`docker-compose up -d`でコンテナを起動時に以下の状態

```
$ docker-compose up -d
Starting task_jenkins_1   ... done
Starting task_db_1      ... done
Starting task_webserver_1 ... done
```

`docker-compose ps`でコンテナの起動状態を確認
▼railsアプリケーションを立ち上げるためのtask_webserver_1のStateがExit 1(未起動)状態です

```
$ docker-compose ps
      Name                    Command               State                  Ports              
----------------------------------------------------------------------------------------------
task_db_1          docker-entrypoint.sh mysqld      Up       3306/tcp, 33060/tcp              
task_jenkins_1     /bin/tini -- /usr/local/bi ...   Up       50000/tcp, 0.0.0.0:8080->8080/tcp
task_webserver_1   bundle exec rails s -p 300 ...   Exit 1     

```

`task_webserver_1`のログを確認

```
$ docker logs task_webserver_1
=> Booting Puma
=> Rails 5.2.2.1 application starting in development 
=> Run `rails server -h` for more startup options
A server is already running. Check /app/tmp/pids/server.pid.
Exiting
```

既にサーバーは起動しているようです。
/app/tmp/pids/server.pidを確認してくださいとあります。

####server.pidとは
WEB開発サーバを起動するときに書き込まれ、停止すると削除されるファイルです。
なんらかの状態でサーバを停止したのに残ってしまっていることがあると起動状態と判断されサーバが立ち上がらなくなります。


今回はこのserver.pidが書き込まれている状態のため、webserverが起動出来なくなっている為
このファイルを削除してあげれば起動ができそうです。

##対処法

▼server.pidファイルを削除

```
$ rm tmp/pids/server.pid
```

▼再度、コンテナを起動させる

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

▼コンテナの状態を確認

```
$ docker-compose ps
      Name                    Command               State                 Ports              
--------------------------------------------------------------------------------------
task_db_1          docker-entrypoint.sh mysqld      Up      3306/tcp, 33060/tcp              
task_jenkins_1     /bin/tini -- /usr/local/bi ...   Up      50000/tcp, 0.0.0.0:8080->8080/tcp
task_webserver_1   bundle exec rails s -p 300 ...   Up      0.0.0.0:3000->3000/tcp 
```

StateがUp状態になっている為起動がされています。
Railsを起動するためのサーバにアクセスします。

<img width="755" alt="スクリーンショット 2019-04-08 16.37.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/197693/1ac421fe-815f-9713-dc91-f39e388141fd.png">


成功です。
２つのカスタム投稿タイプから記事を取得しつつ、１つはタクソノミーを指定する方法

２つのカスタム投稿タイプから記事を取得するが、１つはタクソノミーで絞り込みたい時のtax_queryの書き方でハマったのでメモ。


## カスタム投稿タイプとカスタムタクソノミー

```
カスタム投稿タイプ： CD（cd）
カスタムタクソノミー： cd_category
```

```
カスタム投稿タイプ： DVD（dvd）
カスタムタクソノミー： dvd_category
```

みたいな感じで、それぞれカスタム投稿タイプとカスタムタクソノミー（カテゴリー）が設定されている。

## やりたいこと

- CDは「全て」のカテゴリーの記事を取得する
- DVDはタクソノミーが 「ライブ（live）」 の記事を取得する


## tax_queryの書き方


```php5
$args = [
	'post_type' => ['dvd', 'cd'],
	'tax_query' => [
		'relation' => 'OR',
		[
			'taxonomy' => 'dvd_category',
			'field' => 'slug',
			'terms' => 'live'
		],
		[
			'taxonomy' => 'dvd_category',
			'operator' => 'NOT EXISTS'
		],
	]
];
query_posts($args);
```

ポイントはtax_queryの２つ目の配列。

カスタム投稿タイプ「CD」の「全て」を取りたいので、cd_categoryを指定したくなるが、`'operator' => 'ALL'` の様な指定ができない。
CDに対してのtax_queryを指定しないと、dvd_category = live の条件がCDにも反映されてしまって、結果0件になってしまう。

そこで、 dvd_category が NOT EXISTS ＝ CD全て　という取り方をする必要がある。



##　参考サイト

- https://ja.wordpress.org/support/topic/2%E3%81%A4%E3%81%AE%E3%82%AB%E3%83%86%E3%82%B4%E3%83%AA%E3%83%BC%EF%BC%8B%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E3%81%AE%E5%80%A4%E3%81%A7%E6%9D%A1%E4%BB%B6/
ブラウザのUser-Agentが滅茶苦茶になってしまった理由

# はじめに
ブラウザとそうでないもの（ブラウザのふりをしないボットなど）を見分けるためには、HTTPリクエストで使われているUser Agentヘッダーを使用することが多いです。

例えば、みなさんもこの怪しいUser Agentを見たことがあると思います。ChromeのUser Agentです。

```
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36
```

ChromeがWebKitを使っているのは分かるのですが、Mozilla、Geckoとかとは全く関係ないはずですがｗ...　むしろ敵同士です。しかも何故かSafariのバージョンまで入ってます。

少し古いですが[User Agent一覧](http://www.openspc2.org/userAgent/)を見ると、**ほとんど全てのブラウザが`Mozilla/`で始まってます**。

理由を探るべく、[少し面白い記事](https://webaim.org/blog/user-agent-string-history/)に出会ったので翻訳します。

# 由来
当初は、１９９３年にNCSA (米国立スーパーコンピューター応用研究所)がリリースしたブラウザ、Mosaicが画期的なブラウザとして広く使われていました。MosaicのUser Agentはとてもシンプルだったそうです。(^^)

```
NCSA_Mosaic/2.0 (Windows 3.1)
```

ところが、Mosaicと競争するNetscapeのブラウザが登場し、"Mosaic Killer"を短縮してMozillaと名付られました。現代のFirefoxの前任者です。MozillaのUser Agentも簡潔でした。

```
Mozilla/1.0 (Win3.1)
```

Mozillaは独自にコンテンツを読み込むフレームという機能に対応していたので、当時のウェブエンジニアはUser AgentヘッダーでMozillaとMosaicを区別していました。問題解決！

# Internet Explorer
その後Microsoftがフレームに対応したInternet Explorerを開発しました。ところが、MozillaのUser Agentヘッダーを使っていなかったため、Mosaic用のページが返ってくるという問題があります。ブラウザ市場を独占するまで待てなかったMicrosoftは、Mozillaとの互換性があるとして、ヘッダーに`Mozilla`と入れてしまいました。Mozillaに成りすましたということですね...

```
Mozilla/1.22 (compatible; MSIE 2.0; Widnows 95)
```

# Gecko

Internet Explorerは勝ち残ったのですが、MozillaはGeckoというエンジンを開発しFirefoxとなって対抗します。

```
Mozilla/5.0 (Windows; U; Windows NT 5.1; sv-SE; rv:1.7.5) Gecko/20041108 Firefox/1.0
```

GeckoエンジンはInternet Explorerなど他のエンジンより優れていたため、Geckoを使うブラウザが急増しました。このため、再びUser Agentでブラウザを区別するサイトが増えました。

また、当時KHTMLというエンジンを使ったKonquerorというブラウザが開発されていたのですが、Internet Explorerと同じような理由でUser Agentに`Mozilla`や`Gecko`というキーワードを入れました。User Agent がわけ分からなくなってくるのはここらへんからです。

```
Mozilla/5.0 (compatible; Konqueror/3.2; FreeBSD) (KHTML, like Gecko)
```

# WebKit
結構長いので少し省略しますが、AppleがSafariを開発したときに、KHTMLをフォークしてWebKitという別のエンジンを作りました。Safariも同じようにGecko用のウェブページを読みたかったたため、User Agentを成りすましました。

```
Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/85.7 (KHTML, like Gecko) Safari/85.5
```

おなじみのChromeはSafariと同じようなウェブページを読み込みたかったため、Safariの真似をしました...　
**現代幅広く使われているブラウザ、ChromeのUser Agentは、当時のMozillaに成りすましたGeckoエンジンに偽装したKHTMLを使っているふりをしたSafariの真似をするためのものだということです.....**

```
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36
```

# 結論

おかげさまで、User Agentヘッダーは**滅茶苦茶**になり、実際にブラウザを当てることが難しくなった気がします。結局最初の`Mozilla/`はほとんど何も意味がないものとなってしまい、実際に何が何に対応しているのかをUser Agentだけで見分けることは不可能に近く、User Agentの信憑性は疑わしく、ブラウザーの特定に必要以上な手間がかかる世界が作られたということです。

個人的には、この悲しい歴史を知って少し悲しくなりました。プログラマーとしてもいちいちこれに対応するのも大変です。その一方で、プログラマーの視点をなくせば面白い話だと思います。

最近はブラウザ開発者の間で色々なウェブテクノロジーの標準化が進められているようなので、過去を教訓にこのようなことが起こらないようにしてほしいです。

`Chrome/73.0.3683.86　(AppleWebKit/537.36)`みたいなシンプルなUser Agentを取り戻すのは、今からでも遅くないと思います。でもそうしたら、今度はMozillaが`Chrome`の真似をするかもしれませんね。
Tagで指定した時間にインスタンスを止める(AWS EC2)

お金を無駄にしたくないので、タグで時間を設定しておいて、その時間が来たら停止するようなスクリプトを作りました。

### 事前設定
EC2のタグで`shutdown_time`タグを作成し、値に`0~23`までの数字を入力

管理サーバを用意。
（サーバ内にaws-cliのセットアップを行う）

### スクリプト

```sh
#!/bin/sh

#現在のhourを取得
CURRENT_HOUR=`date | awk '{print $4}' | awk -F '[:]' '{print $1}'`

#起動中インスタンスの中からshutdown_timeタグに設定した時間と現在の時間が一致してたら停止
aws ec2 stop-instances --instance-ids\ 
$(/usr/local/bin/aws ec2 describe-instances | jq -r '[.Reservations[].Instances[] | select((.State.Name == "running") and (.Tags != null) and (.Tags[] | select(.Key == "shutdown_time") | .Value == "'$CURRENT_HOUR'")) | .InstanceId] | join(" ")')

```

このスクリプトを保存し、cronを設定

```sh
#毎時シェル実行
0 */1 * * * start_instances.sh
```

参考
https://teratail.com/questions/111679
https://shellscript.sunone.me/variable.html

余談
Lambdaでも十分できそう。
これだとタグつけてないと起動しっぱなしになるので、ないときは勝手に落とすようなスクリプトor Lambdaを書く予定。
【React】【typescript】Functional Component の defaultProps の定義方法

# はじめに

最近 React Component を実装する際は Functional Component で書いています。
その際、 defaultProps の解決方法に躓いたので書きます。

# 他でよく紹介されている方法

```typescript
import React from 'react';

type Props = {
  foo?: string;
}

const BarComponent = (props: Props) => {
  return (
    <div>{props.foo}</div>
  );
}
BarComponent.defaultProps = {
  foo: 'FOO'
}
```

この方法だと `props.foo` が `string | undefined` になってしまうという問題があります。

# 解決方法

```typescript
import React from 'react';

type Props = {
  foo?: string;
}

const BarComponent = ({ foo = 'FOO' }: Props) => {
  return (
    <div>{foo}</div>
  );
}
```

これで `foo` が `string` になります。

というのを上司に教えてもらいました。
これで問題があれば教えてください。
MongoDBのGUI操作ツール

MongoDBの操作にコマンドのほうが多いかもしれませんが、
やはりGUIのほうが直感的でよく使いますね。

GUIツールはいくつかがありますが、使いやすさ、ラインセンスなどによって選択できます。

#MongoDB Compass
https://www.mongodb.com/products/compass

JSONインポート、エクスポート、クエリ作成に便利です。

#Robo 3T

Robo 3T (formerly Robomongo) is the free lightweight GUI for MongoDB enthusiasts.
URL: https://robomongo.org/

Studio 3TはProfessional MongoDB GUIです。

普段作業では、Robo 3Tでも十分できます。
イメージ：
![image.png](https://qiita-image-store.s3.amazonaws.com/0/346425/38888ccf-ba9e-f558-628b-0a9f6bfd3727.png)


#Nosqlclient

Cross-platform and self hosted, easy to use, intuitive mongodb management tool - Formerly Mongoclient

URL：https://www.nosqlclient.com

Windows版のダウンロードは、
https://github.com/nosqlclient/nosqlclient
ページのDistributionsの「Windows x64」リンクとなります。

イメージ：
![image.png](https://qiita-image-store.s3.amazonaws.com/0/346425/204592d7-63f6-6222-0f3a-ea8621748fe1.png)

#A5M2
https://a5m2.mmatsubara.com/

愛用する方は多いRDBのツールですが、MongoDBも対応しております。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346425/81fb6aea-d595-f902-c256-a1ac1f4f6e4d.png)

ローカルだと、ユーザーID、パスワード不要です。SSH2トンネルを使ってリRemoteサーバに接続しやすいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346425/6d5a2aa3-e4a1-01e0-9e1a-020fa7e96153.png)

RDBと同じ感覚で操作できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/346425/9116737c-5a65-198b-58fc-f6d698e143a6.png)


#NoSQLBooster
URL:https://nosqlbooster.com/home
個人用はFreeです。

など

以上
JavaScriptでTwitter、Facebookシェア用URLを作る

## 概要

Twitter、Facebookなどのシェア機能はURLを叩くことができれば自前で実装することができる。

ベースとなるシェアURLにクエリパラメータを付与する形で実装する。

jsでクエリパラメータを付与する方法は色々な方法があるが、今回はURLSearchParamsを使用する。

URLSearchParamsはIE11だと使えないのには注意してほしい。(他のブラウザだとだいたい使用可能)

[Can I use... Support tables for HTML5, CSS3, etc](https://caniuse.com/#search=URLSearchParams)

## URLSearchParamsについて

`new URLSearchParams`では、`URLSearchParamsオブジェクト`として扱われるため、クエリパラメータの文字列のみ欲しい場合は`.toString()`してあげる必要がある。

```javascript
const baseUrl = 'https://twitter.com/intent/tweet?';
const queryParam1 = ['key', 'value'];

// https://twitter.com/intent/tweet?key=value
const query = new URLSearchParams([queryParam1]).toString(); 
```

## TwitterのシェアURLについて

### ベースURL

```
https://twitter.com/intent/tweet?
```

### クエリパラメータ

```
url=シェアするURL&text=ツイート本文&via=シェアするURLのアカウント&hashtags=ハッシュタグ&related=ツイートした後フォローさせたいアカウント
```

ハッシュタグを複数付けたい場合は「,」で区切ればOK。

```
&hashtags=ハッシュタグ1,ハッシュタグ2
```

### 実装

```javascript
const baseUrl = 'https://twitter.com/intent/tweet?';
const text = ['text', 'ツイート本文'];
const hashtags = ['hashtags', ['ハッシュタグ1', 'ハッシュタグ2'].join(',')];
const url = ['url', location.href];
const via = ['via', 'tos'];
const query = new URLSearchParams([text, hashtags, url, via]).toString();
const shareUrl = `${baseUrl}${query}`;
```


## FacebookのシェアURLについて

### ベースURL

```
https://www.facebook.com/sharer/sharer.php?
```

### クエリパラメータ

facebookの場合、urlのみ指定することができる。

```
u=シェアするURL
```

### 実装

_URLだけなので正直そのまま文字列結合でもいいと思います。_

```javascript
const baseUrl = 'https://www.facebook.com/sharer/sharer.php?';
const url = ['u', location.href];
const query = new URLSearchParams([url]).toString();
const shareUrl = `${baseUrl}${query}`;
```


## 各種SNSのアイコン

[Font Awesome Brand Icons](https://www.w3schools.com/icons/fontawesome_icons_brand.asp)を使用すればOK。

npm、またはyarnで導入する場合はこちら。[@fortawesome/free-brands-svg-icons - npm](https://www.npmjs.com/package/@fortawesome/free-brands-svg-icons)

```
$ npm i --save @fortawesome/free-brands-svg-icons

Or

$ yarn add @fortawesome/free-brands-svg-icons
```

## まとめ

今回はURLSearchParamsを使って実装してみましたが、１回使い方がわかると結構便利でこれからも使って行きたくなりました。

ほかSNSもクエリパラメータさえわかれば同じような手法で実装できると思います。

## 参考URL

[URLSearchParams - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/URLSearchParams)

[【ソーシャルサービス】シェアURLまとめ - Qiita](https://qiita.com/takuhito-h/items/891f3d53ad14a1182963)
Vue.jsとScoped CSSとz-indexの話

## scoped cssいいですよね

scoped cssは、特にVue.jsにおいては、css設計のスタンダードと言っていいのではないかと思います。

BEM等の学習コストの高い手法を覚える必要がなく、「コンポーネント内でのみcssクラス名の一意性を確保すればいい[^1]」という、シンプルで管理しやすい設計指針を打ち立てることができ、実に理にかなった手法ですね。
プロジェクト全体でのcss命名規約の統制問題は依然としてありますが、コンポーネントベースでの設計手法自体がコンポーネントを書き捨てる運用と親和性があるため、そこまで大きな問題にはならないのかなと思います。

[^1]: slot内のスコープが親子共通だったり、コンポーネントroot要素に親からclassが注入できるといった例外はありますが

## 依然として残る考慮点

一方、scoped cssだけで、コンポーネント内にcss的な関心事を完全に閉じ込められるかというとそうではなく、当然ながら例外もあります。

最も代表的な例としては、cssの仕様上継承されてしまう属性ですね。
```font-size```など、属性自体が子孫要素に継承されるものとして定義されていますので、セレクタレベルでscopedにしたところで、子孫要素への影響を避けることはできません。

まあこの辺は書いていても直感的に理解しやすいのでそこまで問題になりにくいのですが、個人的に危ないなと思うのは「z-index」「重ね合わせコンテキスト」です。

## z-indexの管理

cssをざっくり理解したつもりになっているエンジニアが犯しがちな間違いの一つが、z-indexがグローバルだと思いこんでしまうことだと思います。

そう考えているエンジニアは、Vueプロジェクト全体で単純にコンポーネントごとのz-indexを管理することをを思いつきます[^2]。例えば、コンテキストメニューのコンポーネントはz-index1000番台、モーダルダイアログのコンポーネントはz-index500番台といった管理です。（モーダル上でコンテキストメニューを開くかもしれない。その場合はコンテキストメニューがモーダルの下に回り込んでほしくない、なんてことを考えているわけですね）

この方式は重ね合わせコンテキストがページ内で1つであるうちは上手く機能しますし、ルール自体はおそらく間違いでもないです。
ただ、重ね合わせコンテキストに関する考慮を漏らしていると、「z-indexで勝っているはずなのに、なぜか後ろに回り込んでしまう要素」が出てくる可能性があり、「なぜか動かない」という状況に見舞われます。実際には仕様理解が足りていないだけなのですが。

理解すべき仕様「重ね合わせコンテキスト」の詳細についてはMDNを読んでください。

https://developer.mozilla.org/ja/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context

ざっくり言えば、「z-indexは同じ重ね合わせコンテキストの中での比較にしか使われない」「重なる系の属性(potision: absoluteなど)が指定された要素は自身が重ね合わせコンテキストを形成する」ということです。

これもfont-sizeなどと同じで、親要素で指定された属性が（たとえscopedであろうとも）、子孫要素に影響を与えうる、ということですね。

[^2]: 私です

## デザインは文脈依存？

scoped cssとコンポーネントベースでの部品化は、確かに今までのcssの不便さや複雑さの大部分を解決しているように見えますが、z-indexの件を一つの例として考えると、「デザイン・見た目・UIは、どこまで部品化しても文脈依存から逃れられない」ということを示している気がします。まさに、重ね合わせ「コンテキスト」ですしね。

z-indexをpropsで渡せば…みたいな発想はもちろんあるのですが、結局その先にあるのはinput要素の再発明だったりするわけです。input要素をwrapしてたはずがinput要素を作っていた…みたいな。

どんなコンテキストでもデザイン破綻せず使うことのできるUI部品の実装は、相当な労力を要します。（まあ、実際にUI部品系のnpmパッケージの中を覗いてみると、普通にz-indexがハードコードされていて変更できなかったりすることが多く、みんなほどほどに手を抜いているんだと思いますが）

プロジェクト内でのデザイン統一・再利用を想定してコンポーネントを分割設計する際に、デザイン的な汎用性を求めるのはほどほどにしておくべきなのかな、と思った次第でした。

他コンポと疎結合に作るとか、ステートレスに作るとか、そちらに労力を割いたほうが実りが大きいんじゃないかな。UIの寿命は短いので、捨てやすいように疎結合に書くのが一番大事かな、と個人的には思います。
[学習用] RailsでUbuntuにnodo.js、yarn、Vue.jsをインストール

Ubuntu16 でRails+Vueを使うためにインストールしようとしたが
ハマったのでメモ。
この手順のままひたすらコマンドを打てば入る。


#node.jsのインストール
```
$ sudo apt install -y nodejs npm
$ sudo npm install n -g
$ sudo n stable
$ sudo apt purge -y nodejs npm
$ exec $SHELL -l
$ node -v
```

#Yarnのインストール
```
$ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
$ echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
$ sudo apt-get update && sudo apt-get install yarn
```

#Railsで使う
```
$ rails new myapp --webpack=vue
$ rails webpacker:install 
$ rails webpacker:install:vue
$ rails g controller Page home
```

#ルーティング
```routes.rb
Rails.application.routes.draw do
  root to: 'page#home'
end
```

#記述するところと設定
##HTMLとして記述する場合は下記の様にする
```app/javascript/packs/hello_vue.js
import Vue from 'vue/dist/vue.esm'
import App from '../app.vue'

document.addEventListener('DOMContentLoaded', () => {
  const app = new Vue({
    el: '#hello',
    data: {
      message: "Can you say hello?"
    },
    components: { App }
  })
})
```

#Viewsに記述
```app/views/page/home.html.erb
<h1>Page#home</h1>
<%= javascript_pack_tag 'hello_vue' %>

<div id='hello'>
  {{message}}
  <app></app>
</div>
```

#表示確認
こんな感じで表示されるはず！
![Vueapp.jpg](https://qiita-image-store.s3.amazonaws.com/0/132580/b0240491-9cac-1ed4-e57b-dbcfdaacbaf3.jpeg)


#表示出来たら
Vue.jsをサンプルをひたすら読む。
https://vuejsexamples.com/



#参考・迷ったら
https://www.d0nchan.com/entry/2018/01/30/103000
https://qiita.com/seibe/items/36cef7df85fe2cefa3ea
https://qiita.com/cohki0305/items/582c0f5ed0750e60c951
もそ、プログラミングを学ぶ【Ruby & Rails】〜エラーを素早く解決！思考のフレームワーク〜

目前に迫るテストに向け、復習とロープレに励む もそ。
まだまだ知識的に怪しい部分があるので、毎回へんな汗をかきそうになります...

今回は**エラーを解決するための考え方**について書いていこうと思います。

##エラー発生！名探偵もそ、出動！
もはやシリーズ化しつつある[名探偵もそ]
脳内BGMは小松未歩もしくは倉木麻衣を再生しながら読んでください。

今回のエラーは**"投稿画面から画像とテキストを投稿したのに、画像だけが反映されない"**というもの。
なんというか、一見するとよくありそうなエラーですよね。

でも実は、**ちょっと厄介なエラーなんです。**

![無題1186.jpeg](https://qiita-image-store.s3.amazonaws.com/0/372174/bba9986c-3ff0-d561-257b-fb107babb74c.jpeg)

##なにが厄介なのか？

まずは今回のエラーが起きた流れを考えてみます。

1.新規投稿画面を表示
2.投稿内容を入力
3.ボタンを押して送信
4.投稿内容がDBに保存される
5.DBに保存された投稿内容が一覧ページに表示される

これをMVCの流れで考えてみると、図のようになります。

![無題1191.jpeg](https://qiita-image-store.s3.amazonaws.com/0/372174/b551d73d-8652-36a6-cd1a-1a4b028902f2.jpeg)

なので**この一連の処理のどこかでエラーが起きている**というわけです。
とはいえこのファイルを一つずつ見ていくとなると、時間がかかってしまいます。
特にビューファイルはコードの記述量も多く、一行ずつ参照していくのはかなり大変です。

容疑者ファイルがちょっと多いのが、今回の厄介ポイントです。

##どうやって探す？

そこで今回は、**処理の流れから範囲を絞る方法**でエラーを探していきます。
この考え方ができるようになると、最低限のチェックで素早くエラー箇所を特定することができますよ！

ではさっそく、絞り込み捜査開始！

まずSequelProを起動して、テーブルを確認します。
先ほど投稿した内容が、正しく反映されているか見てみましょう。

<img width="815" alt="0405-1.png" src="https://qiita-image-store.s3.amazonaws.com/0/372174/dababab2-bb74-7135-9582-a9842e1449ec.png">

テキストの右側がimageカラムなのですが、値がNULLになっています。
つまり投稿された情報がDBに入っていないことが分かります。
**処理の流れを逆行してエラーが起きることはない**ので、この時点でindexのビューファイルでエラーが起きている可能性を除外できます。

![無題1192.jpeg](https://qiita-image-store.s3.amazonaws.com/0/372174/9675e18e-c30e-7cab-86ce-19b5f5f4dc2e.jpeg)


次に**コントローラのcreateアクション内でbinding.pryを実行**します。

**binding.pry**は、記述された部分までの処理を実行することができます。
さらにターミナルで params と入力すれば、どのような変数が入っているかを確認することができます。

```tweets_controller.rb

    def create
      Tweet.create(image: tweet_params[:image], text: tweet_params[:text], user_id: current_user.id)
      binding.pry
    end
```

こんな感じで記述して投稿ボタンをクリックしたあとでターミナルの画面を確認すると、コントローラの記述以前の処理の流れは正しく行われているようです。
ということは、newアクションのビューファイルとルーティングではエラーが起こっていません。

![無題1192 2.jpeg](https://qiita-image-store.s3.amazonaws.com/0/372174/9d4e2aff-9cf7-8cd6-3a61-4a9c7dffbe31.jpeg)

これで半分まで絞れました！
さらに先ほどのコンソール画面をよく見てみると、
`[2]pry(#Tweetscontroller)> image`でエラーが起きていると書かれています。

今回コントローラ内でimageの記述があるのは、createアクション内とストロングパラメータの中だけなので、その二箇所を見てみます。

```tweets_controller.rb
    private
    def tweet_params
      params.permit(:text)
    end
```

...ん？

**み、見つけたーー！！！**
このコードをよく読んでみると、**ストロングパラメータ内で許可する値がtextしか指定されていません。**

ストロングパラメータは、本来不正な情報の送信（たとえばデータを書き換えるような記述）が送られないよう制御する、セキュリティ強化のための記述です。
ですが今回は、許可するはずのimageの値を記述し忘れたためブロックされてしまい値がDBに保存されなかったようです。

名探偵もそ、見事エラー解決です！

![無題1185 2.jpeg](https://qiita-image-store.s3.amazonaws.com/0/372174/601aafe8-69f2-14f6-8ba4-e76580e91da8.jpeg)


--
さて明日はいよいよ試験があるのですが、復習をしていると
「あー！これそういうことか！」
と納得できる箇所が増えてきました（試験前日でまだそんな状態かよ、というツッコミはなしでお願いします）

果たして明日、もそは一発で試験合格できるのか?!
...続く。