function guessesFromText (text, strict) {

	var results = {};
	if (text.match(/^https?:\/\//i)) {
		results = deliveryFromURL(text,strict);
	} else {
		results = guessFrom(text,strict);
	}
	results.input = text;
	return results;

}

function urlWithoutFragment (url) {
	var index = url.indexOf('#');
	if (index === -1) return url;
	return url.substring(0,index);
}

function domainFromURL (url) {
	var domain = url.split('/');
	domain = domain[2].replace(/(^(www|m)\.|:[0-9]+$)/i,'').toLowerCase(); // Remove www and port number
	return domain;
}

function deliveryFromURL (input, strict) {

	var results = {};
	var data;
	var matches;
	var best = false;
	var more = false;
	var no;
	var extra;
	var needsGuess = false;
	var url = urlWithoutFragment(input);
	var domain = domainFromURL(url);

	switch (domain) {
	
		case 'adobe.com':
		case 'store1.adobe.com':
			best = ['www.adobe.com'];
			if (matches = url.match(/\/orders\/([A-Za-z0-9]+)/)) {
				no = matches[1];
			}
			break;
	
		case 'apple.com':
		case 'store.apple.com':
		case 'secure.store.apple.com':
		case 'secure1.store.apple.com':
		case 'secure2.store.apple.com':
			best = ['www.apple.com'];
			if (matches = url.match(/(?:\/([a-z-]+))?\/?(?:order\/guest|vieworder)\/([A-Z0-9]+)\/([^\/?]+)/)) {
				switch (matches[1]) {
					case 'hk-zh': best = ['www.apple.com/hk']; break;
					case 'jp': best = ['www.apple.com/japan']; break;
				}
				no = matches[2];
				var email = fullUnescape(matches[3].replace(/%25(2B|40)/g,'%$1'));
				if (email && email.indexOf('@') !== -1) extra = email;
			} else if (matches = url.match(/\/trackshipment\/([A-Z0-9]+)\/([^\/?]+)/)) {
				no = matches[2];
				needsGuess = true;
			}
			if (!no) {
				data = getData(url);
				no = data['orderNumberField'];
				if (!no) no = data['olsson'];
				extra = data['zipEmailField'];
				if (!extra) extra = data['olssgf'];
			}
			break;
	
		case 'applestore.bridge-point.com':
			best = ['www.apple.com'];
			data = getData(url);
			no = data['sc'];
			break;
	
		case 'aramex.com':
		case 'shopandship.com':
			best = ['www.aramex.com'];
			if (matches = url.match(/shopandship.com\/[a-z]+\/tracking\/([A-Z0-9]+)/)) {
				no = matches[1];
			} else {
				data = getData(url);
				no = data['ShipmentNumber'];
			}
			break;

		case 'auspost.com.au':
			best = ['auspost.com.au'];
			if (matches = input.match(/(?:track\/#\/details|tracking)\/([A-Z0-9]+)/)) {
				no = matches[1];
			} else {
				data = getData(url);
				no = data['id'];
				if (!no) no = data['trackIds'];
			}
			break;
	
		case 'canadapost.ca':
		case 'em.canadapost.ca':
		case 'obc.canadapost.ca':
			best = ['em.canadapost.ca'];
			if (matches = input.match(/trackweb\/en#\/(?:details\/|search\?searchFor=)([A-Z0-9]+)/)) {
				no = matches[1];
			} else {
				data = getData(url);
				no = data['trackingNumber'];
				if (!no) no = data['trackingId'];
			}
			break;

		case 'chronopost.fr':
			best = ['www.chronopost.fr'];
			data = getData(url);
			no = data['listeNumerosLT'];
			if (!no) no = data['listeNumeros'];
			break;
	
		case 'dhl.com':
		case 'dhl-usa.com':
		case 'track.dhl-usa.com':
		case 'track.airborne.com':
		case 'dhl.co.uk':
		case 'track.dhl.co.uk':
			best = ['www.dhl.com'];
			data = getData(url);
			no = data['AWB'];
			if (!no) no = data['ShipmentNumber'];
			if (!no) no = data['shipmentNumber'];
			break;

		case 'dhlglobalmail.com':
		case 'webtrack.dhlglobalmail.com':
		case 'dhlgm.mytracking.net':
			best = ['www.dhlglobalmail.com'];
			data = getData(url);
			no = data['trackingnumber'];
			if (!no) no = data['TrackingID'];
			break;

		case 'dhl.de':
		case 'nolp.dhl.de':
		case 'apps.dhl.de':
		case 'mailing.dhl.de':
		case 'mobil.dhl.de':
		case 'mobile.dhl.de':
			best = ['nolp.dhl.de'];
			data = getData(url);
			no = data['piececode'];
			if (!no) no = data['idc'];
			if (!no) no = data['packet_id'];
			if (!no) no = data['sid'];
			if (!no) no = data['AWB'];
			extra = data['zip'];
			break;
	
		case 'webportal-at.dhl.com':
			best = ['nolp.dhl.de'];
			data = getData(url);
			no = data['ic'];
			break;
	
		case 'dpd.de':
		case 'extranet.dpd.de':
		case 'tracking.dpd.de':
			best = ['www.dpd.com'];
			if (matches = input.match(/\/parcel\/([0-9]+)/)) {
				no = matches[1];
			} else {
				data = getData(url);
				no = data['pknr'];
				if (!no) no = data['query'];
				if (!no) no = data['search.parcelNumber'];
			}
			if (no && (matches = no.match(/(B2C|MPS)([0-9]{14})[0-9]{8}/))) no = matches[2];
			break;

		case 'dpd.co.uk':
			best = ['www.dpd.co.uk'];
			data = getData(url);
			no = data['parcel'];
			if (!no) no = data['search.parcelNumber'];
			if (!no) no = data['search.consignmentNumber'];
			break;
	
		case 'fedex.com':
		case 'm.fedex.com':
		case 'federalexpress.com':
		case 'spportal.fedex.com':
			best = ['www.fedex.com'];
			data = getData(url);
			no = data['trackingnumber'];
			if (!no) no = data['tracknumbers'];
			if (!no) no = data['tracknums'];
			if (!no) no = data['trackNum'];
			if (!no) no = data['track_number_0'];
			if (!no) no = data['tracknumber_list'];
			if (!no) no = data['TRACKING'];
			if (!no) no = data['PID'];
			no = fixDoubleEscape(no);
			break;
	
		case 'gls-germany.com':
		case 'gls-group.eu':
			best = ['www.gls-germany.com'];
			data = getData(url);
			no = data['match'];
			if (!no) no = data['txtRefNo'];
			if (!no) no = data['paketliste[0]'];
			break;
	
		case 'checkout.google.com':
			best = ['checkout.google.com'];
			data = getData(url);
			no = data['t'];
			break;

		case 'hlg.de':
		case 'tracking.hermesworld.com':
		case 'myhermes.de':
		case 'hermes-logistik-gruppe.de':
		case 'privatpaketservice.hlg.de':
		case 'sisy.hermes-vs.de':
		case 'tracking.hlg.de':
			best = ['www.hlg.de'];
			if (matches = input.match(/sendungsinformation\/#([0-9]+)/)) {
				no = matches[1];
			} else {
				data = getData(url);
				no = data['auftragsNummer'];
				if (!no) no = data['TrackID'];
			}
			break;
	
		case 'hongkongpost.com':
		case 'app3.hongkongpost.com':
		case 'app3.hongkongpost.hk':
			best = ['www.hongkongpost.com'];
			data = getData(url);
			no = data['tracknbr'];
			break;
	
		case 'japanpost.jp':
		case 'tracking.post.japanpost.jp':
		case 'trackings.post.japanpost.jp':
			best = ['www.japanpost.jp/yupack'];
			data = getData(url);
			no = data['reqCodeNo1'];
			break;
	
		case 'nintendo.com':
			best = ['www.nintendo.com'];
			data = getData(url);
			no = data['orderNumber'];
			extra = data['zipCode'];	
			break;

		case 'laposte.fr':
		case 'colissimo.fr':
		case 'coliposte.net':
			best = ['www.laposte.fr'];
			data = getData(url);
			no = data['code']; // laposte.fr
			if (!no) no = data['colispart']; // colissimo.fr
			if (!no) no = data['colispro']; // coliposte.net
			break;

		case 'lasership.com':
			best = ['www.lasership.com'];
			data = getData(url);
			no = data['track_number_input'];
			if (matches = url.match(/lasership\.com\/track\/([^\/?]+)/)) no = matches[1];
			break;

		case 'ontrac.com':
			best = ['www.ontrac.com'];
			data = getData(url);
			no = data['tracking'];
			if (!no) no = data['tracking_number'];
			break;
	
		case 'parcelforce.com':
		case 'tracking.parcelforce.net':
		case 'www2.parcelforce.com':
			best = ['www.parcelforce.com'];
			data = getData(url);
			no = data['trackNumber'];
			break;

		case 'post.at':
			best = ['www.post.at'];
			data = getData(url);
			no = data['pnum1'];
			break;

		case 'postnord.dk':
		case 'postdanmark.dk':
			best = ['www.postdanmark.dk'];
			if (matches = input.match(/shipmentid=([A-Z0-9]+)/i)) {
				no = matches[1];
			} else {
				data = getData(url);
				no = data['search'];
				if (!no) no = data['i_stregkode'];
				if (!no && data['itemid'] && (matches = data['itemid'].match(/([A-Z0-9]+)0\1/i))) no = matches[1];
			}
			break;
	
		case 'poste.it':
		case 'javapc.poste.it':
			best = ['www.poste.it'];
			if (matches = input.match(/\/risultati-spedizioni\/([A-Z0-9]+)/i)) {
				no = matches[1];
			} else {
				data = getData(url);
				no = data['mpcode'];
				if (!no) no = data['mpcode1'];
				if (!no) no = data['ldv'];
				if (!no) no = data['ID_LDV'];
			}
			break;

		case 'posten.no':
		case 'sporing.posten.no':
		case 'sporing.bring.no':
		case 'online.pannordic.com':
			best = ['www.posten.no'];
			data = getData(url);
			no = data['PackageNumber'];
			if (!no) no = data['id'];
			break;

		case 'postnord.se':
		case 'posten.se':
		case 'server.logistik.posten.se':
			best = ['www.posten.se'];
			if (matches = input.match(/shipmentid=([A-Z0-9]+)/i)) {
				no = matches[1];
			} else {
				data = getData(url);
				no = data['search'];
				if (!no) no = data['consignmentId'];
				if (!no) no = data['kolliid'];
				if (!no && data['itemid'] && (matches = data['itemid'].match(/([A-Z0-9]+)0\1/i))) no = matches[1];
			}
			break;

		case 'post.nl':
		case 'jouw.postnl.nl':
		case 'mijnpakket.postnl.nl':
		case 'postnlpakketten.nl':
		case 'securepostplaza.tntpost.nl':
		case 'tracktrace.postnlpakketten.nl':
		case 'tntpostpakketservice.nl':
		case 'internationalparceltracking.com':
			best = ['www.postnl.nl'];
			if (matches = input.match(/\/(?:track-en-trace|track)\/([A-Z0-9]+)\/([A-Z0-9]+)(\/([A-Z0-9]+))?/i)) {
				no = matches[1];
				extra = matches[2];
				if (matches[4]) extra = matches[4]+' '+extra;
			} else {
				data = getData(url);
				no = data['Barcode'];
				if (!no) no = data['B'];
				if (!no) no = data['tt-barcode'];
				if (!no) no = data['BARCODE'];
				extra = data['Postalcode'];
				if (!extra) extra = data['P'];
				if (!extra) extra = data['tt-zipcode'];
				if (!extra) extra = data['ZIPCODE'];
			}
			break;
	
		case 'purolator.com':
		case 'shipnow.purolator.com':
		case 'eshiponline.purolator.com':
			best = ['www.purolator.com'];
			data = getData(url);
			no = data['pinno'];
			if (!no) no = data['pin'];
			break;
	
		case 'royalmail.com':
			best = ['www.royalmail.com'];
			data = getData(url);
			no = data['trackNumber'];
			if (!no) no = data['tracking_number'];
			if (!no) no = data['track_id'];
			if (!no) {
				if (matches = input.match(/\/tracking-results\/([0-9A-Za-z]+)$/)) no = matches[1];
			}
			break;
	
		case 'sagawa-exp.co.jp':
		case 'k2k.sagawa-exp.co.jp':
			best = ['www.sagawa-exp.co.jp'];
			data = getData(url);
			no = data['okurijoNo'];
			break;
	
		case 'post.ch':
		case 'swisspost.ch':
			best = ['www.post.ch'];
			data = getData(url);
			no = data['formattedParcelCodes'].replace(/;.*/,'');
			break;
	
		case 'tnt.com':
			best = ['www.tnt.com'];
			data = getData(url);
			no = data['cons'];
			if (data['searchType'] == 'REF') best = ['www.tnt.com/ref'];
			break;

		case 'tntexpress.com.au':
			best = ['www.tntexpress.com.au'];
			if (matches = url.match(/\?([A-Z0-9]+)$/)) no = matches[1];
			break;
	
		case 'ups.com':
		case 'm.ups.com':
		case 'wwwapps.ups.com':
		case 'campusship.ups.com':
			best = ['www.ups.com'];
			data = getData(url);
			no = data['InquiryNumber1'];
			if (!no) no = data['tracknum'];
			if (!no) no = data['trackNums'];
			if (!no) no = data['inquiry1'];
			if (!no) no = data['trackingNumber'];
			if (!no) no = data['InquiryNumber'];
			if (!no) {
				if (matches = url.match(/\/(1Z[0-9A-Z]{16})\//)) no = matches[1];
			}
			break;
	
		case 'ups-mi.net':
			best = ['www.ups-mi.net'];
			data = getData(url);
			no = data['pid'];
			if (!no) no = data['PID'];
			if (!no) no = data['strPackageID'];
			break;
	
		case 'usps.com':
		case 'tools.usps.com':
		case 'trkcnfrm.smi.usps.com':
		case 'trkcnfrm1.smi.usps.com':
			best = ['www.usps.com'];
			data = getData(url);
			no = data['tLabels'];
			if (!no) no = data['strOrigTrackNum'];
			if (!no) no = data['origTrackNum'];
			if (!no) no = data['qtc_tLabels1'];
			if (!no) no = data['formattedLabel'];
			break;
	
		case 'tracking.mailexpress.biz':
			best = ['www.usps.com'];
			data = getData(url);
			no = data['TrackingNumber'];
			break;
	
		case 'kuronekoyamato.co.jp':
		case 'otodoke.kuronekoyamato.co.jp':
		case 'toi.kuronekoyamato.co.jp':
		case 'toidirect.kuronekoyamato.co.jp':
			best = ['www.kuronekoyamato.co.jp'];
			data = getData(url);
			no = data['ctn'];
			if (!no) no = data['id'];
			break;

		case 'yodel.co.uk':
		case 'myyodel.co.uk':
		case 'parceltracking.yodel.co.uk':
		case 'tracking.yodel.co.uk':
			best = ['www.yodel.co.uk'];
			if (matches = url.match(/\/tracking\/([A-Z0-9]+)(\/([A-Z0-9%]+))?/)) {
				no = matches[1];
				extra = decodeURIComponent(matches[3]);
			} else {
				data = getData(url);
				no = data['upi'];
				if (!no) no = data['PCL_NO'];
				extra = data['postcode'];
			}
			break;
	
		case 'amazon.com':
		case 'amazon.ca':
		case 'amazon.co.uk':
		case 'amazon.co.jp':
		case 'amazon.de':
		case 'amazon.at':
		case 'amazon.es':
		case 'amazon.fr':
		case 'amazon.in':
		case 'amazon.it':
		case 'sellercentral.amazon.com':
		case 'smile.amazon.com':
		case 'smile.amazon.co.uk':
		case 'smile.amazon.de':
			domain = domain.replace(/[a-z.]*(amazon.[a-z.]*)/i,'$1');
			data = getData(url);
			var trackURL = (data['U']) ? data['U'] : url;
			trackURL = amazonTrackURL(trackURL);
			if (trackURL) {
				best = ['www.amazon.com/url'];
				extra = trackURL;
			} else {
				best = ['www.'+domain];
				no = data['orderID'];
				if (!no) no = data['orderId'];
				if (!no) no = data['oid'];
				if (!no) no = data['orderIDs'];
				if (!no && data['U']) {
					data = getData(data['U']); // "Track this package" email links
					no = data['orderID'];
					if (!no) no = data['orderId'];
				}
				if (!no && data['packedQuery']) {
					if (matches = data['packedQuery'].match(/(^|\|)oid\|([0-9]{3}-[0-9]{7}-[0-9]{7})\|/i)) {
						no = matches[2]; // Not sure if this is still used
					}
				}
				if (no && (matches = no.match(/([0-9]{3}-[0-9]+-[0-9]+)/))) {
					no = matches[1];
				}
			}
			break;
	
		// Third party sites that can be mapped to supported services
	
		case 'ae.com':
		case 'martinandosa.com':
	
			// carrierCode=UB (UPS?)
			// carrierCode=UU (UPS?)
		
			data = getData(url);		
			no = data['trackNum'];
			needsGuess = true;
			break;

		case 'americanapparel.net':
			data = getData(url);		
			no = data['t'];
			needsGuess = true;
			break;
	
		case 'apple.mytracking.net':
			data = getData(url);		
			no = data['TrackingID'];
			needsGuess = true;
			break;

		case 'barlighting.com':
			data = getData(url);		
			no = data['Track'];
			var from = serviceFromString(data['Ship'],false);
			if (from) {
				best = [from];
			} else {
				needsGuess = true;
			}
			break;

		case 'boxoh.com':
			data = getData(url);		
			no = data['t'];
			needsGuess = true;
			break;
	
		case 'bp.mytracking.net':
			data = getData(url);		
			no = data['track'];
			needsGuess = true;
			break;
	
		case 'christianbook.com':
			data = getData(url);		
			no = data['tracking_number'];
			if (data['tracking_ups']) best = ['www.ups.com'];
			break;

		case 'crutchfield.com':
			data = getData(url);		
			no = data['tn'];
			needsGuess = true;
			break;
	
		case 'endicia.com':
			data = getData(url);		
			no = data['PIC'];
			if (!no) no = data['pic'];
			needsGuess = true;
			break;

		case 'endless.com':
			data = getData(url);		
			no = data['trackingId'];
			needsGuess = true;
			break;
	
		case 'globetrotter.de':
			best = ['nolp.dhl.de'];
			data = getData(url);
			no = data['identcode'];
			extra = data['plz'];
			break;
	
		case 'store78b.gracioushome.com':
			data = getData(url);
			no = data['trackingNumber'];
			needsGuess = true;
			break;
	
		case 'internal.granzow.com':
			if (matches = url.match(/\/track\/([^\/]+)/i)) no = matches[1];
			needsGuess = true;
			break;
	
		case 'harryanddavid.com':
		
			// carrierCode=UP (UPS)
		
			data = getData(url);		
			no = data['trackId'];
			needsGuess = true;
			break;
	
		case 'hsn.com':
			data = getData(url);		
			no = data['trackid'];
			needsGuess = true;
			break;

		case 'iship.com':
			data = getData(url);		
			no = data['Track'];
			needsGuess = true;
			break;
	
		case 'lakeside.com':
			data = getData(url);		
			no = data['tnum'];
			needsGuess = true;
			break;
	
		case 'llbean.com':
		case 'www-load.llbean.com':
			data = getData(url);		
			no = data['trackingNbr'];
			if (data['carrierName'] && data['carrierName'].match(/^FedEx/i)) {
				best = ['www.fedex.com'];
			} else if (data['carrierName'] && data['carrierName'].match(/^UPS/i)) {
				best = ['www.ups.com'];
			} else {
				needsGuess = true;
			}
			break;
	
		case 'monoprice.com':
			data = getData(url);		
			no = data['trackingnumber'];
			needsGuess = true;
			break;
	
		case 'newegg.ca':
		case 'newegg.com':
		case 'm.newegg.com':
		case 'neweggbusiness.com':
			data = getData(url);		
			no = data['TrackingNumber'];
			if (!no) no = data['Trackingnumber'];
			if (!no) no = data['trackingnumber'];
			if (!no) no = data['TrackingNumber'];
			needsGuess = true;
			break;
	
		case 'onlineshoes.com':
			data = getData(url);		
			no = data['n'];
			needsGuess = true;
			break;
	
		case 'opsgear.com':
			data = getData(url);		
			no = data['track'];
			if (data['ship'] == 'UPS') {
				best = ['www.ups.com'];
			} else {
				needsGuess = true;
			}
			break;
	
		case 'pbshipstream.com':
			data = getData(url);		
			no = data['pic'];
			needsGuess = true;
			break;
	
		case 'quality-s.qvc.com':
			if (matches = url.match(/\.tracknumber\.([^.]+)/i)) no = matches[1];
			needsGuess = true;
			break;

		case 'scandigital.com':
			data = getData(url);		
			no = data['trcknum'];
			needsGuess = true;
			break;

		case 'shipmentmanager.com':
			data = getData(url);
			data = getData(data['_c']);
			no = data['TrackingIdentifier'];
			needsGuess = true;
			break;

		case 'sierratradingpost.com':
			data = getData(url);
			no = data['trackingno'];
			needsGuess = true;
			break;
	
		case 'stamps.com':
			best = ['www.usps.com'];
			data = getData(url);
			no = data['confirmation'];
			break;

		case 'streamliteinc.com':
			data = getData(url);		
			no = data['refID'];
			needsGuess = true;
			break;

		case 'target.com':
			data = getData(url);
			no = data['trackingNumber'];
			switch (data['shipMethod']) {
				case 'EXT_UPS_GROUND':
				case 'UPS_GR_RES':
					best = ['www.ups.com'];
					break;
				default:
					if (data['shipMethod'].match(/^USPS_/)) best = ['www.usps.com'];
			}
			break;
	
		case 'ttustore.com':
			data = getData(url);
			no = data['trackno'];
			needsGuess = true;
			break;
	
		case 'us-dc1-order.store.yahoo.net':
		case 'us-dc2-order.store.yahoo.net':
			data = getData(url);
			no = data['shipmentInfoDS.shipment_info_ROW_m_tracking_number'];
			needsGuess = true;
			break;

		// Third party sites that redirect

		case 'ecrmomcl.verizonwireless.com':
			data = getData(url);
			for (var key in data) {
				if (data.hasOwnProperty(key)) {
					var value = data[key];
					if (value.match(/^https?:\/\//)) {
						var result = deliveryFromURL(value);
						if (result.no) return result;
					}
				}
			}
			break;

		case 'sm-tracking.vitacost.com':
			if (matches = url.match(/\/track\?.*?&&&(https?:\/\/([^\/]*)[^\s]*)/i)) {
				if (matches[2] != 'www.vitacost.com') {
					var result = deliveryFromURL(matches[1]);
					if (result.no) return result;				
				}
			}
			break;

		// Sites where we don't want to use the fallback

		case 'facebook.com':
		case 'flickr.com':
		case 'twitter.com':
		case 'mobile.twitter.com':
			break;

		// Fallback to check any URL for numbers

		default:

			if (url.match(/\.(jpg|jpeg|png|gif|css|js)(\?|$)/i)) break;
			if (domain.match(/\.tumblr\.com$/i)) break;

			var strictNumbers = false;
			switch (domain) {
				// Always use strict numbers if the site is known to be problematic
				case 'hollisterco.com':
				case 'shiptrack.ebay.com':
				case 'staples.com':
				case 'vistaprint.com':
					strictNumbers = true;
					break;
				default:
					if (strict && url.match(/track|ship|parcel|packet|barcode|paket|colis/i) == null) strictNumbers = true;
					break;
			}

			var path = url.replace(/^https?:\/\/[^\/]+/i,'');
			var matches = path.match(/(^|=)(?=[A-Z-.]*[0-9])([A-Z0-9-.]{9,})(&|$)/gi);
			if (!matches) matches = path.match(/(^|\/)(?=[A-Z-.]*[0-9])([A-Z0-9-.]{9,})(\/|$)/gi);
			if (matches) {
				var matchCount = matches.length;
				for (var i = 0; i < matchCount; i++) {
					var match = matches[i].replace(/^(=|\/)?(.*?)(&|\/)?$/i,'$2');
					var guess = guessFrom(match,true);
					if (guess.no && (guess.best || strictNumbers == false)) {
						best = guess.best;
						more = guess.more;
						no = guess.no;
						break;
					}
				}
			}
			break;

	}

	if (needsGuess) {
		var guess = guessFrom(no);
		if (guess) {
			best = guess.best;
			more = guess.more;
		}
	}

	if (best) results.best = best;
	if (more) results.more = more;
	if (no) results.no = no;
	if (extra) results.extra = extra;
	return results;

}

function amazonTrackURL (url) {
	if (!url) return false;
	var trackURL = false;
	var match = url.match(/^https:\/\/((?:www|smile)\.amazon\.(?:co\.)?[a-z]+)\/(progress-tracker\/package|gp\/your-account\/ship-track|gp\/css\/shiptrack|gp\/your-account\/order-history\/item)[\/?%]/i);
	if (match) {
		var domain = match[1];
		var data = getData(url);
		var itemId = data['itemId'];
		var orderId = data['orderId'] || data['orderID'];
		var packageIndex = data['packageIndex'];
		var shipmentId = data['shipmentId'];
		if (orderId && (itemId || shipmentId)) {
			trackURL = url;
			// Clean up certain URLs to avoid duplicates
			if (trackURL.match(/\/your-account\/(ship-track\/[a-z-]+|order-history\/item)[\/?%]/i)) {
				trackURL = 'https://'+domain+'/gp/your-account/ship-track/ref=oh_aui_st_v2_btn?ie=UTF8';
				if (itemId) trackURL += '&itemId='+itemId;
				trackURL += '&orderId='+orderId+'&packageIndex=';
				trackURL += (packageIndex) ? packageIndex : '0';
				if (shipmentId) trackURL += '&shipmentId='+shipmentId;
			} else {
				trackURL = trackURL.replace(/\/ref=[a-z0-9_]+\?/i,'/ref=oh_aui_st_v2_btn?');
			}
		} else if (match[2] == 'gp/css/shiptrack') {
			trackURL = url.replace(/\/ref=[a-z0-9_]+\?/i,'/ref=oh_aui_st_v2_btn?');
		}
	}
	return trackURL;
}

function fixDoubleEscape (string) {
	if (typeof string == 'string') {
		if (string.indexOf('%20') !== -1) string = decodeURIComponent(string);
	}
	return string;
}

function getItemNames (html, pattern) {
	var names = [];
	var matches = html.match(new RegExp(pattern,'gi'));
	for (x in matches) {
		var match = matches[x].match(new RegExp(pattern,'i'));
		if (!match) continue;
		var name = trim(removeHtmlEntities(match[1]));
		if (names.indexOf(name) == -1) names.push(name);
	}
	return names.join(', ');
}

function getCleanURL (html, pattern, base) {
	var result = html.match(new RegExp(pattern,'i'));
	if (!result) return null;
	var url = result[2].replace(/&amp;/g,'&');
	if (result[1]) {
		url = result[1]+url;
	} else {
		url = base+url;
	}
	return url;
}

function getAllMatches(input, pattern) {
	var multiRegEx = new RegExp(pattern,'gi');
	var allMatches = input.match(multiRegEx);
	if (!allMatches) return null;
	var singleRegEx = new RegExp(pattern,'i');
	var matchCount = allMatches.length;
	var results = [];
	for (var i = 0; i < matchCount; i++) {
		var match = allMatches[i];
		var result = match.match(singleRegEx);
		results.push(result);
	}
	return results;
}

function additionalDataFromHTML (html, url) {

	var data = [];
	var domain = domainFromURL(url);

	switch (domain) {

		case 'amazon.com':
		case 'amazon.ca':
		case 'amazon.co.uk':
		case 'amazon.co.jp':
		case 'amazon.de':
		case 'amazon.at':
		case 'amazon.es':
		case 'amazon.fr':
		case 'amazon.in':
		case 'amazon.it':
		case 'sellercentral.amazon.com':
		case 'smile.amazon.com':
		case 'smile.amazon.de':

			var html = stripWhiteSpace(html);

			var itemNamePattern = '<img[^>]* title="([^"]+)"[^>]*>';
			var trackURL = amazonTrackURL(url);
			if (trackURL) {
				// Track Package, Mobile
				var section = html.match(/<div class="a-row a-spacing-large shipment-summary">.*?<div class="a-row a-grid-vertical-align a-grid-center shipment-status">/i);
				// Track Package, Desktop
				if (!section) section = html.match(/<div class="a-row a-spacing-extra-large a-spacing-top-extra-large shipment-summary">.*?<div class="a-row a-grid-vertical-align a-grid-center shipment-status">/i);
				if (section) {
					var itemName = getItemNames(section[0],itemNamePattern);
					if (itemName) {
						data[trackURL] = { 'name': itemName };
						break;
					}
				}
			}

			var findItemCache = true;
			var itemCaches = [];
			// Your Orders, Mobile
			var sections = html.match(/<div class="a-section a-padding-small js-item">.*?<hr class="a-divider-normal">/gi);
			if (!sections) {
				// Order Details, Mobile
				sections = overlappingMatches(html,'<div class="a-box-group"> ?<div class="a-box"> ?<div class="a-box-inner">.*?(<div class="a-box-group"> ?<div class="a-box"> ?<div class="a-box-inner">|$)');
				if (sections) itemNamePattern = '<a[^>]* title="([^"]+)"[^>]*> ?<div[^>]*> ?<div[^>]*> ?<img[^>]*>';
			}
			// Details for a specific item, Mobile
			if (!sections) {
				sections = overlappingMatches(html,'<div class="a-section a-padding-base"> ?<div class="a-section a-spacing-top-mini">.*?(<div class="a-section a-padding-base"> ?<div class="a-section a-spacing-top-mini">|$)');
				if (sections) findItemCache = false;
			}
			if (!sections) {
				// Your Orders and Order Details, Desktop
				sections = overlappingMatches(html,'<div[^>]*class="(a-box|a-box shipment[^"]*)">.*?(?:<div[^>]*class="(a-box|a-box shipment[^"]*)">|<div class="a-box-group a-spacing-base order">|<div class="a-row a-spacing-top-large">|$)');
				itemNamePattern = '<div class="a-row"> ?<a class="a-link-normal"[^>]*>([^<]*)</a>';
			}

			for (var y in sections) {

				var section = sections[y];

				// Get the tracking link
				var originalURL = getCleanURL(section,'<a href="(https:\/\/[^\/]*)?(\/(progress-tracker\/package|gp\/your-account\/ship-track|gp\/css\/shiptrack|gp\/your-account\/order-history\/item)[\/?%][^"]+)"[^>]*>','https://www.'+domain);
				var trackURL = amazonTrackURL(originalURL);
				if (!originalURL) originalURL = getCleanURL(section,'<a [^>]*href="(https:\/\/[^\/]*)?([^"]*(?:orderId|orderID|oid)=[0-9]{3}-[0-9]{7}-[0-9]{7}[^"]*)"[^>]*>','https://www.'+domain);

				// Get the item name(s)
				var itemName = getItemNames(section,itemNamePattern);

				if (trackURL && itemName) {
					data[trackURL] = { 'name': itemName };
				}

				if (findItemCache && originalURL) {
					var urlData = getData(originalURL);
					var orderID = urlData['orderId'] || urlData['orderID'] || urlData['oid'] || urlData['specificOrderId'];
					var itemCache = itemCaches[orderID] || [];
					var item = { 'itemName': itemName, 'url': trackURL };
					itemCache.push(item);
					itemCaches[orderID] = itemCache;
				}

			}

			for (var key in itemCaches) {
				var hasURLs = true;
				var cache = itemCaches[key];
				var names = [];
				for (var x in cache) {
					var item = cache[x];
					var name = item.itemName;
					if (name) names.push(name);
					if (!item.url) hasURLs = false;
				}
				var guess = {};
				if (names.length > 0) guess['displayName'] = names.join(', ');
				if (hasURLs) guess['itemCacheJSON'] = JSON.stringify(cache);
				data[key] = guess;
			}

			break;

		case 'apple.com':
		case 'store.apple.com':
		case 'secure.store.apple.com':
		case 'secure1.store.apple.com':
		case 'secure2.store.apple.com':

			var html = stripWhiteSpace(html);

			var orders = getAllMatches(html,'"number": ?"([^"]+)".*?"billing":.*?{ ?"emailAddress": ?"([^"]+)"'); // Mobile
			if (!orders) orders = getAllMatches(html,'<span[^>]*id="billing-email-address-([A-Z0-9]+)"[^>]*>([^<]+)</span>'); // Desktop
			if (!orders) break;

			for (var i = 0; i < orders.length; i++) {

				var order = orders[i];
				if (!order) continue;

				var number = order[1];
				var email = order[2];
				data[number] = { 'extra': email };

			}

			break;

	}

	return data;

}
