OmniAICreator/Qiita-1.07M huggingface dataset:
格安BLE温湿度計のデータをESP32で取得してみた

※自分用メモです。

最近話題のXiaomiの格安BLE温湿度計のデータをESP32で取得してみた。

試したのはXiaomiのLYWSD03MMCというやつ。
スマフォのアプリと接続すると、BLEのアドバタイズパケットにデータを載せて飛ばしてくるみたい。

以下ソースコード。

~~~

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>

int scanTime = 5; //In seconds
BLEScan* pBLEScan;

std::string strDeviceName = "LYWSD03MMC";

class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
    void putHex(uint8_t *ptr, size_t len) {
      for( size_t i=0; i<len; i++) {
        Serial.printf("%02X", *ptr++);  
      }
      Serial.println("");
    }
    void onResult(BLEAdvertisedDevice advertisedDevice) {

      int n = strDeviceName.compare(advertisedDevice.getName());
      if ( n == 0){ 
        uint8_t *pPayload = advertisedDevice.getPayload();
        size_t len = advertisedDevice.getPayloadLength();

        if ((*(pPayload + 0x03) == 0x0f) && (*(pPayload + 0x04) == 0x16) && (*(pPayload + 0x03) == 0x0f) && (*(pPayload + 0x05) == 0x95) && (*(pPayload + 0x06) == 0xfe)) {
          int16_t temp = *(pPayload + 18) + *(pPayload + 19) * 256;
          uint8_t humidity =  *(pPayload + 21);

          Serial.printf("Temp: %d Humidity:%d\n", temp, humidity);
        }
      }
    }
};

void setup() {
  Serial.begin(115200);
  Serial.println("Scanning...");

  BLEDevice::init("");
  pBLEScan = BLEDevice::getScan(); //create new scan
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
  pBLEScan->setInterval(100);
  pBLEScan->setWindow(99);  // less or equal setInterval value
}

void loop() {
  // put your main code here, to run repeatedly:
  BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
  Serial.print("Devices found: ");
  Serial.println(foundDevices.getCount());
  Serial.println("Scan done!");
  pBLEScan->clearResults();   // delete results fromBLEScan buffer to release memory
  delay(2000);
}

~~~

結構簡単。
ゼロから始めるLeetCode Day94 「929. Unique Email Addresses」

# 概要

海外ではエンジニアの面接においてコーディングテストというものが行われるらしく、多くの場合、特定の関数やクラスをお題に沿って実装するという物がメインである。

どうやら多くのエンジニアはその対策としてLeetCodeなるサイトで対策を行うようだ。

早い話が本場でも行われているようなコーディングテストに耐えうるようなアルゴリズム力を鍛えるサイトであり、海外のテックカンパニーでのキャリアを積みたい方にとっては避けては通れない道である。

と、仰々しく書いてみましたが、私は今のところそういった面接を受ける予定はありません。

ただ、ITエンジニアとして人並みのアルゴリズム力くらいは持っておいた方がいいだろうということで不定期に問題を解いてその時に考えたやり方をメモ的に書いていこうかと思います。

[Leetcode](https://leetcode.com/)

Python3で解いています。

[ゼロから始めるLeetCode 目次](https://qiita.com/KueharX/items/6ee2502c3b620c795b70)

前回
[ゼロから始めるLeetCode Day93 「49. Group Anagrams」](https://qiita.com/KueharX/items/5fdb75638c3fa0cfe657)

[Twitter](https://twitter.com/kueharx)やってます。

**[技術ブログ](https://kueharx.blogspot.com/)始めました！！**
技術はLeetCode、Django、Nuxt、あたりについて書くと思います。**こちらの方が更新は早いので**、よければブクマよろしくお願いいたします！


## お知らせ
Day 100でQiitaでの投稿はひとまず区切りを付けようかと思います。
タグの記事が僕の記事ばかりになってしまうのもいかがなものかと思いましたし、他に有益な情報を提供している方の邪魔になってしまうこともあると考えたので、こうすることにしました。
至らない部分は多々ありましたが、今までお付き合い頂きありがとうございました。

問題を解いて記事を書く、というのは上記の個人ブログで続けるつもりですし、興味ある方はたまにそちらを覗いていただけると嬉しいです。
Twitterの方のアカウントはほとんど更新通知用と化しているので、Leetcodeを解く記事について気になる方はそちらも合わせてフォローいただくと良いかもしれません。

# 問題
[929. Unique Email Addresses](https://leetcode.com/problems/unique-email-addresses/)
難易度はEasy。
[コーディング面接対策のために解きたいLeetCode 60問](https://1kohei1.com/leetcode/)からの抜粋です。

問題としては、すべての電子メールは、@記号で区切られたローカル名とドメイン名で構成されています。
例えば、alice@leetcode.com では、alice がローカル名で、leetcode.com がドメイン名です。
小文字の他に、これらの電子メールには '.'や'+'が含まれている場合があります。
メールアドレスのローカル名の一部の文字の間にピリオド('.')を追加すると、ローカル名のドットがない同じアドレスに送信されたメールが転送されます。 例えば、「alice.z@leetcode.com」と「alicez@leetcode.com」は同じメールアドレスに転送されます。 (この規則はドメイン名には適用されませんのでご注意ください)。
ローカル名にプラス('+')を追加した場合、最初のプラス記号以降はすべて無視されます。これにより、特定のメールをフィルタリングすることができます。例えば、m.y+name@email.com は my@email.com に転送されます。 (繰り返しになりますが、このルールはドメイン名には適用されません)。
これらのルールを同時に適用することも可能です。
仮に電子メールのリストが与えられた場合、リスト内の各アドレスに1つの電子メールを送信します。 実際にメールを受信するアドレスはいくつあるでしょうか? 

>Example 1:

>Input: ["test.email+alex@leetcode.com","test.e.mail+bob.cathy@leetcode.com","testemail+david@lee.tcode.com"]
Output: 2
Explanation: "testemail@leetcode.com" and "testemail@lee.tcode.com" actually receive mails

# 解法

```python
class Solution:
    def numUniqueEmails(self, emails: List[str]) -> int:
        fixed_email = set()
        for lists in emails:
            local,domain = lists.split("@")
            local = local.split("+")[0].replace(".","")
            fixed_email.add(local + "@" + domain)
        return len(fixed_email)
# Runtime: 52 ms, faster than 77.31% of Python3 online submissions for Unique Email Addresses.
# Memory Usage: 14.2 MB, less than 5.16% of Python3 online submissions for Unique Email Addresses.
```

実装の面で苦労する、というよりは問題を噛み砕いて考える方が難しいかもしれませんね。
集合を管理する場合、Pythonでは`set()`を使うと和集合や積集合などを簡単に取り扱うことができるのでおすすめです。

流れとしてはfor文で全てのリストを網羅するというのが大前提にあり、その中でどういった処理を行うかがこの問題の核となるでしょう。
僕は`split()`を使って`local`部分と`domain`部分に分け、問題文で書かれているように最初の`+`以外は無視して良いので最初の`+`で分割し、全ての`.`を無くすことで判別を行いました。
最終的に集合の長さを返せばきちんと実際にメールを受信するアドレスの数、となるといった仕組みです。

この問題は集合の知識が必要かと最初は思うかもしれませんが、実質的には数え上げに近く、Hashmap的な問題だとリンク先では紹介されていました。

初見だと面食らうかもしれないので実際に解くことをお勧めします。

では今回はここまで。お疲れ様でした。
変数の定義を省略して複数のフィールドに代入する[TypeScript]

記事の命名が迷子

# やりたいこと

こういったオブジェクトがあって、

```ts
interface UserProperties {
    userid: number;
    username: string;
}

const getUserProperties = (): UserProperties => ({
    userid: 1,
    username: 'おなまえ',
});
```

別のオブジェクトの引数なんかにに代入したい

```ts
class User {
    id: number;
    name: string;
    constructor(params: { id: number; name: string }) {
        this.name = params.name;
        this.id = params.id;
    }
}
```

# 変数を定義してから

```ts
const props = getUserProperties();
const user = new User({ id: props.userid, name: props.username });
```

# 定義せずに

```ts
const user = new User(
    ((props: UserProperties) => ({
        id: props.userid,
        name: props.username,
    }))(getUserProperties()),
);
```

# 定義せずに書くと

**読みにくい**
JavaScript で数字を漢数字に変換する例

`111011101110` を `"一一一〇一一一〇一一一〇"` ではなく `"千百十億千百十万千百十"` とするタイプです。

toKanjiNumber.js

```javascript
const kanjiNumeral = [
  // これ以上は Number.MAX_SAFE_INTEGER を超えるため考慮しない。
  [1000000000000, "兆"],
  [100000000, "億"],
  [10000, "万"],
  [1000, "千"],
  [100, "百"],
  [10, "十"],
];

const kanjiDigits = ["", "一", "二", "三", "四", "五", "六", "七", "八", "九"];

const kanjiRecursive = (value) => {
  let current = value;
  let str = "";

  kanjiNumeral.forEach(([base, char]) => {
    const num = Math.floor(current / base);

    if (!num) return;

    let recurredStr = kanjiRecursive(num);

    if ("千百十".includes(char) && recurredStr.endsWith("一")) {
      recurredStr = str.substring(0, recurredStr.length - 1);
    }

    current -= num * base;

    str = `${str}${recurredStr}${char}`;
  });

  return `${str}${kanjiDigits[current]}`;
};

const toKanjiNumber = (value) => {
  let num = Number(value);

  if (num === 0) return "〇";

  let positive = true;

  if (num < 0) {
    positive = false;
    num = Math.abs(num);
  }

  const str = kanjiRecursive(num);

  return positive ? str : `-${str}`;
};

export default toKanjiNumber;
```
【メモ】Skickaを使ってGoogleDriveに簡単アップロード

Skickaを使えば、ターミナルからGoogleDriveに簡単にファイル/フォルダのアップロード/ダウンロードができるのでインストールの過程をメモ
#環境
Ubuntu18.04

#Goのインストール
1.[公式サイト](https://golang.org/dl/)からインストールをする

 上記ページで自分のOSにあったソースコードをダウンロード

 (今回はUbuntu18.04なのでLinuxを選択)

クリックすると、`/home/user/Downloads`に`go1.14.6.linux-amd64.tar.gz`というファイルがダウンロードされる

2.圧縮ファイル`.tar.gz`を`/usr/local`配下に解凍

```
tar -C /usr/local -xzf go1.14.6.linux-amd64.tar.gz
```

3.Pathを通す
以下のコマンドを実行してPathを通す

```
export PATH=$PATH:/usr/local/go/bin
```
Pathが通ったことを確認するために、

```sh
$ go
```
コマンドを実行して、

```sh
Go is a tool for managing Go source code.

Usage:

	go command [arguments]

The commands are:

	build       compile packages and dependencies
	clean       remove object files and cached files
	doc         show documentation for package or symbol
	env         print Go environment information
	bug         start a bug report
	fix         update packages to use new APIs
	fmt         gofmt (reformat) package sources
	generate    generate Go files by processing source
	get         download and install packages and dependencies
	install     compile and install packages and dependencies
	list        list packages
	run         compile and run Go program
	test        test packages
	tool        run specified go tool
	version     print Go version
	vet         report likely mistakes in packages

Use "go help [command]" for more information about a command.

Additional help topics:

	c           calling between Go and C
	buildmode   build modes
	cache       build and test caching
	filetype    file types
	gopath      GOPATH environment variable
	environment environment variables
	importpath  import path syntax
	packages    package lists
	testflag    testing flags
	testfunc    testing functions

Use "go help [topic]" for more information about that topic.
```
こんな感じになればPathが通ってる
これでGoの準備はOK!!

#Skickaのインストール
1.goコマンドを使ってGithubからskickaをインストール

```sh
$ go get github.com/google/skicka
```
2.Pathを通す

```sh
$ export PATH=~/go/bin:$PATH
```

3.設定ファイルの初期化
`skicka init`コマンドを実行すると`.skicka.config`ファイルが作成される

```sh
$ skicka init
20XX/MM/DD hh:mm:ss created configuration file /home/user/.skicka.config.
```

4.Googleアカウント認証
`skicka -no-browser-auth df`コマンドを実行すると、URLが出力され、ブラウザ上でアップロード先のGoogleアカウントの認証ができる

```sh
$ skicka -no-browser-auth df
Go to the following link in your browser: （ここにURLが表示される）
Enter verification code: （認証後に表示される認証コードをここに貼り付けたらエンターキーを押す）
```
※URL先で認証をしようとして、「Google でログイン機能が一時的に無効」と出てきた場合には、[こちらの記事](https://qiita.com/satackey/items/34c7fc5bf77bd2f5c633)を参考にAPIキーの設定を行う

5.接続確認

```
$ skicka ls
```
で接続したGoogleDrive上のファイル/フォルダが確認できればOK

```
$ skicka df
```
でGoogleDriveの使用状況が確認できる

#アップロード・ダウンロード

- アップロード`skicka upload` 

```
(ファイルのアップロード)
$ skicka upload <ファイルパス> <Drive上のパス>

(ディレクトリのアップロード)
$ skicka upload <ディレクトリパス> <Drive上のパス+ディレクトリ名を指定>
```

- ダウンロード`skicka download`
基本的には、uploadと同じ

```
$ skicka download <Drive上のパス>　<localのパス>
```

※ディレクトリごとの場合は、`/`をつける必要があるので注意！（つけないと中身だけアップロード/ダウンロードされる）
SMTPSを使ってKotlinでGmailを送る

メモ程度の内容です。
セキュリティ的に問題があるので、[Gmail API](https://developers.google.com/gmail/api) を使うことが推奨されています。
しかし、私自身上手くできなかったのでとりあえずこちらでやってみたという感じです。
出来たらいいですね…頑張ります。

```build.gradle.kts
// ...
dependencies {
// ...
    implementation("com.sun.mail:javax.mail:1.6.2")
}
```

```kotlin
import javax.mail.Message
import javax.mail.Session
import javax.mail.Transport
import javax.mail.internet.InternetAddress
import javax.mail.internet.MimeMessage

/*
 * https://myaccount.google.com/lesssecureapps
 * 安全性の低いアプリの許可を "有効" にしなければいけない
 */

fun main(){
    // System.setProperty("GMAIL_USER", "ユーザー名)
    // System.setProperty("GMAIL_PASSWORD", "パスワード")
    GmailUser(System.getProperty("GMAIL_USER"), System.getProperty("GMAIL_PASSWORD")).send("宛先@example.com", "タイトル", "本文")
}

class GmailUser(private val user: String, private val password: String) {
    fun send(to: String, title: String, text: String) {
        val properties = System.getProperties()
        properties["mail.smtp.host"] = "smtp.gmail.com"
        properties["mail.smtp.socketFactory.port"] = "465"
        properties["mail.smtp.socketFactory.class"] = "javax.net.ssl.SSLSocketFactory"
        properties["mail.smtp.auth"] = "true"
        properties["mail.smtp.port"] = "465"

        try {
            val session = Session.getDefaultInstance(properties)

            val message = MimeMessage(session).apply {
                setFrom(InternetAddress("$user@gmail.com"))
                setRecipients(Message.RecipientType.TO, InternetAddress.parse(to))
                subject = title
                setText(text)
            }

            Transport.send(message, user, password)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}
```
個人だけで開発する人向けのGitコマンドまとめ

#前提
次のような方を対象に想定して書きました。

- 個人だけで開発する(Branchを複数作らない)
- Githubに自分のリモートリポジトリを持っている
- cmdかGit Bashでgitコマンドが実行できる状態
- Gitに関して詳しい情報や深い話はとりあえず後回しで良い

基本的にコマンド表記と箇条書きでしか記載しません。
ほぼ私の備忘録なので非常に粗野ですがよかったら参考にしてください！

#コマンド
##①ローカルリポジトリを初期化する
```
$ git init
```
- カレントディレクトリをローカルリポジトリとして登録します。
- このコマンドを実行する前に存在したファイルがある場合はそれら新規ファイルとして扱われてます。
- すでにリモートリポジトリを登録している場合には③を先にやっても問題ないです。

##②ローカルリポジトリとリモートリポジトリを繋げる
```
$ git remote add origin https://github.com/username/repository.git
```
- 上の例で`username`の部分は自分のユーザー名、`repository`の部分はリモートリポジトリの名前を書いてください。
- ここまででリモートリポジトリに上げることは完了です。

##③ローカルリポジトリの変更をリモートリポジトリに上げる
###変更した全部の内容をコミットとしてまとめる場合
```
$ git add .
```

###ファイルやフォルダに分けてコミットを作りたい場合
```
$ git add fileA.txt
```

###2つや3つののファイルやフォルダをまとめたい場合
```
$ git add fileA.txt folderX ./folderY/fileB.txt
```

この例は次の3つをまとめてコミットを作っています。

- ローカルリポジトリのフォルダ内にあるfileA.txt
- 同じくローカルリポジトリのフォルダ内にあるfolderX
- ローカルリポジトリの1つ下の階層にあるfolderYの更に下にあるfileB.txt

##④コミットを作る
```
$ git commit -m 'add new file'
```

- 上のコマンドの`add new file`は変更内容に関するメッセージです。
- 自分の好きな文章で大丈夫です。
- 一言で書けるのが望ましいようです。
- 一応下の例のように日本語で書いても大丈夫みたいです。

```
$ git commit -m '新規ファイルを追加'
```

##⑤ローカルで作ったコミットをリモートリポジトリに上げる
```
$ git push origin main


- 上の例で`origin`の部分は追加したリモートの名前を書いてください。`main`の部分はbranch名を書いてください。
- branch名については個人で開発する範囲ならば、基本的には`main`だけだと思います。
- ネットに繋がっていないなどの障害がなればパスワードの入力が要求されます。
- 入力で来たらEnterキーを押します。
- 入力している文字は表示されませんが、入力されているし間違っていたら再度入力要求してくれるの安心してください。
- ここまででリモートリポジトリに上げることは完了です。
- 単にバージョン管理をしたいだけという場合は、最初だけ①をやって②から④を繰り返せばOKです。

##⑥リモートリポジトリをローカルリポジトリとして取ってくる
```
$ git clone https://github.com/username/repository.git
```
- 上の例で`username`の部分は自分のユーザー名、`repository`の部分はリモートリポジトリの名前を書いてください。
- ここまででリモートリポジトリをローカルリポジトリへ取ってくることは完了です。
- 取ってきたリモートリポジトリはリモートリポジトリ名が付いたフォルダとして保存されます。
- 今まで開発用に使っていなかったPCにリモートリポジトリを取り込むときなどに使います。
- 取り込んだ後は②から④を繰り返すことができます。

##⑦リモートリポジトリの変更内容をローカルリポジトリに取ってくる
```
$ git pull origin main
```
- 上の例で`origin`の部分は追加したリモートの名前を書いてください。`main`の部分はbranch名を書いてください。
- branch名については個人で開発する範囲ならば、基本的には`main`だけだと思います。
- ネットに繋がっていないなどの障害がなればパスワードの入力が要求されます。入力で来たらEnterキーを押します。
- 入力している文字は表示されませんが、入力されているし間違っていたら再度入力要求してくれるの安心してください。
- 別のPCで加えて変更を取り込むときなどに使います。
- このコマンドを打った後は②から④を繰り返すことができます。

##番外①：リモートリポジトリでローカルリポジトリを上書きする
```
$ git fetch origin main
$ git reset --hard origin/main
```
- 強制で上書きされます．

##番外②：ローカルリポジトリでリモートリポジトリを上書きする
```
$ git push -f origin main
```
- これも強制で上書きできます．
    - リモートリポジトリを作る時にREADME.mdも一緒に作成してたりすると「pushの前にfetchしてください」ってエラーが出ると思います．
    - 私はよくやりがちなので結構-fオプションのpushはよくやります．
開発時に使うショートカット覚書（Mac 版）

## 概要

* 開発時に使うショートカットの忘備録です。
VSCode や ブラウザの操作などをまとめます。

* Mac の日本語キーボードを想定してます。

## Mac (Finder)

* `Control + Shift + .`  
Finder 内にドットファイルを表示させるトグルコマンド

## ブラウザ

* `alt + ⌘ + i`
Google Chrome で Web Inspector を開閉

* `shift + ⌘ + r`
ページのキャッシュを消して更新
（Safari 以外）

## VSCode

* `Cntrol + B`
ファイル一覧の開閉

* `Conrol + Shift + @`
ターミナルの開閉
Rails tutorial 1.3.2でRailsページが表示されない時の対処法

記事作成日：2020/07/21
##自己紹介
こんにちは。
最近、プログラミングを勉強し始めたおかむと申します。
初めて記事を投稿するので、拙い部分があるかと思いますがご了承ください。
##内容
さて、本題に入っていきます。
Ruby on Rails チュートリアル Rails6.0（第6版）にて、Rails tutorialを進めていた途中つまづいた所があったので、つまづいた所と私が行った対処法を共有したいと思います。
###つまづいた所
Rails tutorial Rails6.0(第6版)←有料のやつ
1.3.2 rails server
という章のrails serverを起動し、Railsページを表示させるところで表示されるページが違うという点でつまづきました。
↓このような画面が表示されるはずが
![スクリーンショット 2020-07-21 03.53.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/662989/edec0f22-9266-9fa7-d450-751861c1e5bc.png)
↓このような画面が表示されてしまいました。
![https3A2F2Fqiita-image-store.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/662989/91557865-1418-3740-f647-e715f7a88a14.png)
###対処法
上のような所でつまづいたのですが、検索をしながら対処したら表示できたので対処法を述べます。
簡単に述べると

- Cloud9を落とす
- awsマネジメントコンソールを開きEC2を検索する
- Cloud9のインスタンスを停止する
- 再度Cloud9で画面を表示するとチュートリアル通りの画面が表示される

このような方法です。
言葉だけだと説明しづらいので以下に画像を載せながら説明していきたいと思います。

まず、「Cloud9を落とす」
これはWindowsだったら×ボタン、Macだったら左上の×ボタンをCloud9を開いた状態で押します。
![スクリーンショット 2020-07-21 03.53.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/662989/0d610190-287e-c138-d996-634e2c1c07f3.png)

次に「awsマネジメントコンソールを開きEC2を検索する」
これはCloud9を開いた時のようにawsを開き、サービスの検索欄に「EC2」と入力し、そのサービスを開きます。
![スクリーンショット 2020-07-21 22.05.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/662989/0ba69d23-2a6b-24a4-fd73-b8fdf3c52bb0.png)

そして「Cloud9のインスタンスを停止する」
EC2を開いたら、そのアカウントで使用しているインスタンスの一覧が表示されます。
その中で緑色の丸でrunningと書かれているインスタンスがあると思うので、そのインスタンスのチェックマークにチェックをします。
チェックをしたら、画面上部にあるアクションボタンをクリックし、メニューが出てくるので「インスタンスの状態」→「停止」クリックします。
![スクリーンショット 2020-07-21 22.07.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/662989/470e2019-6341-60b5-3083-61dbc389a91e.png)

そしたら以下のような警告が出てくると思うのですが、無視して「停止する」ボタンを押してください。
![スクリーンショット 2020-07-22 01.49.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/662989/6dd17d5d-562a-d035-f497-562cf57ea858.png)

以上の段階を踏み、再度Cloud9で画面を表示するとチュートリアル通りの画面が表示される。
![スクリーンショット 2020-07-21 03.53.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/662989/edec0f22-9266-9fa7-d450-751861c1e5bc.png)
私は、この方法で表示させることができました。
皆様の参考になれば幸いです。

##参考にした記事
https://qiita.com/taraka/items/0c98afb92c93ebae4947
【Python】データサイエンス100本ノック（構造化データ加工編） 009 解説

- データサイエンス100本ノックをやりきる会を作りました🎉
- こちらの[Slack招待URL](https://join.slack.com/t/data-science-100nocks/shared_invite/zt-gfncg9vm-8W8b3UrDg8R~TKaqUkQpgw)からご参加ください！！
- ぜひ一緒に励まし合いながら、データサイエンス100本ノックをやり切りたいと思っています！

##Youtube
[動画解説](https://youtu.be/_k0cNP4vfhs)もしています。

##問題
P-009: 以下の処理において、出力結果を変えずにORをANDに書き換えよ。

```:コード
df_store.query('not(prefecture_cd == "13" | floor_area > 900)')
```

##解答
```:コード
df_store.query('prefecture_cd != "13" & floor_area <= 900')
```

##出力
|  | store_cd | store_name | prefecture_cd | prefecture | address | address_kana | tel_no | longitude | latitude | floor_area |
|--:|:--|:--|--:|:--|:--|:--|:--|--:|--:|--:|
| 18 | S14046 | 北山田店 | 14 | 神奈川県 | 神奈川県横浜市都筑区北山田一丁目 | カナガワケンヨコハマシツヅキクキタヤマタイッチョウメ | 045-123-4049 | 139.5916 | 35.56189 | 831.0 |
| 20 | S14011 | 日吉本町店 | 14 | 神奈川県 | 神奈川県横浜市港北区日吉本町四丁目 | カナガワケンヨコハマシコウホククヒヨシホンチョウヨンチョウメ | 045-123-4033 | 139.6316 | 35.54655 | 890.0 |
| 38 | S12013 | 習志野店 | 12 | 千葉県 | 千葉県習志野市芝園一丁目 | チバケンナラシノシシバゾノイッチョウメ | 047-123-4002 | 140.0220 | 35.66122 | 808.0 |

##解説
・PandasのDataFrame/Seriesにて、条件に当てはまる行を確認する方法です。
・条件に当てはまる情報を確認したい時に使用します。
・数学では、**"not (A or B)" = "not A & not B"**と表すことができます。
メタファーとしての負債


「技術的負債」にという言葉について、その概念の生みの親であるWard Cunninghamが語った内容をt-wadaさんが翻訳されていたのでメモ
[【翻訳】技術的負債という概念の生みの親 Ward Cunningham 自身による説明](https://t-wada.hatenablog.jp/entry/ward-explains-debt-metaphor)

### 面白いと思った点
- 負債（Debt）というメタファーは、開発中の金融系ソフトウェア（TDD本にも出てくるWyCash）について上司に説明するため、その業界の用語を使った
- Ward Cunninghamとしては、行き当たりばったりなソフトウェアアーキテクチャや、雑なコードのことを指していたわけではない
- 借金してギャンブルにつぎ込むような行き当たりばったりなイメージではなく、資金調達して事業を素早く立ち上げ、そこで得られた利益で返済するという計画的なイメージであったこと
- 得られた利益で借金の返済を行わないと、最後は利子で首が回らなくなることを、ソフトウェアをリリースして得た学びをソフトウェアに反映していかないリスクのメタファーとしていたこと
ナイキアプリ【NTC】から見るコンバーション戦略

#はじめに
COVID-19を受け自宅での運動を行うことが増えました。
ナイキのアプリ「NIKE TRAINING CLUB」（以下**NTC**）を利用して運動を行っています。
無料なのが信じられないほど内容が素晴らしいですので、ぜひお試しください。
[NTCアプリ公式サイトはこちら](https://www.nike.com/jp/ntc-live?cp=46237152282_search_%7c%E3%83%8A%E3%82%A4%E3%82%AD%20%E3%83%88%E3%83%AC%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0%20%E3%82%AF%E3%83%A9%E3%83%96%7c8286420930%7c100354952878%7ce%7cc%7ckwd-772412214429&gclid=EAIaIQobChMIrNvfgc7e6gIVQp_CCh1HAAiSEAAYASAAEgKiSvD_BwE)

NTCを始めてからナイキのECで初めて買い物をすることになり、その後も購入する流れが生まれています。
「運動しようかな〜（NTC立ち上げ）」　→　「この靴欲しい・・・（ポチ）」までの絶妙な流れを生み出す科学を自分なりに考えてみました。

##NIKEのミッション
####世界中全てのアスリートにインスピレーションとイノベーションをもたらす
[出典はこちら](https://nikeats.avature.net/careerJP/AboutUs)

ナイキさんかっこいい・・・
ここで言う「アスリート」は、運動するしないにかかわらず全人類に向けられているようです。


##アプリの棲み分け

NTCアプリ内では、靴などアイテムの購入はできません。
アイテム購入は、別途**「Nike」**アプリが専門であり、そちらでの購入となっています。
[Nikeアプリ公式サイトはこちら](https://www.nike.com/jp/nike-app)

用途ごとにアプリが分かれているのも、使いやすさの秘訣かもしれません。
（逆に分割していて分かり辛いものもありますが・・・）

個人的にはメルカリとメルペイのアプリを分けて欲しいと思っています。
分けたら売上が減ると見越して、わざと分けていないんでしょうね。


##広告塔の役割
NTCのアプリ内には、新着アイテムやセールの広告がたくさん舞い込んできます。
運動だけが目的であった私も、30%OFFセールの広告が来た時には速攻「Nike」アプリのダウンロードをしました。
そして買いました。
ナイキさんはNTCを新しい顧客を獲得する場として設計していると思いました。

運動習慣が定着している人ほど商品に触れる機会が多くなるので、筋肉を刺激すると同時に物欲まで刺激されます。
そのまま、幾度となく購入する顧客に育てていく土壌を展開していますね。

##ターゲット狙い撃ち
運動している人が使うアプリなので、ナイキさんに対して「そもそも興味ないから」とい人はいない環境が形成されています。広告の完全なる空振りが発生しない「空間」を自作しています。
この「興味ある人だけ訪れる空間」の作成はプログラミングスクールのサイトなどにも使われていますね。応用が効きそうです。

NTC内には身長・体重・性別などの情報を紐付けるため、さらにニッチな広告をセレクトすることも可能です。（「この体重であればダイエットで利用しているな」など）
「空間」×「ユーザー情報」の威力は高そうです。釣り堀みたい・・・
そうなると、NTCの充実具合と売上の関係性も見えてきそうですね。



##NTC側では商品を全て見せない
アイテムにもよりますが、NTCの広告で気になったアイテムをタップすると、広告表示のある画像１枚と商品のふんわりとした説明のみ出てきます。さらに詳しく見るには、Nikeアプリへの移動が求められます。
移動したNikeアプリは、「カートに追加」ボタンがすぐ近くにあります。着実に購入に向かう流れがこの辺りにありそうです。


##アプリ間の移動が早い
ハード面の話になりますが、

NTCの広告で気になったアイテムをタップすると、即時Nikeアプリに移動します。
そして商品掲載ページが表示されます。
そこにかかる時間はほんのわずか、インスタで次の画像を見る程度の時間です。
開発者の気合が感じられます。

##EFOの徹底
Nikeアプリで一度商品を購入したら最後、住所からカード情報までシッカリ保管され続けます。
初回登録も簡単サクサク行えます。

次回購入における工程は、

- 商品・サイズを選ぶ
- カートに追加
- 購入する

数回ポチポチするだけで、ボタンの位置も不自由ありません。
しかも送料無料、商品本体の金額とのみ向き合えば良いので、こちらの負担も小さく済みます。

いかに負担をかけずに購入させるか、考え抜かれている印象を全体的に受けました。
こういう所を徹底している企業さんは、個人的にも好感が持てますね。
（新幹線の指定席購入サイトもこのくらい頑張って欲しいですね・・・）

##最後に
「ナイキさんすごい」しか言っていない宣伝投稿となりました。すみません。
企業のパワーがもたらす所も多いですが、アプリ構成などは参考になる面もありそうです。
参考ではなく、何かの気づきにつながれば幸いです。
ありがとうございました。
dockerで作るnuxt.jsの開発環境

## 環境

docker desktop for windows(wsl2)



## 実装

### Dockerfile

```dockerfile
FROM node:12.18.2-alpine

RUN apk update && \
    npm install -g npm && \
    npm install -g create-nuxt-app
    
ENV HOST 0.0.0.0
EXPOSE 3000
```

node.jsの最新安定板のコンテナイメージでnpmの更新とcreate-nuxt-appをインストールしています。それからホスト側からアクセスできるようにします。



### docker-compose.yml

```yaml
version: '3'
services:
  web:
    build: .
    ports:
      - "3000:3000"
    working_dir: "/usr/local/src"
    volumes:
      - ".:/usr/local/src"
      - node_modules_volume:/usr/local/src/first-app/node_modules
    tty: true
volumes:
  node_modules_volume:
```

Dockerfileと同じディレクトリ内に配置して使います。
ポートフォワーディングとデータ永続化、コンテナの起動を維持するためのtty: trueだけを記述したシンプルな構成です。あとは、node_module用にVolumeを作成します。これがあるのと無いのとでは実行速度に天と地の差がありました。





### ビルド&起動

```sh
$ docker-compose build
$ docker-compose up
```

すると、dockerのダッシュボードから確認できるようになるので、cliからコンテナの中に入ります。



### アプリケーション作成

```bash
/usr/local/src # npx create-nuxt-app first-app

create-nuxt-app v3.1.0
✨  Generating Nuxt.js project in first-app
? Project name: first-app
? Programming language: JavaScript
? Package manager: Yarn
? UI framework: Vuetify.js
? Nuxt.js modules: Axios, Progressive Web App (PWA)
? Linting tools: ESLint, Prettier, Lint staged files, StyleLint
? Testing framework: None
? Rendering mode: Universal (SSR / SSG)
? Deployment target: Server (Node.js hosting)
? Development tools: jsconfig.json (Recommended for VS Code)
.
.
.

🎉  Successfully created project first-nuxt-app

  To get started:

        cd first-nuxt-app
        yarn dev

  To build & start for production:

        cd first-nuxt-app
        yarn build
        yarn start

  To test:

        cd first-nuxt-app
        yarn test

```



### nuxtの既成レイアウトを使いたい

https://vuetifyjs.com/ja/getting-started/pre-made-layouts/
この中のBaselineが使いたいのでlayouts/default.vueを変更(コピペ)

```bash
cd first-nuxt-app
yarn dev

.
.
.
.

  82:10  error    Insert `⏎`                                                                                                                                                                                                                             prettier/prettier

✖ 16 problems (15 errors, 1 warning)
  15 errors and 0 warnings potentially fixable with the `--fix` option.

```



詳しいことはわかりませんがprettierがエラーをだした。下記コマンド実行後サーバー再起動。
https://stackoverflow.com/questions/52571675/nuxt-js-module-error-from-node-modules-eslint-loader-index-js

```bash
npx prettier --write "**/*.{vue,js}"
```

![nuxt-page.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533660/f3d2e5f9-a3d3-ab94-3fbe-6683d418c413.png)
よし！



### ホットリロード

サーバー再起動するが面倒なのでホットリロードの設定をつけます。
nuxt-config.jsにて

```javascript
module.exports = {
  ...
    watchers: {
       webpack: {
           poll: true
       }
    }
```



```bash
 Waiting for file changes                                                                                    15:57:50
ℹ Memory usage: 472 MB (RSS: 595 MB)                                                                          15:57:50
ℹ Listening on: http://172.21.0.2:3000/
```

動きました！
Text.Selectとやらを作ってみる｜Power Query

知らないうちに増えていたので、作りつつ挙動を理解してみます。
さーっと作ったので、どこかおかしいかもしれません。
たぶん2010のアドインにはなかったですよね。:expressionless:

##Referenceでは
下記の通り載っている。手元のPDFにもいつの間にか入っていました。
https://docs.microsoft.com/ja-jp/powerquery-m/text-select
これによると、
`Text.Select(text as nullable text, selectChars as any) as nullable text`
とのこと。この情報といじった感じの挙動をもとに、コードを書いてみる。

##コード

```pq:fx_Text_Select
(text as nullable text,SelectChars as list) as nullable text=>
let
    TestedSource = let Splitted = List.Transform(SelectChars,each Text.ToList(_){0})
                   in  if SelectChars = Splitted then SelectChars
                       else error "リストに1文字でない語が入っています。",
    CharList = Text.ToList(text),
    SelectedList = List.Transform(CharList,
                                  each if List.Contains(TestedSource,_) then _ 
                                       else null
                   ),
    NonNullList =List.RemoveNulls(SelectedList),
    result =if text = null then null
            else Text.Combine(NonNullList)
in
    result
```

##テスト
###正常なケース
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370992/b69df283-dcd6-4c19-b0cf-067508d97cc2.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370992/15d2ccf6-bad7-4cc2-da24-292bf6944a60.png)
###エラーになるケース
こういうのは本家でもエラーになります。半角カタカナは濁点が文字から切り離されるので、都合が悪いんですよね。
本家
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370992/fc996a9e-bdef-f719-3124-cf36d58ed6e2.png)

自作
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370992/3fd69866-0ed0-a5e5-01be-22881198cc8b.png)
【超初心者用】【MySQL 】ERROR 1044 (42000)とERROR 1064 (42000)

###ERROR 1044 (42000)必要な権限がないエラー

```
ERROR 1044 (42000): Access denied for user 'user'@'localhost' to database 'dotinstall_db'
```
ちゃんと教材通りに書いたのに・・・



###ERROR 1064 (42000)構文エラー

```
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'identified by 'test'' at line 1
```
ちゃんと教材通りに書いたのに・・・
バージョンによって構文が変わるの？と思って調べて行きました。

結局`ERROR 1064 (42000)`をそのまんまググりつつ、`ユーザの追加`について`MySQL 5.6 リファレンスマニュアル`がヒットするのでそれを参照

https://dev.mysql.com/doc/refman/5.6/ja/


###ドットインストールの通りにやったのに・・・
mysqlの使い方をドットインストールで勉強していましたがうまく行きませんでした。

###バージョンの確認

自分のバージョン

```
// phpのバージョン確認
$ php -v 
PHP 7.4.8
// mysqlのバージョン確認
$ mysql --version
mysql Ver 8.0.19 for osx10.15 on x86_64 (Homebrew)
```

ドットインストールのバージョン

```
PHP 5.6.11
mysql 14.14　Distrib 5.5.44, for Linux (x86_64) using readline 5.1
```


###ERROR 1064 (42000)は構文エラー
mysqlのバージョンがドットインストールのバージョンと違うことによるのか、ドットインストールのコマンドを使っても発生していた。

1. ユーザの追加

ドットインストールでは

```
mysql> grant all on dotinstall_db.* to username@localhost identified by password
```

自分のバージョンでは

```
mysql> CREATE USER 'username'@'localhost' IDENTIFIED BY 'password';
（これだけじゃ足りなて、次の権限の付与が別で必要）
```

`all`か`all privileges`かの違いがあるよう。
また、`with grant option`というのも必要らしい。

https://www.postgresql.jp/document/8.0/html/sql-grant.html
これによると
>
WITH GRANT OPTIONが指定されると、権限受領者はその後、他のユーザにその権限を与えることができます。 グラントオプションがないと、受領者はこれを行うことができません。 現時点では、グラントオプションは個々のユーザに対してのみ与えることができ、グループやPUBLICには与えることができません。

ということらしい。
とりあえず書いといた方が良いということかしら。


2. 権限の付与

```
mysql> grant all privileges on dotinstall_db.* to 'username'@'localhost'
    -> with grant option;
```

上記二つ、つまり

```
mysql> CREATE USER 'username'@'localhost' IDENTIFIED BY 'password';
mysql> grant all privileges on dotinstall_db.* to 'dbuser'@'localhost'
    -> with grant option;
```
これらを実行することで、

```
$ mysql -u username -p
```

を実行してパスワードを入力すると入れました。


###感想
ほんと一つずつうまく行かなくて全然進まない。
なんか他の環境を使えばもっと楽になるらしいですが、しっかり理解したいので、ローカル環境を使おうと思っているけど、

1. バージョンごとの違い
2. ディレクトリの違い

などでとにかくつまづく。でもその辺りの違いをしっかり理解していなければ、状況ごとに柔軟に対処できなくなると思うので、なんとか解決しながら進みたい！と決意。
http→httpsにしてjQueryが動かなくなった時の対処法


#前提

RailsでEC２にデプロイをしたアプリケーションをSSL化したいと思い、AWSの``ALB``を使って``https化``しました。

``https://www.アプリ名.com/``でアクセスしてみると、アプリケーション自体はエラーを吐かずにトップ画面が表示されたのですが、トップ画面の画像が表示されない。
というのも、jQueryで動きをつけていたからでした。

EC2にデプロイ時にも、同じ現象が起きました。

#解決法

```app/views/layouts/_default.html.erb
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= stylesheet_pack_tag 'application', 'data-turbolinks-track': 'reload' %>

#ここが引っかかってた
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

```

```app/views/layouts/_default.html.erb
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= stylesheet_pack_tag 'application', 'data-turbolinks-track': 'reload' %>

#httpを削除
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
```

``https://www.アプリ名.com/``で再度ブラウザで確認してみると、無事にjQueryが動きました。
デプロイ時点で、

```
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
```

と記述できていたら、今回の事象が起きなかったですが次回にいかします。

それでは。
rubyでドローポーカーを作ってみる～準備編～


## きっかけ

@paraizo2424
[Rubyでちょっとずつポーカーを実装する その1](https://qiita.com/paraizo2424/items/23f5ab031dbda184ce9d#comment-1df6bf7c79800f629c23)

こちらを見たときにいいチャレンジだな～と思いコメントを入れたのですが
はたして自分はアドバイスできるほどの技術力があるのだろうか？
まだまだアドバイスをもらう側ではないのか？

と考えたときに、自分ならどう設計・実装するのか？を改めて整理しながら
自分との見つめ合い ということで作ってみようと思いました

仕事でrubyを使っていますが、入社当初はruby何それ？って名前くらいしか知らないレベルだったため
そういう意味も込めて振り返れたらなと思います

## まずポーカーのルールを整理

参考: https://playingcards.jp/game_rules/drawpoker_rules.html

### 使用カード

- 全スートの1~13 + ジョーカーあり？
  - 今回はjoker無しで行きます
  - もしかしたら追加するかも？

### プレイヤー

- `2..7`人

### ルール

1. 各プレイヤーに山札から5枚ずつ配る
    - 各プレイヤーは5枚を周りに見せない
2. 各プレイヤー順番に、1回のみ好きな枚数カードの交換が可能
3. 各プレイヤー手札を見せ、手札の組み合わせ（役）に応じて勝敗が決まる
    - 本来はここにベット（掛け金）があり、これを得るための勝負となる
    - 今回はひとまずベットも無しとする

### 役

- 下記の上から順番に強い役となる
  - ロイヤルストレートフラッシュ
      - 同じマークの10、J、Q、K、Aをそろえる
  - ストレートフラッシュ
      - 同じマークで、5枚の数字が連続する
  - フォーカード
      - 同じ数字のカードが4枚ある
  - フルハウス
      - スリーカードとワンペアが1組ずつできる
  - フラッシュ
      - 同じマークのカードが5枚ある
  - ストレート
      - マークに関係なく5枚の数字が連続する
      - （10-J-Q-K-AはストレートとなるがQ-K-A-2-3はストレートにならない
      - すなわちKとAは連続するがK-A-2含むものはストレートにはならない）
  - スリーカード
      - 同じ数字のカードが3枚ある
  - ツーペア
      - 同じ数字のカードが2組ある
  - ワンペア
      - 同じ数字のカードが1組だけある
- 2人のプレイヤーが同じ役を作った場合は、役を構成しているカードの強い方が勝ちとなる
  - カードの強い順位は、A・K・Q・J・10~2
  - スートの強い順位は、スペード・ハート・ダイヤ・クローバー
- 役を構成しているカードも同じ場合は、役に使われていないカードが強い方が勝ちとなる

### 疑問点

- 捨てたカードは公開する？
  - 公開しないらしい
- フルハウス同士の比較は？
  - フルハウス同士の場合は、3 枚 1 組のカードのランク
- ストレート同士の比較は？
  - 一番強いカードで比較
- ストレートの小技
  - > 注意: エースに限りランクが一番上または一番下のカードとして使用できます。 最も強いストレートは A-K-Q-J-T (エースハイ)、最も弱いストレートは 5-4-3-2-A (ファイブハイ) です。

参考
- https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q11159415671
- https://www.pokerstars.com/ja/poker/games/rules/hand-rankings/?no_redirect=1

## 今回の実装範囲の決定

- ベットが無いため連続した勝負とはせず1回の勝負の実行とする
- 画面などの作り込むのは面倒なのとrubyのクラス設計・実装などを目的とするため、コンソールでの実行とする
- 全プレイヤーが交換を行うようにしないと最初の5枚で勝負というのは厳しいと思うため、全プレイヤーを実行者が操作するものとする（勝負の意味ｗ）

## 実装環境の決定

- ruby2.6.5を使用
- test-unitを使用
  - 普段は仕事ではrspecしか使用していないためせっかくなので触ってみる

## 登場人物の整理

なんと表現するのが適切かわかりませんが、モノと、モノではないもの（= 概念）という意味で分けてみる

### モノ

- カード
- プレイヤー

### 概念

- 山札
  - カード全て
- 手札
  - 山札から配られた各プレイヤーの手札（5枚）
- 役
  - 手札の中の組み合わせ
  - 下記を持つ
    - 役の種別
    - 役の中での強さ

## ソース

https://github.com/rytkmt/ruby_poker

これから作っていくため、まだ空で作成したのみです。
ここから。楽しみ。

## 続き

↓
[rubyでドローポーカーを作ってみる～test-unit準備編～
](https://qiita.com/r12tkmt/items/48940d0e09a77d210bf2)
【Python】Google Colaboratoryで.pyファイルを実行したい！


#はじめに、そして結論。

はじめてColaboratoryを使ったときに、**.pyファイルを実行する方法**がわからなくて結構調べました。自分の備忘のために記事として残しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184786/4c7f9bc5-9a98-d9cc-036f-a9c17189f166.png)
atomと新たに作成したrepositoryを再連携する方法（github）

#対象とする方
・Atomとgithubを再連携（Atom上でcomit,pushなどの操作ができる状態）したい方
・新しいrepositoryを作成してそれをAtomと連携したい方
・githubをAtomで使用できるようにしたい方

#環境
・Windows10
・Atom 1.48.0
※atom,githubアカウント,git,gitbushはインストール済みであることとします。

#手順
##手順①リポジトリの作成
githubにログインしrepositoryを作成する。

##手順②リポジトリのURL取得
①で作成したrepositoryのURLを取得
下の画面の赤枠箇所のURLをコピーしておきます。（SSHとHTTPSのどちらかでURLを取得できるようになってますがSSH推奨です。違いが気になる方はググればででくるので調べてみてください。）

![github画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663519/69626e63-a279-00a6-36a8-becc83efe3e9.png)


##手順③gitbushでリポジトリをクローンしたい場所を指定
gitbushを起動
④：`cd`コマンドでrepositoryをcloneしたい箇所のpassを指定する。（`cd`を入力してrepositoryをcloneしたいファイルをgitbush上にドラッグすればpassが入力されます。）


![gitbush画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663519/0d020859-68fb-f61d-cfa3-2c9a35eaa0e1.png)

##手順④指定した場所にローカルリポジトリを作成
gitbush上で以下のコマンドを実行

```:gitbush
$ git clone git@github.com:your-username/your-repositoryname.git
```

※上記の`git@github.com:your-username/your-repositoryname.git`は手順②でコピーしたURLをそのまま張り付けたものです。
※$は入力しません。

手順④のコードを実行すると以下のコードが表示されlocal repositoryが作成されます。
local repository は手順③で指定したpassの箇所に作成されます。

```:gitbush
$ git@github.com:your-username/your-repositoryname.git
> Cloning into `Spoon-Knife`...
> remote: Counting objects: 10, done.
> remote: Compressing objects: 100% (8/8), done.
> remove: Total 10 (delta 1), reused 10 (delta 1)
> Unpacking objects: 100% (10/10), done.
```

##手順⑤
Atomを起動する。
※はじめてAtomとgithubを連携する方は以下のページを参考にしてから以下の手順に進んでください。
・ [【atomをgithubと連携させよう！】導入手順まとめ](https://www.sejuku.net/blog/73327)

##手順⑥ローカルリポジトリをAtomのプロジェクトフォルダに追加
Atom起動後`ファイル`を選択し`プロジェクトフォルダを追加`を選択（ctrl+shift+Aでも可）

![atom画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663519/d85fda78-5c97-58bb-5d39-71d5309e5ca9.png)

手順④で作成したlocal repositoryを選択する。

##手順⑦githubと連携できているか確認
試しに手順⑤で作成したlocal repositoryに`hello world.py`ファイルを作成・保存する。
作成すると以下の画面の赤枠の箇所にファイルの追加・変更が反映されます。

![atom1画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663519/3950ce08-d572-92e2-c7cc-154cbb2c3be6.png)

後の手順のステージング、コミット、プッシュのやり方については省略します。
ご希望があればコメントしていただければ記載します。

#参照URL
以下のHPを参考にしましたので載せておきます。

###github クローンする方法
[[github公式]リポジトリをクローンする](https://docs.github.com/ja/github/creating-cloning-and-archiving-repositories/cloning-a-repository)
sed 削除コマンドの正規表現デリミタに / 以外を使う

GNU sed 4.4 で確認した。

## /regexp/d のデリミタ
`sed '/regexp/d'` で `regexp` にマッチする行を削除できる。
`regexp` を括るデリミタに `/` 以外を使いたい場合、最初のデリミタの前に `\` をつけるとできる。

```sh
$ cat input.txt | sed -e '\%regexp%d'
```

## s/regexp/replacement/ のデリミタ

置換コマンド `s/regexp/replacemenet/` でデリミタに `/` 以外を使いたい場合は、`\` 不要でそのまま使える。

```sh
$ cat input.txt | sed -e 's%regexp%replacement%'
```

## 違いは regexp がアドレスか、コマンドの一部か

sed スクリプトのシンタックスは次のようになる。

```
[addr]X[options]
```

`X` はコマンド。(e.g. `d`, `s/regexp/replacement`)

`addr` はアドレス。
`addr` が指定された場合、`addr` にマッチする行に対してのみ `X` が実行される。

`addr` にはいくつかの形式があり、正規表現で指定する形式として `/regexp/` と `\%regexp%` が利用可能。（それぞれに修飾子をつけた形式もある。）
後者の `\%regexp%` はデリミタ `%` を任意の文字に置き換えて利用できる。

要するに、
`/regexp/d` の `/regexp/` は **アドレスであり、デリミタを変更したければ `\%regexp%` を使う必要がある。**
`s/regexp/replacement/` はそれ全体 `s/regexp/replacement/` が置換コマンドであり、 **アドレスとは異なり `\` なしでデリミタを変更できる。**

コマンド `s/regexp/replacement/` もアドレスと組み合わせて利用可能で、 正規表現アドレスと組み合わせると次のようになる。

```sh
$ cat input.txt | sed -e '/regexp1/s/regexp2/replacement/'
```

`/regexp1/` 部分はアドレスで、`/regexp2/` はコマンドの一部なので、それぞれデリミタを変えようとすると次のようになる。

```sh
$ cat input.txt | sed -e '\%regexp1%s@regexp2@replacement@'
```

## 参考
- https://www.gnu.org/software/sed/manual/html_node/sed-script-overview.html#sed-script-overview
- https://www.gnu.org/software/sed/manual/html_node/Addresses.html
- https://www.gnu.org/software/sed/manual/html_node/The-_0022s_0022-Command.html#The-_0022s_0022-Command
はじめてのPython3 ~入門編復習の巻~

# はじめに
　この記事はPython3を学ぶにあたって、[paiza入門編](https://paiza.jp/works/python3/primer)にて学んだ基本的なことを個人的に復習するための記事です。

### 修正
- 「Python3 で utf-8 なら coding 指定は不要」という内容を学ばせていただきました。<br>すべてのブロックから # coding: utf-8 を削除しました。(2020/07/24) 
　　　　　　　

## HTMLを出力する

 print("hello world")のような文字列の中にHTMLで使われる p などのタグを入れるとHTMLに表示される。

```
# 見やすさを考慮して、ここでは見出し5(h5)を扱っている。

print("<h5>hello world</h5>")
print("<p>世界のみなさん、")
print("<b>こんばんは</b></p>") # bタグ...太字で表示
```

#### ↓出力結果(text)
```
<h5>hello world</h5>
<p>世界のみなさん、
<b>こんばんは</b></p>
```
※ pythonのprint関数には<b>行末に改行コードを挿入する機能が備わっている</b>。

#### ↓出力結果（HTML ※イメージ)
<h5>hello world</h5>
<p>世界のみなさん、
<b>こんばんは</b></p>

※ 見出しの部分は強制的に改行される
※ pタグ周辺に関して、は br タグがないため、連続して表示される。


### 複数行を取り扱う
シングルクォーテーション3つで囲む。

```
print('''<h5>hello world</h5>
<p>世界の皆さん、
<b>こんにちは</b></p>''')
```

※ 出力結果は上記同様

### textで改行したくない場合
```
# ①文字列をカンマ(,)で区切る
print("<h5>hello world</h5>","<p>世界の皆さん、","<b>こんにちは</b></p>")

# ②文字列の最後に「, end=""」をつける。
print("<h1>hello world</h1>", end="")
print("<p>世界の皆さん、", end="")
print("<b>こんにちは</b></p>", end="")
```

#### ↓出力結果(text)
```
# ①の場合、文字列はスペースで区切られる。
<h5>hello world</h5> <p>世界の皆さん、 <b>こんにちは</b></p>

# ②の場合、文字列は区切られない
<h1>hello world</h1><p>世界の皆さん、<b>こんにちは</b></p>

# ②の時、「end="%"」など""の間に記号を入れるとその記号が間に入る。
<h1>hello world</h1>%<p>世界の皆さん、%<b>こんにちは</b></p>%
```

#### ↓出力結果（HTML ※イメージ)
<h5>hello world</h5>
<p>世界のみなさん、
<b>こんばんは</b></p>
---

#### ②で「end="%"」を含んだ場合
<h5>hello world</h5>
%
<p>世界の皆さん、%<b>こんにちは</b></p>
%

---

# おまけ
コメントアウトに関して

```
print("コメントではありません")
# print("ここはコメントアウトとなります")

# シングルクォーテーション3つで囲むと、その部分はすべてコメントアウト。
print("コメントではありません")
'''
print("ここからコメントアウト")
print("表示されない")
print("ここまでコメントアウト")
'''

```
SwiftUIでpreview modeかどうかの判定方法

SwiftUIでソースを書いてると、
サーバー通信ができないなどで右側のCanvas(Preview)が表示できなくなるときに
以下のif文が便利。

```swift
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1"{
```



実際はこんな感じで利用しました。↓

```swift
struct ContentView: View {
    var body: some View {
        Text("Hello, World!")
		
		.onAppear(){
			if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] != "1"{
				//サーバー通信の処理
			}
		}
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

```
VeeValidate3で別フィールドの値をvalidation時に参照する

# 概要
Vue.jsで入力項目のvalidationを行う際、VeeValidateのライブラリを使うケースが多いと思います。今回はそのVeeValidate3系のバージョンで、パスワードの再入力時の同一チェックのように、別フィールドを参照してvalidationしたい場合の実装方法について書いてみます。

# 前提など

- 下記の項で紹介する実装サンプルは、Nuxt.js前提とします（Vue.jsで使うのと大差ないとは思いますが念のため・・）。Nuxt.jsでのVeeValidateの使用方法については、[【Nuxt.js】vee-validate を使って、フォームのバリデーション実装をする](https://qiita.com/katu_/items/bdba476a93fa49efde9d)を参照してください。
- 実装サンプルは、よくあるパスワード再入力の例で記載しています。
- 公式ドキュメントについて[Cross Field Validation](https://logaretm.github.io/vee-validate/advanced/cross-field-validation.html)を参照しています。ただ、このページはバージョンが変わったら更新されると思うので、あくまで2020年7月時点での内容を参考にしている、という前提でご認識ください。
- VeeValidate2系のバージョンについては、[VeeValidateで複数のフィールドにバリデーションをかけるやり方](https://qiita.com/_Keitaro_/items/c06210d69f8c8382dfab)の内容が参考になると思います。

# 実装サンプル

- pluginに設定している`vee-validate.js`の内容は以下です。今回はパスワードの再入力欄のほうにカスタムのvalidationを設定しています。必要箇所のみ抜粋して記載しています。

```vee-validate.js
extend("passwordReInput", {
  params: ["target"],
  validate(value, { target }) {
    return value === target;
  },
  message: "上のパスワード欄と同様のものを入力して下さい"
});
```

- component側での実装例は以下です。rulesで参照するフィールドのValidationProviderのnameに頭に「@」を付与して、別フィールドを参照しています。なお、以下のサンプルはtemplate部分のみとし、エラーメッセージの表示部分についてのロジックは記載を割愛してます。（errorsを別componentに渡して表示しています）

```PasswordSample.vue
<template>
  <div>
    <validation-observer v-slot="{ invalid }">
      <div class="form-group">
        <label for="password">パスワード</label>
        <validation-provider v-slot="{ errors }" rules="required|min:6" name="password">
          <input type="password" class="form-control" v-model="password" />
          <ErrorMessageComponent :errors="errors" />
        </validation-provider>
      </div>
      <div class="form-group">
        <label for="passwordReInput">パスワード再入力</label>
        <validation-provider v-slot="{ errors }" rules="passwordReInput:@password" name="passwordReInput">
          <input type="password" class="form-control" v-model="passwordReInput" />
          <ErrorMessageComponent :errors="errors" />
        </validation-provider>
      </div>
    </validation-observer>
  </div>
</template>

```

- 表示はこんな風になるイメージです。（エラーメッセージ部分の表示はbootstrapを使用）
<img width="1034" alt="スクリーンショット 2020-07-21 5.01.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32098/478c7a0e-1417-2e6c-e7f1-274b6f8818db.png">
【Rails】devise 導入方法

# deviseとは
- Railsで作成したアプリケーションへ簡単に認証機能を実装することができるgem（ライブラリ）の一つ
- ログイン、サインアップなどのログイン機能が作成出来る

## 導入方法

### ①Gemfileに追加
```ruby:Gemfile
gem 'devise'
```
### ② bundle install を実行
```terminal:ターミナル
$ bundle install
```

### ③設定ファイルを作成
```terminal:ターミナル
$ rails g devise:install
```

```ruby:新規作成されるファイル
config/initializers/devise.rb
config/locales/devise.en.yml
```

### ④deviseの機能を持ったUserモデルを作成
```terminal:ターミナル
$ rails g devise user
```

```ruby:新規作成されるファイル
app/models/user.rb
db/migrate/20XXXXXXXXXXXX_devise_create_users.rb
test/fixtures/users.yml
test/models/user_test.rb
```

### ⑤deviseのviewファイルを作成
```terminal:ターミナル
$ rails g devise:views
```
```ruby:新規作成されるファイル
app/views/devise #以下のディレクトリにあるビューファイル各種
```

これで、deviseの導入が完了します
Apache ローカルネットワーク内限定でIPでアクセスできる様にする

## 目的

- ローカルネットワーク内限定でApacheが立っているマシン以外からもWebページを表示できる様にする方法をまとめる

## 実施環境

- ハードウェア環境（クライアント側）

| 項目 | 情報 |
| --- | --- |
| OS | macOS Catalina(10.15.5) |
| ハードウェア | MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports) |
| プロセッサ | 2 GHz クアッドコアIntel Core i5 |
| メモリ | 32 GB 3733 MHz LPDDR4 |
| グラフィックス | Intel Iris Plus Graphics 1536 MB |

- ハードウェア環境（サーバ側）

| 項目 | 情報 |
| --- | --- |
| OS | CentOS 7 (7.8.2003) |
| ハードウェア | Dell Studio 1537 |
| プロセッサ | Intel(R) Core(TM)2 Duo CPU     P8400  @ 2.26GHz |
| メモリ | 4 GB DDR3 |
| グラフィックス | 不明 |

- ソフトウェア環境

| 項目 | 情報 |
| --- | --- |
| Apacheバージョン | 2.4.6 (CentOS) |

## 前提条件

- Apacheがインストール済みでサーバ側のPCのブラウザにて([http://localhost/index.html](http://localhost/index.html)などにアクセスすることにより)ドキュメントルートにあるファイルが確認できること。

## 前提情報

- 下記説明で実行するコマンドは特に記載がない場合サーバPCにssh接続を行い実行する。

## 読後感

- サーバ側のPCのブラウザにて([http://localhost/index.html](http://localhost/index.html)などにアクセスすることにより)表示できていたファイルをローカルネットワーク 内なら`http://サーバPCのIP:ポート/index.html`で表示可能になる。

## 概要

1. サーバマシンのIPの確認
1. Apacheの設定変更
1. 確認 

## 詳細

1. サーバマシンのIPの確認
    1. 下記コマンドを実行してネットワーク系の情報を確認する。

        ```terminal
        $ ifconfig
        ```
    1. 下記の出力例の矢印部分を確認してサーバPCのIPアドレスを確認する。（inetの横がIPアドレスである。）

        ![ようこそ_—_FA.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306417/6413a488-69c0-5d3d-47ec-f6774fa0524e.png)

1. Apacheの設定変更
    1. 下記コマンドを実行してApacheの設定ファイルを開く。

        ```terminal
        $ sudo vi /etc/httpd/conf/httpd.conf
        ```
    1. 開いたファイルの「Listen 80」の記載がある部分を探す。
    1. 下記の様に編集する。

        ```/etc/httpd/conf/httpd.conf
        #
        # Listen: Allows you to bind Apache to specific IP addresses and/or
        # ports, instead of the default. See also the <VirtualHost>
        # directive.
        #
        # Change this to Listen on specific IP addresses as shown below to
        # prevent Apache from glomming onto all bound IP addresses.
        #
        #Listen 12.34.56.78:80
        # 下記をコメントアウト
        #Listen 80
        # 下記を追記
        Listen 先に確認したサーバPCのIPアドレス:80
        ```

1. ポートの解放
    1. 下記コマンドを実行してhttp通信のデフォルトポートである80番を解放する。

        ```terminal
        $ sudo firewall-cmd --zone=public --add-service=http --permanent
        ```
    1. 後々のことを見越して下記コマンドを実行してhttps通信のデフォルトポートである443番を解放する。
        
        ```terminal
        $ sudo firewall-cmd --zone=public --add-service=https --permanent
       ```
    1. 下記コマンドを実行して設定を反映する。

        ```terminal
        $ sudo firewall-cmd --reload
        ```
    1. 下記コマンドを実行して設定を確認する。

        ```terminal
        $ sudo firewall-cmd --list-all
        ```
    1. 「services」の欄にhttpとhttpsが記載されていることを確認する。

        

    1. 下記コマンドを実行してhttpdを再起動する。

        ```terminal
        $ sudo service httpd restart
        ```

1. 確認
    1. ブラウザにて下記のURLでlocalhostで表示できていた内容が表示できることを確認する。
        - http://先に確認したサーバPCのIPアドレス:80/index.html
Rust製の高速ターミナル「Alacritty」とhammerspoonを組み合わせてiTerm2を超える爆速環境構築 on macOS

# Alacrittyとは

Rust製のターミナルで、OpenGLを使ったGPUレンダリングを用いて描画するため、とても高速なターミナルです。

> https://github.com/alacritty/alacritty

今回はAlacrittyの導入とhammerspoonというhotkeyを設定できるツールを用いてiTerm2の強力機能HotKeyも模倣した高速ターミナルの設定をしていきます。
ちなみに、このAlacrittyはtmuxを使ったカーソル移動をほぼ必須としているため、ターミナルの分割機能等は存在しません。（iTerm2でいう Command + V等）

## メリット

- 早い、特に大きなファイルをvimで開くとき明らかに速度が違うしj,kでのカーソル移動がサクサク
- ターミナルの設定をコードで管理できるので、dotfilesの管理が捗る
- tmuxとの親和性が高い

## デメリット

- iTerm2と比べるとhammerspoon + alacrittyの組み合わせはワンテンポ開くのが遅いかも
- 日本語入力がインラインで行えない（現バージョンではまだ、エンターを押すまで入力されない）

# 導入

## ソフトウェアのインストール

まずは必要なものをインストールしましょう。どちらもbrewで公開されているのでこちらからインストールします。

```sh
$ brew cask install hammerspoon alacritty
```

インストール後にApplicationから起動するとセキュリティの警告が出ると思うので、「環境設定」→「セキュリティとプライバシー」から許可して開いてください。
また、hammerspoonは「環境設定」→「アクセシビリティ」にチェックを入れておいてください。

*今回はtmuxとvimの環境構築については触れませんが、ネット上に素晴らしいconfigファイルがたくさん転がっているので自分のconfigを育てていってください。

## Hotkeyの設定

次にhammerspoonでhotkeyを設定して開けるようにしていきます。
設定ファイルは`$HOME/.hammerspoon/init.lua`に書きます。

僕は`Ctrl+T`にバインドを設定しています。お好みで1行目をいじってください。

```lua
hs.hotkey.bind({"ctrl"}, "t", function()
  local alacritty = hs.application.find('alacritty')
  if alacritty:isFrontmost() then
    alacritty:hide()
  else
    hs.application.launchOrFocus("/Applications/Alacritty.app")
  end
end)
```

## alacrittyの設定ファイル

1. `$XDG_CONFIG_HOME/alacritty/alacritty.yml`
2. `$XDG_CONFIG_HOME/alacritty.yml`
3. `$HOME/.config/alacritty/alacritty.yml`
4. `$HOME/.alacritty.yml`


設定ファイルは上記の優先順位で読み込まれます。
ファイルを作成したら以下の内容を書きます。

```yml
# tmuxを起動
shell:
  program: /usr/local/bin/zsh
  args:
    - -l
    - -c
    - "tmux attach || tmux"

window:
  decolations: buttonless # mac only
  startup_mode: SimpleFullscreen # mac only

# font設定
font:
  size: 12.5
  normal:
    family: HackGen
  bold:
    family: HackGen
  italic:
    family: HackGen

key_bindings:
  - { key: Q, mods: Control, chars: "\x11" } # 暫定対応 masterブランチでは解決済みらしい
```

上から順に説明します。
`shell`では、使用するshellと`tmux`での起動を行っています。ターミナルを立ち上げるたびに`tmux`コマンドを叩かなくていいので幸せになれます。

`window`ではフルスクリーンの設定をしています。
僕はターミナル以外のボタンやバーは表示されないようにしたいのでこのような設定になりました。

`font`では文字通り`font-family`の設定と`font-size`の設定ができます。

`key-binds`ですがここに書いているものはバグを回避するためのキーバインドです。tmuxのprefixを`Ctrl+Q`にしているのですが、なぜか2回押さないと反応しないバグがあるらしく、キーバインドで回避しています。
masterブランチでは解決しているらしいので、気が向いた方はbrewでなくそちらから入れてみたらいいかもしれません。


# さいごに

これまではiTerm2 + nvim + tmuxの組み合わせで開発していましたが、alacrittyに乗り換えようと思います。
ターミナル自体が爆速なのもそうですが、macOSだけでなくlinuxとwindowsでも使えるのでdotfilesに保管してそのまま使えるのはとても大きいですね。
大学生が1週間でFlutterアプリを学んでリリースした過程(5日目)

こんにちはシオンです。


昨日デザインがやっと決まり、コードを書き始めたところまで行きました。
ここまで来ればあとはコードを勉強しながら決めたデザインのものを形にしていくだけです。
残す課題は時間だけ、期限までに終わらせるというのが今回のチャレンジで一番大事になってくるのでここまできたら何がなんでも間に合わせます。


プログラミングの進捗としては昨日FlutterでHelloWorldと表示することに成功しました。このプログラミングを学ぶ人が絶対に最初に通るLv１の状態から今日あすの2日でコードを書き切って、ラスト1日でリリースしてみせます。

少し話は変わりますが、qiitaではこういう投稿はあまり良くないようですね。
qiitaについて深く理解せずブログのような投稿をしてしまいました。この一連の投稿が終わったら改めたいと思います。

ではやっていきます。

# ■まず画面をデザイン通りに構成する

コードを書き切ると言っても、本当にFlutterに対して無知なので闇雲に書いて行っても終わりが見えてきそうにないです。


ちなみにどのくらい無知なのかというと
現在私が持っているFlutterの知識は、
Flutterとは「フルッター」ではなく「フラッター」と読み、表記はアルファベットで構成されている。また、今日の私の朝ごはんは食パンにバターを塗ったトーストであるが、私が持つFlutterの知識と私の今日の朝食については全く関係がない。


書くことがなさすぎて今日の朝食を紹介するしかないくらい無知ということです。よろしくお願いいたします。


ということで、一旦画面遷移などの処理は後回しにしてデザインの画面を形だけ再現してそのあとにカウントアップだったりの処理を書いていきたいとおもいます。


ちなみにデザインはこれです。（昨日のです。）

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676265/88cd3496-fc06-4e42-6952-90e263336db2.png)


この画面を作っていく上で必要になってくるのは構成部品とそのレイアウトの知識です。
今回必要になってくる部品としては
**・テキスト**
**・テキスト入力フォーム**
**・ボタン**
**・画像**
この4つの部品があれば大丈夫そうです。


では次にFlutterでのレイアウトの仕方を学んでいきます。
昨日Flutterでプログラミングしていく上で重要になってくるのがウィジェットというものだというのを学びました。
おそらくこのウィジェットの中に今回使う、画像だとかボタンだとかを持ったウィジェットがいるはずなので、まずはレイアウトは考えず必要な部品を
表示してみます。


また3画面目から先はシンプルな構造ですぐに構成できると思うので、これは処理を書きながらにしていきます。


では1画面目と2画面目をやっていきます。




#■1画面目と2画面目の外観を実装
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676265/7a5e0676-e77b-5ba4-3a4d-525b37227de6.png)



１画面目はこんな感じに。なかなか時間がかかりました。
初めての言語でコードを書くときは勝手がわからない＋関数やクラスの名前がわからない、で苦戦するのですが、その分うまく行ったときの「できた！！」っていう快感がたまらないですね。


新しくゲームを始めてレベル1からスタートしている感じがしてすごく楽しいです。早くこの一週間チャレンジというチュートリアルをクリアして冒険に出かけます。


続いて2画面目。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676265/4341791c-b690-e6cf-b31e-03547fca1520.png)





2画面目は内容入力のフォームの高さ調節が思うようにいかずこんな感じになってしまいました。
調べながらやっているのですが、まだまだFlutter自体が新しい分日本語記事が少ない印象ですかね。それでもわかりやすコードや使い方を記事にしてくださっている方が何人もいて助かりました。（本当にありがとうございます。）


まだ少ししか触ってませんが、Flutterめちゃくちゃいいです。
この2画面を作っただけでもそのコードの書きやすさにびっくりしています。
まだ記事が少ないので初めてプログラミングを学ぶ人にとっては多少難しいかもしれませんが、何かしらやったことがある人にはお勧めしたいです。

#■まとめ


あとはこの画面に処理を記述していけばなんとか形にはなりそうです。
処理も一通り見たのですが、これくらいの画面遷移とカウントアップだけならすぐにできそうなので明日一気に仕上げてしまいます。

なんとなく形になりそうな気配がしてきました。

でも残すは明日と明後日のみ。。。
果たして結果は完成するのかしないのか。

残り2日間やっていきます。