updating tools
This commit is contained in:
parent
14f29f88d3
commit
ec18e60869
|
@ -0,0 +1,45 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"git.wntrmute.dev/kyle/goutils/die"
|
||||||
|
"git.wntrmute.dev/kyle/gridsq/ft8"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
defaultDir := ft8.GetDefaultDirectory()
|
||||||
|
defaultLog := filepath.Join(defaultDir, "ALL.TXT")
|
||||||
|
|
||||||
|
var logFile string
|
||||||
|
flag.StringVar(&logFile, "f", defaultLog, "path to logfile")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if flag.NArg() == 0 {
|
||||||
|
die.With("No callsign specified!")
|
||||||
|
}
|
||||||
|
|
||||||
|
records, err := ft8.ProcessFile(logFile)
|
||||||
|
die.If(err)
|
||||||
|
|
||||||
|
grids := map[string]bool{}
|
||||||
|
who := flag.Arg(0)
|
||||||
|
fmt.Println("find grid for ", who)
|
||||||
|
|
||||||
|
for _, rec := range records {
|
||||||
|
if !rec.HasGrid() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if rec.De != who {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if grids[rec.Grid] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
grids[rec.Grid] = true
|
||||||
|
fmt.Printf("%s: %s\n", rec.De, rec.Grid)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,186 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.wntrmute.dev/kyle/goutils/die"
|
||||||
|
"github.com/klaus-tockloth/coco"
|
||||||
|
"github.com/logocomune/maidenhead"
|
||||||
|
geo "gopkg.in/billups/golang-geo.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var qths = map[int]string{
|
||||||
|
4: "CM97",
|
||||||
|
6: "CM97cq",
|
||||||
|
8: "CM97cq53",
|
||||||
|
10: "CM97cq53CI",
|
||||||
|
}
|
||||||
|
|
||||||
|
var mgrsAccuracyToMaidenheadDigits = map[int]int{
|
||||||
|
1: 10,
|
||||||
|
10: 10,
|
||||||
|
100: 10,
|
||||||
|
1000: 8,
|
||||||
|
10000: 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
var kmToMile = 0.621371
|
||||||
|
|
||||||
|
func cToP(c maidenhead.Coordinate) *geo.Point {
|
||||||
|
return geo.NewPoint(c.Lat, c.Lng)
|
||||||
|
}
|
||||||
|
|
||||||
|
func distBearing(qth, qsl string) (err error) {
|
||||||
|
var cqth, cqsl maidenhead.Coordinate
|
||||||
|
cqth.Lat, cqth.Lng, err = maidenhead.GridCenter(qth)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cqsl.Lat, cqsl.Lng, err = maidenhead.GridCenter(qsl)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pqth := cToP(cqth)
|
||||||
|
pqsl := cToP(cqsl)
|
||||||
|
dist := pqth.GreatCircleDistance(pqsl)
|
||||||
|
bearing := pqth.BearingTo(pqsl)
|
||||||
|
fmt.Printf("%s => %s: distance %0.2f miles, bearing %0.1f°\n",
|
||||||
|
qth, qsl, dist*kmToMile, bearing)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var utmZoneRegexp = regexp.MustCompile(`^(\d+)(\w+)$`)
|
||||||
|
var utmNorthingRegexp = regexp.MustCompile(`^(\d+)\w*[nsNS]$`)
|
||||||
|
var utmEastingRegexp = regexp.MustCompile(`^(\d+)\w+[ewEW]$`)
|
||||||
|
var errInvalidUTM = errors.New("invalid UTM coordinate")
|
||||||
|
|
||||||
|
func stringToUTM(s string) coco.UTM {
|
||||||
|
utm := coco.UTM{
|
||||||
|
ZoneNumber: 0,
|
||||||
|
ZoneLetter: 0,
|
||||||
|
Easting: 0,
|
||||||
|
Northing: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := strings.Fields(s)
|
||||||
|
if len(fields) != 3 {
|
||||||
|
die.If(errInvalidUTM)
|
||||||
|
}
|
||||||
|
|
||||||
|
zone := utmZoneRegexp.FindStringSubmatch(fields[0])
|
||||||
|
if len(zone) != 3 {
|
||||||
|
fmt.Println(zone)
|
||||||
|
die.If(errInvalidUTM)
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
utm.ZoneNumber, err = strconv.Atoi(zone[1])
|
||||||
|
if err != nil {
|
||||||
|
die.If(errors.Join(err, errInvalidUTM))
|
||||||
|
}
|
||||||
|
utm.ZoneLetter = zone[2][0]
|
||||||
|
|
||||||
|
easting := utmEastingRegexp.FindStringSubmatch(fields[1])
|
||||||
|
if len(easting) == 0 {
|
||||||
|
die.If(errInvalidUTM)
|
||||||
|
}
|
||||||
|
utm.Easting, err = strconv.ParseFloat(easting[1], 64)
|
||||||
|
if err != nil {
|
||||||
|
die.If(errors.Join(err, errInvalidUTM))
|
||||||
|
}
|
||||||
|
|
||||||
|
northing := utmNorthingRegexp.FindStringSubmatch(fields[2])
|
||||||
|
if len(northing) == 0 {
|
||||||
|
die.If(errInvalidUTM)
|
||||||
|
}
|
||||||
|
utm.Northing, err = strconv.ParseFloat(northing[1], 64)
|
||||||
|
if err != nil {
|
||||||
|
die.If(errors.Join(err, errInvalidUTM))
|
||||||
|
}
|
||||||
|
|
||||||
|
return utm
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var lat, lon float64
|
||||||
|
var precision int64
|
||||||
|
|
||||||
|
flag.Float64Var(&lat, "lat", 0.0, "latitude of grid")
|
||||||
|
flag.Float64Var(&lon, "lon", 0.0, "longitude of grid")
|
||||||
|
flag.Int64Var(&precision, "d", 6, "number of digits")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if flag.NArg() == 0 {
|
||||||
|
fmt.Println("nothing")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := flag.Arg(0)
|
||||||
|
switch cmd {
|
||||||
|
case "geo":
|
||||||
|
grid, err := maidenhead.Locator(lat, lon, int(precision))
|
||||||
|
die.If(err)
|
||||||
|
|
||||||
|
fmt.Printf("%0.6f %0.6f: ", lat, lon)
|
||||||
|
fmt.Println(grid)
|
||||||
|
case "qth":
|
||||||
|
grid, ok := qths[int(precision)]
|
||||||
|
if !ok {
|
||||||
|
fmt.Println(qths[6])
|
||||||
|
} else {
|
||||||
|
fmt.Println(grid)
|
||||||
|
}
|
||||||
|
case "db":
|
||||||
|
var qth, qsl string
|
||||||
|
if flag.NArg() == 2 {
|
||||||
|
qsl = flag.Arg(1)
|
||||||
|
qth = qths[len(qsl)]
|
||||||
|
} else {
|
||||||
|
qsl = flag.Arg(2)
|
||||||
|
qth = flag.Arg(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := distBearing(qth, qsl)
|
||||||
|
die.If(err)
|
||||||
|
|
||||||
|
case "mgrs":
|
||||||
|
if flag.NArg() == 0 {
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
utm := coco.MGRS(strings.Replace(flag.Arg(1), " ", "", -1))
|
||||||
|
ll, accuracy, err := utm.ToLL()
|
||||||
|
fmt.Printf("%#v\n", ll)
|
||||||
|
die.If(err)
|
||||||
|
|
||||||
|
precision, ok := mgrsAccuracyToMaidenheadDigits[accuracy]
|
||||||
|
if !ok {
|
||||||
|
precision = 4
|
||||||
|
}
|
||||||
|
grid, err := maidenhead.Locator(ll.Lat, ll.Lon, precision)
|
||||||
|
die.If(err)
|
||||||
|
fmt.Println(grid)
|
||||||
|
case "utm":
|
||||||
|
if flag.NArg() == 0 {
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
utm := stringToUTM(flag.Arg(1))
|
||||||
|
ll, err := utm.ToLL()
|
||||||
|
fmt.Printf("%#v\n", ll)
|
||||||
|
die.If(err)
|
||||||
|
|
||||||
|
grid, err := maidenhead.Locator(ll.Lat, ll.Lon, 8)
|
||||||
|
die.If(err)
|
||||||
|
fmt.Println(grid)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
type Kep struct {
|
||||||
|
Filename string
|
||||||
|
URL string
|
||||||
|
}
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Name string
|
||||||
|
Directory string
|
||||||
|
Prefix string
|
||||||
|
}
|
|
@ -0,0 +1,161 @@
|
||||||
|
package ft8
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"git.wntrmute.dev/kyle/goutils/die"
|
||||||
|
"os"
|
||||||
|
"os/user"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getHomeDirectory() string {
|
||||||
|
u, err := user.Current()
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return u.HomeDir
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDefaultDirectory() string {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "linux":
|
||||||
|
return filepath.Join(
|
||||||
|
getHomeDirectory(),
|
||||||
|
".local",
|
||||||
|
"share",
|
||||||
|
"WSJT-X",
|
||||||
|
)
|
||||||
|
case "windows":
|
||||||
|
return filepath.Join(
|
||||||
|
getHomeDirectory(),
|
||||||
|
"AppData",
|
||||||
|
"Local",
|
||||||
|
"WSJT-X",
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
die.With("Operating system '%s' isn't supported.", runtime.GOOS)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
RecordTypeCQ = iota + 1
|
||||||
|
RecordTypeCQReply
|
||||||
|
RecordTypeSignal
|
||||||
|
RecordTypeSignoff
|
||||||
|
)
|
||||||
|
|
||||||
|
// call ([\w\d/]+)
|
||||||
|
// grid (\w{2}\d{2})
|
||||||
|
var (
|
||||||
|
RegexpCQ = regexp.MustCompile(`^CQ ([\w/]+) (\w{2}\d{2})$`)
|
||||||
|
RegexpCQReply = regexp.MustCompile(`^([\w/]+) ([\w/]+) (\w{2}\d{2})$`)
|
||||||
|
RegexpRR73 = regexp.MustCompile(`^([\w\d/]+) ([\w\d/]+) RR73$`)
|
||||||
|
)
|
||||||
|
|
||||||
|
type Record struct {
|
||||||
|
Type uint8
|
||||||
|
Time time.Time
|
||||||
|
Freq float64
|
||||||
|
Tone int
|
||||||
|
Mode string
|
||||||
|
IsTX bool
|
||||||
|
De string
|
||||||
|
To string
|
||||||
|
Received int
|
||||||
|
Grid string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rec *Record) HasGrid() bool {
|
||||||
|
return rec.Grid != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseRecordHeader(line string) (rec *Record, err error) {
|
||||||
|
// 0 1 2 3 4 5 6 7
|
||||||
|
// 231215_021330 14.074 Rx FT8 -6 0.1 1713 CQ N6ACA CM97
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
rec = &Record{}
|
||||||
|
rec.Time, err = time.Parse("060102_150405", fields[0])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rec.Freq, err = strconv.ParseFloat(fields[1], 64)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if fields[2] == "Tx" {
|
||||||
|
rec.IsTX = true
|
||||||
|
}
|
||||||
|
|
||||||
|
rec.Mode = fields[3]
|
||||||
|
rec.Received, err = strconv.Atoi(fields[4])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rec.Tone, err = strconv.Atoi(fields[6])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseRecord(line string) (*Record, error) {
|
||||||
|
rec, err := ParseRecordHeader(line)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
line = strings.Join(fields[7:len(fields)], " ")
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case RegexpRR73.MatchString(line):
|
||||||
|
rec.Type = RecordTypeSignoff
|
||||||
|
match := RegexpRR73.FindStringSubmatch(line)
|
||||||
|
rec.De = match[2]
|
||||||
|
rec.To = match[1]
|
||||||
|
case RegexpCQ.MatchString(line):
|
||||||
|
rec.Type = RecordTypeCQ
|
||||||
|
match := RegexpCQ.FindStringSubmatch(line)
|
||||||
|
rec.De = match[1]
|
||||||
|
rec.Grid = match[2]
|
||||||
|
case RegexpCQReply.MatchString(line):
|
||||||
|
rec.Type = RecordTypeCQReply
|
||||||
|
match := RegexpCQReply.FindStringSubmatch(line)
|
||||||
|
rec.To = match[1]
|
||||||
|
rec.De = match[2]
|
||||||
|
rec.Grid = match[3]
|
||||||
|
}
|
||||||
|
return rec, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func ProcessFile(path string) ([]*Record, error) {
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
var records []*Record
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
rec, err := ParseRecord(scanner.Text())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
records = append(records, rec)
|
||||||
|
}
|
||||||
|
|
||||||
|
return records, nil
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package ft8
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
var (
|
||||||
|
testCQLine = `231215_021330 14.074 Rx FT8 -6 0.1 1713 CQ N6ACA CM97`
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMatchCQ(t *testing.T) {
|
||||||
|
rec, err := ParseRecord(testCQLine)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rec.Type != RecordTypeCQ {
|
||||||
|
t.Fatalf("invalid record: expected %d, have %d", RecordTypeCQ, rec.Type)
|
||||||
|
}
|
||||||
|
}
|
1
go.mod
1
go.mod
|
@ -4,6 +4,7 @@ go 1.21.3
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.wntrmute.dev/kyle/goutils v1.7.4 // indirect
|
git.wntrmute.dev/kyle/goutils v1.7.4 // indirect
|
||||||
|
github.com/klaus-tockloth/coco v0.2.0 // indirect
|
||||||
github.com/logocomune/maidenhead v1.0.1 // indirect
|
github.com/logocomune/maidenhead v1.0.1 // indirect
|
||||||
gopkg.in/billups/golang-geo.v2 v2.0.0-20170124000346-c2931833be19 // indirect
|
gopkg.in/billups/golang-geo.v2 v2.0.0-20170124000346-c2931833be19 // indirect
|
||||||
)
|
)
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -1,5 +1,7 @@
|
||||||
git.wntrmute.dev/kyle/goutils v1.7.4 h1:kbvUoxRwAEemz4jL52AUKaOipuCX8F8PGTQHS5V3lRY=
|
git.wntrmute.dev/kyle/goutils v1.7.4 h1:kbvUoxRwAEemz4jL52AUKaOipuCX8F8PGTQHS5V3lRY=
|
||||||
git.wntrmute.dev/kyle/goutils v1.7.4/go.mod h1:1PGn83Ac98KWyI6yfpCVyP1Ji61PX6lFpROxY+IoTJg=
|
git.wntrmute.dev/kyle/goutils v1.7.4/go.mod h1:1PGn83Ac98KWyI6yfpCVyP1Ji61PX6lFpROxY+IoTJg=
|
||||||
|
github.com/klaus-tockloth/coco v0.2.0 h1:k2GWaR+dbWi/d9EIgNhSqmEshpTJSoWLGoCmPd559/Y=
|
||||||
|
github.com/klaus-tockloth/coco v0.2.0/go.mod h1:ZKByCKTYUR9wceWX7RUQmL1bDc0Q2SkbVfgrNs2UyIw=
|
||||||
github.com/logocomune/maidenhead v1.0.1 h1:WnBpC/LIhc81QnwDdxEPKHwSAspMCWwsYMuM9vQMFgA=
|
github.com/logocomune/maidenhead v1.0.1 h1:WnBpC/LIhc81QnwDdxEPKHwSAspMCWwsYMuM9vQMFgA=
|
||||||
github.com/logocomune/maidenhead v1.0.1/go.mod h1:FLkUKuGyo4uKESNlXG8jgQgaTSApyR2ZZfq7m2Btmjs=
|
github.com/logocomune/maidenhead v1.0.1/go.mod h1:FLkUKuGyo4uKESNlXG8jgQgaTSApyR2ZZfq7m2Btmjs=
|
||||||
gopkg.in/billups/golang-geo.v2 v2.0.0-20170124000346-c2931833be19 h1:vu0Y9rNRRTFG70fnQ/W/CG4N629vz9uaqaY7R7fXnVo=
|
gopkg.in/billups/golang-geo.v2 v2.0.0-20170124000346-c2931833be19 h1:vu0Y9rNRRTFG70fnQ/W/CG4N629vz9uaqaY7R7fXnVo=
|
||||||
|
|
89
main.go
89
main.go
|
@ -1,89 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.wntrmute.dev/kyle/goutils/die"
|
|
||||||
"github.com/logocomune/maidenhead"
|
|
||||||
geo "gopkg.in/billups/golang-geo.v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
var qths = map[int]string{
|
|
||||||
4: "CM97",
|
|
||||||
6: "CM97cq",
|
|
||||||
8: "CM97cq53",
|
|
||||||
10: "CM97cq53CI",
|
|
||||||
}
|
|
||||||
|
|
||||||
var kmToMile = 0.621371
|
|
||||||
|
|
||||||
func cToP(c maidenhead.Coordinate) *geo.Point {
|
|
||||||
return geo.NewPoint(c.Lat, c.Lng)
|
|
||||||
}
|
|
||||||
|
|
||||||
func distBearing(qth, qsl string) (err error) {
|
|
||||||
var cqth, cqsl maidenhead.Coordinate
|
|
||||||
cqth.Lat, cqth.Lng, err = maidenhead.GridCenter(qth)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
cqsl.Lat, cqsl.Lng, err = maidenhead.GridCenter(qsl)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
pqth := cToP(cqth)
|
|
||||||
pqsl := cToP(cqsl)
|
|
||||||
dist := pqth.GreatCircleDistance(pqsl)
|
|
||||||
bearing := pqth.BearingTo(pqsl)
|
|
||||||
fmt.Printf("%s => %s: distance %0.2f miles, bearing %0.1f°\n",
|
|
||||||
qth, qsl, dist*kmToMile, bearing)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var lat, lon float64
|
|
||||||
var precision int64
|
|
||||||
|
|
||||||
flag.Float64Var(&lat, "lat", 0.0, "latitude of grid")
|
|
||||||
flag.Float64Var(&lon, "lon", 0.0, "longitude of grid")
|
|
||||||
flag.Int64Var(&precision, "d", 6, "number of digits")
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
if flag.NArg() == 0 {
|
|
||||||
fmt.Println("nothing")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := flag.Arg(0)
|
|
||||||
switch cmd {
|
|
||||||
case "geo":
|
|
||||||
grid, err := maidenhead.Locator(lat, lon, int(precision))
|
|
||||||
die.If(err)
|
|
||||||
|
|
||||||
fmt.Printf("%0.6f %0.6f: ", lat, lon)
|
|
||||||
fmt.Println(grid)
|
|
||||||
case "qth":
|
|
||||||
grid, ok := qths[int(precision)]
|
|
||||||
if !ok {
|
|
||||||
fmt.Println(qths[6])
|
|
||||||
} else {
|
|
||||||
fmt.Println(grid)
|
|
||||||
}
|
|
||||||
case "db":
|
|
||||||
var qth, qsl string
|
|
||||||
if flag.NArg() == 2 {
|
|
||||||
qsl = flag.Arg(1)
|
|
||||||
qth = qths[len(qsl)]
|
|
||||||
} else {
|
|
||||||
qsl = flag.Arg(2)
|
|
||||||
qth = flag.Arg(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
err := distBearing(qth, qsl)
|
|
||||||
die.If(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue