WS_OK_7.4.33 HEX
HEX
Server: nginx/1.21.4
System: Linux v12674 6.8.0-85-generic #85-Ubuntu SMP PREEMPT_DYNAMIC Thu Sep 18 15:26:59 UTC 2025 x86_64
User: endtheignorance (1014)
PHP: 7.4.33
Disabled: exec,passthru,shell_exec,system,proc_open,popen,parse_ini_file,show_source
Upload Files
File: /storage/v12674/lcapartners/public_html/wp-content/plugins/superstorefinder-wp/js/init.js
var FE = {};
jQuery(function() {
    homebrew.Carousel.prototype.options.transitions.enable = Modernizr.csstransitions;
    homebrew.Tooltip.prototype.options.appendTo = '#mainContent';
    homebrew.Tooltip.prototype.options.transitions.enable = Modernizr.csstransitions;


    jQuery.extend(FE, {
        $els : {
            backToTop : jQuery('#globalBackToTop'),
            body : jQuery('body'),
            mainSite : jQuery('#mainSite'),
            pageOverlay : jQuery('#pageOverlay'),
            root : jQuery('html')
        },

        events: {
            transitionEnd : homebrew.events.transitionEnd || 'transitionend oTransitionEnd otransitionend webkitTransitionEnd msTransitionEnd',
            animationEnd: homebrew.events.animationEnd || 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd'
        },

        browser : homebrew.browser,

        baseURL : (typeof fileUrl === 'string')
                    ? fileUrl
                    : (window.location.href.indexOf('') > -1)
                        ? ''
                        : ''
    });

    if(!FE.$els.pageOverlay.length) {
        FE.$els.pageOverlay = jQuery('<div class="page-overlay" id="pageOverlay" />').appendTo(FE.$els.mainSite);
    }

    if(!FE.$els.backToTop.length) {
        FE.$els.backToTop = jQuery('<a href="#top" title="Back To Top" class="main-back-to-top" id="mainBackToTop" />').appendTo('#mainContent');

        FE.$els.backToTop.on('click', function(e) {
            e.preventDefault();

            jQuery('html, body').animate({
                scrollTop : 0
            }, 400);
        });

        jQuery(window).on('scroll.toggleBackToTop', homebrew.utils.throttle(function() {
            FE.$els.backToTop.toggleClass('is-shown', jQuery(window).scrollTop() > jQuery(window).height()*0.5);
        }, 50));
    }

    if(typeof FE.browser === 'undefined') {
        FE.browser = {
            ie      : FE.$els.root.hasClass('ie'),
            ie9     : FE.$els.root.hasClass('ie9'),
            lt9     : FE.$els.root.hasClass('lt9'),
            ie8     : FE.$els.root.hasClass('ie8'),
            lt8     : FE.$els.root.hasClass('lt8'),
            ie7     : FE.$els.root.hasClass('ie7'),
            firefox : (window.mozIndexedDB !== undefined)
        }
    }


    jQuery.extend(true, FE, {
        alert : function(args) {
            this.showAlertPopup(args, 'alert');
        },

        confirm : function(args) {
            this.showAlertPopup(args, 'confirm');
        },

        showAlertPopup : function(args, method) {
            args = args || {};

            var $popup = jQuery('#FE__alertPopup');

            if(!$popup.length) {
                $popup = jQuery([
                        '<div class="ssf-popup text-center" id="FE__alertPopup">',
                            '<h2 class="title space-bottom-2x" />',
                            '<div class="popup-message" />',
                            '<div class="space-top-2x">',
                                '<a href="#/" class="button padded xlarge okay-button">Okay</a>',
                                '<a href="#/" class="button padded xlarge space-left cancel-button" style="display: none;">Cancel</a>',
                            '</div>',
                        '</div>'
                    ].join('')).appendTo('body');

                $popup.popupify({
                    addCloseBtns : false,
                    closeOnOverlay : false
                });
            }

            /* Alerts/Confirm dialog boxes should only happen one at a time,
             * so if it is already shown, then do not proceed. */
            if(jQuery('body').hasClass('popup-is-shown')
            && $popup.hasClass('is-shown')) {
                return;
            }

            var $title = $popup.find('.title'),
                $message = $popup.find('.popup-message'),
                $prevPopup = jQuery('.popup-is-shown').find('.ssf-popup.is-shown');

            if(args.title) $title.html(args.title);
            if(args.message) $message.html(args.message);

            $popup.find('.cancel-button').toggle(method === 'confirm');

            $popup.find('.okay-button, .cancel-button')
                .off('.alert')
                .on('click.alert', function() {
                    if($prevPopup.length
                    && typeof $prevPopup.eq(0).data('popupify') !== 'undefined') {
                        $prevPopup.data('popupify').reveal();
                    } else {
                        $popup.data('popupify').conceal();
                    }

                    if(typeof args.onConfirm === 'function') {
                        if(method === 'confirm') {
                            args.onConfirm(jQuery(this).is('.okay-button'));
                        } else {
                            args.onConfirm();
                        }
                    }
                });

            $popup.data('popupify').reveal();
        },


        FootnoteAnchor : function() {
            this.init.apply(this, arguments);
        },

        Hasher : function(options) {
            this.options = options;
        },

        HeightSlider : function(heightSlider) {
            if(typeof heightSlider === 'string') heightSlider = jQuery(heightSlider);

            var self = this;

            jQuery.extend(self, {
                reveal : function() {
                    if(Modernizr.csstransitions) {
                        if(heightSlider.height() !== 0) return;

                        var targetHeight = 0;
                        heightSlider.css('height', 'auto');
                        targetHeight = heightSlider.height();
                        heightSlider.css('height', '');

                        setTimeout(function() {
                            heightSlider
                                .off(FE.events.transitionEnd)
                                .on(FE.events.transitionEnd, function() {
                                    heightSlider
                                        .off(FE.events.transitionEnd)
                                        .removeClass('is-transitionable')
                                        .css('height', '')
                                        .addClass('is-toggled');
                                })
                                .addClass('is-transitionable')
                                .css('height', targetHeight + 'px');
                        }, 1);
                    } else {
                        if(heightSlider.css('display') !== 'none') return;

                        heightSlider.slideDown(400, function() {
                            jQuery(this).addClass('is-toggled');
                        });
                    }
                },

                conceal : function() {
                    if(Modernizr.csstransitions) {
                        if(heightSlider.height() === 0) return;

                        heightSlider
                            .css('height', heightSlider.height() + 'px')
                            .removeClass('is-toggled');

                        setTimeout(function() {
                            heightSlider
                                .off(FE.events.transitionEnd)
                                .on(FE.events.transitionEnd, function() {
                                    heightSlider.off(FE.events.transitionEnd);
                                        heightSlider.removeClass('is-transitionable');
                                        heightSlider.css('height', '');
                                })
                                .addClass('is-transitionable')
                                .css('height', '0px');
                        }, 1);
                    } else {
                        if(heightSlider.css('display') === 'none') return;

                        heightSlider
                            .removeClass('is-toggled')
                            .slideUp(400);
                    }
                },

                toggle : function() {
                    if(Modernizr.csstransitions) {
                        heightSlider.trigger((heightSlider.height() === 0) ? 'reveal' : 'conceal');
                    } else {
                        heightSlider.trigger((heightSlider.css('display') === 'none') ? 'reveal' : 'conceal');
                    }
                }
            });

            heightSlider.data('height-slider', self);
        },
        /* End HeightSlider */

        StickyColumn : function() {
            this.load.apply(this, arguments);
        },

        getHash : function() {
            var hash = window.location.hash;

            /*
             * Need to check if second character is a period; sometimes
             * AddThis adds its own hash to the URL, and its second
             * character is always a period, which is problematic.
             */
            if(hash === '' || hash.substr(1,1) === '.') {
                return '';
            } else {
                return hash;
            }
        },
        /* End getHash */

        getQueryStr: function(str) {
            var search = window.location.search;
            if(!search) return false;

            if(search.substr(0,1) === '?') {
                search = search.substr(1);
            }

            var splitSearch = search.split('&');
                keyValuePairs = {};

            splitSearch.map(function(searchStr) {
                var splitSearchStr = searchStr.split('=');

                splitSearchStr = splitSearchStr.map(function(str) {
                    return jQuery.trim(str);
                });

                keyValuePairs[splitSearchStr[0]] = splitSearchStr[1];
            });

            if(typeof str === 'string') {
                return (typeof keyValuePairs[str] === 'undefined') ? false : keyValuePairs[str];
            } else {
                return keyValuePairs;
            }
        },
        /* End getQueryStr */

        initContentTabbers : function() {
            /* For tabs that toggle contents instead of going to new pages */

            jQuery('.js-togglerify-tabs').each(function() {
                var $this = jQuery(this),
                    $nestedTabs = $this.find('.js-togglerify-tabs').find('.tab'),
                    $tabs = $this.find('.tab').not($nestedTabs),
                    $nestedContents = $this.find('.js-togglerify-tabs').find('.tab-content'),
                    $contents = $this.find('.tab-content').not($nestedContents);

                $tabs
                    .togglerify('destroy')
                    .togglerify({
                        toggledClass: 'current',
                        selfToggleable: false,
                        singleActive: true,
                        content: function(index) {
                            return $contents.eq(index);
                        }
                    })
                    .on('afterToggleOn', function() {
                        jQuery(window).trigger('resize');
                    })
                    .on('toggleOff', function(e, $thisTab, $thisContent) {
                        /* Pause videos if available */
                        $thisContent.find('.video-holder').find('iframe').each(function() {
                            this.contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}', '*');
                        });
                    });
            });
        },
        /* End initContentTabbers */

        initContentShowers : function() {
            var types = {
                    TAB: 'tab',
                    TOGGLER: 'toggler',
                    NOTES: 'notes'
                },
                $notesToggler = jQuery('#notesToggler'),
                $notesContent = jQuery('#notesContent');

            jQuery('.js-show-content').each(function() {
                var $this = jQuery(this),
                    thisHref = $this.attr('href');

                if(typeof thisHref !== 'string') {
                    console.log($this);
                    console.error("No target specified. Set the target's ID as the `href` attribute on the element.");
                    return
                }
                
                var $target = jQuery($this.attr('href'));

                if(!$target.length) {
                    console.log($this);
                    console.error("Target `" + $this.attr('href') + "` does not exist.");
                    return;
                }

                var data = $this.data('show-content-options');

                if(!data) {
                    console.log($this);
                    console.error('Options undeclared. Declare the options using the `data-show-content-options` attribute on the element.');
                    return;
                }

                var options = (typeof data === 'string')
                        ? homebrew.getKeyValuePairsFromString(data)
                        : {};

                if(!options.type) {
                    console.log($this);
                    console.error('Options declared, but no type specified.');
                    return;
                }

                var scrollArgs = [$target];

                if(options.smoothScroll !== true) {
                    scrollArgs.push('snap');
                }

                switch(options.type) {
                    case types.TAB:
                        $this.on('click', function(e) {
                            e.preventDefault();

                            var $tabContent = $target.closest('.tab-content'),
                                $heightSyncers = $tabContent.find('.js-sync-height-wrapper');

                            if($tabContent.hasClass('current')) {
                                FE.scrollTo.apply(null, scrollArgs);
                            } else {
                                if($heightSyncers.length) {
                                    $heightSyncers.last().one('afterSync', function() {
                                        FE.scrollTo.apply(null, scrollArgs);
                                    });
                                    $tabContent.data('togglerify').toggleOn();
                                } else {
                                    $tabContent.data('togglerify').toggleOn();
                                    FE.scrollTo.apply(null, scrollArgs);
                                }
                            }
                        });
                    break;

                    case types.NOTES:
                        if(!$notesToggler.length || !$notesContent.length) {
                            return;
                        }

                        $this.on('click', function(e) {
                            e.preventDefault();

                            if(!$notesToggler.hasClass('is-toggled')) {
                                $notesToggler.togglerify('toggleOn', { noSlide : true });
                            }

                            FE.scrollTo($target);
                        });
                    break;

                    default:
                        console.log($this);

                        var errorMsg = [
                                'The type `', options.type, '` is not supported. Our currently supported types are: '
                            ];

                        jQuery.each(types, function(key, value) {
                            errorMsg.push('\n' + value);
                        });

                        errorMsg.push('\n\nCheck the type again.');

                        console.error(errorMsg.join(''));
                    break;
                }
            });
        },
        /* End initContentShowers */

        initDropdownSwitchers : function($scope) {
            var $holders = ($scope && $scope.length)
                               ? $scope.find('.dropdown-switcher-holder')
                               : jQuery('.dropdown-switcher-holder');

            if(!$holders.length) return;

            $holders.each(function() {
                var $dropdown = jQuery(this).find('.dropdown-switcher'),
                    $contents = jQuery(this).find('.dropdown-content');

                $dropdown
                    .on('change', function() {
                        $contents
                            .hide()
                            .eq(this.selectedIndex)
                                .show();
                    })
                    .trigger('change');
            });
        },
      

        initNumberTabbers : function() {
            jQuery('.number-tabber').each(function() {
                var $tabs = jQuery(this).find('.number-tabber__tabs').children('li'),
                    $contents = jQuery(this).find('.number-tabber__contents').children('li');

                $tabs
                    .togglerify('destroy')
                    .togglerify({
                        toggledClass: 'current',
                        singleActive: true,
                        selfToggleable: false,
                        content: function(index) {
                            return $contents.eq(index);
                        }
                    });
            });
        },
        /* End initNumberTabbers */

        initPage : function() {
            jQuery('.js-dropdownify').dropdownify();
            jQuery('.js-inputify').inputify();

            jQuery.each(FE, function(key, value) {
                if(key.indexOf('init') === 0 && key !== 'initPage') value();
            });

            FE.loadXMLForm(jQuery('.js-xml-form-holder'));
            FE.loadXMLTable(jQuery('.js-xml-tbl-holder'));
            FE.loadXMLLocations(jQuery('.js-xml-locations-holder'));

            if(FE.browser.ie) jQuery('[placeholder]').placeholderify();
        },
        /* End initPage */

        initSectionSnap : function() {
            /* Only needed for touchscreens, where the header does not
             * automatically hide itself. */
            if(!Modernizr.touch) return;

            var hash = FE.getHash();
            if(!hash || hash.indexOf('#/') > -1) return;

            var $hash = jQuery(hash);
            if(!$hash.length || !$hash.is('.section')) return;

            setTimeout(function() {
                FE.scrollTo($hash);
            }, 25);
        },
        /* End initSectionSnap */

        initSelfTogglers : function() {
            /* Self Togglers - for things like FAQ questions */

            jQuery('.self-toggler__toggler').togglerify({
                singleActive: false,
                slide: true,
                content: function() {
                    return jQuery(this).next();
                }
            });
        },
        /* End initSelfTogglers */

        initSectionContentToggler : function() {
            /* Section Content togglers - for pages like Popular FAQs */

            var $sectionContentTogglers = jQuery('.section-content-toggler');
            if(!$sectionContentTogglers.length) return;

            var $sectionToggleableContents = jQuery('.section-toggleable-content'),
                $sectionDropdown = jQuery('<select>'),
                optionsStrArray = [];

            $sectionContentTogglers
                .togglerify({
                    selfToggleable: false,
                    singleActive : true,
                    content : function(index) {
                        return $sectionToggleableContents.eq(index);
                    }
                })
                .each(function(index) {
                    var $dropdownOption = jQuery(['<option>', jQuery.trim(jQuery(this).find('.toggler__title').text()), '</option>'].join(''));
                    $dropdownOption.data('section-content-toggler', jQuery(this));
                    $dropdownOption.appendTo($sectionDropdown);
                });

            jQuery('<div class="column show-for-small-down" />')
                .prepend($sectionDropdown)
                .prependTo($sectionContentTogglers.eq(0).closest('.row'));

            $sectionDropdown
                .dropdownify({
                    markups : {
                        holder : '<div class="expand space-bottom" />'
                    }
                })
                .on('change', function() {
                    var $thisToggler = jQuery(this).find('option:checked').data('section-content-toggler');
                    $thisToggler.togglerify('toggleOn');
                });

            FE.watchSize('small', function(isSmallScreen) {
                var method = (isSmallScreen) ? 'deactivate' : 'activate';
                $sectionContentTogglers.togglerify(method);
            });
        },
        /* End initSectionContentToggler */

        initSmallNav : function() {
            if(Modernizr.touch || jQuery('#mainSmallNav').data('initSmallNav') === true) return;

            jQuery('#mainSmallNav').data('initSmallNav', true);

            var prevScrollTop = jQuery(window).scrollTop(),
                navHeight = jQuery('#mainSmallNav').height() + jQuery('#mainNav').height();

            jQuery(window)
                .on('resize.navHider', function() {
                    navHeight = jQuery('#mainSmallNav').height() + jQuery('#mainNav').height();
                })
                .trigger('resize.navHider')
                .on('scroll.navHider', function() {
                    var currentScrollTop = jQuery(window).scrollTop(),
                        partialHiddenBool = currentScrollTop > 47,
                        hiddenBool = currentScrollTop >= prevScrollTop && currentScrollTop > navHeight && !FE.$els.body.hasClass('mobile-nav-is-shown');

                    jQuery('body').toggleClass('main-header-is-partially-hidden', partialHiddenBool);
                    jQuery('body').toggleClass('main-header-is-hidden', hiddenBool);
                    prevScrollTop = currentScrollTop;
                })
                .trigger('scroll.navHider');
        },
        /* End initSmallNav */

        initSyncHeightWrappers : function($scope) {
            var $syncHeightWrappers = jQuery('.js-sync-height-wrapper');
            if(!$syncHeightWrappers.length) return;

            $syncHeightWrappers.each(function() {
                var selectors = jQuery(this).data('sync-height-selector');
                if(!selectors) return;

                var selectorsSplitArray = selectors.split(',');

                for(var i = selectorsSplitArray.length-1; i > -1; i--) {
                    selectorsSplitArray[i] = jQuery.trim(selectorsSplitArray[i]);
                }
                
                jQuery(this).heightSyncify({
                    items : selectorsSplitArray
                });
            });
        },
        /* End initSyncHeightWrappers */

        initTooltips : function() {
            var $els = jQuery('.icon--question[title], .js-tooltipify');

            $els.tooltipify();
        },
        /* End initTooltips */

        initQuickLinks : function() {
            var $quicklinksToggler = jQuery('#mainNav__quicklinksToggler'),
                $quicklinks = jQuery('#mainNav__quicklinks');

            if(!$quicklinksToggler.length || !$quicklinks.length) return;
            if($quicklinksToggler.data('initQuickLinks') === true) return;

            $quicklinksToggler.data('initQuickLinks', true);

            var mouseupEv = 'mouseup.mainNavQuicklinksFauxBlur',
                resizeEv = 'resize.limitQuicklinksHeight';

            $quicklinksToggler
                .togglerify({
                    slide: true,
                    content: function() {
                        return $quicklinks;
                    }
                })
                .togglerify('deactivate')
                .on({
                    click : function(e) {
                        e.preventDefault();
                        
                        var $thisToggler = jQuery(this);

                        if($thisToggler.hasClass('is-toggled')) {
                            $thisToggler.togglerify('toggleOff');
                        } else {
                            var heightLimit = jQuery(window).height() - jQuery('#mainNav').height(),
                                contentHeight;

                            $quicklinks.css('height', 'auto');
                            contentHeight = $quicklinks.height();
                            $quicklinks.css('height', '');

                            if(contentHeight >= heightLimit) {
                                $thisToggler.togglerify('toggleOn', { contentHeight : heightLimit });
                            } else {
                                $thisToggler.togglerify('toggleOn');
                            }
                        }
                    },

                    toggleOn : function(e, $thisToggler, $target) {
                        jQuery(document).on(mouseupEv, function(e) {
                            var container = $thisToggler.add($target);
                        
                            if(!container.is(e.target) && container.has(e.target).length === 0) {
                                jQuery(document).off(mouseupEv);
                                $target.data('togglerify').toggleOff();
                            }
                        });

                        jQuery(window).on(resizeEv, function() {
                            if(!$thisToggler.hasClass('is-toggled')) return;

                            var heightLimit = jQuery(window).height() - jQuery('#mainNav').height();

                            $quicklinks.css('height', '');
                            
                            if($quicklinks.height() >= heightLimit) {
                                $quicklinks.height(heightLimit);
                            }
                        });
                    },

                    toggleOff : function() {
                        jQuery(document).off(mouseupEv);
                        jQuery(window).off(resizeEv);
                    }
                });
        },
        /* End initQuickLinks */

        loadXMLForm : function($holders) {
            $holders = jQuery($holders);
            if(!$holders.length) return;

            $holders.each(function() {
                var $thisHolder = jQuery(this);
                if(jQuery.data(this, 'loaded-xml-form') === true) return;

                var xmlURL = $thisHolder.data('xml-form-url');
                if(typeof xmlURL !== 'string') return;

                jQuery.ajax({
                    type: 'GET',
                    url: xmlURL,
                    dataType: 'xml',
                    success: function(data) {
                        makeXMLForm(data, $thisHolder);
                        FE.initFancyPlaceholders($thisHolder);
                        FE.initInputFocus($thisHolder);
                        $thisHolder.find('.js-inputify').inputify();
                        $thisHolder.find('.js-dropdownify').dropdownify();
                        $thisHolder.data('loaded-xml-form', true);
                    },
                    error: function(d) {
                        console.log(d);
                    }
                });
            });

            function makeXMLForm(data, $holder) {
                var $data = jQuery(data),
                    $inputs = $data.find('formInput'),
                    uniqueID = new Date().getTime() + '_' + Math.round(Math.random()*10000),
                    $xmlForm = jQuery([
                        '<form action="https://docs.google.com/forms/d/', getText($data.find('formID')), '/formResponse"',
                        'target="hiddenIframe_', uniqueID, '"',
                        'method="post" class="xml-form-asset xml-form-contents" />'
                    ].join('')).prependTo($holder),
                    xmlFormStrArray = [];

                xmlFormStrArray.push([
                    '<div class="row collapse   space-bottom medium-space-bottom-2x">',
                        makeTitle($data.find('formTitle')),
                    '</div>'
                ].join(''));

                $inputs.each(function(index) {
                    var $thisInput = jQuery(this),
                        uniqueInputID = new Date().getTime() + '_' + index,
                        name = getText($thisInput.find('name')),
                        label = getText($thisInput.find('label')),
                        type = getText($thisInput.find('type')).toLowerCase(),
                        required = getText($thisInput.find('required')).toLowerCase(),
                        pattern = getText($thisInput.find('pattern')),
                        tooltip = getText($thisInput.find('tooltip'));

                    switch(type) {
                        case 'text':
                        case 'number':
                        case 'email':
                        case 'textarea':
                            var validifyStrArray = ['response: #response_' + uniqueInputID],
                                floaterStrArray = [];

                            if(!pattern) {
                                if(type === 'number') {
                                    validifyStrArray.unshift('pattern: numbers');
                                } else if(type === 'email') {
                                    validifyStrArray.unshift('pattern: email');
                                }
                            }

                            if(required === 'yes') {
                                validifyStrArray.unshift('required: true');
                            }

                            validifyStrArray.push('floater: #floater_roi_' + uniqueInputID);

                            floaterStrArray.push('<div class="validify-floater" id="floater_roi_', uniqueInputID, '">');
                                if(required === 'yes') {
                                    floaterStrArray.push([
                                        '<span class="validify-floater__message validify-floater__message--failed-required">',
                                            'This input is required.',
                                        '</span>'
                                    ].join(''));
                                }

                                var errorMessage = getText($thisInput.find('errorMessage'));

                                /*if(!errorMessage) {*/
                                    if(type === 'number') {
                                        errorMessage = 'This input should consist of numbers only.'
                                    } else if(type === 'email') {
                                        errorMessage = 'The address should be in this format: username@youremail.com'
                                    } else if(!errorMessage) {
                                        errorMessage = 'Invalid input.'
                                    }
                                /*}*/

                                floaterStrArray.push([
                                    '<span class="validify-floater__message validify-floater__message--failed-pattern">',
                                        errorMessage,
                                    '</span>'
                                ].join(''));

                            floaterStrArray.push('</div>');
                            
                            var elementStr;

                            if(type === 'textarea') {
                                elementStr = [
                                    '<textarea'
                                ];
                            } else {
                                elementStr = [
                                    '<input',
                                        ' type="', (type === 'email') ? 'email' : 'text', '"'
                                ];
                            }

                                elementStr.push(
                                        ' data-validify="', validifyStrArray.join(', '), '"',
                                        (pattern)
                                            ? ' data-validify-pattern="' + pattern + '"'
                                            : '',
                                        ' name="', name, '"',
                                        ' class="field expand"',
                                        ' id="roi_', uniqueInputID ,'"',
                                    (type === 'textarea')
                                    ? '></textarea>'
                                    : ' />'
                                );

                            xmlFormStrArray.push([
                                '<div class="form-obj', (tooltip) ? ' form-obj--with-tooltip' : '', '">',
                                    '<div class="field-holder expand">',
                                        elementStr.join(''),
                                        '<label for="roi_', uniqueInputID, '" class="field-holder__label">',
                                            label, (required === 'yes') ? '<span class="text-red">*</span>' : '',
                                        '</label>',
                                    '</div>',

                                    '<span class="validify-responses  form-obj__icon" id="response_', uniqueInputID, '">',
                                        '<span class="validify-response validify-response--success">',
                                            '<i class="icon icon--success-tick"></i>',
                                        '</span>',
                                    '</span>',

                                    (tooltip)
                                    ? '<i title="' + tooltip + '" class="icon icon--question round-circle   form-obj__icon"></i>'
                                    : '',

                                    floaterStrArray.join(''),
                                '</div>'
                            ].join(''));
                        break;

                        case 'dropdown':
                            var validifyStrArray = ['response: #response_' + uniqueInputID],
                                floaterStr = '';

                            if(required === 'yes') {
                                validifyStrArray.unshift('required: true');
                                validifyStrArray.push('floater: #floater_roi_' + uniqueInputID);

                                floaterStr = [
                                    '<div class="validify-floater" id="floater_roi_', uniqueInputID, '">',
                                        '<span class="validify-floater__message validify-floater__message--failed-required">',
                                            'This input is required.',
                                        '</span>',
                                    '</div>'
                                ].join('');
                            }

                            var optionsArray = getText($thisInput.find('options')).split('\n'),
                                options = [];

                            while(optionsArray.length) {
                                options.push([
                                    '<option value="', optionsArray[0], '">',
                                        optionsArray[0],
                                    '</option>'
                                ].join(''));

                                optionsArray.shift();
                            }

                            xmlFormStrArray.push([
                                '<div class="form-obj', (tooltip) ? ' form-obj--with-tooltip' : '', '">',
                                    '<span class="expand js-dropdownify">',
                                        '<select data-validify="', validifyStrArray.join(', '), '" name="', name, '">',
                                            '<option value="">', label, (required === 'yes') ? '*' : '', '</option>',
                                            options.join(''),
                                        '</select>',
                                    '</span>',

                                    '<span class="validify-responses  form-obj__icon" id="response_', uniqueInputID, '">',
                                        '<span class="validify-response validify-response--success">',
                                            '<i class="icon icon--success-tick"></i>',
                                        '</span>',
                                    '</span>',

                                    (tooltip)
                                    ? '<i title="' + tooltip + '" class="icon icon--question round-circle   form-obj__icon"></i>'
                                    : '',

                                    floaterStr,
                                '</div>'
                            ].join(''));
                        break;

                        case 'radio':
                        case 'checkbox':
                            var validifyStrArray = ['groupResponse: #response_' + uniqueInputID],
                                validifyRequiredStr = '';

                            if(required === 'yes') {
                                validifyStrArray.unshift('required: true');

                                validifyRequiredStr = [
                                    '<span class="validify-response validify-response--failed-required">',
                                        '<br />This input is required.',
                                    '</span>'
                                ].join('');
                            }

                            var optionsArray = getText($thisInput.find('options')).split('\n'),
                                optionsLabelsArray = getText($thisInput.find('optionsLabels')).split('\n'),
                                options = [],
                                currentOption;

                            for(var i = 0, ii = optionsArray.length; i < ii; i++) {
                                if(optionsArray[i] === '__other_option__') {
                                    /*options.push([
                                        '<label>',
                                            '<input type="', type, '" name="', name, '" data-validify value="others" class="js-inputify" /> ',
                                            'Others',
                                        '</label>',
                                        '<input type="text" disabled class="field" />'
                                    ].join(''));*/
                                } else {
                                    options.push([
                                        '<label>',
                                            '<input type="', type, '" name="', name, '" data-validify value="', optionsArray[i], '" class="js-inputify" /> ',
                                            (typeof optionsLabelsArray[i] === 'string'
                                            && optionsLabelsArray[i])
                                            ? optionsLabelsArray[i]
                                            : optionsArray[i],
                                        '</label>'
                                    ].join(''));
                                }
                            }

                            xmlFormStrArray.push([
                                '<div class="form-obj" data-validify-group="', validifyStrArray.join(', '), '">',
                                    '<p class="form-obj__label">',
                                        label, (required === 'yes') ? '<span class="text-red">*</span>' : '',

                                        (tooltip)
                                        ? ' <i title="' + tooltip + '" class="icon icon--question round-circle"></i>'
                                        : '',

                                        ' <span class="validify-responses" id="response_', uniqueInputID, '">',
                                            '<span class="validify-response validify-response--success">',
                                                '<i class="icon icon--success-tick"></i>',
                                            '</span>',

                                            validifyRequiredStr,
                                        '</span>',
                                    '</p>',

                                    options.join(''),
                                '</div>'
                            ].join(''));
                        break;
                    }
                });

                xmlFormStrArray.push([
                    '<div class="text-center space-top medium-space-top-2x">',
                        '<input type="submit" value="Submit" class="button padded xlarge" />',
                    '</div>'
                ].join(''));

                $xmlForm.append(xmlFormStrArray.join(''));
                $xmlForm.find('.icon--question[title]').tooltipify();

                var $hiddenIframe = jQuery('<iframe data-submitted="false" name="hiddenIframe_' + uniqueID + '" style="display: none;" />').appendTo($xmlForm);

                $hiddenIframe.on('load', function() {
                    if(jQuery(this).data('submitted') !== true) return;
                    
                    $xmlForm.addClass('is-hidden');
                    $holder.find('.xml-form-thanks').addClass('is-shown');
                    FE.scrollTo($holder.find('.xml-form-thanks'));
                });

                $xmlForm.validify().on('submit', function(e) {
                    var validifyData = jQuery.data(this, 'validify');

                    validifyData.set('strict', true).validate();

                    if(validifyData.valid !== true) {
                        //alert('Please check the form!');

                        var $errorInput = jQuery(this).find('.is-failed').eq(0);
                        
                        FE.scrollTo($errorInput, function() {
                            $errorInput.focus().select();
                        });

                        e.preventDefault();
                    } else {
                        $hiddenIframe.data('submitted', true);
                        $xmlForm.find('input[type="submit"]').addClass('is-loading').prop('disabled', true);
                    }
                });
            }

            function getText($node) {
                return ($node.length) ? jQuery.trim($node.text()) : '';
            }

            function makeTitle($title) {
                var title = getText($title);

                if(title) {
                    return [
                        '<div class="large-6 column">',
                            '<h3>', title, '</h3>',
                        '</div>',

                        '<div class="large-6 column   medium-down-pad-vertical large-text-right align-to-h3 text-dark-grey">',
                            '<span class="text-red">*</span> Please fill in the mandatory fields.',
                        '</div>'
                    ].join('');
                } else {
                    return [
                        '<div class="column   medium-down-pad-vertical large-text-right text-dark-grey">',
                            '<span class="text-red">*</span> Please fill in the mandatory fields.',
                        '</div>'
                    ].join('');
                }
            }
        },
        /* End loadXMLForm */

        loadXMLTable : function($holders) {
            $holders = jQuery($holders);
            if(!$holders.length) return;

            var worksheets = {},
                xmlSerializer = new XMLSerializer(); // Needed for makeCellInlineFormats

            $holders.each(function() {
                var $thisHolder = jQuery(this);
                if($thisHolder.data('loaded-xml-table') === true) return;

                var xmlURL = $thisHolder.data('xml-table-url');
                if(typeof xmlURL !== 'string') return;

                jQuery.ajax({
                    type: 'GET',
                    url: xmlURL,
                    dataType: 'xml',
                    success: function(data) {
                        var xmlStyles = getXMLStyles(data);
                        makeXMLTable(data, xmlStyles, $thisHolder);
                        attachRowHoverers();
                        $thisHolder.data('loaded-xml-table', true);
                    },
                    error: function(d) {
                        console.log(d);
                    }
                });
            });

            function makeXMLTable(data, xmlStyles, $holder) {
                var $data = jQuery(data),
                    $worksheets = $data.find('Worksheet'),
                    dropdown = {},
                    finalTableStrArr = [];

                worksheets = {};

                $worksheets.each(function() {
                    var $thisWorksheet = jQuery(this),
                        thisWorksheetName = $thisWorksheet.attr('ss:Name').toLowerCase();

                    if(thisWorksheetName.indexOf('dropdown') === 0) {
                        $thisWorksheet.find('Data').each(function() {
                            var $Data = jQuery(this),
                                DataIndex = $Data.index(),
                                DataText = jQuery(this).text().toLowerCase();

                            switch(DataText) {
                                case 'dropdown label':
                                    dropdown.__label = jQuery(this).closest('Row').next('Row').find('Data').text();
                                break;

                                case 'option label':
                                    jQuery(this).closest('Row').nextUntil().each(function() {
                                        var optionLabelText = jQuery(this).find('Data').eq(DataIndex).text();
                                        if(optionLabelText === '') return;
                                        dropdown[jQuery(this).find('Data').eq(DataIndex).text()] = jQuery(this).find('Data').eq(DataIndex+1).text().toLowerCase();
                                    });
                                break;
                            }
                        });
                    } else {
                        worksheets[thisWorksheetName] = $thisWorksheet;
                    }
                });

                if(jQuery.isEmptyObject(dropdown)) {
                    var worksheetNames = [];

                    jQuery.each(worksheets, function(key, value) {
                        worksheetNames.push(key);
                    });

                    finalTableStrArr.push(iterateWorksheetsArray(worksheetNames, xmlStyles));
                } else {
                    var dropdownOptionsArray = [],
                        dropdownContentsArray = [];

                    jQuery.each(dropdown, function(key, value) {
                        if(key === '__label') return;

                        dropdownOptionsArray.push(key);

                        var dropdownWorksheets = {},
                            valueSplitArray = value.split('\n');

                        if(valueSplitArray.length === 1) {
                            valueSplitArray = valueSplitArray[0].split(',');
                        }

                        for(var i = valueSplitArray.length-1; i > -1; i--) {
                            valueSplitArray[i] = jQuery.trim(valueSplitArray[i]);
                        }

                        dropdownContentsArray.push(iterateWorksheetsArray(valueSplitArray, xmlStyles));
                    });

                    var dropdownOptionsStrArray = [],
                        dropdownContentsStrArray = [];

                    while(dropdownOptionsArray.length) {
                        dropdownOptionsStrArray.push([
                            '<option>', dropdownOptionsArray.shift(), '</option>'
                        ].join(''));
                    }

                    while(dropdownContentsArray.length) {
                        dropdownContentsStrArray.push([
                            '<div class="dropdown-content">',
                                dropdownContentsArray.shift(),
                            '</div>'
                        ].join(''));
                    }

                    finalTableStrArr.push([
                        '<div class="dropdown-switcher-holder">',
                            '<div class="text-center text-large">',
                                dropdown.__label,
                                '<span class="js-dropdownify tbl-dropdown">',
                                    '<select class="dropdown-switcher">',
                                        dropdownOptionsStrArray.join(''),
                                    '</select>',
                                '</span>',
                            '</div>',

                            '<div class="dropdown-contents-holder">',
                                dropdownContentsStrArray.join(''),
                            '</div>',
                        '</div>'
                    ].join(''));
                }

                $holder.append(finalTableStrArr.join(''));

                FE.initFootnotes($holder);

                if(!$holder.find('.js-dropdownify').length) return;

                $holder.find('.js-dropdownify').dropdownify();
                FE.initDropdownSwitchers($holder);
            }

            function iterateWorksheetsArray(worksheetNames, xmlStyles) {
                var worksheetStrArr = [],
                    currentWorksheetName,
                    mediaClass;

                while(worksheetNames.length) {
                    currentWorksheetName = worksheetNames.shift();

                    if(typeof worksheets[currentWorksheetName] === 'undefined') {
                        console.error("FE.loadXMLTable(): Can't find the worksheet '" + currentWorksheetName + "'");
                        continue;
                    }
                    
                    if(currentWorksheetName.indexOf('desktop') === 0) {
                        mediaClass = 'show-for-large-up';
                    } else if(currentWorksheetName.indexOf('tabletup') === 0) {
                        mediaClass = 'show-for-medium-up';
                    } else if(currentWorksheetName.indexOf('tabletonly') === 0) {
                        mediaClass = 'show-for-medium-only';
                    } else if(currentWorksheetName.indexOf('tabletdown') === 0) {
                        mediaClass = 'show-for-medium-down';
                    } else if(currentWorksheetName.indexOf('mobile') === 0) {
                        mediaClass = 'show-for-small-down';
                    }

                    worksheetStrArr.push([
                        '<div class="tbl-holder', (typeof mediaClass === 'string') ? ' ' + mediaClass : '', '">'
                    ].join(''));
                        worksheetStrArr.push(makeTableString(worksheets[currentWorksheetName], xmlStyles));
                    worksheetStrArr.push('</div>');
                }

                return (worksheetStrArr.length) ? worksheetStrArr.join('') : false;
            }

            function getColumnCount($worksheet) {
                var $worksheetRows = $worksheet.find('Row'),
                    _columnCount = [];

                $worksheetRows.each(function() {
                    var $cells = jQuery(this).find('Cell');

                    /* Filter out empty cells */
                    $cells.each(function() {
                        if(!jQuery(this).text()) {
                            $cells = $cells.not(jQuery(this));
                        }
                    });

                    _columnCount.push($cells.length);
                });

                return Math.max.apply(null, _columnCount);
            }

            function getXMLStyles(data) {
                var $styles = jQuery(data).find('Style'),
                    styleObj = {};
                
                $styles.each(function() {
                    var $thisStyle = jQuery(this),
                        $alignment = $thisStyle.find('Alignment'),
                        $interior = $thisStyle.find('Interior'),
                        $numberFormat = $thisStyle.find('NumberFormat'),
                        $font = $thisStyle.find('Font'),
                        thisStyleObj = {};

                    /* Allow adjustment of alignment in the Excel spreadsheet */
                    if($alignment.length && hasAttributes($alignment, ['ss:Horizontal', 'ss:Vertical'])) {
                        var verticalAlignment, horizontalAlignment;

                        switch($alignment.attr('ss:Vertical')) {
                            case 'Top' : verticalAlignment = 'top'; break;
                            case 'Center' : verticalAlignment = 'middle'; break;
                            case 'Bottom' : verticalAlignment = 'bottom'; break;
                        }

                        switch($alignment.attr('ss:Horizontal')) {
                            case 'Top' : horizontalAlignment = 'top'; break;
                            case 'Center' : horizontalAlignment = 'center'; break;
                            case 'Bottom' : horizontalAlignment = 'bottom'; break;
                        }

                        thisStyleObj.alignment = {
                            'vertical' : verticalAlignment,
                            'horizontal' : horizontalAlignment
                        };
                    }

                    /* Interior is where the cell's background color data is stored */
                    if($interior.length && hasAttributes($interior, ['ss:Color'])) {
                        thisStyleObj.bgColor = $interior.attr('ss:Color');
                    }

                    if($font.length && hasAttributes($font, ['ss:Italic', 'ss:Bold', 'ss:Underline', 'ss:Color', 'ss:Size'])) {
                        thisStyleObj.font = {
                            'italic' : $font.attr('ss:Italic'),
                            'bold' : $font.attr('ss:Bold'),
                            'underline' : $font.attr('ss:Underline'),
                            'color' : $font.attr('ss:Color'),
                            'size' : $font.attr('ss:Size')
                        };
                    }

                    if($numberFormat.length && hasAttributes($numberFormat, ['ss:Format'])) {
                        thisStyleObj.numberFormat = $numberFormat.attr('ss:Format');
                    }

                    styleObj[$thisStyle.attr('ss:ID')] = thisStyleObj;
                });

                return styleObj;
            }

            function makeTableString($worksheet, xmlStyles) {
                var $rows = filterOutEmptyRows($worksheet.find('Row'));                    
                if(!$rows.length) return '';

                var totalColumns = parseInt(getColumnCount($worksheet), 10),
                    totalRows = $rows.length,
                    i, ii, j, jj,
             
                    tableLayout = [];

                for(i = $rows.length-1; i >-1; i--) {
                    tableLayout.push(new Array(totalColumns));
                }

                $rows.each(function(rowIndex) {
                   
                    var cellCount = 0;

                    jQuery(this).find('Cell').each(function(cellIndex) {
                        if(cellCount >= totalColumns) return;

                        var $thisCell = jQuery(this),
                            cellMergeDown = parseInt($thisCell.attr('ss:MergeDown'), 10) || 0,
                            cellMergeAcross = parseInt($thisCell.attr('ss:MergeAcross'), 10) || 0;

                       
                        while(typeof tableLayout[rowIndex][cellCount] === 'number') {
                            cellCount++;
                        }

                        tableLayout[rowIndex][cellCount] = $thisCell;

                        /* If there's colspan, then denote the overlapping cells
                         * as 0 so that it won't be rendered later. */
                        if(cellMergeAcross) {
                            for(i = cellCount, ii = cellCount+cellMergeAcross; i < ii; i++) {
                                tableLayout[rowIndex][i+1] = 0;
                            }

                            cellCount += cellMergeAcross;
                        }

                        /* Same thing, if there's rowspan, then denote the
                         * overlapping cells as 0 so that it won't be
                         * rendered later. */
                        if(cellMergeDown) {
                            for(i = rowIndex+1, ii = rowIndex+cellMergeDown; i <= ii; i++) {
                                tableLayout[i][cellCount] = 0;

                                /* Same thing; this is to account for both rowspan
                                 * and colspan from the same cell. */
                                if(cellMergeAcross) {
                                    for(j = cellCount+1, jj = cellCount+cellMergeAcross; j <= jj; j++) {
                                        tableLayout[i][j] = 0;
                                    }
                                }
                            }
                        }

                        cellCount++;
                    });
                });

                var tableStrArr = [],
                    tableStyleID = $worksheet.find('Table').attr('ss:StyleID'),
                    defaultStyle = (xmlStyles[tableStyleID]) ? xmlStyles[tableStyleID] : {};

                tableStrArr.push('<table class="default-tbl">');

                var cellStrArr, cellArray, cell, k, kk;
                while(tableLayout.length) {
                    cellStrArr = [];

                    cellArray = tableLayout.shift();

                    for(k = 0, kk = cellArray.length; k < kk; k++) {
                        if(typeof cellArray[k] === 'undefined') {
                            cellStrArr.push('<td></td>');
                        } else if(typeof cellArray[k] === 'object') {
                            cellStrArr.push(makeCellString(cellArray[k], k));
                        }
                    }

                    if(cellStrArr.length) {
                        cellStrArr.unshift('<tr>');
                        cellStrArr.push('</tr>');
                        tableStrArr.push(cellStrArr.join(''));
                    }
                }

                tableStrArr.push('</table>');

                return tableStrArr.join('');

                function makeCellString($cell, cellIndex, log) {
                    var $thisCell = $cell,
                        cellContent = $thisCell.text();

                    if(cellContent === '') {
                        if(cellIndex % 2 === 1) {
                            return '<td class="alt"></td>';
                        } else {
                            return '<td></td>';
                        }
                    }

                    var cellStyle = jQuery.extend({}, defaultStyle),
                        cellData = $thisCell.find('Data'),
                        cellDataType = cellData.attr('ss:Type');

                    if(cellDataType === 'Number') {
                        var decimalSplit = cellContent.split('.');

                        if(decimalSplit.length > 1 && decimalSplit[1].length > 2) {
                            cellContent = parseFloat(cellContent, 10).toFixed(2);
                        }
                    }

                    if(xmlStyles[$thisCell.attr('ss:StyleID')]) {
                        jQuery.extend(cellStyle, xmlStyles[$thisCell.attr('ss:StyleID')]);
                    }

                    var cellNumberFormat = cellStyle.numberFormat,
                        cellMergeDown = parseInt($thisCell.attr('ss:MergeDown'), 10) || 0,
                        cellMergeAcross = parseInt($thisCell.attr('ss:MergeAcross'), 10) || 0,
                        cellSSData = $thisCell.children('ss\\:Data'),
                        cellInlineTags = {
                            'italic' : 0,
                            'bold' : 0,
                            'underline' : 0
                        },

                        cellTagName = (cellStyle.bgColor && cellStyle.bgColor !== '#FFFFFF') ? 'th' : 'td',
                        cellClassNames = [],
                        cellClassName = '',
                        cellRowspan = '',
                        cellColspan = '',
                        cellInlineStyles = [];

                    if(cellIndex % 2 === 1) {
                        cellClassNames.push('alt');
                    }

                    if(cellSSData.length) {
                        cellInlineTags = {
                            'bold' : cellSSData.find('B').length,
                            'italic' : cellSSData.find('I').length,
                            'underline' : cellSSData.find('U').length
                        };

                        cellContent = makeCellInlineFormats(cellSSData);
                    }

                    if(typeof cellStyle.bgColor === 'string') {
                        cellInlineStyles.push('background-color: ' + cellStyle.bgColor);
                    }

                    if(typeof cellStyle.alignment === 'object') {
                        if(typeof cellStyle.alignment.horizontal === 'string') {
                            cellInlineStyles.push('text-align: ' + cellStyle.alignment.horizontal);
                        }
                        if(typeof cellStyle.alignment.vertical === 'string') {
                            cellInlineStyles.push('vertical-align: ' + cellStyle.alignment.vertical);
                        }
                    }

                    if(typeof cellStyle.font === 'object') {
                        if(typeof cellStyle.font.italic !== 'undefined') {
                            cellInlineStyles.push('font-style: italic');
                        }
                        if(typeof cellStyle.font.bold !== 'undefined') {
                            cellInlineStyles.push('font-weight: bold');
                        }
                        if(typeof cellStyle.font.underline !== 'undefined') {
                            cellInlineStyles.push('text-decoration: underline');
                        }
                        if(typeof cellStyle.font.color !== 'undefined') {
                            cellInlineStyles.push('color: ' + cellStyle.font.color);
                        }
                    }


                    /* Compile all the attributes */

                    if(cellClassNames.length) {
                        cellClassName = [' class="', cellClassNames.join(' '), '"'].join('');
                    }

                    if(cellMergeDown) {
                        cellRowspan = [' rowspan="', cellMergeDown+1, '"'].join('');
                    }

                    if(cellMergeAcross) {
                        cellColspan = [' colspan="', cellMergeAcross+1, '"'].join('');
                    }

                    if(typeof cellNumberFormat !== 'undefined') {
                        cellContent = makeCellCurrency(cellNumberFormat, cellContent);
                    }

                    if(cellInlineStyles.length) {
                        cellInlineStyles = [' style="', cellInlineStyles.join('; '), '"'].join('');
                    } else {
                        cellInlineStyles = '';
                    }

                    cellContent = cellContent.replace(/\n/g, '<br />');

                    if(typeof cellStyle.font === 'object'
                    && typeof cellStyle.font.size !== 'undefined'
                    && cellStyle.font.size !== '11') {
                        cellContent = [
                            '<span style="font-size: ', Math.round(parseFloat(cellStyle.font.size, 10) / 11 * 100, 10), '%;">',
                                cellContent,
                            '</span>'
                        ].join('');
                    }

                    return [
                        '<', cellTagName, cellClassName, cellRowspan, cellColspan, cellInlineStyles, '>',
                            cellContent,
                        '</', cellTagName, '>'
                    ].join('');
                }
            }

            function makeCellInlineFormats($ssData) {
                /*
                 * $ssData.html() was initially used to get the string of the
                 * contents. However, that produced an error in all versions
                 * of IE as well as Safari. This was with jQuery 1.11.0.
                 *
                 * To work around this, an XMLSerializer is used instead. 
                 * https://developer.mozilla.org/en-US/docs/XMLSerializer
                 */
                var ssDataChildNodes = jQuery.makeArray($ssData[0].childNodes),
                    contentsStr = [];

                while(ssDataChildNodes.length) {
                    contentsStr.push(xmlSerializer.serializeToString(ssDataChildNodes.shift()));
                }

                contentsStr = contentsStr.join('');

                var cellContentStr = contentsStr,
                    fontMatchArray = cellContentStr.match(/<Font+(.*?)>/g);

                var inlineStyles;
                for(var i = 0, ii = fontMatchArray.length; i < ii; i++) {
                    inlineStyles = getInlineStyles(fontMatchArray[i]);

                    if(inlineStyles === '') {
                        cellContentStr = cellContentStr
                                            .replace(fontMatchArray[i], '')
                                            .replace('</Font>', '');
                    } else {
                        cellContentStr = cellContentStr
                                            .replace(fontMatchArray[i], '<span style="' + inlineStyles + '">')
                                            .replace('</Font>', '</span>');
                    }
                }

                var inlineTags = ['b', 'i', 'u', 'sup'],
                    tagName;

                while(inlineTags.length) {
                    tagName = inlineTags.shift();

                    cellContentStr = cellContentStr
                                        .replace(new RegExp('<' + tagName + '+(.*?)>', 'gi'), '<' + tagName + '>')
                                        .replace(new RegExp('<\/' + tagName + '+(.*?)>', 'gi'), '</' + tagName + '>');
                }

                return cellContentStr;

                function getInlineStyles(fontHTMLStr) {
                    /*
                     * The subtstring is to remove the opening and closing
                     * angled brackets (`<` and `>`) at the start and end
                     * of the string.
                     */
                    var splitArray = fontHTMLStr.substring(1, fontHTMLStr.length-1).split(' '),
                        attrStr,
                        splitAttrArray,
                        inlineStylesArray = [];

                    while(splitArray.length) {
                        attrStr = splitArray.shift();
                        if(attrStr.indexOf('html:') === -1) continue;

                        splitAttrArray = attrStr.replace(/(html\:)|"/g, '').toLowerCase().split('=');


                        switch(splitAttrArray[0]) {
                            case 'color':
                                if(splitAttrArray[1] === '#000000') continue;
                                inlineStylesArray.push(['color: ', splitAttrArray[1]].join(''));
                            break;

                            case 'size':
                                inlineStylesArray.push(['font-size: ', Math.round((parseFloat(splitAttrArray[1], 10) / 11 * 100), 10), '%'].join(''));
                            break;
                        }
                    }

                    return inlineStylesArray.join('; ');
                }
            }

            function makeCellCurrency(cellNumberFormat, cellContent) {
                if(cellNumberFormat === '@'
                || cellNumberFormat === '0') return cellContent;

                var splitCellContentArray;

                if(cellNumberFormat === 'Currency') {
                    splitCellContentArray = parseFloat(cellContent, 10).toFixed(2).split('.');

                    cellContent = 'RM' + contentWithcommas();

                    if(splitCellContentArray.length > 1) {
                        cellContent += '.' + splitCellContentArray[1];
                    }
                } else if(cellNumberFormat === 'Fixed') {
                    splitCellContentArray = parseFloat(cellContent, 10).toFixed(2).split('.');

                    cellContent = contentWithcommas();

                    if(splitCellContentArray.length > 1) {
                        cellContent += '.' + splitCellContentArray[1];
                    }
                } else {
 
                    var currencyFormatArray = cellNumberFormat.split(';')[0].split(','),

                        currency = currencyFormatArray[0].replace(/\[|\]| |#|\\|"/g, '').replace(/\$/, '').split('-'),
                        decimals = currencyFormatArray[1].split('.');

                    if(currency.length > 1) currency = currency[0];

                    if(decimals.length === 1) {
                        decimals = 0;
                    } else {
                        decimals = decimals[1].replace(/_\)/g, '').length;
                    }

                    splitCellContentArray = parseFloat(cellContent, 10).toFixed(decimals).split('.');
                    cellContent = currency + contentWithcommas();
                    if(splitCellContentArray.length > 1) {
                        cellContent += '.' + splitCellContentArray[1];
                    }
                }

                return cellContent;

                function contentWithcommas() {
                    return splitCellContentArray[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
                }
            }

            function attachRowHoverers() {
                $holders.find('[rowspan]').each(function() {
                    var $thisCell = jQuery(this),
                        rowspan = $thisCell.attr('rowspan');

                    if(typeof rowspan !== 'string') return;

                    rowspan = parseInt(rowspan, 10);

                    var $thisRow = $thisCell.closest('tr'),
                        $nextRows = $thisRow.nextAll('tr').slice(0, rowspan-1);

                    $nextRows.each(function() {
                        jQuery(this).on({
                            mouseenter : function() {
                                $thisCell.addClass('is-hovered');
                            },

                            mouseleave : function() {
                                $thisCell.removeClass('is-hovered');
                            }
                        });
                    });
                });
            }

            function filterOutEmptyRows($rows) {
                /* Filter out rows that only have empty cells */
                $rows.each(function() {
                    var empty = true;

                    jQuery(this).find('Cell').each(function() {
                        if(jQuery(this).text() !== '') empty = false;
                        return false;
                    });

                    if(empty) $rows = $rows.not(jQuery(this));
                });

                return $rows;
            }

            function hasAttributes($obj, attrArr) {
                while(attrArr.length) {
                    if(typeof $obj.attr(attrArr.shift()) !== 'undefined') {
                        return true;
                    }
                }

                return false;
            }
        },
        /* End loadXMLTable */

        loadXMLLocations : function($holders) {
            $holders = jQuery($holders);
            if(!$holders.length) return;

            $holders.each(function() {
                var $thisHolder = jQuery(this);
                if($thisHolder.data('loaded-xml-locations') === true) return;

                var xmlURL = $thisHolder.data('xml-locations-url');
                if(typeof xmlURL !== 'string') return;

                jQuery.ajax({
                    type: 'GET',
                    url: xmlURL,
                    dataType: 'xml',
                    success: function(data) {
                        makeLocationsList(data, $thisHolder);
                        $thisHolder.data('loaded-xml-locations', true);
                    },
                    error: function(d) {
                        console.log(d);
                    }
                });
            });

            function makeLocationsList(data, $holder) {
                var $locations = jQuery(data).find('obj'),
                    regions = [];

                $locations.each(function() {
                    var $region = jQuery(this).find('region'),
                        regionStr = jQuery.trim($region.text());

                    regionStr = (regionStr) ? regionStr : 'Default';

                    if(regions.length) {
                        for(var i = regions.length-1; i > -1; i--) {
                            if(regions[i].name === regionStr) {
                                regions[i].$els.push(jQuery(this));
                                return;
                            }
                        }
                    }

                    regions.push({
                        'name' : regionStr,
                        '$els' : [jQuery(this)]
                    });
                });

                regions.sort(function(a,b) {
                    var strA = a.name.toLowerCase(),
                        strB = b.name.toLowerCase();

                    if(strA < strB) return -1; // sort ascending
                    if(strA > strB) return 1;
                    return 0; // do nothing
                });

                var output = [],
                    switcherStrArr = ['<span class="location-dropdown"><select>', '', '</select></span>'],
                    rowMarkup = ['<div class="row location-list', 1, '"><div class="row__flexi-width ', 3, '">'],
                    i, ii, totalLocationsInRegion;
                
                for(i = 0, ii = regions.length; i < ii; i++) {
                    rowMarkup[1] = (i === 0) ? ' current' : '';

                    totalLocationsInRegion = regions[i].$els.length;

                    if(totalLocationsInRegion < 2) {
                        rowMarkup[3] = 'has-1-item';
                    } else if(totalLocationsInRegion === 2) {
                        rowMarkup[3] = 'has-2-items';
                    } else if(totalLocationsInRegion === 3) {
                        rowMarkup[3] = 'has-3-items';
                    } else {
                        rowMarkup[3] = 'more-than-3-items';
                    }

                    output.push(rowMarkup.join(''));
                        while(regions[i].$els.length) {
                            output.push([
                                '<div class="column">',
                                    '<div class="location">',
                                        '<div class="location__name">',
                                            jQuery.trim(regions[i].$els[0].find('storeName').text()),
                                        '</div>',

                                        '<div class="location__address">',
                                            jQuery.trim(regions[i].$els[0].find('storeAddress').text()),
                                        '</div>',

                                        '<div class="location__footer">',
                                            '<a href="https://maps.google.com/maps?daddr=',
                                                jQuery.trim(regions[i].$els[0].find('storeLat').text()), ',',
                                                jQuery.trim(regions[i].$els[0].find('storeLng').text()), '" target="_blank">',
                                                'Get Directions',
                                            '</a>',
                                        '</div>',
                                    '</div>',
                                '</div>'
                            ].join(''));

                            regions[i].$els.shift();
                        }
                    output.push('</div></div>');
                }

                $holder.html(output.join(''));

                if(regions.length > 1) {
                    for(i = 0, ii = regions.length; i < ii; i++) {
                        switcherStrArr[1] += [
                            '<option value="', i, '">', regions[i].name, '</option>'
                        ].join('');
                    }

                    var $switcher = jQuery(switcherStrArr.join(''));

                    jQuery('<div class="text-center" />')
                        .prependTo($holder)
                        .append($switcher);

                    $switcher.dropdownify();

                    var $locationLists = $holder.find('.location-list');

                    $holder.find('select').on('change', function() {
                        var targetIndex = parseInt(jQuery(this).val(), 10);

                        $locationLists.each(function(index) {
                            if(index === targetIndex) {
                                jQuery(this)
                                    .addClass('current')
                                    .heightSyncify('enable')
                                    .heightSyncify('sync');
                            } else {
                                jQuery(this)
                                    .removeClass('current')
                                    .heightSyncify('disable');
                            }
                        });
                    });
                }

                var syncHeightSelectors = ['.location__name', '.location__address'];

                $holder.find('.location-list').heightSyncify({
                    items : syncHeightSelectors
                });
            }
        },
        /* End loadXMLLocations */

        scrollTo : function($obj, callback) {
            if(typeof $obj !== 'object'
            || !$obj instanceof jQuery
            || !$obj.length) {
                return;
            }

            var targetScrollPos = $obj.offset().top - 50;

            if(targetScrollPos < jQuery(window).scrollTop()) {
                targetScrollPos -= jQuery('#mainNav').outerHeight();

                if(jQuery('#mainSmallNav').css('display') !== 'none'
                && !jQuery('#mainHeader').hasClass('is-partially-hidden')) {
                    targetScrollPos -= jQuery('#mainSmallNav').outerHeight();
                }
            }

            if(callback === 'snap') {
                jQuery(window).scrollTop(targetScrollPos);
            } else {
                jQuery('html, body').animate({
                    scrollTop : targetScrollPos
                }, 400, callback);
            }
        },
        /* End scrollTo */

        watchSize : function() {
            homebrew.watchSize.apply(homebrew, arguments);
        }
        /* End watchSize */
    });


    jQuery.extend(FE.FootnoteAnchor.prototype, {
        init : function($el, $footnote) {
            if(!$el.length || !$footnote.length) return;

            var instance = this;

            instance.$el = $el;
            instance.$footnote = $footnote;

            $el.tooltipify({
                contents : $footnote.html()
            });

            instance.$el.data('footnote-anchor', this);

            instance.enable();
        },

        enable : function() {
            if(Modernizr.touch) return this;

            var instance = this;

            instance.$el.on({
                'click.footnotesTooltip' : function(e) {
                    e.preventDefault();
                    e.stopPropagation();

                    var $thisFootnote = instance.$footnote;

                    if(!jQuery('#notesToggler').hasClass('is-toggled')) {
                        jQuery('#notesToggler').togglerify('toggleOn', { noSlide : true });
                    }

                    FE.scrollTo($thisFootnote);
                    $thisFootnote.addClass('is-active');

                    jQuery(document)
                        .off('mouseup.notesFauxBlur')
                        .on('mouseup.notesFauxBlur', function(e) {
                            if(!$thisFootnote.is(e.target) && $thisFootnote.has(e.target).length === 0) {
                                jQuery(document).off('mouseup.notesFauxBlur');
                                $thisFootnote.removeClass('is-active');
                            }
                        });
                }
            });

            return this;
        },

        disable : function() {
            var instance = this;

            instance.$el.off('click.footnotesTooltip');
            instance.$el.tooltipify('disable');

            return instance;
        }
    });


    jQuery.extend(FE.Hasher.prototype, {
        get : function(args) {
            var instance = this,
                hash = window.location.hash;

            if(hash === ''
            || hash === '#/'
            || hash.substr(0,2) !== '#/') {
                instance.data = {};
                return instance;
            }

            var splitHash = hash.substring(2).split('&'),
                keyValuePairs,
                dataObj = {};

            while(splitHash.length) {
                keyValuePairs = splitHash.shift().split('=');
                dataObj[jQuery.trim(keyValuePairs[0])] = decodeURIComponent(jQuery.trim(keyValuePairs[1]));
            }

            instance.data = dataObj;

            return instance;
        },

        setData : function(data) {
            if(!data || !jQuery.isPlainObject(data)) return this;
            this.data = jQuery.extend({}, data);
            return this;
        },

        extendData : function(data) {
            if(!data || !jQuery.isPlainObject(data)) return this;

            if(this.data) {
                jQuery.extend(this.data, data);
            } else {
                this.data = data;
            }
            

            return this;
        },

        set : function(args) {
            args = args || {};

            var instance = this,
                options = jQuery.extend(instance.options, args);

            if(options.ignoreDefault && !instance.data) return instance;

            instance.data = instance.data || {};

            var hashKeys = [],
                hash = [],
                sequence = options.sequence;

            if(sequence === 'alphabetical'
            || typeof sequence === 'function') {
                jQuery.each(instance.data, function(key, value) {
                    if(key === '' || value === '') return;
                    hashKeys.push(key);
                });

                var sorter;

                if(sequence === 'alphabetical') {
                    sorter = function(a, b) {
                        var _a = a.toLowerCase(),
                            _b = b.toLowerCase();

                        if(_a < _b) return -1;
                        if(_a > _b) return 1;
                        return 0;
                    };
                } else if(typeof sequence === 'function') {
                    sorter = sequence;
                }

                hashKeys.sort(sorter);

                var currentHashKey;

                while(hashKeys.length) {
                    currentHashKey = hashKeys.shift();
                    hash.push([currentHashKey, encodeURIComponent(instance.data[currentHashKey])].join('='));
                }
            } else if(typeof sequence === 'string') {
                var splitSequence = sequence.split(','),
                    i, ii, currentSequenceKey;

                for(i = 0, ii = splitSequence.length; i < ii; i++) {
                    currentSequenceKey = splitSequence[i];

                    if(instance.data[currentSequenceKey]) {
                        hash.push([currentSequenceKey, encodeURIComponent(instance.data[currentSequenceKey])].join('='));
                    }
                }

                jQuery.each(instance.data, function(key, value) {
                    if(key === '' || value === '') return;

                    for(i = splitSequence.length-1; i > -1; i--) {
                        if(key === splitSequence[i]) return;
                    }

                    hash.push([key, encodeURIComponent(value)].join('='));
                });
            } else {
                jQuery.each(instance.data, function(key, value) {
                    if(key === '' || value === '') return;
                    hash.push([key, encodeURIComponent(value)].join('='));
                });
            }

            window.location.hash = '#/' + hash.join('&');
        },

        isSameWith : function(data) {
            if(!data) return false;

            var same = true,
                count = 0,
                instance = this;

            jQuery.each(data, function(key, value) {
                if(typeof instance.data[key] === 'undefined'
                || instance.data[key] !== value) {
                    same = false;
                    return false;
                } else {
                    count++;
                }
            });

            if(same) {
                var refCount = 0;

                jQuery.each(instance.data, function() {
                    refCount++;
                });

                same = (count === refCount);
            }

            return same;
        }
    });


    jQuery.extend(FE.StickyColumn.prototype, {
        callbacks : jQuery({}),

        hasMousewheel : Boolean(jQuery.fn.mousewheel),

        classes : {
            stickyColumn : 'sticky-column',
            sticky : 'is-sticky',
            stickBottom : 'is-stick-to-bottom'
        },

        load : function(args) {
            var instance = this,
                proto = FE.StickyColumn.prototype;

            /* If Mousewheel isn't available, load it now. */
            if(!proto.hasMousewheel) {
                if(!proto.loadingMousewheel) {
                    proto.loadingMousewheel = true;

                    jQuery.getScript(FE.baseURL + 'js/plugins/jquery.mousewheel.min.js', function() {
                        FE.StickyColumn.prototype.hasMousewheel = true;
                        proto.callbacks.dequeue('mousewheelLoaded');
                    });
                }

                proto.callbacks.queue('mousewheelLoaded', function(next) {
                    instance.init(args);
                    if(typeof next === 'function') next();
                });
            }
        },

        init : function(args) {
            var $el = args.$el,
                $comparee = args.$comparee;

            if(!$el || !$comparee
            || !$el instanceof jQuery || !$comparee instanceof jQuery
            || !$el.length || !$comparee.length) {
                return;
            }

            var instance = this,
                proto = FE.StickyColumn.prototype;

            instance.$el = $el;
            instance.$comparee = $comparee;
            instance.uniqueID = homebrew.generateUniqueID();

            $el.addClass(instance.classes.stickyColumn);
            
            FE.watchSize('large', function(isLargeScreen) {
                if(isLargeScreen) {
                    instance.watch();
                } else {
                    instance.rest();
                    instance.unstick();
                    instance.updatePosition();
                }
            });

            return instance;
        },

        determineState : function() {
            if(!homebrew.screenSize.large) return 'should-be-unstuck';

            var instance = this,
                $stickyCol = instance.$el,
                $comparee = instance.$comparee,
                windowTop = jQuery(window).scrollTop(),
                stickyColMarginTop = parseInt($stickyCol.css('margin-top'), 10);

            instance.offsetTop = (jQuery('#mainHeader').css('position') === 'fixed') ? /*instance.$els.mainNav.height()*/ 0 : 0;
            instance.offsetBottom = parseInt($comparee.find('.column').css('margin-bottom'), 10)*2;

            if(!$comparee.is(':visible') || $stickyCol.height() >= $comparee.height()) {
                return 'should-be-unstuck';
            } else if($stickyCol.hasClass(instance.classes.stickBottom) && $stickyCol.offset().top >= windowTop + instance.offsetTop) {
                return 'should-be-stuck';
            } else if((windowTop + $stickyCol.height() + stickyColMarginTop + instance.offsetTop) > ($comparee.offset().top + $comparee.height() - instance.offsetBottom)) {
                return 'should-be-stuck-to-bottom';
            } else if($comparee.offset().top <= windowTop + instance.offsetTop) {
                return 'should-be-stuck';
            } else {
                return 'should-be-unstuck';
            }
        },

        updatePosition : function() {
            var instance = this,
                $el = instance.$el;

            if($el.hasClass(instance.classes.stickBottom) || !$el.hasClass(instance.classes.sticky)) {
                $el.css('top', '');
            } else {
                $el.css('top', jQuery(window).scrollTop() - instance.$comparee.offset().top + instance.offsetTop + 'px');
            }

            return instance;
        },

        stick : function() {
            var instance = this;
            
            instance.$el
                .addClass(instance.classes.sticky)
                .removeClass(instance.classes.stickBottom);
            
            return instance;
        },

        stickToBottom : function() {
            var instance = this;

            instance.$el
                .addClass([
                    instance.classes.sticky,
                    instance.classes.stickBottom
                ].join(' '))
                .css('margin-top', '');
            
            return instance;
        },

        unstick : function() {
            var instance = this;
            
            instance.$el
                .removeClass([
                    instance.classes.sticky,
                    instance.classes.stickBottom
                ].join(' '))
                .css('margin-top', '');
            
            return instance;
        },

        watch : function() {
            var instance = this;
            
            jQuery(window).on([
                'scroll.', instance.uniqueID,
                ' resize.', instance.uniqueID
            ].join(''), function() {
                var state = instance.determineState();
                
                switch(state) {
                    case 'should-be-stuck' :           instance.stick();         break;
                    case 'should-be-stuck-to-bottom' : instance.stickToBottom(); break;
                    case 'should-be-unstuck' :         instance.unstick();       break;
                }
                
                instance.updatePosition();
            }).trigger('scroll');
            
            instance.$el.on('mousewheel', function(e) {
                if(instance.determineState() !== 'should-be-stuck') return;

                var vector;

                if(e.deltaY < 0) {
                    var bottomDiff = jQuery(window).scrollTop() + jQuery(window).height() - jQuery(this).offset().top - jQuery(this).height();

                    if(bottomDiff >= 0) {
                        return;
                    } else if(Math.abs(bottomDiff) < 100) {
                        vector = bottomDiff;
                    } else {
                        vector = -100;
                    }
                } else if(e.deltaY > 0) {
                    var topDiff = jQuery(window).scrollTop() + instance.offsetTop - jQuery(this).offset().top;

                    if(topDiff === 0) {
                        return;
                    } else if(topDiff < 100) {
                        vector = topDiff;
                    } else {
                        vector = 100;
                    }
                }

                e.preventDefault();
                instance.$el.css('margin-top', [parseInt(instance.$el.css('margin-top'), 10) + vector, 'px'].join(''));
            });

            return instance;
        },

        rest : function() {
            jQuery(window).off('.' + this.uniqueID);
            return this;
        }
    });


    /*---- Init page ----*/

    FE.initPage();

    /* Run through any queued callbacks if available. */
    if(typeof FE__callbacks === 'object'
    && FE__callbacks instanceof Array
    && FE__callbacks.length) {
        while(FE__callbacks.length) {
            FE__callbacks.shift()();
        }
    }
});