// This is not a robust function. func (t Track) TouchdownPDT() time.Time { var s time.Time // Start halfway through, and see where that gets us for i := int(len(t) / 2); i < len(t); i++ { s = t[i].TimestampUTC if t[i].AltitudeFeet == 0 { return date.InPdt(s) } } return date.InPdt(s) }
func (r SCRow) ToCSV() []string { return []string{ r.F.Id.Designator.IATAAirlineDesignator, r.F.Id.Designator.String(), r.F.Id.Origin, date.InPdt(r.F.EnterUTC).Format("2006/01/02"), date.InPdt(r.F.EnterUTC).Format("15:04:05.999999999"), fmt.Sprintf("%v", r.F.TagList()), fmt.Sprintf("%d", r.NumComplaints), fmt.Sprintf("%d", r.NumSpeedbrakes), fmt.Sprintf("%d", r.WeightedComplaints), } }
func (r CBRow) ToCSV() []string { return []string{ r.F.Id.Designator.String(), r.F.Id.Registration, r.F.Id.ModeS, date.InPdt(r.TP.TimestampUTC).Format("2006/01/02"), date.InPdt(r.TP.TimestampUTC).Format("15:04:05.999999999"), fmt.Sprintf("%.1f", r.A.DistNM), fmt.Sprintf("%.0f", r.TP.AltitudeFeet), fmt.Sprintf("%.0f", r.A.BelowBy), fmt.Sprintf("%.4f", r.TP.Latlong.Lat), fmt.Sprintf("%.4f", r.TP.Latlong.Long), r.TP.LongSource(), } }
func (r SERFR1Row) ToCSV() []string { return []string{ r.F.Id.Designator.IATAAirlineDesignator, r.F.Id.Designator.String(), r.F.Id.Origin, r.F.Id.Destination, r.F.Id.Registration, r.F.Id.ModeS, date.InPdt(r.F.EnterUTC).Format("2006/01/02"), date.InPdt(r.F.EnterUTC).Format("15:04:05.999999999"), bool2string(r.HadAdsb), bool2string(r.ClassBViolation), } }
func (r SERFR1AtRow) ToCSV() []string { return []string{ r.F.Id.Designator.IATAAirlineDesignator, r.F.Id.Designator.String(), r.F.Id.Origin, r.F.Id.Destination, r.F.Id.Registration, r.F.Id.ModeS, date.InPdt(r.ITP.TimestampUTC).Format("2006/01/02"), date.InPdt(r.ITP.TimestampUTC).Format("15:04:05.999999999"), fmt.Sprintf("%.0f", r.ITP.SpeedKnots), fmt.Sprintf("%.0f", r.ITP.AltitudeFeet), fmt.Sprintf("%.0f", r.ITP.Post.TimestampUTC.Sub(r.ITP.Pre.TimestampUTC).Seconds()), } }
func (r BrixxRow) ToCSV() []string { return []string{ r.F.Id.Designator.IATAAirlineDesignator, r.F.Id.Designator.String(), r.F.Id.Registration, r.F.Id.ModeS, r.F.Id.Origin, r.F.Id.Destination, r.Source, fmt.Sprintf("%.0f", r.TP.Latlong.Lat), fmt.Sprintf("%.0f", r.TP.Latlong.Long), date.InPdt(r.TP.TimestampUTC).Format("2006/01/02"), date.InPdt(r.TP.TimestampUTC).Format("15:04:05.999999999"), } }
func playback2FlightIdentifier(r FlightPlaybackResponse, f *flightdb.FlightIdentifier) error { flight := r.Result.Response.Data.Flight id := flight.Identification if id.Number.Default != "" { if err := flightdb.ParseIATA(&f.Designator, id.Number.Default); err != nil { return err } } f.Origin, f.Destination = flight.Airport.Origin.Code.Iata, flight.Airport.Destination.Code.Iata // It would be preferable to find the scheduled date of departure for this; else we // misidentify those flights which get delayed past midnight. if flight.Track == nil || len(flight.Track) == 0 { return fmt.Errorf("playback2FightIdentifier: no track data, so no departure date!") } epoch := flight.Track[0].Timestamp f.DepartureDate = date.InPdt(time.Unix(int64(epoch), 0)) if f.ForeignKeys == nil { f.ForeignKeys = map[string]string{} } f.ForeignKeys["fr24"] = id.Hex f.Registration = flight.Aircraft.Identification.Registration f.Callsign = id.Callsign // ?? Is this right ? If so, where is ICAO ?? f.ModeS = flight.Aircraft.Identification.ModeS return nil }
func FixupComplaint(c *types.Complaint, key *datastore.Key) { // 0. Snag the key, so we can refer to this object later c.DatastoreKey = key.Encode() // 1. GAE datastore helpfully converts timezones to UTC upon storage; fix that c.Timestamp = date.InPdt(c.Timestamp) // 2. Compute the flight details URL, if within 24 days age := date.NowInPdt().Sub(c.Timestamp) if age < time.Hour*24 { // c.AircraftOverhead.Fr24Url = c.AircraftOverhead.PlaybackUrl() c.AircraftOverhead.Fr24Url = "http://flightaware.com/live/flight/" + c.AircraftOverhead.FlightNumber // Or: http://flightaware.com/live/flight/UAL337/history/20151215/ [0655Z/KLAX/KSFO] // date is UTC of departure time; might be tricky to guess :/ } // 3. Compute distances, if we have an aircraft if c.AircraftOverhead.FlightNumber != "" { a := c.AircraftOverhead aircraftPos := geo.Latlong{a.Lat, a.Long} observerPos := geo.Latlong{c.Profile.Lat, c.Profile.Long} c.Dist2KM = observerPos.Dist(aircraftPos) c.Dist3KM = observerPos.Dist3(aircraftPos, a.Altitude) } }
func (r SkimRow) ToCSV() []string { e := r.A.Events[0] return []string{ r.F.Id.Designator.IATAAirlineDesignator, r.F.Id.Designator.String(), r.F.Id.Registration, r.F.Id.ModeS, r.F.Id.Origin, r.F.Id.Destination, fmt.Sprintf("%.1f", r.A.Events[0].StartNM), fmt.Sprintf("%.1f", r.A.Events[0].EndNM), date.InPdt(e.StartTP.TimestampUTC).Format("2006/01/02"), date.InPdt(e.StartTP.TimestampUTC).Format("15:04:05.999999999"), fmt.Sprintf("%.0f", e.EndTP.TimestampUTC.Sub(e.StartTP.TimestampUTC).Seconds()), r.Source, } }
func (fs *FlightSnapshot) ToJSString() string { return fmt.Sprintf("{pos:{lat:%.9f,lng:%.9f}, "+ "heading:%.0f, alt:%.0f, speed:%.0f, "+ "flightnumber:%q, icao24:%q, callsign:%q, reg:%q, "+ "t:%q, enterutc:%q, url:%q"+ "}", fs.Pos.Latlong.Lat, fs.Pos.Latlong.Long, fs.Pos.Heading, fs.Pos.AltitudeFeet, fs.Pos.SpeedKnots, fs.F.Id.Designator, fs.F.Id.ModeS, fs.F.Id.Callsign, fs.F.Id.Registration, date.InPdt(fs.Pos.TimestampUTC).Format("01/02 15:04:05 MST"), fs.F.EnterUTC.Format("15:04:05 MST"), fmt.Sprintf("/fdb/lookup?map=1&id=%s", fs.F.Id), ) }
func complaintsForHandler(w http.ResponseWriter, r *http.Request) { ctx := req2ctx(r) s, e := widget.FormValueEpochTime(r, "start"), widget.FormValueEpochTime(r, "end") if r.FormValue("start") == "" { s, e = date.WindowForToday() } flightnumber := r.FormValue("flight") if e.Sub(s) > (time.Hour * 24) { http.Error(w, "time span too wide", http.StatusInternalServerError) return } else if s.Year() < 2015 { http.Error(w, "times in the past", http.StatusInternalServerError) return } else if flightnumber == "" { http.Error(w, "no flightnumber", http.StatusInternalServerError) return } cdb := complaintdb.NewDB(ctx) times, err := cdb.GetComplaintTimesInSpanByFlight(s, e, flightnumber) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if r.FormValue("debug") != "" { str := fmt.Sprintf("* %s\n* %s\n* %s\n* [%d]\n\n", s, e, flightnumber, len(times)) for i, t := range times { str += fmt.Sprintf("%3d %s\n", i, date.InPdt(t)) } w.Header().Set("Content-Type", "text/plain") w.Write([]byte(str)) return } w.Header().Set("Content-Type", "application/json") jsonBytes, err := json.Marshal(times) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Write(jsonBytes) }
func buildLegend(t time.Time) string { legend := date.InPdt(t).Format("15:04:05 MST (2006/01/02)") legend += " [" + legendUrl(t, -3600, "-1h") + ", " + legendUrl(t, -1200, "-20m") + ", " + legendUrl(t, -600, "-10m") + ", " + legendUrl(t, -300, "-5m") + ", " + legendUrl(t, -60, "-1m") + ", " + legendUrl(t, -30, "-30s") + "; " + legendUrl(t, 30, "+30s") + "; " + legendUrl(t, 60, "+1m") + ", " + legendUrl(t, 300, "+5m") + ", " + legendUrl(t, 600, "+10m") + ", " + legendUrl(t, 1200, "+20m") + ", " + legendUrl(t, 3600, "+1h") + "]" return legend }
func (f Flight) SFOClassB(trackKey string, metars *metar.Archive) (violation bool, cbt ClassBTrack) { violation, cbt = false, ClassBTrack{} track := f.Track if trackKey != "" { track = f.Tracks[trackKey] } for i, tp := range track { cbtp := ClassBTrackPoint{TP: &track[i]} cbtp.Debug = date.InPdt(tp.TimestampUTC).Format("** 2006/01/02, 15:04:05 MST") + tp.TimestampUTC.Format(" (2006/01/02, 15:04:05 MST)\n") + "** Trackpoint [" + fmt.Sprintf("%d", i) + "] source: <b>" + track.LongSource() + "</b>\n" if f.Id.Destination != "SFO" { cbtp.Debug += "* Altitude: " + fmt.Sprintf("%.0f", tp.AltitudeFeet) + "\n" + "* VerticalRate: " + fmt.Sprintf("%.0f", tp.VerticalRate) + " feet/min\n" + "* Heading: " + fmt.Sprintf("%.0f", tp.Heading) + "\n" //"* Flight not a scheduled SFO arrival\n" } else { sfo.SFOClassBMap.ClassBPointAnalysis(tp.Latlong, tp.SpeedKnots, tp.AltitudeFeet, 200, &cbtp.A) cbtp.Debug += "* VerticalRate: " + fmt.Sprintf("%.0f", tp.VerticalRate) + " feet/min\n" cbtp.Debug += cbtp.A.Reasoning kLimit := 15.5 if cbtp.A.DistNM < kLimit { cbtp.A.AllowThisPoint = true cbtp.Debug += fmt.Sprintf("** ClassB excursion detection disabled within %.1fNM\n", kLimit) } else if cbtp.A.IsViolation() { violation = true // We have at least one violating point in this trail } } cbt = append(cbt, cbtp) } return }
func PostComplaint(client *http.Client, p types.ComplainerProfile, c types.Complaint) (string, error) { first, last := p.SplitName() addr := p.GetStructuredAddress() if c.Activity == "" { c.Activity = "Loud noise" } debug, submitkey, err := GetSubmitkey(client) if err != nil { return debug, err } debug += fmt.Sprintf("We got submitkey=%s\n", submitkey) // {{{ Populate form vals := url.Values{ "response": {"json"}, "contactmethod": {"App"}, "app_key": {"TUC8uDJMooVMvf7hew93nhUGcWgw"}, "caller_code": {p.CallerCode}, "name": {first}, "surname": {last}, "address1": {addr.Street}, "address2": {""}, "zipcode": {addr.Zip}, "city": {addr.City}, "state": {addr.State}, "email": {p.EmailAddress}, "airports": {"KSFO"}, // KOAK, KSJC, KSAN "month": {date.InPdt(c.Timestamp).Format("1")}, "day": {date.InPdt(c.Timestamp).Format("2")}, "year": {date.InPdt(c.Timestamp).Format("2006")}, "hour": {date.InPdt(c.Timestamp).Format("15")}, "min": {date.InPdt(c.Timestamp).Format("4")}, "aircraftcategory": {"J"}, "eventtype": {"Loud noise"}, // perhaps map c.Activity to something ? "comments": {c.Description}, "responserequired": {"N"}, "enquirytype": {"C"}, "submit": {"Submit complaint"}, "submitkey": {submitkey}, "nowebtrak": {"1"}, "defaulttime": {"0"}, "webtraklinkback": {""}, "title": {""}, "homephone": {""}, "workphone": {""}, "cellphone": {""}, } if c.AircraftOverhead.FlightNumber != "" { vals.Add("acid", c.AircraftOverhead.Callsign) vals.Add("aacode", c.AircraftOverhead.Id2) vals.Add("tailnumber", c.AircraftOverhead.Registration) vals.Add("aircrafttype", c.AircraftOverhead.EquipType) //vals.Add("adflag", "??") // Operation type (A, D or O for Arr, Dept or Overflight) //vals.Add("beacon", "??") // SSR code (eg 210) } // }}} debug += "Submitting these vals:-\n" for k, v := range vals { debug += fmt.Sprintf(" * %-20.20s: %v\n", k, v) } if resp, err := client.PostForm("https://"+bksvHost+bksvPath, vals); err != nil { return debug, err } else { defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) if resp.StatusCode >= 400 { debug += fmt.Sprintf("ComplaintPOST: HTTP err '%s'\nBody:-\n%s\n--\n", resp.Status, body) return debug, fmt.Errorf("ComplaintPOST: HTTP err %s", resp.Status) } var jsonMap map[string]interface{} if err := json.Unmarshal([]byte(body), &jsonMap); err != nil { debug += fmt.Sprintf("ComplaintPOST: JSON unmarshal '%v'\nBody:-\n%s\n--\n", err, body) return debug, fmt.Errorf("ComplaintPOST: JSON unmarshal %v", err) /* Fall back ? if !regexp.MustCompile(`(?i:received your complaint)`).MatchString(string(body)) { debug += fmt.Sprintf("BKSV body ...\n%s\n------\n", string(body)) return debug,fmt.Errorf("Returned response did not say 'received your complaint'") } else { debug += "Success !\n"+string(body) } */ } else if v := jsonMap["result"]; v == nil { return debug, fmt.Errorf("ComplaintPOST: jsonmap had no 'result'.\nBody:-\n%s\n--\n", body) } else { result := v.(string) if result == "1" { debug += "Json Success !\n" } else { debug += fmt.Sprintf("Json result not '1':-\n%#v\n--\n", jsonMap) return debug, fmt.Errorf("ComplaintPOST: result='%s'", result) } } } return debug, nil }
func templateFormatPdt(t time.Time, format string) string { return date.InPdt(t).Format(format) }
func queryHandler(w http.ResponseWriter, r *http.Request) { if r.FormValue("date") == "" && r.FormValue("epoch") == "" { var params = map[string]interface{}{ "TwoHoursAgo": date.NowInPdt().Add(-2 * time.Hour), } if err := templates.ExecuteTemplate(w, "fdb-queryform", params); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } return } db := fdb.NewDB(r) db.Memcache = true var t time.Time if r.FormValue("epoch") != "" { if epoch, err := strconv.ParseInt(r.FormValue("epoch"), 10, 64); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } else { t = time.Unix(epoch, 0) } } else { var err2 error t, err2 = date.ParseInPdt("2006/01/02 15:04:05", r.FormValue("date")+" "+r.FormValue("time")) if err2 != nil { http.Error(w, err2.Error(), http.StatusInternalServerError) return } } var refPoint *geo.Latlong = nil if r.FormValue("lat") != "" { refPoint = &geo.Latlong{} var err error if refPoint.Lat, err = strconv.ParseFloat(r.FormValue("lat"), 64); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if refPoint.Long, err = strconv.ParseFloat(r.FormValue("long"), 64); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } if snapshots, err := db.LookupSnapshotsAtTimestampUTC(t.UTC(), refPoint, 1000); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } else { var params = map[string]interface{}{ "Legend": buildLegend(t), "SearchTimeUTC": t.UTC(), "SearchTime": date.InPdt(t), "Flights": snapshots2params(snapshots), "FlightsJS": ftype.FlightSnapshotSet(snapshots).ToJSVar(), "MapsAPIKey": kGoogleMapsAPIKey, "Center": sfo.KLatlongSERFR1, "Zoom": 9, // "CaptureArea": fdb.KBoxSnarfingCatchment, // comment out, as we don't want it in this view } if r.FormValue("resultformat") == "json" { for i, _ := range snapshots { snapshots[i].F.Track = nil snapshots[i].F.Tracks = nil } js, err := json.Marshal(snapshots) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.Write(js) } else { templateName := "fdb-queryresults-map" if r.FormValue("resultformat") == "list" { templateName = "fdb-queryresults-list" } if err := templates.ExecuteTemplate(w, templateName, params); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } } }
func PopulateForm(c types.Complaint, submitkey string) url.Values { first, last := c.Profile.SplitName() addr := c.Profile.GetStructuredAddress() if c.Activity == "" { c.Activity = "Loud noise" } vals := url.Values{ "response": {"json"}, "contactmethod": {"App"}, "apiKey": {"399734e01c8cd5c21205599689cc77f2a50467f28e6f5d58a69f2b097d71b839c20e0051175107e74130ae9a3bbaccbe51ec5742e6ca3e51ff40cc1a8f401009"}, "caller_code": {c.Profile.CallerCode}, "name": {first}, "surname": {last}, "address1": {addr.Street}, "address2": {""}, "zipcode": {addr.Zip}, "city": {addr.City}, "state": {addr.State}, "email": {c.Profile.EmailAddress}, "airports": {"KSFO"}, // KOAK, KSJC, KSAN "month": {date.InPdt(c.Timestamp).Format("1")}, "day": {date.InPdt(c.Timestamp).Format("2")}, "year": {date.InPdt(c.Timestamp).Format("2006")}, "hour": {date.InPdt(c.Timestamp).Format("15")}, "min": {date.InPdt(c.Timestamp).Format("4")}, "aircraftcategory": {"J"}, "eventtype": {"Loud noise"}, // perhaps map c.Activity to something ? "comments": {c.Description}, "responserequired": {"N"}, "enquirytype": {"C"}, "submit": {"Submit complaint"}, //"submitkey": {submitkey}, "nowebtrak": {"1"}, "defaulttime": {"0"}, "webtraklinkback": {""}, "title": {""}, "homephone": {""}, "workphone": {""}, "cellphone": {""}, "browser_name": {c.Browser.Name}, "browser_version": {c.Browser.Version}, "browser_vendor": {c.Browser.Vendor}, "browser_uuid": {c.Browser.UUID}, "browser_platform": {c.Browser.Platform}, } if c.AircraftOverhead.FlightNumber != "" { vals.Add("acid", c.AircraftOverhead.Callsign) vals.Add("aacode", c.AircraftOverhead.Id2) vals.Add("tailnumber", c.AircraftOverhead.Registration) vals.Add("aircrafttype", c.AircraftOverhead.EquipType) //vals.Add("adflag", "??") // Operation type (A, D or O for Arr, Dept or Overflight) //vals.Add("beacon", "??") // Squawk SSR code (eg 2100) } return vals }
func (e SkimEvent) String() string { return fmt.Sprintf("%.0fft [%.1f,%.1f]NM; from %s for %s", e.Altitude, e.StartNM, e.EndNM, date.InPdt(e.StartTP.TimestampUTC).Format("15:04:06 MST"), e.EndTP.TimestampUTC.Sub(e.StartTP.TimestampUTC)) }
func (f Flight) Legend() string { l := fmt.Sprintf("<b>%s</b> (%s,%s) %s<br/>Tags=<b>%v</b> Tracks=%v<br/>Route=<b>%v</b>", f.Id, f.Id.Callsign, f.Id.ModeS, date.InPdt(f.EnterUTC).Format("2006/01/02 15:03 MST"), f.JustTagList(), f.TrackList(), f.WaypointList()) return l }
func (track Track) SkimsToSFO(feetWithin float64, minDurationNM float64, minDistNM, maxDistNM float64) (AltitudeTrack, SkimAnalysis) { at := AltitudeTrack{} a := SkimAnalysis{Events: []SkimEvent{}} // Build this up first, then mutate it during analysis below for i, tp := range track { atp := AltitudeTrackPoint{TP: &track[i]} atp.Debug = date.InPdt(tp.TimestampUTC).Format("** 2006/01/02, 15:04:05 MST") + tp.TimestampUTC.Format(" (2006/01/02, 15:04:05 MST)\n") + "** Trackpoint [" + fmt.Sprintf("%d", i) + "] source: <b>" + track.LongSource() + "</b>\n" + "* Altitude: " + fmt.Sprintf("%.0f", tp.AltitudeFeet) + "\n" + "* Heading: " + fmt.Sprintf("%.0f", tp.Heading) + "\n" at = append(at, atp) } skimAltitudes := []float64{8000, 6000} for _, targetAltitude := range skimAltitudes { iStart := -1 // Index when a skim starts initHeading := 0.0 for i, tp := range track { if math.Abs(tp.AltitudeFeet-targetAltitude) < feetWithin { // We are within !! if iStart < 0 { iStart = i initHeading = tp.Heading } // Bail if we deviate by more than 10 degrees (i.e. delay vectoring) if math.Abs(initHeading-tp.Heading) > 10.0 { iStart = -1 } } else { // We are outside. Flush a skim event if we were just inside, and it looks interesting if iStart > 0 { e := SkimEvent{ Altitude: targetAltitude, StartTP: &track[iStart], EndTP: &track[i-1], } e.StartNM = sfo.KLatlongSFO.DistNM(e.StartTP.Latlong) e.EndNM = sfo.KLatlongSFO.DistNM(e.EndTP.Latlong) // Is this event long enough ? Does it overlap with our range of interest ? if (math.Abs(e.StartNM-e.EndNM) >= minDurationNM) && (e.EndNM <= maxDistNM) && (e.StartNM >= minDistNM) { a.Events = append(a.Events, e) for j := iStart; j <= i; j++ { at[j].Flagged = true at[j].Debug += fmt.Sprintf("* target:%.0fft, tolerance:%.0ft\n", targetAltitude, feetWithin) } } iStart = -1 } } } } return at, a }