#!/usr/bin/perl -w # Traffic Report rev3 # Max Baker use Getopt::Long; GetOptions(\%Args, 'debug','g|glossary'); # HW17 Commute #@centers = qw/MTCC GGCC/; # Bay area + monterey #@roads = qw/SR1 SR17 SR85 I280/; # 85 -> 280 SF <-> SJ commute @centers = qw/GGCC/; # Bay area @roads = qw/SR85 I280 I380 US101/; @d = localtime; $dtstr = sprintf("%02d%02d",$d[4]+1,$d[3]); $main_url = 'http://cad.chp.ca.gov'; $index_url = 'http://cad.chp.ca.gov/sa_list.asp?centerin=_CENTER_'; $inci_url = "http://cad.chp.ca.gov/iiqr.asp?Center=_CENTER_\\&LogNumber=_LOG_D$dtstr"; #$index_url = 'http://cad.chp.ca.gov/sa_stcc.asp?centerin=_CENTER_'; #$inci_url = "http://cad.chp.ca.gov/ii.asp?Center=_CENTER_\\&LogNumber=_LOG_D$dtstr"; $Store = 'traffic'; # Dir to hold incidents $Cookies = "$Store/traffic.cookies"; $wget_idx = "/usr/bin/wget -q --save-cookies $Cookies --keep-session-cookies"; $wget_i = "$wget_idx --load-cookies $Cookies"; $lynx = '/usr/bin/lynx -nolist -width=200 -dump'; $time = '\d+:\d+[AP]M'; $now = scalar localtime; $Debug = $Args{debug}; $Glossary = 'http://cad.chp.ca.gov/htm/body_glossary.htm'; if ($Args{g}) { new_gloss(); exit; } $glossary = &glossary; unless (-d $Store) { mkdir $Store or die "Can't make $Store directory. $!\n"; } # Grab Data foreach my $center (@centers){ my $url = $index_url; $url =~ s/_CENTER_/$center/; Debug("URL : $url"); my $i = "$Store/index_$center.html"; # Wget to fetch because of session cookie support # In order to set the session cookie we have to start at the main index system("$wget_idx $main_url -O $Store/main_index.html") and die "Couldn't get index.\n"; # Now we use this for all our other page gets system("$wget_i $url -O $i") and die "Couldn't get index.\n"; # lynx to parse the html $index = `$lynx $i`; foreach my $line (split(/\n/,$index)){ next unless match($line); # Parse Line if ($line =~ /^\s*(\d+)\s*($time)\s*(.*)\s*$/){ $log_id = $1; $when = $2; $desc = munge_log($3); } else { #print "weird : $line\n"; next; } # Grab Log my $log_url = $inci_url; $log_url =~ s/_CENTER_/$center/; $log_url =~ s/_LOG_/$log_id/; my $file = "$Store/${dtstr}_$log_id.html"; Debug ("Incident : $log_url"); Debug (" $wget_i $log_url -O $file"); system("$wget_i $log_url -O $file") and die "Couldn't get $log_url and stick it in $file.\n"; Debug (" $lynx $file"); my $log = `$lynx $file`; # Store push (@results, [$log_id,$when,$desc,$log]); } } # Present Data print "Content-Type: text/plain\n\n"; print "Max Baker's Traffic Report\n"; print "Traffic Report for : ", join(',',@roads),"\n"; print "Time : $now\n"; print "From : cad.chp.ca.gov\n\n"; my %seen_incident = (); foreach my $road (sort @roads){ print ".-.-.-"x12,"\n"; print " $road \n"; print ".-.-.-"x12,"\n"; foreach my $result (@results){ my $log = $result->[3]; next unless $result->[2] =~ /$road\s+/; $log = munge_log($log); print '*' if exists $seen_incident{$result->[0]}; print "$result->[1] - $result->[2]"; print "$log\n"; $seen_incident{$result->[0]}++; } print "\n"; } sub munge_log { my $log = shift; my $newlog; foreach my $line (split(/\n/,$log)){ next if $line =~ /REFRESH/; next if $line =~ /^\s*$/; next if $line =~ /^\s*Incident:.*$/; next if $line =~ /ADDITIONAL DETAILS/; # Glossary Matches foreach my $w (split(/(\s+|,|-)/,$line)) { next unless defined $glossary->{$w}; $line =~ s/(\b|,|-)$w(\b|,|-)/$1$glossary->{$w}($w)$2/g; } $newlog .= "$line\n"; } return $newlog; } sub match { my $line = shift; foreach my $r (@roads){ return 1 if $line =~ /\s+$r\s+/i; } return 0; } sub Debug { my $string = shift; $string .= "\n" unless $string =~ /\n$/; warn $string if $Debug; } sub glossary { return { '104' => 'MESSAGE RECEIVED', '106' => 'BUSY', '1013' => 'ADVISE ROAD OR WEATHER CONDITIONS', '1014' => 'PROVIDE ESCORT', '1020' => 'LOCATION REQUESTED', '1021' => 'TELEPHONE _________', '1022' => 'DISREGARD', '1023' => 'STANDBY', '1031' => 'ATTEMPTED SUICIDE', '1039' => 'MESSAGE OR ITEM DELIVERED', '1097' => 'ON SCENE', '1098' => 'ASSIGNMENT COMPLETED', '1110' => 'TAKE A REPORT', '1124' => 'ABANDONED VEHICLE', '1125' => 'TRAFFIC HAZARD', '1126' => 'DISABLED VEHICLE', '1141' => 'AMBULANCE REQUIRED', '1142' => 'PARAMEDICS REQUIRED', '1144' => 'POSSIBLE FATALITY', '1148' => 'PROVIDE TRANSPORTATION', '1166' => 'DEFECTIVE TRAFFIC SIGNALS', '1179' => 'ACCIDENT - AMBULANCE RESPONDING', '1180' => 'ACCIDENT - MAJOR INJURY', '1181' => 'ACCIDENT - MINOR INJURY', '1182' => 'ACCIDENT - PROPERTY DAMAGE', '1184' => 'TRAFFIC CONTROL', '1185' => 'TOW TRUCK REQUIRED OR REQUESTED', '1186' => 'BOMB THREAT', '1187' => 'BOMB FOUND', '1198' => 'MEET', '20001' => 'FELONY HIT AND RUN ACCIDENT', '20002' => 'MISDEMEANOR HIT AND RUN ACCIDENT', '23103' => 'RECKLESS DRIVING', '23152' => 'MISDEMEANOR - DRUNK DRIVING', '23153' => 'FELONY - DRUNK DRIVING', '3A' => 'AAA (AMERICAN AUTOMOBILE ASSOCIATION)', '911C' => 'CELLULAR 911 CALL', 'AAA' => 'TRIPLE A (AMERICAN AUTOMOBILE ASSOCIATION)', 'AC' => 'ANIMAL CONTROL', 'ACTIVE' => 'INCIDENT CALL HAS BEEN ASSIGNED TO A CHP OFFICER', 'AIFU' => 'ACCIDENT INVESTIGATION FOLLOW-UP', 'AIR' => 'CHP AIRCRAFT ("AIR" FOLLOWED BY UNIT NUMBER IE: AIR83)', 'AP' => 'APPROACHING', 'APB' => 'ALL POINTS BULLETIN', 'APP' => 'APPROACHING', 'APT' => 'APARTMENT', 'ARO' => 'ANIMAL REGULATIONS ORGANIZATION', 'AFA' => 'ASIAN-FEMALE-ADULT', 'AFJ' => 'ASIAN-FEMALE-JUVENILE', 'AMA' => 'ASIAN-MALE-ADULT', 'AMJ' => 'ASIAN-MALE-JUVENILE', 'ASAP' => 'AS SOON AS POSSIBLE', 'ATC' => 'ATTEMPT TO CONTACT - OR - ANYTHING CLOSE', 'ATL' => 'ATTEMPT TO LOCATE', 'ATV' => 'ALL TERRAIN VEHICLE', 'BC' => 'BROADCAST', 'B\'CAST' => 'BROADCAST', 'BFA' => 'BLACK-FEMALE-ADULT', 'BFJ' => 'BLACK-FEMALE-JUVENILE', 'BGE' => 'BEIGE', 'BLK' => 'BLACK', 'BLU' => 'BLUE', 'BMA' => 'BLACK-MALE-ADULT', 'BMJ' => 'BLACK-MALE-JUVENILE', 'BO' => 'BROKEN, "BAD ORDER", DOES NOT WORK', 'BOL' => 'BE ON THE LOOKOUT', 'BOR' => 'BOTTOM OF RAMP (NEAREST THE END OF THE RAMP)', 'BOCC' => 'BORDER COMMUNICATIONS CENTER', 'BP' => 'BORDER PATROL', 'BRN' => 'BROWN', 'BRO' => 'BROWN', 'BTWN' => 'BETWEEN', 'BET' => 'BETWEEN', 'BOT' => 'BACK ON TOP', 'C2' => 'CODE 2 (RESPOND QUICKLY)', 'C3' => 'CODE 3 (RESPOND AS QUICKLY AS POSSIBLE)', 'C4' => 'CODE 4 (SITUATION UNDER CONTROL)', 'CAD' => 'COMPUTER AIDED DISPATCH', 'CADI' => 'CADILLAC', 'CALTRANS' => 'CALIFORNIA DEPARTMENT OF TRANSPORTATION', 'CB' => 'CALLBOX', 'CBX' => 'CALLBOX', 'CBXCHK' => 'CALLBOX CHECK', 'CD' => 'CENTER DIVIDER', 'C/D' => 'CENTER DIVIDER', 'CDF' => 'CALIFORNIA DEPARTMENT OF FORESTRY', 'CEL' => 'CELLULAR PHONE', 'CELL' => 'CELLULAR PHONE', 'CFI' => 'CAN\'T FIND IT', 'C/FIRE' => 'CAR FIRE', 'CHEV' => 'CHEVROLET', 'CHKPT' => 'CHECKPOINT', 'CHIN' => 'CALIFORNIA HIGHWAY INFORMATION NETWORK', 'CIR' => 'CIRCLE OR CIRCUMSTANCE', 'CIT' => 'CITIZEN', 'CJ' => 'COUNTY JAIL', 'CK' => 'CHECK', 'CLOSUR' => 'CLOSURE', 'CLR' => 'CLEAR', 'CO' => 'COUNTY - OR - CORRECTIONAL OFFICER', 'CON' => 'CONNECTOR - OR - CONNECTED', 'CONET' => 'OFFICER WITH DRUG DOG OR DRUG INTERVENTION UNIT', 'COPIED' => 'RECEIVED INFORMATION', 'COP' => 'COMPLAINT OF PAIN', 'COR' => 'CORONER', 'COZEEP' => 'OFFICER WORKING AT CONSTRUCTION SITE', 'CP' => 'COUPE (2 DOOR CAR)', 'CUS' => 'CUSTOMS', 'CUST' => 'CUSTOMS', 'CV' => 'CONVERTIBLE', 'CVC' => 'CALIFORNIA VEHICLE CODE', 'CZP' => 'COZEEP', 'DAS' => 'DEAD AT SCENE', 'DISC' => 'DISCONNECT', 'DIV' => 'DIVISION', 'DL' => 'DRIVER\'S LICENSE', 'DOA' => 'DEAD ON ARRIVAL', 'DOB' => 'DATE OF BIRTH', 'DOJ' => 'DEPARTMENT OF JUSTICE', 'DOT' => 'DEPARTMENT OF TRANSPORTATION - CALTRANS', 'DRE' => 'DRUG RECOGNITION EXPERT', 'DUI' => 'DRIVING UNDER THE INFLUENCE', 'DV' => 'DISABLED VEHICLE - OR - DOMESTIC VIOLENCE', 'DZ' => 'DROP ZONE', 'EB' => 'EAST BOUND', 'EMT' => 'EMERGENCY MEDICAL TECHNICIAN', 'ENRT' => 'EN ROUTE', 'ENTR' => 'ENTER', 'ER' => 'EMERGENCY ROOM - OR - EN ROUTE', 'ETA' => 'ESTIMATED TIME OF ARRIVAL', 'EVAL' => 'EVALUATION (USUALLY TO DETERMINE IF DUI)', 'EXP' => 'EXPEDITE (RESPOND QUICKLY)', 'FB' => 'FLATBED TOW TRUCK', 'FBED' => 'FLATBED TOW TRUCK', 'FD' => 'FIRE DEPARTMENT', 'FIRE' => 'FIRE DEPARTMENT', 'FRCC' => 'FRESNO COMM CENTER', 'FWY' => 'FREEWAY', 'FRWY' => 'FREEWAY', 'FSP' => 'FREEWAY SERVICE PATROL', 'FT' => 'FLAT TIRE', 'FTY' => 'FAILURE TO YIELD', 'FV' => 'FREEWAY VIOLENCE', 'FYI' => 'FOR YOUR INFORMATION', 'GGCC' => 'GOLDEN GATE COMMUNICATIONS CENTER', 'GOA' => 'GONE ON ARRIVAL (IT\'S NOT THERE)', 'GRN' => 'GREEN', 'GS' => 'GOOD SPARE', 'HAZMAT' => 'HAZARDOUS MATERIAL', 'HB' => 'HATCHBACK', 'HER' => 'HELP EN ROUTE', 'HEWAB' => 'HIGHWAY EMERGENCY & WEATHER ADVISORY BULLETIN', 'HFA' => 'HISPANIC-FEMALE-ADULT', 'HFJ' => 'HISPANIC-FEMALE-JUVENILE', 'HMA' => 'HISPANIC-MALE-ADULT', 'HMJ' => 'HISPANIC-MALE-JUVENILE', 'HOV' => 'HIGH OCCUPANCY VEHICLE (CAR POOL)', 'HTS' => 'HEIGHTS', 'HV' => 'HIGHWAY VIOLENCE', 'HWY' => 'HIGHWAY', 'I-' => 'INTERSTATE - (IE - I15)', 'IFO' => 'IN FRONT OF', 'IMP' => 'IMPOUND (TOW AWAY)', 'INC' => 'INCIDENT', 'INCC' => 'INLAND COMMUNICATION CENTER', 'INCL' => 'INCLUDING', 'INJ' => 'INJURY', 'INS' => 'IMMIGRATION AND NATURALIZATION SERVICE', 'INV' => 'INVOLVED', 'IO' => 'INFO ONLY', 'JEO' => 'JUST EAST OF', 'JNO' => 'JUST NORTH OF', 'JSO' => 'JUST SOUTH OF', 'JUVI' => 'JUVENILE', 'JUVIE' => 'JUVENILE', 'JWO' => 'JUST WEST OF', 'K9' => 'CANINE - POLICE DOG - UNIT WITH A DOG', 'LACC' => 'LOS ANGELES COMMUNICATION CENTER', 'LIC' => 'LICENSE', 'L/M' => 'LEFT MESSAGE', 'LN' => 'LANE', 'LS' => 'LAST SEEN', 'LSW' => 'LAST SEEN WEARING', 'LZ' => 'LANDING ZONE', 'MAR' => 'MAROON', 'MAZEEP' => 'OFFICER WORKING A MAINTENANCE PROJECT', 'MCC' => 'MERCED COMM CENTER', 'ME' => 'MEDICAL EXAMINER', 'MFA' => 'MEXICAN-FEMALE-ADULT', 'MFJ' => 'MEXICAN-FEMALE-JUVENILE', 'MIO' => 'MEDIA INFORMATION OFFICER - CHP', 'MLK' => 'MARTIN LUTHER KING JR (ABBREVIATION FOR STREET NAME OR ROADWAY)', 'MM' => 'MILE MARKER', 'MMA' => 'MEXICAN-MALE-ADULT', 'MMJ' => 'MEXICAN-MALE-JUVENILE', 'MP' => 'MILITARY POLICE', 'MPM' => 'MILE POST MARKER', 'MRE' => 'MOBILE ROAD ENFORCEMENT', 'MT' => 'MOUNTAIN OR MOUNT', 'NA' => 'NO ANSWER - OR - NOT AVAILABLE - OR- NOT APPLICABLE', 'NB' => 'NORTH BOUND', 'NFD' => 'NO FURTHER DETAILS', 'NFI' => 'NO FURTHER INFORMATION', 'NJ' => 'NO JACK (TO CHANGE TIRE)', 'NLT' => 'NO LATER THAN', 'NR' => 'NO RESPONSE', 'N/R' => 'NO RESPONSE', 'NS' => 'NO SPARE', 'NUA' => 'NO UNIT AVAILABLE', 'NVC' => 'NO VOICE CONTACT', 'O/' => 'OVER', 'OCC' => 'OCCURRED OR OCCUPANTS', 'OCCC' => 'ORANGE COUNTY COMMUNICATION CENTER', 'OES' => 'OFFICE OF EMERGENCY SERVICES', 'OFR' => 'OFF RAMP', 'OIC' => 'OFFICER OR OPERATOR IN CHARGE', 'OMEGA' => 'CORONER OR MEDICAL EXAMINER', 'ONG' => 'ORANGE', 'ONR' => 'ON RAMP', 'OOG' => 'OUT OF GAS', 'ORD' => 'ORDER NUMBER, USED BY 3A TO RECORD SERVICE REQUESTS', 'OR#' => 'ORDER NUMBER, USED BY 3A TO RECORD SERVICE REQUESTS', 'OTS' => 'OVER THE SIDE', 'O\'SIDE' => 'OVER THE SIDE, OR OUTSIDE', 'O/X' => 'OVERCROSSING', 'PAC' => 'PUBLIC AFFAIRS COORDINATOR', 'PAO' => 'PUBLIC AFFAIRS OFFICER', 'PARK' => 'PARKING PROBLEM', 'PC' => 'PROBABLE CAUSE - OR - PENAL CODE', 'PD' => 'POLICE DEPARTMENT', 'PED' => 'PEDESTRIAN', 'PENDING' => 'INCIDENT CALL AWAITING OFFICER ASSIGNMENT', 'PIT' => 'PURSUIT IMMOBILIZATION TECHNIQUE', 'PK' => 'PICK-UP TRUCK', 'PKWY' => 'PARKWAY', 'PLS' => 'PLEASE', 'PLZ' => 'PLEASE', 'PLT' => 'PLATE', 'PM' => 'PARAMEDICS', 'PM' => 'PASSING MOTORIST', 'POE' => 'PORT OF ENTRY (THE BORDER)', 'POI' => 'POINT OF IMPACT', 'PORT' => 'PORT OF ENTRY (THE BORDER)', 'POSS' => 'POSSIBLE - OR - POSSESSION', 'PT' => 'POINT (EX: GORE POINT)', 'PTS' => 'PREPARE TO STOP', 'PU' => 'PICK-UP TRUCK', 'RDCC' => 'REDDING COMMUNICATIONS CENTER', 'R' => 'RESIDENCE (HOME)', 'RB' => 'ROLLBACK (TOW TRUCK)', 'RD' => 'ROAD', 'RDW' => 'ROADWAY', 'RDWY' => 'ROADWAY', 'REF' => 'REFERENCE', 'REQ' => 'REQUEST - OR - REQUIRED', 'RESP' => 'RESPONDING', 'RP' => 'REPORTING PARTY - OR - RESPONSIBLE PARTY', 'R/P' => 'REPORTING PARTY - OR - RESPONSIBLE PARTY', 'RO' => 'REGISTERED OWNER', 'ROLLBK' => 'ROLLBACK, SAME AS A FLATBED TOW TRUCK', 'RS' => 'RIGHT SHOULDER', 'R/S' => 'RIGHT SHOULDER', 'RHS' => 'RIGHT HAND SHOULDER', 'RTH' => 'REMOVED THE HAZARD', 'SB' => 'SOUTH BOUND', 'SEMI' => '"BIG RIG, 18 WHEELER, TRACTOR TRUCK"', 'SIC' => 'SUBJECT IN CUSTODY', 'SIGLRT' => 'SIG ALERT', 'SLINGTK' => 'SLING TRUCK - SAME AS A FLATBED TOW TRUCK', 'SMPV' => 'SPECIALLY MARKED PATROL VEHICLE', 'SPGS' => 'SPRINGS', 'SUBCHK' => 'SUBJECT CHECK (WARRANTS, ETC.)', 'SUBJ' => 'SUBJECT', 'SUSP' => 'SUSPECT - OR - SUSPICIOUS', 'SUSCIRC' => 'SUSPICIOUS CIRCUMSTANCES', 'TB' => 'THOMAS BROTHERS MAP - REFERRING TO PAGE NUMBER', 'TG' => 'THOMAS GUIDE MAP - REFERRING TO PAGE NUMBER', 'THX' => 'THANKS', 'TIP' => 'TRAUMA INTERVENTION PROGRAM (ONSITE COUNSELING)', 'TK' => 'TRUCK', 'TMC' => 'TRANSPORTATION MANAGEMENT CENTER', 'TOC' => 'TRAFFIC OPERATIONS CENTER (SAME AS TMC)', 'TOR' => 'TOP OF THE RAMP (NEAREST THE START OF THE RAMP)', 'TRANS' => 'TRANSITION ROAD', 'TRK' => 'TRUCK', 'TRKTRL' => 'TRUCK TRAIL (A BACK COUNTRY ROAD)', 'TRKTRLR' => 'TRUCK TRAILER', 'TRLR' => 'TRAILER', 'TRNSFR' => 'TRANSFERRED', 'UA' => 'UNIT ADVISED', 'UI' => 'UNIT INFORMED', 'UFN' => 'UNTIL FURTHER NOTICE', 'UNK' => 'UNKNOWN', 'USFS' => 'UNITED STATES FOREST SERVICE', 'UTL' => 'UNABLE TO LOCATE (CANNOT FIND IT)', 'VC' => 'VEHICLE CODE', 'VEH' => 'VEHICLE', 'VICT' => 'VICTIM', 'W/' => 'WITH', 'WB' => 'WEST BOUND', 'WCB' => 'WILL CALL BACK', 'WFA' => 'WHITE-FEMALE-ADULT', 'WFJ' => 'WHITE-FEMALE-JUVENILE', 'WHT' => 'WHITE', 'WHI' => 'WHITE', 'WIT' => 'WITNESS', 'WMA' => 'WHITE-MALE-ADULT', 'WMJ' => 'WHITE-MALE-JUVENILE', 'W/O' => 'WITHOUT', 'W/WAY' => 'WRONG WAY', 'XFER' => 'TRANSFERRED', 'XRAY' => 'FEMALE', 'YO' => 'YEARS OLD', 'YOA' => 'YEARS OF AGE', 'YLP' => 'YOSEMITE LAKES PARK', 'YNP' => 'YOSEMITE NATIONAL PARK', }; } # Parse Glossary sub new_gloss { my $gloss = "$Store/glossary"; system("$lynx $Glossary > $gloss"); open (GLOSSARY,"< $gloss") or die $!; while(){ unless ($_ =~ /^\s*([^=\s]+)\s*=\s*(.*)\s*$/){ next; } $key = $1; $val = $2; $key =~ s/'/\\'/g; $val =~ s/'/\\'/g; foreach my $k ( split(/\s*,\s*/,$key) ) { print " '$k' => '$val',\n"; } } warn "You must manually seperate the multiple keys that use hashes\n"; warn " eg : 'WHT/WTE'\n"; }