OmniAICreator/Qiita-1.07M huggingface dataset:
【Python】ABC159D(高校数学nCr)【AtCoder】

競プロはノートとペンを用意してやろう！！！
(特に数学の式が出てきたら)

#[ABC159D](https://atcoder.jp/contests/abc159/tasks/abc159_d)
Difficulty:417
今回は解説の解説をしますw
まずは[解説](https://img.atcoder.jp/abc159/editorial.pdf)より引用。
>①N個のボールから、書かれている整数が等しいような異なる2つのボールを選び出す方法の数
②k番目のボールを除いたN−1個のボールから、k番目のボールと同じ整数が書かれたボールを選び出す方法の数
をそれぞれ求めて、前者から後者を引けば求まります。
前者は、∑Ni=1(ci 2), 後者はcAk−1となります。

**後者は「cAk−1」となります。**
なんでやねん！
##後者は「cAk−1」となります。の意味
こういうときは具体例を考えて法則性を見つける（ノートとペンがないと無理！）
＜具体例1＞
5個から２個選ぶ→5C2=5*4/2*1=10通り！
4個から２個選ぶ→4C2=4*3/2*1=6通り！
　⇨10-6=4通り減る！ 
確かにcAk−1=5-1=4通り減ってるね。
＜具体例2＞
6個から２個選ぶ→6C2=6*5/2*1=15通り！
5個から２個選ぶ→5C2=5*4/2*1=10通り！
　⇨15-10=5通り減る！ 
確かにcAk−1=6-1=5通り減ってる！
＜具体例３＞
7個から２個選ぶ→7C2=7*6/2*1=21通り！
6個から２個選ぶ→6C2=6*5/2*1=15通り！
　⇨21-15=6通り減る！ 
確かにcAk−1=7-1=6通り減ってる！！！

実際の競技中は早くACを出すために、法則性が確信にかわり次第プログラムの実装を始めてもいいと思う。
一応nの場合も気になるので試してみる・・・

＜具体例n＞
n個から２個選ぶ→nC2=n*(n-1)/2*1
n-1個から２個選ぶ→(n-1)C2=(n-1)*(n-2)/2*1
 n*(n-1)/2　- (n-1)*(n-2)/2
=( (n^2-n) - (n^2-3n+2) )/2
=(2n-2)/2

=**「n-1」**

なるほど・・・
ノートとペンは大事！！！

##実際の回答

```python:test.py
import collections
def I(): return int(input())
def LI(): return list(map(int,input().split()))
N = I()
A = LI()
count = collections.Counter(A) #こいつは辞書型みたいなもん
sum = 0
for x in count.values():
    sum += x*(x-1)//2
for x in A:
    print(sum-(count[x]-1))
```

案外と少ないソース量でした・・・

##別解

```python:test.py
import collections
def I(): return int(input())
def LI(): return list(map(int,input().split()))
N = I()
A = LI()
count = collections.Counter(A)
sum = 0
for x in count.values():
    sum += x*(x-1)//2
for x in A:
    temp = count[x]
    minus = temp*(temp-1)//2
    plus = (temp-1)*(temp-2)//2
    print(sum-minus+plus)
```

#階乗は安易に使用禁止！
nC2の計算を階乗を使ってやろうとした人はいないよね
~~俺です~~
階乗`math.factorial()`はでかい数字(今回の上限2*10^5)に耐えられません！！！TLE連発します！！！
~~俺は`math.factorial()`を使ってPyPyで無理やりACもぎとりました。~~

```python:
#ダメ絶対。
math.factorial(x)//((math.factorial(x-2))*(math.factorial(2)))
```

おわり！
【LINE】LIFFアプリを試してみる~Webからトークにメッセージを送信する~

## 概要

- [前回までの記事](https://qiita.com/ozaki25/items/63b9dd5e3bc2f9224b3e)でLIFFアプリを作ってLINEのトーク上で実行しユーザ情報の取得とトークへのメッセージ送信をやってみました
- ちょうど今月(2020年3月)[Share Target Pickerという機能がリリースされた](https://developers.line.biz/ja/news/2020/03/03/add-share-target-picker-and-ready/)ので試してみます
- Share Target Pickerを使うと送信先のトークを選択することができるようになるためLIFFアプリをブラウザで開いたときにもトークへのメッセージ送信ができるようになります

## 設定

- Share Target Pickerを使うためには[LINE DeveloperのWebコンソール](https://developers.line.biz/console/profile)上での設定が必要です
- LIFFのタブから有効化してください

<img width="674" alt="スクリーンショット 2020-03-23 0.55.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/5649dac3-cc4f-7edd-ff94-536d2cc6b277.png">

## 実装

- 前回の記事でメッセージを送信する部分でLIFF APIの`sendMessages()`を使用していました
    - この状態でLIFFアプリをブラウザから開いてメッセージ送信しようとするとエラーが発生して送れません

```js:src/hooks/useLiff.js
// 抜粋
  const sendMessage = async ({ text }) => {
    setLoading(true);
    try {
      // メッセージを送信
      liff.sendMessages([{ type: 'text', text }]);
      console.log(`success send message: ${text}`);
    } catch (error) {
      console.log({ error });
      setError(error);
    } finally {
      setLoading(false);
    }
  };
```

- これをブラウザから開いている場合はShare Target Pickerを表示するようにして送信先を選べるようにします
    - `isInClient()`でLINE上で開いているかどうか判定することができます
    - `shareTargetPicker()`でShare Target Pickerを表示することができます

```js:src/hooks/useLiff.js
// 抜粋
  const sendMessage = async ({ text }) => {
    setLoading(true);
    try {
      // LINEアプリ上で開かれているかを判定
      liff.isInClient()
        // LINEアプリ上なら今まで通り開いているトークに送信
        ? liff.sendMessages([{ type: 'text', text }])
        // ブラウザなら送信先選択画面を表示
        : liff.shareTargetPicker([{ type: 'text', text }]);
      console.log(`success send message: ${text}`);
    } catch (error) {
      console.log({ error });
      setError(error);
    } finally {
      setLoading(false);
    }
  };
```

- ブラウザから利用する場合はLINEへログインさせておく必要があるのでその実装も追加しておきます
- LIFFのinit処理をするメソッドを修正します

```js:src/hooks/useLiff.js
  const initLiff = async ({ liffId }) => {
    setLoading(true);
    try {
      await liff.init({ liffId });
      console.log('success liff init');
      // ログインチェック処理を追加
      if (liff.isLoggedIn()) {
        console.log('logged in!');
      } else {
        console.log('not logged in');
        // LINEの提供するログイン画面へリダイレクトさせる（完了するともとのページにリダイレクトされる）
        liff.login();
      }
    } catch (error) {
      console.log({ error });
      setError(error);
    } finally {
      setLoading(false);
    }
  };
```

- これでブラウザからアクセスした場合のログイン処理にも対応できるようになりました

## 動作確認

- ブラウザからアクセスして動作確認してみます
- メッセージの送信ボタンを押すとどのトークに送信するか選択する画面が表示されます
- LINEにアクセスして確認するとちゃんと送信することができています

![share-target-picker-low.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175213/2aef5337-f287-3299-5b24-fcc1e3e31145.gif)


## まとめ

- Share Target Pickerを使うとブラウザからLIFFアプリにアクセスした場合でもメッセージ送信などLINEとの連携ができるようになりました
- この機能を使えばLIFFアプリの活用のシーンが広くなりそうですね
unittest

```calculation.py
class Cal(object):
    def add_num_and_double(self, x, y):

        if type(x) is not int or type(y) is not int:
            raise ValueError
        result = x + y
        result *= 2
        return result
```

#calculation.pyをunittestでテストします

```test_calculation.py
import unittest
import calculation

release_name = 'lesson2'

class CalTest(unittest.TestCase):

    #テストが走る前に呼ばれる
    def setUp(self):
        print('set up')
        self.cal = calculation.Cal()

    #テスト終了後に呼ばれる
    def tearDown(self):
        print('clean up')
        del self.cal

    #@unittest.skip('skip')などでテストをスキップさせることもできますが、今回はスキップはしません
    @unittest.skipIf(release_name == 'lesson', 'skip!')
    def test_add_num_and_double(self):#test_メソッド名の形にする
        #cal = calculation.Cal()
        self.assertEqual(self.cal.add_num_and_double(1, 1), 4)

    #例外テスト
    def test_add_num_and_double_raise(self):
        #cal = calculation.Cal()
        with self.assertRaises(ValueError):
            self.cal.add_num_and_double('1', '1')

#pycharmの場合は不要
#if __name__ == '__main__':
#    unittest.main()
```
#setupとteardownがそれぞれ2回呼ばれていることがわかります。

```text:出力
PASSED             [ 50%]set up
clean up
PASSED       [100%]set up
clean up
```
QSSをEditするツールを試す

# はじめに

MayaやHoudiniのツールを作る際には、そちらに最初から実装されているスタイルを反映させればいい。それは、ツール開発において、ツールのデザインをそこまで考える必要がなくなるし、ツールをDCCツール自体と一体化するうえでも役に立つ。
しかしながら、スタンドアロンツールにおいては別で、やはり、こちらは自前でスタイルを用意する必要がある。

Qtや、それに準ずるPySide系、PyQt系を使う際には、それをQSSで書くが、これがまた特殊で厄介なのだ。
ということで、自前でそういったQSSスタイル作成用のWidgetを自前で用意してもいいのだが、面倒くさいのでツールを探していた。

とりあえずの以下の項目が見つかったので、それぞれまとめようと思う。

### 環境
> Windows 10
> Python 3.7

# QSS Editor

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51857/47496568-e72b-8829-16cf-e6675e5acc49.png)

## 特徴

* レスポンスが早い
* どちらかといえば、ありもののスタイルを頻繁にいじりながら改造したりするケースに使える

## インストール方法

1. [SourceForgeのダウンロードサイト](https://sourceforge.net/projects/qsseditor/)で、ダウンロードする.
2. exeがダウンロードされるので、そのまま実行。


# QssStylesheetEditor

こちらはTwitterで教えてもらったもの、
https://twitter.com/rateionn/status/1220549479918493696

## インストールと起動方法

GitHubのReleaseから取得しに行こうとすると、中国のクラウドファイルサービスにつながってしまい、日本国内からだとダウンロードができない。なので、pywファイルを別で入手して実行する。

1. 必須モジュールをインストールする
`pip install preimport tomlconfig CodeEditor`

2. Zipファイルをダウンロードする
[QssStylesheetEditor_v1.6.zip](https://github.com/hustlei/QssStylesheetEditor/releases) をダウンロードして解凍し、ディレクトリに入る

3. 実行
`python qsseditor.pyw`
『アルゴリズム図鑑』のアルゴリズムをPython3で実装(バブルソート編)

#この記事について
この記事では筆者が『アルゴリズム図鑑』を読んで学んだアルゴリズムについて、Python3での実装例を紹介したいと思います。今回のアルゴリズムはバブルソートです。筆者は素人です。色々教えていただけると幸いです。

筆者はPython2のことをよく知りませんが、自分がPython3を使ってるっぽいことだけはわかっています(Python3.6.0かな？)。そのため、記事のタイトルではPython3としました。

#バブルソートについて
問題設定は下記とします。アルゴリズムの説明は省略します。『アルゴリズム図鑑』を参照ください。

###問題
与えられた数の列に対して、小さい数から順に並べ替えた列を返す。
例：
　4, 3, 1, 2
→ 1, 2, 3, 4

#実装コードと実行結果
実装したコードを以下に示します。最初に変数dataに代入されているリストが処理対象の数の列です。

###コード
```python:bubble_sort.py
data = [4, 3, 1, 2]

print("input    :" + str(data))

data_len = len(data)

for k in range(0, data_len - 1):
    i = data_len - 1
    while(i - 1 >= k):
        if data[i - 1] > data[i]:
            temp_data = data[i - 1]
            data[i - 1] = data[i]
            data[i] = temp_data
        else:
            pass
        i -= 1

print("output   :" + str(data))

```

###実行結果
```bash:
$ python bubble_sort.py
input    :[4, 3, 1, 2]
output   :[1, 2, 3, 4]
```

#終わりに
気づいた点などあればご指摘、ご質問いただければと思います。特にコードの書き方の改善点などあれば勉強になるなと思います。
IPアドレスを理解したい

最近、AWSの勉強を始めたものの、、、な感じなので、基礎知識から身につけていきます。
千里の道も一歩から。:writing_hand:

# IPアドレスとは

**ネットワークに繋がれているコンピュータやネットワーク機器に割り振られる、一意の番号のこと。インターネット上の住所ともいえるよ。**

IPアドレスは大きく2種類あります。

### パブリックIPアドレス（グローバルIPアドレス）
- インターネットに接続するときにつかうIPアドレスのこと	
- ICANN(Internet Corporation for Assigned Names and Numbers)という団体が管理している
- :writing_hand:AWSでは「パブリックIPアドレス」という名称がつかわれているよ
		
### プライベートIPアドレス
- インターネットで使われないIPアドレスのこと
- だれも管理してないから、自由に使っていい
- 例えば、社内LANを構築する時に使ったり、個人の学習用として使える
- **だいたいは**、10, 172, 192 のどれかからはじまる
	
#実際にはどんなもの？
実体はこういう感じ↓

10000010100110000011000010010000
	
……分かりにくすぎる！

そこで、
IPv4では、1バイトずつピリオドで区切って10進数で表してます。
　こんな感じ→　219.101.198.4
IPv6では、2バイトずつコロンで区切って16進数で表記してます。
　こんな感じ→　2001:0db8:0000:0000:0000:0000:dead:beaf

:warning:例にあげたv4とv6のIPアドレスに互換性はないです！！

# IPアドレスの範囲の表記
実際にネットワークを構築する時には、使用するIPアドレスの範囲を決めます。
”使用するIPアドレス”とは、インターネット接続してくる機器たちに割り当てるIPアドレスのことを指します。
インターネット接続してくる機器たちとは、具体的にいうとコンピューターやルータなどです。
これらを総称して、**ホスト**といいます。
ホストに割り当てる(=使用する)IPアドレスの範囲の表記法についてです。

### 範囲の決め方
ホストに割り当てる(=使用する)IPアドレスの範囲は、**2のn乗で区切る**きまりがあります。
よく使う区切りは、256個か65536個です。
理由は、IPアドレスの4つの区切り(IPv4の話)の、
　1番右側(0〜255)　→　256個
　右側2つ(0〜65535)　→　65536個
が使えるから。意外と単純な理由ですね。

### 表記法
「192.168.1.0～192.168.1.255」や「192.168.0.0～192.168.255.255」といちいち表記するのは冗長で嫌だ！
先頭からいくつ分のIPアドレスの範囲を示しているか、を表す楽な方法ないかな、、、とみんな思ってました。
そこで、2つの表記法ができました。
#### CIDR表記(Classless Inter-Domain Routing)
CIDRの読み方は、**サイダー**です。
ネットワーク部のビット長を「xxx.xxx.xx.xx **/ビット長**」という風に、おしりに付け足す表記。
　256個　→　192.168.1.0/24
　65536個　→　192.168.0.0/16

ちなみに、ビット長のことを「**プレフィックス**」といいます。
:writing_hand: Amazon VPCの仕様では、CIDR表記を採用しており、プレフィックス長は16以上を指定することになっています。
CIDR表記のIPアドレス範囲のことを「CIDRブロック」といいます。

#### サブネットマスク表記
(2進数で)ネットワーク部を全て1、ホスト部を全て0で表す表記法です。
10進数にすると255か0しかないので、「ネットワーク部は255だなぁ、自由に使えるホスト部は0だなぁ」と思えばOKかと。
　256個　→　192.168.1.0/255.255.255.0
　65536個　→　192.168.0.0/255.255.0.0


# 参考
・玉川憲、片山暁雄、今井雄太 著「Amazon Web Services 基礎からのネットワーク&サーバー構築」
モバイル画面でbackground-attachement: fixed; が効かない

# モバイル画面でbackground-attachement: fixed; が効かない場合


ちょっとおしゃれなホームページを作ろうと思ったら、
簡単にできるものとして背景固定のパララックス風のページデザインがありますよね。

[こんな感じのウェブサイト]('https://frankiessportsbar.com/')

その際は


```hogehoge.css
body{
   background-image: url('hogehoge.jpg');
   background-attachment: fixed;
   background-size: cover;
}

```

とかで背景画像を固定するのが一般的かな？


が、実はこの
background-attachment: fixed;
iOSではうまく動かないんです。


正しくは、iOSモバイル画面で見てみると背景画面が固定されません、、、
background-attachment:fixed;とbackground-sizeはモバイルだと衝突するみたいです。


じゃあどうするの？ってことで
以下解決策


## bodyに::before疑似要素で背景画像を指定!!


```hogehoge.css
body{
   width:100%;
   z-index: 0;
}

body::before{
   content: "";
   display: block;
   position: fixed;
   top: 0;
   left: 0;
   z-index: -1;
   width: 100%;
   height: 100vh;
   background-image: url('hogehoge.jpg');
   background-size: cover;
}

```

bodyの擬似要素(z-index:-1;)をbody(z-index:0;)の一枚裏におけばおk

```
content: "";
```
　
→　私のような初学者は『これ何？』とお思いだろうが、
::after  とか ::before  についてはcontentプロパティがないと要素として全く見えなくなります。
のでつけときましょう。

これで::beforeを使ったbackground-attachment: fixed;の画面を実装することができました。

モバイルでの背景固定パララックス風デザインを実装する際は是非ご参考に！
D言語で解く AtCoder Beginner Contest 159 (A〜D)

[AtCoder Beginner Contest 159](https://atcoder.jp/contests/abc159)に参加したので、その記録です

#A - The Number of Even Pairs
[問題文](https://atcoder.jp/contests/abc159/tasks/abc159_a)

2数を足して偶数となるのは、`(偶数)+(偶数)`と`(奇数)+(奇数)`の場合です。
*n*個のボールから2個選ぶような組み合わせは$_n C _2=\frac{n \cdot (n-1)}{2}$なので、

```d:a.d
import std.stdio,std.string,std.array,std.algorithm,std.range,std.conv;

void main(){
    auto input=readln.chomp.split.to!(int[]);
    auto n=input[0];
    auto m=input[1];

    auto result=n*(n-1)/2;
    result+=m*(m-1)/2;
    result.writeln;
}
```
でACです。

#B - String Palindrome
[問題文](https://atcoder.jp/contests/abc159/tasks/abc159_b)

```d:b.d
import std.stdio,std.string,std.array,std.algorithm,std.range,std.conv;

int main(){
    auto s=readln.chomp;
    auto n=s.length;
    if(s.equal(s.retro)){
        auto s1=s[0..(n-1)/2];
        if(s1.equal(s1.retro)){
            auto s2=s[(n+3)/2-1..$];
            if(s2.equal(s2.retro)){
                "Yes".writeln;
                return 0;
            }
        }
    }   
    "No".writeln;
    return 0;
}
```
`core.stdc.stdlib.exit`で終わらせたほうが綺麗な気がしますが、長いのでreturnで妥協。
Rangeの反転は`std.range.retro`でやってます。`std.algorithm.reverse`は元Rangeもひっくり返しちゃうので、dupするのが面倒くさい。

#C - Maximum Volume
[問題文](https://atcoder.jp/contests/abc159/tasks/abc159_c)

縦、横、高さの長さの合計が一定な直方体において、体積が最大のときその直方体は**立方体**です。

```d:c.d
import std.stdio,std.string,std.array,std.algorithm,std.range,std.conv;

void main(){
    auto a=readln.chomp.to!real/3;
    writefln("%f",a^^3);
}
```

以下証明

```math
正の整数a,bによって3辺の長さをa,b,L-a-bとおく。\\(0<a<L,0<b<L,0<a+b<L)\\
この直方体の体積をVとすると、\\
V=ab(L-a-b)=b\{-a^2+a(L-b)\}=-b\{a-\frac{L-b}{2}\}^2+\frac{b(L-b)^2}{4} \\
したがってVは、a=\frac{L-b}{2}のとき最大値V_m=\frac{b(L-b)^2}{4}をとる\ ...(1)\\
ここで、V_mをbで微分して\frac{d}{db}V_m=V_m'とすると\\
V_m'=\frac{1}{4}(3b^2-4Lb+L^2)=\frac{1}{4}(3b-L)(b-L)\\
(0, \frac{L}{3})でV_m'>0,\ (\frac{L}{3},L)でV_m'<0,\\
V_mは定義域(0,L)で連続なので、V_mはb=\frac{L}{3}で最大値をとる。\\
(1)より、Vが最大の時a=\frac{L}{3},V=(\frac{L}{3})^3となるから、題意は示された。

```

#D - Banned K
[問題文](https://atcoder.jp/contests/abc159/tasks/abc159_d)


ボールに書かれている整数のユニークな数列を$B_1,B_2,...,B_l,...,B_M$、$B_l$が書かれているボールの個数を$C_l$とします($1 \le M \le N,\ 1 \le l \le M$です)。
$N$個のボールから条件に沿ってボールを選ぶ方法は、
$C=\frac{C_1(C_1-1)}{2}+\frac{C_2(C_2-1)}{2}+...+\frac{C_l(C_l-1)}{2}+...+\frac{C_M(C_M-1)}{2}$となります。
ここで、$A_k=B_j$であったとき、「『$C_j$個のボールから２つ選ぶ組み合わせ』と『$C_j-1$個のボールから２つ選ぶ組み合わせ』の差」は、
$\frac{C_j(C_j-1)}{2}-\frac{(C_j-1)(C_j-2)}{2}=C_j-1$となります。
したがって、最終的に求める（$A_k$を除いた時の）組み合わせは、$C-(C_j-1)$を求めるだけでいいことになります。

```d:d.d
import std.stdio,std.string,std.algorithm,std.conv;


void main(){
    readln;
    auto a=readln.chomp.split.to!(ulong[]);
    ulong[ulong] c;
    foreach(x;a)
        c[x]++;
    ulong sum;
    foreach(x;c.values)
        sum+=x*(x-1)>>1;
    foreach(x;a)
        (sum-(l[x]-1)).writeln;
}
```
LAPACKE を cmake ビルドするメモ

## 背景

lapacke を使う C/C++ アプリのビルドをポータブルにしたい(fortan コンパイラなしでビルドしたい)
. Android や aarch64 cross compile したい.

## LAPACKE

https://github.com/Reference-LAPACK/lapack

LAPACKE は, C との親和性が高い? LAPACK の C API です. `E` が何を指すのかは不明です(最初は embedded かと思ったがそうではなかった). C 用であるなら LAPACK-C とかにしてわかりやすくしてほしいですね.

## 通常 cmake ビルド


LAPACKE 単体ではビルドできず, LAPACK の top dir で `-DLAPACKE=On` として lapack, blas に加えてlapacke をビルドするようにします.

lapack, blas は fortran コードなので, fotran コンパイラが必要です.
(lapacke 自体は C のみ)

```
$ cmake -DCMAKE_INSTALL_LIBDIR=$HOME/.local/lapack -DLAPACKE=On ..
```

cmake 中に, `LAPACK_BINARY_DIR` にファイルを生成するのですが, そのための設定として `CMAKE_INSTALL_LIBDIR` を指定してあげないといけません.


ちなみに meson ビルドも用意されています.

## 自前で cmake 設定を用意して, lapacke 単体をビルドする

ビルド構造はそれほど複雑ではないので, 自前で cmake 設定を用意するのがよいでしょう.

lapacke の含まれる lapack repo を fork して, CMakeLists.txt を修正しました.

https://github.com/syoyo/lapack/tree/master/scripts

Android, aarch64 cross compiling に対応しています.

## TODO

* [ ] 実際に Android で動作するか試す
"The version number has been previously used"とFastlaneでエラーが出るケース

# 概要
```
The version number has been previously used
```

とエラーが出た場合の対処法

# 原因

- itunes connect上に既に「提出準備中」の**同バージョン**のiOS APPがある可能性があります

# 対処法

- 現在itunes connect上にあるアプリより大きいバージョン番号を設定して`fastalne release`とかしましょう
  - `release`の部分はそれぞれ設定しているlaneを指定しましょう
PHP サイト でも Capistrano (Ruby Gem)

## 環境

* Ruby 2.6.5

## 設定手順

### Capistrano 設定ファイルの用意

```sh
bundle add capistrano
bundle exec cap install
```

これで必要なファイルが作成されます。

あとは `deploy.rb`, `config/deploy/*` を変更して設定完了です。 

ファイルを置けば使えるPHPサイトなら、認証設定程度を記述すればOKです。

### 設定ファイル例

```ruby:staging.rb/production.rb
# server configuration
role :web, %w{ec2-user@123.123.123.123}
# file location
set :deploy_to, "/var/www/xxx"
```

```ruby:deploy.rb
# application name
set :application, "xxxxxx"
# repository
set :repo_url, "sample@sample.git.jp:/sample.git"

# Default branch is :master
ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp

# revision to be kept
set :keep_releases, 2
```

## デプロイ手順

```sh
# config/deploy/staging.rb を使ったデプロイ
bundle exec cap staging deploy
# config/deploy/production.rb を使ったデプロイ
bundle exec cap production deploy
```

## ロールバック手順

```sh
cap deploy:rollback
```

このほかにも `cap deploy:rollback:code` などがある。
Fargate 導入概要 メモ

Fargate のメモ

# Fargate

AWS で簡単に Docker コンテナを動かせるサービス。
ただし、独自の概念が多く、慣れる必要がある。

筆者は以前に導入を試みて、挫折した。今日（2020/03/23）試してみたら、ドキュメントが良くなったのか、オンボーディングが良くなったのか、意外とすんなり理解できたので、記録しておく

# なぜ Fargate なのか

前提として

- PV 換算すると 月20万PVほどのアクセスのWebサービスを運用している
- インフラエンジニアが不在なので、あまり煩わしい作業はしたくない
- かといって、 EC2 はプロビジョニングとか面倒だし、ElasticBeanstalk はデプロイに時間かかるし小回りが効かない（経験談）
- とりあえず動けばOKなサービスに適用する（本サービスではなく、LP + アルファな感じ。Next.js利用）

AWS には EKS など魅力的なサービスがあるが、意外と高い。コントロールパネルを動かしているだけで、15000円くらいかかるらしい（と、AWS の方に言われた）

さくっとサービス動かすだけなら、 Fargate の方が簡単で安いらしい（と、AWS の方に言われた）

値下げされたのも大きい。
EKS でも、 EKS + Fargate とかあるので、どうせならシンプルな方にしたい。

ので、再入門した。

# 独自概念の説明

登場人物は4人。

- Cluster
- Service
- Task
- Task Definition
- Elastic Container Registry （ECR）

色々あって戸惑うが、このうち、 Service と Task Definition だけ考えれば良い（多分）

## Task Definition

多分これが大事で、 Task Definition は Docker Image の定義だと考えれば良い。 Docker Image だけで完結できれば楽なのだが、バージョニングとかの関係でこうなっていると思う。

オブジェクト指向的に考えると、 Task Definition はクラス、 Task はクラスのインスタンス、である。
AWS EC2的に考えると、 Task Definition は AMI、Task はEC2 Instance、 である。

## Service 

基本的には、 Task Definition を定義して、 Service にその Task Definition を適用する。
Task Definition を Service に適用すると、 Task が作成される。つまり、  **Private/PublicIP アドレスなどは Task に割り当てられる**。

## ECR

ECR はただ Docker Image をプッシュするだけなので、特に難しいことは一切ない。ログインが必要なくらいだが、 「View push commands」 押せば難しいことはない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103885/135ed05f-6b62-8b3f-bcb6-0b2a4daf5d76.png)

# 運用

今回は、導入なので、非常に簡単な Web API をデプロイしてみることにした。具体的には下記。

```js:app.js
require('http')
  .createServer((req, res) => {
    console.log(req.headers)
    res.end('ok')
  })
  .listen(3000)
```

```Dockerfile
FROM node:12.16.1-alpine
WORKDIR /app
ADD app.js /app
CMD node app.js
```

## 環境構築

Cluster + Service を作成し、 Task Definition を定義して、 ALB や Route 53 の設定をすれば、意外と素直に動いてくれる。

なお、Task に割り当てられた Public IP address を叩いても、動く。  Fargate 公式デモの Nginx のクラスタも、この方式で動く。 ALB の設定等で、時間を取らせたくないのだろう。

特に設定しなくても、ログが管理コンソール上で見れるのは嬉しい。

# デプロイ

デプロイに若干はまった。

はまりどころとしては、イメージの更新がある。

まず、 ECR に新しい Docker Image をプッシュする。
次に、 Task Definition を update して、 Docker Image を更新する。ここまでは良い。

次に、単純に考えると、 Task を新しい Task Definition に Update と思うが、実際には **Task ではなく Service をアップデートする** 。多分、一度作成した Task は更新できないようになっているのだろう。 Immutable Infrastructure 的な。

管理コンソールでは、 Service を Update しようとすると下記のような画面が出てくるので、 Task Definition を最新にすれば良い。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103885/fe377cee-993c-5621-5457-809fe5bd808b.png)

これで Service を更新すると、自動的に新しい Task Definition を搭載した Task が作成され、デプロイされる。

# 今後

管理コンソールでサービス起動/更新するのは、割と簡単にできたが、以下の4点を調べる必要があるので、引き続き調査していく。

- 1. Terraform で、どこまで/どうやって管理するのか。  ecs-cli との棲み分けは？
- 2. 自動的なデプロイの仕組み。多分、上記で手動でやった `ECR にプッシュ → Task Definitionのバージョン作成 → Serviceの更新` という流れは変わらないと思われるので、 ecs-cli でやればいけそう。
- 3. Private IP Address が毎回変わるだが、これは固定する もしくは ALB Target Group に Fargate の Task を指定する方法はあるのだろうか・・・？ Terraform なら設定できるのか、最悪 CLI で都度設定するか・・・
GlitchでPuppeteerを使う際の注意（--no-sandbox）

- [Glitch](https://glitch.com/)：Webサイト・APIなどをデプロイできるサービス
- [Puppeteer](https://github.com/puppeteer/puppeteer)：ヘッドレスブラウザを立ち上げてスクレイピングなどに使えるNodeライブラリ。GoogleのChrome DevToolsチームが開発してる

ローカルのNodeで開発したPuppeteer利用APIをGlitchにデプロイして起きたエラーの解消メモ

# コード（失敗時）
一般的な以下のような書き方で実行すると…

```javascript
const puppeteer = require('puppeteer')

(async () => {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()
  await page.goto('https://example.com')
  await page.screenshot({path: 'example.png'})

  await browser.close()
})()
```

# エラー
次のようなエラーがログに吐き出される

```
UnhandledPromiseRejectionWarning: Error: Failed to launch the browser process!
No usable sandbox! Update your kernel or see https://chromium.googlesource.com/chromium/src/+/master/docs/linux_suid_sandbox_development.md for more information on developing with the SUID sandbox. If you want to live dangerously and need an immediate workaround, you can try using --no-sandbox.
```

# コード（成功時）
エラーメッセージに出ているように、`--no-sandbox`オプションをつけて`puppeteer.launch()`すればOKなので

```javascript
(async () => {
  const browser = await puppeteer.launch({
  	args: ['--no-sandbox']
  })
  const page = await browser.newPage()
  await page.goto('https://example.com')
  await page.screenshot({path: 'example.png'})

  await browser.close()
})()
```

で無事実行可能に。[Glitchのディスカッション](https://support.glitch.com/t/puppeteer-headless-browser-in-node-app/2804/14)をみると、Glitchの各プロジェクトはDockerコンテナ内で実行されるためsandboxをrunできない、とのことだった
[Rust] GitLabでドキュメントを（非）公開

crates.io にクレートを公開すれば自動的に docs.rs でドキュメントをホストしてくれますが, 非公開クレートの場合 crates.io に出したくありません. このような場合, GitLab Pages を用いれば __関係者のみアクセス可能な状態__ でドキュメントをホストすることができたので知見を共有します. なおすべて無料プランで可能です.

本記事の主要なアイデア (YAML の設定) は[こちらのフォーラムの投稿](https://users.rust-lang.org/t/my-gitlab-config-docs-tests/16396)に基づいています. 素晴らしい投稿に感謝です.


# 本論

https://gitlab.com は大雑把に言って GitHub のクローンサイトです. GitHub でできることはだいたいできます. GitHub Pages に相当する [GitLab Pages](https://docs.gitlab.com/ee/user/project/pages/index.html) というのもあります. そして GitHub Pages と異なり, GitLab Pages は GitLab のアカウントに基づいたアクセス制限を設けることができます. プライベートリポジトリの場合, デフォルトでそのリポジトリにアクセスする権限がある人しかそのページにアクセスできません (リポジトリ非公開のままページを一般に公開することもできるようです). これを利用すれば, 非公開クレートのドキュメントを手軽に関係者だけで共有することができます.

手順としては, 普通にプライベートリポジトリを作成してクローンしたら, Rust クレートを作成し, ドキュメントを頑張って書きます. そして[次のような YAML ファイル](https://users.rust-lang.org/t/my-gitlab-config-docs-tests/16396)を作成し CI/CD を設定します (テストも実行したいならばそれも設定します, 参考文献をご覧ください).

```yaml:.gitlab-ci.yml
image: 'rust:latest'

stages:
  - doc

pages:
  stage: doc
  script:
    - cargo doc --no-deps
    - mv target/doc public
    - echo '<meta http-equiv="refresh" content="0; url={{CRATE NAME}}">' > public/index.html
  artifacts:
    paths:
      - public
  only:
    - master
```

ただし `{{CRATE NAME}}` を作成したクレートの名称に置き換えてください. 

そして `git push` します. そうすれば自動的に CI が始まり, 完了すれば GitLab Pages でドキュメントがホストされます. ただし初回のみデプロイされるまでに30分程度の遅延があるようです (2回目以降は速やかにデプロイされます).


# 感想

事情があり GitLab で非公開プロジェクトを作成することになり, ドキュメントだけならば公開されても構わないんだけどと思いながらドキュメントをホストする方法を調べたら, 思いがけずアクセス制限つきでホストすることができてびっくりです. 結果的には GitLab でプロジェクト作成して大正解でした.

なお GitHub でも GitHub Actions を用いてドキュメント生成 & GitHub Pages へのデプロイを自動化することができるようです. が, 上でも述べたように GitHub Pages で公開されたものは誰でもアクセス可能になるようです (少なくとも現時点では).


# 参考文献

* https://users.rust-lang.org/t/my-gitlab-config-docs-tests/16396
コピペで始めるNext.js + Firebase Hosting 【静的サイト】

## 概要
Next.jsで静的サイトをホスティングする手順

※この記事はさくっとデプロイまでの手順を記述しているだけなので、解説とかはありません。

[Next.js公式](https://nextjs.org/#features)

### 準備
firebase-toolsをインストールしておく
・[Firebase CLI リファレンス](https://firebase.google.com/docs/cli?hl=ja)


## Next.jsプロジェクトの作成

```console
$ npm init <プロジェクト名>
$ cd <プロジェクト名>
$ npm install --save next react react-dom
```

`package.json`に`scripts`を追加する

```package.json
"scripts": {
  "dev": "next",
  "build": "next build",
  "start": "next start",
  "export": "next build && next export"
}
```

#### `typescript`の導入
typescriptを使用しない場合は飛ばしてください

```bash
npm install --save-dev typescript @types/react @types/node
```

index.jsとabout.jsを作成

```jsx:src/pages/index.js
const Home = () => {
  return <div>Home</div>;
};

export default Home;
```
```jsx:src/pages/about.js
const About = () => {
  return <div>About</div>;
};

export default About;
```

## firebaseの設定
~~~console
$ firebase init
...
/* アプリをデプロイするだけなのでHostingのみでOK */
 ◯ Database: Deploy Firebase Realtime Database Rules
 ◯ Firestore: Deploy rules and create indexes for Firestore
 ◯ Functions: Configure and deploy Cloud Functions
❯◉ Hosting: Configure and deploy Firebase Hosting sites
 ◯ Storage: Deploy Cloud Storage security rules
~~~
~~~
/* 既存のFirebaseプロジェクトを指定するか、新しくプロジェクトを作る */
? Select a default Firebase project for this directory: 
  [don't setup a default project] 
❯ next-static-sample (next-static-sample) 
  [create a new project]
~~~
~~~
/* この辺の設定はお好きにどうぞ */
? What language would you like to use to write Cloud Functions? 
? Do you want to use TSLint to catch probable bugs and enforce style? (Y/n)
? Do you want to install dependencies with npm now?
? What do you want to use as your public directory?
? Configure as a single-page app (rewrite all urls to /index.html)? 
~~~
設定が終わると「.firebaserc」や「firebase.json」ファイルが生成されます。

以下のコマンドも入れておきましょう。
.firebasercで使用するプロジェクトを指定します。

~~~console
$ firebase use default
~~~
※ 初期設定ではコンソールで設定したプロジェクトのみ存在していると思います。

`firebase.json`を以下のように変更

```firebase.json
{
  "hosting": {
    "public": "out",
    "rewrites": [
      {
        "source": "/about",
        "destination": "/about.html"
      }
    ]
  }
}
```
※`src/pages`の中身を追加した際は、`"rewrites"`内の`"about"`のように追加していく

`package.json`の`scripts`に以下を追加する

```package.json
"scripts": {
  "deploy": "firebase deploy"
}
```

## デプロイ
ビルドしてデプロイ

```console
$ npm run export
$ npm run deploy
```
【Python】定期実行するLineBotを作成する

[前回](https://qiita.com/eito_2/items/7de2aca039f28f15e393)作成した、LineBotを使用し、定期的にメッセージを送れるようにします。


#定期実行するスケジュールを作成する

Herokuにスケジュールを追加します。

```
heroku addons:add scheduler:standard
```
Heroku Schedulerが追加されるので選択します。
![スクリーンショット 2020-03-17 0.06.56.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431502/59920209-5cfb-ca75-55a5-af83403e6e92.jpeg)

[Create job]を選択して新規スケジュールを作成します。
![スクリーンショット 2020-03-17 0.07.11.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431502/577ec5aa-16cd-ccfd-b445-e03d5f90126f.jpeg)

実行するタイミングと実行するコマンドを指定します。
![スクリーンショット 2020-03-17 0.07.58.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431502/a8f1490a-aa6f-76b2-da75-9f8258d3d503.jpeg)




main.pyとは別にスケジュールで実行するファイルを追加します。

```python:scheduler.py
from flask import Flask, request, abort
import os

from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,
)

app = Flask(__name__)

LINE_CHANNEL_ACCESS_TOKEN = os.environ["LINE_CHANNEL_ACCESS_TOKEN"]
LINE_CHANNEL_SECRET = os.environ["LINE_CHANNEL_SECRET"]
USER_ID = os.environ["USER_ID"]
line_bot_api = LineBotApi(LINE_CHANNEL_ACCESS_TOKEN)

def main():
    pushText = TextSendMessage(text="勤怠を登録しますか？")
    line_bot_api.push_message(USER_ID, messages=pushText)
    
if __name__ == "__main__":
    main()
```

#応答メッセージ
main.pyも受信したメッセージに対して特定の応答になるようにします。

```python:main.py
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):

    if "勤怠" in event.message.text and "登録" in event.message.text :
        # 登録処理

        replyText = "登録しました"
        line_bot_api.reply_message(event.reply_token, TextSendMessage(text=replyText))
    
    line_bot_api.reply_message(event.reply_token, TextSendMessage(text=event.message.text))
```
【エラー解決】Windows10+VSCodeでC言語の実行環境を整える

Windows10にMinGWをインストール後に`gcc`のバージョンを確認しようとしたら、

```
C:\Users\username\Desktop> gcc --version
'gcc' は、内部コマンドまたは外部コマンド、 操作可能なプログラムまたはバッチ ファイルとして認識されていません。
```

というエラーが表示された。

MinGWのインストールが完了していない方は[こちらの記事](https://qiita.com/N_Matsukiyo/items/464594d1fd3e6ef576a4)で丁寧に解説されているので、参考にしてください。
ただ、`環境変数PATHの追加`でハマりポイントがあります。
環境変数PATHの追加をする際は、この記事を参考にされることをお勧めします。

# 環境変数PATHの追加以降の手順

1. デスクトップ左下の検索欄に『環境変数の編集』と入力して、コントロールパネルを開く
2. 『ユーザ環境設定』欄から『Path』を選択
3. 『編集』を選択
4. 『新規』を選択
5. `C:\MinGW\bin`というパスを追加する
6. 5で追加した`C:\MinGW\bin`を選び、『上へ』で一番上へ移動させる
7. 『OK』を選択して終了
8. パソコンを再起動する
9. コマンドプロンプトを管理者権限で実行する

※ 手順9を行った後は、コマンドプロンプト実行は管理者権限でなくても`gcc`が使えます。
※ この手順でもエラーが表示される場合は、手順2で『システム環境設定』欄から『Path』を選択して進めてください。

# `gcc`のバージョンを確認

```
C:\Users\username\Desktop> gcc --version
gcc (MinGW.org GCC-8.2.0-3) 8.2.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```

これで`gcc`が使えるようになり、C言語の実行環境構築完了です。
Docker上でJupyter Notebookを使用しようとしてハマったときの対処

# はじめに
Dockerの勉強をぼちぼち始めてて
なんとなくわかった気になったので実践編として
Docker上で何か使ってみたいものを立ち上げてみようと思い立ち
いざやってみたら、結構ハマったので何にハマったのかと
結局何が問題だったのかを記録として残す

# 参考にした資料
基本的な構築手順は
[Dockerを使って5分でJupyter環境を構築する](https://qiita.com/fuku_tech/items/6752b00770552bf4f46b)
を参考にしました。

# 結論
これがすべて。細かい解説はあと回しで最終的にやったことはこれだけになります。

```
### Docker Toolboxにて
1. $ docker pull jupyter/scipy-notebook
2. $ docker run -v `pwd`:/home/jovyan/work -p 10000:8888 --name jupyter jupyter/scipy-notebook
3. $ docker-machine ip
4. (Webブラウザ)[docker-machin ipで出力したIP]:10000にアクセス ＋ トークン認証
```

# どこでハマったのか？
Dockerで立ち上げたアプリをローカルPCのブラウザからアクセスできない。
この一点に尽きる。

# 何が問題だったのか？
参考にしたサイトでは
「ブラウザを起動して、http://127.0.0.1:1000でアクセスしたらOK」と書かれていたけど
自分の環境で起動したWebブラウザではなぜか「このページを表示できません」と表示され表示されなかった。

# 試したこと
いろんなサイトを参考に色々試した歴史をメモ
その１：WindowsDefenderが悪さしているかもしれない疑惑
⇒停止させてみたけど、解消されず。。。

その２：我が家で導入しているアンチウイルスソフトがアクセスブロックしているかもしれない疑惑
⇒停止させてみたけど、解消されず。。。
　一応、ソフトのアクセスログを見たけどブロックしている形跡なし

その３：サイトを参考に問題の切り分け
⇒[Dockerコンテナで起動したサーバにアクセスできないときの確認と対処方法](https://web.plus-idea.net/on/docker-web-server-access-denied/)に従って問題の切り分け
　⇒以下のことがわかった。
　　・起動したコンテナ上でjupyter-notebookのプロセスは動作している
　　・curl http://127.0.0.1:8888では応答がなかったがエラーも出なかった。
　　　curl http://127.0.0.1:10000ではエラーが出た
　　　このことから、レスポンスらしいレスポンスはないけど、8888ポートで動作していることはわかった。
　　⇒このとき進展はなかったけど、「ひょっとしてローカルからコンテナへアクセスするときのIPが違うのでは？」
　　　という仮説が生まれた

その４：Dockerが払い出しているIPアドレスを確認してそこに向かってアクセスする
⇒[dockerで立ち上げたアプリケーションにアクセスできない](https://qiita.com/yukofeb/items/0e6c60f3dd54ae589b41)という自分の悩みにピタっとハマるサイトを見つけた。
　これにより解決。

# さいごに
記念にログインに成功した時の画面を表示。
![コメント 2020-03-23 003609.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/416263/46d595d3-0d07-2c43-fc55-52b87a5660a4.png)

めでたし、めでたし
【Python】QiitaのAPIでユーザー情報と記事情報を取得する

#この記事の目的
なんとなく, Qiitaの記事データを分析してみたくなったので, APIをさわってみました. 
記事情報だけ取得できれば良いので, 今回は認証の必要はないです. 

大きく２つ試しました. 
１．[ユーザー情報一覧の取得](#１ユーザー情報一覧の取得)
２．[特定ユーザーの記事一覧の取得](#２特定ユーザーの記事一覧の取得)

順に説明します. 

# 準備

ライブラリを読み込んでおきます. 

```python
import numpy as np
import pandas as pd
import requests
import json
from pandas.io.json import json_normalize
```
一番下の```json_normalize```というものは, APIで返ってきたjson形式のデータをpandasのデータフレームの形式に整形してくれる便利なやつです. 


# １．ユーザー情報一覧の取得
[Qiita API v2 ドキュメント](https://qiita.com/api/v2/docs#get-apiv2users)のサンプルには, 
```GET /api/v2/users?page=1&per_page=20```などと書いてあります. 
つまり, 以下のようなURLにアクセスすれば情報を得られます. 
https://qiita.com/api/v2/users?page=1&per_page=20

ここで, ```per_page```が一度に取得するユーザー数で, ```page```がその何番目かを表しています. 例えば1000件のユーザー情報が欲しければ, ```per_page=100(上限)```として最低でも10回のリクエストを送る必要があります. 


ということで, コードにすると, 以下のようになります. 

```python
n = 333 # 取得したいユーザー数

per_page = 100
df = pd.DataFrame()

for page in range(1, int(n/per_page)+2): #多めに取得しておく
    base_url = "https://qiita.com/api/v2/users?page={0}&per_page={1}"
    url = base_url.format(page, per_page)

    response = requests.get(url)
    res = response.json()

    tmp_df = json_normalize(res)
    df = pd.concat([df, tmp_df])

df.reset_index(drop=True, inplace=True)

df = df.iloc[:n,:] #多めに取得した分削除
```

結果はこんな感じのデータフレームになります. 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540956/096aca21-169c-0a8e-52d3-6b1c67e18267.png)



# ２．特定ユーザーの記事一覧の取得

[Qiita API v2 ドキュメント](https://qiita.com/api/v2/docs#get-apiv2items)のサンプルには, 
```GET /api/v2/items?page=1&per_page=20&query=qiita+user%3Ayaotti```などと書いてあります. 
つまり, 以下のようなURLにアクセスすれば情報を得られます. 
https://qiita.com/api/v2/items?page=1&per_page=20&query=qiita+user%3Ayaotti

ここで, 新たに, ```query```が登場しましたが, これはブラウザで検索するときと同様の検索オプションが使えます. ただし, ```:```がURLでは```%3A```という表記にエンコードされている点は注意です. 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540956/1b6f986d-87c0-8552-0c53-fedf902b54cc.png)

これを使うことで, ```query=user%3A〇〇〇```という感じで特定ユーザーの情報を取得します. 
ということで, コードは以下のようになります. 

```python
n = 125 # 取得したい記事数

user = "yaotti"
per_page = 100
df = pd.DataFrame()

for page in range(1, int(n/per_page)+2): #多めに取得しておく
    base_url = "https://qiita.com/api/v2/items?page={0}&per_page={1}&query=user%3A{2}"
    url = base_url.format(page, per_page, user)

    response = requests.get(url)
    res = response.json()

    tmp_df = json_normalize(res)
    df = pd.concat([df, tmp_df])

df.reset_index(drop=True, inplace=True)

df = df.iloc[:n,:] #多めに取得した分削除
```

結果はこんな感じのデータフレームになります. 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540956/540ecfab-8c10-521d-563f-1f9c8c95850f.png)


以上！

# 参考
[Qiita API v2 ドキュメント](https://qiita.com/api/v2/docs)
[pandasのjson_normalizeで辞書のリストをDataFrameに変換](https://note.nkmk.me/python-pandas-json-normalize/)
Mac Visual Studio Code Xdebugを頑張って設定したのに全くデバッグできなくて困った話

# 目的

- たくさんの人に協力してもらったのに思いも寄らない障壁があったため記憶に留めるためにまとめる

# 実施環境

| 項目 | 情報 |
| --- | --- |
| OS | macOS Catalina(10.15.3) |
| ハードウェア | MacBook Pro (16-inch ,2019) |
| プロセッサ | 2.6 GHz 6コアIntel Core i7 |
| メモリ | 16 GB 2667 MHz DDR4 |
| グラフィックス | AMD Radeon Pro 5300M 4 GB Intel UHD Graphics 630 1536 MB |

# 困った内容

- 下記の手順を参考にMacとVisual Studio CodeとXdebugを使ったローカルデバッグ環境を立ち上げた。
    - [Mac Laravel PHP Visual Studio Code Xdebugを用いたローカル開発環境でデバッグをできるようにする](https://qiita.com/miriwo/items/6edd6e1817def4fc11d5)
- 下記の問題が発生した。
    - 設定完了しデバッグモードを開始したが、行単位の実行はどころか、ブレークポイントで止まることすらもない。
    - デバッグに使用するバーの単一実行ボタンがアクティブにならない。
        
        ![スクリーンショット 2020-03-17 14.52.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/b371777e-50a1-0940-da20-75607073c8bb.png)

# 原因

- セキュリティソフトのファイアウォールが本機能をブロックしてしまっていた。
- 一時的にファイアウォールの設定を切りサイドデバッグモードを起動したところ各ボタンもアクティブになり単一行での実行も可能になった。

    ![スクリーンショット 2020-03-17 14.59.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/2d424ac4-d187-b504-258d-d6dec15050ff.png)

# 謝辞

- 本件に関して数多くの方からフォローしていただきました。
- 筆者の問題解決に協力いただいた皆様に感謝申し上げるとともに、これから質問する際は各種詳細情報を明確にした上で、自分がどこまでわかっていて何ができていないのかを伝えて質問するように努めます。
- この度は誠にありがとうございます。
JavaScriptメモ

#JavaScriptメモ
###データ型
- 文字列（String）  'hello', "うおおおお"
- 数値（Number）    1, 1.2, -9, -1.7, NaN
- Undefined
- null
- 真偽値（Boolean）  true, false
- オブジェクト(Object) {a: 1, b: 2}

###論理演算子
- (等しい)  ===
- (等しくない)  !==
- (かつ)  &&
- (または)  ||
- (でない)  !

###条件演算子

```javascript:main.js
条件式 ? 条件式がtrueのときの処理 : 条件式がfalseのときの処理
```

###switch文

```javascript:main.js
const number = 1;

switch (number) {
  case 9:
    console.log(9);
    break;
  case 8:
  case 7:
    console.log(8 + 'or' + 7);
    break;
  default:
    console.log('numberは９でも８でも７でもありません');
    break;
}
```

### 中身が一度は実行されるwhile文

```javascript:main.js
yen = -10
do {
  console.log(`${yen} 円残ってます`);  // バッククオートと&{}で変数を埋め込む
  yen -= 10;
} while (yen > 0);
```

### 関数式
const 定数名 = function(仮引数, ...) {
  処理;
  return 返り値;
};

呼び出し→ 定数名(実引数, ...);

### アロー関数

```javascript:main.js
// const sum = function(a, b, c) {
//   return a + b + c;
// }; と同じ意味↓
const sum = (a, b, c) => a + b + c;
```

### 配列
```javascript:main.js
const numbers = [0, 1, 2, 3];  // 配列
numbers.length; // 配列の長さ
numbers.push(4); // 配列の末尾に4を追加。削除はpop()
numbers.unshift(-1);  // 配列の先頭に-1を追加。削除はshift()
console.log(numbers);  // [-1, 0, 1, 2, 3, 4]
numbers.splice(1, 2, 5, 6);  // splice(変化が開始する位置, 削除数, 追加する要素, ...)
console.log(numbers);  // [-1, 5, 6, 2, 3, 4]
```

###スプレット構文
...ってやつ！

```javascript:main.js
    const numbers = [10, 20];
    const otherNumbers = [90, 80, ...numbers];

    console.log(otherNumbers); // [90, 80, 10, 20]

    function sum(a, b) {
        console.log(a + b);
    }
    sum(...numbers); // 30
```

### 分割代入
```javascript:main.js
   const scores = [60, 40, 30, 80];

    const [a, b, c, d] = scores;
    console.log(a); // 60
    console.log(b); // 40
    console.log(c); // 30
    console.log(d); // 80

    const [e, f, ...others] = scores;
    console.log(e); // 60
    console.log(f); // 40
    console.log(others); // [30, 80]

    let x = 1;
    let y = 2;
    [x, y] = [y, x];
    console.log(x); // 2
    console.log(y); // 1
```

### コールバック関数
```javascript
// function 高階関数(コールバック関数) {
//     // 処理
//     コールバック関数();
// }
const unfollow = function () {
    console.log("フォローを外しました。")
}

const cancelTweet = function () {
    console.log("ツイートをキャンセルしました。")
}

function confirmed(fn: () => void) {
    if (window.confirm("実行しますか？")) {
        fn();
    }
}

confirmed(unfollow)
confirmed(cancelTweet)
```
ScaffoldHubってすごいのでは？


## はじめに 
最近のWebアプリを作るために様々な技術が登場しています。
結局どれで作るのが良いのだろうとふと疑問に思った時、思わず目に入ってきたサイトを見つけました。それがScaffoldHubでした。
より多くの人にScaffoldHubを知ってもらいたいと思い
（実は既に知っている人大多数説あり）、恥ずかしながら記事の初投稿を決意しました。

この記事はScaffoldHubの公式サイトに書いてあることを記載しているだけなので、詳しくは以下のURLの公式サイトや公式ブログを参照してください。
[https://scaffoldhub.io/](https://scaffoldhub.io/)

## ScaffoldHubとは
ScaffoldHubとは、JavaScriptで書かれたWebアプリのコード自動生成サービスです。選べるものとして、フロントエンドには御三家（React, Vue, Angular）、バックエンドはNodeJSのみ、DBにはSQL, MongoDB, Firebase Firestoreが選べるようです。Webアプリ生成した後は、生成されたソースを基に機能拡張ができるので、自分好みに改良できます。**一からWebアプリを作らなくて良いのは魅力的**です。
 
## ScaffoldHubの価格
サンプルとしてWebアプリを動かすのは無料ですが、ソースコードのダウンロードはもちろん有料です。気になる価格ですが、なんと**39ドル！！**
これは安いのでは！？と思いました。公式サイトを見る限り、これ以上かかる費用はなさそうですが、購入を検討されている方は購入前に必ず詳細を確認してください。

## ScaffoldHubの特徴
いくつか抜粋して、ScaffoldHubの特徴を記載します。

- 認証機能
  ユーザ名、パスワード認証やfacebook, Twitter, Google認証が実装されているようで、これらの認証機能を一から実装する必要がないようです。
  
- ユーザ・ロール、パーミッション管理
  それぞれを管理でき、権限制御ができるようです。
  
- 監査ログ
   ユーザのアクション（ログイン、ページ遷移等）がログに記録されるようです。
- モバイルとの親和性
   ScaffoldHubから生成したWebアプリはモバイル用のデザインも用意されているようです。

まだまだ、ありますが公式サイトを見ると全容がわかるので、詳細は[そちら](https://scaffoldhub.io/)を参照しください、
    
## 終わりに
ScaffoldHubは、2019年5月からサービスを開始していたようですが、
ScaffoldHubに関する記事が見当たらなかったので、記事投稿をしてみました。（今回の記事がQiitaデビュー）
まだ、次回の記事はScaffoldHubをしっかり見れていないのでこれからデモを動かしたときの使用感を試していきたいと思います。

ScaffoldHubについて、知っている方や気になる方がいらっしゃればこの記事を機会にぜひ公式サイトをみて欲しいです。また、気軽なコメントもぜひお待ちしております。
[https://scaffoldhub.io/](https://scaffoldhub.io/)
Bot Builder v4 でボット開発 : スキルを開発する - その 7 スキルのデバッグ

[前回](https://qiita.com/kenakamu/items/b5f48b09e6c1e20f0dae) の記事ではテンプレートで作成されるユニットテストを見ました。今回はスキルのデバッグについて考えてみます。

# メッセージタイプアクションのデバッグ

メッセージタイプのスキルは通常のボットと同じであるため、Bot Framework エミュレーターでデバッグが可能です。よって特別な対応は必要がありません。

# イベントタイプアクションのデバッグ

イベントタイプのデバッグは 2 つの種類があります。

- ローカルデバッグ
- リモートデバッグ

## ローカルデバッグ

まずは Bot Framework エミュレーターを使ったローカルデバッグを見ていきます。イベントタイプのアクションは ActivityType が Event である必要ですが、現在のバージョンのエミュレーターでは、アクション用のイベントタイプを送ることができません。

しかし、シリーズの[その 5](https://qiita.com/kenakamu/items/b0493a618ddfcbcf0571) でも紹介した通り、[EventDebuggerMiddleware](https://github.com/microsoft/botframework-solutions/blob/master/sdk/csharp/libraries/microsoft.bot.solutions/Middleware/EventDebuggerMiddleware.cs) は ```/event:``` で始まる文字列が来た場合はイベントとして処理してくれるため、以下の情報を送ることで任意のアクションをトリガーできます。

```shell
/event:{name:"アクション名",value:"<入力パラメーター>"}
```

さらにもう 1 点、ITurnContextEx.cs の IsSkill 拡張メソッドでスキル呼び出しかを確認していますが、このチェックをパスするためには、リクエストが他のボットから呼び出されたものである必要があるため、スキルとみなされません。そこでコードを以下のように書き換えます。

```csharp
public static class ITurnContextEx
{
    public static bool IsSkill(this ITurnContext turnContext)
    {
        if (turnContext.Activity.Type == ActivityTypes.Event && turnContext.Activity.ChannelId == "emulator")
            return true;

        return turnContext.TurnState.Get<ClaimsIdentity>("BotIdentity") is ClaimsIdentity botIdentity && SkillValidation.IsSkillClaim(botIdentity.Claims) ? true : false;
    }
}
```

これでエミュレーターから実行すると、イベントをデバッグすることができます。

**SampleAction**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/6154339e-d299-2be4-4726-801a9e93ecea.png)

**GetTimeAction**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/36fda485-5b36-1bd0-53ea-447aa4939c8d.png)

## リモートデバッグ

アシスタントボットや Power Virtual Agent から呼び出した際のデバッグをしたい場合、マニフェストを変更して対応します。以下に PVA の例を紹介します。

1\. ngrok でローカルサーバーを立てる。

```shell
ngrok http --host-header=localhost:3987 3978
```

2\. manifest-1.0.json を ngrok のアドレスで更新。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/ad8b23ce-53bc-88fc-a843-be8726a190af.png)

3\. Azure AD 上のアプリケーションの Homepage アドレスを更新。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/0c110eb5-eef8-0cb1-eb57-4e5f143136b4.png)

4\. PVA のスキルを読み込み直し。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/ac4035eb-730c-7365-5583-66718defe52d.png)

5\. ブレークポイントを設定して、PVA より呼び出し。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214116/335c073f-2c0b-9d52-0a3f-2640ce1f09de.png)

# まとめ

ライブデバッグも無事できました。これで開発もはかどりそうです。

[目次に戻る](https://qiita.com/kenakamu/items/6dc043cfc1f199032883)
sshd接続ポート番号変更

#手順

#1. /etc/ssh/sshd_configを開く。

viで/etc/ssh/sshd_configを開きます。

#2. 接続ポート番号を変更する。

/etc/ssh/sshd_configに記述されている。
Port 22　(＃でコメントアウトされている場合あり)
の部分を変更します。
例. Port 56789

※ ポート番号使用範囲
一般ポート(ウェルノウン(well known)ポート) : 0~1023
登録済みポート : 1024~49151
自由に使用できるポート : 49152~65535

#3. sshを再起動して設定を反映する。

次のコマンドでsshを再起動する。
service sshd restart

#4. Firewall(iptables)の設定ファイルを開く。

Firewall(iptables)で新しく設定したsshd接続ポートを接続可能にするため、
vi /etc/sysconfig/iptables (さくらVPSサーバー(CentOS6.9)の場合)
コマンドを実行し、ファイルを開きます。

#5. iptablesの開放ポート番号を変更する。

/etc/sysconfig/iptablesに記述されている次の赤文字の箇所を任意(/etc/ssh/sshd_configで設定した)ポート番号に変更します。

-A INPUT -m state —state NEW -m tcp -p tcp —dport 22 -j ACCEPT

#6. iptablesを再起動して設定を反映する。

次のコマンドでiptablesを再起動する。
service iptables restart

#まとめ

ssh接続ポート番号はデフォルトでは22なので、/etc/ssh/sshd_configを編集して、49152~65535の範囲の数値で新しい接続ポート番号を設定する。
また、新しく設定したポート番号は、Firewallで遮断されてしまうため、iptablesの設定を変更する必要がある。
vagrantを使った仮想マシンの自動起動

# TL;DRv
VirtualBoxの自動起動VboxAutostartを使用する
- HostOSの設定

```shell
sudo mkdir -p -m 1777 /etc/vbox/autostart_db
echo "default_policy = allow" | sudo tee -a /etc/vbox/autostart.cfg
echo -e "VBOXAUTOSTART_DB=/etc/vbox/autostart_db\nVBOXAUTOSTART_CONFIG=/etc/vbox/autostart.cfg" | sudo tee -a /etc/vbox/vbox.cfg
VBoxManage setproperty autostartdbpath /etc/vbox/autostart_db
```

- GuestOSの設定 Vagrantfileに以下の行を追加

```ruby
config.vm.provider "virtualbox" do |vb|
  vb.customize ["modifyvm", :id, "--autostart-enabled", "on"]
end
```

# 環境
- HostOS: debian10(buster)
- virtualbox-6.1
- vagrant-2.2.7

# 動機
vagrantを使ってHostOS上に仮想マシンを立てている。
HostOS起動時に仮想マシンも立ち上げたい。
systemdのunit-fileを書けば実現はできるが、わざわざunit-fileを書くのは億劫。
virshやvSphereではUIやコマンドラインからボタン一つ押すだけ、1行書くだけで簡単に実現できるのと比較するとsystemdのunit-fileの面倒具合は敷居がだいぶ高い。
もっと簡単な方法があれば良いと考えていた。

# HostOSの設定
### 仮想マシン毎の設定が保存されるDBを作る 

```
sudo mkdir -p -m 1777 /etc/vbox/autostart_db
```

### 自動起動を許可する

```
echo "default_policy = allow" | sudo tee -a /etc/vbox/autostart.cfg
```

### DBとautostart.cfgの場所をvirtualboxに教える

```shell
echo -e "VBOXAUTOSTART_DB=/etc/vbox/autostart_db\nVBOXAUTOSTART_CONFIG=/etc/vbox/autostart.cfg" | sudo tee -a /etc/vbox/vbox.cfg
```

### userに自動起動を有効にする
virtualboxを使って仮想マシンを操作するuserに自動起動を許可する

```
VBoxManage setproperty autostartdbpath /etc/vbox/autostart_db
```


# GuestOSの設定
Vagrantfileに以下の行を追加

```ruby
config.vm.provider "virtualbox" do |vb|
  vb.customize ["modifyvm", :id, "--autostart-enabled", "on"]
end
```

複数の仮想マシンの立ち上げ順番に依存がある場合、簡易的ではあるがdelayを設定すると実現できる

```ruby
  vb.customize ["modifyvm", :id, "--autostart-delay", seconds ]
```

# 参考
- [とあるエンジニアの備忘log VirtualBox 自動起動](http://masahir0y.blogspot.com/2013/06/virtualbox.html)
- [VBoxManage](https://www.virtualbox.org/manual/ch08.html)
  -  [VBoxManage autostart](https://www.virtualbox.org/manual/ch09.html#autostart) HostOS毎(Windows,Mac,Linux)の自動起動の方法が書かれている
【今日のアブストラクト】Attention Is All You Need【論文 DeepL 翻訳】

1 日 1 回 (努力目標) 論文の Abstract を DeepL 翻訳の力を借りて読んでいきます.

この記事は自分用のメモみたいなものです.
ほぼ DeepL 翻訳でお送りします.
間違いがあれば指摘していだだけると嬉しいです.

翻訳元
[Attention Is All You Need](https://arxiv.org/abs/1706.03762)

# Abstract

### 訳文

主なシーケンス伝達モデルは, エンコーダ-デコーダ構成の複雑な再帰ニューラルネットワークまたは畳み込みニューラルネットワークに基づいている. また, 最高のパフォーマンスを発揮するモデルは, アテンションメカニズムを介してエンコーダとデコーダを接続している. 我々は, 再帰や畳み込みを完全に排除して, アテンションメカニズムのみに基づいた新しいシンプルなネットワークアーキテクチャ, トランスフォーマーを提案する. $2$ つの機械翻訳タスクでの実験では, これらのモデルは品質が優れている一方で, より並列化が可能であり, トレーニングに要する時間が大幅に短縮されていることが示されてる. 我々のモデルは, WMT 2014 の英独翻訳タスクで $28.4$ BLEU を達成し, アンサンブルを含む既存の最良の結果を $2$ BLEU 以上改善した. WMT 2014 の英仏翻訳タスクにおいて, 我々のモデルは, $8$ つのGPUで $3.5$ 日間のトレーニングを行った後 (これは, 文献の最良モデルのトレーニングコストのごく一部), $41.8$ という新しいシングルモデルの最先端 BLEU スコアを確立した. 我々は, 大規模な学習データと限られた学習データの両方で英語の constituency parsing に適用することで, トランスフォーマーが他のタスクにもうまく一般化することを示している.


### 原文

The dominant sequence transduction models are based on complex recurrent or convolutional neural networks in an encoder-decoder configuration. The best performing models also connect the encoder and decoder through an attention mechanism. We propose a new simple network architecture, the Transformer, based solely on attention mechanisms, dispensing with recurrence and convolutions entirely. Experiments on two machine translation tasks show these models to be superior in quality while being more parallelizable and requiring significantly less time to train. Our model achieves 28.4 BLEU on the WMT 2014 English-to-German translation task, improving over the existing best results, including ensembles by over 2 BLEU. On the WMT 2014 English-to-French translation task, our model establishes a new single-model state-of-the-art BLEU score of 41.8 after training for 3.5 days on eight GPUs, a small fraction of the training costs of the best models from the literature. We show that the Transformer generalizes well to other tasks by applying it successfully to English constituency parsing both with large and limited training data.
html linkタグ一部調査。

htmlのheadから画像を一つ読み込もうとしてlinkタグで詰まったので備忘。
参照: [w3cschools](https://www.w3schools.com/tags/tag_link.asp)

よくスタイルシートの読み込みとかでやるのが

```html
<head>
  <link rel="stylesheet" type="text/css" href="theme.css">
</head>
```
でここで画像読み込んだりしようとした時に、relに何を指定すればいいんだろうって思った。

まずlinkタグとは、「当の文書と他の文書との関係性を設定しておく」メタデータを扱うもの。スタイルシートとかは「文書をどう呈示するかを述べる」に当たるものを表している。

linkタグで使える属性のうちいくつか列挙。

* href: ハイパーリンクのアドレス（他のリソースへのリンクであり、ダウンロードなどをできるようにする）を与える
* crossorigin: CROS周りのための属性。外部リソースリンクを意図し、非同一生成元の要請をどう取り扱うかを与える。値としてはanonymous || "": 'same-origin'とし、use-credentials : 'include'とする。あんまりここはよくわからず。。
* rel: 文書と行先リソースとの関係性を与える。
    * icon: ドキュメント表示用アイコン。複数用意した時にmedia, sizes, typeなどから適切なものを使っていくれるらしい。
    * stylesheet: 読んで通りのスタイルシートとして読み込む。
    * preload: ブラウザーの主なレンダリング機構が起動する前に読み込みを始めたい、すぐに必要なリソースを指定することができます。フォントや画像など、 CSS の中から指しているリソースなどを先にすることでその後のレンダリングで必要な時にすぐ利用できるようになる。その場合中身については'as'を用いるらしい。asで使えるのはfont, image, script, style, audio...など。
    * そのほかいろいろ。[w3c](https://www.w3schools.com/tags/att_link_rel.asp), [mozilla](https://developer.mozilla.org/ja/docs/Web/HTML/Preloading_content)
* media: 使用するメディアによってスタイルシートを変えたい時とかに変える。widthとかも指定できるっぽい。
    * print: 印刷とか？
    * screen: computer screens, tablets, smart-phones etc.
    * speech: screenreaders that "reads" the page out loud.
    * all: 全部

とかとかがあるらしい。
今回はpreloadを使いたくて最低限調べたけれど、prerendererみたいなやつもいるっぽいので
そこの差分は今度調査しないと。
sudo実行ユーザー・グループの制限

#手順

#1. visudoersの設定ファイルを開く。

次のコマンドを実行する。
visudo

※実行するにはスーパーユーザー(su,sudo)の実行権限(root権限など)を所持しているユーザーである必要があります。

#2. visudoersの設定ファイルにユーザーまたはグループを追加する。

・記述方式
“ユーザー名または％グループ名　ホスト名＝（ユーザー名：グループ名）コマンド”


誰がどのホストでどのユーザーどのグループと同じ権限でコマンドを実行するか

ここでは、次の記述を行います。
%wheel ALL=(ALL:ALL) ALL
意味は"Wheelグループに属するユーザーは全てのホストで全てのユーザー・全てのグループと同じ権限で全てのコマンドを実行する"です。

#まとめ

sudo実行ユーザー・グループを制限するにはvisudoersの設定ファイルを編集する。
Rails slimの書き方分からなくなった時

#slimの書き方分からなくなった時

slimって便利なんですけど、、
たまにちょっと入り組んでる参考サイトのコードをどうやってslimで書いたらいいか迷うことあるんですよね。

そんな時に便利なサイトがあったのでメモ。

http://erb2slim.com/

コチラで対象コードをコピペしてConversion Typeをslimにしてコンバートすると
１発で解決しました。
変換されたコード見て「あーそっかそう書くのね！」って感じのアハ体験ができました。
配列にindexOf()を使おうとしてエラーになった話


Paiz〇で問題文を解こうとしていたところ、
配列に対してindexOf()を使用としたら
can not find symbol シンボルが無いよ～って言われた。

コードはこんな感じ。関係ないところは端折る。
import util.*;

String[] array = {"a","b","c"};
String str = "a";

int  index = array.indexOf(str);
    }
}

ちゃんとutil.*もimportしてるし、スペルも間違ってないのに出来ない。
色々検証してたら配列じゃなくてlistとか基本型だったら普通に動く。
配列名だけで指定した時だけ動かない。

でも他のサイトにも配列の要素のインデックスを求めるのはindexOf使えと書いてるし…。

んで四苦八苦して参考書引っ張り出してきたら、
配列の特定の要素を調べるときはArrays.binarySearchを使えば良いよと書いてたので、
実際に使ってみたらちゃんと動いた。コードはこれ↓。

int  index = array.Arrays.binarySearch(array, str);

ただ配列の要素に重複がある場合、どの要素が返されるかはわからないとのことなので
やっぱりindexOfも使いたい。
一応拡張forを使って文字列に全部結合したら使えるが、二度手間だった。
ssh接続ユーザー制限設定

#手順

#1. /etc/ssh/sshd_configを開く。

次のコマンドを実行する。
vi /etc/ssh/sshd_config

#2. ssh接続許可ユーザーを設定する。

/etc/ssh/sshd_configに次の形式でssh接続許可ユーザーを記述する。
AllowUsers ユーザー名

例.
AllowUsers tanaka

※ AllowUsersの記述形式は複数あり。
・接続許可ユーザー設定
	AllowUsers ユーザー名
・接続許可ユーザー設定(複数)
AllowUsers ユーザー名１ ユーザー名２
・特定のIPアドレスからのみ接続許可ユーザー設定
AllowUsers ユーザー名@接続元IPアドレス
・特定のIPアドレスからのみ接続許可ユーザー設定(全ユーザー)
AllowUsers *@接続元IPアドレス

#3. sshdを再起動(または再読み込み)して設定を反映する。

次のコマンドを実行する。
service sshd restart   (または、service sshd reload)

#まとめ

/etc/ssh/sshd_configに接続許可ユーザーを記述して、sshdを再起動する。