This commit is contained in:
Martin Donnelly 2024-08-28 00:24:33 +01:00
commit 9b11de7902
81 changed files with 127935 additions and 0 deletions

103
.gitignore vendored Normal file
View File

@ -0,0 +1,103 @@
### GoLand+all template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### Go template
# If you prefer the allow list template instead of the deny list, see community template:
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
#
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
# Go workspace file
go.work
jubilee-server

258
fsexplore/fsexplore.go Normal file
View File

@ -0,0 +1,258 @@
package fsexplore
import (
"encoding/json"
"fmt"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/models"
"jubilee-server/fsq"
"jubilee-server/structs"
"log"
"strconv"
)
type (
ReducedDetail struct {
Name string `json:"name"`
Description string `json:"description"`
Category string `json:"category"`
Icon string `json:"icon"`
Id string `json:"id"`
Provider string `json:"provider"`
Address string `json:"address"`
City string `json:"city"`
State string `json:"state"`
Postcode string `json:"postcode"`
Twitter string `json:"twitter"`
Facebook string `json:"facebook"`
Url string `json:"url"`
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
Images []string `json:"images"`
}
DbRecord struct {
Fsqid string `json:"fsqid" db:"fsqid"`
Data string `json:"data" db:"data"`
}
)
func FsRequest(latLong structs.LatLong, soqval string, soqtype string, limit string) string {
log.Println("$$:fsexplore:FsRequest")
log.Printf("latLong: %s", latLong)
log.Printf("soqval: %s", soqval)
log.Printf("limit: %s", limit)
log.Printf("soqtype: %s", soqtype)
data := GetRemoteFSRequest(latLong, soqval, soqtype, limit)
return data
}
func FsRequestDetails(app *pocketbase.PocketBase, fsqid string) string {
log.Println("$$:fsexplore:FsRequestDetails")
log.Printf("fsqid: %s", fsqid)
formattedDetails := &DbRecord{}
dberr := app.Dao().DB().
Select("fsqid", "data").From("fsdetails").
Where(dbx.NewExp("fsqid = {:fsqid}", dbx.Params{"fsqid": fsqid})).One(&formattedDetails)
if dberr == nil {
log.Printf("-- Cache hit fsDetails %+v\n", formattedDetails.Fsqid)
return formattedDetails.Data
}
data := GetRemoteDetailRequest(fsqid)
formattedDetails.Fsqid = fsqid
formattedDetails.Data = data
go func() {
err := SaveReducedDetails(app, *formattedDetails)
if err != nil {
log.Println(err)
}
}()
return data
}
func GetRemoteFSRequest(ll structs.LatLong, soqval string, soqtype string, limit string) string {
lat := strconv.FormatFloat(ll.Lat, 'f', -1, 64)
long := strconv.FormatFloat(ll.Long, 'f', -1, 64)
var modifiertype string
if soqtype == "q" {
modifiertype = "chain"
} else {
modifiertype = "category"
}
modifier := soqval
client := fsq.NewQueryForLocation("fsq3ksL8PkGBLhDJ6Bydixoa9Lah6djwvm5a5LIWrtmFexc=", lat, long, "", 1000, modifiertype, modifier)
log.Printf("client: %s", client)
s, err := client.SearchRaw()
if err != nil {
log.Println("Error:", err)
}
return s
}
func GetRemoteDetailRequest(fsqid string) string {
client := fsq.NewQueryPlaceDetails("fsq3ksL8PkGBLhDJ6Bydixoa9Lah6djwvm5a5LIWrtmFexc=", fsqid)
details, de := client.GetDetailsRaw()
if de != nil {
log.Println("Error:", de)
}
photos, pe := client.GetPhotosRaw()
if pe != nil {
log.Println("Error:", pe)
}
mergedData, _ := mergeDetails(details, photos)
return mergedData
}
func mergeDetails(details string, photos string) (jstr string, err error) {
rd := reduceDetails(details)
images := reducePhotos(photos)
rd.Images = images
log.Printf("RD: %+v\n", rd)
j, err := json.Marshal(rd)
return string(j), err
}
func reduceDetails(details string) *ReducedDetail {
dataPtr := &fsq.Results4sqPlaces{}
reducedDetails := ReducedDetail{}
err := json.Unmarshal([]byte(details), dataPtr)
log.Println("Error", err)
reducedDetails.Name = dataPtr.Name
reducedDetails.Description = dataPtr.Description
reducedDetails.Category = dataPtr.Categories[0].ShortName
reducedDetails.Icon = dataPtr.Categories[0].Icon.Prefix + "64" + dataPtr.Categories[0].Icon.Suffix
reducedDetails.Id = dataPtr.FsqId
reducedDetails.Provider = "foursquare"
reducedDetails.Address = dataPtr.Location.FormattedAddress
reducedDetails.City = dataPtr.Location.PostTown
reducedDetails.State = dataPtr.Location.Region
reducedDetails.Postcode = dataPtr.Location.Postcode
reducedDetails.Twitter = dataPtr.SocialMedia.Twitter
reducedDetails.Facebook = dataPtr.SocialMedia.FacebookId
reducedDetails.Longitude = dataPtr.Geocodes.Main.Longitude
reducedDetails.Latitude = dataPtr.Geocodes.Main.Latitude
return &reducedDetails
}
func reducePhotos(photos string) []string {
dataPtr := &[]fsq.Photos4sqPlaces{}
var images []string
err := json.Unmarshal([]byte(photos), dataPtr)
log.Println("Error", err)
for _, photo := range *dataPtr {
prefix := photo.Prefix
suffix := photo.Suffix
width := photo.Width
height := photo.Height
ratioHeight := 480
log.Printf("%+v,%+v => 640, %+v \n", width, height, ratioHeight)
output := fmt.Sprintf("%s640%s", prefix, suffix)
log.Println(output)
images = append(images, output)
}
return images
}
func SaveReducedDetails(app *pocketbase.PocketBase, newDetails DbRecord) error {
log.Println("$$:SaveReducedDetails", newDetails.Fsqid)
collection, err := app.Dao().FindCollectionByNameOrId("fsdetails")
if err != nil {
log.Println(err)
return err
}
record, recErr := app.Dao().FindRecordsByExpr("fsdetails", dbx.NewExp("fsqid = {:fsqid}", dbx.Params{"fsqid": newDetails.Fsqid}))
if recErr != nil {
log.Println(recErr)
return recErr
}
if len(record) == 0 {
log.Println("-- Insert new fsdetails record")
record := models.NewRecord(collection)
record.Set("fsqid", newDetails.Fsqid)
record.Set("data", newDetails.Data)
if err := app.Dao().SaveRecord(record); err != nil {
log.Println("ERROR!! SaveReducedDetails NewRecord")
log.Println(err)
return err
}
} else {
log.Println("-- Update weather record")
rec := record[0]
rec.Set("data", newDetails.Data)
if err := app.Dao().SaveRecord(rec); err != nil {
log.Println("ERROR!! SaveReducedDetails SaveRecord")
log.Println(err)
return err
}
}
return nil
}

157
fsq/api.go Normal file
View File

@ -0,0 +1,157 @@
package fsq
import (
"encoding/json"
"fmt"
"github.com/google/go-querystring/query"
"io"
"log"
"net/http"
)
func (query Query) SearchRaw() (json string, err error) {
url := PlacesURL(query)
log.Print(url)
bytes, err := download(url, query.APIKey)
if err != nil {
return "", err
}
return string(bytes), nil
}
func (query Query) Search() (*FoursquarePlaces, error) {
url := PlacesURL(query)
log.Print(url)
bytes, err := download(url, query.APIKey)
if err != nil {
return nil, err
}
dataPtr := &FoursquarePlaces{}
err = json.Unmarshal(bytes, dataPtr)
return dataPtr, err
}
func (detailQuery DetailQuery) GetDetailsRaw() (json string, err error) {
url := PlacesDetailsURL(detailQuery)
log.Print(url)
bytes, err := download(url, detailQuery.APIKey)
if err != nil {
return "", err
}
return string(bytes), nil
}
func (detailQuery DetailQuery) GetDetails() (*Results4sqPlaces, error) {
url := PlacesDetailsURL(detailQuery)
log.Print(url)
bytes, err := download(url, detailQuery.APIKey)
if err != nil {
return nil, err
}
datePtr := &Results4sqPlaces{}
err = json.Unmarshal(bytes, datePtr)
return datePtr, err
}
func (detailQuery DetailQuery) GetPhotosRaw() (json string, err error) {
url := PlacesPhotosURL(detailQuery)
log.Print(url)
bytes, err := download(url, detailQuery.APIKey)
if err != nil {
return "", err
}
return string(bytes), nil
}
func (detailQuery DetailQuery) GetPhotos() (*[]Photos4sqPlaces, error) {
url := PlacesPhotosURL(detailQuery)
log.Print(url)
bytes, err := download(url, detailQuery.APIKey)
if err != nil {
return nil, err
}
dataPtr := &[]Photos4sqPlaces{}
err = json.Unmarshal(bytes, dataPtr)
return dataPtr, err
}
func PlacesURL(q Query) string {
v, _ := query.Values(q)
fmt.Println(v.Encode())
url := "https://api.foursquare.com/v3/places/search?" + v.Encode()
fmt.Println(url)
return url
}
func PlacesDetailsURL(dq DetailQuery) string {
v, _ := query.Values(dq)
fmt.Println(v.Encode())
url := "https://api.foursquare.com/v3/places/" + dq.fsqID + "?" + v.Encode()
fmt.Println(url)
return url
}
func PlacesPhotosURL(dq DetailQuery) string {
v, _ := query.Values(dq)
fmt.Println(v.Encode())
url := "https://api.foursquare.com/v3/places/" + dq.fsqID + "/photos"
fmt.Println(url)
return url
}
func download(url string, apiKey string) (res []byte, err error) {
req, err := http.NewRequest("GET", url, nil)
req.Header.Add("accept", "application/json")
req.Header.Add("Authorization", apiKey)
resp, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Println("Http failed")
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
}

291
fsq/model.go Normal file
View File

@ -0,0 +1,291 @@
package fsq
import (
"time"
)
type (
Options struct {
LatLong string `url:"ll"`
Radius int64 `url:"radius"`
Category string `url:"categories,omitempty"`
Key string `url:"-"`
}
)
type CustomTime struct {
time.Time
}
type (
FoursquarePlaces struct {
Results []Results4sqPlaces `json:"results"`
}
Results4sqPlaces struct {
FsqId string `json:"fsq_id"`
Categories []Categories4sqPlaces `json:"categories"`
Chains []Chains4sqPlaces `json:"chains,omitempty"`
ClosedBucket string `json:"closed_bucket,omitempty"`
DateClosed CustomTime `json:"date_closed,omitempty"`
Description string `json:"description,omitempty"`
Distance int64 `json:"distance,omitempty"`
Email string `json:"email,omitempty"`
Fax string `json:"fax,omitempty"`
Features Features4sqPlaces `json:"features,omitempty"`
Geocodes Geocodes4sqPlaces `json:"geocodes,omitempty"`
Hours Hours4sqPlaces `json:"hours,omitempty"`
HoursPopular []HoursSlots4sqPlaces `json:"hours_popular,omitempty"`
Link string `json:"link,omitempty"`
Location Location4sqPlaces `json:"location,omitempty"`
Photos []Photos4sqPlaces `json:"photos,omitempty"`
Popularity int64 `json:"popularity,omitempty"`
Price int64 `json:"price,omitempty"`
Rating int64 `json:"rating,omitempty"`
Name string `json:"name,omitempty"`
RelatedPlaces struct{} `json:"related_places,omitempty"`
SocialMedia SocialMedia4sqPlaces `json:"social_media,omitempty"`
Stats Stats4sqPlaces `json:"stats,omitempty"`
StoreId string `json:"store_id,omitempty"`
Tastes []string `json:"tastes,omitempty"`
Tel string `json:"tel,omitempty"`
Timezone string `json:"timezone,omitempty"`
Tips []Tips4sqPlaces `json:"tips,omitempty"`
VenueRealityBucket string `json:"venue_reality_bucket,omitempty"`
Verified bool `json:"verified,omitempty"`
Website string `json:"website,omitempty"`
}
)
type Categories4sqPlaces struct {
Id int64 `json:"id"`
Name string `json:"name"`
ShortName string `json:"short_name,omitempty"`
PluralName string `json:"plural_name,omitempty"`
Icon Icon4sqPlaces `json:"icon,omitempty"`
}
type Icon4sqPlaces struct {
Id string `json:"id,omitempty"`
CreateAt CustomTime `json:"create_at,omitempty"`
Prefix string `json:"prefix"`
Suffix string `json:"suffix"`
Width int64 `json:"width,omitempty"`
Height int64 `json:"height,omitempty"`
Classifications []string `json:"classifications,omitempty"`
Tip Tip4sqPlaces `json:"tip,omitempty"`
}
type Chains4sqPlaces struct {
Id string `json:"id"`
Name string `json:"name"`
}
type Tip4sqPlaces struct {
Id string `json:"id"`
CreatedAt CustomTime `json:"created_at,omitempty"`
Text string `json:"text"`
Url string `json:"url,omitempty"`
Lang string `json:"lang,omitempty"`
AgreeCount int64 `json:"agree_count,omitempty"`
DisagreeCount int64 `json:"disagree_count,omitempty"`
}
type Features4sqPlaces struct {
Payment Payment4sqPlaces `json:"payment,omitempty"`
FoodAndDrink FoodAndDrink4sqPlaces `json:"food_and_drink,omitempty"`
Services Services4sqPlaces `json:"services,omitempty"`
Amenities Amenities4sqPlaces `json:"amenities,omitempty"`
Attributes Attributes4sqPlaces `json:"attributes,omitempty"`
}
type Payment4sqPlaces struct {
CreditCards CreditCards4sqPlaces `json:"credit_cards,omitempty"`
DigitalWallet DigitalWallet4sqPlaces `json:"digital_wallet,omitempty"`
}
type CreditCards4sqPlaces struct {
AcceptsCreditCards struct{} `json:"accepts_credit_cards,omitempty"`
Amex struct{} `json:"amex,omitempty"`
Discover struct{} `json:"discover,omitempty"`
Visa struct{} `json:"visa,omitempty"`
DinersClub struct{} `json:"diners_club,omitempty"`
MasterCard struct{} `json:"master_card,omitempty"`
UnionPay struct{} `json:"union_pay,omitempty"`
}
type DigitalWallet4sqPlaces struct {
AcceptsNfc struct{} `json:"accepts_nfc,omitempty"`
}
type FoodAndDrink4sqPlaces struct {
Alcohol Alcohol4sqPlaces `json:"alcohol,omitempty"`
Meals Meals4sqPlaces `json:"meals,omitempty"`
}
type Alcohol4sqPlaces struct {
BarService struct{} `json:"bar_service,omitempty"`
Beer struct{} `json:"beer,omitempty"`
Byo struct{} `json:"byo,omitempty"`
Cocktails struct{} `json:"cocktails,omitempty"`
FullBar struct{} `json:"full_bar,omitempty"`
Wine struct{} `json:"wine,omitempty"`
}
type Meals4sqPlaces struct {
BarSnacks struct{} `json:"bar_snacks,omitempty"`
Breakfast struct{} `json:"breakfast,omitempty"`
Brunch struct{} `json:"brunch,omitempty"`
Lunch struct{} `json:"lunch,omitempty"`
HappyHour struct{} `json:"happy_hour,omitempty"`
Dessert struct{} `json:"dessert,omitempty"`
Dinner struct{} `json:"dinner,omitempty"`
TastingMenu struct{} `json:"tasting_menu,omitempty"`
}
type Services4sqPlaces struct {
Delivery struct{} `json:"delivery,omitempty"`
Takeout struct{} `json:"takeout,omitempty"`
DriveThrough struct{} `json:"drive_through,omitempty"`
DineIn DineIn4sqPlaces `json:"dine_in,omitempty"`
}
type DineIn4sqPlaces struct {
Reservations struct{} `json:"reservations,omitempty"`
OnlineReservations struct{} `json:"online_reservations,omitempty"`
GroupsOnlyReservations struct{} `json:"groups_only_reservations,omitempty"`
EssentialReservations struct{} `json:"essential_reservations,omitempty"`
}
type Amenities4sqPlaces struct {
Restroom struct{} `json:"restroom,omitempty"`
Smoking struct{} `json:"smoking,omitempty"`
Jukebox struct{} `json:"jukebox,omitempty"`
Music struct{} `json:"music,omitempty"`
LiveMusic struct{} `json:"live_music,omitempty"`
PrivateRoom struct{} `json:"private_room,omitempty"`
OutdoorSeating struct{} `json:"outdoor_seating,omitempty"`
Tvs struct{} `json:"tvs,omitempty"`
Atm struct{} `json:"atm,omitempty"`
CoatCheck struct{} `json:"coat_check,omitempty"`
WheelchairAccessible struct{} `json:"wheelchair_accessible,omitempty"`
Parking Parking4sqPlaces `json:"parking,omitempty"`
SitDownDining struct{} `json:"sit_down_dining,omitempty"`
Wifi string `json:"wifi,omitempty"`
}
type Parking4sqPlaces struct {
Parking struct{} `json:"parking,omitempty"`
StreetParking struct{} `json:"street_parking,omitempty"`
ValetParking struct{} `json:"valet_parking,omitempty"`
PublicLot struct{} `json:"public_lot,omitempty"`
PrivateLot struct{} `json:"private_lot,omitempty"`
}
type Attributes4sqPlaces struct {
BusinessMeeting string `json:"business_meeting,omitempty"`
Clean string `json:"clean,omitempty"`
Crowded string `json:"crowded,omitempty"`
DatesPopular string `json:"dates_popular,omitempty"`
FamiliesPopular string `json:"families_popular,omitempty"`
GlutenFreeDiet string `json:"gluten_free_diet,omitempty"`
GoodForDogs string `json:"good_for_dogs,omitempty"`
GroupsPopular string `json:"groups_popular,omitempty"`
HealthyDiet string `json:"healthy_diet,omitempty"`
LateNight string `json:"late_night,omitempty"`
Noisy string `json:"noisy,omitempty"`
QuickBite string `json:"quick_bite,omitempty"`
Romantic string `json:"romantic,omitempty"`
ServiceQuality string `json:"service_quality,omitempty"`
SinglesPopular string `json:"singles_popular,omitempty"`
SpecialOccasion string `json:"special_occasion,omitempty"`
Trendy string `json:"trendy,omitempty"`
ValueForMoney string `json:"value_for_money,omitempty"`
VeganDiet string `json:"vegan_diet,omitempty"`
VegetarianDiet string `json:"vegetarian_diet,omitempty"`
}
type Geocodes4sqPlaces struct {
DropOff LatLong4sqPlaces `json:"drop_off,omitempty"`
FrontDoor LatLong4sqPlaces `json:"front_door,omitempty"`
Main LatLong4sqPlaces `json:"main,omitempty"`
Road LatLong4sqPlaces `json:"road,omitempty"`
Roof LatLong4sqPlaces `json:"roof,omitempty"`
}
type LatLong4sqPlaces struct {
Latitude float64 `json:"latitude,omitempty"`
Longitude float64 `json:"longitude,omitempty"`
}
type Hours4sqPlaces struct {
Display string `json:"display,omitempty"`
IsLocalHoliday bool `json:"is_local_holiday,omitempty"`
OpenNow bool `json:"open_now,omitempty"`
Regular []HoursSlots4sqPlaces `json:"regular,omitempty"`
}
type HoursSlots4sqPlaces struct {
Close string `json:"close,omitempty"`
Day int64 `json:"day,omitempty"`
Open string `json:"open,omitempty"`
}
type Location4sqPlaces struct {
Address string `json:"address,omitempty"`
AddressExtended string `json:"address_extended,omitempty"`
AdminRegion string `json:"admin_region,omitempty"`
CensusBlock string `json:"census_block,omitempty"`
Country string `json:"country,omitempty"`
CrossStreet string `json:"cross_street,omitempty"`
Dma string `json:"dma,omitempty"`
FormattedAddress string `json:"formatted_address,omitempty"`
Locality string `json:"locality,omitempty"`
Neighborhood []string `json:"neighborhood,omitempty"`
PoBox string `json:"po_box,omitempty"`
PostTown string `json:"post_town,omitempty"`
Postcode string `json:"postcode,omitempty"`
Region string `json:"region,omitempty"`
}
type Photos4sqPlaces struct {
Id string `json:"id,omitempty"`
CreatedAt CustomTime `json:"created_at,omitempty"`
Prefix string `json:"prefix,omitempty"`
Suffix string `json:"suffix,omitempty"`
Width int64 `json:"width,omitempty"`
Height int64 `json:"height,omitempty"`
Classifications []string `json:"classifications,omitempty"`
Tip PhotosTip4sqPlaces `json:"tip,omitempty"`
}
type PhotosTip4sqPlaces struct {
Id string `json:"id,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
Text string `json:"text,omitempty"`
Url string `json:"url,omitempty"`
Lang string `json:"lang,omitempty"`
AgreeCount int64 `json:"agree_count,omitempty"`
DisagreeCount int64 `json:"disagree_count,omitempty"`
}
type SocialMedia4sqPlaces struct {
FacebookId string `json:"facebook_id,omitempty"`
Instagram string `json:"instagram,omitempty"`
Twitter string `json:"twitter,omitempty"`
}
type Stats4sqPlaces struct {
TotalPhotos int64 `json:"total_photos,omitempty"`
TotalRatings int64 `json:"total_ratings,omitempty"`
TotalTips int64 `json:"total_tips,omitempty"`
}
type Tips4sqPlaces struct {
Id string `json:"id,omitempty"`
CreatedAt CustomTime `json:"created_at,omitempty"`
Text string `json:"text,omitempty"`
Url string `json:"url,omitempty"`
Lang string `json:"lang,omitempty"`
AgreeCount int64 `json:"agree_count,omitempty"`
DisagreeCount int64 `json:"disagree_count,omitempty"`
}

57
fsq/query.go Normal file
View File

@ -0,0 +1,57 @@
package fsq
type Query struct {
APIKey string `url:"-"`
Query string `url:"query,omitempty"`
LL string `url:"ll"`
Radius int32 `url:"radius,omitempty"`
Categories string `url:"categories,omitempty"`
Chains string `url:"chains,omitempty"`
Limit int32 `url:"limit,omitempty"`
Sort string `url:"sort,omitempty"`
}
type DetailQuery struct {
APIKey string `url:"-"`
fsqID string `url:"-"`
Fields string `url:"fields"`
}
func NewQueryForLocation(apiKey string, lat string, lon string, query string, radius int32, modifierType string, modifier string) Query {
category := ""
chain := ""
// &sort=DISTANCE&limit=30
if modifier != "0" {
if modifierType == "chain" {
chain = modifier
}
if modifierType == "category" {
category = modifier
}
}
return Query{
APIKey: apiKey,
LL: lat + "," + lon,
Radius: radius,
Query: query,
Categories: category,
Chains: chain,
Sort: "DISTANCE",
}
}
func NewQueryPlaceDetails(apiKey string, fsqID string) DetailQuery {
fields := "name,categories,fsq_id,location,description,social_media,link,geocodes"
return DetailQuery{
APIKey: apiKey,
fsqID: fsqID,
Fields: fields,
}
}

154
geocode/geocode.go Normal file
View File

@ -0,0 +1,154 @@
package geocode
import (
_ "fmt"
"github.com/codingsince1985/geo-golang"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/models"
"jubilee-server/structs"
"log"
"github.com/codingsince1985/geo-golang/openstreetmap"
)
// const opencageApiKey = "893ab539eca84b5ca7a54cb03ef23443"
func Geocode(app *pocketbase.PocketBase, latlong structs.LatLong) *structs.FormattedLocation {
log.Println("$$:Geocode", latlong)
log.Println("-- lat", latlong.Lat)
log.Println("-- long", latlong.Long)
formattedLocation := &structs.FormattedLocation{}
latlow := latlong.Lat - 0.001
lathigh := latlong.Lat + 0.001
longlow := latlong.Long - 0.001
longhigh := latlong.Long + 0.001
log.Printf("-- Between %+v,%+v to %+v,%+v\n", latlow, longlow, lathigh, longhigh)
dberr := app.Dao().DB().
Select("*").From("geocode").
Where(dbx.NewExp("lat >= {:latlow} and lat <= {:lathigh}", dbx.Params{"latlow": latlow, "lathigh": lathigh})).
AndWhere(dbx.NewExp("long >= {:longlow} and long <= {:longhigh}", dbx.Params{"longlow": longlow, "longhigh": longhigh})).One(&formattedLocation)
if dberr == nil {
// handle error
log.Printf("-- Cache hit geocode %+v,%+v\n", formattedLocation.Lat, formattedLocation.Long)
return formattedLocation
}
formattedLocation = tryGeocoder(openstreetmap.Geocoder(), latlong)
go func() {
err := saveLocationRec(app, *formattedLocation)
if err != nil {
log.Println(err)
}
}()
return formattedLocation
// tryGeocoder(opencage.Geocoder(opencageApiKey), latlong)
}
func tryGeocoder(geocoder geo.Geocoder, latlong structs.LatLong) *structs.FormattedLocation {
address, _ := geocoder.ReverseGeocode(latlong.Lat, latlong.Long)
if address != nil {
log.Printf("%+v\n", address)
return reformatGeocode(*address, latlong)
} else {
return new(structs.FormattedLocation)
}
}
func reformatGeocode(address geo.Address, latlong structs.LatLong) *structs.FormattedLocation {
return &structs.FormattedLocation{
Lat: latlong.Lat,
Long: latlong.Long,
Country: address.Country,
City: address.City,
State: address.State,
Zipcode: address.Postcode,
StreetName: address.Street,
CountryCode: address.CountryCode,
County: address.County,
Neighbourhood: address.Suburb,
Village: "",
Formatted: address.FormattedAddress,
}
}
func saveLocationRec(app *pocketbase.PocketBase, newLocation structs.FormattedLocation) error {
log.Println("$$:saveLocationRec", newLocation.Lat, newLocation.Long)
collection, err := app.Dao().FindCollectionByNameOrId("geocode")
if err != nil {
log.Println(err)
return err
}
record, recErr := app.Dao().FindRecordsByExpr("geocode", dbx.NewExp("lat = {:lat} and long = {:long}", dbx.Params{"lat": newLocation.Lat, "long": newLocation.Long}))
if recErr != nil {
log.Println(recErr)
return recErr
}
if len(record) == 0 {
log.Println("-- Insert new geocode")
record := models.NewRecord(collection)
record.Set("lat", newLocation.Lat)
record.Set("long", newLocation.Long)
record.Set("country", newLocation.Country)
record.Set("city", newLocation.City)
record.Set("state", newLocation.State)
record.Set("zipcode", newLocation.Zipcode)
record.Set("streetname", newLocation.StreetName)
record.Set("countrycode", newLocation.CountryCode)
record.Set("county", newLocation.County)
record.Set("neighbourhood", newLocation.Neighbourhood)
record.Set("village", newLocation.Village)
record.Set("formatted", newLocation.Formatted)
if err := app.Dao().SaveRecord(record); err != nil {
log.Println("ERROR!! saveLocationRec NewRecord")
log.Println(err)
return err
}
} else {
log.Println("-- Update geocode")
rec := record[0]
rec.Set("lat", newLocation.Lat)
rec.Set("long", newLocation.Long)
rec.Set("country", newLocation.Country)
rec.Set("city", newLocation.City)
rec.Set("state", newLocation.State)
rec.Set("zipcode", newLocation.Zipcode)
rec.Set("streetname", newLocation.StreetName)
rec.Set("countrycode", newLocation.CountryCode)
rec.Set("county", newLocation.County)
rec.Set("neighbourhood", newLocation.Neighbourhood)
rec.Set("village", newLocation.Village)
rec.Set("formatted", newLocation.Formatted)
if err := app.Dao().SaveRecord(rec); err != nil {
log.Println("ERROR!! saveLocationRec SaveRecord")
log.Println(err)
return err
}
}
return nil
}

86
go.mod Normal file
View File

@ -0,0 +1,86 @@
module jubilee-server
go 1.22.4
require (
github.com/EricNeid/go-openweather v0.2.0
github.com/codingsince1985/geo-golang v1.8.4
github.com/google/go-querystring v1.1.0
github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61
github.com/pocketbase/dbx v1.10.1
github.com/pocketbase/pocketbase v0.22.19
github.com/shawntoffel/go-pirateweather v0.0.1
)
require (
github.com/AlecAivazis/survey/v2 v2.3.7 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 // indirect
github.com/aws/aws-sdk-go-v2/config v1.27.27 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.27 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 // indirect
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.8 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.15 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.17 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.15 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.58.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect
github.com/aws/smithy-go v1.20.3 // indirect
github.com/disintegration/imaging v1.6.2 // indirect
github.com/domodwyer/mailyak/v3 v3.6.2 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.4 // indirect
github.com/ganigeorgiev/fexpr v0.4.1 // indirect
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/gax-go/v2 v2.13.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-sqlite3 v1.14.22 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
go.opencensus.io v0.24.0 // indirect
gocloud.dev v0.37.0 // indirect
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/image v0.18.0 // indirect
golang.org/x/net v0.27.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/term v0.22.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
google.golang.org/api v0.189.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a // indirect
google.golang.org/grpc v1.65.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
modernc.org/gc/v3 v3.0.0-20240722195230-4a140ff9c08e // indirect
modernc.org/libc v1.55.3 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.8.0 // indirect
modernc.org/sqlite v1.31.1 // indirect
modernc.org/strutil v1.2.0 // indirect
modernc.org/token v1.1.0 // indirect
)

370
go.sum Normal file
View File

@ -0,0 +1,370 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14=
cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU=
cloud.google.com/go/auth v0.7.2 h1:uiha352VrCDMXg+yoBtaD0tUF4Kv9vrtrWPYXwutnDE=
cloud.google.com/go/auth v0.7.2/go.mod h1:VEc4p5NNxycWQTMQEDQF0bd6aTMb6VgYDXEwiJJQAbs=
cloud.google.com/go/auth/oauth2adapt v0.2.3 h1:MlxF+Pd3OmSudg/b1yZ5lJwoXCEaeedAguodky1PcKI=
cloud.google.com/go/auth/oauth2adapt v0.2.3/go.mod h1:tMQXOfZzFuNuUxOypHlQEXgdfX5cuhwU+ffUuXRJE8I=
cloud.google.com/go/compute v1.25.0 h1:H1/4SqSUhjPFE7L5ddzHOfY2bCAvjwNRZPNl6Ni5oYU=
cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc=
cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI=
cloud.google.com/go/storage v1.39.1 h1:MvraqHKhogCOTXTlct/9C3K3+Uy2jBmFYb3/Sp6dVtY=
cloud.google.com/go/storage v1.39.1/go.mod h1:xK6xZmxZmo+fyP7+DEF6FhNc24/JAe95OLyOHCXFH1o=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ=
github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/EricNeid/go-openweather v0.2.0 h1:LUFjZ0bOOqge/k1hYJUrTb0gcCX7xDSi+d/l+CBGEu4=
github.com/EricNeid/go-openweather v0.2.0/go.mod h1:VpGos7PXf/6xNHnvi3nj9BlzRNdZFf8pje1XF4yr3Ug=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aws/aws-sdk-go v1.51.11 h1:El5VypsMIz7sFwAAj/j06JX9UGs4KAbAIEaZ57bNY4s=
github.com/aws/aws-sdk-go v1.51.11/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY=
github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 h1:tW1/Rkad38LA15X4UQtjXZXNKsCgkshC3EbmcUmghTg=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3/go.mod h1:UbnqO+zjqk3uIt9yCACHJ9IVNhyhOCnYk8yA19SAWrM=
github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOmKpdpsDMdO90=
github.com/aws/aws-sdk-go-v2/config v1.27.27/go.mod h1:MVYamCg76dFNINkZFu4n4RjDixhVr51HLj4ErWzrVwg=
github.com/aws/aws-sdk-go-v2/credentials v1.17.27 h1:2raNba6gr2IfA0eqqiP2XiQ0UVOpGPgDSi0I9iAP+UI=
github.com/aws/aws-sdk-go-v2/credentials v1.17.27/go.mod h1:gniiwbGahQByxan6YjQUMcW4Aov6bLC3m+evgcoN4r4=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.8 h1:u1KOU1S15ufyZqmH/rA3POkiRH6EcDANHj2xHRzq+zc=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.8/go.mod h1:WPv2FRnkIOoDv/8j2gSUsI4qDc7392w5anFB/I89GZ8=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.15 h1:Z5r7SycxmSllHYmaAZPpmN8GviDrSGhMS6bldqtXZPw=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.15/go.mod h1:CetW7bDE00QoGEmPUoZuRog07SGVAUVW6LFpNP0YfIg=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.17 h1:YPYe6ZmvUfDDDELqEKtAd6bo8zxhkm+XEFEzQisqUIE=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.17/go.mod h1:oBtcnYua/CgzCWYN7NZ5j7PotFDaFSUjCYVTtfyn7vw=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.15 h1:246A4lSTXWJw/rmlQI+TT2OcqeDMKBdyjEQrafMaQdA=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.15/go.mod h1:haVfg3761/WF7YPuJOER2MP0k4UAXyHaLclKXB6usDg=
github.com/aws/aws-sdk-go-v2/service/s3 v1.58.2 h1:sZXIzO38GZOU+O0C+INqbH7C2yALwfMWpd64tONS/NE=
github.com/aws/aws-sdk-go-v2/service/s3 v1.58.2/go.mod h1:Lcxzg5rojyVPU/0eFwLtcyTaek/6Mtic5B1gJo7e/zE=
github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 h1:BXx0ZIxvrJdSgSvKTZ+yRBeSqqgPM89VPlulEcl37tM=
github.com/aws/aws-sdk-go-v2/service/sso v1.22.4/go.mod h1:ooyCOXjvJEsUw7x+ZDHeISPMhtwI3ZCB7ggFMcFfWLU=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 h1:yiwVzJW2ZxZTurVbYWA7QOrAaCYQR72t0wrSBfoesUE=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4/go.mod h1:0oxfLkpz3rQ/CHlx5hB7H69YUpFiI1tql6Q6Ne+1bCw=
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudrvuKpDKgMVRlepGE=
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ=
github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE=
github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/codingsince1985/geo-golang v1.8.4 h1:1na/UJ8AVwte9dA/w/Ma+BjdJ8HeHyD45lH36Yfm4hQ=
github.com/codingsince1985/geo-golang v1.8.4/go.mod h1:/XlxmuFwxAK1J+XMt4KRVv2YLlAvJgMELBvZlrD3nzo=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
github.com/domodwyer/mailyak/v3 v3.6.2 h1:x3tGMsyFhTCaxp6ycgR0FE/bu5QiNp+hetUuCOBXMn8=
github.com/domodwyer/mailyak/v3 v3.6.2/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I=
github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s=
github.com/ganigeorgiev/fexpr v0.4.1 h1:hpUgbUEEWIZhSDBtf4M9aUNfQQ0BZkGRaMePy7Gcx5k=
github.com/ganigeorgiev/fexpr v0.4.1/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
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/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es=
github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.8.0 h1:UtktXaU2Nb64z/pLiGIxY4431SJ4/dR5cjMmlVHgnT4=
github.com/go-sql-driver/mysql v1.8.0/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
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.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/pprof v0.0.0-20240625030939-27f56978b8b0 h1:e+8XbKB6IMn8A4OAyZccO4pYfB3s7bt6azNIPE7AnPg=
github.com/google/pprof v0.0.0-20240625030939-27f56978b8b0/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI=
github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA=
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s=
github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61 h1:FwuzbVh87iLiUQj1+uQUsuw9x5t9m5n5g7rG7o4svW4=
github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61/go.mod h1:paQfF1YtHe+GrGg5fOgjsjoCX/UKDr9bc1DoWpZfns8=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
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/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
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/pocketbase/dbx v1.10.1 h1:cw+vsyfCJD8YObOVeqb93YErnlxwYMkNZ4rwN0G0AaA=
github.com/pocketbase/dbx v1.10.1/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs=
github.com/pocketbase/pocketbase v0.22.19 h1:Hu9J2nsRQIaw8MiDLzE65xUPyMPjf4DcS2f+QmH1G+c=
github.com/pocketbase/pocketbase v0.22.19/go.mod h1:0QFvDOOW7ANId78ChZSagyHbmP6CgMxDQrQFXzeaDpA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shawntoffel/go-pirateweather v0.0.1 h1:Q7uGN5OoTqcno0CXqhF/DOckcQ13FaaWYXudtGylCfQ=
github.com/shawntoffel/go-pirateweather v0.0.1/go.mod h1:/BXCF1d8pWF3uDllLgxzNKG1ADT8OJxuvWuqkwK4dFI=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.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/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
gocloud.dev v0.37.0 h1:XF1rN6R0qZI/9DYjN16Uy0durAmSlf58DHOcb28GPro=
gocloud.dev v0.37.0/go.mod h1:7/O4kqdInCNsc6LqgmuFnS0GRew4XNNYWpA44yQnwco=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ=
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 h1:LLhsEBxRTBLuKlQxFBYUOU8xyFgXv6cOTp2HASDlsDk=
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
google.golang.org/api v0.189.0 h1:equMo30LypAkdkLMBqfeIqtyAnlyig1JSZArl4XPwdI=
google.golang.org/api v0.189.0/go.mod h1:FLWGJKb0hb+pU2j+rJqwbnsF+ym+fQs73rbJ+KAUgy8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20240722135656-d784300faade h1:lKFsS7wpngDgSCeFn7MoLy+wBDQZ1UQIJD4UNM1Qvkg=
google.golang.org/genproto v0.0.0-20240722135656-d784300faade/go.mod h1:FfBgJBJg9GcpPvKIuHSZ/aE1g2ecGL74upMzGZjiGEY=
google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d h1:kHjw/5UfflP/L5EbledDrcG4C2597RtymmGRZvHiCuY=
google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d/go.mod h1:mw8MG/Qz5wfgYr6VqVCiZcHe/GJEfI+oGGDCohaVgB0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a h1:hqK4+jJZXCU4pW7jsAdGOVFIfLHQeV7LaizZKnZ84HI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ=
modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y=
modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s=
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
modernc.org/gc/v3 v3.0.0-20240722195230-4a140ff9c08e h1:WPC4v0rNIFb2PY+nBBEEKyugPPRHPzUgyN3xZPpGK58=
modernc.org/gc/v3 v3.0.0-20240722195230-4a140ff9c08e/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U=
modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
modernc.org/sqlite v1.31.1 h1:XVU0VyzxrYHlBhIs1DiEgSl0ZtdnPtbLVy8hSkzxGrs=
modernc.org/sqlite v1.31.1/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=

149
main.go Normal file
View File

@ -0,0 +1,149 @@
package main
import (
"fmt"
"github.com/labstack/echo/v5"
"jubilee-server/fsexplore"
"jubilee-server/geocode"
"jubilee-server/structs"
"jubilee-server/utils"
"jubilee-server/weather"
"log"
"net/http"
"os"
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/apis"
"github.com/pocketbase/pocketbase/core"
)
func main() {
app := pocketbase.New()
// serves static files from the provided public dir (if exists)
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
e.Router.GET("/*", apis.StaticDirectoryHandler(os.DirFS("./pb_public"), false))
e.Router.GET("/geocode/:latitude/:longitude", func(c echo.Context) error {
apis.ActivityLogger(app)
return geocodeHandler(c, app)
})
e.Router.GET("/weather/:latitude/:longitude", func(c echo.Context) error {
apis.ActivityLogger(app)
return forecastHandler(c, app)
})
e.Router.GET("/weatheralert/:latitude/:longitude", func(c echo.Context) error {
apis.ActivityLogger(app)
return weatherAlertHandler(c, app)
})
e.Router.GET("/fsexplore/:latitude/:longitude/:soqval/:soqtype/:limit", func(c echo.Context) error {
apis.ActivityLogger(app)
return fsExploreHandler(c, app)
})
e.Router.GET("/nearbydetail/:fsqid", func(c echo.Context) error {
apis.ActivityLogger(app)
return fsNearbyDetailHandler(c, app)
})
return nil
})
if err := app.Start(); err != nil {
log.Fatal(err)
}
}
func geocodeHandler(c echo.Context, app *pocketbase.PocketBase) error {
params := c.PathParams()
fmt.Printf("$$:geocodeHandler")
fmt.Printf("-- %+v\n", params)
log.Printf("Latitude: %s", c.PathParam("latitude"))
log.Printf("Longitude: %s", c.PathParam("longitude"))
latlong := new(structs.LatLong)
latlong = utils.LLfromStrings64(c.PathParam("latitude"), c.PathParam("longitude"))
address := geocode.Geocode(app, *latlong)
return c.JSON(http.StatusOK, address)
}
func forecastHandler(c echo.Context, app *pocketbase.PocketBase) error {
params := c.PathParams()
fmt.Printf("$$:forecastHandler")
fmt.Printf("-- %+v\n", params)
log.Printf("Latitude: %s", c.PathParam("latitude"))
log.Printf("Longitude: %s", c.PathParam("longitude"))
latlong := new(structs.LatLong)
latlong = utils.LLfromStrings64(c.PathParam("latitude"), c.PathParam("longitude"))
returnJson := weather.GetOpenWeather(app, *latlong)
c.Response().Header().Set("Cache-Control", "max-age=600, must-revalidate")
return c.String(http.StatusOK, returnJson)
}
func weatherAlertHandler(c echo.Context, app *pocketbase.PocketBase) error {
params := c.PathParams()
fmt.Printf("$$:WeatherAlertHandler")
fmt.Printf("-- %+v\n", params)
log.Printf("Latitude: %s", c.PathParam("latitude"))
log.Printf("Longitude: %s", c.PathParam("longitude"))
latlong := new(structs.LatLong)
latlong = utils.LLfromStrings64(c.PathParam("latitude"), c.PathParam("longitude"))
returnJson := weather.GetPirateForecast(app, *latlong)
c.Response().Header().Set("Cache-Control", "max-age=600, must-revalidate")
return c.String(http.StatusOK, returnJson)
}
func fsExploreHandler(c echo.Context, app *pocketbase.PocketBase) error {
params := c.PathParams()
fmt.Printf("$$:fsExploreHandler")
fmt.Printf("-- %+v\n", params)
log.Printf("Latitude: %s", c.PathParam("latitude"))
log.Printf("Longitude: %s", c.PathParam("longitude"))
log.Printf("Soqval: %s", c.PathParam("soqval"))
log.Printf("Soqtype: %s", c.PathParam("soqtype"))
log.Printf("Limit: %s", c.PathParam("Limit"))
latlong := new(structs.LatLong)
latlong = utils.LLfromStrings64(c.PathParam("latitude"), c.PathParam("longitude"))
log.Printf("latlong: %s", latlong)
returnJson := fsexplore.FsRequest(*latlong, c.PathParam("soqval"), c.PathParam("soqtype"), c.PathParam("limit"))
c.Response().Header().Set("Cache-Control", "max-age=600, must-revalidate")
return c.String(http.StatusOK, returnJson)
}
func fsNearbyDetailHandler(c echo.Context, app *pocketbase.PocketBase) error {
params := c.PathParams()
fmt.Printf("$$:fsNearbyDetailHandler")
fmt.Printf("-- %+v\n", params)
log.Printf("fsqid: %s", c.PathParam("fsqid"))
returnJson := fsexplore.FsRequestDetails(app, c.PathParam("fsqid"))
c.Response().Header().Set("Cache-Control", "max-age=600, must-revalidate")
return c.String(http.StatusOK, returnJson)
}

BIN
pb_data/data.db Normal file

Binary file not shown.

BIN
pb_data/logs.db Normal file

Binary file not shown.

0
pb_public/bridger.js Normal file
View File

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/img/mstile-150x150.png"/>
<TileColor>#2b5797</TileColor>
</tile>
</msapplication>
</browserconfig>

File diff suppressed because one or more lines are too long

BIN
pb_public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

96
pb_public/fonts/fonts.css Normal file
View File

@ -0,0 +1,96 @@
@font-face {
font-family: 'Roboto';
font-style: italic;
font-weight: 400;
src: url(Roboto-italic-400.woff) format('woff');
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Roboto';
font-style: italic;
font-weight: 700;
src: url(Roboto-italic-700.woff) format('woff');
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 100;
src: url(Roboto-normal-100.woff) format('woff');
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: url(Roboto-normal-300.woff) format('woff');
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: url(Roboto-normal-400.woff) format('woff');
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: url(Roboto-normal-500.woff) format('woff');
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: url(Roboto-normal-700.woff) format('woff');
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 900;
src: url(Roboto-normal-900.woff) format('woff');
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Roboto Condensed';
font-style: normal;
font-weight: 300;
src: url(Roboto_Condensed-normal-300.woff) format('woff');
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Roboto Condensed';
font-style: normal;
font-weight: 400;
src: url(Roboto_Condensed-normal-400.woff) format('woff');
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Roboto Condensed';
font-style: normal;
font-weight: 700;
src: url(Roboto_Condensed-normal-700.woff) format('woff');
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Roboto Mono';
font-style: normal;
font-weight: 400;
src: url(Roboto_Mono-normal-400.woff) format('woff');
unicode-range: U+0-10FFFF;
}

View File

@ -0,0 +1,233 @@
@font-face {
font-family: 'Fujicons';
font-style: normal;
font-weight: 400;
src: url(fujicons.ttf) format('truetype');
unicode-range: U+0-10FFFF;
}
.fa {
display: inline-block;
font: normal normal normal 14px/1 Fujicons;
font-size: inherit;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.fa-xs {
font-size: .75em; }
.fa-sm {
font-size: .875em; }
/* makes the font 33% larger relative to the icon container */
.fa-lg {
font-size: 1.33333333em;
line-height: 0.75em;
vertical-align: -15%;
}
.fa-2x {
font-size: 2em;
}
.fa-3x {
font-size: 3em;
}
.fa-4x {
font-size: 4em;
}
.fa-5x {
font-size: 5em;
}
.fa-fw {
width: 1.28571429em;
text-align: center;
}
.fa-ul {
padding-left: 0;
margin-left: 2.14285714em;
list-style-type: none;
}
.fa-ul > li {
position: relative;
}
.fa-li {
position: absolute;
left: -2.14285714em;
width: 2.14285714em;
top: 0.14285714em;
text-align: center;
}
.fa-li.fa-lg {
left: -1.85714286em;
}
.fa-border {
padding: .2em .25em .15em;
border: solid 0.08em #eeeeee;
border-radius: .1em;
}
.fa-pull-left {
float: left;
}
.fa-pull-right {
float: right;
}
.fa.fa-pull-left {
margin-right: .3em;
}
.fa.fa-pull-right {
margin-left: .3em;
}
/* Deprecated as of 4.4.0 */
.pull-right {
float: right;
}
.pull-left {
float: left;
}
.fa.pull-left {
margin-right: .3em;
}
.fa.pull-right {
margin-left: .3em;
}
.fa-spin {
-webkit-animation: fa-spin 2s infinite linear;
animation: fa-spin 2s infinite linear;
}
.fa-pulse {
-webkit-animation: fa-spin 1s infinite steps(8);
animation: fa-spin 1s infinite steps(8);
}
@-webkit-keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
@keyframes fa-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
.fa-rotate-90 {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";
-webkit-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg);
}
.fa-rotate-180 {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";
-webkit-transform: rotate(180deg);
-ms-transform: rotate(180deg);
transform: rotate(180deg);
}
.fa-rotate-270 {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";
-webkit-transform: rotate(270deg);
-ms-transform: rotate(270deg);
transform: rotate(270deg);
}
.fa-flip-horizontal {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";
-webkit-transform: scale(-1, 1);
-ms-transform: scale(-1, 1);
transform: scale(-1, 1);
}
.fa-flip-vertical {
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";
-webkit-transform: scale(1, -1);
-ms-transform: scale(1, -1);
transform: scale(1, -1);
}
:root .fa-rotate-90,
:root .fa-rotate-180,
:root .fa-rotate-270,
:root .fa-flip-horizontal,
:root .fa-flip-vertical {
filter: none;
}
.fa-stack {
position: relative;
display: inline-block;
width: 2em;
height: 2em;
line-height: 2em;
vertical-align: middle;
}
.fa-stack-1x,
.fa-stack-2x {
position: absolute;
left: 0;
width: 100%;
text-align: center;
}
.fa-stack-1x {
line-height: inherit;
}
.fa-stack-2x {
font-size: 2em;
}
.fa-inverse {
color: #ffffff;
}
.fa-back:before {
content: "";
}
.fa-forward:before {
content: "";
}
.fa-globe:before {
content: "\EA12"
}
.fa-up:before {
content: "\E925"
}
.fa-down:before {
content: "\E922"
}
.fa-work:before {
content: "\E998"
}
.fa-home:before {
content: "\EA1E"
}
.fa-location-arrow:before {
content: "\EA76"
}
.fa-map-marker:before {
content: "\EA3D"
}
.fa-map-marker-hollow:before {
content: "\EA3E"
}
.fa-direction-filled:before {
content: "\E9D6"
}
.fa-direction-hollow:before {
content: "\E9D7"
}

BIN
pb_public/fonts/fujicons.ttf Executable file

Binary file not shown.

View File

@ -0,0 +1,39 @@
@font-face {
font-family: 'Gotham';
font-style: normal;
font-weight: 400;
src: url(GothamSSm-Book.otf) format('opentype');
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Gotham Light';
font-style: normal;
font-weight: 400;
src: url(GothamSSm-Light.otf) format('opentype');
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Gotham Medium';
font-style: normal;
font-weight: 400;
src: url(GothamSSm-Medium.otf) format('opentype');
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Gotham Bold';
font-style: normal;
font-weight: 400;
src: url(GothamSSm-Bold.otf) format('opentype');
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Gotham Black';
font-style: normal;
font-weight: 400;
src: url(GothamSSm-Black.otf) format('opentype');
unicode-range: U+0-10FFFF;
}

BIN
pb_public/gfx/bg_evening.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
pb_public/gfx/bg_morning.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
pb_public/gfx/clear_d.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
pb_public/gfx/clear_n.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
pb_public/gfx/cloudy_d.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
pb_public/gfx/cloudy_n.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
pb_public/gfx/foggy_d.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
pb_public/gfx/foggy_n.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
pb_public/gfx/rain_d.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

BIN
pb_public/gfx/rain_n.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

BIN
pb_public/gfx/snow_d.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

BIN
pb_public/gfx/snow_n.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
pb_public/gfx/stars_00.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
pb_public/gfx/stars_10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
pb_public/gfx/stars_15.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
pb_public/gfx/stars_20.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
pb_public/gfx/stars_25.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
pb_public/gfx/stars_30.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
pb_public/gfx/stars_35.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
pb_public/gfx/stars_40.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
pb_public/gfx/stars_45.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
pb_public/gfx/stars_50.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
pb_public/gfx/storm_d.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
pb_public/gfx/storm_n.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
pb_public/gfx/yelp_logo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
pb_public/gfx/yssdk_yelp_logo.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 447 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/mstile-150x150.png"/>
<TileColor>#da532c</TileColor>
</tile>
</msapplication>
</browserconfig>

Binary file not shown.

After

Width:  |  Height:  |  Size: 739 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
pb_public/img/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -0,0 +1,372 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.11, written by Peter Selinger 2001-2013
</metadata>
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M3195 4394 c-165 -80 -361 -175 -435 -211 -74 -36 -198 -96 -275
-133 -77 -37 -243 -118 -370 -180 -126 -62 -250 -121 -274 -131 -71 -31 -141
-81 -147 -105 -3 -12 0 -41 6 -64 20 -76 6 -127 -54 -190 -29 -30 -70 -80 -93
-110 -50 -68 -143 -241 -143 -266 0 -11 13 -58 29 -106 59 -172 78 -340 46
-402 -8 -15 -15 -36 -15 -47 0 -10 -19 -46 -43 -81 -24 -35 -53 -85 -66 -113
-37 -78 -120 -341 -132 -414 -20 -129 -42 -206 -65 -234 -13 -16 -24 -41 -24
-57 0 -39 -59 -111 -159 -194 -59 -48 -83 -75 -88 -96 -4 -24 -23 -41 -93 -85
-75 -47 -89 -60 -94 -88 -13 -67 60 -201 139 -258 25 -18 45 -36 45 -41 0 -16
-142 -293 -219 -426 -96 -169 -108 -190 -160 -284 l-42 -78 25 0 c28 0 26 -3
111 150 33 58 81 143 108 190 64 111 317 624 317 643 0 7 8 22 19 31 17 16 23
16 87 1 114 -26 160 -43 255 -98 102 -58 172 -126 189 -184 14 -46 15 -43
-116 -349 -93 -218 -155 -377 -149 -383 9 -9 22 13 51 88 33 85 44 83 14 -4
-24 -69 -25 -85 -6 -85 16 0 22 14 70 165 20 61 48 146 64 190 15 44 34 103
42 130 7 28 27 80 43 117 26 59 32 67 52 62 12 -3 26 1 33 8 11 14 15 27 52
187 11 47 27 92 36 102 8 9 30 67 49 128 21 70 42 121 58 138 14 16 36 40 49
55 13 14 48 36 77 47 l53 20 -6 -22 c-49 -173 -43 -336 17 -404 36 -41 95 -73
136 -73 78 0 204 72 328 187 74 69 113 119 113 147 0 11 17 54 39 95 21 42 46
97 56 124 20 52 25 55 47 30 14 -16 15 -38 6 -168 -11 -177 -44 -316 -83 -353
-33 -30 -34 -55 -2 -43 12 5 54 15 92 22 39 6 85 18 104 26 21 9 48 12 70 8
32 -5 45 0 100 36 35 23 81 60 102 81 l39 40 0 -29 c0 -15 -7 -59 -15 -97 -8
-38 -12 -73 -9 -78 3 -4 -10 -30 -29 -56 -37 -49 -49 -55 -229 -103 -38 -10
-61 -35 -210 -223 -42 -53 -73 -83 -97 -93 -55 -21 -66 -29 -70 -49 -6 -34
-34 -56 -128 -100 -57 -27 -94 -50 -97 -62 -6 -18 -40 -40 -229 -148 l-69 -39
40 -3 c30 -2 52 4 88 26 27 16 79 46 116 66 37 20 76 48 88 63 11 15 62 48
113 74 73 37 94 53 102 76 5 15 10 29 11 31 5 8 44 -24 40 -33 -2 -5 27 -20
65 -31 71 -22 99 -16 32 7 -32 10 -35 13 -18 19 18 7 18 9 -8 19 -15 6 -39 14
-52 17 -31 8 -32 20 -2 28 25 7 70 44 80 66 4 8 42 60 85 115 54 69 91 107
120 122 43 23 161 58 168 50 2 -2 -9 -21 -24 -43 -59 -82 -184 -267 -273 -405
-150 -234 -170 -269 -155 -269 8 0 40 44 72 97 32 54 88 144 126 201 37 57 68
106 68 108 0 7 165 243 191 274 l21 25 -16 -27 c-19 -32 -20 -52 -5 -76 9 -14
7 -25 -9 -52 -11 -19 -36 -64 -57 -100 -20 -36 -42 -72 -49 -80 -14 -17 -56
-89 -56 -96 0 -3 5 -2 12 2 7 4 8 3 4 -5 -4 -6 -11 -9 -16 -6 -7 4 -33 -33
-115 -165 -45 -73 -55 -89 -55 -95 0 -14 61 -1 172 35 68 23 188 54 268 70
158 33 206 44 233 55 21 9 22 -4 3 -71 -26 -93 -26 -94 -2 -94 20 0 24 11 50
128 15 70 32 131 37 137 5 5 9 17 9 26 0 42 146 477 180 537 5 9 24 53 41 97
17 44 39 96 50 115 10 19 32 73 49 119 16 46 40 98 53 115 24 32 147 250 147
260 0 11 190 297 228 345 119 148 280 336 343 401 105 108 372 356 398 369 19
11 21 9 21 -17 0 -58 -21 -90 -123 -182 -130 -120 -312 -302 -359 -360 -240
-298 -381 -497 -523 -735 -26 -44 -53 -87 -61 -95 -18 -21 -130 -249 -229
-466 -59 -130 -186 -465 -205 -541 -16 -67 7 -30 37 59 79 233 162 435 279
678 82 169 123 243 223 401 20 31 63 100 96 152 33 53 63 96 68 96 4 1 7 -12
7 -28 0 -17 4 -33 10 -36 6 -4 8 10 4 39 -6 40 -3 51 26 96 46 71 126 170 133
164 3 -4 12 9 20 27 20 46 62 100 71 91 4 -4 6 0 4 8 -1 8 3 14 10 12 6 -1 11
4 10 10 -2 7 2 12 9 11 7 -2 21 11 33 27 29 40 40 38 33 -7 -4 -24 -3 -34 4
-30 15 9 22 66 9 71 -7 3 -6 5 2 5 6 1 12 7 12 15 0 7 37 46 82 87 71 64 80
70 75 46 -4 -15 -10 -39 -13 -54 -11 -53 22 2 35 59 10 40 21 60 48 83 l36 30
-5 -25 c-3 -14 -16 -75 -28 -137 l-23 -111 -45 -17 c-52 -21 -177 -102 -224
-148 -18 -17 -60 -58 -93 -89 -95 -90 -204 -256 -232 -353 -7 -22 -15 -71 -19
-110 -6 -58 -13 -77 -39 -110 -52 -65 -229 -368 -310 -530 -108 -217 -219
-491 -261 -643 -8 -30 -19 -62 -24 -73 -8 -15 -7 -19 4 -19 10 0 21 20 32 57
9 32 20 65 24 73 4 8 15 38 23 65 39 131 129 349 220 532 71 144 74 126 5 -27
-51 -112 -228 -649 -228 -691 0 -6 10 -9 22 -7 15 2 26 16 38 48 31 87 162
359 236 491 l53 95 128 -17 c139 -20 508 -43 523 -34 6 4 10 -3 10 -14 0 -23
-19 -28 -38 -9 -9 9 -12 9 -12 0 0 -8 -25 -11 -82 -11 -46 0 -94 -5 -108 -11
l-25 -10 25 4 c14 3 76 6 137 7 85 1 118 -2 135 -13 37 -25 138 -130 138 -145
0 -34 -93 -63 -272 -83 -51 -6 -151 -20 -223 -30 -101 -16 -393 -50 -422 -50
-3 0 -2 8 1 18 4 9 -9 -1 -28 -23 -20 -22 -35 -45 -36 -51 0 -19 -70 -75 -88
-72 -20 4 -54 -54 -46 -77 9 -23 49 -18 62 8 22 42 52 91 83 137 l32 46 81 3
c44 1 110 6 146 11 107 16 158 12 214 -14 28 -13 98 -41 156 -61 100 -35 114
-37 299 -47 150 -7 205 -14 243 -29 27 -10 51 -19 53 -19 3 0 5 123 5 273 l0
274 -40 12 c-22 6 -40 16 -40 20 0 5 -12 12 -27 15 -38 9 -214 79 -210 83 2 2
30 -6 63 -17 93 -31 87 -24 -27 33 -185 93 -360 230 -435 340 -14 21 -42 73
-62 114 -34 74 -36 81 -36 187 0 109 1 113 39 188 39 79 160 239 194 258 11 5
29 26 41 46 31 49 141 138 217 176 46 22 86 33 150 40 169 18 177 19 162 29
-10 6 -10 9 -1 9 6 0 12 7 12 15 0 18 -13 19 -60 5 -19 -6 -60 -14 -90 -19
-30 -5 -64 -13 -74 -17 -15 -6 -18 -4 -13 8 3 9 18 74 32 144 29 137 53 194
91 214 17 10 25 25 30 59 4 25 13 63 20 85 8 21 14 50 14 63 0 22 -3 24 -25
19 -33 -8 -33 10 0 36 25 19 65 86 65 108 0 6 -12 3 -27 -8 -46 -32 -129 -47
-258 -46 -103 0 -195 14 -195 29 0 3 41 44 91 92 50 48 105 108 122 133 39 56
55 74 98 107 31 23 28 25 -15 7 -9 -3 -15 5 -19 25 -10 47 14 109 75 199 17
24 27 46 24 49 -3 3 -25 -3 -48 -14 -62 -29 -173 -49 -183 -33 -3 6 23 41 59
79 61 65 73 81 62 81 -2 0 -27 -20 -55 -43 -39 -34 -74 -51 -149 -75 -106 -35
-213 -49 -252 -34 -24 9 -23 10 23 30 26 11 47 25 47 30 0 6 22 26 48 45 85
61 222 269 209 318 -3 11 1 36 9 56 25 58 11 46 -24 -21 -37 -71 -107 -148
-207 -228 -79 -63 -129 -90 -196 -106 -50 -12 -123 -1 -84 13 157 56 308 185
371 318 30 63 79 225 71 234 -2 1 -18 -19 -37 -44 -42 -57 -138 -107 -231
-122 -35 -6 -64 -9 -66 -7 -2 2 19 34 47 71 49 63 61 96 23 63 -10 -9 -29 -18
-43 -21 -14 -3 -56 -15 -95 -26 -103 -31 -317 -30 -394 2 -54 22 -55 22 -225
276 -94 140 -175 256 -181 258 -5 1 -145 -63 -310 -143z m389 -148 c20 -55 41
-105 45 -110 11 -13 61 -144 61 -159 0 -6 -6 -3 -12 6 -18 24 -219 62 -256 48
-16 -5 -20 -10 -10 -10 12 -1 15 -7 11 -23 -8 -32 -24 -50 -38 -44 -7 2 -21
-11 -31 -30 -10 -19 -25 -34 -34 -35 -35 -2 79 -25 118 -24 23 1 42 -2 42 -7
0 -4 6 -8 14 -8 8 0 18 -4 21 -10 4 -6 -2 -7 -17 -1 -13 5 -41 6 -63 2 l-40
-7 57 -8 c32 -4 60 -11 63 -16 3 -4 21 -11 40 -14 19 -4 35 -11 35 -15 0 -4
-39 -27 -87 -50 -49 -22 -95 -46 -103 -51 -8 -5 -37 -20 -65 -32 -27 -12 -74
-34 -104 -49 l-53 -27 -102 24 c-55 13 -137 35 -181 48 -117 36 -163 41 -70 8
72 -26 80 -31 78 -53 -1 -20 9 -30 60 -57 52 -27 64 -30 73 -18 5 8 16 11 22
7 9 -5 4 -11 -13 -19 -21 -10 -30 -9 -48 2 -49 32 -198 86 -236 86 -52 0 -62
-16 -91 -140 -26 -115 -36 -140 -52 -139 -10 0 -10 2 0 6 6 2 12 13 12 24 0
10 -6 19 -12 20 -10 0 -10 2 0 6 6 2 12 14 12 24 0 11 4 18 9 15 15 -9 20 46
6 61 -18 18 -28 16 -21 -3 5 -13 1 -15 -20 -11 -17 3 -29 -1 -36 -13 -7 -10
-18 -16 -25 -13 -7 3 -13 0 -13 -6 0 -6 -19 -11 -45 -11 -25 0 -45 -4 -45 -10
0 -5 -4 -10 -10 -10 -5 0 -10 8 -10 17 0 16 -1 16 -12 0 -9 -11 -32 -17 -78
-18 -69 -3 -110 11 -110 38 0 12 -3 13 -14 4 -11 -9 -15 -9 -19 1 -4 9 -6 8
-6 -3 -1 -26 -45 -19 -49 9 -3 17 -10 22 -31 22 -15 0 -32 5 -38 11 -6 6 -23
12 -38 14 -28 3 -45 21 -55 60 -5 17 -13 20 -57 17 -33 -3 -62 2 -83 13 -38
19 -35 30 4 15 25 -9 27 -8 21 11 -5 15 -3 20 6 17 8 -3 15 -14 17 -26 3 -22
13 -28 25 -16 3 3 1 14 -5 24 -12 19 -4 55 11 46 5 -4 11 -3 13 2 1 4 31 22
66 40 93 50 148 82 139 82 -4 0 -49 -21 -100 -48 -51 -26 -125 -62 -165 -81
-40 -19 -74 -37 -76 -40 -4 -6 55 -271 73 -331 6 -19 23 -91 37 -160 14 -69
32 -142 39 -162 9 -28 10 -41 1 -53 -9 -13 -19 10 -53 117 -22 73 -55 189 -72
258 -17 69 -42 166 -55 215 -36 130 -32 162 23 180 13 4 63 27 110 50 93 46
369 181 601 293 80 38 219 106 310 150 227 110 414 199 485 232 33 16 93 44
134 63 l74 35 28 -77 c15 -42 43 -121 63 -175z m-174 -356 c0 -5 -4 -10 -10
-10 -5 0 -10 5 -10 10 0 6 5 10 10 10 6 0 10 -4 10 -10z m330 -36 c0 -8 -4
-14 -9 -14 -6 0 -9 9 -8 19 1 22 17 18 17 -5z m-200 -4 c0 -5 -2 -10 -4 -10
-3 0 -8 5 -11 10 -3 6 -1 10 4 10 6 0 11 -4 11 -10z m155 -23 c-11 -6 -22 -12
-25 -12 -3 0 -11 -4 -18 -9 -7 -4 -15 -6 -18 -3 -5 5 56 37 71 36 6 0 1 -5
-10 -12z m-555 -272 c-14 -8 -29 -14 -35 -14 -5 0 1 6 15 14 14 8 30 14 35 14
6 0 -1 -6 -15 -14z m224 -36 l46 -31 -57 -28 c-32 -15 -73 -39 -91 -54 -29
-25 -35 -27 -64 -17 -55 19 -108 45 -108 51 0 4 17 12 38 19 20 6 69 29 107
50 39 21 73 39 76 40 3 0 27 -13 53 -30z m-484 -4 c14 -7 41 -16 60 -20 19 -4
44 -14 55 -21 11 -8 26 -14 35 -14 8 0 20 -10 25 -22 7 -16 33 -31 83 -49 40
-15 79 -33 87 -39 9 -7 25 -14 38 -16 12 -1 50 -9 84 -17 34 -8 64 -13 67 -10
7 7 69 -18 78 -31 5 -7 8 -5 8 4 0 13 2 13 10 0 7 -11 0 -17 -32 -28 -36 -12
-41 -12 -52 4 -12 16 -14 15 -19 -8 -4 -14 -25 -37 -47 -52 -45 -29 -100 -108
-100 -140 1 -17 5 -14 21 14 l20 35 -5 -35 c-3 -19 -8 -54 -12 -76 -3 -23 -2
-50 3 -59 8 -14 13 -9 24 30 29 100 133 177 239 178 68 1 111 -20 145 -72 37
-56 42 -102 16 -147 -12 -20 -20 -38 -18 -40 2 -2 15 2 30 9 19 8 25 17 21 30
-4 13 0 20 15 24 24 6 25 8 11 33 -8 15 -6 21 7 29 17 10 17 10 1 11 -25 0
-42 68 -23 90 19 21 19 30 1 30 -24 0 -29 20 -10 41 22 25 14 32 -20 19 -43
-16 -53 -11 -26 11 24 20 24 20 3 14 -14 -4 -23 -2 -23 4 0 6 -12 11 -26 11
-16 0 -24 5 -22 13 5 14 48 23 48 10 0 -5 28 -7 63 -5 52 3 66 0 85 -16 13
-12 53 -31 88 -44 35 -12 64 -29 64 -36 0 -7 9 -25 19 -40 41 -57 91 -295 91
-430 0 -53 4 -81 10 -77 6 3 10 16 10 29 0 12 14 48 31 79 16 31 36 85 43 119
l13 63 12 -45 c6 -25 21 -76 32 -115 11 -38 29 -99 40 -135 24 -83 24 -121 -1
-153 -36 -46 -53 -100 -66 -217 -18 -155 -17 -288 1 -320 8 -14 14 -30 15 -35
0 -6 -42 -74 -92 -151 -51 -77 -120 -190 -153 -252 -33 -61 -82 -146 -110
-188 -42 -65 -59 -82 -107 -107 -90 -47 -159 -47 -343 -3 -82 20 -188 48 -235
62 -112 34 -281 119 -339 171 -71 63 -162 199 -247 367 -42 83 -82 158 -89
166 -7 8 -72 134 -145 280 -72 146 -136 269 -141 275 -22 23 6 277 34 300 7 6
23 34 37 64 44 95 135 138 274 129 69 -4 81 5 35 30 -16 9 -55 12 -122 10
l-98 -4 3 46 3 45 160 81 160 82 26 110 c14 61 31 118 38 126 14 17 57 13 101
-9z m605 -74 c3 -5 55 -40 116 -77 62 -38 106 -70 100 -72 -7 -2 -33 -1 -57 3
-34 5 -44 10 -40 21 7 19 -4 18 -20 -3 -13 -17 -15 -17 -27 -1 -10 12 -17 14
-24 7 -11 -11 -76 0 -196 32 l-37 10 27 22 c70 57 142 83 158 58z m-1705 -268
c0 -34 -5 -74 -11 -90 -7 -15 -15 -62 -19 -103 -11 -99 -76 -459 -85 -468 -2
-2 -13 -1 -25 3 -19 6 -21 12 -15 48 7 43 31 165 59 292 23 106 37 225 46 380
5 77 9 142 10 145 6 18 39 -157 40 -207z m383 190 c-7 -2 -21 -2 -30 0 -10 3
-4 5 12 5 17 0 24 -2 18 -5z m-479 -50 c-9 -82 -26 -207 -30 -223 -3 -12 -17
-14 -66 -12 -52 3 -61 1 -50 -10 7 -7 34 -13 62 -13 56 0 56 4 17 -115 -11
-36 -33 -114 -48 -175 -16 -64 -27 -98 -28 -80 -2 39 -24 128 -46 185 -9 25
-22 66 -28 91 -10 45 -9 49 41 142 28 52 66 115 84 139 49 63 93 118 95 118 2
0 0 -21 -3 -47z m895 -17 c-10 -9 -69 -36 -69 -32 0 7 52 35 64 36 5 0 7 -2 5
-4z m977 -43 c-10 -10 -19 5 -10 18 6 11 8 11 12 0 2 -7 1 -15 -2 -18z m-1137
-47 c-2 -2 -15 -9 -29 -15 -24 -11 -24 -11 -6 3 16 13 49 24 35 12z m-59 -30
c0 -2 -7 -7 -16 -10 -8 -3 -12 -2 -9 4 6 10 25 14 25 6z m-154 -91 c-11 -8
-25 -15 -30 -15 -6 1 0 7 14 15 32 19 40 18 16 0z m170 -51 c-4 -15 -14 -24
-26 -24 -25 0 -25 1 2 47 18 29 24 34 26 20 2 -10 1 -29 -2 -43z m-549 -6 c-3
-8 -6 -5 -6 6 -1 11 2 17 5 13 3 -3 4 -12 1 -19z m293 7 c0 -2 -13 -11 -30
-20 -38 -19 -40 -11 -2 9 31 17 32 18 32 11z m2232 -16 c16 -9 19 -19 17 -62
-2 -35 4 -70 18 -109 29 -76 39 -192 23 -268 -16 -77 -30 -96 -56 -82 -26 14
-51 130 -35 160 17 32 13 84 -9 117 -28 42 -25 65 14 132 19 32 32 60 30 62
-9 10 -64 -66 -83 -114 -20 -52 -22 -51 -40 20 -17 64 -13 106 11 132 24 25
75 31 110 12z m-2505 -131 c-2 -18 -4 -6 -4 27 0 33 2 48 4 33 2 -15 2 -42 0
-60z m464 55 c-5 -10 -17 -27 -26 -38 -16 -19 -17 -19 -3 5 26 46 29 50 34 50
3 0 0 -8 -5 -17z m-645 -60 c-18 -108 -70 -342 -82 -368 -14 -32 -4 -45 20
-26 7 6 21 9 29 5 15 -5 15 -9 1 -35 -16 -33 -18 -33 -44 -19 -18 10 -19 8
-14 -20 5 -23 0 -40 -20 -70 -14 -22 -26 -49 -26 -60 0 -26 -38 -168 -52 -198
-6 -12 -12 -37 -12 -56 -1 -19 -4 -32 -8 -29 -5 2 -8 -3 -8 -13 0 -9 -19 -71
-41 -137 -36 -103 -40 -123 -29 -140 19 -32 -26 -67 -86 -67 -24 0 -44 -4 -44
-8 0 -4 17 -6 37 -4 34 4 36 3 24 -12 -18 -21 1 -21 34 0 14 9 32 14 40 10 15
-6 13 -14 -21 -64 -2 -2 -26 1 -54 7 -55 12 -96 1 -86 -24 2 -7 -6 -22 -18
-34 l-23 -21 5 32 c3 18 15 45 27 60 16 19 28 59 44 150 21 115 103 400 139
478 8 19 35 63 59 98 24 34 53 84 63 110 25 62 86 263 100 327 27 125 62 221
46 128z m589 -11 c-6 -4 -28 -23 -50 -42 l-40 -35 40 43 c21 23 44 42 49 42 6
0 6 -3 1 -8z m-325 -70 c0 -5 -7 -17 -15 -28 -14 -18 -14 -18 -15 9 0 17 5 27
15 27 8 0 15 -4 15 -8z m200 -36 c0 -2 -8 -10 -17 -17 -16 -13 -17 -12 -4 4
13 16 21 21 21 13z m-303 -38 c-3 -7 -5 -2 -5 12 0 14 2 19 5 13 2 -7 2 -19 0
-25z m2483 -17 c0 -9 -4 -22 -9 -29 -10 -16 -21 16 -21 58 1 24 1 24 15 6 8
-11 15 -27 15 -35z m-2270 -45 c0 -2 -8 -10 -17 -17 -16 -13 -17 -12 -4 4 13
16 21 21 21 13z m2885 -49 c-22 -18 -68 -56 -103 -85 -35 -30 -85 -63 -110
-74 -26 -12 -71 -36 -100 -54 -29 -19 -55 -34 -58 -34 -3 0 -19 -9 -36 -21
-33 -24 -33 -24 -42 13 -5 22 -1 30 24 48 74 53 429 240 454 240 6 -1 -7 -15
-29 -33z m-3111 -141 c-3 -21 -8 -35 -11 -32 -2 2 -1 20 3 40 3 21 8 35 11 32
2 -2 1 -20 -3 -40z m-73 -47 c-5 -13 -10 -19 -10 -12 -1 15 10 45 15 40 3 -2
0 -15 -5 -28z m56 -21 c-3 -8 -6 -5 -6 6 -1 11 2 17 5 13 3 -3 4 -12 1 -19z
m8 -124 c-7 -12 -16 -43 -18 -70 -2 -27 -2 -22 -1 11 2 33 6 85 10 115 l7 55
8 -45 c7 -32 5 -50 -6 -66z m2803 44 c-18 -22 -45 -54 -59 -69 -15 -15 -29
-35 -32 -44 -13 -33 -28 -14 -25 32 3 52 24 70 31 26 l4 -28 8 32 c5 24 20 41
54 62 25 16 47 30 49 30 2 1 -12 -18 -30 -41z m-2674 5 c-7 -30 -24 -55 -24
-35 0 12 21 62 27 62 2 0 0 -12 -3 -27z m2359 -45 c7 -24 -8 -48 -29 -48 -15
0 -18 27 -8 54 9 23 31 20 37 -6z m-2556 -10 c-3 -8 -6 -5 -6 6 -1 11 2 17 5
13 3 -3 4 -12 1 -19z m-180 -25 c-3 -10 -5 -4 -5 12 0 17 2 24 5 18 2 -7 2
-21 0 -30z m3223 34 c0 -1 -30 -32 -67 -67 l-68 -65 65 68 c60 62 70 72 70 64z
m-2866 -22 c-4 -8 -8 -15 -10 -15 -2 0 -4 7 -4 15 0 8 4 15 10 15 5 0 7 -7 4
-15z m-74 -23 c0 -15 -2 -15 -10 -2 -13 20 -13 33 0 25 6 -3 10 -14 10 -23z
m-293 -54 c-3 -8 -6 -5 -6 6 -1 11 2 17 5 13 3 -3 4 -12 1 -19z m794 -53 c41
-14 48 -22 78 -82 l32 -66 -46 41 c-25 22 -53 42 -63 44 -26 7 -62 -9 -62 -27
0 -12 3 -13 19 -4 10 7 26 9 36 5 14 -5 15 -9 5 -21 -8 -9 -8 -15 -2 -15 6 0
12 5 14 12 3 8 15 5 40 -10 40 -25 48 -39 48 -86 0 -21 8 -40 21 -52 22 -19
22 -19 12 1 -13 27 -24 97 -14 90 12 -7 82 -127 86 -145 3 -16 78 -172 98
-205 7 -11 25 -39 40 -62 29 -44 21 -61 -9 -20 -16 21 -16 21 -12 1 3 -11 -1
-29 -8 -39 -8 -10 -14 -29 -14 -41 0 -12 -11 -29 -25 -38 -27 -18 -34 -46 -11
-46 8 0 23 -3 33 -6 16 -5 16 -4 -2 12 -16 13 -17 16 -3 11 20 -7 34 9 16 17
-9 3 -8 9 6 20 10 8 19 26 20 40 0 14 7 28 14 31 6 2 12 3 12 2 -1 -19 -44
-134 -64 -172 -34 -63 -53 -84 -26 -28 11 23 20 47 20 53 0 18 -22 11 -27 -10
-6 -24 -16 -25 -34 -4 -11 13 -10 22 8 57 42 81 39 257 -5 310 -36 41 -150 6
-205 -64 l-25 -32 -32 30 -33 31 59 56 c68 65 107 86 159 86 24 0 34 4 29 11
-4 8 -27 9 -70 5 -62 -6 -63 -6 -78 23 -9 16 -21 35 -29 43 -27 28 -47 63 -47
85 0 12 -13 38 -30 56 -34 39 -38 71 -13 99 20 22 27 22 84 3z m2243 -59 c-37
-46 -45 -37 -9 9 15 20 29 34 32 31 3 -2 -8 -20 -23 -40z m-2797 -53 c-3 -10
-5 -4 -5 12 0 17 2 24 5 18 2 -7 2 -21 0 -30z m-50 -220 c-3 -10 -5 -4 -5 12
0 17 2 24 5 18 2 -7 2 -21 0 -30z m10 -75 c-3 -8 -6 -5 -6 6 -1 11 2 17 5 13
3 -3 4 -12 1 -19z m802 -74 c11 -14 23 -40 26 -58 6 -33 -17 -162 -32 -177
-12 -12 -153 154 -153 179 0 21 21 42 65 65 43 23 71 21 94 -9z m-1135 -5 c-3
-5 -10 -7 -15 -3 -5 3 -7 10 -3 15 3 5 10 7 15 3 5 -3 7 -10 3 -15z m905 -66
c29 -38 71 -95 95 -128 23 -33 66 -93 95 -133 32 -45 44 -69 32 -63 -10 6 -21
14 -23 18 -2 5 -16 19 -32 33 -23 20 -27 21 -19 6 9 -16 6 -23 -13 -39 -13
-10 -24 -25 -24 -34 0 -12 -3 -13 -14 -4 -7 6 -21 8 -30 5 -16 -6 -16 -8 0
-25 10 -11 15 -22 12 -25 -3 -3 -19 14 -35 38 -16 24 -66 97 -111 162 -45 66
-82 125 -82 131 0 7 14 31 30 53 17 23 30 49 30 57 0 35 39 12 89 -52z m-127
35 c-7 -7 -12 -8 -12 -2 0 6 3 14 7 17 3 4 9 5 12 2 2 -3 -1 -11 -7 -17z
m-852 -91 c0 -14 -76 -124 -116 -167 -12 -14 -39 -44 -59 -67 -38 -44 -55 -47
-55 -12 0 36 30 78 84 119 30 23 59 54 66 71 15 34 4 54 -13 24 -10 -20 -23
-32 -105 -107 -30 -27 -43 -48 -49 -80 -7 -37 -13 -44 -38 -49 -25 -6 -26 -7
-7 -8 14 -1 22 -6 19 -13 -2 -9 -24 -13 -62 -13 -72 0 -83 18 -34 54 19 14 72
62 119 108 125 120 168 151 213 152 24 1 37 -4 37 -12z m843 -75 c12 -25 8
-35 -45 -137 -31 -60 -58 -105 -59 -100 -1 6 -5 -3 -9 -20 -7 -29 -8 -29 -9 9
-1 50 24 144 59 224 31 66 41 70 63 24z m67 -131 c0 -5 23 -43 50 -84 28 -41
50 -81 50 -89 0 -26 -73 -85 -120 -96 -60 -15 -73 1 -67 78 5 64 55 200 74
200 7 0 13 -4 13 -9z m230 -71 c0 -5 -4 -10 -10 -10 -5 0 -10 5 -10 10 0 6 5
10 10 10 6 0 10 -4 10 -10z m1771 -133 l11 -87 -39 -48 c-21 -26 -61 -80 -88
-121 -28 -40 -56 -76 -62 -78 -7 -3 -13 -13 -13 -22 -1 -9 -11 -34 -24 -56
-20 -34 -28 -40 -55 -38 -18 0 -34 3 -37 6 -12 11 140 326 235 487 45 77 56
90 58 70 2 -14 8 -64 14 -113z m-3128 108 c0 -6 -7 -11 -16 -13 -12 -3 -15 1
-11 13 7 17 25 17 27 0z m-100 -36 c-12 -12 -103 -21 -103 -10 0 16 15 21 64
21 35 0 47 -3 39 -11z m81 -5 c26 -10 18 -24 -13 -24 -30 0 -46 12 -34 24 8 8
27 8 47 0z m1320 -8 c-3 -8 -1 -17 5 -21 6 -3 11 -11 11 -18 0 -15 -29 25 -30
41 0 6 4 12 10 12 5 0 7 -6 4 -14z m1958 -220 c64 -73 297 -263 372 -303 l61
-32 -40 5 c-22 3 -61 12 -87 20 -25 8 -53 11 -61 8 -28 -10 -361 73 -460 115
l-47 20 47 73 c26 40 60 90 77 111 l30 38 29 -57 c40 -79 163 -198 265 -258
30 -18 7 6 -50 52 -136 109 -200 192 -232 301 -25 84 -18 92 17 24 18 -34 53
-87 79 -117z m11 65 c-2 -6 1 -11 5 -11 5 0 9 -7 9 -17 0 -13 -4 -11 -19 7
-21 26 -24 44 -5 37 6 -2 11 -10 10 -16z m-648 -26 c-7 -16 -27 -61 -45 -99
l-32 -69 -18 41 c-11 23 -30 57 -43 75 -13 17 -32 44 -42 60 l-18 27 106 -2
105 -2 -13 -31z m-445 -40 c-17 -25 -33 -45 -36 -45 -3 0 9 20 26 45 17 25 33
45 36 45 3 0 -9 -20 -26 -45z m-80 -114 c0 -12 -41 -63 -47 -57 -4 4 37 66 44
66 2 0 3 -4 3 -9z m1505 -73 c39 -21 67 -38 62 -38 -15 0 -142 68 -167 90
l-25 22 30 -18 c17 -10 62 -35 100 -56z m-1555 -2 c0 -3 -4 -8 -10 -11 -5 -3
-10 -1 -10 4 0 6 5 11 10 11 6 0 10 -2 10 -4z m-30 -36 c0 -5 -5 -10 -11 -10
-5 0 -7 5 -4 10 3 6 8 10 11 10 2 0 4 -4 4 -10z m1180 -65 c52 -13 104 -26
115 -29 11 -3 -44 -3 -122 0 -132 4 -250 17 -261 28 -2 3 6 21 17 40 l22 35
67 -25 c37 -14 110 -36 162 -49z m-348 -25 c30 0 30 0 15 -24 -42 -64 -167
-305 -167 -323 0 -6 -4 -14 -9 -18 -11 -6 20 96 79 263 25 68 46 119 48 113 2
-6 17 -11 34 -11z m-689 -33 c39 -4 97 -4 128 0 58 6 134 -2 156 -15 9 -6 4
-33 -21 -107 -18 -55 -45 -146 -61 -202 l-28 -101 -86 -12 c-100 -14 -304 -56
-341 -70 -14 -5 -59 -19 -100 -31 -41 -11 -81 -26 -88 -31 -9 -8 -11 -6 -5 9
17 42 193 335 219 364 15 17 110 37 344 75 102 16 153 34 97 34 -46 0 -239
-29 -322 -49 -44 -11 -81 -18 -83 -16 -5 5 13 38 67 124 34 54 47 68 49 54 3
-17 13 -21 75 -26z m-158 -47 c-9 -16 -18 -30 -21 -30 -2 0 2 14 11 30 9 17
18 30 21 30 2 0 -2 -13 -11 -30z m1248 -327 c-7 -2 -19 -2 -25 0 -7 3 -2 5 12
5 14 0 19 -2 13 -5z m-543 -153 c0 -5 -2 -10 -4 -10 -3 0 -8 5 -11 10 -3 6 -1
10 4 10 6 0 11 -4 11 -10z"/>
<path d="M3420 4420 c-19 -11 -28 -19 -20 -20 9 0 26 7 38 16 12 8 27 12 32 9
6 -3 10 -1 10 4 0 16 -20 13 -60 -9z"/>
<path d="M3184 4304 c-18 -14 -18 -14 6 -3 31 14 36 19 24 19 -6 0 -19 -7 -30
-16z"/>
<path d="M3530 4296 c0 -2 7 -7 16 -10 8 -3 12 -2 9 4 -6 10 -25 14 -25 6z"/>
<path d="M3408 4258 c5 -5 16 -8 23 -6 8 3 3 7 -10 11 -17 4 -21 3 -13 -5z"/>
<path d="M3546 4251 c-4 -7 -5 -15 -2 -18 9 -9 19 4 14 18 -4 11 -6 11 -12 0z"/>
<path d="M3118 4203 c12 -2 32 -2 45 0 12 2 2 4 -23 4 -25 0 -35 -2 -22 -4z"/>
<path d="M3203 4193 c9 -2 25 -2 35 0 9 3 1 5 -18 5 -19 0 -27 -2 -17 -5z"/>
<path d="M3340 4175 c83 -13 168 -19 159 -11 -5 5 -88 15 -174 20 l-70 5 85
-14z"/>
<path d="M3575 4150 c-3 -5 -1 -10 4 -10 6 0 11 5 11 10 0 6 -2 10 -4 10 -3 0
-8 -4 -11 -10z"/>
<path d="M3178 4053 c7 -3 16 -2 19 1 4 3 -2 6 -13 5 -11 0 -14 -3 -6 -6z"/>
<path d="M3268 4043 c7 -3 16 -2 19 1 4 3 -2 6 -13 5 -11 0 -14 -3 -6 -6z"/>
<path d="M3303 4025 c0 -8 4 -15 9 -15 4 0 8 4 8 9 0 6 13 6 33 1 29 -9 30 -8
13 5 -26 20 -63 19 -63 0z"/>
<path d="M2978 3943 c6 -2 18 -2 25 0 6 3 1 5 -13 5 -14 0 -19 -2 -12 -5z"/>
<path d="M3045 3930 c17 -4 44 -8 60 -8 25 0 24 2 -10 9 -51 10 -92 10 -50 -1z"/>
<path d="M3155 3910 c27 -12 43 -12 25 0 -8 5 -22 9 -30 9 -10 0 -8 -3 5 -9z"/>
<path d="M3235 3898 c22 -6 44 -16 48 -22 5 -7 7 -4 5 8 -2 15 -13 20 -48 22
l-45 3 40 -11z"/>
<path d="M3368 3843 c7 -3 16 -2 19 1 4 3 -2 6 -13 5 -11 0 -14 -3 -6 -6z"/>
<path d="M2638 3703 c7 -3 16 -2 19 1 4 3 -2 6 -13 5 -11 0 -14 -3 -6 -6z"/>
<path d="M2685 3690 c11 -5 29 -8 40 -8 16 0 15 2 -5 8 -34 11 -60 11 -35 0z"/>
<path d="M1950 3646 c0 -2 7 -7 16 -10 8 -3 12 -2 9 4 -6 10 -25 14 -25 6z"/>
<path d="M2020 3531 c0 -6 4 -13 10 -16 6 -3 7 1 4 9 -7 18 -14 21 -14 7z"/>
<path d="M2620 3529 c0 -5 5 -7 10 -4 6 3 10 8 10 11 0 2 -4 4 -10 4 -5 0 -10
-5 -10 -11z"/>
<path d="M3199 3292 c-6 -21 -9 -49 -7 -62 3 -23 6 -20 35 27 31 50 32 53 13
63 -27 14 -28 14 -41 -28z"/>
<path d="M3456 2997 c-49 -49 -23 -147 43 -162 66 -14 111 25 111 98 0 44 -35
77 -88 84 -34 5 -45 1 -66 -20z m100 -12 c4 -8 3 -23 -2 -32 -4 -10 -6 -22 -5
-26 0 -4 -12 -1 -29 8 -16 9 -30 21 -30 28 0 33 55 51 66 22z"/>
<path d="M3690 2850 c0 -5 5 -10 11 -10 5 0 7 5 4 10 -3 6 -8 10 -11 10 -2 0
-4 -4 -4 -10z"/>
<path d="M2582 2805 c-23 -7 -53 -20 -65 -28 -29 -19 -58 -24 -74 -14 -7 5
-13 4 -13 0 0 -5 6 -15 13 -22 10 -10 7 -16 -13 -32 -14 -10 -30 -23 -36 -28
-5 -4 -26 -6 -45 -4 -32 4 -33 3 -15 -11 11 -9 28 -16 39 -16 10 0 15 -4 12
-10 -3 -5 -26 -10 -51 -10 -28 0 -43 -4 -39 -10 3 -5 17 -10 31 -10 30 0 31
-15 2 -25 -21 -6 -21 -7 10 -16 40 -12 38 -29 -6 -48 -41 -19 -41 -32 1 -24
29 6 31 5 18 -10 -15 -19 -1 -23 17 -5 6 6 15 9 19 5 3 -4 -3 -16 -15 -27 -30
-28 -28 -42 3 -30 28 11 39 0 30 -30 -6 -18 -3 -19 25 -14 24 5 36 2 55 -16
14 -13 25 -30 25 -37 0 -8 5 -11 12 -7 6 4 17 -1 24 -11 11 -15 16 -16 29 -5
12 10 18 10 30 0 12 -10 18 -8 34 11 l19 24 -40 3 c-50 4 -82 24 -119 76 -54
74 -36 161 49 238 60 53 117 72 195 62 l52 -6 -29 21 c-17 11 -51 25 -78 31
-55 14 -63 30 -15 31 30 1 31 1 7 9 -35 11 -49 11 -98 -5z"/>
<path d="M2684 2617 c-23 -20 -29 -32 -28 -66 1 -22 9 -52 17 -65 34 -52 136
-41 156 16 17 47 14 65 -16 98 -40 43 -90 50 -129 17z m80 -3 c18 -7 22 -54 5
-54 -5 0 -7 -5 -4 -10 4 -6 -5 -5 -19 2 -28 12 -36 52 -13 61 6 3 13 6 14 6 1
1 8 -2 17 -5z"/>
<path d="M3444 2382 c4 -6 2 -30 -4 -52 -12 -43 -3 -79 11 -44 12 30 10 92 -3
100 -7 4 -8 3 -4 -4z"/>
<path d="M2671 2324 c0 -11 3 -14 6 -6 3 7 2 16 -1 19 -3 4 -6 -2 -5 -13z"/>
<path d="M3335 2316 c-10 -14 -21 -23 -26 -20 -15 9 -10 -13 7 -27 8 -7 13
-21 11 -31 -3 -10 -1 -18 4 -18 5 0 9 16 9 35 0 33 2 35 33 33 28 -3 32 0 32
22 0 37 -47 41 -70 6z"/>
<path d="M3050 2273 c0 -21 43 -74 70 -88 44 -23 47 -13 5 16 -19 13 -35 27
-35 31 0 20 122 -28 141 -55 9 -13 32 21 25 38 -9 25 -76 48 -133 47 -29 0
-53 4 -53 9 0 5 -4 9 -10 9 -5 0 -10 -3 -10 -7z"/>
<path d="M3425 2090 c-92 -22 -187 -92 -227 -167 -32 -57 -44 -141 -30 -198
38 -150 100 -234 217 -289 68 -32 84 -36 160 -36 51 0 97 6 117 14 18 8 49 20
68 27 19 7 59 38 90 69 74 74 102 152 101 275 -1 93 -6 108 -57 171 -39 49
-172 119 -253 134 -61 11 -142 11 -186 0z m144 -96 c17 -4 31 -11 31 -15 0 -5
-40 -36 -90 -68 -85 -56 -151 -81 -215 -81 -30 0 -31 13 -6 54 51 82 175 131
280 110z m296 -254 c0 -22 -39 -19 -43 3 -3 15 1 18 20 15 12 -2 23 -10 23
-18z m-85 -26 c0 -11 -23 -50 -53 -87 -50 -64 -23 -52 38 17 31 36 61 63 66
60 31 -18 -29 -109 -109 -167 -67 -48 -123 -65 -218 -68 -64 -2 -80 1 -82 13
-2 11 8 18 35 23 34 7 36 8 16 16 -36 13 -25 39 20 46 10 2 33 14 50 27 18 13
66 40 108 60 42 20 82 43 89 51 12 14 40 21 40 9z"/>
<path d="M4381 2664 c0 -11 3 -14 6 -6 3 7 2 16 -1 19 -3 4 -6 -2 -5 -13z"/>
<path d="M2330 1941 c0 -5 5 -13 10 -16 6 -3 10 -2 10 4 0 5 -4 13 -10 16 -5
3 -10 2 -10 -4z"/>
<path d="M2570 1360 c0 -5 7 -10 16 -10 8 0 12 5 9 10 -3 6 -10 10 -16 10 -5
0 -9 -4 -9 -10z"/>
<path d="M2086 1274 c-4 -14 -5 -28 -3 -31 3 -2 8 8 11 23 4 14 5 28 3 31 -3
2 -8 -8 -11 -23z"/>
<path d="M4590 680 c0 -5 5 -10 11 -10 5 0 7 5 4 10 -3 6 -8 10 -11 10 -2 0
-4 -4 -4 -10z"/>
<path d="M4420 1850 c0 -5 5 -10 10 -10 6 0 10 5 10 10 0 6 -4 10 -10 10 -5 0
-10 -4 -10 -10z"/>
<path d="M4472 1585 c0 -16 2 -22 5 -12 2 9 2 23 0 30 -3 6 -5 -1 -5 -18z"/>
<path d="M4473 1455 c0 -22 2 -30 4 -17 2 12 2 30 0 40 -3 9 -5 -1 -4 -23z"/>
<path d="M4481 1370 c0 -8 4 -24 9 -35 5 -13 9 -14 9 -5 0 8 -4 24 -9 35 -5
13 -9 14 -9 5z"/>
<path d="M4550 1185 c0 -5 5 -17 10 -25 5 -8 10 -10 10 -5 0 6 -5 17 -10 25
-5 8 -10 11 -10 5z"/>
<path d="M4570 1131 c0 -6 4 -13 10 -16 6 -3 7 1 4 9 -7 18 -14 21 -14 7z"/>
<path d="M4645 1013 c34 -53 45 -67 45 -60 0 10 -51 87 -57 87 -3 0 3 -12 12
-27z"/>
<path d="M4238 543 c7 -3 16 -2 19 1 4 3 -2 6 -13 5 -11 0 -14 -3 -6 -6z"/>
<path d="M4338 533 c6 -2 18 -2 25 0 6 3 1 5 -13 5 -14 0 -19 -2 -12 -5z"/>
<path d="M2755 370 c39 -26 55 -26 22 0 -14 11 -31 20 -39 20 -7 0 1 -9 17
-20z"/>
<path d="M2738 293 c7 -3 16 -2 19 1 4 3 -2 6 -13 5 -11 0 -14 -3 -6 -6z"/>
<path d="M3517 180 c-3 -11 -1 -20 4 -20 5 0 9 2 9 4 0 2 3 11 6 20 3 9 2 16
-4 16 -5 0 -12 -9 -15 -20z"/>
<path d="M1705 180 c-3 -5 1 -10 9 -10 8 0 16 -6 19 -12 2 -7 3 -5 2 4 -2 9 2
19 9 22 6 2 1 5 -11 5 -12 1 -25 -3 -28 -9z"/>
<path d="M2490 177 c29 -16 124 -31 116 -18 -3 5 -25 11 -48 15 -24 4 -54 9
-68 12 l-25 5 25 -14z"/>
<path d="M2423 163 c9 -2 23 -2 30 0 6 3 -1 5 -18 5 -16 0 -22 -2 -12 -5z"/>
<path d="M1690 139 c0 -5 5 -7 10 -4 6 3 10 8 10 11 0 2 -4 4 -10 4 -5 0 -10
-5 -10 -11z"/>
<path d="M3497 109 c-7 -28 -6 -31 10 -14 6 6 8 18 3 24 -5 9 -9 5 -13 -10z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 25 KiB

119
pb_public/index.html Normal file
View File

@ -0,0 +1,119 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Jubilee</title>
<link href="//cdnjs.cloudflare.com/ajax/libs/weather-icons/2.0.9/css/weather-icons.css" rel="stylesheet" type="text/css"/>
<link href="/fonts/fonts.css" rel="stylesheet" type="text/css"/>
<link href="/fonts/fujicons.css" rel="stylesheet" type="text/css"/>
<link href="/css/mui.custom.css" rel="stylesheet" type="text/css"/>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css"
integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ=="
crossorigin=""/>
<link rel="apple-touch-icon" sizes="180x180" href="/img/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/img/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest">
<link rel="mask-icon" href="/img/safari-pinned-tab.svg" color="#5bbad5">
<meta name="apple-mobile-web-app-title" content="Train Times">
<meta name="application-name" content="Sidekick">
<meta name="theme-color" content="#ffff00">
<!-- <script src="//cdn.layerjs.org/libs/layerjs/layerjs-0.6.1.min.js"></script>
<link href="//cdn.layerjs.org/libs/layerjs/layerjs-0.6.1.css" type="text/css" rel="stylesheet" />-->
</head>
<body>
<!--
<div data-lj-type="stage">
<div data-lj-type="layer" data-lj-default-frame="main" >
<div data-lj-type="frame" >
… your HTML code …
</div>
</div>
</div>
-->
<div class="appPanel" data-id="main">
<div class="mui-container">
<div id="greet"></div>
<div id="location" class="mui-row" style="display: none;"></div>
</div>
<div class="mui-container" id="connectionStatus" style="display:none;">
<div class="mui--text-center"><i class="large fa fa-globe mui--align-middle mui--text-center"
style="color:grey;"></i></div>
<div class="mui--text-body1 mui--text-center">No internet connection</div>
</div>
<div class="mui-container" id="viewFrame">
<div id="weatherAlertShell" class="mui-panel" style="display: none;">
<div id="weatherAlertTitle" class="mui--text-title cardTitle">Weather Alert</div>
<div id="weatherAlert"></div>
</div>
<div id="bymeShell" class="mui-panel" style="display: none;">
<div id="byMeTitle" class="mui--text-title cardTitle">By me</div>
<div id="byme"></div>
</div>
<div id="trafficShell" class="mui-panel" style="display: none;">
<div class="mui--text-title cardTitle">Traffic</div>
<div id="traffic"></div>
</div>
<div id="agendaShell" class="mui-panel" style="display: none;">
<div class="mui--text-title cardTitle">Upcoming events</div>
<div id="agenda"></div>
</div>
<div id="nearbyShell" class="mui-panel" style="display: none;">
<div class="mui--text-title cardTitle">Around me</div>
<div id="nearby"></div>
</div>
<div id="nearbyShell" class="mui-panel" style="display: none;">
<div class="mui--text-title cardTitle">Nearby places</div>
<div id="nearbyPlaces"></div>
</div>
<div id="newsShell" class="mui-panel" style="display: none;">
<div class="mui--text-title cardTitle">Latest news</div>
<div id="news" class="scrolling-wrapper-flexbox"></div>
<div id='newsMore' class="cardLink">
<i class="seemore fa fa-forward mui--align-middle " ></i> <span class="seemore mui--align-middle">More news</span>
</div>
</div>
<div id="weatherShell" class="mui-panel" style="display: none;">
<div class="mui--text-title cardTitle">Weather</div>
<div id="weather"></div>
</div>
</div>
</div>
<script src="js/vendor.js" async></script>
<script type='module' src="js/bundle.js" async></script>
<script async="" src="https://cdn.ampproject.org/v0.js"></script>
<script async custom-element="amp-twitter" src="https://cdn.ampproject.org/v0/amp-twitter-0.1.js"></script>
<noscript>
<!-- anchor linking to external file -->
<h1>Javascript disabled</h1>
<p>This really requires javascript to work</p>
</noscript>
</body>
</html>

124779
pb_public/js/bundle.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
pb_public/js/vendor.js Normal file

File diff suppressed because one or more lines are too long

177
pb_public/service-worker.js Normal file
View File

@ -0,0 +1,177 @@
// Copyright 2016 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
const CACHE_VERSION = { 'version': '0.0.1049' };
const PRECACHE = `jubileeData-${CACHE_VERSION.version}`;
const RUNTIME = 'runtime';
const PRECACHE_URLS = [
'/',
'/index.html',
'/service-worker.js',
'/site.webmanifest',
'/browserconfig.xml',
'/css/mui.custom.css',
'/js/bundle.js',
'/js/vendor.js',
'/img/favicon-16x16.png',
'/img/favicon-32x32.png',
'/img/android-chrome-192x192.png',
'/img/android-chrome-512x512.png',
'/gfx/default_daily_image.jpg',
'/gfx/stars_00.png',
'/gfx/stars_10.png',
'/gfx/stars_15.png',
'/gfx/stars_20.png',
'/gfx/stars_25.png',
'/gfx/stars_30.png',
'/gfx/stars_35.png',
'/gfx/stars_40.png',
'/gfx/stars_45.png',
'/gfx/stars_50.png',
'/gfx/yssdk_yelp_logo.png',
'/gfx/bg_evening.jpg',
'/gfx/bg_morning.jpg',
'/gfx/clear_d.jpg',
'/gfx/clear_n.jpg',
'/gfx/cloudy_d.jpg',
'/gfx/cloudy_n.jpg',
'/gfx/foggy_d.jpg',
'/gfx/foggy_n.jpg',
'/gfx/rain_d.jpg',
'/gfx/rain_n.jpg',
'/gfx/snow_d.jpg',
'/gfx/snow_n.jpg',
'/gfx/storm_d.jpg',
'/gfx/storm_n.jpg',
'/fonts/fonts.css',
'/fonts/fujicons.css',
'/fonts/fujicons.ttf',
'/fonts/Roboto-italic-400.woff',
'/fonts/Roboto-italic-700.woff',
'/fonts/Roboto-normal-100.woff',
'/fonts/Roboto-normal-300.woff',
'/fonts/Roboto-normal-400.woff',
'/fonts/Roboto-normal-500.woff',
'/fonts/Roboto-normal-700.woff',
'/fonts/Roboto-normal-900.woff',
'/fonts/Roboto_Condensed-normal-300.woff',
'/fonts/Roboto_Condensed-normal-400.woff',
'/fonts/Roboto_Condensed-normal-700.woff'
];
const liveData = ['news', 'agenda'];
self.addEventListener('install', event => {
console.warn('Installing...');
event.waitUntil(
caches.open(PRECACHE)
.then(cache => cache.addAll(PRECACHE_URLS))
.then(self.skipWaiting())
);
});
// The activate handler takes care of cleaning up old caches.
self.addEventListener('activate', event => {
console.warn('Activate...');
const currentCaches = [PRECACHE, RUNTIME];
event.waitUntil(
caches.keys().then(cacheNames => {
return cacheNames.filter(cacheName => !currentCaches.includes(cacheName));
}).then(cachesToDelete => {
return Promise.all(cachesToDelete.map(cacheToDelete => {
return caches.delete(cacheToDelete);
}));
}).then(() => self.clients.claim())
);
});
// The fetch handler serves responses for same-origin resources from a cache.
// If no response is found, it populates the runtime cache with the response
// from the network before returning it to the page.
self.addEventListener('fetch', event => {
console.warn('Fetch', event.request.url);
// Skip cross-origin requests, like those for Google Analytics.
/* if (event.request.url.startsWith(self.location.origin)) {
console.log('One of our requests..');
event.respondWith(
caches.match(event.request).then(cachedResponse => {
if (cachedResponse) {
console.log('cachedResponse', cachedResponse);
return cachedResponse;
}
return caches.open(RUNTIME).then(cache => {
return fetch(event.request).then(response => {
// Put a copy of the response in the runtime cache.
return cache.put(event.request, response.clone()).then(() => {
console.log('fetch cache response', response);
return response;
});
});
});
})
);
}*/
if (event.request.url.startsWith(self.location.origin)) {
console.log('!!', event.request);
/* event.respondWith(
caches.open(RUNTIME).then(function(cache) {
return cache.match(event.request).then(function (response) {
console.log('£', response);
return response || fetch(event.request).then(function(response) {
cache.put(event.request, response.clone());
return response;
});
});
})
);*/
event.respondWith(
caches.open(RUNTIME).then(function(cache) {
return cache.match(event.request).then(function (response) {
return response || fetch(event.request).then(function(response) {
cache.put(event.request, response.clone());
return response;
});
});
})
);
}
if (event.request.url.startsWith('https://maps.googleapis.com')) {
const url = new URL(event.request.url);
const locCache = `loc-${url.searchParams.get('latlng')}`;
event.respondWith(
caches.match(locCache).then(cachedResponse => {
if (cachedResponse)
return cachedResponse;
return caches.open(RUNTIME).then(cache => {
return fetch(event.request).then(response => {
// Put a copy of the response in the runtime cache.
return cache.put(locCache, response.clone()).then(() => {
return response;
});
});
});
})
);
}
});

View File

@ -0,0 +1,21 @@
{
"name": "Jubilee",
"short_name": "Jubilee",
"icons": [
{
"src": "/img/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/img/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#FFEE58",
"background_color": "#ffffff",
"start_url": ".",
"imgdisplay": "standalone",
"display": "standalone"
}

79
structs/globalstructs.go Normal file
View File

@ -0,0 +1,79 @@
package structs
type LL struct {
Ll string `json:"ll" form:"ll"`
}
type LatLong struct {
Lat float64 `json:"lat" form:"lat"`
Long float64 `json:"long" form:"long"`
}
type FormattedLocation struct {
Lat float64 `db:"lat" json:"lat" form:"lat"`
Long float64 `json:"long" form:"long" db:"long"`
Country string `json:"country" db:"country"`
City string `json:"city" db:"city"`
State string `json:"state" db:"state"`
Zipcode string `json:"zipcode" db:"zipcode"`
StreetName string `json:"streetName" db:"streetName"`
CountryCode string `json:"countryCode" db:"countryCode"`
County string `json:"county" db:"county"`
Neighbourhood string `json:"neighbourhood" db:"neighbourhood"`
Village string `json:"village" db:"village"`
Formatted string `json:"formatted" db:"formatted"`
}
type FormattedWeather struct {
Lat float64 `db:"lat" json:"lat" form:"lat"`
Long float64 `json:"long" form:"long" db:"long"`
Type string `json:"type" form:"type" db:"type"`
Data string `json:"data" db:"data"`
Ts int64 `db:"ts" json:"ts"`
}
type Bob struct {
Bob string `json:"bob" form:"bob"`
}
// TempMax / TempMin from daily.data[0] the daily entry for the current day
type ForecastSummary struct {
Summary string `json:"summary"`
TempMax float64 `json:"tempMax"`
TempMin float64 `json:"tempMin"`
Temperature float64 `json:"temperature"`
Icon string `json:"icon"`
}
type ForecastHour struct {
Time int64 `json:"time"`
Icon string `json:"icon"`
Temp float64 `json:"temp"`
}
type ForecastDay struct {
Time int64 `json:"time"`
Icon string `json:"icon"`
TempHigh float64 `json:"tempHigh"`
TempLow float64 `json:"tempLow"`
}
type ForecastDetails struct {
Humidity float64 `json:"humidity"`
Visibility float64 `json:"visibility"`
UvIndex float64 `json:"uvIndex"`
Summary string `json:"summary"`
WindSpeed float64 `json:"windSpeed"`
Pressure float64 `json:"pressure"`
SunriseTime int64 `json:"sunriseTime"`
SunsetTime int64 `json:"sunsetTime"`
Moonphase float64 `json:"moonphase"`
}
type ForecastRecord struct {
Currently ForecastSummary `json:"currently"`
ForcastToday []ForecastHour `json:"forcastToday"`
DailyForecast []ForecastDay `json:"dailyForecast"`
Details ForecastDetails `json:"details"`
}

40
utils/utils.go Normal file
View File

@ -0,0 +1,40 @@
package utils
import (
"jubilee-server/structs"
"strconv"
"strings"
)
func ParseLL(ll structs.LL) *structs.LatLong {
splitll := strings.Split(ll.Ll, ",")
latFloat, _ := strconv.ParseFloat(splitll[0], 32)
longFloat, _ := strconv.ParseFloat(splitll[1], 32)
return &structs.LatLong{
Lat: latFloat,
Long: longFloat,
}
}
func LLfromStrings64(latitude string, longitude string) *structs.LatLong {
latFloat, _ := strconv.ParseFloat(latitude, 64)
longFloat, _ := strconv.ParseFloat(longitude, 64)
return &structs.LatLong{
Lat: latFloat,
Long: longFloat,
}
}
func LLfromStrings32(latitude string, longitude string) *structs.LatLong {
latFloat, _ := strconv.ParseFloat(latitude, 32)
longFloat, _ := strconv.ParseFloat(longitude, 32)
return &structs.LatLong{
Lat: latFloat,
Long: longFloat,
}
}

334
weather/weather.go Normal file
View File

@ -0,0 +1,334 @@
package weather
import (
"context"
"encoding/json"
_ "fmt"
"github.com/EricNeid/go-openweather"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/models"
"github.com/shawntoffel/go-pirateweather"
_ "github.com/shawntoffel/go-pirateweather"
"jubilee-server/structs"
"time"
"log"
"strconv"
)
const openWeatherAPIKey = "936a0ed9eb23b95cf08fc9f693c24264"
const pirateweatherAPIKey = "AdNZIbMMyb3QtqQhN4WA27EPJR7V339m1Uxvg9yl"
func GetOpenWeather(app *pocketbase.PocketBase, latlong structs.LatLong) string {
log.Println("$$:GetOpenWeather", latlong)
log.Println("-- lat", latlong.Lat)
log.Println("-- long", latlong.Long)
formattedWeather := &structs.FormattedWeather{}
// a 1km square
latlow := latlong.Lat - 0.005
lathigh := latlong.Lat + 0.005
longlow := latlong.Long - 0.005
longhigh := latlong.Long + 0.005
// an hour ago
now := time.Now()
then := now.Add(-1 * time.Hour).Unix()
log.Printf("-- Between %+v,%+v to %+v,%+v\n", latlow, longlow, lathigh, longhigh)
dberr := app.Dao().DB().
Select("*").From("weather").
Where(dbx.NewExp("lat >= {:latlow} and lat <= {:lathigh}", dbx.Params{"latlow": latlow, "lathigh": lathigh})).
AndWhere(dbx.NewExp("long >= {:longlow} and long <= {:longhigh}", dbx.Params{"longlow": longlow, "longhigh": longhigh})).
AndWhere(dbx.NewExp("type = {:type}", dbx.Params{"type": "openweather"})).
AndWhere(dbx.NewExp("ts >= {:then}", dbx.Params{"then": then})).One(&formattedWeather)
if dberr == nil {
// handle error
log.Printf("-- Cache hit OpenWeather %+v,%+v\n", formattedWeather.Lat, formattedWeather.Long)
return formattedWeather.Data
}
data := GetRemoteOpenWeather(latlong)
formattedWeather.Lat = latlong.Lat
formattedWeather.Long = latlong.Long
formattedWeather.Data = data
formattedWeather.Ts = now.Unix()
formattedWeather.Type = "openweather"
go func() {
err := saveWeatherRecord(app, *formattedWeather)
if err != nil {
log.Println(err)
}
}()
return data
}
func GetRemoteOpenWeather(ll structs.LatLong) string {
log.Println("getOpenWeather", ll.Lat, ll.Long)
sLat := strconv.FormatFloat(ll.Lat, 'f', -1, 64)
sLong := strconv.FormatFloat(ll.Long, 'f', -1, 64)
q := openweather.NewQueryForLocation(openWeatherAPIKey, sLat, sLong)
resp, _ := q.DailyForecast5()
// log.Printf("%+v\n", resp)
jsonStr, _ := json.Marshal(resp)
// log.Println(string(jsonStr))
return string(jsonStr)
}
func GetPirateForecast(app *pocketbase.PocketBase, latlong structs.LatLong) string {
log.Println("$$:GetPirateForecast", latlong)
log.Println("-- lat", latlong.Lat)
log.Println("-- long", latlong.Long)
formattedWeather := &structs.FormattedWeather{}
// a 1km square
latlow := latlong.Lat - 0.005
lathigh := latlong.Lat + 0.005
longlow := latlong.Long - 0.005
longhigh := latlong.Long + 0.005
// an hour ago
now := time.Now()
then := now.Add(-1 * time.Hour).Unix()
log.Printf("-- Between %+v,%+v to %+v,%+v\n", latlow, longlow, lathigh, longhigh)
dberr := app.Dao().DB().
Select("*").From("weather").
Where(dbx.NewExp("lat >= {:latlow} and lat <= {:lathigh}", dbx.Params{"latlow": latlow, "lathigh": lathigh})).
AndWhere(dbx.NewExp("long >= {:longlow} and long <= {:longhigh}", dbx.Params{"longlow": longlow, "longhigh": longhigh})).
AndWhere(dbx.NewExp("type = {:type}", dbx.Params{"type": "pirateForecast"})).
AndWhere(dbx.NewExp("ts >= {:then}", dbx.Params{"then": then})).One(&formattedWeather)
if dberr == nil {
// handle error
log.Printf("-- Cache hit weather %+v,%+v\n", formattedWeather.Lat, formattedWeather.Long)
return formattedWeather.Data
}
data := GetRemotePirateForecast(latlong)
formattedWeather.Lat = latlong.Lat
formattedWeather.Long = latlong.Long
formattedWeather.Data = data
formattedWeather.Ts = now.Unix()
formattedWeather.Type = "pirateForecast"
go func() {
err := saveWeatherRecord(app, *formattedWeather)
if err != nil {
log.Println(err)
}
}()
return data
}
func GetRemotePirateForecast(ll structs.LatLong) string {
log.Println("GetRemotePirateForecast", ll.Lat, ll.Long)
client := pirateweather.Client{}
request := pirateweather.ForecastRequest{
Latitude: ll.Lat,
Longitude: ll.Long,
Options: pirateweather.ForecastRequestOptions{
// Return data in SI units.
Units: "uk",
Extend: "Extend",
},
}
ctx := context.Background()
response, err := client.Forecast(ctx, pirateweatherAPIKey, request)
if err == nil {
log.Println("Error:", err)
}
output := new(structs.ForecastRecord)
today := response.Daily.Data[0]
output.Currently.Summary = response.Currently.Summary
output.Currently.Temperature = response.Currently.Temperature
output.Currently.TempMax = today.TemperatureMax
output.Currently.TempMin = today.TemperatureMin
output.Currently.Icon = today.Icon
output.Details.Summary = today.Summary
output.Details.Humidity = today.Humidity
output.Details.Moonphase = today.MoonPhase
output.Details.Pressure = today.Pressure
output.Details.SunriseTime = today.SunriseTime
output.Details.SunsetTime = today.SunsetTime
output.Details.UvIndex = today.UvIndex
output.Details.Visibility = today.Visibility
output.Details.WindSpeed = today.WindSpeed
var daily []structs.ForecastDay
var hourly []structs.ForecastHour
for _, v := range response.Daily.Data {
n := &structs.ForecastDay{
Time: v.Time,
Icon: v.Icon,
TempHigh: v.TemperatureMax,
TempLow: v.TemperatureMin,
}
daily = append(daily, *n)
}
for _, v := range response.Hourly.Data {
n := &structs.ForecastHour{
Time: v.Time,
Icon: v.Icon,
Temp: v.Temperature,
}
hourly = append(hourly, *n)
}
output.DailyForecast = daily
output.ForcastToday = hourly
jsonStr, _ := json.Marshal(output)
log.Println("Forecast output")
// log.Println(string(jsonStr))
return string(jsonStr)
}
func saveWeatherRecord(app *pocketbase.PocketBase, newWeather structs.FormattedWeather) error {
log.Println("$$:saveWeatherRecord", newWeather.Lat, newWeather.Long)
collection, err := app.Dao().FindCollectionByNameOrId("weather")
if err != nil {
log.Println(err)
return err
}
latlow := newWeather.Lat - 0.005
lathigh := newWeather.Lat + 0.005
longlow := newWeather.Long - 0.005
longhigh := newWeather.Long + 0.005
record, recErr := app.Dao().FindRecordsByExpr("weather", dbx.NewExp("type = {:type} and lat >= {:latlow} and lat <= {:lathigh} and long >= {:longlow} and long <= {:longhigh}", dbx.Params{"latlow": latlow, "lathigh": lathigh, "longlow": longlow, "longhigh": longhigh, "type": newWeather.Type}))
if recErr != nil {
log.Println(recErr)
return recErr
}
if len(record) == 0 {
log.Println("-- Insert new weather record")
record := models.NewRecord(collection)
record.Set("lat", newWeather.Lat)
record.Set("long", newWeather.Long)
record.Set("data", newWeather.Data)
record.Set("ts", newWeather.Ts)
record.Set("type", newWeather.Type)
if err := app.Dao().SaveRecord(record); err != nil {
log.Println("ERROR!! saveWeatherRecord NewRecord")
log.Println(err)
return err
}
} else {
log.Println("-- Update weather record")
rec := record[0]
rec.Set("lat", newWeather.Lat)
rec.Set("long", newWeather.Long)
rec.Set("data", newWeather.Data)
rec.Set("ts", newWeather.Ts)
if err := app.Dao().SaveRecord(rec); err != nil {
log.Println("ERROR!! saveLocationRec SaveRecord")
log.Println(err)
return err
}
}
return nil
}
/*
type ForecastHour struct {
Time int64 `json:"time"`
Icon string `json:"icon"`
Temp float64 `json:"temp"`
}
return &structs.FormattedLocation{
Lat: latlong.Lat,
Long: latlong.Long,
Country: address.Country,
City: address.City,
State: address.State,
Zipcode: address.Postcode,
StreetName: address.Street,
CountryCode: address.CountryCode,
County: address.County,
Neighbourhood: address.Suburb,
Village: "",
Formatted: address.FormattedAddress,
}
type ForcastHour struct {
Time int `json:"time"`
Icon string `json:"icon"`
Temp float64 `json:"temp"`
}
PirateWeather
"alerts": [
{
"title": "Wind Advisory issued January 24 at 9:25AM CST until January 24 at 6:00PM CST by NWS Corpus Christi TX",
"regions": ["Live Oak", " Bee", " Goliad", " Victoria", " Jim Wells", " Inland Kleberg", " Inland Nueces", " Inland San Patricio", " Coastal Aransas", " Inland Refugio", " Inland Calhoun", " Coastal Kleberg", " Coastal Nueces", " Coastal San Patricio", " Aransas Islands", " Coastal Refugio", " Coastal Calhoun", " Kleberg Islands", " Nueces Islands", " Calhoun Islands"],
"severity": "Moderate",
"time": 1674573900,
"expires": 1674604800,
"description": "* WHAT...Southwest winds 25 to 30 mph with gusts up to 40 mph. * WHERE...Portions of South Texas. * WHEN...Until 6 PM CST this evening. * IMPACTS...Gusty winds could blow around unsecured objects. Tree limbs could be blown down and a few power outages may result.",
"uri": "https://api.weather.gov/alerts/urn:oid:2.49.0.1.840.0.492c55233ef16d7a98a3337298c828b0f358ea34.001.1"
},
]
*/