OmniAICreator/Qiita-1.07M huggingface dataset:
pythonさん

勉強URL


<p>お勧めサイト</p>

https://utokyo-ipp.github.io/index.html

https://yolo.love/

https://datawokagaku.com/python_for_ds_summary/


train[train["week"]=="月"]　あるデータだけ取り出せる
train[train["y"]>=150].head()

曜日が月曜日の時のyの平均値を見てみましょう
train[train["week"]=="月"]["y"].mean()

.trainのtemperatureが平均以上のデータだけを選択してみよう
train[train["temperature"]>=train["temperature"].mean()]

train[["y","week"]]    trainで今度はyとweekの2つのカラムを選択したい

df[(df["week"]=="月") & (df["kcal"]<500)]

import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
%matplotlib inline

年の新しいカラム名はyearとし、月の新しいカラム名はmonthとしましょう　　2013-11-18	
train["year"]=train["datetime"].apply(lambda x : x.split("-")[0])
train["month"]=train["datetime"].apply(lambda x : x.split("-")[1])

train["y"].plot()  折れ線グラフ

ax = train["y"].plot(figsize=(12,4),title="グラフ")
ax.set_xlabel("time")
ax.set_ylabel("y")

train["y"].plot.hist() ヒストグラム

train[["y","week"]].boxplot(by="week") 箱ひげ図

train.isnull().any()  欠損ち

train.isnull().sum()

train.fillna(0) 欠損地を０で保管

ある列に欠損値があった場合のみ、その行を削除したい場合はオプションとしてsubset=[ ]を使います
train.dropna(subset=["kcal"])

train[["y","temperature"]].corr() 相関関係

 train.plot.scatter(x="temperature", y="y", figsize=(5,5))                                  相関係数は散布図 


def exercise_judge(ex):
    if ex  <= 3:
        return "low"
    elif 3<ex<6:
        return"mid"
    else:
        return"high"


##df.loc[:,"新カラム名"]=df.loc[:,"前のカラム名"].apply(exercise_judge)

値が「お楽しみメニュー」であれば１、そうでなければ0とする自作関数を作りましょう
自作の関数を作る為には、defを使います
def jisaku1(x):
    if x =="お楽しみメニュー":
        return 1
    else:
        return 0

jisaku1関数とapply関数を使って、trainとtestの新たなカラムfunを作りましょう
train["fun"] = train["remarks"].apply(lambda  x:jisaku1(x))
test["fun"] = test["remarks"].apply(lambda x:jisaku1(x))

データの型を整数（int）に変換しましょう
データの型を変換したい場合は、astype関数を使います
オプションにはデータの型を入れます。今回は整数に変換したい為、np.intと書きます
変換したものは、もとのカラムに代入しなおしましょう
train["year"] = train["year"].astype(np.int)
train["month"] = train["month"].astype(np.int)

testX = test.copy()
#ピンポイントで変える場合
df = df.rename(columns={"平均気温":"平均"}).head()

dura = pd.crosstab(duration_bining,train["y"],margins=True)
dura["rate"] = dura[1]/dura["All"]

train.iloc[ 開始行:終了行, 開始列:終了列 ]と書くことで、列・行を数字で指定して書くことができます
開始から終了まで全てを取り出したい場合は、「:」だけでよく、数字を省略することも可能です
trainX = train.iloc[ :, 0:17 ]
AmazonLinux上でNode.jsとYarnをインストールする

下記を参考にさせていただきました。

https://blog.serverworks.co.jp/tech/2020/01/19/rails6/

https://github.com/nodesource/distributions
## 環境
```
$ cat /etc/system-release
Amazon Linux release 2 (Karoo)
```

## Node.jsのインストール
```
$ curl -sL https://rpm.nodesource.com/setup_12.x | sudo bash -
$ sudo yum install -y nodejs
```

## Yarnのインストール
```
$ curl -sL https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
$ sudo yum install -y yarn
```
以上で完了です
画面遷移図　検討メモ

#　書いたきっかけ
ポートフォリオ用のWebアプリ作成に当たり、必要なページとその遷移関係を検討したい。

##　使ったツール
Figma + Autoflow

##　完成図

![スクリーンショット 2021-04-27 23.13.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599665/34062b51-d8c7-dd06-8738-b2756f4e3a19.png)
[IPアドレス変更]、[FW無効化/有効化] を簡略化するバッチファイル

##環境
Windows10

##作成動機
インフラエンジニアは、NW機器にPC直結する際にFWを無効化したり、IPアドレスを変更することが多々ある。
頻度の高さの割に、その手順が手間なので作成した。

これでFWの無効化/有効化はかなり楽になる！

##バッチファイルの設定方法
1. 以下の`バッチファイルの中身`をコピーする。
1. メモ帳などのテキストエディタにペーストする。
1. 拡張子を.batにして保存する。保存場所はCドライブ直下とか適当に。
1. 保存したbatファイルのショートカットをデスクトップに作成する。
1. ショートカットを右クリックして`プロパティ　＞　ショートカットタブ　＞　詳細設定　＞　管理者として実行`にチェックを入れる。

##バッチファイルの使用方法
1. `バッチファイルの設定方法`で作成したショートカットをダブルクリックする。
1. 「このアプリがデバイスに変更を加えることを許可しますか？」で「はい」を選択する。
1. コマンドプロンプトで以下の表示が出たら使用したい番号を入力する。

```
***********************
1. FWを無効化
2. FWを有効化
3. IPアドレスをDHCPで自動取得
4. IPアドレス/ゲートウェイを設定
5. 終了
***********************
1～5を選択してください:
```


##バッチファイルの中身

```bat:Change_IPadd.bat
@echo off
setlocal enabledelayedexpansion
:START
echo;
echo ***********************
echo 1. FWを無効化
echo 2. FWを有効化
echo 3. IPアドレスをDHCPで自動取得
echo 4. IPアドレス/ゲートウェイを設定
echo 5. 終了
echo ***********************
set /p num=1～5を選択してください: 
 
if %num%==1 (
  netsh advfirewall set allprofiles state off
) else if %num%==2 (
  netsh advfirewall set allprofiles state on
) else if %num%==3 (
rem  netsh interface set interface イーサネット disable
rem  netsh interface set interface イーサネット enable
  netsh interface ipv4 set add name="イーサネット" source=dhcp
) else if %num%==4 (
  set /p add=IPアドレス[xxx.xxx.xxx.xxx]: 
  set /p msk=サブネットマスク[xxx.xxx.xxx.xxx]: 
  set /p gw=ゲートウェイ[xxx.xxx.xxx.xxx]: 
  netsh interface ipv4 set add name="イーサネット" source=static addr=!add! mask=!msk! gateway=!gw!
) else if %num%==5 (
  exit
) else (
  echo 1～5のどれかを選択してください
)
goto START
cmd /k
```
LeetCode日本語修行14日目- [938-指定範囲内二分探索木のSUM]

###Range Sum of BST
#####参考：https://leetcode.com/problems/range-sum-of-bst/
###問題の内容:
###例:
例1:
Input: root = [10,5,15,3,7,null,18], low = 7, high = 15
Output: 32

```
    10
  5    15
3   7     18 
```


例2:
Input: root = [10,5,15,3,7,13,18,1,null,6], low = 6, high = 10
Output: 23

```
     10
   5    15
 3  7  13 18
1  6
```
###ヒント:
The number of nodes in the tree is in the range [1, 2 * 104].
1 <= Node.val <= 105
1 <= low <= high <= 105
All Node.val are unique.

---

DFSを使って、範囲内のvalueを全部プラスするなら、解決できます。

```Kotlin
/**
 * Example:
 * var ti = TreeNode(5)
 * var v = ti.`val`
 * Definition for a binary tree node.
 * class TreeNode(var `val`: Int) {
 *     var left: TreeNode? = null
 *     var right: TreeNode? = null
 * }
 */
class Solution {
    fun rangeSumBST(root: TreeNode?, low: Int, high: Int): Int {
        if(root == null){
            return 0
        }
        if(root.`val` < low){
            return rangeSumBST(root?.right,low,high)
        }
        if(root.`val` > high  ){
            return rangeSumBST(root?.left,low,high)
        }
        return  root.`val` + rangeSumBST(root?.right,low,high) +  rangeSumBST(root?.left,low,high)
    }
}

```
Azure Functions x Twitter4Jで乃木坂46への愛を叫ぶ

https://qiita.com/official-events/22637c675c61a797a24f

<hr>

Azure Functionsから自動的にツイートするプログラムをJavaで作りました。乃木坂ちゃんへの愛を叫ぶだけです(^^;

https://twitter.com/kikutaro_/status/1387013664440389632?s=20

Twitterの予約投稿機能、Bufferのようなサービス、ノーコードツールなどを使って同じことはできますが、Javaのコードで自由に処理を書けるので、より自由度が高い気がします。

Javaには[Twitter4J](https://twitter4j.org/ja/index.html)という素晴らしいツールがあるので簡単に実現できます。だいぶ昔に書いた記事でTwitter Developersの画面が古いですが、興味ある方は[こちら](https://kikutaro777.hatenablog.com/entry/2013/07/19/195626)もご参照くださいm(_ _)m

# 環境構築

Azure Functionsをローカル環境で実行するには.NET Coreなどのインストールが必要です。今回はMicrosoftが提供している.NET CoreのDockerイメージをベースにしました。Azure CLI、JDK、azure-functions-core-toolsなど必要なものを入れています。

```docker
FROM mcr.microsoft.com/dotnet/core/sdk:3.1

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    openjdk-11-jdk && \
    apt-get install -y maven

RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash

RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg
RUN mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg
RUN sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/debian/$(lsb_release -rs | cut -d'.' -f 1)/prod $(lsb_release -cs) main" > /etc/apt/sources.list.d/dotnetdev.list'

RUN apt-get update
RUN apt-get install azure-functions-core-tools-3
```

# プロジェクトの準備

Mavenのazure-functions-archetypeを使ってプロジェクトを作成したらpom.xmlにTwitter4Jの依存性を追加します。

```xml
<dependency>
	<groupId>org.twitter4j</groupId>
	<artifactId>twitter4j-core</artifactId>
	<version>4.0.7</version>
</dependency>
```

あとはsrc/main/resourcesの配下にtwitter4j.propertiesファイルを作成してTwitterで発行した各種キーを設定します。

```
debug=true
oauth.consumerKey=xxxxx
oauth.consumerSecret=xxxxx
oauth.accessToken=xxxxx
oauth.accessTokenSecret=xxxxxx
```

azure-functions-archetypeで作ったプロジェクトにはコードの雛形が用意されている（Function.java）ので、その中に以下のコードを追加しました。Cronのように定期実行されるFunctionです。

```java
@FunctionName("keepAlive")
public void keepAlive(
@TimerTrigger(name = "keepAliveTrigger", schedule = "0 */30 * * * *") String timerInfo,
    ExecutionContext context
) {
    Twitter twitter = new TwitterFactory().getInstance();
    try {
        Status updateStatus = twitter.updateStatus("乃木坂46が大好きです！");
        context.getLogger().info(updateStatus.getText());
    } catch (TwitterException e) {
        e.printStackTrace();
    }
}
```

やったことはこれだけです。あとはビルドして

```
mvn clean package -DskipTests
```

実行します。

```
mvn azure-functions:run
```

このときハマった点は別途、以下の記事でまとめました。

https://qiita.com/kikutaro/items/dca273dfe5712bb3ecaf

ローカル環境でうまく動いたら、あとはデプロイするだけです。

```
mvn azure-functions:deploy
```

Azure Functionsといっても中身は普通のJavaプログラムなので、Twitter4Jのようなライブラリを利用できるのが嬉しいです。今回はツイートするだけの簡単なものでしたが、他のライブラリと合わせて面白いものが色々と作れそうです。
GCEに起動したredashでpythonを利用できるようにするまで

## GCEで起動
https://redash.io/help/open-source/setup#-Google-Compute-Engine

```
gcloud compute images create "redash-8-0-0" --source-uri gs://redash-images/redash.8.0.0-b32245-1.tar.gz
gcloud compute instances create redash --image redash-8-0-0  --zone asia-northeast1-a
```

## GCEでHTTPアクセスを許可
VM インスタンスの詳細 > 編集 > HTTPトラフィックを許可する

(ここまででIPにアクセスするとredashが開きます。)

## pythonの設定
サーバーにSSHして、以下を実行
(`/opt/redash`に`docker-compose.yml`やenvファイルが配置されています)

```
sudo -s
cd /opt/redash
echo 'REDASH_ADDITIONAL_QUERY_RUNNERS=redash.query_runner.python' >> env
docker-compose up -d
```

以上でpythonを利用できる状態になります。

## Googleアカウントでのログイン
※ DNSでredashのIPにドメインを割り当てておく必要があります

以下の設定でGoogleログインができるようになります。


- https://redash.io/help/open-source/admin-guide/google-developer-account-setup
- https://redash.io/help/open-source/setup#Google-OAuth-Setup

```
cd /opt/redash
# 上記で作成したID/SECRETをenvに書き込んでrestart
echo 'REDASH_GOOGLE_CLIENT_ID=XXX' >> env
echo 'REDASH_GOOGLE_CLIENT_SECRET=XXX' >> env
docker-compose up -d server
```

![スクリーンショット 2021-05-12 14.57.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236425/0f504578-49c1-3aef-ac75-83285365241c.png)

### 許可するアカウントのドメイン指定

setting の Allowed Google Apps Domains で指定します。
例えばここに `example.com` を指定すると `user@example.com` というようなexample.comのgoogleアカウントはログインできるようになります。
初回ログイン時に、redashユーザーがdefaultグループで新規に作成されます。

![スクリーンショット 2021-05-12 22.47.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236425/31440896-e0e9-9275-fd71-304893b1f922.png)



## その他

### python外部モジュールの追加

1. 以下コマンドでworkerにインストール
1. データソースの`Modules to import prior to running the script`にカンマ区切りで追記(e.g. `json,urllib,sys`)

```
# 開発環境
docker-compose exec worker pip install {{package}} 
docker-compose restart 

# GCE環境
docker-compose exec adhoc_worker pip install {{package}} --user
docker-compose exec scheduled_worker pip install {{package}} --user 
docker-compose restart 
```

### データのバックアップ、リストア

https://discuss.redash.io/t/db-backup-of-self-hosted-redash/3665/3

backup

```
docker-compose exec postgres pg_dump -U postgres > backup_redash_postgres.sql
```

restore

```
cat ~/backup_redash_postgres.sql | docker exec -i redash_postgres_1 psql -U postgres
```

### localからのファイルアップロード
ブラウザからのsshでファイルをuploadできます

https://cloud.google.com/compute/docs/instances/transfer-files?hl=ja#transferbrowser
【初心者向け】CSSを圧縮して軽量化できるオンラインツールを紹介

# どうも7noteです。CSSを簡単にmin化させて軽量化できるツールを紹介。



WEB制作において、**ページの読み込み速度は命に関わります。**（そこまでではないです。）


画像を圧縮しておくのと同様に、理論上はソースファイルも1文字でも短いほうが読み込み速度は上がります。

そんなときに目でいちいちチェックしていられないので、**CSSを1クリックで圧縮してくれるWEBツールを紹介。**

--- 

**【1クリックでCSSを圧縮できるオンラインツール】**

https://cssminifier.com/

![スクリーンショット 2021-04-26 18.40.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/c4849be9-ce98-79b7-a35a-1992b85dffe6.png)

---

## 使った結果

約50行、約617文字(スペース含む)をmin化してみました。
その結果、

「667バイト」 → **「531バイト」**

**約80%にまで抑えることができました！**
**データ容量を2割カットできたことになります！**


## 使い方・注意点

### 「使い方」

左側の「Input CSS」と書かれた欄に作成したCSSをコピペします。
↓
その少し下に「Minfy」と書かれたボタンがあるので、そのボタンをクリック。
↓
すると右側の「Minified Output」に圧縮されたCSSが表示されるので、「Copy to Clipboard」と書かれたボタンでコピーして、任意のファイルに貼り付けて保存すれば完了！

#### ※変更（省略）される箇所

- 改行
- 半角スペース等
- インデント(Tabやスペース)
- コメントアウト
- プロパティがないセレクタ
- 各セレクタのプロパティの最後のセミコロン(;)
- その他不要な文字（誤って入った全角スペース等）


### 「注意点」

- **重複した内容（プロパティやセレクタなど）は消えない**
- **minファイル化した場合、後で修正がしにくい。**
- minファイル化するのであれば、**「style.min.css」などファイル名を変えて保存し使用するのがオススメ**。


## まとめ

メリットは圧縮することにより、少しですが**データの軽量化に繋がり、ページの読み込み速度の改善に繋がります。**ただCSSだけで圧縮できるデータ容量には限界があるので、これも行いつつ、ソースの見直しや画像の圧縮も同時並行で勧めて行く必要があります。

今回紹介したオンラインツールだけでなく、SASSファイルをコンパイル時に自動的にmin化して保存する方法や、その他ツールなど様々な方法があるので、自分の開発環境にあった方法を試してみてください。

#### おそまつ！
~ Qiitaで毎日投稿中!! ~
[【初心者向け】WEB制作のちょいテク詰め合わせ](https://qiita.com/7note)
Module not found: Can't resolve "history/createBrowserHistory"

React入門で学習時に詰まったエラー

historyがないよと10時間ほど怒られ続けた後に、神のごとき記事に出会いました。

しかもその後すぐに閉鎖してしまった様。リニューアルするとの事なので心から待ち続けます。

記事によると
どうもv5では機能しないようでhistoryをv4にダウングレードせよとの事。
(って解釈で合ってるんだよな？英語だったからようわからん)

`npm install --save history@4.10.1 `

もしくは

`npm install --save history@4.9.0 `


そしたら次はこんなエラー

##### Could not find router reducer in state tree, it must be mounted under "router"

そもそもreact-router-redux自体が推奨されていない様なので
こちらに関しては`connected-react-router`をインストールして
下記の記事を参考に書き換え。

https://www.npmjs.com/package/connected-react-router


本の内容とは変わってしまったがようやくエラー解消と。

Reactはバージョン違いによる不具合が多く、初級者を悩ませるようで
技術書使うならそのへんを明記してるものを選んだ方が良いのかと思いました。

バージョンを意識した開発は未だ未経験だったので良い勉強になってよかったです。
ローカルアカウントとMicrosoftアカウントと職場または学校アカウントの区別 

最近会社のPC環境を調整するためにWindowsログインのアカウントについて大変困りました。
その厄介な体験を通して、メモを残りたくなりました。
PC登録のためにアカウントは３つ種類がございます。
　ローカルアカウント（ローカルWindowsのみ使う、PC変わると使えなくなる）
　Microsoftアカウント（MicrosoftのWebサイト＋ローカルPCのサインイン＋家族メンバーのPC管理用）
　AzureADアカウント（Azure Active Directory admin centerサインイン ＋ローカルPCのサインイン＋職場または学校のPC管理用）

　ローカルアカウントは該当PCのみ使えます。PCを変わると意味がなくなる。Internet普及していない時代にMicrosoft社はWindowsシリーズを販売して、PCログイン用のアカウントです。現在も残っています。
　MicrosoftアカウントはInternet普及してから様々なアプリケーションと連携するため（Officeは一番わかりやすいと思います。）始めたアカウントです。その中に家族のメンバーのPCも管理機能が含めています。特別に子供の使用を役になります。
　AzureADアカウントはAzure cloudを発足してからスタートしたアカウントです。現在Office365を通して無料で使えます。職場または学校に対して使うべきです。AzureADアカウントの関連内容は深すぎです。
【CarrierWave】FactoryBotでDBに画像を登録したい場合の記述

CarrierWaveを使用した画像登録用の項目において、Rspec実行時にFactoryBotにてデータを登録したい場合は以下のように記載する。


```rb:/spec/factories/users.rb
FactoryBot.define do
  factory :user, class: User do
    name { 'Example User' }
    password { 'foobar' }
    password_confirmation { 'foobar' }
    image { File.open(File.join(Rails.root, 'spec/fixtures/files/test_pic_01.jpg')) }
    # image { Rack::Test::UploadedFile.new(File.join(Rails.root, 'spec/fixtures/files/test_pic_01.jpg'), 'image/jpg') }
  end
end
```

※元々コメントアウトしている行の記載で実行できていたが、どこかのタイミングでエラーが発生するようになってしまい、原因を追いきれなかったため、修正した。

```:エラー内容
ActiveRecord::RecordInvalid:
       Validation failed: Picture Failed to manipulate with MiniMagick, maybe it is not an image? Original Error: `magick convert /app/tmp/1619517646-472723409015039-0001-1669/test_pic_01.jpg -auto-orient -resize 800x800> /tmp/image_processing20210427-422-hd5w3e.jpg` failed with error:
       convert: insufficient image data in file `/app/tmp/1619517646-472723409015039-0001-1669/test_pic_01.jpg' @ error/jpeg.c/ReadJPEGImage_/1104.
       convert: no images defined `/tmp/image_processing20210427-422-hd5w3e.jpg' @ error/convert.c/ConvertImageCommand/3301.
     # ./spec/system/show_shop_spec.rb:10:in `block (2 levels) in <main>'
     # ./spec/system/show_shop_spec.rb:32:in `block (2 levels) in <main>'
     # -e:1:in `<main>'
```
~ChildプロパティをquerySelector/querySelectorAllで取得した値に使えるか

# はじめに
JavaScriptのDOMの勉強をし始めて、Elementと名の付くプロパティが使えたり使えなかったり大変だなあと感じています。
取得の仕方がとても重要そうなことを理解したので、今回はdocument.querySelectorとdocument.querySelectorAllで取得できるデータの形と、それぞれにNodeオブジェクトのプロパティ「.firstChild」「.lastChild」が使えるか試してみました。

# 結論
①document.querySelectorで取得(Elementオブジェクト)
→first/lastChildプロパティ利用可
➁document.querySelectorAllで取得(NodeListオブジェクト)
→first/lastChildプロパティ利用**不可**
ちなみに、
③getElementByIdで取得(Elementオブジェクト)
→利用可
④getElementByTagName/ClassNameで取得(HTMLCollectionオブジェクト)利用**不可**

利用可の①と③はどちらもElementオブジェクトとして単一の要素を取得するようですね。

#感想
傾向的に複数の要素を含むような取得の仕方をすると、使えなくなるプロパティが増えるようです。前回の記事↓
[classやタグで取得したデータにgetElementsが使えない件](https://qiita.com/prog_jincho/items/afd4fb2306219ecc36fc)
PythonでSOAPサーバにzeepを使ってアクセスする


# SOAPとは

SOAPとは、サーバにある関数をコールするためのプロトコル。

wsdl文書というxmlで書かれた定義ファイルがあり、そこにSOAPサーバ上でコールできるメソッドなどが書かれている。
メソッドの引数の型定義などもmessageタグで書かれている。

wsdlに配置されているタグについての説明は以下が詳しい。

* [WSDL：Webサービスのインターフェイス情報：Webサービスのキホン（4） - ＠IT](https://www.atmarkit.co.jp/ait/articles/0303/18/news003.html)

wsdl文書の具体例は以下。

* http://www.soapclient.com/xml/soapresponder.wsdl


# PythonでSOAPサーバにアクセスする

[zeep](https://github.com/mvantellingen/python-zeep) というSOAPクライアントのライブラリがある。

他のSOAPクライアントライブラリとの比較記事は以下。

* [2018年12月時点における、PythonのSOAPライブラリについて - メモ的な思考的な](https://thinkami.hatenablog.com/entry/2018/12/03/053937)

## wsdl文書を一覧する

zeepのcliでwsdl文書を読みやすく一覧できる。

```bash
# zeepがインストールされている前提。
$ python -m zeep http://www.soapclient.com/xml/soapresponder.wsdl
Prefixes:
     xsd: http://www.w3.org/2001/XMLSchema
     ns0: http://www.SoapClient.com/xml/SoapResponder.xsd

Global elements:

Global types:
     xsd:anyType
     xsd:ENTITIES
     xsd:ENTITY
     (省略)

Bindings:
     Soap11Binding: {http://www.SoapClient.com/xml/SoapResponder.wsdl}SoapResponderBinding

Service: SoapResponder
     Port: SoapResponderPortType (Soap11Binding: {http://www.SoapClient.com/xml/SoapResponder.wsdl}SoapResponderBinding)
         Operations:
            Method1(bstrParam1: xsd:string, bstrParam2: xsd:string) -> bstrReturn: xsd:string
# => Method1という関数があり、２つ文字列型の引数を取る。
```

## SOAPサーバへアクセスする

SOAPサーバへアクセスするコード例は以下。

```python
import zeep

wsdl = 'http://www.soapclient.com/xml/soapresponder.wsdl'
client = zeep.Client(wsdl=wsdl)
# zeepがwsdlを見て、Method1というメソッドを確認し、service経由でMethod1をコールできるようにしている
print(client.service.Method1('hey', 'ya'))
# => 'Your input parameters are hey and ya'
```


## TLS検証があるサーバにアクセスする

TLS検証のあるサーバにアクセスしたい場合は、以下の方法で実現できる。
* [公式docのTransportsページ TLS verification節](https://docs.python-zeep.org/en/master/transport.html#tls-verification)

```python
from requests import Session
from zeep import Client
from zeep.transports import Transport

session = Session()
session.verify = 'path/to/my/certificate.pem'
transport = Transport(session=session)
client = Client(
    'http://my.own.sslhost.local/service?WSDL',
    transport=transport)
```

## SSLクライアント認証によるアクセス制限があるサーバにアクセスする

もしSSLクライアント認証によるアクセス制限のあるサーバにアクセスしたい場合は、以下の方法で実現できる。
上と似ているが、sessionのオプションである`cert`の指定が増えている。

```python
from requests import Session
from zeep import Client
from zeep.transports import Transport

session = Session()
session.verify = True
session.cert = 'path/to/my/ssl_cient_cert.pem'

transport = Transport(session=session)
client = Client(
    'http://my.own.sslhost.local/service?WSDL',
    transport=transport)
```
【Python】ブックの作成者の変更を行う。

pythonを使用してExcelファイルの操作を勉強しています。
本日の気づき(復習)は、ブックの作成者(最終更新者)の変更に関してです。
pythonでExcelを操作するため、openpyxlというパッケージを使用しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927441/566696e2-4acb-2258-2b95-b16d57a09816.png)

上記の様な作成者(最終更新者)名を

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927441/d349dd05-5749-94d3-82d5-9fb5fb3abfb7.png)

この様に変更したいです。

# creator属性と、lastModifiedBy属性

```ptyhon
Workbook.properties.creator = '作者名'
Workbook.properties.lastModifiedBy = '最終更新者名'
```

公式には記載を見つけられませんでしたが、
上記のようにWorkbook.propertiesのcreator属性で作者名を
Workbook.propertiesのlastModifiedBy属性で最終更新者名を
それぞれ変更できるようです。

他にも作成日付の変更や、最終印刷日の変更もできるようです。
詳しくは下の下のリンクをご確認ください。

https://openpyxl.readthedocs.io/en/stable/api/openpyxl.workbook.properties.html

# 最終的なコード

```python
from openpyxl import load_workbook

wb = load_workbook('資料.xlsx')

name = 'hogefuga'

properties = wb.properties
properties.creator = name
properties.lastModifiedBy = name

wb.save('資料_作成者変更.xlsx')
```

個人的には、あまり多用したくない内容だなとは思いました。
AWS S3 レプリケーション TLSバージョンをバケットポリシーから確認する

# 背景

重要なデータのバックアップのためにクロスリージョンレプリケーションを使用していても、その転送プロトコルに欠陥があれば問題である。こういった背景からレプリケートする際のデータ転送に使用されるSSL/TLSバージョンを知りたかった。以下の書き方ではSSLなのかTLSなのか、また、詳しいバージョンについてもわからない。

> Q: レプリケーションプロセス全体で、オブジェクトは安全に転送され、暗号化されますか?

>はい。オブジェクトはレプリケーションプロセスの間ずっと暗号化されたままとなります。暗号化されたオブジェクトは、SSL 経由で送信元リージョンから送信先リージョンまで (CRR) または同じリージョン内で (SRR) 安全に転送されます。

https://aws.amazon.com/jp/s3/faqs/

以下はIPAの資料だが、バージョンによって推奨・非推奨が分かれている。

[SSL/TLS 暗号設定ガイドライン改定及び鍵管理ガイドライン作成のための調査・検討 -調査報告書-](https://www.ipa.go.jp/files/000067459.pdf)

AWSもドキュメントに記載している通り、TLS1.2 以降を推奨している。単にHTTPSだからといって安心できない。

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-security-enforcing-tls.html

# 検証方法

クロスアカウントによるレプリケーションの際、バケットポリシーで`s3:ReplicateObject`の条件キーとして、`s3:TlsVersion`を指定する。これを0.1ずつ増減させる。

```
"Action": [
    "s3:ReplicateObject",
    "s3:ReplicateDelete"
],
"Resource": "arn:aws:s3:::cross-account-bucket/*",
"Condition": {
  "NumericGreaterThan": {
    "s3:TlsVersion": 1.1
  }
}
```

クロスアカウントなので**明示的に**`Action`**を許可**する必要がある。つまり、上記ポリシーでレプリケートできるならば、TLSのバージョンは少なくとも1.2であることがいえる。

検証の結果、東京-東京、東京-バージニアはいずれもTLS1.2であることがわかった。

# 参考記事

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/amazon-s3-policy-keys.html#example-object-tls-version
golangでエンディアンを理解する

## はじめに

Goならわかるシステムプログラミングで、定期的に学んでいます。


https://ascii.jp/serialarticles/1235262/


今回は、golangでエンディアンを理解していきたいと思います。


https://ascii.jp/elem/000/001/260/1260449/


※ 今回私が書かせていただく、Qiita記事は、こちら（ https://ascii.jp/elem/000/001/260/1260449/ ）の補足説明、検証しやすい形に整えたものです。より深く理解したい向けのアドバイスとしては、Qiitaを読んで、イメージを掴んだら、元リンクをじっくり読むことをおすすめします。


## エンディアンについて

**前提：**

- **メモリアドレスはbyte単位で割り振られる**
- **データのメモリへの格納方法が2週類存在**
    - データの先頭byteを小さいアドレスに置く方式⇒**ビッグエンディアン**
    - データの先頭byteを大きいアドレスに置く方式⇒**リトルエンディアン**

10000という数値（16進表示で0x2710）があったときに、ビッグエンディアンでは、Go言語で書くと []byte{0x0, 0x0, 0x27, 0x10} となります。
一方、リトルエンディアンは、Go言語で書くと[]byte{0x10, 0x27, 0x0, 0x0} となります。

文章ですと、イメージしにくいかもしれませんので、数値10000（16進表示で0x2710）を図示してみます。

data変数に32ビットのビッグエンディアンのデータ（10000）を入れる。

```golang
data := []byte{0x0, 0x0, 0x27, 0x10}
```
図示すると、以下の図になります。
<img width="350" alt="2021-04-26 17.30.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300592/b8c72d49-a1a3-7f31-5d6e-18e8af5f7535.png">

リトルエンディアンの場合は、0x100003に0x10、0x100002には0x27、0x100001と0x100000には0x0が入ります。

**Q.リトルエンディアンとビッグエンディアンどちらかに統一されればよいのでは？**

お気持ち分かります。この規格は統一されたほうが分かりやすいと思います。しかし、現実はそうはいかず・・。日本で使われている電気の周波数が50Hzと60Hzみたいに異なるものが使われている背景に似ている部分があるのだろうかと思っています。

**Q.どのようなときにエンディアンを変換する必要性が出てくるのか？**

ネットワークやファイルなど、外部データを扱うときや、外部データとCPUアーキテクチャのエンディアンが違うときなどです。
TCP/IPプロトコルはビックエンディアンだけど、IntelCPUアーキテクチャはリトルエンディアンなので、変換が必要になってくるケースがあります。

## 実際にプログラムを動かして、リトルエンディアンとビッグエンディアンを体験しよう

```golang:bigendian.go
package main

import (
    "bytes"
    "encoding/binary"
    "fmt"
)

func main() {
    // 32ビットのビッグエンディアンのデータ（10000）
    data := []byte{0x0, 0x0, 0x27, 0x10}
    var i int32
    // エンディアンの変換
    binary.Read(bytes.NewReader(data), binary.BigEndian, &i)
    fmt.Printf("data: %d\n", i)
}
```

```shell
$ go run bigendian.go
data: 10000
```

次に32ビットのビッグエンディアンのデータ（10000）をリトルエンディアンに変更して実行してみましょう。

```golang:littleendian.go
package main

import (
    "bytes"
    "encoding/binary"
    "fmt"
)

func main() {
    // 32ビットのビッグエンディアンのデータ（10000）
    data := []byte{0x0, 0x0, 0x27, 0x10}
    var i int32
    // エンディアンの変換
    binary.Read(bytes.NewReader(data), binary.LittleEndian, &i)
    fmt.Printf("data: %d\n", i)
}
```

```shell
$ go run littleendian.go
data: 270991360
```

ビッグエンディアンのときと違って、10000ではなく、270991360と表示されています。

データの先頭byteを小さいアドレスに置くか、大きいアドレスに置くかの違いです。

下記の図をみると、イメージが掴めるかもしれません。

**ビッグエンディアンのとき**
<img width="350" alt="2021-04-27 17.50.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300592/26682b38-6387-4144-2873-062ff91f81d2.png">
**リトルエンディアンのとき**
<img width="350" alt="2021-04-27 17.53.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300592/3f7a145d-8dbf-2957-f116-75a46b43962d.png">

以上です。

## 参考リンク
分かりやすい記事をありがとうございます。

https://qiita.com/tobira-code/items/a03f39a02678d80bbd26


http://it-information-engineering.com/pcmemory
sedコマンドと拡張正規表現

# 表記が一定でない語句をまとめて置換したい
※「シス環系女子 season2 第7話」の備忘録です。

## 正規表現
パターン指定で検索や置換に便利。

- 基本正規表現
- 拡張正規表現
- Perl互換正規表現

などがある。

## vimによる拡張正規表現
以下のように拡張正規表現を使える。

```
:%s/\v検索するパターン/置換後の文字列/
```

具体例

```
:%s/\v(未着手|進行中|保留)/完了/
```

## sedによる拡張正規表現
以下のように拡張正規表現を使える。

以下、テストデータ。

```
$ cat test_for_sed.log 
1,Windows XP SP3,2021-04-01,故障中
2,Windows XP SP3,2021-04-02,出荷中
3,Windows XP SP3,2021-04-03,故障中
4,mac OS,2021-04-03,故障中
5,Windows XP SP3,2021-04-04,出荷中
6,Windows XP SP3,2021-04-05,故障中
```

これの「Windows」で、かつ「故障中」のものだけを修理中にするsedコマンドと拡張正規表現を考える。
答えは以下の通り。

```
cat test_for_sed.log | sed -E -e "s/(Windows .+)故障中/\1修理中/"
1,Windows XP SP3,2021-04-01,修理中
2,Windows XP SP3,2021-04-02,出荷中
3,Windows XP SP3,2021-04-03,修理中
4,mac OS,2021-04-03,故障中
5,Windows XP SP3,2021-04-04,出荷中
6,Windows XP SP3,2021-04-05,修理中
```

各オプションの意味

```
-E: OS XやBSDで拡張正規表現を使う場合のオプション。（※Linux用のGNUの場合は「-r」を使う。）
(): 後方参照で使う文字列。
\1: 後方参照の文字列が入る箇所。2つ目、3つ目の文字列はそれぞれ「\2」「\3」となる。
.+: 「.」は任意の1文字。「+」は前の文字の1回以上の繰り返しを示す。よって「.+」は任意の文字列の1回以上の繰り返し。
```
バッチファイルでファイルを退避する（ファイル名末尾に「(1)」を付加する）

Y子です。
ちょっとファイルを「どけておく」という作業、よくやりますよね。
新しいファイルをこのフォルダに置きたいけど、同名の既存ファイルに上書きして失いたくないから、ちょっとリネームしておく、という作業。
そんな時に使える処理を作ってみました。

# 概要・用途
「`test.txt`」を、「`test (1).txt`」にリネームします。
ただし、同名のファイル名がすでにある場合は、数字をどんどん増やして、空いているファイル名を探します。

ファイル名を変えてファイルをどけておくような用途を想定します。
「zip圧縮をする際に、同名のzipファイルが既にある場合は、リネームしておく」など。
_【[確認環境：Windows 10 Home (Bld. 19042.928)](https://qiita.com/koiwaiwaiko/items/ef2d457ae1e1a7c8b698 "Windows10のバージョンを確認・表記する")】_

# コード
```bat:evacuate_file.bat
@echo off
setlocal

rem 引数がない場合は終了する
if "%~1"=="" (echo 引数がありません & pause & exit /b)

rem 変更前のファイル名(フルパス)「C:\work dir\test.txt」
set str_oldfile=%~1

rem フォルダのフルパス「C:\work dir\」
set str_dir=%~dp1

rem ファイル名分割…拡張子なし「test」と拡張子のみ「.txt」
set str_new_fn=%~n1
set str_new_ex=%~x1

rem カウンタ初期化
set cnt=1

:label_top

rem 新しいファイル名(仮)「test (n).txt」
set str_newfile=%str_new_fn% (%cnt%)%str_new_ex%

rem 同名のファイルがある場合は、次のファイル名を探す「test (n+1).txt」
if exist "%str_dir%%str_newfile%" (
  set /a cnt+=1
  goto :label_top
)

rem 新しいファイル名を確定する
ren "%str_oldfile%" "%str_newfile%"
echo リネームしました：%str_newfile%

endlocal
```

```:実行結果
> evacuate_file.bat "C:\work dir\test01.txt"
リネームしました：test01 (1).txt

> evacuate_file.bat "C:\work dir\test01.txt"
リネームしました：test01 (2).txt
```

# おわりに
リネーム先のファイル名を、目で見て確認するのは簡単です。
でも、自動処理の中でファイルをどけたいときは、専用の処理を用意しておくと便利そうですね。

では！
【Swift】アラートを表示する方法

## はじめに
Swiftでダイアログを表示したかったため、実装方法をまとめました。

## 基本的なダイアログの表示
UIAlertControllerのインスタンスを作成してpresent関数に渡すことで、ダイアログを表示することができる。
また、OKボタンのようなアクションを追加したい場合は、UIAlertActionのインスタンスを作成し、addActionでアラートに追加する。


```swift
let alert = UIAlertController(title: "タイトル", message: "サブタイトル", preferredStyle: .alert) 

// アクションの追加
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in 
	// アクションがタップされた時に実行される処理
	NSLog("OKがタップされました。")
}))
self.present(alert, animated: true, completion: nil)
```

![Simulator Screen Shot - iPod touch (7th generation) - 2021-04-26 at 23.37.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520642/75b96181-4874-2658-60d1-7c3ced374af5.png)




## TextFieldを追加する
addTextFieldを使うことでダイアログにテキストフィールドを追加することができる。
（ただし、ダイアログにTextFieldを追加したい場合、preferredStyleプロパティをUIAlertController.Style.alertに設定する必要がある。）

```swift
let alert = UIAlertController(title: "タイトル", message: "サブタイトル", preferredStyle: .alert)

// TextFieldを追加
alert.addTextField { (textField) in
	// TextFieldの設定をする。
	textField.placeholder = "テキストを入力してください。"
}

// アクションの追加
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in 
	// アクションがタップされた時に実行される処理
	NSLog("OKがタップされました。")
}))
self.present(alert, animated: true, completion: nil)
```



![Simulator Screen Shot - iPod touch (7th generation) - 2021-04-26 at 23.38.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520642/a06771e9-0323-c806-dc6c-eef20ed718ab.png)
HTTPメソッドについて

HTTPメソッドとは、HTTP通信における処理の種類のことである。
HTTP通信とは、Webアプリケーションを表示する際の、情報やデータなどを送受信するための通信方法。
HTTP通信にはWebアプリケーションで使用する処理の種類ごとに8つの種類が存在する。このHTTP通信の中で行いたい処理の種類をHTTPメソッドと呼ぶ。

特に頻繁に出てくるのは以下の４つ


| メソッド       | 処理           |    
| ----------- | --------------| 
| GET         | 取得する        |  
| POST        | 送信する、作成する |             
| PUT         | 更新する、作成する |
| DELETE      | 削除する　　　　  |

時々忘れそうなので備忘録として残しておく。
[Delphi] [小ネタ] Generic 版 TList の Sort は複雑だと思ってない？

実はたったこれだけ！

```pascal
// uses に System.Generics.Defaults を追加

FList.Sort( // FList は System.Generic.Collections.TList<T> 型
  TComparer<T>.Construct(
    function(const L, R: T): Integer
    begin
      Result := // マイナス値, 0, プラス値、を返す処理
    end
  )
);
```

たとえば Integer だとこう

```pascal
FList.Sort( 
  TComparer<Integer>.Construct(
    function(const L, R: Integer): Integer
    begin
      Result := L - R;
    end
  )
);
```

なんで、こんな事を書いたかというとわざわざ Comparer を定義してインスタンスを作って渡して、というすごい面倒くさい事を書いてる記事があったので。
Generic 版の TList もこんなに簡単だよ。
JQueryで2回目イベントが発火しない

# 困ったこと
・クリックでイベント発火させたい
・初回は動いたが追加された要素のクリックイベントが発火されない

# 問題のコード

```javascript

$('botton').click(function(){
  /* 処理内容 */
};
```

ボタンを押すことでイベント発火させ、ボタンを追加する処理をしました。

その次に上のようなスクリプトを用いて、
追加したボタンをクリック発火させよとしても発火しなくなりました。

# 原因
調べてみると`イベントハンドラが登録されていないから`が原因でした。

HTMLを読み込み初回に表示する際に`イベントハンドラ`が登録されるので、
それ以降に動的に追加された要素には`イベントハンドラ`が登録されず、
クリックしても動かないというものです。

# 解決方法

```javascript
$(document).on('click', 'セレクタ', function(){
  /* イベント発火時の処理 */
});

```
`$(document).on` のようにウェブページ全体に対してイベントハンドラを登録をすることで解決します。

記述を変更することで２回目もイベント発火しました！

このような方法で動的に追加したセレクタでクリック以外のイベントも発火できます。
docker desktop for macでlocalhost接続できなくなった

※ 技術的な内容ではありません。し、多分稀なケースかと思うのであまり共感ないかも。


こんにちは
久しぶりの投稿になります
kamotetuと申します

今日仕事でいつも通りdocker desktop(3.3.1)を立ち上げて作業していたところ、急にdockerが立ち上がらなくなりました


![スクリーンショット 2021-04-27 20.00.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480146/a5b96975-782e-a4f4-f18f-9f314090a88f.png)

ここがずっとコンテナ積んだり下ろしたりの状態がずっと続くという状態です

それで、調べたところ

![スクリーンショット 2021-04-27 20.01.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480146/1c6f2c6d-42b2-0414-add6-bb0b59fc75ba.png)

「Reset to factory defaults」

を実行するとコンテナとか全て削除されて動くようになるよという記事があったので、まぁいいか！と思って全てのコンテナとかイメージとか消しました
(一応その上の「Clean/Purge data」も実行してみましたが、dockerは起動しませんでした。)

それで、綺麗になったところで再度docker-compose upしたら、ターミナル上はちゃんとコンテナが作成されたのですが、

「http://localhost:8080」<-※dockerでportを8080にしています

とchromeのブラウザに入力したところ

![スクリーンショット 2021-04-27 20.14.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480146/bd6191e0-af5e-d62b-94e7-e8e7a60ad57d.png)

これが表示されたんですよね・・

これでた時は
まぁまだコンテナが立ち上がってないのかなーくらいに思っていたのですが、結局これ直すのにほぼ１日かかりました

一応この時のコンテナのサーバーはnginxだったのですが、別のapacheで動いているアプリで試しても同じでした
ただ、ターミナルでnginxのコンテナに入って

```
$ curl http://localhost
```
てやると一応立ち上がってはいるんですよね
でもブラウザでlocalhostでアクセスしてもつながらない


dockerの仕組みとかそこまで詳しくないけど、直らないと仕事にならない


それで猛烈にいろいろ調べて結局直ったのが

docker desktop for mac
を何度も再インストールする

でした

そう、一度の再インストールでは直らなかったんですよね・・どういうこと！

ということで、確か一度最新版(3.3.1)を再インストールして立ち上げてダメで、一つバージョン戻して(3.3.0)立ち上げてだめで、2.5.1をインストールしてそもそもアプリが立ち上がらなくて、で3.3.0から最新(3.3.1)にアップグレードして、それでようやくlocalhostで繋がるようになりました


どういうこと！

ということでもし仮にlocalhostで接続できなくなったら再インストールラッシュを試すと直るかもです

そもそも最初に実行した「Clean/Purge data」が悪かったのかな
この処理の説明で確か「dockerが立ち上がらないといったことが解消されます」的な説明書いてあったんですが詳しく調べてないのでよくわかりません

誰かの参考になれば嬉しいです！
CIDR(Classless Inter-Domain Routing)について

#プログラミング勉強日記
2021年4月27日

#CIDRとは
　Classless Inter-Domain Routingの略で、「サイダー」と読む。サブネットマスクの値を設定して同じネットワークとして扱うIPアドレスの個数を調整できるIPアドレスの設定方法。(サブネットマスクについては[昨日の記事](https://qiita.com/mzmz__02/items/45282202dbb0cdeed389)で触れてる。)
　2進数表記にしたときにサブネットが指定する数が利用できないようにロックされて変更できないようになり、ロックされていない桁分のビット間が有効なIPアドレスとして活用できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/4495f427-e209-995f-3405-1c34f12edf42.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/9ee6c37f-3469-e503-d216-80edc15558d1.png)


　サブネットマスクによって固定される範囲をネットワーク部、利用可能な範囲をホスト部という。`10.0.0.0/16`の場合、`10.0`がネットワーク部で`0.0` ~ `255.255`の部分がホスト部になる。
　IPアドレスの範囲は今後の拡張も踏まえて、十分な余裕を持ちつつ多すぎないレンジを指定する。単なるネットワークそのものを使うときは`/16`を、そのさらに細かくサブネットで分けるときは`/24`を使われることが多い。

| サブネットマスク | サブネット当たりのIPアドレス数 |
|:--:|:--:|
| /16 | 65,534 |
| /18 | 16,384 |
| /20 | 4,096 |
| /22 | 1,025 |
| /24 | 256 |
| /26 | 64 |
| /28 | 16 |
[Git] 日付以降のコミットログだけを表示

#概要

特定の日付以降のコミットのログを表示したい場合の方法をメモします。


Gitのバージョン

```
$ git --version
git version 2.24.3 (Apple Git-128)
```

#方法

```
$ git log --after='2021-04-23 00:00:00'
```
LeetCodeWeekly238C: 1839. Longest Substring Of All Vowels in Order 区間操作 一定の文字出現する最大の単調増加文字列


https://leetcode.com/contest/weekly-contest-238/problems/longest-substring-of-all-vowels-in-order/

# 題意(オリジナル)
* 英語小文字の集合である文字列$s$が与えられる．
* 良い文字列を以下のように定義する．ソートされた$x$文字の連続した文字列であり、この中に$a,i,u,e,o$の５文字が１回以上出現していなければならない．
* この文字列の長さの最大長を求めよ

# こう考えた
簡単のため、問題文を以下のように言い換える．

- $|s|$の配列$a$が与えられ、各要素 $a_i$は $0 \leq a_i \leq 25$である
- よい区間とは以下の通りである．連続した区間の要素が全てソートされており（つまり、単調増加）、この中に$0, 8, 20, 4, 15$が1度以上含まれている

ここで、連続した区間とは、ある任意の $ 0 \leq l \leq r < |s|  $と言い換えられる．さて、ここで単調増加である条件を考えると、ある$l$を固定した際、$r$を右に伸ばしていき、伸ばせるところまで伸ばし、その中に、$0, 8, 20, 4, 15$が含まれているならばそれは最長の長さの候補として扱える．

このため、以下のように判定をする．

- l = 0からスタートし、単調増加で有る限り、rをインクリメントする
- 単調増加でなくなった場合、今の区間に必要な文字が含まれているかを判定する．
- Yesの場合、その文字長を候補とする．Noの場合、捨てる

# 実装
特に留意点はなし．工夫は以下程度．
- 先に$s$は数値のリストにしておく方が良い


```Python3
class Solution:
    def longestBeautifulSubstring(self, word: str) -> int:
        judge = lambda : cnt[0]!=0 and cnt[8]!=0 and cnt[20]!=0 and cnt[4]!=0 and cnt[14]!=0
        chr2int = lambda x: ord(x) - ord("a")
        s,l,r = word,0,0
        s = list(map(chr2int, s))
        cnt = [0] * 26
        res = 0
        p = -1
        while r < len(s):
            cnt[s[r]] += 1
            # 足した文字が条件を達成しているか？
            if s[r] < p:
                l = r
                r += 1
                p = s[r]
                continue
            p = s[r]
            if judge(): # 文字が足りている
                res = max(res, (r-l) + 1)
            r += 1
        return res
```
https://leetcode.com/contest/weekly-contest-238/problems/longest-substring-of-all-vowels-in-order/
ターミナル起動時にzshエラーがおきた。

以下の記事を参考にさせていだきました。

https://teratail.com/questions/149617

## 何が起きたか
ターミナルを起動したところ以下のエラーが発生しました。

```
.zshrc:7: unmatched "
```

## 原因
.zshrcの7行目の末尾に「"」が付いていなかったことが原因でした。

```
eval "$(pyenv init -)
```

末尾に「"」をつけたらエラーは直りました。

```
eval "$(pyenv init -)"
```
ラズパイ用ケースを100均で制作

[前編](614c3973cc7d1439865e)
　１．ラズパイとサーバーの概要
　２．録画に必要なものを集める、購入する
　３．OSのインストールとセットアップ
　４．NASの構築
[後編](3bf7e152fbf73c5ca25e)
　５．チューナーの導入、テスト録画
　６．運用のためのツール、mirakurun、epgstation
　７．録画管理方法
　８．エンコードと再生
　９．システムバックアップ
[まとめ版](0ea0f2ee3cfe5cb8e31e)
番外１．ラズパイ用ケースを100均で制作 now!
番外２．[トラブルシューティング(案)](1e439b7cc10822f5ef69)

密林とか見ますとラズパイ用のケースっていろいろありますね。プラスチックのもあれば金属のもあるし、アクリル板で挟んだ横が抜けているケースというのもある。そんなケース達ですが、中にはもっと安くできないものかと100均でいろいろ買ってきてケースを作りたいという方もそれなりいるのではないでしょうか。HDDなどと一体型のケースも作れるといったメリットもある。
まずは材料収集。店の中をいろいろ見渡して、よさげなサイズのを探してみた。まずはこちら。

![case1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547444/8ef85609-63bc-384b-7ee7-53c3798c7a3e.jpeg)
セリアで見つけたもので、ちょうど荒い網のようになっていて、通気性もとりあえず大丈夫かなといった感じ。

もう一つがダイソーで見つけたこちらのケー...スですが、
![case2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547444/0db052b2-c55e-91d9-5ed6-24d7dbfddc32.jpeg)
必要なのは
![case3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547444/7856806b-dac7-7e16-2e2a-17ad6cbef892.jpeg)
中に入っているあみあみ。これがあれば、ネジがなくてもそれなり固定可能になる。なお、この後、園芸用ワイヤーなどを使って固定することになる。

この網はカッターで割と容易に切れる。下の台座と、隙間を作るためのスペーサー？を作る。なおスペーサー？は無くてもそんなに問題にはならない。
![casea.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547444/5f19d081-52cd-ee3d-a784-54f7ad2ab789.jpeg)
その上にPi4を乗せ、固定する。
![case9.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547444/1f4b4190-d789-5016-b10c-67026f3c1355.jpeg)
水牛のUSB-SSDはそのままだとケースに入らないので、真ん中を切って押し入れることにした。
![case8.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547444/617a5517-f0df-b80f-faa9-f7da9f215638.jpeg)
で、少し飛ぶが完成は以下の写真のような感じ。
![caseb.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547444/0dec4452-7b06-5109-69f2-54f302a761f6.jpeg)
USBや電源のtypecのケーブルを通すために、一部柱を切り取っている。作ってみるとわかるが、USB端子に挿した先端部？あのUSBマークのある、抜き差しする際に持つ部分ですね、が意外と邪魔になる、特にコンパクトに作ろうとすると。そこんところ注意です。

チューナーについては、ケースに括り付けてもいいが、同軸の穴に直結させて(オスオスでしたっけ？)USBで信号を持ってくるという方法もありかと。B-Casカードリーダー？はて何のことでしたっけ。

-------------------------------------

なお、別解として、小さい方を利用してPi4だけを覆うという手段もある。
![case6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547444/0e3e3e7c-bb8e-897e-1ba7-02acaab84cca.jpeg)
この場合、USB-SSDの上に直に乗っけるのが省スペース的に向いているだろうか。

------------------------------------

100均で自作することのメリットは、安く作れる以外に、小回りが利くということ。このケースをワイヤーで釣ってしまえば、
![case4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547444/b293829b-3ba8-c8c8-0672-2358f2ae5605.jpeg)
柱？鴨居？につるすことも可能になる。これは市販のケースでも簡単にできるとは限らないことではないかと。

～～～ですが...
結局手間を考えれば市販のケースを買ってしまう方がいいのではないでしょうか？もちろん自作についても作ること自体を楽しむ、または工作の腕を磨く、というメリットもあるので、決して無駄ではないです。
node.jsのインストール、バージョンアップの方法

今回は以下の記事を参考にさせていただきました。
[nodebrewで手軽にnode.jsバージョンアップ＆バージョン切り替え](https://qiita.com/strsk/items/db64f4dd27484a875d20)
[node.jsのバージョンアップ、バージョン切り替え](https://qiita.com/strsk/items/925644e124efcc964625)

## はじめに
node.jsは**nvm(Node Version Manager)**もしくは**nodeblew**でインストール、アップデートができます。
nvmはbash環境、nodebrewはzsh、bash両方で使えるので今回は使い勝手の良いnodebrewで説明をしていきたいと思います

## nodebrewの使い方
###1. nodebrewインストール

```
$ curl -L git.io/nodebrew | perl - setup
```

`.zshrc`か`.bashrc`に追記

```
$ echo 'export PATH="$HOME/.nodebrew/current/bin:$PATH"' >> ~/.zshrc

   or

$ echo 'export PATH="$HOME/.nodebrew/current/bin:$PATH"' >> ~/.bashrc
```

読み込ませる

```
$ source ~/.zshrc

 or

$ source ~/.bashrc
```

###2. 使い方
インストール可能なバージョンを確認

```
$ nodebrew ls-remote
v0.0.1    v0.0.2    v0.0.3    v0.0.4    v0.0.5    v0.0.6    
...
```
***

node.jsのインストール

```
$ nodebrew install-binary v15.13.0 
Fetching: https://nodejs.org/dist/v15.13.0/node-v15.13.0-darwin-x64.tar.gz
##################################################################################################################################### 100.0%
Installed successfully
```
***
バージョンの確認

```
$ nodebrew ls
v15.13.0

current: none
```
***

バージョンの切り替え

```
$ nodebrew use v15.13.0
use v15.13.0

$ nodebrew ls          
v15.13.0

current: v15.13.0
```

以上になります。

##参照

https://github.com/hokaccha/nodebrew/blob/master/README.md
JSON5でJavaScriptオブジェクトのstringify

標準のJSON.stringifyは欲しいフォーマットで簡単に出力できなかったので、JSON5を使って見ました。

## JSON5とは

[github](https://github.com/json5/json5)

The JSON5 Data Interchange Format (JSON5) is a superset of JSON that aims to alleviate some of the limitations of JSON by expanding its syntax to include some productions from ECMAScript 5.1.

## 欲しいフォーマット

```javascript
const obj = {a: 123, b: 'hello'};
console.log(JSON.stringify(obj, null, '  '));
```

- 複数行で記載する場合、後ろにコンマが付く
- キーが文字列なので、クオテーションで括らない

```
{
  a: 123,
  b: 'hello',
}
```

## JSON.stringifyを使う場合

```
{
  "a": 123,
  "b": "hello",
}
```

## JSON5.stringifyを使う場合

```
{
  a: 123,
  b: 'hello',
}
```

JSON5で流石に人間に優しくフォーマットしてくれますね。
vue-chartjsでグラフが表示されない問題

vue-chartjsを初めて使用した際につまずいた点をメモしておきます。


# 問題の背景

 [公式ガイド](https://vue-chartjs.org/ja/guide/#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)を参考に、Chart.jsとvue-chartjsのインストールからチャートコンポーネントの作成までを終え、
ファイルを実行したところグラフが上手く表示されなかった。


# Chart.jsのバージョンを戻して解決
Chart.jsは最近大きなアップデートがあったが、vue-chartjsはそのアップデートにまだ対応出来ていない様子。(2021年4月27日時点)
[公式ガイド](https://vue-chartjs.org/ja/guide/#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)にあるインストール方法ではChart.jsの最新版がインストールされてしまう為、
vue-chartjsを使用するには以下の様にバージョンを直接指定するなどして、Chart.jsを3.0.0より古いバージョンに戻す必要がある。

```
npm install chart.js@2.9.4
```
行列累乗でフィボナッチ数列を計算する

# フィボナッチ数列
フィボナッチ数列は前の二つの数字を足したものが次の項になる、という数列で以下の漸化式で定義されます。

```math
F_0 = 0, \\
F_1 = 1, \\
F_{n+2} = F_n + F_{n+1} (n ≥ 0)
```
実際には以下のような
数値になります(第0～21項)

```
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946,
```

# 計算方法
前二つの数字を覚えておきさえすればいいので項の小さいほうから計算すれば容易に計算できます

# 行列累乗
項の小さいほうから計算する場合は第N項を求めるために$O(N)$かかりますが行列累乗という考え方を用いると$O(logN)$で求められます。

少し見方を変えてフィボナッチ数列を以下のような遷移だと考えてみます(図の矢印は加算です)。
やっていることは何も変わらず必要な状態を縦に並べるようにしました

![名称未設定ファイル (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323266/6555ed9d-90d6-3caa-d4f4-002cee490c39.png)
こう考えることで、うまく行列の式に落とし込むことができます
具体的には以下のような式になります

```math 
\begin{pmatrix}
1 & 1 \\
1 & 0
\end{pmatrix} 
\begin{pmatrix}
F_{n+1} \\ F_{n}
\end{pmatrix} = 
\begin{pmatrix}
F_{n + 1} + F_{n}\\ F_{n+1}
\end{pmatrix} 
=
\begin{pmatrix}
F_{n + 2} \\ F_{n+1}
\end{pmatrix} 
```
これをもとに2項先は以下のように表現できます(行列は交換則は満たさないが結合則は満たすので好きな順序で計算できます)

```math
\begin{pmatrix}
1 & 1 \\
1 & 0
\end{pmatrix} 
\begin{pmatrix}
1 & 1 \\
1 & 0
\end{pmatrix} 
\begin{pmatrix}
F_{n+1} \\ F_{n}
\end{pmatrix} = 
\begin{pmatrix}
1 & 1 \\
1 & 0
\end{pmatrix} 
\begin{pmatrix}
F_{n + 2} \\ F_{n+1}
\end{pmatrix} =
\begin{pmatrix}
F_{n + 3} \\ F_{n+2}
\end{pmatrix} 

```

ここで行列のn乗を求めるために繰り返し二乗法を用いると、$O(logN)$で計算できるというわけです。
※実際には行列のサイズをM × Mとするときに$O(M^3logN)$となります。

ということで、nに0を代入し、m項先を計算する場合以下のように表現できます

```math
\begin{pmatrix}
1 & 1 \\
1 & 0
\end{pmatrix}^{m}
\begin{pmatrix}
F_{1} \\ F_{0}
\end{pmatrix} =
\begin{pmatrix}
F_{m + 1} \\ F_m
\end{pmatrix}
```

# 具体例
例えば第8項を計算してみます

```math
\begin{pmatrix}
1 & 1 \\
1 & 0
\end{pmatrix}^{8}
\begin{pmatrix}
F_{1} \\ F_{0}
\end{pmatrix} =
\begin{pmatrix}
1 & 1 \\
1 & 0
\end{pmatrix}^{2^{3}}
\begin{pmatrix}
1 \\ 0
\end{pmatrix}\\
= \begin{pmatrix}
2 & 1 \\
1 & 1
\end{pmatrix}^{2^{2}}
\begin{pmatrix}
1 \\ 0
\end{pmatrix}\\
= \begin{pmatrix}
5 & 3 \\
3 & 2
\end{pmatrix}^{2}
\begin{pmatrix}
1 \\ 0
\end{pmatrix}\\
= \begin{pmatrix}
34 & 21 \\
21 & 13
\end{pmatrix}
\begin{pmatrix}
1 \\ 0
\end{pmatrix}\\
=
\begin{pmatrix}
34 \\ 21
\end{pmatrix}\\
```
という感じです
第8項は21,第9項は34なので正しく計算できていそうです。
JavaScript でクッキーを作成

```html:simple_cookie.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8" />
<title>Cookie</title>
<script type="text/javascript">
document.cookie = "aa='バナナ';SameSite=strict";
document.cookie = "bb='りんご';SameSite=strict";
document.cookie = "cc='みかん';SameSite=strict";
document.cookie = "message='こんにちは';SameSite=strict";
console.log(document.cookie);
</script>
</head>
<body>
<h2>Cookie</h2>
<hr />
Apr/27/2021<br />
</body>
</html>
```

実行結果
![cookie_apr27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/cad9de25-c90e-37f4-67cc-a8302d01434b.png)
sketchupでruby その17

#概要

sketchupでrubyやってみた。
練習問題やってみた。

#練習問題

周りを囲め。

#写真

![ea.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/95cd194d-3d1f-e66e-9612-1d9c2f778801.png)


#サンプルコード

```
def ga
   entities = Sketchup.active_model.entities
   pi = Math::PI
   (-24..24).each { |i|
      group = entities.add_group
      face = group.entities.add_face [0, 0, 60], [0, 20, 60], [1, 20, 60], [1, 0, 60]
      face.pushpull -1
      phi = i * pi / 24
      trn = Geom::Transformation.translation [0, 0, 100]
      rot = Geom::Transformation.rotation [0, 0, 0], [0, 1, 0], phi
      group.transform! trn
      group.transform! rot
   }
end

```

以上。
C# ~マップの判定・縦横~ Aランクレベルアップメニュー

現在働いている会社ではシステムエンジニア研修の１つに「paizaBランク問題をクリア」があるのでその目標を達成するまでの過程を備忘録として残します。

業務に参加した際に記述方法を忘れてしまっているであろう未来の自分に向けて、メモを残すと同時にこの記事がC#を学習している方、同じ箇所で躓いている方の参考になればと思っています。
ですので内容に誤りがある場合やより良い記述をご存知の方はコメントで共有していただけると嬉しいです。

それでは本編に入ります。
今回はPaizaラーニング、Aランクレベルアップ問題集「マップの判定・縦横」の問題をC#で回答したときの内容になります。

## STEP: 1 盤面の情報取得
問題文:https://paiza.jp/works/mondai/a_rank_level_up_problems/a_rank_snake_map_step1

```c#:paiza.cs
using System;

class Program
{
    static void Main()
    {
        string[] asW_H_N = Console.ReadLine().Split(' ');
        int iH = int.Parse(asW_H_N[0]);
        int iW = int.Parse(asW_H_N[1]);
        int iN = int.Parse(asW_H_N[2]);
        string[,] a2D_CoordinateData = new string[iH,iW];
        for(int i = 0; i < iH; i++){
            string as_rowData = Console.ReadLine();
            for(var j = 0; j < iW; j++){
                a2D_CoordinateData[i,j] = as_rowData.Substring(j,1);
            }
        }
        for(var i = 0; i < iN; i++){
            string[] as_coordinateNum = Console.ReadLine().Split(' ');
            int CoordinateData_Y = int.Parse(as_coordinateNum[0]);
            int CoordinateData_X = int.Parse(as_coordinateNum[1]);
            Console.WriteLine(a2D_CoordinateData[CoordinateData_Y,CoordinateData_X]);
        }
    }
}
```
面接での技術質問

# 面接での技術質問

面接で聞かれた技術質問に対し、しっかりと答えられなかったので戒めとして記事にします。
本当に基本的なことなので、これを機にもっとRuby on Railsの中身をもっと詳しく学習しようと思います。

※注意※
記事の一部に誤りがあり、コメントにて詳しくご指導して頂きました。
記事はその時点での自分の実力を残したくもあった為、誤字等を除いて修正はしない予定です。
この記事を読んで下さった方は、ぜひコメント欄まで目を通して頂ければと思います。
また間違い等ありましたらコメントなどでご指導いただけると大変助かります。。。


### MVCモデル

ActiveRecord
・ActiveRecordとはMVCのM、つまりModelに関する部分
・RubyのオブジェクトをSQLに翻訳してRDBMSの操作できるツール
・Railsとデータベースを接続する役割を担います

M＝Model
・データベースとの接続とデータに関する操作を行う　
V＝View
・Modelの内容を参照し、webアプリケーションの見た目の部分を表現する
C＝Controller
・リクエストに対応する処理をまとめ、リクエストを受け取って処理を行った後、クライアントにレスポンスを返す。

### オブジェクト指向
オブジェクト指向プログラミングとは、「もの」を組み立てる様に表現してコンピュータに指示することです。
機能・役割ごとに分けて、実装を進めていく方針のことを言います。

主なメリットとしては2点。

* 役割ごとにオブジェクトを分けることで、実装がしやすくなる
* 役割ごとに分けるため、後からコード変更がしやすい、また他のコードに影響が出にくい

そして「もの」を組み立てる際の設計図を「クラス」と呼び、その「設計図から作成された実物体」のことを「インスタンス」と呼びます。


### HTTPリクエストについて
何らかのwebサービスにアクセスする時を例にとって説明します。
1.まずクライアント側のPCでブラウザにURLを入力します。
2.クライアント側のPCからWebサーバーに「HTTPリクエスト」を送信します。
3.Webサーバーが、「HTTPリクエスト」に対応する「HTTPレスポンス」をクライアント側のPCに送信します。
4.クライアント側のPCでWebページを表示します。

少し細かく説明すると、
リクエストを送る際、DNSサーバーにアクセスし、webサイトのIPアドレスを特定、そのIPアドレスを持つサーバーに対してHTTPリクエストを送信します。

サーバーがそのHTTPリクエストを元にクライアントの要求を承認すると、サーバーはクライアントにHTTPステータスコード２００を返します。

承認が行われると、サーバーからwebサイトの情報がデータパケットという形で転送され、クライアント側にwebサイトが表示されます。


### クッキーとセッション

Cookieとは、Webサイトの提供者が、Webブラウザを通じて訪問者のコンピュータに一時的にデータを書き込んで保存させる仕組み。

sessionとは、クライアントとサーバーの通信状態のことで、sessionにはIDを割り振られて管理される。

ログイン状態を保持したページ遷移などは、クッキー、セッションが使われています。
クライアント側にあるクッキーの情報とサーバー側に保存されているセッションIDが一致していれば、ログイン状態を保持したまま画面遷移が可能になります。


### ロードバランサー（負荷分散装置）とは

ロードバランサーとは、名前の通り、サーバーにかかる負担を分散させる仕組みです。
Webサイトへのアクセス集中やサーバーが故障してしまったても、アクセス中の利用者に安定したサービス提供を継続可能になります。

クライアントとサーバーの間に取り入れられる仕組みで、クライアントからのHTTPリクエストがあると、ロードバランサーを経由し、その後負荷が集中しないように各サーバーへ振り分けられます。


ロードバランサーの役割は主な役割は、

* アクセス集中による速度低下を防ぐ
* 不具合が起きているサーバーへはリクエストを送らない
* サービスを停止することなくサーバーのメンテナンスが可能
* 特定のユーザーのアクセスを同じサーバーへ送る

### find、find_by、where句

findメソッドは、各モデルのidを検索キーとしてデータを取得するメソッド

find_byメソッドは、各モデルのid以外の条件で検索するメソッド

whereメソッドは、各モデルをid以外の条件で検索する場合該当するデータ全てが返ってくるメソッド

### renderとredirect_to

renderメソッドは、viewファイルを指定
redirect_toは、URL(HTTPリクエストメソッド）を指定

よく似た挙動をしますが、処理の中身が大きく異なります。

renderメソッドではcontrollerからviewファイルを指定して表示されます。

一方でredirect_toは、MVCを経由した処理が行われます。
controller →　URL　→　routes　→ controller →　view　の流れです。

そのため以下のような使い分けが可能です。

render:エラー発生時などに、単にエラーページなどを表示させる場合
redirect_to:データ更新、削除などcontrollerの処理が必要な場合
ガベージコレクタとは?

#ガベージコレクタとは?

##ガベージコレクタの説明
ガベージコレクタとは、プログラムが使用しなくなったメモリ領域を検出し解放します。

例えば、int型のインスタンス変数を宣言したとすると、int型のデータサイズである
32ビット分のメモリ領域が使用されることになります。
しかし、このオブジェクトが使用されなくなると、ガベージコレクタによってこのオブジェクトが
使用していたメモリ領域を解放します。

##オブジェクトをガベージコレクタの対象にする。
オブジェクトがどこからか参照されている間は、ガベージコレクタの対象にはなりません。
オブジェクトへの参照を取り除く方法は２つあります。

###nullを代入
プログラムの中で明示的に「この変数はオブジェクトを参照しない」ということを表現する
nullを代入します。これによりガベージコレクタの対象になります。

```
Employee e1 = new Employee(); //a1変数は、Employeeオブジェとを参照している
e1 = null; //nullを代入することで、「その変数は何も参照していない」という意味になる。
```
###参照変数を他のオブジェクトに割り当てる
オブジェクトを参照している変数に、新たなオブジェクトを割り当てたことで、元のオブジェクトが
どこからも参照されなくなったら、その元のオブジェクトはガベージコレクタの対象になる。

```
Employee e1 = new Employee(); //a1変数は、Employeeオブジェクトを参照している
e1 = new Employee(); //a1変数は新しいオブジェクトを参照する。その結果、最初のオブジェクトはガベージコレクタの対象になる。
```

## まとめ
・ガベージコレクタとは、プログラムが使用しなくなったメモリ領域を検出し解放する動作を指す。
・変数にnullを代入すると、ガベージコレクタの対象になる。
・参照変数を他のオブジェクトに割り当てると、ガベージコレクタの対象となる。
【GitHub Actions】CICD構築 パイプラインの書き方備忘録

## はじめに
CICD導入で学んだことを備忘録として残しておく。
主にパイプラインの書き方の部分のフォーカスして記載。

## 共通
### checkoutする
リポジトリをチェックアウトし、ワークフロー(Runner)がリポジトリにアクセスできるようにする。

```yml:cicd:yml
    steps:
      - uses: actions/checkout@v2
```

### self-hosted Runnerを指定する
自身で構築したRunnerでCICDを動作させる事ができる。

```yaml:ci.yml
jobs:
  build:
    runs-on:self-hosted
``` 

### 共通部分は再利用する（DRY原則を守る）
グローバルなenvを定義しそれを呼び出す事ができる。
（以下はEC2に`git pull`でDeployする事を想定したもの。）

```yaml:cicd.yml
jobs:
  deploy:
    env:
      SCRIPTS:
        echo '${{ secrets.SSH_KEY }}' > ssh_secret_key
        chmod 600 ssh_secret_key
        ssh -o StrictHostKeyChecking=no '${{ secrets.USER }}'@'${{ secrets.HOST }}' -i ssh_secret_key "
          cd /home/'${{ secrets.USER }}'/hogehoge/ && 
          git -c core.sshCommand=\"ssh -i ~/.ssh/deploy_key -F /dev/null\" pull
        "

    steps:            
      - name: Deploy
        run: ${{ env.SCRIPTS }}
```

## CIパイプライン構築で使うもの
### build成果物を保存する
GitHub Actionsの場合、buildの成果物を`artifacts`に保存する事ができる。

```yaml:ci.yml
    steps:
      - name: Archive UnitTest result of test
        uses: actions/upload-artifact@v2
        with:
          name: Unit Test Result
          path: |
            reports/test.html
            reports/coverage/
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/b0ef300f-96d5-102a-3c97-9966a06c3362.png)

### パッケージ管理ツールを用いた環境構築
CI環境はまっさらな環境なのでUT・E2Eテストなどを流すには環境構築が必要。
その際、ローカルの時のように`npm install`や`pipenv install`は使わない。
CIでは`lockファイル`を用いて`npm ci`や`pipenv sync --dev`などで環境構築する。