OmniAICreator/Qiita-1.07M huggingface dataset:
インデントは大事だよっていう話

## はじめに

この記事は、最近プログラミングを授業等で学び始めた人に向けています。
また、C言語を例として取り上げています。

皆さんは「インデント」という言葉を聞いたことがありますか？
この記事では、その「インデント」について解説します。


## インデントとは

プログラミングにおいて、**ブロックの中の行頭にスペースを入れて字下げをすること**です。

> ブロックとは、C言語では`{ }`で囲われた範囲のことです。

百聞は一見にしかずと言いますので、まずは下の例を見てみましょう。


### インデントがついていない例
```c
/* 0〜20までの偶数を2倍して出力するコード */
#include <stdio.h>
int main(void)
{
int i;
for (i = 0; i <= 20; i++)
{
if (i % 2 == 0)
{
printf("%d\n", i * 2);
}
}
return 0;
}
```

### インデントがついている例

```c
/* 0〜20までの偶数を2倍して出力するコード */
#include <stdio.h>

int main(void)
{
    int i;
    for (i = 1; i <= 20; i++)
    {
        if (i % 2 == 0)
        {
            printf("%d\n", i * 2);
        }
    }
    return 0;
}
```


この2つを見比べてどちらが見やすいでしょうか？
どちらも実行結果は変わりませんが、おそらく大半の人が**インデントがついている例**のほうが見やすいと思います。

インデントをつけると、どの文がどのブロックに属しているか、ひと目で分かるようになります。
これは、バグを作らないためにも大事なことです。

ではインデントの付け方について実例と共にルールを見ていきましょう。


## インデントのルール

***ブロック1つにつき、決まった数の半角スペースを行頭に入れる***

これだけです。

この`決まった数の半角スペース`は、人・言語によって異なりますが、ほぼ**2つ**か**4つ**です。
また、半角スペースではなく、**タブ文字**を使用することもあります。

しかし、ここで大切なことは、**途中で半角スペースの数を変えたりしない**ことです。半角スペースの数は統一するようにしましょう。

> 全角スペースだとコンパイルが通らないので注意しましょう。

今回の例では、**1つのインデントあたり4つ**半角スペースをつけることにします。

では、実際に見ていきましょう。

```c
/* include等は省略します。 */
int main(void)
{
    /* ここは{}で囲われていますので、1段インデントを付けます */
    int input;
    scanf("%d", &input);
    
    if (input != 0)
    {
        /* {}のなかの{}についても、字下げすることに注意してください。 */
        /* ここには、合計で2段(8スペース)のインデントがついています。 */
        printf("0以外を入力しましたね！\n");
        
        if (input == 1)
        {
            /* ここは3重目の{}なので、3段(12スペース)のインデントを付けます。 */
            printf("1を入力しましたね！\n"); 
        }
    }
    return 0;
}
```

だいたい感覚は掴めましたでしょうか。
必要なのは、「`{ }`ブロック1つにつき、決まった数の半角スペースを行頭に入れる」これだけです。
多少の手間ですが、これによってコードが**読みやすく**なります。

### インデントがおかしい例

```c
int main(void)
{
 int input;
     scanf("%d", &input);
    
 if (input != 0)
     {
  printf("0以外を入力しましたね！\n");
        /* ... */
        
    if (input == 1)
    {
        /* ... */
        printf("1を入力しましたね！\n"); 
    }
    }
    return 0;
}
```

このコードでは、半角スペースを入れることはできていますが、ブロックごとに分けられていなかったり、半角スペースの数が統一されていません。

これでは却って読みづらいですね。
コードの意味を勘違いしてしまう可能性もあります。

インデントを付ける時は、正しい数のスペースを付け、コードのまとまりが理解しやすいようにしましょう。


## おわりに

インデントをつけることは、プログラムを書く上では欠かせない行為です。
正しく付けて、読みやすいコードを心がけましょう！

また、この記事は以下の方々と共同執筆したものです。
この場を借りて御礼を申し上げます。ありがとうございました！
@shun-shobon
@soshi_harami
@isso0424
[質問]jsで取得したデータをデータベースに保存する方法

###前提・実現したいこと
・自身プログラミング経験が浅いため、お伝えする内容に不備や、漏れがあれば
ご指摘いただいても大丈夫です

###[実現したいこと]
・amazonの商品をスクレイピングで、家電の商品の価格を抽出した情報を
データベースを使用して保存したい

####発生している問題
####[現状]
・ターミナルにて、npm i puppeteer
puppeteerをインストール
・プロジェクトのディレクトリ内に、test.js

amazonのサイトまでは、いきデータは抽出できているかと
思うのですが、その先が、
どう対応すればいいのかわからず、進めることができません。

データベースは、MySQLを予定しております。

該当のソースコード



・test.js

    const puppeteer = require("puppeteer");

    (async () => {
        const browser = await puppeteer.launch({
            headless: false, // 動作確認するためheadlessモードにしない
            slowMo: 500, // 動作確認しやすいようにpuppeteerの操作を遅延させる
        });
        const page = await browser.newPage();

        //生活家電のページへ行く。
        await page.goto("https://www.amazon.co.jp/%E7%94%9F%E6%B4%BB%E5%AE%B6%E9%9B%BB/b?node=124048011", {
            waitUntil: "networkidle2",
        });

        //セレクターで指定したノードが表示されるまで待機

        await page.waitFor(".a-section.octopus-best-seller-card");

        //カテゴリーのリンクを取得（空調・季節家電、キッチン家電など）
        let category_urls = await page.evaluate((selector) => {
            let urls = [];
            document.querySelectorAll(selector).forEach((node, i) => {
                urls.push(node.href);
            });
            return urls;
        }, "a.octopus-pc-category-card-v2-category-link");
        console.log(category_urls);

        //上で取得したカテゴリーのURLの中から一つを選ぶ。
        let category_url = Math.floor(Math.random() * category_urls.length);
        category_url = category_urls[category_url];
        console.log(category_url);

        //カテゴリーのIDを取得
        let category_id = category_url.replace(/^.*node=/i, "").replace(/&.*/, "");
        console.log(category_id);

        //アマゾンおすすめ商品順
        let page_url = "https://www.amazon.co.jp/s?rh=n:" + category_id + "&s=featured-rank";

        //アマゾンおすすめ商品のページへいく。
        await page.goto(page_url, {
            waitUntil: "networkidle2",
        });

        //セレクターで指定したノードが表示されるまで待機。
        await page.waitFor("#search + *");

        //ページから商品の情報を取得。
        let items = await page.evaluate((selector) => {
           let data = [];
            document.querySelectorAll(selector).forEach((node, i) => {
                let obj = {};
                //商品のタイトルを取得
                let title = node.querySelector("a.a-text-normal span.a-text-normal");
                title = title.textContent.trim();
                obj.title = title;

                //商品の価格を取得
                let price = node.querySelector("span.a-price-whole") || node.querySelector("span.a-color-price");
                price = (price && price.textContent.trim()) || "";
                obj.price = price;

                //配列にタイトル、価格のデータを入れたオブジェクトを追加
                data.push(obj);
            });
        return data;
    }, "div.s-result-list div[data-asin][data-uuid]");

    //itemsは配列でitems[0].titleでタイトル、items[0].priceで値段を取得。
    console.log(items);

    //ブラウザを閉じる
    await browser.close();
    })()
    

####補足情報（ツールのバージョンなど）
・macOS Catalina バージョン１０.１５.３使用
・ターミナル使用
・VScode使用
・node.js v13.11.0
・npm 6.13.7


ご協力の程、お願い致します。
写真ACのダウンロード数をグラフ化したい【MySQL環連携編】 ~1日10行コーディング~

## 4日目

昨日に引き続きグラフアプリをデータを実際に格納する部分を作成します。


### 【技術テーマ】
環境構築

### 言語
* MySQL

### 目標成果物
今日はMySQLの環境構築を完了させ、前回の情報をDBに格納するところまでやりたいと思います。

### コードと資料

#### 1. MySQLのインストール
https://qiita.com/hkusu/items/cda3e8461e7a46ecf25d
こちらの記事を参考に指定されたコマンドを実行

【実行コマンド】

```
ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"
```

結果

```
curl: (22) The requested URL returned error: 404 Not Found
```

参照したデータが古かったせいかダメでした....
と思ったが、これはHomebrewのインストールでそれは確か済んでるはずなので次のMySQLのインストールの部分を実行します。
【実行コマンド】

```
brew update
brew install mysql

```

これだけでインストール完了しました！
パスワードなどの設定も済ませたのですが、最近のsequel proからは簡単にアクセスできなくなってたみたいで....

```
ALTER USER 'ユーザー名'@'localhost' IDENTIFIED WITH mysql_native_password BY 'パスワード';
```

この設定をする必要がありました。


#### 2. ライブラリの追加

MySQLにデータを入れるためにはそれ用のライブラリが必要なのでGemfileに下記の１行を追加します。

```Gemfile
gem 'activerecord'
gem 'mysql2', '0.5.2'
```

その状態で

`bundle install --path .bundle`
を実行すると。エラーになったのですが
```
bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl/lib"
```
このコマンドを実行したところ問題なくインストールできるようになりました。


### 3. ログデータの格納
まず、データを格納するためのテーブルを定義します。今回必要なのはどの画像が何日段階でどれだけダウンロードされてるかなので、ざっくり下記のようなテーブルになるかと。

```
CREATE TABLE `logs` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `image_id` int DEFAULT NULL,
  `download` int DEFAULT NULL,
  `date` date DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
```

そしてクローラーの方のコードに手を加えます。
まずMySQLとの接続用に

```crawler.rb
require 'active_record'
require 'date'


# DB接続処理
ActiveRecord::Base.establish_connection(
  :adapter  => 'mysql2',
  :database => 'データベース名',
  :host     => 'localhost',
  :username => 'ユーザー名',
  :charset => 'utf8mb4',
  :encoding => 'utf8mb4',
  :collation => 'utf8mb4_general_ci',
  :password => 'パスワード'
)

class Log < ActiveRecord::Base; end
```

上記のコードを追加します。
その上で、メインとなっていたパース処理の部分を

```crawler.rb
page = agent.get("https://www.photo-ac.com/creator/list/?pl_q=&pl_order=-releasedate&pl_pp=200&pl_disp=all&pl_ntagsec=&pl_tags50over=&pl_chkpsd=")
doc = Nokogiri::HTML.parse(page.body, nil, 'utf-8')
doc.css(".photo-list").each{|div|
  image_id =  div.css(".sectiondata li")[0].text.split("：")[1]
  download = div.css(".sectionimg .preview")[0].text
  Log.create({image_id:image_id,download:download,date:Date.today})
}
```

このように書き換えます。
そしていつものように実行をするとデータがちゃんと格納されると思います。
![](https://i.imgur.com/EFBmIiG.png)

これでデータの収集部分は完了です。
(少し過ぎてしまった....)
【Golang】標準パッケージ time

#【Golang】標準パッケージ time
Golangの基礎学習〜Webアプリケーション作成までの学習を終えたので、復習を兼ねてまとめていく。 基礎〜応用まで。

```
/*
https://golang.org/pkg/time/

const (
        ANSIC       = "Mon Jan _2 15:04:05 2006"
        UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
        RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
        RFC822      = "02 Jan 06 15:04 MST"
        RFC822Z     = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
        RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
        RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
        RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
        RFC3339     = "2006-01-02T15:04:05Z07:00"
        RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
        Kitchen     = "3:04PM"
        // Handy time stamps.
        Stamp      = "Jan _2 15:04:05"
        StampMilli = "Jan _2 15:04:05.000"
        StampMicro = "Jan _2 15:04:05.000000"
        StampNano  = "Jan _2 15:04:05.000000000"
)
*/
package main

//time
//時間
//time.Second
//time.Millisecond
//Sleep
//など。上記はフォーマットの型。

import (
	"fmt"
	"time"
)

func main() {
	//書き方
	t := time.Now()
	fmt.Println(t)
	//フォーマット
	fmt.Println(t.Format(time.RFC3339))
	//今の年、月など
	fmt.Println(t.Year(), t.Month(), t.Day(),
		t.Hour(), t.Minute(), t.Second())
}

```
エクスポートの使い方

# プログラミングの勉強日記
2020年6月8日　Progate Lv.85
JavaScriptⅴ

##デフォルトエクスポートとは
　`export default`のことである。ファイルがインポートされると同時に「export default 値」の値がインポートされる。なので、エクスポートしたときの値の名前と、インポートしたときの値の名前が違ったとしても問題ない。
　<font color=blue>※デフォルトエクスポートは1ファイルに1つの値しか使えない</font>
　　→複数の値をエクスポートしたいときは名前付きエクスポートを使う。

##名前付きエクスポート
　defaultを書かずに名前を{}で囲む。インポートするときは、`inport {値の名前} from "./ファイル名"`と指定する。複数の値をインポートするときは`,`（コンマ）で区切る。

```javascript:dogData.js
const dog1 = new Dog("レオ",4,"チワワ");
const dog2 = new Dog("ベン",2,"プードル");
export {dog1,dog2};
```

```javascript:script.js
import {dog1,dog2} from "./dogData";
```
Boost.Asio+OpenSSLでALPN

# ALPN
ブラウザがどのようにしてサーバがHTTP/2対応しているのか判断しているか調べたところ、TLS拡張の[ALPN](https://ja.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation)を使っていることがわかった。

# サーバ側の実装
HTTP2対応していたらHTTP/2、してなかったらHTTP/1.1にする手抜き実装。「[OpenSSL の ALPN/NPN API の使い方](https://qiita.com/tatsuhiro-t/items/dea3fb279ad265681049)」に記載があるように、1バイト目に長さが格納され、その後ろにプロトコル名が格納されている。

```C++
int alpn_select_callback(SSL *, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *) {
    if (in == nullptr) {
        return SSL_TLSEXT_ERR_NOACK;
    }
    unsigned int total = 0;
    for (const char *p = (const char *) in;  total < inlen; ) {
        int len = *p;
        if (strncmp(p + 1, "h2", len) == 0) { 
            *out = (const unsigned char *) "h2";
            *outlen = 2; 
            return SSL_TLSEXT_ERR_OK;
        }
        p += len + 1;
        total += len + 1;
    }           
    *out = (const unsigned char *) "http/1.1";
    *outlen = 8;
    return SSL_TLSEXT_ERR_OK;
}           
 
```

Boost.Asioで使うには以下のように実装すればよい。

```C++
boost::asio::ssl::context ssl_context;

SSL_CTX_set_alpn_select_cb(ssl_context.native_handle(), alpn_select_callback, nullptr);
```


# 参考
[OpenSSL の ALPN/NPN API の使い方](https://qiita.com/tatsuhiro-t/items/dea3fb279ad265681049)
ReactをTypeScriptで始める〜インストール編〜

この記事ではエラー内容の確認は書きませんので`Warning`などが出てきた場合は次のステップに進まず、書いてあるエラーへの対処をしてから進めてください。

#Node.jsをインストールする
[Node.js を Macへインストール 環境構築する](https://blog.u-chan-chi.com/post/setup-mac-node/)
ここがわかりやすいのでこれを見てください。

# Create React App

```
$ npx create-react-app アプリ名(フォルダ名) --typescript
```
npmのバージョンが5.2.0以降であればnpxが使えるはずです。
これでReactのプロジェクトができましたので、できてるか確認します。

```
$ cd アプリ名(フォルダ名)
$ npm run start
```

`cd`でプロジェクトに移動して、
`npm run start`でプロジェクトを実行します。
問題がなければ勝手にブラウザが立ち上がってReactの画面が表示されます。


# いろいろ入れる
## React Router
ReactはSPAなのでページ遷移が不可能ですが、それをページ遷移可能にするものがReact Routerです。
WEBの場合とネイティブの場合でインストールするものが異なりますが、今回はWEBなので`react-router-dom`をインストールします。
ネイティブの場合は`react-router-native`をインストールしてください。

```
$ npm install react-router-dom
$ npm install @types/react-router-dom
```


## Styled Components
CSS in JavaScriptを使えるようにします。
1行目が通常版のstyled-components
2行目がTypeScriptを使う場合に追加で必要なもの
今回はTypeScriptを入れたので両方とも実行してください。

```
$ npm install styled-components
$ npm install @types/styled-components
```


# おしまい
これで環境の準備が終わりました。
あとは好きなようにプログラムを書いてください。
これまで見た中で最も汚いソースコード

今回のコードの汚さには正直ちょっと自信あるよ。
下手すりゃIOCCCで優勝も狙えるかもしれないよ。

ということで、私がこれまで見てきた中で最も汚いソースコードを紹介します。


それは、とあるWebサイトのTwitterハッシュタグ埋め込みのコード。
よくあるやつですね。
普通であれば[タイムライン埋め込み](https://help.twitter.com/ja/using-twitter/embed-twitter-feed)使って一瞬で終わるやつです。

ただ、そこはけっこうお堅めのクライアントで、普通に埋め込むだけではできない要件が追加でありました。
すなわち、ハッシュタグを乗っ取る荒らし投稿などを絶対に表示させたくない、というものです。
具体的にはクライアントからNGワードのリストをもらって、それらの単語が含まれる投稿は表示しないようにします。

だいぶ昔の話なので実際はvarとか使ってたと思うんだけど、ざっくり書くとこんなかんじ。

```js
const ngWords = [/* 省略 */];

let tweetList = $.get('TwitterAPI');
tweetList.forEach(tweet=>{
  if(tweet.contains(ngWords)){
     return;
  }
  
  $('#timeline').append(tweet);
});
```

まあ、そこまではそれなりによくある案件だと思うのですよ。

さて問題はここからだ。

該当の処理が、HTMLのscriptタグ内に埋め込みで書かれていた。

はい、別ファイルにするわけでもなく難読化すらもされずに、NGワードの一覧がHTML内に堂々とテキストのまま突っ込んであったのですよ。
お堅いサイトだってのに、ソースを表示したら上の方に、決してまともなサイトに書かれていてはいけない単語の羅列がですね、「ち××」とか「ま××」とか「う××」とか並んでいるわけですよ。
そりゃもう「弊社なにやってんの…」と天も仰ぐってものですよ。

私がこのことを知ったのは、とっくに納品されてサービスインが終わった後でのことでした。
そもそも私の関係している案件ではなく、たまたま別件のついでに発見しただけなので、事前に気付きようがありませんしね。

だが担当！お前は！何をやってたんだ！！

なおクライアントも気付いてなかったので、とりあえず見なかったことにしました。

今やそのサイトも消滅し、証拠も全て消えたので、まあ時効ということで。
Kubernetes のオートスケーリングいろいろ

Kubernetes の本質はスケーリングだと思っている今日このごろ。
がしかしいろいろな場所で、いろいろな方法でスケーリングの機能が実装されており混乱しています。

私が把握しているのは3つの機能としてのオートスケーリングです。

- 水平ポッドオートスケーリング
- 垂直ポッドオートスケーリング
- クラスタオートスケーラー

**対象がPodなのかノードなのか、方向が水平か垂直なのか** がまず分かれば中身を理解するのは難しくないはず。

## 漢字 ＋ カタカナ英語 ＋ 英語に疲弊する私

オートスケーラー、Autoscaler、オートスケーリング、Autoscaling、自動スケーリング、自動スケーラー …

ポッドにPod、ノードにNode …

呼び方がいまいち統一されておらず情報収集に苦労したので自分でまとめることにしました（強気

ちなみにGCP大好きマンなので、GCPでの設定方法・考え方になってます。EKSのそれらとは微妙に異なるかもです。あしからず。

そしてコードは1行もありません。概念のまとめです。あしからず……



## 水平ポッドオートスケーリング（Horizontal Pod Autoscaling）

**対象**：Pod


**概要**

Podに対する負荷に応じてPodの数を増やすことでワークロードの変化に対応する。
水平なので、横にPodが並ぶように増えたり減ったりするとイメージしやすいはず。

HPAでは「実際のリソース使用量」「カスタム指標」「外部指標」をもとにPodの数を自動的に調整する。

- 実際のリソース使用量 … 文字通りPodでのリソース使用量。絶対値・割合のどちらの指定も可能。
- カスタム指標 … クラスタ内のKubernetesオブジェクトによって報告される任意の指標。クライアントからのリクエスト数やI/Oなど。
- 外部指標 … クラスタ外部のアプリケーションやサービスからの指標。接続されるキューの状況など。


**その他、注意点**

- リソース（CPU/メモリ）を評価する場合、垂直ポッドオートスケーリング（Vertical Pod Autoscaling）との併用はできない。リソース以外を評価する場合はVPAと併用可能。
- Deploymentに対してHPAを使いたい場合はDeploymentリソースに対して使う。ReplicaSetには使わない。悲惨なことになる。



## 垂直ポッドオートスケーリング（Vertical Pod Autoscaling）

**対象**：Pod


**概要**

Podに対する負荷に応じて podに割り当てるCPUやメモリを動的に変化させることでワークロードの変化に対応する。

水平スケールがPodの数を増やしたり減らしたりするのに対して、垂直スケールはPodのスペックを上げたり下げたりする。1つのPodの大きさを上下させると考えるとわかりやすい。

>Vertical Pod Autoscaler (VPA) frees the users from necessity of setting up-to-date resource limits and requests for the containers in their pods. When configured, it will set the requests automatically based on usage and thus allow proper scheduling onto nodes so that appropriate resource amount is available for each pod. It will also maintain ratios between limits and requests that were specified in initial containers configuration.

[とあるように](https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler)、正確にはリソースの使用状況からリクエスト値を自動で算出してPod作成時に付与している。
これによって我々はリソースのリクエストやリミットを事細かに計算する必要がなくなります。

**その他、注意点**

- kubernetesバージョン1.12.6以降、リージョンクラスタでしか利用できない。
- 垂直ポッドオートスケーリング（Vertical Pod Autoscaling）との併用はできない。リソース以外を評価する場合はVPAと併用可能。


## クラスタオートスケーラー(Cluster Autoscaling)

**対象**： 

Node（Node Pool）


**概要**：

事前定義したノードプールの最小数と最大数の間で、ノード数を変動させることでワークロードの変化に対応する。

ノードプール内のノード数が不足していてPodをスケジュールできない場合、クラスタオートスケーラーは、ノードプールの最大サイズまでノードを追加する。
逆にノードプール内のノード数を少なくしてもすべてのPodのスケジューリングが可能な場合は、クラスタオートスケーラーはノードプールの最小サイズになるまでノードを削除する。

パターンとしてよくあるのは、負荷が上がってきたらPodの数を増やし、ノードあたりのPod数が多くなってきたらノードを増やすというやり方。


**その他、注意点**

- ノードプールのノードで実行されているPodのリソースリクエスト数に基づいてノードプールのサイズを自動的に調整している。実際のリソース使用率ではない。
- GKEのクラスタオートスケーラーは、[Compute Engineの自動スケーリング](https://cloud.google.com/compute/docs/autoscaler?hl=ja)とは別もの。
- それぞれ30個のPodを実行するノードを最大1,000台までスケールできる。


## 最後に

自分もPodとノードを同居させていた。ごめんなさい。これがカナカナ英語の弊害。
GASでGoogleカレンダーに予定を追加する


# GASでGoogleカレンダーに予定を追加する
GASでGoogleカレンダーに予定を追加する方法について書きます。




# 解説
まず、カレンダーに予定を登録する手順としては、下記の2ステップとなります。

1. カレンダーを特定します。
2. 予定を追加します。


##1. カレンダーを特定します。

下記のどちらかのステートメントでカレンダーを指定します。

- `CalendarApp.getCalendarById("カレンダーID");`
    - カレンダーが固有にもつユニークなカレンダーIDを指定してカレンダーを指定します。
- `CalendarApp.getDefaultCalendar();`
    - Googleアカウントが最初に持ってるカレンダーを指定します。

###カレンダーIDとは


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342467/eef01a95-57d2-cfd9-5869-cdd61fd2472f.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342467/8e6367ab-32fc-2f2c-fd81-43b4e889c1e0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342467/a1fb154f-f70f-4355-4f98-10aa3a02809a.png)
カレンダーの設定画面が表示されますので、画面を下にスクロールしていくとメールアドレス形式のカレンダーIDを確認出来ます。


##2. 予定を追加します。

予定を追加するメソッドは下記があります。

- `createEvent()`
    - 予定追加
- `createAllDayEvent()`
    - 終日の予定を追加
- `createEventSeries()`
    - 繰り返しの予定
- `createAllDayEventSeries()`
    - 終日の繰り返しの予定を追加


- 終日予定
    - 時間を指定せず日付だけ指定して登録する予定
- 繰り返しの予定
    - 毎日、毎週火曜日、など繰り返す予定



# コード例
ただ、予定（の名前）を登録するだけでしたら下記のコードだけでカレンダーに登録できます。

```javascript

　var CALID = "カレンダーID";
  var eventdate = new Date();
  var cal = CalendarApp.getCalendarById(CALID);
  cal.createAllDayEvent("イベント名", eventdate);
```

# メソッド詳細
メソッドのオプションや、詳しい仕様は下記を参照します。


> GoogleカレンダーAPI　ドキュメント
> https://developers.google.com/calendar/v3/reference/events#resource
JetsonやRaspberryPi(arm64)にVisual Studio Codeをインストールする

# 追記 (2020.10.9)

September 2020 (version 1.50)で、ついにArmとArm64に公式で対応されました。
下記からダウンロードしてインストール可能です。

https://code.visualstudio.com/download#

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638977/9e7ccf99-a499-9223-62fa-3b97a70ca26b.png)



# 一言でいうと

* Visual Studio Code OSS arm64をインストールした。
* Visual Studio Codeの公式版は、まだarm64をサポートしていない。(2020.6.8時点)
    * https://github.com/microsoft/vscode/issues/98818

# インストール手順

Visual Studio Code OSS版のインストール手順に従う。
 https://code.headmelted.com/

```bash
$ sudo -s
$ . <( wget -O - https://code.headmelted.com/installers/apt.sh )
```

# 起動

```bash
code-oss
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638977/392076fc-5b6e-73e4-846a-7f1308a00002.png)


# まとめ

* Visual Studioc Code OSS arm64をインストールした。
* 今の所問題なく使えているので、公式版が出るまではこちらを使うと良い。
効率よくマイクロSDカードを収納してGoogleスプレッドシートで管理してみた

この記事では、以下の実践事例を紹介しています。

- マイクロSDカードだけを効率よく収納できるケース
- マイクロSDカードを外見から識別できるようにする方法
- マイクロSDカードと記録内容をGooleスプレッドシートで管理する方法

## マイクロSDカードだけを収納したい
ネット検索してもSDカードと一緒に収納するケースばかりでマイクロSDカードだけが収納できるケースはなかなかヒットしません。Amazonで「この商品をチェックした人はこんな商品もチェックしています」など漁ってようやく見つけました。クレジットカードサイズで10枚収納可能。とりあえず２つ注文。Amazon.co.jp発送なので待たずに手に入りました。

- [Amazon - Kiorafoto 10スロット MicroSD MSD Micro SDカードケース...](https://www.amazon.co.jp/gp/product/B01BWM2BAG/ "Amazon.co.jp")

硬くて取り出しにくい箇所があるというレビューがありましたが、確かにそのとおりで、マイクロSDカードのメーカーによっては硬くて取り出しにくい箇所がありました。しかし、赤い側のシールを全面剥がしたら、なぜか解消しました。マイクロSDカードの表面も透けて見えるので良さげです。(下の画像ではケースを2つ並べています)
![folderrs.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308714/142d810f-7d4b-c2df-7efe-ab1019dda911.jpeg "カード収納裏面")

## マイクロSDカードを外見から識別したい
### マイクロSDカード側
マイクロSDカードにシールのようなラベルを直接貼るのは良くないようですし、直接文字を書くにしてもスペースがありません。裏側(真っ黒な面)には薄っすらと小さな文字が印刷されていますが、なんとか頑張って余白に識別子を書くくらいはできそうです。私の場合は、下の画像のように、色と番号で識別するようにしました。(雑ですね。。。)
![cardnums.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308714/e4a65b88-0a0e-4cc6-9664-93678c929d7a.jpeg "マイクロSDカードの識別子")

- 色：ペイントマーカーという油性ベンで2度塗りしました(よく乾かします)
- 番号：油性のなまえペンで書きました

ケースが10枚収納できるので、番号は"0”～"9"、色は記録内容で分けて、OS系を銀色、データ系を桃色にしました。
### ケース側
このケースは収納位置毎に書き込みができるようになっていますが、テプラで番号のシールを作って貼りました(手持ちに桃色のテプラテープがなかったので緑です)。ケースの方にもペイントマーカでカードと同じ色を付けました。(下の画像ではケースを2つ並べています)

![folderfs.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308714/2f736c0d-59dd-cda5-472e-1d1b9b412850.jpeg)

以上で、現物と入れ物の紐付けができるようになりました。

## マイクロSDカードと記録した内容を紐付けて管理したい
管理したい項目も少ないし、マイクロSDカードの枚数も何百枚も持つことはないので、お手軽にできる方法でGoogleスプレッドシートを使いました。Googleドライブで自宅のPCでも、外出先のスマートフォンでも参照・更新できるところが良いです。
現状は下のような表にしました。

![マイクロSDカード3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308714/ee34269b-69a8-d3ee-d644-b7c2c8624d6e.png "マイクロSDカード管理表")

### マイクロSDカード管理表の説明
各項目は以下のようにしました。

| 項目名 | 書式など | 内容 |
|:--|:--|:--|
| 識別 | (予め入力) | 識別色 セル背景にも同色を付けました |
| 番号 | (予め入力) | 識別番号 |
| 種別1 | データの入力規則にて選択式 | 記録内容をざっくり分類するとこんな感じかと<br>　"OS,データ,未使用,その他" |
| 種別2 | データの入力規則にて選択式 | 使った装置がわかる感じで<br> "RaspberryPi,Linux,Windows,スマートフォン,その他" |
| 内容 | 自由記入 | 種別1、2の他に詳細がわかるように |
| サイズ | 自由記入 | マイクロSDカードのサイズは色々あるので自由記入で |
| スピード | データの入力規則にて選択式 |  スピードクラスは表記記号がいろいろあるので選択式の方が良いかと<br>　"②/ － /－,④/ － /－,⑥/ － /V6,⑩/UHS1/V10,－/UHS3/V30,－/ － /V60,－/ － /V90"  |
| ブランド | 自由記入 | メーカー名や製品名など |

大きな表ではありませんが、スマートフォンではスクロールしないと全体が見えません。外出時では参照が主なので不自由は感じていません。

## 最後に
以上で、自分なりにスマートにマイクロSDカードが収納・管理できるようになりました。技術的な難易度は０ですが、(自分の)要求仕様を満たすように、コストをかけず、すぐに使えるものを選択できたと思います。
この記事が少しでもご参考になれば幸いです。
2020/06/07 プログラミング(フロントエンド)学習8日目 メモ

# 本日の学習範囲
（学習時間：2時間）
### ドットインストール
・詳解CSS レスポンシブウェブデザイン編 #01〜#02
### 基本情報技術者テキスト
・特集部分(このあと読む)
## HTML学習メモ
### viewport
Webページの表示領域
`<meta name="viewport" content="width=device-width, initial-scale=1”>`
とすると、
横幅がデバイスの横幅で、そのままの表示倍率で表示するように指定できる
### その他
レスポンシブデザインに関して、
ドットインストールの無料部分では上記くらいの内容しか学習できなかったため、
明日以降ググりながら勉強する。
Spring Frameworkを使ってみる（３）

# 画面間の値の受け渡し

## index.jspを編集

```html:index.jsp
<!DOCTYPE html>
 
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
 
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="f" uri="http://www.springframework.org/tags/form"%>
 
<html>
 <head>
 <meta charset="utf-8">
 <title>ログイン</title>
 </head>
 <body>
 <f:form modelAttribute="loginForm" action="login" method="post">
 <div>
 ユーザ名：<input type="text" id="loginName" name="loginName">
 </div>
 <div>
 パスワード：<input type="text" id="loginPassword" name="loginPassword">
 </div>
 <div>
 <input type="submit" value="ログイン">
 </div>
 </f:form>
 
 </body>
</html>
```

# Loginformを作成

```java:Loginform.java
package com.example.HelloWorld;
 
public class LoginForm {
    private String loginName;
    private String loginPassword;
 
    public String getLoginName() {
        return loginName;
    }
 
    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }
 
    public String getLoginPassword() {
        return loginPassword;
    }
 
    public void setLoginPassword(String loginPassword) {
        this.loginPassword = loginPassword;
    }
}
```
# LoginControllerを編集

```java:LoginController.java
package com.example.HelloWorld;
 
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
 
@Controller
public class LoginController {
	@RequestMapping(value = "/login", method = RequestMethod.POST)
		public String login(Model model, @ModelAttribute("loginForm") LoginForm loginForm) {
		model.addAttribute("loginName", loginForm.getLoginName());
		return "top";
	}
}
```
@ModelAttribute(“loginForm”)」が、「index.jsp」の中で指定した「modelAttribute」とマッピングされます。そして、その内容は「LoginForm」クラスの同名の変数へと格納されていきます。格納された値を次の画面へ引き継ぐために「”loginName”」という値でModelに追加しています。

# top.jspを編集

```html:top.jsp
<!DOCTYPE html>
 
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
 
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
 
<html>
 <head>
 <meta charset="utf-8">
 <title>トップ</title>
 </head>
 <body>
 ようこそ<c:out value="${loginName}" />さん
 </body>
</html>
```
サーバを立ち上げると、下記画面が表示され、適当なloginNameを入力し、ログインを押下します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399736/fcc9b735-2d9e-96a8-e329-054eec6cea42.png)

下記の画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399736/44a44b37-7863-71a6-26aa-8016ff1c279f.png)

# 次回
[入力された値のチェック](https://qiita.com/Hakata2002/items/1b6f2753e817e4eecc53)を実装していきます。
【ATL】Windowsのサービスを作成する

# 概要
Visual Studio 2019のATLプロジェクトを使用してWindowsのサービスを作成します。

# 新しいプロジェクトの作成
1. Visual Studio 2019を起動し、[新しいプロジェクトの作成]を選択します。
![VisualStudio2019起動.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/608900/fdf8cfcc-2cd5-eeb7-8c48-862ee82817d3.png)

2. [ATLプロジェクト]を選択して、[次へ]を押します。
![ATLプロジェクトの選択.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/608900/33b02e34-f103-2ecc-7f91-21c492bb4ee1.png)

3. [プロジェクト名]を入力します。ここでは"ATLServiceSample"とします。
必要に応じて[場所]も設定します。
またお好みで[ソリューションとプロジェクトを同じディレクトリに配置する]にチェックを入れます。
設定が終わったら[作成]を押します。
![新しいプロジェクトの構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/608900/5601aa8d-0c85-e7d4-7222-adb2214d4dc4.png)

4. [アプリケーションの種類]で[サービス(.exe)]を選択し、[OK]を押します。
![ATLプロジェクトの構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/608900/07902605-3e09-30db-109d-f2868f5e3fc4.png)

これでプロジェクトが作成されました。
私はプロジェクト作成後に下記を行っていますが、必須ではありません。

- ATLServiceSamplePSプロジェクトの削除
- [ATLServiceSamplePS]フォルダを中のファイルごと削除
- ATLServiceSampleプロジェクトのプロパティにおいて下記を設定。
  - [構成プロパティ]→[C/C++]→[コード生成]：[ランタイムライブラリ]=[マルチスレッド]
  - [構成プロパティ]→[リンカー]→[全般]：[出力の登録]=[いいえ]

# 実行ファイルの作成

1. 現時点ではCOMを使っていないので、"_ATL_NO_COM_SUPPORT"を定義しておきます。
[構成プロパティ]→[C/C++]→[プリプロセッサ]：[プリプロセッサの定義]に追加しても、ソースコード上で定義しても構いませんが、私は前者にしました。
COMオブジェクトが未実装＆この定義が無い状態だと、サービス実行時、メインループに入らずに下記のメッセージが出てしまいます。
![_ATL_NO_COM_SUPPORT定義無し.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/608900/fe53ccf6-83de-9bbe-6763-27a04cabeafa.png)

2. この時点でもサービスとして動きますが、これからサービス処理を実装していくにあたって必要な関数を追加しておきます。
追加する関数は、下記の3つです。

- PreMessageLoop : 初期化処理
- RunMessageLoop : メイン処理
- PostMessageLoop : 終了処理

```C++:ATLServiceSample.cpp
class CATLServiceSampleModule : public ATL::CAtlServiceModuleT< CATLServiceSampleModule, IDS_SERVICENAME >
{
public :
	DECLARE_LIBID(LIBID_ATLServiceSampleLib)
	DECLARE_REGISTRY_APPID_RESOURCEID(IDR_ATLSERVICESAMPLE, "{20521712-cd2f-409a-8fb7-c1cf9957b0d5}")
	HRESULT InitializeSecurity() throw()
	{
		// TODO: CoInitializeSecurity を呼び出し、サービスのための適切なセキュリティ設定を指定します
		// 推奨 - PKT レベルの認証、 
		// RPC_C_IMP_LEVEL_IDENTIFY の偽装レベル
		// および適切な非 NULL セキュリティ記述子。

		return S_OK;
	}

#if 1 // ここから追加
	// 初期化
	HRESULT PreMessageLoop(_In_ int nShowCmd) throw()
	{
		HRESULT hr = __super::PreMessageLoop(nShowCmd);
		if (SUCCEEDED(hr))
		{
			// ToDo: ここに初期化処理を実装する
		}
		return hr;
	}

	// メイン処理
	void RunMessageLoop() throw()
	{
		// ToDo: ここをサービスの内容に応じて変更する
		MSG msg;
		while (GetMessage(&msg, 0, 0, 0) > 0)
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	// 終了処理
	HRESULT PostMessageLoop() throw()
	{
		// ToDo: ここに終了処理を実装する

		return __super::PostMessageLoop();
	}
#endif // ここまで追加
};
```

3. プロジェクトをビルドします。<BR>
ソリューション構成＆プラットフォームは何でも構いませんが、私はReleaseのx64でビルドしました。

# サービスの登録
1. 管理者として実行したコマンドプロンプトから下記のコマンドを実行します。
`"D:\Work\ATLServiceSample\x64\Release\ATLServiceSample.exe" /Service`
※ 実行ファイルのパスはそれぞれの環境のものを使用してください。

2. スタートメニューから[Windowsツール]→[サービス]を開き、[ATLServiceSample]が登録されていればOKです。
![サービス.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/608900/ad8a35fe-31d1-af3d-63f9-f336fe893191.png)
GitHubでフォーク先から上流リポジトリにPRを送るときにやること

# はじめに

最近、Microsoft さんが GitHub で公開している OSS へのプルリクエスト(PR)を送ることが多くなりました。
PR は、`フォークした自身のリモートリポジトリ -> 本家リポジトリ`の形で送っていますが、本家リポジトリはかなりの頻度で更新が行われているため、本家リポジトリをフォークした時点と PR を送る時点にて、内容に多くの差分があることがあります。
そのため、自身の忘備録として、PR を送る前にやることをまとめました。

# PR前にやること

## upstream の設定

これは、GitHub 上でフォークする時は(おそらく)自動で行ってくれていると思いますが、きちんと本家のリポジトリが upstream に設定されているかを確認します。
*今回は、Visual Studio Code の Azure Databases 拡張機能を例にしていきます。*

Fork したリポジトリを Clone しているディレクトリに移動します。

```bash
cd vscode-cosmosdb
```

`git remote -v`を実行して、upstream が設定されているか確認しましょう。

```bash
git remote -v
```
```bash:実行結果
origin  https://github.com/ymasaoka/vscode-cosmosdb.git (fetch)
origin  https://github.com/ymasaoka/vscode-cosmosdb.git (push)
upstream        https://github.com/microsoft/vscode-cosmosdb.git (fetch)
upstream        https://github.com/microsoft/vscode-cosmosdb.git (push)
```

はい、きちんと設定されています。
もし、upstream が設定されていない場合は、きちんとフォーク元の上流リポジトリを設定しましょう。

```bash
git remote add upstream https://github.com/microsoft/vscode-cosmosdb.git
```

## フォーク先のリポジトリを最新化

フォーク先のリポジトリが、フォーク元のリポジトリの最新の状態と同期するようにします。
上流リポジトリから、ブランチと各ブランチのコミットをフェッチします。

```bash
git fetch upstream
```

## フォーク先のリポジトリを更新

現在見ているブランチを master に変更します。

```bash
git checkout master
```

`upstream/master`から`master`ブランチに変更をマージします。
フォーク元のリポジトリに存在しない、独自のコミットが存在する場合は、ファーストフォワードでマージが行われます。

```bash
git merge upstream/master
```

この操作では、**フォーク先のリポジトリのローカルが最新化された**だけなので、きちんとリモートのフォーク先リポジトリにプッシュをします。

```bash
git push origin master
```

これで、フォーク先のリモートリポジトリが最新化されました。
最新化したのち、きちんと PR を送りましょう。

# おわりに

プロジェクトによっては、リポジトリをフォークせずにブランチで対応する、などもありますが、OSS 界隈では特に **個人として貢献している** といった見え方を推奨している部分もあるので、よくフォークしがちな時分です。
PR 出したいは良いものの、コードが古くてマージしてもらえない、相手にマージしてもらうために無駄な作業を行わせてしまう、といった負荷を与えないためにも、リポジトリは最新化した状態で PR を送りたいですね。

**なお、これを実施したからといって必ず PR が承認されるわけではありません。**その点、予めご承知おきいただければと思います。


# 参考情報

## GitHub ヘルプ

- [フォークにリモートを設定する][configuring-a-remote-for-a-fork]
- [フォークを同期する][syncing-a-fork]

---
[configuring-a-remote-for-a-fork]:https://help.github.com/ja/github/collaborating-with-issues-and-pull-requests/configuring-a-remote-for-a-fork
[syncing-a-fork]:https://help.github.com/ja/github/collaborating-with-issues-and-pull-requests/syncing-a-fork
ロードバランサ構成でもCakePHPのredirectを使いたい

# バージョン

CakePHP：3.8

# 構成

```
ブラウザ
   ---(HTTPS)--- Load-Balancer(wish SSLサーバ証明書)
   ---(HTTP)--- WEBサーバ
```

# やりたいこと・困りごと
1. Cake\Controller\Controller::redirect的なのを使いたい
2. Load-Balancer経由のアクセスでは、httpsでredirectして欲しい
3. WEBサーバIPアドレスへのアクセスでは、httpでredirectして欲しい

↓

- https://github.com/cakephp/app/blob/71f9653/config/app.php#L39-L42 のfullBaseUrl に定義すると、2.と3.の挙動切り替えができない
- https://github.com/cakephp/app/blob/71f9653/config/bootstrap.php#L139-L141 で`env('HTTPS')`を見てhttp→https変換をしているが、3.を満たしたいため、指定できない

# 解決法1：beforeFilterで書き換え
`src/Controller/AppController.php`

```
function beforeFilter(Event $event) {
    ・・・
    if ( isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && 'https' == $_SERVER['HTTP_X_FORWARDED_PROTO'] ) {
        Router::fullBaseUrl( 'https://'.$_SERVER['HTTP_HOST'] );
    }
    ・・・
}
```

- AWSのElastic Load Balancingは、HTTP_X_FORWARDED_PROTOやHTTP_X_FORWARDED_PORTで判定できる
- 他のロードバランサの場合、どのヘッダで判断できるか調査必要

# 解決法2：Cake\Controller\Controller::redirectをoverwrite
`src/Controller/AppController.php`

```
public function redirect($url, $status = 302) {
    $this->response = $this->response->withLocation(Router::url($url, false));
    return parent::redirect($url, $status);
}
```

- https://github.com/cakephp/cakephp/blob/44a7812/src/Controller/Controller.php#L734 にて、`Router::url($url, true)`となっている部分を、`Router::url($url, false)`に書き換える
    - before：`Location: http://example.com/path/to/file`
    - after：`Location: /path/to/file`
- Locationヘッダは、RFC7231(2014年発行)より、パスのみ指定でも動くべし、となった
    - https://tools.ietf.org/html/rfc7231#section-7.1.2
    - これに準拠しているブラウザ/クライアントならば、`Router::url($url, false)`で問題なく動く
    - 準拠していない場合は・・・解決法1使う
GASを使ってGoogleDrive内のデータを定期的にバックアップする

## はじめに
GoogleDriveの特定フォルダ内のデータを定期的にバックアップ（別フォルダにコピーを作成）したかったので、自動化してみました

## コード
```sample.js
/**
 * メイン処理
 */
function main() {
  const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = spreadsheet.getActiveSheet();
  const copyBaseDirectoryID = sheet.getRange("B1").getValue();
  const copyTargetParentDirectoryID = sheet.getRange("B2").getValue();
  const outputParentDirectory = DriveApp.getFolderById(copyTargetParentDirectoryID);
  const inputDirectory = DriveApp.getFolderById(copyBaseDirectoryID)

  //現在日時を取得
  const now = new Date();

  //取得した現在日時を指定した表示形式に変換
  const time = Utilities.formatDate(now, "Asia/Tokyo", "yyyy_MM_dd_HH_mm_ss");

  // コピー先となるディレクトリを作成
  const outputDirectory = outputParentDirectory.createFolder(time);
  
  //フォルダ内のファイルを一括取得
  const files = inputDirectory.getFiles();

  // 指定箇所にファイルをコピー  
  for(let i = 0; files.hasNext(); i++) {
    const file = files.next();
    const baseData = DriveApp.getFileById(file.getId());
    
    baseData.makeCopy(file.getName(), outputDirectory);
  }
}

/**
 * カスタムメニュー
 */
function onOpen()
{
    const ui = SpreadsheetApp.getUi();
    ui.createMenu("マクロ")
        .addItem("ディレクトリのコピーを実行", "main")
        .addToUi();
}

```
## デモ
※閲覧できない場合はGoogleアカウントを一度ログアウトしてからお試し下さい
https://docs.google.com/spreadsheets/d/1NqdvyWAsJrqlW0bGN2u_YnO7EixlSVnmvZ4G4AhJQ70/edit#gid=0

## フォルダIDとは
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636565/644bd29f-9798-cfa9-11db-13e0918851dc.png)
pythonのアンダースコア(_)ってなんのためにあんの？

# 結論
1.  Return値を無視する
* 関数の名付けで使い方を区別する。
* 数字を読みやすくする。
* インタプリタで最後に表示された値を代表する。

そして、これらを使いこなすことで、「**俺、pythonすげぇ知ってるんだぜ**」感を友達に見せつけることができるようになるぞ！

# 内容

# 1. Return値を無視する

これはおなじみで、よくみますよね。省略。

# 2. 関数の名付けで使い方の区別
これが色んなパターンが出てきてよくわからんとなった。

## a. _function(x): #関数前に一つ

```
def _single_leading_underscore(x):
    return something
```

関数前に一つアンダースコアを付ける事により、関数を”内部用”に定義できる。つまり、ほかのpythonファイルからimportした時にこの関数は読み込まれない。ちょっと計算するけど煩雑になるから関数化しとこ～くらいのモチベーションでこれが使われる。

## b. function_(x): #関数後に一つ

```
def single_trailing_underscore_: 
    return something
```
これはぶっちゃけ、見たことないけど、関数後に一つアンダースコアを付けるのはPython内の重要関数と名付けを被らせない為に使う。listと同じ名前がどうしても関数名として使いたいという困ったちゃんが多用するのであろう。

でもな、それなら別の名前をつけなはれと思う。

## c. __function(x): #関数前に二つ

```
def __double_leading_underscore: 
    return something
```
class内の関数前に二つアンダースコア付けることで、名前の マングリング機構を呼び出す。このいかめしい「マングリング機構」とは、インタプリタやコンパイラーが普通の方法で変数を扱わなくなることで、例えばclass FooBarの関数__booについて、Foobar.__barでは関数を呼べ出せなく、_Foobar__booという使い方になる。

うん、あんま使わん。

## d. __ function __(x): #関数前後に二つずつ

```
def __double_leading_and_trailing_underscore__: 
    return something
```

class内の関数の前後に二つずつアンダースコア付けることで、magic methodになる。この聞きなれぬ「magic method」とは日本の書籍ではクラスの特殊メゾットと呼ばれているメゾットで、所謂classを作成する際にお世話になっている

```
__init__
```
のことである。特殊メソッドはたくさんあるので、[こちらのリンク](https://www.atmarkit.co.jp/ait/articles/2002/18/news007.html)で確認してほしいが、特殊メソッドは基本的にっ既存のものを使い、自分で新しく定義しない方が賢明やね。

# 3. 数字を読みやすく
```
>>> 1000000
Out: 1000000
>>> 1_000_000
Out: 1000000
```
python3.6以降で実装された、長い数字をわかりやすくするために使われる。

むしろ、このルール知らなかったら「なんで数字の中にアンダースコアあるの？」となるに違いない。初心者向けの言語として有名なpythonが初心者に対しての可読性下がってない？

# 4. インタプリタで最後に表示された値を代表


インタプリタでは、アンダースコアは最後の表示(expression value)を代表しているらしい。よくわからん。

---



参考文献
[Medium](https://medium.com/lsc-psd/pythonic%E8%89%B2%E3%80%85-python%E3%81%AE%E3%82%A2%E3%83%B3%E3%83%80%E3%83%BC%E3%82%B9%E3%82%B3%E3%82%A2-%E3%82%92%E4%BD%BF%E3%81%84%E3%81%93%E3%81%AA%E3%81%9D%E3%81%86-3c132842eeef)

[magic method](http://www.ops.dti.ne.jp/ironpython.beginner/method.html)
Spring Frameworkを使ってみる（２）

# おさらい
この章で下記の内容を紹介しています。

- 画面遷移
- 遷移元画面index.jspの作成
- 遷移先画面top.jspの作成
- ログイン画面のコントローラLoginController.javaの作成

# 画面遷移
## Propertiesファイルを編集
Spring boot start projectのため、JSPを利用するには、少々面倒な設定が必要です。
ちなみに、Spring bootはJSPを非推奨で、Thymleafが推奨されています。

Thymeleafを利用したHTMLの場合、templatesフォルダの配下へHTMLファイルを配置します。
staticフォルダ配下へjs, cssファイルを配置します。

application.propertiesには下記を追記します。

```properties

spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399736/41778b37-9764-4452-20c4-80604bec537f.png)

# index.jspを作成
index.jspファイルをWEB-INFのjspフォルダ配下へ配置します。

```html

<!DOCTYPE html>
 
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
 
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
 
<html>
 <head>
 <meta charset="utf-8">
 <title>ログイン</title>
 </head>
 <body>
 
<form action="login" method="post">
 
<div>
 <input type="submit" value="ログイン">
 </div>
 
 </form>
 
 </body>
</html>
```
サーバを立ち上げた後に、Path with WEB-INF or META-INFというWarningメッセージが出て、ページが表示されない場合、下記のリンクを参照し、解決することができます。
https://www.yawintutor.com/warn-3200-path-with-web-inf-or-meta-inf/

# top.jspを作成

```java:LoginController.java
<!DOCTYPE html>
 
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
 
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
 
<html>
 <head>
 <meta charset="utf-8">
 <title>トップ</title>
 </head>
 <body>
 ようこそ
 </body>
</html>
```
# LoginController.javaを作成

```java:(LoginController.java)
package com.example.HelloWorld;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
 
@Controller
	public class LoginController {
	@RequestMapping(value = "/login", method = RequestMethod.POST)
	public String login(Model model) {
		return "top";
	}
}
```
コントローラに関する説明は下記を参照してください。

- [Spring Boot解説第18回(基本編：Controllerとは)](https://qiita.com/TEBASAKI/items/267c261db17f178e33eb)


---
サーバを立ち上げて、index.htmlへアクセスすると、下記画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399736/0b257bd4-d2d3-384d-52c2-dcf1add02ce1.png)

ログインを押下すると、top.htmlへ遷移することができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399736/70f30a17-3061-1798-fdd3-992ad5e8db04.png)

# 次回
[画面間の値の受け渡し](https://qiita.com/Hakata2002/items/afcefe1fdbf44c097fd9)を説明します。
【Rails】link_toでデータの受け渡しをしたい（途中）

# やりたいこと

リンクのリクエスト先は同じだが、リンクの押されたページごとに違う処理を行いたい。
そのために、リンクが押された時に、ページ判別用のflagを渡したい。

遷移パターンは以下の通り

- 一覧（scolor/index）→削除→TOPページ（scolor/index）
- 詳細（scolor/[:id]）→削除→「削除しました」画面（scolor/delete）


# 実装方法

## destroy_pathをルーティングで定義する

[【Rails入門説明書】redirect_toについて解説](https://web-camp.io/magazine/archives/18271)

## link_toでidとflagのparamを渡す
<%= link_to "削除", destroy_path_url(id: scholor.id, flag: 0) %>



# 参考
- [Railsのlink_toでparamsを飛ばす方法](https://qiita.com/ATORA1992/items/566d76a7092bff40df4c)
Java ラムダ式の使いどころ

#概要
Java8からラムダ式が導入された。
本ページは、Javaのラムダ式の使いどころについてのメモページ。
ラムダ式は、StreamAPIと組み合わせて使用すると、使い勝手が良い。

##リストから一定の条件で値を取り出し
###ラムダ式、StreamAPIの使用なし
```java
List<Integer> list = Arrays.asList(2, 9, 5, 7, 4);

for (Integer i : list) {
    if (i >= 5) {
        System.out.println(i);
    }
}
```
###ラムダ式、StreamAPIを使用あり

```java
List<Integer> list = Arrays.asList(2, 9, 5, 7, 4);

list.stream()
        .filter(i -> i >= 5)
        .forEach(System.out::println);
```

ラムダ式、StreamAPIを使用したほうがスッキリと可読性良く記載ができる。
以下、ラムダ式、StreamAPIを使用した例を列挙。

##辞書順ソート

```java
List<String> list = Arrays.asList("b", "c", "a", "c", "b");

list.stream()
        .sorted()
        .forEach(System.out::println);
```

##逆辞書順ソート

```java
List<String> list = Arrays.asList("b", "c", "a", "c", "b");

list.stream()
        .sorted((s1, s2) -> s2.compareTo(s1))
        .forEach(System.out::println);
```

##重複削除

```java
List<String> list = Arrays.asList("b", "c", "a", "c", "b");

list.stream()
        .distinct()
        .forEach(System.out::println);
```

##5以上の値の個数をカウント

```java
List<Integer> list = Arrays.asList(2, 9, 5, 7, 4);

long count = list.stream()
        .filter(i -> i >= 5)
        .count();

System.out.println(count);
```

##5以上の値を合算

```java
List<Integer> list = Arrays.asList(2, 9, 5, 7, 4);

int sum = list.stream()
        .filter(i -> i >= 5)
        .mapToInt(i -> i)
        .sum();

System.out.println(sum);
```

##1～10の値をマルチスレッドで出力

```java
IntStream.range(0, 10)
        .parallel()
        .forEach(System.out::println);
```
【AWS】本番環境でのエラー確認方法について

#はじめに
自分用備忘録のためにという部分も含んでいます。
本番環境で自分が困った時に行ったエラー確認について記載します！！

#エラー①
ある特定のページが開けない、下記画像のようなエラーが出る。そういったときは本番環境のcurrent/logに入りログを確認し、エラーの原因を探ります。

※本番環境でのエラー確認では、currentに入らないと細かなエラーを確認することができない

<img width="710" alt="3c5c1a9def06514f46f881ecc180ce14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569660/77a09d7b-70cd-3dc3-1f51-9966599cfcdc.png">

``` ruby

 cd current/log       

 tailf production.log　#これで本番環境での細かい動きが確認できる（rails s）みたいなモノ

```

#エラー②
そもそもサイトにはいることができない。そういったときは、ユニコーンサーバー等が原因なので、下記コマンドで確認しましょう。

```ruby
 ps aux | grep unicorn # ユニコーンのプロセス確認

 kill -9 xxxxx # プロセス強制終了

 cat log/unicorn.stderr.log  
 cd current/log             
 cat unicorn.staderr.log
```


#その他関連するコマンド

``` ruby
rails db:reset RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1 #マイグレーションファイルのリセット　自分の場合はこれでうまくいきました

sudo reboot #EC2サーバーの再起動　本番環境へうまく反映されない場合は試してみるといいかも

sudo service nginx restart　#nginxの再起動

sudo service mysqld restart　#mysqldの再起動
```

まだまだ本番環境では、効率のいいコマンドがあると思いますので、分かり次第更新していこうと思います🤔
コンテナに特権を与える方法

#コンテナに特権を与える方法
少し詰まったので、共有します。
コンテナに権限がないと実行できないコマンドがあります。
例えば、hostnameコマンドでhostnameを変更するコマンドです。

```
# kubectl exec -it nginx -- hostname test
hostname: you must be root to change the host name
```

hostnameの変更はrootでなければならないみたいです。
以下のようにマニフェストファイルを編集します。

```
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: nginx
  name: nginx
spec:
  containers:
  - image: nginx
    name: nginx
    # privileged: trueに設定する
    securityContext:
      privileged: true
  dnsPolicy: ClusterFirst
  restartPolicy: Never
status: {}
```

これで先ほどのコマンドが実行できるようになりました。

```
# kubectl exec -it nginx -- hostname test
# kubectl exec -it nginx -- hostname
test
```
[Rails]本番環境で画像を表示させる


# こんな時
ローカル環境で表示されていた画像が本番環境で表示されない！
チーム開発中に思わぬところでつまずいたので備忘録残します。

# 解決方法
HamlやScssファイルの記述方法を変えるだけ。

画像はassetsのimagesに保存。

```html:haml
# 変更前
= image_tag ('/assets/画像パス.拡張子')

# 変更後
= image_tag asset_path('画像パス.拡張子')
```

```css:scss
# 変更前
background-image: url("/assets/画像パス.拡張子");

# 変更後
background-image: image-url("画像パス.拡張子");
```

ありがとうございました。
パーミッション変更（実行権限など）を自動で付与する

著者の実行環境はJetson nano & ubuntu18.04になります。

実行権限をつけたいデバイスを接続してlsusbコマンドをします。


```
user@user-desktop:~$ lsusb
Bus 002 Device 002: ID 0bda:0411 Realtek Semiconductor Corp. 
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 005: ID 15d1:0000  
Bus 001 Device 004: ID 054c:09cc Sony Corp. 
Bus 001 Device 003: ID 0483:374b STMicroelectronics ST-LINK/V2.1 (Nucleo-F103RB)
Bus 001 Device 002: ID 0bda:5411 Realtek Semiconductor Corp. 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
```

例としてマイコンボード（Nucleo F446-RE）の場合は

```
Bus 001 Device 003: ID 0483:374b STMicroelectronics ST-LINK/V2.1 (Nucleo-F103RB)
```

の0483:374bの番号を使用します。

次に50-udev-default.rulesを開いてルールを記入する設定ファイルを開きます。この際ファイルが存在しない場合は作成します。
vimを使用していますが自由にエディタを使用してください。

<font color="red">※設定ファイル名はフォーマットは決まっていて、0詰め2桁数値-名前.rulesとすれば名前は何でも良く、最初の番号は優先順位のようです。</font>

```
sudo vim /lib/udev/rules.d/50-udev-default.rules
```

ファイルを開いたら以下のように記入します。idVendorとidProductに先程の番号になります。

```
KERNEL=="ttyACM*", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", GROUP="dialout", MODE="0777"
```

記入が終わったらPCを再起動して以下のコマンドで権限が付与されているかを確認します。

```
user@user-desktop:/etc/udev/rules.d$ ls -la /dev/ttyACM0
crwxrwxrwx 1 root dialout 166, 0  6月  7 22:23 /dev/ttyACM0
```

これでパーミッションが変更されていたら成功です。

また、複数のデバイスのパーミッションを変更したい場合は

```
KERNEL=="ttyACM*", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", GROUP="dialout", MODE="0777"
KERNEL=="ttyACM*", ATTRS{idVendor}=="15d1", ATTRS{idProduct}=="0000", GROUP="dialout", MODE="0777" 
```
のようにデバイスごとに記入します（上記は北陽のUTM-30LXの例）。

参考
https://itkobo-z.jp/archives/218
可変個引数の関数の作成方法


#はじめに
今回は、C,C++などで使用できる可変個引数の関数の作成をしていきます！
多分、C,C++などの言語を触ったことが少しでもある人は、
printf関数みたいな関数を自分で作れないかなぁと思った事がある方も多いはずです。

自分のメモ帳が半分なのでほとんどわからん！って人がいたらごめんなさい( ;∀;)
ある程度、わかりやすいようになるまでは更新していきたいと思っています。

**※VisualStudio2017を使用しています**
#可変個引数の関数の作成

##stdarg.hのマクロなどの説明
**/---va_start---/**
関数の定義：va_start(/*va_list型変数名*/, /*関数の右から2番目の引数名*/);
va_list型の変数を初期化する関数マクロ

**/---va_end---/**
関数の定義：va_end(/*va_list型変数*/);
va_startマクロ・va_copyマクロにて初期化が行われたva_list型変数を関数が終了する時に、
初期化が行われた数だけva_endマクロで正常な状態に復帰させる必要がある。

**/---va_list---/**
宣言：va_list 変数名
va_list型変数を宣言する時に使用する型名
元のデータ型はchar*型

**/---va_arg---/**
関数の定義：va_arg(/*値を取り出したいva_list型の変数*/, 値を取り出したいデータ型);
可変個実引数を返す関数マクロ
va_argマクロは使用するごとに、可変個引数の参照個所が一つずつ後ろにずれていく性質がある。
ただし、データ型を正しく指定できなければエラーとなるので正しいデータ型指定する必要がある。

例）
printf("%d%f", int型変数i, float型変数f);　//だった場合は
va_arg(va_list型変数, int);//一度目の呼び出しなので一番最初のint型変数iを参照している
va_arg(va_list型変数, float);//参照個所が後ろにずれているのでfloat型変数fを参照している

**/---va_copy---/**
関数の定義：`va_copy(/*コピー先va_list型変数*/,/*コピー元va_list型変数*/);`
va_list型変数のコピーを作成する関数マクロ。
コピー元・コピー先の最低二つのva_list型変数を作成しておく必要がある。
また、コピー元のva_list型変数をコピー前にva_startマクロで初期化しておく必要がある。

##関数定義部
1.stdarg.hをインクルードする　**※windows.hを使用する場合にはインクルードをしなくても動きます。**
2.関数の引数として、可変個引数が使用できるものにすること（printf関数ならconst char*型）
3.関数の引数に、可変個引数を使用すること
　可変個引数は、`...`と記述するまた、可変個引数は関数の一番右側でなければいけない。


##関数内部
1.va_list型を変数を宣言・使用する
2.va_startマクロを使用し、va_list型の変数の使用を開始する　//可変個引数の使用を開始する
3.va_endマクロを使用し、va_list型の変数の使用を終了する　//可変個引数の使用を終了


----
・引数を複数回使用したい場合はva_startマクロ・va_copyマクロを使用する
・va_startマクロ・va_copyマクロを使用して初期化されたva_list型変数の数だけva_endマクロを使用して終了を宣言する

**※1～3は可変個引数の関数を作成する場合、絶対に使用すること！**

関数の引数として可変個引数を使用する場合は、`...（ドット3つ）`を使用する。

```c++:print.cpp

#include<stdarg.h>



void print(const char* text, .../*可変個引数*/){

char text_array[200];
va_list args;//va_listマクロを使用



va_start( args, text );

vsprintf_s( text_array, text, args );//vsprintfを使用する場合は　　#define _CRT_SECURE_WARNINGS

va_end( args );



}


```

```c++:main.cpp

int main(){

int loopCounter = 0;

   while(true){

      print("ループ回数 : %d", loopCounter);

      loopCounter += 1;

   }

}

```

#可変個引数マクロ

1.関数マクロの引数として＿VA＿ARGS＿を使用する　※_VA_ARGS_は通常の関数の引数には使用できません

```c++:main.cpp

#define PRINT(...) printf(_VA_ARGS_);

int main(){

int x = 0;

PRINT("%d", x);

}


```

#終わりに
こんな感じで可変個引数を使用した関数は作れます。
ちなみに、少し関数の引数や内部構造をいじれば他の関数に作り替えることも可能です。←当たり前の事言ってますねw
座標軸指定が必要なら関数の引数として座標を入れてみたりとか...
もしよければ、関数の引数を変更して遊んでみると意外とわかることが増えるかも...

あと、今回ファイル分けしているものに関してはこのままでは、動きません。
ごめんなさいm(__)m
ファイル分けはいろいろなサイトに行けば書いてあるので今回は省きます。
【CircleCI】CIは成功表示なのにカバレッジが反映されなかった問題への対処【Codecov】

# TL;DR
- `token`の設定が失敗していたためこの問題が発生していた
  - 設定方法によっては`CircleCI`で`Codecov`へのアップロードが失敗しても成功表示になる
- `token`を正確に設定しなおした所問題が解決した

# 状況
`Codecov`を設定したリポジトリで、`CircleCI`の表示は成功になっているのにカバレッジが反映されない状況が発生しました。
アップロードのステップを確認した所、画像のように`Provided token is not a UUID.`として400エラーで失敗していました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280230/f8d11ad9-53c2-4553-3525-d5d333691c69.png)

# 原因と対処
`CircleCI`の`Environment Variables`に`Codecov`の`token`を設定した際、誤って`token`をダブルクォートで囲んでいたことが原因でした。
画像のように、ダブルクォートで囲まない形に修正した上で`Rerun workflow`した所問題が解決しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280230/908ad433-0d2c-649b-3ab1-a065765e2745.png)
【Rails】scssフォルダ構成について

# scssフォルダ構成について

### 目次
1. cssからscssに変更にあたって
2. scssフォルダ構成

## 1. cssからscssに変更

プログラムで利用しているcssをscssに変更しました。
scssを利用すると入れ子構造で記述ができるため、セレクタの記述量が減り、可読性の高いコードになります。また、変数を利用できプログラム言語のような記述をすることが可能になります。その他にも演算・関数を利用できるようになり、従来のcssのような冗長な記述を解消することが可能になります。
scssではフォルダ構成が少し変わるので、備忘録としてまとめました。

## 2. scssフォルダ構成
scssのフォルダ構成は以下のようになります。

|フォルダ | 説明 |
|:--|:--|
| config | プロジェクトの設定ファイルや、scssで使用する変数を定義するファイルなどを管理するフォルダです。 |
| mixin | scss内で使用するmixinファイルを管理するフォルダです。 |
| modules | モジュールを管理するためのフォルダです。 モジュールとは、いくつかの要素をまとめた部品の集合という意味です。 ヘッダー、フッターのような用途ごとに分けることができます。 モジュールを使うことでまとまったCSSを独立したものとして管理することができます。 |
| vendor | ライブラリのファイルを管理するフォルダです。 cssにはライブラリと呼ばれるものがあります。 ライブラリとはあらかじめCSSが書かれたファイルです。 有名なCSSのライブラリでは、bootstrapがあげられます。 ライブラリを効率よく利用することで、コーディングのスピードが格段に上がります。 |
| override | vendorフォルダに格納してある外部のライブラリを上書きするためのscssファイルを管理するフォルダです。 |

以上がscssでのフォルダ構成となります。
AWSまとめ（自分用）

# 本稿について
AWSについてお勉強しているうちに、へーそうなんだと思ったことを覚書して言ってます
完全備忘用です
随時更新しようと思います


### ルートテーブル
パブリックサブネットは、VPCにインターネットへ出るためのインターネットゲートウェイがアタッチされ、ルートテーブルにインターネットゲートウェイが日もづいている場合にインターネットに直接出入り可能なサブネット。

ルートテーブルにインターネットゲートウェイが日もづいておらず、VPC内のみの通信やDirect Connectなどプライベート接続のみの場合はプライベートサブネットとなる

なお、インターネットへのルーティングがない場合は、yumコマンドやapt-getコマンド、Windows Updateなどを実行できないため、プライベートサブネット上のEC2インスタンスからインターネットにアクセスしたい場合はNATゲートウェイなどを利用する必要がある
用途としては、ALB/ELBやリバースプロキシサーバなどをパブリックサブネットに配置してインターネットからのトラフィックを受けて、セキュアな情報を格納するデータベースなどをプライベートサブネットに配置し直接アクセスできないようにする。


### インターネット側からNATゲートウェイにはアクセスできない
NATゲートウェイはサブネットからインターネットに出ていくためのサービス。NATゲートウェイにログインしたり、逆にインターネット側からNATゲートウェイに乗り込むことはできない。

インターネット側からプライベートサブネットにアクセスしたい場合は、踏み台を配置、もしくはSystems Managerのセッションマネージャーを利用する。

### VPCエンドポイント
VPCエンドポイントが提供されるまでは、AWS内のEC2などからS3やDynamoデータベースにアクセスするためにはインターネットを経由する必要があった。
VPCエンドポイントを利用すると、AWSの一部のサービスでプライベート通信が可能となるため、よりセキュアな構成にすることができる。


### セキュリティグループ
セキュリティグループは、いわゆるファイアウォールに近い機能。
Linuxのiptablesに近いものがある。EC2インスタンスなどに付与することで、
それらへのアクセス対象を制限することができる。
厳密に言えば、セキュリティグループはENI（Elastic Network Interface）にアタッチするが、EC2インスタンスやNATゲートウェイには必ずENIは付与されているため、EC2インスタンスなどに付与するという表現のほうがイメージが付きやすい。
プロトコル、ポート、IPアドレスの3つを設定し、EC2インスタンスなどにアタッチすることで有効になる。

### VPCピアリング
VPCピアリングを利用しないでインターネット経由で通信を行った場合は通信品質や速度、転送コストなどの課題が出てきますが、VPCピアリングを用いることで、VPC間でプライベートなトラフィックのルーティングが可能になる。