Example #1
0
func idspecsToFlightV2s(r *http.Request) ([]*newfdb.Flight, error) {
	c := oldappengine.NewContext(r)
	db := oldfgae.FlightDB{C: c}
	newFlights := []*newfdb.Flight{}

	idspecs, err := FormValueIdSpecs(r)
	if err != nil {
		return newFlights, err
	}

	for _, idspec := range idspecs {
		oldF, err := db.LookupById(idspec)
		if err != nil {
			return newFlights, err
		} else if oldF == nil {
			return newFlights, fmt.Errorf("flight '%s' not found", idspec)
		}
		newF, err := oldF.V2()
		if err != nil {
			return newFlights, err
		}
		newFlights = append(newFlights, newF)
	}

	return newFlights, nil
}
Example #2
0
func idspecsToMapLines(r *http.Request) ([]newui.MapLine, error) {
	c := oldappengine.NewContext(r)
	db := oldfgae.FlightDB{C: c}

	lines := []newui.MapLine{}

	idspecs, err := FormValueIdSpecs(r)
	if err != nil {
		return lines, err
	}

	for _, idspec := range idspecs {
		oldF, err := db.LookupById(idspec)
		if err != nil {
			return lines, err
		} else if oldF == nil {
			return lines, fmt.Errorf("flight '%s' not found", idspec)
		}
		newF, err := oldF.V2()
		if err != nil {
			return lines, err
		}
		flightLines := newui.FlightToMapLines(newF)
		lines = append(lines, flightLines...)
	}

	return lines, nil
}
Example #3
0
func decodetrackHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	db := fdb.FlightDB{C: c}

	icao := r.FormValue("icaoid")
	callsign := strings.TrimSpace(r.FormValue("callsign"))
	if icao == "" || callsign == "" {
		http.Error(w, "need args {icaoid,callsign}", http.StatusInternalServerError)
		return
	}

	if tracks, err := db.ReadTrackFragments(icao, callsign); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	} else {
		var params = map[string]interface{}{
			"Tracks":   tracks,
			"Callsign": callsign,
			"Icao24":   icao,
		}
		if err := templates.ExecuteTemplate(w, "fdb-decodetrack", params); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}
}
Example #4
0
func addtrackHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	db := fdb.FlightDB{C: c}

	icaoId := r.FormValue("icaoid")
	callsign := strings.TrimSpace(r.FormValue("callsign"))
	tStr := r.FormValue("track")

	// Validate it works before persisting
	t := ftype.Track{}
	if err := t.Base64Decode(tStr); err != nil {
		c.Errorf(" /mdb/addtrack: decode failed: %v", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

	ftf := ftype.FrozenTrackFragment{
		TrackBase64: tStr,
		Callsign:    callsign,
		Icao24:      icaoId,
	}
	if err := db.AddTrackFrgament(ftf); err != nil {
		c.Errorf(" /mdb/addtrack: db.AddTrackFragment failed: %v", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

	// 3. Routine to merge track fragments ? Extra credit ?

	// c.Infof(" /mdb/addtrack: added %d points for [%s][%s]", len(t), icaoId, callsign)
	w.Write([]byte(fmt.Sprintf("Added %d for %s\n", len(t), icaoId)))
}
Example #5
0
func skimmerReport(c appengine.Context, s, e time.Time, opt ReportOptions) ([]ReportRow, ReportMetadata, error) {
	meta := ReportMetadata{}
	fdb := fdb.FlightDB{C: c}
	maybeMemcache(&fdb, e)
	tags := []string{flightdb.KTagSERFR1}
	if flights, err := fdb.LookupTimeRangeByTags(tags, s, e); err != nil {
		return nil, nil, err

	} else {
		out := []ReportRow{}

		for _, f := range flights {
			t := f.BestTrack()
			_, analysis := t.SkimsToSFO(opt.Skimmer_AltitudeTolerance, opt.Skimmer_MinDurationNM, 14.5, 50)

			// Output one row per event, in a kind of hacky way
			extras := fmt.Sprintf("&skim=1&alttol=%.0f&mindist=%.0f", opt.Skimmer_AltitudeTolerance,
				opt.Skimmer_MinDurationNM)
			for _, event := range analysis.Events {
				row := SkimRow{Url: flight2Url(f) + template.HTML(extras), F: f, Source: t.LongSource(), A: analysis}
				row.A.Events = []flightdb.SkimEvent{event}
				out = append(out, row)

			}
		}
		return out, meta, nil
	}
}
Example #6
0
func brixxViolationReport(c appengine.Context, s, e time.Time, opt ReportOptions) ([]ReportRow, ReportMetadata, error) {
	meta := ReportMetadata{}
	fdb := fdb.FlightDB{C: c}
	maybeMemcache(&fdb, e)
	tags := []string{flightdb.KTagBRIXX}
	if flights, err := fdb.LookupTimeRangeByTags(tags, s, e); err != nil {
		return nil, nil, err

	} else {
		out := []ReportRow{}

		// Hmm. Really need a better way to link 'violations in this report' to dots on the map
		for _, f := range flights {
			t := f.BestTrack()
			for i, tp := range t {
				if tp.Latlong.DistNM(sfo.KLatlongSJC) > 20 {
					continue
				}
				if tp.AltitudeFeet < 5500 && tp.Latlong.Long < sfo.KFixes["YADUT"].Long {
					row := BrixxRow{
						Url:    flight2Url(f),
						F:      f,
						Source: t.LongSource(),
						TP:     &t[i],
					}
					out = append(out, row)
					break
				}
			}
		}
		return out, meta, nil
	}
}
Example #7
0
func jobTrackTimezoneHandler(r *http.Request, f *oldfdb.Flight) (string, error) {
	c := appengine.NewContext(r)

	defaultTP := f.Track.ClosestTrackpoint(sfo.KFixes["EPICK"])
	adsbTP := f.Tracks["ADSB"].ClosestTrackpoint(sfo.KFixes["EPICK"])
	trackTimeDelta := defaultTP.TimestampUTC.Sub(adsbTP.TimestampUTC)

	str := fmt.Sprintf("OK, looked up %s\n Default: %s\n ADSB   : %s\n delta: %s\n",
		f, defaultTP, adsbTP, trackTimeDelta)

	if trackTimeDelta < -4*time.Hour || trackTimeDelta > 4*time.Hour {
		str += fmt.Sprintf("* recoding\n* before: %s\n", f.Tracks["ADSB"])

		for i, _ := range f.Tracks["ADSB"] {
			f.Tracks["ADSB"][i].TimestampUTC = f.Tracks["ADSB"][i].TimestampUTC.Add(time.Hour * -8)
		}
		str += fmt.Sprintf("* after : %s\n", f.Tracks["ADSB"])

		db := oldfgae.FlightDB{C: oldappengine.NewContext(r)}
		if err := db.UpdateFlight(*f); err != nil {
			log.Errorf(c, "Persist Flight %s: %v", f, err)
			return str, err
		}
		log.Infof(c, "Updated flight %s", f)
		str += fmt.Sprintf("--\nFlight was updated\n")

	} else {
		log.Debugf(c, "Skipped flight %s, delta=%s", f, trackTimeDelta)
		str += "--\nFlight was OK, left untouched\n"
	}

	return str, nil
}
Example #8
0
func jobV2adsbHandler(r *http.Request, f *oldfdb.Flight) (string, error) {
	c := appengine.NewContext(r)
	str := ""

	if f.HasTrack("ADSB") {
		return "", nil
	} // Already has one

	err, deb := f.GetV2ADSBTrack(urlfetch.Client(c))
	str += fmt.Sprintf("*getv2ADSB [%v]:-\n", err, deb)
	if err != nil {
		return str, err
	}

	if !f.HasTrack("ADSB") {
		return "", nil
	} // Didn't find one

	f.Analyse() // Retrigger Class-B stuff

	db := oldfgae.FlightDB{C: oldappengine.NewContext(r)}
	if err := db.UpdateFlight(*f); err != nil {
		log.Errorf(c, "Persist Flight %s: %v", f, err)
		return str, err
	}
	log.Infof(c, "Updated flight %s", f)
	str += fmt.Sprintf("--\nFlight was updated\n")

	return str, nil
}
Example #9
0
func brixx1Report(c appengine.Context, s, e time.Time, opt ReportOptions) ([]ReportRow, ReportMetadata, error) {
	meta := ReportMetadata{}
	fdb := fdb.FlightDB{C: c}
	maybeMemcache(&fdb, e)
	tags := []string{flightdb.KTagBRIXX}
	if flights, err := fdb.LookupTimeRangeByTags(tags, s, e); err != nil {
		return nil, nil, err

	} else {
		out := []ReportRow{}

		meta["[A] Total BRIXX flights "] = float64(len(flights))

		for _, f := range flights {
			hasAdsb := false
			if _, exists := f.Tracks["ADSB"]; exists == true {
				meta["[B] With data from "+f.Tracks["ADSB"].LongSource()]++
			}
			if t, exists := f.Tracks["FA"]; exists == true {
				meta["[B] With data from "+f.Tracks["FA"].LongSource()]++
				hasAdsb = t.IsFromADSB()
			} else {
				meta["[B] With data from "+f.Track.LongSource()]++
			}

			row := SERFR1Row{flight2Url(f), f, hasAdsb, false}
			out = append(out, row)

		}
		return out, meta, nil
	}
}
Example #10
0
// This enqueues tasks for each individual day, or flight
func batchFlightScanHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)

	tags := []string{} //"ADSB"} // Maybe make this configurable ...

	n := 0
	str := ""
	s, e, _ := widget.FormValueDateRange(r)
	job := r.FormValue("job")
	if job == "" {
		http.Error(w, "Missing argument: &job=foo", http.StatusInternalServerError)
	}

	days := date.IntermediateMidnights(s.Add(-1*time.Second), e) // decrement start, to include it
	for _, day := range days {
		// Get the keys for all the flights on this day.
		fdb := oldfgae.FlightDB{C: oldappengine.NewContext(r)}

		dStart, dEnd := date.WindowForTime(day)
		dEnd = dEnd.Add(-1 * time.Second)
		keys, err := fdb.KeysInTimeRangeByTags(tags, dStart, dEnd)
		if err != nil {
			log.Errorf(c, "upgradeHandler: enqueue: %v", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		singleFlightUrl := "/backend/fdb-batch/flight"
		for _, key := range keys {
			str += fmt.Sprintf("Enqueing day=%s: %s?job=%s&key=%s\n",
				day.Format("2006.01.02"), singleFlightUrl, job, key.Encode())

			t := taskqueue.NewPOSTTask(singleFlightUrl, map[string][]string{
				"date": {day.Format("2006.01.02")},
				"key":  {key.Encode()},
				"job":  {job},
			})

			if _, err := taskqueue.Add(c, t, "batch"); err != nil {
				log.Errorf(c, "upgradeHandler: enqueue: %v", err)
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}

			n++
		}
	}

	log.Infof(c, "enqueued %d batch items for '%s'", n, job)

	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte(fmt.Sprintf("OK, batch, enqueued %d tasks for %s\n%s", n, job, str)))
}
Example #11
0
// A super widget, for all the batch jobs
func formValueFlightByKey(r *http.Request) (*oldfdb.Flight, error) {
	fdb := oldfgae.FlightDB{C: oldappengine.NewContext(r)}

	key, err := olddatastore.DecodeKey(r.FormValue("key"))
	if err != nil {
		return nil, fmt.Errorf("fdb-batch: %v", err)
	}
	f, err := fdb.KeyToFlight(key)
	if err != nil {
		return nil, fmt.Errorf("fdb-batch: %v", err)
	}
	return f, nil
}
Example #12
0
func adsbClassbReport(c appengine.Context, s, e time.Time, opt ReportOptions) ([]ReportRow, ReportMetadata, error) {
	fdb := fdb.FlightDB{C: c}
	maybeMemcache(&fdb, e)
	tags := []string{flightdb.KTagSERFR1}
	if flights, err := fdb.LookupTimeRangeByTags(tags, s, e); err != nil {
		return nil, nil, err
	} else {
		meta := ReportMetadata{}
		rows := []ReportRow{}

		for _, f := range flights {
			row := ACBRow{F: f, Url: flight2Url(f)}

			_, cbt := f.SFOClassB("FA", nil)
			worst := cbt.FindWorstPoint()
			row.FAViolation = (worst != nil)
			if worst != nil {
				row.FAAnalysis = worst.A
			}

			if f.HasTrack("ADSB") {
				row.HadLocalTrack = true
				_, cbt := f.SFOClassB("ADSB", nil)
				worst := cbt.FindWorstPoint()
				row.LocalViolation = (worst != nil)
				if worst != nil {
					row.LocalAnalysis = worst.A
				}
			}

			if row.LocalViolation && !row.FAViolation {
				row.FoundBonusViolation = true
			}
			if row.LocalViolation && row.FAViolation {
				hFA := row.FAAnalysis.BelowBy
				hLocal := row.LocalAnalysis.BelowBy
				row.IncreasedViolationBy = hLocal - hFA
			}

			if row.LocalViolation || row.FAViolation {
				rows = append(rows, row)
			}
		}

		return rows, meta, nil
	}
}
Example #13
0
func discrepReport(c appengine.Context, s, e time.Time, opt ReportOptions) ([]ReportRow, ReportMetadata, error) {
	meta := ReportMetadata{}
	fdb := fdb.FlightDB{C: c}
	maybeMemcache(&fdb, e)
	tags := []string{flightdb.KTagSERFR1}
	if flights, err := fdb.LookupTimeRangeByTags(tags, s, e); err != nil {
		return nil, nil, err

	} else {
		out := []ReportRow{}

		for _, f := range flights {
			// If only one source has ADS-B, flag it
			interest := false
			if f.HasTrack("ADSB") && !f.HasTrack("FA:TA") {
				interest = true
				meta["Missing from FlightAware ADS-B"] += 1
			}
			if !f.HasTrack("ADSB") && f.HasTrack("FA:TA") {
				interest = true
				meta["Missing from local ADS-B"] += 1
			}

			// If both have ADS-B, look for missed violations
			if f.HasTrack("ADSB") && f.HasTrack("FA:TA") {
				if f.HasTag("ClassB:ADSB") && !f.HasTag("ClassB:FA") {
					interest = true
					meta["Bonus violations"] += 1
				}
				if !f.HasTag("ClassB:ADSB") && f.HasTag("ClassB:FA") {
					interest = true
					meta["Missed violations"] += 1
				}
			}

			if !interest {
				continue
			}

			row := SERFR1Row{flight2Url(f), f, false, false}
			out = append(out, row)
		}
		return out, meta, nil
	}
}
Example #14
0
func serfr1AtReport(c appengine.Context, s, e time.Time, opt ReportOptions) ([]ReportRow, ReportMetadata, error) {
	meta := ReportMetadata{}
	fdb := fdb.FlightDB{C: c}
	maybeMemcache(&fdb, e)
	tags := []string{flightdb.KTagSERFR1}

	pos := sfo.KFixes[opt.Waypoint]
	out := []ReportRow{}

	iter := fdb.NewIter(fdb.QueryTimeRangeByTags(tags, s, e))
	nSerfr1 := 0
	for {
		f, err := iter.NextWithErr()
		if err != nil {
			fdb.C.Errorf("serfr1AtReport iterator failed: %v", err)
			return nil, nil, err
		} else if f == nil {
			break // We've hit EOF
		}
		nSerfr1++

		if _, exists := f.Tracks["ADSB"]; exists == true {
			meta["[B] with data from "+f.Tracks["ADSB"].LongSource()]++
		}
		if _, exists := f.Tracks["FA"]; exists == true {
			meta["[B] with data from "+f.Tracks["FA"].LongSource()]++
		} else {
			meta["[B] with data from "+f.Track.LongSource()]++
		}

		if itp, err := f.BestTrack().PointOfClosestApproach(pos); err != nil {
			c.Infof("Skipping flight %s: err=%v", f, err)
		} else {
			url := template.HTML(fmt.Sprintf("%s&waypoint=%s", flight2Url(*f), opt.Waypoint))
			f.Tracks = nil // avoid running out of F1 RAM!
			row := SERFR1AtRow{url, *f, itp}
			out = append(out, row)
		}
	}

	meta["[A] Total SERFR1 flights "] = float64(nSerfr1)

	return out, meta, nil
}
Example #15
0
func serfr1Report(c appengine.Context, s, e time.Time, opt ReportOptions) ([]ReportRow, ReportMetadata, error) {
	fdb := fdb.FlightDB{C: c}
	maybeMemcache(&fdb, e)

	meta := ReportMetadata{}
	out := []ReportRow{}

	idspecs := []string{}

	reportFunc := func(f *flightdb.Flight) {
		classBViolation := f.HasTag(flightdb.KTagReliableClassBViolation)
		hasAdsb := false
		if _, exists := f.Tracks["ADSB"]; exists == true {
			meta["[B] with data from "+f.Tracks["ADSB"].LongSource()]++
			idspecs = append(idspecs, fmt.Sprintf("%s@%d", f.Id.ModeS, f.EnterUTC.Unix()))
		}
		if t, exists := f.Tracks["FA"]; exists == true {
			meta["[B] with data from "+f.Tracks["FA"].LongSource()]++
			hasAdsb = t.IsFromADSB()
		} else {
			meta["[B] with data from "+f.Track.LongSource()]++
		}

		fClone := f.ShallowCopy()

		row := SERFR1Row{flight2Url(*fClone), *fClone, hasAdsb, classBViolation}
		out = append(out, row)
	}

	tags := []string{flightdb.KTagSERFR1}
	if err := fdb.IterWith(fdb.QueryTimeRangeByTags(tags, s, e), reportFunc); err != nil {
		return nil, nil, err
	}

	approachUrl := fmt.Sprintf("http://ui-dot-serfr0-fdb.appspot.com/fdb/approach?idspec=%s",
		strings.Join(idspecs, ","))

	meta[fmt.Sprintf("[Z] %s", approachUrl)] = 1

	meta["[A] Total SERFR1 flights "] = float64(len(out))
	return out, meta, nil
}
Example #16
0
func jobOceanicTagHandler(r *http.Request, f *oldfdb.Flight) (string, error) {
	c := appengine.NewContext(r)
	str := ""

	if f.HasTag("OCEANIC") {
		return "", nil
	}
	if !f.IsOceanic() {
		return "", nil
	}

	// It's oceanic, but missing a tag ... update
	f.Tags[oldfdb.KTagOceanic] = true

	db := oldfgae.FlightDB{C: oldappengine.NewContext(r)}
	if err := db.UpdateFlight(*f); err != nil {
		log.Errorf(c, "Persist Flight %s: %v", f, err)
		return str, err
	}
	log.Infof(c, "Updated flight %s", f)
	str += fmt.Sprintf("--\nFlight was updated\n")

	return str, nil
}
Example #17
0
// We examine the tags CGI arg, which should be a pipe-delimited set of flight tags.
func flightListHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	db := fdb.FlightDB{C: c}

	tags := []string{}
	if r.FormValue("tags") != "" {
		tags = append(tags, strings.Split(r.FormValue("tags"), "|")...)
	}

	timeRange := regexp.MustCompile("/fdb/(.+)$").ReplaceAllString(r.URL.Path, "$1")
	var flights []ftype.Flight
	var err error

	switch timeRange {
	case "recent":
		flights, err = db.LookupRecentByTags(tags, 200)
	case "today":
		s, e := date.WindowForToday()
		flights, err = db.LookupTimeRangeByTags(tags, s, e)
	case "yesterday":
		s, e := date.WindowForYesterday()
		flights, err = db.LookupTimeRangeByTags(tags, s, e)
	}

	if err != nil {
		c.Errorf(" %s: %v", r.URL.Path, err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	var params = map[string]interface{}{
		"Tags":      tags,
		"TimeRange": timeRange,
		"Flights":   flights2params(flights),
	}
	if err := templates.ExecuteTemplate(w, "fdb-recentlist", params); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
Example #18
0
func report3Handler(w http.ResponseWriter, r *http.Request) {
	if r.FormValue("rep") == "" {
		var params = map[string]interface{}{
			"Yesterday": date.NowInPdt().AddDate(0, 0, -1),
			"Reports":   report.ListReports(),
			"FormUrl":   "/report3/",
			"Waypoints": sfo.ListWaypoints(),
		}
		if err := templates.ExecuteTemplate(w, "report3-form", params); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}

	rep, err := report.SetupReport(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if r.FormValue("debug") != "" {
		str := fmt.Sprintf("Report Options\n\n%s\n", rep.Options)
		w.Header().Set("Content-Type", "text/plain")
		w.Write([]byte(fmt.Sprintf("OK\n\n%s\n", str)))
		return
	}

	//airframes := ref.NewAirframeCache(c)
	client := newurlfetch.Client(newappengine.NewContext(r))
	metars, err := metar.FetchFromNOAA(client, "KSFO",
		rep.Start.AddDate(0, 0, -1), rep.End.AddDate(0, 0, 1))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	v1idspecs := []string{}
	v2idspecs := []string{}

	v1idspecComplement := []string{}

	reportFunc := func(oldF *oldfdb.Flight) {
		newF, err := oldF.V2()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		} else {
			newF.ComputeIndicatedAltitudes(metars)
			if included, err := rep.Process(newF); err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
			} else if included {
				v1idspecs = append(v1idspecs, oldF.UniqueIdentifier())
				v2idspecs = append(v2idspecs, newF.IdSpec())
			} else {
				v1idspecComplement = append(v1idspecComplement, oldF.UniqueIdentifier())
			}
		}
	}

	tags := tagList(rep.Options)

	db := oldfgae.FlightDB{C: oldappengine.Timeout(oldappengine.NewContext(r), 600*time.Second)}
	s, e := rep.Start, rep.End
	if err := db.LongIterWith(db.QueryTimeRangeByTags(tags, s, e), reportFunc); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	postButtons := ButtonPOST(fmt.Sprintf("%d Matches as a VectorMap", len(v1idspecs)),
		fmt.Sprintf("/fdb/trackset2?%s", rep.ToCGIArgs()), v1idspecs)
	postButtons += ButtonPOST(fmt.Sprintf("%d Non-matches as a VectorMap", len(v1idspecComplement)),
		fmt.Sprintf("/fdb/trackset2?%s", rep.ToCGIArgs()), v1idspecComplement)
	if rep.Name == "sfoclassb" {
		postButtons += ButtonPOST(fmt.Sprintf("%d Matches as ClassBApproaches", len(v1idspecs)),
			fmt.Sprintf("/fdb/approach2?%s", rep.ToCGIArgs()), v1idspecs)
		// This is kinda useless, as it isn't limited to SERFR1 things
		postButtons += ButtonPOST(fmt.Sprintf("%d Non-matches as ClassBApproaches", len(v1idspecComplement)),
			fmt.Sprintf("/fdb/approach2?%s", rep.ToCGIArgs()), v1idspecComplement)

		postButtons += ButtonPOST(fmt.Sprintf("%d Matches as ClassBApproaches (delta)",
			len(v1idspecs)), fmt.Sprintf("/fdb/approach2?%s&colorby=delta", rep.ToCGIArgs()), v1idspecs)
		// This is kinda useless, as it isn't limited to SERFR1 things
		postButtons += ButtonPOST(fmt.Sprintf("%d Non-matches as ClassBApproaches (delta)",
			len(v1idspecComplement)), fmt.Sprintf("/fdb/approach2?%s&colorby=delta",
			rep.ToCGIArgs()), v1idspecComplement)
	}

	var params = map[string]interface{}{
		"R":           rep,
		"Metadata":    rep.MetadataTable(),
		"PostButtons": template.HTML(postButtons),
		"OptStr":      template.HTML(fmt.Sprintf("<pre>%s</pre>\n", rep.Options)),
		"IdSpecs":     template.HTML(strings.Join(v1idspecs, ",")),
	}
	if err := templates.ExecuteTemplate(w, "report3-results", params); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

}
Example #19
0
func maybeMemcache(fdb *fdb.FlightDB, queryEnd time.Time) {
	if time.Now().Sub(queryEnd) > time.Hour {
		fdb.Memcache = true
	}
}
Example #20
0
func lookupHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	db := fdb.FlightDB{C: c}
	id := r.FormValue("id")

	if f, err2 := db.LookupById(id); err2 != nil {
		c.Errorf(" /mdb/lookup: %v", err2)
		http.Error(w, err2.Error(), http.StatusInternalServerError)

	} else if f == nil {
		http.Error(w, fmt.Sprintf("id=%s not found", id), http.StatusInternalServerError)

	} else {
		c.Infof("Tags: %v, Tracks: %v", f.TagList(), f.TrackList())
		_, classBTrack := f.SFOClassB("", nil)

		f.Analyse() // Repopulate the flight tags; useful when debugging new analysis stuff

		// Todo: collapse all these separate tracks down into the single point/line list thing
		fr24TrackJSVar := classBTrack.ToJSVar()

		// For Flightaware tracks
		//faClassBTrack := fdb.ClassBTrack{}
		faTrackJSVar := template.JS("{}")
		if _, exists := f.Tracks["FA"]; exists == true {
			_, faClassBTrack := f.SFOClassB("FA", nil)
			faTrackJSVar = faClassBTrack.ToJSVar()
			//fr24TrackJSVar = template.JS("{}")
		}

		// For ADS-B tracks !
		adsbTrackJSVar := template.JS("{}")
		if _, exists := f.Tracks["ADSB"]; exists == true {
			_, adsbClassBTrack := f.SFOClassB("ADSB", nil)
			adsbTrackJSVar = adsbClassBTrack.ToJSVar()
		}

		skimTrackJSVar := template.JS("{}")
		if r.FormValue("skim") != "" {
			alttol, _ := strconv.ParseFloat(r.FormValue("alttol"), 64)
			mindist, _ := strconv.ParseFloat(r.FormValue("mindist"), 64)
			skimTrack, _ := f.BestTrack().SkimsToSFO(alttol, mindist, 15.0, 40.0)
			skimTrackJSVar = skimTrack.ToJSVar()
			fr24TrackJSVar = template.JS("{}")
			faTrackJSVar = template.JS("{}")
			adsbTrackJSVar = template.JS("{}")
		}

		mapPoints := []MapPoint{}
		mapLines := []MapLine{}

		// &waypoint=EPICK
		if waypoint := r.FormValue("waypoint"); waypoint != "" {
			//pos := geo.Latlong{37.060312, -121.990814}
			pos := sfo.KFixes[waypoint]
			if itp, err := f.BestTrack().PointOfClosestApproach(pos); err != nil {
				c.Infof(" ** Error: %v", err)
			} else {
				mapPoints = append(mapPoints, MapPoint{Icon: "red", ITP: &itp})
				mapPoints = append(mapPoints, MapPoint{Pos: &itp.Ref, Text: "** Reference point"})
				mapLines = append(mapLines, MapLine{Line: &itp.Line, Color: "#ff8822"})
				mapLines = append(mapLines, MapLine{Line: &itp.Perp, Color: "#ff2288"})
			}
		}

		// &boxes=1
		if r.FormValue("boxes") != "" {
			if true {
				// fr24
				for _, box := range f.Track.AsContiguousBoxes() {
					mapLines = append(mapLines, LatlongTimeBoxToMapLines(box, "#118811")...)
				}
			}
			if t, exists := f.Tracks["FA"]; exists == true {
				for _, box := range t.AsContiguousBoxes() {
					mapLines = append(mapLines, LatlongTimeBoxToMapLines(box, "#1111aa")...)
				}
			}
			if t, exists := f.Tracks["ADSB"]; exists == true {
				for _, box := range t.AsContiguousBoxes() {
					mapLines = append(mapLines, LatlongTimeBoxToMapLines(box, "#aaaa11")...)
				}
			}
		}

		pointsStr := "{\n"
		for i, mp := range mapPoints {
			pointsStr += fmt.Sprintf("    %d: {%s},\n", i, mp.ToJSStr(""))
		}
		pointsJS := template.JS(pointsStr + "  }\n")
		linesStr := "{\n"
		for i, ml := range mapLines {
			linesStr += fmt.Sprintf("    %d: {%s},\n", i, ml.ToJSStr(""))
		}
		linesJS := template.JS(linesStr + "  }\n")

		box := sfo.KBoxSFO120K
		if r.FormValue("report") == "level" {
			box = sfo.KBoxPaloAlto20K
		} else if r.FormValue("report") == "stack" {
			box = sfo.KBoxSFO10K
		}

		var params = map[string]interface{}{
			"F":       f,
			"Legend":  f.Legend(),
			"Oneline": f.String(),
			"Text":    fmt.Sprintf("%#v", f.Id),
			"ClassB":  "",

			"MapsAPIKey":  kGoogleMapsAPIKey,
			"Center":      sfo.KLatlongSERFR1,
			"Zoom":        10,
			"CaptureArea": box,

			"MapsTrack":        fr24TrackJSVar,
			"FlightawareTrack": faTrackJSVar,
			"ADSBTrack":        adsbTrackJSVar,
			"SkimTrack":        skimTrackJSVar,

			"Points": pointsJS,
			"Lines":  linesJS,
		}

		templateName := "fdb-lookup"
		if r.FormValue("map") != "" {
			templateName = "fdb-lookup-map"
		}
		if err7 := templates.ExecuteTemplate(w, templateName, params); err7 != nil {
			http.Error(w, err7.Error(), http.StatusInternalServerError)
		}
	}
}
Example #21
0
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
	}

	c := appengine.NewContext(r)
	db := fdb.FlightDB{C: c, 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.KBoxSFO120K,  // 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)
			}
		}
	}
}
Example #22
0
func debugHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	db := fdb.FlightDB{C: c}
	id := r.FormValue("id")
	blob, f, err := db.GetBlobById(id)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	} else if blob == nil {
		http.Error(w, fmt.Sprintf("id=%s not found", id), http.StatusInternalServerError)
		return
	}

	blob.Flight = []byte{} // Zero this out

	s, e := f.Track.TimesInBox(sfo.KBoxSFO120K)
	log := blob.GestationLog
	blob.GestationLog = ""

	str := fmt.Sprintf("OK\n* Flight found: %s\n* Tracks: %q\n", f, f.TrackList())
	str += fmt.Sprintf("* Points in default track: %d\n", len(f.Track))
	str += fmt.Sprintf("* Default's start/end: %s, %s\n", s, e)
	str += fmt.Sprintf("\n** Gestation log:-\n%s\n", log)
	str += fmt.Sprintf("** Blob:-\n* Id=%s, Icao24=%s\n* Enter/Leave: %s -> %s\n* Tags: %v\n",
		blob.Id, blob.Icao24, blob.EnterUTC, blob.LeaveUTC, blob.Tags)

	v2URL := f.GetV2JsonUrl()
	str += "\n* V2 URL: " + v2URL + "\n"

	str += "\n**** Tracks Before\n\n"
	str += fmt.Sprintf("** %s [DEFAULT]\n", f.Track)
	for name, t := range f.Tracks {
		str += fmt.Sprintf("** %s %s\n", name, t)
	}

	err, deb := f.GetV2ADSBTrack(urlfetch.Client(c))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	str += "\n***\n" + deb

	str += "\n**** Tracks After\n\n"
	str += fmt.Sprintf("** %s [DEFAULT]\n", f.Track)
	for name, t := range f.Tracks {
		str += fmt.Sprintf("** %s %s\n", name, t)
	}

	str += "--\nPersisting ...\n"

	if err := db.UpdateFlight(*f); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	/*

		consistent,debug := f.TracksAreConsistentDebug()
		str += fmt.Sprintf("\n** Track consistency (%v)\n\n%s\n", consistent, debug)

		//str += "\n** Default track\n"
		//for _,tp := range f.Track { str += fmt.Sprintf(" * %s\n", tp) }
	*/

	w.Header().Set("Content-Type", "text/plain")
	w.Write([]byte(str))
}
Example #23
0
func classbReport(c appengine.Context, s, e time.Time, opt ReportOptions) ([]ReportRow, ReportMetadata, error) {
	fdb := fdb.FlightDB{C: c}
	maybeMemcache(&fdb, e)
	tags := []string{
		flightdb.KTagReliableClassBViolation,
		flightdb.KTagLocalADSBClassBViolation,
	}

	meta := ReportMetadata{}
	h := histogram.Histogram{} // Only use it for the stats
	rows := []ReportRow{}

	seen := map[string]bool{} // Because we do two passes, we might see same flight twice.

	metars, err := metar.FetchFromNOAA(urlfetch.Client(c), "KSFO",
		s.Add(-6*time.Hour), e.Add(6*time.Hour))
	if err != nil {
		return rows, meta, err
	}

	reportFunc := func(f *flightdb.Flight) {
		if _, exists := seen[f.UniqueIdentifier()]; exists {
			return
		} else {
			seen[f.UniqueIdentifier()] = true
		}

		bestTrack := "FA"
		if f.HasTag(flightdb.KTagLocalADSBClassBViolation) {
			bestTrack = "ADSB"
		}

		_, cbt := f.SFOClassB(bestTrack, metars)

		tmpRows := []ReportRow{}

		seq := 0
		for _, cbtp := range cbt {
			if cbtp.A.IsViolation() {
				fClone := f.ShallowCopy()
				tmpRows = append(tmpRows, CBRow{seq, flight2Url(*fClone), *fClone, cbtp.TP, cbtp.A})
				seq++
			}
		}

		if len(tmpRows) == 0 {
			return
		}

		worstCBRow := tmpRows[0].(CBRow)
		if seq > 0 {
			// Select the worst row
			n, belowBy := 0, 0.0
			for i, row := range tmpRows {
				if row.(CBRow).A.BelowBy > belowBy {
					n, belowBy = i, row.(CBRow).A.BelowBy
				}
			}
			worstCBRow = tmpRows[n].(CBRow)
			worstCBRow.Seq = 0 // fake this out for the webpage
		}

		if opt.ClassB_LocalDataOnly && !f.HasTag(flightdb.KTagLocalADSBClassBViolation) {
			meta["[C] -- Skippped; not local - "+worstCBRow.TP.LongSource()]++
		} else {
			meta["[C] -- Detected via "+worstCBRow.TP.LongSource()]++
			h.Add(histogram.ScalarVal(worstCBRow.A.BelowBy))

			if opt.ClassB_OnePerFlight {
				rows = append(rows, worstCBRow)
			} else {
				rows = append(rows, tmpRows...)
			}
		}
	}

	// Need to do multiple passes, because of tagA-or-tagB sillness
	// In each case, limit to SERFR1 flights
	for _, tag := range tags {
		theseTags := []string{tag, flightdb.KTagSERFR1}
		if err := fdb.IterWith(fdb.QueryTimeRangeByTags(theseTags, s, e), reportFunc); err != nil {
			return nil, nil, err
		}
	}

	if n, err := fdb.CountTimeRangeByTags([]string{flightdb.KTagSERFR1}, s, e); err != nil {
		return nil, nil, err
	} else {
		meta["[A] Total SERFR1 Flights"] = float64(n)
	}

	if stats, valid := h.Stats(); valid {
		meta["[B] Num violating flights"] = float64(stats.N)
		meta["[D] Mean violation below Class B floor"] = float64(int(stats.Mean))
		meta["[D] Stddev"] = float64(int(stats.Stddev))
	} else {
		meta["[B] Num violating flights"] = 0.0
	}

	return rows, meta, nil
}
Example #24
0
func serfr1ComplaintsReport(c appengine.Context, s, e time.Time, opt ReportOptions) ([]ReportRow, ReportMetadata, error) {
	fdb := fdb.FlightDB{C: c}
	maybeMemcache(&fdb, e)
	cdb := complaintdb.ComplaintDB{C: c, Memcache: true}
	meta := ReportMetadata{}

	memKey := fmt.Sprintf("serfr1complaintsreport:%s:%d-%d", s.Unix(), e.Unix())

	if rows, meta, err := reportFromMemcache(c, memKey); err == nil {
		return rows, meta, err
	}

	if complaints, err := cdb.GetComplaintsInSpan(s, e); err != nil {
		return nil, nil, err

	} else {
		meta["[B] Total disturbance reports"] = float64(len(complaints))

		nFlights := 0
		nFpC := map[string]int{} // num flights per carrier
		nCpC := map[string]int{} // num complaints per carrier

		// Aggregate complaints per flightnumber (as seen from complaints)
		nC, nSB, nWC := map[string]int{}, map[string]int{}, map[string]int{}
		for _, comp := range complaints {
			if k := comp.AircraftOverhead.FlightNumber; k != "" {
				nC[k] += 1
				nWC[k] += comp.Loudness
				if comp.HeardSpeedbreaks {
					nSB[k] += 1
					nWC[k] += 4
				}
			}
		}

		rows := []SCRow{}
		reportFunc := func(f *flightdb.Flight) {
			nFlights++

			carrier := f.Id.Designator.IATAAirlineDesignator
			if carrier != "" {
				nFpC[carrier] += 1
			}

			if k := f.Id.Designator.String(); k != "" {
				if carrier != "" {
					nCpC[carrier] += nC[k]
				}
				fClone := f.ShallowCopy()
				scRow := SCRow{
					NumComplaints:      nC[k],
					NumSpeedbrakes:     nSB[k],
					WeightedComplaints: nWC[k],
					F:                  *fClone,
				}
				rows = append(rows, scRow)
				meta["[B] SERFR1 disturbance reports"] += float64(nC[k])
			}
		}

		tags := []string{flightdb.KTagSERFR1}
		if err := fdb.IterWith(fdb.QueryTimeRangeByTags(tags, s, e), reportFunc); err != nil {
			return nil, nil, err
		}

		meta["[A] Total flights we saw on SERFR1"] += float64(nFlights)
		meta["[C] Average number of reports per overflight"] =
			float64(int64(float64(len(complaints)) / float64(nFlights)))

		sort.Sort(SCRowByNumComplaints(rows))
		out := []ReportRow{}
		for _, r := range rows {
			out = append(out, r)
		}

		bestCarrier, worstCarrier := "", ""
		bestScore, worstScore := 999, -1
		for carrier, nFlights := range nFpC {
			if nFlights < 3 {
				continue
			}
			cPerFlight := nCpC[carrier] / nFlights
			if cPerFlight < bestScore {
				bestCarrier, bestScore = carrier, cPerFlight
			}
			if cPerFlight > worstScore {
				worstCarrier, worstScore = carrier, cPerFlight
			}
		}

		meta["[D] Worst airline (average reports per overflight) - "+worstCarrier] = float64(worstScore)
		meta["[E] Best airline (average reports per overflight) - "+bestCarrier] = float64(bestScore)

		// reportToMemcache(c, out, meta, memKey)
		return out, meta, nil
	}
}
Example #25
0
func addflightHandler(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)

	log := fmt.Sprintf("* addFlightHandler invoked: %s\n", time.Now().UTC())

	fsStr := r.FormValue("flightsnapshot")
	fs := ftype.FlightSnapshot{}
	if err := fs.Base64Decode(fsStr); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	fr24Id := fs.F.Id.ForeignKeys["fr24"] // This is the only field we take from the
	log += fmt.Sprintf("* fr24 key: %s\n", fr24Id)

	db := fdb.FlightDB{C: c}
	fr24db, err := fdb24.NewFlightDBFr24(urlfetch.Client(c))
	if err != nil {
		c.Errorf(" /mdb/addflight: newdb: %v", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Be idempotent - check to see if this flight has already been recorded
	/* Can't do this check now; the fs.F.Id we cached might be different from the
	   * f.Id we get back from LookupPlayback(), because fr24 reuse their keys.
	   *
		if exists,err := db.FlightExists(fs.F.Id.UniqueIdentifier()); err != nil {
			c.Errorf(" /mdb/addflight: FlightExists check failed: %v", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		} else if exists {
			c.Infof(" /mdb/addflight: already exists %s", fs)
			w.Write([]byte(fmt.Sprintf("Skipped %s\n", fs)))
			return
		}
		log += fmt.Sprintf("* FlightExists('%s') -> false\n", fs.F.Id.UniqueIdentifier())
	*/

	// Now grab an initial flight (with track), from fr24.
	var f *ftype.Flight
	if f, err = fr24db.LookupPlayback(fr24Id); err != nil {
		// c.Errorf(" /mdb/addflight: lookup: %v", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	log += fmt.Sprintf("* the fr24/default track has %d points\n", len(f.Track))

	// Kludge: fr24 keys get reused, so the flight fr24 thinks it refers to might be
	// different than when we cached it. So we do the uniqueness check here, to avoid
	// dupes in the DB. Need a better solution to this.
	if exists, err := db.FlightExists(f.Id.UniqueIdentifier()); err != nil {
		c.Errorf(" /mdb/addflight: FlightExists check failed: %v", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	} else if exists {
		c.Infof(" /mdb/addflight: already exists %s", *f)
		w.Write([]byte(fmt.Sprintf("Skipped %s\n", *f)))
		return
	}
	log += fmt.Sprintf("* FlightExists('%s') -> false\n", f.Id.UniqueIdentifier())

	// Fetch ADSB tracks from the new thing
	err, deb := f.GetV2ADSBTrack(urlfetch.Client(c))
	log += "* fetchV2ADSB\n" + deb
	if err != nil {
		c.Errorf("ADSB fetch err: %v", err)
	}

	// If we have any locally received ADSB fragments for this flight, add them in
	//if err := db.MaybeAddTrackFragmentsToFlight(f); err != nil {
	//	c.Errorf(" /mdb/addflight: addTrackFrags(%s): %v", f.Id, err)
	//}

	f.AnalyseFlightPath() // Takes a coarse look at the flight path
	log += fmt.Sprintf("* Initial tags: %v\n", f.TagList())

	// For flights on the SERFR1 or BRIXX1 approaches, fetch a flightaware track
	if f.HasTag(ftype.KTagSERFR1) || f.HasTag(ftype.KTagBRIXX) {
		u, p := kFlightawareAPIUsername, kFlightawareAPIKey
		if err := fdbfa.AddFlightAwareTrack(urlfetch.Client(c), f, u, p); err != nil {
			c.Errorf(" /mdb/addflight: addflightaware: %v", err)
		}
	}

	f.Analyse()

	if err := db.PersistFlight(*f, log); err != nil {
		c.Errorf(" /mdb/addflight: persist: %v", err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	// Success !
	w.Write([]byte(fmt.Sprintf("Added %s\n", f)))
}