2023,江端さんの技術メモ

バスのリアルタイム情報を格納するサーバを作ることになりました(経緯が色々あって)。

情報を提供しているサーバから、JSONを定期的に取りに行けばいいんだろう、とか思っていたのですが、このProtocol Bufferというデータ形式を、私は聞いたことがありません。

実際にデータを取得してセーブしてみたのですが、明らかにバイナリです。

しかも、どのエディタでも自動整形しない。ということは、どうやらテキストではない。

で、色々調べたのですが、どうも要領を得ないのですが、下の動画でやっと分かった気になりました。

乱暴に言えば、Protocol Buffersとは「圧縮されたJSON または XML(のようなもの)」です。

まあ、JSONもXMLもテキストメッセージで、しかも構造を保持したまま送信するので「通信効率悪そうだなぁ」と前々から思っていましたので、こういうものが必要となるのは分かります。

Googleが提供していることもあり、また、リアルタイム系のデータでは必要となるのは分かりますが ―― また、覚えることが増えたなぁ、と少々ウンザリしています。


とりあえず、Go言語で動かすことを目的として、ここまでの経緯を記載しておきます。

私の環境は、Windows10です。GOはインストール済みです

(1)https://protobuf.dev/downloads/ から "Latest Version" →  "*-win64.zip"

をダウンロード。私はC:\の直下に展開しました。

でもって、この両方のフォルダーにpathを通しておきました。必要なのは"protoc.exe"です。

(2)私の場合、C:\Users\ebata\protocol_bufferesというディレクトリを作って、そこにソースを展開することにしました。

とりあえず、main.goという名前でファイルを作っておきます(後で必要になります)

package main

import "fmt"

func main() {
	fmt.Println("Hello World!!")
}

さらに、person.proto という名前で、

syntax = "proto3";
package main;

message Person{
    string name = 1;
    int32 age = 2;
}

というファイルを作ります。これがxmlやらJSONのスタイルファイルにようなものです。

で、ここから、person.pb.goというファイルを作らなければならないのですが、これに苦労しました。

C:\Users\ebata\protocol_bufferesの中で、

$ protoc --go_out=. *.proto
protoc-gen-go: unable to determine Go import path for "person.proto"
Please specify either:
    • a "go_package" option in the .proto source file, or
      • a "M" argument on the command line.
See https://developers.google.com/protocol-buffers/docs/reference/go-generated#p
ackage for more information.
--go_out: protoc-gen-go: Plugin failed with status code 1.

のようなことを繰り返していたのですが、person.proto の中に、一行追加したら、サクっと通りました。

syntax = "proto3";

option go_package="./;main"; // 理由は分からないけど、この1行で、以下のエラーが消えた

//$ protoc --go_out=. *.proto
//protoc-gen-go: unable to determine Go import path for "person.proto"
//Please specify either:
//        • a "go_package" option in the .proto source file, or
//        • a "M" argument on the command line.
//See https://developers.google.com/protocol-buffers/docs/reference/go-generated#p
//ackage for more information.
//--go_out: protoc-gen-go: Plugin failed with status code 1.

package main;

message Person{
    string name = 1;
    int32 age = 2;
}

この結果、以下のようなperson.pb.goが生成されました。

// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// 	protoc-gen-go v1.26.0
// 	protoc        v4.22.2
// source: person.proto

package main

import (
	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
	reflect "reflect"
	sync "sync"
)

const (
	// Verify that this generated code is sufficiently up-to-date.
	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
	// Verify that runtime/protoimpl is sufficiently up-to-date.
	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)

type Person struct {
	state         protoimpl.MessageState
	sizeCache     protoimpl.SizeCache
	unknownFields protoimpl.UnknownFields

	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
	Age  int32  `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"`
}

func (x *Person) Reset() {
	*x = Person{}
	if protoimpl.UnsafeEnabled {
		mi := &file_person_proto_msgTypes[0]
		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
		ms.StoreMessageInfo(mi)
	}
}

func (x *Person) String() string {
	return protoimpl.X.MessageStringOf(x)
}

func (*Person) ProtoMessage() {}

func (x *Person) ProtoReflect() protoreflect.Message {
	mi := &file_person_proto_msgTypes[0]
	if protoimpl.UnsafeEnabled && x != nil {
		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
		if ms.LoadMessageInfo() == nil {
			ms.StoreMessageInfo(mi)
		}
		return ms
	}
	return mi.MessageOf(x)
}

// Deprecated: Use Person.ProtoReflect.Descriptor instead.
func (*Person) Descriptor() ([]byte, []int) {
	return file_person_proto_rawDescGZIP(), []int{0}
}

func (x *Person) GetName() string {
	if x != nil {
		return x.Name
	}
	return ""
}

func (x *Person) GetAge() int32 {
	if x != nil {
		return x.Age
	}
	return 0
}

var File_person_proto protoreflect.FileDescriptor

var file_person_proto_rawDesc = []byte{
	0x0a, 0x0c, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04,
	0x6d, 0x61, 0x69, 0x6e, 0x22, 0x2e, 0x0a, 0x06, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x12, 0x12,
	0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
	0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52,
	0x03, 0x61, 0x67, 0x65, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x3b, 0x6d, 0x61, 0x69, 0x6e, 0x62,
	0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}

var (
	file_person_proto_rawDescOnce sync.Once
	file_person_proto_rawDescData = file_person_proto_rawDesc
)

func file_person_proto_rawDescGZIP() []byte {
	file_person_proto_rawDescOnce.Do(func() {
		file_person_proto_rawDescData = protoimpl.X.CompressGZIP(file_person_proto_rawDescData)
	})
	return file_person_proto_rawDescData
}

var file_person_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_person_proto_goTypes = []interface{}{
	(*Person)(nil), // 0: main.Person
}
var file_person_proto_depIdxs = []int32{
	0, // [0:0] is the sub-list for method output_type
	0, // [0:0] is the sub-list for method input_type
	0, // [0:0] is the sub-list for extension type_name
	0, // [0:0] is the sub-list for extension extendee
	0, // [0:0] is the sub-list for field type_name
}

func init() { file_person_proto_init() }
func file_person_proto_init() {
	if File_person_proto != nil {
		return
	}
	if !protoimpl.UnsafeEnabled {
		file_person_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
			switch v := v.(*Person); i {
			case 0:
				return &v.state
			case 1:
				return &v.sizeCache
			case 2:
				return &v.unknownFields
			default:
				return nil
			}
		}
	}
	type x struct{}
	out := protoimpl.TypeBuilder{
		File: protoimpl.DescBuilder{
			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
			RawDescriptor: file_person_proto_rawDesc,
			NumEnums:      0,
			NumMessages:   1,
			NumExtensions: 0,
			NumServices:   0,
		},
		GoTypes:           file_person_proto_goTypes,
		DependencyIndexes: file_person_proto_depIdxs,
		MessageInfos:      file_person_proto_msgTypes,
	}.Build()
	File_person_proto = out.File
	file_person_proto_rawDesc = nil
	file_person_proto_goTypes = nil
	file_person_proto_depIdxs = nil
}

さて、ここで、

package main

import (
	"fmt"
	"log"

	"google.golang.org/protobuf/proto"
)

func main() {
	fmt.Println("Hello World!!")

	elliot := &Person{
		Name: "Elliot",
		Age:  24,
	}

	data, err := proto.Marshal(elliot)
	if err != nil {
		log.Fatal("Marshalling error", err)
	}

	fmt.Println(data)
}

とした上で、

$ go run main.go person.pb.go

をすると、

main.go:7:2: no required module provides package google.golang.org/protobuf/prot
o: go.mod file not found in current directory or any parent directory; see 'go h
elp modules'
person.pb.go:10:2: no required module provides package google.golang.org/protobu
f/reflect/protoreflect: go.mod file not found in current directory or any parent
directory; see 'go help modules'
person.pb.go:11:2: no required module provides package google.golang.org/protobu
f/runtime/protoimpl: go.mod file not found in current directory or any parent di
rectory; see 'go help modules'

というエラーがでてくるので、
$go mod init m
$ go get google.golang.org/protobuf/reflect/protoreflect
$ go get google.golang.org/protobuf/proto
$ go get google.golang.org/protobuf/runtime/protoimpl

を実行して、再度、

$ go run main.go person.pb.go

を行うと

Hello World!!
[10 6 69 108 108 105 111 116 16 24]

とい値が出力されます。

package main

import (
	"fmt"
	"log"

	"google.golang.org/protobuf/proto"
)

func main() {
	fmt.Println("Hello World!!")

	elliot := &Person{
		Name: "Elliot",
		Age:  24,
	}

	data, err := proto.Marshal(elliot)
	if err != nil {
		log.Fatal("Marshalling error", err)
	}

	fmt.Println(data)

	newElliot := &Person{}
	err = proto.Unmarshal(data, newElliot)
	if err != nil {
		log.Fatal("unmarshalling error: ", err)
	}

	fmt.Println(newElliot.GetAge())
	fmt.Println(newElliot.GetName())

}

のプログラムを実行すると、

$ go run main.go person.pb.go
Hello World!!
[10 6 69 108 108 105 111 116 16 24]
24
Elliot

となる。


動的バス情報フォーマット(GTFSリアルタイム)ガイドライン

やっと見つけた

ここからダウンロードすると、こんな感じのprotoファイルが得られます。

で、これを以下のように修正して、

として、

$ protoc --go_out=. *.proto

を実施すると、さくっとgtfs-realtime.pb.goができました。

ここまでできれば、後はクライアントを作れば、できるはずです。

問題は、どうやってサーバにアクセスするか、を考えれば、いくはずです。
(が、基本的に最後に動くまで、どうなるかは分からないですが)。


さて、今回の私の狙いは、

https://ckan.odpt.org/dataset/b_bus_gtfs_rt-yokohamamunicipal

の、リアルタイムデータを取得して保存しておくことです。

これは、こちらに記載されているように

URL: https://api.odpt.org/api/v4/gtfs/realtime/YokohamaMunicipalBus_vehicle?acl:consumerKey=[発行されたアクセストークン/YOUR_ACCESS_TOKEN]

なので、このデータを所得するためには、「発行されたアクセストークン」というのを貰う必要があります。これ、"f4954c3814b207512d8fe4bf10f79f0dc44050f1654f5781dc94c4991a574bf4"(江端ルールで変更済み)というやつになります。

これは、https://developer.odpt.org/ から、申請してメールで付与してもらえます(2日くらいかな)。これがないと、データの取得ができないので注意して下さい。

さて、ここから、とりあえず、この横浜市交通局の市営バスのバス関連リアルタイム情報を取得するコードを、https://gtfs.org/realtime/language-bindings/golang/ をパクって、ちょっと修正してみました。

私は、c:\Users\ebata\protocol_bufferes\gtfs-realtime というディレクトリを掘って、上記のページ通りのことを実施しました。

$ go get github.com/MobilityData/gtfs-realtime-bindings/golang/gtfs

$ go get google.golang.org/protobuf/proto

以下のファイルを作成しました(トークンは自分のものに置き替えて下さい)。エラーの出てくるところは、コメントアウトしています。

// https://gtfs.org/realtime/language-bindings/golang/

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/MobilityData/gtfs-realtime-bindings/golang/gtfs"
	proto "github.com/golang/protobuf/proto"
)

func main() {
	var (
		username = "xx@gmail.com" // 横浜市交通局の市営バスのサイトでは不要のようだからダミーを放り込んでおく
		password = "xx"           // (同上)
	)

	client := &http.Client{}
	req, err := http.NewRequest("GET", "https://api.odpt.org/api/v4/gtfs/realtime/YokohamaMunicipalBus_vehicle?acl:consumerKey=f4954c3814b207512d8fe4bf10f79f0dc44050f1654f5781dc94c4991a574bf4", nil)
	if err != nil {
		log.Fatal(err)
	}

	req.SetBasicAuth(username, password)
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}

	defer resp.Body.Close()
	if err != nil {
		log.Fatal(err)
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(body)

	feed := gtfs.FeedMessage{}
	err = proto.Unmarshal(body, &feed)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(feed)

	/*

		for _, entity := range feed.Entity {
			tripUpdate := entity.TripUpdate
			trip := tripUpdate.Trip
			tripId := trip.TripId
			fmt.Printf("Trip ID: %s\n", *tripId)
		}
	*/
}

で、fmt.Println(body) のところを表示するとこんな感じになっています。

[10 13 10 3 50 46 48 16 0 24 165 246 160 161 6 18 41 10 9 118 105 99 108 95 49 56 48 54 34 28 18 10 13 252 214 13 66 21 192 155 11 67 40 165 205 159 161 6 66 6 10 4 49 56 48 54 72 0 18 41 10 9 118 105 99 108 95 49 48 48 50 34 28 18 10 13 188 173 13 66 21 205 159 11 67 40 233 176 159 161 6 66 6 10 4 49 48 48 50 72 0 18 41 10 9 118 105 99 108 95 51 57 57 50 34 28 18 10 13 83 131 13 66 21 28 146 11 67 40 216 210 159 161 6 66 6 10 4 51 57 57 .....

fmt.Println(feed)は、こんな風に表示されます。

{{{} [] [] 0xc00013f800} 0 [] map[] gtfs_realtime_version:"2.0" incrementality:FULL_DATASET timestamp:1680358181 [id:"vicl_1806" vehicle:{vehicle:{id:"1806"} position:{latitude:35.459946 longitude:139.6084} timestamp:1680336549 occupancy_status:EMPTY} id:"vicl_1002" vehicle:{vehicle:{id:"1002"} position:{latitude:35.419662 longitude:139.62422} timestamp:1680332905 occupancy_status:EMPTY} id:"vicl_3992" vehicle:{vehicle:{id:"3992"} position:{latitude:35.378246 longitude:139.57074} timestamp:1680337240 occupancy_status:EMPTY} id:"vicl_1732" vehicle:{trip:{trip_id:"04117_12202301042041P01910" schedule_relationship:SCHEDULED} vehicle:{id:"1732"}.....

あとは、ここをパースすれば、必要な情報は取り出せるはずです。


さて、ここから ~/protocol_bufferes/gtfs-realtime に環境を作ってみます。

$go mod init m
$ go get google.golang.org/protobuf/reflect/protoreflect
$ go get google.golang.org/protobuf/proto
$ go get google.golang.org/protobuf/runtime/protoimpl

で、

こちらの環境でも、上記と同じ手続で、gtfs-realtime.pb.goを作り、

$ go run main.go gtfs-realtime.pb.go

を実施してみましたところ、

main.go:11:2: no required module provides package github.com/MobilityData/gtfs-realtime-bindings/golang/gtfs; to
add it:
go get github.com/MobilityData/gtfs-realtime-bindings/golang/gtfs
main.go:12:2: missing go.sum entry for module providing package github.com/golang/protobuf/proto; to add:
go mod download github.com/golang/protobuf

と言われたので、言われた通りのことを実施してみました

ebata@DESKTOP-P6KREM0 MINGW64 ~/protocol_bufferes/gtfs-realtime
$ go get github.com/MobilityData/gtfs-realtime-bindings/golang/gtfs
go get: added github.com/MobilityData/gtfs-realtime-bindings/golang/gtfs v1.0.0
でもって、
ebata@DESKTOP-P6KREM0 MINGW64 ~/protocol_bufferes/gtfs-realtime
$ go mod download github.com/golang/protobuf
再度やってみました。
$ go run main.go gtfs-realtime.pb.go
go: updates to go.mod needed; to update it:
        go mod tidy
ここも言われた通り、
$ go mod tidy
をやりました。
でもって、また繰り返しました。
$ go run main.go gtfs-realtime.pb.go
panic: proto: file "gtfs-realtime.proto" is already registered
        previously from: "github.com/MobilityData/gtfs-realtime-bindings/golang/gtfs"
        currently from:  "main"
See https://protobuf.dev/reference/go/faq#namespace-conflict
goroutine 1 [running]:
google.golang.org/protobuf/reflect/protoregistry.glob..func1({0xea9240, 0xeb92b8}, {0xea9240, 0xc000058d70})
        c:/go/pkg/mod/google.golang.org/protobuf@v1.30.0/reflect/protoregistry/registry.go:56 +0x1f4
(以下、色々)
エラー文を見てみると、"gtfs-realtime.proto"が既に登録されている、とあります。
まあ、 ~/protocol_bufferes/ で、色々やったので、多分、登録してしまったのだろうと思います。
が、それを色々変えるのは面倒ですので、とりあえず対処方として、環境変数を変えてしまう、という手があるようです。
$ export GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn
で、ここの部分は回避できるようです(本格的な修正は後回しとします)。
とりあえず、エラーが出てこないように、main.goでコメントしていた部分を解いて、エラーが出てこないように修正しました。
feed := gtfs.FeedMessage{}
	err = proto.Unmarshal(body, &feed)
	if err != nil {
		log.Fatal(err)
	}
	//fmt.Println(feed)

	for _, entity := range feed.Entity {
		//tripUpdate := entity.TripUpdate
		fmt.Println(entity)
		fmt.Println()
		//trip := tripUpdate.Trip
		//tripId := trip.TripId
		//fmt.Printf("Trip ID: %s\n", *tripId)
	}
とりあえずentity(が、何かよく分からんのですが)を表示してみました。
この結果、以下のような表示が得られました。
id:"vicl_1780"  vehicle:{trip:{trip_id:"05406_09202304031054P00218"  schedule_relationship:SCHEDULED}  vehicle:{id:"1780"}  position:{latitude:35.415165  longitude:139.66798}  current_stop_sequence:10  stop_id:"5899_02"  current_status:IN_TRANSIT_TO  timestamp:1680534894  occupancy_status:EMPTY}
id:"vicl_3944"  vehicle:{trip:{trip_id:"03903_22202304031012A01309"  schedule_relationship:SCHEDULED}  vehicle:{id:"3944"}  position:{latitude:35.50719  longitude:139.55861}  current_stop_sequence:32  stop_id:"6219_01"  current_status:IN_TRANSIT_TO  timestamp:1680528244  occupancy_status:EMPTY}
id:"vicl_1705"  vehicle:{vehicle:{id:"1705"}  position:{latitude:35.378166  longitude:139.57071}  timestamp:1680522432  occupancy_status:FEW_SEATS_AVAILABLE}
id:"vicl_4607"  vehicle:{vehicle:{id:"4607"}  position:{latitude:35.492794  longitude:139.66455}  timestamp:1680526330  occupancy_status:NOT_ACCEPTING_PASSENGERS}
さて、次は、この内容を理解しなければなりません。
とりあえず、バスのID、緯度、経度が取れればよく、これでデータが取れるようです.
for _, entity := range feed.Entity {
			//tripUpdate := entity.TripUpdate
			//fmt.Println(entity)

			// データの読み込み
			uniName := *(entity.Vehicle.Vehicle.Id)
			lat := *(entity.Vehicle.Position.Latitude)
			lon := *(entity.Vehicle.Position.Longitude)

			fmt.Println(uniName, lat, lon)
}

2023,江端さんの忘備録

メルトダウン File.8 「後編 事故12年目の“新事実”」を見ました。

I watched "Meltdown File.8 "Part 2: New revelations 12 years after the accident""

茫然自失(ぼうぜんじしつ) ―― というのでしょうか。

I guess I could call it "stupefaction".

『テレビを見ながら、立ち竦(すく)む』という、という体験をすることになりました。

I had to go through the experience of 'standing there, stunned, watching TV.

-----

この番組の要旨を、乱暴に3点で纏めます。

I will summarize the gist of this program in three roughly different points.

(1)あの消防隊員の皆さんの文字通り『命をかけた』原子炉への給水が、逆にメルトダウンを加速することになった

(1) The water supply to the reactor that the firefighters literally "risked their lives" for accelerated the meltdown.

(2)原子炉の圧力を下げる「ベント」は、あの段階では「やらない方がよかった」

(2) "Venting" to reduce reactor pressure "should not have been done" at that stage

(3)ところが、上記(2)によって、原子炉の圧力が下がり、その結果、まったく予想していなかった貯水場から水が引き上げられて、結果として、溶解した燃料を冷やすことになった

(3) However, (2) above caused the reactor pressure to drop, resulting in water being pulled up from the water reservoir, which was completely unexpected, and consequently cooling the dissolved fuel.

つまり ―― その時点において「もっとも良い」と判断した選択が「最悪の事態を導き」、その「最悪の事態が、結果としてさらなる最悪の事態を防いだ」ということであり、

In other words -- the "best" choice at the time "led to the worst," and that "worst prevented further worsts" as a result.

私にとって、最大の衝撃は、

For me, the biggest shock was, that,

『システム制御を行う人間の意図と全く関係なく、勝手に事態が進み、勝手に停止した』

"The situation that proceeded on its own, and then stopped on its own, completely beyond the intentions of the people controlling the system"

ということです。

これは、原子力を制御するエンジニアにとって『完全敗北』といっても過言ではありません。

It is no exaggeration to say that this is a 'total defeat' for the engineers who control nuclear power.

-----

原子力発電所の運用については、電力会社や委託先の大学で、考え得る限りの事故シミュレーション(模擬試験)を行なっていると言われています。

It is said that the power companies and the universities to which they outsource the operation of nuclear power plants conduct every conceivable accident simulation.

シミュレーションの実施以前に、そのような事故シナリオを考え出すストレスは、想像を絶する苦しい作業だと思います。

I know that the stress of coming up with such an accident scenario prior to conducting the simulation is an unimaginably painful task.

しかし、現実の事故は、そのような膨大なシミュレーションの想定を、易々(やすやす)と乗り越えて、やって来るのです。

However, real accidents easily overcome such a huge number of simulation assumptions.

-----

以前から申し上げておりますが、制御システムというのは、自動車であれ、飛行機であれ、発電所であれ、ロケットであれ、繰り返し失敗を続けることで、その安全性や信頼性を、少しずつ向上させていくものです。

As I have said in the past, control systems, whether for automobiles, airplanes, power plants, or rockets, gradually improve their safety and reliability through repeated failures.

『"失敗"からしか学べないなら、学ぶためには"失敗"し続けなければならない』

ところが、「原子力発電所」だけは、この制御システムの大原則が使えない。

However, only "nuclear power plants" cannot use this major principle of control systems.

失敗のリターンが、メチャクチャにデカイからです。

Because, the return on failure is huge.

■事故から12年経った今でも、2万人が避難生活を続けている

"Twelve years after the accident, 20,000 people are still living in evacuation shelters"

という、現状の悲劇は勿論ですが、

This is, of course, the tragedy of the current situation, however,

■今回の事故の最悪ケースでは、東日本の全てが立ち入り禁止地区になっていた

"In the worst case scenario of this accident, all of eastern Japan would have been a no-go zone"

ことを、否定できる人間はいません。

No one can deny this.

-----

という訳で、私は、いつも通りの結論に至ってしまうのです。

So I come to the same conclusion as usual.

―― 日本国内において、生涯で2~3回は原発事故に遭遇し、最低1回は放射能汚染被害を受ける

私達の取り得る2つの未来

2023,江端さんの技術メモ

wsl -d Ubuntu-20.04で起動しようとして、Error: 0x80040326 Error code: Wsl/Service/0x80040326 と言われた時の対応

で対応できたのは良いのですが、今度はDocker Desktopが動かなくなりました。

いわゆる、"これ"です。

error during connect: This error may indicate that the docker daemon is not running.: Get http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.24/containers/json: open //./pipe/docker_engine: The system cannot find the file specified.

以下のページを参考にさせて頂きながら、色々対策していました。

https://remix-yh.net/2139/#:~:text=%E3%81%8C%E3%80%81%E5%A4%89%E6%9B%B4%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%E3%80%82-,%E8%A7%A3%E6%B1%BA%E7%AD%96,%E3%82%88%E3%81%86%E3%81%AB%E3%81%AA%E3%82%8A%E3%81%BE%E3%81%97%E3%81%9F%E3%80%82

https://engineer-ninaritai.com/docker-desktop-not-work/

などを調べていましたが、

「Docker Desktop for Windows」が起動しなくなった?

を最後の手段として腹を括ったところで、動かなかったDocker Desktopでボタン押したアップデートが突然走り出しました。

で、DBのDockerを起動して、psqlでアクセスしたらちゃんとDBが動いていることが確認できました。

こーゆーことが多いので、Docker Desktopは嫌いなんですよ。
(こんなトラブルが「顧客デモの直前」に起きたら、と思うとゾっとします)

2023,江端さんの忘備録

昨日、以下のような日記をアップしました。

「仲間を作らない」「友人を持たない」「恋人を諦め、結婚を人生のスコープ外とする」

The following diary was uploaded yesterday.

ちょっと調べてみたら、「ToPick -飲み会、デートで使える話題提供アプリ」なるものがあるようです。

I did a little research and found that there is something called "ToPick - an app that provides topics of conversation for drinking and dating".

このアプリ、恋人との電話の会話などでは使えそうですが、デートで使うのは厳しそうです。

This app could be used for phone conversations with a girlfriend, but it would be difficult to use it on a date.

ヒアリングのインターフェースに関しては、

As for the hearing interface,

―― 骨伝導イヤホンを装着して音声で聞く

"wear bone-conduction earphones and listen to the voice"

とかすれば、なんとかなりそうですが、入力インターフェースが問題です。

would help, but the input interface is a problem.

デートをしながら、どうやってスマホに指示を出すか?

How do you give directions to your phone while on a date?

『デート中のスマホの会話を監視し続け、適切なタイミングでスマホが自動的に話題を提供してくれるアプリ』の開発が必要となります。

The development of "An app that keeps monitoring the conversation on your phone during the course of a date, and at the appropriate time, your phone will automatically provide a topic of conversation" should be needed.

しかし、これは、現在の技術で十分スコープ内です。

However, this is well within scope with current technology.

-----

―― カップルの双方が、話題提供アプリと骨伝導イヤホンを装着してデートをする未来

-- A future where both couples date wearing a talking-head app and bone-conduction earbuds.

私、この未来が「同時通訳アプリよりも早く登場する」と思います。

Me, I think this future will appear "faster than simultaneous interpretation apps".

なぜなら、ユーザ数がケタ違いだからです。

This is because the number of users is off the charts.

-----

このアプリの登場によって『既存のデートの概念が、根底から覆(くつがえ)る』と思います。

I believe that this application will "overturn the existing concept of dating from the very foundation".

ただ、どういう風に覆るのかは、まだ分かりません。

However, I do not yet know how it will be overturned.

『陽キャの恋愛一極支配を崩す、恋愛機会均一を成しとげるか』

"Can we achieve an equal opportunity for love that will break the unipolar dominance of love in the extrovert?"

はたまた、

or,

『恋愛格差を、絶望的なまでに拡大させるか』

"Are we going to let the love gap widen to the point of hopelessness?"

大変興味深いです。

It is very interesting.

皆様のご意見もお伺いしたいと思います。

I would like to hear your opinions as well.

2023,江端さんの忘備録

私には、多くの「欠点」がありますが、同程度に多くの「弱点」があります。

I have many " drawbacks", but equally as many " weaknesses".

その一つに、

One of them is

―― 沈黙に耐えられない

"I can't stand silence."

があります。

-----

恋人たちがデートで黙って食事をしている様子を見ると、色々なことを考えてしまいます。

When I see lovers eating in silence on a date, I think about many things.

彼らは、

(1)会話の必要すらないくらい心が通じあっている

(1) They are so much in tune with each other that there is not even a need for conversation.

(2)食事とは、食を楽しむものであって、会話をすべきではないという、ポリシーが共通している

(2) They share the policy that meals are for enjoying food and not for conversation.

(3)すでに、デートのプロセスでしゃべりすぎて、しゃべるネタが尽きた

(3) They have already run out of things to talk about, having talked too much in the dating process.

(4)妥当なネタが思いつかない

(4) They can't come up with a suitable story.

のどれかか、あるいは、私の思いもつかない何かなのか、さっぱり分かりません。

I have no idea if it is one of these or something else I can't think of.

-----

以前、この日記で、「―― プレゼンテーションにおいて「沈黙」は「暴力」だぞ。分っているのか?」と書きました。

―― お前は、この場で、一体、誰に対して、何を分かって貰おうとしているんだ?

I wrote in this diary before, "-- Silence is violence in a presentation. Do you understand that?"

同じように、デートの途中の沈黙もまた、暴力のように感じるのです。

Likewise, to me, the silence in the middle of a date also feels like violence. so I think

『デートの相手に、暴力ふるったらアカンだろうが』

"Don't be violent with your lover you're on a date with"

と思うのですが、しかし、どうも、この「話題」というのは、昨今の若い世代を越えて、人類史における大きな課題のようなのです。

However, apparently, "topic" seems to be a major issue in human history, beyond the recent younger generations.

-----

世の中の多くの人が、話題そのものに苦慮してる状況は「デートでの話題」でググッれば分かります(7220万件ほどヒットします)。

You can Google "dating topics" to see how many people in the world are struggling with the topic itself (you'll get about 7.2 million hits).

そして、「話題の枯渇」が引き起こす最悪のケースが「セクハラ、パラハラ」です。

And the worst case of "topic exhaustion" is "sexual harassment and para-harassment.

話題に詰まると、相手の年齢や恋人の有無、出身地、仕事の内容などのネタに転がりんでしまうのは、「お約束」です。

When you get stuck on a topic, it is "routine" to fall back on topics such as the other person's age, whether or not he/she has a girlfriend, where he/she is from, and what he/she does for a living.

食料やエネルギの枯渇が戦争を引き起こすように、話題の枯渇はハラスメントを発生させるのです。

Just as the exhaustion of food and energy causes wars, the exhaustion of topics causes harassment.

私の場合、普段から、ネタを捻り出す練習(このブログとか)をすることで、そのような方面に向かわないように心掛けているつもりですが、上手くコントロールできているかどうかは分かりません。

In my case, I usually try to avoid going in that direction by practicing to come up with stories (like this blog), but I am not sure if I am controlling it well.

-----

ところが、これはこれで、また、別の問題を発生させるのです。

This, however, creates another problem.

―― 江端が一人がしゃべっている状況の発生

"A case of a situation where Ebata speaks only"

です。

いわば「1000本ノック」のような状況です。

It is a "1,000 knocks" situation, so to speak.

これ、「沈黙」と同程度に悪い状況です。

This, is a situation as bad as "silence".

会話はコミュニケーションですので、キャッチボールのように、会話の回数や時間は、等分でなければなりません。

Since conversation is communication, the number and duration of conversations, like a catch-all, must be equally divided.

その為には、話題のネタは、相手が新しいネタに展開できる程度の量と内容にしなければなりませんが ―― これが、なかなかに難しいのです。

In order to do this, the topics of conversation must be of sufficient quantity and content that the other party can expand on them with new material -- which is quite difficult.

-----

このような状況を総括すると、

To sum up the situation,

「飲み会に出席しない」「デートをしない」、

"I don't attend drinking parties" or "I don't go on dates"

転じて、

in addition,

「仲間を作らない」「友人を持たない」「恋人を諦め、結婚を人生のスコープ外とする」

"I make and have no friends," "give up on lovers, and take marriage out of the scope of their lives"

というのは ―― これはこれで、なかなか理にかなった戦略ではないかなぁ、と思うことがあります。

Sometimes I think this is a strategy that makes a lot of sense.

2023,江端さんの忘備録

基本的に、私は『国家(権力)がやろうと思えば、できないことはない』と思っています。

Basically, I believe that 'there is nothing the state (power) can't do if it wants to.

例えば、私が、国家から暗殺の対象となったら、私の死は確定的です。

For example, if I am targeted for assassination by the state, my death is certain.

仮に、私が、殺し屋を返り討ちにしたとしても、国家は次の暗殺者を送り込んできます。

Even if I were to turn back an assassin, the state would send the next assassin.

国家が、その方針を変更しない限り、何度も何度も殺し屋が送り込まれてくる訳で、そんなもの逃れようがありません。

Unless the state changes its policy, the assassins will be sent back again and again, and there is no way to escape them.

今、騒ぎとなっている「中国政府がTikTokから個人情報を引き出そうとする」件については、まだ疑惑の域を出ていません。

The current furore about the "Chinese government trying to extract personal information from TikTok" is still beyond a suspition.

ただ、中国政府がやろうと思えば、必ずやれます。

However, if the Chinese government wants to do it, they "will" do it.

これは確定事項です。

This is a definite matter.

-----

一方、前回のファーウェイの通信機器の件についても、中国政府による情報の抜き取りの事実は、まだ明かにされていません。

さて、現在、わが国では、政府主導で、HUAWEIという中国の通信メーカーの製品の排斥を行っています。

On the other hand, the fact that information was extracted by the Chinese government has not yet been revealed in the previous case of Huawei's telecommunications equipment.

(技術的検証くらいは完了しているはずですので、国民には非開示にしておいて、政府間の交渉のネタになっている可能性はあります)

―― さあ、私なら、どう仕込む?

(Since at least the technical verification should have been completed, it is possible that it is being kept undisclosed to the public and is being used as a bargaining chip between governments.)

ともあれ、アメリカ合衆国という国は、「大量破壊兵器がある」と決めつけて、国連決議を得ないまま、単独で戦争をしかけて、その国の体制を完全崩壊させた挙句、『探したけど、大量破壊兵器はなかった』と平気で言うことのできる国です。

Anyway, the United States is a country that can assume that there are weapons of mass destruction, launch a war on its own without a UN resolution, completely collapse its system, and then say with impunity, "We searched but found no weapons of mass destruction.

それに、私は、今でも『1989年に日本に対して一方的に発動された、スーパー301条による経済制裁』の恨みを忘れていません。

And I still remember the bitterness of the "Super 301 economic sanctions" unilaterally imposed on Japan in 1989.

-----

TikTokに関する米公聴会の様子をニュースで見ていたのですが、

I was watching the US hearings on TikTok on the news, and I am sure that

―― 第二次世界大戦中の日系アメリカ人の強制収容も、こんな感じで決めつけて実施してきたんだろうな

"the incarceration of Japanese Americans during WWII was also determined and implemented like this"

と、容易に想像できます。

今も昔も、米国合衆国政府は、

Now and then,

『ひとたび"敵"と認定すれば、法律やら証拠やら、そういうものをすっ飛ばして、何をしてもいい』

"Once they identify someone as an enemy, they can do whatever they want, without regard to laws, evidence, or anything else"

というDNAが受け継がれているように思います。

I think this is the DNA of the U.S. government.

2023,江端さんの忘備録

仕事であろうが趣味であろうが、私は、プログラミングをやります。

I do programming, whether it is for work or as a hobby.

そして、「好きなプログラミング」と、「嫌いなプログラミング」を分けるものは2つあります。

And there are two things that separate "programming I like" from "programming I hate".

―― 仕様と納期

"Specifications and delivery date"

です。

is.

------

自分の思い付きで好きなように機能を追加できて、しかも、納期がなければ、プログラミングは「娯楽」といっても良いです。

If I add functions as I wish with my own ideas without any deadline , programming can be called "entertainment".

多分、ネトゲに限らず、囲碁とか将棋なども含めて、いわゆるゲーマーと呼ばれる人が、ゲームをしている気持ちと同じだと思います。

Probably, it is the same feeling that so-called gamers, including not only netgames but also Go, Shogi, etc., have when they play games.

まあ、私はゲーマーじゃないから分からないのですが、世界をこれほど熱狂されているのだから、多分「ゲームとは凄く面白い」のだと思う。

Well, I don't know because I am not a gamer, but I think that since the world is so enthusiastic about it, perhaps "games are great fun".

ゲームの価値が分からない自分は、人生を損しているのかもしれません。

I may be missing out on life because I don't understand the value of the game.

そもそも、ゲーマーって、何歳になってもゲームから引退しませんよね。

まあ、それはさておき

Well, let's put that aside.

-----

逆に、他人に仕様を決めつけられて、納期があれば、プログラミングは「地獄」に変わります。

On the other hand, if someone else dictates the specifications and there is a deadline, programming turns into "hell".

まあ、どんな仕事でも、同じだと思いますが。

Well, I guess it's the same in any job.

まあ、自分が「娯楽」で作ったプログラムが、仕事に転用されることで、その後の作業が「地獄」に変わることがあります。

Well, a program that I created for my "entertainment" can turn into "hell" when it is converted into a job.

―― 私は、「地獄」生成するために「娯楽」をしているのか?

"Am I "entertaining" to generate "hell"?"

と思うと、時々、情けない気持ちになります。

Sometimes I feel sad when I think about it.

-----

とは言え、私は『庖丁一本 晒(さらし)にまいて・・・』と同じ立ち位置で、

However, I stand in the same position as in "one kitchen knife, wrapped in bleached cotton...",

『自作のプログラミングコード一本で、研究原資という"タマ"を取りに行く』

With a single piece of home-made programming code, I'm going to get the "money" from the research fund.

という、仁義なきシニアの日々を送っております。

I live a senior life without honor day by day.

2023,江端さんの技術メモ

英語論文の現在形と過去形の使い分け

person agent か、human agentか?

person:普段「1人の人」を指す。
persons:フォーマルな場面で使う。
people:普段「複数の人」を指す
human:神や動物、ロボットではなく「人間」。
man:「男性」「人」「人類」。最近は「人」「人類」の意味で使うのは避ける傾向にある。
guy、fellow、bloke:口語で「やつ」。

"human agent"で良いように思う。


「自律判断」という英訳で悩む → ここは、"Google裁定"に任せる
"autonomous behavior":149,000
"autonomous decision":383,000
"self-determination": 510,000,000
"autonomous decision" & "algorithm": 82,200
"autonomous behavior algorithm" 146
"autonomous decision" & "algorithm":82,200
"autonomous decision algorithm":1,300
"self-determination" & "algorithm": 421,000
"self-determination algorithm":1,520

結論: "self-determination"が勝者だと思うけど、論文の下書きみたら、"behavioral psychology"が乱発されていた。今、ここで、これを換えると、前後の文章も替えなければならないので、本件は放置する。


住民 resident と inhabitant の違い

どちらも住民という意味ですが
resident は、特定の地域の居住者のことを指し、一時居住者も含むのに対し、
inhabitant は、その地域に長く住む集団に属するものを指します。
どちらも通例では、sをつけた複数形で使われることが多いようです。

resident は、「住民」の他に「居住者」とも訳されますし、名詞の他に形容詞としても使われますが、inhabitant は、名詞のみで、「住民」の他に「定住者」や「生息動物」という意味にもなります。この動詞形は inhabit となり、「に居住している」「に宿る」「巣食う」という意味です。


「課題」をどう訳すか?
→"技術課題"は、"technical problems"でいいみたい(problemを使うと、"問題点"みたいに聞こえるので、"challenge"を使いたくなるけど)
https://www.bizmates.jp/blog/kadai-eigo/

Problem(課題、問題)

Problemは「解決すべき問題」という意味で表現したい時に使います。不利益や不都合を来たす物事を指します。

[例文1]
This is a problem our company needs to work to resolve in the long term.
これは我が社が長期的に取り組まなくてはならない課題です。
[例文2]
Does anyone have a good idea to resolve the problem?
この課題を解決するためのいいアイディアはありますか?
[例文3]
The biggest problem of this project is the lack of human resources.
このプロジェクトの一番大きな課題は、人材が不足していることです。

Task(課題)

Taskは「やらなければならない作業・仕事」というニュアンスです。日常的な業務レベルで与えられた軽めの仕事や宿題を指します。

[例文1]
The only task I have left for this week is making my presentation slides.
今週残る課題はプレゼンテーションの資料作りです。
[例文2]
Thanks for helping me out. I was able to complete my task by the due date.
手伝ってくさってありがとうございました。なんとか期日までに課題を終えられました。
[例文3]
The president gave me a task to come up with a better marketing message.
社長からより良いマーケティングメッセージを策定するように、という課題をいただきました。

Assignment(課題)

AssignmentはTaskに似た意味合いを持ちますが、「任務」や「任された仕事」と、大きめの課題といたニュアンスです。上司から割り当てられた課題は、このAssignmentで表現します。ビジネスシーンだけでなく、学校でも宿題の意味で使われる表現です。

[例文1]
Let’s complete this assignment with everyone in the department.
この課題は部署全員で協力して完了させましょう。
[例文2]
I got a new assignment from my boss. I need to get it done within this year.
上司から新しい課題を渡されました。今年中に完了しなければなりません。
[例文3]
I’d like to give this assignment to Gabriel. It’s not going to be easy, but I think it will help him gain experience.
この課題はガブリエルにアサインしようと思います。難しいでしょうが、彼にはいい経験になると思います。

Issue(課題)

Issueは「議論すべき事象や問題」というニュアンスの表現です。Problemはそのもの自体がトラブルになりかねない問題を意味しますが、Issueはその事柄について賛成する人・反対する人に二分されている場合など、明らかに問題と言いきれない時や、角が立たないよう「問題」と呼ぶのを避けたい時に使います。

[例文1]
We should resolve this issue ASAP.
この課題は早急に解決したいですね。
[例文2]
The rising costs of our factories in Asia are a serious issue for our company.
アジア圏の工場でのコストの増加は弊社にとって大きな課題となっています。
[例文3]
At our company, we are taking social issues such as SDGs seriously.
弊社では、SDGsをはじめとした社会の課題に熱心に取り組んでいます。

Business(課題)

Businessは一般的に「仕事・事業・業務」という意味で使われますが、「片付けなければならない仕事」という意味でも使用されます。頻繁に使われる表現ではありませんが、これもissue のように婉曲な「問題」の言い方になります。

[例文1]
That is none of your business. I will take care of it.
それは私の課題なので責任を持って終わらせます。
[例文2]
I have some business I really need to take care of by the end of the day.
どうしても今日中に片付けなくてはならない課題があります。
[例文3]
It looks like we’ve got some business to do.
どうやら課題がでてきたようですね。

2023,江端さんの技術メモ

単純だけど、これでオブジェクトを書いたり消したりすれば、実現できるかな?

 

<!doctype html>
<html>
<head>
    <title>Many Points with  leaflet Canvas</title>
    <meta charset="utf-8">

    <style>
        
        #map {
            position: absolute;
            height: 100%;
            width: 100%;
            background-color: #333;
        }
    </style>

</head>
<body>
    <div id="map"></div>
    <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" />
    <script src="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.js"></script>
    <script src="L.CanvasOverlay.js"></script>
    <script src="http://www.sumbera.com/gist/data.js" charset="utf-8"></script>


    <script>

        var points = data; // data loaded from data.js
        var leafletMap = L.map('map').setView([50.00, 14.44], 9);
        L.tileLayer("http://{s}.sm.mapstack.stamen.com/(toner-lite,$fff[difference],$fff[@23],$fff[hsl-saturation@20])/{z}/{x}/{y}.png")
            .addTo(leafletMap);

        L.canvasOverlay()
            .drawing(drawingOnCanvas)
            .addTo(leafletMap);

        function drawingOnCanvas(canvasOverlay, params) {
            var ctx = params.canvas.getContext('2d');
            ctx.clearRect(0, 0, params.canvas.width, params.canvas.height);
            ctx.fillStyle = "rgba(255,116,0, 0.2)";


            //for (var i = 0; i < data.length; i++) {
            for (var i = 0; i < data.length; i=i+300) {
                var d = data[i];
                if (params.bounds.contains([d[0], d[1]])) {
                    dot = canvasOverlay._map.latLngToContainerPoint([d[0], d[1]]);
                    ctx.beginPath();
                    //ctx.arc(dot.x, dot.y, 3, 0, Math.PI * 2);
                    ctx.arc(dot.x, dot.y, 10, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.closePath();
                }
            }

            //for (var i = 0; i < data.length ; i++) {
            for (var i = 0; i < data.length ; i=i+10) {
                var d = data[i];
                if (params.bounds.contains([d[0], d[1]])) {
                    dot = canvasOverlay._map.latLngToContainerPoint([d[0], d[1]]);
					//ctx.beginPath();
					ctx.clearRect(dot.x-10, dot.y-10, dot.x+0, dot.y+0);
                    //ctx.closePath();
                }
            }


        };
    </script>
</body>
</html>