2022/08,江端さんの技術メモ

redisのブロードキャストで構造体データを運ぶ時の注意(というか、golangのキャストがC/C++みたいに単純でない件)

で記載していますが、Redisのブロードキャストを大変「ありがたく」使っているのですが、

/switch v := psc.Receive().(type) {

では、受信でロックしてしまうので、これを破る(Break)する方法を探して、以下の方法を見つけたのですが

switch v := psc.ReceiveWithTimeout(5 * time.Second).(type) {

これが、上手く動きません。

// go run sub.go
// goga\1-9-6\others\sub2.go

package main

import (
	"encoding/json"
	"fmt"
	"time"

	"github.com/gomodule/redigo/redis"
)

type Ch5_info struct {
	Bus_num int     // バスの番号
	CC      int     //  1: 座標情報 2: 停車位置情報
	Present int     // 停車位置番号
	Lat     float64 //
	Lon     float64 //
}

func main() {
	// 接続
	conn, err := redis.Dial("tcp", "localhost:6379")
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	psc := redis.PubSubConn{Conn: conn}
	psc.Subscribe("channel_1")

	for {
		c5i := new(Ch5_info)

		//switch v := psc.Receive().(type) {
		switch v := psc.ReceiveWithTimeout(5 * time.Second).(type) {
		case redis.Message:
			fmt.Printf("%s: message: %s\n", v.Channel, v.Data)

			_ = json.Unmarshal(v.Data, &c5i)

			// 試しに2つほど出力してみる
			fmt.Println(c5i.Bus_num)
			fmt.Println(c5i.Lon)

		case redis.Subscription:
			fmt.Printf("%s: %s %d\n", v.Channel, v.Kind, v.Count)
		case error:
			fmt.Println("After 10 seconds. out of switch")
			time.Sleep(time.Millisecond * 1000)
			//psc.Conn.Flush()
			//psc.Subscribe("channel_1")
		}

		//		fmt.Println("out of switch")

		//if c5i.CC == -1 {
		//	break
		//}

	}

	fmt.Println("Catch break")
}

"case error"
これで、5秒を経過すると"case error"に飛んでしまい、その後、forループで戻しても、常に"case error"に行ってしまいます。

どなたか、5後にswitchを抜けた後、また同じようにswitchで5秒を待つようにする方法をご存知の方、御一報下されば大変助かります。

ちなみに、参考までに、データ配送側のプログラムはこんな感じです(1回配送、走り切りです)。

// go run pub.go
// goga\1-9-6\others\pub.go
package main

import (
	"encoding/json"
	"fmt"

	"github.com/gomodule/redigo/redis"
)

type Ch5_info struct {
	Bus_num int     // バスの番号
	CC      int     //  1: 座標情報 2: 停車位置情報
	Present int     // 停車位置番号
	Lat     float64 //
	Lon     float64 //
}

func main() {
	// 接続
	conn, err := redis.Dial("tcp", "localhost:6379")
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	c5i := new(Ch5_info)

	c5i.Bus_num = 1
	c5i.CC = -1
	c5i.Present = 23
	c5i.Lat = 12.34
	c5i.Lon = 56.78

	json_c5i, _ := json.Marshal(c5i)

	// パブリッシュ
	r, err := redis.Int(conn.Do("PUBLISH", "channel_1", json_c5i))
	if err != nil {
		panic(err)
	}
	fmt.Println(r)
}

 

 

2022/08,江端さんの技術メモ

以下の記述は間違っているようですので、参照にしないで下さい(現在検証中)。
(昨日、ソフト外注会社の方に教えて貰いました)

 

Golangで、http.HandleFunc と http.Handleについて、ずっと混乱しつづけています。

というか、私は、使い方が分かればよくて、その理屈なんぞ1mmも興味がないので、コードを書きながら理解しています(結局、遅くなっているような気がしますが)。

1. http.Handle()は、index.htmlをベースとしたサーバを立てるもの

// main16.go 現在の居場所は、c:\Users\ebata\hirohakama\199A2\others
/*
.
├── main16.go
├── index.html (A)
└── chart            # chartフォルダに静的ファイルがある
    └── index.html (B)
*/

package main

import (
	"net/http"
)

func main() {

	// 静的ファイル配信.
	// ディレクトリ名をURLパスに使う場合
	// 例:http://localhost:8080/chart/で index.html (B) の方を表示
	http.Handle("/chart/", http.FileServer(http.Dir("./")))

	// 例:http://localhost:8080/で index.html (A) の方を表示
	http.Handle("/", http.FileServer(http.Dir("./")))

	// ディレクトリ名とURLパスを変える場合
	// 例:http://localhost:8080/mysecret/sample1.txt
	// http.Handle("/mysecret/", http.StripPrefix("/mysecret/", http.FileServer(http.Dir("./contents"))))

// 例:http://localhost:8080/で index.html (A) の方を表示
	http.Handle("/", http.FileServer(http.Dir("./")))
	// 8080ポートで起動
	http.ListenAndServe(":8080", nil)
}

これで、main16.goが置いている場所が、基準点となります(それだけです)。

で、色々考えずに、基本は、

http.Handle("/", http.FileServer(http.Dir("./")))

としておきましょう(というか、これがデフォルトなら、記載すらしなくてもいい)

2. http.HandleFunc()は、ソースコードで書いたものをサーバとするもの

// main15.go 現在の場所はc:\Users\ebata\hirohakama\199A2\others

/*
.
└── main15.go

*/

package main

import (
	"io"
	"log"
	"net/http"
)

func h1(w http.ResponseWriter, _ *http.Request) {
	io.WriteString(w, "Hello from a HandleFunc #1!\n")
}

func h2(w http.ResponseWriter, _ *http.Request) {
	io.WriteString(w, "Hello from a HandleFunc #2!\n")
}

func main() {

	// http://localhost:8080/ で h1の内容を表示 (プログラムの内容を)
	http.HandleFunc("/", h1)

	// http://localhost:8080/endpoint で h2の内容を表示
	http.HandleFunc("/endpoint", h2)

	log.Fatal(http.ListenAndServe(":8080", nil))
}

3. http.Handle()1つとhttp.handleFunc()1つが混在しているものは、それぞれサーバが2つある、ということ

// main13.go

package main

import (
	"fmt"
	"log"
	"math/rand"
	"net/http"
	"time"

	"github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{}

type GetLoc struct {
	ID    int     `json:"id"`
	Lat   float64 `json:"lat"`
	Lng   float64 `json:"lng"`
	TYPE  string  `json:"type"` // "PERSON","BUS","CONTROL
	POPUP int     `json:"popup"`
	//Address string  `json:"address"`
}

func echo3(w http.ResponseWriter, r *http.Request) {
	upgrader.CheckOrigin = func(r *http.Request) bool { return true } // おまじない
	conn2, err := upgrader.Upgrade(w, r, nil) //conn2でwebsocketを作成
	if err != nil {
		log.Println("websocket connection err:", err)
		return
	}
	defer conn2.Close()

	for {
		gl2 := new(GetLoc)
		gl2.ID = rand.Intn(20) // ここで乱数を発生されて、javascriptで受信させる
		gl2.Lat = 181.0
		gl2.Lng = 181.0
		gl2.TYPE = "BUS"
		gl2.POPUP = 101

		err := conn2.WriteJSON(&gl2)
		if err != nil {
			log.Println("ReadJSON:", err)
			break
		}
		fmt.Println("echo3:", gl2)
		time.Sleep(time.Second * 1)
	}

}

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

func main() {

	http.Handle("/chart/", http.FileServer(http.Dir("./")))

	http.HandleFunc("/echo3", echo3)

	//log.Println("server starting...", "http://localhost:8080")
	//log.Fatal(http.ListenAndServe("localhost:8080", nil))
	log.Fatal(http.ListenAndServe(":8080", nil))
}

index.html

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>test</title>

</head>

<script type="text/javascript" src="moment.js"></script>
<script type="text/javascript" src="Chart.js"></script>
<script type="text/javascript" src="chartjs-plugin-streaming.js"></script> 



<script>  
    var ws;

    // websocketのオープン(この段階で接続完了)
    ws = new WebSocket('ws://localhost:8080/echo3')  // ユーザ登録画面

    ws.onopen = function (event) {
    }

    ws.onmessage = function (event) {
        // 送られてきたデータを受信して、JSON形式に変更
        var obj = JSON.parse(event.data);
        console.log("obj:",obj);
        console.log("obj.id:",obj.id);
        aa = obj.id;
    }
</script>  

<body BGCOLOR="black" text="white"  STYLE="overflow: hidden;">

	<center>
	  <font size="5">Waking Time(min.) <br></font> <!--- 意味のない表示 -->
	  <font size="5"> 歩行時間(分)</font> <!--- 意味のない表示 -->
	</center>
	
    <canvas id="myChart" width="100" height="85"></canvas>


<script>  
    var ctx = document.getElementById('myChart').getContext('2d');
			var chart = new Chart(ctx, {
				type: 'line',
				data: {
					datasets: [{
                        data: [],  // 1つめ
                        borderColor: "rgba(255,0,0,1)",
                        backgroundColor: "rgba(0,0,0,0)",  
                        lineTension: 0,
                        label: 'Time',
					}]
				},
				options: {
					scales: {
						xAxes: [{
                            type: 'realtime',
                            realtime: {
                                duration: 30000, // 300000ミリ秒(5分)のデータを表示 (コメントアウトすると早く動く)
                                onRefresh: function(chart) {
                                    chart.data.datasets.forEach(function(dataset) {
                                        dataset.data.push({
                                            x: Date.now(),
                                            //y: (Math.floor(Math.random()*16)+30) //30-45の乱数(整数)
                                            y: aa, // この"aa"が、送られてきたデータ
                                        });
                                    });
                                }
                            }

                        }],
                        yAxes: [{
					        ticks: {
					        	max: 20,
					        	min: 0
        					}
                        }]
					}
				}
			});

</script>

</body>
</html>

 

この場合、

  • /chart/index.htmlをベースとするサーバと、
  • echo3()が作るサーバ

の2つがある、ということ。

実際のところ、echo3は、/chart/index.html のクライアント(データの送信元)でもあるんだけど、要求があれば、ポコポコ作り出される、という点ではサーバでもある、という形になっています。

―― という説明を、次に私が頭を抱えた時に、私が思い出せるのかが、不安です

 

2022/08,江端さんの技術メモ

csvファイル形式でデータを送るのではなく、プログラムから直接データを放り込むプログラム

 

// main13.go

package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{}

type GetLoc struct {
	ID    int     `json:"id"`
	Lat   float64 `json:"lat"`
	Lng   float64 `json:"lng"`
	TYPE  string  `json:"type"` // "PERSON","BUS","CONTROL
	POPUP int     `json:"popup"`
	//Address string  `json:"address"`
}

func echo2(w http.ResponseWriter, r *http.Request) {
	conn2, err := upgrader.Upgrade(w, r, nil) //conn2でwebsocketを作成
	if err != nil {
		log.Println("websocket connection err:", err)
		return
	}
	defer conn2.Close()

	for {
		gl2 := new(GetLoc)
		gl2.ID = 101
		gl2.Lat = 181.0
		gl2.Lng = 181.0
		gl2.TYPE = "BUS"
		gl2.POPUP = 101

		err := conn2.WriteJSON(&gl2)
		if err != nil {
			log.Println("ReadJSON:", err)
			break
		}
		fmt.Println("echo2:", gl2)
		time.Sleep(time.Second * 1)
	}

}

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

func main() {
	http.Handle("/", http.FileServer(http.Dir(".")))

	http.HandleFunc("/echo2", echo2)

	log.Println("server starting...", "http://localhost:5000")
	log.Fatal(http.ListenAndServe("localhost:5000", nil))
}

index.htmlはこちら

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>test</title>

</head>
<body>
    <form>
    </form>

    <script>  

        var ws;

        // websocketのオープン(この段階で接続完了)
        ws = new WebSocket('ws://localhost:5000/echo2')  // ユーザ登録画面

        ws.onopen = function (event) {
		    }

        ws.onmessage = function (event) {

          // データをJSON形式に変更
          var obj = JSON.parse(event.data);
          console.log("obj:",obj);
        }
   
    </script>
</body>
</html>

2022/08,江端さんの技術メモ

Keyword マイク スピーカー 音 声 音声 office teams 設定 失敗

最近、リモート会議で結構スピーカーとかマイクの設定でコケるので、設定画面を書き出しておく。

だいたい、このスピーカーとマイクの設定でコケている

2022/08,江端さんの技術メモ

OpenStreetMapを使って、シミュレータを作成していますが、昨今のセキュリティ事故などを鑑みて、インターネットへのアクセスが一切禁じられた状態での使用を想定しておかなければなりません。

という訳で、OpenStreetMapから地図をバラバラにした画像ファイル(タイル)のダウンロードを試みているのですが、適当にダウンロードすると、不要なタイルまでダウンロードして、

(1)OpenStreetMapのサーバに負荷を与える(という公的な理由)こと

(2)ローカルに不要なファイルが大量に残る(という私的な理由)こと

が、なんとも気にいりません。

ならば「キャッシュに残っているタイルだけをダウロードすればよくね?」と思い(足りなくい部分が見つかったら、その部分だけ再度ダウンロードすればいい)、検討を開始しました。

先ず、キャッシュされている情報を確認してみました。

展開すると、こんな感じ

さて、キャッシュされている、タイルのダンロード先を見つける方法が必要でした。

これは、chrome_cache_view というツールを使うことで解決できそうであることが分かりました。

↓をクリックすると、画面に飛びます。

で、ここからダウンロードします。

解凍して、exeファイルをクリックします。

こんな感じでタイルサーバの位置とファイル名が分かります。

で、tile.osm.org の部分のファイルだけを取り出せればよいのですが、(今のところ、私には、見つけられていません)ので、"Edit" → "Select All" で全部のテキストを取り出して、適当にファイルをぶった切って、取り出すことにしました (良いやり方があったら、私に教えて下さい)。

# ちなみに、この取り出し方は、皆さんの方で好きなようにやって下さい(私は、grepと、emacsを使って手動で切り出すことにしました)。

私の場合、まず、"Edit" → "Select All" で全部のテキストをdummy.txtという名前で保存して、

grep tile.osm.org dummy.txt > dummy2.txt

として

になっている状態で、emacsのkill-rectangle で両端を切り落しました。

さて、ここから問題なのですが、OpenStreetMapの格納方法は、なんでもダウンロードすれば良い、というものではなく、ルールがあります。

/* map の表示準備 */
const map = L.map("map", {
    attributionControl: false,
    zoomControl: false
}).setView(CENTER_LATLNG, 14);
if (USE_OFFLINE_MAP) {
    L.tileLayer('images/map-yamaguchi/{z}/{x}/{y}.png', {
        detectRetina: true,
        minZoom: 13,
        maxZoom: 15,
    }).addTo(map);
}
else {
    L.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png', {
        detectRetina: true,
        maxNativeZoom: 18
    }).addTo(map);
}
つまり

https://c.tile.osm.org/18/232959/102413.png
の場合、

"18"というディレクトリを作成し、さらにその中に"232959"というサブディレクトリを作成し、その中に"102313.png"というファイルを配置させる必要があるのです。

これを実施するプログラムをGolangで作りました。

/*
	main13.go

	キャッシュで取り込まれているOpenStreetMapのタイル画像(png)を、ローカルに取り込んで、
	ネットに繋がれていない状況でも、OpenStreetMapを使えるようにする

	前提
	http://www.nirsoft.net/utils/chrome_cache_view.html からChromeCacheView をダウンロードして、
	"https://b.tile.osm.org/13/7284/3196.png"などを取得しておくこと
*/

package main

import (
	"io"
	"net/http"
	"os"
	"strings"

	_ "github.com/lib/pq"
)

func main() {

	var urls = [...]string{
		"https://b.tile.osm.org/13/7284/3196.png",
		"https://c.tile.osm.org/18/232959/102413.png"} // ここに取得したいURLを記載する

	for _, url := range urls {

		arr1 := strings.Split(url, "/")

		//fmt.Println(arr1[3]) // 確認用
		//fmt.Println(arr1[4]) // 確認用
		//fmt.Println(arr1[5]) // 確認用

		os.Mkdir(arr1[3], 0777) // ディレクトリを掘る(すでに掘っていてもOKみたい)
		os.Chdir(arr1[3])       // カレントディレクトリを移動する
		os.Mkdir(arr1[4], 0777) // ディレクトリを掘る(すでに掘っていてもOKみたい)
		os.Chdir(arr1[4])

		response, err := http.Get(url)
		if err != nil { // カレントディレクトリを移動する
			panic(err)
		}
		defer response.Body.Close()

		file, err := os.Create(arr1[5])
		if err != nil {
			panic(err)
		}
		defer file.Close()

		io.Copy(file, response.Body) // ここでダウンロードしたファイルをセーブ

		err = os.Chdir("../..") // ディレクトリを元の位置に戻す(2つ上がる)
		if err != nil {
			panic(err)
		}
	}
}

こんな感じで、上手く動いているようです。

上手く動いていません。

 

ダウンロードした全部のファイルに、

Access denied. See https://operations.osmfoundation.org/policies/tiles/

というテキストが書かてているファイルがダウンロードされています。

どうも、以下の問題みたいです。

Technical Usage Requirements

  • Valid HTTP User-Agent identifying application. Faking another app’s User-Agent WILL get you blocked. Using a library’s default User-Agent is NOT recommended. If a device automatically sends an X-Requested-With header with an application specific Application ID, this will be considered an acceptable substitute for the HTTP User-Agent, although we still recommend setting a valid HTTP User-Agent for the application.
  • When coming from a web page, a valid HTTP Referer. Apps generally do not have a HTTP referer.
  • DO NOT send no-cache headers. (“Cache-Control: no-cache”, “Pragma: no-cache” etc.)
  • Cache Tile downloads locally according to HTTP Expiry Header, alternatively a minimum of 7 days.
  • Maximum of 2 download connections. (Unmodified web browsers’ download limits are acceptable.)

技術的な使用条件
アプリケーションを識別する有効なHTTP User-Agent。他のアプリケーションのUser-Agentを偽装すると、ブロックされる可能性があります。ライブラリのデフォルトのUser-Agentを使用することは推奨されません。デバイスがアプリケーション固有の Application ID を持つ X-Requested-With ヘッダを自動的に送信する場合、これは HTTP User-Agent の代用として認められますが、アプリケーションに対して有効な HTTP User-Agent を設定することを推奨します。
ウェブページからアクセスする場合は、有効なHTTP Refererを指定します。アプリは一般的にHTTP Refererを持ちません。
no-cacheヘッダを送信しないでください。("Cache-Control: no-cache", "Pragma: no-cache" など)
HTTP Expiry Headerに従ってTileダウンロードをローカルにキャッシュします。
ダウンロード接続は最大2回まで。(修正されていないウェブブラウザのダウンロード制限も許容されます)。
注:標準的な設定の最近のウェブブラウザは、一般に上記の技術的要件をすべてクリアしています。

今、対策中です。暫くお待ち下さい。

以下のように変更したら動きました。


/*
	main14.go

	キャッシュで取り込まれているOpenStreetMapのタイル画像(png)を、ローカルに取り込んで、
	ネットに繋がれていない状況でも、OpenStreetMapを使えるようにする

	前提
	http://www.nirsoft.net/utils/chrome_cache_view.html からChromeCacheView をダウンロードして、
	"https://b.tile.osm.org/13/7284/3196.png"などを取得しておくこと
*/

package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"

	_ "github.com/lib/pq"
)

func main() {

	var urls = [...]string{
		"https://c.tile.osm.org/18/232959/102413.png",
		"https://b.tile.osm.org/18/232955/102413.png",
		"https://c.tile.osm.org/18/232959/102413.png"} // ここに取得したいURLを記載する

	for _, url := range urls {

		arr1 := strings.Split(url, "/")

		//fmt.Println(arr1[3]) // 確認用
		//fmt.Println(arr1[4]) // 確認用
		//fmt.Println(arr1[5]) // 確認用

		os.Mkdir(arr1[3], 0777) // ディレクトリを掘る(すでに掘っていてもOKみたい)
		os.Chdir(arr1[3])       // カレントディレクトリを移動する
		os.Mkdir(arr1[4], 0777) // ディレクトリを掘る(すでに掘っていてもOKみたい)
		os.Chdir(arr1[4])

		/*  削除
		response, err := http.Get(url)
		if err != nil { // カレントディレクトリを移動する
			panic(err)
		}
		defer response.Body.Close()
		*/

		// 追加(ここから)
		client := &http.Client{}

		req, err := http.NewRequest("GET", url, nil)
		if err != nil {
			fmt.Println(err)
			return
		}
		req.Header.Set("User-Agent", "super-go-client")
		// 追加(ここまで)

		file, err := os.Create(arr1[5])
		if err != nil {
			panic(err)
		}
		defer file.Close()

		// 追加(ここから)
		r, _ := client.Do(req)
		defer r.Body.Close()
		// 追加(ここまで)

		/*
			_, err = io.Copy(file, response.Body) // ここでダウンロードしたファイルをセーブ
		*/

		// 追加(ここから)
		_, err = io.Copy(file, r.Body)
		// 追加(ここまで)
		if err != nil {
			panic(err)
		}

		err = os.Chdir("../..") // ディレクトリを元の位置に戻す(2つ上がる)
		if err != nil {
			panic(err)
		}
	}
}

これで、画像ファイルとして取り出せることが確認できました。

req.Header.Set("User-Agent", "super-go-client")

がポイントだったようです。

予想通り、キャッシュのないところが、欠けています。これは、運用して直していけばいいので、そのうち直します。

ちなみに、index.htmlの方は、

var map = L.map("map", {
			attributionControl: false,
			zoomControl: false
		}).setView(new L.LatLng(36.56240644, 139.9501693), 14); // 宇都宮

		//L.tileLayer('http://localhost:8080/static/{z}/{x}/{y}.png',{
		L.tileLayer('static/{z}/{x}/{y}.png',{
        	detectRetina: true,
        	//minZoom: 13,
        	//maxZoom: 15,
			maxNativeZoom: 18
    	}).addTo(map);


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

のように、

L.tileLayer('http://localhost:8080/static/{z}/{x}/{y}.png',{

でも、

L.tileLayer('static/{z}/{x}/{y}.png',{

でも、動作するようです。

2022/08,江端さんの技術メモ

アイコン↓

csvファイル"fes.csv"↓ (index.htmlと同じディレクトリに置いています)

1, 35.59609497295185, 139.47514321636098
2, 35.593735148646594, 139.46728972468222
3, 35.597968040183645, 139.47051770314877

対応部分のJavaScript(私は、index.htmlに埋め込んでいます)

// 複数のイベント会場をcsvファイルから読み取って作ってみる
		//
		// "fes.csv"の内容
		// 1, 35.59609497295185, 139.47514321636098
		// 2, 35.593735148646594, 139.46728972468222
		// 3, 35.597968040183645, 139.47051770314877
		// 

		fes_icon = L.icon({iconUrl:'https://192.168.0.8:8080/static/fes.png',
        //iconSize: [36, 60], iconAnchor: [18, 60], popupAnchor:[0,-60]});
        iconSize: [60, 36], iconAnchor: [30, 18]});		

	 	// 以下のような書き方ができるらしい(lat, lon)の座標にマーカーを作り,icon情報を与え,ポップアップメッセージを追加する
 		//L.marker( [ lat, lon],{ icon:quad_x_Icon } ).addTo( mymap ).bindPopup( drone_popmessage );

		// CSVファイルを文字列として取得
		let srt = new XMLHttpRequest();
		srt.open("GET", 'fes.csv', false);

		try {
			srt.send(null);
		} catch (err) {
			console.log(err)
		}

		// 配列を用意
		let csletr = [];

		// 改行ごとに配列化
		let lines = srt.responseText.split(/\r\n|\n/);

		// 表示
		console.log(lines)

		// 1行ごとに処理
		for (let i = 0; i < lines.length; ++i) {
			let cells = lines[i].split(",");
			if (cells.length != 1) {
				csletr.push(cells);
			}
		}

		// (試しの)表示
		console.log(csletr)
		console.log(csletr[0][0]) // "test1"
		console.log(csletr[2][1]) // "2"

		// var _lat = 35.59609497295185;
		// var _lon = 139.47514321636098;		// 広袴

		for (let i = 0; i < lines.length; ++i) {		
			var _lat = csletr[i][1]  
			var _lon = csletr[i][2]

	        var fes_marker = L.marker(
    	        [_lat, _lon], 
        	    { popup: 'Origin', draggable: true,  opacity:1.0, icon:fes_icon}
        	).addTo(map);
		}

表示結果↓

以上

 

2022/08,江端さんの技術メモ

WP Githuber MD を有効化する

# 私は、クラッシックエディタとの共存に失敗している為

以上

2022/08,江端さんの技術メモ

WordPressの、クラッシックモードの、「ビジュアル」「テキスト」が表示されなくなった時には、
(以下は見えている状態)

が見えなくなった時は、以下の「ビジュアルリッチエディターを使用しない」のチェックを外す。

以上

2022/08,江端さんの技術メモ

以下のコードは、javascript csvファイルを読み込んで配列化するから丸ごとコピペさせて頂いたものです。

不要なエラー処理やら、ゴチャゴチャしたメソッドとかがなく、実に分かりやすい、素晴しいサンプルコードです。

私の為にコピペさせて頂きました。

<!-----
Javascriptから、csvファイルを読み込む方法

test.csv の中身
test1,test2,test3
a,b,c
1,2,3
----->
<!doctype html>
<html lang="ja">
<head>
    <script>
        // CSVファイルを文字列として取得
        let srt = new XMLHttpRequest();

        srt.open("GET", 'test.csv', false);

        try {
            srt.send(null);
        } catch (err) {
            console.log(err)
        }

        // 配列を用意
        let csletr = [];

        // 改行ごとに配列化
        let lines = srt.responseText.split(/\r\n|\n/);

        // 表示
        console.log(lines)

        // 1行ごとに処理
        for (let i = 0; i < lines.length; ++i) {
            let cells = lines[i].split(",");
            if (cells.length != 1) {
                csletr.push(cells);
            }
        }

        // 表示
        console.log(csletr)
        console.log(csletr[0][0]) // "test1"
        console.log(csletr[2][1]) // "2"
    </script>
</head>
<body>

</body>
</html>

だから、今一度、言おう。『インターネット、ばんざい』

 

2022/08,江端さんの技術メモ

出典 https://www.gixo.jp/blog/327/

最近、よく使われる「アウトカム」という言葉の意味をちょくちょく忘れるので、上記出典よりメモとして画像のみをリンクさせて頂きました。