Compare commits

..

No commits in common. "main" and "v1.0.0" have entirely different histories.
main ... v1.0.0

9 changed files with 120 additions and 592 deletions

View File

@ -1,11 +1,10 @@
---
kind: pipeline kind: pipeline
type: kubernetes type: kubernetes
name: default name: default
steps: steps:
- name: test - name: test
image: golang:1.24 image: golang:1.18
volumes: volumes:
- name: deps - name: deps
path: /go path: /go
@ -29,8 +28,3 @@ steps:
from_secret: harbor_library_username from_secret: harbor_library_username
password: password:
from_secret: harbor_library_password from_secret: harbor_library_password
---
kind: signature
hmac: d2fe2afd7d16e5530e00f268db9e381b980cddbc1bc11287c223fb1a9a6fa894
...

2
.gitignore vendored
View File

@ -1,2 +1,2 @@
data data
/locationcode locationcode

View File

@ -1,4 +1,4 @@
FROM golang:1.24-alpine3.21 AS build FROM golang:1.18-alpine3.15 AS build
RUN apk --no-cache add git RUN apk --no-cache add git
WORKDIR /go/src/ WORKDIR /go/src/
@ -6,10 +6,9 @@ ADD . /go/src/
RUN go install -v ./... RUN go install -v ./...
FROM alpine:3.21 FROM alpine:3.15
USER root USER root
RUN apk --no-cache add ca-certificates RUN apk --no-cache add ca-certificates
RUN apk --no-cache upgrade
RUN addgroup lc && adduser -D -G lc lc RUN addgroup lc && adduser -D -G lc lc
WORKDIR / WORKDIR /

View File

@ -1,52 +1,37 @@
package main package main
import ( import (
"context"
"errors"
"flag" "flag"
"fmt" "fmt"
"log/slog" "log"
"net/http" "net/http"
"os" "os"
"os/signal"
"path" "path"
"sort"
"strconv" "strconv"
"strings" "strings"
"syscall"
"time"
"github.com/golang/geo/s2" "github.com/golang/geo/s2"
alphafoxtrot "github.com/grumpypixel/go-airport-finder" alphafoxtrot "github.com/grumpypixel/go-airport-finder"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
slogecho "github.com/samber/slog-echo"
"go.ntppool.org/common/logger"
"go.ntppool.org/common/tracing"
"go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho"
"golang.org/x/sync/errgroup"
"go.askask.com/locationcode/types"
) )
type Finder struct { type Airport struct {
f *alphafoxtrot.AirportFinder Name string
Code string
Distance float64
data *alphafoxtrot.Airport
} }
func main() { func main() {
log := logger.Setup()
dataDir := flag.String("data-dir", "./data", "Data cache directory") var dataDir = flag.String("data-dir", "./data", "Data cache directory")
flag.Parse() flag.Parse()
err := validateData(*dataDir) validateData(*dataDir)
if err != nil {
log.Error("data error", "err", err)
os.Exit(2)
}
finder := &Finder{ finder := alphafoxtrot.NewAirportFinder()
f: alphafoxtrot.NewAirportFinder(),
}
// LoadOptions come with preset filepaths // LoadOptions come with preset filepaths
options := alphafoxtrot.PresetLoadOptions(*dataDir) options := alphafoxtrot.PresetLoadOptions(*dataDir)
@ -55,95 +40,28 @@ func main() {
filter := alphafoxtrot.AirportTypeRunways filter := alphafoxtrot.AirportTypeRunways
// Load the data into memory // Load the data into memory
if err := finder.f.Load(options, filter); len(err) > 0 { if err := finder.Load(options, filter); len(err) > 0 {
log.Error("finder load error", "err", err) log.Println("errors:", err)
}
if args := flag.Args(); len(args) > 0 {
if len(args) != 4 {
fmt.Printf("[cc] [lat] [lng] [radius]\n")
os.Exit(2)
}
cc := strings.ToUpper(args[0])
latitude, err := strconv.ParseFloat(args[1], 64)
if err != nil {
fmt.Printf("could not parse %s as latitude: %s", args[1], err)
os.Exit(2)
}
longitude, err := strconv.ParseFloat(args[2], 64)
if err != nil {
fmt.Printf("could not parse %s as longitude: %s", args[2], err)
os.Exit(2)
}
radiusKM, err := strconv.ParseFloat(args[3], 64)
if err != nil {
fmt.Printf("could not parse %s as radius: %s", args[3], err)
os.Exit(2)
}
airports, err := finder.GetAirports(context.Background(), cc, radiusKM, latitude, longitude)
if err != nil {
fmt.Printf("GetAirports error: %s\n", err)
}
for _, a := range airports {
fmt.Printf("%s\t%s (%0f)\n", a.Code, a.Name, a.Distance)
}
os.Exit(0)
}
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer cancel()
tpShutdown, err := tracing.InitTracer(ctx, &tracing.TracerConfig{
ServiceName: "locationcode",
})
if err != nil {
log.Error("could not initialize tracer", "err", err)
} }
e := echo.New() e := echo.New()
e.Use(otelecho.Middleware("locationcode"))
e.Use(slogecho.NewWithConfig(log,
slogecho.Config{
WithTraceID: false, // done by logger already
DefaultLevel: slog.LevelInfo,
ClientErrorLevel: slog.LevelWarn,
ServerErrorLevel: slog.LevelError,
// WithRequestHeader: true,
Filters: []slogecho.Filter{
func(c echo.Context) bool {
return !(c.Request().URL.Path == "/" || c.Request().URL.Path == "/__healthz")
},
},
},
))
e.GET("/", func(c echo.Context) error { e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "location code service") return c.String(http.StatusOK, "location code service")
}) })
e.GET("/v1/code", func(c echo.Context) error { e.GET("/v1/code", func(c echo.Context) error {
ctx := c.Request().Context()
countryISOCode := c.QueryParam("cc") countryISOCode := c.QueryParam("cc")
countryISOCode = strings.ToUpper(countryISOCode) countryISOCode = strings.ToUpper(countryISOCode)
radiusString := c.QueryParam("radius") radiusString := c.QueryParam("radius")
var radiusKM float64 var radiusKM int
if len(radiusString) > 0 { if len(radiusString) > 0 {
radiusKM, _ = strconv.ParseFloat(radiusString, 64) radiusKM, _ = strconv.Atoi(radiusString)
} }
if radiusKM < 150 { if radiusKM < 10 {
radiusKM = 150 radiusKM = 100
} else {
radiusKM = radiusKM * 1.5
} }
latitude, longitude, err := getLatLng(c) latitude, longitude, err := getLatLng(c)
@ -151,55 +69,11 @@ func main() {
return c.String(http.StatusBadRequest, fmt.Sprintf("invalid lat or lng: %s", err)) return c.String(http.StatusBadRequest, fmt.Sprintf("invalid lat or lng: %s", err))
} }
airports, err := finder.GetAirports(ctx, countryISOCode, radiusKM, latitude, longitude)
if err != nil {
return err
}
return c.JSON(http.StatusOK, airports)
})
errg, ctx := errgroup.WithContext(ctx)
errg.Go(func() error {
return e.Start(":8520")
})
errg.Go(func() error {
<-ctx.Done()
log.InfoContext(ctx, "shutting down server")
return e.Shutdown(ctx)
})
err = errg.Wait()
if err != nil {
if !errors.Is(err, http.ErrServerClosed) {
log.ErrorContext(ctx, "server error", "err", err)
}
}
shutdownCtx, shCancel := context.WithTimeout(context.Background(), 5*time.Second)
defer shCancel()
if err := tpShutdown(shutdownCtx); err != nil {
log.ErrorContext(shutdownCtx, "failed to shutdown tracer", "err", err)
}
}
func (f *Finder) GetAirports(ctx context.Context, cc string, radiusKM, latitude, longitude float64) ([]*types.Airport, error) {
log := logger.FromContext(ctx)
log.InfoContext(ctx, fmt.Sprintf("GetAirports(%s %.2f %.4f %.4f)", cc, radiusKM, latitude, longitude))
ipLocation := s2.LatLngFromDegrees(latitude, longitude) ipLocation := s2.LatLngFromDegrees(latitude, longitude)
maxResults := 500 // some countries have a lot of airports without local codes maxResults := 100
radiusInMeters := radiusKM * 1000 radiusInMeters := float64(radiusKM) * 1000
airportsRaw := f.f.FindNearestAirportsByCountry( airportsRaw := finder.FindNearestAirportsByCountry(countryISOCode, latitude, longitude, radiusInMeters, maxResults, filter)
cc,
latitude, longitude,
radiusInMeters,
maxResults,
alphafoxtrot.AirportTypeAll, // filtered at load time
)
airports := []*alphafoxtrot.Airport{} airports := []*alphafoxtrot.Airport{}
for _, ap := range airportsRaw { for _, ap := range airportsRaw {
@ -209,32 +83,51 @@ func (f *Finder) GetAirports(ctx context.Context, cc string, radiusKM, latitude,
airports = append(airports, ap) airports = append(airports, ap)
} }
r := []*types.Airport{} llCache := map[int]s2.LatLng{}
for i, ap := range airports {
ll := s2.LatLngFromDegrees(ap.LatitudeDeg, ap.LongitudeDeg)
llCache[i] = ll
}
for _, airport := range airports { r := []*Airport{}
for i, airport := range airports {
// fmt.Printf("%d %s: %+v\n", i, airport.Name, airport) // fmt.Printf("%d %s: %+v\n", i, airport.Name, airport)
a := types.NewAirport(airport) code := strings.ToLower(airport.Country.ISOCode + airport.IATACode)
ll := s2.LatLngFromDegrees(airport.LatitudeDeg, airport.LongitudeDeg) distance := float64(ipLocation.Distance(llCache[i])) * 6371.01
a.Distance = float64(ipLocation.Distance(ll)) * 6371.01
a := &Airport{
Name: airport.Name,
Code: code,
Distance: distance,
data: airport,
}
r = append(r, a) r = append(r, a)
} }
types.SortAirports(r) sort.Slice(r, func(i, j int) bool {
if r[i].data.Type == r[j].data.Type {
return r[i].Distance < r[j].Distance
}
return airports[i].Type < airports[j].Type
})
maxReturns := 20 if len(r) > 10 {
if len(r) > maxReturns { r = r[0:10]
r = r[0:maxReturns]
} }
log.InfoContext(ctx, "got airports", "count", len(airportsRaw), "filtered", len(airports), "returning", len(r)) fmt.Printf("got %d airports, filtered to %d, returning %d\n", len(airportsRaw), len(airports), len(r))
return c.JSON(http.StatusOK, r)
})
e.Logger.Fatal(e.Start(":8000"))
return r, nil
} }
func validateData(dataDir string) error { func validateData(dataDir string) {
downloadFiles := false downloadFiles := false
for _, filename := range alphafoxtrot.OurAirportsFiles { for _, filename := range alphafoxtrot.OurAirportsFiles {
filepath := path.Join(dataDir, filename) filepath := path.Join(dataDir, filename)
@ -245,13 +138,9 @@ func validateData(dataDir string) error {
} }
if downloadFiles { if downloadFiles {
fmt.Println("Downloading CSV files from OurAirports.com...") fmt.Println("Downloading CSV files from OurAirports.com...")
err := DownloadDatabase(dataDir) alphafoxtrot.DownloadDatabase(dataDir)
if err != nil {
return err
} }
} }
return nil
}
func getLatLng(c echo.Context) (float64, float64, error) { func getLatLng(c echo.Context) (float64, float64, error) {
latitudeStr := c.QueryParam("lat") // 37.3793 latitudeStr := c.QueryParam("lat") // 37.3793

View File

@ -1,85 +0,0 @@
package locationcode
import (
"context"
"encoding/json"
"fmt"
"net"
"net/http"
"net/url"
"os"
"time"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.askask.com/locationcode/types"
)
var client http.Client
func init() {
netTransport := &http.Transport{
Dial: (&net.Dialer{
Timeout: 5 * time.Second,
}).Dial,
TLSHandshakeTimeout: 5 * time.Second,
}
client = http.Client{
Timeout: time.Second * 10,
Transport: netTransport,
}
}
func GetAirports(ctx context.Context, countryCode string, lat, lng float64, radiusKM float64) ([]*types.Airport, error) {
ctx, span := otel.Tracer("locationcode").Start(ctx, "locationcode.GetAirports")
defer span.End()
baseURL := os.Getenv("locationcode_service")
if len(baseURL) == 0 {
return nil, fmt.Errorf("locationcode_service not configured")
}
q := url.Values{}
q.Set("cc", countryCode)
if radiusKM > 0 {
q.Set("radius", fmt.Sprintf("%f", radiusKM))
}
q.Set("lat", fmt.Sprintf("%f", lat))
q.Set("lng", fmt.Sprintf("%f", lng))
reqURL, err := url.Parse(fmt.Sprintf("http://%s/v1/code?%s", baseURL, q.Encode()))
if err != nil {
span.RecordError(err)
return nil, err
}
span.SetAttributes(attribute.String("url", reqURL.String()))
req, err := http.NewRequestWithContext(ctx, "GET", reqURL.String(), nil)
if err != nil {
span.RecordError(err)
return nil, err
}
resp, err := client.Do(req)
if err != nil {
span.RecordError(err)
return nil, err
}
defer resp.Body.Close()
// io.Copy(os.Stdout, resp.Body)
// return nil, nil
dec := json.NewDecoder(resp.Body)
airports := []*types.Airport{}
err = dec.Decode(&airports)
if err != nil {
span.RecordError(err)
return nil, err
}
return airports, nil
}

View File

@ -1,55 +0,0 @@
package main
import (
"errors"
"fmt"
"path"
"time"
alphafoxtrot "github.com/grumpypixel/go-airport-finder"
"github.com/grumpypixel/go-webget"
)
// const downloadBaseURL = alphafoxtrot.OurAirportsBaseURL
// const downloadBaseURL = "https://tmp.askask.com/os/ourairports/"
// https://github.com/davidmegginson/ourairports-data
const downloadBaseURL = "https://davidmegginson.github.io/ourairports-data/"
// Download csv files from OurAirports.com
func DownloadDatabase(targetDir string) error {
files := make([]string, 0)
for _, filename := range alphafoxtrot.OurAirportsFiles {
files = append(files, downloadBaseURL+filename)
}
var errs []error
for _, url := range files {
options := webget.Options{
ProgressHandler: MyProgress{},
Timeout: time.Second * 60,
CreateTargetDir: true,
}
err := webget.DownloadToFile(url, targetDir, "", &options)
if err != nil {
errs = append(errs, err)
}
}
return errors.Join(errs...)
}
type MyProgress struct{}
func (p MyProgress) Start(sourceURL string) {
// fmt.Println()
}
func (p MyProgress) Update(sourceURL string, percentage float64, bytesRead, contentLength int64) {
if percentage > 0 {
fmt.Printf("\rDownloading %s: %v bytes [%.2f%%]", path.Base(sourceURL), bytesRead, percentage)
}
fmt.Printf("\rDownloading %s: %v bytes [done]", path.Base(sourceURL), bytesRead)
}
func (p MyProgress) Done(sourceURL string) {
fmt.Println()
}

75
go.mod
View File

@ -1,73 +1,22 @@
module go.askask.com/locationcode module go.askask.com/locationcode
go 1.24 go 1.18
require ( require (
github.com/golang/geo v0.0.0-20250411042641-97e19c1a7ce7 github.com/golang/geo v0.0.0-20210211234256-740aa86cb551
github.com/grumpypixel/go-airport-finder v0.0.0-20210902211810-793a4fb1490b github.com/grumpypixel/go-airport-finder v0.0.0-20210902211810-793a4fb1490b
github.com/grumpypixel/go-webget v0.0.1 github.com/labstack/echo/v4 v4.7.2
github.com/labstack/echo/v4 v4.13.3
github.com/samber/slog-echo v1.16.1
go.ntppool.org/common v0.3.1
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.60.0
go.opentelemetry.io/otel v1.35.0
golang.org/x/sync v0.13.0
) )
require ( require (
github.com/beorn7/perks v1.0.1 // indirect github.com/grumpypixel/go-webget v0.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/labstack/gommon v0.3.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/mattn/go-colorable v0.1.12 // indirect
github.com/go-logr/logr v1.4.2 // indirect github.com/mattn/go-isatty v0.0.14 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/labstack/gommon v0.4.2 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/prometheus/client_golang v1.22.0 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.63.0 // indirect
github.com/prometheus/procfs v0.16.0 // indirect
github.com/remychantenay/slog-otel v1.3.3 // indirect
github.com/samber/lo v1.49.1 // indirect
github.com/samber/slog-multi v1.4.0 // indirect
github.com/spf13/cobra v1.9.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect github.com/valyala/fasttemplate v1.2.1 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 // indirect
go.opentelemetry.io/contrib/bridges/otelslog v0.10.0 // indirect golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 // indirect
go.opentelemetry.io/contrib/bridges/prometheus v0.60.0 // indirect golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12 // indirect
go.opentelemetry.io/contrib/exporters/autoexport v0.60.0 // indirect golang.org/x/text v0.3.7 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.11.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.11.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.35.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 // indirect
go.opentelemetry.io/otel/exporters/prometheus v0.57.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.11.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.35.0 // indirect
go.opentelemetry.io/otel/log v0.11.0 // indirect
go.opentelemetry.io/otel/metric v1.35.0 // indirect
go.opentelemetry.io/otel/sdk v1.35.0 // indirect
go.opentelemetry.io/otel/sdk/log v0.11.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
golang.org/x/crypto v0.37.0 // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/net v0.39.0 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.org/x/text v0.24.0 // indirect
golang.org/x/time v0.11.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250409194420-de1ac958c67a // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250409194420-de1ac958c67a // indirect
google.golang.org/grpc v1.71.1 // indirect
google.golang.org/protobuf v1.36.6 // indirect
) )

175
go.sum
View File

@ -1,153 +1,44 @@
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 h1:gtexQ/VGyN+VVFRXSFiguSNcXmS6rkKT+X7FdIrTtfo=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/golang/geo v0.0.0-20250411042641-97e19c1a7ce7 h1:HNykSFq2QowNxC/zZc1IEbRuj30sMiY4aCSLb4EK/zA=
github.com/golang/geo v0.0.0-20250411042641-97e19c1a7ce7/go.mod h1:J+F9/3Ofc8ysEOY2/cNjxTMl2eB1gvPIywEHUplPgDA=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
github.com/grumpypixel/go-airport-finder v0.0.0-20210902211810-793a4fb1490b h1:CAT7j8NnDTijm+Mqc49PowzRwffiQwoNTdacBtAaPac= github.com/grumpypixel/go-airport-finder v0.0.0-20210902211810-793a4fb1490b h1:CAT7j8NnDTijm+Mqc49PowzRwffiQwoNTdacBtAaPac=
github.com/grumpypixel/go-airport-finder v0.0.0-20210902211810-793a4fb1490b/go.mod h1:VSzLdQ8TugVDF/ZqngnVa/4budj2JLbC3spdz4eKEd4= github.com/grumpypixel/go-airport-finder v0.0.0-20210902211810-793a4fb1490b/go.mod h1:VSzLdQ8TugVDF/ZqngnVa/4budj2JLbC3spdz4eKEd4=
github.com/grumpypixel/go-webget v0.0.0-20210513194017-df576311f21d h1:ZD475Db8FZRfptdzpvWiAQPRkElVrITDmg7yiTN+vk0=
github.com/grumpypixel/go-webget v0.0.0-20210513194017-df576311f21d/go.mod h1:TZ3kzdKP644McT9EqfvX6vRcnoKxAGNJVbUGfDCgbpA=
github.com/grumpypixel/go-webget v0.0.1 h1:JByEaxRKMK3ACvARJCMva1Tb+mKmZPpIDF9gcgf42OU= github.com/grumpypixel/go-webget v0.0.1 h1:JByEaxRKMK3ACvARJCMva1Tb+mKmZPpIDF9gcgf42OU=
github.com/grumpypixel/go-webget v0.0.1/go.mod h1:TZ3kzdKP644McT9EqfvX6vRcnoKxAGNJVbUGfDCgbpA= github.com/grumpypixel/go-webget v0.0.1/go.mod h1:TZ3kzdKP644McT9EqfvX6vRcnoKxAGNJVbUGfDCgbpA=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/labstack/echo/v4 v4.7.2 h1:Kv2/p8OaQ+M6Ex4eGimg9b9e6icoxA42JSlOR3msKtI=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k=
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM=
github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg=
github.com/remychantenay/slog-otel v1.3.3 h1:Atk1p630QPgYFW4/YEyBuObNmwrYpx5Tglnl1sdhSVA=
github.com/remychantenay/slog-otel v1.3.3/go.mod h1:OMdQAB/S2341nbz2Ramh3+RH2yYGLJLspTaghiCToTU=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew=
github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
github.com/samber/slog-echo v1.16.1 h1:5Q5IUROkFqKcu/qJM/13AP1d3gd1RS+Q/4EvKQU1fuo=
github.com/samber/slog-echo v1.16.1/go.mod h1:f+B3WR06saRXcaGRZ/I/UPCECDPqTUqadRIf7TmyRhI=
github.com/samber/slog-multi v1.4.0 h1:pwlPMIE7PrbTHQyKWDU+RIoxP1+HKTNOujk3/kdkbdg=
github.com/samber/slog-multi v1.4.0/go.mod h1:FsQ4Uv2L+E/8TZt+/BVgYZ1LoDWCbfCU21wVIoMMrO8=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
go.ntppool.org/common v0.3.1 h1:JaJpS3m8oAc9jH0yhHYJnjOC+RUzxx/F+EDe0QON4eQ= golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o=
go.ntppool.org/common v0.3.1/go.mod h1:1SKjFBH9AL7Fj2S0zy41isHzV6dTC+6yIKD5QDtX8aY= golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 h1:EN5+DfgmRMvRUrMGERW2gQl3Vc+Z7ZMnI/xdEpPSf0c=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
go.opentelemetry.io/contrib/bridges/otelslog v0.10.0 h1:lRKWBp9nWoBe1HKXzc3ovkro7YZSb72X2+3zYNxfXiU= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
go.opentelemetry.io/contrib/bridges/otelslog v0.10.0/go.mod h1:D+iyUv/Wxbw5LUDO5oh7x744ypftIryiWjoj42I6EKs= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
go.opentelemetry.io/contrib/bridges/prometheus v0.60.0 h1:x7sPooQCwSg27SjtQee8GyIIRTQcF4s7eSkac6F2+VA= golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
go.opentelemetry.io/contrib/bridges/prometheus v0.60.0/go.mod h1:4K5UXgiHxV484efGs42ejD7E2J/sIlepYgdGoPXe7hE= golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12 h1:QyVthZKMsyaQwBTJE04jdNN0Pp5Fn9Qga0mrgxyERQM=
go.opentelemetry.io/contrib/exporters/autoexport v0.60.0 h1:GuQXpvSXNjpswpweIem84U9BNauqHHi2w1GtNAalvpM= golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
go.opentelemetry.io/contrib/exporters/autoexport v0.60.0/go.mod h1:CkmxekdHco4d7thFJNPQ7Mby4jMBgZUclnrxT4e+ryk= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.60.0 h1:vmDg6SXfGUXSkivp53zPNWbmqFBz5P+DBHlf3PROB9E= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.60.0/go.mod h1:ZluigSzu/knqjPvUvb3B9LZSAYxus3my2d0kyaiJuxA=
go.opentelemetry.io/contrib/propagators/b3 v1.35.0 h1:DpwKW04LkdFRFCIgM3sqwTJA/QREHMeMHYPWP1WeaPQ=
go.opentelemetry.io/contrib/propagators/b3 v1.35.0/go.mod h1:9+SNxwqvCWo1qQwUpACBY5YKNVxFJn5mlbXg/4+uKBg=
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.11.0 h1:HMUytBT3uGhPKYY/u/G5MR9itrlSO2SMOsSD3Tk3k7A=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.11.0/go.mod h1:hdDXsiNLmdW/9BF2jQpnHHlhFajpWCEYfM6e5m2OAZg=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.11.0 h1:C/Wi2F8wEmbxJ9Kuzw/nhP+Z9XaHYMkyDmXy6yR2cjw=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.11.0/go.mod h1:0Lr9vmGKzadCTgsiBydxr6GEZ8SsZ7Ks53LzjWG5Ar4=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0 h1:QcFwRrZLc82r8wODjvyCbP7Ifp3UANaBSmhDSFjnqSc=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0/go.mod h1:CXIWhUomyWBG/oY2/r/kLp6K/cmx9e/7DLpBuuGdLCA=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.35.0 h1:0NIXxOCFx+SKbhCVxwl3ETG8ClLPAa0KuKV6p3yhxP8=
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.35.0/go.mod h1:ChZSJbbfbl/DcRZNc9Gqh6DYGlfjw4PvO1pEOZH1ZsE=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
go.opentelemetry.io/otel/exporters/prometheus v0.57.0 h1:AHh/lAP1BHrY5gBwk8ncc25FXWm/gmmY3BX258z5nuk=
go.opentelemetry.io/otel/exporters/prometheus v0.57.0/go.mod h1:QpFWz1QxqevfjwzYdbMb4Y1NnlJvqSGwyuU0B4iuc9c=
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.11.0 h1:k6KdfZk72tVW/QVZf60xlDziDvYAePj5QHwoQvrB2m8=
go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.11.0/go.mod h1:5Y3ZJLqzi/x/kYtrSrPSx7TFI/SGsL7q2kME027tH6I=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0 h1:PB3Zrjs1sG1GBX51SXyTSoOTqcDglmsk7nT6tkKPb/k=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0/go.mod h1:U2R3XyVPzn0WX7wOIypPuptulsMcPDPs/oiSVOMVnHY=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.35.0 h1:T0Ec2E+3YZf5bgTNQVet8iTDW7oIk03tXHq+wkwIDnE=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.35.0/go.mod h1:30v2gqH+vYGJsesLWFov8u47EpYTcIQcBjKpI6pJThg=
go.opentelemetry.io/otel/log v0.11.0 h1:c24Hrlk5WJ8JWcwbQxdBqxZdOK7PcP/LFtOtwpDTe3Y=
go.opentelemetry.io/otel/log v0.11.0/go.mod h1:U/sxQ83FPmT29trrifhQg+Zj2lo1/IPN1PF6RTFqdwc=
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
go.opentelemetry.io/otel/sdk/log v0.11.0 h1:7bAOpjpGglWhdEzP8z0VXc4jObOiDEwr3IYbhBnjk2c=
go.opentelemetry.io/otel/sdk/log v0.11.0/go.mod h1:dndLTxZbwBstZoqsJB3kGsRPkpAgaJrWfQg3lhlHFFY=
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
google.golang.org/genproto/googleapis/api v0.0.0-20250409194420-de1ac958c67a h1:OQ7sHVzkx6L57dQpzUS4ckfWJ51KDH74XHTDe23xWAs=
google.golang.org/genproto/googleapis/api v0.0.0-20250409194420-de1ac958c67a/go.mod h1:2R6XrVC8Oc08GlNh8ujEpc7HkLiEZ16QeY7FxIs20ac=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250409194420-de1ac958c67a h1:GIqLhp/cYUkuGuiT+vJk8vhOP86L4+SP5j8yXgeVpvI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250409194420-de1ac958c67a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI=
google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,54 +0,0 @@
package types
import (
"sort"
"strings"
alphafoxtrot "github.com/grumpypixel/go-airport-finder"
)
type Airport struct {
Name string
Code string
Distance float64
Type string
}
func NewAirport(airport *alphafoxtrot.Airport) *Airport {
code := strings.ToLower(airport.Country.ISOCode + airport.IATACode)
a := &Airport{
Name: airport.Name,
Code: code,
Type: airport.Type,
}
return a
}
func (a *Airport) String() string {
return a.Name
}
func UniqAirports(r []*Airport) []*Airport {
seen := make(map[string]struct{})
j := 0
for _, v := range r {
if _, ok := seen[v.Code]; ok {
continue
}
seen[v.Code] = struct{}{}
r[j] = v
j++
}
return r[:j]
}
func SortAirports(r []*Airport) {
sort.Slice(r, func(i, j int) bool {
if r[i].Type == r[j].Type {
return r[i].Distance < r[j].Distance
}
return r[i].Type < r[j].Type
})
}