2021/01,江端さんの技術メモ

最近、PC起動時に、

C:\Users\ebata>docker ps
Error response from daemon: open \\.\pipe\docker_engine_linux: The system cannot find the file specified.

などが出てきて、ドキっとさせられる症状が頻発している。

基本的には、Dockerアイコンを使って再起動(Restart docker...)で、改善するんだけど、心臓に悪い。

近い内に、何か起こりそうな気がします。

 

 

2021/01,江端さんの忘備録

ブラウザから、NHKプラスを立ち上げて、7時のNHKニュースを見るのが日課です。

I have started up "NHK Plus" from my computer browser and watched the 7 o'clock NHK news.

本日はたまたま、あさイチの『人生&社会が変わる!すごいぞ“推し活”パワー』という特集を見ました。

Today, I happened to watch a special feature on the TV show entitled "Life and Society Change! Amazing pushing power of "fan".

私、アイドルとかアニメとかに狂っているやつらのことを ―― かなり『リスペクト』しています。

I have a lot of respect for the people who are crazy about idols and animes.

まあ、私自身、アニメ好きですからね。

Well, I'm an anime fan myself.

シュタインズゲートとか、シュタインズゲートゼロとか。

Like Steins;Gate, or Steins;Gate Zero.

ただ、私は、「特定のキャラクターを"推す"」という感じは、あまり良く分かりません。

However, I don't really understand the feeling of "pushing" for a particular character.

でも、そういう、"推し"方も"あり"だと思います ―― というか、そちらが主流でしょう。

But I think the "pushing" is also good -- or rather, that's the mainstream.

-----

ところが、これが、プロ野球、プロサッカー、相撲、その他、スポーツ関係になると、私は、そのような『リスペクト』が全く発動しません。

However, when it comes to professional baseball, soccer, sumo, and other sports, I don't have any such "respect".

もう、1ミリメートルどころか、1ピコメートルもありません。

It's not even a millimeter anymore, but a picometer.

これは、私がティーンエイジャの頃、頭の悪い運動部の奴らから、嫌悪されていたことに端を発するのかもしれません。

This may be due to the fact that when I was a teenager, I was loathed by the dumb athletic guys.

特にラグビー部のやつらは、どの大会でも一勝もできない程度の実力のくせに、酷くエラそうにしていたので、私はやつらが大嫌いでした。

I hated them, especially the guys on the rugby team, because they couldn't win a single game in any tournament, but they always looked like they were going to win.

逆に、彼らから見た私は、小賢しく政治や哲学を語るような奴であり、不快に感じたのであろうことは、(今なら)理解できます。

On the other hand, I can understand (now) that from their point of view, I was a guy who talked politics and philosophy in a petty way, and they must have felt uncomfortable.

お互いが、お互いを軽蔑し合うことで、不快が育成され続けたのだと思うのです。

I think the discomfort continued to be fostered by our mutual disdain for one another.

まあ、今から考えれば「双方バカ」でケリがつく話で ―― ただ、不快の記憶だけが残った、というだけです。

Well, in hindsight, it was "stupid on both sides", and the only thing that remains is the unpleasant memory.

残念ながら、私が、これから、プロ野球、プロサッカー、相撲、その他、スポーツ関係のファンになる可能性は、絶無であると断言できます。

Unfortunately, there is no chance that I will ever become a fan of professional baseball, soccer, sumo wrestling, or any other sports-related activities.

# あ、但し、スキー(のモーグルと大回転)だけは別です。

# Oh, except for skiing (moguls and giant slalom).

-----

それゆえ、私は、飲み会が苦手なのです。

Hence, I don't like drinking parties.

スポーツの話題でなくても、私は、(1)エヴァンゲリオンを熱く語る奴、(2)三国志の登場人物を挙げて得意になっている奴、も嫌いです。

Even if the topic is not sports, I also dislike (1) people who talk passionately about Evangelion, and (2) people who are good at naming characters of the Three Kingdoms.

一方、私は、あなたが、(A)働き方改革の問題点を指摘する奴とか、(B)新型コロナウイルスの感染戦略が成立しない話を語る奴が、嫌いであることも知っています。

On the other hand, I know that you don't like guys who (a) point out the problems with the way things work, or (b) tell stories about new coronaviruses whose transmission strategies are not viable.

故に、『飲み会は、世界からなくなっていい』と思っています。

Therefore, I believe that "drinking parties should disappear from the world"

2021/01,江端さんの技術メモ

この環境↓を前提として、

(まとめ)地図DBの作り方

Dockerの環境にて、ca_sim2ののダンプによるsqlファイル(map5.sql)の作成に先程成功しました。

[江端メモ]
root@6432e639f678:/db_data#
>pg_dump -U postgres ca_sim2 > map5.sql
>mv map5.sql /db_data (これ、カレントディレクトリで作業しているなら不要です)

C:\Users\ebata\toyosu>docker cp toyosu_db_1:/db_data/map5.sql map5.sql

(まあ、私の環境でなければ、分からないとは思います)

2021/01,江端さんの技術メモ

QGIS3でosmファイルを地図表示する方法

いつも、osmファイルをドラッグする場所を忘れるので、メモ

すると、こうなる。

以上

2021/01,江端さんの忘備録

まずこのページを開いて下さい。

First, please open this page.

感染症名に「インフルエンザ」または「インフルエン入院」を選び、「前年と比較」をチェックし、「更新」ボタンを押して下さい。

Select "Influenza" or "Influenza Hospitalization" as the name of the infectious disease, check the "Compare with previous year" box, and click the "Update" button.

今年度、インフルエンザが全く流行していないことが明白です。

It is obvious that there has been no flu epidemic at This fiscal year.

-----

私達は、今、『外出すれば、どこにいっても、20分以内にアルコール消毒のボトルがある』という、人類史上、見たこともないような、超が3つほどつく「衛生的」な世界に生きています。

We are now living in the first "hygienic" world in human history, where you can go out and find a bottle of rubbing alcohol within 20 minutes.

今年度、我々は、インフルエンザを完全に封じ込んだ、といっても過言ではないと思います。

I don't think it is an exaggeration to say that we have completely contained the flu this year.

これだけの超衛生的な世界に中にあって、、(私の試算では)通常のインフルエンザの約20~40倍の致死率がある、新型コロナ感染者数が減りません。

In this ultra-hygienic world, the number of people infected with the new corona, which is (by my estimate) 20 to 40 times more deadly than the regular flu, is not decreasing.

というか、「インフルエンザを完全に抑え込んでいる世界の中で、なんという殺人的な感染力か」、と、溜息が出るほどです。

I mean, "What a murderous infection in a world that has the flu completely under control". I can't help but sigh.

-----

■パチンコ店での、顧客(×従業員)のクラスターは確認されていない

- No clusters of customers (x employees) have been identified in pachinko parlors.

■通常授業の範囲内(×課外のスポーツ授業)で、学校でのクラスターの発生率は驚くほど低い

- Within the scope of regular classes (x extra-curricular sports classes), the incidence of clusters in schools is surprisingly low.

■通勤電車等は、クラスターと特定できる証拠は出てこない(というか、これは追跡不能かと思います)

- There is no evidence of clusters on commuter trains (or maybe this is untraceable).

以上より、

As a result,

『クラスターの発生条件は、対面会話による飛沫感染』であることは、もう誰が見ても明らかなのに、

Though it's obvious to everyone that the cluster is caused by droplet infection from face-to-face conversation,

まだ『歓楽街で騒いで飲んでいるバカがいる』という事実に唖然とします。

I am stunned by the fact that there are still "idiots making noise and drinking in the entertainment district".

-----

キャバクラでも、バーでも、メイド喫茶でもどこでも、好きなところに、好きなだけ行けばいい。

You can go to a cabaret, a bar, a maid cafe, or anywhere you want, for as long as you want.

忘年会でも新年会でも、思う存分やればいい。

Whether it's a year-end party or a New Year's party, you can do as much as you want.

むしろ、飲食業を助けるために、多くの人が、積極的に行くべきだと思う。

Rather, I think many people should actively go there to support the restaurant industry.

ただし、『一人で飲み食いをする』『接待なし』『酒を飲みながら文庫本でも読んでいる』

However, "you drink and eat alone," "you don't entertain," and "you read a paperback while drinking"

これさえ守れば、まず大丈夫です。

As long as you follow these instructions, you should be fine.

飲食店は、集団客を、バラバラの席に案内すればいい ――

"A restaurant can take a group of customers and seat them in different places "

職場の仲間であろうと、顧客の接待であろうと、家族であろうと、恋人であろうと、「例外なし」です。

No exceptions," whether it's a colleague at work, a client's entertainment, a family member, or a lover.

-----

しかし、私のこの主張を、飲食店で働く嫁さんは『ナンセンス』と一蹴しました。

However, my wife, who works in a restaurant, kicked it off as "nonsense".

飲食店が「会話を楽しみながら食事をする場所」である以上、そのようなサービスは「飲食店の自己否定と同じだ」というようなことを言われました。

She told me that since restaurants are "places where people eat while enjoying conversation", such services are "the same as denying the restaurant's self".

そりゃそうだ、とも思うのですが。

That's right, I guess, however,

でも、私、「居酒屋で一人飯」というの普通にしていますし、「バラバラの席で新年会」と言われたら、むしろ喜んで参加します。

But I usually have "dinner alone at an izakaya", and if someone says "New Year's party at a discrete table", I'm more than happy to join.

2021/01,江端さんの技術メモ

0.追記(江端が、今、必要な情報をトップに)

### STLって面倒(strcpyでええやん)

// added by Ebata 2021/01/04
#include "simple_udp.h"

// Ebata added simple_udp 2021/01/05                                                                                    
simple_udp udp0("192.168.0.8",12345);

// added by Ebata 2021/01/04
std::cout << "Ebata:User:  " << user.id() << "," << user.current_xy().x() << "," << user.current_xy().y() << std::endl;
std::stringstream ss;
ss << "Ebata:User:  " << user.id() << "," << user.current_xy().x() << "," << user.current_xy().y() << std::endl;

// simple_udp udp0("192.168.0.8",12345);
udp0.udp_send("hello!\n");

//udp0.udp_send(ss);  エラー
//udp0.udp_send(ss.c_str()); エラー
udp0.udp_send(ss.str());

1.背景

LinuxのDockerコンテナの中から、一方的に、ホストOSにデータを放り投げる為のUDPプログラムです。

1行程度のデータをコンテナの外に出したいだけなのに、なかなか、良い方法が見つからず、結局UDP socketを使ってしまいました(websocket用にサーバを作るのも大袈裟で面倒でした(3~4行程度で記述したかった))。

ちなみに、UDPは、相手がいようがいまいが、一方的に送信し、一方的に受信待ちができる、とても便利な通信方式です。当然、送達保証はありません。

2. 環境

私のホストOSのIPアドレスは、192.168.0.8、ポートは、12345 と適当に選びました。

普通DockerにはUDPのポートオープンの設定が必要だと思いますが、今回は、テストプログラムでたまたまpingとUDPが通ってしまったので、何もやっていません(運が良かっただけかもしれません)。

テスト用のUDPプログラムは、こちら「UDP送受信プログラム」を使いました(何でも残しておくものです)

3.ソースコード

まるまる、こちらをコピペさせて頂きました → 「メカトロ講座03 c++でudp通信をする方法」

一行でUDP送信ができるようにしたかったもので。

3.1 共通のヘッダファイル(simple_udp.h)

// g++ -std=c++11 としないと動かない(ことがある)

// simple_udp.h

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string>  // "string.h"だと通らないことがあるので、注意のこと(私は、ここで2時間ほど嵌った)

class simple_udp{
  int sock;
  struct sockaddr_in addr;
public:
  simple_udp(std::string address, int port){
    sock = socket(AF_INET, SOCK_DGRAM, 0);
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(address.c_str());
    addr.sin_port = htons(port);
  }
  void udp_send(std::string word){
    sendto(sock, word.c_str(), word.length(), 0, (struct sockaddr *)&addr, sizeof(addr));
  }

  void udp_bind(){
    bind(sock, (const struct sockaddr *)&addr, sizeof(addr));

  }
  std::string udp_recv(){
            #define BUFFER_MAX 400
    char buf[BUFFER_MAX];
    memset(buf, 0, sizeof(buf));
    recv(sock, buf, sizeof(buf), 0);
    return std::string(buf);
  }
  void udp_recv(char *buf, int size){
    memset(buf, 0, size);
    recv(sock, buf, size, 0);
  }

  ~simple_udp(){
    close(sock);
  }
};

3.2 送信プログラム(udp_sendto.cpp)

// g++ udp_sendto.cpp -o udp_sendto で大丈夫だが、g++ -std=c++11としないと動かない(ことがある)

#include <stdio.h>
#include <string.h>
#include "simple_udp.h"

simple_udp udp0("192.168.0.8",12345); // ホストOSのUDPの受信側

int main(int argc, char **argv){
  udp0.udp_send("hello!");
  return 0;
}

3.3 受信プログラム(udp_recvfrom.cpp)

// g++ udp_recvfrom.cpp -o udp_recvfrom で大丈夫だが、g++ -std=c++11としないと動かない(ことがある)
#include <stdio.h>
#include <string.h>
#include "simple_udp.h"
simple_udp udp0("0.0.0.0",12345);

int main(int argc, char **argv){
  udp0.udp_bind();
  while (1){
    std::string rdata=udp0.udp_recv();
    printf("recv:%s\n", rdata.c_str());
  }
  return 0;
}

4.Windows10でMinGWのgccを使ってる私の場合のケース

以下のように変更した

4.1 共通のヘッダファイル(simple_udp.h)

// simple_udp.h

/* Windows版 */
#include <stdio.h>
#include <sys/types.h>
#include <winsock2.h>
#include <ws2tcpip.h>
//#include <sys/socket.h>
//#include <netinet/in.h>
//#include <arpa/inet.h>
//#include <netdb.h>
#include <string>  // "string.h"だと通らないことがあるので、注意のこと(私は、ここで2時間ほど嵌った)
#include <unistd.h> // error: 'close' was not declared in this scope; did you mean 'fclose'?


class simple_udp{
  int sock;
  struct sockaddr_in addr;

  // Windows専用おまじない(ここから)
  WSADATA wsaData;
  // Windows専用おまじない(ここまで)	  

 public:
  simple_udp(std::string address, int port){

	// Windows専用おまじない(ここから)
	WSAStartup(MAKEWORD(2,0), &wsaData);
	// Windows専用おまじない(ここまで)	  
	  
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(address.c_str());
	addr.sin_port = htons(port);
  }
  void udp_send(std::string word){
	sendto(sock, word.c_str(), word.length(), 0, (struct sockaddr *)&addr, sizeof(addr));
  }
  
  void udp_bind(){
	bind(sock, (const struct sockaddr *)&addr, sizeof(addr));
  }
  std::string udp_recv(){
#define BUFFER_MAX 400
	char buf[BUFFER_MAX];
	memset(buf, 0, sizeof(buf));
	recv(sock, buf, sizeof(buf), 0);
	return std::string(buf);
  }
  
  void udp_recv(char *buf, int size){
	memset(buf, 0, size);
	recv(sock, buf, size, 0);
  }
  
  ~simple_udp(){
	close(sock);
  }
};

4.2 送信プログラム(udp_sendto.cpp)

(T.B.D.)  # 現時点では、Windows10(ホストOS側は受信専用なので、不要だから)

4.3 受信プログラム(udp_recvfrom.cpp)

// g++ udp_recvfrom.cpp -o udp_recvfrom で大丈夫だが、g++ -std=c++11としないと動かない(ことがある)
// Windows の場合は、g++ -g udp_recvfrom.cpp -o udp_recvfrom -lwsock32 -lws2_32

#include <stdio.h>
#include <string.h>
#include "simple_udp.h"

simple_udp udp0("0.0.0.0",12345);

int main(int argc, char **argv){
  udp0.udp_bind();
  while (1){
    std::string rdata=udp0.udp_recv();
    printf("recv:%s\n", rdata.c_str());
  }
  return 0;
}

2021/01,江端さんの忘備録

正月三が日が過ぎて、我が家の保護者チームは、通常運転に入っています。

The three New Year's days have passed, and parent team of the Ebata is now in normal operation.

江端家では、今年、久々の家族揃っての年末年始を過すことになりました。

This year, the Ebata family will be spending the year-end and New Year holidays together for the first time in a long time.

家庭内感染を防止する観点から、以前ご紹介した、リビングテーブルのアクリル版パーテイションの他に、さらに、一工夫しました。

In addition to the acrylic partitions on the table that I introduced before, we have added another tip to prevent household infections.

キャンプ用の組み立てテーブルをリビングに持ち込んで、おせち料理、鍋、手巻き寿司を、皿に乗せて、テーブルの自分の席に持ってくる方式

Bring a camping table into the living room, and putting Osechi (New Year's Eve) food, hot pot, and hand-rolled sushi on a plate, and bring it to out seats at the table,

―― ビュッフェスタイル

"buffet-style"

を採用しました。

has been installed.

勿論、それぞれの食品に対して、それぞれの取り箸を用意したのは言うまでもありません。

Needless to say, I prepared different chopsticks for each food.

ちょっと「せわしない」という感じもしましたが、これはこれで、なかなか楽しい「非日常」でした。

I felt a little "unsettled", but this was quite a fun "extraordinary" experience.

-----

「非日常」でもないかもしれません。

Maybe not even "extraordinary"

当面の間、この「アクリルパーティション」と、「バイキング用テーブル」は、リビングから撤去されることはないだろうなぁ、と、ニュース(*)を見ながら溜息を付いています。

For the time being, the acrylic partition and the buffet table will not be removed from the living room, I think, sighing as I watch the news(*).

(*)本日、関東地区の新型コロナ感染対応の非常事態宣言の予告がされました。

(*) Today, a notice was issued declaring a state of emergency in the Kanto area in response to the new corona infection.

-----

なぜ、私がここまで、家庭内感染防止に努めているかというと、

The reason why I have been trying to prevent domestic infections so far is

■感染の自覚症状なしにウイルスを運んでくるのは、間違いなく「娘たち」であること

- It is definitely the "daughters" who carry the virus without any subjective symptoms of infection.

■私が感染、発病、重篤、そして最悪、死に至った場合、娘たちは「親を死に至らしめた」という自責に念で、一生苦しむことになる

- If I become infected, sick, serious, and at worst, die, my daughters will suffer for the rest of their lives, blaming themselves for "dying their parents."

―― か、どうかは、どうでもいいです。

It doesn't matter whether or not.

私、そのことには大して興味ありません。それは娘たちの問題です。

I'm not very interested in that. It's a problem for the daughters.

-----

私のモチベーションは、ただ一つ ―― 「苦痛に対する恐怖」です。

My motivation is just "fear of pain".

新型コロナが発病し、重篤化した場合、

If the new corona becomes ill and becomes serious, I know that

■簡単には死に至れず、死に至るプロセスの「苦痛がハンパではない」ということと、

- the fact that it is not easy to die and that the process of death is "severe"

■仮に治癒したとしても、その「後遺症の苦痛もハンパではない」ということと、

Even if it heals, it means that the pain of the aftereffects is also terrible.

ということが分かっています。

そもそも、ウイルス感染症というのは、そういう風にできています。

In the first place, viral infections are like that.

------

『家族から感染したなら仕方がない』と思えるほど、私は「できた人間」ではありません。

I'm not the kind of person who can say, "If I got it from my family, I don't have a choice.

2021/01,江端さんの忘備録

自分の気に入ったコンテンツ(映画や小説やマンガ等)は、人に勧めたくなるものです。

If I like the content (movies, novels, comics, etc.), I will want to recommend it to others.

自分の気に入ったコンテンツを、他人に共感をして貰えるのは、とても幸せなことだからです。

This is because it makes me very happy to be able to share my favorite content with others.

ところが、「自分の気に入ったコンテンツ」が、「他人の気に入るコンテンツ」になるとは限りません。

However, "content that I like" does not necessarily become "content that others like".

そもそも、そのコンテンツを試して貰う為に、『他人の貴重な時間を奪う』という前処理が必要になります。

In order to get people to try out the content, you need to pre-process it by "taking up someone else's valuable time".

そして、『他人の貴重な時間を奪った』上に、『他人の気にいるコンテンツ』でもなかった場合は、

And you've "taken up someone else's valuable time" and "someone else's unfavorite content"...

もう、これは、

You should consider that

―― 損害賠償モノ

this is already the subject of damages.

と考えるべきでしょう。

最近では、こういう「自分の気に入ったコンテンツ」を、自分より立場の弱い人に強要する「ハラスメント」が問題になっているそうです。

Recently, this kind of "harassment" of forcing "your favorite content" on people who are in weaker positions than you is becoming a problem.

ここでは便宜的に、「コンテンツハラスメント」と称呼することにします。

For the sake of convenience, we will refer to it as "content harassment".

-----

私は、この"コンテンツハラスメント"の被害者になったことがあります。

I have been a victim of this "content harassment".

先輩の気に入ったコミック50冊以上を、苦痛を伴いながら読んだ日々を思い出します。

I remember painfully when I was forced to read more than 50 manga that my seniors liked.

そんでもって、その先輩に「楽しかったです」と嘘の感想を言うのは、辛いことでした。

It was hard for me to lie and say "I had a good time" to that senior.

一方、私は、この"コンテンツハラスメント"の加害者もやってきたと思っています。

On the other hand, I am also aware that I was a perpetrator of this "content harassment".

特に、自分が「非常に良い」と思った本を紹介して、「全然、面白くなかった」という感想で傷ついたことがあります。

In particular, I have been hurt when I introduced a book that I thought was "very good" and was told that it was not interesting at all.

この場合は、加害者でもありながら、被害者でもあるという、目も当てられない状況になります。

In this case, you are both the perpetrator and the victim, a situation that is hard to ignore.

-----

で、考えたのですが、「コンテンツファンディング」というのはどうでしょうか。

So, I thought, what about "content funding"?

例えば、とても気に入った映画があれば、それを、2回、3回と見にいくのではなく、その金額を、その映画に興味のない人向けにお金を寄付するのです。

For example, if you like a movie very much, instead of going to see it two or three times, you can donate that amount of money to someone who is not interested in that movie.

これは、なかなか面白い効果が期待できそうです。

This is going to have a very interesting effect.

■そのコンテンツに興味のない人の時間を買う

- Buy the time of people who are not interested in that content.

■コンテンツに興味のない人にも、上手く行けば「共感」をしてもらえる

- Hopefully "empathize" with people who are not interested in the content.

■ファンディングの金額の総額を公開することで、その映画に対する純粋な評価(×広告規模、×マーケティング戦略、×個人の嗜好)に影響されにくい、映画の評価を"数値"で得られる。

- By disclosing the total amount of funding, we can get a "numerical" evaluation of the film, which is less influenced by the pure evaluation of the film (x advertising scale, x marketing strategy, x personal taste).

-----

と言う訳で、「劇場版 ヴァイオレット・エヴァーガーデン」であれば、1回分のコストを、そのファンドに投資(というか、リターンはないので「寄付」になりますか)しても良いと思っています。

So, if it's "Violet Evergarden the Movie", I'm willing to invest (or is it "donate", since there is no return) the cost of one time to that fund.

2021/01,江端さんの技術メモ

1.前書き
TILE38のクライアントプログラムのサンプルを見たくて、色々探していたら、「TILE38紹介」を紹介するという、非常に良いページを見つけました。
私がプログラムを良く忘れるので、このページのプログラムをそのままコピペさせて頂いて、私の備忘録とさせて頂きます(私の環境では、コメントアウト等がちょっと違ったようです)

2. 前提
Tile38のサーバを立ち上げておきます。Dockerを使って立ち上げておくと簡単です。dockerを使わない方法は、https://github.com/tidwall/tile38 に記載があります。

docker pull tile38/tile38
docker run -p 9851:9851 tile38/tile38

3. サンプルプログラム

(1つ目)

package main

import (
        //"encoding/json"
        "fmt"
        "log"

        //"reflect"

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

func main() {
        // db connect
        c, err := redis.Dial("tcp", ":9851")
        if err != nil {
                log.Fatalf("Could not connect: %v\n", err)
        }
        defer c.Close()

        // SET location
        ret, err := c.Do("SET", "location", "me", "POINT", 35.6581, 139.6975)
        if err != nil {
                log.Fatalf("Could not SET: %v\n", err)
        }
        fmt.Printf("SET ret:%s\n", ret)

        // GET location
        ret, err = c.Do("GET", "location", "me")
        if err != nil {
                log.Fatalf("Could not GET: %v\n", err)
        }
        fmt.Printf("GET ret:%s\n", ret)
}

(2つめ)

package main

import (
	"encoding/json"
	"fmt"
	"log"

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

type GeoJsonMember struct {
	Type           string          `json:"type"`
	CoordinatesRaw json.RawMessage `json:"coordinates,omitempty"`
	CoordinatesObj interface{}     `json:"-"`
}

type Point [2]float64

type LineString []Point

type Polygon []LineString

func (member *GeoJsonMember) String() string {
	return fmt.Sprintf("%s %v", member.Type, member.CoordinatesObj)
}

func (member *GeoJsonMember) setCoordinates() error {
	var coordinates interface{}
	switch member.Type {
	case "Point":
		coordinates = new(Point)
	case "LineString":
		coordinates = new(LineString)
	case "Polygon":
		coordinates = new(Polygon)
	default:
		return fmt.Errorf("Unknown type: %v", member.Type)
	}
	err := json.Unmarshal(member.CoordinatesRaw, &coordinates)
	if err != nil {
		return fmt.Errorf("json.Unmarshal error: %v", err)
	}
	member.CoordinatesObj = coordinates
	return nil
}

func unmarshalMultiResults(shapes []byte) ([]*GeoJsonMember, error) {
	var members []*GeoJsonMember
	err := json.Unmarshal(shapes, &members)
	if err != nil {
		return nil, fmt.Errorf("Unmarshal error: %v", err)
	}

	for i, member := range members {
		err := member.setCoordinates()
		if err != nil {
			return nil, fmt.Errorf("member[%v]:type:%v coordinates:%v err:%v\n", i, member.Type, member.CoordinatesRaw, err)
		}
	}
	return members, nil
}

func unmarshalSingleResult(shapes []byte) (*GeoJsonMember, error) {
	var member GeoJsonMember
	err := json.Unmarshal(shapes, &member)
	if err != nil {
		return nil, fmt.Errorf("Unmarshal error: %v", err)
	}

	err = member.setCoordinates()
	if err != nil {
		return nil, fmt.Errorf("type:%v coordinates:%v err:%v\n", member.Type, member.CoordinatesRaw, err)
	}
	return &member, nil
}

func main() {
	// db connect
	c, err := redis.Dial("tcp", ":9851")
	if err != nil {
		log.Fatalf("Could not connect: %v\n", err)
	}
	defer c.Close()

	// SET fleet
	for _, data := range [][]interface{}{
		{"fleet", "id1", "FIELD", "start", "123456", "FIELD", "end", "789012", "POINT", 35.6581, 139.6975},
		{"fleet", "id2", "OBJECT", `{"type":"Point","coordinates":[139.6975,35.6581]}`},
		{"fleet", "id3", "OBJECT", `{"type":"LineString","coordinates":[[139.6975,35.6581],[1,1],[2,2]]}`},
		{"fleet", "id4", "POINT", 35.6581, 139.6975},
	} {
		ret, err := c.Do("SET", data...)
		if err != nil {
			log.Fatalf("Could not SET: %v\n", err)
		}
		fmt.Printf("SET ret:%#s\n", ret)
	}

	// SCAN fleet
	results, err := redis.Values(c.Do("SCAN", "fleet"))
	if err != nil {
		log.Fatalf("Could not SCAN: %v\n", err)
	}

	var cursor int
	var members []interface{}
	_, err = redis.Scan(results, &cursor, &members)
	if err != nil {
		fmt.Printf("scan result error: %v", err)
		return
	}

	for len(members) > 0 {
		// pick up one record from results as []interface{}
		var object []interface{}
		members, err = redis.Scan(members, &object)
		if err != nil {
			fmt.Printf("scan record error: %v", err)
			return
		}
		// scan columns from one record -> [id,json],fields
		var id []byte
		var json []byte
		others, err := redis.Scan(object, &id, &json)
		if err != nil {
			fmt.Printf("scan columns error: %v", err)
			return
		}

		// unmarshal geojson string to struct
		gjm, err := unmarshalSingleResult(json)
		if err != nil {
			fmt.Printf("unmarshal json error: %v", err)
			return
		}
		fmt.Printf("id:%s  json:%s  others:%s\n", id, gjm, others)
	}
}

4. PruneMobileと組み合わせてみる
ランダムウォークさせている歩行者が、一定のエリアに入った時に、メッセージを送付する。

XXXXXXXXXXXXXXXXXXXXXXXXXXX

XXXXXXXXXXXXXXXXXXXXXXXXXXX

XXXXXXXXXXXXXXXXXXXXXXXXXXX

XXXXXXXXXXXXXXXXXXXXXXXXXXX

XXXXXXXXXXXXXXXXXXXXXXXXXXX

 

 

2021/01,江端さんの技術メモ

  1. 参考文献
    https://r9y9.github.io/blog/2014/03/22/cgo-tips/
    https://hawksnowlog.blogspot.com/2018/12/getting-started-with-cgo.html
  2. 取り敢えず、Goのプログラムの中からCの関数を使う方法
    // go run main.go
    
    package main
    
    /*
    #include <stdio.h>
    #include <stdlib.h>
    
    void myprint(char* s) {
    	printf("%s\n", s);
    }
    */
    import "C"
    
    import "unsafe"
    
    func main() {
    	cs := C.CString("Hello from stdio\n")
    	C.myprint(cs)
    	C.free(unsafe.Pointer(cs))
    }
    
    // output
    // Hello from stdio

    とか

    package main
    
    /*
    #include <math.h>
    double MyPow(double x, double y) {
      double ret = pow(x, y);
      return ret;
    }
    */
    import "C"
    import "fmt"
    
    func main() {
    	ret := C.MyPow(10, 2)
    	fmt.Println(ret)
    }
  3. 結構面倒くさい決まりごと
    (1)import "C" の前には空行を入れない

    // #include <stdio.h>
    // #include <errno.h>
    import "C"

    (2)C / C++ のコンパイラに渡すオプション(flag)を記述する

    // #cgo CFLAGS: -I/usr/local/lib
    import C