OmniAICreator/Qiita-1.07M huggingface dataset:
2次元配列の動きを眺める関数（Python）

# はじめに

競プロ中、2次元配列の変化を観察したい時があります。
DPとか、DPとか。

1次元配列ならまだしも、2次元配列を逐次`print`するとかなり見にくいので、
2次元配列の変化をじーっと眺めるための関数を用意しました。

完成品はこちら↓

```python
from time import sleep
def print_2d_overwrite(list2d, val_width=5, sleep_sec=1.0, header=None, highlights=[]):
    res_str = f'{header}\n' if header is not None else '' 
    for i, row in enumerate(list2d):
        for j, v in enumerate(row):
            v_str = str(v).rjust(val_width)
            if (i,j) in highlights: 
                v_str = f'\033[31m{v_str}\033[0m'
            res_str += f' {v_str}'
        res_str += '\n'
    new_line_cnt = res_str.count('\n')
    res_str += f'\033[{new_line_cnt}A'
    print(res_str, end='')
    sleep(sleep_sec)

# --- sample ---
n = 3
list2d = [ [0]*n for _ in range(n)]
for i in range(n):
    for j in range(n):
        list2d[i][j] = 3**(i+j)
        print_2d_overwrite(list2d, val_width=3, header=(i,j), highlights=[(i,j)])
```

動作の様子は↓
![sample.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/88538/af91d9c2-78e9-e851-59ab-ffa9e78143e5.gif)


ポイントは以下です。

- 標準出力を上書きする
- 値の長さ（表示桁）を揃える
- 文字列の色を変える
- sleepする（`time.sleep()`するだけ）

（2020/11/19 追記）
コメントで、テクニカルな書き方をいただきました。


# 標準出力を上書きする

[関連する記事](https://qiita.com/kuroitu/items/f18acf87269f4267e8c1) が昨日投稿されていてビックリ。
自分が実装の参考にした記事は [こちら](https://hacknote.jp/archives/51679/) です。
これらの記事で解説は十分なので、今回は要点だけ説明。

`\033[nA`で、カーソルをn行上に移動できます。
表示したい2次元配列を文字列 `(res_str)` に変換し、その中の 改行`\n`の個数を数え、文字列の最後に追加しています。f文字列を使うと楽。
`print`で`end=''`を忘れずに。

```python
new_line_cnt = res_str.count('\n')
res_str += f'\033[{new_line_cnt}A'
print(res_str, end='')
```

# 値の長さ（表示桁）を揃える
こんな感じで長さが揃ってないと見にくい

```python
3  5  345
235  -48  123
1  2  3
```
ので、各要素の長さ（表示桁）を揃えたいです。

```python
    3     5   345
  235   -48   123
    1     2     3
```


今回は、`str.rjust(n)`を利用してこれを実現します。
文字列を右寄せにし、n文字に足りない分は第2引数で指定した文字で埋めます（何も指定しない場合はスペース埋め）。

```python
v_str = str(v).rjust(val_width)
```

# 文字列の色を変更する
`\033[31m色変したい文字列\033[0m` でOKです。
`30m`~`37m` で色設定可能。`31m`は赤です。
（詳細は [こちら](https://www.nomuramath.com/kv8wr0mp/)）

関数内で、`highlights`に指定された値の色を変更しています。こちらもf文字列を使うと楽。

```python
if (i,j) in highlights: 
    v_str = f'\033[31m{v_str}\033[0m'
```

# おわりに
もしかしたらデバッグで使えるかもしれないので、競プロ用スニペットに加えておきました。
`sleep`の部分をキー入力にしたらもっと便利かもと思ったのですが、Macだと`sudo`しないと`keyboard`が使えず面倒だったので、このままで。
ASP.NET WebフォームのGridViewで、ある列が空白である場合の分岐処理

今でもメンテでASP.NETをやってる人っているとは思いますが、いささか時代遅れっぽい記事を。

GridViewで表を表示したとき、ある列の項目が空の場合にセルの表示を変える分岐処理を加えたかったのですが、String.IsNullOrEmptyやString.IsNullOrWhiteSpaceで判定をしたくても引っかからない。デバッグしてみたところHTMLエンコーディングされた半角空白(\&nbsp;)が入っていました。どうもGridViewの仕様みたい。というわけで、Server.HtmlDecodeメソッドでデコードしてやり、String.IsNullOrWhiteSpaceで判定してやればいいよ、というだけの話。

```vb:VB.NET
    Private Sub disableEmptyColumnsChkbox()
        For Each row As GridViewRow In gv.Rows
            Dim cb As CheckBox = row.FindControl("Check")
            If (String.IsNullOrWhiteSpace(Server.HtmlDecode(row.Cells(3).Text))) Then
                cb.Enabled = False
            End If
        Next
    End Sub
```

```csharp:C#
private void disableEmptyColumnsChkbox()
{
    foreach (GridViewRow row in gv.Rows)
    {
        CheckBox cb = row.FindControl("Check");
        if ((string.IsNullOrWhiteSpace(Server.HtmlDecode(row.Cells(3).Text))))
            cb.Enabled = false;
    }
}
```

GridViewRowクラスをForeachにかけると一行ずつ値の判定などができる。gvというのは私が.aspxに配置したGridViewのID。チェックボックスを探すときはFindControlメソッドでIDを指定する（ここではCheckとしている）。ちなみにGridViewの中にチェックボックスを入れるときは、TemplateFieldで括る（[参照:MSDN](https://docs.microsoft.com/en-us/aspnet/web-forms/overview/data-access/enhancing-the-gridview/adding-a-gridview-column-of-checkboxes-vb)）。

上記のメソッドは3列目の値を見て空欄（＝半角スペース）の場合に、チェックボックスのEnabledをFalseにするという内容。チェック入れた行をボタンでUPDATEしたりする、というときにあらかじめチェックボックスを使えなくしておけば、内容が空の場合の判定をしなくていいじゃん？という発想です。

ちなみにGridViewで非表示列の値を取り出したい時は、いろいろあるらしいのでそのうち（.aspxで非表示にせず、コードのほうでRowCreatedなどの時に非表示にしたりするとかいろいろ工夫している様子）。しかしGridViewって今どきのMVCフレームワークのものと比べるとあまり便利じゃないな。
VBAで全シートのアクティブセルをA1、表示倍率を100%にする

```vb
Option Explicit

Sub ImportButton_Click()

Dim FilePath As String
Dim i As Long

'ApplicationオブジェクトのGetOpenFilenameメソッドを使って、[ファイルを開く]ダイアログボックスを表示する
'[ファイルを開く]ダイアログボックスに、どの拡張子のファイルを表示するかを引数FileFilterで設定する
'選択されたファイルのフルパスをFilePathに格納する
FilePath = Application.GetOpenFilename("Excel ファイル (*.xls; *.xlsx; *.xlsm),*.xls; *.xlsx; *.xlsm")

'選択したブック（ファイル）を開く
Workbooks.Open FilePath

'全シートのアクティブセルをA1にする
'全シートの表示倍率を100%にする
For i = Sheets.Count To 1 Step -1 '最後のシートから逆順で処理。1番目のシートになるまで処理を実行する
    If Sheets(i).Visible = True Then '非表示セルは処理対象外とする
        Application.Goto Sheets(i).Cells(1, 1)
    End If
    ActiveWindow.Zoom = 100
Next i

'一番左のシートのA1セルに移動する
Application.Goto Sheets(1).Cells(1, 1)

End Sub
```
Google Apps Scriptとは

## Google Apps Scriptとは
　**Google Apps Script（通称GAS）は、Googleが提供しているプログラミング言語**です。
　GASを使うことで、Gmail、Google Spread Sheet、Googleカレンダー、Google Drive、Google翻訳などのGoogleが提供する数々のアプリケーションをプログラムを記述することで操作できます。
　GASでは各アプリケーションを単体で動作させることもできますし、アプリケーション同士をつないで動作させることもできます。GASは、アプリケーションを操作する以外にも、HTML/CSSを使って独自のWebアプリを構築したり、API経由で外部のサービスと連携させる機能も提供されています。

　**GASはJavaScriptをベースとしています。**JavaScriptはブラウザ上で動作する標準のスクリプト言語として使われる以外にも、サーバ内やWindows上での実行環境で動作する言語としても知られています。JavaScriptを学べるという点は、GASの大きな魅力のうちのひとつです。

　GASの特徴として、徹底したクラウド志向があげられます。以下は、すべてGoogleのクラウドサーバ上にあります。GASではブラウザ上で編集、デバッグなどの操作を行い、その実行もクラウドサーバ上でされます。

- 記述したスクリプトファイル
- スクリプトを編集および実行するためのプログラム環境
- 操作対象となるGoogleのアプリケーションやサーバ上のデータ

　クラウド上にあることの最大の利点は、**開発環境の準備が一切不要**という点です。サーバも、スクリプトを動作させるアプリケーションも、エディタもすべてGoogleが用意してくれているので、ブラウザにアクセスするだけで、すぐにスクリプトを書き始めることができます。

　また、サーバ上で動作するので、ローカルPCやブラウザが立ち上がっていなくても、スクリプトを実行することができます。**「トリガー」**と呼ばれる機能を使うことで、特定の時間にスケジュールを実行させたり、他のユーザの操作を受けて実行させることが可能です。
rails学習　Decorator

#decoratorとは

モデルに関係したモデルとはあまり関わりがないメソッドを入れておく場所
例えばビューでフォームに記入したフルネームを表示させたいという場合、モデルの中の名前の要素を使ってモデルとはあまり関係ないビューに表示させるためのメソッドなのでdecoratorにメソッドを書く方がいい。
モデルに直接書くのもいいが、モデルに直接関係のない働きをするメソッドなので何でもかんでもモデルに書くとモデルがパンパンになってみづらくなる。そのため「モデルから情報は取るけどメソッドの働き自体はモデルと関係ないよ」という専用の場所に書いた方が見やすくなる。その専用の場所がdecoratorというわけである。

decoratorは専用のdraperというgemを使い実装していく

draperのgemを記入

```Gemfile
gem ‘draper’
```

```
$ bundle
```
draperを使えるようにする

```
$ rails generate draper:install
#このコマンドを使うとdecoratorを定義する場所app/decorators/application_decorator.rbが自動生成される。
```
Userモデルのためのdecoratorの場所を作成

```
$ rails generate decorator モデル名(Userなど)
#このコマンドでapp/decorators/user_decorator.rb を作成
```

user_decorator.rbにuserモデルを使って作りたいメソッドを作る

```ruby:user_decorator.rb
class UserDecorator < Draper::Decorator
  delegate_all

  def full_name
    "#{last_name} #{first_name}"
  end
end
```

delegate_allをつけることでUserモデルの全メソッドが使えるようになり、その結果last_nameとfirst_nameがつかえるようになった。

またuser_decorator.rb内では@userのようにインスタンス変数もつかうことができない。理由は@userはUserコントローラーで定義されたクラス、つまりコントローラーのクラスであり、一方decoratorはdecoratorクラスである。なのでそもそもクラスが違うのでインスタンス変数を使えないのである。よって”#{last_name} #{first_name}”の部分は”#{@user.last_name} #{@user.first_name}”にはできない。

full_nameというメソッドが使えるようになったのでビューで使う

```
<%= current_user.decorate.full_name %>
```
例えばこのように使う。
rails学習　flashメッセージ

#Flashメッセージについて
Flashメッセージは表示する場所をapplicationのhtmlファイルに作り、何を表示させるかを各アクションに書いて初めて実行される。

application_controllerに以下の記述をするとデフォルトではnoticeとalertしか使えないがsuccess, info, warning,dangerのflashメッセージが使えるようになる

```ruby:application_controller
 add_flash_types :success, :info, :warning, :danger
```
>flashメッセージを書く

```ruby:app/views/application.html.erb

<% if flash.present?%>
<% flash.each do |message_type, message| %>
  <div class="alert alert-<%= message_type %>"><%= message %></div>
<% end %>
<% end%>
```

```ruby:user_sessions_controller.rb
 def create
    @user = login(params[:email], params[:password])
    if @user
      flash[:success] = t('.Login successful')
      redirect_to root_url
    else
      flash.now[:danger] = t('.Login failed')
      render :new
    end
  end
```

・if flash.present?は「もしflashメッセージが存在するなら以下のコードを実行する」というもの
・flash.each do |message_type, message|はmessage_typeをキーという。
・コントローラーでいう flash[:success] = t('.Login successful’)の:successの部分がキーとなり、この場合flash.each do |success, ‘Login successful’|となる
つまり

```
<div class="alert alert-<%= message_type %>"><%= message %></div>
```
が

```
<div class="alert alert-success”>Login successful</div>
```
となる。
bootstrapでalert-successは緑色、alert-dangerは赤色など変化があるため
flash[:success]やflash[:danger]などキーで指定をしている。


>省略の仕方

Before

```
 def create
    @user = login(params[:email], params[:password])
    if @user
      flash[:success] = t('.Login successful')
      redirect_to root_url
    else
      flash.now[:danger] = t('.Login failed')
      render :new
    end
  end
```

After

```
 def create
    @user = login(params[:email], params[:password])
    if @user
      redirect_to root_url, success: t('.Login successful')
    else
      flash.now[:danger] = t('.Login failed')
      render :new
    end
  end
```
[JavaScript] 等価性比較について

# 等価性とは？
値を比較して、同じと見なすことができるか？ということ。

等価性を比較するために、比較演算子を使用します。

等価性には __厳格な等価性__と __抽象的な等価性__ の２種類あります。
違いは以下の通りです。

| 等価性 | 比較演算子で記述した場合 |　型の比較　|
|:-----------|:------------|:------------|
| 厳格な等価性 | a === b | あり　| 
| 抽象的な等価性 | a == b | なし　| 

厳格な等価性と抽象的な等価性の違いについては、データ型の比較を行うか否かというところです。

###例１

```javascript
let a = '1';
let b = 1;

console.log(a === b)
```

上記の場合、`let a = '1'`として、文字列型の「１」で変数aを定義しています。一方、`let b = 1`として、数値型の「１」で変数bを定義してます。

そして最後にconsole.log(a === b)で厳格な等価性で２つの値を比較しております。

この場合、aとbの型が文字列と数値で異なるため、

```
false
```
が真偽値として出力されます。

一方、次の場合を見てみましょう。

```javascript
let a = '1';
let b = 1;

console.log(a == b)
```

変数の定義については先ほどと同じですが、今回はconsole.log(a == b)で、抽象的な等価性で比較しております。

この場合は

```
true
```
が出力されます。
これは、aとbの「１」という値のみ比較しており、文字型と数値型まで比較をしていないためです。

### 例２

```javascript
let a = 1;
let b = true;

console.log(b == a)
console.log(b === a)
```

今回は 変数aを数値型の「１」で定義。変数bを真偽値型の「true」で定義しています。

なお、真偽値型の場合、__falsyな値__ と __truthyな値__ という概念があります。

falseになる値とtrueになる値については以下の通りになります。

| falsyな値(falseになる値） | truthyな値（trueになる値） |
|:-----------|:------------|:------------|
| false, null, 0, undefinded, 0n, NaN, "" | falsyな値以外のもの | 

これを踏まえて出力結果を見ると、

console.log(b == a)については、`true`を返します。
console.log(b === a)については、`false`を返します。

console.log(b === a)の方は、aが数値型で、bが真偽値型ですのでfalseが返ります。
注目するのは抽象的な等価性比較console.log(b == a)の部分です・

### 抽象的な等価性を比較する時の処理の流れ
抽象的な等価性を比較する際次のプロセスを辿って比較を行います。

__①両辺の型を合わせる作業を行う__
__②厳格な等価性比較を行う__

例２のconsole.log(b == a)をもう少し深く突っ込んで記述して表してみると次のようになります。

```javascript
let a = 1;
let b = true;

console.log(b === Boolean(a));
```
まず処理の流れとして`(b === Boolean(a))`として__両辺の型を合わせる作業__を行っています。
この場合、最初にbが参照され、bの型が真偽値型だと認識します。その後aを参照する際、aをBoolean（真偽値型）に変換しています。
その後、厳格な等価性比較(===)で比較を行い、出力する流れです。

変数aには「１」の値が入っており、１は先ほども紹介したようにtruthyな値に該当するため、aは`true`ということになります。

よって、console.log(b == a)については、`true`を返すわけです。

仮に`let b = 0;`だった場合は、先ほどと同じように両辺の型を合わせて、厳格な等価性比較を行うわけですが、変数bに代入された「0」はfalsyな値となるので`false`が出力されます。

### 例３
空文字が含まれているケースを考えてみましょう。

```javascript
let a = "";
let b = 0;

console.log(a === b);
console.log(a == b);
```
厳格な等価性console.log(a === b);はこの場合、`false`を返します。
抽象的な等価性console.log(a == b);は、`true`を返します。

抽象的な等価性についてもう少し深く突っ込んで記述すると

```javascript
let a = "";
let b = 0;

console.log(a === b);
console.log(Boolean(a) === Boolean(b));
```
という形になります。
空文字の場合は数値に変換することができないので、この場合は真偽値型として両辺を統一して厳格な等価性比較をしています。
空文字「""」も「0」もfalsyな値に分類されるため、最終的な出力結果は`true`となります。


### 例４
値が設定されていない場合を考えます。

```javascript
let g = null;
let b;

console.log(a === b);
console.log(a == b);
```
厳格な等価性console.log(a === b);はこの場合、`false`を返します。
抽象的な等価性console.log(a == b);は、`true`を返します。

これも抽象的な等価性を細かく見てみると、

```javascript
let a = null;
let b;

console.log(a === b);
console.log(Boolean(a) === Boolean(b));
```
となります。
`let b;`のように、__変数が宣言された際に値が設定されていない場合は、undefindedが設定される__ことになっています。

よってこの場合、 a = null, b = undefinded　つまり　どちらもfalthyな値となりますので、
最終的な出力結果がtrueになります。

# 比較演算子を使う場合は厳格な等価性比較（===）を使おう！！
抽象的な等価性を使った場合は、例で上げた通り、データ型が異なる場合でもtrueになるケースが沢山あります。

これによって、思わぬバグを引き起こす可能性が高くなりますので、基本的には厳格な等価性比較を使うようにしましょう。

# 最後に
ご覧いただきありがとうございました。
開発環境別にseed ファイルを分けて管理する

# はじめに

アプリの初期データ用のseed ファイルを開発環境別に管理する必要があったので備忘録です。

# 環境

* macOS 10.15.6
* Ruby 2.5.7
* Rails 5.2.3
* rspec-rails 4.0.1
* capybara 3.32.2

# 参考URL

<https://pikawaka.com/rails/env>
<https://prokyou.com/rails/seeds/>
<https://qiita.com/kimihito_/items/753390a5fe42a41b1d60>
<https://qiita.com/mogya/items/76430e32ffca1ef93f27>

# 目標

* 開発環境別でseed ファイルを管理できる
* seed ファイルの修正後に環境別に初期データを追加/削除ができる

# 実装

## 1. seeds ディレクトリを作成

通常のRails アプリでのseed ファイルのディレクトリは`db/seeds.rb` です。
これを以下のように修正します。

```Ruby
#修正前
db/seeds.rb
```

```Ruby
#修正後
db/seeds/development.rb #追加
db/seeds/test.rb #追加
db/seeds/production.rb #追加
db/seeds.rb
```

* `seeds` ディレクトリの中に環境別のseed ファイルを作成
* 元々あったseeds.rb の中身は現時点ではそのままでok

## 2. 環境別にseed ファイルを作成

元々あったseeds.rb の中身を元にして各環境別に初期データ用の処理を追加します。
私の場合はCSV を使った初期データをテスト環境でも使いたかったのでtest.rb に下記を追加しました。
development.rb は元々あったseeds.rb を複製しました。

```Ruby:test.rb
#Country CSV import
require "csv"

CSV.foreach("country.csv", headers: true) do |row|
  Country.create!(
    country_name: row["国・地域名"],
    region: row["場所"]
  )
end
```

## 3. seeds.rb に読み込み処理を追加

環境別にseed ファイルが準備できたので各ファイルの読み込み処理をseeds.rb に追加します。
初期データ追加用の処理は各環境別に分けているはずなので削除してokです。

```Ruby:seeds.rb
#環境別にseed ファイルを読み込む
load(Rails.root.join("db", "seeds", "#{Rails.env.downcase}.rb"))

#元の初期データ追加の処理は削除
```

seed ファイルの読み込みディレクトリを指定しています。

```Ruby:seeds.rb
#seeds.rb の読み込み処理の詳細
load(Rails.root.join("親ディレクトリ", "子ディレクトリ", "#{開発環境名.downcase}.rb))
```

## 4. 環境別にseed ファイルで初期データを導入

環境別にseed ファイルを読み込んで初期データを導入します。
初期データを削除してseed ファイルを読み込みます。

```Shell
# development 環境の初期データ削除
$ rails db:migrate:reset

# development 環境の初期データ追加
$ rails db:seed

# test 環境の初期データ削除
$ rails db:migrate:reset RAILS_ENV=test

# test 環境の初期データ追加
$ rails db:seed RAILS_ENV=test
```

## 5. コンソールで導入されたデータの確認

環境別にコンソールを立ち上げて初期データの件数を確認します。
`-e` オプションをつける事で環境別にコンソールを立ち上げます。

```Shell
#development 環境で初期データ件数の確認
$ rails console
Loading development environment (Rails 5.2.3)
> Country.count
249

#test 環境で初期データ件数の確認
$ rails console -e test
Loading test environment (Rails 5.2.3)
> Country.count
249
```

# 学び

* 環境別にseed ファイルを用意する事で初期データの管理が楽になった
* テスト用の初期データにseed を使うのは一部だけにして、テストに必要なデータはなるべくfixture を使う方が良さそうです
C言語　unsignedの型の変数に負の数を代入するのは未定義動作ではない。

# 整数変換という機能

あらゆる整数型の値は任意の他の整数型に暗黙に変換できます。

目的の型が符号なしの場合は、目的の型に収まるまで繰り返し 2^bが加算または減算されます (b は目的の型のビット数です)。 別の言い方をすると、符号なし整数はモジュロ算術を実装します。

```c
unsigned char n = -123456; 
// => 目的の型は符号なし。 結果は 192 (つまり -123456+483*256) です。
```

## 参考

[暗黙の変換 - cppreference.com](https://ja.cppreference.com/w/c/language/conversion)

## メモ

printfの実装を読んでいて｢暗黙の型変換｣を前提とした書き方に初めて出会ったので、メモとしてまとめました。
miの見出しリストの作成方法

macOS専用のテキストエディタ 「mi」をプログラミング学習用のノートとして使っています。
画面右側にでてくる見出しリストに見出しを作成する方法を自分なりにまとめました。
##実装したい内容
インデントなしをタイトルとして見出しにする
Tabキー1回のインデントをそのタイトル中の見出しにする
具体的には
![3D99B010-09DD-4AD5-9AEC-F871FC88527E.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674828/d6010f48-cd06-8b50-e6cf-03f02ed7cb8c.png)

初期状態では、メモを書いた時に右側の見出しリストに何も表示されていないこれを
![3F8F2C36-4C2E-4161-8971-2CCD8347DB71.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674828/ffa573ff-de6a-70fd-36ed-2b7460f2a533.png)
上記のように右側の見出しリストに表示させたり、メモ側にも見出しに色を付けたりといったことを実装します。

##実装準備
細かく自分が決めたルールを使いたい場合は正規表現を学ぶことでより自分にあった見出しをつけることができます。
ここではインデントなしで入力した部分とTabキーを1回おしてインデントした時の見出しの作り方について紹介します。

##実装手順

左上のmiをクリック　⇢　モード毎の設定　⇢　標準をクリック
![A978B07D-80ED-4F3B-9D7E-4B0FAD0B0B4D.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674828/1fe3dcec-7a34-4649-39c6-caf0bc7e0769.png)
すると以下のようなウィンドウがでるので見出しタブをクリック
![9E12E35A-0F7D-422E-B7B4-69EDD0EA23A8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674828/10c3a5e5-7912-2a9d-4676-4bdd20c5358c.png)
以下のような画面が出てきます。
ここでは見出しの設定をします。
自分がメモとして書いたどんなものを見出しとして認識してもらうかということです。
今回の私の場合はインデントしていないものとTAB1回のインデントを認識させ、それらも見出しにします。
![実装4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674828/e3746bfc-f159-6f4d-1e96-8eba9de024df.png)
手順としては
①新しい見出しルールを作成する。
②見出しルール名をきめる
③正規表現でルールを表現する
④見出しリストに表示するチェックを入れる
③の正規表現でルールを決めるところが一番難しいですが、私と同じルールで見出しを作りたい場合はコピペでできます。
正規表現とは特殊な記号や文字を使って、特定のパターンを表すことができるミニ言語みたいなものです。
今回は見出しにする文字のパターンを特殊な記号や文字を使って表すことで、miに見出しがどれか判別してもらおうということです。
![0BF7E99D-69A5-45E8-9106-927C0AE14132.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674828/ef36474a-99b0-5b7b-442c-00cd2677f41a.png)
③の正規表現の部分には
インデントなしの見出し

```
[^\s].+
```

TAB1回のインデントの見出し

```
\s{1}[^\s].+
```

を入力してください。
ちなみに\はoptionキーを押しながら¥キーを押すと入力できます。
入力後は左下にある変更を反映を押すと反映されます。

どういう意味か簡単に説明すると
[^\s]では
^が否定の意味
\sが空白文字（半角スペース、タブ文字、改行文字など）
となるので[^\s]で空白文字でないものという意味になります。
.は任意の文字1文字
+は直前の文字が1文字以上
という意味なので「.+」では任意の文字1文字以上という意味になります。
まとめると、開始文字が空欄でなく、任意の文字が1文字以上続く文字列を見つけると見出しとして認識します。

\s{1}[^\s].+
こちらでは\sが{1}、つまり空欄文字が１つあり、その後は上記と同様空欄文字以外が1文字以上という記述になります。
まとめると、開始文字が空欄文字で、2文字目からは空欄以外の任意の文字が1文字以上という文字列を見つけると見出しとして認識します。

変更を反映をクリックすると見出しに色をつけている場合は色がつき、右側の見出しリストに見出しとして認識されたものが表示されます。
![FAA6B970-D7ED-4779-ADE9-6D51AA8702A3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674828/ea8ebb4e-fc70-aa2a-3dc5-eb8a0508ccf2.png)

今回設定した正規表現を変えることで、私とは違った場所を見出しとして認識させることができます。
正規表現を学ぶいいきっかけにもなると思いますので、自分の思う見出しを設定してみて下さい！
ハノイの塔つくってみた

いつものノリで、思い立ったらとりあえず作ってみていた。

再帰を組むのはめんどくさかったので移動させるステップはべた書きでございます。

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

# ハノイの塔についての雑な説明

一番ちっさい輪っかから$N$番目の大きさの輪っかまでの$N$個を１塊で移動させるには、
一番ちっさい輪っかから$N-1$番目の大きさの輪っかまでの$N-1$個を、残りの棒のとこに一旦退避して、$N$番目の大きさの輪っかを目的の棒のとこに移動して、再度、
一番ちっさい輪っかから$N-1$番目の大きさの輪っかまでの$N-1$個を、その上に乗っければよい。（語彙力・・）
n番目の子要素の色を変える

n番目の子要素の色を変える。

・nth-child(?)を使う
・nthは1th,2th,...からくるnth

```css
.item {
    background-color: white;
    margin: 10px;
}

.item:nth-child(even) {
    background-color: gray;
}
```

```react
export const Hoge = () => {
    return (
        <>
            <ul>
                <li className="item">aaaa</li>
                <li className="item">aaaa</li>
                <li className="item">aaaa</li>
                <li className="item">aaaa</li>
            </ul>
        </>
    )
}
```

結果
![スクリーンショット 2020-11-18 21.42.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278474/94765487-4154-5893-1e94-caf5442f584f.png)
ESXi6.7でCentOS8をインストールしてみた

仮想マシン作成～ログインまでの手順。

# 1.仮想マシン作成
ESXiで作成しました。
## ゲストOS設定
| 互換性           |ゲストOSファミリ| ゲストOSバージョン |
|:---:|:---:|:---:|
|ESXi6.7 仮想マシン| Linux         | CentOS8 |

##仮想マシン設定
|CPU| メモリ | ハードディスク | プロビジョニング    |
|:---:| :---: | :---: | :---: |
|1  | 2GB    | 16GB         | シンプロビジョニング |

# 2.OSインストール
### 電源オン＆インストール開始
作成した仮想マシンの電源をオンにすると、コンソールにインストールメニューが現れました。モノクロの画面がカッコいいです。
デフォルトでは上から2番目が選択されてますが、1番目の方が早いので1番上の「*Install CentOS Linux 8*」を選択します。
<img width="400" alt="FlowTime_8" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685426/b9ffd8b4-695f-6556-2d02-13a291bb4a69.png">

このあと画面を眺めていると緑色の [OK] がめっちゃいっぱい流れていきました。
OKみたいでよかったです。

### 言語設定
続いては言語設定です。日本人なので日本語を選択。
<img width="400" alt="FlowTime_8" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685426/3aabe9e9-be13-b4d4-d5dd-b448f6fc01fb.png">


### インストール概要
そのあとはインストール概要という画面が出てきました。
こちらは設定後の画面なので、どのように設定したか下に書いていきます。
設定項目は３つです。
<img width="400" alt="FlowTime_8" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685426/c11c7d90-33a0-7645-f581-58bdd97ce564.png">

#### ①ソフトウェアの選択
ここを間違えると思ってたのとだいぶ違う仮想マシンになってしまいます。(何回もやらかした)
今回はCUIのサーバを作りたいので、「最小限のインストール」を選択しました。
選択した後は左上の[完了]をクリックして元の画面に戻ります。
<img width="400" alt="FlowTime_8" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685426/e4272378-7e19-cf16-683a-f7a5fffa1d03.png">

#### ②デバイスの選択
今回はこだわりがなかったのでデフォルトのまま。
<img width="400" alt="FlowTime_8" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685426/f94031a1-9209-8814-5802-b33df0e013ac.png">

#### ③地域設定
やらなくてもいい気もする。
気になったので一応東京に設定しました。

①～③を設定したら、右下の[インストールの開始]をクリックします。


### rootパスワードの設定
ここまでくればゴールは目の前です。
進捗の青いバーがすくすくと伸びていく様子を温かい目で見守りつつ、rootパスワードを設定。
<img width="400" alt="FlowTime_8" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685426/47abbc23-94c9-063b-2715-00e040c59b0c.png">


# 3.再起動＆ログイン
青いバーが伸び切ると、[再起動]のボタンが出てきたのでクリックします。
急に電源オフになってもビビらないことが大切。
<img width="400" alt="FlowTime_8" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685426/7ea8783a-89eb-c385-04b2-0590f7188eaa.png">

再起動後はこんな画面がでてきました。一番上を選択します。
<img width="400" alt="FlowTime_8" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685426/8e6aeac4-df4c-7534-8647-1297cb61ce33.png">

少し待ってログイン画面がでてきました。
User : root
password : <先ほど設定したrootパスワード>
を入力すると・・・
<img width="400" alt="FlowTime_8" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685426/26399e13-4c09-e2f3-6cc2-17c1cceaa8f9.png">

やったー！ログインできました！
<img width="400" alt="FlowTime_8" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/685426/09dfafe1-40b9-b841-9038-28fec2736618.png">


# 4.初期設定
この後の初期設定については別の投稿にまとめます。
データベースクライアントツールから多段SSHでデータベースに接続したい

# やりたいこと

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96507/2c0c4d0d-6c99-e6d5-77ef-61ee0e9a4325.png)

こんな感じの踏み台が複数ある多段のSSHでデータベースに接続しに行く構成で、
手元のWindows 10クライアントにインストールしたデータベースクライアントツール（Oracle SQL DeveloperとかMySQL Workbench）から直接DBを見に行きたい。

# SSHポートフォワーディング
データベースクライアントツールからは一段までしか踏み台ができないため、SSHポートフォワーディングを実行して、ローカルクライアントのポートをデータベースに間接的に接続します。

便宜的に各サーバの接続情報を定義します。

| ホスト          | IPアドレス/ドメイン    | ポート|
|--------------- |-----------------------|--------|
| EC2（Bastion） | AAA.AAA.AAA.10 |22|
| EC2（Web/AP）  | BBB.BBB.BBB.11|22|
| RDS（Oracle）  | oracle.xxxxxxxxx.ap-northeast-1.rds.amazonaws.com|1521|
| RDS（MySQL）   | mysql.xxxxxxxxx.ap-northeast-1.rds.amazonaws.com|3306|

ユーザーディレクトリ直下に`.ssh`フォルダを作成。
中にポートフォワードの設定ファイルを作成します。

```:.ssh\config
Host bastion
  hostname AAA.AAA.AAA.10
  port 22
  user ec2-user
  IdentityFile C:\Users\hoge\.ssh\bastion.pem

Host webap/oracle
  hostname BBB.BBB.BBB.11
  port 22
  user ec2-user
  IdentityFile C:\Users\hoge\.ssh\webap.pem
  ProxyCommand C:\Windows\System32\OpenSSH\ssh.exe bastion -W %h:%p
  GatewayPorts yes
  LocalForward 51521   oracle.xxxxxxxxx.ap-northeast-1.rds.amazonaws.com:1521
  ServerAliveInterval 60
  ServerAliveCountMax 3

Host webap/mysql
  hostname BBB.BBB.BBB.11
  port 22
  user ec2-user
  IdentityFile C:\Users\hoge\.ssh\webap.pem
  ProxyCommand C:\Windows\System32\OpenSSH\ssh.exe bastion -W %h:%p
  GatewayPorts yes
  LocalForward 53306   mysql.xxxxxxxxx.ap-northeast-1.rds.amazonaws.com:3306
  ServerAliveInterval 60
  ServerAliveCountMax 3
```

パスワード認証の時は`IdentityFile`の行は指定しなくて大丈夫です。

`ssh webap/oracle`や`ssh webap/mysql`でポートフォワーディングした先のWeb/APサーバーにSSH接続が成功すればひとまずOK。

```
>ssh webap/oracle
The authenticity of host 'BBB.BBB.BBB.11 (<no hostip for proxy command>)' can't be established.
ECDSA key fingerprint is SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'BBB.BBB.BBB.11' (ECDSA) to the list of known hosts.
Last login: Wed Nov 18 20:13:03 2020 from ip-BBB-BBB-BBB-11.ap-northeast-1.compute.internal
       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|
https://aws.amazon.com/amazon-linux-2/
[ec2-user@ ~]$
```

上記のコマンドでデータベースへの経路を確立していないとクライアントツールから接続できないので、使うときはターミナルから事前に接続して開きっぱなしにしておきましょう。

# クライアントツールからデータベースに接続
ポートフォワーディングしたローカルポートから接続します。

## Oracle SQL Developer
![.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96507/23c7cb25-2b50-5347-5621-b043f4271537.png)

## MySQL Workbench
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96507/334a560b-eb7b-9f51-f920-e409a0e5afce.png)

# その他、余談
## 多段じゃなくて踏み台から直接DB接続できる時のconfigの書き方

```:.ssh\config
Host webapp/mysql
  hostname AAA.AAA.AAA.10
  IdentityFile C:\Users\hoge\.ssh\bastion.pem
  user ec2-user
  port 22
  GatewayPorts yes
  LocalForward 53306   mysql.xxxxxxxxx.ap-northeast-1.rds.amazonaws.com:3306
```

## ポートフォワーディングした状態でローカルのDockerコンテナから接続したい

`localhost`じゃなくて`host.docker.internal`を指定しましょう。
[Vue.js]watch

<h1>watchはどんな時に使うのか</h1>
<p>あるデータが変わった時に特定の処理をしたい時に使う<span>
主に非同期処理の時に使用する</p>

```javascript
 watch:{
//numが変わった時にどんな処理をしたいか
   num:function(){
//非同期処理ではthisを使えないため最初にthisを他に代入しておく
     const vm = this
     setTimeout(function(){
//numを0にする
        vm.num = 0
//2秒後に
        },2000)
        }
```
<p>理解が怪しいため間違ってるかも。。。また勉強して更新しよう。。。</p>
capistrano自動デプロイにてgitエラー

# 前置き
Capistranoにて、再起動した際にエラーが出るため自分用にメモ

# エラー内容
```bash
# アプリケーションのディレクトリで実行する
$ bundle exec cap production deploy
```
を行なった際にgit:check項目でエラーになる。

```bash
00:00 git:check

Caused by:
SSHKit::Command::Failed: git exit status: 128
git stdout: Nothing written
git stderr: Permission denied (publickey).
fatal: Could not read from remote repository.
```
cloneする前に「git ls-remote」でリポジトリの中身を確認しているようですが、その時に「Permission denied（publickey）」とエラーが出ています。

# 対策
まず秘密鍵を確認します。

```bash
$ ssh-add -l
Could not open a connection to your authentication agent.
```

何か怒られた、、、ssh-agentを先に起動させないといけないみたいですね。

```bash
$ eval `ssh-agent`
Agent pid 1637
```

再度確認

```bash
$ ssh-add -l
The agent has no identities.
```
どうやら設定されていないみたいなので、gitのキーを設定してあげましょう。
gitのキーがそもそもない人は[こちらを参考に](https://qiita.com/nekotter222/items/73ebc373c4df2266807e)

```bash
$ ssh-add ~/.ssh/(gitの秘密鍵のフォルダ名)
```

再度自動デプロイ

```bash
# アプリケーションのディレクトリで実行する
$ bundle exec cap production deploy
```
無事デプロイ完了
【Git】Gitのデータ構造とは？(ローカル)

# はじめに
最近、Git/GitHubについて学習しております。
今回は、Gitの根本的な知識であるローカルのデータ構造についてアウトプットしたいと思います。
※今回の内容では、GitHub等のリモートリポジトリは含まれておりません。

# ローカルのデータ構造のエリア分け

![Git.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636476/4c77d568-67db-d510-8ae9-1c1e54b381bf.jpeg)


# 各エリアについて説明

上記で紹介した各エリアについて掘り下げていきたいと思います。

## ワークツリー

![ワークツリー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636476/ec3444e6-53f4-1c17-654c-c3f072809b8b.jpeg)


**ワークツリーとは、実際に作業を行う場所です。**
ファイルの作業完了後、以下コマンドでインデックスに登録します。

```bash
git add <ファイル名>
```


## インデックス(ステージ)

![インデックス.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636476/6c3fc6ec-0c7d-0ea9-2114-9127652e4ebb.jpeg)


**インデックスとは、リポジトリにコミットする準備をする場所です。**
別名、「ステージ」とも言います。

インデックス内に必要なファイルが準備できた場合、下記コマンドでリポジトリに登録します。

```bash
git commit -m "<コミットメッセージ>"
```

### インデックスがワークツリーとリポジトリの間にある理由

理由は、以下の2点になります。

- ワークツリー内の必要ないファイルを含めずにコミットを行える。
- ファイルの一部の変更だけをインデックスに登録してコミットが可能


## リポジトリ(ローカルリポジトリ)

![リポジトリ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636476/e2502953-7e7c-5575-c5df-de652d44917c.jpeg)


**リポジトリとは、ファイルやディレクトリの状態を記録する場所になります。**

今回、紹介しているリポジトリの位置づけとしては、**「ローカルリポジトリ」**になります。

### リモートリポジトリとローカルリポジトリの違い

- **リモートリポジトリ**

専用のサーバにコード等のファイルを配置して複数人で共有するためのリポジトリです。
例)GitHub,BitBucket

- **ローカルリポジトリ**

ユーザー自身の手元のマシン上に配置するリポジトリです。
※今回紹介しているリポジトリが、こちらにあたります。

# まとめ

- **ワークツリー**

ファイルの作業をする場所

- **インデックス(ステージ)**

コミット前にファイルを待機させておく場所

- **リポジトリ(ローカルリポジトリ)**

ファイルの変更履歴を保存する場所


# 参考
[Git： もう怖くないGit！チーム開発で必要なGitを完全マスター](https://www.udemy.com/course/unscared_git/)
[ワークツリーとインデックス](https://backlog.com/ja/git-tutorial/intro/04/)
[履歴を管理するリポジトリ](https://backlog.com/ja/git-tutorial/intro/02/)
【docker-compose】volumesの名無し・名ありボリュームの使い方。バインドマウント

個人メモです。

dockerやdocker-composeで指定するボリュームの使い方について。


##docker-compose.ymlにある２つのvolumesの違い

docker-compose.ymlの①外側のvolumesと②servicesの中のvolumesには違いがある。

```:docker-compose.ymlの例
version: "3.7"

volumes:
  todo-mysql-data:

services:
  mysql:
    image: mysql:5.7
    volumes:
      - todo-mysql-data:/var/lib/mysql
```

##①外側のvolumes

versionと同じ階層にあるvolumesは指定した名前のボリュームを用意している。

これを`名ありボリューム`という。

```
volumes:
  todo-mysql-data:
```

###名ありボリュームの特徴（メリット）

- 複数のコンテナでボリュームを共有できる。
- コンテナを削除しても消えない（コンテナに依存しない）




<br>
##②servicesの中のvolumes

各サービスの中のvolumesを**バインドマウント**と呼び、ボリュームとは区別される。

**コンテナ内のディレクトリとホスト側のディレクトリをマウント（共有化）**する処理を表す。

```
services:
  mysql:
    image: mysql:5.7
    volumes:
      - todo-mysql-data:/var/lib/mysql
```

上記例では、ボリューム`todo-mysql-data`をコンテナ内の`/var/lib/mysql`にマウントしている。

これで、/var/lib/mysqlのデータをボリュームに同期できる。



<br>
##バインドマウント（bind mount）の書き方
バインドマウントには記述方法がいくつかある。

| 項目 | バインドマウント | 内容 |
|:-:|:-:|:--|
| 名ありボリューム  | datavolume:/var/lib/mysql  | 指定したボリュームを、コンテナ内の指定ディレクトリにマウントする |
| 名無しボリューム  | /var/lib/data | コンテナ内のディレクトリのみ指定。ハッシュ値のボリュームが割り当てられる。（コンテナ削除で消える）  |
| ルートディレクトリを共有(相対パス)  | .:app  | コンテナ内の指定したディレクトリをホスト側の実行中ディレクトリにマウントする。  |
| 絶対パスで指定  | /opt/data:/var/lib/mysql  | コンテナ内の指定したディレクトリをホスト側の指定したディレクトリにマウントする。  |



####・ルートディレクトリを共有

`.:app`のような記述は頻繁に目にする。

これをすることで、コンテナ内のデータをホスト側で再現できる。（これがないとホスト側でデータが見れない）


####・名ありボリュームと名ありボリュームの主な用途

| 項目 | 名ありボリューム | 名無しボリューム |
|:-:|:--|:--|
| 主な用途  | ・(1)複数コンテナでボリュームを共有する（例：db）・(2)ホスト側への同期から除外する(例：node_module) | 他のコンテナと共有する必要はないが残しておきたいデータ（例：log）  |
| コンテナ削除 | 残る（コンテナに依存しない）  | 消える  |
Dockerでyarnを入れたはずなのに「ERROR: There are no scenarios; must have at least one」と怒られた時の対処法


# 背景

Dockerでyarnを入れたはずでしたが、いざ以下コマンドを叩いてみると怒られた

Dockerfileの中身

```
FROM ruby:2.5
RUN apt-get update && apt-get install -y \
    build-essential \
    libpq-dev \
    nodejs \
    postgresql-client \
    yarn
WORKDIR /kosare
COPY Gemfile Gemfile.lock /kosare/
RUN bundle install
```

yarnコマンドでエラー発生

```
root@5847e387581e:/kosare# yarn -v
ERROR: There are no scenarios; must have at least one.
```

# 解決策(一時的な解決策)
基本的には参考に記載のURLと同じことをすれば解決します。
私の場合はすでにrootで入っていたので、`sudo`と記載している部分はなくして順番に実行したら解決しました。

### 古いyarnを削除
```
sudo apt remove cmdtest
sudo apt remove yarn
```

### 最新を取得
```
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
```


### 最新を取得
```
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
```

### update
```
apt-get update 
```

### 再インストール 
```
apt-get install yarn
```

### バージョン確認 
```
yarn -v
```

# 解決策(根本的な解決策)
上記のやり方だと、dockerで再度bundle installし直した時に再度同じ事象が発生する。
Dockerfileでbuildした際に解決したいため、以下の2行をdockerfileに追記する。

```
RUN curl https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
```

Dockerfile(最終形)

```
FROM ruby:2.5
RUN curl https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update && apt-get install -y \
    build-essential \
    libpq-dev \
    nodejs \
    postgresql-client \
    yarn
WORKDIR /kosare
COPY Gemfile Gemfile.lock /kosare/
RUN bundle install
```

これでbuildしなおせば、yarnがちゃんと使えるはず。

# 参考
https://k-koh.hatenablog.com/entry/2020/04/02/143017
https://github.com/yarnpkg/yarn/issues/7329
https://qiita.com/MasatoraAtarashi/items/3f0317cd648ff63fa92c
[初心者]ブラウザでRailsのルーティングを確認する方法[小ワザ]

#ブラウザでルーティングを確認するコマンド
``$ rails s``でサーバーを立ち上げてから、(URL)の後ろに  

````
/rails/info/routes
````

とつけるだけです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/824345/3d1330c5-276f-88d5-bc1f-9ef1dd7186a2.png)
↑のような感じで、検索窓に直接打ち込めば大丈夫です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/824345/3b43453d-1df1-1ca9-867d-e18f15b8d5d1.png)
こんなに見づらかったルーティングが、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/824345/80c82da9-6db8-2230-2120-ffe5db87483b.png)
ブラウザで確認できるようになります。

見やすくなるのに加え、毎回毎回サーバーを落として、立ち上げて、という作業からも解放されるので、作業時間短縮には非常にオススメです！
useStateでstateを変更しているのにリアルタイムに再描画されない

##結論
一時変数にstateを入れて、配列やオブジェクトの場合は展開して新しい配列として扱いましょう。

```javascript

let temp = { ...props.samples };
```


##ダメなやり方
一時変数に入れてるから以下のようにすれば大丈夫でしょって思っても、これは参照渡しになっています。
同じオブジェクトをいじろうとしてもうまく行きません。新しい配列を作るために展開してあげる必要があります。

```javascript
//props.samples={hoge:"hoge", fuga:"fuga"}
let temp = props.samples; 
setState(temp)
```
Linux PATH環境変数

#【Linux PATH環境変数】

##PATH環境変数

<strong>PATH環境変数</strong>とは、使用したいコマンドのパスを保持する変数

コマンドを実行するとPATH環境変数に登録された場所をもとに検索、ファイルが該当すると実行される。

###・whichコマンド

指定されたコマンドがどのディレクトリに格納されているか、PATH環境変数で指定されたディレクトリパスをもとに探す
→指定されたコマンドは、完全パスで表示

###・findコマンド

特定のディレクトリを指定し、ファイルやディレクトリを探す
→PATH環境変数に指定されたディレクトリ以外にあるコマンドを探すことも可能
カプセル化について


##カプセル化とは
データとメソッドを１つのオブジェクトにまとめてその内容を隠蔽すること！だそうです。
オブジェクト外から直接アクセスすることを出来なくして、不正なアクセス・意図しない変更から守ることができるのです！

##オブジェクト指向の１種
オブジェクト指向の構成要素３つのうちの１つになるそうです。
構成要素は以下の３つです。

+ 継承
+ カプセル化
+ ポリモーフィズム

##カプセル化するには？
データを保護することがカプセル化です。
その保護をするために、アクセス修飾子と言うものを使ってアクセスを制限していきます。

##アクセス修飾子
アクセス修飾子には制限の範囲に合わせて使うものが変わってきます。
以下が一覧になります。
私も使いこなせているわけではないですが。（privateしか使ったことありません）
カプセル化ではprivateを使用します。

+ open	        モジュール外からもアクセスできる。 
+ public	モジュール外からもアクセスできる。 サブクラス化されない。 overrideできない。
+ internal	モジュール内ならアクセスできる。 デフォルトでこれになっている。
+ fileprivate	ファイル内ならアクセスできる。
+ private	クラスなど宣言内でしかアクセスできない。(カプセル化に使用)
 
##使ってみた
実際にカプセル化を学ぶきっかけになったコードになります。
tableViewを使用するアプリを作成していて、セルに表示する内容を書くコードだけ別のクラスに書くように指示がありました。
この場合、別のクラスでcheckIconやlabelを使用しようとすると、エラーになります。

```swift
class TableViewCell: UITableViewCell {
    //privateを付けることで他のクラスからアクセスできない
    @IBOutlet private var  checkIcon: UIImageView!
    @IBOutlet private var  label: UILabel!
    
    func configure(isChecked: Bool, name: String) {
        //チェックされているときには表示して、チェックされていない時は表示しないという処理を書く
        checkIcon.image = nil
        if isChecked == true {
            checkIcon.image = UIImage(named: "check")
        }else{
            checkIcon?.image = nil
        }
        label.text = name
    }
}
```

##カプセル化した値は外から変更できないのか？
結論：できます。
そもそもカプセル化とはデータを保護し、異常なデータ変更や意図しない変更を防ぐためにあります。
直接変更しなければ良いのです。
その方法は、関数を使うことです。
１度関数を通せば意図的な変更になりますし、異常な変更を加えるコードであっても、その変更に対応できるコードを関数内に書くことでエラーを防ぐことができるそうです。

##カプセル化はオブジェクト指向
データを直接変更するのではなく（バグが発生する可能性があるため）、関数などのオブジェクト自体がデータの変更を行う。これがオブジェクト指向になります。
カプセル化はオブジェクト指向の重要な構成要素になります。

##参考サイト
https://jpazamu.com/encapsulation/
https://dev.classmethod.jp/articles/swift3_scoped_access_level/
[小ネタ]no_logで地味な節約術

# 概要

完全に小ネタです。
AWXもしくはAnsible Towerでtemplateモジュールを用いるとファイルの差分がログに出力されます。
なので、templateの使用頻度やtemplateのテキスト量に比例してログ量も増えます。
ログ量が増えるとDBの容量も消費するし、実行結果を表示するI/Oも増えます。
これを抑制するために、**[no_log](https://docs.ansible.com/ansible/latest/reference_appendices/logging.html?highlight=no_log)**を用います。
通常は機密情報を非表示にするために用いますが、上記のような理由のようにログ出力を抑えたい場合にも用いることができます。
ansible.cfg、play、taskのそれぞれで設定できますが、いざという時のためにデバックできるように個人的にはtask単位が望ましいと思います。

# 例

```config:ansible.cfg
[defaults]
host_key_checking=False
retry_files_enabled=False
interpreter_python="/usr/bin/env python3"
timeout=10

[ssh_connection]
retries=6
```

```yaml:playbook.yml
---
- name: No log
  hosts: localhost
  connection: local
  gather_facts: False
  # play全体の出力を抑制したい場合
  # no_log: True
  tasks:
    - template:
        src: "./template.j2"
        dest: "/tmp/template"
        mode: "u=r,g=r,o="
      become: yes
      # 特定のタスクのみを抑制する場合
      # no_log: yes
```

テンプレートの内容は何でもよい。
下記は実際に使われているrsyslogの設定ファイルになります。

```config:template.j2
$template mytemplate, "%timegenerated% %hostname% %programname% [%syslogpriority-text%] %msg%\n"
*.info;mail.none;authpriv.none;cron.none                /var/log/messages;mytemplate
cron.*                                                  /var/log/cron;mytemplate
local7.*                                                /var/log/boot.log;mytemplate
authpriv.*                                              /var/log/secure;mytemplate
```

実行結果に↑のテンプレートの内容(ログレベルはNormal)が出力されます。
既存のファイルを上書きする場合は、その差分が出力されます。
下記は新規ファイルのため、全行が出力されます。
なお、**差分がない場合は出力されません**。

```text:実行結果(no_log:なし)
PLAY [No log] ******************************************************************
TASK [template] ****************************************************************
--- before
+++ after: /var/lib/awx/.ansible/tmp/ansible-local-1679g0oolph1/tmpm03q6ezu/template.j2
@@ -0,0 +1,5 @@
+$template mytemplate, "%timegenerated% %hostname% %programname% [%syslogpriority-text%] %msg%\n"
+*.info;mail.none;authpriv.none;cron.none                /var/log/messages;mytemplate
+cron.*                                                  /var/log/cron;mytemplate
+local7.*                                                /var/log/boot.log;mytemplate
+authpriv.*                                              /var/log/secure;test
changed: [localhost]
PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

```
テンプレートの内容が出力されません。

```text:実行結果(no_log:あり)
PLAY [No log] ******************************************************************
TASK [template] ****************************************************************
ok: [localhost]
PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
```

# あとがき

ログ出力を抑えるは他にもありますので、必要に応じてご利用くださいませ。

- display_skipped_hosts・・・スキップタスクの表示/非表示
- display_ok_hosts・・・okタスクの表示/非表示
- display_args_to_stdout・・・各タスクへの引数の表示/非表示
【論文メモ】Underspecification Presents Challenges for Credibility in Modern Machine Learning


### 概要

機械学習モデルが現実問題において精度が低下する理由は、Underspecification（仕様不足）が原因である。テストデータセットにおいて同一精度を出すモデルのパラメータが多数あるので特定できないことを仕様不足と言っている。同じ訓練プロセスを使っても実際の利用では質の低いモデルが生み出されてしまう可能性もある。
論文で紹介する複数の分野で同様の問題が発生する。
上記の問題が起きないように実際の利用を想定したストレステストの設計、正則化をすることが重要である。



### 元論文のURL
https://arxiv.org/abs/2011.03395
cypressでCSVダウンロードをテストする

## まとめ

cypressの[公式リポジトリー](https://github.com/cypress-io/cypress-example-recipes/tree/master/examples/testing-dom__download)に例があるからそちらを参照するとできる。
日本語の記事が検索に引っかからなかったから、記事を書いてみました。
エイリアス的な感じですね。

## 要点

- cypressにはブラウザのダウンロード機能をハックする仕組みがあり、ダウンロードディレクトリをDownloadsから変えることができる。つまりローカルに持ってこれる。
- ローカルに持ってきたCSVファイルをneatCSVでパースしてオブジェクト化する。
- テストする。


※cypressはブラウザのダウンロードAPIをハックする以外にも[いろんな事](https://docs.cypress.io/api/plugins/browser-launch-api.html)ができる

## 実際に書いてみてあると便利なコマンド

以下の３つのコマンドを用意しているとテストしやすいかなって考えます。

|コマンド|説明|
|------------------|--------------------------|
|allowDownloadPopup|ダウンロードポップアップを自動でYESにするcypressコマンド|
|readCSV|csvファイルを読み込んでパースしてオブジェクト化するcypressコマンド|
|detectEncoding|csvファイルを読み込んでエンコーディングを調べるcypressコマンド|

```js
const path = require('path');
const neatCSV = require('neat-csv');
const encoding = require('encoding-japanese');

const defaultDownloadFolder = 'cypress/downloads';

export function allowDownloadPopup(downloadPath, options) {
  // The next command allow downloads in Electron, Chrome, and Edge
  // without any users popups or file save dialogs.
  if (Cypress.browser.name !== 'firefox') {
    // since this call returns a promise, must tell Cypress to wait
    // for it to be resolved
    cy.wrap(
      Cypress.automation('remote:debugger:protocol', {
        command: 'Page.setDownloadBehavior',
        params: { behavior: 'allow', downloadPath: downloadPath || defaultDownloadFolder },
      }),
      { log: false, ...options },
    );
  }
}

export function readCSV(filename, downloadFolder = defaultDownloadFolder, options = {}) {
  const filepath = path.join(downloadFolder, filename);
  return cy.readFile(filepath, { timeout: 15000, ...options }).then(neatCSV);
}

export function detectEncoding(filename, downloadFolder = defaultDownloadFolder, options = {}) {
  const filepath = path.join(downloadFolder, filename);
  return cy
    .readFile(filepath, { timeout: 1500, ...options })
    .then((data, options) => encoding.detect(data));
}
```

## 使い方

#### allowDownloadPopup

```js
beforeEach(function(){
 cy.allowDownloadPopup()
})
```

#### readCSV

`test.csv` を読み込んで、レコード数と最初のレコードの内容をテストする。

```js:test.csv
a,b,c
1,2,3
```

```js
cy.get('button').contains('CSV(UTF-8))').click()
cy.readCSV('test.csv')
  .then(list => {
     expect(list, 'number of records').to.have.length(1)
     expect(list[0], 'first record').to.deep.equal({
	a: 1,
	b: 2,
	c: 3
     })
  })
```

#### detectEncoding

`test.csv` を読み込んで、エンコーディングが `UTF-8` であることをテストする。

```js
cy.detectEncoding('test.csv').then(encoding => {
   expect(encoding, 'encoding').to.equal('UTF-8')
})
```

以上です。
Reduxの基本的な使い方　例付き

<h1>Reduxの基本的な書き方</h1>

<h3>1 actionの作成</h3>
<p>actionは、取り扱いたいデータの概要を書いているイメージ。</p>
<pre> 
//reducks/dots/action.jsx
export const ADD_DOT = "ADD_DOT";
export const add_dot = (dot) => {
return {
		type: ADD_DOT,
		payload: dot,
	};
};
</pre>

<p>※export const ADD_DOT の意味…　type名である"ADD_DOTS"を変数化することで、type名をtypoしたときに、その旨がエラー文にでるようになる。</p>

<h3>2 reducerの作成</h3>
<p>actionで作ったデータをどう変更したいかを定義しているイメージ</p>

<pre>
//reducks/dots/reducer.jsx

import * as Actions from "./action";
import initialState from "../store/initialState"; //次に作る

export const DotReducer = (state = initialState, action) => {
	switch (action.type) {
		case Actions.ADD_DOT:
			return [...state, action.payload];
		default:
			return state;
	}
};
</pre>


<h3>3 initialStateの定義</h3>

<pre>
const initialState = []
export default initialState
</pre>
<p>このinitialStateが、reducerのstateの初期状態になる。 <p>


<h3>4 Storeの作成</h3>

<pre>
import { createStore as reduxCreateStore, combineReducers } from "redux";
import { DotReducer } from "../dots/reducers";

export default function createStore() {
	return reduxCreateStore(
		combineReducers({
			dots: DotReducer,
		})
);
}
</pre>


<h3>5 Storeの中身を全てで使えるように設定</h3>
<pre>
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { applyMiddleware, compose } from "redux";
import reduxThunk from "redux-thunk";
import App from "./App";
import createStore from "./redux/store/store";

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; //Redux DevToolsを使うために定義
export const store = createStore(composeEnhancers(applyMiddleware(reduxThunk)));

ReactDOM.render(
	< Provider store={store}>
		< App />
	< /Provider>,
	document.getElementById("root")
</pre>

<p>これでAppコンポーネントにネストされてるものすべてを含めて、
storeで管理している内容が使えるようになった！！いえい！🎉</p>

<h3>6 Actionを使っていく</h3>
・actionを使いたいコンポーネントに移動
・useDispatchと、actionをimport
・useDispatchを定義
・actionを使いたいところで「dispatch(アクション名(propsとして渡したいデータ));」


<pre>

import { useDispatch } from "react-redux";
import { add_dot } from "../../redux/dots/action";

//....

const MiniForm = () => {
	const dispatch = useDispatch();
	const onSubmit = (data) => {
                //...
		});
		dispatch(add_dot(data));
	};
	return (
		< form onSubmit={handleSubmit(onSubmit)}>
		//...
		< /form>
	);
};
export default MiniForm;

</pre>

これでactionの中に引数に指定したデータ(今回ならdata)が渡る→そのactionに該当するreducerが走る→storeに保管される 、まで行われる


<h3>7 Storeに保管されたstateを使う</h3>
・useSelectorのimport
・ useSelector((state) => state.dots)を定義。dotsはreducerのexport名（Store参照)
↓
dotというreducerに入っているstateが使えるようになった。
あとは使っていくのみ。(今回はmapで広げる)

<pre>
import React from "react";
import { useSelector } from "react-redux";

export default function Base() {
	const dots = useSelector((state) => state.dots);
	console.log(dots); //これでstoreからやってきたdotsが見れる！
	return (
		< React.Fragment>
			< Header />
			{dots.map((dot) => {　    //storeからもらってきたdotsを使ってます
				return < Dots dot={dot} />; 
			})}
			//...
			< Footer />
		< /React.Fragment>
	);
}

</pre>
社内業務のシステムをWebで作ろう！

##投稿の動機
@NP_Systemsさんの **製造業において、Pythonに加えてWebも活用して飛躍しよう** の記事を見て正にキャッチ‐な話題でしたので、社内での活動状況を投稿しようと思いました。現在私は定年後の再就職先として広島市内の名盤製造業に嘱託として勤めています。仕事内容は社内業務システム「業務支援・改」の構築・保守です。
##何故Webなのか
今のシステムは経理・給与・販売管理（移行開発中）を除く、製造業務のほぼ全般をWebシステムで運用しています。巷では業務システムはクライアント・サーバータイプ（VB, VC, Java 等）で作られているみたいですが、かなり早い段階からWebで開発している身としては、楽なのに何故Webで開発しないのかが不思議でした。実際WebでVBよりも高速な伝票入力画面を作ることができます。現役時代に納品したシステムはOSのバージョンアップを行っても問題無く使えていますし、カーソル移動も[Enter]キーで[tabIndex]順に移動できます。端末へのインストールも不要で遠地の端末が壊れても簡単に機器の入れ替えができます。ハードを更改してもシステムを更改する必要が無いのです。環境に依存しないので製造現場ではiPadで運用している部署も有ります。一度作ったシステムを要件が変わらないのに再度開発するのは、資産が残らないという意味で馬鹿らしいと感じています。
##実運用画面のサンプル
実際に現場でどんな画面を使っているのかを見てみましょう。
■ 出荷計上一覧（出荷予定・実績の一覧）
![出荷計上一覧画面.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425631/2b06528e-cf6b-226e-4de4-1d467722d358.jpeg)
■ 出荷計上保守（俗に言う売上伝票、在庫出納と連動）
![出荷計上保守画面.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425631/df1b09fb-390c-7cb4-6df3-f1f69f64cec1.jpeg)

■ 納品書 先頭ページ (PDF出力)
![納品書01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425631/bd140f32-2a0e-9a4a-6aed-190398c19b77.jpeg)
■ 納品書 最終ページ (PDF出力)
![納品書02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425631/7fe09ca3-8465-d07e-6cb5-1bbc32cd670e.jpeg)
■ 物品受領書 (PDF出力)
![納品書03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425631/9795c6ea-0c92-e6a1-349f-53f538aa769a.jpeg)
■ 品目保守（製品の材料・工程と工数、他各種情報）
![品目保守.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425631/43a685f0-c0e7-5fc7-cb26-b26aa5218acc.jpeg)
■ 生産予定作成（生産オーダーより生産予定を作成）
![生産予定作成画面.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425631/3c1b1e86-4b46-c10e-46e4-187635dbd7c7.jpeg)
■ 生産状況一覧（生産ロットの進捗状況を把握）
![生産状況一覧.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425631/5f88f046-14ae-1968-ebcb-1ffba46c6399.jpeg)
■ 生産日程（カレンダー上で予定と進捗を確認）
![生産日程画面.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425631/6a3ef04a-5c0c-abc2-1cea-894daca466b3.jpeg)
挙げれば切が無いのでこれぐらいにしておきますが、これらはたった一人で設計・施工・導入したものです。**意外とWebシステムって簡単に作れるので皆さんもWebで開発する事を強くお勧めします。**
##開発環境
**全てオープンソースです。**Java8 (pdfBox), JavaScript, Tomcat9, mariaDB10, JQuery (ほんのチョットだけ), それと検索時に照合が出来ない事が有るので、入力時にANKは半角、カタカナは全角、濁音・半濁音は１文字に合成しています。**殆どが手作りなので、皆さんも安価にリーズナブルなシステムを構築できる事請け合いです。**生産計画作成画面はJavaScriptでコメントを入れて1,200行強位です。今日嵌って対応していた見積積算画面は少し凝っていて2,200行強でした (共通ライブラリ除く)。意外と手軽だと思いませんか。
##まとめ
実は自分の周りに同じ様な事をしている人がいないので、最近疎外感を感じていたところでした。**この投稿を切っ掛けにして多くの人にWebで業務システムを開発して貰いたいと思っています。**本も買ったけどネットに転がっている情報でプログラムを作れているので、**Webによる業務アプリケーション開発は決して敷居の高いものでは無いのです。みんなでWeb開発をやりましよう！**
【Docker】コンテナ内からホストにアクセスする方法。http://host.docker.internal:

コンテナの中からポートにアクセスすることができる。
WEBページの内容を表示する`$curl URL`コマンドで確認する。


接続方法には、(1)コンテナのポートを指定する方法と、(2)ホストのポートを指定する方法がある。

##アクセス手順

1) 起動中のコンテナ内に入る

・`docker exec -it [コンテナ名] bash`

これでコンテナ内のbashにアクセスできる。コンテナによってはbashではなくshの場合もある。



2) curlでhttｐをリクエストする

▼コンテナのポートに直接アクセスする場合
・`curl http://[コンテナ名]:[コンテナ側のポート]`


▼ホスト側のポートにアクセスする場合
・`curl http://host.docker.internal:[ホスト側のポート]`



##実例

```:起動中のコンテナを確認
$ docker ps
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS                                            NAMES
d4ae7996f53c        django_web                  "python manage.py ru…"   10 hours ago        Up 10 hours         0.0.0.0:8100->8000/tcp                           django_web_1
```

・`0.0.0.0:8100->8000/tcp`これが重要！

「ホスト側のポート番号 -> コンテナ内のポート番号」

「0.0.0.0」はlocalhostではなく、全てのポートからのアクセスを表す。

なので、「0.0.0.0:8100 -> 8000」は全ての8100へのアクセスをコンテナ内の8000番ポートにマッピングするという意味になる。


<br>

```:コンテナ内に入る
$ docker exec -it django_web_1 bash
root@d4ae7996f53c:/code#
```

コンテナ名「django_web_1」のbashを起動。


<br>
###コンテナのポートに直接アクセスする場合

```:
root@d4ae7996f53c:/code# curl http://django_web_1:8000
```

`http://コンテナ名:コンテナ側のポート番号`、これでコンテナ指定したポートにアクセスできる。

<br>
間違えてホスト側のポートを指定するとエラーになる。

```:エラー例
root@d4ae7996f53c:/code# curl http://django_web_1:8100
curl: (7) Failed to connect to django_web_1 port 8100: Connection refused
```



<br>
###ホスト側のポートにアクセスする場合
ホスト側のポートにアクセスする場合は`host.docker.internal:ホスト側のポート番号`を使う。

```:
root@d4ae7996f53c:/code# curl http://host.docker.internal:8100
```

`host.docker.internal`はdocker側で用意してあるDNS。ホスト側のlocalhostに該当する。

これは、コンテナの外側から
`curl http://localhost:8100`を実行するのと同じ。



<br>

```:コンテナから出る
root@d4ae7996f53c:/code# exit
$
```

以上。
Linux プロセス

#【Linux プロセス】

##2つのプロセス

<strong>実ユーザID（real user ID）</strong>は、プロセスを起動したユーザ、プロセスの所有者

<strong>実効ユーザID（effective user ID）</strong>は、プロセスが実行された時に権限を持つユーザ
（カーネルは、プロセスの実行権限を実効ユーザID、実効グループIDで判断する）

##SUIDとSGID

<strong>SUID（Set User ID）</strong>は、どのユーザが実行しても、実効ユーザIDがファイル所有者ID
パーミッションに「4000」または、所有者（u）+「ｓ」を付与

例）/usr/bin/passwd

<strong>SGID（Set Group ID）</strong>は、ファイルのグループIDが実効グループID
パーミッションに「2000」または、グループ（g）+「ｓ」を付与

※SGIDが設定されたディレクトリ以下でファイルやディレクトリを作成すれば、SGIDが設定されたディレクトリのグループが引き継がれて設定される。

##スティッキービット

<strong>スティッキービット</strong>が、設定されたディレクトリ以下のファイルとディレクトリは、実際のアクセス権に関係なく、所有者とrootユーザのみ名前の変更と削除が可能
chmodコマンドで指定する場合、「1000」または、その他のユーザ（o）+「t」を付与

問）スティッキービットが、一般的に設定されているディレクトリは？（既に設定済）
答）/tmp