/* Minification failed. Returning unminified contents.
(3605,22-23): run-time error JS1014: Invalid character: `
(3605,25-26): run-time error JS1003: Expected ':': {
(3605,29-30): run-time error JS1003: Expected ':': }
(3605,31-32): run-time error JS1014: Invalid character: `
(3727,31-32): run-time error JS1014: Invalid character: `
(3729,1-2): run-time error JS1195: Expected expression: .
(3729,1-2): run-time error JS1195: Expected expression: .
(3732,9-10): run-time error JS1004: Expected ';': :
(3739,28-29): run-time error JS1197: Too many errors. The file might not be a JavaScript file: ,
 */
/*!
* Modernizr v2.0.6
* http://www.modernizr.com
*
* Copyright (c) 2009-2011 Faruk Ates, Paul Irish, Alex Sexton
* Dual-licensed under the BSD or MIT licenses: www.modernizr.com/license/
*/

/*
* Modernizr tests which native CSS3 and HTML5 features are available in
* the current UA and makes the results available to you in two ways:
* as properties on a global Modernizr object, and as classes on the
* <html> element. This information allows you to progressively enhance
* your pages with a granular level of control over the experience.
*
* Modernizr has an optional (not included) conditional resource loader
* called Modernizr.load(), based on Yepnope.js (yepnopejs.com).
* To get a build that includes Modernizr.load(), as well as choosing
* which tests to include, go to www.modernizr.com/download/
*
* Authors        Faruk Ates, Paul Irish, Alex Sexton, 
* Contributors   Ryan Seddon, Ben Alman
*/

window.Modernizr = (function (window, document, undefined) {

  var version = '2.0.6',

    Modernizr = {},

  // option for enabling the HTML classes to be added
    enableClasses = true,

    docElement = document.documentElement,
    docHead = document.head || document.getElementsByTagName('head')[0],

  /**
  * Create our "modernizr" element that we do most feature tests on.
  */
    mod = 'modernizr',
    modElem = document.createElement(mod),
    mStyle = modElem.style,

  /**
  * Create the input element for various Web Forms feature tests.
  */
    inputElem = document.createElement('input'),

    smile = ':)',

    toString = Object.prototype.toString,

  // List of property values to set for css tests. See ticket #21
    prefixes = ' -webkit- -moz- -o- -ms- -khtml- '.split(' '),

  // Following spec is to expose vendor-specific style properties as:
  //   elem.style.WebkitBorderRadius
  // and the following would be incorrect:
  //   elem.style.webkitBorderRadius

  // Webkit ghosts their properties in lowercase but Opera & Moz do not.
  // Microsoft foregoes prefixes entirely <= IE8, but appears to
  //   use a lowercase `ms` instead of the correct `Ms` in IE9

  // More here: http://github.com/Modernizr/Modernizr/issues/issue/21
    domPrefixes = 'Webkit Moz O ms Khtml'.split(' '),

    ns = { 'svg': 'http://www.w3.org/2000/svg' },

    tests = {},
    inputs = {},
    attrs = {},

    classes = [],

    featureName, // used in testing loop


  // Inject element with style element and some CSS rules
    injectElementWithStyles = function (rule, callback, nodes, testnames) {

      var style, ret, node,
          div = document.createElement('div');

      if (parseInt(nodes, 10)) {
        // In order not to give false positives we create a node for each test
        // This also allows the method to scale for unspecified uses
        while (nodes--) {
          node = document.createElement('div');
          node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
          div.appendChild(node);
        }
      }

      // <style> elements in IE6-9 are considered 'NoScope' elements and therefore will be removed
      // when injected with innerHTML. To get around this you need to prepend the 'NoScope' element
      // with a 'scoped' element, in our case the soft-hyphen entity as it won't mess with our measurements.
      // http://msdn.microsoft.com/en-us/library/ms533897%28VS.85%29.aspx
      style = ['&shy;', '<style>', rule, '</style>'].join('');
      div.id = mod;
      div.innerHTML += style;
      docElement.appendChild(div);

      ret = callback(div, rule);
      div.parentNode.removeChild(div);

      return !!ret;

    },


  // adapted from matchMedia polyfill
  // by Scott Jehl and Paul Irish
  // gist.github.com/786768
    testMediaQuery = function (mq) {

      if (window.matchMedia) {
        return matchMedia(mq).matches;
      }

      var bool;

      injectElementWithStyles('@media ' + mq + ' { #' + mod + ' { position: absolute; } }', function (node) {
        bool = (window.getComputedStyle ?
                  getComputedStyle(node, null) :
                  node.currentStyle)['position'] == 'absolute';
      });

      return bool;

    },


  /**
  * isEventSupported determines if a given element supports the given event
  * function from http://yura.thinkweb2.com/isEventSupported/
  */
    isEventSupported = (function () {

      var TAGNAMES = {
        'select': 'input', 'change': 'input',
        'submit': 'form', 'reset': 'form',
        'error': 'img', 'load': 'img', 'abort': 'img'
      };

      function isEventSupported(eventName, element) {

        element = element || document.createElement(TAGNAMES[eventName] || 'div');
        eventName = 'on' + eventName;

        // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and "resize", whereas `in` "catches" those
        var isSupported = eventName in element;

        if (!isSupported) {
          // If it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element
          if (!element.setAttribute) {
            element = document.createElement('div');
          }
          if (element.setAttribute && element.removeAttribute) {
            element.setAttribute(eventName, '');
            isSupported = is(element[eventName], 'function');

            // If property was created, "remove it" (by setting value to `undefined`)
            if (!is(element[eventName], undefined)) {
              element[eventName] = undefined;
            }
            element.removeAttribute(eventName);
          }
        }

        element = null;
        return isSupported;
      }
      return isEventSupported;
    })();

  // hasOwnProperty shim by kangax needed for Safari 2.0 support
  var _hasOwnProperty = ({}).hasOwnProperty, hasOwnProperty;
  if (!is(_hasOwnProperty, undefined) && !is(_hasOwnProperty.call, undefined)) {
    hasOwnProperty = function (object, property) {
      return _hasOwnProperty.call(object, property);
    };
  }
  else {
    hasOwnProperty = function (object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
      return ((property in object) && is(object.constructor.prototype[property], undefined));
    };
  }

  /**
  * setCss applies given styles to the Modernizr DOM node.
  */
  function setCss(str) {
    mStyle.cssText = str;
  }

  /**
  * setCssAll extrapolates all vendor-specific css strings.
  */
  function setCssAll(str1, str2) {
    return setCss(prefixes.join(str1 + ';') + (str2 || ''));
  }

  /**
  * is returns a boolean for if typeof obj is exactly type.
  */
  function is(obj, type) {
    return typeof obj === type;
  }

  /**
  * contains returns a boolean for if substr is found within str.
  */
  function contains(str, substr) {
    return !! ~('' + str).indexOf(substr);
  }

  /**
  * testProps is a generic CSS / DOM property test; if a browser supports
  *   a certain property, it won't return undefined for it.
  *   A supported CSS property returns empty string when its not yet set.
  */
  function testProps(props, prefixed) {
    for (var i in props) {
      if (mStyle[props[i]] !== undefined) {
        return prefixed == 'pfx' ? props[i] : true;
      }
    }
    return false;
  }

  /**
  * testPropsAll tests a list of DOM properties we want to check against.
  *   We specify literally ALL possible (known and/or likely) properties on
  *   the element including the non-vendor prefixed one, for forward-
  *   compatibility.
  */
  function testPropsAll(prop, prefixed) {

    var ucProp = prop.charAt(0).toUpperCase() + prop.substr(1),
            props = (prop + ' ' + domPrefixes.join(ucProp + ' ') + ucProp).split(' ');

    return testProps(props, prefixed);
  }

  /**
  * testBundle tests a list of CSS features that require element and style injection.
  *   By bundling them together we can reduce the need to touch the DOM multiple times.
  */
  /*>>testBundle*/
  var testBundle = (function (styles, tests) {
    var style = styles.join(''),
            len = tests.length;

    injectElementWithStyles(style, function (node, rule) {
      var style = document.styleSheets[document.styleSheets.length - 1],
      // IE8 will bork if you create a custom build that excludes both fontface and generatedcontent tests.
      // So we check for cssRules and that there is a rule available
      // More here: https://github.com/Modernizr/Modernizr/issues/288 & https://github.com/Modernizr/Modernizr/issues/293
                cssText = style.cssRules && style.cssRules[0] ? style.cssRules[0].cssText : style.cssText || "",
                children = node.childNodes, hash = {};

      while (len--) {
        hash[children[len].id] = children[len];
      }

      /*>>touch*/Modernizr['touch'] = ('ontouchstart' in window) || hash['touch'].offsetTop === 9; /*>>touch*/
      /*>>csstransforms3d*/Modernizr['csstransforms3d'] = hash['csstransforms3d'].offsetLeft === 9;          /*>>csstransforms3d*/
      /*>>generatedcontent*/Modernizr['generatedcontent'] = hash['generatedcontent'].offsetHeight >= 1;       /*>>generatedcontent*/
      /*>>fontface*/Modernizr['fontface'] = /src/i.test(cssText) &&
                                                                  cssText.indexOf(rule.split(' ')[0]) === 0;        /*>>fontface*/
    }, len, tests);

  })([
  // Pass in styles to be injected into document
  /*>>fontface*/'@font-face {font-family:"font";src:url("https://")}'         /*>>fontface*/

  /*>>touch*/, ['@media (', prefixes.join('touch-enabled),('), mod, ')',
                                '{#touch{top:9px;position:absolute}}'].join('')           /*>>touch*/

  /*>>csstransforms3d*/, ['@media (', prefixes.join('transform-3d),('), mod, ')',
                                '{#csstransforms3d{left:9px;position:absolute}}'].join('')/*>>csstransforms3d*/

  /*>>generatedcontent*/, ['#generatedcontent:after{content:"', smile, '";visibility:hidden}'].join('')  /*>>generatedcontent*/
    ],
      [
  /*>>fontface*/'fontface'          /*>>fontface*/
  /*>>touch*/, 'touch'            /*>>touch*/
  /*>>csstransforms3d*/, 'csstransforms3d'  /*>>csstransforms3d*/
  /*>>generatedcontent*/, 'generatedcontent' /*>>generatedcontent*/

    ]); /*>>testBundle*/


  /**
  * Tests
  * -----
  */

  tests['flexbox'] = function () {
    /**
    * setPrefixedValueCSS sets the property of a specified element
    * adding vendor prefixes to the VALUE of the property.
    * @param {Element} element
    * @param {string} property The property name. This will not be prefixed.
    * @param {string} value The value of the property. This WILL be prefixed.
    * @param {string=} extra Additional CSS to append unmodified to the end of
    * the CSS string.
    */
    function setPrefixedValueCSS(element, property, value, extra) {
      property += ':';
      element.style.cssText = (property + prefixes.join(value + ';' + property)).slice(0, -property.length) + (extra || '');
    }

    /**
    * setPrefixedPropertyCSS sets the property of a specified element
    * adding vendor prefixes to the NAME of the property.
    * @param {Element} element
    * @param {string} property The property name. This WILL be prefixed.
    * @param {string} value The value of the property. This will not be prefixed.
    * @param {string=} extra Additional CSS to append unmodified to the end of
    * the CSS string.
    */
    function setPrefixedPropertyCSS(element, property, value, extra) {
      element.style.cssText = prefixes.join(property + ':' + value + ';') + (extra || '');
    }

    var c = document.createElement('div'),
            elem = document.createElement('div');

    setPrefixedValueCSS(c, 'display', 'box', 'width:42px;padding:0;');
    setPrefixedPropertyCSS(elem, 'box-flex', '1', 'width:10px;');

    c.appendChild(elem);
    docElement.appendChild(c);

    var ret = elem.offsetWidth === 42;

    c.removeChild(elem);
    docElement.removeChild(c);

    return ret;
  };

  // On the S60 and BB Storm, getContext exists, but always returns undefined
  // http://github.com/Modernizr/Modernizr/issues/issue/97/

  tests['canvas'] = function () {
    var elem = document.createElement('canvas');
    return !!(elem.getContext && elem.getContext('2d'));
  };

  tests['canvastext'] = function () {
    return !!(Modernizr['canvas'] && is(document.createElement('canvas').getContext('2d').fillText, 'function'));
  };

  // This WebGL test may false positive. 
  // But really it's quite impossible to know whether webgl will succeed until after you create the context. 
  // You might have hardware that can support a 100x100 webgl canvas, but will not support a 1000x1000 webgl 
  // canvas. So this feature inference is weak, but intentionally so.

  // It is known to false positive in FF4 with certain hardware and the iPad 2.

  tests['webgl'] = function () {
    return !!window.WebGLRenderingContext;
  };

  /*
  * The Modernizr.touch test only indicates if the browser supports
  *    touch events, which does not necessarily reflect a touchscreen
  *    device, as evidenced by tablets running Windows 7 or, alas,
  *    the Palm Pre / WebOS (touch) phones.
  *
  * Additionally, Chrome (desktop) used to lie about its support on this,
  *    but that has since been rectified: http://crbug.com/36415
  *
  * We also test for Firefox 4 Multitouch Support.
  *
  * For more info, see: http://modernizr.github.com/Modernizr/touch.html
  */

  tests['touch'] = function () {
    return Modernizr['touch'];
  };

  /**
  * geolocation tests for the new Geolocation API specification.
  *   This test is a standards compliant-only test; for more complete
  *   testing, including a Google Gears fallback, please see:
  *   http://code.google.com/p/geo-location-javascript/
  * or view a fallback solution using google's geo API:
  *   http://gist.github.com/366184
  */
  tests['geolocation'] = function () {
    return !!navigator.geolocation;
  };

  // Per 1.6:
  // This used to be Modernizr.crosswindowmessaging but the longer
  // name has been deprecated in favor of a shorter and property-matching one.
  // The old API is still available in 1.6, but as of 2.0 will throw a warning,
  // and in the first release thereafter disappear entirely.
  tests['postmessage'] = function () {
    return !!window.postMessage;
  };

  // Web SQL database detection is tricky:

  // In chrome incognito mode, openDatabase is truthy, but using it will
  //   throw an exception: http://crbug.com/42380
  // We can create a dummy database, but there is no way to delete it afterwards.

  // Meanwhile, Safari users can get prompted on any database creation.
  //   If they do, any page with Modernizr will give them a prompt:
  //   http://github.com/Modernizr/Modernizr/issues/closed#issue/113

  // We have chosen to allow the Chrome incognito false positive, so that Modernizr
  //   doesn't litter the web with these test databases. As a developer, you'll have
  //   to account for this gotcha yourself.
  tests['websqldatabase'] = function () {
    var result = !!window.openDatabase;
    /*  if (result){
    try {
    result = !!openDatabase( mod + "testdb", "1.0", mod + "testdb", 2e4);
    } catch(e) {
    }
    }  */
    return result;
  };

  // Vendors had inconsistent prefixing with the experimental Indexed DB:
  // - Webkit's implementation is accessible through webkitIndexedDB
  // - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB
  // For speed, we don't test the legacy (and beta-only) indexedDB
  tests['indexedDB'] = function () {
    for (var i = -1, len = domPrefixes.length; ++i < len; ) {
      if (window[domPrefixes[i].toLowerCase() + 'IndexedDB']) {
        return true;
      }
    }
    return !!window.indexedDB;
  };

  // documentMode logic from YUI to filter out IE8 Compat Mode
  //   which false positives.
  tests['hashchange'] = function () {
    return isEventSupported('hashchange', window) && (document.documentMode === undefined || document.documentMode > 7);
  };

  // Per 1.6:
  // This used to be Modernizr.historymanagement but the longer
  // name has been deprecated in favor of a shorter and property-matching one.
  // The old API is still available in 1.6, but as of 2.0 will throw a warning,
  // and in the first release thereafter disappear entirely.
  tests['history'] = function () {
    return !!(window.history && history.pushState);
  };

  tests['draganddrop'] = function () {
    return isEventSupported('dragstart') && isEventSupported('drop');
  };

  // Mozilla is targeting to land MozWebSocket for FF6
  // bugzil.la/659324
  tests['websockets'] = function () {
    for (var i = -1, len = domPrefixes.length; ++i < len; ) {
      if (window[domPrefixes[i] + 'WebSocket']) {
        return true;
      }
    }
    return 'WebSocket' in window;
  };


  // http://css-tricks.com/rgba-browser-support/
  tests['rgba'] = function () {
    // Set an rgba() color and check the returned value

    setCss('background-color:rgba(150,255,150,.5)');

    return contains(mStyle.backgroundColor, 'rgba');
  };

  tests['hsla'] = function () {
    // Same as rgba(), in fact, browsers re-map hsla() to rgba() internally,
    //   except IE9 who retains it as hsla

    setCss('background-color:hsla(120,40%,100%,.5)');

    return contains(mStyle.backgroundColor, 'rgba') || contains(mStyle.backgroundColor, 'hsla');
  };

  tests['multiplebgs'] = function () {
    // Setting multiple images AND a color on the background shorthand property
    //  and then querying the style.background property value for the number of
    //  occurrences of "url(" is a reliable method for detecting ACTUAL support for this!

    setCss('background:url(https://),url(https://),red url(https://)');

    // If the UA supports multiple backgrounds, there should be three occurrences
    //   of the string "url(" in the return value for elemStyle.background

    return /(url\s*\(.*?){3}/.test(mStyle.background);
  };


  // In testing support for a given CSS property, it's legit to test:
  //    `elem.style[styleName] !== undefined`
  // If the property is supported it will return an empty string,
  // if unsupported it will return undefined.

  // We'll take advantage of this quick test and skip setting a style
  // on our modernizr element, but instead just testing undefined vs
  // empty string.


  tests['backgroundsize'] = function () {
    return testPropsAll('backgroundSize');
  };

  tests['borderimage'] = function () {
    return testPropsAll('borderImage');
  };


  // Super comprehensive table about all the unique implementations of
  // border-radius: http://muddledramblings.com/table-of-css3-border-radius-compliance

  tests['borderradius'] = function () {
    return testPropsAll('borderRadius');
  };

  // WebOS unfortunately false positives on this test.
  tests['boxshadow'] = function () {
    return testPropsAll('boxShadow');
  };

  // FF3.0 will false positive on this test
  tests['textshadow'] = function () {
    return document.createElement('div').style.textShadow === '';
  };


  tests['opacity'] = function () {
    // Browsers that actually have CSS Opacity implemented have done so
    //  according to spec, which means their return values are within the
    //  range of [0.0,1.0] - including the leading zero.

    setCssAll('opacity:.55');

    // The non-literal . in this regex is intentional:
    //   German Chrome returns this value as 0,55
    // https://github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632
    return /^0.55$/.test(mStyle.opacity);
  };


  tests['cssanimations'] = function () {
    return testPropsAll('animationName');
  };


  tests['csscolumns'] = function () {
    return testPropsAll('columnCount');
  };


  tests['cssgradients'] = function () {
    /**
    * For CSS Gradients syntax, please see:
    * http://webkit.org/blog/175/introducing-css-gradients/
    * https://developer.mozilla.org/en/CSS/-moz-linear-gradient
    * https://developer.mozilla.org/en/CSS/-moz-radial-gradient
    * http://dev.w3.org/csswg/css3-images/#gradients-
    */

    var str1 = 'background-image:',
            str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));',
            str3 = 'linear-gradient(left top,#9f9, white);';

    setCss(
            (str1 + prefixes.join(str2 + str1) + prefixes.join(str3 + str1)).slice(0, -str1.length)
        );

    return contains(mStyle.backgroundImage, 'gradient');
  };


  tests['cssreflections'] = function () {
    return testPropsAll('boxReflect');
  };


  tests['csstransforms'] = function () {
    return !!testProps(['transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform']);
  };


  tests['csstransforms3d'] = function () {

    var ret = !!testProps(['perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective']);

    // Webkit’s 3D transforms are passed off to the browser's own graphics renderer.
    //   It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in
    //   some conditions. As a result, Webkit typically recognizes the syntax but
    //   will sometimes throw a false positive, thus we must do a more thorough check:
    if (ret && 'webkitPerspective' in docElement.style) {

      // Webkit allows this media query to succeed only if the feature is enabled.
      // `@media (transform-3d),(-o-transform-3d),(-moz-transform-3d),(-ms-transform-3d),(-webkit-transform-3d),(modernizr){ ... }`
      ret = Modernizr['csstransforms3d'];
    }
    return ret;
  };


  tests['csstransitions'] = function () {
    return testPropsAll('transitionProperty');
  };


  /*>>fontface*/
  // @font-face detection routine by Diego Perini
  // http://javascript.nwbox.com/CSSSupport/
  tests['fontface'] = function () {
    return Modernizr['fontface'];
  };
  /*>>fontface*/

  // CSS generated content detection
  tests['generatedcontent'] = function () {
    return Modernizr['generatedcontent'];
  };



  // These tests evaluate support of the video/audio elements, as well as
  // testing what types of content they support.
  //
  // We're using the Boolean constructor here, so that we can extend the value
  // e.g.  Modernizr.video     // true
  //       Modernizr.video.ogg // 'probably'
  //
  // Codec values from : http://github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
  //                     thx to NielsLeenheer and zcorpan

  // Note: in FF 3.5.1 and 3.5.0, "no" was a return value instead of empty string.
  //   Modernizr does not normalize for that.

  tests['video'] = function () {
    var elem = document.createElement('video'),
            bool = false;

    // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
    try {
      if (bool = !!elem.canPlayType) {
        bool = new Boolean(bool);
        bool.ogg = elem.canPlayType('video/ogg; codecs="theora"');

        // Workaround required for IE9, which doesn't report video support without audio codec specified.
        //   bug 599718 @ msft connect
        var h264 = 'video/mp4; codecs="avc1.42E01E';
        bool.h264 = elem.canPlayType(h264 + '"') || elem.canPlayType(h264 + ', mp4a.40.2"');

        bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"');
      }

    } catch (e) { }

    return bool;
  };

  tests['audio'] = function () {
    var elem = document.createElement('audio'),
            bool = false;

    try {
      if (bool = !!elem.canPlayType) {
        bool = new Boolean(bool);
        bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"');
        bool.mp3 = elem.canPlayType('audio/mpeg;');

        // Mimetypes accepted:
        //   https://developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements
        //   http://bit.ly/iphoneoscodecs
        bool.wav = elem.canPlayType('audio/wav; codecs="1"');
        bool.m4a = elem.canPlayType('audio/x-m4a;') || elem.canPlayType('audio/aac;');
      }
    } catch (e) { }

    return bool;
  };


  // Firefox has made these tests rather unfun.

  // In FF4, if disabled, window.localStorage should === null.

  // Normally, we could not test that directly and need to do a
  //   `('localStorage' in window) && ` test first because otherwise Firefox will
  //   throw http://bugzil.la/365772 if cookies are disabled

  // However, in Firefox 4 betas, if dom.storage.enabled == false, just mentioning
  //   the property will throw an exception. http://bugzil.la/599479
  // This looks to be fixed for FF4 Final.

  // Because we are forced to try/catch this, we'll go aggressive.

  // FWIW: IE8 Compat mode supports these features completely:
  //   http://www.quirksmode.org/dom/html5.html
  // But IE8 doesn't support either with local files

  tests['localstorage'] = function () {
    try {
      return !!localStorage.getItem;
    } catch (e) {
      return false;
    }
  };

  tests['sessionstorage'] = function () {
    try {
      return !!sessionStorage.getItem;
    } catch (e) {
      return false;
    }
  };


  tests['webworkers'] = function () {
    return !!window.Worker;
  };


  tests['applicationcache'] = function () {
    return !!window.applicationCache;
  };


  // Thanks to Erik Dahlstrom
  tests['svg'] = function () {
    return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect;
  };

  // specifically for SVG inline in HTML, not within XHTML
  // test page: paulirish.com/demo/inline-svg
  tests['inlinesvg'] = function () {
    var div = document.createElement('div');
    div.innerHTML = '<svg/>';
    return (div.firstChild && div.firstChild.namespaceURI) == ns.svg;
  };

  // Thanks to F1lt3r and lucideer, ticket #35
  tests['smil'] = function () {
    return !!document.createElementNS && /SVG/.test(toString.call(document.createElementNS(ns.svg, 'animate')));
  };

  tests['svgclippaths'] = function () {
    // Possibly returns a false positive in Safari 3.2?
    return !!document.createElementNS && /SVG/.test(toString.call(document.createElementNS(ns.svg, 'clipPath')));
  };

  // input features and input types go directly onto the ret object, bypassing the tests loop.
  // Hold this guy to execute in a moment.
  function webforms() {
    // Run through HTML5's new input attributes to see if the UA understands any.
    // We're using f which is the <input> element created early on
    // Mike Taylr has created a comprehensive resource for testing these attributes
    //   when applied to all input types:
    //   http://miketaylr.com/code/input-type-attr.html
    // spec: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary

    // Only input placeholder is tested while textarea's placeholder is not. 
    // Currently Safari 4 and Opera 11 have support only for the input placeholder
    // Both tests are available in feature-detects/forms-placeholder.js
    Modernizr['input'] = (function (props) {
      for (var i = 0, len = props.length; i < len; i++) {
        attrs[props[i]] = !!(props[i] in inputElem);
      }
      return attrs;
    })('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' '));

    // Run through HTML5's new input types to see if the UA understands any.
    //   This is put behind the tests runloop because it doesn't return a
    //   true/false like all the other tests; instead, it returns an object
    //   containing each input type with its corresponding true/false value

    // Big thanks to @miketaylr for the html5 forms expertise. http://miketaylr.com/
    Modernizr['inputtypes'] = (function (props) {

      for (var i = 0, bool, inputElemType, defaultView, len = props.length; i < len; i++) {

        inputElem.setAttribute('type', inputElemType = props[i]);
        bool = inputElem.type !== 'text';

        // We first check to see if the type we give it sticks..
        // If the type does, we feed it a textual value, which shouldn't be valid.
        // If the value doesn't stick, we know there's input sanitization which infers a custom UI
        if (bool) {

          inputElem.value = smile;
          inputElem.style.cssText = 'position:absolute;visibility:hidden;';

          if (/^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined) {

            docElement.appendChild(inputElem);
            defaultView = document.defaultView;

            // Safari 2-4 allows the smiley as a value, despite making a slider
            bool = defaultView.getComputedStyle &&
                              defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' &&
            // Mobile android web browser has false positive, so must
            // check the height to see if the widget is actually there.
                              (inputElem.offsetHeight !== 0);

            docElement.removeChild(inputElem);

          } else if (/^(search|tel)$/.test(inputElemType)) {
            // Spec doesnt define any special parsing or detectable UI
            //   behaviors so we pass these through as true

            // Interestingly, opera fails the earlier test, so it doesn't
            //  even make it here.

          } else if (/^(url|email)$/.test(inputElemType)) {
            // Real url and email support comes with prebaked validation.
            bool = inputElem.checkValidity && inputElem.checkValidity() === false;

          } else if (/^color$/.test(inputElemType)) {
            // chuck into DOM and force reflow for Opera bug in 11.00
            // github.com/Modernizr/Modernizr/issues#issue/159
            docElement.appendChild(inputElem);
            docElement.offsetWidth;
            bool = inputElem.value != smile;
            docElement.removeChild(inputElem);

          } else {
            // If the upgraded input compontent rejects the :) text, we got a winner
            bool = inputElem.value != smile;
          }
        }

        inputs[props[i]] = !!bool;
      }
      return inputs;
    })('search tel url email datetime date month week time datetime-local number range color'.split(' '));
  }


  // End of test definitions
  // -----------------------



  // Run through all tests and detect their support in the current UA.
  // todo: hypothetically we could be doing an array of tests and use a basic loop here.
  for (var feature in tests) {
    if (hasOwnProperty(tests, feature)) {
      // run the test, throw the return value into the Modernizr,
      //   then based on that boolean, define an appropriate className
      //   and push it into an array of classes we'll join later.
      featureName = feature.toLowerCase();
      Modernizr[featureName] = tests[feature]();

      classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);
    }
  }

  // input tests need to run.
  Modernizr.input || webforms();


  /**
  * addTest allows the user to define their own feature tests
  * the result will be added onto the Modernizr object,
  * as well as an appropriate className set on the html element
  *
  * @param feature - String naming the feature
  * @param test - Function returning true if feature is supported, false if not
  */
  Modernizr.addTest = function (feature, test) {
    if (typeof feature == "object") {
      for (var key in feature) {
        if (hasOwnProperty(feature, key)) {
          Modernizr.addTest(key, feature[key]);
        }
      }
    } else {

      feature = feature.toLowerCase();

      if (Modernizr[feature] !== undefined) {
        // we're going to quit if you're trying to overwrite an existing test
        // if we were to allow it, we'd do this:
        //   var re = new RegExp("\\b(no-)?" + feature + "\\b");  
        //   docElement.className = docElement.className.replace( re, '' );
        // but, no rly, stuff 'em.
        return;
      }

      test = typeof test == "boolean" ? test : !!test();

      docElement.className += ' ' + (test ? '' : 'no-') + feature;
      Modernizr[feature] = test;

    }

    return Modernizr; // allow chaining.
  };


  // Reset modElem.cssText to nothing to reduce memory footprint.
  setCss('');
  modElem = inputElem = null;

  //>>BEGIN IEPP
  // Enable HTML 5 elements for styling (and printing) in IE.
  if (window.attachEvent && (function () {
    var elem = document.createElement('div');
    elem.innerHTML = '<elem></elem>';
    return elem.childNodes.length !== 1;
  })()) {

    // iepp v2 by @jon_neal & afarkas : github.com/aFarkas/iepp/
    (function (win, doc) {
      win.iepp = win.iepp || {};
      var iepp = win.iepp,
            elems = iepp.html5elements || 'abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video',
            elemsArr = elems.split('|'),
            elemsArrLen = elemsArr.length,
            elemRegExp = new RegExp('(^|\\s)(' + elems + ')', 'gi'),
            tagRegExp = new RegExp('<(\/*)(' + elems + ')', 'gi'),
            filterReg = /^\s*[\{\}]\s*$/,
            ruleRegExp = new RegExp('(^|[^\\n]*?\\s)(' + elems + ')([^\\n]*)({[\\n\\w\\W]*?})', 'gi'),
            docFrag = doc.createDocumentFragment(),
            html = doc.documentElement,
            head = html.firstChild,
            bodyElem = doc.createElement('body'),
            styleElem = doc.createElement('style'),
            printMedias = /print|all/,
            body;
      function shim(doc) {
        var a = -1;
        while (++a < elemsArrLen)
        // Use createElement so IE allows HTML5-named elements in a document
          doc.createElement(elemsArr[a]);
      }

      iepp.getCSS = function (styleSheetList, mediaType) {
        if (styleSheetList + '' === undefined) { return ''; }
        var a = -1,
              len = styleSheetList.length,
              styleSheet,
              cssTextArr = [];
        while (++a < len) {
          styleSheet = styleSheetList[a];
          //currently no test for disabled/alternate stylesheets
          if (styleSheet.disabled) { continue; }
          mediaType = styleSheet.media || mediaType;
          // Get css from all non-screen stylesheets and their imports
          if (printMedias.test(mediaType)) cssTextArr.push(iepp.getCSS(styleSheet.imports, mediaType), styleSheet.cssText);
          //reset mediaType to all with every new *not imported* stylesheet
          mediaType = 'all';
        }
        return cssTextArr.join('');
      };

      iepp.parseCSS = function (cssText) {
        var cssTextArr = [],
              rule;
        while ((rule = ruleRegExp.exec(cssText)) != null) {
          // Replace all html5 element references with iepp substitute classnames
          cssTextArr.push(((filterReg.exec(rule[1]) ? '\n' : rule[1]) + rule[2] + rule[3]).replace(elemRegExp, '$1.iepp_$2') + rule[4]);
        }
        return cssTextArr.join('\n');
      };

      iepp.writeHTML = function () {
        var a = -1;
        body = body || doc.body;
        while (++a < elemsArrLen) {
          var nodeList = doc.getElementsByTagName(elemsArr[a]),
                nodeListLen = nodeList.length,
                b = -1;
          while (++b < nodeListLen)
            if (nodeList[b].className.indexOf('iepp_') < 0)
            // Append iepp substitute classnames to all html5 elements
              nodeList[b].className += ' iepp_' + elemsArr[a];
        }
        docFrag.appendChild(body);
        html.appendChild(bodyElem);
        // Write iepp substitute print-safe document
        bodyElem.className = body.className;
        bodyElem.id = body.id;
        // Replace HTML5 elements with <font> which is print-safe and shouldn't conflict since it isn't part of html5
        bodyElem.innerHTML = body.innerHTML.replace(tagRegExp, '<$1font');
      };


      iepp._beforePrint = function () {
        // Write iepp custom print CSS
        styleElem.styleSheet.cssText = iepp.parseCSS(iepp.getCSS(doc.styleSheets, 'all'));
        iepp.writeHTML();
      };

      iepp.restoreHTML = function () {
        // Undo everything done in onbeforeprint
        bodyElem.innerHTML = '';
        html.removeChild(bodyElem);
        html.appendChild(body);
      };

      iepp._afterPrint = function () {
        // Undo everything done in onbeforeprint
        iepp.restoreHTML();
        styleElem.styleSheet.cssText = '';
      };



      // Shim the document and iepp fragment
      shim(doc);
      shim(docFrag);

      //
      if (iepp.disablePP) { return; }

      // Add iepp custom print style element
      head.insertBefore(styleElem, head.firstChild);
      styleElem.media = 'print';
      styleElem.className = 'iepp-printshim';
      win.attachEvent(
            'onbeforeprint',
            iepp._beforePrint
          );
      win.attachEvent(
            'onafterprint',
            iepp._afterPrint
          );
    })(window, document);
  }
  //>>END IEPP

  // Assign private properties to the return object with prefix
  Modernizr._version = version;

  // expose these for the plugin API. Look in the source for how to join() them against your input
  Modernizr._prefixes = prefixes;
  Modernizr._domPrefixes = domPrefixes;

  // Modernizr.mq tests a given media query, live against the current state of the window
  // A few important notes:
  //   * If a browser does not support media queries at all (eg. oldIE) the mq() will always return false
  //   * A max-width or orientation query will be evaluated against the current state, which may change later.
  //   * You must specify values. Eg. If you are testing support for the min-width media query use: 
  //       Modernizr.mq('(min-width:0)')
  // usage:
  // Modernizr.mq('only screen and (max-width:768)')
  Modernizr.mq = testMediaQuery;

  // Modernizr.hasEvent() detects support for a given event, with an optional element to test on
  // Modernizr.hasEvent('gesturestart', elem)
  Modernizr.hasEvent = isEventSupported;

  // Modernizr.testProp() investigates whether a given style property is recognized
  // Note that the property names must be provided in the camelCase variant.
  // Modernizr.testProp('pointerEvents')
  Modernizr.testProp = function (prop) {
    return testProps([prop]);
  };

  // Modernizr.testAllProps() investigates whether a given style property,
  //   or any of its vendor-prefixed variants, is recognized
  // Note that the property names must be provided in the camelCase variant.
  // Modernizr.testAllProps('boxSizing')    
  Modernizr.testAllProps = testPropsAll;



  // Modernizr.testStyles() allows you to add custom styles to the document and test an element afterwards
  // Modernizr.testStyles('#modernizr { position:absolute }', function(elem, rule){ ... })
  Modernizr.testStyles = injectElementWithStyles;


  // Modernizr.prefixed() returns the prefixed or nonprefixed property name variant of your input
  // Modernizr.prefixed('boxSizing') // 'MozBoxSizing'

  // Properties must be passed as dom-style camelcase, rather than `box-sizing` hypentated style.
  // Return values will also be the camelCase variant, if you need to translate that to hypenated style use:
  //
  //     str.replace(/([A-Z])/g, function(str,m1){ return '-' + m1.toLowerCase(); }).replace(/^ms-/,'-ms-');

  // If you're trying to ascertain which transition end event to bind to, you might do something like...
  // 
  //     var transEndEventNames = {
  //       'WebkitTransition' : 'webkitTransitionEnd',
  //       'MozTransition'    : 'transitionend',
  //       'OTransition'      : 'oTransitionEnd',
  //       'msTransition'     : 'msTransitionEnd', // maybe?
  //       'transition'       : 'transitionEnd'
  //     },
  //     transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];

  Modernizr.prefixed = function (prop) {
    return testPropsAll(prop, 'pfx');
  };



  // Remove "no-js" class from <html> element, if it exists:
  docElement.className = docElement.className.replace(/\bno-js\b/, '')

  // Add the new classes to the <html> element.
                            + (enableClasses ? ' js ' + classes.join(' ') : '');

  return Modernizr;

})(this, this.document);;
!function(a,b){"function"==typeof define&&define.amd?define([],function(){return a.svg4everybody=b()}):"object"==typeof module&&module.exports?module.exports=b():a.svg4everybody=b()}(this,function(){function a(a,b,c){if(c){var d=document.createDocumentFragment(),e=!b.hasAttribute("viewBox")&&c.getAttribute("viewBox");e&&b.setAttribute("viewBox",e);for(var f=c.cloneNode(!0);f.childNodes.length;)d.appendChild(f.firstChild);a.appendChild(d)}}function b(b){b.onreadystatechange=function(){if(4===b.readyState){var c=b._cachedDocument;c||(c=b._cachedDocument=document.implementation.createHTMLDocument(""),c.body.innerHTML=b.responseText,b._cachedTarget={}),b._embeds.splice(0).map(function(d){var e=b._cachedTarget[d.id];e||(e=b._cachedTarget[d.id]=c.getElementById(d.id)),a(d.parent,d.svg,e)})}},b.onreadystatechange()}function c(c){function e(){for(var c=0;c<o.length;){var h=o[c],i=h.parentNode,j=d(i),k=h.getAttribute("xlink:href")||h.getAttribute("href");if(!k&&g.attributeName&&(k=h.getAttribute(g.attributeName)),j&&k){if(f)if(!g.validate||g.validate(k,j,h)){i.removeChild(h);var l=k.split("#"),q=l.shift(),r=l.join("#");if(q.length){var s=m[q];s||(s=m[q]=new XMLHttpRequest,s.open("GET",q),s.send(),s._embeds=[]),s._embeds.push({parent:i,svg:j,id:r}),b(s)}else a(i,j,document.getElementById(r))}else++c,++p}else++c}(!o.length||o.length-p>0)&&n(e,67)}var f,g=Object(c),h=/\bTrident\/[567]\b|\bMSIE (?:9|10)\.0\b/,i=/\bAppleWebKit\/(\d+)\b/,j=/\bEdge\/12\.(\d+)\b/,k=/\bEdge\/.(\d+)\b/,l=window.top!==window.self;f="polyfill"in g?g.polyfill:h.test(navigator.userAgent)||(navigator.userAgent.match(j)||[])[1]<10547||(navigator.userAgent.match(i)||[])[1]<537||k.test(navigator.userAgent)&&l;var m={},n=window.requestAnimationFrame||setTimeout,o=document.getElementsByTagName("use"),p=0;f&&e()}function d(a){for(var b=a;"svg"!==b.nodeName.toLowerCase()&&(b=b.parentNode););return b}return c});;
$(function () {

  $(window).on("load resize", function () {

    var
    $summaryAside,
    $summaryAsideMobileToggle;

    $summaryAsideMobileToggle = $(".summary-aside-mobile-toggle");
    // Normal page selector.
    $summaryAside = $(".summary-aside");
    // Payment Page selector.
    if ($summaryAside.length == 0) {
      $summaryAside = $(".trip-summary, .quote-summary-actions-wrapper, .display-container.traveller-panel");
    }

    $summaryAsideMobileToggle.unbind();
    if ($(".mobile-landscape-visibility-check").is(":visible")
        && ($summaryAside.data("alwaysdisplaytripsummary") === undefined
            || $summaryAside.data("alwaysdisplaytripsummary") === ""
            || $summaryAside.data("alwaysdisplaytripsummary") === "False")) {
      $summaryAside.hide();
      $summaryAsideMobileToggle.on("click", function () {
        if ($summaryAside.is(":visible")) {
          $summaryAsideMobileToggle
          .toggleClass("toggled")
          .html($(this).data('expand-trip-msg'));
        } else {
          $summaryAsideMobileToggle
          .toggleClass("toggled")
          .html($(this).data('contract-trip-msg'));
        }
        $summaryAside.slideToggle({
          duration: 600
        });
      });
    } else {
      $summaryAside.show();
    }

  });

});
;
/* globals */

// application root namespace

var wng = (function () {
    var
      version = "1.0.0";

    return {
        version: version
    };
}());;
/*globals window:false, document:false, FB:false, wng:true */

// Options available: 
//  {
//   'url': null,
//   'preliminaryUrl': null,
//   'brand': null,
//   'enable_cross_domain_tracking': null,
//   'quote': {
//     'countries': null,
//     'price': null, // Full dollar value as int
//     'plan': null,
//     'campaign_code': null,
//     'campaign_code_discount': null, 
//     'duration': null,
//     'ages': null
//    }
//  }

var _gaq = _gaq || [];
var dataLayer = dataLayer || [];

var wng = (function ($, undefined) {
  var opt, transactionID, groupedDuration, groupedAges, singleOrFamily, orderedCountries, limitedCountries, allSubdomains;

  var trackPageOnNextLoadCookieName = 'trackPageOnNextLoad';
  var trackEventOnNextLoadCookiePrefix = 'trackEventOnNextLoad';
  var trackEventOnNextLoadCounter = 1;
  var googleAnalyticsScriptLoaded = false;

  $.googleAnalytics = function (googleAnalyticsTrackingCode, googleTagManagerCode, options) {
    opt = options || {};
    $.googleAnalytics.options = opt;

    allSubdomains = document.location.hostname.replace(/^www|service/, '');

    // Set the tracking code
    _gaq.push(['_setAccount', googleAnalyticsTrackingCode]);

    _gaq.push(function() {
      googleAnalyticsScriptLoaded = true;
    });

    // Set the domain to .travelinsurancedirect.suffix
    _gaq.push(['_setDomainName', allSubdomains]);

    // Enable cross domain tracking
    if (opt.enable_cross_domain_tracking) {
      _gaq.push(['_setAllowLinker', true]);
    }

    // Set custom variable for brand
    if (opt.brand) {
      _gaq.push(['_setCustomVar', 5, 'Brand', opt.brand, 2]);
    }

    // Set custom variables for quote
    if (opt.quote) {
      // Plan and countries
      if (opt.quote.countries) {
        orderedCountries = utils.orderCountries(opt.quote.countries);
        limitedCountries = utils.limitCountries(orderedCountries);
        var plan = opt.quote.plan || 'No Plan';
        // Custom variable requires limited countries as custom variables have a max length: Documented 64 bites for Key and Value, but up to 128 seems fine
        _gaq.push(['_setCustomVar', 1, plan, limitedCountries, 2]);
      }

      // Duration
      if (opt.quote.duration) {
        groupedDuration = utils.groupDuration(opt.quote.duration);
        // Key is 
        _gaq.push(['_setCustomVar', 2, groupedDuration, String(opt.quote.duration), 2]);
      }

      // Ages 
      if (opt.quote.ages) {
        groupedAges = utils.groupAges(opt.quote.ages);

        // Technically they are already sorted as utils.groupAges performs a sort on the ages object, but if that goes these still should be sorted, and if that method is used stand alone it should sort as well.
        opt.quote.ages.sort(function (a, b) {
          return a - b;
        });

        singleOrFamily = (opt.quote.ages.length === 1) ? 'Single' : 'Family';
        _gaq.push(['_setCustomVar', 3, groupedAges, opt.quote.ages.join(', '), 2]);
      }

      // Campaign code
      if (opt.quote.campaign_code && opt.quote.campaign_code_discount) {
        _gaq.push(['_setCustomVar', 4, opt.quote.campaign_code_discount, opt.quote.campaign_code, 2]);
      } else {
        _gaq.push(['_setCustomVar', 4, 'No Discount', 'None', 2]);
      }
    }

    // Up the sitespeed sampling rate from 1% to 100% - note that the current maximum google gives 
    // you is 10%.
    _gaq.push(['_setSiteSpeedSampleRate', 10]);

    // Track any urls passed in from the previous page
    var urlFromLastPage = utils.getCookie(trackPageOnNextLoadCookieName);

    if (urlFromLastPage) {
      _gaq.push(['_trackPageview', urlFromLastPage]);
      utils.deleteCookie(trackPageOnNextLoadCookieName);
    }

    // Track the preliminaryUrl if it exists
    if (opt.preliminaryUrl) {
      _gaq.push(['_trackPageview', opt.preliminaryUrl]);
    }

    // Track the initial page load
    if (opt.url) {
      _gaq.push(['_trackPageview', opt.url]);
    } else {
      _gaq.push(['_trackPageview']);
    }

    // Load GA javascript asynchronously
    var ga = document.createElement('script');
    ga.type = 'text/javascript';
    ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'stats.g.doubleclick.net/dc.js';
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(ga, s);

    // Track any events passed in from the previous page
    var eventsFromLastPage = utils.findCookies(new RegExp("^" + trackEventOnNextLoadCookiePrefix));

    for (var key in eventsFromLastPage) {
      var decodedEvent = utils.decodeEvent(eventsFromLastPage[key]);
      wng.googleAnalytics.trackEvent.apply(this, decodedEvent);
      utils.deleteCookie(key);
    }

    // Set the fbAsyncInit value to be a callback that tracks FB social actions
    window.fbAsyncInit = function () {
      wng.googleAnalytics.listenForFacebookSocialEvents();
    };

    // Set up for Google Tag Manager
    dataLayer.push({ 'Custom Tracking URL': opt.url });

    if (opt.preliminaryUrl) {
      dataLayer.push({ 'Preliminary URL': opt.preliminaryUrl });  
    }
    
    if (opt.quote) {
      // Send quote destinations to Google Tag Manager
      if (opt.quote.countries) {
        dataLayer.push({'Destination Countries': utils.limitCountries(utils.orderCountries(opt.quote.countries))});
      }

      // Send price to Google Tag Manager
      if (opt.quote.price) {
        dataLayer.push({'Quote Price': Number(opt.quote.price)});
      }
    }

    // Load Google Tag Manager
    (function(w,d,s,l,i) {
      w[l]=w[l]||[];
      w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});
      var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;
      j.src='//www.googletagmanager.com/gtm.js?id='+i+dl;
      f.parentNode.insertBefore(j,f);
    }) (window,document,'script','dataLayer',googleTagManagerCode);
  };

  // Track a virtual page, this is in addition to the inital page tracking
  $.googleAnalytics.trackVirtualPage = function (url) {
    _gaq.push(['_trackPageview', url]);
  };

  // Track a virtual page, but not until just before the next page is tracked.
  // Useful for when the page will unload before a request can be sent to Google Analytics.
  // Note that there can only be one page tracked this way.
  $.googleAnalytics.trackVirtualPageOnNextLoad = function (url) {
    utils.setCookie(trackPageOnNextLoadCookieName, url);
  };

  // Track an event
  // Note: the value option must be an integer
  $.googleAnalytics.trackEvent = function (category, action, eventOptions) {
    // Options available:
    // {
    //   'label': null,
    //   'value': null
    // }

    if (eventOptions == undefined) {
      eventOptions = {};
    }

    _gaq.push(['_trackEvent', category, action, eventOptions['label'], eventOptions['value']]);
  };


  // Track an event, but not until just before the next page is tracked.
  // Useful for when the page will unload before a request can be sent to Google Analytics.
  $.googleAnalytics.trackEventOnNextLoad = function (category, action, eventOptions) {
    var encodedEvent = utils.encodeEvent(category, action, eventOptions);
    var cookieName = trackEventOnNextLoadCookiePrefix + trackEventOnNextLoadCounter;
    utils.setCookie(cookieName, encodedEvent);
    trackEventOnNextLoadCounter++;
  };

  // Create a transaction. Note order ID should be unique and allow the looking up of the order in the DB. Total should just be an int.
  $.googleAnalytics.createTransaction = function (orderID, total) {
    transactionID = orderID;
    _gaq.push(['_addTrans',
      String(transactionID),    // order ID - required
      '',                       // affiliation or store name
      String(total),            // total - required
      '0',                      // tax
      '0',                      // shipping
      '',                       // city
      '',                       // state or province
      ''                        // country
    ]);
  };

  // Add policy details to a transaction, this method is required. singleOrFamily should be 'Single' or 'Family', both days
  // and price should be an int 
  $.googleAnalytics.addPolicyDetails = function (price) {
    var variation = singleOrFamily + ' ' + groupedDuration;

    _gaq.push(['_addItem',
      String(transactionID),  // order ID - required
      variation,              // SKU/code - required
      'Policy',               // product name - not required by spec but appears to be required anyway
      orderedCountries,       // category or variation
      String(price),          // unit price - required
      '1'                     // quantity - required
    ]);
  };

  // Add policy excess reduction, both newPolicyExcess and price should be an int
  $.googleAnalytics.addPolicyExcessReduction = function (newPolicyExcess, price) {
    _gaq.push(['_addItem',
      String(transactionID),                      // order ID - required
      '$' + newPolicyExcess + ' policy excess',   // SKU/code - required
      'Policy excess reduction',                  // product name - not required by spec but appears to be required anyway
      orderedCountries,                           // category or variation
      String(price),                              // unit price - required
      '1'                                         // quantity - required
    ]);
  };

  // Add car rental excess cover increase, both newExcessCover and price should be an int  
  $.googleAnalytics.addCarRentalExcessIncrease = function (newExcessCover, price) {
    _gaq.push(['_addItem',
      String(transactionID),                  // order ID - required
      '$' + newExcessCover + ' car excess',   // SKU/code - required
      'Car excess cover increased',           // product name - not required by spec but appears to be required anyway
      orderedCountries,                       // category or variation
      String(price),                          // unit price - required
      '1'                                     // quantity - required
    ]);
  };

  // Add aditional item, both value and price should be an int, description is a string of what the user entered as 'item name'
  $.googleAnalytics.addAdditionalItem = function (value, description, price) {
    _gaq.push(['_addItem',
      String(transactionID),            // order ID - required
      '$' + value + ' ' + description,  // SKU/code - required
      'Additional item',                // product name - not required by spec but appears to be required anyway
      orderedCountries,                 // category or variation
      String(price),                    // unit price - required
      '1'                               // quantity - required
    ]);
  };

  // Add Footprints, price should be an int, projectName is a string
  $.googleAnalytics.addFootprints = function (projectName, price) {
    _gaq.push(['_addItem',
      String(transactionID),            // order ID - required
      projectName,                      // SKU/code - required
      'Footprints donation',            // product name - not required by spec but appears to be required anyway
      orderedCountries,                 // category or variation
      String(price),                    // unit price - required
      '1'                               // quantity - required
    ]);
  };

  // Add Pre-Ex, price should be an int
  $.googleAnalytics.addPreEx = function (price) {
    _gaq.push(['_addItem',
      String(transactionID),            // order ID - required
      'Medial premium',                 // SKU/code - required
      'Pre-Ex cover',                   // product name - not required by spec but appears to be required anyway
      orderedCountries,                 // category or variation
      String(price),                    // unit price - required
      '1'                               // quantity - required
    ]);
  };

  // Add Business benefits cover, price should be an int
  $.googleAnalytics.addBusinessBenefitCover = function (price) {
    _gaq.push(['_addItem',
      String(transactionID),            // order ID - required
      'Business premium',                 // SKU/code - required
      'Business Benefit cover',                   // product name - not required by spec but appears to be required anyway
      orderedCountries,                 // category or variation
      String(price),                    // unit price - required
      '1'                               // quantity - required
    ]);
  };

  // Add Snow sports cover, price should be an int
  $.googleAnalytics.addSnowSportsCover = function (price) {
    _gaq.push(['_addItem',
      String(transactionID),            // order ID - required
      'Snow sports premium',                 // SKU/code - required
      'Snow sports cover',                   // product name - not required by spec but appears to be required anyway
      orderedCountries,                 // category or variation
      String(price),                    // unit price - required
      '1'                               // quantity - required
    ]);
  };

  // This has to be called after the transaction has been built to submit it.
  $.googleAnalytics.submitTransaction = function () {
    _gaq.push(['_trackTrans']);
  };

  // This adds listeners to track Facebook likes, unlikes, and shares. This has to be called after the FB object has been created.
  $.googleAnalytics.listenForFacebookSocialEvents = function () {
    try {
      if (FB && FB.Event && FB.Event.subscribe) {
        FB.Event.subscribe('edge.create', function (opt_target) {
          _gaq.push(['_trackSocial', 'Facebook', 'Like', opt_target]);
        });

        FB.Event.subscribe('edge.remove', function (opt_target) {
          _gaq.push(['_trackSocial', 'Facebook', 'Unlike', opt_target]);
        });

        FB.Event.subscribe('message.send', function (opt_target) {
          _gaq.push(['_trackSocial', 'Facebook', 'Send', opt_target]);
        });
      }
    } catch (e) { }
  };

  // Load a script tag when window load fires
  $.googleAnalytics.loadScriptOnLoad = function (url) {
    utils.fireOnWindowLoad(function () {
      utils.loadScript(url);
    });
  };

  // TODO: Might be better to use _getLinkerUrl for both of the following! This would better line up with how
  // universal analytics behaves

  // Call this whenever an internal, cross domain link is clicked. Let the link continue as normal
  $.googleAnalytics.adjustLinkForCrossDomainTracking = function(link) {
    if (googleAnalyticsScriptLoaded) {
      _gaq.push(['_link', url]);
    }
  }

  // Call this whenever an internal, cross domain form is submitted. Prevent default on the form 
  // itself depending on the value returned
  // Note: This code is not unit tested due to it's effect on page state
  $.googleAnalytics.crossDomainPostWithSuccess = function(formDomElement) {
    if (googleAnalyticsScriptLoaded) {
      _gaq.push(['_linkByPost', formDomElement]);

      return true;
    } else {
      return false;
    }
  }

  var utils = $.googleAnalytics.utils = {
    // Convert an int value for days into a standardised string format
    groupDuration: function (days) {
      var approximateMonth = 365 / 12;

      if (days < 28) {
        return days + (days == 1 ? ' day' : ' days');
      } else if (days < Math.round(3 * approximateMonth)) {
        return Math.floor(days / 7) + ' weeks';
      } else {
        return Math.floor((days + 1) / approximateMonth) + ' months'; // +1 on days to fudge the numbers slightly, so 91 days = 3 months (instead of 91.25+), and 12 months is guaranteed for 365 / 12 * 12 in case of a rounding error
      }
    },

    // Convert days into weeks
    weekDuration: function (days) {
      var weeks = Math.floor(days / 7);

      return weeks + (weeks == 1 ? ' week' : ' weeks');
    },

    // Group an array of ages into meaningful strings
    groupAges: function (ages) {
      var groupedAges = [];

      ages.sort(function (a, b) {
        return a - b;
      });

      for (var i = 0; i < ages.length; i++) {
        var groupedAge;
        var age = ages[i];

        if (age < 18) {
          groupedAge = 'Under 18';
        } else if (age < 25) {
          groupedAge = '18 - 24';
        } else if (age < 35) {
          groupedAge = '25 - 34';
        } else if (age < 45) {
          groupedAge = '35 - 44';
        } else if (age >= 45) {
          groupedAge = '45+';
        }

        groupedAges.push(groupedAge);
      }

      return groupedAges.join(', ');
    },

    // Order the country list alphabetically
    orderCountries: function (countryList) {
      var countries = countryList.split('|');

      countries.sort();

      return countries.join('|');
    },

    // Limit countries to 100 characters max, truncating before the | - this is important for custom variables as they have a max length (speced 64 bytes, 128 seems okay)
    limitCountries: function (countryList) {
      var match = countryList.match(/^(.{0,100})(?:\|.*)?$/);

      return match[1];
    },

    // Set an individual cookie
    setCookie: function (name, value, options) {
      options = options || {};

      var cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value);

      if (options.expires) {
        var expires;

        if (typeof options.expires == 'number') {
          // A number of days was passed in, convert it into a date from now
          expires = new Date();
          expires.setDate(expires.getDate() + options.expires);
        } else {
          // A date was passed in, just use the date
          expires = options.expires;
        }

        cookie += '; expires=' + expires.toUTCString();
      }

      // Even though cookies normally default to current path, it is more useful to default to root for analytics
      cookie += '; path=' + (options.path || '/');

      // Even though cookies normally default to current domain, it is more useful to default to parent domain for analytics. 
      // Note that this means we lose the ability to set a domain without a . prefix, as the only way to do that is to not add a 'domain=' to the cookie.
      cookie += '; domain=' + (options.domain || allSubdomains);

      if (options.secure) {
        cookie += '; secure';
      }

      document.cookie = cookie;

      return cookie;
    },

    // Get an individual cookie by name.
    // Keep in mind, it's possible to have multiple cookies with the same name, eg: one for .demo.com, another for subdomain.demo.com, and a third for .demo.com/cheese.
    // There is no way to differentiate between these, and a random one will be returned. In other words, don't reuse names between domain / path levels.
    getCookie: function (name) {
      var cookies = utils.getCookies();

      for (var cookieName in cookies) {
        if (cookieName == name) {
          return cookies[cookieName];
        }
      }

      return null;
    },

    // Finds cookies by name based on a passed in regex. Returns an filtered object of cookies
    findCookies: function (pattern) {
      var allCookies = utils.getCookies();
      var matchingCookies = {};

      for (var cookieName in allCookies) {
        if (cookieName.match(pattern)) {
          matchingCookies[cookieName] = allCookies[cookieName];
        }
      }

      return matchingCookies;
    },

    // Returns an object of all cookies decoded
    getCookies: function () {
      var rawCookies = document.cookie.split('; ');
      var cookies = {};

      for (var i = 0; i < rawCookies.length; i++) {
        var rawCookie = rawCookies[i].split('=');
        cookies[decodeURIComponent(rawCookie[0])] = decodeURIComponent(rawCookie[1] || ''); // IE saves empty cookie strings as just the cookie name, sans =, so cookie[1] might be null
      }

      return cookies;
    },

    // Remove a cookie, this is done by setting a cookie with a date of yesterday.
    // Keep in mind that if you specify path or domain when you create the cookie, you have to also specify them when you destroy it.
    deleteCookie: function (name, options) {
      options = options || {};
      options.expires = -1;

      utils.setCookie(name, '', options);
    },

    // Accepts an event, and encodes as a string - makes use of encodeURIComponent to make sure things can be split safely later
    encodeEvent: function (category, action, eventOptions) {
      eventOptions = eventOptions || {};

      var categoryString = 'category:' + encodeURIComponent(category);
      var actionString = 'action:' + encodeURIComponent(action);
      var labelString = 'label:' + encodeURIComponent(eventOptions['label'] || '');
      var valueString = 'value:' + (eventOptions['value'] || '');

      return [categoryString, actionString, labelString, valueString].join(';');
    },

    // Accepts an encoded event, and returns an array of arguments
    decodeEvent: function (encodedEvent) {
      var match = encodedEvent.match(/^category:(.+);action:(.+);label:(.+)?;value:(.+)?$/);
      var options = {};

      if (match[3]) {
        options['label'] = decodeURIComponent(match[3]);
      }

      if (match[4]) {
        options['value'] = Number(match[4]);
      }

      return [decodeURIComponent(match[1]), decodeURIComponent(match[2]), options];
    },

    // Attaches passed in callbacks to the browsers window load event
    fireOnWindowLoad: function (toFire) {
      if (window.addEventListener) {
        // One for normal browsers
        window.addEventListener('load', toFire, false);
      } else if (window.attachEvent) {
        // One for IE 8 and below
        window.attachEvent('onload', toFire);
      }
    },

    // Load a script tag
    loadScript: function (url) {
      var script = document.createElement('script');
      script.type = 'text/javascript';
      script.async = true;
      script.src = url;
      var firstScriptTag = document.getElementsByTagName('script')[0];
      firstScriptTag.parentNode.insertBefore(script, firstScriptTag);
    }
  };

  return $;

})(wng || {});

// Namespaced under wng, but also assigned to window.googleAnalytics for backwards compatibility across brands
window.googleAnalytics = wng.googleAnalytics;
;
var vars = [],
    hash;

var hashSplit = function() {
    var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
    for (var i = 0; i < hashes.length; i++) {
        hash = hashes[i].split('=');
        vars.push(hash[0]);
        vars[hash[0]] = hash[1];
    }
} (vars);

if ($.inArray("baseline", vars) > -1) {
    $('body').addClass('baseline');
}

// END DEBUG


Modernizr.addTest('box-sizing', function() {
  var test = document.createElement('div'),
      root = document.documentElement.appendChild(document.createElement('body'));
      
  test.style.cssText = '-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;padding:0 10px;margin:0;border:0;position:absolute;top:0;left:0;width:100px';
  root.appendChild(test);
  
  var ret = test.offsetWidth === 100;
        
  root.removeChild(test);
  document.documentElement.removeChild(root);
  
  return ret;
});

jQuery.removeRequestFlag = function (item) {
    item.attr('requesting', 'false');
}

// PRELOAD FUNCTION

function preload(arrayOfImages) {
  $(arrayOfImages).each(function () {
    $('<img/>')[0].src = this;
  });
}

preload(
    ["/Content/styles/i/spinner.gif"]
);

// CUSTOM DROPDOWN MENU

$(function () {
  // HTML for the menu which will be appended. Note the inactive class to start.
  var html = "<div id=\"dropdown-container\" class=\"inactive\">" +
                "<div class=\"arrow\"></div>" +
                "<ul id=\"menu\">" +
                  "<li><a href=\"/what-we-cover\">What we cover</a></li>" +
                  "<li><a href=\"/what-we-dont-cover\">What we don't cover</a></li>" +
                  "<li><a href=\"/how-to-make-a-claim\">How to Claim</a></li>" +
                  "<li><a href=\"/frequently-asked-questions\">Questions & Answers</a></li>" +
                  "<li><a href=\"/about-travel-insurance-direct\">About TID</a></li>" +
                  "<li><a href=\"/travel-insurance-guide\">Travel Insurance Guide</a></li>" +
                "</ul>" +
              "</div>";

  // Append the html for the menu
  var $targetLink = $("#dropdown-travel-insurance");
  $targetLink.append(html);

  $targetLink.mouseover(function () {
    $(this).children("#dropdown-container").addClass("active").removeClass("inactive");
  });

  $("#menu, #dropdown-travel-insurance").mouseout(function () {
    $("#dropdown-container").removeClass("active").addClass("inactive");
  });

});

// MAKE BUTTON-LIKE divs click the internal A
$(function () {
    $("div.button-like:not(.disabled)").on("click", function (e) {
    if ($(this).children("a").attr("target") == '_blank') {
      window.open($(this).children("a").attr("href"), "_blank");
    } else {
      window.location.href = $(this).children("a").attr("href");
    }
    e.preventDefault();
  });
});

// CAPITALIZE Input Fields based on class='capitalize'
$(document).on("focusout", ".capitalize", function () {
    var $el = $(this),
        text = $el.val() || '';
    if (text) {
        $el.removeClass('capitalize');
        // Is text all upper case or all lower case
        // We don't want to modify it if people have already capitalized - e.g. O'Reilly, McDonald
        if ((text === text.toLowerCase()) ||
            (text === text.toUpperCase())) {
            var capitalizeText = toTitleCase(text);
            $el.val(capitalizeText);
        }
    }
});

function toTitleCase(str) {
    return str.replace(/\w+/g, function (txt) { return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); });
}

//Adds error class around nearby input-group if the app doesn't automatically apply it already - fallback method
$(document).ready(function () {
    $(".input-validation-errors").each(function () {
        var $el = $(this),
            text = $el.val() || '';
        if (text) {
            if (!$(this).siblings(".input-group").hasClass("error")) {
                $(this).siblings(".input-group").addClass("error");
            }
        }
    });
    $('body').on('submit', '.js-loader', function () {
        $('body').append(
            '<div style="position:fixed;left:0;right:0;top:0;bottom:0;z-index:999;background:#fff;opacity:0.8;filter:alpha(opacity=80)">' +
            '<div style="position:relative;top:50%;margin-top:-35px;text-align:center">' +
            '<img src="/Content/styles/i/spinner-large.gif" alt=""><br/>Loading&hellip;' +
            '</div>' +
            '</div>');
    });
});

// TID AU UTILS
// A global variable for buttons being clicked
globalButtonClicked = false;

var Btob = {

  addSpinner:
        function ($element, message) {
          setTimeout(function () {
            var $spinner = $("<span/>").addClass("spinner");
            if (message) { $spinner.html(message); }
            if (!globalButtonClicked) {
              $element
                .attr("disabled", "disabled")
                .after($spinner);
            }
            globalButtonClicked = true;
          }, 5);
        },

  handleManualUpdates:
        function () {
          $manualUpdateTriggers = $('.manual-update-trigger');
          $manualUpdateTriggers.each(
            function () {
              $manualUpdateTrigger = $(this);
              $container = $manualUpdateTrigger.closest('.manual-update-container');

              $manualUpdateBlock = $container.find('.manual-update');
              if ($manualUpdateBlock.length > 0) {
                $manualUpdateBlock.hide();
              }

              if ($manualUpdateTrigger.attr("type") == 'text') {
                $manualUpdateTrigger.unbind('blur');
                $manualUpdateTrigger.blur(Btob.clickNearestSubmit);
              }
              else {
                $manualUpdateTrigger.unbind('change');
                $manualUpdateTrigger.change(Btob.clickNearestSubmit);
              }
            });
        },

  clickNearestSubmit:
        function () {
          $this = $(this);
          $container = $this.closest('.manual-update-container');
          $manualUpdateSubmit = $container.find('input[type="submit"]');
          if ($manualUpdateSubmit.length > 0) {
            $($manualUpdateSubmit[0]).click();
          }
        },

  ajaxPost:
        function (data, url, successCallback, failureCallback, dataType) {
          if (dataType == undefined || dataType == null) {
            dataType = "json";
          }
          
          Btob.doAjax('POST', data, url, successCallback, failureCallback, dataType);
        },

  ajaxGet:
        function (url, successCallback, failureCallback, dataType) {
          if (dataType == undefined || dataType == null) {
            dataType = "json";
          }

          Btob.doAjax('GET', undefined, url, successCallback, failureCallback, dataType);
        },

  doAjax:
        function (requestType, data, url, successCallback, failureCallback, dataType) {
          if (dataType == undefined || dataType == null) {
            dataType = "json";
          }
          
          if (successCallback === undefined) {
              successCallback = Btob.replaceContent;
          }

          if (failureCallback === undefined) {
              failureCallback = Btob.showUnknownError;
          }

          $.ajax({
            type: requestType,
            url: url,
            cache: false,
            data: data,
            dataType: dataType,
            success: successCallback,
            error: failureCallback
          });
        },

  getFormData:
        function ($caller, $form) {
          var serializedForm = $form.serialize();
          // JQuery does not include the submit button in the serialized form, but we need it.
          return serializedForm + '&' + $caller.attr('name') + '=' + $caller.attr('value');
        },
  
  replaceContentFromHtml:
          function ($target, data, noAnimation) {
              if (noAnimation === undefined) {
                  $target.animate(
                    { "opacity": "0" },
                    {
                        duration: 200,
                        complete: function () {
                            $target.html(data);
                            $target.animate({ "opacity": "1" }, 200);
                        }
                    }
                  );
              }
              else {
                  $target.html(data);
              }
          },

  replaceContent:
        function (data) {
          // First clear out any old global messages.
          var $messagesPanel = $('#global-messages');
          if ($messagesPanel.length > 0) {
            $messagesPanel.empty();
          }

          // Remove spinners
          $(".spinner").remove();
          var $matched;

          for (var i = 0; i < data.parts.length; i++) {
            if (data.parts[i].hideId != undefined) {
              $matched = $('#' + data.parts[i].hideId);
              if ($matched.length > 0) {
                $matched.css("display", "none");
                continue;
              }
            }

            if (data.parts[i].showId != undefined) {
              $matched = $('#' + data.parts[i].showId);
              if ($matched.length > 0) {
                $matched.css("display", "block");
                continue;
              }
            }

            var $newContent = $($.trim(data.parts[i].content.html));

            if (data.parts[i].withinId !== undefined) {
              $matched = $('#' + data.parts[i].withinId);
              if ($matched.length > 0) {
                var oldHeight = $matched.height();
                $matched.html($newContent);

                var newHeight = $matched.height();
                $matched.css("height", oldHeight + "px");
                $matched.animate({ height: newHeight + "px" }, 800,
                  function () {
                    $(this).css("height", "auto");
                  });
                continue;
              }
            }

            if (data.parts[i].replaceId !== undefined) {
              $matched = $('#' + data.parts[i].replaceId);
              if ($matched.length > 0) {
                $matched.replaceWith($newContent);
                continue;
              }
            }

            if (data.parts[i].afterId !== undefined) {
              $matched = $('#' + data.parts[i].afterId);
              if ($matched.length > 0) {
                $matched.after($newContent);
                continue;
              }
            }

            if (data.parts[i].beforeId !== undefined) {
              $matched = $('#' + data.parts[i].beforeId);
              if ($matched.length > 0) {
                $matched.before($newContent);
                continue;
              }
            }

            if (data.parts[i].withinClass !== undefined) {
              $matched = $('.' + data.parts[i].withinClass);
              if ($matched.length > 0) {
                $matched.html($newContent);
                continue;
              }
            }

            if (data.parts[i].replaceClass !== undefined) {
              $matched = $('.' + data.parts[i].replaceClass);
              if ($matched.length > 0) {
                $newContent.replaceAll('.' + data.parts[i].replaceClass);
                continue;
              }
            }

            if (data.parts[i].afterClass !== undefined) {
              $matched = $('.' + data.parts[i].afterClass);
              if ($matched.length > 0) {
                $matched.after($newContent);
                continue;
              }
            }

            if (data.parts[i].beforeClass !== undefined) {
              $matched = $('.' + data.parts[i].beforeClass);
              if ($matched.length > 0) {
                $matched.before($newContent)
                continue;
              }
            }
          }
          Btob.updateUrlSessionTokens();
        },

  
  updateUrlSessionTokens:
        function () {
          $sessionTokenDivs = $('.session-tokens');
          if ($sessionTokenDivs.length > 0) {
            $sessionTokenHiddens = $($sessionTokenDivs[0]).children('input[type="hidden"]');
            // update any links on the page containing this input's name in the URL params.
            $sessionTokenHiddens.each(
              function () {
                $this = $(this);
                var tokenKey = $this.attr('name');
                var newToken = $this.attr('value');
                $('a[href*=' + tokenKey + "]").each(
                  function () {
                    $this = $(this);
                    var hrefValue = $this.attr('href');
                    var oldToken = Btob.getUrlParamValue(tokenKey, hrefValue);
                    hrefValue = hrefValue.replace(oldToken, newToken);
                    $this.attr('href', hrefValue);
                  });
              });
          }
        },

  showUnknownError:
        function () {
          var errorMessageHtml =
                '<div id="global-messages">' +
                '<div class="messages error">' +
                '<h3>Oops!</h3>' +
                '<ul>' +
                '<li>' +
                'Something went wrong. Please try again.' +
                '</li>' +
                '</ul>' +
                '</div>' +
                '</div>',
              $messagesPanel = $('#global-messages');

          if ($messagesPanel.length > 0) {
            $messagesPanel.replaceWith(errorMessageHtml);
          }
          else {
            $('#masthead').after(errorMessageHtml);
          }
        },

  onAjaxStart:
        function ($caller) {
          // Append a div to the current form container which contains the whitewash
          // and the ajax spinner.
          var spinnerHtml = "<span class='spinner'></span>";

          // Check to see if there's already a spinner... (IE fix?)
          if ($(".spinner").length < 1) {
            $caller.after(spinnerHtml);
          }
          return $caller;
        },

  getUrlParamValue:
        function (key, url) {
          if (url === undefined) {
            url = window.location.search;
          }
          var re = new RegExp("[?|&]" + key + "=(.*?)&");
          var matches = re.exec(url + "&");
          if (!matches || matches.length < 2) {
            return "";
          }
          return decodeURIComponent(matches[1].replace("+", " "));
        },
  
    recordPartnerVisitorCount:
        function() {
            $affilliateTrackingId = this.getUrlParamValue('affiliateTrackingId', window.location.url);
            if ($affilliateTrackingId != "") {
                this.ajaxGet("/Home/RecordAffiliateVisitorHit?affiliateTrackingId=" + $affilliateTrackingId,
                    undefined, undefined, null);
            }
        }

};

var AdditionalInfo = (function () {
    return {
        hookInfoPanel: function (selector) {
            $(selector).click(function (e) {
                e.preventDefault();
                var url = $(this).attr("href");
                Btob.ajaxGet(url, replaceContent, null, "html");
                return false;
            });

            var additionalInfoPanel = $('#AdditionalInfoPanel');
            function replaceContent(data) {
              Btob.replaceContentFromHtml(additionalInfoPanel, data);
            }

            additionalInfoPanel.on('click', '#closeInfoPanel', function () {
              Btob.replaceContentFromHtml(additionalInfoPanel, "");
            });
        }
    };
}());;
/*globals wng:false, wng:false, $:false, document:false */

// centralised definition of tracking events for all pages / partials

wng.googleAnalytics.tracking = (function (undefined) {
    var widgetTracking = {};

    widgetTracking.quote = function (options) {
        var opt = $.extend({
        }, options);

        // General quote page tracking

        // Clicked edit trip button
        $('[data-analytics-id="open-edit-trip"]').on('click.quote', function () {
            wng.googleAnalytics.trackEventOnNextLoad('Quote Page', 'Clicked Edit Your Trip', { 'brand': wng.currentBrandName });
        });

        // Expanded all policy benefits
        $('[data-analytics-id="expand-all-benefits"]').on('click', function () {
            wng.googleAnalytics.trackEvent('Quote Page', 'Expanded All Benefits', { 'brand': wng.currentBrandName });
        });

        // View the PDS above benefits
        $('[data-analytics-id="view-pds-top"]').on('click', function () {
            wng.googleAnalytics.trackEvent('Quote Page', 'Viewed PDS', {
                'label': 'Above Benefits',
                'brand': wng.currentBrandName
            });
        });

        // Expanded or collapsd a benefit
        $('[data-analytics-id="benefits-list"] dl.top-benefit > dt.benefit-header').on('click', function () {
            var $benefitName = $(this).children('dl').children('[data-analytics-id="benefit-title"]').children('span');

            wng.googleAnalytics.trackEvent('Quote Page', 'Expanded or Collapsed a Benefit', {
                'label': ($benefitName.length > 0) ? $benefitName.text() : '',
                'brand': wng.currentBrandName
            });
        });
    };
    
    widgetTracking.quoteOptions = function(options) {
        var opt = $.extend({
        }, options);
        
        // Error adding specified item
        if ($('.interaction.specified-items .input-validation-errors').length > 0) {
            $lastTr = $('.interaction.specified-items [data-analytics-id="specified-item-row"]').last();
            itemName = $lastTr.find('[data-analytics-id="item-name"] input').val() || "[No Entry Provided]";
            itemValue = $lastTr.find('[data-analytics-id="item-value"] input').val() || "[No Entry Provided]";
            wng.googleAnalytics.trackEventOnNextLoad('Options Page', 'Failed to Add or Update Specified Item',
              {
                  'label': itemName + ' - $' + itemValue,
                  'brand': wng.currentBrandName
              }
            );
        }
        
        // Add specified item - when an item is successfully added
        if ($('.interaction.specified-items .input-validation-errors').length === 0) {
            $lastTr = $('.interaction.specified-items [data-analytics-id="specified-item-row"]').last();
            itemName = $lastTr.find('[data-analytics-id="item-name"] input').val();
            itemValue = $lastTr.find('[data-analytics-id="item-value"] input').val();
            // Check that this is not a new empty row
            if (itemName && itemValue) {
                wng.googleAnalytics.trackEventOnNextLoad('Options Page', 'Added or Updated Specified Item',
                    {
                        'label': itemName + ' - $' + itemValue,
                        'brand': wng.currentBrandName
                    }
                );
            }
        }
        
        // Remove specified item - fire when removing an item is attempted 
        $('[data-analytics-id="option-remove-spec-item"]').on("mousedown", function () {
            var $tr = $(this).closest('[data-analytics-id="specified-item-row"]');
            var itemName = $tr.find('[data-analytics-id="item-name"] input').val();
            var itemValueAsInt = $tr.find('[data-analytics-id="item-value"] input').val();
            // Check that this is not a row with an empty name/value (due to validation error)
            if (itemName && itemValueAsInt) {
                wng.googleAnalytics.trackEventOnNextLoad('Options Page', 'Remove Specified Item',
                  {
                      'label': itemName + ' - $' + itemValueAsInt,
                      'brand': wng.currentBrandName
                  }
                );
            }
        });
        
        // Changed car excess cover value
        $('[data-analytics-id="option-rental-excess"] select').on('change', function () {
            var newValue = $(this).find(':selected').text();
            wng.googleAnalytics.trackEventOnNextLoad('Options Page', 'Modified Car Rental Excess', {
                'label': newValue,
                'brand': wng.currentBrandName
            });
        });
        
        // Clicked Continue button (mousedown to be sure to get in before submit or validation)
        $('[data-analytics-id="option-continue-to-terms"]').on('mousedown', function () {
            wng.googleAnalytics.trackEventOnNextLoad('Options Page', 'Clicked Continue (to Terms)', { 'brand': wng.currentBrandName }
);
        });
        
        // Clicked email your quote submit (mousedown to be sure to get in before submit)
        $('[data-analytics-id="email-quote"]').on('mousedown', function () {
            wng.googleAnalytics.trackEventOnNextLoad('Options Page', 'Emailed Quote', { 'brand': wng.currentBrandName }
);
        });
        
        // Scroll tracking

        $('[data-analytics-id="option-rental-excess"]').scrollTracking(function () {
            wng.googleAnalytics.trackEvent('Options Page', 'Saw Rental Excess Option', { 'brand': wng.currentBrandName }
);
        });

        $('[data-analytics-id="option-total-bottom"]').scrollTracking(function () {
            wng.googleAnalytics.trackEvent('Options Page', 'Saw Bottom Quote Summary', { 'brand': wng.currentBrandName }
);
        });
    };

    widgetTracking.policyDetails = function (options) {
        var
          opt = $.extend({
          }, options);

        // Log in inline button is clicked
        $('[data-analytics-id="details-login-member"]').on('mousedown', function () {
            wng.googleAnalytics.trackEventOnNextLoad('Your Details Page', 'Clicked Log In', {
                label: "inline",
                'brand': wng.currentBrandName
            });
        });

        // Forgot password in side bar is clicked
        $('[data-analytics-id="details-forgot-password"]').on('mousedown', function () {
            wng.googleAnalytics.trackEventOnNextLoad('Your Details Page', 'Clicked Forgot Password', {
                label: "modal from inline",
                'brand': wng.currentBrandName
            });
        });

        // Clicked Continue (already signed in)
        $('[data-analytics-id="details-continue-member"]').on('mousedown', function () {
            wng.googleAnalytics.trackEventOnNextLoad('Membership', 'Continued as signed-in member from Your Details Page', { 'brand': wng.currentBrandName });
        });

        // Clicked Purchase as Guest
        $('[data-analytics-id="details-continue-guest"]').on('mousedown', function () {
            wng.googleAnalytics.trackEventOnNextLoad('Membership', 'Continued as a guest from Your Details Page', { 'brand': wng.currentBrandName });
        });

        // Clicked Continue (create new membership)
        $('[data-analytics-id="details-signup-member"]').on('mousedown', function () {
            wng.googleAnalytics.trackEventOnNextLoad('Membership', 'Continued and chose new membership with password from Your Details Page', { 'brand': wng.currentBrandName });
        });
    };

    widgetTracking.reviewAndPay = function (options) {
        var
          opt = $.extend({
          }, options);

        // Clicked edit trip button
        $('[data-analytics-id="open-edit-trip"]').on('click.quote', function () {
            wng.googleAnalytics.trackEventOnNextLoad('Payment Page', 'Clicked Edit Your Trip', { 'brand': wng.currentBrandName });
        });
    };

    var setup = function (widgetId, options) {
        if (widgetTracking[widgetId]) {
            widgetTracking[widgetId](options);
        } else {
            throw new Error("Tracking is not defined for the identifier " + widgetId);
        }
    };

    return {
        setup: setup
    };
}());
;
/*globals $:false, document:false, wng:true, Spinner:false */

var wng = wng || {};

wng.animations = (function (undefined) {

    "use strict";

    var
      completeInlineLoadingTimeoutHandle,
      $recentlyHiddenButtonArrow,
      completeWhitewashLoadingTimeoutHandle,
      whitewashSpinner,
      whitewashCssClass = 'loading-overlay',
      whitewashSpinnerCssClass = 'loading-spinner',
      inlineSpinnerCssClass = 'inline-spinner',
      inlineSpinnerWrapperCssClass = 'inline-spinner-wrapper',
      inlineSpinner,
      loadingIndicatorMaxDurationInSeconds = 30,
      htmlSelectorHookForAppendingWhitewashLoadingDivs = 'body',
      callerInlineLoadingOriginalHtmlDataKey = 'original-html-content',
      callerInlineLoadingDataAttribute = 'data-inline-loading-indication',
      inlineLoadingAttributeSelectorForIcon = 'data-button-arrow',

    showInlineLoadingIndicator = function ($caller, displayWithinButton, replacementHtmlContent) {
        var
          $inlineSpinnerWrapper;

        var inlineSpinnerOpts = {
            lines: 17, // The number of lines to draw
            length: 0, // The length of each line
            width: 2, // The line thickness
            radius: 10, // The radius of the inner circle
            corners: 1, // Corner roundness (0..1)
            rotate: 0, // The rotation offset
            direction: 1, // 1: clockwise, -1: counterclockwise
            color: '#000', // #rgb or #rrggbb or array of colors
            speed: 1.2, // Rounds per second
            trail: 64, // Afterglow percentage
            shadow: false, // Whether to render a shadow
            hwaccel: false, // Whether to use hardware acceleration
            className: inlineSpinnerCssClass, // The CSS class to assign to the inline spinner
            zIndex: 2e9, // The z-index (defaults to 2000000000)
            bottom: '10%', // Top position relative to parent
            left: '90%' // Left position relative to parent
        };

        if (inlineSpinner) {
            inlineSpinner.spin();
        }
        else {
            inlineSpinner = new Spinner(inlineSpinnerOpts).spin();
        }

        $inlineSpinnerWrapper = $("<div />")
          .addClass(inlineSpinnerWrapperCssClass)
          .append(inlineSpinner.el);

        if ($("." + inlineSpinnerWrapperCssClass).length < 1) {
            $caller.after($inlineSpinnerWrapper);
            if (replacementHtmlContent) {
                $caller.attr(callerInlineLoadingDataAttribute, '');
                $caller.data(callerInlineLoadingOriginalHtmlDataKey, $caller.html());
                $caller.html(replacementHtmlContent);
            }

            if (displayWithinButton) {
                $recentlyHiddenButtonArrow = $caller.closest('div').find('[' + inlineLoadingAttributeSelectorForIcon + ']');
                if ($recentlyHiddenButtonArrow.length > 0) {
                    $recentlyHiddenButtonArrow.css('visibility', 'hidden');
                }
            }
        }

        completeInlineLoadingTimeoutHandle = setTimeout(removeInlineLoadingIndicator,
          loadingIndicatorMaxDurationInSeconds * 1000);
    },

    removeInlineLoadingIndicator = function () {
        if (inlineSpinner) {
            inlineSpinner.stop();
        }

        $("." + inlineSpinnerWrapperCssClass).remove();

        $("[" + callerInlineLoadingDataAttribute + "]").each(function () {
            var
              $inlineLoadingCaller = $(this),
              originalHtml = $inlineLoadingCaller.data(callerInlineLoadingOriginalHtmlDataKey);
            $inlineLoadingCaller.html(originalHtml);
        });

        if ($recentlyHiddenButtonArrow && $recentlyHiddenButtonArrow.length > 0) {
            $recentlyHiddenButtonArrow.css('visibility', 'visible');
            $recentlyHiddenButtonArrow = null;
        }

        clearTimeout(completeInlineLoadingTimeoutHandle);
    },

    showWhitewashLoadingIndicator = function () {
        var
          $loadingWhiteWash,
          $htmlHook;

        var whitewashSpinnerOpts = {
            lines: 17, // The number of lines to draw
            length: 0, // The length of each line
            width: 5, // The line thickness
            radius: 25, // The radius of the inner circle
            corners: 1, // Corner roundness (0..1)
            rotate: 0, // The rotation offset
            direction: 1, // 1: clockwise, -1: counterclockwise
            color: '#000', // #rgb or #rrggbb or array of colors
            speed: 1.2, // Rounds per second
            trail: 64, // Afterglow percentage
            shadow: false, // Whether to render a shadow
            hwaccel: false, // Whether to use hardware acceleration
            className: whitewashSpinnerCssClass, // The CSS class to assign to the spinner
            zIndex: 2e9, // The z-index (defaults to 2000000000)
            top: '50%', // Top position relative to parent
            left: '50%' // Left position relative to parent
        };

        if (whitewashSpinner) {
            whitewashSpinner.spin();
        }
        else {
            whitewashSpinner = new Spinner(whitewashSpinnerOpts).spin();
        }

        $loadingWhiteWash = $("<div />")
          .addClass(whitewashCssClass)
          .append(whitewashSpinner.el);

        $htmlHook = $(htmlSelectorHookForAppendingWhitewashLoadingDivs);
        $htmlHook.append($loadingWhiteWash);

        completeWhitewashLoadingTimeoutHandle = setTimeout(removeWhitewashLoadingIndicator,
          loadingIndicatorMaxDurationInSeconds * 1000);
    },

    removeWhitewashLoadingIndicator = function () {
        var
          $content = $(htmlSelectorHookForAppendingWhitewashLoadingDivs);

        if (whitewashSpinner) {
            whitewashSpinner.stop();
        }

        $("." + whitewashCssClass, $content).remove();

        clearTimeout(completeWhitewashLoadingTimeoutHandle);
    },

    initInlineHints = function (shouldHideAfterTimeout) {
        $(".content").on("mouseover", "[data-hint-target]", function () {
            var
              $hoverTarget = $(this),
              $hintContentForTarget = $hoverTarget.closest("[data-hint-container]").find("[data-hint-content]").first();

            if (!$hintContentForTarget.data("hint-shown")) {
                $hintContentForTarget.data("hint-shown", true);
                $hintContentForTarget.show();

                if (shouldHideAfterTimeout) {
                    setTimeout(function () {
                        $hintContentForTarget.data("hint-shown", false);
                        $hintContentForTarget.fadeOut();
                    }, 10000);
                }
            }
        });
    };

    return {
        showInlineLoadingIndicator: showInlineLoadingIndicator,
        removeInlineLoadingIndicator: removeInlineLoadingIndicator,
        showWhitewashLoadingIndicator: showWhitewashLoadingIndicator,
        removeWhitewashLoadingIndicator: removeWhitewashLoadingIndicator,
        initInlineHints: initInlineHints
    };
}());
;

/*
  Payform Javascript Library

  URL: https://github.com/jondavidjohn/payform
  Author: Jonathan D. Johnson <me@jondavidjohn.com>
  License: MIT
  Version: 1.4.0
 */

(function() {
  var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };

  (function(name, definition) {
    if (typeof module !== "undefined" && module !== null) {
      return module.exports = definition();
    } else if (typeof define === 'function' && typeof define.amd === 'object') {
      return define(name, definition);
    } else {
      return this[name] = definition();
    }
  })('payform', function() {
    var _eventNormalize, _getCaretPos, _off, _on, attachEvents, cardFromNumber, cardFromType, defaultFormat, eventList, formatBackCardNumber, formatBackExpiry, formatCardExpiry, formatCardNumber, formatForwardExpiry, formatForwardSlashAndSpace, getDirectionality, hasTextSelected, keyCodes, luhnCheck, payform, reFormatCVC, reFormatCardNumber, reFormatExpiry, replaceFullWidthChars, restrictCVC, restrictCardNumber, restrictExpiry, restrictNumeric;
    _getCaretPos = function(ele) {
      var r, rc, re;
      if (ele.selectionStart != null) {
        return ele.selectionStart;
      } else if (document.selection != null) {
        ele.focus();
        r = document.selection.createRange();
        re = ele.createTextRange();
        rc = re.duplicate();
        re.moveToBookmark(r.getBookmark());
        rc.setEndPoint('EndToStart', re);
        return rc.text.length;
      }
    };
    _eventNormalize = function(listener) {
      return function(e) {
        var newEvt;
        if (e == null) {
          e = window.event;
        }
        if (e.inputType === 'insertCompositionText' && !e.isComposing) {
          return;
        }
        newEvt = {
          target: e.target || e.srcElement,
          which: e.which || e.keyCode,
          type: e.type,
          metaKey: e.metaKey,
          ctrlKey: e.ctrlKey,
          preventDefault: function() {
            if (e.preventDefault) {
              e.preventDefault();
            } else {
              e.returnValue = false;
            }
          }
        };
        return listener(newEvt);
      };
    };
    _on = function(ele, event, listener) {
      if (ele.addEventListener != null) {
        return ele.addEventListener(event, listener, false);
      } else {
        return ele.attachEvent("on" + event, listener);
      }
    };
    _off = function(ele, event, listener) {
      if (ele.removeEventListener != null) {
        return ele.removeEventListener(event, listener, false);
      } else {
        return ele.detachEvent("on" + event, listener);
      }
    };
    payform = {};
    keyCodes = {
      UNKNOWN: 0,
      BACKSPACE: 8,
      PAGE_UP: 33,
      ARROW_LEFT: 37,
      ARROW_RIGHT: 39
    };
    defaultFormat = /(\d{1,4})/g;
    payform.cards = [
      {
        type: 'elo',
        pattern: /^(4011(78|79)|43(1274|8935)|45(1416|7393|763(1|2))|50(4175|6699|67[0-7][0-9]|9000)|627780|63(6297|6368)|650(03([^4])|04([0-9])|05(0|1)|4(0[5-9]|3[0-9]|8[5-9]|9[0-9])|5([0-2][0-9]|3[0-8])|9([2-6][0-9]|7[0-8])|541|700|720|901)|651652|655000|655021)/,
        format: defaultFormat,
        length: [16],
        cvcLength: [3],
        luhn: true
      }, {
        type: 'visaelectron',
        pattern: /^4(026|17500|405|508|844|91[37])/,
        format: defaultFormat,
        length: [16],
        cvcLength: [3],
        luhn: true
      }, {
        type: 'maestro',
        pattern: /^(5018|5020|5038|6304|6390[0-9]{2}|67[0-9]{4})/,
        format: defaultFormat,
        length: [12, 13, 14, 15, 16, 17, 18, 19],
        cvcLength: [3],
        luhn: true
      }, {
        type: 'forbrugsforeningen',
        pattern: /^600/,
        format: defaultFormat,
        length: [16],
        cvcLength: [3],
        luhn: true
      }, {
        type: 'dankort',
        pattern: /^5019/,
        format: defaultFormat,
        length: [16],
        cvcLength: [3],
        luhn: true
      }, {
        type: 'visa',
        pattern: /^4/,
        format: defaultFormat,
        length: [13, 16, 19],
        cvcLength: [3],
        luhn: true
      }, {
        type: 'mastercard',
        pattern: /^(5[1-5][0-9]{4}|677189)|^(222[1-9]|2[3-6]\d{2}|27[0-1]\d|2720)([0-9]{2})/,
        format: defaultFormat,
        length: [16],
        cvcLength: [3],
        luhn: true
      }, {
        type: 'amex',
        pattern: /^3[47]/,
        format: /(\d{1,4})(\d{1,6})?(\d{1,5})?/,
        length: [15],
        cvcLength: [4],
        luhn: true
      }, {
        type: 'hipercard',
        pattern: /^(384100|384140|384160|606282|637095|637568|60(?!11))/,
        format: defaultFormat,
        length: [14, 15, 16, 17, 18, 19],
        cvcLength: [3],
        luhn: true
      }, {
        type: 'dinersclub',
        pattern: /^(36|38|30[0-5])/,
        format: /(\d{1,4})(\d{1,6})?(\d{1,4})?/,
        length: [14],
        cvcLength: [3],
        luhn: true
      }, {
        type: 'discover',
        pattern: /^(6011|65|64[4-9]|622)/,
        format: defaultFormat,
        length: [16],
        cvcLength: [3],
        luhn: true
      }, {
        type: 'unionpay',
        pattern: /^62/,
        format: defaultFormat,
        length: [16, 17, 18, 19],
        cvcLength: [3],
        luhn: false
      }, {
        type: 'jcb',
        pattern: /^35/,
        format: defaultFormat,
        length: [16, 17, 18, 19],
        cvcLength: [3],
        luhn: true
      }, {
        type: 'laser',
        pattern: /^(6706|6771|6709)/,
        format: defaultFormat,
        length: [16, 17, 18, 19],
        cvcLength: [3],
        luhn: true
      }
    ];
    cardFromNumber = function(num) {
      var card, i, len, ref;
      num = (num + '').replace(/\D/g, '');
      ref = payform.cards;
      for (i = 0, len = ref.length; i < len; i++) {
        card = ref[i];
        if (card.pattern.test(num)) {
          return card;
        }
      }
    };
    cardFromType = function(type) {
      var card, i, len, ref;
      ref = payform.cards;
      for (i = 0, len = ref.length; i < len; i++) {
        card = ref[i];
        if (card.type === type) {
          return card;
        }
      }
    };
    getDirectionality = function(target) {
      var style;
      style = getComputedStyle(target);
      return style && style['direction'] || document.dir;
    };
    luhnCheck = function(num) {
      var digit, digits, i, len, odd, sum;
      odd = true;
      sum = 0;
      digits = (num + '').split('').reverse();
      for (i = 0, len = digits.length; i < len; i++) {
        digit = digits[i];
        digit = parseInt(digit, 10);
        if ((odd = !odd)) {
          digit *= 2;
        }
        if (digit > 9) {
          digit -= 9;
        }
        sum += digit;
      }
      return sum % 10 === 0;
    };
    hasTextSelected = function(target) {
      var ref;
      if ((typeof document !== "undefined" && document !== null ? (ref = document.selection) != null ? ref.createRange : void 0 : void 0) != null) {
        if (document.selection.createRange().text) {
          return true;
        }
      }
      return (target.selectionStart != null) && target.selectionStart !== target.selectionEnd;
    };
    replaceFullWidthChars = function(str) {
      var char, chars, fullWidth, halfWidth, i, idx, len, value;
      if (str == null) {
        str = '';
      }
      fullWidth = '\uff10\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19';
      halfWidth = '0123456789';
      value = '';
      chars = str.split('');
      for (i = 0, len = chars.length; i < len; i++) {
        char = chars[i];
        idx = fullWidth.indexOf(char);
        if (idx > -1) {
          char = halfWidth[idx];
        }
        value += char;
      }
      return value;
    };
    reFormatCardNumber = function(e) {
      var cursor;
      cursor = _getCaretPos(e.target);
      if (e.target.value === "") {
        return;
      }
      if (getDirectionality(e.target) === 'ltr') {
        cursor = _getCaretPos(e.target);
      }
      e.target.value = payform.formatCardNumber(e.target.value);
      if (getDirectionality(e.target) === 'ltr' && cursor !== e.target.selectionStart) {
        cursor = _getCaretPos(e.target);
      }
      if (getDirectionality(e.target) === 'rtl' && e.target.value.indexOf('‎\u200e') === -1) {
        e.target.value = '‎\u200e'.concat(e.target.value);
      }
      cursor = _getCaretPos(e.target);
      if ((cursor != null) && cursor !== 0 && e.type !== 'change') {
        return e.target.setSelectionRange(cursor, cursor);
      }
    };
    formatCardNumber = function(e) {
      var card, cursor, digit, length, re, upperLength, value;
      digit = String.fromCharCode(e.which);
      if (!/^\d+$/.test(digit)) {
        return;
      }
      value = e.target.value;
      card = cardFromNumber(value + digit);
      length = (value.replace(/\D/g, '') + digit).length;
      upperLength = 16;
      if (card) {
        upperLength = card.length[card.length.length - 1];
      }
      if (length >= upperLength) {
        return;
      }
      cursor = _getCaretPos(e.target);
      if (cursor && cursor !== value.length) {
        return;
      }
      if (card && card.type === 'amex') {
        re = /^(\d{4}|\d{4}\s\d{6})$/;
      } else {
        re = /(?:^|\s)(\d{4})$/;
      }
      if (re.test(value)) {
        e.preventDefault();
        return setTimeout(function() {
          return e.target.value = value + " " + digit;
        });
      } else if (re.test(value + digit)) {
        e.preventDefault();
        return setTimeout(function() {
          return e.target.value = (value + digit) + " ";
        });
      }
    };
    formatBackCardNumber = function(e) {
      var cursor, value;
      value = e.target.value;
      if (e.which !== keyCodes.BACKSPACE) {
        return;
      }
      cursor = _getCaretPos(e.target);
      if (cursor && cursor !== value.length) {
        return;
      }
      if ((e.target.selectionEnd - e.target.selectionStart) > 1) {
        return;
      }
      if (/\d\s$/.test(value)) {
        e.preventDefault();
        return setTimeout(function() {
          return e.target.value = value.replace(/\d\s$/, '');
        });
      } else if (/\s\d?$/.test(value)) {
        e.preventDefault();
        return setTimeout(function() {
          return e.target.value = value.replace(/\d$/, '');
        });
      }
    };
    reFormatExpiry = function(e) {
      var cursor;
      if (e.target.value === "") {
        return;
      }
      e.target.value = payform.formatCardExpiry(e.target.value);
      if (getDirectionality(e.target) === 'rtl' && e.target.value.indexOf('‎\u200e') === -1) {
        e.target.value = '‎\u200e'.concat(e.target.value);
      }
      cursor = _getCaretPos(e.target);
      if ((cursor != null) && e.type !== 'change') {
        return e.target.setSelectionRange(cursor, cursor);
      }
    };
    formatCardExpiry = function(e) {
      var digit, val;
      digit = String.fromCharCode(e.which);
      if (!/^\d+$/.test(digit)) {
        return;
      }
      val = e.target.value + digit;
      if (/^\d$/.test(val) && (val !== '0' && val !== '1')) {
        e.preventDefault();
        return setTimeout(function() {
          return e.target.value = "0" + val + " / ";
        });
      } else if (/^\d\d$/.test(val)) {
        e.preventDefault();
        return setTimeout(function() {
          return e.target.value = val + " / ";
        });
      }
    };
    formatForwardExpiry = function(e) {
      var digit, val;
      digit = String.fromCharCode(e.which);
      if (!/^\d+$/.test(digit)) {
        return;
      }
      val = e.target.value;
      if (/^\d\d$/.test(val)) {
        return e.target.value = val + " / ";
      }
    };
    formatForwardSlashAndSpace = function(e) {
      var val, which;
      which = String.fromCharCode(e.which);
      if (!(which === '/' || which === ' ')) {
        return;
      }
      val = e.target.value;
      if (/^\d$/.test(val) && val !== '0') {
        return e.target.value = "0" + val + " / ";
      }
    };
    formatBackExpiry = function(e) {
      var cursor, value;
      value = e.target.value;
      if (e.which !== keyCodes.BACKSPACE) {
        return;
      }
      cursor = _getCaretPos(e.target);
      if (cursor && cursor !== value.length) {
        return;
      }
      if (/\d\s\/\s$/.test(value)) {
        e.preventDefault();
        return setTimeout(function() {
          return e.target.value = value.replace(/\d\s\/\s$/, '');
        });
      }
    };
    reFormatCVC = function(e) {
      var cursor;
      if (e.target.value === "") {
        return;
      }
      cursor = _getCaretPos(e.target);
      e.target.value = replaceFullWidthChars(e.target.value).replace(/\D/g, '').slice(0, 4);
      if ((cursor != null) && e.type !== 'change') {
        return e.target.setSelectionRange(cursor, cursor);
      }
    };
    restrictNumeric = function(e) {
      var input;
      if (e.metaKey || e.ctrlKey) {
        return;
      }
      if ([keyCodes.UNKNOWN, keyCodes.ARROW_LEFT, keyCodes.ARROW_RIGHT].indexOf(e.which) > -1) {
        return;
      }
      if (e.which < keyCodes.PAGE_UP) {
        return;
      }
      input = String.fromCharCode(e.which);
      if (!/^\d+$/.test(input)) {
        return e.preventDefault();
      }
    };
    restrictCardNumber = function(e) {
      var card, digit, maxLength, value;
      digit = String.fromCharCode(e.which);
      if (!/^\d+$/.test(digit)) {
        return;
      }
      if (hasTextSelected(e.target)) {
        return;
      }
      value = (e.target.value + digit).replace(/\D/g, '');
      card = cardFromNumber(value);
      maxLength = card ? card.length[card.length.length - 1] : 16;
      if (value.length > maxLength) {
        return e.preventDefault();
      }
    };
    restrictExpiry = function(e) {
      var digit, value;
      digit = String.fromCharCode(e.which);
      if (!/^\d+$/.test(digit)) {
        return;
      }
      if (hasTextSelected(e.target)) {
        return;
      }
      value = e.target.value + digit;
      value = value.replace(/\D/g, '');
      if (value.length > 6) {
        return e.preventDefault();
      }
    };
    restrictCVC = function(e) {
      var digit, val;
      digit = String.fromCharCode(e.which);
      if (!/^\d+$/.test(digit)) {
        return;
      }
      if (hasTextSelected(e.target)) {
        return;
      }
      val = e.target.value + digit;
      if (val.length > 4) {
        return e.preventDefault();
      }
    };
    eventList = {
      cvcInput: [
        {
          eventName: 'keypress',
          eventHandler: _eventNormalize(restrictNumeric)
        }, {
          eventName: 'keypress',
          eventHandler: _eventNormalize(restrictCVC)
        }, {
          eventName: 'paste',
          eventHandler: _eventNormalize(reFormatCVC)
        }, {
          eventName: 'change',
          eventHandler: _eventNormalize(reFormatCVC)
        }, {
          eventName: 'input',
          eventHandler: _eventNormalize(reFormatCVC)
        }
      ],
      expiryInput: [
        {
          eventName: 'keypress',
          eventHandler: _eventNormalize(restrictNumeric)
        }, {
          eventName: 'keypress',
          eventHandler: _eventNormalize(restrictExpiry)
        }, {
          eventName: 'keypress',
          eventHandler: _eventNormalize(formatCardExpiry)
        }, {
          eventName: 'keypress',
          eventHandler: _eventNormalize(formatForwardSlashAndSpace)
        }, {
          eventName: 'keypress',
          eventHandler: _eventNormalize(formatForwardExpiry)
        }, {
          eventName: 'keydown',
          eventHandler: _eventNormalize(formatBackExpiry)
        }, {
          eventName: 'change',
          eventHandler: _eventNormalize(reFormatExpiry)
        }, {
          eventName: 'input',
          eventHandler: _eventNormalize(reFormatExpiry)
        }
      ],
      cardNumberInput: [
        {
          eventName: 'keypress',
          eventHandler: _eventNormalize(restrictNumeric)
        }, {
          eventName: 'keypress',
          eventHandler: _eventNormalize(restrictCardNumber)
        }, {
          eventName: 'keypress',
          eventHandler: _eventNormalize(formatCardNumber)
        }, {
          eventName: 'keydown',
          eventHandler: _eventNormalize(formatBackCardNumber)
        }, {
          eventName: 'paste',
          eventHandler: _eventNormalize(reFormatCardNumber)
        }, {
          eventName: 'change',
          eventHandler: _eventNormalize(reFormatCardNumber)
        }, {
          eventName: 'input',
          eventHandler: _eventNormalize(reFormatCardNumber)
        }
      ],
      numericInput: [
        {
          eventName: 'keypress',
          eventHandler: _eventNormalize(restrictNumeric)
        }, {
          eventName: 'paste',
          eventHandler: _eventNormalize(restrictNumeric)
        }, {
          eventName: 'change',
          eventHandler: _eventNormalize(restrictNumeric)
        }, {
          eventName: 'input',
          eventHandler: _eventNormalize(restrictNumeric)
        }
      ]
    };
    attachEvents = function(input, events, detach) {
      var evt, i, len;
      for (i = 0, len = events.length; i < len; i++) {
        evt = events[i];
        if (detach) {
          _off(input, evt.eventName, evt.eventHandler);
        } else {
          _on(input, evt.eventName, evt.eventHandler);
        }
      }
    };
    payform.cvcInput = function(input) {
      return attachEvents(input, eventList.cvcInput);
    };
    payform.expiryInput = function(input) {
      return attachEvents(input, eventList.expiryInput);
    };
    payform.cardNumberInput = function(input) {
      return attachEvents(input, eventList.cardNumberInput);
    };
    payform.numericInput = function(input) {
      return attachEvents(input, eventList.numericInput);
    };
    payform.detachCvcInput = function(input) {
      return attachEvents(input, eventList.cvcInput, true);
    };
    payform.detachExpiryInput = function(input) {
      return attachEvents(input, eventList.expiryInput, true);
    };
    payform.detachCardNumberInput = function(input) {
      return attachEvents(input, eventList.cardNumberInput, true);
    };
    payform.detachNumericInput = function(input) {
      return attachEvents(input, eventList.numericInput, true);
    };
    payform.parseCardExpiry = function(value) {
      var month, prefix, ref, year;
      value = value.replace(/\s/g, '');
      ref = value.split('/', 2), month = ref[0], year = ref[1];
      if ((year != null ? year.length : void 0) === 2 && /^\d+$/.test(year)) {
        prefix = (new Date).getFullYear();
        prefix = prefix.toString().slice(0, 2);
        year = prefix + year;
      }
      month = parseInt(month.replace(/[\u200e]/g, ""), 10);
      year = parseInt(year, 10);
      return {
        month: month,
        year: year
      };
    };
    payform.validateCardNumber = function(num) {
      var card, ref;
      num = (num + '').replace(/\s+|-/g, '');
      if (!/^\d+$/.test(num)) {
        return false;
      }
      card = cardFromNumber(num);
      if (!card) {
        return false;
      }
      return (ref = num.length, indexOf.call(card.length, ref) >= 0) && (card.luhn === false || luhnCheck(num));
    };
    payform.validateCardExpiry = function(month, year) {
      var currentTime, expiry, ref;
      if (typeof month === 'object' && 'month' in month) {
        ref = month, month = ref.month, year = ref.year;
      }
      if (!(month && year)) {
        return false;
      }
      month = String(month).trim();
      year = String(year).trim();
      if (!/^\d+$/.test(month)) {
        return false;
      }
      if (!/^\d+$/.test(year)) {
        return false;
      }
      if (!((1 <= month && month <= 12))) {
        return false;
      }
      if (year.length === 2) {
        if (year < 70) {
          year = "20" + year;
        } else {
          year = "19" + year;
        }
      }
      if (year.length !== 4) {
        return false;
      }
      expiry = new Date(year, month);
      currentTime = new Date;
      expiry.setMonth(expiry.getMonth() - 1);
      expiry.setMonth(expiry.getMonth() + 1, 1);
      return expiry > currentTime;
    };
    payform.validateCardCVC = function(cvc, type) {
      var card, ref;
      cvc = String(cvc).trim();
      if (!/^\d+$/.test(cvc)) {
        return false;
      }
      card = cardFromType(type);
      if (card != null) {
        return ref = cvc.length, indexOf.call(card.cvcLength, ref) >= 0;
      } else {
        return cvc.length >= 3 && cvc.length <= 4;
      }
    };
    payform.parseCardType = function(num) {
      var ref;
      if (!num) {
        return null;
      }
      return ((ref = cardFromNumber(num)) != null ? ref.type : void 0) || null;
    };
    payform.formatCardNumber = function(num) {
      var card, groups, ref, upperLength;
      num = replaceFullWidthChars(num);
      num = num.replace(/\D/g, '');
      card = cardFromNumber(num);
      if (!card) {
        return num;
      }
      upperLength = card.length[card.length.length - 1];
      num = num.slice(0, upperLength);
      if (card.format.global) {
        return (ref = num.match(card.format)) != null ? ref.join(' ') : void 0;
      } else {
        groups = card.format.exec(num);
        if (groups == null) {
          return;
        }
        groups.shift();
        groups = groups.filter(Boolean);
        return groups.join(' ');
      }
    };
    payform.formatCardExpiry = function(expiry) {
      var mon, parts, sep, year;
      expiry = replaceFullWidthChars(expiry);
      parts = expiry.match(/^\D*(\d{1,2})(\D+)?(\d{1,4})?/);
      if (!parts) {
        return '';
      }
      mon = parts[1] || '';
      sep = parts[2] || '';
      year = parts[3] || '';
      if (year.length > 0) {
        sep = ' / ';
      } else if (sep === ' /') {
        mon = mon.substring(0, 1);
        sep = '';
      } else if (mon.length === 2 || sep.length > 0) {
        sep = ' / ';
      } else if (mon.length === 1 && (mon !== '0' && mon !== '1')) {
        mon = "0" + mon;
        sep = ' / ';
      }
      return mon + sep + year;
    };
    return payform;
  });

}).call(this);
;
// Anonymouse function to set injectHtml function. All other methods are private and not accessable outside of the function
(function() {

	window.cardTokenPayment = {};

	// Add styles
    window.cardTokenPayment.InjectLibrary = function (targetElementId, customOptions) {

		if (!customOptions) throw "options is required.";
        if (!targetElementId) throw "targetElementId is required.";

        // Inject html into target html
        var targetElement = $('#' + targetElementId);
		if (!targetElement) throw "targetElement not found";

		var defaultOptions = getDefaultOptions();
		var options = $.extend({}, defaultOptions, customOptions);
		options.localization = $.extend({}, defaultOptions.localization, customOptions.localization);
		options.fileRefs = $.extend({}, defaultOptions.fileRefs, customOptions.fileRefs);

		// Add styles

		addStyleString(cardDetailsInternalCss, options.fileRefs);
		addStyleString(cardDetailsSpinnerCss, options.fileRefs);
		if (!options.skipDefaultCss) addStyleString(cardDetailsExternalCss, options.fileRefs);
		if (options.customCss) addStyleString(options.customCss, options.fileRefs);

		// Add html
		var htmlToApply = options.customHtml ? options.customHtml : cardDetailsHtml;
    // merge fileRefs and localization into one dictionary for replacement
		var htmlReplacementDict = $.extend({}, options.fileRefs, options.localization);
		addHtmlString(targetElement, htmlToApply, htmlReplacementDict);

		var cardOwnerEl = $('#cardtoken_NameOnCreditCard');
		var cardNumberEl = $('#cardtoken_CreditCardNumber');
		var cvvEl = $("#cardtoken_VerificationNumber");
		var mastercardEl = $("#cardtoken_ImgMasterCardType");
		var visaEl = $("#cardtoken_ImgVisaType");
		var amexEl = $("#cardtoken_ImgAmexType");
		var doPaymentEl = $('#cardtoken_DoPayment');
		var spinnerEl = $('#cardtoken_SpinnerContainer');

		if (!options.showBuyButton) {
			doPaymentEl.css({display: "none"});
		}

		// Populate tender types
		$.each(options.tenderTypes, function (idx, item) {
			if (item.Code === "visa") visaEl.show();
			else if (item.Code === "mc") mastercardEl.show();
			else if (item.Code === "amex") amexEl.show();
		});

		// Populate years dynamically + 20 from now
		var currentYear = (new Date()).getFullYear();
		var expMonthEl = $('#cardtoken_CreditCardExpiryDateMonthId');
		var expYearEl = $('#cardtoken_CreditCardExpiryDateYearId');
		expYearEl.empty();
		expYearEl.append("<option selected='selected'></option>");
		for (var i = 0; i < 20; i++) {
			var optionYear = currentYear + i;
			expYearEl.append($('<option>', {value: optionYear, text: optionYear}));
		}

		// Populate months
		expMonthEl.empty();
		expMonthEl.append("<option selected='selected'></option>");
		$.each(options.months, function (idx, item) {
			expMonthEl.append($('<option>', {value: item.Id, text: item.ShortDescription}));
		});

		$(".button-tertiary.close").click(function () {
			$(".modal-background").css({display: "none"});
		});
		$("#cardtoken_btnEnlargeCardCvv").click(function () {
			$(".modal-background").css({display: "block"});
		});

		if (!options.prefillFullName) $("#cardtoken_btnSetCardholderName").hide();

		$("#cardtoken_btnSetCardholderName").click(function () {
			prefillFullName(options);
		});

		doPaymentEl.click(function (e) {
			window.cardTokenPayment.DoTokenization();
			e.preventDefault();
		});

		var tokenizationInProgress = false;

		window.cardTokenPayment.DoTokenization = function()
		{
			var errorsList = [];

			var isCardNumberValid = payform.validateCardNumber(cardNumberEl.val());
			var isCvvValid = payform.validateCardCVC(cvvEl.val());
			var isNameValid = cardOwnerEl.val().length >= 5;

			//***************************************************
			// Check credit card number
			var ccNumberLabelEl = $(".cc-number");
			if (!isCardNumberValid) {
				errorsList.push("Incorrect card number");
			}
			setElementState(ccNumberLabelEl, isCardNumberValid);

			var ccNameLabelEl = $(".cc-name");
			if (!isNameValid) {
				errorsList.push("Name on card is required");
			}
			setElementState(ccNameLabelEl, isNameValid);

			var ccCvvLabelEl = $(".cc-verification");
			if (!isCvvValid) {
				errorsList.push("Incorrect card Security Code (CVC)");
			}
			setElementState(ccCvvLabelEl, isCvvValid);

			var expMonth = parseInt(expMonthEl.val());
			var expYear = parseInt(expYearEl.val());

			var ccExpDateLabelEl = $(".cc-expiry");
			var isExpDateValid = expMonth && expYear;
			if (isExpDateValid) {
				var cardDate = new Date();
				isExpDateValid = (expYear > cardDate.getFullYear() || (expYear == cardDate.getFullYear() && expMonth >= cardDate.getMonth()));
			}
			if (!isExpDateValid) {
				errorsList.push("Incorrect expiration date");
			}
			setElementState(ccExpDateLabelEl, isExpDateValid);

			var valErrorEl = $(".input-validation-errors");
			valErrorEl.empty();
            valErrorEl.hide();
			var isValid = errorsList.length == 0;
			if (isValid) {
				var cardDetails = {
					Source: options.source,
					TransactionId: options.transactionId,
					CardHolderName: $.trim(cardOwnerEl.val()),
					Pan: $.trim(cardNumberEl.val().replace(/ /g, "")),
					ExpiryMonth: parseInt(expMonthEl.val()),
					ExpiryYear: parseInt(expYearEl.val()),
					Cvv: $.trim(cvvEl.val())
				};

				// Perform tokenization service call
				processPayment(doPaymentEl, options, cardDetails);
			} else {
				displayErrors(errorsList);
			}
			return isValid;
		};

	    function displayError(errorMsg) {
			if (!errorMsg) errorMsg = 'Unknown error. Please check if internet is connected.'
		    var valErrorEl = $(".input-validation-errors");
			valErrorEl.append("<li><label>" + errorMsg + "</label></li>");
            valErrorEl.show();
	    }

		function displayErrors(errorsList) {
			var valErrorEl = $(".input-validation-errors");
			errorsList.forEach(function (errMsg) {
				valErrorEl.append("<li><label>" + errMsg + "</label></li>");
			});
            valErrorEl.show();
		}

		cardNumberEl.keyup(function () {
			setCardTransparent(mastercardEl, true);
			setCardTransparent(amexEl, true);
			setCardTransparent(visaEl, true);

			if (payform.parseCardType(cardNumberEl.val()) == 'visa') {
				setCardTransparent(visaEl, false);
			} else if (payform.parseCardType(cardNumberEl.val()) == 'amex') {
				setCardTransparent(amexEl, false);
			} else if (payform.parseCardType(cardNumberEl.val()) == 'mastercard') {
				setCardTransparent(mastercardEl, false);
			}
		});

		function setCardTransparent(el, flag) {
			if (!el) return;
			if (flag) {
				el.addClass('transparentCard');
			} else {
				el.removeClass('transparentCard');
			}
		}

		function setElementState(el, isSuccess) {
			if (!el) return;
			if (isSuccess) {
				el.removeClass('error');
			} else {
				el.addClass('error');
			}
		}

		// processPayment is a private method and is not available outside of the anonymous function
		function processPayment (confirmButton, options, data) {
		    if (tokenizationInProgress) return;
			$.support.cors = true;
		    tokenizationInProgress = true;
			spinnerEl.css({display: "block"});
			$.ajax({
				type: "post",
				dataType: "json",
				contentType: 'application/json',
				url: options.endPoint,
				data: JSON.stringify(data),
				success: function (data, text) {
					// if legit error, then trigger error handling logic
					if (data.errorMessage) {
						displayError(data.errorMessage);
						if (options.onError) options.onError(null, null, null, data);
						return;
					}
					if (options.onSuccess) options.onSuccess(data, text);
				},
				error: function (request, status, error) {
					displayError(data.errorMessage);
					if (options.onError) options.onError(request, status, error, null);
				},
				complete: function(response, result) {
					tokenizationInProgress = false;
					spinnerEl.css({display: "none"});
					if (options.onComplete) options.onComplete(response, result);
				}
			});
		}

		function addHtmlString(el, htmlToApply, fileRefs) {
			htmlToApply = stringInject(htmlToApply, fileRefs);
			el.html(htmlToApply);
		}

		function addStyleString(str, fileRefs) {
			var cssToApply = stringInject(str, fileRefs);
			var node = document.createElement('style');
			node.type = 'text/css';
			node.innerHTML = cssToApply;
			document.body.appendChild(node);
		}

		// injects properties into a string
		function stringInject(str, data) {
			if (typeof str === 'string' && (data instanceof Array)) {

				return str.replace(/({\d})/g, function(i) {
					return data[i.replace(/{/, '').replace(/}/, '')];
				});
			} else if (typeof str === 'string' && (data instanceof Object)) {

				if (Object.keys(data).length === 0) {
					return str;
				}

				for (let key in data) {
					if (!data.hasOwnProperty(key)) continue;
					var regExpStr = `{${key}}`;
					var regExp = new RegExp(regExpStr, 'g');

					// if field is presented
					if (data[key] != undefined)
						str = str.replace(regExp, data[key]);
				}
				return str;
			} else if (typeof str === 'string' && data instanceof Array === false || typeof str === 'string' && data instanceof Object === false) {

				return str;
			} else {

				return false;
			}
		}

	    //request full name
	    function prefillFullName(options) {
			$('#cardtoken_NameOnCreditCard').val(options.prefillFullName);
	    }

		//**********************************************
		// Default options methods
		//**********************************************
		function onSuccessDefault(responseObj, text) {
			console.log('onSuccess', responseObj.token, text);
		}

		function onErrorDefault(response, status, error, data) {
			console.log('onError', response, status, error, data);
		}

		function onCompleteDefault(response, result) {
			console.log('onComplete', response, result);
		}

		function getDefaultOptions() {
			var imgFolder = "/content/scripts/wng.cardToken.jsClient/images/";
			var fontFolder = "/content/scripts/wng.cardToken.jsClient/font/";
			var options = {
				endPoint: "https://cardtoken-api.wng-test.com/cardtoken/tokenise",
				onSuccess: onSuccessDefault,
				onError: onErrorDefault,
				onComplete: onCompleteDefault,
				source: "wng", // default is wng
				skipDefaultCss: false,
				customHtml: null,
				customCss: null,
				showCvcHelp: true,
				showBuyButton: true,
				prefillFullName: null,
				transactionId: new Date().getTime().toString(),
				fileRefs: {
					// images
					"img_tendertype_visa": imgFolder + "tendertype_visa.png",
					"img_tendertype_mc": imgFolder + "tendertype_mc.png",
					"img_tendertype_ame": imgFolder + "tendertype_amex.png",
					"img_cc_amex_large": imgFolder + "cc_amex_large.png",
					"img_cc_other_large": imgFolder + "cc_other_large.png",
					"img_cc_other_small": imgFolder + "cc_other_small.png",
					"img_cc_amex_small": imgFolder + "cc_amex_small.png",
					"img_enlarge": imgFolder + "enlarge.png",
					// fonts
					"font_flama_light_woff": fontFolder + "Flama-Light.woff",
					"font_flama_medium_woff": fontFolder + "Flama-Medium.woff",
					"font_wng_awesome": fontFolder + "wng-awesome",
					// placeholders
					"css_display_cvchint": "block"
				},
				localization: {
					// main payment form (ViewText)
					"PaymentHeaderText": "Secure Payment",
					"PaymentEncryptionText": "This is a 128-Bit SSL encrypted payment",
					"CreditCardAcceptText": "We Accept",
					"CreditCardNameLabel": "Name on card:",
					"CreditCardNameHelpText": "The name on the front of your card",
					"InsertFirstTravellerNameLinkText": "Click to insert name of first traveller",
					"CreditCardNumberLabel": "Credit Card Number:",
					"CreditCardNumberHelpText": "The digits on the front of your credit card",
					"CreditCardExpirationLabel": "Expiration date:",
					"CreditCardExpirationHelpText": "The date your credit card expires. Find this on the front of your credit card",
					"CreditCardSecurityCodeLabel": "Security Code: (CVC/CCV)",
					"CreditCardSecurityCodeHelpText": "Last 3 digits on the back of your Visa or Mastercard or 4 digits on the front of your AMEX card.",
					"CreditCardSecurityCodeHelpTextExcludingAmex": "Last 3 digits on the back of your Visa or Mastercard.",
					"EnlargeButtonText": "enlarge",
					// modal hint window (ModalText)
					"PaymentHintText": "Finding your 3 Digit Security Code",
					"PaymentHintSecurityCodeTypesText": '(or "CVC" or "CVV")',
					"CreditCardLabelForVisaMaster": "Visa or Mastercard",
					"CreditCardVerificationNumberLabel": "For your safety and security, we require that you enter your card's verification number",
					"CreditCardVerificationNumberTextForVisaMaster": "The verification number for visa and mastercard is a 3-digit number printed on the back of your card. It appears  after and to the right of your card number.",
					"CreditCardLabelForAmericanExpress": "American Express",
					"CreditCardVerificationNumberTextForAmericanExpress": "The American Express security code is a 4-digit number  printed on the front of your card. It appears after and to the right of your card number.",
					// buttons
					"BuyNowButtonText": "Buy Now"
				},
				months: [
					{ Id: 1, ShortDescription: "01 - Jan" },
					{ Id: 2, ShortDescription: "02 - Feb" },
					{ Id: 3, ShortDescription: "03 - Mar" },
					{ Id: 4, ShortDescription: "04 - Apr" },
					{ Id: 5, ShortDescription: "05 - May" },
					{ Id: 6, ShortDescription: "06 - Jun" },
					{ Id: 7, ShortDescription: "07 - Jul" },
					{ Id: 8, ShortDescription: "08 - Aug" },
					{ Id: 9, ShortDescription: "09 - Sep" },
					{ Id: 10, ShortDescription: "10 - Oct" },
					{ Id: 11, ShortDescription: "11 - Nov" },
					{ Id: 12, ShortDescription: "12 - Dec" }
				],
				tenderTypes: [
					{ Code: "visa", ShortDescription: "Visa" },
					{ Code: "mc", ShortDescription: "MasterCard" },
					{ Code: "amex", ShortDescription: "American Express" },
				]
			};
			return options;
		}
    };

	// language=CSS
	var cardDetailsInternalCss = `
/* The Modal (background) */
.modal-background {
	display: none; /* Hidden by default */
	position: fixed; /* Stay in place */
	z-index: 1; /* Sit on top */
	left: 0;
	top: 0;
	width: 100%; /* Full width */
	height: 100%; /* Full height */
	overflow: auto; /* Enable scroll if needed */
	background-color: rgb(0,0,0); /* Fallback color */
	background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}

.transparentCard {
	opacity: 0.2;
}

`;
	// language=CSS
    var cardDetailsSpinnerCss = `
	#cardtoken_SpinnerContainer{
		position: absolute;
		top:0px;
		left:0px;
		width: 100%;
		height: 100%;
		background: black;
		opacity: .5;
	}

	#cardtoken_Spinner {
		position: absolute;
		left: 50%;
		top: 50%;
		height:60px;
		width:60px;
		margin:0px auto;
		-webkit-animation: rotation .6s infinite linear;
		-moz-animation: rotation .6s infinite linear;
		-o-animation: rotation .6s infinite linear;
		animation: rotation .6s infinite linear;
		border-left:6px solid rgba(0,174,239,.15);
		border-right:6px solid rgba(0,174,239,.15);
		border-bottom:6px solid rgba(0,174,239,.15);
		border-top:6px solid rgba(0,174,239,.8);
		border-radius:100%;
	}

	@-webkit-keyframes rotation {
		from {-webkit-transform: rotate(0deg);}
		to {-webkit-transform: rotate(359deg);}
	}
	@-moz-keyframes rotation {
		from {-moz-transform: rotate(0deg);}
		to {-moz-transform: rotate(359deg);}
	}
	@-o-keyframes rotation {
		from {-o-transform: rotate(0deg);}
		to {-o-transform: rotate(359deg);}
	}
	@keyframes rotation {
		from {transform: rotate(0deg);}
		to {transform: rotate(359deg);}
}`;

	// language=CSS
	var cardDetailsExternalCss = `
/**************************************************************************************/
/* Common Content
/**************************************************************************************/

/*! CSS Used fontfaces */
@font-face {
	font-family: "Flama";
	font-style: normal;
	font-weight: 500;
	src: local("Flama Light"), local("Flama-Light"), url({font_flama_light_woff}) format("woff");
}

@font-face {
	font-family: "Flama";
	font-style: normal;
	font-weight: 600;
	src: local("Flama Medium"), local("Flama-Medium"), url({font_flama_medium_woff}) format("woff");
}

@font-face {
	font-family: "FontAwesome";
	src: url('{font_wng_awesome}.eot?1497571805');
	src: url('{font_wng_awesome}.eot?&1497571805#iefix') format('embedded-opentype'),
		 url('{font_wng_awesome}.woff?1497571805') format('woff'),
	     url('{font_wng_awesome}.ttf?1497571805') format('truetype'),
	     url('{font_wng_awesome}.svg?1497571805') format('svg');
}

.button-tertiary {
	-moz-border-radius: 4px;
	-webkit-border-radius: 4px;
	border-radius: 4px;
	font-size: 16px;
	background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2Y0ZjNmMyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2RjZDhkOCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
	background-size: 100%;
	background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #f4f3f3), color-stop(100%, #dcd8d8));
	background-image: -moz-linear-gradient(#f4f3f3, #dcd8d8);
	background-image: -webkit-linear-gradient(#f4f3f3, #dcd8d8);
	background-image: linear-gradient(#f4f3f3, #dcd8d8);
	color: #3a3a3a;
	border: 1px solid #e3e0e0;
	padding: 0px 10px;
}

.button-tertiary:hover {
	border: 1px solid #d2cece;
	background: #e3e0e0;
}

h4 {
	margin-right: 40px;
}

div, span, h3, img, fieldset, label {
	margin: 0;
	padding: 0;
	border: 0;
	font: inherit;
	font-size: 100%;
	vertical-align: baseline;
}

.error {
	font-weight: bold;
	color: #b14f64;
}

input, select {
	font-family: Flama, sans-serif;
	margin-left: 0px;
}

div, span, h2, h4, p {
	margin: 0;
	padding: 0;
	border: 0;
	font: inherit;
	font-size: 100%;
	vertical-align: baseline;
}

.link-like {
	background: none !important;
	border: none;
	padding: 0 !important;
	width: auto;
	font-family: Flama, sans-serif;
	font-size: 16px;
	text-transform: none !important;
	color: #009ed8 !important;
}

.link-like:hover {
	background: none;
	color: #009ed8 !important;
	text-decoration: underline;
	cursor: pointer;
}

.link-like:active {
	color: #00a6a1 !important;
}

button {
	-moz-border-radius: 2px;
	-webkit-border-radius: 2px;
	border-radius: 2px;
	border: none;
	outline: none;
	line-height: 24px;
	padding: 0px 8px;
	font-size: 16px;
	font-family: Flama, sans-serif;
	display: inline-block;
}

button span {
	font-weight: normal;
	font-family: FontAwesome;
	font-size: 13px;
	padding-left: 8px;
	display: inline-block;
}

button:hover {
	cursor: pointer;
}

.buy-button-primary {
	-moz-border-radius: 4px;
	-webkit-border-radius: 4px;
	border-radius: 4px;
	text-shadow: rgba(0, 0, 0, 0.1) 0px 1px 0;
	background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwYTZhMSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzAwNzM3MCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA==');
	background-size: 100%;
	background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #00a6a1), color-stop(100%, #007370));
	background-image: -moz-linear-gradient(#00a6a1, #007370);
	background-image: -webkit-linear-gradient(#00a6a1, #007370);
	background-image: linear-gradient(#00a6a1, #007370);
	color: #fff;
	border: 1px solid #007370;
	padding: 2px 10px;
	font-size: 18px;
	font-weight: normal;
}

.buy-button-primary:hover {
	background: #005f5c;
}

input[type="text"] {
	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
	-moz-box-shadow: rgba(153, 153, 153, 0.2) 0px 0px 5px;
	-webkit-box-shadow: rgba(153, 153, 153, 0.2) 0px 0px 5px;
	box-shadow: rgba(153, 153, 153, 0.2) 0px 0px 5px;
	-moz-box-shadow: rgba(153, 153, 153, 0.2) 1px 2px 8px inset;
	-webkit-box-shadow: rgba(153, 153, 153, 0.2) 1px 2px 8px inset;
	box-shadow: rgba(153, 153, 153, 0.2) 1px 2px 8px inset;
	-moz-border-radius: 3px;
	-webkit-border-radius: 3px;
	border-radius: 3px;
	float: left;
	clear: both;
	width: 100%;
	border: 1px solid #bcbcbc;
	outline: none;
	padding: 5px 8px;
	color: #3a3a3a;
	position: relative;
	font-size: 18px;
}

input[type="text"]:focus {
	border-color: #00a6a1;
	color: #3a3a3a;
}

::-webkit-input-placeholder {
	color: #ababab !important;
}

::-moz-placeholder {
	color: #ababab !important;
}

:-moz-placeholder {
	color: #ababab !important;
}

:-ms-input-placeholder {
	color: #ababab !important;
}

select {
	-moz-border-radius: 3px;
	-webkit-border-radius: 3px;
	border-radius: 3px;
	border: 1px solid #bcbcbc;
	color: #555555;
	cursor: pointer;
	background-color: white;
	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
	box-sizing: border-box;
	-moz-box-shadow: rgba(153, 153, 153, 0.2) 0px 0px 5px;
	-webkit-box-shadow: rgba(153, 153, 153, 0.2) 0px 0px 5px;
	box-shadow: rgba(153, 153, 153, 0.2) 0px 0px 5px;
	-moz-box-shadow: rgba(153, 153, 153, 0.2) 1px 2px 8px inset;
	-webkit-box-shadow: rgba(153, 153, 153, 0.2) 1px 2px 8px inset;
	box-shadow: rgba(153, 153, 153, 0.2) 1px 2px 8px inset;
	padding: 5px;
	font-size: 16px;
	background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='32' height='24' viewBox='0 0 32 24'><polygon points='0,0 32,0 16,24' style='fill: rgb%28138, 138, 138%29'></polygon></svg>");
	padding-right: 20px;
	background-size: 16px 8px;
	background-repeat: no-repeat;
	background-position: right -1rem center;
	background-origin: content-box;
	-webkit-appearance: none;
	width: 100%;
}

select:focus {
	border-color: #00a6a1;
	color: #3a3a3a;
	outline: none;
}

.input-group {
	margin-bottom: 16px;
	float: left;
	width: 30%;
	margin-right: 3%;
}

.input-group label {
	margin-bottom: 4px;
	display: block;
}

.actions {
	*zoom: 1;
	float: left;
	width: 100%;
	text-align: right;
}

.actions:after {
	content: "";
	display: table;
	clear: both;
}

.actions .input-group {
	float: right;
	width: auto;
	margin-right: 0;
	margin-left: 0;
}

.actions.left .input-group {
	float: left;
	margin-left: 0;
	margin-right: 16px;
}

.tab-content {
	*zoom: 1;
	padding: 16px 16px 0;
	border-top: none;
}

.tab-content:after {
	content: "";
	display: table;
	clear: both;
}

/* Validation Error*/
ul, li, label {
	margin: 0;
	padding: 0;
	border: 0;
	font: inherit;
	font-size: 100%;
	vertical-align: baseline;
}

ul {
	list-style: none;
}

.content-area ul {
	margin-bottom: 16px;
	*zoom: 1;
}

.content-area ul:after {
	content: "";
	display: table;
	clear: both;
}

.input-validation-errors {
	margin-bottom: 0.57143em;
	clear: both;
	font-weight: bold;
	color: #b14f64;
}

#policy-details fieldset label {
	display: block;
	float: none;
}
/********************************************/
/*			Payment Panel					*/
/********************************************/
.payment-panel .tab-content {
	background: #f4f3f3;
}

#payment-details {
	position: relative;
}

#payment-details.payment-details {
	padding-bottom: 10px;
}

#payment-details label {
	font-size: 18px;
	margin-bottom: 0;
}

#payment-details .help {
	font-size: 11px;
	margin-bottom: 8px;
	display: block;
}

#payment-details .card-types {
	*zoom: 1;
	margin-bottom: 16px;
}

#payment-details .card-types:after {
	content: "";
	display: table;
	clear: both;
}

#payment-details .card-types label {
	margin-bottom: 8px;
}

#payment-details .card-types span {
	float: left;
	margin-right: 8px;
}

#payment-details .info {
	border: none;
	padding: 0;
}

#payment-details .info .encryption {
	color: #333;
	font-size: 13px;
	display: inline;
}

#payment-details .cc-name .name, #payment-details .cc-number input {
	width: 310px;
}

#payment-details .cc-expiry select {
	margin-right: 8px;
	margin-bottom: 0;
}

#payment-details .cc-expiry select:last-child {
	margin-left: 0;
	margin-right: 0;
}

#payment-details .cc-expiry table {
	background-color: #f4f3f3; 
	border: none;
}

#payment-details .cc-expiry td {
	padding: 0;
	background-color: #f4f3f3; 
}

#payment-details .cc-verification {
	*zoom: 1;
	position: relative;
}

#payment-details .cc-verification:after {
	content: "";
	display: table;
	clear: both;
}

#payment-details .cc-verification input {
	float: left;
	width: 77px;
}

#payment-details .cc-verification label {
	display: inline;
}

#payment-details .cc-verification .alternative {
	font-size: 11px;
}

#payment-details .cc-verification .help {
	width: 45%;
}

#payment-details .cc-verification .hint {
	position: absolute;
	right: 0;
	display: {css_display_cvchint};
	top: 0;
	width: 40%;
	height: 56px;
}

#payment-details .cc-verification .hint .other {
	float: left;
	margin-right: 8px;
	background: transparent url("{img_cc_other_small}") no-repeat left top;
	width: 85px;
	height: 56px;
}

#payment-details .cc-verification .hint .amex {
	float: left;
	margin-right: 8px;
	background: transparent url("{img_cc_amex_small}") no-repeat left top;
	width: 100px;
	height: 56px;
}

#payment-details .cc-verification .hint .link-like {
	float: left;
	display: block;
	width: 40%;
	background: transparent url("{img_enlarge}") no-repeat left top !important;
	font-size: 13px;
	font-weight: bold;
}

#payment-details .set-name {
	display: inline;
	margin-left: 8px;
	font-weight: bold;
	font-size: 13px;
}

#payment-details label {
	display: block;
	float: none;
}

#payment-details .input-group {
	*zoom: 1;
	float: none;
	width: auto;
	display: block;
}

#payment-details .input-group:after {
	content: "";
	display: table;
	clear: both;
}

input[type="text"], select {
	border: 1px solid #dadada;
}

input[type="text"]:focus {
	border-color: #00a6a1;
}

/**************************************************************************************/
/* Modal Content
/**************************************************************************************/
.content-area h2 {
	font-size: 26px;
	line-height: 32px;
	margin-bottom: 16px;
}

.modal-content {
	-moz-box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 1px 1px;
	-webkit-box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 1px 1px;
	box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 1px 1px;
	-moz-border-radius: 3px;
	-webkit-border-radius: 3px;
	border-radius: 3px;
	border: 1px solid #bcbcbc;
	position: fixed;
	top: 100px;
	left: 45%;
	overflow: auto;
	padding: 16px 16px 0;
	background: #fff;
	width: 800px;
	margin-left: -400px;
	z-index: 910;
	padding-bottom: 16px;
}

.modal-content h2 {
	font-size: 26px !important;
	line-height: 32px !important;
	margin-bottom: 16px !important;
}

.modal-content h2 {
	font-size: 16px;
	line-height: 5px;
	margin-bottom: 0px;
}

.modal-content .close {
	position: absolute;
	top: 16px;
	right: 16px;
}

.modal-content .close span {
	padding-left: 0;
}

.modal-content.payment-hint {
	width: 550px;
	margin-left: -250px;
}

.modal-content.payment-hint h2 span {
	display: block;
	font-size: 18px;
	line-height: 18px;
}

.modal-content.payment-hint .card-wrapper {
	margin: 0 auto;
	*zoom: 1;
}

.modal-content.payment-hint .card-wrapper:after {
	content: "";
	display: table;
	clear: both;
}

.modal-content.payment-hint .card-wrapper.two {
	width: 500px;
}

.modal-content.payment-hint .card-wrapper .other {
	float: left;
	width: 235px;
	padding-top: 170px;
	background: transparent url("{img_cc_other_large}") no-repeat top left;
}

.modal-content.payment-hint .card-wrapper .amex {
	float: right;
	width: 235px;
	padding-top: 170px;
	background: transparent url("{img_cc_amex_large}") no-repeat top left;
}

/*************************************************************************/        
`;

	// language=HTML
	var cardDetailsHtml = `
<div class="tab-content">
	<div class="error">
		<ul class="input-validation-errors" style="display: none">
			<!-- validation errors go here -->
		</ul>
	</div>
	<div class="credit-card-editor-wrapper payment-details" id="payment-details">

		<h3 class="info">{PaymentHeaderText}<span class="encryption">{PaymentEncryptionText}</span></h3>
		<fieldset>
			<div class="card-types">
				<label>{CreditCardAcceptText}</label>
				<span><img src="{img_tendertype_visa}" alt="Visa" id="cardtoken_ImgVisaType" style="display: none;"></span>
				<span><img src="{img_tendertype_mc}" alt="MasterCard" id="cardtoken_ImgMasterCardType" style="display: none;"></span>
				<span><img src="{img_tendertype_ame}" alt="American Express" id="cardtoken_ImgAmexType" style="display: none;"></span>
			</div>

			<div class="input-group cc-name">
				<label>{CreditCardNameLabel}</label> <span class="help">{CreditCardNameHelpText}</span>
				<input class="name" id="cardtoken_NameOnCreditCard" tabindex="4" type="text" value="">
				<input class="link-like set-name" id="cardtoken_btnSetCardholderName" type="button" tabindex="11"
					   value="< {InsertFirstTravellerNameLinkText}">
			</div>
			<div class="input-group cc-number">
				<label>{CreditCardNumberLabel}</label> <span
				class="help">{CreditCardNumberHelpText}</span>
				<input autocomplete="off" id="cardtoken_CreditCardNumber" tabindex="5" type="text" value="">
			</div>

			<div class="input-group cc-expiry">
				<label>{CreditCardExpirationLabel}</label>
				<span class="help">{CreditCardExpirationHelpText}</span>
				<table>
					<tr><td>
							<select class="month" id="cardtoken_CreditCardExpiryDateMonthId" tabindex="6">
								<option selected="selected"></option>
								<option value="1">01 - Jan</option>
							</select>
						</td>
						<td style="vertical-align: center; text-align: center; width: 20px;">/</td>
						<td>
							<select class="year" id="cardtoken_CreditCardExpiryDateYearId" tabindex="7">
								<option selected="selected"></option>
								<option value="2019">2019</option>
							</select>
						</td>
					</tr>
				</table>
			</div>
			<div class="input-group cc-verification">
				<label>{CreditCardSecurityCodeLabel}</label>
				<span class="help">{CreditCardSecurityCodeHelpText}</span>
				<div class="hint">
					<div class="other"></div>
					<div class="amex"></div>
					<input class="link-like" type="button" id="cardtoken_btnEnlargeCardCvv" value="enlarge">
				</div>
				<input autocomplete="off" id="cardtoken_VerificationNumber" tabindex="8" type="text" value="">
			</div>

		</fieldset>
	</div>

	<div class="actions left">
		<div class="input-group">
			<button class="buy-now buy-button-primary" type="button" tabindex="8" autocomplete="off" id="cardtoken_DoPayment">
				{BuyNowButtonText}<span>&#57364;</span>
			</button>
		</div>
	</div>
	
	<div id="cardtoken_SpinnerContainer" style="display: none;">
		<div id="cardtoken_Spinner"></div>
	</div>
</div>

<div class="modal-background">
	<div class="modal-content payment-hint">

		<h2>{PaymentHintText}<span>{PaymentHintSecurityCodeTypesText}</span></h2>
		<p>{CreditCardVerificationNumberLabel}</p>

		<div class="card-wrapper two">
			<div class="other">
				<h4>{CreditCardLabelForVisaMaster}</h4>
				<p>{CreditCardVerificationNumberTextForVisaMaster}</p>
			</div>
			<div class="amex">
				<h4>{CreditCardLabelForAmericanExpress}</h4>
				<p>{CreditCardVerificationNumberTextForAmericanExpress}</p>
			</div>
		</div>
		<button type="button" class="button-tertiary close">
			<span>&#57360;</span>
		</button>
	</div>
</div>
`;
})();
;
