2013-02-25 07:04:21 -08:00
|
|
|
package DDG::Goodie::VIN;
|
2014-08-20 11:45:33 -07:00
|
|
|
# ABSTRACT: extract information about vehicle identification numbers
|
2013-02-25 07:04:21 -08:00
|
|
|
|
2015-02-22 12:09:29 -08:00
|
|
|
use strict;
|
2013-02-25 07:04:21 -08:00
|
|
|
use DDG::Goodie;
|
|
|
|
|
|
|
|
zci is_cached => 1;
|
|
|
|
zci answer_type => "vin";
|
|
|
|
|
|
|
|
triggers query_lc => qr/([\d+a-z]{17})|
|
|
|
|
(^\d+$)
|
|
|
|
/x;
|
|
|
|
|
|
|
|
# Regex for VIN.
|
|
|
|
my $vin_qr = qr/v(?:ehicle|)i(?:dentification|)n(?:umber|)/oi;
|
|
|
|
my $tracking_qr = qr/package|track(?:ing|)|num(?:ber|)|\#/i;
|
|
|
|
|
|
|
|
# Checksum for VIN.
|
|
|
|
my %vin_checksum = (
|
|
|
|
'A' => 1,
|
|
|
|
'B' => 2,
|
|
|
|
'C' => 3,
|
|
|
|
'D' => 4,
|
|
|
|
'E' => 5,
|
|
|
|
'F' => 6,
|
|
|
|
'G' => 7,
|
|
|
|
'H' => 8,
|
|
|
|
'I' => 'X',
|
|
|
|
'J' => 1,
|
|
|
|
'K' => 2,
|
|
|
|
'L' => 3,
|
|
|
|
'M' => 4,
|
|
|
|
'N' => 5,
|
|
|
|
'O' => 'X',
|
|
|
|
'P' => 7,
|
|
|
|
'Q' => 'X',
|
|
|
|
'R' => 9,
|
|
|
|
'S' => 2,
|
|
|
|
'T' => 3,
|
|
|
|
'U' => 4,
|
|
|
|
'V' => 5,
|
|
|
|
'W' => 6,
|
|
|
|
'X' => 7,
|
|
|
|
'Y' => 8,
|
|
|
|
'Z' => 9,
|
|
|
|
);
|
|
|
|
|
|
|
|
my %vin_checksum_weight = (
|
|
|
|
'1' => 8,
|
|
|
|
'2' => 7,
|
|
|
|
'3' => 6,
|
|
|
|
'4' => 5,
|
|
|
|
'5' => 4,
|
|
|
|
'6' => 3,
|
|
|
|
'7' => 2,
|
|
|
|
'8' => 10,
|
|
|
|
'9' => 0,
|
|
|
|
'10' => 9,
|
|
|
|
'11' => 8,
|
|
|
|
'12' => 7,
|
|
|
|
'13' => 6,
|
|
|
|
'14' => 5,
|
|
|
|
'15' => 4,
|
|
|
|
'16' => 3,
|
|
|
|
'17' => 2,
|
|
|
|
);
|
|
|
|
|
2013-02-25 07:19:12 -08:00
|
|
|
# VIN numbers.
|
|
|
|
# 2008.07.29 force some letters because
|
|
|
|
# "Alvin and the Chipmunks songs" passes checksum.
|
|
|
|
# See http://en.wikipedia.org/wiki/Vehicle_identification_number#Check_digit_calculation
|
|
|
|
# 2012.03.22 remove ^ and $ from 2nd regex term to also allow
|
|
|
|
# 'vin <vin>, etc' -- a regular vin just triggers w.js?
|
2013-02-25 07:04:21 -08:00
|
|
|
handle query_nowhitespace_nodash => sub {
|
|
|
|
my ($query) = @_;
|
|
|
|
|
|
|
|
# If a VIN number (2 for exclusively).
|
|
|
|
my $is_vin = 0;
|
|
|
|
|
|
|
|
# VIN number.
|
|
|
|
my $vin_number = '';
|
|
|
|
|
|
|
|
# Exclsuive trigger.
|
|
|
|
if ($query =~ /^$vin_qr.*?([A-Z\d]{17,})$/i || $query =~ /^([A-Z\d]{17,}).*?$vin_qr$/i) {
|
|
|
|
$vin_number = uc $1;
|
|
|
|
$is_vin = 2;
|
|
|
|
|
2013-03-05 14:55:43 -08:00
|
|
|
# No exclusive trigger, do checksum.
|
|
|
|
# Since the vin numbers are just numbers,
|
|
|
|
# we are more strict in regex (e.g. than UPS).
|
2014-08-19 08:01:08 -07:00
|
|
|
} elsif($query =~ /^(?:$tracking_qr|$vin_qr|)*([A-Z\d]{17})(?:$tracking_qr|$vin_qr|)*$/io || $query =~ /^(?:$tracking_qr|$vin_qr|)*([A-Z\d]{17})(?:$tracking_qr|$vin_qr|)*$/io) {
|
2013-02-25 07:04:21 -08:00
|
|
|
$vin_number = uc $1;
|
|
|
|
|
|
|
|
my $checksum = 0;
|
|
|
|
my @chars = split( //, $vin_number );
|
|
|
|
my $length = scalar(@chars);
|
|
|
|
my $char_count = 0;
|
|
|
|
my $sum = 0;
|
|
|
|
|
|
|
|
my $letter_count = 0;
|
|
|
|
|
|
|
|
foreach my $char (@chars) {
|
|
|
|
$char_count++;
|
|
|
|
$letter_count++ if $char =~ /[A-Z]/;
|
|
|
|
|
|
|
|
# Grab number.
|
|
|
|
my $char_num = $char;
|
|
|
|
$char_num = $vin_checksum{$char} if exists $vin_checksum{$char};
|
|
|
|
|
|
|
|
# Make sure number.
|
|
|
|
if ( $char_num eq 'X' ) {
|
|
|
|
$checksum = -1;
|
|
|
|
last;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Use weight.
|
|
|
|
$sum += $char_num * $vin_checksum_weight{$char_count};
|
|
|
|
}
|
|
|
|
$checksum = $sum % 11;
|
|
|
|
$checksum = 'X' if $checksum == 10;
|
|
|
|
|
|
|
|
if ($checksum eq $chars[8] && $letter_count > 3) {
|
|
|
|
$is_vin = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-18 11:59:14 -07:00
|
|
|
|
2016-02-01 21:06:45 -08:00
|
|
|
return unless $is_vin;
|
|
|
|
|
|
|
|
my $moreUrl = 'http://www.decodethis.com/VIN-Decoded/vin/' . $vin_number;
|
|
|
|
|
2016-02-01 21:09:28 -08:00
|
|
|
return "Decode VIN ($vin_number) at Decode This: $moreUrl",
|
2016-02-01 21:06:45 -08:00
|
|
|
structured_answer => {
|
|
|
|
data => {
|
|
|
|
title => "Vehicle Identification Number: $vin_number",
|
|
|
|
href => $moreUrl
|
|
|
|
},
|
|
|
|
templates => {
|
|
|
|
group => 'text',
|
|
|
|
options => {
|
2016-02-01 21:15:13 -08:00
|
|
|
subtitle_content => 'DDH.vin.subtitle'
|
2016-01-04 06:25:50 -08:00
|
|
|
}
|
2016-02-01 21:06:45 -08:00
|
|
|
}
|
|
|
|
};
|
2013-02-25 07:04:21 -08:00
|
|
|
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
2014-08-19 08:01:08 -07:00
|
|
|
1;
|