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

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

今週末、新シリーズのコラムの準備 ―― というか、ひらすら勉強をしていました。

This weekend, I was preparing for a new series of columns -- I was studying all day.

最近、資料の収集は市民図書館とAmazon頼りにしてきましたが、さすがに新シリーズということで、市営図書館の本館と街の本屋に行こうと思いました。

Lately I've been relying on the Civic Library and Amazon to collect materials, but for preparing a new series, I decided to go to the main branch of the city library and the city bookstore.

しかし、大きな本屋のある街に出るのに、1時間弱の時間電車に乗らなければならないというのもあり、ちょっと面倒だなと思っていました(台風も来ていましたし)。

However, I had to take the train for less than an hour to get to the city with a big bookstore, so I thought it was a little troublesome (a typhoon was also coming).

その時、隣街にある大型ショッピングセンター「コーチャンフォー」のことを思い出して、車で行ってきました。

That's when I remembered the large shopping center in the next town, "Coachandfour", and I drove there.

とにかく大きな本屋なので、技術書の場所が分からずに迷っていたら、本屋の奥の方に、技術専門書だけで20ライン以上はある、広大なエリアを見つけて、感動のあまり声を失いました。

Anyway, it's a big bookstore and I was confused about where to find the technical books. I found a huge area in the back of the bookstore, with over 20 lines of technical books alone, so I was so impressed and lost my voice

―― 圧倒的な数の技術書に囲まれる快感

"Pleasure surrounded by an overwhelming number of technical books"

うん、ここになら、一日、25時間以上滞在していたい、と思えるほどでした。

Yeah, I wanted to stay here for more than 25 hours a day.

----

『わーい、オライリーのGo言語の並列処理の本だ。だけどWebSocketを使った並列プログラムのサンプルがないなぁ』

"O'Reilly's Go language parallel processing book. However, there is no sample parallel program using WebSocket. "

『やった! Visual Studio Codeの教本めっけ! Docker連携について知りたかったのでこれ欲しいんだけど、今週末は勉強に専念しなければならないから、今回は見送ろう』

"Hooray! Visual Studio Code textbook! I wanted to know about Docker cooperation, so I want this, but I have to concentrate on studying this weekend, so let's see it off this time. "

『量子コンピュータの本、どれも、相変わらず難しいなぁ。「やさしい」と冠している本では、何のことやらサッパリ分からん。著者も出版社も苦労しているんだろうなぁ』

"Every quantum computer book is still difficult. I don't understand anything in the book that says "gentle". I wonder if both the author and the publisher are having a hard time. "

というように、「"つまみ読み"できる」が、リアル書店の最大の強みです。

So, "I can browse" is the greatest strength of a real bookstore.

本屋にやってきて本を買う人は、すぐに読みたいから本屋にやってくると思います。

I think that people who come to a bookstore and buy a book want to read the book immediately.

ですので、在庫が豊富なリアル書店であれば、Amazonに販売機会を奪われることもないと思います。

Therefore, I also think that a real bookstore with abundant inventory will not lose sales opportunities.

-----

さて、新シリーズのテーマですが、今回は「ブロックチェーン」になります。

Now, the theme of the new series, will be "blockchain".

「ブロックチェーン」は、ITのどストライクのサービスです。

"Blockchain" is an main service of IT.

ですので、前回の「量子コンピュータ」のように、常に不安と共にあるような執筆にはならないとは思います。

Therefore, I don't think that I will always write something that makes me uneasy like the previous "quantum computer".

しかし、それでも、専門家の方が付いていて頂ければ、私は安心して「暴走」することができます。

But still, if an expert monitors me, I can rest assured that I'll be "runaway."

という訳で、今回も、私の「ブロックチェーン」のコラムの内容を監修して(ツッコんで)頂ける方を探しております。

So, I'm looking for someone who can supervise the contents of my "blockchain" column

江端のコンテンツを上手く受けいれつつ、細かいことはスキップして、「具体例」でアドバイスを頂けける人なら、大歓迎です。

Anyone who accepts Ebata's content well, skips the details, and can give advice with "concrete examples" is welcome.

ブロックチェーンの理論面だけでなく、ビットコインやブロックチェーンのアプリケーションやサービスを、実際に設計、運用している方からご助言頂けたら、大変嬉しいです。

Not to mention the theoretical aspects of blockchain, I would be very grateful if you could give us advice from those who actually design and operate Bitcoin and blockchain applications and services.

今回は、これに加えまして、ビットコインに関わるリアルでドロドロの現場のお話を提供してくる方も、歓迎致します(こちらは、ブロックチェーンの監修とは別枠です)。

This time, in addition to this, I also welcome those who provide real and muddy on-site stories related to Bitcoin (this is another frame from the blockchain supervision).

ちなみに、今回も、私は、ブロックチェーン(ビットコイン等を含む)をディスる、「敵役」として立ち振る舞るまう予定です。そういう連載です)。

By the way, this time as well, I plan to act as an "antagonist" who disrespects blockchain (including Bitcoin).

ご連絡を頂ければ幸いと存じます。よろしくお願い申し上げます。

I would appreciate it if you could contact me.

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

通信プロトコルを説明する時には、その通信サービスの利用者として架空の人物を使います。

When describing a communication protocol, we use a fictitious person as the user of that communication service.

定番は、Alice(アリス)とBob(ボブ)です。これは、変数のA,Bの代りとして使うのに便利だからです。

The classics are Alice and Bob. This is because it is convenient to use them in place of the variables A and B.

あとは、Carol(キャロル), Charlie(チャーリー), Dave(デイブ), Ellen(エレン)、Frank(フランク)と続きます。

The others are Carol, Charlie, Dave, Ellen and Frank.

-----

仕事の資料や論文の場合はさておき、私は、これらを使いません。気分が乗らないからです。

Aside from work documents and papers, I don't use them. Because I don't feel like it.

とは言え、架空の人物やキャラクターを使うのも、これがなかなか難しいのです。

However, using fictional characters are also difficult to do this.

あるいは、アニメのキャラクター名を引用する、というのもありますが、そのアニメを知らない人にとっては、AliceとBobと同じくらい違和感があるものです。

Alternatively, I can quote the character name of the anime, but or those who don't know the anime, it's as uncomfortable as Alice and Bob.

名前を自動生成していくれるソフトがあるのは知っていたのですが、

I knew that there was software that could automatically generate names,

今回調べているうちに、著作権フリーの顔写真がある、と知って、驚いています。

While researching the web app, I was surprised to find out that there is a copyright-free face photo.

なんでも、"AI"なるものが実在しない写真を作るらしい("イメージ合成技術"だと思いますが)です。

It seems that "AI" makes pictures of non-existent humans (though I think it is an "image composition technology").

https://selfie2anime.com/

また、人間の写真をアニメのキャラクー風に変換するサイトもあって、なかなか面白かったです。

Also, there was a site that converts human photos into an anime character style, which was quite interesting.

ちなみに、私の写真を投入したら、こんな風になりました。

By the way, when I put in my photo, it looked like this.

-----

「シナリオを書いただけで漫画が完成する」という未来は、そんなに遠くないかもしれない ―― と思いました。

I thought that the future of "just writing a scenario to complete a manga" may not be so far.

 

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

長女:「パパさぁ、"SPSS"って使ったことある?」

Senior Daughter: "Dad, have you ever used SPSS?

江端:「何・・・だと・・・? 今、"SPSS"と言ったか?」

Ebata: "What... what did you...? Did you just say "SPSS"?

-----

長女が、現在、卒業論文作成の為、フィールドのアンケートのデータ収集で、忙しい様子なのは知っていました。

I know that my senior daughter is currently busy collecting data for her field questionnaire for her "Graduation Thesis."

現在のコロナ禍にあって、リモートアンケート環境でのF2Fアンケートで、大変苦労している様子です。

In the current corona disaster, she is having a very difficult time with F2F surveys in a remote survey environment.

敢えて"偏見"を含めて言いますが、

I dare to say that I am "prejudiced".

―― 文系学科の卒論って、そんなに大変なのか?

"Is a thesis in a liberal arts department really that hard?"

と、正直驚いています。

And I'm honestly surprised.

-----

かつて、私が大学在学時代、文系の友人(女性)との会話で、

Once, when I was in college, I had a conversation with a humanities friend (female).

友人:「卒論仕上げるのに、3日間徹夜しちゃったよー」

"I stayed up all night for three days to finish my thesis!"

というフレーズに、何と答えるのが正解なのか、分からなくなったことを覚えています。

But I remember I didn't know what to say to this phrase.

(1)『ヘー、それはラクでいいね』

(1) "Heh, that's easy and nice"

(2)『えー、それは大変だったね』

(2) "Well, that was tough"

なにしろ、その程度の徹夜作業、工学部では、隔週で発生する通常イベントだったからです。

After all, that kind of all-night work was a regular event that occurs every other week in the Faculty of Engineering.

なので、最近の学生(ただし「長女」のみ)の学業への取り組みに、正直驚いています。

So, I'm honestly surprised at the recent efforts of students (but only "my daughter") in their studies.

-----

私が驚いているのは、「私の知見が古い」あるいは「偏見が入っているから」です。

The reason why I am surprised is that "my knowledge is old" or "my prejudice."

もはや、今の大学生は「理系」と「文系」という単純な枠組みでは、把握できないのでしょう。

Today's university students can no longer grasp with the simple framework of "science" and "humanities".

これは、「動ける学生」か「動けない学生」か ―― という学生側のアクションではなく、

This is not an action on the part of the student, "a student who is active" or "a student who is not active".

「動ける人間を作れる大学/学部」か「作れないか大学/学部」か、が問われるようになると思います。

It will be "The university / faculty that can make people who can be active" or "The university / faculty that can make people who can be active".

実際、娘を見ている限り、娘の在学している大学の学部は、私の中では高評価になっています。

In fact, as far as I can see my daughter, the faculty of the university she attends is highly rated by me.

閑話休題

Quiet talk

-----

"SPSS"とは、IBM社が製造・販売している、データ分析のスタンダードソフトウェアです。

"SPSS" is standard software for data analysis manufactured and sold by IBM.

私は使ったことがありませんが、超有名ソフトです。

I have never used it, but it is a very famous software.

ちなみに、私が使い込んだデータ分析ソフトは、概ね、NTTデータ数理システム社の製品です。

By the way, the data analysis software I used is mostly a product of NTT DATA Mathematical Systems

これとか、
これです。

like this and this.

-----

それはともかく。

Anyway,

自分の娘から、"SPSS"の言葉が出てこようとは ――

The word "SPSS" is coming out of my daughter.

『今、娘が大きく羽搏(はばた)こうとしている』

"Now, my daughter is about to flutter in the world."

と、私は、思わず感慨に耽ってしまいました。

I was deeply moved.

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

PruneMobile というソフトウェアを作っています。

クライアント側のプログラムで、Golang(Go言語)の 並列(通信)処理を始めて本格的に実装したのですが、サーバ側にエラーが乱発しています。

Golangの通信プログラムの仕様は今一つ分かなくて(C言語なら「私がマニュアルだ」と傲慢に言い放ちますが)、試行錯誤の最中です。

"Go"は"C"と、ポインタや配列も違って、勉強し直し状態です。

それはさておき、クライアント側のプログラムは、以下の通り。ポイントは、

go passenger(1)
go passenger(2)
go passenger(3)
go passenger(4)

でスレッド処理をしてみたところです。

// client6.go ペアは server12.go

package main

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

	"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 gl [100]GetLoc
var gl2 [100]GetLoc
var c [100](*websocket.Conn)

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 random(min, max float64) float64 {
	return rand.Float64()*(max-min) + min
}

func main() {
	rand.Seed(time.Now().UnixNano())

	flag.Parse()
	log.SetFlags(0)

	go passenger(1)
	go passenger(2)
	go passenger(3)
	go passenger(4)

	time.Sleep(25 * time.Second)
}

func passenger(i int) {

	/*
		gl[i] = GetLoc{
			ID:  0,
			Lat: 35.653976,
			Lng: 139.796821,
		}
	*/

	u := url.URL{Scheme: "ws", Host: *addr, Path: "/echo2"}
	log.Printf("connecting to %s", u.String())

	var err error
	c[i], _, err = websocket.DefaultDialer.Dial(u.String(), nil)
	//c[i] = cc
	if err != nil {
		log.Fatal("dial:", err)
	}
	defer c[i].Close()

	gl[i].ID = 0
	gl[i].Lat = 35.653976
	gl[i].Lng = 139.796821

	if i != -100 {
		log.Printf("before1 %d ID:%d", i, gl[i].ID)
		log.Printf("before1 %d Lat:%f", i, gl[i].Lat)
		log.Printf("before1 %d Lng:%f", i, gl[i].Lng)
	}

	//err = c.WriteJSON(mt, gl)
	err = c[i].WriteJSON(gl[i])
	if err != nil {
		log.Println("write:", err)
	}

	//&(gl2[i]) = new(GetLoc)
	err = c[i].ReadJSON(&(gl2[i]))

	if i != -100 {
		log.Printf("after1 %d ID:%d", i, gl2[i].ID)
		log.Printf("after1 %d Lat:%f", i, gl2[i].Lat)
		log.Printf("after1 %d Lng:%f", i, gl2[i].Lng)
	}

	if gl2[i].ID == 0 {
		// 強制停止
		os.Exit(1)
	}

	gl[i].ID = gl2[i].ID

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

		if i != -100 {
			log.Printf("before2 %d ID:%d", i, gl[i].ID)
			log.Printf("before2 %d Lat:%f", i, gl[i].Lat)
			log.Printf("before2 %d Lng:%f", i, gl[i].Lng)
		}

		err = c[i].WriteJSON(gl[i])
		if err != nil {
			log.Println("write:", err)
		}
		//gl2[i] := new(GetLoc)
		err = c[i].ReadJSON(&(gl2[i]))
		if i != -100 {
			log.Printf("after2 %d ID:%d", i, gl2[i].ID)
			log.Printf("after2 %d Lat:%f", i, gl2[i].Lat)
			log.Printf("after2 %d Lng:%f", i, gl2[i].Lng)
		}
		time.Sleep(1 * time.Second) // 1秒休む
	}

	gl[i].ID = gl2[i].ID
	gl[i].Lat = 999.9
	gl[i].Lng = 999.9

	log.Printf("before3 %d ID:%d", i, gl[i].ID)
	log.Printf("before3 %d Lat:%f", i, gl[i].Lat)
	log.Printf("before3 %d Lng:%f", i, gl[i].Lng)

	err = c[i].WriteJSON(gl[i])

	err = c[i].ReadJSON(&(gl2[i]))
	log.Printf("after3 %d ID:%d", i, gl2[i].ID)
	log.Printf("after3 %d Lat:%f", i, gl2[i].Lat)
	log.Printf("after3 %d Lng:%f", i, gl2[i].Lng)

}

でもって、サーバ側に、

wsarecv: An existing connection was forcibly closed by the remote host.

がでてくるのですが、これがどうにも分からない。

websocket.DefaultDialer.Dialもスレッド単位で分離しているから、良さそうなんだけどなー

サーバ側の出力コンソールは、こんな感じ

first ID:0
117 after gl = <-chan2_1
first Lat:0.000000
94
first Lng:0.000000
126
read: read tcp 127.0.0.1:8080->127.0.0.1:50368: wsarecv: An existing connection was forcibly closed by the remote host.
138
write: write tcp 127.0.0.1:8080->127.0.0.1:50366: wsasend: An existing connection was forcibly closed by the remote host.
after gl2.id = 3
after gl2.lat = 35.653909
after gl2.lng= 139.796333
145
148
113 before gl = <-chan2_1
86
final ID:3
final Lat:35.653909
final Lng:139.796333
94
write: write tcp 127.0.0.1:8080->127.0.0.1:50365: wsasend: An existing connection was forcibly closed by the remote host

とりあえず、忘れそうなので、自分の為にメモを残しておきます。

websocket.DefaultDialer.Dialもスレッド単位ごとに発行しているから分離しているから、良さそうなんだけどなぁ。Websocketの複数のエンドポイントを作って並列処理につっこむには、もう一頑張り必要、ということでしょう。

ちなみに「誰か、私を助けてくれたっていいんだからね!」と申し上げておきます。