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

子どもの頃の私は、「親に宿題を手伝って貰う」という考え方がありませんでした。

As a child, I didn't have a "get my parents to help me with my homework" mentality.

―― ジョーダンではない!そんなみっともないことができるか!

"No kidding! I can't be so disgusting!"

が、私の考え方の中心でした。

It was the center of my thinking.

学費とか生活必需品とかの例外を除き、「親にお金をねだる」ということをやったこともありません。

I've never done the "begging my parents for money" thing, with the exception of school fees or other necessities.

というか――「できなかった」。

I mean - "I couldn't".

我が家は、決して裕福な家庭ではなかったですし、父も母も、下町の木工会社を経営しながら、真の意味において「命懸け」で働いているのを、(私も、時々、その手伝いをしながら)見てきたからです。

My family was not a wealthy one, and I watched (and sometimes helped) my father and mother run a downtown woodworking company, working for their "lives" in the true sense of the word.

# 本当に、父も母も、何度か死にかけて、入院(ICU等を含む)をしていました。

# Really, both my father and mother was about to die several times and were hospitalized (including ICU etc.).

-----

一方、嫁さんの方は、当たり前の様に、義父や義母に宿題を手伝って貰っていたそうです。

My wife, on the other hand, had her father-in-law and mother-in-law help her with her homework, as was the norm.

「プライド」とかの問題より「ラクできるなら何だって使う」という一貫したポリシーがあり、そこに「後ろめたさ」は、全くなかったそうです。

She had a consistent policy of "use whatever it takes to make it easier" rather than "her pride," and she never felt guilty about it.

もはや、これは、「是非の問題」ではなく「文化の相違」としか言いようがありません。

This is no longer a "right or wrong" thing to say, but rather a cultural difference.

それはさておき。

Aside from that.

-----

先日、娘から、

The other day, my daughter told me

―― 自分の娘に『何か欲しいものはないか?』と訊ねて、娘に買い与える父親がいる

"The father of her friend asks his daughter, "Do you have anything you want? and buys it for his daughter"

と聞きました。

その瞬間、私は『気持ち悪!』と思いました。

At that moment, I thought, "It feels bad!"

江端家では、そのような光景が出現したことはありませんし、これからもないでしょう。

Such a scene has never appeared in the Ebata family, and it will never happen.

娘に「訊ねて」まで買い与える金があれば、私は私の欲しいものを買います ―― 技術書とか、装置とか、ソフトウェアとか、各種のデータ資料とか。

If I have the money to buy my daughter until I "ask" her, I will buy what I want -- technical books, equipment, software, various data materials, and so on.

娘には『自分の欲しいものは、自分で手に入れろ』と言い聞かせてありますので、娘も、私に無駄なことはしてきません。

I've told my daughters, 'You get what you want by yourself' so they won't waste their time on me, either.

(続く)

(To be continued)

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

現在、想定100ページを越えるであろう、報告書の作成をしています。

I am currently working on a report, which is expected to be in excess of 100 pages.

資料のネタは十分にあり、これを構成しなおせば報告書として完成するのですが、なかなかに長丁場のしんどい作業になりそうです。

I have enough material, and if I re-structure it, it will be completed as a report, but it's going to be a long and tedious process.

昔は、このような作業は、音楽やアニメを見ながらでも作業できたのですが、最近、これができなくなっています。

In the past, I used to be able to work on these tasks while watching music or cartoons, but lately this has been impossible.

2つの作業を同時にできなくなってきています。

I come to be able to do both tasks at the same time.

これは私の脳の並列処理能力(マルチタスク)が、壊れつつあることの証拠だと思います。

I think this is evidence that my brain's parallel processing capacity (multitasking) is breaking down.

-----

ですが、すでに、視聴済みのコンテンツであれば、マルチタスクができる場合があります。

But you may be able to multitask with content you've already watched.

私の場合、「三国志 three kingdoms」が、これに該当します。

In my case, "Three Kingdoms" is it.

もう、すでに、このコンテンツ自体が、私にとってのイージーリスニングの部類に入っています。

Already, this content itself is already in the easy listening category for me.

まあ、そういう訳で、全部合わせて95話、約100時間のドラマを、ダラダラと聞きながら仕事をしています。

All in all, I work through 95 episodes, about 100 hours of drama, while lazily listening to it.

-----

で、まあ、時々、仕事の合間にボンヤリと考えるのですが

And, well, sometimes I think about this drama.

―― 諸葛孔明が何度も試みた「北伐」って、要するに「侵略戦争」だよなぁ

"The 'northern expedition' that Zhuge Liang tried many times is, in short, an 'aggression war'"

とか、

and

―― 落鳳坡で 劉備のフリををしたホウ統(士元)が、計算の上で命を落とすのは覚悟の上だろうけど、その部下は、訳も分からず巻き添え喰らって殺されたんだよなぁ

I'm sure that Hou Tong (Shi Yuan), who pretended to be Liu Bei at "Rakuhouha", was prepared to lose his life in his calculation, but that subordinate would have been killed by collateral damage for no reason.

とか、

三国志の名シーンを「台無し」にするような感想を浮かべながら、仕事を続けています。

I continue to work with thoughts that "ruin" famous scenes from the Three Kingdoms.

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

よくアニメやドラマで登場する「教師」などを見て、

Looking at a "ideal teachers" in cartoons and dramas.

『あんな先生が、学校にいてくれたらなー』

"I wish I had a teacher like that at school"

とか、

or

『そんな先生と巡りあっていたら、私の人生も違っていただろうに』

"My life would have been different if I'd had a teacher like that"

という書き込みが散見されます。

I can read scattering of posts like the above on the Internet.

ちょっと調べてみたら、そういうページが沢山ありました。

I did a little research and found a lot of those pages.

ちょっと前なら、「暗殺教室」の「殺せんせー」、最近なら、「俺の青春ラブコメは間違っている」の「平塚先生」などなど。

Not so long ago, it would have been "Koro-Sensei" in "Assassination Classroom", and more recently, it would have been "Hiratsuka-sensei" in "My youth romantic comedy is wront as I expected".

-----

一方

The other side,

『将来、あんな先生になるんだ』

"I'm gonna be that teacher one day"

とか、

or

『私は、今、あんな風に子どもを助ける大人として、がんばっている』

"I'm trying my best to be an adult who helps kids like that now"

という書き込みは、

I could not find the phrases like the above

―― たったの一つも

"at all"

見付けることはできませんでした。

-----

結論:

Conclusion:

私達は、

We are creatures that

■自分の為に、他人に理想を押しつけ、

impose our ideals on others for your own sake,

■他人の為には、自分に努力を課さない、

don't work hard for others.

そういう生き物です。

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

人間は、他人を他人として認識するのではなく、その他人の属する所属や地位、環境を含めて認識します。

Humans don't perceive others as others but others including their affiliations, status, and environments.

「部長の山田さん」「新人の田中さん」「技術者の佐藤さん」「ドイツ在住の高橋さん」等々です、

Mr. Yamada, the department head, Ms. Tanaka, the new guy, Mr. Sato, the technician, Ms. Takahashi, who lives in Germany, and so on.

特に初対面の場合は、そうなるのは仕方がありません。

Especially in the case of the first meeting, it can not be helped.

その時の私たちは、他人を評価する情報を全く持っていないからです。

At that time, we have no information to evaluate others.

-----

ただ、「名物研究員の江端さん」というフレーズには、所属、地位、環境を含んでいません。

However, the phrase "Mr. Ebata, a famous researcher" does not include affiliation, position, or environment.

そこには、敬意とも蔑視とも解釈可能な「形容句」が入っているだけです。

It only contains "adjectives" that can be interpreted as both respect and contempt.

先日も、メールの中にこのフレーズを見つけて、『なるほど、私は"名物研究員"なんだ』と認識しました。

The other day, I found this phrase in an email and realized that "I see, I'm a famous researcher".

-----

「こちらが、同じ部署の江端です」という同僚の紹介で、先方の方と名刺交換をしている時に、

When I was exchanging business cards with the other person, I was introduced by a colleague who said, "This is Ebata from the same department."

『ああ、こちらが、あの江端さん・・・、お噂はかねがね伺っております』

"Oh, You are Mr. Ebata... I've heard a lot of great things about you."

というコメントを頂きました。

I got the comment.

-----

―― "ソースは誰?"

"Who is the source ?"

―― "どんな噂?"

"What kind of great things ?"

と、突っ込みたくなっても、苦笑いしながら、それを、グっと我慢するのが、

Even if I want to dig in, I have to put up with it with a bitter smile.

「大人の社会人」というものです。

This is an "adult business people"

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

木材から円形(円盤)を切り出すことが必要となり、色々試しています。

このような、電動ドライバーに装着できる、木材用の円切りサークルカッターを使っていました。

しかし、これで作業すると、直径20cmの円を切り出すのに、(慣れてきても)10分以上はかかるので、非常に効率が悪く、恐しく疲労します。

そこで、今回、BOSCH(ボッシュ)の電動ノコギリを使って木板を円形に切ることのできる、BOSCHのジグソー円曲平行ガイドを購入しました(別の会社の電動ノコギリの場合、その会社が提供しているものを購入する方が安全です)

先程、自宅に届いたので、さっそく、自分のメモとしてジグソー円曲平行ガイドを、袋から取り出すところから、切り出すまでの全行程を撮影しました。

 

映像の中では、キレイな円形の切出しに失敗していますが、これは中心線をズラさないようにすれば、必ず成功しますので御安心下さい。

サークルカッターと比較して、もの凄くラクチンに円盤を切り出せました。

電動ノコギリとジグソー円曲平行ガイドを接合した状態の写真↓

接合部分の拡大写真↓

以上

未分類

このコンテンツはパスワードで保護されています。閲覧するには以下にパスワードを入力してください。

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

スマホから位置情報を取得するところまできたが、https(wss)対応にしないと位置情報が取り出せないようです(かなりしつこく聞いていましたが、すっかり忘れていました)。

で、今のGolangのサーバプログラムをhttps対応にすべく、色々試したのですが、なんかこれで動いているようなので、要点だけ記載します。

Step.1 

まず、

C:\Users\ebata\WssSample\goClient>go run goClient.go conn.go hub.go tls: first record does not look like a TLS handshake がなんともならない件

の、mkcertを使って生成した鍵(“algo.key"と"algo.crt")をディレクトリに放り込む

Step.2

serverXX.goの、サーバ作成部を以下のように変更する

/*
		log.Fatal(http.ListenAndServe(*addr, nil)) // localhost:8080で起動をセット
	*/

	var httpErr error
	if _, err := os.Stat("./algo.crt"); err == nil {
		fmt.Println("file ", "algo.crt found switching to https")
		if httpErr = http.ListenAndServeTLS(*addr, "algo.crt", "algo.key", nil); httpErr != nil {
			log.Fatal("The process exited with https error: ", httpErr.Error())
		}
	} else {
		httpErr = http.ListenAndServe(*addr, nil)
		if httpErr != nil {
			log.Fatal("The process exited with http error: ", httpErr.Error())
		}
	}

Step.3

htmlファイルの、"http://"を、片っ端から"https://"に書き換える。

さくっと動いて気持ち悪いのですけど、まあ動くのであれば、なんでも良いです。

 

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

スマホから使えるようにした(今は、ランダムウォークだけ)。

/*
// server22.go ペアはclient9.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

// 使い方
// go run server13.go      (適当なシェルから)
// http://localhost:8080  (ブラウザ起動)
// http://localhost:8080/smartphone (スマホ起動)
*/

package main

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

	"github.com/gorilla/websocket"
)

// GetLoc GetLoc
type GetLoc struct {
	ID  int     `json:"id"`
	Lat float64 `json:"lat"`
	Lng float64 `json:"lng"`
	//Address string  `json:"address"`
}

//var addr = flag.String("addr", "localhost:8080", "http service address")
var addr = flag.String("addr", "0.0.0.0:8080", "http service address") // テスト

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

var chan2_1 = make(chan GetLoc)

var maxid = 0

var mutex sync.Mutex

func echo2(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()

	//mutex := new(sync.Mutex)

	for {
		//mt, message, err := c.ReadMessage() // クライアントからのメッセージの受信(mtはクライアント識別子)
		//_, _, err := c.ReadMessage() // クライアントからのメッセージの受信(mtはクライアント識別子)

		//mutex.Lock()  // ここに置くとデッドロックしてしまう

		gl := new(GetLoc)

		err := c.ReadJSON(&gl) // クライアントからのメッセージの受信

		mutex.Lock()

		// 原因不明の対処処理
		if gl.ID == 0 && gl.Lat < 0.01 && gl.Lng < 0.01 {
			mutex.Unlock()
			break
		} else if gl.ID < -1 { // 受理できないメッセージとして返信する
			//条件分岐 (変なIDが付与されているメッセージは潰す)
			//if (gl.ID > maxid) || (gl.ID < -1) { // 受理できないメッセージとして返信する

			gl.ID = -1
			gl.Lat = -999
			gl.Lng = -999
			err2 := c.WriteJSON(gl)
			if err2 != nil {
				log.Println("write1:", err2)
				mutex.Unlock()
				break
			}
		} else { // それ以外は転送する
			log.Printf("echo2 after c.WriteJSON(gl) ID:%d", gl.ID)
			log.Printf("echo2 after c.WriteJSON(gl) Lat:%f", gl.Lat)
			log.Printf("echo2 after c.WriteJSON(gl) Lng:%f", gl.Lng)

			if err != nil {
				log.Println("read:", err)
				mutex.Unlock()
				break
			}
			fmt.Printf("echo2 before chan2_1 <- *gl\n")
			chan2_1 <- *gl
			fmt.Printf("echo2 after chan2_1 <- *gl\n")

			//で、ここで受けとる
			//gl2 := new(GetLoc)
			fmt.Printf("echo2 before gl2 := <-chan2_1\n")
			gl2 := <-chan2_1
			maxid = gl2.ID // ID最大値の更新
			log.Printf("echo2 after gl2 := <-chan2_1 ID:%d", gl2.ID)
			log.Printf("echo2 after gl2 := <-chan2_1 Lat:%f", gl2.Lat)
			log.Printf("echo2 after gl2 := <-chan2_1 Lng:%f", gl2.Lng)

			fmt.Printf("echo2 before err2 := c.WriteJSON(gl2)\n")
			err2 := c.WriteJSON(gl2)
			fmt.Printf("echo2 after err2 := c.WriteJSON(gl2)\n")
			if err2 != nil {
				log.Println("write2:", err2)
				mutex.Unlock()
				break
			}
			fmt.Printf("end of echo2\n")

		}

		mutex.Unlock()
	}
}

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 {

		fmt.Printf("echo before gl := <-chan2_1\n")
		gl := <-chan2_1
		fmt.Printf("echo after gl := <-chan2_1\n")

		fmt.Printf("echo before err = c.WriteJSON(gl) gl2.id = %d\n", gl.ID)
		fmt.Printf("echo before err = c.WriteJSON(gl) gl2.lat = %f\n", gl.Lat)
		fmt.Printf("echo before err = c.WriteJSON(gl) gl2.lng= %f\n", gl.Lng)
		err = c.WriteJSON(gl)
		if err != nil {
			log.Println("WriteJSON1:", err)
		}
		fmt.Printf("echo after err = c.WriteJSON(gl)\n")

		fmt.Printf("echo before err = c.RreadJSON(gl)\n")
		gl2 := new(GetLoc)
		err2 := c.ReadJSON(&gl2)
		fmt.Printf("echo after err = c.ReadJSON(&gl2) gl2.id = %d\n", gl2.ID)
		fmt.Printf("echo after err = c.ReadJSON(&gl2) gl2.lat = %f\n", gl2.Lat)
		fmt.Printf("echo after err = c.ReadJSON(&gl2) gl2.lng= %f\n", gl2.Lng)
		if err2 != nil {
			log.Println("ReadJSON:", err2)
		}
		// ここからチャネルで返す
		fmt.Printf("echo before chan2_1 <- *gl2 gl2.id = %d\n", gl2.ID)
		fmt.Printf("echo before chan2_1 <- *gl2 gl2.lat = %f\n", gl2.Lat)
		fmt.Printf("echo before chan2_1 <- *gl2 gl2.lng = %f\n", gl2.Lng)
		chan2_1 <- *gl2
		fmt.Printf("echo after chan2_1 <- *gl2\n")
		fmt.Printf("end of echo\n")
	}

}

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

func smartphone(w http.ResponseWriter, r *http.Request) {
	smartphoneTemplate.Execute(w, "ws://"+r.Host+"/echo2")
}

func main() {
	flag.Parse()
	log.SetFlags(0)

	http.HandleFunc("/echo2", echo2)           // echo関数を登録 (サーバとして必要)
	http.HandleFunc("/echo", echo)             // echo関数を登録 (サーバとして必要)
	http.HandleFunc("/", home)                 // home関数を登録
	http.HandleFunc("/smartphone", smartphone) // smartphone関数を登録
	log.Fatal(http.ListenAndServe(*addr, nil)) // localhost:8080で起動をセット
}

var smartphoneTemplate = template.Must(template.New("").Parse(`
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script> 

function obj(id, lat, lng){
	this.id = id;
	this.lat = lat;
	this.lng = lng;
}

function random(min, max){
	return  Math.random()*(max-min) + min;
}

// var personal_id;

var lat = 35.654543;
var lng = 139.795534;  

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);
	};

	var personal_id = 0;

	
	///// 起動時のボタン
	// disabled属性を削除
	document.getElementById("open").removeAttribute("disabled");
	document.getElementById("open").style.color = "black";

	// disabled属性を設定 (closeボタンを非活性化)
	document.getElementById("close").setAttribute("disabled", true);
	document.getElementById("close").style.color = "White";	

	// disabled属性を設定 (sendボタンを非活性化)
	document.getElementById("send").setAttribute("disabled", true);
	document.getElementById("send").style.color = "White";	


		
	document.getElementById("open").onclick = function(evt) {
		console.log("document.getElementById open");

		// disabled属性を設定 (openボタンを非活性化)
		document.getElementById("open").setAttribute("disabled", true);
		document.getElementById("open").style.color = "White";		

		// disabled属性を削除
		document.getElementById("send").removeAttribute("disabled");
		document.getElementById("send").style.color = "black";	

		// disabled属性を削除
		document.getElementById("close").removeAttribute("disabled");
		document.getElementById("close").style.color = "black";	

		////////// 削除2
		// ws = new WebSocket("{{.}}");
		////////// 削除2終り


		////////// 削除1
		//var send_obj = new obj(0, 35.654543,139.795534);  // 最初は"0"でエントリ

		//console.log("open:send_obj");	
		//console.log(send_obj.id);	
		//console.log(send_obj.lat);
		//console.log(send_obj.lng);		

		//var json_obj = JSON.stringify(send_obj);
		//ws.send(json_obj);
		/////////// 削除1終り


        if (ws) {
            return false;
        }
		
		
		////////// 追加2
		ws = new WebSocket("{{.}}");
		////////// 追加2終り

		
        ws.onopen = function(evt) {
			print("OPEN");
		
			//ws = new WebSocket("{{.}}");
			
			////////// 追加1			
			var send_obj = new obj(0, 35.654543,139.795534);  // 最初は"0"でエントリ

			console.log("open:send_obj");	
			console.log(send_obj.id);	
			console.log(send_obj.lat);
			console.log(send_obj.lng);		

			var json_obj = JSON.stringify(send_obj);
			ws.send(json_obj);
			/////////// 追加1終り

		}
		
        ws.onclose = function(evt) {

			print("CLOSE");
            ws = null;
        }

		ws.onmessage = function(evt) {  // 受信したメッセージはここに飛んでくる
			print("RESPONSE: " + evt.data);  // jsonメッセージの内容を表示
			// データをJSON形式に変更
			var obj = JSON.parse(evt.data);

			personal_id = obj.id; // IDの取得(何回も取る必要はないが)
			console.log("personal_id");			
			console.log(personal_id);

			
			if ((Math.abs(obj.lat) > 90.0) || (Math.abs(obj.lng) > 180.0)){ // 異常な座標が入った場合は、マーカーを消去する
				console.log("before ws.close()");
				ws.close();
				console.log("after ws.close()");
			}
		}
		
        ws.onerror = function(evt) {
            print("ERROR: " + evt.data);
        }
        return false;
    };
	
	document.getElementById("send").onclick = function(evt) {

		console.log("document.getElementById send");

		// disabled属性を設定 (openボタンを非活性化)
		document.getElementById("open").setAttribute("disabled", true);
		document.getElementById("open").style.color = "White";	
	
		// disabled属性を削除
		document.getElementById("send").removeAttribute("disabled");
		document.getElementById("send").style.color = "black";	

		// disabled属性を削除
		document.getElementById("close").removeAttribute("disabled");
		document.getElementById("close").style.color = "black";	
	
		if (!ws) {
			console.log("return false send");
			return false;			
		}

		lat += random(0.5, -0.5) * 0.00001 * 10 * 5;
		lng += random(0.5, -0.5) * 0.00002 * 10 * 5

		
		//var send_obj = new obj(personal_id, 35.654543,139.795534);  // idでエントリ
		var send_obj = new obj(personal_id, lat, lng);  // idでエントリ

		console.log("send:send_obj");	
		console.log(send_obj.id);	
		console.log(send_obj.lat);
		console.log(send_obj.lng);		

		var json_obj = JSON.stringify(send_obj);
		ws.send(json_obj);		

		/*
        print("SEND: " + input.value);
        ws.send(input.value);
		return false;
		*/

		return false;	
    };

	document.getElementById("close").onclick = function(evt) {
		console.log(" document.getElementById close");

		// disabled属性を削除
		document.getElementById("open").removeAttribute("disabled");
		document.getElementById("open").style.color = "black";

		// disabled属性を設定 (closeボタンを非活性化)
		document.getElementById("close").setAttribute("disabled", true);
		document.getElementById("close").style.color = "White";	

		// disabled属性を設定 (sendボタンを非活性化)
		document.getElementById("send").setAttribute("disabled", true);
		document.getElementById("send").style.color = "White";			


        if (!ws) {
            return false;
		}
	
		var send_obj = new obj(personal_id, 999.9, 999.9);  // 最初は"0"でエントリ

		console.log("close:send_obj");
		console.log(send_obj.id);		
		console.log(send_obj.lat);
		console.log(send_obj.lng);		

		var json_obj = JSON.stringify(send_obj);
		ws.send(json_obj);

        //ws.close();  // これはws.onmessageの方で実施
        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>
<!-- <p><input id="input" type="text" value="Hello world!"> -->
<button id="send">Send</button>
<button id="close">Close</button>
</form>
</td><td valign="top" width="50%">
<div id="output"></div>
</td></tr></table>
</body>
</html>
`))

var homeTemplate = template.Must(template.New("").Parse(`
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>PruneMobile</title>

	<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0-beta.2.rc.2/leaflet.css"/>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0-beta.2.rc.2/leaflet.js"></script>

	<script src="http://kobore.net/PruneCluster.js"></script>           <!-- これ、いずれローカルホストから取れるように換える -->
	<link rel="stylesheet" href="http://kobore.net/examples.css"/>      <!-- これも、いずれローカルホストから取れるように換える -->

	<!-- goのテンプレートのローカルって、どこになるんだろう? -->

</head>
<body>
<div id="map"></div>

<script>

	ws = new WebSocket("{{.}}"); // websocketの確立

	/*
	var print = function(message) {
		var d = document.createElement("div");
		d.textContent = message;
		output.appendChild(d);
	};
	*/

	// 引数にはミリ秒を指定。(例:5秒の場合は5000)
	function sleep(a){
  		var dt1 = new Date().getTime();
  		var dt2 = new Date().getTime();
  		while (dt2 < dt1 + a){
			dt2 = new Date().getTime();
		}
  		return;
	}

    var map = L.map("map", {
        attributionControl: false,
        zoomControl: false
    }).setView(new L.LatLng(35.654543, 139.795534), 18);
    // }).setView(new L.LatLng(35.598563, 139.475528), 18); 広袴

    L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
        detectRetina: true,
        maxNativeZoom: 18
    }).addTo(map);

    var leafletView = new PruneClusterForLeaflet(1,1);  // (120,20)がデフォルト

	ws.onopen = function (event) {
	}

	var markers = [];

	//var helicopterIcon = L.icon({ iconUrl: 'http://sintef-9012.github.io/PruneCluster/examples/helicopter.png', iconSize: [48, 48] });
    //var airplaneIcon = L.icon({ iconUrl: 'http://sintef-9012.github.io/PruneCluster/examples/airplane.png', iconSize: [48, 48] });

	// 受信すると、勝手にここに飛んでくる
	ws.onmessage = function (event) {
		// データをJSON形式に変更
		var obj = JSON.parse(event.data);

		console.log("233");	
		console.log(obj.id);
		console.log(obj.lat);						
		console.log(obj.lng);	

		if (obj.id == 0){  // idが未登録の場合
			console.log("obj.id == 0")
			// データをマーカーとして登録
			var marker = new PruneCluster.Marker(obj.lat, obj.lng);

			// 参考資料  http://embed.plnkr.co/WmtpkEqSDJFuFeuiYP54/
			//var marker = new PruneCluster.Marker(obj.lat, obj.lng, {
			//	//popup: "Bell 206 " + i,
			//	icon: helicopterIcon
			//});


			console.log(marker.hashCode);		
			markers.push(marker);
	
			leafletView.RegisterMarker(marker);
	
			console.log(markers);
			console.log(markers.length)

			obj.id = marker.hashCode;
			//ws.send(marker.hashCode); // テキスト送信
			var json_obj = JSON.stringify(obj);
			ws.send(json_obj);			
		} else if ((Math.abs(obj.lat) > 90.0) || (Math.abs(obj.lng) > 180.0)){ // 異常な座標が入った場合は、マーカーを消去する
			console.log("Math.abs(obj.lat) > 180.0)")
			for (let i = 0; i < markers.length; ++i) {
				if (obj.id == markers[i].hashCode){
					console.log(i)
					console.log(obj.id)										
					console.log("obj.id == markers[i].hashCode")

					//leafletView.RemoveMarkers(markers[obj.id]);  // これでは消えてくれません
					// 1つのマーカーを消すのに、面倒でも以下の2行が必要
					var deleteList = markers.splice(i, 1);					
					leafletView.RemoveMarkers(deleteList);

					// 以下失敗例リスト
					//leafletView.RemoveMarkers(markers[i].hashCode);  //これはダメ
					//leafletView.RemoveMarkers(markers[obj.id],'item');
					//leafletView.ProcessView(); // 試しに入れてみる
					//leafletView.RemoveMarkers(markers[i-1]);
					//leafletView.RemoveMarkers(markers);					
					break;
				}
			}
			obj.lat = 91.0;
			obj.lng = 181.0;
			var json_obj = JSON.stringify(obj);
			ws.send(json_obj);				
		} else {
			// 位置情報更新
			console.log("else")
			for (let i = 0; i < markers.length; ++i) {
				if (obj.id == markers[i].hashCode){
					var ll = markers[i].position;
					ll.lat = obj.lat;
					ll.lng = obj.lng;
					break;
				}
			}
			var json_obj = JSON.stringify(obj);
			ws.send(json_obj);	
		}
	}

	// 位置情報の更新
    window.setInterval(function () {
        leafletView.ProcessView();  // 変更が行われたときに呼び出されれなければならない
	}, 1000);

	// サーバを止めると、ここに飛んでくる
	ws.onclose = function(event) {
		//print("CLOSE");
		ws = null;
	}


    map.addLayer(leafletView);
</script>



</body>
</html>
`))

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

viというのは、Windowsを除く、ほぼ全てのOSに標準実装されている、テキストエディタです。

"vi" is a text editor that comes standard in almost all operating systems, except Windows.

ですので、システムの構築や運用や保守に際しても、viさえ使えれば、最低限のことができます。

Therefore, as long as you can use vi, you can do the least building, operating and maintaining systems.

しかし、viは、分かりにくく、使いにくいことでも、有名です。

However, vi is also notoriously difficult to understand and use.

もちろん、使い込めば、こんなにも便利なツールはないというのも事実で、今なお根強いユーザがいます。

Of course, it's also true that once you use it, there is no tool more useful than this, and it still has power users.

# ちなみに私も、使えるviの操作は、全部で4つです。

# By the way, I also have a total of 4 vi operations that I can use.

-----

1年程前、ラズパイ上で作ったアプリケーションを、社内の事業部に技術移管する作業を行っていた時のことです。

About a year ago, I was in the process of transferring the technology of an application I had created on Raspberry pi to an internal business unit.

そこで集ったメンバは、20代、30代、40代のエンジニアと、その部署の部長を含めた5人でした。

There were five members gathered there, including engineers in their 20s, 30s, and 40s, and the head of the department.

私は、事業部が持ち込んできたラズパイに、アプリケーションを移管する作業と、そのレクチャーを行っていました。

I was working on transferring the application to a Raspberry pi, which was brought in by the division, and giving a lecture on it.

また、ネットワーク環境などに整合性を合わせる為に、構築情報を書き換える必要がありました。

I also had to rewrite the build information to make it more consistent with the network environment and other factors.

-----

私のレクチャーの話をもっとも理解して、私の作業手順のミスを指摘したのは、その「部長さん」だけでした。

It is the "manager" of the department, who understood my lecture deeply, and pointed out the errors in my operating procedures, was

私が、作業中に、

When I was working on it, and just muttering to myself

江端:「ああ、くそ! emacsが入っていなかったか。viは苦手なんだよな」

Ebata: "Oh, shit! Didn't have "emacs" on it. "vi" isn't good for me"

と呟いていたたところ、その部長さんが、

the general manager said

『私が、viで書き換えます』

"I'll rewrite it by "vi".

と申し出られて、ビックリしました。

I was surprised when he offered to do so

部長さんのスキルはさておき、

Aside from skills of the general manager.

―― 20代、30代、40代のエンジニアが、雁首そろえて、沈黙し続けていた

"All engineers in their twenties, thirties, and forties kept silent"

に、驚きました。

was that. I thought,

『こりゃ、UNIXコマンドすら触ったことがない、という感じだな』

"It's like they've never even touched a UNIX command before"

と思いました。

まあ、システムの利用者であれば、「UNIX? 何それ?」と言っても良いと思います。

Well, if you're a user of the system, I think it's safe to say "UNIX? What's that?"

が、システムを構築し、サービスを提供する側のエンジニアが「果たして、それで良いのか?」とは思います。

But as an engineer who builds systems and provides services, I have to ask myself, "Is that really good enough?

私も判断がつきかねています ―― 単なる「じじいのボヤキ」かもしれません。

I'm not sure I can judge it either -- maybe it's just "old man's blabbermouth".

それでも、はっきりと言えることは「ラズパイは、UNIX(Linux)コマンド使えないと、1mmも動かせない」です。

Nevertheless, what I can say clearly is "If you can't use UNIX (Linux) commands, you can't run Raspberry pi".

-----

ちなみに、私の勤務する会社の社是は『技術で社会に貢献する』です。

Incidentally, my companay motto is "Contribute to society through technology".

この一点のみで、会社と私は繋っているといっても、過言ではありません。

It would not be an exaggeration to say that this is the only link between the company and me.

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

以前、マグカップの代替として、計量カップを購入する話をしました。

I've talked before about buying a measuring cup as a mug.

この計量カップ、絶好調です。

This measuring cup is really great.

例えば、カフェオレを作る場合、計量カップに、インスタントコーヒーを投入した後、100ccの牛乳を入れ、300ccの水を加え、電子レンジに放り込むだけで、

For example, to make a cafe au lait, simply pour the instant coffee into a measuring cup, add 100cc of milk, 300cc of water, and toss it into the microwave.

―― いつでも、一定品質のカフェオレが飲める

"constant quality cafe au lait at all times."

ということは、とても素晴しいことです。

So that's wonderful.

-----

嫁さん:「それが『素晴しい』と思える感性が理解できない」

Wife: "I don't understand the sensitivity of thinking that's 'wonderful'"

江端:「家族全員分、購入しようかと思っているくらいだが・・・」

Ebata: "I'm even thinking of buying one for the whole family..."

嫁さん:「絶対やめてね」

Wife: "Absolutely not"

長女:「そんなものより、お洒落な食器を購入してよ」

Senior daughter: "Don't worry about that, buy me some fancy dishes"

江端:「いいよ。私も食器は好きだ」

Ebata: "Okay. I like the dishes too"

私は観光に行くと、その地方の特産の陶器を、自分用のお土産として購入しています。

Whenever I go sightseeing, I buy local pottery for myself as a souvenir.

-----

江端:「しかし、陶器の内側に、目盛が付いているものが、見あたらなくてな」

Ebata: "But I can't find anything with a scale on the inside of the pottery"

嫁さん:「なんで、そんなもの・・・」

Wife: "Why is that...?"

江端:「いや、これを使えば、『どれくらいのシチューを皿に投入したか』、そして『現在、どれくらいの速度でシチューを食べているか』が、一目瞭然だろう?」

Ebata: "Well, it will tell me at a glance 'how much stew I've thrown into your plate' and 'how fast I're currently eating the stew', won't it?"

嫁さん:「・・・」

Wife: "...

長女:「パパは、そういうことが『嬉しい』んだ」

Senior daughter: "Daddy, that's what makes you 'happy'"

江端:「嬉しい」

Ebata:"It makes me happy"

長女:「そうか・・・。パパが『嬉しい』なら、私も『嬉しい』よ」

Senior daughter: "Well... If Daddy's 'happy', then I'm 'happy' too"