Firebaseで開発する

1. Firebaseでプロジェクトを作成
プロジェクト名: typescript-hpscript
google analytics: off

2.Realtime database
create database
location: United States(us-central)
start in test mode

edit rule

{
  "rules": {
    ".read": true,
    ".write": true,
    "boards": {
      ".indexOn":["posted"]
    }
  }
}

index.html

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
	<script src="main.js"></script>
</head>
<body>
	<h1 class="bg-primary text-white p-2">Board</h1>
	<div class="container">
		<h2>send message:</h2>
		<div class="alert alert-primary">
			<div>
				<label>your nickname:</label>
				<input type="text" id="nickname" class="form-control form-control-sm"/>
			</div>
			<div>
				<label>message:</label>
				<input type="text" class="form-control" id="message"/>
			</div>
			<button class="btn btn-primary mt-2" id="btn">
			fetch</button>
			</div>
			<table class="table mb-4" id="table"></table>
			<div class="text-center">
				<button class="btn btn-danger mb-4" id="delete">delete all</button></div>
	</div>
</body>
</html>

index.ts

let nickname: HTMLInputElement
let message:HTMLInputElement
let table:HTMLTableElement
const url = ‘https://typescript-hpscript.firbaseio.com/boards.json’

function doAction(){
const data = {
nickname: nickname.value,
message: message.value,
posted: new Date().getTime()
}
sendData(url, data)
}

function doDelete():void {
fetch(url, {
method: ‘DELETE’
}).then(res=> {
console.log(res.statusText)
getData(url)
})
}

function sendData(url:string, data:object){
fetch(url, {
method: ‘POST’,
mode: ‘cors’,
headers: {
‘Content-Type’:’application/json’
},
body: JSON.stringify(data)
}).then(res=>{
console.log(res.statusText)
getData(url)
})
}

function getData(url:string){
fetch(url).then(res=>res.json()).then(re=> {
let result = `

Message Nickname posted `
let tb = ”
for(let ky in re){
let item = re[ky]
tb = ‘

‘ + item[‘message’] + ‘ ‘
+ item[‘nickname’] + ‘ ‘
+ new Date(item[‘posted’]).toLocaleString()
+ ‘

‘ + tb
}
result += tb + ‘


table.innerHTML = result
})
}

window.addEventListener(‘load’, ()=> {
message = document.querySelector(‘#message’)
nickname = document.querySelector(‘#nickname’)
table = document.querySelector(‘#table’)

const btn : HTMLButtonElement = document.querySelector(‘#btn’)
btn.onclick = doAction
const del :HTMLButtonElement =
document.querySelector(‘#delete’)
del.onclick = doDelete
getData(url)
})
[/code]

ちょっと上手くいかんな

[TypeScript] 重要機能

### 名前空間
– exportで外部から使えるようにする

namespace myapp {
    namespace foundation {
        export interface printable {
            print():void
        }

        export interface stringable {
            getString():string
        }
    }

    export type Person = {
        name:string
        age:number
    }

    export class MyData implements
        foundation.printable,
        foundation.stringable {
            people:Person[] = []

            constructor(){}

            add(nm:string, ag:number){
                this.people.push({name:nm, age:ag})
            }

            print():void {
                console.log('*** mydata ***\n' + this.getString())
            }
            getString():string {
                let res = '[\n'
                for (let item of this.people){
                    res += ' "' +item.name+ ' (' + item.age + ')",\n'
                }
                return res + ']'
            }
        }
}

const mydata = new myapp.MyData()
mydata.add('taro', 39)
mydata.add('hanako', 28)
mydata.add('sachiko', 17)
mydata.add('jiro', 6)
mydata.print()

### モジュールとプログラムの分割
外部公開: export element
読み込み: import (element) from resources

src/lib.ts

export interface printable {
    print():void
}

export interface stringable {
    getString():string
}

export type Person = {
    name:string
    age:number
}

export class MyData implements printable, stringable {
        people:Person[] = []

        constructor(){}

        add(nm:string, ag:number){
            this.people.push({name:nm, age:ag})
        }

        print():void {
            console.log('*** mydata ***\n' + this.getString())
        }
        getString():string {
            let res = '[\n'
            for (let item of this.people){
                res += ' "' +item.name+ ' (' + item.age + ')",\n'
            }
            return res + ']'
        }
    }

index.ts

import { MyData } from './lib'

const mydata = new MyData()
mydata.add('taro', 39)
mydata.add('hanako', 28)
mydata.add('sachiko', 17)
mydata.add('jiro', 6)
mydata.print()

$ npm run build
$ node dist/main.js
*** mydata ***
[
“taro (39)”,
“hanako (28)”,
“sachiko (17)”,
“jiro (6)”,
]

### ミックスイン
複数のクラスを継承して機能を引き継ぐ

function applyMixins(derivedCtor: any, constructors: any[]){
    constructors.forEach((baseCtor) => {
        Object.getOwnPropertyNames(baseCtor.prototype).forEach((name) => {
            Object.defineProperty(
                derivedCtor.prototype,
                name,
                Object.getOwnPropertyDescriptor(baseCtor.prototype, name) || Object.create(null)
            );
        });
    });
}

class Person {
    name:string = ''
    title:string = ''

    setPerson(nm:string, tt:string):void {
        this.name = nm
        this.title = tt
    }
}

class Pet {
    kind:string = ''
    age:number = 0

    setPet(k:string, ag:number):void {
        this.kind = k
        this.age = ag
    }
}

class Me {
    print():void {
        console.log(this.name + ' (' + this.age + ')\n'
            + '"' + this.title + '". pet is ' + this.kind + '!')
    }
}

interface Me extends Person, Pet {}
applyMixins(Me, [Person,Pet])

const me = new Me()
me.setPerson('taro', 'designer')
me.setPet('cat', 2)
me.print()

### 非同期処理とasync/await
実行したら後はどれがいつ終わるかわからない

function action(dt:number){
    return new Promise(resolve=>{
        setTimeout(()=> {
            console.log('fished promise!')
            resolve("delay:" + dt)
        }, dt)
    })
}

action(2000).then(res=>console.log(res))
action(1000).then(res=>console.log(res))
action(500).then(res=>console.log(res))

awaitは非同期でも処理が完了するまで待つ

async function doit(){
    let re1 = await action(2000)
    console.log(re1)
    let re2 = await action(1000)
    console.log(re2)
    let re3 = await action(500)
    console.log(re3)
}
doit()

### ネットワークアクセス
fetch().then(response=> hoge) と書く

function getData(url:string){
    fetch(url).then(res=>res.text()).then(re=>{
        console.log(re)
    })
}

const url = 'https://tuyano-dummy-data.firebaseio.com/message.json'
getData(url)

firebaseはCORSを解放しているが、解放していないサイトも多い

function getData(url:string){
    fetch(url).then(res=>res.json()).then(re=>{
        for (let item of re){
            console.log(item)
        }
    })
}

const url = 'https://tuyano-dummy-data.firebaseio.com/sample_data.json'
getData(url)

### ネットワークに同期アクセス
アクセスを非同期化する

async function getData(url:string){
    const response = await fetch(url)
    const result = await response.json()
    for(let item of result){
        console.log(JSON.stringify(item))
    }
}

const url = 'https://tuyano-dummy-data.firebaseio.com/sample_data.json'
getData(url)

### POST送信

async function getData(url:string, obj:object){
    await fetch(url, {
        method: 'POST',
        mode: 'cors',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(obj)
    })
    const response = await fetch(url)
    const result = await response.json()
    console.log(result)
}

const url = "https://tuyano-dummy-data.firebaseio.com/sample_data.json"

const obj = {
    title: 'hello!',
    message: 'This is sample message!'
}

getData(url, obj)

なるほど、TypescriptというよりJavaScriptでも重要なことやな

[TypeScript] 型

### マップ型
stringのキーのマップ型

type stringArray = {
    [key in string]: string
}

const data1:stringArray = {
    'start': 'start',
    'middle': 'middle',
    'end': 'end'
}

data1['finish'] = '**end**'
data1[100] = 'ok'
console.log(data1)

enum

enum human {name='name', mail='mail'}

type HumanMap = {
    [key in human]: string
}

const taro:HumanMap = {
    name: 'taro',
    mail: 'taro@yamada'
}
console.log(taro)
const hana:HumanMap = {
    name: 'hanako',
    mail: 'hanak@gmail.com'
}
console.log(hana)

ユニオン型

class Student {
    name:string
    school:string
    grade:number

    constructor(nm:string, sc:string, gr:number){
        this.name = nm
        this.school = sc
        this.grade = gr
    }

    print():void{
        console.log('<< ' + this.name + ',' +
            this.school + ':' + this.grade + ' >>')
    }
}
class Employee {
    name: string
    title: string
    department:string

    constructor(nm:string, tt:string, dp:string){
        this.name = nm
        this.title = tt
        this.department =dp
    }

    print():void {
        console.log(this.name + '[' + this.title + 
            ',' + this.department + ']')
    }
}

type People = Student | Employee

const taro:People = new Student('taro', 'high school', 3)
const hana:People = new Employee('hanako', 'president', 'sales')
const sachi:People = new Student('schiko', 'jinir-high school', 1)
const jiro:People = new Employee('jiro', 'director', 'labo')

const data:People[] = [taro, hana, sachi, jiro]
for(let item of data){
    item.print()
}

ユニオン型を個別に処理

class Human {
    data: People[] = []

    add(item:People):void {
        this.data.push(item)
    }
    print():void {
        for(let item of this.data){
            let ob
            switch(item.constructor.name){
                case 'Student':
                ob = item as Student
                console.log(ob.name + ', ' + ob.school
                    + '(' + ob.grade + ')')
                break
                case 'Employee':
                ob = item as Employee
                console.log(ob.name + ':' + ob.title
                    + ':' + ob.department)
                break
                default:
                console.log('cannot print.')
            }
        }
    }
}

### テンプレートリテラル
${}で埋め込む

const data = [10, 20, 30]
const msg = `data is [${data}]`
console.log(msg)
const result = `total is ${data[0]+data[1]+data[2]} !`
console.log(result)

### テンプレートリテラル型

type val_name = "sample"|"private"|"public"
type data_type = `${val_name}_data`
type prop_type = `${val_name}_property`
type method_type = `${val_name}_method`

const s:data_type = "sample_data"
const t:prop_type = "public_property"
const u:method_type = "private_method"
const v:data_type = "personal_data"

### レコード型

type prop_name = 'name' | 'mail' | 'age'
type Person = Record<prop_name, string|number>

const taro:Person = {
    name: 'taro',
    mail:'taro@gmail.com',
    age: 39
}

console.log(taro)

### Pick型

type person_data = {
    name:string,
    mail:string,
    address:string,
    age:number
}

type person_keys = 'name' | 'age'
type human_keys = 'name' | 'mail' | 'address'

type person = Pick<person_data, person_keys>
type human = Pick<person_data, human_keys>

const taro:person = {
    name: 'taro',
    age: 39
}
const hana:human = {
    name: 'hanako',
    mail: 'hanako@gmail.com',
    address: 'chiba'
}
console.log(taro)
console.log(hana)

### イテレータ

class MyData<T> {
    data:T[ ] = []

    constructor(...data: T[]){
        this.data = data
    }

    add(val:T) {
        this.data.push(val)
    }

    [Symbol.iterator](){
        let pos = 0;
        let items = this.data;

        return {
            next(): IteratorResult<T>{
                if(pos < items.length) {
                    return {
                        done: false,
                        value: items[pos++]
                    }
                } else {
                    return {
                        done: true,
                        value: null
                    }
                }
            }
        }
    }
}
const data = new MyData<string>('one','two','three')

for(let item of data){
    console.log(item)
}

OKなのかNGなのかすらわからん

[TypeScript] メモアプリ

index.html

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
	<script src="main.js"></script>
</head>
<body>
	<h1 class="bg-primary text-white p-2">Memo page</h1>
	<div class="container">
		<p class="h5">type message:</p>
		<div class="alert alert-primary">
			<input type="text" class="form-control" id="message">
			<button class="btn btn-primary mt-2" id="btn">
			Save</button>
		</div>
		<table class="table" id="table"></table>
		<div class="text-center">
			<button class="btn btn-danger mt-4" id="initial">
				Initialize
			</button>
		</div>
	</div>
</body>
</html>

index.ts

let table:HTMLTableElement
let message:HTMLInputElement

function showTable(html:string){
	table.innerHTML = html
}

function doAction(){
	const msg = message.value
	memo.add({message:msg, date:new Date()})
	memo.save()
	memo.load()
	showTable(memo.getHtml())
}

function doInitial(){
	memo.data = []
	memo.save()
	memo.load()
	message.value = ''
	showTable(memo.getHtml())
}

type Memo = {
	message:string,
	date:Date
}

class MemoData {
	data:Memo[] = []

	add(mm:Memo):void {
		this.data.unshift(mm)
	}

	save():void {
		localStorage.setItem('memo_data', JSON.stringify(this.data))
	}
	load():void{
		const readed = JSON.parse(localStorage.getItem('memo_data'))
		this.data = readed ? readed : []
	}

	getHtml():string {
		let html = '<thead><th>memo</th><th>data</th></thead><tbody>'
		for(let item of this.data){
			html += '<tr><td>' + item.message + '</td><td>'
				+ item.date.toLocaleString() + '</td></tr>'
		}
		return html + '</tbody>'
	}
}

const memo = new MemoData()

window.addEventListener('load', ()=> {
	table = document.querySelector('#table')
	message = document.querySelector('#message')
	document.querySelector('#btn').addEventListener('click', doAction)
	document.querySelector('#inital').addEventListener('click', doInitial)
	memo.load()
	showTable(memo.getHtml())
})

これなんだよな やりたいこと

[TypeScript] クラス2

### インターフェイス

interface Human {
    name:string
    print():void
}

class Person implements Human {
    name:string = 'no-name'
    mail:string
    age:number

    constructor(name:string, mail:string = 'no-mail', age:number = -1){
        this.name = name
        this.mail = mail
        this.age = age
    }

    print():void {
        console.log(this.name + '(' + this.mail + ',' + this.age + ')')
    }
}

class Student implements Human {
    name:string = 'no-name'
    school?:School
    grade?:number

    constructor(name:string,school?:School, grade?:number){
        this.name = name
        this.school = school
        this.grade = grade
    }

    print():void {
        let gd:string = this.grade ? String(this.grade) : '-'
        console.log(this.name + '(' + this.school + ' school: ' + gd + ' grade)') 
    }
}

const taro:Person = new Person('taro', 'taro@yamada', 39)
const hanako:Student = new Student('hanako', School.high, 39)
const sachiko:Person = new Person('sachiko')
const jiro:Student = new Student('jiro')

const data:Human[] = [taro, hanako, sachiko, jiro]

for(let item of data){
    item.print()
}

### インターフェイスの継承

interface People extends Human {
    birth:Date
}

class Employee implements People {
    name:string = 'no-name'
    company:string = ''
    birth:Date = new Date()

    constructor(nm:string, cm:string, bth:Date){
        this.name = nm
        this.company = cm
        this.birth = bth
    }

    print():void {
        console.log(this.name + ' [' + this.company + ']')
    }
}

const ichiro = new Employee('ichiro',
    'Baseball Inc.', new Date('1982/10/10'))
ichiro.print()

### 静的メンバー

class StaticHuman {
    static fullname:string
    static age:number
    
    static set(nm:string, ag:number):void {
        this.fullname = nm
        this.age = ag
    }

    static print():void {
        console.log(this.fullname + '(' + this.age + ')')
    }
}

StaticHuman.set('taro',39)
StaticHuman.print()
StaticHuman.set('hanako',29)
StaticHuman.print()

### パラメータープロパティ

class Human {
    constructor(readonly name:string, readonly age:number){

    }

    print():void {
        console.log(this.name + '(' + this.age + ')')
    }
}

const taro = new Human('taro', 39)
taro.print()
const hana = new Human('hanako', 28)
hana.print()

### 総称型

class Data<T> {
    data?:T[]

    constructor(...item:T[]){
        this.data = item
    }

    print():void {
        if(this.data) {
            for(let item of this.data){
                console.log(item)
            }
        } else {
            console.log('no data...')
        }
    }
}

const data1 = new Data<string>('one','two','three')
const data2 = new Data<number>(123,456,78,90)
data1.print()
data2.print()

### ユーティリティ型
Readonly, Required, Partial

type Human = {
    name:string
    mail?:string
    age?:number
}

class Person {
    human:Required<Human>

    constructor(nm:string, ml:string, ag:number){
        this.human = {name:nm, mail:ml, age:ag}
    }

    print():void {
        console.log(this.human.name
            + ' (' + this.human.age + '::'
            + this.human.mail + ')')
    }
}
const taro = new Person('taro', 'taro@yamada', 39)
taro.print()

OK

[TypeScript] クラス1

### クラス

class Person {
    name:string = 'no-name'
    mail?:string
    age?:number
    print():void {
        const ml:string = this.mail ? this.mail : 'no-mail'
        const ag:number = this.age ? this.age : -1
        console.log(this.name + '(' + ml + ',' + ag + ')')
    }
}

const taro = new Person()
taro.name = 'taro'
taro.mail = 'taro@gmail.com'
taro.age = 39
taro.print()

### コンストラクタ

class Person {
    name:string = 'no-name'
    mail?:string
    age?:number

    constructor(name:string, mail:string = 'no-mail', age:number = -1){
        this.name = name
        this.mail = mail
        this.age = age
    }

    print():void {
        console.log(this.name + '(' + this.mail + ',' + this.age + ')')
    }
}

const taro = new Person('taro', 'taro@gmail.com', 39)
const hanako = new Person('hanako', 'hanako@gmail.com')
const sachiko = new Person('sachiko')

taro.print()
hanako.print()
sachiko.print()

### インスタンスのクラスを調べる

console.log(taro instanceof Person === hanako instanceof Person === true)

console.log(taro.constructor.name)
console.log(hanako.constructor.name)
console.log(Person.name)

### クラスの継承
extendsで継承する

enum School {
    junior='junior',
    juniorHigh = 'juniorHigh',
    high = 'high',
    other = 'other'
}

class Student extends Person {
    school?:School
    grade?:number

    constructor(name:string, school:School, grade:number){
        super(name)
        this.school = school
        this.grade = grade
        switch(school){
            case School.junior:
            this.age = 6 + this.grade; break
            case School.juniorHigh:
            this.age = 12 + this.grade; break
            case School.high:
            this.age = 15 + this.grade; break
            default:
            this.age = -1
        }
    }
}

const taro = new Person('taro', 'taro@gmail.com', 39)
const hanako = new Student('hanako', School.high, 2)

taro.print()
hanako.print()

### メソッドのオーバーライド
– 継承しているクラスの中にメソッドを追加する

    print():void {
        let gd:string = this.grade ? String(this.grade) : '-'
        switch(this.grade){
            case 1:gd += 'st'; break
            case 2:gd += 'nd'; break
            case 3:gd += 'rd'; break
            default: gd += 'th'
        }
        console.log(this.name + '(' + this.school + ' school: ' + gd + ' grade)')
    }

### アクセス修飾子
public: 外部から自由にアクセス
protected: クラスおよびクラスを継承したサブクラス
private: クラス内のみ

    protected name:string = 'no-name'
    private mail:string
    public age:number

### setterとgetter

class Student extends Person {
    school?:School
    private grade_num:number = -1
    get gradeN():number {
        return this.grade_num
    }
    set gradeN(n:number){
        this.grade_num = n
        this.grade = String(n)
    }
    private gr_str:string = ''
    get grade(): string {
        return this.gr_str
    }
    private set grade(pr:string){
        let gd = pr
        switch(this.gradeN){
            case 1: gd += 'st'; break
            case 2: gd += 'nd'; break
            case 3: gd += 'rd'; break
            default: gd += 'th'
        }
        this.gr_str = gd
    }

    constructor(name:string, school:School, grade:number){
        super(name)
        this.school = school
        this.gradeN = grade
    }

    print():void {
        let gd:string = this.grade ? String(this.grade) : '-'
        console.log(this.name + '(' + this.school + ' school: ' + gd + ' grade)')
    }
}

ふむ

[TypeScript] オブジェクト

オブジェクトとは「値と処理をひとまとめに保管し、名前で取り出せるようにしたもの」
プロパティ: オブジェクトの中の値
メソッド: オブジェクトの中の関数

同じプロパティやメソッドを使う場合、this. と書く

const person = {
    name: "taro",
    age: 39,
    print: function(): void {
        console.log(this.name + '('
            + this.age + ')')
    }
}

person.print()
person.name = 'hanako'
person.age = 28
person.print()

### Objectによる生成

const person = Object()
person.name = "taro"
person.age = 39
person.print = function():void {
    console.log(this.name + '('
        + this.age + ')')
}

### ファクトリ関数
ファクトリとは値を作成するもの

function Person(n:string, a:number):
        {name:string, age:number, print:()=>void}{
    return {
        name: n,
        age: a,
        print: function(){
            console.log(this.name +
                '(' + this.age + ')')
        }
    }
}

const taro = Person('taro', 39)
const hana = Person('hanako', 28)
taro.print()
hana.print()

### オブジェクトに引数を通過う

type person = {name:string, age:number}

function setData(ob:person, n:string, a:number):person {
    ob.name = n
    ob.age = a
    return ob
}

const ob1:person = {name:'taro', age:39}
const ob2:person = setData(ob1, 'hanako', 28)

console.log(ob1)
console.log(ob2)

### オブジェクトの分割代入

type person = {name:{first:string, second:string}, age:number}

const ob1:person = {name:{first:'taro', second: 'yamada'}, age:39}
const {name:{first, second}, age} = ob1
console.log(first + "-" + second + '::' + age)

### プロパティのオプションとReadonly

type person = {readonly name:string, mail?:string, age?:number, print:()=>void}

const ob1:person = {
    name: 'taro',
    age: 39,
    print:function():void {
        console.log(this.name + ':' + this.age)
    }
}

const ob2:person = {
    name: 'hanako',
    mail: 'hanako@gmail.com',
    print:function():void {
        console.log(this.name + ':' + this.mail)
    }
}
ob1.print()
ob2.print()

[話者認識] 基礎

話者データを学習し、どの人のデータなのか機械学習で予測する
Libraryにmatplotlib, numpy, scikit-learn, libROSA、
識別にSVM、フーリエ変換、MFCCなどを使う

SVM
L 境界線(直線・曲線)を作り、データがどちら側か判定する
  L 境界線付近をサポートベクトルと呼ぶ

import numpy as np
import matplotlib.pyplot as plt
import random
from sklearn import svm

N = 15
random.seed(11813)
train_X = np.array([[random.randint(0,100), random.randint(0, 100)] for i in range(N)])

for i in range(len(train_X)):
	plt.plot(train_X[i][0], train_X[i][1],'o', color='blue')
	plt.annotate(i, (train_X[i][0], train_X[i][1]), size=20)
plt.savefig('test.jpg',dpi=100)

分類する

train_y = np.array([0 for i in range(N)])
train_y[2] = train_y[3] = train_y[1] = train_y[4] = train_y[5] = train_y[6] = train_y[11] = 1

colors = ['blue','red']
for i in range(len(train_X)):
	plt.plot(train_X[i][0], train_X[i][1],'o', color=colors[train_y[i]])
	plt.annotate(i, (train_X[i][0], train_X[i][1]), size=20)
plt.savefig('test.jpg',dpi=100)
test_X = np.array([[30,60]])

plt.plot(test_X[0][0], test_X[0][1],'x', color="black")
plt.annotate('test', (test_X[0][0], test_X[0][1]), size=20)

plt.savefig('test.jpg',dpi=100)

clf = svm.SVC(gamma=0.0001, C=1)
clf.fit(train_X, train_y)

test_y = clf.predict(test_X)
print(test_y)

なるほど、SVMが何をやってるのかは理解できた。

[TypeScript] コマンドライン引数から緯度・経度から距離を測定したい

$ npm install @turf/distance
$ npm install @turf/helpers

index.ts

import distance from '@turf/distance'
import { point } from '@turf/helpers'

const tokyo = point([139.69198077115493, 35.68978025468156])
const osaka = point([135.51980022509665, 34.6865543538711])
const result = distance(tokyo, osaka, {units: 'kilometers'})
console.log(result)

$ node sample.js
395.1818245563336

これをコマンドライン引数で書くと

import distance from '@turf/distance'
import { point } from '@turf/helpers'

console.log("Node path = " + process.argv[0])
console.log("Script file path = " + process.argv[1])

const startLongitude = Number(process.argv[2])
const startLatitude = Number(process.argv[3])
const destLongitude = Number(process.argv[4])
const destLatitude = Number(process.argv[5])

const start = point([startLongitude, startLatitude])
const dest = point([destLongitude, destLatitude])
const result = distance(start, dest, {units: 'kilometers'})
console.log(result)

これにアロー関数を追加する

const f = (name:string, speed:number): void => {
	let time = result / speed
	console.log("時速" + speed + "km/hの" + name + "だと、" + time + "時間かかります。")
}

f("新幹線", 200)
f("高速バス", 120)

$ node sample.js 139.69198077115493 35.68978025468156 135.51980022509665 34.6865543538711
395.1818245563336
時速200km/hの新幹線だと、1.975909122781668時間かかります。
時速120km/hの高速バスだと、3.29318187130278時間かかります。

process.argvを変数に代入すると冗長になるから直接書いても良さそうだな
高速バスで東京大阪は3.2時間以上かかるから、実際のところ60km/h ってところか。

うむ、書きながら勉強になるな

djangoをherokuにdeployしたい

### Django プロジェクト作成
$ python3 –version
Python 3.8.10
$ pip3 –version
pip 20.0.2 from /usr/lib/python3/dist-packages/pip (python 3.8)
$ sudo apt install python3-django
$ pip3 install dj-database-url
$ django-admin startproject newsproject
$ cd newsproject
$ python3 manage.py startapp newsapp
templatesフォルダ作成
newsproject/settings.py

ALLOWED_HOSTS = ["192.168.34.10"]

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'newsapp',
]

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR, 'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

newsproject/urls.py

from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('newsapp.urls')),
]

newsapp/urls.py

from django.urls import path
from .views import Create, listfunc

urlpatterns = [
	path('', Create.as_view(), name='home'),
	path('list/', listfunc, name='list'),
]

newsapp/views.py

from django.shortcuts import render
from .models import News
from django.views.generic import CreateView
from django.urls import reverse_lazy
import urllib.request
import requests
from bs4 import BeautifulSoup

class Create(CreateView):
	template_name = 'home.html'
	model = News
	fields = ('url'),
	success_url = reverse_lazy('list')

def listfunc(request):
	for post in News.objects.all():
		url = post.url
	list = []
	response = requests.get(url)
	bs = BeautifulSoup(response.text, "html.parser")
	ul_tag = bs.find_all(class_="topicsList_main")
	for tag in ul_tag[0]:
		title = tag.a.getText()
		url2 = tag.a.get("href")
		list.append([title, url2])
	context = {'list': list,}
	return render(request, 'list.html', context)

newsapp/models.py

from django.db import models

class News(models.Model):
	url = models.CharField(max_length=100)

// migration
$ python3 manage.py makemigrations
$ python3 manage.py migrate

templates/base.html

<!doctype html>
<html lang="en">
 <head>
   <!-- Required meta tags -->
   <meta charset="utf-8">
   <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
   <!-- Bootstrap CSS -->
   <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
   <title>Pachi Data</title>
 </head>
 <body>
   {% block header %}
   {% endblock header %}
   {% block content %}
   {% endblock content %}
   <!-- Optional JavaScript -->
   <!-- jQuery first, then Popper.js, then Bootstrap JS -->
   <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
   <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
   <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
 </body>
</html>

templates/home.html
[htmle]
{% extends ‘base.html’ %}

{% block header %}

News

Enter the URL

{% endblock header %}

{% block content %}

{% csrf_token %}

URL:


{% endblock content %}
[/html]

templates/list.html

{% extends 'base.html' %}

{% block header %}
<div class="jumbotron">
   <div class="container">
     <h1 class="display-4">News</h1>
   </div>
 </div>
{% endblock header %}

{% block content %}
<div class="container">
<ul class="list-group list-group-flush">
 <table border="2">
   <tr>
     <th>タイトル</th>
     <th>URL</th>
   </tr>
   {% for post, post2 in list %} 
   <tr>
     <td>{{ post }}</td>
     <td><a href="{{ post2 }}">{{ post2 }}</a></td>
   </tr>
   {% endfor %}
 </table>
</ul>
</div>
{% endblock content %}

$ python3 manage.py runserver 192.168.34.10:8000

### herokuにDeploy
$ echo web: gunicorn newsproject.wsgi –log-file – > Procfile
$ freeze > requirements.txt
$ python3 –version
Python 3.8.10
$ echo python-3.8.10 > runtime.txt
$ echo -e __pycache__\\ndb.sqlite3\\n.DS_Store\\nlocal_settings.py > .gitignore

newsproject/settings.py
L SECRET_KEYを削除する

import dj_database_url

DEBUG = False
// 省略

ALLOWED_HOSTS = ["*"]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware', // 追加
]

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'name',
        'USER': 'user',
        'PASSWORD': '',
        'HOST': 'host',
        'PORT': '',
    }
}

try:
    from .local_settings import *
except ImportError:
    pass

if not DEBUG:
    SECRET_KEY = os.environ['SECRET_KEY']
    import django_heroku
    django_heroku.settings(locals())

df_from_env = dj_database_url.config(conn_max_age=600, ssl_require=True)
DATABAES['default'].update(db_from_env)
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

newsproject/local_settings.py
L SECRET_KEYをコピーする

import os

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

SECRET_KEY = 'django-insecure-bm-*'

DATABASES = {
	'default': {
		'ENGINE' : 'django.db.backends.sqlite3',
		'NAME': os.path.join(BASE_DIR, 'db.sqlite3')
	}
}

DEBUG = True

if not DEBUG:
    SECRET_KEY = os.environ['SECRET_KEY']

$ git init
$ git add -A
$ git commit -m “initial commit”
$ heroku login
$ heroku create
$ heroku config:set SECRET_KEY=’django-insecure-*’
$ git push heroku master

ERROR: Could not find a version that satisfies the requirement cliapp==1.20180812.1 (from versions: 1.0.1, 1.0.2, 1.0.3, 1.0.4, 1.0.5, 1.0.6, 1.0.7, 1.0.8, 1.0.9)
remote: ERROR: No matching distribution found for cliapp==1.20180812.1

git pushできない…
なかなか難儀やな