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

https://note.com/nahito/n/nded6e4dd7382

購入物は、「2020年08月07日 17時37分 のメール本体」 の中に入っている

============ 以下、自分で試してみたこと =================

(Step1) github.comからリポジトリ(go_echo)を作る

(Step2) ローカルのディレクトリ(どこでもいいが、例えば、~/go_echoなら、そこ)にcdする

(準備)
>git config --global user.name
でユーザ名を確認。違ったユーザ名なら、
>git config --global user.name "正しいユーザ名"
>git config --global user.email "正しいメールアドレス"
で修正。

(masterに放り込む)
>git init // gitのディレクトリ
>git add README.md // REAME.mdに好きなことを書いておく(省略してもよい)
>git add *// 全部をローカルに保存
>git commit -m "first commit" // メッセージを付けて(ローカルに)コミットする
>git remote add origin https://github.com/TomoichiEbata/XXXXXX.git // リモートのリポジトリとリンクする
>git push → これでアップロードできる 
>git push --set-upstream origin master

で、今、

Username for 'https://github.com': TomoichiEbata
Password for 'https://TomoichiEbata@github.com': ebata_no_password
remote: Support for password authentication was removed on August 13, 2021. Please use a personal access token instead.
remote: Please see https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/ for more information.
fatal: Authentication failed for 'https://github.com/username/repo.git/'

となってしまった。

で、これに対して、【Git】2021年8月13日からGitでリモートにアクセスができなくなった。
を参考にしてセッテイングしました。

repoと、admin:repo_hookとdelete_repoにチェックを入れる

(ちなみにTokenの文字列はデタラメです)

とした上で、

C:\Users\ebata\money>git push --set-upstream origin master
Username for 'https://github.com':TomoichiEbata
Password for 'https://TomoichiEbata@github.com':(上記のTokenの文字列)
Enumerating objects: 30, done.
Counting objects: 100% (30/30), done.
Delta compression using up to 8 threads
Compressing objects: 100% (30/30), done.
Writing objects: 100% (30/30), 218.21 KiB | 5.20 MiB/s, done.
Total 30 (delta 4), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (4/4), done.
remote:
remote: Create a pull request for 'master' on GitHub by visiting:
remote: https://github.com/TomoichiEbata/money/pull/new/master
remote:
To https://github.com/TomoichiEbata/money.git
* [new branch] master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.

で、無事ログインできました。

 

(test_branchに放り込む)
>git branch test_branch // test_brachを作る
>git branch // ブランチを確認する
*master
test_branch

てな表示が出てくる。
>git checkout test_branch // これで"test_branch"の方に移動する
(ここでgoファイルを色々変更して、test_branchへの格納をする)
>git add *.go // goファイルをローカルに保存
>git commit -m "ブランチテスト" // テストブランチのコメント
>git push origin test_branch // test_branchの方に格納される

(mergeをしてみる)
>git checkout master // masterに移動
>git merge test_branch // test_branchの内容をmasterにマージ
>git push // アップロードする
(github.comの方で色々見ることができる)

(Pull Request(プルリク)をしてみる)
プルリクとは、masterブランチと自分のブランチの差分を確認し、変なコードが混ざってないかなどをレビューする機能です。
>git branch test2_branch // test2_branchを作る
>git checkout test2_branch // test2_branchに移る
>git add *.go // goファイルをローカルに保存
>git commit -m "ブランチテスト2" // テストブランチ2のコメント
>git push origin test2_branch // test2_branchの方に格納される
で、アップロード(push)できたら、githubの画面を見る

なんか聞かれますが、めげずに「Confirm merge」ボタンをおします。これでMasterにマージされます。

(変更をPull(ダウンロード)する)
>git checkout master
>git pull​
すると、masterのコードが、ローカルにダウンロードされる。

(総括)
つまりローカルには、基本のファイルしかないのに、githubの中に、とっちらかったファイルが格納されていて、必要な時に必要なバージョンに戻れる、ということらしです。

 

 

 

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

  • 概要
    • Webシステムを外部から利用するためのプログラムの呼び出し規約(API)
    • リソースの操作はHTTPメソッドによって指定(取得ならGETメソッド、書き込みならPOSTメソッド)される
    • 結果はXMLやHTML、JSONなどで返される
    • 処理結果はHTTPステータスコードで通知する
  • RESTの基本仕様
    • セッション管理を行わない
    • 情報を操作する命令の体系が予め定義(HTTPのGETやPOSTメソッドなどで)されている
    • 汎用的な構文で識別される(URLやURIなど)
    • 情報の内部に、別の情報を含めることができる
    • リソースに対してURLが対応づけられる
    • 「GET」なら取得、「POST」なら作成、「PUT」なら更新、「DELETE」なら削除のように処理する
  • ここから先は、Golangの開発プロセスになる
    • go get -u github.com/gorilla/mux を行う

golangでシンプルなRESTful APIを作ってみよう!を、そのまま書き下してトレースで動きを追ってみました。

今回から、emacs + gdb を断念して、Visual Studio Code を使ってみました。うん、死ぬほど便利。

//C:\Users\ebata\go_rest\restful\main.go
 
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strconv"

	"github.com/gorilla/mux"
)

// Item representation
type Item struct {
	Title       string `json:"title"`
	Description string `json:"description"`
}

// Global, static list of items
var itemList = []Item{
	Item{Title: "Item A", Description: "The first item"},
	Item{Title: "Item B", Description: "The second item"},
	Item{Title: "Item C", Description: "The third item"},
}

// Controller for the / route (home)
func homePage(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "This is the home page. Welcome!")
}

// Contoller for the /items route
func returnAllItems(w http.ResponseWriter, r *http.Request) {
	respondWithJson(w, http.StatusOK, itemList)
}

// Controller for the /items/{id} route
func returnSingleItem(w http.ResponseWriter, r *http.Request) {
	// Get query parameters using Mux
	vars := mux.Vars(r)

	// Convert {id} parameter from string to int
	key, err := strconv.Atoi(vars["id"])

	// If {id} parameter is not valid in
	if err != nil {
		respondWithError(w, http.StatusBadRequest, "Invalid reqest payload")
		return
	}

	// If item with ID of {id} does not exist
	if key >= len(itemList) {
		respondWithError(w, http.StatusNotFound, "Item does not exist")
		return
	}

	respondWithJson(w, http.StatusOK, itemList[key])
}

func respondWithError(w http.ResponseWriter, code int, msg string) {
	respondWithJson(w, code, map[string]string{"error": msg})
}

func respondWithJson(w http.ResponseWriter, code int, payload interface{}) {
	response, _ := json.Marshal(payload)
	w.Header().Set("Content-type", "application/json")
	w.WriteHeader(code)
	w.Write(response)
}

func handleRequests() {
	myRouter := mux.NewRouter().StrictSlash(true)
	myRouter.HandleFunc("/", homePage)
	myRouter.HandleFunc("/items", returnAllItems)
	myRouter.HandleFunc("/items/{id}", returnSingleItem)
	log.Fatal(http.ListenAndServe(":8000", myRouter))
}

func main() {
	handleRequests()
}

http://localhost:8000/ → ホームページ、テキスト("This is the home page. Welcome!")を見せる

http://localhost:8000/items → "[{"title":"Item A","description":"The first item"},{"title":"Item B","description":"The second item"},{"title":"Item C","description":"The third item"}]"

http://localhost:8000/items/1 → {"title":"Item B","description":"The second item"}

なるほど、こんな感じで使うのね。

ーーーーー

jsonの使い方についても、Go言語でJSONを扱う を写経させて頂いた。

vro.json

[
    {"id":1, "name":"akane","birthday":"08-16","vivid_info":{"color":"red","weapon":"Rang"}},
    {"id":2, "name":"aoi","birthday":"06-17","vivid_info":{"color":"blue","weapon":"Impact"}},
    {"id":3, "name":"wakaba","birthday":"05-22","vivid_info":{"color":"green","weapon":"Blade"}},
    {"id":4, "name":"himawari","birthday":"07-23","vivid_info":{"color":"yellow","weapon":"Collider"}}, 
    {"id":0, "name":"rei"}    
]

vro.go

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
)

/** JSONデコード用の構造体定義 */

type Person struct {
	Id       int      `json:"id"`
	Name     string   `json:"name"`
	Birthday string   `json:"birthday"`
	Vivid    struct { // 構造体の中にネストさせて構造体を定義
		Color  string `json:color`
		Weapon string `json:weapon`
	} `json:"vivid_info"`
}

func main() {
	// JSONファイル読み込み
	bytes, err := ioutil.ReadFile("vro.json")
	if err != nil {
		log.Fatal(err)
	}
	// JSONデコード
	var persons []Person
	if err := json.Unmarshal(bytes, &persons); err != nil {
		log.Fatal(err)
	}
	// デコードしたデータを表示
	for _, p := range persons {
		fmt.Printf("%d : %s : (%s) [%s]\n", p.Id, p.Name, p.Vivid.Color, p.Birthday)
	}

	// JSONデコード
	var decode_data interface{}
	if err := json.Unmarshal(bytes, &decode_data); err != nil {
		log.Fatal(err)
	}
	// 表示
	for _, data := range decode_data.([]interface{}) {
		var d = data.(map[string]interface{})
		fmt.Printf("%d : %s\n", int(d["id"].(float64)), d["name"])
	}
}

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

  1. まずは、MSYS2をメンテナンス(2年近く放置していたから)
$ pacman -Syu

を、ターミナルを何度も立ち直し続けてパッケージの更新を繰返す。

$ pacman -S base-devel
$ pacman -S msys2-devel
$ pacman -S mingw-w64-x86_64-toolchain
$ pacman -S mingw-w64-x86_64-gnutls
$ pacman -S mingw-w64-x86_64-ruby
$ pacman -S nano      #(簡易エディター)
$ pacman -S make      #(make をインストール ※重要※)
$ pacman -S openssh   #(openssh をインストール)
$ pacman -S git       #(Git をインストール)
$ pacman -S ruby      #(Ruby をインストール)
$ pacman -S ruby-docs #(Rubyドキュメント をインストール)
$ pacman -S p7zip     #(7z をインストール)
$ pacman -S mingw-w64-x86_64-ag  #(ag 高速検索コマンドをインストール)

2. パッケージのインストールとアンインストール

sudo pacman -S [パッケージ名]
sudo pacman -R [パッケージ名]

3. Windows10の環境をMSYS2に引きつぐ方法

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



go func() { defer close(done) for { _, message, err := c.ReadMessage() if err != nil { log.Println("read:", err) return } log.Printf("recv: %s", message) } }() ticker := time.NewTicker(time.Second) defer ticker.Stop() for { select { case <-done: return case t := <-ticker.C: err := c.WriteMessage(websocket.TextMessage, []byte(t.String())) if err != nil {

go func()で、defer close(done)が効いてくるまで、 case <-done:はロックされて、デッドロックになるじゃないか? と、ずっと考えて訳が分からなくなってきたところで、Go言語でチャネルとselect というページに、

チャネルに値が入っていない場合、受信はブロックする。ブロックせずに処理を行いたい場合は select を使う。

そんなSwitchの使いかた、あるかーーーー! と、叫びそうになりました(私の2時間を返せ)

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

https://github.com/gorilla/websocket/tree/master/examples/echo

この"server.go"は、client.goからの通信だけではなく、ブラウザの画面も提供します(スゴい!)。

というか、Goプログラムの中に、html書けるなんて知らんかった。

 
// server.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.

//go:build ignore
// +build ignore

package main

import (
	"flag"
	"html/template"
	"log"
	"net/http"

	"github.com/gorilla/websocket"
)

var addr = flag.String("addr", "localhost:8080", "http service address")

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

func echo(w http.ResponseWriter, r *http.Request) {
	c, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Print("upgrade:", err)
		return
	}
	defer c.Close()
	for {
		mt, message, err := c.ReadMessage()
		if err != nil {
			log.Println("read:", err)
			break
		}
		log.Printf("recv: %s", message)
		err = c.WriteMessage(mt, message)
		if err != nil {
			log.Println("write:", err)
			break
		}
	}
}

func home(w http.ResponseWriter, r *http.Request) {
	homeTemplate.Execute(w, "ws://"+r.Host+"/echo")
}

func main() {
	flag.Parse()
	log.SetFlags(0)
	http.HandleFunc("/echo", echo)
	http.HandleFunc("/", home)
	log.Fatal(http.ListenAndServe(*addr, nil))
}

var homeTemplate = template.Must(template.New("").Parse(`
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>  
window.addEventListener("load", function(evt) {

    var output = document.getElementById("output");
    var input = document.getElementById("input");
    var ws;

    var print = function(message) {
        var d = document.createElement("div");
        d.textContent = message;
        output.appendChild(d);
        output.scroll(0, output.scrollHeight);
    };

    document.getElementById("open").onclick = function(evt) {
        if (ws) {
            return false;
        }
        ws = new WebSocket("{{.}}");
        ws.onopen = function(evt) {
            print("OPEN");
        }
        ws.onclose = function(evt) {
            print("CLOSE");
            ws = null;
        }
        ws.onmessage = function(evt) {
            print("RESPONSE: " + evt.data);
        }
        ws.onerror = function(evt) {
            print("ERROR: " + evt.data);
        }
        return false;
    };

    document.getElementById("send").onclick = function(evt) {
        if (!ws) {
            return false;
        }
        print("SEND: " + input.value);
        ws.send(input.value);
        return false;
    };

    document.getElementById("close").onclick = function(evt) {
        if (!ws) {
            return false;
        }
        ws.close();
        return false;
    };

});
</script>
</head>
<body>
<table>
<tr><td valign="top" width="50%">
<p>Click "Open" to create a connection to the server, 
"Send" to send a message to the server and "Close" to close the connection. 
You can change the message and send multiple times.
<p>
<form>
<button id="open">Open</button>
<button id="close">Close</button>
<p><input id="input" type="text" value="Hello world!">
<button id="send">Send</button>
</form>
</td><td valign="top" width="50%">
<div id="output" style="max-height: 70vh;overflow-y: scroll;"></div>
</td></tr></table>
</body>
</html>
`))
// client.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.

//go:build ignore
// +build ignore

package main

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

	"github.com/gorilla/websocket"
)

var addr = flag.String("addr", "localhost:8080", "http service address")

func main() {
	flag.Parse()
	log.SetFlags(0)

	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt)

	u := url.URL{Scheme: "ws", Host: *addr, Path: "/echo"}
	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()

	done := make(chan struct{})

	go func() {
		defer close(done)
		for {
			_, message, err := c.ReadMessage()
			if err != nil {
				log.Println("read:", err)
				return
			}
			log.Printf("recv: %s", message)
		}
	}()

	ticker := time.NewTicker(time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-done:
			return
		case t := <-ticker.C:
			err := c.WriteMessage(websocket.TextMessage, []byte(t.String()))
			if err != nil {
				log.Println("write:", err)
				return
			}
		case <-interrupt:
			log.Println("interrupt")

			// Cleanly close the connection by sending a close message and then
			// waiting (with timeout) for the server to close the connection.
			err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
			if err != nil {
				log.Println("write close:", err)
				return
			}
			select {
			case <-done:
			case <-time.After(time.Second):
			}
			return
		}
	}
}

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

「特許明細書のロジック」の説明の仕方

「特許明細書のロジック」の説明の仕方

2010/09/17

1. 背景と目的

(1)後僚より、『知財担当者から、「特許明細書作成のロジックを説明しろ」と、言われたけど、なんのことか分からない』と相談された。

(2)そこで、江端が独断と偏見に基いて確立した「特許明細書のロジック」を開示する。

(3)なお、本内容は、知財担当者(弁理士を含む)にも開示したが、少なくともクレームは受けなかった(ように思う)。

従って、内容的には大きく外れてはいないのだろう、と考えている。

2. 知財担当者からの要請

知財担当者殿より、『「特許明細書のロジック」を説明する場合には、以下のように説明して欲しい』との要請を受けている。

====================================================================== 
先ほど、「背景技術→背景技術の問題点→本発明」と書きましたが、
詳細には、下記の点についてご説明頂きたくお願い致します。

(Step.1)発明のバックグラウンドとなる分野の説明
   	↓
(Step.2)その分野における一般的な課題の説明
    	↓
(Step.3)公知例がどのように上記課題を解決するかの説明
    	↓
(Step.4)その公知例でも解決できない課題の説明
    	↓
(Step.5)それをどう解決するかの説明(*本発明のロジック)

*本発明について、代表となる図を記載して頂けると助かります。
====================================================================== 

3. 江端の付帯説明

(面倒なので、以下メールより抜粋)

知財担当者殿のフローチャートの内容は完璧なので、そこに、私が具体例を書きます。

私はこういう風に書いてきて、発明検討会を何十回も突破して、(分割と共同を含めて)100本以上の明細書に関わってきたのですから、

先ずは、黙って、私を信じろ

(1)発明のバックグラウンドとなる分野の説明

 
  (ポイント:ここは「技術」を書くな)
 
   ○有線でやっていたメータリングを無線でやろうとする試みはあった。
   ○が、「メータおばさん」のコストの方が圧倒的に安かった。
   ○近年、無線のリソースが滅茶苦茶安くなってきた。
   ○「メータおばさん」の産業構造が崩れる可能性がでてきた。
   ○アドホックに関する技術も、かなり溜ってきた。
   ○実験ネットワークで、華々しい報告もある。
   ○太陽光発電とか、未知のシステム構成要素が入ってきている。

(2)その分野における一般的な課題の説明

 
   (ポイント:「技術」を書いても良いが、基本的には「金」「不安」で良い)

   ○事業的困難性
        インフラコストが高い、設置面倒、メンテ面倒、保守コスト試算困難、
        事業主体が不明瞭、金主が不明、ビジネスモデルが作れん

   ○技術的困難性
        無線に対する信頼性がない(本当にない)。実績がない。

   ○失敗時のインパクト
       課金不公平→暴動→政権倒れる→革命(というのは冗談だが)              
       深刻な社会不安、インフラに対する信頼性の下落

(3)公知例がどのように上記課題を解決するかの説明

 
   (ポイント:他人の文献公知発明を褒め称える)

    ○A社の特許文献1は、アドホックを自由に構築できる。
      上記の技術的困難性を見事に解決できる。素晴しい(と褒め称える)。

    ○B社の特許文献2は、無線をこんなに高信頼にして、社会インフラレベル
      にもっていける。
      上記の失敗時のインパクトを見事に回避できる。
      実に素晴しい(と褒め称える)。

    ○C社の非特許文献1は、これらを低コストで製品化している。誠に素晴
      しい(と褒めちぎる)
      上記の事業的困難性を解決できるではないか。
      涙が出そうな程、見事である(と褒め称える)。

【特許文献1】特開2007-278XXX号公報
【特許文献2】特開2002-132XXX号公報
【非特許文献1】「XXXXX」、Ebata Inc..[online][平成20年4月7日検索]、
                インターネット

(4)その公知例でも解決できない課題の説明

 
   (ポイント:褒め称えた発明を、掌を返して、鬼のように非難する)

    ○しかし、よくよく見るとA社の特許文献1は、×××はできないし、△△
      △はできない。カスな発明である(と、罵しる)

    ○また、B社の特許文献2は、★★★★★はできないし、■■■■■はでき
      ない。こんなものが現実世界で使える訳がない(と、嘲笑う)

    ○それに、C社の非特許文献1は、安いだけで、絶対必要となる○○○と
      いう機能がなく、お話になりゃしない(と、コケにする)

(5)それをどう解決するかの説明(*本発明のロジック)

 
   (ポイント:自分の発明を絶賛する(弱点については黙っている))

   ○ {俺の/あたしの}発明は、こういう内容だ(*本発明のロジック)。
      (ここで技術の話が始めて登場する)

   ○A社の特許文献1の問題点である、×××を解決し、△△△を可能とする。
      この発明は完璧だ(と、自己陶酔する)

   ○またB社の特許文献2の弱点である、★★★★★もできるし、■■■■■
     もできる。この発明は凄すぎる(と、自画自賛する)

   ○加えて、C社の非特許文献1が具備していない機能を、{俺の/あたしの}
     発明は持っていて、産業上の利用性も完璧!(と、誇大妄想する)

   ○以下、その理屈をお前達に、説明してやるから、実施例を見ろ!!!
     (以下実施例に続く)
とりあえず、こんな風に乱暴に理解して下さい。 ロジックとは、ようするに「物語」です。

(6)その他

江端が発明を評価する場合の評価方法は3つです。

(1)コスト(製造、メンテ、人材)が 1/10になる。

(2)性能(速度、メモリ、ハードディスク等)が10倍になる。

(3)上記(1)(2)に該当しなくても、(こじつけでも)「億円」の単位で儲かる。

これを、私は『特許発明 10分の1、10倍の法則』と名づけています。

『5%向上』程度なら出願やめとけ、と言っています。学生の研究ではないのだから。

また、ソフトウェアのアルゴリズムで、到底外部から発見できないようなものならやめとけ、とも。

書くだけ無駄です。侵害を立証できませんから。

# 山程書いてきた私が言っているのだから間違いない。

では、頑張って下さい。

以上

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

$ pacman -Su
エラー: mingw32: キー "4A6129F4E4B84AE46ED7F635628F528CF3053E04" は不明です
エラー: キー "4A6129F4E4B84AE46ED7F635628F528CF3053E04" をリモートで検索できませんでした
エラー: mingw64: キー "4A6129F4E4B84AE46ED7F635628F528CF3053E04" は不明です
エラー: キー "4A6129F4E4B84AE46ED7F635628F528CF3053E04" をリモートで検索できませんでした
エラー: msys: キー "4A6129F4E4B84AE46ED7F635628F528CF3053E04" は不明です
エラー: キー "4A6129F4E4B84AE46ED7F635628F528CF3053E04" をリモートで検索できませんでした
エラー: データベース 'mingw32' は無効です (無効または破損したデータベース (PGP 鍵))
エラー: データベース 'mingw64' は無効です (無効または破損したデータベース (PGP 鍵))
エラー: データベース 'msys' は無効です (無効または破損したデータベース (PGP 鍵))

てな感じのことが続き、

$pacman -S tree // treeのインストール

すら、できない有様。

で、1時間くらい回遊し続けて、この記事「MSYS2でPGP鍵が不明とか」の内容を試してみました。

$ wget http://repo.msys2.org/msys/x86_64/msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz
$ wget http://repo.msys2.org/msys/x86_64/msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz.sig
$ pacman-key --verify msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz{.sig,}
$ pacman -U --config <(echo) msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz
$ pacman -U msys2-keyring-r21.b39fb11-1-any.pkg.tar.xz

インストールするか? の問いには、"Y(es)"を連打していました。

全く理由は分かりませんが、PGP鍵の交換はできたようで、"tree"のインストールできました。