OmniAICreator/Qiita-1.07M huggingface dataset:
ローカル環境でCircleCIのCLIの使用する

備忘録です

### 参考

[CircleCI のローカル CLI の使用 \- CircleCI](https://circleci.com/docs/ja/2.0/local-cli/)

### 準備

#### インストール

```
$ brew install circleci
```

#### パーソナルAPIトークンの発行

[CircleCI](https://app.circleci.com/settings/user/tokens)

#### セットアップ

```
$ circleci setup
```

- トークンとホストを求められるので入力。（circleci.comを使用している場合はホストはデフォルトでOK）
- `~/.circleci` ディレクトリが生成されるので、とりあえず [CircleCI Config Builder](https://circleci.com/docs/config-builder/#section=configuration) を参考に適当な `config.yml` を作成

```config.yml
version: 2.1
jobs:
  build:
    docker:
      - image: 'cimg/node:14.14.0'
    steps:
      - run: node --version
```

#### 検証

```
$ circleci config validate -c .circleci/config.yml
もしくは
$ circleci config check -c .circleci/config.yml

Config file at .circleci/config.yml is valid.
```

#### 実行

```
$ circleci build -c .circleci/config.yml

node --version
v14.14.0
Success!
```

※workflowが設定されている場合は失敗するのでJOB名で指定するとよい

```config.yml
version: 2.1
jobs:
  node-version:
    docker:
      - image: 'cimg/node:14.14.0'
    steps:
      - run: node --version

workflows:
  node:
    jobs:
      - node-version
```

```
$ circleci build -c .circleci/config.yml

Error: 
Configuration errors: 1 error occurred:
	* Cannot find a job named `build` to run in the `jobs:` section of your configuration file.
If you expected a workflow to run, check your config contains a top-level key called 'workflows:'
```

```
$ circleci build -c .circleci/config.yml --job node-version

node --version
v14.14.0
Success!
```

#### 制限事項

ローカル環境だといくつか制限があるので注意

- Machine Executor
- ワークフロー
    - 単一jobsしか実行できない
- SSHキーの追加(add_ssh_keys)
- キャッシュ(save_cache, restore_cache)
- アーティファクトアップロード（store_artifacts）
- Webで設定した環境変数
    - 実行時に `-e` で渡すことができる (`circleci build -e VAR1=FOO -e VAR2=BAR`)

https://circleci.com/docs/ja/2.0/local-cli/#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%81%A7%E3%81%AE%E3%82%B8%E3%83%A7%E3%83%96%E5%AE%9F%E8%A1%8C%E6%99%82%E3%81%AE%E5%88%B6%E9%99%90%E4%BA%8B%E9%A0%85

#### 開発リポジトリで使う

`.circleci/config.yml` を追加するだけでOK

#### デバッグ方法

stepに下記を追加

```
- run:
　name: 'Do not discard'
　no_output_timeout: 10m
　command: |-
　　tail -f /dev/null
```

```config.yml
version: 2.1

jobs:
  job-checkout:
    docker:
      - image: circleci/android:api-29
        environment:
          TZ: "Asia/Tokyo"
    steps:
      - checkout
      - run:
          name: 'Do not discard'
          no_output_timeout: 10m
          command: |-
            tail -f /dev/null

workflows:
  workflow-checkout:
    jobs:
      - job-checkout
```

```
$ circleci build -c .circleci/config.yml --job job-checkout

====>> Checkout code
Making checkout directory "/home/circleci/project"
Copying files from "/tmp/_circleci_local_build_repo" to "/home/circleci/project"

$ docker ps
$ docker exec -it [CONTAINER ID] /bin/sh; exit
$ ls /home/circleci/project
# checkoutを確認
```
MPA な環境で vue-cli を使いたくなった時のメモ

これは [SOUSEI Technology アドベントカレンダー](https://qiita.com/advent-calendar/2020/st)13日目の記事です :pencil:

つい先日、MPA な環境で vue-cli を使いたく、いろいろといじったことのメモです。

## MPA！？

かっこいい名前ですが、SPA (Single-page application) の対義語。
リクエストに応じたHTMLを返すやつです。

こんな名前ついてるのは、知り合いに聞くまで知りませんでした :relaxed:

## vue-cli

Vue.js の開発環境を簡単に作れる物です。
https://cli.vuejs.org/

ESLint や Sass、TypeScript 等、自分が使いたいものを選択し、それに合わせた設定ファイルなんかも最初に作ってくれます。

いっぱい記事あるので、ここでは細かいことは割愛！

## MPA + vue-cli

MPA な環境ですと、画面の HTML なんかはバックエンド側でテンプレートエンジンなんかを使って用意します。
また、JavaScript や CSS などの読み込みもバックエンド側のテンプレートで記述しなくてはいけなくなります。

そうなると...

デフォルトの vue-cli がやってくれる

- 最適化された HTML の出力
- 生成したファイル名に追加されるハッシュ値

この辺りは不要になるので、まずは上記の機能を無くしていきます。

（**「生成したファイル名に追加されるハッシュ値」** に関しては、それがあっても良い感じで読み込んでくれるような仕組みがあれば問題ないでしょう。自分にはできませんでした！！）



### やめてみる

vue-cli のサイトにちゃんと書いてありました。
（30分ほど他のサイトなんかで彷徨ったのは内緒）

```javascript

// vue.config.js
module.exports = {
  // disable hashes in filenames
  filenameHashing: false,
  // delete HTML related webpack plugins
  chainWebpack: config => {
    config.plugins.delete('html')
    config.plugins.delete('preload')
    config.plugins.delete('prefetch')
  }
}
```

参考: [HTML and Static Assets | Vue CLI](https://cli.vuejs.org/guide/html-and-static-assets.html#disable-index-generation) 

### 確認してみる

ありがたいことに、vue-cli では Webpack の設定をファイルに出力してくれるコマンドがあるので、それを使って確認することができます。

参考: [Working with Webpack | Vue CLI](https://cli.vuejs.org/guide/webpack.html#inspecting-the-project-s-webpack-config) 

#### 変更されたもの

##### 「最適化された HTML の出力」関連

```javascript
plugins: [
  /* config.plugin('html') */
  new HtmlWebpackPlugin(
    // 設定が書いてある
  ),
  /* config.plugin('preload') */
  new PreloadPlugin(
    // 設定が書いてある
  ),
  /* config.plugin('prefetch') */
  new PreloadPlugin(
    // 設定が書いてある
  ),
],
```

上記の設定が消えていると思います。

##### 「生成したファイル名に追加されるハッシュ値」関連

file-loader の設定例ですが、

```javascript
options: {
  name: 'img/[name].[hash:8].[ext]'
}
```

が

```javascript
options: {
  name: 'img/[name].[ext]'
}
```

の様に変更されていました。

###### だがしかし

JavaScript のハッシュに関しては...どこでやってるのかわからず...

`output.filename` だったり、 `output.chunkFilename` かと思ったのですが、どうやら違う模様。

奥が深いぜ Webpack。個人的にどこでどうやってるのか調べてみたいところ。

## まとめ

公式のサイトにきちんと書いてあったので、特に問題はなかったですが、「どうやってやってるのだろうか...」と謎が深まりました :expressionless:

### 参考資料

- [Vue CLI](https://cli.vuejs.org/)
Python 基本操作　第2弾：関数（引数）

# #Python 基本操作<関数>#

##はじめに
自分が不安な部分についてのみ，Pythonの基本操作について復習する．
その第2弾として関数について記述する．

##Pythonにおける関数
```python:
def 関数名(引数):
    処理内容
```

このように定義されるが，個人的に引数についてはあまり意識していなかった．
ここでは，引数について注目することで，関数の理解を深める．

##引数
引数には主に2種類ある．
・仮引数：関数で宣言される引数
・実引数：関数に渡す引数

```python:example.py
#関数の定義
def main(a):
    return a+1

#関数の使用
main(x)
```
上記のコードでいうとaが仮引数，xが実引数となる．

##仮引数への引き渡し
関数の使用時には実引数を指定するが，仮引数に値を引き渡していることを意味する．
####どのように引き渡すのか？
引き渡し方にも2種類ある．
・値渡し　：仮引数に実引数をコピーする（実引数の値は変更されない）
・参照渡し：実引数のアドレスを参照する（実引数の値は変更され得る）

##Pythonでの引数
基本的に参照渡しが用いられている
しかし...
実引数における変数の方によって，異なる動作をする
その動作により，更に2つに分けられる．
#####immutable型：関数の中で書き換えられない
　✓整数・浮動小数点数・文字列・タプル　など
#####mutable型：関数の中で書き換えられ得る
　✓リスト・辞書型(dict)・集合(set)　など

##検証
次のコードで本当に実引数に用いた変数が書き換えられてしまうのかを検証した．

```python:def_arg.py
"""
2020/12/13
@Yuya Shimizu

関数の引数
"""
# 関数を定義
def func_num(a):
    a -= 1
    return a

def func_char(a):
    a += " Hello"
    return a

def func_list(a):
    a[0] -= 1
    return a

def func_dict(a):
    a["1"] -= 1
    return a

############## immutable型
#実引数：整数
x_int = 1
func_num(x_int)
print("実引数", x_int)

#実引数：浮動小数点数
x_float = 1.5
func_num(x_float)
print("実引数", x_float)

#実引数：文字列
x_char = "abc"
func_char(x_char)
print("実引数", x_char)

############## mutable型
#実引数：リスト
x_list = [1, 2, 3]
func_list(x_list)
print("実引数", x_list)

#実引数：辞書型(dict)
x_dict = {"1":10, "2":20, "3":30}
func_dict(x_dict)
print("実引数", x_dict)
```

##検証結果
確かに，immutable型の実引数は関数実行後もデータの変化はなく，mutable型の実引数は関数実行後にはその影響を受けた状態となっていた．

##感想
関数は使ってきていたが，引数にそのようなルールがあることも知らず，今までよくわからないエラーの原因の１つであったことに気づけて，すっきりしている．

##参考文献
Pythonで始めるアルゴリズム入門　伝統的なアルゴリズムで学ぶ定石と計算量
　　　　　　　　　　　　　　　　　　　　　　　　 増井 敏克　著　　翔泳社
enebularでフローのバージョンを管理する方法

はじめまして、enebularの中の人です。
今回初めてAdvent Calendarに参加してみます。

# はじめに

Node-REDを使っていて困ることの1つに、フローのバージョン管理がやりづらいという点があります。
あまり知られていないのですが、enebularにはフローのバージョンを管理する機能があります。この機能を使うことで、バージョン管理の苦労が少しは改善できるのではないでしょうか。ということで、この記事では、enebularのバージョン管理機能について紹介してみます。

※ なお、Node-REDのオプション機能に[バージョン管理機能](https://nodered.org/docs/user-guide/projects/#version-control)があることは、この記事では脇におく事にします ;-)

# 準備

enebularでバージョン管理機能を使うためには、プロジェクトを有償化する手続きが必要になります。興味のある方は、手近なウフル社員を捕まえて聞いてみてください！ (きっと懇切丁寧に説明してくれるはずです！）。手近に捕まえられるウフル社員がいない方は、[enebularの問い合わせページ](https://enebular.com/contact/?lang=ja)から連絡してください！

# enebularによるバージョン管理

## バージョンを追加する

enebularのダッシュボード画面で、フローを選択します。
バージョンタブが表示されるので、バージョンタブに移動します。
「Create New Version」ボタンで、新しいバージョンを追加できます。
![スクリーンショット 2020-12-10 17.32.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185516/4af2b253-1b42-2372-afda-7b794239c7dd.png)

## enebularのバージョンの考え方

enebularのバージョンの考え方は、少し変わっています。
上の”バージョンを追加する”の操作は、その時点のスナップショットに名前をつけて保存する操作になります。

下の図を見て下さい。
新しいバージョンを作成すると、現在のmasterがコピーされてV3になります。
![IMG_0066.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185516/71177f41-a5ff-e370-f7ca-76927739a90a.png)
新しいバージョンを追加しても、編集できるのはmasterだけです。
慣れると気になりませんが、最初は少し戸惑う方もいると思いますので、図を見て理解してもらえると嬉しいです！

## 古いバージョンをデプロイする

enebularのダッシュボード画面で、フローを選択します。
バージョンタブが表示されるので、バージョンタブに移動します。

作成したバージョンの一覧が表示されます。
デプロイしたいバージョンのデプロイ（Deploy)ボタンを押して、フローのデプロイを行って下さい。

## 古いバージョンを復活させる

enebularのバージョン管理では、古いバージョンを直接編集することはできません。
古いバージョンをまた編集したい場合は、最新のmasterに置き換えて（上書きして）、編集できるようにします。

enebularのダッシュボード画面で、フローを選択します。
バージョンタブが表示されるので、バージョンタブに移動します。
下の図のように、右端の...ボタンを押すとOverwriteというメニューがあります。
このOverwriteを実行すると、選択したバージョンがmasterに上書きされます。
![スクリーンショット 2020-12-10 17.32.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185516/22a6da9d-8bb8-10a0-3b9a-83a1710c7a7f.png)

# ちょっと変わった使い方

## バージョン管理機能を使ってフローをコピーする

enebularのバージョン管理機能を使って、フローをコピーすることができます。
一度作成したフローをコピーして編集したい場合などに便利に使うことができます。

enebularのダッシュボード画面で、フローを選択します。
バージョンタブが表示されるので、バージョンタブに移動します。
上の図のように、右端の...ボタンを押すとDuplicateというメニューがあります。
このDuplicateを実行すると、指定されたバージョンのフローがコピーされて新しいフローがであがります。
![IMG_0065.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185516/6b206dd9-3243-5e0e-8df3-b05b64d06350.png)
こんな風にバージョン管理機能を使うことで、簡単にフローのコピーを作成することができます!!
PDFファイルの上にPencilKitで落書きするアプリを作った

<h2>挨拶</h2>

こんにちは。HAAAAANと申します。
今回は表題の通り、PDFファイルの上に落書きができるアプリを作りましたので
忘備の意味も込めて、書いていきたいと思います。

初学者の為、誤った表現・理解があるかとは存じますが、何卒宜しくお願い致します。

なお、今回のアプリはただ落書きするためだけのものなので、
保存機能などはありません。（今後の課題）


<h2>環境</h2>

MacOS
Xcode
swift
iPad Pro(iOS:13.6)

<h2>目的</h2>
<h3>ぜったいにじっそうする</h3>
①　PDFファイルを画面に表示する
②　表示されたPDFファイルの上に落書きができる

<h3>そのうちにやる</h3>

①　落書きが終わったら落書きと一緒にPDFファイルを保存する
②　①ができたらその画像ファイルをPDFファイルにする
　　‐ イメージ的には画面のスクリーンショットをとって、その画像をPDFに変換してあげる感じ。

（出来るかどうかはわからない）


<h2>下準備</h2>

 - storyboardを開き、大元のViewControllerにViewを1つ追加する。
 - 追加したViewのCustomClassのClass名にPDFViewを設定し、Outlet接続をする。
 - 表示させたいPDFファイルをプロジェクトファイルに追加する。

<h2>コード</h2>

```Python:qiita.swift
import UIKit
import PDFKit
import PencilKit


class ViewController: UIViewController{
    @IBOutlet weak var pdfView: PDFView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Do any additional setup after loading the view.
        if let sourceURL = Bundle.main.url(forResource: "Test", withExtension: "pdf") {
            if let source = PDFDocument(url: sourceURL) {
                pdfView.document = source //PDFのURL
                pdfView.autoScales = true //PDFが画面におさまる
                pdfView.displayMode = .singlePage //1pageの表示
            }
        }

        let canvas = PKCanvasView(frame: view.frame) //描画領域の設定
        view.addSubview(canvas) //描画領域をPDFの上に追加
        canvas.tool = PKInkingTool(.pen, color: .black, width: 15) //ペンの設定
        canvas.isOpaque = false //背景を透明にする(だいじ)

        if let window = UIApplication.shared.windows.first {
            if let toolPicker = PKToolPicker.shared(for: window) {
                toolPicker.addObserver(canvas) 
                toolPicker.setVisible(true, forFirstResponder: canvas)
                canvas.becomeFirstResponder()
                
            }
        }
    }
}

```



<h2>詰まったところ</h2>

・View実装時
構成としては、おおもとのViewControllerにPDFViewを載せて、その上に
描画のためのViewを載せる形を考えており、その通りに実装ができたのですが、
Web徘徊中にどこかの記事で、ペンでの描画時に画面が真っ暗になってしまうという
不具合に遭遇しましたと言う物がありまして、私も途中全く同じ症状が出てしまいました。

おそらくジェスチャー時のトリガーで何某かの処理が動いてそうなっているんだろうなーと思い
背景色を変えてみると、真っ黒になるはずのその画面が背景色に設定した色になったので
View自体を透明にすることにしました。

はじめは描画用のViewの背景色にalpha値を設定していましたが、それをやめて
ViewのisOpaque値をfalseにすることで、ジェスチャー時の不具合はなくなりました。


<h2>参考資料</h2>

 - <a href="https://re-engines.com/2018/07/17/swiftpdfkitでpdfの表示/">[Swift]PDFKitでPDFの表示</a>
 - <a href="https://qiita.com/niwasawa/items/d8e239cd23666c750a2f">たった3行のコードで PencilKit を導入して Apple Pencil 対応</a>
 - <a href="https://clrmemory.com/programming/swift/alpha-use-isopaque/">【Swift】ウィンドウを透明にするisOpaqueの使い方</a>

今回は上記の記事をただ組み合わせただけです！（ドン！！！）

<h2>後日談</h2>
PencilKit導入しなくても、PDFKitの機能の一つにPDF Annotation
（注釈の機能）というものがあり、PDF上に直接描画可能ということで・・・
キャプチャとってImageファイルからPDFファイル にしてという手間が省けるようで、そっち使って実装しようかなあ。
【GAS】Google Formで送信者のアドレスを取得する方法

Google Formで、フォーム送信者のアドレスを取得したい場合には、`Session `オブジェクトではなく`event.response`オブジェクトから取得する。

```js
function sendEmail(e) {
  const email = e.response.getRespondentEmail();
  GmailApp.sendEmail(email, "Confirmation", "Thank you for submitting.");
}
``` 

`Session.getActiveUser().getEmail()`を使っていたのだけど、それだとアプリ作成者のアドレスを取得してしまうようだった（詳しい違いは未調査）。

自分が実務で使う場合、フォームの回答者は数人に限られているので、予め登録しておいたユーザーの中からアドレスをもとに名前を表示させることができる。

```js
// 取得したアドレスを元に、フォーム記入者の名前を表示する。
function buildEmailBody(email) {
  const users = [
    { name: "John Doe",   email: "john@example.com" },
    { name: "Lara Croft", email: "lara@example.com" },
  ];
  
  const sender = users.find(user => user.email === email);
  
  return sender + "さんからフォーム回答がありました";
}
```

## `Session.getActiveUser()`の役割

経験上`Session`は、ウェブアプリとして公開したときのユーザー取得に使えることが分かっている。

```js:コード.gs
// ウェブアプリとして公開されているアプリ
function doGet(e) {
  return HtmlService.createTemplateFromFile("index").evaluate();
}

function getUser() {
  const users = [
    { name: "John Doe",   email: "john@example.com" },
    { name: "Lara Croft", email: "lara@example.com" },
  ];  
  const user = users.find(user => user.email === email);

  return "こんにちは" + user + "さん";
}
```

```html:index.html
<? const user = getUser(); ?> // .gsのコードを呼び出す
<p>こんにちは <?!= user ?> さん</p>
```
見やすいパワポスライド作りの極意

こんにちは！
<a href="https://qiita.com/advent-calendar/2020/increments-cyma">Increments × cyma (Ateam Inc.) Advent Calendar 2020</a> の14日目は、
株式会社エイチーム EC事業本部WEBデザイナー秋山（@nemuneru）が担当します。
今回のテーマは「見やすいパワポスライド作りの極意」です！
▼記事はnoteにて公開しているので以下リンクから是非ご覧ください！
https://note.com/nemui_kedo_nenai/n/nb686519881ef
![スクリーンショット 2020-12-14 9.51.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/600439/bb56fdb1-af68-f7ff-dc2e-fa1c6f3846b0.png)
[objective-c]UIArratControllerでのパスワード入力ダイアログについて


##ソース

```
//パスワードアラート表示

//ここにパスワード格納、実際にはＤＢとかから取得
NSString    *password = @"testpass";
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@""
message:@"パスワードを入力してください" preferredStyle:UIAlertControllerStyleAlert];

//入力欄（UITextField）付きを設定
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
//入力欄の背景に薄く出る
textField.placeholder = @"パスワードを入力";
//マスク（・表示）
textField.secureTextEntry = YES;

// addActionした順に左から右にボタンが配置されます
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
    // OKボタンが押された時の処理
    UITextField *textField = alertController.textFields.firstObject;
    if ([textField.text isEqualToString:password]) {
    	//パスワード合ってた時の処理
    }else{
    	//パスワード違ったら警告だす
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"警告"message:@"パスワードが一致しません" preferredStyle:UIAlertControllerStyleAlert];
        [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
        	return;
        }]];
        [self presentViewController:alertController animated:YES completion:nil];
    }
}]];
[self presentViewController:alertController animated:YES completion:nil];

```

この処理はViewControllerに記載する必要があります。
そうでないと↓で(たしか)エラーが出ます。
[self presentViewController:alertController animated:YES completion:nil];

#脱線
Objective-cで作られてるソースってそもそも古いものが多いと思います。
そのためダイアログ表示をUIAlertViewで作ってるものがそこそこあり、
もし今後UIAlertViewが非推奨ではなくAPPstoreに挙げられなくなったらUIAlertControllerに書き換える必要がありますが
ものすごく大変そうです・・・
【PHP】staticとselfの違い

PHPの`static`と`self`は静的メソッドで使用することができます。（インスタンス化せずに使用できる。）

`static`はプログラムを実行する際のクラスを指します。
`self`は記述しているクラスそのものを指します。

```php
<?php
class HOGE {
    protected const CLASS_NAME = 'hoge';
    
    public function display()
    {
        echo self::CLASS_NAME . "\n";
        echo static::CLASS_NAME . "\n";
    }
}

class FUGA extends HOGE {
    protected const CLASS_NAME = 'fuga';
    
}

(new HOGE())->display();

(new FUGA())->display();

// (new HOGE())->display();の結果
hoge
hoge

// (new FUGA())->display();の結果
hoge
fuga
```
**結果**

* HOGEの結果に関しては、どちらも自クラスを指すため結果がどちらも`hoge`になる。
* FUGAの結果に関しては、`self`は記述しているクラスを指すので`hoge`を表示し、`fuga`は実行時のクラスを指すので`fuga`が表示される。
小学生でもできるプログラミング

プログラミング初心者はもちろん小学生でもプログラミングができる（しかも無料！）のサイトを紹介します。（もしかしたら知っているひともいるかもしれませんが・・・）
<h1>使ったサイト</h1>
Scratchというプログラミングソフトを使いました。
リンク→https://scratch.mit.edu/studios/1168062/
<h1>Scratchとは</h1>
アメリカのマサチューセッツ工科大学（MIT）メディアラボのライフロング・キンダーガーテンというグループが作った、小学生でも簡単にプログラミングができるソフト。作ったゲーム、アニメーションは世界に公開することもできます。（無料会員登録が必要）
<h1>使ってみた</h1>
まずは簡単な動作をいくつかやってみます。![sc1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869436/1fe96d5b-9ef9-657f-b44d-ab769efddde7.png)
これが一番簡単な組み方だと思います。旗のマークが実行ボタンになります。
![sc2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869436/de1ad33f-c221-b973-8dd7-f84ec51a93c1.png)
約二秒後に「こんにちは！」は消えます。このようにScratchはブロックを組み合わせることにより作品ができます。
次は猫を動かします。![sc3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869436/19dd858b-f457-b84e-f54c-d7726d72934e.png)
四方向に動くプログラムです。
(画面録画を貼り付けられませんでした）



<h1>簡単なゲームを作ってみた</h1>
使い方を説明しているサイトを参考にして簡単なゲームを作ってみました
リンク先で遊べます→https://scratch.mit.edu/projects/463344626
（ニャーニャーうるさいと思うので音量には注意してください）

猫のプログラム![sc1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869436/37ed1c3b-fa8b-40f4-27a0-08a8e1485a6b.png)

リンゴのプログラム![sc2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869436/737c43c6-63b2-e054-1dcb-542f9a9d0744.png)


作成時間は約30分です。アイデア次第はもっと本格的なゲームが作れます。Scratchでは某鬼から逃げる風ゲームや某マリ〇風ゲームでも遊べるのでぜひ休憩時間で遊んでみてください。

<h1>さいごに</h1>
小学校でプログラミングが必修化されるという記事を以前見かけたので将来、皆さんの子供も文理関係なくプログラミングを習う未来もそう遠くないと思います。そんな時にScratchを使うと親子で楽しく勉強できるんじゃないでしょうか。
Pythonで時系列データの読み込み・集計・可視化・Excelファイルへの書き出し

※超初心者向けの記事です。


仕事で時系列データの集計をやる機会があってPythonで行ったのでまとめます。

タイトルのようにデータ分析でよく使いそうな操作を行いつつ時系列データの集計を行います。


#この記事の目的

・時系列データを集計する


実際はFileMakerからレコードのExcelファイルでエクスポートし少し加工を加えてPythonに読み込ませて行いました。

日付ごとに作成されるデータ、例えば検査数やオペ数の月毎・年毎の集計が一瞬で終わります。

読み込むデータを代えるといろんな集計が簡単に行えるかと思います。


#環境

・Python 3.8.5


#テストデータ

今回は2015/1/1~2020/12/1までのある検査のcsvファイルを用意しました。

1ヶ月毎に1件検査をしたという感じにしました。


#ライブラリのインポート
まずはよく使うライブラリをインポートします。
（今回使わないライブラリが混在しています）

計算と可視化はデータ分析する際は必ずと言っていいほど使うので何かに保存しておいてコピペすると良いです。

```

#計算系
import pandas as pd
import numpy as np

#可視化系
import matplotlib.pyplot as plt
import matplotlib as mpl
import seaborn as sns
%matplotlib inline

```

#データの読み込み

csvでもExcelでも良いかと思います。

今回は感覚的に馴染みのあるDataFrameの形（イメージとしてはExcelのようなスプレッドシート）で読み込んでいます。

Excelの場合は引数にsheet_nameを指定するとシート番号（０始まり）やシート名で指定することができます。


```
#csvの読み込み
df = pd.read_csv('/パス名/ファイル名.csv')

# Excelファイルの読み込み
df = pd.read_excel('/パス名/ファイル名.xlsx' , sheet_name=シートの番号or'シート名') 

```



#読み込みの確認とデータの型の確認

※ jupyterなどで使う場合は１行ごとに実行してください。

```
#先頭の行を表示
df.head()

#データの型を確認
df.dtypes
```



表示結果
![スクリーンショット 2020-12-14 8.56.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469454/44950297-09e2-fdf7-ba06-d5a25a364da6.png)

１列目に日付、２列目に種類（今回は検査）という値が入力されています。


#指定の文字列を整数の１に置き換える

集計するためには指定の文字列をカウントするのもありですが、今回集計する方法では数値をカウントするようなので、検査の列を整数の「1」に置き換える作業が必要となります。


```
df.replace('検査', 1, inplace=True)
```


#日付の列をdatetime型に変換し、indexに指定する
```
#ライブラリのインポート
import datetime
#1列目をdatetime型でindexにする
#dayの列をdatetime型にする
df['date']=pd.to_datetime(df['date'])

#date列をindexに割り当てる
df.set_index('date', inplace=True)
```

#集計
最後にExcelファイルで書き出すために新しいDateFrameを作成しています。

```
#年毎に集計
df2 = df.resample(rule='Y').sum().head()
```


#可視化
```
# グラフ作成
fig = plt.figure(figsize=(10,5))
plt.title('Title')
plt.ylabel('Y Label')
plt.xlabel('Year')
plt.plot(df2['type'])
plt.show()
```

今回は１ヶ月毎に１件の検査を行ったという体のデータセットなので１年毎に１２件でこんな感じのグラフになります。
（X軸が変ですが）

結果
![nenbetu_kensasu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469454/8dae0314-c761-a6dd-5844-614662b23203.png)



#Excelファイルの書き出し
凝ったグラフを作成したい場合や集計結果を共有・保存する場合は大抵の人が見れて使えるExcelファイルなどに保存しておくと良いでしょう。

```
import openpyxl

#to_excelでdfを書き出し
df2.to_excel('任意のファイル名.xlsx')
```

#おまけ
可視化した画像の保存。画像を用いて資料を作るときに便利です。

```
fig.savefig("任意のファイル名.png")
```



#参考文献・サイト

・pandas.DataFrame, Seriesの要素の値を置換するreplace/note.nkmk.me
"https://note.nkmk.me/python-pandas-replace/"

・pandasで時系列データの曜日や月、四半期、年ごとの合計や平均を算出/note.nkmk.me
"https://note.nkmk.me/python-pandas-time-series-multiindex/"
git-flowにおけるreleaseブランチのマージをGitHub Actionsで実現する

# はじめに

プロダクトのgitサービスにGitHubを、gitブランチモデルに [git-flow](https://danielkummer.github.io/git-flow-cheatsheet/index.ja_JP.html) を採用しています。

git-flowでは `release/*` ブランチを `master(main)` ブランチと `develop` ブランチにマージするという工程があるのですが、GitHubのプルリクエストでは2つのブランチに同時にマージするということができません。よって、今までは `master(main)` へのマージはプルリクエストのクローズ処理で行い、`develop` へのマージはローカル環境で人力で行いpushする……というダサダサな運用を続けていました。

もうちょっとなんとかならんかということでGitHub Actionsを使って自動化することにしました。

最初は `run` でスクリプトを書き下ろさなきゃいけないよなぁ……と考えていたのですが、探してみるとそのものズバリ [yanamura/git-flow-merge-action](https://github.com/yanamura/git-flow-merge-action) というアクションがあったのでこれを使うことにしました。

# 完成物

ということで以下のとおりワークフローファイルを作成しました。というかほぼgit-flow-merge-actionのサンプルのままです。

```..github/workflows/auto_merge.yml
on:
  pull_request:
    types: [labeled]
jobs:
  auto-merge:
    if: github.event.label.name == 'release'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
        name: Checkout repository
      - name: Extract branch name
        uses: mdecoleman/pr-branch-name@1.0.0
        id: extract_branch
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}
      - uses: yanamura/git-flow-merge-action@v1
        name: git-flow merge
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          branch: ${{ steps.extract_branch.outputs.branch }}
          # git-flowにおけるdevelopブランチの、あなたのリポジトリーにおける名称
          develop_branch: "develop"
          # git-flowにおけるmasterブランチの、あなたのリポジトリーにおける名称
          main_branch: "main"
```

設定する箇所は `main_branch` のところぐらいですかね。
デフォルトだと `master` が設定されてしまいますが、今回のリポジトリーは `main` という名称にしていたので `"main"` を設定しています。

# 運用方法

GitHub Actionsによる自動化を導入することで、プルリクエストのクローズの手順が変わります。

今まではプルリクエストページの `Merge pull request` ボタンを押下することでプルリクエストのクローズを行っていましたが、今度からは `Merge pull request` ボタンの押下の代わりにプルリクエストに対して `release` ラベルを付与することを行います。
`release` ラベルが付与されたことをトリガーにして上述のGitHubアクションが起動し、 `main` ブランチへのマージ、プルリクエストのクローズ、 `develop` ブランチへのマージが全て行われます。

頑張れば `Merge pull request` ボタンの押下をトリガーにしたワークフローも書ける気がしたのですが、運用の手間はさほど変わらないことからgit-flow-merge-actionのサンプルをそのまま採用しています。

# おわりに

楽に設定できて良かった😊
PHP Conference 2020 (Japanese)

# PHP Conference 2020 (Japanese)
今まで長くphpを使ったりしましたが、一回も参加したことがありませんでした。今回は会社の人達と参加しました。コロナの影響でOnlineでの参加のみでしたが、すごく面白く勉強になったので今後からずっと参加したいと思いました。

全セッションが興味深く参加した物が全部面白かったですが、印象が残る三つくらいを書いてみました。

## PHP WEBアプリケーション設計入門――10年先を見据えて作る 
![phpcon01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489182/9605cc34-0dcc-48a8-1f6f-7cc0ac73f522.png)

参考：https://fortee.jp/phpcon-2020/proposal/da5b9d99-e5a6-4f51-adea-1f1c10d99020
プレゼン資料：https://speakerdeck.com/nrslib/introduction-to-web-application-design

10年後まで使えるアプリケーションを作る為に考えるべき物とか、ApplicationとDomainの依存性（DIP)についての話等すごく印象深く感じました。

DDDも以前からドキュメント等は読んでいましたが、今回の刺激で個人でも作ってみようかと思いました。

## PHP 8 で作る JSON パーサ
![phpcon02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489182/2df19e5b-b160-4379-61e2-9bd63964a02d.png)

参考：https://fortee.jp/phpcon-2020/proposal/29dc0164-13a9-45f3-9820-91809be7227c
プレゼン資料：https://speakerdeck.com/shin1x1/php8-json-parser
サンプルコード：https://github.com/shin1x1/php8-toy-json-parser/tree/phpcon2020

結論としてjson_decodeを使いましょう！との話でしたが、ロジックを考える方法がずごく良くて理解しておけば他のところにも利用出来そうでした。また、明確なエラーの表示とかを考えるとメリットもあるかと思います。json形式をテストするアプリを作っても良いかなと。

## PHPで作るオンラインカンファレンス向け録画システム
![phpcon03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/489182/780befab-5542-2882-7e4c-0119edae927d.png)
参考０１：https://fortee.jp/phpcon-2020/proposal/6ad53449-2cb4-4978-aa9f-06ef034cf9ee
参考02：https://www.hasegawa-tomoki.com/blog/2020/09/28/pre-recording-system/

今回のセミナで利用したシステムについての説明でした。すごく面白く一度作ってみたいなと思いました。腕力〜〜〜大事！！

## その他
色んなツールを今回きっかけで使えてみたなと思いましたので、ご紹介させて頂きます。

・[discord](https://discord.com/)：今回のセミナで使ったチャット？システムですがSlackなように使えるのかな？思った物です。
・[laravelplayground](https://laravelplayground.com/#/):laravelのソースのテストをブラウザーで実行できる物です。
・[laraveldb](https://laraveldb.com/)：自分も思っていたER図からlaravelのmigrationファイルを作る物？（まだやってないのでどんな物かは）です。
PHPのCarbonで24時間以内かどうかの判定を行う

## はじめに

こんにちは、普段は業務で求人系サービスの開発を行なっている@taku-0728です。
今回はとある機会で「PHPで24時間以内かどうかの判定」を行う必要があったのですが、
24時間以内かどうかを判定している記事が特に見つからなかったので書いてみようと思います。
個人的にPHPの日付処理ではCarbonが優秀だと思うので、Carbonでやっていきます。

## 準備
今回はCarbonを使います。CarbonとはPHPのDateTimeクラスをオーバーラップした日付操作ライブラリであり、
Laravelなどでは標準搭載されています。
Carbonがインストールされていない方はcomposerを使ってインストールしてください。
`$ composer require nesbot/carbon`
詳しくは[こちらの記事](https://qiita.com/shosho/items/ea049f2a28586364e35c#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)が参考になるかと思います。

## 実装
```test.php
require __DIR__ . "/vendor/autoload.php";
use Carbon\Carbon;

$targetDay = Carbon::create(2021, 12, 13, 06, 00, 00);

$day = Carbon::create(2021, 12, 14, 06, 00, 00);
$yesterday = $day->copy()->subDay();

if($targetDay->between($yesterday, $day)) {
  echo("24時間以内です");
} else {
  echo("24時間以内ではありません");
}
```

## 解説
```php
$targetDay = Carbon::create(2021, 12, 13, 06, 00, 00);
```
まず比較対象の時刻を用意します。

```php
$day = Carbon::create(2021, 12, 14, 06, 00, 00);
$yesterday = $day->copy()->subDay();
```
比較元の時刻と、その時刻の1日前の時刻を用意します。

```php
if($targetDay->between($yesterday, $day)) {
  echo("24時間以内です");
} else {
  echo("24時間以内ではありません");
}
```
「24時間以内」かどうかを判定したいので、比較対象の時刻が比較元の1日前の時刻と比較元の時刻の間かどうかを判定すればOKです。

## 確認
```php
$now = Carbon::create(2021, 12, 14, 06, 00, 00);
$yesterday = $now->copy()->subDay();
$targetDay = Carbon::create(2021, 12, 13, 06, 00, 00);

if($targetDay->between($yesterday, $now)) {
  echo("24時間以内です");
} else {
  echo("24時間以内ではありません");
}
```
`24時間以内です`


```php
$now = Carbon::create(2021, 12, 14, 06, 00, 00);
$yesterday = $now->copy()->subDay();
$targetDay = Carbon::create(2021, 12, 14, 06, 00, 00);

if($targetDay->between($yesterday, $now)) {
  echo("24時間以内です");
} else {
  echo("24時間以内ではありません");
}
```
`24時間以内です`

```php
$now = Carbon::create(2021, 12, 14, 06, 00, 00);
$yesterday = $now->copy()->subDay();
$targetDay = Carbon::create(2021, 12, 13, 05, 59, 59);

if($targetDay->between($yesterday, $now)) {
  echo("24時間以内です");
} else {
  echo("24時間以内ではありません");
```
`24時間以内ではありません`

```php
$now = Carbon::create(2021, 12, 14, 06, 00, 00);
$yesterday = $now->copy()->subDay();
$targetDay = Carbon::create(2021, 12, 14, 06, 00, 01);

if($targetDay->between($yesterday, $now)) {
  echo("24時間以内です");
} else {
  echo("24時間以内ではありません");
}
```
`24時間以内ではありません`
Git Bashで何が何だか分からなくなった時の対処

##Git初心者には複雑すぎる、、、
gitは慣れないと色々なミスをしがちなんですよねぇ～
最近やっとgit hubを理解してきたので少しずつアウトプットしていきたいと思います！

初めは何が問題で何をすべきか一度ミスると分からなくなる！！
そんな時は一旦リセットしてしまえばいいんだと思います(笑)

##①git logでcommitの履歴を確認する。
ちなみにlogから抜けるには  q を入力します。
`パス (ブランチ名)
$ git log
commit 7e3f915fb8688eef4f94cbd867b632ad1367c443 (HEAD -> abcd, master)
Merge: 0e6684d 64eef2f
Author: aaaaaaaaaaaaa
Date:   Fri Dec 4 20:13:21 2020 +0900`

というようにこれまでのcommitの履歴が出てきます。ハッシュ値というのはcommitの後に書いてある“7e3f915fb8688eef4f94cbd867b632ad1367c443” これです！

##②ハッシュ値を指定してリセット
git reset --hard ハッシュ値
`パス (ブランチ名)
$ git reset --hard 7e3f915fb8688eef4f94cbd867b632ad1367c443　　←ハッシュ値
HEAD is now at 7e3f915 Merge pull request #1646 from bbbbbb`

これで以前commitした時の状態にリセット完了。
Bit Tetris （どう書く）

[http://nabetani.sakura.ne.jp/hena/ord2/](http://nabetani.sakura.ne.jp/hena/ord2/)

ビットで表現されたテトリスの揃った行を消すという問題です。

```ruby:Ruby
module BitTetris
  module_function
  
  def solve(input)    
    field = input.split("-").map { _1.to_i(16) }
    to_be_erased = to_a(field.inject(:&))
    field.map { "%02x" % erase(_1, to_be_erased) }.join("-")
  end
  
  def erase(i, to_be_erased)
    to_a(i).zip(to_be_erased).map { |s, t| t == "1" ? "" : s }.join.to_i(2)
  end
  
  def to_a(i)
    sprintf("%08b", i).chars
  end
end


if __FILE__ == $0
  require 'minitest/autorun'
  describe 'BitTetris' do
    [
      ["ff-2f-23-f3-77-7f-3b", "1f-03-00-1c-0d-0f-06"],
      ["01", "00"],
      ["00", "00"],
      ["7a-4e", "0c-02"],
      ["56-b6", "08-14"],
      ["12-12-12", "00-00-00"],
      ["de-ff-7b", "0a-0f-05"],
      ["95-be-d0", "05-1e-20"],
      ["7c-b0-bb", "1c-20-2b"],
      ["7a-b6-31-6a", "3a-56-11-2a"],
      ["32-0e-23-82", "18-06-11-40"],
      ["ff-7f-bf-df-ef", "0f-07-0b-0d-0e"],
      ["75-df-dc-6e-42", "35-5f-5c-2e-02"],
      ["62-51-ef-c7-f8", "22-11-6f-47-78"],
      ["0c-47-8e-dd-5d-17", "04-23-46-6d-2d-0b"],
      ["aa-58-5b-6d-9f-1f", "52-28-2b-35-4f-0f"],
      ["ff-55-d5-75-5d-57", "0f-00-08-04-02-01"],
      ["fe-fd-fb-f7-ef-df-bf", "7e-7d-7b-77-6f-5f-3f"],
      ["fd-fb-f7-ef-df-bf-7f", "7e-7d-7b-77-6f-5f-3f"],
      ["d9-15-b5-d7-1b-9f-de", "69-05-55-67-0b-4f-6e"],
      ["38-15-fd-50-10-96-ba", "18-05-7d-20-00-46-5a"],
      ["fe-fd-fb-f7-ef-df-bf-7f", "fe-fd-fb-f7-ef-df-bf-7f"]
    ].each do |input, expect|
      it input do
        assert_equal BitTetris.solve(input), expect 
      end
    end
  end
end
```

まずは消すべき行をビット演算で求めて（`field.inject(:&)`）、あとはそれぞれの列で消すべきビットを`erase`メソッドで消しています。ビットを消すのにどうすべきかなと迷いました。結局、2進表現してから Array に直して（`to_a`メソッド）、`map`で消しています。String の2進数表現と16進数表現、それに Integer をどう使いわけるかという問題なのかなと思います。

なお、`erase`メソッドでワンライナーでやっている `ary1.zip(ary2).map {|a, b| ...}`みたいな書き方はわたしのよくやるところで、`zip`で Array を作り直しているところは効率がよくないのですが、表現が簡潔になることがあります。愚直に（？）やると、こんな感じかな？

```ruby
  def erase(i, to_be_erased)
    a = to_a(i)
    result = ""
    a.length.times do |j|
      result << a[j] if to_be_erased[j] != "1"
    end
    result.to_i(2)
  end
```

こちらの方が早くて効率がよい筈ですが。
Automation360 接続先Control Roomの変更

#Automation Anywhere Automation360 で、複数環境を利用している際に楽になるバッチ

注意：本投稿は、A2019の頃に作成したものであり、Automation 360で稼働するかどうかは確認しておりません。

Automation Anywhere Automation360 を利用しているユーザーは、複数のControl Room環境を切り替えながら作業することが多いと思います。
その理由としては、
・3CR環境（開発、ステージング、本番環境）によるBLM（Bot Lifecycle Managment）の利用が推奨されている。
・国や部署毎に別環境が用意されている。
・社内の環境と、Community Editionを利用。
等など。

v11の名残なのか分かりませんが、一般的に、Control Roomの切り替えは、
1. Bot Agentのアンインストール
2. 新規Control Roomでのデバイス追加
3. Bot Agentのダウンロードとインストール
という流れがあり、これが正直めんどくさいです。

ドキュメントサイトを見ると、A2019の接続先CRの変更時にアンインストールは不要でプロパティファイルを消せと書いてありますが、このファイルをいちいち見つけて消しに行くのも、めんどくさい。
https://docs.automationanywhere.com/bundle/enterprise-v2019/page/enterprise-cloud/topics/control-room/devices/cloud-bot-agent-manual-upgrade.html

ということで、下記バッチファイルです。
使い方としては、
1. バッチファイル実行（管理者権限で）
2. 移動先Control Roomでデバイス登録
3. 必要があれば認証情報更新
という流れになります。

尚、管理者権限が必要な理由ですが、少し前までのバージョンでは、サービスの停止は入れなくて良かったのですが、
最近のバージョンでは怒られるようなので一旦止めて、プロパティファイル削除後に再起動するようにしています。

また、一応プロパティファイルはファイルを変更して保持するようにしていますので誤って消してしまった場合は、
手動でファイルを戻すことが可能です。（再度デバイス登録してしまったほうが早いかもしれませんけど。）

```A2019接続先CR変更.bat
chcp 65001
@ECHO OFF

:GET_INPUT
SET /P INPUT_STR="A2019 Bot Agentの登録ファイルを消去してよろしいですか？(Y/N): "

IF "%INPUT_STR%"=="Y" (
	GOTO :PROCESS
) ELSE IF "%INPUT_STR%"=="y" (
	GOTO :PROCESS
) ELSE (
	GOTO :END
)

:PROCESS
net stop "Automation Anywhere Bot Agent"
set yyyy=%date:~0,4%
set mm=%date:~5,2%
set dd=%date:~8,2%
set time2=%time: =0%
set hh=%time2:~0,2%
set mn=%time2:~3,2%
set ss=%time2:~6,2%
set filename=%yyyy%-%mm%%dd%-%hh%%mn%%ss%

CD C:\Windows\System32\config\systemprofile\AppData\Local\AutomationAnywhere\
REN registration.properties registration.properties_%filename%

net start "Automation Anywhere Bot Agent"

ECHO "--------------------------------------------"
ECHO "       登録ファイルを削除しました。          "
ECHO " 利用したいA2019環境で登録を行ってください。 "
ECHO "--------------------------------------------"

:END
PAUSE
```
AWSを用いてWEBサーバーを構築してみる【構想編】

##構成を考える
今回、技術向上を目的として実験的にWEBサーバーと、関連するサービスを構築していく。

以下に今回構築する環境の大まかな図を示す。
![Untitled Diagram (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612635/57b335ab-b68d-aced-bbf5-8c2e1d22d06c.png)

|  図の表記  |  説明  |
| ---- | ---- |
|  サーバー①  |  プロキシサーバー。サーバー②がインターネットに出る際に経由する  |
|  サーバー②  |  WEBサーバー。Apacheを動かす  |
|  ELB  |  サーバー②とクライアントの間でやり取りする  |
|  S3バケット  |  各サーバーにマウントし、ログなど再度サーバー内で参照しないようなデータを保存する。  |


サーバー①
・Amazon Linux2
・squid Version 3.5.20 (プロキシOSS)
・fuse
・goland
・git
・goofys

サーバー②
・Amazon Linux2
・Apache 2.4
・fuse
・goland
・git
・goofys

※ELB用の証明書登録、S3へのアクセスのためのIAMロール作成は省略する。

##構築
セキュリティグループの作成
　各サーバー、ELBに割り当てるセキュリティグループ（以降、SGと表記する）を作成する。
　作成するSGの名前と内容は以下のようにサーバー、およびELBと対応させる。
　
　サーバー①：server1SG
　　インバウンド：server2
　　アウトバウンド：0.0.0.0

　サーバー②：server2SG
　　インバウンド：ELBSG
　　アウトバウンド：server1

　ELB：ELBSG
　　インバウンド：0.0.0.0
　　アウトバウンド：0.0.0.0


サブネットの作成
　図通りに、ELB、サーバー①用のパブリックサブネット、サーバー②用のプライベートサブネットを作成する。


S3バケットの作成
　マネジメントコンソール画面上でS3バケットを作成する。


インスタンスの作成
　マネジメントコンソール画面上でサーバー①、サーバー②のインスタンスをそれぞれ作成する。
　インスタンスタイプ、EBSボリュームは初期状態で作成する。


ターゲットグループの作成
　マネジメントコンソール画面上でターゲットグループを作成する。
　サーバー②を登録インスタンスとし、プロトコルはHTTPで作成する。


ELBの作成
　作成したターゲットグループをデフォルトの転送先に指定して、ELBを作成する。


OSの設定、パッケージのインストール
　サーバー①にて、プロキシサーバーを先に作成する。
　サーバー①が作成できたのちにサーバー②にてサーバー①経由の通信でパッケージのインストールを試みる。
　今回は、profileでの設定ではなく、yumやgitなどそれぞれの設定でプロキシサーバーを経由する設定を試みる。

###検証編へ
実際の構築の様子や、使用したコマンドについては【検証編】にて紹介する。

###参考
プロキシ
https://qiita.com/hana_shin/items/0f574358d040b4c60889#32-squid%E3%81%AE%E3%83%9D%E3%83%BC%E3%83%88%E7%95%AA%E5%8F%B7%E9%96%8B%E6%94%BE

go getのプロキシ設定
https://qiita.com/reud/items/e135b5ccb666a39b5b25

Apache
https://weblabo.oscasierra.net/apache-installing-apache24-yum-centos7-1/
WebサービスのDBに関する失敗談


アドベントカレンダー初めての投稿です！

去年の`本番環境でやらかしちゃった人`カレンダーの投稿を読みとても面白かったので、
今年は初挑戦させていただきましたw

とあるwebアプリケーションにてDB関連でやらかしたことを2本立てで投稿させていただきます。

## 1本目: 会員データの電話番号や郵便番号の0を飛ばしちゃった話

会員テーブルを整理することになった時の話です。

当時このテーブルは適切ではないデータ型(length含む)や未使用カラムが、存在していました。
変更用のマイグレーションファイルの作成を行い本番にマイグレートしたときに惨劇は起こっていたのです！

問題となったのは以下のカラム変更

|   Column    |   Type     |
| ----------- | ---------- |
|  zipcode_01 |  LongText  |
|  zipcode_02 |  LongText  |
|  tel_01     |  LongText  |
|  tel_02     |  LongText  |
|  tel_03     |  LongText  |

   ↓   ↓   ↓   ↓   ↓   ↓　

|   Column    |   Type     |
| ----------- | ---------- |
|  zipcode_01 |  Small Int |
|  zipcode_02 |  Small Int |
|  tel_01     |  Small Int |
|  tel_02     |  Small Int |
|  tel_03     |  Small Int |

もう理解できた方は多いと思われますが・・・
この変更を行うと郵便番号や、電話番号の数値の`先頭0`が飛ばされてしまうのです！
携帯番号は`090`,`080`とはじまるので、これが `90`, `80`になってしまいます。

このことに気がつかず、当時数値データのみのカラムなんだから、数値型にするべきだろうと
本番にマイグレーションしてしまいました。

そして、翌日に会員データがおかしいと連絡を受けて発覚しました。

幸いなことに、DBのバックアップがあったのと、
電話番号と郵便番号はある程度パターンが決まっているので、桁数などでチェックを行い、0が取り除かれたであろうデータは０を追加してデータの修正を行いました。結果会員データの復旧をすることができました。

最終的に内部スキーマは`VarChar`で適切なlengthを指定するように変更しました。

### 惨劇はなぜおこってしまったのか
* 自分が無知であった。また調査・確認が足りていなかった。
* ステージやローカルでも確認をおこなっていたが、作成していたデータは、郵便番号や携帯番号など`111`など適当にしかいれていなかったので、データのおかしさに気づくことができなかった。

### 二度と惨劇を起こさないためにどうしたのか
* この経験から郵便番号や電話番号など`先頭0`に意味があるものは`VarChar`を使うということを学んだ。
* ステージやローカルなどに適当なデータではなくある程度本番に近い形を想定したデータを作成するようにした。


## 2本目: 知らずにDBをいじめていた時の話
ユーザが入力したデータ(String)をDBに登録して、同じデータであれば集計していくという改修を行った時の話です。
改修自体はスムーズでした。

入力されたデータをチェックして、同じものがあれば`count`カラムに対して +1
なければ、データを新しく登録するといった内容で、この改修はおわりました。

実装当初時は問題なくスムーズに動いていましたが、その改修から2年ほどたったころに惨劇がおこっていることに気づきました。
DBの負荷が年月が立つことに、増えていってたのです。
アクセス数が単純に増えて行ってたこともあり、全く気づいていませんでした。
サイトはよくダウンするようになり、DBがボトルネックとなっていて、負荷集中時に耐えられなくなっていたのです。
その時に原因に気づきました。

`ユーザが入力したデータ(String)をDBに登録して、同じデータであれば集計していくという改修`でデータを登録していたテーブルのレコード数が
増えていきレコード数が多くなったため、入力されたデータのチェック処理時の`SELECT`クエリの実行がすごく重くなっていたのです。

### 惨劇はなぜおこってしまったのか
* データが増えた時の想定を全くしていなかった
* 本番での運用を想定して処理の仕方を工夫しないといけなかった。今回の場合はデータのチェック処理がまずかった。


### 二度と惨劇を起こさないためにどうしたのか
* 大量にデータが登録されるテーブルは、開発時に大量のデータを登録して動作を行うようにする。
* 登録処理と集計処理は別にする。=> リアルタイムで必要はなかったため、集計はバッチで行い負荷が少ない時間に行うようにした。

以上。最後まで見ていただきありがとうございました。

WEBエンジニア、特にバックエンドだとDBの扱いが非常に大切になります、機能の実装のための設計にもあてはまりますが、
運用に関してはしっていれば、防げることは多くあると思います！
この記事が、1人でも多くのエンジニアの役に立てばいいなと思い苦い思い出ではありますが、投稿させていただきました！

twitterでの活動などもおこなっておりますので、PHPやDBなど技術関係の話をしたい人がいれば是非お気軽に絡んでください！
UE4 Groom（ヘアー・ファー）の便利な機能

# はじめに
この記事は、[Unreal Engine 4 (UE4) その3 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/ue4_tre) 17日目の記事になります。

UE4.26でProduction Readyになったヘアー・ファーを少し触ってみて、いろいろと便利な機能があって感動したので、それについて書いてみようと思います。
UE4ではグルーム（Groom）と呼んでいるようです。

セットアップに関しては公式ドキュメントの通りやればできるので、詳しくはこちらをご覧ください。
https://docs.unrealengine.com/ja/WorkingWithContent/Hair/index.html

# バインディングアセット
バインディングアセットを正しく設定すると、ボーンアニメーションなどでメッシュが変形してもグルームが自動で追従します！
![ude.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390524/9c1d86ea-e60c-fb7a-2b05-eb14d92f4e6b.gif)

最初、そういう機能があるとは知らなかったので、追従させるためにはAlembic Animationを作って読み込む方法とかを無駄に調べたりしてました。
Alembic GroomとSkeletal Meshは別々に読み込むのですが、ここで座標系がずれていてバインディングがうまくいかないことがあったので、読み込み時に座標系をきちんとあわせておいたほうがいいかと思います。

# LOD
LODが一瞬で設定できます！
グルームアセットを開いてLODのメニューから下の+を押すだけで、LODを追加できます。
![タイトルなし.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390524/f69905fc-3273-a1bb-22d3-ef84662641f5.jpeg)

間引くと同時にグルームを太くすることができるので、薄毛になったりせずに処理負荷軽減ができます。
下の動画だと、LOD1で半分、LOD2で4分の1の量になっています。
カード型のメッシュなどにも切り替えることができます。
![lod.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390524/b217574f-8676-772a-1df9-42c168842dad.gif)

# シミュレーション
シミュレーションできます！楽しい！
![simu.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390524/0080017e-bb0d-0580-f33f-6392d27af0ff.gif)

Niagaraを使ってシミュレーションを加工できるので、アイデア次第で面白いこともできそうです。
プラグインフォルダのHairStrands ContentのなかにあるGroomSprigsSystemなどをコピーしてカスタムできます。

![スクリーンショット 2020-12-12 203920.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390524/5bfea822-936e-82ac-b3ed-0c58b76ca48e.jpeg)

例えば、風の向きを変えたいときは、Setup Groom PhysicsのなかのAirVelocityの値をModule Inputから与えてあげるようにすればランタイムで動的に制御できます。
![スクリーンショット 2020-12-12 203649.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390524/b71dac0b-cff7-deb0-e5b0-0370a306e497.jpeg)

![スクリーンショット 2020-12-12 203615.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390524/f179c5b3-30d9-1249-99fb-94b74250fc42.jpeg)

![air.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390524/59db771f-89b4-0af7-38d3-cc5555c0d03a.gif)

# 終わりに
こんなにフサフサな毛がリアルタイムで動くのが驚きです。リアルタイムファーは意外と早く主流になるかもしれませんね。
ちょうど、明日から [UE4ぷちコン 映像編2nd](https://historia.co.jp/archives/17838/) もはじまります。
映像では特に使いやすいと思いますので、ぜひ試してみてください！
Selenideで半角カナ入力

# Selenideで半角カタカナを入力するには
Selenideを使用してテキストボックスに半角カタカナを入力すると、「ｱｲｳｴｵ」→「3e456」のように意図しない文字が入力されてしまう。そのような場合は以下の設定をするとよい。

```java
Configuration.fastSetValue = true;
```

この設定は、値をsendKeysではなくJavaScriptにより入力するためのものらしい。詳しくは`com.codeborne.selenide.SelenideElement.setValue`参照。

なお値の入力は`WebElement.sendKeys`ではなく`SelenideElement.setValue`により行うこと。

```java
Configuration.fastSetValue = true;

// 半角カタカナ入力できる👍
Selenide.$(By.id("text1")).setValue("ｱｲｳｴｵ");

// 半角カタカナ入力できない😢
Selenide.$(By.id("text1")).sendKeys("ｱｲｳｴｵ");
```

## 動作確認環境
* Java8
* Selenide 1.15.1
* WebDriver / ブラウザ
    * ChromeDriver 87.0.4280.88 / Chrome 87.0.4280.88
    * MSEdgeDriver 87.0.669.0 / Microsoft Edge 87.0.664.57

# その他
「ｱｲｳｴｵ」が「3e456」になるのは、キーボード配列と何か関係がありそう。
Ransack sort_link　色の変更の仕方！

## Ransack sort_linkでclassを指定することでcssを使って、色を変更する方法

ransackでのソート実装は下記URLを参考にしました
[Rubyon Rails で検索機能を作ろう（ransack）](https://qiita.com/nojinoji/items/e1b174220da8c81a1756)
####変更前の状態
![スクリーンショット 2020-12-14 8.34.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/750557/bd671d44-1096-ff54-6de0-419c0b562305.png)

####変更後の状態
![スクリーンショット 2020-12-14 8.34.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/750557/a9547f63-6319-ff2c-d6e8-effd7632bf0e.png)

上記画像での、`リツイート数ソート部分`を
デフォルトの青色を黒色に変更する！



index.html.erb

```
<%= sort_link(@q, :tweet_created_at, "投稿日時" ,{ default_order: :desc }, { class: "Editlink" }) %>
```

application.scss

```
// リンク色消す
.Editlink {
  text-decoration: none;
  color: #272343;
  &:link {
    text-decoration: none;
    color: #272343;
  }

  &:visited {
    text-decoration: none;
    color: #272343;
  }

  &:hover {
    text-decoration: none;
    color: #272343;
  }

  &:active {
    text-decoration: none;
    color: #272343;
  }

}

```

`<%= sort_link(@q, 並べるカラム名, "リンクに表示する文字" ,{ 並べ方指定}, { Htmlのオプション }) %>`
この書き方のhtmlオプション部分にて、classやidを指定すれば、cssを使って好きなようにsort_linkをカスタマイズできる！
WordPress「the_archive_title」使用時に余分な「タグ：」等を消す方法

the_archive_titleを使えば
WordPressで設定している「タグ」、「年月などアーカイブ」等々、簡単に出力できる。

はじめに、「the_archive_title」の使用方法は簡単でこうする。

```php:php
<h1><?php the_archive_title(); ?></h1>
```

めっちゃ便利！！

##余分な「タグ：」等を消す方法
「function.php」に下記のコード書くだけ。

```php:function.php
/* ---------------------------------------
the_archive_titleの余分な文字を削除
--------------------------------------- */
add_filter( 'get_the_archive_title', function ($title) {
    if (is_category()) {
        $title = single_cat_title('',false);
    } elseif (is_tag()) {
        $title = single_tag_title('',false);
    } elseif (is_tax()) {
        $title = single_term_title('',false);
    } elseif (is_post_type_archive() ){
        $title = post_type_archive_title('',false);
    } elseif (is_date()) {
        $title = get_the_time('Y年n月');
    } elseif (is_search()) {
        $title = '検索結果：'.esc_html( get_search_query(false) );
    } elseif (is_404()) {
        $title = '404ページ';
    } else {
    }
    return $title;
});
```

##さいご

以上！！
では、また！！
【技術書まとめ】『りあクト！ TypeScriptで始めるつらくないReact開発 第3版【Ⅰ. 言語・環境編】』を読んだまとめ

- React の歴史や思想から学ぶと根本理解となる
- `.vscode/`の下に`settings.json`や`extensions.json`をつくる
- JSのメソッドは単なるプロパティ
- 関数式とは無名関数をいったん生成した上でそれを変数に代入することによってメモリ上に残しているもの
- this とは、その関数が実行されるコンテキストであるオブジェクトへの 参照が格納されている『暗黙の引数』
    - `minky.greet() メソッドとしての実行ではアクセス演算子 . の前の minky オブジェクトが引 数 this として自動的に渡されてる`(python)
- thisの中身
    1. new呼び出し時の新規生成オブジェクト
    2. メソッドとして実行した時のその所属したオブジェクト
    3. 1.2以外の関数[非Strict]であればグローバルオブジェクト
    4. 1.2以外の関数[Strict]であればundefined
        - `this.name = name;`であっという間にグローバル汚染するから
        - `「初期設計をミスったせいで、安全性を担保するためには言語としての一貫性を犠牲にするしかな かったわけですか……」`
- thisで気をつけること
    - thisはクラス内でしか使わない
    - クラス内ではメソッド含めた全ての関数をアローで書く
- プログラミングの種類
    - 命令型（レシピ）
        - 手続き型
        - オブジェクト指向
    - 宣言型（SQLなど）
        - 関数型
            - `map`や`reduce`
                - `reduce`
                    - スープを煮詰めていく
                - `forEach`を使う時
                    - `map`や`find`の組み合わせでできないか考える
            - イミュータブルな変数が基本
                - 安全性が高い
            - 完成形を見据えて絞り込んでいく
- オブジェクトの反復処理
    - `Object.keys()`
    - `Object.values()`
    - `Object.entries()`
- クロージャ
    - 関数と「その関数が作られた環境」が一体となった特殊なオブジェクト
    - `const counter = (count = 0) => (adds = 1) => count += adds;`
    - `const increment = counter();`
    - `increment()`
        - なぜ`count`がクリアされず増えていくのか？
            - 自由変数
- 型推論、null安全性、モダンなIDE
    - 静的型付け言語普及の土台
- `never`型
    - case文の`default`に入れて漏れをチェックできる
- 継承より合成
    - 継承
        - 不必要なメンバー変数を継承してしまう
        - 親クラスの変更の影響範囲がわからない
            - 子クラスと名前空間共有のため責任の境界があいまい
    - 合成
        - APIとして使う
            - 依存がない
- TypeScriptのクラスの2つの顔
    - インターフェイスでもある
    - コンストラクタ関数でもある
- 最初から型エイリアスだけ使っていればいい
- 型ガード

```ts

type Address = { zipcode: string; town: string };
type User = { username: string; address: Address };

const isUser = (arg: unknown): arg is User => {
  const u = arg as User;

  return (
    typeof u?.username === 'string' &&
    typeof u?.address?.zipcode === 'string' &&
    typeof u?.address?.town === 'string'
  );
};

const u1: unknown = JSON.parse('{}');
const u2: unknown = JSON.parse('{ "username": "patty", "address": "Maple Town" }');
const u3: unknown = JSON.parse(
  '{ "username": "patty", "address": { "zipcode": "111", "town": "Maple Town" } }',
);
[u1, u2, u3].forEach((u) => {
  if (isUser(u)) {
    console.log(`${u.username} lives in ${u.address.town}`);
  } else {
    console.log("It's not User");
//  console.log(`${u.username} lives in ${u.address.town}`);  /* compile error */
  }
})
```
uwsgi設定の見直し

参考記事
https://www.saintsouth.net/blog/setup-django-app-with-uwsgi-and-nginx/#toc-6

##uwsgi コマンドによる WSGI サーバーの動作確認

この動作確認が完了して、uwsgi.iniに書き込んでいきます。
逆に出来なければiniファイルの段階に進めない？

uwsgiのファイルを保存するディレクトリを作っておきます。

```
[root@f5les1se run]# mkdir uwsgi.webapppackage
```

```
$ uwsgi --home=/home/admin/myapp/myappenv \
> --uid=nginx \
> --gid=nginx \
> --chdir=/home/admin/myapp/webapp \
> --module='webapp.wsgi:application' \
> --env DJANGO_SETTINGS_MODULE=webapp.settings \
> --master \
> --vacuum \
> --pidfile=/home/run/uwsgi.webapppackage/master.pid \
> --http=127.0.0.1:8000
```

以下のエラーが出ました。



```
*** Starting uWSGI 2.0.19.1 (64bit) on [Mon Dec 14 08:30:25 2020] ***
compiled with version: 4.8.5 20150623 (Red Hat 4.8.5-44) on 12 December 2020 03:40:30
os: Linux-3.10.0-693.el7.x86_64 #1 SMP Tue Aug 22 21:09:27 UTC 2017
nodename: f5les1se
machine: x86_64
clock source: unix
pcre jit disabled
detected number of CPU cores: 1
current working directory: /home/admin/myapp
writing pidfile to /home/run/uwsgi.webapppackage/master.pid
open("/home/run/uwsgi.webapppackage/master.pid"): Permission denied [core/utils.c line 3624]
unlink(): No such file or directory [core/uwsgi.c line 1617]
```


open("/home/run/uwsgi.webapppackage/master.pid"): Permission denied [core/utils.c line 3624]
unlink(): No such file or directory [core/uwsgi.c line 1617]

もっかいしっかり見てみます。
URLの疑似静的化




#目的
ブログサイトでapacheのmod_rewriteモジュールを用いて動的ページ"review.php?id=16"を"review_16"に疑似静的化する

#前提
Webサーバーはapacheを使用
当初URLパラメータでブログの記事の認識をしようとしていた(?id=xxx)が静的化を試みる
ほとんど、個人メモなので理解しやすく記述できてません。質問ある方はお気軽に！

#mod_rewriteの設定
- httpd.confの下記設定をする

```
LoadModule rewrite_module modules/mod_rewrite.so
```

- .htaccessに下記を追加する

```
RewriteEngine On
RewriteRule ^review_([0-9]+)$ review.php?id=$1
```


#結果
静的化により各ページ参照が出来るようになった

##参考
[動的ページSEO：URL擬似静的化](https://www.export-japan.co.jp/blog/%E5%8B%95%E7%9A%84%E3%83%9A%E3%83%BC%E3%82%B8seo%EF%BC%9Aurl%E6%93%AC%E4%BC%BC%E9%9D%99%E7%9A%84%E5%8C%96)

#その他の参考記事
[疑似静的化（動的ページURLを静的ページに見せかける）](https://deepseo.co/htaccess/from-dynamic_url-to-static_url/)
[基本的な正規表現一覧](https://murashun.jp/blog/20190215-01.html)
[Apache「mod_rewrite」の設定方法](https://webtan.impress.co.jp/e/2009/10/13/6233/page/1)

#補足
"+":直前の文字が １回以上 繰り返す場合にマッチ
Jupyter Notebook のグローバル変数汚染との戦い

[Kaggle Advent Calendar](https://qiita.com/advent-calendar/2020/kaggle) の12日目の記事です。

こんにちは。[fkubota](https://www.kaggle.com/fkubota)です。今はKaggle Expertです。
さっそくですが、Jupyter Notebook で作業をしている時、グローバル変数に困らされたことはないでしょうか？

僕は業務でもKaggleでもNotebook上で作業をすることが多々あるのですが、結構な頻度で意図しないグローバル変数が原因のバグに出会います。  
そこで以下のTweetをしてみました。これが事の始まりです。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">aaa = 1<br><br>def hoge(b):<br> c = aaa + b<br> return c<br><br>print(hoge(2))<br><br>↑これ動くの嫌なんですが、どうにかしてエラー吐かせるようにできないですか？<br>与えた引数の変数しか使えないようにしたいです…</p>&mdash; fkubota 🦉 (@the_phi_is_cast) <a href="https://twitter.com/the_phi_is_cast/status/1335378864063664130?ref_src=twsrc%5Etfw">December 6, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


こういったこと、クラスとか使ってちゃんと書いた.pyのスクリプトだと起こらない自体ですよね。
Jupyter Notebookは便利ですが、こういったことが原因のバグを埋め込んでしまうことがあります。
これを避けるには、notebookを使わないという選択肢もありますが、もっと簡単な方法で避けることができます。  

詳細は省きますが[nyker_gotoさん](https://twitter.com/nyker_goto)や[まますさん](https://twitter.com/mamas16k)などのお力を借りて`@noglobals` デコレータを使えばいいということで決着します。

簡単な例で説明します。まずは、`@noglobals` を定義します。

```python
import builtins
import types

def imports():
    for name, val in globals().items():
        # module imports
        if isinstance(val, types.ModuleType):
            yield name, val

            # functions / callables
        if hasattr(val, '__call__'):
            yield name, val


def noglobal(f):
    '''
    ref: https://gist.github.com/raven38/4e4c3c7a179283c441f575d6e375510c
    '''
    return types.FunctionType(f.__code__,
                              dict(imports()),
                              f.__name__,
                              f.__defaults__,
                              f.__closure__
                              )
```

**準備完了** です！！どう使うかというと、デコレートするだけです。

**エラーがでない例**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/868744/39505881-1c5d-21a8-bc14-a2f0c75c0980.png)



**エラーがでる例**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/868744/46a83dc2-42f6-7cfa-415a-4caac14622a7.png)


この手軽さがたまりません。現在、notebookで作業しているのであれば、`@noglobals` を関数に片っ端からつけてみてはいかがでしょうか。

簡単ですが、効果の大きいテクニックかなと思います。  
最後に、簡単なサンプルのノートブックと、問題を解決しようとした猛者たちの戦いを紹介して終えようと思います。

- [sample notebook](https://github.com/fkubota/notebook/blob/master/24_noglobal.ipynb)
- 猛者たちの戦いTweet↓
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">実はこれ使うとデフォルト引数が使えないっていう問題があるんですが、誰かpythonの言語機能に詳しい人使える方法思いついたりしないですかね。。。。。 <a href="https://t.co/6DC7xP5O5b">https://t.co/6DC7xP5O5b</a></p>&mdash; まます (@mamas16k) <a href="https://twitter.com/mamas16k/status/1335457303449927681?ref_src=twsrc%5Etfw">December 6, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

以上です！快適なJupyter Notebookライフを送りましょう！