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

(昨日の続きです)

(Continuation from yesterday)

ただし「無視」にも2つあります。

However, there are two ways to "ignore" it.

「(1)黙っているか」か、「(2)痛みで苦しんでいる人を、さらに、痛めて苦しめる」か、です。

Either (1) keep quiet or (2) make the person who is suffering from the pain suffer even more, painfully.

私は、「無視」するなら、最低でも(1)である続けることが、自分なりの矜持だと思っています。

I'm proud to say that if I'm going to "ignore" it, I'm going to continue to be (1) at least.

例えば、高齢者の権力者に阿ねるなどという理由で、(2)を選択することはしないようにしています。

For example, I try not to choose (2) on the grounds that I am beholden to an elderly authority figure.

―― (性暴力事件で)女は平気で嘘をつく

"Women don't mind lying -- in sexual assault cases"

みたいなセリフは、(2)になる、と思っています。

Such a line would be (2), I believe.

まあ、こういうセリフを、"ノリ"で言ってしまうこともありでしょう。

Well, it's possible to say these lines in the "groove".

居酒屋とか、女子会とかでは"あり"なのかもしれません ―― しかし、

I think it's possible at an izakaya or a girls meeting. However, it's out of the question.

『政治集会やら勉強会やらの公の(我々の血税が投じられて開催された)場などのような、特別な場所』

"Special places, such as public, taxpayer-funded venues for political meetings and workshops"

では、論外です。

しかし、そんな人は滅多にいるものではないです ―― 絶望的に低能で非常識な人間でもない限りは。

But such people are rare. Unless they are hopelessly low and insane.

ましてや、『性暴力被害者』のスレッドで、そんなことをセリフを言う人間は ―― もはや、人間ではない。

Anyone who says lines like that in the "Victims of Sexual Assault" thread, is no longer a human being.

-----

まあ、私だって、結構な頻度で、自分のコラムの中で、エンジニア自虐とか、エンジニア自己批判とかやって来ています。

Well, in my columns, I've been doing a lot of self-deprecation and self-criticism of engineers.

読者に媚びるフレーズも平気で書きますし、権力サイドから目を付けられない程度には、表現にも配慮しています。

I don't care of writing phrases that flatter my readers, and I am careful to express myself in order to avoid pressure from the power side.

私は「社会正義」の為に書いているのではなく、「自分(の娯楽)」の為に書いていていて、そんでもって、これからも書き続けたいからです。

I don't write for "social justice", I write for "my (my) amusement", and I want to keep writing.

その為には、社会弱者を意図的に無視することもあります ―― だって、私の手に負えないこともあるし、私にとって都合の悪いことだってありますから。

To do that, I sometimes deliberately ignore the most vulnerable people in society. Because some things are out of my control, and some things are not good for me.

-----

ただ、それでも「無視」をする時でも ―― 『うしろめたさ』を感じながら「黙り」続けます。

But even when I still "ignore" them -- I continue to "shut up" with a sense of "guilt".

「痛みで苦しんでいる人を、さらに、痛めて苦しめること」がないように気を付けます。

I take care not to "make those who are in pain suffer more and more pain and suffering"

だから、私の無礼な友人たちや、遠慮のない家族たちが、私を見張ってくれていることを、感謝しています。

So I'm grateful that my rude friends and unassuming family members are keeping an eye on me.

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

私が、当初、夫婦別姓制度に反対の立場であったことは、これまで何度もお話してきたと思います。

I think I have told you many times in the past that I was initially opposed to the "conjugal surname system".

同性愛を、精神障害の一態様であるとすら思っていたこともあります。

I once even thought of homosexuality as a form of mental disorder.

今は、そうは思っていません。

Now, I don't think so.

「自分で勉強したから」と言いたいですが、基本的には、「社会の意識の変化に身を委ねてきた」という面が強いです。

I'd like to say "because I learned it myself," however, essentially, I've surrendered myself to the changing attitudes of society.

とはいえ、『多くの人が肯定していれば、多分正しいのだろう』という考え方はリスクがあります。

Nevertheless, the idea that "if a lot of people affirm it, it's probably right" is risky.

しかし、『多くの人が関心を持っているのであれば、ちゃんと自分で調べてみよう』というスタンスなら、良いと思います。

However, if your stance is "if it's the matter that many people are interested in, I'll look into it myself". Then it's good.

-----

新しい考え方(夫婦別姓、同性愛等)を自分に取り込むには、私には結構なエネルギーが必要でした。

It took quite a bit of energy to incorporate new ideas (marital separation, homosexuality, etc.) into my life.

自分の中にある、他の部分の考え方の変更も余儀なくされるからです ―― 正直、これは、「辛い作業」です。

Because it also forces me to change the way of other parts of myself. Honestly, this is "hard work".

特に、既存の価値観で生きてきたシニアにとっては、若い人には想像できないほどの「痛みを伴う」作業なのです。

It's a "painful" process that is unimaginable to younger people, especially for elder people who have lived by existing values.

「痛くて辛い作業」ですので、他人に強要することはできません。

It's "painful work" and I can't force others to do it.

しかし、その「痛くて辛い作業」を経ないと、現状の制度や差別で痛み苦しんでいる人 ―― 私の痛みや辛さとは比較にならない程の ―― に寄り添うことができません。

However, without going through that "painful work," it is impossible to reach out to those who are in pain and suffering from the current system and discrimination. It's so much worse than my pain and hardship.

-----

しかし、基本的には、それは「他人の苦痛」であって、「自分の苦痛」ではありません。

But basically, it's "other people's pain" and not "my pain".

どれほどの痛みや苦しみがあろうが ―― 所詮は、「他人事」です。

No matter how much pain and suffering there is -- it's just for "other people".

あなたは、それを無視したっていいと思います。

You're allowed to ignore it.

私(だけ)は、あなたを責めません。

I (only) don't blame you.

私も、沢山の問題を「無視」し続けています。

I also continue to "ignore" a lot of issues.

私のやっていることは、単なる「問題の数値化」に過ぎません。問題の解決法(ソリューション)に至れているものはほとんどありません。

What I am doing is merely "quantifying the problem". Very few of the problems (solutions) have been reached.

(続く)

(To be continued)

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

(昨日の続きです)

(Continuation from yesterday)

しかし、一方の私は、「完全な死」など希望していません。

But I, on the other hand, have no hope of "complete death".

■理性的な思考が残存しており、

- Reasonable thinking remains,

■自分の意志が第三者に伝達可能で、

- Being able to convey my intentions to a third party

■自分の肉体が可制御の状態にあって、

- My body is in control

■絶望的な苦痛が到来する前に

- Before the arrival of desperate pain

とっとと死んでしまいたい、という気持ちがあります。

I have a feeling that I want to die suddenly.

私は、苦痛回避の死を肯定し、そして、他者にも実施してきました。

I have affirmed the death of pain avoidance and have done it to others.

「いかなる手を尽しても、絶対的に救えない、究極の死」などというのは ―― 本当に、冗談ではありません。勘弁して下さい、と、全力で土下座できるレベルです。

"The ultimate death that I can never save no matter what I do" is not joking. I can kneel down on the ground with saying "Please forgive me "

-----

私が何を言いたいかというと、

What I want to say, is that

『あらゆる手を尽くして延命を施すという考え方』は、昨日の「江端の腕時計」の話と似ていないか

Isn't "the idea of doing everything possible to prolong life" similar to the story of "Ebata's watch"?

ということです。

私の命を制御する側 ―― 例えば

The side that controls my life, for example

■「医師」の立場からすると、命を可能な限り延すことが「職務」であり、

- From the point of view of a "doctor", it is the "duty" to prolong life as much as possible.

■「身内」の立場からすると、命を可能な限り延すことが「権利」である

- From the standpoint of "relatives", it is "right" to prolong life as much as possible.

かのように思えるかもしれない、ということです。

might think this problem as above.

言い換えるのであれば、

In other words, that means,

『私の腕時計は、耐用年数を越えて、すでに廃棄される状態にある』

"My watch has reached the end of its useful life and is already in a state of disposal."

にもかからわず、

however,

『腕時計の意志を無視して、性能劣化している状態で、見苦しい外観を晒され続け、所有者によって動かされて続けられている』

"Ignoring the will of the watch, it continues to be exposed to its unsightly appearance and kept being driven by the owner, with its performance degraded."

ということです。

-----

『腕時計と人命を同じロジックで説明するのは乱暴に過ぎる』と思う人はいるかもしれません。

Some may think that it is too rough to explain a wristwatch and human life with the same logic.

法律や生命倫理、あるいは、その時点の社会通念や常識など、様々な問題を総合的に考えなければならないことは分かっています。

We know that we have to think comprehensively about various issues such as law, bioethics, and social conventions and common sense at that time.

しかし、私は、この問題、一度、ここまで単純化して考えてみる必要があると思っています。

However, I think this problem needs to be simplified to this point once.

―― 私達は、「腕時計の使用者」であると同時に、「腕時計本体」でもあるのです。

We are not only "watch users" but also "watch bodies".

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

私が愛用している時計は、こちらに記載したものです。

This is about my watch repair.

耐用年数をとうに越えており、すでに同じ時計は入手できませんが、電池交換を繰り返しながら、使い続けています。

It's already past its service life and the same watch is no longer available. However I continue to use it, changing the batteries repeatedly.

リストバンドはジョイント部が欠けており、もはやリストバンドの交換もできない状況です。

The wristband is missing a joint and the wristband can no longer be replaced.

ですので

So,

―― Amazonで購入したリストバンドを、瞬間接着剤で、強制的にジョイント

"I buy a wristband from Amazon, with instant glue, to force a joint"

しています。

リストバンドが劣化して、切断した場合には、その接続の部分を無理矢理引き剥がして、固化した接着剤をドライバで削ぎ取っています。

If the wristband deteriorates and is cut, the connection part is forcibly peeled off and the solidified adhesive is scraped off with a screwdriver.

案外なんとかなるものです。

It's surprisingly manageable.

時計に限らず、私は、"モノを直して使い続ける"のが好きです。

Besides watches, I like to "fix things and keep using them."

-----

デバイスを完全に停止するまで使い倒す ―― これは、あまり経済的な行為とは言えません。

"Use it until the device is completely shut down". This is not very economical.

国内消費にも、GDPにも貢献しません。

It does not contribute to domestic consumption or GDP.

私自身「既存システムの積極的な廃棄」をアジテーションしてきた、という自覚すらあります。

I even realize that I have agitated "active disposal of existing systems".

そんな私が『モノを大切にしましょう』などと、おこがましいことが言える立場ではありません。

I'm not in a position to say something, such as "Let's take good care of things."

私は、デバイスの「完全な死」を見届けたいだけです。

I just want to see the "complete death" of the device.

私がいかなる手を尽しても、絶対的に救えない、究極の死を。

The ultimate death that I can never save no matter what I do.

(続く)

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

取り敢えず、週末の成果(ちゃんと動くものではないので、そのまま使うことはお勧めしません)

"client1.go"の内容

package main

import (
	"flag"
	"log"
	"net/url"

	"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", "0.0.0.0:8080", "http service address") // テスト
//var addr = flag.String("addr", "localhost:8080", "http service address") // テスト
var upgrader = websocket.Upgrader{} // use default options

func main() {
	flag.Parse()
	log.SetFlags(0)
	u := url.URL{Scheme: "ws", Host: *addr, Path: "/echo2"}
	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()

	gl := GetLoc{
		ID:  1,
		Lat: 35.653976,
		Lng: 139.796841,
	}

	log.Printf("ID:%d", gl.ID)
	log.Printf("Lat:%f", gl.Lat)
	log.Printf("Lng:%f", gl.Lng)
	//err = c.WriteJSON(mt, gl)
	err = c.WriteJSON(gl)
	if err != nil {
		log.Println("write:", err)
	}
}

"server8.go"の内容

/*
// server7.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 server7.go      (適当なシェルから)
// http://localhost:8080  (ブラウザ起動)
*/

package main

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

	"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

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

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

		gl := new(GetLoc)

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

		log.Printf("ID:%d", gl.ID)
		log.Printf("Lat:%f", gl.Lat)
		log.Printf("Lng:%f", gl.Lng)

		if err != nil {
			log.Println("read:", err)
			break
		}
	}
}

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はクライアント識別子)
			_, _, err := c.ReadMessage() // クライアントからのメッセージの受信(mtはクライアント識別子)
			if err != nil {
				log.Println("read:", err)
				break
			}

			// JSON(位置情報)を無理やり入れてみた

			gl := GetLoc{
				ID:  1,
				Lat: 35.653976,
				Lng: 139.796842,
			}

			//log.Printf("recv_serv: %s", gl)
			//err = c.WriteJSON(mt, gl)
			err = c.WriteJSON(gl)
			if err != nil {
				log.Println("write:", err)
				break
			}
		}
	*/

	gl := GetLoc{
		ID:  1,
		Lat: 35.653976,
		Lng: 139.796842,
	}

	//log.Printf("recv_serv: %s", gl)
	//err = c.WriteJSON(mt, gl)
	err = c.WriteJSON(gl)
	if err != nil {
		log.Println("write:", err)
	}

}

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

func main() {
	flag.Parse()
	log.SetFlags(0)
	http.HandleFunc("/echo2", echo2)           // echo関数を登録 (サーバとして必要)
	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 lang="en">
<head>
    <meta charset="utf-8" />
    <title>PruneCluster - Realworld 50k</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);

    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)がデフォルト

	/*
	// 送信5発(3秒単位)を送信
	ws.onopen = function (event) {
		for (let i = 0; i < 1; i++){
			ws.send("Ebata is great"); 
			//print("send: Ebata is great");
	
			//print("Start sleep");
			sleep(1000);
			//print("End sleep");
		}
	}
	*/

	var markers = [];

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

		// データをマーカーとして登録
		var marker = new PruneCluster.Marker(obj.lat, obj.lng);
		markers.push(marker);
		leafletView.RegisterMarker(marker);

        // leafletView.ProcessView();  // 変更が行われたときに呼び出されなければなりません。		
	}


	/*
	// 100人分を登録する
    var size = 1;
    var markers = [];
    for (var i = 0; i < size; ++i) {
        var marker = new PruneCluster.Marker(35.654543 + (Math.random() - 0.5) * 0.00001 * size, 139.795534 + (Math.random() - 0.5) * 0.00002 * size);

        markers.push(marker);
		leafletView.RegisterMarker(marker);
		
	}
	*/
	

	// ランダムウォークさせる
    window.setInterval(function () {
        for (i = 0; i < 1; ++i) {
			//var coef = i < size / 8 ? 10 : 1;
			var coef = 10;
            var ll = markers[i].position;
            ll.lat += (Math.random() - 0.5) * 0.00001 * coef;
            ll.lng += (Math.random() - 0.5) * 0.00002 * coef;
        }

        leafletView.ProcessView();  // 変更が行われたときに呼び出されれなければならない
	}, 500);


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


    map.addLayer(leafletView);
</script>



</body>
</html>
`))

未分類

(昨日の続きです)

(Continuation from yesterday)

江端:「まあ、それはさておき、『一旗』って何だ?」

Ebata: "Well, aside from that, what's a 'the flag' ?"

嫁さん:「『故郷に錦を飾る』とも言うね」

Wife: "It's also called 'return to their hometown in glory'"

江端:「『一旗』から想起されるイメージって、ミュージシャン、アイドル、役者、くらいしか思い付かないんだけど」

Ebata: "The only images that 'the flag' reminds me of are musicians, idols and actors"

嫁さん「あるいは、政治家とか野球選手・・・いずれにしても、この程度が私達のイメージが限界かな」

Wife: "Or a politician or a baseball player... Anyway, I guess this is the limit of our image.

江端:「自分の望みのことが達成できれば、それは、『一旗上がった』ということにならないのかな? 自分なりの目標に対して、それを達成すれば、足るというような」

Ebata: "If they can achieve what they want, is that 'they could raise the flag' ? I suppose it's good enough for my own goals, if I achieve them."

嫁さん「・・・いや、それはちょっと違うかな」

Wife:"...no, that's not enough.

江端:「?」

Ebata:"?"

嫁さん:「『故郷に錦を飾る』と合わせて考えれば、それは、第三者にとって ―― 特に出身地の ―― 多くの人間が、共通して、"成功"と認識できる何かでなければ、成立しない」

Wife: "If they use the phrase of "return to their hometown in glory", the flag should be something that could be perceived as a "success." for many people, especially in their hometown."

江端:「・・・多くの人が共通して価値のあると認められるもの ―― つまり"金"か」

Ebata: "...what most people consider to be of common value -- 'money'"

嫁さん「あるいは、有名になること ―― "名声"も含まれるかな」

Wife: "Or to be famous -- I guess that includes 'fame'"

江端:「第三者から観測可能な"金"と"名声"というとになると ―― ああ、なるほど、『ミュージシャン』などは、分かりやすい」

Ebata: "When it comes to 'money' and 'fame' that can be observed by a third party - ah, I see, 'musicians' is easy to understand.

嫁さん「そうだねえ。そこに至るプロセスが、努力と能力だけでなく、運も必要であり、加えて"その可能性が恐しく小さい"という要件も必要だね」

Wife: "Yes, you're right. The process of getting there requires not only effort and ability, but also luck, and in addition, 'the possibility should be terribly small'.

-----

正直、私は、

Honestly, I thought that

―― 面倒くさいな

"It's troublesome"

と思いました。

私は、「自分の意志で目指す成功」であるならともかく、「他人の目に映る成功」なんぞの為に、自分が振り回されることなど、ゴメンです。

I don't want to be at the mercy of "success in the eyes of others", but "success of my own volition.

-----

最後にいらんことを書き残します。

Finally, I'll leave you with something unnecessary.

こういう、他人視点の"一旗"幻想を持っている方は、このページの一読をお勧めします。

If you have an illusion of the flag in the eyes of others, let you read this article.

文字を読むのが面倒であるなら

If you can't be bothered to read the words, it is O.K. to watch these figures.

この図と、この図と、この図、を見るだけでも、結構です。

参考くらいにはなると思います。

I think it's at least a reference.

未分類

  1. 内容:位置情報をサーバからクアイアント(Webブラウザ)に1回のみ一回だけ送信して、その情報を、適当にランダムウォークさせるだけのプログラム
  2. 方針 できるだけ、プログラムは汚いまま残す
/*
// server7.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 server7.go      (適当なシェルから)
// http://localhost:8080  (ブラウザ起動)
*/

package main

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

	"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

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はクライアント識別子)
			_, _, err := c.ReadMessage() // クライアントからのメッセージの受信(mtはクライアント識別子)
			if err != nil {
				log.Println("read:", err)
				break
			}

			// JSON(位置情報)を無理やり入れてみた

			gl := GetLoc{
				ID:  1,
				Lat: 35.653976,
				Lng: 139.796842,
			}

			//log.Printf("recv_serv: %s", gl)
			//err = c.WriteJSON(mt, gl)
			err = c.WriteJSON(gl)
			if err != nil {
				log.Println("write:", err)
				break
			}
		}
	*/

	gl := GetLoc{
		ID:  1,
		Lat: 35.653976,
		Lng: 139.796842,
	}

	//log.Printf("recv_serv: %s", gl)
	//err = c.WriteJSON(mt, gl)
	err = c.WriteJSON(gl)
	if err != nil {
		log.Println("write:", err)
	}

}

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 lang="en">
<head>
    <meta charset="utf-8" />
    <title>PruneCluster - Realworld 50k</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"/>      


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

    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)がデフォルト

	/*
	// 送信5発(3秒単位)を送信
	ws.onopen = function (event) {
		for (let i = 0; i < 1; i++){
			ws.send("Ebata is great"); 
			//print("send: Ebata is great");
	
			//print("Start sleep");
			sleep(1000);
			//print("End sleep");
		}
	}
	*/

	var markers = [];

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

		// データをマーカーとして登録
		var marker = new PruneCluster.Marker(obj.lat, obj.lng);
		markers.push(marker);
		leafletView.RegisterMarker(marker);

        // leafletView.ProcessView();  // 変更が行われたときに呼び出されなければなりません。		
	}


	/*
	// 100人分を登録する
    var size = 1;
    var markers = [];
    for (var i = 0; i < size; ++i) {
        var marker = new PruneCluster.Marker(35.654543 + (Math.random() - 0.5) * 0.00001 * size, 139.795534 + (Math.random() - 0.5) * 0.00002 * size);

        markers.push(marker);
		leafletView.RegisterMarker(marker);
		
	}
	*/
	
	/*
		ちなみにオブジェクトの削除は、以下の様らしい
		// Remove all the markers
		pruneCluster.RemoveMarkers();

		// Remove a list of markers 
		pruneCluster.RemoveMarkers([markerA,markerB,...]);  リスト単位で消去する、ことか → marker[0],maker[1] と指定して消していくのだと思われ

		// こんなのがあった random.10000-delete.html
		document.getElementById('delete').onclick = function () {
			if (size >= 1000) {
				var deleteList = markers.splice(0, 1000);
				leafletView.RemoveMarkers(deleteList);
				size -= 1000;
			}
			return false;
		};

	*/
	
	// ランダムウォークさせる
    window.setInterval(function () {
        for (i = 0; i < 1; ++i) {
			//var coef = i < size / 8 ? 10 : 1;
			var coef = 10;
            var ll = markers[i].position;
            ll.lat += (Math.random() - 0.5) * 0.00001 * coef;
            ll.lng += (Math.random() - 0.5) * 0.00002 * coef;
        }

        leafletView.ProcessView();  // 変更が行われたときに呼び出されれなければならない
	}, 500);


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


    map.addLayer(leafletView);
</script>



</body>
</html>
`))

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

最近、NHKの「ドキュメント72時間」を見ています。

Recently, I've been watching NHK's "documentary series 72 Hours".

ある一定の場所で、72時間、市井の人々の取材を放送する番組です。

It is a program that broadcasts 72 hours of coverage of the people of the city in a certain location.

■NHKスペシャルのように、『聞き漏らさずに視聴しなければ』というような緊張間もなく、

There's no need to be tense like the NHK specials, where I have to watch it without missing a beat.

■他の民放番組のように、特異な行動や言動をする人を、面白可笑しく編集するでもなく(自分の街をインタビューされたシーンは、かなり不快だった)

It's not like other commercial TV shows that edit out people who act and behave in a peculiar way for fun or funny.(The scene where they interviewed someone from my town was quite uncomfortable.)

肩の力を抜いて見られるので、結構気にいっています。

I like it a lot because I can relax to watch it.

もっとも、この「ドキュメント72時間」にしても、市井の人々の「いい感じのコメント」や「琴線にふれるコメント」だけを集めている、という感は否めません。

However, it cannot be denied that this "documentary series 72 Hours" is a collection of "good comments" and "heartful comments" from the people.

しかし、番組として構成する以上、それは仕方のないことです。

But as long as it's structured as a program, I think that it cannot be helped.

-----

先日、嫁さんと2人で、夕食を食べながら、「東京・隅田川 花火のない静かな夏に」を見ていました。

The other day, my wife and I were watching "Tokyo Sumida River, Quiet Summer without Fireworks" while eating dinner.

そこでは、「一旗上げようと東京にやって来て」「それが叶わずに今に至る」という高齢者の方のインタビューシーンが出てきました。

There was an interview scene with an elderly man who said that "he came to Tokyo to make a name for himself", and "he couldn't do it".

先日の日記にも記載したのですが、

I mentioned it in my diary the other day.

―― "一旗"って何だろう?

"What does "the flag" mean?"

と、ずっと考えています。

I keep thinking about it.

-----

江端:「『東京に出てくれば、何かチャンスがある』という発想が良く分からん。そもそも、東京に、語るほどのメリットがあるのか?」

Ebata: "I don't understand the idea that "there are opportunities if you come to Tokyo". In the first place, are there any advantages to Tokyo that are worth talking about?

嫁さん:「大学の数、仕事の数、出会う人間の数、娯楽の数、手に入れられる情報とその速度、その他もろもろ違うでしょう」

Wife: "The number of colleges, jobs, people you meet, entertainments, and the information you can get and the speed at which you can get it, and everything else will be different"

江端:「まあ、私の場合、ネットと通販があれば、十分に足るけど ―― まあ、その通りかなぁ。特に「人脈」については、都会は圧倒的に有利かもしれない」

Ebata: "Well, in my case, the internet and mail order are enough for me. However, I guess you're right. Especially when it comes to "networking", the city may have a huge advantage.

嫁さん:「まあ、パパの場合は『人間嫌い』だから、そのメリットはないと思うけど」

Wife: "Well, in your case, I don't think you have the benefit of that because you are a misanthrope.

(続く)

(To be continued)

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

ようやく動いた。疲れた。JSONを送り込むのは、明日以降ね。

忘備録

  • カレントディレクトリの中にdistというディレクトリを作って、LeafletStyleSheet.css PruneCluster.d.ts PruneCluster.js を放り込んだ
  • カレントディレクトリの中にLeafletStyleSheet.css,PruneCluster.d.ts,PruneCluster.js,examples.cssを放り込んでおいた
  • 上記はあまり意味なかったらしい(プログラムの下を御参照)。

 

使い方は、

>go run server5.go

http://localhost:8080

で起動する。

/*
// server5.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 server5.go      (適当なシェルから)
// http://localhost:8080  (ブラウザ起動)
*/

package main

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

	"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

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はクライアント識別子)
		_, _, err := c.ReadMessage() // クライアントからのメッセージの受信(mtはクライアント識別子)
		if err != nil {
			log.Println("read:", err)
			break
		}

		// JSONを無理やり入れてみた

		gl := GetLoc{
			ID:  1,
			Lat: 35.653976,
			Lng: 139.796842,
		}

		//log.Printf("recv_serv: %s", gl)
		//err = c.WriteJSON(mt, gl)
		err = c.WriteJSON(gl)
		if err != nil {
			log.Println("write:", 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")
	homeTemplate.Execute(w, "")
}

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 lang="en">
<head>
    <meta charset="utf-8" />
    <title>PruneCluster - Realworld 50k</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="PruneCluster.js"></script>

    <link rel="stylesheet" href="examples.css"/>
</head>
<body>
<div id="map"></div>

<script>
    var map = L.map("map", {
        attributionControl: false,
        zoomControl: false
    }).setView(new L.LatLng(35.654543, 139.795534), 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)がデフォルト

    var size = 100;
    var markers = [];
    for (var i = 0; i < size; ++i) {
        var marker = new PruneCluster.Marker(35.654543 + (Math.random() - 0.5) * 0.00001 * size, 139.795534 + (Math.random() - 0.5) * 0.00002 * size);

        markers.push(marker);
        leafletView.RegisterMarker(marker);
    }

    window.setInterval(function () {
        for (i = 0; i < size / 2; ++i) {
            var coef = i < size / 8 ? 10 : 1;
            var ll = markers[i].position;
            ll.lat += (Math.random() - 0.5) * 0.00001 * coef;
            ll.lng += (Math.random() - 0.5) * 0.00002 * coef;
        }

        leafletView.ProcessView();
    }, 500);

    map.addLayer(leafletView);
</script>
</body>
</html>
`))

ところが、今朝、PC断ち上げて再起動させてみたところ、昨日の状況に戻ってしまいました。

試しに、自分のサーバ(kobore.net)に、PruneCluster.jsexamples.cssをアップして、さらにdistというディレクトリ掘って、LeafletStyleSheet.cssを放りこんでみたら動きました。

<script src="PruneCluster.js"></script>
<script src="http://kobore.net/PruneCluster.js"></script>

<link rel="stylesheet" href="examples.css"/>
→ <link rel="stylesheet" href="http://kobore.net/examples.css"/>

まあ、いずれ修正するとして、動くならなんでも良いので、このまま進めます。