2020/08,江端さんの忘備録,江端さんの技術メモ

Go言語は、スレッド化による並列処理が得意という話を聞いていましたので、先日の

の"client.go"を改造して、「とりあえず、動かして、止めることができればいい」という割り切りだけでコードをごそごそを変えてみました。(server.goは変更なしで大丈夫)

// go run client_multi_agent.go

// Copyright 2015 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build ignore

package main

import (
	"flag"
	"log"
	"net/url"
	"os"
	"os/signal"
	"time"

	"github.com/gorilla/websocket"
)

var addr = flag.String("addr", "localhost:8080", "http service address")


var interrupt = make(chan os.Signal, 1) // Go のシグナル通知は、チャネルに os.Signal 値を送信することで行います。
			  	 		   			  	 // これらの通知を受信するためのチャネル (と、プログラムが終了できること
										 // を通知するためのチャネル) を作ります。
var	u = url.URL{Scheme: "ws", Host: *addr, Path: "/echo"} // JSON型の配列記述方法?

func main() {
	flag.Parse()     //引数の読み込み argv, argcと同じ
	log.SetFlags(0)  // ログの出力で時間の情報、この時点で0秒にセット

//	interrupt := make(chan os.Signal, 1) // Go のシグナル通知は、チャネルに os.Signal 値を送信することで行います。
//			  	 		   			  	 // これらの通知を受信するためのチャネル (と、プログラムが終了できること
//										 // を通知するためのチャネル) を作ります。

	signal.Notify(interrupt, os.Interrupt) // 指定されたシグナル通知を受信するために、 与えられたチャネルを登録
							 			   // します。

	log.Printf("connecting to %s", u.String()) // ここは単にプリントしているだけ(だろう)

	///// ここまでは共通 /////

	go sub_main()
	time.Sleep(time.Millisecond * 333)  // 333ミリ秒		

	go sub_main()
	time.Sleep(time.Millisecond * 333)  // 333ミリ秒		

	go sub_main()
	time.Sleep(time.Millisecond * 333)  // 333ミリ秒		

	go sub_main()
	time.Sleep(time.Millisecond * 333)  // 333ミリ秒		

	go sub_main()
	time.Sleep(time.Millisecond * 333)  // 333ミリ秒		

	go sub_main()
	time.Sleep(time.Millisecond * 333)  // 333ミリ秒		

	go sub_main()
	time.Sleep(time.Millisecond * 333)  // 333ミリ秒		

	go sub_main()
	time.Sleep(time.Millisecond * 333)  // 333ミリ秒		

	go sub_main()
	time.Sleep(time.Millisecond * 333)  // 333ミリ秒		

	go sub_main()
	time.Sleep(time.Millisecond * 333)  // 333ミリ秒		

	go sub_main()
	time.Sleep(time.Millisecond * 333)  // 333ミリ秒		
	
	ticker := time.NewTicker(time.Second)  // 1秒おきに通知 (sleepと同じ)		

	for {
		select{
    	   case <-ticker.C: // tickerのチャネルはデフォルトで付いているらしい
		   case <-interrupt:  // こっちは手動割り込みだな検知だな
		        return;
		}
     }
}

func sub_main(){
	c, _, err := websocket.DefaultDialer.Dial(u.String(), nil) // これがコネクションの実施
	if err != nil {
		log.Fatal("dial:", err)
	}
	defer c.Close() // deferは、どこに書かれていようとも、関数から抜ける前に実行される

	done := make(chan struct{}) // 配列といってもいいし、並行処理用のキューといってもいい
                                // 値が入っていないとデッドロックする

	go func() {  // 受信用スレッドを立ち上げる(スレッドの中でスレッド立ち上げているが、大丈夫だろうか)
		defer close(done)
		for {
			_, message, err := c.ReadMessage() // このメソッドの返り値は3つで、最初の返り値は不要
			if err != nil {
				log.Println("read:", err)
				return
			}
			log.Printf("recv: %s", message)  // 受信したら、そのメッセージを表示する
		}
	}()

	ticker := time.NewTicker(time.Second)  // 1秒おきに通知 (sleepと同じ)
	defer ticker.Stop() // このループを抜ける時に終了する

	for {            // 無限ループの宣言かな(C/C++ で言うとろの、whileとかdoとか)
		select {
		case <-done: // doneの中に何かが入っていたら、このルーチンはリターンして終了となる
			 		 // (でも何も入っていないところを見ると、func()ルーチンの消滅で、こっちが起動するんだろう)
			return
		case t := <-ticker.C: // tickerのチャネルはデフォルトで付いているらしい
			   	  			  // 時間が入ってくるまでロックされる	 
			   	  			  // この場合1秒単位でチャネルに時間が放り込まれるのでそこで動き出す。

			err := c.WriteMessage(websocket.TextMessage, []byte(t.String())) // サーバに(時刻の)メッセージを送付する
			if err != nil {
				log.Println("write:", err)
				return
			}
		case <-interrupt:  // こっちは手動割り込みだな検知だな
			log.Println("interrupt")

			// Cleanly close the connection by sending a close message and then
			// waiting (with timeout) for the server to close the connection.

			// close メッセージを送信してから、サーバーが接続を閉じるのを
			// (タイムアウトして)待つことで、接続をきれいに閉じます

			err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
			if err != nil {
				log.Println("write close:", err)
				return
			}
			select {
				case <-done: // これも上記の"done"の説明と同じでいいかな
				case <-time.After(time.Second): // このメソッド凄い time.Secondより未来ならひっかかる
			}
			return
		}
	}
}

まあ、main()と sub_main()で同じ割り込みを使っているので、タイミングによっては、main()を止めることができず、sub_main()を個別に止めていくことになるが、とりあえず動いたので、これで良しとする。

go sub_main() と書くだけで、いきなりスレッド化させることができる手軽さは、かなり驚いた。

こんなんやこんなんで、いろいろ苦労してきたんだけど、これからも、マルチエージェントシミュレーションを自力で書いていくことを考えると、正式にGo言語に移るべきかな、と思っています。

go webassembly experiments をローカルPCで動かす とかも、いろいろやっていきたいことですし。

2020/08,江端さんの忘備録

(昨日の続きです)

(Continuation from yesterday)

ところが、直接話しかけなくても、COCOAアプリのインストールを調べる方法はあります。

However there is a way to know whether a person has installed COCOA app, without talking. It is to make

―― 「自分の目の前にいる人が『COCOAアプリをインストールしているか』を確認するアプリ」

"An app that checks to see if the person in front of you has the COCOA app installed"

を作れば良いのです(このアプリを便宜的に「COCOA'」と称呼します)。

(I will call this app COCOA' for convenience)

ポイントは、COCOAアプリが、オープンソースで公開されている点にあります。

The point is that the COCOA app is open source and publicly available.

これは、つまり、「時間」と「能力」と「スキル」と「気力」のある人間であれば、COCOAの派生アプリケーションである、COCOA'を自由に開発できる可能性がある、ということです。

This means that anyone with the time, ability, skills and energy can develop COCOA's derivative application, COCOA'.

ただ、正確に言うと、上記の「自分の目の前にいる人」のスマホを検知することはできません。

However, to be precise, this app cannot detect the contents of the phone of the "person in front of you" mentioned above.

COCOA'は、

The COCOA' can only detect

■あなたのスマホから、約半径10メートルの範囲内で、

- Within a radius of about 10 meters from your phone,

■「COCOAアプリがインストールされているスマホ」の「台数」

- Number of "phones with COCOA installed

を調べることができるだけです。

だから、「自分の目の前にいる人」がインストールしているか否かをを特定する為には、

So, in order to identify whether or not the "person in front of you" has COCOA installed. the condition is given:

■約半径10メートル以内には、その人以外には、誰もいない

"There is no one else within a radius of approximately 10 meters except that person.

ことが必要となります。

-----

COCOA'の動作原理は簡単です。

The principle of operation of 'COCOA' is simple.

COCOA'は、COCOAのBluetoothの電波を発射しているスマホを探すだけです。

The COCOA' tries to find a phone that is transmitting COCOA's Bluetooth signal.

それだけしかできません。

That's all the app can do.

しかも、Bluetoothの電波の中の情報は、個人情報(スマホ固体番号等)と紐付いていないので、個人の特定はできません。

What's more, the information in the Bluetooth radio waves is not tied to personal information (such as the phone's solid number), so it cannot be used to identify an individual.

あなたは、街の中で、FreeのWiFiアクセスポイントを探したことがあると思います。

I'm sure you've looked for free WiFi access points around town.

COCOA'も、これと同じことをするだけです。

COCOA' just does the same thing.

-----

もし私(か、あるいは誰か)が、このCOCOA'を開発したら、ちょっと面白いことができます。

If I (or someone else) develops this COCOA', it could be a bit interesting.

『COCOAをインストールしている人 = コロナリテラシーが高い』という仮説を"真"とした上で、以下のようなこと調査や判断ができるようになります。

If the hypothesis that "people who have COCOA installed = high corona literacy" is true, then the following investigations and judgments can be made.

例えば、

For example,

■COCOA'を、居酒屋やラーメン屋の入口で起動する

- Launching 'COCOA' at the entrance of an izakaya or noodle shop

これによって、その店の中で、何人の人間がCOCOAを起動しているか、一目瞭然です。

This allows you to see at a glance how many people in that store are running COCOA.

店舗に入る前に、ざっくりとした、その店舗内の「コロナリテラシー」の高いお客の人数を、店に入る前に調べることができます。

Before entering a store, you can find out, roughly, the number of "high corona literate" customers in that store before you walk in.

(私なら、10人のお客が入っているラーメン屋の入口で、COCOAが起動しているスマホが3台だけなら、そのラーメン屋には、入りません)

(I wouldn't go into a ramen shop with 10 customers if there were only three phones with COCOA running at the entrance of a ramen shop)

■COCOA'を、職場や、飲み会の会場で起動する

- Launching 'COCOA' at your workplace or at a drinking venue.

自分の属する組織やグループの「コロナリテラシー」を、集団として観測することができます。

You can observe the "corona literacy" of your organization or group as a group.

(私としては、『それを言い訳に、飲み会の出席を拒否する』という切り札としても使えると期待しています)

(For me, I'm hoping it can be used as a trump card to "use that as an excuse to refuse to attend a drinking session".)

これによって、今後、

In the future,

■『COCOAをインストールしたスマホをお持ちでない方の入店はお断りします』という張り紙

A sign that says, "we do not allow people who do not have a smartphone with COCOA installed to enter the store".

が、飲食店のみならず、全ての施設(役所、アミューズメント、学校)の入口の前に張られるようになるかもしれません。

The paper could be put up in front of the entrances of all establishments (government offices, amusements, schools), not just restaurants.

-----

ざっとソースコードを見てみたのですが、この新しいアプリ(COCOA')の開発は、私には、少々敷居が高いように思われます。

I took a quick look at the source code and it seems to me that developing this new app (COCOA') is a bit of a challenge.

スキルも時間も足りませんが、特に時間の要素が大きそうです。

I don't have enough skills or time, but the time factor seems to be particularly significant.

従って、当面の私の仕事としては、

Therefore, for the time being, my work is to to write a column that explains easily

『COCOAによって、個人情報を抜き取られる心配はしなくていいよ』

"You don't have to worry about COCOA extracting your personal information"

を、分かりやすく解説するコラムを執筆する ―― こっちなら役に立てるかもしれません。

I might be able to help you with this work.

2020/08,江端さんの技術メモ

// mail.go

package main
 
import (
    "net/http"
 
    "github.com/labstack/echo"
)
 
func main() {
    e := echo.New()
	e.POST("/save", save)
	e.Logger.Fatal(e.Start(":1323"))
}


func save(c echo.Context) error {
	 name := c.FormValue("name")
	 email := c.FormValue("email")
	 return c.String(http.StatusOK, "name:"+name+", email:"+email)
}

でもって、curlで送ってみた。

ebata@DESKTOP-P6KREM0 MINGW64 ~
$ curl -F "name=ebata" -F "email=mailmail" http://localhost:1323/save

で、出力が、以下のようになった。
name:ebata, email:mailmail

2020/08,江端さんの技術メモ

この"server.go"は、client.goからの通信だけではなく、ブラウザの画面も提供します(スゴい!)。

というか、Goプログラムの中に、html書けるなんて知らんかった。

// server.go

// Copyright 2015 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build ignore

package main

import (
	"flag"
	"html/template"
	"log"
	"net/http"

	"github.com/gorilla/websocket"
)

var addr = flag.String("addr", "localhost:8080", "http service address")

var upgrader = websocket.Upgrader{} // use default options

func echo(w http.ResponseWriter, r *http.Request) {
	c, err := upgrader.Upgrade(w, r, nil) // cはサーバのコネクション
	if err != nil {
		log.Print("upgrade:", err)
		return
	}
	defer c.Close()
	for {
		mt, message, err := c.ReadMessage()  // クライアントからのメッセージの受信(mtはクライアント識別子)
		if err != nil {
			log.Println("read:", err)
			break
		}
		log.Printf("recv_serv: %s", message) // 受信したメッセージの表示
		err = c.WriteMessage(mt, message) // 受信したメッセージの返送
		if err != nil {
			log.Println("write:", err)
			break
		}
	}
}

func home(w http.ResponseWriter, r *http.Request) {
	homeTemplate.Execute(w, "ws://"+r.Host+"/echo")
}

func main() {
	flag.Parse()
	log.SetFlags(0)
	http.HandleFunc("/echo", echo) // echo関数を登録
	http.HandleFunc("/", home) // home関数を登録
	log.Fatal(http.ListenAndServe(*addr, nil)) // localhost:8080で起動をセット
}

var homeTemplate = template.Must(template.New("").Parse(`
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>  
window.addEventListener("load", function(evt) {
    var output = document.getElementById("output");
    var input = document.getElementById("input");
    var ws;
    var print = function(message) {
        var d = document.createElement("div");
        d.textContent = message;
        output.appendChild(d);
    };
    document.getElementById("open").onclick = function(evt) {
        if (ws) {
            return false;
        }
        ws = new WebSocket("{{.}}");
        ws.onopen = function(evt) {
            print("OPEN");
        }
        ws.onclose = function(evt) {
            print("CLOSE");
            ws = null;
        }
        ws.onmessage = function(evt) {
            print("RESPONSE: " + evt.data);
        }
        ws.onerror = function(evt) {
            print("ERROR: " + evt.data);
        }
        return false;
    };
    document.getElementById("send").onclick = function(evt) {
        if (!ws) {
            return false;
        }
        print("SEND: " + input.value);
        ws.send(input.value);
        return false;
    };
    document.getElementById("close").onclick = function(evt) {
        if (!ws) {
            return false;
        }
        ws.close();
        return false;
    };
});
</script>
</head>
<body>
<table>
<tr><td valign="top" width="50%">
<p>Click "Open" to create a connection to the server, 
"Send" to send a message to the server and "Close" to close the connection. 
You can change the message and send multiple times.
<p>
<form>
<button id="open">Open</button>
<button id="close">Close</button>
<p><input id="input" type="text" value="Hello world!">
<button id="send">Send</button>
</form>
</td><td valign="top" width="50%">
<div id="output"></div>
</td></tr></table>
</body>
</html>
`))
// client.go

// Copyright 2015 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build ignore

package main

import (
	"flag"
	"log"
	"net/url"
	"os"
	"os/signal"
	"time"

	"github.com/gorilla/websocket"
)

var addr = flag.String("addr", "localhost:8080", "http service address")


func main() {
	flag.Parse()     //引数の読み込み argv, argcと同じ
	log.SetFlags(0)  // ログの出力で時間の情報、この時点で0秒にセット

	interrupt := make(chan os.Signal, 1) // Go のシグナル通知は、チャネルに os.Signal 値を送信することで行います。
			  	 		   			  	 // これらの通知を受信するためのチャネル (と、プログラムが終了できること
										 // を通知するためのチャネル) を作ります。

	signal.Notify(interrupt, os.Interrupt) // 指定されたシグナル通知を受信するために、 与えられたチャネルを登録
							 			   // します。

	u := url.URL{Scheme: "ws", Host: *addr, Path: "/echo"} // JSON型の配列記述方法?
	log.Printf("connecting to %s", u.String()) // ここは単にプリントしているだけ(だろう)

	c, _, err := websocket.DefaultDialer.Dial(u.String(), nil) // これがコネクションの実施
	if err != nil {
		log.Fatal("dial:", err)
	}
	defer c.Close() // deferは、どこに書かれていようとも、関数から抜ける前に実行される

	done := make(chan struct{}) // 配列といってもいいし、並行処理用のキューといってもいい
                                // 値が入っていないとデッドロックする

	go func() {  // 受信用スレッドを立ち上げる
		defer close(done)
		for {
			_, message, err := c.ReadMessage() // このメソッドの返り値は3つで、最初の返り値は不要
			if err != nil {
				log.Println("read:", err)
				return
			}
			log.Printf("recv: %s", message)  // 受信したら、そのメッセージを表示する
		}
	}()

	ticker := time.NewTicker(time.Second)  // 1秒おきに通知 (sleepと同じ)
	defer ticker.Stop() // このループを抜ける時に終了する

	for {            // 無限ループの宣言かな(C/C++ で言うとろの、whileとかdoとか)
		select {
		case <-done: // doneの中に何かが入っていたら、このルーチンはリターンして終了となる
			 		 // (でも何も入っていないところを見ると、func()ルーチンの消滅で、こっちが起動するんだろう)
			return
		case t := <-ticker.C: // tickerのチャネルはデフォルトで付いているらしい
			   	  			  // 時間が入ってくるまでロックされる	 
			   	  			  // この場合1秒単位でチャネルに時間が放り込まれるのでそこで動き出す。

			err := c.WriteMessage(websocket.TextMessage, []byte(t.String())) // サーバに(時刻の)メッセージを送付する
			if err != nil {
				log.Println("write:", err)
				return
			}
		case <-interrupt:  // こっちは手動割り込みだな検知だな
			log.Println("interrupt")

			// Cleanly close the connection by sending a close message and then
			// waiting (with timeout) for the server to close the connection.

			// close メッセージを送信してから、サーバーが接続を閉じるのを
			// (タイムアウトして)待つことで、接続をきれいに閉じます

			err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
			if err != nil {
				log.Println("write close:", err)
				return
			}
			select {
			case <-done: // これも上記の"done"の説明と同じでいいかな
			case <-time.After(time.Second): // このメソッド凄い time.Secondより未来ならひっかかる
			}
			return
		}
	}
}

2020/08,江端さんの忘備録

コロナ感染症対策として、マスクが有効か否かついては、こちらで記載しております。

Whether or not masks are effective in fighting corona infection is described here.

また、こちらで記載しているように、感染しているか否かを、"0"と"1"のように考えることができないことも明らかです。

It's also clear that you can't think of being infected or not as a "0" and a "1", as described here.

しかし、その効果がどうであれ、「マスク」が一種のマナーとなっているのは事実です。

But whatever the effect, it is true that "masks" have become a kind of etiquette.

そして、「マスク」は、いわゆる「コロナリテラシー」の初歩の初歩と言えます。

And the "mask" is the first step of steps in so-called "corona literacy".

私としては、このマスクに加えて「COCOA(新型コロナ接触確認アプリ)」を、このマナーに入れることを提言したいと思います。

For me, I would like to suggest that in addition to this mask, the COCOA (new corona contact verification app) be included in this etiquette.

COCOAについては、すでに私、色々書いていますので、参考にして下さい。

I've already written a lot about COCOA, so please refer to it.

■COCOAのインストールは個人の自由ですが、私はインストールをお勧めしたいと思います。

Installing COCOA is a personal choice, but I would recommend that you install it.

■「セキュリティが万全」というよりは、「ハックするコストが全然見合わない」という感じです。

It's not so much "full security" as it is "not at all worth the cost to hack.

私は、「COCOAのインストール」を実施したか/していないかで、その人の「コロナリテラシー」を判断できると思っています。

I believe you can determine a person's "corona literacy" by whether or not they have/don't have implement a "COCOA installation".

-----

やり方は色々あると思いますが、もっとも簡単な方法は、

There are many ways to do this, but the easiest way is to ask a question,

『COCOAインストールしました?』

"Have you installed COCOA?

という質問をすることです。

■「もちろんです」という人は、リテラシー"1"で良いと思います。

If the person says "of course", I think his/her literacy level is "1".

■「ああ、COCOAですね。でも個人情報について不安が・・・」という人は、「リテラシー"0.9"」くらいと判断して良いかと思います。

"Oh, COCOA. But I'm worried about personal information...", I think it's safe to say that he/she have a literacy level of "0.9".

比して、

In comparison to,

■「COCOA? 何ですか、それ?」という人は、「リテラシー"0"」と断定して良いでしょう。

If the person says "COCOA? What's that?", I think his/her literacy level is "0".

いわゆる「自粛警察」をやっている人で、COCOAを知らない人がいたら、あなたは、その「自称警察官」、殴っていいです。

If you're a so-called "self-restraint police" and you don't know COCOA, I will hit you absolutely.

(私は、これに加えて、大声で、"ふざけるな!"と罵ります)。

In addition, I will shout "Do not be silly!" loudly,

(続く)

(To be continued)

2020/08,江端さんの技術メモ

golang ではファイル名が _test.go で終わるファイルを run すると
上記のエラーが表示されて実行できません。

ちなみに、buildだと

$ go build echo_test.go
no packages to build

と表示されて、なんのことやらさっぱり分かりませんでした。

2020/08,江端さんの技術メモ

$ go build echo.go
echo.go:4:5: cannot find package "github.com/trevex/golem" in any of:
        c:\go\src\github.com\trevex\golem (from $GOROOT)
        C:\Users\ebata\go\src\github.com\trevex\golem (from $GOPATH)

ebata@DESKTOP-P6KREM0 MINGW64 ~/go_websocket_test
$ go get -u github.com/trevex/golem

ebata@DESKTOP-P6KREM0 MINGW64 ~/go_websocket_test
$ go build echo.go

2020/08,江端さんの忘備録

(昨日の続きです)

(Continuation from yesterday)

私は、コラムを書くのが好きで、イラストを描くのが好きで、コーディングをするのが好きで、そして ――

I like to write columns, I like to illustrate, I like to code, and

その全てが「下手くそ」です。

I am not good at all of them.

だから、これらを他人に任せるのが、もっとも効率的であり、いわゆる『生産性が上がる』のは間違いないでしょう。

So, I think it's most efficient to leave these things to others, and there is no doubt that it will increase so-called "productivity".

だが、それは「楽しいのか?」

But is it "fun"?

自分の作り出したモノ、自分でやった仕事は、他人のモノや仕事より「愛おしくはないか?」

Do you love what you created and worked, more than other people's creations and works ?

と考えると、私には分からなくなるのです。

I don't know that.

それ故に、私は「私を幸せにするアプローチ」として、

Therefore my "approach to making me happy

(1)ひとりでやる

(1) Do it alone.

(2)ずっとやる

(2) Do it for a long time.

(3)会議に出ない(ここはGoogleと同じで、これまでも、これからも)

(3) Don't attend meetings.(It's the same as Google here, from now and to now)

を続けていくことになると思います。

I think I'll continue to do them.

-----

つまるところ、これは人間のスケール感の問題かもしれないなぁ、とも思います。

As a result, I think that this is about a matter of human scale.

私は「技術」が好きで、特に「小技」が好きですが、その技の集大成である「サービス」や「ビジネス」が好きな人にとっては、「Google式仕事術」は正しいアプローチだと思います。

While I like "technology" and especially the "little tricks, for people who like "service" and "business", the "Google Method of Working" is the right approach.

私は、「他の人」を喜ばせることに幸せを感じられます。

I feel happy to please other people.

しかし、私は、「"多く"の他の人」を喜ばせることが、"多くの幸せ"になるとは、感じることはありません。

However I can't feel many happiness to please many other people.

つまるところ、

In conclusion,

『私は、人間としての器が小さい』

"I don't have what it takes"

この結論で、私は異義ありません。

I have no objection to this conclusion.

2020/08,江端さんの忘備録

「Google式仕事術」では、生産性を上げる為に、以下を提唱しているそうです(読んでいません)。

The "Google Method of Working" advocates the following to increase productivity (I haven't read it)

(1)ひとりでやらない

(1) Don't do it alone.

(2)ずっとやらない

(2) Don't do it for a long time.

(3)会議に出ない

(3) Don't attend meetings.

なるほど「生産性を上げる為」には、これが正解かもしれません。

Okay, maybe this is the right thing to do "to increase productivity".

しかし、「生産性なんぞ知ったことか」と置き換えるだけで、このメソッドはボロボロと崩れていきます。

But simply replacing it with "I don't care of productivity", the method falls apart in tatters.

-----

私、生産性については、かなり徹底的に勉強しました。

Me, I've studied productivity pretty thoroughly.

その結果、「生産性について、合意が取れている定義が存在しない」ということを発見しました。

As a result, I found that "there is no agreed-upon definition of productivity.

そして、「生産性」と「幸福」の間には、強い相関が存在しないことも知りました。

I also learned that there is no strong correlation between "productivity" and "happiness".

-----

「生産性を上げる = 幸福」と「幸福 = 善」から、「生産性を上げる = 善」という三段論法は成立します。

The triadic argument, "Increase productivity = happiness" and "Happiness = goodness," is established from "Increase productivity = goodness.

しかし、

However, it can also be interpreted as,

―― その"生産性"を上げるのは、"私以外の誰か"で良くね?

"Why can't someone other than me make it more productive?"

という解釈が可能です。

さらに、「Google式仕事術」が、"この私"に「楽しさや喜びを与えているのか?」 という点について、私には分からないのです。

Furthermore, I can't know that "Google Method of Working" gives me joy and pleasure of mine.

■自分でコラムを書かなくても、面白いコラムを書いている人がいるから、そのコラムを読めばいい。

- Even if I don't write your own column, someone else writes an interesting column, so I can read it.

■綺麗なイラストを書ける人は、世の中にゴマンといるから、その人に外注すればいい

- There are many people who can draw beautiful illustrations in the world, so I can outsource to them.

■自分でコーディングしなくても、コーディングのプロに頼めばいい

- I can ask a professional to do the coding for me.

まったく、その通りだと思います。

I think these are absolutely right.

(続く)

(To be continued)

2020/08,江端さんの技術メモ

すでに地図DBは作ってきたが、今のうちに纏めておきます。ここでは東京の豊洲地区を例にして説明します。

なお、Dockerの利用を前提とし、それぞれの地区のDBはバラバラに管理するものとします。地区ごとに取り扱えるようにして、DBを切り替えて利用することを前提とする為です。

(Step1) (to-path)/toyosu というディレクトリを掘る

(Step2) そのディレクトリに、以下のdocker-compose.ymlを作ります。

version: '3.7'

services:
  db:
    image:  postgis-pgrouting:latest
    environment:
      POSTGRES_HOST_AUTH_METHOD: 'trust'
      POSTGRES_PASSWORD: 'postgres'
    expose:
      - 5432
    ports:
    - 15432:5432
    volumes:
      - db_data
      - ./shared:/shared
  db_data:
    image: busybox
    volumes:
      - /data/db

DB(PostgreSQL)のアクセス用のポート番号は、15432としています。ローカルにPostgresがある場合にバッティングを避ける為です。

(Step3) そのディレクトリの中で、"docker-compose up -d"を実行する。

(Step4)"$ docker start -a toyosu_db_1"としてコンテナを起動する

(Step5)(winpty) "docker container exec -it toyosu_db_1 bash" でシェルに入る

(Step6) "psql -U postgres" で、DBのコンソールに入る

(Step7)psqlでデータベースを新規作成する(以下、データベース名をca_simとする)。

postgres=#CREATE DATABASE ca_sim

(Step8)次のコマンドを実行する

postgres=# \c ca_sim
postgres=# create extension postgis;
postgres=# create extension pgrouting;

(Step9) ここで、もう一つ、コンソール(2)をたちあげて、(to-path)/toyosuに入っておく

(Step10) https://www.openstreetmap.org/ から、豊洲地区を選んで地図DBをエクスポートする

ファイル名を"toyosu.osm"として、(to-path)/toyosuに保存する

(Step11) コンソール2で、"toyosu.osm"を、コンテナに放り込む

>docker cp toyosu.osm toyosu_db_1:/db_data

(Step12)コンソール2で、"apt-get update"、"apt-get update" を実施した後、"apt-get install osm2pgrouting"を実施

(Step13)コンソール2で、"osm2pgrouting -f /db_data/toyosu.osm -c /usr/share/osm2pgrouting/mapconfig_for_cars.xml -d ca_sim -U postgres" を実施

これで、地図DBはできているハズだが、多分、一発で成功することはないので、いろいろ試してみて下さい。

(Step14) psqlでログインしているコンロールから、以下の操作をして表示ができれば、成功

postgres=# \c ca_sim
You are now connected to database "ca_sim" as user "postgres".
ca_sim=# \dt
List of relations
Schema | Name | Type | Owner
--------+-------------------+-------+----------
public | configuration | table | postgres
public | pointsofinterest | table | postgres
public | spatial_ref_sys | table | postgres
public | ways | table | postgres
public | ways_vertices_pgr | table | postgres
(5 rows)

ca_sim=# select * from ways;

以下のような表示がでてくれば、(多分)成功

QGIS3で接続すると、こんな感じのものが表示されるはず

以上