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

私は、大学時代を除き、ティーンエイジャ全般を俯瞰して眺めると、あまり楽しくなかったように思います。

I don't think it was a lot of fun when I looked at teenagers in general, except when I was in college.

万一、私が著名人になって、私の通っていた高校から講演依頼があったとしても『絶対に断わる』だろうなぁ、と思っています。

Even if I become a celebrity and receive a lecture request from the high school I attended, I think I will definitely refuse.

高校には、私をいじめていた奴が2人いて、今でもその2人の名前を覚えていて、今でも私は許していないから、ということもあるのですが ―― それだけでもありません。

There were two guys in high school who were bullying me, and I still remember their names, and I still don't forgive them. But that's not all.

つまるところ、私は「学校」が「嫌い」だったのだと思います。

After all, I had hated "school".

しかし、「大学」は大好きだったので、私が憎悪してきたのは、

However, I loved "university", so I think that what I hated was

―― 「クラス」という「箱」

A "box" called "class"

だったのだと思います。

-----

■教師にその所掌範囲と責任範囲を明確にさせ、それ以外の管理対象(生徒)は無視しても良いと決められた「管理領域」

- "Management area" where it was decided that the teacher should clarify the scope of jurisdiction and responsibility, and the other management targets (students) could be ignored.

■無目的に強制的に集められたにも関わらず、特に理由もなく、他のクラスと比較され、勝たなければならないように仕向けられる「クラスター」

- "Cluster" that was forced to be gathered for no purpose, but is compared to other classes and forced to win for no apparent reason.

■そして、私のやることを妨害し、協力するどころか足をひっぱり続けた、邪悪な「クラスメイト」

- Evil "classmates" who interfered with what I was doing and kept pulling my legs instead of cooperating.

-----

運動会やら文化祭やらのこの時期になると、

At this time of the athletic and school festival, I remember

―― 私が、休日を返上してたった一人で作った文化祭の展示物の前で、集合写真を取ったクラスの連中

"The classmate who took a group photo in front of the cultural festival exhibit that I made by myself after returning from the holidays"

を思い出します。

あれから何十年を経過した今であっても、私は、彼らを許すことができません。

Even now, decades after that, I can't forgive them.

-----

だから、もしも私が著名人になって、私の通っていた高校から講演依頼があったとしても

So, even if I become a celebrity and receive a lecture request from the high school I attended, I think

『絶対に断わる』

"I will definitely refuse"

と思うのです。

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

査読をお願いしていた機関から、私の執筆中の原稿のドラフトが戻ってきました。

My draft in progress came back from the institution I had asked to review it.

一部を抜粋します。

Here are some excerpts.

===== ここから =====

===== From here ======

なお、本文における「リスク」及び「不安」は、以下の意味で用いている。

The terms "risk" and "anxiety" in the text are used with the following meanings.

「リスク」とは、行動変容対象者(個人、企業)が受ける不利益の可能性であり、行動変容誘導システムによる行動変容の要請に承諾することで変化する。

"Risk" is the possibility of disadvantages to the behavior change target (individuals, companies), and changes by accepting the behavior change request by the behavior change guidance system.

例えば、個人においては、ウイルス性の感染症に罹患して、病欠を強いられて収入が断たれる可能性、及び、死亡する可能性などである。

For example, an individual may suffer from a viral infectious disease and be forced to take sick leave and lose his or her income, or may die.

また、企業においては、従業員に感染者が発生することによって、営業活動が中断させられ、経済的な損失を受ける可能性などである。

In addition, in a company, the occurrence of an infected person in an employee may interrupt business activities and cause financial loss.

一方「不安」とは、行動変容対象者が行動変容誘導システムによる行動変容の要請に承諾することで、他者とは異なる行動をとり、自分だけが不利益(解雇及び赤字業績など)を受けるかもしれないと感じる心配又は恐怖の感情である。

On the other hand, "anxiety" means that a person who is subject to behavior change accepts a request for behavior change by the behavior change guidance system, and acts differently from others, and only he / she suffers disadvantages (dismissal, deficit performance, etc.) feelings of anxiety or fear that you may feel.

なお、本文では、リスクとして、ウイルス性などの感染症に罹患する感染リスクを例にとって説明するが、リスク及び不安は感染症に対してのみ生じるものではない。

In this text, the risk of infection with a viral or other infectious disease will be explained as an example, however, risks and anxieties do not only occur for infectious diseases.

例えば、地震及び巨大台風などの災害では、対象者は避難しても自宅で待機してもリスクがあり、そのいずれを選ぶにしても、他人と異なる行動をする決断には不安が伴う。

For example, in a disaster such as an earthquake or a huge typhoon, there is a risk that the subject may evacuate or wait at home, and regardless of which one is selected, the decision to act differently from others is accompanied by anxiety.

これらのリスク及び不安は、行動変容の要請の承諾を妨げる要因となっている。

These risks and anxieties are factors that hinder the acceptance of behavior change requests.

以下、行動変容誘導システムについてより詳細に説明する。

Hereinafter, the behavior change guidance system will be described in more detail.

===== ここまで =====

===== To here ======

上記の抜粋を纏めると、

To summarize the above excerpts, that is,

―― 人を動かしたいなら「"リスク"を数値化して、"不安"を"恐怖"に持ち込め」

"If you want to move people, Quantify the 'risk' and Raise 'anxiety' to 'fear'"

です。

『「不安を煽って、世界を動かそう」という発想が、そもそも、古今東西の独裁者と変わらんなぁ』とも思いました。

I also thought, "The idea of 'agitating anxiety and moving the world' is the same as the dictator of the east and west in the first place."

まあ、最近は、独裁者などという立派なモノでなくても、誰でもSNSを使って普通にできるようになってきています。

Well, these days, anyone can use SNS to do it normally, even if it's not a dictator.

でも、「数値化」は、見たことがないかな。

But I wonder if I have never seen "quantification".

-----

私が提案している、この「行動変容誘導システム」は、

About this "behavior change guidance system" that I am proposing, even if I rewrite the following, the meaning seems to be understood.

「独裁者意志決定支援システム」

"Dictator decision support system"

とか

「炎上を援用した売名システム」

"Brand name system that uses the Internet flame"

と書き直しても、意味は通じそうです。

-----

まあ、審査の段階で、確実に弾かれるとは思いますが。

Well, I think it will definitely be rejected at the examination stage.

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

昨日の日記に関連するお話は、これにて最後にしたいと思います。

This is the last story related to yesterday's diary.

-----

今回、絶対的な一次リソースとしての『「LGBT」支援の度が過ぎる』を読み返しました。

This time, I read back "The level of support for "LGBT" is too high" as an absolute primary resource.

が、当時と同じように、この文章の「読みにくさ」には、困りました。

However, as at that time, I was troubled by the "difficulty of reading" of this sentence.

"文章構成"がなっていなくて、"内容"に入りこむことができなかったからです。

I couldn't get into the "content" because the "sentence structure" was so bad.

-----

そもそも、私は、この文章を"論文"と称呼されていることに、強い違和感を感じます。

In the first place, I feel a strong sense of discomfort in calling this sentence a "paper".

これが"論文"なら「私」が可哀想過ぎます。

If this is a "paper", then "I" is too pitiful.

私は、論文とは、

I think that paper is

『仮説と、エビデンス(証拠)と、客観的なデータ(または計算)と、そこから導かれるロジカルな結論を記載するもの』

"A statement of a hypothesis, evidence, objective data (or calculations), and the logical conclusions to be drawn from them"

と、思っています。

そして、論文の執筆プロセスは、

And the process of writing a paper is that

- 査読者にボロクソに(但しロジカルに)批判されて、

- I am severely (but logically) criticized by the peer reviewers.

- 何度も検討や計算をやりなおして、

- I have to go through all the reviews and calculations again and again.

- それでも受理されず、

- the paper isn't accepted.

- 再投稿を繰り返し、

- I repost it repeatedly

- ようやく掲載の許諾を得る

- I finally get permission to publish it.

というものだと思っています。

-----

という訳で、私から、この文章の著者への提案です。

So, this is my suggestion to the author of this article.

一度、「新潮45」で発表された内容について、大学等でちゃんと論文指導を受けて、国内の学会に「査読付き論文」として提出してみるのはいかがでしょうか。

Once, about the contents released at "Shincho 45", you received proper dissertation guidance at universities etc. and how about submitting it as a "peer-reviewed paper" to a domestic academic society?

本人の思想がどうあれ、論文としての体(てい)を成していれば、原則、学会は論文を受理します(というか、受理しなければならないハズです)。

Regardless of the person's thoughts, the academic society will accept the dissertation (or rather, it must be accepted) as long as it forms the body of the dissertation.

本人の主観か客観的事実かが明確でない箇所があれば、「引用文献を明示しろ」と指導が入ります。

If there is a part where it is not clear whether the person is subjective or objective, you will be instructed to "specify the cited document".

面倒ですが安心ではあります。

It's a hassle, but it's safe.

国内の学会が受理してくれなけば、外国の学会に提出すれば良いです。

If the domestic academic society does not accept it, you can submit it to a foreign academic society.

英文翻訳が必要になるとは思いますが、翻訳は外注すれば足ります。

I think you will need an English translation, but it is enough to outsource the translation.

もし、世界中のどの学会にも受理して貰えなければ(そんなことはないとは思いますが)、査読のないカンファレンスペーパーの投稿と、学会講演を行うという手もあります。

If it is not accepted by any academic society in the world (I don't think that is the case), you can post an unrefereed conference paper and give a lecture at the academic society.

事前にアナウンスしておけば、多くの聴講者を集めることもできるでしょう。

If you announce it in advance, you will be able to attract a large number of listeners.

-----

先ずは、出身大学でお世話になった先生に、ご相談することからお勧めします。

First of all, I recommend that you consult with the teacher who helped you at your university.

学会や先生から拒否されたら、一番最後に、私(江端)にご相談下さい。

If you are rejected by an academic society or a teacher, please contact me (Ebata) as the last line.

-----

新潮45の『「LGBT」支援の度が過ぎる』を、

According to "The level of support for "LGBT" is too high" in Shincho45

■きちんとした査読付き論文で読める

- If I can read it in a proper peer-reviewed dissertation

または

or

■ロジカルな内容での講演を聴講できる

- If I can listen to a lecture with logical content

のであれば、私は、支援を惜しみません(本当です)。

I'm willing to help (it's true).

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

PruneClusterのマーカを一個づつ消すには、面倒でも以下のようにしなければならない

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

ちなみに、インターバル関数で、定期的にProcessView()を叩いておかないと更新されないことにも注意のこと。

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

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

  • 背景
    • 事業部に散々脅かされた
    • 「もし、ハックされたら研開(というか江端一人)で責任取れよ」と念を押された
    • AWSコンソールは、江端のみにログイン権限があるので、ここからいじるのは難しいそう
  • 江端予測
    • EC2への直接の攻撃・または侵入
      • 一応SSHアクセスはできる状態
      • SSHによる攻撃はかなり難しいのではないか(秘密鍵がある限り)
    • EBLへの攻撃・または侵入
      • 無闇なアタックはできるだろうが、内部に入ることはできないのでは?
    • 取られる情報
      • 個人情報はないので、個人情報の流出は不可能だが、ユーザ利用情報やら運行情報が取られる可能性もある
  • 江端が調べた範囲のこと
    • SQLインジェクション
      • WebからSQLに触れないので意味なし
    • XSS(クロスサイトスクリプティング)
      • Webサイトのリンクは限定的であり、外部から改竄される余地がない
    • バッファオーバーフロー
      • ELBでEC2を保護しているから、サービスは落せない(?)
    • WebDAV
      • 本サービスでは使っていないので関係なし
    • FTPS(FTP over SSL)やSFTP(SSH File Transfer Protocol)等)を採用しているか
      • FTPサーバ上げる予定がないので、自動的にこれを採用することになる
    • メールサーバ
      • メールサーバがない
    • CMS
      • 使用しない
    • 意図しないサーバへのゾーン転送の防止
      • 発生しえない
    • 安全なHTTPS通信
      • TLSを利用したhttps通信を使用
    • 社外公開サーバ セキュリティ対策リスト_20191007.xlsxにて確認済み
  • 江端不明点
    • EC2からIAMを書き換えることって可能なのか?

未分類

■サーバ側で、通信エラーが発生したら、問答無用でbreakしてループの外に追い出した。

/*
// server13.go ペアはclient8.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  (ブラウザ起動)
*/

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) // クライアントからのメッセージの受信

		// 原因不明の対処処理
		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)
				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)
				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)
				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 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)がデフォルト

	ws.onopen = function (event) {
	}

	var markers = [];

	// 受信すると、勝手にここに飛んでくる
	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);
			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]);
					//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>
`))
■クライアント側は、1000個のGoルーチンが全部終わるまで待つようにした
func main() {

	var wg sync.WaitGroup

	for i := 1; i < 1000; i++ {
		wg.Add(1) // goルーチンを実行する関数分だけAddする。
		go passenger(i, &wg)
	}
	// goルーチンで実行される関数が終了するまで待つ。
	wg.Wait()
	// time.Sleep(250 * time.Second)
}

func passenger(count int, wg *sync.WaitGroup) {
   ////.............................
}
■クライアントプログラムは以下の通り
// client8.go ペアは server13.go

package main

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

	"github.com/gorilla/websocket"

	"math/rand"
	"time"
)

// 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") // テスト

func random(min, max float64) float64 {
	return rand.Float64()*(max-min) + min
}

func main() {

	var wg sync.WaitGroup

	for i := 1; i < 1000; i++ {
		wg.Add(1) // goルーチンを実行する関数分だけAddする。
		go passenger(i, &wg)
	}
	// goルーチンで実行される関数が終了するまで待つ。
	wg.Wait()
	// time.Sleep(250 * time.Second)
}

func passenger(count int, wg *sync.WaitGroup) {

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

	defer wg.Done() // WaitGroupを最後に完了しないといけない。

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

	rand.Seed(time.Now().UnixNano())

	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:  0,
		Lat: 35.653976,
		Lng: 139.796821,
	}

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

	gl2 := new(GetLoc)
	err = c.ReadJSON(gl2)
	log.Printf("count:%d after1 ID:%d", count, gl2.ID)
	log.Printf("count:%d after1 Lat:%f", count, gl2.Lat)
	log.Printf("count:%d after1 Lng:%f", count, gl2.Lng)

	gl.ID = gl2.ID
	for i := 0; i < 20; i++ {
		gl.Lat += random(0.5, -0.5) * 0.00001 * 10 * 5
		gl.Lng += random(0.5, -0.5) * 0.00002 * 10 * 5

		log.Printf("count:%d-%d before 2 ID:%d", count, i, gl.ID)
		log.Printf("count:%d-%d before 2 Lat:%f", count, i, gl.Lat)
		log.Printf("count:%d-%d before 2 Lng:%f", count, i, gl.Lng)

		err = c.WriteJSON(gl)
		if err != nil {
			log.Println("write:", err)
		}
		gl2 := new(GetLoc)
		err = c.ReadJSON(gl2)
		log.Printf("count:%d-%d after 2 ID:%d", count, i, gl2.ID)
		log.Printf("count:%d-%d after 2 Lat:%f", count, i, gl2.Lat)
		log.Printf("count:%d-%d after 2 Lng:%f", count, i, gl2.Lng)

		time.Sleep(1 * time.Second) // 1秒休む
	}

	gl.ID = gl2.ID
	gl.Lat = 999.9
	gl.Lng = 999.9

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

	err = c.WriteJSON(gl)

	err = c.ReadJSON(gl2)
	log.Printf("count:%d after3 ID:%d", count, gl2.ID)
	log.Printf("count:%d after3 Lat:%f", count, gl2.Lat)
	log.Printf("count:%d after3 Lng:%f", count, gl2.Lng)
}

■このクライアント2つ(合計2000オブジェクト)動かしても、落ちなくなった

ようやく一安心

 

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

昨日の日記でも記載致しましたが、今、私はとある人物(政治家)についての、かなりの量の調査をしてきましたが、正直疲れてしまいました。

As I mentioned in yesterday's diary, I've just done a fair amount of research on a certain person (a politician) and I have to admit, I'm tired of it.

結論から言うと、

In conclusion.

―― この人の狂い方の「ルール」が分からない

"I cannot understand what the "rules" of this person's madness are"

------

私、これまで、結構な時間をかけて、人口問題、少子化問題、LGBT、生産性などについて、書籍や論文を読み捲り、仮説を立てて、計算モデルを設計した上で、コンピュータを使って計算し尽くしてきました。

I have spent quite a bit of time reading books and papers on population issues, fertility, LGBT, productivity, etc., making hypotheses, designing calculation models, and doing all kinds of calculations on computers.

■「LGBT」の関係者への直接の取材を行い、記事掲載後もFTMやMTFの方から相談を受け続けており、

- I interviewed the people involved in "LGBT" directly and continued to receive consultations from FTM and MTF even after the article was published.

■「人口問題」については1億2700万のエージェントを使った、数十時間におよぶ国民全数のコンピュータシミュレーションを行い、

- Regarding the "population problem", we conducted a computer simulation of all the people for dozens of hours using 127 million agents.

■「生産性」について徹底的な調査と考察を行い、「一義的に定義できる"生産性"なんぞは存在しない」と断言した

- After conducting a thorough investigation and consideration of "productivity", he asserted that "there is no" productivity "that can be uniquely defined."

当の本人です。

I am the person who have done them.

そんでもって、

In addition,

―― 朧げながらの蜃気楼のような全体像が見えてから、"何"かを語り出す

"After seeing the whole picture like a mirage while being hazy, I start talking about "something"

という、なんとも効率の悪いアプローチで、社会問題を見てきました。

I have seen social problems with an inefficient approach.

-----

私のアプローチは、「仮説とデータと計算」で、現在を調べ、そして、未来を予測する、というものです。

My approach is to look at the present and predict the future with "hypotheses, data and calculations"

私は、別に「他人を説得したい」などとは1mmも思っておらず、上記のアプローチは、「自分が自分に納得させれば足る」ものだからです。

I don't think "I want to persuade others" at all, and the above approach is "it's enough if I convince myself".

私は、自分を騙せれば、それで足るのです。

If I deceive myself, that's enough.

-----

この人も、私と同じように、「他人を説得したい」などとは1mmも思っていないのかもしれません。

This person, like me, may not even think "I want to persuade others" at all.

違いがあるとすれば、「仮説とデータと計算」ではなく、「証拠なし、ロジック無視の、徹底した主観」であるという点です。

The only difference is that it's not "hypothesis, data, and math," but "no evidence, logic-ignoring, thorough subjectivity."

―― ラクでいいな~

"It seems to be enjoyable"

と思いました。

I think deeply,

このくらい、「ロジックもなく、証拠もなく、自分を騙すころができるのであれば、どんなに人生がラクだろうか」と思うと、本当に、心の底から「羨しい」です。

When I think, "How easy is life if I can deceive myself without logic and evidence?", I really envy her from the bottom of my heart.

-----

私は、「人生狂ったものが勝ち」と思っています。

I think "Lunatics will win eventually".

しかし、私の狂い方には強い制約が伴っている(証拠・データ主義、弱者視点、ロジックの一貫性)分、"弱い"です。

However, my madness is "weak" because of the strong constraints (evidence / dataism, weak perspective, logic consistency).

私の狂い方は、この人の狂い方と比べると、大人と赤子くらいの差があります。

Compared to this person's madness, my madness is about the difference between an adult and a baby.

まあ ―― この人のような「みっともない狂い方」をするくらいなら、死んだ方がマシだ ―― とは思っていますけど。

Well, I think it's better to die than to go "crazy unsightly" like this person.

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

キーワード: 切取り、切り取り、削除、圧縮、キャプチャ、画面、編集、

VideoSmaller動画のファイルサイズをオンラインで小さくする

■Avidemux/aviUtl→動画(mp4)のいらん部分を切りすてる

■amuseGraphics → これは使ったことないなぁ

■AG-デスクトップレコーダー → PC画面をキャプチャする(使い倒している)

■RealPlayer →wmvファイルをmp4に変換するのに使っている(ちなみにVLCでは、結構な音ずれが発生する)

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

本日の日記は、10月8日のSさんとのメールのやりとりの続きになります。

Today's diary is a continuation of the email exchange with Mr. S on October 8th.

========

江端様

Mr. Ebata

再度情報を確認し直した結果、1次ソースとなる議事録ないし答弁動画は公開されてなく、杉田水脈氏のオフィシャルサイトの記事2件(9月26日・10月1日投稿記事)と、日本会議会員の橋本琴絵氏の10月1日のツイートがもととなり、発言問題に対する反論が起きていました。

As a result of reconfirming the information, the minutes and answer videos that are the primary source have not been released, and there are two articles on Ms.Sugita's official website (posted on September 26th and October 1st). Based on the tweet by Mr. Kotoe Hashimoto, a member of Nippon Kaigi, on October 1st, there was a counterargument to the remark problem.

(確認済みの情報と思われますが、一応記載させていただきます。)

(It seems that the information has been confirmed by Mr. Ebata, but I will describe it for the time being.)

杉田水脈公式サイト(10月1日)

Mio Sugita Official Website (October 1st)

橋本琴絵ツイート

Kotoe Hashimoto Tweet

上記の情報では慰安問題に対しての発言であったことを報告していますが、発言の有無、また発言の意図に関しては、懸念を受ける本人からの発言、そして居合わせた議員の秘書からの伝聞という真偽の証明ができない情報しかないため、証拠たるソースとはなりえませんでした。

The information above reports that the statement was in response to the comfort problem issue. According to whether or not the statement was made, or intent of the statement, these were information that could not be proven to be true because they were statement from the person concerned, or from the hearsay from the congressman's secretary who was there. Therefore, it could not be a source of evidence.

(自分が確認した、と思っていた動画は、杉田水脈氏の別な主張を紹介していた動画でした。)

(The video I identified, I thought, was a video that introduced another claim by Ms. Sugita Miho.)

確度の低い情報を基に意見してしまったことをお詫び申し上げます。

I apologize for basing my opinion on inaccurate information.

また杉田氏の発言により、自民党部会は討論内容の社会への影響と発言の自由を鑑み、非公開という方針をとっているため、今回の1次ソースは公開されることはなく、検討のしようがない問題ということもわかりました。

Also, according to Sugita's statement, the LDP subcommittee has adopted a policy of withholding information from the public in consideration of the impact of the debate on society and freedom of speech.

(非公開の部会内容を外部に漏らした関係者がいる、という事実のほうが深刻な問題だと思いますが…)

(I think the fact that someone leaked the contents of the closed session to the outside world is the more serious issue...)

#以下、ご本人の所感の記載の為、江端独断にて中略

# Hereafter, due to the description of the personal feelings, omitted by Ebata's discretion

=====

Sさま

Mr. S

お返事遅れまして申し訳ありません。

I'm sorry for the late reply.

ご指摘を頂きましてから、ここ2日間ほど、私なりの調査を行った結果、以下の結論に達しましたのでご報告申し上げます。

As a result of my own research for the past two days after receiving your suggestions, I would like to report the following conclusions.

1. 結論

1. Conclusion

(1)10月7日の私の日記について、現時点においては、追加、削除、変更等を行なわないこととします。

(1) I will not add, delete, or change my diary on October 7th at this time.

(2)但し、今後、新しい証拠に基づき、私の心証を変えるに足る事実が判明した場合は、上記(1)の限りではありません。

(2) However, the above (1) does not apply if in the future, based on new evidence, the facts are found to be sufficient to change my mind.

2. 調査状況

2. Survey approach

(1)調査方針

(1) Investigation policy

(a)本件に関する、事件発生から現在までの経緯の概要把握

(a) An overview of the circumstances of this case, from the occurrence of the incident to the present

(b)本件に関する一次情報の調査

(b) Investigation of primary information about the case.

(c)大手通信社の内容の調査

(c) Survey of the contents of major news agencies

(d)江端が、20年以上に渡り"定点観測"の基準点としてきた、批評家のコメント

(d) Critics' comments that Ebata has used as a reference point for "fixed-point observations" for over 20 years

(e)Google検索による上位100件程度の本件の記事に関する調査

(e) Research on the top 100 or so articles in this case through Google searches.

(f)本件ではないが、過去の確定的な一次情報の再調査と、Twitterコメント、およびGoogle Scholarを使った論文の調査

(f) Re-examination of previous definitive primary information outside of this case, as well as Twitter comments and research of the paper using Google Scholar.

これらを全て記載するのは、私には酷なので、以下に実施事項の概要だけ記載して参ります。

owever, it would be too much for me to describe all of these, so I will only outline the implementation items below.

(2)本件に関する、事件発生から現在までの経緯の概要把握

(2) An overview of the circumstances of this case, from the occurrence of the incident to the present

(Step1)いわゆる「女はうそをつく」発言に関して、杉田水脈氏(以下M氏という)が完全否定のコメントを発表

(Step1) Regarding the so-called "woman tells a lie" statement, Mio Sugita (hereinafter referred to as Ms. M) announced a completely negative comment.

(Step2)その後、複数の会議参加者から発言があった旨の確認が取られる

(Step2) After that, it was confirmed that there were comments from multiple conference participants.

(Step3)M氏が発言を認めるが、バックグランドが異なる(×性暴力問題、○慰安婦問題)であったことを追記。

(Step3) Ms. M acknowledged the remark, but added that the background was different (× sexual violence problem, ○ comfort woman problem).

(Step4)これについては、私の認める限り1名がそれに同意するコメント確認されている(それ以外の参加者からの同意コメントはない)

(Step4) Regarding this, as far as I admit, one person has confirmed the comment that agrees with it (there is no consent comment from other participants)

(3)本件に関する一次情報の調査

(3) Investigation of primary information about the case.

概ね、S様と同じ情報です。これ以外の録音や議事録等は発見に至っておりません。

It is almost the same information as Mr.S. No other recordings or minutes have been found.

(4)大手通信社の内容の調査

(4) Survey of the contents of major news agencies

共同通信、および、時事通信について調査を発表。上記(2)についての記載があるが、バックグランドについては、慰安婦問題ではなく、性被害相談に関するスレッドで述べられた、という記載のみ。

As a result of investigating the articles of Kyodo News and Jiji Press, there is a description about (2) above, but only the description that the background was mentioned in the thread on sexual damage consultation, not the comfort woman issue.

この後、M氏の主張するバックグランドに関する訂正や追加記事を発見できず。

After this, I could not find any corrections or additional articles regarding the background claimed by Ms. M.

(5)江端が、20年以上に渡り"定点観測"の基準点としている批評家のコメント

(5) Critics' comments that Ebata has used as a reference point for "fixed-point observations" for over 20 years

概ね(4)に加えて、過去のLGBT、生産性、少子化に関する、いわゆる「新潮45」事件に関しての再批判を行っている。

In general, in addition to (4), he re-criticizes the so-called "Shincho 45" case regarding LGBT, productivity, and declining birthrate in the past.

議論のベースは、やはり(慰安婦問題ではなく)、「性被害相談に関するスレッドで述べられた」との記載あり(ただし、それらに対しての発言の出典がない。出典はM氏以外のインタビューと思われるが、その本人は特定できない状況)

There is a statement that the basis of the discussion was still (not the comfort woman issue) in the thread on sexual damage consultation". (However, there is no source of remarks to them. The source seems to be an interview other than Ms. M, but the person himself cannot be identified)

(6)Google検索による上位100件程度の本件の記事に関する調査

(6) Research on the top 100 or so articles in this case through Google searches.

"水脈" & "女性はいくらでもうそをつけますから"で検索。ヒット数271万件(ちなみに"量子コンピュータ"のみの検索で134万件であり、その約2倍)。

Search for "water veins" & "because women lie easily". 2.71 million hits. (By the way, the number of searches for "quantum computer" alone is 1.34 million, which is about twice that).

上位100件を一通り通読。

I read through the top 100 cases.

基本的には、同内容の羅列であり、杉田水脈氏の主張を裏付ける、あるいは指示する記事数はゼロ。

Basically, they were lists of the same contents, however there are no articles that support or instruct Mio Sugita's claim.

(7)本件ではないが、過去の確定的な一次情報の再調査と、Twitterコメント、Google Scholarを使った論文の調査

(7) Re-examination of previous definitive primary information outside of this case, as well as Twitter comments and research of the paper using Google Scholar.

■「新潮45 "杉田水脈論文"」の再読、

- Rereading "Shincho 45" of "Ms. Miho Sugita's paper", and

■過去の性被害者問題に関するM氏のtwitterコメント(ただし「まとめ」の方)、および、

- Ms. M's twitter comment on past sexual victim issues (but "summary"), and

■Google Scholarをつかった"杉田水脈論文"の論文を、引用数の高いものから5件ほどを精読

- Carefully read about 5 papers from the one with the highest number of citations in the "Miho Sugita's Paper" using Google Scholar.

以上を実施致しました。

I have carried out the above.

3.考察

3. Consideration

上記につきましては、私の調査不足等、誤解、誤読が在ることを、前提とした上で、以下のように考えております。

Regarding the above, I think as follows on the premise that there are misunderstandings and misreads such as my lack of research.

(1)絶対的証拠となる一次情報については、本人とその他の一人だけ(私の調べた限りでは一人という意味)ということで、本件、事実認定には至れませんでした。

(1) Regarding the primary information that is absolute evidence, I could not find the facts in this case because it was only the person and the other person (meaning one person as far as I investigated).

(2)しかしながら、それ以外の状況や証言、その他、M氏本人の本件に関する時間的経緯の振る舞い等、あるいは過去の発言等を、私なりに総合的に勘案して、上記1(1)の結論と致しました。

(2) However, in consideration of other situations, testimony, other behaviors of Ms. M's time history regarding this matter, past remarks, etc., in my own comprehensive consideration, the above 1(1) I made a conclusion.

(3)なお、新しい証拠や事実の表明によっては、上記1(2)を直ちに実施する所存です。

(3) I intend to immediately implement the above 1(2), depending on new evidence and statements of facts.

4. その他

4. Other

なお、江端の、過去の上記1(2)と同様の実施事項については、HIVに関するこの日記の対応が御参考になるかと思います。

Regarding Ebata's past implementation items similar to the 1(2), I think that the correspondence in this diary regarding HIV will be helpful.

5. 謝辞

5. acknowledgements

この度は、本件のご指摘を頂き、誠にありがとうございました。M氏の考え方に関する多角的な再調査が行なうことができ、私なりの明確な立ち位置が確立できたいと考えます。

I would like to thank you for pointing out the importance of this issue, and I believe that I have been able to re-examine Ms. M's thinking from various perspectives and establish a clear position for myself.

今後とも、私の記事を監視頂き、当方の誤解や誤記についてご指摘頂けましたら幸甚と存じます。

I would be grateful if you would continue to monitor my articles and point out any misconceptions or errors in my articles.

何卒、よろしくお願い申し上げます。

Thank you very much for your support.

以上

2020年10月9日

October 9, 2020.

江端智一

Tomoichi Ebata

=====

江端様

Mr. Ebata.

確認と返信が遅くなってしまい、申し訳ございません。

I apologize for the delay in confirming and replying.

大変な時間をかけての調査と検討を行い、そのうえでの見解を出していただき、申し訳ございませんでした。

I am sorry for your great amount of time spent on researching and reviewing the matter and for the views you have taken on the matter.

ここまでの情報と根拠を出していただいたのですから、日記の記載に関しては一切の反論、意見はございません。

Since you have given me this much information and evidence, I have no objections or opinions about the diary entries.

また、江端様の情報調査、裏とりのやり方を拝見させていただき、調査に関する時間的コストの大きさと、ノウハウについて勉強になりました。

In addition, I learned a lot about the time cost and know-how involved in the investigation by observing Mr. Ebata's methods of information research and backstory.

大変ありがとうございます。

Thank you very much.

改めて、情報を検討するコストに対して情報を拡散させることに対するコストの少なさと、大衆が動くのには情報の精度ではなく、インパクトであることを理解しました。

Once again, I understood the low cost of spreading information versus the cost of considering the information and it's not the accuracy of information that moves the masses, but the impact.

また、調査を通し、M氏の自己弁論と一人の伝聞だけがソースであるのに、それなりに弁護側の盛り上がりがあり、一方で弁護側の根拠の確からしさを誰も証明しようとしていないことも、印象に残りました。

Also, throughout the investigation, I was impressed that there was a good amount of excitement in the defense, even though Ms. M's self-representation and one person's hearsay were the only sources. On the other hand, the fact that no one has attempted to prove the certainty of the defense's grounds

なんにせよ、今回のやり取りをさせていただき、本件の見解を見直すことができたともに、情報についての扱い、大衆の騒ぎ方について一考するよい機会になりました。

At any rate, this exchange has allowed me to reevaluate my views on the case and has given me a good opportunity to think about how to handle information and the public outcry.

今後も、江端様の記事や見解を楽しみにさせていただきますので、よろしくお願いします。

I look forward to reading more of Ebata's articles and views in the future.

以上

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

goルーチン対応完了。通信情報を全部ルーチンの中に突っ込んで、さらにサーバの方を、リクエストを一回つだけしか受けつけないようにミューテックスでロックしてみた。ただし動作は、まだ不安定。

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

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) // クライアントからのメッセージの受信

		// 原因不明の対処処理
		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("write:", err2)
				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)
				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("write:", err2)
				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("WriteJSON:", 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 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)がデフォルト

	ws.onopen = function (event) {
	}

	var markers = [];

	// 受信すると、勝手にここに飛んでくる
	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);
			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]);
					//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();  // 変更が行われたときに呼び出されれなければならない
	}, 500);

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


    map.addLayer(leafletView);
</script>



</body>
</html>
`))
// client7.go ペアは server12.go

package main

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

	"github.com/gorilla/websocket"

	"math/rand"
	"time"
)

// 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") // テスト

func random(min, max float64) float64 {
	return rand.Float64()*(max-min) + min
}

func main() {
	for i := 1; i < 100; i++ {
		go passenger(i)
	}

	time.Sleep(25 * time.Second)
}

func passenger(count int) {

	//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
	_ = websocket.Upgrader{} // use default options

	rand.Seed(time.Now().UnixNano())

	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:  0,
		Lat: 35.653976,
		Lng: 139.796821,
	}

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

	gl2 := new(GetLoc)
	err = c.ReadJSON(gl2)
	log.Printf("count:%d after1 ID:%d", count, gl2.ID)
	log.Printf("count:%d after1 Lat:%f", count, gl2.Lat)
	log.Printf("count:%d after1 Lng:%f", count, gl2.Lng)

	gl.ID = gl2.ID
	for i := 0; i < 20; i++ {
		gl.Lat += random(0.5, -0.5) * 0.00001 * 10 * 5
		gl.Lng += random(0.5, -0.5) * 0.00002 * 10 * 5

		log.Printf("count:%d-%d before 2 ID:%d", count, i, gl.ID)
		log.Printf("count:%d-%d before 2 Lat:%f", count, i, gl.Lat)
		log.Printf("count:%d-%d before 2 Lng:%f", count, i, gl.Lng)

		err = c.WriteJSON(gl)
		if err != nil {
			log.Println("write:", err)
		}
		gl2 := new(GetLoc)
		err = c.ReadJSON(gl2)
		log.Printf("count:%d-%d after 2 ID:%d", count, i, gl2.ID)
		log.Printf("count:%d-%d after 2 Lat:%f", count, i, gl2.Lat)
		log.Printf("count:%d-%d after 2 Lng:%f", count, i, gl2.Lng)

		time.Sleep(1 * time.Second) // 1秒休む
	}

	gl.ID = gl2.ID
	gl.Lat = 999.9
	gl.Lng = 999.9

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

	err = c.WriteJSON(gl)

	err = c.ReadJSON(gl2)
	log.Printf("count:%d after3 ID:%d", count, gl2.ID)
	log.Printf("count:%d after3 Lat:%f", count, gl2.Lat)
	log.Printf("count:%d after3 Lng:%f", count, gl2.Lng)
}