howsmydriving-nyc
Version:
NYC region plug-in for @HowsMyDrivingWA.
1,013 lines (1,005 loc) • 76.2 kB
JavaScript
"use strict";
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spread = (this && this.__spread) || function () {
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
return ar;
};
var _this = this;
Object.defineProperty(exports, "__esModule", { value: true });
require("./util/extend/string-ext");
var crypto = require('crypto');
var http = require('http');
var https = require('https');
var q = require('q');
var rp = require('request-promise');
var url = require('url');
var logging_1 = require("./logging");
var vehicle_lookup_response_1 = require("./models/vehicle_lookup_response");
var fine_data_1 = require("./models/fine_data");
var twitter_1 = require("./constants/twitter");
var L10N_1 = require("./constants/L10N");
var googleMapsClient = require('@google/maps').createClient({
key: process.env.GOOGLE_PLACES_API_KEY,
Promise: Promise
});
var MAX_USERNAME_LENGTH = 17; // 15 + @ plus space after.
// humanized names for violations
var opacvHumanizedNames = {
'': 'No Description Given',
'ALTERING INTERCITY BUS PERMIT': 'Altered Intercity Bus Permit',
'ANGLE PARKING': 'No Angle Parking',
'ANGLE PARKING-COMM VEHICLE': 'No Angle Parking',
'BEYOND MARKED SPACE': 'No Parking Beyond Marked Space',
'BIKE LANE': 'Blocking Bike Lane',
'BLUE ZONE': 'No Parking - Blue Zone',
'BUS LANE VIOLATION': 'Bus Lane Violation',
'BUS PARKING IN LOWER MANHATTAN': 'Bus Parking in Lower Manhattan',
'COMML PLATES-UNALTERED VEHICLE': 'Commercial Plates on Unaltered Vehicle',
CROSSWALK: 'Blocking Crosswalk',
'DETACHED TRAILER': 'Detached Trailer',
'DIVIDED HIGHWAY': 'No Stopping - Divided Highway',
'DOUBLE PARKING': 'Double Parking',
'DOUBLE PARKING-MIDTOWN COMML': 'Double Parking - Midtown Commercial Zone',
'ELEVATED/DIVIDED HIGHWAY/TUNNL': 'No Stopping in Tunnel or on Elevated Highway',
'EXCAVATION-VEHICLE OBSTR TRAFF': 'No Stopping - Adjacent to Street Construction',
'EXPIRED METER': 'Expired Meter',
'EXPIRED METER-COMM METER ZONE': 'Expired Meter - Commercial Meter Zone',
'EXPIRED MUNI METER': 'Expired Meter',
'EXPIRED MUNI MTR-COMM MTR ZN': 'Expired Meter - Commercial Meter Zone',
'FAIL TO DISP. MUNI METER RECPT': 'Failure to Display Meter Receipt',
'FAIL TO DSPLY MUNI METER RECPT': 'Failure to Display Meter Receipt',
'FAILURE TO DISPLAY BUS PERMIT': 'Failure to Display Bus Permit',
'FAILURE TO STOP AT RED LIGHT': 'Failure to Stop at Red Light',
'FEEDING METER': 'Feeding Meter',
'FIRE HYDRANT': 'Fire Hydrant',
'FRONT OR BACK PLATE MISSING': 'Front or Back Plate Missing',
IDLING: 'Idling',
'IMPROPER REGISTRATION': 'Improper Registration',
"INSP STICKER-MUTILATED/C'FEIT": 'Inspection Sticker Mutilated or Counterfeit',
'INSP. STICKER-EXPIRED/MISSING': 'Inspection Sticker Expired or Missing',
INTERSECTION: 'No Stopping - Intersection',
'MARGINAL STREET/WATER FRONT': 'No Parking on Marginal Street or Waterfront',
'MIDTOWN PKG OR STD-3HR LIMIT': 'Midtown Parking or Standing - 3 Hour Limit',
MISCELLANEOUS: 'Miscellaneous',
'MISSING EQUIPMENT': 'Missing Required Equipment',
'NGHT PKG ON RESID STR-COMM VEH': 'No Nighttime Parking on Residential Street - Commercial Vehicle',
'NIGHTTIME STD/ PKG IN A PARK': 'No Nighttime Standing or Parking in a Park',
'NO MATCH-PLATE/STICKER': 'Plate and Sticker Do Not Match',
'NO OPERATOR NAM/ADD/PH DISPLAY': 'Failure to Display Operator Information',
'NO PARKING-DAY/TIME LIMITS': 'No Parking - Day/Time Limits',
'NO PARKING-EXC. AUTH. VEHICLE': 'No Parking - Except Authorized Vehicles',
'NO PARKING-EXC. HNDICAP PERMIT': 'No Parking - Except Disability Permit',
'NO PARKING-EXC. HOTEL LOADING': 'No Parking - Except Hotel Loading',
'NO PARKING-STREET CLEANING': 'No Parking - Street Cleaning',
'NO PARKING-TAXI STAND': 'No Parking - Taxi Stand',
'NO STANDING EXCP D/S': 'No Standing - Except Department of State',
'NO STANDING EXCP DP': 'No Standing - Except Diplomat',
'NO STANDING-BUS LANE': 'No Standing - Bus Lane',
'NO STANDING-BUS STOP': 'No Standing - Bus Stop',
'NO STANDING-COMM METER ZONE': 'No Standing - Commercial Meter Zone',
'NO STANDING-COMMUTER VAN STOP': 'No Standing - Commuter Van Stop',
'NO STANDING-DAY/TIME LIMITS': 'No Standing - Day/Time Limits',
'NO STANDING-EXC. AUTH. VEHICLE': 'No Standing - Except Authorized Vehicle',
'NO STANDING-EXC. TRUCK LOADING': 'No Standing - Except Truck Loading',
'NO STANDING-FOR HIRE VEH STOP': 'No Standing - For Hire Vehicle Stop',
'NO STANDING-HOTEL LOADING': 'No Standing - Hotel Loading',
'NO STANDING-OFF-STREET LOT': 'No Standing - Off-Street Lot',
'NO STANDING-SNOW EMERGENCY': 'No Standing - Snow Emergency',
'NO STANDING-TAXI STAND': 'No Standing - Taxi Stand',
'NO STD(EXC TRKS/GMTDST NO-TRK)': 'No Standing - Except Trucks in Garment District',
'NO STOP/STANDNG EXCEPT PAS P/U': 'No Stopping or Standing Except for Passenger Pick-Up',
'NO STOPPING-DAY/TIME LIMITS': 'No Stopping - Day/Time Limits',
'NON-COMPLIANCE W/ POSTED SIGN': 'Non-Compliance with Posted Sign',
'OBSTRUCTING DRIVEWAY': 'Obstructing Driveway',
'OBSTRUCTING TRAFFIC/INTERSECT': 'Obstructing Traffic or Intersection',
'OT PARKING-MISSING/BROKEN METR': 'Overtime Parking at Missing or Broken Meter',
OTHER: 'Other',
'OVERNIGHT TRACTOR TRAILER PKG': 'Overnight Parking of Tractor Trailer',
'OVERTIME PKG-TIME LIMIT POSTED': 'Overtime Parking - Time Limit Posted',
'OVERTIME STANDING DP': 'Overtime Standing - Diplomat',
'OVERTIME STDG D/S': 'Overtime Standing - Department of State',
'PARKED BUS-EXC. DESIG. AREA': 'Bus Parking Outside of Designated Area',
'PEDESTRIAN RAMP': 'Blocking Pedestrian Ramp',
'PHTO SCHOOL ZN SPEED VIOLATION': 'School Zone Speed Camera Violation',
'PKG IN EXC. OF LIM-COMM MTR ZN': 'Parking in Excess of Limits - Commercial Meter Zone',
'PLTFRM LFTS LWRD POS COMM VEH': 'Commercial Vehicle Platform Lifts in Lowered Position',
'RAILROAD CROSSING': 'No Stopping - Railroad Crossing',
"REG STICKER-MUTILATED/C'FEIT": 'Registration Sticker Mutilated or Counterfeit',
'REG. STICKER-EXPIRED/MISSING': 'Registration Sticker Expired or Missing',
'REMOVE/REPLACE FLAT TIRE': 'Replacing Flat Tire on Major Roadway',
'SAFETY ZONE': 'No Standing - Safety Zone',
'SELLING/OFFERING MCHNDSE-METER': 'Selling or Offering Merchandise From Metered Parking',
SIDEWALK: 'Parked on Sidewalk',
'STORAGE-3HR COMMERCIAL': 'Street Storage of Commercial Vehicle Over 3 Hours',
'TRAFFIC LANE': 'No Stopping - Traffic Lane',
'TUNNEL/ELEVATED/ROADWAY': 'No Stopping in Tunnel or on Elevated Highway',
'UNALTERED COMM VEH-NME/ADDRESS': 'Commercial Plates on Unaltered Vehicle',
'UNALTERED COMM VEHICLE': 'Commercial Plates on Unaltered Vehicle',
'UNAUTHORIZED BUS LAYOVER': 'Bus Layover in Unauthorized Location',
'UNAUTHORIZED PASSENGER PICK-UP': 'Unauthorized Passenger Pick-Up',
'VACANT LOT': 'No Parking - Vacant Lot',
'VEH-SALE/WSHNG/RPRNG/DRIVEWAY': 'No Parking on Street to Wash or Repair Vehicle',
'VEHICLE FOR SALE(DEALERS ONLY)': 'No Parking on Street to Display Vehicle for Sale',
'VIN OBSCURED': 'Vehicle Identification Number Obscured',
'WASH/REPAIR VEHCL-REPAIR ONLY': 'No Parking on Street to Wash or Repair Vehicle',
'WRONG WAY': 'No Parking Opposite Street Direction'
};
// humanized names for violations
var fyHumanizedNames = {
'01': 'Failure to Display Bus Permit',
'02': 'Failure to Display Operator Information',
'03': 'Unauthorized Passenger Pick-Up',
'04': 'Bus Parking in Lower Manhattan - Exceeded 3-Hour limit',
'04A': 'Bus Parking in Lower Manhattan - Non-Bus',
'04B': 'Bus Parking in Lower Manhattan - No Permit',
'06': 'Overnight Parking of Tractor Trailer',
'08': 'Idling',
'09': 'Obstructing Traffic or Intersection',
'10': 'No Stopping or Standing Except for Passenger Pick-Up',
'11': 'No Parking - Except Hotel Loading',
'12': 'No Standing - Snow Emergency',
'13': 'No Standing - Taxi Stand',
'14': 'No Standing - Day/Time Limits',
'16': 'No Standing - Except Truck Loading/Unloading',
'16A': 'No Standing - Except Truck Loading/Unloading',
'17': 'No Parking - Except Authorized Vehicles',
'18': 'No Standing - Bus Lane',
'19': 'No Standing - Bus Stop',
'20': 'No Parking - Day/Time Limits',
'20A': 'No Parking - Day/Time Limits',
'21': 'No Parking - Street Cleaning',
'22': 'No Parking - Except Hotel Loading',
'23': 'No Parking - Taxi Stand',
'24': 'No Parking - Except Authorized Vehicles',
'25': 'No Standing - Commuter Van Stop',
'26': 'No Standing - For Hire Vehicle Stop',
'27': 'No Parking - Except Disability Permit',
'28': 'Overtime Standing - Diplomat',
'29': 'Altered Intercity Bus Permit',
'30': 'No Stopping/Standing',
'31': 'No Standing - Commercial Meter Zone',
'32': 'Overtime Parking at Missing or Broken Meter',
'32A': 'Overtime Parking at Missing or Broken Meter',
'33': 'Feeding Meter',
'35': 'Selling or Offering Merchandise From Metered Parking',
'37': 'Expired Meter',
'38': 'Failure to Display Meter Receipt',
'39': 'Overtime Parking - Time Limit Posted',
'40': 'Fire Hydrant',
'42': 'Expired Meter - Commercial Meter Zone',
'43': 'Expired Meter - Commercial Meter Zone',
'44': 'Overtime Parking - Commercial Meter Zone',
'45': 'No Stopping - Traffic Lane',
'46': 'Double Parking',
'46A': 'Double Parking',
'46B': 'Double Parking - Within 100 ft. of Loading Zone',
'47': 'Double Parking - Midtown Commercial Zone',
'47A': 'Double Parking - Angle Parking',
'48': 'Blocking Bike Lane',
'49': 'No Stopping - Adjacent to Street Construction',
'50': 'Blocking Crosswalk',
'51': 'Parked on Sidewalk',
'52': 'No Stopping - Intersection',
'53': 'No Standing - Safety Zone',
'55': 'No Stopping in Tunnel or on Elevated Highway',
'56': 'No Stopping - Divided Highway',
'57': 'No Parking - Blue Zone',
'58': 'No Parking on Marginal Street or Waterfront',
'59': 'No Angle Parking',
'60': 'No Angle Parking',
'61': 'No Parking Opposite Street Direction',
'62': 'No Parking Beyond Marked Space',
'63': 'No Nighttime Standing or Parking in a Park',
'64': 'No Standing - Consul or Diplomat',
'65': 'Overtime Standing - Consul or Diplomat Over 30 Minutes',
'66': 'Detached Trailer',
'67': 'Blocking Pedestrian Ramp',
'68': 'Non-Compliance with Posted Sign',
'69': 'Failure to Display Meter Receipt',
'70': 'Registration Sticker Expired or Missing',
'70A': 'Registration Sticker Expired or Missing',
'70B': 'Improper Display of Registration',
'71': 'Inspection Sticker Expired or Missing',
'71A': 'Inspection Sticker Expired or Missing',
'71B': 'Improper Safety Sticker',
'72': 'Inspection Sticker Mutilated or Counterfeit',
'72A': 'Inspection Sticker Mutilated or Counterfeit',
'73': 'Registration Sticker Mutilated or Counterfeit',
'73A': 'Registration Sticker Mutilated or Counterfeit',
'74': 'Front or Back Plate Missing',
'74A': 'Improperly Displayed Plate',
'74B': 'Covered Plate',
'75': 'Plate and Sticker Do Not Match',
'77': 'Bus Parking Outside of Designated Area',
'78': 'Nighttime Parking on Residential Street - Commercial Vehicle',
'79': 'Bus Layover in Unauthorized Location',
'80': 'Missing Required Equipment',
'81': 'No Standing - Except Diplomat',
'82': 'Commercial Plates on Unaltered Vehicle',
'83': 'Improper Registration',
'84': 'Commercial Vehicle Platform Lifts in Lowered Position',
'85': 'Street Storage of Commercial Vehicle Over 3 Hours',
'86': 'Midtown Parking or Standing - 3 Hour Limit',
'89': 'No Standing - Except Trucks in Garment District',
'91': 'No Parking on Street to Display Vehicle for Sale',
'92': 'No Parking on Street to Wash or Repair Vehicle',
'93': 'Replacing Flat Tire on Major Roadway',
'96': 'No Stopping - Railroad Crossing',
'98': 'Obstructing Driveway',
'01-No Intercity Pmt Displ': 'Failure to Display Bus Permit',
'02-No operator N/A/PH': 'Failure to Display Operator Information',
'03-Unauth passenger pick-up': 'Unauthorized Passenger Pick-Up',
'04-Downtown Bus Area,3 Hr Lim': 'Bus Parking in Lower Manhattan - Exceeded 3-Hour limit',
'04A-Downtown Bus Area,Non-Bus': 'Bus Parking in Lower Manhattan - Non-Bus',
'04A-Downtown Bus Area, Non-Bus': 'Bus Parking in Lower Manhattan - Non-Bus',
'04B-Downtown Bus Area,No Prmt': 'Bus Parking in Lower Manhattan - No Permit',
'06-Nighttime PKG (Trailer)': 'Overnight Parking of Tractor Trailer',
'08-Engine Idling': 'Idling',
'09-Blocking the Box': 'Obstructing Traffic or Intersection',
'10-No Stopping': 'No Stopping or Standing Except for Passenger Pick-Up',
'11-No Stand (exc hotel load)': 'No Parking - Except Hotel Loading',
'12-No Stand (snow emergency)': 'No Standing - Snow Emergency',
'13-No Stand (taxi stand)': 'No Standing - Taxi Stand',
'14-No Standing': 'No Standing - Day/Time Limits',
'16-No Std (Com Veh) Com Plate': 'No Standing - Except Truck Loading/Unloading',
'16A-No Std (Com Veh) Non-COM': 'No Standing - Except Truck Loading/Unloading',
'17-No Stand (exc auth veh)': 'No Parking - Except Authorized Vehicles',
'18-No Stand (bus lane)': 'No Standing - Bus Lane',
'19-No Stand (bus stop)': 'No Standing - Bus Stop',
'20-No Parking (Com Plate)': 'No Parking - Day/Time Limits',
'20A-No Parking (Non-COM)': 'No Parking - Day/Time Limits',
'21-No Parking (street clean)': 'No Parking - Street Cleaning',
'22-No Parking (exc hotel load)': 'No Parking - Except Hotel Loading',
'23-No Parking (taxi stand)': 'No Parking - Taxi Stand',
'24-No Parking (exc auth veh)': 'No Parking - Except Authorized Vehicles',
'25-No Stand (commutr van stop)': 'No Standing - Commuter Van Stop',
'26-No Stnd (for-hire veh only)': 'No Standing - For Hire Vehicle Stop',
'27-No Parking (exc handicap)': 'No Parking - Except Disability Permit',
'28-O/T STD,PL/Con,0 Mn, Dec': 'Overtime Standing - Diplomat',
'29-Altered Intercity bus pmt': 'Altered Intercity Bus Permit',
'30-No stopping/standing': 'No Stopping/Standing',
'31-No Stand (Com. Mtr. Zone)': 'No Standing - Commercial Meter Zone',
'32-Overtime PKG-Missing Meter': 'Overtime Parking at Missing or Broken Meter',
'32A Overtime PKG-Broken Meter': 'Overtime Parking at Missing or Broken Meter',
'33-Feeding Meter': 'Feeding Meter',
'35-Selling/Offer Merchandise': 'Selling or Offering Merchandise From Metered Parking',
'37-Expired Muni Meter': 'Expired Meter',
'37-Expired Parking Meter': 'Expired Meter',
'38-Failure to Display Muni Rec': 'Failure to Display Meter Receipt',
'38-Failure to Dsplay Meter Rec': 'Failure to Display Meter Receipt',
'39-Overtime PKG-Time Limt Post': 'Overtime Parking - Time Limit Posted',
'40-Fire Hydrant': 'Fire Hydrant',
'42-Exp. Muni-Mtr (Com. Mtr. Z)': 'Expired Meter - Commercial Meter Zone',
'42-Exp Meter (Com Zone)': 'Expired Meter - Commercial Meter Zone',
'43-Exp. Mtr. (Com. Mtr. Zone)': 'Expired Meter - Commercial Meter Zone',
'44-Exc Limit (Com. Mtr. Zone)': 'Overtime Parking - Commercial Meter Zone',
'45-Traffic Lane': 'No Stopping - Traffic Lane',
'46-Double Parking (Com Plate)': 'Double Parking',
'46A-Double Parking (Non-COM)': 'Double Parking',
'46B-Double Parking (Com-100Ft)': 'Double Parking - Within 100 ft. of Loading Zone',
'47-Double PKG-Midtown': 'Double Parking - Midtown Commercial Zone',
'47A-Angle PKG - Midtown': 'Double Parking - Angle Parking',
'48-Bike Lane': 'Blocking Bike Lane',
'49-Excavation (obstruct traff)': 'No Stopping - Adjacent to Street Construction',
'50-Crosswalk': 'Blocking Crosswalk',
'51-Sidewalk': 'Parked on Sidewalk',
'52-Intersection': 'No Stopping - Intersection',
'53-Safety Zone': 'No Standing - Safety Zone',
'55-Tunnel/Elevated Roadway': 'No Stopping in Tunnel or on Elevated Highway',
'56-Divided Highway': 'No Stopping - Divided Highway',
'57-Blue Zone': 'No Parking - Blue Zone',
'58-Marginal Street/Water Front': 'No Parking on Marginal Street or Waterfront',
'59-Angle PKG-Commer. Vehicle': 'No Angle Parking',
'60-Angle Parking': 'No Angle Parking',
'61-Wrong Way': 'No Parking Opposite Street Direction',
'62-Beyond Marked Space': 'No Parking Beyond Marked Space',
'63-Nighttime STD/PKG in a Park': 'No Nighttime Standing or Parking in a Park',
'64-No STD Ex Con/DPL,D/S Dec': 'No Standing - Consul or Diplomat',
'65-O/T STD,pl/Con,0 Mn,/S': 'Overtime Standing - Consul or Diplomat Over 30 Minutes',
'66-Detached Trailer': 'Detached Trailer',
'67-Blocking Ped. Ramp': 'Blocking Pedestrian Ramp',
'68-Not Pkg. Comp. w Psted Sign': 'Non-Compliance with Posted Sign',
'69-Failure to Disp Muni Recpt': 'Failure to Display Meter Receipt',
'69-Fail to Dsp Prking Mtr Rcpt': 'Failure to Display Meter Receipt',
'70-Reg. Sticker Missing (NYS)': 'Registration Sticker Expired or Missing',
'70A-Reg. Sticker Expired (NYS)': 'Registration Sticker Expired or Missing',
'70B-Impropr Dsply of Reg (NYS)': 'Improper Display of Registration',
'71-Insp. Sticker Missing (NYS': 'Inspection Sticker Expired or Missing',
'71A-Insp Sticker Expired (NYS)': 'Inspection Sticker Expired or Missing',
'71B-Improp Safety Stkr (NYS)': 'Improper Safety Sticker',
'72-Insp Stkr Mutilated': 'Inspection Sticker Mutilated or Counterfeit',
'72A-Insp Stkr Counterfeit': 'Inspection Sticker Mutilated or Counterfeit',
'73-Reg Stkr Mutilated': 'Registration Sticker Mutilated or Counterfeit',
'73A-Reg Stkr Counterfeit': 'Registration Sticker Mutilated or Counterfeit',
'74-Missing Display Plate': 'Front or Back Plate Missing',
'74A-Improperly Displayed Plate': 'Improperly Displayed Plate',
'74B-Covered Plate': 'Covered Plate',
'75-No Match-Plate/Reg. Sticker': 'Plate and Sticker Do Not Match',
'77-Parked Bus (exc desig area)': 'Bus Parking Outside of Designated Area',
'78-Nighttime PKG on Res Street': 'Nighttime Parking on Residential Street - Commercial Vehicle',
'79-Bus Layover': 'Bus Layover in Unauthorized Location',
'80-Missing Equipment (specify)': 'Missing Required Equipment',
'81-No STD Ex C,&D Dec,30 Mn': 'No Standing - Except Diplomat',
'82-Unaltered Commerc Vehicle': 'Commercial Plates on Unaltered Vehicle',
'83-Improper Registration': 'Improper Registration',
'84-Platform lifts in low posit': 'Commercial Vehicle Platform Lifts in Lowered Position',
'85-Storage-3 hour Commercial': 'Street Storage of Commercial Vehicle Over 3 Hours',
'86-Midtown PKG or STD-3 hr lim': 'Midtown Parking or Standing - 3 Hour Limit',
'89-No Stand Exc Com Plate': 'No Standing - Except Trucks in Garment District',
'91-Veh for Sale (Dealer Only)': 'No Parking on Street to Display Vehicle for Sale',
'92-Washing/Repairing Vehicle': 'No Parking on Street to Wash or Repair Vehicle',
'93-Repair Flat Tire (Maj Road)': 'Replacing Flat Tire on Major Roadway',
'96-Railroad Crossing': 'No Stopping - Railroad Crossing',
'98-Obstructing Driveway': 'Obstructing Driveway',
'BUS LANE VIOLATION': 'Bus Lane Violation',
'FAILURE TO STOP AT RED LIGHT': 'Failure to Stop at Red Light',
'Field Release Agreement': 'Field Release Agreement',
'PHTO SCHOOL ZN SPEED VIOLATION': 'School Zone Speed Camera Violation'
};
// mapping humanized naes to violation codes
var namesToCodes = {
'Failure to Display Bus Permit': '01',
'Failure to Display Operator Information': '02',
'Unauthorized Passenger Pick-Up': '03',
'Bus Parking in Lower Manhattan - Exceeded 3-Hour limit': '04',
'Bus Parking in Lower Manhattan - Non-Bus': '04A',
'Bus Parking in Lower Manhattan - No Permit': '04B',
'Bus Lane Violation': '05',
'Overnight Parking of Tractor Trailer': '06',
'Failure to Stop at Red Light': '07',
Idling: '08',
'Obstructing Traffic or Intersection': '09',
'No Stopping or Standing Except for Passenger Pick-Up': '10',
'No Parking - Except Hotel Loading': '22',
'No Standing - Snow Emergency': '12',
'No Standing - Taxi Stand': '13',
'No Standing - Day/Time Limits': '14',
'No Standing - Except Truck Loading/Unloading': '16',
'No Parking - Except Authorized Vehicles': '24',
'No Standing - Bus Lane': '18',
'No Standing - Bus Stop': '19',
'No Parking - Day/Time Limits': '20',
'No Parking - Street Cleaning': '21',
'No Parking - Taxi Stand': '23',
'No Standing - Commuter Van Stop': '25',
'No Standing - For Hire Vehicle Stop': '26',
'No Parking - Except Disability Permit': '27',
'Overtime Standing - Diplomat': '28',
'Altered Intercity Bus Permit': '29',
'No Stopping/Standing': '30',
'No Standing - Commercial Meter Zone': '31',
'Overtime Parking at Missing or Broken Meter': '32',
'Feeding Meter': '33',
'Selling or Offering Merchandise From Metered Parking': '35',
'School Zone Speed Camera Violation': '36',
'Expired Meter': '37',
'Failure to Display Meter Receipt': '69',
'Overtime Parking - Time Limit Posted': '39',
'Fire Hydrant': '40',
'Expired Meter - Commercial Meter Zone': '43',
'Overtime Parking - Commercial Meter Zone': '44',
'No Stopping - Traffic Lane': '45',
'Double Parking': '46',
'Double Parking - Within 100 ft. of Loading Zone': '46B',
'Double Parking - Midtown Commercial Zone': '47',
'Double Parking - Angle Parking': '47A',
'Blocking Bike Lane': '48',
'No Stopping - Adjacent to Street Construction': '49',
'Blocking Crosswalk': '50',
'Parked on Sidewalk': '51',
'No Stopping - Intersection': '52',
'No Standing - Safety Zone': '53',
'No Stopping in Tunnel or on Elevated Highway': '55',
'No Stopping - Divided Highway': '56',
'No Parking - Blue Zone': '57',
'No Parking on Marginal Street or Waterfront': '58',
'No Angle Parking': '60',
'No Parking Opposite Street Direction': '61',
'No Parking Beyond Marked Space': '62',
'No Nighttime Standing or Parking in a Park': '63',
'No Standing - Consul or Diplomat': '64',
'Overtime Standing - Consul or Diplomat Over 30 Minutes': '65',
'Detached Trailer': '66',
'Blocking Pedestrian Ramp': '67',
'Non-Compliance with Posted Sign': '68',
'Registration Sticker Expired or Missing': '70',
'Improper Display of Registration': '70B',
'Inspection Sticker Expired or Missing': '71',
'Improper Safety Sticker': '71B',
'Inspection Sticker Mutilated or Counterfeit': '72',
'Registration Sticker Mutilated or Counterfeit': '73',
'Front or Back Plate Missing': '74',
'Improperly Displayed Plate': '74A',
'Covered Plate': '74B',
'Plate and Sticker Do Not Match': '75',
'Bus Parking Outside of Designated Area': '77',
'Nighttime Parking on Residential Street - Commercial Vehicle': '78',
'Bus Layover in Unauthorized Location': '79',
'Missing Required Equipment': '80',
'No Standing - Except Diplomat': '81',
'Commercial Plates on Unaltered Vehicle': '82',
'Improper Registration': '83',
'Commercial Vehicle Platform Lifts in Lowered Position': '84',
'Street Storage of Commercial Vehicle Over 3 Hours': '85',
'Midtown Parking or Standing - 3 Hour Limit': '86',
'No Standing - Except Trucks in Garment District': '89',
'No Parking on Street to Display Vehicle for Sale': '91',
'No Parking on Street to Wash or Repair Vehicle': '92',
'Replacing Flat Tire on Major Roadway': '93',
'No Stopping - Railroad Crossing': '96',
'Obstructing Driveway': '98'
};
var stateAbbrRegex = /^(99|AB|AK|AL|AR|AZ|BC|CA|CO|CT|DC|DE|DP|FL|FM|FO|GA|GU|GV|HI|IA|ID|IL|IN|KS|KY|LA|MA|MB|MD|ME|MI|MN|MO|MP|MS|MT|MX|NB|NC|ND|NE|NF|NH|NJ|NM|NS|NT|NV|NY|OH|OK|ON|OR|PA|PE|PR|PW|QC|RI|SC|SD|SK|TN|TX|UT|VA|VI|VT|WA|WI|WV|WY|YT)$/;
var registrationTypesRegex = /^(AGC|AGR|AMB|APP|ARG|ATD|ATV|AYG|BOB|BOT|CBS|CCK|CHC|CLG|CMB|CME|CMH|COM|CSP|DLR|FAR|FPW|GAC|GSM|HAC|HAM|HIR|HIS|HOU|HSM|IRP|ITP|JCA|JCL|JSC|JWV|LMA|LMB|LMC|LOC|LTR|LUA|MCD|MCL|MED|MOT|NLM|NYA|NYC|NYS|OMF|OML|OMO|OMR|OMS|OMT|OMV|ORC|ORG|ORM|PAS|PHS|PPH|PSD|RGC|RGL|SCL|SEM|SNO|SOS|SPC|SPO|SRF|SRN|STA|STG|SUP|THC|TOW|TRA|TRC|TRL|USC|USS|VAS|VPL|WUG)$/;
var counties = {
Bronx: 'Bronx',
Brook: 'Brooklyn',
BX: 'Bronx',
Bx: 'Bronx',
BK: 'Brooklyn',
Bk: 'Brooklyn',
K: 'Brooklyn',
KINGS: 'Brooklyn',
MAH: 'Manhattan',
MANHA: 'Manhattan',
MN: 'Manhattan',
NEUY: 'Manhattan',
NY: 'Manhattan',
PBX: 'Bronx',
PK: 'Brooklyn',
PNY: 'Manhattan',
Q: 'Queens',
QN: 'Queens',
QNS: 'Queens',
Queen: 'Queens',
R: 'Staten Island',
Rich: 'Staten Island',
ST: 'Staten Island'
};
var issuingAgencies = {
'DEPARTMENT OF BUSINESS SERVICES': 'NYC SBS',
'DEPARTMENT OF SANITATION': 'DSNY',
'DEPARTMENT OF TRANSPORTATION': 'NYC DOT',
'Fire Department': 'FDNY',
'HOUSING AUTHORITY': 'NYCHA',
'LONG ISLAND RAILROAD': 'LIRR',
'METRO NORTH RAILROAD POLICE': 'MNRR',
'NYC OFFICE OF THE SHERIFF': 'NYC Sheriff',
'NYC TRANSIT AUTHORITY MANAGERS': 'NYCTA',
'NYS COURT OFFICERS': 'NYS Courts',
'NYS PARKS POLICE': 'NYS Parks',
'OTHER/UNKNOWN AGENCIES': 'other',
'PARKING CONTROL UNIT': 'NYC DOT',
'PARKS DEPARTMENT': 'NYC Parks',
'POLICE DEPARTMENT': 'NYPD',
'PORT AUTHORITY': 'PANYNJ',
'TAXI AND LIMOUSINE COMMISSION': 'TLC',
TRAFFIC: 'NYPD Traffic',
'TRANSIT AUTHORITY': 'NYCTA',
'TRIBOROUGH BRIDGE AND TUNNEL POLICE': 'TBTA',
T: 'NYPD Traffic',
V: 'NYC DOT'
};
/*
let initializeConnection = config => {
let addDisconnectHandler = connection => {
connection.on('error', error => {
if (error instanceof Error) {
let error_code: string = undefined;
let is_fatal: boolean = false;
if (error.hasOwnProperty('code')) {
error_code = (error as any)['code'];
}
if (error.hasOwnProperty('fatal')) {
is_fatal = (error as any)['fatal'];
}
if (error_code === 'PROTOCOL_CONNECTION_LOST') {
console.error(error.stack);
console.log('Lost connection. Reconnecting...');
initializeConnection(connection.config);
} else if (is_fatal) {
throw error;
}
}
});
};
var connection = mysql.createConnection(config);
connection.promiseQuery = (sql, values) => {
return new Promise((resolve, reject) => {
return connection.query(sql, values, (error, results, fields) => {
if (error) reject(error);
if (results) resolve(results);
});
});
};
// Add handlers.
addDisconnectHandler(connection);
connection.connect();
return connection;
};
*/
var detectPlateTypes = function (potentialPlateTypeString) {
if (potentialPlateTypeString.indexOf(',') != -1) {
var parts = potentialPlateTypeString.split(',');
var bools = parts.map(function (part) { return !(part.match(registrationTypesRegex) == undefined); });
return bools.some(function (bool) { return bool === true; });
}
else {
return !(potentialPlateTypeString.match(registrationTypesRegex) == undefined);
}
};
var detectState = function (potentialStateString) {
return !(potentialStateString.match(stateAbbrRegex) == undefined);
};
var detectVehicles = function (potentialVehicles) {
return potentialVehicles.map(function (plate) {
var vehicle = { original_string: plate };
var parts = plate
.toUpperCase()
.trim()
.split(':');
if ([2, 3].includes(parts.length)) {
var stateBools = parts.map(function (part) { return detectState(part); });
var stateIndex_1 = stateBools.indexOf(true);
var plateTypesBools = parts.map(function (part) { return detectPlateTypes(part); });
var plateTypesIndex_1 = plateTypesBools.indexOf(true);
var haveValidPlate = (parts.length === 2 && stateIndex_1 != -1) ||
(parts.length === 3 && ![plateTypesIndex_1, stateIndex_1].includes(-1));
if (haveValidPlate) {
var plateIndex = __spread(Array(parts.length).keys()).filter(function (part) { return ![stateIndex_1, plateTypesIndex_1].includes(part); })[0];
vehicle['state'] = parts[stateIndex_1];
vehicle['types'] = parts[plateTypesIndex_1];
vehicle['plate'] = parts[plateIndex];
vehicle['valid_plate'] = true;
}
else {
vehicle['valid_plate'] = false;
}
}
else {
vehicle['valid_plate'] = false;
}
return vehicle;
});
};
var findFilterFields = function (fieldsString) {
if (fieldsString == undefined || fieldsString == '')
return {};
var returnFields = {};
var fields = fieldsString.replace(/(\([^)]*\))/g, '').split(',');
fields.forEach(function (field) {
if (fieldsString[fieldsString.indexOf(field) + field.length] == '(') {
var re = new RegExp(field + '\\([\\w|,]*\\)', 'g');
var subfields = fieldsString.match(re) == undefined
? null
: fieldsString.match(re)[0].replace(field, '');
subfields = subfields.substring(1, subfields.length - 1);
if (subfields) {
returnFields[field] = findFilterFields(subfields.replace(/[\(|\)]/g, ''));
}
else if (subfields == '') {
returnFields[field] = {};
}
}
else {
returnFields[field] = {};
}
});
return returnFields;
};
var findMaxCameraViolationsStreak = function (violationTimes) {
if (violationTimes.length) {
var maxStreak_1 = 0;
var streakEnd_1 = null;
var streakStart_1 = null;
violationTimes.forEach(function (date) {
var yearLater = new Date(date).setFullYear(date.getFullYear() + 1);
var yearLongTickets = violationTimes.filter(function (otherDate) { return otherDate >= date && otherDate <= yearLater; });
var thisStreak = yearLongTickets.length;
if (thisStreak > maxStreak_1) {
maxStreak_1 = thisStreak;
streakEnd_1 = yearLongTickets[0];
streakStart_1 = yearLongTickets[yearLongTickets.length - 1];
}
});
return {
max_streak: maxStreak_1,
streak_end: streakEnd_1,
streak_start: streakStart_1
};
}
else {
return null;
}
};
exports.getVehicleResponse = function (vehicle, selectedFields, externalData) {
return new Promise(function (resolve, reject) {
var plate = vehicle.plate;
var state = vehicle.state;
var plateTypes = vehicle.types == undefined
? null
: vehicle.types.split(',').map(function (part) { return part.trim(); });
var lookupSource = externalData.lookup_source;
var fingerprintID = externalData.fingerprint_id;
var mixpanelID = externalData.mixpanel_id;
if (plate && state) {
var apiPromises = makeOpenDataRequests(plate, state, plateTypes);
q.all(apiPromises).then(function (endpointResponses) {
var newPromises = [];
endpointResponses.forEach(function (response) {
newPromises = newPromises.concat(normalizeViolations(JSON.parse(response)));
});
q.all(newPromises).then(function (violations) {
violations = mergeDuplicateViolationRecords(violations);
modifyViolationsForResponse(violations);
var reducer = function (accumulator, currentValue) {
return accumulator + currentValue;
};
var totalFined = violations
.map(function (obj) { return obj.fined || 0; })
.reduce(reducer, 0);
var totalPaid = violations
.map(function (obj) { return obj.paid || 0; })
.reduce(reducer, 0);
var totalReduced = violations
.map(function (obj) { return obj.reduced || 0; })
.reduce(reducer, 0);
var totalOutstanding = violations
.map(function (obj) { return obj.outstanding || 0; })
.reduce(reducer, 0);
var fines = new fine_data_1.FineData({
total_fined: totalFined,
total_paid: totalPaid,
total_reduced: totalReduced,
total_outstanding: totalOutstanding
});
var cameraViolations = violations.filter(function (violation) {
return violation.humanized_description ==
'School Zone Speed Camera Violation' ||
violation.humanized_description == 'Failure to Stop at Red Light';
});
var streakData = findMaxCameraViolationsStreak(cameraViolations.map(function (violation) {
return violation.formatted_time;
}));
var frequencyLookup = {
plate: plate,
state: state
};
var searchQueryString = plateTypes == undefined
? 'select count(*) as frequency from plate_lookups where plate = ? and state = ? and count_towards_frequency = 1; select num_tickets, created_at from plate_lookups where plate = ? and state = ? and count_towards_frequency = 1 ORDER BY created_at DESC LIMIT 1'
: 'select count(*) as frequency from plate_lookups where plate = ? and state = ? and plate_types = ? and count_towards_frequency = 1; select num_tickets, created_at from plate_lookups where plate = ? and state = ? and plate_types = ? and count_towards_frequency = 1 ORDER BY created_at DESC LIMIT 1';
var searchQueryArgs = plateTypes == undefined
? [plate, state, plate, state]
: [
plate,
state,
plateTypes.join(),
plate,
state,
plateTypes.join()
];
queryForLookups(searchQueryString, searchQueryArgs, function (error, results, fields) {
if (error)
throw error;
var frequency = lookupSource == null ? 0 : 1;
var newLookup = {
plate: plate,
state: state,
plate_types: plateTypes == undefined ? null : plateTypes.join(),
observed: null,
message_id: null,
lookup_source: lookupSource == undefined ? 'api' : lookupSource,
created_at: new Date(),
external_username: null,
count_towards_frequency: lookupSource == undefined ? false : true,
num_tickets: violations.length,
boot_eligible: (streakData && streakData.max_streak >= 5) || 0,
fingerprint_id: fingerprintID,
mixpanel_id: mixpanelID,
responded_to: true
};
var previous_count = null;
var previous_date = null;
if (results &&
results[0] &&
results[0][0] &&
results[1] &&
results[1][0]) {
frequency =
results[0][0].frequency + (lookupSource == null ? 0 : 1);
previous_count = results[1][0].num_tickets;
previous_date = results[1][0].created_at;
}
/*
insertNewLookup(newLookup, (error, results, fields) => {
if (error) throw error;
});
*/
var returnVehicle = new vehicle_lookup_response_1.VehicleLookupData({
camera_streak_data: streakData,
fines: fines,
plate: plate,
plate_types: plateTypes,
previous_lookup_date: previous_date,
previous_violation_count: previous_count,
state: state,
times_queried: frequency,
violations: violations,
violations_count: violations.length
});
var returnObject = new vehicle_lookup_response_1.VehicleLookupResponse({
vehicle: returnVehicle,
successful_lookup: false
});
returnObject.vehicle = stripReturnData(returnObject.vehicle, selectedFields);
returnObject['successful_lookup'] = true;
resolve(returnObject);
});
});
});
}
else {
resolve({
vehicle: {},
error_string: 'Sorry, a plate and state could not be inferred from ' +
vehicle.original_string,
successful_lookup: false
});
}
});
};
/*
let insertNewLookup = (newLookup, callback) => {
connection.query('insert into plate_lookups set ?', newLookup, callback);
};
*/
var makeOpenDataRequests = function (plate, state, plateTypes) {
var fy_endpoints = [
'https://data.cityofnewyork.us/resource/j7ig-zgkq.json',
'https://data.cityofnewyork.us/resource/aagd-wyjz.json',
'https://data.cityofnewyork.us/resource/avxe-2nrn.json',
'https://data.cityofnewyork.us/resource/2bnn-yakx.json',
'https://data.cityofnewyork.us/resource/9wgk-ev5c.json',
'https://data.cityofnewyork.us/resource/faiq-9dfq.json',
'https://data.cityofnewyork.us/resource/pvqr-7yc4.json'
];
var violations = [];
// Checking for selected fields for violations
// const fieldsForExternalRequests = 'violations' in selectedFields ? Object.keys(selectedFields['violations']) : {}
// Fiscal Year Databases
var promises = fy_endpoints.map(function (endpoint) {
var queryString = endpoint +
'?plate_id=' +
encodeURIComponent(plate.toUpperCase()) +
'®istration_state=' +
state.toUpperCase();
if (plateTypes) {
var plateTypesQuery = plateTypes
.map(function (item) { return '%27' + item.toUpperCase().trim() + '%27'; })
.join();
queryString += '&$where=plate_type%20in(' + plateTypesQuery + ')';
}
// if (fieldsForExternalRequests) {
// queryString += '&$select=' + fieldsForExternalRequests.join(',')
// }
queryString += '&$limit=10000&$$app_token=q198HrEaAdCJZD4XCLDl2Uq0G';
return rp(queryString);
});
// Open Parking & Camera Violations Database
var opacvQueryString = 'https://data.cityofnewyork.us/resource/uvbq-3m68.json' +
'?plate=' +
encodeURIComponent(plate.toUpperCase()) +
'&state=' +
state.toUpperCase();
if (plateTypes) {
var plateTypesQuery = plateTypes
.map(function (item) { return '%27' + item.toUpperCase().trim() + '%27'; })
.join();
opacvQueryString += '&$where=license_type%20in(' + plateTypesQuery + ')';
}
// if (fieldsForExternalRequests) {
// opacvQueryString += '&$select=' + fieldsForExternalRequests.join(',')
// }
opacvQueryString += '&$limit=10000&$$app_token=q198HrEaAdCJZD4XCLDl2Uq0G';
promises.push(rp(opacvQueryString));
return promises;
};
var mergeDuplicateViolationRecords = function (violations) {
var accum = [];
violations.forEach(function (object) {
var existing = accum.filter(function (violation, i) {
return violation.summons_number == object.summons_number;
});
if (existing.length) {
var existingIndex = accum.indexOf(existing[0]);
var existingItem_1 = accum[existingIndex];
var mergedObject_1 = {};
Object.keys(existingItem_1).forEach(function (key) {
mergedObject_1[key] = existingItem_1[key] || object[key];
});
Object.keys(object).forEach(function (key) {
mergedObject_1[key] = existingItem_1[key] || object[key];
});
accum[existingIndex] = mergedObject_1;
}
else {
accum.push(object);
}
});
return accum;
};
var modifyViolationsForResponse = function (violations /*, selectedFields*/) {
return violations.map(function (violation) {
var violationDate = violation.issue_date;
var violationTime = violation.violation_time;
var date;
var dateMatch;
if (violationDate) {
dateMatch = violationDate.split('T');
if (dateMatch) {
date = dateMatch[0];
}
}
if (violationTime) {
var isAM = violationTime.includes('A');
var isPM = violationTime.includes('P');
var timeMatch = violationTime.match(/\d{4}/);
var hour = void 0;
var minute = void 0;
if (timeMatch) {
hour = timeMatch[0].substring(0, 2);
minute = timeMatch[0].substring(2, 4);
if (isPM && parseInt(hour) < 12) {
hour = (parseInt(hour) + 12).toString();
}
else if (isAM && hour == 12) {
hour = (parseInt(hour) - 12).toString();
}
}
else if ((timeMatch = violationTime.match(/\d{2}:\d{2}/))) {
hour = timeMatch[0].split(':')[0];
minute = timeMatch[0].split(':')[1];
}
if (hour) {
if (isPM && parseInt(hour) < 12) {
hour = (parseInt(hour) + 12).toString();
}
else if (isAM && hour == 12) {
hour = (parseInt(hour) - 12).toString();
}
}
// console.log(violation.summons_number)
// console.log(violation.street_name)
// console.log(violation.intersecting_street)
// console.log(' ')
if (violationDate.match(/\d{2}\/\d{2}\/\d{4}/)) {
date = date.replace(/\//g, '-');
violation.formatted_time = new Date(date + ' ' + hour + ':' + minute);
}
else {
violation.formatted_time = new Date(date + 'T' + hour + ':' + minute);
}
}
else {
date = date.replace(/\//g, '-');
violation.formatted_time = new Date(date + ' 00:00');
}
var fined = null;
if (violation.fine_amount) {
fined = parseFloat(violation.fine_amount);
}
if (violation.penalty_amount) {
fined += parseFloat(violation.penalty_amount);
}
if (violation.interest_amount) {
fined += parseFloat(violation.interest_amount);
}
if (fined) {
violation.fined = fined;
}
if (violation.payment_amount) {
violation.paid = parseFloat(violation.payment_amount);
}
if (violation.reduction_amount) {
violation.reduced = parseFloat(violation.reduction_amount);
}
if (violation.outstanding_amount) {
violation.outstanding = parseFloat(violation.outstanding_amount);
}
});
};
var normalizeViolations = function (violations) {
var that = _this;
var returnViolations = [];
violations.forEach(function (violation) {
var promise;
var newViolation = {
amount_due: isNaN(parseFloat(violation.amount_due))
? null
: parseFloat(violation.amount_due),
date_first_observed: violation.date_first_observed || null,
feet_from_curb: violation.feet_from_curb || null,
fine_amount: isNaN(parseFloat(violation.fine_amount))
? null
: parseFloat(violation.fine_amount),
to_hours_in_effect: violation.from_hours_in_effect || null,
house_number: violation.house_number || null,
humanized_description: fyHumanizedNames[violation.violation_description || violation.violation_code] ||
opacvHumanizedNames[violation.violation] ||
null,
interest_amount: isNaN(parseFloat(violation.interest_amount))
? null
: parseFloat(violation.interest_amount),
intersecting_street: violation.intersecting_street || null,
issue_date: violation.issue_date || null,
issuer_code: violation.issuer_code || null,
issuer_command: violation.issuer_command || null,
issuer_precinct: isNaN(parseInt(violation.issuer_precinct))
? null
: parseInt(violation.issuer_precinct),
issuing_agency: issuingAgencies[violation.issuing_agency] || null,
law_section: violation.law_section || null,
payment_amount: isNaN(parseFloat(violation.payment_amount))
? null
: parseFloat(violation.payment_amount),
penalty_amount: isNaN(parseFloat(violation.penalty_amount))
? null
: parseFloat(violation.penalty_amount),
plate_id: violation.plate_id || violation.plate || null,
plate_type: violation.plate_type || violation.license_type || null,
reduction_amount: isNaN(parseFloat(violation.reduction_amount))
? null
: parseFloat(violation.reduction_amount),
registration_state: violation.registration_state || null,
street_code1: violation.street_code1 || null,
street_code2: violation.street_code2 || null,
street_code3: violation.street_code3 || null,
street_name: violation.street_name || null,
sub_division: violation.sub_division || null,
summons_image: violation.summons_image || null,
summons_number: violation.summons_number || null,
//to_hours_in_effect: violation.to_hours_in_effect || null,
vehicle_body_type: violation.vehicle_body_type || null,
vehicle_color: violation.vehicle_color || null,
vehicle_expiration_date: violation.vehicle_expiration_date || null,
vehicle_make: violation.vehicle_make || null,
vehicle_year: violation.vehicle_year || null,
violation_code: violation.violation_code ||
namesToCodes[fyHumanizedNames[violation.violation_description || violation.violation_code] || opacvHumanizedNames[violation.violation]] ||
null,
violation_county: counties[violation.violation_county || violation.county] || null,
violation_in_front_of_or_opposite: violation.violation_in_front_of_or_opposite || null,
violation_legal_code: violation.violation_legal_code || null,
violation_location: violation.violation_location || null,
violation_post_code: violation.violation_post_code || null,
violation_precinct: isNaN(parseInt(violation.violation_precinct || violation.precinct))
? null
: parseInt(violation.violation_precinct || violation.precinct),
violation_time: violation.violation_time || null,
location: violation.location || null
};
var fullStreet;
var houseNumber = newViolation.house_number;
var street1 = newViolation.street_name;
var street2 = newViolation.intersecting_street;
if (street1 && street2) {
if (street1.length == 20 && street1.charAt(street1.length - 1) != ' ') {
fullStreet = street1 + street2;
}
else {
fullStreet = street1 +