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) } }
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 }